项目中需要用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;}