S5P4418,Cortex-A9系列。
結合了 RT-Thread內核實現(六):時間片 和 S5P4418裸機開發(十四):TIMER 的代碼。
SysTick & PendSV
RT-Thread實現線程調度兩個比較核心的中斷。
SysTick更新系統時基。PendSV做上下文切換。
- SysTick在S5P4418中用timer0代替。週期10ms,注意中斷服務函數要清除中斷標誌位。
void SysTick_Config(){ // 只是換了個名字
IP_RESET_REGISTER1 |= (1 << 4); // 關閉復位
TCFG0 |= (250 - 1); // PCLK = 200MHz 200000000 / 16 / 250 = 50000;
TCFG1 |= 0x4;
TCNTB0 = 500; // 500 = 10ms
TCON |= (1 << 1);
// vic_init(23, (u32)timer0_ISR); // 註冊VIC
vic_init(23, (u32)SysTick_Handler); // 註冊VIC
TINT_CSTAT |= (1 << 0); // 中斷使能
TCON &= ~(1 << 1);
TCON |= ((1 << 3) | (1 << 0)); // 自動重裝載,啓動定時器
}
void SysTick_Handler(void)
{
/* 進入中斷 */
rt_interrupt_enter();
rt_tick_increase();
TINT_CSTAT |= (1 << 5); // 清除中斷標誌
/* 離開中斷 */
rt_interrupt_leave();
}
- 再選一個能替代PendSV的中斷,因爲S5P4418上的中斷都可以軟件觸發,所以選一個沒人用的即可,我選擇了63號中斷。重點是中斷服務程序的修改。
PendSV_Handler
- Coterx-M3調度在 RT-Thread內核實現(一):線程與調度 中描述的比較清楚。切換上下文的幾個步驟:
- 硬件自動保存xPSR, PC, LR, R12以及R3‐R0到線程棧中。
- 取出源線程的psp,即棧頂sp,保存r4 - r11到sp指向的位置。這就完成了保存上文的工作。
- 下文切換,取即將運行的線程的sp值,不是sp寄存器,裝載r4 - r11,再將sp值寫回sp寄存器。
- 退出中斷後,硬件再從棧中自動裝載xPSR, PC, LR, R12以及R3‐R0。
- 而A9在響應中斷時沒有自動保存的操作,也沒有MSP和PSP寄存器。移植時也可以按上面4個步驟來操作。
- 第一步,保存CPSR, PC, LR, R12以及R3‐R0到線程棧中。CPU進入IRQ模式後,sp寄存器是該模式下的r13_irq。我設置的線程是運行在特權模式下,其sp寄存器應該r13_svc。所以先切回中斷前的模式。
- 然後push那8個寄存器,這裏要注意一下順序,後一步講解。
- 第二步,保存r4 - r11,此時通過模式切換,已經是源線程的棧了,直接push。
- 第三步,下文切換,和M3的操作一樣。
- 第四步,A9進中斷時會自動保存上一個模式的CPSR到SPSR,在退出中斷時,如果LDMFD等指令帶’^’,CPSR由硬件自動寫回。所以恢復PC, LR, R12以及R3‐R0時,先將原CPSR寫入SPSR中,爲了方便取cpsr的值,在第一步保存時CPSR最後一個push。同時
struct exception_stack_frame
中的rt_uint32_t psr
放在最上面。
其他細節後續再補。