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.
    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.
    vApplicationMallocFailedHook();  // Possibly we've failed trying to initialise heap for the scheduler. Let someone know.

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 v9.0.0 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 v9.0.0-1.

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.


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.6.9 on Windows 10.

// Device:   loop() -> FreeRTOS | Additional Program Storage
// Uno:         444 ->   7340   |     21%
// Goldilocks:  502 ->   7408   |      6%
// Leonardo:   3624 ->  10508   |     24%
// Yun:        3618 ->  10502   |     24%
// Mega:        656 ->  24108   |      9%

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 <Arduino_FreeRTOS.h>

// 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.
    ,  (const portCHAR *) "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 );

    ,  (const portCHAR *) "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.

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

  for (;;)
    // read the input on analog pin 0:
    int sensorValue = analogRead(A0);
    // print out the value you read:
    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 <avr/sleep.h>  // 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;

// 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.

// There are several macros provided in the header file to actually put
// the device into sleep mode.

set_sleep_mode( SLEEP_MODE_IDLE );


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

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 128 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.


  • 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.


  • 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.

ArduSat XRAMFS Prototyping

It is not every day that I get to tell the family I’m doing “rocket science”, but I hope over the past few days, it can be an exception. Space, the final frontier. In this case, it was a lack of space and the frontier it creates, that got me thinking.

At the recent Linux Conf AU Jon Oxer spoke about Freetronics’ efforts in designing the payload for the upcoming NanoSatisfi ArduSat1 launch (pictured below). Jon mentioned in the presentation that the AVR freeRTOS code compilation that I’ve been supporting is being used in the Supervisor node of that platform.


I immediately thought that it would be great to build a distributed cache RAM system to support each of the ATmega328p “Arduino” Client nodes, using the XRAM capabilities of the ATmega2561 Supervisor node. So, I did.


Using this prototype system, each Arduino Client node now has sole access to 32kByte of XRAMFS in addition to their 2kByte of internal RAM.

Initial performance measured is 422kByte/s throughput for the swap function. In other words, half of the entire Arduino RAM can be swapped with the contents of XRAMFS in just 4.74ms.

I’ve also the code for supporting a centralised SD Card on this platform to Sourceforge AVRfreeRTOS, and written about it at ArduSat SD Card Prototyping.


In working with the Arduino hardware I’ve found that the severe limitation in RAM space causes constraints on what can be done. For example, Ethernet, USB and other modern applications need kBytes of buffer to be used effectively, and the ATmega328p used as the Arduino Uno platform supports a total of only 2kB RAM.

Using the Arduino Mega (or Android ADK hardware) has been the saviour of that situation for me, offering an identical environment, but 8kByte of RAM as a playground. And, most importantly, the ability to directly connect 0 wait-state external SRAM.

This XRAM capability of the ATmega2560 and ATmega2561 has been exploited by Rugged Circuits in their QuadRam module, which offers 512kByte of SRAM in one small package.


Therefore, using common off the shelf technology, I had the materials available to test the theory that building a XRAMFS system, to support the ArduSat platform, would work.

This allows each ArduSat Client to store 16 TIMES more data than it can currently access, and have access to that data at a relatively high speed from a medium not subject to wear (such as for example an SD card).

Ingredients & Build

This section looks at the ingredients and how to construct the prototype.

Supervisor Node – Arduino Mega / Freetronics EtherMega / Android ADK

The ArduSat Supervisor node is based on the ATmega2561 MCU, because it is significantly smaller than the ATmega2560 MCU used in the Arduino Mega platform. The only difference between the two chips is that the ATmega2561 doesn’t provide as many Ports, and has only 64 Pins versus 100 Pins on the ATmega2560.


For this prototyping, the ATmega2560 is necessary, because I elected to use pin change interrupts as part of the bus protocol. Also, the Arduino Mega platform is readily available. I don’t even know where I’d go to get a ATmega2561 board…

The use of rainbow hook-up wire was essential for the success of the prototype.

Client Node – Arduino Uno / Freetronics Eleven

The ArduSat Client node is designed to be identical to the Arduino Uno platform, to ensure that it is absolutely easy for people to test code they intend to run in space. Therefore a variety of Arduino Uno devices are being used (basically, whatever I had around).

XRAM Module – Rugged Circuits QuadRAM

I’ve implemented using the Rugged Circuits QuadRAM and the MegaRAM previously. These modules slip over the end of the Arduino Mega platform, instantly enabling either 512kByte or 128kByte of zero wait state SRAM, mapped to the system address space. They also conveniently bring out the SPI interface onto through-hole for pins.


Something about the ability to create 16x 32kByte XRAM pages, linked with 16x Client nodes, seemed like synchronicity.


The prototype platform is designed to be the classic multi-slave SPI bus layout. This design is demonstrated in the AVR151 document and, in excerpt, is produced below.


