MSP430上LittleFS适配FRAM内存遇超级块不可写问题
在MSP430微控制器的外部FRAM内存上适配LittleFS时,格式化阶段出现超级块不可写错误(错误码-28,提示无可用空间)。单独测试FRAM读写操作正常,但LittleFS初始化失败。
已实现的块接口代码如下:
lfs_t lfs; lfs_file_t file; #pragma PERSISTENT(read_cache) static uint8_t read_cache[512] = {0}; #pragma PERSISTENT(write_cache) static uint8_t write_cache[512] = {0}; #pragma PERSISTENT(lookahead_buffer) static uint8_t lookahead_buffer[64] = {0}; const struct lfs_config cfg = { // block device operations .read = block_device_read, .prog = block_device_write, .erase = block_device_erase, .sync = block_device_sync, // block device configuration .read_size = 512, .prog_size = 512, .block_size = 512, .block_count = 6144, .cache_size = 512, .lookahead_size = 64, .block_cycles = -1, // buffers .read_buffer = read_cache, .prog_buffer = write_cache, .lookahead_buffer = lookahead_buffer, }; // Erase function (Not needed for FRAM, just return 0) int block_device_erase(const struct lfs_config *c, lfs_block_t block) { return 0; } // Sync function (Not needed for FRAM, just return 0) int block_device_sync(const struct lfs_config *c) { return 0; } int block_device_read(const struct lfs_config *c, lfs_block_t block, lfs_off_t off, uint8_t *buffer, lfs_size_t size) { // Convert LittleFS block and offset to FRAM address uint32_t addr = (block * BLOCK_SIZE) + off; // Read data from FRAM if (!mem_get_size()) { debug_printf("Memory size equal 0"); return LFS_ERR_IO; // Check if FRAM is available } int result = mem_read(addr, buffer, size); if(result == 0) { return 0; } else { return LFS_ERR_IO; } } int block_device_write(const struct lfs_config *c, lfs_block_t block, lfs_off_t off, const uint8_t *buffer, lfs_size_t size) { // Convert LittleFS block and offset to FRAM address uint32_t addr = (block * BLOCK_SIZE) + off; // Write data to FRAM if (!mem_get_size()) { debug_printf("Memory size equal 0"); return LFS_ERR_IO; // Check if FRAM is available } int result = mem_write(addr, buffer, size); if(result == 0) { return 0; } else { return LFS_ERR_IO; } }
补充测试信息:
- FRAM读写驱动验证正常:用LittleFS的CRC功能测试随机数据写入/读取,CRC一致,无数据错误。
- 错误定位:LittleFS初始化时触发
superblock 0xx has become unwritable警告,最终在CRC校验代码处返回LFS_ERR_CORRUPT:
// make sure to check crc in case we happen to pick // up an unrelated crc (frozen block?) err = lfs_bd_crc(lfs, NULL, &lfs->rcache, sizeof(uint32_t), commit->block, off1, sizeof(uint32_t), &crc); if (err) { return err; } if (crc != 0) { return LFS_ERR_CORRUPT; }
需求:无需修改LittleFS库的前提下,解决FRAM适配问题,明确问题原因和修复方向。
1. 修正擦除函数的实现逻辑
LittleFS的擦除函数并非仅用于Flash物理擦除,它还负责标记块为可写入状态。FRAM无需物理擦除,但需要让LittleFS认为块已被"擦除"(即块内数据为全0,符合LittleFS对擦除块的预期)。
当前直接返回0的方式会导致LittleFS无法确认块是否可用,修改建议:
int block_device_erase(const struct lfs_config *c, lfs_block_t block) { // FRAM无需物理擦除,但需将块填充为全0以符合LittleFS擦除状态定义 uint32_t addr = block * c->block_size; // 若块大小过大,可改为静态数组或分批次写入避免栈溢出 uint8_t zero_buf[512]; memset(zero_buf, 0, sizeof(zero_buf)); if (!mem_get_size()) { debug_printf("Memory size equal 0"); return LFS_ERR_IO; } int result = mem_write(addr, zero_buf, c->block_size); return result == 0 ? 0 : LFS_ERR_IO; }
2. 统一地址计算中的块大小定义
代码中block * BLOCK_SIZE的BLOCK_SIZE必须与LittleFS配置的.block_size = 512完全一致,否则会出现地址计算错位,进而引发CRC校验失败。建议直接使用配置结构体中的值替代硬编码:
uint32_t addr = (block * c->block_size) + off;
3. 调整block_cycles参数
虽然FRAM没有Flash的擦写寿命限制,但block_cycles = -1会让LittleFS进入"无限寿命"模式,部分逻辑会发生变化。可先尝试将其设置为较大固定值(如100000),验证是否解决CRC校验问题:
.block_cycles = 100000,
4. 清除FRAM残留数据
若FRAM之前存储过其他数据,残留内容可能干扰超级块的创建。建议在初始化LittleFS前,手动擦除整个FRAM区域(全0填充),确保初始环境干净。
5. 验证FRAM容量匹配
配置的.block_count = 6144对应总容量为6144 * 512 = 3MB,需确认外部FRAM的实际容量大于等于该值,避免写入越界引发不可预期错误。
内容的提问来源于stack exchange,提问作者Kuba Jjj

