Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
UART
原子指令-原子操作_atomic
作为一个RT-Thread开发者,回顾这一段时间以来趟过的坑
发布于 2023-04-14 23:48:08 浏览:6115
订阅该版
[tocm] # 作为一个RT-Thread开发者,回顾这一段时间以来趟过的坑(1) ## 1: -1不等于-1的情况 ***Q:-1在什么情况下等于-1呢?-1当然在任何情况下等于-1呀,生活中当然这么回答没有任何问题,因为 -1在人看来是独一无二的。*** 场景: 前一段时间在给某个BSP适配串口驱动时,需要传递一个**int**型的变量,由于个人主观意识,在最初的环节将这个变量设置为了**char**型,在小伙伴的帮助下排查了好久最终定位到了数据类型不匹配的原因,直接上代码,这里以RT1060 BSP 举例。 - 正确代码 ```c static int imxrt_getc(struct rt_serial_device *serial) { int ch; struct imxrt_uart *uart; RT_ASSERT(serial != RT_NULL); uart = rt_container_of(serial, struct imxrt_uart, serial); ch = -1; if (LPUART_GetStatusFlags(uart->uart_base) & kLPUART_RxDataRegFullFlag) { ch = LPUART_ReadByte(uart->uart_base); } return ch; } ``` - 错误代码 ```c static int imxrt_getc(struct rt_serial_device *serial) { char ch; struct imxrt_uart *uart; RT_ASSERT(serial != RT_NULL); uart = rt_container_of(serial, struct imxrt_uart, serial); ch = -1; if (LPUART_GetStatusFlags(uart->uart_base) & kLPUART_RxDataRegFullFlag) { ch = LPUART_ReadByte(uart->uart_base); } return ch; } ``` **仅一个数据类型不一致,整个代码就跑飞了**,跑飞的地方如下: ```c void rt_hw_serial_isr(struct rt_serial_device *serial, int event) { switch (event & 0xff) { case RT_SERIAL_EVENT_RX_IND: { int ch = -1; rt_base_t level; struct rt_serial_rx_fifo* rx_fifo; /* interrupt mode receive */ rx_fifo = (struct rt_serial_rx_fifo*)serial->serial_rx; RT_ASSERT(rx_fifo != RT_NULL); while (1) { ch = serial->ops->getc(serial); if (ch == -1) break; //问题关键 /* disable interrupt */ level = rt_hw_interrupt_disable(); rx_fifo->buffer[rx_fifo->put_index] = ch; rx_fifo->put_index += 1; if (rx_fifo->put_index >= serial->config.bufsz) rx_fifo->put_index = 0; ... } } } } ``` 我们可以看到者关键的一句**if (ch == -1) break;**这里在无输入时ch会返回-1并退出循环。 通常上述C代码在翻译成汇编时,会翻译成 判断 **ch - 1**的结果的相应指令。这里ch是char型的-1,在内存中存储的值就是0xFF, 这里的-**-1是个立即数,在这里回被默认为32位int型,所以这里-1在内存中的值为0xFFFFFFFF**,通过运算单元0XFF-0xFFFFFFFF比较二者的大小,结果显而易见不为0,这样就出现了**人为认为的-1 = -1而机器人认为-1 ≠-1的现象**,所以串口驱动便会卡死在这里。 ## 2:-1 不等于 -1的情况2 场景: 在验证原子指令时出现了这么一个情况,编写测试用例时一致不通过,最终添加判断,发现 **-1 > -1**,这是受过九年义务教育的我能接受的?上代码: 出问题的地方: ```c base = 2; result = rt_atomic_add(&base, -3); uassert_true(base == -1); ``` 这里**uassert_true(base == -1);**一直不通过。 中间省略长时间的调试过程。。。我们看一下**rt_atomic_add**这个函数: ```c rt_atomic_t rt_hw_atomic_add(volatile rt_atomic_t *ptr, rt_atomic_t val) { rt_atomic_t result; asm volatile ("amoadd.w %0, %1, (%2)" : "=r"(result) : "r"(val), "r"(ptr) : "memory"); return result; } ``` 看着没毛病吧,其实就是没毛病,错的时其没用对地方。该指令的语义是,将一个32位的val与ptr地址指向的数据相加并将结果保存在ptr所指向的内存空间。 函数在翻译成汇编时,会添加一些上下文代码,在RV64的qemu上使用上述指令测试时,由于其是64位环境,这个指令是操作32位数,而且结果是负数,这就很有趣了,工具链会将过程优化,把计算出来的**32位有符号的-1优化为64为的有符号-1**,64位-1在内存中的值为 0XFFFFFFFFFFFFFFFF,而与之相比较的-1默认为int型,在内存中的值位0XFFFFFFFF,上文提到,判断俩个数是否相等通常是通过做差,显然**0XFFFFFFFFFFFFFFFF-0XFFFFFFFF 不等于 0**,这样**uassert_true(base == -1);**便判断为不相等,且是前者大于后者。 ## 3 未完待续
50
条评论
默认排序
按发布时间排序
登录
注册新账号
关于作者
rv666
调网络不抓包,调I2C等时序不上逻辑分析仪,就像电工不用万用表!多用整理的好的文字,比截图更省流量,还能在整理过程中思考。
文章
20
回答
52
被采纳
8
关注TA
发私信
相关文章
1
rt thread 2.0.2 usart 接收缓存问题
2
关于STM32串口通信的问题
3
STM32F1+RTT串口接收终端数据丢失问题
4
UART TX丢数据?
5
RTT打开串口的时候如何自定义波特率呢?
6
STM32F4的USART数据接收问题
7
串口1234使用问题
8
串口接收回调函数
9
LPC18xx UART问题讨论
10
x1000串口配置的失败问题
推荐文章
1
RT-Thread应用项目汇总
2
玩转RT-Thread系列教程
3
国产MCU移植系列教程汇总,欢迎查看!
4
机器人操作系统 (ROS2) 和 RT-Thread 通信
5
五分钟玩转RT-Thread新社区
6
【技术三千问】之《玩转ART-Pi》,看这篇就够了!干货汇总
7
关于STM32H7开发板上使用SDIO接口驱动SD卡挂载文件系统的问题总结
8
STM32的“GPU”——DMA2D实例详解
9
RT-Thread隐藏的宝藏之completion
10
【ART-PI】RT-Thread 开启RTC 与 Alarm组件
热门标签
RT-Thread Studio
串口
Env
LWIP
SPI
AT
Bootloader
Hardfault
CAN总线
ART-Pi
FinSH
USB
DMA
文件系统
RT-Thread
SCons
RT-Thread Nano
线程
MQTT
STM32
RTC
rt-smart
FAL
ESP8266
I2C_IIC
WIZnet_W5500
ota在线升级
UART
cubemx
PWM
flash
packages_软件包
freemodbus
BSP
潘多拉开发板_Pandora
定时器
ADC
GD32
flashDB
socket
中断
Debug
编译报错
msh
SFUD
keil_MDK
rt_mq_消息队列_msg_queue
ulog
C++_cpp
at_device
本月问答贡献
出出啊
1516
个答案
342
次被采纳
小小李sunny
1440
个答案
289
次被采纳
张世争
799
个答案
171
次被采纳
crystal266
547
个答案
161
次被采纳
whj467467222
1222
个答案
148
次被采纳
本月文章贡献
出出啊
1
篇文章
1
次点赞
小小李sunny
1
篇文章
1
次点赞
张世争
1
篇文章
4
次点赞
crystal266
2
篇文章
2
次点赞
whj467467222
2
篇文章
1
次点赞
回到
顶部
发布
问题
投诉
建议
回到
底部