首页 > 系统相关 >【嵌入式Linux】---- 基于petaLinux和SDK开发的LED驱动和应用测试(全流程实战)

【嵌入式Linux】---- 基于petaLinux和SDK开发的LED驱动和应用测试(全流程实战)

时间:2024-12-23 20:02:47浏览次数:7  
标签:led addr ---- static Linux LED include 输入

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的控制

标签:led,addr,----,static,Linux,LED,include,输入
From: https://blog.csdn.net/weixin_66509332/article/details/144611140

相关文章

  • c语言指针
    指针指针=>内存地址指针变量=>存储着内存地址的变量定义格式:数据类型*变量名(数据类型要跟指向的数据类型保持一样)指针作用 1.查询数据  inta=10;  int*p=&a;  printf("%d\n",*p);2.存储数据/修改数据 *p=200; printf("%d",*p);3.参数传递4......
  • 3.2 图像加权和
    OpenCV中提供了函数cv2.addWeighted(),用来实现图像的加权和(混合、融合),该函数的语法格式为:dst=cv2.addWeighted(src1,alpha,src2,beta,gamma)其中,参数alpha和beta是src1和src2所对应的系数,它们的和可以等于1,也可以不等于1。该函数实现的功是dst=src1alpha+src2be......
  • 3.3按位逻辑运算
    OpenCV中提供了函数cv2.addWeighted(),用来实现图像的加权和(混合、融合),该函数的语法格式为:dst=cv2.addWeighted(src1,alpha,src2,beta,gamma)其中,参数alpha和beta是src1和src2所对应的系数,它们的和可以等于1,也可以不等于1。该函数实现的功是dst=src1alpha+src2be......
  • niushop开源商城靶场漏洞
    文件上传漏洞先注册一个账号来到个人信息修改个人头像选择我们的马#一句话(不想麻烦的选择一句话也可以)<?php@eval($_POST["cmd"]);?>#生成h.php文件<?phpfputs(fopen('h.php','w'),'<?php@eval($_POST["cmd"]);?>');?>在BP中进行抓包,改为1.php......
  • JavaScript从基础到进阶的155个问题
    文章目录1.输出是什么?2.输出是什么?3.输出是什么?4.输出是什么?5.哪一个是正确的?6.输出是什么?7.输出是什么?8.输出是什么?9.输出是什么?10.当我们这么做时,会发生什么?11.输出是什么?12.输出是什么?13.事件传播的三个阶段是什么?14.所有对象都有原型。15.输出是什么?1......
  • 心语空间:校园心理健康网站开发与实践
    2.1Java语言Java语言流行至今,依然是后台程序开发人员从业者需要学习的技能之一,并且可以不断的进行深造,可以用Java解决各种各样的问题。Java是一种面向对象的语言,这一点对Java语言的发展功不可没。万物皆对象,很生动的对自然存在的各种环境,各种问题提供了一个解决思路,人类对......
  • 心桥计划:校园心理健康网站架构与实现
    3.1可行性分析系统是否可以正常实现操作流程,实现操作目的,符合操作流程,这些都可以提前进行分析论证。提前进行分析在开发之前是很重要的,并且进行书面记载,有助于开发流程的缜密性。3.1.1运行可行性分析开发校园心理健康网站必然是有运行条件的,开发条件和运行条件都可以进行......
  • niushop-master开源商场漏洞
    文件上传漏洞有很多地方都存在文件上传;有的地方是要校验,加一个GIF89a就可以绕过先注册一个账号来到个人信息修改个人头像选择我们的马#一句话(不想麻烦的选择一句话也可以)<?php@eval($_POST["cmd"]);?>#生成h.php文件<?phpfputs(fopen('h.php','w'),'<?php......
  • 数据结构与算法 - 排序 #直接插入排序 #希尔排序 #直接选择排序 #堆排序 #冒泡排序 #
    文章目录前言一、插入排序(一)、直接插入排序1、思路2、参考代码:3、复杂度计算:(二)、希尔排序1、思路2、参考代码:3、时间复杂度计算:二、选择排序(一)、直接选择排序1、思路2、参考代码3、时间复杂度计算(二)、堆排序三、交换排序(一)、冒泡排序(二)、快速......
  • 【信息系统项目管理师】高分论文:论信息系统项目的质量管理(城市停车诱导系统)
    更多内容请见:备考信息系统项目管理师-专栏介绍和目录文章目录一、科学严谨,规划质量管理。二、定期评审,管理质量。三、客观严谨,控制质量。2021年3月,我公司承接了某市公安局交通警察支队“城市停车诱导系统”项目的建设,并任命我为项目经理,项目建设的目......