在 RAM 中调试代码的优点:
在 RAM 中调试代码的缺点:
stm32的启动方式:
(1)从地址 0x00000000 处取出栈指针 MSP 的初始值,该值就是栈顶的地址;
(2)从地址 0x00000004 处取出程序指针 PC 的初始值,该值指向复位后应执行的第一条指令;
上述过程由内核自动设置运行环境并执行主体程序,因此它被称为自举过程。
这个实际上和启动文件是相对应的:
实际应用中,我们会根据BOOT0和BOOT1两个引脚,把这两个地址映射到其他地址空间;
对于内部FLASH和内部SRAM已经很熟悉了,系统存储器是什么?
实际上,当我们按住复位然后松开时,内核就会从映射到的地址,取出SP指针和PC指针开始运行。
启动文件决定0地址和4地址的存储内容,sct 文件决定这些内容的绝对地址。
系统存储器启动方式(ISP)
当芯片上电后采样到 BOOT0 引脚为高电平, BOOT1 为低电平时,内核将从系统存储器的 0x1FFFF000 及 0x1FFFF004
获取 MSP 及 PC 值进行自举。系统存储器是一段特殊的空间,用户不能访问, ST 公司在芯片出厂前就在系统存储器中固化了
一段代码。因而使用系统存储器启动方式时,内核会执行该代码,该代码运行时,会为 ISP 提供支持(In System Program),如检
测 USART1/2、 CAN2 及 USB 通讯接口传输过来的信息,并根据这些信息更新自己内部 FLASH 的内容,达到升级产品应用程
序的目的,因此这种启动方式也称为 ISP 启动方式。
内部Flash启动过程:
来分析一下启动文件:
然后根据 sct 文件:
*.o(RESET, +First)命令,用于把启动文件中定义的 RESET 节区放在当前执行域的开头,即地址为 0X0800 0000。这个设计非常的巧妙,这样的话,__initial_sp 和 Reset_Handler 就分别被存储到0X0800 0000 和 0X0800 0004。
那么加入我们把*.o(RESET, +First)语句放到RW_IRAM1中,__initial_sp 和 Reset_Handler就会被存储到0X2000 0000和
0X2000 0004,如下所示:
接下来,使用 fromelf 生成反汇编代码:
fromelf --text -c .流水灯.axf > test.txt
从反汇编代码可了解到,这个工程的 0x08000000 地址存储的值为 0x20000428,0x08000004 地址存储的值为
0x08000145,查看 map 文件,这两个值正好是栈顶地址__initial_sp 以及首条指令 Reset_Handler 的地址。下载器会根据 axf 文
件(bin、 hex 类似)存储相应的内容到内部 FLASH 中。
SRAM 中调试代码
首先是注意事项:
RAM 调试,由于原 FLASH 中可能有程序,因此在 BOOT0 和 BOOT1 没改变时,不能用硬件复位(硬件复位会跳转执行FLASH中的代码),只能用调试按钮,然后点击全速运行。硬件开发板上的复位和调试界面的复位均不能使用,不然就会跳转去执行FLASH程序,导致代码出错。要想复位程序,必须先退出调试,再重新进入调试。
(1)创建 RAM 调试版本
(2)配置 sct 分散加载文件:
接下来,我们使用 fromelf 工具分别生成了普通版本和RAM调试版本的工程,对比如下:
可以看到,RAM版本中的程序,完全是保存在内部SRAM的,而且和FLASH版本完全对应。
(3)设置中断向量表偏移:
由于 startup_stm32f10x.s 文件中的启动代码不是指定到绝对地址的,经过它由链接器决定应存储到内部 FLASH 还是 SRAM,所以 SRAM 版本工程中的启动文件不需要作任何修改。
重点在于启动文件定义的中断向量表被存储到内部 FLASH 和内部 SRAM 时,这两种情况对内核的影响是不同的,内核会根据它的“向量表偏移寄存器 VTOR”配置来获取向量表,即中断服务函数的入口。我们来看一下关于VTOR寄存器的描述:
VTOR 寄存器是由启动文件中 Reset_Handle 中调用的库函数 SystemInit 配置的,标准库函数如下:
void SystemInit (void)
{
/* Reset the RCC clock configuration to the default reset state(for debug purpose) */
/* Set HSION bit */
RCC->CR |= (uint32_t)0x00000001;
/* Reset SW, HPRE, PPRE1, PPRE2, ADCPRE and MCO bits */
#ifndef STM32F10X_CL
RCC->CFGR &= (uint32_t)0xF8FF0000;
#else
RCC->CFGR &= (uint32_t)0xF0FF0000;
#endif /* STM32F10X_CL */
/* Reset HSEON, CSSON and PLLON bits */
RCC->CR &= (uint32_t)0xFEF6FFFF;
/* Reset HSEBYP bit */
RCC->CR &= (uint32_t)0xFFFBFFFF;
/* Reset PLLSRC, PLLXTPRE, PLLMUL and USBPRE/OTGFSPRE bits */
RCC->CFGR &= (uint32_t)0xFF80FFFF;
#ifdef STM32F10X_CL
/* Reset PLL2ON and PLL3ON bits */
RCC->CR &= (uint32_t)0xEBFFFFFF;
/* Disable all interrupts and clear pending bits */
RCC->CIR = 0x00FF0000;
/* Reset CFGR2 register */
RCC->CFGR2 = 0x00000000;
#elif defined (STM32F10X_LD_VL) || defined (STM32F10X_MD_VL) || (defined STM32F10X_HD_VL)
/* Disable all interrupts and clear pending bits */
RCC->CIR = 0x009F0000;
/* Reset CFGR2 register */
RCC->CFGR2 = 0x00000000;
#else
/* Disable all interrupts and clear pending bits */
RCC->CIR = 0x009F0000;
#endif /* STM32F10X_CL */
#if defined (STM32F10X_HD) || (defined STM32F10X_XL) || (defined STM32F10X_HD_VL)
#ifdef DATA_IN_ExtSRAM
SystemInit_ExtMemCtl();
#endif /* DATA_IN_ExtSRAM */
#endif
/* Configure the System clock frequency, HCLK, PCLK2 and PCLK1 prescalers */
/* Configure the Flash Latency cycles and enable prefetch buffer */
SetSysClock();
#ifdef VECT_TAB_SRAM
SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM. */
#else
SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH. */
#endif
}
其中,值得注意的是这一块,根据是否定义宏VECT_TAB_SRAM,来设置VTOR的偏移地址是基于SRAM还是FLASH。
两个基地址定义如下,其实也就是SRAM和FLASH的起始地址:
那么,我们可以在SRAM调试的工程配置中加入VECT_TAB_SRAM宏(正常版本中没有),来进行向量表偏移:
(4)修改 FLASH 下载配置:
得到 SRAM 版本的代码指令后,为了把它下载到芯片的 SRAM 中,还需要修改下载器的配置,如图所示:
但是,以上配置都完成后,并不能下载使用!!!
一个解决方案是,利用调试按钮运行程序。后面还有一堆脚本配置,参考零死角玩转STM32。
上一篇:stm32专题三十七:自动分配变量到指定 SRAM 空间
下一篇:stm32专题三十九:SDIO
推荐阅读最新更新时间:2024-11-18 04:56