查看: 4712|回复: 9

[分享] 【LPC分享】KEIL MDK环境下uCOS-II在LPC17xx上的移植实例(有源...

[复制链接]
  • TA的每日心情
    奋斗
    2017-5-3 11:19
  • 签到天数: 10 天

    [LV.3]偶尔看看II

    50

    主题

    1万

    帖子

    0

    金牌会员

    Rank: 6Rank: 6

    积分
    14090
    最后登录
    2024-4-19
    发表于 2016-9-23 10:36:59 | 显示全部楼层 |阅读模式
    本帖最后由 党国特派员 于 2016-9-23 10:39 编辑

    1. 知识准备
    要想对ucos-ii的移植有较深的理解,需要两方面知识:
    (1)目标芯片,这里是lpc17xx系列芯片,它们都是基于ARMv7 Cortex-M3内核,所以这一类芯片的ucos-ii移植几乎都是一样的,要想了解Cortex-M3内核,推荐《ARM Cortex-M3权威指南》(宋岩译);
    (2)ucos-ii内核原理,推荐《嵌入式实时操作系统uC/OS-II(第2版)》(邵贝贝译)。
    2. 下载文件
    ucos-ii移植过程主要涉及三个文件:os_cpu.h, os_cpu_a.asm和os_cpu_c.c
    实际上,一般情况下,我们想要移植的目标芯片前辈们都已经移植成功过了,我们需要做的就是下载就可以了。
    需要下载两类文件:
    (1)lpc17xx芯片启动/初始化代码:LPC17xx.h, system_LPC17xx.h, core_cm3.h, core_cm3.c, startup_LPC17xx.s和system_LPC17xx.c,这几个文件都可以从lpc官方网站lpc17xx系列芯片的任何一个项目中找到;
    (2)ucos-ii移植代码:可以在Micrium官方网站中找到uCOS-II在LPC17xx上的移植代码(IAR平台)。
    3. 创建工程
    (1)创建文件夹UCOS_II_V289,在该目录下创建子目录APP, lpc17xx, Output, uC-CPU, UCOS-II,在Output下创建obj和list子目录,然后将第2步下载的文件添加进相应的文件夹中,文件拓扑图如下:
    UCOS_II_V289
    ├─APP
    │      hello.c

    ├─lpc17xx
    │      core_cm3.c
    │      core_cm3.h
    │      LPC17xx.h
    │      startup_LPC17xx.s
    │      system_LPC17xx.c
    │      system_LPC17xx.h
    │      type.h

    ├─Output
    │  ├─list
    │  └─obj
    ├─uC-CPU
    │      os_cpu.h
    │      os_cpu_a.asm
    │      os_cpu_c.c
    │      os_dbg.c

    └─uCOS-II
             app_cfg.h
             os_cfg.h
             os_core.c
             os_flag.c
             os_mbox.c
             os_mem.c
             os_mutex.c
             os_q.c
             os_sem.c
             os_task.c
             os_time.c
             os_tmr.c
             ucos_ii.h
    其中,hello.c中的文件代码如下:
    1. #include <LPC17xx.h>
    2. #include <ucos_ii.h>

    3. #define TASK_STK_SIZE 512

    4. OS_STK TaskStartStk[TASK_STK_SIZE];

    5. void TaskStart(void *data);

    6. int main(void)
    7. {
    8.     OSInit();

    9.     OSTaskCreate(TaskStart, (void *)0, &TaskStartStk[TASK_STK_SIZE - 1], 0);

    10.     OSStart();

    11.     return 0;
    12. }

    13. void  TaskStart(void *data)
    14. {
    15.     data=data;

    16.     OS_CPU_SysTickInit(SystemFrequency/100);

    17.     for(;;)
    18.     {
    19.         OSCtxSwCtr = 0;
    20.         OSTimeDlyHMSM(0,0,0,10);
    21.     }
    22. }
    复制代码
    (2)Keil uVision4创建新工程,选择UCOS_II_V289作为工程目录,选择芯片型号,需要注意的是当提示“Copy NXP LPC17xx Startup Code to Project Folder and Add File to Project?”时,选择“否”,因为我们已经有这个文件了。创建组,添加相应文件到组,如下所示:
    2012121416403577.jpg
    右击“UCOS_II_V289”,更改工程设置:
    1.jpg
    2.jpg
    3.jpg
    如果勾选“Run to main()”,那么在仿真的时候,就会跳过启动代码,直接到main函数。
    4. 编译
    编译,会报很多错误,下面一个一个改:
    (1)将os_cpu_a.asm中的“public”改为“EXPORT”;
    (2)将os_cpu_a.asm中的
            RSEG CODE:CODE:NOROOT(2)        THUMB
    改为
            AREA OSKernelschedular,code,READONLY        THUMB
    (3)将os_cfg.h中“OS_APP_HOOKS_EN”、“OS_DEBUG_EN”和“OS_TASK_STAT_EN”设置为0;
    (4)将startup_LPC17xx.s中的所有的“PendSVHandler”改为“OS_CPU_PendSVHandler”,所有的“SysTickHandler”改为“OS_CPU_SysTickHandler”。
    编译通过。
    5. 软件仿真调试
    在步骤4中已经设置为软件仿真调试,编译成功后,即可添加断点进行软件仿真调试,查看代码运行是否符合预期。至此,移植结束。
    6. 相关说明
    (1)启动文件与启动流程
    i)启动文件
    启动文件为以下几个文件core_cm3.c, core_cm3.h, LPC17xx.h, startup_LPC17xx.s, system_LPC17xx.c 和 system_LPC17xx.h,下面分别说明它们的功能。
    startup_LPC17xx.s:该文件是Cortex-M3的启动汇编代码,阅读源代码不难发现,它的作用是:堆和栈的初始化以及向量表的定义。Cortex-M3的向量表其实就是一个32位整数数组,每个下标对应一个向量,该下标元素的值则是该中断服务子程序的入口地址。向量表在地址空间中的位置是可以设置的,通过NVIC(向量中断控制器)中的一个重定位七寸器来指出向量表的地址。复位后,该寄存器的值为0,因此,在地址0处必须包含一张向量表,用于初始时的中断分配。
    中断类型
    表项地址偏移量
    中断向量
    0
    0x00
    MSP的初始值
    1
    0x04
    复位
    2
    0x08
    NMI
    其中,向量表中的第一个元素并非中断向量,而是MSP(主堆栈寄存器)的初始值。
    LPC17xx.h:该文件是CM3(Cortex-M3,下同)内核芯片的头文件,它定义了芯片寄存器的结构体。
    core_cm3.h和core_cm3.c:这两个文件分别是CM3内核芯片的外围驱动头文件和源代码。
    system_LPC17xx.h和system_LPC17xx.c:这两个文件为我们提供了一个系统初始化函数SystemInit(),CM3的初始化包括时钟配置、电源管理、功耗管理等。其中时钟配置比较复杂,因为他包括两个PLL倍频电路,一个是主PLL0,主要为系统和USB提供时钟,另一个是PLL1,专门为USB提供48M时钟。默认情况下,系统使用12M外部晶振,通过PLL0倍频到一个较高的频率,之后可以通过分频为CPU、外设以及可选的USB子系统提供精确的时钟。
    ii)启动流程
    由Cortex-M3的启动步骤可知,系统上电后,首先执行复位的5个步骤:
         ①NVIC复位,控制内核;
         ②NVIC从复位中释放内核;
         ③内核配置堆栈;
         ④从地址0x00000000处取出MSP的初始值,从地址0x00000004处取出PC的初始值——这个值是复位向量;
         ⑤运行复位中断服务子程序;

    其中,复位中断服务子程序的代码如下:
    1. Reset_Handler   PROC
    2.                 EXPORT  Reset_Handler             [WEAK]
    3.                 IMPORT  SystemInit
    4.                 IMPORT  __main
    5.                 LDR     R0, =SystemInit
    6.                 BLX     R0
    7.                 LDR     R0, =__main
    8.                 BX      R0
    9.                 ENDP
    复制代码
    可知,通过复位中断服务子程序,首先引导程序进入SystemInit()函数,然后进入__main(此__main是C_Library中的函数,非main())。
    (2)SysTick定时器、SysTickInit与SysTickHandler
    i)SysTick定时器
    Cortex-M3内核内部包含了一个简单的定时器——SysTick定时器。SysTick定时器被捆绑在NVIC中,用于产生SysTick中断。一般情况下,操作系统以及所有使用了时基的系统,都必须由硬件定时器来产生需要的“滴答”中断,作为整个系统的时基。SysTick定时器就是用来产生周期性的中断,以维持操作系统“心跳”节律的。SysTick定时器的时钟源可以是内部时钟(FCLK,CM3上的自由运行时钟),或者是外部时钟(CM3上的STCLK信号)。
    SysTick定时器能产生中断,CM3为它专门开出一个中断类型,并且在向量表中有它的一席之地——SysTickHandler,它使得操作系统和其它软件系统在CM3内核的移植变得更加简单,因为在所有的CM3微处理器上,SysTick的处理方式都是相同的。
    有4个寄存器控制SysTick定时器,下面只介绍其中经常用到的三个:
    ①SysTick控制及状态寄存器(地址:0xE000E010)
    位段
    名称
    类型
    复位值
    描述
    16
    COUNTFLAG
    R
    0
    如果在上次读取本寄存器后,SysTick已经计到了0,则该位为1;如果读取该位,该位自动清0
    2
    CLKSOURCE
    R/W
    0
    0=外部时钟源(STCLK)
    1=内核时钟源(FCLK)
    1
    TICKINT
    R/W
    0
    1=SysTick倒数计数到0时产生SysTick异常请求
    0=倒数到0时无动作
    0
    ENABLE
    R/W
    0
    SysTick定时器的使能位
    ②SysTick重装载数值寄存器(地址:0xE000E014)
    位段
    名称
    类型
    复位值
    描述
    23:0
    RELOAD
    R/W
    0
    当倒数计数到0时,将被重装载的值
    ③SysTick当前数值寄存器(地址:0xE000E018)
    位段
    名称
    类型
    复位值
    描述
    23:0
    CURRENT
    R/Wc
    0
    读取时返回当前倒数计数的值,写它则使之清零,同时还会清除在SysTick控制及状态寄存器中的COUNTFLAG标志
    ii) SysTickInit()函数

    该函数用于初始化SysTick定时器,在本移植实例中,它位于os_cpu_c.c文件中,其函数名被更改为“OS_CPU_SysTickInit”,源代码如下:
    1. void  OS_CPU_SysTickInit (INT32U  cnts)
    2. {
    3.     OS_CPU_CM3_NVIC_ST_RELOAD = cnts - 1u;
    4.                                                  /* 设置SysTickHandler中断优先级为最低优先级           */
    5.     OS_CPU_CM3_NVIC_PRIO_ST   = OS_CPU_CM3_NVIC_PRIO_MIN;
    6.                                                  /* 使能定时器                                      */
    7.     OS_CPU_CM3_NVIC_ST_CTRL  |= OS_CPU_CM3_NVIC_ST_CTRL_CLK_SRC | OS_CPU_CM3_NVIC_ST_CTRL_ENABLE;
    8.                                                  /* 使能SysTickHandler中断                            */
    9.     OS_CPU_CM3_NVIC_ST_CTRL  |= OS_CPU_CM3_NVIC_ST_CTRL_INTEN;
    10. }
    复制代码
    第一行用于装载SysTick重装载数值寄存器,其他几行都有注释,在此不再解释。
    iii)SysTickHandler

    当SysTick定时器倒数计数到0时,将产生SysTick中断,该中断位于向量表15号位置(中断向量号:15,下同)。在本移植实例中,该中断服务子程序的名称被更改为“OS_CPU_SysTickHandler”,其位于os_cpu_c.c文件中,源码如下:
    1. void  OS_CPU_SysTickHandler (void)
    2. {
    3.     OS_CPU_SR  cpu_sr;


    4.     OS_ENTER_CRITICAL();                         /* Tell uC/OS-II that we are starting an ISR          */
    5.     OSIntNesting++;
    6.     OS_EXIT_CRITICAL();

    7.     OSTimeTick();                                /* Call uC/OS-II's OSTimeTick()                       */

    8.     OSIntExit();                                 /* Tell uC/OS-II that we are leaving the ISR          */
    9. }
    复制代码
    (3) OSCtxSw与PendSVHandler
    i)PendSV中断
    Cortex-M3内核内置了一个重要的中断——PendSV中断(可挂起的系统调用)。与SVC中断(系统服务调用,简称系统调用)不同的是,PendSV可以像普通的中断一样被挂起,OS可以利用它“缓期执行”一个中断——直到其他重要的任务完成后才执行动作。挂起PendSV的方法是:手动往NVIC的PendSV挂起寄存器中写1,挂起后,如果该中断优先级不够高,则将缓期等待执行。
    PendSV的典型功能是上下文(任务)切换。若在即将做上下文(任务)切换时发现CPU正在响应一个中断,这时,OS是不能执行上下文(任务)切换的,否则将使中断请求被延迟,而这在实时系统中是绝不能容忍的。PendSV可以完美地解决这个问题,PendSV中断会自动延迟上下文(任务)切换的请求,直到其他的中断请求都完成后才响应。为实现这个机制,需要把PendSV的优先级设置为最低,当OS需要做上下文(任务)切换时挂起一个PendSV中断即可。

    PendSV中断位于向量表14号位置,在本移植实例中,该中断服务子程序的名称被更改为“OS_CPU_PendSVHandler”,其位于os_cpu_a.asm文件中,源码如下:
    1. OS_CPU_PendSVHandler
    2.     CPSID   I                                                   ; Prevent interruption during context switch
    3.     MRS     R0, PSP                                             ; PSP is process stack pointer
    4.     CBZ     R0, OS_CPU_PendSVHandler_nosave                     ; Skip register save the first time

    5.     SUBS    R0, R0, #0x20                                       ; Save remaining regs r4-11 on process stack
    6.     STM     R0, {R4-R11}

    7.     LDR     R1, =OSTCBCur                                       ; OSTCBCur->OSTCBStkPtr = SP;
    8.     LDR     R1, [R1]
    9.     STR     R0, [R1]                                            ; R0 is SP of process being switched out

    10.                                                                 ; At this point, entire context of process has been saved
    11. OS_CPU_PendSVHandler_nosave
    12.     PUSH    {R14}                                               ; Save LR exc_return value
    13.     LDR     R0, =OSTaskSwHook                                   ; OSTaskSwHook();
    14.     BLX     R0
    15.     POP     {R14}

    16.     LDR     R0, =OSPrioCur                                      ; OSPrioCur = OSPrioHighRdy;
    17.     LDR     R1, =OSPrioHighRdy
    18.     LDRB    R2, [R1]
    19.     STRB    R2, [R0]

    20.     LDR     R0, =OSTCBCur                                       ; OSTCBCur  = OSTCBHighRdy;
    21.     LDR     R1, =OSTCBHighRdy
    22.     LDR     R2, [R1]
    23.     STR     R2, [R0]

    24.     LDR     R0, [R2]                                            ; R0 is new process SP; SP = OSTCBHighRdy->OSTCBStkPtr;
    25.     LDM     R0, {R4-R11}                                        ; Restore r4-11 from new process stack
    26.     ADDS    R0, R0, #0x20
    27.     MSR     PSP, R0                                             ; Load PSP with new process SP
    28.     ORR     LR, LR, #0x04                                       ; Ensure exception return uses process stack
    29.     CPSIE   I
    30.     BX      LR                                                  ; Exception return will restore remaining context

    31.     END
    复制代码
    ii)OSCtxSw

    ucos-ii中,OSCtxSw的功能是上下文(任务)切换。而由上面的介绍可知,真正的切换工作是在PendSV中断中完成的,那么可想而知,OSCtxSw只需触发一个PendSV中断即可完成上下文(任务)切换的工作。OSCtxSw位于os_cpu_a.asm文件中,源码如下:
    1. OSCtxSw
    2.     LDR     R0, =NVIC_INT_CTRL                                  ; Trigger the PendSV exception (causes context switch)
    3.     LDR     R1, =NVIC_PENDSVSET
    4.     STR     R1, [R0]
    5.     BX      LR
    复制代码
    7. 工程源码
    工程源码链接: UCOS_II_V289.rar (606.79 KB, 下载次数: 121)
    该会员没有填写今日想说内容.
    回复

    使用道具 举报

  • TA的每日心情
    开心
    2016-12-19 14:46
  • 签到天数: 11 天

    [LV.3]偶尔看看II

    4

    主题

    101

    帖子

    0

    注册会员

    Rank: 2

    积分
    179
    最后登录
    2018-9-19
    发表于 2016-11-2 16:05:37 | 显示全部楼层
    不错, 不错!很好的帖子!
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    开心
    2016-11-13 14:54
  • 签到天数: 4 天

    [LV.2]偶尔看看I

    1

    主题

    70

    帖子

    0

    注册会员

    Rank: 2

    积分
    137
    最后登录
    2016-11-13
    发表于 2016-11-9 20:24:45 | 显示全部楼层
       谢谢楼主
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    开心
    昨天 11:19
  • 签到天数: 818 天

    [LV.10]以坛为家III

    71

    主题

    2444

    帖子

    24

    金牌会员

    Rank: 6Rank: 6

    积分
    5513
    最后登录
    2024-4-23
    发表于 2016-11-21 14:10:25 | 显示全部楼层
    收藏了谢谢
    该会员没有填写今日想说内容.
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    无聊
    2019-5-1 06:15
  • 签到天数: 5 天

    [LV.2]偶尔看看I

    0

    主题

    91

    帖子

    0

    中级会员

    Rank: 3Rank: 3

    积分
    207
    最后登录
    2021-8-4
    发表于 2019-5-1 06:21:04 | 显示全部楼层
    谢谢分享
    该会员没有填写今日想说内容.
    回复

    使用道具 举报

  • TA的每日心情
    开心
    2020-12-18 10:54
  • 签到天数: 8 天

    [LV.3]偶尔看看II

    40

    主题

    262

    帖子

    0

    高级会员

    Rank: 4

    积分
    977
    最后登录
    2024-3-10
    发表于 2020-9-20 12:58:30 | 显示全部楼层
    谢谢分享
    哎...今天够累的,签到来了~
    回复

    使用道具 举报

  • TA的每日心情
    开心
    2020-12-18 10:54
  • 签到天数: 8 天

    [LV.3]偶尔看看II

    40

    主题

    262

    帖子

    0

    高级会员

    Rank: 4

    积分
    977
    最后登录
    2024-3-10
    发表于 2020-12-9 13:03:14 | 显示全部楼层
    谢谢分享~~~~
    哎...今天够累的,签到来了~
    回复

    使用道具 举报

  • TA的每日心情
    开心
    2020-12-18 10:54
  • 签到天数: 8 天

    [LV.3]偶尔看看II

    40

    主题

    262

    帖子

    0

    高级会员

    Rank: 4

    积分
    977
    最后登录
    2024-3-10
    发表于 2020-12-9 13:31:03 | 显示全部楼层
    官网上已经有2.92版本的
    哎...今天够累的,签到来了~
    回复 支持 反对

    使用道具 举报

    该用户从未签到

    0

    主题

    5

    帖子

    0

    新手上路

    Rank: 1

    积分
    23
    最后登录
    2021-4-19
    发表于 2021-3-31 13:35:57 | 显示全部楼层
    谢谢楼主分享经验
    回复 支持 反对

    使用道具 举报

    该用户从未签到

    0

    主题

    1

    帖子

    0

    新手上路

    Rank: 1

    积分
    14
    最后登录
    2024-1-5
    发表于 2024-1-5 11:26:50 | 显示全部楼层
    謝謝,分享
    回复

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 /4 下一条

    Archiver|手机版|小黑屋|恩智浦技术社区

    GMT+8, 2024-4-24 05:57 , Processed in 0.143466 second(s), 29 queries , MemCache On.

    Powered by Discuz! X3.4

    Copyright © 2001-2024, Tencent Cloud.

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