7 Star 48 Fork 17

THEWON/serialX

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
贡献代码
同步代码
取消
提示: 由于 Git 不支持空文件夾,创建文件夹后会生成空的 .keep 文件
Loading...
README
Apache-2.0

serialX

前言

“serialX” 我起的名字,起个名字想破头。 在前一篇文章里,大致提出了我的串口驱动框架理论。里面做了一些对串口驱动特性的幻想。也在 NUC970 芯片下通过了中断模式的实践验证。但是,因为 NUC970 的 uart 自带 fifo 。用它测试效果好,并不能真正说明驱动框架通过验证了。

然后,紧接着笔者在 STM32F429 完成了中断和 DMA 两种模式。今天,我把一些测试结果和移植说明发出来,征求全网公测。

测试配置:DMA 二级缓存 32 个字节,串口收发缓存各 512 字节。

注:本串口驱动工作特性请参阅前一篇文章rt-thread 驱动篇 之 串口驱动框架剖析性能提升

STM32 中断模式测试

以下是三组连续发收测试:

  1. 定时间隔20ms,发送250字节数据,持续发送2600w,接收发送数据量相等

    250-20ms-2600w.png

  2. 定时间隔50ms,发送250字节数据,持续发送600w,接收发送数据量相等

    250-50ms-600w.png

  3. 定时间隔80ms,发送1000字节数据,持续发送600w,接收发送数据量相等

    1000-80ms-610w.png

注:刚刚跟我们小伙伴求证了一下,串口调试助手的定时间隔是固定周期。如果是这样的,以上测试是有意义的,如果不是,那就没达到串口带宽上限。

STM32 DMA模式测试

  1. 读写测试,串口调试助手定时 10ms ,发送40字节数据,持续发送129w

    dma-40-10ms-129w.png

  2. 串口调试助手定时 50ms ,发送500字节数据,持续发送527w

    dma-500-50ms-527w.png

  3. 串口调试助手定时 40ms ,发送500字节数据,持续发送261w

    dma-500-40ms-261w.png

  4. 串口调试助手定时 40ms ,发送1000字节数据,持续发送262w

    dma-1000-40ms-262w.png

    串口调试助手上发送和接收数量不相等,接着我在代码中添加了个断点,单独发送了一个字节 ‘Z’ 。

    dma-1000-40ms-262w-rw.png

    代码中接收和发送数量相等,都等于串口调试助手的接收量。这个缺少的部分是串口调试助手发送失败数量,还是串口驱动接收丢失了?

接下来,修改成中断接收发送模式,其它不做修改进行相同的测试,也是有数量差。进一步检查串口驱动里,接收缓存有溢出现象。应用层没来得及把数据取走,就删掉了最旧的数据。

接口详解及移植说明

rtdef.h 添加几个宏定义

添加一个强制 inline 宏定义

#define rt_forceinline static __attribute__((always_inline))

添加阻塞打开相关标志()

#define RT_DEVICE_OFLAG_BLOCKING        0x000           /**< blocking io mode */
#define RT_DEVICE_OFLAG_NONBLOCKING     0x004           /**< non-blocking io mode */

...

#define RT_DEVICE_CTRL_BLOCKING         0x05            /**< blocking io */

serialX.h

添加串口驱动缓存和 DMA 二级缓存大小定义(放弃使用 RT_SERIAL_RB_BUFSZ):

#ifndef RT_SERIAL_FIFO_BUFSZ
#define RT_SERIAL_FIFO_BUFSZ            512
#endif

#ifndef RT_SERIAL_DMA_BUFSZ
#define RT_SERIAL_DMA_BUFSZ             32
#endif

串口接收和发送使用的缓存大小是一样的,如果想改变串口缓存大小,请修改 RT_SERIAL_FIFO_BUFSZ 的值。

如果想改变 DMA 二级缓存大小,请修改 RT_SERIAL_DMA_BUFSZ 的值。

定义一个收发通用 fifo:

struct rt_serial_fifo
{
    rt_uint32_t buf_sz;
    /* software fifo */
    rt_uint8_t *buffer;

    rt_uint16_t put_index, get_index;

    rt_bool_t is_full;
};

重新定义 rt_serial_device 定义:

struct rt_serial_device
{
    struct rt_device          parent;

    const struct rt_uart_ops *ops;
    struct serial_configure   config;

    void *serial_rx;			// 串口接收缓存
    void *serial_tx;			// 串口发送缓存

#ifdef RT_SERIAL_USING_DMA							// 串口收发缓存和 DMA 使用的二级缓存分开
    rt_size_t dma_idx_rx;
    rt_uint8_t serial_dma_rx[RT_SERIAL_DMA_BUFSZ];	// DMA 接收缓存
    rt_uint8_t serial_dma_tx[RT_SERIAL_DMA_BUFSZ];	// DMA 发送缓存
#endif

    cb_serial_tx _cb_tx;		// 写过程回调函数指针
    cb_serial_rx _cb_rx;		// 读过程回调函数指针

    struct rt_completion completion_tx;				// 发送完成
    struct rt_completion completion_rx;				// 接收到新数据
    笔者注:这里虽然用的是完成量,但是这样有个漏洞,见下面详细分析说明
};
typedef struct rt_serial_device rt_serial_t;

串口驱动通用框架和硬件底层接口定义

struct rt_uart_ops
{
	// 用于配置外设寄存器,引脚功能复用,启用外设等等
    rt_err_t (*configure)(struct rt_serial_device *serial, struct serial_configure *cfg);
    // 用于使能禁用中断,初始配置 DMA
    rt_err_t (*control)(struct rt_serial_device *serial, int cmd, void *arg);
	// 串口外设写数据寄存器*为空*,把数据放入写数据寄存器。*不为空*,死等
    int (*putc)(struct rt_serial_device *serial, char c);
    // 串口外设读数据寄存器*不为空*,读出读数据寄存器的值。*为空*,返回 -1
    int (*getc)(struct rt_serial_device *serial);

	// 启动发送,多数是开启串口外设发送寄存器空中断
    void (*start_tx)(struct rt_serial_device *serial);
	// 结束发送,多数是关闭串口外设发送寄存器空中断
    void (*stop_tx)(struct rt_serial_device *serial);

#ifdef RT_SERIAL_USING_DMA
	// 判断 DMA 是否在发送过程中,就像上一篇里笔者多次提示的,必须有效检测 DMA 是否在发送数据中
    rt_bool_t (*is_dma_txing)(struct rt_serial_device *serial);
    // 启动 DMA 发送
    void (*start_dma_tx)(struct rt_serial_device *serial, rt_uint8_t *buf, rt_size_t size);
    // 停止 DMA 发送
    void (*stop_dma_tx)(struct rt_serial_device *serial);
#endif
	// 使能串口外设中断
    void (*enable_interrupt)(struct rt_serial_device *serial);
    // 禁用串口外设中断
    void (*disable_interrupt)(struct rt_serial_device *serial);
};

移植 serialX 到新芯片上,必须按照 rt_uart_ops 的定义实现上述几个接口。函数功能不能随意更改。

rt_hw_serial_isr

这个中断只接收 RT_SERIAL_EVENT_RX_IND RT_SERIAL_EVENT_RX_IND RT_SERIAL_EVENT_RX_DMADONE RT_SERIAL_EVENT_TX_DMADONE 四种中断状态。

  • RT_SERIAL_EVENT_RX_IND 接收寄存器不空中断
  • RT_SERIAL_EVENT_TX_DONE 发送寄存器空中断,为了兼容自带 fifo 的芯片,event 参数的高三字节代表 fifo 容量
  • RT_SERIAL_EVENT_RX_DMADONE 串口接收 DMA 中断。 这个可以兼容接收半传输和全传输等多种中断。event 参数的高三字节代表 DMA fifo 接收数据数量(1-RT_SERIAL_DMA_BUFSZ)。
  • RT_SERIAL_EVENT_TX_DMADONE 串口发送 DMA 中断。这个应该保证 DMA 发送完本次 DMA 缓存中的所有数据,也就是对于 stm32 芯片是 DMA 计数达到 0。

