2.FreeRTOS中斷優先級和任務優先級


FreeRTOS中斷優先級和任務優先級

  • 架構:Cortex-M3

  • 版本:FreeRTOS V9.0.0

  • 前言:

    最開始,我並沒有搞清楚什么是中斷優先級和任務優先級,但看了部分資料后發現這兩個並沒有半毛錢關系,於是便有了這篇筆記,本篇文章以Cortex-M3(STM32F103)為例子。

1.Cortex-M3的中斷優先級

​ 根據Cortex-M3權威指南,每個外部中斷都有一個可編程的中斷優先級寄存器。並且記住優先級越大在這個寄存器的值是越小的。在STM32F103中,該寄存器的高四位才是代表優先級值,低四位沒用。

​ 優先級分組寄存器PRIGROUP,把優先級分為搶占優先級和子優先級,一般為了方便,我們把它設為NVIC_PriorityGroup_4,意思就是4個bit都為搶占優先級,所以一共是0~15個級別的優先級,0的最優先級大,15的最優先級小。

1.1 PendSV和SysTick的中斷優先級

​ 在FreeRTOS中SysTickPendSV的優先級都是最低的,具體在開啟調度器函數BaseType_t xPortStartScheduler( void )里面賦值:

	/* Make PendSV and SysTick the lowest priority interrupts. */
	portNVIC_SYSPRI2_REG |= portNVIC_PENDSV_PRI;
	portNVIC_SYSPRI2_REG |= portNVIC_SYSTICK_PRI;

portNVIC_SYSPRI2_REG實際上是0xE000_ED20-0xE000_ED23(一共四字節),22-23分別是設置PendSV和Systick優先級的寄存器。portNVIC_PENDSV_PRIportNVIC_SYSTICK_PRI**的值具體展開:


1. #define __NVIC_PRIO_BITS          4 /*!< STM32 uses 4 Bits for the Priority Levels    */
2. #define configPRIO_BITS       		__NVIC_PRIO_BITS

3. #define configLIBRARY_LOWEST_INTERRUPT_PRIORITY			15         //中斷最低優先級

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

5.#define portNVIC_PENDSV_PRI					( ( ( uint32_t ) configKERNEL_INTERRUPT_PRIORITY ) << 16UL )
6.#define portNVIC_SYSTICK_PRI				( ( ( uint32_t ) configKERNEL_INTERRUPT_PRIORITY ) << 24UL )
    
    

前面說了,STM32使用了4個bit來表示優先級,並且15是為最低優先級,很明白,把(0xFFFF0000)這個優先級放到了0xE000_ED22和0xE000_ED23中,即把Systick和PendSV的優先級設為最低。

1.1.2 在FreeRTOS中關閉中斷

Cortex-M3中有一個寄存器BASEPRI,和配置優先級一樣,當低於這個寄存器的優先級數,會被屏蔽,比如設置了優先級為5,那么優先級0~4會被關閉,FreeRTOS用函數portDISABLE_INTERRUPTS() portENABLE_INTERRUPTS() 控制中斷開關,根據配置的宏configMAX_SYSCALL_INTERRUPT_PRIORITY確認屏蔽的優先級數。

1.1.3 FreeRTOS利用關閉中斷實現臨界代碼區的保護

1.1.3.1普通臨界區

所謂臨界區就是不希望有中斷來打擾某段程序的執行,用函數taskENTER_CRITICAL()taskEXIT_CRITICAL() ,具體看如何實現:

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 );
	}
}

沒錯,就是利用BASEPRI寄存器來關閉中斷,當進入調用這個函數時全局變量uxCriticalNesting會加1,那么我們基本可以得出,退出臨界區一定是當uxCriticalNesting為1時,會打開中斷,退出臨界區函數如下:

void vPortExitCritical( void )
{
	configASSERT( uxCriticalNesting );
	uxCriticalNesting--;
	if( uxCriticalNesting == 0 )
	{
		portENABLE_INTERRUPTS();
	}
}
1.1.3.2中斷臨界區

除此之外還有在保護中斷臨界區的函數,就是不希望某個中斷里的代碼不被另一個中斷打斷,用函數taskENTER_CRITICAL_FROM_ISR() taskEXIT_CRITICAL_FROM_ISR( x ),函數實現上普通臨界區是一模一樣的

2. FreeRTOS 的任務優先級

FreeRTOS的任務優先級和中斷優先級最大的不同就是,任務優先級數的值越大,任務的優先級越大。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM