RT-Thread 4.0.3 适配 UART_V2 版本

本文为针对发布版4.0.3 进行 UART_V2 驱动的移植适配操作笔记。

由于使用了 libmodbus 软件包,需要 posix_termios 支持,但新版 serial_v2.c 还未支持,下面移植时添加对应适配代码。

[串口 V2 适配指南](RT-Thread-串口 V2 适配指南RT-Thread问答社区 - RT-Thread)主要是基于主干开发版的移植,下面以实际项目(基于STM32F407)使用发布版4.0.3 的BSP开发为例进行移植说明.

详情参考

[UART 设备 v2 版本]

[串口 V2 适配指南](RT-Thread-串口 V2 适配指南RT-Thread问答社区 - RT-Thread)

V2驱动文件添加

从主干版本获取新版驱动文件:

drv_usart_v2.c drv_usart_v2.h 放入 bsp的 libraries/HAL_Drivers/ 目录下

serial_v2.c 放入 components/drivers/serial/serial_v2.c

serial_v2.h 放入 components/drivers/include/drivers/serial_v2.h

修改驱动层支持 UART_V2

1. libraries/HAL_Drivers/SConscript

if GetDepend(['RT_USING_SERIAL']):
if GetDepend(['RT_USING_SERIAL_V2']):
src += ['drv_usart_v2.c']
else:
src += ['drv_usart.c']

2. libraries/HAL_Drivers/drv_common.c

#ifdef RT_USING_SERIAL
#ifdef RT_USING_SERIAL_V2
#include "drv_usart_v2.h"
#else
#include "drv_usart.h"
#endif
#endif

3. libraries/HAL_Drivers/drv_usart_v2.c

stm32_uart_get_config 增加 UART5~8的支持

#ifdef BSP_USING_UART5
uart_obj[UART5_INDEX].serial.config = config;
uart_obj[UART5_INDEX].uart_dma_flag = 0; uart_obj[UART5_INDEX].serial.config.rx_bufsz = BSP_UART5_RX_BUFSIZE;
uart_obj[UART5_INDEX].serial.config.tx_bufsz = BSP_UART5_TX_BUFSIZE; #ifdef BSP_UART5_RX_USING_DMA
uart_obj[UART5_INDEX].uart_dma_flag |= RT_DEVICE_FLAG_DMA_RX;
static struct dma_config uart5_dma_rx = UART5_DMA_RX_CONFIG;
uart_config[UART5_INDEX].dma_rx = &uart5_dma_rx;
#endif #ifdef BSP_UART5_TX_USING_DMA
uart_obj[UART5_INDEX].uart_dma_flag |= RT_DEVICE_FLAG_DMA_TX;
static struct dma_config uart5_dma_tx = UART5_DMA_TX_CONFIG;
uart_config[UART5_INDEX].dma_tx = &uart5_dma_tx;
#endif
#endif #ifdef BSP_USING_UART6
uart_obj[UART6_INDEX].serial.config = config;
uart_obj[UART6_INDEX].uart_dma_flag = 0; uart_obj[UART6_INDEX].serial.config.rx_bufsz = BSP_UART6_RX_BUFSIZE;
uart_obj[UART6_INDEX].serial.config.tx_bufsz = BSP_UART6_TX_BUFSIZE; #ifdef BSP_UART6_RX_USING_DMA
uart_obj[UART6_INDEX].uart_dma_flag |= RT_DEVICE_FLAG_DMA_RX;
static struct dma_config uart6_dma_rx = UART6_DMA_RX_CONFIG;
uart_config[UART6_INDEX].dma_rx = &uart6_dma_rx;
#endif #ifdef BSP_UART6_TX_USING_DMA
uart_obj[UART6_INDEX].uart_dma_flag |= RT_DEVICE_FLAG_DMA_TX;
static struct dma_config uart6_dma_tx = UART6_DMA_TX_CONFIG;
uart_config[UART6_INDEX].dma_tx = &uart6_dma_tx;
#endif
#endif #ifdef BSP_USING_UART7
uart_obj[UART7_INDEX].serial.config = config;
uart_obj[UART7_INDEX].uart_dma_flag = 0; uart_obj[UART7_INDEX].serial.config.rx_bufsz = BSP_UART7_RX_BUFSIZE;
uart_obj[UART7_INDEX].serial.config.tx_bufsz = BSP_UART7_TX_BUFSIZE; #ifdef BSP_UART7_RX_USING_DMA
uart_obj[UART7_INDEX].uart_dma_flag |= RT_DEVICE_FLAG_DMA_RX;
static struct dma_config uart7_dma_rx = UART7_DMA_RX_CONFIG;
uart_config[UART7_INDEX].dma_rx = &uart7_dma_rx;
#endif #ifdef BSP_UART7_TX_USING_DMA
uart_obj[UART7_INDEX].uart_dma_flag |= RT_DEVICE_FLAG_DMA_TX;
static struct dma_config uart7_dma_tx = UART7_DMA_TX_CONFIG;
uart_config[UART7_INDEX].dma_tx = &uart7_dma_tx;
#endif
#endif #ifdef BSP_USING_UART8
uart_obj[UART8_INDEX].serial.config = config;
uart_obj[UART8_INDEX].uart_dma_flag = 0; uart_obj[UART8_INDEX].serial.config.rx_bufsz = BSP_UART8_RX_BUFSIZE;
uart_obj[UART8_INDEX].serial.config.tx_bufsz = BSP_UART8_TX_BUFSIZE; #ifdef BSP_UART8_RX_USING_DMA
uart_obj[UART8_INDEX].uart_dma_flag |= RT_DEVICE_FLAG_DMA_RX;
static struct dma_config uart8_dma_rx = UART8_DMA_RX_CONFIG;
uart_config[UART8_INDEX].dma_rx = &uart8_dma_rx;
#endif #ifdef BSP_UART8_TX_USING_DMA
uart_obj[UART8_INDEX].uart_dma_flag |= RT_DEVICE_FLAG_DMA_TX;
static struct dma_config uart8_dma_tx = UART8_DMA_TX_CONFIG;
uart_config[UART8_INDEX].dma_tx = &uart8_dma_tx;
#endif
#endif

