From a831e48755bd7342b2ff6f4fd1445959007f4fa8 Mon Sep 17 00:00:00 2001 From: Dylan McKay Date: Mon, 5 Nov 2018 23:29:14 +1300 Subject: [PATCH 01/38] Revert "Expose some structs for the IO ports" This reverts commit 99ad3f0ab116a12f7fd4447e3685d9340950134b. --- src/io/mod.rs | 5 -- src/io/port.rs | 183 ------------------------------------------------- src/lib.rs | 33 --------- src/prelude.rs | 2 - 4 files changed, 223 deletions(-) delete mode 100644 src/io/mod.rs delete mode 100644 src/io/port.rs diff --git a/src/io/mod.rs b/src/io/mod.rs deleted file mode 100644 index 5d359f0..0000000 --- a/src/io/mod.rs +++ /dev/null @@ -1,5 +0,0 @@ -pub mod port; - -pub const PORT_B: port::Port = port::Port::new(); -pub const PORT_C: port::Port = port::Port::new(); -pub const PORT_D: port::Port = port::Port::new(); diff --git a/src/io/port.rs b/src/io/port.rs deleted file mode 100644 index 73c8ee0..0000000 --- a/src/io/port.rs +++ /dev/null @@ -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 { - _port: PhantomData

, - direction: [Option; BITS_IN_BYTE], - pullup: [Option; BITS_IN_BYTE], -} - -impl

Configuration

