Arduino FreeRTOS

Arduino FreeRTOS Logo

For a long time I have been using the AVR port of FreeRTOS as the platform for my Arduino hardware habit. I’ve written (acquired, stolen, and corrupted) a plethora of different drivers and solutions for the various projects I’ve built over the last years. But, sometimes it would be nice to just try out a new piece of hardware in a solid multi-tasking environment without having to dive into the datasheets and write code. Also, when time is of the essence rewriting someone’s existing driver is just asking for stress and failure.

So recently, with an important hack-a-thon coming up, I thought it would be nice to build a robust FreeRTOS implementation that can just shim into the Arduino IDE and allow me to use the best parts of both environments, seamlessly.

Arduino IDE Core is just AVR

One of the good things about the Arduino core environment is that it is just the normal AVR environment with a simple Java IDE added. That means that all of the AVR command line tools used to build Arduino sketches will also just work my AVR port of FreeRTOS.

Some key aspects of the AVR FreeRTOS port have been adjusted to create the seamless integration with the Arduino IDE. These optimizations are not necessarily the best use of FreeRTOS, but they make the integration much easier.

FreeRTOS needs to have an interrupt timer to trigger the scheduler to check which task should be using the CPU, and to fairly distribute processing time among equivalent priority tasks. In the case of the Arduino environment all of the normal timers are configured in advance, and therefore are not available for use as the system_tick timer. However, all AVR ATmega devices have a watchdog timer which is driven by an independent 128kHz internal oscillator. Arduino doesn’t configure the watchdog timer, and conveniently the watchdog configuration is identical across the entire ATmega range. That means that the entire range of classic AVR based Arduino boards can be supported within FreeRTOS with one system_tick configuration.

The Arduino environment has only two entry point functions available for the user, setup() and loop(). These functions are written into an .ino file and are linked together with and into a main() function present in the Arduino libraries. The presence of a fixed main() function within the Arduino libraries makes it really easy to shim FreeRTOS into the environment.

The main() function in the main.c file contains a initVariant() weak attribute stub function prior to the internal Arduino initialisation setup() function. By implementing an initVariant() function execution can be diverted into the FreeRTOS environment, after calling the normal setup() initialisation, by simply continuing to start the FreeRTOS scheduler.

int main(void) // Normal Arduino main.cpp. Normal execution order.
{
init();
initVariant(); // Our initVariant() diverts execution from here.
setup(); // The Arduino setup() function.

for (;;)
{
loop(); // The Arduino loop() function.
if (serialEventRun) serialEventRun();
}
return 0;
}

Firstly, this initVariant() function is located in the variantHooks.cpp file in the FreeRTOS library. It replaces the weak attribute function definition in the Arduino core.

void initVariant(void)
{
setup(); // The Arduino setup() function.
vTaskStartScheduler(); // Initialise and run the FreeRTOS scheduler. Execution should never return to here.
}

Secondly, the FreeRTOS idle task is used to run the loop() function whenever there is no unblocked FreeRTOS task available to run. In the trivial case, where there are no configured FreeRTOS tasks, the loop() function will be run exactly as normal, with the exception that a short scheduler interrupt will occur every 15 milli-seconds (configurable). This function is located in the variantHooks.cpp file in the library.

void vApplicationIdleHook( void )
{
loop(); // The Arduino loop() function.
if (serialEventRun) serialEventRun();
}

Putting these small changes into the Arduino IDE, together with a single directory containing the necessary FreeRTOS v10.x.x files configured for AVR, is all that needs to be done to slide the FreeRTOS shim under the Arduino environment.

I have published the relevant files on Github where the commits can be browsed and the repository downloaded. The simpler solution is to install FreeRTOS using the Arduino Library Manager, or download the ZIP files from Github and install manually as a library in your Arduino IDE.

Getting Started with FreeRTOS

Ok, with these simple additions to the Arduino IDE via a normal Arduino library, we can get started.

Firstly in the Arduino IDE Library manager, from Version 1.6.8, look for the FreeRTOS library under the Type: “Contributed” and the Topic: “Timing”.

Arduino Library Manager

Arduino Library Manager

Ensure that the most recent FreeRTOS library is installed. As of writing that is v10.3.0-4.

FreeRTOS v8.2.3-6 Installed

Example of FreeRTOS v8.2.3-6 Installed

