Write on a mtd block device
Asked Answered
A

1

14

I'm trying to write on a NAND flash memory using MTD block device but I don't understand everything.

As I read here

  • mtdblockN is the read only block device N
  • mtdN is the read/write char device N
  • mtdNro is the read only char device N

But I'd like to directly write bytes to the partition using a simple write in C and I don't understand how it works (I read somewhre that I first must erase the sectors I want to write on).

Which device should I use and how to write on this device?

Altorelievo answered 11/3, 2013 at 10:28 Comment(6)
Not sure if this helps, but have you seen the examples provided here: link, section "Accessing MTDs from applications"Toad
Yeah I saw it ;-) I'm currently trying itAltorelievo
MTD devices give you access to the raw flash. If you want to create, edit, remove files and so on. This should be made over a filesystem (yaffs2 in your case). Accessing the flash through MTD devices does not provide you such layer.Vittoria
I want to write a kernel image on the partition that can be read by u-bootAltorelievo
how to write on this device from user space or from kernel space?Unweave
from user space, I just need to read a file and write it bytes per bytes to /dev/mtdNAltorelievo
U
24

Reading and writing from/to memory technology devices isn't really all that different than any other type of IO, with the exception that before you write you need to erase the sector (erase block)

To make things simple on yourself you can always just use the mtd-utils (such as flash_erase, nanddump and nandwrite, for erasing, read, and writing respectively) without the need for writing code.

However if you do want to do it pragmatically, here's an example, make sure to read all the comments as I put all the details in there:

#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;
}

The nice thing about this is since you can use the standards utils as you do from other devices, it makes it easy to understand what write(), open(), and read() do and what to expect from them.

For example if while using write() you got a value of EINVAL it could mean:

fd is attached to an object which is unsuitable for writing; or the file was opened with the O_DIRECT flag, and either the address specified in buf, the value specified in count, or the current file offset is not suitably aligned.

Unweave answered 11/3, 2013 at 14:9 Comment(11)
OK that's what I did according to the link given by Habi and it works! But I have to align the writing size to the next sector otherwise I have a kernel warning :-)Altorelievo
And another question: How are bad blocks handled in this case? You do a sanity check but how does the kernel deal with dead blocks which are un-writable anymore?Altorelievo
@Altorelievo - for the changing sectors, that's pretty easy to get by, you just need to modify the lseek command and use the erase size from the mtd_info structure. Bad blocks (on raw flash) are your responsibility to deal with... most flash chips implement some sort of FTL (flash translation layer) which takes care of BBM and ware leveling for you, that's typically done in hardware, you need to consult the spec for your NAND flash to know for sureUnweave
@Altorelievo - sorry, missed the fact that you have a yaffs2 mounted on your Flash, in which case yes, that file system does handle bad blocks for you... can't seem to find the details of that at the moment however (I'm more used to JFFS2)Unweave
Hmm no in fact I don't use the yaffs filesystem, I directly deal with /dev/mtdN and write bytes on it, so I guess I have to handle the bad blocks myselfAltorelievo
@Altorelievo - yes... unless there's a hardware FTL in place. You might want to update your question you said in there a NAND flash memory (yaffs2) I guess to me that implied you were mounting a yaffs2 file system on your NAND flash device.Unweave
+1 If the flash is NAND, it may return errors like -EUCLEAN which means the NAND flash detected a bit-flip, but corrected the error. It means everything is ok, but the flash sector is wearing out. We used nandwrite and nandread as you suggested; why re-invent the wheel. Certainly the source to these programs can be helpful.Hawsepipe
I will have a look at the sources of this toolsAltorelievo
Great post! Allthough I have a problem. when calling write() I get the EINVAL error. Any idea what could cause this?Katowice
@Katowice - I updated the answer with some additional information about error values, but that's all in the man pages too. If you have additional questions you might want to open a new Question on SO. Link me to it and I'll take a look.Unweave
@Unweave Thanks! I did post a new question here: https://mcmap.net/q/829173/-getting-einval-when-trying-to-write-to-mtd-device/338476 Is there a special way of linking a user to a question?Katowice

© 2022 - 2024 — McMap. All rights reserved.