linux 对MTD分区nand flash的烧写和读取

使用mtd-utils工具实现对flash的升级分区的烧写yaffs2

yaffs2的格式是根据所使用的nandflash来制作的,不同的nandflash,得到的yaffs2是不一样的,具体可以参考自己所用的nandflash,以及生成yaffs2文件系统的工具mkyaffs2image。
yaffs2包含了oob数据,所以写flash的时候要分开,本文所使用的是256M oob是64bit,page是2048byte-2kByte,block=64page制作的yaffs2的大小是(2048+64)的倍数!
每次写入是按页(page)的大小写入,而擦除是按照块来的,坏块也是按照块来的,如果当前块是坏的就必须跳过该块!
下载mtd-utils源码!

yaffs2的写入函数

?
int mtd_write_yaffs2_skip_bad(libmtd_t desc,const struct mtd_dev_info *mtd, int fd, int eb, int offs,
          const char *img_name)函数用来烧写flash,如下:
{
    int tmp, ret, in_fd, len, written = 0;
    int write_eb_num,i;
    int data_length,left_to_write,writesize;
    off_t seek;
    struct stat st;
    char *buf,*temp,*dataAddr,*oobAddr;

    if (offs < 0 || offs >= mtd->eb_size) {
        errmsg("bad offset %d, mtd%d eraseblock size is %d",
                   offs, mtd->mtd_num, mtd->eb_size);
        errno = EINVAL;
        return -1;
    }
    if (offs % mtd->subpage_size) {
        //start address must align to page (2048)0x800
        errmsg("write offset %d is not aligned to mtd%d min. I/O size %d",
            offs, mtd->mtd_num, mtd->subpage_size);
        errno = EINVAL;
        return -1;
    }
    in_fd = open(img_name, O_RDONLY | O_CLOEXEC);
    if (in_fd == -1)
            return sys_errmsg("cannot open \"%s\"", img_name);

    if (fstat(in_fd, &st)){
            sys_errmsg("cannot stat %s", img_name);
            goto out_close;
    }

    len = st.st_size;
    if (len % (mtd->subpage_size + mtd->oob_size)){
        errmsg("size of \"%s\" is %d byte, which is not aligned to "
               "mtd%d min. I/O size %d, it is not a yaffs2 file ", img_name, len, mtd->mtd_num,
               mtd->subpage_size + mtd->oob_size);
        errno = EINVAL;
        goto out_close;
    }
    data_length = len / (mtd->subpage_size + mtd->oob_size) * mtd->subpage_size;

    tmp = (offs + data_length + mtd->eb_size - 1) / mtd->eb_size;
    if (eb + tmp > mtd->eb_cnt) {
        errmsg("\"%s\" image size(except oob size) is %d bytes, mtd%d size is %d "
               "eraseblocks, the image does not fit if we write it "
               "starting from eraseblock %d, offset %d",
               img_name, data_length, mtd->mtd_num, mtd->eb_cnt, eb, offs);
        errno = EINVAL;
        goto out_close;
    }

    /* Seek to the beginning of the eraseblock */
    seek = (off_t)eb * mtd->eb_size + offs;
    if (lseek(fd, seek, SEEK_SET) != seek) {
        sys_errmsg("cannot seek mtd%d to offset %llu",
                mtd->mtd_num, (unsigned long long)seek);
        goto out_close;
    }
    writesize = (mtd->eb_size / mtd->subpage_size) *( mtd->subpage_size + mtd->oob_size);
    printf("write size with oob size is: %d \n",writesize);
    buf = xmalloc(writesize);

    left_to_write = len;
    write_eb_num = eb;
    ///writeoffs = eb*mtd->eb_size + offs;

    while (left_to_write > 0) {
        int rd = 0;

        ret = mtd_is_bad(mtd,fd,write_eb_num);//判断当前块是否是坏块!
        if(ret >0){ //是坏块!
            write_eb_num = write_eb_num + 1;
            if(write_eb_num >= mtd->eb_cnt)
            {
                if(left_to_write < 1){
                    goto out_free;
                }
            }
            else {
                printf("skip bad blocks at offset: %d \n",write_eb_num);
                continue;
            }
        }else if(ret <0){
            printf("get bad blocks error: %d\n",errno);
        }

        if(left_to_write < (mtd->eb_size +mtd->oob_size)){
            writesize = left_to_write;
        }
        else{
            writesize = (mtd->eb_size / mtd->subpage_size) *( mtd->subpage_size + mtd->oob_size);
        }

        ret = read(in_fd, buf, writesize);
        if(ret == -1) {
            sys_errmsg("cannot read \"%s\"", img_name);
            goto out_free;
        }

        temp = buf;

        dataAddr = temp;
        oobAddr = temp + mtd->subpage_size;

        for(i=0;i< mtd->eb_size/mtd->subpage_size;i++){ //完成一个块的写入!
            ret = mtd_write(desc,mtd,fd,write_eb_num,i*mtd->subpage_size,dataAddr,mtd->subpage_size,oobAddr,mtd->oob_size,MTD_OPS_RAW);
            if(ret < 0){
                printf("write data witd oob error : %d \n",errno);
            }
            temp = oobAddr + mtd->oob_size;
            dataAddr = temp;
            oobAddr = temp + mtd->subpage_size;
        }
        write_eb_num = write_eb_num +1;
        left_to_write -= writesize;
        printf("left_to_write :%d write_eb_num: %d,writesize:%d\n",left_to_write,write_eb_num,writesize);

    }

    free(buf);
    close(in_fd);
    return 0;

out_free:
    free(buf);
out_close:
    close(in_fd);
    return -1;

}

