海思HI35xx平台串口配置方法

前言

串行接口简称串口(通常指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

在海思芯片架构中,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多种波特率可选。

海思UART启用

海思默认只开启UART0单元作为调试功能使用,在实际应用中我们常常需要使用UART1、UART2来与外围设备对接,以实现串口通信。此时我们就需要配置启用UART1、UART2单元,这个过程分为3步:

  1. 确保硬件IO口设计及时钟频率正常
  2. 检查UART单元所使用的IO口复用关系
  3. 配置内核,将UART映射为设备文件

硬件电路部分按要求布线连接,一般没什么问题,这里主要讲解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

海思UART软件操作

与其他的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单元的应用于配置及提供一个简单的串口通信样例实现,样例代码点击此下载。原创不易,转载说明出处。