This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Nrf SPI Timing Configurations

Hello sir,

I am a beginner on NRF52840. I am using Nrfx_spim example for interfacing sensor with NRF Board.

I have done some driver about Reg_read and Reg_write. I tried to read the device ID of the sensor through SPI yielding improper results.

Hence I probed on the SPI_SCK line and I found that the duty cycle of SPI_SCK is not proper and also set up and hold times are not proper. 

In my requirement timing of the SPI should be as in the attached image below. 

To be more specific I need to meet the timing requirements as of detailed in the image below.

Presently The waveform what I am observing on probing SPI_SCK is as below.

I am pretty sure that my SPI configurations are not proper, please provide me a pointer where I can do the SPI configurations to meet the timing requirements detailed above.

Expecting your kind help.

Thanks,

Rohit 

Parents
  • Hi,

    I assume you have used the SDK example as reference: \nRF5_SDK_15.2.0_9412b96\examples\peripheral\spi 
    (http://infocenter.nordicsemi.com/topic/com.nordic.infocenter.sdk5.v15.2.0/hardware_driver_spi_master.html?cp=4_0_0_2_0_13

    The timing you refer are okey, these are just min and max values, and should fall well within the timing of the spi master of the nRF52. For instance it says the clock frequency should be between 0 and 12MHz, which means you can for instance use 1MHz clock rate.

    I think you should zoom into your plot, I suspect you have an SPI transfer every 250ms(? timing not shown) here.

    Best regards,
    Kenneth

  • Hi Kenneth,

    I am not satisfied with your answer. We are working with the max30003 sensor and we plan to record ECG data with it.

     I am referred below link because the same problem is coming into my code :

    https://devzone.nordicsemi.com/f/nordic-q-a/38483/using-nrf52832-as-spi-master-to-get-data-from-sensor/148560#148560

    I have used the SDK example as reference: \nRF5_SDK_15.1.0\examples\peripheral\nRFX_SPIM.

     I Have done reg read and reg write driver as per MAXIM Drivers (.cpp and.h file) Please see the below link:

    https://www.maximintegrated.com/en/products/analog/data-converters/analog-front-end-ics/MAX30003.html

    But My problem is that:

    1) I don't know Written Driver is correct or not as per MAXIM? and I unable to read INFO Register Correctly. 

    2) If I Read 0x0F register then I Got below waveform and data in RX Buffer.

    Probing: MOSI For Yellow and Blue for SCK Pin

    3) but Even without calling the Reg_Read function into the main function then also data is coming in to RX Buffer. 

    Probing: MOSI For Yellow and Blue for SCK Pin

    In my requirement timing of the SPI should be as in the attached image below. 

    I am pretty sure that my SPI configurations are not proper, please provide me a pointer where I can do the SPI configurations to meet the timing requirements detailed above.

    Expecting your kind help.

    please check below code:

    #include "nrfx_spim.h"
    #include "app_util_platform.h"
    #include "nrf_gpio.h"
    #include "nrf_delay.h"
    #include "boards.h"
    #include "app_error.h"
    #include <string.h>
    #include "nrf_log.h"
    #include "nrf_log_ctrl.h"
    #include "nrf_log_default_backends.h"
    #include "MAX30003.h"
    
    
    #define NRFX_SPIM_SCK_PIN  3
    #define NRFX_SPIM_MOSI_PIN 4
    #define NRFX_SPIM_MISO_PIN 28
    #define NRFX_SPIM_SS_PIN   29
    #define NRFX_SPIM_DCX_PIN  30
    
    #define SPI_INSTANCE  3                                           /**< SPI instance index. */
    static const nrfx_spim_t spi = NRFX_SPIM_INSTANCE(SPI_INSTANCE);  /**< SPI instance. */
    
    static volatile bool spi_xfer_done;  /**< Flag used to indicate that SPI instance completed the transfer. */
    static  uint8_t m_tx_buf[4]; //= {0xff,0x01,0x02}; // ={0x0F}; // 32 bit transfers
    static uint8_t       m_rx_buf[sizeof(m_tx_buf)];  /**< RX buffer. */
    static const uint8_t m_length = sizeof(m_tx_buf);        /**< Transfer length. */
    
    
    void spim_event_handler(nrfx_spim_evt_t const * p_event,
                           void *                  p_context)
    {
        spi_xfer_done = true;
        NRF_LOG_INFO("Transfer completed.");
        if (m_rx_buf[0] != 0)
        {
            NRF_LOG_INFO(" Received:");
            NRF_LOG_HEXDUMP_INFO(m_rx_buf, strlen((const char *)m_rx_buf));
        }
    }
    uint8_t MAX30003_Reg_Read(uint8_t Reg_address)
    {
      nrfx_err_t err_code = 0;	
      uint8_t data;
      //Prepare the tx buffer
      memset(m_rx_buf, 0x00, sizeof(m_rx_buf)); // Erases the buffer
      m_tx_buf[0] = ((Reg_address << 1 ) | 0x01); 
      //Create the transfer descriptor
      nrfx_spim_xfer_desc_t xfer_desc = NRFX_SPIM_XFER_TRX(m_tx_buf, sizeof(m_tx_buf), m_rx_buf, sizeof(m_tx_buf));
      //Initiate the transfer
      spi_xfer_done == false;
      err_code = nrfx_spim_xfer(&spi, &xfer_desc, 0);
      APP_ERROR_CHECK(err_code);
      while (spi_xfer_done == true);
      data |= (m_rx_buf[1] << 16);
      data |= (m_rx_buf[2] << 8);
      data |= m_rx_buf[3];
      return data;
    }
    uint8_t MAX30003_Reg_Write(uint8_t Reg_address,  uint32_t data)
    {
       nrfx_err_t err_code = 0;	
      //Prepare the tx buffer
      memset(m_rx_buf, 0x00, sizeof(m_rx_buf)); // Erases the buffer
      m_tx_buf[0] = ((Reg_address << 1) | 0x00); 
      //Create the transfer descriptor
       nrfx_spim_xfer_desc_t xfer_desc = NRFX_SPIM_XFER_TRX(m_tx_buf, sizeof(m_tx_buf), m_rx_buf, sizeof(m_tx_buf));
      //Initiate the transfer
      spi_xfer_done == false;
      err_code = nrfx_spim_xfer(&spi, &xfer_desc, 0);
      APP_ERROR_CHECK(err_code);
      while (spi_xfer_done == true);
      data |= (m_rx_buf[1] >> 16);
      data |= (m_rx_buf[2] >> 8);
      data |= m_rx_buf[3];
      return data;
    }
    void max30003_sw_reset(void)
    {
        MAX30003_Reg_Write(SW_RST,0x000000);     
        nrf_delay_ms(100);
    }
    
    void max30003_synch(void)
    {
        MAX30003_Reg_Write(SYNCH,0x000000);
    }
    void MAX30003_begin()
    {    
        max30003_sw_reset();
        MAX30003_Reg_Write(CNFG_GEN, 0x081007);
        nrf_delay_ms(100);
        MAX30003_Reg_Write(CNFG_CAL, 0x720000);  // 0x700000  
        nrf_delay_ms(100);
        MAX30003_Reg_Write(CNFG_EMUX,0x0B0000);
        nrf_delay_ms(100);
        MAX30003_Reg_Write(CNFG_ECG, 0x805000);  // 
        nrf_delay_ms(100);
        MAX30003_Reg_Write(CNFG_RTOR1,0x3fc600);
        max30003_synch();
        nrf_delay_ms(100);
    }
    int main(void)
    {
    bsp_board_init(BSP_INIT_LEDS);
    APP_ERROR_CHECK(NRF_LOG_INIT(NULL));
    NRF_LOG_DEFAULT_BACKENDS_INIT();
    	
    //MAX30003_Reg_Read(0x0F); //0x0F
    
    
    nrfx_spim_config_t spi_config = NRFX_SPIM_DEFAULT_CONFIG;
    spi_config.frequency = SPIM_FREQUENCY_FREQUENCY_M1;
    spi_config.ss_pin = NRFX_SPIM_SS_PIN;
    spi_config.miso_pin = NRFX_SPIM_MISO_PIN;
    spi_config.mosi_pin = NRFX_SPIM_MOSI_PIN;
    spi_config.sck_pin = NRFX_SPIM_SCK_PIN;
    spi_config.dcx_pin = NRFX_SPIM_DCX_PIN;
    spi_config.use_hw_ss = true;
    spi_config.ss_active_high = false;
    spi_config.mode = NRF_SPIM_MODE_0; // SCK active high, sample on leading edge of clock, CPOL=0/CPHA=0
    spi_config.bit_order=NRF_SPIM_BIT_ORDER_LSB_FIRST; 
    
    nrfx_spim_xfer_desc_t xfer_desc=NRFX_SPIM_XFER_TRX(m_tx_buf, sizeof(m_tx_buf), m_rx_buf, sizeof(m_tx_buf));
    
    APP_ERROR_CHECK(nrfx_spim_init(&spi, &spi_config, spim_event_handler, NULL));
    
    NRF_LOG_INFO("NRFX SPIM example started.");
    
    while (1)
    {
    // Reset rx buffer and transfer done flag
    memset(m_rx_buf, 0, m_length);
    
    spi_xfer_done = false;
    APP_ERROR_CHECK(nrfx_spim_xfer_dcx(&spi, &xfer_desc, 0, 15)); 
    
    while (!spi_xfer_done)
    {
    	
    __WFE();
    }
    NRF_LOG_FLUSH();
    bsp_board_led_invert(BSP_BOARD_LED_0);
    nrf_delay_ms(200);
    }
    }
     

    Thanks and Regards,

    rohit

  • Can you explain how the following code works?

      spi_xfer_done == false;
      err_code = nrfx_spim_xfer(&spi, &xfer_desc, 0);
      APP_ERROR_CHECK(err_code);
      while (spi_xfer_done == true);

    I would think it should be:

      spi_xfer_done = false;
      err_code = nrfx_spim_xfer(&spi, &xfer_desc, 0);
      APP_ERROR_CHECK(err_code);
      while (spi_xfer_done == false);

    When it doubt, go back to the working example in the SDK:

    \nRF5_SDK_15.1.0_a8c0c4d\examples\peripheral\nrfx_spim 

