Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Discussion: littlefs on SPI NAND #11

Open
hchaudhary1 opened this issue Jan 19, 2018 · 77 comments
Open

Discussion: littlefs on SPI NAND #11

hchaudhary1 opened this issue Jan 19, 2018 · 77 comments

Comments

@hchaudhary1
Copy link

hchaudhary1 commented Jan 19, 2018

Hi I would like to use LittleFS directly on a NAND chip, such as Micron MT29F.

The minimum erasable unit on the MT29F is 128KiB
The smallest writable unit is 2KiB (random write)
The smallest writable unit is 1 byte (sequential write)

Thanks

@hchaudhary1
Copy link
Author

Forgot to ask my question... will LittleFS work with such a memory?
Thanks

@geky
Copy link
Member

geky commented Jan 20, 2018

Hi @hchaudhary1, at the moment you may run into problems.

LittleFS has only been used on NOR flash, eMMC, SD cards; devices with <4KB erase units, so I'm not sure how it will perform on NAND flash.

Concerns:

  1. You must provide ECC

    LittleFS will hand write errors, which is the main effect of flash wear. But with NAND memory you also have to worry about read errors. NAND memory is so dense that the stored electrons start misbehaving pretty easily.

    Scanning the MT29F's datasheet, it looks like that part has built in ECC you can use.

  2. On disk, each file uses 1 erase unit at minimum.

    For 128KiB erase units, this may waste a large amount of space.

    But NAND devices are also very large, so if you have few files this may not be a problem? I'm not sure. It probably depends a lot on how you use the filesystem.

    I have plans to improve this issue by storing multiple files in a block, but I don't know when I'll be able to implement the idea. So unfortunately at the moment 1 file per erase unit is the best LittleFS can do.

  3. You may need 2KiB (writable unit) of RAM for the program cache?

    I'm not sure if you can take advantage of the 1 byte sequential writes.

    For each block, LittleFS does write the data out sequentially. But, it may partially write to multiple erase units multiple times (for example, partially write erase unit A, partially write erase unit B, finish writing erase unit A). Can the NAND chip handle that sort of pattern?


At the moment, I think LittleFS might need a flash translation layer (FTL) to be efficient. An FTL would provide a smaller erase unit and prevent all of the issues, though you may still want to use LittleFS for power resilience.

At the very least, LittleFS is probably better than putting FAT directly on top of raw NAND.

If you do try to put LittleFS on a NAND chip, let me know how it goes! I'd be interested to know what sort of problems you run into.

@hchaudhary1
Copy link
Author

hchaudhary1 commented Jan 20, 2018

geky, thanks for elaborating on this

