diff --git a/src/lib.rs b/src/lib.rs index eae809d..6b37278 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -19,7 +19,6 @@ pub use self::usart::HardwareUsart; pub mod prelude; pub mod serial; -pub mod timer1; pub mod cores; pub mod modules; diff --git a/src/modules/mod.rs b/src/modules/mod.rs index 238d405..f8ac3bd 100644 --- a/src/modules/mod.rs +++ b/src/modules/mod.rs @@ -1,7 +1,7 @@ //! Modules that can be implemented for specific cores. pub use self::spi::HardwareSpi; -pub use self::timer::{Timer8, Timer8Setup}; +pub use self::timer::{Timer8, Timer8Setup, Timer16, Timer16Setup}; mod spi; mod timer; diff --git a/src/modules/timer/mod.rs b/src/modules/timer/mod.rs index 92412a5..11c28c6 100644 --- a/src/modules/timer/mod.rs +++ b/src/modules/timer/mod.rs @@ -1,4 +1,6 @@ pub use self::timer8::{Timer8, Timer8Setup}; +pub use self::timer16::{Timer16, Timer16Setup}; mod timer8; +mod timer16; diff --git a/src/modules/timer/timer16.rs b/src/modules/timer/timer16.rs new file mode 100644 index 0000000..2f4d7c9 --- /dev/null +++ b/src/modules/timer/timer16.rs @@ -0,0 +1,211 @@ +use {Bitset, Mask, Register}; +use core::marker; + +/// A 16-bit timer. +pub trait Timer16 { + /// The first compare register. + /// For example, OCR0A. + type CompareA: Register; + + /// The second compare register. + /// For example, OCR0B. + type CompareB: Register; + + /// The counter register. + /// + /// For example, TCNT0. + type Counter: Register; + + /// The first control register. + /// + /// For example, TCCR0A. + type ControlA: Register; + + /// The second control register. + /// + /// For example, TCCR0B. + type ControlB: Register; + + /// The third control register. + /// + /// For example, TCCR0C. + type ControlC: Register; + + /// The interrupt mask register. + /// + /// For example, TIMSK0. + type InterruptMask: Register; + + /// The interrupt flag register. + /// + /// For example, TIFR0. + type InterruptFlag: Register; + + const CS0: Mask; + const CS1: Mask; + const CS2: Mask; + + const WGM0: Mask; + const WGM1: Mask; + const WGM2: Mask; + const WGM3: Mask; // fixme: right reg? + + const OCIEA: Bitset; +} + +pub enum ClockSource { + None, + Prescale1, + Prescale8, + Prescale64, + Prescale256, + Prescale1024, + ExternalFalling, + ExternalRising, +} + +impl ClockSource { + fn bits(&self) -> Mask { + use self::ClockSource::*; + + match *self { + None => Mask::zero() | Mask::zero() | Mask::zero(), + Prescale1 => Mask::zero() | Mask::zero() | T::CS0, + Prescale8 => Mask::zero() | T::CS1 | Mask::zero(), + Prescale64 => Mask::zero() | T::CS1 | T::CS0, + Prescale256 => T::CS2 | Mask::zero() | Mask::zero(), + Prescale1024 => T::CS2 | Mask::zero() | T::CS0, + ExternalFalling => T::CS2 | T::CS1 | Mask::zero(), + ExternalRising => T::CS2 | T::CS1 | T::CS0, + } + } + + #[inline] + fn mask() -> Mask { + !(T::CS2 | T::CS1 | T::CS0) + } +} + +pub enum WaveformGenerationMode { + Normal, + PwmPhaseCorrect8Bit, + PwmPhaseCorrect9Bit, + PwmPhaseCorrect10Bit, + ClearOnTimerMatchOutputCompare, + FastPwm8Bit, + FastPwm9Bit, + FastPwm10Bit, + PwmPhaseAndFrequencyCorrectInputCapture, + PwmPhaseAndFrequencyCorrectOutputCompare, + PwmPhaseCorrectInputCapture, + PwmPhaseCorrectOutputCompare, + ClearOnTimerMatchInputCapture, + FastPwmInputCapture, + FastPwmOutputCompare, +} + +impl WaveformGenerationMode { + /// Returns bits for TCCR1A, TCCR1B + #[inline] + fn bits(&self) -> (Mask, Mask) { + 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 => (Mask::zero() | Mask::zero(), Mask::zero() | Mask::zero()), + PwmPhaseCorrect8Bit => (Mask::zero() | Mask::zero(), Mask::zero() | T::WGM0), + PwmPhaseCorrect9Bit => (Mask::zero() | Mask::zero(), T::WGM1 | Mask::zero()), + PwmPhaseCorrect10Bit => (Mask::zero() | Mask::zero(), T::WGM1 | T::WGM0), + ClearOnTimerMatchOutputCompare => (Mask::zero() | T::WGM2, Mask::zero() | Mask::zero()), + FastPwm8Bit => (Mask::zero() | T::WGM2, Mask::zero() | T::WGM0), + FastPwm9Bit => (Mask::zero() | T::WGM2, T::WGM1 | Mask::zero()), + FastPwm10Bit => (Mask::zero() | T::WGM2, T::WGM1 | T::WGM0), + PwmPhaseAndFrequencyCorrectInputCapture => (T::WGM3 | Mask::zero(), Mask::zero() | Mask::zero()), + PwmPhaseAndFrequencyCorrectOutputCompare => (T::WGM3 | Mask::zero(), Mask::zero() | T::WGM0), + PwmPhaseCorrectInputCapture => (T::WGM3 | Mask::zero(), T::WGM1 | Mask::zero()), + PwmPhaseCorrectOutputCompare => (T::WGM3 | Mask::zero(), T::WGM1 | T::WGM0), + ClearOnTimerMatchInputCapture => (T::WGM3 | T::WGM2, Mask::zero() | Mask::zero()), + // Reserved => (T::WGM3 | T::WGM2, Mask::zero() | T::WGM0), + FastPwmInputCapture => (T::WGM3 | T::WGM2, T::WGM1 | Mask::zero()), + FastPwmOutputCompare => (T::WGM3 | T::WGM2, T::WGM1 | T::WGM0), + }; + + (a, b) + } + + #[inline] + fn mask() -> (Mask, Mask) { + (!(T::WGM0 | T::WGM1), !(T::WGM2 | T::WGM3)) + } +} + +pub struct Timer16Setup { + a: Mask, + b: Mask, + c: Mask, + output_compare_1: Option, + _phantom: marker::PhantomData, +} + +impl Timer16Setup { + #[inline] + pub fn new() -> Self { + Timer16Setup { + a: Mask::zero(), + b: Mask::zero(), + c: Mask::zero(), + output_compare_1: None, + _phantom: marker::PhantomData, + } + } + + #[inline] + pub fn clock_source(mut self, source: ClockSource) -> Self { + self.b &= ClockSource::mask::(); + self.b |= source.bits::(); + self + } + + #[inline] + 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 + } + + #[inline] + pub fn output_compare_1(mut self, value: Option) -> Self { + self.output_compare_1 = value; + self + } + + #[inline] + pub fn configure(self) { + unsafe { + T::ControlA::write(self.a); + T::ControlB::write(self.b); + T::ControlC::write(self.c); + + // Reset counter to zero + T::Counter::write(0u16); + + if let Some(v) = self.output_compare_1 { + // Set the match + T::CompareA::write(v); + + // Enable compare interrupt + // FIXME: uncomment + // write_volatile(TIMSK1, OCIE1A); + } + } + } +} diff --git a/src/modules/timer/timer8.rs b/src/modules/timer/timer8.rs index 9d4679a..cdc55d1 100644 --- a/src/modules/timer/timer8.rs +++ b/src/modules/timer/timer8.rs @@ -1,7 +1,7 @@ use {Bitset, Mask, Register}; use core::marker; -/// An 8-bit timer. +/// A 8-bit timer. pub trait Timer8 { /// The first compare register. /// For example, OCR0A. @@ -177,6 +177,7 @@ impl Timer8Setup { T::CompareA::write(v); // Enable compare interrupt + // FIXME: is this right? T::OCIEA.set_all(); } } diff --git a/src/timer1.rs b/src/timer1.rs deleted file mode 100644 index 5c0cfad..0000000 --- a/src/timer1.rs +++ /dev/null @@ -1,159 +0,0 @@ -use core::prelude::v1::*; -use core::ptr::write_volatile; - -use super::*; - -pub enum ClockSource { - None, - Prescale1, - Prescale8, - Prescale64, - Prescale256, - Prescale1024, - ExternalFalling, - ExternalRising, -} - -impl ClockSource { - #[inline] - fn bits(&self) -> u8 { - use self::ClockSource::*; - - match *self { - None => 0 | 0 | 0, - Prescale1 => 0 | 0 | CS10, - Prescale8 => 0 | CS11 | 0, - Prescale64 => 0 | CS11 | CS10, - Prescale256 => CS12 | 0 | 0, - Prescale1024 => CS12 | 0 | CS10, - ExternalFalling => CS12 | CS11 | 0, - ExternalRising => CS12 | CS11 | CS10, - } - } - - #[inline] - fn mask() -> u8 { - !(CS12 | CS11 | CS10) - } -} - -pub enum WaveformGenerationMode { - Normal, - PwmPhaseCorrect8Bit, - PwmPhaseCorrect9Bit, - PwmPhaseCorrect10Bit, - ClearOnTimerMatchOutputCompare, - FastPwm8Bit, - FastPwm9Bit, - FastPwm10Bit, - PwmPhaseAndFrequencyCorrectInputCapture, - PwmPhaseAndFrequencyCorrectOutputCompare, - PwmPhaseCorrectInputCapture, - PwmPhaseCorrectOutputCompare, - ClearOnTimerMatchInputCapture, - FastPwmInputCapture, - FastPwmOutputCompare, -} - -impl WaveformGenerationMode { - /// Returns bits for TCCR1A, TCCR1B - #[inline] - 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 | 0), - PwmPhaseCorrect8Bit => ( 0 | 0, 0 | WGM10), - PwmPhaseCorrect9Bit => ( 0 | 0, WGM11 | 0), - PwmPhaseCorrect10Bit => ( 0 | 0, WGM11 | WGM10), - ClearOnTimerMatchOutputCompare => ( 0 | WGM12, 0 | 0), - FastPwm8Bit => ( 0 | WGM12, 0 | WGM10), - FastPwm9Bit => ( 0 | WGM12, WGM11 | 0), - FastPwm10Bit => ( 0 | WGM12, WGM11 | WGM10), - PwmPhaseAndFrequencyCorrectInputCapture => (WGM13 | 0, 0 | 0), - PwmPhaseAndFrequencyCorrectOutputCompare => (WGM13 | 0, 0 | WGM10), - PwmPhaseCorrectInputCapture => (WGM13 | 0, WGM11 | 0), - PwmPhaseCorrectOutputCompare => (WGM13 | 0, WGM11 | WGM10), - ClearOnTimerMatchInputCapture => (WGM13 | WGM12, 0 | 0), - // Reserved => (WGM13 | WGM12, 0 | WGM10), - FastPwmInputCapture => (WGM13 | WGM12, WGM11 | 0), - FastPwmOutputCompare => (WGM13 | WGM12, WGM11 | WGM10), - }; - - (a, b) - } - - #[inline] - fn mask() -> (u8, u8) { - (!(WGM10 | WGM11), !(WGM12 | WGM13)) - } -} - -pub struct Timer { - a: u8, - b: u8, - c: u8, - output_compare_1: Option, -} - -impl Timer { - #[inline] - pub fn new() -> Self { - Timer { - a: 0, - b: 0, - c: 0, - output_compare_1: None, - } - } - - #[inline] - pub fn clock_source(mut self, source: ClockSource) -> Self { - self.b &= ClockSource::mask(); - self.b |= source.bits(); - self - } - - #[inline] - 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 - } - - #[inline] - pub fn output_compare_1(mut self, value: Option) -> Self { - self.output_compare_1 = value; - self - } - - #[inline] - pub fn configure(self) { - unsafe { - write_volatile(TCCR1A, self.a); - write_volatile(TCCR1B, self.b); - write_volatile(TCCR1C, self.c); - - // Reset counter to zero - write_volatile(TCNT1, 0); - - if let Some(v) = self.output_compare_1 { - // Set the match - write_volatile(OCR1A, v); - - // Enable compare interrupt - write_volatile(TIMSK1, OCIE1A); - } - } - } -}