DM368通过EMIF将数据发送至FPGA,然后FPGA将数据再通过AEMIF接口发送回DM368,自增数没有问题,但是发送视频等实际的数据有问题!
求大神指教!!
代码如下:
驱动代码:emif_cpu.c emif_cpu.h 测试代码:emif_main_cpu.c
测试代码功能:从src.txt文件中读1k的数据,发送至FPGA,然后FPGA再将数据发回至DM368,程序将接收到的数据存在dst.txt文件中。
执行完成后比较src.txt 和dst.txt的数据,看是否有误。
症状:如果src.txt文件里面存的是自增数,收到的数据没有问题;
但是如果src.txt是实际中应用的数据,比如视频数据,则接收到的数据就会有部分出错!!!
!
求大神指教!!
代码如下:
驱动代码:emif_cpu.c emif_cpu.h 测试代码:emif_main_cpu.c
测试代码功能:从src.txt文件中读1k的数据,发送至FPGA,然后FPGA再将数据发回至DM368,程序将接收到的数据存在dst.txt文件中。
执行完成后比较src.txt 和dst.txt的数据,看是否有误。
症状:如果src.txt文件里面存的是自增数,收到的数据没有问题;
但是如果src.txt是实际中应用的数据,比如视频数据,则接收到的数据就会有部分出错!!!
--------------------------------------------------------------------------------------------------------------------------------
驱动代码:emif_cpu.c
/* * edma-test kernel module * * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/ * * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the * distribution. * * Neither the name of Texas Instruments Incorporated nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ /******************************************************************************* * HEADER FILES */ #include <linux/module.h> #include <linux/init.h> #include <linux/mm.h> #include <linux/dma-mapping.h> #include <linux/io.h> #include <linux/types.h> #include <mach/io.h> #include <mach/irqs.h> #include <mach/hardware.h> #include <mach/memory.h> #include <mach/edma.h> #include <mach/aemif.h> #include <linux/fs.h> #include "emif_cpu.h" #include <linux/uaccess.h> MODULE_LICENSE("Dual BSD/GPL"); /******************************************************************************* * LOCAL DEFINES */ /* #undef EDMA3_DEBUG */ #define EDMA3_DEBUG #ifdef EDMA3_DEBUG #define DMA_PRINTK(ARGS...) printk(KERN_INFO "<%s>: ",__FUNCTION__);printk(ARGS) #define DMA_FN_IN printk(KERN_INFO "[%s]: start\n", __FUNCTION__) #define DMA_FN_OUT printk(KERN_INFO "[%s]: end\n",__FUNCTION__) #else #define DMA_PRINTK( x... ) #define DMA_FN_IN #define DMA_FN_OUT #endif //#define MAX_DMA_TRANSFER_IN_BYTES(32768) #define MAX_DMA_TRANSFER_IN_BYTES(128*1024) #define STATIC_SHIFT3 #define TCINTEN_SHIFT20 #define ITCINTEN_SHIFT21 #define TCCHEN_SHIFT22 #define ITCCHEN_SHIFT23 //#define USE_FIFO #define TSET_B //#define PRINT #define SAVE_TIME #define BIT_16 /******************************************************************************* * FILE GLOBALS */ static volatile int irqraised1 = 0; static volatile int irqraised2 = 0; int edma3_memtomemcpytest_dma_write(const char *buf, int acnt, int bcnt, int ccnt, int sync_mode,int event_queue); int edma3_memtomemcpytest_dma_read(char *buf, int acnt, int bcnt, int ccnt, int sync_mode,int event_queue); dma_addr_t dmaphyssrc1 = 0; dma_addr_t dmaphyssrc2 = 0; dma_addr_t dmaphysdest1 = 0; dma_addr_t dmaphysdest2 = 0; char *dmabufsrc1 = NULL; char *dmabufsrc2 = NULL; char *dmabufdest1 = NULL; char *dmabufdest2 = NULL; unsigned long ce1_start = DM365_ASYNC_EMIF_DATA_CE1_BASE; unsigned long ce1_end = DM365_ASYNC_EMIF_DATA_CE1_BASE + SZ_32M - 1; unsigned long ctrl_start = DM365_ASYNC_EMIF_CONTROL_BASE; unsigned long ctrl_end = DM365_ASYNC_EMIF_CONTROL_BASE + SZ_4K - 1; volatile unsigned short *pstr_emif; void __iomem *vaddr; //ce1 void __iomem *base; //ctrl chargDrvrName[]= "emif_cpu";// Name of driver in proc. intgDrvrMajor = 242;// Major number not dynamic. /* module_param(acnt, int, S_IRUGO); module_param(bcnt, int, S_IRUGO); module_param(ccnt, int, S_IRUGO); */ int Emif_edma_Open(struct inode *inode, struct file *filp) { printk(KERN_INFO"%s: Open: module opened\n",gDrvrName); return 0; } int Emif_edma_Release(struct inode *inode, struct file *filp) { printk(KERN_INFO"%s: Release: module released\n",gDrvrName); return 0; } #if 1 static struct aemif_para my_aemif_para = { .wsetup = 15, .wstrobe = 63, .whold = 7, .rsetup = 15, .rstrobe = 63, .rhold = 7, .ta =3, }; #endif #if 0 static struct aemif_para my_aemif_para = { .wsetup = 1, .wstrobe = 2, .whold = 1, .rsetup = 0, .rstrobe = 7, .rhold = 1, .ta = 3, }; #endif #if 0 static struct aemif_para my_aemif_para = { .wsetup = 1, .wstrobe = 2, .whold = 1, .rsetup = 0, .rstrobe = 3, .rhold = 0, .ta = 3, }; #endif #if 0 static struct aemif_para my_aemif_para = { .wsetup = 0, .wstrobe = 0, .whold = 0, .rsetup = 0, .rstrobe = 3, .rhold = 0, .ta = 3, }; #endif #if 0 static struct aemif_para my_aemif_para = { .wsetup = 5, .wstrobe = 21, .whold = 2, .rsetup = 0, .rstrobe = 0, .rhold = 0, .ta =0, }; #endif //set the clock para of aemif static inline void emif_clkpara_set(void __iomem *base, unsigned cs) { unsigned set, val; unsigned offset = A1CR_OFFSET + cs * 4; set = TA(my_aemif_para.ta) | RHOLD(my_aemif_para.rhold) | RSTROBE(my_aemif_para.rstrobe) | RSETUP(my_aemif_para.rsetup) | WHOLD(my_aemif_para.whold) | WSTROBE(my_aemif_para.wstrobe) | WSETUP(my_aemif_para.wsetup); val = __raw_readl(base + offset); val &= ~TIMING_MASK; val |= set; __raw_writel(val, base + offset); return 0; } ssize_t Emif_edma_Write(struct file *filp, const char *buf, size_t count,loff_t *f_pos) { #if 0 int i = 0; for(i = 0; i < count/2; i++) { *(pstr_emif+i) = *(((unsigned short *)buf) + i); } #endif memcpy((char *)pstr_emif, buf, count); // printk(KERN_INFO"%s: Emif_cpu_Write: %d bytes have been written...\n", gDrvrName, count); return (0); } ssize_t Emif_edma_Read(struct file *filp, char *buf, size_t count, loff_t *f_pos) { #if 0 int i = 0; for(i = 0; i < count/2; i++) { *(((unsigned short *)buf) + i) = *(pstr_emif+i); } #endif memcpy(buf, (char *)pstr_emif, count); // printk(KERN_INFO"%s: Emif_cpu_Read: %d bytes have been read...\n", gDrvrName, count); return count; } static inline unsigned int emif_readl(void __iomem *base, int offset) { return __raw_readl(base + offset); } static inline void emif_writel(void __iomem *base, int offset, unsigned long value) { __raw_writel(value, base + offset); } /* All timings in nanoseconds */ static struct davinci_aemif_timing fpga_emif_timing = { .wsetup = 29, .wstrobe = 24, .whold = 14, .rsetup = 19, .rstrobe = 33, .rhold = 0, .ta = 29, }; void edma_test_exit(void) { printk("\nExiting edma3_sample_app module\n"); } /* DMA Channel, Mem-2-Mem Copy, ASYNC Mode, INCR Mode */ /* DMA Channel, Mem-2-Mem Copy, ASYNC Mode, INCR Mode */ // Aliasing write, read, ioctl, etc... struct file_operations Emif_edma_Intf = {owner: THIS_MODULE,read:Emif_edma_Read,write:Emif_edma_Write,open:Emif_edma_Open,release:Emif_edma_Release, }; static int __init emif_edma_init(void) { unsigned int ret; unsigned int chipsel = 1; unsigned int val; // unsigned short data_send[DATA_LENGTH]; // unsigned int i = 0; // unsigned int n = 0; vaddr = ioremap(ce1_start, ce1_end - ce1_start); base = ioremap(ctrl_start, ctrl_end - ctrl_start); if (!vaddr || !base) { printk("emif_mod: ioremap failed\n"); return -1; } val = emif_readl(base, A1CR_OFFSET + chipsel * 4); /* Extended Wait is not valid and Select Strobe mode is not used */ val &= ~(ACR_ASIZE_MASK | ACR_EW_MASK | ACR_SS_MASK); #ifdef BIT_16 val |= 0x1; //kang:16 bit data bus #else val |= 0x0; #endif emif_writel(base, A1CR_OFFSET + chipsel * 4, val); emif_clkpara_set(base, chipsel);//set time para #if 0 ret = davinci_aemif_setup_timing(&fpga_emif_timing, base, 1 ); //0:cs0, 1:cs1 if (ret < 0) { printk("emif_mod: emif timing values setup fail\n"); return -1; } #endif pstr_emif = (unsigned short *)vaddr; //--- START: Register Driver // Register with the kernel as a character device. if (0 > register_chrdev(gDrvrMajor, gDrvrName, &Emif_edma_Intf)) { printk(KERN_WARNING"%s: Init: will not register\n", gDrvrName); return -1; } printk(KERN_INFO"%s: Init: module registered\n", gDrvrName); printk(KERN_ALERT "Hello, world\n"); return 0; } static void emif_edma_exit(void) { iounmap(vaddr); iounmap(base); unregister_chrdev(gDrvrMajor, gDrvrName); } module_init(emif_edma_init); module_exit(emif_edma_exit); MODULE_AUTHOR("Texas Instruments"); MODULE_LICENSE("GPL");
:
驱动代码头文件:emif_cpu.h
struct aemif_para { u8 wsetup; u8 wstrobe; u8 whold; u8 rsetup; u8 rstrobe; u8 rhold; u8 ta; }; #define DM365_ASYNC_EMIF_CONTROL_BASE 0x01d10000 #define DM365_ASYNC_EMIF_DATA_CE0_BASE 0x02000000 #define DM365_ASYNC_EMIF_DATA_CE1_BASE 0x04000000 #define ACR_ASIZE_MASK 0x3 #define ACR_EW_MASK BIT(30) #define ACR_SS_MASK BIT(31) #define NRCSR_OFFSET 0x00 #define AWCCR_OFFSET 0x04 #define A1CR_OFFSET 0x10 #ifndef __sizes_h #define __sizes_h1 /* handy sizes */ #define SZ_1K0x00000400 #define SZ_4K0x00001000 #define SZ_8K0x00002000 #define SZ_16K0x00004000 #define SZ_32K0x00008000 #define SZ_64K0x00010000 #define SZ_128K0x00020000 #define SZ_256K0x00040000 #define SZ_512K0x00080000 #define SZ_1M0x00100000 #define SZ_2M0x00200000 #define SZ_4M0x00400000 #define SZ_8M0x00800000 #define SZ_16M0x01000000 #define SZ_31M0x01F00000 #define SZ_32M0x02000000 #define SZ_64M0x04000000 #define SZ_128M0x08000000 #define SZ_256M0x10000000 #define SZ_512M0x20000000 #define SZ_1G0x40000000 #define SZ_2G0x80000000 #endif
测试程序:emif_main_cpu.c
#include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <sys/time.h> #define DATA_LENGTH (1*1024) //#define DATA_LENGTH (32*1024) //#define DATA_LENGTH (256) struct timeval emif_time_start; struct timeval emif_time_end; int main(void) { FILE* fp; FILE* fp_1; FILE* fp_2; int g_devFile; unsigned short data_send[DATA_LENGTH/2]; unsigned short data_recv[DATA_LENGTH/2]; int i = 0, ret = 0; for(i = 0; i < DATA_LENGTH/2; i++){ data_send[i] = i; } for(i = 0; i < DATA_LENGTH/2; i++){ data_recv[i] = 0 ; } //open the device g_devFile = open("/dev/emif_edma", O_RDWR); if ( g_devFile < 0 ){ printf("emif_main: Error opening device file.\n"); return -1; } fp_1 = fopen("src.dat","ab+"); fp_2 = fopen("dst.dat","ab+"); while(1) { gettimeofday(&emif_time_start, NULL); ret = fread((char *)data_send,1,DATA_LENGTH,fp_1); if(ret < DATA_LENGTH){ return -1; } write(g_devFile,(char *)data_send, DATA_LENGTH); usleep(1000); #if 1 memset(data_recv, 0, DATA_LENGTH); ret = read(g_devFile, (char *)data_recv, DATA_LENGTH); if(ret < DATA_LENGTH){ return -1; } fwrite((char *)data_recv,1,DATA_LENGTH,fp_2); for(i = 0; i < DATA_LENGTH/2;i++){ if(data_recv[i] != data_send[i]){ printf("error occur!!!"); // return -1; } } #endif gettimeofday(&emif_time_end, NULL); printf("write time:%dus\n",(emif_time_end.tv_sec*1000000+emif_time_end.tv_usec)-(emif_time_start.tv_sec*1000000+emif_time_start.tv_usec)); } return 0; }
KK Z:
请各路大神多多指教哇
Da Li3:
回复 KK Z:
好巧啊,我也在研究DM368的EMIF接口呢,也遇到了些问题,你有没有试过mmap 映射/dev/mem在用户空间直接读写EMIF接口呀?我用这种方式写的时候出现提示segmentation fault,
操作emif口必须要写驱动吗?
HG:
你好! EMIF 接口其实是一种转接控制器挂在系统总线上。所以大数据量交互时,请严格参照示例代码。
关于DM368的视频支持,TI提供相关支持见网址:http://www.ti.com.cn/tool/cn/linuxdvsdk-dm36x?keyMatch=DM368&tisearch=Search-CN-Everything。
用于 DM365、DM368 数字媒体处理器的 Linux 数字视频软件开发套件 (DVSDK)