diff options
| author | Dario Nieuwenhuis <[email protected]> | 2023-07-18 14:17:44 +0200 |
|---|---|---|
| committer | Dario Nieuwenhuis <[email protected]> | 2023-07-18 14:24:58 +0200 |
| commit | 10f59667879bc476004c78bc0d3d6a0c4f560e55 (patch) | |
| tree | 07bba56ac60667c8a63776fda9acef0583751f65 | |
| parent | 48957dce8767fb573527626b4a4a060fa3f1b98a (diff) | |
Convert files to LF endings.
| -rw-r--r-- | embassy-nrf/src/pdm.rs | 588 | ||||
| -rw-r--r-- | embassy-stm32/src/qspi/mod.rs | 664 |
2 files changed, 626 insertions, 626 deletions
diff --git a/embassy-nrf/src/pdm.rs b/embassy-nrf/src/pdm.rs index 0e30f7002..efa1fbccc 100644 --- a/embassy-nrf/src/pdm.rs +++ b/embassy-nrf/src/pdm.rs | |||
| @@ -1,294 +1,294 @@ | |||
| 1 | //! Pulse Density Modulation (PDM) mirophone driver. | 1 | //! Pulse Density Modulation (PDM) mirophone driver. |
| 2 | 2 | ||
| 3 | #![macro_use] | 3 | #![macro_use] |
| 4 | 4 | ||
| 5 | use core::marker::PhantomData; | 5 | use core::marker::PhantomData; |
| 6 | use core::sync::atomic::{compiler_fence, Ordering}; | 6 | use core::sync::atomic::{compiler_fence, Ordering}; |
| 7 | use core::task::Poll; | 7 | use core::task::Poll; |
| 8 | 8 | ||
| 9 | use embassy_hal_common::drop::OnDrop; | 9 | use embassy_hal_common::drop::OnDrop; |
| 10 | use embassy_hal_common::{into_ref, PeripheralRef}; | 10 | use embassy_hal_common::{into_ref, PeripheralRef}; |
| 11 | use futures::future::poll_fn; | 11 | use futures::future::poll_fn; |
| 12 | 12 | ||
| 13 | use crate::chip::EASY_DMA_SIZE; | 13 | use crate::chip::EASY_DMA_SIZE; |
| 14 | use crate::gpio::sealed::Pin; | 14 | use crate::gpio::sealed::Pin; |
| 15 | use crate::gpio::{AnyPin, Pin as GpioPin}; | 15 | use crate::gpio::{AnyPin, Pin as GpioPin}; |
| 16 | use crate::interrupt::typelevel::Interrupt; | 16 | use crate::interrupt::typelevel::Interrupt; |
| 17 | use crate::{interrupt, Peripheral}; | 17 | use crate::{interrupt, Peripheral}; |
| 18 | 18 | ||
| 19 | /// Interrupt handler. | 19 | /// Interrupt handler. |
| 20 | pub struct InterruptHandler<T: Instance> { | 20 | pub struct InterruptHandler<T: Instance> { |
| 21 | _phantom: PhantomData<T>, | 21 | _phantom: PhantomData<T>, |
| 22 | } | 22 | } |
| 23 | 23 | ||
| 24 | impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> { | 24 | impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> { |
| 25 | unsafe fn on_interrupt() { | 25 | unsafe fn on_interrupt() { |
| 26 | T::regs().intenclr.write(|w| w.end().clear()); | 26 | T::regs().intenclr.write(|w| w.end().clear()); |
| 27 | T::state().waker.wake(); | 27 | T::state().waker.wake(); |
| 28 | } | 28 | } |
| 29 | } | 29 | } |
| 30 | 30 | ||
| 31 | /// PDM microphone interface | 31 | /// PDM microphone interface |
| 32 | pub struct Pdm<'d, T: Instance> { | 32 | pub struct Pdm<'d, T: Instance> { |
| 33 | _peri: PeripheralRef<'d, T>, | 33 | _peri: PeripheralRef<'d, T>, |
| 34 | } | 34 | } |
| 35 | 35 | ||
| 36 | /// PDM error. | 36 | /// PDM error. |
| 37 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | 37 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] |
| 38 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | 38 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| 39 | #[non_exhaustive] | 39 | #[non_exhaustive] |
| 40 | pub enum Error { | 40 | pub enum Error { |
| 41 | /// Buffer is too long. | 41 | /// Buffer is too long. |
| 42 | BufferTooLong, | 42 | BufferTooLong, |
| 43 | /// Buffer is empty | 43 | /// Buffer is empty |
| 44 | BufferZeroLength, | 44 | BufferZeroLength, |
| 45 | /// PDM is not running | 45 | /// PDM is not running |
| 46 | NotRunning, | 46 | NotRunning, |
| 47 | } | 47 | } |
| 48 | 48 | ||
| 49 | static DUMMY_BUFFER: [i16; 1] = [0; 1]; | 49 | static DUMMY_BUFFER: [i16; 1] = [0; 1]; |
| 50 | 50 | ||
| 51 | impl<'d, T: Instance> Pdm<'d, T> { | 51 | impl<'d, T: Instance> Pdm<'d, T> { |
| 52 | /// Create PDM driver | 52 | /// Create PDM driver |
| 53 | pub fn new( | 53 | pub fn new( |
| 54 | pdm: impl Peripheral<P = T> + 'd, | 54 | pdm: impl Peripheral<P = T> + 'd, |
| 55 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | 55 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, |
| 56 | clk: impl Peripheral<P = impl GpioPin> + 'd, | 56 | clk: impl Peripheral<P = impl GpioPin> + 'd, |
| 57 | din: impl Peripheral<P = impl GpioPin> + 'd, | 57 | din: impl Peripheral<P = impl GpioPin> + 'd, |
| 58 | config: Config, | 58 | config: Config, |
| 59 | ) -> Self { | 59 | ) -> Self { |
| 60 | into_ref!(pdm, clk, din); | 60 | into_ref!(pdm, clk, din); |
| 61 | Self::new_inner(pdm, clk.map_into(), din.map_into(), config) | 61 | Self::new_inner(pdm, clk.map_into(), din.map_into(), config) |
| 62 | } | 62 | } |
| 63 | 63 | ||
| 64 | fn new_inner( | 64 | fn new_inner( |
| 65 | pdm: PeripheralRef<'d, T>, | 65 | pdm: PeripheralRef<'d, T>, |
| 66 | clk: PeripheralRef<'d, AnyPin>, | 66 | clk: PeripheralRef<'d, AnyPin>, |
| 67 | din: PeripheralRef<'d, AnyPin>, | 67 | din: PeripheralRef<'d, AnyPin>, |
| 68 | config: Config, | 68 | config: Config, |
| 69 | ) -> Self { | 69 | ) -> Self { |
| 70 | into_ref!(pdm); | 70 | into_ref!(pdm); |
| 71 | 71 | ||
| 72 | let r = T::regs(); | 72 | let r = T::regs(); |
| 73 | 73 | ||
| 74 | // setup gpio pins | 74 | // setup gpio pins |
| 75 | din.conf().write(|w| w.input().set_bit()); | 75 | din.conf().write(|w| w.input().set_bit()); |
| 76 | r.psel.din.write(|w| unsafe { w.bits(din.psel_bits()) }); | 76 | r.psel.din.write(|w| unsafe { w.bits(din.psel_bits()) }); |
| 77 | clk.set_low(); | 77 | clk.set_low(); |
| 78 | clk.conf().write(|w| w.dir().output()); | 78 | clk.conf().write(|w| w.dir().output()); |
| 79 | r.psel.clk.write(|w| unsafe { w.bits(clk.psel_bits()) }); | 79 | r.psel.clk.write(|w| unsafe { w.bits(clk.psel_bits()) }); |
| 80 | 80 | ||
| 81 | // configure | 81 | // configure |
| 82 | // use default for | 82 | // use default for |
| 83 | // - gain right | 83 | // - gain right |
| 84 | // - gain left | 84 | // - gain left |
| 85 | // - clk | 85 | // - clk |
| 86 | // - ratio | 86 | // - ratio |
| 87 | r.mode.write(|w| { | 87 | r.mode.write(|w| { |
| 88 | w.edge().bit(config.edge == Edge::LeftRising); | 88 | w.edge().bit(config.edge == Edge::LeftRising); |
| 89 | w.operation().bit(config.operation_mode == OperationMode::Mono); | 89 | w.operation().bit(config.operation_mode == OperationMode::Mono); |
| 90 | w | 90 | w |
| 91 | }); | 91 | }); |
| 92 | r.gainl.write(|w| w.gainl().default_gain()); | 92 | r.gainl.write(|w| w.gainl().default_gain()); |
| 93 | r.gainr.write(|w| w.gainr().default_gain()); | 93 | r.gainr.write(|w| w.gainr().default_gain()); |
| 94 | 94 | ||
| 95 | // IRQ | 95 | // IRQ |
| 96 | T::Interrupt::unpend(); | 96 | T::Interrupt::unpend(); |
| 97 | unsafe { T::Interrupt::enable() }; | 97 | unsafe { T::Interrupt::enable() }; |
| 98 | 98 | ||
| 99 | r.enable.write(|w| w.enable().set_bit()); | 99 | r.enable.write(|w| w.enable().set_bit()); |
| 100 | 100 | ||
| 101 | Self { _peri: pdm } | 101 | Self { _peri: pdm } |
| 102 | } | 102 | } |
| 103 | 103 | ||
| 104 | /// Start sampling microphon data into a dummy buffer | 104 | /// Start sampling microphon data into a dummy buffer |
| 105 | /// Usefull to start the microphon and keep it active between recording samples | 105 | /// Usefull to start the microphon and keep it active between recording samples |
| 106 | pub async fn start(&mut self) { | 106 | pub async fn start(&mut self) { |
| 107 | let r = T::regs(); | 107 | let r = T::regs(); |
| 108 | 108 | ||
| 109 | // start dummy sampling because microphon needs some setup time | 109 | // start dummy sampling because microphon needs some setup time |
| 110 | r.sample | 110 | r.sample |
| 111 | .ptr | 111 | .ptr |
| 112 | .write(|w| unsafe { w.sampleptr().bits(DUMMY_BUFFER.as_ptr() as u32) }); | 112 | .write(|w| unsafe { w.sampleptr().bits(DUMMY_BUFFER.as_ptr() as u32) }); |
| 113 | r.sample | 113 | r.sample |
| 114 | .maxcnt | 114 | .maxcnt |
| 115 | .write(|w| unsafe { w.buffsize().bits(DUMMY_BUFFER.len() as _) }); | 115 | .write(|w| unsafe { w.buffsize().bits(DUMMY_BUFFER.len() as _) }); |
| 116 | 116 | ||
| 117 | r.tasks_start.write(|w| unsafe { w.bits(1) }); | 117 | r.tasks_start.write(|w| unsafe { w.bits(1) }); |
| 118 | } | 118 | } |
| 119 | 119 | ||
| 120 | /// Stop sampling microphon data inta a dummy buffer | 120 | /// Stop sampling microphon data inta a dummy buffer |
| 121 | pub async fn stop(&mut self) { | 121 | pub async fn stop(&mut self) { |
| 122 | let r = T::regs(); | 122 | let r = T::regs(); |
| 123 | r.tasks_stop.write(|w| unsafe { w.bits(1) }); | 123 | r.tasks_stop.write(|w| unsafe { w.bits(1) }); |
| 124 | r.events_started.reset(); | 124 | r.events_started.reset(); |
| 125 | } | 125 | } |
| 126 | 126 | ||
| 127 | /// Sample data into the given buffer. | 127 | /// Sample data into the given buffer. |
| 128 | pub async fn sample(&mut self, buffer: &mut [i16]) -> Result<(), Error> { | 128 | pub async fn sample(&mut self, buffer: &mut [i16]) -> Result<(), Error> { |
| 129 | if buffer.len() == 0 { | 129 | if buffer.len() == 0 { |
| 130 | return Err(Error::BufferZeroLength); | 130 | return Err(Error::BufferZeroLength); |
| 131 | } | 131 | } |
| 132 | if buffer.len() > EASY_DMA_SIZE { | 132 | if buffer.len() > EASY_DMA_SIZE { |
| 133 | return Err(Error::BufferTooLong); | 133 | return Err(Error::BufferTooLong); |
| 134 | } | 134 | } |
| 135 | 135 | ||
| 136 | let r = T::regs(); | 136 | let r = T::regs(); |
| 137 | 137 | ||
| 138 | if r.events_started.read().bits() == 0 { | 138 | if r.events_started.read().bits() == 0 { |
| 139 | return Err(Error::NotRunning); | 139 | return Err(Error::NotRunning); |
| 140 | } | 140 | } |
| 141 | 141 | ||
| 142 | let drop = OnDrop::new(move || { | 142 | let drop = OnDrop::new(move || { |
| 143 | r.intenclr.write(|w| w.end().clear()); | 143 | r.intenclr.write(|w| w.end().clear()); |
| 144 | r.events_stopped.reset(); | 144 | r.events_stopped.reset(); |
| 145 | 145 | ||
| 146 | // reset to dummy buffer | 146 | // reset to dummy buffer |
| 147 | r.sample | 147 | r.sample |
| 148 | .ptr | 148 | .ptr |
| 149 | .write(|w| unsafe { w.sampleptr().bits(DUMMY_BUFFER.as_ptr() as u32) }); | 149 | .write(|w| unsafe { w.sampleptr().bits(DUMMY_BUFFER.as_ptr() as u32) }); |
| 150 | r.sample | 150 | r.sample |
| 151 | .maxcnt | 151 | .maxcnt |
| 152 | .write(|w| unsafe { w.buffsize().bits(DUMMY_BUFFER.len() as _) }); | 152 | .write(|w| unsafe { w.buffsize().bits(DUMMY_BUFFER.len() as _) }); |
| 153 | 153 | ||
| 154 | while r.events_stopped.read().bits() == 0 {} | 154 | while r.events_stopped.read().bits() == 0 {} |
| 155 | }); | 155 | }); |
| 156 | 156 | ||
| 157 | // setup user buffer | 157 | // setup user buffer |
| 158 | let ptr = buffer.as_ptr(); | 158 | let ptr = buffer.as_ptr(); |
| 159 | let len = buffer.len(); | 159 | let len = buffer.len(); |
| 160 | r.sample.ptr.write(|w| unsafe { w.sampleptr().bits(ptr as u32) }); | 160 | r.sample.ptr.write(|w| unsafe { w.sampleptr().bits(ptr as u32) }); |
| 161 | r.sample.maxcnt.write(|w| unsafe { w.buffsize().bits(len as _) }); | 161 | r.sample.maxcnt.write(|w| unsafe { w.buffsize().bits(len as _) }); |
| 162 | 162 | ||
| 163 | // wait till the current sample is finished and the user buffer sample is started | 163 | // wait till the current sample is finished and the user buffer sample is started |
| 164 | Self::wait_for_sample().await; | 164 | Self::wait_for_sample().await; |
| 165 | 165 | ||
| 166 | // reset the buffer back to the dummy buffer | 166 | // reset the buffer back to the dummy buffer |
| 167 | r.sample | 167 | r.sample |
| 168 | .ptr | 168 | .ptr |
| 169 | .write(|w| unsafe { w.sampleptr().bits(DUMMY_BUFFER.as_ptr() as u32) }); | 169 | .write(|w| unsafe { w.sampleptr().bits(DUMMY_BUFFER.as_ptr() as u32) }); |
| 170 | r.sample | 170 | r.sample |
| 171 | .maxcnt | 171 | .maxcnt |
| 172 | .write(|w| unsafe { w.buffsize().bits(DUMMY_BUFFER.len() as _) }); | 172 | .write(|w| unsafe { w.buffsize().bits(DUMMY_BUFFER.len() as _) }); |
| 173 | 173 | ||
| 174 | // wait till the user buffer is sampled | 174 | // wait till the user buffer is sampled |
| 175 | Self::wait_for_sample().await; | 175 | Self::wait_for_sample().await; |
| 176 | 176 | ||
| 177 | drop.defuse(); | 177 | drop.defuse(); |
| 178 | 178 | ||
| 179 | Ok(()) | 179 | Ok(()) |
| 180 | } | 180 | } |
| 181 | 181 | ||
| 182 | async fn wait_for_sample() { | 182 | async fn wait_for_sample() { |
| 183 | let r = T::regs(); | 183 | let r = T::regs(); |
| 184 | 184 | ||
| 185 | r.events_end.reset(); | 185 | r.events_end.reset(); |
| 186 | r.intenset.write(|w| w.end().set()); | 186 | r.intenset.write(|w| w.end().set()); |
| 187 | 187 | ||
| 188 | compiler_fence(Ordering::SeqCst); | 188 | compiler_fence(Ordering::SeqCst); |
| 189 | 189 | ||
| 190 | poll_fn(|cx| { | 190 | poll_fn(|cx| { |
| 191 | T::state().waker.register(cx.waker()); | 191 | T::state().waker.register(cx.waker()); |
| 192 | if r.events_end.read().bits() != 0 { | 192 | if r.events_end.read().bits() != 0 { |
| 193 | return Poll::Ready(()); | 193 | return Poll::Ready(()); |
| 194 | } | 194 | } |
| 195 | Poll::Pending | 195 | Poll::Pending |
| 196 | }) | 196 | }) |
| 197 | .await; | 197 | .await; |
| 198 | 198 | ||
| 199 | compiler_fence(Ordering::SeqCst); | 199 | compiler_fence(Ordering::SeqCst); |
| 200 | } | 200 | } |
| 201 | } | 201 | } |
| 202 | 202 | ||
| 203 | /// PDM microphone driver Config | 203 | /// PDM microphone driver Config |
| 204 | pub struct Config { | 204 | pub struct Config { |
| 205 | /// Use stero or mono operation | 205 | /// Use stero or mono operation |
| 206 | pub operation_mode: OperationMode, | 206 | pub operation_mode: OperationMode, |
| 207 | /// On which edge the left channel should be samples | 207 | /// On which edge the left channel should be samples |
| 208 | pub edge: Edge, | 208 | pub edge: Edge, |
| 209 | } | 209 | } |
| 210 | 210 | ||
| 211 | impl Default for Config { | 211 | impl Default for Config { |
| 212 | fn default() -> Self { | 212 | fn default() -> Self { |
| 213 | Self { | 213 | Self { |
| 214 | operation_mode: OperationMode::Mono, | 214 | operation_mode: OperationMode::Mono, |
| 215 | edge: Edge::LeftFalling, | 215 | edge: Edge::LeftFalling, |
| 216 | } | 216 | } |
| 217 | } | 217 | } |
| 218 | } | 218 | } |
| 219 | 219 | ||
| 220 | /// PDM operation mode. | 220 | /// PDM operation mode. |
| 221 | #[derive(PartialEq)] | 221 | #[derive(PartialEq)] |
| 222 | pub enum OperationMode { | 222 | pub enum OperationMode { |
| 223 | /// Mono (1 channel) | 223 | /// Mono (1 channel) |
| 224 | Mono, | 224 | Mono, |
| 225 | /// Stereo (2 channels) | 225 | /// Stereo (2 channels) |
| 226 | Stereo, | 226 | Stereo, |
| 227 | } | 227 | } |
| 228 | 228 | ||
| 229 | /// PDM edge polarity | 229 | /// PDM edge polarity |
| 230 | #[derive(PartialEq)] | 230 | #[derive(PartialEq)] |
| 231 | pub enum Edge { | 231 | pub enum Edge { |
| 232 | /// Left edge is rising | 232 | /// Left edge is rising |
| 233 | LeftRising, | 233 | LeftRising, |
| 234 | /// Left edge is falling | 234 | /// Left edge is falling |
| 235 | LeftFalling, | 235 | LeftFalling, |
| 236 | } | 236 | } |
| 237 | 237 | ||
| 238 | impl<'d, T: Instance> Drop for Pdm<'d, T> { | 238 | impl<'d, T: Instance> Drop for Pdm<'d, T> { |
| 239 | fn drop(&mut self) { | 239 | fn drop(&mut self) { |
| 240 | let r = T::regs(); | 240 | let r = T::regs(); |
| 241 | 241 | ||
| 242 | r.tasks_stop.write(|w| unsafe { w.bits(1) }); | 242 | r.tasks_stop.write(|w| unsafe { w.bits(1) }); |
| 243 | 243 | ||
| 244 | r.enable.write(|w| w.enable().disabled()); | 244 | r.enable.write(|w| w.enable().disabled()); |
| 245 | 245 | ||
| 246 | r.psel.din.reset(); | 246 | r.psel.din.reset(); |
| 247 | r.psel.clk.reset(); | 247 | r.psel.clk.reset(); |
| 248 | } | 248 | } |
| 249 | } | 249 | } |
| 250 | 250 | ||
| 251 | pub(crate) mod sealed { | 251 | pub(crate) mod sealed { |
| 252 | use embassy_sync::waitqueue::AtomicWaker; | 252 | use embassy_sync::waitqueue::AtomicWaker; |
| 253 | 253 | ||
| 254 | /// Peripheral static state | 254 | /// Peripheral static state |
| 255 | pub struct State { | 255 | pub struct State { |
| 256 | pub waker: AtomicWaker, | 256 | pub waker: AtomicWaker, |
| 257 | } | 257 | } |
| 258 | 258 | ||
| 259 | impl State { | 259 | impl State { |
| 260 | pub const fn new() -> Self { | 260 | pub const fn new() -> Self { |
| 261 | Self { | 261 | Self { |
| 262 | waker: AtomicWaker::new(), | 262 | waker: AtomicWaker::new(), |
| 263 | } | 263 | } |
| 264 | } | 264 | } |
| 265 | } | 265 | } |
| 266 | 266 | ||
| 267 | pub trait Instance { | 267 | pub trait Instance { |
| 268 | fn regs() -> &'static crate::pac::pdm::RegisterBlock; | 268 | fn regs() -> &'static crate::pac::pdm::RegisterBlock; |
| 269 | fn state() -> &'static State; | 269 | fn state() -> &'static State; |
| 270 | } | 270 | } |
| 271 | } | 271 | } |
| 272 | 272 | ||
| 273 | /// PDM peripheral instance. | 273 | /// PDM peripheral instance. |
| 274 | pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send { | 274 | pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send { |
| 275 | /// Interrupt for this peripheral. | 275 | /// Interrupt for this peripheral. |
| 276 | type Interrupt: interrupt::typelevel::Interrupt; | 276 | type Interrupt: interrupt::typelevel::Interrupt; |
| 277 | } | 277 | } |
| 278 | 278 | ||
| 279 | macro_rules! impl_pdm { | 279 | macro_rules! impl_pdm { |
| 280 | ($type:ident, $pac_type:ident, $irq:ident) => { | 280 | ($type:ident, $pac_type:ident, $irq:ident) => { |
| 281 | impl crate::pdm::sealed::Instance for peripherals::$type { | 281 | impl crate::pdm::sealed::Instance for peripherals::$type { |
| 282 | fn regs() -> &'static crate::pac::pdm::RegisterBlock { | 282 | fn regs() -> &'static crate::pac::pdm::RegisterBlock { |
| 283 | unsafe { &*pac::$pac_type::ptr() } | 283 | unsafe { &*pac::$pac_type::ptr() } |
| 284 | } | 284 | } |
| 285 | fn state() -> &'static crate::pdm::sealed::State { | 285 | fn state() -> &'static crate::pdm::sealed::State { |
| 286 | static STATE: crate::pdm::sealed::State = crate::pdm::sealed::State::new(); | 286 | static STATE: crate::pdm::sealed::State = crate::pdm::sealed::State::new(); |
| 287 | &STATE | 287 | &STATE |
| 288 | } | 288 | } |
| 289 | } | 289 | } |
| 290 | impl crate::pdm::Instance for peripherals::$type { | 290 | impl crate::pdm::Instance for peripherals::$type { |
| 291 | type Interrupt = crate::interrupt::typelevel::$irq; | 291 | type Interrupt = crate::interrupt::typelevel::$irq; |
| 292 | } | 292 | } |
| 293 | }; | 293 | }; |
| 294 | } | 294 | } |
diff --git a/embassy-stm32/src/qspi/mod.rs b/embassy-stm32/src/qspi/mod.rs index e9db934bf..31b676088 100644 --- a/embassy-stm32/src/qspi/mod.rs +++ b/embassy-stm32/src/qspi/mod.rs | |||
| @@ -1,332 +1,332 @@ | |||
| 1 | #![macro_use] | 1 | #![macro_use] |
| 2 | 2 | ||
| 3 | pub mod enums; | 3 | pub mod enums; |
| 4 | 4 | ||
| 5 | use embassy_hal_common::{into_ref, PeripheralRef}; | 5 | use embassy_hal_common::{into_ref, PeripheralRef}; |
| 6 | use enums::*; | 6 | use enums::*; |
| 7 | 7 | ||
| 8 | use crate::dma::Transfer; | 8 | use crate::dma::Transfer; |
| 9 | use crate::gpio::sealed::AFType; | 9 | use crate::gpio::sealed::AFType; |
| 10 | use crate::gpio::AnyPin; | 10 | use crate::gpio::AnyPin; |
| 11 | use crate::pac::quadspi::Quadspi as Regs; | 11 | use crate::pac::quadspi::Quadspi as Regs; |
| 12 | use crate::rcc::RccPeripheral; | 12 | use crate::rcc::RccPeripheral; |
| 13 | use crate::{peripherals, Peripheral}; | 13 | use crate::{peripherals, Peripheral}; |
| 14 | 14 | ||
| 15 | pub struct TransferConfig { | 15 | pub struct TransferConfig { |
| 16 | /// Instraction width (IMODE) | 16 | /// Instraction width (IMODE) |
| 17 | pub iwidth: QspiWidth, | 17 | pub iwidth: QspiWidth, |
| 18 | /// Address width (ADMODE) | 18 | /// Address width (ADMODE) |
| 19 | pub awidth: QspiWidth, | 19 | pub awidth: QspiWidth, |
| 20 | /// Data width (DMODE) | 20 | /// Data width (DMODE) |
| 21 | pub dwidth: QspiWidth, | 21 | pub dwidth: QspiWidth, |
| 22 | /// Instruction Id | 22 | /// Instruction Id |
| 23 | pub instruction: u8, | 23 | pub instruction: u8, |
| 24 | /// Flash memory address | 24 | /// Flash memory address |
| 25 | pub address: Option<u32>, | 25 | pub address: Option<u32>, |
| 26 | /// Number of dummy cycles (DCYC) | 26 | /// Number of dummy cycles (DCYC) |
| 27 | pub dummy: DummyCycles, | 27 | pub dummy: DummyCycles, |
| 28 | /// Length of data | 28 | /// Length of data |
| 29 | pub data_len: Option<usize>, | 29 | pub data_len: Option<usize>, |
| 30 | } | 30 | } |
| 31 | 31 | ||
| 32 | impl Default for TransferConfig { | 32 | impl Default for TransferConfig { |
| 33 | fn default() -> Self { | 33 | fn default() -> Self { |
| 34 | Self { | 34 | Self { |
| 35 | iwidth: QspiWidth::NONE, | 35 | iwidth: QspiWidth::NONE, |
| 36 | awidth: QspiWidth::NONE, | 36 | awidth: QspiWidth::NONE, |
| 37 | dwidth: QspiWidth::NONE, | 37 | dwidth: QspiWidth::NONE, |
| 38 | instruction: 0, | 38 | instruction: 0, |
| 39 | address: None, | 39 | address: None, |
| 40 | dummy: DummyCycles::_0, | 40 | dummy: DummyCycles::_0, |
| 41 | data_len: None, | 41 | data_len: None, |
| 42 | } | 42 | } |
| 43 | } | 43 | } |
| 44 | } | 44 | } |
| 45 | 45 | ||
| 46 | pub struct Config { | 46 | pub struct Config { |
| 47 | /// Flash memory size representend as 2^[0-32], as reasonable minimum 1KiB(9) was chosen. | 47 | /// Flash memory size representend as 2^[0-32], as reasonable minimum 1KiB(9) was chosen. |
| 48 | /// If you need other value the whose predefined use `Other` variant. | 48 | /// If you need other value the whose predefined use `Other` variant. |
| 49 | pub memory_size: MemorySize, | 49 | pub memory_size: MemorySize, |
| 50 | /// Address size (8/16/24/32-bit) | 50 | /// Address size (8/16/24/32-bit) |
| 51 | pub address_size: AddressSize, | 51 | pub address_size: AddressSize, |
| 52 | /// Scalar factor for generating CLK [0-255] | 52 | /// Scalar factor for generating CLK [0-255] |
| 53 | pub prescaler: u8, | 53 | pub prescaler: u8, |
| 54 | /// Number of bytes to trigger FIFO threshold flag. | 54 | /// Number of bytes to trigger FIFO threshold flag. |
| 55 | pub fifo_threshold: FIFOThresholdLevel, | 55 | pub fifo_threshold: FIFOThresholdLevel, |
| 56 | /// Minimum number of cycles that chip select must be high between issued commands | 56 | /// Minimum number of cycles that chip select must be high between issued commands |
| 57 | pub cs_high_time: ChipSelectHightTime, | 57 | pub cs_high_time: ChipSelectHightTime, |
| 58 | } | 58 | } |
| 59 | 59 | ||
| 60 | impl Default for Config { | 60 | impl Default for Config { |
| 61 | fn default() -> Self { | 61 | fn default() -> Self { |
| 62 | Self { | 62 | Self { |
| 63 | memory_size: MemorySize::Other(0), | 63 | memory_size: MemorySize::Other(0), |
| 64 | address_size: AddressSize::_24bit, | 64 | address_size: AddressSize::_24bit, |
| 65 | prescaler: 128, | 65 | prescaler: 128, |
| 66 | fifo_threshold: FIFOThresholdLevel::_17Bytes, | 66 | fifo_threshold: FIFOThresholdLevel::_17Bytes, |
| 67 | cs_high_time: ChipSelectHightTime::_5Cycle, | 67 | cs_high_time: ChipSelectHightTime::_5Cycle, |
| 68 | } | 68 | } |
| 69 | } | 69 | } |
| 70 | } | 70 | } |
| 71 | 71 | ||
| 72 | #[allow(dead_code)] | 72 | #[allow(dead_code)] |
| 73 | pub struct Qspi<'d, T: Instance, Dma> { | 73 | pub struct Qspi<'d, T: Instance, Dma> { |
| 74 | _peri: PeripheralRef<'d, T>, | 74 | _peri: PeripheralRef<'d, T>, |
| 75 | sck: Option<PeripheralRef<'d, AnyPin>>, | 75 | sck: Option<PeripheralRef<'d, AnyPin>>, |
| 76 | d0: Option<PeripheralRef<'d, AnyPin>>, | 76 | d0: Option<PeripheralRef<'d, AnyPin>>, |
| 77 | d1: Option<PeripheralRef<'d, AnyPin>>, | 77 | d1: Option<PeripheralRef<'d, AnyPin>>, |
| 78 | d2: Option<PeripheralRef<'d, AnyPin>>, | 78 | d2: Option<PeripheralRef<'d, AnyPin>>, |
| 79 | d3: Option<PeripheralRef<'d, AnyPin>>, | 79 | d3: Option<PeripheralRef<'d, AnyPin>>, |
| 80 | nss: Option<PeripheralRef<'d, AnyPin>>, | 80 | nss: Option<PeripheralRef<'d, AnyPin>>, |
| 81 | dma: PeripheralRef<'d, Dma>, | 81 | dma: PeripheralRef<'d, Dma>, |
| 82 | config: Config, | 82 | config: Config, |
| 83 | } | 83 | } |
| 84 | 84 | ||
| 85 | impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> { | 85 | impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> { |
| 86 | pub fn new( | 86 | pub fn new( |
| 87 | peri: impl Peripheral<P = T> + 'd, | 87 | peri: impl Peripheral<P = T> + 'd, |
| 88 | d0: impl Peripheral<P = impl D0Pin<T>> + 'd, | 88 | d0: impl Peripheral<P = impl D0Pin<T>> + 'd, |
| 89 | d1: impl Peripheral<P = impl D1Pin<T>> + 'd, | 89 | d1: impl Peripheral<P = impl D1Pin<T>> + 'd, |
| 90 | d2: impl Peripheral<P = impl D2Pin<T>> + 'd, | 90 | d2: impl Peripheral<P = impl D2Pin<T>> + 'd, |
| 91 | d3: impl Peripheral<P = impl D3Pin<T>> + 'd, | 91 | d3: impl Peripheral<P = impl D3Pin<T>> + 'd, |
| 92 | sck: impl Peripheral<P = impl SckPin<T>> + 'd, | 92 | sck: impl Peripheral<P = impl SckPin<T>> + 'd, |
| 93 | nss: impl Peripheral<P = impl NSSPin<T>> + 'd, | 93 | nss: impl Peripheral<P = impl NSSPin<T>> + 'd, |
| 94 | dma: impl Peripheral<P = Dma> + 'd, | 94 | dma: impl Peripheral<P = Dma> + 'd, |
| 95 | config: Config, | 95 | config: Config, |
| 96 | ) -> Self { | 96 | ) -> Self { |
| 97 | into_ref!(peri, d0, d1, d2, d3, sck, nss); | 97 | into_ref!(peri, d0, d1, d2, d3, sck, nss); |
| 98 | 98 | ||
| 99 | sck.set_as_af(sck.af_num(), AFType::OutputPushPull); | 99 | sck.set_as_af(sck.af_num(), AFType::OutputPushPull); |
| 100 | sck.set_speed(crate::gpio::Speed::VeryHigh); | 100 | sck.set_speed(crate::gpio::Speed::VeryHigh); |
| 101 | nss.set_as_af(nss.af_num(), AFType::OutputPushPull); | 101 | nss.set_as_af(nss.af_num(), AFType::OutputPushPull); |
| 102 | nss.set_speed(crate::gpio::Speed::VeryHigh); | 102 | nss.set_speed(crate::gpio::Speed::VeryHigh); |
| 103 | d0.set_as_af(d0.af_num(), AFType::OutputPushPull); | 103 | d0.set_as_af(d0.af_num(), AFType::OutputPushPull); |
| 104 | d0.set_speed(crate::gpio::Speed::VeryHigh); | 104 | d0.set_speed(crate::gpio::Speed::VeryHigh); |
| 105 | d1.set_as_af(d1.af_num(), AFType::OutputPushPull); | 105 | d1.set_as_af(d1.af_num(), AFType::OutputPushPull); |
| 106 | d1.set_speed(crate::gpio::Speed::VeryHigh); | 106 | d1.set_speed(crate::gpio::Speed::VeryHigh); |
| 107 | d2.set_as_af(d2.af_num(), AFType::OutputPushPull); | 107 | d2.set_as_af(d2.af_num(), AFType::OutputPushPull); |
| 108 | d2.set_speed(crate::gpio::Speed::VeryHigh); | 108 | d2.set_speed(crate::gpio::Speed::VeryHigh); |
| 109 | d3.set_as_af(d3.af_num(), AFType::OutputPushPull); | 109 | d3.set_as_af(d3.af_num(), AFType::OutputPushPull); |
| 110 | d3.set_speed(crate::gpio::Speed::VeryHigh); | 110 | d3.set_speed(crate::gpio::Speed::VeryHigh); |
| 111 | 111 | ||
| 112 | Self::new_inner( | 112 | Self::new_inner( |
| 113 | peri, | 113 | peri, |
| 114 | Some(d0.map_into()), | 114 | Some(d0.map_into()), |
| 115 | Some(d1.map_into()), | 115 | Some(d1.map_into()), |
| 116 | Some(d2.map_into()), | 116 | Some(d2.map_into()), |
| 117 | Some(d3.map_into()), | 117 | Some(d3.map_into()), |
| 118 | Some(sck.map_into()), | 118 | Some(sck.map_into()), |
| 119 | Some(nss.map_into()), | 119 | Some(nss.map_into()), |
| 120 | dma, | 120 | dma, |
| 121 | config, | 121 | config, |
| 122 | ) | 122 | ) |
| 123 | } | 123 | } |
| 124 | 124 | ||
| 125 | fn new_inner( | 125 | fn new_inner( |
| 126 | peri: impl Peripheral<P = T> + 'd, | 126 | peri: impl Peripheral<P = T> + 'd, |
| 127 | d0: Option<PeripheralRef<'d, AnyPin>>, | 127 | d0: Option<PeripheralRef<'d, AnyPin>>, |
| 128 | d1: Option<PeripheralRef<'d, AnyPin>>, | 128 | d1: Option<PeripheralRef<'d, AnyPin>>, |
| 129 | d2: Option<PeripheralRef<'d, AnyPin>>, | 129 | d2: Option<PeripheralRef<'d, AnyPin>>, |
| 130 | d3: Option<PeripheralRef<'d, AnyPin>>, | 130 | d3: Option<PeripheralRef<'d, AnyPin>>, |
| 131 | sck: Option<PeripheralRef<'d, AnyPin>>, | 131 | sck: Option<PeripheralRef<'d, AnyPin>>, |
| 132 | nss: Option<PeripheralRef<'d, AnyPin>>, | 132 | nss: Option<PeripheralRef<'d, AnyPin>>, |
| 133 | dma: impl Peripheral<P = Dma> + 'd, | 133 | dma: impl Peripheral<P = Dma> + 'd, |
| 134 | config: Config, | 134 | config: Config, |
| 135 | ) -> Self { | 135 | ) -> Self { |
| 136 | into_ref!(peri, dma); | 136 | into_ref!(peri, dma); |
| 137 | 137 | ||
| 138 | T::enable(); | 138 | T::enable(); |
| 139 | T::REGS.cr().write(|w| w.set_fthres(config.fifo_threshold.into())); | 139 | T::REGS.cr().write(|w| w.set_fthres(config.fifo_threshold.into())); |
| 140 | 140 | ||
| 141 | while T::REGS.sr().read().busy() {} | 141 | while T::REGS.sr().read().busy() {} |
| 142 | 142 | ||
| 143 | T::REGS.cr().write(|w| { | 143 | T::REGS.cr().write(|w| { |
| 144 | w.set_prescaler(config.prescaler); | 144 | w.set_prescaler(config.prescaler); |
| 145 | w.set_en(true); | 145 | w.set_en(true); |
| 146 | }); | 146 | }); |
| 147 | T::REGS.dcr().write(|w| { | 147 | T::REGS.dcr().write(|w| { |
| 148 | w.set_fsize(config.memory_size.into()); | 148 | w.set_fsize(config.memory_size.into()); |
| 149 | w.set_csht(config.cs_high_time.into()); | 149 | w.set_csht(config.cs_high_time.into()); |
| 150 | w.set_ckmode(false); | 150 | w.set_ckmode(false); |
| 151 | }); | 151 | }); |
| 152 | 152 | ||
| 153 | Self { | 153 | Self { |
| 154 | _peri: peri, | 154 | _peri: peri, |
| 155 | sck, | 155 | sck, |
| 156 | d0, | 156 | d0, |
| 157 | d1, | 157 | d1, |
| 158 | d2, | 158 | d2, |
| 159 | d3, | 159 | d3, |
| 160 | nss, | 160 | nss, |
| 161 | dma, | 161 | dma, |
| 162 | config, | 162 | config, |
| 163 | } | 163 | } |
| 164 | } | 164 | } |
| 165 | 165 | ||
| 166 | pub fn command(&mut self, transaction: TransferConfig) { | 166 | pub fn command(&mut self, transaction: TransferConfig) { |
| 167 | T::REGS.cr().modify(|v| v.set_dmaen(false)); | 167 | T::REGS.cr().modify(|v| v.set_dmaen(false)); |
| 168 | self.setup_transaction(QspiMode::IndirectWrite, &transaction); | 168 | self.setup_transaction(QspiMode::IndirectWrite, &transaction); |
| 169 | 169 | ||
| 170 | while !T::REGS.sr().read().tcf() {} | 170 | while !T::REGS.sr().read().tcf() {} |
| 171 | T::REGS.fcr().modify(|v| v.set_ctcf(true)); | 171 | T::REGS.fcr().modify(|v| v.set_ctcf(true)); |
| 172 | } | 172 | } |
| 173 | 173 | ||
| 174 | pub fn blocking_read(&mut self, buf: &mut [u8], transaction: TransferConfig) { | 174 | pub fn blocking_read(&mut self, buf: &mut [u8], transaction: TransferConfig) { |
| 175 | T::REGS.cr().modify(|v| v.set_dmaen(false)); | 175 | T::REGS.cr().modify(|v| v.set_dmaen(false)); |
| 176 | self.setup_transaction(QspiMode::IndirectWrite, &transaction); | 176 | self.setup_transaction(QspiMode::IndirectWrite, &transaction); |
| 177 | 177 | ||
| 178 | if let Some(len) = transaction.data_len { | 178 | if let Some(len) = transaction.data_len { |
| 179 | let current_ar = T::REGS.ar().read().address(); | 179 | let current_ar = T::REGS.ar().read().address(); |
| 180 | T::REGS.ccr().modify(|v| { | 180 | T::REGS.ccr().modify(|v| { |
| 181 | v.set_fmode(QspiMode::IndirectRead.into()); | 181 | v.set_fmode(QspiMode::IndirectRead.into()); |
| 182 | }); | 182 | }); |
| 183 | T::REGS.ar().write(|v| { | 183 | T::REGS.ar().write(|v| { |
| 184 | v.set_address(current_ar); | 184 | v.set_address(current_ar); |
| 185 | }); | 185 | }); |
| 186 | 186 | ||
| 187 | for idx in 0..len { | 187 | for idx in 0..len { |
| 188 | while !T::REGS.sr().read().tcf() && !T::REGS.sr().read().ftf() {} | 188 | while !T::REGS.sr().read().tcf() && !T::REGS.sr().read().ftf() {} |
| 189 | buf[idx] = unsafe { (T::REGS.dr().as_ptr() as *mut u8).read_volatile() }; | 189 | buf[idx] = unsafe { (T::REGS.dr().as_ptr() as *mut u8).read_volatile() }; |
| 190 | } | 190 | } |
| 191 | } | 191 | } |
| 192 | 192 | ||
| 193 | while !T::REGS.sr().read().tcf() {} | 193 | while !T::REGS.sr().read().tcf() {} |
| 194 | T::REGS.fcr().modify(|v| v.set_ctcf(true)); | 194 | T::REGS.fcr().modify(|v| v.set_ctcf(true)); |
| 195 | } | 195 | } |
| 196 | 196 | ||
| 197 | pub fn blocking_write(&mut self, buf: &[u8], transaction: TransferConfig) { | 197 | pub fn blocking_write(&mut self, buf: &[u8], transaction: TransferConfig) { |
| 198 | T::REGS.cr().modify(|v| v.set_dmaen(false)); | 198 | T::REGS.cr().modify(|v| v.set_dmaen(false)); |
| 199 | self.setup_transaction(QspiMode::IndirectWrite, &transaction); | 199 | self.setup_transaction(QspiMode::IndirectWrite, &transaction); |
| 200 | 200 | ||
| 201 | if let Some(len) = transaction.data_len { | 201 | if let Some(len) = transaction.data_len { |
| 202 | T::REGS.ccr().modify(|v| { | 202 | T::REGS.ccr().modify(|v| { |
| 203 | v.set_fmode(QspiMode::IndirectWrite.into()); | 203 | v.set_fmode(QspiMode::IndirectWrite.into()); |
| 204 | }); | 204 | }); |
| 205 | 205 | ||
| 206 | for idx in 0..len { | 206 | for idx in 0..len { |
| 207 | while !T::REGS.sr().read().ftf() {} | 207 | while !T::REGS.sr().read().ftf() {} |
| 208 | unsafe { (T::REGS.dr().as_ptr() as *mut u8).write_volatile(buf[idx]) }; | 208 | unsafe { (T::REGS.dr().as_ptr() as *mut u8).write_volatile(buf[idx]) }; |
| 209 | } | 209 | } |
| 210 | } | 210 | } |
| 211 | 211 | ||
| 212 | while !T::REGS.sr().read().tcf() {} | 212 | while !T::REGS.sr().read().tcf() {} |
| 213 | T::REGS.fcr().modify(|v| v.set_ctcf(true)); | 213 | T::REGS.fcr().modify(|v| v.set_ctcf(true)); |
| 214 | } | 214 | } |
| 215 | 215 | ||
| 216 | pub fn blocking_read_dma(&mut self, buf: &mut [u8], transaction: TransferConfig) | 216 | pub fn blocking_read_dma(&mut self, buf: &mut [u8], transaction: TransferConfig) |
| 217 | where | 217 | where |
| 218 | Dma: QuadDma<T>, | 218 | Dma: QuadDma<T>, |
| 219 | { | 219 | { |
| 220 | self.setup_transaction(QspiMode::IndirectWrite, &transaction); | 220 | self.setup_transaction(QspiMode::IndirectWrite, &transaction); |
| 221 | 221 | ||
| 222 | T::REGS.ccr().modify(|v| { | 222 | T::REGS.ccr().modify(|v| { |
| 223 | v.set_fmode(QspiMode::IndirectRead.into()); | 223 | v.set_fmode(QspiMode::IndirectRead.into()); |
| 224 | }); | 224 | }); |
| 225 | let current_ar = T::REGS.ar().read().address(); | 225 | let current_ar = T::REGS.ar().read().address(); |
| 226 | T::REGS.ar().write(|v| { | 226 | T::REGS.ar().write(|v| { |
| 227 | v.set_address(current_ar); | 227 | v.set_address(current_ar); |
| 228 | }); | 228 | }); |
| 229 | 229 | ||
| 230 | let request = self.dma.request(); | 230 | let request = self.dma.request(); |
| 231 | let transfer = unsafe { | 231 | let transfer = unsafe { |
| 232 | Transfer::new_read( | 232 | Transfer::new_read( |
| 233 | &mut self.dma, | 233 | &mut self.dma, |
| 234 | request, | 234 | request, |
| 235 | T::REGS.dr().as_ptr() as *mut u8, | 235 | T::REGS.dr().as_ptr() as *mut u8, |
| 236 | buf, | 236 | buf, |
| 237 | Default::default(), | 237 | Default::default(), |
| 238 | ) | 238 | ) |
| 239 | }; | 239 | }; |
| 240 | 240 | ||
| 241 | T::REGS.cr().modify(|v| v.set_dmaen(true)); | 241 | T::REGS.cr().modify(|v| v.set_dmaen(true)); |
| 242 | 242 | ||
| 243 | transfer.blocking_wait(); | 243 | transfer.blocking_wait(); |
| 244 | } | 244 | } |
| 245 | 245 | ||
| 246 | pub fn blocking_write_dma(&mut self, buf: &[u8], transaction: TransferConfig) | 246 | pub fn blocking_write_dma(&mut self, buf: &[u8], transaction: TransferConfig) |
| 247 | where | 247 | where |
| 248 | Dma: QuadDma<T>, | 248 | Dma: QuadDma<T>, |
| 249 | { | 249 | { |
| 250 | self.setup_transaction(QspiMode::IndirectWrite, &transaction); | 250 | self.setup_transaction(QspiMode::IndirectWrite, &transaction); |
| 251 | 251 | ||
| 252 | T::REGS.ccr().modify(|v| { | 252 | T::REGS.ccr().modify(|v| { |
| 253 | v.set_fmode(QspiMode::IndirectWrite.into()); | 253 | v.set_fmode(QspiMode::IndirectWrite.into()); |
| 254 | }); | 254 | }); |
| 255 | 255 | ||
| 256 | let request = self.dma.request(); | 256 | let request = self.dma.request(); |
| 257 | let transfer = unsafe { | 257 | let transfer = unsafe { |
| 258 | Transfer::new_write( | 258 | Transfer::new_write( |
| 259 | &mut self.dma, | 259 | &mut self.dma, |
| 260 | request, | 260 | request, |
| 261 | buf, | 261 | buf, |
| 262 | T::REGS.dr().as_ptr() as *mut u8, | 262 | T::REGS.dr().as_ptr() as *mut u8, |
| 263 | Default::default(), | 263 | Default::default(), |
| 264 | ) | 264 | ) |
| 265 | }; | 265 | }; |
| 266 | 266 | ||
| 267 | T::REGS.cr().modify(|v| v.set_dmaen(true)); | 267 | T::REGS.cr().modify(|v| v.set_dmaen(true)); |
| 268 | 268 | ||
| 269 | transfer.blocking_wait(); | 269 | transfer.blocking_wait(); |
| 270 | } | 270 | } |
| 271 | 271 | ||
| 272 | fn setup_transaction(&mut self, fmode: QspiMode, transaction: &TransferConfig) { | 272 | fn setup_transaction(&mut self, fmode: QspiMode, transaction: &TransferConfig) { |
| 273 | T::REGS.fcr().modify(|v| { | 273 | T::REGS.fcr().modify(|v| { |
| 274 | v.set_csmf(true); | 274 | v.set_csmf(true); |
| 275 | v.set_ctcf(true); | 275 | v.set_ctcf(true); |
| 276 | v.set_ctef(true); | 276 | v.set_ctef(true); |
| 277 | v.set_ctof(true); | 277 | v.set_ctof(true); |
| 278 | }); | 278 | }); |
| 279 | 279 | ||
| 280 | while T::REGS.sr().read().busy() {} | 280 | while T::REGS.sr().read().busy() {} |
| 281 | 281 | ||
| 282 | if let Some(len) = transaction.data_len { | 282 | if let Some(len) = transaction.data_len { |
| 283 | T::REGS.dlr().write(|v| v.set_dl(len as u32 - 1)); | 283 | T::REGS.dlr().write(|v| v.set_dl(len as u32 - 1)); |
| 284 | } | 284 | } |
| 285 | 285 | ||
| 286 | T::REGS.ccr().write(|v| { | 286 | T::REGS.ccr().write(|v| { |
| 287 | v.set_fmode(fmode.into()); | 287 | v.set_fmode(fmode.into()); |
| 288 | v.set_imode(transaction.iwidth.into()); | 288 | v.set_imode(transaction.iwidth.into()); |
| 289 | v.set_instruction(transaction.instruction); | 289 | v.set_instruction(transaction.instruction); |
| 290 | v.set_admode(transaction.awidth.into()); | 290 | v.set_admode(transaction.awidth.into()); |
| 291 | v.set_adsize(self.config.address_size.into()); | 291 | v.set_adsize(self.config.address_size.into()); |
| 292 | v.set_dmode(transaction.dwidth.into()); | 292 | v.set_dmode(transaction.dwidth.into()); |
| 293 | v.set_abmode(QspiWidth::NONE.into()); | 293 | v.set_abmode(QspiWidth::NONE.into()); |
| 294 | v.set_dcyc(transaction.dummy.into()); | 294 | v.set_dcyc(transaction.dummy.into()); |
| 295 | }); | 295 | }); |
| 296 | 296 | ||
| 297 | if let Some(addr) = transaction.address { | 297 | if let Some(addr) = transaction.address { |
| 298 | T::REGS.ar().write(|v| { | 298 | T::REGS.ar().write(|v| { |
| 299 | v.set_address(addr); | 299 | v.set_address(addr); |
| 300 | }); | 300 | }); |
| 301 | } | 301 | } |
| 302 | } | 302 | } |
| 303 | } | 303 | } |
| 304 | 304 | ||
| 305 | pub(crate) mod sealed { | 305 | pub(crate) mod sealed { |
| 306 | use super::*; | 306 | use super::*; |
| 307 | 307 | ||
| 308 | pub trait Instance { | 308 | pub trait Instance { |
| 309 | const REGS: Regs; | 309 | const REGS: Regs; |
| 310 | } | 310 | } |
| 311 | } | 311 | } |
| 312 | 312 | ||
| 313 | pub trait Instance: Peripheral<P = Self> + sealed::Instance + RccPeripheral {} | 313 | pub trait Instance: Peripheral<P = Self> + sealed::Instance + RccPeripheral {} |
| 314 | 314 | ||
| 315 | pin_trait!(SckPin, Instance); | 315 | pin_trait!(SckPin, Instance); |
| 316 | pin_trait!(D0Pin, Instance); | 316 | pin_trait!(D0Pin, Instance); |
| 317 | pin_trait!(D1Pin, Instance); | 317 | pin_trait!(D1Pin, Instance); |
| 318 | pin_trait!(D2Pin, Instance); | 318 | pin_trait!(D2Pin, Instance); |
| 319 | pin_trait!(D3Pin, Instance); | 319 | pin_trait!(D3Pin, Instance); |
| 320 | pin_trait!(NSSPin, Instance); | 320 | pin_trait!(NSSPin, Instance); |
| 321 | 321 | ||
| 322 | dma_trait!(QuadDma, Instance); | 322 | dma_trait!(QuadDma, Instance); |
| 323 | 323 | ||
| 324 | foreach_peripheral!( | 324 | foreach_peripheral!( |
| 325 | (quadspi, $inst:ident) => { | 325 | (quadspi, $inst:ident) => { |
| 326 | impl sealed::Instance for peripherals::$inst { | 326 | impl sealed::Instance for peripherals::$inst { |
| 327 | const REGS: Regs = crate::pac::$inst; | 327 | const REGS: Regs = crate::pac::$inst; |
| 328 | } | 328 | } |
| 329 | 329 | ||
| 330 | impl Instance for peripherals::$inst {} | 330 | impl Instance for peripherals::$inst {} |
| 331 | }; | 331 | }; |
| 332 | ); | 332 | ); |
