contiki学习笔记 clock部分

1.前言
    contiki是一款小型开源,易于移植的多任务操作系统,专门为无线传感网设计,适合内存受限制的网络系统。国内的研究和应用还处于初级阶段,甚至还不知道这个contiki如何发音,也没有那么响亮的中文名称。如果还没有中文名称的话,就干脆叫它“康提基”(来自wifi百科)。
    本文先详细描述clock部分,clock部分是contiki运行的基础,和任务调度、网络协议都有关系。从clock部分的分析也可获得移植contiki的一般方法。
    平台说明
    硬件平台:CC2530    
    软件平台:IAR EW8051/Instant Contiki 2.7

2.相关文件
    contiki的组织结构较为清晰,但是由于开发者众多便出现了若干矛盾的地方,最严重的便是同名文件较多,同名文件多出现于contiki/cpu/中的某个CPU文件夹和contiki/platform/某个平台文件夹
    2.1 clock.h
    clock.h位于contiki/core/sys。该文件为内核文件,定义了clock模块实现的接口和必要条件,最好保持不变。
    2.2 clcok.c文件
    有clock.h必有clock.c,该文件可以位于contiki/cpu/cc253x,也可以位于contiki/platform/cc2530dk
    2.3 contiki-conf.h
    该文件中有非常多的定义,其中和clock模块有关的定义有两个
    /* Time type. */
    typedef unsigned short clock_time_t;

    /* Defines tick counts for a second. */
    #define CLOCK_CONF_SECOND 128
     clock_time_t被定义为无符号16位整数,在IAR平台int和short同为16位长度。CLOCK_CONF_SECOND为clock经历一秒的嘀嗒总数。选择128是因为clcok模块的参考时钟源为32768Hz。

3.clock模块的实现
    clock模块实现需要4个步骤。初始化函数clock_init(),获得时钟时间clock_time(),更新时钟中断函数,简单的软件延时函数clock_delay()。
    3.1 clock_init()函数
    在CC2530平台上,zigbee和contiki不约而同的选择睡眠定时器,睡眠定时器由一个计数寄存器和一个捕获寄存器组成,计数寄存器和捕获寄存器均由三个8位寄存器组成。在clcok_init()函数中初始化了CC2530的时钟,该部分对系统运行和rtimer模块都非常重要。
    具体代码如下
void
clock_init(void)
{
  /* Make sure we know where we stand */
  CLKCONCMD = CLKCONCMD_OSC32K | CLKCONCMD_OSC;

  /* Stay with 32 KHz RC OSC, Chance System Clock to 32 MHz */
  CLKCONCMD &= ~CLKCONCMD_OSC;
  while(CLKCONSTA & CLKCONCMD_OSC);

  /* Tickspeed 500 kHz for timers[1-4] */
  CLKCONCMD |= CLKCONCMD_TICKSPD2 | CLKCONCMD_TICKSPD1;
  while(CLKCONSTA != CLKCONCMD);

  /*Initialize tick value*/
  timer_value = ST0;
  timer_value += ((unsigned long int) ST1) << 8;
  timer_value += ((unsigned long int) ST2) << 16;
  timer_value += TICK_VAL;
  ST2 = (unsigned char) (timer_value >> 16);
  ST1 = (unsigned char) (timer_value >> 8);
  ST0 = (unsigned char) timer_value;
  
  STIE = 1;		/* IEN0.STIE interrupt enable */
}
    几点说明
    【1】32K时钟源选择片内RC。
    【2】系统时钟源选择片外OSC,32MHz
    【3】定时器时钟选择500K,和之后的rtimer有关
    【4】系统运行时钟选择32M。
    【5】休眠定时器的累加值为256。和时钟源23768有关。
    【6】使能休眠定时器中断,勿忘其他函数中应启动全局中断。
   
contiki学习笔记 clock部分_第1张图片

    3.2 clock_timer()函数
    返回一个counter即可。该counter应在睡眠定时器中不断增加。
