Contiki-NG在GD32F310的移植

Contiki-NG概述

Contiki-NG是物联网中资源受限设备的操作系统。 Contiki-NG包含符合 RFC 的低功耗 IPv6 通信堆栈,可实现 Internet 连接。
据官方描述,Contiki-NG代码占用量约为 100 kB,内存使用量可配置为低至 10 kB。个人认为这应该是系统基本无裁剪的情况下的资源占用。
Contiki-NG除了自带低功耗IPv6协议栈(6LoWPAN)之外,其本身也是一个优秀的事件驱动系统。对于事件驱动系统,除了Contiki-NG之外,笔者只接触过TI的Zigbee协议栈。Zigbee协议栈基于OSAL系统,整个系统分为很多层次(应用层、应用支持子层、网络层、MAC层、物理层等),每个层次分别轮询各个层次的事件,底层的事件比上层的优先级高,当有事件到来时,则触发事件处理函数的运行。这样的处理机制是不是很像平时单片机裸机情况下跑的轮询程序?在while(1)循环中判断某个事件标志位是否置1,置1则运行相对应的事件处理。
Contiki-NG也是同样的事件驱动机制,但它将事件驱动机制抽象成了线程处理模型,这也是笔者对此感兴趣的一个比较大的原因。具体是什么意思呢?我们来看一段Contiki-NG的例程,如下:

PROCESS(hello_world_process, "Hello world process");
AUTOSTART_PROCESSES(&hello_world_process);
/*---------------------------------------------------------------------------*/
PROCESS_THREAD(hello_world_process, ev, data)
{
  static struct etimer timer;

  PROCESS_BEGIN();

  /* Setup a periodic timer that expires after 10 seconds. */
  etimer_set(&timer, CLOCK_SECOND * 100);

  while(1) {
    printf("Hello, world\n");

    /* Wait for the periodic timer to expire and then restart the timer. */
    PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&timer));
    etimer_reset(&timer);
  }

  PROCESS_END();
}

看了以上代码,如果你不了解Contiki-NG,是否会觉得这是一个实时系统?笔者稍微解释一下这段代码的意思:

  1. PROCESS和AUTOSTART_PROCESSES这两个宏定义了一个helloworld任务;
  2. PROCESS_THREAD宏函数的执行内容即是任务的执行内容;
  3. 在Contiki-NG中,每个PROCESS的开始都需要有PROCESS_BEGIN,结束位置要有对应的PROCESS_END,并且Contiki-NG是不可抢占的系统,所以每个PROCESS在执行事件处理后必须主动交出CPU的使用权,也就是代码中PROCESS_WAIT_EVENT_UNTIL的作用。

事实上,Contiki-NG在初始化完毕之后,就进入主循环while(1)中,在循环中不断地检测是否有事件发生,并把事件分发到具体的PROCESS,假设有事件触发了上面的hello_world_process会怎样呢?CPU就会开始运行hello_world_process中的while(1),那问题来了,CPU如何退出hello_world_process的执行,然后把使用权交给事件调度器呢?下一次又有事件发送给hello_world_process时,hello_world_process又是怎么实现继续之前的执行呢(而不是重新开始执行)?
答案就在PROCESS_BEGIN、PROCESS_END、PROCESS_WAIT_EVENT_UNTIL这些宏的实现里面,本篇就不对这些原理进行叙述。

Contiki-NG移植

移植说明

本文的Contiki-NG移植是在https://github.com/contiki-ng/contiki-ng.git 下载的源码中添加GD32F310平台。一个系统的适配不是一蹴而就的,需要对gpio、usart、timer、watchdog等等一一进行适配,甚至后期可能还需要做一些代码的优化。本文在发布的时候呢,只适配了跑“Helloworld”例程所需的基本组件和驱动,另外,GD32F310本身只有8k的ram,没有集成RF,因此暂时将系统的射频和网络协议栈部分裁剪掉。
Contiki-NG工程默认是用Makefile管理工程的,初期为了避免Makefile引入的其他问题,先在Keil中移植GD32F310平台。

移植关键步骤

建立Keil工程

建立工程文件夹,将对应的C文件分类存放,笔者建立的目录如下:

  • app:存放应用逻辑程序
  • cmsis:存放arm内核提供给芯片厂商的接口文件及具体实现
  • cpu:Contiki-NG存放芯片相关源码的目录
  • os:Contiki-NG存放系统源码的目录
  • platform:Contiki-NG存放平台相关源码的目录
  • stdlib:GD32F310的标准库
  • output:编译输出文件目录

前期的目的是为了跑通整个系统,一些不必要的驱动可以先不需要加入工程,甚至可以注释掉一些外设的运行,比如看门狗、按键等。不必要的驱动代表去掉也不会影响系统功能性运行。怎么确定是不必要的驱动呢?这可以从系统认知、官网的文档说明、Makefile等去确定。

适配基础组件

在Contiki-NG中,PROCESS的轮询调度器在主循环中运行,不需要定时器的参与。但是很多PROCESS都会用到一个event timer,也就是etimer。一般情况下,一个PROCESS不是在等待事件到来,就是在执行事件。没有事件,就不会有PROCESS的运行。如果PROCESS在没有事件的情况下也需要周期性地执行,该如何做呢?我们可以定义一个etimer,etimer可以通过我们设置的参数定时发出事件,达到定时触发PROCESS运行的效果。
因此,我们首先适配etimer,etimer的底层实现是一个定时器,并且还有很多其他的timer实现与etimer是同一个底层实现。根据其他平台的适配情况,我们选择所以systick作为etimer的底层实现。相关代码如下:

void
SysTick_Handler(void)
{
  count++;
  if(etimer_pending()) {
    etimer_request_poll();
  }

  if(--second_countdown == 0) {
    current_seconds++;
    second_countdown = CLOCK_SECOND;
  }

}

void
clock_init(void)
{
    /* setup systick timer for 1000Hz interrupts */
    if(SysTick_Config(SystemCoreClock / 1000U)) {
        /* capture error */
        while(1) {
        }
    }
    /* configure the systick handler priority */
    NVIC_SetPriority(SysTick_IRQn, 0x00U);
}

无论哪个程序,log的输出对于调试都是很有帮助的。因此,我们第二个适配的组件就是log输出。相关代码如下:

int
dbg_putchar(int c)
{
#if DBG_CONF_SLIP_MUX
  static char debug_frame = 0;

  if(!debug_frame) {
    write_byte(SLIP_END);
    write_byte('\r');
    debug_frame = 1;
  }
#endif

  write_byte(c);

  if(c == '\n') {
#if DBG_CONF_SLIP_MUX
    write_byte(SLIP_END);
    debug_frame = 0;
#endif
    flush();
  }
  return c;
}
/*---------------------------------------------------------------------------*/
unsigned int
dbg_send_bytes(const unsigned char *s, unsigned int len)
{
  unsigned int i = 0;

  while(s && *s != 0) {
    if(i >= len) {
      break;
    }
    putchar(*s++);
    i++;
  }
  return i;
}

在串口的适配上,其实有个坑花了较多时间。在Contiki-NG的原本的printf实现上,是直接在源文件中定义了一个printf的具体实现来实现重定向,笔者发现这种方法在Keil中无法实现,Keil会使用C库中的printf实现,并移除重定向的printf实现。(而在gcc平台,是可以直接重定向printf的。)Keil重定向printf有几种实现方式,因此最后直接使用了GD32F310 Demo中的重定向实现。

提供栈底和栈顶地址

Contiki-NG在初始化会有检测栈的操作(目前没了解这一步去掉是否有影响),因此,需要提供栈地址变量_stack和_stack_origin。
在Keil中,提供栈地址变量的方法,笔者认为有2种:

  1. 在启动文件中分配栈空间的时候加标号,并导出符号;
  2. 在分散加载文件中将栈的运行地址单独放置,这样Keil就可以导出相应的$$符号变量来代表栈起始和结束位置。

笔者使用第一种方法,相关代码如下:

Stack_Size      EQU     0x00000400
                AREA    STACK, NOINIT, READWRITE, ALIGN=3
_stack
Stack_Mem       SPACE   Stack_Size
__initial_sp
_stack_origin

				EXPORT  _stack
				EXPORT  _stack_origin

通过编译生成的map文件可查到以下信息:

    _stack                                   0x20000960   Data           0  startup_gd32f3x0.o(STACK)
    __initial_sp                             0x20000d60   Data           0  startup_gd32f3x0.o(STACK)
    _stack_origin                            0x20000d60   Data           0  startup_gd32f3x0.o(STACK)

_stack和_stack_origin的地址都是在0x20000000(RAM空间地址),且差值刚好是0x400,因此应该是获取到了正确的地址(有兴趣还可以通过读取内存来确认)。

