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:
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