Skip to content

Commit

Permalink
use timers instead of delay objects
Browse files Browse the repository at this point in the history
  • Loading branch information
sajattack committed Mar 5, 2019
1 parent 8c9c1f3 commit 0ef6938
Show file tree
Hide file tree
Showing 7 changed files with 123 additions and 136 deletions.
9 changes: 9 additions & 0 deletions .cargo/config
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# vim:ft=toml:
[target.thumbv7em-none-eabihf]
runner = 'arm-none-eabi-gdb'
rustflags = [
"-C", "link-arg=-Tlink.x",
]

[build]
target = "thumbv7em-none-eabihf"
7 changes: 7 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,10 @@ nb = "~0.1"
[dependencies.embedded-hal]
version = "~0.2"
features = ["unproven"]

[dev-dependencies.metro_m4]
version = "~0.1"
features = ["unproven"]

[dev-dependencies]
panic-halt = "~0.2"
56 changes: 56 additions & 0 deletions examples/spi.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
#![no_std]
#![no_main]

#[allow(unused)]
use panic_halt;

use metro_m4 as hal;
use embedded_hal;
use hal::clock::GenericClockController;
use hal::delay::Delay;
use hal::prelude::*;
use hal::{entry, CorePeripherals, Peripherals};
use hal::timer::TimerCounter;
use nb::block;
use bitbang_hal;

#[entry]
fn main() -> ! {
let mut peripherals = Peripherals::take().unwrap();
let core = CorePeripherals::take().unwrap();
let mut clocks = GenericClockController::with_external_32kosc(
peripherals.GCLK,
&mut peripherals.MCLK,
&mut peripherals.OSC32KCTRL,
&mut peripherals.OSCCTRL,
&mut peripherals.NVMCTRL,
);

let gclk0 = clocks.gclk0();
let timer_clock = clocks.tc2_tc3(&gclk0).unwrap();
let mut timer = TimerCounter::tc3_(
&timer_clock,
peripherals.TC3,
&mut peripherals.MCLK);
timer.start(6.mhz()); // results in a SPI frequency of 3MHz

let mut pins = hal::Pins::new(peripherals.PORT);
let miso = pins.miso.into_pull_up_input(&mut pins.port);
let mosi = pins.mosi.into_push_pull_output(&mut pins.port);
let sck = pins.sck.into_push_pull_output(&mut pins.port);

let mode = embedded_hal::spi::Mode {
polarity: embedded_hal::spi::Polarity::IdleLow,
phase: embedded_hal::spi::Phase::CaptureOnFirstTransition,
};
let mut spi = bitbang_hal::spi::SPI::new(mode, miso, mosi, sck, timer);

let mut delay = Delay::new(core.SYST, &mut clocks);

loop {
for byte in b"Hello, World!" {
block!(spi.send(*byte)).unwrap();
}
delay.delay_ms(1000u16);
}
}
1 change: 0 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,3 @@
pub mod i2c;
pub mod spi;
pub mod serial;
pub mod time;
45 changes: 20 additions & 25 deletions src/serial.rs
Original file line number Diff line number Diff line change
@@ -1,66 +1,62 @@
use embedded_hal::digital::{OutputPin, InputPin};
use embedded_hal::blocking::delay::DelayUs;
use embedded_hal::timer::{CountDown, Periodic};
use embedded_hal::serial;
use crate::time::Hertz;
use nb::block;

pub struct Serial<TX, RX, Delay>
pub struct Serial<TX, RX, Timer>
where
TX: OutputPin,
RX: InputPin,
Delay: DelayUs<u32>,
Timer: CountDown + Periodic,
{
delay_time: u32,
tx: TX,
rx: RX,
delay: Delay,
timer: Timer,
}

