Skip to content

Commit

Permalink
Do more work
Browse files Browse the repository at this point in the history
  • Loading branch information
dylanmckay committed Nov 5, 2018
1 parent 190a3ec commit 906b548
Show file tree
Hide file tree
Showing 11 changed files with 358 additions and 15 deletions.
8 changes: 8 additions & 0 deletions 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" }
47 changes: 44 additions & 3 deletions build.rs
Expand Up @@ -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 {
Expand All @@ -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> {
Expand All @@ -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)?;
Expand All @@ -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)?;

Expand All @@ -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, "}}")?;
Expand Down
1 change: 1 addition & 0 deletions build.sh
@@ -1,2 +1,3 @@
#! /bin/sh
export AVR_CPU_FREQUENCY=16000000
xargo build --target avr-atmega328p $@
14 changes: 14 additions & 0 deletions 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() {
}

2 changes: 2 additions & 0 deletions src/.gitignore
@@ -0,0 +1,2 @@
# Generated automatically.
config.rs
5 changes: 4 additions & 1 deletion src/lib.rs
Expand Up @@ -4,14 +4,16 @@
#![feature(no_core)]
#![feature(const_fn)]
#![feature(associated_consts)]
#![feature(associated_type_defaults)]
#![feature(const_fn)]
#![feature(lang_items)]
#![feature(unwind_attributes)]

#![no_core]

#![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;

Expand All @@ -22,6 +24,7 @@ pub mod timer1;
pub mod cores;

pub mod spi;
pub mod config;

mod register;
mod pin;
Expand Down
74 changes: 72 additions & 2 deletions 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<Output=Self> +
Expand All @@ -14,7 +14,9 @@ pub trait RegisterValue : Copy + Clone +
}

/// A register.
pub trait Register<T: RegisterValue> {
pub trait Register<T: RegisterValue> : Sized {
type Mask = Mask<T, Self>;

/// The address of the register.
const ADDR: *mut T;

Expand All @@ -33,6 +35,8 @@ pub trait Register<T: RegisterValue> {
}

/// Sets a bitmask in a register.
///
/// This is equivalent to `r |= mask`.
#[inline(always)]
fn set(mask: T) {
unsafe {
Expand All @@ -41,6 +45,8 @@ pub trait Register<T: RegisterValue> {
}

/// Clears a bitmask from a register.
///
/// This is equivalent to `r &= !mask`.
#[inline(always)]
fn unset(mask: T) {
unsafe {
Expand All @@ -49,6 +55,8 @@ pub trait Register<T: RegisterValue> {
}

/// Toggles a mask in the register.
///
/// This is equivalent to `r ^= mask`.
#[inline(always)]
fn toggle(mask: T) {
unsafe {
Expand All @@ -57,6 +65,8 @@ pub trait Register<T: RegisterValue> {
}

/// 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 {
Expand All @@ -65,6 +75,8 @@ pub trait Register<T: RegisterValue> {
}

/// 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 {
Expand All @@ -90,6 +102,64 @@ pub trait Register<T: RegisterValue> {
}
}

/// A register bitmask.
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Bitset<T: RegisterValue, R: Register<T>> {
mask: T,
_phantom: marker::PhantomData<R>,
}

/// A register bitmask.
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Mask<T: RegisterValue, R: Register<T>> {
mask: T,
_phantom: marker::PhantomData<R>,
}

impl<T,R> Bitset<T,R>
where T: RegisterValue, R: Register<T> {
/// 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<T,R> Mask<T,R>
where T: RegisterValue, R: Register<T> {
/// 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 { }

60 changes: 60 additions & 0 deletions 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
}
}

23 changes: 19 additions & 4 deletions src/spi.rs → src/spi/mod.rs
@@ -1,3 +1,6 @@
mod clock;
mod settings;

use {Register, Pin};

/// An SPI module.
Expand All @@ -18,7 +21,7 @@ pub trait HardwareSpi {
type DataRegister: Register<u8>;

/// 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();
Expand All @@ -27,19 +30,31 @@ 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();
Self::Clock::set_input();
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.
Expand Down

0 comments on commit 906b548

Please sign in to comment.