Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
serial_V1
serial_V2
串口
串口框架V1和V2版本对比
1.00
发布于 2021-07-24 16:13:09 浏览:5701
订阅该版
[tocm] # 串口框架V1和V2版本对比 ## V1版本串口框架(以及驱动)总结 这部分的总结,其实也是在之前写的串口V1版本的文章中有所提及的,这里大致再总结一下,如果初次查看的话,可能会造成一些困扰,那么就去请先去查看之前的三篇文章:[串口(一)](https://club.rt-thread.org/ask/article/2894.html)、 [串口(二)](https://club.rt-thread.org/ask/article/2898.html) 、[串口(三)](https://club.rt-thread.org/ask/article/2904.html)相信看完之后会更加清晰一些。另外如果有任何描述不当或者分析不对的地方,尽情评论区发言或者直接私信我。 * 发送模式不够完善: * 串口驱动中,发送中断模式未发挥出中断应有的特性,造成使用中断时,仍然需要浪费大量CPU时间,影响系统整体性能。 * DMA发送使用不当容易丢包: * 当写数据为轮询或者中断时,调用`rt_device_write`正确返回后即代表数据发送完成。而使用DMA时,调用`rt_device_write`返回后仅仅代表数据准备完毕,并不能代表数据发送完成,如果用户在正确返回后再次调用`rt_device_write`,将有可能出现上次数据未发送完成,数据又被修改的发送数据错误的问题。 * 不同模式时,影响应用层执行逻辑: * 结合第二点再引申下来这个问题:当使用中断和轮询时,发送模式为阻塞模式,使用DMA时,发送模式为非阻塞模式,且未对数据块进行保护。另外不仅仅是发送端的考虑,接收端也有可能会出现阻塞和非阻塞的模式选择问题。因此框架层应该更多关心阻塞非阻塞的操作模式,使得应用层执行流程能够统一。 ## V2版本的串口框架(以及驱动)主要改动点: * 取消了硬件工作模式的判断,硬件工作模式由驱动层支持,使得框架层与 硬件工作模式 无关; * 统一操作接口,应用层不再关心 硬件工作模式, * 统一使用 阻塞/非阻塞 操作模式,不会因为模式的变更导致应用层逻辑代码行为不一致。 * 增加发送缓冲区功能,保证应用层数据的完整性,从而解决丢包率; * 每一路的串口都有独立的发送缓冲区和接收缓冲区的宏定义,取代之前的所有串口默认使用`RT_SERIAL_RB_BUFSZ`这一个宏定义。 * 完善工作模式,分工明确,轮询、中断、DMA都能按照正确的工作模式执行。 **ps:** 这里我用了两个词汇用来区分模式:硬件工作模式和应用操作模式,这两个词汇可能不是官方用词,这里旨在用来区别描述上的混淆和困扰 ``` 硬件工作模式: 指串口的三种模式,代表的是使用轮询、中断、DMA进行操作串口时的工作模式。 应用操作模式: 指串口的实际操作模式,代表的是应用层使用串口时选择使用阻塞或非阻塞传输的操作模式。 ``` ## V1和V2版本对比 V2版本的在使用上的改动点,上文已经描述过了,下面主要从代码层面以及用户使用上对比两个版本的差异。 ### 结构体的成员变量的变更 #### `serial_configure` 修改V1版本的`bufsz`为`rx_bufsz`,指代的含义未变更,均指代接收缓冲区字节长度;增加发送缓冲区字节长度的成员变量`tx_bufsz`。具体如下代码段所示: ```c /* V1版本的成员变量 */ struct serial_configure { rt_uint32_t baud_rate; rt_uint32_t data_bits :4; rt_uint32_t stop_bits :2; rt_uint32_t parity :2; rt_uint32_t bit_order :1; rt_uint32_t invert :1; rt_uint32_t bufsz :16; rt_uint32_t reserved :6; }; /* V2版本的成员变量 */ struct serial_configure { rt_uint32_t baud_rate; rt_uint32_t data_bits :4; rt_uint32_t stop_bits :2; rt_uint32_t parity :2; rt_uint32_t bit_order :1; rt_uint32_t invert :1; rt_uint32_t rx_bufsz :16; /* 修改之前版本的bufsz为接收缓冲区字节长度 */ rt_uint32_t tx_bufsz :16; /* 增加成员变量发送缓冲区字节长度 */ rt_uint32_t reserved :6; }; ``` 与其对应的是宏定义`RT_SERIAL_CONFIG_DEFAULT`的变更: ```c /* V1版本的串口的宏定义RT_SERIAL_CONFIG_DEFAULT */ #define RT_SERIAL_CONFIG_DEFAULT \ { \ BAUD_RATE_115200, /* 115200 bits/s */ \ DATA_BITS_8, /* 8 databits */ \ STOP_BITS_1, /* 1 stopbit */ \ PARITY_NONE, /* No parity */ \ BIT_ORDER_LSB, /* LSB first sent */ \ NRZ_NORMAL, /* Normal mode */ \ RT_SERIAL_RB_BUFSZ, /* Buffer size */ \ 0 \ } /* V2版本的串口的宏定义RT_SERIAL_CONFIG_DEFAULT */ #define RT_SERIAL_CONFIG_DEFAULT \ { \ BAUD_RATE_115200, /* 115200 bits/s */ \ DATA_BITS_8, /* 8 databits */ \ STOP_BITS_1, /* 1 stopbit */ \ PARITY_NONE, /* No parity */ \ BIT_ORDER_LSB, /* LSB first sent */ \ NRZ_NORMAL, /* Normal mode */ \ RT_SERIAL_RX_MINBUFSZ, /* rxBuf size */ \ RT_SERIAL_TX_MINBUFSZ, /* txBuf size */ \ 0 \ } ``` 注意:这里需要注意的是,V2版本完全删除了`RT_SERIAL_RB_BUFSZ`宏定义。因此如果用户在使用V2版本时候遇到之前的代码或者软件包使用到了`RT_SERIAL_RB_BUFSZ`,那么需要将其更改为对应的串口设备的接收缓冲区的值。这个下文会再进一步阐述。 #### `rt_uart_ops` 更改V1版本的`dma_transmit`操作接口为`transmit`: V1版本的`dma_transmit` 用于DMA传输,而V2版本的`transmit`用于阻塞和非阻塞传输(或者认为是中断和DMA模式的传输) ```c /* V1版本 rt_uart_ops */ struct rt_uart_ops { ... ... rt_size_t (*dma_transmit)(struct rt_serial_device *serial, rt_uint8_t *buf, rt_size_t size, int direction); }; /* V2版本 rt_uart_ops */ struct rt_uart_ops { ... ... rt_size_t (*transmit)(struct rt_serial_device *serial, rt_uint8_t *buf, rt_size_t size, rt_uint32_t tx_flag); }; ``` #### 发送接收缓冲区结构体 ```c /* V1版本自主实现ringbuffer */ struct rt_serial_rx_fifo { rt_uint8_t *buffer; rt_uint16_t put_index, get_index; rt_bool_t is_full; }; struct rt_serial_tx_fifo { struct rt_completion completion; }; struct rt_serial_rx_dma { rt_bool_t activated; }; struct rt_serial_tx_dma { rt_bool_t activated; struct rt_data_queue data_queue; }; /* V2版本使用RTT自带的ringbuffer结构体 */ struct rt_serial_rx_fifo { struct rt_ringbuffer rb; struct rt_completion rx_cpt; rt_uint16_t rx_cpt_index; rt_uint8_t buffer[]; }; struct rt_serial_tx_fifo { struct rt_ringbuffer rb; rt_size_t put_size; rt_bool_t activated; struct rt_completion tx_cpt; rt_uint8_t buffer[]; }; ``` ### 宏定义的差别 #### 缓冲区宏定义的差别 V1版本统一使用的`RT_SERIAL_RB_BUFSZ`,每个串口设备统一使用该参数设置接收缓冲区长度。 V2版本删除了该宏定义,取而代之的是让每一个串口都有独立的发送缓冲区和接收缓冲区的宏定义。 举例说明: ```c /* V1版本 */ #define RT_SERIAL_RB_BUFSZ 64 /* V2版本缓冲区宏定义 */ #define BSP_UART1_RX_BUFSIZE 256 #define BSP_UART1_TX_BUFSIZE 0 /* 不需要发送缓冲区,用于轮询模式 */ #define BSP_UART2_RX_BUFSIZE 256 #define BSP_UART2_TX_BUFSIZE 256 ``` 另外需要注意的是,当用户需要使用缓冲区,且缓冲区设置值小于64字节时,将会按照64字节设置。 ```c #define RT_SERIAL_RX_MINBUFSZ 64 #define RT_SERIAL_TX_MINBUFSZ 64 ``` #### 模式选择上的差别 V2版本 **基本完全兼容**V1版本的串口使用方式,即统一使用rt_device的设备驱动框架。 唯一的区别在于V1版本的串口打开标志是: ```C /* 接收模式参数 */ #define RT_DEVICE_FLAG_INT_RX 0x100 /* 中断接收模式 */ #define RT_DEVICE_FLAG_DMA_RX 0x200 /* DMA 接收模式 */ /* 发送模式参数 */ #define RT_DEVICE_FLAG_INT_TX 0x400 /* 中断发送模式 */ #define RT_DEVICE_FLAG_DMA_TX 0x800 /* DMA 发送模式 */ ``` V2版本串口打开标志是: ```c /* 接收模式参数 */ #define RT_DEVICE_FLAG_RX_BLOCKING 0x1000 /* 接收阻塞模式*/ #define RT_DEVICE_FLAG_RX_NON_BLOCKING 0x2000 /* 接收非阻塞模式*/ /* 发送模式参数 */ #define RT_DEVICE_FLAG_TX_BLOCKING 0x4000 /* 发送阻塞模式*/ #define RT_DEVICE_FLAG_TX_NON_BLOCKING 0x8000 /* 发送非阻塞模式*/ ``` 注意:当用户使用V2版本的串口框架时,设置的参数是V1版本的,那么无论设置的何种模式,都会统一按照(发送阻塞模式和接收非阻塞模式)进行配置。 该模式也是串口使用最为广泛的模式组合方式。 ## 其他 V2版本的模式有四种操作模式的配置,然而对应到串口驱动层也有三种硬件工作模式的配置,因此使用起来就是需要将操作模式和工作模式进行组合使用的。 例如 发送阻塞接收非阻塞 ,这个测试有很多种硬件配置,配置情况例如:DMA发送阻塞DMA接收非阻塞、INT发送阻塞DMA接收非阻塞、POLL发送阻塞DMA接收非阻塞等等。 因此通过排列组合后的测试场景有4*9=36种,有意义的组合方式为20种。如下表: | 接收非阻塞 | 发送阻塞 | 组合 | 有意义的组合方式 | | ---------- | -------- | ----------------- | ---------------- | | POLL | POLL | RX_POLL + TX_POLL | | | | INT | RX_POLL + TX_INT | | | | DMA | RX_POLL + TX_DMA | | | INT | POLL | RX_INT + TX_POLL | ✔ | | | INT | RX_INT + TX_INT | ✔ | | | DMA | RX_INT + TX_DMA | ✔ | | DMA | POLL | RX_DMA + TX_POLL | ✔ | | | INT | RX_DMA + TX_INT | ✔ | | | DMA | RX_DMA + TX_DMA | ✔ | | 接收非阻塞 | 发送非阻塞 | 组合 | 有意义的组合方式 | | ---------- | ---------- | ----------------- | ---------------- | | POLL | POLL | RX_POLL + TX_POLL | | | | INT | RX_POLL + TX_INT | | | | DMA | RX_POLL + TX_DMA | | | INT | POLL | RX_INT + TX_POLL | | | | INT | RX_INT + TX_INT | ✔ | | | DMA | RX_INT + TX_DMA | ✔ | | DMA | POLL | RX_DMA + TX_POLL | | | | INT | RX_DMA + TX_INT | ✔ | | | DMA | RX_DMA + TX_DMA | ✔ | | 接收阻塞 | 发送阻塞 | 组合 | 有意义的组合方式 | | -------- | -------- | ----------------- | ---------------- | | POLL | POLL | RX_POLL + TX_POLL | | | | INT | RX_POLL + TX_INT | | | | DMA | RX_POLL + TX_DMA | | | INT | POLL | RX_INT + TX_POLL | ✔ | | | INT | RX_INT + TX_INT | ✔ | | | DMA | RX_INT + TX_DMA | ✔ | | DMA | POLL | RX_DMA + TX_POLL | ✔ | | | INT | RX_DMA + TX_INT | ✔ | | | DMA | RX_DMA + TX_DMA | ✔ | | 接收阻塞 | 发送非阻塞 | 组合 | 有意义的组合方式 | | -------- | ---------- | ----------------- | ---------------- | | POLL | POLL | RX_POLL + TX_POLL | | | | INT | RX_POLL + TX_INT | | | | DMA | RX_POLL + TX_DMA | | | INT | POLL | RX_INT + TX_POLL | | | | INT | RX_INT + TX_INT | ✔ | | | DMA | RX_INT + TX_DMA | ✔ | | DMA | POLL | RX_DMA + TX_POLL | | | | INT | RX_DMA + TX_INT | ✔ | | | DMA | RX_DMA + TX_DMA | ✔ | 需要解释的是,为什么会存在无意义的组合模式,举个例子,非阻塞模式下,肯定是不会出现POLL(轮询)方式的,因为POLL方式已经表明是阻塞方式了。 这部分的内容详见[serial_v2的测试用例的说明](https://github.com/RT-Thread/rt-thread/pull/4809)。 ## 总结 本章节主要介绍了串口V1和V2对比差异,并引出串口V2的一些设计实现思想。目前串口V2版本已经在ART-PI的`serial_lab`分支进行了适配,链接如下:[ab_serial](https://github.com/RT-Thread-Studio/sdk-bsp-stm32h750-realthread-artpi/tree/lab_serial),另外在RT-Thread的`master`分支上也已经在`STM32L475-pandora`平台上进行了适配,链接如下[stm32l475-atk-pandora](https://github.com/RT-Thread/rt-thread/tree/master/bsp/stm32/stm32l475-atk-pandora)。关于串口V2的介绍,还有文档中心的链接:[[UART 设备 v2 版本](https://www.rt-thread.org/document/site/#/rt-thread-version/rt-thread-standard/programming-manual/device/uart/uart_v2/uart?id=uart-设备-v2-版本)]。另外后边也会做关于适配移植的文档资料,如有需要,可参照这些链接资料进行适配。 更多文章: [RTT串口V1版本的使用分析及问题排查指南(一)](https://club.rt-thread.org/ask/article/2894.html) [RTT串口V1版本的使用分析及问题排查指南(二)](https://club.rt-thread.org/ask/article/2898.html) [RTT串口V1版本的使用分析及问题排查指南(三)](https://club.rt-thread.org/ask/article/2904.html) [串口框架V1和V2版本对比](https://club.rt-thread.org/ask/article/2915.html) [串口 V2 适配指南](https://club.rt-thread.org/ask/article/2920.html)
1
条评论
默认排序
按发布时间排序
登录
注册新账号
关于作者
123
这家伙很懒,什么也没写!
文章
6
回答
309
被采纳
68
关注TA
发私信
相关文章
1
串口DMA发送数据时,数据被覆盖
2
关于串口DMA模式下rt_device_close问题
3
利用stm32f427实现usb转串口,电脑端什么也没有识别到
4
finsh 控制台 适配 RS 485请大神指点????
5
uart_sample.c 中,读串口设备时偏移量pos要设置为-1而不是0?
6
【结贴】at_device软件包中对串口接收数据缺少判断导致数据接收异常
7
串口无法接受数据,但可以发送
8
串口如何有效的清除掉接收缓冲,而不必一个一个的去读取
9
串口接收使用方式问题
10
雅特力FINSH问题
推荐文章
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总线
FinSH
ART-Pi
USB
DMA
文件系统
RT-Thread
SCons
RT-Thread Nano
线程
MQTT
STM32
RTC
FAL
rt-smart
ESP8266
I2C_IIC
UART
WIZnet_W5500
ota在线升级
freemodbus
PWM
flash
cubemx
packages_软件包
BSP
潘多拉开发板_Pandora
定时器
ADC
GD32
flashDB
socket
中断
编译报错
Debug
rt_mq_消息队列_msg_queue
SFUD
msh
keil_MDK
ulog
C++_cpp
MicroPython
本月问答贡献
出出啊
1517
个答案
342
次被采纳
小小李sunny
1444
个答案
289
次被采纳
张世争
809
个答案
175
次被采纳
crystal266
547
个答案
161
次被采纳
whj467467222
1222
个答案
148
次被采纳
本月文章贡献
catcatbing
3
篇文章
5
次点赞
qq1078249029
2
篇文章
2
次点赞
xnosky
2
篇文章
1
次点赞
Woshizhapuren
1
篇文章
5
次点赞
YZRD
1
篇文章
2
次点赞
回到
顶部
发布
问题
投诉
建议
回到
底部