功能比较庞杂,写得不好,抛砖引玉
预备知识
stm32 默认从主闪存0x08000000启动
art-pi2的psram 映射0x90000000
art-pi2的8线ospi flash 映射0x70000000
-
stm32h7比较灵活,通过修改选项字节,可以实现从
0x0000 0000 到 0x3FFF 0000 地址进行启动,这里不展开,感兴趣参考:【不是问题的问题】为什么STM32的Flash地址要设置到0x08000000 - STM32H7 - 硬汉嵌入式论坛 - Powered by Discuz!
-
stm32h7r系列内部flash只有64k,支持在外部flash上xip运行代码
内存映射原理
将内核对地址的访问操作转为对ospi/xspi总线的操作,需要内核支持且外设配置进入内存映射模式(初始化),进入内存映射模式后就可以xip运行代码;可以类比fsmc对扩展sdram的操作
下载算法flash loader
下载算法大致原理为调试器通过jtag/swd将一小段可执行程序传输到板子的ram,并通过jtag/swd调用其中的init、erase、read、write等函数,以操作内部/外部flash;原理参考下图:
- flm/stldr格式本质也是elf可执行程序,不含main程序;.stldr可以导出给cubeprogram等软件使用,studio的APP工程也有使用;keil的下载算法格式为.flm
下载和运行流程
通过stlink下载app的流程:swd传输下载算法,将用户app的elf写入0x70000000然后重启,由bl完成剩余操作
运行流程:从0x08000000启动bl,初始化psram和外部flash,进行内存映射HAL_XSPI_MemoryMapped;跳转到0x70000000(外部flash映射后的地址),开始XIP运行
app下载到外部flash需要设置下载算法(默认已配好):
- 注意下载算法运行在ram中,仅操作外部flash,不能替代bootloader,不能完成上电到跳转app的过程
- 也可以使用stm32 cubeprogram下载,支持回读外部flash的内容
bootloader工程
在studio中新建工程,选择基于开发板/art-pi2/示例工程/art_pi2_bootloader
在main中完成了外部flash和psram的初始化,并进入xip模式;
随后跳转到外部flash运行app程序;比较常规
int main(void)
{
MX_FLASH_Init();
EXTMEM_Init();
EXTMEM_Flash_Probe();
EXTMEM_PSRAM_Probe();
EXTMEM_Flash_EnterXIP();
EXTMEM_PSRAM_EnterXIP();
rt_kprintf("\nJump to APP...\n");
rt_hw_interrupt_disable();
JumpToApplication();
return RT_EOK;
}
#define APPLICATION_ADDRESS XSPI2_BASE //(uint32_t)0x70000000
int JumpToApplication(void)
{
typedef void (*pFunction)(void);
pFunction JumpToApp;
uint32_t Application_vector;
/* Suspend SysTick */
SysTick->CTRL = 0;
/* Disable I-Cache---------------------------------------------------------*/
SCB_DisableICache(); //TODO SCB_Disables Cache and jump success
/* Disable D-Cache---------------------------------------------------------*/
SCB_DisableDCache();
/* Apply offsets for image location and vector table offset */
// Application_vector += EXTMEM_XIP_IMAGE_OFFSET + EXTMEM_HEADER_OFFSET;
Application_vector = APPLICATION_ADDRESS;
SCB->VTOR = (uint32_t)Application_vector;
JumpToApp = (pFunction)(*(__IO uint32_t *)(Application_vector + 4u));
__set_MSP(*(__IO uint32_t *)Application_vector);
__set_CONTROL(0);
JumpToApp();
return 0;
}
- 注意:bootloader工程这里选择全片擦除,扇区擦除可能无法烧写
app示例工程
art_pi2_blink_led
重点看看链接脚本lds文件,text段放在了QFLASH中,如下图,链接时会将代码链接到外部flash中
程序中注意重定向中断向量表,然后就可以愉快地写应用了~
#define XSPI2_BASE 0x70000000UL /*!< XSPI2 base address */
static int vtor_config(void)
{
/* Vector Table Relocation in Internal XSPI2_BASE */
SCB->VTOR = XSPI2_BASE;
return 0;
}
INIT_BOARD_EXPORT(vtor_config);
- 下载算法配置:ART-Pi2_ST_winbond_64MB.stldr
补充
-
对裸机感兴趣的可以看看 @lizimu2020 的仓库 https://gitee.com/lizimu2020/ART_Pi2
-
对于全片跑在sram方案(章节7/8 RT-Thread-ART-Pi2移植CMSIS-DAP(基于CherryUSB协议栈)RT-Thread问答社区 - RT-Thread ),如果无需频繁修改bootloader程序(固定跑在0x70000000的外置flash上,仅做应用开发),使用默认bootloader即可