根据您的描述,问题发生在使用 EasyFlash 保存多条日志到 W25Q16JV 芯片时写入成功但读取失败。以下是可能的原因及解决方案:
日志存储区尺寸配置不足
EF_LOG_AREA_SIZE 配置过小,无法容纳多条日志时,会发生写入溢出Flash 物理扇区不匹配
多日志读取逻辑错误
SPI Flash 驱动层问题
/* ef_cfg.h */
#define EF_START_ADDR 0 // 实际起始地址根据分区确定
#define EF_LOG_AREA_SIZE (8 * 4096) // 至少分配8个扇区(32KB)
// 关键配置
#define EF_LOG_BUF_SIZE 256 // 单条日志缓冲区
#define EF_ERASE_MIN_SIZE 4096 // 必须=W25Q16JV扇区大小(4KB)// 确认驱动层实现了正确的跨扇区读取
uint32_t w25qxx_read(uint32_t addr, uint32_t *buf, uint32_t size) {
uint32_t remain = size;
while(remain > 0) {
uint32_t sec_addr = addr & 0xFFFFF000; // 对齐到4K边界
uint32_t offset = addr - sec_addr;
uint32_t read_len = MIN(4096 - offset, remain);
// 调用具体SPI读取函数(需处理跨扇区)
spi_flash_read(sec_addr + offset, buf, read_len);
buf += read_len;
addr += read_len;
remain -= read_len;
}
return EF_NO_ERR;
}void read_all_logs(void) {
static uint32_t saved_log_len = 0;
ef_log_read_history(saved_log_len, print_log, true, 0);
saved_log_len = ef_log_get_used_size(); // 更新已读位置
}
// EasyFlash日志回调函数
static bool print_log(const char *log, size_t len) {
// 确保接收缓冲区足够大
char buf[EF_LOG_BUF_SIZE + 1] = {0};
len = MIN(len, EF_LOG_BUF_SIZE);
memcpy(buf, log, len);
rt_kprintf("[LOG] %sn", buf);
return false; // 返回true停止遍历
}// 初始化必须按顺序执行
void log_system_init(void) {
/* 先初始化Flash设备 */
spi_flash_init();
/* 再初始化EasyFlash */
ef_init();
/* 检查日志系统状态 */
if(ef_log_get_used_size() == 0) {
rt_kprintf("Log system init OK. Storage free: %dn",
ef_log_get_free_size());
}
}| 现象 | 检查点 | 解决方法 |
|---|---|---|
| 仅第一条可读 | EF_LOG_AREA_SIZE 是否太小 | 扩大至至少32KB |
| 随机读取失败 | SPI时序配置稳定性 | 降低SPI时钟速率至20MHz以下 |
| 重启后日志丢失 | Flash驱动写入后未同步 | 添加w25q_wait_busy()检查 |
| 日志中出现乱码 | 缓冲区溢出 | 检查EF_LOG_BUF_SIZE大小 |
| HardFault错误 | 堆栈溢出 | 增大RT-Thread线程栈大小 |
增加擦写均衡机制:
// ef_cfg.h 启用损耗均衡
#define EF_USING_WEAR_LEVELING
#define EF_WL_GC_TIME 5 // 每5次写入触发GC添加掉电保护:
// 每次写入后执行同步
ef_log_flush();
spi_flash_write_sync(); // 等待Flash内部操作完成使用日志分块存储:
/* 在ef_port.c中重写分区策略 */
const ef_partition_t log_part = {
.start_addr = 0x1000,
.end_addr = 0x1000 + 64*1024, // 64KB分区
.type = LOG_PARTITION,
};
ef_partition_register(&log_part);
特别注意:W25Q16JV 的页写入限制为 256 字节/次,确保驱动中单次写入不超过此限制。典型错误是连续写入多条日志时超过页边界未分开写入。
在 ef_env.c 中添加调试输出:
void ef_log_write(const char *log, size_t len) {
rt_kprintf("[EF] Writing log @ %08X, size=%dn",
current_write_addr, len);
... // 原始函数
}使用逻辑分析仪捕获SPI波形,确认:
通过以上方法,95%以上的日志读写问题都可解决。重点检查Flash分区配置和SPI驱动稳定性,这两点是GD32平台最常见的问题根源。
举报
更多回帖