FreeRTOS臨界セグメントコード
5683 ワード
本稿は『ALIENTEK STM 32 F 429 FreeRTOS開発チュートリアル』第4章学習ノートの補足第1章ノート–FreeRTOS概要とソースコードダウンロード第2章ノート–FreeRTOS STM 32 F 4に第3章ノートを移植-FreeRTOSシステム構成第4章ノート-FreeRTOS中断分析
臨界セグメントコードは臨界領域とも呼ばれ、完全に実行され、中断できないコードセグメントを指す.
FreeRTOSは,臨界セグメントコードに入る際に割り込みを閉じる必要があり,臨界セグメントコードを処理した後に割り込みを開く.
FreeRTOSシステム自体には多くの臨界セグメントコードが保護されています
臨界セグメントに入る:taskENTER_CRITICAL()
終了臨界セグメント:taskEXIT_CRITICAL()
この2つの関数は、次のように定義されたマクロ定義です.
それぞれ関数portENTERをカプセル化CRITICAL()とportEXIT_CRITICAL()であり、カプセル化された2つの関数もマクロ定義であり、以下のように定義される.
関数vPortEnterCritical()とvPortExitCritical()はファイルport.cでは、関数のプロトタイプは次のとおりです.
関数vPortEnterCritical()に入り、portDISABLE_を先に実行します.INTERUPTS()関数(クローズ割り込み)
さらにuxCriticalNesting++を実行し、変数に変数を加えて臨界セグメントネスト回数を表す
次に1の場合、断言関数に入ります.
関数vPortExitCritical()に入りconfigASSERT(uxCriticalNesting)を実行します.
更にuxCriticalNestingに対して1を減らして変数が0の時だけ関数portENABLEを呼び出しますINTERUPTS()イネーブル中断
portENABLE_INTERUPTS()は、BASEPRIレジスタに0を書き込む、すなわち、マスク優先度が0以下の割り込みであり、0優先度が最も高いため、マスク割り込みを停止する
これにより、複数の臨界セグメントコードがある場合に、ある臨界セグメントコードの終了によって他の臨界セグメントの保護を乱すことなく、すべての臨界セグメントコードが終了してから中断できることが保証される.
割り込みサービスプログラムで使用される臨界セグメントコード保護
臨界セグメントに入る:taskENTER_CRITICAL_FROM_ISR()
終了臨界セグメント:taskEXIT_CRITICAL_FROM_ISR()
ulPortRaiseBASEPRI():
まずBASEPRIレジスタの値を読み出しulReturnに保存する
configmaX_をSYSCALL_INTERRUPT_PRIORITY BASEPRIレジスタに書き込む
ulReturnの値を返します
vPortSetBASEPRI():
BASEPRIレジスタに値を書き込む
1.臨界セグメントコードの概要
臨界セグメントコードは臨界領域とも呼ばれ、完全に実行され、中断できないコードセグメントを指す.
FreeRTOSは,臨界セグメントコードに入る際に割り込みを閉じる必要があり,臨界セグメントコードを処理した後に割り込みを開く.
FreeRTOSシステム自体には多くの臨界セグメントコードが保護されています
2.タスクレベルの臨界セグメントコード保護
臨界セグメントに入る:taskENTER_CRITICAL()
終了臨界セグメント:taskEXIT_CRITICAL()
この2つの関数は、次のように定義されたマクロ定義です.
#define taskENTER_CRITICAL() portENTER_CRITICAL()
#define taskEXIT_CRITICAL() portEXIT_CRITICAL()
それぞれ関数portENTERをカプセル化CRITICAL()とportEXIT_CRITICAL()であり、カプセル化された2つの関数もマクロ定義であり、以下のように定義される.
#define portENTER_CRITICAL() vPortEnterCritical()
#define portEXIT_CRITICAL() vPortExitCritical()
関数vPortEnterCritical()とvPortExitCritical()はファイルport.cでは、関数のプロトタイプは次のとおりです.
void vPortEnterCritical( void )
{
portDISABLE_INTERRUPTS();
uxCriticalNesting++;
if( uxCriticalNesting == 1 )
{
configASSERT( ( portNVIC_INT_CTRL_REG & portVECTACTIVE_MASK ) == 0 );
}
}
void vPortExitCritical( void )
{
configASSERT( uxCriticalNesting );
uxCriticalNesting--;
if( uxCriticalNesting == 0 )
{
portENABLE_INTERRUPTS();
}
}
関数vPortEnterCritical()に入り、portDISABLE_を先に実行します.INTERUPTS()関数(クローズ割り込み)
さらにuxCriticalNesting++を実行し、変数に変数を加えて臨界セグメントネスト回数を表す
次に1の場合、断言関数に入ります.
configASSERT( ( portNVIC_INT_CTRL_REG & portVECTACTIVE_MASK ) == 0 );
#define configASSERT( x ) if( ( x ) == 0 ) { taskDISABLE_INTERRUPTS(); for( ;; ); }
関数vPortExitCritical()に入りconfigASSERT(uxCriticalNesting)を実行します.
更にuxCriticalNestingに対して1を減らして変数が0の時だけ関数portENABLEを呼び出しますINTERUPTS()イネーブル中断
#define portENABLE_INTERRUPTS() vPortSetBASEPRI( 0 )
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
}
}
portENABLE_INTERUPTS()は、BASEPRIレジスタに0を書き込む、すなわち、マスク優先度が0以下の割り込みであり、0優先度が最も高いため、マスク割り込みを停止する
これにより、複数の臨界セグメントコードがある場合に、ある臨界セグメントコードの終了によって他の臨界セグメントの保護を乱すことなく、すべての臨界セグメントコードが終了してから中断できることが保証される.
3.割り込みレベルの臨界セグメントコード保護
割り込みサービスプログラムで使用される臨界セグメントコード保護
臨界セグメントに入る:taskENTER_CRITICAL_FROM_ISR()
終了臨界セグメント:taskEXIT_CRITICAL_FROM_ISR()
#define taskENTER_CRITICAL_FROM_ISR() portSET_INTERRUPT_MASK_FROM_ISR()
#define taskEXIT_CRITICAL_FROM_ISR( x ) portCLEAR_INTERRUPT_MASK_FROM_ISR( x )
#define portSET_INTERRUPT_MASK_FROM_ISR() ulPortRaiseBASEPRI()
#define portCLEAR_INTERRUPT_MASK_FROM_ISR(x) vPortSetBASEPRI(x)
ulPortRaiseBASEPRI():
static portFORCE_INLINE uint32_t ulPortRaiseBASEPRI( void )
{
uint32_t ulReturn, ulNewBASEPRI = configMAX_SYSCALL_INTERRUPT_PRIORITY;
__asm
{
mrs ulReturn, basepri
msr basepri, ulNewBASEPRI
dsb
isb
}
return ulReturn;
}
まずBASEPRIレジスタの値を読み出しulReturnに保存する
configmaX_をSYSCALL_INTERRUPT_PRIORITY BASEPRIレジスタに書き込む
ulReturnの値を返します
vPortSetBASEPRI():
static portFORCE_INLINE void vPortSetBASEPRI( uint32_t ulBASEPRI )
{
__asm
{
msr basepri, ulBASEPRI
}
}
BASEPRIレジスタに値を書き込む
割り込みレベルの臨界コード保護の使用方法:
// 5
void TIM5_IRQHandler(void)
{
HAL_TIM_IRQHandler(&TIM5_Handler);
}
// ,
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
uint32_t status_value
if(htim==(&TIM5_Handler))
{
status_value=taskENTER_CRITICAL_FROM_ISR();
printf("TIM5 .......\r
");
taskEXIT_CRITICAL_FROM_ISR(status_value);
}
}