UART0串口調試過程:1、配置DTS節點 在Z:\rk3399\kernel\arch\arm64\boot\dts\rockchip路徑下打開rk3399.dtsi文件,裡面已經有UART0相關節點定義,如下所示: uart0: serial@ff180000 { compatible = "r ...
UART0串口調試過程:
1、配置DTS節點
在Z:\rk3399\kernel\arch\arm64\boot\dts\rockchip路徑下打開rk3399.dtsi文件,裡面已經有UART0相關節點定義,如下所示:
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";
pinctrl-0 = <&uart0_xfer &uart0_cts &uart0_rts>;
status = "disabled"; // 使用UART0時需將“disabled”改為“okay”
};
由於本次調試使用UART0作為調試外接串口,所以需對UART0進行使能配置,即將上述定義中的最後一句status = "disabled"改為status = "okay",從而完成使能配置,將內核重新編譯,並將kernel.img和resource.img燒寫到開發板中。
2、編寫測試代碼(見附件ursend.c和receive.c文件)
ursend.c用來發送開發板中的數據,主要包括波特率設置函數set_speed(),奇偶校驗設置函數set_parity(),串口數據發送函數serial_send()三個函數;
receive.c用來讀取從PC端發送的數據內容。
3、連接硬體
將開發板uart0的TX、RX、GND(分別對應圖1中引腳18、16、14)引腳分別和主機串口適配器的RX、TX、GND引腳相連,並PC端使用串口調試助手軟體將主機的波特率設置與開發板的波特率一致,同時連接到相應串口,uart0串口所在的GPIO_EXT部分硬體示意圖如下:
圖1 GPIO_EXT示意圖
4、開發板發送數據,PC端讀取串口數據
在Z:\rk3399\external路徑下新建一個文件夾,命名為uart_send,裡面包含兩個文件:ursend.c和Android.mk,執行mm指令後得到可執行文件ursend。將可執行文件ursend傳送到開發板/system/xbin目錄下,在/system/xbin路徑下執行./ursend指令後即完成發送操作,圖2為在開發板上運行數據發送程式ursend。
圖2 開發板發送數據
然後在串口調試助手上就可以看到要接收到的數據內容,如下圖所示:
圖3 PC端數據接收
註:如果開發板發送端串口和主機接收端串口的波特率已經設置成一致,也可以在開發板終端上使用echo Hello, this is a Seria_Port test! > dev/ttyS1指令,向串口發送數據,並同樣能在串口調試助手上顯示接收內容。
5、PC端發送數據,開發板讀取串口數據
在Z:\rk3399\external路徑下新建一個文件夾,命名為uart_receive,裡面包含兩個文件:receive.c和Android.mk,執行mm指令後得到可執行文件receive。將可執行文件receive傳送到開發板/system/xbin目錄下,在/system/xbin路徑下執行./receive指令後即可開始執行數據接收操作,接著在串口調試助手上發送數據(如圖4所示),所發送的內容便會在開發板終端上顯示(如圖5所示)。
圖4 PC端發送數據
圖5 開發板數據接收
代碼區:
1、receive.c
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<termios.h>
#include<errno.h>
#include<string.h>
#define TRUE 1
void setTermios(struct termios * pNewtio, int uBaudRate)
{
memset(pNewtio, 0, sizeof(struct termios));
pNewtio->c_cflag = uBaudRate | CS8 | CREAD | CLOCAL;
pNewtio->c_iflag = IGNPAR;
pNewtio->c_oflag = 0;
pNewtio->c_lflag = 0;
pNewtio->c_cc[VINTR] = 0;
pNewtio->c_cc[VQUIT] = 0;
pNewtio->c_cc[VERASE] = 0;
pNewtio->c_cc[VKILL] = 0;
pNewtio->c_cc[VEOF] = 4;
pNewtio->c_cc[VTIME] = 5;
pNewtio->c_cc[VMIN] = 0;
pNewtio->c_cc[VSWTC] = 0;
pNewtio->c_cc[VSTART] = 0;
pNewtio->c_cc[VSTOP] = 0;
pNewtio->c_cc[VSUSP] = 0;
pNewtio->c_cc[VEOL] = 0;
pNewtio->c_cc[VREPRINT] = 0;
pNewtio->c_cc[VDISCARD] = 0;
pNewtio->c_cc[VWERASE] = 0;
pNewtio->c_cc[VLNEXT] = 0;
pNewtio->c_cc[VEOL2] = 0;
}
#define BUFSIZE 512
int main(int argc, char **argv)
{
int fd;
int nread;
int Rlength = BUFSIZE;
int Length = 0;
char buff[BUFSIZE] = {0};
char cMsg[BUFSIZE] = {0};
char *pch = buff;
int i = 0;
struct termios oldtio, newtio;
struct timeval tv;
char *dev =(char *)"/dev/ttyS0";
fd_set rfds;
if ((fd = open(dev, O_RDWR | O_NOCTTY))<0)
{
printf("err: can't open serial port!\n");
return -1;
}
tcgetattr(fd, &oldtio);
setTermios(&newtio, B9600);
tcflush(fd, TCIFLUSH);
tcsetattr(fd, TCSANOW, &newtio);
tv.tv_sec=3;
tv.tv_usec=0;
while (TRUE)
{
FD_ZERO(&rfds);
FD_SET(fd, &rfds);
if (select(1+fd, &rfds, NULL, NULL, &tv)>0)
{
printf("wait.......\n");
if (FD_ISSET(fd, &rfds))
{
nread=read(fd, pch, BUFSIZE-Length);
for(i=Length;i<nread+Length;i++)
{
printf("%c ", buff[i]);
}
Length += nread;
if(Length >= BUFSIZE)
{
printf("######Length<%d> is too long.\n", Length);
return -1;
}
pch += nread;
}
}
else
{
printf("Uart msg is :\n");
printf("%s\n", buff);
memset(buff, 0, BUFSIZE);
pch = buff;
Length = 0;
tv.tv_sec=3;
tv.tv_usec=0;
sleep(1);
}
}
tcsetattr(fd, TCSANOW, &oldtio);
close(fd);
}
2、ursend.c
#include <unistd.h>
#include <stdio.h>
#include <termios.h>
#include <fcntl.h>
#include <string.h>
#include <time.h>
#define max_buffer_size 100
int speed_arr[] = { B115200, B57600, B38400, B19200, B9600, B4800, B2400, B1200, B300,
B115200, B57600, B38400, B19200, B9600, B4800, B2400, B1200, B300, };
int name_arr[] = {115200, 57600, 38400, 19200, 9600, 4800, 2400, 1200, 300,
115200, 57600, 38400, 19200, 9600, 4800, 2400, 1200, 300, };
/*-----------------------------------------------------------------------------
函數名: set_speed
參數: int fd ,int speed
返回值: void
描述: 設置fd 表述符的串口波特率
*-----------------------------------------------------------------------------*/
void set_speed(int fd ,int speed)
{
struct termios opt;
int i;
int status;
tcgetattr(fd,&opt);
for(i = 0;i<sizeof(speed_arr)/sizeof(int);i++)
{
if(speed == name_arr[i])
{
tcflush(fd,TCIOFLUSH);
cfsetispeed(&opt,speed_arr[i]);
cfsetospeed(&opt,speed_arr[i]);
status = tcsetattr(fd,TCSANOW,&opt);
if(status != 0)
perror("tcsetattr fd:");
return ;
}
tcflush(fd,TCIOFLUSH);
}
}
/*-----------------------------------------------------------------------------
函數名: set_parity
參數: int fd
返回值: int
描述: 設置fd 表述符的奇偶校驗
*-----------------------------------------------------------------------------*/
int set_parity(int fd)
{
struct termios opt;
if(tcgetattr(fd,&opt) != 0)
{
perror("Get opt in parity error:");
return -1;
}
opt.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP
| INLCR | IGNCR | ICRNL | IXON);
opt.c_oflag &= ~OPOST;
opt.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
opt.c_cflag &= ~(CSIZE | PARENB);
opt.c_cflag |= CS8;
tcflush(fd,TCIFLUSH); \
if(tcsetattr(fd,TCSANOW,&opt) != 0)
{
perror("set attr parity error:");
return -1;
}
return 0;
}
/*-----------------------------------------------------------------------------
函數名: serial_init
參數: char *dev_path,int speed,int is_block
返回值: 初始化成功返回打開的文件描述符
描述: 串口初始化,根據串口文件路徑名,串口的速度,和串口是否阻塞,block為1表示阻塞
*-----------------------------------------------------------------------------*/
int serial_init(char *dev_path,int speed,int is_block)
{
int fd;
int flag;
flag = 0;
flag |= O_RDWR;
if(is_block == 0)
flag |=O_NONBLOCK;
fd = open(dev_path,flag);
if(fd < 0)
{
perror("Open device file err:");
close(fd);
return -1;
}
set_speed(fd,speed);
if(set_parity(fd) != 0)
{
perror("set parity error:");
close(fd);
return -1;
}
return fd;
}
/*-----------------------------------------------------------------------------
函數名: serial_send
參數: int fd,char *str,unsigned int len
返回值: 發送成功返回發送長度,否則返回小於0的值
描述: 向fd描述符的串口發送數據,長度為len,內容為str
*-----------------------------------------------------------------------------*/
int serial_send(int fd,char *str,unsigned int len)
{
int ret;
if(len > strlen(str))
len = strlen(str);
printf("str: %s \n", str);
printf("len: %d \n", len);
ret = write(fd,str,len);
printf("ret: %d \n", ret);
if(ret < 0)
{
perror("serial send err:");
return -1;
}
return ret;
}
int main()
{
int fd;
int ret;
char str[]="Hello, this is a Seria_Port test!";
char buf[100];
printf("buf is: %d \n", sizeof(buf));
fd = serial_init("/dev/ttyS0",9600,1);
if(fd < 0)
{
perror("serial init err:");
return -1;
}
ret = serial_send(fd,str,50);
printf("send %d bytes!\n",ret);
close(fd);
return 0;
}