Then under the Sketch->Include Library menu, ensure that the FreeRTOS library is included in your sketch. A new empty sketch will look like this.

ArduinoIDE_FreeRTOS

Compile and upload this empty sketch. This will show you how much of your flash is consumed by the FreeRTOS scheduler. As a guide the following information was compiled using Arduino v1.8.5 on Windows 10.

// Device: loop() -> FreeRTOS | Additional Program Storage
// Uno: 444 -> 6592 | 20%
// Goldilocks: 502 -> 6684 | 5%
// Leonardo: 3462 -> 9586 | 23%
// Yun: 3456 -> 9580 | 23%
// Mega: 662 -> 6898 | 2%

Now test and upload the Blink sketch, with an underlying Real-Time Operating System. That’s all there is to having FreeRTOS running in your sketches. So simple.

Next Steps

Blink_AnalogRead.ino is a good way to take the next step as it combines two basic Arduino examples, Blink and AnalogRead into one sketch with in two separate tasks. Both tasks perform their duties, managed by the FreeRTOS scheduler.

#include

// define two tasks for Blink and AnalogRead
void TaskBlink( void *pvParameters );
void TaskAnalogRead( void *pvParameters );

// the setup function runs once when you press reset or power the board
void setup()
{
// Now set up two tasks to run independently.
xTaskCreate(
TaskBlink
, "Blink"; // A name just for humans
, 128      // This stack size can be checked and adjusted by reading the Stack Highwater
, NULL
, 2        // Priority, with 3 (configMAX_PRIORITIES - 1) being the highest, and 0 being the lowest.
, NULL );

xTaskCreate(
TaskAnalogRead
, "AnalogRead";
, 128      // Stack size
, NULL
, 1        // Priority, with 3 (configMAX_PRIORITIES - 1) being the highest, and 0 being the lowest.
, NULL );

// Now the task scheduler, which takes over control of scheduling individual tasks, is automatically started.
}

void loop()
{
// Empty. Things are done in Tasks. Never Block or delay.
}

/*--------------------------------------------------*/
/*---------------------- Tasks ---------------------*/
/*--------------------------------------------------*/

void TaskBlink(void *pvParameters) // This is a task.
{
(void) pvParameters;

// initialize digital pin 13 as an output.
pinMode(13, OUTPUT);

for (;;) // A Task shall never return or exit.
{
digitalWrite(13, HIGH); // turn the LED on (HIGH is the voltage level)
vTaskDelay( 1000 / portTICK_PERIOD_MS ); // wait for one second
digitalWrite(13, LOW); // turn the LED off by making the voltage LOW
vTaskDelay( 1000 / portTICK_PERIOD_MS ); // wait for one second
}
}

void TaskAnalogRead(void *pvParameters) // This is a task.
{
(void) pvParameters;

// initialize serial communication at 9600 bits per second:
Serial.begin(9600);

for (;;)
{
// read the input on analog pin 0:
int sensorValue = analogRead(A0);
// print out the value you read:
Serial.println(sensorValue);
vTaskDelay(1); // one tick delay (15ms) in between reads for stability
}
}

Next there are a number of examples in the FreeRTOS Quick Start Guide.

One last important thing you can do is to reduce device power consumption by not using the default loop() function for anything more than putting the MCU to sleep. This code below can be used for simply putting the MCU into a sleep mode of your choice, while no tasks are unblocked. Remember that the loop() function shouldn’t ever disable interrupts and block processing.

#include // include the Arduino (AVR) sleep functions.

