ZYNQ开发板和电脑网络连接

注:这里是不使用路由器而只采用ZYNQ开发板、电脑和虚拟机的网络连接记录

1.ZYNQ开发板和电脑以太网连接

  • 开发板使用网线连接电脑以太网后,给电脑以太网口手动配置ip192.168.1.100/24,然后在开发板Linux系统上使用命令ifconfig eth0 192.168.1.27将网口0(实际上是ETH1)的ip地址设置为192.168.1.27/24
  • 一般这样配置好ip地址后应该能互相ping通,但是可能由于防火墙的问题导致不能ping通,此时就需要关闭windows电脑和开发板的防火墙,然后应该就能ping通了

2.ZYNQ开发板和虚拟机连接

  • 如果虚拟机网络配置选择net模式的话,一般是虚拟机能ping通开发板但是开发板或电脑都不能ping通虚拟机
  • 此时需要修改虚拟机网络配置为桥接模式,并手动配置虚拟机网络ip地址与电脑以太网同一网段,例如192.168.1.30/24,此时应该开发板和虚拟机都能互相ping

Linux删除路由:sudo route del -net 192.168.1.0 netmask 255.255.255.0

linux显示网关:ip route show,``default via字段后面的IP即为网关IP`

通过NFS共享运行代码:

1
$ mount -t nfs -o nolock 192.168.1.30:/home/lyj/work /mnt

Linux下点灯实验

官网驱动用法链接:Linux GPIO Driver

1.SHELL控制GPIO来点灯

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# gpio_test.sh
#!/bin/sh
gpio_test() {
gpio=$1
echo $gpio > /sys/class/gpio/export
echo out > /sys/class/gpio/gpio${gpio}/direction
for i in $(seq 1 3)
do
echo 0 >/sys/class/gpio/gpio${gpio}/value
sleep 1
echo 1 >/sys/class/gpio/gpio${gpio}/value
sleep 1
done
echo $gpio > /sys/class/gpio/unexport
}
gpio_test 900
gpio_test 1019
  • 这里点亮两个LED灯,900对应的是核心板上的LED11019对应扩展板上的PL_LED1
  • 代码理解(对于gpio_test 900来说):
    • 配置GPIO:首先将900赋值给gpio,然后echo $gpio > /sys/class/gpio/export来生成该端口的输入输出设置等配置文件
    • 设置GPIO输入还是输出:out表示输出,in表示输入
    • 设置GPIO输出电平:循环点亮和熄灭三次LED即向该GPIO端口输出对应的电平,1表示输出高电平,0表示输出低电平
    • 关闭GPIOecho $gpio > /sys/class/gpio/unexport,删除GPIO配置文件

2.C语言控制GPIO来点灯

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
// gpio.c
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>

// The specific GPIO being used must be setup and replaced thru
// this code. The GPIO of 240 is in the path of most the sys dirs
// and in the export write.
//
// Figuring out the exact GPIO was not totally obvious when there
// were multiple GPIOs in the system. One way to do is to go into
// the gpiochips in /sys/class/gpio and view the label as it should
// reflect the address of the GPIO in the system. The name of the
// the chip appears to be the 1st GPIO of the controller.
//
// The export causes the gpio240 dir to appear in /sys/class/gpio.
// Then the direction and value can be changed by writing to them.

// The performance of this is pretty good, using a nfs mount,
// running on open source linux, on the ML507 reference system,
// the GPIO can be toggled about every 4 usec.

// The following commands from the console setup the GPIO to be
// exported, set the direction of it to an output and write a 1
// to the GPIO.
//
// bash> echo 900 > /sys/class/gpio/export
// bash> echo out > /sys/class/gpio/gpio900/direction
// bash> echo 1 > /sys/class/gpio/gpio900/value

// if sysfs is not mounted on your system, the you need to mount it
// bash> mount -t sysfs sysfs /sys

// the following bash script to toggle the gpio is also handy for
// testing
//
// while [ 1 ]; do
// echo 1 > /sys/class/gpio/gpio900/value
// sleep 1
// echo 0 > /sys/class/gpio/gpio900/value
// sleep 1
// done

// to compile this, use the following command
// gcc gpio.c -o gpio

// The kernel needs the following configuration to make this work.
//
// CONFIG_GPIO_SYSFS=y
// CONFIG_SYSFS=y
// CONFIG_EXPERIMENTAL=y
// CONFIG_GPIO_XILINX=y

int main()
{
int valuefd, exportfd, directionfd;

printf("GPIO test running...\n");

// The GPIO has to be exported to be able to see it
// in sysfs

exportfd = open("/sys/class/gpio/export", O_WRONLY);
if (exportfd < 0)
{
printf("Cannot open GPIO to export it\n");
exit(1);
}

write(exportfd, "900", 4);
close(exportfd);

printf("GPIO exported successfully\n");

// Update the direction of the GPIO to be an output

directionfd = open("/sys/class/gpio/gpio900/direction", O_RDWR);
if (directionfd < 0)
{
printf("Cannot open GPIO direction it\n");
exit(1);
}

write(directionfd, "out", 4);
close(directionfd);

printf("GPIO direction set as output successfully\n");

// Get the GPIO value ready to be toggled

valuefd = open("/sys/class/gpio/gpio900/value", O_RDWR);
if (valuefd < 0)
{
printf("Cannot open GPIO value\n");
exit(1);
}

printf("GPIO value opened, now toggling...\n");

// toggle the GPIO as fast a possible forever, a control c is needed
// to stop it

while (1)
{
write(valuefd,"1", 2);
sleep(1);
write(valuefd,"0", 2);
sleep(1);
}
}

编译命令:

1
2
$ source /opt/Xilinx/Vivado/2017.4/settings64.sh
$ arm-linux-gnueabihf-gcc gpio.c -o gpio

Linux源码编译

参考:Build kernel

1.编译环境准备

注意:这里的都采用2017.4版本

1.交叉编译工具链安装

参考:Install Xilinx Tools

(这里如果安装了vivado的话就不用再安装其他工具)

  • 设置交叉编译器的环境变量
1
2
3
4
$ export CROSS_COMPILE=<x-tool prefix>
# 例如export CROSS_COMPILE=arm-linux-gnueabihf-
$ source <vivado dir>/settings64.sh
# 在当前bash环境下读取并执行settings64.sh中的命令(使交叉编译工具能够在该bash使用)

Xilinx tools提供一下交叉编译工具链

Target Architecture x-tool prefix
Zynq-7000 (CodeSourcery - soft float) arm-xilinx-linux-gnueabi-
Zynq-7000 (Linaro - hard float) arm-linux-gnueabihf-
Zynq UltraScale+ MPSoC (ZynqMP) / Versal aarch64-linux-gnu-
Microblaze little endian microblazeel-xilinx-linux-gnu-
Microblaze big endian microblaze-xilinx-linux-gnu-
PowerPC powerpc-eabi-
2.编译FSBL(只是编译内核不需要这步)

参考:Build FSBL

1
2
3
$ hsi
hsi% set hwdsgn [open_hw_design design_1_wrapper.hdf]
hsi% generate_app -hw $hwdsgn -os standalone -proc ps7_cortexa9_0 -app zynq_fsbl -compile -sw fsbl -dir ./

报错:ERROR: [Common 17-70] Application Exception: Not found in path: gmake

解决:网上说gmake其实就是make,所以添加软链接sudo ln -s /usr/bin/make /usr/bin/gmake再次执行就没问题了

3.生成设备树编译器(dtc)

参考:Build Device Tree Compiler (dtc)

下载地址:https://git.kernel.org/pub/scm/utils/dtc/dtc.git

  • 编译dtc
1
$ make

这是可能会提示## Skipping pylibfdt (install python dev and swig to build),此时需要使用命令sudo apt install python-devsudo apt install swig来安装缺失库

  • 添加dtc的环境变量

构建过程完成后,有必要让工具(例如U-Boot构建过程)访问dtc二进制文件的路径。

1
$ export PATH=`pwd`:$PATH
4.编译U-Boot

参考:Build U-Boot

下载地址:https://github.com/Xilinx/u-boot-xlnx

  • 添加工具链路径
1
2
3
# Zynq:
$ export CROSS_COMPILE=arm-linux-gnueabihf-
$ export ARCH=arm
  • 编译
1
2
3
$ make distclean
$ make zynq_zc706_defconfig
$ make

为了使编译Linux内核源码时mkimage可用,建议将工具目录添加到$PATH

1
2
$ cd tools
$ export PATH=`pwd`:$PATH

2.编译Linux内核源码

1
2
3
4
$ make ARCH=arm xilinx_zynq_defconfig
$ make ARCH=arm menuconfig
# 编译内核镜像文件
$ make ARCH=arm UIMAGE_LOADADDR=0x8000 uImage

3.生成镜像文件和启动文件

Linux内核文件解释

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
#include <linux/***.h> 是在linux-2.6.29/include/linux下面寻找源文件。
#include <asm/***.h> 是在linux-2.6.29/arch/arm/include/asm下面寻找源文件。
#include <mach/***.h> 是在linux-2.6.29/arch/arm/mach-s3c2410/include/mach下面寻找源文件。

#include <plat/regs-adc.h>在linux-2.6.31_TX2440A20100510\linux-2.6.31_TX2440A\arch\arm\plat-s3c\include\plat
#include <linux/module.h> //最基本的文件,支持动态添加和卸载模块。Hello World驱动要这一个文件就可以了
#include <linux/fs.h> //包含了文件操作相关struct的定义,例如大名鼎鼎的struct file_operations

//包含了struct inode 的定义,MINOR、MAJOR的头文件。
#include <linux/errno.h> //包含了对返回值的宏定义,这样用户程序可以用perror输出错误信息。
#include <linux/types.h> //对一些特殊类型的定义,例如dev_t, off_t, pid_t.其实这些类型大部分都是unsigned int型通过一连串的typedef变过来的,只是为了方便阅读。
#include <linux/cdev.h> //对字符设备结构cdev以及一系列的操作函数的定义。//包含了cdev 结构及相关函数的定义。
#include <linux/wait.h> //等代队列相关头文件//内核等待队列,它包含了自旋锁的头文件

#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/slab.h> //包含了kcalloc、kzalloc内存分配函数的定义。
#include <linux/uaccess.h> //包含了copy_to_user、copy_from_user等内核访问用户进程内存地址的函数定义。
#include <linux/device.h> //包含了device、class 等结构的定义
#include <linux/io.h> //包含了ioremap、iowrite等内核访问IO内存等函数的定义。
#include <linux/miscdevice.h> //包含了miscdevice结构的定义及相关的操作函数。
#include <linux/interrupt.h> //使用中断必须的头文件
#include <mach/irqs.h> //使用中断必须的头文件
#include <asm/bitops.h> //包含set_bit等位操作函数,实现Input子系统时可用。
#include <linux/semaphore.h> //使用信号量必须的头文件
#include <linux/spinlock.h> //自旋锁

#include <linux/sched.h> //内核等待队列中要使用的TASK_NORMAL、TASK_INTERRUPTIBLE包含在这个头文件
#include <linux/kfifo.h> //fifo环形队列
#include <linux/timer.h> //内核定时器
#include <linux/input.h> //中断处理

头文件主目录include

头文件目录中总共有32个.h头文件。其中主目录下有13个,asm子目录中有4个,linux子目录中有10个,sys子目录中有5个。这些头文件各自的功能如下,具体的作用和所包含的信息请参见第14章。

<a.out.h>:a.out头文件,定义了a.out执行文件格式和一些宏。
<const.h>:常数符号头文件,目前仅定义了i节点中i_mode字段的各标志位。
<ctype.h>:字符类型头文件,定义了一些有关字符类型判断和转换的宏。
<errno.h>:错误号头文件,包含系统中各种出错号。(Linus从minix中引进的)。
<fcntl.h>:文件控制头文件,用于文件及其描述符的操作控制常数符号的定义。
<signal.h>:信号头文件,定义信号符号常量,信号结构以及信号操作函数原型。
<stdarg.h>:标准参数头文件,以宏的形式定义变量参数列表。主要说明了一个类型(va_list)和3个宏(va_start, va_arg和va_end),用于vsprintf、vprintf、vfprintf函数。
<stddef.h>:标准定义头文件,定义了NULL, offsetof(TYPE, MEMBER)。
<string.h>:字符串头文件,主要定义了一些有关字符串操作的嵌入函数。
<termios.h>:终端输入输出函数头文件,主要定义控制异步通信口的终端接口。
<time.h>:时间类型头文件,主要定义了tm结构和一些有关时间的函数原形。
<unistd.h>:Linux标准头文件,定义了各种符号常数和类型,并声明了各种函数。如,定义了__LIBRARY__,则还包括系统调用号和内嵌汇编_syscall0()等。
<utime.h>:用户时间头文件,定义了访问和修改时间结构以及utime()原型。


(1)体系结构相关头文件子目录include/asm
这些头文件主要定义了一些与CPU体系结构密切相关的数据结构、宏函数和变量。共4个文件。

<asm/io.h>:I/O头文件,以宏的嵌入汇编程序形式定义对I/O端口操作的函数。
<asm/memory.h>:内存拷贝头文件,含有memcpy()嵌入式汇编宏函数。
<asm/segment.h>:段操作头文件,定义了有关段寄存器操作的嵌入式汇编函数。
<asm/system.h>:系统头文件,定义了设置或修改描述符/中断门等的嵌入式汇编宏。

(2)Linux内核专用头文件子目录include/linux

<linux/config.h>:内核配置头文件,定义键盘语言和硬盘类型(HD_TYPE)可选项。
<linux/fdreg.h>:软驱头文件,含有软盘控制器参数的一些定义。
<linux/fs.h>:文件系统头文件,定义文件表结构(file,buffer_head,m_inode等)。
<linux/hdreg.h>:硬盘参数头文件,定义访问硬盘寄存器端口、状态码和分区表等信息。
<linux/head.h>:head头文件,定义了段描述符的简单结构,和几个选择符常量。
<linux/kernel.h>:内核头文件,含有一些内核常用函数的原形定义。
<linux/mm.h>:内存管理头文件,含有页面大小定义和一些页面释放函数原型。
<linux/sched.h>: 调度程序头文件,定义了任务结构task_struct、初始任务0的数据,
以及一些有关描述符参数设置和获取的嵌入式汇编函数宏语句。
<linux/sys.h>:系统调用头文件,含有72个系统调用C函数处理程序,以"sys_"开头。
<linux/tty.h>:tty头文件,定义了有关tty_io,串行通信方面的参数、常数。

(3)系统专用数据结构子目录include/sys
<sys/stat.h>: 文件状态头文件,含有文件或文件系统状态结构stat{}和常量。
<sys/times.h>:定义了进程中运行时间结构tms以及times()函数原型。
<sys/types.h>:类型头文件,定义了基本的系统数据类型。
<sys/utsname.h>:系统名称结构头文件。
<sys/wait.h>:等待调用头文件,定义系统调用wait()和waitpid()及相关常数符号。



<assert.h> 验证程序断言
<complex.h> 支持复数算术运算
<ctype.h> 字符类型
<errno.h> 出错码
<fenv.h> 浮点环境
<float.h> 浮点常量
<inttypes.h> 整形格式转换
<iso646.h> 替代关系操作符宏
<limits.h> 实现常量
<locale.h> 局部类别
<math.h> 数学常量
<setjmp.h> 非局部goto
<signal.h> 信号
<stdarg.h> 可变参数表
<stdbool.h> 布尔类型和值
<stddef.h> 标准定义
<stdint.h> 整型
<stdio.h> 标准I/O库
<stdlib.h> 实用程序库函数
<string.h> 字符串操作
<tgmath.h> 通用类型数学宏
<time.h> 时间和日期
<wchar.h> 扩展的多字节和宽字符支持
<wctype.h> 宽字符分类和映射支持
POSIX标准定义的头文件
[ sell=2]<direct.h> 目录项
<fchtol.h> 文件控制
<fnmatch.h> 文件名匹配类型
<glob.h> 路径名模式匹配类型
<grp.h> 组文件
<netdb.h> 网络数据库操作
<pwd.h> 口令文件
<regex.h> 正则表达式
<tar.h> tar归档值
<termios.h> 终端I/O
<unistd.h> 符号常量
<utime.h> 文件时间
<wordexp.h> 字扩展类型
<arpa/inet.h> Internet定义
<net/if.h> 套接字本地接口
<netinet/in.h> Internet地址族
<sys/mman.h> 内存管理声明
<sys/select.h> select函数
<sys/socket.h> 套接字接口
<sys/stat.h> 文件状态
<sys/times.h> 进程时间
<sys/types.h> 基本系统数据类型
<sys/un.h> UNIX域套接字定义
<sys/utsname.h> 系统名
<sys/wait.h> 进程控制

POSIX标准定义的XSI扩展头文件
<cpio.h> cpio归档值
<dlfcn.h> 动态连接
<fmtmsg.h> 消息显示结构
<ftw.h> 文件树漫游
<iconv.h> 代码集转换实用程序
<langinfo.h> 语言信息常量
<libgen.h> 模式匹配函数定义
<monetary.h> 货币类型
<ndbm.h> 数据库操作
<nl_types.h> 消息类别
<poll.h> 轮询函数
<search.h> 搜索表
<strings.h> 字符串操作
<syslog.h> 系统出错日志记录
<ucontext.h> 用户上下文
<ulimit.h> 用户限制
<utmpx.h> 用户账户数据库
<sys/ipc.h> IPC
<sys/msg.h> 消息队列
<sys/resource.h>资源操作
<sys/sem.h> 信号量
<sys/shm.h> 共享存储
<sys/statvfs.h> 文件系统信息
<sys/time.h> 时间类型
<sys/timeb.h> 附加的日期和时间定义
<sys/uio.h> 矢量I/O操作
<aio.h> 异步I/O
<mqueue.h> 消息队列
<pthread.h> 线程
<sched.h> 执行调试
<semaphore.h> 信号量
<spawn.h> 实时spawn接口
<stopts.h> XSI STREAMS 接口
<trace.h> 时间跟踪[/sell]

i2c模块编译

驱动程序开发步骤

  • 查看原理图以及数据手册

  • 修改设备树

  • 套用设备框架编写驱动

  • 编译动程序

petalinux定制Linux系统

1.建立petalinux工程

  • 添加环境变量
1
2
$ source /opt/pkg/petalinux/settings.sh
$ source /opt/Xilinx/Vivado/2017.4/settings64.sh
  • 创建petalinux工程(peta_linux)
1
$ petalinux-create --type project --template zynq --name peta_linux
  • 配置petalinux工程硬件信息(../linux_base.sdk目录下就是vivado导出的硬件信息)
1
2
$ cd peta_linux
$ petalinux-config --get-hw-description ../linux_base.sdk
  • 接再来会弹出窗口来配置petalinux工程,配置过后想再次配置可以运行petalinux-config命令

2.配置Linux内核

  • 使用以下命令配置内核
1
$ petalinux-config -c kernel
  • 等待一段时间后弹出配置内核的界面,在此界面进行内核配置

3.配置根文件系统

  • 使用以下命令配置根文件系统
1
$ petalinux-config -c rootfs
  • 同样等待一段时间后弹出配置根文件系统的界面,在此界面进行配置

4.编译

  • 使用以下命令配置编译uboot、内核、根文件系统、设备树等,也需要等待一段时间
1
$ petalinux-build

5.生成BOOT文件

  • 使用以下命令生成BOOT文件
1
$ petalinux-package --boot --fsbl ./images/linux/zynq_fsbl.elf --fpga ./images/linux/design_1_wrapper.bit --u-boot --force
  • 生成的BOOT文件在./images/linux/目录下,将BOOT.BINimage.ub复制到SD卡,插到开发板上并设置为SD卡启动