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,

    You cannot switch mode just like that. However, I would assume that the slave device would not matter that there is a delay between the first 16 and last 16 bits, as the clock is anyway generated by the master. The idea is that after transmitting the first 16 bits you initialize the driver to use another mode and receives the 16 bits. It would stretch the transaction so that it looks something like this:

  • Thanks Einar for the explanation, 

    Is this the correct implementation to achieve what you showed in the diagram above ? 

                                                         nrf_drv_spi_transfer (spi, first 16bit data, 2, first 16bit data, 2);

                                                         unint spi

                                                         spi mode-> 3

                                                        nrf_drv_spi_transfer (spi, last 16bit data, 2, last 16bit data, 2);

    I am just confused with the length parameter. if I am specifying 2 bytes of length, will that mean that the CS line will go high after writing 2 bytes ? if that is true, then this implementation will obviously not work. 

    Regards,

  • Hi,

     

    The "nrf_drv_spi_transfer" function will set the CSN active prior to the first byte written. If you require the CSN pin to be kept low (ie: active), then you need to manually control the GPIO. This is done by setting "spi_config.ss_pin = NRF_DRV_SPI_PIN_NOT_USED", then controlling it manually in your own transfer function.

    Best regards,

    Håkon

  • is this the correct implementation ? 

    nrf_drv_spi_uninit(&spi);
    
    nrf_drv_spi_config_t spi_config = NRF_DRV_SPI_DEFAULT_CONFIG;
    spi_config.ss_pin = NRF_DRV_SPI_PIN_NOT_USED;
    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_2;
    APP_ERROR_CHECK(nrf_drv_spi_init(&spi, &spi_config, spi_event_handler, NULL));
    
    nrf_gpio_cfg_output(29);
    nrf_gpio_pin_clear(29);
    
    memset(m_rx_buf, 0, m_length);
    spi_xfer_done = false;
    APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi, &m_tx_buf4, m_length1, m_rx_buf, m_length1));
    NRF_LOG_FLUSH();
    bsp_board_led_invert(3);
    // nrf_gpio_pin_set(BSP_BOARD_LED_0);
    nrf_delay_ms(200);
    
    nrf_drv_spi_uninit(&spi);
    
    nrf_drv_spi_config_t spi_config1 = NRF_DRV_SPI_DEFAULT_CONFIG;
    spi_config.ss_pin = NRF_DRV_SPI_PIN_NOT_USED;
    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_3;
    APP_ERROR_CHECK(nrf_drv_spi_init(&spi, &spi_config1, spi_event_handler, NULL));
    
    
    nrf_gpio_pin_clear(29);
    
    memset(m_rx_buf, 0, m_length);
    spi_xfer_done = false;
    APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi, &m_tx_buf5, m_length1, m_rx_buf, m_length1));
    NRF_LOG_FLUSH();
    bsp_board_led_invert(3);
    // nrf_gpio_pin_set(BSP_BOARD_LED_0);
    nrf_delay_ms(200);
    
    nrf_gpio_pin_set(29);

  • If GPIO 29 is your CSN, then it looks to be handled correctly. The delay calls are redundant, and can be removed.

    Are you able to communicate with the device? How does the scoped signals look?

