More work done

This commit is contained in:
Dylan McKay 2017-12-14 00:55:57 +13:00
parent 1f638dbea3
commit 274d4611ec
11 changed files with 317 additions and 238 deletions

View File

@ -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,7 +106,6 @@ 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 {
@ -117,7 +117,6 @@ mod gen {
current_mask >>= 1;
}
}
writeln!(w)?;
}
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<u8, Self::ControlB> = Self::ControlB::CS00;")?;
writeln!(w, " const CS1: Mask<u8, Self::ControlB> = Self::ControlB::CS01;")?;
writeln!(w, " const CS2: Mask<u8, Self::ControlB> = Self::ControlB::CS02;")?;
writeln!(w, " const WGM0: Mask<u8, Self::ControlA> = Self::ControlA::WGM00;")?;
writeln!(w, " const WGM1: Mask<u8, Self::ControlA> = Self::ControlA::WGM01;")?;
writeln!(w, " const WGM2: Mask<u8, Self::ControlB> = Self::ControlB::WGM020;")?;
writeln!(w, " const OCIEA: Bitset<u8, Self::InterruptMask> = Self::InterruptMask::OCIE0A;")?;
writeln!(w, "}}")?;
}
Ok(())
}
/// Gets the name of a pin.
fn pin_name(instance: &Instance, signal: &Signal) -> String {
let idx = signal.index.expect("signal with no index");

View File

@ -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;

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

@ -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;

View File

@ -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;
}

View File

@ -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;

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

@ -0,0 +1,4 @@
pub use self::timer8::{Timer8, Timer8Setup};
mod timer8;

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

@ -0,0 +1,184 @@
use {Bitset, Mask, Register};
use core::marker;
/// An 8-bit timer.
pub trait Timer8 {
/// The first compare register.
/// For example, OCR0A.
type CompareA: Register<u8>;
/// The second compare register.
/// For example, OCR0B.
type CompareB: Register<u8>;
/// The counter register.
///
/// For example, TCNT0.
type Counter: Register<u8>;
/// The first control register.
///
/// For example, TCCR0A.
type ControlA: Register<u8>;
/// The second control register.
///
/// For example, TCCR0B.
type ControlB: Register<u8>;
/// The interrupt mask register.
///
/// For example, TIMSK0.
type InterruptMask: Register<u8>;
/// The interrupt flag register.
///
/// For example, TIFR0.
type InterruptFlag: Register<u8>;
const CS0: Mask<u8, Self::ControlB>;
const CS1: Mask<u8, Self::ControlB>;
const CS2: Mask<u8, Self::ControlB>;
const WGM0: Mask<u8, Self::ControlA>;
const WGM1: Mask<u8, Self::ControlA>;
const WGM2: Mask<u8, Self::ControlB>;
const OCIEA: Bitset<u8, Self::InterruptMask>;
}
pub enum ClockSource {
None,
Prescale1,
Prescale8,
Prescale64,
Prescale256,
Prescale1024,
ExternalFalling,
ExternalRising,
}
impl ClockSource {
fn bits<T: Timer8>(&self) -> Mask<u8, T::ControlB> {
use self::ClockSource::*;
match *self {
None => Mask::zero() | Mask::zero() | Mask::zero(),
Prescale1 => Mask::zero() | Mask::zero() | T::CS0,
Prescale8 => Mask::zero() | T::CS1 | Mask::zero(),
Prescale64 => Mask::zero() | T::CS1 | T::CS0,
Prescale256 => T::CS2 | Mask::zero() | Mask::zero(),
Prescale1024 => T::CS2 | Mask::zero() | T::CS0,
ExternalFalling => T::CS2 | T::CS1 | Mask::zero(),
ExternalRising => T::CS2 | T::CS1 | T::CS0,
}
}
#[inline]
fn mask<T: Timer8>() -> Mask<u8, T::ControlB> {
!(T::CS2 | T::CS1 | T::CS0)
}
}
pub enum WaveformGenerationMode {
Normal,
PwmPhaseCorrect,
ClearOnTimerMatchOutputCompare,
FastPwm ,
PwmPhaseCorrectOutputCompare,
FastPwmOutputCompare,
}
impl WaveformGenerationMode {
/// Returns bits for TCCR0A, TCCR0B
#[inline]
fn bits<T: Timer8>(&self) -> (Mask<u8, T::ControlA>, Mask<u8, T::ControlB>) {
use self::WaveformGenerationMode::*;
// It makes more sense to return bytes (A,B), but the manual
// lists the table as (B,A). We match the manual here for
// inspection purposes and flip the values for sanity
// purposes.
let (b, a) = match *self {
Normal => (Mask::zero(), Mask::zero() | Mask::zero()),
PwmPhaseCorrect => (Mask::zero(), Mask::zero() | T::WGM0),
ClearOnTimerMatchOutputCompare => (Mask::zero(), T::WGM1 | Mask::zero()),
FastPwm => (Mask::zero(), T::WGM1 | T::WGM0),
// Reserved => (T::WGM2, Mask::zero() | Mask::zero()),
PwmPhaseCorrectOutputCompare => (T::WGM2, Mask::zero() | T::WGM0),
// Reserved => (T::WGM2, T::WGM1 | Mask::zero())),
FastPwmOutputCompare => (T::WGM2, T::WGM1 | T::WGM0),
};
(a, b)
}
#[inline]
fn mask<T: Timer8>() -> (Mask<u8, T::ControlA>, Mask<u8, T::ControlB>) {
(!(T::WGM0 | T::WGM1), !(T::WGM2))
}
}
pub struct Timer8Setup<T: Timer8> {
a: Mask<u8, T::ControlA>,
b: Mask<u8, T::ControlB>,
output_compare_1: Option<u8>,
_phantom: marker::PhantomData<T>,
}
impl<T: Timer8> Timer8Setup<T> {
#[inline]
pub fn new() -> Self {
Timer8Setup {
a: Mask::zero(),
b: Mask::zero(),
output_compare_1: None,
_phantom: marker::PhantomData,
}
}
#[inline]
pub fn clock_source(mut self, source: ClockSource) -> Self {
self.b &= ClockSource::mask::<T>();
self.b |= source.bits::<T>();
self
}
#[inline]
pub fn waveform_generation_mode(mut self, mode: WaveformGenerationMode) -> Self {
let (a, b) = WaveformGenerationMode::mask::<T>();
self.a &= a;
self.b &= b;
let (a, b) = mode.bits::<T>();
self.a |= a;
self.b |= b;
self
}
#[inline]
pub fn output_compare_1(mut self, value: Option<u8>) -> Self {
self.output_compare_1 = value;
self
}
#[inline]
pub fn configure(self) {
unsafe {
T::ControlA::write(self.a);
T::ControlB::write(self.b);
// Reset counter to zero
T::Counter::write(0);
if let Some(v) = self.output_compare_1 {
// Set the match
T::CompareA::write(v);
// Enable compare interrupt
T::OCIEA.set_all();
}
}
}
}

