Merge pull request #4 from dylanmckay/pin-support

WIP: Support for autogenerated mcu cores
This commit is contained in:
Dylan McKay 2018-11-05 23:42:09 +13:00 committed by GitHub
commit 7a8572e094
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
27 changed files with 1574 additions and 678 deletions

View File

@ -4,11 +4,20 @@ version = "0.1.1"
authors = [ authors = [
"The AVR-Rust Project Developers", "The AVR-Rust Project Developers",
"Jake Goulding <jake.goulding@gmail.com>", "Jake Goulding <jake.goulding@gmail.com>",
"Dylan McKay <me@dylanmckay.io>",
] ]
license = "MIT/Apache-2.0" license = "MIT/Apache-2.0"
readme = "README.md" readme = "README.md"
repository = "https://github.com/avr-rust/ruduino" repository = "https://github.com/avr-rust/ruduino"
description = """ description = """
Reusable components for the Arduino Uno. Reusable components for AVR microcontrollers
""" """
build = "core_generator/build.rs"
keywords = ["avr", "arduino", "uno"] keywords = ["avr", "arduino", "uno"]
[build-dependencies]
avr-mcu = "0.2"

97
core_generator/build.rs Normal file
View File

@ -0,0 +1,97 @@
extern crate avr_mcu;
mod gen;
use avr_mcu::*;
use std::fs::{self, File};
use std::io;
use std::io::prelude::*;
use std::path::{Path, PathBuf};
/// The MCU that will be assumed when running 'cargo doc' targeting
/// archicectures that are not AVR.
const DEFAULT_MCU_FOR_NON_AVR_DOCS: &'static str = "atmega328";
fn src_path() -> PathBuf {
Path::new(env!("CARGO_MANIFEST_DIR")).join("src")
}
fn cores_path() -> PathBuf {
src_path().join("cores")
}
fn core_module_name(mcu: &Mcu) -> String {
mcu.device.name.to_lowercase().to_owned()
}
fn main() {
if !cores_path().exists() {
fs::create_dir_all(&cores_path()).expect("could not create cores directory");
}
let current_mcu = if cfg!(arch = "avr") {
avr_mcu::current::mcu()
.expect("no target cpu specified")
} else {
avr_mcu::microcontroller(DEFAULT_MCU_FOR_NON_AVR_DOCS)
};
generate_config_module().unwrap();
generate_cores(&[current_mcu]).unwrap();
}
fn generate_cores(mcus: &[Mcu]) -> Result<(), io::Error> {
for mcu in mcus {
generate_core_module(mcu).expect("failed to generate mcu core");
}
generate_cores_mod_rs(mcus)
}
fn generate_config_module() -> Result<(), io::Error> {
let path = src_path().join("config.rs");
let mut f = File::create(&path)?;
let clock = env!("AVR_CPU_FREQUENCY_HZ");
writeln!(f, "/// The clock frequency of device being targeted in Hertz.")?;
writeln!(f, "pub const CPU_FREQUENCY_HZ: u32 = {};", clock)?;
Ok(())
}
fn generate_core_module(mcu: &Mcu) -> Result<(), io::Error> {
let path = cores_path().join(format!("{}.rs", core_module_name(mcu)));
let mut file = File::create(&path)?;
write_core_module(mcu, &mut file)
}
fn generate_cores_mod_rs(mcus: &[Mcu]) -> Result<(), io::Error> {
let path = cores_path().join("mod.rs");
let mut w = File::create(&path)?;
writeln!(w)?;
for mcu in mcus {
let module_name = core_module_name(mcu);
writeln!(w, "/// The {}.", mcu.device.name)?;
writeln!(w, "pub mod {};", module_name)?;
writeln!(w, "#[cfg(all(target_arch = \"avr\", target_cpu = \"{}\"))]", module_name)?;
writeln!(w, "pub use self::{} as current;", module_name)?;
}
writeln!(w)
}
fn write_core_module(mcu: &Mcu, w: &mut Write) -> Result<(), io::Error> {
writeln!(w, "//! Core for {}.", mcu.device.name)?;
writeln!(w)?;
writeln!(w, "use {{RegisterBits, Register}};")?;
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)
}

240
core_generator/gen.rs Normal file
View File

