在STM32F401上移植uC/OS的一个小问题 [原创]
STM32F401xx是意法半导体新推出的Cortex-M4内核的MCU,相较于已经非常流行的STM32F407xx和STM32F427xx等相同内核的MCU而言,其特点是功耗仅为128uA/MHz,且存在64pin封装的小封装器件。我设计一款新产品使用了STM32F401xx,想把自己熟悉的uC/OS-II实时操作系统移植到这款MCU上。懒得从底层开始从头移植,偷懒从原子的“探索者”开发板移植的uC/OS-II开始修改。完成后在板子上一跑,发现系统时钟总存在约5%的偏差。仔细搜索代码后才发现,问题在把原子的uC/OS-II移植直接用在STM32F401上时的一个小bug,把发现问题的过程和解决办法分享给大家。
以下原创内容欢迎网友转载,但请注明出处:http://cnblogs.com/helesheng
一、把探索者开发板移植的uC/OS-II用在STM32F401xx上
原子的探索者开发板使用了STM32F407ZG,其内核是和32F401xx 相同的Cortex-M4,外设也基本相同。简单地将原子在探索者开发板上移植的uC/OS-II工程中的Device修改为STM32F401RC,编译后发现大量的预定义找不到。想到可能是代表处理器的预定义的宏没有修改,在Option中的C/C++页中,将Preprocessor Symbols改为代表401的“STM32F401xx,USE_STDPERIPH_DRIVER”,直接编译通过,心中一阵窃喜。

图1 修改预定义
二、uC/OS-II系统时钟偏差的小问题
运行之前在其它款STM32上写的uC/OS-II程序,开始一切顺利,但随后用示波器仔细分析各个任务内部及相互间的时间关系时,发现总存在+5%左右的时间误差,即实际系统时钟的周期只有理论系统时钟的95%左右。以每秒系统节拍数OS_TICKS_PER_SEC设置为200为例,每个OSTimeDly(1);的任务延迟仅为4750us。
开始以为是原子编写的延迟函数void delay_ms(u16 nms);的问题,仔细阅读代码后发现,这个函数只是在调用系统延迟函数OSTimeDly();的基础之上,将无法由系统延迟实现的us级延迟改由硬延迟实现。虽然我个人非常不赞同这种做法,因为这会造成uC/OS-II时间调度的盲区,从而影响uC/OS-II系统的实时性。但这不至于造成系统时钟的偏差,继续查找问题的原因。
既然调用系统延迟函数OSTimeDly的过程没有问题,那么只可能是系统时钟本身出了问题。Cortex-M内核的uC/OS移植都会用了SysTick定时器的中断构建系统时钟,因此在SysTick上找原因。打开MDK,连接自制的STM32F401电路板和仿真器,进入Debug模式,运行程序,让uC/OS完成初始化配置,然后暂停程序;在外设(peripheral)菜单中找到SysTick定时器,界面如下图所示。

图2 System tick定时器状态监视器
其中重装寄存器中的值为0xC350,即50_000,仔细一想发现有问题——STM32F401的主频为84MHz,那要达到200Hz的系统时钟,无论如何都不可能把System Tick的初值配置为50_000啊!于是开始查找uC/OS移植代码中配置System Tick的部分,原来在探索者开发板移植代码中初始化延迟函数delay_init();中。看看原子的代码。

图3 delay_init();函数原来的代码
原子的代码简洁清晰,将System Tick的时钟配置为AHB时钟的1/8,在计算System Tick的初值。其中红圈中的一句是计算AHB时钟的八分之一,为后续计算定时器初始值做准备。但进一步仔细查看后发现变量SYSCLK中存放的AHB时钟数是以MHz作为单位的,对STM32F401xx而言,就是84。84无法整除8,而赋值语句左边的变量reload却是int型变量,从而导致了红圈中的一句计算误差。这样即使后一句将reload的单位切换回了Hz,也无法挽回前一句无法整除造成的计算误差。而这真是uC/OS系统时钟误差5%的真正原因!对这两句进行简单修改——现将SYSCLK折算为以Hz为单位,即可保证足够的计算精度。

