[Tinyos-2-commits] CVS: tinyos-2.x/doc/html/tutorial lesson10.html, NONE, 1.1.2.1

Henri DF henridf at users.sourceforge.net
Mon Oct 23 13:41:21 PDT 2006


Update of /cvsroot/tinyos/tinyos-2.x/doc/html/tutorial
In directory sc8-pr-cvs10.sourceforge.net:/tmp/cvs-serv13076

Added Files:
      Tag: tinyos-2_0_devel-BRANCH
	lesson10.html 
Log Message:
add lesson 10


--- NEW FILE: lesson10.html ---
<!DOCTYPE doctype PUBLIC "-//w3c//dtd html 4.0 transitional//en">
<html>
<head>
  <title>TinyOS Tutorial Lesson 10: Platforms</title>
  <link href="../../stylesheets/tutorial.css" rel="stylesheet" type="text/css">
</head>

<body>

<div class="title">Lesson 10: Platforms</div>
<div class="subtitle">Last updated October 23 2006</div>

<h1>Introduction</h1>

<p>Many different hardware platforms (e.g micaZ, telos, eyesIFX) can be
  used with TinyOS. This lesson shows you what a platform port consists
  of, and how TinyOS reuses as much code as possible between different
  platforms.
  The lesson will proceed by showing how to do the port for an imaginary
  mote called "yamp", which has a MSP430 microcontroller and a CC2420 
  radio transceiver. 

<p>
  The <b>target audience</b> of this lesson consists of those people that want
  to better understand what the difference between e.g "make micaz" and "make
  telosb" is, and how these differences concretely map into the underlying
  files, definitions, etc. 

<p> Note that the material covered in this tutorial is <b>not</b>
  strictly necessary for regular tinyos developpers, and you can safely skip
  it if you have no intention of working down to the lowest level or
  developping new platforms.

</p>

<h1>Chips vs Platforms</h1>

<p>
  Two key building blocks for any mote are the microcontroller and
  radio transceiver. 
  Of course, both a microcontroller and a radio can be used on 
  more than one platform. This is indeed the case for the MSP430 and CC2420
  that our yamp mote uses (telos, eyes, and tinynode use the MSP430; telos
  and micaz use the CC2420).
</p>

<p>
  Given this multiplicity of platforms, it would be vasly redundant if each
  platform developper had to rewrite the software support for each chip
  from scratch. While a chip may be physically wired in a different way on
  different platforms (e.g., a radio is connected to a different digital
  pins on the microcontroller), by far the largest part of the logic to
  deal with a chip is platform-independent.
</p>

<p>
  Thus, platform-independent code to support a chip is placed in a
  chip-specific directory. Writing a platform port for a platform is then 
  (essentially) a matter of <b>pulling in the code for each of the 
  platform's chips, and "gluing"  things together</b>.
  For example, the modules and components that support the CC2420 are in
  tos/chips/cc2420. This radio is used on both the telos and micaZ motes; the
  "gluing" is done by the modules in the tos/platforms/telosa/chips/cc2420 and
  tos/platforms/micaz/chips/cc2420/ directories.
</p>

<p>
  Note that in general there may
  be more to a platform port than pulling in existing code for different
  chips, in particular when a new platform uses a chip that is not yet
  supported. Developping drivers for a new chip can be a non-trivial
  undertaking (especially for radios and microcontrollers); these aspects
  are not covered here. 
</p>

<h1>Initial platform bring-up</h1>

<p>
  As a first step to bring up the platform, we will stick to the bare minimum in
  order to compile and install the Null application on our yamp mote. 
</p>

<p>
  All platform-specific code goes in tos/platforms/<platformname>. 
    For example, we have tos/platforms/micaz or tos/platforms/tinynode.
    Our first step is to create a directory for the yamp platform:
    <pre>
      $ cd tinyos-2.x/tos/platforms
      $ mkdir yamp
    </pre>
</p>

<h2>The .platform file</h2>

Each platform directory (such as tos/platforms/yamp) should contain a
file named ".platform", that contains basic compiler parameters
information for each platform. So, create the file
"tos/platforms/yamp/.platform" (note the <b>.</b> in  "<b>.</b>platform" !!!), that contains the following:

<pre>
  push( @includes, qw(

  %T/chips/cc2420
  %T/chips/msp430
  %T/chips/msp430/adc12
  %T/chips/msp430/dma
  %T/chips/msp430/pins
  %T/chips/msp430/timer
  %T/chips/msp430/usart
  %T/chips/msp430/sensors
  %T/lib/timer
  %T/lib/serial
  %T/lib/power
  ) );

  @opts = qw(

  -gcc=msp430-gcc
  -mmcu=msp430x1611
  -fnesc-target=msp430
  -fnesc-no-debug
  -fnesc-scheduler=TinySchedulerC,TinySchedulerC.TaskBasic,TaskBasic,TaskBasic,runTask,postTask

  );