Reply
  • Can you explain how the following code works?

      spi_xfer_done == false;
      err_code = nrfx_spim_xfer(&spi, &xfer_desc, 0);
      APP_ERROR_CHECK(err_code);
      while (spi_xfer_done == true);

    I would think it should be:

      spi_xfer_done = false;
      err_code = nrfx_spim_xfer(&spi, &xfer_desc, 0);
      APP_ERROR_CHECK(err_code);
      while (spi_xfer_done == false);

    When it doubt, go back to the working example in the SDK:

    \nRF5_SDK_15.1.0_a8c0c4d\examples\peripheral\nrfx_spim 

Children
  • Hi,

    Explanation:

    It depends on how I set spi_xfer_done in the SPIM callback handler.  I should set it false before transfer, then set it true in the callback.  then I have to loop in the while as long as the flag is not set true. Now I will skip the loop as the flag is not set to true (I set it to false right before nrfx_spim_xfer).

    Thanks for my driver recovery. I have changed the code as per your suggestion. And Its work fine.

    I get data in TX and RX buffer.

    But I am not getting correct waveform please check my SPI configuration.

    In my requirement timing of the SPI should be as in the attached image below. 

    but I am getting below waveform it is totally wrong. I am not sure about my SPI Configuration so please check it.

     

    MISO Channel 3 , CS channel 7, SCK Channel  9 and Channel  13 MOSI.

    #include "nrfx_spim.h"
    #include "app_util_platform.h"
    #include "nrf_gpio.h"
    #include "nrf_delay.h"
    #include "boards.h"
    #include "app_error.h"
    #include <string.h>
    #include "nrf_log.h"
    #include "nrf_log_ctrl.h"
    #include "nrf_log_default_backends.h"
    #include "MAX30003.h"
    
    
    #define NRFX_SPIM_SCK_PIN  3
    #define NRFX_SPIM_MOSI_PIN 4
    #define NRFX_SPIM_MISO_PIN 28
    #define NRFX_SPIM_SS_PIN   29
    #define NRFX_SPIM_DCX_PIN  30
    
    #define SPI_INSTANCE  3                                           /**< SPI instance index. */
    const nrfx_spim_t spi = NRFX_SPIM_INSTANCE(SPI_INSTANCE);  /**< SPI instance. */
    
    volatile bool spi_xfer_done;  /**< Flag used to indicate that SPI instance completed the transfer. */
    uint8_t m_tx_buf[4]; //= {0xff,0x01,0x02}; // ={0x0F}; // 32 bit transfers
    uint8_t       m_rx_buf[sizeof(m_tx_buf)];  /**< RX buffer. */
    const uint8_t m_length = sizeof(m_tx_buf);        /**< Transfer length. */
    nrfx_spim_xfer_desc_t xfer_desc=NRFX_SPIM_XFER_TRX(m_tx_buf, sizeof(m_tx_buf), m_rx_buf, sizeof(m_tx_buf));
    
    
    void spim_event_handler(nrfx_spim_evt_t const * p_event,
                           void *                  p_context)
    {
    	
    
        spi_xfer_done = true;
        NRF_LOG_INFO("Transfer completed.");
        if (m_rx_buf[0] != 0)
        {
            NRF_LOG_INFO(" Received:");
            NRF_LOG_HEXDUMP_INFO(m_rx_buf, strlen((const char *)m_rx_buf));
        }
    }
    uint8_t MAX30003_Reg_Read(uint8_t Reg_address)
    {
      nrfx_err_t err_code = 0;	
      uint32_t data;
      //Prepare the tx buffer
       memset(m_rx_buf, 0x00, sizeof(m_rx_buf)); // Erases the buffer
      m_tx_buf[0] = ((Reg_address << 1) | 0x01); 
      //Create the transfer descriptor
     // nrfx_spim_xfer_desc_t xfer_desc = NRFX_SPIM_XFER_TRX(m_tx_buf, sizeof(m_tx_buf), m_rx_buf, sizeof(m_tx_buf));
      //Initiate the transfer
      spi_xfer_done = false;
      err_code = nrfx_spim_xfer(&spi, &xfer_desc, 0);
      APP_ERROR_CHECK(err_code);
      while (spi_xfer_done == false);
      data |= (m_rx_buf[1] << 16);
      data |= (m_rx_buf[2] << 8);
      data |= m_rx_buf[3];
      return data;
    }
    
    uint8_t MAX30003_Reg_Write(uint8_t Reg_address,  uint32_t data)
    {
      nrfx_err_t err_code = 0;	
      //Prepare the tx buffer
      memset(m_rx_buf, 0x00, sizeof(m_rx_buf)); // Erases the buffer
      m_tx_buf[0] = ((Reg_address << 1) | 0x01); 
    //  //Create the transfer descriptor
    //   nrfx_spim_xfer_desc_t xfer_desc = NRFX_SPIM_XFER_TRX(m_tx_buf, sizeof(m_tx_buf), m_rx_buf, sizeof(m_tx_buf));
    //  //Initiate the transfer
      spi_xfer_done = false;
      err_code = nrfx_spim_xfer(&spi, &xfer_desc, 0);
      APP_ERROR_CHECK(err_code);
      while (spi_xfer_done == false);
      data |= (m_rx_buf[1] >> 16);
      data |= (m_rx_buf[2] >> 8);
      data |= m_rx_buf[3];
      return data;
    }
    void max30003_sw_reset(void)
    {
        MAX30003_Reg_Write(SW_RST,0x000000);     
        nrf_delay_ms(100);
    }
    
    void max30003_synch(void)
    {
        MAX30003_Reg_Write(SYNCH,0x000000);
    }
    void MAX30003_begin()
    {    
        max30003_sw_reset();
        MAX30003_Reg_Write(CNFG_GEN, 0x081007);
        nrf_delay_ms(100);
        MAX30003_Reg_Write(CNFG_CAL, 0x720000);  // 0x700000  
        nrf_delay_ms(100);
        MAX30003_Reg_Write(CNFG_EMUX,0x0B0000);
        nrf_delay_ms(100);
        MAX30003_Reg_Write(CNFG_ECG, 0x805000);  // 
        nrf_delay_ms(100);
        MAX30003_Reg_Write(CNFG_RTOR1,0x3fc600);
        max30003_synch();
        nrf_delay_ms(100);
    }
    
    int main(void)
    {
    bsp_board_init(BSP_INIT_LEDS);
    APP_ERROR_CHECK(NRF_LOG_INIT(NULL));
    NRF_LOG_DEFAULT_BACKENDS_INIT();
    nrfx_spim_config_t spi_config = NRFX_SPIM_DEFAULT_CONFIG;
    spi_config.frequency = SPIM_FREQUENCY_FREQUENCY_M1;
    spi_config.ss_pin = NRFX_SPIM_SS_PIN;
    spi_config.miso_pin = NRFX_SPIM_MISO_PIN;
    spi_config.mosi_pin = NRFX_SPIM_MOSI_PIN;
    spi_config.sck_pin = NRFX_SPIM_SCK_PIN;
    spi_config.dcx_pin = NRFX_SPIM_DCX_PIN;
    spi_config.use_hw_ss = true;
    spi_config.ss_active_high = false;
    spi_config.mode = NRF_SPIM_MODE_0; // SCK active high, sample on leading edge of clock, CPOL=0/CPHA=0
    spi_config.bit_order=NRF_SPIM_BIT_ORDER_LSB_FIRST; 
    //nrfx_spim_xfer_desc_t xfer_desc=NRFX_SPIM_XFER_TRX(m_tx_buf, sizeof(m_tx_buf), m_rx_buf, sizeof(m_tx_buf));
    	
    APP_ERROR_CHECK(nrfx_spim_init(&spi, &spi_config, spim_event_handler, NULL));
    
    	NRF_LOG_INFO("NRFX SPIM example started.");
    while (1)
    {
    // Reset rx buffer and transfer done flag
    memset(m_rx_buf, 0, m_length);
    spi_xfer_done = false;
    MAX30003_Reg_Read(INFO); //0x0F
    APP_ERROR_CHECK(nrfx_spim_xfer_dcx(&spi, &xfer_desc, 0, 15)); 
    
    while (!spi_xfer_done)
    {
    	
    __WFE();
    }
    NRF_LOG_FLUSH();
    bsp_board_led_invert(BSP_BOARD_LED_0);
    nrf_delay_ms(200);
    }
    }
    

    Thanks and Regards,

    Rohit.

  • Looks like you are sampling the SPI with too slow sampling rate setting, then you get strange waveform. You need to reduce SPI speed or increase sample rate (preferred). 

    Best regards,
    Kenneth

  • Hi,

    Since  i am unable to find a function to change sampling rate in nRFX_SPIM code example.suggest me a exmple code in peripheral that can be merged in my original code and used in spi function to change sampling rate.

    Thanks,

    rohit

  • You misunderstand. The problem here is your logic analyzer that can't handle the SPI data stream, you must set the sample rate to higher in your "Hantek" analyzer.

    Best regards,
    Kenneth

  • Hi,

    I tested out both that drivers (SPI and SPIM) I am unable to figure out how to meet the requirement as given in below diagram.

    can you please share me APIs with configurations which can meet above diagram.

    please share the waveforms capture by you to meet above requirement.

    a project is quite critical quick help could be highly appreciated.

    There is another pin named DCx as seen from data sheet which comes under SPIM interface. I want to work as legacy SPI with MISO MOSI SCLK CS PINS, Hence is SPIM Driver suitable for this.

    Thanks,

    Rohit

Related