打印

430也能玩嵌入式:Contiki内核在IAR+MSP430下移植(转发)

[复制链接]
5926|33
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
houjiakai|  楼主 | 2013-11-21 23:58 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
摘要:
本文详细记录了Contiki内核在IAR+MSP430下移植步骤,遇到的问题,分析解决,最后附上工程源码。

前言
分析了Contiki有一段时间了,但本人还没真正移植过。之前是我们项目组一哥们移植好了(IAR+ARM),我在调试Contiki文件系统Coffee遇到了难题,于是就想在MSP430平台上调试,理由是MSP430硬件比较简单。最近,CU网友kangerbiao45d已经把Contiki移到IAR+Telosb,给了我莫大鼓舞(感谢他)。我手头有MSP430-169LCD,于是下决心移植Contiki到IAR+MSP430-169LCD。终于跑通了,遂将过程详细记录,以供分享。

官方的Contiki源码是在Linux开发环境进行的,移植到IAR,首要解决的就是GCC与IAR之间的差异,包括:
    (1)GCC是用Makefile来管理工程编译,而IAR是IDE,通过工程文件目录来反映文件间的关系,所以必要时需要将路径加到preprocesses;
(2)嵌入式汇编,GCC内嵌汇编与IAR内嵌汇编格式差异甚大,需要全面修改Contiki出现内嵌汇编的地方;
(3)文件差异,Linux平台下的Contiki会调用Linux的头文件或者文件名不同(比如io.h与io430.h)。
再者需要解决版子间的差异,如果节点恰是Contiki支持的,那最好(比如Telosb),否则选择一个相近的节点进行修改,比如我的板子MSP430-169LCD,其MCU是MSP430F169,与Telosb的MSP430F1161属于同一序列。
一、下载源码及创建工程文件
1.1 下载源代码
Contiki最新版本是2.5,可以从SourceForge下载源码,猛击这里下载。
1.2 创建工程文件
移植的指导思想是先把内核跑起来,而后根据需求再把文件系统、动态加载、网络模块加上去。所以这里只需把Contiki内核相关的源文件加到工程目录,不过加多了也没关系,还有后续的调试嘛:-)取一个Contiki支持的节点来修改,这里选择Tosek(因其MCU是MSP430F1611),将platform/sky/下文件拷贝到新建文件夹platform/MSP430-169LCD。我的工程目录如下(期间删了若干文件):
图1 Contiki_msp430工程目录示意图
接下来,就一步步修改吧。值得一提的是,考虑到后续还要移植文件系统、动态加载、网络模块,本次遇到错误是尽可能的修改,实在不行,才从工程目录将该文件删除。所以,实际移植Contiki内核要比以下描述的要简单得多。


相关帖子

沙发
houjiakai|  楼主 | 2013-11-21 23:58 | 只看该作者
二、编译调试
2.1 找不到文件解决
工程make之后,有时会提示找不到源文件,例如:"Fatal Error[Pe1696]: cannot open source file "contiki-conf.h" ,错误提示如下:
图2 找不到源文件错误
解决方法:
(1) 检查工程目录是否包容该文件
在代码编辑区选中相应的源文件(如上例的"contiki-conf.h"),右击选择open "contiki-conf.h",打开该源文件,查看其文件属性,观其路径,再对应工程目录,确定该源文件已被包含进工程目录。

使用特权

评论回复
板凳
houjiakai|  楼主 | 2013-11-21 23:58 | 只看该作者
(2) 设置预处理路径
第一步设置后,并不能保证问题解决(事实上,不用第一步设置也可以),如果还提示找不到源文件错误,那就得把该源文件所在的目录加到预处理路径中,如下图所示:
图3 设置预处理路径

使用特权

评论回复
地板
houjiakai|  楼主 | 2013-11-21 23:59 | 只看该作者
2.2 将io.h替换成io430.h
不同的开发环境,将MSP430 io组织成不同文件,这点可以从rtimer-arch.c源代码得到佐证,如下:

  • #ifdef __GNUC__
  •   #include <io.h>
  •   #include <signal.h>
  • #endif
  • #ifdef __IAR_SYSTEMS_ICC__
  •   #include <msp430.h>
  • #endif


从编译错误提示信息可以直接定位到出错的地方,将io.h替换成io430.h。有些文件明显跟内核无关,也可以直接从工程文件删除。

使用特权

