aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRick Rogers <[email protected]>2025-01-31 18:12:30 -0500
committerMatt Johnston <[email protected]>2025-04-04 15:36:33 +0800
commit6d384a1a39f586c86cabe912fef639336cdc1ac7 (patch)
treeb1f5f7f037b95e2871a4832e791055376dc62a7c
parentb2d9203af77821931dc79a70d4c42c2a03d82c27 (diff)
introduce stm32h7rs xspi
-rw-r--r--embassy-stm32/build.rs78
-rw-r--r--embassy-stm32/src/lib.rs2
-rw-r--r--embassy-stm32/src/xspi/enums.rs385
-rw-r--r--embassy-stm32/src/xspi/mod.rs1427
4 files changed, 1892 insertions, 0 deletions
diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs
index 798133162..13ef74f16 100644
--- a/embassy-stm32/build.rs
+++ b/embassy-stm32/build.rs
@@ -116,6 +116,7 @@ fn main() {
116 "peri_usb_otg_fs", 116 "peri_usb_otg_fs",
117 "peri_usb_otg_hs", 117 "peri_usb_otg_hs",
118 "peri_octospi2", 118 "peri_octospi2",
119 "peri_xspi2",
119 ]); 120 ]);
120 cfgs.declare_all(&["mco", "mco1", "mco2"]); 121 cfgs.declare_all(&["mco", "mco1", "mco2"]);
121 122
@@ -1098,6 +1099,72 @@ fn main() {
1098 (("octospim", "P2_NCS"), quote!(crate::ospi::NSSPin)), 1099 (("octospim", "P2_NCS"), quote!(crate::ospi::NSSPin)),
1099 (("octospim", "P2_CLK"), quote!(crate::ospi::SckPin)), 1100 (("octospim", "P2_CLK"), quote!(crate::ospi::SckPin)),
1100 (("octospim", "P2_NCLK"), quote!(crate::ospi::NckPin)), 1101 (("octospim", "P2_NCLK"), quote!(crate::ospi::NckPin)),
1102 (("xspi", "IO0"), quote!(crate::xspi::D0Pin)),
1103 (("xspi", "IO1"), quote!(crate::xspi::D1Pin)),
1104 (("xspi", "IO2"), quote!(crate::xspi::D2Pin)),
1105 (("xspi", "IO3"), quote!(crate::xspi::D3Pin)),
1106 (("xspi", "IO4"), quote!(crate::xspi::D4Pin)),
1107 (("xspi", "IO5"), quote!(crate::xspi::D5Pin)),
1108 (("xspi", "IO6"), quote!(crate::xspi::D6Pin)),
1109 (("xspi", "IO7"), quote!(crate::xspi::D7Pin)),
1110 (("xspi", "IO8"), quote!(crate::xspi::D8Pin)),
1111 (("xspi", "IO9"), quote!(crate::xspi::D9Pin)),
1112 (("xspi", "IO10"), quote!(crate::xspi::D10Pin)),
1113 (("xspi", "IO11"), quote!(crate::xspi::D11Pin)),
1114 (("xspi", "IO12"), quote!(crate::xspi::D12Pin)),
1115 (("xspi", "IO13"), quote!(crate::xspi::D13Pin)),
1116 (("xspi", "IO14"), quote!(crate::xspi::D14Pin)),
1117 (("xspi", "IO15"), quote!(crate::xspi::D15Pin)),
1118 (("xspi", "DQS0"), quote!(crate::xspi::DQS0Pin)),
1119 (("xspi", "DQS1"), quote!(crate::xspi::DQS1Pin)),
1120 (("xspi", "NCS1"), quote!(crate::xspi::NCS1Pin)),
1121 (("xspi", "NCS2"), quote!(crate::xspi::NCS2Pin)),
1122 (("xspi", "CLK"), quote!(crate::xspi::CLKPin)),
1123 (("xspi", "NCLK"), quote!(crate::xspi::NCLKPin)),
1124 (("xspim", "P1_IO0"), quote!(crate::xspi::D0Pin)),
1125 (("xspim", "P1_IO1"), quote!(crate::xspi::D1Pin)),
1126 (("xspim", "P1_IO2"), quote!(crate::xspi::D2Pin)),
1127 (("xspim", "P1_IO3"), quote!(crate::xspi::D3Pin)),
1128 (("xspim", "P1_IO4"), quote!(crate::xspi::D4Pin)),
1129 (("xspim", "P1_IO5"), quote!(crate::xspi::D5Pin)),
1130 (("xspim", "P1_IO6"), quote!(crate::xspi::D6Pin)),
1131 (("xspim", "P1_IO7"), quote!(crate::xspi::D7Pin)),
1132 (("xspim", "P1_IO8"), quote!(crate::xspi::D8Pin)),
1133 (("xspim", "P1_IO9"), quote!(crate::xspi::D9Pin)),
1134 (("xspim", "P1_IO10"), quote!(crate::xspi::D10Pin)),
1135 (("xspim", "P1_IO11"), quote!(crate::xspi::D11Pin)),
1136 (("xspim", "P1_IO12"), quote!(crate::xspi::D12Pin)),
1137 (("xspim", "P1_IO13"), quote!(crate::xspi::D13Pin)),
1138 (("xspim", "P1_IO14"), quote!(crate::xspi::D14Pin)),
1139 (("xspim", "P1_IO15"), quote!(crate::xspi::D15Pin)),
1140 (("xspim", "P1_DQS0"), quote!(crate::xspi::DQS0Pin)),
1141 (("xspim", "P1_DQS1"), quote!(crate::xspi::DQS1Pin)),
1142 (("xspim", "P1_NCS1"), quote!(crate::xspi::NCS1Pin)),
1143 (("xspim", "P1_NCS2"), quote!(crate::xspi::NCS2Pin)),
1144 (("xspim", "P1_CLK"), quote!(crate::xspi::CLKPin)),
1145 (("xspim", "P1_NCLK"), quote!(crate::xspi::NCLKPin)),
1146 (("xspim", "P2_IO0"), quote!(crate::xspi::D0Pin)),
1147 (("xspim", "P2_IO1"), quote!(crate::xspi::D1Pin)),
1148 (("xspim", "P2_IO2"), quote!(crate::xspi::D2Pin)),
1149 (("xspim", "P2_IO3"), quote!(crate::xspi::D3Pin)),
1150 (("xspim", "P2_IO4"), quote!(crate::xspi::D4Pin)),
1151 (("xspim", "P2_IO5"), quote!(crate::xspi::D5Pin)),
1152 (("xspim", "P2_IO6"), quote!(crate::xspi::D6Pin)),
1153 (("xspim", "P2_IO7"), quote!(crate::xspi::D7Pin)),
1154 (("xspim", "P2_IO8"), quote!(crate::xspi::D8Pin)),
1155 (("xspim", "P2_IO9"), quote!(crate::xspi::D9Pin)),
1156 (("xspim", "P2_IO10"), quote!(crate::xspi::D10Pin)),
1157 (("xspim", "P2_IO11"), quote!(crate::xspi::D11Pin)),
1158 (("xspim", "P2_IO12"), quote!(crate::xspi::D12Pin)),
1159 (("xspim", "P2_IO13"), quote!(crate::xspi::D13Pin)),
1160 (("xspim", "P2_IO14"), quote!(crate::xspi::D14Pin)),
1161 (("xspim", "P2_IO15"), quote!(crate::xspi::D15Pin)),
1162 (("xspim", "P2_DQS0"), quote!(crate::xspi::DQS0Pin)),
1163 (("xspim", "P2_DQS1"), quote!(crate::xspi::DQS1Pin)),
1164 (("xspim", "P2_NCS1"), quote!(crate::xspi::NCS1Pin)),
1165 (("xspim", "P2_NCS2"), quote!(crate::xspi::NCS2Pin)),
1166 (("xspim", "P2_CLK"), quote!(crate::xspi::CLKPin)),
1167 (("xspim", "P2_NCLK"), quote!(crate::xspi::NCLKPin)),
1101 (("hspi", "IO0"), quote!(crate::hspi::D0Pin)), 1168 (("hspi", "IO0"), quote!(crate::hspi::D0Pin)),
1102 (("hspi", "IO1"), quote!(crate::hspi::D1Pin)), 1169 (("hspi", "IO1"), quote!(crate::hspi::D1Pin)),
1103 (("hspi", "IO2"), quote!(crate::hspi::D2Pin)), 1170 (("hspi", "IO2"), quote!(crate::hspi::D2Pin)),
@@ -1190,6 +1257,17 @@ fn main() {
1190 peri = format_ident!("{}", "OCTOSPI1"); 1257 peri = format_ident!("{}", "OCTOSPI1");
1191 } 1258 }
1192 1259
1260 // XSPIM is special
1261 if p.name == "XSPIM" {
1262 if pin.signal.starts_with("P1") {
1263 peri = format_ident!("{}", "XSPI1");
1264 } else if pin.signal.starts_with("P2") {
1265 peri = format_ident!("{}", "XSPI2");
1266 } else {
1267 panic! {"malformed XSPIM pin: {:?}", pin}
1268 }
1269 }
1270
1193 g.extend(quote! { 1271 g.extend(quote! {
1194 pin_trait_impl!(#tr, #peri, #pin_name, #af); 1272 pin_trait_impl!(#tr, #peri, #pin_name, #af);
1195 }) 1273 })
diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs
index 4d7aac81f..226293a9d 100644
--- a/embassy-stm32/src/lib.rs
+++ b/embassy-stm32/src/lib.rs
@@ -127,6 +127,8 @@ pub mod usart;
127pub mod usb; 127pub mod usb;
128#[cfg(iwdg)] 128#[cfg(iwdg)]
129pub mod wdg; 129pub mod wdg;
130#[cfg(xspi)]
131pub mod xspi;
130 132
131// This must go last, so that it sees all the impl_foo! macros defined earlier. 133// This must go last, so that it sees all the impl_foo! macros defined earlier.
132pub(crate) mod _generated { 134pub(crate) mod _generated {
diff --git a/embassy-stm32/src/xspi/enums.rs b/embassy-stm32/src/xspi/enums.rs
new file mode 100644
index 000000000..4214dde37
--- /dev/null
+++ b/embassy-stm32/src/xspi/enums.rs
@@ -0,0 +1,385 @@
1//! Enums used in Xspi configuration.
2#[allow(dead_code)]
3#[derive(Copy, Clone)]
4pub(crate) enum XspiMode {
5 IndirectWrite,
6 IndirectRead,
7 AutoPolling,
8 MemoryMapped,
9}
10
11impl Into<u8> for XspiMode {
12 fn into(self) -> u8 {
13 match self {
14 XspiMode::IndirectWrite => 0b00,
15 XspiMode::IndirectRead => 0b01,
16 XspiMode::AutoPolling => 0b10,
17 XspiMode::MemoryMapped => 0b11,
18 }
19 }
20}
21
22/// Xspi lane width
23#[allow(dead_code)]
24#[derive(Copy, Clone)]
25pub enum XspiWidth {
26 /// None
27 NONE,
28 /// Single lane
29 SING,
30 /// Dual lanes
31 DUAL,
32 /// Quad lanes
33 QUAD,
34 /// Eight lanes
35 OCTO,
36}
37
38impl Into<u8> for XspiWidth {
39 fn into(self) -> u8 {
40 match self {
41 XspiWidth::NONE => 0b00,
42 XspiWidth::SING => 0b01,
43 XspiWidth::DUAL => 0b10,
44 XspiWidth::QUAD => 0b11,
45 XspiWidth::OCTO => 0b100,
46 }
47 }
48}
49
50/// Flash bank selection
51#[allow(dead_code)]
52#[derive(Copy, Clone)]
53pub enum FlashSelection {
54 /// Bank 1
55 Flash1,
56 /// Bank 2
57 Flash2,
58}
59
60impl Into<bool> for FlashSelection {
61 fn into(self) -> bool {
62 match self {
63 FlashSelection::Flash1 => false,
64 FlashSelection::Flash2 => true,
65 }
66 }
67}
68
69/// Wrap Size
70#[allow(dead_code)]
71#[allow(missing_docs)]
72#[derive(Copy, Clone)]
73pub enum WrapSize {
74 None,
75 _16Bytes,
76 _32Bytes,
77 _64Bytes,
78 _128Bytes,
79}
80
81impl Into<u8> for WrapSize {
82 fn into(self) -> u8 {
83 match self {
84 WrapSize::None => 0x00,
85 WrapSize::_16Bytes => 0x02,
86 WrapSize::_32Bytes => 0x03,
87 WrapSize::_64Bytes => 0x04,
88 WrapSize::_128Bytes => 0x05,
89 }
90 }
91}
92
93/// Memory Type
94#[allow(missing_docs)]
95#[allow(dead_code)]
96#[derive(Copy, Clone)]
97pub enum MemoryType {
98 Micron,
99 Macronix,
100 Standard,
101 MacronixRam,
102 HyperBusMemory,
103 HyperBusRegister,
104}
105
106impl Into<u8> for MemoryType {
107 fn into(self) -> u8 {
108 match self {
109 MemoryType::Micron => 0x00,
110 MemoryType::Macronix => 0x01,
111 MemoryType::Standard => 0x02,
112 MemoryType::MacronixRam => 0x03,
113 MemoryType::HyperBusMemory => 0x04,
114 MemoryType::HyperBusRegister => 0x04,
115 }
116 }
117}
118
119/// Xspi memory size.
120#[allow(missing_docs)]
121#[derive(Copy, Clone)]
122pub enum MemorySize {
123 _1KiB,
124 _2KiB,
125 _4KiB,
126 _8KiB,
127 _16KiB,
128 _32KiB,
129 _64KiB,
130 _128KiB,
131 _256KiB,
132 _512KiB,
133 _1MiB,
134 _2MiB,
135 _4MiB,
136 _8MiB,
137 _16MiB,
138 _32MiB,
139 _64MiB,
140 _128MiB,
141 _256MiB,
142 _512MiB,
143 _1GiB,
144 _2GiB,
145 _4GiB,
146 Other(u8),
147}
148
149impl Into<u8> for MemorySize {
150 fn into(self) -> u8 {
151 match self {
152 MemorySize::_1KiB => 9,
153 MemorySize::_2KiB => 10,
154 MemorySize::_4KiB => 11,
155 MemorySize::_8KiB => 12,
156 MemorySize::_16KiB => 13,
157 MemorySize::_32KiB => 14,
158 MemorySize::_64KiB => 15,
159 MemorySize::_128KiB => 16,
160 MemorySize::_256KiB => 17,
161 MemorySize::_512KiB => 18,
162 MemorySize::_1MiB => 19,
163 MemorySize::_2MiB => 20,
164 MemorySize::_4MiB => 21,
165 MemorySize::_8MiB => 22,
166 MemorySize::_16MiB => 23,
167 MemorySize::_32MiB => 24,
168 MemorySize::_64MiB => 25,
169 MemorySize::_128MiB => 26,
170 MemorySize::_256MiB => 27,
171 MemorySize::_512MiB => 28,
172 MemorySize::_1GiB => 29,
173 MemorySize::_2GiB => 30,
174 MemorySize::_4GiB => 31,
175 MemorySize::Other(val) => val,
176 }
177 }
178}
179
180/// Xspi Address size
181#[derive(Copy, Clone)]
182pub enum AddressSize {
183 /// 8-bit address
184 _8Bit,
185 /// 16-bit address
186 _16Bit,
187 /// 24-bit address
188 _24bit,
189 /// 32-bit address
190 _32bit,
191}
192
193impl Into<u8> for AddressSize {
194 fn into(self) -> u8 {
195 match self {
196 AddressSize::_8Bit => 0b00,
197 AddressSize::_16Bit => 0b01,
198 AddressSize::_24bit => 0b10,
199 AddressSize::_32bit => 0b11,
200 }
201 }
202}
203
204/// Time the Chip Select line stays high.
205#[allow(missing_docs)]
206#[derive(Copy, Clone)]
207pub enum ChipSelectHighTime {
208 _1Cycle,
209 _2Cycle,
210 _3Cycle,
211 _4Cycle,
212 _5Cycle,
213 _6Cycle,
214 _7Cycle,
215 _8Cycle,
216}
217
218impl Into<u8> for ChipSelectHighTime {
219 fn into(self) -> u8 {
220 match self {
221 ChipSelectHighTime::_1Cycle => 0,
222 ChipSelectHighTime::_2Cycle => 1,
223 ChipSelectHighTime::_3Cycle => 2,
224 ChipSelectHighTime::_4Cycle => 3,
225 ChipSelectHighTime::_5Cycle => 4,
226 ChipSelectHighTime::_6Cycle => 5,
227 ChipSelectHighTime::_7Cycle => 6,
228 ChipSelectHighTime::_8Cycle => 7,
229 }
230 }
231}
232
233/// FIFO threshold.
234#[allow(missing_docs)]
235#[derive(Copy, Clone)]
236pub enum FIFOThresholdLevel {
237 _1Bytes,
238 _2Bytes,
239 _3Bytes,
240 _4Bytes,
241 _5Bytes,
242 _6Bytes,
243 _7Bytes,
244 _8Bytes,
245 _9Bytes,
246 _10Bytes,
247 _11Bytes,
248 _12Bytes,
249 _13Bytes,
250 _14Bytes,
251 _15Bytes,
252 _16Bytes,
253 _17Bytes,
254 _18Bytes,
255 _19Bytes,
256 _20Bytes,
257 _21Bytes,
258 _22Bytes,
259 _23Bytes,
260 _24Bytes,
261 _25Bytes,
262 _26Bytes,
263 _27Bytes,
264 _28Bytes,
265 _29Bytes,
266 _30Bytes,
267 _31Bytes,
268 _32Bytes,
269}
270
271impl Into<u8> for FIFOThresholdLevel {
272 fn into(self) -> u8 {
273 match self {
274 FIFOThresholdLevel::_1Bytes => 0,
275 FIFOThresholdLevel::_2Bytes => 1,
276 FIFOThresholdLevel::_3Bytes => 2,
277 FIFOThresholdLevel::_4Bytes => 3,
278 FIFOThresholdLevel::_5Bytes => 4,
279 FIFOThresholdLevel::_6Bytes => 5,
280 FIFOThresholdLevel::_7Bytes => 6,
281 FIFOThresholdLevel::_8Bytes => 7,
282 FIFOThresholdLevel::_9Bytes => 8,
283 FIFOThresholdLevel::_10Bytes => 9,
284 FIFOThresholdLevel::_11Bytes => 10,
285 FIFOThresholdLevel::_12Bytes => 11,
286 FIFOThresholdLevel::_13Bytes => 12,
287 FIFOThresholdLevel::_14Bytes => 13,
288 FIFOThresholdLevel::_15Bytes => 14,
289 FIFOThresholdLevel::_16Bytes => 15,
290 FIFOThresholdLevel::_17Bytes => 16,
291 FIFOThresholdLevel::_18Bytes => 17,
292 FIFOThresholdLevel::_19Bytes => 18,
293 FIFOThresholdLevel::_20Bytes => 19,
294 FIFOThresholdLevel::_21Bytes => 20,
295 FIFOThresholdLevel::_22Bytes => 21,
296 FIFOThresholdLevel::_23Bytes => 22,
297 FIFOThresholdLevel::_24Bytes => 23,
298 FIFOThresholdLevel::_25Bytes => 24,
299 FIFOThresholdLevel::_26Bytes => 25,
300 FIFOThresholdLevel::_27Bytes => 26,
301 FIFOThresholdLevel::_28Bytes => 27,
302 FIFOThresholdLevel::_29Bytes => 28,
303 FIFOThresholdLevel::_30Bytes => 29,
304 FIFOThresholdLevel::_31Bytes => 30,
305 FIFOThresholdLevel::_32Bytes => 31,
306 }
307 }
308}
309
310/// Dummy cycle count
311#[allow(missing_docs)]
312#[derive(Copy, Clone)]
313pub enum DummyCycles {
314 _0,
315 _1,
316 _2,
317 _3,
318 _4,
319 _5,
320 _6,
321 _7,
322 _8,
323 _9,
324 _10,
325 _11,
326 _12,
327 _13,
328 _14,
329 _15,
330 _16,
331 _17,
332 _18,
333 _19,
334 _20,
335 _21,
336 _22,
337 _23,
338 _24,
339 _25,
340 _26,
341 _27,
342 _28,
343 _29,
344 _30,
345 _31,
346}
347
348impl Into<u8> for DummyCycles {
349 fn into(self) -> u8 {
350 match self {
351 DummyCycles::_0 => 0,
352 DummyCycles::_1 => 1,
353 DummyCycles::_2 => 2,
354 DummyCycles::_3 => 3,
355 DummyCycles::_4 => 4,
356 DummyCycles::_5 => 5,
357 DummyCycles::_6 => 6,
358 DummyCycles::_7 => 7,
359 DummyCycles::_8 => 8,
360 DummyCycles::_9 => 9,
361 DummyCycles::_10 => 10,
362 DummyCycles::_11 => 11,
363 DummyCycles::_12 => 12,
364 DummyCycles::_13 => 13,
365 DummyCycles::_14 => 14,
366 DummyCycles::_15 => 15,
367 DummyCycles::_16 => 16,
368 DummyCycles::_17 => 17,
369 DummyCycles::_18 => 18,
370 DummyCycles::_19 => 19,
371 DummyCycles::_20 => 20,
372 DummyCycles::_21 => 21,
373 DummyCycles::_22 => 22,
374 DummyCycles::_23 => 23,
375 DummyCycles::_24 => 24,
376 DummyCycles::_25 => 25,
377 DummyCycles::_26 => 26,
378 DummyCycles::_27 => 27,
379 DummyCycles::_28 => 28,
380 DummyCycles::_29 => 29,
381 DummyCycles::_30 => 30,
382 DummyCycles::_31 => 31,
383 }
384 }
385}
diff --git a/embassy-stm32/src/xspi/mod.rs b/embassy-stm32/src/xspi/mod.rs
new file mode 100644
index 000000000..b2fdebe75
--- /dev/null
+++ b/embassy-stm32/src/xspi/mod.rs
@@ -0,0 +1,1427 @@
1//! XSPI Serial Peripheral Interface
2//!
3
4#![macro_use]
5
6pub mod enums;
7
8use core::marker::PhantomData;
9
10use embassy_embedded_hal::{GetConfig, SetConfig};
11use embassy_hal_internal::{into_ref, PeripheralRef};
12pub use enums::*;
13
14use crate::dma::{word, ChannelAndRequest};
15use crate::gpio::{AfType, AnyPin, OutputType, Pull, SealedPin as _, Speed};
16use crate::mode::{Async, Blocking, Mode as PeriMode};
17use crate::pac::xspi::{vals::*, Xspi as Regs};
18#[cfg(xspim_v2_1)]
19use crate::pac::xspim::Xspim;
20use crate::rcc::{self, RccPeripheral};
21use crate::{peripherals, Peripheral};
22
23/// XPSI driver config.
24#[derive(Clone, Copy)]
25pub struct Config {
26 /// Fifo threshold used by the peripheral to generate the interrupt indicating data
27 /// or space is available in the FIFO
28 pub fifo_threshold: FIFOThresholdLevel,
29 /// Indicates the type of external device connected
30 pub memory_type: MemoryType, // Need to add an additional enum to provide this public interface
31 /// Defines the size of the external device connected to the XSPI corresponding
32 /// to the number of address bits required to access the device
33 pub device_size: MemorySize,
34 /// Sets the minimum number of clock cycles that the chip select signal must be held high
35 /// between commands
36 pub chip_select_high_time: ChipSelectHighTime,
37 /// Enables the free running clock
38 pub free_running_clock: bool,
39 /// Sets the clock level when the device is not selected
40 pub clock_mode: bool,
41 /// Indicates the wrap size corresponding to the external device configuration
42 pub wrap_size: WrapSize,
43 /// Specified the prescaler factor used for generating the external clock based
44 /// on the AHB clock
45 pub clock_prescaler: u8,
46 /// Allows the delay of 1/2 cycle the data sampling to account for external
47 /// signal delays
48 pub sample_shifting: bool,
49 /// Allows hold to 1/4 cycle the data
50 pub delay_hold_quarter_cycle: bool,
51 /// Enables the transaction boundary feature and defines the boundary to release
52 /// the chip select
53 pub chip_select_boundary: u8,
54 /// Enables communication regulation feature. Chip select is released when the other
55 /// XSpi requests access to the bus
56 pub max_transfer: u8,
57 /// Enables the refresh feature, chip select is released every refresh + 1 clock cycles
58 pub refresh: u32,
59}
60
61impl Default for Config {
62 fn default() -> Self {
63 Self {
64 fifo_threshold: FIFOThresholdLevel::_16Bytes, // 32 bytes FIFO, half capacity
65 memory_type: MemoryType::Micron,
66 device_size: MemorySize::Other(0),
67 chip_select_high_time: ChipSelectHighTime::_5Cycle,
68 free_running_clock: false,
69 clock_mode: false,
70 wrap_size: WrapSize::None,
71 clock_prescaler: 0,
72 sample_shifting: false,
73 delay_hold_quarter_cycle: false,
74 chip_select_boundary: 0, // Acceptable range 0 to 31
75 max_transfer: 0,
76 refresh: 0,
77 }
78 }
79}
80
81/// XSPI transfer configuration.
82pub struct TransferConfig {
83 /// Instruction width (IMODE)
84 pub iwidth: XspiWidth,
85 /// Instruction Id
86 pub instruction: Option<u32>,
87 /// Number of Instruction Bytes
88 pub isize: AddressSize,
89 /// Instruction Double Transfer rate enable
90 pub idtr: bool,
91
92 /// Address width (ADMODE)
93 pub adwidth: XspiWidth,
94 /// Device memory address
95 pub address: Option<u32>,
96 /// Number of Address Bytes
97 pub adsize: AddressSize,
98 /// Address Double Transfer rate enable
99 pub addtr: bool,
100
101 /// Alternate bytes width (ABMODE)
102 pub abwidth: XspiWidth,
103 /// Alternate Bytes
104 pub alternate_bytes: Option<u32>,
105 /// Number of Alternate Bytes
106 pub absize: AddressSize,
107 /// Alternate Bytes Double Transfer rate enable
108 pub abdtr: bool,
109
110 /// Data width (DMODE)
111 pub dwidth: XspiWidth,
112 /// Data buffer
113 pub ddtr: bool,
114
115 /// Number of dummy cycles (DCYC)
116 pub dummy: DummyCycles,
117}
118
119impl Default for TransferConfig {
120 fn default() -> Self {
121 Self {
122 iwidth: XspiWidth::NONE,
123 instruction: None,
124 isize: AddressSize::_8Bit,
125 idtr: false,
126
127 adwidth: XspiWidth::NONE,
128 address: None,
129 adsize: AddressSize::_8Bit,
130 addtr: false,
131
132 abwidth: XspiWidth::NONE,
133 alternate_bytes: None,
134 absize: AddressSize::_8Bit,
135 abdtr: false,
136
137 dwidth: XspiWidth::NONE,
138 ddtr: false,
139
140 dummy: DummyCycles::_0,
141 }
142 }
143}
144
145/// Error used for Xspi implementation
146#[derive(Debug)]
147#[cfg_attr(feature = "defmt", derive(defmt::Format))]
148pub enum XspiError {
149 /// Peripheral configuration is invalid
150 InvalidConfiguration,
151 /// Operation configuration is invalid
152 InvalidCommand,
153 /// Size zero buffer passed to instruction
154 EmptyBuffer,
155}
156
157/// XSPI driver.
158pub struct Xspi<'d, T: Instance, M: PeriMode> {
159 _peri: PeripheralRef<'d, T>,
160 clk: Option<PeripheralRef<'d, AnyPin>>,
161 d0: Option<PeripheralRef<'d, AnyPin>>,
162 d1: Option<PeripheralRef<'d, AnyPin>>,
163 d2: Option<PeripheralRef<'d, AnyPin>>,
164 d3: Option<PeripheralRef<'d, AnyPin>>,
165 d4: Option<PeripheralRef<'d, AnyPin>>,
166 d5: Option<PeripheralRef<'d, AnyPin>>,
167 d6: Option<PeripheralRef<'d, AnyPin>>,
168 d7: Option<PeripheralRef<'d, AnyPin>>,
169 d8: Option<PeripheralRef<'d, AnyPin>>,
170 d9: Option<PeripheralRef<'d, AnyPin>>,
171 d10: Option<PeripheralRef<'d, AnyPin>>,
172 d11: Option<PeripheralRef<'d, AnyPin>>,
173 d12: Option<PeripheralRef<'d, AnyPin>>,
174 d13: Option<PeripheralRef<'d, AnyPin>>,
175 d14: Option<PeripheralRef<'d, AnyPin>>,
176 d15: Option<PeripheralRef<'d, AnyPin>>,
177 ncs1: Option<PeripheralRef<'d, AnyPin>>,
178 ncs2: Option<PeripheralRef<'d, AnyPin>>,
179 dqs0: Option<PeripheralRef<'d, AnyPin>>,
180 dqs1: Option<PeripheralRef<'d, AnyPin>>,
181 dma: Option<ChannelAndRequest<'d>>,
182 _phantom: PhantomData<M>,
183 config: Config,
184 width: XspiWidth,
185}
186
187impl<'d, T: Instance, M: PeriMode> Xspi<'d, T, M> {
188 /// Enter memory mode.
189 /// The Input `read_config` is used to configure the read operation in memory mode
190 pub fn enable_memory_mapped_mode(
191 &mut self,
192 read_config: TransferConfig,
193 write_config: TransferConfig,
194 ) -> Result<(), XspiError> {
195 // Use configure command to set read config
196 self.configure_command(&read_config, None)?;
197
198 let reg = T::REGS;
199 while reg.xspi_sr().read().busy() {}
200
201 reg.xspi_ccr().modify(|r| {
202 r.set_dqse(XspiCcrDqse::B_0X0);
203 });
204
205 // Set wrting configurations, there are separate registers for write configurations in memory mapped mode
206 reg.xspi_wccr().modify(|w| {
207 w.set_imode(XspiWccrImode::from_bits(write_config.iwidth.into()));
208 let idtr = match write_config.idtr {
209 true => XspiWccrIdtr::B_0X1,
210 false => XspiWccrIdtr::B_0X0,
211 };
212 w.set_idtr(idtr);
213 w.set_isize(XspiWccrIsize::from_bits(write_config.isize.into()));
214
215 w.set_admode(XspiWccrAdmode::from_bits(write_config.adwidth.into()));
216 let addtr = match write_config.idtr {
217 true => XspiWccrAddtr::B_0X1,
218 false => XspiWccrAddtr::B_0X0,
219 };
220 w.set_addtr(addtr);
221 w.set_adsize(XspiWccrAdsize::from_bits(write_config.adsize.into()));
222
223 w.set_dmode(XspiWccrDmode::from_bits(write_config.dwidth.into()));
224 let ddtr = match write_config.idtr {
225 true => XspiWccrDdtr::B_0X1,
226 false => XspiWccrDdtr::B_0X0,
227 };
228 w.set_ddtr(ddtr);
229
230 w.set_abmode(XspiWccrAbmode::from_bits(write_config.abwidth.into()));
231 w.set_dqse(XspiWccrDqse::B_0X1);
232 });
233
234 reg.xspi_wtcr().modify(|w| w.set_dcyc(write_config.dummy.into()));
235
236 // Enable memory mapped mode
237 reg.xspi_cr().modify(|r| {
238 r.set_fmode(Fmode::B_0X3);
239 r.set_tcen(Tcen::B_0X0);
240 });
241 Ok(())
242 }
243
244 /// Quit from memory mapped mode
245 pub fn disable_memory_mapped_mode(&mut self) {
246 let reg = T::REGS;
247
248 reg.xspi_cr().modify(|r| {
249 r.set_fmode(Fmode::B_0X0);
250 r.set_abort(Abort::B_0X1);
251 r.set_dmaen(Dmaen::B_0X0);
252 r.set_en(En::B_0X0);
253 });
254
255 // Clear transfer complete flag
256 reg.xspi_fcr().write(|w| w.set_ctcf(true));
257
258 // Re-enable ospi
259 reg.xspi_cr().modify(|r| {
260 r.set_en(En::B_0X1);
261 });
262 }
263
264 fn new_inner(
265 peri: impl Peripheral<P = T> + 'd,
266 d0: Option<PeripheralRef<'d, AnyPin>>,
267 d1: Option<PeripheralRef<'d, AnyPin>>,
268 d2: Option<PeripheralRef<'d, AnyPin>>,
269 d3: Option<PeripheralRef<'d, AnyPin>>,
270 d4: Option<PeripheralRef<'d, AnyPin>>,
271 d5: Option<PeripheralRef<'d, AnyPin>>,
272 d6: Option<PeripheralRef<'d, AnyPin>>,
273 d7: Option<PeripheralRef<'d, AnyPin>>,
274 d8: Option<PeripheralRef<'d, AnyPin>>,
275 d9: Option<PeripheralRef<'d, AnyPin>>,
276 d10: Option<PeripheralRef<'d, AnyPin>>,
277 d11: Option<PeripheralRef<'d, AnyPin>>,
278 d12: Option<PeripheralRef<'d, AnyPin>>,
279 d13: Option<PeripheralRef<'d, AnyPin>>,
280 d14: Option<PeripheralRef<'d, AnyPin>>,
281 d15: Option<PeripheralRef<'d, AnyPin>>,
282 clk: Option<PeripheralRef<'d, AnyPin>>,
283 ncs1: Option<PeripheralRef<'d, AnyPin>>,
284 ncs2: Option<PeripheralRef<'d, AnyPin>>,
285 dqs0: Option<PeripheralRef<'d, AnyPin>>,
286 dqs1: Option<PeripheralRef<'d, AnyPin>>,
287 dma: Option<ChannelAndRequest<'d>>,
288 config: Config,
289 width: XspiWidth,
290 dual_quad: bool,
291 ) -> Self {
292 into_ref!(peri);
293
294 #[cfg(xspim_v2_1)]
295 {
296 // RCC for xspim should be enabled before writing register
297 crate::pac::RCC.ahb5enr().modify(|w| w.set_iomngren(true));
298
299 // Disable XSPI peripheral first
300 T::REGS.xspi_cr().modify(|w| {
301 w.set_en(En::B_0X0);
302 });
303
304 // XSPI IO Manager has been enabled before
305 T::SPIM_REGS.xspim_cr().modify(|w| {
306 w.set_muxen(false);
307 w.set_req2ack_time(0xff);
308 });
309 }
310
311 // System configuration
312 rcc::enable_and_reset::<T>();
313 while T::REGS.xspi_sr().read().busy() {}
314
315 // Device configuration
316 T::REGS.xspi_dcr1().modify(|w| {
317 w.set_devsize(config.device_size.into());
318 w.set_mtyp(Mtyp::from_bits(config.memory_type.into()));
319 w.set_csht(Csht::from_bits(config.chip_select_high_time.into()));
320 w.set_frck(Frck::B_0X0);
321 w.set_ckmode(Ckmode::from_bits(config.clock_mode.into()));
322 });
323
324 T::REGS.xspi_dcr2().modify(|w| {
325 w.set_wrapsize(Wrapsize::from_bits(config.wrap_size.into()));
326 });
327
328 T::REGS.xspi_dcr3().modify(|w| {
329 w.set_csbound(Csbound::from_bits(config.chip_select_boundary.into()));
330 #[cfg(xspi_v2_1)]
331 {
332 w.set_maxtran(Maxtran::from_bits(config.max_transfer.into()));
333 }
334 });
335
336 T::REGS.xspi_dcr4().modify(|w| {
337 w.set_refresh(Refresh::from_bits(config.refresh.into()));
338 });
339
340 T::REGS.xspi_cr().modify(|w| {
341 w.set_fthres(Fthres::from_bits(config.fifo_threshold.into()));
342 });
343
344 // Wait for busy flag to clear
345 while T::REGS.xspi_sr().read().busy() {}
346
347 T::REGS.xspi_dcr2().modify(|w| {
348 w.set_prescaler(Prescaler::from_bits(config.clock_prescaler.into()));
349 });
350
351 T::REGS.xspi_cr().modify(|w| {
352 w.set_dmm(match dual_quad {
353 true => Dmm::B_0X1,
354 false => Dmm::B_0X0,
355 });
356 });
357
358 T::REGS.xspi_tcr().modify(|w| {
359 w.set_sshift(match config.sample_shifting {
360 true => XspiTcrSshift::B_0X1,
361 false => XspiTcrSshift::B_0X0,
362 });
363 w.set_dhqc(match config.delay_hold_quarter_cycle {
364 true => XspiTcrDhqc::B_0X1,
365 false => XspiTcrDhqc::B_0X0,
366 });
367 });
368
369 // Enable peripheral
370 T::REGS.xspi_cr().modify(|w| {
371 w.set_en(En::B_0X1);
372 });
373
374 // Free running clock needs to be set after peripheral enable
375 if config.free_running_clock {
376 T::REGS.xspi_dcr1().modify(|w| {
377 w.set_frck(match config.free_running_clock {
378 true => Frck::B_0X1,
379 false => Frck::B_0X0,
380 });
381 });
382 }
383
384 Self {
385 _peri: peri,
386 clk,
387 d0,
388 d1,
389 d2,
390 d3,
391 d4,
392 d5,
393 d6,
394 d7,
395 d8,
396 d9,
397 d10,
398 d11,
399 d12,
400 d13,
401 d14,
402 d15,
403 ncs1,
404 ncs2,
405 dqs0,
406 dqs1,
407 dma,
408 _phantom: PhantomData,
409 config,
410 width,
411 }
412 }
413
414 // Function to configure the peripheral for the requested command
415 fn configure_command(&mut self, command: &TransferConfig, data_len: Option<usize>) -> Result<(), XspiError> {
416 // Check that transaction doesn't use more than hardware initialized pins
417 if <enums::XspiWidth as Into<u8>>::into(command.iwidth) > <enums::XspiWidth as Into<u8>>::into(self.width)
418 || <enums::XspiWidth as Into<u8>>::into(command.adwidth) > <enums::XspiWidth as Into<u8>>::into(self.width)
419 || <enums::XspiWidth as Into<u8>>::into(command.abwidth) > <enums::XspiWidth as Into<u8>>::into(self.width)
420 || <enums::XspiWidth as Into<u8>>::into(command.dwidth) > <enums::XspiWidth as Into<u8>>::into(self.width)
421 {
422 return Err(XspiError::InvalidCommand);
423 }
424
425 T::REGS.xspi_cr().modify(|w| {
426 w.set_fmode(0.into());
427 });
428
429 // Configure alternate bytes
430 if let Some(ab) = command.alternate_bytes {
431 T::REGS.xspi_abr().write(|v| v.set_alternate(ab));
432 T::REGS.xspi_ccr().modify(|w| {
433 w.set_abmode(XspiCcrAbmode::from_bits(command.abwidth.into()));
434 w.set_abdtr(XspiCcrAbdtr::from_bits(command.abdtr.into()));
435 w.set_absize(XspiCcrAbsize::from_bits(command.absize.into()));
436 })
437 }
438
439 // Configure dummy cycles
440 T::REGS.xspi_tcr().modify(|w| {
441 w.set_dcyc(command.dummy.into());
442 });
443
444 // Configure data
445 if let Some(data_length) = data_len {
446 T::REGS.xspi_dlr().write(|v| {
447 v.set_dl((data_length - 1) as u32);
448 })
449 } else {
450 T::REGS.xspi_dlr().write(|v| {
451 v.set_dl((0) as u32);
452 })
453 }
454
455 // Configure instruction/address/data modes
456 T::REGS.xspi_ccr().modify(|w| {
457 w.set_imode(XspiCcrImode::from_bits(command.iwidth.into()));
458 w.set_idtr(match command.idtr {
459 true => XspiCcrIdtr::B_0X1,
460 false => XspiCcrIdtr::B_0X0,
461 });
462 w.set_isize(XspiCcrIsize::from_bits(command.isize.into()));
463
464 w.set_admode(XspiCcrAdmode::from_bits(command.adwidth.into()));
465 w.set_addtr(match command.idtr {
466 true => XspiCcrAddtr::B_0X1,
467 false => XspiCcrAddtr::B_0X0,
468 });
469 w.set_adsize(XspiCcrAdsize::from_bits(command.adsize.into()));
470
471 w.set_dmode(XspiCcrDmode::from_bits(command.dwidth.into()));
472 w.set_ddtr(match command.ddtr {
473 true => XspiCcrDdtr::B_0X1,
474 false => XspiCcrDdtr::B_0X0,
475 });
476 });
477
478 // Set information required to initiate transaction
479 if let Some(instruction) = command.instruction {
480 if let Some(address) = command.address {
481 T::REGS.xspi_ir().write(|v| {
482 v.set_instruction(instruction);
483 });
484
485 T::REGS.xspi_ar().write(|v| {
486 v.set_address(address);
487 });
488 } else {
489 // Double check requirements for delay hold and sample shifting
490 // if let None = command.data_len {
491 // if self.config.delay_hold_quarter_cycle && command.idtr {
492 // T::REGS.xspi_ccr().modify(|w| {
493 // w.set_ddtr(true);
494 // });
495 // }
496 // }
497
498 warn!("instruction: {:#x}", instruction);
499 T::REGS.xspi_ir().write(|v| {
500 v.set_instruction(instruction);
501 });
502 }
503 } else {
504 if let Some(address) = command.address {
505 T::REGS.xspi_ar().write(|v| {
506 v.set_address(address);
507 });
508 } else {
509 // The only single phase transaction supported is instruction only
510 return Err(XspiError::InvalidCommand);
511 }
512 }
513
514 Ok(())
515 }
516
517 /// Function used to control or configure the target device without data transfer
518 pub fn blocking_command(&mut self, command: &TransferConfig) -> Result<(), XspiError> {
519 // Wait for peripheral to be free
520 while T::REGS.xspi_sr().read().busy() {}
521
522 // Need additional validation that command configuration doesn't have data set
523 self.configure_command(command, None)?;
524
525 // Transaction initiated by setting final configuration, i.e the instruction register
526 while !T::REGS.xspi_sr().read().tcf() {}
527 T::REGS.xspi_fcr().write(|w| {
528 w.set_ctcf(true);
529 });
530
531 Ok(())
532 }
533
534 /// Blocking read with byte by byte data transfer
535 pub fn blocking_read<W: Word>(&mut self, buf: &mut [W], transaction: TransferConfig) -> Result<(), XspiError> {
536 if buf.is_empty() {
537 return Err(XspiError::EmptyBuffer);
538 }
539
540 // Wait for peripheral to be free
541 while T::REGS.xspi_sr().read().busy() {}
542
543 // Ensure DMA is not enabled for this transaction
544 T::REGS.xspi_cr().modify(|w| {
545 w.set_dmaen(Dmaen::B_0X0);
546 });
547
548 // self.configure_command(&transaction, Some(buf.len()))?;
549 self.configure_command(&transaction, Some(buf.len())).unwrap();
550
551 let current_address = T::REGS.xspi_ar().read().address();
552 let current_instruction = T::REGS.xspi_ir().read().instruction();
553
554 // For a indirect read transaction, the transaction begins when the instruction/address is set
555 T::REGS
556 .xspi_cr()
557 .modify(|v| v.set_fmode(Fmode::from_bits(XspiMode::IndirectRead.into())));
558 if T::REGS.xspi_ccr().read().admode() == XspiCcrAdmode::B_0X0 {
559 T::REGS.xspi_ir().write(|v| v.set_instruction(current_instruction));
560 } else {
561 T::REGS.xspi_ar().write(|v| v.set_address(current_address));
562 }
563
564 for idx in 0..buf.len() {
565 while !T::REGS.xspi_sr().read().tcf() && !T::REGS.xspi_sr().read().ftf() {}
566 buf[idx] = unsafe { (T::REGS.xspi_dr().as_ptr() as *mut W).read_volatile() };
567 }
568
569 while !T::REGS.xspi_sr().read().tcf() {}
570 T::REGS.xspi_fcr().write(|v| v.set_ctcf(true));
571
572 Ok(())
573 }
574
575 /// Blocking write with byte by byte data transfer
576 pub fn blocking_write<W: Word>(&mut self, buf: &[W], transaction: TransferConfig) -> Result<(), XspiError> {
577 if buf.is_empty() {
578 return Err(XspiError::EmptyBuffer);
579 }
580
581 // Wait for peripheral to be free
582 while T::REGS.xspi_sr().read().busy() {}
583
584 T::REGS.xspi_cr().modify(|w| {
585 w.set_dmaen(Dmaen::B_0X0);
586 });
587
588 self.configure_command(&transaction, Some(buf.len()))?;
589
590 T::REGS
591 .xspi_cr()
592 .modify(|v| v.set_fmode(Fmode::from_bits(XspiMode::IndirectWrite.into())));
593
594 for idx in 0..buf.len() {
595 while !T::REGS.xspi_sr().read().ftf() {}
596 unsafe { (T::REGS.xspi_dr().as_ptr() as *mut W).write_volatile(buf[idx]) };
597 }
598
599 while !T::REGS.xspi_sr().read().tcf() {}
600 T::REGS.xspi_fcr().write(|v| v.set_ctcf(true));
601
602 Ok(())
603 }
604
605 /// Set new bus configuration
606 pub fn set_config(&mut self, config: &Config) {
607 // Wait for busy flag to clear
608 while T::REGS.xspi_sr().read().busy() {}
609
610 // Disable DMA channel while configuring the peripheral
611 T::REGS.xspi_cr().modify(|w| {
612 w.set_dmaen(Dmaen::B_0X0);
613 });
614
615 // Device configuration
616 T::REGS.xspi_dcr1().modify(|w| {
617 w.set_devsize(config.device_size.into());
618 w.set_mtyp(Mtyp::from_bits(config.memory_type.into()));
619 w.set_csht(Csht::from_bits(config.chip_select_high_time.into()));
620 w.set_frck(Frck::B_0X0);
621 w.set_ckmode(match config.clock_mode {
622 true => Ckmode::B_0X1,
623 false => Ckmode::B_0X0,
624 });
625 });
626
627 T::REGS.xspi_dcr2().modify(|w| {
628 w.set_wrapsize(Wrapsize::from_bits(config.wrap_size.into()));
629 });
630
631 T::REGS.xspi_dcr3().modify(|w| {
632 w.set_csbound(Csbound::from_bits(config.chip_select_boundary.into()));
633 #[cfg(xspi_v2_1)]
634 {
635 w.set_maxtran(Maxtran::from_bits(config.max_transfer.into()));
636 }
637 });
638
639 T::REGS.xspi_dcr4().modify(|w| {
640 w.set_refresh(Refresh::from_bits(config.refresh.into()));
641 });
642
643 T::REGS.xspi_cr().modify(|w| {
644 w.set_fthres(Fthres::from_bits(config.fifo_threshold.into()));
645 });
646
647 // Wait for busy flag to clear
648 while T::REGS.xspi_sr().read().busy() {}
649
650 T::REGS.xspi_dcr2().modify(|w| {
651 w.set_prescaler(Prescaler::from_bits(config.clock_prescaler.into()));
652 });
653
654 T::REGS.xspi_tcr().modify(|w| {
655 w.set_sshift(match config.sample_shifting {
656 true => XspiTcrSshift::B_0X1,
657 false => XspiTcrSshift::B_0X0,
658 });
659 w.set_dhqc(match config.delay_hold_quarter_cycle {
660 true => XspiTcrDhqc::B_0X1,
661 false => XspiTcrDhqc::B_0X0,
662 });
663 });
664
665 // Enable peripheral
666 T::REGS.xspi_cr().modify(|w| {
667 w.set_en(En::B_0X1);
668 });
669
670 // Free running clock needs to be set after peripheral enable
671 if config.free_running_clock {
672 T::REGS.xspi_dcr1().modify(|w| {
673 w.set_frck(match config.free_running_clock {
674 true => Frck::B_0X1,
675 false => Frck::B_0X0,
676 });
677 });
678 }
679
680 self.config = *config;
681 }
682
683 /// Get current configuration
684 pub fn get_config(&self) -> Config {
685 self.config
686 }
687}
688
689impl<'d, T: Instance> Xspi<'d, T, Blocking> {
690 /// Create new blocking XSPI driver for a single spi external chip
691 pub fn new_blocking_singlespi(
692 peri: impl Peripheral<P = T> + 'd,
693 clk: impl Peripheral<P = impl CLKPin<T>> + 'd,
694 d0: impl Peripheral<P = impl D0Pin<T>> + 'd,
695 d1: impl Peripheral<P = impl D1Pin<T>> + 'd,
696 ncs: impl Peripheral<P = impl NCS1Pin<T>> + 'd,
697 config: Config,
698 ) -> Self {
699 Self::new_inner(
700 peri,
701 new_pin!(d0, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
702 new_pin!(d1, AfType::input(Pull::None)),
703 None,
704 None,
705 None,
706 None,
707 None,
708 None,
709 None,
710 None,
711 None,
712 None,
713 None,
714 None,
715 None,
716 None,
717 new_pin!(clk, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
718 new_pin!(ncs, AfType::output(OutputType::OpenDrain, Speed::VeryHigh)),
719 None,
720 None,
721 None,
722 None,
723 config,
724 XspiWidth::SING,
725 false,
726 )
727 }
728
729 /// Create new blocking XSPI driver for a dualspi external chip
730 pub fn new_blocking_dualspi(
731 peri: impl Peripheral<P = T> + 'd,
732 clk: impl Peripheral<P = impl CLKPin<T>> + 'd,
733 d0: impl Peripheral<P = impl D0Pin<T>> + 'd,
734 d1: impl Peripheral<P = impl D1Pin<T>> + 'd,
735 ncs: impl Peripheral<P = impl NCS1Pin<T>> + 'd,
736 config: Config,
737 ) -> Self {
738 Self::new_inner(
739 peri,
740 new_pin!(d0, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
741 new_pin!(d1, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
742 None,
743 None,
744 None,
745 None,
746 None,
747 None,
748 None,
749 None,
750 None,
751 None,
752 None,
753 None,
754 None,
755 None,
756 new_pin!(clk, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
757 new_pin!(
758 ncs,
759 AfType::output_pull(OutputType::PushPull, Speed::VeryHigh, Pull::Up)
760 ),
761 None,
762 None,
763 None,
764 None,
765 config,
766 XspiWidth::DUAL,
767 false,
768 )
769 }
770
771 /// Create new blocking XSPI driver for a quadspi external chip
772 pub fn new_blocking_quadspi(
773 peri: impl Peripheral<P = T> + 'd,
774 clk: impl Peripheral<P = impl CLKPin<T>> + 'd,
775 d0: impl Peripheral<P = impl D0Pin<T>> + 'd,
776 d1: impl Peripheral<P = impl D1Pin<T>> + 'd,
777 d2: impl Peripheral<P = impl D2Pin<T>> + 'd,
778 d3: impl Peripheral<P = impl D3Pin<T>> + 'd,
779 ncs: impl Peripheral<P = impl NCS1Pin<T>> + 'd,
780 config: Config,
781 ) -> Self {
782 Self::new_inner(
783 peri,
784 new_pin!(d0, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
785 new_pin!(d1, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
786 new_pin!(d2, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
787 new_pin!(d3, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
788 None,
789 None,
790 None,
791 None,
792 None,
793 None,
794 None,
795 None,
796 None,
797 None,
798 None,
799 None,
800 new_pin!(clk, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
801 new_pin!(
802 ncs,
803 AfType::output_pull(OutputType::PushPull, Speed::VeryHigh, Pull::Up)
804 ),
805 None,
806 None,
807 None,
808 None,
809 config,
810 XspiWidth::QUAD,
811 false,
812 )
813 }
814
815 /// Create new blocking XSPI driver for two quadspi external chips
816 pub fn new_blocking_dualquadspi(
817 peri: impl Peripheral<P = T> + 'd,
818 clk: impl Peripheral<P = impl CLKPin<T>> + 'd,
819 d0: impl Peripheral<P = impl D0Pin<T>> + 'd,
820 d1: impl Peripheral<P = impl D1Pin<T>> + 'd,
821 d2: impl Peripheral<P = impl D2Pin<T>> + 'd,
822 d3: impl Peripheral<P = impl D3Pin<T>> + 'd,
823 d4: impl Peripheral<P = impl D4Pin<T>> + 'd,
824 d5: impl Peripheral<P = impl D5Pin<T>> + 'd,
825 d6: impl Peripheral<P = impl D6Pin<T>> + 'd,
826 d7: impl Peripheral<P = impl D7Pin<T>> + 'd,
827 ncs: impl Peripheral<P = impl NCS1Pin<T>> + 'd,
828 config: Config,
829 ) -> Self {
830 Self::new_inner(
831 peri,
832 new_pin!(d0, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
833 new_pin!(d1, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
834 new_pin!(d2, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
835 new_pin!(d3, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
836 new_pin!(d4, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
837 new_pin!(d5, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
838 new_pin!(d6, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
839 new_pin!(d7, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
840 None,
841 None,
842 None,
843 None,
844 None,
845 None,
846 None,
847 None,
848 new_pin!(clk, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
849 new_pin!(
850 ncs,
851 AfType::output_pull(OutputType::PushPull, Speed::VeryHigh, Pull::Up)
852 ),
853 None,
854 None,
855 None,
856 None,
857 config,
858 XspiWidth::QUAD,
859 true,
860 )
861 }
862
863 /// Create new blocking XSPI driver for xspi external chips
864 pub fn new_blocking_xspi(
865 peri: impl Peripheral<P = T> + 'd,
866 clk: impl Peripheral<P = impl CLKPin<T>> + 'd,
867 d0: impl Peripheral<P = impl D0Pin<T>> + 'd,
868 d1: impl Peripheral<P = impl D1Pin<T>> + 'd,
869 d2: impl Peripheral<P = impl D2Pin<T>> + 'd,
870 d3: impl Peripheral<P = impl D3Pin<T>> + 'd,
871 d4: impl Peripheral<P = impl D4Pin<T>> + 'd,
872 d5: impl Peripheral<P = impl D5Pin<T>> + 'd,
873 d6: impl Peripheral<P = impl D6Pin<T>> + 'd,
874 d7: impl Peripheral<P = impl D7Pin<T>> + 'd,
875 ncs: impl Peripheral<P = impl NCS1Pin<T>> + 'd,
876 config: Config,
877 ) -> Self {
878 Self::new_inner(
879 peri,
880 new_pin!(d0, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
881 new_pin!(d1, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
882 new_pin!(d2, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
883 new_pin!(d3, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
884 new_pin!(d4, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
885 new_pin!(d5, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
886 new_pin!(d6, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
887 new_pin!(d7, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
888 None,
889 None,
890 None,
891 None,
892 None,
893 None,
894 None,
895 None,
896 new_pin!(clk, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
897 new_pin!(
898 ncs,
899 AfType::output_pull(OutputType::PushPull, Speed::VeryHigh, Pull::Up)
900 ),
901 None,
902 None,
903 None,
904 None,
905 config,
906 XspiWidth::OCTO,
907 false,
908 )
909 }
910}
911
912impl<'d, T: Instance> Xspi<'d, T, Async> {
913 /// Create new blocking XSPI driver for a single spi external chip
914 pub fn new_singlespi(
915 peri: impl Peripheral<P = T> + 'd,
916 clk: impl Peripheral<P = impl CLKPin<T>> + 'd,
917 d0: impl Peripheral<P = impl D0Pin<T>> + 'd,
918 d1: impl Peripheral<P = impl D1Pin<T>> + 'd,
919 ncs: impl Peripheral<P = impl NCS1Pin<T>> + 'd,
920 dma: impl Peripheral<P = impl XDma<T>> + 'd,
921 config: Config,
922 ) -> Self {
923 Self::new_inner(
924 peri,
925 new_pin!(d0, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
926 new_pin!(d1, AfType::input(Pull::None)),
927 None,
928 None,
929 None,
930 None,
931 None,
932 None,
933 None,
934 None,
935 None,
936 None,
937 None,
938 None,
939 None,
940 None,
941 new_pin!(clk, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
942 new_pin!(ncs, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
943 None,
944 None,
945 None,
946 new_dma!(dma),
947 config,
948 XspiWidth::SING,
949 false,
950 )
951 }
952
953 /// Create new blocking XSPI driver for a dualspi external chip
954 pub fn new_dualspi(
955 peri: impl Peripheral<P = T> + 'd,
956 clk: impl Peripheral<P = impl CLKPin<T>> + 'd,
957 d0: impl Peripheral<P = impl D0Pin<T>> + 'd,
958 d1: impl Peripheral<P = impl D1Pin<T>> + 'd,
959 ncs: impl Peripheral<P = impl NCS1Pin<T>> + 'd,
960 dma: impl Peripheral<P = impl XDma<T>> + 'd,
961 config: Config,
962 ) -> Self {
963 Self::new_inner(
964 peri,
965 new_pin!(d0, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
966 new_pin!(d1, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
967 None,
968 None,
969 None,
970 None,
971 None,
972 None,
973 None,
974 None,
975 None,
976 None,
977 None,
978 None,
979 None,
980 None,
981 new_pin!(clk, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
982 new_pin!(
983 ncs,
984 AfType::output_pull(OutputType::PushPull, Speed::VeryHigh, Pull::Up)
985 ),
986 None,
987 None,
988 None,
989 new_dma!(dma),
990 config,
991 XspiWidth::DUAL,
992 false,
993 )
994 }
995
996 /// Create new blocking XSPI driver for a quadspi external chip
997 pub fn new_quadspi(
998 peri: impl Peripheral<P = T> + 'd,
999 clk: impl Peripheral<P = impl CLKPin<T>> + 'd,
1000 d0: impl Peripheral<P = impl D0Pin<T>> + 'd,
1001 d1: impl Peripheral<P = impl D1Pin<T>> + 'd,
1002 d2: impl Peripheral<P = impl D2Pin<T>> + 'd,
1003 d3: impl Peripheral<P = impl D3Pin<T>> + 'd,
1004 ncs: impl Peripheral<P = impl NCS1Pin<T>> + 'd,
1005 dma: impl Peripheral<P = impl XDma<T>> + 'd,
1006 config: Config,
1007 ) -> Self {
1008 Self::new_inner(
1009 peri,
1010 new_pin!(d0, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
1011 new_pin!(d1, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
1012 new_pin!(d2, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
1013 new_pin!(d3, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
1014 None,
1015 None,
1016 None,
1017 None,
1018 None,
1019 None,
1020 None,
1021 None,
1022 None,
1023 None,
1024 None,
1025 None,
1026 new_pin!(clk, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
1027 new_pin!(
1028 ncs,
1029 AfType::output_pull(OutputType::PushPull, Speed::VeryHigh, Pull::Up)
1030 ),
1031 None,
1032 None,
1033 None,
1034 new_dma!(dma),
1035 config,
1036 XspiWidth::QUAD,
1037 false,
1038 )
1039 }
1040
1041 /// Create new blocking XSPI driver for two quadspi external chips
1042 pub fn new_dualquadspi(
1043 peri: impl Peripheral<P = T> + 'd,
1044 clk: impl Peripheral<P = impl CLKPin<T>> + 'd,
1045 d0: impl Peripheral<P = impl D0Pin<T>> + 'd,
1046 d1: impl Peripheral<P = impl D1Pin<T>> + 'd,
1047 d2: impl Peripheral<P = impl D2Pin<T>> + 'd,
1048 d3: impl Peripheral<P = impl D3Pin<T>> + 'd,
1049 d4: impl Peripheral<P = impl D4Pin<T>> + 'd,
1050 d5: impl Peripheral<P = impl D5Pin<T>> + 'd,
1051 d6: impl Peripheral<P = impl D6Pin<T>> + 'd,
1052 d7: impl Peripheral<P = impl D7Pin<T>> + 'd,
1053 ncs: impl Peripheral<P = impl NCS1Pin<T>> + 'd,
1054 dma: impl Peripheral<P = impl XDma<T>> + 'd,
1055 config: Config,
1056 ) -> Self {
1057 Self::new_inner(
1058 peri,
1059 new_pin!(d0, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
1060 new_pin!(d1, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
1061 new_pin!(d2, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
1062 new_pin!(d3, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
1063 new_pin!(d4, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
1064 new_pin!(d5, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
1065 new_pin!(d6, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
1066 new_pin!(d7, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
1067 None,
1068 None,
1069 None,
1070 None,
1071 None,
1072 None,
1073 None,
1074 None,
1075 new_pin!(clk, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
1076 new_pin!(
1077 ncs,
1078 AfType::output_pull(OutputType::PushPull, Speed::VeryHigh, Pull::Up)
1079 ),
1080 None,
1081 None,
1082 None,
1083 new_dma!(dma),
1084 config,
1085 XspiWidth::QUAD,
1086 true,
1087 )
1088 }
1089
1090 /// Create new blocking XSPI driver for xspi external chips
1091 pub fn new_xspi(
1092 peri: impl Peripheral<P = T> + 'd,
1093 clk: impl Peripheral<P = impl CLKPin<T>> + 'd,
1094 d0: impl Peripheral<P = impl D0Pin<T>> + 'd,
1095 d1: impl Peripheral<P = impl D1Pin<T>> + 'd,
1096 d2: impl Peripheral<P = impl D2Pin<T>> + 'd,
1097 d3: impl Peripheral<P = impl D3Pin<T>> + 'd,
1098 d4: impl Peripheral<P = impl D4Pin<T>> + 'd,
1099 d5: impl Peripheral<P = impl D5Pin<T>> + 'd,
1100 d6: impl Peripheral<P = impl D6Pin<T>> + 'd,
1101 d7: impl Peripheral<P = impl D7Pin<T>> + 'd,
1102 ncs: impl Peripheral<P = impl NCS1Pin<T>> + 'd,
1103 dma: impl Peripheral<P = impl XDma<T>> + 'd,
1104 config: Config,
1105 ) -> Self {
1106 Self::new_inner(
1107 peri,
1108 new_pin!(d0, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
1109 new_pin!(d1, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
1110 new_pin!(d2, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
1111 new_pin!(d3, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
1112 new_pin!(d4, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
1113 new_pin!(d5, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
1114 new_pin!(d6, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
1115 new_pin!(d7, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
1116 None,
1117 None,
1118 None,
1119 None,
1120 None,
1121 None,
1122 None,
1123 None,
1124 new_pin!(clk, AfType::output(OutputType::PushPull, Speed::VeryHigh)),
1125 new_pin!(
1126 ncs,
1127 AfType::output_pull(OutputType::PushPull, Speed::VeryHigh, Pull::Up)
1128 ),
1129 None,
1130 None,
1131 None,
1132 new_dma!(dma),
1133 config,
1134 XspiWidth::OCTO,
1135 false,
1136 )
1137 }
1138
1139 /// Blocking read with DMA transfer
1140 pub fn blocking_read_dma<W: Word>(&mut self, buf: &mut [W], transaction: TransferConfig) -> Result<(), XspiError> {
1141 if buf.is_empty() {
1142 return Err(XspiError::EmptyBuffer);
1143 }
1144
1145 // Wait for peripheral to be free
1146 while T::REGS.xspi_sr().read().busy() {}
1147
1148 self.configure_command(&transaction, Some(buf.len()))?;
1149
1150 let current_address = T::REGS.xspi_ar().read().address();
1151 let current_instruction = T::REGS.xspi_ir().read().instruction();
1152
1153 // For a indirect read transaction, the transaction begins when the instruction/address is set
1154 T::REGS
1155 .xspi_cr()
1156 .modify(|v| v.set_fmode(Fmode::from_bits(XspiMode::IndirectRead.into())));
1157 if T::REGS.xspi_ccr().read().admode() == XspiCcrAdmode::B_0X0 {
1158 T::REGS.xspi_ir().write(|v| v.set_instruction(current_instruction));
1159 } else {
1160 T::REGS.xspi_ar().write(|v| v.set_address(current_address));
1161 }
1162
1163 let transfer = unsafe {
1164 self.dma
1165 .as_mut()
1166 .unwrap()
1167 .read(T::REGS.xspi_dr().as_ptr() as *mut W, buf, Default::default())
1168 };
1169
1170 T::REGS.xspi_cr().modify(|w| w.set_dmaen(Dmaen::B_0X1));
1171
1172 transfer.blocking_wait();
1173
1174 finish_dma(T::REGS);
1175
1176 Ok(())
1177 }
1178
1179 /// Blocking write with DMA transfer
1180 pub fn blocking_write_dma<W: Word>(&mut self, buf: &[W], transaction: TransferConfig) -> Result<(), XspiError> {
1181 if buf.is_empty() {
1182 return Err(XspiError::EmptyBuffer);
1183 }
1184
1185 // Wait for peripheral to be free
1186 while T::REGS.xspi_sr().read().busy() {}
1187
1188 self.configure_command(&transaction, Some(buf.len()))?;
1189 T::REGS
1190 .xspi_cr()
1191 .modify(|v| v.set_fmode(Fmode::from_bits(XspiMode::IndirectWrite.into())));
1192
1193 let transfer = unsafe {
1194 self.dma
1195 .as_mut()
1196 .unwrap()
1197 .write(buf, T::REGS.xspi_dr().as_ptr() as *mut W, Default::default())
1198 };
1199
1200 T::REGS.xspi_cr().modify(|w| w.set_dmaen(Dmaen::B_0X1));
1201
1202 transfer.blocking_wait();
1203
1204 finish_dma(T::REGS);
1205
1206 Ok(())
1207 }
1208
1209 /// Asynchronous read from external device
1210 pub async fn read<W: Word>(&mut self, buf: &mut [W], transaction: TransferConfig) -> Result<(), XspiError> {
1211 if buf.is_empty() {
1212 return Err(XspiError::EmptyBuffer);
1213 }
1214
1215 // Wait for peripheral to be free
1216 while T::REGS.xspi_sr().read().busy() {}
1217
1218 self.configure_command(&transaction, Some(buf.len()))?;
1219
1220 let current_address = T::REGS.xspi_ar().read().address();
1221 let current_instruction = T::REGS.xspi_ir().read().instruction();
1222
1223 // For a indirect read transaction, the transaction begins when the instruction/address is set
1224 T::REGS
1225 .xspi_cr()
1226 .modify(|v| v.set_fmode(Fmode::from_bits(XspiMode::IndirectRead.into())));
1227 if T::REGS.xspi_ccr().read().admode() == XspiCcrAdmode::B_0X0 {
1228 T::REGS.xspi_ir().write(|v| v.set_instruction(current_instruction));
1229 } else {
1230 T::REGS.xspi_ar().write(|v| v.set_address(current_address));
1231 }
1232
1233 let transfer = unsafe {
1234 self.dma
1235 .as_mut()
1236 .unwrap()
1237 .read(T::REGS.xspi_dr().as_ptr() as *mut W, buf, Default::default())
1238 };
1239
1240 T::REGS.xspi_cr().modify(|w| w.set_dmaen(Dmaen::B_0X1));
1241
1242 transfer.await;
1243
1244 finish_dma(T::REGS);
1245
1246 Ok(())
1247 }
1248
1249 /// Asynchronous write to external device
1250 pub async fn write<W: Word>(&mut self, buf: &[W], transaction: TransferConfig) -> Result<(), XspiError> {
1251 if buf.is_empty() {
1252 return Err(XspiError::EmptyBuffer);
1253 }
1254
1255 // Wait for peripheral to be free
1256 while T::REGS.xspi_sr().read().busy() {}
1257
1258 self.configure_command(&transaction, Some(buf.len()))?;
1259 T::REGS
1260 .xspi_cr()
1261 .modify(|v| v.set_fmode(Fmode::from_bits(XspiMode::IndirectWrite.into())));
1262
1263 let transfer = unsafe {
1264 self.dma
1265 .as_mut()
1266 .unwrap()
1267 .write(buf, T::REGS.xspi_dr().as_ptr() as *mut W, Default::default())
1268 };
1269
1270 T::REGS.xspi_cr().modify(|w| w.set_dmaen(Dmaen::B_0X1));
1271
1272 transfer.await;
1273
1274 finish_dma(T::REGS);
1275
1276 Ok(())
1277 }
1278}
1279
1280impl<'d, T: Instance, M: PeriMode> Drop for Xspi<'d, T, M> {
1281 fn drop(&mut self) {
1282 self.clk.as_ref().map(|x| x.set_as_disconnected());
1283 self.d0.as_ref().map(|x| x.set_as_disconnected());
1284 self.d1.as_ref().map(|x| x.set_as_disconnected());
1285 self.d2.as_ref().map(|x| x.set_as_disconnected());
1286 self.d3.as_ref().map(|x| x.set_as_disconnected());
1287 self.d4.as_ref().map(|x| x.set_as_disconnected());
1288 self.d5.as_ref().map(|x| x.set_as_disconnected());
1289 self.d6.as_ref().map(|x| x.set_as_disconnected());
1290 self.d7.as_ref().map(|x| x.set_as_disconnected());
1291 self.d8.as_ref().map(|x| x.set_as_disconnected());
1292 self.d9.as_ref().map(|x| x.set_as_disconnected());
1293 self.d10.as_ref().map(|x| x.set_as_disconnected());
1294 self.d11.as_ref().map(|x| x.set_as_disconnected());
1295 self.d12.as_ref().map(|x| x.set_as_disconnected());
1296 self.d13.as_ref().map(|x| x.set_as_disconnected());
1297 self.d14.as_ref().map(|x| x.set_as_disconnected());
1298 self.d15.as_ref().map(|x| x.set_as_disconnected());
1299 self.ncs1.as_ref().map(|x| x.set_as_disconnected());
1300 self.ncs2.as_ref().map(|x| x.set_as_disconnected());
1301 self.dqs0.as_ref().map(|x| x.set_as_disconnected());
1302 self.dqs1.as_ref().map(|x| x.set_as_disconnected());
1303
1304 rcc::disable::<T>();
1305 }
1306}
1307
1308fn finish_dma(regs: Regs) {
1309 while !regs.xspi_sr().read().tcf() {}
1310 regs.xspi_fcr().write(|v| v.set_ctcf(true));
1311
1312 regs.xspi_cr().modify(|w| {
1313 w.set_dmaen(Dmaen::B_0X0);
1314 });
1315}
1316
1317/// XSPI I/O manager instance trait.
1318#[cfg(xspim_v2_1)]
1319pub(crate) trait SealedXspimInstance {
1320 const SPIM_REGS: Xspim;
1321 const SPI_IDX: u8;
1322}
1323
1324/// XSPI instance trait.
1325pub(crate) trait SealedInstance {
1326 const REGS: Regs;
1327}
1328
1329/// XSPI instance trait.
1330#[cfg(xspim_v2_1)]
1331#[allow(private_bounds)]
1332pub trait Instance: Peripheral<P = Self> + SealedInstance + RccPeripheral + SealedXspimInstance {}
1333
1334/// XSPI instance trait.
1335#[cfg(not(xspim_v2_1))]
1336#[allow(private_bounds)]
1337pub trait Instance: Peripheral<P = Self> + SealedInstance + RccPeripheral {}
1338
1339pin_trait!(D0Pin, Instance);
1340pin_trait!(D1Pin, Instance);
1341pin_trait!(D2Pin, Instance);
1342pin_trait!(D3Pin, Instance);
1343pin_trait!(D4Pin, Instance);
1344pin_trait!(D5Pin, Instance);
1345pin_trait!(D6Pin, Instance);
1346pin_trait!(D7Pin, Instance);
1347pin_trait!(D8Pin, Instance);
1348pin_trait!(D9Pin, Instance);
1349pin_trait!(D10Pin, Instance);
1350pin_trait!(D11Pin, Instance);
1351pin_trait!(D12Pin, Instance);
1352pin_trait!(D13Pin, Instance);
1353pin_trait!(D14Pin, Instance);
1354pin_trait!(D15Pin, Instance);
1355pin_trait!(DQS0Pin, Instance);
1356pin_trait!(DQS1Pin, Instance);
1357pin_trait!(NCS1Pin, Instance);
1358pin_trait!(NCS2Pin, Instance);
1359pin_trait!(CLKPin, Instance);
1360pin_trait!(NCLKPin, Instance);
1361dma_trait!(XDma, Instance);
1362
1363// Hard-coded the xspi index, for SPIM
1364#[cfg(xspim_v2_1)]
1365impl SealedXspimInstance for peripherals::XSPI1 {
1366 const SPIM_REGS: Xspim = crate::pac::XSPIM;
1367 const SPI_IDX: u8 = 1;
1368}
1369
1370// #[cfg(all(xspim_v2_1, peri_xspi2))]
1371#[cfg(xspim_v2_1)]
1372impl SealedXspimInstance for peripherals::XSPI2 {
1373 const SPIM_REGS: Xspim = crate::pac::XSPIM;
1374 const SPI_IDX: u8 = 2;
1375}
1376
1377#[cfg(xspim_v2_1)]
1378foreach_peripheral!(
1379 (xspi, $inst:ident) => {
1380 impl SealedInstance for peripherals::$inst {
1381 const REGS: Regs = crate::pac::$inst;
1382 }
1383
1384 impl Instance for peripherals::$inst {}
1385 };
1386);
1387
1388#[cfg(not(xspim_v2_1))]
1389foreach_peripheral!(
1390 (xspi, $inst:ident) => {
1391 impl SealedInstance for peripherals::$inst {
1392 const REGS: Regs = crate::pac::$inst;
1393 }
1394
1395 impl Instance for peripherals::$inst {}
1396 };
1397);
1398
1399impl<'d, T: Instance, M: PeriMode> SetConfig for Xspi<'d, T, M> {
1400 type Config = Config;
1401 type ConfigError = ();
1402 fn set_config(&mut self, config: &Self::Config) -> Result<(), ()> {
1403 self.set_config(config);
1404 Ok(())
1405 }
1406}
1407
1408impl<'d, T: Instance, M: PeriMode> GetConfig for Xspi<'d, T, M> {
1409 type Config = Config;
1410 fn get_config(&self) -> Self::Config {
1411 self.get_config()
1412 }
1413}
1414
1415/// Word sizes usable for XSPI.
1416#[allow(private_bounds)]
1417pub trait Word: word::Word {}
1418
1419macro_rules! impl_word {
1420 ($T:ty) => {
1421 impl Word for $T {}
1422 };
1423}
1424
1425impl_word!(u8);
1426impl_word!(u16);
1427impl_word!(u32);