zedboard之GPIO驅動(從FPGA一直到LINUX應用)
阿新 • • 發佈:2019-02-08
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。這個過程十分複雜任何一個方面都要搞幾個月,但是站在巨人的肩膀上就是好。
圖 1 FPGA 硬體地址分配表
圖2 硬體設計
2 SDK
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 \n",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.\n"); 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.\n"); 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 .\n"); 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\n"); 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!\n"); 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.\n"); } 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官方資料ZYNQ外設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
我們一直在思考生命,有人相通了,有人還在摸索,無論如何我們都逃不出死亡的魔掌