- where - P: Information -{ - #[inline] - pub fn new() -> Configuration

{ - 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 { - _port: PhantomData

, -} - -impl

Data

- where - P: Information -{ - #[inline] - pub fn new() -> Data

{ 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

(PhantomData

); - -impl Port

{ - pub(crate) const fn new() -> Port

{ Port(PhantomData) } - pub fn configuration(&self) -> Configuration

{ Configuration::new() } - pub fn data(&self) -> Data

{ Data::new() } -} diff --git a/src/lib.rs b/src/lib.rs index b4e5948..08a1c3f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,43 +8,10 @@ extern crate core; -// Look like we have a standard library -#[allow(unused_imports)] -use core::{option, iter, fmt, ops, clone, marker}; - pub mod prelude; pub mod timer0; pub mod timer1; pub mod serial; -pub mod io; - -#[derive(Copy, Clone)] -pub enum Bit { - Bit0 = 0, - Bit1 = 1, - Bit2 = 2, - Bit3 = 3, - Bit4 = 4, - Bit5 = 5, - Bit6 = 6, - Bit7 = 7, -} - -impl Bit { - fn as_mask(&self) -> u8 { 1 << *self as u8 } - - 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) => {}; diff --git a/src/prelude.rs b/src/prelude.rs index 8592448..8895d93 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -1,8 +1,6 @@ use core::prelude::v1::*; use core::marker::PhantomData; -pub use io::{PORT_B, PORT_C, PORT_D}; - pub struct DisableInterrupts(PhantomData<()>); impl DisableInterrupts { From d833813374850a0749c170d694700a01eade93fd Mon Sep 17 00:00:00 2001 From: Dylan McKay Date: Wed, 30 Aug 2017 01:48:44 +1200 Subject: [PATCH 02/38] Support auto-generated cores --- Cargo.toml | 4 ++ avr-atmega328p.json | 26 +++++++ build.rs | 161 +++++++++++++++++++++++++++++++++++++++++ build.sh | 2 + src/cores/.gitignore | 1 + src/cores/.gitkeep | 0 src/lib.rs | 18 ++++- src/pin.rs | 81 +++++++++++++++++++++ src/reg.rs | 95 +++++++++++++++++++++++++ src/spi.rs | 166 +++++++++++++++++++++++++++++++++++++++++++ 10 files changed, 552 insertions(+), 2 deletions(-) create mode 100644 avr-atmega328p.json create mode 100644 build.rs create mode 100755 build.sh create mode 100644 src/cores/.gitignore create mode 100644 src/cores/.gitkeep create mode 100644 src/pin.rs create mode 100644 src/reg.rs create mode 100644 src/spi.rs diff --git a/Cargo.toml b/Cargo.toml index 5a1a6d8..51034a4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,3 +12,7 @@ description = """ Reusable components for the Arduino Uno. """ keywords = ["avr", "arduino", "uno"] + +[build-dependencies] +avr-mcu = "0.2" + diff --git a/avr-atmega328p.json b/avr-atmega328p.json new file mode 100644 index 0000000..951e1ef --- /dev/null +++ b/avr-atmega328p.json @@ -0,0 +1,26 @@ +{ + "llvm-target": "avr-unknown-unknown", + "cpu": "atmega328p", + "target-endian": "little", + "target-pointer-width": "16", + "os": "unknown", + "target-env": "", + "target-vendor": "unknown", + "arch": "avr", + "data-layout": "e-p:16:8-i8:8-i16:8-i32:8-i64:8-f32:8-f64:8-n8-a:8", + + "executables": true, + + "linker": "avr-gcc", + "linker-flavor": "gcc", + "pre-link-args": { + "gcc": ["-Os", "-mmcu=atmega328p"] + }, + "exe-suffix": ".elf", + "post-link-args": { + "gcc": ["-Wl,--gc-sections"] + }, + + "no-default-libraries": false +} + diff --git a/build.rs b/build.rs new file mode 100644 index 0000000..1ccf925 --- /dev/null +++ b/build.rs @@ -0,0 +1,161 @@ +extern crate avr_mcu; + +use avr_mcu::*; +use std::fs::{self, File}; +use std::io; +use std::io::prelude::*; +use std::path::{Path, PathBuf}; + +fn cores_path() -> PathBuf { + Path::new(env!("CARGO_MANIFEST_DIR")).join("src").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 = avr_mcu::current::mcu() + .expect("no target cpu specified"); + 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_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, "//! Cores")?; + writeln!(w)?; + for mcu in mcus { + writeln!(w, "/// The {}.", mcu.device.name)?; + writeln!(w, "pub mod {};", core_module_name(mcu))?; + } + 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 {{HardwareSpi, Pin, Register}};")?; + writeln!(w)?; + + gen::write_registers(mcu, w)?; + gen::write_pins(mcu, w)?; + gen::write_spi_modules(mcu, w)?; + + writeln!(w) +} + +mod gen { + 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, "impl Register<{}> for {} {{", ty, register.name)?; + writeln!(w, " const ADDR: *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") { + for instance in port.instances.iter() { + for signal in instance.signals.iter() { + let idx = signal.index.expect("signal with no index"); + let struct_name = pin_name(instance, signal); + + 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)?; + } + } + } + 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 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); + + writeln!(w, " type {} = {};", spi_signal_name, pin_name)?; + } + + for reg in module.registers() { + let const_name = match ®.caption[..] { + "SPI Data Register" => "SPDR", + "SPI Status Register" => "SPSR", + "SPI Control Register" => "SPCR", + _ => panic!("unknown SPI module register: '{}'", reg.caption), + }; + + + writeln!(w, " /// {}.", reg.caption)?; + writeln!(w, " type {} = {};", const_name, reg.name)?; + } + 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"); + format!("{}{}", instance.name, idx) + } +} + diff --git a/build.sh b/build.sh new file mode 100755 index 0000000..f780e29 --- /dev/null +++ b/build.sh @@ -0,0 +1,2 @@ +#! /bin/sh +xargo build --target avr-atmega328p diff --git a/src/cores/.gitignore b/src/cores/.gitignore new file mode 100644 index 0000000..6f5f3d1 --- /dev/null +++ b/src/cores/.gitignore @@ -0,0 +1 @@ +*.rs diff --git a/src/cores/.gitkeep b/src/cores/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/src/lib.rs b/src/lib.rs index 08a1c3f..599ac9f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,12 +6,26 @@ #![no_core] -extern crate core; +#![no_std] + +pub use self::reg::Register; +pub use self::pin::Pin; +pub use self::spi::HardwareSpi; pub mod prelude; +pub mod serial; pub mod timer0; pub mod timer1; -pub mod serial; +pub mod cores; + +mod reg; +mod pin; +mod spi; + +pub enum DataDirection { + Input, + Output, +} macro_rules! bit { (-, $pos:expr) => {}; diff --git a/src/pin.rs b/src/pin.rs new file mode 100644 index 0000000..dfb76df --- /dev/null +++ b/src/pin.rs @@ -0,0 +1,81 @@ +use {DataDirection, Register}; + +/// An IO pin. +pub trait Pin { + /// The associated data direction registerr. + type DDR: Register; + /// The associated port register. + type PORT: Register; + /// The associated pin register. + /// + /// Reads from the register will read input bits. + /// Writes to the register will toggle bits. + type PIN: Register; + /// 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(Self::MASK); + } + + /// Sets the pin up as an output. + #[inline(always)] + fn set_output() { + Self::DDR::set(Self::MASK); + } + + /// Set the pin to high. + /// + /// The pin must be configured as an output. + #[inline(always)] + fn set_high() { + Self::PORT::set(Self::MASK); + } + + /// Set the pin to low. + /// + /// The pin must be configured as an output. + #[inline(always)] + fn set_low() { + Self::PORT::unset(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(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_set(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(Self::MASK) + } +} + diff --git a/src/reg.rs b/src/reg.rs new file mode 100644 index 0000000..194823f --- /dev/null +++ b/src/reg.rs @@ -0,0 +1,95 @@ +use core::{cmp, convert, ops}; + +pub trait RegVal : Copy + Clone + + ops::BitAnd + + ops::BitAndAssign + + ops::BitOr + + ops::BitOrAssign + + ops::BitXor + + ops::BitXorAssign + + ops::Not + + cmp::PartialEq + cmp::Eq + + cmp::PartialOrd + cmp::Ord + + convert::From { +} + +/// A register. +pub trait Register { + /// The address of the register. + const ADDR: *mut T; + + /// Writes a value to the register. + #[inline(always)] + fn write(value: T) { + unsafe { + *Self::ADDR = value; + } + } + + /// Reads the value of the register. + #[inline(always)] + fn read() -> T { + unsafe { *Self::ADDR } + } + + /// Sets a bitmask in a register. + #[inline(always)] + fn set(mask: T) { + unsafe { + *Self::ADDR |= mask; + } + } + + /// Clears a bitmask from a register. + #[inline(always)] + fn unset(mask: T) { + unsafe { + *Self::ADDR &= !mask; + } + } + + /// Toggles a mask in the register. + #[inline(always)] + fn toggle(mask: T) { + unsafe { + *Self::ADDR ^= mask; + } + } + + /// Checks if a mask is set in the register. + #[inline(always)] + fn is_set(mask: T) -> bool { + unsafe { + (*Self::ADDR & mask) == mask + } + } + + /// Checks if a mask is clear in the register. + #[inline(always)] + fn is_clear(mask: T) -> bool { + unsafe { + (*Self::ADDR & mask) == T::from(0) + } + } + + /// Waits until some condition is true of the register. + #[inline(always)] + fn wait_until(mut f: F) + where F: FnMut() -> bool { + loop { + if f() { + break; + } + } + } + + /// Waits until a mask is set. + #[inline(always)] + fn wait_until_set(mask: T) { + Self::wait_until(|| Self::is_set(mask)) + } +} + +impl RegVal for u8 { } +impl RegVal for u16 { } + diff --git a/src/spi.rs b/src/spi.rs new file mode 100644 index 0000000..71d5892 --- /dev/null +++ b/src/spi.rs @@ -0,0 +1,166 @@ +use {Register, Pin}; + + +/// An SPI module. +/// +/// Information at +/// http://maxembedded.com/2013/11/the-spi-of-the-avr/ +pub trait HardwareSpi { + /// Master-in slave-out pin. + type MISO: Pin; + /// Master-out slave-in pin. + type MOSI: Pin; + /// Serial clock pin. + type SCK: Pin; + /// Slave-select pin. + type SS: Pin; + + /// The SPI control register. + type SPCR: Register; + /// The SPI status register. + type SPSR: Register; + /// The SPI data register. + type SPDR: Register; + + /// Sets up the SPI as a master. + fn setup_master() { + // Setup DDR registers. + Self::MISO::set_input(); + Self::MOSI::set_output(); + Self::SCK::set_output(); + Self::SS::set_input(); + + Self::set_master(); + Self::enable_interrupt(); + Self::enable(); + } + + /// Sets up the SPI as a slave. + fn setup_slave() { + // Setup DDR registers. + Self::MISO::set_output(); + Self::MOSI::set_input(); + Self::SCK::set_input(); + Self::SS::set_input(); + + Self::set_slave(); + Self::enable(); + } + + /// Enables interrupts for the spi module. + #[inline(always)] + fn enable_interrupt() { + Self::SPCR::set(spcr::INTERRUPT_ENABLE); + } + + /// Disables interrupts for the spi module. + #[inline(always)] + fn disable_interrupt() { + Self::SPCR::unset(spcr::INTERRUPT_ENABLE); + } + + /// Enables the SPI. + #[inline(always)] + fn enable() { + Self::SPCR::set(spcr::ENABLE); + } + + /// Disables the SPI. + #[inline(always)] + fn disable() { + Self::SPCR::unset(spcr::ENABLE); + } + + /// Enables least-significant-bit first. + #[inline(always)] + fn set_lsb() { + Self::SPCR::set(spcr::DATA_ORDER_LSB); + } + + /// Enables most-significant-bit first. + #[inline(always)] + fn set_msb() { + Self::SPCR::unset(spcr::DATA_ORDER_LSB); + } + + /// Enables master mode. + #[inline(always)] + fn set_master() { + Self::SPCR::set(spcr::MASTER); + } + + /// Enables slave mode. + #[inline(always)] + fn set_slave() { + Self::SPCR::unset(spcr::MASTER); + } + + /// Enables double speed mode. + #[inline(always)] + fn enable_double_speed() { + Self::SPSR::set(spsr::SPI2X); + } + + /// Disables double speed mode. + #[inline(always)] + fn disable_double_speed() { + Self::SPSR::unset(spsr::SPI2X); + } + + /// Checks if there is a write collision. + #[inline(always)] + fn is_write_collision() -> bool { + Self::SPSR::is_set(spsr::WCOL) + } + + /// Sends a byte through the serial. + #[inline(always)] + fn send_byte(byte: u8) { + Self::SPDR::write(byte); + Self::SPSR::wait_until_set(spsr::SPIF); + } + + /// Reads a byte from the serial. + #[inline(always)] + fn receive_byte() -> u8 { + Self::SPSR::wait_until_set(spsr::SPIF); + Self::SPDR::read() + } + + /// Sends and receives a byte. + #[inline(always)] + fn send_receive(byte: u8) -> u8 { + Self::SPDR::write(byte); + Self::SPSR::wait_until_set(spsr::SPIF); + Self::SPDR::read() + } +} + +/// Constants for the control register. +#[allow(dead_code)] +mod spcr { + 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. +#[allow(dead_code)] +mod spsr { + /// 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; +} + From 394e07e160adb15684a380fc243c1d6a4bf3a978 Mon Sep 17 00:00:00 2001 From: Dylan McKay Date: Thu, 31 Aug 2017 01:37:56 +1200 Subject: [PATCH 03/38] Hardware usart support --- build.rs | 29 ++++++++++++++++++++++++++++- src/lib.rs | 2 ++ src/usart.rs | 14 ++++++++++++++ 3 files changed, 44 insertions(+), 1 deletion(-) create mode 100644 src/usart.rs diff --git a/build.rs b/build.rs index 1ccf925..993c088 100644 --- a/build.rs +++ b/build.rs @@ -53,12 +53,13 @@ fn generate_cores_mod_rs(mcus: &[Mcu]) -> Result<(), io::Error> { fn write_core_module(mcu: &Mcu, w: &mut Write) -> Result<(), io::Error> { writeln!(w, "//! Core for {}.", mcu.device.name)?; writeln!(w)?; - writeln!(w, "use {{HardwareSpi, Pin, Register}};")?; + writeln!(w, "use {{HardwareSpi, HardwareUsart, Pin, Register}};")?; writeln!(w)?; gen::write_registers(mcu, w)?; gen::write_pins(mcu, w)?; gen::write_spi_modules(mcu, w)?; + gen::write_usarts(mcu, w)?; writeln!(w) } @@ -152,6 +153,32 @@ mod gen { 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, "pub struct {};", usart.name)?; + writeln!(w)?; + writeln!(w, "impl HardwareUsart for {} {{", usart.name)?; + for register in usart.registers.iter() { + let reg_ty = if register.name.starts_with("UDR") { // the data register. + "UDR".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!("UCSR{}", suffix) + } else if register.name.starts_with("UBRR") { // the baud rate register. + "UBRR".to_owned() + } else { + panic!("unknown usart register '{}'", register.name); + }; + writeln!(w, " type {} = {};", reg_ty, register.name)?; + } + writeln!(w, "}}")?; + 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 599ac9f..4fc6780 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -11,6 +11,7 @@ pub use self::reg::Register; pub use self::pin::Pin; pub use self::spi::HardwareSpi; +pub use self::usart::HardwareUsart; pub mod prelude; pub mod serial; @@ -21,6 +22,7 @@ pub mod cores; mod reg; mod pin; mod spi; +mod usart; pub enum DataDirection { Input, diff --git a/src/usart.rs b/src/usart.rs new file mode 100644 index 0000000..c378138 --- /dev/null +++ b/src/usart.rs @@ -0,0 +1,14 @@ +use Register; + +pub trait HardwareUsart { + /// The USART data register. + type UDR: Register; + /// USART control and status register A. + type UCSRA: Register; + /// USART control and status register B. + type UCSRB: Register; + /// USART control and status register C. + type UCSRC: Register; + /// USART baud rate register. + type UBRR: Register; +} From 61b32145df64243fedeaa9cb208e3bcd138ebec1 Mon Sep 17 00:00:00 2001 From: Dylan McKay Date: Thu, 31 Aug 2017 02:05:59 +1200 Subject: [PATCH 04/38] Improve the names of the Spi trait consts --- build.rs | 19 ++++++++++---- src/spi.rs | 74 ++++++++++++++++++++++++++---------------------------- 2 files changed, 49 insertions(+), 44 deletions(-) diff --git a/build.rs b/build.rs index 993c088..68c62e5 100644 --- a/build.rs +++ b/build.rs @@ -133,15 +133,23 @@ mod gen { .expect("no port signal associated with the spi signal pad"); let pin_name = self::pin_name(port_instance, port_signal); - writeln!(w, " type {} = {};", spi_signal_name, pin_name)?; + 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 ®.caption[..] { - "SPI Data Register" => "SPDR", - "SPI Status Register" => "SPSR", - "SPI Control Register" => "SPCR", - _ => panic!("unknown SPI module register: '{}'", reg.caption), + "SPI Data Register" => "DataRegister", + "SPI Status Register" => "StatusRegister", + "SPI Control Register" => "ControlRegister", + _ => panic!("unknown SPI module register: {}", reg.caption), }; @@ -156,6 +164,7 @@ mod gen { 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 HardwareUsart for {} {{", usart.name)?; diff --git a/src/spi.rs b/src/spi.rs index 71d5892..d36440a 100644 --- a/src/spi.rs +++ b/src/spi.rs @@ -6,29 +6,25 @@ use {Register, Pin}; /// Information at /// http://maxembedded.com/2013/11/the-spi-of-the-avr/ pub trait HardwareSpi { - /// Master-in slave-out pin. - type MISO: Pin; - /// Master-out slave-in pin. - type MOSI: Pin; - /// Serial clock pin. - type SCK: Pin; - /// Slave-select pin. - type SS: Pin; + type MasterInSlaveOut: Pin; + type MasterOutSlaveIn: Pin; + type Clock: Pin; + type SlaveSelect: Pin; /// The SPI control register. - type SPCR: Register; + type ControlRegister: Register; /// The SPI status register. - type SPSR: Register; + type StatusRegister: Register; /// The SPI data register. - type SPDR: Register; + type DataRegister: Register; /// Sets up the SPI as a master. fn setup_master() { // Setup DDR registers. - Self::MISO::set_input(); - Self::MOSI::set_output(); - Self::SCK::set_output(); - Self::SS::set_input(); + Self::MasterInSlaveOut::set_input(); + Self::MasterOutSlaveIn::set_output(); + Self::Clock::set_output(); + Self::SlaveSelect::set_input(); Self::set_master(); Self::enable_interrupt(); @@ -38,10 +34,10 @@ pub trait HardwareSpi { /// Sets up the SPI as a slave. fn setup_slave() { // Setup DDR registers. - Self::MISO::set_output(); - Self::MOSI::set_input(); - Self::SCK::set_input(); - Self::SS::set_input(); + Self::MasterInSlaveOut::set_output(); + Self::MasterOutSlaveIn::set_input(); + Self::Clock::set_input(); + Self::SlaveSelect::set_input(); Self::set_slave(); Self::enable(); @@ -50,95 +46,95 @@ pub trait HardwareSpi { /// Enables interrupts for the spi module. #[inline(always)] fn enable_interrupt() { - Self::SPCR::set(spcr::INTERRUPT_ENABLE); + Self::ControlRegister::set(control_register::INTERRUPT_ENABLE); } /// Disables interrupts for the spi module. #[inline(always)] fn disable_interrupt() { - Self::SPCR::unset(spcr::INTERRUPT_ENABLE); + Self::ControlRegister::unset(control_register::INTERRUPT_ENABLE); } /// Enables the SPI. #[inline(always)] fn enable() { - Self::SPCR::set(spcr::ENABLE); + Self::ControlRegister::set(control_register::ENABLE); } /// Disables the SPI. #[inline(always)] fn disable() { - Self::SPCR::unset(spcr::ENABLE); + Self::ControlRegister::unset(control_register::ENABLE); } /// Enables least-significant-bit first. #[inline(always)] fn set_lsb() { - Self::SPCR::set(spcr::DATA_ORDER_LSB); + Self::ControlRegister::set(control_register::DATA_ORDER_LSB); } /// Enables most-significant-bit first. #[inline(always)] fn set_msb() { - Self::SPCR::unset(spcr::DATA_ORDER_LSB); + Self::ControlRegister::unset(control_register::DATA_ORDER_LSB); } /// Enables master mode. #[inline(always)] fn set_master() { - Self::SPCR::set(spcr::MASTER); + Self::ControlRegister::set(control_register::MASTER); } /// Enables slave mode. #[inline(always)] fn set_slave() { - Self::SPCR::unset(spcr::MASTER); + Self::ControlRegister::unset(control_register::MASTER); } /// Enables double speed mode. #[inline(always)] fn enable_double_speed() { - Self::SPSR::set(spsr::SPI2X); + Self::StatusRegister::set(status_register::SPI2X); } /// Disables double speed mode. #[inline(always)] fn disable_double_speed() { - Self::SPSR::unset(spsr::SPI2X); + Self::StatusRegister::unset(status_register::SPI2X); } /// Checks if there is a write collision. #[inline(always)] fn is_write_collision() -> bool { - Self::SPSR::is_set(spsr::WCOL) + Self::StatusRegister::is_set(status_register::WCOL) } /// Sends a byte through the serial. #[inline(always)] fn send_byte(byte: u8) { - Self::SPDR::write(byte); - Self::SPSR::wait_until_set(spsr::SPIF); + Self::DataRegister::write(byte); + Self::StatusRegister::wait_until_set(status_register::SPIF); } /// Reads a byte from the serial. #[inline(always)] fn receive_byte() -> u8 { - Self::SPSR::wait_until_set(spsr::SPIF); - Self::SPDR::read() + Self::StatusRegister::wait_until_set(status_register::SPIF); + Self::DataRegister::read() } /// Sends and receives a byte. #[inline(always)] fn send_receive(byte: u8) -> u8 { - Self::SPDR::write(byte); - Self::SPSR::wait_until_set(spsr::SPIF); - Self::SPDR::read() + Self::DataRegister::write(byte); + Self::StatusRegister::wait_until_set(status_register::SPIF); + Self::DataRegister::read() } } /// Constants for the control register. #[allow(dead_code)] -mod spcr { +mod control_register { pub const INTERRUPT_ENABLE: u8 = 1<<7; pub const ENABLE: u8 = 1<<6; pub const DATA_ORDER_LSB: u8 = 1<<5; @@ -155,7 +151,7 @@ mod spcr { /// Constants for the status register. #[allow(dead_code)] -mod spsr { +mod status_register { /// SPI interrupt flag. pub const SPIF: u8 = 1<<7; /// Write collision flag. From fcca0f8c27bb1d1883810d7aa6652f90f4c2ef71 Mon Sep 17 00:00:00 2001 From: Dylan McKay Date: Thu, 31 Aug 2017 02:20:28 +1200 Subject: [PATCH 05/38] Place ports into their own module --- build.rs | 40 +++++++++++++++++++++++++--------------- src/usart.rs | 10 +++++----- 2 files changed, 30 insertions(+), 20 deletions(-) diff --git a/build.rs b/build.rs index 68c62e5..b1b5f56 100644 --- a/build.rs +++ b/build.rs @@ -53,7 +53,7 @@ fn generate_cores_mod_rs(mcus: &[Mcu]) -> Result<(), io::Error> { fn write_core_module(mcu: &Mcu, w: &mut Write) -> Result<(), io::Error> { writeln!(w, "//! Core for {}.", mcu.device.name)?; writeln!(w)?; - writeln!(w, "use {{HardwareSpi, HardwareUsart, Pin, Register}};")?; + writeln!(w, "use {{HardwareSpi, HardwareUsart, Register}};")?; writeln!(w)?; gen::write_registers(mcu, w)?; @@ -87,10 +87,17 @@ mod gen { 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 = pin_name(instance, signal); + 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"); @@ -98,22 +105,25 @@ mod gen { .find(|rg| rg.name == instance.name) .expect("no register group defined for this port"); - writeln!(w, "pub struct {};", struct_name)?; + writeln!(w, " pub struct {};", struct_name)?; writeln!(w)?; - writeln!(w, "impl Pin for {} {{", struct_name)?; + 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, " /// {}.", reg.caption)?; + writeln!(w, " type {} = {};", const_name, reg.name)?; } - writeln!(w, " /// {}", signal.pad)?; - writeln!(w, " const MASK: u8 = 1<<{};", idx)?; - writeln!(w, "}}")?; + writeln!(w, " /// {}", signal.pad)?; + writeln!(w, " const MASK: u8 = 1<<{};", idx)?; + writeln!(w, " }}")?; writeln!(w)?; } } + + writeln!(w, "}}")?; + writeln!(w)?; } Ok(()) } @@ -152,11 +162,10 @@ mod gen { _ => panic!("unknown SPI module register: {}", reg.caption), }; - - writeln!(w, " /// {}.", reg.caption)?; writeln!(w, " type {} = {};", const_name, reg.name)?; } writeln!(w, "}}")?; + writeln!(w)?; } Ok(()) } @@ -170,12 +179,12 @@ mod gen { writeln!(w, "impl HardwareUsart for {} {{", usart.name)?; for register in usart.registers.iter() { let reg_ty = if register.name.starts_with("UDR") { // the data register. - "UDR".to_owned() + "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!("UCSR{}", suffix) + format!("ControlRegister{}", suffix) } else if register.name.starts_with("UBRR") { // the baud rate register. - "UBRR".to_owned() + "BaudRateRegister".to_owned() } else { panic!("unknown usart register '{}'", register.name); }; @@ -191,7 +200,8 @@ mod gen { /// Gets the name of a pin. fn pin_name(instance: &Instance, signal: &Signal) -> String { let idx = signal.index.expect("signal with no index"); - format!("{}{}", instance.name, idx) + let letter = instance.name.chars().rev().next().unwrap(); + format!("port::{}{}", letter, idx) } } diff --git a/src/usart.rs b/src/usart.rs index c378138..995b953 100644 --- a/src/usart.rs +++ b/src/usart.rs @@ -2,13 +2,13 @@ use Register; pub trait HardwareUsart { /// The USART data register. - type UDR: Register; + type DataRegister: Register; /// USART control and status register A. - type UCSRA: Register; + type ControlRegisterA: Register; /// USART control and status register B. - type UCSRB: Register; + type ControlRegisterB: Register; /// USART control and status register C. - type UCSRC: Register; + type ControlRegisterC: Register; /// USART baud rate register. - type UBRR: Register; + type BaudRateRegister: Register; } From f1756787dbe8446ca30482c737b2938a94b315af Mon Sep 17 00:00:00 2001 From: Dylan McKay Date: Thu, 31 Aug 2017 02:24:24 +1200 Subject: [PATCH 06/38] Make a module public --- build.rs | 3 ++- src/lib.rs | 4 ++-- src/spi.rs | 5 ++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/build.rs b/build.rs index b1b5f56..9f1ea92 100644 --- a/build.rs +++ b/build.rs @@ -53,7 +53,8 @@ fn generate_cores_mod_rs(mcus: &[Mcu]) -> Result<(), io::Error> { fn write_core_module(mcu: &Mcu, w: &mut Write) -> Result<(), io::Error> { writeln!(w, "//! Core for {}.", mcu.device.name)?; writeln!(w)?; - writeln!(w, "use {{HardwareSpi, HardwareUsart, Register}};")?; + writeln!(w, "use {{HardwareUsart, Register}};")?; + writeln!(w, "use spi::HardwareSpi;")?; writeln!(w)?; gen::write_registers(mcu, w)?; diff --git a/src/lib.rs b/src/lib.rs index 4fc6780..6036bad 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,7 +10,6 @@ pub use self::reg::Register; pub use self::pin::Pin; -pub use self::spi::HardwareSpi; pub use self::usart::HardwareUsart; pub mod prelude; @@ -19,9 +18,10 @@ pub mod timer0; pub mod timer1; pub mod cores; +pub mod spi; + mod reg; mod pin; -mod spi; mod usart; pub enum DataDirection { diff --git a/src/spi.rs b/src/spi.rs index d36440a..216e24b 100644 --- a/src/spi.rs +++ b/src/spi.rs @@ -133,8 +133,7 @@ pub trait HardwareSpi { } /// Constants for the control register. -#[allow(dead_code)] -mod 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; @@ -151,7 +150,7 @@ mod control_register { /// Constants for the status register. #[allow(dead_code)] -mod status_register { +pub mod status_register { /// SPI interrupt flag. pub const SPIF: u8 = 1<<7; /// Write collision flag. From a19ef84d8d4b7e95aff9700ae0db7c66cb123f96 Mon Sep 17 00:00:00 2001 From: Dylan McKay Date: Sat, 23 Sep 2017 16:44:02 +1200 Subject: [PATCH 07/38] Fix typo --- src/pin.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pin.rs b/src/pin.rs index dfb76df..160b11d 100644 --- a/src/pin.rs +++ b/src/pin.rs @@ -2,7 +2,7 @@ use {DataDirection, Register}; /// An IO pin. pub trait Pin { - /// The associated data direction registerr. + /// The associated data direction register. type DDR: Register; /// The associated port register. type PORT: Register; From 72b0169d5301a4f8a0393edad88dfd4aa65d7cbf Mon Sep 17 00:00:00 2001 From: Dylan McKay Date: Sat, 23 Sep 2017 16:50:01 +1200 Subject: [PATCH 08/38] Rename RegVal to Register --- src/lib.rs | 4 ++-- src/{reg.rs => register.rs} | 8 ++++---- src/spi.rs | 2 -- 3 files changed, 6 insertions(+), 8 deletions(-) rename src/{reg.rs => register.rs} (93%) diff --git a/src/lib.rs b/src/lib.rs index 6036bad..691ebce 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,7 +8,7 @@ #![no_std] -pub use self::reg::Register; +pub use self::register::{Register, RegisterValue}; pub use self::pin::Pin; pub use self::usart::HardwareUsart; @@ -20,7 +20,7 @@ pub mod cores; pub mod spi; -mod reg; +mod register; mod pin; mod usart; diff --git a/src/reg.rs b/src/register.rs similarity index 93% rename from src/reg.rs rename to src/register.rs index 194823f..7c18068 100644 --- a/src/reg.rs +++ b/src/register.rs @@ -1,6 +1,6 @@ use core::{cmp, convert, ops}; -pub trait RegVal : Copy + Clone + +pub trait RegisterValue : Copy + Clone + ops::BitAnd + ops::BitAndAssign + ops::BitOr + @@ -14,7 +14,7 @@ pub trait RegVal : Copy + Clone + } /// A register. -pub trait Register { +pub trait Register { /// The address of the register. const ADDR: *mut T; @@ -90,6 +90,6 @@ pub trait Register { } } -impl RegVal for u8 { } -impl RegVal for u16 { } +impl RegisterValue for u8 { } +impl RegisterValue for u16 { } diff --git a/src/spi.rs b/src/spi.rs index 216e24b..fbac626 100644 --- a/src/spi.rs +++ b/src/spi.rs @@ -1,6 +1,5 @@ use {Register, Pin}; - /// An SPI module. /// /// Information at @@ -149,7 +148,6 @@ 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; From 1888fa52d38a0e791c480bed017a009f5683acec Mon Sep 17 00:00:00 2001 From: Dylan McKay Date: Sat, 23 Sep 2017 16:52:09 +1200 Subject: [PATCH 09/38] Propagate arguments to build script --- build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.sh b/build.sh index f780e29..8ef4b3f 100755 --- a/build.sh +++ b/build.sh @@ -1,2 +1,2 @@ #! /bin/sh -xargo build --target avr-atmega328p +xargo build --target avr-atmega328p $@ From 5d65ad4efd9a6e406cbe8d650919c8521fbf4cfa Mon Sep 17 00:00:00 2001 From: Dylan McKay Date: Sat, 23 Sep 2017 17:09:24 +1200 Subject: [PATCH 10/38] Add a few stubs required from std into the library --- src/lib.rs | 5 +++++ src/std_stub.rs | 16 ++++++++++++++++ 2 files changed, 21 insertions(+) create mode 100644 src/std_stub.rs diff --git a/src/lib.rs b/src/lib.rs index 691ebce..7e1dc59 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,6 +3,9 @@ #![feature(asm)] #![feature(no_core)] #![feature(const_fn)] +#![feature(associated_consts)] +#![feature(lang_items)] +#![feature(unwind_attributes)] #![no_core] @@ -23,6 +26,8 @@ pub mod spi; mod register; mod pin; mod usart; +#[doc(hidden)] +pub mod std_stub; pub enum DataDirection { Input, diff --git a/src/std_stub.rs b/src/std_stub.rs new file mode 100644 index 0000000..60bbb60 --- /dev/null +++ b/src/std_stub.rs @@ -0,0 +1,16 @@ +//! 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 ()) -> () { + } + + #[lang = "panic_fmt"] + #[unwind] + pub extern fn rust_begin_panic(_msg: (), _file: &'static str, _line: u32) -> ! { + loop { } + } +} + From 190a3ec8f13c8ab3d4c4e3028bd908a58dd43afc Mon Sep 17 00:00:00 2001 From: Dylan McKay Date: Sat, 23 Sep 2017 17:09:48 +1200 Subject: [PATCH 11/38] Add a cores::current module for getting the current microcontroller --- build.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/build.rs b/build.rs index 9f1ea92..d114de1 100644 --- a/build.rs +++ b/build.rs @@ -44,8 +44,12 @@ fn generate_cores_mod_rs(mcus: &[Mcu]) -> Result<(), io::Error> { writeln!(w, "//! Cores")?; writeln!(w)?; for mcu in mcus { + let module_name = core_module_name(mcu); writeln!(w, "/// The {}.", mcu.device.name)?; - writeln!(w, "pub mod {};", core_module_name(mcu))?; + 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) } From 906b548dfaa2a4e8e0b7564036fc1f664a664391 Mon Sep 17 00:00:00 2001 From: Dylan McKay Date: Fri, 17 Nov 2017 17:18:35 +1300 Subject: [PATCH 12/38] Do more work --- Xargo.toml | 8 +++ build.rs | 47 +++++++++++++- build.sh | 1 + examples/spi.rs | 14 ++++ src/.gitignore | 2 + src/lib.rs | 5 +- src/register.rs | 74 ++++++++++++++++++++- src/spi/clock.rs | 60 ++++++++++++++++++ src/{spi.rs => spi/mod.rs} | 23 +++++-- src/spi/settings.rs | 127 +++++++++++++++++++++++++++++++++++++ src/timer0.rs | 12 ++-- 11 files changed, 358 insertions(+), 15 deletions(-) create mode 100644 Xargo.toml create mode 100644 examples/spi.rs create mode 100644 src/.gitignore create mode 100644 src/spi/clock.rs rename src/{spi.rs => spi/mod.rs} (88%) create mode 100644 src/spi/settings.rs diff --git a/Xargo.toml b/Xargo.toml new file mode 100644 index 0000000..72578c6 --- /dev/null +++ b/Xargo.toml @@ -0,0 +1,8 @@ +[dependencies.std] +features = ["panic_unwind"] + +[dependencies.test] +stage = 1 + +[target.avr-atmega328p.dependencies] +core = { git = "https://github.com/avr-rust/libcore", branch = "rust-26015da0" } diff --git a/build.rs b/build.rs index d114de1..6da6b28 100644 --- a/build.rs +++ b/build.rs @@ -6,8 +6,12 @@ use std::io; use std::io::prelude::*; use std::path::{Path, PathBuf}; +fn src_path() -> PathBuf { + Path::new(env!("CARGO_MANIFEST_DIR")).join("src") +} + fn cores_path() -> PathBuf { - Path::new(env!("CARGO_MANIFEST_DIR")).join("src").join("cores") + src_path().join("cores") } fn core_module_name(mcu: &Mcu) -> String { @@ -21,7 +25,8 @@ fn main() { let current_mcu = avr_mcu::current::mcu() .expect("no target cpu specified"); - generate_cores(&[current_mcu]).unwrap() + generate_config_module().unwrap(); + generate_cores(&[current_mcu]).unwrap(); } fn generate_cores(mcus: &[Mcu]) -> Result<(), io::Error> { @@ -31,6 +36,15 @@ fn generate_cores(mcus: &[Mcu]) -> Result<(), io::Error> { 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"); + writeln!(f, "pub const CPU_FREQUENCY: 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)?; @@ -57,7 +71,7 @@ fn generate_cores_mod_rs(mcus: &[Mcu]) -> Result<(), io::Error> { fn write_core_module(mcu: &Mcu, w: &mut Write) -> Result<(), io::Error> { writeln!(w, "//! Core for {}.", mcu.device.name)?; writeln!(w)?; - writeln!(w, "use {{HardwareUsart, Register}};")?; + writeln!(w, "use {{Mask, Bitset, HardwareUsart, Register}};")?; writeln!(w, "use spi::HardwareSpi;")?; writeln!(w)?; @@ -82,6 +96,33 @@ mod gen { 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 {}: Bitset<{}, Self> = Bitset::new(0x{:x});", bitfield.name, ty, bitfield.mask)?; + + // 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; + } + } + writeln!(w)?; + } + writeln!(w, "}}")?; + writeln!(w)?; + writeln!(w, "impl Register<{}> for {} {{", ty, register.name)?; writeln!(w, " const ADDR: *mut {} = 0x{:x} as *mut {};", ty, register.offset, ty)?; writeln!(w, "}}")?; diff --git a/build.sh b/build.sh index 8ef4b3f..c81f123 100755 --- a/build.sh +++ b/build.sh @@ -1,2 +1,3 @@ #! /bin/sh +export AVR_CPU_FREQUENCY=16000000 xargo build --target avr-atmega328p $@ diff --git a/examples/spi.rs b/examples/spi.rs new file mode 100644 index 0000000..ccecf27 --- /dev/null +++ b/examples/spi.rs @@ -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() { +} + diff --git a/src/.gitignore b/src/.gitignore new file mode 100644 index 0000000..5c921d9 --- /dev/null +++ b/src/.gitignore @@ -0,0 +1,2 @@ +# Generated automatically. +config.rs diff --git a/src/lib.rs b/src/lib.rs index 7e1dc59..4970f7d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,6 +4,8 @@ #![feature(no_core)] #![feature(const_fn)] #![feature(associated_consts)] +#![feature(associated_type_defaults)] +#![feature(const_fn)] #![feature(lang_items)] #![feature(unwind_attributes)] @@ -11,7 +13,7 @@ #![no_std] -pub use self::register::{Register, RegisterValue}; +pub use self::register::{Bitset, Mask, Register, RegisterValue}; pub use self::pin::Pin; pub use self::usart::HardwareUsart; @@ -22,6 +24,7 @@ pub mod timer1; pub mod cores; pub mod spi; +pub mod config; mod register; mod pin; diff --git a/src/register.rs b/src/register.rs index 7c18068..b50151e 100644 --- a/src/register.rs +++ b/src/register.rs @@ -1,4 +1,4 @@ -use core::{cmp, convert, ops}; +use core::{cmp, convert, marker, ops}; pub trait RegisterValue : Copy + Clone + ops::BitAnd + @@ -14,7 +14,9 @@ pub trait RegisterValue : Copy + Clone + } /// A register. -pub trait Register { +pub trait Register : Sized { + type Mask = Mask; + /// The address of the register. const ADDR: *mut T; @@ -33,6 +35,8 @@ pub trait Register { } /// Sets a bitmask in a register. + /// + /// This is equivalent to `r |= mask`. #[inline(always)] fn set(mask: T) { unsafe { @@ -41,6 +45,8 @@ pub trait Register { } /// Clears a bitmask from a register. + /// + /// This is equivalent to `r &= !mask`. #[inline(always)] fn unset(mask: T) { unsafe { @@ -49,6 +55,8 @@ pub trait Register { } /// Toggles a mask in the register. + /// + /// This is equivalent to `r ^= mask`. #[inline(always)] fn toggle(mask: T) { unsafe { @@ -57,6 +65,8 @@ pub trait Register { } /// Checks if a mask is set in the register. + /// + /// This is equivalent to `(r & mask) == mask`. #[inline(always)] fn is_set(mask: T) -> bool { unsafe { @@ -65,6 +75,8 @@ pub trait Register { } /// Checks if a mask is clear in the register. + /// + /// This is equivalent to `(r & mask) == 0`. #[inline(always)] fn is_clear(mask: T) -> bool { unsafe { @@ -90,6 +102,64 @@ pub trait Register { } } +/// A register bitmask. +#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct Bitset> { + mask: T, + _phantom: marker::PhantomData, +} + +/// A register bitmask. +#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct Mask> { + mask: T, + _phantom: marker::PhantomData, +} + +impl Bitset + where T: RegisterValue, R: Register { + /// Creates a new register mask. + pub const fn new(mask: T) -> Self { + Bitset { mask, _phantom: marker::PhantomData } + } + + /// Sets the mask in the register. + /// + /// This is equivalent to `r |= mask`. + pub fn set_all(self) { + R::set(self.mask); + } + + /// Clears the mask from the register. + /// + /// This is equivalent to `r &= !mask`. + pub fn unset_all(self) { + R::unset(self.mask); + } + + /// Toggles the masked bits in the register. + /// + /// This is equivalent to `r ^= mask`. + pub fn toggle_all(self) { + R::toggle(self.mask); + } + + /// Checks if the mask is clear. + /// + /// This is equivalent to `(r & mask) == 0`. + pub fn is_clear(self) -> bool { + R::is_clear(self.mask) + } +} + +impl Mask + where T: RegisterValue, R: Register { + /// Creates a new register mask. + pub const fn new(mask: T) -> Self { + Mask { mask, _phantom: marker::PhantomData } + } +} + impl RegisterValue for u8 { } impl RegisterValue for u16 { } diff --git a/src/spi/clock.rs b/src/spi/clock.rs new file mode 100644 index 0000000..aea8ff0 --- /dev/null +++ b/src/spi/clock.rs @@ -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 / 2 { + 0 + } else if spi_clock >= config::CPU_FREQUENCY / 4 { + 1 + } else if spi_clock >= config::CPU_FREQUENCY / 8 { + 2 + } else if spi_clock >= config::CPU_FREQUENCY / 16 { + 3 + } else if spi_clock >= config::CPU_FREQUENCY / 32 { + 4 + } else if spi_clock >= config::CPU_FREQUENCY / 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 + } +} + diff --git a/src/spi.rs b/src/spi/mod.rs similarity index 88% rename from src/spi.rs rename to src/spi/mod.rs index fbac626..e0298d9 100644 --- a/src/spi.rs +++ b/src/spi/mod.rs @@ -1,3 +1,6 @@ +mod clock; +mod settings; + use {Register, Pin}; /// An SPI module. @@ -18,7 +21,7 @@ pub trait HardwareSpi { type DataRegister: Register; /// Sets up the SPI as a master. - fn setup_master() { + fn setup_master(clock: u32) { // Setup DDR registers. Self::MasterInSlaveOut::set_input(); Self::MasterOutSlaveIn::set_output(); @@ -27,11 +30,11 @@ pub trait HardwareSpi { Self::set_master(); Self::enable_interrupt(); - Self::enable(); + Self::setup_common(clock) } /// Sets up the SPI as a slave. - fn setup_slave() { + fn setup_slave(clock: u32) { // Setup DDR registers. Self::MasterInSlaveOut::set_output(); Self::MasterOutSlaveIn::set_input(); @@ -39,7 +42,19 @@ pub trait HardwareSpi { Self::SlaveSelect::set_input(); Self::set_slave(); - Self::enable(); + 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.control_register_mask()); + Self::StatusRegister::set(mask.status_register_mask()); } /// Enables interrupts for the spi module. diff --git a/src/spi/settings.rs b/src/spi/settings.rs new file mode 100644 index 0000000..d3563dc --- /dev/null +++ b/src/spi/settings.rs @@ -0,0 +1,127 @@ +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. +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. +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/timer0.rs b/src/timer0.rs index 5869b7c..df6ab9f 100644 --- a/src/timer0.rs +++ b/src/timer0.rs @@ -3,6 +3,8 @@ use core::ptr::write_volatile; use super::*; +use cores::atmega328p as c; + pub enum ClockSource { None, Prescale1, @@ -121,18 +123,18 @@ impl Timer { #[inline] pub fn configure(self) { unsafe { - write_volatile(TCCR0A, self.a); - write_volatile(TCCR0B, self.b); + c::TCCR0A::write(self.a); + c::TCCR0B::write(self.b); // Reset counter to zero - write_volatile(TCNT0, 0); + c::TCNT0::write(0); if let Some(v) = self.output_compare_1 { // Set the match - write_volatile(OCR0A, v); + c::OCR0A::write(v); // Enable compare interrupt - write_volatile(TIMSK0, OCIE0A); + c::TIMSK0::OCIE0A.set_all(); } } } From 468289e05fc2c890d2b8d75f5badffb5e0af11a9 Mon Sep 17 00:00:00 2001 From: Dylan McKay Date: Wed, 13 Dec 2017 22:17:28 +1300 Subject: [PATCH 13/38] Support raw things --- src/pin.rs | 14 +++++++------- src/register.rs | 46 +++++++++++++++++++++++++++++++++++----------- src/spi/mod.rs | 32 ++++++++++++++++---------------- 3 files changed, 58 insertions(+), 34 deletions(-) diff --git a/src/pin.rs b/src/pin.rs index 160b11d..b23b2f1 100644 --- a/src/pin.rs +++ b/src/pin.rs @@ -26,13 +26,13 @@ pub trait Pin { /// Sets the pin up as an input. #[inline(always)] fn set_input() { - Self::DDR::unset(Self::MASK); + Self::DDR::unset_raw(Self::MASK); } /// Sets the pin up as an output. #[inline(always)] fn set_output() { - Self::DDR::set(Self::MASK); + Self::DDR::set_raw(Self::MASK); } /// Set the pin to high. @@ -40,7 +40,7 @@ pub trait Pin { /// The pin must be configured as an output. #[inline(always)] fn set_high() { - Self::PORT::set(Self::MASK); + Self::PORT::set_raw(Self::MASK); } /// Set the pin to low. @@ -48,7 +48,7 @@ pub trait Pin { /// The pin must be configured as an output. #[inline(always)] fn set_low() { - Self::PORT::unset(Self::MASK); + Self::PORT::unset_raw(Self::MASK); } /// Toggles the pin. @@ -59,7 +59,7 @@ pub trait Pin { // 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(Self::MASK); + Self::PORT::toggle_raw(Self::MASK); } /// Check if the pin is currently high. @@ -67,7 +67,7 @@ pub trait Pin { /// The pin must be configured as an input. #[inline(always)] fn is_high() -> bool { - Self::PIN::is_set(Self::MASK) + Self::PIN::is_set_raw(Self::MASK) } /// Checks if the pin is currently low. @@ -75,7 +75,7 @@ pub trait Pin { /// The pin must be configured as an input. #[inline(always)] fn is_low() -> bool { - Self::PIN::is_clear(Self::MASK) + Self::PIN::is_clear_raw(Self::MASK) } } diff --git a/src/register.rs b/src/register.rs index b50151e..f3a2c7f 100644 --- a/src/register.rs +++ b/src/register.rs @@ -34,51 +34,71 @@ pub trait Register : Sized { unsafe { *Self::ADDR } } + fn set(mask: Mask) { + Self::set_raw(mask.mask); + } + /// Sets a bitmask in a register. /// /// This is equivalent to `r |= mask`. #[inline(always)] - fn set(mask: T) { + fn set_raw(mask: T) { unsafe { *Self::ADDR |= mask; } } + fn unset(mask: Mask) { + Self::unset_raw(mask.mask); + } + /// Clears a bitmask from a register. /// /// This is equivalent to `r &= !mask`. #[inline(always)] - fn unset(mask: T) { + fn unset_raw(mask: T) { unsafe { *Self::ADDR &= !mask; } } + fn toggle(mask: Mask) { + Self::toggle_raw(mask.mask); + } + /// Toggles a mask in the register. /// /// This is equivalent to `r ^= mask`. #[inline(always)] - fn toggle(mask: T) { + fn toggle_raw(mask: T) { unsafe { *Self::ADDR ^= mask; } } + fn is_set(mask: Mask) -> bool { + Self::is_set_raw(mask.mask) + } + /// Checks if a mask is set in the register. /// /// This is equivalent to `(r & mask) == mask`. #[inline(always)] - fn is_set(mask: T) -> bool { + fn is_set_raw(mask: T) -> bool { unsafe { (*Self::ADDR & mask) == mask } } + fn is_clear(mask: Mask) -> 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(mask: T) -> bool { + fn is_clear_raw(mask: T) -> bool { unsafe { (*Self::ADDR & mask) == T::from(0) } @@ -95,10 +115,14 @@ pub trait Register : Sized { } } + fn wait_until_set(mask: Mask) { + Self::wait_until_set_raw(mask.mask); + } + /// Waits until a mask is set. #[inline(always)] - fn wait_until_set(mask: T) { - Self::wait_until(|| Self::is_set(mask)) + fn wait_until_set_raw(mask: T) { + Self::wait_until(|| Self::is_set_raw(mask)) } } @@ -127,28 +151,28 @@ impl Bitset /// /// This is equivalent to `r |= mask`. pub fn set_all(self) { - R::set(self.mask); + R::set_raw(self.mask); } /// Clears the mask from the register. /// /// This is equivalent to `r &= !mask`. pub fn unset_all(self) { - R::unset(self.mask); + R::unset_raw(self.mask); } /// Toggles the masked bits in the register. /// /// This is equivalent to `r ^= mask`. pub fn toggle_all(self) { - R::toggle(self.mask); + R::toggle_raw(self.mask); } /// Checks if the mask is clear. /// /// This is equivalent to `(r & mask) == 0`. pub fn is_clear(self) -> bool { - R::is_clear(self.mask) + R::is_clear_raw(self.mask) } } diff --git a/src/spi/mod.rs b/src/spi/mod.rs index e0298d9..75f98fd 100644 --- a/src/spi/mod.rs +++ b/src/spi/mod.rs @@ -53,87 +53,87 @@ pub trait HardwareSpi { /// Sets the clock speed. fn set_clock(clock: u32) { let mask = clock::ClockMask::with_clock(clock); - Self::ControlRegister::set(mask.control_register_mask()); - Self::StatusRegister::set(mask.status_register_mask()); + Self::ControlRegister::set_raw(mask.control_register_mask()); + Self::StatusRegister::set_raw(mask.status_register_mask()); } /// Enables interrupts for the spi module. #[inline(always)] fn enable_interrupt() { - Self::ControlRegister::set(control_register::INTERRUPT_ENABLE); + Self::ControlRegister::set_raw(control_register::INTERRUPT_ENABLE); } /// Disables interrupts for the spi module. #[inline(always)] fn disable_interrupt() { - Self::ControlRegister::unset(control_register::INTERRUPT_ENABLE); + Self::ControlRegister::unset_raw(control_register::INTERRUPT_ENABLE); } /// Enables the SPI. #[inline(always)] fn enable() { - Self::ControlRegister::set(control_register::ENABLE); + Self::ControlRegister::set_raw(control_register::ENABLE); } /// Disables the SPI. #[inline(always)] fn disable() { - Self::ControlRegister::unset(control_register::ENABLE); + Self::ControlRegister::unset_raw(control_register::ENABLE); } /// Enables least-significant-bit first. #[inline(always)] fn set_lsb() { - Self::ControlRegister::set(control_register::DATA_ORDER_LSB); + Self::ControlRegister::set_raw(control_register::DATA_ORDER_LSB); } /// Enables most-significant-bit first. #[inline(always)] fn set_msb() { - Self::ControlRegister::unset(control_register::DATA_ORDER_LSB); + Self::ControlRegister::unset_raw(control_register::DATA_ORDER_LSB); } /// Enables master mode. #[inline(always)] fn set_master() { - Self::ControlRegister::set(control_register::MASTER); + Self::ControlRegister::set_raw(control_register::MASTER); } /// Enables slave mode. #[inline(always)] fn set_slave() { - Self::ControlRegister::unset(control_register::MASTER); + Self::ControlRegister::unset_raw(control_register::MASTER); } /// Enables double speed mode. #[inline(always)] fn enable_double_speed() { - Self::StatusRegister::set(status_register::SPI2X); + Self::StatusRegister::set_raw(status_register::SPI2X); } /// Disables double speed mode. #[inline(always)] fn disable_double_speed() { - Self::StatusRegister::unset(status_register::SPI2X); + Self::StatusRegister::unset_raw(status_register::SPI2X); } /// Checks if there is a write collision. #[inline(always)] fn is_write_collision() -> bool { - Self::StatusRegister::is_set(status_register::WCOL) + Self::StatusRegister::is_set_raw(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(status_register::SPIF); + Self::StatusRegister::wait_until_set_raw(status_register::SPIF); } /// Reads a byte from the serial. #[inline(always)] fn receive_byte() -> u8 { - Self::StatusRegister::wait_until_set(status_register::SPIF); + Self::StatusRegister::wait_until_set_raw(status_register::SPIF); Self::DataRegister::read() } @@ -141,7 +141,7 @@ pub trait HardwareSpi { #[inline(always)] fn send_receive(byte: u8) -> u8 { Self::DataRegister::write(byte); - Self::StatusRegister::wait_until_set(status_register::SPIF); + Self::StatusRegister::wait_until_set_raw(status_register::SPIF); Self::DataRegister::read() } } From 1f638dbea3cc9206786e12a394da68c2381d6d6d Mon Sep 17 00:00:00 2001 From: Dylan McKay Date: Wed, 13 Dec 2017 22:24:16 +1300 Subject: [PATCH 14/38] Add a timer trait --- src/lib.rs | 2 ++ src/timer.rs | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) create mode 100644 src/timer.rs diff --git a/src/lib.rs b/src/lib.rs index 4970f7d..6000613 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -15,6 +15,7 @@ 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; @@ -29,6 +30,7 @@ pub mod config; mod register; mod pin; mod usart; +mod timer; #[doc(hidden)] pub mod std_stub; diff --git a/src/timer.rs b/src/timer.rs new file mode 100644 index 0000000..4793dde --- /dev/null +++ b/src/timer.rs @@ -0,0 +1,38 @@ +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; +} + From 274d4611ec6f34c555d12d98d2109d2579dac7b3 Mon Sep 17 00:00:00 2001 From: Dylan McKay Date: Thu, 14 Dec 2017 00:55:57 +1300 Subject: [PATCH 15/38] 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(); - } - } - } -} From d125f69f7d67d2fd42099a3c78c2967731f9640d Mon Sep 17 00:00:00 2001 From: Dylan McKay Date: Thu, 14 Dec 2017 01:33:15 +1300 Subject: [PATCH 16/38] Get 16-bit timers working --- src/lib.rs | 1 - src/modules/mod.rs | 2 +- src/modules/timer/mod.rs | 2 + src/modules/timer/timer16.rs | 211 +++++++++++++++++++++++++++++++++++ src/modules/timer/timer8.rs | 3 +- src/timer1.rs | 159 -------------------------- 6 files changed, 216 insertions(+), 162 deletions(-) create mode 100644 src/modules/timer/timer16.rs delete mode 100644 src/timer1.rs diff --git a/src/lib.rs b/src/lib.rs index eae809d..6b37278 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -19,7 +19,6 @@ pub use self::usart::HardwareUsart; pub mod prelude; pub mod serial; -pub mod timer1; pub mod cores; pub mod modules; diff --git a/src/modules/mod.rs b/src/modules/mod.rs index 238d405..f8ac3bd 100644 --- a/src/modules/mod.rs +++ b/src/modules/mod.rs @@ -1,7 +1,7 @@ //! Modules that can be implemented for specific cores. pub use self::spi::HardwareSpi; -pub use self::timer::{Timer8, Timer8Setup}; +pub use self::timer::{Timer8, Timer8Setup, Timer16, Timer16Setup}; mod spi; mod timer; diff --git a/src/modules/timer/mod.rs b/src/modules/timer/mod.rs index 92412a5..11c28c6 100644 --- a/src/modules/timer/mod.rs +++ b/src/modules/timer/mod.rs @@ -1,4 +1,6 @@ pub use self::timer8::{Timer8, Timer8Setup}; +pub use self::timer16::{Timer16, Timer16Setup}; mod timer8; +mod timer16; diff --git a/src/modules/timer/timer16.rs b/src/modules/timer/timer16.rs new file mode 100644 index 0000000..2f4d7c9 --- /dev/null +++ b/src/modules/timer/timer16.rs @@ -0,0 +1,211 @@ +use {Bitset, Mask, Register}; +use core::marker; + +/// A 16-bit timer. +pub trait Timer16 { + /// The first compare register. + /// For example, OCR0A. + type CompareA: Register; + + /// The second compare register. + /// For example, OCR0B. + type CompareB: Register; + + /// The counter register. + /// + /// For example, TCNT0. + type Counter: Register; + + /// The first control register. + /// + /// For example, TCCR0A. + type ControlA: Register; + + /// The second control register. + /// + /// For example, TCCR0B. + type ControlB: Register; + + /// The third control register. + /// + /// For example, TCCR0C. + type ControlC: Register; + + /// The interrupt mask register. + /// + /// For example, TIMSK0. + type InterruptMask: Register; + + /// The interrupt flag register. + /// + /// For example, TIFR0. + type InterruptFlag: Register; + + const CS0: Mask; + const CS1: Mask; + const CS2: Mask; + + const WGM0: Mask; + const WGM1: Mask; + const WGM2: Mask; + const WGM3: Mask; // fixme: right reg? + + const OCIEA: Bitset; +} + +pub enum ClockSource { + None, + Prescale1, + Prescale8, + Prescale64, + Prescale256, + Prescale1024, + ExternalFalling, + ExternalRising, +} + +impl ClockSource { + fn bits(&self) -> Mask { + use self::ClockSource::*; + + match *self { + None => Mask::zero() | Mask::zero() | Mask::zero(), + Prescale1 => Mask::zero() | Mask::zero() | T::CS0, + Prescale8 => Mask::zero() | T::CS1 | Mask::zero(), + Prescale64 => Mask::zero() | T::CS1 | T::CS0, + Prescale256 => T::CS2 | Mask::zero() | Mask::zero(), + Prescale1024 => T::CS2 | Mask::zero() | T::CS0, + ExternalFalling => T::CS2 | T::CS1 | Mask::zero(), + ExternalRising => T::CS2 | T::CS1 | T::CS0, + } + } + + #[inline] + fn mask() -> Mask { + !(T::CS2 | T::CS1 | T::CS0) + } +} + +pub enum WaveformGenerationMode { + Normal, + PwmPhaseCorrect8Bit, + PwmPhaseCorrect9Bit, + PwmPhaseCorrect10Bit, + ClearOnTimerMatchOutputCompare, + FastPwm8Bit, + FastPwm9Bit, + FastPwm10Bit, + PwmPhaseAndFrequencyCorrectInputCapture, + PwmPhaseAndFrequencyCorrectOutputCompare, + PwmPhaseCorrectInputCapture, + PwmPhaseCorrectOutputCompare, + ClearOnTimerMatchInputCapture, + FastPwmInputCapture, + FastPwmOutputCompare, +} + +impl WaveformGenerationMode { + /// Returns bits for TCCR1A, TCCR1B + #[inline] + fn bits(&self) -> (Mask, Mask) { + use self::WaveformGenerationMode::*; + + // It makes more sense to return bytes (A,B), but the manual + // lists the table as (B,A). We match the manual here for + // inspection purposes and flip the values for sanity + // purposes. + let (b, a) = match *self { + Normal => (Mask::zero() | Mask::zero(), Mask::zero() | Mask::zero()), + PwmPhaseCorrect8Bit => (Mask::zero() | Mask::zero(), Mask::zero() | T::WGM0), + PwmPhaseCorrect9Bit => (Mask::zero() | Mask::zero(), T::WGM1 | Mask::zero()), + PwmPhaseCorrect10Bit => (Mask::zero() | Mask::zero(), T::WGM1 | T::WGM0), + ClearOnTimerMatchOutputCompare => (Mask::zero() | T::WGM2, Mask::zero() | Mask::zero()), + FastPwm8Bit => (Mask::zero() | T::WGM2, Mask::zero() | T::WGM0), + FastPwm9Bit => (Mask::zero() | T::WGM2, T::WGM1 | Mask::zero()), + FastPwm10Bit => (Mask::zero() | T::WGM2, T::WGM1 | T::WGM0), + PwmPhaseAndFrequencyCorrectInputCapture => (T::WGM3 | Mask::zero(), Mask::zero() | Mask::zero()), + PwmPhaseAndFrequencyCorrectOutputCompare => (T::WGM3 | Mask::zero(), Mask::zero() | T::WGM0), + PwmPhaseCorrectInputCapture => (T::WGM3 | Mask::zero(), T::WGM1 | Mask::zero()), + PwmPhaseCorrectOutputCompare => (T::WGM3 | Mask::zero(), T::WGM1 | T::WGM0), + ClearOnTimerMatchInputCapture => (T::WGM3 | T::WGM2, Mask::zero() | Mask::zero()), + // Reserved => (T::WGM3 | T::WGM2, Mask::zero() | T::WGM0), + FastPwmInputCapture => (T::WGM3 | T::WGM2, T::WGM1 | Mask::zero()), + FastPwmOutputCompare => (T::WGM3 | T::WGM2, T::WGM1 | T::WGM0), + }; + + (a, b) + } + + #[inline] + fn mask() -> (Mask, Mask) { + (!(T::WGM0 | T::WGM1), !(T::WGM2 | T::WGM3)) + } +} + +pub struct Timer16Setup { + a: Mask, + b: Mask, + c: Mask, + output_compare_1: Option, + _phantom: marker::PhantomData, +} + +impl Timer16Setup { + #[inline] + pub fn new() -> Self { + Timer16Setup { + a: Mask::zero(), + b: Mask::zero(), + c: Mask::zero(), + output_compare_1: None, + _phantom: marker::PhantomData, + } + } + + #[inline] + pub fn clock_source(mut self, source: ClockSource) -> Self { + self.b &= ClockSource::mask::(); + self.b |= source.bits::(); + self + } + + #[inline] + pub fn waveform_generation_mode(mut self, mode: WaveformGenerationMode) -> Self { + let (a, b) = WaveformGenerationMode::mask::(); + self.a &= a; + self.b &= b; + + let (a, b) = mode.bits::(); + self.a |= a; + self.b |= b; + + self + } + + #[inline] + pub fn output_compare_1(mut self, value: Option) -> Self { + self.output_compare_1 = value; + self + } + + #[inline] + pub fn configure(self) { + unsafe { + T::ControlA::write(self.a); + T::ControlB::write(self.b); + T::ControlC::write(self.c); + + // Reset counter to zero + T::Counter::write(0u16); + + if let Some(v) = self.output_compare_1 { + // Set the match + T::CompareA::write(v); + + // Enable compare interrupt + // FIXME: uncomment + // write_volatile(TIMSK1, OCIE1A); + } + } + } +} diff --git a/src/modules/timer/timer8.rs b/src/modules/timer/timer8.rs index 9d4679a..cdc55d1 100644 --- a/src/modules/timer/timer8.rs +++ b/src/modules/timer/timer8.rs @@ -1,7 +1,7 @@ use {Bitset, Mask, Register}; use core::marker; -/// An 8-bit timer. +/// A 8-bit timer. pub trait Timer8 { /// The first compare register. /// For example, OCR0A. @@ -177,6 +177,7 @@ impl Timer8Setup { T::CompareA::write(v); // Enable compare interrupt + // FIXME: is this right? T::OCIEA.set_all(); } } diff --git a/src/timer1.rs b/src/timer1.rs deleted file mode 100644 index 5c0cfad..0000000 --- a/src/timer1.rs +++ /dev/null @@ -1,159 +0,0 @@ -use core::prelude::v1::*; -use core::ptr::write_volatile; - -use super::*; - -pub enum ClockSource { - None, - Prescale1, - Prescale8, - Prescale64, - Prescale256, - Prescale1024, - ExternalFalling, - ExternalRising, -} - -impl ClockSource { - #[inline] - fn bits(&self) -> u8 { - use self::ClockSource::*; - - match *self { - None => 0 | 0 | 0, - Prescale1 => 0 | 0 | CS10, - Prescale8 => 0 | CS11 | 0, - Prescale64 => 0 | CS11 | CS10, - Prescale256 => CS12 | 0 | 0, - Prescale1024 => CS12 | 0 | CS10, - ExternalFalling => CS12 | CS11 | 0, - ExternalRising => CS12 | CS11 | CS10, - } - } - - #[inline] - fn mask() -> u8 { - !(CS12 | CS11 | CS10) - } -} - -pub enum WaveformGenerationMode { - Normal, - PwmPhaseCorrect8Bit, - PwmPhaseCorrect9Bit, - PwmPhaseCorrect10Bit, - ClearOnTimerMatchOutputCompare, - FastPwm8Bit, - FastPwm9Bit, - FastPwm10Bit, - PwmPhaseAndFrequencyCorrectInputCapture, - PwmPhaseAndFrequencyCorrectOutputCompare, - PwmPhaseCorrectInputCapture, - PwmPhaseCorrectOutputCompare, - ClearOnTimerMatchInputCapture, - FastPwmInputCapture, - FastPwmOutputCompare, -} - -impl WaveformGenerationMode { - /// Returns bits for TCCR1A, TCCR1B - #[inline] - fn bits(&self) -> (u8, u8) { - use self::WaveformGenerationMode::*; - - // It makes more sense to return bytes (A,B), but the manual - // lists the table as (B,A). We match the manual here for - // inspection purposes and flip the values for sanity - // purposes. - let (b, a) = match *self { - Normal => ( 0 | 0, 0 | 0), - PwmPhaseCorrect8Bit => ( 0 | 0, 0 | WGM10), - PwmPhaseCorrect9Bit => ( 0 | 0, WGM11 | 0), - PwmPhaseCorrect10Bit => ( 0 | 0, WGM11 | WGM10), - ClearOnTimerMatchOutputCompare => ( 0 | WGM12, 0 | 0), - FastPwm8Bit => ( 0 | WGM12, 0 | WGM10), - FastPwm9Bit => ( 0 | WGM12, WGM11 | 0), - FastPwm10Bit => ( 0 | WGM12, WGM11 | WGM10), - PwmPhaseAndFrequencyCorrectInputCapture => (WGM13 | 0, 0 | 0), - PwmPhaseAndFrequencyCorrectOutputCompare => (WGM13 | 0, 0 | WGM10), - PwmPhaseCorrectInputCapture => (WGM13 | 0, WGM11 | 0), - PwmPhaseCorrectOutputCompare => (WGM13 | 0, WGM11 | WGM10), - ClearOnTimerMatchInputCapture => (WGM13 | WGM12, 0 | 0), - // Reserved => (WGM13 | WGM12, 0 | WGM10), - FastPwmInputCapture => (WGM13 | WGM12, WGM11 | 0), - FastPwmOutputCompare => (WGM13 | WGM12, WGM11 | WGM10), - }; - - (a, b) - } - - #[inline] - fn mask() -> (u8, u8) { - (!(WGM10 | WGM11), !(WGM12 | WGM13)) - } -} - -pub struct Timer { - a: u8, - b: u8, - c: u8, - output_compare_1: Option, -} - -impl Timer { - #[inline] - pub fn new() -> Self { - Timer { - a: 0, - b: 0, - c: 0, - output_compare_1: None, - } - } - - #[inline] - pub fn clock_source(mut self, source: ClockSource) -> Self { - self.b &= ClockSource::mask(); - self.b |= source.bits(); - self - } - - #[inline] - pub fn waveform_generation_mode(mut self, mode: WaveformGenerationMode) -> Self { - let (a, b) = WaveformGenerationMode::mask(); - self.a &= a; - self.b &= b; - - let (a, b) = mode.bits(); - self.a |= a; - self.b |= b; - - self - } - - #[inline] - pub fn output_compare_1(mut self, value: Option) -> Self { - self.output_compare_1 = value; - self - } - - #[inline] - pub fn configure(self) { - unsafe { - write_volatile(TCCR1A, self.a); - write_volatile(TCCR1B, self.b); - write_volatile(TCCR1C, self.c); - - // Reset counter to zero - write_volatile(TCNT1, 0); - - if let Some(v) = self.output_compare_1 { - // Set the match - write_volatile(OCR1A, v); - - // Enable compare interrupt - write_volatile(TIMSK1, OCIE1A); - } - } - } -} From 0157a8553c17056e5fd8cecf6477bb081db31ab0 Mon Sep 17 00:00:00 2001 From: Dylan McKay Date: Thu, 14 Dec 2017 01:54:47 +1300 Subject: [PATCH 17/38] Implement the Timer16 trait --- build.rs | 39 ++++++++++++++++++++++++++++++++++-- src/lib.rs | 2 -- src/modules/mod.rs | 2 ++ src/modules/timer/timer16.rs | 29 +++++++++++++-------------- src/modules/timer/timer8.rs | 21 +++++++++---------- src/{ => modules}/usart.rs | 0 6 files changed, 62 insertions(+), 31 deletions(-) rename src/{ => modules}/usart.rs (100%) diff --git a/build.rs b/build.rs index bff50ac..6a16bcc 100644 --- a/build.rs +++ b/build.rs @@ -71,7 +71,7 @@ fn generate_cores_mod_rs(mcus: &[Mcu]) -> Result<(), io::Error> { 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 {{Mask, Bitset, Register}};")?; writeln!(w, "use modules;")?; writeln!(w)?; @@ -221,7 +221,7 @@ mod gen { writeln!(w, "/// The {} module.", usart.name)?; writeln!(w, "pub struct {};", usart.name)?; writeln!(w)?; - writeln!(w, "impl HardwareUsart for {} {{", usart.name)?; + 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() @@ -276,6 +276,41 @@ mod gen { 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)) + }; + + 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: Mask = Self::ControlB::CS10;")?; + writeln!(w, " const CS1: Mask = Self::ControlB::CS11;")?; + writeln!(w, " const CS2: Mask = Self::ControlB::CS12;")?; + writeln!(w, " const WGM0: Mask = Self::ControlA::WGM10;")?; + writeln!(w, " const WGM1: Mask = Self::ControlA::WGM11;")?; + writeln!(w, " const WGM2: Mask = Self::ControlB::WGM10;")?; + writeln!(w, " const WGM3: Mask = Self::ControlB::WGM11;")?; + writeln!(w, " const OCIEA: Bitset = Self::InterruptMask::OCIE1A;")?; + writeln!(w, "}}")?; + } + Ok(()) } diff --git a/src/lib.rs b/src/lib.rs index 6b37278..88501b1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -15,7 +15,6 @@ pub use self::register::{Bitset, Mask, Register, RegisterValue}; pub use self::pin::Pin; -pub use self::usart::HardwareUsart; pub mod prelude; pub mod serial; @@ -26,7 +25,6 @@ pub mod config; mod register; mod pin; -mod usart; #[doc(hidden)] pub mod std_stub; diff --git a/src/modules/mod.rs b/src/modules/mod.rs index f8ac3bd..371c7ac 100644 --- a/src/modules/mod.rs +++ b/src/modules/mod.rs @@ -2,7 +2,9 @@ pub use self::spi::HardwareSpi; pub use self::timer::{Timer8, Timer8Setup, Timer16, Timer16Setup}; +pub use self::usart::HardwareUsart; mod spi; mod timer; +mod usart; diff --git a/src/modules/timer/timer16.rs b/src/modules/timer/timer16.rs index 2f4d7c9..24456d8 100644 --- a/src/modules/timer/timer16.rs +++ b/src/modules/timer/timer16.rs @@ -48,9 +48,11 @@ pub trait Timer16 { const WGM0: Mask; const WGM1: Mask; const WGM2: Mask; - const WGM3: Mask; // fixme: right reg? + const WGM3: Mask; const OCIEA: Bitset; + + fn setup() -> Timer16Setup { Timer16Setup::new() } } pub enum ClockSource { @@ -152,7 +154,7 @@ pub struct Timer16Setup { impl Timer16Setup { #[inline] - pub fn new() -> Self { + fn new() -> Self { Timer16Setup { a: Mask::zero(), b: Mask::zero(), @@ -190,22 +192,19 @@ impl Timer16Setup { #[inline] pub fn configure(self) { - unsafe { - T::ControlA::write(self.a); - T::ControlB::write(self.b); - T::ControlC::write(self.c); + T::ControlA::write(self.a); + T::ControlB::write(self.b); + T::ControlC::write(self.c); - // Reset counter to zero - T::Counter::write(0u16); + // Reset counter to zero + T::Counter::write(0u16); - if let Some(v) = self.output_compare_1 { - // Set the match - T::CompareA::write(v); + if let Some(v) = self.output_compare_1 { + // Set the match + T::CompareA::write(v); - // Enable compare interrupt - // FIXME: uncomment - // write_volatile(TIMSK1, OCIE1A); - } + // Enable compare interrupt + T::OCIEA.set_all(); } } } diff --git a/src/modules/timer/timer8.rs b/src/modules/timer/timer8.rs index cdc55d1..4da6603 100644 --- a/src/modules/timer/timer8.rs +++ b/src/modules/timer/timer8.rs @@ -165,21 +165,18 @@ impl Timer8Setup { #[inline] pub fn configure(self) { - unsafe { - T::ControlA::write(self.a); - T::ControlB::write(self.b); + T::ControlA::write(self.a); + T::ControlB::write(self.b); - // Reset counter to zero - T::Counter::write(0); + // Reset counter to zero + T::Counter::write(0); - if let Some(v) = self.output_compare_1 { - // Set the match - T::CompareA::write(v); + if let Some(v) = self.output_compare_1 { + // Set the match + T::CompareA::write(v); - // Enable compare interrupt - // FIXME: is this right? - T::OCIEA.set_all(); - } + // Enable compare interrupt + T::OCIEA.set_all(); } } } diff --git a/src/usart.rs b/src/modules/usart.rs similarity index 100% rename from src/usart.rs rename to src/modules/usart.rs From cb6e0d3b692a7b4d2353601c5d41b136268e2f2d Mon Sep 17 00:00:00 2001 From: Dylan McKay Date: Thu, 14 Dec 2017 02:13:24 +1300 Subject: [PATCH 18/38] Invert the direction of the Register type parameter --- build.rs | 39 +++++++++--------- src/modules/spi/mod.rs | 6 +-- src/modules/timer/timer16.rs | 50 +++++++++++----------- src/modules/timer/timer8.rs | 42 +++++++++---------- src/modules/usart.rs | 10 ++--- src/pin.rs | 6 +-- src/register.rs | 80 +++++++++++++++++------------------- 7 files changed, 115 insertions(+), 118 deletions(-) diff --git a/build.rs b/build.rs index 6a16bcc..73d9814 100644 --- a/build.rs +++ b/build.rs @@ -102,7 +102,7 @@ mod gen { writeln!(w, "impl {} {{", register.name)?; for bitfield in register.bitfields.iter() { // Create a mask for the whole bitset. - writeln!(w, " pub const {}: Bitset<{}, Self> = Bitset::new(0x{:x});", bitfield.name, ty, bitfield.mask)?; + writeln!(w, " pub const {}: Bitset = Bitset::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. @@ -110,8 +110,8 @@ mod gen { 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)?; + writeln!(w, " pub const {}{}: Mask = Mask::new(1<<{});", + bitfield.name, current_mask_bit_num, current_register_bit_num)?; current_mask_bit_num += 1; } @@ -122,7 +122,8 @@ mod gen { writeln!(w, "}}")?; writeln!(w)?; - writeln!(w, "impl Register<{}> for {} {{", ty, register.name)?; + writeln!(w, "impl Register for {} {{", register.name)?; + writeln!(w, " type T = {};", ty)?; writeln!(w, " const ADDR: *mut {} = 0x{:x} as *mut {};", ty, register.offset, ty)?; writeln!(w, "}}")?; } @@ -266,13 +267,13 @@ mod gen { 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, " 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, "}}")?; } @@ -300,14 +301,14 @@ mod gen { 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: Mask = Self::ControlB::CS10;")?; - writeln!(w, " const CS1: Mask = Self::ControlB::CS11;")?; - writeln!(w, " const CS2: Mask = Self::ControlB::CS12;")?; - writeln!(w, " const WGM0: Mask = Self::ControlA::WGM10;")?; - writeln!(w, " const WGM1: Mask = Self::ControlA::WGM11;")?; - writeln!(w, " const WGM2: Mask = Self::ControlB::WGM10;")?; - writeln!(w, " const WGM3: Mask = Self::ControlB::WGM11;")?; - writeln!(w, " const OCIEA: Bitset = Self::InterruptMask::OCIE1A;")?; + writeln!(w, " const CS0: Mask = Self::ControlB::CS10;")?; + writeln!(w, " const CS1: Mask = Self::ControlB::CS11;")?; + writeln!(w, " const CS2: Mask = Self::ControlB::CS12;")?; + writeln!(w, " const WGM0: Mask = Self::ControlA::WGM10;")?; + writeln!(w, " const WGM1: Mask = Self::ControlA::WGM11;")?; + writeln!(w, " const WGM2: Mask = Self::ControlB::WGM10;")?; + writeln!(w, " const WGM3: Mask = Self::ControlB::WGM11;")?; + writeln!(w, " const OCIEA: Bitset = Self::InterruptMask::OCIE1A;")?; writeln!(w, "}}")?; } diff --git a/src/modules/spi/mod.rs b/src/modules/spi/mod.rs index 852b70e..64be15e 100644 --- a/src/modules/spi/mod.rs +++ b/src/modules/spi/mod.rs @@ -14,11 +14,11 @@ pub trait HardwareSpi { type SlaveSelect: Pin; /// The SPI control register. - type ControlRegister: Register; + type ControlRegister: Register; /// The SPI status register. - type StatusRegister: Register; + type StatusRegister: Register; /// The SPI data register. - type DataRegister: Register; + type DataRegister: Register; /// Sets up the SPI as a master. fn setup_master(clock: u32) { diff --git a/src/modules/timer/timer16.rs b/src/modules/timer/timer16.rs index 24456d8..a7dfcb4 100644 --- a/src/modules/timer/timer16.rs +++ b/src/modules/timer/timer16.rs @@ -2,57 +2,57 @@ use {Bitset, Mask, Register}; use core::marker; /// A 16-bit timer. -pub trait Timer16 { +pub trait Timer16 : Sized { /// The first compare register. /// For example, OCR0A. - type CompareA: Register; + type CompareA: Register; /// The second compare register. /// For example, OCR0B. - type CompareB: Register; + type CompareB: Register; /// The counter register. /// /// For example, TCNT0. - type Counter: Register; + type Counter: Register; /// The first control register. /// /// For example, TCCR0A. - type ControlA: Register; + type ControlA: Register; /// The second control register. /// /// For example, TCCR0B. - type ControlB: Register; + type ControlB: Register; /// The third control register. /// /// For example, TCCR0C. - type ControlC: Register; + type ControlC: Register; /// The interrupt mask register. /// /// For example, TIMSK0. - type InterruptMask: Register; + type InterruptMask: Register; /// The interrupt flag register. /// /// For example, TIFR0. - type InterruptFlag: Register; + type InterruptFlag: Register; - const CS0: Mask; - const CS1: Mask; - const CS2: Mask; + const CS0: Mask; + const CS1: Mask; + const CS2: Mask; - const WGM0: Mask; - const WGM1: Mask; - const WGM2: Mask; - const WGM3: Mask; + const WGM0: Mask; + const WGM1: Mask; + const WGM2: Mask; + const WGM3: Mask; - const OCIEA: Bitset; + const OCIEA: Bitset; - fn setup() -> Timer16Setup { Timer16Setup::new() } + fn setup() -> Timer16Setup { Timer16Setup::new() } } pub enum ClockSource { @@ -67,7 +67,7 @@ pub enum ClockSource { } impl ClockSource { - fn bits(&self) -> Mask { + fn bits(&self) -> Mask { use self::ClockSource::*; match *self { @@ -83,7 +83,7 @@ impl ClockSource { } #[inline] - fn mask() -> Mask { + fn mask() -> Mask { !(T::CS2 | T::CS1 | T::CS0) } } @@ -109,7 +109,7 @@ pub enum WaveformGenerationMode { impl WaveformGenerationMode { /// Returns bits for TCCR1A, TCCR1B #[inline] - fn bits(&self) -> (Mask, Mask) { + fn bits(&self) -> (Mask, Mask) { use self::WaveformGenerationMode::*; // It makes more sense to return bytes (A,B), but the manual @@ -139,15 +139,15 @@ impl WaveformGenerationMode { } #[inline] - fn mask() -> (Mask, Mask) { + fn mask() -> (Mask, Mask) { (!(T::WGM0 | T::WGM1), !(T::WGM2 | T::WGM3)) } } pub struct Timer16Setup { - a: Mask, - b: Mask, - c: Mask, + a: Mask, + b: Mask, + c: Mask, output_compare_1: Option, _phantom: marker::PhantomData, } diff --git a/src/modules/timer/timer8.rs b/src/modules/timer/timer8.rs index 4da6603..e2c2e2e 100644 --- a/src/modules/timer/timer8.rs +++ b/src/modules/timer/timer8.rs @@ -2,49 +2,49 @@ use {Bitset, Mask, Register}; use core::marker; /// A 8-bit timer. -pub trait Timer8 { +pub trait Timer8 : Sized { /// The first compare register. /// For example, OCR0A. - type CompareA: Register; + type CompareA: Register; /// The second compare register. /// For example, OCR0B. - type CompareB: Register; + type CompareB: Register; /// The counter register. /// /// For example, TCNT0. - type Counter: Register; + type Counter: Register; /// The first control register. /// /// For example, TCCR0A. - type ControlA: Register; + type ControlA: Register; /// The second control register. /// /// For example, TCCR0B. - type ControlB: Register; + type ControlB: Register; /// The interrupt mask register. /// /// For example, TIMSK0. - type InterruptMask: Register; + type InterruptMask: Register; /// The interrupt flag register. /// /// For example, TIFR0. - type InterruptFlag: Register; + type InterruptFlag: Register; - const CS0: Mask; - const CS1: Mask; - const CS2: Mask; + const CS0: Mask; + const CS1: Mask; + const CS2: Mask; - const WGM0: Mask; - const WGM1: Mask; - const WGM2: Mask; + const WGM0: Mask; + const WGM1: Mask; + const WGM2: Mask; - const OCIEA: Bitset; + const OCIEA: Bitset; } pub enum ClockSource { @@ -59,7 +59,7 @@ pub enum ClockSource { } impl ClockSource { - fn bits(&self) -> Mask { + fn bits(&self) -> Mask { use self::ClockSource::*; match *self { @@ -75,7 +75,7 @@ impl ClockSource { } #[inline] - fn mask() -> Mask { + fn mask() -> Mask { !(T::CS2 | T::CS1 | T::CS0) } } @@ -92,7 +92,7 @@ pub enum WaveformGenerationMode { impl WaveformGenerationMode { /// Returns bits for TCCR0A, TCCR0B #[inline] - fn bits(&self) -> (Mask, Mask) { + fn bits(&self) -> (Mask, Mask) { use self::WaveformGenerationMode::*; // It makes more sense to return bytes (A,B), but the manual @@ -114,14 +114,14 @@ impl WaveformGenerationMode { } #[inline] - fn mask() -> (Mask, Mask) { + fn mask() -> (Mask, Mask) { (!(T::WGM0 | T::WGM1), !(T::WGM2)) } } pub struct Timer8Setup { - a: Mask, - b: Mask, + a: Mask, + b: Mask, output_compare_1: Option, _phantom: marker::PhantomData, } diff --git a/src/modules/usart.rs b/src/modules/usart.rs index 995b953..7e8bc77 100644 --- a/src/modules/usart.rs +++ b/src/modules/usart.rs @@ -2,13 +2,13 @@ use Register; pub trait HardwareUsart { /// The USART data register. - type DataRegister: Register; + type DataRegister: Register; /// USART control and status register A. - type ControlRegisterA: Register; + type ControlRegisterA: Register; /// USART control and status register B. - type ControlRegisterB: Register; + type ControlRegisterB: Register; /// USART control and status register C. - type ControlRegisterC: Register; + type ControlRegisterC: Register; /// USART baud rate register. - type BaudRateRegister: Register; + type BaudRateRegister: Register; } diff --git a/src/pin.rs b/src/pin.rs index b23b2f1..758b89e 100644 --- a/src/pin.rs +++ b/src/pin.rs @@ -3,14 +3,14 @@ use {DataDirection, Register}; /// An IO pin. pub trait Pin { /// The associated data direction register. - type DDR: Register; + type DDR: Register; /// The associated port register. - type PORT: Register; + type PORT: Register; /// The associated pin register. /// /// Reads from the register will read input bits. /// Writes to the register will toggle bits. - type PIN: Register; + type PIN: Register; /// The mask of the pin used for accessing registers. const MASK: u8; diff --git a/src/register.rs b/src/register.rs index c543e96..6442188 100644 --- a/src/register.rs +++ b/src/register.rs @@ -14,15 +14,16 @@ pub trait RegisterValue : Copy + Clone + } /// A register. -pub trait Register : Sized { - type Mask = Mask; +pub trait Register : Sized { + type T: RegisterValue; + type Mask = Mask; /// The address of the register. - const ADDR: *mut T; + const ADDR: *mut Self::T; /// Writes a value to the register. #[inline(always)] - fn write(value: V) where V: Into { + fn write(value: V) where V: Into { unsafe { *Self::ADDR = value.into(); } @@ -30,11 +31,11 @@ pub trait Register : Sized { /// Reads the value of the register. #[inline(always)] - fn read() -> T { + fn read() -> Self::T { unsafe { *Self::ADDR } } - fn set(mask: Mask) { + fn set(mask: Mask) { Self::set_raw(mask.mask); } @@ -42,13 +43,13 @@ pub trait Register : Sized { /// /// This is equivalent to `r |= mask`. #[inline(always)] - fn set_raw(mask: T) { + fn set_raw(mask: Self::T) { unsafe { *Self::ADDR |= mask; } } - fn unset(mask: Mask) { + fn unset(mask: Mask) { Self::unset_raw(mask.mask); } @@ -56,13 +57,13 @@ pub trait Register : Sized { /// /// This is equivalent to `r &= !mask`. #[inline(always)] - fn unset_raw(mask: T) { + fn unset_raw(mask: Self::T) { unsafe { *Self::ADDR &= !mask; } } - fn toggle(mask: Mask) { + fn toggle(mask: Mask) { Self::toggle_raw(mask.mask); } @@ -70,13 +71,13 @@ pub trait Register : Sized { /// /// This is equivalent to `r ^= mask`. #[inline(always)] - fn toggle_raw(mask: T) { + fn toggle_raw(mask: Self::T) { unsafe { *Self::ADDR ^= mask; } } - fn is_set(mask: Mask) -> bool { + fn is_set(mask: Mask) -> bool { Self::is_set_raw(mask.mask) } @@ -84,13 +85,13 @@ pub trait Register : Sized { /// /// This is equivalent to `(r & mask) == mask`. #[inline(always)] - fn is_set_raw(mask: T) -> bool { + fn is_set_raw(mask: Self::T) -> bool { unsafe { (*Self::ADDR & mask) == mask } } - fn is_clear(mask: Mask) -> bool { + fn is_clear(mask: Mask) -> bool { Self::is_clear_raw(mask.mask) } @@ -98,9 +99,9 @@ pub trait Register : Sized { /// /// This is equivalent to `(r & mask) == 0`. #[inline(always)] - fn is_clear_raw(mask: T) -> bool { + fn is_clear_raw(mask: Self::T) -> bool { unsafe { - (*Self::ADDR & mask) == T::from(0) + (*Self::ADDR & mask) == Self::T::from(0) } } @@ -115,35 +116,34 @@ pub trait Register : Sized { } } - fn wait_until_set(mask: Mask) { + fn wait_until_set(mask: Mask) { Self::wait_until_set_raw(mask.mask); } /// Waits until a mask is set. #[inline(always)] - fn wait_until_set_raw(mask: T) { + fn wait_until_set_raw(mask: Self::T) { Self::wait_until(|| Self::is_set_raw(mask)) } } /// A register bitmask. #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct Bitset> { - mask: T, +pub struct Bitset { + mask: R::T, _phantom: marker::PhantomData, } /// A register bitmask. #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct Mask> { - mask: T, +pub struct Mask { + mask: R::T, _phantom: marker::PhantomData, } -impl Bitset - where T: RegisterValue, R: Register { +impl Bitset where R: Register { /// Creates a new register mask. - pub const fn new(mask: T) -> Self { + pub const fn new(mask: R::T) -> Self { Bitset { mask, _phantom: marker::PhantomData } } @@ -176,10 +176,9 @@ impl Bitset } } -impl Mask - where T: RegisterValue, R: Register { +impl Mask where R: Register { /// Creates a new register mask. - pub const fn new(mask: T) -> Self { + pub const fn new(mask: R::T) -> Self { Mask { mask, _phantom: marker::PhantomData } } @@ -188,8 +187,7 @@ impl Mask } } -impl ops::BitOr for Mask - where T: RegisterValue, R: Register +impl ops::BitOr for Mask where R: Register { type Output = Self; @@ -198,15 +196,13 @@ impl ops::BitOr for Mask } } -impl ops::BitOrAssign for Mask - where T: RegisterValue, R: Register { +impl ops::BitOrAssign for Mask where R: Register { fn bitor_assign(&mut self, rhs: Self) { self.mask |= rhs.mask; } } -impl ops::BitAnd for Mask - where T: RegisterValue, R: Register +impl ops::BitAnd for Mask where R: Register { type Output = Self; @@ -215,15 +211,13 @@ impl ops::BitAnd for Mask } } -impl ops::BitAndAssign for Mask - where T: RegisterValue, R: Register { +impl ops::BitAndAssign for Mask where R: Register { fn bitand_assign(&mut self, rhs: Self) { self.mask &= rhs.mask; } } -impl ops::Not for Mask - where T: RegisterValue, R: Register { +impl ops::Not for Mask where R: Register { type Output = Self; fn not(self) -> Self { @@ -231,10 +225,12 @@ impl ops::Not for Mask } } -impl Into for Mask where R: Register { - fn into(self) -> u8 { - self.mask - } +impl Into for Mask where R: Register { + fn into(self) -> u8 { self.mask } +} + +impl Into for Mask where R: Register { + fn into(self) -> u16 { self.mask } } impl RegisterValue for u8 { } From ea1aef9b1af728812ade54ec77ea9dc5ce3f0a52 Mon Sep 17 00:00:00 2001 From: Dylan McKay Date: Thu, 14 Dec 2017 02:22:40 +1300 Subject: [PATCH 19/38] Remove as much atmega328p-hardcoded stuff as possible --- src/lib.rs | 126 -------------------------------------------------- src/serial.rs | 46 +++++++++++++++++- 2 files changed, 44 insertions(+), 128 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 88501b1..18ac3b9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -33,129 +33,3 @@ pub enum DataDirection { Output, } -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; diff --git a/src/serial.rs b/src/serial.rs index 76e9643..acbc193 100644 --- a/src/serial.rs +++ b/src/serial.rs @@ -1,8 +1,10 @@ +//! A serial. +//! +//! *WARNING* The current implementation of this will only work on ATmega328. + use core::prelude::v1::*; use core::ptr::{read_volatile, write_volatile}; -use super::*; - pub enum CharacterSize { FiveBits, SixBits, @@ -107,6 +109,8 @@ impl StopBits { } } +/// A serial connection. +/// *WARNING* The current implementation of this will only work on ATmega328. pub struct Serial { ubrr: u16, a: u8, @@ -224,3 +228,41 @@ pub fn try_receive() -> Option { 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, UCPOL0 ]); + register!(0xC1, UCSR0B, [RXCIE0, TXCIE0, UDRIE0, RXEN0, TXEN0, UCSZ02, RXB80, TXB80 ]); + register!(0xC0, UCSR0A, [RXC0, TXC0, UDRE0, FE0, DOR0, UPE0, U2X0, MPCM0 ]); + + // 16-bit register pairs + pub const UBRR0: *mut u16 = UBRR0L as *mut u16; +} From c5dac9d7c0cbfb82cc23c97c465b163d3f1a1900 Mon Sep 17 00:00:00 2001 From: Dylan McKay Date: Thu, 14 Dec 2017 02:28:11 +1300 Subject: [PATCH 20/38] Move the serial module into a 'legacy' module --- src/legacy/mod.rs | 9 +++++++++ src/{ => legacy}/serial.rs | 0 src/lib.rs | 9 ++------- src/pin.rs | 7 ++++++- 4 files changed, 17 insertions(+), 8 deletions(-) create mode 100644 src/legacy/mod.rs rename src/{ => legacy}/serial.rs (100%) diff --git a/src/legacy/mod.rs b/src/legacy/mod.rs new file mode 100644 index 0000000..7aaba83 --- /dev/null +++ b/src/legacy/mod.rs @@ -0,0 +1,9 @@ +//! Legacy code. +//! +//! The code in here needs to be cleaned up and rewritten. +//! +//! Once a replacement exists, these legacy modules may be removed +//! in a major release! + +pub mod serial; + diff --git a/src/serial.rs b/src/legacy/serial.rs similarity index 100% rename from src/serial.rs rename to src/legacy/serial.rs diff --git a/src/lib.rs b/src/lib.rs index 18ac3b9..770b487 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -14,10 +14,10 @@ #![no_std] pub use self::register::{Bitset, Mask, Register, RegisterValue}; -pub use self::pin::Pin; +pub use self::pin::{DataDirection, Pin}; pub mod prelude; -pub mod serial; +pub mod legacy; pub mod cores; pub mod modules; @@ -28,8 +28,3 @@ mod pin; #[doc(hidden)] pub mod std_stub; -pub enum DataDirection { - Input, - Output, -} - diff --git a/src/pin.rs b/src/pin.rs index 758b89e..c917721 100644 --- a/src/pin.rs +++ b/src/pin.rs @@ -1,4 +1,9 @@ -use {DataDirection, Register}; +use Register; + +pub enum DataDirection { + Input, + Output, +} /// An IO pin. pub trait Pin { From 3e29e87d3817e8883c3601cde7e93a9b8f1c59f3 Mon Sep 17 00:00:00 2001 From: Dylan McKay Date: Thu, 14 Dec 2017 02:30:20 +1300 Subject: [PATCH 21/38] Rename ADDR to ADDRESS --- build.rs | 2 +- src/register.rs | 17 +++++++++-------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/build.rs b/build.rs index 73d9814..b735a9f 100644 --- a/build.rs +++ b/build.rs @@ -124,7 +124,7 @@ mod gen { writeln!(w, "impl Register for {} {{", register.name)?; writeln!(w, " type T = {};", ty)?; - writeln!(w, " const ADDR: *mut {} = 0x{:x} as *mut {};", ty, register.offset, ty)?; + writeln!(w, " const ADDRESS: *mut {} = 0x{:x} as *mut {};", ty, register.offset, ty)?; writeln!(w, "}}")?; } diff --git a/src/register.rs b/src/register.rs index 6442188..7f11221 100644 --- a/src/register.rs +++ b/src/register.rs @@ -1,5 +1,6 @@ use core::{cmp, convert, marker, ops}; +/// A value that a register can store. pub trait RegisterValue : Copy + Clone + ops::BitAnd + ops::BitAndAssign + @@ -19,20 +20,20 @@ pub trait Register : Sized { type Mask = Mask; /// The address of the register. - const ADDR: *mut Self::T; + const ADDRESS: *mut Self::T; /// Writes a value to the register. #[inline(always)] fn write(value: V) where V: Into { unsafe { - *Self::ADDR = value.into(); + *Self::ADDRESS = value.into(); } } /// Reads the value of the register. #[inline(always)] fn read() -> Self::T { - unsafe { *Self::ADDR } + unsafe { *Self::ADDRESS } } fn set(mask: Mask) { @@ -45,7 +46,7 @@ pub trait Register : Sized { #[inline(always)] fn set_raw(mask: Self::T) { unsafe { - *Self::ADDR |= mask; + *Self::ADDRESS |= mask; } } @@ -59,7 +60,7 @@ pub trait Register : Sized { #[inline(always)] fn unset_raw(mask: Self::T) { unsafe { - *Self::ADDR &= !mask; + *Self::ADDRESS &= !mask; } } @@ -73,7 +74,7 @@ pub trait Register : Sized { #[inline(always)] fn toggle_raw(mask: Self::T) { unsafe { - *Self::ADDR ^= mask; + *Self::ADDRESS ^= mask; } } @@ -87,7 +88,7 @@ pub trait Register : Sized { #[inline(always)] fn is_set_raw(mask: Self::T) -> bool { unsafe { - (*Self::ADDR & mask) == mask + (*Self::ADDRESS & mask) == mask } } @@ -101,7 +102,7 @@ pub trait Register : Sized { #[inline(always)] fn is_clear_raw(mask: Self::T) -> bool { unsafe { - (*Self::ADDR & mask) == Self::T::from(0) + (*Self::ADDRESS & mask) == Self::T::from(0) } } From d3d41e457a2793baf11072f194b2138f50fe0c5a Mon Sep 17 00:00:00 2001 From: Dylan McKay Date: Thu, 14 Dec 2017 02:31:24 +1300 Subject: [PATCH 22/38] Silence the half-written module --- src/modules/spi/mod.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/modules/spi/mod.rs b/src/modules/spi/mod.rs index 64be15e..e6cdbd1 100644 --- a/src/modules/spi/mod.rs +++ b/src/modules/spi/mod.rs @@ -1,5 +1,8 @@ mod clock; -mod settings; + + +// FIXME: Start using this module or delete!!! +#[allow(dead_code)] mod settings; use {Register, Pin}; From c5946dc846b289045a3ef8372d8bf839f78b140d Mon Sep 17 00:00:00 2001 From: Dylan McKay Date: Thu, 14 Dec 2017 02:38:06 +1300 Subject: [PATCH 23/38] Remove all compiler warnings --- src/legacy/serial.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/legacy/serial.rs b/src/legacy/serial.rs index acbc193..610cd45 100644 --- a/src/legacy/serial.rs +++ b/src/legacy/serial.rs @@ -257,11 +257,11 @@ mod hack { }; } - register!(0xC6, UDR0 ); - 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!(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; From 76298abdb377f96830d51b864f7a271ff229ff6a Mon Sep 17 00:00:00 2001 From: Dylan McKay Date: Thu, 14 Dec 2017 02:50:06 +1300 Subject: [PATCH 24/38] Add myself to authors --- Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/Cargo.toml b/Cargo.toml index 51034a4..f6d610c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,6 +4,7 @@ version = "0.1.1" authors = [ "The AVR-Rust Project Developers", "Jake Goulding ", + "Dylan McKay ", ] license = "MIT/Apache-2.0" readme = "README.md" From e1a05bbf96185a325cb1f24439fd5b3b8a43e8d1 Mon Sep 17 00:00:00 2001 From: Dylan McKay Date: Thu, 14 Dec 2017 02:53:28 +1300 Subject: [PATCH 25/38] Move the build script into a subdir --- Cargo.toml | 4 + build.rs | 325 ---------------------------------------- core_generator/build.rs | 88 +++++++++++ core_generator/gen.rs | 236 +++++++++++++++++++++++++++++ 4 files changed, 328 insertions(+), 325 deletions(-) delete mode 100644 build.rs create mode 100644 core_generator/build.rs create mode 100644 core_generator/gen.rs diff --git a/Cargo.toml b/Cargo.toml index f6d610c..81a3fe4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,12 +6,16 @@ authors = [ "Jake Goulding ", "Dylan McKay ", ] + license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/avr-rust/ruduino" description = """ Reusable components for the Arduino Uno. """ + +build = "core_generator/build.rs" + keywords = ["avr", "arduino", "uno"] [build-dependencies] diff --git a/build.rs b/build.rs deleted file mode 100644 index b735a9f..0000000 --- a/build.rs +++ /dev/null @@ -1,325 +0,0 @@ -extern crate avr_mcu; - -use avr_mcu::*; -use std::fs::{self, File}; -use std::io; -use std::io::prelude::*; -use std::path::{Path, PathBuf}; - -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 = avr_mcu::current::mcu() - .expect("no target cpu specified"); - 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"); - writeln!(f, "pub const CPU_FREQUENCY: 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, "//! Cores")?; - 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 {{Mask, Bitset, 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) -} - -mod gen { - 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 {}: Bitset = Bitset::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 {}{}: Mask = Mask::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 ®.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)) - }; - - 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, "}}")?; - } - - 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)) - }; - - 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: Mask = Self::ControlB::CS10;")?; - writeln!(w, " const CS1: Mask = Self::ControlB::CS11;")?; - writeln!(w, " const CS2: Mask = Self::ControlB::CS12;")?; - writeln!(w, " const WGM0: Mask = Self::ControlA::WGM10;")?; - writeln!(w, " const WGM1: Mask = Self::ControlA::WGM11;")?; - writeln!(w, " const WGM2: Mask = Self::ControlB::WGM10;")?; - writeln!(w, " const WGM3: Mask = Self::ControlB::WGM11;")?; - writeln!(w, " const OCIEA: Bitset = Self::InterruptMask::OCIE1A;")?; - 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) - } -} - diff --git a/core_generator/build.rs b/core_generator/build.rs new file mode 100644 index 0000000..d69a66e --- /dev/null +++ b/core_generator/build.rs @@ -0,0 +1,88 @@ +extern crate avr_mcu; + +use avr_mcu::*; +use std::fs::{self, File}; +use std::io; +use std::io::prelude::*; +use std::path::{Path, PathBuf}; + +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 = avr_mcu::current::mcu() + .expect("no target cpu specified"); + 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"); + writeln!(f, "pub const CPU_FREQUENCY: 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, "//! Cores")?; + 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 {{Mask, Bitset, 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) +} + +mod gen; + diff --git a/core_generator/gen.rs b/core_generator/gen.rs new file mode 100644 index 0000000..40fe789 --- /dev/null +++ b/core_generator/gen.rs @@ -0,0 +1,236 @@ +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 {}: Bitset = Bitset::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 {}{}: Mask = Mask::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 ®.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)) + }; + + 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, "}}")?; + } + + 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)) + }; + + 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: Mask = Self::ControlB::CS10;")?; + writeln!(w, " const CS1: Mask = Self::ControlB::CS11;")?; + writeln!(w, " const CS2: Mask = Self::ControlB::CS12;")?; + writeln!(w, " const WGM0: Mask = Self::ControlA::WGM10;")?; + writeln!(w, " const WGM1: Mask = Self::ControlA::WGM11;")?; + writeln!(w, " const WGM2: Mask = Self::ControlB::WGM10;")?; + writeln!(w, " const WGM3: Mask = Self::ControlB::WGM11;")?; + writeln!(w, " const OCIEA: Bitset = Self::InterruptMask::OCIE1A;")?; + 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) +} From 3f3c8e255974fae5ba9f9489cae6c5dd670d9788 Mon Sep 17 00:00:00 2001 From: Dylan McKay Date: Thu, 14 Dec 2017 02:57:45 +1300 Subject: [PATCH 26/38] Move 'mod' to more appropriate place --- core_generator/build.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core_generator/build.rs b/core_generator/build.rs index d69a66e..7252cc7 100644 --- a/core_generator/build.rs +++ b/core_generator/build.rs @@ -1,5 +1,7 @@ extern crate avr_mcu; +mod gen; + use avr_mcu::*; use std::fs::{self, File}; use std::io; @@ -84,5 +86,3 @@ fn write_core_module(mcu: &Mcu, w: &mut Write) -> Result<(), io::Error> { writeln!(w) } -mod gen; - From c486e1b7a93fb4008a01111031a9ac2be6793096 Mon Sep 17 00:00:00 2001 From: Dylan McKay Date: Sun, 17 Dec 2017 12:58:41 +1300 Subject: [PATCH 27/38] Rename crate to 'ruduino' --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 81a3fe4..e04c30c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,7 +11,7 @@ license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/avr-rust/ruduino" description = """ -Reusable components for the Arduino Uno. +Reusable components for AVR microcontrollers """ build = "core_generator/build.rs" From 61c62ad0ed4e5efaa2ef3004efa6ca139579566c Mon Sep 17 00:00:00 2001 From: Dylan McKay Date: Sun, 17 Dec 2017 13:14:10 +1300 Subject: [PATCH 28/38] Merge Mask and Bitset, remove Bitset There isn't as much value as I thought in making the distinction. --- core_generator/build.rs | 2 +- core_generator/gen.rs | 6 +++--- src/lib.rs | 2 +- src/modules/timer/timer16.rs | 6 +++--- src/modules/timer/timer8.rs | 6 +++--- src/register.rs | 42 ------------------------------------ 6 files changed, 11 insertions(+), 53 deletions(-) diff --git a/core_generator/build.rs b/core_generator/build.rs index 7252cc7..72c015c 100644 --- a/core_generator/build.rs +++ b/core_generator/build.rs @@ -73,7 +73,7 @@ fn generate_cores_mod_rs(mcus: &[Mcu]) -> Result<(), io::Error> { 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, Register}};")?; + writeln!(w, "use {{Mask, Register}};")?; writeln!(w, "use modules;")?; writeln!(w)?; diff --git a/core_generator/gen.rs b/core_generator/gen.rs index 40fe789..331b021 100644 --- a/core_generator/gen.rs +++ b/core_generator/gen.rs @@ -15,7 +15,7 @@ pub fn write_registers(mcu: &Mcu, w: &mut Write) -> Result<(), io::Error> { writeln!(w, "impl {} {{", register.name)?; for bitfield in register.bitfields.iter() { // Create a mask for the whole bitset. - writeln!(w, " pub const {}: Bitset = Bitset::new(0x{:x});", bitfield.name, bitfield.mask)?; + writeln!(w, " pub const {}: Mask = Mask::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. @@ -186,7 +186,7 @@ pub fn write_timers(mcu: &Mcu, w: &mut Write) -> Result<(), io::Error> { 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, " const OCIEA: Mask = Self::InterruptMask::OCIE0A;")?; writeln!(w, "}}")?; } @@ -221,7 +221,7 @@ pub fn write_timers(mcu: &Mcu, w: &mut Write) -> Result<(), io::Error> { writeln!(w, " const WGM1: Mask = Self::ControlA::WGM11;")?; writeln!(w, " const WGM2: Mask = Self::ControlB::WGM10;")?; writeln!(w, " const WGM3: Mask = Self::ControlB::WGM11;")?; - writeln!(w, " const OCIEA: Bitset = Self::InterruptMask::OCIE1A;")?; + writeln!(w, " const OCIEA: Mask = Self::InterruptMask::OCIE1A;")?; writeln!(w, "}}")?; } diff --git a/src/lib.rs b/src/lib.rs index 770b487..a474a88 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -13,7 +13,7 @@ #![no_std] -pub use self::register::{Bitset, Mask, Register, RegisterValue}; +pub use self::register::{Mask, Register, RegisterValue}; pub use self::pin::{DataDirection, Pin}; pub mod prelude; diff --git a/src/modules/timer/timer16.rs b/src/modules/timer/timer16.rs index a7dfcb4..4dce3ab 100644 --- a/src/modules/timer/timer16.rs +++ b/src/modules/timer/timer16.rs @@ -1,4 +1,4 @@ -use {Bitset, Mask, Register}; +use {Mask, Register}; use core::marker; /// A 16-bit timer. @@ -50,7 +50,7 @@ pub trait Timer16 : Sized { const WGM2: Mask; const WGM3: Mask; - const OCIEA: Bitset; + const OCIEA: Mask; fn setup() -> Timer16Setup { Timer16Setup::new() } } @@ -204,7 +204,7 @@ impl Timer16Setup { T::CompareA::write(v); // Enable compare interrupt - T::OCIEA.set_all(); + T::InterruptMask::set(T::OCIEA); } } } diff --git a/src/modules/timer/timer8.rs b/src/modules/timer/timer8.rs index e2c2e2e..fa09717 100644 --- a/src/modules/timer/timer8.rs +++ b/src/modules/timer/timer8.rs @@ -1,4 +1,4 @@ -use {Bitset, Mask, Register}; +use {Mask, Register}; use core::marker; /// A 8-bit timer. @@ -44,7 +44,7 @@ pub trait Timer8 : Sized { const WGM1: Mask; const WGM2: Mask; - const OCIEA: Bitset; + const OCIEA: Mask; } pub enum ClockSource { @@ -176,7 +176,7 @@ impl Timer8Setup { T::CompareA::write(v); // Enable compare interrupt - T::OCIEA.set_all(); + T::InterruptMask::set(T::OCIEA); } } } diff --git a/src/register.rs b/src/register.rs index 7f11221..d642a80 100644 --- a/src/register.rs +++ b/src/register.rs @@ -128,13 +128,6 @@ pub trait Register : Sized { } } -/// A register bitmask. -#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct Bitset { - mask: R::T, - _phantom: marker::PhantomData, -} - /// A register bitmask. #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct Mask { @@ -142,41 +135,6 @@ pub struct Mask { _phantom: marker::PhantomData, } -impl Bitset where R: Register { - /// Creates a new register mask. - pub const fn new(mask: R::T) -> Self { - Bitset { mask, _phantom: marker::PhantomData } - } - - /// Sets the mask in the register. - /// - /// This is equivalent to `r |= mask`. - pub fn set_all(self) { - R::set_raw(self.mask); - } - - /// Clears the mask from the register. - /// - /// This is equivalent to `r &= !mask`. - pub fn unset_all(self) { - R::unset_raw(self.mask); - } - - /// Toggles the masked bits in the register. - /// - /// This is equivalent to `r ^= mask`. - pub fn toggle_all(self) { - R::toggle_raw(self.mask); - } - - /// Checks if the mask is clear. - /// - /// This is equivalent to `(r & mask) == 0`. - pub fn is_clear(self) -> bool { - R::is_clear_raw(self.mask) - } -} - impl Mask where R: Register { /// Creates a new register mask. pub const fn new(mask: R::T) -> Self { From 2b58e360657a1132e0fac3fa6a6046b18fb6c8f4 Mon Sep 17 00:00:00 2001 From: Dylan McKay Date: Sun, 17 Dec 2017 13:19:14 +1300 Subject: [PATCH 29/38] Add documentation --- src/modules/timer/timer8.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/modules/timer/timer8.rs b/src/modules/timer/timer8.rs index fa09717..15bfb98 100644 --- a/src/modules/timer/timer8.rs +++ b/src/modules/timer/timer8.rs @@ -36,14 +36,21 @@ pub trait Timer8 : Sized { /// For example, TIFR0. type InterruptFlag: Register; + /// Bit 0 of the clock select mask. const CS0: Mask; + /// Bit 1 of the clock select mask. const CS1: Mask; + /// Bit 2 of the clock select mask. const CS2: Mask; + /// Bit 0 of the waveform generation mode mask. const WGM0: Mask; + /// Bit 1 of the waveform generation mode mask. const WGM1: Mask; + /// Bit 2 of the waveform generation mode mask. const WGM2: Mask; + /// Output compare interrupt enable flag. const OCIEA: Mask; } From 2430724262682ddcd992e66d29696963922a7a45 Mon Sep 17 00:00:00 2001 From: Dylan McKay Date: Sun, 17 Dec 2017 13:29:33 +1300 Subject: [PATCH 30/38] Remove temporarily-added debugging files --- Xargo.toml | 8 -------- avr-atmega328p.json | 26 -------------------------- build.sh | 3 --- 3 files changed, 37 deletions(-) delete mode 100644 Xargo.toml delete mode 100644 avr-atmega328p.json delete mode 100755 build.sh diff --git a/Xargo.toml b/Xargo.toml deleted file mode 100644 index 72578c6..0000000 --- a/Xargo.toml +++ /dev/null @@ -1,8 +0,0 @@ -[dependencies.std] -features = ["panic_unwind"] - -[dependencies.test] -stage = 1 - -[target.avr-atmega328p.dependencies] -core = { git = "https://github.com/avr-rust/libcore", branch = "rust-26015da0" } diff --git a/avr-atmega328p.json b/avr-atmega328p.json deleted file mode 100644 index 951e1ef..0000000 --- a/avr-atmega328p.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "llvm-target": "avr-unknown-unknown", - "cpu": "atmega328p", - "target-endian": "little", - "target-pointer-width": "16", - "os": "unknown", - "target-env": "", - "target-vendor": "unknown", - "arch": "avr", - "data-layout": "e-p:16:8-i8:8-i16:8-i32:8-i64:8-f32:8-f64:8-n8-a:8", - - "executables": true, - - "linker": "avr-gcc", - "linker-flavor": "gcc", - "pre-link-args": { - "gcc": ["-Os", "-mmcu=atmega328p"] - }, - "exe-suffix": ".elf", - "post-link-args": { - "gcc": ["-Wl,--gc-sections"] - }, - - "no-default-libraries": false -} - diff --git a/build.sh b/build.sh deleted file mode 100755 index c81f123..0000000 --- a/build.sh +++ /dev/null @@ -1,3 +0,0 @@ -#! /bin/sh -export AVR_CPU_FREQUENCY=16000000 -xargo build --target avr-atmega328p $@ From dcab721dc12400bf94984beee73e219501dfde27 Mon Sep 17 00:00:00 2001 From: Dylan McKay Date: Sun, 17 Dec 2017 15:02:23 +1300 Subject: [PATCH 31/38] Use the correct timer thing --- core_generator/gen.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/core_generator/gen.rs b/core_generator/gen.rs index 331b021..a4b23cf 100644 --- a/core_generator/gen.rs +++ b/core_generator/gen.rs @@ -168,6 +168,8 @@ pub fn write_timers(mcu: &Mcu, w: &mut Write) -> Result<(), io::Error> { 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)?; @@ -186,7 +188,7 @@ pub fn write_timers(mcu: &Mcu, w: &mut Write) -> Result<(), io::Error> { 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: Mask = Self::InterruptMask::OCIE0A;")?; + writeln!(w, " const OCIEA: Mask = Self::InterruptMask::OCIE{}A;", timer_number)?; writeln!(w, "}}")?; } @@ -201,6 +203,8 @@ pub fn write_timers(mcu: &Mcu, w: &mut Write) -> Result<(), io::Error> { 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)?; @@ -221,7 +225,7 @@ pub fn write_timers(mcu: &Mcu, w: &mut Write) -> Result<(), io::Error> { writeln!(w, " const WGM1: Mask = Self::ControlA::WGM11;")?; writeln!(w, " const WGM2: Mask = Self::ControlB::WGM10;")?; writeln!(w, " const WGM3: Mask = Self::ControlB::WGM11;")?; - writeln!(w, " const OCIEA: Mask = Self::InterruptMask::OCIE1A;")?; + writeln!(w, " const OCIEA: Mask = Self::InterruptMask::OCIE{}A;", timer_number)?; writeln!(w, "}}")?; } From 4b451634e7739e8e87cb9cce90a352a350df0861 Mon Sep 17 00:00:00 2001 From: Dylan McKay Date: Mon, 5 Nov 2018 20:16:51 +1300 Subject: [PATCH 32/38] Rename AVR_FREQUENCY to AVR_FREQUENCY_HZ A bit less ambiguous. --- core_generator/build.rs | 4 ++-- src/modules/spi/clock.rs | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/core_generator/build.rs b/core_generator/build.rs index 72c015c..cd2bf15 100644 --- a/core_generator/build.rs +++ b/core_generator/build.rs @@ -42,8 +42,8 @@ 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"); - writeln!(f, "pub const CPU_FREQUENCY: u32 = {};", clock)?; + let clock = env!("AVR_CPU_FREQUENCY_HZ"); + writeln!(f, "pub const CPU_FREQUENCY_HZ: u32 = {};", clock)?; Ok(()) } diff --git a/src/modules/spi/clock.rs b/src/modules/spi/clock.rs index aea8ff0..92fe90c 100644 --- a/src/modules/spi/clock.rs +++ b/src/modules/spi/clock.rs @@ -19,17 +19,17 @@ 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 / 2 { + let mut divider_bits = if spi_clock >= config::CPU_FREQUENCY_HZ / 2 { 0 - } else if spi_clock >= config::CPU_FREQUENCY / 4 { + } else if spi_clock >= config::CPU_FREQUENCY_HZ / 4 { 1 - } else if spi_clock >= config::CPU_FREQUENCY / 8 { + } else if spi_clock >= config::CPU_FREQUENCY_HZ / 8 { 2 - } else if spi_clock >= config::CPU_FREQUENCY / 16 { + } else if spi_clock >= config::CPU_FREQUENCY_HZ / 16 { 3 - } else if spi_clock >= config::CPU_FREQUENCY / 32 { + } else if spi_clock >= config::CPU_FREQUENCY_HZ / 32 { 4 - } else if spi_clock >= config::CPU_FREQUENCY / 64 { + } else if spi_clock >= config::CPU_FREQUENCY_HZ / 64 { 5 } else { 6 From f94b23ed1d308f7ca5d803d7a1639e168fcf55a1 Mon Sep 17 00:00:00 2001 From: Dylan McKay Date: Mon, 5 Nov 2018 20:20:24 +1300 Subject: [PATCH 33/38] Use the new panic handler feature The "panic_fmt" lang item no longer exists; it has been replaced with the unstable feature #[panic_handler] --- src/lib.rs | 1 + src/std_stub.rs | 7 +++---- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index a474a88..7be2b49 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,6 +7,7 @@ #![feature(associated_type_defaults)] #![feature(const_fn)] #![feature(lang_items)] +#![feature(panic_handler)] #![feature(unwind_attributes)] #![no_core] diff --git a/src/std_stub.rs b/src/std_stub.rs index 60bbb60..53cd096 100644 --- a/src/std_stub.rs +++ b/src/std_stub.rs @@ -7,10 +7,9 @@ pub mod std { pub unsafe extern "C" fn rust_eh_personality(_state: (), _exception_object: *mut (), _context: *mut ()) -> () { } - #[lang = "panic_fmt"] - #[unwind] - pub extern fn rust_begin_panic(_msg: (), _file: &'static str, _line: u32) -> ! { - loop { } + #[panic_handler] + fn panic(_info: &::core::panic::PanicInfo) -> ! { + loop {} } } From 8a320ca9da61956b55e3de81212dad5deace0084 Mon Sep 17 00:00:00 2001 From: Dylan McKay Date: Mon, 5 Nov 2018 22:23:57 +1300 Subject: [PATCH 34/38] Assume atmega328 when building documentation This allows 'cargo doc', and notably, docs.rs to work. --- core_generator/build.rs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/core_generator/build.rs b/core_generator/build.rs index cd2bf15..f6840ad 100644 --- a/core_generator/build.rs +++ b/core_generator/build.rs @@ -8,6 +8,10 @@ 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") } @@ -25,8 +29,13 @@ fn main() { fs::create_dir_all(&cores_path()).expect("could not create cores directory"); } - let current_mcu = avr_mcu::current::mcu() - .expect("no target cpu specified"); + 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(); } From f90d5b2d0b648b22e323da7fb7fa401b8ede089b Mon Sep 17 00:00:00 2001 From: Dylan McKay Date: Mon, 5 Nov 2018 22:40:04 +1300 Subject: [PATCH 35/38] Clean up the documentation and public exports The interrupt helper struct does not need to be public. Add some documentation to a bunch of types. --- core_generator/build.rs | 1 - src/interrupt.rs | 35 +++++++++++++++++++++++++++++++++++ src/legacy/mod.rs | 3 ++- src/lib.rs | 3 +++ src/prelude.rs | 26 ++------------------------ 5 files changed, 42 insertions(+), 26 deletions(-) create mode 100644 src/interrupt.rs diff --git a/core_generator/build.rs b/core_generator/build.rs index f6840ad..d9d94cd 100644 --- a/core_generator/build.rs +++ b/core_generator/build.rs @@ -66,7 +66,6 @@ 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, "//! Cores")?; writeln!(w)?; for mcu in mcus { let module_name = core_module_name(mcu); diff --git a/src/interrupt.rs b/src/interrupt.rs new file mode 100644 index 0000000..83d358b --- /dev/null +++ b/src/interrupt.rs @@ -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: 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") } + } +} + diff --git a/src/legacy/mod.rs b/src/legacy/mod.rs index 7aaba83..1cd9e64 100644 --- a/src/legacy/mod.rs +++ b/src/legacy/mod.rs @@ -1,6 +1,7 @@ //! Legacy code. //! -//! The code in here needs to be cleaned up and rewritten. +//! 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! diff --git a/src/lib.rs b/src/lib.rs index 7be2b49..1089a3b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -19,9 +19,12 @@ pub use self::pin::{DataDirection, Pin}; pub mod prelude; pub mod legacy; +/// Low level register-based API for device-specific operations. pub mod cores; +pub mod interrupt; pub mod modules; +/// Configuration for the currently-targeted microcontroller. pub mod config; mod register; diff --git a/src/prelude.rs b/src/prelude.rs index 8895d93..a5e529e 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -1,26 +1,4 @@ -use core::prelude::v1::*; -use core::marker::PhantomData; +//! Re-exports commonly-used APIs that can be imported at once. -pub struct DisableInterrupts(PhantomData<()>); +pub use interrupt::without_interrupts; -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: F) -> T - where F: FnOnce() -> T -{ - let _disabled = DisableInterrupts::new(); - f() -} From aecd4edb360a5d6508e01f457af5de0ac577f20e Mon Sep 17 00:00:00 2001 From: Dylan McKay Date: Mon, 5 Nov 2018 23:05:34 +1300 Subject: [PATCH 36/38] Rename Mask to RegisterBits This is much more intuitive. --- core_generator/build.rs | 3 +- core_generator/gen.rs | 34 +++++----- src/lib.rs | 2 +- src/modules/spi/mod.rs | 32 +++++----- src/modules/timer/timer16.rs | 85 ++++++++++++------------- src/modules/timer/timer8.rs | 60 +++++++++--------- src/pin.rs | 15 +++-- src/register.rs | 116 ++++++++++++++++++++++------------- 8 files changed, 191 insertions(+), 156 deletions(-) diff --git a/core_generator/build.rs b/core_generator/build.rs index d9d94cd..e148399 100644 --- a/core_generator/build.rs +++ b/core_generator/build.rs @@ -52,6 +52,7 @@ fn generate_config_module() -> Result<(), io::Error> { 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(()) } @@ -81,7 +82,7 @@ fn generate_cores_mod_rs(mcus: &[Mcu]) -> Result<(), io::Error> { 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, Register}};")?; + writeln!(w, "use {{RegisterBits, Register}};")?; writeln!(w, "use modules;")?; writeln!(w)?; diff --git a/core_generator/gen.rs b/core_generator/gen.rs index a4b23cf..4b0d4da 100644 --- a/core_generator/gen.rs +++ b/core_generator/gen.rs @@ -15,7 +15,7 @@ pub fn write_registers(mcu: &Mcu, w: &mut Write) -> Result<(), io::Error> { writeln!(w, "impl {} {{", register.name)?; for bitfield in register.bitfields.iter() { // Create a mask for the whole bitset. - writeln!(w, " pub const {}: Mask = Mask::new(0x{:x});", bitfield.name, bitfield.mask)?; + writeln!(w, " pub const {}: RegisterBits = 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. @@ -23,7 +23,7 @@ pub fn write_registers(mcu: &Mcu, w: &mut Write) -> Result<(), io::Error> { 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 = Mask::new(1<<{});", + writeln!(w, " pub const {}{}: RegisterBits = RegisterBits::new(1<<{});", bitfield.name, current_mask_bit_num, current_register_bit_num)?; current_mask_bit_num += 1; } @@ -182,13 +182,13 @@ pub fn write_timers(mcu: &Mcu, w: &mut Write) -> Result<(), io::Error> { 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: Mask = Self::InterruptMask::OCIE{}A;", timer_number)?; + writeln!(w, " const CS0: RegisterBits = Self::ControlB::CS00;")?; + writeln!(w, " const CS1: RegisterBits = Self::ControlB::CS01;")?; + writeln!(w, " const CS2: RegisterBits = Self::ControlB::CS02;")?; + writeln!(w, " const WGM0: RegisterBits = Self::ControlA::WGM00;")?; + writeln!(w, " const WGM1: RegisterBits = Self::ControlA::WGM01;")?; + writeln!(w, " const WGM2: RegisterBits = Self::ControlB::WGM020;")?; + writeln!(w, " const OCIEA: RegisterBits = Self::InterruptMask::OCIE{}A;", timer_number)?; writeln!(w, "}}")?; } @@ -218,14 +218,14 @@ pub fn write_timers(mcu: &Mcu, w: &mut Write) -> Result<(), io::Error> { 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: Mask = Self::ControlB::CS10;")?; - writeln!(w, " const CS1: Mask = Self::ControlB::CS11;")?; - writeln!(w, " const CS2: Mask = Self::ControlB::CS12;")?; - writeln!(w, " const WGM0: Mask = Self::ControlA::WGM10;")?; - writeln!(w, " const WGM1: Mask = Self::ControlA::WGM11;")?; - writeln!(w, " const WGM2: Mask = Self::ControlB::WGM10;")?; - writeln!(w, " const WGM3: Mask = Self::ControlB::WGM11;")?; - writeln!(w, " const OCIEA: Mask = Self::InterruptMask::OCIE{}A;", timer_number)?; + writeln!(w, " const CS0: RegisterBits = Self::ControlB::CS10;")?; + writeln!(w, " const CS1: RegisterBits = Self::ControlB::CS11;")?; + writeln!(w, " const CS2: RegisterBits = Self::ControlB::CS12;")?; + writeln!(w, " const WGM0: RegisterBits = Self::ControlA::WGM10;")?; + writeln!(w, " const WGM1: RegisterBits = Self::ControlA::WGM11;")?; + writeln!(w, " const WGM2: RegisterBits = Self::ControlB::WGM10;")?; + writeln!(w, " const WGM3: RegisterBits = Self::ControlB::WGM11;")?; + writeln!(w, " const OCIEA: RegisterBits = Self::InterruptMask::OCIE{}A;", timer_number)?; writeln!(w, "}}")?; } diff --git a/src/lib.rs b/src/lib.rs index 1089a3b..6825751 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -14,7 +14,7 @@ #![no_std] -pub use self::register::{Mask, Register, RegisterValue}; +pub use self::register::{Register, RegisterBits, RegisterValue}; pub use self::pin::{DataDirection, Pin}; pub mod prelude; diff --git a/src/modules/spi/mod.rs b/src/modules/spi/mod.rs index e6cdbd1..73dac79 100644 --- a/src/modules/spi/mod.rs +++ b/src/modules/spi/mod.rs @@ -56,87 +56,87 @@ pub trait HardwareSpi { /// Sets the clock speed. fn set_clock(clock: u32) { let mask = clock::ClockMask::with_clock(clock); - Self::ControlRegister::set_raw(mask.control_register_mask()); - Self::StatusRegister::set_raw(mask.status_register_mask()); + 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_raw(settings::control_register::INTERRUPT_ENABLE); + Self::ControlRegister::set_mask_raw(settings::control_register::INTERRUPT_ENABLE); } /// Disables interrupts for the spi module. #[inline(always)] fn disable_interrupt() { - Self::ControlRegister::unset_raw(settings::control_register::INTERRUPT_ENABLE); + Self::ControlRegister::unset_mask_raw(settings::control_register::INTERRUPT_ENABLE); } /// Enables the SPI. #[inline(always)] fn enable() { - Self::ControlRegister::set_raw(settings::control_register::ENABLE); + Self::ControlRegister::set_mask_raw(settings::control_register::ENABLE); } /// Disables the SPI. #[inline(always)] fn disable() { - Self::ControlRegister::unset_raw(settings::control_register::ENABLE); + Self::ControlRegister::unset_mask_raw(settings::control_register::ENABLE); } /// Enables least-significant-bit first. #[inline(always)] fn set_lsb() { - Self::ControlRegister::set_raw(settings::control_register::DATA_ORDER_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_raw(settings::control_register::DATA_ORDER_LSB); + Self::ControlRegister::unset_mask_raw(settings::control_register::DATA_ORDER_LSB); } /// Enables master mode. #[inline(always)] fn set_master() { - Self::ControlRegister::set_raw(settings::control_register::MASTER); + Self::ControlRegister::set_mask_raw(settings::control_register::MASTER); } /// Enables slave mode. #[inline(always)] fn set_slave() { - Self::ControlRegister::unset_raw(settings::control_register::MASTER); + Self::ControlRegister::unset_mask_raw(settings::control_register::MASTER); } /// Enables double speed mode. #[inline(always)] fn enable_double_speed() { - Self::StatusRegister::set_raw(settings::status_register::SPI2X); + Self::StatusRegister::set_mask_raw(settings::status_register::SPI2X); } /// Disables double speed mode. #[inline(always)] fn disable_double_speed() { - Self::StatusRegister::unset_raw(settings::status_register::SPI2X); + 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_set_raw(settings::status_register::WCOL) + 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_set_raw(settings::status_register::SPIF); + 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_set_raw(settings::status_register::SPIF); + Self::StatusRegister::wait_until_mask_set_raw(settings::status_register::SPIF); Self::DataRegister::read() } @@ -144,7 +144,7 @@ pub trait HardwareSpi { #[inline(always)] fn send_receive(byte: u8) -> u8 { Self::DataRegister::write(byte); - Self::StatusRegister::wait_until_set_raw(settings::status_register::SPIF); + Self::StatusRegister::wait_until_mask_set_raw(settings::status_register::SPIF); Self::DataRegister::read() } } diff --git a/src/modules/timer/timer16.rs b/src/modules/timer/timer16.rs index 4dce3ab..961f75b 100644 --- a/src/modules/timer/timer16.rs +++ b/src/modules/timer/timer16.rs @@ -1,4 +1,4 @@ -use {Mask, Register}; +use {RegisterBits, Register}; use core::marker; /// A 16-bit timer. @@ -41,16 +41,16 @@ pub trait Timer16 : Sized { /// For example, TIFR0. type InterruptFlag: Register; - const CS0: Mask; - const CS1: Mask; - const CS2: Mask; + const CS0: RegisterBits; + const CS1: RegisterBits; + const CS2: RegisterBits; - const WGM0: Mask; - const WGM1: Mask; - const WGM2: Mask; - const WGM3: Mask; + const WGM0: RegisterBits; + const WGM1: RegisterBits; + const WGM2: RegisterBits; + const WGM3: RegisterBits; - const OCIEA: Mask; + const OCIEA: RegisterBits; fn setup() -> Timer16Setup { Timer16Setup::new() } } @@ -67,23 +67,23 @@ pub enum ClockSource { } impl ClockSource { - fn bits(&self) -> Mask { + fn bits(&self) -> RegisterBits { 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(), + 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() -> Mask { + fn mask() -> RegisterBits { !(T::CS2 | T::CS1 | T::CS0) } } @@ -109,45 +109,46 @@ pub enum WaveformGenerationMode { impl WaveformGenerationMode { /// Returns bits for TCCR1A, TCCR1B #[inline] - fn bits(&self) -> (Mask, Mask) { + fn bits(&self) -> (RegisterBits, RegisterBits) { 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 => (Mask::zero() | Mask::zero(), Mask::zero() | Mask::zero()), - PwmPhaseCorrect8Bit => (Mask::zero() | Mask::zero(), Mask::zero() | T::WGM0), - PwmPhaseCorrect9Bit => (Mask::zero() | Mask::zero(), T::WGM1 | Mask::zero()), - PwmPhaseCorrect10Bit => (Mask::zero() | Mask::zero(), T::WGM1 | T::WGM0), - ClearOnTimerMatchOutputCompare => (Mask::zero() | T::WGM2, Mask::zero() | Mask::zero()), - FastPwm8Bit => (Mask::zero() | T::WGM2, Mask::zero() | T::WGM0), - FastPwm9Bit => (Mask::zero() | T::WGM2, T::WGM1 | Mask::zero()), - FastPwm10Bit => (Mask::zero() | T::WGM2, T::WGM1 | T::WGM0), - PwmPhaseAndFrequencyCorrectInputCapture => (T::WGM3 | Mask::zero(), Mask::zero() | Mask::zero()), - PwmPhaseAndFrequencyCorrectOutputCompare => (T::WGM3 | Mask::zero(), Mask::zero() | T::WGM0), - PwmPhaseCorrectInputCapture => (T::WGM3 | Mask::zero(), T::WGM1 | Mask::zero()), - PwmPhaseCorrectOutputCompare => (T::WGM3 | Mask::zero(), T::WGM1 | T::WGM0), - ClearOnTimerMatchInputCapture => (T::WGM3 | T::WGM2, Mask::zero() | Mask::zero()), - // Reserved => (T::WGM3 | T::WGM2, Mask::zero() | T::WGM0), - FastPwmInputCapture => (T::WGM3 | T::WGM2, T::WGM1 | Mask::zero()), - FastPwmOutputCompare => (T::WGM3 | T::WGM2, T::WGM1 | T::WGM0), + 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() -> (Mask, Mask) { + fn mask() -> (RegisterBits, RegisterBits) { (!(T::WGM0 | T::WGM1), !(T::WGM2 | T::WGM3)) } } pub struct Timer16Setup { - a: Mask, - b: Mask, - c: Mask, + a: RegisterBits, + b: RegisterBits, + c: RegisterBits, output_compare_1: Option, _phantom: marker::PhantomData, } @@ -156,9 +157,9 @@ impl Timer16Setup { #[inline] fn new() -> Self { Timer16Setup { - a: Mask::zero(), - b: Mask::zero(), - c: Mask::zero(), + a: RegisterBits::zero(), + b: RegisterBits::zero(), + c: RegisterBits::zero(), output_compare_1: None, _phantom: marker::PhantomData, } diff --git a/src/modules/timer/timer8.rs b/src/modules/timer/timer8.rs index 15bfb98..a02f6d5 100644 --- a/src/modules/timer/timer8.rs +++ b/src/modules/timer/timer8.rs @@ -1,4 +1,4 @@ -use {Mask, Register}; +use {RegisterBits, Register}; use core::marker; /// A 8-bit timer. @@ -37,21 +37,21 @@ pub trait Timer8 : Sized { type InterruptFlag: Register; /// Bit 0 of the clock select mask. - const CS0: Mask; + const CS0: RegisterBits; /// Bit 1 of the clock select mask. - const CS1: Mask; + const CS1: RegisterBits; /// Bit 2 of the clock select mask. - const CS2: Mask; + const CS2: RegisterBits; /// Bit 0 of the waveform generation mode mask. - const WGM0: Mask; + const WGM0: RegisterBits; /// Bit 1 of the waveform generation mode mask. - const WGM1: Mask; + const WGM1: RegisterBits; /// Bit 2 of the waveform generation mode mask. - const WGM2: Mask; + const WGM2: RegisterBits; /// Output compare interrupt enable flag. - const OCIEA: Mask; + const OCIEA: RegisterBits; } pub enum ClockSource { @@ -66,23 +66,23 @@ pub enum ClockSource { } impl ClockSource { - fn bits(&self) -> Mask { + fn bits(&self) -> RegisterBits { 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(), + 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() -> Mask { + fn mask() -> RegisterBits { !(T::CS2 | T::CS1 | T::CS0) } } @@ -99,7 +99,7 @@ pub enum WaveformGenerationMode { impl WaveformGenerationMode { /// Returns bits for TCCR0A, TCCR0B #[inline] - fn bits(&self) -> (Mask, Mask) { + fn bits(&self) -> (RegisterBits, RegisterBits) { use self::WaveformGenerationMode::*; // It makes more sense to return bytes (A,B), but the manual @@ -107,13 +107,13 @@ impl WaveformGenerationMode { // 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())), + 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), }; @@ -121,14 +121,14 @@ impl WaveformGenerationMode { } #[inline] - fn mask() -> (Mask, Mask) { + fn mask() -> (RegisterBits, RegisterBits) { (!(T::WGM0 | T::WGM1), !(T::WGM2)) } } pub struct Timer8Setup { - a: Mask, - b: Mask, + a: RegisterBits, + b: RegisterBits, output_compare_1: Option, _phantom: marker::PhantomData, } @@ -137,8 +137,8 @@ impl Timer8Setup { #[inline] pub fn new() -> Self { Timer8Setup { - a: Mask::zero(), - b: Mask::zero(), + a: RegisterBits::zero(), + b: RegisterBits::zero(), output_compare_1: None, _phantom: marker::PhantomData, } diff --git a/src/pin.rs b/src/pin.rs index c917721..806ba99 100644 --- a/src/pin.rs +++ b/src/pin.rs @@ -1,7 +1,10 @@ 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, } @@ -11,7 +14,7 @@ pub trait Pin { type DDR: Register; /// The associated port register. type PORT: Register; - /// The associated pin register. + /// /// Reads from the register will read input bits. /// Writes to the register will toggle bits. @@ -31,13 +34,13 @@ pub trait Pin { /// Sets the pin up as an input. #[inline(always)] fn set_input() { - Self::DDR::unset_raw(Self::MASK); + Self::DDR::unset_mask_raw(Self::MASK); } /// Sets the pin up as an output. #[inline(always)] fn set_output() { - Self::DDR::set_raw(Self::MASK); + Self::DDR::set_mask_raw(Self::MASK); } /// Set the pin to high. @@ -45,7 +48,7 @@ pub trait Pin { /// The pin must be configured as an output. #[inline(always)] fn set_high() { - Self::PORT::set_raw(Self::MASK); + Self::PORT::set_mask_raw(Self::MASK); } /// Set the pin to low. @@ -53,7 +56,7 @@ pub trait Pin { /// The pin must be configured as an output. #[inline(always)] fn set_low() { - Self::PORT::unset_raw(Self::MASK); + Self::PORT::unset_mask_raw(Self::MASK); } /// Toggles the pin. @@ -72,7 +75,7 @@ pub trait Pin { /// The pin must be configured as an input. #[inline(always)] fn is_high() -> bool { - Self::PIN::is_set_raw(Self::MASK) + Self::PIN::is_mask_set_raw(Self::MASK) } /// Checks if the pin is currently low. diff --git a/src/register.rs b/src/register.rs index d642a80..2a13f98 100644 --- a/src/register.rs +++ b/src/register.rs @@ -1,6 +1,8 @@ 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 + ops::BitAndAssign + @@ -16,8 +18,11 @@ pub trait RegisterValue : Copy + Clone + /// A register. pub trait Register : Sized { + /// The type that can represent the value of the register. type T: RegisterValue; - type Mask = Mask; + /// The type representing a set of bits that may be manipulated + /// within the register. + type RegisterBits = RegisterBits; /// The address of the register. const ADDRESS: *mut Self::T; @@ -36,35 +41,44 @@ pub trait Register : Sized { unsafe { *Self::ADDRESS } } - fn set(mask: Mask) { - Self::set_raw(mask.mask); + /// Sets a set of bits to `1` in the register. + fn set(bits: RegisterBits) { + Self::set_mask_raw(bits.mask); } /// Sets a bitmask in a register. /// /// This is equivalent to `r |= mask`. #[inline(always)] - fn set_raw(mask: Self::T) { + fn set_mask_raw(mask: Self::T) { unsafe { *Self::ADDRESS |= mask; } } - fn unset(mask: Mask) { - Self::unset_raw(mask.mask); + /// Unsets a set of bits in the register. + /// + /// All of the bits will be set to `0`. + fn unset(bits: RegisterBits) { + Self::unset_mask_raw(bits.mask); } /// Clears a bitmask from a register. /// /// This is equivalent to `r &= !mask`. #[inline(always)] - fn unset_raw(mask: Self::T) { + fn unset_mask_raw(mask: Self::T) { unsafe { *Self::ADDRESS &= !mask; } } - fn toggle(mask: 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::toggle_raw(mask.mask); } @@ -78,21 +92,29 @@ pub trait Register : Sized { } } - fn is_set(mask: Mask) -> bool { - Self::is_set_raw(mask.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) -> 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_set_raw(mask: Self::T) -> bool { + fn is_mask_set_raw(mask: Self::T) -> bool { unsafe { (*Self::ADDRESS & mask) == mask } } - fn is_clear(mask: Mask) -> bool { + /// 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) -> bool { Self::is_clear_raw(mask.mask) } @@ -106,92 +128,100 @@ pub trait Register : Sized { } } - /// Waits until some condition is true of the register. - #[inline(always)] - fn wait_until(mut f: F) - where F: FnMut() -> bool { - loop { - if f() { - break; - } - } + /// 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::wait_until_mask_set_raw(bits.mask); } - fn wait_until_set(mask: Mask) { - Self::wait_until_set_raw(mask.mask); - } - - /// Waits until a mask is set. + /// 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_set_raw(mask: Self::T) { - Self::wait_until(|| Self::is_set_raw(mask)) + fn wait_until_mask_set_raw(mask: Self::T) { + wait_until(|| Self::is_mask_set_raw(mask)) } } -/// A register bitmask. +/// Represents a set of bits within a specific register. #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct Mask { +pub struct RegisterBits { + /// The raw bitmask. mask: R::T, _phantom: marker::PhantomData, } -impl Mask where R: Register { +impl RegisterBits where R: Register { /// Creates a new register mask. pub const fn new(mask: R::T) -> Self { - Mask { mask, _phantom: marker::PhantomData } + RegisterBits { mask, _phantom: marker::PhantomData } } pub fn zero() -> Self { - Mask::new(0u8.into()) + RegisterBits::new(0u8.into()) } } -impl ops::BitOr for Mask where R: Register +impl ops::BitOr for RegisterBits where R: Register { type Output = Self; fn bitor(self, rhs: Self) -> Self { - Mask::new(self.mask | rhs.mask) + RegisterBits::new(self.mask | rhs.mask) } } -impl ops::BitOrAssign for Mask where R: Register { +impl ops::BitOrAssign for RegisterBits where R: Register { fn bitor_assign(&mut self, rhs: Self) { self.mask |= rhs.mask; } } -impl ops::BitAnd for Mask where R: Register +impl ops::BitAnd for RegisterBits where R: Register { type Output = Self; fn bitand(self, rhs: Self) -> Self { - Mask::new(self.mask & rhs.mask) + RegisterBits::new(self.mask & rhs.mask) } } -impl ops::BitAndAssign for Mask where R: Register { +impl ops::BitAndAssign for RegisterBits where R: Register { fn bitand_assign(&mut self, rhs: Self) { self.mask &= rhs.mask; } } -impl ops::Not for Mask where R: Register { +impl ops::Not for RegisterBits where R: Register { type Output = Self; fn not(self) -> Self { - Mask::new(!self.mask) + RegisterBits::new(!self.mask) } } -impl Into for Mask where R: Register { +impl Into for RegisterBits where R: Register { fn into(self) -> u8 { self.mask } } -impl Into for Mask where R: Register { +impl Into for RegisterBits where R: Register { 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(mut f: F) + where F: FnMut() -> bool { + loop { + if f() { + break; + } + } +} + From 3fbe33504ac57f9e8b06c561992281f25a8196c8 Mon Sep 17 00:00:00 2001 From: Dylan McKay Date: Mon, 5 Nov 2018 23:35:46 +1300 Subject: [PATCH 37/38] Fixes --- src/lib.rs | 5 ----- src/prelude.rs | 2 ++ 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 6825751..7f0e0ce 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,7 +1,6 @@ //! Definitions of register addresses and bits within those registers #![feature(asm)] -#![feature(no_core)] #![feature(const_fn)] #![feature(associated_consts)] #![feature(associated_type_defaults)] @@ -10,10 +9,6 @@ #![feature(panic_handler)] #![feature(unwind_attributes)] -#![no_core] - -#![no_std] - pub use self::register::{Register, RegisterBits, RegisterValue}; pub use self::pin::{DataDirection, Pin}; diff --git a/src/prelude.rs b/src/prelude.rs index a5e529e..5683120 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -1,4 +1,6 @@ //! Re-exports commonly-used APIs that can be imported at once. +use core::prelude::v1::*; + pub use interrupt::without_interrupts; From 49a34da4e27487713c357a72dbb3ab9df71fb7b1 Mon Sep 17 00:00:00 2001 From: Dylan McKay Date: Mon, 5 Nov 2018 23:37:50 +1300 Subject: [PATCH 38/38] Fixes from incorrect rebase --- src/lib.rs | 4 ++-- src/prelude.rs | 2 -- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 7f0e0ce..92079e1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,13 +2,13 @@ #![feature(asm)] #![feature(const_fn)] -#![feature(associated_consts)] #![feature(associated_type_defaults)] -#![feature(const_fn)] #![feature(lang_items)] #![feature(panic_handler)] #![feature(unwind_attributes)] +#![no_std] + pub use self::register::{Register, RegisterBits, RegisterValue}; pub use self::pin::{DataDirection, Pin}; diff --git a/src/prelude.rs b/src/prelude.rs index 5683120..a5e529e 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -1,6 +1,4 @@ //! Re-exports commonly-used APIs that can be imported at once. -use core::prelude::v1::*; - pub use interrupt::without_interrupts;