13

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?

artless noise
  • 21,212
  • 6
  • 68
  • 105
marmottus
  • 351
  • 1
  • 3
  • 18
  • Not sure if this helps, but have you seen the examples provided here: [link](http://www.linuxforu.com/2012/01/working-with-mtd-devices/), section "Accessing MTDs from applications" – Habi Mar 11 '13 at 10:55
  • Yeah I saw it ;-) I'm currently trying it – marmottus Mar 11 '13 at 10:59
  • 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. – Rerito Mar 11 '13 at 11:10
  • I want to write a kernel image on the partition that can be read by u-boot – marmottus Mar 11 '13 at 11:14
  • `how to write on this device` from user space or from kernel space? – Mike Mar 11 '13 at 12:10
  • from user space, I just need to read a file and write it bytes per bytes to /dev/mtdN – marmottus Mar 11 '13 at 13:19

1 Answers1

23

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.

Mike
  • 47,263
  • 29
  • 113
  • 177
  • 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 :-) – marmottus Mar 11 '13 at 14:20
  • 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? – marmottus Mar 11 '13 at 14:21
  • @marmottus - 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 sure – Mike Mar 11 '13 at 14:26
  • @marmottus - 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) – Mike Mar 11 '13 at 14:27
  • 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 myself – marmottus Mar 11 '13 at 15:15
  • 1
    @marmottus - 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. – Mike Mar 11 '13 at 15:27
  • +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. – artless noise Mar 11 '13 at 17:20
  • I will have a look at the sources of this tools – marmottus Mar 11 '13 at 17:43
  • 2
    Great post! Allthough I have a problem. when calling write() I get the EINVAL error. Any idea what could cause this? – tzippy Jun 18 '14 at 08:33
  • @tzippy - 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](http://stackoverflow.com/questions/ask). Link me to it and I'll take a look. – Mike Jun 18 '14 at 16:06
  • @Mike Thanks! I did post a new question here: http://stackoverflow.com/q/24302243/338476 Is there a special way of linking a user to a question? – tzippy Jun 19 '14 at 08:38