RT-Thread论坛
直播中

安立路

9年用户 886经验值
私信 关注
[问答]

通用bootloader无法使用45db161flash怎么解决?

通用bootloader不选“支持spi flash”,download放于片内flash,正常启动,ota正常,app驱动at45db161读写正常。通用bootloader选“支持spi flash”,spi引脚设定无误,无论设定download为片内还是片外flash(app内分区表按通用bootloader设定地址做响应修改),启动都找不到at45db161,经长时间后,显示如下提示

  •     [SFUD]Error: Flash wait busy has an error.
  •     [SFUD]Error: Flash wait busy has an error.
  •     [SFUD]Error: Flash device reset failed.
  •     [SFUD]Error: spi flash device is initialize fail.


接着进入app正常启动,加载at45db161驱动正常读写。请问有没有关于通用bootloader的详细说明?启动时bootloader是如何加载外部flash驱动的?是否不调用app内的驱动函数?谢谢!


回帖(1)

李燕

2025-9-23 17:00:59

针对通用Bootloader启用"支持SPI Flash"后无法识别AT45DB161的问题,结合错误信息(Flash wait busyFlash device reset failed),以下是系统性的解决方案:




根本原因分析



  1. SFUD驱动不兼容

    AT45DB161是Adesto(原Atmel)的DataFlash,采用非标准SPI指令集(与常见SPI NOR Flash如W25Q系列不同)。SFUD默认支持标准JEDEC SPI Flash,需特殊适配AT45DB161。

  2. 初始化时序差异

    AT45DB161上电后需要更长复位时间(典型值10ms)或特定复位序列,Bootloader未正确处理。

  3. SPI配置冲突

    Bootloader与App的SPI模式、速率、CS引脚控制逻辑可能存在差异。




解决方案


1. 适配SFUD驱动以支持AT45DB161


AT45DB161需要自定义SFUD驱动层:


// 在bootloader项目中添加`sfud_at45db161.c`
#include "sfud.h"
#include "spi_flash_sfud_cfg.h"

// 自定义AT45DB161复位指令(示例)
static void at45db161_reset(sfud_flash *flash) {
    uint8_t cmd = 0xF0; // AT45DB161复位命令(查阅手册确认)
    sfud_spi_port *spi = &flash->spi;
    spi->wr(spi, &cmd, 1); // 发送复位命令
    sfud_udelay(10000);    // 等待10ms复位完成
}

// 自定义等待忙状态函数
static sfud_err at45db161_wait_busy(sfud_flash *flash) {
    uint8_t status;
    do {
        uint8_t cmd = 0xD7; // AT45DB161状态寄存器指令
        sfud_spi_port *spi = &flash->spi;
        spi->wr(spi, &cmd, 1);
        spi->read(spi, &status, 1);
    } while (status & 0x80); // 最高位为Busy标志
    return SFUD_SUCCESS;
}

// 注册AT45DB161到SFUD
sfud_err sfud_at45db161_init(sfud_flash *flash) {
    flash->reset = at45db161_reset;
    flash->wait_busy = at45db161_wait_busy;
    // 添加其他必要操作(擦除/写/读等)
    return SFUD_SUCCESS;
}

在初始化代码中调用:


// bootloader初始化SPI Flash时
if (detected_flash_id == AT45DB161_ID) { // 检查器件ID
    sfud_at45db161_init(flash); // 应用自定义驱动
}


关键点:  



  • 查阅AT45DB161手册确认指令集(Page 28-30)。

  • 标准SFUD的resetwait_busy操作不兼容AT45DB161,必须重写。





2. 延长初始化延时


在初始化SPI Flash前增加硬件复位延时:


// 在sfud_init()前调用
void board_spi_flash_init() {
    rt_pin_mode(CS_PIN, PIN_MODE_OUTPUT);  // 确保CS引脚可控
    rt_pin_write(CS_PIN, PIN_HIGH);        // 取消片选
    rt_thread_delay(50); // 延时50ms(AT45DB161上电需30ms+)
    // 再执行SPI和SFUD初始化
}



3. 同步SPI配置


确保Bootloader与App使用相同的SPI配置



  • 检查项

    • SPI模式(AT45DB161通常需Mode 3:CPOL=1, CPHA=1)。

    • 时钟速率(首次初始化建议≤1MHz)。

    • CS引脚是否复用为GPIO且控制逻辑正确(避免硬件冲突)。



在Board层配置中显式指定参数:


// 在board.c中覆写SPI配置
static struct rt_spi_configuration spi_config = {
    .mode = RT_SPI_MODE_3 | RT_SPI_MSB, // Mode 3 + MSB First
    .max_hz = 500000, // 初始速率500kHz
};
rt_spi_configure(spi_bus, &spi_config);



4. 验证硬件连接



  • 使用逻辑分析仪抓取Bootloader启动时的SPI波形:

    • 检查CS、SCK、MOSI信号是否正常。

    • 确认AT45DB161的RESETWP引脚未被错误拉低。


  • 测量VCC电压(确保≥2.7V)。




调试建议



  1. 步骤式验证

    • 先实现最小Bootloader:仅初始化SPI和AT45DB161,打印状态寄存器。

    • 逐步移植App中已验证的驱动代码到Bootloader。


  2. 日志增强

    • sfud_init()中打印SPI返回的JEDEC ID(0x1F表示Adesto)。

    • 捕获初始化失败时的详细错误码:
      if (sfud_init() != RT_EOK) {
      rt_kprintf("[SFUD] Init failed: %dn", result);
      }





通过以上步骤,重点解决SFUD驱动不兼容AT45DB161初始化时序问题,即可使Bootloader正确识别并操作此Flash芯片。

举报

更多回帖

发帖
×
20
完善资料,
赚取积分