loop() // Remember that loop() is simply the FreeRTOS idle task. Something to do, when there's nothing else to do.
{
// Digital Input Disable on Analogue Pins
// When this bit is written logic one, the digital input buffer on the corresponding ADC pin is disabled.
// The corresponding PIN Register bit will always read as zero when this bit is set. When an
// analogue signal is applied to the ADC7..0 pin and the digital input from this pin is not needed, this
// bit should be written logic one to reduce power consumption in the digital input buffer.

#if defined(__AVR_ATmega640__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega1281__) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega2561__) // Mega with 2560
DIDR0 = 0xFF;
DIDR2 = 0xFF;
#elif defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644PA__) || defined(__AVR_ATmega1284P__) || defined(__AVR_ATmega1284PA__) // Goldilocks with 1284p
DIDR0 = 0xFF;

#elif defined(__AVR_ATmega328P__) || defined(__AVR_ATmega168__) || defined(__AVR_ATmega8__) // assume we're using an Arduino with 328p
DIDR0 = 0x3F;

#elif defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega16U4__) // assume we're using an Arduino Leonardo with 32u4
DIDR0 = 0xF3;
DIDR2 = 0x3F;
#endif

// Analogue Comparator Disable
// When the ACD bit is written logic one, the power to the Analogue Comparator is switched off.
// This bit can be set at any time to turn off the Analogue Comparator.
// This will reduce power consumption in Active and Idle mode.
// When changing the ACD bit, the Analogue Comparator Interrupt must be disabled by clearing the ACIE bit in ACSR.
// Otherwise an interrupt can occur when the ACD bit is changed.
ACSR &= ~_BV(ACIE);
ACSR |= _BV(ACD);

// There are several macros provided in the header file to actually put
// the device into sleep mode.
// SLEEP_MODE_IDLE (0)
// SLEEP_MODE_ADC (_BV(SM0))
// SLEEP_MODE_PWR_DOWN (_BV(SM1))
// SLEEP_MODE_PWR_SAVE (_BV(SM0) | _BV(SM1))
// SLEEP_MODE_STANDBY (_BV(SM1) | _BV(SM2))
// SLEEP_MODE_EXT_STANDBY (_BV(SM0) | _BV(SM1) | _BV(SM2))

set_sleep_mode( SLEEP_MODE_IDLE );

portENTER_CRITICAL();
sleep_enable();

// Only if there is support to disable the brown-out detection.
#if defined(BODS) && defined(BODSE)
sleep_bod_disable();
#endif

portEXIT_CRITICAL();
sleep_cpu(); // good night.

// Ugh. I've been woken up. Better disable sleep mode.
sleep_reset(); // sleep_reset is faster than sleep_disable() because it clears all sleep_mode() bits.
}

o that’s all there is to it. There’s nothing more to do except to read the FreeRTOS Quick Start Guide.
Further reading with manicbug, and by searching on this site too.

General Usage

FreeRTOS has a multitude of configuration options, which can be specified from within the FreeRTOSConfig.h file. To keep commonality with all of the Arduino hardware options, some sensible defaults have been selected.

The AVR Watchdog Timer is used with to generate 15ms time slices, but Tasks that finish before their allocated time will hand execution back to the Scheduler. This does not affect the use of any of the normal Timer functions in Arduino.

Time slices can be selected from 15ms up to 500ms. Slower time slicing can allow the Arduino MCU to sleep for longer, without the complexity of a Tickless idle.

Watchdog period options:

  • WDTO_15MS
  • WDTO_30MS
  • WDTO_60MS
  • WDTO_120MS
  • WDTO_250MS
  • WDTO_500MS

Note that Timer resolution is affected by integer math division and the time slice selected. Trying to accurately measure 100ms, using a 60ms time slice for example, won’t work.

Stack for the loop() function has been set at 192 bytes. This can be configured by adjusting the configIDLE_STACK_SIZE parameter. It should not be less than the configMINIMAL_STACK_SIZE. If you have stack overflow issues, just increase it. Users should prefer to allocate larger structures, arrays, or buffers using pvPortMalloc(), rather than defining them locally on the stack. Or, just declare them as global variables.

Memory for the heap is allocated by the normal malloc() function, wrapped by pvPortMalloc(). This option has been selected because it is automatically adjusted to use the capabilities of each device. Other heap allocation schemes are supported by FreeRTOS, and they can used with additional configuration.

Never use the Arduino delay() function in your Tasks, as it burns CPU cycles and doesn’t place the Task into Blocked State, allowing the Scheduler to place other lower priority tasks into Running State. Use vTaskDelay() or vTaskDelayUntil() instead. Also never delay or Block the Arduino loop() as this is being run by the FreeRTOS Idle Task, which must never be blocked.

Errors

  • Stack Overflow: If any stack (for the loop() or) for any Task overflows, there will be a slow LED blink, with 4 second cycle.
  • Heap Overflow: If any Task tries to allocate memory and that allocation fails, there will be a fast LED blink, with 100 millisecond cycle.