@ -0,0 +1,240 @@
use avr_mcu::*;
use std::io;
use std::io::prelude::*;
pub fn write_registers(mcu: &Mcu, w: &mut Write) -> Result<(), io::Error> {
for register in mcu.registers() {
let ty = if register.size == 1 { "u8" } else { "u16" };
// HACK: Skip, atmeg328p pack defines two of these.
if register.name == "GTCCR" { continue; }
writeln!(w, "pub struct {};", register.name)?;
writeln!(w)?;
writeln!(w, "impl {} {{", register.name)?;
for bitfield in register.bitfields.iter() {
// Create a mask for the whole bitset.
writeln!(w, " pub const {}: RegisterBits<Self> = RegisterBits::new(0x{:x});", bitfield.name, bitfield.mask)?;
// We create masks for the individual bits in the field if there
// is more than one bit in the field.
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 {}{}: RegisterBits<Self> = RegisterBits::new(1<<{});",
bitfield.name, current_mask_bit_num, current_register_bit_num)?;
current_mask_bit_num += 1;
}
current_mask >>= 1;
}
writeln!(w)?;
}
writeln!(w, "}}")?;
writeln!(w)?;
writeln!(w, "impl Register for {} {{", register.name)?;
writeln!(w, " type T = {};", ty)?;
writeln!(w, " const ADDRESS: *mut {} = 0x{:x} as *mut {};", ty, register.offset, ty)?;
writeln!(w, "}}")?;
}
Ok(())
}
pub fn write_pins(mcu: &Mcu, w: &mut Write) -> Result<(), io::Error> {
if let Some(port) = mcu.peripheral("PORT") {
writeln!(w, "pub mod port {{")?;
writeln!(w, " use super::*;")?;
writeln!(w, " use Pin;")?;
writeln!(w)?;
for instance in port.instances.iter() {
let port_letter = instance.name.chars().rev().next().unwrap();
for signal in instance.signals.iter() {
let idx = signal.index.expect("signal with no index");
let struct_name = format!("{}{}", port_letter, idx);
let io_module = mcu.modules.iter().find(|m| m.name == "PORT")
.expect("no port io module defined for this port");
let register_group = io_module.register_groups.iter()
.find(|rg| rg.name == instance.name)
.expect("no register group defined for this port");
writeln!(w, " pub struct {};", struct_name)?;
writeln!(w)?;
writeln!(w, " impl Pin for {} {{", struct_name)?;
for reg in register_group.registers.iter() {
let mut const_name = reg.name.clone();
const_name.pop(); // Pop port character from register name (DDRB/PORTB/etc)..
writeln!(w, " /// {}.", reg.caption)?;
writeln!(w, " type {} = {};", const_name, reg.name)?;
}
writeln!(w, " /// {}", signal.pad)?;
writeln!(w, " const MASK: u8 = 1<<{};", idx)?;
writeln!(w, " }}")?;
writeln!(w)?;
}
}
writeln!(w, "}}")?;
writeln!(w)?;
}
Ok(())
}
pub fn write_spi_modules(mcu: &Mcu, w: &mut Write) -> Result<(), io::Error> {
if let Some(module) = mcu.module("SPI") {
let peripheral = mcu.peripheral("SPI").expect("found SPI module but no peripheral");
let port_peripheral = mcu.port_peripheral();
writeln!(w, "pub struct Spi;")?;
writeln!(w)?;
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");
let (port_instance, port_signal) = port_peripheral.instance_signal_with_pad(&spi_signal.pad)
.expect("no port signal associated with the spi signal pad");
let pin_name = self::pin_name(port_instance, port_signal);
let const_name = match &spi_signal_name[..] {
"MISO" => "MasterInSlaveOut",
"MOSI" => "MasterOutSlaveIn",
"SCK" => "Clock",
"SS" => "SlaveSelect",
_ => panic!("unknown spi signal name: '{}'", spi_signal_name),
};
writeln!(w, " type {} = {};", const_name, pin_name)?;
}
for reg in module.registers() {
let const_name = match &reg.caption[..] {
"SPI Data Register" => "DataRegister",
"SPI Status Register" => "StatusRegister",
"SPI Control Register" => "ControlRegister",
_ => panic!("unknown SPI module register: {}", reg.caption),
};
writeln!(w, " type {} = {};", const_name, reg.name)?;
}
writeln!(w, "}}")?;
writeln!(w)?;
}
Ok(())
}
pub fn write_usarts(mcu: &Mcu, w: &mut Write) -> Result<(), io::Error> {
if let Some(module) = mcu.module("USART") {
for usart in module.register_groups.iter() {
writeln!(w, "/// The {} module.", usart.name)?;
writeln!(w, "pub struct {};", usart.name)?;
writeln!(w)?;
writeln!(w, "impl modules::HardwareUsart for {} {{", usart.name)?;
for register in usart.registers.iter() {
let reg_ty = if register.name.starts_with("UDR") { // the data register.
"DataRegister".to_owned()
} else if register.name.starts_with("UCSR") { // one of the three control/status registers.
let suffix = register.name.chars().rev().next().unwrap();
format!("ControlRegister{}", suffix)
} else if register.name.starts_with("UBRR") { // the baud rate register.
"BaudRateRegister".to_owned()
} else {
panic!("unknown usart register '{}'", register.name);
};
writeln!(w, " type {} = {};", reg_ty, register.name)?;
}
writeln!(w, "}}")?;
writeln!(w)?;
}
}
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))
};
let timer_number = find_reg("TIMSK").name.chars().last().unwrap()
.to_digit(10).unwrap();
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: RegisterBits<Self::ControlB> = Self::ControlB::CS00;")?;
writeln!(w, " const CS1: RegisterBits<Self::ControlB> = Self::ControlB::CS01;")?;
writeln!(w, " const CS2: RegisterBits<Self::ControlB> = Self::ControlB::CS02;")?;
writeln!(w, " const WGM0: RegisterBits<Self::ControlA> = Self::ControlA::WGM00;")?;
writeln!(w, " const WGM1: RegisterBits<Self::ControlA> = Self::ControlA::WGM01;")?;
writeln!(w, " const WGM2: RegisterBits<Self::ControlB> = Self::ControlB::WGM020;")?;
writeln!(w, " const OCIEA: RegisterBits<Self::InterruptMask> = Self::InterruptMask::OCIE{}A;", timer_number)?;
writeln!(w, "}}")?;
}
if let Some(tc) = mcu.module("TC16") { // Timer/Counter, 16-bit.
const TYPE_NAME: &'static str = "Timer16";
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))
};
let timer_number = find_reg("TIMSK").name.chars().last().unwrap()
.to_digit(10).unwrap();
writeln!(w, "/// 16-bit timer.")?;
writeln!(w, "pub struct {};", TYPE_NAME)?;
writeln!(w)?;
writeln!(w, "impl modules::Timer16 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 ControlC = {};", find_reg_suffix("TCCR", "C").name)?;
writeln!(w, " type InterruptMask = {};", find_reg("TIMSK").name)?;
writeln!(w, " type InterruptFlag = {};", find_reg("TIFR").name)?;
writeln!(w, " const CS0: RegisterBits<Self::ControlB> = Self::ControlB::CS10;")?;
writeln!(w, " const CS1: RegisterBits<Self::ControlB> = Self::ControlB::CS11;")?;
writeln!(w, " const CS2: RegisterBits<Self::ControlB> = Self::ControlB::CS12;")?;
writeln!(w, " const WGM0: RegisterBits<Self::ControlA> = Self::ControlA::WGM10;")?;
writeln!(w, " const WGM1: RegisterBits<Self::ControlA> = Self::ControlA::WGM11;")?;
writeln!(w, " const WGM2: RegisterBits<Self::ControlB> = Self::ControlB::WGM10;")?;
writeln!(w, " const WGM3: RegisterBits<Self::ControlB> = Self::ControlB::WGM11;")?;
writeln!(w, " const OCIEA: RegisterBits<Self::InterruptMask> = Self::InterruptMask::OCIE{}A;", timer_number)?;
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");
let letter = instance.name.chars().rev().next().unwrap();
format!("port::{}{}", letter, idx)
}

14
examples/spi.rs Normal file
View File

@ -0,0 +1,14 @@
#![no_std]
#![no_main]
extern crate arduino;
use arduino::cores::current;
// Some devices may have multiple SPI modules.
// The ATmega328p only has one.
type Spi = current::Spi;
#[no_mangle]
pub extern fn main() {
}

2
src/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
# Generated automatically.
config.rs

1
src/cores/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
*.rs

0
src/cores/.gitkeep Normal file
View File

35
src/interrupt.rs Normal file
View File

@ -0,0 +1,35 @@
//! Routines for managing interrupts.
use core::prelude::v1::*;
use core::marker::PhantomData;
/// Helper struct that automatically restores interrupts
/// on drop.
struct DisableInterrupts(PhantomData<()>);
/// Executes a closure, disabling interrupts until its completion.
///
/// Restores interrupts after the closure has completed
/// execution.
pub fn without_interrupts<F, T>(f: F) -> T
where F: FnOnce() -> T
{
let _disabled = DisableInterrupts::new();
f()
}
impl DisableInterrupts {
#[inline]
pub fn new() -> DisableInterrupts {
unsafe { asm!("CLI") }
DisableInterrupts(PhantomData)
}
}
impl Drop for DisableInterrupts {
#[inline]
fn drop(&mut self) {
unsafe { asm!("SEI") }
}
}

View File

@ -1,5 +0,0 @@
pub mod port;
pub const PORT_B: port::Port<port::B> = port::Port::new();
pub const PORT_C: port::Port<port::C> = port::Port::new();
pub const PORT_D: port::Port<port::D> = port::Port::new();

View File

