DM8168經過GPMC接口與FPGA高速數據通訊實現

硬件:TI達芬奇TMS320DM8168(如下簡稱DSP)、EP4CE6E22C8N(如下簡稱FPGA)html

軟件:linux-2.6.37linux

轉載請註明出處~app

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

    近期項目須要實現DSP與FPGA之間的高速數據交換,用到了DM8168的GPMC接口。這部分的中文資料網上仍是比較少的,因而苦苦研究芯片的數據手冊和參考指南,最近終於有所成果,在Linux下調用GPMC驅動函數調通了GPMC接口,所以發出調試過程與你們分享。目前以DSP端能夠經過GPMC用EDMA的方式讀取FPGA端的數據,讀取8KB字節大概用了235us,即34MB/s的速度,實際上經過配置GPMC接口的時間參數,速度還能夠更快。async

    GPMC的全稱是 General-Purpose Memory Controller,即通用存儲控制器,是TI的DSP芯片DM8168用來與外部存儲設備例如NOR FLASH、NAND FLASH、SRAM等等通訊的一個接口。這個接口並非DM8168特有的,在BeagleBone Black、AM35XX芯片上也有相似接口。ide

一、硬件鏈接方式:在DM8168中GPMC接口時鐘在異步模式下爲125MHz,這裏就把GPMC接口配置爲異步模式並設置NOR FLASH、非地址數據線複用的模式與FPGA通訊,但只用16位數據線,不用地址線,即採用相似於FIFO的方式與FPGA通訊。目前實際只使用到了以下I/O口:函數

    GPMC_CS3:  用CS3作片選信號
    GPMC_OEN:  輸出使能時鐘
    D[15:0]:   16位數據總線
    FIFO_RRST: 用於通知FPGA讀指針復位ui

 

二、接口協議:採用異步方式讀取,即不使用GPMC_CLK,FPGA端在GPMC_OEN的降低沿把數據送出去。spa

 

三、Linux下DSP端代碼分析.net

    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\n"); } // 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\n"); 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 ("\n From Callback 1: Channel %d status is: %u\n", lch, ch_status);*/
127         break; 128     case DMA_CC_ERROR: 129         irqraised1 = -1; 130         printk ("\nFrom Callback 1: DMA_CC_ERROR occured on Channel %d\n", 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\n"); 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\n"); 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...\n"); 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\n"); 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]\n", cnt+1, val); 302  } 303 
304     printk("Gpmc now start reading...\n"); 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!\n"); 339     }else{ 340         printk ("Gpmc&edma reading data check error at: %d\n", chk); 341  } 342 
343     for(cnt=0; cnt<8; cnt++){ 344         printk("[%04X] [%04X] [%04X] [%04X]\n", 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!\n"); 359 } 360 module_exit(fpga_perh_exit); 361 
362 MODULE_LICENSE("GPL");
View Code

四、實驗結果

    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

相關文章
相關標籤/搜索