2

I have two ARM Cortex-M3 chips: STMF103C8T6 and STM32F103VET6.

When set to boot from RAM, initial state of STMF103C8T6 PC register is 0x20000108; 0x200001e0 for STM32F103VET6.

I am unable to find and information about these addresses in the datasheets. Why are they booted this way and where I can find some information about it?

Edit:

To clarify. When chip set to boot from flash, PC register points to the location of the Reset Handler. This address is provided in the reset vector table at address 0x0. But when chip set to boot from RAM, PC points to constant addresses, mentioned above.

Edit 2:

STMF103C8T6 disassembly:

20000000 <Vectors>:
20000000:       20005000        andcs   r5, r0, r0
20000004:       2000010f        andcs   r0, r0, pc, lsl #2
20000008:       2000010d        andcs   r0, r0, sp, lsl #2
2000000c:       2000010d        andcs   r0, r0, sp, lsl #2
20000010:       2000010d        andcs   r0, r0, sp, lsl #2
20000014:       2000010d        andcs   r0, r0, sp, lsl #2
20000018:       2000010d        andcs   r0, r0, sp, lsl #2
    ...
20000108:       f000 b801       b.w     2000010e <Reset_Handler>

2000010c <HardFault_Handler>:
2000010c:       e7fe            b.n     2000010c <HardFault_Handler>

2000010e <Reset_Handler>:
    ...

STM32F103VET6 disassembly:

20000000 <Vectors>:
20000000:       20005000        andcs   r5, r0, r0
20000004:       200001e7        andcs   r0, r0, r7, ror #3
20000008:       200001e5        andcs   r0, r0, r5, ror #3
2000000c:       200001e5        andcs   r0, r0, r5, ror #3
20000010:       200001e5        andcs   r0, r0, r5, ror #3
20000014:       200001e5        andcs   r0, r0, r5, ror #3
20000018:       200001e5        andcs   r0, r0, r5, ror #3
    ...
200001e0:       f000 b801       b.w     200001e6 <Reset_Handler>

200001e4 <HardFault_Handler>:
200001e4:       e7fe            b.n     200001e4 <HardFault_Handler>

200001e6 <Reset_Handler>:
    ...
artless noise
  • 21,212
  • 6
  • 68
  • 105
