首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 移动开发 > 移动开发 >

STM32移栽contiki进阶之二:再叙systick

2013-10-08 
STM32移植contiki进阶之二:再叙systick在前一篇中,我们提到了contiki需要一个系统嘀嗒,称之为systick,在本

STM32移植contiki进阶之二:再叙systick

在前一篇中,我们提到了contiki需要一个系统嘀嗒,称之为systick,在本篇中,我会结合我的程序,详细的叙述systick。

 

一、systick初始化

我们在main函数中,有这样一句clock_init();这是对系统时钟的初始化

void clock_init()
{
  SysTick_Config(clock_get(CLOCK_SYSTICK)/ CLOCK_SECOND);
}

#define CLOCK_SECOND CLOCK_CONF_SECOND

#define CLOCK_CONF_SECOND 100

 

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_CTRL_TICKINT_Msk   |
                   SysTick_CTRL_ENABLE_Msk;                   

  return (0);                                                

}

这里涉及到几个寄存器的控制:STM32移栽contiki进阶之二:再叙systick

 

SysTick->LOAD 对应硬件寄存器STRELOAD,设置寄存器的重载值。一旦寄存器递减至零,就会从这个寄存器中取出重载值,然后实现下一个systick

SysTick->VAL对应硬件寄存器STCURR,这里当前的值设置为0

SysTick->CTRL对应硬件寄存器STCTRL,这里我们将其设置为7,即:将系统节拍时钟源选择为CPU时钟,系统节拍中断使能,系统节拍计数器使能。

关于重载值的问题,LPC1788官方的文档上面也有详细的阐述:

       下列示例说明如何根据不同的系统配置选择系统节拍定时器的值。 在所有示例中,都使用10毫秒的中断间隔进行计算,就像系统节拍定时器的设计用法一样。
示例1)
        该示例适用于使用100MHz的CPU时钟(CCLK)运行的系统节拍定时器。
STCTRL=7。当STCTRL为7时会使能定时器及其中断,并选择CCLK作为时钟源。 RELOAD = (cclk / 100) - 1 = 1,000,000 - 1 = 999,999 = 0xF423F
在该例中,不存在舍入误差,所以结果与CCLK一样精确。

      同样的,我的CPU时钟频率是120MHz,将此作为systick时钟源,那么

RELOAD=(120,000,000/100) - 1 = 0x124F7F,且不存在误差。

 二、systick中断

当systick到来的时候,也就是current value值减为零后,系统会发出一个中断,这个中断就是systick的中断,我们要想通过systick驱动etimer,必须在systick的中断中实现。

下面是systick中断的实现

void SysTick_Handler(void)
{
 SCB->ICSR = SCB_ICSR_PENDSTCLR;   /*!< Clear pending SysTick bit */
  TickCounter++;   

 if (etimer_pending() && etimer_next_expiration_time() <= TickCounter) //timerlist不为空且还没有etimer到期,则执行etimer_request_poll
 {
  etimer_request_poll(); //让etimer_process更快地再次获得执行。
 }

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

在程序中,我们看到有一个Tick_Counter的变量自加,这个counter就是systick了。

contiki维护着几个counter,一个是Tick_Counter,这个是系统嘀嗒,描述的是系统在一段时间内跑了多少个嘀嗒;一个是current_seconds,这个是系统跑了多少秒。我们知道,一个systick是10ms,那么一个surrent_seconds就是100个系统嘀嗒,这个数字100,正好是我们之前定义的CLOCK_CONF_SECOND 。了解到这一点,我们就明白这段程序后面,second_countdown的作用了。即:先将current_countdown赋值100,每次系统嘀嗒到来的时候,将其值减一,如果减到零了,说明1秒时间到了,那么当前的current_seconds要加一,然后将current_countdown赋值100,重新开始计数。

三、用系统嘀嗒做延迟检测

我们在主函数外,加入一段延迟的代码,用做延时的测试

void clock_delay(unsigned int len)
{
  unsigned int i;
  for(i = 0; i< len; i++)
 {
    ;
  }
}

然后参考前面的contiki的编程模型,写一个延时的进程

PROCESS(hello_world_process, "Hello world");
PROCESS(led_on_process, "led on");
AUTOSTART_PROCESSES(&hello_world_process,NULL); 

PROCESS_THREAD(hello_world_process, ev, data)
{
 static unsigned short start_time; 
 static unsigned short end_time;
 static unsigned short diff_time;  
 static unsigned int i ;
 
 PROCESS_BEGIN();
 printf("Clock delay test, (1,200,000 x 20) cycles:\r\n");
 i = 1;
 while(i <= 20) { 
    start_time = clock_time();                   // 记录开始timer 
    clock_delay(1200000 * i);                       // 软件延时 
    end_time = clock_time();                     // 记录结束timer 
    diff_time = end_time - start_time;               // 计算差值,单位为tick 
    printf("Delayed %u  CPU tick; %u system ticks =~ %u ms\r\n", 1200000 * i, diff_time, diff_time * 10); 
    i++; 
  } 
 PROCESS_END();
}

测试的结果如下

STM32移栽contiki进阶之二:再叙systick

测试是符合要求的。说明我们的systick已经OK了,进程也没有问题。

        细心的你可能会发现:如果系统时钟设置为120MHz,那么我延时1200000次,1200000 / 120M = 10ms,那应该正好是1个systick才对,怎么会是4个systick呢?

问这个问题人都是很仔细的人,说明真正用心去思欧考了。这里我详细说明一下:

        操作系统中,有机器周期,时钟周期和指令周期这一说法,一般的,1个指令周期=4个时钟周期=4个机器周期。在本例中,我们延时的时候,用的指令是“;”,其实不管用什么,都指的是指令周期,而机器在响应systick的时候,寄存器的值减一,却是时钟周期。

也就是说:延时一个指令周期,时钟周期要跑4次。所以计算出来的systick当然应该是4而不是1。

 

 

热点排行