Because of my decision to use the Pin Change Interrupts as part of the bus protocol, The Supervisor node (SPI Master) would use the Port K and Port J pins to fill the role of individual Slave Select (SS) pins. The Client nodes would each use their normal SS pin (PB2) to connect to the Supervisor.

In designing for 16x Client nodes, there is a limitation on Port J in that the good folks at Arduino determined not to break out all of the pins which, together with sharing PCINT8 with the Rx0 pin, significantly limits the number of Clients feasible on the prototype platform.

In practice, 8 Client nodes attached to all the pins on Pork K is the simple alternative. As luck (or good planning) would have it, those pins are all brought out onto one connector on the Arduino Mega platform, as evidenced by these pictures.

Amongst friends, a direct connection of the SPI SCK, MISO, and MOSI lines to all Clients is optimal. But in a shared environment, it would make sense to use FET bus isolation to keep Clients from physically attaching to the SPI bus until their SS line is held low by the Supervisor. A gram of hardware prevention can cure a tonne of software ill, as a “rogue” Client could otherwise potentially lock up the SPI bus for all, and the guys in the ISS won’t be happy if asked to hit the reset button.

Bus Protocol

Hey! – Yeah What? – This! – OK

That’s the protocol. Works in the home. Works in the office. Works the world over.


Information to this Saleae Logic chart below in Client Implementation section.


The Supervisor node holds all the PCINT pins high. If a Client wants to initiate a Read/Write/Swap transaction, it will pull its SS line low for 30µs. This needs to be long enough for the Supervisor to register an interrupt and process it. If multiple Clients call out simultaneously, no problem, the Supervisor will grab all of the requests and push them onto a queue of requests to serve.

Yeah What?

At the next opportunity, the Supervisor serving task will pop a request off the queue, and identify which Client made the request. It will also check if there were other simultaneous requests, and push them back to the front of the queue.

The Supervisor then pulls the relevant Client SS line low. The Client has been listening for this, and at this point it enables its Slave interface to the SPI bus, and the two swap acknowledgements. When the Supervisor receives the ACK code, it knows the Client is ready, so it requests a command.


When the Client (SPI Slave) has received the Supervisor ACK code, it prepares a command, and is prepared to either read, write or swap XRAMFS data under the command of the Supervisor (SPI Master).

The command set implemented by this protocol can be easily extended to include accessing other shared resources connected to the Supervisor node. This could include analogue sensors, SDCARD mass storage (though using the SPI bus would offer a degree of complexity), or serial interfaced devices.


At the end of one command, with the data transaction complete, a final byte is exchanged to ensure that the Client has remained in sync with the Supervisor, and the SPI bus is released by the Client. It is important the Client stays off the SPI bus. The Supervisor then processes the next Yeah What? request.

Supervisor Implementation – freeRTOS

The Supervisor is implemented as a freeRTOS task, using standard SPI bus libraries contained in my code base. These libraries (now that this project has worked them over) are about as optimised as is possible to write in C, and achieve a good throughput over the SPI bus.

There are two (or one) PCINT based Interrupt that reads the PCINT pins and pushes the raw pin state onto a queue. This process traps multiple simultaneous requests, overcoming any interrupt masking or race conditions. Currently 30µs are allowed for the interrupts to execute. 10µs has been tested, but depending on how long the Supervisor stays in “Critical” state (interrupts off) processing other (non XRAMFS) tasks this time can be adjusted.

From idle, the Supervisor takes only 90µs to 0.1ms to pop a request from the queue and action it. Under load, it could take as long as 64ms to action a request. As soon as the pin state is collected it is processed to identify which SS line triggered the call, and therefore which bank of XRAM should be enabled. Also, at this time I check that no additional requests are pending from the same pin state. If so, the remaining pin state is pushed back on the queue to get next time round.

The exchange of acknowledgements ensures that both sides are speaking SPI, and are set to proceed.

The command contains the action (read / write / swap / test), the address of the XRAMFS block, the size of the XRAMFS block, and a CRC byte.

The bus transaction speed is dependent on the SPI Master SCK clock divisor. Optimally, a SPI Slave can receive data at 1/4th of its system clock. Currently, it is set to one 1/8th, therefore theoretical performance is double that of the logic capture above.

Initially, I determined to calculate a CRC byte to store along with the data, but the calculation time is large compared to the transaction time, and therefore too costly to implement at the protocol level. The application should utilise the CRC when it recovers data to confirm that the data is intact, and not irradiated.

Also, error checking following the transfer could be implemented. But at this stage I think it is better to have the Client do all sanity and error checking of its own data.

Client Implementation – freeRTOS or Arduino IDE

The Client is implemented in freeRTOS as a simple library function, that is passed a command structure, and a pointer to local RAM to be Read/Write/Swap. Some details below.

typedef enum { Huh        = 0, // Client didn't issue us a command, so just break.
               Read       = 1, // read from XRAMFS
               Write      = 2, // write to XRAMFS
               Swap       = 3, // read from both XRAMFS &amp; local RAM, and swap
               Test       = 4  // do something else, to be determined
} RAMFSCommand; // from point of view of the client (Arduino 328p)

