天天看点

米尔科技zynq三色灯 linux 驱动

一.目标

在zynq的randisk操作系统上,通过编写驱动,实现对三色灯的控制。采用的是米尔科技

7z020开发板。

二.分析

1)逻辑分析

三色灯是挂载在PL上,可以通过AXI-GPIO实现ps控制。

米尔科技zynq三色灯 linux 驱动

由于是三色灯,所以只需要三个位宽即可,同时设置为输出。

米尔科技zynq三色灯 linux 驱动

通常操作一个I/O口,①需要配置I/O口时钟,②配置I/O口方向(输入还是输出),③I/O口使能,④给I/O口赋值。在vivado上已经将完成I/O的,时钟连接,设置了输出,只需要向I/O口写数据就能操作三色灯了。

查看AXI GPIO 的物理地址:

米尔科技zynq三色灯 linux 驱动

在驱动中操作I/O口需要先将物理地址映射成虚拟地址。

米尔科技zynq三色灯 linux 驱动

在物理地址上差4,在虚拟地址上差4。

2)驱动分析

用户想要直接操作硬件是不行的,操作系统不允许,只有间接的操作,通过操作系统提供的接口函数,open,write、read等。

字符驱动框架

①头文件包含

②与read,write,open对应的led_read,led_write,led_open接口函数。

③模块初始化。

三.代码实现

①vivado上约束文件将三色灯引脚确定。

米尔科技zynq三色灯 linux 驱动

②制作BOOT.bin

Vivado上产生bit文件与SDK产生的FSBL,加u-boot生成。

③驱动代码

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <asm/io.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/miscdevice.h>
#include <linux/ioport.h>
#include <linux/of.h>
#include <linux/uaccess.h>
/**
 *三色灯驱动  
 *
 *
 *前提:需要在vivado上配置好pl部分,使用AXI操作GPIO,约束好引脚。
 *
 *
 *在AXI——GPIO上已经配置好了 位宽为3,输出,同时也有时钟;
 *在驱动中只需要对io地址直接进行赋值即可。
 *
 *
 *
 * **/


//驱动框架
int major;
static volatile unsigned int *led_base;
#define LED_ADDRESS 0X41200000
static struct class *led_class   = NULL;
static struct device *led_device = NULL;
static int led_init(void);
static int led_exit(void);
static int led_open(struct inode *inode,struct file *file);
static int led_write(struct file *file,const char __user *buf, size_t count,loff_t *ppos);
static int led_read(struct file *file,char __user *buf,size_t size,loff_t *ppos);
/*
 *file_operations 结构数据,沟通内核与操作系统桥梁
 *建立起 read 与led_read  write与led_write 对应关系
 * */
static struct file_operations led_lops=
{
.owner = THIS_MODULE,
.read  = led_read,
.write = led_write,
};
/*
 *LED 初始化,用于module init
 *
 * */
static int led_init(void)
{
    major=register_chrdev(0,"leds",&led_lops);
    led_class  = class_create(THIS_MODULE,"leds");
    led_device = device_create(led_class,NULL,MKDEV(major,0),NULL,"leds");
    
    led_base =  ioremap(LED_ADDRESS,4);
    printk("LED init");
    return 0;
}
/*
 *LED 退出 用于 module exit
 *
 * */
static int led_exit(void)
{
    unregister_chrdev(major,"leds");
    
    device_destroy(led_device,MKDEV(major,0));
    class_destroy(led_class);
    
    iounmap(led_base);
    printk("LED exit");
    return 0;
}
/*
 *LED open 接口函数
 *
 * */
static int led_open(struct inode *inode,struct file *file)
{
    printk("LED open\r\n");
    return 0;
}
/*
 *LED write 接口函数
 *
 * */
static int led_write(struct file *file,const char __user *buf, size_t count,loff_t *ppos)
{
    int val;
    int i;
    i= copy_from_user(&val,buf,count);

    iowrite32(val,led_base);

    return 0;
}
/*
 *LED read 接口函数
 *
 * */
static int led_read(struct file *file,char __user *buf,size_t size,loff_t *ppos)
{
    printk("LED read\n");
    return 0;
}

module_init(led_init);
module_exit(led_exit);

MODULE_AUTHOR("[email protected]");
MODULE_DESCRIPTION("LED driver");
MODULE_ALIAS("led linux driver");
MODULE_LICENSE("GPL");
           

测试代码

#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
	
	void delay(void)
	{
    int i,j;
    for(i=0;i<20000;i++)
        for(j=0;j<10000;j++);
	}

	int main(int argc , char ** argv)


	{
   
    int fd;
    int i;
    
    int val=7;
    
    fd = open("/dev/led_dev",O_RDWR);
    if(fd<0) {printf("can not open file\n");while(1);}
    else printf("open file sucuss\n");
    while(1)
    {
        printf(" light off all led!\n");
        val = 7;
        write(fd,&val,4);
        delay();delay();

        printf("light on frist!\n");
        val = 6;
        write(fd,&val,4);
        delay();delay();delay();

        printf("light on second!\n");
        val = 5;
        write(fd,&val,4);
        delay();delay();delay();

        printf("light on third!\n");
        val = 3;
        write(fd,&val,4);
        delay();delay();delay();
        
        printf("light on all led!\n");
        val = 0;
        write(fd,&val,4);
        delay();delay();delay();
    }

    return 0;
	}
           

④产生驱动文件,可执行文件

产生驱动的makefile文件如下,内核源码放在linux-xlnx下面。

KDIR = /home/python/Hard_disk_21G/04-Linux_Source/Kernel/linux-xlnx
	PWD := $(shell pwd)
	CC   = $(CROSS_COMPILE)gcc
	ARCH = arm
	MAKE = make

	obj-m:=led_driver.o

	modules:
	$(MAKE) -C $(KDIR) ARCH=$(ARCH) CROSS_COMPLE=$(CROSS_COMPLE) M=$(PWD) modules
	clean:
	make -C $(KDIR) ARCH=$(ARCH) CROSS_COMPLE=$(CROSS_COMPLE) M=$(PWD) clean
           

产生可执行文件

采用赛灵斯的交叉编译工具编译即可得到。

⑤将驱动和可执行文件拷贝到randisk的文件中,在拷贝到SD卡上,运行即可观察到三色灯按照预定的方式点亮。

继续阅读