Compatibility

  • ATmega328 @ 16MHz : Arduino UNO, Arduino Duemilanove, Arduino Diecimila, etc.
  • ATmega328 @ 16MHz : Adafruit Pro Trinket 5V, Adafruit Metro 328, Adafruit Metro Mini
  • ATmega328 @ 16MHz : Seeed Studio Stalker
  • ATmega328 @ 16MHz : Freetronics Eleven, Freetronics 2010
  • ATmega328 @ 12MHz : Adafruit Pro Trinket 3V
  • ATmega32u4 @ 16MHz : Arduino Leonardo, Arduino Micro, Arduino Yun, Teensy 2.0
  • ATmega32u4 @ 8MHz : Adafruit Flora, Bluefruit Micro
  • ATmega1284p @ 20MHz : Freetronics Goldilocks V1
  • ATmega1284p @ 24.576MHz : Seeed Studio Goldilocks V2, Seeed Studio Goldilocks Analogue
  • ATmega2560 @ 16MHz : Arduino Mega, Arduino ADK
  • ATmega2560 @ 16MHz : Freetronics EtherMega
  • ATmega2560 @ 16MHz : Seeed Studio ADK
  • ATmegaXXXX @ XXMHz : Anything with an ATmega MCU, really.

Files and Configuration

  • Arduino_FreeRTOS.h : Must always be #include first. It references other configuration files, and sets defaults where necessary.
  • FreeRTOSConfig.h : Contains a multitude of API and environment configurations.
  • FreeRTOSVariant.h : Contains the AVR specific configurations for this port of FreeRTOS.
  • heap_3.c : Contains the heap allocation scheme based on malloc(). Other schemes are available and can be substituted (heap_1.c, heap_2.c, heap_4.c, and heap_5.c) to get a smaller binary file, but they depend on user configuration for specific MCU choice.

