Sunday, March 16, 2014

FreeRTOS on Teensy 3.1

 
This post is about running FreeRTOS on a Teensy 3.1 board from PJRC. It is not a detailed in-depth coverage but will get you started. If you have not heard about this board you can find it here. Since my last post on making FreeRTOS run on the BeagleBoard, which was a nice learning experience, i've been porting FreeRTOS on anything i can get my hands on - a blender, television, chickens. You see, to port FreeRTOS on a chicken all you have to do is shove a compiled image up it's...never mind. Let's get started with this thing. First the pre-requisites

Pre-requisites:
- Teensy 3.1
- Arduino 1.0.5 with the support for Teensy installed.
- FreeRTOS source code
- Cortex M Series TRM (duh)
- Datasheet of the MK20DX256VLH7 (you probably will not open it)


FreeRTOS:
FreeRTOS can be downloaded from the website. The latest version 8.0.0 has ports for Cortex M devices  already. You can refer to that and it's accompanying demo example. As we are using the Teensy here some minor modifications are necessary. In the portable directory we need to look inside the GCC sub-directory as the arduino uses the gcc toolchain for code compilation. Within the GCC directory there will be three sub-folders - ARM_CM0, ARM_CM3, ARM_CM3_MPU, ARM_CM4F. I used the ARM_CM3 port for the Teensy as it was simple and did not create unnecessary link errors. Perhaps i will try with the MPU version later. Do not use the ARM_CM4/F port, in my opinion it is wierd, maybe just not for this board.
The directory structure
- Source: The FreeRTOS source code.
- Source/include: The header files
- Source/portable: Target dependent files. For the Cortex these will be in the ARM_CM3 sub-directory inside GCC within portable, jeez...


Procedure:
1. Make a duplicate copy of the Arduino folder as a back up in case you need to revert back the code.
2. Copy all the FreeRTOS C / headers / portable files into the /Arduino1.0.5/hardware/teensy/cores/teensy3.
3. Copy the memory manager of you choice, i chose heap_2.c, from FreeRTOS's MemMang directory to the directory in [2].
4. The Teensy 3.1 has a 256K flash but it uses the mk20dx128.c file as it's startup. This file needs some editing as mentioned below.

4.1. Include FreeRTOS.h and task.h
4.2. stick_default_isr needs to be commented out, we shall see why later in [4.5]
4.3. I defined vApplicationStackOverflowHook function in this file.
4.4. Comment out prototype declaration for svcall_isr, pendablesrvreq_isr and systic_isr. Yes, i will not be using CMSIS naming conventions.
4.5. Replace the functions mentioned in [4.4] with vPortSVCHandler, xPortPendSVHandler, xPortSysTickHandler respectively  in the gVectors array. 
4.6. In the ResetHandler function comment out the initialization of the Systick as we shall be doing that during FreeRTOS initialization.
5. To setup the heap, mk20dx256.ld linker script needs to be modified. Here add a new region .heap as shown below. "heapsection" is the name given in as the __attribute__ for the static heap. This will not be present in the original file and needs to be modified as:

static uint8_t ucHeap[ configTOTAL_HEAP_SIZE ]  __attribute__ ((section(".heapsection")));

6. I setup my FreeRTOSconfig.h as shown below

7. I then edited the main.cpp file to test the FreeRTOS functionality.


Well this should get FreeRTOS running, if you get any compiling / linking errors then i probably missed out something, but i am confident you can fix those yourself. FreeRTOS runs like a charm on this board only limited by it's memory capacity. Now there are problems with the rest of the Arduino code not being thread-safe and not designed to run under an OS. There is a discussion on the same on the Teensy forum right here - http://forum.pjrc.com/threads/540-ChibiOS-RTand-FreeRTOS-for-Teensy-3-0

I have a very busy schedule and it takes time to implement and write up all this stuff. I will be updating this post with new findings as i go forward with this like the maximum tasks that can be run, etc... 

Code:
https://github.com/circuitsenses/Teensy-3.1-FreeRTOS

Happy Coding... 
P.S - Notice that you never referred to the MK20DX256VLH7 datasheet :P

8 comments:

David Miller Lowe said...

Worked Pretty well, One of the sticky points I had to sleuth a bit for is that by disabling the default timer isr which normally runs at 1KHZ the arduino delay(x) function will never return.

There is a delay() call in the in the Reset() function that was keeping my main() from being called...

Awesome instructions! Thanks!

David Haile said...

Sheesh! I fussed around for a couple of hours trying to get it to work before I followed directions. It worked the first time! Now to wedge my working application into FreeRTOS....

Khalid Alshamkhany said...

Hi Rishi,

I have followed your guide on the latest version of FreeRTOS 8.2.3, but I was unable to get Teensy 3.2 board running. The code compiles but the code doesn't run. I have to press the program button to program the board again.

David Miller Lowe said...

I know it can work.. I have several 3.1 and 3.2 boards that all work fine.. Mind the instructions and make sure you're not calling the arduino delay() method that is relying on it's timer interrupt.

There is another issue I have with stack corruption on the main thread.. If you are seeing corruption of data automatically declared in main I can describe a workaround but am still chasing a solution in my non-existant spare time.

Mil

Christopher Parish said...

Looks like _init_Teensyduino_internal_() in current versions of Teensyduino (post Nov 2015) have an arduino delay built in (which freezes everything). Given that delays are creeping into the pre-main code, I'm wondering if it makes sense to leave the default SysTick ISR from boot and replace it only when the scheduler starts.

vanbergeijk said...

Great write up! I followed your instructions for a teensy 3.6 FreeRTOS port and got this working. That port is posted at https://github.com/vanbergeijk/teensy-3.6-FreeRTOS-template. The delay() in _init_Teensyduino_internal_() was the only one that had to be replaced to get past the SysTick initialization hurdle.

David Miller Lowe said...

There is a known issue (some argument if it's an issue or not) about the FreeRTOS kernel resetting the stack pointer ( http://www.freertos.org/FreeRTOS_Support_Forum_Archive/January_2015/freertos_Main_stack_pointer_reset_when_starting_the_scheduler_e5a776c1j.html )


I called this a defect last March.. (See above)...

To give myself some stack space for the main I've modified my startup code to allocate a small stack space for the main thread (separate from what ARM thinks is the

In the global area
//*****************************************************************************
//
// Reserve space for the system stack.
//
//*****************************************************************************

static uint32_t pui32Stack[128]; // normal main stack allocation
static uint32_t pui32MainStack[128]; // new one that I use for main()


Then following the .bss initialization in the startup.c file.

//
// set the main task stack seperate than the
// boot stack

void * ulMainStackTop = (void *) ((uint32_t)pui32MainStack + sizeof(pui32MainStack));


__asm volatile( "mov r0, %0" : "=r"( ulMainStackTop ) );
__asm volatile( "mov sp, r0\n" );


Mil

David Miller Lowe said...

oops... Only use this if you want to use some automatic allocation in main(), otherwise FreeRTOS may step on it.

I'll leave the 'is allocation in main needed?' discussion to those with a concern, for my purpose I wanted it.

Mil