其它

由于没用到网络协议栈,因此需添加部分宏定义取消协议栈的运行,如下:

ROUTING_CONF_NULLROUTING=1, NETSTACK_CONF_WITH_NULLNET=1, MAC_CONF_WITH_NULLMAC=1

Contiki-NG运行效果

为了验证系统是否已经运行,笔者选择Helloworld例程进行验证,效果如下:
在这里插入图片描述

最后,我们再来看下系统的内存和flash占用情况,如下:

==============================================================================

    Total RO  Size (Code + RO Data)                 9236 (   9.02kB)
    Total RW  Size (RW Data + ZI Data)              3424 (   3.34kB)
    Total ROM Size (Code + RO Data + RW Data)       9388 (   9.17kB)

==============================================================================

对本项目有兴趣的伙伴可以通过百度网盘下载相关源码:
链接:https://pan.baidu.com/s/1-e85NmI56b8Ama7a3IX6XA?pwd=1234
提取码:1234

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: Contiki-NG是一种非常流行的开源操作系统,用于物联网和嵌入式系统。为了帮助用户更好地了解和使用Contiki-NG,一本名为“实用Contiki-NG”的PDF文件已经发布,其中包括有关Contiki-NG的基本知识、配置、网络、协议和编程的信息。 该PDF文件的作者是Oliver Hahm,他是Contiki-NG团队的核心成员之一。该文件非常适合那些希望学习Contiki-NG的人,尤其是那些希望了解Contiki-NG的入门知识,并希望掌握基本的Contiki-NG编程技巧的人。 通过这本实用的Contiki-NG PDF文件,用户可以了解Contiki-NG的基本架构和应用场景,了解Contiki-NG的基本组件和网络协议,掌握Contiki-NG的编程技巧和实践。除此之外,该文件还介绍了Contiki-NG的编译和调试方法,以及与Contiki-NG相关的硬件和软件环境。 最后,实用的Contiki-NG PDF文件为用户提供了大量的资源和链接,以便于用户深入了解Contiki-NG和相关技术。总之,该文件是学习和掌握Contiki-NG的绝佳资源,是物联网和嵌入式系统开发者的必备指南。 ### 回答2: Practical Contiki-NG PDF是一本Contiki-NG操作系统的实用指南。Contiki-NG是一个轻量级操作系统,特别适合物联网设备,具有低功耗、低资源消耗等优势。Practical Contiki-NG PDF为读者提供了深入了解Contiki-NG操作系统的机会。 本书以实用性为核心,全书共分为11章,涵盖了Contiki-NG操作系统的各个方面,包括了操作系统内核的特性、网络协议、网络堆栈、设备驱动、测试工具和调试等内容。读者可以通过本书学习到Contiki-NG操作系统的架构和开发工具。 本书由作者Simon Duquennoy撰写,他在物联网领域有多年经验,曾领导Contiki-NG团队开发了很多以Contiki-NG操作系统为基础的物联网项目。因此,本书具有很高的权威性,是学习Contiki-NG操作系统的很好的入门资料。 总的来说,Practical Contiki-NG PDF对于想要深入了解Contiki-NG操作系统的读者来说,是一本不可错过的实用指南。在阅读完本书后,读者将掌握Contiki-NG操作系统的核心特性及其应用,能够快速开发出高质量的物联网设备。 ### 回答3: Contiki-NG是一款开源的操作系统,专门用于物联网设备。Practical Contiki-NG是一本提供基本指南和示例的书籍,它涵盖了Contiki-NG操作系统的各个方面,包括网络协议,传感器节点,安全性等等。此书提供Contiki-NG开发的基础知识,适合物联网开发者和研究人员,而这类开发者和研究人员往往需要访问传感器、控制执行器或实现物联网设备之间的通信。 这本书主要包括四个方面的内容:介绍Contiki-NG的基础知识,Contiki-NG的网络协议栈,Contiki-NG的应用程序和Contiki-NG的安全性。书籍通过一个基于Contiki-NG的传感器网络示例,以及其他示例来展示学习Contiki-NG的方法。此外,书籍中还提供了一些编程代码用于实践。 总体而言,Practical Contiki-NG是一本非常有用的指南,其详尽的篇幅和直接的语言使得所有物联网开发人员无论是初学者还是专家都能理解。此书为物联网领域的研究人员和开发者提供许多有用的资源,以帮助他们实现更好的应用程序。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大目熊

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值