Reply Children
  • Hi, I talked to the manufacturer. He asked me to check the SPI timings by doing a simple read operation on register 0x30 . I should be reading 0x6886 but i am reading 0Xffff instead. May be because of the pull up resistors on SPI pins ???

    It is a very small code base . I will be glad if you could verify for me if the code is right

    #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;    //0X80BC
    static uint16_t       m_tx_buf5= 0b0000000000000000;
     
     
    
    
    
    static uint16_t       m_rx_buf1[1];    /**< RX buffer. */
    static const uint8_t  m_length1 = 2;        /**< 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_buf1[0] != 0)
        {
            NRF_LOG_INFO(" Received:");
            NRF_LOG_HEXDUMP_INFO(m_rx_buf1, strlen((const char *)m_rx_buf1));
        }
    }
    
    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_config1 = NRF_DRV_SPI_DEFAULT_CONFIG;
            spi_config1.ss_pin   = NRF_DRV_SPI_PIN_NOT_USED;
            spi_config1.miso_pin = SPI_MISO_PIN;
            spi_config1.mosi_pin = SPI_MOSI_PIN;
            spi_config1.sck_pin  = SPI_SCK_PIN;
            spi_config1.mode = NRF_DRV_SPI_MODE_2;
         //   APP_ERROR_CHECK(nrf_drv_spi_init(&spi, &spi_config, spi_event_handler1, NULL));
    
            nrf_drv_spi_config_t spi_config2 = NRF_DRV_SPI_DEFAULT_CONFIG;
            spi_config2.ss_pin   = NRF_DRV_SPI_PIN_NOT_USED;
            spi_config2.miso_pin = SPI_MISO_PIN;
            spi_config2.mosi_pin = SPI_MOSI_PIN;
            spi_config2.sck_pin  = SPI_SCK_PIN;
            spi_config2.mode = NRF_DRV_SPI_MODE_3;
         //   APP_ERROR_CHECK(nrf_drv_spi_init(&spi, &spi_config, spi_event_handler1, NULL));
    
           nrf_gpio_cfg_output(29);
    
        NRF_LOG_INFO("SPI example started.");
    
    
    
      
            while(1){
    
            //initialize with spi config 1
          
            APP_ERROR_CHECK(nrf_drv_spi_init(&spi, &spi_config1, spi_event_handler, NULL));
            
    
            memset(m_rx_buf1, 0, m_length1);
            spi_xfer_done = false;
            //clear CS line
            nrf_gpio_pin_clear(29);
            //Send 80H to BCH to read power factor from BCH register
            APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi, &m_tx_buf4, m_length1, m_rx_buf1, m_length1));
            NRF_LOG_FLUSH();
            bsp_board_led_invert(3);
            nrf_delay_ms(200);
    
            nrf_drv_spi_uninit(&spi);
            APP_ERROR_CHECK(nrf_drv_spi_init(&spi, &spi_config2, spi_event_handler, NULL));
              memset(m_rx_buf1, 0, m_length1);
            spi_xfer_done = false;
            APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi, &m_tx_buf5, m_length1, m_rx_buf1, m_length1));
            NRF_LOG_FLUSH();
            bsp_board_led_invert(2);
            nrf_delay_ms(200);
    
            //set CS pin high again
            nrf_gpio_pin_set(29);
             
              nrf_drv_spi_uninit(&spi);
    
    
            
    
            }
    
    
            
    }
    
    or not .

    I am also attaching the O'scope diagrams of CLK and MOSI line .

     5277.Atmel-46004-SE-M90E36A-Datasheet.pdf

    Thanks,

  • Hi,

     

    Are you able to scope all SPI lines, so that we're able to see that the mode is successfully changed when reading the response from the device?

    Kind regards,

    Håkon

  • This looks like only one part of the SPI communication, the first 16 bits, where you lack the mode switch over to the last 16 bit transfer. Do you have access to a logic analyzer/oscilloscope with 4 channels, so that you can sample all lines simultaneously? 

  • Hi Hakan,

    Unfortunately I have access to only one channel oscilloscope for now. Have ordered one with 4 channels. 

    I have reduced the code base just to see the mode switch. I can only see a consistent 16bit clock with no delay as described in this attached picture. 

    The code does not work as expected . 

            nrf_drv_spi_config_t spi_config1 = NRF_DRV_SPI_DEFAULT_CONFIG;
            spi_config1.ss_pin   = NRF_DRV_SPI_PIN_NOT_USED;
            spi_config1.miso_pin = SPI_MISO_PIN;
            spi_config1.mosi_pin = SPI_MOSI_PIN;
            spi_config1.sck_pin  = SPI_SCK_PIN;
            spi_config1.mode = NRF_DRV_SPI_MODE_2;
         //   APP_ERROR_CHECK(nrf_drv_spi_init(&spi, &spi_config, spi_event_handler1, NULL));
    
            nrf_drv_spi_config_t spi_config2 = NRF_DRV_SPI_DEFAULT_CONFIG;
            spi_config2.ss_pin   = NRF_DRV_SPI_PIN_NOT_USED;
            spi_config2.miso_pin = SPI_MISO_PIN;
            spi_config2.mosi_pin = SPI_MOSI_PIN;
            spi_config2.sck_pin  = SPI_SCK_PIN;
            spi_config2.mode = NRF_DRV_SPI_MODE_3;
         //   APP_ERROR_CHECK(nrf_drv_spi_init(&spi, &spi_config, spi_event_handler1, NULL));
    
           nrf_gpio_cfg_output(29);
    
        NRF_LOG_INFO("SPI example started.");
    
    
    
      
            while(1){
    
            //initialize with spi config 1
          
            APP_ERROR_CHECK(nrf_drv_spi_init(&spi, &spi_config1, spi_event_handler, NULL));
            
    
            memset(m_rx_buf1, 0, m_length1);
            spi_xfer_done = false;
            //clear CS line
            nrf_gpio_pin_clear(29);
            //Send 80H to BCH to read power factor from BCH register
            APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi, &m_tx_buf4, m_length1, m_rx_buf1, m_length1));
            NRF_LOG_FLUSH();
            bsp_board_led_invert(3);
           nrf_delay_ms(200);
    
            nrf_drv_spi_uninit(&spi);
            APP_ERROR_CHECK(nrf_drv_spi_init(&spi, &spi_config2, spi_event_handler, NULL));
              memset(m_rx_buf1, 0, m_length1);
            spi_xfer_done = false;
            APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi, &m_tx_buf5, m_length1, m_rx_buf1, m_length1));
            NRF_LOG_FLUSH();
            bsp_board_led_invert(2);
            nrf_delay_ms(200);
    
            //set CS pin high again
            nrf_gpio_pin_set(29);
             
              nrf_drv_spi_uninit(&spi);
    
    
            
    
            }
    
    
            
    }

    Thanks,

Related