一.目标
在米尔科技zynq的z-turn开发板上,通过编写驱动,实现对两盏灯的控制。
二.分析
①硬件部分
这两盏绿灯位于zynq的MIO0和MIO9上。
有关操作IO口的地址,查找ug585-zynq-7000-TRM手册
可以看出GPIO基地址为0xe000a000,同样的有关IO操作的寄存器相对地址可以从手册中找到。
②boot.bin生成
在vivado上进行配置IP等一些列操作,导入SDK中产生。
三.代码实现
①驱动代码
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
/**
* LED MIO驱动
*
*MIO0---LED1
*MIO9---LED2
*
*
*
*
*
*
* **/
//驱动框架
int major;
//MIO基地址
#define GPIO_BASE_Address 0xe000a000
volatile unsigned int *mask_data_lsw;
//屏蔽输出低16bit
#define MASK_DATA_0_LSW 0X00000000
volatile unsigned int *mask_data_msw;
//屏蔽输出高16bit
#define MASK_DATA_0_MSW 0X00000004
volatile unsigned int *data;
//输出数据
#define DATA_0 0X00000040
volatile unsigned int *dirm;
//配置I/O口方向
#define DIRM_0 0X00000204
volatile unsigned int *oen;
//输出使能
#define OEN_0 0X00000208
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_0_LSW,4);
mask_data_msw = ioremap(GPIO_BASE_Address+MASK_DATA_0_MSW,4);
data = ioremap(GPIO_BASE_Address+DATA_0,4);
dirm = ioremap(GPIO_BASE_Address+DIRM_0,4);
oen = ioremap(GPIO_BASE_Address+OEN_0,4);
clk = ioremap(CLK_ADDR,4);//时钟默认打开,可以不用管啦
iowrite32(0xffffdfe,mask_data_lsw);
iowrite32(0xffffdfe,mask_data_msw);
iowrite32(0x00000201,dirm);
iowrite32(0x00000201,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 = 0x00000201;
write(fd,&val,4);
delay();delay();
printf("light on frist!\n");
val = 0x00000200;
write(fd,&val,4);
delay();delay();delay();
printf("light on second!\n");
val = 0x00000001;
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_mio_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