Halt and reboot APIs

65 views
Skip to first unread message

Matthijs Kooijman

unread,
Jul 2, 2015, 7:16:25 AM7/2/15
to devel...@arduino.cc
Hey folks,

while working with external hardware, you will regularly need to handle
initialization failure, typically by printing an error and then stopping
further processing. When working with external (network) connections,
you often need to handle unexpected disconnections. Often, the easiest
way to handle these would be to just reboot, going through the initial
setup again.

Would it make sense to add some functions for these? I can imagine:

halt()
Halts the CPU, never returns. Might disable interrupts, and/or put
the CPU to sleep as well?

halt(Print&, const char *)
halt(Print&, const __FlashStringHelper *)
Prints a given message to the given Print instance, flushes the
buffer and then calls halt. Would be typically called as:

halt(Serial, F("Failed to initialize foo"));

reboot()
Reboots the Arduino. On AVR, this could use the watchdog, not
sure what would be suitable on SAM?

reboot(Print&, const char *)
reboot(Print&, const __FlashStringHelper *)
Just like the halt functions, but reboots instead of halting


These seem like fairly simple additions. Would these seem useful to
anyone else as well? Any corner cases I'm missing?

Gr.

Matthijs
signature.asc

Rob Tillaart

unread,
Jul 2, 2015, 3:49:48 PM7/2/15
to Arduino Developers
interesting,
On a PC there are 2 kinds of reboot, warm and cold. with small differences. I can imagine a flag for the reboot that keeps ISR's or disable's them during reboot. 
The case I'm thinking of is a reboot that keeps the receive buffer of a Serial intact so the sketch can process data from before reboot.

Would a "crashdump" mechanism also be interesting? A small routine that can dump RAM, stack & heap?  I never needed it on Arduino, but I recall a post long ago about a monitor part that allowed to debug the contents of the AVR. Sorry no link.



Matthijs

--
You received this message because you are subscribed to the Google Groups "Developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to developers+...@arduino.cc.

Tyler

unread,
Jul 2, 2015, 5:38:23 PM7/2/15
to devel...@arduino.cc
There's already a function for rebooting the Arduino, called bonzai() :-P . I've used it many times for complicated firmware upgrades using the Arduino as a USB-to-UART bridge.

-Tyler

Peter Olson

unread,
Jul 3, 2015, 2:11:23 AM7/3/15
to Matthijs Kooijman, developers
> On July 2, 2015 at 7:16 AM Matthijs Kooijman <matt...@stdin.nl> wrote:

> Would it make sense to add some functions for these? I can imagine:
>
> halt()
> Halts the CPU, never returns. Might disable interrupts, and/or put
> the CPU to sleep as well?
>
> halt(Print&, const char *)
> halt(Print&, const __FlashStringHelper *)
> Prints a given message to the given Print instance, flushes the
> buffer and then calls halt. Would be typically called as:
>
> halt(Serial, F("Failed to initialize foo"));

I wrote a function, specific to my sketch, which I use for just this purpose.

But it has to do other things when invoked. I use it after initialization as
well, a little like assert(), to stop a machine control process safely. (Yeah,
I am not an educational user of Arduino.)

I am using an Arduino Due Timer-Counter which must be turned off to avoid
attached machine damage if a fault is detected while the TC is emitting a pulse.
I use a numeric code rather than a string because I want to blink some LEDs in
the style that old PC BIOS ROMs did for faults. Since the serial link to the
host has a packet-based protocol, I can't just print an error message, I have to
use the client-side API to send a packet with the error message. I also use
that interface to report some critical process parameters at the time of the
fault.

So it seems to me that the halt() API needs something like the traditional C
atexit() to register a limited number of callbacks to be invoked as part of the
shutdown. Without this I think it would be impossible to anticipate all the
needs that are essential to halting.

I assume halting means at a minimum "noInterrupts(); for (;;) continue;"

> reboot()
> Reboots the Arduino. On AVR, this could use the watchdog, not
> sure what would be suitable on SAM?

I have a specific use for this on the Arduino Due.