CCIF clock_time_t
clock_time(void)
{
  return count;
}

    3.3睡眠定时器中断
    睡眠定时器中断主要做三件事情
    【1】更新睡眠定时器捕获寄存器
    【2】更新etimer模块(以后会详细分析etimer和rtimer)
    【3】若经历一个整数秒,增累加second
    【4】最后清除中断标志位。
  #pragma vector=ST_VECTOR
  __near_func __interrupt void clock_isr(void)
{
  DISABLE_INTERRUPTS();
  ENERGEST_ON(ENERGEST_TYPE_IRQ);

  timer_value = ST0;
  timer_value += ((unsigned long int) ST1) << 8;
  timer_value += ((unsigned long int) ST2) << 16;
  timer_value += TICK_VAL;
  ST2 = (unsigned char) (timer_value >> 16);
  ST1 = (unsigned char) (timer_value >> 8);
  ST0 = (unsigned char) timer_value;
  
  ++count;
  
  if(count % CLOCK_CONF_SECOND == 0) {
    ++seconds;
  }
  
  if(etimer_pending()
      && (etimer_next_expiration_time() - count - 1) > MAX_TICKS) {
    etimer_request_poll();
  }
  
  STIF = 0; /* IRCON.STIF */
  ENERGEST_OFF(ENERGEST_TYPE_IRQ);
  ENABLE_INTERRUPTS();
}

    3.4 辅助部分clock_delay()和clock_seconds()
    请看代码:
CCIF unsigned long
clock_seconds(void)
{
  return seconds;
}
void
clock_delay(unsigned int len)
{
  unsigned int i;
  for(i = 0; i< len; i++) {
    ASM(nop);
  }
}


4.范例

    【范例1】
    使用clock_delay和clock_time函数。先记录下当前timer时间,假设为t1,调用clock_delay函数延时一定的时间,clock_delay本质为软件延时函数,clock_delay运行完之后再次记录timer时间,假设为t2。t2和t1之间的差值便可获得clock_time运行的大致时间(可精确到ms)。
    【实验代码】
PROCESS_THREAD(clock_test_process, ev, data)
{

  PROCESS_BEGIN();

  printf("Clock delay test, (10,000 x i) cycles:\n");
  i = 1;
  while(i < 6) {
    start_count = clock_time();                   // 记录开始timer
    clock_delay(10000 * i);                       // 软件延时
    end_count = clock_time();                     // 记录结束timer
    diff = end_count - start_count;               // 计算差值,单位为tick
    printf("Delayed %u \n%u ticks =~ %u ms\n", 10000 * i, diff, diff * 8);
    i++;
  }

  printf("Done!\n");

  PROCESS_END();
}
    【实验结果】
contiki学习笔记 clock部分_第2张图片
    【结果分析】
    clock_delay(10000)的时间约为8ms。由于clock的时钟源为片内RC晶振,频率为32768Hz。clock一秒钟嘀嗒的最大值为128,那么每嘀嗒一次的时间约为8ms。通过这个8ms的关系便可把嘀嗒差值换算为具体时间。从这个实验虽然简单但是非常重要。

    【范例2】
    使用etimer模块间隔5s读取系统运行时间分析间隔是否为5S。这里已经假定etimer模块调试成功了仅验证clock_second。
    【实验代码】
PROCESS_THREAD(clock_test_process, ev, data)
{

  PROCESS_BEGIN();

  printf("Clock Seconds Test (5s):\n");             // 间隔为5S
  i = 0;
  while(i < 10) {
    etimer_set(&et, 5 * CLOCK_SECOND);              // etimer溢出时间为5s
    PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&et));  // 等待定时器溢出
                    
    sec = clock_seconds();                          // 系统运行时间 单位s
    printf("%lu Seconds\n", sec);                   // 打印

    i++;
  }

  printf("Done!\n");

  PROCESS_END();
}
【实验结果】
contiki学习笔记 clock部分_第3张图片
    【结果分析】
    从运行的可过看,每次打印的时间间隔的确为5S。

5.总结
    由于contiki是一款开源的操作系统,许多工程师或者科研工作者都可以提交代码,扩充contiki支持的CPU和Platform。正由于这样不严密的合作关系,使得我个人初次阅读contiki的代码总觉得非常的混乱,乱到几乎没有头绪,遥想中国第一批linux开发者也遇到这样头疼的问题。软件环境和开发环境是一个,还遇到硬件平台的困难。国内和欧美的环境毕竟有所差异,欧美开发者熟悉的CPU国人并不了解。在无线传感网领域还没有出现一款像S3C2440一样遍地开花的芯片,如果已经有的话那就算CC2530了
    从嵌入式的发展来看,国人从事的嵌入式行业从没有操作系统到接受uCOS,FreeRTOS甚至Linux,期间有一个漫长的过程,在这个过程中同仁逐渐熟悉的任务调度,信号量和消息邮箱等概念。无线传感网络也会有一个从陌生到熟悉的过程,其中诸多的概念会让人沮丧甚至崩溃。

你可能感兴趣的:(学习笔记,contiki,Clock)