首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

使用ADS移植mC/OS-II实例分析 03

使用ADS移植mC/OS-II实例分析 03

OSIntCtxSw 最重要的作用就是它完成了在中断ISR中直接进行任务切换,从而提高了实时响应的速度。它发生的时机是在 ISR 执行到 OSIntExit 时,如果发现有高优先级的任务因为等待的 time tick 到来获得了执行的条件,这样就可以马上被调度执行,而不用返回被中断的那个任务之后再进行任务切换,因为那样的话就不够实时了。
 
  实现 OSIntCtxSw 的方法大致也有两种情况:一种是通过调整 sp 堆栈指针的方法,根据所用的编译器对于函数嵌套的处理,通过精确计算出所需要调整的 sp 位置来使得进入中断时所作的保存现场的工作可以被重用。这种方法的好处是直接在函数嵌套内部发生任务切换,使得高优先级的任务能够最快的被调度执行。但是这个办法需要和具体的编译器以及编译参数的设置相关,需要较多技巧。
 
  另一种是设置需要切换标志位的方法,在 OSIntCtxSw 里面不发生切换,而是设置一个需要切换的标志,等函数嵌套从进入OSIntExit => OS_ENTER_CRITICAL() => OSIntCtxSw() => OS_EXIT_CRITICAL() => OSIntExit退出后,再根据标志位来判断是否需要进行中断级的任务切换。这种方法的好处是不需要考虑编译器的因素,也不用做计算,但是从实时响应上不是最快,不过这种方法实现起来比较简单。
 
  在中断态下进行任务切换,需要特别说明的一个问题是如何获得被中断任务的  lr_svc .因为进入中断态后,lr 变成了lr_irq ,原来任务的 lr_svc 无法在中断态下获得,这样要得到lr_svc,就必须在中断 ISR 里面进行一次cpu mode强制转换,即对CPSR赋值为0x000000d3,只有返回到svc态之后才能得到 原来任务的lr,这个对于任务切换很重要。还有一个需要留意的问题是在强制CPSR变成svc态之后,SPSR 也会相应地变成 SPSR_irq,这样就需要在强制转变之前保存 SPSR ,也就是被中断任务中断前的 CPSR .移植中使用的编程技巧ADS 编译器在编译 C 语言的程序时,如果程序中使用了 main 函数,则编译器将自动添加如下代码,完成初始化堆栈和C库等工作,工作流程如下:1> 将执行文件中的 RO 段和 RW 段从 load address 复制到 execution address 2> 初始化 ZI 区域,用 0 来初始化变量3> 跳转到 __rt_entry 执行如下 4 个调用3.1> 调用 __rt_statckheap_init ,建立程序的堆和栈3.2> 调用 __rt_lib_init ,初始化程序用到的 C 库,并为 main 传递参数3.3> 调用 main ,即用户程序的入口3.4> 调用 exit因为系统复位后,在启动代码中已经设置了系统堆栈,同时也不需要使用C库,因此可以从 __rt_entry 处直接跳转到mC/OS-II 的代码中,即直接执行 main 函数,可以用新的 __rt_entry 来作为链接的目标入口。
 
  IMPORT main EXPORT __rt_entry __rt_entry b main这样在启动代码的最后,加入一条跳转语句:bl __main __main 入口是用户程序执行的真正入口,我们利用 armCC 编译 C 里面的 main 入口以求得到 1> 和 2> 的代码,使得可以支持全局变量。否则的话,必须自己来实现全局变量的初始化或者把这些初始化操作放到函数内部来实现。
 
  另外一个非常有用的编程技巧是通过串口实现自己的 printf 输出。 如果使用armCC编译器的 semihosting 的话,会把 printf 通过 target 的 swi 0x123456 输出。如果已经实现的 serial_putchar 之类的函数,那么可以用它来实现 fputc 接口,也就是低级的输出函数,这样就可以使用 printf 来输出了,详细的做法在 ADS 安装目录下面的文档里可以找到,这里就不再赘述
返回列表