The CDC interface on the native port is substantially faster than the
programming port, but (IIRC) doesn't have an option to reset the chip. The 1200
bps hack resets it for programming, but I need to reset the chip without
programming at the start of a job in my physical process to guarantee job
integrity. I thought of doing something with the watchdog to do this but never
was faced with a situation where I had to use the native port, so I didn't
proceed further.

A good watchdog API would be great.

Peter Olson

Donald Delmar Davis

unread,
Jul 3, 2015, 5:22:43 AM7/3/15
to devel...@arduino.cc, Matthijs Kooijman
reload();  //jump to bootloader If you are going to make rebooting nice and cross platform you should be able to get to the bootloader.

-- my 2 Pfennigs

Matthijs Kooijman

unread,
Jul 3, 2015, 5:29:53 AM7/3/15
to devel...@arduino.cc
Hi Rob,

> On a PC there are 2 kinds of reboot, warm and cold. with small differences.
> I can imagine a flag for the reboot that keeps ISR's or disable's them
> during reboot.
> The case I'm thinking of is a reboot that keeps the receive buffer of a
> Serial intact so the sketch can process data from before reboot.
My idea for reboot would be to disable interrupts and enable the
watchdog, so it reboots the board after 15ms, which would constitue a
"cold reboot", I think.

I'm not sure what a "warm reboot" would mean here and if it's useful or
feasible. I think that, using longjmps, you could create a reboot()
function that jumps back to the start of main(). But what you say, about
keeping ISRs and serial buffers intact seems pretty much impossible to
me. When the setup() function runs, everything, such as the serial
buffers I think, will be re-initialized. Additionally, a lot of code
assumes that their global variables are initialized to zero or some
specific value before setup() runs, which will not be the case with such
a warm reboot.

If you really think this would be useful, could you describe some usecases?

> Would a "crashdump" mechanism also be interesting? A small routine that can
> dump RAM, stack & heap? I never needed it on Arduino, but I recall a post
> long ago about a monitor part that allowed to debug the contents of the
> AVR. Sorry no link.
I don't think this would be useful for Arduino, unless you would also
provide an easy way to analyze such dumps in the IDE (which will be
pretty complicated, I think). Without that, analysis must be manual,
making this useful for advanced users only. Those users can just as
easily write their own crashdump function, or this can be provided by a
library. Even better would be to use debugger hardware.

In any case, I think a crashdump is interesting, but out of scope for
the Arduino Core.

Gr.

Matthijs
signature.asc

Matthijs Kooijman

unread,
Jul 3, 2015, 5:34:02 AM7/3/15
to devel...@arduino.cc

Hi Donald,

> reload(); //jump to bootloader If you are going to make rebooting nice and cross platform you should be able to get to the bootloader.
So the difference between reload() and my proposed reboot() is that
reboot() skips the bootloader and reload() executes the bootloader? I'm
not entirely sure if this can be implemented right now. Jumping directly
to the bootloader is possible, but without resetting all registers,
things might actually behave pretty randomly. Jumping to the bootloader
through a proper (watchdog) reset is possible, but it seems some
bootloaders currently skip to the sketch directly when this happens,
while some don't.

Gr.

Matthijs
signature.asc

Matthijs Kooijman

unread,
Jul 3, 2015, 5:38:58 AM7/3/15
to devel...@arduino.cc
Hi Tyler,

> There's already a function for rebooting the Arduino, called
> bonzai() <span class="moz-smiley-s4"><span> :-P </span></span>.
> I've used it many times for complicated firmware upgrades using the
> Arduino as a USB-to-UART bridge.<br>
Do you have any reference about this? I can't find it defined in the
Arduino core, and googling for "arduino bonzai" doesn't turn up
anything. Perhaps you defined it yourself at some point in your local
installation?

Gr.

Matthijs

PS, would be good if you could configure your e-mail client to include a
text part in your emails, sending HTML-only mail to mailing lists isn't
usually appreciate :-)
signature.asc

facchinm