typedef struct        /* structure to hold the RAMFS info */
{ RAMFSCommand       ram_cmd;        // Read / Write / Swap / Test
  size_t             ram_addr;       // Address of first byte of RAM in a RAMFS (greater than RAM_START_ADDR)
  uint16_t           ram_size;       // Size of RAM block in RAMFS (less than RAM_COUNT or 32kByte)
  uint8_t            ram_crc8;       // Calculated CRC of stored data
} xRAMFSarray, * pRAMFSarray;

uint8_t ramfs_transfer_block( pRAMFSarray pRAMFS_block, uint8_t *data );

I used C and the freeRTOS platform because it is easiest for my environment, and I know it best. But, I’ll re-write it as a library in the Arduino IDE environment as needed. It won’t be too hard.

The client can use the XRAMFS malloc function to manage RAM allocation. A very simple malloc has been built, which can’t free XRAMFS. But, it can be simply ignored if desired and the command structure can be filled manually.

Initially, I implemented an interrupt driven semaphore system to manage the Yeah What? part of the bus protocol, but typically the Supervisor responds so quickly that the time to do several context swaps generated by the interrupt exceeded the time the Supervisor was prepared to wait. A simple wait loop keeps the Client on ready standby for 90µs so it can complete the transaction in the shortest time.

The Client code has no knowledge of where its XRAM is located on the Supervisor. Therefore the code is orthogonal and constant, irrespective which Client being used. This is a very useful feature where the author may not know in advance which ArduSat Client his code will be running upon.

Client application code should be written to make use of the Swap XRAMFS <-> RAM capability. This makes best use of the SPI bus features to combine Read and Write into one transaction, effectively doubling throughput over the Write plus Read combination.

The user interface (monitor) is just for initial testing. I’ll have to write a load generation rig to find out what this baby can do, but that can wait for the next post. The logic analyser has captured the result of the > r (read) command in the below command line sequence. We can see the 20µs (now 30µs) Hey! on the Slave Select, 90µs pass before the acknowledgement bytes are swapped (only one cycle needed), 6 bytes of command structure are passed (Read command is 0x01), and then the data is read out of XRAMFS to the Client.


Design Notes

The basis of every design: detailed functional specifications, hardware design, and user interface documentation. Oh, and scribbles much.



I’ve updated the code on 22 February to remove some oversights in the Client main program, and added the OK check byte to the protocol. Code as usual on AVRfreeRTOS on Sourceforge.

Updated on 23 February to include some error checking on Supervisor side (preventing malicious Client requests), and on Client side preventing hang if the Supervisor is AWOL. Also removed the aggressive SPI timing utilising receive double buffering, as it often caused errors, and had no performance effect.

Initial performance measured is about 422kByte/s throughput for the swap function. Specifically 4.73825ms is needed for a complete 2048Byte data payload transaction (including sync, command, & OK timing). This also includes freeRTOS task swapping, as the Supervisor task is run with interrupts enabled in normal mode.

Have fixed some code issues on 4 March, mainly around a few µs delays required to let things run their course.

Now the platform is running stable with 4x Clients. A video is here

And here is a screenshot of the 4x terminals.

4xXRAMFS Client Monitors Screenshot

April 27th – I’ve uploaded the code for supporting a centralised SD Card on this platform to Sourceforge AVRfreeRTOS, and written about it at ArduSat SD Card Prototyping.

freeRTOS and libraries for AVR ATmega with Eclipse IDE

I’ve created a Sourceforge project as a place to host all my current tools and working environment. The Sourceforge site is now 4 years old, and there’s a GitHub site too, which is now the most up to date repository

Preferred: Github freeRTOS & libraries for AVR ATMEGA

Secondary: Sourceforge freeRTOS & libraries for AVR ATMEGA

The Sourceforge repository has become so complex, with so many libraries, I thought that it was about time to make a simple version, which has the minimum implementation to get started. No additional libraries included. One timer option, using the watchdog timer. One heap option, using avr-libc malloc. One example application, just a blink with two tasks, for Uno, Mega, and Goldilocks boards.

Github minimum AVRfreeRTOS

The thing about open source. Sometime you have to give back.

