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)
TI中文支持网

