diff --git a/arduino-hal/src/lib.rs b/arduino-hal/src/lib.rs index f5640f35c9..5c358cfccc 100644 --- a/arduino-hal/src/lib.rs +++ b/arduino-hal/src/lib.rs @@ -38,6 +38,18 @@ pub mod port; #[cfg(feature = "board-selected")] pub use port::Pins; +#[cfg(feature = "board-selected")] +pub mod adc { + pub use crate::hal::adc::{ + channel, AdcChannel, AdcOps, AdcSettings, Channel, ClockDivider, ReferenceVoltage, + }; + + /// Check the [`avr_hal_generic::adc::Adc`] documentation. + pub type Adc = crate::hal::Adc; +} +#[cfg(feature = "board-selected")] +pub use adc::Adc; + #[cfg(feature = "board-selected")] pub mod i2c { pub use crate::hal::i2c::*; @@ -48,16 +60,13 @@ pub mod i2c { pub use i2c::I2c; #[cfg(feature = "board-selected")] -pub mod adc { - pub use crate::hal::adc::{ - channel, AdcChannel, AdcOps, AdcSettings, Channel, ClockDivider, ReferenceVoltage, - }; +pub mod spi { + pub use crate::hal::spi::*; - /// Check the [`avr_hal_generic::adc::Adc`] documentation. - pub type Adc = crate::hal::Adc; + pub type Spi = crate::hal::spi::Spi; } #[cfg(feature = "board-selected")] -pub use adc::Adc; +pub use spi::Spi; #[cfg(feature = "board-selected")] pub mod usart { diff --git a/avr-hal-generic/src/spi.rs b/avr-hal-generic/src/spi.rs index fe26748fde..3a68e2f4b3 100644 --- a/avr-hal-generic/src/spi.rs +++ b/avr-hal-generic/src/spi.rs @@ -1,4 +1,6 @@ //! SPI Implementation +use crate::port; +use core::marker::PhantomData; use embedded_hal::spi; /// Oscillator Clock Frequency division options. @@ -64,220 +66,268 @@ impl Default for Settings { } } +/// Internal trait for low-level SPI peripherals +/// +/// This trait defines the common interface for all SPI peripheral variants. It is used as an +/// intermediate abstraction ontop of which the [`Spi`] API is built. **Prefer using the +/// [`Spi`] API instead of this trait.** +pub trait SpiOps { + fn raw_setup(&mut self, settings: &Settings); + fn raw_release(&mut self); -/// Implement traits for a SPI interface -#[macro_export] -macro_rules! impl_spi { - ( - $(#[$spi_attr:meta])* - pub struct $Spi:ident { - peripheral: $SPI:ty, - pins: { - sclk: $sclkmod:ident::$SCLK:ident, - mosi: $mosimod:ident::$MOSI:ident, - miso: $misomod:ident::$MISO:ident, - cs: $csmod:ident::$CS:ident, - } - } - ) => { - /// First match was without a 'ChipSelectPin' - /// we set it here to a default name and then - /// recusiv expand to the real inplementation - $crate::impl_spi! { - pub struct $Spi { - peripheral: $SPI, - pins: { - sclk: $sclkmod::$SCLK, - mosi: $mosimod::$MOSI, - miso: $misomod::$MISO, - cs: $csmod::$CS, - } - } - pub struct ChipSelectPin; - } - }; - + fn raw_check_iflag(&self) -> bool; + fn raw_read(&self) -> u8; + fn raw_write(&mut self, byte: u8); +} - ( - $(#[$spi_attr:meta])* - pub struct $Spi:ident { - peripheral: $SPI:ty, - pins: { - sclk: $sclkmod:ident::$SCLK:ident, - mosi: $mosimod:ident::$MOSI:ident, - miso: $misomod:ident::$MISO:ident, - cs: $csmod:ident::$CS:ident, - } - } - pub struct $ChipSelectPin:ident; - ) => { +/// Wrapper for the CS pin +/// +/// Used to contain the chip-select pin during operation to prevent its mode from being +/// changed from Output. This is necessary because the SPI state machine would otherwise +/// reset itself to SPI slave mode immediately. This wrapper can be used just like an +/// output pin, because it implements all the same traits from embedded-hal. +pub struct ChipSelectPin(port::Pin); - /// Wrapper for the CS pin - /// - /// Used to contain the chip-select pin during operation to prevent its mode from being - /// changed from Output. This is necessary because the SPI state machine would otherwise - /// reset itself to SPI slave mode immediately. This wrapper can be used just like an - /// output pin, because it implements all the same traits from embedded-hal. - pub struct $ChipSelectPin($csmod::$CS<$crate::port::mode::Output>); - impl $crate::hal::digital::v2::OutputPin for $ChipSelectPin { - type Error = $crate::void::Void; - fn set_low(&mut self) -> Result<(), Self::Error> { - self.0.set_low() - } - fn set_high(&mut self) -> Result<(), Self::Error> { - self.0.set_high() - } - } - impl $crate::hal::digital::v2::StatefulOutputPin for $ChipSelectPin { - fn is_set_low(&self) -> Result { - self.0.is_set_low() - } - fn is_set_high(&self) -> Result { - self.0.is_set_high() - } - } - impl $crate::hal::digital::v2::ToggleableOutputPin for $ChipSelectPin { - type Error = $crate::void::Void; - fn toggle(&mut self) -> Result<(), Self::Error> { - self.0.toggle() - } - } +impl hal::digital::v2::OutputPin for ChipSelectPin { + type Error = crate::void::Void; + fn set_low(&mut self) -> Result<(), Self::Error> { + self.0.set_low(); + Ok(()) + } + fn set_high(&mut self) -> Result<(), Self::Error> { + self.0.set_high(); + Ok(()) + } +} - /// 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. - $(#[$spi_attr])* - pub struct $Spi { - peripheral: $SPI, - sclk: $sclkmod::$SCLK<$crate::port::mode::Output>, - mosi: $mosimod::$MOSI<$crate::port::mode::Output>, - miso: $misomod::$MISO<$crate::port::mode::Input>, - settings: Settings, - is_write_in_progress: bool, - } +impl hal::digital::v2::StatefulOutputPin for ChipSelectPin { + fn is_set_low(&self) -> Result { + Ok(self.0.is_set_low()) + } + fn is_set_high(&self) -> Result { + Ok(self.0.is_set_high()) + } +} - impl $Spi<$crate::port::mode::PullUp> { - /// Instantiate an SPI with the registers, SCLK/MOSI/MISO/CS pins, and settings, - /// with the internal pull-up enabled on the MISO pin. - /// - /// The pins are not actually used directly, but they are moved into the struct in - /// order to enforce that they are in the correct mode, and cannot be used by anyone - /// else while SPI is active. CS is placed into a `ChipSelectPin` instance and given - /// back so that its output state can be changed as needed. - pub fn new( - peripheral: $SPI, - sclk: $sclkmod::$SCLK<$crate::port::mode::Output>, - mosi: $mosimod::$MOSI<$crate::port::mode::Output>, - miso: $misomod::$MISO<$crate::port::mode::Input<$crate::port::mode::PullUp>>, - cs: $csmod::$CS<$crate::port::mode::Output>, - settings: Settings - ) -> (Self, $ChipSelectPin) { - let spi = $Spi { - peripheral, - sclk, - mosi, - miso, - settings, - is_write_in_progress: false, - }; - spi.setup(); - (spi, $ChipSelectPin(cs)) - } - } +impl hal::digital::v2::ToggleableOutputPin for ChipSelectPin { + type Error = crate::void::Void; + fn toggle(&mut self) -> Result<(), Self::Error> { + self.0.toggle(); + Ok(()) + } +} - impl $Spi<$crate::port::mode::Floating> { - /// Instantiate an SPI with the registers, SCLK/MOSI/MISO/CS pins, and settings, - /// with an external pull-up on the MISO pin. - /// - /// The pins are not actually used directly, but they are moved into the struct in - /// order to enforce that they are in the correct mode, and cannot be used by anyone - /// else while SPI is active. CS is placed into a `ChipSelectPin` instance and given - /// back so that its output state can be changed as needed. - pub fn with_external_pullup( - peripheral: $SPI, - sclk: $sclkmod::$SCLK<$crate::port::mode::Output>, - mosi: $mosimod::$MOSI<$crate::port::mode::Output>, - miso: $misomod::$MISO<$crate::port::mode::Input<$crate::port::mode::Floating>>, - settings: Settings - ) -> Self { - let spi = $Spi { - peripheral, - sclk, - mosi, - miso, - settings, - is_write_in_progress: false, - }; - spi.setup(); - spi +/// 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. +pub struct Spi { + p: SPI, + sclk: port::Pin, + mosi: port::Pin, + miso: port::Pin, + write_in_progress: bool, + _cs: PhantomData, + _h: PhantomData, +} + +impl Spi +where + SPI: SpiOps, + SCLKPIN: port::PinOps, + MOSIPIN: port::PinOps, + MISOPIN: port::PinOps, + CSPIN: port::PinOps, +{ + /// Instantiate an SPI with the registers, SCLK/MOSI/MISO/CS pins, and settings, + /// with the internal pull-up enabled on the MISO pin. + /// + /// The pins are not actually used directly, but they are moved into the struct in + /// order to enforce that they are in the correct mode, and cannot be used by anyone + /// else while SPI is active. CS is placed into a `ChipSelectPin` instance and given + /// back so that its output state can be changed as needed. + pub fn new( + p: SPI, + sclk: port::Pin, + mosi: port::Pin, + miso: port::Pin, MISOPIN>, + cs: port::Pin, + settings: Settings, + ) -> (Self, ChipSelectPin) { + let mut spi = Self { + p, + sclk, + mosi, + miso: miso.forget_imode(), + write_in_progress: false, + _cs: PhantomData, + _h: PhantomData, + }; + spi.p.raw_setup(&settings); + (spi, ChipSelectPin(cs)) + } + + /// Instantiate an SPI with the registers, SCLK/MOSI/MISO/CS pins, and settings, + /// with an external pull-up on the MISO pin. + /// + /// The pins are not actually used directly, but they are moved into the struct in + /// order to enforce that they are in the correct mode, and cannot be used by anyone + /// else while SPI is active. + pub fn with_external_pullup( + p: SPI, + sclk: port::Pin, + mosi: port::Pin, + miso: port::Pin, MISOPIN>, + cs: port::Pin, + settings: Settings, + ) -> (Self, ChipSelectPin) { + let mut spi = Self { + p, + sclk, + mosi, + miso: miso.forget_imode(), + write_in_progress: false, + _cs: PhantomData, + _h: PhantomData, + }; + spi.p.raw_setup(&settings); + (spi, ChipSelectPin(cs)) + } + + /// Reconfigure the SPI peripheral after initializing + pub fn reconfigure(&mut self, settings: Settings) -> nb::Result<(), crate::void::Void> { + // wait for any in-flight writes to complete + self.flush()?; + self.p.raw_setup(&settings); + Ok(()) + } + + /// Disable the SPI device and release ownership of the peripheral + /// and pins. Instance can no-longer be used after this is + /// invoked. + pub fn release( + mut self, + cs: ChipSelectPin, + ) -> ( + SPI, + port::Pin, + port::Pin, + port::Pin, + port::Pin, + ) { + self.p.raw_release(); + (self.p, self.sclk, self.mosi, self.miso, cs.0) + } + + fn flush(&mut self) -> nb::Result<(), void::Void> { + if self.write_in_progress { + if self.p.raw_check_iflag() { + self.write_in_progress = false; + } else { + return Err(nb::Error::WouldBlock); } } + Ok(()) + } - impl $Spi { - /// Disable the SPI device and release ownership of the peripheral - /// and pins. Instance can no-longer be used after this is - /// invoked. - pub fn release(self, cs: $ChipSelectPin) -> ( - $SPI, - $sclkmod::$SCLK<$crate::port::mode::Output>, - $mosimod::$MOSI<$crate::port::mode::Output>, - $misomod::$MISO<$crate::port::mode::Input>, - $csmod::$CS<$crate::port::mode::Output>, - ) { - self.peripheral.spcr.write(|w| { - w.spe().clear_bit() - }); - (self.peripheral, self.sclk, self.mosi, self.miso, cs.0) - } + fn write(&mut self, byte: u8) { + self.write_in_progress = true; + self.p.raw_write(byte); + } +} - /// Write a byte to the data register, which begins transmission - /// automatically. - fn write(&mut self, byte: u8) { - self.is_write_in_progress = true; - self.peripheral.spdr.write(|w| unsafe { w.bits(byte) }); - } +/// 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 spi::FullDuplex + for Spi +where + SPI: SpiOps, + SCLKPIN: port::PinOps, + MOSIPIN: port::PinOps, + MISOPIN: port::PinOps, + CSPIN: port::PinOps, +{ + type Error = void::Void; - /// Check if write flag is set, and return a WouldBlock error if it is not. - fn flush(&mut self) -> $crate::nb::Result<(), $crate::void::Void> { - if self.is_write_in_progress { - if self.peripheral.spsr.read().spif().bit_is_set() { - self.is_write_in_progress = false; - } else { - return Err($crate::nb::Error::WouldBlock); - } - } - Ok(()) - } + /// Sets up the device for transmission and sends the data + fn send(&mut self, byte: u8) -> nb::Result<(), Self::Error> { + self.flush()?; + self.write(byte); + Ok(()) + } + /// Reads and returns the response in the data register + fn read(&mut self) -> nb::Result { + self.flush()?; + Ok(self.p.raw_read()) + } +} + +/// Default Transfer trait implementation. Only 8-bit word size is supported for now. +impl hal::blocking::spi::transfer::Default + for Spi +where + SPI: SpiOps, + SCLKPIN: port::PinOps, + MOSIPIN: port::PinOps, + MISOPIN: port::PinOps, + CSPIN: port::PinOps, +{ +} + +/// Default Write trait implementation. Only 8-bit word size is supported for now. +impl hal::blocking::spi::write::Default + for Spi +where + SPI: SpiOps, + SCLKPIN: port::PinOps, + MOSIPIN: port::PinOps, + MISOPIN: port::PinOps, + CSPIN: port::PinOps, +{ +} + +/// Implement traits for a SPI interface +#[macro_export] +macro_rules! impl_spi { + ( + hal: $HAL:ty, + peripheral: $SPI:ty, + sclk: $sclkpin:ty, + mosi: $mosipin:ty, + miso: $misopin:ty, + 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 setup(&self) { + fn raw_setup(&mut self, settings: &Settings) { use $crate::hal::spi; // set up control register - self.peripheral.spcr.write(|w| { + self.spcr.write(|w| { // enable SPI w.spe().set_bit(); // Set to primary mode w.mstr().set_bit(); // set up data order control bit - match self.settings.data_order { + match settings.data_order { DataOrder::MostSignificantFirst => w.dord().clear_bit(), DataOrder::LeastSignificantFirst => w.dord().set_bit(), }; // set up polarity control bit - match self.settings.mode.polarity { + match settings.mode.polarity { spi::Polarity::IdleHigh => w.cpol().set_bit(), spi::Polarity::IdleLow => w.cpol().clear_bit(), }; // set up phase control bit - match self.settings.mode.phase { + match settings.mode.phase { spi::Phase::CaptureOnFirstTransition => w.cpha().clear_bit(), spi::Phase::CaptureOnSecondTransition => w.cpha().set_bit(), }; // set up clock rate control bit - match self.settings.clock { + match settings.clock { SerialClockRate::OscfOver2 => w.spr().fosc_4_2(), SerialClockRate::OscfOver4 => w.spr().fosc_4_2(), SerialClockRate::OscfOver8 => w.spr().fosc_16_8(), @@ -288,7 +338,7 @@ macro_rules! impl_spi { } }); // set up 2x clock rate status bit - self.peripheral.spsr.write(|w| match self.settings.clock { + self.spsr.write(|w| match settings.clock { SerialClockRate::OscfOver2 => w.spi2x().set_bit(), SerialClockRate::OscfOver4 => w.spi2x().clear_bit(), SerialClockRate::OscfOver8 => w.spi2x().set_bit(), @@ -298,44 +348,27 @@ macro_rules! impl_spi { SerialClockRate::OscfOver128 => w.spi2x().clear_bit(), }); } - // to reconfigure the peripheral after initializing - pub fn reconfigure(&mut self, settings: Settings) -> $crate::nb::Result<(), $crate::void::Void> { - // wait for any in-flight writes to complete - self.flush()?; - self.settings = settings; - self.setup(); - Ok(()) - } - } - - /// 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 $crate::hal::spi::FullDuplex for $Spi { - type Error = $crate::void::Void; - /// Sets up the device for transmission and sends the data - fn send(&mut self, byte: u8) -> $crate::nb::Result<(), Self::Error> { - self.flush()?; - self.write(byte); - Ok(()) + /// Disable the peripheral + fn raw_release(&mut self) { + self.spcr.write(|w| w.spe().clear_bit()); } - /// Reads and returns the response in the data register - fn read(&mut self) -> $crate::nb::Result { - self.flush()?; - Ok(self.peripheral.spdr.read().bits()) + /// Check the interrupt flag to see if the write has completed + fn raw_check_iflag(&self) -> bool { + self.spsr.read().spif().bit_is_set() } - } - /// Default Trasmer trait implementation. Only 8-bit word size is supported for now. - impl $crate::hal::blocking::spi::transfer::Default for $Spi - { - } + /// Read a byte from the data register + fn raw_read(&self) -> u8 { + self.spdr.read().bits() + } - /// Default Write trait implementation. Only 8-bit word size is supported for now. - impl $crate::hal::blocking::spi::write::Default for $Spi - { + /// 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) }); + } } }; } diff --git a/examples/arduino-leonardo/src/bin/leonardo-spi-feedback.rs b/examples/arduino-leonardo/src/bin/leonardo-spi-feedback.rs new file mode 100644 index 0000000000..19b332bdd0 --- /dev/null +++ b/examples/arduino-leonardo/src/bin/leonardo-spi-feedback.rs @@ -0,0 +1,50 @@ +//! This example demonstrates how to set up a SPI interface and communicate +//! over it. The physical hardware configuation consists of connecting a +//! jumper directly from pin `~11` to pin `~12`. +//! +//! Once this program is written to the board, the serial output can be +//! accessed with +//! +//! ``` +//! sudo screen /dev/ttyACM0 57600 +//! ``` +//! +//! You should see it output the line `data: 15` repeatedly (aka 0b00001111). +//! If the output you see is `data: 255`, you may need to check your jumper. + +#![no_std] +#![no_main] + +use arduino_hal::prelude::*; +use arduino_hal::spi; +use embedded_hal::spi::FullDuplex; +use panic_halt as _; + +#[arduino_hal::entry] +fn main() -> ! { + let dp = arduino_hal::Peripherals::take().unwrap(); + let pins = arduino_hal::pins!(dp); + + // set up serial interface for text output + let mut serial = arduino_hal::default_serial!(dp, pins, 57600); + + // Create SPI interface. + let (mut spi, _) = arduino_hal::Spi::new( + dp.SPI, + pins.sck.into_output(), + pins.mosi.into_output(), + pins.miso.into_pull_up_input(), + pins.led_rx.into_output(), + spi::Settings::default(), + ); + + loop { + // Send a byte + nb::block!(spi.send(0b00001111)).void_unwrap(); + // Because MISO is connected to MOSI, the read data should be the same + let data = nb::block!(spi.read()).void_unwrap(); + + ufmt::uwriteln!(&mut serial, "data: {}\r", data).void_unwrap(); + arduino_hal::delay_ms(1000); + } +} diff --git a/examples/arduino-mega2560/src/bin/mega2560-spi-feedback.rs b/examples/arduino-mega2560/src/bin/mega2560-spi-feedback.rs new file mode 100644 index 0000000000..197adab9cd --- /dev/null +++ b/examples/arduino-mega2560/src/bin/mega2560-spi-feedback.rs @@ -0,0 +1,50 @@ +//! This example demonstrates how to set up a SPI interface and communicate +//! over it. The physical hardware configuation consists of connecting a +//! jumper directly from pin `~11` to pin `~12`. +//! +//! Once this program is written to the board, the serial output can be +//! accessed with +//! +//! ``` +//! sudo screen /dev/ttyACM0 57600 +//! ``` +//! +//! You should see it output the line `data: 15` repeatedly (aka 0b00001111). +//! If the output you see is `data: 255`, you may need to check your jumper. + +#![no_std] +#![no_main] + +use arduino_hal::prelude::*; +use arduino_hal::spi; +use embedded_hal::spi::FullDuplex; +use panic_halt as _; + +#[arduino_hal::entry] +fn main() -> ! { + let dp = arduino_hal::Peripherals::take().unwrap(); + let pins = arduino_hal::pins!(dp); + + // set up serial interface for text output + let mut serial = arduino_hal::default_serial!(dp, pins, 57600); + + // Create SPI interface. + let (mut spi, _) = arduino_hal::Spi::new( + dp.SPI, + pins.d52.into_output(), + pins.d51.into_output(), + pins.d50.into_pull_up_input(), + pins.d53.into_output(), + spi::Settings::default(), + ); + + loop { + // Send a byte + nb::block!(spi.send(0b00001111)).void_unwrap(); + // Because MISO is connected to MOSI, the read data should be the same + let data = nb::block!(spi.read()).void_unwrap(); + + ufmt::uwriteln!(&mut serial, "data: {}\r", data).void_unwrap(); + arduino_hal::delay_ms(1000); + } +} diff --git a/examples/arduino-uno/src/bin/uno-spi-feedback.rs b/examples/arduino-uno/src/bin/uno-spi-feedback.rs new file mode 100644 index 0000000000..3355684c46 --- /dev/null +++ b/examples/arduino-uno/src/bin/uno-spi-feedback.rs @@ -0,0 +1,50 @@ +//! This example demonstrates how to set up a SPI interface and communicate +//! over it. The physical hardware configuation consists of connecting a +//! jumper directly from pin `~11` to pin `~12`. +//! +//! Once this program is written to the board, the serial output can be +//! accessed with +//! +//! ``` +//! sudo screen /dev/ttyACM0 57600 +//! ``` +//! +//! You should see it output the line `data: 15` repeatedly (aka 0b00001111). +//! If the output you see is `data: 255`, you may need to check your jumper. + +#![no_std] +#![no_main] + +use arduino_hal::prelude::*; +use arduino_hal::spi; +use embedded_hal::spi::FullDuplex; +use panic_halt as _; + +#[arduino_hal::entry] +fn main() -> ! { + let dp = arduino_hal::Peripherals::take().unwrap(); + let pins = arduino_hal::pins!(dp); + + // set up serial interface for text output + let mut serial = arduino_hal::default_serial!(dp, pins, 57600); + + // Create SPI interface. + let (mut spi, _) = arduino_hal::Spi::new( + dp.SPI, + pins.d13.into_output(), + pins.d11.into_output(), + pins.d12.into_pull_up_input(), + pins.d10.into_output(), + spi::Settings::default(), + ); + + loop { + // Send a byte + nb::block!(spi.send(0b00001111)).void_unwrap(); + // Because MISO is connected to MOSI, the read data should be the same + let data = nb::block!(spi.read()).void_unwrap(); + + ufmt::uwriteln!(&mut serial, "data: {}\r", data).void_unwrap(); + arduino_hal::delay_ms(1000); + } +} diff --git a/mcu/atmega-hal/src/lib.rs b/mcu/atmega-hal/src/lib.rs index 28c1172410..c6e2e834fd 100644 --- a/mcu/atmega-hal/src/lib.rs +++ b/mcu/atmega-hal/src/lib.rs @@ -52,24 +52,29 @@ pub use avr_hal_generic::clock; pub use avr_hal_generic::delay; #[cfg(feature = "device-selected")] -pub mod port; +pub mod adc; #[cfg(feature = "device-selected")] -pub use port::Pins; +pub use adc::Adc; #[cfg(feature = "device-selected")] -pub mod usart; +pub mod i2c; #[cfg(feature = "device-selected")] -pub use usart::Usart; +pub use i2c::I2c; #[cfg(feature = "device-selected")] -pub mod i2c; +pub mod spi; #[cfg(feature = "device-selected")] -pub use i2c::I2c; +pub use spi::Spi; #[cfg(feature = "device-selected")] -pub mod adc; +pub mod port; #[cfg(feature = "device-selected")] -pub use adc::Adc; +pub use port::Pins; + +#[cfg(feature = "device-selected")] +pub mod usart; +#[cfg(feature = "device-selected")] +pub use usart::Usart; pub struct Atmega; diff --git a/mcu/atmega-hal/src/spi.rs b/mcu/atmega-hal/src/spi.rs new file mode 100644 index 0000000000..8906c92671 --- /dev/null +++ b/mcu/atmega-hal/src/spi.rs @@ -0,0 +1,78 @@ +#[allow(unused_imports)] +use crate::port; +pub use avr_hal_generic::spi::*; + +#[cfg(any(feature = "atmega2560", feature = "atmega32u4"))] +pub type Spi = avr_hal_generic::spi::Spi< + crate::Atmega, + crate::pac::SPI, + port::PB1, + port::PB2, + port::PB3, + port::PB0, +>; +#[cfg(any(feature = "atmega2560", feature = "atmega32u4"))] +avr_hal_generic::impl_spi! { + hal: crate::Atmega, + peripheral: crate::pac::SPI, + sclk: port::PB1, + mosi: port::PB2, + miso: port::PB3, + cs: port::PB0, +} + +#[cfg(any(feature = "atmega168", feature = "atmega328p", feature = "atmega48p",))] +pub type Spi = avr_hal_generic::spi::Spi< + crate::Atmega, + crate::pac::SPI, + port::PB5, + port::PB3, + port::PB4, + port::PB2, +>; +#[cfg(any(feature = "atmega168", feature = "atmega328p", feature = "atmega48p",))] +avr_hal_generic::impl_spi! { + hal: crate::Atmega, + peripheral: crate::pac::SPI, + sclk: port::PB5, + mosi: port::PB3, + miso: port::PB4, + cs: port::PB2, +} + +#[cfg(feature = "atmega328pb")] +pub type Spi0 = avr_hal_generic::spi::Spi< + crate::Atmega, + crate::pac::SPI0, + port::PB5, + port::PB3, + port::PB4, + port::PB2, +>; +#[cfg(feature = "atmega328pb")] +avr_hal_generic::impl_spi! { + hal: crate::Atmega, + peripheral: crate::pac::SPI0, + sclk: port::PB5, + mosi: port::PB3, + miso: port::PB4, + cs: port::PB2, +} +#[cfg(feature = "atmega328pb")] +pub type Spi1 = avr_hal_generic::spi::Spi< + crate::Atmega, + crate::pac::SPI1, + port::PC1, + port::PE3, + port::PC0, + port::PE2, +>; +#[cfg(feature = "atmega328pb")] +avr_hal_generic::impl_spi! { + hal: crate::Atmega, + peripheral: crate::pac::SPI1, + sclk: port::PC1, + mosi: port::PE3, + miso: port::PC0, + cs: port::PE2, +} diff --git a/mcu/attiny-hal/src/spi.rs b/mcu/attiny-hal/src/spi.rs new file mode 100644 index 0000000000..2b0176a2b6 --- /dev/null +++ b/mcu/attiny-hal/src/spi.rs @@ -0,0 +1,22 @@ +#[allow(unused_imports)] +use crate::port; +pub use avr_hal_generic::spi::*; + +#[cfg(feature = "attiny88")] +pub type Spi = avr_hal_generic::spi::Spi< + crate::Atmega, + crate::pac::SPI, + port::PB5, + port::PB3, + port::PB4, + port::PB2, +>; +#[cfg(feature = "attiny88")] +avr_hal_generic::impl_spi! { + hal: crate::Atmega, + peripheral: crate::pac::SPI, + sclk: port::PB5, + mosi: port::PB3, + miso: port::PB4, + cs: port::PB2, +}