评论回复
5
houjiakai|  楼主 | 2013-11-21 23:59 | 只看该作者
2.3 ISR定义修改
Contiki默认开发环境是Linux,其中断服务处理程序定义格式与IAR不同,编译的时候报如下错误:
图4 ISR相关错误
这里只要略加修改即可,改成符合IAR的格式,以button-sensor.c为例,如下:

  • interrupt(PORT2_VECTOR)
  • irq_p2(void)
  • /***改成如下内容***/
  • #pragma vector= PORT2_VECTOR
  • __interrupt void irq_p2(void)



使用特权

评论回复
6
houjiakai|  楼主 | 2013-11-21 23:59 | 只看该作者
2.4 找不到库文件
Contiki用到了Linux下的库文件,先注释掉,编译单个文件,没问题最好(如cpu/msp430.c的sys/unistd.h),也就是说这个文件压根就没用到这个库文件。如果真用到了,再编译会引进新的错误,此时,果断将文件从工程目录移除(比如dlfcn.h、lib/malloc.h)。你可能会说,为何不将这些头文件从Linux找出来加到编译路径,我确实尝试了,发现可行性不高,因为库文件还调用其他库文件。不过后续移植可能得正视社个问题了。
注:LINUX下使用动态链接库,源程序需要包含dlfcn.h头文件,文件dlfcn.h定义了调用动态链接库的函数的原型。
2.5 嵌入式汇编修改
(1) __asm__未定义
GCC下关键字__asm__,等同于IAR的asm。不过,从文档《IAR C/C++ Compiler Reference Guide.pdf》来看,推荐使用关键字__asm(英文原文:the asm keyword is not available when the option --strict is used. The __asm keyword is always available)。在相应文件增加如下代码(比如msp430.c),即可解决:

  • #ifdef __IAR_SYSTEMS_ICC__
  •   #define __asm__ __asm
  • #endif


使用特权

评论回复
7
houjiakai|  楼主 | 2013-11-22 00:00 | 只看该作者
但__volatile__不是IAR的关键字,还是有问题,索性改成这样(没加volatile会不会有副作用?):

  • #ifdef __IAR_SYSTEMS_ICC__
  •   #define asmv(arg) __asm(arg)
  • #elif
  •   #define asmv(arg) __asm__ __volatile__(arg)
  • #endif


(2) expected a "(" 及 expected a ")"
尽管解决了__asm__未定义问题,但还是报错了expected a "(",原因是IAR内嵌汇编与GCC不同,解决方法就是改写这些GCC内嵌汇编以符合IAR。好在需要修改的地方不多,只有3处(在msp430.c文件),我仿照《IAR C/C++ Compiler Reference Guide for Texas Instruments' MSP430 Microcontroller Family.pdf》上面的例子修改,但不行,最后我用宏替代了,另一处我直接注释掉,后续发点时间把msp430内嵌汇编了解下。

使用特权

评论回复
8
houjiakai|  楼主 | 2013-11-22 00:00 | 只看该作者
修改的部分源码如下:

  • //filename:msp430.c
  • //asmv("mov r1, %0" : "=r" (stack_pointer)); //sbrk(int incr)函数
  • *stack_pointer = (unsigned short)__get_SP_register();
  • //asmv("mov r2, %0" : "=r" (sr)); //splhigh_(void)函数
  • //asmv("bic %0, r2" : : "i" (GIE));
  • asmv("EINT");
  • //asmv("bis %0, r2" : : "r" (sr)); //splx_(int sr)函数
  • asmv(" bis &sr,r2"); //改成这样不行!!!直接注释了


2.6 板子相关的未定义变量
编译会出现很多未定义错误,诸如ADC12MCTL_NO(sky-sensors.c,显然板子相关)、UCB0CTL1等(cpu/msp430/spix.c)、UCA0STAT等(cpu/msp430/dev/uart0x.c及uart1x.c),这里简单地把这些相关文件从工程目录移除。


使用特权

评论回复
9
houjiakai|  楼主 | 2013-11-22 00:01 | 只看该作者
三、链接调试
3.1 slip_arch_init和slip_arch_writeb重定义
链接提示slip_arch_init、slip_arch_writeb重定义,错误提示如下:
图5 slip_arch_init重定义错误提示
这点确实,slip_arch_init与slip_arch_writeb函数分别在slip_uart0.c和slip_uart1.c定义了,SLIP是指Serial Line Interface Protocol,即串行线路接口协议,是旧式的协议,这里只是简单地注释掉slip_uart1.c中的slip_arch_init定义(估计计这玩意也用不着)。
3.2 putchar重定义
与(1)类似,putchar函数分别在uart0-putchar.c和uart1-putchar.c定义,处理方法同上。