Things I’m really happy about:

  • Arduino Uno family ATmega328p, Freetronics EtherMega (Arduino Mega2560), and Goldilocks ATmega1284p, scheduling and IO works.
  • Being able to use any Timer on the AVR as the system Tick. In practice this means Timer0 on 328p (Arduino Uno), Timer3 on 2560 (Arduino Mega) and 1284p (Pololu SVP) and Timer2 on 1284p with 32.768kHz watch crystal (Freetronics Goldilocks). The watchdog timer has also been implemented, and if there is no critical need for accurate timing, this is the lowest resource impact system tick.
  • Converting all of the relevant libraries to be friendly to a RTOS system. No delay busy-wait loops etc. Everything defers to (is interruptible by) the scheduler when waiting, or is driven from interrupts.
  • Having many finished projects, that are good demonstrations of lots of AVR and freeRTOS capabilities.
  • Having the Sparkfun LCD Shield working properly, with printf string formatting.
  • Having the Rugged Circuits QuadRAM 512kByte and MegaRAM 128kByte RAM extensions working on ATmega2560.
  • Porting ChaN FatF microSD card support for a variety of uSD shield cages.
  • Porting Wiznet W5100, W5200, and W5500 drivers for Arduino Ethernet shields.
  • Porting Wiznet and uIP DHCP and HTTP applications, creating options for implementing a basic web server.
  • Properly implementing semaphores for access to resources (ports, interfaces, ADC, LCD).
  • Properly implementing queues for transferring data between tasks (threads).

The repository of files on Sourceforge freeRTOS & libraries for AVR ATMEGA is a working collection for a freeRTOS based platform using the AVR-GCC and AVRDUDE platform. The development environment used was Eclipse IDE.

With the Eclipse IDE the C Development Environment (CDE), and the AVR plug-in are both needed. It is assumed that the AVR avr-libc libraries are installed.

The freeRTOS folder contains the most recent version 8.2.3 of freeRTOS, but it has been abridged down to only those files relevant for AVR GCC. The port.c file has been extensively modified to allow the use of either of the 328p Timer0 or Timer1 timers. And, the use of Timer3 on the Pololu SVP which has uses a 1284p. Timer 3 for Arduino Mega using a 2560 also works. Timer2 support has been added for the Freetronics Goldilocks and its 32,768kHz crystal. A Real Time system_tick is added using time.h functionality added to the system libraries described below.

The freeRTOSBoardDefs.h file contains most of the variables that you’ll need to change regularly.

There are some relevant and often used libraries added to the basic freeRTOS capabilities.

  • lib_io: contains often used I/O digital and ADC routines borrowed from Pololu.
  • lib_io: contains the tools to use the TWI (non-trademarked I2C) bus. It contains integrated interrupt driven master and slave routines
  • lib_io: contains the tools to use the SPI bus.
  • lib_io: contains routines to drive the serial interface. there are three versions; avrSerial for use before the freeRTOS scheduler has been enabled, and xSerial for use during normal operations. xSerial is interrupt driven and uses an optimised ring buffer. xSerialN is further generalised to allow multiple simultaneous serial ports.
  • lib_ext_ram: contains routines to drive the Rugged Circuits QuadRam on Arduino Mega2560, or Freetronics EtherMega.
  • lib_util: Optimised CRC calculations.
  • lib_util: Extended alpha (string) to integer (binary, octal, decimal, hexdecimal) conversion.
  • lib_time: Real time calculations, from avr-libc upstream, providing esoteric time and date calculations.
  • lib_rtc: drivers for the DS1307 RTC using I2C.
  • lib_fatf: contains ChaN’s FatF FAT32 libraries for driving the microSD card.
  • lib_iinchip: contains the W5100 drivers and the W5200 drivers from Wiznet.
  • lib_inet: contains a DHCP, and HTTP implementation.
  • lib-uIP: contains the uIP implementation derived from Contiki2.7, implemented on MACRAW mode of W5100/W5200, and extensible.
  • lib_ft800: contains optimised drivers for the Gameduino2, a FTDI FT800 implementation, with LCD and touch screen support.

Some more recent posts are here:

Arduino AVRfreeRTOS

Goldilocks Analogue Synthesiser

Goldilocks Analogue Prototyping 4

Melding freeRTOS with ChaN’s FatF & HD44780 LCD on Freetronics EtherMega

Rugged Circuits QuadRAM on Freetronics EtherMega

Quick review of Freetronics EtherMega

Description of the AVR Pong multi-processor game.

Additional steps to use the Mega2560

EtherMega (Arduino Mega2560) and FreeRTOS

I sell on Tindie

Step-by-step Instructions

Our Destination:

On completing these instructions you should have an Eclipse IDE (Integrated Development Environment) installed with all relevant libraries installed, to use the freeRTOS, and the libraries I’ve modified, to build projects (Eclipse term for a set of code) of your own.

We’re Assuming:

These instructions are based on an Ubuntu LTS install, but the path to the destination is not complex, and can be roughly followed for any installation platform.

Step 0. As usual on an Ubuntu (Debian) system, refresh the software sources.

sudo apt-get update

Step 1. Install the AVR Libraries.

Together, avr-binutils, avr-gcc, and avr-libc form the heart of the Free Software toolchain for the Atmel AVR microcontrollers. They are further accompanied by projects for in-system programming software (uisp, avrdude), simulation (simulavr) and debugging (avr-gdb, AVaRICE).
sudo aptitude install avr-libc avrdude binutils-avr gcc-avr gdb-avr

Step 2. Install the Arduino environment.

