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:
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:
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