yarf 0.1
Yet Another RepRap Firmware
|
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