使用注意

  • RT_SERIAL_FIFO_BUFSZ RT_SERIAL_DMA_BUFSZ 两个的定义和实际是否合适,小数据量通信可以定义小点儿,数据量大的情况适当调整这两个值。
  • rt_uart_ops 接口定义,功能实现必须匹配。
  • 阻塞模式,收发是一致的。默认是阻塞模式。想使用非阻塞模式请 open 的时候添加 RT_DEVICE_OFLAG_NONBLOCKING flag。
  • 使用 RT_DEVICE_FLAG_INT RT_DEVICE_FLAG_DMA_RX RT_DEVICE_FLAG_INT_TX RT_DEVICE_FLAG_DMA_TX 四个 open flag 指定收发模式,是用中断还是 DMA。
  • 特别提醒,非阻塞模式下,read 可能返回 0。write 返回值可能不是目标写入 size。read/write 还可能返回 RT_EXXX 错误值。
  • 特别提醒,阻塞模式下,read 返回值可能不是期望数据量 size。笔者也曾经提供过可靠处理流数据的方案,详见 rt-thread 使用宝典(2021-1210更新)

使用完成量进入阻塞漏洞分析

串口驱动里有几个阻塞点,进入阻塞都使用的 rt_complition ,如下代码:

serial->ops->enable_interrupt(serial);
ret = rt_completion_wait(&(serial->completion_rx), RT_WAITING_FOREVER);// 或者 serial->completion_tx

首先开中断,调用 rt_completion_wait 等待完成量进入阻塞。这样是有个漏洞的,当开中断后有个串口中断,中断处理函数里调用 rt_completion_done 是没有任何反应的,rt_completion_done 直接返回退出。

进而回到原线程才执行 rt_completion_wait。之后,如果有第二次接收(或发送)中断发生时才会结束上一次的阻塞。但是,第二次什么时候出现也就是个未知数了。即便前一次可能已经收全了全部想要的数据,但是会不定期阻塞下去。

解决方法有两个:一、不用永久阻塞,换成 10ms 或者几 ms 等待;二、用二值信号量替代。

但是!!!我没有用上述方法中的任何一个进行改进,原因是:

第一种方法无疑要引入一个循环,rt_completion_wait 超时返回的时候循环继续阻塞。还有就是等待时间没有理论支持。最重要的是用循环方式补漏洞的方式不美观。

没使用二值信号量的原因是,rt-thread 的信号量实现没有真正的“二值”,如果中断已经多次 release 了,然后应用层才来一次 take,之后还可能成功 take 多次(虽然应该是要阻塞的,但是实际不阻塞,反而会循环 take 多次)。

因此,暂时继续使用完成量。年后信号量的真正的二值性实现后,再换成信号量方式。

新增适配芯片

N32G45

  • 已在 N32G45XVL-STB 开发板上测试,芯片 N32G457VEL7;
  • 已添加适配 USART 1/2/3/4 ,可以自行添加其他串口外设;
  • 支持中断和 DMA (收发可任意选择)。

2022/06/06

AB32VG1

  • 已在 AB32VG1 开发板上测试,芯片 N32G457VEL7;
  • 已添加适配 USART 0/1/2 ,可以自行添加其他串口外设;
  • 支持中断收发(不支持轮询发送,因为把发送完成判断去掉了)。

2022/06/08

RA6M4

  • 已在 RA6M4 开发板上测试,芯片 R7FA6M4AF3CFB;
  • 已添加适配 USART 1/2/3/4 ,可以自行添加其他串口外设;
  • 支持中断接收。
  • 本想改成中断发送,但是失败了,连续发送多个字节数据会不响应发送完成中断(望有熟悉这个芯片的大佬指点迷津)。

