联盛德微W806芯片移植RTthread-Nano
联盛德微W806芯片移植RTthread-Nano
移植前知识点
1、W806芯片基于平头哥E804 CPU内核,该芯片数据手册下载链接:
datasheet/玄铁E804用户手册_v04.pdf · ZH-OuYangLei/W806-RTT-Nano - 码云 - 开源中国 (gitee.com)
2、E804处理器存在两种运行模式: 普通用户模式和超级用户模式,芯片在复位后自动进入超级用户模式,超级用户模式下CPU可以访问所有的寄存器,而用户模式下只能访问少量的寄存器。在对RTT系统移植中,始终保持系统运行在超级用户模式。用户模式对应能访问的寄存器如下图所示:
3、编程模型
寄存器 | 功能 |
---|---|
R0 | 函数调用时第一个参数 |
R1 | 函数调用时第二个参数 |
R2 | 函数调用时第三个参数 |
R3 | 函数调用时第四个参数 |
R14 | 堆栈指针 |
R15 | 链接寄存器 |
EPSR | 处理器状态寄存器 PSR的影子寄存器,在进入异常中断时自动保存当前PSR的值 |
EPC | 程序计数器PC的影子寄存器,在进入异常中断时自动保存当前PC的值 |
堆栈初始化
文件路径: rtthread->libcpu->x804->cpu.c
typedef struct stack_frame
{
rt_uint32_t epc;
rt_uint32_t epsr;
rt_uint32_t r4;
rt_uint32_t r5;
rt_uint32_t r6;
rt_uint32_t r7;
rt_uint32_t r8;
rt_uint32_t r9;
rt_uint32_t r10;
rt_uint32_t r11;
rt_uint32_t lr; //R15
rt_uint32_t r16;
rt_uint32_t r17;
rt_uint32_t r18;
rt_uint32_t r19;
rt_uint32_t r20;
rt_uint32_t r21;
rt_uint32_t r22;
rt_uint32_t r23;
rt_uint32_t r24;
rt_uint32_t r25;
rt_uint32_t r26;
rt_uint32_t r27;
rt_uint32_t r28;
rt_uint32_t r29;
rt_uint32_t r30;
rt_uint32_t r31;
rt_uint32_t fr0;
rt_uint32_t fr1;
rt_uint32_t fr2;
rt_uint32_t fr3;
rt_uint32_t fr4;
rt_uint32_t fr5;
rt_uint32_t fr6;
rt_uint32_t fr7;
rt_uint32_t fr8;
rt_uint32_t fr9;
rt_uint32_t fr10;
rt_uint32_t fr11;
rt_uint32_t fr12;
rt_uint32_t fr13;
rt_uint32_t fr14;
rt_uint32_t fr15;
rt_uint32_t r0;
rt_uint32_t r1;
rt_uint32_t r2;
rt_uint32_t r3;
rt_uint32_t r12;
rt_uint32_t r13;
}stack_frame;
rt_uint8_t *rt_hw_stack_init(void *tentry,
void *parameter,
rt_uint8_t *stack_addr,
void *texit)
{
stack_frame *sf;
rt_uint8_t *stk;
unsigned long i;
stk = stack_addr + sizeof(rt_uint32_t);
stk = (rt_uint8_t *)RT_ALIGN_DOWN((rt_uint32_t)stk, 8);
stk -= sizeof(stack_frame);
sf = (stack_frame *)stk;
/* init all register */
for (i = 0; i < sizeof(stack_frame) / sizeof(rt_uint32_t); i ++)
{
((rt_uint32_t *)sf)[i] = 0xdeadbeef;
}
sf->r0 = (unsigned long)parameter; /* r0 : argument */
sf->r1 = 0x01010101L; /* r1 */
sf->r2 = 0x02020202L; /* r2 */
sf->r3 = 0x03030303L; /* r3 */
sf->r12 = 0x12121212L; /* r12 */
sf->r13 = 0x13131313L; /* r12 */
sf->lr = (rt_uint32_t)texit; /* lr */
sf->epc = (rt_uint32_t)tentry; /* entry point, pc */
sf->epsr = 0x80000140L; /* PSR */
/* return task's current stack address */
return stk;
}
上下文切换汇编代码编写
文件路径: rtthread->libcpu->x804->contex_x804.s
关闭中断
/*
* rt_base_t rt_hw_interrupt_disable(void);
*/
.global rt_hw_interrupt_disable //函数 rt_hw_interrupt_disable
.type rt_hw_interrupt_disable, %function
rt_hw_interrupt_disable:
mfcr r0, CR<0,0> //读取当前PSR寄存器,函数返回值保存在R0寄存器中
psrclr ee,ie //清除ESP中的EE、IE,关闭异常和中断
rts
开启中断
/*
* void rt_hw_interrupt_enable(rt_base_t psr);
*/
.global rt_hw_interrupt_enable //函数 rt_hw_interrupt_enable
.type rt_hw_interrupt_enable, %function
rt_hw_interrupt_enable:
mtcr r0, CR<0,0> //调用函数,实参保存在R0中,该实参为函数rt_hw_interrupt_disable的返回值
rts
第一次切换上下文
/*
* void rt_hw_context_switch_to(rt_uint32 to);
* R0 --> to
*/
.global rt_hw_context_switch_to
.type rt_hw_context_switch_to, %function
rt_hw_context_switch_to:
psrclr ee,ie
lrw r1, rt_interrupt_to_thread
st.w r0, (r1,0)
/* set form thread = 0 */
lrw r1, rt_interrupt_from_thread
lrw r0, 0
st.w r0, (r1,0)
lrw r1, rt_thread_switch_interrupt_flag
lrw r0, 1
st.w r0, (r1,0)
/* 初始化TSPEND */
lrw r0, 0xE000EC10 //设置最低的中断优先级
lrw r1, 0xff
st.w r1, (r0,0)
lrw r0, 0xE000EC0C //清除状态
lrw r1, 0
st.w r1, (r0,0)
/*触发tspend中断*/
lrw r0, 0XE000EC08
bgeni r1, 0
st.w r1, (r0,0)
psrset ee,ie
rts
中断中切换上下文和一般切换上下文
/*
* void rt_hw_context_switch_interrupt(rt_uint32 from, rt_uint32 to);
* r0 --> from
* r1 --> to
*/
.global rt_hw_context_switch_interrupt
.type rt_hw_context_switch_interrupt, %function
rt_hw_context_switch_interrupt:
lrw r2, rt_thread_switch_interrupt_flag
ld.w r3, (r2,0)
bhz r3, _to_thread1
lrw r3, 1
st.w r3, (r2,0)
lrw r2, rt_interrupt_from_thread /* set rt_interrupt_from_thread */
st.w r0, (r2,0)
_to_thread1:
lrw r2, rt_interrupt_to_thread /* set rt_interrupt_to_thread */
st.w r1, (r2,0)
lrw r0, 0XE000EC08
bgeni r1, 0
st.w r1, (r0,0)
rts
挂起中断代码实现
关键点:
异常中断响应时,当前的PSR、EPC寄存器自动保存到EPSR、EPC寄存器中
异常中断返回时,EPSR、EPC寄存器会自动更新到当前的PSR、PC寄存器中
.global tspend_handler
.type tspend_handler, %function
tspend_handler:
psrclr ee,ie
///压栈 R13-R12,R3-R0
ipush
///判断上下文切换标志
///如果为0,说明没有发生上下文切换调用,则重新开启异常中断,并恢复现场
///如果大于0,说明有发生上下文切换调用,则清除标志,保存from上下文
lrw r2, rt_thread_switch_interrupt_flag
ld.w r3, (r2,0)
bez r3, _enable_ie_ee
lrw r3, 0
st.w r3, (r2,0)
///如果不存在from线程,则直接恢复to线程上下文
lrw r2, rt_interrupt_from_thread
ld.w r3, (r2,0)
bez r3, _to_thread3
///保存from线程上下文
subi sp, sp, 64
fstms fr0-fr15, (sp)
subi sp, sp, 68
stm r15-r31, (sp)
subi sp, sp, 32
stm r4-r11, (sp)
subi sp, sp, 8
mfcr r0, CR<4,0>
mfcr r1, CR<2,0>
stm r0-r1, (sp)
///更新堆栈地址到thread->sp
st.w sp, (r3,0)
///恢复to线程上下文
_to_thread3:
lrw r2, rt_interrupt_to_thread
ld.w r0, (r2,0)
ld.w sp, (r0,0)
ldm r0-r1, (sp)
mtcr r0, CR<4,0>
mtcr r1, CR<2,0>
addi sp, sp, 8
ldm r4-r11, (sp)
addi sp, sp, 32
ldm r15-r31, (sp)
addi sp, sp, 68
fldms fr0-fr15,(sp)
addi sp, sp, 64
///开启异常中断,设置PSR备份寄存器EPSR
_enable_ie_ee:
mfcr r0, CR<2,0>
bseti r0, 6
bseti r0, 8
mtcr r0, CR<2,0>
//出栈 R0-R3,R12-R13
ipop
rte
修改Rtthread入口函数
文件路径: platform->arch->xt804->bsp->startup.S
将其中的 jbsr main
替换为 jbsr entry
硬件初始化
在rt_hw_board_init()函数中初始化时钟、GPIO、串口等硬件和相关软件资源,请查看相关软件代码。
编写示例运行结果如下:
图中显示主任务、串口任务、LED闪烁钩子函数已经都成功被调用运行。
整个工程代码请见链接: