- 论坛徽章:
- 0
|
一块16KB的SRAM,由FPGA定制产生,挂载在数据总线BANk2。
SRAM主要用于存放临时大量待处理的数据,物理地址从0x30000000开始。
在网上找了些资料看了,说是用ioremap先把实际物理内存映射到内核空间,
再用mmap从内核空间映射到用户空间, 在用户空间对SRAM进行读写,提高处理速度。
驱动代码如下:
- #include <linux/module.h>
- #include <linux/kernel.h>
- #include <linux/errno.h>
- #include <linux/mm.h>
- #include <linux/wrapper.h> /* for mem_map_(un)reserve */
- #include <asm/io.h> /* for virt_to_phys */
- #include <linux/slab.h> /* for kmalloc and kfree */
- #include <linux/init.h> /* __init __exit */
- #include <linux/ioport.h>
- #include <asm/uaccess.h> /*copy_from_user */
- #define SRAM_STARTADD ((volatile unsigned long*)0x30000000L)
- #define SRAM_SIZE (0x400<<4) //16kB
- volatile unsigned short * reserve_virt_addr16;
- static struct resource *iomap_wdt_mem=NULL;
- static int major=242;
- int mmapdrv_open(struct inode *inode, struct file *file);
- int mmapdrv_release(struct inode *inode, struct file *file);
- int mmapdrv_mmap(struct file *file, struct vm_area_struct *vma);
- int mmapdrv_ioctl(struct inode *inode, struct file *file,unsigned int cmd, unsigned long arg) ;
- static struct file_operations mmapdrv_fops =
- {
- owner: THIS_MODULE,
- mmap: mmapdrv_mmap,
- ioctl: mmapdrv_ioctl,
- open: mmapdrv_open,
- release: mmapdrv_release,
- };
- static int __init mmapdrv_init_module(void)
- {
- int ret;
- if ( ( register_chrdev(major, "mmapdrv", &mmapdrv_fops) ) < 0 )
- {
- printk("mmapdrv: unable to register character device\n");
- return (-EIO);
- }
- //printk("mmap device major = %d\n",major );
- //printk( "high memory physical address %ldM\n",virt_to_phys(high_memory)/1024/1024 );
- if(0 == check_mem_region(SRAM_STARTADD,SRAM_SIZE))
- {
- printk("check_region oK\n");
- if((iomap_wdt_mem=request_mem_region(SRAM_STARTADD,SRAM_SIZE,"mmapdrv"))==NULL)
- {
- printk("failed to reserve memory region\n");
- ret = -ENOENT;
- goto err_nomap;
- }
- else
- printk("request_region oK\n");
-
-
- }
- else
- {
- printk("iomap from 0x%x num %d busy\n",SRAM_STARTADD,SRAM_SIZE);
- return -1;
- }
- reserve_virt_addr16 = (short *)ioremap( SRAM_STARTADD,SRAM_SIZE);
- if ( reserve_virt_addr )
- {
- }
- else
- {
- unregister_chrdev( major, "mmapdrv" );
- printk("ioremap failed\n");
- ret = -EINVAL;
- goto err_nomap;
- }
- return 0;
- err_nomap:
- if(iomap_wdt_mem)
- release_resource(iomap_wdt_mem);
- err_nores:
- return ret;
-
- }
- /* remove the module */
- static void __exit mmapdrv_cleanup_module(void)
- {
- if ( reserve_virt_addr )
- iounmap( (void *)reserve_virt_addr );
- if(iomap_wdt_mem)
- release_resource(iomap_wdt_mem);
- unregister_chrdev( major, "mmapdrv" );
- return;
- }
- int mmapdrv_open(struct inode *inode, struct file *file)
- {
- MOD_INC_USE_COUNT;
- return(0);
- }
-
- int mmapdrv_release(struct inode *inode, struct file *file)
- {
- MOD_DEC_USE_COUNT;
- return(0);
- }
- #define IOMAP_WRITE1 1
- #define IOMAP_WRITE2 2
- #define IOMAP_READ1 3
- #define IOMAP_READ2 4
- int mmapdrv_ioctl(struct inode *inode, struct file *file,unsigned int cmd, unsigned long arg)
- {
- static int i=0;
- switch(cmd)
- {
- case IOMAP_WRITE1:
- {
- for(i=0;i<10;i++)
- {
- *(reserve_virt_addr16+i)=0x55+i;
- }
- }
- break;
- case IOMAP_WRITE2:
- {
- short buf[10];
- for(i=0;i<10;i++)
- {
- buf[i]=0x55+i;
- }
- memcpy(reserve_virt_addr16,buf,10*sizeof(short));
- }
- break;
- case IOMAP_READ1:
- {
- int i,j;
- for ( i=0;i<10;i++)
- {
- //printk("[%d]:%d\n",i,reserve_virt_addr16[i]);
- j=*(unsigned short *)(reserve_virt_addr16+i);
-
- }
- }
- break;
- case IOMAP_READ2:
- {
- short buf[10];
- memcpy(buf,reserve_virt_addr16,10*sizeof(short));
-
- }
- break;
- default:
- printk("default:%d\n",cmd);
- break;
-
- }
- return 0;
-
- }
- int mmapdrv_mmap(struct file *file, struct vm_area_struct *vma)
- {
- unsigned long offset = vma->vm_pgoff<<PAGE_SHIFT;
- unsigned long size = vma->vm_end - vma->vm_start;
- if ( size > SRAM_SIZE )
- {
- printk("size too big\n");
- return(-ENXIO);
- }
-
- if (offset >= __pa(high_memory)||file->f_flags & O_SYNC)
- {
- vma->vm_flags |= VM_IO;//设置vm_flags标记为VM_IO,将VMA标记为一个内存映射的I/O区域
- }
-
- vma->vm_flags |= VM_RESERVED;//VM_RESERVED标记内存区域不能被换出
-
- //vma->vm_flags |= VM_LOCKED;
- offset = offset + SRAM_STARTADD;
- /* we do not want to have this area swapped out, lock it */
- if ( remap_page_range(vma->vm_start,offset,size,PAGE_SHARED))
- {
- printk("remap page range failed\n");
- return -ENXIO;
- }
-
- return(0);
- }
- MODULE_PARM(SRAM_STARTADD,"i");
- MODULE_PARM(SRAM_SIZE,"i");
- module_init(mmapdrv_init_module);
- module_exit(mmapdrv_cleanup_module);
- MODULE_AUTHOR ("");
- MODULE_DESCRIPTION ("");
- MODULE_LICENSE("GPL");
- //-----------------------------------------------------------------
- 测试代码:
- #include <stdio.h>
- #include <fcntl.h>
- #include <sys/mman.h>
- #define DEV_FILE "/dev/mmapdrv"
- #define SRAM_STARTADD 0x30000000
- #define SRAM_SIZE (0x400<<4) //16kB
- #define MMAP_SIZE (1*1024)
- #define IOMAP_WRITE1 1
- #define IOMAP_WRITE2 2
- #define IOMAP_READ1 3
- #define IOMAP_READ2 4
- int test(int fd ,int cmd,int data)
- {
- if(ioctl(fd,cmd,(void *)&data)<0)
- {
- printf("ioctl failed\n");
- return -1;
- }
- return 0;
- }
- int main(int argc ,char **argv)
- {
- int fd;
- int i;
- if(argc<2)
- {
- return -1;
- }
- fd = open(DEV_FILE, O_RDWR);
- if(!strcmp(argv[1], "-W1"))
- {
- test(fd,IOMAP_WRITE1,0);
- }
- else if(!strcmp(argv[1], "-W2"))
- {
- test(fd,IOMAP_WRITE2,0);
- }
- else if(!strcmp(argv[1], "-R1"))
- {
- test(fd,IOMAP_READ1,0);
- }
- else if(!strcmp(argv[1], "-R2"))
- {
- test(fd,IOMAP_READ2,0);
- }
- else if(!strcmp(argv[1], "-MMAP"))
- {
- unsigned short* vadr=NULL;
- vadr = (short*)mmap(NULL, MMAP_SIZE, PROT_READ|PROT_WRITE , MAP_SHARED, fd, 0);
- if (vadr == MAP_FAILED)
- {
- perror("mmap");
- exit(-1);
- }
- for(i=0;i<10;i++)
- {
- *(unsigned short *)(vadr+i)=0xAA+i;
- }
- printf("\n");
-
- for(i=0;i<10;i++)
- {
- printf("[0x%x]",*(unsigned short *)(vadr+i));
- }
- printf("\n");
- munmap(vadr, MMAP_SIZE);
- }
- else
- {
- printf("error\n");
- }
- close(fd);
- return 0;
- }
复制代码
//-----------------------
其中的SRAM是由FPGA定制生成的。
上面对SRAM物理地址的ioremap映射的过程是正确的,
在/proc/iomem中可以查看到映射的物理地址段。
借助FPGA软件可以查看到在内核空间一次写一个字节写数据的时候,片选,地址,写信号线都是正确的,
但是当每次写许多个字节数据的时候,时而出现写信号不对的情况。对SRAM读操作的,不管一次读一个数据还是一次读多个数据信号线都是错误的。
如:
reserve_virt_addr16 = ioremap( SRAM_STARTADD,SRAM_SIZE);
在内核空间写数据操作:
1)这种方式写:分析软件参看正常
int i;
for(i=0;i<10;i++)
*(reserve_virt_addr16+i) =(short)i;
2)这种方式写:分析软件参看出现信号不对
short buf[100];
int i;
for(i=0;i<10;i++)
buf=(short)i;
memcpy(reserve_virt_addr,buf,100*sizeof(char));
在内核空间读数据操作
3)一次读一个:
short c;
int i;
for(i=0;i<10;i++)
c=*(reserve_virt_addr16+i);
4)一次读多个数据:
memcpy(buf,reserve_virt_addr16,100);
5)把SRAM从内核空间用mmap()映射到应用层进行写操作,采用1)或2)方式的写操作,还是3)或4)方式的读操作,软件分析查看都是错误的
请大家帮帮忙啊,为什么会出现上述的不同情况?
6)上面采用不同方式的读写造成时序的变化,是否跟EBI_SMC2_CSR寄存器配置有关,又如何配置该寄存器值?
[ 本帖最后由 cth2008 于 2009-6-12 15:38 编辑 ] |
|