联德胜微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系统移植中,始终保持系统运行在超级用户模式。用户模式对应能访问的寄存器如下图所示:

联德胜微W806移植RTthread-Nano

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
挂起中断代码实现

关键点: 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、串口等硬件和相关软件资源,请查看相关软件代码。

编写示例运行结果如下:

联德胜微W806移植RTthread-Nano

图中显示主任务、串口任务、LED闪烁钩子函数已经都成功被调用运行。

整个工程代码请见链接:

W806-RTT-Nano: 基于联德胜微W806芯片移植RTthread-Nano (gitee.com)

上一篇:sharedPreference特性


下一篇:SQL基础-第7章 集合运算