历史上的今天
返回首页

历史上的今天

今天是:2025年04月15日(星期二)

正在发生

2018年04月15日 | S3C6410使用---11uboot写yaffs2文件系统过程分析

2018-04-15 来源:eefocus

一、介绍
Nand flash  K9GAG08U0D  (2G Byte)
在u-boot的shell里面执行如下命令: 把 rootfs.yaffs从SD卡的第一个分区读取出来,并写到nand flash中去.
SMDK6401> fatload mmc 0:1 50008000 rootfs.yaffs
SMDK6401> nand erase 600000  $(filesize)
SMDK6401> nand write.yaffs2 50008000 600000 $(filesize)
这儿分析一下最后一条命令:将数据写入到yaffs2分区的过程


二、 过程分析
1.1 u-boot/common/cmd_nand.c中

  1. int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])

  2. {

  3.     if (strncmp(cmd, "read", 4) == 0 || strncmp(cmd, "write", 5) == 0) {

  4.         addr = (ulong)simple_strtoul(argv[2], NULL, 16);

  5.         read = strncmp(cmd, "read", 4) == 0; /* 1 = read, 0 = write */


  6.         if (arg_off_size(argc - 3, argv + 3, nand, &off, &size) != 0)

  7.             return 1;


  8.         s = strchr(cmd, '.');

  9.          if (!read && s != NULL && + (!strcmp(s, ".yaffs2") || !strcmp(s, ".yaffs1"))) 

  10.          {

  11.             nand_write_options_t opts;

  12.              memset(&opts, 0, sizeof(opts));

  13.              opts.buffer = (u_char*) addr;              // addr=0x50008000内存

  14.              opts.length = size;                        // length是文件长度

  15.              opts.offset = off;                         // offset 是要写到nand flash的地址0x600000

  16.              opts.pad = 0;

  17.              opts.blockalign = 1;

  18.              opts.quiet = quiet;

  19.              opts.writeoob = 1;

  20.              opts.autoplace = 1;

  21.              ret = nand_write_opts(nand, &opts);

  22.          }

  23. }

argv[0]    argv[1]      argv[2]    argv[3]   argv[4]
nand     write.yaffs2   50008000   600000   $(filesize)
                         addr       off     size=0x420000

1.2 在文件driver/nand/nand_utils.c中

  1. int nand_write_opts(nand_info_t *meminfo, const nand_write_options_t *opts)

  2. {

  3.     ulong mtdoffset = opts->offset;                // mtdoffset=nand_flash中的偏移0x600000

  4.     ulong erasesize_blockalign;

  5.     u_char *buffer = opts->buffer;                 // buffer=(u_char*)0x500080

  6.     imglen = opts->length;                         // imglen是rootfs.yaffs2这个文件的长度   

  7.     while (imglen && (mtdoffset < meminfo->size)) {


  8.         //下面这个 while判断要写入的块是不是坏块,如果是坏块继续查找直到找到一个好块

  9.         while (blockstart != (mtdoffset & (~erasesize_blockalign+1))) {

  10.             blockstart = mtdoffset & (~erasesize_blockalign+1);

  11.             offs = blockstart;

  12.             baderaseblock = 0;


  13.             do {

  14.                 int ret = meminfo->block_isbad(meminfo, offs);    //判断是不是块坏


  15.                 if (ret < 0) {

  16.                     printf("Bad block check failedn");

  17.                     goto restoreoob;

  18.                 }

  19.                 if (ret == 1) {                                    //ret=1是坏块

  20.                     baderaseblock = 1;                             //这个地方还要设个标志,直接do_something不就得了?

  21.                     if (!opts->quiet)

  22.                         printf("rBad block at 0x%lx "

  23.                          "in erase block from "

  24.                          "0x%x will be skippedn",

  25.                          (long) offs,

  26.                          blockstart);

  27.                 }


  28.                 if (baderaseblock) {

  29.                     mtdoffset = blockstart + erasesize_blockalign; //如果ret=1是坏块,要写入的起始位置指向下一个块

  30.                 }

  31.                 offs +=     erasesize_blockalign

  32.                     / opts->blockalign;

  33.             } while (offs < blockstart + erasesize_blockalign);

  34.         }


  35.         readlen = meminfo->writesize;        

  36.         memcpy(data_buf, buffer, readlen);                      //初始时:buffer=(u_char*)0x50008000

  37.         buffer += readlen;                                      //meminfo->writesize= 4096


  38.         if (opts->writeoob) {            

  39.             memcpy(oob_buf, buffer, meminfo->oobsize);          //buffer=(data+oob)*n, oob紧跟data

  40.             buffer += meminfo->oobsize;                         //meminfo->oobsize = 128

  41.             oob_ops.mode = MTD_OOB_AUTO;    

  42.             oob_ops.len = meminfo->writesize;                   // 每一次写的大小为writesize=4k

  43.             oob_ops.ooboffs = 0;

  44.             oob_ops.ooblen = meminfo->oobsize;

  45.             oob_ops.oobbuf = (unsigned char *)&oob_buf;

  46.             oob_ops.datbuf = (unsigned char *)&data_buf;


  47.             result = meminfo->write_oob(meminfo, mtdoffset, &oob_ops);    //如果没有坏块的话: mtdoffset=nand_flash中的偏移0x600000

  48.             

  49.             imglen -= meminfo->oobsize;

  50.         }

  51.         imglen -= readlen;                                                // mtd->writesize=4096

  52.         mtdoffset += meminfo->writesize;                                  // mtdoffset指向下一个page,是page_align

  53.     }

  54. }

1.3 在driver/nand/nand_base.c中

  1. int nand_scan_tail(struct mtd_info *mtd)

  2. {

  3.     mtd->write_oob = nand_write_oob;                    //初始化

  4. }

  5. //初始化时,所以 meminfo->write_oob(meminfo, mtdoffset, &oob_ops),就是调用nand_write_oob

  6. static int nand_write_oob(struct mtd_info *mtd, loff_t to, struct mtd_oob_ops *ops)

  7. {

  8.     struct nand_chip *chip = mtd->priv;

  9.     nand_get_device(chip, mtd, FL_WRITING); 


  10.     if (!ops->datbuf)                                   //ops->databuf不为空,要调用下面那个

  11.         ret = nand_do_write_oob(mtd, to, ops);

  12.     else

  13.         ret = nand_do_write_ops(mtd, to, ops);         //调用这个,这就是nand flash写的过程,可参考下面的图

  14.     

  15. }

1.4 在driver/nand/nand_base.c中

  1. /**

  2.  * nand_do_write_ops - [Internal] NAND write with ECC

  3.  * @mtd:    MTD device structure

  4.  * @to:        offset to write to

  5.  * @ops:    oob operations description structure

  6.  *

  7.  * NAND write with ECC

  8.  */

  9. static int nand_do_write_ops(struct mtd_info *mtd, loff_t to, struct mtd_oob_ops *ops)

  10. {

  11.     int chipnr, realpage, page, blockmask, column;

  12.     struct nand_chip *chip = mtd->priv;

  13.     uint32_t writelen = ops->len;

  14.     uint8_t *oob = ops->oobbuf;

  15.     uint8_t *buf = ops->datbuf;

  16.     int ret, subpage;


  17.     ops->retlen = 0;


  18.     column = to & (mtd->writesize - 1);

  19.     subpage = column || (writelen & (mtd->writesize - 1));


  20.     if (subpage && oob)

  21.         return -EINVAL;


  22.     chipnr = (int)(to >> chip->chip_shift);

  23.     chip->select_chip(mtd, chipnr);                                            //写过程第1步,选中芯片


  24.     realpage = (int)(to >> chip->page_shift);

  25.     page = realpage & chip->pagemask;

  26.     blockmask = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1;


  27.     /* Invalidate the page cache, when we write to the cached page */

  28.     if (to <= (chip->pagebuf << chip->page_shift) &&

  29.             (chip->pagebuf << chip->page_shift) < (to + ops->len))

  30.         chip->pagebuf = -1;


  31.     while(1) {

  32.         int bytes = mtd->writesize;

  33.         int cached = writelen > bytes && page != blockmask;

  34.         uint8_t *wbuf = buf;


  35.         if (unlikely(column || writelen < (mtd->writesize - 1))) {

  36.             cached = 0;

  37.             bytes = min_t(int, bytes - column, (int) writelen);

  38.             chip->pagebuf = -1;

  39.             memset(chip->buffers->databuf, 0xff, mtd->writesize);

  40.             memcpy(&chip->buffers->databuf[column], buf, bytes);

  41.             wbuf = chip->buffers->databuf;

  42.         }


  43.         if (unlikely(oob))

  44.             oob = nand_fill_oob(chip, oob, ops);


  45.         ret = chip->write_page(mtd, chip, wbuf, page, cached,  (ops->mode == MTD_OOB_RAW));

  46.         if (ret)

  47.             break;


  48.         writelen -= bytes;


  49.         if (!writelen)

  50.             break;


  51.         column = 0;

  52.         buf += bytes;

  53.         realpage++;


  54.         page = realpage & chip->pagemask;

  55.         /* Check, if we cross a chip boundary */

  56.         if (!page) {

  57.             chipnr++;

  58.             chip->select_chip(mtd, -1);

  59.             chip->select_chip(mtd, chipnr);

  60.         }

  61.     }


  62.     ops->retlen = ops->len - writelen;

  63.     if (unlikely(oob))

  64.         ops->oobretlen = ops->ooblen;

  65.     return ret;

  66. }

1.5 在driver/nand/nand_base.c中

  1. static uint8_t *nand_fill_oob(struct nand_chip *chip, uint8_t *oob,    struct mtd_oob_ops *ops)

  2. {

  3.     size_t len = ops->ooblen;

  4.     int i=0;

  5.     switch(ops->mode) {

  6.         case MTD_OOB_AUTO:

  7.         {

  8.          struct nand_oobfree *free = chip->ecc.layout->oobfree;

  9.          uint32_t boffs = 0, woffs = ops->ooboffs;

  10.          size_t bytes = 0;

  11.          // free->length=22, len=128, woffs=0

  12.          for(; free->length && len; free++, len -= bytes) 

  13.          {    // bytes=22, boffs=2

  14.             bytes = min_t(size_t, len, free->length);

  15.             boffs = free->offset;

  16.             

  17.             memcpy(chip->oob_poi + boffs, oob, bytes);                       //将rootfs.yaffs2中紧跟main区的22个字节copy到oob_poi[2-24]处     

  18.             oob += bytes;                                                    //这块数据是yaffs2文件系统的信息

  19.          }

  20.          return oob;    

  21.         }

  22.      }       

  23.     return NULL;

  24. }


1.6 在driver/nand/nand_base.c中

  1. nand_scan_tail
    {
        if (!chip->write_page)
            chip->write_page = nand_write_page;
    }

  2. static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,  const uint8_t *buf, int page, int cached, int raw)

  3. {


  4.     int status;


  5.     chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);                            //写过程第2-3步,发命令0x80,发地址


  6.     if (unlikely(raw))

  7.        chip->ecc.write_page_raw(mtd, chip, buf);

  8.     else    //exec       

  9.        chip->ecc.write_page(mtd, chip, buf);  

  10.    

  11.    cached = 0;

  12.     if (!cached || !(chip->options & NAND_CACHEPRG)) { 

  13.         chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1,-1);                           //写过程第5步,写命令0x10

  14.         status = chip->waitfunc(mtd, chip);                                                          //写过程第6步,等侍结束

  15.         

  16.         if ((status & NAND_STATUS_FAIL) && (chip->errstat))

  17.             status = chip->errstat(mtd, chip, FL_WRITING, status,page);


  18.         if (status & NAND_STATUS_FAIL)

  19.             return -EIO;

  20.     } 

  21.     return 0;

  22. }