4. components/drivers/Kconfig

menuconfig RT_USING_SERIAL
bool "Using serial device drivers"
select RT_USING_DEVICE_IPC
select RT_USING_DEVICE
default y if RT_USING_SERIAL
choice
prompt "Choice Serial version"
default RT_USING_SERIAL_V1
config RT_USING_SERIAL_V1
bool "RT_USING_SERIAL_V1"
config RT_USING_SERIAL_V2
bool "RT_USING_SERIAL_V2"
endchoice
config RT_SERIAL_USING_DMA
bool "Enable serial DMA mode"
default y config RT_SERIAL_RB_BUFSZ
int "Set RX buffer size"
depends on !RT_USING_SERIAL_V2
default 64
endif

5. components/drivers/serial/SConscript

from building import *

cwd = GetCurrentDir()
CPPPATH = [cwd + '/../include']
group = []
if GetDepend(['RT_USING_SERIAL']):
if GetDepend(['RT_USING_SERIAL_V2']):
src = Glob('serial_v2.c')
group = DefineGroup('DeviceDrivers', src, depend = ['RT_USING_SERIAL_V2'], CPPPATH = CPPPATH)
else:
src = Glob('serial.c')
group = DefineGroup('DeviceDrivers', src, depend = ['RT_USING_SERIAL'], CPPPATH = CPPPATH) Return('group')

6. components/drivers/include/rtdevice.h

#ifdef RT_USING_SERIAL
#ifdef RT_USING_SERIAL_V2
#include "drivers/serial_v2.h"
#else
#include "drivers/serial.h"
#endif
#endif /* RT_USING_SERIAL */

修改应用层 Kconfig

board/Kconfig

menuconfig BSP_USING_UART
bool "Enable UART"
default y
select RT_USING_SERIAL
select RT_SERIAL_USING_DMA
if BSP_USING_UART
menuconfig BSP_USING_UART1
bool "Enable UART1"
default y
if BSP_USING_UART1
config BSP_UART1_RX_USING_DMA
bool "Enable UART1 RX DMA"
depends on BSP_USING_UART1 && RT_SERIAL_USING_DMA
default n config BSP_UART1_TX_USING_DMA
bool "Enable UART1 TX DMA"
depends on BSP_USING_UART1 && RT_SERIAL_USING_DMA
default n config BSP_UART1_RX_BUFSIZE
int "Set UART1 RX buffer size"
range 64 65535
depends on RT_USING_SERIAL_V2
default 256 config BSP_UART1_TX_BUFSIZE
int "Set UART1 TX buffer size"
range 0 65535
depends on RT_USING_SERIAL_V2
default 0
endif menuconfig BSP_USING_UART2
bool "Enable UART2"
default y
if BSP_USING_UART2
config BSP_UART2_RX_USING_DMA
bool "Enable UART2 RX DMA"
depends on BSP_USING_UART2 && RT_SERIAL_USING_DMA
default n config BSP_UART2_TX_USING_DMA
bool "Enable UART2 TX DMA"
depends on BSP_USING_UART2 && RT_SERIAL_USING_DMA
default n config BSP_UART2_RX_BUFSIZE
int "Set UART2 RX buffer size"
range 64 65535
depends on RT_USING_SERIAL_V2
default 256 config BSP_UART2_TX_BUFSIZE
int "Set UART2 TX buffer size"
range 0 65535
depends on RT_USING_SERIAL_V2
default 0
endif

