【问题标题】:Write on a mtd block device在 mtd 块设备上写入
【发布时间】:2013-03-11 10:28:52
【问题描述】:

我正在尝试使用 MTD 块设备在 NAND 闪存上写入,但我不了解所有内容。

当我读到here

  • mtdblockN 是只读块设备 N
  • mtdN 是读/写字符设备 N
  • mtdNro 是只读字符设备 N

但我想使用 C 语言中的简单 write 直接将字节写入分区,但我不明白它是如何工作的(我读到我首先必须擦除我想要写入的扇区)。

我应该使用哪种设备以及如何在此设备上书写?

【问题讨论】:

  • 不确定这是否有帮助,但您是否看过此处提供的示例:link,“从应用程序访问 MTD”部分
  • 是的,我看到了 ;-) 我目前正在尝试
  • MTD 设备让您可以访问原始闪存。如果要创建、编辑、删除文件等。这应该通过文件系统(在您的情况下为 yaffs2)进行。通过 MTD 设备访问 flash 并没有为您提供这样的层。
  • 我想在分区上写一个u-boot可以读取的内核镜像
  • how to write on this device 来自用户空间还是来自内核空间?

标签: c linux embedded flash-memory


【解决方案1】:

从/向内存技术设备读取和写入与任何其他类型的 IO 并没有什么不同,除了在写入之前您需要擦除扇区(擦除块)

为了让事情变得简单,您可以随时使用 mtd-utils(例如 flash_erasenanddumpnandwrite,分别用于擦除、读取和写入),而无需编写代码。

但是,如果您确实想务实地这样做,这里有一个示例,请确保阅读所有 cmets,因为我将所有详细信息都放在那里:

#include <stdio.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <mtd/mtd-user.h>

int main()
{
    mtd_info_t mtd_info;           // the MTD structure
    erase_info_t ei;               // the erase block structure
    int i;

    unsigned char data[20] = { 0xDE, 0xAD, 0xBE, 0xEF,  // our data to write
                               0xDE, 0xAD, 0xBE, 0xEF,
                               0xDE, 0xAD, 0xBE, 0xEF,
                               0xDE, 0xAD, 0xBE, 0xEF,
                               0xDE, 0xAD, 0xBE, 0xEF};
    unsigned char read_buf[20] = {0x00};                // empty array for reading

    int fd = open("/dev/mtd0", O_RDWR); // open the mtd device for reading and 
                                        // writing. Note you want mtd0 not mtdblock0
                                        // also you probably need to open permissions
                                        // to the dev (sudo chmod 777 /dev/mtd0)

    ioctl(fd, MEMGETINFO, &mtd_info);   // get the device info

    // dump it for a sanity check, should match what's in /proc/mtd
    printf("MTD Type: %x\nMTD total size: %x bytes\nMTD erase size: %x bytes\n",
         mtd_info.type, mtd_info.size, mtd_info.erasesize);

    ei.length = mtd_info.erasesize;   //set the erase block size
    for(ei.start = 0; ei.start < mtd_info.size; ei.start += ei.length)
    {
        ioctl(fd, MEMUNLOCK, &ei);
        // printf("Eraseing Block %#x\n", ei.start); // show the blocks erasing
                                                  // warning, this prints a lot!
        ioctl(fd, MEMERASE, &ei);
    }    

    lseek(fd, 0, SEEK_SET);               // go to the first block
    read(fd, read_buf, sizeof(read_buf)); // read 20 bytes

    // sanity check, should be all 0xFF if erase worked
    for(i = 0; i<20; i++)
        printf("buf[%d] = 0x%02x\n", i, (unsigned int)read_buf[i]);

    lseek(fd, 0, SEEK_SET);        // go back to first block's start
    write(fd, data, sizeof(data)); // write our message

    lseek(fd, 0, SEEK_SET);              // go back to first block's start
    read(fd, read_buf, sizeof(read_buf));// read the data

    // sanity check, now you see the message we wrote!    
    for(i = 0; i<20; i++)
         printf("buf[%d] = 0x%02x\n", i, (unsigned int)read_buf[i]);


    close(fd);
    return 0;
}

这样做的好处是,因为您可以像在其他设备上一样使用标准实用程序,所以很容易理解 write()open()read() 的作用以及对它们的期望。

例如,如果在使用 write() 时,您的值是 EINVAL,这可能意味着:

fd 附加到不适合写入的对象上;或者文件是使用 O_DIRECT 标志打开的,并且 buf 中指定的地址、count 中指定的值或当前文件偏移量未正确对齐。

【讨论】:

  • 好的,这就是我根据 Habi 提供的链接所做的,它有效!但是我必须将写入大小与下一个扇区对齐,否则我会收到内核警告:-)
  • 还有一个问题:在这种情况下如何处理坏块?您进行了完整性检查,但内核如何处理不再可写的死块?
  • @marmottus - 对于不断变化的扇区,这很容易做到,您只需修改lseek 命令并使用 mtd_info 结构中的擦除大小。坏块(在原始闪存上)是您处理的责任......大多数闪存芯片都实现了某种 FTL(闪存转换层),它为您处理 BBM 和 ware leveling,这通常在硬件中完成,您需要咨询确定您的 NAND 闪存的规格
  • @marmottus - 是的...除非有硬件 FTL。您可能想更新您在 a NAND flash memory (yaffs2) 中所说的问题,我猜这暗示您正在 NAND 闪存设备上安装 yaffs2 文件系统。
  • 好帖子!虽然我有问题。调用 write() 时出现 EINVAL 错误。知道是什么原因造成的吗?
猜你喜欢
  • 2023-03-11
  • 1970-01-01
  • 1970-01-01
  • 2011-09-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-09-08
  • 1970-01-01
相关资源
最近更新 更多