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

how to drive spi CS line low for 32 bits.

Hi,

Can you please direct me to the document that explains about generating more than 8 bits of clock in SPI and keeping CS line low for that entire period.

Also, if i have to send two 16bit data, would i have to send them in lots of 8bit ? or i can send them as 16bits using nrf_drv_spi_transfer API?

I am modifying the SPI example found under SDK15/example/peripheral/spi.

And i have to achieve the sequence attached in the image. 

Thank you  

Parents
  • Hi,

    I recommend you use the SPI master driver, which will handle everything for you. The SPI hardware peripheral and SPI driver count 8 bit words but that does not have any practical implication for what happens on the SPI line. How you think of the data is up to you, whether you think of it as a single 16 bit word or two 8 bit words has no implication on the physical data on the SPI bus.

  • I realized that first i should understand the SPI examples provided in the SDK thoroughly before customizing them.

    I am using nrf52832 DK as Master and flashing SPI example to it which is supposed to send a string " NORDIC " and then i am flashing SPIS example to my nrf52840 DK which should act as the slave then.  Now, though the transactions are getting completed in both the kits and LED's get toggled but i am not receiving the string "NORDIC" from my slave . What do i have to modify in the slave example to receive the string ?

    #include "sdk_config.h"
    #include "nrf_drv_spis.h"
    #include "nrf_gpio.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"
    
    #define SPIS_INSTANCE 1 /**< SPIS instance index. */
    static const nrf_drv_spis_t spis = NRF_DRV_SPIS_INSTANCE(SPIS_INSTANCE);/**< SPIS instance. */
    
    #define TEST_STRING "Nordic"
    static uint8_t       m_tx_buf[] = TEST_STRING;           /**< TX buffer. */
    static uint8_t       m_rx_buf[sizeof(TEST_STRING) + 1];    /**< RX buffer. */
    static const uint8_t m_length = sizeof(m_tx_buf);        /**< Transfer length. */
    
    static volatile bool spis_xfer_done; /**< Flag used to indicate that SPIS instance completed the transfer. */
    
    /**
     * @brief SPIS user event handler.
     *
     * @param event
     */
    void spis_event_handler(nrf_drv_spis_event_t event)
    {
        if (event.evt_type == NRF_DRV_SPIS_XFER_DONE)
        {
            spis_xfer_done = true;
            NRF_LOG_INFO(" Transfer completed. Received: %s",(uint32_t)m_rx_buf);
            printf("recieved : %s", m_rx_buf );
        }
    }
    
    int main(void)
    {
        // Enable the constant latency sub power mode to minimize the time it takes
        // for the SPIS peripheral to become active after the CSN line is asserted
        // (when the CPU is in sleep mode).
        NRF_POWER->TASKS_CONSTLAT = 1;
    
        bsp_board_init(BSP_INIT_LEDS);
    
        APP_ERROR_CHECK(NRF_LOG_INIT(NULL));
        NRF_LOG_DEFAULT_BACKENDS_INIT();
    
        NRF_LOG_INFO("SPIS example");
    
        nrf_drv_spis_config_t spis_config = NRF_DRV_SPIS_DEFAULT_CONFIG;
        spis_config.csn_pin               = APP_SPIS_CS_PIN;
        spis_config.miso_pin              = APP_SPIS_MISO_PIN;
        spis_config.mosi_pin              = APP_SPIS_MOSI_PIN;
        spis_config.sck_pin               = APP_SPIS_SCK_PIN;
    
        APP_ERROR_CHECK(nrf_drv_spis_init(&spis, &spis_config, spis_event_handler));
    
        while (1)
        {
            memset(m_rx_buf, 0, m_length);
            spis_xfer_done = false;
    
            APP_ERROR_CHECK(nrf_drv_spis_buffers_set(&spis, m_tx_buf, m_length, m_rx_buf, m_length));
    
            while (!spis_xfer_done)
            {
                __WFE();
            }
    
            NRF_LOG_FLUSH();
    
            bsp_board_led_invert(BSP_BOARD_LED_0);
        }
    }
    

  • Hi,

     

    I am sorry for the late reply.

    You cannot enable pull up on a gpio configured as output. If you need a pull-resistor on a GPIO configured as output, you can either set the level (1 or 0), or add an external pull-resistor.

    Kind regards,

    Håkon

  • Hi Hakon,

    I am still struggling to produce correct SPI timings . Below is the actual SPI timing sent to me by an Application Engineer from MICROCHIP. I need to replicate the same using nrf52840 chip :

    I am getting these SPI timings using the same operation as in above image through nrf52840 chip . 

    Can you identify what is going wrong with my attached firmware ????

    Any kind of help or suggestion will be appreciated . We are really running late now on our project .

    #include "nrf_drv_spi.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"
    
    #define SPI_INSTANCE  0 /**< SPI instance index. */
    static const nrf_drv_spi_t spi = NRF_DRV_SPI_INSTANCE(SPI_INSTANCE);  /**< SPI instance. */
    static volatile bool spi_xfer_done;  /**< Flag used to indicate that SPI instance completed the transfer. */
    
    
    static uint16_t       m_tx_buf4= 0b1000000000110000;    //0X30H
    static uint16_t       m_tx_buf5= 0b0000000000000000;
     
    
    static uint8_t       m_rx_buf[2];    /**< RX buffer. */
    static const uint8_t  m_length = 4;        /**< Transfer length. */
    
    /**
     * @brief SPI user event handler.
     * @param event
     */
    
    
    
    void spi_event_handler(nrf_drv_spi_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));
        }
    }
    
    int main(void)
    {
        bsp_board_init(BSP_INIT_LEDS);
    
        APP_ERROR_CHECK(NRF_LOG_INIT(NULL));
        NRF_LOG_DEFAULT_BACKENDS_INIT();
    
            nrf_drv_spi_config_t spi_config = NRF_DRV_SPI_DEFAULT_CONFIG;
            spi_config.ss_pin   = SPI_SS_PIN;
            spi_config.miso_pin = SPI_MISO_PIN;
            spi_config.mosi_pin = SPI_MOSI_PIN;
            spi_config.sck_pin  = SPI_SCK_PIN;
            spi_config.mode = NRF_DRV_SPI_MODE_0;
            APP_ERROR_CHECK(nrf_drv_spi_init(&spi, &spi_config, spi_event_handler, NULL));
    
            NRF_LOG_INFO("SPI example started.");
    
            while(1){
    
            memset(m_rx_buf, 0, m_length);
            spi_xfer_done = false;
           
            APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi, &m_tx_buf4, m_length, m_rx_buf, m_length));
            
                  while (!spi_xfer_done)
            {
                __WFE();
            }
    
            NRF_LOG_FLUSH();
    
    
            bsp_board_led_invert(3);
            nrf_delay_ms(200);  
    
          }
        
    }
    

    Thanks,

    Arshdeep

  • Hi,

     

    1. You are overflowing your buffer (m_rx_buffer) by 2 bytes, as the buffer is declared as 2 byte and you are receiving 4 bytes. This is _very crucial_ that you fix.

    2. You are no longer switching SPI mode as per the spec for the sensor you are communicating with.

    Best regards,

    Håkon

  • Hi Hakon,

    So my rxbuffer sjould be of 4 bytes, right? rx_buffer[4]. Is it a violation or i can directly increase the size? 

    Switching mode is not required as suggested by MICROCHIP. All transactions will happen using single mode only.

    Thanks 

  • rx_buffer should be equal (or larger) to the length that you are receiving.

    Declare it like this:

    static uint8_t m_rx_buf[4];

    The salaea logic analyzer trace shows that your send buffer and the actual byte endianess on the bus does not correspond, as the READ bit is not set.

    Could you try setting your transfer buffer like this and see if the sensor responds?

    uint8_t m_tx_buf4[] = {0x80, 0x30};

    Kind regards,

    Håkon

