小弟今天尝试着着学习写nor flash的驱动程序,测试的时候发现,读数据是没有问题的,而写数据则总是写不进去。
看AM29lv160db芯片资料上说对特定地址写数据的时候就是采用
向aaa地址写入aa
向555地址写入55
向aaa地址写入a0
然后向目的地址写目的数据
我就是这么来写的,但是测试程序测试显示根本没写进去。
测试程序的逻辑
打开norflash
读出基地址base_addr 开始的0~15字节,存入original_data数组中
然后向这些地址写入flash_data的数据
然后读出
再将original_data写回
。谁能帮我解决一下,我怀疑是写norflash的时序不对?
先谢谢了。
串行口发送回来的数据如下:
Open nor_drv successful!
/**************read test***********************Trying to vfree() nonexistent vm)
Badness in __vunmap at mm/vmalloc.c:308
Trying to vfree() nonexistent vm area (c480a000)
Badness in __vunmap at mm/vmalloc.c:308
***/
[e] = 0
[d] = 0
[c] = 0
= 0
[a] = 0
[9] = 0
[8] = 0
[7] = 0
[6] = 0
[5] = 0
[4] = 0
[3] = 0
[2] = 0
[1] = 0
[0] = 0
/***************write test***********************/
flash_data[0] = 0
flash_data[1] = 1
flash_data[2] = 2
flash_data[3] = 3
flash_data[4] = 4
flash_data[5] = 5
flash_data[6] = 6
flash_data[7] = 7
flash_data[8] = 8
flash_data[9] = 9
flash_data[10] = a
flash_data[11] = b
flash_data[12] = c
flash_data[13] = d
flash_data[14] = e
flash_data[15] = f
flash_data[0] = 0
flash_data[1] = 1
flash_data[2] = 2
flash_data[3] = 3
flash_data[4] = 4
flash_data[5] = 5
flash_data[6] = 6
flash_data[7] = 7
flash_data[8] = 8
flash_data[9] = 9
flash_data[10] = a
flash_data[11] = b
flash_data[12] = c
flash_data[13] = d
flash_data[14] = e
flash_data[15] = f
/**************read test**************************/
[e] = 0
[d] = 0
[c] = 0
= 0
[a] = 0
[9] = 0
[8] = 0
[7] = 0
[6] = 0
[5] = 0
[4] = 0
[3] = 0
[2] = 0
[1] = 0
[0] = 0
测试程序如下:
#include <stdio.h>
#include <stdlib.h> //system
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <sys/ioctl.h>
#define DEVICE_NODE "/dev/nor"
#define READ_IN 0
#define WRITE_OUT 1
#define CPU_RESET 3
int main(int argc,char *argv[ ])
{
int fd;
int i;
int count;
unsigned int capacity;
unsigned long addr,arg;
unsigned int data;
unsigned int cmd=0xff;
unsigned char original_data[1024];
unsigned char flash_data[1024];
unsigned char write_buffer[1024];
fd=open(DEVICE_NODE,O_RDWR);
if(fd<0)
{
perror("Can not open device!!!\n");
exit(1);
}
printf("/**************read test**************************/\n");
count = read(fd, original_data, 15);
for(i = count - 1; i >= 0; i--)
{
printf("[%x] = %x\n", i, original_data);
}
printf("/***************write test***********************/\n");
for(i = 0; i <= 15; i++)
{
write_buffer = i;
printf("flash_data[%d] = %x\n", i, write_buffer);
}
count = write(fd, write_buffer, 15);
for(i = 0; i <= 15; i++)
{
printf("flash_data[%d] = %x\n", i, write_buffer);
}
printf("/**************read test**************************/\n");
count = read(fd, flash_data, count);
for(i = count - 1; i >= 0; i--)
{
printf("[%x] = %x\n", i, flash_data);
}
count = write(fd, original_data, 15);
/** printf("capacity: ... ");
scanf("%d", &capacity);
printf("capacity is %d M.\nstart read the nor flash\n", capacity);
for(i = 0; i < capacity; i++)
{
for(addr = 0; addr < 0x80000; addr++){
arg=((unsigned long)0<<24)+((i * 0x80000 + addr) &0x00ffffff);
ioctl(fd,0,arg);
}
}
*/
/*
printf("cmd: ");
scanf("%d",&cmd);
printf("cmd is %d\n",cmd);
switch(cmd)
{
case READ_IN:
printf("read!\n");
printf("address: ");
scanf("%lx",&addr);
arg=((unsigned long)cmd<<24)+(addr&0x00ffffff);
ioctl(fd,0,arg);
break;
case WRITE_OUT:
printf("write!\n");
printf("address: ");
scanf("%lx",&addr);
arg=((unsigned long)cmd<<24)+(addr&0x00ffffff);
printf("data: ");
scanf("%x",&data);
if(data>0xffff)
{
printf("Data too long!\n");
return 1;
}
ioctl(fd,data,arg);
break;
case CPU_RESET:
printf("Cpu reset!\n");
arg=((unsigned long)cmd<<24);
ioctl(fd,0,arg);
break;
default:
printf("Wrong Command!\n");
break;
}
*/
close(fd);
return 0;
}
驱动程序如下:
#include <linux/config.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/mman.h>
#include <linux/vmalloc.h>
#include <asm/pgalloc.h>
#include <linux/pagemap.h>
#include <linux/rmap.h>
#include <linux/mm.h>
#include <linux/init.h>
#include <linux/kernel.h> /* DPRINTK() */
#include <linux/slab.h> /* kmalloc() */
#include <linux/fs.h> /* everything... */
#include <linux/errno.h> /* error codes */
#include <linux/types.h> /* size_t */
#include <linux/proc_fs.h>
#include <linux/delay.h>
#include <asm/io.h>
#include <linux/seq_file.h>
#include <linux/cdev.h>
#include <asm/uaccess.h> /* copy_*_user */
#include <linux/interrupt.h>
#include <asm/arch/irqs.h>
#define PRINTK printk
#define DEVICE_CAPACITY 0X100000 /*QQ2440V3有 2M nor_flash*/
unsigned long base_addr = 0x14000;/*测试程序为了不引起nor flash内部原来的程序,从1M开始的地方进行测试,看是否好用*/
int nor_major = 240;
int nor_minor = 0;
int nor_nr_devs = 1;
struct cdev *nor_cdev; //×Ö·ûÉ豞µÄœÚµã
dev_t nor_dev ; //Çý¶¯É豞ºÅµÄœÚµã
static int nor_open(struct inode *inode,struct file *file);
static int nor_ioctl(struct inode *inode,struct file *file,unsigned int cmd,unsigned long arg);
ssize_t read(struct file *file, char __user *buf,
size_t len, loff_t *ppos);
ssize_t write(struct file *file, const char __user *buf,
size_t len, loff_t *ppos);
static struct file_operations nor_fops = {
.owner = THIS_MODULE,
.open = nor_open,
.ioctl = nor_ioctl,
.read = read,
.write = write,
};
static int nor_open(struct inode *inode,struct file *file)
{
try_module_get(THIS_MODULE);
PRINTK("Open nor_drv successful!\n");
return 0;
}
unsigned short read_data(unsigned long addr)
{
unsigned long v_addr;
unsigned short data;
v_addr=(unsigned long)ioremap(addr,4);
data=*((volatile unsigned short*)v_addr);
iounmap((void*)v_addr);
return data;
}
ssize_t read(struct file *file, char __user *buf,
size_t len, loff_t *ppos)
{
size_t count = 0;
unsigned long v_addr;
for(count = 0; (count <= DEVICE_CAPACITY) && (count < len); count ++)
{
v_addr=(unsigned long)ioremap(base_addr + count,1);
copy_to_user(buf + count, ((volatile unsigned short*)v_addr), 1);
iounmap(v_addr);
}
return count;
}
ssize_t write(struct file *file, const char __user *buf,
size_t len, loff_t *ppos){
unsigned long v_addr[4];
size_t count;
int i;
//printk("[0x%08lx] = %04x\n",addr,data);
v_addr[0]=(unsigned long)ioremap(0x00000aaa,4);
v_addr[1]=(unsigned long)ioremap(0x00000555,4);
v_addr[2]=(unsigned long)ioremap(0x00000aaa,4);
for(count = 0; count < len; count++)
{
v_addr[3]=(unsigned long)ioremap(base_addr+count,4);
*((volatile unsigned short*)v_addr[0])=0xaa;
*((volatile unsigned short*)v_addr[1])=0x55;
*((volatile unsigned short*)v_addr[2])=0xa0;
copy_from_user((volatile unsigned short *)v_addr[3], &(buf[count]), 1);
// *((volatile unsigned short*)v_addr[3])=data;
iounmap((void*)v_addr[3]);
}
for(i=0;i<4;i++)
{
iounmap((void*)v_addr);
}
return count;
}
static int nor_ioctl(struct inode *inode,struct file *file,unsigned int cmd,unsigned long arg)
{
unsigned short data;
data=read_data(arg);
printk("[%x] = %d\n",arg, data);
}
static int __init nor_init(void)
{
int result,err;
if(nor_major)
{
nor_dev=MKDEV(nor_major,nor_minor); //²úÉúÉ豞œÚµã
//²ÎÊýÊÇÖ÷É豞ºÅºÍŽÓÉ豞ºÅ|·µ»ØÉ豞œÚµã
result=register_chrdev_region(nor_dev,1,"nor"); //×¢²áÉ豞
//²ÎÊýÊÇÉ豞œÚµã£¬É豞Êý£¬É豞Ãû|·µ»Øœá¹û
}
else
{
result=alloc_chrdev_region(&nor_dev,nor_minor,1,"nor"); //¶¯Ì¬²úÉúÉ豞œÚµã
//²ÎÊýÊÇÉ豞œÚµãµÄÖžÕ룬ŽÓÉ豞ºÅ£¬É豞Êý£¬É豞Ãû|·µ»Øœá¹û
nor_major=MAJOR(nor_dev); //²ÎÊýÊÇÉ豞œÚµã|·µ»ØÖ÷É豞ºÅ
}
if(result<0)
{
PRINTK(KERN_ERR " nor: Can not get major %d!\n",nor_major);
return -1;
}
nor_cdev=cdev_alloc(); //²úÉú×Ö·ûÉ豞œÚµã
if(nor_cdev!=NULL)
{
cdev_init(nor_cdev, &nor_fops); //³õÊŒ»¯×Ö·ûÉ豞œÚµã
//²ÎÊýÊÇ×Ö·ûÉ豞œÚµã£¬ÎÄŒþ²Ù×÷
nor_cdev->ops=&nor_fops;
nor_cdev->owner=THIS_MODULE;
err=cdev_add(nor_cdev,nor_dev,1); //ÌíŒÓ×Ö·ûÉ豞µœÉ豞œÚµã
//²ÎÊýÊÇ×Ö·ûÉ豞œÚµã£¬É豞œÚµã£¬É豞Êý|·µ»ØŽíÎó
if(err)
{
PRINTK(KERN_NOTICE " ERROR: %d adding nor_cdev!\n",err);
}
else
{
PRINTK(" Adding nor_cdev successful!\n");
}
}
else
{
PRINTK(KERN_ERR "Register nor_cdev error!\n");
return -1;
}
devfs_mk_cdev(MKDEV(nor_major, nor_minor), S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, "nor");
return 0;
}
static void __exit nor_cleanup(void)
{
devfs_remove("nor");
unregister_chrdev_region(nor_dev,1); //Ð¶ÔØÇý¶¯@²ÎÊýÊÇÉ豞Çý¶¯œÚµã
PRINTK("Unregister Successful!\n");
}
module_init(nor_init);
module_exit(nor_cleanup);
MODULE_AUTHOR("ELVIS");
MODULE_DESCRIPTION("ELVIS's norflash driver");
MODULE_LICENSE("GPL");