2
\$\begingroup\$

I have a system with an STM32F103, which has a bootloader and a main app. Now, the main app is offset from the beginning of the flash to make room for the bootloader, and on cold boot the firmware is entered through the bootloaders reset handler. Then the bootloader does it's thing and eventually starts the main app by calling an entry point defined in the app image. The main app then relocates the vector table via the vector table offset register SCB_VTOR to set up its own interrupts, and everything proceeds from there.

In this case, the main apps reset handler is never called. Further, according to page 35 of the Cortex M3 programming manual, on any reset (cold or soft) VTOR is reset to 0, i.e. it'll point to the bootloaders vector table.

My question: am I right in thinking that the main apps reset handler vector is never called (unless I call it directly myself), i.e. I can just leave it unimplemented/make it assert etc? Or is there maybe some peculiar reset circumstance where the reset handler in the offset vector table might be called?

The motivation for the question is that if I write some "just-in-case" reset handler, I'd certainly like to test it. However, if

  1. the handler is never called during reset, I can't test it (under real conditions, i.e. whatever state the MCU is in when the reset happens. I could of course call it directly, but that isn't quite the same)
  2. if there are circumstances where the handler may be called during reset, then I need to know what those circumstances are, so I can test my handler.
\$\endgroup\$
  • 1
    \$\begingroup\$ That's up to your bootloader, if you branch to the main app's reset handler then it is run, if you branch to somewhere else in the main app it isn't. It is probably from the main app's reset handler that bss is cleared and statics are initialised and constructed so it's a sensible thing to run, unless you know you're ready for main(). \$\endgroup\$ – Colin Mar 11 at 11:02
  • \$\begingroup\$ @Colin of course, if I call the handler from the bootloader, the handler gets called. However, instead of that, my FW image defines an entry point, which gets called (and all initialization etc happens via that entry point). See edit for motivation. \$\endgroup\$ – Timo Mar 11 at 12:21
  • \$\begingroup\$ An advantage of entering you main app via the reset handler in its complete vector table is that you can just use the chips vector table layout as your bootloader to app handoff API definition. And you can run the main app without the bootloader for debugging, either by re-linking or just by copying its vector table to the start of flash - the relocation it does with its own offset copy is then unnecessary but still perfectly workable. \$\endgroup\$ – Chris Stratton Mar 11 at 21:28
  • \$\begingroup\$ @ChrisStratton that's right, and I did have the setup you describe previously. The main motivation for changing the handoff API is that I needed to pass a parameter to the main app, and having a reset handler which expects a parameter is a bit of a hack. Debugging actually works fine at least with GCC/Eclipse/OpenOCD, I just put the debug entrypoint to be that of the bootloader, and when debugging the main app the boot goes through the bootloader and after that everything works normally (when the bootloader has been flashed once). \$\endgroup\$ – Timo Mar 12 at 8:22
1
\$\begingroup\$

VTOR is reset by the main core reset. All types of hardware reset in M3 will toggle this, including a write to AIRCR.SYSRESETREQ.

This will apply to all implementations of M3.

Nothing prevents your software from using the relocated vector address, but it should be unreachable from the core boot process (similarly, the relocated initial stack pointer is never interesting to the core).

Implementation specific memory banking/aliasing can obviously affect this, but that would apply regardless of VTOR.

\$\endgroup\$
2
\$\begingroup\$

From my reading of ST's Reference Manual RM008 (which I think is the reference manual for your chip -- I'm looking at Rev. 20, dated Decemeber 2018), it appears that:

  • There are 3 kinds of reset (these are listed in Section 7.1 or 8.1, depending on your specific chip (Connectivity line or any other line)): (1) System Reset, (2) Power Reset, and (3) Backup Domain reset. The sections in the manual talk about what constitutes a system reset and what constitutes a power reset.
  • For (1) System Reset the manual explicitly states "A system reset sets all registers to their reset values except the reset flags in the clock controller CSR register and the registers in the Backup domain". This would include VTOR.
  • For (2) Power Reset: "A power reset sets all registers to their reset values except the Backup domain". This would include VTOR.
  • For the section on Backup Domain resets, I didn't see any language about registers being reset.

I haven't used the STM32 Backup Domain functionality, but that might be a way that you can "reset" and not reset VTOR.

