This thread has been locked.
If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.
您好!
我正在尝试实现引导加载程序应用程序。
为了开始了解如何执行引导加载、设计了一个用例。 成功完成此简单用例后、可以增强基本功能并针对外部存储器或仿真 EEPROM 进行缩放。 有各种可能性。
用例:
我正在使用 TI 提供的引导加载程序示例。
我迄今采取的步骤:
内存 { /*扇区0 */ 矢量 (x) :O=0x00000000 l=0x00001000 BOOT_LOAD (RX):o=0x00001000 l=0x00001000 //引导加载程序位于此处*/ FLASH_API (RX):o=0x00002000 l=0x00002000 // F021 API 驻留在此处*/ /*扇区1..14 */ FLASH0 (Rx):O=0x00004000 l=0x0011BFFF /*扇区15 */ Flash_copy (RX):o=0x00120000 l=0x0001FFFF f=0x5A5A5A 堆栈 (RW):o=0x08000000 l=0x00010500 RAM (RW):o=0x08010500 l=0x0001fb00 //用户代码开始(2)*/ *用户代码结束*/ }
部分 { .intvecs:{}>向量 .text :{}>FLASH0 .const :{}>FLASH0 .cinit :{}>FLASH0 .pinit :{}>FLASH0 .bss :{}> RAM .data :{}> RAM sysmem :{}>RAM /*用户代码开始(4)*/ BOOT_LDR:{sys_core_AFw.obj (.text)}> boot_load eabi_start:{sys_startup_AFw.obj (.text)}> boot_load FLASH_API: { fapi_usr_func.obj (.text) bl_flash.obj (.text) l F021_API_CortexR4_be_V3D16.lib (.text) } LOAD = FLASH_API、 运行= RAM、 LOAD_START (API_LOAD)、 RUN_START (API_RUN)、 load_size (api_size) /*用户代码结束*/ }
… ;切换到未定义指令模式(M=11011) CPS #27 MOV LR、r0 R1女士、CPSR MSR spsr_cxsf、R1 ;切换到系统模式(共享用户模式寄存器)(M = 11111) CPS #31 MOV LR、r0 R1女士、CPSR MSR spsr_cxsf、R1 ;切换回 Supervisor 模式(M=10011)-引导加载程序 CPS #19 MOV LR、r0 R1女士、CPSR MSR spsr_cxsf、R1 ;ARM 模式- cortex R4手动 ARM DDI 0363G p.56
;MPU cortex R4 ARM DDI 0363G 第184页 MRC P15、 0x00、 R2、 c1、c0、#0x02 ORR R2、 R2、 0xF00000 MCR P15、 0x00、 R2、 c1、c0、#0x02 MOV R2、 0x40000000 fmxr fpexc、R2 ;读/写完全访问 ARM DDI 0363G 第126页 MRC P15、 0x00、 R2、 C6、C1、#0x04 MOV R2、 0x03 MCR P15、 0x00、 R2、 C6、C1、#0x04 MOV R2、 0x40000000 fmxr fpexc、R2
/**-设置闪存读取模式、地址等待状态和数据等待状态*/ flashWREG->FRDCNTL = 0x000000000000 |(UINT32)((UINT32) 3U << 8U) |(uint32)((uint32) 1U <<4U) | 1U;
extern uint8_t api_load; extern uint8_t api_run; extern uint8_t api_size; // f021 API 以 u32字表示的大小*/ #define API_U32_word_count (uint32_t)((uint32_t)(&api_size)/ sizeof (uint32_word_)* 要 定义闪存地址/#int32_t)*要定义的地址 0x00120000 #define ADDR_FLASH_API 0x00002000 /*闪存-组0、EEPROM -组7 */ #define Bank_0 0U #define Bank_7 7U #define Bank_0_Sector_15 0x8000U void fn_copy_api_to_ram (uint8_t * p_load、uint8_t * p_start、uint32_t u32_size) { 操作 { *p_start =*p_load; P_START++; P_LOAD++; } while (--u32_size); return; } void fn_updateer_util (void) { /*首先将闪存 API 复制到 RAM **以便写入闪存组0 */ fn_copy_api_to_ram ((uint8_t*)&api_load、(uint8_t*)&api_run、(uint32_t)&api_size); uint32_t u32_fapi_res =(uint32_t) 0U; u32_fapi_res = Fapi_initializeFlashBanks (SYS_CLK_FREQ); u32_fapi_res = Fapi_setActiveFlashBank (Bank_0); u32_fapi_res = Fapi_enableMainBankSecors (Bank_0_Secto_15); while (fapi_check_FSM_ready_busy!= fapi_Status_FsmReady); while (fapi_get_FSM_status!= fapi_Status_Success); u32_fapi_res = Fapi_issue19 CommandWithAddress (Fapi_EraseSector、(uint32_t*) ADDR_FLASH_COPY); fapi_flushPipeline(); while (fapi_check_FSM_ready_busy =fapi_Status_FsmBusy); while (fapi_get_FSM_status!= fapi_Status_Success); u32_fapi_res = fapi_get_FSM_status; u32_fapi_res = Fapi_initializeFlashBanks (SYS_CLK_FREQ); u32_fapi_res = Fapi_setActiveFlashBank (Bank_0); u32_fapi_res = Fapi_enableMainBankSecors (Bank_0_Secto_15); while (fapi_check_FSM_ready_busy!= fapi_Status_FsmReady); while (fapi_get_FSM_status!= fapi_Status_Success); uint8_t u8_dum_buff [4]={0xBA、0xD0、0xBA、0xD0}; u32_fapi_res = fapi_issueProgrammingCommand (((uint32_t *) ADDR_FLASH_COPY、 u8_dum_buff [0]、 4、 0U、 0U、 Fapi_AutoEccGeneration); while (fapi_check_FSM_ready_busy =fapi_Status_FsmBusy); u32_fapi_res = fapi_get_FSM_status; 返回; }
我面临的问题:
使用调试器时,如果我单步执行 Fapi_issuedCommandWithAddress()函数,它将正常工作,并且我可以在内存浏览器中看到已擦除的闪存。 如果我在函数之后设置一个断点、并在程序开始时按 Resume Execution、则会导致预取尝试。
2.当我单步执行 fapi_issueProgrammingCommand()的汇编代码时,它可以正常工作,并且重新编程新擦除的闪存! 当我尝试单步执行函数时、它会导致预取。
我不知道如何继续下去,这证明是一个阻挡者。 提前感谢您!
此致、
米哈伊尔
为了进一步澄清、 SYS_CLK_FREQ 被设定为160
// // //用于为微控制器计时的晶体的频率(MHz)。 // //这定义了运行 //引导加载程序的微控制器所使用的晶振频率。 // //取决于:无 //不包括:无 //要求:无 // //********* #define CRYSTICL_FREQ 16. //MHz #define SYS_CLK_FREQ 160 //MHz
您好!
fn_updater_util(
) should be executed from SRAM too,
大家好、感谢大家的回答。 我相信该函数也是从 RAM 运行的!
从 sys_startup.c 中摘录:
/*配置系统对发送给 ESM 组1的错误条件的响应*/ /*可以从 HALCoGen 的"ESM"选项卡配置此函数*/ esmInit(); /*初始化复制表*/ __TI_auto_init(); //用户代码开始(75)*/ //用户代码结束*/ /*调用应用程序*/*SAFETYMCUSW 296 S MR:8.6 "启动代码(块范围内的库函数)"*/ /* SAFETYMCUSW 326 S MR:8.2 "startup code (Declaration for main in library)"*/ /* SAFETYMCUSW 60 D MR:8.8 "启动代码(库中 main 的声明;仅为相同操作 extern)"*/ fn_updateer_util(); //用户代码开始(76)*// //*用户代码结束*// *SAFETYMCUSW 122 S MR:20.11 "启动代码(需要存在 EXIT 和 ABORT)"*/ EXIT (0); /*用户代码开始(77)*/ /*用户代码结束*/ }
您好!
fn_updateer_util() fapi_usr_func()? 我在 链接器命令文件中找不到 fn_updateer_util()。
再好一次!
我已修改链接器文件以包括 fn_updateer_util()函数所驻留的文件。 它是 bl_main.obj:
BOOT_LDR:{sys_core_AFw.obj (.text)}> boot_load eabi_start:{sys_startup_AFw.obj (.text)}> boot_load /*链接器将段分配到单个存储器范围以便运行、 但不同的加载存储器范围。 * FLASH_API: { fapi_usr_func.obj (.text) bl_flash.obj (.text) bl_main.obj (.text) l F021_API_CortexR4_be_V3D16.lib (.text) } LOAD = FLASH_API、 /*在何处加载段*/ 运行= RAM、 /*运行段的位置*/ load_start (api_load)、/* api_load 保存 flashAPI 段的 load addr * run_start (api_run)、/* api_run 保存 flashAPI 段的运行地址*/ load_size (api_size) /* api_size 保存 flashAPI 段的大小*/ /* api_load、api_run、api_size 可从复制表中引用。 *
现在、我将直接在 sys_startup.c 中调用函数 fn_copy_api_to_ram ()、如 TI 引导加载程序示例中所示。 从 sys_startup.c 中摘录:
/*用户代码开始(74)*/ /*用户代码结束*/ /*配置系统对发送给 ESM 组1的错误条件的响应*/ /*可以从 HALCoGen 的"ESM"选项卡配置此函数*/ esmInit(); /*初始化复制表*/ __TI_auto_init(); //用户代码开始(75)*/ //用户代码结束*/ /*调用应用程序*/*SAFETYMCUSW 296 S MR:8.6 "启动代码(块范围内的库函数)"*/ /* SAFETYMCUSW 326 S MR:8.2 "startup code (Declaration for main in library)"*/ /* SAFETYMCUSW 60 D MR:8.8 "启动代码(库中 main 的声明;仅为相同操作 extern)"*/ fn_copy_api_to_ram ((uint8_t*)&api_load、(uint8_t*)&api_run、(uint32_t)&api_size); fn_updateer_util(); //用户代码开始(76)*// //*用户代码结束*// *SAFETYMCUSW 122 S MR:20.11 "启动代码(需要存在 EXIT 和 ABORT)"*/ EXIT (0); /*用户代码开始(77)*/ /*用户代码结束*/ }
现在我可以单步执行两个函数(Fapi_issueCommandAppoAddress()和 Fapi_issueProgrammingCommand()),它们不会生成预取指令。
如果我在 fn_updateer_util()函数的末尾设置了一个断点,并在系统复位后按 Resume 键,它将进入 prefetchEntry!
一个非常有用的答案,可能指向正确的方向,就是 Anthony F. Seely 在这个主题中所作的回答: 。
您能否解释一下在提供的引导加载程序示例中、在 sys_intvecs.asm 中、应用程序映像的中断分支为何? 从 TI 引导加载程序示例中从 sys_intvecs.asm 中摘录:
;------------------------------------------------------------------ ;中断矢量 ;请更改#0x??? 在 bl_config.h 中定义的指定图像位置 b _c_int00 ;0x00 b #0x1FFF8 ;0x04 b #0x1FFF8 ;0x08、软件中断 b #0x1FFF8 ;0x0C,中止(预取) b #0x1FFF8 ;0x10,中止(数据) 保留尝试 b 保留尝试 ;0x14 LDR PC、[PC、#-0x1b0] ;0x18 LDR PC、[PC、#-0x1b0] ;0x1C
我相信解决方案即将推出、但 TI 团队的帮助将不胜感激!
我将使用此平台记录我的调查结果、以便任何面临类似问题的人都可以参阅我为解决此问题而采取的步骤。
查看我在上面的注释()中引用的论坛线程后、我在中断矢量表(sys_intvecs.asm)的 prefetchEntry 处设置一个断点、并恢复应用程序、使其导致中止。
已达到断点、我可以使用 CCS 中的"Register"视图观察 MCU 的寄存器。 在本例中、需要关注的是 CP15_instruction_FAULT_STATUS。 Anthony F. Seely 的评论 指出了这一点(链接: 2015年6月1日晚上10:41)
使用 CortexR4F 技术参考手册(ARM DDI 0363G ID041111)在第4-47页的表4-27中、CP15_instruction_FAULT_STATUS 的位[10、3-0]的值建议为"同步奇偶校验/ECC 错误"
使用_coreDisableRamEcc_()禁用 RAM ECC;使用 disableParity ()禁用奇偶校验;也无法解决问题。
将中断矢量设置为与引导加载程序示例中的中断矢量相同并不是最佳选择、因为检查 TCRAMM ECC 的函数会生成数据中止(DABT)、这会导致跳转到中断矢量。
我在本地克隆了 Hercules 示例 git 存储库(),并签出了名为"qjwang_Hercules _examples"的分支(提交哈希:2ec9e6f9f8a09932f1d6455ab3c101c6efa27711)。
在此存储库中、我发现 sys_link.cmd 链接器文件与 TI 网页上提供的引导加载程序示例非常不同。 我相应地修改了链接器文件。 现在针对链接器文件中的每个闪存区域调用 ECC 生成。
在引导加载程序示例的 readme.txt 中、我找到了以下内容(在"新功能"主题下):"使用链接器 CMD 文件生成闪存 ECC 以避免推测取 ECC 错误。"
在 readme.txt 的"Linker CMD file to generate Flash ECC"主题中对此进行了进一步讨论。 我遵循了指出的所有步骤:
(从 readme.txt 中摘录)
请执行闪存设置下的以下更改。 CCS 项目属性-->调试-->闪存设置:
1.检查"连接时系统复位"
2.取消选中"Auto ECC Generation"
3.选中"将程序段与64位内存区域对齐"
4.为“Flash 验证设置”选择“无”
5.取消选中"程序加载前执行空白检查"
6.按“应用”保存更改!
所有这些操作也完成后、我仍然会获得预取终止!
我真的很难解决这个问题、因此我们非常感谢您的帮助!
米哈伊尔
您是否解决了此问题?
我遇到了一个微笑问题。
Rob
您好、 Mihail、
您能否发布您的项目、以便我可以在电路板上进行检查?
您好!
您是否已解决此问题?
QJ、
我没有解决所有闪存问题,尽管我现在已经解决了这个特定问题。
新用户的陷阱是推测分支。
我在擦除的某个扇区中有一段测试代码、在固件更新期间、我将不会访问测试代码。
事实证明、情况并非如此、CPU 必须不时访问已擦除的部分以进行 推测分支、从而得出不一致的结果。
我现在已将测试代码移出此区域、这会导致代码空间不足的另一个问题。
因此、我想我现在已经开始讨论这个问题了。
我现在还有一个问题需要解决、但我认为最好启动一个新线程、因为它与写入闪存失败相关。 我处于另一个调试会话的中间,如果我在太长的时间内无法解析,我将创建一个新线程。
感谢你的帮助。
此致
Robert
您好!
很抱歉、我的回复延迟了、我不在办公室、无法访问源代码!
这是源代码。 这是一个展示我仍面临的问题的最低工作示例!
提前感谢您!
e2e.ti.com/.../5127.tms570ls_5F00_bootloader.zip
您好!
请您发布新主题的参考链接!
此致
您好、Mihail、
Fapi_flushPipeline()用于刷新 FMC 管道缓冲区。 请在状态检查后调用此函数。 但您在状态检查之前调用它。
void fn_updateer_util (void)
{
uint32_t u32_fapi_res =(uint32_t) 0U;
u32_fapi_res = Fapi_initializeFlashBanks (SYS_CLK_FREQ);
fapi_flushPipeline();
if (((Fapi_initiatalizeFlashBanks ((uint32_t) SYS_CLK_FREQ))= Fapi_Status_Success)
{
(空) Fapi_setActiveFlashBank (((Fapi_FlashBankType) Bank_0);
(空) Fapi_enableMainBankSectors (0xFFFF);
}
其他
{
返回;
}
while (fapi_check_FSM_ready_busy!= fapi_Status_FsmReady);
while (fapi_get_FSM_status!= fapi_Status_Success);
u32_fapi_res = Fapi_issue19 CommandWithAddress (Fapi_EraseSector、(uint32_t*) ADDR_FLASH_COPY);
// fapi_flushPipeline();
while (fapi_check_FSM_ready_busy =fapi_Status_FsmBusy);
while (fapi_get_FSM_status!= fapi_Status_Success);
fapi_flushPipeline();
u32_fapi_res = fapi_get_FSM_status;
while (fapi_check_FSM_ready_busy!= fapi_Status_FsmReady);
while (fapi_get_FSM_status!= fapi_Status_Success);
uint8_t u8_dum_buff [4]={0xBA、0xD0、0xBA、0xD0};
u32_fapi_res = fapi_issueProgrammingCommand (((uint32_t *) ADDR_FLASH_COPY、
u8_dum_buff [0]、
4、
0U、
0U、
Fapi_AutoEccGeneration);
//fapi_flushPipeline();
while (fapi_check_FSM_ready_busy =fapi_Status_FsmBusy);
fapi_flushPipeline();
u32_fapi_res = fapi_get_FSM_status;
返回;
}
另一项建议是、
请使用 vfill 而不是填入链接器 cmd 文件。
非常感谢、
这完全解决了问题!
应用软件不再跳转到中断矢量!
此致、
米哈伊尔