搜索
bottom↓
回复: 18

[编程指南增补] RT-Thread 在 STM32 芯片上的移植方法

[复制链接]

出0入0汤圆

发表于 2010-3-30 15:14:05 | 显示全部楼层 |阅读模式
看完 RT-Thread 在 STM32 移植这一章节后觉得总归组织的不是特别清晰. 我个人认为这一章节应该是一个给出的一个实例, 应该起到抛砖引玉或者对于任何一款单片机移植方法借鉴的作用. 这一章节我个人觉得应该独立于所有章节.

目前<<编程指南>>此章节表达的并不是特别的完善, 因此根据自己的理解稍微进行了一些增补:


=============================================================

(原文件名:移植.png)


由于 Cotex-M3 的内核特性, STM32 的移植部分的代码可在 STM32 文件夹下述文件中找到:fault.c, stack.c , context_rvds.S ,fault_rvds.S , start_rvds.s , serial.C , CPU.C , interrupt.C 。

其中具体表述为:
CPU.C: 芯片相关代码
interrupt.C: 中断相关代码
start.S: 启动代码汇编代码
stack.C:  栈处理C语言代码.
context_rvds.S: 上下文处理汇编代码
fault.C:  故障处理 C 语言代码
fault_rvds.S: 故障处理汇编代码
serial.C: 串口处理(使用 finsh 组件)

除了 CPU.C 和 interrupt.C 函数我们无需修改外, 其余移植部分需要修改的分为四个方面:
启动代码处理. start.S
上下文处理, 保证任务调度器现场保护. stack.C, context_rvds.S
异常状态处理, 获得出错处的栈指针, 提供钩子函数提示故障信息. fault.C fault_rvds.S
系统信息处理, 串口 finsh 组件有关.serial.C



下文将细化这四个方面:

启动代码处理

这里需要设置程序的堆和栈的大小.
具体详见 start_rvds.S 文件.
这里我们使用 MDK 的 Configuration Wizard 模式设置
堆大小: 0x0000 0000
栈大小: 0x0000 0200


上下文处理

stack.C 中我们需要移植一个地方

硬件栈初始化, 这个也是和根据 Cotex-M3 内核固有特性设计出的栈结构进行初始化的代码. 初始状态是模拟一次中断发生后的堆栈情况.
rt_hw_stack_init() 函数是由 rt_thread_init() 函数调用的, 即 RT-Thread 创建任务是调用的.
rt_hw_stack_init() 函数只需要三个输入传递参数, 返回当前任务的栈初始化结束的栈地址.


(原文件名:堆栈.jpg)

rt_uint8_t *rt_hw_stack_init(void *tentry, void *parameter,
        rt_uint8_t *stack_addr, void *texit)
{
        unsigned long *stk;

        stk          = (unsigned long *)stack_addr;
        *(stk)   = 0x01000000L;                                        /* PSR */
        *(--stk) = (unsigned long)tentry;                /* entry point, pc */
        *(--stk) = (unsigned long)texit;                /* lr */
        *(--stk) = 0;                                                        /* r12 */
        *(--stk) = 0;                                                        /* r3 */
        *(--stk) = 0;                                                        /* r2 */
        *(--stk) = 0;                                                        /* r1 */
        *(--stk) = (unsigned long)parameter;        /* r0 : argument */

        *(--stk) = 0;                                                        /* r11 */
        *(--stk) = 0;                                                        /* r10 */
        *(--stk) = 0;                                                        /* r9 */
        *(--stk) = 0;                                                        /* r8 */
        *(--stk) = 0;                                                        /* r7 */
        *(--stk) = 0;                                                        /* r6 */
        *(--stk) = 0;                                                        /* r5 */
        *(--stk) = 0;                                                        /* r4 */

        /* return task's current stack address */
        return (rt_uint8_t *)stk;
}

