Linux驱动之USART

文章详细介绍了串口驱动的基础知识,包括UART的电平标准如TTL、RS232和RS485,以及在单片机上的UART驱动实现。在Linux内核中,UART驱动通常由SOC厂商提供,通过设备树配置匹配多个串口设备。驱动注册和probe函数在初始化和设备探测阶段发挥作用,而设备树的配置对串口设备的添加至关重要。最后,文章提及了设备节点的生成及其在实际通信中的应用。
摘要由CSDN通过智能技术生成

一、理解串口驱动

我们所谓串口驱动,先说串口,其实就是异步的半/全双工串行通信,TX RX 还有地 这是本质,然后区分不同串口的其实是根据电平

比如:

  1. UART TTL电平(逻辑1: 2.4V–5V 逻辑0: 0V-- 0.5V)
  2. RS232 (逻辑1:-15V – -3V 逻辑0:+3V-- +15V)
  3. RS485(逻辑1:+2V-- +6V 逻辑0:-6V-- -2V)这里的电平指AB 两线间的电压差。

然后不同种类的有不同优点与缺点,比如RS485抗干扰能力强,距离长。

二、单片机本质驱动UART

我们要在单片机上驱动串口,其实本质是驱动uart,如果要实现其它电平那么会在单片机外围再加上对应电平转换电路。(因为单片机是TTL电平的。)

三、linux内核下的UART驱动

说明:

linux的uart驱动一般都被soc厂商写好了,且只有一个驱动程序,但是可以匹配多个串口设备,这就需要我们更改设备树,添加串口节点了(这就是我们驱动工程师要做的)相比于I2C/SPI驱动,UART驱动没有自己的总线,因为驱动程序就一个而且还是soc厂商写好的,但是

UART驱动和设备是挂在Platform下的。UART设备一旦挂上就会执行驱动中probe

驱动实现:

uart设备驱动本质上是一个基于platform的字符设备驱动,它的major与min_start和次设备数量都是由各个soc确定下来的。

1.设备树讲解

不是讲驱动吗?为啥要讲设备树呢?

因为我们要清楚一点就是设备树头文件imx6ull.dtsi与我们自己要修改的设备树文件如:imx6ull_14x14_dts,

一般SOC厂商写好的程序匹配的都是imx6ull.dtsi中的compitable,然后将节点匿名如uart1 = &uart1,那么在我们自己的dts中就直接可以用&uart1了,如果在&uart1节点下的节点不写compitable的话那么默认就是父节点&uart1的compitable了。

2.回到uart驱动

soc在驱动与设备树匹配这块是这样实现的,所有uart1/2/3/4/5/6的父节点都在imx6ull.dtsi中实现,然后compitable都一样。

那么也就是会有的效果就是,如果在自己的dts下不论是那个&uart如果添加了没有自己compible的节点都会匹配到soc厂商写的那个驱动,也是唯一的一个uart驱动。

3.先上结构体
struct uart_driver {
	struct module		*owner;
	const char		*driver_name;
	const char		*dev_name;
	int			 major;
	int			 minor;
	int			 nr;
	struct console		*cons;
	
	struct uart_state	*state;
	struct tty_driver	*tty_driver;
};

struct uart_port {
	unsigned int		type;			/* port type */
	const struct uart_ops	*ops;//里面是底层的与uart交互的函数
	.....
	void			*private_data;		/* generic platform data pointer */
};


4.编写步骤
1.在init中
static int __init imx_serial_init(void)
{
	int ret = uart_register_driver(&imx_reg);//在这里面注册了字符设备,但是还没有与uart_ops绑定

	if (ret)
		return ret;

	ret = platform_driver_register(&serial_imx_driver);//当有设备时,调用serial_imx_driver的probe函数,调用uart_add_one_port函数将cdev与uart_ops绑定.
	if (ret != 0)
		uart_unregister_driver(&imx_reg);

	return ret;
}
2.probe函数
 static int serial_imx_probe(struct platform_device *pdev)
{
	struct imx_port *sport;
	void __iomem *base;
	int ret = 0;
	struct resource *res;
	int txirq, rxirq, rtsirq;
	....
	....
	sport->port.dev = &pdev->dev;
	sport->port.mapbase = res->start;
	sport->port.membase = base;
	sport->port.type = PORT_IMX,
	sport->port.iotype = UPIO_MEM;
	sport->port.irq = rxirq;
	sport->port.fifosize = 32;
	sport->port.ops = &imx_pops;//实现ops函数
    return uart_add_one_port(&imx_reg, &sport->port);//添加到cdev下
}
我们要做的事,添加设备节点:

注意:

​ 由于串口驱动只能一对一,所以设备有多少个串口就只能设多少个节点,比如imx的imx6ull.dtsi下只有&uart1-8,那么我们只能在自己的dts文件下的每个&uart下最多创建一个节点。不能一个uart有多个子节点。

步骤:

1.pinctrl
pinctrl_uart3: uart3grp {
	fsl,pins = <
		MX6UL_PAD_UART3_TX_DATA__UART3_DCE_TX 0X1b0b1
		MX6UL_PAD_UART3_RX_DATA__UART3_DCE_RX 0X1b0b1
	>;
};
2.uart
&uart3 {
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_uart3>;
	status = "okay";
};
应用:

在更改完设备树并重新启动内核后,就会在/dev下多出对应节点,其名称由soc写的驱动中的dev_name决定。

我们可以在开发板上minicom进行与电脑的串口通信,具体如何用test.c打开设备与外界通信还不知道。

原理:

(83条消息) Linux串口驱动分析及移植_heat.huang的博客-CSDN博客_linux 串口驱动

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值