From 274d4611ec6f34c555d12d98d2109d2579dac7b3 Mon Sep 17 00:00:00 2001 From: Dylan McKay Date: Thu, 14 Dec 2017 00:55:57 +1300 Subject: [PATCH] More work done --- build.rs | 62 +++++++--- src/lib.rs | 5 +- src/modules/mod.rs | 8 ++ src/{ => modules}/spi/clock.rs | 0 src/{ => modules}/spi/mod.rs | 54 +++------ src/{ => modules}/spi/settings.rs | 2 + src/modules/timer/mod.rs | 4 + src/modules/timer/timer8.rs | 184 ++++++++++++++++++++++++++++++ src/register.rs | 57 ++++++++- src/timer.rs | 38 ------ src/timer0.rs | 141 ----------------------- 11 files changed, 317 insertions(+), 238 deletions(-) create mode 100644 src/modules/mod.rs rename src/{ => modules}/spi/clock.rs (100%) rename src/{ => modules}/spi/mod.rs (64%) rename src/{ => modules}/spi/settings.rs (98%) create mode 100644 src/modules/timer/mod.rs create mode 100644 src/modules/timer/timer8.rs delete mode 100644 src/timer.rs delete mode 100644 src/timer0.rs diff --git a/build.rs b/build.rs index 6da6b28..bff50ac 100644 --- a/build.rs +++ b/build.rs @@ -72,13 +72,14 @@ fn write_core_module(mcu: &Mcu, w: &mut Write) -> Result<(), io::Error> { writeln!(w, "//! Core for {}.", mcu.device.name)?; writeln!(w)?; writeln!(w, "use {{Mask, Bitset, HardwareUsart, Register}};")?; - writeln!(w, "use spi::HardwareSpi;")?; + writeln!(w, "use modules;")?; writeln!(w)?; gen::write_registers(mcu, w)?; gen::write_pins(mcu, w)?; gen::write_spi_modules(mcu, w)?; gen::write_usarts(mcu, w)?; + gen::write_timers(mcu, w)?; writeln!(w) } @@ -105,18 +106,16 @@ mod gen { // We create masks for the individual bits in the field if there // is more than one bit in the field. - if bitfield.mask.count_ones() > 1 { - let mut current_mask = bitfield.mask; - let mut current_mask_bit_num = 0; - for current_register_bit_num in 0..15 { - if (current_mask & 0b1) == 0b1 { - writeln!(w, " pub const {}{}: Mask<{}, Self> = Mask::new(1<<{});", - bitfield.name, current_mask_bit_num, ty, current_register_bit_num)?; - current_mask_bit_num += 1; - } - - current_mask >>= 1; + let mut current_mask = bitfield.mask; + let mut current_mask_bit_num = 0; + for current_register_bit_num in 0..15 { + if (current_mask & 0b1) == 0b1 { + writeln!(w, " pub const {}{}: Mask<{}, Self> = Mask::new(1<<{});", + bitfield.name, current_mask_bit_num, ty, current_register_bit_num)?; + current_mask_bit_num += 1; } + + current_mask >>= 1; } writeln!(w)?; } @@ -181,7 +180,7 @@ mod gen { writeln!(w, "pub struct Spi;")?; writeln!(w)?; - writeln!(w, "impl HardwareSpi for Spi {{")?; + writeln!(w, "impl modules::HardwareSpi for Spi {{")?; for spi_signal in peripheral.signals() { let spi_signal_name = spi_signal.group.clone().expect("spi signal does not have group name"); @@ -243,6 +242,43 @@ mod gen { Ok(()) } + pub fn write_timers(mcu: &Mcu, w: &mut Write) -> Result<(), io::Error> { + if let Some(tc) = mcu.module("TC8") { // Timer/Counter, 8-bit. + const TYPE_NAME: &'static str = "Timer8"; + + let find_reg = |name: &'static str| { + tc.registers().find(|r| r.name.starts_with(name)) + .expect(&format!("could not find '{}' register", name)) + }; + let find_reg_suffix = |name: &'static str, suffix: &'static str| { + tc.registers().find(|r| r.name.starts_with(name) && r.name.ends_with(suffix)) + .expect(&format!("could not find '{}' register", name)) + }; + + writeln!(w, "/// 8-bit timer.")?; + writeln!(w, "pub struct {};", TYPE_NAME)?; + writeln!(w)?; + writeln!(w, "impl modules::Timer8 for {} {{", TYPE_NAME)?; + writeln!(w, " type CompareA = {};", find_reg_suffix("OCR", "A").name)?; + writeln!(w, " type CompareB = {};", find_reg_suffix("OCR", "B").name)?; + writeln!(w, " type Counter = {};", find_reg("TCNT").name)?; + writeln!(w, " type ControlA = {};", find_reg_suffix("TCCR", "A").name)?; + writeln!(w, " type ControlB = {};", find_reg_suffix("TCCR", "B").name)?; + writeln!(w, " type InterruptMask = {};", find_reg("TIMSK").name)?; + writeln!(w, " type InterruptFlag = {};", find_reg("TIFR").name)?; + writeln!(w, " const CS0: Mask = Self::ControlB::CS00;")?; + writeln!(w, " const CS1: Mask = Self::ControlB::CS01;")?; + writeln!(w, " const CS2: Mask = Self::ControlB::CS02;")?; + writeln!(w, " const WGM0: Mask = Self::ControlA::WGM00;")?; + writeln!(w, " const WGM1: Mask = Self::ControlA::WGM01;")?; + writeln!(w, " const WGM2: Mask = Self::ControlB::WGM020;")?; + writeln!(w, " const OCIEA: Bitset = Self::InterruptMask::OCIE0A;")?; + writeln!(w, "}}")?; + } + + Ok(()) + } + /// Gets the name of a pin. fn pin_name(instance: &Instance, signal: &Signal) -> String { let idx = signal.index.expect("signal with no index"); diff --git a/src/lib.rs b/src/lib.rs index 6000613..eae809d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -15,22 +15,19 @@ pub use self::register::{Bitset, Mask, Register, RegisterValue}; pub use self::pin::Pin; -pub use self::timer::Timer8; pub use self::usart::HardwareUsart; pub mod prelude; pub mod serial; -pub mod timer0; pub mod timer1; pub mod cores; +pub mod modules; -pub mod spi; pub mod config; mod register; mod pin; mod usart; -mod timer; #[doc(hidden)] pub mod std_stub; diff --git a/src/modules/mod.rs b/src/modules/mod.rs new file mode 100644 index 0000000..238d405 --- /dev/null +++ b/src/modules/mod.rs @@ -0,0 +1,8 @@ +//! Modules that can be implemented for specific cores. + +pub use self::spi::HardwareSpi; +pub use self::timer::{Timer8, Timer8Setup}; + +mod spi; +mod timer; + diff --git a/src/spi/clock.rs b/src/modules/spi/clock.rs similarity index 100% rename from src/spi/clock.rs rename to src/modules/spi/clock.rs diff --git a/src/spi/mod.rs b/src/modules/spi/mod.rs similarity index 64% rename from src/spi/mod.rs rename to src/modules/spi/mod.rs index 75f98fd..852b70e 100644 --- a/src/spi/mod.rs +++ b/src/modules/spi/mod.rs @@ -60,80 +60,80 @@ pub trait HardwareSpi { /// Enables interrupts for the spi module. #[inline(always)] fn enable_interrupt() { - Self::ControlRegister::set_raw(control_register::INTERRUPT_ENABLE); + Self::ControlRegister::set_raw(settings::control_register::INTERRUPT_ENABLE); } /// Disables interrupts for the spi module. #[inline(always)] fn disable_interrupt() { - Self::ControlRegister::unset_raw(control_register::INTERRUPT_ENABLE); + Self::ControlRegister::unset_raw(settings::control_register::INTERRUPT_ENABLE); } /// Enables the SPI. #[inline(always)] fn enable() { - Self::ControlRegister::set_raw(control_register::ENABLE); + Self::ControlRegister::set_raw(settings::control_register::ENABLE); } /// Disables the SPI. #[inline(always)] fn disable() { - Self::ControlRegister::unset_raw(control_register::ENABLE); + Self::ControlRegister::unset_raw(settings::control_register::ENABLE); } /// Enables least-significant-bit first. #[inline(always)] fn set_lsb() { - Self::ControlRegister::set_raw(control_register::DATA_ORDER_LSB); + Self::ControlRegister::set_raw(settings::control_register::DATA_ORDER_LSB); } /// Enables most-significant-bit first. #[inline(always)] fn set_msb() { - Self::ControlRegister::unset_raw(control_register::DATA_ORDER_LSB); + Self::ControlRegister::unset_raw(settings::control_register::DATA_ORDER_LSB); } /// Enables master mode. #[inline(always)] fn set_master() { - Self::ControlRegister::set_raw(control_register::MASTER); + Self::ControlRegister::set_raw(settings::control_register::MASTER); } /// Enables slave mode. #[inline(always)] fn set_slave() { - Self::ControlRegister::unset_raw(control_register::MASTER); + Self::ControlRegister::unset_raw(settings::control_register::MASTER); } /// Enables double speed mode. #[inline(always)] fn enable_double_speed() { - Self::StatusRegister::set_raw(status_register::SPI2X); + Self::StatusRegister::set_raw(settings::status_register::SPI2X); } /// Disables double speed mode. #[inline(always)] fn disable_double_speed() { - Self::StatusRegister::unset_raw(status_register::SPI2X); + Self::StatusRegister::unset_raw(settings::status_register::SPI2X); } /// Checks if there is a write collision. #[inline(always)] fn is_write_collision() -> bool { - Self::StatusRegister::is_set_raw(status_register::WCOL) + Self::StatusRegister::is_set_raw(settings::status_register::WCOL) } /// Sends a byte through the serial. #[inline(always)] fn send_byte(byte: u8) { Self::DataRegister::write(byte); - Self::StatusRegister::wait_until_set_raw(status_register::SPIF); + Self::StatusRegister::wait_until_set_raw(settings::status_register::SPIF); } /// Reads a byte from the serial. #[inline(always)] fn receive_byte() -> u8 { - Self::StatusRegister::wait_until_set_raw(status_register::SPIF); + Self::StatusRegister::wait_until_set_raw(settings::status_register::SPIF); Self::DataRegister::read() } @@ -141,34 +141,8 @@ pub trait HardwareSpi { #[inline(always)] fn send_receive(byte: u8) -> u8 { Self::DataRegister::write(byte); - Self::StatusRegister::wait_until_set_raw(status_register::SPIF); + Self::StatusRegister::wait_until_set_raw(settings::status_register::SPIF); Self::DataRegister::read() } } -/// Constants for the control register. -pub mod control_register { - pub const INTERRUPT_ENABLE: u8 = 1<<7; - pub const ENABLE: u8 = 1<<6; - pub const DATA_ORDER_LSB: u8 = 1<<5; - pub const MASTER: u8 = 1<<4; - /// Clock polarity. - pub const CPOL: u8 = 1<<3; - /// Clock phase. - pub const CPHA: u8 = 1<<2; - /// Clock rate select 1. - pub const SPR1: u8 = 1<<1; - /// Clock rate select 2. - pub const SPR0: u8 = 1<<0; -} - -/// Constants for the status register. -pub mod status_register { - /// SPI interrupt flag. - pub const SPIF: u8 = 1<<7; - /// Write collision flag. - pub const WCOL: u8 = 1<<6; - /// SPI double speed mode. - pub const SPI2X: u8 = 1<<0; -} - diff --git a/src/spi/settings.rs b/src/modules/spi/settings.rs similarity index 98% rename from src/spi/settings.rs rename to src/modules/spi/settings.rs index d3563dc..45edb9d 100644 --- a/src/spi/settings.rs +++ b/src/modules/spi/settings.rs @@ -96,6 +96,7 @@ impl Default for Settings { } /// Constants for the control register. +#[allow(dead_code)] pub mod control_register { /// Set if interrupts are enabled. pub const INTERRUPT_ENABLE: u8 = 1<<7; @@ -116,6 +117,7 @@ pub mod control_register { } /// Constants for the status register. +#[allow(dead_code)] pub mod status_register { /// SPI interrupt flag. pub const SPIF: u8 = 1<<7; diff --git a/src/modules/timer/mod.rs b/src/modules/timer/mod.rs new file mode 100644 index 0000000..92412a5 --- /dev/null +++ b/src/modules/timer/mod.rs @@ -0,0 +1,4 @@ +pub use self::timer8::{Timer8, Timer8Setup}; + +mod timer8; + diff --git a/src/modules/timer/timer8.rs b/src/modules/timer/timer8.rs new file mode 100644 index 0000000..9d4679a --- /dev/null +++ b/src/modules/timer/timer8.rs @@ -0,0 +1,184 @@ +use {Bitset, Mask, Register}; +use core::marker; + +/// An 8-bit timer. +pub trait Timer8 { + /// 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 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 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, + PwmPhaseCorrect, + ClearOnTimerMatchOutputCompare, + FastPwm , + PwmPhaseCorrectOutputCompare, + FastPwmOutputCompare, +} + +impl WaveformGenerationMode { + /// Returns bits for TCCR0A, TCCR0B + #[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()), + PwmPhaseCorrect => (Mask::zero(), Mask::zero() | T::WGM0), + ClearOnTimerMatchOutputCompare => (Mask::zero(), T::WGM1 | Mask::zero()), + FastPwm => (Mask::zero(), T::WGM1 | T::WGM0), + // Reserved => (T::WGM2, Mask::zero() | Mask::zero()), + PwmPhaseCorrectOutputCompare => (T::WGM2, Mask::zero() | T::WGM0), + // Reserved => (T::WGM2, T::WGM1 | Mask::zero())), + FastPwmOutputCompare => (T::WGM2, T::WGM1 | T::WGM0), + }; + + (a, b) + } + + #[inline] + fn mask() -> (Mask, Mask) { + (!(T::WGM0 | T::WGM1), !(T::WGM2)) + } +} + +pub struct Timer8Setup { + a: Mask, + b: Mask, + output_compare_1: Option, + _phantom: marker::PhantomData, +} + +impl Timer8Setup { + #[inline] + pub fn new() -> Self { + Timer8Setup { + a: Mask::zero(), + b: 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); + + // Reset counter to zero + T::Counter::write(0); + + if let Some(v) = self.output_compare_1 { + // Set the match + T::CompareA::write(v); + + // Enable compare interrupt + T::OCIEA.set_all(); + } + } + } +} diff --git a/src/register.rs b/src/register.rs index f3a2c7f..c543e96 100644 --- a/src/register.rs +++ b/src/register.rs @@ -22,9 +22,9 @@ pub trait Register : Sized { /// Writes a value to the register. #[inline(always)] - fn write(value: T) { + fn write(value: V) where V: Into { unsafe { - *Self::ADDR = value; + *Self::ADDR = value.into(); } } @@ -182,6 +182,59 @@ impl Mask pub const fn new(mask: T) -> Self { Mask { mask, _phantom: marker::PhantomData } } + + pub fn zero() -> Self { + Mask::new(0u8.into()) + } +} + +impl ops::BitOr for Mask + where T: RegisterValue, R: Register +{ + type Output = Self; + + fn bitor(self, rhs: Self) -> Self { + Mask::new(self.mask | rhs.mask) + } +} + +impl ops::BitOrAssign for Mask + where T: RegisterValue, R: Register { + fn bitor_assign(&mut self, rhs: Self) { + self.mask |= rhs.mask; + } +} + +impl ops::BitAnd for Mask + where T: RegisterValue, R: Register +{ + type Output = Self; + + fn bitand(self, rhs: Self) -> Self { + Mask::new(self.mask & rhs.mask) + } +} + +impl ops::BitAndAssign for Mask + where T: RegisterValue, R: Register { + fn bitand_assign(&mut self, rhs: Self) { + self.mask &= rhs.mask; + } +} + +impl ops::Not for Mask + where T: RegisterValue, R: Register { + type Output = Self; + + fn not(self) -> Self { + Mask::new(!self.mask) + } +} + +impl Into for Mask where R: Register { + fn into(self) -> u8 { + self.mask + } } impl RegisterValue for u8 { } diff --git a/src/timer.rs b/src/timer.rs deleted file mode 100644 index 4793dde..0000000 --- a/src/timer.rs +++ /dev/null @@ -1,38 +0,0 @@ -use {Register}; - -/// An 8-bit timer. -pub trait Timer8 { - /// 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 interrupt mask register. - /// - /// For example, TIMSK0. - type InterruptMask: Register; - - /// The interrupt flag register. - /// - /// For example, TIFR0. - type InterruptFlag: Register; -} - diff --git a/src/timer0.rs b/src/timer0.rs deleted file mode 100644 index df6ab9f..0000000 --- a/src/timer0.rs +++ /dev/null @@ -1,141 +0,0 @@ -use core::prelude::v1::*; -use core::ptr::write_volatile; - -use super::*; - -use cores::atmega328p as c; - -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 | 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, - } - } - - #[inline] - fn mask() -> u8 { - !(CS02 | CS01 | CS00) - } -} - -pub enum WaveformGenerationMode { - Normal, - PwmPhaseCorrect, - ClearOnTimerMatchOutputCompare, - FastPwm , - PwmPhaseCorrectOutputCompare, - FastPwmOutputCompare, -} - -impl WaveformGenerationMode { - /// Returns bits for TCCR0A, TCCR0B - #[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), - 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) - } - - #[inline] - fn mask() -> (u8, u8) { - (!(WGM00 | WGM01), !(WGM02)) - } -} - -pub struct Timer { - a: u8, - b: u8, - output_compare_1: Option, -} - -impl Timer { - #[inline] - pub fn new() -> Self { - Timer { - a: 0, - b: 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 { - c::TCCR0A::write(self.a); - c::TCCR0B::write(self.b); - - // Reset counter to zero - c::TCNT0::write(0); - - if let Some(v) = self.output_compare_1 { - // Set the match - c::OCR0A::write(v); - - // Enable compare interrupt - c::TIMSK0::OCIE0A.set_all(); - } - } - } -}