笔者:xiabodan 资源: http://blog.csdn.net/xiabodan/article/details/24308373
1 EDK
大家知道我们在EDK中建立GPIO然后倒出到SDK中,在SDK中能够用C语言操作外设GPIO,可是这还是裸机程序。没实用到LINUX。本文将记录从FPGA EDK生成GPIO一直到导入SDK中,建立.fsbl文件。creat BOOT.BIN,然后依据前面的文章(生成uboot.elf 以及生成zImage。.dtb文件)。然后我们在linux中编写GPIO驱动程序,操作我们在FPGA中建立的GPIO。这个过程十分复杂不论什么一个方面都要搞几个月,可是站在巨人的肩膀上就是好。
首先我们要在EDK中建立GPIO外设,这里我用的AXI_GPIO,具体的过程不讲述了,能够參考官网资料CTT:http://download.csdn.net/detail/xiabodan/7235031
图 1 FPGA 硬件地址分配表
图2 硬件设计
2 SDK
然后到出到SDK,生成BOOT.BIN,详细步骤见http://blog.csdn.net/xiabodan/article/details/23379645
3 驱动编写
#include <linux/module.h> #include <linux/kernel.h> #include <linux/fs.h> #include <linux/device.h> #include <asm/io.h> #define DEVICE_NAME "AXI_GPIO_MOUDLE" #define PWM_MOUDLE_PHY_ADDR 0x41200000 //This Address is based XPS 见图1 MODULE_AUTHOR("Xilinx "); MODULE_DESCRIPTION("AXI GPIO moudle dirver"); MODULE_VERSION("v1.0"); MODULE_LICENSE("GPL"); static int pwm_driver_major; static struct class* axi_gpio_driver_class = NULL; static struct device* axi_gpio_driver_device = NULL; unsigned long AXI_gpio_fre_addr = 0; //AXI_GPIO moulde's visual address static struct file_operations axi_gpio_fops = { .owner = THIS_MODULE, }; static ssize_t sys_axi_gpio_set (struct device* dev, struct device_attribute* attr, const char* buf, size_t count) { // unsigned int direg; //unsigned int opreg; printk("I am come in"); outl(0x00000000, pwm_fre_addr+12); //设置AXI GPIO的方向输出 outl(0xffffffff, pwm_fre_addr+8); //设置AXI GPIO的方向输出全为高 printk("sys_axi_gpio_set pwm_fre_adr is %ld ",axi_gpio_fre_addr); return count; } static DEVICE_ATTR(axi_gpio, S_IWUSR, NULL, sys_axi_gpio_set); static int __init axi_gpio_driver_module_init(void) { int ret; axi_gpio_driver_major=register_chrdev(0, DEVICE_NAME, &axi_gpio_fops );//内核注冊设备驱动 if (axi_gpio_driver_major < 0){ printk("failed to register device. "); return -1; } axi_gpio_driver_class = class_create(THIS_MODULE, "axi_gpio_driver");//创建设备类 if (IS_ERR(axi_gpio_driver_class)){ printk("failed to create zxi_gpio moudle class. "); unregister_chrdev(axi_gpio_driver_major, DEVICE_NAME); return -1; } axi_gpio_driver_device = device_create(axi_gpio_driver_class, NULL, MKDEV(axi_gpio_driver_major, 0), NULL, "axi_gpio_device"); if (IS_ERR(axi_gpio_driver_device)){ printk("failed to create device . "); unregister_chrdev(axi_gpio_driver_major, DEVICE_NAME); return -1; } ret = device_create_file(axi_gpio_driver_device, &dev_attr_axi_gpio); // if (ret < 0) printk("failed to create axi_gpio endpoint "); axi_gpio_fre_addr = (unsigned long)ioremap(PWM_MOUDLE_PHY_ADDR, sizeof(u32));//To get Custom IP--gpio moudle's virtual address //将模块的物理地址映射到虚拟地址上 printk(" axi_gpio driver initial successfully! "); return 0;} static void __exit axi_gpio_driver_module_exit(void) { device_remove_file(axi_gpio_driver_device, &dev_attr_axi_gpio); device_destroy(axi_gpio_driver_class, MKDEV(axi_gpio_driver_major, 0)); class_unregister(axi_gpio_driver_class); class_destroy(axi_gpio_driver_class); unregister_chrdev(axi_gpio_driver_major, DEVICE_NAME); printk("axi_gpio module exit. "); } module_init(axi_gpio_driver_module_init); module_exit(axi_gpio_driver_module_exit);
4 编写makefile 然后编译驱动
详细见博客 http://blog.csdn.net/xiabodan/article/details/242367575 载入insmod
insmod gpio.ko进入/sys/class/axi_gpio/
在此文件夹下 echo 0 > axi_gpio
能够看到zedboard上全部的LED都亮了
6 声明
事实上以上的做法是不正确的 由于理论上讲 驱动仅仅为我们提供策略,不应该在驱动里面实现功能函数。不然就和裸鸡程序一抹一样了,可是这里我仅仅是本着測试目的,不必较真。
7 參 考
digilent官方资料www.digilent.orgZYNQ外设datasheet(GPIO 等等能够在EDK生成)
嵌入式系统软硬件协同设计实战指南基于Xilinx zynq . 陆佳华
xilinx all programmable Zynq-7000 soc 何宾
懒兔子博客 http://www.eefocus.com/nightseas/blog/cate_12977_0.html
肖志远博客:http://blog.csdn.net/column/details/zynq.html
我们一直在思考人生,有人相通。有些人还在摸索,反正大家都逃脱死亡的魔掌
版权声明:本文博主原创文章,博客,未经同意,不得转载。