1.7 在cpu/s3c64xx/nand.c中

  1. board_nand_init()

  2. {

  3. #if defined(CONFIG_NAND_BL1_8BIT_ECC) && (defined(CONFIG_S3C6410) || defined(CONFIG_S3C6430))

  4.     nand->ecc.write_page = s3c_nand_write_page_8bit;

  5.     nand->ecc.size = 512;

  6.     nand->ecc.bytes = 13;

  7.     nand->ecc.layout = &s3c_nand_oob_mlc_128_8bit;

  8. #endif

  9. }

  10. void s3c_nand_write_page_8bit(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t *buf)

  11. {

  12.     int i, eccsize = 512;

  13.     int eccbytes = 13;

  14.     int eccsteps = mtd->writesize / eccsize;

  15.     uint8_t *ecc_calc = chip->buffers->ecccalc;

  16.     uint8_t *p = buf;

  17.                                                                                     //下面这个for代码,写的不明了,             

  18.     for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {                //意思是: 每512字节生成13字节的ECC,4K生成13*(4K/512)=104字节的ECC

  19.         s3c_nand_enable_hwecc_8bit(mtd, NAND_ECC_WRITE);                            //使能硬件ECC

  20.         chip->write_buf(mtd, p, eccsize);                                           //写过程第4步,写数据

  21.         s3c_nand_calculate_ecc_8bit(mtd, p, &ecc_calc[i]);                          //每写512字节到main区,就生成13字节的ECC,依次填充到ecc_calc[0-13*8=104]处

  22.     }


  23.     for (i = 0; i < eccbytes * (mtd->writesize / eccsize); i++)

  24.         chip->oob_poi[i+24] = ecc_calc[i];                                      //将硬件生成的ECC值填入oob的[24-128]处, ECC_size=8*13=104, (24+104=128)


  25.     chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);                 //写过程第4步,写OOB(OOB数据紧随main区数据写入的,单独写OOB是写不了的 )            

  26. }


1.8 在driver/nand/nand_base.c中

  1. static void nand_set_defaults(struct nand_chip *chip, int busw)

  2. {

  3.     if (!chip->write_buf)

  4.         chip->write_buf = busw ? nand_write_buf16 : nand_write_buf;

  5. }

  6. static void nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)

  7. {

  8.     int i;

  9.     struct nand_chip *chip = mtd->priv;


  10.     for (i = 0; i < len; i++)

  11.         writeb(buf[i], chip->IO_ADDR_W);

  12. }

1.9 上述写过程如下图所示:

1.10 OOB数据如下图所示


推荐阅读

史海拾趣

国炬(GOOGLL)公司的发展小趣事
静态工作点的设置对功放电路的性能有重要影响。需要确保静态工作点稳定且适当,以避免出现交越失真等问题。
Astro Tool Corp公司的发展小趣事

随着技术的不断成熟和市场的逐步认可,Astro Tool Corp公司开始积极拓展海外市场。通过与国际知名电子制造商建立合作伙伴关系,公司成功将产品打入国际市场。同时,公司还积极参与国际行业展会和交流活动,不断提升品牌知名度和影响力。这些努力不仅为公司带来了更多的订单和合作伙伴,也进一步巩固了其在全球电子制造工具市场的地位。

Curtis Electromusic Specialties Inc公司的发展小趣事

