build_embed_linux_system

串口tty管理框架

在接触嵌入式Linux以来,从上电那一刻开始,我们接触的就是从串口命令行打印的信息;作为U-Boot和Kernel调试打印和交互的接口,串口的重要性不言而喻。从硬件上来说,串口并不复杂,最简单的通讯只需要RX,TX,GND三根线即可;复杂的也就是增加RTS,CTS实现流控,或者增加DIR方向引脚实现RS485通讯。但是从软件的角度来看,串口的管理框架是非常复杂的,涉及到了串口驱动、tty设备注册,console终端管理,理解起来就相当复杂了;这也是如此靠后去讲解tty serial框架的原因。

本文中将从UART常用硬件结构、UART驱动实现、串口命令调试和应用层访问以及Console终端管理四部分讲解tty serial框架相关说明;具体目录如下所示。

uart_hw

UART是支持全双工和半双工、异步收发的通讯模块。在嵌入式系统中,UART可以说是最常用的通讯模块之一,例如用于打印调试信息和命令控制的调试口,用于和蓝牙,wifi模块连接的通讯口,板级芯片通讯的连接口,都是基于UART功能实现。另外UART也支持外扩芯片支持不同的物理接口,如RS232,RS485和RS422等,可以满足多场景多设备的需求。

uart_connect

UART对于芯片I/O输出的是TTL电平,一般用于短距离通讯。为了增加可靠性和远距离通讯,可以通过外部扩展支持RS232,RS485和RS422等多种通讯接口,这些接口连接时注意不能混用,否则有损坏器件的风险。

我们的调试串口一般使用UART-TTL或者UART-RS232来实时打印;在工业中,通常使用RS232或者RS485来实现稳定可靠的远程通讯。RS422因为成本问题,则常用于对通讯速率要求高,要求全双工,且传输距离远的场景。

uart_pins

UART的常用引脚如下所示。

在产品开发中,一般使用UART-TXD和UART-RXD进行通信。对于部分低功耗或者高低频搭配的产品,通过流控线来限制高速产品的数据发送,避免处理来不及导致数据包丢失。方向控制则用于RS485连接通讯,控制收发方向。

tty_driver

tty_app

console_terminal

串口模块

tty的操作主要涉及文件:

//获取tty相关的gpio,分别对应cts-gpios, dsr-gpios, dcd-gpios, rng-gpios, rts-gpios, dtr-gpios
drivers/tty/serial/serial_mctrl_gpio.c  
drivers/tty/serial/serial_core.c
drivers/tty/serial/imx.c
drivers/tty/serial/imx_earlycon.c

//include/linux/circ_buf.h
struct circ_buf {
    char *buf;
    int head;
    int tail;
};

//include/linux/serial_core.h
struct uart_state {
    struct tty_port         port;

    enum uart_pm_state      pm_state;
    struct circ_buf         xmit;

    atomic_t                refcount;
    wait_queue_head_t       remove_wait;
    struct uart_port        *uart_port;
};

struct uart_port {
    spinlock_t              lock;            /* port lock */
    unsigned long           obase;            /* in/out[bwl] */
    unsigned char __iomem   *membase;        /* read/write[bwl] */
    unsigned int            (*serial_in)(struct uart_port *, int);
    void                    (*serial_out)(struct uart_port *, int, int);
    void                    (*set_termios)(struct uart_port *,
                               struct ktermios *new,
                               const struct ktermios *old);
    void                    (*set_ldisc)(struct uart_port *,
                                struct ktermios *);
    unsigned int            (*get_mctrl)(struct uart_port *);
    void                    (*set_mctrl)(struct uart_port *, unsigned int);
    unsigned int            (*get_divisor)(struct uart_port *,
                                unsigned int baud,
                                unsigned int *frac);
    void                    (*set_divisor)(struct uart_port *,
                                unsigned int baud,
                                unsigned int quot,
                                unsigned int quot_frac);
    int                     (*startup)(struct uart_port *port);
    void                    (*shutdown)(struct uart_port *port);
    void                    (*throttle)(struct uart_port *port);
    void                    (*unthrottle)(struct uart_port *port);
    int                     (*handle_irq)(struct uart_port *);
    void                    (*pm)(struct uart_port *, unsigned int state,
                                unsigned int old);
    void                    (*handle_break)(struct uart_port *);
    int                     (*rs485_config)(struct uart_port *,
                                struct ktermios *termios,
                                struct serial_rs485 *rs485);
    int                     (*iso7816_config)(struct uart_port *,
                                struct serial_iso7816 *iso7816);
    unsigned int            irq;            /* irq number */
    unsigned long           irqflags;        /* irq flags  */
    unsigned int            uartclk;        /* base uart clock */
    unsigned int            fifosize;        /* tx fifo size */
    unsigned char           x_char;            /* xon/xoff char */
    unsigned char           regshift;        /* reg offset shift */
    unsigned char           iotype;            /* io access style */
    unsigned char           quirks;            /* internal quirks */

    unsigned int            read_status_mask;    /* driver specific */
    unsigned int            ignore_status_mask;    /* driver specific */
    struct uart_state       *state;            /* pointer to parent state */
    struct uart_icount      icount;            /* statistics */

    struct console          *cons;            /* struct console, if any */
    /* flags must be updated while holding port mutex */
    upf_t                   flags;

    /*
     * Must hold termios_rwsem, port mutex and port lock to change;
     * can hold any one lock to read.
     */
    upstat_t                status;

    int                     hw_stopped;        /* sw-assisted CTS flow state */
    unsigned int            mctrl;            /* current modem ctrl settings */
    unsigned int            frame_time;        /* frame timing in ns */
    unsigned int            type;            /* port type */
    const struct uart_ops    *ops;
    unsigned int            custom_divisor;
    unsigned int            line;            /* port index */
    unsigned int            minor;
    resource_size_t         mapbase;        /* for ioremap */
    resource_size_t         mapsize;
    struct device           *dev;            /* parent device */

    unsigned long           sysrq;            /* sysrq timeout */
    unsigned int            sysrq_ch;        /* char for sysrq */
    unsigned char           has_sysrq;
    unsigned char           sysrq_seq;        /* index in sysrq_toggle_seq */

    unsigned char           hub6;            /* this should be in the 8250 driver */
    unsigned char           suspended;
    unsigned char           console_reinit;
    const char              *name;            /* port name */
    struct attribute_group    *attr_group;        /* port specific attributes */
    const struct attribute_group **tty_groups;    /* all attributes (serial core use only) */
    struct serial_rs485     rs485;
    struct serial_rs485    rs485_supported;    /* Supported mask for serial_rs485 */
    struct gpio_desc    *rs485_term_gpio;    /* enable RS485 bus termination */
    struct serial_iso7816   iso7816;
    void            *private_data;        /* generic platform data pointer */
};

next_chapter

返回目录

直接开始下一节说明: nvmem子系统管理框架