Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Upgrading spi to embedded_hal 1.0 #517

Merged
merged 8 commits into from
Mar 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions avr-hal-generic/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ paste = "1.0.0"
avr-device = "0.5.4"
embedded-storage = "0.2"
embedded-hal = "1.0"
embedded-hal-bus = "0.1"
unwrap-infallible = "0.1.5"

[dependencies.embedded-hal-v0]
Expand Down
5 changes: 3 additions & 2 deletions avr-hal-generic/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
#![cfg_attr(avr_hal_asm_macro, feature(asm_experimental_arch))]
#![cfg_attr(not(avr_hal_asm_macro), feature(llvm_asm))]

pub use embedded_hal_v0 as hal;
pub use embedded_hal as hal;
pub use embedded_hal_v0 as hal_v0;

#[doc(hidden)]
pub use avr_device;
Expand All @@ -24,7 +25,7 @@ pub mod wdt;

/// Prelude containing all HAL traits
pub mod prelude {
pub use crate::hal::prelude::*;
pub use crate::hal_v0::prelude::*;
pub use ufmt::uWrite as _ufmt_uWrite;
pub use unwrap_infallible::UnwrapInfallible as _unwrap_infallible_UnwrapInfallible;
}
Expand Down
145 changes: 137 additions & 8 deletions avr-hal-generic/src/spi.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! SPI Implementation
use crate::port;
use core::marker::PhantomData;
use embedded_hal_v0::spi;
use embedded_hal::spi::{self,SpiBus};

/// Oscillator Clock Frequency division options.
///
Expand Down Expand Up @@ -69,12 +69,22 @@ impl Default for Settings {
/// intermediate abstraction ontop of which the [`Spi`] API is built. **Prefer using the
/// [`Spi`] API instead of this trait.**
pub trait SpiOps<H, SCLK, MOSI, MISO, CS> {
/// Sets up the control/status registers with the right settings for this secondary device
fn raw_setup(&mut self, settings: &Settings);
/// Disable the peripheral
fn raw_release(&mut self);

/// Check the interrupt flag to see if the write has completed
///
/// Returns `true` if the bus is idle
fn raw_check_iflag(&self) -> bool;
/// Read a byte from the data register
fn raw_read(&self) -> u8;
/// Write a byte to the data register, which begins transmission
/// automatically.
fn raw_write(&mut self, byte: u8);
/// Perform a transaction of a single byte
fn raw_transaction(&mut self, byte: u8) -> u8;
}

/// Wrapper for the CS pin
Expand Down Expand Up @@ -114,11 +124,45 @@ impl<CSPIN: port::PinOps> embedded_hal_v0::digital::v2::ToggleableOutputPin for
}
}

impl<CSPIN: port::PinOps> embedded_hal::digital::ErrorType for ChipSelectPin<CSPIN> {
type Error = core::convert::Infallible;
}

impl<CSPIN: port::PinOps> embedded_hal::digital::OutputPin for ChipSelectPin<CSPIN> {
fn set_high(&mut self) -> Result<(), Self::Error> {
self.0.set_high();
Ok(())
}

fn set_low(&mut self) -> Result<(), Self::Error> {
self.0.set_low();
Ok(())
}
}

impl<CSPIN: port::PinOps> embedded_hal::digital::StatefulOutputPin for ChipSelectPin<CSPIN> {
fn is_set_high(&mut self) -> Result<bool, Self::Error> {
Ok(self.0.is_set_high())
}

fn is_set_low(&mut self) -> Result<bool, Self::Error> {
Ok(self.0.is_set_low())
}
}



/// Behavior for a SPI interface.
///
/// Stores the SPI peripheral for register access. In addition, it takes
/// ownership of the MOSI and MISO pins to ensure they are in the correct mode.
/// Instantiate with the `new` method.
///
/// This can be used both with the embedded-hal 0.2 [`spi::FullDuplex`] trait, and
/// with the embedded-hal 1.0 [`spi::SpiBus`] trait.
///
/// [`spi::FullDuplex`]: `embedded_hal_v0::spi::FullDuplex`
/// [`spi::SpiBus`]: `embedded_hal::spi::SpiBus`
pub struct Spi<H, SPI, SCLKPIN, MOSIPIN, MISOPIN, CSPIN> {
p: SPI,
sclk: port::Pin<port::mode::Output, SCLKPIN>,
Expand Down Expand Up @@ -241,7 +285,7 @@ where
/// FullDuplex trait implementation, allowing this struct to be provided to
/// drivers that require it for operation. Only 8-bit word size is supported
/// for now.
impl<H, SPI, SCLKPIN, MOSIPIN, MISOPIN, CSPIN> spi::FullDuplex<u8>
impl<H, SPI, SCLKPIN, MOSIPIN, MISOPIN, CSPIN> embedded_hal_v0::spi::FullDuplex<u8>
for Spi<H, SPI, SCLKPIN, MOSIPIN, MISOPIN, CSPIN>
where
SPI: SpiOps<H, SCLKPIN, MOSIPIN, MISOPIN, CSPIN>,
Expand All @@ -266,6 +310,89 @@ where
}
}

