Why do most MCU code start by resetting peripherals? - Page 1
Forum section: electronics / general

author: Saimoun
author_rank: Frequent Contributor
timestamp: October 15, 2021, 05:32:26 am
content: HiLooking at examples of written startup code for MCU (for example the STM32 HAL lib), I see often that the first thing the code does, right in the ResetHandler interrupt, is resetting the peripheral it is about to configure.Is there any reasons for this other than "you never know"? Because if we are in the Reset interrupt routine, well the whole system has been reset so the peripheral should already be at reset state?ThanksPS: I am using an ARM Cortex M-23 (GD32E230), but I am asking this question generally for all MCU.

author: JPortici
author_rank: Super Contributor
timestamp: October 15, 2021, 09:40:04 am
content: "You never know" is a very good reason.Also don't know about your specific MCU but for many you have register that initialize at predefined value only at POR (and even then you better not trust it) but will not change at other resets

author: semir-t
author_rank: Regular Contributor
timestamp: October 15, 2021, 10:03:45 am
content: I would assume that when we reset the MCU through the external pin, there would be some internal circuit that would bring the MCU in some default/starting state. But what about when we initiate software reset through CPU instruction. So from my point of view it is better to do this stuff in the startup script then to leave it hanging.Note: I don't have any reference for the things that I have stated above, it is just my understanding and logic thing that I would do if i designed MCU

author: jpanhalt
author_rank: Super Contributor
timestamp: October 15, 2021, 10:32:21 am
content: Quote from: semir-t on October 15, 2021, 10:03:45 amSuch matters are described in the respective datasheets. Here is a sample from a Microchip PIC. It takes 11 pages:As for the logic, in Microchip PIC templates, the starting code is like this:;------------------------------------------------------------------------------; RESET VECTOR;------------------------------------------------------------------------------ORG 0x0000 ; processor reset vectorPAGESEL STARTGOTO START ; When using debug header, first inst.; may be passed over by ICD2.;------------------------------------------------------------------------------; INTERRUPT SERVICE ROUTINE;------------------------------------------------------------------------------ORG 0x0004;------------------------------------------------------------------------------; USER INTERRUPT SERVICE ROUTINE GOES HERE;------------------------------------------------------------------------------For that device , the reset and interrupt vectors are set, but you can start the code anywhere. In fact, I have seen code where the authors put all the set-up housekeeping at the end, then vector back to something after the interrupt vector for the meat. While that start-up code still runs first, it is not at the top.

author: tszaboo
author_rank: Super Contributor
timestamp: October 15, 2021, 10:40:28 am
content: Cause maybe your MCU is reset because of some irregular behavior. For example an ESD event can set the PC to a wrong address, and then it just starts executing code from 0x0000 without resetting the peripherals. Or brownout. Or a dozen different kind of issues.

author: Siwastaja
author_rank: Super Contributor
timestamp: October 15, 2021, 10:42:51 am
content: "Generic" driver, when written properly, has to assume that the peripheral might have been in use earlier, by said driver, or some other code. Resetting it to known state is very good idea, but is a small overhead (bloat) - almost always insignificant, but in some special cases causes trouble (e.g., initialization delay, code size).I always write my own peripheral drivers and I tend to have a general "grasp" about the future of my project so I can decide on case-by-case basis whether such deinit is needed or not. Usually no, so I just assume the datasheet reset values hold true. Performance isn't the only reason, also avoiding unnecessary code keeps project smaller, easier to read, understand and maintain, and finally, such "deinit" feature usually ends up untested so has high risk of having a hidden bug that manifests itself when this feature is actually needed the first time; so I'd rather implement thatwhen needed, not earlier.In all MCU families I know about, peripheral resets with device reset are completely reliable. If that fails due to ESD event or whatever, anything else can fail, too. We need stronger mitigations in high-reliability devices used in rough environment than just resetting a few registers "just in case".There are some catches, but these are special cases and should be mentioned in the manual. For example, some configuration of the CAN peripheral in the new ST devices is stored in a special RAM segment which is NOT cleared by the device reset and must be always manually set to known state. This is kinda obvious because it's called RAM, not configuration registers, and everybody "should" know RAM is not cleared automatically, but I could imagine you can still make a mistake here.