My hope is to avoid using a fully featured FTL layer such as dhara (https://github.com/dlbeer/dhara), since fail-safety, wear-leveling, and bad-block-management are already built into littlefs...

  1. ECC correction upon physical read is handled by the chip itself. Up to 8-bits can be corrupted in the physical page, but when the read happens, the data is corrected and fixed before transferring over SPI.

  2. The smallest capacity NAND (1Gbit) contains 1024 erasable units (each unit being 128KiB). This means I can have over 1000 files. This is more than enough for me. Capacity is also not an issue; I just need fast write speeds, which is why I am not using NOR.

  3. This is something I will have to test; especially in a multi-threaded environment where I will have multiple files open simultaneously.

I guess my main concern is what will happen to stale data that over several years develops more than 8-bits of errors. I supposed only static wear leveling can reduce this issue...

Thanks. I will provide some feedback

@geky
Copy link
Member

geky commented Jan 21, 2018

Ah interesting, that is a nice side effect of static wear leveling.

Though I've heard that errors from stale data are less concerning on SLC NAND parts. Looking at the MT29F's datasheet, it only mentions concerns about write errors:

Over time, some memory locations may fail to program or erase properly.

The same datasheet also lists a data retention of 10 years. I suspect that is in the case when the chip has no power, and may be the same for stale data. If you need longer data retention, you could probably increase the size of the ECC, though that may require software ECC.

Although it may be a good idea to ask someone who's a better expert on NAND memory.

@hchaudhary1
Copy link
Author

implementation was a success!

@geky
Copy link
Member

geky commented Jan 25, 2018

Ah! That is exciting! Thanks for the update.

@rahmanih
Copy link

rahmanih commented Apr 3, 2018

Hi,

just to understand, does littleFS support NAND flash without any change?

regards
Haithem.

@hchaudhary1
Copy link
Author

hchaudhary1 commented Apr 3, 2018

Yes, it supports NAND without modifications.
You have to write your own read, write, erase functions ofcoarse

EDIT:
Tested with Micron MT29F 1GiB model, that has hardware ECC.

@tomyqg
Copy link

tomyqg commented Apr 23, 2018

is there any example,how to use littlefs on spi nand?

@hassanmj
Copy link

hassanmj commented Jan 9, 2019

What is the status of LittleFS with NAND flash support? Any improvement?

@rojer
Copy link
Contributor

rojer commented Jan 9, 2019

there isn't anyhting special about nand and lfs, same as NOR pretty much. blocks are larger, but that's it.

@hchaudhary1
Copy link
Author

NAND working well

@timandr
Copy link

timandr commented Jan 24, 2019

I have connected the littlefs to NAND flash too. 1gb SPI nand W25N01. It works too. FTL didn't connect yet, maybe I will connect it later.

@joicetm
Copy link

joicetm commented Feb 26, 2019

Hi,

its good to see @hchaudhary1, @timandr made it work with NAND ,

i am also trying to add lfs to NAND based flash (winbond w25n01gv) with nrf52 but it gives mount error.

lfs error:495: Corrupted dir pair at 0 1
lfs error:2228: Invalid superblock at 0 1
lfs mount error
lfs error:494: Corrupted dir pair at 0 1
lfs error:2222: Invalid superblock at 0 1

i have added it without making any changes to the lfs, i have tested the read/write/erase functions and all are working fine.

this is how my implementation looks like,

const struct lfs_config cfg = {
// block device operations
.read = read_littlefs_wrapper,
.prog = write_littlefs_wrapper,
.erase = erase_littlefs_wrapper,
.sync = sync_littlefs_wrapper,

// block device configuration
.read_size = 24,
.prog_size = 24,
.block_size = 1024*64,
.block_count = 1024,
.lookahead = 2048,

};

these wrapper functions will call the spi based flash drivers.

void init_littlefs(){

int err = lfs_mount(&lfs, &cfg);

if (err) {
  printf("lfs mount error\n");
    lfs_format(&lfs, &cfg);
    err = lfs_mount(&lfs, &cfg);
    if(err) printf("failed to mount--------->\n");
}

// read current count
uint32_t boot_count = 0;
lfs_file_open(&lfs, &file, "boot_count", LFS_O_RDWR | LFS_O_CREAT);
lfs_file_read(&lfs, &file, &boot_count, sizeof(boot_count));

boot_count += 1;
lfs_file_rewind(&lfs, &file);
lfs_file_write(&lfs, &file, &boot_count, sizeof(boot_count));

lfs_file_read(&lfs, &file, &boot_count, sizeof(boot_count));
printf("boot count%ld\n", boot_count);

fs_file_close(&lfs, &file);
lfs_unmount(&lfs);

print the boot count
printf("boot_count: %d\n", boot_count);

}

I have also read somewhere that the SPI operations needs to be synchronous/blocking in order for lfs to work.
what does it mean?

as i have looked at the code lfc.c,
at line 462 condition fails,

    if ((0x7fffffff & test.size) < sizeof(test)+4 ||
        (0x7fffffff & test.size) > lfs->cfg->block_size) {
        continue;
    }

the read for srtuct test is all 0xff

i can see only one write operation before it fails, which i have tried to read back and it gives some data (1,0,0,0,20,0,0,0).
i think i am missing something but couldn't figure out whats wrong , i haven't also looked at the implementation of lfs in detail.

@hchaudhary1
Copy link
Author

Post your read/write/erase/sync functions... also you lfs_config struct settings...

@joicetm
Copy link

joicetm commented Feb 27, 2019

const struct lfs_config cfg = {
    // block device operations
    .read  = read_littlefs_wrapper,
    .prog  = write_littlefs_wrapper,
    .erase = erase_littlefs_wrapper,
    .sync  = sync_littlefs_wrapper,

    // block device configuration
    .read_size = 16,
    .prog_size = 16,
    .block_size = 2048*64,
    .block_count = 1024,
    .lookahead = 2048,
};


int read_littlefs_wrapper(const struct lfs_config *c, lfs_block_t block, lfs_off_t off, void *buffer, lfs_size_t size){

  int err = 0;

  uint16_t page_numb = (block * FLASH_BLOCK_SIZE_INPAGES) + (off/FLASH_PAGE_SIZE_INBYTES);
  uint16_t column_numb = off%FLASH_PAGE_SIZE_INBYTES;

  err = flash_w25n01gv_read_lfs(page_numb, column_numb,  buffer, size);

  return 0;
  //return err;
}

int write_littlefs_wrapper(const struct lfs_config *c, lfs_block_t block,
            lfs_off_t off, const void *buffer, lfs_size_t size){

  int err = 0;

  uint16_t page_numb = (block * FLASH_BLOCK_SIZE_INPAGES) + (off/FLASH_PAGE_SIZE_INBYTES);
  uint16_t column_numb = off%FLASH_PAGE_SIZE_INBYTES;

  err = flash_w25n01gv_write_lfs(page_numb, column_numb, (uint8_t *)  buffer, size);

  //return err;
  return 0;
}

int erase_littlefs_wrapper(const struct lfs_config *cfg, lfs_block_t block){

  flash_w25n01gv_erase_lfs(block);
return 0;
}

int sync_littlefs_wrapper(const struct lfs_config *cfg){
return 0;
}

flash details,

page size 2048
block size 64 pages
total blocks 1024

minimum write = 1 byte
minimum erase = 1 block

@hchaudhary1
Copy link
Author

i can't give my code, since it is closed source.
you need to test your read & write wrappers independently of littleFS first. you are not handling all the corner cases, such as, what if the requested read size is larger than the page size, etc...

Write in a test pattern (at a random offeset) with a large size, and read it back. Do this at multiple random starting blocks. once you can make that portion work, then everything should fall in place

@joicetm
Copy link

joicetm commented Mar 6, 2019

@hchaudhary1 thanks for the update, there was an issue with my spi driver while reading big blocks of code(limited dma size).

now its working like a charm :)

