打印
[STM32F1]

stm32下面怎么实现原子操作(不能被中断打断)

[复制链接]
12476|13
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
yan2005|  楼主 | 2014-8-15 17:11 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
stm32下面怎么实现原子操作(不能被中断打断的操作)。
下面有一段示意的代码,请大家帮忙分析分析。多谢了!

uint32_t data_flag = NO_DATA;
void main()
{
   while(1)
   {   if(data_flag == NO_DATA)   // 判断buf里面是否有数据
       {
           copy_data_into_buf();  // 拷贝数据
           data_flag = DATA_IS_IN_BUF; // 设置有数据的标志  <---- 此处有没有可能被中断?
       }
   }
}
void isr()  // 中断处理程序
{
   if(data_flag == DATA_IS_IN_BUF) // 判断buf里面是否有数据
   {
       transmit_data();            // 发送数据
       data_flag = NO_DATA;        // 设置没有数据的标志
   }
}
上面的代码里面data_flag = DATA_IS_IN_BUF这句话,有没有可能被中断程序打断?
如果能被中断打断的话,会不会出现这样的情况:
-step1. main开始设置data_flag,到了一半的时候发生中断
-step2. 中断处理程序看到标志,就传输数据
-step3. main从中断回来之后,继续设置标志。从而导致transmit_data()被多调用一次。

请教下大家,stm32下有没有保证data_flag = DATA_IS_IN_BUF是原子操作的简单办法?感谢!

沙发
jar1866| | 2014-8-15 19:12 | 只看该作者
uc_os 中的两个函数:
        PUBLIC  CPU_IntDis
        PUBLIC  CPU_IntEn

CPU_IntDis
        CPSID   I
        BX      LR


CPU_IntEn
        CPSIE   I
        BX      LR
把这两个函数加到一个汇编文件中,执行原子操作时关闭中断,处理完后打开即可

使用特权

评论回复
板凳
jar1866| | 2014-8-15 19:15 | 只看该作者
上面语句中最后还差一个END语句,你可以试下

使用特权

评论回复
地板
jar1866| | 2014-8-15 19:19 | 只看该作者
以下附件已经在iar下编译成功

intctl.zip

389 Bytes

使用特权

评论回复
5
mmuuss586| | 2014-8-15 19:23 | 只看该作者

只要你中断开了,还是有可能被中断;

使用特权

评论回复
6
yan2005|  楼主 | 2014-8-15 21:24 | 只看该作者
多谢2位,等我试下,后面把结果发回来。

使用特权

评论回复
7
airwill| | 2014-8-16 07:45 | 只看该作者
这么个存数据函数, 给中断打断的机会肯定是有的. 但是很多时候都会遇到这样的数据访问共享冲突.
处理器提供了不少办法解决这个问题, 比如
1. 禁止中断. 就是 2楼的办法.
2. 用半主机, 借助系统服务异常, 把共享数据的访问交给 SVC 服务来实现
3. Cortex-M3 特别提供的共享互斥访问机制, ldrex 指令, 效率很高.

此外, 还有一些编程技巧也可以避免共享访问的影响, 就是合理安排指令顺序和标志方式. 这么说有点难懂. 不过楼主的代码就是个例子.
主程序先写数据, 再置标志, 中断服务先判标志, 再读数据,
那么主程序在完成置标志前, 中断服务即使执行了, 因为没有标志, 空操作就退出了, 所以不会影响主程序写数据的操作.
当然这个做法只能应付单数据的缓冲, 如果 data_buf 里有多次中断才能发送完的数据, 那这办法就不行了. 当然还有更巧妙的技巧.

使用特权

评论回复
8
john_lee| | 2014-8-16 08:42 | 只看该作者
把 data_flag 的定义加上 volatile 修饰就可以了。
你就一个 data_flag 变量,本身还是 32 位的标量类型,CPU 可以一条指令读写的,谈不上“原子操作”。

使用特权

评论回复
9
原野之狼| | 2014-8-16 12:49 | 只看该作者
简单的问题搞这么复杂干嘛哟
就一个volatile搞定的事

使用特权

评论回复
10
tuzihog| | 2014-8-16 16:50 | 只看该作者
关注一下

使用特权

评论回复
11
kseeker| | 2014-8-16 17:07 | 只看该作者
如7楼所说,大多数情况下合理安排访问顺序就可以解决问题,而且这样在数据量很大的时候可以避免漏过中断。但是弄不好的话也很容易出错(比如说忘了加volatile),而且出了错还不好找。
stm32是可以开关总中断的,不过貌似不同编译器下具体写法有些区别。我不怎么喜欢写汇编,通常都是查一下对应的寄存器,只把相关的中断临时禁掉。

使用特权

评论回复
12
Lkingz| | 2015-2-26 14:03 | 只看该作者
john_lee 发表于 2014-8-16 08:42
把 data_flag 的定义加上 volatile 修饰就可以了。
你就一个 data_flag 变量,本身还是 32 位的标量类型,C ...

确实考证过stm32 对u32类型变量的读写是单指令周期就可完成的吗?
包括以下2种情况
1、stm32 对u32类型变量的赋值,如本例中data_flag = DATA_IS_IN_BUF;
2、u32类型变量值的判断,如 if(data_flag == NO_DATA),

若确实如此,那u8, u16类型呢?

使用特权

评论回复
13
kevinliuwei| | 2015-2-27 11:33 | 只看该作者
如果那么怕被中断打断,那就在data_flag = DATA_IS_IN_BUF;语句前关闭所有中断,在此语句后再开启

使用特权

评论回复
14
搞IT的| | 2015-2-28 18:18 | 只看该作者
支持~~

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

个人签名:Activist > thinker  与大家一起进步

47

主题

302

帖子

1

粉丝