author: SiliconWizard
author_rank: Super Contributor
timestamp: October 15, 2021, 05:54:38 pm
content: Other that some of the things already said, I would suspect that quite a few MCUs out there have errata that prevent them from completely resetting all peripherals upon system reset. Or, even in the absence of silicon bugs, on some MCUs, it's possible that not ALL registers are reset to a known state upon system reset, except the "enable" bits, for instance.Can also be just out of habit. I've seen some startup code (although it's relatively rare) that also would reset all CPU registers explicitely. Although useless per se, it may help with debugging, or something.But do not think every line of third-party code you may deal with is useful. If that was the case, "bloat" would be much less of a problem in general.

author: Siwastaja
author_rank: Super Contributor
timestamp: October 15, 2021, 06:06:48 pm
content: I would think the opposite is more likely, namely the special reset functionality not working.Power on reset / soft reset are pretty darn reliable because they get tested directly or indirectly in every possible project. If some peripheral does not reset properly on device reset, the design team will see that immediately (by noticing the difference in behavior between first run after power-on, and second run after soft reset).OTOH a hidden design bug in a special "reset this peripheral" command register is a real possibility.Even a "manual" peripheral reset by writing each and every peripheral register is prone to fail because peripherals tend to have quite weird (sometimes useful) locking mechanisms where some registers (or parts of them) are inaccessible and writes fail silently unless done with some specific trickery (which can be buggy, again).I have seen neither. POR, soft reset and dedicated peripheral resets have always worked as they should, despite all the other numerous documented and undocumented bugs especially in ST's contraptions. But you have to trustsomething, and if you can't trust reset, there's not much you can do with the MCU at all.

author: SiliconWizard
author_rank: Super Contributor
timestamp: October 15, 2021, 06:46:12 pm
content: And with all that said, the OP probably needs to be more specific and give examples.In startup code provided by ST for STM32 MCUs I have used, the Reset_Handler routine typically, after setting up the stack and dealing with data and bss segments, will eventually calls the SystemInit() function (and then call main). This function will typically: configure the FPU, reset registers relative to clocks (for a reason I don't know, as those are indeed reset values) and not just all peripherals, and then disable interrupts and setup the vector table.So can the OP show us example code provided by ST which would reset peripherals other than clocks?The second point I do not understand from the OP's statement is this: "in the ResetHandler interrupt, is resetting the peripheralit is about to configure."Except for what I mentioned above, no peripheral is configured by the ResetHandler. But there may be some information missing here. Or a misunderstanding of what the "ResetHandler" is.Then they are talking about STM32's HAL and says they are using a GD32E230, which comes with completely different vendor code?

author: mikeselectricstuff
author_rank: Super Contributor
timestamp: October 15, 2021, 07:02:48 pm
content: Example :Develop application, assume peripherals are in their reset state, everything works.Then add a bootloader so code can be updated. Bootloader sets up the UART, updates firmware, then jumps to the code's reset vector to restart.Suddenly the assumption the application made about the state of the peripherals is no longer valid.Some MCUs have an explicit "reset" instruction, or can do it via the watchdog, but not all.It should be a reasonable assumption that jumping to the reset vector should be the same as a power-up reset, so explicitly initialising all registers ( and RAM) is a wise precaution.If you then add the use of libraries, these libraries have no way of knowing what might have happened before they were called, so they should initialise everything.Assuming reset values is OK in situations where you are absolutely sure the only startup mechanism is a real reset.When looking at things like startup code in manufacturer-supplied libraries, bear in mind that these may include stuff that isn't necessarily needed for your particular device, but may be in others, or may contain artifacts from earlier versions.

author: PCB.Wiz
author_rank: Super Contributor
timestamp: October 15, 2021, 07:22:34 pm
content: Quote from: simonlasnier on October 15, 2021, 05:32:26 amNote some MCUs have software resets, that are not always as complete as HW resets.You can also enter the reset-inits vector from something like a bootloader, and I have a MCU chip on my bench right now, that exits the inbuilt bootloader with wrong init values...So I had to add a line in INIT code to clear the register, that 'should have been' at 0x00 .

author: T3sl4co1l
author_rank: Super Contributor
timestamp: October 15, 2021, 08:59:39 pm
content: Seconded, belts-and-suspenders. STM32 HAL takes up its hulking 10-100kB for one reason and one reason only: ease of use.The most obvious case where this would apply, is where something causes a jump to the reset vector -- a soft reset, without triggering the hardware reset signal that actually flops all the flip-flops in the chip. It's not obvious when or why someone would do this, but maybe it's a simple enough solution to a program always crashing: instead of dumping to the default hardware error handler (a spin loop), just go back to start and hope it goes better the next time (ha).Or given how often callbacks are used in the HAL, and maybe in user code as well -- if one happens to be NULLed by accident or otherwise, which adventure are we going on? Maybe not much of an adventure after all.You can certainly get away without complete inits in self-contained projects, but also the more stuff you pull in from other places (libraries, other authors, copy-paste..), the less well understood the project is as a whole, and the more potential value there is in using, what would otherwise be, redundant operations like this.Could also do kinda the flip side, assert register values from time to time -- scan swaths of memory, comparing against images in ROM, looking for inconsistencies. This could also maybe be defensive against fuzzing attacks, power glitching attacks, etc. Though a lot of those specifically target program execution, or private (stack) variables; and, measuring and auditing program state, in a potentially virtual environment (i.e., interrogating C's abstract machine, from within itself, without being hardware-dependent -- good luck with that?), isn't going to be straightforward. Ah, but I digress; I'm far from an expert on computer security, this is just idle pondering.Tim

author: ejeffrey
author_rank: Super Contributor
timestamp: October 15, 2021, 09:20:12 pm
content: Quote from: mikeselectricstuff on October 15, 2021, 07:02:48 pmCode worked fine, but I wanted to use it with a bootloader and it failed.Specifically the problem was in the clock configuration. Even though the code looked like it would correctly set all the registers, it did so in the wrong order causing an illegal intermediate state -- I don't remember if it was switching to a disabled clock or running an invalid multiplier that was overclocked or what. This caused the MCU to crash before it could complete the clock configuration. The fix was to first return the clock to the default source and speed before transitioning to the desired mode.

author: abyrvalg
author_rank: Frequent Contributor
timestamp: October 15, 2021, 11:34:14 pm
content: Jumping back to Reset_Handler purely in sw is not so obvious on Cortex-M (you either need to use the “Reset_Handler” name as a code ptr or extract the ptr from vector table). Dereferencing a NULL code ptr wouldn’t lead there (will lead to a fault instead). For a HAL user it would be more logical just to call some dedicated HAL reset function (which usually sets SCB.AIRCR.SYSRESETREQ that resets both the core and peripherals).

author: ataradov
author_rank: Super Contributor
timestamp: October 15, 2021, 11:49:17 pm
content: Quote from: ejeffrey on October 15, 2021, 09:20:12 pmThat's why I always exit the bootloader by setting a flag that it needs to run the application and resetting the MCU. Bootloader runs again, checks the flag, jumps to the application without initializing any peripherals.Anything else would fail sooner or later.Software resets are for the case when the initialization function may be called multiple times, to configure different modes, for example.

author: David Hess
author_rank: Super Contributor
timestamp: October 16, 2021, 09:24:32 pm
content: Quote from: semir-t on October 15, 2021, 10:03:45 amYou can probably count on a hardware reset also resetting microcontroller peripherals but in the past it was more common to have separate peripherals which may or may not be tied to the CPU reset signal, and that will still be the case today sometimes. The safe bet by default is to reset the peripheral before initialization unless you have specific reason not to, like needing to maintain the previous state.

author: Saimoun
author_rank: Frequent Contributor
timestamp: October 17, 2021, 12:34:31 pm
content: Hi! I'm the OP. Thank you all very much for your insights, very interesting to hear!!Quote from: Siwastaja on October 15, 2021, 06:06:48 pmI fully agree and actually this is the model I have been running so far, always assuming that I could trust the reset values, and I have had zero issues with this so far. It made sense for my project which is a relatively small project where I have 100% control (i.e. no libraries and no external people). But I keep seeing these resets in code examples (in particular in the reset handler which really triggered me - see exactly what right below), hence my question.Quote from: SiliconWizard on October 15, 2021, 06:46:12 pmYou wrote "reset registers relative to clocks (for a reason I don't know, as those are indeed reset values)" (in bold italic in the quote) - that's it ha haThat's the one I saw in the Reset Handler which I did not understand either.Apart from that I have seen it a couple of times in other code and libraries, but that part has been answered by many here (the answer is basically ease of use and because you do not know when the library will be executed).On the other side I completely understand the idea that for sure when you "assume" anything in hardware coding you better be darn sure you have not forgotten anything, and that gets much, much more complicated as the size of the project goes. So yes Tim/T3sl4co1l, very good point I agreeQuote from: T3sl4co1l on October 15, 2021, 08:59:39 pmAnd as for ejeffrey and mikeselectricstuff who mentioned the Bootloader - yes I would always restart the whole thing (call a full software Reset, or even using the external NRST pin) after finishing a Bootloader.And just to throw my own opinion, I personally also find a good middle ground by writing:Code:PERIPH->REG = PERIPH_REG_RESET VALUE | myValue;instead ofCode:PERIPH->REG |= myValue;when I know the peripheral should be in reset, in most cases it will produce even smaller binary code and if for whatever reasons the peripheral is not at reset then it will still work.

author: Siwastaja
author_rank: Super Contributor
timestamp: October 17, 2021, 12:37:12 pm
content: Quote from: simonlasnier on October 17, 2021, 12:34:31 pmJust keep doing what you do, it's perfectly OK since you understand what you are doing and are not writing generic libraries for others.

author: free_electron
author_rank: Super Contributor
timestamp: October 17, 2021, 05:02:39 pm
content: silicon fixes ...some startup routines contain code to fix silicon issues.for many arm processors there is a hidden start block that gets compiled in 'front' of your code and runs before anything else. It fixes hardware issues

author: SiliconWizard
author_rank: Super Contributor
timestamp: October 17, 2021, 05:15:52 pm
content: Quote from: simonlasnier on October 17, 2021, 12:34:31 pmYeah. That's where comments would actually be welcome. Could be because of some silicon issue on some parts, or because they are assuming the "reset handler" could be called from other contexts than hardware resets... dunno. Again do not necessarily assume it is useful in your case just because some vendor's engineers wrote this either.First thing to do would be to read the errata doc for the part you're using.If you don't see anything related to this in it - you can probably safely assume clocks start with their default config upon reset.

author: Siwastaja
author_rank: Super Contributor
timestamp: October 17, 2021, 05:19:18 pm
content: Quote from: free_electron on October 17, 2021, 05:02:39 pmNever seen one. Any example?

author: free_electron
author_rank: Super Contributor
timestamp: October 18, 2021, 05:36:34 pm
content: Quote from: Siwastaja on October 17, 2021, 05:19:18 pmin some of them it is added to the binary , in some it is part of the bootrom in a sealed off block. During firmware load this can be updated with latest fixes. Certain STM32 7xx series have it. Same for Arm-7 or Arm9. Raspberry pi has it too. runs before anything else.This is common these days.

author: Siwastaja
author_rank: Super Contributor
timestamp: October 18, 2021, 06:15:35 pm
content: I have worked extensively with STM32F7 and H7 series and definitely nothing like this is compiled or linked in. These come with errata notes and working around with broken peripherals is left to the user (obviously, their library code implements said workarounds, too).The CPU of course can execute some code that resides in the factory rom section (similar to the factory bootloader which cannot be erased), this would be invisible to the user, so I don't know about that.

author: semir-t
author_rank: Regular Contributor
timestamp: October 19, 2021, 06:38:49 am
content: I also never saw this in the binary for the STM32 boards, and if something like this is part of the binary file it should be visible in the source code. I would like to read about this more if someone has docs to share.

author: ataradov
author_rank: Super Contributor
timestamp: October 19, 2021, 03:29:14 pm
content: I've only seen pre-boot patches on some obscure parts from Infineon. I don't think any common MCUs do anything like this.MPUs might, I don't know. But also, what would MPUs patch? They don't have any internal code.

author: mac.6
author_rank: Regular Contributor
timestamp: December 15, 2021, 03:37:04 pm
content: Mostly bootrom patches, pretty common (in fuses or IFR)