随着全球环保意识的不断提高,电子行业对环保材料的需求也日益增长。CUI公司敏锐地抓住了这一市场机遇,积极投入研发,成功开发出了一种绿色环保型的碘化亚铜生产工艺。这种工艺不仅降低了生产过程中的能耗和排放,而且提高了产品的纯度和质量。通过推广这一工艺,CUI公司不仅赢得了客户的青睐,也为行业的绿色发展做出了积极贡献。

Chip Quik公司的发展小趣事

随着国内市场的稳定发展,Chip Quik公司开始将目光投向国际市场。公司通过分析不同国家和地区的电子维修市场需求,制定针对性的市场策略。通过参加国际电子展会、建立海外销售渠道等方式,公司逐渐在国际市场上取得了一席之地。

普芯达电子(Chipswinner)公司的发展小趣事

普芯达电子的“中国风”系列产品是公司发展历程中的一个重要里程碑。该系列产品经过严格的质量控制和品质检测,以其优异的性能和可靠的品质赢得了市场的广泛认可。通过一系列的市场推广活动,“中国风”品牌逐渐深入人心,成为国产集成电路产品的代表之一。同时,普芯达电子还通过不断创新和优化产品,满足了客户日益增长的需求,进一步巩固了市场地位。

Amulet Technologies公司的发展小趣事

