Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

The method of Protection switch interrupt and entry and exit in the critical Section of freertos Real-time operating system

2025-03-29 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/01 Report--

Today, I would like to share with you about the critical section of the freertos real-time operating system to protect the switch interrupt and enter and exit the relevant knowledge, detailed content, clear logic, I believe that most people still know too much about this knowledge, so share this article for your reference, I hope you can get something after reading this article, let's take a look at it.

Interruption basics nesting:

Nested vector interrupt controller NVIC (Nested Vectored Interrupt Controller is tightly coupled to the kernel. Provide the following functions: nested interrupt support, vector interrupt support, dynamic priority adjustment support, interrupt delay greatly shortened, interrupts can be shielded.

All external interrupts and most system exceptions support nested interrupts. Exceptions can be given different priorities, and the current priority is stored in a dedicated field of xPSR. When an exception occurs, the hardware automatically compares the priority of the exception with the current exception priority, and if it is found that the exception has a higher priority, the processor will interrupt the current interrupt service routine (or ordinary program). And serve the new exception (immediate preemption).

If the priority group setting makes the interrupt nesting deep, make sure that there is enough space in the main stack. Exception servers always use MSP, and the capacity of the main stack should be the amount needed for the deepest nesting.

Priority:

CM3 supports interrupt nesting so that high-priority exceptions preempt (preempt) low-priority exceptions.

There are three system exceptions: reset, NMI, and hard fault, which have a fixed priority and the priority number is negative, higher than all other exceptions. The priority of all other exceptions is programmable (but cannot be programmed to negative).

CM3 supports 3 fixed high priorities and up to 256 programmable priorities, as well as level 128 preemption. But most CM3 chips actually support fewer priorities such as level 8, level 16, level 32, and so on.

Cut out several low-end significant bits that express priority, thus reducing the number of priorities. If more bits are used to express priority, the number of priorities increases, and more doors are needed, resulting in more cost and power consumption.

Three bits are used to express priority. The structure of the priority configuration register is shown in the following figure. The eight priorities that can be used are: 0x00 (highest), 0x20prime0x40meme0x60memo0x80,0xA0mem0xC0pen0xE0.

In order to make the preemption function more controllable, CM3 divides the 256-level priority into high and low bits, which are preemption priority and sub-priority. Preemption priority determines preemption behavior. When more than one exception with the same preemptive priority is suspended, it gives priority to responding to the exception with the highest sub-priority (sub-priority housekeeping).

Priority grouping states that the sub-priority is at least 1 bit. So the priority of preemption is at most 7 bits, and there is only a phenomenon of level 128 preemption at most.

The following figure shows that only 3 bits are used to express priority, grouped from bit5 to get level 4 preemptive priority, with two sub-priorities inside each preemptive priority.

The following figure is a 3-bit priority, grouped from bit 1, (although [4:0] is not used, grouping from them is allowed).

The application interrupt and reset control register (AIRCR) (address: 0xE000_ED00) is as follows.

Suspension and release of interruption:

When an interrupt occurs, a peer or high priority exception is being processed, or is masked, the interrupt cannot be responded immediately. At this point, the interrupt is suspended.

You can read the suspension state of an interrupt by setting the suspension register (SETPEND) and the interrupt suspension clear register (CLRPEND), and you can write them to manually suspend the interrupt.

Tail bite interrupts Tail-Chaining:

When the processor responds to an exception, if its high priority exception occurs again, the current exception is blocked and the high priority exception is executed instead. Then after the exception is returned, when the system handles the suspended exception, if you POP first and then PUSH the POP, this is a waste of CPU time.

So instead of POP these registers, CM3 continues to use the results of the previous exception that have already been PUSH. This is shown in the following figure.

Late high priority exception:

In the stack phase, when the service routine has not been executed, if the request with high priority exception is received, the service routine with high priority exception will be executed after entering the stack. If the high priority exception comes so late that the previous exception instruction has been executed, the normal preemption processing will require more processor time and an additional 32 bytes of stack space. After the execution of the high priority exception, the previously preempted exception is executed in the way of tail-biting interruption.

Turn on interrupt and off interrupt instruction in cortex-m

Critical segment: a piece of code that cannot be interrupted during execution (a code segment that must be fully run and cannot be interrupted). Generally speaking, the critical section is used when operating on global variables. When a task accesses a global variable, if it is interrupted by other interrupts, the global variable is changed, and when it goes back to the previous task, the global variable is no longer what it was then, which may lead to unintended consequences.

The situation in which the critical section is interrupted: system scheduling (and eventually PendSV interruptions); external interrupts.

When freertos enters the critical section code, it needs to turn off the interrupt, and then turn on the interrupt after processing the critical section code.

First, take a look at the following code.

_ _ asm void prvStartFirstTask (void) {PRESERVE8/* in Cortex-M, 0xE000ED08 is the address of the SCB_VTOR register, which contains the starting address of the vector table That is, the address of MSP * / ldr R0, = 0xE000ED08ldr R0, [R0] ldr R0, [R0] / * sets the value of the main stack pointer msp * / msr msp, R0 cpsie icpsie fdsbisb/* * enables global interruptions * / cpsie icpsie fdsbisb/* calls SVC to start the first task * / svc 0nopnop} _ asm void vPortSVCHandler (void) {extern pxCurrentTCB PRESERVE8ldr R3, = pxCurrentTCB / * load the address of pxCurrentTCB to R3 * / ldr R1, [R3] / * load pxCurrentTCB to R1 * / ldr R0, and [R1] / * load the value pointed to by pxCurrentTCB to R0. At present, the value of R0 is equal to the top of the first task stack * / ldmia R0, and {r4-r11} / * is based on R0. Load the contents of the stack into the r4~r11 register, while R0 increments * / msr psp, R0 / * updates the value of R0, that is, the stack pointer of the task to psp * / isbmov R0, # 0 / * sets the value of R0 to 0 * / msr basepri, R0 / * sets the value of the basepri register to 0 That is, all interrupts are not blocked * / orr R14, # 0xdbx R14} _ asm void xPortPendSVHandler (void) {extern pxCurrentTCB Extern vTaskSwitchContext When PRESERVE8/* enters PendSVC Handler, the environment in which the last task is run is: xPSR,PC (task entry address), R14, xPSR,PC, R12, R3, R2, R1, and R0 (the formal parameter of the task). The values of these CPU registers are automatically saved to the task stack. The remaining r4~r11 needs to manually save * / / * get the task stack pointer to R0 * / mrs R0, pspisbldr R3, = pxCurrentTCB / * load the address of pxCurrentTCB to R3 * / ldr R2, [R3] / * load pxCurrentTCB to R2 * / stmdb R0, {r4-r11} / * store the value of CPU register r4~r11 to the address pointed to by R0 * / str R0 [R2] / * Store the new top pointer of the task stack to the first member of the current task TCB That is, the pointer at the top of the stack * / stmdb spares, {R3, R14} / * temporarily push R3 and R14 into the stack * / mov R0, # configMAX_SYSCALL_INTERRUPT_PRIORITY / * enter the critical section * / msr basepri, r0dsbisbbl vTaskSwitchContext / * call the function vTaskSwitchContext Find a new task to run, switch tasks to * / mov R0, # 0 / * exit the critical section * / msr basepri, r0ldmia spares, {R3, R14} / * recover R3 and R14 * / ldr R1, [R3] ldr R0 by making the variable pxCurrentTCB point to the new task. [R1] / * the first item of the currently active task TCB saves the top of the task stack, and now the top value of the stack is stored in R0*/ldmia r0tasks, {r4-r11} / * out of the stack * / msr psp, r0isbbx r14nop} cpsie icpsie fmsrbasepri, r0cpsie icpsie fmsrbasepri, R0

In order to quickly switch on and off interrupts, CM3 specifically sets the CPS instruction, which can be used in four ways.

CPSID I; PRIMASK=1,; off interrupt CPSIE I; PRIMASK=0,; on interrupt CPSID F; FAULTMASK=1,; off exception CPSIE F; FAULTMASK=0; on exception

As you can see, the above instructions are still controlled PRIMASK and FAULTMASK registers.

As shown in the following figure, global interrupts can be turned on or off through the CPS instruction.

Basepri is an interrupt mask register. In the following setting, interrupts with priority greater than or equal to 11 will be masked. It is equivalent to turning off the interrupt to enter the critical section.

Mov r0, # configMAX_SYSCALL_INTERRUPT_PRIORITY msr basepri, r0/*#define configMAX_SYSCALL_INTERRUPT_PRIORITY 191 / * the top four bits are valid, that is, equal to 0xb0, or the conversion of 11 * / 191 to binary is 11000000, and the high four bits is 1100 bits /

The following code: interrupts with priority higher than 0 are shielded, which is equivalent to opening interrupts to exit the critical segment.

Mov R0, # 0 / * exit critical section * / msr basepri, R0

Off interrupt and on interrupt

The following code, with the return value means: when writing a new value to BASEPRI, first save the value of BASEPRI, and update the value of BASEPRI, return the previously saved value of BASEPRI, and pass the returned value into the open interrupt function as a formal parameter.

No return value means: when writing a new value to BASEPRI, you do not need to save the BASEPRI value first, regardless of the current interrupt state, since you do not care about the current interrupt state, it means that such a function cannot be called in the interrupt.

/ * portmacro.h*//* has no return value and cannot be nested, and cannot use * / # define portDISABLE_INTERRUPTS () vPortRaiseBASEPRI () / * open interrupt function without interrupt protection * / # define portENABLE_INTERRUPTS () vPortSetBASEPRI (0) / * close break function with return value, and can be nested You can use * / # define portSET_INTERRUPT_MASK_FROM_ISR () ulPortRaiseBASEPRI () / * open interrupt function with interrupt protection * / # define portCLEAR_INTERRUPT_MASK_FROM_ISR (x) vPortSetBASEPRI (x) # define configMAX_SYSCALL_INTERRUPT_PRIORITY 191 / * in interrupts, which is equal to 0xb0 Or 11 * / / * Guanzhong break function with no return value * / static portFORCE_INLINE void vPortRaiseBASEPRI (void) {uint32_t ulNewBASEPRI = configMAX_SYSCALL_INTERRUPT_PRIORITY / * Guanzhong break function without return value * / static portFORCE_INLINE void vPortRaiseBASEPRI (void) {uint32_t ulNewBASEPRI = configMAX_SYSCALL_INTERRUPT_PRIORITY; _ asm {/ * Set BASEPRI to the max syscall priority to effect a critical section. * / msr basepri, ulNewBASEPRI dsb isb}} / * Guanzhong break function with return value * / static portFORCE_INLINE uint32_t ulPortRaiseBASEPRI (void) {uint32_t ulReturn, ulNewBASEPRI = configMAX_SYSCALL_INTERRUPT_PRIORITY; _ asm {/ * Set BASEPRI to the max syscall priority to effect a critical section. * / mrs ulReturn, basepri msr basepri, ulNewBASEPRI dsb isb} return ulReturn } / * Open-interrupt function without interrupt protection differs from open-interrupt function with interrupt protection in the parameter value * / static portFORCE_INLINE void vPortSetBASEPRI (uint32_t ulBASEPRI) {_ _ asm {/ * Barrier instructions are not used as this function is only used to lower the BASEPRI value. * / msr basepri, ulBASEPRI}} enter and exit the critical section

For cases without interrupt protection, the uxCriticalNesting in the vPortEnterCritical function is a global variable that records the number of critical segment nesting. The vPortExitCritical function reduces the uxCriticalNesting by one each time, and only when uxCriticalNesting = 0 will the portENABLE_INTERRUPTS function be called to enable interruptions. In this way, when there are multiple critical sections of code, the protection of other critical segments will not be interrupted because of the exit of one critical section code, but will be interrupted only after all the critical segment codes have been exited.

With interrupt protection, it is mainly to save the value of BASEPRI when writing a new value to BASEPRI, and when the value of BASEPRI is updated, the previously saved value of BASEPRI is returned, and the returned value is passed into the open interrupt function as a formal parameter.

/ * enter the critical section without interruption protection * / # define taskENTER_CRITICAL () portENTER_CRITICAL () / * exit the critical section without interruption protection * / # define taskEXIT_CRITICAL () portEXIT_CRITICAL () / * enter the critical section with interruption protection Can nest * / # define taskENTER_CRITICAL_FROM_ISR () portSET_INTERRUPT_MASK_FROM_ISR () / * exit the critical section with interrupt protection, and can nest * / # define taskEXIT_CRITICAL_FROM_ISR (x) portCLEAR_INTERRUPT_MASK_FROM_ISR (x) / * enter the critical section without interrupt protection * / # define portENTER_CRITICAL () vPortEnterCritical () / * exit the critical section Without interrupt protection * / # define portEXIT_CRITICAL () vPortExitCritical () / * enters the critical section, with interrupt protection, you can nest * / # define portSET_INTERRUPT_MASK_FROM_ISR () ulPortRaiseBASEPRI () / * to exit the critical section, with interrupt protection, you can nest * / # define portCLEAR_INTERRUPT_MASK_FROM_ISR (x) vPortSetBASEPRI (x) / * to enter the critical section. Without interrupt protection * / void vPortEnterCritical (void) {/ * the cut-off function with no return value cannot be nested and cannot be used in interrupts with * / portDISABLE_INTERRUPTS () UxCriticalNesting++; if (uxCriticalNesting = = 1) {configASSERT ((portNVIC_INT_CTRL_REG & portVECTACTIVE_MASK) = = 0);}} / * exit the critical section without interruption protection * / void vPortExitCritical (void) {configASSERT (uxCriticalNesting); uxCriticalNesting-- If (uxCriticalNesting = = 0) {/ * Open interrupt function without interrupt protection * / portENABLE_INTERRUPTS ();}} / * enters the critical section with interrupt protection, and can be nested * / static portFORCE_INLINE uint32_t ulPortRaiseBASEPRI (void) {uint32_t ulReturn, ulNewBASEPRI = configMAX_SYSCALL_INTERRUPT_PRIORITY _ _ asm {/ * Set BASEPRI to the max syscall priority to effect a critical section. * / mrs ulReturn, basepri msr basepri, ulNewBASEPRI dsb isb} return ulReturn } / * exits the critical section with interrupt protection and can nest * / static portFORCE_INLINE void vPortSetBASEPRI (uint32_t ulBASEPRI) {_ _ asm {/ * Barrier instructions are not used as this function is only used to lower the BASEPRI value. * / msr basepri, ulBASEPRI}} / * the application of critical section code * / / * in the case of interruption, the critical segment can be nested * / {uint32_t ulReturn; / * into the critical section, and the critical segment can be nested * / ulReturn = taskENTER_CRITICAL_FROM_ISR () / * critical section code * / / * exit critical section * / taskEXIT_CRITICAL_FROM_ISR (ulReturn);} / * in non-interrupted situations, critical section cannot be nested * / {/ * enter critical section * / taskENTER_CRITICAL (); / * critical section code * / * exit critical section * / taskEXIT_CRITICAL () } these are all the contents of this article entitled "the method of protecting switch interrupts and entry and exit in the critical section of freertos real-time operating system". Thank you for reading! I believe you will gain a lot after reading this article. The editor will update different knowledge for you every day. If you want to learn more knowledge, please pay attention to the industry information channel.

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report