Debugging STM32F10X codes in RAM using Keil MDK

I’m using STM32F103ZE recently, it has 512KB flash and 64KB RAM, for a small program, the 64K RAM is big enough to hold both the code and the data. If we can debug codes in RAM, then there’s no need to write the flash every time, so you don’t have to worry about the life of the flash.

STM32F10X chips have 3 boot mode: flash, bootloader and RAM, depends on the levels on Boot0 and Boot1 pins. But the Boot From RAM mode is actually not very useful, because there’s no mapping mechanism in the chip to let to CPU to access RAM area at reset. We know that in STM32F10x chips, flash memory starts from address 0x800 0000, and bootloader resides from 0x1FFF B000 or 0x1FFF F000, and in the respective boot mode, both of the addresses are mapped to 0x0000 0000, so the CPU can get the right place (the CPU loads stack pointer SP and program pointer PC from address 0x0000 0000 and 0x0000 0004 at reset).

But for RAM, it can not be mapped to address 0, so there’s no strait way to get the CPU to boot from RAM. We need the help from the debugger to load the SP and PC, later in this article I will show you how to do it.

I wrote a simple program to do the RAM demo, it just flashes a LED at PB0:

 #define LED1 0x0001 // PB0
int main(void)
	volatile unsigned long i;
	GPIOB->CRL = 0x44444442;
		for (i=0; i<0x100000; i++);
	return 0;

To let the code loaded in RAM, we need to do some modifications with the project options.

First, In the Keil uVision IDE, select the project settings from Project →Options for Target ‘Target1’ :

The high-lighted area are the settings need to be modified. We change to IROM1 address to start from the RAM base address, and divide the whole RAM in 2 parts, half for code, and half for data.

Step 2, we go to the ‘Debug’ tab and make the following changes:

You probably have already noticed the RAM.ini file. What is this? This is the most important part in this project to make the RAM debugging successful. The Initialisation File is a command set for the debugger hardware, these commands are executed at the beginning of debug. Keil provided it with it’s MDK package, you can find it here:


The file is short and the code is straight forward, it basically just load the SP and PC from the start of the RAM and setup the vector table:

FUNC void Setup (void) {
	SP = _RDWORD(0x20000000); // Setup Stack Pointer
	PC = _RDWORD(0x20000004); // Setup Program Counter
	_WDWORD(0xE000ED08, 0x20000000); // Setup Vector Table Offset Register

load %L incremental

Setup(); // Setup for Running

g, main

Final step, to modify the programming algorithm. Hit the “settings” in the “Debug” tab, then select “Flash Download” tab.

First of all, select the “Do not Erase” option, as we are using RAM, then change the address range to the RAM area, otherwise you will be prompted a “no algorithm for address xxxxxxxxx” error when downloading the code. Finally, don’t forget to change the “RAM for Algorithm” to avoid overlaps with the code area.

Now we are all set to run our code in RAM! Make the project and then enter the debug widow, and hit ‘Run’. Yeah, the LED is flashing, our code is running in RAM! The BOOT0 and BOOT1 pins are actually not having effect on the running, you can have any settings on these 2 pins when debugging.

Some issues with the RAM debugging:

  1. Code and Data size are limited.

  2. If you reset the chip, you have to run the Setup() function in the debugger initialization file manually, otherwise the CPU will not get the correct SP and PC. To do so, in the command window, type “Setup()” in the command line and press ENTRE.