当前位置: 首页 > article >正文

ambiq apollo3 Flash实例程序注释

#include "am_mcu_apollo.h"  // Apollo3芯片的硬件抽象层头文件

//! Flash操作函数表(BootROM函数跳转表)
const g_am_hal_flash_t g_am_hal_flash = {
    // 各成员为BootROM中预置的Flash操作函数地址(通过逆向工程或厂商提供)
    ((int (*)(uint32_t, uint32_t))0x0800004d),          // flash_mass_erase: 整片擦除
    ((int (*)(uint32_t, uint32_t, uint32_t))0x08000051),// flash_page_erase: 页擦除
    // ... 其他函数指针(省略具体地址)
};

// SRAM最大有效地址(Apollo3 SRAM大小定义)
const uint32_t ui32SramMaxAddr = (AM_HAL_FLASH_SRAM_LARGEST_VALID_ADDR + 1);

// 工作区函数对齐属性(ARM指令集要求16字节对齐)
#if defined (编译器判断)
// ... 各编译器对齐指令(省略)
#endif

//! 唤醒工作区函数指令集(解决低功耗模式唤醒后的Flash操作问题)
static const uint16_t WakeWorkaround[] WA_ATTRIB = { 
    0x20c3, 0xf244, ... // 16位Thumb指令机器码(实现特定时序或配置)
};

// 工作区函数指针(+1表示Thumb模式)
typedef void (*WakeWAfunc_t)(void);
WakeWAfunc_t WakeWAfunc = (WakeWAfunc_t)((uint8_t*)WakeWorkaround + 1);

//*****************************************************************************
// 整片擦除函数
// @param ui32ProgramKey - 编程密钥(需AM_HAL_FLASH_PROGRAM_KEY)
// @param ui32FlashInst - Flash实例号(0/1)
// @return 状态码(0=成功)
//*****************************************************************************
int am_hal_flash_mass_erase(uint32_t ui32ProgramKey, uint32_t ui32FlashInst) {
    return g_am_hal_flash.flash_mass_erase(ui32ProgramKey, ui32FlashInst); 
}

//*****************************************************************************
// 页擦除函数(带唤醒工作区)
// @param ui32PageNum - 页号(每页8KB)
//*****************************************************************************
int am_hal_flash_page_erase(uint32_t ui32ProgramKey, uint32_t ui32FlashInst,
                            uint32_t ui32PageNum) {
    WakeWAfunc(); // 执行唤醒工作区代码(确保Flash控制器状态)
    return g_am_hal_flash.flash_page_erase(ui32ProgramKey, ui32FlashInst, ui32PageNum);
}

//*****************************************************************************
// 主Flash区编程函数(处理SRAM边界特殊情况)
// @param pui32Src - 源数据地址(SRAM)
// @param pui32Dst - 目标Flash地址(需字对齐)
// @param ui32NumWords - 写入字数(每个字4字节)
//*****************************************************************************
int am_hal_flash_program_main(uint32_t ui32ProgramKey, uint32_t *pui32Src,
                              uint32_t *pui32Dst, uint32_t ui32NumWords) {
    uint32_t ui32MaxSrcAddr = (uint32_t)pui32Src + (ui32NumWords << 2);

    WakeWAfunc(); // 唤醒工作区

    // 处理SRAM末尾地址限制(BootROM无法读取最后一个字)
    if ( ui32MaxSrcAddr == ui32SramMaxAddr ) {
        // 分段写入:前n-1个字正常写入,最后一个字通过临时变量写入
        // ...(具体实现省略)
    }

    return g_am_hal_flash.flash_program_main(...); // 调用BootROM函数
}

//*****************************************************************************
// 位清除函数(Flash位只能从1→0编程一次)
// @param ui32BitMask - 需清除的位掩码(1表示清位)
//*****************************************************************************
int am_hal_flash_clear_bits(uint32_t ui32ProgramKey, uint32_t *pui32Addr,
                            uint32_t ui32BitMask) {
    // 生成新值:仅清除未编程的位(避免重复操作)
    uint32_t ui32Val = ~ui32BitMask | ~(*pui32Addr);
    return g_am_hal_flash.flash_program_main(..., &ui32Val, pui32Addr, 1);
}


#include "am_mcu_apollo.h"   // Apollo3 HAL库
#include "am_bsp.h"          // 板级支持包
#include "am_util.h"         // 通用工具函数

//! 定义在Flash实例1中的任意页地址(绕过实例0)
#define ARB_PAGE_ADDRESS (AM_HAL_FLASH_INSTANCE_SIZE + (2 * AM_HAL_FLASH_PAGE_SIZE))
// AM_HAL_FLASH_INSTANCE_SIZE = 512KB (0x80000)
// AM_HAL_FLASH_PAGE_SIZE = 8KB (0x2000)
// 计算得:0x80000 + 2*0x2000 = 0x84000(实际应为528KB,但注释中的260KB可能有误)

static uint32_t ui32Source[512]; // SRAM中的源数据缓冲区(512字=2KB)

int main(void)
{
    // 初始化部分
    am_hal_clkgen_control(AM_HAL_CLKGEN_CONTROL_SYSCLK_MAX, 0); // 设置最大系统时钟(通常96MHz)
    am_hal_cachectrl_config(&am_hal_cachectrl_defaults);         // 配置缓存控制器
    am_hal_cachectrl_enable();                                   // 启用缓存(加速执行)
    am_bsp_low_power_init();                                     // 低功耗外设初始化
    am_bsp_itm_printf_enable();                                  // 启用ITM调试输出
    am_util_stdio_terminal_clear();                              // 清空终端
    am_util_stdio_printf("Flash Write Example\n");               // 打印标题

    // 目标地址设置(Flash实例1的第2页)
    uint32_t ui32PrgmAddr = ARB_PAGE_ADDRESS; // 实际地址可能需要根据芯片手册确认

    // 阶段1:整片擦除实例1
    am_util_stdio_printf("  ... erasing all of flash instance %d.\n", 
                        AM_HAL_FLASH_ADDR2INST(ui32PrgmAddr));
    int32_t i32ReturnCode = am_hal_flash_mass_erase(AM_HAL_FLASH_PROGRAM_KEY, 1);
    if (i32ReturnCode) // 错误处理(下同)
    {
        am_util_stdio_printf("FLASH_MASS_ERASE error: 0x%x\n", i32ReturnCode);
        i32ErrorFlag++;
    }

    // 阶段2:准备数据并编程
    am_util_stdio_printf("  ... programming flash instance %d, page %d.\n",
                        AM_HAL_FLASH_ADDR2INST(ui32PrgmAddr),
                        AM_HAL_FLASH_ADDR2PAGE(ui32PrgmAddr));
    // 填充测试数据(0x100-0x100+2047,步长4)
    uint32_t *pui32Src = ui32Source;
    for (int ix = 0x100; ix < (0x100 + 512*4); ix +=4)
    {
        *pui32Src++ = ix; // 生成递增模式:0x00000100, 0x00000104,...0x000005FC
    }

    // 调用Flash编程函数(关键步骤)
    uint32_t *pui32Dst = (uint32_t *)ui32PrgmAddr;
    i32ReturnCode = am_hal_flash_program_main(AM_HAL_FLASH_PROGRAM_KEY,
                                             ui32Source, pui32Dst, 512);
    if (i32ReturnCode) // 错误检测
    {
        am_util_stdio_printf("FLASH program error at 0x%08x: 0x%x\n",
                            ui32PrgmAddr, i32ReturnCode);
        i32ErrorFlag++;
    }

    // 阶段3:验证编程结果
    am_util_stdio_printf("  ... verifying the page just programmed.\n");
    for (int ix = 0; ix < 512; ix++)
    {
        uint32_t ui32FlashVal = *(uint32_t*)(ui32PrgmAddr + (ix*4));
        if (ui32FlashVal != ui32Source[ix]) // 逐字校验
        {
            am_util_stdio_printf("ERROR @ 0x%08x: Exp=0x%08x, Act=0x%08x\n",
                                ui32PrgmAddr + (ix*4),
                                ui32Source[ix], ui32FlashVal);
        }
    }

    // 阶段4:位清除操作演示
    pui32Dst = ((uint32_t*)ui32PrgmAddr) + (512 - 1); // 最后一个字
    i32ReturnCode = am_hal_flash_clear_bits(AM_HAL_FLASH_PROGRAM_KEY,
                                           pui32Dst, ~0UL); // 尝试清除所有位
    if (i32ReturnCode)
    {
        am_util_stdio_printf("CLEAR_BITS error @ 0x%08x: 0x%x\n",
                            pui32Dst, i32ReturnCode);
        i32ErrorFlag++;
    }

    // 验证位清除结果(期望值0x00000000)
    am_util_stdio_printf("  ... verifying the word just reprogrammed.\n");
    if (*pui32Dst != 0)
    {
        am_util_stdio_printf("ERROR @ 0x%08x: Exp=0x00000000, Act=0x%08x\n",
                            pui32Dst, *pui32Dst);
    }

    // 阶段5:页擦除与验证
    am_util_stdio_printf("  ... erasing the page just programmed.\n");
    i32ReturnCode = am_hal_flash_page_erase(AM_HAL_FLASH_PROGRAM_KEY,
                                           AM_HAL_FLASH_ADDR2INST(ui32PrgmAddr),
                                           AM_HAL_FLASH_ADDR2PAGE(ui32PrgmAddr));
    if (i32ReturnCode)
    {
        am_util_stdio_printf("PAGE_ERASE error: 0x%x\n", i32ReturnCode);
        i32ErrorFlag++;
    }

    // 验证擦除结果(全FF)
    am_util_stdio_printf("  ... verifying the page just erased.\n");
    for (int ix = 0; ix < 512; ix++)
    {
        uint32_t ui32FlashVal = *(uint32_t*)(ui32PrgmAddr + (ix*4));
        if (ui32FlashVal != 0xFFFFFFFF)
        {
            am_util_stdio_printf("ERASE FAIL @ 0x%08x: 0x%08x\n",
                                ui32PrgmAddr + (ix*4), ui32FlashVal);
        }
    }

    // 结果汇总
    if (i32ErrorFlag)
    {
        am_util_stdio_printf("FAILURE: %d errors\n", i32ErrorFlag);
    }
    else
    {
        am_util_stdio_printf("SUCCESS\n");
    }

    am_hal_itm_not_busy(); // 等待ITM输出完成
    return i32ErrorFlag;    // 返回错误计数(可用于脚本化测试)
}

