spi.rs 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607
  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. #[cfg(feature = "connectivity")]
  34. use crate::dma::dma2::C2;
  35. use crate::dma::{Transfer, TransferPayload, Transmit, TxDma, R};
  36. use crate::gpio::gpioa::{PA5, PA6, PA7};
  37. use crate::gpio::gpiob::{PB13, PB14, PB15, PB3, PB4, PB5};
  38. #[cfg(feature = "connectivity")]
  39. use crate::gpio::gpioc::{PC10, PC11, PC12};
  40. use crate::gpio::{Alternate, Floating, Input, PushPull};
  41. use crate::rcc::{Clocks, Enable, GetBusFreq, Reset, APB1, APB2};
  42. use crate::time::Hertz;
  43. use core::sync::atomic::{self, Ordering};
  44. use embedded_dma::StaticReadBuffer;
  45. /// SPI error
  46. #[derive(Debug)]
  47. #[non_exhaustive]
  48. pub enum Error {
  49. /// Overrun occurred
  50. Overrun,
  51. /// Mode fault occurred
  52. ModeFault,
  53. /// CRC error
  54. Crc,
  55. }
  56. use core::marker::PhantomData;
  57. mod sealed {
  58. pub trait Remap {
  59. type Periph;
  60. const REMAP: bool;
  61. }
  62. pub trait Sck<REMAP> {}
  63. pub trait Miso<REMAP> {}
  64. pub trait Mosi<REMAP> {}
  65. pub struct _Sck;
  66. pub struct _Miso;
  67. pub struct _Mosi;
  68. }
  69. use sealed::{Miso, Mosi, Remap, Sck};
  70. pub trait Pins<REMAP, P> {
  71. type _Pos;
  72. }
  73. macro_rules! pins_impl {
  74. ( $( ( $($PINX:ident),+ ), ( $($TRAIT:ident),+ ), ( $($POS:ident),* ); )+ ) => {
  75. $(
  76. #[allow(unused_parens)]
  77. impl<REMAP, $($PINX,)+> Pins<REMAP, ($(sealed::$POS),+)> for ($($PINX),+)
  78. where
  79. $($PINX: $TRAIT<REMAP>,)+
  80. {
  81. type _Pos = ($(sealed::$POS),+);
  82. }
  83. )+
  84. };
  85. }
  86. pins_impl!(
  87. (SCK, MISO, MOSI), (Sck, Miso, Mosi), (_Sck, _Miso, _Mosi);
  88. (SCK, MOSI, MISO), (Sck, Mosi, Miso), (_Sck, _Mosi, _Miso);
  89. (MOSI, SCK, MISO), (Mosi, Sck, Miso), (_Mosi, _Sck, _Miso);
  90. (MOSI, MISO, SCK), (Mosi, Miso, Sck), (_Mosi, _Miso, _Sck);
  91. (MISO, MOSI, SCK), (Miso, Mosi, Sck), (_Miso, _Mosi, _Sck);
  92. (MISO, SCK, MOSI), (Miso, Sck, Mosi), (_Miso, _Sck, _Mosi);
  93. );
  94. pub struct Spi<SPI, REMAP, PINS, FRAMESIZE> {
  95. spi: SPI,
  96. pins: PINS,
  97. _remap: PhantomData<REMAP>,
  98. _framesize: PhantomData<FRAMESIZE>,
  99. }
  100. /// The bit format to send the data in
  101. #[derive(Debug, Clone, Copy)]
  102. pub enum SpiBitFormat {
  103. /// Least significant bit first
  104. LsbFirst,
  105. /// Most significant bit first
  106. MsbFirst,
  107. }
  108. /// A filler type for when the SCK pin is unnecessary
  109. pub struct NoSck;
  110. /// A filler type for when the Miso pin is unnecessary
  111. pub struct NoMiso;
  112. /// A filler type for when the Mosi pin is unnecessary
  113. pub struct NoMosi;
  114. impl<REMAP> Sck<REMAP> for NoSck {}
  115. impl<REMAP> Miso<REMAP> for NoMiso {}
  116. impl<REMAP> Mosi<REMAP> for NoMosi {}
  117. macro_rules! remap {
  118. ($name:ident, $SPIX:ident, $state:literal, $SCK:ident, $MISO:ident, $MOSI:ident) => {
  119. pub struct $name;
  120. impl Remap for $name {
  121. type Periph = $SPIX;
  122. const REMAP: bool = $state;
  123. }
  124. impl Sck<$name> for $SCK<Alternate<PushPull>> {}
  125. impl Miso<$name> for $MISO<Input<Floating>> {}
  126. impl Mosi<$name> for $MOSI<Alternate<PushPull>> {}
  127. };
  128. }
  129. remap!(Spi1NoRemap, SPI1, false, PA5, PA6, PA7);
  130. remap!(Spi1Remap, SPI1, true, PB3, PB4, PB5);
  131. remap!(Spi2NoRemap, SPI2, false, PB13, PB14, PB15);
  132. #[cfg(feature = "high")]
  133. remap!(Spi3NoRemap, SPI3, false, PB3, PB4, PB5);
  134. #[cfg(feature = "connectivity")]
  135. remap!(Spi3Remap, SPI3, true, PC10, PC11, PC12);
  136. impl<REMAP, PINS> Spi<SPI1, REMAP, PINS, u8> {
  137. /**
  138. Constructs an SPI instance using SPI1 in 8bit dataframe mode.
  139. The pin parameter tuple (sck, miso, mosi) should be `(PA5, PA6, PA7)` or `(PB3, PB4, PB5)` configured as `(Alternate<PushPull>, Input<Floating>, Alternate<PushPull>)`.
  140. You can also use `NoSck`, `NoMiso` or `NoMosi` if you don't want to use the pins
  141. */
  142. pub fn spi1<F, POS>(
  143. spi: SPI1,
  144. pins: PINS,
  145. mapr: &mut MAPR,
  146. mode: Mode,
  147. freq: F,
  148. clocks: Clocks,
  149. apb: &mut APB2,
  150. ) -> Self
  151. where
  152. F: Into<Hertz>,
  153. REMAP: Remap<Periph = SPI1>,
  154. PINS: Pins<REMAP, POS>,
  155. {
  156. mapr.modify_mapr(|_, w| w.spi1_remap().bit(REMAP::REMAP));
  157. Spi::<SPI1, _, _, u8>::_spi(spi, pins, mode, freq.into(), clocks, apb)
  158. }
  159. }
  160. impl<REMAP, PINS> Spi<SPI2, REMAP, PINS, u8> {
  161. /**
  162. Constructs an SPI instance using SPI2 in 8bit dataframe mode.
  163. The pin parameter tuple (sck, miso, mosi) should be `(PB13, PB14, PB15)` configured as `(Alternate<PushPull>, Input<Floating>, Alternate<PushPull>)`.
  164. You can also use `NoSck`, `NoMiso` or `NoMosi` if you don't want to use the pins
  165. */
  166. pub fn spi2<F, POS>(
  167. spi: SPI2,
  168. pins: PINS,
  169. mode: Mode,
  170. freq: F,
  171. clocks: Clocks,
  172. apb: &mut APB1,
  173. ) -> Self
  174. where
  175. F: Into<Hertz>,
  176. REMAP: Remap<Periph = SPI2>,
  177. PINS: Pins<REMAP, POS>,
  178. {
  179. Spi::<SPI2, _, _, u8>::_spi(spi, pins, mode, freq.into(), clocks, apb)
  180. }
  181. }
  182. #[cfg(any(feature = "high", feature = "connectivity"))]
  183. impl<REMAP, PINS> Spi<SPI3, REMAP, PINS, u8> {
  184. /**
  185. Constructs an SPI instance using SPI3 in 8bit dataframe mode.
  186. The pin parameter tuple (sck, miso, mosi) should be `(PB3, PB4, PB5)` or `(PC10, PC11, PC12)` configured as `(Alternate<PushPull>, Input<Floating>, Alternate<PushPull>)`.
  187. You can also use `NoSck`, `NoMiso` or `NoMosi` if you don't want to use the pins
  188. */
  189. pub fn spi3<F, POS>(
  190. spi: SPI3,
  191. pins: PINS,
  192. mapr: &mut MAPR,
  193. mode: Mode,
  194. freq: F,
  195. clocks: Clocks,
  196. apb: &mut APB1,
  197. ) -> Self
  198. where
  199. F: Into<Hertz>,
  200. REMAP: Remap<Periph = SPI3>,
  201. PINS: Pins<REMAP, POS>,
  202. {
  203. mapr.modify_mapr(|_, w| w.spi3_remap().bit(REMAP::REMAP));
  204. Spi::<SPI3, _, _, u8>::_spi(spi, pins, mode, freq.into(), clocks, apb)
  205. }
  206. }
  207. pub type SpiRegisterBlock = crate::pac::spi1::RegisterBlock;
  208. pub trait SpiReadWrite<T> {
  209. fn read_data_reg(&mut self) -> T;
  210. fn write_data_reg(&mut self, data: T);
  211. fn spi_write(&mut self, words: &[T]) -> Result<(), Error>;
  212. }
  213. impl<SPI, REMAP, PINS, FrameSize> SpiReadWrite<FrameSize> for Spi<SPI, REMAP, PINS, FrameSize>
  214. where
  215. SPI: Deref<Target = SpiRegisterBlock>,
  216. FrameSize: Copy,
  217. {
  218. fn read_data_reg(&mut self) -> FrameSize {
  219. // NOTE(read_volatile) read only 1 byte (the svd2rust API only allows
  220. // reading a half-word)
  221. unsafe { ptr::read_volatile(&self.spi.dr as *const _ as *const FrameSize) }
  222. }
  223. fn write_data_reg(&mut self, data: FrameSize) {
  224. // NOTE(write_volatile) see note above
  225. unsafe { ptr::write_volatile(&self.spi.dr as *const _ as *mut FrameSize, data) }
  226. }
  227. // Implement write as per the "Transmit only procedure" page 712
  228. // of RM0008 Rev 20. This is more than twice as fast as the
  229. // default Write<> implementation (which reads and drops each
  230. // received value)
  231. fn spi_write(&mut self, words: &[FrameSize]) -> Result<(), Error> {
  232. // Write each word when the tx buffer is empty
  233. for word in words {
  234. loop {
  235. let sr = self.spi.sr.read();
  236. if sr.txe().bit_is_set() {
  237. // NOTE(write_volatile) see note above
  238. // unsafe { ptr::write_volatile(&self.spi.dr as *const _ as *mut u8, *word) }
  239. self.write_data_reg(*word);
  240. if sr.modf().bit_is_set() {
  241. return Err(Error::ModeFault);
  242. }
  243. break;
  244. }
  245. }
  246. }
  247. // Wait for final TXE
  248. loop {
  249. let sr = self.spi.sr.read();
  250. if sr.txe().bit_is_set() {
  251. break;
  252. }
  253. }
  254. // Wait for final !BSY
  255. loop {
  256. let sr = self.spi.sr.read();
  257. if !sr.bsy().bit_is_set() {
  258. break;
  259. }
  260. }
  261. // Clear OVR set due to dropped received values
  262. // NOTE(read_volatile) see note above
  263. // unsafe {
  264. // let _ = ptr::read_volatile(&self.spi.dr as *const _ as *const u8);
  265. // }
  266. let _ = self.read_data_reg();
  267. let _ = self.spi.sr.read();
  268. Ok(())
  269. }
  270. }
  271. impl<SPI, REMAP, PINS, FrameSize> Spi<SPI, REMAP, PINS, FrameSize>
  272. where
  273. SPI: Deref<Target = SpiRegisterBlock>,
  274. FrameSize: Copy,
  275. {
  276. #[deprecated(since = "0.6.0", note = "Please use release instead")]
  277. pub fn free(self) -> (SPI, PINS) {
  278. self.release()
  279. }
  280. pub fn release(self) -> (SPI, PINS) {
  281. (self.spi, self.pins)
  282. }
  283. /// Select which frame format is used for data transfers
  284. pub fn bit_format(&mut self, format: SpiBitFormat) {
  285. match format {
  286. SpiBitFormat::LsbFirst => self.spi.cr1.modify(|_, w| w.lsbfirst().set_bit()),
  287. SpiBitFormat::MsbFirst => self.spi.cr1.modify(|_, w| w.lsbfirst().clear_bit()),
  288. }
  289. }
  290. }
  291. impl<SPI, REMAP, PINS> Spi<SPI, REMAP, PINS, u8>
  292. where
  293. SPI: Deref<Target = SpiRegisterBlock> + Enable + Reset,
  294. SPI::Bus: GetBusFreq,
  295. {
  296. fn _spi(
  297. spi: SPI,
  298. pins: PINS,
  299. mode: Mode,
  300. freq: Hertz,
  301. clocks: Clocks,
  302. apb: &mut SPI::Bus,
  303. ) -> Self {
  304. // enable or reset SPI
  305. SPI::enable(apb);
  306. SPI::reset(apb);
  307. // disable SS output
  308. spi.cr2.write(|w| w.ssoe().clear_bit());
  309. let br = match SPI::Bus::get_frequency(&clocks).0 / freq.0 {
  310. 0 => unreachable!(),
  311. 1..=2 => 0b000,
  312. 3..=5 => 0b001,
  313. 6..=11 => 0b010,
  314. 12..=23 => 0b011,
  315. 24..=47 => 0b100,
  316. 48..=95 => 0b101,
  317. 96..=191 => 0b110,
  318. _ => 0b111,
  319. };
  320. spi.cr1.write(|w| {
  321. w
  322. // clock phase from config
  323. .cpha()
  324. .bit(mode.phase == Phase::CaptureOnSecondTransition)
  325. // clock polarity from config
  326. .cpol()
  327. .bit(mode.polarity == Polarity::IdleHigh)
  328. // mstr: master configuration
  329. .mstr()
  330. .set_bit()
  331. // baudrate value
  332. .br()
  333. .bits(br)
  334. // lsbfirst: MSB first
  335. .lsbfirst()
  336. .clear_bit()
  337. // ssm: enable software slave management (NSS pin free for other uses)
  338. .ssm()
  339. .set_bit()
  340. // ssi: set nss high = master mode
  341. .ssi()
  342. .set_bit()
  343. // dff: 8 bit frames
  344. .dff()
  345. .clear_bit()
  346. // bidimode: 2-line unidirectional
  347. .bidimode()
  348. .clear_bit()
  349. // both TX and RX are used
  350. .rxonly()
  351. .clear_bit()
  352. // spe: enable the SPI bus
  353. .spe()
  354. .set_bit()
  355. });
  356. Spi {
  357. spi,
  358. pins,
  359. _remap: PhantomData,
  360. _framesize: PhantomData,
  361. }
  362. }
  363. /// Converts from 8bit dataframe to 16bit.
  364. pub fn frame_size_16bit(self) -> Spi<SPI, REMAP, PINS, u16> {
  365. self.spi.cr1.modify(|_, w| w.spe().clear_bit());
  366. self.spi.cr1.modify(|_, w| w.dff().set_bit());
  367. self.spi.cr1.modify(|_, w| w.spe().set_bit());
  368. Spi {
  369. spi: self.spi,
  370. pins: self.pins,
  371. _remap: PhantomData,
  372. _framesize: PhantomData,
  373. }
  374. }
  375. }
  376. impl<SPI, REMAP, PINS> Spi<SPI, REMAP, PINS, u16>
  377. where
  378. SPI: Deref<Target = SpiRegisterBlock>,
  379. {
  380. /// Converts from 16bit dataframe to 8bit.
  381. pub fn frame_size_8bit(self) -> Spi<SPI, REMAP, PINS, u8> {
  382. self.spi.cr1.modify(|_, w| w.spe().clear_bit());
  383. self.spi.cr1.modify(|_, w| w.dff().clear_bit());
  384. self.spi.cr1.modify(|_, w| w.spe().set_bit());
  385. Spi {
  386. spi: self.spi,
  387. pins: self.pins,
  388. _remap: PhantomData,
  389. _framesize: PhantomData,
  390. }
  391. }
  392. }
  393. impl<SPI, REMAP, PINS, FrameSize> crate::hal::spi::FullDuplex<FrameSize>
  394. for Spi<SPI, REMAP, PINS, FrameSize>
  395. where
  396. SPI: Deref<Target = SpiRegisterBlock>,
  397. FrameSize: Copy,
  398. {
  399. type Error = Error;
  400. fn read(&mut self) -> nb::Result<FrameSize, Error> {
  401. let sr = self.spi.sr.read();
  402. Err(if sr.ovr().bit_is_set() {
  403. nb::Error::Other(Error::Overrun)
  404. } else if sr.modf().bit_is_set() {
  405. nb::Error::Other(Error::ModeFault)
  406. } else if sr.crcerr().bit_is_set() {
  407. nb::Error::Other(Error::Crc)
  408. } else if sr.rxne().bit_is_set() {
  409. // NOTE(read_volatile) read only 1 byte (the svd2rust API only allows
  410. // reading a half-word)
  411. return Ok(self.read_data_reg());
  412. } else {
  413. nb::Error::WouldBlock
  414. })
  415. }
  416. fn send(&mut self, data: FrameSize) -> nb::Result<(), Error> {
  417. let sr = self.spi.sr.read();
  418. Err(if sr.ovr().bit_is_set() {
  419. nb::Error::Other(Error::Overrun)
  420. } else if sr.modf().bit_is_set() {
  421. nb::Error::Other(Error::ModeFault)
  422. } else if sr.crcerr().bit_is_set() {
  423. nb::Error::Other(Error::Crc)
  424. } else if sr.txe().bit_is_set() {
  425. // NOTE(write_volatile) see note above
  426. self.write_data_reg(data);
  427. return Ok(());
  428. } else {
  429. nb::Error::WouldBlock
  430. })
  431. }
  432. }
  433. impl<SPI, REMAP, PINS, FrameSize> crate::hal::blocking::spi::transfer::Default<FrameSize>
  434. for Spi<SPI, REMAP, PINS, FrameSize>
  435. where
  436. SPI: Deref<Target = SpiRegisterBlock>,
  437. FrameSize: Copy,
  438. {
  439. }
  440. impl<SPI, REMAP, PINS> crate::hal::blocking::spi::Write<u8> for Spi<SPI, REMAP, PINS, u8>
  441. where
  442. SPI: Deref<Target = SpiRegisterBlock>,
  443. {
  444. type Error = Error;
  445. // Implement write as per the "Transmit only procedure" page 712
  446. // of RM0008 Rev 20. This is more than twice as fast as the
  447. // default Write<> implementation (which reads and drops each
  448. // received value)
  449. fn write(&mut self, words: &[u8]) -> Result<(), Error> {
  450. self.spi_write(words)
  451. }
  452. }
  453. impl<SPI, REMAP, PINS> crate::hal::blocking::spi::Write<u16> for Spi<SPI, REMAP, PINS, u16>
  454. where
  455. SPI: Deref<Target = SpiRegisterBlock>,
  456. {
  457. type Error = Error;
  458. fn write(&mut self, words: &[u16]) -> Result<(), Error> {
  459. self.spi_write(words)
  460. }
  461. }
  462. // DMA
  463. pub struct SpiPayload<SPI, REMAP, PINS> {
  464. spi: Spi<SPI, REMAP, PINS, u8>,
  465. }
  466. pub type SpiTxDma<SPI, REMAP, PINS, CHANNEL> = TxDma<SpiPayload<SPI, REMAP, PINS>, CHANNEL>;
  467. macro_rules! spi_dma {
  468. ($SPIi:ident, $TCi:ident) => {
  469. impl<REMAP, PINS> Transmit for SpiTxDma<$SPIi, REMAP, PINS, $TCi> {
  470. type TxChannel = $TCi;
  471. type ReceivedWord = u8;
  472. }
  473. impl<REMAP, PINS> Spi<$SPIi, REMAP, PINS, u8> {
  474. pub fn with_tx_dma(self, channel: $TCi) -> SpiTxDma<$SPIi, REMAP, PINS, $TCi> {
  475. let payload = SpiPayload { spi: self };
  476. SpiTxDma { payload, channel }
  477. }
  478. }
  479. impl<REMAP, PINS> TransferPayload for SpiTxDma<$SPIi, REMAP, PINS, $TCi> {
  480. fn start(&mut self) {
  481. self.payload
  482. .spi
  483. .spi
  484. .cr2
  485. .modify(|_, w| w.txdmaen().set_bit());
  486. self.channel.start();
  487. }
  488. fn stop(&mut self) {
  489. self.payload
  490. .spi
  491. .spi
  492. .cr2
  493. .modify(|_, w| w.txdmaen().clear_bit());
  494. self.channel.stop();
  495. }
  496. }
  497. impl<B, REMAP, PIN> crate::dma::WriteDma<B, u8> for SpiTxDma<$SPIi, REMAP, PIN, $TCi>
  498. where
  499. B: StaticReadBuffer<Word = u8>,
  500. {
  501. fn write(mut self, buffer: B) -> Transfer<R, B, Self> {
  502. // NOTE(unsafe) We own the buffer now and we won't call other `&mut` on it
  503. // until the end of the transfer.
  504. let (ptr, len) = unsafe { buffer.static_read_buffer() };
  505. self.channel.set_peripheral_address(
  506. unsafe { &(*$SPIi::ptr()).dr as *const _ as u32 },
  507. false,
  508. );
  509. self.channel.set_memory_address(ptr as u32, true);
  510. self.channel.set_transfer_length(len);
  511. atomic::compiler_fence(Ordering::Release);
  512. self.channel.ch().cr.modify(|_, w| {
  513. w
  514. // memory to memory mode disabled
  515. .mem2mem()
  516. .clear_bit()
  517. // medium channel priority level
  518. .pl()
  519. .medium()
  520. // 8-bit memory size
  521. .msize()
  522. .bits8()
  523. // 8-bit peripheral size
  524. .psize()
  525. .bits8()
  526. // circular mode disabled
  527. .circ()
  528. .clear_bit()
  529. // read from memory
  530. .dir()
  531. .set_bit()
  532. });
  533. self.start();
  534. Transfer::r(buffer, self)
  535. }
  536. }
  537. };
  538. }
  539. spi_dma!(SPI1, C3);
  540. spi_dma!(SPI2, C5);
  541. #[cfg(feature = "connectivity")]
  542. spi_dma!(SPI3, C2);