目录
获取flash类型
嵌入式开发常用的flash类型有nor和nand
不同flash的擦写方法不同,因此需要对flash的类型进行判断
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <mtd/mtd-abi.h>
static unsigned char get_flash_type(const char *p_dev)
{
if (NULL == p_dev)
{
printf("get null pointer!\n");
return -1;
}
int app_fd = open(p_dev, O_RDWR, 0666);
if (-1 == app_fd)
{
printf("open %s failed:%m\n", p_dev);
return -1;
}
struct mtd_info_user mtd_info;
if (-1 == ioctl(app_fd, MEMGETINFO, &mtd_info))
{
close(app_fd);
printf("ioctl MEMGETINFO failed!\n");
return -1;
}
close(app_fd);
return mtd_info.type;
}
int main()
{
unsigned char flash_type = get_flash_type("/dev/mtd4");
if (MTD_NANDFLASH == flash_type)
{
printf("The flash type if MTD_NANDFLASH, FLASH_APP_NAME\n");
}
else if (MTD_NORFLASH == flash_type)
{
printf("The flash type if MTD_NORFLASH, FLASH_APP_NAME\n");
}
else
{
printf("not support flash type=%d\n", flash_type);
}
return -1;
}
//boot中fw_printenv中的实现
struct mtd_info_user mtdinfo;
struct stat st;
int rc;
rc = fstat(fd, &st);
if (rc < 0) {
fprintf(stderr, "Cannot stat the file %s\n",
DEVNAME(dev_current));
return -1;
}
if (S_ISCHR(st.st_mode)) { //判断文件是否为字符设备
rc = ioctl(fd, MEMGETINFO, &mtdinfo);
if (rc < 0) {
fprintf(stderr, "Cannot get MTD information for %s\n",
DEVNAME(dev_current));
return -1;
}
if (mtdinfo.type != MTD_NORFLASH &&
mtdinfo.type != MTD_NANDFLASH &&
mtdinfo.type != MTD_DATAFLASH &&
mtdinfo.type != MTD_UBIVOLUME) {
fprintf (stderr, "Unsupported flash type %u on %s\n",
mtdinfo.type, DEVNAME(dev_current));
return -1;
}
} else {
memset(&mtdinfo, 0, sizeof(mtdinfo));
mtdinfo.type = MTD_ABSENT;
}
读写flash
nor
static int flash_app_erase(const char *flash_name)
{
int app_fd = open(flash_name, O_RDWR, 0666);
if (-1 == app_fd)
{
printf("open %s failed:%m\n", flash_name);
return -1;
}
int fs_len = flash_app_len(app_fd);
if (0 >= fs_len)
{
close(app_fd);
printf("get flash app len failed!\n");
return -1;
}
//获取MTD设备信息
struct mtd_info_user mtd_info;
if (-1 == ioctl(app_fd, MEMGETINFO, &mtd_info))
{
close(app_fd);
printf("ioctl MEMGETINFO failed!\n");
return -1;
}
//擦除falsh
if (-1 == lseek(app_fd, 0, SEEK_SET))
{
close(app_fd);
printf("lseek SEEK_SET failed!\n");
return -1;
}
if (0 != (fs_len % mtd_info.erasesize))
{
close(app_fd);
printf("erasesize=%d fs_len=%d fs_len not align!\n", mtd_info.erasesize, fs_len);
return -1;
}
printf("start erase flash:\n");
uint32 block_cnt = (fs_len / mtd_info.erasesize);
struct erase_info_user argp;
for (uint32 i = 0; i < block_cnt; i++)
{
//擦除对应块数据
argp.start = i * mtd_info.erasesize;
argp.length = mtd_info.erasesize;
if (-1 == ioctl(app_fd, MEMERASE, &argp))
{
close(app_fd);
printf("ioctl MEMERASE failed!\n");
return -1;
}
fprintf(stderr, ".");
fflush(stderr);
}
printf("\n");
printf("erase flash size=%d success!\n", fs_len);
close(app_fd);
return 0;
}
static int flash_mtd_len(const char * p_mtd_name)
{
int len = 0;
if (NULL == p_mtd_name)
{
return -1;
}
int fd = open(p_mtd_name, O_RDWR, 0666);
if (fd < 0)
{
printf("open %s failed:%m\n", p_mtd_name);
return -1;
}
len = flash_app_len(fd);
close(fd);
fd = -1;
return len;
}
int nor_flash_app_write(const char * p_buf, uint32 buf_len, const char *flash_name)
{
int ret = 0;
if (NULL == p_buf || buf_len <= 0)
{
printf("p_buf==null or buf_len<=0, check!\n");
return -1;
}
int fs_len = flash_mtd_len(flash_name);
if (fs_len < 0)
{
printf("get flash app len failed!\n");
return -1;
}
if (buf_len > fs_len)
{
printf("buf len=%d > flash len=%d, error!\n", buf_len, fs_len);
return -1;
}
/* 擦除整个 app 分区 */
ret = flash_app_erase(flash_name);
if (ret < 0)
{
printf("erase flash app failed!\n");
return -1;
}
/* 写flash */
int app_fd = open(flash_name, O_RDWR, 0666);
if (-1 == app_fd)
{
printf("open %s failed:%m\n", flash_name);
return -1;
}
if (-1 == lseek(app_fd, 0, SEEK_SET))
{
printf("lseek %s to SEEK_SET failed!\n", flash_name);
close(app_fd);
return -1;
}
printf("start write image to flash......\n");
// int w_len = write(app_fd, p_buf, buf_len);
int w_len = 0;
int cnt = buf_len / (1024 * 1024);
int i = 0;
for (; i < cnt; ++i)
{
w_len += write(app_fd, p_buf + i * 1024 * 1024, 1024 * 1024);
usleep(10000);
}
if (buf_len - w_len > 0)
{
w_len += write(app_fd, p_buf + w_len, buf_len - w_len);
}
close(app_fd);
if (w_len != buf_len)
{
printf("write image to %s failed:%m\n", flash_name);
return -1;
}
printf("write app image to flash done!\n\n");
return 0;
}
nand
使用flash_eraseall 和 nandwrite进行擦写。如果默认不支持这两个命令,可能是busybox没配置。
使用nandwrite 写时 要加上 -p选项,表示按页写,否则如果文件不是页大小的整数倍,会写不成功。nandwrite -p /dev/mtd1 file
判断nand是否有怀快
fd是打开的块设备 比如 /dev/mtd2
/*
* Test for bad block on NAND, just returns 0 on NOR, on NAND:
* 0 - block is good
* > 0 - block is bad
* < 0 - failed to test
*/
static int flash_bad_block (int fd, uint8_t mtd_type, loff_t *blockstart)
{
if (mtd_type == MTD_NANDFLASH) {
int badblock = ioctl (fd, MEMGETBADBLOCK, blockstart);
if (badblock < 0) {
perror ("Cannot read bad block mark");
return badblock;
}
if (badblock) {
#ifdef DEBUG
fprintf (stderr, "Bad block at 0x%llx, "
"skipping\n", *blockstart);
#endif
return badblock;
}
}
return 0;
}