@ -1,183 +0,0 @@
use core::prelude::v1::*;
use core::ptr::{read_volatile, write_volatile};
use core::marker::PhantomData;
use Bit;
pub trait Information {
const DDR: *mut u8;
const IO: *mut u8;
const PIN: *mut u8;
}
#[derive(Copy, Clone)]
pub struct B;
impl Information for B {
const DDR: *mut u8 = ::DDRB;
const IO: *mut u8 = ::PORTB;
const PIN: *mut u8 = ::PINB;
}
#[derive(Copy, Clone)]
pub struct C;
impl Information for C {
const DDR: *mut u8 = ::DDRC;
const IO: *mut u8 = ::PORTC;
const PIN: *mut u8 = ::PINC;
}
#[derive(Copy, Clone)]
pub struct D;
impl Information for D {
const DDR: *mut u8 = ::DDRD;
const IO: *mut u8 = ::PORTD;
const PIN: *mut u8 = ::PIND;
}
#[derive(Copy, Clone)]
enum Direction {
Output,
Input,
}
const BITS_IN_BYTE: usize = 8;
pub struct Configuration<P: Information> {
_port: PhantomData<P>,
direction: [Option<Direction>; BITS_IN_BYTE],
pullup: [Option<bool>; BITS_IN_BYTE],
}
impl<P> Configuration<P>
where
P: Information
{
#[inline]
pub fn new() -> Configuration<P> {
Configuration {
_port: PhantomData,
direction: Default::default(),
pullup: Default::default(),
}
}
#[inline]
pub fn set_all_as_output(&mut self) -> &mut Self {
self.direction = [Some(Direction::Output); 8];
self
}
#[inline]
pub fn set_all_as_input(&mut self) -> &mut Self {
self.direction = [Some(Direction::Input); 8];
self
}
#[inline]
pub fn set_as_output(&mut self, bit: Bit) -> &mut Self {
self.direction[bit as usize] = Some(Direction::Output);
self
}
#[inline]
pub fn set_as_input(&mut self, bit: Bit) -> &mut Self {
self.direction[bit as usize] = Some(Direction::Input);
self
}
#[inline]
pub fn enable_pullup(&mut self, bit: Bit) -> &mut Self {
self.pullup[bit as usize] = Some(true);
self
}
#[inline]
pub fn disable_pullup(&mut self, bit: Bit) -> &mut Self {
self.pullup[bit as usize] = Some(false);
self
}
#[inline]
pub fn configure(&self) {
// FIXME: Both of these loops are wasteful if we are
// setting all 8 bits, when we could set the entire IO
// register at once. Is there a way we can track that?
// We use `zip` instead of `enumerate` to guarantee it's a constant
for (&p, i) in self.direction.iter().zip(0..BITS_IN_BYTE) {
if let Some(enabled) = p {
if let Direction::Output = enabled {
unsafe { asm!("sbi $0 $1" : : "n"(P::DDR), "n"(i)) }
} else {
unsafe { asm!("cbi $0 $1; A" : : "n"(P::DDR), "n"(i)) }
}
}
}
for (&p, i) in self.pullup.iter().zip(0..BITS_IN_BYTE) {
if let Some(enabled) = p {
if enabled {
unsafe { asm!("sbi $0 $1" : : "n"(P::IO), "n"(i)) }
} else {
unsafe { asm!("cbi $0 $1; B" : : "n"(P::IO), "n"(i)) }
}
}
}
}
}
#[derive(Copy, Clone)]
pub struct Data<P: Information> {
_port: PhantomData<P>,
}
impl<P> Data<P>
where
P: Information
{
#[inline]
pub fn new() -> Data<P> { Data { _port: PhantomData } }
#[inline]
pub fn get(&self) -> u8 {
unsafe { read_volatile(P::PIN) }
}
#[inline]
pub fn set(&self, value: u8) {
unsafe { write_volatile(P::IO, value) };
}
#[inline]
pub fn bit_is_set(&self, bit: Bit) -> bool {
bit.is_set(self.get())
}
#[inline]
pub fn set_bit(&self, bit: Bit) {
unsafe { asm!("sbi $0 $1" : : "n"(P::IO), "n"(bit as u8)) }
}
#[inline]
pub fn clear_bit(&self, bit: Bit) {
unsafe { asm!("cbi $0 $1; C" : : "n"(P::IO), "n"(bit as u8)) }
}
#[inline]
pub fn toggle_bit(&self, bit: Bit) {
unsafe { asm!("sbi $0 $1" : : "n"(P::PIN), "n"(bit as u8)) }
}
}
#[derive(Copy, Clone)]
pub struct Port<P>(PhantomData<P>);
impl<P: Information> Port<P> {
pub(crate) const fn new() -> Port<P> { Port(PhantomData) }
pub fn configuration(&self) -> Configuration<P> { Configuration::new() }
pub fn data(&self) -> Data<P> { Data::new() }
}

10
src/legacy/mod.rs Normal file
View File

@ -0,0 +1,10 @@
//! Legacy code.
//!
//! The code in here needs to be cleaned up and rewritten to use
//! the new core-based API.
//!
//! Once a replacement exists, these legacy modules may be removed
//! in a major release!
pub mod serial;

View File

@ -1,8 +1,10 @@
//! A serial.
//!
//! *WARNING* The current implementation of this will only work on ATmega328.
use core::prelude::v1::*; use core::prelude::v1::*;
use core::ptr::{read_volatile, write_volatile}; use core::ptr::{read_volatile, write_volatile};
use super::*;
pub enum CharacterSize { pub enum CharacterSize {
FiveBits, FiveBits,
SixBits, SixBits,
@ -107,6 +109,8 @@ impl StopBits {
} }
} }
/// A serial connection.
/// *WARNING* The current implementation of this will only work on ATmega328.
pub struct Serial { pub struct Serial {
ubrr: u16, ubrr: u16,
a: u8, a: u8,
@ -224,3 +228,41 @@ pub fn try_receive() -> Option<u8> {
None None
} }
} }
// Dirty hack.
// We should write this out and use the neat build-script method instead.
use self::hack::*;
mod hack {
macro_rules! bit {
(-, $pos:expr) => {};
($name:ident, $pos:expr) => {
pub const $name: u8 = 1 << $pos;
};
}
macro_rules! register {
($address:expr, $name:ident, [$b7:tt, $b6:tt, $b5:tt, $b4:tt, $b3:tt, $b2:tt, $b1:tt, $b0:tt]) => {
register!($address, $name);
bit!($b7, 7);
bit!($b6, 6);
bit!($b5, 5);
bit!($b4, 4);
bit!($b3, 3);
bit!($b2, 2);
bit!($b1, 1);
bit!($b0, 0);
};
($address:expr, $name:ident) => {
pub const $name: *mut u8 = $address as *mut u8;
};
}
register!(0xC6, UDR0);
register!(0xC4, UBRR0L);
register!(0xC2, UCSR0C, [UMSEL01, UMSEL00, UPM01, UPM00, USBS0, UCSZ01, UCSZ00, - ]);
register!(0xC1, UCSR0B, [-, -, -, RXEN0, TXEN0, UCSZ02, -, - ]);
register!(0xC0, UCSR0A, [RXC0, -, UDRE0, -, -, -, -, - ]);
// 16-bit register pairs
pub const UBRR0: *mut u16 = UBRR0L as *mut u16;
}

View File

