aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-stm32/build.rs7
-rw-r--r--embassy-stm32/src/lib.rs3
-rw-r--r--embassy-stm32/src/qspi/enums.rs294
-rw-r--r--embassy-stm32/src/qspi/mod.rs338
4 files changed, 641 insertions, 1 deletions
diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs
index dbfc1370d..3780c5a40 100644
--- a/embassy-stm32/build.rs
+++ b/embassy-stm32/build.rs
@@ -427,6 +427,12 @@ fn main() {
427 (("sdmmc", "D6"), quote!(crate::sdmmc::D6Pin)), 427 (("sdmmc", "D6"), quote!(crate::sdmmc::D6Pin)),
428 (("sdmmc", "D6"), quote!(crate::sdmmc::D7Pin)), 428 (("sdmmc", "D6"), quote!(crate::sdmmc::D7Pin)),
429 (("sdmmc", "D8"), quote!(crate::sdmmc::D8Pin)), 429 (("sdmmc", "D8"), quote!(crate::sdmmc::D8Pin)),
430 (("quadspi", "BK1_IO0"), quote!(crate::qspi::D0Pin)),
431 (("quadspi", "BK1_IO1"), quote!(crate::qspi::D1Pin)),
432 (("quadspi", "BK1_IO2"), quote!(crate::qspi::D2Pin)),
433 (("quadspi", "BK1_IO3"), quote!(crate::qspi::D3Pin)),
434 (("quadspi", "CLK"), quote!(crate::qspi::SckPin)),
435 (("quadspi", "BK1_NCS"), quote!(crate::qspi::NSSPin)),
430 ].into(); 436 ].into();
431 437
432 for p in METADATA.peripherals { 438 for p in METADATA.peripherals {
@@ -507,6 +513,7 @@ fn main() {
507 (("dcmi", "PSSI"), quote!(crate::dcmi::FrameDma)), 513 (("dcmi", "PSSI"), quote!(crate::dcmi::FrameDma)),
508 // SDMMCv1 uses the same channel for both directions, so just implement for RX 514 // SDMMCv1 uses the same channel for both directions, so just implement for RX
509 (("sdmmc", "RX"), quote!(crate::sdmmc::SdmmcDma)), 515 (("sdmmc", "RX"), quote!(crate::sdmmc::SdmmcDma)),
516 (("quadspi", "QUADSPI"), quote!(crate::qspi::QuadDma)),
510 ] 517 ]
511 .into(); 518 .into();
512 519
diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs
index eeaa04f67..8dc4df2dc 100644
--- a/embassy-stm32/src/lib.rs
+++ b/embassy-stm32/src/lib.rs
@@ -48,6 +48,8 @@ pub mod crc;
48))] 48))]
49pub mod flash; 49pub mod flash;
50pub mod pwm; 50pub mod pwm;
51#[cfg(quadspi)]
52pub mod qspi;
51#[cfg(rng)] 53#[cfg(rng)]
52pub mod rng; 54pub mod rng;
53#[cfg(sdmmc)] 55#[cfg(sdmmc)]
@@ -60,7 +62,6 @@ pub mod usart;
60pub mod usb; 62pub mod usb;
61#[cfg(otg)] 63#[cfg(otg)]
62pub mod usb_otg; 64pub mod usb_otg;
63
64#[cfg(iwdg)] 65#[cfg(iwdg)]
65pub mod wdg; 66pub mod wdg;
66 67
diff --git a/embassy-stm32/src/qspi/enums.rs b/embassy-stm32/src/qspi/enums.rs
new file mode 100644
index 000000000..2dbe2b061
--- /dev/null
+++ b/embassy-stm32/src/qspi/enums.rs
@@ -0,0 +1,294 @@
1#[allow(dead_code)]
2#[derive(Copy, Clone)]
3pub(crate) enum QspiMode {
4 IndirectWrite,
5 IndirectRead,
6 AutoPolling,
7 MemoryMapped,
8}
9
10impl Into<u8> for QspiMode {
11 fn into(self) -> u8 {
12 match self {
13 QspiMode::IndirectWrite => 0b00,
14 QspiMode::IndirectRead => 0b01,
15 QspiMode::AutoPolling => 0b10,
16 QspiMode::MemoryMapped => 0b11,
17 }
18 }
19}
20
21#[allow(dead_code)]
22#[derive(Copy, Clone)]
23pub enum QspiWidth {
24 NONE,
25 SING,
26 DUAL,
27 QUAD,
28}
29
30impl Into<u8> for QspiWidth {
31 fn into(self) -> u8 {
32 match self {
33 QspiWidth::NONE => 0b00,
34 QspiWidth::SING => 0b01,
35 QspiWidth::DUAL => 0b10,
36 QspiWidth::QUAD => 0b11,
37 }
38 }
39}
40
41#[derive(Copy, Clone)]
42pub enum MemorySize {
43 _1KiB,
44 _2KiB,
45 _4KiB,
46 _8KiB,
47 _16KiB,
48 _32KiB,
49 _64KiB,
50 _128KiB,
51 _256KiB,
52 _512KiB,
53 _1MiB,
54 _2MiB,
55 _4MiB,
56 _8MiB,
57 _16MiB,
58 _32MiB,
59 _64MiB,
60 _128MiB,
61 _256MiB,
62 _512MiB,
63 _1GiB,
64 _2GiB,
65 _4GiB,
66 Other(u8),
67}
68
69impl Into<u8> for MemorySize {
70 fn into(self) -> u8 {
71 match self {
72 MemorySize::_1KiB => 9,
73 MemorySize::_2KiB => 10,
74 MemorySize::_4KiB => 11,
75 MemorySize::_8KiB => 12,
76 MemorySize::_16KiB => 13,
77 MemorySize::_32KiB => 14,
78 MemorySize::_64KiB => 15,
79 MemorySize::_128KiB => 16,
80 MemorySize::_256KiB => 17,
81 MemorySize::_512KiB => 18,
82 MemorySize::_1MiB => 19,
83 MemorySize::_2MiB => 20,
84 MemorySize::_4MiB => 21,
85 MemorySize::_8MiB => 22,
86 MemorySize::_16MiB => 23,
87 MemorySize::_32MiB => 24,
88 MemorySize::_64MiB => 25,
89 MemorySize::_128MiB => 26,
90 MemorySize::_256MiB => 27,
91 MemorySize::_512MiB => 28,
92 MemorySize::_1GiB => 29,
93 MemorySize::_2GiB => 30,
94 MemorySize::_4GiB => 31,
95 MemorySize::Other(val) => val,
96 }
97 }
98}
99
100#[derive(Copy, Clone)]
101pub enum AddressSize {
102 _8Bit,
103 _16Bit,
104 _24bit,
105 _32bit,
106}
107
108impl Into<u8> for AddressSize {
109 fn into(self) -> u8 {
110 match self {
111 AddressSize::_8Bit => 0b00,
112 AddressSize::_16Bit => 0b01,
113 AddressSize::_24bit => 0b10,
114 AddressSize::_32bit => 0b11,
115 }
116 }
117}
118
119#[derive(Copy, Clone)]
120pub enum ChipSelectHightTime {
121 _1Cycle,
122 _2Cycle,
123 _3Cycle,
124 _4Cycle,
125 _5Cycle,
126 _6Cycle,
127 _7Cycle,
128 _8Cycle,
129}
130
131impl Into<u8> for ChipSelectHightTime {
132 fn into(self) -> u8 {
133 match self {
134 ChipSelectHightTime::_1Cycle => 0,
135 ChipSelectHightTime::_2Cycle => 1,
136 ChipSelectHightTime::_3Cycle => 2,
137 ChipSelectHightTime::_4Cycle => 3,
138 ChipSelectHightTime::_5Cycle => 4,
139 ChipSelectHightTime::_6Cycle => 5,
140 ChipSelectHightTime::_7Cycle => 6,
141 ChipSelectHightTime::_8Cycle => 7,
142 }
143 }
144}
145
146#[derive(Copy, Clone)]
147pub enum FIFOThresholdLevel {
148 _1Bytes,
149 _2Bytes,
150 _3Bytes,
151 _4Bytes,
152 _5Bytes,
153 _6Bytes,
154 _7Bytes,
155 _8Bytes,
156 _9Bytes,
157 _10Bytes,
158 _11Bytes,
159 _12Bytes,
160 _13Bytes,
161 _14Bytes,
162 _15Bytes,
163 _16Bytes,
164 _17Bytes,
165 _18Bytes,
166 _19Bytes,
167 _20Bytes,
168 _21Bytes,
169 _22Bytes,
170 _23Bytes,
171 _24Bytes,
172 _25Bytes,
173 _26Bytes,
174 _27Bytes,
175 _28Bytes,
176 _29Bytes,
177 _30Bytes,
178 _31Bytes,
179 _32Bytes,
180}
181
182impl Into<u8> for FIFOThresholdLevel {
183 fn into(self) -> u8 {
184 match self {
185 FIFOThresholdLevel::_1Bytes => 0,
186 FIFOThresholdLevel::_2Bytes => 1,
187 FIFOThresholdLevel::_3Bytes => 2,
188 FIFOThresholdLevel::_4Bytes => 3,
189 FIFOThresholdLevel::_5Bytes => 4,
190 FIFOThresholdLevel::_6Bytes => 5,
191 FIFOThresholdLevel::_7Bytes => 6,
192 FIFOThresholdLevel::_8Bytes => 7,
193 FIFOThresholdLevel::_9Bytes => 8,
194 FIFOThresholdLevel::_10Bytes => 9,
195 FIFOThresholdLevel::_11Bytes => 10,
196 FIFOThresholdLevel::_12Bytes => 11,
197 FIFOThresholdLevel::_13Bytes => 12,
198 FIFOThresholdLevel::_14Bytes => 13,
199 FIFOThresholdLevel::_15Bytes => 14,
200 FIFOThresholdLevel::_16Bytes => 15,
201 FIFOThresholdLevel::_17Bytes => 16,
202 FIFOThresholdLevel::_18Bytes => 17,
203 FIFOThresholdLevel::_19Bytes => 18,
204 FIFOThresholdLevel::_20Bytes => 19,
205 FIFOThresholdLevel::_21Bytes => 20,
206 FIFOThresholdLevel::_22Bytes => 21,
207 FIFOThresholdLevel::_23Bytes => 22,
208 FIFOThresholdLevel::_24Bytes => 23,
209 FIFOThresholdLevel::_25Bytes => 24,
210 FIFOThresholdLevel::_26Bytes => 25,
211 FIFOThresholdLevel::_27Bytes => 26,
212 FIFOThresholdLevel::_28Bytes => 27,
213 FIFOThresholdLevel::_29Bytes => 28,
214 FIFOThresholdLevel::_30Bytes => 29,
215 FIFOThresholdLevel::_31Bytes => 30,
216 FIFOThresholdLevel::_32Bytes => 31,
217 }
218 }
219}
220
221#[derive(Copy, Clone)]
222pub enum DummyCycles {
223 _0,
224 _1,
225 _2,
226 _3,
227 _4,
228 _5,
229 _6,
230 _7,
231 _8,
232 _9,
233 _10,
234 _11,
235 _12,
236 _13,
237 _14,
238 _15,
239 _16,
240 _17,
241 _18,
242 _19,
243 _20,
244 _21,
245 _22,
246 _23,
247 _24,
248 _25,
249 _26,
250 _27,
251 _28,
252 _29,
253 _30,
254 _31,
255}
256
257impl Into<u8> for DummyCycles {
258 fn into(self) -> u8 {
259 match self {
260 DummyCycles::_0 => 0,
261 DummyCycles::_1 => 1,
262 DummyCycles::_2 => 2,
263 DummyCycles::_3 => 3,
264 DummyCycles::_4 => 4,
265 DummyCycles::_5 => 5,
266 DummyCycles::_6 => 6,
267 DummyCycles::_7 => 7,
268 DummyCycles::_8 => 8,
269 DummyCycles::_9 => 9,
270 DummyCycles::_10 => 10,
271 DummyCycles::_11 => 11,
272 DummyCycles::_12 => 12,
273 DummyCycles::_13 => 13,
274 DummyCycles::_14 => 14,
275 DummyCycles::_15 => 15,
276 DummyCycles::_16 => 16,
277 DummyCycles::_17 => 17,
278 DummyCycles::_18 => 18,
279 DummyCycles::_19 => 19,
280 DummyCycles::_20 => 20,
281 DummyCycles::_21 => 21,
282 DummyCycles::_22 => 22,
283 DummyCycles::_23 => 23,
284 DummyCycles::_24 => 24,
285 DummyCycles::_25 => 25,
286 DummyCycles::_26 => 26,
287 DummyCycles::_27 => 27,
288 DummyCycles::_28 => 28,
289 DummyCycles::_29 => 29,
290 DummyCycles::_30 => 30,
291 DummyCycles::_31 => 31,
292 }
293 }
294}
diff --git a/embassy-stm32/src/qspi/mod.rs b/embassy-stm32/src/qspi/mod.rs
new file mode 100644
index 000000000..f33319620
--- /dev/null
+++ b/embassy-stm32/src/qspi/mod.rs
@@ -0,0 +1,338 @@
1#![macro_use]
2
3pub mod enums;
4
5use embassy_hal_common::{into_ref, PeripheralRef};
6use enums::*;
7
8use crate::dma::TransferOptions;
9use crate::gpio::sealed::AFType;
10use crate::gpio::AnyPin;
11use crate::pac::quadspi::Quadspi as Regs;
12use crate::rcc::RccPeripheral;
13use crate::{peripherals, Peripheral};
14
15pub struct TransferConfig {
16 /// Instraction width (IMODE)
17 pub iwidth: QspiWidth,
18 /// Address width (ADMODE)
19 pub awidth: QspiWidth,
20 /// Data width (DMODE)
21 pub dwidth: QspiWidth,
22 /// Instruction Id
23 pub instruction: u8,
24 /// Flash memory address
25 pub address: Option<u32>,
26 /// Number of dummy cycles (DCYC)
27 pub dummy: DummyCycles,
28 /// Length of data
29 pub data_len: Option<usize>,
30}
31
32impl Default for TransferConfig {
33 fn default() -> Self {
34 Self {
35 iwidth: QspiWidth::NONE,
36 awidth: QspiWidth::NONE,
37 dwidth: QspiWidth::NONE,
38 instruction: 0,
39 address: None,
40 dummy: DummyCycles::_0,
41 data_len: None,
42 }
43 }
44}
45
46pub struct Config {
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.
49 pub memory_size: MemorySize,
50 /// Address size (8/16/24/32-bit)
51 pub address_size: AddressSize,
52 /// Scalar factor for generating CLK [0-255]
53 pub prescaler: u8,
54 /// Number of bytes to trigger FIFO threshold flag.
55 pub fifo_threshold: FIFOThresholdLevel,
56 /// Minimum number of cycles that chip select must be high between issued commands
57 pub cs_high_time: ChipSelectHightTime,
58}
59
60impl Default for Config {
61 fn default() -> Self {
62 Self {
63 memory_size: MemorySize::Other(0),
64 address_size: AddressSize::_24bit,
65 prescaler: 128,
66 fifo_threshold: FIFOThresholdLevel::_17Bytes,
67 cs_high_time: ChipSelectHightTime::_5Cycle,
68 }
69 }
70}
71
72#[allow(dead_code)]
73pub struct Qspi<'d, T: Instance, Dma> {
74 _peri: PeripheralRef<'d, T>,
75 sck: Option<PeripheralRef<'d, AnyPin>>,
76 d0: Option<PeripheralRef<'d, AnyPin>>,
77 d1: Option<PeripheralRef<'d, AnyPin>>,
78 d2: Option<PeripheralRef<'d, AnyPin>>,
79 d3: Option<PeripheralRef<'d, AnyPin>>,
80 nss: Option<PeripheralRef<'d, AnyPin>>,
81 dma: PeripheralRef<'d, Dma>,
82 config: Config,
83}
84
85impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> {
86 pub fn new(
87 peri: impl Peripheral<P = T> + 'd,
88 d0: impl Peripheral<P = impl D0Pin<T>> + 'd,
89 d1: impl Peripheral<P = impl D1Pin<T>> + 'd,
90 d2: impl Peripheral<P = impl D2Pin<T>> + 'd,
91 d3: impl Peripheral<P = impl D3Pin<T>> + 'd,
92 sck: impl Peripheral<P = impl SckPin<T>> + 'd,
93 nss: impl Peripheral<P = impl NSSPin<T>> + 'd,
94 dma: impl Peripheral<P = Dma> + 'd,
95 config: Config,
96 ) -> Self {
97 into_ref!(peri, d0, d1, d2, d3, sck, nss);
98
99 unsafe {
100 sck.set_as_af(sck.af_num(), AFType::OutputPushPull);
101 sck.set_speed(crate::gpio::Speed::VeryHigh);
102 nss.set_as_af(nss.af_num(), AFType::OutputPushPull);
103 nss.set_speed(crate::gpio::Speed::VeryHigh);
104 d0.set_as_af(d0.af_num(), AFType::OutputPushPull);
105 d0.set_speed(crate::gpio::Speed::VeryHigh);
106 d1.set_as_af(d1.af_num(), AFType::OutputPushPull);
107 d1.set_speed(crate::gpio::Speed::VeryHigh);
108 d2.set_as_af(d2.af_num(), AFType::OutputPushPull);
109 d2.set_speed(crate::gpio::Speed::VeryHigh);
110 d3.set_as_af(d3.af_num(), AFType::OutputPushPull);
111 d3.set_speed(crate::gpio::Speed::VeryHigh);
112 }
113
114 Self::new_inner(
115 peri,
116 Some(d0.map_into()),
117 Some(d1.map_into()),
118 Some(d2.map_into()),
119 Some(d3.map_into()),
120 Some(sck.map_into()),
121 Some(nss.map_into()),
122 dma,
123 config,
124 )
125 }
126
127 fn new_inner(
128 peri: impl Peripheral<P = T> + 'd,
129 d0: Option<PeripheralRef<'d, AnyPin>>,
130 d1: Option<PeripheralRef<'d, AnyPin>>,
131 d2: Option<PeripheralRef<'d, AnyPin>>,
132 d3: Option<PeripheralRef<'d, AnyPin>>,
133 sck: Option<PeripheralRef<'d, AnyPin>>,
134 nss: Option<PeripheralRef<'d, AnyPin>>,
135 dma: impl Peripheral<P = Dma> + 'd,
136 config: Config,
137 ) -> Self {
138 into_ref!(peri, dma);
139
140 T::enable();
141 unsafe {
142 T::REGS.cr().write(|w| w.set_fthres(config.fifo_threshold.into()));
143
144 while T::REGS.sr().read().busy() {}
145
146 T::REGS.cr().write(|w| {
147 w.set_prescaler(config.prescaler);
148 w.set_en(true);
149 });
150 T::REGS.dcr().write(|w| {
151 w.set_fsize(config.memory_size.into());
152 w.set_csht(config.cs_high_time.into());
153 w.set_ckmode(false);
154 });
155 }
156
157 Self {
158 _peri: peri,
159 sck,
160 d0,
161 d1,
162 d2,
163 d3,
164 nss,
165 dma,
166 config,
167 }
168 }
169
170 pub fn command(&mut self, transaction: TransferConfig) {
171 unsafe {
172 T::REGS.cr().modify(|v| v.set_dmaen(false));
173 self.setup_transaction(QspiMode::IndirectWrite, &transaction);
174
175 while !T::REGS.sr().read().tcf() {}
176 T::REGS.fcr().modify(|v| v.set_ctcf(true));
177 }
178 }
179
180 pub fn blocking_read(&mut self, buf: &mut [u8], transaction: TransferConfig) {
181 unsafe {
182 T::REGS.cr().modify(|v| v.set_dmaen(false));
183 self.setup_transaction(QspiMode::IndirectWrite, &transaction);
184
185 if let Some(len) = transaction.data_len {
186 let current_ar = T::REGS.ar().read().address();
187 T::REGS.ccr().modify(|v| {
188 v.set_fmode(QspiMode::IndirectRead.into());
189 });
190 T::REGS.ar().write(|v| {
191 v.set_address(current_ar);
192 });
193
194 for idx in 0..len {
195 while !T::REGS.sr().read().tcf() && !T::REGS.sr().read().ftf() {}
196 buf[idx] = *(T::REGS.dr().ptr() as *mut u8);
197 }
198 }
199
200 while !T::REGS.sr().read().tcf() {}
201 T::REGS.fcr().modify(|v| v.set_ctcf(true));
202 }
203 }
204
205 pub fn blocking_write(&mut self, buf: &[u8], transaction: TransferConfig) {
206 unsafe {
207 T::REGS.cr().modify(|v| v.set_dmaen(false));
208 self.setup_transaction(QspiMode::IndirectWrite, &transaction);
209
210 if let Some(len) = transaction.data_len {
211 T::REGS.ccr().modify(|v| {
212 v.set_fmode(QspiMode::IndirectWrite.into());
213 });
214
215 for idx in 0..len {
216 while !T::REGS.sr().read().ftf() {}
217 *(T::REGS.dr().ptr() as *mut u8) = buf[idx];
218 }
219 }
220
221 while !T::REGS.sr().read().tcf() {}
222 T::REGS.fcr().modify(|v| v.set_ctcf(true));
223 }
224 }
225
226 pub fn blocking_read_dma(&mut self, buf: &mut [u8], transaction: TransferConfig)
227 where
228 Dma: QuadDma<T>,
229 {
230 unsafe {
231 self.setup_transaction(QspiMode::IndirectWrite, &transaction);
232
233 let request = self.dma.request();
234 let options = TransferOptions::default();
235
236 T::REGS.ccr().modify(|v| {
237 v.set_fmode(QspiMode::IndirectRead.into());
238 });
239 let current_ar = T::REGS.ar().read().address();
240 T::REGS.ar().write(|v| {
241 v.set_address(current_ar);
242 });
243
244 self.dma
245 .start_read(request, T::REGS.dr().ptr() as *mut u8, buf, options);
246
247 T::REGS.cr().modify(|v| v.set_dmaen(true));
248
249 while self.dma.is_running() {}
250 }
251 }
252
253 pub fn blocking_write_dma(&mut self, buf: &[u8], transaction: TransferConfig)
254 where
255 Dma: QuadDma<T>,
256 {
257 unsafe {
258 self.setup_transaction(QspiMode::IndirectWrite, &transaction);
259
260 let request = self.dma.request();
261 let options = TransferOptions::default();
262
263 T::REGS.ccr().modify(|v| {
264 v.set_fmode(QspiMode::IndirectWrite.into());
265 });
266
267 self.dma
268 .start_write(request, buf, T::REGS.dr().ptr() as *mut u8, options);
269
270 T::REGS.cr().modify(|v| v.set_dmaen(true));
271
272 while self.dma.is_running() {}
273 }
274 }
275
276 fn setup_transaction(&mut self, fmode: QspiMode, transaction: &TransferConfig) {
277 unsafe {
278 T::REGS.fcr().modify(|v| {
279 v.set_csmf(true);
280 v.set_ctcf(true);
281 v.set_ctef(true);
282 v.set_ctof(true);
283 });
284
285 while T::REGS.sr().read().busy() {}
286
287 if let Some(len) = transaction.data_len {
288 T::REGS.dlr().write(|v| v.set_dl(len as u32 - 1));
289 }
290
291 T::REGS.ccr().write(|v| {
292 v.set_fmode(fmode.into());
293 v.set_imode(transaction.iwidth.into());
294 v.set_instruction(transaction.instruction);
295 v.set_admode(transaction.awidth.into());
296 v.set_adsize(self.config.address_size.into());
297 v.set_dmode(transaction.dwidth.into());
298 v.set_abmode(QspiWidth::NONE.into());
299 v.set_dcyc(transaction.dummy.into());
300 });
301
302 if let Some(addr) = transaction.address {
303 T::REGS.ar().write(|v| {
304 v.set_address(addr);
305 });
306 }
307 }
308 }
309}
310
311pub(crate) mod sealed {
312 use super::*;
313
314 pub trait Instance {
315 const REGS: Regs;
316 }
317}
318
319pub trait Instance: Peripheral<P = Self> + sealed::Instance + RccPeripheral {}
320
321pin_trait!(SckPin, Instance);
322pin_trait!(D0Pin, Instance);
323pin_trait!(D1Pin, Instance);
324pin_trait!(D2Pin, Instance);
325pin_trait!(D3Pin, Instance);
326pin_trait!(NSSPin, Instance);
327
328dma_trait!(QuadDma, Instance);
329
330foreach_peripheral!(
331 (quadspi, $inst:ident) => {
332 impl sealed::Instance for peripherals::$inst {
333 const REGS: Regs = crate::pac::$inst;
334 }
335
336 impl Instance for peripherals::$inst {}
337 };
338);