</pre>
    
<p>
  This file contains perl snippets that are intepreted by the ncc compiler. 
  The first statement simply adds some directories to the include path that
  is used when compiling an application for the yamp platform (the %T gets
  expanded to the full location of tinyos-2.x/tos, using the TOS2DIR
  environment variable). Note that we have included the CC2420 and MSP430
  directories, as well as some libraries.
</p>

<p>
  The second statement defines the @opts list, that contains various parameters
  passed to nesc. Please consult the nesc documentation for information on the
  meaning of these parameters.
</p>

<h2>The hardware.h file</h2>

<p>
  Each platform directory also has a file named "hardware.h" that is included by
  default when compiling an application for that platform. This can define
  platform-specific constants, pin names, or also include other "external"
  header files (e.g. msp430hardware.h in our case, or atm128hardware.h for
  platforms using the atm128 MCU).<br>

  So, create the file "tos/platforms/yamp/hardware.h" with the following contents:
</p>

<pre>
  #ifndef _H_hardware_h
  #define _H_hardware_h

  #include "msp430hardware.h"

  // LEDs
  TOSH_ASSIGN_PIN(RED_LED, 5, 4);
  TOSH_ASSIGN_PIN(GREEN_LED, 5, 5);
  TOSH_ASSIGN_PIN(YELLOW_LED, 5, 6);

  // UART pins
  TOSH_ASSIGN_PIN(SOMI0, 3, 2);
  TOSH_ASSIGN_PIN(SIMO0, 3, 1);
  TOSH_ASSIGN_PIN(UCLK0, 3, 3);
  TOSH_ASSIGN_PIN(UTXD0, 3, 4);
  TOSH_ASSIGN_PIN(URXD0, 3, 5);
  TOSH_ASSIGN_PIN(UTXD1, 3, 6);
  TOSH_ASSIGN_PIN(URXD1, 3, 7);
  TOSH_ASSIGN_PIN(UCLK1, 5, 3);
  TOSH_ASSIGN_PIN(SOMI1, 5, 2);
  TOSH_ASSIGN_PIN(SIMO1, 5, 1);


  #endif // _H_hardware_h
</pre>

<p>
  This file simply pulls in msp430hardware.h from tos/chips/msp430 (the compiler
  will find it because we have added this directory to our search path in the
  .platform created previously) and defines some physical pins using macros from
  msp430hardware.h. For example, on our yamp mote, the red led is physically
  connected to the general purpose I/O (GPIO) pin 5.4.
</p>

<p>
  Some other very important functions (that are defined in msp430hardware.h
  and so pulled in indirectly via this hardware.h)
  concern the disabling of interrupts for atomic sections (atomic blocks in nesc
  code essentially get converted into __nesc_atomic_start() and
  __nesc_atomic_end()). How interrupts are disabled is of course microcontroller
  specific; the same applies to putting the microcontroller to sleep (as is done
  by the scheduler when there are no more tasks to run, using the McuSleep
  interface). These functions must be somehow defined for each platform, 
  typically by means of an <tt>#include</tt>'d MCU-specific file.<br>
<i>  As an exercise, try finding the definitions of</i> __nesc_atomic_start() <i>and
</i>  __nesc_atomic_end()<i> for the micaZ and intelmote2 platforms.</i>

</p>

<h1>Setting up the build environment and building the "null" app</h1>
Before pulling in existing chip drivers or writing any code, we must set up
the build environment so that it is aware of and supports our platform.

Once this is done, we will define the basic TinyOS module for our platform,
and use the Null app (in tinyos-2.x/apps/null) in order to test that our
platform is properly configured. As per it's description in its README file,
Null is an empty skeleton application.  It is useful to test that the
build environment is functional in its most minimal sense, i.e., you
can correctly compile an application. So, let's go ahead and try to compile 
Null for the yamp platform:

<!-- <h2> Defining a make target</h3> -->

<!-- At this point we have created all the necessary files in tos/platforms/yamp/ -->
<!-- in order to run the Null application. But how do we compile it and install it -->
<!-- on our yamp mote? -->

<!-- We would like to enter "make yamp" in any application directory and have a -->
<!-- yamp binary be built, just as e.g. "make micaz" builds us a micaz -->
<!-- binary. But if we try it at this point we get an error message listing all the -->
<!-- valid targets and telling us that yamp is not a valid target: -->

