基于MDK-Keil环境如何把STM32程序直接下载到SRAM运行

1. 前言

对于 Cortex-M 内核的微控制器,它们都可以支持在 RAM 中执行程序,有些非 ARM 的微控制器是不支持的。

在内部 SRAM 执行程序,有基于以下几方面的原因:

  • 1、所使用的设备可能具有OTP(One-time Programmable,一次性可编程)ROM区域,还没有确定最终代码之前,还不会把程序编程到芯片中;
  • 2、有些MCU内部内部可能没有Flash,可能会使用到外部的存储器。但是在软件开发阶段可以下载到SRAM进行开发测试;
  • 3、对于特定的测试场合,Flash已经烧录了程序,但是不想擦除。这时可以把测试程序下载到SRAM运行;
  • 4、对于有些Flash被锁定的芯片,可以把代码下载到SRAM,然后进行解锁;
  • 5、Flash写入需要先擦除,所以SRAM的写入速度要比Flash快很多,如果程序很大的话,在开发阶段直接在SRAM运行可以提高效率。

对于程序下载到内部SRAM运行,有多种方法:

  • 1、配置boot引脚,然后下载代码到SRAM,使程序从SRAM启动
  • 2、不修改boot引脚启动模式,借助仿真器,进入仿真模式,然后强制更改 PC SP 指针,从SRAM位置取值开始运行
  • 3、程序下载到内部Flash或者外部的SD卡、SPI Flash等存储设备,然后上电之后把代码搬运到SRAM运行(类似代码的重定位)

下面只介绍前面两种方式。

首先在修改程序在SRAM运行之前,要先准备好一份可以正常在Flash运行的程序。

2. 修改散列文件

散列文件,就是链接脚本,指导链接器如何对程序进行链接的。

我们要让代码在SRAM运行,首先就要修改散列文件,让程序链接地址修改在内部SRAM空间。

我们打开Keil的配置界面,然后使用我们自己修改的散列文件。

修改后的散列文件内容如下:

assembly 复制代码
; *************************************************************
; *** Scatter-Loading Description File generated by uVision ***
; *************************************************************

LR_IROM1 0x20000000 0x00010000  {    ; load region size_region
  ER_IROM1 0x20000000 0x00010000  {  ; load address = execution address
   *.o (RESET, +First)
   *(InRoot$$Sections)
   .ANY (+RO)
   .ANY (+XO)
  }
  RW_IRAM1 0x20010000 0x00010000  {  ; RW data
   .ANY (+RW +ZI)
  }
}

我使用的MCU型号是 STM32F407ZG ,IARM1 的 SRAM 大小有 0x20000 ,即 128KB。我这里分配的代码区域(ER_IROM1)大小是 0x10000(64KB),然后可读可写的数据区域大小是0x10000(64KB),也就是把他们平均分了。

在实际的项目开发中,可根据实际情况改写分配。

3. 修改中断向量表基地址

默认的中断向量表基地址是指向 0x08000000 的地址处的,现在我们已经更改了链接地址,把程序链接到内部SRAM 0x20000000 区域了。

如果发生中断,CPU还是跳到0x08000000开始的地址处执行中断服务函数的话,那么肯定是程序崩溃,因为现在0x08000000处的地址已经没有代码了。

要想正常使用中断的话,就必须修改中断向量表的基地址指向0x20000000地址处。

修改中断向量表基地址,只要修改 SCB->VTOR 寄存器的值就行。

具体代码,在 system_stm3f4xx.c 的 SystemInit 函数就有。如下:

c 复制代码
void SystemInit(void)
{
	/* 部分代码省略 ........ */

    /* Configure the Vector Table location add offset address */
    #ifdef VECT_TAB_SRAM
    SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM */
    #else
    SCB->VTOR = FMC_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH */
    #endif
}

我们只要定义这个 VECT_TAB_SRAM 宏,就可以修改中断向量表的基地址指向 0x20000000 的地址处了。

这个宏可以直接在Keil的配置界面 C/C++ 选项里面的宏定义那里填写,当然直接在 system_stm3f4xx.c 这个文件前面自己手动写一下也可以。

4. 修改下载算法的配置

为了把代码下载到SRAM中,还需要修改Jlink的下载算法配置,只要其实就是更改下载的地址改为 SRAM 的地址。

