Skip to content

Commit

Permalink
Add bitbanging SPI driver
Browse files Browse the repository at this point in the history
  • Loading branch information
bugadani committed Nov 7, 2023
1 parent 427b3e6 commit 46a7af5
Show file tree
Hide file tree
Showing 4 changed files with 118 additions and 15 deletions.
108 changes: 108 additions & 0 deletions src/board/drivers/bitbang_spi.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
use core::convert::Infallible;

use crate::hal::clock::Clocks;
use embassy_time::{Duration, Ticker};
use embedded_hal::{
digital::{InputPin, OutputPin, PinState},
spi::ErrorType,
};
use embedded_hal_async::spi::SpiBus;
use fugit::HertzU32;

pub struct BitbangSpi<MOSI, MISO, SCLK> {
mosi: MOSI,
miso: MISO,
sclk: SCLK,
half_bit_delay: Duration,
}

impl<MOSI, MISO, SCLK> BitbangSpi<MOSI, MISO, SCLK>
where
MOSI: OutputPin,
MISO: InputPin,
SCLK: OutputPin,
{
pub const fn new(mosi: MOSI, miso: MISO, sclk: SCLK, frequency: HertzU32) -> Self {
Self {
mosi,
miso,
sclk,
half_bit_delay: Self::frequency_to_duration(frequency),
}
}

const fn frequency_to_duration(frequency: HertzU32) -> Duration {
let bit_duration: fugit::Duration<u32, 1, { embassy_time::TICK_HZ as u32 }> =
frequency.into_duration();
let clock_ticks = bit_duration.ticks() / 2;
Duration::from_ticks(clock_ticks as u64)
}

pub async fn transfer_byte(&mut self, write: u8, out: &mut u8) {
let mut ticker = Ticker::every(self.half_bit_delay);
*out = 0;
for i in (0..8).rev() {
ticker.next().await;
self.sclk.set_high().unwrap();
self.mosi
.set_state(PinState::from(write & (1 << i) != 0))
.unwrap();

ticker.next().await;
self.sclk.set_low().unwrap();
*out |= (self.miso.is_high().unwrap() as u8) << i;
}
}

pub fn change_bus_frequency(&mut self, frequency: HertzU32, _clocks: &Clocks<'_>) {
self.half_bit_delay = Self::frequency_to_duration(frequency);
}
}

impl<MOSI, MISO, SCLK> ErrorType for BitbangSpi<MOSI, MISO, SCLK>
where
MOSI: OutputPin,
MISO: InputPin,
SCLK: OutputPin,
{
type Error = Infallible;
}

impl<MOSI, MISO, SCLK> SpiBus for BitbangSpi<MOSI, MISO, SCLK>
where
MOSI: OutputPin,
MISO: InputPin,
SCLK: OutputPin,
{
async fn read(&mut self, bytes: &mut [u8]) -> Result<(), Self::Error> {
for byte in bytes {
self.transfer_byte(0, byte).await;
}
Ok(())
}

async fn write(&mut self, bytes: &[u8]) -> Result<(), Self::Error> {
for byte in bytes {
self.transfer_byte(*byte, &mut 0).await;
}
Ok(())
}

async fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Self::Error> {
for (read, write) in read.iter_mut().zip(write.iter()) {
self.transfer_byte(*write, read).await;
}
Ok(())
}

async fn transfer_in_place(&mut self, bytes: &mut [u8]) -> Result<(), Self::Error> {
for byte in bytes {
self.transfer_byte(*byte, byte).await;
}
Ok(())
}

async fn flush(&mut self) -> Result<(), Self::Error> {
Ok(())
}
}
1 change: 1 addition & 0 deletions src/board/drivers/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
pub mod battery_monitor;
pub mod bitbang_spi;
pub mod display;
pub mod frontend;
2 changes: 0 additions & 2 deletions src/board/startup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,6 @@ use esp_println::logger::init_logger;

use fugit::RateExtU32;

pub static WIFI_DRIVER: StaticCell<WifiDriver> = StaticCell::new();

pub struct StartupResources {
pub display: Display,
pub frontend: EcgFrontend,
Expand Down
22 changes: 9 additions & 13 deletions src/states/measure.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use crate::{
board::{
config::types::FilterStrength,
hal::{prelude::*, spi::Error as SpiError},
hal::prelude::*,
initialized::{Context, InnerContext},
EcgFrontend, PoweredEcgFrontend,
AdcSpi, EcgFrontend, PoweredEcgFrontend,
},
states::{menu::AppMenu, to_progress, INIT_MENU_THRESHOLD, INIT_TIME, MIN_FRAME_TIME},
task_control::{TaskControlToken, TaskController},
Expand All @@ -15,6 +15,7 @@ use alloc::{boxed::Box, sync::Arc};
use embassy_sync::{blocking_mutex::raw::CriticalSectionRawMutex, channel::Channel};
use embassy_time::{Duration, Instant, Ticker};
use embedded_graphics::Drawable;
use embedded_hal::spi::ErrorType;
use embedded_hal_bus::spi::DeviceError;
use gui::screens::{init::StartupScreen, measure::EcgScreen};
use macros as cardio;
Expand All @@ -40,7 +41,10 @@ type MessageQueue = Channel<CriticalSectionRawMutex, Sample, 32>;
unsafe impl Send for PoweredEcgFrontend {}

struct EcgTaskParams {
token: TaskControlToken<Result<(), Error<SpiError>>, PoweredEcgFrontend>,
token: TaskControlToken<
Result<(), Error<<AdcSpi<'static> as ErrorType>::Error>>,
PoweredEcgFrontend,
>,
sender: Arc<MessageQueue>,
}

Expand Down Expand Up @@ -335,7 +339,7 @@ async fn reader_task(params: EcgTaskParams) {
async fn read_ecg(
queue: &MessageQueue,
frontend: &mut PoweredEcgFrontend,
) -> Result<(), Error<SpiError>> {
) -> Result<(), Error<<AdcSpi<'static> as ErrorType>::Error>> {
loop {
match frontend.read().await {
Ok(sample) => {
Expand All @@ -348,15 +352,7 @@ async fn read_ecg(
warn!("Sample lost");
}
}
Err(e) => {
return Err(match e {
Error::InvalidState => Error::InvalidState,
Error::UnexpectedDeviceId => Error::UnexpectedDeviceId,
Error::Verification => Error::Verification,
Error::Transfer(DeviceError::Spi(e)) => Error::Transfer(e),
Error::Transfer(DeviceError::Cs(_)) => unreachable!(),
});
}
Err(e) => return Err(e),
}
}
}

0 comments on commit 46a7af5

Please sign in to comment.