aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-stm32/src/dma/bdma.rs6
-rw-r--r--embassy-stm32/src/spi/mod.rs4
-rw-r--r--embassy-stm32/src/spi/v2.rs217
-rw-r--r--embassy-stm32/src/spi/v3.rs28
-rw-r--r--examples/stm32l4/src/bin/spi.rs3
-rw-r--r--examples/stm32l4/src/bin/spi_dma.rs103
6 files changed, 344 insertions, 17 deletions
diff --git a/embassy-stm32/src/dma/bdma.rs b/embassy-stm32/src/dma/bdma.rs
index 46670e1be..adb288eb0 100644
--- a/embassy-stm32/src/dma/bdma.rs
+++ b/embassy-stm32/src/dma/bdma.rs
@@ -89,7 +89,11 @@ pub(crate) unsafe fn do_transfer(
89 ch.cr().write(|w| { 89 ch.cr().write(|w| {
90 w.set_psize(vals::Size::BITS8); 90 w.set_psize(vals::Size::BITS8);
91 w.set_msize(vals::Size::BITS8); 91 w.set_msize(vals::Size::BITS8);
92 w.set_minc(vals::Inc::ENABLED); 92 if incr_mem {
93 w.set_minc(vals::Inc::ENABLED);
94 } else {
95 w.set_minc(vals::Inc::DISABLED);
96 }
93 w.set_dir(dir); 97 w.set_dir(dir);
94 w.set_teie(true); 98 w.set_teie(true);
95 w.set_tcie(true); 99 w.set_tcie(true);
diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs
index 9bb5a729c..046ec0fe7 100644
--- a/embassy-stm32/src/spi/mod.rs
+++ b/embassy-stm32/src/spi/mod.rs
@@ -1,8 +1,8 @@
1#![macro_use] 1#![macro_use]
2 2
3#[cfg_attr(spi_v1, path = "v1.rs")] 3//#[cfg_attr(spi_v1, path = "v1.rs")]
4#[cfg_attr(spi_v2, path = "v2.rs")] 4#[cfg_attr(spi_v2, path = "v2.rs")]
5#[cfg_attr(spi_v3, path = "v3.rs")] 5//#[cfg_attr(spi_v3, path = "v3.rs")]
6mod _version; 6mod _version;
7use crate::{dma, peripherals, rcc::RccPeripheral}; 7use crate::{dma, peripherals, rcc::RccPeripheral};
8pub use _version::*; 8pub use _version::*;
diff --git a/embassy-stm32/src/spi/v2.rs b/embassy-stm32/src/spi/v2.rs
index 4e135e9df..400fd89af 100644
--- a/embassy-stm32/src/spi/v2.rs
+++ b/embassy-stm32/src/spi/v2.rs
@@ -1,16 +1,23 @@
1#![macro_use] 1#![macro_use]
2 2
3use crate::dma::NoDma;
3use crate::gpio::{AnyPin, Pin}; 4use crate::gpio::{AnyPin, Pin};
4use crate::pac::gpio::vals::{Afr, Moder}; 5use crate::pac::gpio::vals::{Afr, Moder};
5use crate::pac::gpio::Gpio; 6use crate::pac::gpio::Gpio;
6use crate::pac::spi; 7use crate::pac::spi;
7use crate::spi::{ByteOrder, Config, Error, Instance, MisoPin, MosiPin, SckPin, WordSize}; 8use crate::spi::{
9 ByteOrder, Config, Error, Instance, MisoPin, MosiPin, RxDmaChannel, SckPin, TxDmaChannel,
10 WordSize,
11};
8use crate::time::Hertz; 12use crate::time::Hertz;
13use core::future::Future;
9use core::marker::PhantomData; 14use core::marker::PhantomData;
10use core::ptr; 15use core::ptr;
11use embassy::util::Unborrow; 16use embassy::util::Unborrow;
12use embassy_extras::unborrow; 17use embassy_extras::unborrow;
18use embassy_traits::spi as traits;
13pub use embedded_hal::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; 19pub use embedded_hal::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3};
20use futures::future::join3;
14 21
15impl WordSize { 22impl WordSize {
16 fn ds(&self) -> spi::vals::Ds { 23 fn ds(&self) -> spi::vals::Ds {
@@ -28,26 +35,30 @@ impl WordSize {
28 } 35 }
29} 36}
30 37
31pub struct Spi<'d, T: Instance> { 38pub struct Spi<'d, T: Instance, Tx, Rx> {
32 sck: AnyPin, 39 sck: AnyPin,
33 mosi: AnyPin, 40 mosi: AnyPin,
34 miso: AnyPin, 41 miso: AnyPin,
42 txdma: Tx,
43 rxdma: Rx,
35 phantom: PhantomData<&'d mut T>, 44 phantom: PhantomData<&'d mut T>,
36} 45}
37 46
38impl<'d, T: Instance> Spi<'d, T> { 47impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
39 pub fn new<F>( 48 pub fn new<F>(
40 _peri: impl Unborrow<Target = T> + 'd, 49 _peri: impl Unborrow<Target = T> + 'd,
41 sck: impl Unborrow<Target = impl SckPin<T>>, 50 sck: impl Unborrow<Target = impl SckPin<T>>,
42 mosi: impl Unborrow<Target = impl MosiPin<T>>, 51 mosi: impl Unborrow<Target = impl MosiPin<T>>,
43 miso: impl Unborrow<Target = impl MisoPin<T>>, 52 miso: impl Unborrow<Target = impl MisoPin<T>>,
53 txdma: impl Unborrow<Target = Tx>,
54 rxdma: impl Unborrow<Target = Rx>,
44 freq: F, 55 freq: F,
45 config: Config, 56 config: Config,
46 ) -> Self 57 ) -> Self
47 where 58 where
48 F: Into<Hertz>, 59 F: Into<Hertz>,
49 { 60 {
50 unborrow!(sck, mosi, miso); 61 unborrow!(sck, mosi, miso, txdma, rxdma);
51 62
52 unsafe { 63 unsafe {
53 Self::configure_pin(sck.block(), sck.pin() as _, sck.af_num()); 64 Self::configure_pin(sck.block(), sck.pin() as _, sck.af_num());
@@ -98,6 +109,8 @@ impl<'d, T: Instance> Spi<'d, T> {
98 sck, 109 sck,
99 mosi, 110 mosi,
100 miso, 111 miso,
112 txdma,
113 rxdma,
101 phantom: PhantomData, 114 phantom: PhantomData,
102 } 115 }
103 } 116 }
@@ -140,9 +153,156 @@ impl<'d, T: Instance> Spi<'d, T> {
140 }); 153 });
141 } 154 }
142 } 155 }
156
157 #[allow(unused)]
158 async fn write_dma_u8(&mut self, write: &[u8]) -> Result<(), Error>
159 where
160 Tx: TxDmaChannel<T>,
161 {
162 unsafe {
163 T::regs().cr1().modify(|w| {
164 w.set_spe(false);
165 });
166 T::regs().cr2().modify(|reg| {
167 reg.set_rxdmaen(true);
168 });
169 }
170 Self::set_word_size(WordSize::EightBit);
171
172 let request = self.txdma.request();
173 let dst = T::regs().dr().ptr() as *mut u8;
174 let f = self.txdma.write(request, write, dst);
175
176 unsafe {
177 T::regs().cr2().modify(|reg| {
178 reg.set_txdmaen(true);
179 });
180 T::regs().cr1().modify(|w| {
181 w.set_spe(true);
182 });
183 }
184
185 f.await;
186 Ok(())
187 }
188
189 #[allow(unused)]
190 async fn read_dma_u8(&mut self, read: &mut [u8]) -> Result<(), Error>
191 where
192 Tx: TxDmaChannel<T>,
193 Rx: RxDmaChannel<T>,
194 {
195 unsafe {
196 T::regs().cr1().modify(|w| {
197 w.set_spe(false);
198 });
199 T::regs().cr2().modify(|reg| {
200 reg.set_rxdmaen(true);
201 });
202 }
203 Self::set_word_size(WordSize::EightBit);
204
205 let clock_byte_count = read.len();
206
207 let rx_request = self.rxdma.request();
208 let rx_src = T::regs().dr().ptr() as *mut u8;
209 let rx_f = self.rxdma.read(rx_request, rx_src, read);
210
211 let tx_request = self.txdma.request();
212 let tx_dst = T::regs().dr().ptr() as *mut u8;
213 let clock_byte = 0x00;
214 let tx_f = self
215 .txdma
216 .write_x(tx_request, &clock_byte, clock_byte_count, tx_dst);
217
218 unsafe {
219 T::regs().cr2().modify(|reg| {
220 reg.set_txdmaen(true);
221 });
222 T::regs().cr1().modify(|w| {
223 w.set_spe(true);
224 });
225 }
226
227 join3(tx_f, rx_f, Self::wait_for_idle()).await;
228
229 unsafe {
230 T::regs().cr2().modify(|reg| {
231 reg.set_txdmaen(false);
232 reg.set_rxdmaen(false);
233 });
234 T::regs().cr1().modify(|w| {
235 w.set_spe(false);
236 });
237 }
238
239 Ok(())
240 }
241
242 #[allow(unused)]
243 async fn read_write_dma_u8(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Error>
244 where
245 Tx: TxDmaChannel<T>,
246 Rx: RxDmaChannel<T>,
247 {
248 unsafe {
249 T::regs().cr1().modify(|w| {
250 w.set_spe(false);
251 });
252 T::regs().cr2().modify(|reg| {
253 reg.set_rxdmaen(true);
254 });
255 }
256 Self::set_word_size(WordSize::EightBit);
257
258 let rx_request = self.rxdma.request();
259 let rx_src = T::regs().dr().ptr() as *mut u8;
260 let rx_f = self.rxdma.read(rx_request, rx_src, read);
261
262 let tx_request = self.txdma.request();
263 let tx_dst = T::regs().dr().ptr() as *mut u8;
264 let tx_f = self.txdma.write(tx_request, write, tx_dst);
265
266 unsafe {
267 T::regs().cr2().modify(|reg| {
268 reg.set_txdmaen(true);
269 });
270 T::regs().cr1().modify(|w| {
271 w.set_spe(true);
272 });
273 }
274
275 join3(tx_f, rx_f, Self::wait_for_idle()).await;
276
277 unsafe {
278 T::regs().cr2().modify(|reg| {
279 reg.set_txdmaen(false);
280 reg.set_rxdmaen(false);
281 });
282 T::regs().cr1().modify(|w| {
283 w.set_spe(false);
284 });
285 }
286
287 Ok(())
288 }
289
290 async fn wait_for_idle() {
291 unsafe {
292 while T::regs().sr().read().ftlvl() > 0 {
293 // spin
294 }
295 while T::regs().sr().read().frlvl() > 0 {
296 // spin
297 }
298 while T::regs().sr().read().bsy() {
299 // spin
300 }
301 }
302 }
143} 303}
144 304
145impl<'d, T: Instance> Drop for Spi<'d, T> { 305impl<'d, T: Instance, Tx, Rx> Drop for Spi<'d, T, Tx, Rx> {
146 fn drop(&mut self) { 306 fn drop(&mut self) {
147 unsafe { 307 unsafe {
148 Self::unconfigure_pin(self.sck.block(), self.sck.pin() as _); 308 Self::unconfigure_pin(self.sck.block(), self.sck.pin() as _);
@@ -200,7 +360,7 @@ fn read_word<W: Word>(regs: &'static crate::pac::spi::Spi) -> Result<W, Error> {
200 } 360 }
201} 361}
202 362
203impl<'d, T: Instance> embedded_hal::blocking::spi::Write<u8> for Spi<'d, T> { 363impl<'d, T: Instance, Rx> embedded_hal::blocking::spi::Write<u8> for Spi<'d, T, NoDma, Rx> {
204 type Error = Error; 364 type Error = Error;
205 365
206 fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> { 366 fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> {
@@ -216,7 +376,7 @@ impl<'d, T: Instance> embedded_hal::blocking::spi::Write<u8> for Spi<'d, T> {
216 } 376 }
217} 377}
218 378
219impl<'d, T: Instance> embedded_hal::blocking::spi::Transfer<u8> for Spi<'d, T> { 379impl<'d, T: Instance> embedded_hal::blocking::spi::Transfer<u8> for Spi<'d, T, NoDma, NoDma> {
220 type Error = Error; 380 type Error = Error;
221 381
222 fn transfer<'w>(&mut self, words: &'w mut [u8]) -> Result<&'w [u8], Self::Error> { 382 fn transfer<'w>(&mut self, words: &'w mut [u8]) -> Result<&'w [u8], Self::Error> {
@@ -232,7 +392,7 @@ impl<'d, T: Instance> embedded_hal::blocking::spi::Transfer<u8> for Spi<'d, T> {
232 } 392 }
233} 393}
234 394
235impl<'d, T: Instance> embedded_hal::blocking::spi::Write<u16> for Spi<'d, T> { 395impl<'d, T: Instance, Rx> embedded_hal::blocking::spi::Write<u16> for Spi<'d, T, NoDma, Rx> {
236 type Error = Error; 396 type Error = Error;
237 397
238 fn write(&mut self, words: &[u16]) -> Result<(), Self::Error> { 398 fn write(&mut self, words: &[u16]) -> Result<(), Self::Error> {
@@ -248,7 +408,7 @@ impl<'d, T: Instance> embedded_hal::blocking::spi::Write<u16> for Spi<'d, T> {
248 } 408 }
249} 409}
250 410
251impl<'d, T: Instance> embedded_hal::blocking::spi::Transfer<u16> for Spi<'d, T> { 411impl<'d, T: Instance> embedded_hal::blocking::spi::Transfer<u16> for Spi<'d, T, NoDma, NoDma> {
252 type Error = Error; 412 type Error = Error;
253 413
254 fn transfer<'w>(&mut self, words: &'w mut [u16]) -> Result<&'w [u16], Self::Error> { 414 fn transfer<'w>(&mut self, words: &'w mut [u16]) -> Result<&'w [u16], Self::Error> {
@@ -263,3 +423,42 @@ impl<'d, T: Instance> embedded_hal::blocking::spi::Transfer<u16> for Spi<'d, T>
263 Ok(words) 423 Ok(words)
264 } 424 }
265} 425}
426
427impl<'d, T: Instance, Tx, Rx> traits::Spi<u8> for Spi<'d, T, Tx, Rx> {
428 type Error = super::Error;
429}
430
431impl<'d, T: Instance, Tx: TxDmaChannel<T>, Rx> traits::Write<u8> for Spi<'d, T, Tx, Rx> {
432 #[rustfmt::skip]
433 type WriteFuture<'a> where Self: 'a = impl Future<Output = Result<(), Self::Error>> + 'a;
434
435 fn write<'a>(&'a mut self, data: &'a [u8]) -> Self::WriteFuture<'a> {
436 self.write_dma_u8(data)
437 }
438}
439
440impl<'d, T: Instance, Tx: TxDmaChannel<T>, Rx: RxDmaChannel<T>> traits::Read<u8>
441 for Spi<'d, T, Tx, Rx>
442{
443 #[rustfmt::skip]
444 type ReadFuture<'a> where Self: 'a = impl Future<Output = Result<(), Self::Error>> + 'a;
445
446 fn read<'a>(&'a mut self, data: &'a mut [u8]) -> Self::ReadFuture<'a> {
447 self.read_dma_u8(data)
448 }
449}
450
451impl<'d, T: Instance, Tx: TxDmaChannel<T>, Rx: RxDmaChannel<T>> traits::FullDuplex<u8>
452 for Spi<'d, T, Tx, Rx>
453{
454 #[rustfmt::skip]
455 type WriteReadFuture<'a> where Self: 'a = impl Future<Output = Result<(), Self::Error>> + 'a;
456
457 fn read_write<'a>(
458 &'a mut self,
459 read: &'a mut [u8],
460 write: &'a [u8],
461 ) -> Self::WriteReadFuture<'a> {
462 self.read_write_dma_u8(read, write)
463 }
464}
diff --git a/embassy-stm32/src/spi/v3.rs b/embassy-stm32/src/spi/v3.rs
index eb8df44ae..fb2a46f3e 100644
--- a/embassy-stm32/src/spi/v3.rs
+++ b/embassy-stm32/src/spi/v3.rs
@@ -201,7 +201,28 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
201 Tx: TxDmaChannel<T>, 201 Tx: TxDmaChannel<T>,
202 Rx: RxDmaChannel<T>, 202 Rx: RxDmaChannel<T>,
203 { 203 {
204 unimplemented!() 204 let clock_byte_count = read.len();
205
206 let rx_request = self.rxdma.request();
207 let rx_src = T::regs().rxdr().ptr() as *mut u8;
208 let rx_f = self.rxdma.read(rx_request, rx_src, read);
209
210 let tx_request = self.txdma.request();
211 let tx_dst = T::regs().txdr().ptr() as *mut u8;
212 let clock_byte = 0x00;
213 let tx_f = self
214 .txdma
215 .write_x(tx_request, &clock_byte, clock_byte_count, tx_dst);
216
217 unsafe {
218 T::regs().cfg1().modify(|reg| {
219 reg.set_txdmaen(true);
220 reg.set_rxdmaen(true);
221 });
222 }
223
224 let r = join(tx_f, rx_f).await;
225 Ok(())
205 } 226 }
206 227
207 #[allow(unused)] 228 #[allow(unused)]
@@ -218,10 +239,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
218 239
219 let tx_request = self.txdma.request(); 240 let tx_request = self.txdma.request();
220 let tx_dst = T::regs().txdr().ptr() as *mut u8; 241 let tx_dst = T::regs().txdr().ptr() as *mut u8;
221 let clock_byte = 0x00; 242 let tx_f = self.txdma.write(tx_request, write, tx_dst);
222 let tx_f = self
223 .txdma
224 .write_x(tx_request, &clock_byte, clock_byte_count, tx_dst);
225 243
226 unsafe { 244 unsafe {
227 T::regs().cfg1().modify(|reg| { 245 T::regs().cfg1().modify(|reg| {
diff --git a/examples/stm32l4/src/bin/spi.rs b/examples/stm32l4/src/bin/spi.rs
index 8702fe0cc..14605283b 100644
--- a/examples/stm32l4/src/bin/spi.rs
+++ b/examples/stm32l4/src/bin/spi.rs
@@ -17,6 +17,7 @@ use embassy_stm32::time::Hertz;
17use embedded_hal::blocking::spi::Transfer; 17use embedded_hal::blocking::spi::Transfer;
18use embedded_hal::digital::v2::OutputPin; 18use embedded_hal::digital::v2::OutputPin;
19use example_common::*; 19use example_common::*;
20use embassy_stm32::dma::NoDma;
20 21
21#[entry] 22#[entry]
22fn main() -> ! { 23fn main() -> ! {
@@ -41,6 +42,8 @@ fn main() -> ! {
41 p.PC10, 42 p.PC10,
42 p.PC12, 43 p.PC12,
43 p.PC11, 44 p.PC11,
45 NoDma,
46 NoDma,
44 Hertz(1_000_000), 47 Hertz(1_000_000),
45 Config::default(), 48 Config::default(),
46 ); 49 );
diff --git a/examples/stm32l4/src/bin/spi_dma.rs b/examples/stm32l4/src/bin/spi_dma.rs
new file mode 100644
index 000000000..ca77c2f9b
--- /dev/null
+++ b/examples/stm32l4/src/bin/spi_dma.rs
@@ -0,0 +1,103 @@
1#![no_std]
2#![no_main]
3#![feature(trait_alias)]
4#![feature(min_type_alias_impl_trait)]
5#![feature(impl_trait_in_bindings)]
6#![feature(type_alias_impl_trait)]
7#![allow(incomplete_features)]
8
9#[path = "../example_common.rs"]
10mod example_common;
11
12use cortex_m_rt::entry;
13use embassy::executor::Executor;
14use embassy::time::Clock;
15use embassy::util::Forever;
16use embassy_stm32::pac;
17use example_common::*;
18use embassy_stm32::spi::{Spi, Config};
19use embassy_traits::spi::FullDuplex;
20use embassy_stm32::time::Hertz;
21use embassy_stm32::gpio::{Output, Level, Speed};
22use embedded_hal::digital::v2::OutputPin;
23
24#[embassy::task]
25async fn main_task() {
26 let p = embassy_stm32::init(Default::default());
27
28 let mut spi = Spi::new(
29 p.SPI3,
30 p.PC10,
31 p.PC12,
32 p.PC11,
33 p.DMA1_CH0,
34 p.DMA1_CH1,
35 Hertz(1_000_000),
36 Config::default(),
37 );
38
39 let mut cs = Output::new(p.PE0, Level::High, Speed::VeryHigh);
40
41 loop {
42 let write = [0x0A; 10];
43 let mut read = [0; 10];
44 unwrap!(cs.set_low());
45 spi.read_write(&mut read, &write).await.ok();
46 unwrap!(cs.set_high());
47 info!("xfer {=[u8]:x}", read);
48 }
49}
50
51struct ZeroClock;
52
53impl Clock for ZeroClock {
54 fn now(&self) -> u64 {
55 0
56 }
57}
58
59static EXECUTOR: Forever<Executor> = Forever::new();
60
61#[entry]
62fn main() -> ! {
63 info!("Hello World!");
64
65 unsafe {
66 pac::DBGMCU.cr().modify(|w| {
67 w.set_dbg_sleep(true);
68 w.set_dbg_standby(true);
69 w.set_dbg_stop(true);
70 });
71
72 //pac::RCC.apbenr().modify(|w| {
73 //w.set_spi3en(true);
74 // });
75
76 pac::RCC.apb2enr().modify(|w| {
77 w.set_syscfgen(true);
78 });
79
80 pac::RCC.ahb1enr().modify(|w| {
81 w.set_dmamux1en(true);
82 w.set_dma1en(true);
83 w.set_dma2en(true);
84 });
85
86 pac::RCC.ahb2enr().modify(|w| {
87 w.set_gpioaen(true);
88 w.set_gpioben(true);
89 w.set_gpiocen(true);
90 w.set_gpioden(true);
91 w.set_gpioeen(true);
92 w.set_gpiofen(true);
93 });
94 }
95
96 unsafe { embassy::time::set_clock(&ZeroClock) };
97
98 let executor = EXECUTOR.put(Executor::new());
99
100 executor.run(|spawner| {
101 unwrap!(spawner.spawn(main_task()));
102 })
103}