[STM32F429-DISCO-uCosiii]3.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- 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- 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, # ; Set the PSP to 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 *) ,
(OS_PRIO ) APP_TASK_START_PRIO,
(CPU_STK *)&AppTaskStartStk[],
(CPU_STK_SIZE) APP_TASK_START_STK_SIZE / ,
(CPU_STK_SIZE) APP_TASK_START_STK_SIZE,
(OS_MSG_QTY ) 5u,
(OS_TICK ) 0u,
(void *) ,
(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 ()
{ }
} 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(, , , , OS_OPT_TIME_HMSM_STRICT, &err);
}
}
来看效果图
可能有疏漏。。。发现了一定及时改。。虽然没人看哈哈
[STM32F429-DISCO-uCosiii]3.uCOSIII 移植的更多相关文章
- 在秉火STM32F429挑战者开发板上移植Huawei LiteOS指南
昨天在B站上突然看到了一个短视频,是在正点原子的战舰V3开发板上移植华为的Huawei LiteOS操作系统,就是这个视频:看完鸿蒙OS发布会,试用华为的物联网操作系统Lite OS(B站),于是呢, ...
- uCos-III移植到STM32F10x
最近在百度上看了uCOS-III 的介绍后,诸多功能有很大的提升和改进,感觉有必要升级一下开发环境.百度介绍:http://baike.baidu.com/view/8531313.htm 环境: S ...
- ucosiii 移植
最近想在 f429 上面使用 mdk526 版本的 IDE,配合 HAL 和ucosiii.考虑到的方法是对比 v7 开发板的 ucosiii 和裸机程序,找出需要修改的地方,然后对比 v6 开发板的 ...
- stm32之UCOS-III
一.UCOS-III 学习UCOS-III,一般会学习以下内容: 任务创建.删除.挂起.恢复等: 临界区:独占CPU,尽量少用,否则会降低效率: 时间管理:时钟节拍(基于硬件定时器).软件定时器: 互 ...
- UCOSIII(一)
一,前后台系统和RTOS 1,前后台系统 早期嵌入式开发没有嵌入式操作系统的概念 ,直接操作裸机,在裸机上写程序,比如用51单片机基本就没有操作系统的概念.通常把程序分为两部分:前台系统和后台系统. ...
- 第39章 ETH—Lwip以太网通信—零死角玩转STM32-F429系列
第39章 ETH—Lwip以太网通信 全套200集视频教程和1000页PDF教程请到秉火论坛下载:www.firebbs.cn 野火视频教程优酷观看网址:http://i.youku.com/ ...
- stm32CubeMx+TrueSTUDIO+uc/os-III移植开发(二)
(三)复制相关文件 (1)继上次的代码生成后会显示如下的图 点击第一个,打开文件夹如下 (2)新建文件夹UCOSIII 在UCOSIII文件夹下,新建如下的文件夹 (3)将uc/os源文件中 Micr ...
- ETH—Lwip以太网通信
第39章 ETH—Lwip以太网通信 全套200集视频教程和1000页PDF教程请到秉火论坛下载:www.firebbs.cn 野火视频教程优酷观看网址:http://i.youku.com/ ...
- 第39章 ETH—Lwip以太网通信
第39章 ETH—Lwip以太网通信 全套200集视频教程和1000页PDF教程请到秉火论坛下载:www.firebbs.cn 野火视频教程优酷观看网址:http://i.youku.com/ ...
- 程序进入 EXPORT App_Fault_ISR的原因及措施:
最近再UCOSIII+LPC1768上移植modbus,在定时器初始化部分竟然跑飞进入 EXPORT App_Fault_ISR,查资料.逛论坛.问大牛都没有解决,最后发现竟然是犹豫一个低级失误引起 ...
随机推荐
- PHP接入阿里云市场 阿里短信服务DEMO
阿里短信服务:支持三大运营商短信.智能管道等优质能力,产品特点:3秒可达.99%到达率.超低资费. 使用阿里短信服务步骤: 1.购买服务 到https://market.aliyun.com/prod ...
- accp8.0转换教材第5章事务、视图、索引、备份和恢复理解与练习
知识点:事务.视图.索引.数据库的备份和恢复 一.单词部分 ①transation事务②atomicity原子性③consistency一致性④isolation隔离性 ⑤durability持久性⑥ ...
- Vijos 1006 晴天小猪历险记之Hill 单源单汇最短路
背景 在很久很久以前,有一个动物村庄,那里是猪的乐园(^_^),村民们勤劳.勇敢.善良.团结-- 不过有一天,最小的小小猪生病了,而这种病是极其罕见的,因此大家都没有储存这种药物.所以晴天小猪自告奋勇 ...
- 教你如何取消GCD任务
GCD 是一种非常方便的使用多线程的方式.通过使用 GCD,我们可以在确保尽量简单的语法的前提下进行灵活的多线程编程.在 "复杂必死" 的多线程编程中,保持简单就是避免错误的金科玉 ...
- JavaScript中的坑--全局变量惹得祸
js中变量的作用域及闭包的概念 概述 身为一名程序员,因为bug周末加班是必不可少的事情,当解决bug的时候,总有些bug是因为规范导致的,但是这些bug往往不好找,也就是"前人挖坑,后 ...
- powershell 统计AD中所有计算机及对应的操作系统信息
要想用powershell管理域,首先先加载activedirectory模块 PS C:\> import-module activedirectory 下面就可以利用get-adcomput ...
- python新手之一环境安装
今天开始学习python,首先环境安装 1.在https://www.python.org/downloads/下载python2.X或者3.X(ps:这里建议下载32位的python ,因为64位p ...
- Spark的误解-不仅spark是内存计算,hadoop也是内存计算
市面上有一些初学者的误解,他们拿spark和hadoop比较时就会说,Spark是内存计算,内存计算是spark的特性.请问在计算机领域,mysql,redis,ssh框架等等他们不是内存计算吗?依据 ...
- java基础05 集合
一.集合的由来? 我们学习Java,可以操作很多对象 ,存储 的容器有数组和StringBuffer,StringBuilder; 而数组的长度固定,所以不适合做变化的需求,Java就提供了集合供我们 ...
- python中的模块,以及包的导入的总结
模块导入的方式: 模块的概念:一个.py文件就称为一个模块 导入模块中函数的方式: 方式一:import 模块名 使用时:模块名.函数名() 方式二 :from 模块名 import 函数名 使用 ...