@kazola
Copy link

kazola commented Jun 5, 2019

Thanks for all your information sharing, plan to test this myself next week.

@kuoyaoming93
Copy link

Thank you for the great work!!! It works for Windbond W25M02GWZEIT (SLC Nand SPI Flash, 2 Gbit)

@visakh-png
Copy link

@hchaudhary1 thanks for the update, there was an issue with my spi driver while reading big blocks of code(limited dama size).

now its working like a charm :)

Hi hcChaudary/Joice,

  1. I am using Winbond QSPI Nand flash with W25N01GV 1 G-bit(128 MB) memory with only block erase(128 KB). Is there any size limitation for using higher size/Block-size in LittleFs?.

  2. For my flash memory (with a page read/program and block erase interface) , does it requires a flash translation layer?. In my first look and up on looking the configuration structures I felt like LittleFs is handling these translation.

  3. If it not requires the translation layer, Can I use it straight in my program which runs in FreeRTOS*?. With minimal mapping, i.e. only configuring "lfs_config".

Regards,
Visakh SV

@visakh-png
Copy link

@joicetm . Hi I am working on the same Winbond flash. Could you have some time to talk

@joicetm
Copy link

joicetm commented Jan 3, 2020

Hi visakh,

1, Not sure, the minimum value should be the chip block size 1024*64
2, I have not used FTL, it will work without an FTL.
3, Only the read, write , erase functions you have to create.

FYI, LFS still have some performance issues on NAND flash as the number of files increases.

@visakh-png
Copy link

@joicetm Hi Thanks Joice,

Yes. I have given the actual block size (128 KiB - 2048*64). I have created a separate post where I have added my code for test. Can you please check over there. This I have pasted here as well, can you please review it.

#361

