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

SPI event DONE too early?

Hello,

currently, I am trying to get the SPI (master with EasyDMA) to work. I interfaced it with an LED driver IC, which needs some signaling (via GPIO pins) along with the SPI clock and data. More specifically, I need to set a GPIO pin low, then send 2 to 14 bytes via SPI, then set the GPIO pin high again for the IC to process the data.

The problem is that my SPI handler get called a bit too early with the NRF_DRV_SPI_EVENT_DONE event. If I then instantly set my GPIO pin high, the SPI transfer seems not to have finished yet (about 8 bits missing at 8 Mbps). If I first wait 1 µs by calling nrf_delay_us(1); before setting the pin high, everything works fine. But this really shouldn't be the resolution to the problem when using events and handles, should it?

Edit: the problem seems to predominantly happen upon 2-byte packets.

Any ideas how to fix the problem other than delaying execution?

Thanks, NewtoM


Major edit:

OK, here is the code I test with

// defines
#define SPI_CLK_PIN                    (22)
#define SPI_DAT_PIN                    (23)
#define SPI_SS_PIN                     (2)                        
#define SPI_DEBUG_PIN                  (31)                        
#define SPI_BUFFER_SIZE                (14)

// global variables
static const nrf_drv_spi_t m_spi0= NRF_DRV_SPI_INSTANCE(0);
static uint8_t m_SPI_TX_buffer[SPI_BUFFER_SIZE]= {0};

// SPI event handler
static void spi0_handler(nrf_drv_spi_evt_t const * p_event)
{
  if (p_event->type == NRF_DRV_SPI_EVENT_DONE)
  {
    // set DEBUG pin
    nrf_gpio_pin_clear(SPI_DEBUG_PIN);
  }
}

int main(void)
{
  // configure GPIOs
  nrf_gpio_cfg(SPI_CLK_PIN, NRF_GPIO_PIN_DIR_OUTPUT, NRF_GPIO_PIN_INPUT_DISCONNECT, NRF_GPIO_PIN_NOPULL, NRF_GPIO_PIN_S0S1, NRF_GPIO_PIN_NOSENSE);      
  nrf_gpio_cfg(SPI_DAT_PIN, NRF_GPIO_PIN_DIR_OUTPUT, NRF_GPIO_PIN_INPUT_DISCONNECT, NRF_GPIO_PIN_NOPULL, NRF_GPIO_PIN_S0S1, NRF_GPIO_PIN_NOSENSE);   
  nrf_gpio_cfg(SPI_SS_PIN, NRF_GPIO_PIN_DIR_OUTPUT, NRF_GPIO_PIN_INPUT_DISCONNECT, NRF_GPIO_PIN_NOPULL, NRF_GPIO_PIN_S0S1, NRF_GPIO_PIN_NOSENSE);
  nrf_gpio_cfg(SPI_DEBUG_PIN, NRF_GPIO_PIN_DIR_OUTPUT, NRF_GPIO_PIN_INPUT_DISCONNECT, NRF_GPIO_PIN_NOPULL, NRF_GPIO_PIN_S0S1, NRF_GPIO_PIN_NOSENSE);
  
  // set SPI configuration
  nrf_drv_spi_config_t const SPI_config =
  {
    .sck_pin= SPI_CLK_PIN,
    .mosi_pin= SPI_DAT_PIN,
    .miso_pin= NRF_DRV_SPI_PIN_NOT_USED,
    .ss_pin= SPI_SS_PIN,
    .irq_priority= SPI0_CONFIG_IRQ_PRIORITY,
    .orc= 0x00,
    .frequency= NRF_DRV_SPI_FREQ_8M,
    .mode= NRF_DRV_SPI_MODE_0,
    .bit_order= NRF_DRV_SPI_BIT_ORDER_MSB_FIRST
  };
  
  // SPI init
  nrf_drv_spi_init(&m_spi0, &SPI_config, spi0_handler);
  
  // main loop
  for (;;)
  {
    // clear DEBUG pin (will be set again from the SPI event handler)
    nrf_gpio_pin_clear(SPI_DEBUG_PIN);

    // start SPI transfer
    nrf_drv_spi_transfer(&m_spi0, SPI_data, SPI_BUFFER_SIZE, NULL, 0);
    
    // wait some time
    nrf_delay_ms(250);
  }
}

Now, if I disable EasyDMA in nrf_drv_config.h via #define SPI0_USE_EASY_DMA 0, then I see the following sequences on my scope:

image description

We see that the slave select pin (SPI_SS_PIN) being low embraces the SPI activity, which is good. Furthermore, my SPI_DEBUG_PIN, which was set low just before calling nrf_drv_spi_transfer() and set high once the NRF_DRV_SPI_EVENT_DONE arrived, is low for just a bit longer than the SPI_SS_PIN, which is correct.

Now, if I do use EasyDMA (#define SPI0_USE_EASY_DMA 1 in nrf_drv_config.h), the picture changes a lot:

image description

Now, the NRF_DRV_SPI_EVENT_DONE event arrives well before the actual SPI transfer has finished. (Maybe it arrives once the EasyDMA transfer has finished, but not the SPI itself?) My questions are:

  • Is this by design?
  • Can I do anything about it? I'd need the NRF_DRV_SPI_EVENT_DONE event fire only when the SPI transaction has ended, not before.
  • How is it possible that the event gets fired too early, but the SPI_SS_PIN is set high at the right time?
  • If no other solutions are possible, is a workaround viable, where an event gets generated once the SPI_SS_PIN becomes high? If yes, how to do that?

Thank you! NewtoM

Related