Doesn’t hurt to have the Arduino environment available. It can be used for programming boot-loaders (using AVR-ISP code), and generally for checking health of equipment, using known good example code.

This will pull in some extra libraries that the Arduino platform needs.

sudo aptitude install arduino


Step 3. Install the Eclipse IDE.

It is not necessary to use or install an IDE to develop with freeRTOS, or with any other system. It is easy to use makefiles and the command line with avr-gcc and avrdude. In fact, I didn’t use Eclipse for a long time. And, when I first started to use it, it felt very unnatural and clumsy.

However, now I’ve been using it for some time I highly recommend it, for the ability to see deeper into the code (definitions are detailed on mouse over), and to compare (live differences) and roll-back code to any step of your editing process.

Again, installation is easy with Ubuntu (Debian), but it can take a while. Lots of things get installed along with it.

sudo aptitude install eclipse

Step 4. Select the C & C++ development tools within Eclipse.

Eclipse is a Java based platform, but it works just as well with C, and C++, as it does with a wide variety of languages. Getting the C Development Tools (CDT) is the first step to a C environment that we’ll be using.

Open Eclipse, and lock it to your launcher. You’ll be using it frequently.

Using the Menus, click:

Help>>Install New Software…>>Add…

CDT Indigo

Select only “CDT Main Features”, and install these plugin development tools.

Step 5. Select the AVR development environment within Eclipse.

The AVR environment includes direct access to the avrdude downloading tool for one-click programming of your AVR devices.

Using the Menus, click:

Help>>Install New Software…>>Add…

AVR Plugin

Select “CDT Optional Features”, and install these plugin development tools.

Step 5c. Select C/C++ Perspective

First you need to select the right perspective, being C/C++. Top right there is a button showing “Java”. Just to the left is a button (like a window) for selecting perspective. Select


When that is finished, you should have Eclipse menu button containing a AVR* with a green down arrow. That is the button used to program the device.

Step 6. Define a freeRTOS static library project.

There are lots of short cuts, and alternative ways to achieve things using context sensitive menus in Eclipse. I’ll concentrate on the top menu bar options, though you can get most things from a context menu click in the right window.

File>>New>>C Project: AVR Cross Target Static Library: Empty Project

A static library project is never run by itself. It is always linked to by other projects, called AVR Cross Target Applications.

Give the project a name (perhaps freeRTOS82x).

Now a project will apear in the “Project Explorer” window. Select it. We are going to set some options relating to this project.

Project>>Build Configurations>>Set Active>>Release


AVR:Target Hardware: MCU Type: ATmega328p (or other depending on hardware)

AVR:Target Hardware: MCU Clock Frequency: 16000000 (for Arduino hardware or other depending on your hardware)

C/C++ Build: Configuration: [All Configurations] (make sure this is set for all following configurations)

C/C++ Build: Environment: AVRTARGETFCPU: 16000000

C/C++ Build: Environment: AVRTARGETMCU: atmega328p

C/C++ Build: Settings: AVR Compiler: Optimisation: Other Optimisation Flags: -ffunction-sections -fdata-sections -mcall-prologues -mrelax (and use -Os or -O2)

Now we are going to add just the freeRTOS files, from the subdirectory within the file that you have downloaded from Sourceforge, and extracted somewhere sensible.

File>>Import…>>General:File System

Select the “into folder” as the project name you just created, and “Select All” for the import on the freeRTOS subdirectory. That should import the entire freeRTOS system. Spend some time browsing, if you like.

NOTE. Do NOT import the entire contents of the file. At this stage just import contents of the freeRTOS subdirectory.

Now we define the include library for the build. Remember to select [All Configurations] first.

Project>>Properties>>C/C++ Build>>Settings: AVR Compiler: Directories 

Add the from the “Workspace…”: freeRTOS82x/include


Now there are fouralternative memory management routines, explained in the freeRTOS documentation. We are going to use the heap_2.c version, so we need to exclude the other three files from the build. In the project explorer RIGHT CLICK (context menu) each one then exclude them.




Resource Configurations>>Exclude from Build…: Select All

Following this step, it should be possible to compile the library.

Project>>Build All

If there are any ERRORS, then go back and check the configurations for the project. Sometimes they may be changed, forgotten, or otherwise different from what you expected.

There will be some WARNINGS, relating to the usage of different Timers. I added these warnings to keep these things front of mind, as depending on which hardware I’m using the ./include/FreeRTOSBoardDefs.h file needs to be managed to suit.

Step 7. Define an Application Project.

An Application will generate the final hex code that you upload to the AVR with avrdude. This final code is created from the freeRTOS static library code generated above, together with code contained in the avr-libc, and any other linked projects.

We are going to import the UnoBlink or MegaBlink project as it makes a good example. Without a display, or real-time-clock module, it will only flash a LED. But, least we know it is alive.

To get started create a new project as below.

 File>>New>>C Project: AVR Cross Target Application: Empty Project