2022/06/06

GD32F4

  • 已在 GD32450i-EVAL 开发板上测试,芯片 GD32F450IK;
  • 已添加适配 USART 0-7 ,可以自行添加其他串口外设;
  • 支持中断收发 (收发可任意选择)。
  • 支持轮询收发。
  • 未支持 DMA 收发。

2022/06/08

AT32

2023/04/19

  • 只是编译通过,并未进行测试。

其他芯片

下一步计划中。。。敬请期待!

2023/02/15 修改记录

  1. 修改 struct serial_configure 结构体,去掉 rt_uint32_t bufsz 成员元素,并将其移动到 struct rt_serial_device 内部。
  2. struct rt_uart_ops 添加 init 接口。

initconfigure 进行功能划分,

  • configure 只进行配置串口外设的“波特率、数据位长度、停止位长度、校验位以及其它可能存在的流控”等配置。
  • init 除了包含 configure 的功能外,还可能包含“引脚复用设置、串口外设时钟配置、串口外设使能以及开启串口外设中断总开关”。

**强烈建议:**使能串口外设之前,先给串口外设配置一组默认的“波特率、数据位长度”等。这组默认值,或者是 rt_hw_serial_register 初始化的,或者是上次使用串口设备留下来的。

解决的问题

initconfigure 功能分离之后,可以使 configure 的操作在 open 之后或者之前,

uart_dev = rt_device_find(SERIAL_DEV_NAME);
rt_device_control(uart_dev, RT_DEVICE_CTRL_CONFIG, &uart_conf);
rt_device_open(uart_dev, RT_DEVICE_OFLAG_RDWR);

uart_dev = rt_device_find(SERIAL_DEV_NAME);
rt_device_open(uart_dev, RT_DEVICE_OFLAG_RDWR);
rt_device_control(uart_dev, RT_DEVICE_CTRL_CONFIG, &uart_conf);

这两种操作结果都是一样的。

因为,在开启 posix 之后,使用 termios 配置串口波特率只能在 open 之后。

需要注意的地方

很多芯片厂商提供的开发包里,串口外设使能和配置波特率是同一个函数,并没有单独的配置波特率的函数!

比如 stm32 只有一个 HAL_UART_Init 初始化函数,它的功能是配置串口外设寄存器然后使能串口,这个函数内部调用了静态函数 UART_SetConfig 配置波特率等寄存器。并没有外部接口版本的 UART_SetConfig

作为对比,gd32 提供的接口就丰富多了,不仅有 usart_baudrate_set 还有 usart_word_length_set usart_stop_bit_set usart_parity_config ,每一个都是可以单独设置的。

因此,结论是,initconfigure 功能分离之后,stm32 并没有改进。除非我们修改 HAL 的源码,把 UART_SetConfig 修改成全局函数并提供外部引用声明(这可能要触动很多人的神经了), configure 里只调用 UART_SetConfig

2023/08/19 修改记录

添加阻塞超时特性

rt_tick_t timeout = 50;
rt_device_control(serial_dev, RT_DEVICE_CTRL_TIMEOUT, &timeout);

设置读写超时时间,在阻塞模式下等待读/写超过一定时间后从读/写等待返回

结束语

现笔者将打码开放出来 gitee 仓库 serialX,求全论坛公测。期待各位大佬提出各种测试方案,它最不怕的就是考验。

有问题可以在仓库里提 issue ,或者到 rt-thread 官方论坛上进行讨论。

Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

简介

基于 rt-thread 平台的串口框架 展开 收起
C 等 2 种语言
Apache-2.0
取消

发行版

暂无发行版

贡献者

全部

近期动态

不能加载更多了
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
C
1
https://gitee.com/thewon/serialX.git
git@gitee.com:thewon/serialX.git
thewon
serialX
serialX
master

搜索帮助