impl<H, SPI, SCLKPIN, MOSIPIN, MISOPIN, CSPIN> embedded_hal::spi::ErrorType
for Spi<H, SPI, SCLKPIN, MOSIPIN, MISOPIN, CSPIN>
where
SPI: SpiOps<H, SCLKPIN, MOSIPIN, MISOPIN, CSPIN>,
SCLKPIN: port::PinOps,
MOSIPIN: port::PinOps,
MISOPIN: port::PinOps,
CSPIN: port::PinOps,
{
type Error = core::convert::Infallible;
}

impl<H, SPI, SCLKPIN, MOSIPIN, MISOPIN, CSPIN> SpiBus
for Spi<H, SPI, SCLKPIN, MOSIPIN, MISOPIN, CSPIN>
where
SPI: SpiOps<H, SCLKPIN, MOSIPIN, MISOPIN, CSPIN>,
SCLKPIN: port::PinOps,
MOSIPIN: port::PinOps,
MISOPIN: port::PinOps,
CSPIN: port::PinOps,
{
fn flush(&mut self) -> Result<(), Self::Error> {
if self.write_in_progress {
while !self.p.raw_check_iflag() {}
self.write_in_progress = false;
}

Ok(())
}
fn read(&mut self, read: &mut [u8]) -> Result<(), Self::Error> {
// Must flush() first, if asynchronous operations happened before this.
// To be removed if in the future we "only" implement embedded_hal 1.0
SpiBus::flush(self)?;

for b in read.iter_mut() {
// We send 0x00 on MOSI during "pure" reading
*b = self.p.raw_transaction(0x00);
}

Ok(())
}

fn write(&mut self, write: &[u8]) -> Result<(), Self::Error> {
// Must flush() first, if asynchronous operations happened before this.
// To be removed if in the future we "only" implement embedded_hal 1.0
SpiBus::flush(self)?;

for b in write.iter() {
self.p.raw_transaction(*b);
}

Ok(())
}

fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Self::Error> {
// Must flush() first, if asynchronous operations happened before this.
// To be removed if in the future we "only" implement embedded_hal 1.0
SpiBus::flush(self)?;

let longest = read.len().max(write.len());
for i in 0..longest {
let r = self.p.raw_transaction(*write.get(i).unwrap_or(&0x00));
if i < read.len() {
read[i] = r;
}
}

Ok(())
}
fn transfer_in_place(&mut self, buffer: &mut [u8]) -> Result<(), Self::Error> {
// Must flush() first, if asynchronous operations happened before this.
// To be removed if in the future we "only" implement embedded_hal 1.0
SpiBus::flush(self)?;

for b in buffer.iter_mut() {
*b = self.p.raw_transaction(*b)
}

Ok(())
}

}

/// Default Transfer trait implementation. Only 8-bit word size is supported for now.
impl<H, SPI, SCLKPIN, MOSIPIN, MISOPIN, CSPIN> embedded_hal_v0::blocking::spi::transfer::Default<u8>
for Spi<H, SPI, SCLKPIN, MOSIPIN, MISOPIN, CSPIN>
Expand Down Expand Up @@ -302,7 +429,7 @@ macro_rules! impl_spi {
cs: $cspin:ty,
) => {
impl $crate::spi::SpiOps<$HAL, $sclkpin, $mosipin, $misopin, $cspin> for $SPI {
/// Sets up the control/status registers with the right settings for this secondary device

fn raw_setup(&mut self, settings: &Settings) {
use $crate::hal::spi;

Expand Down Expand Up @@ -350,26 +477,28 @@ macro_rules! impl_spi {
});
}

/// Disable the peripheral
fn raw_release(&mut self) {
self.spcr.write(|w| w.spe().clear_bit());
}

/// Check the interrupt flag to see if the write has completed
fn raw_check_iflag(&self) -> bool {
self.spsr.read().spif().bit_is_set()
}

/// Read a byte from the data register
fn raw_read(&self) -> u8 {
self.spdr.read().bits()
}

/// Write a byte to the data register, which begins transmission
/// automatically.

fn raw_write(&mut self, byte: u8) {
self.spdr.write(|w| unsafe { w.bits(byte) });
}

fn raw_transaction(&mut self, byte: u8) -> u8 {
self.raw_write(byte);
while !self.raw_check_iflag() {}
self.raw_read()
}
}
};
}