FreeRTOSで割り込みルーチンを使う場合の注意
投稿:2012-09-13
このページはmorizzoさんの「バグのある生活: Cortex-M3 + FreeRTOS = 備忘録」の受け売りです。
morizzoさんがブログで説明してくださらなかったら今でも「うー、さっぱりわかんねorz」と頭を抱えていたことでしょう。
LPCXpresso(LPC1768)でFreeRTOSを使い、割り込みルーチンを使うと、
プログラムを実行して相当長い時間が経過した後に全タスクの動作が止まりデバッガで一時停止させるとlist.cのリスト検索処理で無限ループしています。
使った割り込みの優先度がデフォルト(0=最優先)で呼ばれた割り込みルーチンの中からFreeRTOSの関数(~FromISR)を呼び出し
FreeRTOS内部で他の割り込みを認めないクリティカル処理中に、別の割り込みが発生、同様にクリティカル処理を始めて、混乱したため。
//タイマー0割り込み void TIMER0_IRQHandler(void) { unsigned long ulDummy = portSET_INTERRUPT_MASK_FROM_ISR(); if (pTimerFromIRQ && pTimerFromIRQ->pSelectTimer) { //割り込みフラグをクリアして、2回目以降の割り込みを抑止 pTimerFromIRQ->pSelectTimer->IR = 0b1; } if (hTimeLine) { //呼び出し元へダミーのデータを送信する portBASE_TYPE HigherPriorityTaskWoken = pdFALSE; xQueueSendToBackFromISR(hTimeLine, &tl_match, &HigherPriorityTaskWoken); if (HigherPriorityTaskWoken) { //中身はvPortYieldFromISR taskYIELD(); } } portCLEAR_INTERRUPT_MASK_FROM_ISR(ulDummy); }
これまでも、これからも、タスク優先度を利用した問題解決を行う気はないので、この件のために一律にFreeRTOSを呼べる優先度に変更します。
初期処理に全ての割り込み番号を用意して設定しました。
static IRQn_Type irq_list[] = { WDT_IRQn, TIMER0_IRQn, TIMER1_IRQn, TIMER2_IRQn, TIMER3_IRQn, UART0_IRQn, UART1_IRQn, UART2_IRQn, UART3_IRQn, PWM1_IRQn, I2C0_IRQn, I2C1_IRQn, I2C2_IRQn, SPI_IRQn, SSP0_IRQn, SSP1_IRQn, PLL0_IRQn, RTC_IRQn, EINT0_IRQn, EINT1_IRQn, EINT2_IRQn, EINT3_IRQn, ADC_IRQn, BOD_IRQn, USB_IRQn, CAN_IRQn, DMA_IRQn, I2S_IRQn, ENET_IRQn, RIT_IRQn, MCPWM_IRQn, QEI_IRQn, PLL1_IRQn, USBActivity_IRQn, CANActivity_IRQn }; static void startup(void *pvParameters) { //Kickstart ROM Kernel ksrk_led2(FALSE); // 割り込み優先度設定 // 割り込み中にFreeRTOSを呼び出す場合、割り込み優先度をconfigMAX_SYSCALL_INTERRUPT_PRIORITYより上げるとリスト処理が失敗するので一律設定 uint32_t i; for (i = 0; i < sizeof(irq_list) / sizeof(irq_list[0]); i++) { NVIC_SetPriority(irq_list[i], configMAX_SYSCALL_INTERRUPT_PRIORITY); }