开发板:英蓓特科技有限公司的Mini8600B

处理器:TI公司的AM3359

操作系统:Linux3.2.0

FIFO芯片:IDT7205L20

硬件连接图:

一、GPMC module 简介

1、  GPMC简介

GPMC用于控制external memory的读写访问,GPMC的地址为0x0000 0000到0x1fff ff ff,最大支持512MB的片外存储器访问;GPMC寄存器的基地址为0x5000 0000,用于配置GPMC模块。GPMC能提供最大100MHz的外部时钟频率(gpmc_clk)。

支持的设备或存储器:

NAND flash与NOR flash结构的device/memory:

(1)8bit与16bit的同步/异步读写device/memory

(2)16bit地址数据复用的NOR flash(pSRAM)

(3)8bit与16bit的NAND flash

(4)其他支持的设备:使用NOR interface protocol进行通信,

Technical Reference Manual上有这么一句:Other supported device type interact with the GPMC through the NOR interface protocol.

2NOR Interface Protocol

NOR flash architecture, introduced in 1988, is a flash technology. Unlike NAND, which is a sequential access device, NOR is directly addressable; i.e., it is designed to be a random access device. NOR is best suited to devices used to store and run code or firmware, usually in small capacities. While NOR has fast read capabilities it has slow write and erase functions compared to NAND architecture.

3、GPMC编程模式

如上图所示,使用GPMC驱动外设时,要先对其进行初始化和配置。GPMC支持软件复位操作,通过GPMC_SYSCONFIG寄存器的配置来实现。接下来配置GPMC,NOR类型的device的配置要比NAND简单得多,主要配置GPMC_CONFIG1_i到GPMC_CONFIG7_i这七个寄存器,这些寄存器包含了memory类型(NAND、NOR)的配置,片选配置,时序配置等信息,关于片选配置,下面会详细描述。需要注意的是,在配置GPMC这七个片选寄存器之前,要先使GPMC_CONFIG7_i的CSVALID disabled,Technical Reference Manual上有这么一句:Chip-select configuration (base and mask address or any protocol and timing settings) must be performed      while the associated chip-select is disabled through the GPMC_CONFIG7_i[6] CSVALID bit. In addition, a chip-select configuration can only be disabled if there is no ongoing access to that chip-select. 片选寄存器配置完之后应当enable CSVALID。

片寻配置(chip-select configuration):GPMC最大支持512MB的片外寻址,被分成8片,每片的大小可选以下数值:16M、32M、64M、128M、256M,但8片大小的总和不能大于512MB。可通过GPMC_CONFIG7_i来配置片寻基址、片寻大小等,片寻基址必须是2的n次方,其他基址应该避免,否则会产生hole。其中CS0~CS6是可配置的,而CS7不是外部引脚(not pin out),配置了也没用。我研究了Linux3.2.0中NAND驱动的源码,发现NAND使用的是CS0,用户可从CS1~CS6中选择一个来设计自己的驱动。

二、FIFO芯片IDT7205L20简介

IDT7205L20是Integrated Device Technology,Inc.公司的一款8K*9bit的FIFO芯片,

异步读写,没有时钟引脚,没有地址引脚。通过WE和OE来控制读写,以读为例,OE变为低电平(enable电平)时,数据送到输出端口,等待CPU取走,CPU取走数据后,OE变为高电平(disable 电平),这样就完成了一个读周期。FIFO内部有一个读指针和写指针,复位后读写指针指向同一个位置。每往FIFO写一个数据时,写指针加一,每从FIFO读一个数据时,读指针加一,当读写指针相等时,FIFO空标志EF变为低电平,此时数据输出线呈高阻态,不能再读数据。当往FIFO写满8K个数据后,满标志FF变为低电平,数据输入线呈高阻态,不能再写数据。

在GPMC_CONFIG1_i中应当配置成异步读写,并且是非地址/数据复用模式,采用NOR接口协议。此外还需配置GPMC_CONFIG4_i的 WEONTIME和WEOFFTIME,OEONTIME和OEOFFTIM,根据你的FIFO datasheet来配置时间,一般是几十个纳秒级的,然后配置GPMC_CONFIG5_i和GPMC_CONFIG6_i的total read time和total write time。这些工作做完之后,FIFO与GPMC应该可以通信了。

三、 配置GPMC引脚

在以下文件Linux-3.2.0-psp04.06.00.08.sdk/arch/arm/mach-omap2/board-am335xevm.c

中配置:

1、添加如下引脚配置代码

/*pin mux for FIFO writing*/

