diff options
| author | Dario Nieuwenhuis <[email protected]> | 2021-07-24 09:24:11 +0200 |
|---|---|---|
| committer | GitHub <[email protected]> | 2021-07-24 09:24:11 +0200 |
| commit | 9c503a92564aa5fb16ba1c0ffb15d8e3a721b742 (patch) | |
| tree | c3453fcd15f82b88d2576ea0860f0bdd52cf4a18 | |
| parent | 372884422aab45f9fd09890c85e317cadd71c0d0 (diff) | |
| parent | 83f63890e59715596093c907c50998d2f1033adb (diff) | |
Merge pull request #305 from bobmcwhirter/spi_dma_take3
Spi dma take3
| -rw-r--r-- | embassy-nrf/src/spim.rs | 23 | ||||
| -rw-r--r-- | embassy-stm32/src/dma/bdma.rs | 35 | ||||
| -rw-r--r-- | embassy-stm32/src/dma/dma.rs | 40 | ||||
| -rw-r--r-- | embassy-stm32/src/dma/mod.rs | 8 | ||||
| -rw-r--r-- | embassy-stm32/src/spi/mod.rs | 57 | ||||
| -rw-r--r-- | embassy-stm32/src/spi/v1.rs | 212 | ||||
| -rw-r--r-- | embassy-stm32/src/spi/v2.rs | 218 | ||||
| -rw-r--r-- | embassy-stm32/src/spi/v3.rs | 232 | ||||
| -rw-r--r-- | embassy-traits/src/spi.rs | 32 | ||||
| -rw-r--r-- | examples/stm32f4/src/bin/spi.rs | 3 | ||||
| -rw-r--r-- | examples/stm32f4/src/bin/spi_dma.rs | 85 | ||||
| -rw-r--r-- | examples/stm32h7/src/bin/spi.rs | 112 | ||||
| -rw-r--r-- | examples/stm32h7/src/bin/spi_dma.rs | 109 | ||||
| -rw-r--r-- | examples/stm32l0/src/bin/spi.rs | 5 | ||||
| -rw-r--r-- | examples/stm32l4/src/bin/spi.rs | 3 | ||||
| -rw-r--r-- | examples/stm32l4/src/bin/spi_dma.rs | 116 |
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; | |||
| 9 | use embassy::util::{AtomicWaker, Unborrow}; | 9 | use embassy::util::{AtomicWaker, Unborrow}; |
| 10 | use embassy_extras::unborrow; | 10 | use embassy_extras::unborrow; |
| 11 | use futures::future::poll_fn; | 11 | use futures::future::poll_fn; |
| 12 | use traits::spi::FullDuplex; | 12 | use traits::spi::{FullDuplex, Read, Spi, Write}; |
| 13 | 13 | ||
| 14 | use crate::gpio; | 14 | use crate::gpio; |
| 15 | use crate::gpio::sealed::Pin as _; | 15 | use crate::gpio::sealed::Pin as _; |
| @@ -177,22 +177,31 @@ impl<'d, T: Instance> Drop for Spim<'d, T> { | |||
| 177 | } | 177 | } |
| 178 | } | 178 | } |
| 179 | 179 | ||
| 180 | impl<'d, T: Instance> FullDuplex<u8> for Spim<'d, T> { | 180 | impl<'d, T: Instance> Spi<u8> for Spim<'d, T> { |
| 181 | type Error = Error; | 181 | type Error = Error; |
| 182 | } | ||
| 182 | 183 | ||
| 184 | impl<'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 | |||
| 193 | impl<'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 | |||
| 202 | impl<'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 | ||
| 47 | pub struct NoDma; | 55 | pub 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")] |
| 6 | mod _version; | 6 | mod _version; |
| 7 | use crate::{peripherals, rcc::RccPeripheral}; | 7 | use crate::{dma, peripherals, rcc::RccPeripheral}; |
| 8 | pub use _version::*; | 8 | pub use _version::*; |
| 9 | 9 | ||
| 10 | use crate::gpio::Pin; | 10 | use 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 | |||
| 67 | pub trait Instance: sealed::Instance + RccPeripheral + 'static {} | ||
| 68 | 65 | ||
| 69 | pub trait SckPin<T: Instance>: sealed::SckPin<T> + 'static {} | 66 | pub trait TxDmaChannel<T: Instance> { |
| 67 | fn request(&self) -> dma::Request; | ||
| 68 | } | ||
| 70 | 69 | ||
| 71 | pub trait MosiPin<T: Instance>: sealed::MosiPin<T> + 'static {} | 70 | pub trait RxDmaChannel<T: Instance> { |
| 71 | fn request(&self) -> dma::Request; | ||
| 72 | } | ||
| 73 | } | ||
| 72 | 74 | ||
| 73 | pub trait MisoPin<T: Instance>: sealed::MisoPin<T> + 'static {} | 75 | pub trait Instance: sealed::Instance + RccPeripheral {} |
| 76 | pub trait SckPin<T: Instance>: sealed::SckPin<T> {} | ||
| 77 | pub trait MosiPin<T: Instance>: sealed::MosiPin<T> {} | ||
| 78 | pub trait MisoPin<T: Instance>: sealed::MisoPin<T> {} | ||
| 79 | pub trait TxDmaChannel<T: Instance>: sealed::TxDmaChannel<T> + dma::Channel {} | ||
| 80 | pub trait RxDmaChannel<T: Instance>: sealed::RxDmaChannel<T> + dma::Channel {} | ||
| 74 | 81 | ||
| 75 | crate::pac::peripherals!( | 82 | crate::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 | |||
| 120 | macro_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 | |||
| 147 | crate::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 | ||
| 3 | use crate::dma::NoDma; | ||
| 3 | use crate::gpio::{sealed::Pin, AnyPin}; | 4 | use crate::gpio::{sealed::Pin, AnyPin}; |
| 4 | use crate::pac::spi; | 5 | use crate::pac::spi; |
| 5 | use crate::spi::{ByteOrder, Config, Error, Instance, MisoPin, MosiPin, SckPin, WordSize}; | 6 | use crate::spi::{ |
| 7 | ByteOrder, Config, Error, Instance, MisoPin, MosiPin, RxDmaChannel, SckPin, TxDmaChannel, | ||
| 8 | WordSize, | ||
| 9 | }; | ||
| 6 | use crate::time::Hertz; | 10 | use crate::time::Hertz; |
| 11 | use core::future::Future; | ||
| 7 | use core::marker::PhantomData; | 12 | use core::marker::PhantomData; |
| 8 | use core::ptr; | 13 | use core::ptr; |
| 9 | use embassy::util::Unborrow; | 14 | use embassy::util::Unborrow; |
| 10 | use embassy_extras::unborrow; | 15 | use embassy_extras::unborrow; |
| 16 | use embassy_traits::spi as traits; | ||
| 11 | pub use embedded_hal::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; | 17 | pub use embedded_hal::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; |
| 18 | use futures::future::join3; | ||
| 12 | 19 | ||
| 13 | impl WordSize { | 20 | impl 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 | ||
| 22 | pub struct Spi<'d, T: Instance> { | 29 | pub 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 | ||
| 30 | impl<'d, T: Instance> Spi<'d, T> { | 39 | impl<'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 | ||
| 133 | impl<'d, T: Instance> Drop for Spi<'d, T> { | 288 | impl<'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 | ||
| 143 | impl<'d, T: Instance> embedded_hal::blocking::spi::Write<u8> for Spi<'d, T> { | 298 | impl<'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 | ||
| 179 | impl<'d, T: Instance> embedded_hal::blocking::spi::Transfer<u8> for Spi<'d, T> { | 334 | impl<'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 | ||
| 220 | impl<'d, T: Instance> embedded_hal::blocking::spi::Write<u16> for Spi<'d, T> { | 375 | impl<'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 | ||
| 256 | impl<'d, T: Instance> embedded_hal::blocking::spi::Transfer<u16> for Spi<'d, T> { | 411 | impl<'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 | |||
| 450 | impl<'d, T: Instance, Tx, Rx> traits::Spi<u8> for Spi<'d, T, Tx, Rx> { | ||
| 451 | type Error = super::Error; | ||
| 452 | } | ||
| 453 | |||
| 454 | impl<'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 | |||
| 463 | impl<'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 | |||
| 474 | impl<'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 | ||
| 3 | use crate::dma::NoDma; | ||
| 3 | use crate::gpio::{AnyPin, Pin}; | 4 | use crate::gpio::{AnyPin, Pin}; |
| 4 | use crate::pac::gpio::vals::{Afr, Moder}; | 5 | use crate::pac::gpio::vals::{Afr, Moder}; |
| 5 | use crate::pac::gpio::Gpio; | 6 | use crate::pac::gpio::Gpio; |
| 6 | use crate::pac::spi; | 7 | use crate::pac::spi; |
| 7 | use crate::spi::{ByteOrder, Config, Error, Instance, MisoPin, MosiPin, SckPin, WordSize}; | 8 | use crate::spi::{ |
| 9 | ByteOrder, Config, Error, Instance, MisoPin, MosiPin, RxDmaChannel, SckPin, TxDmaChannel, | ||
| 10 | WordSize, | ||
| 11 | }; | ||
| 8 | use crate::time::Hertz; | 12 | use crate::time::Hertz; |
| 13 | use core::future::Future; | ||
| 9 | use core::marker::PhantomData; | 14 | use core::marker::PhantomData; |
| 10 | use core::ptr; | 15 | use core::ptr; |
| 11 | use embassy::util::Unborrow; | 16 | use embassy::util::Unborrow; |
| 12 | use embassy_extras::unborrow; | 17 | use embassy_extras::unborrow; |
| 18 | use embassy_traits::spi as traits; | ||
| 13 | pub use embedded_hal::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; | 19 | pub use embedded_hal::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; |
| 20 | use futures::future::join3; | ||
| 14 | 21 | ||
| 15 | impl WordSize { | 22 | impl 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 | ||
| 31 | pub struct Spi<'d, T: Instance> { | 38 | pub 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 | ||
| 38 | impl<'d, T: Instance> Spi<'d, T> { | 47 | impl<'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 | ||
| 145 | impl<'d, T: Instance> Drop for Spi<'d, T> { | 306 | impl<'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 | ||
| 203 | impl<'d, T: Instance> embedded_hal::blocking::spi::Write<u8> for Spi<'d, T> { | 364 | impl<'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 | ||
| 219 | impl<'d, T: Instance> embedded_hal::blocking::spi::Transfer<u8> for Spi<'d, T> { | 380 | impl<'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 | ||
| 235 | impl<'d, T: Instance> embedded_hal::blocking::spi::Write<u16> for Spi<'d, T> { | 396 | impl<'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 | ||
| 251 | impl<'d, T: Instance> embedded_hal::blocking::spi::Transfer<u16> for Spi<'d, T> { | 412 | impl<'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 | |||
| 428 | impl<'d, T: Instance, Tx, Rx> traits::Spi<u8> for Spi<'d, T, Tx, Rx> { | ||
| 429 | type Error = super::Error; | ||
| 430 | } | ||
| 431 | |||
| 432 | impl<'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 | |||
| 441 | impl<'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 | |||
| 452 | impl<'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 | ||
| 3 | use crate::dma::NoDma; | ||
| 3 | use crate::gpio::{AnyPin, Pin}; | 4 | use crate::gpio::{AnyPin, Pin}; |
| 4 | use crate::pac::gpio::vals::{Afr, Moder}; | 5 | use crate::pac::gpio::vals::{Afr, Moder}; |
| 5 | use crate::pac::gpio::Gpio; | 6 | use crate::pac::gpio::Gpio; |
| 6 | use crate::pac::spi; | 7 | use crate::pac::spi; |
| 7 | use crate::spi::{ByteOrder, Config, Error, Instance, MisoPin, MosiPin, SckPin, WordSize}; | 8 | use crate::spi::{ |
| 9 | ByteOrder, Config, Error, Instance, MisoPin, MosiPin, RxDmaChannel, SckPin, TxDmaChannel, | ||
| 10 | WordSize, | ||
| 11 | }; | ||
| 8 | use crate::time::Hertz; | 12 | use crate::time::Hertz; |
| 13 | use core::future::Future; | ||
| 9 | use core::marker::PhantomData; | 14 | use core::marker::PhantomData; |
| 10 | use core::ptr; | 15 | use core::ptr; |
| 11 | use embassy::util::Unborrow; | 16 | use embassy::util::Unborrow; |
| 12 | use embassy_extras::unborrow; | 17 | use embassy_extras::unborrow; |
| 18 | use embassy_traits::spi as traits; | ||
| 13 | pub use embedded_hal::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; | 19 | pub use embedded_hal::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; |
| 14 | 20 | ||
| 21 | use futures::future::join3; | ||
| 22 | |||
| 15 | impl WordSize { | 23 | impl 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 | ||
| 31 | pub struct Spi<'d, T: Instance> { | 39 | #[allow(unused)] |
| 40 | pub 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 | ||
| 38 | impl<'d, T: Instance> Spi<'d, T> { | 49 | impl<'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 | ||
| 166 | impl<'d, T: Instance> Drop for Spi<'d, T> { | 339 | impl<'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 | ||
| 176 | impl<'d, T: Instance> embedded_hal::blocking::spi::Write<u8> for Spi<'d, T> { | 349 | impl<'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 | ||
| 213 | impl<'d, T: Instance> embedded_hal::blocking::spi::Transfer<u8> for Spi<'d, T> { | 386 | impl<'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 | ||
| 270 | impl<'d, T: Instance> embedded_hal::blocking::spi::Write<u16> for Spi<'d, T> { | 443 | impl<'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 | ||
| 307 | impl<'d, T: Instance> embedded_hal::blocking::spi::Transfer<u16> for Spi<'d, T> { | 480 | impl<'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 | |||
| 534 | impl<'d, T: Instance, Tx, Rx> traits::Spi<u8> for Spi<'d, T, Tx, Rx> { | ||
| 535 | type Error = super::Error; | ||
| 536 | } | ||
| 537 | |||
| 538 | impl<'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 | |||
| 547 | impl<'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 | |||
| 558 | impl<'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. |
| 21 | pub trait FullDuplex<Word> { | 21 | |
| 22 | pub 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 | 27 | pub 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 | |||
| 42 | pub 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 | |||
| 50 | pub 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; | |||
| 18 | use embassy_stm32::spi::{Config, Spi}; | 18 | use embassy_stm32::spi::{Config, Spi}; |
| 19 | use embassy_stm32::time::Hertz; | 19 | use embassy_stm32::time::Hertz; |
| 20 | use embedded_hal::blocking::spi::Transfer; | 20 | use embedded_hal::blocking::spi::Transfer; |
| 21 | use embassy_stm32::dma::NoDma; | ||
| 21 | 22 | ||
| 22 | #[entry] | 23 | #[entry] |
| 23 | fn main() -> ! { | 24 | fn 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"] | ||
| 10 | mod example_common; | ||
| 11 | use core::fmt::Write; | ||
| 12 | use cortex_m_rt::entry; | ||
| 13 | use embassy::executor::Executor; | ||
| 14 | use embassy::time::Clock; | ||
| 15 | use embassy::util::Forever; | ||
| 16 | use example_common::*; | ||
| 17 | use embassy_traits::spi::FullDuplex; | ||
| 18 | use heapless::String; | ||
| 19 | use embassy_stm32::spi::{Spi, Config}; | ||
| 20 | use embassy_stm32::pac; | ||
| 21 | use embassy_stm32::time::Hertz; | ||
| 22 | use core::str::from_utf8; | ||
| 23 | |||
| 24 | #[embassy::task] | ||
| 25 | async 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 | |||
| 48 | struct ZeroClock; | ||
| 49 | |||
| 50 | impl Clock for ZeroClock { | ||
| 51 | fn now(&self) -> u64 { | ||
| 52 | 0 | ||
| 53 | } | ||
| 54 | } | ||
| 55 | |||
| 56 | static EXECUTOR: Forever<Executor> = Forever::new(); | ||
| 57 | |||
| 58 | #[entry] | ||
| 59 | fn 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"] | ||
| 10 | mod example_common; | ||
| 11 | |||
| 12 | use core::fmt::Write; | ||
| 13 | use embassy::executor::Executor; | ||
| 14 | use embassy::time::Clock; | ||
| 15 | use embassy::util::Forever; | ||
| 16 | use embassy_stm32::dma::NoDma; | ||
| 17 | use example_common::*; | ||
| 18 | use embedded_hal::blocking::spi::Transfer; | ||
| 19 | |||
| 20 | use hal::prelude::*; | ||
| 21 | use stm32h7xx_hal as hal; | ||
| 22 | |||
| 23 | use cortex_m_rt::entry; | ||
| 24 | use stm32h7::stm32h743 as pac; | ||
| 25 | use heapless::String; | ||
| 26 | use embassy_stm32::spi::{Spi, Config}; | ||
| 27 | use embassy_stm32::time::Hertz; | ||
| 28 | |||
| 29 | #[embassy::task] | ||
| 30 | async 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 | |||
| 57 | struct ZeroClock; | ||
| 58 | |||
| 59 | impl Clock for ZeroClock { | ||
| 60 | fn now(&self) -> u64 { | ||
| 61 | 0 | ||
| 62 | } | ||
| 63 | } | ||
| 64 | |||
| 65 | static EXECUTOR: Forever<Executor> = Forever::new(); | ||
| 66 | |||
| 67 | #[entry] | ||
| 68 | fn 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"] | ||
| 10 | mod example_common; | ||
| 11 | use core::fmt::Write; | ||
| 12 | use embassy::executor::Executor; | ||
| 13 | use embassy::time::Clock; | ||
| 14 | use embassy::util::Forever; | ||
| 15 | use example_common::*; | ||
| 16 | use embassy_traits::spi::FullDuplex; | ||
| 17 | |||
| 18 | use hal::prelude::*; | ||
| 19 | use stm32h7xx_hal as hal; | ||
| 20 | |||
| 21 | use cortex_m_rt::entry; | ||
| 22 | use stm32h7::stm32h743 as pac; | ||
| 23 | use heapless::String; | ||
| 24 | use embassy_stm32::spi::{Spi, Config}; | ||
| 25 | use embassy_stm32::time::Hertz; | ||
| 26 | use core::str::from_utf8; | ||
| 27 | |||
| 28 | #[embassy::task] | ||
| 29 | async 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 | |||
| 54 | struct ZeroClock; | ||
| 55 | |||
| 56 | impl Clock for ZeroClock { | ||
| 57 | fn now(&self) -> u64 { | ||
| 58 | 0 | ||
| 59 | } | ||
| 60 | } | ||
| 61 | |||
| 62 | static EXECUTOR: Forever<Executor> = Forever::new(); | ||
| 63 | |||
| 64 | #[entry] | ||
| 65 | fn 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; | |||
| 18 | use embassy_stm32::spi::{Config, Spi}; | 18 | use embassy_stm32::spi::{Config, Spi}; |
| 19 | use embassy_stm32::time::Hertz; | 19 | use embassy_stm32::time::Hertz; |
| 20 | use embedded_hal::blocking::spi::Transfer; | 20 | use embedded_hal::blocking::spi::Transfer; |
| 21 | use embassy_stm32::dma::NoDma; | ||
| 21 | 22 | ||
| 22 | #[entry] | 23 | #[entry] |
| 23 | fn main() -> ! { | 24 | fn 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; | |||
| 17 | use embedded_hal::blocking::spi::Transfer; | 17 | use embedded_hal::blocking::spi::Transfer; |
| 18 | use embedded_hal::digital::v2::OutputPin; | 18 | use embedded_hal::digital::v2::OutputPin; |
| 19 | use example_common::*; | 19 | use example_common::*; |
| 20 | use embassy_stm32::dma::NoDma; | ||
| 20 | 21 | ||
| 21 | #[entry] | 22 | #[entry] |
| 22 | fn main() -> ! { | 23 | fn 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"] | ||
| 10 | mod example_common; | ||
| 11 | |||
| 12 | use cortex_m_rt::entry; | ||
| 13 | use embassy::executor::Executor; | ||
| 14 | use embassy::time::Clock; | ||
| 15 | use embassy::util::Forever; | ||
| 16 | use embassy_stm32::pac; | ||
| 17 | use example_common::*; | ||
| 18 | use embassy_stm32::spi::{Spi, Config}; | ||
| 19 | use embassy_traits::spi::FullDuplex; | ||
| 20 | use embassy_stm32::time::Hertz; | ||
| 21 | use embassy_stm32::gpio::{Output, Level, Speed, Input, Pull}; | ||
| 22 | use embedded_hal::digital::v2::{OutputPin, InputPin}; | ||
| 23 | |||
| 24 | #[embassy::task] | ||
| 25 | async 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 | |||
| 64 | struct ZeroClock; | ||
| 65 | |||
| 66 | impl Clock for ZeroClock { | ||
| 67 | fn now(&self) -> u64 { | ||
| 68 | 0 | ||
| 69 | } | ||
| 70 | } | ||
| 71 | |||
| 72 | static EXECUTOR: Forever<Executor> = Forever::new(); | ||
| 73 | |||
| 74 | #[entry] | ||
| 75 | fn 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 | } | ||
