Beware that this post is related to an SDK in maintenance mode
More Info: Consider nRF Connect SDK for new designs
This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

nrf_blk_dev_read_req is called from critical region in the SDK

Hello,

I'm using SDK nrf5_17.0.2 on nrf52840

I'm implementing a custom nrf block device for a spi nand flash, and I'm getting trouble with the calling site of the nrf_blk_dev_read_req call from the usb msc (app_usbd_msc).

nrf_blk_dev_read_req could be called either by app_usbd_msc.c::cmd_read_start or by app_usbd_msc.c:msc::msc_blockdev_ev_handler as shown in the following screenshot:

The call stack from the cmd_read_start is "the normal path" and this path works. The callstack from the msc_blockdev_ev_handler comes from my block device where I have to notify the usb msc stack the status of the block device request (for the example at the end of the read request):


const nrf_block_dev_event_t ev = {
        .ev_type = NRF_BLOCK_DEV_EVT_BLK_READ_DONE,
        .result = NRF_BLOCK_DEV_RESULT_SUCCESS,
        .p_context = p_work->p_context,
        .p_blk_req = p_blk,
};

p_work->ev_handler(p_blk_dev, &ev);

The problem is in the ev_handler (pointing to msc_blockdev_ev_handler) implementation where the _BLK_READ_DONE command is handled like the following:

 case NRF_BLOCK_DEV_EVT_BLK_READ_DONE:
    CRITICAL_REGION_ENTER();
    msc_blockdev_read_done_handler(p_blk_dev, p_event);
    CRITICAL_REGION_EXIT();
    break;

msc_blockdev_read_done_handler is called in a critical region. So following the call stack from this point leads to app_usbd_msc.c::read_block_mem_processor:L950 where nrf_blk_dev_read_req is called if there is still some bytes to process.

The problem is that I currently reading page size (4096 bytes) in the external memory by SPI in a asynchronous way so I'm using SPIM with EasyDMA. And the SPI irq is never called because NVIC->ICER has been clear in CRITICAL_REGION_ENTER.

Why msc_blockdev_read_done_handler has to be called in a critical region ? How can I fix this issue ?

Best

Joël

Parents
  • Hi

    Seems like the snippet wasn't included indeed. Very sorry about that, but here it is:

    #ifdef SOFTDEVICE_PRESENT
    #define CRITICAL_REGION_ENTER() \
     { \
     uint8_t __CR_NESTED = 0; \
     app_util_critical_region_enter(&__CR_NESTED);
    #else
    #define CRITICAL_REGION_ENTER() app_util_critical_region_enter(NULL)
    #endif

    I think you're misunderstanding the interrupts section. Interrupts are disabled during the critical region, but not the events that raise interrupts. This means that if an event raises an interrupt while they're disabled, it will be pending until the critical region is exited, and interrupts are enabled again.

    Best regards,

    Simon

Reply
  • Hi

    Seems like the snippet wasn't included indeed. Very sorry about that, but here it is:

    #ifdef SOFTDEVICE_PRESENT
    #define CRITICAL_REGION_ENTER() \
     { \
     uint8_t __CR_NESTED = 0; \
     app_util_critical_region_enter(&__CR_NESTED);
    #else
    #define CRITICAL_REGION_ENTER() app_util_critical_region_enter(NULL)
    #endif

    I think you're misunderstanding the interrupts section. Interrupts are disabled during the critical region, but not the events that raise interrupts. This means that if an event raises an interrupt while they're disabled, it will be pending until the critical region is exited, and interrupts are enabled again.

    Best regards,

    Simon

Children
No Data
Related