static struct pinmux_config fifo_pin_mux[] = {

{"gpmc_ad0.gpmc_ad0",        OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT},

{"gpmc_ad1.gpmc_ad1",        OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT},

{"gpmc_ad2.gpmc_ad2",        OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT},

{"gpmc_ad3.gpmc_ad3",        OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT},

{"gpmc_ad4.gpmc_ad4",        OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT},

{"gpmc_ad5.gpmc_ad5",        OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT},

{"gpmc_ad6.gpmc_ad6",        OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT},

{"gpmc_ad7.gpmc_ad7",        OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT},

{"gpmc_ad8.gpmc_ad8",        OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT},

{"gpmc_ad9.gpmc_ad9",        OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT},

{"gpmc_ad10.gpmc_ad10",     OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT},

{"gpmc_ad11.gpmc_ad11",     OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT},

{"gpmc_ad12.gpmc_ad12",     OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT},

{"gpmc_ad13.gpmc_ad13",     OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT},

{"gpmc_ad14.gpmc_ad14",     OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT},

{"gpmc_ad15.gpmc_ad15",     OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT},

{"gpmc_csn1.gpio1_30",        OMAP_MUX_MODE7 | AM33XX_PIN_OUTPUT},

{"gpmc_csn2.gpio1_31",        OMAP_MUX_MODE7 | AM33XX_PIN_INPUT},

{"gpmc_csn3.gpio2_0",   OMAP_MUX_MODE7 | AM33XX_PIN_INPUT},

{"gpmc_clk.gpio2_1",      OMAP_MUX_MODE7 | AM33XX_PIN_OUTPUT},

{"lcd_vsync.gpio2_22",   OMAP_MUX_MODE7 | AM33XX_PIN_OUTPUT},

{"lcd_pclk.gpio2_24",      OMAP_MUX_MODE7 | AM33XX_PIN_OUTPUT},

{"gpmc_wen.gpmc_wen",     OMAP_MUX_MODE0 | AM33XX_PULL_DISA},

{"gpmc_ben1.gpmc_dir",    OMAP_MUX_MODE4 | AM33XX_PULL_DISA},

{NULL, 0},

};

2、定义GPMC device,这个gpmc_device的内容可根据驱动的实际情况而定,其目的是作为调用GPMC初始化函数omap_init_gpmc()的参数。

struct omap_fifo_platform_data {

int                  cs;

struct gpmc_timings      *gpmc_t;

int                  gpmc_irq;

unsigned long         phys_base;

int                  devsize;

bool               elm_used;

};

static struct gpmc_timings fifo_timings = {

.sync_clk = 0,

.cs_on = 0,     /* Assertion time */

.cs_rd_off = 82,/* Read deassertion time */

.cs_wr_off = 82,/* Write deassertion time */

.we_on = 40,  /* WE assertion time */

.we_off  = 40,      /* WE deassertion time */

.oe_on = 40,   /* OE assertion time */

.oe_off = 40,  /* OE deassertion time */

.access = 64,  /* Start-cycle to first data valid delay */

.rd_cycle = 82,      /* Total read cycle time */

.wr_cycle = 82,     /* Total write cycle time */

};

static struct omap_fifo_platform_data fifo_data = {

.cs = 1,

.gpmc_t = &fifo_timings,

.devsize = 16,

.elm_used = true,

};

static struct gpmc_devices_info gpmc_device[2] = {

{ .pdata = &fifo_data, .flag = GPMC_DEVICE_NOR },

{ NULL, 0 }, /* reserved */

};

3、添加初始化函数fifo_init(),调用setup_pin_mux()使引脚配置生效,调用omap_init_gpmc()与omap_init_elm()初始化GPMC,这一步是必须的,否则GPMC相关的函数不能使用。

static void fifo_init(int evm_id, int profile)

{

setup_pin_mux(fifo_pin_mux);

omap_init_gpmc(gpmc_device, sizeof(gpmc_device));

omap_init_elm();

return;

}

3、在结构体evm_dev_cfg sbc8600_dev_cfg[]中添加

{fifo_init, DEV_ON_BASEBOARD, PROFILE_ALL},

系统初始化的时候会调用下面的函数:

_configure_device(EVM_SK, sbc8600_dev_cfg, PROFILE_NONE);

4、注意事项

引脚配置不应有冲突,即不应有两个或以上的驱动配置相同的引脚,同一个引脚不应被配置两次或多次不同的数值。

5、编译内核,生成uImage文件,下载到开发板上。

四、驱动设计

1、除一般驱动所要的头文件外,还需包含的头文件

#include

#include

#include

#include

#include

2、定义片选号、GPIO引脚等

/* GPMC chip select */

#define GPMC_CS         4

#define NONE_MUXADDATA  ~(0x03 << 8)