unread,
Jul 3, 2015, 5:43:33 AM7/3/15
to devel...@arduino.cc
I don't think that an halt() API has any use case in the embedded world if it doesn't alias a "go low power" call (and of course a way to recover from this state without removing the power supply)

Instead, I'd really appreciate a reboot() API wrapping a clean exit and a call to watchdog.

BTW, the mainline Due core already has a watchdog implementation (https://github.com/arduino/Arduino/pull/3111) although it is not exposed in the Reference (my fault, need to do it soon)

Marco Brianza

unread,
Jul 3, 2015, 5:59:20 AM7/3/15
to devel...@arduino.cc
the correct function name is banzai()
It is defined in the Due core, and is used as software alternative to the reset button, to bring the processor in boot loader mode after reset

Cristian Maglie

unread,
Jul 3, 2015, 6:03:58 AM7/3/15
to devel...@arduino.cc
Il 03/07/2015 11:38, Matthijs Kooijman ha scritto:
> Do you have any reference about this?

Here you go:

https://github.com/arduino/Arduino/blob/master/hardware/arduino/sam/cores/arduino/Reset.cpp

C


Matthijs Kooijman

unread,
Jul 3, 2015, 6:08:50 AM7/3/15
to devel...@arduino.cc
Hi Peter,

> I wrote a function, specific to my sketch, which I use for just this purpose.
>
> But it has to do other things when invoked. I use it after initialization as
> well, a little like assert(), to stop a machine control process safely. (Yeah,
> I am not an educational user of Arduino.)
Right. I would say you could still do the same - just create a
safehalt() function which cleans up and then calls halt()?

My intention was not really to create a halt/reboot for use in libraries
or other generic code - but mostly to have some convenience functions
for sketches to concisely print an error and halt execution. IMHO,
libraries should never be calling halt() or reboot() in case of errors -
they should report back to the sketch and let the sketch decide what to
do.

In that regard, only the reboot() function would add something that
sketches cannot currently implement (portably) themselves, the halt
functions and reboot functions with arguments could be implemented in
the sketch itself directly. Still, I think they have added value as
convenience functions.

> So it seems to me that the halt() API needs something like the traditional C
> atexit() to register a limited number of callbacks to be invoked as part of the
> shutdown. Without this I think it would be impossible to anticipate all the
> needs that are essential to halting.
I'm afraid that adding such callbacks significantly complicates things.
Also, it seems to me that without them, the API is still useful. If it
is not sufficient, a sketch can implement their own wrappers instead.

> I assume halting means at a minimum "noInterrupts(); for (;;) continue;"
That's what I had in mind, yes.

> > reboot()
> > Reboots the Arduino. On AVR, this could use the watchdog, not
> > sure what would be suitable on SAM?
>
> I have a specific use for this on the Arduino Due.
>
> The CDC interface on the native port is substantially faster than the
> programming port, but (IIRC) doesn't have an option to reset the chip. The 1200
> bps hack resets it for programming, but I need to reset the chip without
> programming at the start of a job in my physical process to guarantee job
> integrity. I thought of doing something with the watchdog to do this but never
> was faced with a situation where I had to use the native port, so I didn't
> proceed further.
Ah, it seems that the 1200 baud trick actively configures the bootloader
to run indeed:

https://github.com/arduino/Arduino/blob/bd8f7932e64fb3a41e3d934437d5eabd8707dcc9/hardware/arduino/sam/cores/arduino/Reset.cpp#L27-L51

This reboot() API should probably not set those flags and instead just
reboot into the sketch directly.

On complication I just found, is that not all bootloaders currently
clear the watchdog flag. On AVR, this means that the watchdog
immediately triggers again after 15ms, leading to a reboot loop. In
particular, the atmega, atmega8, lilypad and bt bootloaders do not do
this. This means that the watchdog reset won't be usable on those
bootloaders (but I am not aware of any alternatives). This affects the
Diecimila, nano, mega1280, mini, fio, bt, lilypad, pro and pro mini
boards. It's a fairly trivial fix, though (which could at least fix
to-be-produced boards).

Gr.

Matthijs
signature.asc

Matthijs Kooijman

