1

In external interrupt function, I want to reset by calling main function. But afterwards, if I have a new interrupt trigger, MCU thinks that It's handling in interrupt function and It doesn't call interrupt function again. What is my solution? (in my project, I'm not allowed to call soft Reset function)

  • 2
    If you call the `main` function you don't really do a reset at all - you just call one of the functions. In fact, `main` isn't even the first function that's normally called after power up or reset. The real question is - if you want to do a reset, why can't you call a reset function? That's technically the proper way to do the reset. – J_S Jun 24 '17 at 08:14
  • 2
    "not allowed..." ? What kind of irrational ill-informed constraint is that. There are possibly genuine reasons why you might not want to,such as the need to maintain GPIO state and not let outputs float, but "not allowed" is not a sound argument. – Clifford Jun 24 '17 at 13:20
  • @Clifford I am working with USB peripheral. This doesn't allow to reset the system. (I use "allow", It may be wrong or confused because my english not sound good) – Mạnh Hùng Jun 26 '17 at 01:36

3 Answers3

4

Calling main() in any event is a bad idea, calling it from an interrupt handler is a really bad idea as you have discovered.

What you really need is to modify the stack and link-register so that when the interrupt context exits,, it "returns" to main(), rather than from whence it came. That is a non-trivial task, probably requiring some assembler code or compiler intrinsics.

You have to realise that the hardware will not have been restored to its reset state; you will probably need at least to disable all interrupts to prevent them occurring while the system is re-initialising.

Moreover the standard library will not be reinitialised if you jump to main(); rather than the reset vector. In particular, any currently allocated dynamic memory will instantly leak away and become unusable. In fact all of the C run-time environment initialisation will be skipped - leaving amongst for example static and global data in its last state rather than applying correct initialisation.

In short it is dangerous, error-prone, target specific, and fundamentally poor practice. Most of what you would have to do to make it work is already done in the start-up code that is executed before main() is called, so it would be far simpler to invoke that. The difference between that and forcing a true reset (via the watchdog or AICR) is that the on-chip peripheral state remains untouched (apart from any initialisation explicitly done in the start-up). In my experience, if you are using a more complex peripheral such as USB, safely restarting the system without a true reset is difficult to achieve safely (or at least it is difficult to determine how to do it safely) and hardly worth the effort.

Clifford
  • 88,407
  • 13
  • 85
  • 165
  • A `longjmp` will get you back to `main` easily enough on ARM (please mask any higher-priority interrupts first though). The real issue, as you have noted, is to reliably reset the state of the system both in regards to peripheral devices and sub-modules and best avoided if at all possible. Occasionally you do require a _partial_ system reset and things get messy but even then blindly unwinding all the way back to `main` unlikely to be the answer. – doynax Jun 24 '17 at 13:37
  • 1
    @doynax : `longjmp()` will restore the stack context, but won't I think get you out of the interrupt context, and you would end up with the (probable non-terminating) `main()` function essentially running as an _interrupt handler_ which is exactly the problem in question. It solves only the problem of reentering `main()`, it does not solve the problem of exiting the interrupt context. – Clifford Jun 24 '17 at 15:29
  • @Clifford - you are 100% right. This is an example of the extremely bad programming. Instead of having the correct program logic, someone tries to implement a prosthesis. This clearly shows that the programmer has to improve his coding skills. – 0___________ Jun 24 '17 at 17:47
2

Reset by calling main() is wrong. There is code in front of main inserted by the linker and C-runtime that you will skip by such soft-reset.

Instead, call NVIC_SystemReset() or enable the IWDG and while(1){} to reset.
The HAL should have example files for the watchdog timer.

SRAM is maintained. Any value not initialized by the linker script will still be there.

Jeroen3
  • 919
  • 5
  • 20
2

Calling Main() from any point of your code is a wrong idea if you are not resetting the stack and setting the initial values.

There is always a initialization function ( that actually calls Main()) which is inside an interrupt vector, usually this function can be triggered by calling the function NVIC_SystemReset(void) , be sure than you enable this interrupt so it can be software triggered.

As far as I know, when get inside and interrupt code, other interruptions are inhibit, I am thinking on two different options:

  • Enable the interruptions inside the interruption and call the function NVIC_SystemReset(void)
  • Modify the stack and push the direction of the function NVIC_SystemReset(void) so when you go out of the interruption it could be executed.
adrianzx
  • 21
  • 2