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

Switching between blocking and non-blocking SPI

Hello,

I'm using the nrf52840 and SDKv16 to interface with an SD card. An SD card block is 512 bytes. I would like to do this:

1. Get the card ready for a write (use blocking SPI)

2. Write 512 bytes to SD card (use non blocking SPI)

3. Send the CRC and wrap up the transfer (use blocking SPI)

Repeat as necessary.

What is the best way of switching between blocking and non blocking modes? I'm working off of this example to set up the SPI transfers: https://devzone.nordicsemi.com/f/nordic-q-a/19891/transfer-more-than-255-bytes-with-spi-master-on-nrf52

But that example doesn't switch between blocking and non blocking. My understanding is that whether or not the transfers happen in a blocking or nonblocking mode when using nrf_drv_spi_xfer depends on whether a handler is specified to nrf_drv_spi_init. Is that correct? This is my code for configuring the SPI controller

void handler_sd_spi(nrf_spim_event_t evt, void *p_ctx) 
{
    SpiXferDone = true;
}

void per_spim_config(const nrf_drv_spi_t *spim_inst,  nrf_drv_spi_config_t *spim_cfg,
    int sclk_freq,
    gpio_t miso_pin, gpio_t mosi_pin, gpio_t sck_pin, gpio_t csn_pin,
    void *handler,
    bool csn_cntl) 
{
    spim_cfg->frequency = sclk_freq;
    spim_cfg->miso_pin = NRF_GPIO_PIN_MAP(miso_pin.port, miso_pin.pin);
    spim_cfg->mosi_pin = NRF_GPIO_PIN_MAP(mosi_pin.port, mosi_pin.pin);
    spim_cfg->sck_pin = NRF_GPIO_PIN_MAP(sck_pin.port, sck_pin.pin);
    if (csn_cntl) {
        spim_cfg->ss_pin = NRF_GPIO_PIN_MAP(csn_pin.port, csn_pin.pin);
    } else {
        spim_cfg->ss_pin = NRFX_SPIM_PIN_NOT_USED;
    } 

    nrf_drv_spi_uninit(spim_inst);
    nrf_drv_spi_init(spim_inst, spim_cfg, handler, NULL);
}

void sd_spi_init(int sclk_freq, void *handler)
{
    nrf_gpio_cfg_output(NRF_GPIO_PIN_MAP(sd_csn.port, sd_csn.pin));
    nrf_gpio_pin_set(NRF_GPIO_PIN_MAP(sd_csn.port, sd_csn.pin));

    per_spim_config(&sd_spim, &sd_spim_cfg, sclk_freq,
        sd_miso, sd_mosi,
        sd_sck, sd_csn,
        handler,
        false);
    // per_spim_enable(&sd_spim);
}

My (possibly wrong) expectation is that whether SPI is in blocking mode depends on how I call sd_spi_init:

sd_spi_init(NRF_DRV_SPI_FREQ_8M, NULL); // blocking SPI
sd_spi_init(NRF_DRV_SPI_FREQ_8M, handler_sd_spi); // non blocking SPI

Currently I can write to the card with blocking SPI, but I would like to be able to do this:

// data is a global variable
sd_wrt_success = sd_write_start(0, data); // set up the card using blocking spi, then start a non blocking write
while (!SpiXferDone); // wait for the handler to be called
SpiXferDone = false; 
sd_write_end(); // put back in blocking mode, send the CRC, etc

When I do this, combining the techniques from the thread I mentioned, and what I've shown, the behavior I get is that the handler is called, but the next time I call sd_write_start, my program hangs. Any ideas? I can post more code if necessary, but a lot of my code is specific to SD cards, and I would prefer a general answer so that I don't have to post too much of it. All the best

Edit:

When I change the handler like this:

void handler_sd_spi(nrf_spim_event_t evt, void *p_ctx) 
{
    if (evt == NRF_SPIM_EVENT_STARTED ||
        evt == NRF_SPIM_EVENT_ENDRX || 
        evt == NRF_SPIM_EVENT_END || 
        evt == NRF_SPIM_EVENT_ENDTX || 
        evt == NRF_SPIM_EVENT_STARTED) {
        SpiXferDone = true;
    }
}

The boolean is never set to true. This could mean a problem with my configuration with regards to SPIM vs SPI... I think? I've attached my sdk_config.h file.sdk_config.h

Parents
  • In  case someone finds this thread who Is having trouble migrating from blocking to non blocking SPI (and needs EasyDMA to write large payloads), the link in the original post is excellent (including the discussion on how to make the DMA controller output the exact number of bytes). That, combined with Kenneth's suggestion of using a flag when you need to block, is what did it for me.

    Beware of NRF_DRV_SPI_FLAG_TX_POSTINC vs NRF_DRV_SPI_FLAG_RX_POSTINC when setting flags for the DMA transfer.

Reply
  • In  case someone finds this thread who Is having trouble migrating from blocking to non blocking SPI (and needs EasyDMA to write large payloads), the link in the original post is excellent (including the discussion on how to make the DMA controller output the exact number of bytes). That, combined with Kenneth's suggestion of using a flag when you need to block, is what did it for me.

    Beware of NRF_DRV_SPI_FLAG_TX_POSTINC vs NRF_DRV_SPI_FLAG_RX_POSTINC when setting flags for the DMA transfer.

Children
No Data
Related