Home News Features Examples Code FAQ License
AVR Webring
Prev Hub Join Rate Next
Getting Started
0.92 0.91 0.89 0.88 0.87

Preparation

This guide is meant to get you started writing your own tasks. It is valid only for version 0.89 of Femto OS. Please select the correct version first, for names, codes and descriptions made be significantly different between the versions.

I assume you already where able to build the toolchain, flash the prebuild binaries and compile the examples from the command line. This is all described in the Readme file that goes with the distribution. Having done that, this is the place to continue and build your first application.

The preparations you have to make, is to make sure you have a working development board with a mounted and supported microcontroller. Connect the leds and switches to the correct ports. Leds usually must be connected to PORTB, except for the tiny's: 43u 261,461,861 for these must be connected to PORTA. The switches usually must be connected to PORTD, except for the tiny's: 43u 25,45,85,261,461,861, wich have them on PORTB and the tiny's: 24,44,84 which have them on PORTA. More info in the FemtoOS_0.89/MainCode/femtoos_devices directory, look for the file that matches your device. Note that the latter tiny's are so small they share the led- and switchport, which makes experimenting a little hard. Most examples will not run out of the box.

Hello World, part 1.

I start by explaining the Hello World Application, and after that, we will make some modifications and see how the OS behaves. Please note this example only runs as described in the latest version (Femto OS v0.89) of the distribution. All examples consist of two files, in this case code_TestHelloWorld.c and config_application.h. The latter name is identical for all examples so that they can be included automatically, and contains, well, configuration parameters. Since we use the my compiler script, the first is fixed too, and will contain our code. Code files must include femtoos_code.h to make all OS functions available, and nothing more.

Now you will usually need some variables, say for example an integer and a string. For the moment, it is important to make sure NO initialization is put in the .data section; which is a waste anyway. So we initialize the integer to zero, and make sure the string is put into flash. Thus up to this moment our code_TestHelloWorld.c looks like:

#include "femtoos_code.h"

static Tuint08 speed = 0;
const Tchar HelloWorldStr[] PROGMEM = "Hello World.";

Following misra, i redefined all types uint8_t, unsigned char etc to Tuint08, Tchar. Their definitions can be found in femtoos_globals.h, but they are pretty straightforward. You can of course keep using standard types if you like.

Further, we want to define a name for our first task. All tasks in Femto OS have name literals, and the preprocessor gives each task a number (0..15) depending on its use. Since you do not know this number, you refer to the task by name always. Naming is done inside the config_application.h file, from which we show the relevant part:

/* ========================================================================= */
/* TASK NAMES ============================================================== */
/* ========================================================================= */


#define  CN_00                                   Display

Note that all configuration parameters are described on the Code | Config page on this site. From now on, we can use the name "Display" if we want to refer to that task. Ok, now we have defined the name, let's define some code. We want to let task display the ascii values from the words "Hello World" on the leds. Here it is:

#if (preTaskDefined(Display))

void
appLoop_Display(void)
{
 speed = 64;
  while (true)
  {
Tuint08 uiCharCount;
    Tchar
cChar;
    for
(uiCharCount = 0; uiCharCount<12; uiCharCount++)
    {
cChar = portFlashReadByte(Tchar, HelloWorldStr[uiCharCount]);
      devLedPORT = ~cChar;
      taskDelayFromNow
( ((Tuint16)speed)*4 + 64 );
      devLedPORT = 0xFF;
      taskDelayFromNow
(64); }
    taskDelayFromNow
(2000); } }

#endif

We see a couple of things. The code itself is packed within a preprocessor check to see if the taskname is defined. This is just to make sure we do not include code, when the name is not defined. It is not stricly necessary. Then we see that the task is called appLoop_Display(). This is convention. All user defined code is called from the OS using the app prefix. The appLoop stands for the main loop of the task, and the name you have defined before is simply added to that, thus we get appLoop_Display. Femto OS calls that function after the context has been setup, and that function should NEVER return. To be certain, the rest is packed in a while(true) loop. Then we see an character counter variable and character variable, followed by a loop to read the characters. Nothing special.

To read the characters from flash, we make use of a port function (all portable functions used by the OS are packed in the femtoos_port.h and femtoos_port.c files) and we can make use of that too. Here we use:

#define portFlashReadByte(byteType, byteVar) ((byteType) pgm_read_byte(&(byteVar)))