Give the project a name (perhaps MegaBlink or retrograde).

Now a project will appear in the “Project Explorer” window. Select it. We are going to set some options relating to this project.

Project>>Build Configurations>>Set Active>>Release



Configuration name: Arduino or Freetronics 2010

Programmer Hardware: Atmel STK500 Version 1.x firmware

Override default port: /dev/ttyUSB0 (FTDI USB) OR /dev/ttyACM0 (AVR USB)

Override default baudrate: as or if required.

AVR:Target Hardware: MCU Type: ATmega328p (or other depending on hardware)

AVR:Target Hardware: MCU Clock Frequency: 16000000 (or other depending on hardware)

C/C++ Build: Configuration: [All Configurations] (make sure this is set for all following configurations)

C/C++ Build: Environment: AVRTARGETFCPU: 16000000

C/C++ Build: Environment: AVRTARGETMCU: atmega328p

C/C++ Build: Settings: AVR Compiler: Directories: “${workspace_loc:/freeRTOS82x/include}”

C/C++ Build: Settings: AVR Compiler: Optimisation: Other Optimisation Flags: -mcall-prologues -mrelax (and use -Os or -O2)

C/C++ Build: Settings: AVR C Linker: General: Other Arguments -Wl,–gc-sections

C/C++ Build: Settings: AVR C Linker: Libraries: Add “m” without quotes. m is the standard math library, which should be included in most projects.

C/C++ Build: Settings: AVR C Linker: Objects: Other Objects Here you need to add the compiled freeRTOS library. And this is the only place where the Debug and Release builds are different.

With Release Build selected, paste “${workspace_loc:/freeRTOS82x/Release/libfreeRTOS82x.a}”

With Debug Build selected, paste “${workspace_loc:/freeRTOS82x/Debug/libfreeRTOS82x.a}”

Or select the Workspace option to navigate to the actual assembler files to be linked into the project.

Project References: freeRTOS82x ticked.

