You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@nuttx.apache.org by Javier Alonso <ja...@geotab.com.INVALID> on 2025/10/22 16:11:27 UTC

Inquiry about LittleFS + FTL + Progmem

Hello devs,

I'm playing around with some LittleFS configuration on an STM32G0 device. I
have the following snippet:

```
#ifdef CONFIG_MTD_PROGMEM
struct mtd_dev_s * mtd;
/* Initialize on-chip program memory support */
mtd = stm32_progmem_initialize();
if (mtd == NULL)
  {
    syslog(LOG_ERR, "ERROR: stm32_progmem_initialize() failed\n");
  }
else
  {
    ret = ftl_initialize(0, mtd);
    if (ret < 0)
     {
       syslog(LOG_ERR, "ERROR: ftl_initialize() failed: %d\n", ret);
     }
   }
#endif /* CONFIG_MTD_PROGMEM */
#ifdef CONFIG_FS_LITTLEFS
ret = nx_mount("/dev/mtdblock0", "/mnt/progmem", "littlefs", 0,
"autoformat");
if (ret < 0)
  {
    syslog(LOG_ERR, "ERROR: Failed to mount littlefs at /mnt/progmem:
%d\n", ret);
  }
#endif
```
(I'm omitting the internals, but I've implemented the "progmem" layer for
the STM32G0 with the required "up_" functions).

So far the code runs correctly until the "nx_mount" call is reached. It
fails with "ret = -28", which stands for "ENOSPC". I've been digging around
some forums and it seems the LFS configuration may be wrong. For instance:

```
fs->cfg.context = fs;
fs->cfg.read = littlefs_read_block;
fs->cfg.prog = littlefs_write_block;
fs->cfg.erase = littlefs_erase_block;
fs->cfg.sync = littlefs_sync_block;
fs->cfg.read_size = fs->geo.blocksize *
                    CONFIG_FS_LITTLEFS_READ_SIZE_FACTOR;
fs->cfg.prog_size = fs->geo.blocksize *
                    CONFIG_FS_LITTLEFS_PROGRAM_SIZE_FACTOR;
fs->cfg.block_size = fs->geo.erasesize *
                     CONFIG_FS_LITTLEFS_BLOCK_SIZE_FACTOR;
fs->cfg.block_count = fs->geo.neraseblocks /
                      CONFIG_FS_LITTLEFS_BLOCK_SIZE_FACTOR;
fs->cfg.block_cycles = CONFIG_FS_LITTLEFS_BLOCK_CYCLE;
fs->cfg.cache_size = fs->geo.blocksize *
                     CONFIG_FS_LITTLEFS_CACHE_SIZE_FACTOR;
```

The geometry is directly obtained from the underlying FTL MTD device. For
this particular case, I'm reserving 4KB at the end of the flash to be used
as user memory with a fixed page size of 2KB and 2 pages.

- up_progmem_neraseblocks -> 2
- up_progmem_isuniform -> true
- up_progmem_pagesize(n) -> 2048
- up_progmem_erasesize(n) -> 2048

I've tried changing the different LFS configurations, so now I have:

- CONFIG_FS_LITTLEFS_READ_SIZE_FACTOR=1
- CONFIG_FS_LITTLEFS_PROGRAM_SIZE_FACTOR=1
- CONFIG_FS_LITTLEFS_BLOCK_SIZE_FACTOR=1
- CONFIG_FS_LITTLEFS_BLOCK_CYCLE=200 (default)
- CONFIG_FS_LITTLEFS_CACHE_SIZE_FACTOR=1
- CONFIG_FS_LITTLEFS_LOOKAHEAD_SIZE=0
- CONFIG_FS_LITTLEFS_ATTR_MAX=1022 (default)

Is there anything I need to tweak or adjust for LFS to work? So far I've
been unable to make it, it fails on the mount stage.

Thanks in advance,

Javier Alonso (he, him, his)
Geotab

Team Lead - Embedded Systems | GEUR

Re: Inquiry about LittleFS + FTL + Progmem

Posted by Javier Alonso <ja...@geotab.com.INVALID>.
Follow-up of the conversation.