impl <TX, RX, Delay> Serial <TX, RX, Delay>
impl <TX, RX, Timer> Serial <TX, RX, Timer>
where
TX: OutputPin,
RX: InputPin,
Delay: DelayUs<u32>
Timer: CountDown + Periodic
{
pub fn new<F: Into<Hertz>>(
baud: F,
pub fn new(
tx: TX,
rx: RX,
delay: Delay
timer: Timer
) -> Self {
let delay_time = 1_000_000 / (baud.into().0);
Serial {
delay_time: delay_time,
tx: tx,
rx: rx,
delay: delay
timer: timer
}
}
}

impl <TX, RX, Delay> serial::Write<u8> for Serial <TX, RX, Delay>
impl <TX, RX, Timer> serial::Write<u8> for Serial <TX, RX, Timer>
where
TX: OutputPin,
RX: InputPin,
Delay: DelayUs<u32>
Timer: CountDown + Periodic
{

type Error = ();

fn write(&mut self, byte: u8) -> nb::Result<(), Self::Error> {
let mut data_out = byte;
self.tx.set_low(); // start bit
self.delay.delay_us(self.delay_time);
block!(self.timer.wait()).ok();
for _bit in 0..8 {
if data_out & 1 == 1 {
self.tx.set_high();
} else {
self.tx.set_low();
}
data_out >>= 1;
self.delay.delay_us(self.delay_time);
block!(self.timer.wait()).ok();
}
self.tx.set_high(); // stop bit
self.delay.delay_us(self.delay_time);
block!(self.timer.wait()).ok();
Ok(())
}

Expand All @@ -69,11 +65,11 @@ where
}
}

impl <TX, RX, Delay> serial::Read<u8> for Serial <TX, RX, Delay>
impl <TX, RX, Timer> serial::Read<u8> for Serial <TX, RX, Timer>
where
TX: OutputPin,
RX: InputPin,
Delay: DelayUs<u32>
Timer: CountDown + Periodic
{

type Error = ();
Expand All @@ -82,17 +78,16 @@ where
let mut data_in = 0;
// wait for start bit
while self.rx.is_high() {}
// catch the middle of the first bit
self.delay.delay_us((self.delay_time as f32 * 1.5) as u32);
block!(self.timer.wait()).ok();
for _bit in 0..8 {
data_in <<= 1;
if self.rx.is_high() {
data_in |= 1
}
self.delay.delay_us(self.delay_time);
block!(self.timer.wait()).ok();
}
// wait for stop bit
self.delay.delay_us(self.delay_time);
block!(self.timer.wait()).ok();
Ok(data_in)
}
}
73 changes: 31 additions & 42 deletions src/spi.rs
Original file line number Diff line number Diff line change
@@ -1,70 +1,59 @@
use embedded_hal::spi::FullDuplex;
use embedded_hal::spi::Mode;
use embedded_hal::spi::Phase::*;
use embedded_hal::spi::Polarity::*;
use embedded_hal::spi::{FullDuplex, Mode, Phase::*, Polarity::*};
use embedded_hal::digital::{InputPin, OutputPin};
use embedded_hal::blocking::delay::DelayUs;
use crate::time::Hertz;
use nb;
use embedded_hal::timer::{CountDown, Periodic};
use nb::block;

#[derive(Debug)]
pub enum Error {
Unimplemented,
}

pub struct SPI<Miso, Mosi, Sck, Delay>
/// A Full-Duplex SPI implementation, takes 3 pins, and a timer running at 2x
/// the desired SPI frequency.
pub struct SPI<Miso, Mosi, Sck, Timer>
where
Miso: InputPin,
Mosi: OutputPin,
Sck: OutputPin,
Delay: DelayUs<u32>
Timer: CountDown + Periodic,
{
mode: Mode,
miso: Miso,
mosi: Mosi,
sck: Sck,
delay: Delay,
half_delay_us: u32,
timer: Timer,
}

