打印
[信息]

【实战经验】多任务系统中的不可重函数使用注意事项

[复制链接]
993|5
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
本帖最后由 香水城 于 2017-8-16 14:31 编辑

多任务系统中的不可重函数使用注意事项
前言
本**主要介绍多任务系统中的的不可重入函数的用法和如何避免出错。

1. 可重入函数与不可重入函数的区别
在多任务环境中,可重入函数可以由多于一个的任务并发使用,而不用担心数据错误。这个函数可以在执行的任何时刻中断
它。
不可重入函数由于使用了一些系统资源,比如全局变量等,不能被很多任务所共享,除非能确保函数的互斥性。
1)可重入函数:
不返回指向静态数据的指针。
使用本地数据。
如果必须访问全局变量,记住利用互斥信号量来保护全局变量。
绝不调用任何不可重入函数。
3)不可重入函数:
函数中使用了静态变量。
函数返回静态变量。
函数中调用了不可重入函数。
函数体内使用了静态的数据结构;
函数体内调用了malloc()或者free()函数;
函数体内调用了其他标准I/O 函数。
总的来说,如果一个函数在重入条件下使用了未受保护的共享的资源,那么它是不可重入的。

2. 不可重入函数的一次错误应用示例,造成I2C Master 端收到的数据无**确解析。
这个产品使用的MCU 为STM32F411,是作为Sensor hub使用的,做为I2C 的Master端,总线上挂了好几个传感
器,如加速度、陀螺仪、光感应等。并且同时采用定时方式和中断方式通过I2C总线读取sensor上数据的。

客户产品功能是在实时操作系统上实现的,属于多任务系统。在中断处理函数中会调用I2C_Read(…)函数,而
I2C_Read(…)函数中又调用了 HAL_I2C_Master_Receive_IT(…)函数。
函数代码在示例程序中的位置如下:
…\stm32cubef4\STM32Cube_FW_F4_V1.6.0\Drivers\STM32F4xx_HAL_Driver\Src 的stm32f4xx_hal_i2c.c
stm32f4xx_hal_i2c.c 文件中有一段I2C slave 接收程序,具体代码如下:



上面程序中通过下面指令对硬件端口进行加锁:
__HAL_LOCK(hi2c);
__HAL_UNLOCK(hi2c);
初步看来多任务系统中好像是安全的,但实际应用中并非如此(客户的不可重入函数调用了这个I2C 函数),下面用图例来说明:

上图中”t”为时间轴,”T1”时间发生 sensor 1 中断并调用I2C_Read(…),在I2C_Read(…)函数中会调用
HAL_I2C_Master_Receive_IT(…)函数,在调用HAL_I2C_Master_Receive_IT(…)函数之前已经进行了传参,即:
Addr=0x1A0,Size=3,Buf 指向buffer1 的地址。
当程序运行到”T2”时又来了一个sensor 2 中断,调用I2C_Read(…)函数,在调用HAL_I2C_Master_Receive_IT(…)函数
之前已经传参完成。此时的I2C 地址,Size 等的值如下:
Addr=0x1B0,Size=5,Buf 指向buffer1 的地址。
由于HAL_I2C_Master_Receive_IT(…)程序有加锁,和判断busy 状况,当程序判断到总线busy 时或是有加锁时跳出
HAL_I2C_Master_Receive_IT(…)函数;但此时的I2C 地址,buffer 地址, Size 都已经是Sensor2 对应的值了。然后程序
进入 ”T3“。
Sensor2 中断返回时会把sensor2 的Size 值5 赋给hi2c->XferSize,因此后面的I2C 通讯中的值如下:
Addr=0x1A0(sensor1 value)
Buf 指向buffer1(sensor1 value)Size=5(sensor2 value)
因此程序处理中会出错。

3.上面的问题解决方法:
上面多任务系统的I2C 处理程序中出现了不可重入函数的多次调用问题,主要是I2C_Read(…)为不可重入函数,但对它进行
了多次调用,使变量更改。
下面的办法可以解决多次调用问题,既对调用I2C_Read(…)的动作加锁,使第二个I2C 中断发生后不进行传参动作,如下图所示:

也可以使用信号量方式处理。如下图:


4. 程序占用资源后要防止死锁发生
上面I2C 程序处理中要注意不要发生死锁,假设在I2C_Read(…) 函数里有一条指令是对I2C 端口的状态进行判断,如busy
状态,如果程序一直在等待中,就很容易发生死锁,下面图示是程序发生死锁的情况:

在上面程序中需要增加超时跳出机制来防止死锁。

5.总结
在多任务系统中,在使用函数时要了解函数的可重入性,对待有信号量或是加互斥锁的函数要防止死锁的发生。通讯程序比
如I2C, UART 等最好增加超时跳出机制。

对应PDF:多任务系统中的不可重函数使用注意事项
更多实战经验请看:【ST MCU实战经验汇总贴】


沙发
airwill| | 2015-12-25 19:37 | 只看该作者
造成I2C Master 端收发的数据错误, 这是软件设计问题, 不合适算作不可重入函数问题
应该将 I2C 作为单独的设备做成设备驱动接口与任务通信.

使用特权

评论回复
评论
john_lee 2015-12-26 00:55 回复TA
正解。 
板凳
yiyigirl2014| | 2015-12-25 22:24 | 只看该作者
在多任务系统中,在使用函数时要了解函数的可重入性,对待有信号量或是加互斥锁的函数要防止死锁的发生。通讯程序比如I2C, UART 等最好增加超时跳出机制。原来这样啊

使用特权

评论回复
地板
karaxiaoyu| | 2015-12-25 23:57 | 只看该作者
学习了

使用特权

评论回复
5
wangjianxing| | 2015-12-26 09:43 | 只看该作者
感谢楼主分享资源

使用特权

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

本版积分规则

认证:意法半导体(中国)投资有限公司
简介:STM32技术专家

596

主题

17066

帖子

283

粉丝