2026年5月4日星期一

NK-N9H31A2 開發板:ETIMER

在 Timer 這篇中已介紹相關基本觀念,本篇將配合實際範例進行操作,使用 N9H31 的 ETIMER 控制 LED 定時閃爍,並透過 UART 輸出訊息。
本範例以官方提供的 ETIMER_Periodic 為基礎進行修改。原始範例僅透過 UART 輸出計數秒數,未對應到開發板上的 LED,因此本篇額外加入 GPIO 控制,使 LED 能夠呈現固定週期的亮滅。
同時,透過 serial port tool(例如 Arduino Serial Monitor)觀察 UART 訊息時間戳記,可進一步驗證 Timer 的實際運作頻率。

實驗目的

透過 Timer 定時觸發中斷:
  • 控制 LED 週期性亮滅
  • 透過 UART 輸出訊號,觀察時間間隔

使用範例

官方範例 ETIMER_Periodic

程式碼

核心概念:Timer 週期性產生中斷 → CPU 進入 ISR → 在 ISR 中控制 LED 並輸出 UART 訊息。

範例是基於 Nuvoton 官方 Sample Code(ETIMER_Periodic)進行修改,
僅作為學習與教學用途,以下為修改後的範例程式:

static int state = 0;

/**
 * ETIMER0 interrupt handler. Toggle LED state and print message every time timer timeout.
 */
void ETMR0_IRQHandler(void)
{
	ETIMER_ClearIntFlag(0);

	if (state)
	{
		/* LED ON */
		outpw(REG_GPIOF_DATAOUT, inpw(REG_GPIOF_DATAOUT) & ~BIT10);
		outpw(REG_GPIOI_DATAOUT, inpw(REG_GPIOI_DATAOUT) & ~BIT10);
		state = 0;
		sysprintf("H\n");
	}
	else
	{
		/* LED OFF */
		outpw(REG_GPIOF_DATAOUT, inpw(REG_GPIOF_DATAOUT) | BIT10);
		outpw(REG_GPIOI_DATAOUT, inpw(REG_GPIOI_DATAOUT) | BIT10);
		state = 1;
		sysprintf("L\n");
	}
}

/*-----------------------------------------------------------------------------*/
int main(void)
{
	sysDisableCache();
	sysFlushCache(I_D_CACHE);
	sysEnableCache(CACHE_WRITE_BACK);
	sysInitializeUART();

	sysprintf("\nETIMER0 periodic + LED toggle test\n");

	/* Enable ETIMER0 clock */
	outpw(REG_CLK_PCLKEN0, inpw(REG_CLK_PCLKEN0) | (1 << 4));

	/* Enable GPIO clock */
	outpw(REG_CLK_PCLKEN0, inpw(REG_CLK_PCLKEN0) | (1 << 3));

	/* PF10 PI10 set as GPIO function */
	outpw(REG_SYS_GPF_MFPH, inpw(REG_SYS_GPF_MFPH) & ~(0xF << 8));
	outpw(REG_SYS_GPI_MFPH, inpw(REG_SYS_GPI_MFPH) & ~(0xF << 8));

	/* PF10 PI10 set as output */
	outpw(REG_GPIOF_DIR, inpw(REG_GPIOF_DIR) | BIT10);
	outpw(REG_GPIOI_DIR, inpw(REG_GPIOI_DIR) | BIT10);

	/* PF10 PI10 initial low */
	outpw(REG_GPIOF_DATAOUT, inpw(REG_GPIOF_DATAOUT) & ~BIT10);
	outpw(REG_GPIOI_DATAOUT, inpw(REG_GPIOI_DATAOUT) & ~BIT10);

	/* Set timer frequency to 1Hz */
	ETIMER_Open(0, ETIMER_TOGGLE_MODE, 1);

	/* Enable timer interrupt */
	ETIMER_EnableInt(0);
	sysInstallISR(HIGH_LEVEL_SENSITIVE | IRQ_LEVEL_1, ETMR0_IRQn, (PVOID)ETMR0_IRQHandler);
	sysSetLocalInterrupt(ENABLE_IRQ);
	sysEnableInterrupt(ETMR0_IRQn);

	/* Start Timer 0 */
	ETIMER_Start(0);

	while (1)
		;
}
補充說明:本範例同時控制 PF10 與 PI10,因為開發板上分別對應兩顆 LED。透過 Timer 中斷同時切換兩個 GPIO,可快速驗證 Timer 與中斷機制是否正常運作。

函式說明

ETIMER_Open(timerNo, mode, freq)
  • 設定 Timer 的運作模式與目標頻率。
  • 設定 Timer mode(One-shot / Periodic / Continuous / Toggle)
  • 自動計算 prescaler 與 compare value
  • 回傳實際可達到的頻率(可能略有誤差)
注意:此函式不會啟動 Timer,需搭配 ETIMER_Start()


ETIMER_EnableInt(timerNo)
    啟用 Timer 中斷功能。

sysInstallISR(level, irq, handler)
    註冊中斷服務函式(ISR)
 將 interrupt source 對應到 handler

sysSetLocalInterrupt(ENABLE_IRQ)
啟用 CPU 層級中斷(全域開關)

sysEnableInterrupt(irq)
啟用中斷控制器(AIC)中的指定 IRQ

ETIMER_Start(timerNo)
啟動 Timer 計數


ETIMER_ClearIntFlag(timerNo)
清除 Timer 中斷旗標

ETMR0_IRQHandler()
  • Timer 中斷服務函式(ISR)
  • 要處理的事情
目前流程:清除中斷旗標 -> 執行應用邏輯(toggle LED + UART 輸出)
原則:保持簡短 避免阻塞

Timer 中斷的觸發需要同時啟用:
1. Timer 中斷功能(ETIMER_EnableInt)
2. 中斷控制器(sysEnableInterrupt)
3. CPU 中斷(sysSetLocalInterrupt)

三者缺一不可。

實驗結果


沒有留言:

發佈留言

打賞按讚