The problem was not the configured size (I was able to make it work
with 4K). I was missing adding a __ISB between writes: LittleFS was
verifying the memory but failed due to CRC. Instead of forwarding the
"LFS_ERR_CORRUPTED" back, it was changed (I don't know why) with
-ENOSPC.

Once I added the synchronization barrier, everything is working as expected :)

Thanks,

Javier Alonso (he, him, his)
Geotab

Team Lead - Embedded Systems | GEUR

Javier Alonso (he, him, his)
Geotab

Team Lead - Embedded Systems | GEUR


Quickly schedule a meeting

Toll-free

Visit

+1 (877) 436-8221
www.geotab.com

X | Facebook | YouTube | LinkedIn

Celebrating 25 years of innovation and impact



On Mon, Oct 27, 2025 at 12:15 PM Javier Alonso <ja...@geotab.com> wrote:
>
> I'm going to give it a try, thanks Jehudi!
>
> Although it doesn't fit our needs, we'd need a FS that supports
> smaller values. Do you have any suggestions and/or recommendations for
> an FS embedded into NuttX that we can use for this purpose? I've been
> digging into some NuttX docs about this, but I only found LittleFS to
> be the one with examples on how to configure it.
>
> Best regards,
>
> Javier Alonso (he, him, his)
> Geotab
>
> Team Lead - Embedded Systems | GEUR
>
> Javier Alonso (he, him, his)
> Geotab
>
> Team Lead - Embedded Systems | GEUR
>
>
> Quickly schedule a meeting
>
> Toll-free
>
> Visit
>
> +1 (877) 436-8221
> www.geotab.com
>
> X | Facebook | YouTube | LinkedIn
>
> Celebrating 25 years of innovation and impact
>
>
>
> On Wed, Oct 22, 2025 at 6:24 PM Laczen JMS <la...@gmail.com> wrote:
> >
> > Hi Javier,
> >
> > Littles needs more than 2 blocks. At least 4 are required IIRC, but more to
> > be really functional. When working with flash always remember that a
> > complete page needs to be erased before it can be reused, when there are
> > only 2 blocks everything needs to fit in one block (nothing can be stored
> > in ram because a reboot could destroy it).
> >
> > Hope this helps,
> >
> > Kind regards,
> >
> > Jehudi
> >
> > On Wed, Oct 22, 2025, 18:12 Javier Alonso <ja...@geotab.com.invalid>
> > wrote:
> >
> > > Hello devs,
> > >
> > > I'm playing around with some LittleFS configuration on an STM32G0 device. I
> > > have the following snippet:
> > >
> > > ```
> > > #ifdef CONFIG_MTD_PROGMEM
> > > struct mtd_dev_s * mtd;
> > > /* Initialize on-chip program memory support */
> > > mtd = stm32_progmem_initialize();
> > > if (mtd == NULL)
> > >   {
> > >     syslog(LOG_ERR, "ERROR: stm32_progmem_initialize() failed\n");
> > >   }
> > > else
> > >   {
> > >     ret = ftl_initialize(0, mtd);
> > >     if (ret < 0)
> > >      {
> > >        syslog(LOG_ERR, "ERROR: ftl_initialize() failed: %d\n", ret);
> > >      }
> > >    }
> > > #endif /* CONFIG_MTD_PROGMEM */
> > > #ifdef CONFIG_FS_LITTLEFS
> > > ret = nx_mount("/dev/mtdblock0", "/mnt/progmem", "littlefs", 0,
> > > "autoformat");
> > > if (ret < 0)
> > >   {
> > >     syslog(LOG_ERR, "ERROR: Failed to mount littlefs at /mnt/progmem:
> > > %d\n", ret);
> > >   }
> > > #endif
> > > ```
> > > (I'm omitting the internals, but I've implemented the "progmem" layer for
> > > the STM32G0 with the required "up_" functions).
> > >
> > > So far the code runs correctly until the "nx_mount" call is reached. It
> > > fails with "ret = -28", which stands for "ENOSPC". I've been digging around
> > > some forums and it seems the LFS configuration may be wrong. For instance:
> > >
> > > ```
> > > fs->cfg.context = fs;
> > > fs->cfg.read = littlefs_read_block;
> > > fs->cfg.prog = littlefs_write_block;
> > > fs->cfg.erase = littlefs_erase_block;
> > > fs->cfg.sync = littlefs_sync_block;
> > > fs->cfg.read_size = fs->geo.blocksize *
> > >                     CONFIG_FS_LITTLEFS_READ_SIZE_FACTOR;
> > > fs->cfg.prog_size = fs->geo.blocksize *
> > >                     CONFIG_FS_LITTLEFS_PROGRAM_SIZE_FACTOR;
> > > fs->cfg.block_size = fs->geo.erasesize *
> > >                      CONFIG_FS_LITTLEFS_BLOCK_SIZE_FACTOR;
> > > fs->cfg.block_count = fs->geo.neraseblocks /
> > >                       CONFIG_FS_LITTLEFS_BLOCK_SIZE_FACTOR;
> > > fs->cfg.block_cycles = CONFIG_FS_LITTLEFS_BLOCK_CYCLE;
> > > fs->cfg.cache_size = fs->geo.blocksize *
> > >                      CONFIG_FS_LITTLEFS_CACHE_SIZE_FACTOR;
> > > ```
> > >
> > > The geometry is directly obtained from the underlying FTL MTD device. For
> > > this particular case, I'm reserving 4KB at the end of the flash to be used
> > > as user memory with a fixed page size of 2KB and 2 pages.
> > >
> > > - up_progmem_neraseblocks -> 2
> > > - up_progmem_isuniform -> true
> > > - up_progmem_pagesize(n) -> 2048
> > > - up_progmem_erasesize(n) -> 2048
> > >
> > > I've tried changing the different LFS configurations, so now I have:
> > >
> > > - CONFIG_FS_LITTLEFS_READ_SIZE_FACTOR=1
> > > - CONFIG_FS_LITTLEFS_PROGRAM_SIZE_FACTOR=1
> > > - CONFIG_FS_LITTLEFS_BLOCK_SIZE_FACTOR=1
> > > - CONFIG_FS_LITTLEFS_BLOCK_CYCLE=200 (default)
> > > - CONFIG_FS_LITTLEFS_CACHE_SIZE_FACTOR=1
> > > - CONFIG_FS_LITTLEFS_LOOKAHEAD_SIZE=0
> > > - CONFIG_FS_LITTLEFS_ATTR_MAX=1022 (default)
> > >
> > > Is there anything I need to tweak or adjust for LFS to work? So far I've
> > > been unable to make it, it fails on the mount stage.
> > >
> > > Thanks in advance,
> > >
> > > Javier Alonso (he, him, his)
> > > Geotab
> > >
> > > Team Lead - Embedded Systems | GEUR
> > >

