zoukankan      html  css  js  c++  java
  • DM8168通过GPMC接口与FPGA高速数据通信实现

    硬件:TI达芬奇TMS320DM8168(以下简称DSP)、EP4CE6E22C8N(以下简称FPGA)

    软件:linux-2.6.37

    转载请注明出处~

    http://www.cnblogs.com/imapla/p/4122609.html 

        近期项目需要实现DSP与FPGA之间的高速数据交换,用到了DM8168的GPMC接口。这部分的中文资料网上还是比较少的,于是苦苦研究芯片的数据手册和参考指南,最近终于有所成果,在Linux下调用GPMC驱动函数调通了GPMC接口,因此发出调试过程与大家分享。目前以DSP端可以通过GPMC用EDMA的方式读取FPGA端的数据,读取8KB字节大概用了235us,即34MB/s的速度,实际上通过配置GPMC接口的时间参数,速度还可以更快。

        GPMC的全称是 General-Purpose Memory Controller,即通用存储控制器,是TI的DSP芯片DM8168用来与外部存储设备例如NOR FLASH、NAND FLASH、SRAM等等通信的一个接口。这个接口并不是DM8168特有的,在BeagleBone Black、AM35XX芯片上也有类似接口。

    1、硬件连接方式:在DM8168中GPMC接口时钟在异步模式下为125MHz,这里就把GPMC接口配置为异步模式并设置NOR FLASH、非地址数据线复用的模式与FPGA通信,但只用16位数据线,不用地址线,即采用类似于FIFO的方式与FPGA通信。目前实际只使用到了如下I/O口:

        GPMC_CS3:  用CS3做片选信号
        GPMC_OEN:  输出使能时钟
        D[15:0]:   16位数据总线
        FIFO_RRST: 用于通知FPGA读指针复位

     

    2、接口协议:采用异步方式读取,即不使用GPMC_CLK,FPGA端在GPMC_OEN的下降沿把数据送出去。

     

    3、Linux下DSP端代码分析

        Linux中gpmc驱动源代码在 /arch/arm/mach-omap2/gpmc.c

        配置方面主要包括与GPMC相关的7个特殊寄存器,其实linux函数中已经把相关配置封装成了函数,我们只需要调用相关函数就可以。

        EDMA的配置也是如此,需要注意的是,EDMA中配置的地址都为物理地址,即DMA传送到源端为外设的地址即GPMC的物理地址,目的地端为你申请的内存空间物理地址。由于DSP是使用FIFO模式读取FPGA端数据的,所以EDMA还需配置源地址为不自增模式。代码如下,内容不多,所以不做详细注释。

        FPGA端的代码只要是实现在每个OEN信号下降沿来的时候,把16bit的数据送到GPMC_DATA端口,并自加一次。

    GPMC配置代码如下

    static struct gpmc_timings fpga_timings = {
        /*- GPMC timing configurations -*/
        .sync_clk = 0,
        // CONFIG2 chip-select time
        .cs_on = 0,         /* Assertion time */
        .cs_rd_off = 50,    /* Read deassertion time */
        .cs_wr_off = 50,    /* Write deassertion time */
        // CONFIG3
        .adv_on = 0,
        .adv_rd_off = 0,
        .adv_wr_off = 0,
        // CONFIG4
        .we_on = 20,        /* WE assertion time */
        .we_off  = 20,      /* WE deassertion time */
        // CONFIG4
        .oe_on = 20,        /* OE assertion time */
        .oe_off = 20,       /* OE deassertion time */
        // CONFIG5
        .page_burst_access = 0,
        .access = 30,       /* Start-cycle to first data valid delay */
        .rd_cycle = 50,     /* Total read cycle time */
        .wr_cycle = 50,     /* Total write cycle time */
        // CONFIG6
        .wr_access = 0,
        .wr_data_mux_bus = 0,
    };
    static int gpmc_config(void)
    {
        // first reg gpmc_init() already called; io pinmux already configed
        // ti8168evm board_nand_init -> gpmc_nand_init
        u32 val = 0;
        int err = 0;
    /*-
    EXPORT_SYMBOL(gpmc_cs_write_reg);
    EXPORT_SYMBOL(gpmc_cs_read_reg);
    EXPORT_SYMBOL(gpmc_cs_set_timings);
    -*/
        // gpmc cs disable memory
        val = gpmc_cs_read_reg(GPMC_FPGA_CS, GPMC_CS_CONFIG7);
        val &= ~GPMC_CONFIG7_CSVALID;
        gpmc_cs_write_reg(GPMC_FPGA_CS, GPMC_CS_CONFIG7, val);
    
        // disable cs3 irq
        gpmc_cs_configure(GPMC_FPGA_CS, GPMC_SET_IRQ_STATUS, 0);
        gpmc_cs_configure(GPMC_FPGA_CS, GPMC_ENABLE_IRQ, 0);
    
        // set config1
        gpmc_cs_write_reg(GPMC_FPGA_CS, GPMC_CS_CONFIG1, GPMC_CONFIG1_READTYPE_ASYNC|  // set read type async
            GPMC_CONFIG1_WRITETYPE_ASYNC| // set write type async
            GPMC_CONFIG1_DEVICESIZE_16|   // set device size 16bit
            GPMC_CONFIG1_DEVICETYPE_NOR   // set device type nor
        );
        val = gpmc_cs_read_reg(GPMC_FPGA_CS, GPMC_CS_CONFIG1);
        val &= ~GPMC_CONFIG1_MUXADDDATA;
        gpmc_cs_write_reg(GPMC_FPGA_CS, GPMC_CS_CONFIG1, val);
     
        // set gpmc timings
        err = gpmc_cs_set_timings(GPMC_FPGA_CS, &fpga_timings);
        if(err < 0){
            printk(KERN_ERR "Unable to set gpmc timings
    ");
        }
    
        // apply gpmc select memory
        err = gpmc_cs_request(GPMC_FPGA_CS, GPMC_FIFO_SIZE, &gpmc_membase);
        if(err < 0){
            printk(KERN_ERR "Cannot request GPMC CS
    ");
            return err;
        }
    
     //   request_mem_region(gpmc_membase, GPMC_FIFO_SIZE, DRIVERNAME);
    
     //   fpga_membase = ioremap(gpmc_membase, GPMC_FIFO_SIZE);
    
        return err;
    }

     

    下面是总的代码,折叠了。

      1 /*
      2 * fileName: fpga_perh.c
      3 * for gpmc fpga communication
      4 */
      5 #include <linux/device.h>
      6 #include <linux/fs.h>
      7 #include <linux/module.h>
      8 #include <linux/kernel.h>
      9 #include <linux/init.h>
     10 #include <linux/moduleparam.h>
     11 #include <linux/list.h>
     12 #include <linux/cdev.h>
     13 #include <linux/proc_fs.h>
     14 #include <linux/mm.h>
     15 #include <linux/seq_file.h>
     16 #include <linux/ioport.h>
     17 #include <linux/delay.h>
     18 #include <asm/io.h>
     19 #include <linux/io.h>
     20 #include <mach/gpio.h>
     21 #include <linux/device.h>
     22 #include <linux/platform_device.h>
     23 // gpmc spec
     24 #include <plat/gpmc.h>
     25 // edma spec
     26 #include <linux/interrupt.h>
     27 #include <linux/dma-mapping.h>
     28 #include <mach/memory.h>
     29 #include <mach/hardware.h>
     30 #include <mach/irqs.h>
     31 #include <asm/hardware/edma.h>
     32 
     33 #define DRIVERNAME  "fpga"
     34 
     35 // once_dma = 8KByte = 4*1024*16bit 
     36 #define FPGA_FIFO_SIZE SZ_4K
     37 
     38 /*------------------------------------------------------------------------------------------------------------------*/
     39 // GPMC Config
     40 #define GPMC_FIFO_SIZE SZ_16K
     41 
     42 #define GPMC_FPGA_CS   3           // gpmc use CS 3
     43 #define GPMC_CONFIG1_3 0x00001010  // 16bit size NOR FLASH like
     44 #define GPMC_CONFIG2_3 0x00101080  // CSWROFFTIME=16cy   CSRDOFFTIME=16cy     CSEXTRADELAY=1
     45 #define GPMC_CONFIG3_3 0x00000000  // ADV TIME used
     46 #define GPMC_CONFIG4_3 0x0F031003  // WEOFFTIME=15cy     WEONTIME=3cy         OEOFFTIME=16cy       OEONTIME=3cy
     47 #define GPMC_CONFIG5_3 0x000F1111  // RDACCESSTIME=15cy  WRCYCLETIME=1cy      RDCYCLETIME=1cy
     48 #define GPMC_CONFIG6_3 0x0F030000  // WRACCESSTIME=15cy  WRDATAONADMUXBUS=3cy Add CYCLE2CYCLEDELAY
     49 #define GPMC_CONFIG7_3 0x00000F42  // set up CONFIG7 and enable cs3
     50 // chip-select mask address = MASKADDRESS = 16MB
     51 // CS enabled
     52 // Chip-select base address = BASEADDRESS = 0x02000000
     53 // Access address 0x02000000-0x02FFFFFF
     54 #define GPMC_MASKADDRESS 0x00FFFFFF  // fifo_size
     55 #define GPMC_BASEADDRESS 0x02000000  // gpmc address
     56 /*------------------------------------------------------------------------------------------------------------------*/
     57 // FPGA GPIOs
     58 #define CTRL_MODULE_BASE_ADDR    0x48140000
     59 #define conf_gpio18              (CTRL_MODULE_BASE_ADDR + 0x0B98)
     60 #define conf_gpio19              (CTRL_MODULE_BASE_ADDR + 0x0B9C)
     61 
     62 #define WR_MEM_32(addr, data)    *(unsigned int*)OMAP2_L4_IO_ADDRESS(addr) = (unsigned int)(data)
     63 #define RD_MEM_32(addr)          *(unsigned int*)OMAP2_L4_IO_ADDRESS(addr)
     64 
     65 // delay for reset
     66 #define _delay_ms(n)   mdelay(n) 
     67 #define _delay_ns(n)   ndelay(n) 
     68 
     69 // Read Point Low is Reset
     70 #define FPGA_RRST_H gpio_set_value(18, 1);
     71 #define FPGA_RRST_L gpio_set_value(18, 0);
     72 /*------------------------------------------------------------------------------------------------------------------*/
     73 // EDMA Config
     74 #define MAX_DMA_TRANSFER_IN_BYTES  (4096*2)
     75 #define STATIC_SHIFT               3
     76 #define TCINTEN_SHIFT              20  
     77 #define ITCINTEN_SHIFT             21
     78 #define TCCHEN_SHIFT               22
     79 #define ITCCHEN_SHIFT              23
     80 /*------------------------------------------------------------------------------------------------------------------*/
     81 //unsigned int fpga_buf[FPGA_FIFO_SIZE] = {0};
     82 static unsigned long gpmc_membase = 0;
     83 static void __iomem *fpga_membase = 0;
     84 static int gpio[2];
     85 dma_addr_t dmaphysdest = 0;
     86 unsigned short *fpga_buf = NULL;
     87 unsigned int dma_ch = 0;
     88 static volatile int irqraised1 = 0;
     89 
     90 static struct gpmc_timings fpga_timings = {
     91     /*- GPMC timing configurations -*/
     92     .sync_clk = 0,
     93     // CONFIG2 chip-select time
     94     .cs_on = 0,         /* Assertion time */
     95     .cs_rd_off = 50,    /* Read deassertion time */
     96     .cs_wr_off = 50,    /* Write deassertion time */
     97     // CONFIG3
     98     .adv_on = 0,
     99     .adv_rd_off = 0,
    100     .adv_wr_off = 0,
    101     // CONFIG4
    102     .we_on = 20,        /* WE assertion time */
    103     .we_off  = 20,      /* WE deassertion time */
    104     // CONFIG4
    105     .oe_on = 20,        /* OE assertion time */
    106     .oe_off = 20,       /* OE deassertion time */
    107     // CONFIG5
    108     .page_burst_access = 0,
    109     .access = 30,       /* Start-cycle to first data valid delay */
    110     .rd_cycle = 50,     /* Total read cycle time */
    111     .wr_cycle = 50,     /* Total write cycle time */
    112     // CONFIG6
    113     .wr_access = 0,
    114     .wr_data_mux_bus = 0,
    115 };
    116 
    117 // static         dev_t  dev;
    118 // static struct  cdev   cdev;
    119 // static struct  class  *gpmc_edma_class = NULL;
    120 
    121 static void callback1(unsigned lch, u16 ch_status, void *data)
    122 {
    123     switch(ch_status) {
    124     case DMA_COMPLETE:
    125         irqraised1 = 1;
    126         /*DMA_PRINTK ("
     From Callback 1: Channel %d status is: %u
    ", lch, ch_status);*/
    127         break;
    128     case DMA_CC_ERROR:
    129         irqraised1 = -1;
    130         printk ("
    From Callback 1: DMA_CC_ERROR occured on Channel %d
    ", lch);
    131         break;
    132     default:
    133         break;
    134     }
    135 }
    136 
    137 static int gpio_store(void);
    138 static int gpio_recover(void);
    139 static int gpio_config(void);
    140 static int gpmc_config(void);
    141 static int edma_config(void);
    142 
    143 static int gpio_store(void)
    144 {
    145     // store gpio pinmux
    146     gpio[0] = RD_MEM_32(conf_gpio18);
    147     gpio[1] = RD_MEM_32(conf_gpio19);
    148     return 0;
    149 }
    150 
    151 static int gpio_recover(void)
    152 {
    153     // recover gpio pinmux
    154     WR_MEM_32(conf_gpio18, gpio[0]);
    155     WR_MEM_32(conf_gpio19, gpio[1]);
    156     gpio_free(gpio[0]);
    157     gpio_free(gpio[1]);
    158     return 0;
    159 }
    160 
    161 static int gpio_config(void)
    162 {
    163     // config gpio direction
    164     WR_MEM_32(conf_gpio18, 1);           // MUXMODE=001
    165     gpio_request(18, "gpio18_en");       // request gpio46
    166     gpio_direction_output(18, 1);
    167 
    168     WR_MEM_32(conf_gpio19, 1);           // MUXMODE=001
    169     gpio_request(19, "gpio19_en");       // request gpio47
    170     gpio_direction_output(19, 1);
    171 
    172     return 0;
    173 }
    174 
    175 static int gpmc_config(void)
    176 {
    177     // first reg gpmc_init() already called; io pinmux already configed
    178     // ti8168evm board_nand_init -> gpmc_nand_init
    179     u32 val = 0;
    180     int err = 0;
    181 /*-
    182 EXPORT_SYMBOL(gpmc_cs_write_reg);
    183 EXPORT_SYMBOL(gpmc_cs_read_reg);
    184 EXPORT_SYMBOL(gpmc_cs_set_timings);
    185 -*/
    186     // gpmc cs disable memory
    187     val = gpmc_cs_read_reg(GPMC_FPGA_CS, GPMC_CS_CONFIG7);
    188     val &= ~GPMC_CONFIG7_CSVALID;
    189     gpmc_cs_write_reg(GPMC_FPGA_CS, GPMC_CS_CONFIG7, val);
    190 
    191     // disable cs3 irq
    192     gpmc_cs_configure(GPMC_FPGA_CS, GPMC_SET_IRQ_STATUS, 0);
    193     gpmc_cs_configure(GPMC_FPGA_CS, GPMC_ENABLE_IRQ, 0);
    194 
    195     // set config1
    196     gpmc_cs_write_reg(GPMC_FPGA_CS, GPMC_CS_CONFIG1, GPMC_CONFIG1_READTYPE_ASYNC|  // set read type async
    197         GPMC_CONFIG1_WRITETYPE_ASYNC| // set write type async
    198         GPMC_CONFIG1_DEVICESIZE_16|   // set device size 16bit
    199         GPMC_CONFIG1_DEVICETYPE_NOR   // set device type nor
    200     );
    201     val = gpmc_cs_read_reg(GPMC_FPGA_CS, GPMC_CS_CONFIG1);
    202     val &= ~GPMC_CONFIG1_MUXADDDATA;
    203     gpmc_cs_write_reg(GPMC_FPGA_CS, GPMC_CS_CONFIG1, val);
    204  
    205     // set gpmc timings
    206     err = gpmc_cs_set_timings(GPMC_FPGA_CS, &fpga_timings);
    207     if(err < 0){
    208         printk(KERN_ERR "Unable to set gpmc timings
    ");
    209     }
    210 
    211     // apply gpmc select memory
    212     err = gpmc_cs_request(GPMC_FPGA_CS, GPMC_FIFO_SIZE, &gpmc_membase);
    213     if(err < 0){
    214         printk(KERN_ERR "Cannot request GPMC CS
    ");
    215         return err;
    216     }
    217 
    218  //   request_mem_region(gpmc_membase, GPMC_FIFO_SIZE, DRIVERNAME);
    219 
    220  //   fpga_membase = ioremap(gpmc_membase, GPMC_FIFO_SIZE);
    221 
    222     return err;
    223 }
    224 
    225 static int edma_config(void)
    226 {
    227     // use AB mode, one_dma = 8KB/16bit
    228     static int acnt = 4096*2;
    229     static int bcnt = 1;
    230     static int ccnt = 1;
    231 
    232     int result = 0;
    233     unsigned int BRCnt = 0;
    234     int srcbidx = 0;
    235     int desbidx = 0;
    236     int srccidx = 0;
    237     int descidx = 0;
    238     struct edmacc_param param_set;
    239 
    240     printk("Initializing dma transfer...
    ");
    241 
    242     // set dest memory
    243     fpga_buf  = dma_alloc_coherent (NULL, MAX_DMA_TRANSFER_IN_BYTES, &dmaphysdest, 0);
    244     if (!fpga_buf) {
    245         printk ("dma_alloc_coherent failed for physdest
    ");
    246         return -ENOMEM;
    247     }
    248 
    249     /* Set B count reload as B count. */
    250     BRCnt = bcnt;
    251 
    252     /* Setting up the SRC/DES Index */
    253     srcbidx = 0;
    254     desbidx = acnt;
    255 
    256     /* A Sync Transfer Mode */
    257     srccidx = 0;
    258     descidx = acnt;
    259  
    260     // gpmc channel
    261     result = edma_alloc_channel (52, callback1, NULL, 0);
    262     
    263     if (result < 0) {
    264         printk ("edma_alloc_channel failed, error:%d", result);
    265         return result;
    266     }
    267      
    268     dma_ch = result;
    269     edma_set_src (dma_ch, (unsigned long)(gpmc_membase), INCR, W16BIT);
    270     edma_set_dest (dma_ch, (unsigned long)(dmaphysdest), INCR, W16BIT);
    271     edma_set_src_index (dma_ch, srcbidx, srccidx);   // use fifo, set zero
    272     edma_set_dest_index (dma_ch, desbidx, descidx);  // A mode
    273 
    274     // A Sync Transfer Mode
    275     edma_set_transfer_params (dma_ch, acnt, bcnt, ccnt, BRCnt, ASYNC);
    276 
    277     /* Enable the Interrupts on Channel 1 */
    278     edma_read_slot (dma_ch, &param_set);
    279     param_set.opt |= (1 << ITCINTEN_SHIFT);
    280     param_set.opt |= (1 << TCINTEN_SHIFT);
    281     param_set.opt |= EDMA_TCC(EDMA_CHAN_SLOT(dma_ch));
    282     edma_write_slot (dma_ch, &param_set);
    283 
    284     return 0;
    285 }
    286 
    287 static int __init fpga_perh_init(void)
    288 {
    289     unsigned int cnt;
    290     u32 val = 0;
    291     int ret = 0;
    292     int chk = 0;
    293 
    294     gpio_store();     // GPIO初始化
    295     gpio_config();
    296     gpmc_config();    // GPMC配置
    297     edma_config();    // EDMA配置
    298 
    299     for(cnt=0; cnt<7; cnt++){
    300         val = gpmc_cs_read_reg(GPMC_FPGA_CS, GPMC_CS_CONFIG1 + cnt*0x04);
    301         printk("GPMC_CS3_CONFIG_%d : [%08X]
    ", cnt+1, val);
    302     }
    303 
    304     printk("Gpmc now start reading...
    ");
    305 
    306     FPGA_RRST_L;
    307     _delay_ns(1);   // 1us
    308     FPGA_RRST_H;
    309 
    310 
    311     ret = edma_start(dma_ch);
    312     
    313     if (ret != 0) {
    314         printk ("dm8168_start_dma failed, error:%d", ret);
    315         return ret;
    316     }
    317 
    318     // wait for completion ISR
    319     while(irqraised1 == 0u){
    320         _delay_ms(10);
    321  //       break;
    322     }
    323 
    324 
    325     if (ret == 0) {
    326         for (cnt=0; cnt<FPGA_FIFO_SIZE; cnt++) {
    327 //            fpga_buf[cnt] = readw(fpga_membase);
    328             if (fpga_buf[cnt] != cnt+1) {            // 进行数据校验
    329                 chk = cnt+1;
    330                 break;
    331             }
    332         }
    333         edma_stop(dma_ch);
    334         edma_free_channel(dma_ch);
    335     }
    336 
    337     if (chk == 0){
    338         printk ("Gpmc&edma reading sequence data check successful!
    ");
    339     }else{
    340         printk ("Gpmc&edma reading data check error at: %d
    ", chk);
    341     }
    342 
    343     for(cnt=0; cnt<8; cnt++){
    344         printk("[%04X] [%04X] [%04X] [%04X]
    ", fpga_buf[cnt*4], fpga_buf[cnt*4+1], fpga_buf[cnt*4+2], fpga_buf[cnt*4+3]);
    345     }
    346 
    347 //    gpmc_cs_free(GPMC_FPGA_CS);  
    348     return 0;
    349 }
    350 module_init(fpga_perh_init);
    351 
    352 static void __exit fpga_perh_exit(void)
    353 {
    354     gpio_recover();
    355     // free CS3
    356     gpmc_cs_free(GPMC_FPGA_CS); 
    357     dma_free_coherent (NULL, MAX_DMA_TRANSFER_IN_BYTES, fpga_buf, dmaphysdest);
    358     printk("fpga_perh exit!
    ");
    359 }
    360 module_exit(fpga_perh_exit);
    361 
    362 MODULE_LICENSE("GPL");
    View Code

    4、实验结果

        1.代码编译后通过insmod加载驱动,抓取CS3和OEN的波形如下,刚开始设计时没有用到EDMA传送,只是在linux循环读取,可以看见每个周期里片选信号CS3都会维持很长一段高电平的时间,GPMC一次的读取周期大概为250ns。

    通道1为片选信号CS3,通道2为输出使能信号OEN

    这样的速率大概只有 16bit / 250ns = 8MBytes/s

        2.使用EDMA传送,这下读周期就小了很多了,只有57.6ns,和GPMC参数里设置的几乎一致。

        3.传送8KBytes即4096次,大概用了235us,速率为 8KBytes / 235us = 34MB/s

        4.fpga端使用signaltap抓取波形如下,可以看见GPMC_DATA为从1开始的自加顺序序列

        5.Linux端读取数据并做校验,还打印出了GPMC的7个寄存器的内容。校验通过,说明数据一致性正确!至此DSP与FPGA通过GPMC接口用EDMA实现数据高速传输,验证可行!

      

        总结,FPGA端代码比较简单就不上传了,如有需要欢迎交流。

        DM8168这款DSP芯片,本人刚接手开发也就两个月,文中若有不对之处欢迎指出。

        FPGA工程

    参考资料:

    http://blog.csdn.net/hailin0716/article/details/26553389

    http://blog.chinaunix.net/uid-28818752-id-3655729.html

    http://blog.chinaunix.net/uid-28818752-id-3749701.html

    http://blog.chinaunix.net/uid-28818752-id-3750016.html

     

    联系本人:

    hihuanglong艾特foxmail.com

    有任何问题,欢迎加入 TI DSP 技术交流 QQ 群:652563558

  • 相关阅读:
    web服务器,应用程序服务器,http服务器的区别
    tomcat、weblogic、jboss的区别,容器的作用
    linux系统编辑神器 -vim用法大全
    web弹出对话框
    c#获取打印机列表
    cookie
    lodop打印多页
    lodop判断是否打印成功
    一般处理程序
    让图片在div中居中
  • 原文地址:https://www.cnblogs.com/imapla/p/4122609.html
Copyright © 2011-2022 走看看