I have ported littlefs to my application and written wrapper functions for it to attach to the config structure (lfs_config). This wrapper function is tested individually by writing a test application that writes a 100byte buffer to all the 1024 blocks (each block 128 KB) start addresses(first column) and read back and compared. All is Success.

But when I started to test with the example like in the littlefs readme.md mount error and format error has returned and finally hangs at fileopen(the next instruction). I can paste the test code here and config here, if someone have a clue please respond..... I expects a solution from @geky @geky
// configuration of the filesystem is provided by this struct
const struct lfs_config cfg = {
// block device operations
.read = QSPIFlashRead,
.prog = QSPIflashProgram,
.erase = QSPIflashErase,
.sync = QSPIflashSync,

// block device configuration
.read_size = 16,
.prog_size = 16,
.block_size = 0x20000, //128KB
.block_count = 0x400, //1024 blocks
.lookahead_size = 0x800, // less idea , but given size of a page
.cache_size = 16,
.block_cycles = 500,
};

------------------------------Test code -------------------------

uint32_t FlashTest(void) {
// mount the filesystem

uint32_t err = lfs_mount(&lfs, &cfg);

// reformat if we can't mount the filesystem
// this should only happen on the first boot
if (err) {
err= lfs_format(&lfs, &cfg);
{
CPrintf("ERROR: Format \n\r");
}
lfs_mount(&lfs, &cfg);
{
CPrintf("ERROR: Mount \n\r");
}
}
// read current count
uint32_t boot_count = 0;
err= lfs_file_open(&lfs, &file, "boot_count", LFS_O_RDWR | LFS_O_CREAT);
if(err)
{
CPrintf("ERROR: File Open \n\r");
}
err= lfs_file_read(&lfs, &file, &boot_count, sizeof(boot_count));
if(err)
{
CPrintf("ERROR: File Read \n\r");
}

// update boot count
boot_count += 1;
err= lfs_file_rewind(&lfs, &file);
if(err)
{
CPrintf("ERROR: File Rewind \n\r");
}

err= lfs_file_write(&lfs, &file, &boot_count, sizeof(boot_count));

if(err)
{
CPrintf("ERROR: File Write \n\r");
}

// remember the storage is not updated until the file is closed successfully
err= lfs_file_close(&lfs, &file);

if(err)
{
CPrintf("ERROR: File Close \n\r");
}

// release any resources we were using
lfs_unmount(&lfs);

// print the boot count
CPrintf("boot_count: %d\n", boot_count);
}

@visakh-png
Copy link

@joicetm .

Hi @joicetm .
PF the log from my console, If you can figure out the issue,

lfs_trace:3603: lfs_mount(0x2001b484, 0x8022470 {.context=0, .read=0x8003d65, .p rog=0x8003d91, .erase=0x8003dbd, .sync=0x8003de3, .read_size=16, .prog_size=16, .block_size=131072, .block_count=1024, .block_cycles=500, .cache_size=16, .looka head_size=2048, .read_buffer=0, .prog_buffer=0, .lookahead_buffer=0, .name_max=0 , .file_max=0, .attr_max=0})
lfs_error:977: Corrupted dir pair at 0 1
lfs_trace:3727: lfs_unmount(0x2001b484)
lfs_trace:3729: lfs_unmount -> 0
lfs_trace:3722: lfs_mount -> -84
lfs_trace:3522: lfs_format(0x2001b484, 0x8022470 {.context=0, .read=0x8003d65, . prog=0x8003d91, .erase=0x8003dbd, .sync=0x8003de3, .read_size=16, .prog_size=16, .block_size=131072, .block_count=1024, .block_cycles=500, .cache_size=16, .look ahead_size=2048, .read_buffer=0, .prog_buffer=0, .lookahead_buffer=0, .name_max= 0, .file_max=0, .attr_max=0})

@joicetm
Copy link

joicetm commented Jan 8, 2020

Make sure that your read/write/erase functions are working fine.
Also make some test cases to test all possible corner cases. it should work.

@pauloet
Copy link

pauloet commented May 20, 2021

Also, since the lfs_config struct has a cache_size, I suggest to add a buffer pointer in that structure for the cache buffer. This can make it simpler for those who don't use MALLOC.
void *cache_buffer;
This way, everything stays in the global configuration.