Re: Inquiry about LittleFS + FTL + Progmem

Posted by Javier Alonso <ja...@geotab.com.INVALID>.
I'm going to give it a try, thanks Jehudi!

Although it doesn't fit our needs, we'd need a FS that supports
smaller values. Do you have any suggestions and/or recommendations for
an FS embedded into NuttX that we can use for this purpose? I've been
digging into some NuttX docs about this, but I only found LittleFS to
be the one with examples on how to configure it.

Best regards,

Javier Alonso (he, him, his)
Geotab

Team Lead - Embedded Systems | GEUR

Javier Alonso (he, him, his)
Geotab

Team Lead - Embedded Systems | GEUR


Quickly schedule a meeting

Toll-free

Visit

+1 (877) 436-8221
www.geotab.com

X | Facebook | YouTube | LinkedIn

Celebrating 25 years of innovation and impact



On Wed, Oct 22, 2025 at 6:24 PM Laczen JMS <la...@gmail.com> wrote:
>
> Hi Javier,
>
> Littles needs more than 2 blocks. At least 4 are required IIRC, but more to
> be really functional. When working with flash always remember that a
> complete page needs to be erased before it can be reused, when there are
> only 2 blocks everything needs to fit in one block (nothing can be stored
> in ram because a reboot could destroy it).
>
> Hope this helps,
>
> Kind regards,
>
> Jehudi
>
> On Wed, Oct 22, 2025, 18:12 Javier Alonso <ja...@geotab.com.invalid>
> wrote:
>
> > Hello devs,
> >
> > I'm playing around with some LittleFS configuration on an STM32G0 device. I
> > have the following snippet:
> >
> > ```
> > #ifdef CONFIG_MTD_PROGMEM
> > struct mtd_dev_s * mtd;
> > /* Initialize on-chip program memory support */
> > mtd = stm32_progmem_initialize();
> > if (mtd == NULL)
> >   {
> >     syslog(LOG_ERR, "ERROR: stm32_progmem_initialize() failed\n");
> >   }
> > else
> >   {
> >     ret = ftl_initialize(0, mtd);
> >     if (ret < 0)
> >      {
> >        syslog(LOG_ERR, "ERROR: ftl_initialize() failed: %d\n", ret);
> >      }
> >    }
> > #endif /* CONFIG_MTD_PROGMEM */
> > #ifdef CONFIG_FS_LITTLEFS
> > ret = nx_mount("/dev/mtdblock0", "/mnt/progmem", "littlefs", 0,
> > "autoformat");
> > if (ret < 0)
> >   {
> >     syslog(LOG_ERR, "ERROR: Failed to mount littlefs at /mnt/progmem:
> > %d\n", ret);
> >   }
> > #endif
> > ```
> > (I'm omitting the internals, but I've implemented the "progmem" layer for
> > the STM32G0 with the required "up_" functions).
> >
> > So far the code runs correctly until the "nx_mount" call is reached. It
> > fails with "ret = -28", which stands for "ENOSPC". I've been digging around
> > some forums and it seems the LFS configuration may be wrong. For instance:
> >
> > ```
> > fs->cfg.context = fs;
> > fs->cfg.read = littlefs_read_block;
> > fs->cfg.prog = littlefs_write_block;
> > fs->cfg.erase = littlefs_erase_block;
> > fs->cfg.sync = littlefs_sync_block;
> > fs->cfg.read_size = fs->geo.blocksize *
> >                     CONFIG_FS_LITTLEFS_READ_SIZE_FACTOR;
> > fs->cfg.prog_size = fs->geo.blocksize *
> >                     CONFIG_FS_LITTLEFS_PROGRAM_SIZE_FACTOR;
> > fs->cfg.block_size = fs->geo.erasesize *
> >                      CONFIG_FS_LITTLEFS_BLOCK_SIZE_FACTOR;
> > fs->cfg.block_count = fs->geo.neraseblocks /
> >                       CONFIG_FS_LITTLEFS_BLOCK_SIZE_FACTOR;
> > fs->cfg.block_cycles = CONFIG_FS_LITTLEFS_BLOCK_CYCLE;
> > fs->cfg.cache_size = fs->geo.blocksize *
> >                      CONFIG_FS_LITTLEFS_CACHE_SIZE_FACTOR;
> > ```
> >
> > The geometry is directly obtained from the underlying FTL MTD device. For
> > this particular case, I'm reserving 4KB at the end of the flash to be used
> > as user memory with a fixed page size of 2KB and 2 pages.
> >
> > - up_progmem_neraseblocks -> 2
> > - up_progmem_isuniform -> true
> > - up_progmem_pagesize(n) -> 2048
> > - up_progmem_erasesize(n) -> 2048
> >
> > I've tried changing the different LFS configurations, so now I have:
> >
> > - CONFIG_FS_LITTLEFS_READ_SIZE_FACTOR=1
> > - CONFIG_FS_LITTLEFS_PROGRAM_SIZE_FACTOR=1
> > - CONFIG_FS_LITTLEFS_BLOCK_SIZE_FACTOR=1
> > - CONFIG_FS_LITTLEFS_BLOCK_CYCLE=200 (default)
> > - CONFIG_FS_LITTLEFS_CACHE_SIZE_FACTOR=1
> > - CONFIG_FS_LITTLEFS_LOOKAHEAD_SIZE=0
> > - CONFIG_FS_LITTLEFS_ATTR_MAX=1022 (default)
> >
> > Is there anything I need to tweak or adjust for LFS to work? So far I've
> > been unable to make it, it fails on the mount stage.
> >
> > Thanks in advance,
> >
> > Javier Alonso (he, him, his)
> > Geotab
> >
> > Team Lead - Embedded Systems | GEUR
> >

