Implement basics for timer0

This commit is contained in:
Jake Goulding
2016-06-02 23:00:56 -04:00
parent 89b8f31f68
commit 49c1bd785b
2 changed files with 145 additions and 4 deletions

View File

@@ -13,6 +13,7 @@ use avr_core::prelude::v1::*;
use avr_core::intrinsics::{volatile_load, volatile_store};
pub mod prelude;
pub mod timer0;
pub mod timer1;
use arduino::*;
@@ -25,15 +26,19 @@ extern fn eh_personality() {}
extern fn panic_fmt() -> ! { loop {} }
#[no_mangle]
pub unsafe extern "avr-interrupt" fn _ivr_timer1_compare_a() {
pub unsafe extern "avr-interrupt" fn _ivr_timer0_compare_a() {
let prev_value = volatile_load(PORTB);
volatile_store(PORTB, prev_value ^ PINB5);
}
const CPU_FREQUENCY_HZ: u64 = 16_000_000;
const DESIRED_HZ: f64 = 10.0/3.0;
const PRESCALER: u64 = 1024;
const INTERRUPT_EVERY_1_HZ_1024_PRESCALER: u16 = ((CPU_FREQUENCY_HZ as f64 / (DESIRED_HZ * PRESCALER as f64)) as u64 - 1) as u16;
const DESIRED_HZ_TIM1: f64 = 1.0;
const TIM1_PRESCALER: u64 = 1024;
const INTERRUPT_EVERY_1_HZ_1024_PRESCALER: u16 = ((CPU_FREQUENCY_HZ as f64 / (DESIRED_HZ_TIM1 * TIM1_PRESCALER as f64)) as u64 - 1) as u16;
const DESIRED_HZ_TIM0: f64 = 30.0;
const TIM0_PRESCALER: u64 = 1024;
const INTERRUPT_EVERY_30_HZ_1024_PRESCALER: u8 = ((CPU_FREQUENCY_HZ as f64 / (DESIRED_HZ_TIM0 * TIM0_PRESCALER as f64)) as u64 - 1) as u8;
#[no_mangle]
pub extern fn main() {
@@ -44,6 +49,12 @@ pub extern fn main() {
// Turn on all Port B pins
volatile_store(PORTB, 0xFF);
timer0::Timer::new()
.waveform_generation_mode(timer0::WaveformGenerationMode::ClearOnTimerMatchOutputCompare)
.clock_source(timer0::ClockSource::Prescale1024)
.output_compare_1(Some(INTERRUPT_EVERY_30_HZ_1024_PRESCALER))
.configure();
timer1::Timer::new()
.waveform_generation_mode(timer1::WaveformGenerationMode::ClearOnTimerMatchOutputCompare)
.clock_source(timer1::ClockSource::Prescale1024)

130
blink/src/timer0.rs Normal file
View File

@@ -0,0 +1,130 @@
use avr_core::prelude::v1::*;
use avr_core::intrinsics::volatile_store;
use arduino::*;
pub enum ClockSource {
None,
Prescale1,
Prescale8,
Prescale64,
Prescale256,
Prescale1024,
ExternalFalling,
ExternalRising,
}
impl ClockSource {
pub fn bits(&self) -> u8 {
use self::ClockSource::*;
match *self {
None => 0 | 0 | 0,
Prescale1 => 0 | 0 | CS00,
Prescale8 => 0 | CS01 | 0,
Prescale64 => 0 | CS01 | CS00,
Prescale256 => CS02 | 0 | 0,
Prescale1024 => CS02 | 0 | CS00,
ExternalFalling => CS02 | CS01 | 0,
ExternalRising => CS02 | CS01 | CS00,
}
}
pub fn mask() -> u8 {
!(CS02 | CS01 | CS00)
}
}
pub enum WaveformGenerationMode {
Normal,
PwmPhaseCorrect,
ClearOnTimerMatchOutputCompare,
FastPwm ,
PwmPhaseCorrectOutputCompare,
FastPwmOutputCompare,
}
impl WaveformGenerationMode {
/// Returns bits for TCCR0A, TCCR0B
pub fn bits(&self) -> (u8, u8) {
use self::WaveformGenerationMode::*;
// It makes more sense to return bytes (A,B), but the manual
// lists the table as (B,A). We match the manual here for
// inspection purposes and flip the values for sanity
// purposes.
let (b, a) = match *self {
Normal => ( 0, 0 | 0),
PwmPhaseCorrect => ( 0, 0 | WGM00),
ClearOnTimerMatchOutputCompare => ( 0, WGM01 | 0),
FastPwm => ( 0, WGM01 | WGM00),
// Reserved => (WGM02, 0 | 0),
PwmPhaseCorrectOutputCompare => (WGM02, 0 | WGM00),
// Reserved => (WGM02, WGM01 | 0),
FastPwmOutputCompare => (WGM02, WGM01 | WGM00),
};
(a, b)
}
pub fn mask() -> (u8, u8) {
(!(WGM00 | WGM01), !(WGM02))
}
}
pub struct Timer {
a: u8,
b: u8,
output_compare_1: Option<u8>,
}
impl Timer {
pub fn new() -> Self {
Timer {
a: 0,
b: 0,
output_compare_1: None,
}
}
pub fn clock_source(mut self, source: ClockSource) -> Self {
self.b &= ClockSource::mask();
self.b |= source.bits();
self
}
pub fn waveform_generation_mode(mut self, mode: WaveformGenerationMode) -> Self {
let (a, b) = WaveformGenerationMode::mask();
self.a &= a;
self.b &= b;
let (a, b) = mode.bits();
self.a |= a;
self.b |= b;
self
}
pub fn output_compare_1(mut self, value: Option<u8>) -> Self {
self.output_compare_1 = value;
self
}
pub fn configure(self) {
unsafe {
volatile_store(TCCR0A, self.a);
volatile_store(TCCR0B, self.b);
// Reset counter to zero
volatile_store(TCNT0, 0);
if let Some(v) = self.output_compare_1 {
// Set the match
volatile_store(OCR0A, v);
// Enable compare interrupt
volatile_store(TIMSK0, OCIE0A);
}
}
}
}