42 thoughts on “Arduino FreeRTOS

  1. Pingback: freeRTOS and libraries for AVR ATmega with Eclipse IDE | feilipu

  2. Hello, I wanted to ask, if its possible to use the FreeRTOS library, with visual studio and the visual micro plugin. I ask because I get some compiler errors. In mywebsite below, there is a link to a forum post, where i describe the problem more precisely. I would be glad if someone could tell me why this isnt working properly. best regards herophil322

  3. What is the configured heap size and where to I find this setting? I looked for configTOTAL_HEAP_SIZE but could not find it in the library.

    Thanks.

    • Hi Kafolske,

      Short answer is that it is auto configured based on the heap size provided to malloc() by configuration avr-libc.
      This is based on the option of heap_3.c for memory management.
      There will be an error (fast blink) when the heap has been exhausted.

      Why do it this way?
      Because the avr-libc code automatically recognises which ATmega devices is being used, and the amount of RAM (heap) available.
      That means that I don’t have to care which Arduino board is being used.
      You can tune this if you want to using malloc() tuning in the linker.

      When I’m building a project, I use one of the other heap_*.c heap memory schemes (mainly heap_4.c), which allow me to define the heap more precisely, and allocate it differently depending on which hardware.

      If you feel inclined, you can swap the memory management code for one of the other versions provided, and that will give you the control you are looking for.

      And then you’re using FreeRTOS the way it should be used.

      Good luck, Phillip

  4. The reason I ask the earlier question is that I have 1k of RAM available after including the library. I am only able to create two tasks with a stack of 128 bytes each. When I create the third task, I see the fast flashing LED which is presumably the malloc failure when creating the third task.

    Thanks.

    • Kafolske,

      Managing memory can be very frustrating. Some tips.

      You can tune the stack size of each Task individually, so use the stack high water functions to check this,
      and reduce the each task stack where you can.
      Try to keep variables off the stack, by making them a global variable, or declared as “static” if declared in the Task.

      As an example see this FreeRTOS style “Blink” program which has both stack and heap highwater checking functions.

      When using anything other than heap_3.c, you can check the heap high water mark,
      and I tend to check this often during building a project, and then remove these code lines later.

      So try substituting one of the other heap_1.c, heap_2.c into the library, if you like.
      You will need to add the additional definitions for using this code, into the Variant header file.

      For the Uno this is the configuration that I use that has 1530 bytes available for the heap.


      // Cannot emphasise how important it is to watch and massage this heap size number.
      // Greater than 100% memory usage. Subtle fail.
      // Less than 96%. Typically every byte counts for 328p.
      // Watch for the stack overflowing, if you use interrupts. Use configCHECK_FOR_STACK_OVERFLOW
      #define configTOTAL_HEAP_SIZE ( (size_t ) 1530 ) // used for heap_1.c, heap_2.c, and heap_4.c only

      Good luck, Phillip

  5. thank you very much for sharing the port – it looks great

    could i ask – is a short duration flash at a freq ~1 sec indicative of an error? (its not either of the two you described above). i see that behaviour with the ‘Blink_AnalogRead’ example on closing the arduino serial monitor. on adding another task to toggle the level i see that that task is blocked when the led flashes at ~1Hz with short duration (its not the ‘TaskBlink’ as that has a 1 sec on time).

    could i also ask is there any guide lines about which arduino library methods can be called in tasks? or is it necessary to check all code for thread safety and re-entrancy etc?

    thanks in advance for any comments
    mike

    • Mike,

      I think the only guideline that I can think of regarding Arduino methods is to watch for global interrupt disabling situations. Some libraries may (and the Software Serial comes to mind immediately) disable the global interrupt for long periods to be able to generate accurate pulse trains. This doesn’t work when you’re trying to use the WDT to schedule tasks.

      Otherwise, the loop() function should never block (or busy wait using delay() for example). The loop() function is called by the IdleTask and therefore needs to finish often to enable the scheduler to work. The fact that configIDLE_SHOULD_YIELD is configured may assist to avoid this issue.

      There are only two error flashes signaled, as noted in the Github readme, and in this post, for malloc fail (heap overflow), and stack overflow. If either of these issues happen you should see the LED flash timing noted. Otherwise, I’m not sure what’s going on.

      Otherwise, generally for serious usage, I’d suggest moving to one of the static heap_x.c mechanisms for heap allocation, configured to suit your preferred platform. That will save you some headaches, as actual heap usage can be tracked using freeRTOS tools which is much more transparent than a blinking LED as an error message.

      Enjoy,
      Phillip

  6. thank you very much Phillip for the excellent tips. i will look into alternative tools to the Arduino ide / tool chain so can better investigate and understand whats going on, and look into the freeRTOS tools you mentioned

  7. Mike, (and anyone else reading later),

    I would also like to note that understanding memory allocation and management is an essential tool for using microcontroller platforms, like the Arduino . And, I’ve got to say that I’ve only got a tenuous grasp on it myself.

    But when using the Arduino tools (avr-gcc C compiler and avr-libc libraries) you’re given a Stack and a Heap. Understanding the use of these two memory regions is important basis.

    And then, to make matters more complex, FreeRTOS uses either the C heap (using heap_3.c which uses the avr-libc malloc() and free() functions) or its own allocated heap in the .bss region (when using heap_1.c or the other heap mechanisms). This FreeRTOS heap is then used to allocate FreeRTOS Task Control Blocks (TCB) which include each Task Stack.

    So in the case of Arduino FreeRTOS we have the TCB and Task Stacks allocated on the C heap.

    For the Arduino UNO with only about 1,500 bytes of RAM available for the C heap (2kB total, but excluding globally defined and initialised variables (.data), globally defined but uninitialised variables (.bss), and the C stack), it is easy to see that FreeRTOS Task Stacks and each TCB that are allocated exclusively to a particular Task can consume that limited memory very easily, leading to weird memory effects (crashes).

    Many a painful session spent understanding these things, is all part of the learning experience.

    Cheers,
    Phillip

  8. Hi Phillip,
    I like your post here, it helped me to start with FreeRTOS for Arduino.
    Now I’m trying to run some of the examples that come with FreeRTOS.
    I tryed BlockQ.c.
    First question: I must rename it to BlockQ.ino in order to load it in the IDE, isn’t it?
    Second Question: Inside the code says that configSUPPORT_DYNAMIC_ALLOCATION must be set to 1.
    I searched for this option and cound’t found it, so I went to “yours” FreeRTOSConfig.h and put it there.
    What I did is correct?
    Is the option in somewhere that I didn’t search?
    Why “yours” FreeRTOSConfig.h doesn’t have this option.
    Thanks a lot in advance. Best regards,
    Luis Vital

    • I like your post here, it helped me to start with FreeRTOS for Arduino.

      Thanks Luis.

      Now I’m trying to run some of the examples that come with FreeRTOS.
      I tryed BlockQ.c.
      First question: I must rename it to BlockQ.ino in order to load it in the IDE, isn’t it?

      Yes. The Arduino IDE and Windows prefers that you rename your file to .ino.

      Second Question: Inside the code says that configSUPPORT_DYNAMIC_ALLOCATION must be set to 1.
      I searched for this option and cound’t found it, so I went to “yours” FreeRTOSConfig.h and put it there.
      What I did is correct?

      Starting with v9.0.0, FreeRTOS supports STATIC Allocation options for tasks, queues, etc.
      In v8.2.3 and lower versions, there is only DYNAMIC Allocation available. A degree of control of allocation can be obtained by using the heap_1.c or heap_2.c options to control where memory allocation is assigned, and then heap management can also identify how much heap remains.

      The configSUPPORT_DYNAMIC_ALLOCATION option is not relevant to v8.2.3 or lower, but is not harmful in any way.

      Is the option in somewhere that I didn’t search?
      Why “yours” FreeRTOSConfig.h doesn’t have this option.

      See above. I haven’t moved to FreeRTOS v9.0.0 yet.
      I’m waiting for the first bug fix release before migrating.

      Good Luck, Phillip

    • FreeRTOS is supported on many MCU, and porting it to a new MCU is straightforward.

      My solution here supports all AVR ATmega based Arduino boards, such as Uno, Leonardo, and Mega. Others have support for Cortex Mx based boards like Teensy for example.

      This repository won’t support Due because it is not an ATmega MCU. I can’t advise where to find support for the Due, I’m afraid. It is effectively EoL.

  9. Hi Philip,
    I want to execute the tasks below 5ms, But there is certain limitations and the scheduler runs on watchdog timer on arduino uno. Is it possible to run the tasks at 5ms or below on arduino mega as it is supposed to contain 6 timers?

    • Certainly.

      Cut the Timer configuration from port.c here. You can set the configuration to use any of the timers present on the ATmega2560. The example uses Timer0 (8 bit), Timer2 (8 bit RTC), and Timer1 and Timer3 (16 bit).

      But be aware you will have to manage compilation conflict, as the Arduino core code configures everything in advance, whether needed or not.

      • Hello,
        Can you please speak more on how to change the FreeRTOS code to run on a faster scheduler tick? I need a 0.5 mS scheduler tick for my project. Should I just copy and paste all of your “port.c” into my “port.c” file in my FreeRTOS file structure? I’m going to use timer 1 for my application since I’m not using any servo or analogWrite() functions. Is that all that needs to be modified?
        What additional steps need to be taken?

      • John,

        yes, you’re right. The place to start is with the port.c code in my avrfreertos repository. This provides all of the optional configurations for using (almost) any timer available on the AVR.
        port.c

        Beyond this, you may find it useful to use the configuration in the FreeRTOSBoardsDefs.h file, which is how I control the settings for individual timers in the ports.c file. You’ll probably need to roll your own, to suit what you need, but the precedent is there.
        FreeRTOSBoardDefs.h

        Also, FreeRTOS has a multitude of configuration options. My selection may not suit what you need, so the FreeRTOSConfig.h file can be massaged to tune things to suit your needs. Don’t try to reduce the minimum task stack size. About 85 bytes is the safe minimum. Although if you are doing things in the Arduino loop() function, which is called by the IdleTask, then you may need to increase the Idle Task Size in configIDLE_STACK_SIZE.
        FreeRTOSConfig.h

        Good luck.

    • Yoflippo,

      It is absolutely possible to use any AVR Timer to drive the FreeRTOS Scheduler. But, as always, the devil is in the detail.

      The Arduino IDE is designed for people taking their first steps in the world of microelectronics and microcontrollers. Many Arduino users don’t even care that they’re using a microcontroller; they just want to take the existing sketches (not even called programs) and play around. Therefore, to make it easy to do “stuff” the Arduino “core” preconfigures almost every resource on the AVR microcontroller during the initialisation phase, even before the user gets to do their setup().

      Because all of the Timers are preconfigured in advance (with the exception of the Watchdog Timer), there are two types of failure that you will have to work around to use them. Firstly, compilation conflicts with the Arduino core. And secondly, run-time conflicts where things don’t work as expected.

      To the first issue, every AVR Timer is preconfigured in the Arduino core, using its normal Interrupt Vector. This is done in the wiring.c and WInterrupts.c. If you try to configure any Timer in your library using its normal Vector, then you will have a compile error because the Interrupt will be defined twice.

      It is possible to work around this using an alternative Timer Interrupt Vector as I have done in my implementation for the DAC using Timer 3 in the Goldilocks Analogue. But this is messy, and very dependent on the availability of Timers, and their Vectors, across the AVR range of MCU.

      In contrast, the Watchdog Timer is not configured by the Arduino IDE and the configuration is constant (the same) for every ATmega MCU.

      To the second issue of run-time conflicts. It is very possible to work around the Timer pre-configuration issue to provide specific solutions suitable for your application. The only thing that is then problematic is that certain Arduino features depend on using Timers under the covers. This includes the Tones function that uses Timer 2, and analogWrite() that uses any or all Timers to generate PWM output.

      Again, as the Watchdog Timer is not used by the Arduino IDE, there are never conflicts caused by its use to drive the FreeRTOS Scheduler. This is the case across all the Arduino AVR Boards.

      TL;DR. Using the Arduino IDE doesn’t presuppose you know what you’re doing. Hence this library has tried to provide a robust solution to introduce the capabilities of FreeRTOS, and get a feel for how it can help, without the need to know what you’re doing. You can use any Timer you like if you know what you are doing, and doing that is part of the fun.

  10. Hi,

    Could you explain why other timers can not be used in your solution. the WDT is pretty slow and the other faster timers would come in handy. Hope you can help!

    • Yoflippo,

      yes, you’re quite correct. the WDT is a very slow timer. But this has some advantages that I’ve used for some projects.

      Generally, I find that there are two things I need to do. 1. have very accurate high speed timing, and 2. manage a number of different tasks or threads that have quite different timing requirements.

      To get a very regular high speed interval I usually configure a hardware Timer to drive an interrupt routine, and run the FreeRTOS Scheduler interrupt with NO BLOCK enabled. This enables the global interrupt even as the scheduler is running. This is necessary because the AVR ATmega doesn’t have interrupt nesting, and we want to make sure that the Timer Interrupt is not prevented from running. I did this when building an audio (analogue) output system on the Goldilocks Analogue. In this case we want to output SPI Word to configure the DAC every 21 microseconds for 48kHz stereo audio!

      To manage slower simultaneous Tasks, like sampling a temperature every 500 milliseconds, or writing to a screen every 50 milliseconds, using the Watchdog Timer is very suitable.

      There is another advantage for using the WDT, and that comes from its ability to wake up a sleeping MCU. We can can use this to run a very slow watchdog timer with (say) 500 millisecond timing, and put the MCU to sleep once it has run its tasks. This will save substantial power (order of 1000x less) if the amount of processing time is small compared to the amount of sleeping time.

      Your design process has to consider the right way to achieve what you need. In some cases it might be using hardware Timers, in other it might be using the FreeRTOS scheduler with fast cycle Interrupt. All part of the fun and learning experience.

  11. Pingback: Programación Arduino | Aprendiendo Arduino

  12. Hi
    Since the ArduinoIDE is not really practical to develop, I’m trying to get freertos to work with a makefile but i’m having some issues. I tried with inotool(http://inotool.org) and a direct makefile(https://github.com/ladislas/Bare-Arduino-Project) but both tools/toolchains have issues with freertos. I tried the basic example (Blink Analogread). With the IDE it works but with the toolchain it compiles and flashes but it does nothing. But a basic ArduinoIDE project (Blink) works with the toolchain.
    Do you have any idea why? I hope I didn’t describe it too complicated..
    What works:
    ArduinoIDE + Freetos project
    Makefile + Arduino basic project
    What doesn’t work:
    Makefile + Freetos project

  13. Hi.
    I want to control several motors, which start sequentially with a 40 minute timer respectively.
    Each timer independently timed? As the engines are started?
    And how can i do it? , with Arduino FreeRTOS.
    Thanks in advance for your reply.

  14. Pingback: #244 Multiple tasks on an Arduino?😲FreeRTOS can do it – so can you😜 – DISTRIBUTOR ALAT PENGUSIR TIKUS

  15. Pingback: Arduino_FreeRTOS_Library: GitHub File Free Download

  16. Hello, is it possible to customize your FreeRTOS library only for one Arduino project? I have multiple Arduino project with default configuration but now I need to configure one project to use Timer1 not WDT. How to do that if I don’t want to apply these changes to another projects? Thanks.

  17. Pingback: استفاده از الگوهای خواب در کتابخانه freeRTOS - مجله آموزشی سیستم های نهفته

Leave a comment