?

yaffs2的读取函数

?
int mtd_read_yaffs2_skip_bad(libmtd_t desc,const struct mtd_dev_info *mtd, int fd, int eb, int offs,
    const char *img_name)
{
    int tmp, ret, out_fd, len, written = 0;
    int read_eb_num,i,sekOffs;
    int data_length,left_to_read,readsize;
    off_t seek;
    struct stat st;
    char *buf,*dataAddr,*oobAddr;

    if (offs < 0 || offs >= mtd->eb_size) {
        errmsg("bad offset %d, mtd%d eraseblock size is %d",
                   offs, mtd->mtd_num, mtd->eb_size);
        errno = EINVAL;
        return -1;
    }
    if (offs % mtd->subpage_size) {
        //start address must align to page (2048)0x800
        errmsg("write offset %d is not aligned to mtd%d min. I/O size %d",
            offs, mtd->mtd_num, mtd->subpage_size);
        errno = EINVAL;
        return -1;
    }
    len = 0x193b3c0;//for test‘s length, you can read nand flash frome straddr to endaddr!!!
    //also can read all mtdx device!
    if (len % (mtd->subpage_size + mtd->oob_size)){
        errmsg("size of \"%s\" is %d byte, which is not aligned to "
               "mtd%d min. I/O size %d, it is not a yaffs2 file ", img_name, len, mtd->mtd_num,
               mtd->subpage_size + mtd->oob_size);
        errno = EINVAL;
        goto out_close;
    }
    data_length = len / (mtd->subpage_size + mtd->oob_size) * mtd->subpage_size;

    tmp = (offs + data_length + mtd->eb_size - 1) / mtd->eb_size;
    if (eb + tmp > mtd->eb_cnt) {
        errmsg("\"%s\" image size(except oob size) is %d bytes, mtd%d size is %d "
               "eraseblocks, the image does not fit if we write it "
               "starting from eraseblock %d, offset %d",
               img_name, data_length, mtd->mtd_num, mtd->eb_cnt, eb, offs);
        errno = EINVAL;
        goto out_close;
    }
    /* Seek to the beginning of the eraseblock */
    seek = (off_t)eb * mtd->eb_size + offs;
    if (lseek(fd, seek, SEEK_SET) != seek) {
        sys_errmsg("cannot seek mtd%d to offset %llu",
                mtd->mtd_num, (unsigned long long)seek);
        goto out_close;
    }

    readsize = mtd->subpage_size + mtd->oob_size;
    printf("read size with oob size is: %d \n",readsize);

    buf = xmalloc(readsize);

    dataAddr = buf;
    oobAddr = buf + mtd->subpage_size;

    left_to_read = len;
    read_eb_num = eb;

    out_fd = open(img_name,O_WRONLY|O_CREAT|O_TRUNC|O_APPEND, S_IRUSR | S_IWUSR);
    if(out_fd < 0){
        printf("open write file error: %d \n",errno);
        return -1;
    }

    while (left_to_read > 0) {
        int rd = 0;

        ret = mtd_is_bad(mtd,fd,read_eb_num);
        if(ret >0){
            read_eb_num = read_eb_num + 1;
            if(read_eb_num >= mtd->eb_cnt)
            {
                if(left_to_read < 1){
                    goto out_free;
                }
            }
            else {
                printf("skip bad blocks at offset: %d \n",read_eb_num);
                continue;
            }
        }else if(ret <0){
            printf("get bad blocks error: %d\n",errno);
        }

        if(left_to_read < (mtd->eb_size +mtd->oob_size)){
            readsize = left_to_read;
        }
        else{
            readsize = (mtd->eb_size / mtd->subpage_size) *( mtd->subpage_size + mtd->oob_size);
        }

        for(i=0;i< mtd->eb_size/mtd->subpage_size;i++){

            ret = mtd_read(mtd,fd,read_eb_num,i*mtd->subpage_size,dataAddr,mtd->subpage_size);
            if(ret < 0){
                printf("read data error: %d \n",errno);
                goto out_free;
            }

            sekOffs = read_eb_num * mtd->eb_size + i*mtd->subpage_size;
            seek = (off_t)sekOffs;
            //printf("seek %#llx sek offs %#x \n",seek,sekOffs);
            ret = mtd_read_oob(desc,mtd,fd,seek,mtd->oob_size,oobAddr);
            if(ret < 0){
                printf("read oob error: %d \n",errno);
                goto out_free;
            }

            ret = write(out_fd, dataAddr, mtd->subpage_size);
            if(ret == -1) {
                sys_errmsg("cannot write data \"%s\"", img_name);
                goto out_free;
            }
            ret = write(out_fd, oobAddr, mtd->oob_size);
            if(ret == -1) {
                sys_errmsg("cannot write oob \"%s\"", img_name);
                goto out_free;
            }
        }
        read_eb_num = read_eb_num +1;
        left_to_read -= readsize;
        printf("left_to_read :%-7d write_eb_num: %-3d,readsize:%-6d\n",left_to_read,read_eb_num,readsize);
    }
    free(buf);
    close(out_fd);
    return 0;
out_free:
    free(buf);
out_close:
    close(out_fd);
    return -1;

}