使用特权

评论回复
10
houjiakai|  楼主 | 2013-11-22 00:01 | 只看该作者
3.3 重复段Error[e24]
链接时提示如下错误:
图6 IAR Error[e24]示意图
造成这个问题的原因是有些文件包含了msp430.h,而有些文件包含了io430.h。以MSP430F1611为例,前者通过宏定位到msp430f1600.h,通过则是定位到iox16x.h,而这两个文件有很多重叠的地方(如本例的IE1)。cpu/msp430/rom.c包含了io430.h,flash.c包含了msp430.h,在这里,将flash.c包含的msp430.h改成io430.h。
同样的问题也发生在cpu/msp430/watchdog.c、core/dev/sht11.c、platform/MSP430-169LCD/dev/button-sensor.c(这个还得从包含的头文件追溯,在cpu/msp430/dev/hwconf.h文件)、cpu/msp430/leds-arch.c、cpu/msp430/clock.c、cpu/msp430/cc2420-arch-sfd.c等,可以通过Find in Files寻找msp430.h来替换。

使用特权

评论回复
11
houjiakai|  楼主 | 2013-11-22 00:01 | 只看该作者
3.4 外部符号未定义
(1) BV
在cpu/msp430/button.c提示外部符号BV未定义,通过Find in Files查找,可知该宏通常是定义在contiki-conf.h或者platform-conf.h文件,如下:
图7 BV宏定义位置
这里,模仿其他例程,在platform/MSP430-169LCD/contiki-conf.h文件加入如下代码:

  • #ifndef BV
  •   #define BV(x) (1<<(x))
  • #endif



使用特权

评论回复
12
houjiakai|  楼主 | 2013-11-22 00:02 | 只看该作者
(2)cc2420_sfd_counter、cc2420_sfd_start_time和cc2420_sfd_end_time
在cpu/msp430/cc2420-arch-sfd.c提示外部符号cc2420_sfd_counter.c、cc2420_sfd_start_time和cc2420_sfd_end_time未定义,该文件将这三个变量声明为外部变量,源码如下:

  • extern volatile uint8_t cc2420_sfd_counter;
  • extern volatile uint16_t cc2420_sfd_start_time;
  • extern volatile uint16_t cc2420_sfd_end_time;


事实上,这三个变量已经在contiki-2.5/core/dev/cc2420.c文件定义了, 而这个文件已经被我工程目录删除了,因为编译cc2420.c会引发一系列端口未定义(如TXEPT、UTXIFG0),而这些端口大概是跟cc2420芯片有关吧。这里,我们简单将cpu/msp430/目录下的cc2420*.c文件从工程移除。

使用特权

评论回复
13
houjiakai|  楼主 | 2013-11-22 00:03 | 只看该作者
(3) dint与eint
在cpu/msp430/clock.c提示外部符号dint和eint未定义,这是因为Linux开发环境用eint()和dint()分别开、关中断,但IAR则是使用__enable_interrupt()和__disable_interrupt()。可以直接替换eint()和dint(),这里采用更具移植性的方法,在platform/MSP430-169LCD/platform-conf.h加下如下代码:

  • #ifdef __IAR_SYSTEMS_ICC__
  •   #define dint() __disable_interrupt()
  •   #define eint() __enable_interrupt()
  • #endif


(4)autostart_processes未定义
在测试例子main文件提示外部符号autostart_processes未定义,原因是autostart_processes指针数组是由宏AUTOSTART_PROCESSES定义,而该宏又取决于条件编译,直接看源码吧(在core/sys/autostart.h):

使用特权