<pre>
  $ cd tinyos-2.x/apps/Null
  $ make yamp
/home/henridf/work/tinyos-2.x/support/make/Makerules:166: *** 

Usage:  make <target> <extras>
        make <target> help

        Valid targets: all btnode3 clean eyesIFX eyesIFXv1 eyesIFXv2 intelmote2 mica2 mica2dot micaz null telos telosa telosb tinynode tmote
        Valid extras: docs ident_flags nescDecls nowiring rpc sim sim-cygwin sim-fast tos_image verbose wiring

 Welcome to the TinyOS make system!

 You must specify one of the valid targets and possibly some combination of
 the extra options.  Many targets have custom extras and extended help, so be
 sure to try "make <target> help" to learn of all the available features.

 Global extras:

   docs    : compile additional nescdoc documentation
   tinysec : compile with TinySec secure communication

ERROR, "yamp tos-ident-flags tos_image" does not specify a valid target.  Stop. 
  
</pre>

<p>
The problem is that we need to define the platform in the <i>TinyOS build
  system</i>, so that the make invocation above recognizes the yamp platform.
The TinyOS build system is a Makefile-based set of rules and definitions
that has a very rich functionality. This includes invoking
necessary  compilation commands as with any build system, but goes much
  further and includes support for other important aspects such as 
device reprogramming or supporting multiple platforms and targets.
</p>

<p>
A full description of the inner workings of the TinyOS build system is beyond
  the scope of this tutorial. For now, we will simply see how to define the
  yamp platform so that the "make yamp" command does what it should. (For those
  that want to delve deeper, start with "tinyos-2.x/support/make/Makerules".)
</p>

<h2> Defining a make target</h3>

