在嵌入式Linux开发里,串口是最常用的通信接口之一。调试用串口、跟外设通信用串口、接GPS模块用串口,到处都能看到它。写Linux串口驱动说难不难,说简单也不简单,关键是搞清楚tty子系统的框架。
Linux的串口驱动属于tty驱动框架。tty是teletype的缩写,最早指电传打字机,现在泛指所有终端类设备。串口设备在/dev目录下一般是ttyS0、ttyS1这样的设备节点(PC上的串口),或者ttymxc0、ttyAMA0这样的(嵌入式平台的串口)。应用层通过open、read、write这些系统调用操作串口,内核里有一层tty核心负责分发,底层才是具体的串口驱动。
写串口驱动主要是实现struct uart_ops这个结构体里的回调函数。常用的接口有tx_empty(发送缓冲区是否为空)、set_mctrl(设置调制解调控制信号)、get_mctrl(获取调制解调信号)、stop_tx(停止发送)、start_tx(开始发送)、stop_rx(停止接收)、enable_ms(使能调制解调信号中断)、break_ctl(控制break信号)、startup(启动串口)、shutdown(关闭串口)、set_termios(设置串口参数)这些。
内核里已经有一套通用的串口驱动框架叫serial core,大部分驱动都是基于这个框架写的。你不用从零实现tty驱动,只要实现uart_ops里的几个关键函数,然后通过uart_add_one_port注册到serial core里就行。serial core会帮你处理tty设备的注册、termios设置、缓冲区管理这些通用逻辑。
收发数据的流程是这样的。发送的时候,上层调用write,数据进tty的发送缓冲区,serial core调用驱动的start_tx函数,驱动从缓冲区取数据往硬件发送寄存器里写,发完一个字节触发发送中断,在中断里继续写下一个字节,直到缓冲区空了调用stop_tx。接收的时候,硬件收到一个字节触发接收中断,驱动在中断里把数据读出来,通过uart_insert_char把数据塞进tty的接收缓冲区,上层read就能取到了。
实际开发中常见的坑有几个。一个是时钟配置,串口的波特率是根据时钟分频来的,时钟配错了波特率就不对,收的数据全是乱码。另一个是中断号和DMA配置,设备树里要写对,不然中断进不来或者DMA不工作。还有就是引脚复用,串口的TX和RX引脚要配置成串口功能,别配成GPIO了。调试的时候先用示波器或者逻辑分析仪抓波形,确认硬件层没问题再查软件。
上一篇:74HC138译码器原理与应用:三根线怎么控制8个灯
下一篇:没有了