To be completed!
# 嵌入式系統設計:實驗 4
# Part I. Clock & Timer
typedef struct
{
__IO uint32_t PWRCON; /* System Power-down Control Register */
__IO uint32_t AHBCLK; /* AHB Devices Clock Enable Control Register */
__IO uint32_t APBCLK; /* APB Devices Clock Enable Control Register */
__IO uint32_t CLKSTATUS; /* Clock status monitor Register */
__IO uint32_t CLKSEL0; /* Clock Source Select Control Register 0 */
__IO uint32_t CLKSEL1; /* Clock Source Select Control Register 1 */
__IO uint32_t CLKDIV; /* Clock Divider Number Register */
__IO uint32_t CLKSEL2; /* Clock Source Select Control Register 2 */
__IO uint32_t PLLCON; /* PLL Control Register */
__IO uint32_t FRQDIV; /* Frequency Divider Control Register */
__IO uint32_t RESERVE[2];
__IO uint32_t APBCLK1; /* APB Devices Clock Enable Control Register 1 */
__IO uint32_t CLKSEL3; /* Clock Source Select Control Register 3 */
__IO uint32_t CLKDIV1; /* Clock Divider Number Register 1 */
} CLK_T;
typedef struct
{
__IO uint32_t TCSR; /* Timer Control and Status Register */
__IO uint32_t TCMPR; /* Timer Compare Register */
__IO uint32_t TISR; /* Timer Interrupt Status Register */
__I uint32_t TDR; /* Timer Data Register */
__I uint32_t TCAP; /* Timer Capture Data Register */
__IO uint32_t TEXCON; /* Timer External Control Register */
__IO uint32_t TEXISR; /* Timer External Interrupt Status Register */
} TIMER_T;
/* Get Timer Clock Frequency */
uint32_t TIMER_GetModuleClock(TIMER_T *timer)
{
uint32_t u32Src;
const uint32_t au32Clk[] = {__HXT, __LXT, 0, 0, 0, __LIRC, 0, __HIRC};
if(timer == TIMER0)
u32Src = (CLK->CLKSEL1 & CLK_CLKSEL1_TMR0_S_Msk) >> CLK_CLKSEL1_TMR0_S_Pos;
else if(timer == TIMER1)
u32Src = (CLK->CLKSEL1 & CLK_CLKSEL1_TMR1_S_Msk) >> CLK_CLKSEL1_TMR1_S_Pos;
else if(timer == TIMER2)
u32Src = (CLK->CLKSEL1 & CLK_CLKSEL1_TMR2_S_Msk) >> CLK_CLKSEL1_TMR2_S_Pos;
else // Timer 3
u32Src = (CLK->CLKSEL1 & CLK_CLKSEL1_TMR3_S_Msk) >> CLK_CLKSEL1_TMR3_S_Pos;
if(u32Src == 2) return(SystemCoreClock);
return(au32Clk[u32Src]);
}
uint32_t TIMER_Open(TIMER_T *timer, uint32_t u32Mode, uint32_t u32Freq)
{
uint32_t u32Clk = TIMER_GetModuleClock(timer);
uint32_t u32Cmpr = 0, u32Prescale = 0;
/*
* Fastest possible timer working freq is (u32Clk / 2).
* While cmpr = 2, pre-scale = 0.
*/
if(u32Freq > (u32Clk / 2))
{
u32Cmpr = 2;
}
else
{
if(u32Clk >= 0x4000000)
{
u32Prescale = 7; // real prescaler value is 8
u32Clk >>= 3;
}
else if(u32Clk >= 0x2000000)
{
u32Prescale = 3; // real prescaler value is 4
u32Clk >>= 2;
}
else if(u32Clk >= 0x1000000)
{
u32Prescale = 1; // real prescaler value is 2
u32Clk >>= 1;
}
u32Cmpr = u32Clk / u32Freq;
}
timer->TCSR = u32Mode | u32Prescale;
timer->TCMPR = u32Cmpr;
return(u32Clk / (u32Cmpr * (u32Prescale + 1)));
}
這個函式較為複雜,但你可以仔細查看它。為了生成特定的計時器頻率,我們將根據以下公式計算所需的值,包括比較值(comparison value)和預分頻器(prescaler)。
Questions:
- There are 4 modes of timer, which bitfield of
TIMER_Tstores the mode of the timer? - Based on the comment for
CLK_T::CLKSEL1, try to guess the values ofCLK_CLKSEL1_TMR0_S_MskandCLK_CLKSEL1_TMR0_S_Pos, and explain the following code fromTIMER_GetModuleClock()u32Src = (CLK->CLKSEL1 & CLK_CLKSEL1_TMR0_S_Msk) >> CLK_CLKSEL1_TMR0_S_Pos;
# Part II. Interrupt
...
volatile uint8_t ledState = 0;
void TMR1_IRQHandler(void)
{
ledState = ~ledState; // changing ON/OFF state
if (ledState)
PC12 = 0;
else
PC12 = 1;
TIMER_ClearIntFlag(TIMER1); // Clear Timer1 time-out interrupt flag
}
void Init_Timer1(void)
{
TIMER_Open(TIMER1, TMR1_OPERATING_MODE, TMR1_OPERATING_FREQ);
TIMER_EnableInt(TIMER1);
NVIC_EnableIRQ(TMR1_IRQn);
TIMER_Start(TIMER1);
}
int main(void)
{
SYS_Init(); // Intialize System/Peripheral clocks & multi-function I/Os
GPIO_SetMode(PC, BIT12, GPIO_MODE_OUTPUT); // set LED GPIO pin
Init_Timer1();
while (1);
}
你可以在 TMR_LED/main.c 中找到這個範例。這裡有一個奇怪的地方:沒有人在呼叫 TMR1_IRQHandler() ,但它卻能正常運作。為什麼會觸發呢?
秘密就在於 NVIC_EnableIRQ(TMR1_IRQn) 。當計時器發送中斷信號時,中斷處理函式會跳轉到向量表(vector table)來決定適當的動作。
/* startup_NUC100Series.s */
MODULE ?cstartup
;; Forward declaration of sections.
SECTION CSTACK:DATA:NOROOT(3) ;; 8 bytes alignment
SECTION .intvec:CODE:NOROOT(2);; 4 bytes alignment
EXTERN SystemInit
EXTERN __iar_program_start
PUBLIC __vector_table
DATA
__vector_table
DCD sfe(CSTACK)
DCD Reset_Handler
DCD NMI_Handler
DCD HardFault_Handler
DCD 0
...
DCD SysTick_Handler
; External Interrupts
...
DCD TMR0_IRQHandler ; Timer 0 interrupt
DCD TMR1_IRQHandler ; Timer 1 interrupt
DCD TMR2_IRQHandler ; Timer 2 interrupt
DCD TMR3_IRQHandler ; Timer 3 interrupt
DCD UART02_IRQHandler ; UART0 interrupt
DCD UART1_IRQHandler ; UART1 interrupt
DCD SPI0_IRQHandler ; SPI0 interrupt
DCD SPI1_IRQHandler ; SPI1 interrupt
DCD SPI2_IRQHandler ; SPI2 interrupt
DCD SPI3_IRQHandler ; SPI3 interrupt
...
END
處理函式會檢查你的 C 程式碼中是否定義了 TMR1_IRQHandler ;如果沒有,它將觸發預設的處理函式來處理計時器中斷。這就是為什麼 void TMR1_IRQHandler(void) 會被觸發的原因。
# 實作
我們複寫了系統預設的中斷處理函數,並做了 periodic counting 的練習。
補充
Lab 5: Mixed Topics
我們組別做了一個飛機射擊遊戲,我方是透過 keypad 左右移動,敵人則是自動生成,由上往下前進。
需要用 keypad 發射砲彈攻擊敵人,直到死亡為止。
使用到的原件: keypad, LCD, , 7-segment, timer