FreeRTOS中,中斷優先級設置方法

摘要

FreeRTOS爲了保證實時性要求嚴格的中斷能及時響應,在屏蔽任務切換時,只屏蔽了優先級比較低的部分中斷。而可被屏蔽的這些中斷可以保證內核的臨界區不被破壞,因此這些中斷也能使用部分內核API。在這樣的中斷髮送信號量,可以讓有時序性要求較高的任務或信號量來自於外設的任務及時獲取信號量並運行。

本文將介紹CortxM7的相關中斷寄存器,並說明如何配置FreeRTOS中與中斷有關的宏。最後說明想要運行操作系統內核API的中斷時,該中斷優先級的設置範圍。

另外,本文還額外說明了pvPortMalloc()這個堆內存申請函數不能在中斷中使用的原因。

CortxM7的相關中斷寄存器

參見:《ARM Cortex-M7 Devices Generic User Guide》

1、基礎優先級屏蔽寄存器:

Base Priority Mask Register

The BASEPRI register defines the minimum group priority for exception processing. When

BASEPRI is set to a nonzero value, it prevents the activation of all exceptions with the same or

lower group priority level as the BASEPRI value.

表格下方有一段小注釋,這就是我們從其他二手渠道中知道的優先級寄存器中的值越大,優先級越小的來源。

Remember that higher priority field values correspond to lower exception priorities.

在 Table 4-9中也強調了這一說法:

Each priority field holds a priority value, 0-255. The lower the value, the greater the priority of the corresponding interrupt.

If enabled, the processor can implement only bits[7:n] of each field, bits[n-x:0] read as zero and ignore writes. The values of n and x are implementation defined.

 

stm32h7提供的系統初始化函數中,就設置了默認的中斷分組:

HAL_Init();→HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);→SCB->AIRCR

@arg NVIC_PRIORITYGROUP_4: 4 bits for preemption priority,   0 bits for subpriority

#define NVIC_PRIORITYGROUP_4         ((uint32_t)0x00000003) /*!< 4 bits for pre-emption priority

                                                                 0 bits for subpriority */

 

2、在應用中斷和復位控制寄存器中設置中斷優先級分組

Application Interrupt and Reset Control Register

The AIRCR provides priority grouping control for the exception model, endian status for data

accesses, and reset control of the system. See the register summary in Table 4-12 on page 4-11

and Table 4-17 on page 4-18 for its attributes.

To write to this register, you must write 0x5FA to the VECTKEY field, otherwise the processor

ignores the write.

Bits

 Name

 Type

Function

[10:8]

 PRIGROUP

 RW

 Interrupt priority grouping field. This field determines the split of group priority from subpriority, see Binary point on page 4-19.

 

 

FreeRTOS有如下與中斷優先級有關的宏定義

在FreeRTOSConfig.h文件中,有如下宏:(這裏的宏定義已經與前文的程序向匹配)

/* Cortex-M specific definitions. */

#ifdef __NVIC_PRIO_BITS

        /* __BVIC_PRIO_BITS will be specified when CMSIS is being used. */

        #define configPRIO_BITS                       __NVIC_PRIO_BITS

#else

        #define configPRIO_BITS                       4        /* 15 priority levels */

#endif

 

/* The lowest interrupt priority that can be used in a call to a "set priority"

function. */

#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY                        0xf

/* The highest interrupt priority that can be used by any interrupt service

routine that makes calls to interrupt safe FreeRTOS API functions.  DO NOT CALL

INTERRUPT SAFE FREERTOS API FUNCTIONS FROM ANY INTERRUPT THAT HAS A HIGHER

PRIORITY THAN THIS! (higher priorities are lower numeric values. */

#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY        5

 

/* Interrupt priorities used by the kernel port layer itself.  These are generic

to all Cortex-M ports, and do not rely on any particular library functions. */

#define configKERNEL_INTERRUPT_PRIORITY                 ( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )

/* !!!! configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to zero !!!!

See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html. */

#define configMAX_SYSCALL_INTERRUPT_PRIORITY         ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )

 基本中斷屏蔽是通過如下程序實現的:


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. */
		cpsid i
		msr basepri, ulNewBASEPRI
		dsb
		isb
		cpsie i
	}
}

結論

具體設置使用下面這個函數:

HAL_NVIC_SetPriority(IRQn_Type IRQn, uint32_t PreemptPriority, uint32_t SubPriority)

需要注意的是:這個函數是基於優先級分組爲NVIC_PRIORITYGROUP_4  設計的,所有搶佔優先級和子優先級都被程序限定在了0~15,如果自己想要充分系統CortexM7的優先級特性,則可以自己寫個函數替代此函數。

根據文中前面的設置,當前僅當

PreemptPriority=[configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY1 :configLIBRARY_LOWEST_INTERRUPT_PRIORITY]

時,程序在運行xxxxFromISR()這樣的函數時,程序不會陷入taskENTER_CRITICAL();斷言中而出不來。

應用及延伸;pvPortMalloc不能在中斷中使用

1、程序原因

void *pvPortMalloc( size_t xWantedSize )→BaseType_t xTaskResumeAll( void )→void vPortEnterCritical( void )

void vPortEnterCritical( void )
{
	portDISABLE_INTERRUPTS();
	uxCriticalNesting++;

	/* This is not the interrupt safe version of the enter critical function so
	assert() if it is being called from an interrupt context.  Only API
	functions that end in "FromISR" can be used in an interrupt.  Only assert if
	the critical nesting count is 1 to protect against recursive calls if the
	assert function also uses a critical section. */
	if( uxCriticalNesting == 1 )
	{
		configASSERT( ( portNVIC_INT_CTRL_REG & portVECTACTIVE_MASK ) == 0 );
	}
}

2、邏輯原因:heap4的堆需要通過堆鏈表來維護,在修改和分配堆的過程中,顯然不能在另一個進程中修改。雖然在100MHz主頻的單片機下第一次獲取棧只使用了9μs,但不能保證堆鏈表比較複雜的時候會需要多長時間才能申請到內存。

發佈了25 篇原創文章 · 獲贊 5 · 訪問量 8204
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章