Reply
  • rx_buffer should be equal (or larger) to the length that you are receiving.

    Declare it like this:

    static uint8_t m_rx_buf[4];

    The salaea logic analyzer trace shows that your send buffer and the actual byte endianess on the bus does not correspond, as the READ bit is not set.

    Could you try setting your transfer buffer like this and see if the sensor responds?

    uint8_t m_tx_buf4[] = {0x80, 0x30};

    Kind regards,

    Håkon

Children
  • Hi Hakon,

    The problems were endianess and also the frequency. I had to decrease the frequency according to the peripheral. I am able to communicate with the IC now. But I am facing another problem now. 

    In the attached code. I am placing the break point at every nrf_drv_spi_transfer. But it is not stopping on  2nd and last transfer. This is strange. If I change the order of transfers, the debugger will not stop at some other location. What could be causing this? Is the delay not enough to wait for the completion of previous transfer ? Is it getting stuck somewhere? Can you please have a quick look at this simple code snippet and advise. Thanks,

    #define SPI_INSTANCE  0 /**< SPI instance index. */
    static const nrf_drv_spi_t spi = NRF_DRV_SPI_INSTANCE(SPI_INSTANCE);  /**< SPI instance. */
    static volatile bool spi_xfer_done;  /**< Flag used to indicate that SPI instance completed the transfer. */
    
    
    static uint32_t       config_start =  0b01111000010101100011000000000000;           //0X30H
    static uint32_t       cal_start =     0b01111000010101100100000000000000; 
    static uint32_t       harm_start =    0b01111000010101100110000000000000;           //0X50H
    static uint32_t       adj_start =     0b01111000010101100110000000000000;           //0X60H
    static uint32_t       mmode0 =        0b11000010000010000011001100000000;           //0X60H
    static uint32_t       test =          0b0011000010000000;
    static uint16_t       urmsA =         0b1101100110000000;                           //0XBCH
    static uint16_t       urmsB =         0b1101101010000000;                           //0XBCH
    static uint16_t       urmsC =         0b1101101110000000;                           //0XBCH
    static uint16_t       irmsA =         0b1101110110000000;                           //0XBCH
    static uint16_t       irmsB =         0b1101111010000000;                           //0XBCH
    static uint16_t       irmsC =         0b1101111110000000;                           //0XBCH
    static uint32_t       uoffsetA =      0b00000000000000000110001100000000;           //0X60H
    static uint32_t       uoffsetB =      0b00000000000000000110011100000000;           //0X60H
    static uint32_t       uoffsetC =      0b00000000000000000110101100000000;           //0X60H
    static uint32_t       ioffsetA =      0b00000000000000000110100000000000;           //0X60H
    static uint32_t       ioffsetB =      0b00000000000000000110110000000000;           //0X60H
    static uint32_t       ioffsetC =      0b00000000000000000110110000000000;           //0X60H
    static uint32_t       igainA =        {0x30, 0x75, 0x62, 0x00};                     //0X60H
    static uint32_t       igainA_r =      0b00110000011101010110001000000000;                   //0X60H
               //0X30H
     
    
    static uint8_t       m_rx_buf[4];                                               /**< RX buffer. */
    static const uint8_t  m_length = 4;                                            /**< Transfer length. */
    
    /**
     * @brief SPI user event handler.
     * @param event
     */
    
    
    
    void spi_event_handler(nrf_drv_spi_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));
        }
    }
    
    int main(void)
    {
        bsp_board_init(BSP_INIT_LEDS);
    
        APP_ERROR_CHECK(NRF_LOG_INIT(NULL));
        NRF_LOG_DEFAULT_BACKENDS_INIT();
    
            nrf_drv_spi_config_t spi_config = NRF_DRV_SPI_DEFAULT_CONFIG;
            spi_config.ss_pin   = 47 ;
            spi_config.miso_pin = 43;
            spi_config.mosi_pin = 46;
            spi_config.sck_pin  = 42;
            spi_config.mode = NRF_DRV_SPI_MODE_0;
            spi_config.frequency = NRF_DRV_SPI_FREQ_1M;
            APP_ERROR_CHECK(nrf_drv_spi_init(&spi, &spi_config, spi_event_handler, NULL));
    
            NRF_LOG_INFO("SPI example started.");
    
    
                           
    
            while(1){
          
            memset(m_rx_buf, 0, m_length);
            spi_xfer_done = false;
           
            APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi, &config_start, m_length, m_rx_buf, m_length));
            
                  while (!spi_xfer_done)
            {
                __WFE();
            }
    
            NRF_LOG_FLUSH();
    
    
            bsp_board_led_invert(0);
            nrf_delay_ms(200);  
    
              memset(m_rx_buf, 0, m_length);
            spi_xfer_done = false;
           
            APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi, &cal_start, m_length, m_rx_buf, m_length));
            
                  while (!spi_xfer_done)
            {
                __WFE();
            }
    
            NRF_LOG_FLUSH();
    
    
            bsp_board_led_invert(0);
            nrf_delay_ms(200);
    
             memset(m_rx_buf, 0, m_length);
            spi_xfer_done = false;
           
            APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi, &harm_start, m_length, m_rx_buf, m_length));
            
                  while (!spi_xfer_done)
            {
                __WFE();
            }
    
            NRF_LOG_FLUSH();
    
    
            bsp_board_led_invert(0);
            nrf_delay_ms(200);
    
             memset(m_rx_buf, 0, m_length);
            spi_xfer_done = false;
           
            APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi, &adj_start, m_length, m_rx_buf, m_length));
            
                  while (!spi_xfer_done)
            {
                __WFE();
            }
    
            NRF_LOG_FLUSH();
    
    
            bsp_board_led_invert(0);
            nrf_delay_ms(200);
    
             memset(m_rx_buf, 0, m_length);
            spi_xfer_done = false;
           
            APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi, &igainA_r, m_length, m_rx_buf, m_length));
            
                  while (!spi_xfer_done)
            {
                __WFE();
            }
    
            NRF_LOG_FLUSH();
    
    
            bsp_board_led_invert(0);
            nrf_delay_ms(200);
    
            memset(m_rx_buf, 0, m_length);
            spi_xfer_done = false;
           
            APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi, &irmsA, m_length, m_rx_buf, m_length));
            
                  while (!spi_xfer_done)
            {
                __WFE();
            }
    
            NRF_LOG_FLUSH();
    
    
            bsp_board_led_invert(0);
            nrf_delay_ms(200);
        
    }
    }
    
     

  • Hi,

     

    Is there anything going out on the SPI lines when this occurs?

    When debugging, It is recommend that you keep the optimization level low, if not; the compiler will try to find patterns in your generated code and thus the "normal flow" will not be followed.

    Kind regards,

    Håkon

Related