RT-Thread 4.0.3 适配 UART_V2 版本
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开发为例进行移植说明.
详情参考
[串口 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;
}