You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

TriCore微控制器:CBL代码从Flash重定位至SRAM运行及自更新方案咨询

问题解答

你的理解是否正确?

完全正确。绝大多数微控制器的Flash存储单元在被CPU读取执行代码时,无法同时进行擦除或编程操作——这是Flash硬件的固有特性:要么当前存储块被用于指令读取,要么被用于擦写操作,二者无法并行;部分MCU甚至会直接锁定当前执行的Flash块,禁止任何修改操作。

解决方案

1. 将Flash擦写核心逻辑重定位到SRAM运行

这是最直接的解决方式,把需要操作Flash的代码移到SRAM中执行,避免占用当前运行的Flash块:

  • 修改链接脚本:新增一个代码段,指定其加载地址在Flash,但运行地址在SRAM。示例GCC链接脚本片段:
MEMORY
{
  FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 64K  /* CBL所在Flash区域 */
  SRAM (rwx) : ORIGIN = 0x20000000, LENGTH = 16K   /* MCU的SRAM区域 */
}

SECTIONS
{
  /* 定义SRAM执行的代码段 */
  .sram_code :
  {
    . = ALIGN(4);
    __sram_code_start = .;
    *(.sram_code)  /* 匹配所有标记为.sram_code的函数 */
    __sram_code_end = .;
  } >SRAM AT>FLASH  /* 加载在Flash,运行在SRAM */
}
  • 标记需要重定位的函数:给Flash擦写相关函数添加段属性,让编译器把它们放到.sram_code段:
// GCC编译器属性,指定函数放到.sram_code段
__attribute__((section(".sram_code"))) void cbl_self_update_flash(uint32_t new_cbl_addr, uint32_t new_cbl_len)
{
  // 解锁Flash
  HAL_FLASH_Unlock();
  
  // 擦除原CBL所在的Flash块
  FLASH_EraseInitTypeDef erase_init = {0};
  uint32_t page_error = 0;
  erase_init.TypeErase = FLASH_TYPEERASE_PAGES;
  erase_init.PageAddress = 0x08000000;  // 原CBL起始地址
  erase_init.NbPages = (new_cbl_len + FLASH_PAGE_SIZE - 1) / FLASH_PAGE_SIZE;
  HAL_FLASHEx_Erase(&erase_init, &page_error);
  
  // 写入新的CBL镜像
  uint8_t *new_cbl_data = (uint8_t*)new_cbl_addr;
  for(uint32_t i=0; i<new_cbl_len; i+=4)
  {
    uint32_t word_data = *(uint32_t*)(new_cbl_data + i);
    HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, 0x08000000 + i, word_data);
  }
  
  // 锁定Flash
  HAL_FLASH_Lock();
}
  • 启动时复制代码到SRAM:如果链接脚本没有自动处理,需要在CBL初始化阶段(还未操作Flash前),手动把Flash中的.sram_code段复制到SRAM:
// 从链接脚本中导入的符号
extern uint32_t __sram_code_start;
extern uint32_t __sram_code_end;
extern uint32_t LOADADDR(.sram_code);

void copy_sram_code(void)
{
  uint8_t *src = (uint8_t*)&LOADADDR(.sram_code);  // Flash中的起始地址
  uint8_t *dest = (uint8_t*)&__sram_code_start;     // SRAM中的运行地址
  uint32_t len = (uint32_t)&__sram_code_end - (uint32_t)&__sram_code_start;
  
  // 逐字节复制
  while(len--)
  {
    *dest++ = *src++;
  }
}

// 在CBL的main函数开头调用
int main(void)
{
  copy_sram_code();  // 先把SRAM代码复制好
  // ... 其他初始化操作 ...
  
  // 需要更新CBL时,调用cbl_self_update_flash()
}

2. 借助应用程序完成CBL更新

利用你已有的跳转逻辑,让应用程序承担CBL的擦写工作:

  • 流程:
    1. CBL收到自身更新指令后,先将新的CBL镜像写入Flash的临时区域(比如应用程序的空闲块,或者专门预留的更新缓冲区)。
    2. CBL修改跳转标记,然后跳转到应用程序。
    3. 应用程序启动时检测到CBL更新标记,执行擦除原CBL区域、写入新CBL镜像的操作。
    4. 应用程序完成后,跳转回新的CBL。
  • 优势:不需要修改CBL的内存布局,复用现有跳转逻辑,实现成本低。

3. 双Bank Flash硬件方案(如果MCU支持)

若你的MCU支持双Bank Flash(如STM32H7、STM32L4系列),可以采用双Bank交替运行的方式:

  • 初始时CBL运行在Bank1,更新时将新CBL写入Bank2。
  • 修改MCU的启动配置(比如通过Boot引脚设置,或者修改向量表偏移),让下一次启动从Bank2运行。
  • 新CBL启动后,可选择擦除Bank1并同步镜像(保持双Bank一致性)。
  • 注意:需要MCU硬件支持双Bank,且需适配启动流程和向量表配置。

内容的提问来源于stack exchange,提问作者Tony

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 07:34:55