LPC11x CortexM0 - optional PRIMASK emulation for low IRQ latency

Dear community,

this revision of the port is a follow up on the current version available in the latest posts.

It is based on the Keil toolchain, but should be rather easy to port to LPCXpresso syntax.

This version enables the user to choose from two system level options:

a) interrupts shall be turned off completely during a task switch
b) the Cortex-M3 BASEPRI register behavior shall be emulated

this is chosen by means of the configuration constant configEMULATE_BASEPRIO


Case A - BASEPRI is not emulated:

The port has a compatible behavior with the former versions, since:

- critical sections are implemented by disabling the interrupts globally

- the interrupts are disabled around the task switch function (in PendSV) only if configKERNEL_INTERRUPT_PRIORITY!= configMAX_SYSCALL_INTERRUPT_PRIORITY (if they are equal, there can be no preemption by hardware)

- the user can specify different priority levels for the kernel and OS-related interrupts (which can make OS API calls)

- the user can specify interrupts at priority higher than configMAX_SYSCALL_INTERRUPT_PRIORITY which are not allowed by design to make OS API calls

Example: configKERNEL_INTERRUPT_PRIORITY= 3, configMAX_SYSCALL_INTERRUPT_PRIORITY = 2, other non-OS interrupts can use priority 1 or 0

Case B - BASEPRI is emulated:

The critical sections must ensure that Systick and the OS-related interrupts are disabled, so that there is no preemption.

Critical sections are implemented by disabling selectively only those user defined interrupts which can cause a preemption (by calling OS APIs) during a critical section

Within PendSV disabling of the SysTick can be avoided, since PendSv and SysTick are always at the same priority by OS design (so they will not preempt each other by NVIC hardware guarantee)

Since SysTick does not have a disable bit within the NVIC, the port must clear the TICKINT bit within the control register.  To do this, the control register can be only written, since reading the register would clear the SysTick COUNTFLAG bit.

The user interrupts are disabled via the NVIC set / clear registers ICER/ISER.

For tracking the status of the NVIC, a 32-bit variable is used. Although it could be done by manipulating the NVIC directly, during the critical sections it allows to replace a read/modify/write of the NVIC register content with just a write of the mask value when enabling the "user" interrupts.

- emulating the BASEPRI register behavior still requires disabling the interrupts globally. This time is tentatively kept to a minimum, being as short as possible

- the user needs to provide additional configuration options, as described in the comments of the FreeRTOSConfig.h file. The user must specify:

    1. if SysTick is used for the OS (configUSE_SYSTICK), this since some implementations (like the M0 on the LPC4300) might not have SysTick, or if another timer should be used.
    2. the systick source clock (configSYSTICK_CLKSOURCE), applicable if SysTick is used
    3: a static mask which defines which interrupts can make OS calls (bit 0 <> user interrupt #0, bit 31 <> user interrupt 31)

- a slight restriction with regard to the application code, to Enable or Disable a single interrupt within a task or an ISR, the NVIC_EnableIRQ / NVIC_DisableIRQ calls must be replaced with with portENABLE_ISR() / portDISABLE_ISR() function calls. These take the same IRQn_Type parameter as the NVIC call.


Hope this is useful....testing and comments are always welcome =)




Please sign in to leave a comment.