评论回复
14
houjiakai|  楼主 | 2013-11-22 00:03 | 只看该作者

  • #if AUTOSTART_ENABLE
  •   #define AUTOSTART_PROCESSES(...) \
  •   struct process * const autostart_processes[ = {__VA_ARGS__, NULL}
  • #else
  •   #define AUTOSTART_PROCESSES(...) \
  •   extern int _dummy
  • #endif


现在只需把AUTOSTART_ENABLE定义为1就可以了,在platform/MSP430-169LCD/contiki-conf.h文件添加如下语句:
  • #define AUTOSTART_ENABLE 1


使用特权

评论回复
15
houjiakai|  楼主 | 2013-11-22 00:03 | 只看该作者
四、其他地方
(1)loader-arch.h
cpu/msp430/loader-arch.c文件中的#include "loader/loader-arch.h"改成#include "loader/elfloader-arch.h"。(通过逻辑判断)
(2)FSSEL_SMCLK
contiki-2.5/cpu/msp430/rom.c文件中的FCTL2 = FWKEY | FSSEL_SMCLK | (FN2 | FN1)改成FCTL2 = FWKEY | FSSEL_2 | (FN2 | FN1)。即把FSSEL_SMCLK 改成FSSEL_2 ,这点从io430.h对应的MCU头文件(比如msp430ff161.h)可以看出。
(3) CH_CURS_UP未定义
透过错误提示信息,可以发现这些类似的错误都跟ctk有关(文件名前缀),在contiki-2.5/core/有个目录ctk,文件ctk.h有这么一行注释"This file is part of the Contiki desktop OS."。纵观ctk的源码可知是跟图形相关的东西,在这里,我们将这些文件从工程目录移除(在core/lib/及core/ctk目录)。后来,查阅资料证实,ctk是Contiki的TK图形库(c是Contiki的首字母,Tk is a graphics library that extends Tcl with graphical-interface facilities)。
(4) core/dev目录
这个目录改起来很简单,将cc2420相关的文件从工程目录移除,重新编译,会报io.h的错,改成io430.h即可(我觉得直接注释掉会更好)。

使用特权

评论回复
16
houjiakai|  楼主 | 2013-11-22 00:04 | 只看该作者
(5) core/loader目录
移除其他平台的文件(比如elfloader-avr.c、cle_avr.c),编译会提示找不到malloc.h、dlfcn.h,再移除报错的文件。再编译,会提示错误(文件cle.c)"expression must be a pointer to a complete object type" ,移除该文件(粗略看下,大概是跟编译器支持有关),再编译就没问题了:-)这对跑Contiki内核不会有影响的,因为仅仅跑内核是没有用到动态加载这个模块的。
(6)LOADER_ARCH_MAGIC和LOADER_ARCH_VERSION没定义
用Find in Files的目录查找,可知这两个变量在Contiki-2.5/platform/esb/loader/loader-arch.h和Contiki-2.5/platform/msb430/loader/loader-arch.h有定义。在这里,仿照定义这两个变量。创建文件platform/MSP430-169LCD/loader-arch.h文件,文件内容如下:

  • //this file added by jelline
  • #ifndef __LOADER_ARCH_H__
  • #define __LOADER_ARCH_H__
  • #define LOADER_ARCH_MAGIC 0x373a
  • #define LOADER_ARCH_VERSION 0x0001
  • #endif


使用特权

评论回复
17
houjiakai|  楼主 | 2013-11-22 00:04 | 只看该作者
(7) profile_timestamps和PROFILE_TIMESTAMP_PTR未定义

    这两个变量都在core/sys/profile-aggregates.c,其用途是"Compuation of aggregates for the Contiki profiling system"。但整个Contiki源码找不到有定义的,真无语了,直接从工程移除吧。

使用特权

评论回复
18
houjiakai|  楼主 | 2013-11-22 00:04 | 只看该作者
庆幸的是,Google搜索找到了profile.h(v 1.2 2007/11/17,而该工程的profile.h是v 1.3 2008/01/17)[1]文件含有这些变量定义,在profile.h增加如下内容:
  • /**************added by jelline**********************/
  • struct profile_timestamp
  • {
  •   const char *ptr;
  •   rtimer_clock_t time;
  • };
  • #ifdef PROFILE_CONF_LIST_LENGTH
  •   #define PROFILE_LIST_LENGTH PROFILE_CONF_LIST_LENGTH
  • #else
  •   #define PROFILE_LIST_LENGTH 128
  • #endif
  • extern struct profile_timestamp profile_timestamps[PROFILE_LIST_LENGTH;
  • extern unsigned int profile_timestamp_ptr;
  • extern rtimer_clock_t profile_timestamp_time;
  • #define PROFILE_TIMESTAMP_PTR (profile_timestamp_ptr / sizeof(struct profile_timestamp))



至此,编译链接成功,下载到板子上,看到灯闪烁:-)

使用特权

评论回复
19
dirtwillfly| | 2013-11-22 09:51 | 只看该作者
谢谢分享

使用特权

评论回复
20
iiccee521| | 2013-11-22 10:45 | 只看该作者
很好的帖子

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

191

主题

5976

帖子

5

粉丝