GlobLib
HAL and API libraries for MCUs and hardware.
attiny13a_timer.c
Go to the documentation of this file.
1 /*!**************************************************************************
2  @file attiny13a_timer.c
3  @brief Source file for attiny13a TIMER
4  @author Stuart Ianna
5  @version 0.1
6  @date October 2018
7  @copyright GNU GPLv3
8  @warning None
9  @bug
10 
11  @details
12 
13  @par Compilers
14  - avr-gcc V4.9.2
15 ******************************************************************************/
16 #include "attiny13a_timer.h"
17 
18 //TIMER_IC is enabled in the makefile
19 #ifdef TIMER_IC
20 static uint8_t IC_time;
21 static uint8_t IC_highTime;
22 #endif
23 
24 /****************************************************************************/
25 // TIMER_ISR -> Enabled in makefile
26 /****************************************************************************/
27 
28 
29 #ifdef TIMER_ISR
30 static void (*tim0_handler)(void);
31 
32 void IC_ISR(void);
33 
34 ISR(TIM0_COMPA_vect){
35 
36  tim0_handler();
37 }
38 
39 mcu_error TIMER_enableISR(timer_main timerNumber, void(*handler)(void)){
40 
41  (void)timerNumber;
42  cli();
43  tim0_handler = handler;
44  TIMSK0 |= (1<<OCIE0A);
45  sei();
46  return E_TIMER_NOERROR;
47 
48 }
49 
51 
52  cli();
53  TIMSK0 &= ~(1<<OCIE0A);
54  sei();
55  return E_TIMER_NOERROR;
56 
57 }
58 
59 mcu_error TIMER_setupCount(timer_main timerNumber, uint16_t frequency, void (*handler)(void)){
60 
61  //Use ctc mode to set the timeout time
62  (void)timerNumber;
63  tim0_handler = handler;
64  TCCR0A |= (1 << WGM01);
65  TIMSK0 |= (1<<OCIE0A);
66  return TIMER_setFrequency(timerNumber,frequency);
67 }
68 
69 mcu_error TIMER_setPeriod(timer_main timerNumber, uint32_t period){
70 
71  //Possibly a better way the set the period which doesn't invlude this divide term.
72  return TIMER_setFrequency(timerNumber,(uint16_t)(1e6/period));
73 }
74 
75 mcu_error TIMER_setFrequency(timer_main timerNumber,uint16_t frequency){
76 
77  cli();
78  TCCR0B = 0x0;
79 
80  //The divisions in the if statements should be evaluated at compile time.
81 
82  if(frequency > (F_CPU / 960)){
83 
84  return E_TIMER_PERIOD;
85  }
86  else if(frequency > 600){
87 
88  //Prescalar = 64
89  TCCR0B |= 0x3;
90  OCR0A = (CLOCK_DIV_64/frequency);
91  }
92  else if(frequency > (F_CPU / 240000)){
93 
94  //Prescalar = 1024
95  TCCR0B |= 0x5;
96  OCR0A = (CLOCK_DIV_1024/frequency);
97  }
98  else{
99 
100  return E_TIMER_PERIOD;
101  }
102 
103  sei();
104  return E_TIMER_NOERROR;
105 
106 }
107 #endif
108 
109 /****************************************************************************/
110 // PAUSE RESUME
111 /****************************************************************************/
112 
114 
115  (void)timerNumber;
116 
117  //Timer is stopped by clearing the prescaler bits.
118  TCCR0B &= ~0x7;
119  return 0;
120 }
121 
123 
124  //Problem here
125  //Timer prescaler value gets overwritten when timer is paused
126  //Use setup function to restart timer, or read prescaler in main
127  //application.
128  return 0;
129 }
130 
131 /****************************************************************************/
132 // INPUT CAPTUER -> TIMER_IC enabled in Makefile
133 /****************************************************************************/
134 
135 #ifdef TIMER_IC
136 mcu_error TIMER_setupIC(timer_main timerNumber, timer_channel timerChannel){
137 
138  (void)timerNumber;
139  (void)timerChannel;
140 
141  //Set frequency dependant on main clock, see attiny13a_timer.h
142  TCCR0B = 0x0;
143 
144 #if F_CPU == 9600000
145  TCCR0B |= 0x4; //256 prescaler
146 #elif F_CPU == 4800000
147  TCCR0B |= 0x4; //256 prescaler
148 #elif F_CPU == 1200000
149  TCCR0B |= 0x3; //64 prescaler
150 #elif F_CPU == 600000
151  TCCR0B |= 0x3; //64 prescaler
152 #endif
153 
154  //Setup the GPIO pin as an input with interrupts on both edges.
155  //This is used here both to save space and to force independant usage
156  //of input capture and GPIO_ISR, as they both need the interrupt vector
157  cli();
158  DDRB &= ~(1<<IC_PIN);
159  *(uint8_t*)PORTB &= ~(1<<IC_PIN);
160  PCMSK |= (1<<IC_PIN);
161  GIMSK |= 1<<PCIE;
162  MCUCR &= ~(1<<ISC01);
163  MCUCR |= 1<<ISC00;
164  sei();
165 
166  return E_TIMER_NOERROR;
167 }
168 
169 //External interrupt vector, stolen from attiny13a_gpio.c
170 ISR(PCINT0_vect){
171 
172  //Need to check if the pin is high or low
173  if(pinRead(PORTB,IC_PIN)){
174 
175  IC_highTime = TCNT0;
176  }
177  else{
178 
179  IC_time = TCNT0 - IC_highTime;
180  }
181 }
182 
183 uint16_t TIMER_getIC(timer_main timerNumber, timer_channel channel){
184 
185  (void) timerNumber;
186  (void) channel;
187 
188  if(0 == IC_time){
189 
190  return 0;
191  }
192 
193  uint8_t tempTime = IC_time;
194  IC_time = 0;
195 
196  //Take one of the IC_time reading for zero based couter.
197  //Multiplyers can be calculated as
198  // (1e6 *prescaler / F_CPU)
199  // This is the resolution of the counter in microseconds
200 
201 #if F_CPU == 9600000
202  return ((uint16_t)(tempTime-1) * 27);
203 #elif F_CPU == 4800000
204  return ((uint16_t)(tempTime-1) * 53);
205 #elif F_CPU == 1200000
206  return ((uint16_t)(tempTime-1) * 53);
207 #elif F_CPU == 600000
208  return ((uint16_t)(tempTime-1) * 106);
209 #else
210  return ((uint16_t)(tempTime-1) * 27);
211 #endif
212 }
213 
214 #endif
215 
216 /****************************************************************************/
217 // The following are always active
218 /****************************************************************************/
219 
220 mcu_error TIMER_setupPWM(timer_main timerNumber, timer_channel timerChannel, uint16_t frequency, uint8_t duty){
221 
222  //PWM is setup as fast PWM
223 
224  (void)timerNumber;
225  (void)frequency;
226 
227  TCCR0B = 0x0;
228  TCCR0B |= 0x1;
229 
230  if(timerChannel == CHANNEL_1){
231 
232  TCCR0A |= (1 << WGM01) | (1 << WGM00);
233  TCCR0A |= (1 << COM0A1);
234 
235  //Setup port as output.
236  DDRB |= 0x1;
237  }
238  else{
239 
240  TCCR0A |= (1 << WGM01) | (1 << WGM00);
241  TCCR0A |= (1 << COM0B1);
242 
243  //Setup port as output.
244  DDRB |= 0x2;
245  }
246 
247  TIMER_setDuty(timerNumber,timerChannel,duty);
248  return E_TIMER_NOERROR;
249 }
250 
251 mcu_error TIMER_setupPulse(timer_main timerNumber, timer_channel timerChannel, uint16_t frequency, uint16_t pulse){
252 
253  (void)timerNumber;
254  (void)frequency;
255 
256  TCCR0B = 0x0;
257 
258  //Prescaler value is dependent on clock frequency.
259 
260 #if F_CPU == 9600000
261  TCCR0B |= 0x4; //256 prescaler
262 #elif F_CPU == 4800000
263  TCCR0B |= 0x4; //256 prescaler
264 #elif F_CPU == 1200000
265  TCCR0B |= 0x3; //64 prescaler
266 #elif F_CPU == 600000
267  TCCR0B |= 0x3; //64 prescaler
268 #endif
269 
270 
271  if(timerChannel == CHANNEL_1){
272 
273  TCCR0A |= (1 << WGM01) | (1 << WGM00);
274  TCCR0A |= (1 << COM0A1);
275 
276  //Setup port as output.
277  DDRB |= 0x1;
278  }
279  else{
280 
281  TCCR0A |= (1 << WGM01) | (1 << WGM00);
282  TCCR0A |= (1 << COM0B1);
283 
284  //Setup port as output.
285  DDRB |= 0x2;
286  }
287 
288  TIMER_setPulse(timerNumber,timerChannel,pulse);
289  return E_TIMER_NOERROR;
290 }
291 
292 
293 /****************************************************************************/
294 // GET / SET COUNT
295 /****************************************************************************/
296 
297 uint8_t TIMER_getCount(timer_main timerNumber){
298 
299  (void) timerNumber;
300  return TCNT0;
301 
302 }
303 mcu_error TIMER_setCount(timer_main timerNumber, uint8_t count){
304 
305  (void) timerNumber;
306  return TCNT0 = count;
307 }
308 /****************************************************************************/
309 // PERIOD / FREQUENCY
310 /****************************************************************************/
311 
312 mcu_error TIMER_setDuty(timer_main timerNumber, timer_channel channel, uint8_t duty){
313 
314  if(channel == CHANNEL_1){
315 
316  OCR0A = (duty * 0xFF)/100;
317  }
318  else{
319 
320  OCR0B = (duty * 0xFF)/100;
321 
322  }
323  return E_TIMER_NOERROR;
324 }
325 
326 mcu_error TIMER_setPulse(timer_main timerNumber, timer_channel channel, uint16_t pulse){
327 
328  //Dividers can be calculated as
329  // (1e6 *prescaler / F_CPU)
330  // This is the resolution of the counter in microseconds
331 #if F_CPU == 9600000
332  OCR0B = (pulse / 27);
333 #elif F_CPU == 4800000
334  OCR0B = (pulse / 53);
335 #elif F_CPU == 1200000
336  OCR0B = (pulse / 53);
337 #elif F_CPU == 600000
338  OCR0B = (pulse / 106);
339 #endif
340 
341  return E_TIMER_NOERROR;
342 }
343 
uint8_t TIMER_getCount(timer_main timerNumber)
Get the current value of a running timer.
mcu_error TIMER_setCount(timer_main timerNumber, uint8_t count)
Set the current value of a running timer.
mcu_error TIMER_setupPWM(timer_main timerNumber, timer_channel timerChannel, uint16_t frequency, uint8_t duty)
Initialize given timer for PWM mode.
mcu_error TIMER_resume(timer_main timerNumber)
Resume a paused timer.
mcu_error TIMER_pause(timer_main timerNumber)
Pause an already running timer.
mcu_error TIMER_enableISR(timer_main timerNumber, void(*handler)(void))
Set the ISR target for timeout.
mcu_error TIMER_setPeriod(timer_main timerNumber, uint32_t period)
Set the period for the timer. (in microseconds)
Header file for attiny13a timers.
timer_main
Main timers available on the MCU.
mcu_error TIMER_disableISR(timer_main timerNumber)
Disable the timeout IRQ.
mcu_error TIMER_setFrequency(timer_main timerNumber, uint16_t frequency)
Set the frequency for the timer. (in hertz)
timer_channel
Timers channels available for each timer.
#define CLOCK_DIV_1024
Clock speed divided by 1024.
Channel 1.
mcu_error TIMER_setDuty(timer_main timerNumber, timer_channel channel, uint8_t duty)
Set the duty cycle for the waveform (PWM only, 0 - 100%).
Port B of the MCU.
mcu_error TIMER_setupPulse(timer_main timerNumber, timer_channel timerChannel, uint16_t frequency, uint16_t pulse)
Initialize given timer for Pulse mode.
Error timer: Period too long / frequency too high.
mcu_error TIMER_setupIC(timer_main timerNumber, timer_channel timerChannel)
Initialize given timer for input capture.
uint8_t pinRead(gpio_port port, gpio_pin pin)
Read the current digital value of an input pin.
mcu_error TIMER_setPulse(timer_main timerNumber, timer_channel channel, uint16_t pulse)
Set the pulse width for the output. (in milliseconds)
#define CLOCK_DIV_64
Clock speed divided by 64.
#define IC_PIN
Pin used for input capture.
Error timer: No error.
mcu_error TIMER_setupCount(timer_main timerNumber, uint16_t frequency, void(*handler)(void))
Initialize given timer for standard count with interrupt trigging the function handler on timeout...
mcu_error
Error enumerators for the Debug peripheral.
uint16_t TIMER_getIC(timer_main timerNumber, timer_channel channel)
Get the last input capture time from a channel of a timer.