If you have a contact (e.g. FAE) at ST, I'd ask him/her that question. And maybe if you get a definitive answer, you can come back and amend this answer (or post your own).

\$\endgroup\$
1
\$\begingroup\$

Difficult to understand your question.

Yes, VTOR resets to zeros. So the offset is zeros. the cortex-m looks for the stack pointer at 0x00000000 and then the reset handler at 0x00000004 and this will happen on that device. Note there is or are boot pins on stm32 devices that determine what is mapped to address zero, the on chip bootloader or your firmware. Assuming you have that or those pins set correct at power on/reset then your applications reset handler address will be read from address 0x00000004 and the logic will execute from that address (well if the logic finds 0xFFs it will go to the bootloader not the application since there is no application).

The reset handler can technically point to main() but you wont have zeroed .bss nor initialized .data, technically it will work fine so long as you have filled in the handler correctly (lsbit of addresses must be set, let the tools do this dont force it). Can you do a dump of your vector table as built by the toolchain? What you are loading into the device?

Without a reset handler you cannot run your firmware so clearly you have or have to have one. Once you are into that code you are free to change the VTOR if that device supports it (not all cortex-ms do). to move the vector table elsewhere for whatever reason you think you need to do that. But that vector table will be used for the non-reset handlers. When a reset happens again it goes back to a VTOR of 0x00000000.

\$\endgroup\$
0
\$\begingroup\$

Is there any particular reason why you don't want to implement Reset handler in main application? Just point it to the main() in you application and you are safe.

Do you have new vector table created by compiler by default? Why don't you want relocate vector table in bootloader routine?

Several years ago I made implementation of something similar to your case. On STM32F429ZI I had small custom startup code flashed in ROM, and main code was placed in RAM every time on power on. Startup code actually does nothing (initialize AHB1ENR and blinked led two times, then relocate vector table by itself via setting VTOR to the beginning of RAM and load SP with initial value from this address, then put Reset handler value from new vector table to PC).

The only difference for RAM main application was correction of sections .isr_vector, .text and so on to the ">RAM" value in ldscript file and nothing more. Everything else including new vector table were created by compiler itself. In your case it can be even easier as you should change only FLASH ORIGIN to new address where you want to place your application.

I had many soft and cold resets and always program started with blinking from ROM startup code (as it is written in manual that you have cited).

\$\endgroup\$
  • \$\begingroup\$ No particular reason not to implement it, except that: if the handler might ever be called, I need to test whatever I put there, so I need to know how to get it called. OTOH, if it's never called, I can't obviously test it. So I feel uncomfortable in leaving an untested "just in case" implementation there. \$\endgroup\$ – Timo Mar 11 at 12:11
  • \$\begingroup\$ The vector table is indeed created by the compiler, and as far I understand, it doesn't really matter whether VTOR is set by the bootloader or the app itself, except that if the app sets it, then I don't need to update the bootloader if the main app vector table address changes. \$\endgroup\$ – Timo Mar 11 at 12:13
  • \$\begingroup\$ @Timo Yes, that's true, it doesn't really matters where you update VTOR. But I meant that if you have VTOR table relocation on startup implemented in you bootloader (or whatever code executed before main), than you can forget about addresses, VTORs and vector tables in your main application. You can recompile any code without any modification to it, just use a slightly (one line, literally) modified ldscript file and nothing more. And if you need to relocate vector table again in your main application, just go ahead - do it as before. \$\endgroup\$ – cyclone125 Mar 11 at 12:20
  • \$\begingroup\$ I'm not quite sure if I understand what you're getting at here, but let me clarify just in case: the bootloader is a separate app, compiled separately, which is flashed exactly once in production, whereas the main app may be updated by the bootloader (from a binary image transmitted via i.e. the serial port) at a later time. So the bootloader never gets recompiled. \$\endgroup\$ – Timo Mar 11 at 12:27
  • \$\begingroup\$ @Timo So, I don't see any problems here concerning my words. :) You have app (binary file) which is uploaded later. How your bootloader would give control to app? Let's say your app will always start always from the same address in Flash (where it will be uploaded). This is typically for bootloaders to give control to some specific predefined address at the time of bootloader compilation. If you implement "load SP register from the first address pointer of uploaded binary" and load PC from the second address pointer" (e.g. jump to this address), then you shouldn't worry about any vector tables \$\endgroup\$ – cyclone125 Mar 11 at 12:34

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.