あなたの天然記念物
ホーム更新雑談Perl鉄ゲタランドナーコースガイド自転車Linuxリンク経歴連絡先

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

今回の鉄ゲタは…

このページ自体が鉄ゲタですよホントにもう(ぐすん)。 まあ、どうせ話が通じないと思うので、あとはソース見てください(^^;
yrntrlmnmnt20120913.zip (296,152 バイトをVPSから 00:05 で)