to read one character in a 'typed' way. Subsequently we write the value of the character to devLedPORT, a device independent way to write to the port whith the leds connected. (Not all devices have for example PORTA available for output. Every device has a seperate file where these definitions are given. For example the Atmel tiny861 has the file femtoos_ATtiny861.asm.

After we have written the chacter to the outside world, we want to pause for a while. To that end we call taskDelayFromNow(128) (speed variable set to 64 at this point). This is an OS method that may only be called from within a task (hence the 'task' prefix), and will delay the task for 128 ticks. The whole API of Femto OS is described on the site as well: Code | API. The time one tick takes depens on many variables, but for now, please accept we have set it to 1ms. This call will lead to a context switch, but since we do not yet have other tasks, the OS will start waiting in the idle mode for the requested time. However, before we can make use of the call, we must configure it to be used.

/* ========================================================================= */
/* API INCLUSIONS ========================================================== */
/* ========================================================================= */

/* Standard functions ------------------------------------------------------ */

#define  includeTaskYield                        cfgFalse
#define  includeTaskDelayFromNow                 cfgTrue
#define  includeTaskDelayFromWake                cfgFalse
#define  includeGenSuspend                       cfgFalse

This is a general policy. Any function (or group of functions) you want to use must be switched on in the config file. This is to make sure the preprocessor only includes the required functionality in the OS. Observe the other includes to be false. (Use cfgFalse and cfgTrue instead of plain 'true' and 'false'. This enables further quality checking by the preprocessor.)

Although this may seem quite complete, only a few things are missing. First, we usually must initialize the hardware before use, and second, we must tell the OS how much stack must be reserved for the task. Standard initizalition, such as cleaning the memory, resetting the watchdog etc is done for you by the OS, but if you want to use some ports, they must be initialized. Femto OS calls a special function, named appBoot() just once, so this is ideal for our situation:

void appBoot(void)
{
devLedDRR = 0xFF;
  devLedPORT = 0xFF;
  devSwitchDRR = 0x00; }

As you can see, de define the ledPORT to be outputs, and clear all leds, and we define the switches to be input. Of course, we must make sure that Femto OS indeed calls this method:

/* ========================================================================= */
/* EXTERNAL CALLS ========================================================== */
/* ========================================================================= */


#define  callAppTick00                           cfgFalse
#define  callAppTick08                           cfgFalse
#define  callAppTick16                           cfgFalse
#define  callAppTickSleep                        cfgFalse
#define  callAppEnterIdle                        cfgFalse
#define  callAppEnterSleep                       cfgFalse
#define  callAppExitSleep                        cfgFalse
#define  callAppBoot                             cfgTrue
#define  callAppInit                             cfgFalse
#define  callAppBark                             cfgFalse

As you can see, there a lot more hooks possible, but for now, we only need a call to appBoot(). The last thing we need to do is to define the use of memory, in this example, only the stack.

/* ========================================================================= */
/* STACK SIZES ============================================================= */
/* ========================================================================= */


#define  StackSafety                             4
#define  StackSizeOS                             24
#define  StackSizeISR                            0
#define  StackSizeOverride                       46

The StackSizeOverride is used to define the taskspace for all tasks. And since we have only one task this will do fine. (Defining overrides is possible for all parameters that must be defined on a task by task basis.) Furthermore, we see the definition of the stackspace for the OS, and a StackSafety. We will explain that lateron.

What we have done up to this moment should result in runable code. Of course, we did not discuss every tiny bit of it, and there is also second task in the code which i will adress in a moment. But, out of the box, this should run. So go to your commandline (cygwin if you are on windows), change to your FemtoOS_0.89/IDE directory and type: ./script/compile HelloWorld attiny861 and substitute your device. Subsequently flash it, by providing the device and comport of your development board.

ruud@wolf IDE $ ./script/compile HelloWorld attiny861
   text    data     bss     dec     hex    device      project
   1482       0      78    1560     618    attiny861   HelloWorld
ruud@wolf IDE $ ./script/flash /dev/ttyS1 stk500v2

At compiling and flashing, parameters need only to be specified once. If the operation was succesfull the script stores the last parameters, so you can skip them. Get the full syntax of the commands by typing help as parameter. If the leds are very slow, then you are probably running on a speed lower than 8MHz. This typically happens when your device does not have a clock prescaler, (atmega 8,16,32,64,128,8515,8535). You need to fuse it to make it run on 8MHz:

ruud@wolf IDE $ ./script/flash 8MHz

This command will activate the internal clock and set it to 8MHz (other bits on the fuse are left alone). If all is well this should be your result.

Hello World, part 2.

For one task, we don't really need an OS, so we must at least define a second. Lets read the value of a switch, which controlles the speed at which the letter are displayed.

#if (preTaskDefined(Speed))

void appLoop_Speed(void)
{ Tuint08 button = devSwitchPIN & 01;
  Tuint08 lastbutton = button;
  while (true)
  { button = devSwitchPIN & 01;
    if (button != lastbutton) { speed += 64; }
    taskDelayFromNow(100); } }

#endif

The idea of this piece of code is first to read the current setting of the switch, which is assumed to be the deactivated mode, and subsequently wait for a change in the setting. If that change happens, we increase the speed, and wait 100 ms to suppress bouncing.

Up to this point the code ran like this, out of the box, but now, you must make the first changes. The taskname has already be defined, but we must make sure the task is really included into the code. There go to the config file and make adjustments to go from:

/* ========================================================================= */
/* INCLUDE TASKS =========================================================== */
/* ========================================================================= */


#define  TaskInclude_Display                    cfgStartRunning
#define  TaskInclude_Speed                      cfgExclude

to (changed values are bold and cursive):

/* ========================================================================= */
/* INCLUDE TASKS =========================================================== */
/* ========================================================================= */


#define  TaskInclude_Display                    cfgStartRunning
#define  TaskInclude_Speed                      cfgStartRunning

When a task is set to cfgExclude, the code is not only not executed, but also not incorporated in the executable. After you have made the adjustments, let's try it:

ruud@wolf IDE $ ./script/compile
   text    data     bss     dec     hex    device      project
   1648       0     128    1776     6f0    attiny861   HelloWorld
ruud@wolf IDE $ ./script/flash

When all is well, you should have two tasks running, and be able to adjust the speed by pressing the first button.

Hello World, fun part.

What we have done, could be done with any OS, so now it is time to have some fun. Basically there are two ways we could continue this demo. First we are going to downscale the current application, after that we will restore it, and add extra functionality. Also, from now on, i cannot guarantee complete succes, since what we are about to do, may differ between te different systems.

Let we first try to reduce the use of the stack on one of the tasks, to see what happens. We can estimate this by the following what happens when a context save occurs:

since we have a very simple function we do not expect any stackuse there. Thus this adds up to 37 bytes. At this moment we have defined it to 46 bytes, so lets reduce it to 38 and see what happens:

/* ========================================================================= */
/* STACK SIZES ============================================================= */
/* ========================================================================= */


#define  StackSafety                             4
#define  StackSizeOS                             24
#define  StackSizeISR                            0
#define  StackSizeOverride                       cfgOverrideNon
#define  StackSize_Display                       46
#define  StackSize_Speed                         38

Note that we must deactivate the override value (which takes precedence when defined) and also define the stacksize parameters for all tasks. When we compile and flash this task we see that the ram consumption has decreased by 8 bytes (as expected):

ruud@wolf IDE $ ./script/compile
   text    data     bss     dec     hex    device      project
   1680       0     120    1800     708    attiny861   HelloWorld
ruud@wolf IDE $ ./script/flash

and that the Femto OS gives an error message (see to the left), not as expected. Let us first explore what that error message means. What you see is three different bit patterns, namely: 10.000010 - 01.000010 - 0000.0001. The dots indicate how this message is to be understood. From the first two patterns, only the last six bits are relevant, they contain the error code, 0x02 in this case. The first two bits are alternating, and just to get your attention. I made them behave like that to distinguish it from normal operations, but you may alter that in the error call back method portShowError() in the femtoos_port.c file if you like. You can look this code up on the Code | Errors page, and it tells you that this error, errTaskStackSetupTooSmall means that the OS calculated that the task does not have enough stackspace, so it will not be started. After a while other tasks (one in this case) will be started as normal. The last four bits of the last bit pattern tells you, task number 1 was the offending task.

Now, before i told you you cannot know on before hand which tasknumber corresponds to which task. True, but we can ask the compiler a little more information

ruud@wolf IDE $ ./script/compile info
   text    data     bss     dec     hex    device      project
   1680       0     120    1800     708    attiny861   HelloWorld

   Function ===========  Stack ===   Regtable   Individual registers use (changed) ====
   HelloWorldStr:        0 (  0)     ........
   appLoop_Display:      4 (  4)     xx.x....   r31 r30 r25 r24 r17 r16
   appLoop_Speed:        4 (  4)     .x.x....   r25 r24 r17

   Label ====  Name ========================================
   Task  0     Display
   Task  1     Speed

   Address     Fields ======================================
   0x0060      xOS
   0x0078      Stack00
   0x00a6      Stack01
   0x00cd      tcb00
   0x00d1      uxTickCount
   0x00d3      uiOsStatus
   0x00d4      tcb01

   Address     Size =    Unit ==============================
   0x0060      0x006c    ./femtoos_shared.o
   0x00cc      0x0001    ./code_TestHelloWorld.o
   0x00cd      0x000b    ./femtoos_shared.o

You see a lot more than needed, but at least it is clear that task number zero corresponds to the Display task and one to the speed task. (The information can also be found in the FemtoOS_0.89/IDE/workspace/FemtoOS_HelloWorld/Release/main.defs file.)

Now what happened? Maybe you have noticed the present of the StackSafety parameter in the config file, which was set to 4 bytes. This parameter is our live saver. What happens is that, 4 bytes before the real border of stack is crossed, the OS will break off the task and report an error. Note, that the AVR has no memory protection unit, so this protection is not absolute. Only when the OS itself runs, this check is performed. When the task overruns its stackspace before a context switch happens, you are still out of luck. But this tool helps you fine-tuning and gaurding the stack use.

Try to set the StackSafety to zero, and compile again. Flash, an see what happens.

Hello World, the party.

What if we really do not have more stack space available than say 30 bytes or so. Is it still possible to run the task? We certainly do not want to spend nearly 40 bytes just to read a switch! It looks like this is not possible given the calculation of the stack size above. These where all minimal values. However, there still is a way out.

If we have a look at the assembly (found in FemtoOS_0.89/IDE/workspace/FemtoOS_HelloWorld/Release/main.lss), we can see by inspection that most of the registers of the device are not used at all:

0000060a <appLoop_Speed>:
 60a: 16 b3         in    r17, 0x16    ; 22
 60c: 11 70         andi  r17, 0x01    ; 1
 60e: 86 b3         in    r24, 0x16    ; 22
 610: 81 70         andi  r24, 0x01    ; 1
 612: 81 17         cp    r24, r17
 614: 29 f0         breq  .+10         ; 0x620 <appLoop_Speed+0x16>
 616: 80 91 d4 00   lds   r24, 0x00D4
 61a: 80 5c         subi  r24, 0xC0    ; 192
 61c: 80 93 d4 00   sts   0x00D4, r24
 620: 84 e6         ldi   r24, 0x64    ; 100
 622: 90 e0         ldi   r25, 0x00    ; 0
 624: a9 de         rcall .-686        ; 0x378 <taskDelayFromNow>
 626: f3 cf         rjmp  .-26         ; 0x60e <appLoop_Speed+0x4>

so the question arises, why do we put them all on the context at a context switch? What a waste! Let us take some registers out. Femto OS has the possiblity to save only those registers which are needed, but per block of four registers. So we define in the configuration file:

/* ========================================================================= */
/* REGISTER USE ============================================================ */
/* ========================================================================= */

#define  RegisterUse_Display                     registersAll
#define  RegisterUse_Speed                       r16r17r18r19 | r24r25r26r27

which registers can be used is defined in FemtoOS_0.89/MainCode/femtoos_headers/femtoos_constants.h

Maybe you have noted that this information was also presented by the compile script using the info switch. Please be warned that this is only an indication. This script is not guaranteed to be correct. Inspect the code yourself.

OK, so now we reduced the context by 24 registers, so we must be able to reduce the stack by the same amount. Set StackSafety to zero as well.

/* ========================================================================= */
/* STACK SIZES ============================================================= */
/* ========================================================================= */


#define  StackSafety                             0
#define  StackSizeOS                             24
#define  StackSizeISR                            0
#define  StackSizeOverride                       cfgOverrideNon
#define  StackSize_Display                       46
#define  StackSize_Speed                         12

Compile and flash and see that indeed we have a working application, with a context size of only 12 bytes! The total amount of RAM has decreased below the 100 bytes. Of course this kind of optimization should be done at the very end of your development cycle, because the choice of the registers by gcc cannot be predicted and can change even with the most minor change of your code.

You explore the optimization possibilities some more and redude this application even further. When you have reached the figures given on the front page:

ruud@wolf IDE $ ./script/compile compact
   text    data     bss     dec     hex    device      project
    960       0      48    1008     3f0    attiny861   HelloWorld

you are close the the optimum and a master in code reduce.

Here we part?

I was only able to show you a small part of the Femto OS and all its possibilities to reduce code size and ram usage. The best way to continue is to start building your own extra tasks in the Hello World application (do not forget to restore stack size and register use to their larger values!) and learn while you are using the OS. Have a look at the examples too, where it is shown how Femto OS calls can be used.

When you are comfortable with the syntax, you can define your own files. At the bottom of (starting at around line 2800) FemtoOS_0.89/MainCode/femtoos_headers/femtoos_constants.h a configuration template is listed, which can be used as a starting point for your own application.

And, of course, if you have additional questions, post them on the sf forum or email me.

Contact: info@femtoos.org   CC-BY License: Ruud Vlaming.