am3358——GPMC——参考网上驱动
2019-07-13 20:47 发布
生成海报
作者:chenzhufly QQ:36886052 ( 转载请注明出处) 转自: http://bbs.eeworld.com.cn/thread-333652-1-1.html 1. 参考资料 《 AM335x ARM® Cortex™-A8 Microprocessors Technical Reference Manual 》 《 BeagleBone_revA3_SCH.pdf 》 《 BeagleBone_revA3_SRM.pdf 》 《 BeagleBone_revA3_BOM.xls 》 2. 测试的硬件环境: Beaglebone + EE_FPGA 3. 硬件连接图:用的是GPMC to 16-Bit Nonmultiplexed Memory 4. 设计思路 初始化 GPMC 相关引脚 完成 GPMC 驱动设计 完成 GPMC 应用设计 5. 初始化相关代码,主要修改并编译 /linux-3.1.0-psp04.06.00.03.sdk/arch/arm/mach-omap2/board-am335xevm.c 配置相关引脚 /* Pin mux for fpga module */ static struct pinmux_config fpga_pin_mux[] = { {"gpmc_ad0.gpmc_ad0", OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP}, {"gpmc_ad1.gpmc_ad1", OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP}, {"gpmc_ad2.gpmc_ad2", OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP}, {"gpmc_ad3.gpmc_ad3", OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP}, {"gpmc_ad4.gpmc_ad4", OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP}, {"gpmc_ad5.gpmc_ad5", OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP}, {"gpmc_ad6.gpmc_ad6", OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP}, {"gpmc_ad7.gpmc_ad7", OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP}, {"gpmc_ad8.gpmc_ad8", OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP}, {"gpmc_ad9.gpmc_ad9", OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP}, {"gpmc_ad10.gpmc_ad10", OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP}, {"gpmc_ad11.gpmc_ad11", OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP}, {"gpmc_ad12.gpmc_ad12", OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP}, {"gpmc_ad13.gpmc_ad13", OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP}, {"gpmc_ad14.gpmc_ad14", OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP}, {"gpmc_ad15.gpmc_ad15", OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP}, {"lcd_data0.gpmc_a0", OMAP_MUX_MODE1 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA}, {"lcd_data1.gpmc_a1", OMAP_MUX_MODE1 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA}, {"lcd_data2.gpmc_a2", OMAP_MUX_MODE1 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA}, {"lcd_data3.gpmc_a3", OMAP_MUX_MODE1 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA}, {"lcd_data4.gpmc_a4", OMAP_MUX_MODE1 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA}, {"lcd_data5.gpmc_a5", OMAP_MUX_MODE1 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA}, {"lcd_data6.gpmc_a6", OMAP_MUX_MODE1 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA}, {"lcd_data7.gpmc_a7", OMAP_MUX_MODE1 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA}, {"lcd_vsync.gpmc_a8", OMAP_MUX_MODE1 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA}, {"lcd_hsync.gpmc_a9", OMAP_MUX_MODE1 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA}, {"lcd_pclk.gpmc_a10", OMAP_MUX_MODE1 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA}, {"lcd_ac_bias_en.gpmc_a11", OMAP_MUX_MODE1 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA}, {"lcd_data8.gpmc_a12", OMAP_MUX_MODE1 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA}, {"lcd_data9.gpmc_a13", OMAP_MUX_MODE1 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA}, {"lcd_data10.gpmc_a14", OMAP_MUX_MODE1 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA}, {"lcd_data11.gpmc_a15", OMAP_MUX_MODE1 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA}, {"gpmc_advn_ale.gpmc_advn_ale", OMAP_MUX_MODE0 | AM33XX_PULL_DISA}, {"gpmc_oen_ren.gpmc_oen_ren", OMAP_MUX_MODE0 | AM33XX_PULL_DISA}, {"gpmc_wen.gpmc_wen", OMAP_MUX_MODE0 | AM33XX_PULL_DISA}, {"gpmc_ben0_cle.gpmc_ben0_cle", OMAP_MUX_MODE0 | AM33XX_PULL_DISA}, {"gpmc_csn1.gpmc_csn1", OMAP_MUX_MODE0 | AM33XX_PULL_DISA}, {"gpmc_clk.gpmc_clk", OMAP_MUX_MODE0 | AM33XX_PULL_DISA}, {NULL, 0}, }; 复制代码 static void evm_fpga_init(int evm_id, int profile) { setup_pin_mux(fpga_pin_mux); } 复制代码 /* Beaglebone Rev A3 and after */ static struct evm_dev_cfg beaglebone_dev_cfg[] = { {mii1_init, DEV_ON_BASEBOARD, PROFILE_NONE}, {usb0_init, DEV_ON_BASEBOARD, PROFILE_NONE}, {usb1_init, DEV_ON_BASEBOARD, PROFILE_NONE}, {mmc0_init, DEV_ON_BASEBOARD, PROFILE_NONE}, {evm_fpga_init, DEV_ON_BASEBOARD, PROFILE_NONE}, {NULL, 0, 0}, 复制代码 6. GPMC 驱动设计 /* Char device driver fpga. Do a global replace of 'fpga' with your driver name. */ #include #include #include #include #include #include #include #include #include #include #include "plat/gpio.h" #include "plat/dma.h" #include "asm/uaccess.h" #include "asm/io.h" #include "asm/atomic.h" #define USER_BUFF_SIZE 128 struct fpga_dev { dev_t devt; struct cdev cdev; struct semaphore sem; struct class *class; char *user_buff; }; static struct fpga_dev fpga_dev; unsigned long mem_base; static void __iomem *fpga_base; static void __iomem *gpmc_base; /* GPMC register offsets */ #define GPMC_REVISION 0x00 #define GPMC_SYSCONFIG 0x10 #define GPMC_SYSSTATUS 0x14 #define GPMC_IRQSTATUS 0x18 #define GPMC_IRQENABLE 0x1c #define GPMC_TIMEOUT_CONTROL 0x40 #define GPMC_ERR_ADDRESS 0x44 #define GPMC_ERR_TYPE 0x48 #define GPMC_CONFIG 0x50 #define GPMC_STATUS 0x54 #define GPMC_PREFETCH_CONFIG1 0x1e0 #define GPMC_PREFETCH_CONFIG2 0x1e4 #define GPMC_PREFETCH_CONTROL 0x1ec #define GPMC_PREFETCH_STATUS 0x1f0 #define GPMC_ECC_CONFIG 0x1f4 #define GPMC_ECC_CONTROL 0x1f8 #define GPMC_ECC_SIZE_CONFIG 0x1fc #define GPMC_ECC1_RESULT 0x200 #define GPMC_ECC_BCH_RESULT_0 0x240 #define GPMC_BASE_ADDR 0x50000000 #define GPMC_CS 1 #define GPMC_CS0 0x60 #define GPMC_CS_SIZE 0x30 #define STNOR_GPMC_CONFIG1 0x28601000 #define STNOR_GPMC_CONFIG2 0x00011001 #define STNOR_GPMC_CONFIG3 0x00020201 #define STNOR_GPMC_CONFIG4 0x08031003 #define STNOR_GPMC_CONFIG5 0x000f1111 #define STNOR_GPMC_CONFIG6 0x0f030080 static const u32 gpmc_nor[7] = { STNOR_GPMC_CONFIG1, STNOR_GPMC_CONFIG2, STNOR_GPMC_CONFIG3, STNOR_GPMC_CONFIG4, STNOR_GPMC_CONFIG5, STNOR_GPMC_CONFIG6, 0 }; static ssize_t fpga_write(struct file *filp, const char __user *buff, size_t count, loff_t *f_pos) { ssize_t status; size_t len = USER_BUFF_SIZE - 1; int i,tmp; if (count == 0) return 0; if (down_interruptible(&fpga_dev.sem)) return -ERESTARTSYS; if (len > count) len = count; memset(fpga_dev.user_buff, 0, USER_BUFF_SIZE);if (copy_from_user(fpga_dev.user_buff, buff, len)) { status = -EFAULT; goto fpga_write_done; } /* do something with the user data */ printk("fpga_write
"); for (i = 0; i < len; i=i+2) { tmp = fpga_dev.user_buff | fpga_dev.user_buff[i+1] << 8; writew(tmp,fpga_base+i); } for (i = 0; i < len; i++) { printk("0x%x ",fpga_dev.user_buff ); } printk("
"); fpga_write_done: up(&fpga_dev.sem); return status; } static ssize_t fpga_read(struct file *filp, char __user *buff, size_t count, loff_t *offp) { ssize_t status; size_t len; // int i,tmp; /* Generic user progs like cat will continue calling until we return zero. So if *offp != 0, we know this is at least the second call. */ if (*offp > 0) return 0; if (down_interruptible(&fpga_dev.sem)) return -ERESTARTSYS; strcpy(fpga_dev.user_buff, "fpga driver data goes here
"); len = strlen(fpga_dev.user_buff); if (len > count) len = count; if (copy_to_user(buff, fpga_dev.user_buff, len)) { status = -EFAULT; goto fpga_read_done; } fpga_read_done: up(&fpga_dev.sem); return status; } static int fpga_open(struct inode *inode, struct file *filp) { int status = 0; if (down_interruptible(&fpga_dev.sem)) return -ERESTARTSYS; if (!fpga_dev.user_buff) { fpga_dev.user_buff = kmalloc(USER_BUFF_SIZE, GFP_KERNEL); if (!fpga_dev.user_buff) { printk(KERN_ALERT "fpga_open: user_buff alloc failed
"); status = -ENOMEM; } } up(&fpga_dev.sem); return status; } static const struct file_operations fpga_fops = { .owner = THIS_MODULE, .open = fpga_open, .read = fpga_read, .write = fpga_write, }; static int __init fpga_init_cdev(void) { int error; u32 val; fpga_dev.devt = MKDEV(0, 0); error = alloc_chrdev_region(&fpga_dev.devt, 0, 1, "fpga"); if (error) { printk(KERN_ALERT "alloc_chrdev_region() failed: %d
", error); return error; } cdev_init(&fpga_dev.cdev, &fpga_fops); fpga_dev.cdev.owner = THIS_MODULE; error = cdev_add(&fpga_dev.cdev, fpga_dev.devt, 1); if (error) { printk(KERN_ALERT "cdev_add() failed: %d
", error); unregister_chrdev_region(fpga_dev.devt, 1); return error; } printk("Getting Chip Select
"); // val = 0xf64; // gpmc_cs_write_reg(GPMC_CS, GPMC_CS_CONFIG7, val); //gpmc_base = ioremap(GPMC_BASE_ADDR, SZ_4K); val = gpmc_read_reg(GPMC_REVISION); printk("GPMC revision %d.%d
", (val >> 4) & 0x0f, val & 0x0f); gpmc_write_reg(GPMC_IRQENABLE, 0); gpmc_write_reg(GPMC_TIMEOUT_CONTROL, 0);gpmc_cs_write_reg(GPMC_CS, GPMC_CS_CONFIG1, gpmc_nor[0]); gpmc_cs_write_reg(GPMC_CS, GPMC_CS_CONFIG2, gpmc_nor[1]); gpmc_cs_write_reg(GPMC_CS, GPMC_CS_CONFIG3, gpmc_nor[2]); gpmc_cs_write_reg(GPMC_CS, GPMC_CS_CONFIG4, gpmc_nor[3]); gpmc_cs_write_reg(GPMC_CS, GPMC_CS_CONFIG5, gpmc_nor[4]); gpmc_cs_write_reg(GPMC_CS, GPMC_CS_CONFIG6, gpmc_nor[5]); val = gpmc_cs_read_reg(GPMC_CS, GPMC_CS_CONFIG7); printk("GPMC_CS_CONFIG7 value 0x%x
", val);if (gpmc_cs_request(GPMC_CS, SZ_2K, (unsigned long *)&mem_base) < 0) { printk(KERN_ERR "Failed request for GPMC mem for usrp_e
"); return -1; } printk("Got CS0, address = %lx
", mem_base);if (!request_mem_region(mem_base, SZ_2K, "mem_fpga")) { printk(KERN_ERR "Request_mem_region failed.
"); gpmc_cs_free(GPMC_CS); return -1; }fpga_base = ioremap(mem_base, SZ_2K); return 0; } static int __init fpga_init_class(void) { struct device *device; fpga_dev.class = class_create(THIS_MODULE, "fpga"); if (IS_ERR(fpga_dev.class)) { printk(KERN_ALERT "class_create(fpga) failed
"); return PTR_ERR(fpga_dev.class); } device = device_create(fpga_dev.class, NULL, fpga_dev.devt, NULL, "fpga"); if (IS_ERR(device)) { class_destroy(fpga_dev.class); return PTR_ERR(device); } return 0; } static int __init fpga_init(void) { printk(KERN_INFO "fpga_init()
"); memset(&fpga_dev, 0, sizeof(struct fpga_dev)); sema_init(&fpga_dev.sem, 1); if (fpga_init_cdev()) goto init_fail_1; if (fpga_init_class()) goto init_fail_2; return 0; init_fail_2: cdev_del(&fpga_dev.cdev); unregister_chrdev_region(fpga_dev.devt, 1); init_fail_1: return -1; } module_init(fpga_init); static void __exit fpga_exit(void) { printk(KERN_INFO "fpga_exit()
"); device_destroy(fpga_dev.class, fpga_dev.devt); class_destroy(fpga_dev.class); cdev_del(&fpga_dev.cdev); unregister_chrdev_region(fpga_dev.devt, 1);release_mem_region(mem_base, SZ_2K); gpmc_cs_free(GPMC_CS); iounmap(fpga_base); if (fpga_dev.user_buff) kfree(fpga_dev.user_buff); } module_exit(fpga_exit); MODULE_AUTHOR("chenzhufly"); MODULE_DESCRIPTION("fpga driver"); MODULE_LICENSE("Dual BSD/GPL"); MODULE_VERSION("0.1"); 复制代码 7. GPMC应用程序设计,目前只实现了beaglebone向FPGA写的流程 #include #include #include #include #define FPGA_DEV "/dev/fpga" #define PAGE_SIZE 10 int main(void) { int fd,i,res; unsigned char buf[PAGE_SIZE]; printf("GPMC Test version 1.0-BeagleBone Build on %s %s
",__DATE__,__TIME__); fd=open(FPGA_DEV,O_RDWR); if(fd<0) { printf("Can't Open %s !!!
",FPGA_DEV); return -1; } for(i=0;i { buf = i; } write(fd,&buf,PAGE_SIZE); close(fd); return 0; } 复制代码 8. FPGA相关设计 ARM和FPGA的管脚分配如下图所示 FPGA简要代码如下所示: module interface_test ( input clk, input ebgcs, input eboe, input ebwe, input [11:0]ebaddr, input [15:0]ebdata, output led, output led1 ); wire [15:0] ram_q; wire ram_wren; wire ram_rden; assign ram_wren = ((ebgcs == 1'b0) && (ebwe == 1'b0)) ? 1'b1 : 1'b0; assign ram_rden = ((ebgcs == 1'b0) && (eboe == 1'b0)) ? 1'b1 : 1'b0; TestRam testram_inst ( .clock ( clk), .data ( ebdata[15:0] ), .rdaddress ( ebaddr[11:1] ), .rden ( ram_rden ), .wraddress ( ebaddr[11:1] ), .wren ( ram_wren ), .q ( ram_q[15:0] ) ); wire ARM_READ_REG_EN; assign ARM_READ_REG_EN = ((ebgcs == 1'b0) && (eboe == 1'b0) && (ebaddr[11:1] == 11'b111_1111_1111)) ? 1'b1 : 1'b0; assign led1 = ARM_READ_REG_EN ? 1'b1 : ram_rden ? ram_q[0] : 1'bz; endmodule 复制代码 FPGA管脚分配如下所示: set_location_assignment PIN_89 -to ebaddr[0] set_location_assignment PIN_90 -to ebaddr[1] set_location_assignment PIN_87 -to ebaddr[2] set_location_assignment PIN_88 -to ebaddr[3] set_location_assignment PIN_84 -to ebaddr[4] set_location_assignment PIN_86 -to ebaddr[5] set_location_assignment PIN_81 -to ebaddr[6] set_location_assignment PIN_82 -to ebaddr[7] set_location_assignment PIN_63 -to ebaddr[8] set_location_assignment PIN_67 -to ebaddr[9] set_location_assignment PIN_64 -to ebaddr[10] set_location_assignment PIN_68 -to ebaddr[11] set_location_assignment PIN_60 -to ebdata[0] set_location_assignment PIN_59 -to ebdata[1] set_location_assignment PIN_28 -to ebdata[2] set_location_assignment PIN_30 -to ebdata[3] set_location_assignment PIN_58 -to ebdata[4] set_location_assignment PIN_57 -to ebdata[5] set_location_assignment PIN_24 -to ebdata[6] set_location_assignment PIN_27 -to ebdata[7] set_location_assignment PIN_47 -to ebdata[8] set_location_assignment PIN_40 -to ebdata[9] set_location_assignment PIN_41 -to ebdata[10] set_location_assignment PIN_45 -to ebdata[11] set_location_assignment PIN_39 -to ebdata[12] set_location_assignment PIN_37 -to ebdata[13] set_location_assignment PIN_44 -to ebdata[14] set_location_assignment PIN_43 -to ebdata[15] set_location_assignment PIN_61 -to ebgcs set_location_assignment PIN_33 -to eboe set_location_assignment PIN_35 -to ebwe set_location_assignment PIN_23 -to clk set_location_assignment PIN_31 -to led set_location_assignment PIN_34 -to led1 复制代码 9. 测试结果 BeagleBone向EE_FPGA写0,1,2,3,4,5,6,7,8,9;通过signaltap抓的结果。 备注: 实际项目中只使用了其初始化,应用程序只操作内存就好。GPMC其实很简单,就是只要向相应的GPMC_CS所申请的内存中丢数据,GPMC相应的片选会自动拉低。
打开微信“扫一扫”,打开网页后点击屏幕右上角分享按钮