Abstract
The purpose of this TEP is to provide on overview of how to build a new TinyOS 2 platform. While the purpose of most TEPs is to describe TinyOS 2 entities, we will present concrete suggestions on how to implement a new TinyOS 2 platform. We will use examples and briely cover the relevant TEPs to present a platform that adheres to the current TinyOS standards. We will not cover the TEPs in detail, but to the full text of each TEP for further information.
This TEP will go through the tool chain setup and the most basic components for a functional TinyOS platform. We consider only TinyOS version 2.x (from now on TinyOS).
Before venturing on this quest we will take a diversion and introduce general TinyOS 2 concepts and terminology (Section 1), readers familiar to TinyOS 2 can skip this section. This document will introduce the TinyOS 2 platform (Section 2) and describes the 3 elements that make up a platform: the tool chain (Section 3) the platform de nitions (Section 4) and the chips de nitions (Section 5).
1. TinyOS Overview
Before describing the process of writing TinyOS platforms we will briefly sum up the TinyOS ecosystem and the terminology required in this TEP. To learn more visit the TinyOS website http://www.tinyos.net.
A systems overview is depicted below. In this TEP we will primarily concern our selves with the platform portion of gure and briefly cover the tool chain. This involves writing the necessary drivers and writing rules to pass the code to the TinyOS tool chain. We will not cover sensor boards in this TEP refer to, see [TEP109] for details.
+——————————————+
| Application |
+——————————————+
+——–+ +———-+ +————–+
| TinyOS | + | Platform | + | Sensor board |
+——–+ +———-+ +————–+
|
V
+——————-+
| TinyOS tool chain |
+——————-+
|
Target platform V
+————————————-+
| +——-+ +—–+ +——-+ |
| | Radio |—-| MCU |—-|Sensors| |
| +——-+ +—–+ +——-+ |
+————————————-+
1.1 TinyOS 2 architecture
TinyOS 2.x is built on a tree-layered hardware abstraction architecture (HAA)[TEP2]. This architecture separates the code for each platform into distinct layers:
1. the Hardware Independent Layer (HIL)
2. the Hardware Adaptation Layer (HAL)
3. the Hardware Presentation Layer (HPL)
A platform is built from bottom up, starting with the HPL level, building HAL and HIL layers on top. Platform independent applications are written using HIL level interfaces, allowing them to move easily from platform to platform. While applications can target a platform speci c HAL layer for finer control of hardware speci c features, this will could prohibit such an application from being easily portable. An overview of the TinyOS 2 architecture is given in [tos2.0view].
The requirements for the platform implementation is described in TinyOS Enhancement Proposals (TEP). Each TEP covers a particular area and species the recommendations within that area, some of which are relevant for platforms. While no speci c label or designation is given to platforms adhering to the set of TEPs, [TEP1] states: \Developers desiring to add code (or TEPs) to TinyOS SHOULD follow all current BCPs (Best Current Practice)". At the time of writing no TEP has been awarded this designation or been nalized and we will refer to the drafts as they are.
This document will not go through each of the requirements, but merely outline how to build a basic functional platform. For further information see \TinyOS 2.0 Overview" [tos2.0view] or the TEP list on the TinyOS website http://www.tinyos.net.
1.2 TinyOS Contrib
The core of TinyOS is maintained by a set of working groups that govern specific parts of the source code. New project can bene t from the contrib section of TinyOS. This is a separate section of the website and source repository maintained more loosely than the core of TinyOS. It is intended for sharing code at an early stage or code that may not gain the same popularity as the core.
New projects request a directory in this repository by following a simple procedure on the TinyOS contrib web page
In contrib is a skeleton project skel that provides the most basic framework for setting up a new platform, MCU, etc.
2. A TinyOS Platform
A TinyOS platform provides the code and tool chain de nitions that enable an application writer to implement an application for a mote. A platform in TinyOS exposes some or all of the features of a particular physical mote device to TinyOS applications – it refers to an entire system, not a single chip. In order to write programs for a device using TinyOS a platform for that device must exist within TinyOS.
A physical platform is comprised of a set of chips. Similarly a TinyOS platform is the collection of the components representing these chips (corresponding to drivers) Common chips can be shared among platforms and implementing a new platform could simply mean wiring existing components in a new way. If the chips that make up the platform are not supported by TinyOS implementing the new platform consists if implementing components for those chips (much like implementing drivers).
2.1 A New Platform
Platforms are discovered at compile time by the TinyOS tool chain and a new platform placed in the search path will be discovered automatically. In addition sensor boards can be de ned in a very similar manner, however we will not cover sensor boards, see [TEP109] for details. De ning a new platform boils down to 3 things:
1. de nitions of the chips that make up the platform,
2. platform de nitions (combining chips to a platform) and,
3. the tool chain or make definitions.
The code for a TinyOS platform is spread out in a few locations of the TinyOS tree depending based on those 3 categories. Below is an overview of the locations and some of the les we will be needing in
the following (for further information see see \Coding Conventions" [TEP3] and the \README" les in
each directory).
Through this TEP we will use the terms PlatformX and MCUX to denote the new generic platform
and MCU being created:
tos
+–chips 1. Chip definitions
| +–chipX
+–platforms
| +–platformX 2. Platform definitions
| +–PlatformP/PlatformC
| +–PlatformLeds example component
| +–.platform
| +–hardware.h
| +–chips
| +–MCUX Platform specific features
| +–chipX
+–sensorboards
| +–boardX
| +–.sensor
+–support
+–make 3. Make definitions
+–platformX.target platformX make targets
+–MCUX
+–MCUX.rules make rules for MCUX
+–install.extra additional target for MCUX
In the following we will briefly introduce each of the parts and describe them in more detail in sections 2 through 4.
2.2 The Chips
Each of the chips that provide software accessible functionality must have de nitions present in the chips directory sensors, radios, micro controllers (MCU) alike. Each chip is assigned a separate directory under tos/chips. This directory contains chip speci c interfaces (HPL and HAL interfaces) and their implementations as well as implementations of the hardware independent interface (HIL).
Some chips, MCUs in particular, contain distinct subsystems, such as uart, timer, A/D converter, SPI, and so forth. These subsystems are often put in a sub directory of their own within the chip-specific directory.
If some feature of a chip is available or used only on a particular platform, the platform directory can contain code that is speci c to this combination of chip and platform, say pin assignments, interrupt assignments, etc. For example such additions would be placed in tos/platforms/platformX/chips/chipX for PlatformX.
2.3 The Platform Directory
The platform is the piece of the puzzle that ties the components corresponding to physical chips (drivers) together to form a platform. The platform ties together the code that exposes the features of the platform to TinyOS programs. In practise this is done by i) including code for each of the chips and ii) by providing any additional code that is speci c to this particular platform.
A platform PlatformX would be placed in the directory tos/platforms/platformX/ and code for subsystems reside in further sub directories. Also in this directory is the .platform le that sets up include paths and more (see Section 3).
An empty platform with no code (null) is provided and serves as an example for other platforms.
2.4 The Tool-Chain (Make System)
The build system for TinyOS is written using GNU Make1. The build system controls the process from pre-processing a TinyOS application into a single C le and to pass this le to the appropriate compiler and other tools. The make system is documented in support/make/README and in TinyOS 2 Tutorial Lesson 10[TUT10].
The make system is located in the support directory. This directory contains a platform de nition and Make rules to build an application for this platform (see Section 2).
2.5 The Minimal Platform
Before describing each of the subsystems, we will show a simple check list. The absolute minimal TinyOS platform would have to provide the following resources, given a PlatformX with MCUX:
a platform directory tos/platform/PlatformX/ with the following
{ a platform de nition (.platform le)
{ a hardware.h header
a platformX.target in tos/support/make
a MCUX.rules in tos/support/make/MCUX
a MCUX directory in tos/chips/MCUX, containing
{ a McuSleepC (must enable interrupts)
{ a mcuxhardware.h (de nes nesc atomic start/nesc atomic end)
3. Tool Chain
The major components in the tool chain of TinyOS are i) the compiler and ii) the build system that uses the compiler to produce an executable binary or hex le. The rst is installed separately, while the second is part of the TinyOS source code. The compile process transforms a set of nesC les into a binary executable or hex le. Involved in this process is set of separate tools that are linked in a chain.
We will briefly cover this chain in a moment, but a detailed description is beyond the scope of this TEP. The make system is split in two: a general part and a platform speci c part. Section 3.1 will introduce the general mechanism and Section 3.2 will cover how to introduce a new platform in the tool chain.
3.1 Compiling using nesC
The process of the build system is depicted below. This system feeds the source code through the tools to produce an executable or hex le for uploading to the platform. The nesC pre-compiler is split in two tools ncc an nescc. These two tools are used to assemble nesC source les into a single C le which is compiled using a regular C compiler. This requires that a C compiler is available for a given platform and that this compiler accepts the dialect produced by nesC.
TinyOS
application
|
|
V
+——+ +—–+ +———+ +————+
| ncc | app.c | | Binary | | app.hex | |
| + |——>| GCC |——->| objdump |——–>| programmer |
| nesC | | | | | | |
+——+ +—–+ +———+ +————+
|
|
V
Target
platform
The core TinyOS platforms are centered around GCC, this includes the telos family, mica family and intelmote2. The nesC compiler expects code resembling GCC C-dialect and also outputs code in GCC C-dialect. The current TinyOS platforms are supported by GCC, but for some processor architectures GCC is not available (e.g. Motorola HCS08, Intel MCS51).
Porting to platforms that are GCC supported can bene t from the existing tool flow, while porting to other platforms requires some e ort. A straight forward solution adopted for these platforms is to post-process the C les produced by nesC to t the needs of a speci c compiler, see TEP121 for an example of such a solution.
3.2 The Make System
TinyOS controls the build process using make. The global make le searches certain locations to nd make de nitions for all available platforms. In order to make a new platform available to the TinyOS make system, a few les must be created in particular locations. These les will be read by the global make system and exposed to the users by make targets. Often the required rules are tied to a particular MCU that is shared among several platforms and TinyOS leverages this fact by creating a light-weight .target le pointing to the appropriate rules in a .rules le. The make system is documented in support/make/README and in TinyOS 2 Tutorial Lesson 10[TUT10].
The make system looks for .target les in support/make and the directories listed in the environment variable TOSMAKE_PATH. Each of the les found contain make targets for one TinyOS platform. The target les usually do not contain the rules to build the binary les, but include the appropriate rules from a .rules le, located in a sub directory for the appropriate MCU architecture (e.g. avr for the ATMega128 used by Mica). In this way many platforms share the build rules, but have di erent .target les. In addition .extra targets can be used to de ne helper targets such as install or clean.
Setting up the make system, requires two steps (Section 3.2.1 gives an example):
1. Creating a platformX.target le that allows the make system to discover the new platform. This le must contain a make rule with the name of the platform. Further this target must depend on the targets given in the variable BUILD_DEPS – this variable contains the remainder of targets to be build during the build process.
2. Creating a .rules le in a sub diretory of support/make. Each le contain the actual target for producing the binaries, hex les, etc. for one platform. They are assembled in the BUILD_DEPS variable.
We will cover these two les next.
3.2.1 The .target file
As mentioned above TinyOS searches for targets in the support/make directory of the TinyOS source code and in the directories listed in the environment variable TOSMAKE_PATH. A .target le for the platform must exist in one of these locations. The .target usually only sets up variables related to this platform and provide a target named after the platform, this target depend on other rules to build the binaries. These rules are included by calling TOSMake_include_platform. toni.target is listed below:
PLATFORM = toni
PFLAGS += -finline-limit=100000 -I../../tos/platforms/toni
$(call TOSMake_include_platform,toni)
toni: $(BUILD_DEPS)
@:
Pay attention to the call to TOSMake_include_platform,toni this call includes .rules les in support/make or any sub directory of TOSHMAKE_PATH named toni.
3.2.2 The .rules file
The .rules file contain the make rules for building the target binary. If a MCU implementation already exists for a new platform, simply pointing to this .rules from the corresponding .target is sufficient. If not the .rules le must be built for a new MCU architecture.
TOSMake_include_platform expects a sub directory with a rule le of the form toni/toni.rules. The call also includes additional .rules and .extra les present in that sub directory. For I still feel confusing on how to integrate nios2gcc tools into nesC, so I just use the .rules of skel from tinyos-2.x-contrib to generate pc binary just for getting the .c file. Then we could compile .c file in Nios2 IDE instead of generating nios2 binary file automatically. See support/make/README for details.
The toni.rules is as followings:
define TONI_HELP
TONI extras:
toni : this is a skeleton – it doesn’t do anything!
endef
TONI += $(TONI_HELP)
OBJCOPY = objcopy
OBJDUMP = objdump
NCC = ncc
LIBS = -lm
BUILDDIR = build/$(PLATFORM)
MAIN_EXE = $(BUILDDIR)/main.exe
MAIN_SREC = $(BUILDDIR)/main.srec
MAIN_IHEX = $(BUILDDIR)/main.ihex
INSTALL_SREC = $(MAIN_SREC).out$(if $(NODEID),-$(NODEID),)
VOLUMEFILE = volumes-at45db.xml
PFLAGS += -Wall -Wshadow -DDEF_TOS_AM_GROUP=$(DEFAULT_LOCAL_GROUP) $(NESC_FLAGS)
PFLAGS += -I../../tos/platforms/toni -target=$(PLATFORM) -fnesc-cfile=$(BUILDDIR)/app.c
ifdef MSG_SIZE
PFLAGS += -DTOSH_DATA_LENGTH=$(MSG_SIZE)
endif
BUILDLESS_DEPS += bytes
ifndef NOWIRING
include $(TINYOS_MAKE_PATH)/wiring.extra
endif
ifndef BUILD_DEPS
ifeq ($(filter $(BUILDLESS_DEPS),$(GOALS)),)
BUILD_DEPS = exe bytes $(POST_BUILD_EXTRA_DEPS)
endif
endif
exe: exe0 bytes FORCE
@:
exe0: builddir $(BUILD_EXTRA_DEPS) FORCE
@echo " compiling $(COMPONENT) to a $(PLATFORM) binary"
$(NCC) -o $(MAIN_EXE) $(OPTFLAGS) $(PFLAGS) $(CFLAGS) $(COMPONENT).nc $(LIBS) $(LDFLAGS)
@echo " compiled $(COMPONENT) to $(MAIN_EXE)"
builddir: FORCE
mkdir -p $(BUILDDIR)
bytes: FORCE
@objdump -h $(MAIN_EXE) | perl -ne ‘$$b{$$1}=hex $$2 if /^\s*\d+\s*\.(text|data|bss)\s+(\S+)/; END { printf("%16d bytes in ROM\n%16d bytes in RAM\n",$$b{text}+$$b{data},$$b{data}+$$b{bss}); }’
Note: This process need to be updated in the following days.
4. The Platform
A TinyOS platform is a collection of components corresponding to a physical devices (a collection of drivers). A platform is constructed by de ning which components make up the platform and by providing any additional platform specific components. The content of a platform is not covered by a TEP at the time of writing and the following is based on the available tutorials, READMEs and the current consensus.
The platform definitions for a PlatformX are located in tos/platforms/platformX and contain 3 major elements:
1. The .platform file containing include paths and other arguments for nesC
2. Platform boot procedure: PlatformP/PlatformC
3. Platform specific code, including a header for hardware specific funtions (hardware.h) and code that is specific to the combination of chip and platform (e.g. pin assignments, modifications, etc.).
In the following we will describe each of these in more detail, below is a depiction of a fictuous platform and the required definitions.
Platform: .platform
include MCU driver
+————————-+
| Chips: | PlatformP
| | Initialize MCU
| +——-+ |
| | NIOS2 +—–+ | hardware.h
| +——-+ | | Include MCU HW macros
| +–+—-+ |
| | Leds | | HIL interfaces, eg:
| +——-+ | PlatformLeds
| |
+————————-+
All the files we describe here must be found in a common directory named after the platform; we call this a platform directory. This directory must be found in the TinyOS tool chain search path for example tos/platforms (or found in TOSHMAKE_PATH see Section 3.2.1). For example a platform named PlatformX could be placed in the directory tos/platforms/platformX.
4.1 .platform file
All platform directories must carry a .platform file, this file defines what makes up the platform. This file carries instructions for the make system on where to locate the drivers for each of the components of the platform. The de nitions are read in a two step process: the le is read by the ncc script that passes the appropriate arguments to the nesC pre-processor[nescman]. The .platform file is written as a Perl script interpreted by ncc.
The file is documented in form of the README le in the platforms directory (tos/platforms), and the source code of the ncc script found in the TinyOS distribution. Valuable information can also be found in [TEP106], [TEP109], TinyOS 2 Tutorial Lesson 10[TUT10].
In addition to setting up include paths for nesC other arguments can be passed on. In particular the components to be used for the scheduler are selected with the ‘-fnesc-scheduler’ command line argument (see [TEP106]). The include paths are passed on using the ‘-I’ command line argument covered in [TEP109].
.platform file that includes all toni directories look like this:
#
# .platform file that includes all toni directories
#
#
push( @includes, qw(
%T/platforms/toni
%T/chips/nios2
%T/lib/timer
%T/lib/serial
) );
@opts = qw(
-gcc=gcc
-fnesc-target=pc
-fnesc-no-debug
-fnesc-scheduler=TinySchedulerC,TinySchedulerC.TaskBasic,TaskBasic,TaskBasic,runTask,postTask
);
4.2 PlatformP and PlatformC
The PlatformP and PlatformC components are responsible for booting this platform to a usable state. In general this usually means things like calibrating clock and initializing I/O pins. If this platform requires that some devices are initialized in a particular order this can be implemented in a platform dependent way here. The boot process covered in [TEP107].
Most hardware peripherals require an initialization procedure of some sort. For most peripheral devices this procedure is only required when the device is in use and can be left out if the device is unused. TinyOS accomplishes this by providing a few initialization call backs interfaces. When a given component is included it wires an initialization procedure to one of these interfaces. In this way the procedure will only be included when the component is included, this process is known as auto wiring[TOSPRG].
The boot sequence calls two initialization interfaces in the following order: PlatformC.Init and MainC.SoftwareInit. PlatformC.Init must take care of initializing the hardware to an operable state and initialization that has hidden dependencies must occur here. Other components are initialized as part of SoftwareInit and the orderign is determined at compile time.
Common tasks in PlatformC.Init include clock calibration and IO pins. However this component can be used to provide greater control of the boot process if required. Consider for example that some component which is initialized in SoftwareInit requires that some other component has been initialized previously – lets say that the radio must be initialized prior to the radio stack or that a component prints a message to the UART during boot. How can this order be ensured? One solution is to provide an additional initialization handle prior to SoftwareInit and wire such procedures to this handle. Below is an example from the Mica mote family using the MoteInit interface. Components that must be initialized early in the boot process is wired to this interface. If greater level of control is required
this strategy can be trivially be expanded to further levels of interfaces for example MoteInit1 being initialized prior to MoteInit2, this strategy is chosen by the MSP430 implementation.
4.2.1 PlatformC
Below is depicted the PlatformC component from the Mica family of platforms.
#include "hardware.h"
configuration PlatformC {
provides {
interface Init;
/**
* Provides calibration information for other components.
*/
interface Atm128Calibrate;
}
uses interface Init as SubInit;
} implementation {
components PlatformP, MotePlatformC, MeasureClockC;
Init = PlatformP;
Atm128Calibrate = MeasureClockC;
PlatformP.MeasureClock -> MeasureClockC;
PlatformP.MoteInit -> MotePlatformC;
MotePlatformC.SubInit = SubInit;
}
4.2.1 PlatformP
Below is depicted the PlatformP component from the Mica family of platforms.
module PlatformP
{
provides interface Init;
uses interface Init as MoteInit;
uses interface Init as MeasureClock;
}
implementation
{
void power_init() {
…
}
command error_t Init.init()
{
error_t ok;
ok = call MeasureClock.init();
ok = ecombine(ok, call MoteInit.init());
return ok;
}
}
4.2.3 Init example: PlatformLedsC
Below is an example from mica/PlatformLedsC.nc wiring to the platform specific MoteInit interface.
configuration PlatformLedsC {
provides interface GeneralIO as Led0;
…
uses interface Init;
} implementation {
components HplAtm128GeneralIOC as IO;
components PlatformP;
Init = PlatformP.MoteInit;
…