You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
183 lines
3.8 KiB
183 lines
3.8 KiB
/** @file timer0.c
|
|
@author M. P. Hayes, UCECE
|
|
@date 15 May 2007
|
|
@brief
|
|
*/
|
|
#include "system.h"
|
|
#include "timer0.h"
|
|
#include "bits.h"
|
|
#include "prescale.h"
|
|
#include <avr/io.h>
|
|
|
|
/* Timer/Counter0 is a general purpose, single channel, 8-bit
|
|
Timer/Counter module.
|
|
|
|
It has two output compare registers and two corresponding outputs:
|
|
OC0A and OCOB. However, the counter can only be reset by the A
|
|
output compure register, OCRA.
|
|
|
|
TODO: rewrite driver to provide standard modes, such as:
|
|
* generate square wave on OCOA
|
|
* generate square wave on OCOB
|
|
* generate PWM on OCOA
|
|
* generate PWM on OCOB
|
|
* programmable timer (for delays)
|
|
|
|
*/
|
|
|
|
|
|
/* Prescale values:
|
|
1, 8, 64, 256, or 1024.
|
|
|
|
2^0, 2^3, 2^6, 2^8, 2^10. */
|
|
|
|
static const uint8_t log_prescales[] = {0, 3, 6, 8, 10};
|
|
static uint8_t prescale_bits = 1;
|
|
|
|
|
|
|
|
static inline void
|
|
timer0_prescaler_set (uint8_t value)
|
|
{
|
|
BITS_INSERT (TCCR0B, value, CS00, CS02);
|
|
}
|
|
|
|
|
|
static inline uint8_t
|
|
timer0_prescaler_get (void)
|
|
{
|
|
return BITS_EXTRACT (TCCR0B, CS00, CS02);
|
|
}
|
|
|
|
|
|
static inline bool
|
|
timer0_running_p (void)
|
|
{
|
|
return timer0_prescaler_get () != 0;
|
|
}
|
|
|
|
|
|
/* Set the desired period in terms of clocks. The closest
|
|
suitable period is returned. */
|
|
uint16_t timer0_period_set (uint16_t period)
|
|
{
|
|
uint8_t counter;
|
|
uint8_t index;
|
|
|
|
index = prescale_select (period, log_prescales,
|
|
ARRAY_SIZE (log_prescales), &counter);
|
|
|
|
prescale_bits = index + 1;
|
|
|
|
|
|
/* F = F_CPU / (2 * prescale * (1 + OCR0A))
|
|
Maximum frequency of F_CPU / 2 when OCR0A = 0. */
|
|
OCR0A = counter - 1;
|
|
OCR0B = 0;
|
|
|
|
/* A prescale value of 0 selects no clock source and is used to
|
|
stop the timer. The cheapskates haven't provided a start/stop
|
|
bit so we cannot set the prescaler if the timer is stopped. */
|
|
if (timer0_running_p ())
|
|
timer0_prescaler_set (prescale_bits);
|
|
|
|
/* Return the quantised period. */
|
|
return counter << log_prescales[index];
|
|
}
|
|
|
|
|
|
void
|
|
timer0_start (void)
|
|
{
|
|
/* Clear overflow flags. */
|
|
TIFR0 &= ~(BIT (OCF0A) | BIT (OCF0B));
|
|
|
|
/* Enable timer by supplying a clock from the prescaler. */
|
|
timer0_prescaler_set (prescale_bits);
|
|
}
|
|
|
|
|
|
void
|
|
timer0_stop (void)
|
|
{
|
|
/* Disable clock source. */
|
|
timer0_prescaler_set (0);
|
|
}
|
|
|
|
|
|
bool
|
|
timer0_compare_p (void)
|
|
{
|
|
return (TIFR0 & BIT (OCF0B)) != 0;
|
|
}
|
|
|
|
|
|
void timer0_output_set (timer0_output_t output, timer0_output_mode_t mode)
|
|
{
|
|
switch (output)
|
|
{
|
|
case TIMER0_OUTPUT_A:
|
|
/* Select output mode for 0C0A.
|
|
The port pin must also be configured as an output. */
|
|
BITS_INSERT (TCCR0A, mode, COM0A0, COM0A1);
|
|
break;
|
|
|
|
case TIMER0_OUTPUT_B:
|
|
/* Select output mode for 0C0B.
|
|
The port pin must also be configured as an output. */
|
|
BITS_INSERT (TCCR0A, mode, COM0B0, COM0B1);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
int8_t
|
|
timer0_mode_set (timer0_mode_t mode)
|
|
{
|
|
switch (mode)
|
|
{
|
|
case TIMER0_MODE_NORMAL:
|
|
/* Normal mode---counter not reset. It rolls over when it
|
|
gets to 0xFF and thus there is limited frequency control
|
|
for waveform generation. */
|
|
TCCR0A &= ~(BIT (WGM01) | BIT (WGM00));
|
|
|
|
/* Need WGM02 bit set to 0 (default) in TCCR0B. */
|
|
break;
|
|
|
|
case TIMER0_MODE_CTC:
|
|
/* Set CTC mode. Clear timer in compare mode---counter reset
|
|
on match with OCRA. */
|
|
TCCR0A &= ~BIT (WGM00);
|
|
TCCR0A |= BIT (WGM01);
|
|
|
|
/* Need WGM02 bit set to 0 (default) in TCCR0B. */
|
|
break;
|
|
|
|
default:
|
|
return 0;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
int8_t
|
|
timer0_init (void)
|
|
{
|
|
/* Set to normal mode, clock source disabled, output compare match
|
|
to not trigger OC pin. */
|
|
TCCR0A = 0;
|
|
TCCR0B = 0;
|
|
TCNT0 = 0;
|
|
|
|
OCR0B = 0;
|
|
|
|
timer0_mode_set (TIMER0_MODE_CTC);
|
|
|
|
return 1;
|
|
}
|