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; // 返回错误计数(可用于脚本化测试)
}
关键操作解析:
-
地址转换宏:
-
AM_HAL_FLASH_ADDR2INST()
:将物理地址转换为Flash实例号(0或1) -
AM_HAL_FLASH_ADDR2PAGE()
:计算地址对应的页号(0-63)
-
-
Flash编程限制:
-
需先擦除(全FF)才能写入
-
字编程操作(4字节对齐)
-
am_hal_flash_clear_bits()
只能将1→0,不可逆
-
-
唤醒工作区(WakeWA):
-
在
am_hal_flash_page_erase()
内部调用WakeWAfunc()
-
确保低功耗唤醒后Flash控制器状态正确
-
-
错误处理:
-
每个关键操作后检查返回值
-
错误码含义参考
am_hal_flash.h
定义(如0x1=无效密钥)
-