unread,
Jul 3, 2015, 6:13:06 AM7/3/15
to devel...@arduino.cc
Hi Marco,

> the correct function name is banzai()
> It is defined in the Due core, and is used as software alternative to the
> reset button, to bring the processor in boot loader mode after reset
Ah, just found it indeed. It's not really an official (documented) and
portable function. It does provide ready-made code to implement reboot()
as well :-)

Gr.

Matthijs
signature.asc

Matthijs Kooijman

unread,
Jul 3, 2015, 6:23:24 AM7/3/15
to devel...@arduino.cc
Hi,

> I don't think that an halt() API has any use case in the embedded world if
> it doesn't alias a "go low power" call (and of course a way to recover from
> this state without removing the power supply)
My intention was not to have a sleeping API to be used in normal
operation - it's just a way to make it easier to report an error through
serial and then stop running, in case an (initialization) error happens.
Sure, halting in low power and allowing to recover from errors in some
way would be nice, but also significantly more complex. Just having a
halt() API would mean that this code:

if (!some_library.begin()) {
Serial.println("Failed to initialize some_library");
while (true);
}

can be replaced by:

if (!some_library.begin())
halt("Failed to initalize some_library");

which is more concise, but also more readable. I'm assuming that the
while(true); loop isn't exactly obvious to novice users.

My original incentive for proposing this was an example in an Adafruit
library, which uses exactly this concept (but uses a macro, which I
think might be even more confusing to novice users):
https://github.com/adafruit/Adafruit_MQTT_Library/blob/master/examples/mqtt_cc3k/mqtt_cc3k.ino#L59

> BTW, the mainline Due core already has a watchdog implementation
> (https://github.com/arduino/Arduino/pull/3111) although it is not exposed
> in the Reference (my fault, need to do it soon)
Still, having a "reboot()" API is still useful IMHO, since it more
closely matches what you want to do. Using the watchdog to implement
reboot seems to be a common implementation of rebooting, but it might
not be the only one (also, having reboot() allows rebooting on platforms
that have some way of rebooting, but not have a watchdog).

Gr.

Matthijs
signature.asc

Thibaut VIARD

unread,
Jul 6, 2015, 5:58:57 AM7/6/15
to devel...@arduino.cc
Hi,

On both Due and Zero, the watchdog is not enabled.

On Due, banzai() function can be seen as a cold reset as it goes back to the bootloader present in ROM

Warm reset can be done only by playing with reset controller:
const int RSTC_KEY = 0xA5;
RSTC->RSTC_CR = RSTC_CR_KEY(RSTC_KEY) |    RSTC_CR_PROCRST |    RSTC_CR_PERRST;

On Zero, the bootloader being in flash, starting a reset can be done using NVIC_SystemReset(), as seen in Reset.cpp/banzai() but will go back to bootloader present in flash.
banzai acts like a cold reset also.
To do a warm reset on Zero, the most appropriate would be to assign PC register to ResetHandler and SP register to the stack value present in vectors.
Doing a preliminary blank erase of the RAM would be a plus.

Cheers,

Thibaut

Collin Kidder

unread,
Aug 19, 2015, 4:02:27 PM8/19/15
to developers
So, let's say that I'd like to try out the new watchdog functionality
that was approved to be merged into the core files for the Due. What
is the easiest approach there? It seems to be tagged that it would be
in a 1.6.5 release but I assume that means the 1.6.5 board files
release for the Due which has not been produced yet. I come to this
assumption because I have the 1.6.5 version of the IDE installed and
the files are not there. I could download the project on GIT and copy
the files over but that would be a pain if I wanted to get a couple of
other people onto this new version as well. Am I really stuck
downloading the files from github and manually copying them for now?

BTW, whose brilliant idea was it to make the board file versions
nearly identical to the IDE version?! Does anyone have any idea how
confusing it is when I explain to people that they might have the
1.6.5 version of the IDE but they only have the 1.6.4 version of the
Due core files? That versioning decision was nearly as bad as using
hydrogen to lift a powered blimp - just look how that whole business
turned out.

-Collin
Reply all
Reply to author
Forward
0 new messages