I have had requests from several folks for my version of FreeRTOS for the ATmega2560. I had always intended to take the latest) version of FreeRTOS, apply my changes, and submit it to the FreeRTOS group as another supported AVR processor, but I simply haven't gotten around to it.
Instead, I'm posting the code here, free for anyone's use. Please note that *all* the licenses from FreeRTOS apply to this version. Also, you get the same support, which is you can ask me for help and I may or may not help, depending on the request and my work load.
This code is based on FreeRTOS 4.8.0, although the grand majority of the changes are fairly simple and would be easy to merge with the latest version of FreeRTOS.
I have not included the co-routine stuff, since I do not use it.
There is a new switch, USE_RTC_TIMER which switches the RTOS timer from a dedicated timer (timer 0) to the RTC-crystal driven timer (timer 2). Your tick is a little longer than 2 mS, but you now have a single OS/RTC timer instead of two timers used for the same task of keeping track of time.
I've included the second level heap manager, heap_2.c, since I've added a routine to report memory usage for each task and for the total managed help.
Note that the task list function has had sprintf patched out in favor of itoa() and ltoa(). I did this because I don't like the added overhead of sprintf.
One of the problems with the ATmega2560/1 series is that GCC uses a 16-bit word to keep track of location. Most of the time this is corrected in the loader, but jump tables and function pointers have trouble with the upper half of the flash memory. (Keep in mind that the AVR addresses instructions by a word pointer so you have direct access to 128 Kbytes of flash. That's exactly half of the total 256 KBytes in the ATmega2560/1).
Since I want to be sure that the task stack initialization is simple, I require that all user-defined task routines reside in lower flash memory. I do that by modifying the portTASK_FUNCTION_PROTO macro to put the task function into the .task linker section. The custom script linker_script.x contains the special section .task located before the main code section.
For the same reason, my command handler defines the following macro:
#define COMMAND_HANDLER __attribute__ ((section (".fptr_target")))
The .fptr_target section, like .task, is set up before the main code section. I use it in the prototypes of my command routines, like:
CmdError CmdUnimplementedCommand( CmdPacket* pCmdPkt ) COMMAND_HANDLER; /*---------------------------------------------------------------------------*\ Usage: result = CmdUnimplementedCommand( pCmdPkt ); Description: Default command procedure for unimplemented commands Arguments: pCmdPkt - pointer to the command packet for this command Results: CMD_ERROR_FUNCTION_NOT_IMPLEMENTED - always returns this! \*---------------------------------------------------------------------------*/
The final bit of weirdness in linker_script.x is that I have another of these "pre-main code" sections, .isr, for ISRs. I am unconvinced that this is necessary since the JMP command can easily handle jumps to the top of memory, but I put it in a pique of anger once when an ISR wasn't working and I have never taken it out.
Nonetheless, inside of the projdefs.h file you will find:
/* The following defines the section for ISRs used throughout the code. * This is added to the current ISR() macro as another called argument. */ #define ISR_SECTION __attribute__ ((section (".isr")))
This can be appended to the list of arguments in the ISR macro like this:
ISR( SIG_2WIRE_SERIAL, ISR_BLOCK ISR_SECTION )
(Yes, there is not a comma between ISR_BLOCK and ISR_SECTION. That's a weirdity of the way the ISR macro is defined.)
That's pretty much it. I currenlty have more than 70,000 lines of code and 9 tasks running on this. I regularly use queues, semaphores and task suspension without problems.
The problems that crop up regularly are:
1 - Insufficient stack space allocated to a task. Look for this if the machine "reboots" when you don't expect it. Use the task list function to get reports on how much stack your tasks are using. Keep in mind that ISRs can fire in any task, so if you have and ISR that uses lots of RAM (bad idea), make sure your minimumSTACK_SIZE is increased to handle it.
2 - Using a non-ISR function in an ISR. This will almost always lock up the machine.
At any rate, I hope this helps folks along. Enjoy!
Stu