More work done
This commit is contained in:
parent
1f638dbea3
commit
274d4611ec
62
build.rs
62
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, "//! Core for {}.", mcu.device.name)?;
|
||||||
writeln!(w)?;
|
writeln!(w)?;
|
||||||
writeln!(w, "use {{Mask, Bitset, HardwareUsart, Register}};")?;
|
writeln!(w, "use {{Mask, Bitset, HardwareUsart, Register}};")?;
|
||||||
writeln!(w, "use spi::HardwareSpi;")?;
|
writeln!(w, "use modules;")?;
|
||||||
writeln!(w)?;
|
writeln!(w)?;
|
||||||
|
|
||||||
gen::write_registers(mcu, w)?;
|
gen::write_registers(mcu, w)?;
|
||||||
gen::write_pins(mcu, w)?;
|
gen::write_pins(mcu, w)?;
|
||||||
gen::write_spi_modules(mcu, w)?;
|
gen::write_spi_modules(mcu, w)?;
|
||||||
gen::write_usarts(mcu, w)?;
|
gen::write_usarts(mcu, w)?;
|
||||||
|
gen::write_timers(mcu, w)?;
|
||||||
|
|
||||||
writeln!(w)
|
writeln!(w)
|
||||||
}
|
}
|
||||||
|
@ -105,18 +106,16 @@ mod gen {
|
||||||
|
|
||||||
// We create masks for the individual bits in the field if there
|
// We create masks for the individual bits in the field if there
|
||||||
// is more than one bit in the field.
|
// is more than one bit in the field.
|
||||||
if bitfield.mask.count_ones() > 1 {
|
let mut current_mask = bitfield.mask;
|
||||||
let mut current_mask = bitfield.mask;
|
let mut current_mask_bit_num = 0;
|
||||||
let mut current_mask_bit_num = 0;
|
for current_register_bit_num in 0..15 {
|
||||||
for current_register_bit_num in 0..15 {
|
if (current_mask & 0b1) == 0b1 {
|
||||||
if (current_mask & 0b1) == 0b1 {
|
writeln!(w, " pub const {}{}: Mask<{}, Self> = Mask::new(1<<{});",
|
||||||
writeln!(w, " pub const {}{}: Mask<{}, Self> = Mask::new(1<<{});",
|
bitfield.name, current_mask_bit_num, ty, current_register_bit_num)?;
|
||||||
bitfield.name, current_mask_bit_num, ty, current_register_bit_num)?;
|
current_mask_bit_num += 1;
|
||||||
current_mask_bit_num += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
current_mask >>= 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
current_mask >>= 1;
|
||||||
}
|
}
|
||||||
writeln!(w)?;
|
writeln!(w)?;
|
||||||
}
|
}
|
||||||
|
@ -181,7 +180,7 @@ mod gen {
|
||||||
|
|
||||||
writeln!(w, "pub struct Spi;")?;
|
writeln!(w, "pub struct Spi;")?;
|
||||||
writeln!(w)?;
|
writeln!(w)?;
|
||||||
writeln!(w, "impl HardwareSpi for Spi {{")?;
|
writeln!(w, "impl modules::HardwareSpi for Spi {{")?;
|
||||||
|
|
||||||
for spi_signal in peripheral.signals() {
|
for spi_signal in peripheral.signals() {
|
||||||
let spi_signal_name = spi_signal.group.clone().expect("spi signal does not have group name");
|
let spi_signal_name = spi_signal.group.clone().expect("spi signal does not have group name");
|
||||||
|
@ -243,6 +242,43 @@ mod gen {
|
||||||
Ok(())
|
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<u8, Self::ControlB> = Self::ControlB::CS00;")?;
|
||||||
|
writeln!(w, " const CS1: Mask<u8, Self::ControlB> = Self::ControlB::CS01;")?;
|
||||||
|
writeln!(w, " const CS2: Mask<u8, Self::ControlB> = Self::ControlB::CS02;")?;
|
||||||
|
writeln!(w, " const WGM0: Mask<u8, Self::ControlA> = Self::ControlA::WGM00;")?;
|
||||||
|
writeln!(w, " const WGM1: Mask<u8, Self::ControlA> = Self::ControlA::WGM01;")?;
|
||||||
|
writeln!(w, " const WGM2: Mask<u8, Self::ControlB> = Self::ControlB::WGM020;")?;
|
||||||
|
writeln!(w, " const OCIEA: Bitset<u8, Self::InterruptMask> = Self::InterruptMask::OCIE0A;")?;
|
||||||
|
writeln!(w, "}}")?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
/// Gets the name of a pin.
|
/// Gets the name of a pin.
|
||||||
fn pin_name(instance: &Instance, signal: &Signal) -> String {
|
fn pin_name(instance: &Instance, signal: &Signal) -> String {
|
||||||
let idx = signal.index.expect("signal with no index");
|
let idx = signal.index.expect("signal with no index");
|
||||||
|
|
|
@ -15,22 +15,19 @@
|
||||||
|
|
||||||
pub use self::register::{Bitset, Mask, Register, RegisterValue};
|
pub use self::register::{Bitset, Mask, Register, RegisterValue};
|
||||||
pub use self::pin::Pin;
|
pub use self::pin::Pin;
|
||||||
pub use self::timer::Timer8;
|
|
||||||
pub use self::usart::HardwareUsart;
|
pub use self::usart::HardwareUsart;
|
||||||
|
|
||||||
pub mod prelude;
|
pub mod prelude;
|
||||||
pub mod serial;
|
pub mod serial;
|
||||||
pub mod timer0;
|
|
||||||
pub mod timer1;
|
pub mod timer1;
|
||||||
pub mod cores;
|
pub mod cores;
|
||||||
|
pub mod modules;
|
||||||
|
|
||||||
pub mod spi;
|
|
||||||
pub mod config;
|
pub mod config;
|
||||||
|
|
||||||
mod register;
|
mod register;
|
||||||
mod pin;
|
mod pin;
|
||||||
mod usart;
|
mod usart;
|
||||||
mod timer;
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub mod std_stub;
|
pub mod std_stub;
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -60,80 +60,80 @@ pub trait HardwareSpi {
|
||||||
/// Enables interrupts for the spi module.
|
/// Enables interrupts for the spi module.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn enable_interrupt() {
|
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.
|
/// Disables interrupts for the spi module.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn disable_interrupt() {
|
fn disable_interrupt() {
|
||||||
Self::ControlRegister::unset_raw(control_register::INTERRUPT_ENABLE);
|
Self::ControlRegister::unset_raw(settings::control_register::INTERRUPT_ENABLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Enables the SPI.
|
/// Enables the SPI.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn enable() {
|
fn enable() {
|
||||||
Self::ControlRegister::set_raw(control_register::ENABLE);
|
Self::ControlRegister::set_raw(settings::control_register::ENABLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Disables the SPI.
|
/// Disables the SPI.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn disable() {
|
fn disable() {
|
||||||
Self::ControlRegister::unset_raw(control_register::ENABLE);
|
Self::ControlRegister::unset_raw(settings::control_register::ENABLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Enables least-significant-bit first.
|
/// Enables least-significant-bit first.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn set_lsb() {
|
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.
|
/// Enables most-significant-bit first.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn set_msb() {
|
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.
|
/// Enables master mode.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn set_master() {
|
fn set_master() {
|
||||||
Self::ControlRegister::set_raw(control_register::MASTER);
|
Self::ControlRegister::set_raw(settings::control_register::MASTER);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Enables slave mode.
|
/// Enables slave mode.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn set_slave() {
|
fn set_slave() {
|
||||||
Self::ControlRegister::unset_raw(control_register::MASTER);
|
Self::ControlRegister::unset_raw(settings::control_register::MASTER);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Enables double speed mode.
|
/// Enables double speed mode.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn enable_double_speed() {
|
fn enable_double_speed() {
|
||||||
Self::StatusRegister::set_raw(status_register::SPI2X);
|
Self::StatusRegister::set_raw(settings::status_register::SPI2X);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Disables double speed mode.
|
/// Disables double speed mode.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn disable_double_speed() {
|
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.
|
/// Checks if there is a write collision.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn is_write_collision() -> bool {
|
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.
|
/// Sends a byte through the serial.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn send_byte(byte: u8) {
|
fn send_byte(byte: u8) {
|
||||||
Self::DataRegister::write(byte);
|
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.
|
/// Reads a byte from the serial.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn receive_byte() -> u8 {
|
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()
|
Self::DataRegister::read()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -141,34 +141,8 @@ pub trait HardwareSpi {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn send_receive(byte: u8) -> u8 {
|
fn send_receive(byte: u8) -> u8 {
|
||||||
Self::DataRegister::write(byte);
|
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()
|
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;
|
|
||||||
}
|
|
||||||
|
|
|
@ -96,6 +96,7 @@ impl Default for Settings {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Constants for the control register.
|
/// Constants for the control register.
|
||||||
|
#[allow(dead_code)]
|
||||||
pub mod control_register {
|
pub mod control_register {
|
||||||
/// Set if interrupts are enabled.
|
/// Set if interrupts are enabled.
|
||||||
pub const INTERRUPT_ENABLE: u8 = 1<<7;
|
pub const INTERRUPT_ENABLE: u8 = 1<<7;
|
||||||
|
@ -116,6 +117,7 @@ pub mod control_register {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Constants for the status register.
|
/// Constants for the status register.
|
||||||
|
#[allow(dead_code)]
|
||||||
pub mod status_register {
|
pub mod status_register {
|
||||||
/// SPI interrupt flag.
|
/// SPI interrupt flag.
|
||||||
pub const SPIF: u8 = 1<<7;
|
pub const SPIF: u8 = 1<<7;
|
|
@ -0,0 +1,4 @@
|
||||||
|
pub use self::timer8::{Timer8, Timer8Setup};
|
||||||
|
|
||||||
|
mod timer8;
|
||||||
|
|
|
@ -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<u8>;
|
||||||
|
|
||||||
|
/// The second compare register.
|
||||||
|
/// For example, OCR0B.
|
||||||
|
type CompareB: Register<u8>;
|
||||||
|
|
||||||
|
/// The counter register.
|
||||||
|
///
|
||||||
|
/// For example, TCNT0.
|
||||||
|
type Counter: Register<u8>;
|
||||||
|
|
||||||
|
/// The first control register.
|
||||||
|
///
|
||||||
|
/// For example, TCCR0A.
|
||||||
|
type ControlA: Register<u8>;
|
||||||
|
|
||||||
|
/// The second control register.
|
||||||
|
///
|
||||||
|
/// For example, TCCR0B.
|
||||||
|
type ControlB: Register<u8>;
|
||||||
|
|
||||||
|
/// The interrupt mask register.
|
||||||
|
///
|
||||||
|
/// For example, TIMSK0.
|
||||||
|
type InterruptMask: Register<u8>;
|
||||||
|
|
||||||
|
/// The interrupt flag register.
|
||||||
|
///
|
||||||
|
/// For example, TIFR0.
|
||||||
|
type InterruptFlag: Register<u8>;
|
||||||
|
|
||||||
|
const CS0: Mask<u8, Self::ControlB>;
|
||||||
|
const CS1: Mask<u8, Self::ControlB>;
|
||||||
|
const CS2: Mask<u8, Self::ControlB>;
|
||||||
|
|
||||||
|
const WGM0: Mask<u8, Self::ControlA>;
|
||||||
|
const WGM1: Mask<u8, Self::ControlA>;
|
||||||
|
const WGM2: Mask<u8, Self::ControlB>;
|
||||||
|
|
||||||
|
const OCIEA: Bitset<u8, Self::InterruptMask>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum ClockSource {
|
||||||
|
None,
|
||||||
|
Prescale1,
|
||||||
|
Prescale8,
|
||||||
|
Prescale64,
|
||||||
|
Prescale256,
|
||||||
|
Prescale1024,
|
||||||
|
ExternalFalling,
|
||||||
|
ExternalRising,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ClockSource {
|
||||||
|
fn bits<T: Timer8>(&self) -> Mask<u8, T::ControlB> {
|
||||||
|
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<T: Timer8>() -> Mask<u8, T::ControlB> {
|
||||||
|
!(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<T: Timer8>(&self) -> (Mask<u8, T::ControlA>, Mask<u8, T::ControlB>) {
|
||||||
|
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<T: Timer8>() -> (Mask<u8, T::ControlA>, Mask<u8, T::ControlB>) {
|
||||||
|
(!(T::WGM0 | T::WGM1), !(T::WGM2))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Timer8Setup<T: Timer8> {
|
||||||
|
a: Mask<u8, T::ControlA>,
|
||||||
|
b: Mask<u8, T::ControlB>,
|
||||||
|
output_compare_1: Option<u8>,
|
||||||
|
_phantom: marker::PhantomData<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Timer8> Timer8Setup<T> {
|
||||||
|
#[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::<T>();
|
||||||
|
self.b |= source.bits::<T>();
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn waveform_generation_mode(mut self, mode: WaveformGenerationMode) -> Self {
|
||||||
|
let (a, b) = WaveformGenerationMode::mask::<T>();
|
||||||
|
self.a &= a;
|
||||||
|
self.b &= b;
|
||||||
|
|
||||||
|
let (a, b) = mode.bits::<T>();
|
||||||
|
self.a |= a;
|
||||||
|
self.b |= b;
|
||||||
|
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn output_compare_1(mut self, value: Option<u8>) -> 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -22,9 +22,9 @@ pub trait Register<T: RegisterValue> : Sized {
|
||||||
|
|
||||||
/// Writes a value to the register.
|
/// Writes a value to the register.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn write(value: T) {
|
fn write<V>(value: V) where V: Into<T> {
|
||||||
unsafe {
|
unsafe {
|
||||||
*Self::ADDR = value;
|
*Self::ADDR = value.into();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -182,6 +182,59 @@ impl<T,R> Mask<T,R>
|
||||||
pub const fn new(mask: T) -> Self {
|
pub const fn new(mask: T) -> Self {
|
||||||
Mask { mask, _phantom: marker::PhantomData }
|
Mask { mask, _phantom: marker::PhantomData }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn zero() -> Self {
|
||||||
|
Mask::new(0u8.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T,R> ops::BitOr for Mask<T,R>
|
||||||
|
where T: RegisterValue, R: Register<T>
|
||||||
|
{
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn bitor(self, rhs: Self) -> Self {
|
||||||
|
Mask::new(self.mask | rhs.mask)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T,R> ops::BitOrAssign for Mask<T,R>
|
||||||
|
where T: RegisterValue, R: Register<T> {
|
||||||
|
fn bitor_assign(&mut self, rhs: Self) {
|
||||||
|
self.mask |= rhs.mask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T,R> ops::BitAnd for Mask<T,R>
|
||||||
|
where T: RegisterValue, R: Register<T>
|
||||||
|
{
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn bitand(self, rhs: Self) -> Self {
|
||||||
|
Mask::new(self.mask & rhs.mask)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T,R> ops::BitAndAssign for Mask<T,R>
|
||||||
|
where T: RegisterValue, R: Register<T> {
|
||||||
|
fn bitand_assign(&mut self, rhs: Self) {
|
||||||
|
self.mask &= rhs.mask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T,R> ops::Not for Mask<T,R>
|
||||||
|
where T: RegisterValue, R: Register<T> {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn not(self) -> Self {
|
||||||
|
Mask::new(!self.mask)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<R> Into<u8> for Mask<u8,R> where R: Register<u8> {
|
||||||
|
fn into(self) -> u8 {
|
||||||
|
self.mask
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RegisterValue for u8 { }
|
impl RegisterValue for u8 { }
|
||||||
|
|
38
src/timer.rs
38
src/timer.rs
|
@ -1,38 +0,0 @@
|
||||||
use {Register};
|
|
||||||
|
|
||||||
/// An 8-bit timer.
|
|
||||||
pub trait Timer8 {
|
|
||||||
/// The first compare register.
|
|
||||||
/// For example, OCR0A.
|
|
||||||
type CompareA: Register<u8>;
|
|
||||||
|
|
||||||
/// The second compare register.
|
|
||||||
/// For example, OCR0B.
|
|
||||||
type CompareB: Register<u8>;
|
|
||||||
|
|
||||||
/// The counter register.
|
|
||||||
///
|
|
||||||
/// For example, TCNT0.
|
|
||||||
type Counter: Register<u8>;
|
|
||||||
|
|
||||||
/// The first control register.
|
|
||||||
///
|
|
||||||
/// For example, TCCR0A.
|
|
||||||
type ControlA: Register<u8>;
|
|
||||||
|
|
||||||
/// The second control register.
|
|
||||||
///
|
|
||||||
/// For example, TCCR0B.
|
|
||||||
type ControlB: Register<u8>;
|
|
||||||
|
|
||||||
/// The interrupt mask register.
|
|
||||||
///
|
|
||||||
/// For example, TIMSK0.
|
|
||||||
type InterruptMask: Register<u8>;
|
|
||||||
|
|
||||||
/// The interrupt flag register.
|
|
||||||
///
|
|
||||||
/// For example, TIFR0.
|
|
||||||
type InterruptFlag: Register<u8>;
|
|
||||||
}
|
|
||||||
|
|
141
src/timer0.rs
141
src/timer0.rs
|
@ -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<u8>,
|
|
||||||
}
|
|
||||||
|
|
||||||
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<u8>) -> 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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue