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开发为例进行移植说明.

详情参考

[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

RT-Thread 4.0.3 适配 UART_V2 版本

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

RT-Thread 4.0.3 适配 UART_V2 版本

#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

RT-Thread 4.0.3 适配 UART_V2 版本

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

RT-Thread 4.0.3 适配 UART_V2 版本

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

RT-Thread 4.0.3 适配 UART_V2 版本

#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

RT-Thread 4.0.3 适配 UART_V2 版本

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

RT-Thread 4.0.3 适配 UART_V2 版本

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

RT-Thread 4.0.3 适配 UART_V2 版本

#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 */

RT-Thread 4.0.3 适配 UART_V2 版本

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;
}
上一篇:yp线段树


下一篇:洛谷 P1972 [SDOI2009]HH的项链