单片机/MCU论坛
直播中

张莹

8年用户 1108经验值
私信 关注
[问答]

请问如何创建在 RAM 区域完全独立运行的闪存驱动程序代码?

我在开发闪存驱动程序代码时遇到了一个问题。我将准备好的HEX文件写入指定的RAM区域,并尝试使用指针调用,但调用失败,无法正常擦除或写入。对于flash的操作代码已经通过了单独的测试,为了使其更加独立,我已经尽可能的避免调用位于FLASH上的API,但似乎还是不行。我想问一下我应该如何制作flash驱动程序?有没有任何可用的演示参考?下面是我的闪存驱动程序代码的一部分。

uint16 结束初始化安全密码;
Ifx_SCU_WDTS *看门狗 = &MODULE_SCU.WDTS;
endInitSafetyPassword = 看门狗->CON0.B.PW;
endInitSafetyPassword ^= 0x003F;

如果(SCU_WDTS_CON0.B.LCK)
{
/* see Table 1 (Password Access Bit Pattern Requirements) */
SCU_WDTS_CON0.U = (1 << 0u) |
(0 << 1u) |
(endInitSafetyPassword << 2u) |
(SCU_WDTS_CON0.B.REL << 16u);
}
/* 清除 ENDINT 并设置 Config_0 寄存器中的 LCK 位 */
SCU_WDTS_CON0.U = (0 << 0u) |
(1 << 1u)|
(endInitSafetyPassword << 2u) | (endInitSafetyPassword << 2u) |
(SCU_WDTS_CON0.B.REL<<16u);
/* 读回 ENDINIT 并等待直到它被清除 */
而(SCU_WDTS_CON0.B.ENDINIT == 1)
{}


                                                                                                                                                                                                                                                                                                                                                                                                      

回帖(1)

从未拥有

2025-7-30 18:01:45

在RAM区域创建完全独立运行的闪存驱动程序需要确保代码在RAM中执行时,不依赖任何FLASH中的函数或数据。以下是关键步骤和解决方案:


关键步骤:




  1. 代码位置无关性 (PIC):

    使用-fPIC编译选项确保代码在RAM中任意地址均可运行。




  2. 独立链接脚本:

    创建专用链接脚本,将驱动程序代码和数据完全定位到RAM区域,避免与FLASH关联。




  3. 初始化代码复制:

    在main()初始化阶段,将编译后的驱动代码从FLASH复制到目标RAM区域。




  4. 函数指针调用:

    通过函数指针调用RAM中的函数,确保程序计数器跳转到RAM执行。




  5. 中断处理:

    操作FLASH前禁用中断,防止中断处理程序调用FLASH中的代码。






解决方案示例(基于TriCore架构):


1. 链接脚本 (ram_driver.ld)


MEMORY {
  RAM (rwx) : ORIGIN = 0xD0000000, LENGTH = 32K  /* RAM区域地址 */
}

SECTIONS {
  .ram_code : {
    *(.ram_text)       /* 代码段 */
    *(.ram_rodata)     /* 只读数据 */
    *(.ram_data)       /* 初始化数据 */
  } > RAM

  .bss (NOLOAD) : {
    *(.ram_bss)        /* 未初始化数据 */
  } > RAM
}

2. 驱动程序代码 (flash_driver.c)


#include 
#include "IfxScu_reg.h"

// 强制使用位置无关代码
__attribute__((section(".ram_text"), used, noinline, naked, optimize("O0")))
void ram_flash_erase_sector(uint32_t sector_addr) {
    uint16_t endInitSafetyPassword;
    Ifx_SCU_WDTS *watchdog = &MODULE_SCU.WDTS;

    // 1. 停止看门狗
    endInitSafetyPassword = watchdog->CON0.B.PW;
    endInitSafetyPassword ^= 0x003F; // 解锁安全寄存器
    __disable(); // 禁用全局中断

    // 2. FLASH擦除序列(伪代码)
    uint32_t *flash_cmd = (uint32_t*)0xF0000000;
    flash_cmd[0] = 0xAAAAAAAA; // 解锁序列1
    flash_cmd[1] = 0x55555555; // 解锁序列2
    flash_cmd[2] = 0x80;
    flash_cmd[3] = 0xAAAAAAAA;
    flash_cmd[4] = 0x55555555;
    flash_cmd[5] = sector_addr; // 目标扇区地址

    // 3. 等待操作完成
    while (flash_cmd[6] & 0x80); // 检查状态位

    // 4. 恢复看门狗
    watchdog->CON0.B.PW = endInitSafetyPassword;
    __enable(); // 启用全局中断
}

3. 主程序初始化


extern uint8_t _ram_driver_start; // 链接脚本定义的符号
extern uint8_t _ram_driver_end;

void init_ram_driver() {
    // 复制驱动代码到RAM
    uint8_t *flash_src = (uint8_t*)0x80000000; // FLASH中的驱动代码起始地址
    uint8_t *ram_dest = &_ram_driver_start;
    uint32_t size = &_ram_driver_end - &_ram_driver_start;

    for (uint32_t i = 0; i < size; i++) {
        ram_dest[i] = flash_src[i];
    }

    // 可选:缓存一致性操作(如Cache无效化)
}

int main() {
    init_ram_driver();

    // 函数指针调用RAM中的驱动
    void (*erase_func)(uint32_t) = (void(*)(uint32_t))&_ram_driver_start;
    erase_func(0xF0001000); // 擦除目标扇区

    while (1);
}

4. 编译选项


CFLAGS += -fPIC -O1 -nostdlib -ffreestanding
LDFLAGS += -T ram_driver.ld -Wl,--gc-sections



常见问题解决:




  • 调用失败:

    确保函数指针指向复制后的RAM地址&_ram_driver_start而非原始FLASH地址)。




  • 寄存器访问错误:

    使用volatile修饰硬件寄存器指针,例如:  


    volatile Ifx_SCU_WDTS *watchdog = &MODULE_SCU.WDTS;



  • 时序问题:

    在关键操作序列间插入__nop()延迟,满足FLASH控制器时序要求。






参考示例:



  1. Infineon iLLD库:查看 IfxFlash.cIfxFlash_eraseSector()的实现,重点关注其__ram函数属性。  

  2. TI Stellaris LM4F:参考driverlib/rom_map.h中的内存映射驱动设计。  

  3. STM32 HAL库:研究__attribute__((section(".ramfunc")))的使用。



建议:  



  1. 使用JTAG调试器单步跟踪RAM函数,确认指令执行路径。  

  2. 检查芯片手册的FLASH编程时序,确保命令序列完全正确。  

  3. 在操作前关闭数据缓存(DCache),防止访问冲突。



通过以上方法,可使闪存驱动程序完全独立运行于RAM区域,避免擦除/写入过程中的代码执行冲突。

举报

更多回帖

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