Title: Porting Contiki Crash Course
1Porting ContikiCrash Course
- Kista, Sweden
- 26-27 March 2007
2Porting Contiki
- Contiki is designed to be easy to port
- Porting the base system is instant
- No architecture-dependent code
- Stuff that needs porting
- The clock module
- I/O (network drivers, serial driver, sensors, )
- ELF loader
- Multi-threading
- Possible C compiler-quirks
- Makefiles
3This presentation
- I will present the ideal Contiki port
- Not all ports look exacly like this
- Ports under development typically do not look
like this - However, we should aim for it
- Having this structure in mind during porting
makes things easier
4Overview
- Directory structure
- The native port
- The clock module
- contiki-conf.h
- Network drivers
- Sensors
- Integrating into the Contiki build system
- ELF loader
- Multi-threading
5Directory structure
6Directory structure
- Two directories are of importance
- cpu/
- platform/
- cpu/ contains code common to all platforms with
the same microcontroller - platform/ contains platform specific code
- Example platform/sky, platform/esb, and
cpu/msp430
7The native port
8The native port
- The simplest port can be used as a template
- ls platform/native
- Makefile.native
- clock.c
- contiki-conf.h
- contiki-main.c
- dev/
9The native port (contd)
- Makefile.native
- For integration into the Contiki build system,
must have the name Makefile.(platform name) - clock.c
- Architecture-specific clock code
- contiki-conf.h
- Configuration options
- contiki-main.c
- main() boot-up code and the main loop
- dev/
- Device drivers
10Other subdirectories used in platform/ subdirs
- apps/
- Platform-specific applications
- Example platform/sky/apps/burn-nodeid.c
- net/
- Platform-specific network code/drivers
- Example platform/esb/net/tr1001-rime.c
11The clock module
12The clock module
- The clock module is hardware-specific
- Generic header file in core/sys/clock.h
- clock.c can be either in platform/ or in cpu/
- Example platform/ for native, cpu/ for MSP430
ports - Three functions
- clock_init()
- clock_time()
- clock_delay()
13clock_init()
- Initializes the clock module
- Called by the boot-up code
- Configures hardware timers, interrupts
14clock_time()
- Should return an increasing tick counter
- The tick typically is increased in an interrupt
handler - Implemented in clock.c
- Interrupt handler must wake up CPU if there are
etimers pending - etimer_request_poll()
15Example cpu/msp430/clock.c
- static volatile clock_time_t count 0
- interrupt(TIMERA1_VECTOR) timera1 (void)
- if(TAIV 2)
- TACCR1 INTERVAL / Set next hw
interrupt / - count / Increase tick
counter / - / If there are pending etimers, poll etimer
process, - wake up CPU. /
- if(etimer_pending()
- (etimer_next_expiration_time() - count - 1)
gt - MAX_TICKS)
- etimer_request_poll()
- LPM4_EXIT
-
-
-
16clock_delay()
- Delay for a platform-specific amount of time
- This function is only used by device drivers and
other low-level code
17Example cpu/msp430/clock.c
- /
- Delay the CPU for a multiple
- of 2.83 us.
- /
- void clock_delay(unsigned int i)
- asm("add -1, r15")
- asm("jnz -2")
-
18Workplan
- Copy exiting clock.c (cpu/msp430/dev/clock.c)
- Modify
- Look at application notes for CPU to see how
timer interrupt works
19The future of the clock module
- Periodic ticking is inefficient
- The clock module might be replaced by the rtimer
module in the future - The rtimer code will have to be backed by code
similar to the current clock.c code
20contiki-conf.h
21contiki-conf.h
- Found in platform/(name of platform)
- Example platform/native/contiki-conf.h
- Contains platform-specific configuration options
- C compiler configuration
- C types
- uIP configuration
- Clock configuration clock_time_t,
CLOCK_CONF_SECOND - Sometimes used as a kitchen sink
- Workplan copy platform/native/contiki-conf.h
22Network device drivers
23Network device drivers
- Two operations
- Send out packet
- Receive packets
- Driver design
- Split code into three files
- Hardware-specific code
- Interface between uIP and hw specific code
- Interface between Rime and hw specific code
24Example core/dev/simple-cc2420.c
- / Initialize driver /
- void simple_cc2420_init(void)
- / Setup a function to be called when a packet
has arrived / - void simple_cc2420_set_receiver(void (
recv)(void)) - / Read arrived packet into a buffer /
- int simple_cc2420_read(u8_t buf, u8_t bufsize)
- / Send a packet from a buffer /
- int simple_cc2420_send(const u8_t data, u8_t
len)
25Example core/dev/simple-cc2420.c
- Hardware driver does not add any headers
- Only handles reception/sending of raw bytes
- Any 802.15.4 headers (optional) could be handled
by upper layer module - Add function for switching on CC2420 address
decoding
26Example core/dev/simple-cc2420-rime.c
- Uses the hardware-specific code in
simple-cc2420.c to send and receive packets - No hardware-specific code outside of lowest level
driver
27core/dev/simple-cc2420-rime.c
- static void receiver(void)
- u8_t len
- rimebuf_clear()
-
- len simple_cc2420_read(rimebuf_dataptr(),
- RIMEBUF_SIZE)
-
- if(len gt 0)
- rimebuf_set_datalen(len)
- rime_input()
-
-
- void simple_cc2420_rime_init(void)
- simple_cc2420_set_receiver(receiver)
-
- void rime_driver_send(void)
28The equivalent uIP driver
- static void receiver(void)
- u8_t len
-
- len simple_cc2420_read(uip_buf,
- UIP_BUFSIZE)
-
- if(len gt 0)
- uip_len len
- tcpip_input()
-
-
- void simple_cc2420_rime_init(void)
- simple_cc2420_set_receiver(receiver)
-
- int simple_cc2420_uip_send(void)
- simple_cc2420_send(uip_bufUIP_LLH_LEN,
- uip_len)
29Overall comments
- Keep things simple
- Keep low-level code in a seprate file
- As little low-level code as possible
- Create simple interfaces between the low-level
code and Rime/uIP driver - Workplan
- Copy existing driver (simple-cc2420, tr1001)
- Modify
30Sensors
31Sensor drivers in Contiki
- When a sensor changes an event is broadcast to
all processes - Button press, PIR movement detected,
- Generic code for sending events in
core/lib/sensors.c - Low-level code in separate file
32Example platform/sky/dev/button-sensor.c
- HWCONF_PIN(BUTTON, 2, 7) / Button is on
port 2, pin 7 / - HWCONF_IRQ(BUTTON, 2, 7) / Connect this
to an interrupt / - static void init(void)
- timer_set(debouncetimer, 0)
- BUTTON_IRQ_EDGE_SELECTD() / Trigger
interrupt on down flank / - BUTTON_SELECT() / Select this
pin / - BUTTON_MAKE_INPUT() / Make button
pin an input pin / -
- static int irq(void)
- if(BUTTON_CHECK_IRQ()) / Is this why
we got an interrupt? / - if(timer_expired(debouncetimer))
- timer_set(debouncetimer, CLOCK_SECOND /
4) - sensors_changed(button_sensor) / Send
event to all processes / - return 1
-
-
33In platform/sky/contiki-sky-main.c
- include "dev/button-sensor.h"
- SENSORS(button_sensor)
- / /
- int main(void)
- / /
- process_start(sensors_process, NULL)
- button_sensor.activate()
- / /
-
34Workplan
- Copy platform/sky/dev/button-dev.c
- Modify
35The future of the sensor API
- Works well for digital sensors
- Does not work that well for analog sensors
- May need to be updated in the future
36Integrating into the Contiki build system
37Platform-specific Makefile
- platform/name/Makefile.name
- Included by top-level Makefile.include
- Never invoked directly
- Not supposed to run make in platform directory
- Makefile specifies source files, directories,
- Usually includes CPU-specific Makefile
- cpu/name/Makefile.name
38Example platform/sky/Makefile.sky
-
- CONTIKI_TARGET_DIRS . dev apps net
-
- CONTIKI_TARGET_SOURCEFILES
-
- include (CONTIKI)/cpu/msp430/Makefile.msp430
-
39CPU-specific Makefile
- cpu/name/Makefile.name
- Definitions for CPU-specific source files
- Definitions for rules for C compiler
- CFLAGS, CC
- Definition of vpath
- Where (GNU) make looks for .c files
40Example cpu/x86/Makefile.x86
- CONTIKI_SOURCEFILES mtarch.c elfloader-stub.c
- Compiler definitions
- CC gcc
- LD gcc
- AS as
- OBJCOPY objcopy
- STRIP strip
- CFLAGSNO -I. -I(CONTIKI) -I(CONTIKI)/core \
- -I(CONTIKI_CPU) \
- -I(CONTIKI)/platform/(TARGET) \
- addprefix -I,(APPDIRS)
(APP_INCLUDES) \ - -DWITH_UIP -DWITH_ASCII \
- -Wall -g -I. -I/usr/local/include
- CFLAGS (CFLAGSNO) -O
- LDFLAGS -Wl,-Mapcontiki.map,-export-dynamic
-
41Integrating into build system
- Keep things simple
- Copy entire platform/native directory
- Modify
- Copy entire cpu/x86 directory
- Modify
42ELF loader
43ELF loader
- Only needs porting for new CPUs
- Designed for portability
- Ported to MSP430, AVR, x86, ARM7
44ELF loader architecture-specific interface
- / Allocate RAM for data and bss segments /
- void elfloader_arch_allocate_ram(int size)
- / Allocate ROM for text segment (code) /
- void elfloader_arch_allocate_rom(int size)
- / Relocate one relocation entry. /
- void elfloader_arch_relocate(int fd,
- unsigned int
sectionoffset, - char sectionaddr,
- struct elf32_rela
rela, - char addr)
- / Write code to previously allocated ROM /
- void elfloader_arch_write_rom(int fd,
- unsigned short
textoff, - unsigned int size,
- char mem)
45Workplan
- Copy core/loader/elfloader-stub.c
- Modify
- Look at core/loader/elfloader-msp430.c,
elfloader-avr.c, elfloader-x86.c - Need knowledge of the ELF format for the CPU
46The future of the ELF loader
- The current interface cannot nicely hold multiple
allocations - But Contiki itself supports it
- API change will be needed
- Current ELF loader does not properly process
relocation entries - New ELF loader code on the way
47Multi-threading library
48Multi-threading library
- Must be ported to new CPUs
- But not used very often
- Porting often not required
- Split into two parts (Contiki-style)
- mt.c
- mtarch.c
49mtarch API
- / Thread structure /
- struct mtarch_thread
- / Initialize the architecture-specific code /
- void mtarch_init(void)
- / Remove clean up /
- void mtarch_remove(void)
- / Start a thread (setup its stack) /
- void mtarch_start(struct mtarch_thread thread,
- void ( function)(void data),
- void data)
- / Switch to the specified thread /
- void mtarch_exec(struct mtarch_thread thread)
- / Yield the current thread /
- void mtarch_yield(void)
50Example cpu/msp430/mtarch.c
- void mtarch_start(struct mtarch_thread t,
- void (function)(void ), void
data) - t-gtsp t-gtstackMTARCH_STACKSIZE - 1
- t-gtsp (unsigned short)mt_exit
- --t-gtsp
- t-gtsp (unsigned short)function
- --t-gtsp
- / Space for registers. /
- t-gtsp - 11
-
- static struct mtarch_thread running
- void mtarch_exec(struct mtarch_thread t)
- running t
- sw()
- running NULL
-
51Example cpu/msp430/mtarch.c
- static void sw(void)
- sptmp running-gtsp
-
- __asm__("push r4") / Push all registers
on the current stack / - __asm__("push r5")
- __asm__("push r6")
- __asm__("push r7")
- __asm__("push r8")
- __asm__("push r9")
- __asm__("push r10")
- __asm__("push r11")
- __asm__("push r12")
- __asm__("push r13")
- __asm__("push r14")
- __asm__("push r15")
-
- __asm__("mov.w r1,0" "r" (running-gtsp))
/ Switch stack pointer to new stack / - __asm__("mov.w 0,r1" "m" (sptmp))
52Potential problems with mtarch.c
- C compiler specific
- Different compilers behave differently
- Different compiler versions behave differently
53Workplan
- Copy cpu/msp430/mtarch.c
- Modify
- Google and see how existing threading libraries
for your CPU push and pop the stack
54Conclusions
- Contiki designed to be portable
- No architecture-specific code out in Contiki base
- Two directories cpu/ and platform/
- To begin porting, copy modify the
platform/native code