IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> ARM Cortex-M3 深度研究 - 慎用 volatile 关键字修饰 double longlong 等64位长度类型的变量 -> 正文阅读

[嵌入式]ARM Cortex-M3 深度研究 - 慎用 volatile 关键字修饰 double longlong 等64位长度类型的变量

ARM Cortex-M3 深度研究 - 慎用 volatile 关键字修饰 double longlong 等64位长度类型的变量

导语

大家在做嵌入式项目的时候应该都使用过volatile关键字来修饰访问比较频繁的变量。volatile关键字会告诉编译器,变量是随时可能发生变化的,每次使用它的时候必须从内存重新取出它的值。但是volatile可以无所顾虑的被使用吗?

1 ARM Cortex-M3 基础知识

1.1 字长的定义

字的大小取决去具体系统的总线宽度,如果是32位的系统,则一个字是4个字节,如果是64位,则是8个字节;由于ARM Cortex-M3是32位系统,所以在这里定义一个字为4字节(32Bit)

1.2 数据的加载与存储指令集

指令集含义指令集含义Bit
LDRB字节数据加载指令STRB字节数据存储指令8
LDRH半字数据加载指令STRH半字数据存储指令16
LDR字数据加载指令STR字数据存储指令32
LDRD双字数据加载指令STRD双字数据存储指令64

注意:LDRD和STRD Load and Store Doubleword Instructions 是ARM扩展的64位指令

1.3 常用变量类型

变量类型名称英文Bit读写指令Volatile 修饰后
(unsigned) char字节Byte8LDRB STRBLDRB STRB
(unsigned) short半字Half Word16LDRH STRHLDRH STRH
(unsigned) intWord32LDR STRLDR STR
(unsigned) longWord32LDR STRLDR STR
floatWord32LDR STRLDR STR
(unsigned) long long双字Double Word64LDRD STRD2·LDR 2·STR
double双字Double Word64LDRD STRD2·LDR 2·STR

注意:Volatile 修饰的双字变量存取指令都由单个双字指令拆分成两个单字指令

2 实验测试 - volatile 修饰双字变量的影响

2.1 实验测试场景

场景一:使用 volatile 修饰 unsinged long long (double同理)

  • 选择一款基于ARM Cortex-M3 内核的MCU,这里用的是GD32F103VET6,IDE为Keil MDK 5.06 Update7 (build 960) 编译优化O0-O3均可
  • 定义两个volatile unsigned long long 类型的全局变量A和B,A、B赋初值为0
  • 定义main函数并编写一个while死循环,循环处理函数中始终将A的值赋给B
  • 初始化并使能一个外部按键触发中断,在中断处理函数中将A赋值为0xFFFFFFFFFFFFFFFF
  • 启动汇编调试,观察赋值的汇编语句
//定义全局变量
volatile unsigned long long A=0,B=0;
//定义主函数
void main(void)
{
 EXTI_Init();//外部中断
 while(1)
 {
  /*此处使用汇编查看*/
  B=A;
  /*汇编代码如下
  LDR r0,[pc,#16]   取得变量A的内存地址并装入r0
  LDR r1,[r0,#0x00] 将变量A的低32位装入 r1       此处使用断点
  LDR r0,[r0,#0x04] 将变量A的高32位装入 r0
  LDR r2,[pc,#12]   取得变量B的内存地址并装入r2
  STR r1,[r2,#0x00] 将r1值存储到变量B的低32位
  STR r0,[r2,#0x04] 将r0值存储到变量B的高32位    此处使用断点
  汇编代码如上*/
 }
}
//外部中断处理函数
EXTI_IRQHandler()
{
 /*此处添加断点*/
 EXTI_Interrupt_Flag_Clear(EXTI);//清中断标志位
 A=0xFFFFFFFFFFFFFFFF;
}
指令参数含义结果
LDRr0,[pc,#16]从PC指针偏移16所指向的地址处读取一个字(Word/32bit)的值 装入r0中取得变量A的内存地址并装入r0
LDRr1,[r0,#0x00]从r0值所指向的地址处读取一个字(Word/32bit)的值 装入r1中将变量A的低32位装入 r1
LDRr0,[r0,#0x04]从r0值偏移4所指向的地址处读取一个字(Word/32bit)的值 装入r0中将变量A的高32位装入 r0
LDRr2,[pc,#12]从PC指针偏移12所指向的地址处读取一个字(Word/32bit)的值 装入r2中取得变量B的内存地址并装入r2
STRr1,[r2,#0x00]将r1值以字(Word/32bit)的方式存储到r2值所指向地址的内存中将r1值存储到变量B的低32位
STRr0,[r2,#0x04]将r0值以字(Word/32bit)的方式存储到r2值偏移4所指向地址的内存中将r0值存储到变量B的高32位
  • 在 LDR r1,[r0,#0x00]处使用断点暂停,然后按住外部触发按键,再点击全速运行触发外部中断,操作顺序一定要对
  • 再次全速运行,跳出外部中断,在STR r0,[r2,#0x04]处使用断点暂停,然后观察r1,r0的值,可见异常
  • 再次单步运行即可完成B的赋值过程,观察B最终的值

完整调试过程如下GIF图所示:

在这里插入图片描述
赋值结果:B=0xFFFFFFFF00000000,其值的低32位来自A更改前的值,高32位来自于中断更改后A的值!

场景二:不使用 volatile 修饰

如果不使用 volatile 修饰,则赋值汇编指令为下表所示:

指令参数含义结果
LDRr0,[pc,#16]从PC指针偏移16所指向的地址处读取一个字(Word/32bit)的值 装入r0中读取变量A的内存地址值到r0寄存器中
LDRDr1,r0,[r0,#0]从r0值所指向的地址处读取两个字(DWord/64bit)的值 装入r1,r0中读取变量A的值到r1,r0寄存器中
LDRr2,[pc,#12]从PC指针偏移12所指向的地址处读取一个字(Word/32bit)的值 装入r2中读取变量B的内存地址值到r2寄存器中
STRDr1,r0,[r2,#0]将r1,r0中的值 以两个字(DWord/64bit)的方式存储到r2所指向地址的内存中将r1,r0寄存器中的值赋给变量B

由于LDRD和STRD均为单指令且一步完成了双字节赋值/读值操作,因此不会被中断程序打断!

2.2 实验测试结论

实验表明:在ARM Cortex-M3上“多线程"使用volatile 修饰double longlong 等64位长度类型的变量是非常危险的。
中断可以打断两次连续的LDR和STR指令,出现奇怪的数值,如果使用了这个异常的数值做进一步的控制处理,则有可能会出现一系列不可控的后果,大家务必注意!!!!

3 为何 volatile 修饰双字变量会改变使用的指令集宽度

暂时未知,大家可以去研究一下!!!

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2022-04-09 18:36:52  更:2022-04-09 18:38:14 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 4:35:38-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码