其余使用串口参考着添加

修改相关文件适配 posix_termios

修改 components/drivers/serial/serial_v2.c 以支持 posix_termios

#ifdef RT_USING_POSIX_TERMIOS
#include <posix_termios.h>
#endif

#ifdef RT_USING_POSIX_TERMIOS
struct speed_baudrate_item
{
speed_t speed;
int baudrate;
}; const static struct speed_baudrate_item _tbl[] =
{
{B2400, BAUD_RATE_2400},
{B4800, BAUD_RATE_4800},
{B9600, BAUD_RATE_9600},
{B19200, BAUD_RATE_19200},
{B38400, BAUD_RATE_38400},
{B57600, BAUD_RATE_57600},
{B115200, BAUD_RATE_115200},
{B230400, BAUD_RATE_230400},
{B460800, BAUD_RATE_460800},
{B921600, BAUD_RATE_921600},
{B2000000, BAUD_RATE_2000000},
{B3000000, BAUD_RATE_3000000},
}; static speed_t _get_speed(int baudrate)
{
int index; for (index = 0; index < sizeof(_tbl)/sizeof(_tbl[0]); index ++)
{
if (_tbl[index].baudrate == baudrate)
return _tbl[index].speed;
} return B0;
} static int _get_baudrate(speed_t speed)
{
int index; for (index = 0; index < sizeof(_tbl)/sizeof(_tbl[0]); index ++)
{
if (_tbl[index].speed == speed)
return _tbl[index].baudrate;
} return 0;
} static void _tc_flush(struct rt_serial_device *serial, int queue)
{
rt_base_t level;
int ch = -1;
struct rt_serial_rx_fifo *rx_fifo = RT_NULL; /* 接收环形缓冲 */ RT_ASSERT(serial != RT_NULL); rx_fifo = (struct rt_serial_rx_fifo *) serial->serial_rx; switch(queue)
{
case TCIFLUSH:
case TCIOFLUSH: RT_ASSERT(rx_fifo != RT_NULL); if (serial->config.rx_bufsz > 0)
{
RT_ASSERT(RT_NULL != rx_fifo);
level = rt_hw_interrupt_disable();
rx_fifo->rb.read_index = rx_fifo->rb.write_index;
rt_hw_interrupt_enable(level);
}
else
{
while (1)
{
ch = serial->ops->getc(serial);
if (ch == -1) break;
}
} break; case TCOFLUSH:
break;
} }
#endif /* RT_USING_POSIX_TERMIOS */