Are you suggesting a pointer to the on-chip cache? That is not the same as the LFS cache buffer and because it is not memory mapped you would have to implement a management layer. If you are using a QSPI memory interface to interface with the NAND, maybe it would be feasible to to do something like that. I have been wondering if we could disable the LFS cache somehow and use the on-chip cache but I am not certain you can do that and there may be performance issues. @geky would have to wade in on that.

I was suggesting it just for the LFS cache buffer, but your idea seems to be useful indeed.

@pauloet
Copy link

pauloet commented May 20, 2021

I do not think the look ahead buffer needs to be that large. You can probably reduce that considerably.
The Kioxia flash devices support partial page writes so you can use a smaller page size (1024 instead of 4096) and reduce your buffer sizes as well.
I have noticed a peculiar thing about the Kioxia nand. When reading a page from nand, the OIP time will occasionally exceed the max page read time specification in the data sheet. I am wondering if this is common for other nand devices?

Yes, it supports the page partial program, but I've tested to write byte-by-byte and it also works. So maybe doing as discussed at #277 can achieve a best performance right?

I think you might be confusing the write to the on-chip cache with the page write. There is a limit to the number of writes you can do to the cell array. This is specified in the datasheet as " Number of programs per page" which for the Kioxia chip is 4 (other vendors may only allow 1. For instance, the Alliance chips). You can certainly write byte-by-byte to the cache. But when it comes time to write the cache to the nand cell array, you are limited to 4 times. There are some other limitations related to how the ECC is calculated that impact this as well. The simple solution is to use 1K blocks.

Here's what I'm struggling now because I agree with what you say about what the datasheet says. However, my tests tell me that I can really write byte-by-byte to the cell array. My prog function looks like:

BOOL Flash_LFS_Prog( ... )
{
   if (Flash_EnableWrite() == FALSE)
        return FALSE;

   if (Flash_ProgramLoad(src, colAddr, size) == FALSE)
        return FALSE;

   if (Flash_ProgramExecute(rowAddr) == FALSE)
        return FALSE;

   Flash_DisableWrite();
   return TRUE;
}

By performing the Program execute, I think I'm writing it to the cell array. What am I missing?
Thanks again for your support!

@sslupsky
Copy link

Yes, that is correct. Each time you execute "Program Execute", you write the on chip cache to the NAND cell array. My understanding of what the datasheet says is you can only do this 4 times before you have to erase the block. I haven't actually tried to see if I could write the page more than 4 times. If you go down this path I would be interested to learn how reliable it is.

There are some implications for the spare area as well. ECC is calculated on 512 byte sub blocks of the page. So, when you program the page, ECC is calculated for each 512 chunk.

@pauloet
Copy link

pauloet commented May 20, 2021

Yes, that is correct. Each time you execute "Program Execute", you write the on chip cache to the NAND cell array. My understanding of what the datasheet says is you can only do this 4 times before you have to erase the block. I haven't actually tried to see if I could write the page more than 4 times. If you go down this path I would be interested to learn how reliable it is.

There are some implications for the spare area as well. ECC is calculated on 512 byte sub blocks of the page. So, when you program the page, ECC is calculated for each 512 chunk.

Yes, with ECC enabled it's like that, but for now I'm disabling it to keep it simple. I'm not using the spare area also because I can detect if the block is bad or not while doing a block erase or a page program. Besides that, my Flash_LFS_Sync function is returning always 0 because I'm doing the program execute always on the Flash_LFS_Prog. Maybe it's better to switch the program execute to the Flash_LFS_Sync function right?

About the reliability you say, I suspect it's not the best approach (byte-by-byte) to achieve a good one.

@alperenemiroglu
Copy link

@geky @joicetm . I have solved the issue with the help of another person who has faced same issue with QSPI NAND. Please note that this will never come in the case of SPI, as this is a problem bw STM32 QSPI and the W25N01GV NAND.

The microcontroller sends the QSPI command(HAL_QSPI_Command) fields in the order:

  1. Instruction
  2. Address
  3. Alternate bytes
  4. Dummy Clocks
  5. Data

