yarf 0.1
Yet Another RepRap Firmware
src/scheduling/realtime_timer.c
Go to the documentation of this file.
00001 /*
00002  * realtime_timer.c
00003  *
00004  * Copyright 2011 Pieter Agten
00005  *
00006  * This file is part of Yarf.
00007  *
00008  * Yarf is free software: you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation, either version 3 of the License, or
00011  * (at your option) any later version.
00012  *
00013  * Yarf is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  * GNU General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU General Public License
00019  * along with Yarf.  If not, see <http://www.gnu.org/licenses/>.
00020  */
00021 
00039 #include "realtime_timer.h"
00040 
00041 #include "hardware/fastio.h"
00042 #include "yarf.h"
00043 #include "util/math.h"
00044 
00045 #include <stdint.h>
00046 #include <stdlib.h>
00047 #include <avr/interrupt.h>
00048 #include <util/atomic.h>
00049 
00053 #define RTTIMER_TICKS_PER_US (((float)F_CPU)/8/1000000)
00054 
00059 static volatile realtime_task_t *pending_task;
00060 
00061 
00073 static inline void
00074 timer2_set(long ticks)
00075 {
00076   /* Note: the timer should be disabled at this point */
00077 
00078   /* Limit the number of ticks to the maximum possible ticks in hardware */
00079   uint8_t hw_ticks = MIN(UINT8_MAX, MAX(0,ticks));
00080 
00081   /* Set TCNTn to 0 */
00082   TCNT2 = 0;
00083   /* Set the TOP register to the number of ticks we want to wait */
00084   OCR2A = hw_ticks;
00085   
00086   /* Enable timer 2 (with /8 prescaler) */
00087   TCCR2B =  (2 << CS20);
00088 }
00089 
00097 ISR(TIMER2_COMPA_vect, ISR_BLOCK)
00098 {
00099   /* Disable the timer */
00100   TCCR2B = 0;
00101 
00102   if (pending_task != NULL) {
00103     if (pending_task->ticks_remaining > OCR2A) {
00104       pending_task->ticks_remaining -= OCR2A;
00105 
00106       /* The delay has not been passed yet */
00107       timer2_set(pending_task->ticks_remaining);
00108     } else {
00109       /* The delay has been passed, let's execute the task */
00110 
00111       volatile realtime_task_t *t = pending_task;
00112       /* Set pending_task to NULL so f will be able to schedule another task */
00113       pending_task = NULL;
00114       t->f();
00115     }
00116   }
00117 }
00118 
00119 
00120 void
00121 rttimer_init(void)
00122 {
00123   pending_task = NULL;
00124   
00125   /* Select OCR2A CTC mode; */
00126   TCCR2A = (2 << WGM20);
00127   TCCR2B = 0;
00128 
00129   /* Clear all timer 2 interrupt flags */
00130   TIFR2 = _BV(OCF2B)|_BV(OCF2A)|_BV(TOV2);
00131 
00132   /* Enable the OCR2A interrupt */
00133   TIMSK2 = _BV(OCIE2A);
00134 }
00135 
00136 
00137 int
00138 rttimer_schedule_ticks(realtime_task_t *t, uint16_t ticks)
00139 {
00140   if (pending_task != NULL) {
00141     return RTTIMER_BUSY;
00142   }
00143   pending_task = t;
00144 
00145   pending_task->ticks_remaining = ticks;
00146   timer2_set(pending_task->ticks_remaining);
00147   
00148   return RTTIMER_SUCCESS;
00149 }
00150 
00151 
00152 int
00153 rttimer_cancel(void)
00154 {
00155   if (pending_task == NULL) {
00156     return RTTIMER_NOT_RUNNING;
00157   }
00158 
00159   /* Disable the timer */
00160   TCCR2B = 0;
00161   
00162   /* Clear all timer 2 interrupt flags */
00163   TIFR2 = _BV(OCF2B)|_BV(OCF2A)|_BV(TOV2);
00164 
00165   /* Remove the pending task */
00166   pending_task = NULL;
00167 
00168   return RTTIMER_SUCCESS;
00169 }
00170 
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines