第一步,自己写了bootloader,然后用华大官方库写了一个APP,是没有问题的,SCB->VTOR中断向量已经偏移,华大的偏移函数在SystemInit函数中,SystemInit是在S,汇编文件中调用的,然后才会去到main函数.才会执行rtthread_startup函数。翻了好久rt-thread的源码,也没找到有重复修改SCB->VTOR的地方,特地来论坛求助。
1:不用rt-thread写的app没有问题的;
2:把rt-thread源码编译进来,就跑不了了;
3:取消APP程序,不使用跳转应用程序,不偏移中断向量,带rt-thread的程序是没有问题的,只是出在了偏移rom地址后,无法运行
4:app跳转方式,也不能用debug看在哪里跑错了.
我使用MDK分散加载文件如下配置,偏移地址是0x00020000
; ****************************************************************
; Scatter-Loading Description File
; ****************************************************************
LR_IROM1 0x00020000 0x00058000 { ; load region size_region
ER_IROM1 0x00020000 0x00058000 { ; load address = execution address
*.o (RESET, +First)
*(InRoot$$Sections)
.ANY (+RO)
.ANY (+XO)
}
RW_IRAM1 0x1FFF8000 0x0002F000 { ; RW data
.ANY (+RW +ZI)
}
}
app偏移自己写就是了,参考这个,地址根据自己偏移地址就好了。
/**
* Function ota_app_vtor_reconfig
* Description Set Vector Table base location to the start addr of app(RT_APP_PART_ADDR).
*/
static int ota_app_vtor_reconfig(void)
{
//#define NVIC_VTOR_MASK 0x3FFFFF80
/* Set the Vector Table base location by user application firmware definition */
SCB->VTOR = RT_APP_PART_ADDR ;
return 0;
}
INIT_BOARD_EXPORT(ota_app_vtor_reconfig);
boot程序配置,可以参考楼上写的QBOOT代码,其中跟平台相关配置我是这样处理的
/*
* qboot_stm32.c
*
* Change Logs:
* Date Author Notes
* 2020-08-31 qiyongzhong first version
*/
#include <board.h>
#define CHIP_FAMILY_HC32
#define IAP_PERIPH_WP (LL_PERIPH_GPIO | LL_PERIPH_EFM | LL_PERIPH_FCG | \
LL_PERIPH_PWC_CLK_RMU | LL_PERIPH_SRAM)
#ifdef CHIP_FAMILY_HC32
#include <rtthread.h>
#include <rtdevice.h>
#include <qboot.h>
#include <hc32f460.h>
//#include "hc32_ddl.h"
//#define QBOOT_APP_RUN_IN_QSPI_FLASH
//#define QBOOT_DEBUG
#define QBOOT_USING_LOG
#define DBG_TAG "Qboot"
#ifdef QBOOT_DEBUG
#define DBG_LVL DBG_LOG
#else
#define DBG_LVL DBG_INFO
#endif
#ifdef QBOOT_USING_LOG
#ifndef DBG_ENABLE
#define DBG_ENABLE
#endif
#ifndef DBG_COLOR
#define DBG_COLOR
#endif
#endif
#include <rtdbg.h>
#ifdef QBOOT_APP_RUN_IN_QSPI_FLASH
static void qbt_qspi_flash_init(void)
{
//waiting realize
}
void qbt_jump_to_app(void)
{
qbt_qspi_flash_init();
//waiting realize
}
#else
/**
* @brief Systick De-Initialize.
* @param None
* @retval None
*/
static void SysTick_DeInit(void)
{
SysTick->CTRL = 0UL;
SysTick->LOAD = 0UL;
SysTick->VAL = 0UL;
}
/**
* @brief IAP clock De-Initialize.
* @param None
* @retval None
*/
void IAP_CLK_DeInit(void)
{
CLK_SetSysClockSrc(CLK_SYSCLK_SRC_MRC);
/* Switch driver ability */
(void)PWC_HighPerformanceToLowSpeed();
/* Set bus clk div. */
CLK_SetClockDiv(CLK_BUS_CLK_ALL, (CLK_HCLK_DIV1 | CLK_EXCLK_DIV1 | CLK_PCLK0_DIV1 |
CLK_PCLK1_DIV1 | CLK_PCLK2_DIV1 | CLK_PCLK3_DIV1 | CLK_PCLK4_DIV1));
CLK_XtalCmd(DISABLE);
CLK_PLLCmd(DISABLE);
/* sram init include read/write wait cycle setting */
SRAM_SetWaitCycle(SRAM_SRAM_ALL, SRAM_WAIT_CYCLE0, SRAM_WAIT_CYCLE0);
SRAM_SetWaitCycle(SRAM_SRAMH, SRAM_WAIT_CYCLE0, SRAM_WAIT_CYCLE0);
/* 0 cycles */
GPIO_SetReadWaitCycle(GPIO_RD_WAIT0);
/* flash read wait cycle setting */
EFM_SetWaitCycle(EFM_WAIT_CYCLE0);
}
static void qbt_reset_periph(void)
{
// #define ENABLE_FCG0_REG_WRITE() (M4_MSTP->FCG0PC = 0xa5a50001u)
// #define DISABLE_FCG0_REG_WRITE() (M4_MSTP->FCG0PC = 0xa5a50000u)
// #define DEFAULT_FCG0 (0xFFFFFAEEul)
// #define DEFAULT_FCG1 (0xFFFFFFFFul)
// #define DEFAULT_FCG2 (0xFFFFFFFFul)
// #define DEFAULT_FCG3 (0xFFFFFFFFul)
// ENABLE_FCG0_REG_WRITE();
// M4_MSTP->FCG0 = DEFAULT_FCG0;
// M4_MSTP->FCG1 = DEFAULT_FCG1;
// M4_MSTP->FCG2 = DEFAULT_FCG2;
// M4_MSTP->FCG3 = DEFAULT_FCG3;
// DISABLE_FCG0_REG_WRITE();
SysTick_DeInit();
// IAP_CLK_DeInit();
/* Peripheral registers write protected */
EFM_FWMC_Cmd(DISABLE);
LL_PERIPH_WP(IAP_PERIPH_WP);
}
void qbt_jump_to_app(void)
{
typedef void (*app_func_t)(void);
u32 app_addr = QBOOT_APP_ADDR;
u32 stk_addr = *((__IO uint32_t *)app_addr);
app_func_t app_func = (app_func_t)(*((__IO uint32_t *)(app_addr + 4)));
if ((((u32)app_func & 0xff000000) != 0x00000000) || (((stk_addr+0x00010000) & 0x2ff00000) != 0x20000000))
{
LOG_E("No legitimate application.");
return;
}
rt_kprintf("Jump to application running ... \n");
rt_thread_mdelay(200);
__disable_irq();
qbt_reset_periph();
for(int i=0; i<144; i++)
{
NVIC_DisableIRQ(i);
NVIC_ClearPendingIRQ(i);
//enIrqResign(i);
}
// SysTick->CTRL = 0;
// SysTick->LOAD = 0;
// SysTick->VAL = 0;
// CLK_MrcCmd(Enable);
// CLK_SetSysClkSource(ClkSysSrcMRC);
// EFM_Unlock();
// EFM_SetLatency(0);
// EFM_Lock();
//
__set_CONTROL(0);
__set_MSP(stk_addr);
app_func();//Jump to application running
LOG_E("Qboot jump to application fail.");
}
#endif
#endif
跳转时注意时钟切换问题,我是发现在boot跳转前把时钟切换到内部8M,在app切换成外部时钟时,尽管已经检测时钟稳定标志,但实际切换运行不起来。所以我BOOT直接不切换了,直接把BOOT跟APP时针配置得一样。
感谢解答,我查看了ICG功能是关闭了的,我今天把debug位置修改后,可以直接debug了,发现停在了如下位置
在开启任务调度后,就会进入NMI_Handler
你这是已跳转到APP了吗?
总RAM是128k,分两个64k的段,它们虽然地址连续,但是作连续使用会有问题,建议全局变量、系统堆栈等使用前64k,堆空间使用后64k。
已经跳转了,hc32f460,我用的RAM是256KB的。APP rt-thread开始调度任务后,就进这里面了。debug方式很曲折,要改debug里面的flash开始地址,然后把bin,放到SD卡,APP开始debug,开始debug后,进入的是bootloader,bootloader把SD卡的程序更新到flash里面,然后跳转,这时keil的debug给接管到跳过来的app,开始单步调试。
关键是不用rt-thread,就完全没有问题
如果不是用qboot做的bootloader,那么跳转代码最好参考qboot中hc32的跳转代码做些修改
代码我是抄的华大官方的iap 例子,已对修改成和你的一样了,仍然不能运行,下面是bootloader跳转代码
下面是app跳转的偏移,地址为0xA004,多偏移了4字节,是我用来存放app写入完成标志的,防止APP写的时候SD卡被拔出来,APP未写入完成,bootloader就跳转了程序
你还是把堆空间的开始和结果指定到第2个段RAM试试吧!不要和系统堆栈、全局变量在一个RAM段内。我曾经经历过在一个段内就运行不正常的问题。
感谢,我用的Keil,不会把堆和栈分开指定,还要研究一下,刚搜索了下hc32f460的确把ram分段了,跨段访问时,会出问题。真让人头大
感谢大佬,我查到问题了,如下图
手册写着可以按4字节偏移,我在APP中debug,跟踪SCB->VTOR的值,发现值为0xA000,我明明写的0xA004,就证明手册写的可以按照4字节偏移是错误的,指定到一个扇区开始位置才行。官方写这种手册是真的害人。
您好,请教一下,app除须“修改连接配置文件中的Flash起始地址”和“重映射中断向量”外,还须关闭ICG部分参与编译,即要配置DDL_ICG_ENABLE为DDL_OFF,想问下您这个回复里面的重映射中断向量是在哪里做的呀
@memeda
工程中加入重映射操作模块文件,文件名:drv_vtor_reconfig.c,文件代码如下: