Skip to main content
added 409 characters in body
Source Link
Thorn
  • 2.2k
  • 14
  • 16

There are two points to be made here:

  • An embedded program, strictly speaking, cannot "finish".
  • There is very rarely a need to run an embedded program for some time and then "finish".

The concept of a program shutdown doesn't normally exist in an embedded environment. At a low level a CPU will execute instructions while it can; there is no such thing as a "final return statement". A CPU may stop execution if it encounters an unrecoverable fault or if explicitly halted (put into a sleep mode, a low power mode, etc), but note that even sleep modes or unrecoverable faults do not generally guarantee that no more code is going to be executed. You can wakeup from sleep modes (that's how they're normally used), and even a locked up CPU can still execute a NMI handler (this is the case for Cortex-M). A watchdog will still run, too, and you may not be able to disable it on some microcontrollers once it's enabled. The details vary greatly between architectures. You will need to read relevant manuals really carefully if you want to ensure certain behavior (see below why you shouldn't attempt to do that anyway).

In case of firmware written in a language such as C or C++, what happens if main() exits is determined by the startup code. For example, here is the relevant part of the startup code from the STM32 Standard Peripheral Library (for a GNU toolchain, comments are mine):

Reset_Handler:  
  /*  ...  */
  bl  main    ; call main()
  bx , lr points to next instruction
  ;bx return (branchlr to the address stored in the; linkinfinite register)loop

NowThis code will enter an infinite loop when main() returns, as specifiedalthough in the ARMv7a non-M ARM A2.3.1,obvious way (bl main loads lr with the link register is set to 0xFFFFFFFF on reset, and a branch to that address will trigger a fault. Soof the STM32 SPL clearly treatsnext instruction which is effectively a return from main(jump to itself) as abnormal. It doesn't attemptNo attempts are made to halt the CPU or make it enter a low-power mode, etc. If you have a legitimate need for any of that in your application you will have to do it yourself.

Note that as specified in the ARMv7-M ARM A2.3.1, the link register is set to 0xFFFFFFFF on reset, and a branch to that address will trigger a fault. So the designers of Cortex-M decided to treat a return from the reset handler as abnormal, and it's hard to argue with them.

Speaking of a legitimate need to stop the CPU after the firmware is finished, it's hard to imagine any that wouldn't be better served by a powerdown of your device. (If you do disable your CPU "for good" the only thing that can be done to your device is a power cycle or external hardware reset.) You can deassert an ENABLE signal for your DC/DC converter or turn your power supply off in some other way, like an ATX PC does.

There are two points to be made here:

  • An embedded program, strictly speaking, cannot "finish".
  • There is very rarely a need to run an embedded program for some time and then "finish".

The concept of a program shutdown doesn't normally exist in an embedded environment. At a low level a CPU will execute instructions while it can; there is no such thing as a "final return statement". A CPU may stop execution if it encounters an unrecoverable fault or if explicitly halted (put into a sleep mode, a low power mode, etc), but note that even sleep modes or unrecoverable faults do not generally guarantee that no more code is going to be executed. You can wakeup from sleep modes (that's how they're normally used), and even a locked up CPU can still execute a NMI handler (this is the case for Cortex-M). The details vary greatly between architectures. You need to read relevant manuals really carefully if you want to ensure certain behavior (see below why you shouldn't attempt to do that anyway).

In case of firmware written in a language such as C or C++, what happens if main() exits is determined by the startup code. For example, here is the relevant part of the startup code from the STM32 Standard Peripheral Library (for a GNU toolchain, comments are mine):

Reset_Handler:  
  /*  ...  */
  bl  main    ; call main()
  bx  lr      ; return (branch to the address stored in the link register)

Now, as specified in the ARMv7-M ARM A2.3.1, the link register is set to 0xFFFFFFFF on reset, and a branch to that address will trigger a fault. So the STM32 SPL clearly treats a return from main() as abnormal. It doesn't attempt to halt the CPU or make it enter a low-power mode, etc. If you have a legitimate need for any of that in your application you will have to do it yourself.

Speaking of a legitimate need, it's hard to imagine any that wouldn't be better served by a powerdown of your device. (If you do disable your CPU "for good" the only thing that can be done to your device is a power cycle or external hardware reset.) You can deassert an ENABLE signal for your DC/DC converter or turn your power supply off in some other way, like an ATX PC does.

There are two points to be made here:

  • An embedded program, strictly speaking, cannot "finish".
  • There is very rarely a need to run an embedded program for some time and then "finish".

The concept of a program shutdown doesn't normally exist in an embedded environment. At a low level a CPU will execute instructions while it can; there is no such thing as a "final return statement". A CPU may stop execution if it encounters an unrecoverable fault or if explicitly halted (put into a sleep mode, a low power mode, etc), but note that even sleep modes or unrecoverable faults do not generally guarantee that no more code is going to be executed. You can wakeup from sleep modes (that's how they're normally used), and even a locked up CPU can still execute a NMI handler (this is the case for Cortex-M). A watchdog will still run, too, and you may not be able to disable it on some microcontrollers once it's enabled. The details vary greatly between architectures. You will need to read relevant manuals really carefully if you want to ensure certain behavior (see below why you shouldn't attempt to do that anyway).

In case of firmware written in a language such as C or C++, what happens if main() exits is determined by the startup code. For example, here is the relevant part of the startup code from the STM32 Standard Peripheral Library (for a GNU toolchain, comments are mine):

Reset_Handler:  
  /*  ...  */
  bl  main    ; call main(), lr points to next instruction
  bx  lr      ; infinite loop

This code will enter an infinite loop when main() returns, although in a non-obvious way (bl main loads lr with the address of the next instruction which is effectively a jump to itself). No attempts are made to halt the CPU or make it enter a low-power mode, etc. If you have a legitimate need for any of that in your application you will have to do it yourself.

Note that as specified in the ARMv7-M ARM A2.3.1, the link register is set to 0xFFFFFFFF on reset, and a branch to that address will trigger a fault. So the designers of Cortex-M decided to treat a return from the reset handler as abnormal, and it's hard to argue with them.

Speaking of a legitimate need to stop the CPU after the firmware is finished, it's hard to imagine any that wouldn't be better served by a powerdown of your device. (If you do disable your CPU "for good" the only thing that can be done to your device is a power cycle or external hardware reset.) You can deassert an ENABLE signal for your DC/DC converter or turn your power supply off in some other way, like an ATX PC does.

Source Link
Thorn
  • 2.2k
  • 14
  • 16

There are two points to be made here:

  • An embedded program, strictly speaking, cannot "finish".
  • There is very rarely a need to run an embedded program for some time and then "finish".

The concept of a program shutdown doesn't normally exist in an embedded environment. At a low level a CPU will execute instructions while it can; there is no such thing as a "final return statement". A CPU may stop execution if it encounters an unrecoverable fault or if explicitly halted (put into a sleep mode, a low power mode, etc), but note that even sleep modes or unrecoverable faults do not generally guarantee that no more code is going to be executed. You can wakeup from sleep modes (that's how they're normally used), and even a locked up CPU can still execute a NMI handler (this is the case for Cortex-M). The details vary greatly between architectures. You need to read relevant manuals really carefully if you want to ensure certain behavior (see below why you shouldn't attempt to do that anyway).

In case of firmware written in a language such as C or C++, what happens if main() exits is determined by the startup code. For example, here is the relevant part of the startup code from the STM32 Standard Peripheral Library (for a GNU toolchain, comments are mine):

Reset_Handler:  
  /*  ...  */
  bl  main    ; call main()
  bx  lr      ; return (branch to the address stored in the link register)

Now, as specified in the ARMv7-M ARM A2.3.1, the link register is set to 0xFFFFFFFF on reset, and a branch to that address will trigger a fault. So the STM32 SPL clearly treats a return from main() as abnormal. It doesn't attempt to halt the CPU or make it enter a low-power mode, etc. If you have a legitimate need for any of that in your application you will have to do it yourself.

Speaking of a legitimate need, it's hard to imagine any that wouldn't be better served by a powerdown of your device. (If you do disable your CPU "for good" the only thing that can be done to your device is a power cycle or external hardware reset.) You can deassert an ENABLE signal for your DC/DC converter or turn your power supply off in some other way, like an ATX PC does.