[STM32F429-DISCO-uCosiii]1.uCOSIII 移植

uCOSiii的结构比uCOSii看上去是清晰了不少,也比较有条理,所以呢,移植不是让人感觉很乱。在工程中添加如下目录和文件

     与CPU相关的文件都集中在uC-CPU文件夹中。这部分有很多是底层的实现,比如调度算法,CPU现场保护,前导零,时间相关的函数,其中也有不少我们需要自己来添加相关代码。库文件提供了我们对字符串、数学运算、存储运算等的处理函数,ucOS-OS提供了操作系统的各功能模块代码。移植的详细步骤UCOSiii user manual.pdf比较详细 我参考其中文译书《嵌入式实时操作系统ucos-iii》和《嵌入式实时操作系统uc/os-iii应用开发-基于STM32处理器》来完成移植工作。官网上有stm32移植的例子,但是用起来比较麻烦,startup里大部分中断向量表里定义的函数名和标准库给的不一样。我们可参照其现成的汇编代码,来移植,这样会更容易些

     操作系统最频繁调用的两个中断是PendSV与Systick,在startup_stm32xxxx.s中 找到中断向量表对应的中断向量的名字,像这样。这个就对应着中断函数名,不要搞错了,我们需要注释掉stm32f4xx.it.c中相关的中断函数,但是如果我们用到了延迟函数,不要忘记systick_handler()中添加HAL_IncTick(); 目的是delay还可以用,我们SDRAM配置的时候要用到1ms延时。所以暂时可以这样。。。谁让我们还需要HAL库呢。。

     我们的主要工作集中在os_cpu.h、os_cpu_c.c和os_cpu_a.s这三个文件上。。其实就是和CPU架构直接相关的函数的编写。

    os_cpu.h中。定义了几个宏与函数,我们可以看出,OS_TASK_SW()与OSIntCtxSW()的实现,其实就是向NVIC中断控制寄存器内写入PENDSV触发值,以触发pendsv中断来完成的。我们需要完成几个函数,直接上代码

#ifndef  OS_CPU_H
#define  OS_CPU_H
#include "CPU.h"
#ifdef   OS_CPU_GLOBALS
#define  OS_CPU_EXT
#else
#define  OS_CPU_EXT  extern
#endif

#ifndef  NVIC_INT_CTRL
#define  NVIC_INT_CTRL                      *((CPU_REG32 *)0xE000ED04)
#endif

#ifndef  NVIC_PENDSVSET
#define  NVIC_PENDSVSET                                    0x10000000
#endif

#define  OS_TASK_SW()               NVIC_INT_CTRL = NVIC_PENDSVSET
#define  OSIntCtxSw()               NVIC_INT_CTRL = NVIC_PENDSVSET

#if      OS_CFG_TS_EN == 1u
#define  OS_TS_GET()               (CPU_TS)CPU_TS_TmrRd()   /* See Note #2a.                                          */
#else
#define  OS_TS_GET()               (CPU_TS)0u
#endif

#if (CPU_CFG_TS_32_EN    == DEF_ENABLED) && \
    (CPU_CFG_TS_TMR_SIZE  < CPU_WORD_SIZE_32)
                                                            /* CPU_CFG_TS_TMR_SIZE MUST be >= 32-bit (see Note #2b).  */
#error  "cpu_cfg.h, CPU_CFG_TS_TMR_SIZE MUST be >= CPU_WORD_SIZE_32"
#endif

#define  OS_CPU_CFG_SYSTICK_PRIO           0u
/*
*********************************************************************************************************
*                                          GLOBAL VARIABLES
*********************************************************************************************************
*/
OS_CPU_EXT  CPU_STK  *OS_CPU_ExceptStkBase;

/*
*********************************************************************************************************
*                                         FUNCTION PROTOTYPES
*********************************************************************************************************
*/
void  OSStartHighRdy       (void);
void  PendSV_Handler (void);
void  SysTick_Handler(void);
void  OS_CPU_SysTickInit   (CPU_INT32U  cnts);

从os_cpu.h的定义中,我们就知道了我们所需要做的工作了。。。最下面四个函数的实现一个一个来,PendSV_Handler汇编程序:

PendSV_Handler
    CPSID   I                                                       ; Prevent interruption during context switch
    MRS     R0, PSP                                                ; PSP is process stack pointer
    CBZ     R0, PendSV_Handler_nosave                           ; Skip register save the first time

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

    LDR     R1, =OSTCBCurPtr                                   ; OSTCBCurPtr->OSTCBStkPtr = SP;
    LDR     R1, [R1]
    STR     R0, [R1]                                              ; R0 is SP of process being switched out

                                                                      ; At this point, entire context of process has been saved
