1 背景
项目实施过程中,采用zynq系列芯片,由于zynq自身PS侧仅仅提供两路串口,无法满足实际需求。这就需要从PL侧扩展出来多路串口出来。网上也有一些针对的使用步骤,但是都不够友好,缺少很多细节上的步骤,很难调试成功。本文详解一下实际实现的步骤,供大家参考学习使用。
2 vivado工程
2.1 BD设计
这里使用axi_uartlite IP添加8路串口,BD中涉及uartlite相关内容如下:
2.2 顶层设计
VIVADO工程在顶层文件中,将串口的收发管脚短接,方便环路测试
顶层环路相关代码如下:
wire uart0_rx_tx;
wire uart1_rx_tx;
wire uart2_rx_tx;
wire uart3_rx_tx;
wire uart4_rx_tx;
wire uart5_rx_tx;
wire uart6_rx_tx;
wire uart7_rx_tx;
wire uart8_rx_tx;
.uart_rtl_0_rxd(uart0_rx_tx),
.uart_rtl_0_txd(uart0_rx_tx),
.uart_rtl_1_rxd(uart1_rx_tx),
.uart_rtl_1_txd(uart1_rx_tx),
.uart_rtl_2_rxd(uart2_rx_tx),
.uart_rtl_2_txd(uart2_rx_tx),
.uart_rtl_3_rxd(uart3_rx_tx),
.uart_rtl_3_txd(uart3_rx_tx),
.uart_rtl_4_rxd(uart4_rx_tx),
.uart_rtl_4_txd(uart4_rx_tx),
.uart_rtl_5_rxd(uart5_rx_tx),
.uart_rtl_5_txd(uart5_rx_tx),
.uart_rtl_6_rxd(uart6_rx_tx),
.uart_rtl_6_txd(uart6_rx_tx),
.uart_rtl_7_rxd(uart7_rx_tx),
.uart_rtl_7_txd(uart7_rx_tx),
.uart_rtl_8_rxd(uart8_rx_tx),
.uart_rtl_8_txd(uart8_rx_tx)
2.3 资源下载
本文使用vivado工程,和设备树文件如下链接:
《一文精通zynquartlite的使用》vivado工程,设备树文件,PL使用uartlite例化9路串口,详细步骤文档资源-优快云文库
3 设备树
在pl.dtsi文件中,自动生成如下设备树信息
axi_uartlite_0: serial@42c00000 {
clock-names = "s_axi_aclk";
clocks = <&clkc 15>;
compatible = "xlnx,axi-uartlite-2.0", "xlnx,xps-uartlite-1.00.a";
current-speed = <9600>;
device_type = "serial";
interrupt-names = "interrupt";
interrupt-parent = <&intc>;
interrupts = <0 29 1>;
port-number = <0>;
reg = <0x42c00000 0x10000>;
xlnx,baudrate = <0x2580>;
xlnx,data-bits = <0x8>;
xlnx,odd-parity = <0x0>;
xlnx,s-axi-aclk-freq-hz-d = "50.0";
xlnx,use-parity = <0x0>;
};
axi_uartlite_1: serial@42c10000 {
clock-names = "s_axi_aclk";
clocks = <&clkc 15>;
compatible = "xlnx,axi-uartlite-2.0", "xlnx,xps-uartlite-1.00.a";
current-speed = <9600>;
device_type = "serial";
interrupt-names = "interrupt";
interrupt-parent = <&intc>;
interrupts = <0 30 1>;
port-number = <2>;
reg = <0x42c10000 0x10000>;
xlnx,baudrate = <0x2580>;
xlnx,data-bits = <0x8>;
xlnx,odd-parity = <0x0>;
xlnx,s-axi-aclk-freq-hz-d = "50.0";
xlnx,use-parity = <0x0>;
};
axi_uartlite_2: serial@42c20000 {
clock-names = "s_axi_aclk";
clocks = <&clkc 15>;
compatible = "xlnx,axi-uartlite-2.0", "xlnx,xps-uartlite-1.00.a";
current-speed = <9600>;
device_type = "serial";
interrupt-names = "interrupt";
interrupt-parent = <&intc>;
interrupts = <0 31 1>;
port-number = <3>;
reg = <0x42c20000 0x10000>;
xlnx,baudrate = <0x2580>;
xlnx,data-bits = <0x8>;
xlnx,odd-parity = <0x0>;
xlnx,s-axi-aclk-freq-hz-d = "50.0";
xlnx,use-parity = <0x0>;
};
axi_uartlite_3: serial@42c30000 {
clock-names = "s_axi_aclk";
clocks = <&clkc 15>;
compatible = "xlnx,axi-uartlite-2.0", "xlnx,xps-uartlite-1.00.a";
current-speed = <9600>;
device_type = "serial";
interrupt-names = "interrupt";
interrupt-parent = <&intc>;
interrupts = <0 32 1>;
port-number = <4>;
reg = <0x42c30000 0x10000>;
xlnx,baudrate = <0x2580>;
xlnx,data-bits = <0x8>;
xlnx,odd-parity = <0x0>;
xlnx,s-axi-aclk-freq-hz-d = "50.0";
xlnx,use-parity = <0x0>;
};
axi_uartlite_4: serial@42c40000 {
clock-names = "s_axi_aclk";
clocks = <&clkc 15>;
compatible = "xlnx,axi-uartlite-2.0", "xlnx,xps-uartlite-1.00.a";
current-speed = <9600>;
device_type = "serial";
interrupt-names = "interrupt";
interrupt-parent = <&intc>;
interrupts = <0 33 1>;
port-number = <5>;
reg = <0x42c40000 0x10000>;
xlnx,baudrate = <0x2580>;
xlnx,data-bits = <0x8>;
xlnx,odd-parity = <0x0>;
xlnx,s-axi-aclk-freq-hz-d = "50.0";
xlnx,use-parity = <0x0>;
};
axi_uartlite_5: serial@42c50000 {
clock-names = "s_axi_aclk";
clocks = <&clkc 15>;
compatible = "xlnx,axi-uartlite-2.0", "xlnx,xps-uartlite-1.00.a";
current-speed = <9600>;
device_type = "serial";
interrupt-names = "interrupt";
interrupt-parent = <&intc>;
interrupts = <0 34 1>;
port-number = <6>;
reg = <0x42c50000 0x10000>;
xlnx,baudrate = <0x2580>;
xlnx,data-bits = <0x8>;
xlnx,odd-parity = <0x0>;
xlnx,s-axi-aclk-freq-hz-d = "50.0";
xlnx,use-parity = <0x0>;
};
axi_uartlite_6: serial@42c60000 {
clock-names = "s_axi_aclk";
clocks = <&clkc 15>;
compatible = "xlnx,axi-uartlite-2.0", "xlnx,xps-uartlite-1.00.a";
current-speed = <9600>;
device_type = "serial";
interrupt-names = "interrupt";
interrupt-parent = <&intc>;
interrupts = <0 35 1>;
port-number = <7>;
reg = <0x42c60000 0x10000>;
xlnx,baudrate = <0x2580>;
xlnx,data-bits = <0x8>;
xlnx,odd-parity = <0x0>;
xlnx,s-axi-aclk-freq-hz-d = "50.0";
xlnx,use-parity = <0x0>;
};
axi_uartlite_7: serial@42c70000 {
clock-names = "s_axi_aclk";
clocks = <&clkc 15>;
compatible = "xlnx,axi-uartlite-2.0", "xlnx,xps-uartlite-1.00.a";
current-speed = <9600>;
device_type = "serial";
interrupt-names = "interrupt";
interrupt-parent = <&intc>;
interrupts = <0 36 1>;
port-number = <8>;
reg = <0x42c70000 0x10000>;
xlnx,baudrate = <0x2580>;
xlnx,data-bits = <0x8>;
xlnx,odd-parity = <0x0>;
xlnx,s-axi-aclk-freq-hz-d = "50.0";
xlnx,use-parity = <0x0>;
};
axi_uartlite_8: serial@42c80000 {
clock-names = "s_axi_aclk";
clocks = <&clkc 15>;
compatible = "xlnx,axi-uartlite-2.0", "xlnx,xps-uartlite-1.00.a";
current-speed = <9600>;
device_type = "serial";
interrupt-names = "interrupt";
interrupt-parent = <&intc>;
interrupts = <0 52 1>;
port-number = <9>;
reg = <0x42c80000 0x10000>;
xlnx,baudrate = <0x2580>;
xlnx,data-bits = <0x8>;
xlnx,odd-parity = <0x0>;
xlnx,s-axi-aclk-freq-hz-d = "50.0";
xlnx,use-parity = <0x0>;
};
4 内核
4.1 uartlite内核配置项
打开uartlite内核驱动,我使用的内核版本中,没有说明uartlite最大支持多少路的配置,所以不用关注,如下图所示打开驱动配置即可。
这里看使用的内核版本号,高版本的内核版本需要配置一下使用的串口数量的上限如下图所示
5 上板调试
BD文件中例化9个uartlite串口,在顶层文件将收发管脚短接,所以使用何种开发板测试都比较方便。
5.1 启动log
Linux启动过程关键log如下,这里看
PS串口识别如下
PL串口识别如下
5.2 串口文件节点
/dev/下串口节点查看如下图:
5.3 自发自收测试
这里使用了一个串口应用uart_app,在我之前的博客有介绍该软件的使用(提供了该软件的源码和makfile),感兴趣的同学,可以翻翻之前的博客,这里就直接截图测试结果如下:
6 不踩坑必读
6.1 关于中断线
VIVADO工程必须连接axi_uartlite IP的中断线,不然驱动无法正确加载,/dev下无对应的串口节点。
6.2 串口数量大于16
如果使用更多了大于16路axi_uartlite IP,PL-PS中断线不够使用,该怎么办呢?留个问题
6.3 参数配置
axi_uartlite在Linux应用层无法配置串口参数,如波特率等,配置了也没有用,只能在VIVADO工程中配置,配置完后要重新更新bit流文件、设备树文件等相关烧录文件。如下图所示
7 资源下载
本文使用vivado工程,和设备树文件如下链接:
《一文精通zynquartlite的使用》vivado工程,设备树文件,PL使用uartlite例化9路串口,详细步骤文档资源-优快云文库