聯盛德微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閃爍鈎子函數已經都成功被調用運行。

整個工程代碼請見鏈接:

W806-RTT-Nano: 基於聯德勝微W806芯片移植RTthread-Nano (gitee.com)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM