Chinaunix首页 | 论坛 | 博客
  • 博客访问: 191311
  • 博文数量: 49
  • 博客积分: 1756
  • 博客等级: 上尉
  • 技术积分: 602
  • 用 户 组: 普通用户
  • 注册时间: 2010-06-27 16:46
文章分类

全部博文(49)

文章存档

2014年(1)

2013年(17)

2012年(10)

2011年(5)

2010年(16)

我的朋友

分类: LINUX

2012-09-21 14:47:54

在beaglebone上实现AM3359与FPGA的GPMC通信

作者:chenzhufly QQ:36886052 ( 转载请注明出处)

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 \n\");
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(\"\n\");


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\n\");

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\n\");
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\n\", 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\n\", error);
unregister_chrdev_region(fpga_dev.devt, 1);
return error;
}

printk(\"Getting Chip Select\n\");

// 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\n\", (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\n\", 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\n\");
return -1;
}
printk(\"Got CS0, address = %lx\n\", mem_base);

if (!request_mem_region(mem_base, SZ_2K, \"mem_fpga\")) {
printk(KERN_ERR \"Request_mem_region failed.\n\");
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\n\");
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()\n\");

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()\n\");

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\n\r\",__DATE__,__TIME__);
fd=open(FPGA_DEV,O_RDWR);
if(fd<0)
{
printf(\"Can't Open %s !!!\n\r\",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抓的结果。




阅读(5312) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~