/* GPIO pin */

#define GPIO_TO_PIN(bank, gpio)     ((32 * (bank)) + (gpio))

#define GPMC_CSN1_RESET  GPIO_TO_PIN(1, 30) /*FIFO reset*/

#define GPMC_DEVICE_NAME "mygpmc"

#define GPMC_DRIVER_NAME "gpmc_write"

#define FIFO_SIZE SZ_8K

#define BUF_SIZE 1024

3、  配置时序信息

static struct gpmc_timings fifo_timings = {/*GPMC timing configurations*/

.sync_clk = 0,

.cs_on = 0,             /* Assertion time */

.cs_rd_off = 82,      /* Read deassertion time */

.cs_wr_off = 82,     /* Write deassertion time */

.we_on = 40,   /* WE assertion time */

.we_off  = 40,       /* WE deassertion time */

.oe_on = 40,    /* OE assertion time */

.oe_off = 40,   /* OE deassertion time */

.access = 50,   /* Start-cycle to first data valid delay */

.rd_cycle = 82,       /* Total read cycle time */

.wr_cycle = 82,      /* Total write cycle time */

};

4、  配置GPMC寄存器

/*Chip-select configuration (base and mask address or any protocol and timing settings) must be performed while the associated chip-select is disabled through the GPMC_CONFIG7_i[6] CSVALID bit. In addition, a chip-select configuration can only be disabled if there is no ongoing access to that chip-select.*/

val = gpmc_cs_read_reg(GPMC_CS, GPMC_CS_CONFIG7);

val &= ~GPMC_CONFIG7_CSVALID; /*disable chip-select*/

gpmc_cs_write_reg(GPMC_CS, GPMC_CS_CONFIG7, val);

gpmc_cs_configure(GPMC_CS, GPMC_SET_IRQ_STATUS, 0); /*set irq status*/

gpmc_cs_configure(GPMC_CS, GPMC_ENABLE_IRQ, 0); /*disable irqs*/

gpmc_cs_write_reg(GPMC_CS,GPMC_CS_CONFIG1, GPMC_CONFIG1_READTYPE_ASYNC  | /*set read type Asynchronous*/

GPMC_CONFIG1_WRITETYPE_ASYNC  | /*set write type Asynchronous*/

GPMC_CONFIG1_DEVICESIZE_16      | /*set device size 16bit*/

GPMC_CONFIG1_DEVICETYPE_NOR   | /*set device type NOR*/

GPMC_CONFIG1_FCLK_DIV3);    /*GPMC_CLK frequency=GPMC_FCLK frequency/3*/

val = gpmc_cs_read_reg(GPMC_CS, GPMC_CS_CONFIG1);

val &= NONE_MUXADDATA; /*Non-multiplexed attached device*/

gpmc_cs_write_reg(GPMC_CS, GPMC_CS_CONFIG1, val);

ret = gpmc_cs_set_timings(GPMC_CS, &fifo_timings); /*set timing parameters*/

这段代码编译时可能会提示gpmc_cs_write_reg、 gpmc_cs_read_reg、 gpmc_cs_set_timings这几个函数undefined,这时需要在mach-omap2/gpmc.c文件中找到这些函数,并在函数定义的末尾添加EXPORT_SYMBOL(gpmc_cs_write_reg);

EXPORT_SYMBOL(gpmc_cs_read_reg); EXPORT_SYMBOL(gpmc_cs_set_timings);

重新编译内核,下载到开发板上。

5、  申请gpmc片选空间并用ioremap函数映射为内核虚拟地址

/***********为FIFO申请GPMC chip-select空间**********/

if (gpmc_cs_request(GPMC_CS, FIFO_SIZE, &mem_base)<0)

{

printk(KERN_ERR "gpmc_cs_request failed.\n");

return -1;

}

/***********为FIFO申请虚拟内存空间**********/

if (!request_mem_region(mem_base, FIFO_SIZE, GPMC_DRIVER_NAME))

{

printk(KERN_ERR "request_mem_region failed.\n");

return -1;

}

/******物理地址映射为虚拟地址*****/

fifo_base = ioremap (mem_base, FIFO_SIZE);

6、  完成以上步骤后,就可以对fifo进行读写了

writew(gpmc_dev.user_buff[i], fifo_base);

gpmc_dev.user_buff[i] = readw(fifo_base);

FIFO是一个none ramdom access的器件,每次的读写操作都基于同一个地址。

7、  中断

GPMC有中断但是内部中断,只有wait0与wait1引脚是外部中断,而wait引脚通常连接外设的ready引脚,所以采用GPIO引脚来产生中断:

GPIO引脚号转换为中断号: irq_num = gpio_to_irq(gpio_pin);

设置中断出发方式为下降沿触发

irq_set_irq_type(irq_num, IRQF_TRIGGER_FALLING);

申请中断:

request_irq(irq_num, irq_proc, IRQF_DISABLED, GPIO_DEVICE_NAME, NULL);

中断处理函数:

static irqreturn_t irq_proc(int irq, void *dev_id)

{

//    your code

return IRQ_HANDLED;

}

中断类型IRQF_DISABLED表示此中断处理函数调用时,屏蔽所有中断,更多信息可在头文件 与中找到。

8、  释放GPMC、 GPIO资源

release_mem_region(mem_base, FIFO_SIZE);

gpmc_cs_free(GPMC_CS);

iounmap(fifo_base);

gpio_free(gpio_pin);

9、释放中断资源

free_irq(irq_num, NULL);

10、驱动源程序

见附件

五、Makefile

ARCH=arm

CROSS_COMPILE=/opt/arm-2009q1/bin/arm-none-linux-gnueabi-

KERNELDIR := /home/linfan/linux-3.2.0-for-write

obj-m      := gpmc_write.o

PWD       := $(shell pwd)

default:

$(MAKE) -C $(KERNELDIR) M=$(PWD) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) modules

app:

arm-none-linux-gnueabi-gcc test_write.c -o write

clean:

rm -rf *.o *.ko *.mod.c *.symvers *.order

六、用户空间应用程序

见附件

七、总结

AM3359的驱动设计要在board-am335xevm.c中定义设备和配置引脚,然后再编译内核,生成映像文件,颇有不便之处。我在编写这个驱动时,大部分时间花在修改内核源码及编译内核之上。

GPMC驱动设计的关键是要正确配置相关的寄存器,否则得不到想要的运行结果。对于NOR类型的器件,只需配置GPMC_CONFIG1~ GPMC_CONFIG7这几个寄存器就可以了;对于NAND类型的器件,还需配置prefetch、ECC engine等的内容。我在写这个驱动时,由于在GPMC_CONFIG1中配置了同步读写,以及一些时序上的不正确配置,一直不能往/从FIFO读写数据,后来通过FIFO datasheet的研究,才发现并解决这个问题的。

Linux3.2.0内核源码中有gpmc.h与 gpmc.c文件,里面的函数对GPMC的支持还是比较全面的,但要使用这些函数,还要先调用omap_init_gpmc()与omap_init_elm()初始化GPMC device,否则无法调用insmod加载驱动模块。有些函数明明在gpmc.c文件中有定义,但编译时却提示undefined,对于这个问题,我的解决办法是,对于非static函数,调用EXPORT_SYMBOL()来导出这些函数。编译内核时,会在module.symvers文件中生成相应的symbol。当编译驱动模块时,编译器自动进入你指定的Linux内核源码目录,而你的驱动中的系统调用则由编译器在module.symvers文件中查找,如果找不到,则会提示undefined。

我曾试图自己编写配置GPMC寄存器的函数,方法是根据technical reference manual里的memory map找到GPMC寄存器的地址,通过ioremap函数转换为内核虚拟地址,然后调用writel(),readl()之类的函数将配置data写进寄存器中。但编写起来所遇到的问题比解决的问题还多,要考虑的方面很多,是一个浩大的工程。对于编写一个小程序测试一下还是容易的,当你的工程比较大的时候,这个工作就显得困难了,而且代码的可读性与可移植性都比较差。所以还是使用系统自带的函数来操作好,毕竟是经过原厂编译并测试通过的,可靠性稳定性都比较高。