@ -1,174 +1,29 @@
//! Definitions of register addresses and bits within those registers //! Definitions of register addresses and bits within those registers
#![feature(asm)] #![feature(asm)]
#![feature(no_core)]
#![feature(const_fn)] #![feature(const_fn)]
#![feature(associated_type_defaults)]
#![feature(lang_items)]
#![feature(panic_handler)]
#![feature(unwind_attributes)]
#![no_core] #![no_std]
extern crate core; pub use self::register::{Register, RegisterBits, RegisterValue};
pub use self::pin::{DataDirection, Pin};
// Look like we have a standard library
#[allow(unused_imports)]
use core::{option, iter, fmt, ops, clone, marker};
pub mod prelude; pub mod prelude;
pub mod timer0; pub mod legacy;
pub mod timer1; /// Low level register-based API for device-specific operations.
pub mod serial; pub mod cores;
pub mod io; pub mod interrupt;
pub mod modules;
#[derive(Copy, Clone)] /// Configuration for the currently-targeted microcontroller.
pub enum Bit { pub mod config;
Bit0 = 0,
Bit1 = 1,
Bit2 = 2,
Bit3 = 3,
Bit4 = 4,
Bit5 = 5,
Bit6 = 6,
Bit7 = 7,
}
impl Bit { mod register;
fn as_mask(&self) -> u8 { 1 << *self as u8 } mod pin;
#[doc(hidden)]
pub mod std_stub;
pub fn is_set(&self, value: u8) -> bool {
(value & self.as_mask()) != 0
}
pub fn set(&self, value: u8) -> u8 {
value | self.as_mask()
}
pub fn unset(&self, value: u8) -> u8 {
value & !self.as_mask()
}
}
macro_rules! bit {
(-, $pos:expr) => {};
($name:ident, $pos:expr) => {
pub const $name: u8 = 1 << $pos;
};
}
macro_rules! register {
($address:expr, $name:ident, [$b7:tt, $b6:tt, $b5:tt, $b4:tt, $b3:tt, $b2:tt, $b1:tt, $b0:tt]) => {
register!($address, $name);
bit!($b7, 7);
bit!($b6, 6);
bit!($b5, 5);
bit!($b4, 4);
bit!($b3, 3);
bit!($b2, 2);
bit!($b1, 1);
bit!($b0, 0);
};
($address:expr, $name:ident) => {
pub const $name: *mut u8 = $address as *mut u8;
};
}
register!(0xC6, UDR0 );
register!(0xC5, UBRR0H );
register!(0xC4, UBRR0L );
register!(0xC2, UCSR0C, [UMSEL01, UMSEL00, UPM01, UPM00, USBS0, UCSZ01, UCSZ00, UCPOL0 ]);
register!(0xC1, UCSR0B, [RXCIE0, TXCIE0, UDRIE0, RXEN0, TXEN0, UCSZ02, RXB80, TXB80 ]);
register!(0xC0, UCSR0A, [RXC0, TXC0, UDRE0, FE0, DOR0, UPE0, U2X0, MPCM0 ]);
register!(0xBD, TWAMR, [TWAM6, TWAM5, TWAM4, TWAM3, TWAM2, TWAM1, TWAM0, - ]);
register!(0xBC, TWCR, [TWINT, TWEA, TWSTA, TWSTO, TWWC, TWEN, -, TWIE ]);
register!(0xBB, TWDR );
register!(0xBA, TWAR, [TWA6, TWA5, TWA4, TWA3, TWA2, TWA1, TWA0, TWGCE ]);
register!(0xB9, TWSR, [TWS7, TWS6, TWS5, TWS4, TWS3, -, TWPS1, TWPS0 ]);
register!(0xB8, TWBR );
register!(0xB6, ASSR, [-, EXCLK, AS2, TCN2UB, OCR2AUB, OCR2BUB, TCR2AUB, TCR2BUB]);
register!(0xB4, OCR2B );
register!(0xB3, OCR2A );
register!(0xB2, TCNT2 );
register!(0xB1, TCCR2B, [FOC2A, FOC2B, -, -, WGM22, CS22, CS21, CS20 ]);
register!(0xB0, TCCR2A, [COM2A1, COM2A0, COM2B1, COM2B0, -, -, WGM21, WGM20 ]);
register!(0x8B, OCR1BH );
register!(0x8A, OCR1BL );
register!(0x89, OCR1AH );
register!(0x88, OCR1AL );
register!(0x87, ICR1H );
register!(0x86, ICR1L );
register!(0x85, TCNT1H );
register!(0x84, TCNT1L );
register!(0x82, TCCR1C, [FOC1A, FOC1B, -, -, -, -, -, - ]);
register!(0x81, TCCR1B, [ICNC1, ICES1, -, WGM13, WGM12, CS12, CS11, CS10 ]);
register!(0x80, TCCR1A, [COM1A1, COM1A0, COM1B1, COM1B0, -, -, WGM11, WGM10 ]);
register!(0x7F, DIDR1, [-, -, -, -, -, -, AIN1D, AIN0D ]);
register!(0x7E, DIDR0, [-, -, ADC5D, ADC4D, ADC3D, ADC2D, ADC1D, ADC0D ]);
register!(0x7C, ADMUX, [REFS1, REFS0, ADLAR, -, MUX3, MUX2, MUX1, MUX0 ]);
register!(0x7B, ADCSRB, [-, ACME, -, -, -, ADTS2, ADTS1, ADTS0 ]);
register!(0x7A, ADCSRA, [ADEN, ADSC, ADATE, ADIF, ADIE, ADPS2, ADPS1, ADPS0 ]);
register!(0x79, ADCH );
register!(0x78, ADCL );
register!(0x70, TIMSK2, [-, -, -, -, -, OCIE2B, OCIE2A, TOIE2 ]);
register!(0x6F, TIMSK1, [-, -, ICIE1, -, -, OCIE1B, OCIE1A, TOIE1 ]);
register!(0x6E, TIMSK0, [-, -, -, -, -, OCIE0B, OCIE0A, TOIE0 ]);
register!(0x6D, PCMSK2, [PCINT23, PCINT22, PCINT21, PCINT20, PCINT19, PCINT18, PCINT17, PCINT16]);
register!(0x6C, PCMSK1, [-, PCINT14, PCINT13, PCINT12, PCINT11, PCINT10, PCINT9, PCINT8 ]);
register!(0x6B, PCMSK0, [PCINT7, PCINT6, PCINT5, PCINT4, PCINT3, PCINT2, PCINT1, PCINT0 ]);
register!(0x69, EICRA, [-, -, -, -, ISC11, ISC10, ISC01, ISC00 ]);
register!(0x68, PCICR, [-, -, -, -, -, PCIE2, PCIE1, PCIE0 ]);
register!(0x66, OSCCAL );
register!(0x64, PRR, [PRTWI, PRTIM2, PRTIM0, -, PRTIM1, PRSPI, PRUSART0,PRADC ]);
register!(0x61, CLKPR, [CLKPCE, -, -, -, CLKPS3, CLKPS2, CLKPS1, CLKPS0 ]);
register!(0x60, WDTCSR, [WDIF, WDIE, WDP3, WDCE, WDE, WDP2, WDP1, WDP0 ]);
register!(0x5F, SREG, [I, T, H, S, V, N, Z, C ]);
register!(0x5E, SPH, [-, -, -, -, -, SP10, SP9, SP8 ]);
register!(0x5D, SPL, [SP7, SP6, SP5, SP4, SP3, SP2, SP1, SP0 ]);
register!(0x57, SPMCSR, [SPMIE, RWWSB, SIGRD, RWWSRE, BLBSET, PGWRT, PGERS, SPMEN ]);
register!(0x55, MCUCR, [-, BODS, BODSE, PUD, -, -, IVSEL, IVCE ]);
register!(0x54, MCUSR, [-, -, -, -, WDRF, BORF, EXTRF, PORF ]);
register!(0x53, SMCR, [-, -, -, -, SM2, SM1, SM0, SE ]);
register!(0x50, ACSR, [ACD, ACBG, ACO, ACI, ACIE, ACIC, ACIS1, ACIS0 ]);
register!(0x4E, SPDR );
register!(0x4D, SPSR, [SPIF, WCOL, -, -, -, -, -, SPI2X ]);
register!(0x4C, SPCR, [SPIE, SPE, DORD, MSTR, CPOL, CPHA, SPR1, SPR0 ]);
register!(0x4B, GPIOR2 );
register!(0x4A, GPIOR1 );
register!(0x48, OCR0B );
register!(0x47, OCR0A );
register!(0x46, TCNT0 );
register!(0x45, TCCR0B, [FOC0A, FOC0B, -, -, WGM02, CS02, CS01, CS00 ]);
register!(0x44, TCCR0A, [COM0A1, COM0A0, COM0B1, COM0B0, -, -, WGM01, WGM00 ]);
register!(0x43, GTCCR, [TSM, -, -, -, -, -, PSRASY, PSRSYNC]);
register!(0x42, EEARH );
register!(0x41, EEARL );
register!(0x40, EEDR );
register!(0x3F, EECR, [-, -, EEPM1, EEPM0, EERIE, EEMPE, EEPE, EERE ]);
register!(0x3E, GPIOR0 );
register!(0x3D, EIMSK, [-, -, -, -, -, -, INT1, INT0 ]);
register!(0x3C, EIFR, [-, -, -, -, -, -, INTF1, INTF0 ]);
register!(0x3B, PCIFR, [-, -, -, -, -, PCIF2, PCIF1, PCIF0 ]);
register!(0x37, TIFR2, [-, -, -, -, -, OCF2B, OCF2A, TOV2 ]);
register!(0x36, TIFR1, [-, -, ICF1, -, -, OCF1B, OCF1A, TOV1 ]);
register!(0x35, TIFR0, [-, -, -, -, -, OCF0B, OCF0A, TOV0 ]);
register!(0x2B, PORTD, [PORTD7, PORTD6, PORTD5, PORTD4, PORTD3, PORTD2, PORTD1, PORTD0 ]);
register!(0x2A, DDRD, [DDD7, DDD6, DDD5, DDD4, DDD3, DDD2, DDD1, DDD0 ]);
register!(0x29, PIND, [PIND7, PIND6, PIND5, PIND4, PIND3, PIND2, PIND1, PIND0 ]);
register!(0x28, PORTC, [-, PORTC6, PORTC5, PORTC4, PORTC3, PORTC2, PORTC1, PORTC0 ]);
register!(0x27, DDRC, [-, DDC6, DDC5, DDC4, DDC3, DDC2, DDC1, DDC0 ]);
register!(0x26, PINC, [-, PINC6, PINC5, PINC4, PINC3, PINC2, PINC1, PINC0 ]);
register!(0x25, PORTB, [PORTB7, PORTB6, PORTB5, PORTB4, PORTB3, PORTB2, PORTB1, PORTB0 ]);
register!(0x24, DDRB, [DDB7, DDB6, DDB5, DDB4, DDB3, DDB2, DDB1, DDB0 ]);
register!(0x23, PINB, [PINB7, PINB6, PINB5, PINB4, PINB3, PINB2, PINB1, PINB0 ]);
// 16-bit register pairs
pub const ADC: *mut u16 = ADCL as *mut u16;
pub const EEAR: *mut u16 = EEARL as *mut u16;
pub const ICR1: *mut u16 = ICR1L as *mut u16;
pub const OCR1A: *mut u16 = OCR1AL as *mut u16;
pub const OCR1B: *mut u16 = OCR1BL as *mut u16;
pub const OSCCA: *mut u16 = OSCCAL as *mut u16;
pub const SP: *mut u16 = SPL as *mut u16;
pub const TCNT1: *mut u16 = TCNT1L as *mut u16;
pub const UBRR0: *mut u16 = UBRR0L as *mut u16;
// Aliases
pub const UDORD0: u8 = UCSZ01;
pub const UCPHA0: u8 = UCSZ00;

