aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2021-07-24 09:24:11 +0200
committerGitHub <[email protected]>2021-07-24 09:24:11 +0200
commit9c503a92564aa5fb16ba1c0ffb15d8e3a721b742 (patch)
treec3453fcd15f82b88d2576ea0860f0bdd52cf4a18
parent372884422aab45f9fd09890c85e317cadd71c0d0 (diff)
parent83f63890e59715596093c907c50998d2f1033adb (diff)
Merge pull request #305 from bobmcwhirter/spi_dma_take3
Spi dma take3
-rw-r--r--embassy-nrf/src/spim.rs23
-rw-r--r--embassy-stm32/src/dma/bdma.rs35
-rw-r--r--embassy-stm32/src/dma/dma.rs40
-rw-r--r--embassy-stm32/src/dma/mod.rs8
-rw-r--r--embassy-stm32/src/spi/mod.rs57
-rw-r--r--embassy-stm32/src/spi/v1.rs212
-rw-r--r--embassy-stm32/src/spi/v2.rs218
-rw-r--r--embassy-stm32/src/spi/v3.rs232
-rw-r--r--embassy-traits/src/spi.rs32
-rw-r--r--examples/stm32f4/src/bin/spi.rs3
-rw-r--r--examples/stm32f4/src/bin/spi_dma.rs85
-rw-r--r--examples/stm32h7/src/bin/spi.rs112
-rw-r--r--examples/stm32h7/src/bin/spi_dma.rs109
-rw-r--r--examples/stm32l0/src/bin/spi.rs5
-rw-r--r--examples/stm32l4/src/bin/spi.rs3
-rw-r--r--examples/stm32l4/src/bin/spi_dma.rs116
16 files changed, 1234 insertions, 56 deletions
diff --git a/embassy-nrf/src/spim.rs b/embassy-nrf/src/spim.rs
index 47d7c5f90..221c52051 100644
--- a/embassy-nrf/src/spim.rs
+++ b/embassy-nrf/src/spim.rs
@@ -9,7 +9,7 @@ use embassy::traits;
9use embassy::util::{AtomicWaker, Unborrow}; 9use embassy::util::{AtomicWaker, Unborrow};
10use embassy_extras::unborrow; 10use embassy_extras::unborrow;
11use futures::future::poll_fn; 11use futures::future::poll_fn;
12use traits::spi::FullDuplex; 12use traits::spi::{FullDuplex, Read, Spi, Write};
13 13
14use crate::gpio; 14use crate::gpio;
15use crate::gpio::sealed::Pin as _; 15use crate::gpio::sealed::Pin as _;
@@ -177,22 +177,31 @@ impl<'d, T: Instance> Drop for Spim<'d, T> {
177 } 177 }
178} 178}
179 179
180impl<'d, T: Instance> FullDuplex<u8> for Spim<'d, T> { 180impl<'d, T: Instance> Spi<u8> for Spim<'d, T> {
181 type Error = Error; 181 type Error = Error;
182}
182 183
184impl<'d, T: Instance> Read<u8> for Spim<'d, T> {
183 #[rustfmt::skip] 185 #[rustfmt::skip]
184 type WriteFuture<'a> where Self: 'a = impl Future<Output = Result<(), Self::Error>> + 'a; 186 type ReadFuture<'a> where Self: 'a = impl Future<Output=Result<(), Self::Error>> + 'a;
185 #[rustfmt::skip]
186 type ReadFuture<'a> where Self: 'a = impl Future<Output = Result<(), Self::Error>> + 'a;
187 #[rustfmt::skip]
188 type WriteReadFuture<'a> where Self: 'a = impl Future<Output = Result<(), Self::Error>> + 'a;
189 187
190 fn read<'a>(&'a mut self, data: &'a mut [u8]) -> Self::ReadFuture<'a> { 188 fn read<'a>(&'a mut self, data: &'a mut [u8]) -> Self::ReadFuture<'a> {
191 self.read_write(data, &[]) 189 self.read_write(data, &[])
192 } 190 }
191}
192
193impl<'d, T: Instance> Write<u8> for Spim<'d, T> {
194 #[rustfmt::skip]
195 type WriteFuture<'a> where Self: 'a = impl Future<Output=Result<(), Self::Error>> + 'a;
196
193 fn write<'a>(&'a mut self, data: &'a [u8]) -> Self::WriteFuture<'a> { 197 fn write<'a>(&'a mut self, data: &'a [u8]) -> Self::WriteFuture<'a> {
194 self.read_write(&mut [], data) 198 self.read_write(&mut [], data)
195 } 199 }
200}
201
202impl<'d, T: Instance> FullDuplex<u8> for Spim<'d, T> {
203 #[rustfmt::skip]
204 type WriteReadFuture<'a> where Self: 'a = impl Future<Output = Result<(), Self::Error>> + 'a;
196 205
197 fn read_write<'a>(&'a mut self, rx: &'a mut [u8], tx: &'a [u8]) -> Self::WriteReadFuture<'a> { 206 fn read_write<'a>(&'a mut self, rx: &'a mut [u8], tx: &'a [u8]) -> Self::WriteReadFuture<'a> {
198 async move { 207 async move {
diff --git a/embassy-stm32/src/dma/bdma.rs b/embassy-stm32/src/dma/bdma.rs
index e2da2a8ea..adb288eb0 100644
--- a/embassy-stm32/src/dma/bdma.rs
+++ b/embassy-stm32/src/dma/bdma.rs
@@ -47,6 +47,7 @@ pub(crate) unsafe fn do_transfer(
47 peri_addr: *const u8, 47 peri_addr: *const u8,
48 mem_addr: *mut u8, 48 mem_addr: *mut u8,
49 mem_len: usize, 49 mem_len: usize,
50 incr_mem: bool,
50 #[cfg(dmamux)] dmamux_regs: pac::dmamux::Dmamux, 51 #[cfg(dmamux)] dmamux_regs: pac::dmamux::Dmamux,
51 #[cfg(dmamux)] dmamux_ch_num: u8, 52 #[cfg(dmamux)] dmamux_ch_num: u8,
52) -> impl Future<Output = ()> { 53) -> impl Future<Output = ()> {
@@ -88,7 +89,11 @@ pub(crate) unsafe fn do_transfer(
88 ch.cr().write(|w| { 89 ch.cr().write(|w| {
89 w.set_psize(vals::Size::BITS8); 90 w.set_psize(vals::Size::BITS8);
90 w.set_msize(vals::Size::BITS8); 91 w.set_msize(vals::Size::BITS8);
91 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 }
92 w.set_dir(dir); 97 w.set_dir(dir);
93 w.set_teie(true); 98 w.set_teie(true);
94 w.set_tcie(true); 99 w.set_tcie(true);
@@ -182,6 +187,7 @@ pac::dma_channels! {
182 src, 187 src,
183 buf.as_mut_ptr(), 188 buf.as_mut_ptr(),
184 buf.len(), 189 buf.len(),
190 true,
185 #[cfg(dmamux)] 191 #[cfg(dmamux)]
186 <Self as super::dmamux::sealed::MuxChannel>::DMAMUX_REGS, 192 <Self as super::dmamux::sealed::MuxChannel>::DMAMUX_REGS,
187 #[cfg(dmamux)] 193 #[cfg(dmamux)]
@@ -206,6 +212,33 @@ pac::dma_channels! {
206 dst, 212 dst,
207 buf.as_ptr() as *mut u8, 213 buf.as_ptr() as *mut u8,
208 buf.len(), 214 buf.len(),
215 true,
216 #[cfg(dmamux)]
217 <Self as super::dmamux::sealed::MuxChannel>::DMAMUX_REGS,
218 #[cfg(dmamux)]
219 <Self as super::dmamux::sealed::MuxChannel>::DMAMUX_CH_NUM,
220 )
221 }
222 }
223
224 fn write_x<'a>(
225 &'a mut self,
226 request: Request,
227 word: &u8,
228 count: usize,
229 dst: *mut u8,
230 ) -> Self::WriteFuture<'a> {
231 unsafe {
232 do_transfer(
233 crate::pac::$dma_peri,
234 $channel_num,
235 (dma_num!($dma_peri) * 8) + $channel_num,
236 request,
237 vals::Dir::FROMMEMORY,
238 dst,
239 word as *const u8 as *mut u8,
240 count,
241 false,
209 #[cfg(dmamux)] 242 #[cfg(dmamux)]
210 <Self as super::dmamux::sealed::MuxChannel>::DMAMUX_REGS, 243 <Self as super::dmamux::sealed::MuxChannel>::DMAMUX_REGS,
211 #[cfg(dmamux)] 244 #[cfg(dmamux)]
diff --git a/embassy-stm32/src/dma/dma.rs b/embassy-stm32/src/dma/dma.rs
index cf0889a3e..c5695baca 100644
--- a/embassy-stm32/src/dma/dma.rs
+++ b/embassy-stm32/src/dma/dma.rs
@@ -48,6 +48,7 @@ pub(crate) unsafe fn do_transfer(
48 peri_addr: *const u8, 48 peri_addr: *const u8,
49 mem_addr: *mut u8, 49 mem_addr: *mut u8,
50 mem_len: usize, 50 mem_len: usize,
51 incr_mem: bool,
51 #[cfg(dmamux)] dmamux_regs: pac::dmamux::Dmamux, 52 #[cfg(dmamux)] dmamux_regs: pac::dmamux::Dmamux,
52 #[cfg(dmamux)] dmamux_ch_num: u8, 53 #[cfg(dmamux)] dmamux_ch_num: u8,
53) -> impl Future<Output = ()> { 54) -> impl Future<Output = ()> {
@@ -87,22 +88,27 @@ pub(crate) unsafe fn do_transfer(
87 w.set_dir(dir); 88 w.set_dir(dir);
88 w.set_msize(vals::Size::BITS8); 89 w.set_msize(vals::Size::BITS8);
89 w.set_psize(vals::Size::BITS8); 90 w.set_psize(vals::Size::BITS8);
90 w.set_minc(vals::Inc::INCREMENTED); 91 if incr_mem {
92 w.set_minc(vals::Inc::INCREMENTED);
93 } else {
94 w.set_minc(vals::Inc::FIXED);
95 }
91 w.set_pinc(vals::Inc::FIXED); 96 w.set_pinc(vals::Inc::FIXED);
92 w.set_teie(true); 97 w.set_teie(true);
93 w.set_tcie(true); 98 w.set_tcie(true);
94 #[cfg(dma_v1)] 99 #[cfg(dma_v1)]
95 w.set_trbuff(true); 100 w.set_trbuff(true);
96 w.set_en(true);
97 101
98 #[cfg(dma_v2)] 102 #[cfg(dma_v2)]
99 w.set_chsel(request); 103 w.set_chsel(request);
104
105 w.set_en(true);
100 }); 106 });
101 } 107 }
102 108
103 async move { 109 async move {
104 let res = poll_fn(|cx| { 110 let res = poll_fn(|cx| {
105 let n = channel_number as usize; 111 let n = state_number as usize;
106 STATE.ch_wakers[n].register(cx.waker()); 112 STATE.ch_wakers[n].register(cx.waker());
107 match STATE.ch_status[n].load(Ordering::Acquire) { 113 match STATE.ch_status[n].load(Ordering::Acquire) {
108 CH_STATUS_NONE => Poll::Pending, 114 CH_STATUS_NONE => Poll::Pending,
@@ -187,6 +193,7 @@ pac::dma_channels! {
187 src, 193 src,
188 buf.as_mut_ptr(), 194 buf.as_mut_ptr(),
189 buf.len(), 195 buf.len(),
196 true,
190 #[cfg(dmamux)] 197 #[cfg(dmamux)]
191 <Self as super::dmamux::sealed::MuxChannel>::DMAMUX_REGS, 198 <Self as super::dmamux::sealed::MuxChannel>::DMAMUX_REGS,
192 #[cfg(dmamux)] 199 #[cfg(dmamux)]
@@ -211,6 +218,33 @@ pac::dma_channels! {
211 dst, 218 dst,
212 buf.as_ptr() as *mut u8, 219 buf.as_ptr() as *mut u8,
213 buf.len(), 220 buf.len(),
221 true,
222 #[cfg(dmamux)]
223 <Self as super::dmamux::sealed::MuxChannel>::DMAMUX_REGS,
224 #[cfg(dmamux)]
225 <Self as super::dmamux::sealed::MuxChannel>::DMAMUX_CH_NUM,
226 )
227 }
228 }
229
230 fn write_x<'a>(
231 &'a mut self,
232 request: Request,
233 word: &u8,
234 num: usize,
235 dst: *mut u8,
236 ) -> Self::WriteFuture<'a> {
237 unsafe {
238 do_transfer(
239 crate::pac::$dma_peri,
240 $channel_num,
241 (dma_num!($dma_peri) * 8) + $channel_num,
242 request,
243 vals::Dir::MEMORYTOPERIPHERAL,
244 dst,
245 word as *const u8 as *mut u8,
246 num,
247 false,
214 #[cfg(dmamux)] 248 #[cfg(dmamux)]
215 <Self as super::dmamux::sealed::MuxChannel>::DMAMUX_REGS, 249 <Self as super::dmamux::sealed::MuxChannel>::DMAMUX_REGS,
216 #[cfg(dmamux)] 250 #[cfg(dmamux)]
diff --git a/embassy-stm32/src/dma/mod.rs b/embassy-stm32/src/dma/mod.rs
index fbf82b87b..60f6a3020 100644
--- a/embassy-stm32/src/dma/mod.rs
+++ b/embassy-stm32/src/dma/mod.rs
@@ -42,6 +42,14 @@ pub trait Channel: sealed::Channel {
42 buf: &'a [u8], 42 buf: &'a [u8],
43 dst: *mut u8, 43 dst: *mut u8,
44 ) -> Self::WriteFuture<'a>; 44 ) -> Self::WriteFuture<'a>;
45
46 fn write_x<'a>(
47 &'a mut self,
48 request: Request,
49 word: &u8,
50 num: usize,
51 dst: *mut u8,
52 ) -> Self::WriteFuture<'a>;
45} 53}
46 54
47pub struct NoDma; 55pub struct NoDma;
diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs
index 9b04c03aa..9bb5a729c 100644
--- a/embassy-stm32/src/spi/mod.rs
+++ b/embassy-stm32/src/spi/mod.rs
@@ -4,7 +4,7 @@
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::{peripherals, rcc::RccPeripheral}; 7use crate::{dma, peripherals, rcc::RccPeripheral};
8pub use _version::*; 8pub use _version::*;
9 9
10use crate::gpio::Pin; 10use crate::gpio::Pin;
@@ -62,15 +62,22 @@ pub(crate) mod sealed {
62 pub trait MisoPin<T: Instance>: Pin { 62 pub trait MisoPin<T: Instance>: Pin {
63 fn af_num(&self) -> u8; 63 fn af_num(&self) -> u8;
64 } 64 }
65}
66
67pub trait Instance: sealed::Instance + RccPeripheral + 'static {}
68 65
69pub trait SckPin<T: Instance>: sealed::SckPin<T> + 'static {} 66 pub trait TxDmaChannel<T: Instance> {
67 fn request(&self) -> dma::Request;
68 }
70 69
71pub trait MosiPin<T: Instance>: sealed::MosiPin<T> + 'static {} 70 pub trait RxDmaChannel<T: Instance> {
71 fn request(&self) -> dma::Request;
72 }
73}
72 74
73pub trait MisoPin<T: Instance>: sealed::MisoPin<T> + 'static {} 75pub trait Instance: sealed::Instance + RccPeripheral {}
76pub trait SckPin<T: Instance>: sealed::SckPin<T> {}
77pub trait MosiPin<T: Instance>: sealed::MosiPin<T> {}
78pub trait MisoPin<T: Instance>: sealed::MisoPin<T> {}
79pub trait TxDmaChannel<T: Instance>: sealed::TxDmaChannel<T> + dma::Channel {}
80pub trait RxDmaChannel<T: Instance>: sealed::RxDmaChannel<T> + dma::Channel {}
74 81
75crate::pac::peripherals!( 82crate::pac::peripherals!(
76 (spi, $inst:ident) => { 83 (spi, $inst:ident) => {
@@ -109,3 +116,39 @@ crate::pac::peripheral_pins!(
109 impl_pin!($inst, $pin, MisoPin, $af); 116 impl_pin!($inst, $pin, MisoPin, $af);
110 }; 117 };
111); 118);
119
120macro_rules! impl_dma {
121 ($inst:ident, {dmamux: $dmamux:ident}, $signal:ident, $request:expr) => {
122 impl<T> sealed::$signal<peripherals::$inst> for T
123 where
124 T: crate::dma::MuxChannel<Mux = crate::dma::$dmamux>,
125 {
126 fn request(&self) -> dma::Request {
127 $request
128 }
129 }
130
131 impl<T> $signal<peripherals::$inst> for T where
132 T: crate::dma::MuxChannel<Mux = crate::dma::$dmamux>
133 {
134 }
135 };
136 ($inst:ident, {channel: $channel:ident}, $signal:ident, $request:expr) => {
137 impl sealed::$signal<peripherals::$inst> for peripherals::$channel {
138 fn request(&self) -> dma::Request {
139 $request
140 }
141 }
142
143 impl $signal<peripherals::$inst> for peripherals::$channel {}
144 };
145}
146
147crate::pac::peripheral_dma_channels! {
148 ($peri:ident, spi, $kind:ident, RX, $channel:tt, $request:expr) => {
149 impl_dma!($peri, $channel, RxDmaChannel, $request);
150 };
151 ($peri:ident, spi, $kind:ident, TX, $channel:tt, $request:expr) => {
152 impl_dma!($peri, $channel, TxDmaChannel, $request);
153 };
154}
diff --git a/embassy-stm32/src/spi/v1.rs b/embassy-stm32/src/spi/v1.rs
index 01cbf86b6..43489bb6f 100644
--- a/embassy-stm32/src/spi/v1.rs
+++ b/embassy-stm32/src/spi/v1.rs
@@ -1,14 +1,21 @@
1#![macro_use] 1#![macro_use]
2 2
3use crate::dma::NoDma;
3use crate::gpio::{sealed::Pin, AnyPin}; 4use crate::gpio::{sealed::Pin, AnyPin};
4use crate::pac::spi; 5use crate::pac::spi;
5use crate::spi::{ByteOrder, Config, Error, Instance, MisoPin, MosiPin, SckPin, WordSize}; 6use crate::spi::{
7 ByteOrder, Config, Error, Instance, MisoPin, MosiPin, RxDmaChannel, SckPin, TxDmaChannel,
8 WordSize,
9};
6use crate::time::Hertz; 10use crate::time::Hertz;
11use core::future::Future;
7use core::marker::PhantomData; 12use core::marker::PhantomData;
8use core::ptr; 13use core::ptr;
9use embassy::util::Unborrow; 14use embassy::util::Unborrow;
10use embassy_extras::unborrow; 15use embassy_extras::unborrow;
16use embassy_traits::spi as traits;
11pub use embedded_hal::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; 17pub use embedded_hal::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3};
18use futures::future::join3;
12 19
13impl WordSize { 20impl WordSize {
14 fn dff(&self) -> spi::vals::Dff { 21 fn dff(&self) -> spi::vals::Dff {
@@ -19,27 +26,31 @@ impl WordSize {
19 } 26 }
20} 27}
21 28
22pub struct Spi<'d, T: Instance> { 29pub struct Spi<'d, T: Instance, Tx, Rx> {
23 sck: AnyPin, 30 sck: AnyPin,
24 mosi: AnyPin, 31 mosi: AnyPin,
25 miso: AnyPin, 32 miso: AnyPin,
33 txdma: Tx,
34 rxdma: Rx,
26 current_word_size: WordSize, 35 current_word_size: WordSize,
27 phantom: PhantomData<&'d mut T>, 36 phantom: PhantomData<&'d mut T>,
28} 37}
29 38
30impl<'d, T: Instance> Spi<'d, T> { 39impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
31 pub fn new<F>( 40 pub fn new<F>(
32 _peri: impl Unborrow<Target = T> + 'd, 41 _peri: impl Unborrow<Target = T> + 'd,
33 sck: impl Unborrow<Target = impl SckPin<T>>, 42 sck: impl Unborrow<Target = impl SckPin<T>>,
34 mosi: impl Unborrow<Target = impl MosiPin<T>>, 43 mosi: impl Unborrow<Target = impl MosiPin<T>>,
35 miso: impl Unborrow<Target = impl MisoPin<T>>, 44 miso: impl Unborrow<Target = impl MisoPin<T>>,
45 txdma: impl Unborrow<Target = Tx>,
46 rxdma: impl Unborrow<Target = Rx>,
36 freq: F, 47 freq: F,
37 config: Config, 48 config: Config,
38 ) -> Self 49 ) -> Self
39 where 50 where
40 F: Into<Hertz>, 51 F: Into<Hertz>,
41 { 52 {
42 unborrow!(sck, mosi, miso); 53 unborrow!(sck, mosi, miso, txdma, rxdma);
43 54
44 unsafe { 55 unsafe {
45 sck.set_as_af(sck.af_num()); 56 sck.set_as_af(sck.af_num());
@@ -94,6 +105,8 @@ impl<'d, T: Instance> Spi<'d, T> {
94 sck, 105 sck,
95 mosi, 106 mosi,
96 miso, 107 miso,
108 txdma,
109 rxdma,
97 current_word_size: WordSize::EightBit, 110 current_word_size: WordSize::EightBit,
98 phantom: PhantomData, 111 phantom: PhantomData,
99 } 112 }
@@ -128,9 +141,151 @@ impl<'d, T: Instance> Spi<'d, T> {
128 self.current_word_size = word_size; 141 self.current_word_size = word_size;
129 } 142 }
130 } 143 }
144
145 #[allow(unused)]
146 async fn write_dma_u8(&mut self, write: &[u8]) -> Result<(), Error>
147 where
148 Tx: TxDmaChannel<T>,
149 {
150 unsafe {
151 T::regs().cr1().modify(|w| {
152 w.set_spe(false);
153 });
154 }
155 self.set_word_size(WordSize::EightBit);
156
157 let request = self.txdma.request();
158 let dst = T::regs().dr().ptr() as *mut u8;
159 let f = self.txdma.write(request, write, dst);
160
161 unsafe {
162 T::regs().cr2().modify(|reg| {
163 reg.set_txdmaen(true);
164 });
165 T::regs().cr1().modify(|w| {
166 w.set_spe(true);
167 });
168 }
169
170 f.await;
171 Ok(())
172 }
173
174 #[allow(unused)]
175 async fn read_dma_u8(&mut self, read: &mut [u8]) -> Result<(), Error>
176 where
177 Tx: TxDmaChannel<T>,
178 Rx: RxDmaChannel<T>,
179 {
180 unsafe {
181 T::regs().cr1().modify(|w| {
182 w.set_spe(false);
183 });
184 T::regs().cr2().modify(|reg| {
185 reg.set_rxdmaen(true);
186 });
187 }
188 self.set_word_size(WordSize::EightBit);
189
190 let clock_byte_count = read.len();
191
192 let rx_request = self.rxdma.request();
193 let rx_src = T::regs().dr().ptr() as *mut u8;
194 let rx_f = self.rxdma.read(rx_request, rx_src, read);
195
196 let tx_request = self.txdma.request();
197 let tx_dst = T::regs().dr().ptr() as *mut u8;
198 let clock_byte = 0x00;
199 let tx_f = self
200 .txdma
201 .write_x(tx_request, &clock_byte, clock_byte_count, tx_dst);
202
203 unsafe {
204 T::regs().cr2().modify(|reg| {
205 reg.set_txdmaen(true);
206 });
207 T::regs().cr1().modify(|w| {
208 w.set_spe(true);
209 });
210 }
211
212 join3(tx_f, rx_f, Self::wait_for_idle()).await;
213
214 unsafe {
215 T::regs().cr2().modify(|reg| {
216 reg.set_txdmaen(false);
217 reg.set_rxdmaen(false);
218 });
219 T::regs().cr1().modify(|w| {
220 w.set_spe(false);
221 });
222 }
223
224 Ok(())
225 }
226
227 #[allow(unused)]
228 async fn read_write_dma_u8(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Error>
229 where
230 Tx: TxDmaChannel<T>,
231 Rx: RxDmaChannel<T>,
232 {
233 assert!(read.len() >= write.len());
234
235 unsafe {
236 T::regs().cr1().modify(|w| {
237 w.set_spe(false);
238 });
239 T::regs().cr2().modify(|reg| {
240 reg.set_rxdmaen(true);
241 });
242 }
243 self.set_word_size(WordSize::EightBit);
244
245 let rx_request = self.rxdma.request();
246 let rx_src = T::regs().dr().ptr() as *mut u8;
247 let rx_f = self
248 .rxdma
249 .read(rx_request, rx_src, &mut read[0..write.len()]);
250
251 let tx_request = self.txdma.request();
252 let tx_dst = T::regs().dr().ptr() as *mut u8;
253 let tx_f = self.txdma.write(tx_request, write, tx_dst);
254
255 unsafe {
256 T::regs().cr2().modify(|reg| {
257 reg.set_txdmaen(true);
258 });
259 T::regs().cr1().modify(|w| {
260 w.set_spe(true);
261 });
262 }
263
264 join3(tx_f, rx_f, Self::wait_for_idle()).await;
265
266 unsafe {
267 T::regs().cr2().modify(|reg| {
268 reg.set_txdmaen(false);
269 reg.set_rxdmaen(false);
270 });
271 T::regs().cr1().modify(|w| {
272 w.set_spe(false);
273 });
274 }
275
276 Ok(())
277 }
278
279 async fn wait_for_idle() {
280 unsafe {
281 while T::regs().sr().read().bsy() {
282 // spin
283 }
284 }
285 }
131} 286}
132 287
133impl<'d, T: Instance> Drop for Spi<'d, T> { 288impl<'d, T: Instance, Tx, Rx> Drop for Spi<'d, T, Tx, Rx> {
134 fn drop(&mut self) { 289 fn drop(&mut self) {
135 unsafe { 290 unsafe {
136 self.sck.set_as_analog(); 291 self.sck.set_as_analog();
@@ -140,7 +295,7 @@ impl<'d, T: Instance> Drop for Spi<'d, T> {
140 } 295 }
141} 296}
142 297
143impl<'d, T: Instance> embedded_hal::blocking::spi::Write<u8> for Spi<'d, T> { 298impl<'d, T: Instance> embedded_hal::blocking::spi::Write<u8> for Spi<'d, T, NoDma, NoDma> {
144 type Error = Error; 299 type Error = Error;
145 300
146 fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> { 301 fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> {
@@ -176,7 +331,7 @@ impl<'d, T: Instance> embedded_hal::blocking::spi::Write<u8> for Spi<'d, T> {
176 } 331 }
177} 332}
178 333
179impl<'d, T: Instance> embedded_hal::blocking::spi::Transfer<u8> for Spi<'d, T> { 334impl<'d, T: Instance> embedded_hal::blocking::spi::Transfer<u8> for Spi<'d, T, NoDma, NoDma> {
180 type Error = Error; 335 type Error = Error;
181 336
182 fn transfer<'w>(&mut self, words: &'w mut [u8]) -> Result<&'w [u8], Self::Error> { 337 fn transfer<'w>(&mut self, words: &'w mut [u8]) -> Result<&'w [u8], Self::Error> {
@@ -217,7 +372,7 @@ impl<'d, T: Instance> embedded_hal::blocking::spi::Transfer<u8> for Spi<'d, T> {
217 } 372 }
218} 373}
219 374
220impl<'d, T: Instance> embedded_hal::blocking::spi::Write<u16> for Spi<'d, T> { 375impl<'d, T: Instance> embedded_hal::blocking::spi::Write<u16> for Spi<'d, T, NoDma, NoDma> {
221 type Error = Error; 376 type Error = Error;
222 377
223 fn write(&mut self, words: &[u16]) -> Result<(), Self::Error> { 378 fn write(&mut self, words: &[u16]) -> Result<(), Self::Error> {
@@ -253,7 +408,7 @@ impl<'d, T: Instance> embedded_hal::blocking::spi::Write<u16> for Spi<'d, T> {
253 } 408 }
254} 409}
255 410
256impl<'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> {
257 type Error = Error; 412 type Error = Error;
258 413
259 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> {
@@ -291,3 +446,42 @@ impl<'d, T: Instance> embedded_hal::blocking::spi::Transfer<u16> for Spi<'d, T>
291 Ok(words) 446 Ok(words)
292 } 447 }
293} 448}
449
450impl<'d, T: Instance, Tx, Rx> traits::Spi<u8> for Spi<'d, T, Tx, Rx> {
451 type Error = super::Error;
452}
453
454impl<'d, T: Instance, Tx: TxDmaChannel<T>, Rx> traits::Write<u8> for Spi<'d, T, Tx, Rx> {
455 #[rustfmt::skip]
456 type WriteFuture<'a> where Self: 'a = impl Future<Output = Result<(), Self::Error>> + 'a;
457
458 fn write<'a>(&'a mut self, data: &'a [u8]) -> Self::WriteFuture<'a> {
459 self.write_dma_u8(data)
460 }
461}
462
463impl<'d, T: Instance, Tx: TxDmaChannel<T>, Rx: RxDmaChannel<T>> traits::Read<u8>
464 for Spi<'d, T, Tx, Rx>
465{
466 #[rustfmt::skip]
467 type ReadFuture<'a> where Self: 'a = impl Future<Output = Result<(), Self::Error>> + 'a;
468
469 fn read<'a>(&'a mut self, data: &'a mut [u8]) -> Self::ReadFuture<'a> {
470 self.read_dma_u8(data)
471 }
472}
473
474impl<'d, T: Instance, Tx: TxDmaChannel<T>, Rx: RxDmaChannel<T>> traits::FullDuplex<u8>
475 for Spi<'d, T, Tx, Rx>
476{
477 #[rustfmt::skip]
478 type WriteReadFuture<'a> where Self: 'a = impl Future<Output=Result<(), Self::Error>> + 'a;
479
480 fn read_write<'a>(
481 &'a mut self,
482 read: &'a mut [u8],
483 write: &'a [u8],
484 ) -> Self::WriteReadFuture<'a> {
485 self.read_write_dma_u8(read, write)
486 }
487}
diff --git a/embassy-stm32/src/spi/v2.rs b/embassy-stm32/src/spi/v2.rs
index 4e135e9df..2144dfcc8 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,157 @@ 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 }
167 Self::set_word_size(WordSize::EightBit);
168
169 let request = self.txdma.request();
170 let dst = T::regs().dr().ptr() as *mut u8;
171 let f = self.txdma.write(request, write, dst);
172
173 unsafe {
174 T::regs().cr2().modify(|reg| {
175 reg.set_txdmaen(true);
176 });
177 T::regs().cr1().modify(|w| {
178 w.set_spe(true);
179 });
180 }
181
182 f.await;
183 Ok(())
184 }
185
186 #[allow(unused)]
187 async fn read_dma_u8(&mut self, read: &mut [u8]) -> Result<(), Error>
188 where
189 Tx: TxDmaChannel<T>,
190 Rx: RxDmaChannel<T>,
191 {
192 unsafe {
193 T::regs().cr1().modify(|w| {
194 w.set_spe(false);
195 });
196 T::regs().cr2().modify(|reg| {
197 reg.set_rxdmaen(true);
198 });
199 }
200 Self::set_word_size(WordSize::EightBit);
201
202 let clock_byte_count = read.len();
203
204 let rx_request = self.rxdma.request();
205 let rx_src = T::regs().dr().ptr() as *mut u8;
206 let rx_f = self.rxdma.read(rx_request, rx_src, read);
207
208 let tx_request = self.txdma.request();
209 let tx_dst = T::regs().dr().ptr() as *mut u8;
210 let clock_byte = 0x00;
211 let tx_f = self
212 .txdma
213 .write_x(tx_request, &clock_byte, clock_byte_count, tx_dst);
214
215 unsafe {
216 T::regs().cr2().modify(|reg| {
217 reg.set_txdmaen(true);
218 });
219 T::regs().cr1().modify(|w| {
220 w.set_spe(true);
221 });
222 }
223
224 join3(tx_f, rx_f, Self::wait_for_idle()).await;
225
226 unsafe {
227 T::regs().cr2().modify(|reg| {
228 reg.set_txdmaen(false);
229 reg.set_rxdmaen(false);
230 });
231 T::regs().cr1().modify(|w| {
232 w.set_spe(false);
233 });
234 }
235
236 Ok(())
237 }
238
239 #[allow(unused)]
240 async fn read_write_dma_u8(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Error>
241 where
242 Tx: TxDmaChannel<T>,
243 Rx: RxDmaChannel<T>,
244 {
245 assert!(read.len() >= write.len());
246
247 unsafe {
248 T::regs().cr1().modify(|w| {
249 w.set_spe(false);
250 });
251 T::regs().cr2().modify(|reg| {
252 reg.set_rxdmaen(true);
253 });
254 }
255 Self::set_word_size(WordSize::EightBit);
256
257 let rx_request = self.rxdma.request();
258 let rx_src = T::regs().dr().ptr() as *mut u8;
259 let rx_f = self
260 .rxdma
261 .read(rx_request, rx_src, &mut read[0..write.len()]);
262
263 let tx_request = self.txdma.request();
264 let tx_dst = T::regs().dr().ptr() as *mut u8;
265 let tx_f = self.txdma.write(tx_request, write, tx_dst);
266
267 unsafe {
268 T::regs().cr2().modify(|reg| {
269 reg.set_txdmaen(true);
270 });
271 T::regs().cr1().modify(|w| {
272 w.set_spe(true);
273 });
274 }
275
276 join3(tx_f, rx_f, Self::wait_for_idle()).await;
277
278 unsafe {
279 T::regs().cr2().modify(|reg| {
280 reg.set_txdmaen(false);
281 reg.set_rxdmaen(false);
282 });
283 T::regs().cr1().modify(|w| {
284 w.set_spe(false);
285 });
286 }
287
288 Ok(())
289 }
290
291 async fn wait_for_idle() {
292 unsafe {
293 while T::regs().sr().read().ftlvl() > 0 {
294 // spin
295 }
296 while T::regs().sr().read().frlvl() > 0 {
297 // spin
298 }
299 while T::regs().sr().read().bsy() {
300 // spin
301 }
302 }
303 }
143} 304}
144 305
145impl<'d, T: Instance> Drop for Spi<'d, T> { 306impl<'d, T: Instance, Tx, Rx> Drop for Spi<'d, T, Tx, Rx> {
146 fn drop(&mut self) { 307 fn drop(&mut self) {
147 unsafe { 308 unsafe {
148 Self::unconfigure_pin(self.sck.block(), self.sck.pin() as _); 309 Self::unconfigure_pin(self.sck.block(), self.sck.pin() as _);
@@ -200,7 +361,7 @@ fn read_word<W: Word>(regs: &'static crate::pac::spi::Spi) -> Result<W, Error> {
200 } 361 }
201} 362}
202 363
203impl<'d, T: Instance> embedded_hal::blocking::spi::Write<u8> for Spi<'d, T> { 364impl<'d, T: Instance, Rx> embedded_hal::blocking::spi::Write<u8> for Spi<'d, T, NoDma, Rx> {
204 type Error = Error; 365 type Error = Error;
205 366
206 fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> { 367 fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> {
@@ -216,7 +377,7 @@ impl<'d, T: Instance> embedded_hal::blocking::spi::Write<u8> for Spi<'d, T> {
216 } 377 }
217} 378}
218 379
219impl<'d, T: Instance> embedded_hal::blocking::spi::Transfer<u8> for Spi<'d, T> { 380impl<'d, T: Instance> embedded_hal::blocking::spi::Transfer<u8> for Spi<'d, T, NoDma, NoDma> {
220 type Error = Error; 381 type Error = Error;
221 382
222 fn transfer<'w>(&mut self, words: &'w mut [u8]) -> Result<&'w [u8], Self::Error> { 383 fn transfer<'w>(&mut self, words: &'w mut [u8]) -> Result<&'w [u8], Self::Error> {
@@ -232,7 +393,7 @@ impl<'d, T: Instance> embedded_hal::blocking::spi::Transfer<u8> for Spi<'d, T> {
232 } 393 }
233} 394}
234 395
235impl<'d, T: Instance> embedded_hal::blocking::spi::Write<u16> for Spi<'d, T> { 396impl<'d, T: Instance, Rx> embedded_hal::blocking::spi::Write<u16> for Spi<'d, T, NoDma, Rx> {
236 type Error = Error; 397 type Error = Error;
237 398
238 fn write(&mut self, words: &[u16]) -> Result<(), Self::Error> { 399 fn write(&mut self, words: &[u16]) -> Result<(), Self::Error> {
@@ -248,7 +409,7 @@ impl<'d, T: Instance> embedded_hal::blocking::spi::Write<u16> for Spi<'d, T> {
248 } 409 }
249} 410}
250 411
251impl<'d, T: Instance> embedded_hal::blocking::spi::Transfer<u16> for Spi<'d, T> { 412impl<'d, T: Instance> embedded_hal::blocking::spi::Transfer<u16> for Spi<'d, T, NoDma, NoDma> {
252 type Error = Error; 413 type Error = Error;
253 414
254 fn transfer<'w>(&mut self, words: &'w mut [u16]) -> Result<&'w [u16], Self::Error> { 415 fn transfer<'w>(&mut self, words: &'w mut [u16]) -> Result<&'w [u16], Self::Error> {
@@ -263,3 +424,42 @@ impl<'d, T: Instance> embedded_hal::blocking::spi::Transfer<u16> for Spi<'d, T>
263 Ok(words) 424 Ok(words)
264 } 425 }
265} 426}
427
428impl<'d, T: Instance, Tx, Rx> traits::Spi<u8> for Spi<'d, T, Tx, Rx> {
429 type Error = super::Error;
430}
431
432impl<'d, T: Instance, Tx: TxDmaChannel<T>, Rx> traits::Write<u8> for Spi<'d, T, Tx, Rx> {
433 #[rustfmt::skip]
434 type WriteFuture<'a> where Self: 'a = impl Future<Output = Result<(), Self::Error>> + 'a;
435
436 fn write<'a>(&'a mut self, data: &'a [u8]) -> Self::WriteFuture<'a> {
437 self.write_dma_u8(data)
438 }
439}
440
441impl<'d, T: Instance, Tx: TxDmaChannel<T>, Rx: RxDmaChannel<T>> traits::Read<u8>
442 for Spi<'d, T, Tx, Rx>
443{
444 #[rustfmt::skip]
445 type ReadFuture<'a> where Self: 'a = impl Future<Output = Result<(), Self::Error>> + 'a;
446
447 fn read<'a>(&'a mut self, data: &'a mut [u8]) -> Self::ReadFuture<'a> {
448 self.read_dma_u8(data)
449 }
450}
451
452impl<'d, T: Instance, Tx: TxDmaChannel<T>, Rx: RxDmaChannel<T>> traits::FullDuplex<u8>
453 for Spi<'d, T, Tx, Rx>
454{
455 #[rustfmt::skip]
456 type WriteReadFuture<'a> where Self: 'a = impl Future<Output = Result<(), Self::Error>> + 'a;
457
458 fn read_write<'a>(
459 &'a mut self,
460 read: &'a mut [u8],
461 write: &'a [u8],
462 ) -> Self::WriteReadFuture<'a> {
463 self.read_write_dma_u8(read, write)
464 }
465}
diff --git a/embassy-stm32/src/spi/v3.rs b/embassy-stm32/src/spi/v3.rs
index 0b4a71457..f433d7f9c 100644
--- a/embassy-stm32/src/spi/v3.rs
+++ b/embassy-stm32/src/spi/v3.rs
@@ -1,17 +1,25 @@
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};
14 20
21use futures::future::join3;
22
15impl WordSize { 23impl WordSize {
16 fn dsize(&self) -> u8 { 24 fn dsize(&self) -> u8 {
17 match self { 25 match self {
@@ -28,26 +36,31 @@ impl WordSize {
28 } 36 }
29} 37}
30 38
31pub struct Spi<'d, T: Instance> { 39#[allow(unused)]
40pub struct Spi<'d, T: Instance, Tx = NoDma, Rx = NoDma> {
32 sck: AnyPin, 41 sck: AnyPin,
33 mosi: AnyPin, 42 mosi: AnyPin,
34 miso: AnyPin, 43 miso: AnyPin,
44 txdma: Tx,
45 rxdma: Rx,
35 phantom: PhantomData<&'d mut T>, 46 phantom: PhantomData<&'d mut T>,
36} 47}
37 48
38impl<'d, T: Instance> Spi<'d, T> { 49impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
39 pub fn new<F>( 50 pub fn new<F>(
40 _peri: impl Unborrow<Target = T> + 'd, 51 _peri: impl Unborrow<Target = T> + 'd,
41 sck: impl Unborrow<Target = impl SckPin<T>>, 52 sck: impl Unborrow<Target = impl SckPin<T>>,
42 mosi: impl Unborrow<Target = impl MosiPin<T>>, 53 mosi: impl Unborrow<Target = impl MosiPin<T>>,
43 miso: impl Unborrow<Target = impl MisoPin<T>>, 54 miso: impl Unborrow<Target = impl MisoPin<T>>,
55 txdma: impl Unborrow<Target = Tx>,
56 rxdma: impl Unborrow<Target = Rx>,
44 freq: F, 57 freq: F,
45 config: Config, 58 config: Config,
46 ) -> Self 59 ) -> Self
47 where 60 where
48 F: Into<Hertz>, 61 F: Into<Hertz>,
49 { 62 {
50 unborrow!(sck, mosi, miso); 63 unborrow!(sck, mosi, miso, txdma, rxdma);
51 64
52 unsafe { 65 unsafe {
53 Self::configure_pin(sck.block(), sck.pin() as _, sck.af_num()); 66 Self::configure_pin(sck.block(), sck.pin() as _, sck.af_num());
@@ -97,7 +110,6 @@ impl<'d, T: Instance> Spi<'d, T> {
97 w.set_crcen(false); 110 w.set_crcen(false);
98 w.set_mbr(spi::vals::Mbr(br)); 111 w.set_mbr(spi::vals::Mbr(br));
99 w.set_dsize(WordSize::EightBit.dsize()); 112 w.set_dsize(WordSize::EightBit.dsize());
100 //w.set_fthlv(WordSize::EightBit.frxth());
101 }); 113 });
102 T::regs().cr2().modify(|w| { 114 T::regs().cr2().modify(|w| {
103 w.set_tsize(0); 115 w.set_tsize(0);
@@ -113,6 +125,8 @@ impl<'d, T: Instance> Spi<'d, T> {
113 sck, 125 sck,
114 mosi, 126 mosi,
115 miso, 127 miso,
128 txdma,
129 rxdma,
116 phantom: PhantomData, 130 phantom: PhantomData,
117 } 131 }
118 } 132 }
@@ -161,9 +175,168 @@ impl<'d, T: Instance> Spi<'d, T> {
161 }); 175 });
162 } 176 }
163 } 177 }
178
179 #[allow(unused)]
180 async fn write_dma_u8(&mut self, write: &[u8]) -> Result<(), Error>
181 where
182 Tx: TxDmaChannel<T>,
183 {
184 Self::set_word_size(WordSize::EightBit);
185 unsafe {
186 T::regs().cr1().modify(|w| {
187 w.set_spe(false);
188 });
189 }
190
191 let request = self.txdma.request();
192 let dst = T::regs().txdr().ptr() as *mut u8;
193 let f = self.txdma.write(request, write, dst);
194
195 unsafe {
196 T::regs().cfg1().modify(|reg| {
197 reg.set_txdmaen(true);
198 });
199 T::regs().cr1().modify(|w| {
200 w.set_spe(true);
201 });
202 T::regs().cr1().modify(|w| {
203 w.set_cstart(true);
204 });
205 }
206
207 f.await;
208 unsafe {
209 T::regs().cfg1().modify(|reg| {
210 reg.set_txdmaen(false);
211 });
212 T::regs().cr1().modify(|w| {
213 w.set_spe(false);
214 });
215 }
216
217 Ok(())
218 }
219
220 #[allow(unused)]
221 async fn read_dma_u8(&mut self, read: &mut [u8]) -> Result<(), Error>
222 where
223 Tx: TxDmaChannel<T>,
224 Rx: RxDmaChannel<T>,
225 {
226 Self::set_word_size(WordSize::EightBit);
227 unsafe {
228 T::regs().cr1().modify(|w| {
229 w.set_spe(false);
230 });
231 T::regs().cfg1().modify(|reg| {
232 reg.set_rxdmaen(true);
233 });
234 }
235
236 let clock_byte_count = read.len();
237
238 let rx_request = self.rxdma.request();
239 let rx_src = T::regs().rxdr().ptr() as *mut u8;
240 let rx_f = self.rxdma.read(rx_request, rx_src, read);
241
242 let tx_request = self.txdma.request();
243 let tx_dst = T::regs().txdr().ptr() as *mut u8;
244 let clock_byte = 0x00;
245 let tx_f = self
246 .txdma
247 .write_x(tx_request, &clock_byte, clock_byte_count, tx_dst);
248
249 unsafe {
250 T::regs().cfg1().modify(|reg| {
251 reg.set_txdmaen(true);
252 });
253 T::regs().cr1().modify(|w| {
254 w.set_spe(true);
255 });
256 T::regs().cr1().modify(|w| {
257 w.set_cstart(true);
258 });
259 }
260
261 join3(tx_f, rx_f, Self::wait_for_idle()).await;
262 unsafe {
263 T::regs().cfg1().modify(|reg| {
264 reg.set_rxdmaen(false);
265 reg.set_txdmaen(false);
266 });
267 T::regs().cr1().modify(|w| {
268 w.set_spe(false);
269 });
270 }
271 Ok(())
272 }
273
274 #[allow(unused)]
275 async fn read_write_dma_u8(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Error>
276 where
277 Tx: TxDmaChannel<T>,
278 Rx: RxDmaChannel<T>,
279 {
280 assert!(read.len() >= write.len());
281
282 Self::set_word_size(WordSize::EightBit);
283 unsafe {
284 T::regs().cr1().modify(|w| {
285 w.set_spe(false);
286 });
287 T::regs().cfg1().modify(|reg| {
288 reg.set_rxdmaen(true);
289 });
290 }
291
292 let rx_request = self.rxdma.request();
293 let rx_src = T::regs().rxdr().ptr() as *mut u8;
294 let rx_f = self
295 .rxdma
296 .read(rx_request, rx_src, &mut read[0..write.len()]);
297
298 let tx_request = self.txdma.request();
299 let tx_dst = T::regs().txdr().ptr() as *mut u8;
300 let tx_f = self.txdma.write(tx_request, write, tx_dst);
301
302 unsafe {
303 T::regs().cfg1().modify(|reg| {
304 reg.set_txdmaen(true);
305 });
306 T::regs().cr1().modify(|w| {
307 w.set_spe(true);
308 });
309 T::regs().cr1().modify(|w| {
310 w.set_cstart(true);
311 });
312 }
313
314 join3(tx_f, rx_f, Self::wait_for_idle()).await;
315 unsafe {
316 T::regs().cfg1().modify(|reg| {
317 reg.set_rxdmaen(false);
318 reg.set_txdmaen(false);
319 });
320 T::regs().cr1().modify(|w| {
321 w.set_spe(false);
322 });
323 }
324 Ok(())
325 }
326
327 async fn wait_for_idle() {
328 unsafe {
329 while !T::regs().sr().read().txc() {
330 // spin
331 }
332 while T::regs().sr().read().rxplvl().0 > 0 {
333 // spin
334 }
335 }
336 }
164} 337}
165 338
166impl<'d, T: Instance> Drop for Spi<'d, T> { 339impl<'d, T: Instance, Tx, Rx> Drop for Spi<'d, T, Tx, Rx> {
167 fn drop(&mut self) { 340 fn drop(&mut self) {
168 unsafe { 341 unsafe {
169 Self::unconfigure_pin(self.sck.block(), self.sck.pin() as _); 342 Self::unconfigure_pin(self.sck.block(), self.sck.pin() as _);
@@ -173,7 +346,7 @@ impl<'d, T: Instance> Drop for Spi<'d, T> {
173 } 346 }
174} 347}
175 348
176impl<'d, T: Instance> embedded_hal::blocking::spi::Write<u8> for Spi<'d, T> { 349impl<'d, T: Instance> embedded_hal::blocking::spi::Write<u8> for Spi<'d, T, NoDma> {
177 type Error = Error; 350 type Error = Error;
178 351
179 fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> { 352 fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> {
@@ -210,7 +383,7 @@ impl<'d, T: Instance> embedded_hal::blocking::spi::Write<u8> for Spi<'d, T> {
210 } 383 }
211} 384}
212 385
213impl<'d, T: Instance> embedded_hal::blocking::spi::Transfer<u8> for Spi<'d, T> { 386impl<'d, T: Instance> embedded_hal::blocking::spi::Transfer<u8> for Spi<'d, T, NoDma> {
214 type Error = Error; 387 type Error = Error;
215 388
216 fn transfer<'w>(&mut self, words: &'w mut [u8]) -> Result<&'w [u8], Self::Error> { 389 fn transfer<'w>(&mut self, words: &'w mut [u8]) -> Result<&'w [u8], Self::Error> {
@@ -267,7 +440,7 @@ impl<'d, T: Instance> embedded_hal::blocking::spi::Transfer<u8> for Spi<'d, T> {
267 } 440 }
268} 441}
269 442
270impl<'d, T: Instance> embedded_hal::blocking::spi::Write<u16> for Spi<'d, T> { 443impl<'d, T: Instance> embedded_hal::blocking::spi::Write<u16> for Spi<'d, T, NoDma> {
271 type Error = Error; 444 type Error = Error;
272 445
273 fn write(&mut self, words: &[u16]) -> Result<(), Self::Error> { 446 fn write(&mut self, words: &[u16]) -> Result<(), Self::Error> {
@@ -304,7 +477,7 @@ impl<'d, T: Instance> embedded_hal::blocking::spi::Write<u16> for Spi<'d, T> {
304 } 477 }
305} 478}
306 479
307impl<'d, T: Instance> embedded_hal::blocking::spi::Transfer<u16> for Spi<'d, T> { 480impl<'d, T: Instance> embedded_hal::blocking::spi::Transfer<u16> for Spi<'d, T, NoDma> {
308 type Error = Error; 481 type Error = Error;
309 482
310 fn transfer<'w>(&mut self, words: &'w mut [u16]) -> Result<&'w [u16], Self::Error> { 483 fn transfer<'w>(&mut self, words: &'w mut [u16]) -> Result<&'w [u16], Self::Error> {
@@ -357,3 +530,42 @@ impl<'d, T: Instance> embedded_hal::blocking::spi::Transfer<u16> for Spi<'d, T>
357 Ok(words) 530 Ok(words)
358 } 531 }
359} 532}
533
534impl<'d, T: Instance, Tx, Rx> traits::Spi<u8> for Spi<'d, T, Tx, Rx> {
535 type Error = super::Error;
536}
537
538impl<'d, T: Instance, Tx: TxDmaChannel<T>, Rx> traits::Write<u8> for Spi<'d, T, Tx, Rx> {
539 #[rustfmt::skip]
540 type WriteFuture<'a> where Self: 'a = impl Future<Output = Result<(), Self::Error>> + 'a;
541
542 fn write<'a>(&'a mut self, data: &'a [u8]) -> Self::WriteFuture<'a> {
543 self.write_dma_u8(data)
544 }
545}
546
547impl<'d, T: Instance, Tx: TxDmaChannel<T>, Rx: RxDmaChannel<T>> traits::Read<u8>
548 for Spi<'d, T, Tx, Rx>
549{
550 #[rustfmt::skip]
551 type ReadFuture<'a> where Self: 'a = impl Future<Output = Result<(), Self::Error>> + 'a;
552
553 fn read<'a>(&'a mut self, data: &'a mut [u8]) -> Self::ReadFuture<'a> {
554 self.read_dma_u8(data)
555 }
556}
557
558impl<'d, T: Instance, Tx: TxDmaChannel<T>, Rx: RxDmaChannel<T>> traits::FullDuplex<u8>
559 for Spi<'d, T, Tx, Rx>
560{
561 #[rustfmt::skip]
562 type WriteReadFuture<'a> where Self: 'a = impl Future<Output = Result<(), Self::Error>> + 'a;
563
564 fn read_write<'a>(
565 &'a mut self,
566 read: &'a mut [u8],
567 write: &'a [u8],
568 ) -> Self::WriteReadFuture<'a> {
569 self.read_write_dma_u8(read, write)
570 }
571}
diff --git a/embassy-traits/src/spi.rs b/embassy-traits/src/spi.rs
index 227b8bfea..04322dddc 100644
--- a/embassy-traits/src/spi.rs
+++ b/embassy-traits/src/spi.rs
@@ -18,25 +18,39 @@ use core::future::Future;
18/// 18///
19/// - Some SPIs can work with 8-bit *and* 16-bit words. You can overload this trait with different 19/// - Some SPIs can work with 8-bit *and* 16-bit words. You can overload this trait with different
20/// `Word` types to allow operation in both modes. 20/// `Word` types to allow operation in both modes.
21pub trait FullDuplex<Word> { 21
22pub trait Spi<Word> {
22 /// An enumeration of SPI errors 23 /// An enumeration of SPI errors
23 type Error; 24 type Error;
25}
24 26
25 type WriteFuture<'a>: Future<Output = Result<(), Self::Error>> + 'a 27pub trait FullDuplex<Word>: Spi<Word> + Write<Word> + Read<Word> {
26 where
27 Self: 'a;
28 type ReadFuture<'a>: Future<Output = Result<(), Self::Error>> + 'a
29 where
30 Self: 'a;
31 type WriteReadFuture<'a>: Future<Output = Result<(), Self::Error>> + 'a 28 type WriteReadFuture<'a>: Future<Output = Result<(), Self::Error>> + 'a
32 where 29 where
33 Self: 'a; 30 Self: 'a;
34 31
35 fn read<'a>(&'a mut self, data: &'a mut [Word]) -> Self::ReadFuture<'a>; 32 /// The `read` array must be at least as long as the `write` array,
36 fn write<'a>(&'a mut self, data: &'a [Word]) -> Self::WriteFuture<'a>; 33 /// but is guaranteed to only be filled with bytes equal to the
34 /// length of the `write` array.
37 fn read_write<'a>( 35 fn read_write<'a>(
38 &'a mut self, 36 &'a mut self,
39 read: &'a mut [Word], 37 read: &'a mut [Word],
40 write: &'a [Word], 38 write: &'a [Word],
41 ) -> Self::WriteReadFuture<'a>; 39 ) -> Self::WriteReadFuture<'a>;
42} 40}
41
42pub trait Write<Word>: Spi<Word> {
43 type WriteFuture<'a>: Future<Output = Result<(), Self::Error>> + 'a
44 where
45 Self: 'a;
46
47 fn write<'a>(&'a mut self, data: &'a [Word]) -> Self::WriteFuture<'a>;
48}
49
50pub trait Read<Word>: Write<Word> {
51 type ReadFuture<'a>: Future<Output = Result<(), Self::Error>> + 'a
52 where
53 Self: 'a;
54
55 fn read<'a>(&'a mut self, data: &'a mut [Word]) -> Self::ReadFuture<'a>;
56}
diff --git a/examples/stm32f4/src/bin/spi.rs b/examples/stm32f4/src/bin/spi.rs
index 88fc84bc0..604283877 100644
--- a/examples/stm32f4/src/bin/spi.rs
+++ b/examples/stm32f4/src/bin/spi.rs
@@ -18,6 +18,7 @@ use embassy_stm32::dbgmcu::Dbgmcu;
18use embassy_stm32::spi::{Config, Spi}; 18use embassy_stm32::spi::{Config, Spi};
19use embassy_stm32::time::Hertz; 19use embassy_stm32::time::Hertz;
20use embedded_hal::blocking::spi::Transfer; 20use embedded_hal::blocking::spi::Transfer;
21use embassy_stm32::dma::NoDma;
21 22
22#[entry] 23#[entry]
23fn main() -> ! { 24fn main() -> ! {
@@ -34,6 +35,8 @@ fn main() -> ! {
34 p.PC10, 35 p.PC10,
35 p.PC12, 36 p.PC12,
36 p.PC11, 37 p.PC11,
38 NoDma,
39 NoDma,
37 Hertz(1_000_000), 40 Hertz(1_000_000),
38 Config::default(), 41 Config::default(),
39 ); 42 );
diff --git a/examples/stm32f4/src/bin/spi_dma.rs b/examples/stm32f4/src/bin/spi_dma.rs
new file mode 100644
index 000000000..10a419fda
--- /dev/null
+++ b/examples/stm32f4/src/bin/spi_dma.rs
@@ -0,0 +1,85 @@
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;
11use core::fmt::Write;
12use cortex_m_rt::entry;
13use embassy::executor::Executor;
14use embassy::time::Clock;
15use embassy::util::Forever;
16use example_common::*;
17use embassy_traits::spi::FullDuplex;
18use heapless::String;
19use embassy_stm32::spi::{Spi, Config};
20use embassy_stm32::pac;
21use embassy_stm32::time::Hertz;
22use core::str::from_utf8;
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.SPI1,
30 p.PB3,
31 p.PB5,
32 p.PB4,
33 p.DMA2_CH3,
34 p.DMA2_CH2,
35 Hertz(1_000_000),
36 Config::default(),
37 );
38
39 for n in 0u32.. {
40 let mut write: String<128> = String::new();
41 let mut read = [0;128];
42 core::write!(&mut write, "Hello DMA World {}!\r\n", n).unwrap();
43 spi.read_write(&mut read[0..write.len()], write.as_bytes()).await.ok();
44 info!("read via spi+dma: {}", from_utf8(&read).unwrap());
45 }
46}
47
48struct ZeroClock;
49
50impl Clock for ZeroClock {
51 fn now(&self) -> u64 {
52 0
53 }
54}
55
56static EXECUTOR: Forever<Executor> = Forever::new();
57
58#[entry]
59fn main() -> ! {
60 info!("Hello World!");
61 unsafe {
62 pac::DBGMCU.cr().modify(|w| {
63 w.set_dbg_sleep(true);
64 w.set_dbg_standby(true);
65 w.set_dbg_stop(true);
66 });
67
68 pac::RCC.ahb1enr().modify(|w| {
69 w.set_gpioaen(true);
70 w.set_gpioben(true);
71 w.set_gpiocen(true);
72 w.set_gpioden(true);
73 w.set_gpioeen(true);
74 w.set_gpiofen(true);
75 });
76 }
77
78 unsafe { embassy::time::set_clock(&ZeroClock) };
79
80 let executor = EXECUTOR.put(Executor::new());
81
82 executor.run(|spawner| {
83 unwrap!(spawner.spawn(main_task()));
84 })
85}
diff --git a/examples/stm32h7/src/bin/spi.rs b/examples/stm32h7/src/bin/spi.rs
new file mode 100644
index 000000000..ac483a311
--- /dev/null
+++ b/examples/stm32h7/src/bin/spi.rs
@@ -0,0 +1,112 @@
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 core::fmt::Write;
13use embassy::executor::Executor;
14use embassy::time::Clock;
15use embassy::util::Forever;
16use embassy_stm32::dma::NoDma;
17use example_common::*;
18use embedded_hal::blocking::spi::Transfer;
19
20use hal::prelude::*;
21use stm32h7xx_hal as hal;
22
23use cortex_m_rt::entry;
24use stm32h7::stm32h743 as pac;
25use heapless::String;
26use embassy_stm32::spi::{Spi, Config};
27use embassy_stm32::time::Hertz;
28
29#[embassy::task]
30async fn main_task() {
31 let p = embassy_stm32::init(Default::default());
32
33 let mut spi = Spi::new(
34 p.SPI3,
35 p.PB3,
36 p.PB5,
37 p.PB4,
38 NoDma,
39 NoDma,
40 Hertz(1_000_000),
41 Config::default(),
42 );
43
44 for n in 0u32.. {
45 let mut write: String<128> = String::new();
46 core::write!(&mut write, "Hello DMA World {}!\r\n", n).unwrap();
47 unsafe {
48 let result = spi.transfer(write.as_bytes_mut());
49 if let Err(_) = result {
50 defmt::panic!("crap");
51 }
52 }
53 info!("read via spi: {}", write.as_bytes());
54 }
55}
56
57struct ZeroClock;
58
59impl Clock for ZeroClock {
60 fn now(&self) -> u64 {
61 0
62 }
63}
64
65static EXECUTOR: Forever<Executor> = Forever::new();
66
67#[entry]
68fn main() -> ! {
69 info!("Hello World!");
70
71 let pp = pac::Peripherals::take().unwrap();
72
73 let pwrcfg = pp.PWR.constrain().freeze();
74
75 let rcc = pp.RCC.constrain();
76
77 rcc.sys_ck(96.mhz())
78 .pclk1(48.mhz())
79 .pclk2(48.mhz())
80 .pclk3(48.mhz())
81 .pclk4(48.mhz())
82 .pll1_q_ck(48.mhz())
83 .freeze(pwrcfg, &pp.SYSCFG);
84
85 let pp = unsafe { pac::Peripherals::steal() };
86
87 pp.DBGMCU.cr.modify(|_, w| {
88 w.dbgsleep_d1().set_bit();
89 w.dbgstby_d1().set_bit();
90 w.dbgstop_d1().set_bit();
91 w.d1dbgcken().set_bit();
92 w
93 });
94
95 pp.RCC.ahb4enr.modify(|_, w| {
96 w.gpioaen().set_bit();
97 w.gpioben().set_bit();
98 w.gpiocen().set_bit();
99 w.gpioden().set_bit();
100 w.gpioeen().set_bit();
101 w.gpiofen().set_bit();
102 w
103 });
104
105 unsafe { embassy::time::set_clock(&ZeroClock) };
106
107 let executor = EXECUTOR.put(Executor::new());
108
109 executor.run(|spawner| {
110 unwrap!(spawner.spawn(main_task()));
111 })
112}
diff --git a/examples/stm32h7/src/bin/spi_dma.rs b/examples/stm32h7/src/bin/spi_dma.rs
new file mode 100644
index 000000000..9dbfd0960
--- /dev/null
+++ b/examples/stm32h7/src/bin/spi_dma.rs
@@ -0,0 +1,109 @@
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;
11use core::fmt::Write;
12use embassy::executor::Executor;
13use embassy::time::Clock;
14use embassy::util::Forever;
15use example_common::*;
16use embassy_traits::spi::FullDuplex;
17
18use hal::prelude::*;
19use stm32h7xx_hal as hal;
20
21use cortex_m_rt::entry;
22use stm32h7::stm32h743 as pac;
23use heapless::String;
24use embassy_stm32::spi::{Spi, Config};
25use embassy_stm32::time::Hertz;
26use core::str::from_utf8;
27
28#[embassy::task]
29async fn main_task() {
30 let p = embassy_stm32::init(Default::default());
31
32 let mut spi = Spi::new(
33 p.SPI3,
34 p.PB3,
35 p.PB5,
36 p.PB4,
37 p.DMA1_CH3,
38 p.DMA1_CH4,
39 Hertz(1_000_000),
40 Config::default(),
41 );
42
43 for n in 0u32.. {
44 let mut write: String<128> = String::new();
45 let mut read = [0;128];
46 core::write!(&mut write, "Hello DMA World {}!\r\n", n).unwrap();
47 // read_write will slice the &mut read down to &write's actual length.
48 spi.read_write(&mut read, write.as_bytes()).await.ok();
49 info!("read via spi+dma: {}", from_utf8(&read).unwrap());
50 }
51
52}
53
54struct ZeroClock;
55
56impl Clock for ZeroClock {
57 fn now(&self) -> u64 {
58 0
59 }
60}
61
62static EXECUTOR: Forever<Executor> = Forever::new();
63
64#[entry]
65fn main() -> ! {
66 info!("Hello World!");
67
68 let pp = pac::Peripherals::take().unwrap();
69
70 let pwrcfg = pp.PWR.constrain().freeze();
71
72 let rcc = pp.RCC.constrain();
73
74 rcc.sys_ck(96.mhz())
75 .pclk1(48.mhz())
76 .pclk2(48.mhz())
77 .pclk3(48.mhz())
78 .pclk4(48.mhz())
79 .pll1_q_ck(48.mhz())
80 .freeze(pwrcfg, &pp.SYSCFG);
81
82 let pp = unsafe { pac::Peripherals::steal() };
83
84 pp.DBGMCU.cr.modify(|_, w| {
85 w.dbgsleep_d1().set_bit();
86 w.dbgstby_d1().set_bit();
87 w.dbgstop_d1().set_bit();
88 w.d1dbgcken().set_bit();
89 w
90 });
91
92 pp.RCC.ahb4enr.modify(|_, w| {
93 w.gpioaen().set_bit();
94 w.gpioben().set_bit();
95 w.gpiocen().set_bit();
96 w.gpioden().set_bit();
97 w.gpioeen().set_bit();
98 w.gpiofen().set_bit();
99 w
100 });
101
102 unsafe { embassy::time::set_clock(&ZeroClock) };
103
104 let executor = EXECUTOR.put(Executor::new());
105
106 executor.run(|spawner| {
107 unwrap!(spawner.spawn(main_task()));
108 })
109}
diff --git a/examples/stm32l0/src/bin/spi.rs b/examples/stm32l0/src/bin/spi.rs
index 9bb9b741e..5290906ef 100644
--- a/examples/stm32l0/src/bin/spi.rs
+++ b/examples/stm32l0/src/bin/spi.rs
@@ -18,10 +18,11 @@ use embassy_stm32::rcc;
18use embassy_stm32::spi::{Config, Spi}; 18use embassy_stm32::spi::{Config, Spi};
19use embassy_stm32::time::Hertz; 19use embassy_stm32::time::Hertz;
20use embedded_hal::blocking::spi::Transfer; 20use embedded_hal::blocking::spi::Transfer;
21use embassy_stm32::dma::NoDma;
21 22
22#[entry] 23#[entry]
23fn main() -> ! { 24fn main() -> ! {
24 info!("Hello World, dude!"); 25 info!("Hello World, folks!");
25 26
26 let mut p = embassy_stm32::init(Default::default()); 27 let mut p = embassy_stm32::init(Default::default());
27 let mut rcc = rcc::Rcc::new(p.RCC); 28 let mut rcc = rcc::Rcc::new(p.RCC);
@@ -32,6 +33,8 @@ fn main() -> ! {
32 p.PB3, 33 p.PB3,
33 p.PA7, 34 p.PA7,
34 p.PA6, 35 p.PA6,
36 NoDma,
37 NoDma,
35 Hertz(1_000_000), 38 Hertz(1_000_000),
36 Config::default(), 39 Config::default(),
37 ); 40 );
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..ba03ff44e
--- /dev/null
+++ b/examples/stm32l4/src/bin/spi_dma.rs
@@ -0,0 +1,116 @@
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, Input, Pull};
22use embedded_hal::digital::v2::{OutputPin, InputPin};
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
40 // These are the pins for the Inventek eS-Wifi SPI Wifi Adapter.
41
42 let _boot = Output::new(p.PB12, Level::Low, Speed::VeryHigh);
43 let _wake = Output::new(p.PB13, Level::Low, Speed::VeryHigh);
44 let mut reset = Output::new(p.PE8, Level::Low, Speed::VeryHigh);
45 let mut cs = Output::new(p.PE0, Level::High, Speed::VeryHigh);
46 let ready = Input::new(p.PE1, Pull::Up);
47
48 cortex_m::asm::delay(100_000);
49 reset.set_high().unwrap();
50 cortex_m::asm::delay(100_000);
51
52 while ready.is_low().unwrap() {
53 info!("waiting for ready");
54 }
55
56 let write = [0x0A; 10];
57 let mut read = [0; 10];
58 unwrap!(cs.set_low());
59 spi.read_write(&mut read, &write).await.ok();
60 unwrap!(cs.set_high());
61 info!("xfer {=[u8]:x}", read);
62}
63
64struct ZeroClock;
65
66impl Clock for ZeroClock {
67 fn now(&self) -> u64 {
68 0
69 }
70}
71
72static EXECUTOR: Forever<Executor> = Forever::new();
73
74#[entry]
75fn main() -> ! {
76 info!("Hello World!");
77
78 unsafe {
79 pac::DBGMCU.cr().modify(|w| {
80 w.set_dbg_sleep(true);
81 w.set_dbg_standby(true);
82 w.set_dbg_stop(true);
83 });
84
85 //pac::RCC.apbenr().modify(|w| {
86 //w.set_spi3en(true);
87 // });
88
89 pac::RCC.apb2enr().modify(|w| {
90 w.set_syscfgen(true);
91 });
92
93 pac::RCC.ahb1enr().modify(|w| {
94 w.set_dmamux1en(true);
95 w.set_dma1en(true);
96 w.set_dma2en(true);
97 });
98
99 pac::RCC.ahb2enr().modify(|w| {
100 w.set_gpioaen(true);
101 w.set_gpioben(true);
102 w.set_gpiocen(true);
103 w.set_gpioden(true);
104 w.set_gpioeen(true);
105 w.set_gpiofen(true);
106 });
107 }
108
109 unsafe { embassy::time::set_clock(&ZeroClock) };
110
111 let executor = EXECUTOR.put(Executor::new());
112
113 executor.run(|spawner| {
114 unwrap!(spawner.spawn(main_task()));
115 })
116}