PendSV_Handler_nosave
    PUSH    {R14}                                                    ; Save LR exc_return value
    LDR     R0, =OSTaskSwHook                              ; OSTaskSwHook();
    BLX     R0
    POP     {R14}

    LDR     R0, =OSPrioCur                                        ; OSPrioCur   = OSPrioHighRdy;
    LDR     R1, =OSPrioHighRdy
    LDRB    R2, [R1]
    STRB    R2, [R0]

    LDR     R0, =OSTCBCurPtr                                  ; OSTCBCurPtr = OSTCBHighRdyPtr;
    LDR     R1, =OSTCBHighRdyPtr
    LDR     R2, [R1]
    STR     R2, [R0]

    LDR     R0, [R2]                                                ; R0 is new process SP; SP = OSTCBHighRdyPtr->StkPtr;
    LDM     R0, {R4-R11}                                            ; Restore r4-11 from new process stack
    ADDS    R0, R0, #0x20
    MSR     PSP, R0                                                  ; Load PSP with new process SP
    ORR     LR, LR, #0x04                                           ; Ensure exception return uses process stack
    CPSIE   I
    BX      LR                                                      ; Exception return will restore remaining context

看看它做了什么?第一步 关中断啦。防止骚扰。。然后如果是第一次就跳过CPU寄存器的保护工作,否则保护现场。然后到了 PendSV_Handler_nosave标号。他做了这些事情,最高进程的优先级给当前优先级,最高进程的TCB赋予当前TCB,还有堆栈指针暂时给R0。然后恢复新的任务现场(即R4-R11)。然后就恢复新的SP,这样就可以执行新的进程了。

SysTick_Handler就比较简单了。直接上代码即可

void  SysTick_Handler (void)
{

    HAL_IncTick();            //add manually , to make the delay(ms)function work..

    CPU_SR_ALLOC();

    CPU_CRITICAL_ENTER();
    OSIntNestingCtr++;                                      /* Tell uC/OS-III that we are starting an ISR             */
    CPU_CRITICAL_EXIT();

    OSTimeTick();                                           /* Call uC/OS-III‘s OSTimeTick()                          */

    OSIntExit();                                            /* Tell uC/OS-III that we are leaving the ISR             */
}

它实际做了两件事,进入中断模式,调用OSTimeTick(),但我们需要的delay也是靠这个函数实现的,所以加上我们需要的HAL_IncTick函数。其实我们可以将HAL使用的Delay用TImer6或者其他定时器实现,这个稍后再改吧。。先凑合用。

OSStartHighRdy:

OSStartHighRdy
    LDR     R0, =NVIC_SYSPRI14                                 ; Set the PendSV exception priority
    LDR     R1, =NVIC_PENDSV_PRI
    STRB    R1, [R0]

    MOVS    R0, #0                                                  ; Set the PSP to 0 for initial context switch call
    MSR     PSP, R0

    LDR     R0, =OS_CPU_ExceptStkBase                           ; Initialize the MSP to the OS_CPU_ExceptStkBase
    LDR     R1, [R0]
    MSR     MSP, R1    

    LDR     R0, =NVIC_INT_CTRL                                  ; Trigger the PendSV exception (causes context switch)
    LDR     R1, =NVIC_PENDSVSET
    STR     R1, [R0]

    CPSIE   I                                                   ; Enable interrupts at processor level

OSStartHang
    B       OSStartHang                                         ; Should never get here

实质还是出发了 PENDSV来实现的

OS_CPU_SysTickInit:此函数目的就是让systick每1ms触发一次中断,实际上我们可以这样:

uint32_t  cnt = HAL_RCC_GetSysClockFreq() / (uint32_t)OS_CFG_TICK_RATE_HZ;
OS_CPU_SysTickInit(cnt);

cnt的值就是180,000

我们需要OS的Timer,需要定义并实现两个函数:

void  CPU_TS_TmrInit (void);

CPU_TS_TMR  CPU_TS_TmrRd (void);

这两个函数 官方给的是看门狗来计时的,我们可以换Timer6/7基本定时期来实现。。让狗狗啃骨头去。。。

大部分工作,我们已经做完了。包括系统滴答,任务调度等。。。

cpu.h 、cpu.c、cpu.a中的内容比较少了。主要是程序状态寄存器的保存和前导零等等。

EXPORT  CPU_IntDis
        EXPORT  CPU_IntEn

        EXPORT  CPU_SR_Save
        EXPORT  CPU_SR_Restore

        EXPORT  CPU_WaitForInt
        EXPORT  CPU_WaitForExcept

        EXPORT  CPU_CntLeadZeros
        EXPORT  CPU_CntTrailZeros
        EXPORT  CPU_RevBits

