cancel
Showing results for 
Search instead for 
Did you mean: 

littleFS using STM32L4 HAL and EMMC chip

kikib
Associate II

Hey!

I'm stumbling around with integrating littleFS using STM32 HAL library and EMMC 4GB chip, and any help would be greatly appreciated.

I modified FATFS EMMC example so that it uses littleFS. I changed nothing in the SDMMC driver, so since it worked with original example I'm expecting it should also work with littleFS.

I'm using STM32L4P5G-DK development kit with EMMC chip: Block size is 512 bytes and number of blocks is 7634944.

The issue here is that I cannot for the life of me get it to work reliably. When I somehow (by tweaking parameters) get it to work and I change one parameter, it fails to format and then even if I reverse the changes the same issue persist.

I would really appreciate if somebody could help me by checking the configuration and functions.

 

Thank you so much!

 

 

int read(const struct lfs_config *c, lfs_block_t block,
            lfs_off_t off, void *buffer, lfs_size_t size)
{
    DWORD start_sector = (block * c->block_size) + off; // start address

    if (MMC_read(0, (uint8_t*)buffer, start_sector, size) != RES_OK) {
        // Handle read error
        return LFS_ERR_IO;
    }

    return LFS_ERR_OK;
}

int prog(const struct lfs_config *c, lfs_block_t block,
        lfs_off_t off, const void *buffer, lfs_size_t size)
{
    // Calculate the start sector based on block and offset
    DWORD start_sector = (block * c->block_size) + off;

    if (MMC_write(0, buffer, start_sector, size) != RES_OK) {
		// Handle write error
		return LFS_ERR_IO;
    }
    return LFS_ERR_OK;}

int erase(const struct lfs_config *c, lfs_block_t block)
{
    // Calculate the start sector address based on block
    DWORD start_sector = block * c->block_size;

    // Calculate the end sector address based on block size
    DWORD end_sector = (block + 1) * c->block_size) - 1;

    // Erase the specified memory area on the MMC card
    if (BSP_MMC_Erase(start_sector, end_sector) != MMC_OK) {
        // Handle erase error
        return LFS_ERR_IO;
    }
    return LFS_ERR_OK;
} 

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

    // block device configuration
    .read_size = 512,
    .prog_size = 512,
    .block_size = 512,
    .block_count = 7634944,
    .cache_size = 512,
    .lookahead_size = 512,
    .block_cycles = 100,
};

 

One weird things is that from time to time, lfs.c library had an assert when it said that detected block count (127249) is different from configured one (7634944). And then it was never asserted again.

Also in the littlefs source files, if block_count is set to zero LFS will automatically set it to detected size. (as per comments in the code), and setting it to zero worked for some time, and suddenly it started generating assertions that block_count cannot be 0.

 

Below is beginning of main code that handles initialization and mounting.

 

    DSTATUS status = MMC_initialize(0);
    if(status != RES_OK) {
    	printf("Error MMC_initialize %d\n", status);
    	while(1);
    }
    
    BSP_MMC_CardInfo CardInfo = {9};
    status = BSP_MMC_GetCardInfo(&CardInfo);
    if(status != RES_OK) {
    	printf("Error BSP_MMC_GetCardInfo %d\n", status);
    	while(1);
    }
    
    printf("Card Initialized\n");
    printf("block size: %d, %d\n", CardInfo.LogBlockSize, CardInfo.LogBlockNbr);

    // mount the filesystem
    int err = lfs_mount(&lfs, &cfg);

    // reformat if we can't mount the filesystem
    // this should only happen on the first boot
    if (err || FORCE_FORMAT) {
    	printf("Formating filesystem..\n");
    	err = lfs_format(&lfs, &cfg);
    	if(err < 0) {
    		printf("Error lfs_format %d\n", err);
    		while(1);
    	}
    	err = lfs_mount(&lfs, &cfg);
    	if(err < 0) {
    		printf("Error lfs_mount %d\n", err);
    		while(1);
    	}
    }

 

Whenever I run the program I get this:

 

Card Initialized
block size: 512, 7634944
D:/Projects/stm32/STM32CubeL4/Projects/32L4P5GDISCOVERY/Applications/FatFs/FatFs_eMMC_Standalone/third_party/littlefs/lfs.c:1346:error: Corrupted dir pair at {0x0, 0x1}
Formating filesystem..
Error lfs_format -5

 

 

Thank you!

4 REPLIES 4

Step one validate the read functionality for the eMMC blocks thoroughly.

Step two validate write functionality, that a) it works, and b) you can read the SAME data back you wrote.

Step three integrate the working block storage layer with a file system.

eMMC typically has two CSD capacity reporting modes, the more usual one provides some arbitrary capacity, and you need the EXTCSD to get the actual capacity.

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..

Hello. Thank you for taking the time to answer.

I completed first two steps successfully and now I'm working on step three.

While I can read and write to a file, I worry that I don't have correct configuration, because my timings for 32kb byte array are: 

 

 

450579 us to write 32768 bytes
513808 us to read 32768 bytes

 

Which does not look too good.

My current parameters are:

 

    .read_size = 512,
    .prog_size = 512,
    .block_size = 512,
    .block_count = 7634944, number of blocks, read from MMC chip
    .cache_size = 512,
    .lookahead_size = 512,
    .block_cycles = 100,

 

 Does any of these parameters stand out?

Also, I'm wondering, is erase functionality required? I tried removing it and everything still works fine.

 

Hi, have you resolved the issue? I am facing the same issue, the same exact error code (-5). My setup is SDIO 4 bit wide with a micro SD card (size 32GB). SDIO and eMMC should have similar handling and my code looks almost like yours. Any luck in solving this problem?

Yeah I managed to get it to work, but with speeds that are way below optimal. Few things I learned:
1) Erase LFS callback should be empty (only return OK). Sync should also be implemented but only return OK.

					lfsConfig.read_size = 512;
					lfsConfig.prog_size = 512;
					lfsConfig.block_size = 512;
					lfsConfig.block_count = 62160896;
					lfsConfig.block_cycles = -1; // -1 means wear-leveling disabled
					lfsConfig.cache_size = 512;
					lfsConfig.lookahead_size = 32;
				static int Lfs_ReadBlock(const struct lfs_config* c, lfs_block_t block, lfs_off_t off, void* buffer, lfs_size_t size)
				{

					int err = HAL_MMC_ReadBlocks(&hmmc, (uint8_t*)buffer, block, 1, HAL_MAX_DELAY);
					if (err != HAL_OK) {
						// Handle read error
						return LFS_ERR_IO;
					}

					while (HAL_MMC_GetCardState(&hmmc) != HAL_MMC_CARD_TRANSFER) {

					}

					return LFS_ERR_OK;
				}
				static int Lfs_ProgBlock(const struct lfs_config* c, lfs_block_t block, lfs_off_t off, const void* buffer, lfs_size_t size)
				{
					int err =  HAL_MMC_WriteBlocks(&hmmc, (uint8_t*)buffer, (uint32_t)block, 1, HAL_MAX_DELAY);
					if (err != HAL_OK) {
						// Handle write error
						return LFS_ERR_IO;
					}

					while (HAL_MMC_GetCardState(&hmmc) != HAL_MMC_CARD_TRANSFER) {

					}

					return LFS_ERR_OK;
				}
				static int Lfs_EraseBlock(const struct lfs_config* c, lfs_block_t block)
				{
					return LFS_ERR_OK;
				}
				static int Lfs_SyncBlock(const struct lfs_config* c)
				{
					return LFS_ERR_OK;
				}

2) Polling mode only works with 1bit width. Meaning I could not get it to work with higher width. (Or maybe I just used wrong combination of settings, idk)

hmmc.Instance = SDMMC1;
hmmc.Init.ClockEdge = SDMMC_CLOCK_EDGE_RISING;
hmmc.Init.ClockPowerSave = SDMMC_CLOCK_POWER_SAVE_DISABLE;
hmmc.Init.BusWide = SDMMC_BUS_WIDE_1B;
hmmc.Init.HardwareFlowControl = SDMMC_HARDWARE_FLOW_CONTROL_ENABLE;
hmmc.Init.ClockDiv = 0;
hmmc.Init.Transceiver = SDMMC_TRANSCEIVER_DISABLE;

This causes lower speeds, however I found it the most stable.

3) There is a bug in DMA mode which causes driver to hang (I don't remember the details anymore).