Wednesday 28 April 2010

Monitor Functions in the IAR Compilers for AVR

In AVR chips, game-changing actions like changing the clock prescaler or setting the watchdog are so important that they are afforded a protection mechanism all of their own. Timed write sequences are used to prevent accidental or rogue writes from fundamentally messing with your day.

These require you to perform a sequence of write operations within a defined time period - typically you need to do two writes within four clock cycles.

Care must be taken when performing such a write sequence that no other operations could take place that would violate the required timing. Typical candidates for such mischievous behaviour are interrupt service routines, which have an uncanny knack of firing at the most inconvenient times.

The obvious way to ensure that your timed write sequence is interrupt-safe is to disable interrupts around it, like so:

void do_timed_write_operation( void )
{
__disable_interrupt();
// timed write sequence goes here
__enable interrupt();
}

Unfortunately this contains a nasty little gotcha: if you call this function from code in which interrupts are disabled, they will be enabled on return from the function. This is almost certainly not what is intended, and can lead to late night debugging sessions.

A safer approach is to save the interrupt state on function entry, disable interrupts, do your business, and then put the interrupts back the way you found them:

void do_timed_write_operation_2( void )
{
uint8_t interrupt_state = __save_interrupt();
__disable_interrupt();
// timed write sequence goes here
__restore_interrupt( interrupt_state );
}

This approach is so common and idiomatic that the IAR compilers for AVR support it directly with the __monitor keyword. The following function is equivalent to the previous one:

__monitor void do_timed_write_operation_3( void )
{
// timed write sequence goes here
}

Unfortunately declaring a monitor function involves a code overhead - after all, even though you can't see it explicitly in the C, a quick squint at the list files will show that the interrupts are still being saved, disabled, and restored.

A saving grace here is that most such Big Important Things tend to happen during system initialisation, when interrupts are disabled anyway. In such circumstances you can perform your timed writes au naturel, without any interrupt protection. However you really need to convince yourself that it is safe to do so. It would be a brave man indeed who called the first function above once the system was up and running without spending a very long time looking at possible consequences.

In general I would suggest that all timed write sequences be protected by default. Such protection can be removed if you're convinced that it's safe to do so - and of course if you document this assumption in the comments.


Wednesday 21 April 2010

File Under Easy Listening

This is an excellent podcast by David Heinemeier Hansson (DHH) on Legacy Software.  It's a recording from a talk at RailsConf Europe, and the podcast (i.e., audio-only) format doesn't really work in the last third of the talk, in which he's refactoring some code on stage.  However, the gist of his argument is completely sound - if you wince in embarrassment/pain/surprise when you look at code you wrote a few years ago, it's nothing to be ashamed of.  The code hasn't got worse - you've got better.  In the interim you've learned new techniques and idioms, and the fact that the earlier you wasn't favoured with your current clear-sighted and visionary approach to writing code shows that you've progressed.

[The corollary of this is that the future you will be embarrassed/pained/surprised by what the current clear-sighted and visionary you is doing today, but what the hey, just appreciate the step change from yesteryear.]

Also highly recommended is this appearance by DHH on Jason Calacanis's This Week In Startups podcast.  Two successful and highly opinionated people with entirely different takes on business, money, and work slug it out.  Who's right?  They both are, of course.  They've figured out what works for them, and good luck to them.  You don't have to agree wholeheartedly with either to enjoy the debate.