这是cpu.a实现的函数。。。顾名思义吧,很简洁的代码,不难懂。

这样基本上我们就可以跑一个任务试试了。。就拿上午刷LCD的程序来开刀。

main.c如下

int main(void)
{

    /* STM32F4xx HAL library initialization:
       - Configure the Flash prefetch, Flash preread and Buffer caches
       - Systick timer is configured by default as source of time base, but user
             can eventually implement his proper time base source (a general purpose
             timer for example or other time source), keeping in mind that Time base
             duration should be kept 1ms since PPP_TIMEOUT_VALUEs are defined and
             handled in milliseconds basis.
       - Low Level Initialization
     */
    HAL_Init();

    /* Configure the System clock to 180 MHz */
    SystemClock_Config();

    OS_ERR err;
    //OS_CPU_SysTickInit( SystemCoreClock / OSCfg_TickRate_Hz );    //Load SysTick to trigger ISR every 1 ms
    OSInit(&err);
    OSTaskCreate((OS_TCB     *)&AppTaskStartTCB,                /* Create the start task                                */
                 (CPU_CHAR   *)"App Task Start",
                 (OS_TASK_PTR ) AppTaskStart,
                 (void       *) 0,
                 (OS_PRIO     ) APP_TASK_START_PRIO,
                 (CPU_STK    *)&AppTaskStartStk[0],
                 (CPU_STK_SIZE) APP_TASK_START_STK_SIZE / 10,
                 (CPU_STK_SIZE) APP_TASK_START_STK_SIZE,
                 (OS_MSG_QTY  ) 5u,
                 (OS_TICK     ) 0u,
                 (void       *) 0,
                 (OS_OPT      )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR),
                 (OS_ERR     *)&err);

    OSStart(&err);
    /* Infinite loop */
    /* Add your application code here
     */

    /* Infinite loop */
    while (1)
    {

    }
}

static  void  AppTaskStart (void *p_arg)
{
//    int i = 0 ;
    OS_ERR      err;
   (void)p_arg;

    /* Initialize BSP functions                             */
    CPU_Init();

    /* Init uC/OS periodic time src (SysTick).              */
    uint32_t  cnt = HAL_RCC_GetSysClockFreq() / (uint32_t)OS_CFG_TICK_RATE_HZ;
    OS_CPU_SysTickInit(cnt);  

    /* Initialize ucOS Memory Management Module                  */
    Mem_Init();     

#if OS_CFG_STAT_TASK_EN > 0u
    OSStatTaskCPUUsageInit(&err);                               /* Compute CPU capacity with no task running            */
#endif

    CPU_IntDisMeasMaxCurReset();

#if (APP_CFG_SERIAL_EN  == DEF_ENABLED)
    //BSP_Ser_Init(115200);                                       /* Enable Serial Interface                              */
#endif

   // APP_TRACE_INFO(("Creating Application Tasks...\n\r"));
    AppTaskCreate();                                            /* Create Application Tasks                             */

 //   APP_TRACE_INFO(("Creating Application Events...\n\r"));
    AppObjCreate();                                             /* Create Application Objects                           */

   // BSP_LED_Off(0);

    while (DEF_TRUE)
    { /* Task body, always written as an infinite loop.       */
        LCD_TEXT_STRINGLINE("hello world");
        BSP_LED_Toggle(LED3);
        BSP_LED_Toggle(LED4);
        OSTimeDlyHMSM(0, 0, 0, 500, OS_OPT_TIME_HMSM_STRICT, &err);
    }
}

来看效果图

可能有疏漏。。。发现了一定及时改。。虽然没人看哈哈

时间: 2024-10-28 21:09:39

[STM32F429-DISCO-uCosiii]1.uCOSIII 移植的相关文章

ucosiii 移植

最近想在 f429 上面使用 mdk526 版本的 IDE,配合 HAL 和ucosiii.考虑到的方法是对比 v7 开发板的 ucosiii 和裸机程序,找出需要修改的地方,然后对比 v6 开发板的 ucosiii 和 裸机程序,然后把相应的修改融合起来即可. 一. V7开发板 ucosiii 和 裸机程序对比差别: 工程配置中头文件包含增加了: ....\uCOS-III\uC-CPU ....\uCOS-III\uC-CPU\ARM-Cortex-M\ARMv7-M\RealView ..

第39章 ETH—Lwip以太网通信

