ZYNQ学习之路5.扩展PL端串口

在ZYNQ7000中,硬核只集成了两个串口外设,除去终端使用的串口,只剩一下一个串口可用,而在大多数应用中一个串口往往不能满足要求。使用FPGA模拟串口可以解决串口外设不足的问题,Xilinx提供了两种串口IP:AXI UART Lite和AXI UART 16550,使用这两个IP可以非常方便的使用扩展串口,并且Xilinx提供了Linux中的相应的串口驱动程序,符合tty标准设备。本文介绍这两种串口IP的使用。

一. UART Lite与UART 16550介绍

1.1 AXI UART Lite

AXI UART Lite IP是完全使用FPGA资源模拟出来的异步串口收发器,使用AXI总线与ARM硬核进行通信控制。它支持常用的5~8位数据位,奇偶校验,可配置的波特率,发送与接收分别使用了16字节FIFO。其原理框图如图1-1所示。

图1-1: AXI UART Lite原理框图

在ZYNQ7010中,AXI UART LiteIP支持的最大波特率是921600,不到1MHz,基本满足大部分场景需求,如果系统要求波特率更高则使用另外一个IP,也就是本文提到的UART 16550。

1.2 AXI UART 16550

16550 uart最初是一个集成芯片,为了满足计算机串口的高速通信而设计,在最初的一版设计中其FIFO存在BUG,随后便推出了16550A版本。正如其是为了满足高速串口通信,它的波特率可以远远高于大部分单片机内部集成的串口。

UART16550除了拥有AXI UART Lite的全部功能外,还提供1.5bit和2bit停止位,在可配置波特率的基础上还可以使用外部时钟供给串口接收模块,经测试发现,其波特率可以达到linux中tty设备定义的最大波特率,也就是4.5Mbps。

功能如此齐全的UART IP在资源的利用上显然要比UART Lite要高,事实上同样的配置UART16550是UART Lite资源的3倍左右。

二. 使用串口AXI UART Lite IP

2.1 编译uboot源码