?

测试烧写;

?
具体如下:
    int mtdDevFd1 =0,ret =0,i;
    libmtd_t mtd_desc;
    char* image_file = FILE_NAME;
    struct mtd_dev_info mtd;
    //open mtd device, see it at /dev/mtdX
    //get mtd message : cat /proc/mtd
    if ((mtdDevFd1 = open(mtdDev1, O_RDWR)) < 0){
        _SEND_DBUG_MSG("open %s error \n",mtdDev2);
        ret =-1;
        goto out_close;
    }
    mtd_desc = libmtd_open();
    if(mtd_desc == NULL){
        _SEND_DBUG_MSG("can not initlize mtd lib \n");
        ret =-1;
        goto out_close;
    }

    if (mtd_get_dev_info(mtd_desc,mtdDev1,&mtd) < 0){
        ret =-1;
        goto out_close;;
        _SEND_DBUG_MSG("get dev info error!\n");
    }
    printf("size:%#x \n",mtd.size);
    printf("eb_size:%#x \n",mtd.eb_size);
    printf("name:%s \n",mtd.name);
    printf("subpage size: %#x \n",mtd.subpage_size);
    printf("oob size: %#x \n",mtd.oob_size);
    printf("eb_cnt: %#x \n",mtd.eb_cnt);

    for(i = 0; i< mtd.eb_cnt;i++){
        if(mtd_is_bad(&mtd, mtdDevFd1, i))
        {
            printf("erase skip bad block num: %d \n",i);
            continue;
        }
        if(0 != mtd_erase(mtd_desc,&mtd,mtdDevFd1,i)){//擦除!
            _SEND_DBUG_MSG("ersae error \n");
            ret =-1;
            goto out_close;
        }
    }
    if(0 != mtd_write_yaffs2_skip_bad(mtd_desc,&mtd,mtdDevFd1,0,0,image_file)){
        _SEND_DBUG_MSG("write yaffs2 error \n");
        ret = -1;
    }
out_close:
    libmtd_close(mtd_desc);
    close(mtdDevFd1);
    //write end!!!

?

原文地址:https://www.cnblogs.com/liqinghan/p/10064429.html

时间: 2024-08-29 21:53:43

linux 对MTD分区nand flash的烧写和读取的相关文章

嵌入式Linux之旅——环境搭建篇之烧写整个系统

上一小结我们已经烧写完u-boot,我烧写的u-boot是板子厂家定制的,本小节将利用这个u-boot烧写整个系统.当然,在系统移植篇的时候也会涉及到如何定制一个u-boot. 烧写整个系统我们一个叫dnw的工具,dnw是一个USB工具,通过USB发送文件给具有USB下载功能的bootloader.也就说我用的厂家定制的u-boot已经具备了USB下载功能.我需要先安装一些库: sudo apt-get install libncurses5:i386 libstdc++6:i386 zlib1

嵌入式Linux之旅——环境搭建篇之烧写裸机程序

