前言:
对与NandFlash等块设备的访问操作,mtd-utils工具集中提供了非常好的支持(可以到http://www.linux-mtd.infradead.org/进行了解),要使用mtd-utils工具集首先需要搞到mtd-utils的源码,并且使用目标设备上的交叉工具编译链进行编译。关于mtd-utils工具的使用可以参考:http://www.cnblogs.com/pengdonglin137/p/3415663.html 其中介绍了mtd-utils中常用的工具。
我们可以参考mtd-utils中工具的实现,从而完成在自己的应用程序中实现对NandFlash的操作。
#1.打开设备
这里需要注意的是,打开的设备结点是/dev/mtdN,而不是/dec/mtdblockN,原因可以参考:
https://www.cnblogs.com/hnrainll/archive/2011/06/09/2076075.html - 里面介绍了mtd与mtdblock的区别
fd = open ("/dev/mtd0", O_SYNC | O_RDWR);
#2.获取设备信息
#include <linux/types.h>
struct mtd_info_user {
__u8 type;
__u32 flags;
__u32 size; // Total size of the MTD
__u32 erasesize;
__u32 writesize;
__u32 oobsize;// Amount of OOB data per block (e.g. 16)
/*
The below two fields are obsolete and broken, do not use them * (TODO: remove at some point) */
__u32 ecctype;
__u32 eccsize;
};
struct mtd_info_user mtd;
//The struct above is defined in <linux/types.h>. Not need redefine in our program.
ioctl(fd, MEMGETINFO,&mtd) ;
根据MEMGETINFO可以获得mtd的设备信息
#3.擦除NAND FLASH
#include <mtd/mtd-abi.h>
#include <linux/types.h>
struct erase_info_user {
__u32 start;
__u32 length;
};
typedef struct erase_info_user erase_info_t;
erase_info_t erase;
//The struct above is defined in the above head file. Not need redefine in our pogram.
int isNAND, bbtest = 1;
ioctl(fd, MEMGETINFO,&mtd) ;
struct mtd_info_user *DevInfo = &mtd;
erase.length = DevInfo->erasesize;
// erase.length 表示的是擦除大小,也就是一块的大小,如128KB
// DevInfo->size 为某个/dev/mtdx的大小
// erasse.start应该是按块对齐递增
isNAND = (DevInfo->type == MTD_NANDFLASH) ? 1 : 0;
for (erase.start = 0; erase.start < DevInfo->size; erase.start += DevInfo->erasesize)
{
if (bbtest)
{
loff_t offset = erase.start;
int ret = ioctl(DevInfo->fd, MEMGETBADBLOCK, &offset); //判断是不是坏块
if (ret > 0)
{
if (!quiet)
DEBUG ("\nSkipping bad block at 0x%08x\n", erase.start);
continue;//发现是坏块,应该跳过
}
#if 0 //if not need this judge,disable it
else if (ret < 0)
{
if (errno == EOPNOTSUPP)
{
bbtest = 0;
if (isNAND)
{
fprintf(stderr, "%s: Bad block check not available\n", DevInfo->dir);
return 1;
}
}
else
{
fprintf(stderr, "\n%s: MTD get bad block failed: %s\n", DevInfo->dir, strerror(errno));
return 1;
}
}
#endif
}
if (!quiet)
{
fprintf(stderr, "\rErasing %d Kibyte @ %x -- %2llu %% complete.", \
(DevInfo->erasesize) / 1024, erase.start,
(unsigned long long) erase.start * 100 / (DevInfo->size));
}
if (ioctl(DevInfo->fd, MEMERASE, &erase) != 0) //执行擦除操作
{
fprintf(stderr, "\n%s: MTD Erase failure: %s\n", DevInfo->dir,strerror(errno));
continue;
}
}
#4.写NAND FLASH
char IPLFile[] = "customer.jffs2";
int readfd = 0;
int readlen;
printf("%s read\n",IPLFile);
readfd = open(IPLFile, O_RDONLY);
if(readfd == 0)
{
printf("OPEN %s ERROR, not to upgrade\n",IPLFile);
}
memset(Buffer , 0 , sizeof(Buffer));
readlen = read(readfd, Buffer, sizeof(Buffer));
printf("readlen = %d\n",readlen);
if(readlen <= 0)
{
printf("buffer fread error \n");
close(readfd);
readfd = 0;
return -1;
}
close(readfd);
readfd = 0; //清零
#if 1 //write
{
int num = (readlen + 2*1024-1)/(2*1024);
int j = 0x0;
int alwlen = 0x0;
int cur_write_pos = 0;
int write_ret = 0;
int wlen = 0x0;
int write_cnt = 0;
printf("Start write\n");
for(j=0x0; j<num; j++)
{
alwlen = 0x0;
loff_t offset;
cur_write_pos = 0;
write_ret = 0;
wlen = 0x0;
offset = 0/*FlashDevice.MtdDevice[i].StartAddress*/ + j * 2*1024;
lseek(fd, offset, 0);
wlen = ((readlen - alwlen)>(2*1024)) ? (2*1024) : (readlen-alwlen);
printf("+");
while(cur_write_pos != wlen)
{
#if 1
//printf("wlen: %d,cur_write_pos: %d\n",wlen,cur_write_pos);
write_ret = write(fd, Buffer + offset + cur_write_pos, wlen - cur_write_pos);
if (write_ret < 0)
{
printf(" (%d)\nFlashWrite failed, not erase? (%d)\n", write_cnt, write_ret);
return -1;
}
else if (write_ret == 0)
{
break;
}
#endif
cur_write_pos += write_ret;
}
write_cnt++;
}
printf("write (%d)*2k\n", write_cnt);
printf("finish write\n");
}
#endif
return 0;
}
#5.关于mtd的ioctl中更多的命令
#define MEMGETINFO _IOR('M', 1, struct mtd_info_user)
#define MEMERASE _IOW('M', 2, struct erase_info_user)
#define MEMWRITEOOB _IOWR('M', 3, struct mtd_oob_buf)
#define MEMREADOOB _IOWR('M', 4, struct mtd_oob_buf)
#define MEMLOCK _IOW('M', 5, struct erase_info_user)
#define MEMUNLOCK _IOW('M', 6, struct erase_info_user)
#define MEMGETREGIONCOUNT _IOR('M', 7, int)
#define MEMGETREGIONINFO _IOWR('M', 8, struct region_info_user)
#define MEMSETOOBSEL _IOW('M', 9, struct nand_oobinfo)
#define MEMGETOOBSEL _IOR('M', 10, struct nand_oobinfo)
#define MEMGETBADBLOCK _IOW('M', 11, __kernel_loff_t)
#define MEMSETBADBLOCK _IOW('M', 12, __kernel_loff_t)
#define OTPSELECT _IOR('M', 13, int)
#define OTPGETREGIONCOUNT _IOW('M', 14, int)
#define OTPGETREGIONINFO _IOW('M', 15, struct otp_info)
#define OTPLOCK _IOR('M', 16, struct otp_info)
#define ECCGETLAYOUT _IOR('M', 17, struct nand_ecclayout_user)
#define ECCGETSTATS _IOR('M', 18, struct mtd_ecc_stats)
#define MTDFILEMODE _IO('M', 19)
#define MEMERASE64 _IOW('M', 20, struct erase_info_user64)
#define MEMWRITEOOB64 _IOWR('M', 21, struct mtd_oob_buf64)
#define MEMREADOOB64 _IOWR('M', 22, struct mtd_oob_buf64)
#define MEMISLOCKED _IOR('M', 23, struct erase_info_user)
#6.后言
这是在我在工作中所用到的对NAND FLASH的操作,如果想要跟多操作,可以参考mtd-util工具的源码。mtd-util工具开源,网上可以容易下载到。✧ (≖ ‿ ≖)✧
#7.参考博客
感谢:ヾ(*´▽‘*)ノ
[1] 在应用程序中实现对NandFlash的操作 - 摩斯电码