下载uboot源代码(https://github.com/Xilinx/u-boot-xlnx)

2.2 编译Linux内核

下载xilinx的linux源代码(https://github.com/Digilent/linux-digilent-Dev)

解压进入内核根目录

# make ARCH=arm CROSS_COMPILE=arm-xilinx-linux-gnueabi- xilinx_zynq_defconfig
# make ARCH=arm CROSS_COMPILE=arm-xilinx-linux-gnueabi- menuconfig

在内核中配置支持AXI UART:

-->Device Dirvers --> Character devices --> Serial drivers -->Xilinx uartlite serial port support

# make ARCH=arm CROSS_COMPILE=arm-xilinx-linux-gnueabi- UIMAGE_LOADADDR=0x8000 uImage

2.3 编译设备树

下载device-tree-generator工具:http://wiki.xilinx.com/device-tree-generator

解压到vivado安装目录下,在xilinx的SDK软件中选择Xilinx->Respositories工具,在Local Respositories中点击New,选择刚解压的Device tree generator工具的根目录,然后点击Apply,OK。

图2-1: Device tree generator工具配置

在点击Apply后在SDK的控制台上可以看到有软件的编译输出,说明安装正确。

点击File->New->Xilinx Board Support Package,可以发现在Board Support Package OS选项中多了一项device-tree.

图2-2: device_tree工程创建

点击Finish进入BSP的设置,首先需要设置console_device,zedboard使用的是串口1,所以必须选择ps7_uart_1.

图2-3: 选择终端串口

BSP设置完后点击Finish,软件会自动生成所有需要的设备树,包括用户在PL中建立的IP核生成的设备树文件,如下图所示:

图2-4: 设备树生成工程

其中zynq-7000.dtsi是zynq的PS部分所需要的设备树,pl.dtsi中则是PL部分用户添加的IP的设备树,将其添加到开发板的dts文件中,在执行编译生成设备树即可。

# make ARCH=arm CROSS_COMPILE=arm-xilinx-linux-gnueabi- dtbs

由于内核中已经添加了xilinx的uartlite支持,并且设备树建立完成,在linux启动后,在dev目录下回生成一个ttyUL1的设备,如下图所示。

图2-5: /dev目录文件增加了uartlite设备

三. 使用UART16550

uart16550可以达到比较高的波特率,而且可以外接晶振,提高波特率。

3.1 添加UART16550 IP核

在vivado中添加IP,搜索uart16550,添加即可,点自动连线,然后删除连接的引脚。展开UART,从sin和sout创建引脚,如下图所示。

图3-1: AXI UART16550连接

分配好地址后综合,添加引脚约束,导出硬件设计,进入SDK。首先为了确保硬件设计的正确与否,可以在裸机上测试串口的功能,常用的函数如下:

a.设置串口的输入时钟和波特率: XUartNs550_SetBaud()

b.发送一个字节:XUartNs550_SendByte(UINTPTR BaseAddress, u8 Data)

c.接收一个字节:XUartNs550_RecvByte(UINTPTR BaseAddress)

新建一个devicetree的BSP工程,console_device选择ps7_uart_1,在选择列表中出现了新增的UART16550的选项,注意不要选错。

图3-2: 设置串口终端

3.2 编辑设备树文件

打开devicetree_bsp中生成的pl.dtsi文件,该文件是用户在PL中添加的硬件需要新增的设备树文件,全部复制到zed内核中配置设备树的文件中。

/ {
	amba_pl: amba_pl {
        #address-cells = <1>;
        #size-cells = <1>;
        compatible = "simple-bus";
        ranges ;
        axi_uart16550_0: serial@43c00000 {
            clock-frequency = <2.5e+08>;
            clock-names = "ref_clk";
            clocks = "clkc 0";
            compatible = "xlnx,xps-uart16550-2.00.a", "ns16550a";
            current-speed = <115200>;
            device_type = "serial";
            interrupt-parent = <&intc>;
            interrupts = <0 29 4>;
            port-number = <1>;
            reg = <0x43c00000 0x10000>;
            reg-offset = <0x1000>;
            reg-shift = <2>;
            xlnx,external-xin-clk-hz = <0x17d7840>;
            xlnx,external-xin-clk-hz-d = <0x19>;
            xlnx,has-external-rclk = <0x0>;
            xlnx,has-external-xin = <0x0>;
            xlnx,is-a-16550 = <0x1>;
            xlnx,s-axi-aclk-freq-hz-d = "250.0";
            xlnx,use-modem-ports = <0x1>;
            xlnx,use-user-ports = <0x1>;
        };
};

打开devicetree_bsp中的system-top.dts文件,可以看到在aliases节点中新增了用户添加的AXI外设,将新增的内容复制到zed的dts文件中。

/dts-v1/;
/include/ "zynq-7000.dtsi"
/include/ "pl.dtsi"
/include/ "pcw.dtsi"
/ {
	chosen {
        bootargs = "earlycon";
        stdout-path = "serial0:115200n8";
	};
	aliases {
        ethernet0 = &gem0;
        serial0 = &uart1;
        serial1 = &uart0;
        serial2 = &axi_uart16550_0;
        spi0 = &qspi;
	};
	memory {
        device_type = "memory";
        reg = <0x0 0x20000000>;
	};
};

修改后zynq_ztrun.dts文件开始部分如下:

/dts-v1/;
/include/ "zynq-7000.dtsi"
/ {
	model = "MYIR Z-turn Development Board";
	compatible = "myir,zynq-zturn", "xlnx,zynq-7000";

	aliases {
        ethernet0 = &gem0;
        serial0 = &uart1;
        serial1 = &uart0;
        spi0 = &qspi;
        
        serial2 = &axi_uart16550_0;
	};

	memory {
        device_type = "memory";
        reg = <0x0 0x1c000000>; // Reserved 256MB for xylonfb driver
	};

	chosen {
        bootargs = "console=ttyPS0,115200 root=/dev/ram rw earlyprintk";
        linux,stdout-path = "/amba/serial@e0001000";
	};
};

3.3 配置内核

进入内核进行配置,添加16550的支持,并且设置支持的个数为16,最后在zynq_zturn_defconfig文件中找到non-8250 serial port support位置,在下面的配置中添加CONFIG_SERIAL_OF_PLATFORM=y,添加后如下图所示:

图3-3: 修改内核配置文件

编译内核及设备树。

3.4 测试

在上述所有的文件制作好之后,复制到SD卡,让开发板从SD卡启动,启动之后查看/dev目录,可以得到如下信息。

图3-4: /dev目录下新增了UART16550设备节点

可以看到系统中多了ttyS0~ttyS15,本次系统中可以使用的是ttyS2~ttyS11, 因为在aliases节点下ARM端的两个串口已经占用了serial0和serial1。

使用USB转串口模块连接开发板,打开PC端的串口调试助手,设置波特率为1500000,在终端中使用命令测试串口:

> stty -F /dev/ttyS2 speed 1500000 cs8		#设置波特率
> echo heelo > /dev/ttyS2				#发送数据
> cat /dev/ttyS2					#接收数据
图3-5: 使用命令测试串口

参考链接

[1]. Xilinx axi-uartlite手册

[2]. Xilinx uart16550手册

[3]. Uartlite Driver

[4]. 16550 UART 


欢迎关注亦梦云烟的微信公众号: 亦梦智能计算

 

  • 11
    点赞
  • 120
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值