use core::ptr; use hal; pub use hal::spi::{Mode, Phase, Polarity}; use nb; use stm32::{SPI1, SPI2}; use afio::MAPR; use gpio::gpioa::{PA5, PA6, PA7}; use gpio::gpiob::{PB13, PB14, PB15, PB3, PB4, PB5}; use gpio::{Alternate, Floating, Input, PushPull}; use rcc::{APB1, APB2, Clocks}; use time::Hertz; /// SPI error #[derive(Debug)] pub enum Error { /// Overrun occurred Overrun, /// Mode fault occurred ModeFault, /// CRC error Crc, #[doc(hidden)] _Extensible, } pub trait Pins { const REMAP: bool; } impl Pins for ( PA5>, PA6>, PA7>, ) { const REMAP: bool = false; } impl Pins for ( PB3>, PB4>, PB5>, ) { const REMAP: bool = true; } impl Pins for ( PB13>, PB14>, PB15>, ) { const REMAP: bool = false; } pub struct Spi { spi: SPI, pins: PINS, } impl Spi { pub fn spi1( spi: SPI1, pins: PINS, mapr: &mut MAPR, mode: Mode, freq: F, clocks: Clocks, apb: &mut APB2, ) -> Self where F: Into, PINS: Pins, { mapr.mapr().modify(|_, w| w.spi1_remap().bit(PINS::REMAP)); Spi::_spi1(spi, pins, mode, freq.into(), clocks, apb) } } impl Spi { pub fn spi2( spi: SPI2, pins: PINS, mode: Mode, freq: F, clocks: Clocks, apb: &mut APB1, ) -> Self where F: Into, PINS: Pins, { Spi::_spi2(spi, pins, mode, freq.into(), clocks, apb) } } macro_rules! hal { ($($SPIX:ident: ($spiX:ident, $spiXen:ident, $spiXrst:ident, $APB:ident),)+) => { $( impl Spi<$SPIX, PINS> { fn $spiX( spi: $SPIX, pins: PINS, mode: Mode, freq: Hertz, clocks: Clocks, apb: &mut $APB, ) -> Self { // enable or reset $SPIX apb.enr().modify(|_, w| w.$spiXen().set_bit()); apb.rstr().modify(|_, w| w.$spiXrst().set_bit()); apb.rstr().modify(|_, w| w.$spiXrst().clear_bit()); // disable SS output spi.cr2.write(|w| w.ssoe().clear_bit()); let br = match clocks.pclk2().0 / freq.0 { 0 => unreachable!(), 1...2 => 0b000, 3...5 => 0b001, 6...11 => 0b010, 12...23 => 0b011, 24...47 => 0b100, 48...95 => 0b101, 96...191 => 0b110, _ => 0b111, }; // mstr: master configuration // lsbfirst: MSB first // ssm: enable software slave management (NSS pin free for other uses) // ssi: set nss high = master mode // dff: 8 bit frames // bidimode: 2-line unidirectional // spe: enable the SPI bus spi.cr1.write(|w| { w.cpha() .bit(mode.phase == Phase::CaptureOnSecondTransition) .cpol() .bit(mode.polarity == Polarity::IdleHigh) .mstr() .set_bit() .br() .bits(br) .lsbfirst() .clear_bit() .ssm() .set_bit() .ssi() .set_bit() .rxonly() .clear_bit() .dff() .clear_bit() .bidimode() .clear_bit() .spe() .set_bit() }); Spi { spi, pins } } pub fn free(self) -> ($SPIX, PINS) { (self.spi, self.pins) } } impl hal::spi::FullDuplex for Spi<$SPIX, PINS> { type Error = Error; fn read(&mut self) -> nb::Result { let sr = self.spi.sr.read(); Err(if sr.ovr().bit_is_set() { nb::Error::Other(Error::Overrun) } else if sr.modf().bit_is_set() { nb::Error::Other(Error::ModeFault) } else if sr.crcerr().bit_is_set() { nb::Error::Other(Error::Crc) } else if sr.rxne().bit_is_set() { // NOTE(read_volatile) read only 1 byte (the svd2rust API only allows // reading a half-word) return Ok(unsafe { ptr::read_volatile(&self.spi.dr as *const _ as *const u8) }); } else { nb::Error::WouldBlock }) } fn send(&mut self, byte: u8) -> nb::Result<(), Error> { let sr = self.spi.sr.read(); Err(if sr.ovr().bit_is_set() { nb::Error::Other(Error::Overrun) } else if sr.modf().bit_is_set() { nb::Error::Other(Error::ModeFault) } else if sr.crcerr().bit_is_set() { nb::Error::Other(Error::Crc) } else if sr.txe().bit_is_set() { // NOTE(write_volatile) see note above unsafe { ptr::write_volatile(&self.spi.dr as *const _ as *mut u8, byte) } return Ok(()); } else { nb::Error::WouldBlock }) } } impl ::hal::blocking::spi::transfer::Default for Spi<$SPIX, PINS> {} impl ::hal::blocking::spi::write::Default for Spi<$SPIX, PINS> {} )+ } } hal! { SPI1: (_spi1, spi1en, spi1rst, APB2), SPI2: (_spi2, spi2en, spi2rst, APB1), }