Now we are going to add the MegaBlink (or retrograde) files, from the (or file that you have downloaded from sourceforge, and extracted somewhere sensible. If you downloaded the, you have all the sources.

File>>Import…>>General:File System

Select the “into folder” as the project name you just created, and “Select All” for the import. That should import the 2 files shown inro the project file system. Spend some time browsing, if you like.

Following this step, it should be possible to compile and link the project.

Project>>Build All

If this step completes successfully, with no additional ERRORS, then the final step is to upload the new application into your Arduino or Freetronics device.

Make sure that you have your device plugged into the USB port, then simply hit the AVR* button in the row of buttons. You will see some green text showing the status of the upload, finishing with the words

avrdude done. Thank you.

Now, you should have a flashing LED.

Now you can import any additional projects, in the same way.

Step 8. Things to watch.

Turn on the serial port by removing the comments around the serial port definitions, and watch to see aspects of the program in action.

Expect to manage the amount of heap allocated in the ./include/FreeRTOSBoardDefs.h file, to ensure that the total SRAM utilised (as noted in the final linker stage when using heap_1.c, heap_2.c or heap_4.c) remains less than 100% or for ATmega328p 2048 bytes.

Expect to manage the amount of stack space allocated to each task during the set up, to ensure you’re not wasting space, nor (worse) you’re over writing another task’s stack.

For the Arduino Uno, keep the total number of tasks to below 4, otherwise too much SRAM is consumed in stack allocations.

Freetronics 2010 (Arduino Duemilanova) freeRTOS Real Time Clock (DS1307) – Part 1

I was pondering the blank space on my 2010 recently, and combining that space with some other left over kit from Dogbot, I decided to make a dual retrograde analogue clock.

To build the clock I have the choice of either using NTP to sync a wireless enabled device, or use a RTC clock and re-set it every month or so. For this iteration, I’ve decided to go the RTC route.

Actually, reading this Tronixstuff page also got me going on the idea of using a DS1307 chip, and also Sparkfun makes a nice module that just happens to fit in the vacant space on the 2010. So, I bought one from LittleBird Electronics.

Only other thing to do was to add some servo headers, to get me going with the analogue clock face (using servos).

The picture below shows the layout. I tried a few different options, but this layout seems to only affect the legibility of the pin labelling. Other layouts mask the crystals close together, and I’m not sure how that would affect clock accuracy, or prevent the battery from being removed (9 years later).


Yes, everything fits. Now to the soldering iron.


Ok now it is soldered together, and everything looks reasonably fine.


Now, on the test bed, I have the RTC clock working well using my beloved freeRTOS, and can get on with using the servos to drive analogue hands.


In the years since this instruction was writen, I’ve migrated to Github. So the code is hosted here. The freeRTOS code is also posted on Github. I used the Pololu Library for writing to the display, so it needs to be installed along with the normal AVR libraries.

Part 2 looks at building the PWM control for the retrograde hands, and adding a temperature function.

Freetronics 2010 (Arduino Duemilanova) Overclocking & Review

Recently, I picked up a Freetronics 2010 from Little Bird Electronics.


I thought that it would make a nice upgrade to my Dogbot test bed. It uses the same USB connector as Dogbot’s Pololu SVP, so it saves me from keeping different USB cables handy, but is in every way 100% the same as the Arduino Duemilanove that I’ve been using up to now.

But, everything I own is hacked in some way. So as usual, I thought that the 2010 could be improved, just as I’ve improved the Duemilanove before it, by overclocking it to 22.1184MHz.

Overclocking to 22.1184MHz

So why change the clock frequency to this odd number of 22.1184MHZ, and not to 20MHz which would be in specification?

It turns out that because of the binary and integer world the 2010 and the Duemilanova ATmega328p MCU live in, it is much better have a “nice” binary and integer friendly base frequency. Unfortunately, although 16MHz on a 2010 or Arduino sounds nice, from the point of view of integer programming, clock scaling, and UART interfacing, it is difficult to get clean integer numbers.

A small example.
16MHz clock scaled to 115200baud = 138.888888889 so rounding gives an error term.
20MHz clock scaled to 115200baud = 173.6111111111 so, again, rounding gives an error term.
22.1184MHz clock scaled to 115200baud = 192 with no rounding error.

Also, even though we are getting 16,000,000 instructions per second out of a standard?2010, and that should be enough for any application. I can get 22,118,400 or a 38% improvement for the cost of a few cents. So, why wouldn’t you?

What kind of issues can occur?

Well, over-clocking means that the ATmega328p is out of specification. But, I’m not too worried about pushing specification on this project, as the 328p is certified for an industrial operating temperature range, which is way outside of my operating temperature… There are also unverified reports of AVR ATmegas working successfully up to 32MHz.

In the overall scheme of things, raising the clock frequency on the AVR ATmega328p above specification by 10% to 22.1184MHz is no big deal.

Upgrading Process

1. Obtain a 22.1184MHz HC49/US crystal from Digikey They’re pretty cheap. Buy a bag in case of accidents.


2. Use a knife tip under the existing 16MHz crystal to give you a lever to pressure it into removal, without burning your fingers. It will get very hot!

3. Turn over the board and use a soldering iron to heat the joints, whilst leaning on the knife to lever out the 16MHz crystal. Once it is removed, use some solder wick or similar to remove excess solder, and make it easier to insert and solder the new 22.1184MHz crystal.


4. Building a new bootloader. In replacing the crystal, the 2010 is effectively bricked. You can no longer communicate with it using the standard bootloader. It is now running too fast and out of specification for avrdude to communicate with it, so we have to compile and burn a new boot loader before we go any further. I choose to use the Adaboot328 bootloader from Ladyada. It resolves a few known issues with Arduino compatible boards, and is easy to compile.

In the ATmegaBOOT_xx8.c file, change the UART baud rate to 115200, if you use avrdude for programming (if using Arduino IDE, do not change this from 19200). Who has time to wait around these days for 19200 baud, anyway?

/* set the UART baud rate */
#define BAUD_RATE?? 115200

In the Makefile, change the AVR_FREQ value to 22118400L for the adaboot328: TARGET.

adaboot328: TARGET = adaboot328
# Change clock frequency from 16000000L
adaboot328: AVR_FREQ = 22118400L

Then, compile the bootloader, and keep it safe.

5. Prepare an ISP. There are many alternative ways to do this, and here is not the place to describe the alternatives. Suffice to say that I used the AVRISP method in the Arduino-0018 IDE. I’ve struggled with avrdude (which I otherwise use for everything) as a bootloader ISP. I don’t know why, but I can’t make it work.

It happens that I have a standard Arduino clone available, which I prepare as the AVRISP, by uploading the following sketch File>Examples>ArduinoISP.

6. To be able to use Arduino IDE to burn our special bootloader, you have to replace the standard ATmegaBOOT_168_atmega328.hex bootloader file, found in ~arduino/bootloaders/atmega/ with our newly generated file. And, to make things simple, I just rename or remove the standard one, and replace it with our newly prepared and renamed bootloader with this name

7. Connect our Freetronics 2010 up using the AVRISP connections, described on the Arduino web site. Make sure we have the right board type selected; it should be Duemilanova w/ ATmega328. Then using the Arduino IDE use Tools > Burn Bootloader > w/ Arduino as ISP.


8. Program a sketch using either the Arduino IDE, or using avrdude, remembering that the baudrate is set to 115200. And, enjoy.

Conclusions regarding the Freetronics 2010.

Its a very well designed and produced device, that is 100% compatible with the Arduino Duemilanova. Some advantages are: the mounting holes are slightly larger so cable ties go through nicely, smaller USB connector is more common than the B connector used on Duemilanova, and there’s no solder in the holes for the X3 connector so it is easy to add headers to make it possible to burn its own bootloader (if you want).

It runs my freeRTOS build with no problems, as seen in this demo on my Dogbot test bed with a Robot Electronics Thermopile, and Sharp IR Distance sensor.


DogBot – Post 5

So some time has passed and I’ve had some success with different aspects of my robot.

For simplicity, I’m using a test bed based on an Arduino Duemilianova connected to a Nerdkits sourced display. I’ve hooked the display up as if it was a Pololu Orangutan SV-328 and am using Pololu libraries to write to it. Also, I’ve been working on the actual SVP based robot, so both of which are working well.

The processor 328p is used for the Duemilianova and requires the use of the Timer0, which implies no Pololu motor library code is possible without conflicts. However this is not an issue, as the Duemilianova doesn’t have motor drives anyway. The actual DogBot has the 1284p which is used in the SVP and uses Timer3, which has no limitations on any known libraries to my knowledge.

The freeRTOS code is posted on the Pololu Forum, mostly just back-up as the application code is very immature.

At  this stage I’ve got all of the I2C bus based sensors working, based on code developed by Fleury. So, I can read the thermal sensor for its 8 pixels, and equally importantly, I can read the SRT10 Ultrasonic Sensor for distance in cm. One issue with the ultrasonic sensor is that its field of vision is so great that it basically detects anything “in front” of it. Good to not run into things, but pretty useless as a fine directional capability. It seems lucky that the Sharp IR distance sensors are very directional, and sufficiently accurate as a complement. The analog sensor readings are working well too, though I still have to create a ADC to cm regression.

From the point of view of sensing, it looks like the Sharp IR sensors will be the reference. With the SRT10 sonar being most relevant to create a “zone of safety” where I can be assured that the nearest object in a cone of 120deg is measured, but can’t be sure exactly which direction the object is. On the thermal side, I will get a vector (direction and temperature) from the sensing location, but no distance. But, that I knew and expected.

Putting some effort into designing the motor control, or Transport Task, has taken up my thoughts recently. I don’t want to link the odometry available from the quadrature encoders back into the mapping or routing task. Similarly, I don’t want to link the intertial navigation available from yaw and linear acceleration sensors into the motor task.

I think the transport task should simply take a vector,  relative to the the current pose of the robot, and execute these translation commands subject to feedback from odometry, leaving the inertial navigation to another task.

This fits well into the design of the hardware, as odometry can can be queried from the Pololu SVP ancillary processor, without blocking, and the motor PWM drivers can be also managed without blocking other tasks. This creates a self contained task that does not need to share resources with other tasks.

However, the inertial sensors are analogue readings and the ADC will need to be shared with the Sharp IR distances sensors. Creating the need for a semaphore, and blocking based on the availability of the ADC.

Because of the battery issues described in Post 4, I’ve had to remove the servo neck of the DogBot. Therefore, I will implement the option for motion to be along circular paths, as well as along a straight line. Motion along a straight line, with stationary rotations to create the correct pose prior to departure, are the best paths to arrive at the destination with the lowest risk and shortest path. However, with a fixed sensor head, straight lines don’t fill the map with information as they leave the sensors always pointing in the same direction.

If the DogBot proceeds from A to B via a circular route (if this is requested by the mapping or logistics task), then the sensors will be pointed at all directions from +90 to -90 degrees along the path to the destination. Allowing the travel time to be used effectively for data acquisition.

If I’m feeling smart, then I can create any number of route subdivisions, and force DogBot to describe a path of smooth semicircles to the destination, gathering sensor data along the route.

The inertial sensors can be run in a parallel task (using the ADC along with the Sharp IR sensors), with the odometry (from the ancillary processor) to cross check that the expected distances and directions are traveled. Whilst I think the odometry is more likely to be accurate, the map will be updated constantly so some inaccuracy should be expected and tolerated by the code.

My next step is to design this transport task. This task should take distance, bearing and path description (straight line, circle, sinusoidal, etc) and carry it out to the best of its ability (odometry PID data only). I expect resolving this effort will take the next few weeks, and perhaps longer.

Later work is to develop the logistics and routing task that will issue the navigation requests to the transport task.

Continued with Post 6 (one year later).

Make Arduino Duemilanova run NerdKits C code

Just got a NerdKit, and although it was fun to put the it all together
and make it work, I like stable power and comms, so I also just bought
a Duemilanova to play with too.

But, also not liking IDE programming, much less dirty code that has
“wiring” in it, I thought it might be nice to run NerdKit C code on
the 328p in the Duemilanova.

Following the simple instructions from the pdf in the ATmega328P
Upgrade Nano-Guide
 gets you most of the way.

In the C code file you’re writing change the CPU speed definition from

#define F_CPU 14745600 // for NerdKit


#define F_CPU 16000000 // for Duemilanova

To make avrdude work these parameters are needed for the make file:

AVRDUDEFLAGS=-c stk500v1 -p m328p -b 57600 -P /dev/ttyUSB0

Press the “S1” button on the board simultaneously with your `make` or
`avrdude` command

It works. That’s all!