第39章     ETH-Lwip以太网通信 全套200集视频教程和1000页PDF教程请到秉火论坛下载:www.firebbs.cn 野火视频教程优酷观看网址:http://i.youku.com/firege 互联网技术对人类社会的影响不言而喻.当今大部分电子设备都能以不同的方式接入互联网(Internet),在家庭中PC常见的互联网接入方式是使用路由器(Router)组建小型局域网(LAN),利用互联网专线或者调制调解器(modem)经过电话线网络,连接到互联网服务提供商(ISP),由互联

STM32F429i-DISCO FreeRTOS keil STM32CubeMX

目标: 在STM32F429 Disco开发板上用FreeRTOS双线程点亮双闪led. 准备: 0. STM32F429i-DISCO 1. keil ARMMDK 5.13 2. STM32CubeMX 4.8 步骤: 1. 建立工程 keil - project - new project 2. 保存在硬盘上, 给工程起名字 3. 保存工程 同时弹出了器件选择界面, 选STM32F429ZITx 4. 上面界面点OK后出来了运行环境配置界面 展开CMSIS:RTOS and enable

【Xilinx-ZYNQ ucos-iii的移植与开发】-00-开始

前一段时间,调试了一块ZYNQ的板子,上面用到了ucos-iii操作系统,最终在该板子上实现了操作系统的运行,并实现了一些外设模块的功能,主要包括PWM,I2C,GPIO,两级中断. 等有空了总结一下. 包括操作系统的移植(不算是移植,因为官方已经做好了-_-,就介绍一下怎么安装到Xilinx SDK当中去,和一些必要的参数配置), 基于ZYNQ ucos-iii的平台编写了一些AXI4外设模块的驱动程序,到时候也介绍一下,最重要的是AXI4 Interrupt Controller这个模块的功

20155227辜彦霖《基于Cortex-M4的UCOSIII的应用》课程设计个人报告

20155227辜彦霖<基于Cortex-M4的UCOSIII的应用>课程设计个人报告 一.个人贡献 参与课设题目讨论及完成全过程: 资料收集: 负责主要代码调试: 撰写小组结题报告. 二.设计中遇到的问题及解决方法 ① 移植之后编译出现错误,没能出现正确现象: 解决方法是修改几个重要文件时出错,具体如图: ②老师给的示例代码是基于STM32F429的,没法在STM32F407上出现结果,需要修改 修改心路历程大致如下:先找到在STM32F407能够成功运用LCD上出现现象的工程,对比两个工程

ucos-III前言

前言 自从 2009年 uC/OS-III实时操作系统面世以来,uC/OS-III的性能和稳定性已经日趋完善.uC/OS-III对前面版本取精弃粕,推陈出新,功能和性能比起 uC/OS-II已经上了很大一步台阶.uC/OS-III 正在逐渐取代 uC/OS-II,学习 uC/OS-III 已经成为许多嵌入式工程师迫在眉睫的一件事. 下面是 uC/OS 系统各个版本的对比. uC/OS-III 的源码已经跟前面版本的源码相差很大,很多方面都做了更加规范的修改,很多处理问题的机制也有很大的突破. 因

stm32f407 官方ucos-iii 不支持FPU 导致haltfault错误的处理办法

由于官方提供的μCOS-III移植工程中对于浮点寄存器的入栈和出栈处理是错误的,所以网上就流传了 各种修正版本.但是这些修正的代码只能在 MDK4.7 以下版本中可以正常的运行,MDK4.7 及其以上的版 本无法正常运行.下面针对高版本的MDK进行修正处理 处理方法如下: 为了解决 FPU 的问题,有两个函数需要修改:一个是 CPU_STK  *OSTaskStkInit(),另一个是 PendSV 中断. 最后需要在工程选项中开启FPU的支持 修改函数CPU_STK  *OSTaskStkIn

嵌入式:UCOSIII的使用

0.一些移植.系统相关 OS_CFG_APP.H /* --------------------- MISCELLANEOUS ------------------ */ #define OS_CFG_MSG_POOL_SIZE 100u /* 消息池 大小 */ #define OS_CFG_ISR_STK_SIZE 128u /* Stack size of ISR stack (number of CPU_STK elements) */ #define OS_CFG_TASK_STK_L

uCOSIII任务管理

任务简介: 任务即由系统管理的程序实体,由三部分组成: 任务堆栈:本质是一个数组,不同的任务在创建前可以自己定义相关数组的大小: 任务控制块:本质上是一个结构体,用于保存任务当前的各种状态信息,其成员只可用uCOSIII相关函数访问,用户不可直接访问: 任务函数:即表达任务功能的地方,通过系统调用来切换,分为运行至完成型(完成后自我删除)和无限循环型(while(1)): 任务还有一些其他属性,如优先级等等,这些在以后使用中会注意到: 任务状态: 用户角度: 休眠态:任务已经在CPU的flash