spi.rs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500
  1. /*!
  2. # Serial Peripheral Interface
  3. To construct the SPI instances, use the `Spi::spiX` functions.
  4. The pin parameter is a tuple containing `(sck, miso, mosi)` which should be configured as `(Alternate<PushPull>, Input<Floating>, Alternate<PushPull>)`.
  5. You can also use `NoSck`, `NoMiso` or `NoMosi` if you don't want to use the pins
  6. - `SPI1` can use `(PA5, PA6, PA7)` or `(PB3, PB4, PB5)`.
  7. - `SPI2` can use `(PB13, PB14, PB15)`
  8. - `SPI3` can use `(PB3, PB4, PB5)` or `(PC10, PC11, PC12)`
  9. ## Initialisation example
  10. ```rust
  11. // Acquire the GPIOB peripheral
  12. let mut gpiob = dp.GPIOB.split(&mut rcc.apb2);
  13. let pins = (
  14. gpiob.pb13.into_alternate_push_pull(&mut gpiob.crh),
  15. gpiob.pb14.into_floating_input(&mut gpiob.crh),
  16. gpiob.pb15.into_alternate_push_pull(&mut gpiob.crh),
  17. );
  18. let spi_mode = Mode {
  19. polarity: Polarity::IdleLow,
  20. phase: Phase::CaptureOnFirstTransition,
  21. };
  22. let spi = Spi::spi2(dp.SPI2, pins, spi_mode, 100.khz(), clocks, &mut rcc.apb1);
  23. ```
  24. */
  25. use core::ops::Deref;
  26. use core::ptr;
  27. pub use crate::hal::spi::{FullDuplex, Mode, Phase, Polarity};
  28. #[cfg(any(feature = "high", feature = "connectivity"))]
  29. use crate::pac::SPI3;
  30. use crate::pac::{SPI1, SPI2};
  31. use crate::afio::MAPR;
  32. use crate::dma::dma1::{C3, C5};
  33. use crate::dma::{Static, Transfer, TransferPayload, Transmit, TxDma, R};
  34. use crate::gpio::gpioa::{PA5, PA6, PA7};
  35. use crate::gpio::gpiob::{PB13, PB14, PB15, PB3, PB4, PB5};
  36. #[cfg(feature = "connectivity")]
  37. use crate::gpio::gpioc::{PC10, PC11, PC12};
  38. use crate::gpio::{Alternate, Floating, Input, PushPull};
  39. use crate::rcc::{Clocks, Enable, GetBusFreq, Reset, APB1, APB2};
  40. use crate::time::Hertz;
  41. use core::sync::atomic::{self, Ordering};
  42. use as_slice::AsSlice;
  43. /// SPI error
  44. #[derive(Debug)]
  45. pub enum Error {
  46. /// Overrun occurred
  47. Overrun,
  48. /// Mode fault occurred
  49. ModeFault,
  50. /// CRC error
  51. Crc,
  52. #[doc(hidden)]
  53. _Extensible,
  54. }
  55. use core::marker::PhantomData;
  56. mod sealed {
  57. pub trait Remap {
  58. type Periph;
  59. const REMAP: bool;
  60. }
  61. pub trait Sck<REMAP> {}
  62. pub trait Miso<REMAP> {}
  63. pub trait Mosi<REMAP> {}
  64. pub struct _Sck;
  65. pub struct _Miso;
  66. pub struct _Mosi;
  67. }
  68. use sealed::{Miso, Mosi, Remap, Sck};
  69. pub trait Pins<REMAP, P> {
  70. type _Pos;
  71. }
  72. macro_rules! pins_impl {
  73. ( $( ( $($PINX:ident),+ ), ( $($TRAIT:ident),+ ), ( $($POS:ident),* ); )+ ) => {
  74. $(
  75. #[allow(unused_parens)]
  76. impl<REMAP, $($PINX,)+> Pins<REMAP, ($(sealed::$POS),+)> for ($($PINX),+)
  77. where
  78. $($PINX: $TRAIT<REMAP>,)+
  79. {
  80. type _Pos = ($(sealed::$POS),+);
  81. }
  82. )+
  83. };
  84. }
  85. pins_impl!(
  86. (SCK, MISO, MOSI), (Sck, Miso, Mosi), (_Sck, _Miso, _Mosi);
  87. (SCK, MOSI, MISO), (Sck, Mosi, Miso), (_Sck, _Mosi, _Miso);
  88. (MOSI, SCK, MISO), (Mosi, Sck, Miso), (_Mosi, _Sck, _Miso);
  89. (MOSI, MISO, SCK), (Mosi, Miso, Sck), (_Mosi, _Miso, _Sck);
  90. (MISO, MOSI, SCK), (Miso, Mosi, Sck), (_Miso, _Mosi, _Sck);
  91. (MISO, SCK, MOSI), (Miso, Sck, Mosi), (_Miso, _Sck, _Mosi);
  92. );
  93. pub struct Spi<SPI, REMAP, PINS> {
  94. spi: SPI,
  95. pins: PINS,
  96. _remap: PhantomData<REMAP>,
  97. }
  98. /// A filler type for when the SCK pin is unnecessary
  99. pub struct NoSck;
  100. /// A filler type for when the Miso pin is unnecessary
  101. pub struct NoMiso;
  102. /// A filler type for when the Mosi pin is unnecessary
  103. pub struct NoMosi;
  104. impl<REMAP> Sck<REMAP> for NoSck {}
  105. impl<REMAP> Miso<REMAP> for NoMiso {}
  106. impl<REMAP> Mosi<REMAP> for NoMosi {}
  107. macro_rules! remap {
  108. ($name:ident, $SPIX:ident, $state:literal, $SCK:ident, $MISO:ident, $MOSI:ident) => {
  109. pub struct $name;
  110. impl Remap for $name {
  111. type Periph = $SPIX;
  112. const REMAP: bool = $state;
  113. }
  114. impl Sck<$name> for $SCK<Alternate<PushPull>> {}
  115. impl Miso<$name> for $MISO<Input<Floating>> {}
  116. impl Mosi<$name> for $MOSI<Alternate<PushPull>> {}
  117. };
  118. }
  119. remap!(Spi1NoRemap, SPI1, false, PA5, PA6, PA7);
  120. remap!(Spi1Remap, SPI1, true, PB3, PB4, PB5);
  121. remap!(Spi2NoRemap, SPI2, false, PB13, PB14, PB15);
  122. #[cfg(feature = "high")]
  123. remap!(Spi3NoRemap, SPI3, false, PB3, PB4, PB5);
  124. #[cfg(feature = "connectivity")]
  125. remap!(Spi3Remap, SPI3, true, PC10, PC11, PC12);
  126. impl<REMAP, PINS> Spi<SPI1, REMAP, PINS> {
  127. /**
  128. Constructs an SPI instance using SPI1.
  129. The pin parameter tuple (sck, miso, mosi) should be `(PA5, PA6, PA7)` or `(PB3, PB4, PB5)` configured as `(Alternate<PushPull>, Input<Floating>, Alternate<PushPull>)`.
  130. You can also use `NoSck`, `NoMiso` or `NoMosi` if you don't want to use the pins
  131. */
  132. pub fn spi1<F, POS>(
  133. spi: SPI1,
  134. pins: PINS,
  135. mapr: &mut MAPR,
  136. mode: Mode,
  137. freq: F,
  138. clocks: Clocks,
  139. apb: &mut APB2,
  140. ) -> Self
  141. where
  142. F: Into<Hertz>,
  143. REMAP: Remap<Periph = SPI1>,
  144. PINS: Pins<REMAP, POS>,
  145. {
  146. mapr.modify_mapr(|_, w| w.spi1_remap().bit(REMAP::REMAP));
  147. Spi::<SPI1, _, _>::_spi(spi, pins, mode, freq.into(), clocks, apb)
  148. }
  149. }
  150. impl<REMAP, PINS> Spi<SPI2, REMAP, PINS> {
  151. /**
  152. Constructs an SPI instance using SPI1.
  153. The pin parameter tuple (sck, miso, mosi) should be `(PB13, PB14, PB15)` configured as `(Alternate<PushPull>, Input<Floating>, Alternate<PushPull>)`.
  154. You can also use `NoSck`, `NoMiso` or `NoMosi` if you don't want to use the pins
  155. */
  156. pub fn spi2<F, POS>(
  157. spi: SPI2,
  158. pins: PINS,
  159. mode: Mode,
  160. freq: F,
  161. clocks: Clocks,
  162. apb: &mut APB1,
  163. ) -> Self
  164. where
  165. F: Into<Hertz>,
  166. REMAP: Remap<Periph = SPI2>,
  167. PINS: Pins<REMAP, POS>,
  168. {
  169. Spi::<SPI2, _, _>::_spi(spi, pins, mode, freq.into(), clocks, apb)
  170. }
  171. }
  172. #[cfg(any(feature = "high", feature = "connectivity"))]
  173. impl<REMAP, PINS> Spi<SPI3, REMAP, PINS> {
  174. /**
  175. Constructs an SPI instance using SPI1.
  176. The pin parameter tuple (sck, miso, mosi) should be `(PB3, PB4, PB5)` or `(PC10, PC11, PC12)` configured as `(Alternate<PushPull>, Input<Floating>, Alternate<PushPull>)`.
  177. You can also use `NoSck`, `NoMiso` or `NoMosi` if you don't want to use the pins
  178. */
  179. pub fn spi3<F, POS>(
  180. spi: SPI3,
  181. pins: PINS,
  182. mode: Mode,
  183. freq: F,
  184. clocks: Clocks,
  185. apb: &mut APB1,
  186. ) -> Self
  187. where
  188. F: Into<Hertz>,
  189. REMAP: Remap<Periph = SPI3>,
  190. PINS: Pins<REMAP, POS>,
  191. {
  192. Spi::<SPI3, _, _>::_spi(spi, pins, mode, freq.into(), clocks, apb)
  193. }
  194. }
  195. pub type SpiRegisterBlock = crate::pac::spi1::RegisterBlock;
  196. impl<SPI, REMAP, PINS> Spi<SPI, REMAP, PINS>
  197. where
  198. SPI: Deref<Target = SpiRegisterBlock> + Enable + Reset,
  199. SPI::Bus: GetBusFreq,
  200. {
  201. fn _spi(
  202. spi: SPI,
  203. pins: PINS,
  204. mode: Mode,
  205. freq: Hertz,
  206. clocks: Clocks,
  207. apb: &mut SPI::Bus,
  208. ) -> Self {
  209. // enable or reset SPI
  210. SPI::enable(apb);
  211. SPI::reset(apb);
  212. // disable SS output
  213. spi.cr2.write(|w| w.ssoe().clear_bit());
  214. let br = match SPI::Bus::get_frequency(&clocks).0 / freq.0 {
  215. 0 => unreachable!(),
  216. 1..=2 => 0b000,
  217. 3..=5 => 0b001,
  218. 6..=11 => 0b010,
  219. 12..=23 => 0b011,
  220. 24..=47 => 0b100,
  221. 48..=95 => 0b101,
  222. 96..=191 => 0b110,
  223. _ => 0b111,
  224. };
  225. spi.cr1.write(|w| {
  226. w
  227. // clock phase from config
  228. .cpha()
  229. .bit(mode.phase == Phase::CaptureOnSecondTransition)
  230. // clock polarity from config
  231. .cpol()
  232. .bit(mode.polarity == Polarity::IdleHigh)
  233. // mstr: master configuration
  234. .mstr()
  235. .set_bit()
  236. // baudrate value
  237. .br()
  238. .bits(br)
  239. // lsbfirst: MSB first
  240. .lsbfirst()
  241. .clear_bit()
  242. // ssm: enable software slave management (NSS pin free for other uses)
  243. .ssm()
  244. .set_bit()
  245. // ssi: set nss high = master mode
  246. .ssi()
  247. .set_bit()
  248. // dff: 8 bit frames
  249. .dff()
  250. .clear_bit()
  251. // bidimode: 2-line unidirectional
  252. .bidimode()
  253. .clear_bit()
  254. // both TX and RX are used
  255. .rxonly()
  256. .clear_bit()
  257. // spe: enable the SPI bus
  258. .spe()
  259. .set_bit()
  260. });
  261. Spi {
  262. spi,
  263. pins,
  264. _remap: PhantomData,
  265. }
  266. }
  267. #[deprecated(since = "0.6.0", note = "Please use release instead")]
  268. pub fn free(self) -> (SPI, PINS) {
  269. self.release()
  270. }
  271. pub fn release(self) -> (SPI, PINS) {
  272. (self.spi, self.pins)
  273. }
  274. }
  275. impl<SPI, REMAP, PINS> crate::hal::spi::FullDuplex<u8> for Spi<SPI, REMAP, PINS>
  276. where
  277. SPI: Deref<Target = SpiRegisterBlock>,
  278. {
  279. type Error = Error;
  280. fn read(&mut self) -> nb::Result<u8, Error> {
  281. let sr = self.spi.sr.read();
  282. Err(if sr.ovr().bit_is_set() {
  283. nb::Error::Other(Error::Overrun)
  284. } else if sr.modf().bit_is_set() {
  285. nb::Error::Other(Error::ModeFault)
  286. } else if sr.crcerr().bit_is_set() {
  287. nb::Error::Other(Error::Crc)
  288. } else if sr.rxne().bit_is_set() {
  289. // NOTE(read_volatile) read only 1 byte (the svd2rust API only allows
  290. // reading a half-word)
  291. return Ok(unsafe { ptr::read_volatile(&self.spi.dr as *const _ as *const u8) });
  292. } else {
  293. nb::Error::WouldBlock
  294. })
  295. }
  296. fn send(&mut self, byte: u8) -> nb::Result<(), Error> {
  297. let sr = self.spi.sr.read();
  298. Err(if sr.ovr().bit_is_set() {
  299. nb::Error::Other(Error::Overrun)
  300. } else if sr.modf().bit_is_set() {
  301. nb::Error::Other(Error::ModeFault)
  302. } else if sr.crcerr().bit_is_set() {
  303. nb::Error::Other(Error::Crc)
  304. } else if sr.txe().bit_is_set() {
  305. // NOTE(write_volatile) see note above
  306. unsafe { ptr::write_volatile(&self.spi.dr as *const _ as *mut u8, byte) }
  307. return Ok(());
  308. } else {
  309. nb::Error::WouldBlock
  310. })
  311. }
  312. }
  313. impl<SPI, REMAP, PINS> crate::hal::blocking::spi::transfer::Default<u8> for Spi<SPI, REMAP, PINS> where
  314. SPI: Deref<Target = SpiRegisterBlock>
  315. {
  316. }
  317. impl<SPI, REMAP, PINS> crate::hal::blocking::spi::Write<u8> for Spi<SPI, REMAP, PINS>
  318. where
  319. SPI: Deref<Target = SpiRegisterBlock>,
  320. {
  321. type Error = Error;
  322. // Implement write as per the "Transmit only procedure" page 712
  323. // of RM0008 Rev 20. This is more than twice as fast as the
  324. // default Write<> implementation (which reads and drops each
  325. // received value)
  326. fn write(&mut self, words: &[u8]) -> Result<(), Error> {
  327. // Write each word when the tx buffer is empty
  328. for word in words {
  329. loop {
  330. let sr = self.spi.sr.read();
  331. if sr.txe().bit_is_set() {
  332. // NOTE(write_volatile) see note above
  333. unsafe { ptr::write_volatile(&self.spi.dr as *const _ as *mut u8, *word) }
  334. if sr.modf().bit_is_set() {
  335. return Err(Error::ModeFault);
  336. }
  337. break;
  338. }
  339. }
  340. }
  341. // Wait for final TXE
  342. loop {
  343. let sr = self.spi.sr.read();
  344. if sr.txe().bit_is_set() {
  345. break;
  346. }
  347. }
  348. // Wait for final !BSY
  349. loop {
  350. let sr = self.spi.sr.read();
  351. if !sr.bsy().bit_is_set() {
  352. break;
  353. }
  354. }
  355. // Clear OVR set due to dropped received values
  356. // NOTE(read_volatile) see note aboev
  357. unsafe {
  358. let _ = ptr::read_volatile(&self.spi.dr as *const _ as *const u8);
  359. }
  360. let _ = self.spi.sr.read();
  361. Ok(())
  362. }
  363. }
  364. // DMA
  365. pub struct SpiPayload<SPI, REMAP, PINS> {
  366. spi: Spi<SPI, REMAP, PINS>,
  367. }
  368. pub type SpiTxDma<SPI, REMAP, PINS, CHANNEL> = TxDma<SpiPayload<SPI, REMAP, PINS>, CHANNEL>;
  369. macro_rules! spi_dma {
  370. ($SPIi:ident, $TCi:ident) => {
  371. impl<REMAP, PINS> Transmit for SpiTxDma<$SPIi, REMAP, PINS, $TCi> {
  372. type TxChannel = $TCi;
  373. type ReceivedWord = u8;
  374. }
  375. impl<REMAP, PINS> Spi<$SPIi, REMAP, PINS> {
  376. pub fn with_tx_dma(self, channel: $TCi) -> SpiTxDma<$SPIi, REMAP, PINS, $TCi> {
  377. let payload = SpiPayload { spi: self };
  378. SpiTxDma { payload, channel }
  379. }
  380. }
  381. impl<REMAP, PINS> TransferPayload for SpiTxDma<$SPIi, REMAP, PINS, $TCi> {
  382. fn start(&mut self) {
  383. self.payload
  384. .spi
  385. .spi
  386. .cr2
  387. .modify(|_, w| w.txdmaen().set_bit());
  388. self.channel.start();
  389. }
  390. fn stop(&mut self) {
  391. self.payload
  392. .spi
  393. .spi
  394. .cr2
  395. .modify(|_, w| w.txdmaen().clear_bit());
  396. self.channel.stop();
  397. }
  398. }
  399. impl<A, B, REMAP, PIN> crate::dma::WriteDma<A, B, u8> for SpiTxDma<$SPIi, REMAP, PIN, $TCi>
  400. where
  401. A: AsSlice<Element = u8>,
  402. B: Static<A>,
  403. {
  404. fn write(mut self, buffer: B) -> Transfer<R, B, Self> {
  405. {
  406. let buffer = buffer.borrow().as_slice();
  407. self.channel.set_peripheral_address(
  408. unsafe { &(*$SPIi::ptr()).dr as *const _ as u32 },
  409. false,
  410. );
  411. self.channel
  412. .set_memory_address(buffer.as_ptr() as u32, true);
  413. self.channel.set_transfer_length(buffer.len());
  414. }
  415. atomic::compiler_fence(Ordering::Release);
  416. self.channel.ch().cr.modify(|_, w| {
  417. w
  418. // memory to memory mode disabled
  419. .mem2mem()
  420. .clear_bit()
  421. // medium channel priority level
  422. .pl()
  423. .medium()
  424. // 8-bit memory size
  425. .msize()
  426. .bits8()
  427. // 8-bit peripheral size
  428. .psize()
  429. .bits8()
  430. // circular mode disabled
  431. .circ()
  432. .clear_bit()
  433. // read from memory
  434. .dir()
  435. .set_bit()
  436. });
  437. self.start();
  438. Transfer::r(buffer, self)
  439. }
  440. }
  441. };
  442. }
  443. spi_dma!(SPI1, C3);
  444. spi_dma!(SPI2, C5);