对于上面的配置简单解释如下:

  • 1、由于是下载到SRAM,SRAM写入是不需要擦除的,所以勾选 DO not Erase 即可
  • 2、"Programming Algorithm"一栏的配置,由于没有内置的SRAM下载算法,所以下载算法选择的还是原来的Flash下载算法。但是下面的起始地址和大小需要更改,就改为我们在散列文件定义代码区域的起始地址和大小。
  • 2、"RAM for Algorithm"一栏是指"编程算法"(Programming Algorithm)可使用的 RAM 空间,下载程序到 FLASH 时运行的编程算法需要使用 RAM 空间,在默认配置中它的首地址为 0x20000000,即内部 SRAM 的首地址。但是现在我们修改了0x20000000开始处存放的是代码,所以这里的起始地址要修改了散列文件设置的 RW 区域的起始地址,即 0x20010000 。然后大小默认不用改。

5. 修改boot启动模式

配置到这里,其实我们这时如果更改Boot的启动引脚,配置为内部SRAM启动,然后点击下载按钮,程序就可以正常跑了的。

但是如果不修改boot启动模式,然后从SRAM启动的话,也可以借助仿真器配置,进入仿真调试模式,然后通过仿真器配置强制 PC SP 指针从 0x20000000 开始处取值,这样也能让程序正常从SRAM运行。

6. 通过仿真器配置修改 PC SP 的值

修改boot模式的目的,其实就是让MCU上电之后,可以从正确的地址处获取到 PC SP 指针的初始值,这样代码才可以正常开始运行。

让 PC SP 获取到正确的值,有两种方式:

  • 修改Boot启动模式,让程序从内部SRAM启动
  • 不修改启动模式,然后通过仿真器配置,进入仿真模式,强制修改 PC SP 的值。

下面介绍下怎么通过仿真器配置,让代码在SRAM运行。

首先我们自己编写一份 .ini 的调试配置文件,强制 PC SP 指针的地址值。内容如下:

c 复制代码
/***********************************************************/
/* Debug_RAM.ini: Initialization File for Debugging from Internal RAM */
/******************************************************/
/* This file is part of the uVision/ARM development tools. */
/* Copyright (c) 2005-2014 Keil Software. All rights reserved.*/
/* This software may only be used under the terms of a valid, current */
/* end user licence from KEIL for a compatible version of KEIL software */
/*development tools. Nothing else gives you the right to use this software ?*/
/***************************************************/

 FUNC void Setup (void) {
 SP = _RDWORD(0x20000000); // 设置栈指针 SP,把 0x20000000 地址中的内容赋值到 SP。
 PC = _RDWORD(0x20000004); // 设置程序指针 PC,把 0x20000004 地址中的内容赋值到 PC。
 // XPSR = 0x01000000; // 设置状态寄存器指针 xPSR
 _WDWORD(0xE000ED08, 0x20000000); // Setup Vector Table Offset Register
 }

 LOAD %L INCREMENTAL // 下载 axf 文件到 RAM
 Setup(); //调用上面定义的 setup 函数设置运行环境

 g, main //跳转到 main 函数

然后配置Keil的选项,如下:

这样,通过这种方式,不需要修改boot引脚的启动模式,点击 debug 调式按钮,也一样可以正常在SRAM运行。

缺点就是下载程序必须是点击进入调试界面,不能通过下载程序的按钮下载程序。因为这种方式是通过仿真器的配置强制设置 PC SP 指向正确的地址的。

相关推荐
追梦少年时6 小时前
STM32-Flash闪存
stm32·单片机·嵌入式硬件·51单片机
小刘同学-很乖15 小时前
MQTT从入门到精通之MQTT Dashboard
spring boot·stm32·物联网·iot
YuCaiH16 小时前
【STM32】USART串口数据包
笔记·stm32·单片机·嵌入式硬件
Kasen's experience18 小时前
STM32 GPIO 配置
stm32·单片机·嵌入式硬件
非概念19 小时前
stm32学习笔记----51单片机和stm32单片机的区别
笔记·stm32·单片机·学习·51单片机
无敌最俊朗@21 小时前
stm32学习之路——八种GPIO口工作模式
c语言·stm32·单片机·学习
EterNity_TiMe_21 小时前
【论文复现】STM32设计的物联网智能鱼缸
stm32·单片机·嵌入式硬件·物联网·学习·性能优化
7yewh1 天前
嵌入式硬件杂谈(一)-推挽 开漏 高阻态 上拉电阻
驱动开发·stm32·嵌入式硬件·mcu·物联网·硬件架构·pcb工艺
电子工程师UP学堂1 天前
STM32 设计的较为复杂的物联网项目,包括智能家居控制系统,涵盖了硬件和软件的详细设计。
stm32
7yewh1 天前
嵌入式硬件电子电路设计(五)MOS管详解(NMOS、PMOS、三极管跟mos管的区别)
stm32·嵌入式硬件·mcu·物联网·硬件架构·硬件工程·pcb工艺