10
src/modules/mod.rs Normal file
View File

@ -0,0 +1,10 @@
//! Modules that can be implemented for specific cores.
pub use self::spi::HardwareSpi;
pub use self::timer::{Timer8, Timer8Setup, Timer16, Timer16Setup};
pub use self::usart::HardwareUsart;
mod spi;
mod timer;
mod usart;

60
src/modules/spi/clock.rs Normal file
View File

@ -0,0 +1,60 @@
use config;
/// A clock mask.
///
/// The format looks like this
///
/// ```
/// 0b00000<1><0><2x>
/// ```
///
/// Where
///
/// * `1` is the value of the `SPR1` bit
/// * `0` is the value of the `SPR0` bit
/// * `2x` indicates if double speed mode is enabled
#[derive(Copy, Clone)]
pub struct ClockMask(pub u8);
impl ClockMask {
/// Gets the clock mask for a specific baute rate.
pub fn with_clock(spi_clock: u32) -> ClockMask {
let mut divider_bits = if spi_clock >= config::CPU_FREQUENCY_HZ / 2 {
0
} else if spi_clock >= config::CPU_FREQUENCY_HZ / 4 {
1
} else if spi_clock >= config::CPU_FREQUENCY_HZ / 8 {
2
} else if spi_clock >= config::CPU_FREQUENCY_HZ / 16 {
3
} else if spi_clock >= config::CPU_FREQUENCY_HZ / 32 {
4
} else if spi_clock >= config::CPU_FREQUENCY_HZ / 64 {
5
} else {
6
};
// Invert the SPI2X bit
divider_bits ^= 0x1;
// Compensate for the duplicate F_osc/64
if divider_bits == 6 {
divider_bits = 7;
}
ClockMask(divider_bits)
}
pub fn control_register_mask(self) -> u8 {
// SPR1 and SPR0
// These both form bits 1 and 0 of the control register.
(self.0 & 0b110) >> 1
}
pub fn status_register_mask(self) -> u8 {
// SPI2x
// This forms bit 0 of the status register.
self.0 & 0b1
}
}

151
src/modules/spi/mod.rs Normal file
View File

@ -0,0 +1,151 @@
mod clock;
// FIXME: Start using this module or delete!!!
#[allow(dead_code)] mod settings;
use {Register, Pin};
/// An SPI module.
///
/// Information at
/// http://maxembedded.com/2013/11/the-spi-of-the-avr/
pub trait HardwareSpi {
type MasterInSlaveOut: Pin;
type MasterOutSlaveIn: Pin;
type Clock: Pin;
type SlaveSelect: Pin;
/// The SPI control register.
type ControlRegister: Register<T=u8>;
/// The SPI status register.
type StatusRegister: Register<T=u8>;
/// The SPI data register.
type DataRegister: Register<T=u8>;
/// Sets up the SPI as a master.
fn setup_master(clock: u32) {
// Setup DDR registers.
Self::MasterInSlaveOut::set_input();
Self::MasterOutSlaveIn::set_output();
Self::Clock::set_output();
Self::SlaveSelect::set_input();
Self::set_master();
Self::enable_interrupt();
Self::setup_common(clock)
}
/// Sets up the SPI as a slave.
fn setup_slave(clock: u32) {
// Setup DDR registers.
Self::MasterInSlaveOut::set_output();
Self::MasterOutSlaveIn::set_input();
Self::Clock::set_input();
Self::SlaveSelect::set_input();
Self::set_slave();
Self::setup_common(clock)
}
fn setup_common(clock: u32) {
Self::set_clock(clock);
Self::enable()
}
/// Sets the clock speed.
fn set_clock(clock: u32) {
let mask = clock::ClockMask::with_clock(clock);
Self::ControlRegister::set_mask_raw(mask.control_register_mask());
Self::StatusRegister::set_mask_raw(mask.status_register_mask());
}
/// Enables interrupts for the spi module.
#[inline(always)]
fn enable_interrupt() {
Self::ControlRegister::set_mask_raw(settings::control_register::INTERRUPT_ENABLE);
}
/// Disables interrupts for the spi module.
#[inline(always)]
fn disable_interrupt() {
Self::ControlRegister::unset_mask_raw(settings::control_register::INTERRUPT_ENABLE);
}
/// Enables the SPI.
#[inline(always)]
fn enable() {
Self::ControlRegister::set_mask_raw(settings::control_register::ENABLE);
}
/// Disables the SPI.
#[inline(always)]
fn disable() {
Self::ControlRegister::unset_mask_raw(settings::control_register::ENABLE);
}
/// Enables least-significant-bit first.
#[inline(always)]
fn set_lsb() {
Self::ControlRegister::set_mask_raw(settings::control_register::DATA_ORDER_LSB);
}
/// Enables most-significant-bit first.
#[inline(always)]
fn set_msb() {
Self::ControlRegister::unset_mask_raw(settings::control_register::DATA_ORDER_LSB);
}
/// Enables master mode.
#[inline(always)]
fn set_master() {
Self::ControlRegister::set_mask_raw(settings::control_register::MASTER);
}
/// Enables slave mode.
#[inline(always)]
fn set_slave() {
Self::ControlRegister::unset_mask_raw(settings::control_register::MASTER);
}
/// Enables double speed mode.
#[inline(always)]
fn enable_double_speed() {
Self::StatusRegister::set_mask_raw(settings::status_register::SPI2X);
}
/// Disables double speed mode.
#[inline(always)]
fn disable_double_speed() {
Self::StatusRegister::unset_mask_raw(settings::status_register::SPI2X);
}
/// Checks if there is a write collision.
#[inline(always)]
fn is_write_collision() -> bool {
Self::StatusRegister::is_mask_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_mask_set_raw(settings::status_register::SPIF);
}
/// Reads a byte from the serial.
#[inline(always)]
fn receive_byte() -> u8 {
Self::StatusRegister::wait_until_mask_set_raw(settings::status_register::SPIF);
Self::DataRegister::read()
}
/// Sends and receives a byte.
#[inline(always)]
fn send_receive(byte: u8) -> u8 {
Self::DataRegister::write(byte);
Self::StatusRegister::wait_until_mask_set_raw(settings::status_register::SPIF);
Self::DataRegister::read()
}
}

