STM32移植contiki进阶之一:从头开始,从main开始
本篇,我将从main函数开始,从头开始分析contiki,给你展示contiki的魅力
PS:在移植contiki之前,我已经实现了STM32的裸跑,所以很多关于硬件的程序已经实现,例如时钟、串口、SDRAM,nandflash等。关于串口打印的问题,我在另一篇文章(arm cortex M3 实现printf)中有详细的介绍。如果有问题,请咨询我(hurryliu28@gmail.com)
int main(void)
{
SystemInit ();/*时钟初始化,配置,与硬件相关,不做具体阐述*/
WDOG_MOD = WDOG_DISABLE;/*关看门狗*/
uart_gpio_init(); /*串口的GPIO初始化,我用的是UART1*/
uart_init(CONSOLE_PORT, 115200);/*串口初始化,和硬件相关,不做阐述*/
/*打印相关信息,打印CPU时钟,PCLK时钟等*/
printf("Init uart............\r\n");
printf("system tick clock : %d Hz\r\n",clock_get(CLOCK_SYSTICK) );
printf("system pclk clock : %d Hz\r\n",clock_get(CLOCK_PCLK) );
printf("system emc clock : %d Hz\r\n",clock_get(CLOCK_EMCCLK) );
clock_init(); /*系统时钟初始化,sys_tick,详情见1.1*/
process_init();*进程初始化,详情见1.2*/
autostart_start(autostart_processes);/*启动指针数组autostart_processes[]里的所有进程,详情见1.3*/
while (1)
{
do{
}while (process_run() > 0);
}
}
函数剖析:
系统先进行一系列初始化(串口、时钟、进程),接着启动系统进程etimer_process和指针数组autostart_processes[]里的所有进程,到这里就启动了所有的系统进程(当然,后续的操作还可能动态产生新进程)。接下来的工作,就是系统处理满足条件的进程及事件队列中所有事件。(满足什么条件,我也不知道,以后慢慢分析,呵呵)而处理事件过程中(典型情况是让某些进程继续执行)又可能产生新的事件,再处理事件,系统如此反复运行。
代码详解
1.1 clock_init系统嘀嗒初始化
该函数的原型如下
void clock_init()
{
SysTick_Config(clock_get(CLOCK_SYSTICK)/ CLOCK_SECOND);
}
#define CLOCK_SECOND CLOCK_CONF_SECOND
#define CLOCK_CONF_SECOND 100
作用是:clock_init用于配置系统产生嘀嗒的间隔,我的开发板系统时钟跑的是120MHz,即每隔120,000,000/100产生一次系统嘀嗒,一个系统嘀嗒是10ms,CLOCK_SECOND(这里定义为100)个时钟嘀嗒即为1S。
再向下分析,systick_config函数原型如下
static __INLINE uint32_t SysTick_Config(uint32_t ticks)
{
if (ticks > SysTick_LOAD_RELOAD_Msk) return (1); /*检查传入的值是否正确*/
SysTick->LOAD = (ticks & SysTick_LOAD_RELOAD_Msk) - 1; /*设置重载值*/
NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1); /*设置中断*/
SysTick->VAL = 0;
SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | /*打开systick,开始计数*/
SysTick_CTRL_TICKINT_Msk |
SysTick_CTRL_ENABLE_Msk;
return (0);
}
systick_config是系统嘀嗒的硬件实现。我们来看文档中关于systick的描述
上面说systick是提供给操作系统使用的10ms的间隔,就是我们所说的操作系统为每个进程分配的时间片。
1.2 process_init()进程初始化
void process_init(void)
{
lastevent = PROCESS_EVENT_MAX;/*初始化事件队列*/
nevents = fevent = 0;
process_current = process_list = NULL; /*初始化进程链表*/
}
1.3autostart_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);
}
}