But, according to the Winbond data sheet, some commands (those in which the page address is used) need the address after the dummy clock. So this cannot be achieved with sending a QSPI command. So, for these commands now I am sending HAL_QSPI_Command with no address and then sending the address as if it were the data, with "HAL_QSPI_Transmit" function.

FYI. I am not using littlefs now, Instead managing a static queue that holds address and size of data in NAND. Once I get some time I will check with LittleFS. I hope performance will be better as compared to SPI since Quad SPI is much faster.

Regards,
Visakh

@geky @joicetm . I have solved the issue with the help of another person who has faced same issue with QSPI NAND. Please note that this will never come in the case of SPI, as this is a problem bw STM32 QSPI and the W25N01GV NAND.

The microcontroller sends the QSPI command(HAL_QSPI_Command) fields in the order:

  1. Instruction
  2. Address
  3. Alternate bytes
  4. Dummy Clocks
  5. Data

But, according to the Winbond data sheet, some commands (those in which the page address is used) need the address after the dummy clock. So this cannot be achieved with sending a QSPI command. So, for these commands now I am sending HAL_QSPI_Command with no address and then sending the address as if it were the data, with "HAL_QSPI_Transmit" function.

FYI. I am not using littlefs now, Instead managing a static queue that holds address and size of data in NAND. Once I get some time I will check with LittleFS. I hope performance will be better as compared to SPI since Quad SPI is much faster.

Regards,
Visakh

Hi,
I am currently experiencing the problem you describe.
When You say you are sending it back to back,
Firstly,
HAL_StatusTypeDef status;
QSPI_CommandTypeDef cmd;
cmd.InstructionMode = QSPI_INSTRUCTION_1_LINE;
cmd.AddressMode = QSPI_ADDRESS_NONE;
cmd.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
cmd.DataMode = QSPI_DATA_NONE;
cmd.DummyCycles = dummyCycles;
cmd.DdrMode = QSPI_DDR_MODE_DISABLE;
cmd.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
cmd.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;

cmd.Instruction       = 0xD8; // erase
cmd.Address           = 0x00;
cmd.AddressSize     =0x00;
cmd.NbData            = 0;

Are you sending the address like this?

QSPI_CommandTypeDef cmd;
cmd.InstructionMode   = QSPI_INSTRUCTION_1_LINE;
cmd.AddressMode       = QSPI_ADDRESS_1_LINE;
cmd.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
cmd.DataMode          = QSPI_DATA_NONE;
cmd.DummyCycles       = 0;
cmd.DdrMode           = QSPI_DDR_MODE_DISABLE;
cmd.DdrHoldHalfCycle  = QSPI_DDR_HHC_ANALOG_DELAY;
cmd.SIOOMode          = QSPI_SIOO_INST_EVERY_CMD;

cmd.Instruction       = 0xD8; // erase
cmd.Address           = page_address;
cmd.AddressSize     = QSPI_ADDRESS_16_BITS;
cmd.NbData            = 0;

Did you try to do this? I understood that from what you said.

@zbqxyz
Copy link

zbqxyz commented Aug 11, 2021

@hchaudhary1 @geky
How to deal with bad blocks ?Factory-generated bad blocks or erase/write?
I have this nand flash:
Page Size 2048
block_Count 1024

Use below config is OK?

.read_size = 2048,
.prog_size = 2048,
.block_size = 2048 * 64,
.block_count = 1024,
.cache_size = 2048,
.lookahead_size = 2048,
.block_cycles = 500,

@hchaudhary1
Copy link
Author

I believe LittleFS already has bad block management

@rojer
Copy link
Contributor

rojer commented Aug 11, 2021

yes, the idea is that failing writes will be reallocated to a different block

@zbqxyz
Copy link

zbqxyz commented Aug 13, 2021

@hchaudhary1 @rojer
when failing writes return LFS_ERR_CORRUPT?but i test ,mark block 0 bad ,Error when open then read file,test code below,
Step1: erase all block
Step2: mark block0 bad
Step3: in nand drv port : _block_read ,_block_erase _block_prog
if block bad return LFS_ERR_CORRUPT

