一、調試環(huán)境
平臺:rk3568
kernel: 4.19.232
SDK: rk_android11.0_sdk
Board: rk3568-evb1-ddr4-v10
二、 rk3568 uart控制器
1. 特性:
-?UART控制器通道:UART0~UART8????【datasheet好像寫的有問題】
-?包含2組64字節(jié)的?FIFO,用于接收和傳輸??
-?支持流控
-?支持速率?115.2Kbps,?460.8Kbps,?921.6Kbps,?1.5Mbps,?3Mbps,?4Mbps
-?支持5、6、7、8?bits數(shù)據(jù)位。
-?支持1、1.5、2?bits停止位。
-?支持奇校驗和偶校驗。
-?支持基于中斷/DMA?模式
2. UART控制器架構
APB INTERFACE
處理器通過APB接口訪問UART的數(shù)據(jù),做控制,以及狀態(tài)信息。
UART支持8、16和32位的APB數(shù)據(jù)總線寬度。
Register block
負責UART的主要功能,包括控制、狀態(tài)和中斷產(chǎn)生。
Modem Synchronization block
同步modem輸入信號.
FIFO block
負責FIFO控制和存儲或向發(fā)送信號以控制外部RAM。
Baud Clock Generator
收發(fā)比特率設置。
Serial Transmitter
數(shù)據(jù)發(fā)送模塊。
Serial Receiver
數(shù)據(jù)接收模塊。
3. 控制器驅動
瑞芯微提供sdk中已經(jīng)提供了8250uart驅動。
以下為主要驅動文件:
drivers/tty/serial/8250/8250_core.c?????#?8250串口驅動核心
drivers/tty/serial/8250/8250_dw.c???????#?Synopsis?DesignWare?8250串口驅動
drivers/tty/serial/8250/8250_dma.c?????#?8250串口DMA驅動
drivers/tty/serial/8250/8250_port.c??????#?8250串口端口操作
drivers/tty/serial/8250/8250_early.c?????#?8250串口early?console驅動
4. 設備樹:
普通串口設備將會根據(jù)dts中的aliase來對串口進行編號,對應注冊成ttySx設備。
dts中的aliases如下:
?aliases?{
serial0?=?&uart0;
serial1?=?&uart1;
serial2?=?&uart2;
serial3?=?&uart3;
......
@kernelarcharm64bootdtsrockchiprk3568.dtsi
?uart6:?serial@fe6a0000?{
??compatible?=?"rockchip,rk3568-uart",?"snps,dw-apb-uart";
??reg?=?<0x0?0xfe6a0000?0x0?0x100>;
??interrupts?=?<GIC_SPI?122?IRQ_TYPE_LEVEL_HIGH>;
??clocks?=?<&cru?SCLK_UART6>,?<&cru?PCLK_UART6>;
??clock-names?=?"baudclk",?"apb_pclk";
??reg-shift?=?<2>;
??reg-io-width?=?<4>;
??dmas?=?<&dmac0?12>,?<&dmac0?13>;
??pinctrl-names?=?"default";
??pinctrl-0?=?<&uart6m0_xfer>;
??status?=?"disabled";
?};
UART的板級dts配置只有以下參數(shù)允許修改:
-
- dma-names:
-
- "tx" 打開tx dma
-
- "rx" 打開rx dma
-
- "!tx" 關閉tx dma
-
- "!rx" 關閉rx dmapinctrl-0:
-
- &uart1m0_xfer 配置tx和rx引腳為iomux group 0
-
- &uart1m1_xfer 配置tx和rx引腳為iomux group 1
-
- &uart1m0_ctsn和&uart1m0_rtsn 配置硬件自動流控cts和rts引腳為iomux group 0
-
- &uart1m1_ctsn和&uart1m1_rtsn 配置硬件自動流控cts和rts引腳為iomux group 1status:
-
- "okay" 打開
- "disabled" 關閉
引腳說明在下面定義:
以UART6為例:
@kernelarcharm64bootdtsrockchiprk3568-pinctrl.dtsi
?uart6?{
??/omit-if-no-ref/
??uart6m0_xfer:?uart6m0-xfer?{
???rockchip,pins?=
????/*?uart6_rxm0?*/
????<2?RK_PA3?3?&pcfg_pull_up>,
????/*?uart6_txm0?*/
????<2?RK_PA4?3?&pcfg_pull_up>;
??};
??/omit-if-no-ref/
??uart6m0_ctsn:?uart6m0-ctsn?{
???rockchip,pins?=
????/*?uart6m0_ctsn?*/
????<2?RK_PC0?3?&pcfg_pull_none>;
??};
??/omit-if-no-ref/
??uart6m0_rtsn:?uart6m0-rtsn?{
???rockchip,pins?=
????/*?uart6m0_rtsn?*/
????<2?RK_PB7?3?&pcfg_pull_none>;
??};
??/omit-if-no-ref/
??uart6m1_xfer:?uart6m1-xfer?{
???rockchip,pins?=
????/*?uart6_rxm1?*/
????<1?RK_PD6?3?&pcfg_pull_up>,
????/*?uart6_txm1?*/
????<1?RK_PD5?3?&pcfg_pull_up>;
??};
?};
5. 使用硬件自動流控
UART使用硬件自動流控時,需要確保UART驅動使能硬件自動流控功能,且在dts中已經(jīng)切換cts和rts流控引腳的iomux。
建議在高波特率(1.5M波特率及以上)、大數(shù)據(jù)量的場景下都使用硬件自動流控,即使用四線UART。
6. 使用串口喚醒系統(tǒng)
串口喚醒系統(tǒng)功能是在系統(tǒng)待機時串口保持打開,并且把串口中斷設置為喚醒源。使用時需要在dts中增
加以下參數(shù):
?&uart1?{
??wakeup-source;
?};
注意,串口喚醒系統(tǒng)需要同時修改trust固件,請聯(lián)系Rockchip以獲取支持。
三、 移植
1. 修改設備樹
sdk中UART默認并沒有打開,所以我們只需要修改設備樹就可以了。
下面以uart6為例,帶流控:
/arch/arm64/boot/dts/rockchip/rk3568-evb1-ddr4-v10.dtsi
&uart6{
???????status?=?"okay";
???????pinctrl-names?=?"default";
???????pinctrl-0?=?<&uart6m1_xfer?>;
};
注意:
“
引腳選擇有兩種配置: m0、m1;
編寫設備樹之前,查看電路圖先確認,
公板是m1。
只有m0支持流控,如果需要支持設置 pinctrl-0:
pinctrl-0 = <&uart6m0_xfer &uart6m0_ctsn &uart6m0_rtsn>;
”
重新編譯燒錄boot.img即可。
查看設備文件
rk3568_r:/?#?ls?/dev/ttyS*
/dev/ttyS6??/dev/ttyS8
其中ttyS8是給藍牙使用。
2. 引腳復用問題:uart6與gmac0沖突
uart6引腳與以太網(wǎng)口Gmac0會有沖突:
@kernelarcharm64bootdtsrockchiprk3568-pinctrl.dtsi
?gmac0?{
??/omit-if-no-ref/
??gmac0_miim:?gmac0-miim?{
???rockchip,pins?=
????/*?gmac0_mdc?*/
????<2?RK_PC3?2?&pcfg_pull_none>,
????/*?gmac0_mdio?*/
????<2?RK_PC4?2?&pcfg_pull_none>;
??};
??…………………………
??/omit-if-no-ref/
??gmac0_rgmii_bus:?gmac0-rgmii-bus?{
???rockchip,pins?=
????/*?gmac0_rxd2?*/
????<2?RK_PA3?2?&pcfg_pull_none>,
????/*?gmac0_rxd3?*/
????<2?RK_PA4?2?&pcfg_pull_none>,
????/*?gmac0_txd2?*/
????<2?RK_PA6?2?&pcfg_pull_none_drv_level_2>,
????/*?gmac0_txd3?*/
????<2?RK_PA7?2?&pcfg_pull_none_drv_level_2>;
??};
?};
只需要禁用gmac0即可
/arch/arm64/boot/dts/rockchip/rk3568-evb1-ddr4-v10.dtsi
&gmac0?{
?………………
?phy-handle?=?<&rgmii_phy0>;
?status?=?"disable";
};
3. 通過寄存器,查看引腳復用配置情況
uart6使用到的引腳如下:
請?zhí)砑訄D片描述
1) GRF_GPIO1D_IOMUX_H
Address: Operational Base + offset (0x001C)
2) GRF_GPIO2A_IOMUX_L
Address: Operational Base + offset (0x0020)
3) GRF_GPIO2A_IOMUX_H
Address: Operational Base + offset (0x0024)
4) GRF_GPIO2B_IOMUX_H
Address: Operational Base + offset (0x002C)
5) GRF_GPIO2C_IOMUX_L
Address: Operational Base + offset (0x0030)
uart6寄存器配置對應位位置如下圖所示:,
我們只設置m1引腳為uart6的收發(fā)引腳,m0引腳未設置
所以只有寄存器 0xFDC60000+0x1c 的 ?bit[11:4]為 33
四、測試
公板預留了UART2~UART7的接口(4根線),
一口君不會焊接線,所以直接找的硬件工程師把線連好,
我只負責測試。
板子上的測試程序,瑞芯微官方已經(jīng)提供了: ts_uart.uart
該工具獲取,見文章底部。
1. 移植ts_uart.uart
adb?root
adb?remount
adb?push?ts_uart.uart?/bin
adb?push?send_0x55?/bin
adb?push?send_00_ff?/bin
2. ts_uart.uart實用
1) 查看ts_uart.uart幫助信息:
rk3568_r:/?#?ts_uart.uart
?Use?the?following?format?to?run?the?HS-UART?TEST?PROGRAM
?ts_uart?v1.1
?For?sending?data:
?./ts_uart?<tx_rx(s/r)>?<file_name>?<baudrate>?<flow_control(0/1)>?<max_delay(0-100)>?<random_size(0/1)>
?tx_rx?:?send?data?from?file?(s)?or?receive?data?(r)?to?put?in?file
?file_name?:?file?name?to?send?data?from?or?place?data?in
?baudrate?:?baud?rate?used?for?TX/RX
?flow_control?:?enables?(1)?or?disables?(0)?Hardware?flow?control?using?RTS/CTS?lines
?max_delay?:?defines?delay?in?seconds?between?each?data?burst?when?sending.?Choose?0?for?continuous?stream.
?random_size?:?enables?(1)?or?disables?(0)?random?size?data?bursts?when?sending.?Choose?0?for?max?size.
?max_delay?and?random_size?are?useful?for?sleep/wakeup?over?UART?testing.?ONLY?meaningful?when?sending?data
?Examples:
?Sending?data?(no?delays)
?ts_uart?s?init.rc?1500000?0?0?0?/dev/ttyS0
?loop?back?mode:
?ts_uart?m?init.rc?1500000?0?0?0?/dev/ttyS0
?receive,?data?must?be?0x55
?ts_uart?r?init.rc?1500000?0?0?0?/dev/ttyS0
2) 非流控read:
ts_uart.uart?r?init.rc?115200?0?0?0??/dev/ttyS6
3) 流控read:
ts_uart.uart?r?init.rc?115200?1?0?0??/dev/ttyS6
4) 非流控write:
ts_uart.uart?s?/data/send_0x55.0x55?115200?0?0?0?/dev/ttyS6
5) 流控write:
ts_uart.uart?s?/data/send_0x55.0x55?115200?1?0?0?/dev/ttyS6
五、編寫自己的測試程序
下面是一口君自己編寫的測試程序,可以實現(xiàn)簡單的數(shù)據(jù)收發(fā),
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
#include<termios.h>
#include<string.h>
int?set_opt(int?fd,int?nSpeed,?int?nBits,?char?nEvent,?int?nStop)
{
?struct?termios?newtio,oldtio;
?if??(?tcgetattr(?fd,&oldtio)??!=??0)?
?{
??perror("SetupSerial?1");
??return?-1;
?}
?bzero(?&newtio,?sizeof(?newtio?)?);
?newtio.c_cflag??|=??CLOCAL?|?CREAD;
?newtio.c_cflag?&=?~CSIZE;
?switch(?nBits?)
?{
?case?7:
??newtio.c_cflag?|=?CS7;
??break;
?case?8:
??newtio.c_cflag?|=?CS8;
??break;
?}
?switch(?nEvent?)
?{
?case?'O':
??newtio.c_cflag?|=?PARENB;
??newtio.c_cflag?|=?PARODD;
??newtio.c_iflag?|=?(INPCK?|?ISTRIP);
??break;
?case?'E':?
??newtio.c_iflag?|=?(INPCK?|?ISTRIP);
??newtio.c_cflag?|=?PARENB;
??newtio.c_cflag?&=?~PARODD;
??break;
?case?'N':??
??newtio.c_cflag?&=?~PARENB;
??break;
?}
?switch(?nSpeed?)
?{
?case?2400:
??cfsetispeed(&newtio,?B2400);
??cfsetospeed(&newtio,?B2400);
??break;
?case?4800:
??cfsetispeed(&newtio,?B4800);
??cfsetospeed(&newtio,?B4800);
??break;
?case?9600:
??cfsetispeed(&newtio,?B9600);
??cfsetospeed(&newtio,?B9600);
??break;
?case?115200:
??cfsetispeed(&newtio,?B115200);
??cfsetospeed(&newtio,?B115200);
??break;
?case?460800:
??cfsetispeed(&newtio,?B460800);
??cfsetospeed(&newtio,?B460800);
??break;
?default:
??cfsetispeed(&newtio,?B9600);
??cfsetospeed(&newtio,?B9600);
??break;
?}
?if(?nStop?==?1?)
??newtio.c_cflag?&=??~CSTOPB;
?else?if?(?nStop?==?2?)
??newtio.c_cflag?|=??CSTOPB;
?newtio.c_cc[VTIME]??=?0;
?newtio.c_cc[VMIN]?=?0;
?tcflush(fd,TCIFLUSH);
?if((tcsetattr(fd,TCSANOW,&newtio))!=0)
?{
??perror("com?set?error");
??return?-1;
?}
//?printf("set?done!nr");
?return?0;
}
int?main(void)
{
?int?fd1;
?char??data[10]?=?"yikoupeng";
?char?buf[100]={0};
?fd1?=?open(?"/dev/ttyS6",?O_RDWR);
?if?(fd1?==?-1)
??exit(1);
?nset?=?set_opt(fd1,?115200,?8,?'N',?1);
?if?(nset?==?-1)
?{
??exit(1);?
?}
????printf("write?start!n");?
?write(fd1,data,strlen(data));?
????read(fd1,buf,sizeof(buf));
????printf("rcv:%sn",buf);
?close(fd1);
?return?0;
}
工具ts_uart.uart s獲取,公眾號【一口Linux】后臺回復:rxw