转载于:www.acodelife.cn
概述
因项目需要,需要使用的HI3521D的串口1和串口2,并把串口2作为485使用。
海思UART启用
因为海思默认启用uart0 ,作为调试串口。所以我们需要说明的是uart1和uart2。
uart1:
我们进入/dev目录下,发现有uart1存在,编写代码的时候,open /dev/ttyARM1,发现报错No such device or address。我猜,肯定是内核问题,所以内核需要配置,这个稍后再讲。 使用uart1 ,我们需要做些什么? 查看电路图:
连接uart1的引脚,有两个功能,所以,我们先要复用引脚。
在Hi3521DV100_PINOUT_CN.xlsx文件中,找到GPIO6_5和GPIO6_7,如图
我们可以在启动文件中,通过如下方式复用GPIO6_5和GPIO6_7使为uart1引脚使用。
himm 0x120F00F8 0x1
himm 0x120F00FC 0x1
第二步:就是我们将的配置内核了。以实现UART单元映射为linux下的设备文件,这里主要涉及就是海思的设备树更改。
在osdrv/opensource/kernel/linux-3.18y/arch/arm/boot/dts目录下,找到如下文件
打开hi3521d.dtsi文件,修改文件。
aliases {
fmc = &fmc;
serial0 = &uart0;
serial1 = &uart1;
spi0 = &spi_bus0;
};
uart1: uart@121090000 {
compatible = “arm,pl011”, “arm,primecell”;
reg = <0x12090000 0x1000>;
interrupts = <0 7 4>;
clocks = <&clock HI3521D_UART1_CLK>;
clock-names = “apb_pclk”;
status = “okay”;
};
保存,然后编译内核,烧写内核,就ok啦。
uart2
对呀uart2,完全就是按照uart1的方式操作,略过。
串口编程
uart1
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <errno.h>
#include <math.h>
#include <time.h>
#include <unistd.h>
#include <termios.h>
int serial_fd = 0 ;
#define RECE_BUFF_LEN 3000
char serialBuff[RECE_BUFF_LEN] ;
int open_port(int fd,int comport)
{
long vdisable;
fd = open("/dev/ttyAMA2", O_RDWR|O_NOCTTY|O_NDELAY);
if (-1 == fd)
{
perror("Can't Open Serial Port");
return(-1);
}else
{
printf("%d\n" , fd) ;
}
return fd;
}
int set_speed(int fd , int speed)
{
int birdrate_arr[] = {B115200, B38400, B19200, B9600, B4800,
B2400, B1200, B300, B38400, B19200, B9600, B4800, B2400, B1200, B300};
int name_arr[] = {115200, 38400, 19200, 9600, 4800, 2400 ,
1200, 300, 38400, 19200, 9600, 4800, 2400, 1200, 300};
struct termios oldtio;
if (tcgetattr( fd,&oldtio) != 0) {
perror("SetupSerial 1");
return -1;
}
int i = -1 ;
for(i = 0 ; i < sizeof(name_arr)/sizeof(name_arr[0]) ; i++)
{
if(speed == name_arr[i])
break ;
}
tcflush(fd,TCIFLUSH);
cfsetispeed(&oldtio, birdrate_arr[i]);
cfsetospeed(&oldtio, birdrate_arr[i]);
if((tcsetattr(fd,TCSANOW,&oldtio))!=0)
{
perror("com set error");
return -1;
}
tcflush(fd,TCIFLUSH);
return 0 ;
}
int set_Parity(int fd, int databits, int stopbits, int parity)
{
struct termios oldtio;
if (tcgetattr( fd,&oldtio) != 0)
{
perror(“SetupSerial 1”);
return -1;
}
oldtio.c_cflag |= (CLOCAL | CREAD) ;
switch(databits) //ÉèÖÃÊýŸÝλ
{
case 7:
oldtio.c_cflag &= ~CSIZE ;
oldtio.c_cflag |= CS7 ;
break ;
case 8:
oldtio.c_cflag &= ~CSIZE ;
oldtio.c_cflag |= CS8 ;
break ;
default:
perror(“Unsupported data size.”);
return -1 ;
}
switch(parity)
{
case ‘n’:
case ‘N’:
oldtio.c_cflag &= ~PARENB ;
oldtio.c_iflag &= ~INPCK ;
break ;
case ‘o’:
case ‘O’:
oldtio.c_cflag |= PARENB ;
oldtio.c_cflag |= PARODD ;
oldtio.c_iflag |= INPCK ;
break ;
case ‘s’:
case ‘S’:
oldtio.c_cflag &= ~PARENB ;
oldtio.c_cflag &= ~CSTOPB ;
oldtio.c_iflag |= INPCK ;
break ;
case ‘e’:
case ‘E’:
oldtio.c_cflag |= PARENB;
oldtio.c_cflag &= ~ PARODD ;
oldtio.c_iflag |= INPCK ;
break ;
default :
perror(“Unsupported parity.”);
return -1 ;
}
switch(stopbits)
{
case 1:
oldtio.c_cflag &= ~CSTOPB ;
break ;
case 2:
oldtio.c_cflag |= CSTOPB ;
break ;
default :
perror("Unsupported stopbits.");
return -1 ;
}
oldtio.c_cflag |= (CLOCAL|CREAD) ;
oldtio.c_iflag &= ~(ICANON|ECHO|ECHOE|ISIG) ;
oldtio.c_oflag &= ~OPOST ;
oldtio.c_oflag &= ~(ONLCR|OCRNL) ;
oldtio.c_iflag &= (ICRNL | INLCR) ;
oldtio.c_iflag &= ~(IXON|IXOFF|IXANY) ;
tcflush(fd,TCIFLUSH);
oldtio.c_cc[VTIME] = 0 ;
oldtio.c_cc[VTIME] = 0 ;
/*raw model*/
oldtio.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
oldtio.c_oflag &= ~OPOST;
oldtio.c_iflag &= ~(INLCR|IGNCR|ICRNL);
oldtio.c_iflag &= ~(ONLCR|OCRNL);
oldtio.c_oflag &= ~(INLCR|IGNCR|ICRNL);
oldtio.c_oflag &= ~(ONLCR|OCRNL);
if((tcsetattr(fd,TCSANOW,&oldtio))!=0)
{
perror("com set error");
return -1;
}
return 0 ;
}
int init_serial_port()
{
int serial_fd ;
if((serial_fd=open_port(serial_fd,1))<0){//Žò¿ªŽ®¿Ú
perror(“open_port error”);
return 0;
}
int speed = 9600; //115200 ;
if(set_speed(serial_fd,speed) < 0)
{
perror("set speed error");
return 0 ;
}
int databits = 8 ;
int stopBits = 1 ;
if(set_Parity(serial_fd,databits , stopBits , 'N') < 0)
{
perror("set_Parity error");
return 0 ;
}
return serial_fd ;
}
void serial_port_pthread()
{
while(1)
{
usleep(400) ;
if(serial_fd <= 0)
{
printf("get_serial_fd() <= 0\n") ;
continue ;
}
{
char buff[RECE_BUFF_LEN] ;
int ret = read(serial_fd , buff , RECE_BUFF_LEN) ;
if(ret <= 0)
{
//printf("serial read error!\n") ;
continue ;
}else
{
int i = 0 ;
for( i = 0 ; i < ret ; i++)
printf("%x,", buff[i]) ;
printf(" end!\n") ;
}
}
}
}
int main(void)
{
printf(“Hello World!\n”);
if((serial_fd = init_serial_port()) ==-1)
printf("init_serial_port error!\n") ;
serial_port_pthread();
return 0;
}
uart2串口编程
对于uart2,我们是用来作为RS485的,所以,需要有一个使能信号。如图:
RE脚连接到海思是GPIO0_7引脚,图就不截了。
所以,我们需要设置GPIO0_7为IO输出,配置步骤如下:
通用输入输出
每个管脚可以配置为输入或者输出,具体步骤如下:
步骤 1. 参考“管脚复用控制寄存器”配置管脚的相应位,使能需要使用的GPIO 管脚功能。
步骤 2. 配置寄存器GPIO_DIR,选择GPIO 是作为输入还是输出。
步骤 3. 当配置成输入管脚时,读取GPIO_DATA 寄存器可查看输入信号值;当配置成输出管
脚时,通过向GPIO_DATA 寄存器写入输出值可控制GPIO管脚输出电平。
配置GPIO_DIR
GPIO0基地址(0x1215_0000)+GPIO_DIR偏移地址(0x400),设置为何值?
从图可以看出,我们设置的是GPIO0_7的DIR,所以第8位设置为1,即himm 0x12150400 0x80
配置GPIO_DATA ,因为DATA的配置跟DIR差不多,所以不详细的说。GPIO_DATA 地址:0x121503FC
所以,uart2的编程跟uart1编程区别就在,需要发送数据的时候,DATA拉高,读取数据的时候DATA拉低。
system(“himm 0x121503fc 0xff”);
usleep(250);
write(serial_fd , buff , ret) ;
system(“himm 0x121503fc 0x7f”);
以上是我的小见解,如有错误,多多指教。
转载于:www.acodelife.cn