King3399(ubuntu文件系统)串口功能测试
0 引言
串口作为大多数人接触嵌入式的第一种数据传输方式,由于其简单易用的特性,在程序调试过程中起着重要作用,本文将对king3399的uart进行测试并对硬件电路、设备树与驱动程序进行分析
1 uart接口快速测试
通过King3399底板-硬件规格书能够了解到,板子在不修改设备树的情况下有两个可用的串口:uart0和uart4,这里以uart4为例,进行测试分析,打开...\02-软件文档\荣品文档\驱动调试\串口
可以看到有关于串口部分的测试说明,里边的内容很简单,这里可以快速复现一下串口使用测试说明.pdf
的内容,顺便测试是否存在硬件故障
首先板子上电并安装cutecom串口调试工具,关于cutecom的安装与使用可以参考脚注【a】,如果不确定系统是否安装cutecom,可以打开命令行输入cutecom并回车,如果已安装则会弹出应用界面
cutecom安装完成后便可进行回环测试(自己发送自己接收),有条件的可以找对应的接插件,将位号为J30的RX与TX短接,剩余两个引脚不用管,没有条件的找一根双母头2.54杜邦线,将两头的胶壳取下,再往金属端子裹一层胶布,然后将两头分别接到J30的RX与TX上,注意不要让vcc与gnd短接,可能会造成不可逆后果!!!
命令行输入cutecom打开串口调试工具,参考配置如下,在“Device”处选择时可挨个试试,本人选择的是“ttyS*”,如果不清楚这个tty是什么的可以参考脚注【b】,然后在“Input”输入发送的字符按下回车键发送,发送的历史记录将将会显示在上边的文本框中,如果想要快速发送可以直接双击历史记录中的数据,如果硬件没有问题将会在下边文本框中收到发送的数据,至此,uart驱动与硬件一切正常
进一步的,我们还可以测试不同设备/系统之间的uart通信是否正常,这里需要准备一个CH340_USB转串口模块,双母头杜邦线3根,电路连接如下所示,注意RX与TX的交叉连接,为保证数据传输的稳定性还需将两者的GND相连
打开电脑上串口调试工具,波特率与板子上调试工具的一致,这里设置为9600,8-None-1,分别在电脑端与板子端发送数据,如果一切正常则能够收到对方的数据,电脑与板子调试工具的配置如下图所示
通过上述两组测试能够验证uart相关的软硬件没有问题,下面我们将更深入地去讲解板子uart的硬件部分
2 uart接口硬件分析
打开...\底板硬件资料\KING3399-20180712原理图.pdf
,截取相关电路原理图如下所示,uart4(J30)与spi(J35)复用芯片的GPIO1_A7与GPIO1_B0,uart(J30)经过RS232(U10)进行电平转换,再进入Q27/Q28两颗mos管实现不同电平的隔离,本人电路知识有限,这里只能粗略说明工作原理
首先是U10这颗芯片,这颗芯片贴片时并没有贴,在...\03-硬件文档\king3399 改 RS232.jpg
中可以了解到,该芯片是选配的,由用户自行决定是否焊接,默认不焊接,未焊接时,可使用uart进行通信,焊接后使用rs232通信,相信很多人对于串行通信、uart以及rs232这几个概念是比较模糊的,具体的区别可参考脚注【c】,关于该芯片的具体信息BOM表中并没有提到,但从引脚数量、功能及外接电路可以猜测出可能是sp3232
其次是Q27/Q28这两颗mos管,这俩的作用是实现不同电平域的隔离,功能与熟知的光耦或者电磁继电器相似,分析这部分电路时需要注意VCCA1V8_CODEC
与VDD_IO
这两个电源网络的电压,前者是1.8v,后者是3.3v,有人可能好奇这里为什么是1.8v而不是常见的3.3v,关于这个问题可以参考脚注【d】,另外由于rk3399这颗芯片在初始化时将GPIO1_A7与GPIO1_B0等引脚的电压设定为1.8v,这就意味着这部分引脚的最大承受电压为1.8v,而我们使用的大多数uart通信外设使用的电压为标准TTL电平(高电平通常为3.3V至5V,低电平为0V至0.4V),这显然不能采用直连的方案,于是便使用mos对不同电平域隔离,关于此处mos管的工作原理可以参考脚注【e】
关于板子uart的硬件部分差不多就分析完了,这部分涉及的知识点比较杂,本人也是边写边学,有讲错的地方还请斧正
3 uart设备树分析
为了验证前面的硬件电路分析,我们还可以从设备树的配置入手,打开/home/username/ws/sdk/kernel/arch/arm64/boot/dts/rockchip/rk3399.dtsi
,摘取spi1与uart4节点的部分内容如下,从配置中可以看到spi1与uart4共用PA7与PB0这两个引脚
spi1 {
spi1_clk: spi1-clk {
rockchip,pins = <1 RK_PB1 2 &pcfg_pull_up>;
};
spi1_cs0: spi1-cs0 {
rockchip,pins = <1 RK_PB2 2 &pcfg_pull_up>;
};
spi1_rx: spi1-rx {
rockchip,pins = <1 RK_PA7 2 &pcfg_pull_up>; // <------------------
};
spi1_tx: spi1-tx {
rockchip,pins = <1 RK_PB0 2 &pcfg_pull_up>; // <------------------
};
};
......
uart4 {
uart4_xfer: uart4-xfer {
rockchip,pins =
<1 RK_PA7 1 &pcfg_pull_up>, // <------------------
<1 RK_PB0 1 &pcfg_pull_up>; // <------------------
};
};
在/home/username/ws/sdk/kernel/arch/arm64/boot/dts/rockchip/rk3399/king-rk3399.dts
中可以看到,spi1的状态为disable,而uart4的状态为okay,这也就意味着J35这个接口并不起作用
&spi1 {
status = "disabled"; // <------------------
max-freq = <50000000>;
spi_test:spi_test@0 {
status = "okay";
compatible = "rockchip,spidev";
reg = <0>;
spi-max-frequency = <4000000>;
spi-cpha;
spi-cpol;
cs-gpios = <&gpio1 RK_PB2 GPIO_ACTIVE_LOW>;
};
};
......
&uart4 {
status = "okay"; // <------------------
pinctrl-names = "default";
pinctrl-0 = <&uart4_xfer>;
dma-names = "tx", "rx";
dmas = <&dmac_peri 8>, <&dmac_peri 9>;
};
在上一个小节中我们提到了电源域,在写这篇文章时,本人原想结合电路在设备树看看这个板子是如何配置的,但官方所给的资料中没有核心板的原理图,对于电源配置这方面无从下手,在文件02-软件文档\RK原厂文档\linux\cn\RK3399\Rockchip_RK3399_IO_电源域配置指南_CN.pdf
中有提到如何去配置,本人水平有限看不懂
4 uart驱动代码分析
为确定uart驱动源码需打开文件:\02-软件文档\荣品文档\源码文件路径.xlsx
,在工作簿RK3399中找到SERIAL
,其对应的路径就为uart驱动源码的路径kernel/drivers/tty/serial/8250/
,打开上述路径会发现该路径中存在大量文件,一时无从下手,为快速定位具体使用的驱动程序可打开/home/username/ws/sdk/kernel/arch/arm64/boot/dts/rockchip/rk3399.dtsi
,可以看到uart4的具体配置信息
uart4: serial@ff370000 {
compatible = "rockchip,rk3399-uart", "snps,dw-apb-uart";
reg = <0x0 0xff370000 0x0 0x100>;
clocks = <&pmucru SCLK_UART4_PMU>, <&pmucru PCLK_UART4_PMU>;
clock-names = "baudclk", "apb_pclk";
interrupts = <GIC_SPI 102 IRQ_TYPE_LEVEL_HIGH 0>;
reg-shift = <2>;
reg-io-width = <4>;
pinctrl-names = "default";
pinctrl-0 = <&uart4_xfer>;
status = "disabled";
};
其中compatible = "rockchip,rk3399-uart", "snps,dw-apb-uart";
值得注意,在kernel/drivers/tty/serial/8250/
目录下全局查找rockchip,rk3399-uart
与snps,dw-apb-uart
字串,会发现前者无结果,而后者在两个文件中有提到,分别为8250_dw.c与8250_early.c,根据文件头部说明可以知道8250_dw.c为Synopsys DesignWare 8250 driver
,也即Synopsys的串口驱动程序,king3399借用该驱动,而8250_early.c的作用是提供系统早期控制台支持,允许在内核启动早期阶段使用8250 uart进行调试输出,该文件可先不理会,本文只分析内核启动后串口的驱动分析
因此8250_dw.c为主要源码分析对象,为便于对比,参考脚注【f】中将会提供添加注释前后的源码文件,需要注意的是由于源码涉及很多知识点,本人也并不精通这部分内容,在添加注释时借用了vscode MarsCode AI
插件,注释的准确性需自行甄别
根据设备树的兼容性属性可以定位到of_device_id dw8250_of_match
,而该结构体在platform_driver dw8250_platform_driver
被调用,细心地可以注意到,该结构何体中有两个设备匹配表,分别为dw8250_of_match
与dw8250_acpi_match
,驱动中使用的是前者,关于这两者的区别为:ACPI主要用于x86架构,是UEFI固件的一部分,致力于提升电源效率,在内核启动时加载;而设备树(DTS)适用于ARM架构,是独立的文件,旨在分离设备驱动与设备信息,DTS在启动前传递给内核,参考脚注【g】,rk3399使用的是设备树,因此选择前者,此外,驱动程序中还将uart设备添加到MODULE_DEVICE_TABLE
外设队列中,表示该外设支持热插拔功能
在dw8250_platform_driver
中还注册了电源管理相关的函数dw8250_pm_ops
,在结构体dev_pm_ops dw8250_pm_ops
中主要实现了四个函数:睡眠模式下的挂起与恢复,运行模式下的挂起与恢复
接下来便是设备注册函数dw8250_probe
,主要完成以下操作:变量声明与初始化,检查寄存器资源和获取中断号,初始化UART端口参数,内存映射和数据结构分配,设置DMA过滤函数和UART状态寄存器偏移,读取设备属性并设置UART端口参数,配置时钟和复位控制,处理设备的特殊特性,配置DMA,注册UART端口,注册时钟通知器以及启用电源管理
与注册相对应的为注销函数dw8250_remove
,主要完成以下操作:取消注册时钟通知器、取消注册UART端口、复位设备、禁用时钟以及禁用设备的电源管理
最后通过module_platform_driver
对外设进行注册与注销,该函数替代了module_init
与module_exit
以上是8250_dw.c的粗略分析,更多细节部分可下载文末提供的源码文件比对查看
【a】 ubuntu cutecom串口调试工具使用方法 (图形界面)
【b】 Linux TTY基本概念之ttys*、tty*、ttyS*、console理解
【c】 电子设计 | 串口,UART,RS232之间的区别
【d】 1.8V、3.3V、5V、12V等常用电压等级是如何确立的?
【e】 经典的MOS管电平转换电路
【f】 代码仓库(pwd : 73ig)
【g】 ACPI和设备树(DTS)的区别