129
src/modules/spi/settings.rs Normal file
View File

@ -0,0 +1,129 @@
use super::clock::ClockMask;
#[derive(Copy, Clone)]
pub enum BitOrder {
/// The least significant bit is sent first.
LeastSignificantBit,
/// The most significant bit is sent first.
MostSignificantBit,
}
#[derive(Copy, Clone)]
pub enum ClockPhase {
LeadingEdge,
TrailingEdge,
}
/// SPI settings.
#[derive(Copy, Clone)]
pub struct Settings {
/// Whether the SPI module is enabled.
enabled: bool,
/// Whether to be configured as a master or slave.
master: bool,
/// The clock speed.
clock: u32,
/// The bit ordering.
bit_order: BitOrder,
/// The clock phase.
clock_phase: ClockPhase,
/// Whether interrupts should be enabled.
enable_interrupts: bool,
}
impl Settings {
/// Gets the default settings for the master.
pub fn master() -> Self {
Settings {
master: true,
..Default::default()
}
}
/// Gets the default settings for the slave.
pub fn slave() -> Self {
Settings {
master: false,
..Default::default()
}
}
pub fn control_register_bits(self) -> u8 {
let mut bits = 0;
bits |= self.clock().control_register_mask();
if self.enable_interrupts {
bits |= control_register::INTERRUPT_ENABLE
}
if self.enabled {
bits |= control_register::ENABLE
}
if let ClockPhase::LeadingEdge = self.clock_phase {
bits |= control_register::CPHA;
}
if let BitOrder::LeastSignificantBit = self.bit_order {
bits |= control_register::DATA_ORDER_LSB;
}
bits
}
pub fn status_register_bits(self) -> u8 {
let mut bits = 0;
bits |= self.clock().status_register_mask();
bits
}
fn clock(self) -> ClockMask {
ClockMask::with_clock(self.clock)
}
}
impl Default for Settings {
fn default() -> Settings {
Settings {
enabled: true,
master: true,
// same as Arduino default in `SPI.h`.
clock: 4_000_000,
bit_order: BitOrder::MostSignificantBit,
clock_phase: ClockPhase::LeadingEdge,
enable_interrupts: false,
}
}
}
/// Constants for the control register.
#[allow(dead_code)]
pub mod control_register {
/// Set if interrupts are enabled.
pub const INTERRUPT_ENABLE: u8 = 1<<7;
/// Set if the SPI module is enabled.
pub const ENABLE: u8 = 1<<6;
/// Set if data is sent in LSB format.
pub const DATA_ORDER_LSB: u8 = 1<<5;
/// Set if we are configuring a master.
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.
#[allow(dead_code)]
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;
}

6
src/modules/timer/mod.rs Normal file
View File

@ -0,0 +1,6 @@
pub use self::timer8::{Timer8, Timer8Setup};
pub use self::timer16::{Timer16, Timer16Setup};
mod timer8;
mod timer16;

View File

@ -0,0 +1,211 @@
use {RegisterBits, Register};
use core::marker;
/// A 16-bit timer.
pub trait Timer16 : Sized {
/// The first compare register.
/// For example, OCR0A.
type CompareA: Register<T=u16>;
/// The second compare register.
/// For example, OCR0B.
type CompareB: Register<T=u16>;
/// The counter register.
///
/// For example, TCNT0.
type Counter: Register<T=u16>;
/// The first control register.
///
/// For example, TCCR0A.
type ControlA: Register<T=u8>;
/// The second control register.
///
/// For example, TCCR0B.
type ControlB: Register<T=u8>;
/// The third control register.
///
/// For example, TCCR0C.
type ControlC: Register<T=u8>;
/// The interrupt mask register.
///
/// For example, TIMSK0.
type InterruptMask: Register<T=u8>;
/// The interrupt flag register.
///
/// For example, TIFR0.
type InterruptFlag: Register<T=u8>;
const CS0: RegisterBits<Self::ControlB>;
const CS1: RegisterBits<Self::ControlB>;
const CS2: RegisterBits<Self::ControlB>;
const WGM0: RegisterBits<Self::ControlA>;
const WGM1: RegisterBits<Self::ControlA>;
const WGM2: RegisterBits<Self::ControlB>;
const WGM3: RegisterBits<Self::ControlB>;
const OCIEA: RegisterBits<Self::InterruptMask>;
fn setup() -> Timer16Setup<Self> { Timer16Setup::new() }
}
pub enum ClockSource {
None,
Prescale1,
Prescale8,
Prescale64,
Prescale256,
Prescale1024,
ExternalFalling,
ExternalRising,
}
impl ClockSource {
fn bits<T: Timer16>(&self) -> RegisterBits<T::ControlB> {
use self::ClockSource::*;
match *self {
None => RegisterBits::zero() | RegisterBits::zero() | RegisterBits::zero(),
Prescale1 => RegisterBits::zero() | RegisterBits::zero() | T::CS0,
Prescale8 => RegisterBits::zero() | T::CS1 | RegisterBits::zero(),
Prescale64 => RegisterBits::zero() | T::CS1 | T::CS0,
Prescale256 => T::CS2 | RegisterBits::zero() | RegisterBits::zero(),
Prescale1024 => T::CS2 | RegisterBits::zero() | T::CS0,
ExternalFalling => T::CS2 | T::CS1 | RegisterBits::zero(),
ExternalRising => T::CS2 | T::CS1 | T::CS0,
}
}
#[inline]
fn mask<T: Timer16>() -> RegisterBits<T::ControlB> {
!(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<T: Timer16>(&self) -> (RegisterBits<T::ControlA>, RegisterBits<T::ControlB>) {
use self::WaveformGenerationMode::*;
use RegisterBits as B;
// 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 => (B::zero() | B::zero(), B::zero() | B::zero()),
PwmPhaseCorrect8Bit => (B::zero() | B::zero(), B::zero() | T::WGM0),
PwmPhaseCorrect9Bit => (B::zero() | B::zero(), T::WGM1 | B::zero()),
PwmPhaseCorrect10Bit => (B::zero() | B::zero(), T::WGM1 | T::WGM0),
ClearOnTimerMatchOutputCompare => (B::zero() | T::WGM2, B::zero() | B::zero()),
FastPwm8Bit => (B::zero() | T::WGM2, B::zero() | T::WGM0),
FastPwm9Bit => (B::zero() | T::WGM2, T::WGM1 | B::zero()),
FastPwm10Bit => (B::zero() | T::WGM2, T::WGM1 | T::WGM0),
PwmPhaseAndFrequencyCorrectInputCapture => (T::WGM3 | B::zero(), B::zero() | B::zero()),
PwmPhaseAndFrequencyCorrectOutputCompare => (T::WGM3 | B::zero(), B::zero() | T::WGM0),
PwmPhaseCorrectInputCapture => (T::WGM3 | B::zero(), T::WGM1 | B::zero()),
PwmPhaseCorrectOutputCompare => (T::WGM3 | B::zero(), T::WGM1 | T::WGM0),
ClearOnTimerMatchInputCapture => (T::WGM3 | T::WGM2, B::zero() | B::zero()),
// Reserved => (T::WGM3 | T::WGM2, B::zero() | T::WGM0),
FastPwmInputCapture => (T::WGM3 | T::WGM2, T::WGM1 | B::zero()),
FastPwmOutputCompare => (T::WGM3 | T::WGM2, T::WGM1 | T::WGM0),
};
(a, b)
}
#[inline]
fn mask<T: Timer16>() -> (RegisterBits<T::ControlA>, RegisterBits<T::ControlB>) {
(!(T::WGM0 | T::WGM1), !(T::WGM2 | T::WGM3))
}
}
pub struct Timer16Setup<T: Timer16> {
a: RegisterBits<T::ControlA>,
b: RegisterBits<T::ControlB>,
c: RegisterBits<T::ControlC>,
output_compare_1: Option<u16>,
_phantom: marker::PhantomData<T>,
}
impl<T: Timer16> Timer16Setup<T> {
#[inline]
fn new() -> Self {
Timer16Setup {
a: RegisterBits::zero(),
b: RegisterBits::zero(),
c: RegisterBits::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<u16>) -> Self {
self.output_compare_1 = value;
self
}
#[inline]
pub fn configure(self) {
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
T::InterruptMask::set(T::OCIEA);
}
}
}

189
src/modules/timer/timer8.rs Normal file
View File

@ -0,0 +1,189 @@
use {RegisterBits, Register};
use core::marker;
/// A 8-bit timer.
pub trait Timer8 : Sized {
/// The first compare register.
/// For example, OCR0A.
type CompareA: Register<T=u8>;
/// The second compare register.
/// For example, OCR0B.
type CompareB: Register<T=u8>;
/// The counter register.
///
/// For example, TCNT0.
type Counter: Register<T=u8>;
/// The first control register.
///
/// For example, TCCR0A.
type ControlA: Register<T=u8>;
/// The second control register.
///
/// For example, TCCR0B.
type ControlB: Register<T=u8>;
/// The interrupt mask register.
///
/// For example, TIMSK0.
type InterruptMask: Register<T=u8>;
/// The interrupt flag register.
///
/// For example, TIFR0.
type InterruptFlag: Register<T=u8>;
/// Bit 0 of the clock select mask.
const CS0: RegisterBits<Self::ControlB>;
/// Bit 1 of the clock select mask.
const CS1: RegisterBits<Self::ControlB>;
/// Bit 2 of the clock select mask.
const CS2: RegisterBits<Self::ControlB>;
/// Bit 0 of the waveform generation mode mask.
const WGM0: RegisterBits<Self::ControlA>;
/// Bit 1 of the waveform generation mode mask.
const WGM1: RegisterBits<Self::ControlA>;
/// Bit 2 of the waveform generation mode mask.
const WGM2: RegisterBits<Self::ControlB>;
/// Output compare interrupt enable flag.
const OCIEA: RegisterBits<Self::InterruptMask>;
}
pub enum ClockSource {
None,
Prescale1,
Prescale8,
Prescale64,
Prescale256,
Prescale1024,
ExternalFalling,
ExternalRising,
}
impl ClockSource {
fn bits<T: Timer8>(&self) -> RegisterBits<T::ControlB> {
use self::ClockSource::*;
match *self {
None => RegisterBits::zero() | RegisterBits::zero() | RegisterBits::zero(),
Prescale1 => RegisterBits::zero() | RegisterBits::zero() | T::CS0,
Prescale8 => RegisterBits::zero() | T::CS1 | RegisterBits::zero(),
Prescale64 => RegisterBits::zero() | T::CS1 | T::CS0,
Prescale256 => T::CS2 | RegisterBits::zero() | RegisterBits::zero(),
Prescale1024 => T::CS2 | RegisterBits::zero() | T::CS0,
ExternalFalling => T::CS2 | T::CS1 | RegisterBits::zero(),
ExternalRising => T::CS2 | T::CS1 | T::CS0,
}
}
#[inline]
fn mask<T: Timer8>() -> RegisterBits<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) -> (RegisterBits<T::ControlA>, RegisterBits<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 => (RegisterBits::zero(), RegisterBits::zero() | RegisterBits::zero()),
PwmPhaseCorrect => (RegisterBits::zero(), RegisterBits::zero() | T::WGM0),
ClearOnTimerMatchOutputCompare => (RegisterBits::zero(), T::WGM1 | RegisterBits::zero()),
FastPwm => (RegisterBits::zero(), T::WGM1 | T::WGM0),
// Reserved => (T::WGM2, RegisterBits::zero() | RegisterBits::zero()),
PwmPhaseCorrectOutputCompare => (T::WGM2, RegisterBits::zero() | T::WGM0),
// Reserved => (T::WGM2, T::WGM1 | RegisterBits::zero())),
FastPwmOutputCompare => (T::WGM2, T::WGM1 | T::WGM0),
};
(a, b)
}
#[inline]
fn mask<T: Timer8>() -> (RegisterBits<T::ControlA>, RegisterBits<T::ControlB>) {
(!(T::WGM0 | T::WGM1), !(T::WGM2))
}
}
pub struct Timer8Setup<T: Timer8> {
a: RegisterBits<T::ControlA>,
b: RegisterBits<T::ControlB>,
output_compare_1: Option<u8>,
_phantom: marker::PhantomData<T>,
}
impl<T: Timer8> Timer8Setup<T> {
#[inline]
pub fn new() -> Self {
Timer8Setup {
a: RegisterBits::zero(),
b: RegisterBits::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) {
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::InterruptMask::set(T::OCIEA);
}
}
}

14
src/modules/usart.rs Normal file
View File

@ -0,0 +1,14 @@
use Register;
pub trait HardwareUsart {
/// The USART data register.
type DataRegister: Register<T=u8>;
/// USART control and status register A.
type ControlRegisterA: Register<T=u8>;
/// USART control and status register B.
type ControlRegisterB: Register<T=u8>;
/// USART control and status register C.
type ControlRegisterC: Register<T=u8>;
/// USART baud rate register.
type BaudRateRegister: Register<T=u16>;
}

89
src/pin.rs Normal file
View File

@ -0,0 +1,89 @@
use Register;
/// Represents whether a pin is an input or an output.
pub enum DataDirection {
/// The pin is exclusively used for reading signals.
Input,
/// The pin is exclusively used for sending signals.
Output,
}
/// An IO pin.
pub trait Pin {
/// The associated data direction register.
type DDR: Register<T=u8>;
/// The associated port register.
type PORT: Register<T=u8>;
///
/// Reads from the register will read input bits.
/// Writes to the register will toggle bits.
type PIN: Register<T=u8>;
/// The mask of the pin used for accessing registers.
const MASK: u8;
/// Sets the data direction of the pin.
#[inline(always)]
fn set_direction(direction: DataDirection) {
match direction {
DataDirection::Input => Self::set_input(),
DataDirection::Output => Self::set_output(),
}
}
/// Sets the pin up as an input.
#[inline(always)]
fn set_input() {
Self::DDR::unset_mask_raw(Self::MASK);
}
/// Sets the pin up as an output.
#[inline(always)]
fn set_output() {
Self::DDR::set_mask_raw(Self::MASK);
}
/// Set the pin to high.
///
/// The pin must be configured as an output.
#[inline(always)]
fn set_high() {
Self::PORT::set_mask_raw(Self::MASK);
}
/// Set the pin to low.
///
/// The pin must be configured as an output.
#[inline(always)]
fn set_low() {
Self::PORT::unset_mask_raw(Self::MASK);
}
/// Toggles the pin.
///
/// The pin must be configured as an output.
#[inline(always)]
fn toggle() {
// FIXME: We can optimise this on post-2006 AVRs.
// http://www.avrfreaks.net/forum/toggle-state-output-pin
// set(Self::PIN, Self::MASK);
Self::PORT::toggle_raw(Self::MASK);
}
/// Check if the pin is currently high.
///
/// The pin must be configured as an input.
#[inline(always)]
fn is_high() -> bool {
Self::PIN::is_mask_set_raw(Self::MASK)
}
/// Checks if the pin is currently low.
///
/// The pin must be configured as an input.
#[inline(always)]
fn is_low() -> bool {
Self::PIN::is_clear_raw(Self::MASK)
}
}

