aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorxoviat <[email protected]>2021-04-13 16:11:06 -0500
committerGitHub <[email protected]>2021-04-13 16:11:06 -0500
commit8e040cc5d25280a2baf8189428c80ae8c7081d2b (patch)
tree6de6c0062157e27a8f2001d565ce7227f4978e31
parent0bd35373c02356bfa28e17b7dc630b5dacb74206 (diff)
stm32: add draft spi trait (#130)
-rw-r--r--embassy-stm32/src/f4/mod.rs1
-rw-r--r--embassy-stm32/src/f4/spi.rs479
-rw-r--r--embassy-stm32/src/lib.rs2
3 files changed, 481 insertions, 1 deletions
diff --git a/embassy-stm32/src/f4/mod.rs b/embassy-stm32/src/f4/mod.rs
index b1fc0cf1d..9edde82ca 100644
--- a/embassy-stm32/src/f4/mod.rs
+++ b/embassy-stm32/src/f4/mod.rs
@@ -1 +1,2 @@
1pub mod serial; 1pub mod serial;
2pub mod spi;
diff --git a/embassy-stm32/src/f4/spi.rs b/embassy-stm32/src/f4/spi.rs
new file mode 100644
index 000000000..bc73611fd
--- /dev/null
+++ b/embassy-stm32/src/f4/spi.rs
@@ -0,0 +1,479 @@
1//! Async SPI
2
3use embassy::time;
4
5use core::{future::Future, marker::PhantomData, mem, ops::Deref, pin::Pin, ptr};
6use embassy::{interrupt::Interrupt, traits::spi::FullDuplex, util::InterruptFuture};
7use nb;
8
9pub use crate::hal::spi::{Mode, Phase, Polarity};
10use crate::hal::{
11 bb, dma,
12 dma::config::DmaConfig,
13 dma::traits::{Channel, DMASet, PeriAddress, Stream},
14 dma::{MemoryToPeripheral, PeripheralToMemory, Transfer},
15 rcc::Clocks,
16 spi::Pins,
17 time::Hertz,
18};
19use crate::interrupt;
20use crate::pac;
21use futures::future;
22
23#[derive(Debug, Clone, Copy, PartialEq, Eq)]
24#[cfg_attr(feature = "defmt", derive(defmt::Format))]
25#[non_exhaustive]
26pub enum Error {
27 TxBufferTooLong,
28 RxBufferTooLong,
29 Overrun,
30 ModeFault,
31 Crc,
32}
33
34fn read_sr<T: Instance>(spi: &T) -> nb::Result<u8, Error> {
35 let sr = spi.sr.read();
36 Err(if sr.ovr().bit_is_set() {
37 nb::Error::Other(Error::Overrun)
38 } else if sr.modf().bit_is_set() {
39 nb::Error::Other(Error::ModeFault)
40 } else if sr.crcerr().bit_is_set() {
41 nb::Error::Other(Error::Crc)
42 } else if sr.rxne().bit_is_set() {
43 // NOTE(read_volatile) read only 1 byte (the svd2rust API only allows
44 // reading a half-word)
45 return Ok(unsafe { ptr::read_volatile(&spi.dr as *const _ as *const u8) });
46 } else {
47 nb::Error::WouldBlock
48 })
49}
50
51fn write_sr<T: Instance>(spi: &T, byte: u8) -> nb::Result<(), Error> {
52 let sr = spi.sr.read();
53 Err(if sr.ovr().bit_is_set() {
54 // Read from the DR to clear the OVR bit
55 let _ = spi.dr.read();
56 nb::Error::Other(Error::Overrun)
57 } else if sr.modf().bit_is_set() {
58 // Write to CR1 to clear MODF
59 spi.cr1.modify(|_r, w| w);
60 nb::Error::Other(Error::ModeFault)
61 } else if sr.crcerr().bit_is_set() {
62 // Clear the CRCERR bit
63 spi.sr.modify(|_r, w| {
64 w.crcerr().clear_bit();
65 w
66 });
67 nb::Error::Other(Error::Crc)
68 } else if sr.txe().bit_is_set() {
69 // NOTE(write_volatile) see note above
70 unsafe { ptr::write_volatile(&spi.dr as *const _ as *mut u8, byte) }
71 return Ok(());
72 } else {
73 nb::Error::WouldBlock
74 })
75}
76
77/// Interface to the Serial peripheral
78pub struct Spi<
79 SPI: PeriAddress<MemSize = u8> + WithInterrupt,
80 TSTREAM: Stream + WithInterrupt,
81 RSTREAM: Stream + WithInterrupt,
82 CHANNEL: Channel,
83> {
84 tx_stream: Option<TSTREAM>,
85 rx_stream: Option<RSTREAM>,
86 spi: Option<SPI>,
87 tx_int: TSTREAM::Interrupt,
88 rx_int: RSTREAM::Interrupt,
89 spi_int: SPI::Interrupt,
90 channel: PhantomData<CHANNEL>,
91}
92
93impl<SPI, TSTREAM, RSTREAM, CHANNEL> Spi<SPI, TSTREAM, RSTREAM, CHANNEL>
94where
95 SPI: Instance
96 + PeriAddress<MemSize = u8>
97 + DMASet<TSTREAM, CHANNEL, MemoryToPeripheral>
98 + DMASet<RSTREAM, CHANNEL, PeripheralToMemory>
99 + WithInterrupt,
100 TSTREAM: Stream + WithInterrupt,
101 RSTREAM: Stream + WithInterrupt,
102 CHANNEL: Channel,
103{
104 // Leaking futures is forbidden!
105 pub unsafe fn new<PINS>(
106 spi: SPI,
107 streams: (TSTREAM, RSTREAM),
108 pins: PINS,
109 tx_int: TSTREAM::Interrupt,
110 rx_int: RSTREAM::Interrupt,
111 spi_int: SPI::Interrupt,
112 mode: Mode,
113 freq: Hertz,
114 clocks: Clocks,
115 ) -> Self
116 where
117 PINS: Pins<SPI>,
118 {
119 let (tx_stream, rx_stream) = streams;
120
121 // let spi1: crate::pac::SPI1 = unsafe { mem::transmute(()) };
122 // let mut hspi = crate::hal::spi::Spi::spi1(
123 // spi1,
124 // (
125 // crate::hal::spi::NoSck,
126 // crate::hal::spi::NoMiso,
127 // crate::hal::spi::NoMosi,
128 // ),
129 // mode,
130 // freq,
131 // clocks,
132 // );
133
134 unsafe { SPI::enable_clock() };
135
136 let clock = SPI::clock_speed(clocks);
137
138 // disable SS output
139 // spi.cr2
140 // .write(|w| w.ssoe().clear_bit().rxdmaen().set_bit().txdmaen().set_bit());
141 spi.cr2.write(|w| w.ssoe().clear_bit());
142
143 let br = match clock.0 / freq.0 {
144 0 => unreachable!(),
145 1..=2 => 0b000,
146 3..=5 => 0b001,
147 6..=11 => 0b010,
148 12..=23 => 0b011,
149 24..=47 => 0b100,
150 48..=95 => 0b101,
151 96..=191 => 0b110,
152 _ => 0b111,
153 };
154
155 // mstr: master configuration
156 // lsbfirst: MSB first
157 // ssm: enable software slave management (NSS pin free for other uses)
158 // ssi: set nss high = master mode
159 // dff: 8 bit frames
160 // bidimode: 2-line unidirectional
161 // spe: enable the SPI bus
162 spi.cr1.write(|w| {
163 w.cpha()
164 .bit(mode.phase == Phase::CaptureOnSecondTransition)
165 .cpol()
166 .bit(mode.polarity == Polarity::IdleHigh)
167 .mstr()
168 .set_bit()
169 .br()
170 .bits(br)
171 .lsbfirst()
172 .clear_bit()
173 .ssm()
174 .set_bit()
175 .ssi()
176 .set_bit()
177 .rxonly()
178 .clear_bit()
179 .dff()
180 .clear_bit()
181 .bidimode()
182 .clear_bit()
183 .spe()
184 .set_bit()
185 });
186
187 Self {
188 tx_stream: Some(tx_stream),
189 rx_stream: Some(rx_stream),
190 spi: Some(spi),
191 tx_int: tx_int,
192 rx_int: rx_int,
193 spi_int: spi_int,
194 channel: PhantomData,
195 }
196 }
197}
198
199impl<SPI, TSTREAM, RSTREAM, CHANNEL> FullDuplex<u8> for Spi<SPI, TSTREAM, RSTREAM, CHANNEL>
200where
201 SPI: Instance
202 + PeriAddress<MemSize = u8>
203 + DMASet<TSTREAM, CHANNEL, MemoryToPeripheral>
204 + DMASet<RSTREAM, CHANNEL, PeripheralToMemory>
205 + WithInterrupt
206 + 'static,
207 TSTREAM: Stream + WithInterrupt + 'static,
208 RSTREAM: Stream + WithInterrupt + 'static,
209 CHANNEL: Channel + 'static,
210{
211 type Error = Error;
212
213 type WriteFuture<'a> = impl Future<Output = Result<(), Error>> + 'a;
214 type ReadFuture<'a> = impl Future<Output = Result<(), Error>> + 'a;
215 type WriteReadFuture<'a> = impl Future<Output = Result<(), Error>> + 'a;
216
217 fn read<'a>(self: Pin<&'a mut Self>, buf: &'a mut [u8]) -> Self::ReadFuture<'a> {
218 let this = unsafe { self.get_unchecked_mut() };
219 #[allow(mutable_transmutes)]
220 let static_buf: &'static mut [u8] = unsafe { mem::transmute(buf) };
221
222 async move {
223 let rx_stream = this.rx_stream.take().unwrap();
224 let spi = this.spi.take().unwrap();
225
226 spi.cr2.modify(|_, w| w.errie().set_bit());
227
228 let mut rx_transfer = Transfer::init(
229 rx_stream,
230 spi,
231 static_buf,
232 None,
233 DmaConfig::default()
234 .transfer_complete_interrupt(true)
235 .memory_increment(true)
236 .double_buffer(false),
237 );
238
239 let fut = InterruptFuture::new(&mut this.rx_int);
240 let fut_err = InterruptFuture::new(&mut this.spi_int);
241
242 rx_transfer.start(|_spi| {});
243 future::select(fut, fut_err).await;
244
245 let (rx_stream, spi, _buf, _) = rx_transfer.free();
246
247 spi.cr2.modify(|_, w| w.errie().clear_bit());
248 this.rx_stream.replace(rx_stream);
249 this.spi.replace(spi);
250
251 Ok(())
252 }
253 }
254
255 fn write<'a>(self: Pin<&'a mut Self>, buf: &'a [u8]) -> Self::WriteFuture<'a> {
256 let this = unsafe { self.get_unchecked_mut() };
257 #[allow(mutable_transmutes)]
258 let static_buf: &'static mut [u8] = unsafe { mem::transmute(buf) };
259
260 async move {
261 let tx_stream = this.tx_stream.take().unwrap();
262 let spi = this.spi.take().unwrap();
263
264 // let mut tx_transfer = Transfer::init(
265 // tx_stream,
266 // spi,
267 // static_buf,
268 // None,
269 // DmaConfig::default()
270 // .transfer_complete_interrupt(true)
271 // .memory_increment(true)
272 // .double_buffer(false),
273 // );
274 //
275 // let fut = InterruptFuture::new(&mut this.tx_int);
276 //
277 // tx_transfer.start(|_spi| {});
278 // fut.await;
279
280 // let (tx_stream, spi, _buf, _) = tx_transfer.free();
281
282 for i in 0..(static_buf.len() - 1) {
283 let byte = static_buf[i];
284 nb::block!(write_sr(&spi, byte));
285 }
286
287 this.tx_stream.replace(tx_stream);
288 this.spi.replace(spi);
289
290 Ok(())
291 }
292 }
293
294 fn read_write<'a>(
295 self: Pin<&'a mut Self>,
296 read_buf: &'a mut [u8],
297 write_buf: &'a [u8],
298 ) -> Self::WriteReadFuture<'a> {
299 let this = unsafe { self.get_unchecked_mut() };
300
301 #[allow(mutable_transmutes)]
302 let write_static_buf: &'static mut [u8] = unsafe { mem::transmute(write_buf) };
303 let read_static_buf: &'static mut [u8] = unsafe { mem::transmute(read_buf) };
304
305 async move {
306 let tx_stream = this.tx_stream.take().unwrap();
307 let rx_stream = this.rx_stream.take().unwrap();
308 let spi_tx = this.spi.take().unwrap();
309 let spi_rx: SPI = unsafe { mem::transmute_copy(&spi_tx) };
310
311 spi_rx
312 .cr2
313 .modify(|_, w| w.errie().set_bit().txeie().set_bit().rxneie().set_bit());
314
315 // let mut tx_transfer = Transfer::init(
316 // tx_stream,
317 // spi_tx,
318 // write_static_buf,
319 // None,
320 // DmaConfig::default()
321 // .transfer_complete_interrupt(true)
322 // .memory_increment(true)
323 // .double_buffer(false),
324 // );
325 //
326 // let mut rx_transfer = Transfer::init(
327 // rx_stream,
328 // spi_rx,
329 // read_static_buf,
330 // None,
331 // DmaConfig::default()
332 // .transfer_complete_interrupt(true)
333 // .memory_increment(true)
334 // .double_buffer(false),
335 // );
336 //
337 // let tx_fut = InterruptFuture::new(&mut this.tx_int);
338 // let rx_fut = InterruptFuture::new(&mut this.rx_int);
339 // let rx_fut_err = InterruptFuture::new(&mut this.spi_int);
340 //
341 // rx_transfer.start(|_spi| {});
342 // tx_transfer.start(|_spi| {});
343 //
344 // time::Timer::after(time::Duration::from_millis(500)).await;
345 //
346 // // tx_fut.await;
347 // // future::select(rx_fut, rx_fut_err).await;
348 //
349 // let (rx_stream, spi_rx, _buf, _) = rx_transfer.free();
350 // let (tx_stream, _, _buf, _) = tx_transfer.free();
351
352 for i in 0..(read_static_buf.len() - 1) {
353 let byte = write_static_buf[i];
354 loop {
355 let fut = InterruptFuture::new(&mut this.spi_int);
356 match write_sr(&spi_tx, byte) {
357 Ok(()) => break,
358 _ => {}
359 }
360 fut.await;
361 }
362
363 loop {
364 let fut = InterruptFuture::new(&mut this.spi_int);
365 match read_sr(&spi_tx) {
366 Ok(byte) => {
367 read_static_buf[i] = byte;
368 break;
369 }
370 _ => {}
371 }
372 fut.await;
373 }
374 }
375
376 spi_rx.cr2.modify(|_, w| {
377 w.errie()
378 .clear_bit()
379 .txeie()
380 .clear_bit()
381 .rxneie()
382 .clear_bit()
383 });
384 this.rx_stream.replace(rx_stream);
385 this.tx_stream.replace(tx_stream);
386 this.spi.replace(spi_rx);
387
388 Ok(())
389 }
390 }
391}
392
393mod private {
394 pub trait Sealed {}
395}
396
397pub trait WithInterrupt: private::Sealed {
398 type Interrupt: Interrupt;
399}
400
401pub trait Instance: Deref<Target = pac::spi1::RegisterBlock> + private::Sealed {
402 unsafe fn enable_clock();
403 fn clock_speed(clocks: Clocks) -> Hertz;
404}
405
406macro_rules! dma {
407 ($($PER:ident => ($dma:ident, $stream:ident),)+) => {
408 $(
409 impl private::Sealed for dma::$stream<pac::$dma> {}
410 impl WithInterrupt for dma::$stream<pac::$dma> {
411 type Interrupt = interrupt::$PER;
412 }
413 )+
414 }
415 }
416
417macro_rules! spi {
418 ($($PER:ident => ($SPI:ident, $pclkX:ident, $apbXenr:ident, $en:expr),)+) => {
419 $(
420 impl private::Sealed for pac::$SPI {}
421 impl Instance for pac::$SPI {
422 unsafe fn enable_clock() {
423 const EN_BIT: u8 = $en;
424 // NOTE(unsafe) this reference will only be used for atomic writes with no side effects.
425 let rcc = &(*pac::RCC::ptr());
426 // Enable clock.
427 bb::set(&rcc.$apbXenr, EN_BIT);
428 // Stall the pipeline to work around erratum 2.1.13 (DM00037591)
429 cortex_m::asm::dsb();
430 }
431
432 fn clock_speed(clocks: Clocks) -> Hertz {
433 clocks.$pclkX()
434 }
435 }
436 impl WithInterrupt for pac::$SPI {
437 type Interrupt = interrupt::$PER;
438 }
439 )+
440 }
441}
442
443dma! {
444 DMA2_STREAM0 => (DMA2, Stream0),
445 DMA2_STREAM1 => (DMA2, Stream1),
446 DMA2_STREAM2 => (DMA2, Stream2),
447 DMA2_STREAM3 => (DMA2, Stream3),
448 DMA2_STREAM4 => (DMA2, Stream4),
449 DMA2_STREAM5 => (DMA2, Stream5),
450 DMA2_STREAM6 => (DMA2, Stream6),
451 DMA2_STREAM7 => (DMA2, Stream7),
452 DMA1_STREAM0 => (DMA1, Stream0),
453 DMA1_STREAM1 => (DMA1, Stream1),
454 DMA1_STREAM2 => (DMA1, Stream2),
455 DMA1_STREAM3 => (DMA1, Stream3),
456 DMA1_STREAM4 => (DMA1, Stream4),
457 DMA1_STREAM5 => (DMA1, Stream5),
458 DMA1_STREAM6 => (DMA1, Stream6),
459}
460
461#[cfg(any(
462 feature = "stm32f401",
463 feature = "stm32f410",
464 feature = "stm32f411",
465 feature = "stm32f446",
466))]
467spi! {
468 SPI1 => (SPI1, pclk2, apb2enr, 12),
469 SPI2 => (SPI2, pclk1, apb2enr, 14),
470// SPI6 => (SPI6, pclk2, apb2enr, 21),
471 SPI4 => (SPI3, pclk2, apb2enr, 13),
472// SPI5 => (SPI3, pclk2, apb2enr, 20),
473}
474
475#[cfg(any(feature = "stm32f405", feature = "stm32f407"))]
476spi! {
477 SPI1 => (SPI1, pclk2, apb2enr, 12),
478 SPI3 => (SPI3, pclk1, apb2enr, 15),
479}
diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs
index 370b5f0db..56efa461c 100644
--- a/embassy-stm32/src/lib.rs
+++ b/embassy-stm32/src/lib.rs
@@ -109,7 +109,7 @@ pub mod rtc;
109 feature = "stm32f469", 109 feature = "stm32f469",
110 feature = "stm32f479", 110 feature = "stm32f479",
111))] 111))]
112pub use f4::serial; 112pub use f4::{serial, spi};
113 113
114#[cfg(any( 114#[cfg(any(
115 feature = "stm32f401", 115 feature = "stm32f401",