From 4dd92ef2716652d6e891c5ecad81f2abe150ed53 Mon Sep 17 00:00:00 2001 From: Jonah Dahlquist Date: Mon, 16 Nov 2020 22:46:01 -0800 Subject: [PATCH 1/3] Added CS pin and wrapper struct to SPI macro, updated usage in ATmega328p --- avr-hal-generic/src/spi.rs | 40 ++++++++++++++++++++++++++------- chips/atmega328p-hal/src/lib.rs | 1 + 2 files changed, 33 insertions(+), 8 deletions(-) diff --git a/avr-hal-generic/src/spi.rs b/avr-hal-generic/src/spi.rs index 7999cbf7c9..11da66baa2 100644 --- a/avr-hal-generic/src/spi.rs +++ b/avr-hal-generic/src/spi.rs @@ -75,9 +75,29 @@ macro_rules! impl_spi { sclk: $sclkmod:ident::$SCLK:ident, mosi: $mosimod:ident::$MOSI:ident, miso: $misomod:ident::$MISO:ident, + cs: $csmod:ident::$CS:ident, } } ) => { + + /// Wrapper for the CS pin + /// + /// Used to contain the chip-select pin during operation to prevent its mode from being + /// changed from Output. Implements + /// [`OutputPin`](https://docs.rs/embedded-hal/latest/embedded_hal/digital/v2/trait.OutputPin.html) + /// so that it can still be controlled. + pub struct ChipSelectPin($csmod::$CS<$crate::port::mode::Output>); + + impl $crate::hal::digital::v2::OutputPin for ChipSelectPin { + type Error = <$csmod::$CS<$crate::port::mode::Output> as $crate::hal::digital::v2::OutputPin>::Error; + fn set_low(&mut self) -> Result<(), Self::Error> { + self.0.set_low() + } + fn set_high(&mut self) -> Result<(), Self::Error> { + self.0.set_high() + } + } + /// Behavior for a SPI interface. /// /// Stores the SPI peripheral for register access. In addition, it takes @@ -94,19 +114,21 @@ macro_rules! impl_spi { } impl $Spi<$crate::port::mode::PullUp> { - /// Instantiate an SPI with the registers, SCLK/MOSI/MISO pins, and settings, + /// 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. + /// 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 { + ) -> (Self, ChipSelectPin) { let spi = $Spi { peripheral, sclk, @@ -116,17 +138,18 @@ macro_rules! impl_spi { is_write_in_progress: false, }; spi.setup(); - spi + (spi, ChipSelectPin(cs)) } } impl $Spi<$crate::port::mode::Floating> { - /// Instantiate an SPI with the registers, SCLK/MOSI/MISO pins, and settings, + /// 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. + /// 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>, @@ -151,16 +174,17 @@ macro_rules! 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) -> ( + 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) + (self.peripheral, self.sclk, self.mosi, self.miso, cs.0) } /// Write a byte to the data register, which begins transmission diff --git a/chips/atmega328p-hal/src/lib.rs b/chips/atmega328p-hal/src/lib.rs index 3e5dd85940..1f4a412f68 100644 --- a/chips/atmega328p-hal/src/lib.rs +++ b/chips/atmega328p-hal/src/lib.rs @@ -169,6 +169,7 @@ pub mod spi { sclk: portb::PB5, mosi: portb::PB3, miso: portb::PB4, + cs: portb::PB2, } } } From 843f9ea8094ee66a0261d8ebd4922c50a7cc0404 Mon Sep 17 00:00:00 2001 From: Jonah Dahlquist Date: Tue, 17 Nov 2020 13:27:54 -0800 Subject: [PATCH 2/3] Implemented other traits for ChipSelectPin, re-worded docs for it --- avr-hal-generic/src/spi.rs | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/avr-hal-generic/src/spi.rs b/avr-hal-generic/src/spi.rs index 11da66baa2..70442074f0 100644 --- a/avr-hal-generic/src/spi.rs +++ b/avr-hal-generic/src/spi.rs @@ -83,13 +83,12 @@ macro_rules! impl_spi { /// Wrapper for the CS pin /// /// Used to contain the chip-select pin during operation to prevent its mode from being - /// changed from Output. Implements - /// [`OutputPin`](https://docs.rs/embedded-hal/latest/embedded_hal/digital/v2/trait.OutputPin.html) - /// so that it can still be controlled. + /// 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 = <$csmod::$CS<$crate::port::mode::Output> as $crate::hal::digital::v2::OutputPin>::Error; + type Error = $crate::void::Void; fn set_low(&mut self) -> Result<(), Self::Error> { self.0.set_low() } @@ -97,6 +96,20 @@ macro_rules! impl_spi { 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() + } + } /// Behavior for a SPI interface. /// From f6f8478a3458e6055d07916361ed7300e0d1741f Mon Sep 17 00:00:00 2001 From: Jonah Dahlquist Date: Tue, 17 Nov 2020 14:10:31 -0800 Subject: [PATCH 3/3] Updated all usages of the Spi macro to properly provide the CS pin --- .../arduino-leonardo/examples/leonardo-spi-feedback.rs | 5 ++--- boards/arduino-leonardo/src/lib.rs | 3 +-- .../arduino-mega2560/examples/mega2560-spi-feedback.rs | 5 ++--- boards/arduino-uno/examples/uno-spi-feedback.rs | 5 ++--- boards/arduino-uno/src/lib.rs | 5 ++--- .../examples/pro-micro-spi-feedback.rs | 5 ++--- chips/atmega168-hal/src/lib.rs | 5 +++-- chips/atmega2560-hal/src/spi.rs | 5 +++-- chips/atmega328p-hal/src/lib.rs | 10 ++++++---- chips/atmega32u4-hal/src/lib.rs | 5 +++-- chips/atmega48p-hal/src/spi.rs | 5 +++-- chips/attiny88-hal/src/spi.rs | 5 +++-- 12 files changed, 32 insertions(+), 31 deletions(-) diff --git a/boards/arduino-leonardo/examples/leonardo-spi-feedback.rs b/boards/arduino-leonardo/examples/leonardo-spi-feedback.rs index 158a611c04..6bd5c46ef2 100644 --- a/boards/arduino-leonardo/examples/leonardo-spi-feedback.rs +++ b/boards/arduino-leonardo/examples/leonardo-spi-feedback.rs @@ -28,14 +28,13 @@ fn main() -> ! { 57600.into_baudrate(), ); - pins.led_rx.into_output(&mut pins.ddr); // SS must be set to output mode. - // Create SPI interface. - let mut spi = spi::Spi::new( + let (mut spi, _) = spi::Spi::new( dp.SPI, pins.sck.into_output(&mut pins.ddr), pins.mosi.into_output(&mut pins.ddr), pins.miso.into_pull_up_input(&mut pins.ddr), + pins.led_rx.into_output(&mut pins.ddr), spi::Settings::default(), ); diff --git a/boards/arduino-leonardo/src/lib.rs b/boards/arduino-leonardo/src/lib.rs index 35c2f270fa..ffadc9a6f7 100644 --- a/boards/arduino-leonardo/src/lib.rs +++ b/boards/arduino-leonardo/src/lib.rs @@ -93,14 +93,13 @@ pub fn delay_us(us: u16) { /// /// let mut pins = arduino_leonardo::Pins::new(dp.PORTB, dp.PORTC, dp.PORTD, dp.PORTE); /// -/// pins.led_rx.into_output(&mut pins.ddr); // Chip Select must be set to output mode. -/// /// // Create SPI interface. /// let mut spi = arduino_leonardo::spi::Spi::new( /// dp.SPI, /// pins.sck.into_output(&mut pins.ddr), /// pins.mosi.into_output(&mut pins.ddr), /// pins.miso.into_pull_up_input(&mut pins.ddr), +/// pins.led_rx.into_output(&mut pins.ddr), /// arduino_leonardo::spi::Settings::default(), /// ); /// ``` diff --git a/boards/arduino-mega2560/examples/mega2560-spi-feedback.rs b/boards/arduino-mega2560/examples/mega2560-spi-feedback.rs index c5752e0ece..52cb9f697f 100644 --- a/boards/arduino-mega2560/examples/mega2560-spi-feedback.rs +++ b/boards/arduino-mega2560/examples/mega2560-spi-feedback.rs @@ -45,14 +45,13 @@ fn main() -> ! { 57600.into_baudrate(), ); - pins.d53.into_output(&mut pins.ddr); // SS must be set to output mode. - // Create SPI interface. - let mut spi = Spi::new( + let (mut spi, _) = Spi::new( dp.SPI, pins.d52.into_output(&mut pins.ddr), pins.d51.into_output(&mut pins.ddr), pins.d50.into_pull_up_input(&mut pins.ddr), + pins.d53.into_output(&mut pins.ddr), Settings::default(), ); diff --git a/boards/arduino-uno/examples/uno-spi-feedback.rs b/boards/arduino-uno/examples/uno-spi-feedback.rs index ba71258cdc..a8565c66c0 100644 --- a/boards/arduino-uno/examples/uno-spi-feedback.rs +++ b/boards/arduino-uno/examples/uno-spi-feedback.rs @@ -32,14 +32,13 @@ fn main() -> ! { 57600.into_baudrate(), ); - pins.d10.into_output(&mut pins.ddr); // SS must be set to output mode. - // Create SPI interface. - let mut spi = spi::Spi::new( + let (mut spi, _) = spi::Spi::new( dp.SPI, pins.d13.into_output(&mut pins.ddr), pins.d11.into_output(&mut pins.ddr), pins.d12.into_pull_up_input(&mut pins.ddr), + pins.d10.into_output(&mut pins.ddr), spi::Settings::default(), ); diff --git a/boards/arduino-uno/src/lib.rs b/boards/arduino-uno/src/lib.rs index f1d5b2ab2a..7b1f942d4d 100644 --- a/boards/arduino-uno/src/lib.rs +++ b/boards/arduino-uno/src/lib.rs @@ -106,14 +106,13 @@ pub fn delay_us(us: u16) { /// /// let mut pins = arduino_uno::Pins::new(dp.PORTB, dp.PORTC, dp.PORTD); /// -/// pins.d10.into_output(&mut pins.ddr); // Chip Select must be set to output mode. -/// /// // Create SPI interface. -/// let mut spi = arduino_uno::spi::Spi::new( +/// let (mut spi, mut cs) = arduino_uno::spi::Spi::new( /// dp.SPI, /// pins.d13.into_output(&mut pins.ddr), /// pins.d11.into_output(&mut pins.ddr), /// pins.d12.into_pull_up_input(&mut pins.ddr), +/// pins.d10.into_output(&mut pins.ddr), /// arduino_uno::spi::Settings::default(), /// ); /// ``` diff --git a/boards/sparkfun-pro-micro/examples/pro-micro-spi-feedback.rs b/boards/sparkfun-pro-micro/examples/pro-micro-spi-feedback.rs index 0de0883f17..83a0167f76 100644 --- a/boards/sparkfun-pro-micro/examples/pro-micro-spi-feedback.rs +++ b/boards/sparkfun-pro-micro/examples/pro-micro-spi-feedback.rs @@ -28,14 +28,13 @@ fn main() -> ! { 57600.into_baudrate(), ); - pins.led_rx.into_output(&mut pins.ddr); // SS must be set to output mode. - // Create SPI interface. - let mut spi = spi::Spi::new( + let (mut spi, _) = spi::Spi::new( dp.SPI, pins.sck.into_output(&mut pins.ddr), pins.mosi.into_output(&mut pins.ddr), pins.miso.into_pull_up_input(&mut pins.ddr), + pins.led_rx.into_output(&mut pins.ddr), spi::Settings::default(), ); diff --git a/chips/atmega168-hal/src/lib.rs b/chips/atmega168-hal/src/lib.rs index d2a999f895..9e8cb5f801 100644 --- a/chips/atmega168-hal/src/lib.rs +++ b/chips/atmega168-hal/src/lib.rs @@ -62,13 +62,13 @@ pub mod spi { //! or passed into a driver. Example usage: //! //! ``` - //! pins.d10.into_output(&mut pins.ddr);// SS must be set to output mode //! // create SPI interface - //! let mut spi = Spi::new( + //! let (mut spi, mut cs) = Spi::new( //! dp.SPI,// SPI peripheral //! pins.d13.into_output(&mut pins.ddr),// SCLK //! pins.d11.into_output(&mut pins.ddr),// MOSI output pin //! pins.d12.into_pull_up_input(&mut pins.ddr),// MISO input pin + //! pins.d10.into_output(&mut pins.ddr),// CS pin //! Settings::default(), //! ); //! @@ -90,6 +90,7 @@ pub mod spi { sclk: portb::PB5, mosi: portb::PB3, miso: portb::PB4, + cs: portb::PB2, } } } diff --git a/chips/atmega2560-hal/src/spi.rs b/chips/atmega2560-hal/src/spi.rs index 62cd39398a..63d0d7bbf9 100644 --- a/chips/atmega2560-hal/src/spi.rs +++ b/chips/atmega2560-hal/src/spi.rs @@ -4,13 +4,13 @@ //! or passed into a driver. Example usage: //! //! ``` -//! pins.d53.into_output(&mut pins.ddr);// SS must be set to output mode //! // create SPI interface -//! let mut spi = Spi::new( +//! let (mut spi, mut cs) = Spi::new( //! dp.SPI,// SPI peripheral //! pins.d52.into_output(&mut pins.ddr),// SCLK //! pins.d51.into_output(&mut pins.ddr),// MOSI output pin //! pins.d50.into_pull_up_input(&mut pins.ddr),// MISO input pin +//! pins.d53.into_output(&mut pins.ddr),// CS pin //! Settings::default(), //! ); //! @@ -35,6 +35,7 @@ avr_hal_generic::impl_spi! { sclk: portb::PB1, mosi: portb::PB2, miso: portb::PB3, + cs: portb::PB0, } } } diff --git a/chips/atmega328p-hal/src/lib.rs b/chips/atmega328p-hal/src/lib.rs index 1f4a412f68..b3eaf14aa9 100644 --- a/chips/atmega328p-hal/src/lib.rs +++ b/chips/atmega328p-hal/src/lib.rs @@ -141,13 +141,13 @@ pub mod spi { //! or passed into a driver. Example usage: //! //! ``` - //! pins.d10.into_output(&mut pins.ddr);// SS must be set to output mode //! // create SPI interface - //! let mut spi = Spi::new( + //! let (mut spi, mut cs) = Spi::new( //! dp.SPI,// SPI peripheral //! pins.d13.into_output(&mut pins.ddr),// SCLK //! pins.d11.into_output(&mut pins.ddr),// MOSI output pin //! pins.d12.into_pull_up_input(&mut pins.ddr),// MISO input pin + //! pins.d10.into_output(&mut pins.ddr),// CS pin //! Settings::default(), //! ); //! @@ -183,13 +183,13 @@ pub mod spi { //! or passed into a driver. Example usage: //! //! ``` - //! pins.d10.into_output(&mut pins.ddr);// SS must be set to output mode //! // create SPI interface - //! let mut spi = Spi0::new( + //! let (mut spi, mut cs) = Spi0::new( //! dp.SPI,// SPI peripheral //! pins.d13.into_output(&mut pins.ddr),// SCLK //! pins.d11.into_output(&mut pins.ddr),// MOSI output pin //! pins.d12.into_pull_up_input(&mut pins.ddr),// MISO input pin + //! pins.d10.into_output(&mut pins.ddr),// CS pin //! Settings::default(), //! ); //! @@ -211,6 +211,7 @@ pub mod spi { sclk: portb::PB5, mosi: portb::PB3, miso: portb::PB4, + cs: portb::PB2, } } } @@ -222,6 +223,7 @@ pub mod spi { sclk: portc::PC1, mosi: porte::PE3, miso: portc::PC0, + cs: portc::PE2, } } } diff --git a/chips/atmega32u4-hal/src/lib.rs b/chips/atmega32u4-hal/src/lib.rs index 173943e5a7..5da8134eaf 100644 --- a/chips/atmega32u4-hal/src/lib.rs +++ b/chips/atmega32u4-hal/src/lib.rs @@ -59,12 +59,12 @@ pub mod spi { //! or passed into a driver. Example usage: //! //! ``` - //! pins.d10.into_output(&mut pins.ddr);// SS must be set to output mode //! // create SPI interface - //! let mut spi = Spi::new( + //! let (mut spi, mut cs) = Spi::new( //! dp.SPI,// SPI peripheral //! pins.d11.into_output(&mut pins.ddr),// MOSI output pin //! pins.d12.into_pull_up_input(&mut pins.ddr),// MISO input pin + //! pins.d10.into_output(&mut pins.ddr),// CS pin //! Settings::default(), //! ); //! @@ -86,6 +86,7 @@ pub mod spi { sclk: portb::PB1, mosi: portb::PB2, miso: portb::PB3, + cs: portb::PB0, } } } diff --git a/chips/atmega48p-hal/src/spi.rs b/chips/atmega48p-hal/src/spi.rs index 618ab8078c..7c30521672 100644 --- a/chips/atmega48p-hal/src/spi.rs +++ b/chips/atmega48p-hal/src/spi.rs @@ -4,13 +4,13 @@ //! or passed into a driver. Example usage: //! //! ``` -//! pins.d10.into_output(&mut pins.ddr);// SS must be set to output mode //! // create SPI interface -//! let mut spi = Spi::new( +//! let (mut spi, mut cs) = Spi::new( //! dp.SPI,// SPI peripheral //! pins.d13.into_output(&mut pins.ddr),// SCLK //! pins.d11.into_output(&mut pins.ddr),// MOSI output pin //! pins.d12.into_pull_up_input(&mut pins.ddr),// MISO input pin +//! pins.d10.into_output(&mut pins.ddr),// CS pin //! Settings::default(), //! ); //! @@ -32,6 +32,7 @@ avr_hal_generic::impl_spi! { sclk: portb::PB5, mosi: portb::PB3, miso: portb::PB4, + cs: portb::PB2, } } } diff --git a/chips/attiny88-hal/src/spi.rs b/chips/attiny88-hal/src/spi.rs index df204f5806..9c79b8d7e0 100644 --- a/chips/attiny88-hal/src/spi.rs +++ b/chips/attiny88-hal/src/spi.rs @@ -4,13 +4,13 @@ //! or passed into a driver. Example usage: //! //! ``` -//! portb::PB2.into_output(&mut pins.ddr);// SS must be set to output mode //! // create SPI interface -//! let mut spi = Spi::new( +//! let (mut spi, mut cs) = Spi::new( //! dp.SPI,// SPI peripheral //! portb::PB5.into_output(&mut pins.ddr),// SCLK //! portb::PB3.into_output(&mut pins.ddr),// MOSI output pin //! portb::PB4.into_pull_up_input(&mut pins.ddr),// MISO input pin +//! portb::PB2.into_output(&mut pins.ddr),// CS pin //! Settings::default(), //! ); //! @@ -32,6 +32,7 @@ avr_hal_generic::impl_spi! { sclk: portb::PB5, mosi: portb::PB3, miso: portb::PB4, + cs: portb::PB2, } } }