Run code :
int err = lfs_mount(&cfg_NandFlash, &cfg_NandFlash);
if (err) {
LFS_LOG_WARN("first fs mount failed\n");
lfs_format(&cfg_NandFlash, &cfg_NandFlash);
lfs_mount(&cfg_NandFlash, &cfg_NandFlash);
}
#if 1
uint32_t boot_count = 0;
FS_FILE *fp = fs_open("boot_count", LFS_O_RDWR | LFS_O_CREAT);
fs_read(&boot_count, sizeof(boot_count), fp);
LFS_LOG_ERROR("boot_count is %d\n", boot_count);
boot_count += 1;
fs_seek(fp, 0, LFS_SEEK_SET);
fs_write(&boot_count, sizeof(boot_count), fp);
fs_seek(fp, 0, LFS_SEEK_SET);
boot_count = 0;
fs_read(&boot_count, sizeof(boot_count), fp);
LFS_LOG_ERROR("boot_count is %d\n", boot_count);
fs_close(fp);
#endif

Err info:
lfs.c
line:5161
Expression Faild :
lfs_mlist_open

@zbqxyz
Copy link

zbqxyz commented Aug 13, 2021

I tested without bad blocks and it works fine

@zbqxyz
Copy link

zbqxyz commented Aug 13, 2021

i debug in lfs_format ,when call lfs_dir_compact, lfs_bd_erase(block 0) return LFS_ERR_CORRUPT,goto relocate

run here return LFS_ERR_NOSPC;
// can't relocate superblock, filesystem is now frozen
if (lfs_pair_cmp(dir->pair, (const lfs_block_t[2]){0, 1}) == 0) {
LFS_WARN("Superblock 0x%"PRIx32" has become unwritable",
dir->pair[1]);
return LFS_ERR_NOSPC;
}

@zbqxyz
Copy link

zbqxyz commented Aug 13, 2021

@geky @hchaudhary1 @rojer
so when bad block at 0 or 1
littlefs cannot handle this situation?

@rojer
Copy link
Contributor

rojer commented Aug 13, 2021

yeah, i guess when block 0 or 1, the superblocks, go bad, it's game over. fortunately, they don't get changed much, normally.

@ferremarco
Copy link

Yes, it supports NAND without modifications. You have to write your own read, write, erase functions ofcoarse

EDIT: Tested with Micron MT29F 1GiB model, that has hardware ECC.

Can you share the MT29F wrapper ?

@votuananhs
Copy link

@zbqxyz and @hchaudhary1

Which nand (mt29f2g01abagdwb), it has 128 bytes per page. So I don't see and understand why you didn't include it in littlefs configuration. Without that it will calculate wrong physical block ?

@Jacq666
Copy link

Jacq666 commented Oct 11, 2022

Hello,

I am using LittleFs on a spi nand flash Micron, MT29F and it works very well.

But now, I would like to improve write speed, if possible.

I understand (tell me if I am wrong), that after every write, there is a read spi transfert, and a compare to check.

Pleased find enclosed a timing:

  • CS and CLK of spi
  • Debug is the whole duration of lfs_file_write
    We see that about 1/3 of time is write, 1/3 is read, 1/3 is compare.

But MT29F nand flash provide an 'uncorrected ECC error code' when it cannot correct read page.

So I think that we just have to test the flag, no need to do a spi read transfert to check write. So we could avoid many read spi transferts.

What do you think about this ?

Thank you, best regards

image

@Jacq666
Copy link

Jacq666 commented Oct 17, 2022 via email

@mattmercaldo
Copy link

Perfect! Thanks so much!

@CalebDueck
Copy link

@joicetm I am wondering what SPI driver you are using? I am using the same Winbond NAND memory and can't find the driver that provides the functions your wrapper uses.
flash_w25n01gv_read_lfs or similar functions

Any help would be appreciated. Or if there are other drivers that would do the job that would be much appreciated.

@CalebDueck
Copy link

CalebDueck commented Jan 31, 2023

Update, if you contact Winbond they can provide you with an example driver that works on STM32 MCUs.
I used this as the basis of my own driver.

@p3zhy
Copy link

p3zhy commented Feb 3, 2023