View File

@ -22,9 +22,9 @@ pub trait Register<T: RegisterValue> : Sized {
/// Writes a value to the register.
#[inline(always)]
fn write(value: T) {
fn write<V>(value: V) where V: Into<T> {
unsafe {
*Self::ADDR = value;
*Self::ADDR = value.into();
}
}
@ -182,6 +182,59 @@ impl<T,R> Mask<T,R>
pub const fn new(mask: T) -> Self {
Mask { mask, _phantom: marker::PhantomData }
}
pub fn zero() -> Self {
Mask::new(0u8.into())
}
}
impl<T,R> ops::BitOr for Mask<T,R>
where T: RegisterValue, R: Register<T>
{
type Output = Self;
fn bitor(self, rhs: Self) -> Self {
Mask::new(self.mask | rhs.mask)
}
}
impl<T,R> ops::BitOrAssign for Mask<T,R>
where T: RegisterValue, R: Register<T> {
fn bitor_assign(&mut self, rhs: Self) {
self.mask |= rhs.mask;
}
}
impl<T,R> ops::BitAnd for Mask<T,R>
where T: RegisterValue, R: Register<T>
{
type Output = Self;
fn bitand(self, rhs: Self) -> Self {
Mask::new(self.mask & rhs.mask)
}
}
impl<T,R> ops::BitAndAssign for Mask<T,R>
where T: RegisterValue, R: Register<T> {
fn bitand_assign(&mut self, rhs: Self) {
self.mask &= rhs.mask;
}
}
impl<T,R> ops::Not for Mask<T,R>
where T: RegisterValue, R: Register<T> {
type Output = Self;
fn not(self) -> Self {
Mask::new(!self.mask)
}
}
impl<R> Into<u8> for Mask<u8,R> where R: Register<u8> {
fn into(self) -> u8 {
self.mask
}
}
impl RegisterValue for u8 { }

View File

@ -1,38 +0,0 @@
use {Register};
/// An 8-bit timer.
pub trait Timer8 {
/// The first compare register.
/// For example, OCR0A.
type CompareA: Register<u8>;
/// The second compare register.
/// For example, OCR0B.
type CompareB: Register<u8>;
/// The counter register.
///
/// For example, TCNT0.
type Counter: Register<u8>;
/// The first control register.
///
/// For example, TCCR0A.
type ControlA: Register<u8>;
/// The second control register.
///
/// For example, TCCR0B.
type ControlB: Register<u8>;
/// The interrupt mask register.
///
/// For example, TIMSK0.
type InterruptMask: Register<u8>;
/// The interrupt flag register.
///
/// For example, TIFR0.
type InterruptFlag: Register<u8>;
}

View File

@ -1,141 +0,0 @@
use core::prelude::v1::*;
use core::ptr::write_volatile;
use super::*;
use cores::atmega328p as c;
pub enum ClockSource {
None,
Prescale1,
Prescale8,
Prescale64,
Prescale256,
Prescale1024,
ExternalFalling,
ExternalRising,
}
impl ClockSource {
#[inline]
fn bits(&self) -> u8 {
use self::ClockSource::*;
match *self {
None => 0 | 0 | 0,
Prescale1 => 0 | 0 | CS00,
Prescale8 => 0 | CS01 | 0,
Prescale64 => 0 | CS01 | CS00,
Prescale256 => CS02 | 0 | 0,
Prescale1024 => CS02 | 0 | CS00,
ExternalFalling => CS02 | CS01 | 0,
ExternalRising => CS02 | CS01 | CS00,
}
}
#[inline]
fn mask() -> u8 {
!(CS02 | CS01 | CS00)
}
}
pub enum WaveformGenerationMode {
Normal,
PwmPhaseCorrect,
ClearOnTimerMatchOutputCompare,
FastPwm ,
PwmPhaseCorrectOutputCompare,
FastPwmOutputCompare,
}
impl WaveformGenerationMode {
/// Returns bits for TCCR0A, TCCR0B
#[inline]
fn bits(&self) -> (u8, u8) {
use self::WaveformGenerationMode::*;
// It makes more sense to return bytes (A,B), but the manual
// lists the table as (B,A). We match the manual here for
// inspection purposes and flip the values for sanity
// purposes.
let (b, a) = match *self {
Normal => ( 0, 0 | 0),
PwmPhaseCorrect => ( 0, 0 | WGM00),
ClearOnTimerMatchOutputCompare => ( 0, WGM01 | 0),
FastPwm => ( 0, WGM01 | WGM00),
// Reserved => (WGM02, 0 | 0),
PwmPhaseCorrectOutputCompare => (WGM02, 0 | WGM00),
// Reserved => (WGM02, WGM01 | 0),
FastPwmOutputCompare => (WGM02, WGM01 | WGM00),
};
(a, b)
}
#[inline]
fn mask() -> (u8, u8) {
(!(WGM00 | WGM01), !(WGM02))
}
}
pub struct Timer {
a: u8,
b: u8,
output_compare_1: Option<u8>,
}
impl Timer {
#[inline]
pub fn new() -> Self {
Timer {
a: 0,
b: 0,
output_compare_1: None,
}
}
#[inline]
pub fn clock_source(mut self, source: ClockSource) -> Self {
self.b &= ClockSource::mask();
self.b |= source.bits();
self
}
#[inline]
pub fn waveform_generation_mode(mut self, mode: WaveformGenerationMode) -> Self {
let (a, b) = WaveformGenerationMode::mask();
self.a &= a;
self.b &= b;
let (a, b) = mode.bits();
self.a |= a;
self.b |= b;
self
}
#[inline]
pub fn output_compare_1(mut self, value: Option<u8>) -> Self {
self.output_compare_1 = value;
self
}
#[inline]
pub fn configure(self) {
unsafe {
c::TCCR0A::write(self.a);
c::TCCR0B::write(self.b);
// Reset counter to zero
c::TCNT0::write(0);
if let Some(v) = self.output_compare_1 {
// Set the match
c::OCR0A::write(v);
// Enable compare interrupt
c::TIMSK0::OCIE0A.set_all();
}
}
}
}