项目中需要用ARM与FPGA进行通信,通信方式是通过FPGA生成的SRAM作为数据的交换区,ARM9芯片为ATMEL的AT91SAM9260,采用Linux 2.6.19的内核,今天搞了一天,总算是读写成功,下面简要的说明一下。
ARM中只有I/O内存的没有I/O端口,ARM9运行后默认是开启MMU的,Linux采用虚拟存储管理内存,具体的内存管理方式本文不作展开。所以要使用Linux访问外设必须要先进行内存映射。这里主要涉及两个函数:
Ø Request_mem_region:该函数检查所需要转换的内存是否被占用,进行合法性检查,有些驱动中没有,个人认为安全性起见还是使用为妙。
Ø Ioremap:该函数完成物理地址到虚拟地址的映射,映射后的地址才能被Linux内核使用。
下面给出代码:
驱动程序:
#include <linux/module.h> #include <linux/types.h> #include <linux/fs.h> #include <linux/types.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/platform_device.h> #include <linux/cdev.h> #include <linux/ioctl.h> #include <linux/gpio.h> #include <linux/mm.h> #include <linux/errno.h> #include <asm/arch/hardware.h> #include <asm/arch/gpio.h> #include <asm/uaccess.h> #include <linux/slab.h> /*for Kmalloc*/ #include <asm/io.h>/*for virt_to_phys*/ #include <asm/hardware.h> #include <asm/arch/at91_pio.h> #include <asm/arch/at91rm9200.h>/*for sram address and size*/ #define SRAM0_PHYADDR 0x300000 #define SRAM0_SIZE 0x1000 /*4K*/ int sram_major = 242; int sram_open(struct inode *inode,struct file *filp); int sram_release(struct inode *inode,struct file *filp); int sram_release(struct inode *inode,struct file *filp); ssize_t sram_read(struct file *filp , char __user *buf ,size_t count,loff_t *f_pos); ssize_t sram_write(struct file *filp , char __user *buf ,size_t count,loff_t *f_pos); //int sram_mmap(struct file *filp, struct vm_area_struct *vma ); //static void sram_setup_cdev(struct sram_dev *dev,int index); int sram_init(void); void sram_cleanup(void); MODULE_AUTHOR("Cun Tian Rui"); MODULE_LICENSE("Dual BSD/GPL"); struct sram_dev { struct cdev cdev; unsigned long startAddr; unsigned long size; char *mapPtr; }sram_dev; struct sram_dev *sramdevp; struct file_operations sram_fops = { .owner = THIS_MODULE, // .ioctl = sram_ioctl, .open = sram_open, .release = sram_release, .read = sram_read, .write = sram_write, // .mmap = sram_mmap }; int sram_open(struct inode *inode,struct file *filp) { struct sram_dev *devp; devp = container_of(inode->i_cdev,struct sram_dev,cdev); filp->private_data = devp; return 0; } int sram_release(struct inode *inode,struct file *filp) { return 0; } ssize_t sram_read(struct file *filp , char __user *buf ,size_t count,loff_t *f_pos) { unsigned long p = *f_pos; struct sram_dev *devp = filp->private_data; printk("Driver read function running\n"); printk("p is %d\n",p); if (p >= devp->size) return -EINVAL; if (count > devp->size-p) count = devp->size-p; printk("count is %d\n",count); if (copy_to_user(buf, devp->mapPtr+p,count)) return -EFAULT; *f_pos+= count; return count; } ssize_t sram_write(struct file *filp , char __user *buf ,size_t count,loff_t *f_pos) { unsigned long p = *f_pos; printk("Driver write function running\n"); printk("p is %d\n",p); struct sram_dev *devp = filp->private_data; if (p >= devp->size) return -EINVAL; if (count > devp->size-p) count = devp->size-p; printk("count is %d\n",count); if (copy_from_user( devp->mapPtr+p,buf,count)) return -EFAULT; *f_pos += count; return count; } /* int sram_mmap(struct file *filp, struct vm_area_struct *vma ) { unsigned long offset = vma->vm_pgoff<<PAGE_SHIFT; unsigned long size = vma->vm_end - vma->vm_start; if ( size > SRAM0_SIZE ) { printk("size too big\n"); return(-ENXIO); } offset = offset + SRAM0_PHYADDR; vma->vm_flags |= VM_LOCKED; if ( remap_pfn_range(vma,vma->vm_start,offset,size,PAGE_SHARED)) { printk("remap page range failed\n"); return -ENXIO; } return(0); } */ int sram_init(void) { int result; int err,ret; int devno = MKDEV(sram_major,0); dev_t dev = MKDEV(sram_major,0); if(sram_major) { result = register_chrdev_region(dev,1,"SRAM0"); } if(result < 0) { return result; } sramdevp = kmalloc(sizeof(struct sram_dev),GFP_KERNEL); if(!sramdevp) { result = - ENOMEM; goto fail_malloc; } memset(sramdevp,0,sizeof(struct sram_dev)); //sram_setup_cdev(sramdevp,0); sramdevp->startAddr = SRAM0_PHYADDR; sramdevp->size = SRAM0_SIZE; ret = request_mem_region(SRAM0_PHYADDR, SRAM0_SIZE, "SRAM0 Region"); if(ret==NULL) { printk("Request Memory Region Failed!\n"); return -1; } sramdevp->mapPtr = ioremap(SRAM0_PHYADDR,SRAM0_SIZE); cdev_init(&sramdevp->cdev,&sram_fops); sramdevp->cdev.owner = THIS_MODULE; sramdevp->cdev.ops = &sram_fops; err = cdev_add(&sramdevp->cdev,devno,1); if(err) { printk(KERN_NOTICE "Error %d adding SRAM%d",err,0); } printk( "SRAM0_virt_addr = 0x%lx\n", (unsigned long)sramdevp->mapPtr ); return 0; fail_malloc: unregister_chrdev_region(dev,sramdevp); kfree(sramdevp); return result; } void sram_cleanup(void) { cdev_del(&sramdevp->cdev); iounmap(sramdevp->mapPtr); kfree(sramdevp); unregister_chrdev_region(MKDEV(sram_major,0),1); } module_init(sram_init); module_exit(sram_cleanup);
写SRAM:
#include<sys/types.h> #include<sys/stat.h> #include<fcntl.h> #include<stdio.h> #include<linux/fs.h> #include<stdlib.h> #include<unistd.h> #define SRAM_DEV "/dev/SRAM0" int main() { int fd; char * data="ctrboss"; fd=open(SRAM_DEV,O_WRONLY); if(fd<0) { printf("Unable to open sram device %s\n",SRAM_DEV); return 0; } write(fd,data,sizeof(data)); close(fd); return 1; }
读SRAM:
#include<sys/types.h> #include<sys/stat.h> #include<fcntl.h> #include<stdio.h> #include<linux/fs.h> #include<stdlib.h> #include<unistd.h> #define SRAM_DEV "/dev/SRAM0" int main() { int i,fd; char data[6]; fd=open(SRAM_DEV,O_RDONLY); if(fd<0) { printf("Unable to open sram device %s\n",SRAM_DEV); return 0; } read(fd,data,sizeof(data)); printf("data is %x\n",data[0]); printf("data is %x\n",data[1]); printf("data is %x\n",data[2]); printf("data is %x\n",data[3]); printf("data is %x\n",data[4]); printf("data is %x\n",data[5]); printf("data is %c\n",data[0]); printf("data is %c\n",data[1]); printf("data is %c\n",data[2]); printf("data is %c\n",data[3]); printf("data is %c\n",data[4]); printf("data is %c\n",data[5]); close(fd); return 1; }