关键操作解析:

  1. 地址转换宏

    • AM_HAL_FLASH_ADDR2INST():将物理地址转换为Flash实例号(0或1)

    • AM_HAL_FLASH_ADDR2PAGE():计算地址对应的页号(0-63)

  2. Flash编程限制

    • 需先擦除(全FF)才能写入

    • 字编程操作(4字节对齐)

    • am_hal_flash_clear_bits()只能将1→0,不可逆

  3. 唤醒工作区(WakeWA)

    • am_hal_flash_page_erase()内部调用WakeWAfunc()

    • 确保低功耗唤醒后Flash控制器状态正确

  4. 错误处理

    • 每个关键操作后检查返回值

    • 错误码含义参考am_hal_flash.h定义(如0x1=无效密钥)


http://www.kler.cn/a/593678.html

相关文章:

  • Java 实现两个线程交替打印AB的几种方式
  • 从零开始搭建向量数据库:基于 Xinference 和 Milvus 的文本搜索实践
  • 机器学习是怎么一步一步由神经网络发展到今天的Transformer架构的?
  • 2025 使用docker部署ubuntu24容器并且需要ubuntu24容器能通过ssh登录SSH 登录的Ubuntu24容器
  • Modern C++处理 Hooks 机制
  • Datawhale大语言模型-Transformer以及模型详细配置
  • HttpClient通讯时间过久
  • MiniMax GenAI 可观测性分析:基于阿里云 SelectDB 构建 PB 级别日志系统
  • python采集小红书笔记详情API接口,json数据示例分享
  • 理工超市-多用户注册
  • 【C++模板】
  • Linux--进程创建
  • Android 13深度定制:SystemUI状态栏时间居中显示终极实战指南
  • The Illustrated Stable Diffusion
  • 电机控制常见面试问题(十四)
  • pytorch v1.4.0安装问题
  • 2024年国赛高教杯数学建模E题交通流量管控解题全过程文档及程序
  • 嵌入式系统开发如何选择和备考软考高级
  • webpack等构建工具如何支持移除未使用的代码
  • 基于carla的模仿学习(附数据集CORL2017)更新中........