串行接口简称串口(通常指COM接口),是采用串行通信方式的扩展接口,其特点是通信线路简单,只要一对传输线就可以实现双向通信,从而大大降低了成本,但传送速度一般,数据传输率为115kbps~230kbps。异步串行UART(Universal Asynchronous Receiver/Transmitter),即通用异步接收/发送。UART是一款并行输入转换为串行输出的芯片(如MAX232、MAX485等),它们通常集成在主板上。UART芯片的另一功能是将TTL逻辑电平进行转换,属于硬件逻辑实现,不需要软件的干涉。UART常用的接口标准有RS-232、RS-485,其中RS-232的传送距离最大为约15米,最高速率为20kb/s;而RS-485的最大传输距离约为1219米,最大传输速率为10Mb/s。这两种接口标准的传输速率与传输速度差异这么大,主要是因对逻辑电平的规定以及信号传输抗干扰能力不一样导致的,在实际应用中根据传输距离及速度的不同需求选用即可。
在海思芯片架构中,UART主要是将来自外围设备的数据进行串并转换后传入内部总线,以及将数据进行并串转换后输出到外围设备,从而实现两芯片之间的通信。Hi35XX提供了3个UART单元:
UART0:4线UART,可用于调试、报警和云台控制。
UART1:2线UART,可用于调试、报警。
UART3:2线UART,可用于调试、报警。
UART配置:
1、支持数据位和停止位的位宽可编程。数据位可通过编程设定为5/6/7/8比特,停止位可通过过编程设定为1bit或2bit。
2、支持奇、偶校验方式或无校验。
3、支持速率可编程,支持9600bit/s、14400bit/s、19200bit/s、38400bit/s、57600bit/s、76800bit/s、115200bit/s、230400bit/s、460800bit/s多种波特率可选。
海思默认只开启UART0单元作为调试功能使用,在实际应用中我们常常需要使用UART1、UART2来与外围设备对接,以实现串口通信。此时我们就需要配置启用UART1、UART2单元,这个过程分为3步:
硬件电路部分按要求布线连接,一般没什么问题,这里主要讲解IO口的复用关系配置及内核配置。
上表是海思芯片IO口复用关系表,由此可知大多数IO口的默认功能都不是作为UART单元来使用,故需要配置它们的复用关系,可以采用在系统启动脚本里添加如下命令来配置IO口的复用关系:
himm 0x120F00F8 0x1
himm 0x120F00FC 0x1
……
接下来是配置内核,以实现UART单元映射为linux下的设备文件,这里主要涉及就是海思的设备树更改,相对简单。进入SDK目录\osdrv\opensource\kernel\linux-3.18.y\arch\arm\boot\dts,找到以下设备树文件。
修改以下内容:
至此海思UART单元配置完成,重新编译内核,并将内核烧录运行。如果没有什么异常,在设备上的/dev/目录下会有以下3个设备文件出现,接下来软件对此设备文件进行编程操作即可。
/dev/ttyAMA0
/dev/ttyAMA1
/dev/ttyAMA2
与其他的linux设备操作类似,通过open、fcntl、close来实现与UART单元进行操作。在串口设备中,比较特殊的就是串口的波特率、奇偶校验、数据位以及停止位的设置了,只有将它们正确设置了才能进行串口通讯。下面是一个样例程序:
* *Function: HI_Serial_Open(int fd,char* ComDevice) *Param: fd:file descirbe handle Serial Device: /dev/ttyAMA1 /dev/ttyAMA2 *Output: Ok or Fail */ int HI_Serial_Open(char* HiSerDevice) { int fd; fd = open(HiSerDevice, O_RDWR|O_NOCTTY|O_NDELAY); if (HI_FALSE == fd) { perror("HiSerial Can't Open Serial HiSerDevice"); return(HI_FALSE); } //恢复串口为阻塞状态 if(fcntl(fd, F_SETFL, 0) < 0) { debugpri("fcntl failed!\n"); return(HI_FALSE); } else { debugpri("fcntl=%d\n",fcntl(fd, F_SETFL,0)); } //测试是否为终端设备 if(0 == isatty(STDIN_FILENO)) { debugpri("standard input is not a terminal device\n"); return(HI_FALSE); } else { debugpri("isatty success!\n"); } printf("fd->open=%d\n",fd); return fd; } /* *Function: HI_Serial_Close(int fd) *Param: fd:file descirbe handle *Output: Null */ void HI_Serial_Close(int fd) { if(fd > 0) close(fd); return; } /* *Function: HI_Serial_Set(int fd,int speed,int flow_ctrl,int databits,int stopbits,int parity) *Param1: fd: file descirbe handle *Param2: speed: select the Serial speed.115200,19200,9600... *Param3: flow_ctrl: if use flow control *Param4: databits: data bit select *Param5: stopbits: stopbits select *Param5: parity: partiy select *Output: Ok or Fail */ int HI_Serial_Set(int fd,int speed,int flow_ctrl,int databits,int stopbits,int parity) { /******* ******** ********/ } int HI_Serial_Usage(void) { printf("Usage:\n"); printf("\tmyhicom [-d] <HiSerialDevice> [-s] get netdeviece info [-rw] read or wite select\n"); printf("\tmyhicom [-h] for more usage\n"); printf("\tmyhicom [-v] the verson of the sofware\n"); printf("\tExample:\n\tmyhicom -d /dev/ttyAMA1 -s 115200 -w HiSerial:HelloWorld\n"); } /* **Function: main() **usage: read or write com **parameter: help */ int main ( int argc, char *argv[] ) { int cmd; int len; //extern char *optarg; //extern int optind, opterr, optopt; char HiSerialDev[32]="/dev/ttyAMA1"; char sendbuf[1024]={0}; char recvbuf[1024]={0}; int SerialSpeed = 115200; Hi_init_signals(); if(argc == 1) { HI_Serial_Usage(); exit(0); } else { while ((cmd = getopt(argc, argv, ":d:s:rw:hv")) != -1) { switch (cmd) { case 'h': HI_Serial_Usage(); break; case 'v': printf("myHicom --Verson V1.0.0\n"); break; case 'd': //printf("catch -d %s \n",optarg); memset(HiSerialDev,0,sizeof(HiSerialDev)); sprintf(HiSerialDev,"%s",optarg); printf("myHicom HiSerialDev %s\n",optarg); break; case 's': SerialSpeed = atoi(optarg); printf("myHicom speed %d\n",SerialSpeed); break; case 'r': debugpri("myHicom read\n"); HiSerfd = HI_Serial_Open(HiSerialDev); HI_Serial_Init(HiSerfd,SerialSpeed,0,8,1,'N'); while(1) { len = HI_Serial_Recv(HiSerfd, recvbuf,sizeof(recvbuf)); if(len > 0) { recvbuf[len] = '\0'; printf("Hiserial receive data: %s\n",recvbuf); memset(recvbuf,0,sizeof(recvbuf)); //break; } else { debugpri("Hiserial haven't data receive \n"); } sleep(2); }; break; case 'w': debugpri("myHicom write %s\n",optarg); HiSerfd = HI_Serial_Open(HiSerialDev); printf("fd = %d device = %s speed = %d\n",HiSerfd,HiSerialDev,SerialSpeed); HI_Serial_Init(HiSerfd,SerialSpeed,0,8,1,'N'); sprintf(sendbuf,"%s\n",optarg); HI_Serial_Send(HiSerfd, sendbuf, strlen(sendbuf)+1); if(HiSerfd > 0) HI_Serial_Close(HiSerfd); break; case ':': printf ("option: -%c missing argument. -h for help.\n",(char)optopt); break; case '?': printf("Unknown option: -%c\n",(char)optopt); break; default: exit(0); } } } return 0; }
串口通信加强了主控芯片与外围设备之间的联系,通过RS485接口可以实现远距离通信。在海思平台开发中,可以实现球机平台远程控制、红外报警等智能监控应用。本文主要是总结海思UART单元的应用于配置及提供一个简单的串口通信样例实现,样例代码点击此下载。原创不易,转载说明出处。