context_rvds.S: 上下文处理汇编代码

        与其他实时系统一样,RT-Thread 在进入系统临界代码区之前也需要关闭中断来保护核心数据不被多任务环境下的其他任务或中断破坏。因为 MDK 支持嵌入汇编语句,所以加入关闭/打开中断的语句是很方便的。
        RT-Thread 定义了两个函数用来关闭/打开中断:rt_hw_interrupt_disable() 和rt_hw_interrupt_enable()。
        我们知道在处理此处的临界状态最简单的办法就是关闭中断, 处理完临界状态后再打开中断但这种方法有一个隐患,如果在关闭中断后调用 RT-Thread 函数,当函数返回后,中断将被打开!

        执行 rt_hw_interrupt_disable() 的最有效的方法是先将中断关闭的状态保存到堆栈中,然后关闭中断。与之对应的 rt_hw_interrupt_enable() 的操作是从堆栈中恢复中断状态。采用此方法,不管用户是在中断关闭还是允许的情况下调用 RT-Thread 中的函数,在调用过程中都不会改变中断状态。如果用户在中断关闭的情况下调用 RT-Thread 函数,其实是延长了中断响应时间。虽然 rt_hw_interrupt_disable() 和 rt_hw_interrupt_enable() 可以保护代码的临界段。但如此用法要小心,特别是在调用系统延时一类函数之前关闭了中断。此时任务将处于延时挂起状态,等待时钟中断,但此时时钟中断是禁止的!则系统可能会崩溃。很明显,所有的会让当前任务挂起的函数的调用都会涉及到这个问题,必须十分小心。所以建议用户调用 RT-Thread 的系统函数之前打开中断。

   具体参考实例和使用办法可以参考 7.1 章节 "关闭中断".

   (接下来内容即原编程指南中的这一章节中的上下文处理部分)

(3) 异常状态处理
fault.C 异常处理中我们需要移植两个地方, 这个也和 Cotex-M3 固有特性有关, 我们只需要获得出错时芯片 R0,R1,R2,R3,R12,LR,PC,PSR 的值.

由于Cortex-M3在进入异常服务例程时,自动压栈了 R0-R3, R12, LR, PSR 和PC,并且在
返回时自动弹出它们,所以我们的工作不需要自己保存这些值, 只需要异常处理中打印出这些反映程序状态的关键寄存器即可.

PSR: 程序状态字
PC: 程序计数器, 即程序指针
LR: 连接寄存器
R12: 通用高组寄存器
R0-R3: 通用低组寄存器

(1) 栈内容
struct stack_contex
{
        rt_uint32_t r0;
        rt_uint32_t r1;
        rt_uint32_t r2;
        rt_uint32_t r3;
        rt_uint32_t r12;
        rt_uint32_t lr;
        rt_uint32_t pc;
        rt_uint32_t psr;
};

(2) 异常状态下的系统内容提示
void rt_hw_hard_fault_exception(struct stack_contex* contex)
{
        rt_kprintf("psr: 0x%08x\n", contex->psr);
        rt_kprintf(" pc: 0x%08x\n", contex->pc);
        rt_kprintf(" lr: 0x%08x\n", contex->lr);
        rt_kprintf("r12: 0x%08x\n", contex->r12);
        rt_kprintf("r03: 0x%08x\n", contex->r3);
        rt_kprintf("r02: 0x%08x\n", contex->r2);
        rt_kprintf("r01: 0x%08x\n", contex->r1);
        rt_kprintf("r00: 0x%08x\n", contex->r0);

        rt_kprintf("hard fault on thread: %s\n", rt_current_thread->name);
#ifdef RT_USING_FINSH
        list_thread();
#endif
        while (1);
}


(4) 系统信息处理

串口

阿莫论坛20周年了!感谢大家的支持与爱护!!

该献的血还是要献的。你不献他不献。难道让我去献? --- 出自坛友:lovejp1981

出0入0汤圆

 楼主| 发表于 2010-3-30 15:16:20 | 显示全部楼层
由于串口部分 ffxz 修改了代码, 因此重新读了代码再写.

出0入0汤圆

发表于 2010-3-30 15:40:20 | 显示全部楼层
关于移植到新芯片的方法在其中的前两章有提及:
移植到GCC
移植到MDK