impl <Miso, Mosi, Sck, Delay> SPI<Miso, Mosi, Sck, Delay>
impl <Miso, Mosi, Sck, Timer> SPI<Miso, Mosi, Sck, Timer>
where
Miso: InputPin,
Mosi: OutputPin,
Sck: OutputPin,
Delay: DelayUs<u32>
Timer: CountDown + Periodic,
{
pub fn new<F: Into<Hertz>>(
freq: F,
pub fn new(
mode: Mode,
miso: Miso,
mosi: Mosi,
sck: Sck,
delay: Delay,
timer: Timer,
) -> Self {
let hertz = freq.into().0;
let mut half_delay_us = 500_000 / hertz;
// round up the delay (lower the baudrate)
if 500_000 % hertz != 0 {
half_delay_us += 1;
}
SPI {
mode: mode,
miso: miso,
mosi: mosi,
sck: sck,
delay: delay,
half_delay_us: half_delay_us
timer: timer,
}
}
}

impl<Miso, Mosi, Sck, Delay> FullDuplex<u8> for SPI<Miso, Mosi, Sck, Delay>
impl<Miso, Mosi, Sck, Timer> FullDuplex<u8> for SPI<Miso, Mosi, Sck, Timer>
where
Miso: InputPin,
Mosi: OutputPin,
Sck: OutputPin,
Delay: DelayUs<u32>
Timer: CountDown + Periodic
{
type Error = Error;

Expand All @@ -74,47 +63,47 @@ where
for _bit in 0..8 {
if self.mode.phase == CaptureOnFirstTransition {
if self.mode.polarity == IdleLow {
self.delay.delay_us(self.half_delay_us);
block!(self.timer.wait()).ok();
self.sck.set_high();
if self.miso.is_high() {
data_in = (data_in << 1) | 1
} else {
data_in = data_in << 1
}
self.delay.delay_us(self.half_delay_us);
block!(self.timer.wait()).ok();
self.sck.set_low();
} else {
self.delay.delay_us(self.half_delay_us);
block!(self.timer.wait()).ok();
self.sck.set_low();
if self.miso.is_high() {
data_in = (data_in << 1) | 1
} else {
data_in = data_in << 1
}
self.delay.delay_us(self.half_delay_us);
block!(self.timer.wait()).ok();
self.sck.set_high();
}
} else {
if self.mode.polarity == IdleLow {
self.sck.set_high();
self.delay.delay_us(self.half_delay_us);
block!(self.timer.wait()).ok();
if self.miso.is_high() {
data_in = (data_in << 1) | 1
} else {
data_in = data_in << 1
}
self.sck.set_low();
self.delay.delay_us(self.half_delay_us);
block!(self.timer.wait()).ok();
} else {
self.sck.set_low();
self.delay.delay_us(self.half_delay_us);
block!(self.timer.wait()).ok();
if self.miso.is_high() {
data_in = (data_in << 1) | 1
} else {
data_in = data_in << 1
}
self.sck.set_high();
self.delay.delay_us(self.half_delay_us);
block!(self.timer.wait()).ok();
}
}
}
Expand All @@ -132,27 +121,27 @@ where
}
if self.mode.phase == CaptureOnFirstTransition {
if self.mode.polarity == IdleLow {
self.delay.delay_us(self.half_delay_us);
block!(self.timer.wait()).ok();
self.sck.set_high();
self.delay.delay_us(self.half_delay_us);
block!(self.timer.wait()).ok();
self.sck.set_low();
} else {
self.delay.delay_us(self.half_delay_us);
block!(self.timer.wait()).ok();
self.sck.set_low();
self.delay.delay_us(self.half_delay_us);
block!(self.timer.wait()).ok();
self.sck.set_high();
}
} else {
if self.mode.polarity == IdleLow {
self.sck.set_high();
self.delay.delay_us(self.half_delay_us);
block!(self.timer.wait()).ok();
self.sck.set_low();
self.delay.delay_us(self.half_delay_us);
block!(self.timer.wait()).ok();
} else {
self.sck.set_low();
self.delay.delay_us(self.half_delay_us);
block!(self.timer.wait()).ok();
self.sck.set_high();
self.delay.delay_us(self.half_delay_us);
block!(self.timer.wait()).ok();
}
}
data_out <<= 1;
Expand Down
Loading

0 comments on commit 0ef6938

Please sign in to comment.