1 / 54

Porting Contiki Crash Course

Kista, Sweden 26-27 March 2007 Porting Contiki Crash Course Porting 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

niveditha
Download Presentation

Porting Contiki Crash Course

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Kista, Sweden 26-27 March 2007 Porting ContikiCrash Course

  2. Porting 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

  3. This 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

  4. Overview • Directory structure • The native port • The clock module • contiki-conf.h • Network drivers • Sensors • Integrating into the Contiki build system • ELF loader • Multi-threading

  5. Directory structure

  6. Directory 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

  7. The native port

  8. The 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/

  9. The 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

  10. Other 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

  11. The clock module

  12. The 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()

  13. clock_init() • Initializes the clock module • Called by the boot-up code • Configures hardware timers, interrupts

  14. clock_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()

  15. Example: 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) > MAX_TICKS) { etimer_request_poll(); LPM4_EXIT; } } } clock_time_t clock_time(void) { return count; /* Return tick count */ }

  16. clock_delay() • Delay for a platform-specific amount of time • This function is only used by device drivers and other low-level code

  17. Example: 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"); }

  18. Workplan • Copy exiting clock.c (cpu/msp430/dev/clock.c) • Modify • Look at application notes for CPU to see how timer interrupt works

  19. The 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

  20. contiki-conf.h

  21. contiki-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

  22. Network device drivers

  23. Network 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

  24. Example: 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);

  25. Example: 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

  26. Example: 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

  27. core/dev/simple-cc2420-rime.c static void receiver(void) { u8_t len; rimebuf_clear(); len = simple_cc2420_read(rimebuf_dataptr(), RIMEBUF_SIZE); if(len > 0) { rimebuf_set_datalen(len); rime_input(); } } void simple_cc2420_rime_init(void) { simple_cc2420_set_receiver(receiver); } void rime_driver_send(void) { simple_cc2420_send(rimebuf_hdrptr(), rimebuf_totlen()); }

  28. The equivalent uIP driver static void receiver(void) { u8_t len; len = simple_cc2420_read(uip_buf, UIP_BUFSIZE); if(len > 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_buf[UIP_LLH_LEN], uip_len); }

  29. Overall 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

  30. Sensors

  31. Sensor 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

  32. Example: 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; } } return 0; } /* … more stuff here … */ SENSORS_SENSOR(button_sensor, BUTTON_SENSOR, init, irq, activate, deactivate, active, value, configure, status);

  33. In 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(); /* … */ }

  34. Workplan • Copy platform/sky/dev/button-dev.c • Modify

  35. The 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

  36. Integrating into the Contiki build system

  37. Platform-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

  38. Example: platform/sky/Makefile.sky # … CONTIKI_TARGET_DIRS = . dev apps net # … CONTIKI_TARGET_SOURCEFILES += # … include $(CONTIKI)/cpu/msp430/Makefile.msp430 # …

  39. CPU-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

  40. Example: 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,-Map=contiki.map,-export-dynamic # …

  41. Integrating into build system • Keep things simple • Copy entire platform/native directory • Modify • Copy entire cpu/x86 directory • Modify

  42. ELF loader

  43. ELF loader • Only needs porting for new CPUs • Designed for portability • Ported to MSP430, AVR, x86, ARM7

  44. ELF 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);

  45. Workplan • 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

  46. The 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

  47. Multi-threading library

  48. Multi-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

  49. mtarch 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); /* Stop preemption */ void mtarch_pstop(void); /* Start preemption */ void mtarch_pstart(void);

  50. Example: cpu/msp430/mtarch.c void mtarch_start(struct mtarch_thread *t, void (*function)(void *), void *data) { t->sp = &t->stack[MTARCH_STACKSIZE - 1]; *t->sp = (unsigned short)mt_exit; --t->sp; *t->sp = (unsigned short)function; --t->sp; /* Space for registers. */ t->sp -= 11; } static struct mtarch_thread *running; void mtarch_exec(struct mtarch_thread *t) { running = t; sw(); running = NULL; } void mtarch_yield(void) { sw(); }

More Related