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
放在最上面。
其他细节后续再补。