一 、 背景
在最近的一次项目中,使用的是ciu32L系列的单片机,因为初始化时,需要对flash进行一些数据写入,发现其使用的是ARM5编译
用官方的历程编译一切正常,但我项目使用的是ARM6编译器,所以我也试了下,直接将编译器改为ARM6,此时编译报了各警告
如下:
二、解决方案
2.1、 官方例程如下:
#if defined ( __CC_ARM )
#pragma arm section code = "FAST_PROGRAM"
#elif defined ( __ICCARM__ )
__ramfunc
#elif defined ( __GNUC__ )
__attribute__ ((section (".RamFunc")))
#endif/**
* @brief Flash快速编程,往目标地址快速编程半页数据
* @param address 编程地址
* @param data_buf 编程数据
* @retval std_status_t 本函数执行结果
*/
std_status_t bsp_flash_fast_write(uint32_t address, uint32_t *data_buf)
{std_status_t status = STD_OK;uint32_t prog_count = 0;/* 启动快速编程模式 */FLASH->CR |= FLASH_CR_FSTPG_MODE;/* 向目标地址写入数据 */for (prog_count=0; prog_count < FSTPG_WORD_COUNT; prog_count++){((uint32_t *)address)[prog_count] = data_buf[prog_count];/* 查询等待BSY标志被清除 */while ((FLASH->SR & FLASH_FLAG_BSY) == FLASH_FLAG_BSY);/* 若出现错误,则退出编程循环 */if (FLASH->SR & FLASH_FLAG_ALL_ERR){status = STD_ERR;break;}}/* 查询等待FSTPG_MODE状态被自动清零 */while ((FLASH->CR & FLASH_CR_FSTPG_MODE) == FLASH_CR_FSTPG_MODE);/* 清除Flash标志 */FLASH->SR = (FLASH_FLAG_ALL_ERR | FLASH_SR_EOP);return (status);
}#if defined ( __CC_ARM )
#pragma arm section
#endif
分散加载文件如下:
LR_IROM1 0x08000000 0x00040000 { ; load region size_regionER_IROM1 0x08000000 0x00040000 { ; load address = execution address*.o (RESET, +First)*(InRoot$$Sections).ANY (+RO)}RW_IRAM1 0x20000000 0x00001000 { ; RW data*.o(FAST_PROGRAM).ANY (+RW +ZI)}
}
注意:
在ARM6(即AC6编译器,基于LLVM/Clang)环境下,__CC_ARM 这个宏已被废弃,GNUC
也被Keil的ARM编译器6支持。但你遇到的问题的根本原因是,没有正确地在链接脚本和代码中统一声明和使用 .FAST_PROGRAM
段,导致编译时找不到匹配的 .o(FAST_PROGRAM) 段。
2.2、解决方案:
- 确保正确的编译器宏判断
ARM6 编译器在 Keil 中的宏是 __ARMCC_VERSION
#if defined(__CC_ARM) // ARM Compiler 5
#pragma arm section code="FAST_PROGRAM"
#elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6000000) // ARM Compiler 6
__attribute__((section(".FAST_PROGRAM"), used))
#elif defined(__ICCARM__) // IAR
__ramfunc
#elif defined(__GNUC__) // GCC
__attribute__((section(".FAST_PROGRAM"), used))
#endif
分散加载文件如下:
LR_IROM1 0x08000000 0x00040000 { ; load region size_regionER_IROM1 0x08000000 0x00040000 { ; load address = execution address*.o (RESET, +First)*(InRoot$$Sections).ANY (+RO)}RW_IRAM1 0x20000000 0x00002000 { ; RW data*(FAST_PROGRAM) ; 让 .FAST_PROGRAM 段放入 RAM.ANY (+RW +ZI)}
}
此时编译通过,程序运行正常。
写笔记的目的其实就是当再次遇到同一个问题,时间久了可能会忘记处理方法,同时也可以解决大家在项目中碰到此类问题,给以快速解决方案。赠人玫瑰,手有余香。养成做笔记的习惯。