diff options
| author | Rick Rogers <[email protected]> | 2025-01-31 18:12:30 -0500 |
|---|---|---|
| committer | Matt Johnston <[email protected]> | 2025-04-04 15:36:33 +0800 |
| commit | 6d384a1a39f586c86cabe912fef639336cdc1ac7 (patch) | |
| tree | b1f5f7f037b95e2871a4832e791055376dc62a7c | |
| parent | b2d9203af77821931dc79a70d4c42c2a03d82c27 (diff) | |
introduce stm32h7rs xspi
| -rw-r--r-- | embassy-stm32/build.rs | 78 | ||||
| -rw-r--r-- | embassy-stm32/src/lib.rs | 2 | ||||
| -rw-r--r-- | embassy-stm32/src/xspi/enums.rs | 385 | ||||
| -rw-r--r-- | embassy-stm32/src/xspi/mod.rs | 1427 |
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; | |||
| 127 | pub mod usb; | 127 | pub mod usb; |
| 128 | #[cfg(iwdg)] | 128 | #[cfg(iwdg)] |
| 129 | pub mod wdg; | 129 | pub mod wdg; |
| 130 | #[cfg(xspi)] | ||
| 131 | pub 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. |
| 132 | pub(crate) mod _generated { | 134 | pub(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)] | ||
| 4 | pub(crate) enum XspiMode { | ||
| 5 | IndirectWrite, | ||
| 6 | IndirectRead, | ||
| 7 | AutoPolling, | ||
| 8 | MemoryMapped, | ||
| 9 | } | ||
| 10 | |||
| 11 | impl 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)] | ||
| 25 | pub 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 | |||
| 38 | impl 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)] | ||
| 53 | pub enum FlashSelection { | ||
| 54 | /// Bank 1 | ||
| 55 | Flash1, | ||
| 56 | /// Bank 2 | ||
| 57 | Flash2, | ||
| 58 | } | ||
| 59 | |||
| 60 | impl 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)] | ||
| 73 | pub enum WrapSize { | ||
| 74 | None, | ||
| 75 | _16Bytes, | ||
| 76 | _32Bytes, | ||
| 77 | _64Bytes, | ||
| 78 | _128Bytes, | ||
| 79 | } | ||
| 80 | |||
| 81 | impl 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)] | ||
| 97 | pub enum MemoryType { | ||
| 98 | Micron, | ||
| 99 | Macronix, | ||
| 100 | Standard, | ||
| 101 | MacronixRam, | ||
| 102 | HyperBusMemory, | ||
| 103 | HyperBusRegister, | ||
| 104 | } | ||
| 105 | |||
| 106 | impl 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)] | ||
| 122 | pub 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 | |||
| 149 | impl 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)] | ||
| 182 | pub 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 | |||
| 193 | impl 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)] | ||
| 207 | pub enum ChipSelectHighTime { | ||
| 208 | _1Cycle, | ||
| 209 | _2Cycle, | ||
| 210 | _3Cycle, | ||
| 211 | _4Cycle, | ||
| 212 | _5Cycle, | ||
| 213 | _6Cycle, | ||
| 214 | _7Cycle, | ||
| 215 | _8Cycle, | ||
| 216 | } | ||
| 217 | |||
| 218 | impl 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)] | ||
| 236 | pub 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 | |||
| 271 | impl 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)] | ||
| 313 | pub 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 | |||
| 348 | impl 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 | |||
| 6 | pub mod enums; | ||
| 7 | |||
| 8 | use core::marker::PhantomData; | ||
| 9 | |||
| 10 | use embassy_embedded_hal::{GetConfig, SetConfig}; | ||
| 11 | use embassy_hal_internal::{into_ref, PeripheralRef}; | ||
| 12 | pub use enums::*; | ||
| 13 | |||
| 14 | use crate::dma::{word, ChannelAndRequest}; | ||
| 15 | use crate::gpio::{AfType, AnyPin, OutputType, Pull, SealedPin as _, Speed}; | ||
| 16 | use crate::mode::{Async, Blocking, Mode as PeriMode}; | ||
| 17 | use crate::pac::xspi::{vals::*, Xspi as Regs}; | ||
| 18 | #[cfg(xspim_v2_1)] | ||
| 19 | use crate::pac::xspim::Xspim; | ||
| 20 | use crate::rcc::{self, RccPeripheral}; | ||
| 21 | use crate::{peripherals, Peripheral}; | ||
| 22 | |||
| 23 | /// XPSI driver config. | ||
| 24 | #[derive(Clone, Copy)] | ||
| 25 | pub 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 | |||
| 61 | impl 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. | ||
| 82 | pub 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 | |||
| 119 | impl 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))] | ||
| 148 | pub 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. | ||
| 158 | pub 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 | |||
| 187 | impl<'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 | |||
| 689 | impl<'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 | |||
| 912 | impl<'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 | |||
| 1280 | impl<'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 | |||
| 1308 | fn 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)] | ||
| 1319 | pub(crate) trait SealedXspimInstance { | ||
| 1320 | const SPIM_REGS: Xspim; | ||
| 1321 | const SPI_IDX: u8; | ||
| 1322 | } | ||
| 1323 | |||
| 1324 | /// XSPI instance trait. | ||
| 1325 | pub(crate) trait SealedInstance { | ||
| 1326 | const REGS: Regs; | ||
| 1327 | } | ||
| 1328 | |||
| 1329 | /// XSPI instance trait. | ||
| 1330 | #[cfg(xspim_v2_1)] | ||
| 1331 | #[allow(private_bounds)] | ||
| 1332 | pub trait Instance: Peripheral<P = Self> + SealedInstance + RccPeripheral + SealedXspimInstance {} | ||
| 1333 | |||
| 1334 | /// XSPI instance trait. | ||
| 1335 | #[cfg(not(xspim_v2_1))] | ||
| 1336 | #[allow(private_bounds)] | ||
| 1337 | pub trait Instance: Peripheral<P = Self> + SealedInstance + RccPeripheral {} | ||
| 1338 | |||
| 1339 | pin_trait!(D0Pin, Instance); | ||
| 1340 | pin_trait!(D1Pin, Instance); | ||
| 1341 | pin_trait!(D2Pin, Instance); | ||
| 1342 | pin_trait!(D3Pin, Instance); | ||
| 1343 | pin_trait!(D4Pin, Instance); | ||
| 1344 | pin_trait!(D5Pin, Instance); | ||
| 1345 | pin_trait!(D6Pin, Instance); | ||
| 1346 | pin_trait!(D7Pin, Instance); | ||
| 1347 | pin_trait!(D8Pin, Instance); | ||
| 1348 | pin_trait!(D9Pin, Instance); | ||
| 1349 | pin_trait!(D10Pin, Instance); | ||
| 1350 | pin_trait!(D11Pin, Instance); | ||
| 1351 | pin_trait!(D12Pin, Instance); | ||
| 1352 | pin_trait!(D13Pin, Instance); | ||
| 1353 | pin_trait!(D14Pin, Instance); | ||
| 1354 | pin_trait!(D15Pin, Instance); | ||
| 1355 | pin_trait!(DQS0Pin, Instance); | ||
| 1356 | pin_trait!(DQS1Pin, Instance); | ||
| 1357 | pin_trait!(NCS1Pin, Instance); | ||
| 1358 | pin_trait!(NCS2Pin, Instance); | ||
| 1359 | pin_trait!(CLKPin, Instance); | ||
| 1360 | pin_trait!(NCLKPin, Instance); | ||
| 1361 | dma_trait!(XDma, Instance); | ||
| 1362 | |||
| 1363 | // Hard-coded the xspi index, for SPIM | ||
| 1364 | #[cfg(xspim_v2_1)] | ||
| 1365 | impl 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)] | ||
| 1372 | impl 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)] | ||
| 1378 | foreach_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))] | ||
| 1389 | foreach_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 | |||
| 1399 | impl<'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 | |||
| 1408 | impl<'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)] | ||
| 1417 | pub trait Word: word::Word {} | ||
| 1418 | |||
| 1419 | macro_rules! impl_word { | ||
| 1420 | ($T:ty) => { | ||
| 1421 | impl Word for $T {} | ||
| 1422 | }; | ||
| 1423 | } | ||
| 1424 | |||
| 1425 | impl_word!(u8); | ||
| 1426 | impl_word!(u16); | ||
| 1427 | impl_word!(u32); | ||
