Skip to content

The devil is in the details: Atmega startup to freertos

Figuring out why something breaks usually involves understanding how it is supposed to work.  Sure, it was easy getting my first Atmega328 code running using Arduino.  Getting the DuinOS version of freeRTOS was a little bit more of a challenge but ran remarkably well given its alpha state.  Getting a printf function to work using some avr-libc utilities (that map a routine to a file handle like stdout) was a bit more of a stretch, and discovering that printf in the avr-libc was not thread safe, requiring a fancy macro using a Variadic Macro (google that one) to wrap the printf in a Mutex semaphore did stretch things a bit, along with finding how to turn Mutexes on in the DuinOS version of free RTOS.

All of this was for not though, when my benchmark program using ThreadX failed to even run.  Chasing that problem lead me to a realization that I had no_idea how a main() starts on an Atmega after being loaded by the bootloader and no idea how freeRTOS gets its kick start.  To that end, I write this little blurb to remind me that the devil is in the details.

Digging around on the net has uncovered some interesting tid bits about the Atmega 8 MC family.   At the same time, I started fingering (with vim and egrep) the freeRTOS sources to get a feel for how things get underway.

First a bit about the Atmega.  It’s got lots and lots of goodies.  My focus is on what happens when you reset this little puppy.  Well, as expected, it starts from location 0000.  But which 0000, there are three different memory spaces (or more).  Fortunately the processor block diagram provides a hint.  EEPROM memory, as it turns out, is the usually starting point, but, an io port can be hit to move the starting point to FLASH where programs are loaded by the boot loader.  So, we start at 0000 in FLASH (at least for the turnkey setups on the Arduino boards).  What happens next?  Magic happens in the linker when the program code is built.  The linker puts a jump instruction at 0000 to the first location after all the interrupt vectors that come right after the 0000 and 0001 location.  The linker also adds a bit of asm code to initialize the stack pointer to the top of memory in ram space (usually a strange address, as the Atmega IO space is allocated the lowest locations in that volatile address space) causing ram to start at some higher location).  The asm code then jumps to the main() routine where, one more time, a small amount of code (not seen in your main c code) is plugged in by the linker (or compiler) to initialize the stack pointer again and set some io bits.  Then, finally, recognizable code that you have written in your main routine shows up.  There you have it.  A readers digest version of an Atmega starting up.

It should be possible, with a bare bones enough interface to the hardware serial port, to read the just initialized stack pointer to verify this little aspect.  It should also be possible to find the lowest ram location that is above all theconstant and non constant allocated variable space.  Still looking for the gcc-avr system variable or define that tells me that.  Would be useful for the next step:  Understanding how freeRTOS gets started.

freeRTOS gets itself started when the first task is created.  The task creation routine detects that the first task is being requested and initializes the heap to be used by the scheduler. The task creation routine only does this once then does normal task initialization.   Once initialized the scheduler can allocate stack space for the idle loop and stack space for the first task then, based on priority, return control to the task with the higher priority (usually the first task created, not the idle loop) and off it goes.  Stack space is user definable on a task by task basis at creation time.  To get a feel for how well the tasks are using their compute assets, we need some instrumentation (dah).  Useful data would be, how much stack space is consumed, how much is left and how much cpu time has the task eaten.  There is some instumenation delivered with freeRTOS but it seems pretty heavy weight and does not give the simple details that tell so much.  This is probably my next steps (including the main() report of first data location and first stack location).  I’m thinking I should have something that looks like this:

mBottom=[], mSP=[]

These could be dumped when main() is entered.


These could be dumped on the initial startup of the scheduleer




This could be run inside the scheduler and dumped to the hardware uart.

need some uart code


  1. Julián wrote:

    Hi, many thanks for your comments. We have posted a link to your site regarding the printf bug in the “Tracker” section in our new wiki:
    Please fell free to contribute to the wiki or the whole project if you want, or if you like to share the workarounds you have made to get DuinOS working with printf.


    Sunday, December 27, 2009 at 9:51 am | Permalink
  2. Audrius wrote:

    Basicaly it’s a question. Recently I began playing with FreeRTOS on Atmega128 and also discovered that printf in the avr-libc was not thread safe with was not an isue before. I did nothing about that. And now I’m reading that you have solved that by using a “fancy macro using a Variadic Macro (google that one) to wrap the printf in a Mutex semaphore”. Could you share your experience by example? That would be appreciated.

    Friday, January 1, 2010 at 12:12 pm | Permalink
  3. Paula wrote:

    Should be a new entry in my blog that provides an example. I’m working on a version that would hide the underlying mutex, but not complete yet.

    Tuesday, January 12, 2010 at 9:24 pm | Permalink
  4. Paula wrote:

    Thanks Julian, I have added a detailed explaination on how to make printf thread safe. I’m working a a version that is more user friendly.

    Tuesday, January 12, 2010 at 9:25 pm | Permalink
  5. Julián wrote:

    Hi Paula, can we add your mprintf version to the DuinOS v0.2?

    Sunday, January 24, 2010 at 7:22 am | Permalink
  6. Paula wrote:

    Hi Julian, Yes, of course. Do warn users that they need to allocate more stack space or the type conversion will fail. Through my name in to the source for good measure 🙂


    Sunday, January 24, 2010 at 1:31 pm | Permalink
  7. Julián wrote:


    Thursday, January 28, 2010 at 7:53 pm | Permalink

Post a Comment

Your email is never published nor shared. Required fields are marked *