赞
踩
一、基本环境
1、linux版本:ubuntu 18.04.2 LTS
2、vivado2020.2、petalinux2020.2、vitis2020.2
3、MobaXterm
二、petalinux软件安装
1、虚拟机硬盘设置200G,内存设置16G,处理器个数2、每个处理器核数8(总共16核)
petalinux-v2020.2-final-installer.run
download
sstate_arm_2020.2
3、安装依赖库:
sudo apt-get install iproute2 gawk python3 python build-essential gcc git make net-tools libncurses5-dev tftpd zlib1g-dev libssl-dev flex bison libselinux1 gnupg wget git-core diffstat chrpath socat xterm autoconf libtool tar unzip texinfo zlib1g-dev gcc-multilib automake zlib1g:i386 screen pax gzip cpio python3-pip python3-pexpect xz-utils debianutils iputils-ping python3-git python3-jinja2 libegl1-mesa libsdl1.2-dev pylint3
4、修改bash
Petalinux 工具需要主机系统的/bin/sh 是 bash,而 Ubuntu 默认的/bin/sh 是 dash,所以这里 需要进行更改。运行 sudo dpkg-reconfigure dash 命令进行更改,执行结果如下图所示:
选择“否”按下回车即可。
5、安装
安装 Petalinux 就要考虑安装位置了,对于 Petalinux 这种体积庞大的工具,我们将其放在 /opt 目录下。在/opt 目录下新建专门存放 Petalinux 的文件夹,如/opt/pkg/petalinux/2020.2,在 终端输入以下命令即可:
- sudo chown -R $USER:$USER /opt
- mkdir -p /opt/pkg/petalinux/2020.2
现在我们将 petalinux 安装在/opt/pkg/petalinux/2020.2 目录下,在终端中输入如下命令:
./petalinux-v2020.2-final-installer.run -d /opt/pkg/petalinux/2020.2
运行上述命令后,需要等待一段时间,当出现“Press Enter to display the license agreements” 字样的时候,如下图所示:
从显示的意思可以知道,让我们按下回车键显示软件许可协议,按下键盘上的回车键 Enter, 显示协议内容如下:
这些内容如果你感兴趣可以看看,此处我们就不详细看了,直接按下键盘上的 Q 键退出, 回到之前的界面之后会出现一个选择项,询问我们是否接受 xilinx 最终用户协议。
输入 y 按回车接受。除了 xilinx 最终用户协议之外,还有两个协议也需要大家接受,会依次显示在终端上,同理也是输入 Y 按下回车接受。
接受所有协议之后 Petalinux 安装工具便会继续安装,直到安装完成。安装完成之后,我 们进入到安装目录下,目录内容如下图所示:
每次开启一个terminal都要source setting.sh 文件。
三、工程搭建
1、vivado工程:
剩下的为正常的vivado开发步骤,最后导出 .xsa文件。
2、Petalinux 定制 Linux 系统
a、配置环境变量
source /opt/pkg/petalinux/2020.2/settings.sh
b、创建工程
petalinux-create -t project --template zynq -n ALIENTEK-ZYNQ
c、配置工程,将vivado产生的.xsa文件复制到ALIENTEK-ZYNQ项目目录下
- cd ALIENTEK-ZYNQ
- petalinux-config --get-hw-description ./
弹出窗口,保持默认配置,选择Save,保存配置文件,选择Exit退出。
d、设置离线编译
petalinux-config
进入 Petalinux 工程,输入“petalinux-config”配置工程,配置“Yocto Settings --->Local sstate feeds settings--->local sstate feeds url”,添加解压后文件的路径,添加格式为“”。对 于笔者而言,路径为“/mnt/hgfs/share18/sstate/sstate_arm_2020.2/arm”,如下图所示:
配置“Yocto Settings --->Add pre-mirror url”,删除原来的内容,添加 downloads 包文件路径,添加格式为“file://”。 对于笔者而言,路径为“file:///mnt/hgfs/share18/downloads/downloads”,如下图所示:
保存配置,返回到“Yocto Settings”界面,取消“Enable Network sstate feeds”使能,如 下图所示:
使能“Enable BB NO NETWORK”,如下图所示:
进入 Petalinux 工程,编辑工程下的 project-spec/meta-user/conf/petalinuxbsp.conf 文件,在 文件末尾添加如下内容
- PREMIRRORS_prepend = " \
- git://.*/.* file:///mnt/hgfs/share18/downloads/downloads \n \
- gitsm://.*/.* file:///mnt/hgfs/share18/downloads/downloads \n \
- ftp://.*/.* file:///mnt/hgfs/share18/downloads/downloads \n \
- http://.*/.* file:///mnt/hgfs/share18/downloads/downloads \n \
- https://.*/.* file:///mnt/hgfs/share18/downloads/downloads \n"
文件中 file:///mnt/hgfs/share18/downloads/downloads 要与 6.3.2 小节 pre-mirror url 的路径相 同。读者在添加时,需要将其替换成自己的包文件路径。结果如下图所示:
e、编译u-boot
petalinux-config -c -u-boot
然后等待GUI出来,这里暂时不改动啥,直接save(save为u-boot.config
,名字随便取但不要留空),选择exit退出。
f、编译kernel
petalinux-config -c kernel
同上、直接save保存为kernel.config,选择exit退出。
g、编译rootfs
petalinux-config -c rootfs
操作同上(save为默认即可)。
h、编译工程
petalinux-build
等待即可,最后生成的文件在 image/linux下。
I、生成BOOT.bin
petalinux-package --boot --fsbl --fpga --u-boot --force
如果没有FPGA部分,--fpag可以不加,本次实验没有加。
将BOOT.BIN,boot.scr,image.ub复制到SD卡 FAT32 分区即可。
四、制作SD卡
1、在虚拟机中执行下面步骤:
2、执行下面命令,查看SD卡
sudo fdisk -l
3、执行下面命令,开始制作SD卡
sudo fdisk /dev/sdb
输入p查看SD卡
可以看到当前的分区表,有两个分区,一个 FAT32 的分区和一个 exFAT 分区。在开始新 分区之前需要将以前的分区删除,键入“d”,然后输入 1,删除 1 分区,再次键入“d”删除 第 2 个分区,如果读者的 SD 卡原本就只有一个分区,前面只需执行一次删除就行。当再次键 入“d”并出现提示“还没有定义分区!”时,表明已无存在的分区。
下面开始新建分区。输入“n”创建一个新分区。通过选择“p”使其为主,使用默认分区 号 1 和第一个扇区 2048。设置最后一个扇区,也就是设置第一个分区的大小,一般设置 500M 足够了,通过输入“+500M”,为该分区预留 500MB,如果提示分区包含 vfat 签名并询问是 否移除该签名,则输入“y”,如下图所示:
现在设置分区类型,输入“t”,然后输入“c”,设置为“W95 FAT32 (LBA)”,如下图 所示:
输入“a”,设为引导分区,如下图所示:
第一个分区就创建好了,开始创建第二个分区。 通过键入“n”来创建根文件系统分区。后面一路默认就可以了,如下图所示:
如果现在输入“p”检查分区表,会看到刚刚创建的 2 个分区。如果没问题,键入“w” 以写入到 SD 卡并退出。
完成了分区创建后,就可以格式化分区了。在终端输入如下命令:
- sudo mkfs.vfat -F 32 -n boot /dev/sdb1
- sudo mkfs.ext4 -L rootfs /dev/sdb2
将第一个分区格式化成 FAT32 分区并命名为 boot,将第二个分区格式化成 ext4 分区并命 名为 rootfs。执行结果如下图所示:
格式化分区之后就可以挂载分区了(重新插拔读卡器或者使用 mount 命令进行挂载)。挂 载完成后,我们将该工程 image/linux 目录下的 BOOT.BIN、boot.scr 和 image.ub 文件拷贝到名 为 boot 的分区也即/dev/sdb1 分区中。
五、启动开发板
1、设置虚拟机为桥接(后面使用NFS做准备,要与开发板处于同一网段)
2、设置串口软件
3、启动开发板,串口打印,证明启动成功
4、安装nfs与开发板共享文件
a、通过下面的命令安装 NFS 服务器
sudo apt-get install nfs-kernel-server
b、 新建一个 work 目录做为 NFS 的一个工作目录,以后我们可以把交叉编译的程序放在这个目 录里,开发板可以很方便共享到这个目录里的文件。
c、使用下面命令编辑/etc/exports 文件,配置 NFS 服务路径
sudo gedit /etc/exports
在尾部添加/home/alinx/work *(rw,sync,no_root_squash,no_subtree_check) ,配置 /home/alinx/work 目录为 NFS 的一个工作目录。其中 alinx 是用户名,这里要根据实际修改。
d、执行下面命令重启 rpcbind 服务。nfs 是一个 RPC 程序,使用它前,需要映射好端口,通过 rpcbind 设定
sudo /etc/init.d/rpcbind restart
e、执行下面命令重启 nfs 服务
sudo /etc/init.d/nfs-kernel-server restart
f、在开发板中执行下面命令设置共享文件夹,注意替换ip和路径
sudo mount -t nfs 192.168.1.154:/home/alinx/work /mnt -o nolock
六、C代码实现TCP
客户端
- #include <sys/stat.h>
-
- #include <fcntl.h>
-
- #include <errno.h>
-
- #include <netdb.h>
-
- #include <sys/types.h>
-
- #include <sys/socket.h>
-
- #include <netinet/in.h>
-
- #include <arpa/inet.h>
-
- #include <stdio.h>
-
- #include <string.h>
-
- #include <stdlib.h>
-
- #include <unistd.h>
-
- #define SERVER_PORT 6666
-
- /*
- 连接到服务器后,会不停循环,等待输入,
- 输入quit后,断开与服务器的连接
- */
-
- int main()
-
- {
-
- //客户端只需要一个套接字文件描述符,用于和服务器通信
-
- int clientSocket;
-
- //描述服务器的socket
-
- struct sockaddr_in serverAddr;
-
- char sendbuf[200];
-
- char recvbuf[200];
-
- int iDataNum;
-
- if((clientSocket = socket(AF_INET, SOCK_STREAM, 0)) < 0)
-
- {
-
- perror("socket");
-
- return 1;
-
- }
-
- serverAddr.sin_family = AF_INET;
-
- serverAddr.sin_port = htons(SERVER_PORT);
-
- //指定服务器端的ip,本地测试:127.0.0.1
-
- //inet_addr()函数,将点分十进制IP转换成网络字节序IP
-
- serverAddr.sin_addr.s_addr = inet_addr("192.168.1.102");
-
- if(connect(clientSocket, (struct sockaddr *)&serverAddr, sizeof(serverAddr)) < 0)
-
- {
-
- perror("connect");
-
- return 1;
-
- }
-
- printf("连接到主机...\n");
-
- while(1)
-
- {
-
- printf("发送消息:");
-
- scanf("%s", sendbuf);
-
- printf("\n");
-
- send(clientSocket, sendbuf, strlen(sendbuf), 0);
-
-
-
- if(strcmp(sendbuf, "quit") == 0)
-
- break;
-
- printf("读取消息:");
-
- recvbuf[0] = '\0';
-
- iDataNum = recv(clientSocket, recvbuf, 200, 0);
-
- recvbuf[iDataNum] = '\0';
-
- printf("%s\n", recvbuf);
-
- }
-
- close(clientSocket);
-
- return 0;
-
- }
服务端
- #include <sys/stat.h>
-
- #include <fcntl.h>
-
- #include <errno.h>
-
- #include <netdb.h>
-
- #include <sys/types.h>
-
- #include <sys/socket.h>
-
- #include <netinet/in.h>
-
- #include <arpa/inet.h>
-
- #include <stdio.h>
-
- #include <string.h>
-
- #include <stdlib.h>
-
- #include <unistd.h>
-
- #define SERVER_PORT 6666
-
- /*
- 监听后,一直处于accept阻塞状态,
- 直到有客户端连接,
- 当客户端如数quit后,断开与客户端的连接
- */
-
- int main()
-
- {
-
- //调用socket函数返回的文件描述符
-
- int serverSocket;
-
- //声明两个套接字sockaddr_in结构体变量,分别表示客户端和服务器
-
- struct sockaddr_in server_addr;
-
- struct sockaddr_in clientAddr;
-
- int addr_len = sizeof(clientAddr);
-
- int client;
-
- char buffer[2048];
-
- int iDataNum;
-
- //socket函数,失败返回-1
-
- //int socket(int domain, int type, int protocol);
-
- //第一个参数表示使用的地址类型,一般都是ipv4,AF_INET
-
- //第二个参数表示套接字类型:tcp:面向连接的稳定数据传输SOCK_STREAM
-
- //第三个参数设置为0
-
- if((serverSocket = socket(AF_INET, SOCK_STREAM, 0)) < 0)
-
- {
-
- perror("socket");
-
- return 1;
-
- }
-
- bzero(&server_addr, sizeof(server_addr));
-
- //初始化服务器端的套接字,并用htons和htonl将端口和地址转成网络字节序
-
- server_addr.sin_family = AF_INET;
-
- server_addr.sin_port = htons(SERVER_PORT);
-
- //ip可是是本服务器的ip,也可以用宏INADDR_ANY代替,代表0.0.0.0,表明所有地址
-
- server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
-
- //对于bind,accept之类的函数,里面套接字参数都是需要强制转换成(struct sockaddr *)
-
- //bind三个参数:服务器端的套接字的文件描述符,
-
- if(bind(serverSocket, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0)
-
- {
-
- perror("connect");
-
- return 1;
-
- }
-
- //设置服务器上的socket为监听状态
-
- if(listen(serverSocket, 5) < 0)
-
- {
-
- perror("listen");
-
- return 1;
-
- }
-
- while(1)
-
- {
-
- printf("监听端口: %d\n", SERVER_PORT);
-
- //调用accept函数后,会进入阻塞状态
-
- //accept返回一个套接字的文件描述符,这样服务器端便有两个套接字的文件描述符,
-
- //serverSocket和client。
-
- //serverSocket仍然继续在监听状态,client则负责接收和发送数据
-
- //clientAddr是一个传出参数,accept返回时,传出客户端的地址和端口号
-
- //addr_len是一个传入-传出参数,传入的是调用者提供的缓冲区的clientAddr的长度,以避免缓冲区溢出。
-
- //传出的是客户端地址结构体的实际长度。
-
- //出错返回-1
-
- client = accept(serverSocket, (struct sockaddr*)&clientAddr, (socklen_t*)&addr_len);
-
- if(client < 0)
-
- {
-
- perror("accept");
-
- continue;
-
- }
-
- printf("等待消息...\n");
-
- //inet_ntoa ip地址转换函数,将网络字节序IP转换为点分十进制IP
-
- //表达式:char *inet_ntoa (struct in_addr);
-
- printf("IP is %s\n", inet_ntoa(clientAddr.sin_addr));
-
- printf("Port is %d\n", htons(clientAddr.sin_port));
-
- while(1)
-
- {
-
- printf("读取消息:");
-
- buffer[0] = '\0';
-
- iDataNum = recv(client, buffer, 1024, 0);
-
- if(iDataNum < 0)
-
- {
-
- perror("recv null");
-
- continue;
-
- }
-
- buffer[iDataNum] = '\0';
-
- if(strcmp(buffer, "quit") == 0)
-
- break;
-
- printf("%s\n", buffer);
-
-
-
- printf("发送消息:");
-
- scanf("%s", buffer);
-
- printf("\n");
-
- send(client, buffer, strlen(buffer), 0);
-
- if(strcmp(buffer, "quit") == 0)
-
- break;
-
- }
-
- }
-
- close(serverSocket);
-
- return 0;
-
- }
1、在Petalinux工程下创建linux应用程序工程
在创建的petalinux工程目录下(ALIENTEK-ZYNQ)
petalinux-create -t apps -n linux-app --template c
-t表示创建的工程类型,“apps"表示创建的工程类型为用户应用
-n表示创建的工程名,这里工程名取为"linux-app”
--template表示创建的应用类型,“c"代表是c语言应用,若是c++应用则输入"c++”
2、在项目目录下:project-spec/meta-user/recipes-apps/linux-app/files
编写linux-app.c,将服务端代码复制到linux-app.c
3、编译
在创建的petalinux工程目录下(ALIENTEK-ZYNQ)输入以下命令:
petalinux-build -c linux-app -x do_compile
-c
后接工程名字-x do_compile
表示编译操作
编译生成的可执行文件通过nfs共享给开发板,编译生成的文件位置为:
ALIENTEK-ZYNQ/build/tmp/work/cortexa9hf-neon-xilinx-linux-gnueabi/linux-app/1.0-r0
七,结果展示
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。