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

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=无效密钥)

相关文章:

  • 通过Typora + PicGo + 阿里云对象存储(OSS)实现图床
  • Numpy
  • 【vulhub/wordpress靶场】------获取webshell
  • 为什么 API 接口漏洞越来越多?与现代网站开发环境的关系
  • [Deepseek 学c++]初始化捕获与按值(显式与隐式)捕获傻傻分不清
  • 2025年云南食品安全员管理员考试题库
  • 代码随想录_动态规划
  • webpack等构建工具如何支持移除未使用的代码
  • 力扣hot100——三数之和(双指针)
  • 每天五分钟玩转深度学习PyTorch:基于pytorch搭建LSTM和GRU模型
  • 深度优先搜索(DFS)与广度优先搜索(BFS)全面解析 + 经典算法题实战(Java实现)
  • leetcode106 从中序与后序遍历序列构造二叉树
  • Java学习笔记-XXH3哈希算法
  • Dify 项目开源大模型应用开发平台
  • deque
  • Linux基础开发工具--gdb的使用
  • 蓝桥杯青少组stema2025年3月9日scratch初级组真题——转动的图形
  • 除自身以外数组的乘积——面试经典150题(力扣)
  • 每天一道算法题-两数相加
  • C++编程语言特性
  • 苏州1-4月进出口总值增长6.8%,工业机器人出口额倍增
  • 特朗普与普京通话前夕,英美法德意领导人通话讨论俄乌问题
  • 浙江广厦:诚挚道歉,涉事责任人交公安机关
  • 2025吉林市马拉松开跑,用赛道绘制“博物馆之城”动感地图
  • 竞彩湃|英超欧冠悬念持续,纽卡斯尔诺丁汉能否拿分?
  • 上海天文馆走进徐家汇书院,XR沉浸式天文科普体验再推力作