Skip to content

Commit c1062c0

Browse files
committed
Do more work
1 parent 74082df commit c1062c0

File tree

10 files changed

+247
-6
lines changed

10 files changed

+247
-6
lines changed

Xargo.toml

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
[dependencies.std]
2+
features = ["panic_unwind"]
3+
4+
[dependencies.test]
5+
stage = 1

build.rs

+16-2
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,12 @@ use std::io;
66
use std::io::prelude::*;
77
use std::path::{Path, PathBuf};
88

9+
fn src_path() -> PathBuf {
10+
Path::new(env!("CARGO_MANIFEST_DIR")).join("src")
11+
}
12+
913
fn cores_path() -> PathBuf {
10-
Path::new(env!("CARGO_MANIFEST_DIR")).join("src").join("cores")
14+
src_path().join("cores")
1115
}
1216

1317
fn core_module_name(mcu: &Mcu) -> String {
@@ -21,7 +25,8 @@ fn main() {
2125

2226
let current_mcu = avr_mcu::current::mcu()
2327
.expect("no target cpu specified");
24-
generate_cores(&[current_mcu]).unwrap()
28+
generate_config_module().unwrap();
29+
generate_cores(&[current_mcu]).unwrap();
2530
}
2631

2732
fn generate_cores(mcus: &[Mcu]) -> Result<(), io::Error> {
@@ -31,6 +36,15 @@ fn generate_cores(mcus: &[Mcu]) -> Result<(), io::Error> {
3136
generate_cores_mod_rs(mcus)
3237
}
3338

39+
fn generate_config_module() -> Result<(), io::Error> {
40+
let path = src_path().join("config.rs");
41+
let mut f = File::create(&path)?;
42+
43+
let clock = env!("AVR_CPU_FREQUENCY");
44+
writeln!(f, "pub const CPU_FREQUENCY: u32 = {};", clock)?;
45+
Ok(())
46+
}
47+
3448
fn generate_core_module(mcu: &Mcu) -> Result<(), io::Error> {
3549
let path = cores_path().join(format!("{}.rs", core_module_name(mcu)));
3650
let mut file = File::create(&path)?;

build.sh

+1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
#! /bin/sh
2+
export AVR_CPU_FREQUENCY=16000000
23
xargo build --target avr-atmega328p $@

examples/spi.rs

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#![no_std]
2+
#![no_main]
3+
4+
extern crate arduino;
5+
use arduino::cores::current;
6+
7+
// Some devices may have multiple SPI modules.
8+
// The ATmega328p only has one.
9+
type Spi = current::Spi;
10+
11+
#[no_mangle]
12+
pub extern fn main() {
13+
}
14+

src/.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# Generated automatically.
2+
config.rs

src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ pub mod timer1;
1818
pub mod cores;
1919

2020
pub mod spi;
21+
pub mod config;
2122

2223
mod register;
2324
mod pin;

src/register.rs

+2
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ pub trait Register<T: RegisterValue> {
3333
}
3434

3535
/// Sets a bitmask in a register.
36+
// FIXME: this will not clear any existing bits
37+
// Think about how this will interact with everything else.
3638
#[inline(always)]
3739
fn set(mask: T) {
3840
unsafe {

src/spi/clock.rs

+60
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
use config;
2+
3+
/// A clock mask.
4+
///
5+
/// The format looks like this
6+
///
7+
/// ```
8+
/// 0b00000<1><0><2x>
9+
/// ```
10+
///
11+
/// Where
12+
///
13+
/// * `1` is the value of the `SPR1` bit
14+
/// * `0` is the value of the `SPR0` bit
15+
/// * `2x` indicates if double speed mode is enabled
16+
#[derive(Copy, Clone)]
17+
pub struct ClockMask(pub u8);
18+
19+
impl ClockMask {
20+
/// Gets the clock mask for a specific baute rate.
21+
pub fn with_clock(spi_clock: u32) -> ClockMask {
22+
let mut divider_bits = if spi_clock >= config::CPU_FREQUENCY / 2 {
23+
0
24+
} else if spi_clock >= config::CPU_FREQUENCY / 4 {
25+
1
26+
} else if spi_clock >= config::CPU_FREQUENCY / 8 {
27+
2
28+
} else if spi_clock >= config::CPU_FREQUENCY / 16 {
29+
3
30+
} else if spi_clock >= config::CPU_FREQUENCY / 32 {
31+
4
32+
} else if spi_clock >= config::CPU_FREQUENCY / 64 {
33+
5
34+
} else {
35+
6
36+
};
37+
38+
// Invert the SPI2X bit
39+
divider_bits ^= 0x1;
40+
41+
// Compensate for the duplicate F_osc/64
42+
if divider_bits == 6 {
43+
divider_bits = 7;
44+
}
45+
ClockMask(divider_bits)
46+
}
47+
48+
pub fn control_register_mask(self) -> u8 {
49+
// SPR1 and SPR0
50+
// These both form bits 1 and 0 of the control register.
51+
(self.0 & 0b110) >> 1
52+
}
53+
54+
pub fn status_register_mask(self) -> u8 {
55+
// SPI2x
56+
// This forms bit 0 of the status register.
57+
self.0 & 0b1
58+
}
59+
}
60+

src/spi.rs renamed to src/spi/mod.rs

+19-4
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
mod clock;
2+
mod settings;
3+
14
use {Register, Pin};
25

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

2023
/// Sets up the SPI as a master.
21-
fn setup_master() {
24+
fn setup_master(clock: u32) {
2225
// Setup DDR registers.
2326
Self::MasterInSlaveOut::set_input();
2427
Self::MasterOutSlaveIn::set_output();
@@ -27,19 +30,31 @@ pub trait HardwareSpi {
2730

2831
Self::set_master();
2932
Self::enable_interrupt();
30-
Self::enable();
33+
Self::setup_common(clock)
3134
}
3235

3336
/// Sets up the SPI as a slave.
34-
fn setup_slave() {
37+
fn setup_slave(clock: u32) {
3538
// Setup DDR registers.
3639
Self::MasterInSlaveOut::set_output();
3740
Self::MasterOutSlaveIn::set_input();
3841
Self::Clock::set_input();
3942
Self::SlaveSelect::set_input();
4043

4144
Self::set_slave();
42-
Self::enable();
45+
Self::setup_common(clock)
46+
}
47+
48+
fn setup_common(clock: u32) {
49+
Self::set_clock(clock);
50+
Self::enable()
51+
}
52+
53+
/// Sets the clock speed.
54+
fn set_clock(clock: u32) {
55+
let mask = clock::ClockMask::with_clock(clock);
56+
Self::ControlRegister::set(mask.control_register_mask());
57+
Self::StatusRegister::set(mask.status_register_mask());
4358
}
4459

4560
/// Enables interrupts for the spi module.

src/spi/settings.rs

+127
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
use super::clock::ClockMask;
2+
3+
#[derive(Copy, Clone)]
4+
pub enum BitOrder {
5+
/// The least significant bit is sent first.
6+
LeastSignificantBit,
7+
/// The most significant bit is sent first.
8+
MostSignificantBit,
9+
}
10+
11+
#[derive(Copy, Clone)]
12+
pub enum ClockPhase {
13+
LeadingEdge,
14+
TrailingEdge,
15+
}
16+
17+
/// SPI settings.
18+
#[derive(Copy, Clone)]
19+
pub struct Settings {
20+
/// Whether the SPI module is enabled.
21+
enabled: bool,
22+
/// Whether to be configured as a master or slave.
23+
master: bool,
24+
/// The clock speed.
25+
clock: u32,
26+
/// The bit ordering.
27+
bit_order: BitOrder,
28+
/// The clock phase.
29+
clock_phase: ClockPhase,
30+
/// Whether interrupts should be enabled.
31+
enable_interrupts: bool,
32+
}
33+
34+
impl Settings {
35+
/// Gets the default settings for the master.
36+
pub fn master() -> Self {
37+
Settings {
38+
master: true,
39+
..Default::default()
40+
}
41+
}
42+
43+
/// Gets the default settings for the slave.
44+
pub fn slave() -> Self {
45+
Settings {
46+
master: false,
47+
..Default::default()
48+
}
49+
}
50+
51+
pub fn control_register_bits(self) -> u8 {
52+
let mut bits = 0;
53+
54+
bits |= self.clock().control_register_mask();
55+
56+
if self.enable_interrupts {
57+
bits |= control_register::INTERRUPT_ENABLE
58+
}
59+
if self.enabled {
60+
bits |= control_register::ENABLE
61+
}
62+
if let ClockPhase::LeadingEdge = self.clock_phase {
63+
bits |= control_register::CPHA;
64+
}
65+
66+
if let BitOrder::LeastSignificantBit = self.bit_order {
67+
bits |= control_register::DATA_ORDER_LSB;
68+
}
69+
bits
70+
}
71+
72+
pub fn status_register_bits(self) -> u8 {
73+
let mut bits = 0;
74+
75+
bits |= self.clock().status_register_mask();
76+
bits
77+
}
78+
79+
fn clock(self) -> ClockMask {
80+
ClockMask::with_clock(self.clock)
81+
}
82+
}
83+
84+
impl Default for Settings {
85+
fn default() -> Settings {
86+
Settings {
87+
enabled: true,
88+
master: true,
89+
// same as Arduino default in `SPI.h`.
90+
clock: 4_000_000,
91+
bit_order: BitOrder::MostSignificantBit,
92+
clock_phase: ClockPhase::LeadingEdge,
93+
enable_interrupts: false,
94+
}
95+
}
96+
}
97+
98+
/// Constants for the control register.
99+
pub mod control_register {
100+
/// Set if interrupts are enabled.
101+
pub const INTERRUPT_ENABLE: u8 = 1<<7;
102+
/// Set if the SPI module is enabled.
103+
pub const ENABLE: u8 = 1<<6;
104+
/// Set if data is sent in LSB format.
105+
pub const DATA_ORDER_LSB: u8 = 1<<5;
106+
/// Set if we are configuring a master.
107+
pub const MASTER: u8 = 1<<4;
108+
/// Clock polarity.
109+
pub const CPOL: u8 = 1<<3;
110+
/// Clock phase.
111+
pub const CPHA: u8 = 1<<2;
112+
/// Clock rate select 1.
113+
pub const SPR1: u8 = 1<<1;
114+
/// Clock rate select 2.
115+
pub const SPR0: u8 = 1<<0;
116+
}
117+
118+
/// Constants for the status register.
119+
pub mod status_register {
120+
/// SPI interrupt flag.
121+
pub const SPIF: u8 = 1<<7;
122+
/// Write collision flag.
123+
pub const WCOL: u8 = 1<<6;
124+
/// SPI double speed mode.
125+
pub const SPI2X: u8 = 1<<0;
126+
}
127+

0 commit comments

Comments
 (0)