关于串口:串口框架V1和V2版本对比

1次阅读

共计 5735 个字符,预计需要花费 15 分钟才能阅读完成。

本文由 RT-Thread 官方论坛用户 123 原创公布:https://club.rt-thread.org/as…
串口框架 V1 和 V2 版本比照
V1 版本串口框架(以及驱动)总结

这部分的总结,其实也是在之前写的串口 V1 版本的文章中有所提及的,这里大抵再总结一下,如果首次查看的话,可能会造成一些困扰,那么就去请先去查看之前的三篇文章:串口 (一)、串口(二)、串口(三) 置信看完之后会更加清晰一些。另外如果有任何形容不当或者剖析不对的中央,纵情评论区发言或者间接私信我。

发送模式不够欠缺:串口驱动中,发送中断模式未施展出中断应有的个性,造成应用中断时,依然须要节约大量 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。具体如下代码段所示:

/ 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 的变更:

/ 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 模式的传输)

/ 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);

};

发送接收缓冲区构造体

/ 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 版本删除了该宏定义,取而代之的是让每一个串口都有独立的发送缓冲区和接收缓冲区的宏定义。

举例说明:

/ 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 字节设置。

define RT_SERIAL_RX_MINBUFSZ 64

define RT_SERIAL_TX_MINBUFSZ 64

模式抉择上的差异

V2 版本 根本齐全兼容 V1 版本的串口应用形式,即对立应用 rt_device 的设施驱动框架。

惟一的区别在于 V1 版本的串口关上标记是:

/ 接管模式参数 /

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 版本串口关上标记是:

/ 接管模式参数 /

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 的测试用例的阐明。
总结

本章节次要介绍了串口 V1 和 V2 比照差别,并引出串口 V2 的一些设计实现思维。目前串口 V2 版本曾经在 ART-PI 的 serial_lab 分支进行了适配,链接如下:ab_serial,另外在 RT-Thread 的 master 分支上也曾经在 STM32L475-pandora 平台上进行了适配,链接如下 stm32l475-atk-pandora。对于串口 V2 的介绍,还有文档核心的链接:[UART 设施 v2 版本]。另外后边也会做对于适配移植的文档资料,如有须要,可参照这些链接材料进行适配。

更多文章:
RTT 串口 V1 版本的应用剖析及问题排查指南 (一)
RTT 串口 V1 版本的应用剖析及问题排查指南(二)
RTT 串口 V1 版本的应用剖析及问题排查指南(三)
串口框架 V1 和 V2 版本比照
串口 V2 适配指南

正文完
 0