The TinyOS build system resides in "tinyos-2.x/support/make". The strict
minimum for a platform to be recognized by the build system (i.e., for the
build system to understand that "yamp" is a legal platform when we enter "make
yamp") is the existence of a <i>platformname</i>.target file in the
aforementioned make directory.<br>
So, create the file "tinyos-2.x/support/make/yamp.target" with the following
contents:

<pre>

PLATFORM = yamp

$(call TOSMake_include_platform,msp)

yamp: $(BUILD_DEPS)
	@:
</pre>

This sets the PLATFORM variable to yamp, includes the msp platform
("make/msp/msp.rules") file, and provides in the last two lines a make rule
for building a yamp application using standard Makefile syntax.

Now, let's go back and try to compile the Null app as before. This time we get:

<pre>
[18:23 henridf at tinyblue: ~/work/tinyos-2.x/apps/Null] make yamp
mkdir -p build/yamp
    compiling NullAppC to a yamp binary
ncc -o build/yamp/main.exe -Os -Wall -Wshadow -DDEF_TOS_AM_GROUP=0x7d -Wnesc-all -target=yamp -fnesc-cfile=build/yamp/app.c -board=   NullAppC.nc -lm 
In file included from NullAppC.nc:42:
In component `MainC':
/home/henridf/work/tinyos-2.x/tos/system/MainC.nc:50: component PlatformC not found
/home/henridf/work/tinyos-2.x/tos/system/MainC.nc:53: no match
make: *** [exe0] Error 1
</pre>

So there's progress of sorts, since now we're getting a "real" compilation
error as opposed to not even making it past the build system. Let's take a
closer look at the output. The ncc compiler is unhappy about not finding a
"PlatformC" component.

The "PlatformC" component must be defined for each platform. Its role and
placement in the system is described in more detail in TEP107. For now,
suffice to cite from that TEP that:
<i>A port of TinyOS to a new plaform MUST include a component PlatformC which
  provides one and only one instance of the Init interface.</i>.


Create the file "tos/platforms/yamp/PlatformP.nc" with the following contents:

<pre>
#include "hardware.h"

module PlatformP{
  provides interface Init;
  uses interface Init as Msp430ClockInit;
  uses interface Init as LedsInit;
}
implementation {
  command error_t Init.init() {
    call Msp430ClockInit.init();
    call LedsInit.init();
    return SUCCESS;
  }

  default command error_t LedsInit.init() { return SUCCESS; }

}
</pre>

, and create the file "tos/platforms/yamp/PlatformC.nc" as:

<pre>
#include "hardware.h"

configuration PlatformC
{
  provides interface Init;
}
implementation
{
  components PlatformP
    , Msp430ClockC
    ;

  Init = PlatformP;
  PlatformP.Msp430ClockInit -> Msp430ClockC.Init;
}
</pre>

Now, compilation of the Null application finally works for the yamp platform:

<pre>
[19:47 henridf at tinyblue: ~/work/tinyos-2.x/apps/Null] make yamp
mkdir -p build/yamp
    compiling NullAppC to a yamp binary
ncc -o build/yamp/main.exe -Os -Wall -Wshadow -DDEF_TOS_AM_GROUP=0x7d -Wnesc-all -target=yamp -fnesc-cfile=build/yamp/app.c -board=   NullAppC.nc -lm 
    compiled NullAppC to build/yamp/main.exe
            1216 bytes in ROM
               6 bytes in RAM
msp430-objcopy --output-target=ihex build/yamp/main.exe build/yamp/main.ihex
    writing TOS image
</pre>


<h1>Getting Blink to work</h1>

With the previous steps, we now have the basic foundation to start working on
our yamp platform: the basic platform definitions are in place, and the build
system recognizes and correctly acts upon the "make yamp" target. We haven't
yet actually <i>programmed</i> our mote yet. 
<p>
The next step in the bring-up of a platform, that we will cover in this part,
is to program a node with an application and verify that it actually
works. We'll do this with Blink, because it is simple, and easy to verify that
it works. As a bonus, we'll also have validated basic timer functionality once
we see those Leds turning on and off.
<p>
As a first step, let's go to the Blink application directory and try to
compile the application:
<pre> 
[19:06 henridf at tinyblue: ~/work/tinyos-2.x/apps/Blink] make yamp
mkdir -p build/yamp
    compiling BlinkAppC to a yamp binary
ncc -o build/yamp/main.exe -Os -Wall -Wshadow -DDEF_TOS_AM_GROUP=0x7d -Wnesc-all -target=yamp -fnesc-cfile=build/yamp/app.c -board=   BlinkAppC.nc -lm 
In file included from BlinkAppC.nc:45:
In component `LedsC':
/home/henridf/work/tinyos-2.x/tos/system/LedsC.nc:38: component PlatformLedsC not found
/home/henridf/work/tinyos-2.x/tos/system/LedsC.nc:42: cannot find `Init'
/home/henridf/work/tinyos-2.x/tos/system/LedsC.nc:43: cannot find `Led0'
/home/henridf/work/tinyos-2.x/tos/system/LedsC.nc:44: cannot find `Led1'
/home/henridf/work/tinyos-2.x/tos/system/LedsC.nc:45: cannot find `Led2'
make: *** [exe0] Error 1
</pre>

The compiler cannot find the component "PlatformLedsC" that is referred to in 
the file tos/system/LedsC.nc. As the name indicates, "PlatformLedsC" is a
platform-specific component, and thus we will need to define this component
for the yamp platform. 
<p>
Why should there be such a platform-specific component for accessing Leds?  This is because at
the lowest level, i.e in hardware, Leds are implemented differently on
different platforms. Typically, a Led is connected to a microcontroller I/O pin,
and the Led is turned on/off by setting the appropriate output 0/1 on that
pin. This is in fact the model used on all current TinyOS platforms. 
But even in this simple and uniform model, (and disregarding
the fact that future platforms may use different hardware implementations
and not connect each Led directly to an I/O pin), we have that the
lowest-level to turn on/off a Led must be defined on a per-platform basis. 
<p> 
Now, consider Leds from another perspective, namely that of the Leds.nc
interface (defined in tos/interfaces/Leds.nc). In this interface, we have
commands such as <tt>get();</tt> in principle such a command does not need to be
platform-dependent: the code that maintains the current state of a Led and
returns it via the get() call does not need to be re-written each time a Led
is connected to a different pin (of course re-writing get() for each
platform would  not be much overhead given its simplicity; this argument
clearly becomes far stronger in more complex situations involving entire chips
rather than individual GPIOs).
<p> The key notion that the above example is simply that there is a boundary
  above which software components are platform-independent, and below which
  components are specifically written with one hardware platform in mind. 
  This is at heart a very simple concept; its complete instantiation in TinyOS is of
  course richer than the above example, and is the topic of TEP2 (Hardware
  Abstraction Architecture).
<p> Let's now return to the task at hand, which is to make Blink work on our
  platform. If we take a closer look at the file "tos/system/LedsC.nc", we see
  that it contains a configuration that wires the module LedsP with modules
  Init, Leds0,  Leds1, and Leds2, all of which are to be provided by the
  (still missing) PlatformLedsC. Taking a closer look at
  "tos/system/LedsP.nc", we see that the Leds0,1,2 modules used by LedsP are
  GeneralIO interfaces. The GeneralIO interface (see
  "tos/interfaces/GeneralIO.nc" and TEP 117) simply encapsulates a digital I/O pin and
  provides functions to control its direction and get/set its input/output
  values. 
<p> So, we need to create a PlatformLedsC configuration that shall provide
  three GeneralIO interfaces and an Init. This is done by creating the file
  "tos/platforms/yamp/PlatformLedsC.nc" with the following contents:

<pre>
#include "hardware.h"

configuration PlatformLedsC {
  provides interface GeneralIO as Led0;
  provides interface GeneralIO as Led1;
  provides interface GeneralIO as Led2;
  uses interface Init;
}
implementation
{
  components 
      HplMsp430GeneralIOC as GeneralIOC
    , new Msp430GpioC() as Led0Impl
    , new Msp430GpioC() as Led1Impl
    , new Msp430GpioC() as Led2Impl
    ;
  components PlatformP;

  Init = PlatformP.LedsInit;

  Led0 = Led0Impl;
  Led0Impl -> GeneralIOC.Port54;

  Led1 = Led1Impl;
  Led1Impl -> GeneralIOC.Port55;

  Led2 = Led2Impl;
  Led2Impl -> GeneralIOC.Port56;

}
</pre>

We refer the reader to the TinyOS Programming Guide cited below for more
explanations on how the above confiuration uses generics (ie with the "new"
keyword). For the purpose of this lesson, the key point is that we are wiring
to ports 5.4, 5.5, and 5.6 -- we shall suppose that these  are the MSP430 
microcontroller pins to which the three Leds are connected on the yamp
platform.  <p>

With the above file in place, we can now compile Blink for the yamp platform. 
How do we test that the application actually works? We have thus far presented
yamp as an imaginary platform, but it turns out that the above application
should work on any platform with the MSP430x1611 microcontroller and where the
Leds are connected to microcontroller ports 5.4-5.6. 
Not entirely coincidentally, these are exactly the Led wirings used by the
telos/tmote platforms. So those readers that have a telos/tmote at hand can
test this application on it. (Testing on a tinynode or eyes mote is also easy and only
requires changing the pin wirings in PlatformLedsC to follow those of that
platform; running this application on mica-family motes will require more
changes since they use a different microcontroller).

<p>
Now, enter the following command (where you have suitably replaced /dev/ttyXXX by the appropriate serial port),
<pre>
  make yamp install bsl,/dev/ttyXXX
</pre>
and you will see the Leds of your impersonated (by a telos) yamp node Blinking!

<h1>Conclusion</h1>

<p>This lesson has introduced the notion of per-platform support in TinyOS
  using as a guiding example the development of a platform port to an
  imaginary "yamp" platform. We have seen how introducing support for a new
  platform requires touching not only nesc code but also adding some rules to
  the build system. This tutorial also touched upon the notions of Hardware
  Abstraction Architecture (HAA) that is central to the clean and modular
  support of different platforms and chips in TinyOS.
<p>
  The steps outlined here did not cover what is the hardest part of
  a platform port: developping the components to drive a radio transceiver or
  MCU (which are necessary if the platform uses chips that are not currently
  supported in TinyOS). Developping such drivers is an advanced topic that is
  beyond the scope of the tutorials; for those curious to gain some insight we
  recommend perusing the code for a chip (e.g the CC2420 radio in
  tos/chips/cc2420 or the xe1205 radio in tos/chips/xe1205) armed with that
  chips datasheet and the platform schematics.
<p>
<a name=#related_docs>
<h1>Related Documentation</h1>
</a>
<ul>
<li> <a href="https://sourceforge.net/projects/nescc">nesc at sourceforge</a>
<li> <a href="http://nescc.sourceforge.net/papers/nesc-ref.pdf">nesC reference manual</a>
<li> <a href="http://csl.stanford.edu/~pal/pubs/tinyos-programming-1-0.pdf">TinyOS Programming Guide</a>
<li> <a href="../tep102.html">TEP 2: Hardware Abstraction Architecture</a>
<li> <a href="../tep106.html">TEP 106: Schedulers and Tasks</a>
<li> <a href="../tep107.html">TEP 107: TinyOS 2.x Boot Sequence</a>
<li> <a href="../tep117.html">TEP 117: Low-level I/O</a>
</ul>

<p>
<hr>


<!-- Begin footer -->
<br>
<hr>
<center>
<p>&lt;&nbsp;<b><a href="index.html">Top</a></b> 
&nbsp;</b>
</center>

</body>
</html>



More information about the Tinyos-2-commits mailing list