米尔科技Zynq利用EMIO操作三色灯的linux驱动

一.目标
在米尔科技的zynq的z-turn开发板上利用EMIO操作三色灯亮灭。
二.分析
三色灯是挂载在PL部分的,PS想要操作它可以通过EMIO接口实现。
IP配置关键如下

米尔科技Zynq利用EMIO操作三色灯的linux驱动_第1张图片
米尔科技Zynq利用EMIO操作三色灯的linux驱动_第2张图片
产生顶层文件中有gpio_0_tri_io。
米尔科技Zynq利用EMIO操作三色灯的linux驱动_第3张图片
驱动部分的IO口地址可以从手册中查看,类似MIO操作。
三.代码实现
①vivado上的约束文件

set_property PACKAGE_PIN R14 [get_ports {gpio_0_tri_io[0]}]
set_property PACKAGE_PIN Y16 [get_ports {gpio_0_tri_io[1]}]
set_property PACKAGE_PIN Y17 [get_ports {gpio_0_tri_io[2]}]
set_property IOSTANDARD LVCMOS33 [get_ports {gpio_0_tri_io[2]}]
set_property IOSTANDARD LVCMOS33 [get_ports {gpio_0_tri_io[1]}]
set_property IOSTANDARD LVCMOS33 [get_ports {gpio_0_tri_io[0]}]

②驱动代码

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
/**
 *  LED EMIO驱动  
 *
 *EMIO0---三
 *EMIO1---色
 *EMIO2---灯
 *
 *
 *
 *
 *
 * **/


//驱动框架
int major;
//GPIO基地址
#define GPIO_BASE_Address 0xe000a000

volatile unsigned int *mask_data_lsw;
//屏蔽输出低16bit
#define MASK_DATA_2_LSW   0X00000010

volatile unsigned int *mask_data_msw;
//屏蔽输出高16bit
#define MASK_DATA_2_MSW   0X00000014

volatile unsigned int *data;
//输出数据
#define DATA_2            0X00000048

volatile unsigned int *dirm;
//配置I/O口方向
#define DIRM_2            0X00000284

volatile unsigned int *oen;
//输出使能
#define OEN_2             0X00000288

volatile unsigned int *clk;
//时钟地址
#define CLK_ADDR          0XF800012C

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");
    
    mask_data_lsw = ioremap(GPIO_BASE_Address+MASK_DATA_2_LSW,4);
    mask_data_msw = ioremap(GPIO_BASE_Address+MASK_DATA_2_MSW,4);
    data          = ioremap(GPIO_BASE_Address+DATA_2,4);
    dirm          = ioremap(GPIO_BASE_Address+DIRM_2,4);
    oen           = ioremap(GPIO_BASE_Address+OEN_2,4);
    clk           = ioremap(CLK_ADDR,4);//时钟默认打开,可以不用管啦

    iowrite32(0xfffffff8,mask_data_lsw);
    iowrite32(0xfffffff8,mask_data_msw);
    iowrite32(0x00000007,dirm);
    iowrite32(0x00000007,oen);

    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(mask_data_lsw);
    iounmap(mask_data_msw);
    iounmap(data);
    iounmap(dirm);
    iounmap(oen);
    iounmap(clk);
    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,data);

    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("TEST@LED");
MODULE_DESCRIPTION("LED driver");
MODULE_ALIAS("led linux driver");
MODULE_LICENSE("GPL");

③测试代码

#include 
#include 
#include 
#include 
#include 

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 = 0x00000007;
        write(fd,&val,4);
        delay();delay();

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

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

        printf("light on third!\n");
        val = 0x00000003;
        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文件

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_emio_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文件系统里,运行开发板,串口打印出如下
米尔科技Zynq利用EMIO操作三色灯的linux驱动_第4张图片
观察到三色灯亮灭符合预期。

你可能感兴趣的:(zynq)