AVR RTOS Update

I haven’t forgot about my little rtos project, although its moving towards not really being an RTOS.  The goal is to write a task manager for the AVR and as an extent, the Arduino.  As I don’t have an Arduino Mega, or any board with an AVR with more than 64 K words of flash, such as an ATmega2560, I can not write the task switcher for that board, at least not properly test it because the pointers are a bit larger for flash.  So the function pointer sizes change.  So this project will support AVRs that have 16 bit program counters.

As I mentioned earlier, this project is moving away from being an RTOS to more of a process manager.  The task switcher will still consider time as a factor in the decision to run a thread, but will have extended set of run conditions.  I am going to add the concept of a lock to the task switcher and remove the concept of priority  This is so the AVR cpu does not have to waste precious clock cycles performing the context switch to a task only to have yield called again.  The locks are going to be contained in a linked list, and when the list is empty, the task can run.  I am not removing the concept of the “next run time” because I believe that most thread locks are going to be due to sleeping, such as a PID algorithm.  It needs to run at 25 Hz, and doesn’t need locks calculated until its time to run again.  A lock could be used for example, with a UART reader.  It should be locked until data is available.  This generates some new definitions in the code along with the discovery that in the AVR, malloc is not an expensive operation (~100 cycles).

struct _avr_task_lock
{
    struct _avr_task_lock *next_lock;
    void *lock_data;
    char (*lock_function)(void *); 
}

struct _avr_task_entry
{
    uint32_t next_run_time;
    uint16_t *stackptr;               // use cpiw to check if its equal to zero, if so, its invalid
    struct _avr_task_lock *lock_list;
}

The _avr_task_lock structure defines the lock object. It contains a pointer to the next object, a pointer to some data, and a pointer to a function which is used to figure out if that lock should expire because of the data pointer to by lock_data.  The _avr_task_entry structure defines the task entry to the AVR.  It contains the next time it should be run (locks are not crawled unless it should be allowed to run again), the current stack pointer, and a pointer to the first lock object.  I think the manager should use the X and Z pointer to store last and current pointers when everything is ported to assembly.  The only reason I would choose to store a next run time value is because if the thread needs not to be run until a time, why waste precious CPU cycles on something dependent on the clock.

A pure assembly function will be added to wrap a function that is desired to be executed.  This provides a wrapper so that when the thread function potentially returns, it can catch that and not blow up like the current implementation.  Basically, when the task adder pushes an executable thread, it stores a function pointer to the desired function as a parameter to the beginning of the wrapper function.  This wrapper function, when switched to, will call the function that is the thread, and if the thread returns, it invalidates the thread’s entry and performs a context switch, never to be executed again.

Eventually, when I get around to it, I’ll make a C++ extension to this, for the Arduino boards, or just people who use avr-g++.  Personally, I shy away from C++ in resource constrained environment, but hell, to each his own.

– Teknoman117

Hacking new MCUs into Arduino IDE

Its probably safe to assume that most of you who end of reading this have heard about the Arduino.   For those of you who haven’t heard of it, they are the latest microcontroller craze and they are selling by the tens of thousands.  Basically its a development board for a few lucky Atmel AVRs and it has a standard expansion connector set to adapt with numerous peripheral boards.  Personally, I’m not too much of a fan of them, for most of my projects I don’t need a board with a boot loader.  I own an AVR ISP mk.ii programmer and I don’t need to spend $35+ on a board with a $2 ATmega328 when I can by an ATmega644 or a larger chip for $4 and build my own dev board for another few dollars or so.  Although, I do understand that they are nice for prototyping and what I’m doing is more of an end-product type thing.