static rt_err_t rt_serial_control(struct rt_device *dev,
int cmd,
void *args)
{
rt_err_t ret = RT_EOK;
struct rt_serial_device *serial; RT_ASSERT(dev != RT_NULL);
serial = (struct rt_serial_device *)dev; switch (cmd)
{
case RT_DEVICE_CTRL_SUSPEND:
/* suspend device */
dev->flag |= RT_DEVICE_FLAG_SUSPENDED;
break; case RT_DEVICE_CTRL_RESUME:
/* resume device */
dev->flag &= ~RT_DEVICE_FLAG_SUSPENDED;
break; case RT_DEVICE_CTRL_CONFIG:
if (args != RT_NULL)
{
struct serial_configure *pconfig = (struct serial_configure *) args;
if (serial->parent.ref_count)
{
/*can not change buffer size*/
return -RT_EBUSY;
}
/* set serial configure */
serial->config = *pconfig;
serial->ops->configure(serial,
(struct serial_configure *) args);
} break; #ifdef RT_USING_POSIX
#ifdef RT_USING_POSIX_TERMIOS
case TCGETA:
{
struct termios *tio = (struct termios*)args;
if (tio == RT_NULL) return -RT_EINVAL; tio->c_iflag = 0;
tio->c_oflag = 0;
tio->c_lflag = 0; /* update oflag for console device */
if (rt_console_get_device() == dev)
tio->c_oflag = OPOST | ONLCR; /* set cflag */
tio->c_cflag = 0;
if (serial->config.data_bits == DATA_BITS_5)
tio->c_cflag = CS5;
else if (serial->config.data_bits == DATA_BITS_6)
tio->c_cflag = CS6;
else if (serial->config.data_bits == DATA_BITS_7)
tio->c_cflag = CS7;
else if (serial->config.data_bits == DATA_BITS_8)
tio->c_cflag = CS8; if (serial->config.stop_bits == STOP_BITS_2)
tio->c_cflag |= CSTOPB; if (serial->config.parity == PARITY_EVEN)
tio->c_cflag |= PARENB;
else if (serial->config.parity == PARITY_ODD)
tio->c_cflag |= (PARODD | PARENB); cfsetospeed(tio, _get_speed(serial->config.baud_rate));
}
break; case TCSETAW:
case TCSETAF:
case TCSETA:
{
int baudrate;
struct serial_configure config; struct termios *tio = (struct termios*)args;
if (tio == RT_NULL) return -RT_EINVAL; config = serial->config; baudrate = _get_baudrate(cfgetospeed(tio));
config.baud_rate = baudrate; switch (tio->c_cflag & CSIZE)
{
case CS5:
config.data_bits = DATA_BITS_5;
break;
case CS6:
config.data_bits = DATA_BITS_6;
break;
case CS7:
config.data_bits = DATA_BITS_7;
break;
default:
config.data_bits = DATA_BITS_8;
break;
} if (tio->c_cflag & CSTOPB) config.stop_bits = STOP_BITS_2;
else config.stop_bits = STOP_BITS_1; if (tio->c_cflag & PARENB)
{
if (tio->c_cflag & PARODD) config.parity = PARITY_ODD;
else config.parity = PARITY_EVEN;
}
else config.parity = PARITY_NONE; serial->ops->configure(serial, &config);
}
break;
case TCFLSH:
{
int queue = (int)args; _tc_flush(serial, queue);
} break;
case TCXONC:
break;
case TIOCSWINSZ:
{
struct winsize* p_winsize; p_winsize = (struct winsize*)args;
rt_kprintf("\x1b[8;%d;%dt", p_winsize->ws_col, p_winsize->ws_row);
}
break;
case TIOCGWINSZ:
{
struct winsize* p_winsize; p_winsize = (struct winsize*)args;
/* TODO: get windows size from console */
p_winsize->ws_col = 80;
p_winsize->ws_row = 24;
p_winsize->ws_xpixel = 0;/*unused*/
p_winsize->ws_ypixel = 0;/*unused*/
}
break;
#endif /*RT_USING_POSIX_TERMIOS*/
case FIONREAD:
{
rt_size_t recved = 0;
rt_base_t level; level = rt_hw_interrupt_disable();
struct rt_serial_rx_fifo *rx_fifo = (struct rt_serial_rx_fifo *)serial->serial_rx;
recved = rt_ringbuffer_data_len(&rx_fifo->rb);
rt_hw_interrupt_enable(level); *(rt_size_t *)args = recved;
}
break;
#endif /*RT_USING_POSIX*/ default :
/* control device */
ret = serial->ops->control(serial, cmd, args);
break;
} return ret;
}