在电子行业中,技术创新是企业持续发展的关键。普芯达电子深知这一点,因此始终将技术创新作为公司发展的核心驱动力。公司不断加大研发投入,引进先进技术和设备,培养了一支高素质的研发团队。通过持续的技术创新和产品升级,普芯达电子不断推出具有市场竞争力的新产品,为客户提供了更加优质和多样化的选择。

问答坊 | AI 解惑

研祥做客嵌入式在线

研祥做客嵌入式在线——嵌入式带来工业控制的新变革             ·2008年7月25日上午10:00--11:30             ·访谈嘉宾:朱 军              ·嘉宾简介:国家工控机专委会常委、研祥智能科技股份有 ...…

查看全部问答>

好东东共享,Cadence SPB15.7 视频教程第1-7讲(于博士版)

可在线观看,也可以下载。 文件太大,传不上来。 给个地址,自己去下载吧。 http://www.sig007.com/videoclass/107.html http://www.sig007.com/videoclass/108.html http://www.sig007.com/videoclass/109.html http://www.sig007.com/video ...…

查看全部问答>

AT89C52中文资料

AT89C52中文资料,希望对大家有用…

查看全部问答>

FPGA与单片机通信

本帖最后由 paulhyde 于 2014-9-15 09:39 编辑 大家FPGA与单片机用的什么通信模式呢?串口和并口哪个好做啊?不知哪里有相关资料可供下载阿……  …

查看全部问答>

高分求助!EVC4.0环境,就一个.c文件(demo.c),为什么不包含 dshow.h 时编译通过,包含时就出一大堆错误呢?

用的是EVC4.0开发环境,就一个.c文件(demo.c),文件内容非常简单,为什么不包含 dshow.h 时编译通过,包含时就出一大堆错误呢? #include //#include     // 不包含 dshow.h 编译通过,包含时就出一大堆错误,见后面。 int W ...…

查看全部问答>

唤醒后死机了,发现没有中断信号却不断产生中断??

我的情况是这样的:2450 WinCE5.0 唤醒后,机器卡死:除了显示屏显示一静态图像外,系统不响应其他的外设。 通过打印信息知道,与EINT9注册了的那个事件(我命名为Event_EINT9)不断地被置成通知状态。 因此系统就在那个处理中断的线程里循环,导 ...…

查看全部问答>

还是EEPROM,怎么用软件判断EEPROM的大小

RT,不知道能不能对地址以外的空间读写的异常来判断一个EEPROM的大小,比如一个8K的,我向8K以外的区域写数据,如果出现异常,而7K区域没异常,我就认为这个EEPROM是8K的,不知道这样行不行…

查看全部问答>

求救(摄像头背景偏暗且带有明显的红横条)

各位高手:      小弟使用美光的MT9D111摄像头,使用中发现LCD显示屏背景偏暗(LCD使用其它功能正常),同时横向布满密集的红色的线条,导致拍摄时图像不清晰。      不知道该怎么调节,高手们救我啊! ...…

查看全部问答>

求救

你哪位大侠有关于stm32的TFT屏资料,给我发一个:405838540@qq.com 谢了…

查看全部问答>

FLASH写的问题

请问各位大哥,F149要对FLASH写时。是不是把430程序停了就可以进行 ,请各位详细指点一下,小弟谢谢。 程序的要求是第一次程序用JTAG口烧到430里。然后程序进行到一定时间时要对FLASH里的几个数进行修改,下次RESET时CPU程序直接用新的参数。 ...…

查看全部问答>