AM3359 中利用GPMC控制器驱动FIFO相关推荐

  1. u盘安装linux找不到驱动,利用U盘加载控制器驱动来安装Linux系统的方法

    一般我们在安装服务器过程中需要加载一些scsi卡或raid卡驱动,以便操作系统可以检测到硬盘. 常规的安装方式是要用到软驱,其实我们也是可以通过U盘来进行加载的. 装Linux控制器驱动往往都是*.d ...

  2. 详解sd协议以及裸机和u-boot中的sd卡驱动(2)

    3. sd卡驱动 3.1 引入 经过第2章我们知道,要想实现读写sd卡,需要按照sd协议规定的基本传输单位(命令.响应.数据)以及流程(初始化.读.写),向sd卡发送信号或者从sd卡接收信号. 为了简 ...

  3. i2c--ioctl--主机控制器驱动(i2c_adapter)--外设驱动(i2c_driver)

    updating... i2c驱动目录 [root@localhost i2c]# pwd /opt/FriendlyArm/mini2440/linux-2.6.32.2/drivers/i2c [ ...

  4. 中国电信北京研究院副院长陈运清:网络云化推进中技术和商业驱动场景探讨...

    由天地互连.下一代互联网国家工程中心主办的"2017全球SDNFV技术大会" (2017.chinasdn.org)于 2017年8月2-3日,在北京国宾酒店火热开幕.在3日上午的 ...

  5. Linux SPI驱动框架(2)——控制器驱动层

    SPI控制器驱动层   上节中,讲了SPI核心层的东西,这一部分,以全志平台SPI控制器驱动为例,对SPI控制器驱动进行说明. SPI控制器驱动,即SPI硬件控制器对应的驱动,核心部分需要实现硬件SP ...

  6. 在Unreal引擎中利用实现实时动作捕捉

    在Unreal引擎中利用实现实时动作捕捉 前言: 准备的软件: 准备工作: 为motionbuilder安装livelink插件: 演员及Motionbuilder准备: 捕捉流程 将Motionbu ...

  7. Linux SPI子系统(3):SPI控制器驱动层

    目录 1. 前言 2. SPI控制器驱动 2.1 dts 2.2 匹配注册 2.3 probe函数 2.4 数据收发函数:spi_st_transfer_one 2.5 中断处理程序:spi_st_i ...

  8. linux卸载cf卡命令,嵌入式Linux 中CF卡的驱动和管理技术研究

    在嵌入式Linux系统中,为了在没有PCMCIA控制器的情况下仍然要利用CompactFlash存储卡(简称CF卡)作为存储设备,作者从CF卡的硬件特性入手,在系统层基于CF卡的memory寻址访问方 ...

  9. java jmf 视屏监控的核心代码_Java中利用JMF编写摄像头拍照程序_java

    我把程序分为两种,有趣的和无趣的,最近做了几个有趣的项目,其中一个,应当就算是摄像头拍照程序了.用于现场拍照,生成照片,主要用到java Media Framework(JMF). 首先到SUN下载最 ...

  10. Linux SPI总线和设备驱动架构之三:SPI控制器驱动

    通过第一篇文章,我们已经知道,整个SPI驱动架构可以分为协议驱动.通用接口层和控制器驱动三大部分.其中,控制器驱动负责最底层的数据收发工作,为了完成数据的收发工作,控制器驱动需要完成以下这些功能: 1 ...

最新文章

  1. 纯干货!文字识别在高德地图数据生产中的演进
  2. ASP.NET Core管道深度剖析
  3. C语言库函数大全及应用实例三
  4. linux中的lock文件,linux – 为什么即使文件被锁定,File :: FcntlLock的l_type总是“F_UNLCK”?...
  5. java性能调试命令_性能测试必备监控技能jvm之jdk命令行工具篇16
  6. findwindowex子窗口类型有哪几种_游戏场景该怎么画?来参考一下不同的类型吧
  7. 计算机语言语法语义,程序设计语言语义
  8. Apollo阿波罗配置中心基本概述
  9. win10设置pg/pc接口_win10安装postgresql
  10. UEFI启动+GPT分区
  11. 51单片机实战教程之C语言基础(一 创建Keil Project)
  12. 深入浅出 proxy 系列之一:Proxy 是什么
  13. 微软输入法怎么最小化到托盘_微软推出 Windows 10X 系统模拟器,未来的双屏电脑系统长这样?...
  14. 微信开发实战(2)—微信公众平台接口调试工具
  15. 剧场版动画《巨虫列岛》1月上映决定!
  16. 实用又好用,6 款 Python 特殊文本格式处理库推荐
  17. 操作系统学习- 二 -同步-信号量(semaphore)
  18. 实验报告:RC电路的充放电过程仿真实验
  19. 基于vue+element实现多级菜单动态生成
  20. Cloud Design Pattern - Circuit Breaker Pattern(断路器模式)

热门文章

  1. 江坪水利枢纽工程施工组织设计——碾压混凝土围堰
  2. 受疫情影响,全国多地影院密钥暂停供给,《长津湖》将面临改档
  3. 为了让女儿学打字,开发了个免费的打字网站
  4. java操作excel文件_利用Java Excel API读写excel文件
  5. oracle如何把多条放单条,oracle利用游标单条插入数据举例
  6. 『最小生成树』Kruskal算法——加边法 (并查集优化 + C++语言编写 + 例题)
  7. Camtasia Studio2024破解版注册机
  8. 尽享网wordpress微门户主题 Red SOHO一族使用方法教程
  9. 前端电商项目常用组件——放大镜
  10. Kaggle入门——Titanic+随机森林(调参)+逻辑回归