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

来源:互联网 发布:太原哪里购买知豆d3 编辑:程序博客网 时间:2024/05/17 22:13
   

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

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 <linux/init.h>

#include <linux/module.h>

#include <linux/fs.h>

#include <linux/cdev.h>

#include <asm/uaccess.h>

#include <linux/string.h>

#include <linux/kernel.h>

#include <linux/device.h>

#include <linux/slab.h>

#include <plat/gpmc.h>

#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 <stdio.h>

#include <stdlib.h>

#include <fcntl.h>

#include <errno.h>

#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<sizeof(buf);i++)

{

buf = i;

}

write(fd,&buf,PAGE_SIZE);

close(fd);

return 0;

}

8. 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抓的结果。(l略)


0 0
原创粉丝点击