首先我们要将出厂系统通过Mftool工具烧录到开发板上,烧录好的系统是自带uart1和uart3串口,将内核版本相同的Linux内核传到Ubuntu(跟上一篇一样,版本一定要一样),使用build.sh编译内核,
根据正点原子教程创建VSCODE工程并屏蔽部分内容(不屏蔽也可以,就是找文件麻烦一点,参开正点原子驱动开发手册)
找到imx6ul-pinfunc.h文件查看宏定义找到UART4有关的宏定义,然后
在imx6ull-alientek-emmc.dts中,在pinctrl_uart3: uart3grp这个函数下方创建uart4的节点
创建节点
pinctrl_uart4: uart4grp {
fsl,pins = <
MX6UL_PAD_UART4_RX_DATA__UART4_DCE_RX 0x1b0b1
MX6UL_PAD_UART4_TX_DATA__UART4_DCE_TX 0x1b0b1
>;
};
找到到&uart3,在下面添加uart4的节点
添加节点
&uart4 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_uart4>;
status = "okay";
};
注意使用查找功能(Ctrl+F)查看是否串口重用,将重用的进行屏蔽
然后编译设备树
make dtbs
将设备树和镜像拷贝到tftp目录下
sudo cp arch/arm/boot/dts/imx6ull-alientek-emmc.dtb /home/lxy/linux/tftpboot/ -f
sudo cp arch/arm/boot/zImage /home/lxy/linux/tftpboot/ -f
启动开发板进入Uboot模式 (出现倒计时时候按回车键),设置IP(如果开始就设置好的话这里可以不用再次设置)
setenv ipaddr 192.168.150.8
setenv ethaddr b8:ae:1d:01:00:00
setenv gatewayip 192.168.150.1
setenv netmask 255.255.255.0
setenv serverip 192.168.150.16
saveenv
设置bootcmd 和bootargs环境变量以便从tftp下载zImage和dtb
//从emmc启动文件系统
setenv bootargs 'console=ttymxc0,115200 root=/dev/mmcblk1p2 rootwait rw'
//网络启动内核和设置树
setenv bootcmd 'tftp 80800000 zImage; tftp 83000000 imx6ull-alientek-emmc.dtb; bootz 80800000 - 83000000;'
saveenv
在Uboot下使用bootz命令重启开发板,(注意:不能按复位,因为它下载在DRAM中,掉电就没了)系统自动下载镜像和设备树到DRAM,(先ping一下虚拟机看是否可以ping通,如果不通需要再次设置ip和服务器)
启动后查看/dev如下,出现ttymxc3
首先要设置开发板静态IP和挂载网络文件系统(参考上一篇文章)
使用select函数监视串口信息
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define F_UART3 "/dev/ttymxc2" //串口3
#define F_UART4 "/dev/ttymxc3" //串口4
#define MAX 3 //串口数量
void Open_File(); //打开文件,参数为描述符集合
void Close_File(int buf[MAX]); //关闭文件,参数为描述符集合
void Set_select(int buf[MAX]); //布置监视任务并获取结果
int Read_file(int fd, char *buf, int size); //读文件信息,参数:文件描述符,信息缓冲区,一次读的字节数
void Write_Uart(char *buf, int fd); //向串口发送数据,参数:写入的数据,文件描述符
int max(int a, int b);
int set_opt(int fd,int nSpeed, int nBits, char nEvent, int nStop); //初始化串口,参数:文件描述符,波特率,数据位,是否校验,停止位
char bufferR[10]; //读取数据缓冲区
char bufferW[8] = "Hellow"; //写入数据
static int file_descri[MAX];
void main()
{
Open_File();
Set_select(file_descri);
Close_File(file_descri);
}
void Open_File(int buf[MAX])
{
if((file_descri[0]=open(F_UART3,O_RDWR,0777))<0)
{
printf("uart3failed\n");
}
else
{
printf("uart3uccess\n");
set_opt(file_descri[0], 115200, 8, 'N', 1);
}
if((file_descri[1]=open(F_UART4,O_RDWR,0777))<0)
{
printf("uart4failed\n");
}
else
{
printf("uart4uccess\n");
set_opt(file_descri[1], 115200, 8, 'N', 1);
}
}
void Close_File(int buf[MAX])
{
close(buf[0]);
close(buf[1]);
}
int Read_file(int fd, char *buf, int size)
{
int len = 0;
len = read(fd, buf, size);
printf("len = %d,read:%s\n", len,bufferR); //读
if(-1==len) {
return -1;
}
return len;
}
void Write_Uart(char *buf, int fd)
{
int len = strlen(buf);
write(fd,bufferW,len);
}
void Set_select(int buf[MAX])
{
while(1)
{
int ret = 0;
fd_set fs_read;
//布置监视任务
//置空读集
FD_ZERO(&fs_read);
FD_SET(buf[0], &fs_read);
FD_SET(buf[1], &fs_read);
//监视
while(FD_ISSET(buf[0],&fs_read)||FD_ISSET(buf[1],&fs_read))
{
FD_ZERO(&fs_read);
FD_SET(buf[0],&fs_read);
FD_SET(buf[1],&fs_read);
ret = select(max(buf[0],buf[1])+1, &fs_read, NULL, NULL, NULL);
if(ret < 0)
{
if(errno == EINTR) break;
perror("select");
exit(1);
}
if(FD_ISSET(buf[0], &fs_read))
{
if(-1 == Read_file(buf[0],bufferR,2))
{
break;
}
Write_Uart(bufferW, buf[0]);
}
if(FD_ISSET(buf[1], &fs_read))
{
if(-1 == Read_file(buf[1],bufferR,1))
{
break;
}
Write_Uart(bufferW, buf[1]);
}
}
}
}
//选两个文件描述符大的
int max(int a, int b)
{
if(a > b) return a;
else return b;
}
//串口通用初始化函数
int set_opt(int fd,int nSpeed, int nBits, char nEvent, int nStop)
{
struct termios newtio,oldtio;//定义结构体newtio和oldtio
//将原串口的数据取到oldtio
if ( tcgetattr( fd,&oldtio) != 0) {
perror("SetupSerial 1");
return -1;
}
//将newio清零和设置c_cflag
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;//读取最小字符数为0
tcflush(fd,TCIFLUSH);//清空缓冲区
//使配置生效
if((tcsetattr(fd,TCSANOW,&newtio))!=0)
{
perror("com set error");
return -1;
}
// printf("set done!\n\r");
return 0;
}
使用交叉编译arm-linux-gnueabihf-gcc器进行编译,
arm-linux-gnueabihf-gcc uart34App.c -o uart34App
然后拷贝到Ubuntu的nfs目录下,在开发板运行,这里要使用minicom,出厂系统里边自带了,正点原子驱动开发手册查看使用教程即可,使用串口调试助手通过USB转TTL模块将电脑和开发板连接可以进行测试,程序亲测能用。
好的!终于把自己的零散笔记整理起来了!!!