1 配置petaLinux环境变量

在Linuxproject目录下,打开终端,输入命令source /opt/pkg/petalinux/2018.3/settings.sh

2 新建petaLinux工程

petalinux-create -t project --template zynq -n ZYNQ7010_LED
在这里插入图片描述

3 配置petaLinux工程

输入cd ZYNQ7010_LED,进入刚刚创建的工程文件;

输入petalinux-config --get-hw-description /mnt/hgfs/ShareFile/project_File/Class_text/,【此命令指向一个硬件描述文件的目录,HDF 文件包含了 Zynq 硬件设计的配置信息(如处理器核、外设等),供 PetaLinux 使用】,稍等一会就能进入配置界面
在这里插入图片描述

3.1 配置为从QSPI Flash中启动

3.1.1 进入Subsystem AUTO Hardware Settings

在这里插入图片描述

3.1.2 进入Advanced bootable images storage Settings

在这里插入图片描述

3.1.3 进入boot image settings

在这里插入图片描述
修改为primary flash
在这里插入图片描述

3.1.4 进入kernel image settings

在这里插入图片描述
也修改为primary flash
在这里插入图片描述

3.2 保存并退出

等待petaLinux配置完成
在这里插入图片描述

4 修改自定义设备树文件

设备树文件在该工程路径下
在这里插入图片描述

/include/ "system-conf.dtsi"
#include <dt-bindings/gpio/gpio.h>

#define GPIO_ACTIVE_HIGH 0
#define GPIO_ACTIVE_LOW  1

/ {  
    model = "Navigator Development Board"; 
    compatible = "zynq7010,zynq-7020","xlnx,zynq-7000";

    leds { 
		compatible = "gpio-leds";

		gpio-led1 {
			label = "led1"; 
			gpios = <&gpio0 9 GPIO_ACTIVE_HIGH>; 
			default-state = "on"; 
		};

		gpio-led2{
			label = "led2"; 
			gpios = <&gpio0 54 GPIO_ACTIVE_HIGH>; 
			default-state = "on"; 
		};

		gpio-led3{
			label = "led3"; 
			gpios = <&gpio0 55 GPIO_ACTIVE_HIGH>; 
			default-state = "on"; 
		};

		gpio-led4{
			label = "led4"; 
			gpios = <&gpio0 56 GPIO_ACTIVE_HIGH>; 
			default-state = "on"; 
		};

		gpio-led5{
			label = "led5"; 
			gpios = <&gpio0 57 GPIO_ACTIVE_HIGH>; 
			default-state = "on"; 
		};
 
    	};

	keys {
		compatible = "gpio-keys";
		autorepeat; 

		gpio-key1 {
			label = " key1"; 
			gpios = <&gpio0 0 GPIO_ACTIVE_LOW>; 
			linux,code = <105>; // Right 
			debounce-interval = <20>; // 20ms 
		};
	
		gpio-key2 {
			label = " key2"; 
			gpios = <&gpio0 58 GPIO_ACTIVE_LOW>; 
			linux,code = <106>; // Left 
			debounce-interval = <20>; // 20ms 
		};

		gpio-key3 {
			label = " key3"; 
			gpios = <&gpio0 59 GPIO_ACTIVE_LOW>; 
			linux,code = <28>; // Enter
			debounce-interval = <20>; // 20ms 
		};
	};
};

&i2c0 {
	status = "okay";
	clock-frequency = <100000>; 

	myiic@50 {
		compatible = "cdns,i2c-r1p10";
		reg = <0x50>;
	}; 
};

&PWM_0 { 
	compatible = "digilent,axi-pwm"; 
	clock-names = "pwm";
	npwm = <1>; 
};

设备树中描述了5个LED接口,3个按键接口,1个IIC接口和1个PWM接口

5 配置内核

输入petalinux-config -c kernel,回车等待…
在这里插入图片描述

不用修改,直接保存退出
在这里插入图片描述
等待配置完成
在这里插入图片描述

6 创建驱动模块

输入petalinux-create -t modules --name leddrive --enable,创建一个名为leddrive的驱动模块【驱动模块的名称不要大写,也不要出现下划线
在这里插入图片描述

找到该驱动模块的路径,并对leddrive.c文件进行修改
在这里插入图片描述

//#include <linux/typlinuxkes.h>
#include <linux/kernel.h>
#include <linux/delay.h>
//#include <linux/ide.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <asm/mach/map.h>
#include <linux/uaccess.h>
#include <asm/io.h>

#define LED_MAJOR 200  /* 主设备号 */
#define LED_NAME "led" /* 设备名字 */
/* GPIO 相关寄存器地址定义 */
#define ZYNQ_GPIO_REG_BASE      0xE000A000
#define DATA_OFFSET             0x00000040
#define DIRM_OFFSET             0x00000204
#define OUTEN_OFFSET            0x00000208
#define INTDIS_OFFSET           0x00000214
#define APER_CLK_CTRL           0xF800012C
/* 映射后的寄存器虚拟地址指针 */
static void __iomem *data_addr;
static void __iomem *dirm_addr;
static void __iomem *outen_addr;
static void __iomem *intdis_addr;
static void __iomem *aper_clk_ctrl_addr;

static int led_open(struct inode *inode, struct file *filp)
{
    return 0;
}
static ssize_t led_read(struct file *filp, char __user *buf,
                        size_t cnt, loff_t *offt)
{
    return 0;
}
static ssize_t led_write(struct file *filp, const char __user *buf,
                         size_t cnt, loff_t *offt)
{
    int ret;
    int val;
    char kern_buf[1];

    ret = copy_from_user(kern_buf, buf, cnt); // 得到应用层传递过来的数据
    if (0 > ret)
    {
        printk(KERN_ERR "kernel write failed!\r\n");
        return -EFAULT;
    }

    val = readl(data_addr);
    if (0 == kern_buf[0])
        val &= ~(0x1U << 9); // 如果传递过来的数据是 0 则关闭 led
    else if (1 == kern_buf[0])
        val |= (0x1U << 9); // 如果传递过来的数据是 1 则点亮 led
    writel(val, data_addr);
    return 0;
}
static int led_release(struct inode *inode, struct file *filp)
{
    return 0;
}
static struct file_operations led_fops = {
    .owner = THIS_MODULE,
    .open = led_open,
    .read = led_read,
    .write = led_write,
    .release = led_release,
};
static int __init led_init(void)
{
    u32 val;
    int ret;

    /* 1.寄存器地址映射 */
    data_addr = ioremap(ZYNQ_GPIO_REG_BASE + DATA_OFFSET, 4);
    dirm_addr = ioremap(ZYNQ_GPIO_REG_BASE + DIRM_OFFSET, 4);
    outen_addr = ioremap(ZYNQ_GPIO_REG_BASE + OUTEN_OFFSET, 4);
    intdis_addr = ioremap(ZYNQ_GPIO_REG_BASE + INTDIS_OFFSET, 4);
    aper_clk_ctrl_addr = ioremap(APER_CLK_CTRL, 4);

    /* 2.使能 GPIO 时钟 */
    val = readl(aper_clk_ctrl_addr);
    val |= (0x1U << 22);
    writel(val, aper_clk_ctrl_addr);
    /* 3.关闭中断功能 */
    val |= (0x1U << 9);
    writel(val, intdis_addr);

    /* 4.设置 GPIO 为输出功能 */
    val = readl(dirm_addr);
    val |= (0x1U << 9);
    writel(val, dirm_addr);

    /* 5.使能 GPIO 输出功能 */
    val = readl(outen_addr);
    val |= (0x1U << 9);
    writel(val, outen_addr);

    /* 6.默认关闭 LED */
    val = readl(data_addr);
    val &= ~(0x1U << 9);
    writel(val, data_addr);

    /* 7.注册字符设备驱动 */
    ret = register_chrdev(LED_MAJOR, LED_NAME, &led_fops);
    if (0 > ret)
    {
        printk(KERN_ERR "Register LED driver failed!\r\n");
        return ret;
    }

    return 0;
}
static void __exit led_exit(void)
{
    /* 1.卸载设备 */
    unregister_chrdev(LED_MAJOR, LED_NAME);

    /* 2.取消内存映射 */
    iounmap(data_addr);
    iounmap(dirm_addr);
    iounmap(outen_addr);
    iounmap(intdis_addr);
    iounmap(aper_clk_ctrl_addr);
}
/* 驱动模块入口和出口函数注册 */
module_init(led_init);
module_exit(led_exit);

MODULE_AUTHOR("zxr");
MODULE_DESCRIPTION("ZYNQ GPIO LED Driver");
MODULE_LICENSE("GPL");

7 配置Linux根文件系统

输入petalinux-config -c rootfs,等待…
在这里插入图片描述
检查刚刚创建的leddrive模块是否使能
在这里插入图片描述
在这里插入图片描述

leddrive有星号就说明已经使能,直接保存退出即可
在这里插入图片描述

8 编译

输入petalinux-build -c leddrive,先编译刚刚创建的leddrive模块,等待…
在这里插入图片描述

输入petalinux-build,编译整个工程,等待…
在这里插入图片描述

9 打包制作boot.bin启动文件

输入petalinux-package --boot --fsbl --fpga --u-boot --force,等待…
在这里插入图片描述
然后将镜像文件image复制到共享文件夹下,以便在Windows端进行镜像烧录

10 SDK烧录flash

打开烧录界面
在这里插入图片描述

在image文件夹中找到对应的文件
在这里插入图片描述

然后将开发板boot拨码开关置于JATG模式进行烧录程序
在这里插入图片描述

然后,再将image里面的image.ub修改为image.ub.bin文件,烧录进开发板,offset修改为0x520000
在这里插入图片描述

11 SDK开发应用程序

11.1 创建应用工程

在这里插入图片描述

就基于模板创建
在这里插入图片描述
对模板工程重新命名
在这里插入图片描述

11.2 添加应用程序代码

打开模板工程,自行修改为
在这里插入图片描述

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char *argv[])
{
    int fd, ret;
    unsigned char buf[1];

    if (3 != argc)
    {
        printf("Usage:\n"
               "\t./ledApp /dev/led 1 @ close LED\n"
               "\t./ledApp /dev/led 0 @ open LED\n");
        return -1;
    }

    /* 打开设备 */
    fd = open(argv[1], O_RDWR);
    if (0 > fd)
    {
        printf("file %s open failed!\r\n", argv[1]);
        return -1;
    }

    /* 将字符串转换为 int 型数据 */
    buf[0] = atoi(argv[2]);

    /* 向驱动写入数据 */
    ret = write(fd, buf, sizeof(buf));
    if (0 > ret)
    {
        printf("LED Control Failed!\r\n");
        close(fd);
        return -1;
    }

    /* 关闭设备 */
    close(fd);
    return 0;
}


保存应用程序代码,sdk会自动编译,且生成一个elf的可执行文件
在这里插入图片描述
该执行文件处于SDK的工作空间路径下

12 功能验证

烧录成功后,将开发板的boot拨码开关至于QSPI模式进行启动,打开串口,点击POR复位,串口开始打印信息
在这里插入图片描述
其中有个联网的等待过程
在这里插入图片描述
直接ctrl+c打断,进入下一步,等待串口继续打印信息
在这里插入图片描述
直到显示了<工程名称> login: ,才说明工程烧录成功

12.1 Linux登录

Class_ZYNQ7010 login: 后面输入root,登录,然后提示输入密码,继续输入root,即可登录成功
在这里插入图片描述

12.2 网口连接

输入ping 192.168.50.7,连接Windows电脑网口
在这里插入图片描述

12.3 设备树硬件测试

12.3.1 LED测试

输入cd /sys/class/leds/,进入这个路径,再输入ls展开该路径下的内容

在这里插入图片描述
这五个led,刚好对应着自定义设备树system-conf.dtsi中的信息,输入cd led1,进入led1,再输入ls,展开led1中的配置信息

在这里插入图片描述
其中brightness用于控制led的亮灭程度,默认情况下,echo 1 > brightness点亮LED,echo 0 > brightness熄灭LED
在这里插入图片描述

12.3.2 按键测试

输入cd /dev/input/,再输入ls,展开/dev/input/ 下的内容

在这里插入图片描述
输入cat event0 | hexdump,即可进入按键的检测
在这里插入图片描述
检测完后,通过ctrl+c退出检测

12.4 驱动程序和应用程序测试

12.4.1 检查驱动程序和设备节点

输入cd /lib/modules/4.14.0-xilinx-v2018.3/extra/,再输入ls,检查该路径下是否存在对应的驱动文件(以.ko为后缀)
在这里插入图片描述
输入cd /dev/ls展开,检查是否存在驱动节点
在这里插入图片描述
发现不存在对应的led节点,继续执行以下命令:

cd回到主目录
depmod生成模块的依赖关系
modprobe leddrive.ko加载驱动模块并自动处理模块依赖
mknod /dev/led c 200 0创建设备节点
在这里插入图片描述

再输入cd /dev/ls展开,检查是否存在驱动节点
在这里插入图片描述
此时,dev目录下便有了一个led设备节点

12.4.2 挂载NFS服务

回到主目录,输入mkdir /mnt/nfs,在开发板的Linux系统中新建一个nfs文件夹,用以存放Windows端nfs挂载的共享文件

然后输入mount -t nfs -o nolock 192.168.50.7:/nfs /mnt/nfs/进行挂载

输入cd /mnt/nfs,进入开发板Linux系统刚刚创建的nfs路径中,ls展开,便能看到Windows端nfs服务所共享的文件
在这里插入图片描述

在这里插入图片描述

12.4.3 复制应用程序文件

输入cp LED_APP.elf /home/root/,将应用程序的可执行文件复制到开发板的root目录下,输入cd /home/root/进入该目录,再输入ls展开,检查文件是否复制成功
在这里插入图片描述

12.4.4 赋予权限

输入chmod a+x LED_APP.elf,给文件添加可执行权限
在这里插入图片描述

12.4.5 运行应用程序

输入./LED_APP.elf /dev/led 1,开发板LED亮;输入./LED_APP.elf /dev/led 0,开发板LED灭

在这里插入图片描述
到此,成功通过petaLinux编译驱动程序和SDK编译应用程序并在ZYNQ7010开发板上实现LED的控制

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