View File

@ -1,28 +1,4 @@
use core::prelude::v1::*; //! Re-exports commonly-used APIs that can be imported at once.
use core::marker::PhantomData;
pub use io::{PORT_B, PORT_C, PORT_D}; pub use interrupt::without_interrupts;
pub struct DisableInterrupts(PhantomData<()>);
impl DisableInterrupts {
#[inline]
pub fn new() -> DisableInterrupts {
unsafe { asm!("CLI") }
DisableInterrupts(PhantomData)
}
}
impl Drop for DisableInterrupts {
#[inline]
fn drop(&mut self) {
unsafe { asm!("SEI") }
}
}
pub fn without_interrupts<F, T>(f: F) -> T
where F: FnOnce() -> T
{
let _disabled = DisableInterrupts::new();
f()
}

227
src/register.rs Normal file
View File

@ -0,0 +1,227 @@
use core::{cmp, convert, marker, ops};
/// A value that a register can store.
///
/// All registers are either `u8` or `u16`.
pub trait RegisterValue : Copy + Clone +
ops::BitAnd<Output=Self> +
ops::BitAndAssign +
ops::BitOr<Output=Self> +
ops::BitOrAssign +
ops::BitXor<Output=Self> +
ops::BitXorAssign +
ops::Not<Output=Self> +
cmp::PartialEq + cmp::Eq +
cmp::PartialOrd + cmp::Ord +
convert::From<u8> {
}
/// A register.
pub trait Register : Sized {
/// The type that can represent the value of the register.
type T: RegisterValue;
/// The type representing a set of bits that may be manipulated
/// within the register.
type RegisterBits = RegisterBits<Self>;
/// The address of the register.
const ADDRESS: *mut Self::T;
/// Writes a value to the register.
#[inline(always)]
fn write<V>(value: V) where V: Into<Self::T> {
unsafe {
*Self::ADDRESS = value.into();
}
}
/// Reads the value of the register.
#[inline(always)]
fn read() -> Self::T {
unsafe { *Self::ADDRESS }
}
/// Sets a set of bits to `1` in the register.
fn set(bits: RegisterBits<Self>) {
Self::set_mask_raw(bits.mask);
}
/// Sets a bitmask in a register.
///
/// This is equivalent to `r |= mask`.
#[inline(always)]
fn set_mask_raw(mask: Self::T) {
unsafe {
*Self::ADDRESS |= mask;
}
}
/// Unsets a set of bits in the register.
///
/// All of the bits will be set to `0`.
fn unset(bits: RegisterBits<Self>) {
Self::unset_mask_raw(bits.mask);
}
/// Clears a bitmask from a register.
///
/// This is equivalent to `r &= !mask`.
#[inline(always)]
fn unset_mask_raw(mask: Self::T) {
unsafe {
*Self::ADDRESS &= !mask;
}
}
/// Toggles a set of bits within the register.
///
/// All specified bits which were previously `0` will become
/// `1`, and all specified bits that were previous `1` will
/// become `0`.
fn toggle(mask: RegisterBits<Self>) {
Self::toggle_raw(mask.mask);
}
/// Toggles a mask in the register.
///
/// This is equivalent to `r ^= mask`.
#[inline(always)]
fn toggle_raw(mask: Self::T) {
unsafe {
*Self::ADDRESS ^= mask;
}
}
/// Checks if a set of bits are enabled.
///
/// All specifed bits must be set for this function
/// to return `true`.
fn is_set(bits: RegisterBits<Self>) -> bool {
Self::is_mask_set_raw(bits.mask)
}
/// Checks if a mask is set in the register.
///
/// This is equivalent to `(r & mask) == mask`.
#[inline(always)]
fn is_mask_set_raw(mask: Self::T) -> bool {
unsafe {
(*Self::ADDRESS & mask) == mask
}
}
/// Checks if a set of bits are not set.
///
/// All specified bits must be `0` for this
/// function to return `true`.
fn is_clear(mask: RegisterBits<Self>) -> bool {
Self::is_clear_raw(mask.mask)
}
/// Checks if a mask is clear in the register.
///
/// This is equivalent to `(r & mask) == 0`.
#[inline(always)]
fn is_clear_raw(mask: Self::T) -> bool {
unsafe {
(*Self::ADDRESS & mask) == Self::T::from(0)
}
}
/// Waits until a set of bits are set in the register.
///
/// This function will block until all bits that are set in
/// the mask are also set in the register.
fn wait_until_set(bits: RegisterBits<Self>) {
Self::wait_until_mask_set_raw(bits.mask);
}
/// Waits until a bit mask is set in the register.
///
/// This function will block until all bits that are set in
/// the mask are also set in the register.
#[inline(always)]
fn wait_until_mask_set_raw(mask: Self::T) {
wait_until(|| Self::is_mask_set_raw(mask))
}
}
/// Represents a set of bits within a specific register.
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct RegisterBits<R: Register> {
/// The raw bitmask.
mask: R::T,
_phantom: marker::PhantomData<R>,
}
impl<R> RegisterBits<R> where R: Register {
/// Creates a new register mask.
pub const fn new(mask: R::T) -> Self {
RegisterBits { mask, _phantom: marker::PhantomData }
}
pub fn zero() -> Self {
RegisterBits::new(0u8.into())
}
}
impl<R> ops::BitOr for RegisterBits<R> where R: Register
{
type Output = Self;
fn bitor(self, rhs: Self) -> Self {
RegisterBits::new(self.mask | rhs.mask)
}
}
impl<R> ops::BitOrAssign for RegisterBits<R> where R: Register {
fn bitor_assign(&mut self, rhs: Self) {
self.mask |= rhs.mask;
}
}
impl<R> ops::BitAnd for RegisterBits<R> where R: Register
{
type Output = Self;
fn bitand(self, rhs: Self) -> Self {
RegisterBits::new(self.mask & rhs.mask)
}
}
impl<R> ops::BitAndAssign for RegisterBits<R> where R: Register {
fn bitand_assign(&mut self, rhs: Self) {
self.mask &= rhs.mask;
}
}
impl<R> ops::Not for RegisterBits<R> where R: Register {
type Output = Self;
fn not(self) -> Self {
RegisterBits::new(!self.mask)
}
}
impl<R> Into<u8> for RegisterBits<R> where R: Register<T=u8> {
fn into(self) -> u8 { self.mask }
}
impl<R> Into<u16> for RegisterBits<R> where R: Register<T=u16> {
fn into(self) -> u16 { self.mask }
}
impl RegisterValue for u8 { }
impl RegisterValue for u16 { }
/// Waits until some condition is true of the register.
#[inline(always)]
fn wait_until<F>(mut f: F)
where F: FnMut() -> bool {
loop {
if f() {
break;
}
}
}

15
src/std_stub.rs Normal file
View File

@ -0,0 +1,15 @@
//! Stub methods that `libstd` normally defines.
// These do not need to be in a module, but we group them here for clarity.
pub mod std {
#[lang = "eh_personality"]
#[no_mangle]
pub unsafe extern "C" fn rust_eh_personality(_state: (), _exception_object: *mut (), _context: *mut ()) -> () {
}
#[panic_handler]
fn panic(_info: &::core::panic::PanicInfo) -> ! {
loop {}
}
}

View File

@ -1,139 +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 | 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 {
write_volatile(TCCR0A, self.a);
write_volatile(TCCR0B, self.b);
// Reset counter to zero
write_volatile(TCNT0, 0);
if let Some(v) = self.output_compare_1 {
// Set the match
write_volatile(OCR0A, v);
// Enable compare interrupt
write_volatile(TIMSK0, OCIE0A);
}
}
}
}

View File

@ -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<u16>,
}
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<u16>) -> 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);
}
}
}
}