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

CRITICAL_REGION_EXIT with Timer and UART interrupts

Hi All,

I have some code that I'm porting from a Zilog platform over to the nRF52 platform.  The code uses 1 timer and 1 uart.  The goal of the code is to handle RS485 messages.

First, a quick question on the timer, I'm using the following function:

nrf_drv_timer_extended_compare(&TIMER_MB, NRF_TIMER_CC_CHANNEL0, time_ticks, NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK, true);

This is from the timer example.  Am I correct that this timer will continue to call interrupts at the specified rate until I specifically call nrf_drv_timer_disable?   

Second part of the question, is I'm using the following to setup a UART:

APP_UART_FIFO_INIT(&comm_params, UART_RX_BUF_SIZE, UART_TX_BUF_SIZE, uart_error_handle, APP_IRQ_PRIORITY_LOWEST, err_code);

(I've run the example and had everything running with putty, a windows serial program using rs232 protocol.)

For my RS485 app I need to toggle when the device can read and when it transmit.  What I'm currently doing is app_uart_close(),  and then redefine the port in the desired mode.

My real question is, I perform "CRITICAL_REGION_ENTER() "  when making changes to the UART and after everything is setup I perform "CRITICAL_REGION_EXIT()"

my problem is for some reason it is triggering a NRF_BREAKPOINT_COND    at CRITICAL_REGION_EXIT() when stepping through in debug mode.  (I'm running in SEGGER Embedded Studio.)

Any thoughts?  Should I be using different functions to toggle the UART setup?

thanks!

Bob

Parents
  • CRITICAL_REGION_ENTER() is defined in app_util_platform.h like this:

    #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

    app_util_critical_region_enter() is defined in app_util_platformc. like this:

    void app_util_critical_region_enter(uint8_t *p_nested)
    {
    #if __CORTEX_M == (0x04U)
    ASSERT(APP_LEVEL_PRIVILEGED == privilege_level_get())
    #endif

    #if defined(SOFTDEVICE_PRESENT)
    /* return value can be safely ignored */
    (void) sd_nvic_critical_region_enter(p_nested);
    #else
    app_util_disable_irq();
    #endif
    }

    Note the ASSERT() that checks the current privilege level.

    The ARM Cortex-M4 supports a couple of different execution states:

    - handler mode (you're executing in an exception handler/interrupt service routine)

    - thread mode (you're *not* executing in an exception handler)

    Also, thread mode has two execution modes: privileged and unprivileged. (Handler mode is always privileged.) You can control the privilege state by setting a bit in the CONTROL register. If you have an RTOS, it's permitted to have some threads run in privileged state and others in unprivileged state. The unprivileged ones will not be able to affect critical system state. The system control block, NVIC and a few other things will be off limits. (You also can't change the CONTROL register from unprivileged state, so if you make yourself unprivileged, the only way to change back is through an exception handler.)

    Critical regions are guarded by enabling/disabling interrupts using the "cpsid i" instruction. This is a privileged instruction. If you use it from thread mode in the unprivileged state, it has no effect (it becomes a no-op). The ASSERT above is intended to trap cases where people are tying to use this mechanism from an unprivileged state since obviously it won't work, and this would thwart your attempt to guard a critical section.

    Lastly, if the ASSERT() fails, it will execute a breakpoint trap instruction.

    The implication here is that somehow you've set up your system so that your application code is executing in unprivileged thread mode, and you're getting an ASSERT() that's trying to tell you you're attempting to perform a privileged operation. I'm not sure how things ended up this way since I don't think the nRF52 SDK tries to use unprivileged thread mode.

    -Bill

Reply
  • CRITICAL_REGION_ENTER() is defined in app_util_platform.h like this:

    #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

    app_util_critical_region_enter() is defined in app_util_platformc. like this:

    void app_util_critical_region_enter(uint8_t *p_nested)
    {
    #if __CORTEX_M == (0x04U)
    ASSERT(APP_LEVEL_PRIVILEGED == privilege_level_get())
    #endif

    #if defined(SOFTDEVICE_PRESENT)
    /* return value can be safely ignored */
    (void) sd_nvic_critical_region_enter(p_nested);
    #else
    app_util_disable_irq();
    #endif
    }

    Note the ASSERT() that checks the current privilege level.

    The ARM Cortex-M4 supports a couple of different execution states:

    - handler mode (you're executing in an exception handler/interrupt service routine)

    - thread mode (you're *not* executing in an exception handler)

    Also, thread mode has two execution modes: privileged and unprivileged. (Handler mode is always privileged.) You can control the privilege state by setting a bit in the CONTROL register. If you have an RTOS, it's permitted to have some threads run in privileged state and others in unprivileged state. The unprivileged ones will not be able to affect critical system state. The system control block, NVIC and a few other things will be off limits. (You also can't change the CONTROL register from unprivileged state, so if you make yourself unprivileged, the only way to change back is through an exception handler.)

    Critical regions are guarded by enabling/disabling interrupts using the "cpsid i" instruction. This is a privileged instruction. If you use it from thread mode in the unprivileged state, it has no effect (it becomes a no-op). The ASSERT above is intended to trap cases where people are tying to use this mechanism from an unprivileged state since obviously it won't work, and this would thwart your attempt to guard a critical section.

    Lastly, if the ASSERT() fails, it will execute a breakpoint trap instruction.

    The implication here is that somehow you've set up your system so that your application code is executing in unprivileged thread mode, and you're getting an ASSERT() that's trying to tell you you're attempting to perform a privileged operation. I'm not sure how things ended up this way since I don't think the nRF52 SDK tries to use unprivileged thread mode.

    -Bill

Children
No Data
Related