Implement basics for timer0
This commit is contained in:
@@ -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
130
blink/src/timer0.rs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user