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