RT-Thread 4.0.3 适配 UART_V2 版本的更多相关文章

  1. 写个续集,填坑来了!关于“Thread.sleep(0)这一行‘看似无用’的代码”里面留下的坑。

    "我报名参加金石计划1期挑战--瓜分10万奖池,这是我的第2篇文章,点击查看活动详情" 你好呀,我是居家十三天只出了一次小区门的歪歪. 这篇文章是来填坑的,我以前写文章的时候也会去 ...

  2. Thread.Sleep(0) vs Sleep(1) vs Yeild

    本文将要提到的线程及其相关内容,均是指 Windows 操作系统中的线程,不涉及其它操作系统. 文章索引 核心概念 Thread.Yeild       Thread.Sleep(0) Thread. ...

  3. phpMyAdmin - 错误 您应升级到 MySQL 5.5.0 或更高版本,解决办法。。。

    折腾自己的个人网站,装了个数据库管理工具,遇到您应升级到 MySQL 5.5.0 或更高版本... 采用降级phpmyadmin版本的方法解决了: 查找phpmyadmin/libraries/com ...

  4. 【转】Thread.sleep(0)的意义

    Thread.sleep(0)的意义 2012-03-23 17:47 2188人阅读 评论(2) 收藏 举报 windows算法unixthread 我们可能经常会用到 Thread.Sleep 函 ...

  5. Thread系列之Thread.Sleep(0)

    线程这一概念,可以理解成进程中的一个小单元.这个单元是一个独立的执行单元,但是与进程中的其他线程共享进程中的内存单元. 由于Cpu资源是有限的,所以进程中的多个线程要抢占Cpu,这也导致进程中的多个线 ...

  6. Thread.sleep(0)的意义& 多线程

    我们可能经常会用到 Thread.Sleep 函数来使线程挂起一段时间.那么你有没有正确的理解这个函数的用法呢?思考下面这两个问题: 假设现在是 2008-4-7 12:00:00.000,如果我调用 ...

  7. 关于Thread.Sleep(0)

    看到的文章,写的不错. 我们可能经常会用到 Thread.Sleep 函数来使线程挂起一段时间.那么你有没有正确的理解这个函数的用法呢?思考下面这两个问题:假设现在是 2008-4-7 12:00:0 ...

  8. 对线程调度中Thread.sleep(0)的深入理解

    在Java或者C#中,都会用到 Thread.Sleep()来使线程挂起一段时间.那么你有没有正确的理解这个方法的用法呢?思考下面这两个问题: 1.假设现在是 2014-8-13 17:00:00.0 ...

  9. Thread系列——Thread.Sleep(0)

    转载自:http://www.cnblogs.com/ATually/archive/2010/10/21/1857261.html 线程这一概念,可以理解成进程中的一个小单元.这个单元是一个独立的执 ...

  10. 说说Thread.Sleep(0)的那些奇怪的事

    写在前面 最近在弄一个传输组件,用到很多多线程的知识,其中有个问题,困扰我很久,不知道是什么原因,脑子一热,在传输过程中,添加了一句代码Thread.Sleep(0).那个问题竟然解决了,耗费我一上午 ...

随机推荐

  1. Docker restart 重启容器

    就像很多常驻后台应用程序动不动可能就需要重启操作一样,有时候我们可能也需要重启容器 而重启容器使用的就是 docker restart 命令 docker restart <container_ ...

  2. vue3-webseek网页版AI问答|Vite6+DeepSeek+Arco流式ai聊天打字效果

    2025 AI实战vue3+deepseek+arcoDesign仿DeepSeek/豆包网页版AI聊天助手. vue3-web-deepseek 实战网页PC版智能AI对话,基于vite6+vue3 ...

  3. 【SpringMVC】数据转换 & 数据格式化

    数据转换 & 数据格式化 & 数据校验 数据转换 数据绑定流程 Spring MVC 主框架将 ServletRequest 对象及目标方法的入参实例传递给 WebDataBinder ...

  4. leetcode每日一题:转换二维数组

    题目 2610. 转换二维数组 给你一个整数数组 nums .请你创建一个满足以下条件的二维数组: 二维数组应该 只 包含数组 nums 中的元素. 二维数组中的每一行都包含 不同 的整数. 二维数组 ...

  5. unigui如何直接显示一个PDF文件【13】

    这个问题有点搞笑. PDF.js v1.9.426 (build: 2558a58d) 信息:Unexpected server response (204) while retrieving PDF ...

  6. CentOS linux 安装openssl(openssl拒绝服务漏洞【CVE-2022-0778】解决)

    一.安装 1.下载相关openssl包 下载地址: https://www.openssl.org/source/ 2.将下载好的压缩包放到 /app/server/nginx 路径下(根据自己实际需 ...

  7. Coze实现古诗文图集

    Coze实现古诗文图集   目标:通过Coze自动化生成古诗配图,并将多张图片排版到画板中,最终直接在对话框展示完整图集(而非链接). 思路: 用户输入诗句 → 2. 补全古诗 → 3.拆分诗文 → ...

  8. 康谋方案 | AVM合成数据仿真验证方案

    随着自动驾驶技术的快速发展,仿真软件在开发过程中扮演着越来越重要的角色.仿真传感器与环境不仅能够加速算法验证,还能在安全可控的条件下进行复杂场景的重复测试. 本文将分享如何利用自动驾驶仿真软件配置仿真 ...

  9. FastAPI与Tortoise-ORM实现关系型数据库关联

    title: FastAPI与Tortoise-ORM实现关系型数据库关联 date: 2025/04/21 10:51:41 updated: 2025/04/21 10:51:41 author: ...

  10. 拆解 Cursor Pro 自动化工具,看看它是怎么实现的?

    深入解析Cursor Pro自动化工具的核心实现 ‍ 从源码角度剖析关键技术 完整解读:注册.认证.机器码重置的自动化方案 项目概述 大家好,我是松哥.这篇文章将为大家详细解析一个Cursor自动化管 ...