Sergey
  • 1,166
  • 14
  • 27
  • 1
    What do you mean by "set to boot from RAM"? What are tool are you using and what option are you setting? – kkrambo Jun 22 '18 at 13:47
  • 1
    The offset from 0x20000000 may be equal to the size of the interrupt vector table. Do the two chips have a different number of interrupt sources? – kkrambo Jun 22 '18 at 13:51
  • @kkrambo STM32F1 chips use boot pins to control memory aliasing upon boot. I pull these pins to GND to alias 0x0 to FLASH, to Vcc to alias 0x0 to RAM. Reset Handler address is always located at 0x4 and supposed to be loaded to `PC` upon reboot. Why instead of doing this, CPU jumps to the end of reset vector? – Sergey Jun 22 '18 at 14:30
  • 2
    [This thread](https://community.st.com/thread/44601-boot-from-sram) has some information. – kkrambo Jun 22 '18 at 15:08
  • @kkrambo Thanks! That is exactly what I was looking for. Quick summary: this behavior is related to internal buses and those addresses are probably board specific. – Sergey Jun 22 '18 at 16:22
  • I dont see those addresses in the documentation, but it is likely the tools put the reset entry after the vector table for a complete table. some of the parts 0x12C is the last offset so a 0x20000131 would be a possible address at offset 4 in the table. But you of course dont have to support all the interrupt vectors if you are not using them and could put the reset handler somewhere else. – old_timer Jun 23 '18 at 04:24
  • The handler address orred with one is located in the table, the lsbit is checked and stripped then the remaining address is "loaded into the pc" for fetching that handler. – old_timer Jun 23 '18 at 04:26
  • can you show a disassembly of your code? the first few items at 0x20000000 and the reset handler plus and minus a few words? – old_timer Jun 23 '18 at 04:27
  • @old_timer I've added disassembly for two chips. – Sergey Jun 23 '18 at 08:05
  • so that looks fine, what part dont you understand? The st data sheet indicates cortex-m3 so you go to arms website to get the cortex-m3 technical reference manual which says it is armv7-m architecture based and at arms site get the armv7-m architectural reference manual which contains information about the vector table, first word stack pointer if desired, 0x4 offset is reset pointer orred with one because thats how they chose to do it, thumb like. up through the core exceptions, the chip vendor interrupts start after that and can be very many... – old_timer Jun 23 '18 at 19:50
  • the vendor determines what the ahb/amba bus connects to (flash or ram) and at what addresses (within arms rules). the boot0/boot1 pin strapping which is st based determines what is mapped in, we assume on boot, but perhaps there is some code that runs from something burned in the chip...who knows...either way if we select ram then if this is how it is build and if it works then it is no different than flash vector offset 0x0 is stack pointer init, offset 0x4 is reset handler address orred with one. – old_timer Jun 23 '18 at 19:53
  • Is that wast you were confused about or is it beyond that basic information? – old_timer Jun 23 '18 at 19:53
  • @old_timer What is confusing is that chips do not have the same booting process when booted from Flash and RAM. In Flash mode CPU loads address from `0x4` just like you explained. But in RAM mode CPU jumps to predetermined, and not mentioned in the manual, address after the vector table (you can see jumps in the disassemblies above). Even if I put some garbage in `0x4`, it would run just fine in RAM mode. – Sergey Jun 23 '18 at 20:18
  • st application flash is at 0x08000000 so if programming this for flash you would be at say 0x08000103, the processor is not capable of knowing what kind of memory is attached, it fetches address 0x4, the vendor either routes that to address 0x08000004 or 0x20000004 where it finds an address to load into the program counter for fetching the first instruction of the handler so say 0x0800010f it strips the lsbit and fetches the first instruction at 0x0800010e for a flash based boot, for ram it reads 0x04 which the chip maps to 0x20000004 where it finds 0x2000010f,... – old_timer Jun 23 '18 at 20:38
  • checks and strips the lsbit fetching the first instruction of the handler at 0x2000010e, exactly the same process. – old_timer Jun 23 '18 at 20:38
  • the address 0x000 mapping is limited in size, you can in both cases have the vector be 0x0000010f but the mirroring from 0x00000000 to 0x08000000 or 0x20000000 is limited relative to those actual address spaces, thus it is desireable to link for the actual space (0x0800010F or 0x2000010f) so that it only uses the mirror to get the vector then uses the actual address when it uses that vector. – old_timer Jun 23 '18 at 20:40

1 Answers1

5

I am unable to find and information about these addresses in the datasheets. Why are they booted this way and where I can find some information about it?

As far as I am aware, there is no official documentation from ST that so much as mentions this behavior, let alone explains it in any detail. The STM32F1 family reference manual states vaguely in section 3.4 ("Boot Configuration") that:

Due to its fixed memory map, the code area starts from address 0x0000 0000 (accessed through the ICode/DCode buses) while the data area (SRAM) starts from address 0x2000 0000 (accessed through the system bus). The Cortex®-M3 CPU always fetches the reset vector on the ICode bus, which implies to have the boot space available only in the code area (typically, Flash memory). STM32F10xxx microcontrollers implement a special mechanism to be able to boot also from SRAM and not only from main Flash memory and System memory.

The only place these addresses and values are referenced at all is in some of their template startup files -- and even then, not all of them. The SPL startup files supplied for the ARM and IAR toolchains lack support for BootRAM; this functionality is only included in the startup files for the GCC and TrueSTUDIO toolchains.

Anyways. Here's my best analysis of the situation.

When a STM32F1 part is reset, the memory block starting at 0x00000000 is mapped based on the configuration of the BOOT pins. When it is set to boot from flash, that block is aliased to flash; when it is set to run from the bootloader, that block is aliased to a block of internal ROM (around or slightly below 0x1FFFF000). However, when it is set to boot from RAM, something very strange happens.

Instead of aliasing that memory block to SRAM, as you would expect, that memory block is aliased to a tiny (16 byte!) ROM. On a STM32F103C8 (medium density) part, this ROM has the contents:

20005000 20000109 20000004 20000004

This data is interpreted as a vector table:

  • The first word causes the stack pointer to be initialized to 0x20005000, which is at the top of RAM.

  • The second word is the reset vector, and is set to 0x20000108 (with the low bit set to enable Thumb mode). This address is in RAM as well, a few words beyond the end of the vector table, and it's where you're supposed to put the "magic" value 0xF108F85F. This is actually the instruction ldr.w pc, [pc, #-480], which loads the real reset vector from RAM and branches to it.

  • The third and fourth words are the NMI and hardfault vectors. They do not have the low bit set, so the processor will double-fault if either of these exceptions occurs while VTOR is still zero. Confusingly, the PC will be left pointing to the vector table in RAM.

The exact contents of this ROM vary slightly from part to part. For example, a F107 (connectivity line) has the ROM contents:

20005000 200001e1 20000004 20000004

which has the same initial SP, but a different initial PC. This is because this part has a larger vector table, and the medium-density address would be inside its vector table.

A full list of the locations and values used is:

  • Low/medium density: 0x0108 (value: 0xF108F85F)
  • Low/medium density value line: 0x01CC (value: 0xF1CCF85F)
    Note: ST's sample files give the same value as for low/medium density parts. I'm pretty sure this is wrong and have corrected it here, but I don't have any parts of this type to test with. I'd appreciate feedback to confirm if this works.
  • All others: 0x01E0 (value: 0xF1E0F85F)

Thankfully, this behavior seems to be largely unique to the F103/5/7 family. Newer parts use different methods to control booting which are much more consistent.

Michael Slade
  • 13,802
  • 2
  • 39
  • 44
  • It checks out. For `0x108` device actual command is `ldr.w pc, [pc, #-264]`; for `0x1e0` device it is `ldr.w pc, [pc, #-480]`. I've checked both magic numbers, chips do work. I don't have `0x01CC` device, but I think it's safe to assume, that it will work also. Command for it is `ldr.w pc, [pc, #-460]`. – Sergey Jun 25 '18 at 20:43
  • So does this imply if not simply state that the bootloader sampling the boot pins branches to this address, if you happen to have the magic instruction it happens to mimic a "reset"? Meaning you could just have your entry point there for this mode. Or do we know that the magic value has to be there for this to work at all, it wont execute from ram if not found? – old_timer Jun 27 '18 at 14:42
  • @old_timer No. The bootloader is not involved here -- the state of the BOOT pins controls what memory is mapped at 0x0, which affects its behavior on reset. I haven't tested the SRAM boot behavior with a different "magic instruction", but I'll try that in a bit and update my answer with results. –  Jun 27 '18 at 19:48
  • one point being it is unlikely this is really done in logic, I think I have one of these parts at least and want to try this as well – old_timer Jun 27 '18 at 20:37
  • @old_timer STM32F1 reference manual, §3.4: "The values on the BOOT pins are latched on the 4th rising edge of SYSCLK after a reset." That seems too early to be possible for code -- it'd take more than 4 clocks to enable a GPIO and read the pin values. –  Jun 27 '18 at 23:28
  • could easily latch the straps in a few clocks and have them available for an indefinite period of time. silicon folks prefer to pass the buck to software for certain tasks can change what is burned into rom/flash in production far easier than a chip spin but... – old_timer Jun 28 '18 at 07:29
  • the blue pill STMF103C8T6 shows 20005000 20000109 20000004 20000004 and hangs on the read to 0x00000010. The magic instruction is not required, filled the beginning of sram with enough bl reset instructions to cover 0x20000108, and later isolated 108. so it does look like they simply mapped in the 32 byte rom or flash or fused or hardcoded logic. Very strange why they didnt just make it 0x20000005 instead of 0x20000109. – old_timer Jun 28 '18 at 07:33
  • Outside software development pondering what boot from sram use cases are anyway (and no surprise that a number of parts dont have a boot1 pin, smaller ones naturally). – old_timer Jun 28 '18 at 07:55
  • It's a common technique to have certain vectors point to an instruction that jumps to itself. That way you can tell when a certain kind of exception occurred because from your debugger you can see it executing that instruction. Here when IP = 0x20000004 you can deduce that a fault occurred, just not which type. – Michael Slade Feb 12 '19 at 19:40