spi.rs 19 KB

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