Re: Inquiry about LittleFS + FTL + Progmem

Posted by Laczen JMS <la...@gmail.com>.
Hi Javier,

Littles needs more than 2 blocks. At least 4 are required IIRC, but more to
be really functional. When working with flash always remember that a
complete page needs to be erased before it can be reused, when there are
only 2 blocks everything needs to fit in one block (nothing can be stored
in ram because a reboot could destroy it).

Hope this helps,

Kind regards,

Jehudi

On Wed, Oct 22, 2025, 18:12 Javier Alonso <ja...@geotab.com.invalid>
wrote:

> Hello devs,
>
> I'm playing around with some LittleFS configuration on an STM32G0 device. I
> have the following snippet:
>
> ```
> #ifdef CONFIG_MTD_PROGMEM
> struct mtd_dev_s * mtd;
> /* Initialize on-chip program memory support */
> mtd = stm32_progmem_initialize();
> if (mtd == NULL)
>   {
>     syslog(LOG_ERR, "ERROR: stm32_progmem_initialize() failed\n");
>   }
> else
>   {
>     ret = ftl_initialize(0, mtd);
>     if (ret < 0)
>      {
>        syslog(LOG_ERR, "ERROR: ftl_initialize() failed: %d\n", ret);
>      }
>    }
> #endif /* CONFIG_MTD_PROGMEM */
> #ifdef CONFIG_FS_LITTLEFS
> ret = nx_mount("/dev/mtdblock0", "/mnt/progmem", "littlefs", 0,
> "autoformat");
> if (ret < 0)
>   {
>     syslog(LOG_ERR, "ERROR: Failed to mount littlefs at /mnt/progmem:
> %d\n", ret);
>   }
> #endif
> ```
> (I'm omitting the internals, but I've implemented the "progmem" layer for
> the STM32G0 with the required "up_" functions).
>
> So far the code runs correctly until the "nx_mount" call is reached. It
> fails with "ret = -28", which stands for "ENOSPC". I've been digging around
> some forums and it seems the LFS configuration may be wrong. For instance:
>
> ```
> fs->cfg.context = fs;
> fs->cfg.read = littlefs_read_block;
> fs->cfg.prog = littlefs_write_block;
> fs->cfg.erase = littlefs_erase_block;
> fs->cfg.sync = littlefs_sync_block;
> fs->cfg.read_size = fs->geo.blocksize *
>                     CONFIG_FS_LITTLEFS_READ_SIZE_FACTOR;
> fs->cfg.prog_size = fs->geo.blocksize *
>                     CONFIG_FS_LITTLEFS_PROGRAM_SIZE_FACTOR;
> fs->cfg.block_size = fs->geo.erasesize *
>                      CONFIG_FS_LITTLEFS_BLOCK_SIZE_FACTOR;
> fs->cfg.block_count = fs->geo.neraseblocks /
>                       CONFIG_FS_LITTLEFS_BLOCK_SIZE_FACTOR;
> fs->cfg.block_cycles = CONFIG_FS_LITTLEFS_BLOCK_CYCLE;
> fs->cfg.cache_size = fs->geo.blocksize *
>                      CONFIG_FS_LITTLEFS_CACHE_SIZE_FACTOR;
> ```
>
> The geometry is directly obtained from the underlying FTL MTD device. For
> this particular case, I'm reserving 4KB at the end of the flash to be used
> as user memory with a fixed page size of 2KB and 2 pages.
>
> - up_progmem_neraseblocks -> 2
> - up_progmem_isuniform -> true
> - up_progmem_pagesize(n) -> 2048
> - up_progmem_erasesize(n) -> 2048
>
> I've tried changing the different LFS configurations, so now I have:
>
> - CONFIG_FS_LITTLEFS_READ_SIZE_FACTOR=1
> - CONFIG_FS_LITTLEFS_PROGRAM_SIZE_FACTOR=1
> - CONFIG_FS_LITTLEFS_BLOCK_SIZE_FACTOR=1
> - CONFIG_FS_LITTLEFS_BLOCK_CYCLE=200 (default)
> - CONFIG_FS_LITTLEFS_CACHE_SIZE_FACTOR=1
> - CONFIG_FS_LITTLEFS_LOOKAHEAD_SIZE=0
> - CONFIG_FS_LITTLEFS_ATTR_MAX=1022 (default)
>
> Is there anything I need to tweak or adjust for LFS to work? So far I've
> been unable to make it, it fails on the mount stage.
>
> Thanks in advance,
>
> Javier Alonso (he, him, his)
> Geotab
>
> Team Lead - Embedded Systems | GEUR
>