本小节将介绍如何使用oflash和openjtag烧写裸机程序.oflash也支持并口烧写,方法与openjtag类似.如果你想使用jlink烧写,需要安装SEGGER的J-Flash的工具,这里我们就不多介绍. 首先需要先安装oflash,oflash由开发板厂商提供或者从网上下载.将oflash加上可执行权限,拷贝到“/usr/bin”目录下即可.命令如下: sudo cp oflash /usr/bin/ && sudo chmod +x /usr/bin/oflash 下面就是具体

如何利用JLINK烧写U-boot到NAND Flash中

原文:http://blog.csdn.net/yanghao23/article/details/7689534  很多同学使用笔记本作为自己的ARM开发和学习的平台,绝大多数笔记本都没有并口,也就是无法使用JTag调试和烧写程序到Nand Flash中,幸好我们还有JLINK,用JLINK烧写U-boot到Nor Flash中很简单,大部分NOR Flash都已经被JLink的软件SEGGER所支持,而新手在学习的时候经常会实验各种各样的命令,最悲剧的莫过于将NAND Flash中原有的bo

向开发板中烧写Linux系统-型号S3C6410

作者 : 万境绝尘 转载请著名出处 终于拿到板子了, 嵌入式开发正式开启. 板子型号 : 三星 S3C6410 基于ARM11, 指令集基于arm6指令集; 为毛不是 Cortext A9的板子; 烧写内容 : BootLoader, Linux Kernel, File System; 烧写流程 : -- sd卡烧写u-boot并启动 : 首先将 u-boot 烧写到 sd 卡中, 使用 sd 卡的bootloader启动; -- 擦出nand flash : 之后将开发板的闪存 nand f

DM365视频处理流程/DM368 NAND Flash启动揭秘

DM365的视频处理涉及到三个相关处理器,分别是视频采集芯片.ARM处理器和视频图像协处理器(VICP),整个处理流程由ARM核协调.视频处理主要涉及三个处理流程,分别是视频采集.视频编码和对编码后的视频的处理,为了提高性能,通常为每个处理流程提供一个处理线程.视频采集  TVP5146将采集到的视频数据转化为数字信号,并将这些数据送入DM365的BT656接口,然后通过Resize得到所需要的分辨率,然后将这些数据写入到指定的内存中,这些内存空间由cmem模块分配.cmem模块用于分配连续的存

【详解】如何编写Linux下Nand Flash驱动

From: http://www.crifan.com/files/doc/docbook/linux_nand_driver/release/html/linux_nand_driver.html 版本:v2.2 Crifan Li 摘要 本文先解释了Nand Flash相关的一些名词,再从Flash硬件机制开始,介绍到Nand Flash的常见的物理特性,且深入介绍了Nand Flash的一些高级功能,然后开始介绍Linux下面和Nand Flash相关的软件架构MTD的相关知识,最后介绍了

uboot环境变量与内核MTD分区关系

uboot 与系统内核中MTD分区的关系: 分区只是内核的概念,就是说A-B地址放内核,C-D地址放文件系统,(也就是规定哪个地址区间放内核或者文件系统)等等. 1:在内核MTD中可以定义分区A~B,C~D......并予以绝对的地址赋值给每个分区.我们可以来看看在内核中是怎样来对MTD进行分区的:arch/arm/plat-s3c24xx/common-smdk.c static struct mtd_partition smdk_default_nand_part[] = { [0] = {

u-boot中分区和内核MTD分区关系

一.u-boot中环境变量与uImage中MTD的分区关系 分区只是内核的概念,就是说A-B地址放内核,C-D地址放文件系统,(也就是规定哪个地址区间放内核或者文件系统)等等. 一般我们只需要分3-4个区,第一个为boot区,一个为boot参数区(传递给内核的参数),一个为内核区,一个为文件系统区.(但是有的内核就会有很多分区,比如内核参数会有两个,还有会Logo的地址) 而对于bootloader中只要能将内核下载到A~B区的A地址开始处就可以,C~D区的C起始地址下载文件系统…….这些起始地

一键烧写Linux,USB烧写Linux,裸机调试准备

一键烧写linux步骤 A:格式化SD卡,格式为FAT32(尽量用SD卡,其他需要转接板的卡可能会有问题) B:利用PC烧写工具SD_Writer.exe将SD卡启动文件mmc.bin烧写进SD卡中 a:启动SD_Writer.exe(win7需要以管理员身份运行) b:board model 选择6410 c:sd volume(SD盘符),首先点击scan自动搜寻,错误的话手动调整 d:sd type类型为auto(win7还需要点击format格式化SD卡) e:os type选择linu