The robot I built with my friends from the UC Merced Robotics Society for Robomagellan in the spring 2012 semester used a pair of Arduinos and I wanted to use the code I developed there with my pre-existing software framework for the AVRs.  Since I don’t have any arduinos hanging around, I needed to either port the code or just make my own arduino.  My favorite AVR is the Atmega644, it has a ton of I/O and the most flash of any DIP variant AVR.  I came across this web page on using a chip from the most popular of the arduinos in its bare chip form to run a christmas frame.  It goes over how to add a definition to the  arduino IDE hardware list.  As I was reading through it, I noticed a few places where I could set different MCUs, frequencies, etc.  So I decided to try it out.

There are a multitude of steps in adding a whole new MCU to the arduino environment, these are assuming you are adding a new class of chip (such as the ATmega644)

  • Create a new “variant.”  This defines how the arduino IDE’s digital pins and analog pins map to the physical pins on the device.  This file also covers the pwm and pcint pins as well
  • Modify “wiring_private.h”
  • Add a new hardware entry

The arduino ide manages different devices in what they seem to call variants.  Each variant is a definition of the chip that you are using.  It defines how pins map to internal components of the AVR.  The first step is defining how many analog and digital pins exists on the device.  The rest of the file is mapping arduino digital pin numbers to registers in the device.  It also covers how these pins translate to their corresponding PCINT pins and which pins have PWM capabilities and what timer drives it.  You can get this in my github repository.

The next step is to modify the wiring_private.h header and add the new mcu’s external interrupt count.  You can see where I added the ATmega644 on line 57 of wiring_private.h

The last step is to add an entry for the board you are using.  The board I used is rather old.  It was designed by Wrighthobbies about 7 years ago.  It was literally not much more than a board that broke out the pins of an ATmega32 and provided a stk200 compatible programming header, a reset button, two 5V regulators, an optional oscillator, and some power rails.  The ATmega644 and its variants are pin for pin compatible with the ATmega32, so I just replaced the chips.  Although, you can add a comment to your order at Wrighthobbies and Eddy will just ship an ATmega644 with it.

The hardware testing of the ATmega644 arduino mod with it hooked up to my avrispmkii and an LED

We need to add an entry into “Arduino.app/Contents/Resources/Java/hardware/arduino/boards.txt” to reflect the devboard’s settings

devboard_m644.name = Wright Hobbies Devboard w/ ATmega644 and ext 11.0592 MHz osc

devboard_m644.upload.protocol=stk500
devboard_m644.upload.maximum_size=65536
devboard_m644.upload.using=avrispmkii

devboard_m644.bootloader.low_fuses=0xCE
devboard_m644.bootloader.high_fuses=0xDD
devboard_m644.bootloader.extended_fuses=0×FF

devboard_m644.build.mcu=atmega644
devboard_m644.build.f_cpu=11059200UL
devboard_m644.build.core=Arduino
devboard_m644.build.variant=atmega644
  • <board name>.name – provides the textual name of your board that you are presented in the Arduino IDE.
  • <board name>.upload.protocol – the protocol which your programmer uses.  In the case of the AVR ISP mk.ii this is stk500
  • <board name>.upload.maximum_size – the size in bytes of the flash ram on your AVR
  • <board name>.upload.using – the programmer which you want to use with your chip
  • <board name>.bootloader.low_fuses – the low fuse byte to set in your chip (see http://www.engbedded.com/fusecalc)
  • <board name>.bootloader.high_fuses – the high fuse byte to set in your chip (see http://www.engbedded.com/fusecalc)
  • <board name>.bootloader.extended_fuses – the extended fuse byte to set in your chip (see http://www.engbedded.com/fusecalc)
  • <board name>.build.mcu – the MCU you are adding
  • <board name>.build.f_cpu – the frequency it operates at
  • <board name>.build.core – currently, unless you want to write your own core library, set it to arduino
  • <board name>.build.variant – set to the variant of the chip you created earlier

Here is an example of it in the editor

See the board name in the bottom right corner

There is one caveat when doing this though, you have to use the “Upload with Programmer” option instead of just the upload button.  Here are two YouTube videos of it working and all of the sources for this are available on GitHub in my repo – http://github.com/Teknoman117/avr-libraries

Blinking LED

Ramping LED