• 欢迎访问我的博客,推荐使用最新版火狐浏览器和Chrome浏览器访问本网站
  • 本网站关闭了评论功能,联系请点击→邮箱
  • Ctrl+D 可快捷收藏本站点

IAP的两种实现方式

STM32 gql 4年前 (2021-04-01) 1027次浏览

在Coretext-M3与Coretext-M4核中,在System Control Block中存在一个向量表偏移量寄存器 VTOR(0xE000ED08),系统产生中断后,内核通过这个寄存器的值来找到中断向量表的地址,进而执行中断例程代码,当然,此寄存器的值是可以修改的,它的默认值为0,由于映射关系,实际上就是指向映射地址,比如0x0800 0000。值得注意的是由于STM32F0XX采用的是M0核,它是没有VTOR寄存器的,也就是说,对于M0来说,中断向量表的地址固定在地址0x0000 0000上。简单的来说,将M0理解成M3/M4的特殊情况,M0假设也存在VTOR这么一个虚拟寄存器,只不过它的值不能修改,固定为0罢了。如果M0需要使用IAP程序,那么需要从内部FLASH中拷贝中断向量表到内存然后重映射SRAM。

这里捋一下STM32的启动流程,System Control Block(SYSCFG寄存器)有个MEM_MODE寄存器。

  1. MEM_MODE的值在上电后有BOOT0,BOOT1的状态值决定。这就是为默认映射,是系统自动完成的
  2. MEM_MODE的值决定了哪个内存映射到地址0x0000 0000(程序从哪开始启动)
  3. 当MEM_MODE =00/10时,Main Flash(主闪存)映射到地址0x0000 0000,即地址0x0800 0000映射到0x0000 0000.
  4. 当MEM_MODE =01时,System Flash映射到地址0x0000 0000,也就是芯片自带的Bootloader代码部分会映射到地址0x0000 0000,即0x1FFF C800映射到地址0x0000 0000.(下载程序时)
  5.  当MEM_MODE =11时,Embeded SRAM映射到地址0x0000 0000,也就是内存地址0x2000 0000映射到地址0x0000 0000.
  6. MEM_MODE位是RW的,也就是说可以修改的这一修改的过程,我们就叫其为重映射。重映射是通过用户代码通过修改MEM_MODE的值来完成的。

在复位启动后,系统在系统时钟的第4个上升沿根据BOOT0,BOOT1的配置获取其值,也就是存储到寄存器SYSCFG_CFGR1的MEM_MODE位上,这里确定了0x0000 0000的映射地址,是系统自动完成的。(这里加上从Main Flash(主闪存))在系统启动后,CPU从地址0x0000 0000获取栈顶地址,然后从0x0000 0004开始执行代码。由于0x0000 0000被映射了0x0800 0000,获取栈顶与执行实际上都是从映射的地址上实施的。也就是从映射的地址开始执行代码,比如从地址0x08000 0004开始执行代码(这里就是Reset_Handler),也就是正常启动代码,首先就运行了复位中断,进而运行SystemInit然后进入到main函数(启动文件决定),就这样,整个代码启动完成,并按照地址开始执行代码。那么如果这个时候中断产生了,如何响应中断呢?CPU根据中断类型确定偏移地址,并固定到地址0x0000 0000上找中断入口函数,映射后0x0800 0000上找中断服务函数,比如发送复位中断,PC指针偏移4字节(4字节对齐)到Reset_Handler(0x08000 0004)开始执行,执行完成后返回原地址执行。正常的程序基本流程就是这样。

现在需要加入IAP功能,假设APP地址为0x08000 6000 (0x08000 0000 — 0x08000 6000存放IAP)

如果再次按照这个流程,在IAP判断APP地址存在用户代码,并跳转到APP执行,则时候APP跳转后,PC指针变了,SP栈指针也修改了,但是中断向量表的位置并没有改变,这个时候发送中断时,再次按照默认映射从0x08000 0000开始找中断向量表,继续执行IAP的中断例程,进而引发hard fault,所以这个时候就需要利用到重映射(修改MEM_MODE =11)。f030有这么一段程序

void CMainApp::IapSet()
{
	u32 i = 0;
	for(i = 0; i < 48; i++)
	{
		*((u32*)(0x20000000 + (i << 2)))=*(__IO u32*)(APP_BASE + (i<<2));
	}
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE); 
	SYSCFG_MemoryRemapConfig(SYSCFG_MemoryRemap_SRAM);
}

这段代码执行了从内部FLASH中拷贝中断向量表到内存,然后重映射SRAM,(M0最多48个中断服务函数),当发生中断的时候PC指针固定到地址0x0000 0000上找中断入口函数,映射后0x20000000上找中断服务函数,这个就是APP中中断。值得注意的是由于这个地方会占用4*48=192=0xc0的RAM,那么APP的RAM的起始地址应修改为0x200000C0。具体修改方式Keil请自行百度,GCC请修改链接文件,请查看这里 :evil:
M0、M3、M4都可以按照这个方法实现,但是M3、M4建议通过修改前面提到的VTOR寄存器完成重映射。加入一句

SCB->VTOR = APP_BASE;

也不用去占用RAM,所以也不用去修改APP的RAM的起始地址。


如未注明 , 均为原创。转载请注明原文链接:IAP的两种实现方式
喜欢 (0)