📄 clock.c
字号:
// This file is part of MANTIS OS, Operating System// See http://mantis.cs.colorado.edu///// Copyright (C) 2003,2004,2005 University of Colorado, Boulder//// This program is free software; you can redistribute it and/or// modify it under the terms of the mos license (see file LICENSE)/************************************************* Project Mantis File: clock.c Original Author: Jeff Rose Date: 4/20/04 Heavily Modified and debugged: Brian, Cyrus, Charles, Adam Date: 5/25/04 An alarm timer implementation for the avr *************************************************/#include "mos.h"#include "mutex.h"#include "msched.h"#include "clock.h"#include "printf.h"#include "plat_dep.h"#include "plat_clock.h"#ifdef ARCH_AVR#define TIMER_OCR OCR3A#define TIMER_INT OCIE3A#define TIMER_CNT TCNT3#define TIMER_CNTRLA TCCR3A#define TIMER_CNTRLB TCCR3B#define TIMER_FLAG OCF3A#define TIMER_SIG SIG_OUTPUT_COMPARE3A/** @brief an arbitrary "short" number of ticks */#define SHORT_TICKS 65static mos_alarm_t *head; // head of the list of alarms// the upper half of our 32 bit timer, since our hardware// timers are only 16 bitsstatic uint16_t elapsed_high_count;static mos_mutex_t clock_mutex;static void set_alarm_timer(uint32_t t);/** @brief Convert ticks to seconds. * * @param ticks Original time in ticks */#define to_secs(ticks) (ticks / (uint32_t)TICKS_PER_SEC)/** @brief Convert seconds to ticks. * * @param ticks Original time in seconds */#define to_usecs(ticks) (ticks * (uint32_t)USECS_PER_TICK)/** @brief Reset the timer. */#define clear_timer(void) do { TIMER_CNT = 0; \ elapsed_high_count = 0; \ } while(0);#define get_ticks() (TIMER_CNT - 200)/* subtract alarm2 from alarm1 */#define clock_sub(alarm1, alarm2) do { alarm1->ticks -= alarm2->ticks; } while (0)/* add alarm2's time to alarm 1 */#define clock_add(alarm1, alarm2) do { alarm1->ticks += alarm2->ticks; } while (0)#define enable_timer() do { \ TIMER_CNTRLB |= (1 << CS32); \ TIMER_CNTRLB &= ~((1 << CS31) | (1 << CS30)); \ } while (0)#define disable_timer() TIMER_CNTRLB &= ~((1 << CS32) | (1 << CS31) | (1 << CS30))void print_clock_list(void){ mos_alarm_t *aptr = head; uint8_t i = 0; printf("Clock list: \n"); while(aptr) { printf("alarm%C: %l\n", i++, aptr->ticks); aptr = aptr->next; } }/* Remove the first instance of alarm on the list */boolean mos_remove_alarm(mos_alarm_t *alarm){ mos_alarm_t *current = head; mos_alarm_t *prev = NULL; if(alarm == NULL) return false; while(current) { if(current == alarm) { //remove this alarm if(current == head) //removing head element head = current->next; if(prev) { prev->next = current->next; } if(current->next) { //add relative time to next timer clock_add(current->next, current); } return true; } prev = current; current = current->next; } return false;}int8_t mos_alarm (mos_alarm_t *new, uint32_t secs, uint32_t usecs){ // convert the arguments into a tick value uint32_t ticks = secs * TICKS_PER_SEC + usecs / USECS_PER_TICK; return mos_alarm_ticks(new, ticks);}int8_t mos_alarm_ticks(mos_alarm_t *new, uint32_t ticks){ mos_alarm_t *aptr, *prev; // Kill the timer so we don't have it go off while we are here disable_timer(); new->ticks = ticks; // the alarm list is empty, insert a new head if(head == NULL) { new->next = NULL; head = new; set_alarm_timer(head->ticks); } else { // initialize aptr for list traversal aptr = head; prev = NULL; // Run through the list to find the correct spot while(aptr) { if(new->ticks < aptr->ticks) { // Subtract the new value from the next alarm since it is now // relative to the newly inserted value. clock_sub(aptr, new); // break out if we find the correct spot. that way if // the loop hits the end we can add there too break; } // Since we are keeping relative times we need to // keep subtracting as we traverse the list. clock_sub(new, aptr); prev = aptr; aptr = aptr->next; } // Update the head to be relative to the new alarm if we have // a new head if(aptr == head) { new->next = head; head = new; set_alarm_timer(head->ticks); } else { // or just insert the new alarm prev->next = new; new->next = aptr; } } // enable the timer once again enable_timer(); return 0;}/* Set the current real world time. *//*int8_t mos_set_time (mos_time_t *tv){ ctime.sec = tv->sec; ctime.usec = tv->usec; return 0;}int8_t mos_get_time (mos_time_t *tv){ tv->sec = ctime.sec; ctime.usec = tv->usec; return 0;}*/void clock_init (void){ // correct config for these registers happens to be 0 TIMER_CNTRLA = 0; TIMER_CNTRLB = 0; disable_timer (); clear_timer (); mos_mutex_init (&clock_mutex); // set the output compare interrrupt flag //ETIFR |= (1 << TIMER_FLAG); ETIMSK |= (1 << TIMER_INT);}/*** Functions private to this file. ***/static uint16_t high_count, low_count; // 16 bit tick countsstatic void set_alarm_timer(uint32_t new_ticks){ // fudge the new ticks a bit to make things more precise // TODO: is this right? //new_ticks += 385; // shift the 32 bit ticks into our two 16 bit counters high_count = new_ticks >> 16; low_count = new_ticks & 0xFFFF; // reset the high bits and counter val clear_timer(); // if the alarm is long enough to go into the high bits, // set the counter comparator to maximum (16 bits) so we // can finagle it to be 32 bits, else set it to the ticks // of the new alarm if(high_count > 0) { TIMER_OCR = 0xffff; high_count--; } else { TIMER_OCR = low_count; low_count = 0; } }// we need to call the alarm's function AFTER removing it// from the list since we may call mos_alarm from inside// this interrupt handlerstatic inline void fire_alarm(void){ mos_alarm_t *temp_aptr; temp_aptr = head; if(head) { head = head->next; if(temp_aptr->func != NULL) temp_aptr->func(temp_aptr->data); }}/** @brief Alarm interrupt handler */SIGNAL(TIMER_SIG){ if(high_count == 0) { //no overruns left if(low_count == 0) { //time expired // reset the high bits elapsed_high_count = 0; //always fire the head node fire_alarm(); // If we have multiple alarms that overlap exactly then we will need // to call all the functions and pull them off the list. while(head) { if(head->ticks < SHORT_TICKS) { fire_alarm(); } else // no need to keep going since the list is in order break; } //set timer for next alarm if(head) { set_alarm_timer (head->ticks); } else //no more alarms, turn timer off disable_timer(); } else { //low count not zero TIMER_OCR = low_count; elapsed_high_count++; low_count = 0; head->ticks -= 0xffff; } } else { //high count not zero TIMER_OCR = 0xffff; elapsed_high_count++; high_count--; head->ticks -= 0xffff; }}#elseint8_t mos_alarm (mos_alarm_t *new, uint32_t secs, uint32_t usecs){ return 0;}int8_t mos_alarm_ticks(mos_alarm_t *new, uint32_t ticks){ return 0;}#ifdef PLATFORM_TELOSBvoid clock_init(void){ uint16_t old_ccr2_val; int16_t new_ccr2_val; uint8_t rsel_val; uint8_t dco_val; BCSCTL1 = XT2OFF | DIVA1 | RSEL2 | RSEL0; BCSCTL2 = 0; TACTL = TASSEL_2 | TACLR; // clear clock, source is SMCLK TACTL |= MC1; // start timer in continuous mode CCTL2 = CM0 | CCIS0 | CAP; // rising edge capture for(;;) { while(!(CCTL2 & CCIFG)) ; // wait for capture flag old_ccr2_val = CCR2; CCTL2 &= ~CCIFG; while(!(CCTL2 & CCIFG)) ; // wait for capture flag CCTL2 &= ~CCIFG; rsel_val = BCSCTL1; rsel_val &= (RSEL0 | RSEL1 | RSEL2); // mask out rsel bits dco_val = DCOCTL; if(dco_val == 0xff) { if(rsel_val < 7) { BCSCTL1++; } else { goto err; } } else if(dco_val == 0) { if(rsel_val != 0) { BCSCTL1--; } else { goto err; } } else { new_ccr2_val = CCR2; new_ccr2_val -= old_ccr2_val; old_ccr2_val = CCR2; new_ccr2_val -= (CLOCK_SPEED / (32768 / 4)); if(new_ccr2_val < 0) { DCOCTL++; continue; } else if(new_ccr2_val == 0) { goto err; } else { DCOCTL--; continue; } } DCOCTL = 0x60; // center dco }err: CCTL2 = 0; return; }#elsevoid clock_init(void){ }#endifboolean mos_remove_alarm(mos_alarm_t *alarm){ return TRUE; }#endif/* Delay for the given number of milliseconds * @param usec Number of milliseconds to be delayed */void mos_mdelay(uint16_t msec){ while(msec > 0) { // account for the instructions of processing the // 16 bit msec variable // TODO: is this fudge factor right? mos_udelay (950); msec--; }}/* Delay the current thread for give number of microseconds * @param usec number of microseconds to be delayed */#if defined(CLOCK_SPEED_7_37)void mos_udelay(uint16_t usec){ while(usec > 0) { asm volatile("nop" ::); asm volatile("nop" ::); asm volatile("nop" ::); asm volatile("nop" ::); usec--; }}#elif defined(CLOCK_SPEED_3_68)void mos_udelay(uint16_t usec){ while(usec > 0) { asm volatile("nop" ::); usec--; }}#elif defined(CLOCK_SPEED_4_0)void mos_udelay(uint16_t usec){ while(usec > 0) { asm volatile("nop" ::); asm volatile("nop" ::); usec--; }}#else#error "Unimplemented clock speed"#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -