TinkerBoardR支持两路UART扩展功能,分别对应UART0和UART4。对应的串口引脚接线如下所示
UART (Universal Asynchronous Receiver/Transmitter),以下是linux 4.4 uart驱动支持的一些特性︰
TinkerBoardR的Uart采用的是8250通用驱动,类型是16550A
路径:kernel/drivers/tty/serial/8250/
//make menuconfig配置界面
Device Drivers --->
Character devices --->
Serial drivers --->
[*] 8250/16550 and compatible serial support5
[ ] Support 8250_core.* kernel options (DEPRECATED)
[*] Console on 8250/16550 and compatible serial port //8250串口开启console功能7
[ ] DMA support for 16550 compatible UART controllers
(5) Maximum number of 8250/16550 serial ports //一般填最大串口数
(5) Number of 8250/16550 serial ports to register at runtime //一般填最大串口数
[ ] Extended 8250/16550 serial driver options
[*] Support for Synopsys DesignWare 8250 quirks
首先配置DTS,这里示范的是UART4的配置流程。要注意一点,UART4和SPI1是使用的相同IO口,不要将UART4和SPI1同时使能。否则会出现灵异事件。
//kernel/arch/arm64/boot/dts/rockchip/rk3399pro-tinker_edge_r.dtsi
gpio_init_config {
gpio_init: gpio_init {
rockchip,pins =
<1 9 0 &pcfg_pull_none>,
<1 10 0 &pcfg_pull_none>;
//<1 7 0 &pcfg_pull_none>, //此处为了避免IO口冲突,将这里注释
//<1 8 0 &pcfg_pull_none>;
};
};
&uart4 {
status = "okay";
};
配置完成串口后,硬件接口对应软件上的节点如下所示
UART4:/dev/ttyS4
查看串口信息
rk3399pro:/ # stty -F /dev/ttyS4
speed 9600 baud; line = 0;
hupcl clocal
-brkint ixon -imaxbel
设置串口波特率为115200
rk3399pro:/ # stty -F /dev/ttyS4 speed 115200
9600
rk3399pro:/ # stty -F /dev/ttyS4
speed 115200 baud; line = 0;
hupcl clocal
-brkint ixon -imaxbel
串口数据读写操作
这里使用TTL-USB工具来和PC通信,模拟串口通信过程。
//终端1 用于TinkerBoardR向PC端发送数据
rk3399pro:/ # echo "Message From Tinker Board R" > /dev/ttyS4
PC端显示如下
Message From Tinker Board R
PC端发送信息
Message From My PC
//终端2 用于接收PC端的数据
rk3399pro:/ # cat /dev/ttyS4
Message From My PC
//kernel/arch/arm64/boot/dts/rockchip/rk3399.dtsi
uart0: serial@ff180000 {
compatible = "rockchip,rk3399-uart", "snps,dw-apb-uart";
reg = <0x0 0xff180000 0x0 0x100>;
clocks = <&cru SCLK_UART0>, <&cru PCLK_UART0>;
clock-names = "baudclk", "apb_pclk";
//串口中断传输相关配置
interrupts = <GIC_SPI 99 IRQ_TYPE_LEVEL_HIGH 0>;
reg-shift = <2>;
reg-io-width = <4>;
pinctrl-names = "default";
//其中uart0_cts和uart0_rts是硬件流控脚,这只代表引脚有配置为相应的功能脚,并不代表使能硬件流控。
//使能硬件流控需要从运用层设置下来。需要注意的是,如果使能流控,uart0_cts和uart0_rts必须同时配上。
//如果不需要流控,可以把uart0_cts和uart0_rts去掉。
pinctrl-0 = <&uart0_xfer &uart0_cts &uart0_rts>;
status = "disabled";
};
uart0 {
uart0_xfer: uart0-xfer {
rockchip,pins =
//串口TX RX相关IOMUX寄存器设置
<2 16 RK_FUNC_1 &pcfg_pull_up>,
<2 17 RK_FUNC_1 &pcfg_pull_none>;
};
uart0_cts: uart0-cts {
rockchip,pins =
//串口CTS相关IOMUX寄存器设置
<2 18 RK_FUNC_1 &pcfg_pull_none>;
};
uart0_rts: uart0-rts {
rockchip,pins =
////串口RTS相关IOMUX寄存器设置
<2 19 RK_FUNC_1 &pcfg_pull_none>;
};
};
和中断传输模式相比,使用DMA并不一定能提高传输速度,相反可能略降低传输速度。因为现在CPU的性能都很高,传输瓶颈在外设,而且启动DMA还会消耗额外的资源。但整体上看中断模式会占用更多的CPU资源。只有传输数据量很大时,DMA的使用对CPU负载的减轻效果才会比较明显。关于DMA使用的几点建议:如果外接的设备传输数据量不大,请使用默认的中断模式。如果外接的设备传输数据量较大,可以使用DMA。如果串口没接自动流控脚,可以使用DMA作为FIFO缓冲,防止数据丢失需要使用DMA时需要以下配置,如果没有需要自己手动添加:dma-names = "tx", "rx"; 使能DMA发送和接收dma-names = "!tx", "!rx"; 禁止DMA发送和接收。
dmas = <&dmac_peri 0>, <&dmac_peri 1>;
这里的0和1是外设和DMAC连接的通道号,DMAC通过这个号来识别外设。通过手册查找Req number,如下图
&dmac_peri要根据手册确认外设属于哪个DMAC,来选择,一般DMAC1是dmac_peri,DMAC0是dmac_bus。如下
amba {
compatible = "arm,amba-bus";
#address-cells = <2>;
#size-cells = <2>;
ranges;
dmac_bus: dma-controller@ff6d0000 {
compatible = "arm,pl330", "arm,primecell";
reg = <0x0 0xff6d0000 0x0 0x4000>;
interrupts = <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH 0>,
<GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH 0>;
#dma-cells = <1>;
clocks = <&cru ACLK_DMAC0_PERILP>;
clock-names = "apb_pclk";
peripherals-req-type-burst;
};
dmac_peri: dma-controller@ff6e0000 {
compatible = "arm,pl330", "arm,primecell";
reg = <0x0 0xff6e0000 0x0 0x4000>;
interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH 0>,
<GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH 0>;
#dma-cells = <1>;
clocks = <&cru ACLK_DMAC1_PERILP>;
clock-names = "apb_pclk";
peripherals-req-type-burst;
};
};
有些不需要使用DMA的场景,也可以考虑收发都关闭DMA,如下
dma-names = "!tx", "!rx";
会有以下log
[54696.575402] ttyS0 - failed to request DMA, use interrupt mode
由于DMA通道资源有限,在通道资源紧张的情况下,可以考虑关掉TX的DMA传输,如下
dma-names = "!tx", "rx";
会有以下log:
[498.889713] dw-apb-uart ff0a0000.serial: got rx dma channels onl
在默认情况下,平台默认UART0是支持串口DEBUG打印的。下面可以看一看相关配置
//使能fiq_debugger节点,并且禁止对应的uart节点,这里用uart0作为DEBUG口
&fiq_debugger {
rockchip,serial-id = <0>; //设置串口相关的ID,如果想换不同的串口就需要改这里的ID
rockchip,baudrate = <115200>; //设置串口波特率
pinctrl-0 = <&uart0_xfer>; //指定串口
};
&uart0 {
status = "disabled"; //因为这里uart0作为DEBUG口用,所以这里禁用了
};
//将fiq_debugger功能从设备树中移除
//&fiq_debugger {
// rockchip,serial-id = <0>; //设置串口相关的ID,如果想换不同的串口就需要改这里的ID
// rockchip,baudrate = <115200>; //设置串口波特率
// pinctrl-0 = <&uart0_xfer>; //指定串口
//};
//make menuconfig
Device Drivers --->
Character devices --->
Serial drivers --->
[ ] Console on 8250/16550 and compatible serial port