STM32章节是为了说明RT-Thread在STM32上的移植情况,实际的STM32使用则是拿来即可使用,不需要修改了。另外,fault.c中有一个while(1)。在实际的调试过程中也可以把这个while(1)拿掉,但需要在fault.S中设置一个断点(否则出现了fault也不知道,这个也是为什么前面留了一个while(1)的原因),这样断下来后可以直接单步跳回到出错的位置。

出0入0汤圆

 楼主| 发表于 2010-3-30 16:15:43 | 显示全部楼层
根据楼上 ffxz 的介绍我回过头再看了一遍前两章节,  确实发觉有条有理.

我第一遍看 RT-Thread 编程指南, 因为发觉 "移植到GCC", "移植到MDK" 两个章节是关于 AT91SAM7S 芯片的移植. 而我是用 STM32 的, 因此一扫而过, 没有重视.

而 STM32 介绍这个章节详细看了两遍, 当自己分析完关于 RTT 关于 STM32 移植之后, 回过头看了前两个章节, ffxz 的总结功底, 写的有条不紊, 不过我也理解了移植的内涵.

也明白了 ffxz 并不是拿 stm32 做移植范例, 而是选择了 AT91SAM7S. 是因为 AT91SAM7S 更加具有典型性,  STM32 因为 Cotex-M3 的内核特性, 已经简化了一些移植工作量. 所以不具有代表性.

=============================================================

^_^ , 今天很有收获.

出0入0汤圆

 楼主| 发表于 2010-3-30 16:20:53 | 显示全部楼层
编程指南的
"移植到GCC"
"移植到MDK"

这两个章节的标题是否应该修改个标题呢?

AT91SAM7S 基于 GCC 的移植
AT91SAM7S 基于 MDK 的移植

这样更加一目了然点.

出0入0汤圆

发表于 2010-3-30 16:41:38 | 显示全部楼层
呵呵,你上面的增补可以继续,当读书笔记也很好的,而且我在写的过程中可能考虑的角度不同,从读者的角度来理解可能会更好。

因为这篇文档成型的比较早,所以使用的是AT91SAM7S,也有过打算完全采用STM32,只是时间上不允许啊。至于标题,因为左边有导航栏,所以没有取这么长的标题。这个可以慢慢完善,增补进来。

出0入0汤圆

发表于 2010-3-31 13:45:05 | 显示全部楼层
安哥:
既然理解了RTT在STM32上的移植。
有没有兴趣写一个RTT移植到renesas M16C上的教程呢?

出0入0汤圆

发表于 2010-3-31 15:05:05 | 显示全部楼层
^--^,理论上讲,如果有ucos-ii的移植,把它迁移到RT-Thread是一件非常容易的事。

移植就那么点事:
- 线程上下文切换
- 开关中断
- 中断处理
- OS Timer处理
- 串口设备(提供给rt_kprintf使用)

出0入0汤圆

发表于 2010-8-18 11:13:30 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-8-18 15:01:23 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-9-6 19:42:16 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-11-10 20:48:31 | 显示全部楼层
学习了好多!!

出0入0汤圆

发表于 2013-3-12 19:31:08 来自手机 | 显示全部楼层
我还是不会……

出0入22汤圆

发表于 2013-3-12 23:27:27 来自手机 | 显示全部楼层
关注一个,哦哦哦

出0入0汤圆

发表于 2013-4-3 15:19:31 | 显示全部楼层
顶,正想移植到STM32

出0入0汤圆

发表于 2013-4-3 15:20:30 来自手机 | 显示全部楼层
水印。。

出0入0汤圆

发表于 2013-4-4 21:14:05 | 显示全部楼层
顶楼主学习了

出0入0汤圆

发表于 2014-7-10 23:04:41 来自手机 | 显示全部楼层
mark   cm3移植

出0入0汤圆

发表于 2014-7-10 23:26:56 | 显示全部楼层
我也想这样学习呢,所以现在开始好好加油!
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片。注意:要连续压缩2次才能满足要求!!】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-9-1 18:18

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表