Hello .I am using LittleFs on a spi nand flash in esp32s3.
What suggestions do you have to increase the speed of reading and writing?
In a situation where the number of files is small, I can read 3 files with size 100 byte in a second. By increasing the number of files to 3000, the speed decreases a lot and it takes 40 seconds to read 3 files .

@gineelee
Copy link

gineelee commented May 11, 2023

Hi,
Does your user application directly access the NAND flash through Zephyr's FS subsystem (fs_xxx) or LittleFS interfaces (lfs_xxx)? I ask because I encountered a linking issue when attempting to use Zephyr's FS subsystem by adding partition configuration in the device tree.

However, everything works perfectly when I utilize the LittleFS interfaces to access the NAND flash.

[Partition configuration]
&MT29FXXX {
partitions {
compatible = "fixed-partitions";
#address-cells = <1>;
#size-cells = <1>;
littlefs_partition: partition@0 {
label = "littlefs_storage";
reg = <0x00000000 0x001000000>;
};
};
};

[Application]
#define STORAGE_PARTITION littlefs_partition
#define STORAGE_PARTITION_ID FIXED_PARTITION_ID(STORAGE_PARTITION)

static struct fs_mount_t lfs_mnt = {
.type = FS_LITTLEFS,
.fs_data = &cfg,
.storage_dev = (void*)STORAGE_PARTITION_ID,
.mnt_point = "/littlefs",
};
...
fs_mount(&lfs_mnt);

[Error messages]
[4/12] Linking C executable zephyr/zephyr_pre0.elf FAILED: bin/ld.bfd: zephyr/libzephyr.a(flash_map_default.c.obj):(.rodata.default_flash_map+0x4c): undefined reference to __device_dts_ord_98

__device_dts_ord_98 corresponds to my spi flash driver

I constructed my SPI NAND flash driver as an out-of-tree driver, considering that it might be the cause of the problem.
I'm curious to know if you encountered a similar issue when building your SPI NAND driver outside of the Zephyr codebase and adding partition configurations.

@mintisan
Copy link

mintisan commented Jun 13, 2023

wonderful discussion...

@ParthJaiswal17
Copy link

Hi,

I am also working on porting littlefs driver, on top of MT29. I am able to port the fs.

Although while life testing, I am getting -84 error (i.e. LFS_ERR_CORRUPT) after I write around 210 files of 3K, and after that complete file system gets corrupted.

So can anyone help me to understand the cause of error.

My config struct is as follows:

const struct lfs_config cfg = {

.context = NULL,
.read = lfsread,
.prog = lfsprog,
.erase = lfserase,
.sync = lfssync,

#ifdef LFS_THREADSAFE
.lock = sh_lfslock,
.unlock = sh_lfsunlock,
#endif

.read_size = 4096,
.prog_size = 4096,
.block_size = 4096,
.block_count = 262144,
.block_cycles = 512,
.cache_size = 4096,
.lookahead_size = 4096,

};

@mattmercaldo
Copy link

mattmercaldo commented Jul 13, 2023 via email

@ParthJaiswal17
Copy link

Hi mattmercaldo,

Thank you for the advice, although if decrease the prog size to 1024, I get ecc error during read, also if reduce read size I am getting error while reading file number 32, must be metadeta issue.

Although the update is I have resolved the Issue by Increasing the block size to actual block size of MT29 flash which is 256KB and now it is working well, but with the cost of low speed.

Thank you.

@BadboyIntheLoop
Copy link

NAND working well

Hello @hchaudhary1
Can you give me the config for littleFS, in my case, I'vs already completed the driver for MT29F2G01 flash (read/prog/erase working ok) but I'm stucking at some points.
Anyway, if you do not mind, can you give me your contact, I wanna ask you some questions about your config for littlefs on that nand flash. Thank you

@Motirn
Copy link

Motirn commented Dec 18, 2023

Trying to get littleFS running on w25m02gw SPI NAND, So far it seem to be working okay, with ability to write multiple file, read back and confirm data..etc.

.read_size/.prog_size is 2048 bytes(page size), and .erase_size is 64 x page size(128KB)

@hchaudhary1 Any guess Why I am seeing frequent block erases.. on every 4K write? It appears like its starting on a new block on every write.

More details here - #905

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests