登录
|
注册会员
开启辅助访问
设为首页
收藏本站
扫一扫关注官方微信
论坛
BBS
M币充值
M currency prepaid phone
M币获取
附件中心
搜索
search
全新论坛MCU智学网上线,欢迎访问新论坛!稀缺资源、技术干货、参考设计、原厂资料尽在MCU智学网
MCU资讯论坛
»
论坛
›
单片机开发论坛
›
C语言论坛
›
本人工作10年总结文档——《导致STM32芯片指令速度变化 ...
更新自动建库工具PCB Footprint Expert 2023.13 Pro / Library Expert 破解版
本人工作10年总结文档——《导致STM32芯片指令速度变化的问题分析过程》
[复制链接]
4274
2
ifree***
新手上路
发表于 2015-6-22 16:23:35
|
查看全部
|
阅读模式
本文包含原理图、PCB、源代码、封装库、中英文PDF等资源
您需要
登录
才可以下载或查看,没有帐号?
注册会员
x
全文请见附件
导致STM32芯片指令速度变化的问题分析过程.pdf
(174.01 KB, 下载次数: 11)
2015-6-22 16:22 上传
点击文件名下载附件
在word里写好了,在
论坛
里不好排版,请下载附件观看全文
导致 STM32芯片指令速度变化的问题分析过程
过年那几天将一份代码从TI 的LM3S8962 芯片移植到ST 的STM32F103VB 芯片上,
结果发现了STM32 芯片指令速度会发生变化,本文将讲述这个问题的定位过程,从中你可
以看到作者根据问题的现象结合已有的知识,2 次否定了出问题的地方,但随着逐步缩小定
位范围,认真分析现象,最终还是找回到了出问题的地方,并与网友讨论后,查找芯片手册
找到了问题的原因。本文的重点不在于介绍这个问题,而是在于介绍定位这个问题的思路以
及过程,很多问题通过仔细分析是可以找到原因的。
现象描述
下面这段延迟时间的函数在LM3S8962 芯片上可以产生正确的延迟时间, 但在
STM32F103VB 芯片上却表现出不确定性,有时候可以延迟正确的时间,而有时候则变为正
确时间的1.25 倍。比如,输入200,正常的延迟时间是2000ms,而出现异常时这段代码则
运行了2500ms。
void DEV_DelayMs(U32 uiMs)
{
unsigned int i;
unsigned int j;
j = 5998 * uiMs;
for(i = 0; ; i++)
{
if(i == j)
{
break;
}
}
}
背景知识介绍
我写了2 个具有任务切换功能的小型操作系统,其中一个我称之为wanlix,需要函数主
动调用任务切换函数才能发生任务切换,只有这一个功能,功能虽少,但也非常小巧,编译
后只有几百字节,适合程序空间只有几十K 的小系统使用。另一个我称之为mindows,是
实时抢占式的内核,高优先级的任务会自动抢占低优先级的任务,支持信号量、队列等功能。
更多信息,请访问我的新浪博客blog.sina.com.cn/ifreecoding
其中DEV_DelayMs 函数用来在任务中产生延迟,模拟任务的业务,其中mindows 拥有
tick 定时器,操作系统打印出的tick 时间会反应出DEV_DelayMs 函数的执行时间。
LM3S8962 芯片与STM32F103VB 芯片指令速度不一样,因此在移植这2 个操作系统时
对DEV_DelayMs 函数内的i、j 数值做了精确的调整,并使用了O0(哦零,不优化)优化
选项,使之能产生精确的延迟。DEV_DelayMs 函数在LM3S8962 芯片上工作正常,但在
STM32F103VB 芯片上却有时正常,有时异常。
原因分析
mindows 操作系统的打印带有tick 时间(每个tick 是10ms),这个问题最先是在mindows
上发现的。程序中有一段2000ms 的延迟,正常时,串口打印出这段延迟时间是2000ms,
如下所示:
Task Test1 ---> Task Test2! Tick is: 200
Task2 is running! Tick is: 200
但异常时打印却变成了2500ms,如下所示:
Task Test1 ---> Task Test2! Tick is: 250
Task2 is running! Tick is: 250
出现这个问题,有可能是tick 时间不准,也有可能是DEV_DelayMs 函数时间不准。在
运行时对比钟表的时间,发现tick 时间是准的,那么说明是DEV_DelayMs 函数时间不准。
既然是DEV_DelayMs 函数不准,那么很可能是DEV_DelayMs 函数在编译时生成的汇
编指令不一样,导致DEV_DelayMs 函数执行时间的长短不一样,而且,这个异常还伴随着
一个特点——异常与编译是相关的,也就是说编译后一旦出现异常,那么无论复位多少次,
异常一直出现,编译后一旦正常,那么无论复位多少次,均不会出现异常。这一点使我更加
坚信了是编译器编译出了不同的代码导致了问题。为了证明这一点,将正常和异常时的
DEV_DelayMs 函数进行反汇编,对比汇编代码,结果让我很失望,汇编代码完全一样(除
了函数跳转的绝对地址,但相对地址是一样的),这说明不是DEV_DelayMs 函数的问题,
反汇编的代码如下:
正常的代码:
8019004: f241 736e movw r3, #5998 ; 0x176e
8019008: fb00 f203 mul.w r2, r0, r3
801900c: f04f 0300 mov.w r3, #0
8019010: 4619 mov r1, r3
8019012: bf00 nop
8019014: 4291 cmp r1, r2
8019016: d100 bne.n 801901a <DEV_DelayMs+0x16>
8019018: e003 b.n 8019022 <DEV_DelayMs+0x1e>
801901a: f101 0301 add.w r3, r1, #1
801901e: 4619 mov r1, r3
8019020: e7f8 b.n 8019014 <DEV_DelayMs+0x10>
8019022: bf00 nop
8019024: 4770 bx lr
异常的代码:
8019000: f241 736e movw r3, #5998 ; 0x176e
8019004: fb00 f203 mul.w r2, r0, r3
8019008: f04f 0300 mov.w r3, #0
801900c: 4619 mov r1, r3
801900e: bf00 nop
8019010: 4291 cmp r1, r2
8019012: d100 bne.n 8019016 <DEV_DelayMs+0x16>
8019014: e003 b.n 801901e <DEV_DelayMs+0x1e>
8019016: f101 0301 add.w r3, r1, #1
801901a: 4619 mov r1, r3
801901c: e7f8 b.n 8019010 <DEV_DelayMs+0x10>
801901e: bf00 nop
8019020: 4770 bx lr
mindows 在运行DEV_DelayMs 函数的同时还会产生tick 中断,会不会是tick 中断对
DEV_DelayMs 函数产生了影响?为了验证这个问题,只需要在wanlix 上运行DEV_DelayMs
函数就可以了,因为wanlix 是主动切换任务的系统,如果没有调用任务切换函数,那么
DEV_DelayMs 函数就会一直运行,与没有使用操作系统的情况是一样的。在wanlix 上运行
DEV_DelayMs 函数,对比钟表的时间,这个问题与mindows 上表现的情况一模一样,依然
存在,说明也不是tick 中断的问题。
上述2 个原因都被排除了,我能想到的最后一个原因就是——硬件时钟不准确,导致芯
片运行的频率错误,最终导致了DEV_DelayMs 函数执行时间不确定。但tick 时钟和串口打
印时钟表现出都是正确的情况,使得这个问题看起来又不像是芯片时钟的问题。我使用的是
芯片自带的库函数来设置tick 和串口,也许库函数里做了一些自适应功能使tick 和串口时钟
在错误的芯片时钟下也能计算出它们正确的工作时钟?死马当活马医吧,先看看时钟是否有
问题。查看正常和异常情况下与tick 时钟有关的寄存器,结果完全正常,这说明芯片时钟也
是没有问题的。而且,异常情况的出现是与代码是否重新编译相关的,与芯片是否重新启动
是无关的,又是概率性出现的,这也说明了不是硬件时钟的问题。这下我真的黔驴技穷了。
经过反复试验,终于又发现一个重要的线索:增量编译其它函数时也会触发这个问题概
率性出现。增量编译的意思是只编译其中一部分文件,然后一起连接成目标程序。比如说有
a.c 和b.c 这两个文件,先将这两个文件编译成a.o 和b.o,然后再将a.o 和b.o 链接成目标文
件。当只有a.c 文件做了改动时,那么我们可以只编译a.c,使用新生成的a.o 与原来的b.o
一起链接成新的目标文件,这就是增量编译。
DEV_DelayMs 函数位于unoptimize.c 文件中, 当我改动其它c 文件而没有改动
unoptimize.c 文件做增量编译时,这个问题也会概率性出现。这说明什么?这说明这个问题
与DEV_DelayMs 函数无关,是其它函数导致的。但这个问题又确实是在DEV_DelayMs 函
数上表现出来的,而DEV_DelayMs 函数又与其它函数没有任何耦合,这似乎是不可能的事
情。问题定位到这里已经走不下去了。
既然是修改其它文件里的函数对DEV_DelayMs 函数有影响,那么只能试着改其它文件
中的函数来找出其中规律了。在试验中又发现,在不相关的文件中随便加入几条无用的指令
都有可能随机触发这个问题,这似乎又是不可能的事情。
问题说到这里,我已经把当时定位时所获得的全部信息都介绍全了,现在,你是否能猜
到这个问题的原因?下面就是见证奇迹的时刻!
在不相干的文件中修改不相干的指令,那么对DEV_DelayMs 函数的影响是——链接后
的绝对地址不同。难道是DEV_DelayMs 函数所在的地址会对运行结果产生影响?带着最后
一丝希望,我构造出了将DEV_DelayMs 函数链接到不同地址的多种情况,最后终于发现了
导致这个问题的一个规律。
当DEV_DelayMs 函数被编译到8 字节对齐(0b1000 结尾)的地址,运行时间就是错误
的,当被编译到4 字节对齐(0b100 结尾)的地址,运行时间就是正确的!
原文定位到这里就结束了,至于为什么会产生这个问题,我也不清楚,原以为是芯片的
bug。后来在论坛上有网友提出是FLASH 读取速度不均衡造成的,我觉得有可能,但如果
是这样的话那只能说这个芯片做的不是很好,因为这个现象是与地址相关的,而且表现出来
的速度差异太大了,达到了1:0.8,并且在TI 的
Cortex
内核上没有发现这个问题。因此我
查了一下ST 的FLASH 手册,发现有如下这段话:“预取缓冲器包含两个数据块,每个数据
块有8 个字节;预取指令(数据)块直接映像到闪存中,因为数据块的大小与闪存的宽度相同,
所以读取预取指令块可以在一个读周期完成。设置预取缓冲器可以使CPU 更快地执行,CPU
读取一个字的同时下一个字已经在预取缓冲器中等候,即当代码跳转的边界为8 字节的倍
数时,闪存的加速比例为2。”从中可以看到其中提到了“跳转”,提到了“8 字节对齐”,
从上面的2 段反汇编代码可以看到,区别就在于跳转的地址不同,并且我验证的结论也是有
关8 字节对齐的,因此这段话与我上面所得出的结论是一致的。至于上面2 段反汇编后的代
码为何会表现出指令执行速度上的差异,我结合这段话没有找到原因。
解决方法
经过前面的分析,我们需要将DEV_DelayMs 函数链接到4 字节对齐的地址空间,需要
修改链接文件,在我的工程中这个链接文件名称叫STM3210E-EVAL.sct,你可以到我的博
客mindows5.3 节及以后的章节中找到这部分代码,修改如下:
LR_IROM2 0x08019004 0x00000FFC { ; load region size_region
ER_IROM2 0x08019004 0x00000FFC { ; load address = execution address
unoptimize.o
}
}
上面这段代码的含义是,将unoptimize.o 文件链接到0x08019004 这个地址空间,这就
是一个4 字节对齐的地址空间, 而unoptimize.o 是由unoptimize.c 文件编译成的, 而
unoptimize.c 文件中只有DEV_DelayMs 这一个函数,这样就将DEV_DelayMs 函数链接到了
4 字节对齐的0x08019004 地址空间了。
经过这么处理DEV_DelayMs 函数就可以正常工作了。
另外,在ST 的FLASH 手册中也指出了可以通过寄存器关闭“预取缓冲器”功能,不
过还有一些额外的限制,由于我没有完全理解这些描述,这里就不介绍了,有兴趣的同学可
以参考PM0042 编程手册“STM32F10xxx 闪存编程”,里面有描述。
经验总结
可以说这个问题不是问题,芯片就是这么设计的,当初没有仔细看FLASH 手册,误以
为这是一个bug。
1.出现问题时应该仔细阅读相关文档,避免“问题”就是芯片特性。
2.看一遍芯片的buglist,看看其中描述的bug 是否会遇到。
3.对于问题表现出的现象一定要运用已知的知识仔细分析,尽管过程不会很顺利,有时
候甚至还会引向另一个错误的方向,但最终仍会缩小范围,解决问题。
C语言
相关帖子
从零开始学单片机C语言,很全的资料
C语言编程宝典
单片机C语言程序设计实训100例-基于8051 Proteus仿真
C语言经典程序100题(完整版)
【众拳】STM8入门视频教程资料分享
ATmega16运行速度
上课了讲解C语言之一维数组
求助
国产单片机推荐:无锡矽杰微电子XC8P8600
51单片机STC8H8K64U通过RA8889/RA8876如何控制彩屏(I2C源码下载)
举报
回复
2 个评论
ca***
新手上路
发表于 2015-6-27 21:43:48
|
显示全部楼层
强人,牛人!!
举报
回复
lyd***
新手上路
发表于 2016-6-6 15:58:15
|
显示全部楼层
非常感谢你的分享
举报
回复
支持
反对
返回列表
*
滑块验证:
高级模式
B
Color
Image
Link
Quote
Code
Smilies
您需要登录后才可以回帖
登录
|
注册会员
本版积分规则
发表回复
回帖后跳转到最后一页
回复
转播
评分
分享
打开支付宝扫一扫,最高立得1212元红包
搜索
本版
帖子
用户
热搜:
传感器
51串口程序
电子管放大器
夾式電表
夾式電流
Mentor论坛
打印机
版块推荐
百宝箱
My 布拉格
无边框Z9
Z9Max
Z9mini
nubia动态
问题 & 建议
资源分享
爱拍
同城会
牛仔生活
查看论坛所有版块>>
每日签到
论坛任务
摄影技巧
跳蚤市场
互助问答
论坛导读
申请内测
红包中心
每日摇一摇
活动中心
网站地图
官方旗舰店
图文热点
俄罗斯的6H23+6П43推挽电路机器欣赏
AP3215 8-150V 外围简单 宽输入 电压降压BU
产品描述 AP3215是 一系列外围电路简洁的宽输入电压降压BUCK 恒压恒流驱动器 ,适用
VK1056Q QFN246是一个点阵式存储映射的LCD
产品品牌:永嘉微电/VINKA 产品型号:VK1056Q 封装形式:QFN24L 概述 VK1056Q是
超高清图解示波器使用方法
3线串行接口/工作电压工作电压 2.4-5.2V/VK
产品品牌:永嘉微电/VINKA 产品型号:VK1056B/C 封装形式:SOP/SSOP24 概述 VK1
更多
精华推荐
俄罗斯的6H23+6П43推挽电路机器欣赏
AP3215 8-150V 外围简单 宽输入 电压降压BU
VK1056Q QFN246是一个点阵式存储映射的LCD
一个名为伯努瓦(Gislain)的人,用了3年时
AP2121太阳能草坪灯驱动芯片
超高清图解示波器使用方法
3线串行接口/工作电压工作电压 2.4-5.2V/VK
单片机驱动彩屏最简方案:单片机_RA8889最
更多
社区学堂
俄罗斯的6H23+6П43推挽电路机器欣赏
AP3215 8-150V 外围简单 宽输入 电压降
俄罗斯的6H23+6П43推挽电路机器欣赏
AP3215 8-150V 外围简单 宽输入 电压降压BU
产品描述 AP3215是 一系列外围电路简洁的宽输入电压降压BUCK 恒压恒流驱动器 ,适用
VK1056Q QFN246是一个点阵式存储映射的LCD
产品品牌:永嘉微电/VINKA 产品型号:VK1056Q 封装形式:QFN24L 概述 VK1056Q是
更多
客服中心
QQ:187196467
服务时间:周一至周日 8:30-20:30
在线客服
客服微博
产品咨询
售后中心
关注我们
关于我们
关于我们
友情链接
联系我们
帮助中心
网友中心
购买须知
支付方式
服务支持
资源下载
售后服务
定制流程
关注我们
官方微博
官方空间
官方微信
QQ:187196467
周一到周日 8:30-22:00 (全年无休)
7 x 24小时在线客服
手机版
Powered by
MCUZX!
X3.4 © 2008-2015
MCU资讯论坛
版权所有
京ICP备18035221号-2
客服QQ: 187196467
技术支持:
MCU资讯论坛
|
网站地图
快速回复
返回顶部
返回列表