本文旨在剖析main函数,从更高层次理解Contiki系统。先是给出源码,接着总结功能,最后深入源码分析。

1. main函数源码

//filename:contiki-main.c
#include <stm32f10x.h>
#include <stm32f10x_dma.h>
#include <stdint.h>
#include <stdio.h>
#include <debug-uart.h>
#include <sys/process.h>
#include <sys/procinit.h>
#include <etimer.h>
#include <sys/autostart.h>
#include <clock.h>

int main()
{
  dbg_setup_uart(); //串口初始化,与硬件相关(注1)
  usart_puts("Initialising\n"); //向串口打印字符串"Initialising"

  clock_init();//时钟初始化,与硬件相关,见3.3

  process_init(); //进程初始化,详情见3.1
  process_start(&etimer_process, NULL); //启动etimer_process,详情见3.2
  autostart_start(autostart_processes); //启动指针数组autostart_processes[]里的所有进程,详情见3.2

  while (1)
  {
    /*执行完所有needspoll为1的进程及处理完所有队列,详情见3.2*/
    do
    {
    }
    while (process_run() > 0);
  }
  return 0;
}

注:串口初始化和时钟初始化与硬件相关(我用的MCU是STM32F103RBT6),不深入讨论,主要基于以下两个原因:其一,这部分对理解系统影响不大;其二,我对硬件不是很熟。

2. 程序解读

系统先进行一系列初始化(串口、时钟、进程),接着启动系统进程etimer_process和指针数组autostart_processes[]里的所有进程,到这里就启动了所有的系统进程(当然,后续的操作还可能动态产生新进程)。接下来的工作,就是系统反复处理所有needspoll标记为1的进程及事件队列中所有事件。而处理事件过程中(典型情况是让某些进程继续执行)又可能产生新的事件,再处理事件,系统如此反复运行。

3. 源码详解

3.1 进程初始化

/****进程初始化****/
void process_init(void)
{
  /*初始化事件队列*/
  lastevent = PROCESS_EVENT_MAX;
  nevents = fevent = 0;

  #if PROCESS_CONF_STATS
    process_maxevents = 0;
  #endif

  process_current = process_list = NULL; //初始化进程链表
}

3.2 注明

autostart_start函数用于启动autostart_processes指针数组里的进程,源代码如下:

//autostart_start(autostart_processes);
void autostart_start(struct process *const processes[])
{
  int i;

  for(i = 0; processes[i] != NULL; ++i)
  {
    process_start(processes[i], NULL);
    PRINTF("autostart_start: starting process '%s'\n", processes[i]->name);
  }
}

autostart_processes由宏AUTOSTART_PROCESSES定义,详情参见博文《实例hello_world剖析》第三部分。其源代码如下:

#define AUTOSTART_PROCESSES(...)                    \
struct process * const autostart_processes[] = {__VA_ARGS__, NULL}

3.3 时钟初始化

clock_init用于配置系统产生嘀嗒的间隔,即每隔72000000/CLOCK_SECOND产生一次系统嘀嗒(72000000是指1s可以产生最大的嘀嗒数),也就是说1秒钟可以产生CLOCK_SECOND次时钟中断。

void clock_init()
{
  SysTick_Config(72000000 / CLOCK_SECOND);
}

/*CLOCK_SECOND宏定义*/
#define CLOCK_CONF_SECOND 10

#ifdef CLOCK_CONF_SECOND
  #define CLOCK_SECOND CLOCK_CONF_SECOND
#else
  #define CLOCK_SECOND (clock_time_t)32
#endif

SysTick_Config函数展开如下,与硬件相关(我用的MCU是STM32F103RBT6):

/**
 * @brief Initialize and start the SysTick counter and its interrupt.
 *
 * @param ticks number of ticks between two interrupts
 * @return 1 = failed, 0 = successful
 *
 * Initialise the system tick timer and its interrupt and start the
 * system tick timer / counter in free running mode to generate
 * periodical interrupts.
 */
static __INLINE uint32_t SysTick_Config(uint32_t ticks)
{
  if (ticks > SysTick_LOAD_RELOAD_Msk) return (1);            /* Reload value impossible */

  SysTick->LOAD = (ticks & SysTick_LOAD_RELOAD_Msk) - 1;      /* set reload register */
  NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1); /* set Priority for Cortex-M0 System Interrupts */
  SysTick->VAL = 0;   /* Load the SysTick Counter Value */
  SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk |
                   SysTick_CTRL_TICKINT_Msk |
                   SysTick_CTRL_ENABLE_Msk;   /* Enable SysTick IRQ and SysTick Timer */
  return (0);   /* Function successful */
}
本文系Spark & Shine原创,转载需注明出处本文最近一次修改时间 2022-03-20 17:35

results matching ""

    No results matching ""