Skip to content

Commit

Permalink
bitbang spi seems to work ok
Browse files Browse the repository at this point in the history
  • Loading branch information
sajattack committed Feb 18, 2019
0 parents commit 97ed511
Show file tree
Hide file tree
Showing 7 changed files with 251 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
/target
**/*.rs.bk
Cargo.lock
12 changes: 12 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[package]
name = "bitbang-hal"
version = "0.1.0"
authors = ["Paul Sajna <sajattack@gmail.com>"]
edition = "2018"

[dependencies]
nb = "~0.1"

[dependencies.embedded-hal]
version = "~0.2"
features = ["unproven"]
Empty file added src/i2c.rs
Empty file.
6 changes: 6 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#![no_std]

pub mod i2c;
pub mod spi;
pub mod serial;
pub mod time;
Empty file added src/serial.rs
Empty file.
162 changes: 162 additions & 0 deletions src/spi.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
use embedded_hal::spi::FullDuplex;
use embedded_hal::spi::Mode;
use embedded_hal::spi::Phase::*;
use embedded_hal::spi::Polarity::*;
use embedded_hal::digital::{InputPin, OutputPin};
use embedded_hal::blocking::delay::DelayUs;
use crate::time::Hertz;
use nb;

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

pub struct SPI<Miso, Mosi, Sck, Delay>
where
Miso: InputPin,
Mosi: OutputPin,
Sck: OutputPin,
Delay: DelayUs<u32>
{
mode: Mode,
miso: Miso,
mosi: Mosi,
sck: Sck,
delay: Delay,
half_delay_us: u32,
}

impl <Miso, Mosi, Sck, Delay> SPI<Miso, Mosi, Sck, Delay>
where
Miso: InputPin,
Mosi: OutputPin,
Sck: OutputPin,
Delay: DelayUs<u32>
{
pub fn new<F: Into<Hertz>>(
freq: F,
mode: Mode,
miso: Miso,
mosi: Mosi,
sck: Sck,
delay: Delay,
) -> 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
}
}
}

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

fn read(&mut self) -> nb::Result<u8, Error> {
self.mosi.set_low();
let mut data_in: u8 = 0;
for _bit in 0..8 {
if self.mode.phase == CaptureOnFirstTransition {
if self.mode.polarity == IdleLow {
self.delay.delay_us(self.half_delay_us);
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);
self.sck.set_low();
} else {
self.delay.delay_us(self.half_delay_us);
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);
self.sck.set_high();
}
} else {
if self.mode.polarity == IdleLow {
self.sck.set_high();
self.delay.delay_us(self.half_delay_us);
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);
} else {
self.sck.set_low();
self.delay.delay_us(self.half_delay_us);
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);
}
}
}
Ok(data_in)
}

fn send(&mut self, byte: u8) -> nb::Result<(), Self::Error> {
let mut data_out = byte;
for _bit in 0..8 {
let out_bit = (data_out >> 7) & 1;
if out_bit == 1 {
self.mosi.set_high();
} else {
self.mosi.set_low();
}
if self.mode.phase == CaptureOnFirstTransition {
if self.mode.polarity == IdleLow {
self.delay.delay_us(self.half_delay_us);
self.sck.set_high();
self.delay.delay_us(self.half_delay_us);
self.sck.set_low();
} else {
self.delay.delay_us(self.half_delay_us);
self.sck.set_low();
self.delay.delay_us(self.half_delay_us);
self.sck.set_high();
}
} else {
if self.mode.polarity == IdleLow {
self.sck.set_high();
self.delay.delay_us(self.half_delay_us);
self.sck.set_low();
self.delay.delay_us(self.half_delay_us);
} else {
self.sck.set_low();
self.delay.delay_us(self.half_delay_us);
self.sck.set_high();
self.delay.delay_us(self.half_delay_us);
}
}
data_out <<= 1;
}
Ok(())
}
}
68 changes: 68 additions & 0 deletions src/time.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
//! Time units
/// Bits per second
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct Bps(pub u32);

/// Hertz
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct Hertz(pub u32);

/// KiloHertz
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct KiloHertz(pub u32);

/// MegaHertz
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct MegaHertz(pub u32);

/// Extension trait that adds convenience methods to the `u32` type
pub trait U32Ext {
/// Wrap in `Bps`
fn bps(self) -> Bps;

/// Wrap in `Hertz`
fn hz(self) -> Hertz;

/// Wrap in `KiloHertz`
fn khz(self) -> KiloHertz;

/// Wrap in `MegaHertz`
fn mhz(self) -> MegaHertz;
}

impl U32Ext for u32 {
fn bps(self) -> Bps {
Bps(self)
}

fn hz(self) -> Hertz {
Hertz(self)
}

fn khz(self) -> KiloHertz {
KiloHertz(self)
}

fn mhz(self) -> MegaHertz {
MegaHertz(self)
}
}

impl Into<Hertz> for KiloHertz {
fn into(self) -> Hertz {
Hertz(self.0 * 1_000)
}
}

impl Into<Hertz> for MegaHertz {
fn into(self) -> Hertz {
Hertz(self.0 * 1_000_000)
}
}

impl Into<KiloHertz> for MegaHertz {
fn into(self) -> KiloHertz {
KiloHertz(self.0 * 1_000)
}
}

0 comments on commit 97ed511

Please sign in to comment.