图4 修改过的delay_init();函数代码
修改过后,uC/OS的系统时钟又恢复了原有的准确性。
究其原因并不是原子探索者开发板移植的uC/OS的问题,因为探索者采用的STM32F407ZG运行在168MHz,能够整除8,不存在这个问题。这里给大家展示这个过程,一是给大家在STM32F401上移植uC/OS做些探索,二是分享一下嵌入式调试和查找问题的点滴思路和心得。
在STM32F401上移植uC/OS的一个小问题 [原创]的更多相关文章
- FMX相当于在界面上自己又做了一个小操作系统
FMX的自画界面我也不看好,比如复制粘贴,太丑了,系统做得很好很精细的复制粘贴界面,就是无法调出,比如MIUI,复制粘贴还能有个放大镜,可以选择到屏幕边缘的文字,可以选择剪贴板内多个可粘贴的文字:还有 ...
- 关于uC/OS的简单学习(转)
1.微内核 与Linux的首要区别是,它是一个微内核,内核所实现的功能非常简单,主要包括: 一些通用函数,如TaskCreate(),OSMutexPend(),OSQPost()等. 中断处理函数, ...
- uc/os iii移植到STM32F4---IAR开发环境
也许是先入为主的原因,时钟用不惯Keil环境,大多数的教程都是拿keil写的,尝试将官方的uc/os iii 移植到IAR环境. 1.首先尝试从官网上下载的官方移植的代码,编译通过,但是执行会报堆栈溢 ...
- uC/OS - III 移植 IAR平台
关于移植uC/OS-III 网上已经有很多教程了此处只是做个记录 首先下载源码然后解压得到下面的文件: 然后在模版工程里新建各种文件夹: 最后全部都添加进工程: OK了,编译一下,惊呆了,竟然 0错误 ...
- uC/OS II原理分析及源码阅读(一)
uC/OS II(Micro Control Operation System Two)是一个可以基于ROM运行的.可裁减的.抢占式.实时多任务内核,具有高度可移植性,特别适合于微处理器和控制器,是和 ...
- 【小梅哥SOPC学习笔记】NIOS II处理器运行UC/OS II
SOPC开发流程之NIOS II 处理器运行 UC/OS II 这里以在芯航线FPGA学习套件的核心板上搭建 NIOS II 软核并运行 UCOS II操作系统为例介绍SOPC的开发流程. 第一步:建 ...
- 在秉火STM32F429挑战者开发板上移植Huawei LiteOS指南
昨天在B站上突然看到了一个短视频,是在正点原子的战舰V3开发板上移植华为的Huawei LiteOS操作系统,就是这个视频:看完鸿蒙OS发布会,试用华为的物联网操作系统Lite OS(B站),于是呢, ...
- 树莓派3b在rt-thread上移植LittlevGL
树莓派3b在rt-thread上移植LittlevGL 目录 树莓派3b在rt-thread上移植LittlevGL 1.本文概述 2.资源准备 3.上手体验 4.rt-thread与lvgl进行无缝 ...
- 在 Linux 的 KVM虚拟机 上安装 Mac OS 系统的研究总结
在 Linux 的 KVM虚拟机 上安装 Mac OS 系统的研究总结 一.资料来源: 网上一共找到两个方法,一个是视频上的教程,一个是网页资料. 二.视频资料方法内容:1.install qe ...
随机推荐
- hdu 1556 Color the ball 线段树 区间更新
水一下 #include <bits/stdc++.h> #define lson l, m, rt<<1 #define rson m+1, r, rt<<1|1 ...
- git分支案例
- AcWing 204. 表达整数的奇怪方式
#include<bits/stdc++.h> using namespace std; typedef long long LL; LL exgcd(LL a,LL b,LL & ...
- php+swoole多线程的操作
多个任务同时执行 比如,我们要对已知的用户数据进行判断,是否需要发送邮件和短信,如果需要发送则发送. 不使用多进程时,我们首先判断是否发送邮件,如果需要则发送:然后再判断是否需要发送短信,如果需要则发 ...
- [小技巧] google map使用
在网页中打开 google map 中,可以使用 shift + - 来缩小地图,shift + + 来放大地图.
- ARTS第二周
第二周. 1.Algorithm:每周至少做一个 leetcode 的算法题2.Review:阅读并点评至少一篇英文技术文章3.Tip:学习至少一个技术技巧4.Share:分享一篇有观点和思考的技术文 ...
- [转载]API网关
1. 使用API网关统一应用入口 API网关的核心设计理念是使用一个轻量级的消息网关作为所有客户端的应用入口,并且在 API 网关层面上实现通用的非功能性需求.如下图所示:所有的服务通过 API 网关 ...
- 二、从GitHub浏览Prism示例代码的方式入门WPF下的Prism之Modules的几种加载方式
这一篇梳理Prism中07示例Module的几种加载方式. 07示例分为了5个,有5种不同的Module加载方式. 我们开始学习加载Modules 观察07-Modules-Appconfig示例 分 ...
- C语言:进制表示
二进制由 0 和 1 两个数字组成,使用时必须以0b或0B(不区分大小写)开头 八进制由 0~7 八个数字组成,使用时必须以0开头(注意是数字 0,不是字母 o) 十六进制由数字 0~9.字母 A~F ...
- C语言经典试题--指针
分享一道C语言的经典的题目.题目要求如下: 利用字符指针实现字符串1"I Love China"与字符串2"So do I"的输出.然后利用字符指针将字符串2的 ...