diff options
| author | Felipe Balbi <[email protected]> | 2025-04-03 08:47:25 -0700 |
|---|---|---|
| committer | Felipe Balbi <[email protected]> | 2025-04-09 09:37:45 -0700 |
| commit | aa9a16e569dfb56ce2b689733975f4d854af0b00 (patch) | |
| tree | 865ae0aa84bcb4c438463d34dd567ea07abe98e3 /embassy-imxrt | |
| parent | 0ec3e78c1bb0cdb20749cca4b294cb8a16e7fd43 (diff) | |
Add embassy-imxrt
Adds initial support for MIMXRT600 series MCUs from NXP. Subsequent
PRs will add more drivers.
Diffstat (limited to 'embassy-imxrt')
| -rw-r--r-- | embassy-imxrt/Cargo.toml | 84 | ||||
| -rw-r--r-- | embassy-imxrt/README.md | 59 | ||||
| -rw-r--r-- | embassy-imxrt/src/chips/mimxrt633s.rs | 389 | ||||
| -rw-r--r-- | embassy-imxrt/src/chips/mimxrt685s.rs | 388 | ||||
| -rw-r--r-- | embassy-imxrt/src/clocks.rs | 1687 | ||||
| -rw-r--r-- | embassy-imxrt/src/fmt.rs | 257 | ||||
| -rw-r--r-- | embassy-imxrt/src/gpio.rs | 1060 | ||||
| -rw-r--r-- | embassy-imxrt/src/iopctl.rs | 717 | ||||
| -rw-r--r-- | embassy-imxrt/src/lib.rs | 130 |
9 files changed, 4771 insertions, 0 deletions
diff --git a/embassy-imxrt/Cargo.toml b/embassy-imxrt/Cargo.toml new file mode 100644 index 000000000..38087bf77 --- /dev/null +++ b/embassy-imxrt/Cargo.toml | |||
| @@ -0,0 +1,84 @@ | |||
| 1 | [package] | ||
| 2 | name = "embassy-imxrt" | ||
| 3 | version = "0.1.0" | ||
| 4 | edition = "2021" | ||
| 5 | license = "MIT" | ||
| 6 | description = "Embassy Hardware Abstraction Layer (HAL) for the IMXRT microcontroller" | ||
| 7 | keywords = ["embedded", "async", "imxrt", "rt600", "embedded-hal"] | ||
| 8 | categories = ["embedded", "hardware-support", "no-std", "asynchronous"] | ||
| 9 | repository = "https://github.com/embassy-rs/embassy" | ||
| 10 | documentation = "https://docs.embassy.dev/embassy-imxrt" | ||
| 11 | |||
| 12 | [package.metadata.embassy_docs] | ||
| 13 | src_base = "https://github.com/embassy-rs/embassy/blob/embassy-imxrt-v$VERSION/embassy-imxrt/src/" | ||
| 14 | src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-imxrt/src/" | ||
| 15 | features = ["defmt", "unstable-pac"] | ||
| 16 | flavors = [ | ||
| 17 | { regex_feature = "mimxrt6.*", target = "thumbv8m.main-none-eabihf" } | ||
| 18 | ] | ||
| 19 | |||
| 20 | [package.metadata.docs.rs] | ||
| 21 | features = ["mimxrt685s", "defmt", "unstable-pac"] | ||
| 22 | rustdoc-args = ["--cfg", "docsrs"] | ||
| 23 | |||
| 24 | [features] | ||
| 25 | default = ["rt"] | ||
| 26 | |||
| 27 | ## Cortex-M runtime (enabled by default) | ||
| 28 | rt = [ | ||
| 29 | "mimxrt685s-pac?/rt", | ||
| 30 | "mimxrt633s-pac?/rt", | ||
| 31 | ] | ||
| 32 | |||
| 33 | ## Enable defmt | ||
| 34 | defmt = ["dep:defmt", "embassy-hal-internal/defmt", "embassy-sync/defmt", "mimxrt685s-pac?/defmt", "mimxrt633s-pac?/defmt"] | ||
| 35 | |||
| 36 | ## Reexport the PAC for the currently enabled chip at `embassy_imxrt::pac` (unstable) | ||
| 37 | unstable-pac = [] | ||
| 38 | |||
| 39 | # Features starting with `_` are for internal use only. They're not intended | ||
| 40 | # to be enabled by other crates, and are not covered by semver guarantees. | ||
| 41 | |||
| 42 | _mimxrt685s = [] | ||
| 43 | _mimxrt633s = ["_espi"] | ||
| 44 | |||
| 45 | # Peripherals | ||
| 46 | _espi = [] | ||
| 47 | |||
| 48 | #! ### Chip selection features | ||
| 49 | ## MIMXRT685S | ||
| 50 | mimxrt685s = ["mimxrt685s-pac", "_mimxrt685s"] | ||
| 51 | ## MIMXRT633S | ||
| 52 | mimxrt633s = ["mimxrt633s-pac", "_mimxrt633s"] | ||
| 53 | |||
| 54 | [dependencies] | ||
| 55 | embassy-sync = { version = "0.6.2", path = "../embassy-sync" } | ||
| 56 | embassy-hal-internal = { version = "0.2.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-3"] } | ||
| 57 | embassy-embedded-hal = { version = "0.3.0", path = "../embassy-embedded-hal", default-features = false } | ||
| 58 | embassy-futures = { version = "0.1.1", path = "../embassy-futures" } | ||
| 59 | |||
| 60 | defmt = { version = "1.0", optional = true } | ||
| 61 | log = { version = "0.4.14", optional = true } | ||
| 62 | nb = "1.0.0" | ||
| 63 | cfg-if = "1.0.0" | ||
| 64 | cortex-m-rt = ">=0.7.3,<0.8" | ||
| 65 | cortex-m = "0.7.6" | ||
| 66 | critical-section = "1.1" | ||
| 67 | embedded-io = { version = "0.6.1" } | ||
| 68 | embedded-io-async = { version = "0.6.1" } | ||
| 69 | rand_core = "0.6.4" | ||
| 70 | fixed = "1.23.1" | ||
| 71 | |||
| 72 | embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = [ | ||
| 73 | "unproven", | ||
| 74 | ] } | ||
| 75 | embedded-hal-1 = { package = "embedded-hal", version = "1.0" } | ||
| 76 | embedded-hal-async = { version = "1.0" } | ||
| 77 | embedded-hal-nb = { version = "1.0" } | ||
| 78 | |||
| 79 | document-features = "0.2.7" | ||
| 80 | paste = "1.0" | ||
| 81 | |||
| 82 | # PACs | ||
| 83 | mimxrt685s-pac = { version = "0.4.0", optional = true, features = ["rt", "critical-section"] } | ||
| 84 | mimxrt633s-pac = { version = "0.4.0", optional = true, features = ["rt", "critical-section"] } | ||
diff --git a/embassy-imxrt/README.md b/embassy-imxrt/README.md new file mode 100644 index 000000000..cfdfb8ce2 --- /dev/null +++ b/embassy-imxrt/README.md | |||
| @@ -0,0 +1,59 @@ | |||
| 1 | # Embassy iMXRT HAL | ||
| 2 | |||
| 3 | ## Introduction | ||
| 4 | |||
| 5 | HALs implement safe, idiomatic Rust APIs to use the hardware capabilities, so | ||
| 6 | raw register manipulation is not needed. | ||
| 7 | |||
| 8 | The Embassy iMXRT HAL targets the NXP iMXRT Family of MCUs. The HAL implements | ||
| 9 | both blocking and async APIs for many peripherals. The benefit of using the | ||
| 10 | async APIs is that the HAL takes care of waiting for peripherals to complete | ||
| 11 | operations in low power mode and handling of interrupts, so that applications | ||
| 12 | can focus on business logic. | ||
| 13 | |||
| 14 | NOTE: The Embassy HALs can be used both for non-async and async operations. For | ||
| 15 | async, you can choose which runtime you want to use. | ||
| 16 | |||
| 17 | For a complete list of available peripherals and features, see the | ||
| 18 | [embassy-imxrt documentation](https://docs.embassy.dev/embassy-imxrt). | ||
| 19 | |||
| 20 | ## Hardware support | ||
| 21 | |||
| 22 | The `embassy-imxrt` HAL currently supports two main variants of the iMXRT | ||
| 23 | family: | ||
| 24 | |||
| 25 | * MIMXRT685S | ||
| 26 | ([examples](https://github.com/OpenDevicePartnership/embassy-imxrt/tree/main/examples/rt685s-evk)) | ||
| 27 | * MIMXRT633s | ||
| 28 | ([examples](https://github.com/OpenDevicePartnership/embassy-imxrt/tree/main/examples/rt633)) | ||
| 29 | |||
| 30 | Several peripherals are supported and tested on both supported chip variants. To | ||
| 31 | check what's available, make sure to the MCU you're targetting in the top menu | ||
| 32 | in the [documentation](https://docs.embassy.dev/embassy-imxrt). | ||
| 33 | |||
| 34 | ## TrustZone support | ||
| 35 | |||
| 36 | TrustZone support is yet to be implemented. | ||
| 37 | |||
| 38 | ## Time driver | ||
| 39 | |||
| 40 | If the `time-driver` feature is enabled, the HAL uses the RTC peripheral as a | ||
| 41 | global time driver for [embassy-time](https://crates.io/crates/embassy-time), | ||
| 42 | with a tick rate of 32768 Hz. | ||
| 43 | |||
| 44 | ## Embedded-hal | ||
| 45 | |||
| 46 | The `embassy-imxrt` HAL implements the traits from | ||
| 47 | [embedded-hal](https://crates.io/crates/embedded-hal) (v0.2 and 1.0) and | ||
| 48 | [embedded-hal-async](https://crates.io/crates/embedded-hal-async), as well as | ||
| 49 | [embedded-io](https://crates.io/crates/embedded-io) and | ||
| 50 | [embedded-io-async](https://crates.io/crates/embedded-io-async). | ||
| 51 | |||
| 52 | ## Interoperability | ||
| 53 | |||
| 54 | This crate can run on any executor. | ||
| 55 | |||
| 56 | Optionally, some features requiring | ||
| 57 | [`embassy-time`](https://crates.io/crates/embassy-time) can be activated with | ||
| 58 | the `time` feature. If you enable it, you must link an `embassy-time` driver in | ||
| 59 | your project. | ||
diff --git a/embassy-imxrt/src/chips/mimxrt633s.rs b/embassy-imxrt/src/chips/mimxrt633s.rs new file mode 100644 index 000000000..30072132a --- /dev/null +++ b/embassy-imxrt/src/chips/mimxrt633s.rs | |||
| @@ -0,0 +1,389 @@ | |||
| 1 | pub use mimxrt633s_pac as pac; | ||
| 2 | |||
| 3 | #[allow(clippy::missing_safety_doc)] | ||
| 4 | pub mod interrupts { | ||
| 5 | embassy_hal_internal::interrupt_mod!( | ||
| 6 | ACMP, | ||
| 7 | ADC0, | ||
| 8 | CASPER, | ||
| 9 | CTIMER0, | ||
| 10 | CTIMER1, | ||
| 11 | CTIMER2, | ||
| 12 | CTIMER3, | ||
| 13 | CTIMER4, | ||
| 14 | DMA0, | ||
| 15 | DMA1, | ||
| 16 | DMIC0, | ||
| 17 | ESPI, | ||
| 18 | FLEXCOMM0, | ||
| 19 | FLEXCOMM1, | ||
| 20 | FLEXCOMM14, | ||
| 21 | FLEXCOMM15, | ||
| 22 | FLEXCOMM2, | ||
| 23 | FLEXCOMM3, | ||
| 24 | FLEXCOMM4, | ||
| 25 | FLEXCOMM5, | ||
| 26 | FLEXCOMM6, | ||
| 27 | FLEXCOMM7, | ||
| 28 | FLEXSPI, | ||
| 29 | GPIO_INTA, | ||
| 30 | GPIO_INTB, | ||
| 31 | HASHCRYPT, | ||
| 32 | HWVAD0, | ||
| 33 | HYPERVISOR, | ||
| 34 | I3C0, | ||
| 35 | MRT0, | ||
| 36 | MU_A, | ||
| 37 | OS_EVENT, | ||
| 38 | PIN_INT0, | ||
| 39 | PIN_INT1, | ||
| 40 | PIN_INT2, | ||
| 41 | PIN_INT3, | ||
| 42 | PIN_INT4, | ||
| 43 | PIN_INT5, | ||
| 44 | PIN_INT6, | ||
| 45 | PIN_INT7, | ||
| 46 | PMC_PMIC, | ||
| 47 | POWERQUAD, | ||
| 48 | PUF, | ||
| 49 | RNG, | ||
| 50 | RTC, | ||
| 51 | SCT0, | ||
| 52 | SECUREVIOLATION, | ||
| 53 | SGPIO_INTA, | ||
| 54 | SGPIO_INTB, | ||
| 55 | USB, | ||
| 56 | USBPHY_DCD, | ||
| 57 | USB_WAKEUP, | ||
| 58 | USDHC0, | ||
| 59 | USDHC1, | ||
| 60 | UTICK0, | ||
| 61 | WDT0, | ||
| 62 | WDT1, | ||
| 63 | ); | ||
| 64 | } | ||
| 65 | |||
| 66 | embassy_hal_internal::peripherals!( | ||
| 67 | ACMP, | ||
| 68 | ADC0, | ||
| 69 | CASPER, | ||
| 70 | CRC, | ||
| 71 | CTIMER0_COUNT_CHANNEL0, | ||
| 72 | CTIMER0_COUNT_CHANNEL1, | ||
| 73 | CTIMER0_COUNT_CHANNEL2, | ||
| 74 | CTIMER0_COUNT_CHANNEL3, | ||
| 75 | CTIMER0_CAPTURE_CHANNEL0, | ||
| 76 | CTIMER0_CAPTURE_CHANNEL1, | ||
| 77 | CTIMER0_CAPTURE_CHANNEL2, | ||
| 78 | CTIMER0_CAPTURE_CHANNEL3, | ||
| 79 | CTIMER1_COUNT_CHANNEL0, | ||
| 80 | CTIMER1_COUNT_CHANNEL1, | ||
| 81 | CTIMER1_COUNT_CHANNEL2, | ||
| 82 | CTIMER1_COUNT_CHANNEL3, | ||
| 83 | CTIMER1_CAPTURE_CHANNEL0, | ||
| 84 | CTIMER1_CAPTURE_CHANNEL1, | ||
| 85 | CTIMER1_CAPTURE_CHANNEL2, | ||
| 86 | CTIMER1_CAPTURE_CHANNEL3, | ||
| 87 | CTIMER2_COUNT_CHANNEL0, | ||
| 88 | CTIMER2_COUNT_CHANNEL1, | ||
| 89 | CTIMER2_COUNT_CHANNEL2, | ||
| 90 | CTIMER2_COUNT_CHANNEL3, | ||
| 91 | CTIMER2_CAPTURE_CHANNEL0, | ||
| 92 | CTIMER2_CAPTURE_CHANNEL1, | ||
| 93 | CTIMER2_CAPTURE_CHANNEL2, | ||
| 94 | CTIMER2_CAPTURE_CHANNEL3, | ||
| 95 | CTIMER3_COUNT_CHANNEL0, | ||
| 96 | CTIMER3_COUNT_CHANNEL1, | ||
| 97 | CTIMER3_COUNT_CHANNEL2, | ||
| 98 | CTIMER3_COUNT_CHANNEL3, | ||
| 99 | CTIMER3_CAPTURE_CHANNEL0, | ||
| 100 | CTIMER3_CAPTURE_CHANNEL1, | ||
| 101 | CTIMER3_CAPTURE_CHANNEL2, | ||
| 102 | CTIMER3_CAPTURE_CHANNEL3, | ||
| 103 | CTIMER4_COUNT_CHANNEL0, | ||
| 104 | CTIMER4_COUNT_CHANNEL1, | ||
| 105 | CTIMER4_COUNT_CHANNEL2, | ||
| 106 | CTIMER4_COUNT_CHANNEL3, | ||
| 107 | CTIMER4_CAPTURE_CHANNEL0, | ||
| 108 | CTIMER4_CAPTURE_CHANNEL1, | ||
| 109 | CTIMER4_CAPTURE_CHANNEL2, | ||
| 110 | CTIMER4_CAPTURE_CHANNEL3, | ||
| 111 | DMA0, | ||
| 112 | DMA0_CH0, | ||
| 113 | DMA0_CH1, | ||
| 114 | DMA0_CH2, | ||
| 115 | DMA0_CH3, | ||
| 116 | DMA0_CH4, | ||
| 117 | DMA0_CH5, | ||
| 118 | DMA0_CH6, | ||
| 119 | DMA0_CH7, | ||
| 120 | DMA0_CH8, | ||
| 121 | DMA0_CH9, | ||
| 122 | DMA0_CH10, | ||
| 123 | DMA0_CH11, | ||
| 124 | DMA0_CH12, | ||
| 125 | DMA0_CH13, | ||
| 126 | DMA0_CH14, | ||
| 127 | DMA0_CH15, | ||
| 128 | DMA0_CH16, | ||
| 129 | DMA0_CH17, | ||
| 130 | DMA0_CH18, | ||
| 131 | DMA0_CH19, | ||
| 132 | DMA0_CH20, | ||
| 133 | DMA0_CH21, | ||
| 134 | DMA0_CH22, | ||
| 135 | DMA0_CH23, | ||
| 136 | DMA0_CH24, | ||
| 137 | DMA0_CH25, | ||
| 138 | DMA0_CH26, | ||
| 139 | DMA0_CH27, | ||
| 140 | DMA0_CH28, | ||
| 141 | DMA0_CH29, | ||
| 142 | DMA0_CH30, | ||
| 143 | DMA0_CH31, | ||
| 144 | DMA0_CH32, | ||
| 145 | DMA1, | ||
| 146 | DMA1_CH0, | ||
| 147 | DMA1_CH1, | ||
| 148 | DMA1_CH2, | ||
| 149 | DMA1_CH3, | ||
| 150 | DMA1_CH4, | ||
| 151 | DMA1_CH5, | ||
| 152 | DMA1_CH6, | ||
| 153 | DMA1_CH7, | ||
| 154 | DMA1_CH8, | ||
| 155 | DMA1_CH9, | ||
| 156 | DMA1_CH10, | ||
| 157 | DMA1_CH11, | ||
| 158 | DMA1_CH12, | ||
| 159 | DMA1_CH13, | ||
| 160 | DMA1_CH14, | ||
| 161 | DMA1_CH15, | ||
| 162 | DMA1_CH16, | ||
| 163 | DMA1_CH17, | ||
| 164 | DMA1_CH18, | ||
| 165 | DMA1_CH19, | ||
| 166 | DMA1_CH20, | ||
| 167 | DMA1_CH21, | ||
| 168 | DMA1_CH22, | ||
| 169 | DMA1_CH23, | ||
| 170 | DMA1_CH24, | ||
| 171 | DMA1_CH25, | ||
| 172 | DMA1_CH26, | ||
| 173 | DMA1_CH27, | ||
| 174 | DMA1_CH28, | ||
| 175 | DMA1_CH29, | ||
| 176 | DMA1_CH30, | ||
| 177 | DMA1_CH31, | ||
| 178 | DMA1_CH32, | ||
| 179 | DMIC0, | ||
| 180 | DSPWAKE, | ||
| 181 | ESPI, | ||
| 182 | FLEXCOMM0, | ||
| 183 | FLEXCOMM1, | ||
| 184 | FLEXCOMM14, | ||
| 185 | FLEXCOMM15, | ||
| 186 | FLEXCOMM2, | ||
| 187 | FLEXCOMM3, | ||
| 188 | FLEXCOMM4, | ||
| 189 | FLEXCOMM5, | ||
| 190 | FLEXCOMM6, | ||
| 191 | FLEXCOMM7, | ||
| 192 | FLEXSPI, | ||
| 193 | FREQME, | ||
| 194 | GPIO_INTA, | ||
| 195 | GPIO_INTB, | ||
| 196 | HASHCRYPT, | ||
| 197 | HSGPIO0, | ||
| 198 | HSGPIO1, | ||
| 199 | HSGPIO2, | ||
| 200 | HSGPIO3, | ||
| 201 | HSGPIO4, | ||
| 202 | HSGPIO5, | ||
| 203 | HSGPIO6, | ||
| 204 | HSGPIO7, | ||
| 205 | HWVAD0, | ||
| 206 | HYPERVISOR, | ||
| 207 | I3C0, | ||
| 208 | MRT0, | ||
| 209 | MU_A, | ||
| 210 | OS_EVENT, | ||
| 211 | PIN_INT0, | ||
| 212 | PIN_INT1, | ||
| 213 | PIN_INT2, | ||
| 214 | PIN_INT3, | ||
| 215 | PIN_INT4, | ||
| 216 | PIN_INT5, | ||
| 217 | PIN_INT6, | ||
| 218 | PIN_INT7, | ||
| 219 | PIO0_0, | ||
| 220 | PIO0_1, | ||
| 221 | PIO0_10, | ||
| 222 | PIO0_11, | ||
| 223 | PIO0_12, | ||
| 224 | PIO0_13, | ||
| 225 | PIO0_14, | ||
| 226 | PIO0_15, | ||
| 227 | PIO0_16, | ||
| 228 | PIO0_17, | ||
| 229 | PIO0_18, | ||
| 230 | PIO0_19, | ||
| 231 | PIO0_2, | ||
| 232 | PIO0_20, | ||
| 233 | PIO0_21, | ||
| 234 | PIO0_22, | ||
| 235 | PIO0_23, | ||
| 236 | PIO0_24, | ||
| 237 | PIO0_25, | ||
| 238 | PIO0_26, | ||
| 239 | PIO0_27, | ||
| 240 | PIO0_28, | ||
| 241 | PIO0_29, | ||
| 242 | PIO0_3, | ||
| 243 | PIO0_30, | ||
| 244 | PIO0_31, | ||
| 245 | PIO0_4, | ||
| 246 | PIO0_5, | ||
| 247 | PIO0_6, | ||
| 248 | PIO0_7, | ||
| 249 | PIO0_8, | ||
| 250 | PIO0_9, | ||
| 251 | PIO1_0, | ||
| 252 | PIO1_1, | ||
| 253 | PIO1_10, | ||
| 254 | PIO1_11, | ||
| 255 | PIO1_12, | ||
| 256 | PIO1_13, | ||
| 257 | PIO1_14, | ||
| 258 | PIO1_15, | ||
| 259 | PIO1_16, | ||
| 260 | PIO1_17, | ||
| 261 | PIO1_18, | ||
| 262 | PIO1_19, | ||
| 263 | PIO1_2, | ||
| 264 | PIO1_20, | ||
| 265 | PIO1_21, | ||
| 266 | PIO1_22, | ||
| 267 | PIO1_23, | ||
| 268 | PIO1_24, | ||
| 269 | PIO1_25, | ||
| 270 | PIO1_26, | ||
| 271 | PIO1_27, | ||
| 272 | PIO1_28, | ||
| 273 | PIO1_29, | ||
| 274 | PIO1_3, | ||
| 275 | PIO1_30, | ||
| 276 | PIO1_31, | ||
| 277 | PIO1_4, | ||
| 278 | PIO1_5, | ||
| 279 | PIO1_6, | ||
| 280 | PIO1_7, | ||
| 281 | PIO1_8, | ||
| 282 | PIO1_9, | ||
| 283 | PIO2_0, | ||
| 284 | PIO2_1, | ||
| 285 | PIO2_10, | ||
| 286 | PIO2_11, | ||
| 287 | PIO2_12, | ||
| 288 | PIO2_13, | ||
| 289 | PIO2_14, | ||
| 290 | PIO2_15, | ||
| 291 | PIO2_16, | ||
| 292 | PIO2_17, | ||
| 293 | PIO2_18, | ||
| 294 | PIO2_19, | ||
| 295 | PIO2_2, | ||
| 296 | PIO2_20, | ||
| 297 | PIO2_21, | ||
| 298 | PIO2_22, | ||
| 299 | PIO2_23, | ||
| 300 | PIO2_24, | ||
| 301 | PIO2_25, | ||
| 302 | PIO2_26, | ||
| 303 | PIO2_27, | ||
| 304 | PIO2_28, | ||
| 305 | PIO2_29, | ||
| 306 | PIO2_3, | ||
| 307 | PIO2_30, | ||
| 308 | PIO2_31, | ||
| 309 | PIO2_4, | ||
| 310 | PIO2_5, | ||
| 311 | PIO2_6, | ||
| 312 | PIO2_7, | ||
| 313 | PIO2_8, | ||
| 314 | PIO2_9, | ||
| 315 | PIO3_0, | ||
| 316 | PIO3_1, | ||
| 317 | PIO3_10, | ||
| 318 | PIO3_11, | ||
| 319 | PIO3_12, | ||
| 320 | PIO3_13, | ||
| 321 | PIO3_14, | ||
| 322 | PIO3_15, | ||
| 323 | PIO3_16, | ||
| 324 | PIO3_17, | ||
| 325 | PIO3_18, | ||
| 326 | PIO3_19, | ||
| 327 | PIO3_2, | ||
| 328 | PIO3_20, | ||
| 329 | PIO3_21, | ||
| 330 | PIO3_22, | ||
| 331 | PIO3_23, | ||
| 332 | PIO3_24, | ||
| 333 | PIO3_25, | ||
| 334 | PIO3_26, | ||
| 335 | PIO3_27, | ||
| 336 | PIO3_28, | ||
| 337 | PIO3_29, | ||
| 338 | PIO3_3, | ||
| 339 | PIO3_30, | ||
| 340 | PIO3_31, | ||
| 341 | PIO3_4, | ||
| 342 | PIO3_5, | ||
| 343 | PIO3_6, | ||
| 344 | PIO3_7, | ||
| 345 | PIO3_8, | ||
| 346 | PIO3_9, | ||
| 347 | PIO4_0, | ||
| 348 | PIO4_1, | ||
| 349 | PIO4_10, | ||
| 350 | PIO4_2, | ||
| 351 | PIO4_3, | ||
| 352 | PIO4_4, | ||
| 353 | PIO4_5, | ||
| 354 | PIO4_6, | ||
| 355 | PIO4_7, | ||
| 356 | PIO4_8, | ||
| 357 | PIO4_9, | ||
| 358 | PIO7_24, | ||
| 359 | PIO7_25, | ||
| 360 | PIO7_26, | ||
| 361 | PIO7_27, | ||
| 362 | PIO7_28, | ||
| 363 | PIO7_29, | ||
| 364 | PIO7_30, | ||
| 365 | PIO7_31, | ||
| 366 | PIOFC15_SCL, | ||
| 367 | PIOFC15_SDA, | ||
| 368 | PMC_PMIC, | ||
| 369 | PIMCTL, | ||
| 370 | POWERQUAD, | ||
| 371 | PUF, | ||
| 372 | RNG, | ||
| 373 | RTC, | ||
| 374 | SCT0, | ||
| 375 | SECGPIO, | ||
| 376 | SECUREVIOLATION, | ||
| 377 | SEMA42, | ||
| 378 | SGPIO_INTA, | ||
| 379 | SGPIO_INTB, | ||
| 380 | USBHSD, | ||
| 381 | USBHSH, | ||
| 382 | USBPHY, | ||
| 383 | USB_WAKEUP, | ||
| 384 | USDHC0, | ||
| 385 | USDHC1, | ||
| 386 | UTICK0, | ||
| 387 | WDT0, | ||
| 388 | WDT1, | ||
| 389 | ); | ||
diff --git a/embassy-imxrt/src/chips/mimxrt685s.rs b/embassy-imxrt/src/chips/mimxrt685s.rs new file mode 100644 index 000000000..746861e35 --- /dev/null +++ b/embassy-imxrt/src/chips/mimxrt685s.rs | |||
| @@ -0,0 +1,388 @@ | |||
| 1 | pub use mimxrt685s_pac as pac; | ||
| 2 | |||
| 3 | #[allow(clippy::missing_safety_doc)] | ||
| 4 | pub mod interrupts { | ||
| 5 | embassy_hal_internal::interrupt_mod!( | ||
| 6 | ACMP, | ||
| 7 | ADC0, | ||
| 8 | CASPER, | ||
| 9 | CTIMER0, | ||
| 10 | CTIMER1, | ||
| 11 | CTIMER2, | ||
| 12 | CTIMER3, | ||
| 13 | CTIMER4, | ||
| 14 | DMA0, | ||
| 15 | DMA1, | ||
| 16 | DMIC0, | ||
| 17 | DSPWAKE, | ||
| 18 | FLEXCOMM0, | ||
| 19 | FLEXCOMM1, | ||
| 20 | FLEXCOMM14, | ||
| 21 | FLEXCOMM15, | ||
| 22 | FLEXCOMM2, | ||
| 23 | FLEXCOMM3, | ||
| 24 | FLEXCOMM4, | ||
| 25 | FLEXCOMM5, | ||
| 26 | FLEXCOMM6, | ||
| 27 | FLEXCOMM7, | ||
| 28 | FLEXSPI, | ||
| 29 | GPIO_INTA, | ||
| 30 | GPIO_INTB, | ||
| 31 | HASHCRYPT, | ||
| 32 | HWVAD0, | ||
| 33 | HYPERVISOR, | ||
| 34 | I3C0, | ||
| 35 | MRT0, | ||
| 36 | MU_A, | ||
| 37 | OS_EVENT, | ||
| 38 | PIN_INT0, | ||
| 39 | PIN_INT1, | ||
| 40 | PIN_INT2, | ||
| 41 | PIN_INT3, | ||
| 42 | PIN_INT4, | ||
| 43 | PIN_INT5, | ||
| 44 | PIN_INT6, | ||
| 45 | PIN_INT7, | ||
| 46 | PMC_PMIC, | ||
| 47 | POWERQUAD, | ||
| 48 | PUF, | ||
| 49 | RNG, | ||
| 50 | RTC, | ||
| 51 | SCT0, | ||
| 52 | SECUREVIOLATION, | ||
| 53 | SGPIO_INTA, | ||
| 54 | SGPIO_INTB, | ||
| 55 | USB, | ||
| 56 | USBPHY_DCD, | ||
| 57 | USB_WAKEUP, | ||
| 58 | USDHC0, | ||
| 59 | USDHC1, | ||
| 60 | UTICK0, | ||
| 61 | WDT0, | ||
| 62 | WDT1, | ||
| 63 | ); | ||
| 64 | } | ||
| 65 | |||
| 66 | embassy_hal_internal::peripherals!( | ||
| 67 | ACMP, | ||
| 68 | ADC0, | ||
| 69 | CASPER, | ||
| 70 | CRC, | ||
| 71 | CTIMER0_COUNT_CHANNEL0, | ||
| 72 | CTIMER0_COUNT_CHANNEL1, | ||
| 73 | CTIMER0_COUNT_CHANNEL2, | ||
| 74 | CTIMER0_COUNT_CHANNEL3, | ||
| 75 | CTIMER0_CAPTURE_CHANNEL0, | ||
| 76 | CTIMER0_CAPTURE_CHANNEL1, | ||
| 77 | CTIMER0_CAPTURE_CHANNEL2, | ||
| 78 | CTIMER0_CAPTURE_CHANNEL3, | ||
| 79 | CTIMER1_COUNT_CHANNEL0, | ||
| 80 | CTIMER1_COUNT_CHANNEL1, | ||
| 81 | CTIMER1_COUNT_CHANNEL2, | ||
| 82 | CTIMER1_COUNT_CHANNEL3, | ||
| 83 | CTIMER1_CAPTURE_CHANNEL0, | ||
| 84 | CTIMER1_CAPTURE_CHANNEL1, | ||
| 85 | CTIMER1_CAPTURE_CHANNEL2, | ||
| 86 | CTIMER1_CAPTURE_CHANNEL3, | ||
| 87 | CTIMER2_COUNT_CHANNEL0, | ||
| 88 | CTIMER2_COUNT_CHANNEL1, | ||
| 89 | CTIMER2_COUNT_CHANNEL2, | ||
| 90 | CTIMER2_COUNT_CHANNEL3, | ||
| 91 | CTIMER2_CAPTURE_CHANNEL0, | ||
| 92 | CTIMER2_CAPTURE_CHANNEL1, | ||
| 93 | CTIMER2_CAPTURE_CHANNEL2, | ||
| 94 | CTIMER2_CAPTURE_CHANNEL3, | ||
| 95 | CTIMER3_COUNT_CHANNEL0, | ||
| 96 | CTIMER3_COUNT_CHANNEL1, | ||
| 97 | CTIMER3_COUNT_CHANNEL2, | ||
| 98 | CTIMER3_COUNT_CHANNEL3, | ||
| 99 | CTIMER3_CAPTURE_CHANNEL0, | ||
| 100 | CTIMER3_CAPTURE_CHANNEL1, | ||
| 101 | CTIMER3_CAPTURE_CHANNEL2, | ||
| 102 | CTIMER3_CAPTURE_CHANNEL3, | ||
| 103 | CTIMER4_COUNT_CHANNEL0, | ||
| 104 | CTIMER4_COUNT_CHANNEL1, | ||
| 105 | CTIMER4_COUNT_CHANNEL2, | ||
| 106 | CTIMER4_COUNT_CHANNEL3, | ||
| 107 | CTIMER4_CAPTURE_CHANNEL0, | ||
| 108 | CTIMER4_CAPTURE_CHANNEL1, | ||
| 109 | CTIMER4_CAPTURE_CHANNEL2, | ||
| 110 | CTIMER4_CAPTURE_CHANNEL3, | ||
| 111 | DMA0, | ||
| 112 | DMA0_CH0, | ||
| 113 | DMA0_CH1, | ||
| 114 | DMA0_CH2, | ||
| 115 | DMA0_CH3, | ||
| 116 | DMA0_CH4, | ||
| 117 | DMA0_CH5, | ||
| 118 | DMA0_CH6, | ||
| 119 | DMA0_CH7, | ||
| 120 | DMA0_CH8, | ||
| 121 | DMA0_CH9, | ||
| 122 | DMA0_CH10, | ||
| 123 | DMA0_CH11, | ||
| 124 | DMA0_CH12, | ||
| 125 | DMA0_CH13, | ||
| 126 | DMA0_CH14, | ||
| 127 | DMA0_CH15, | ||
| 128 | DMA0_CH16, | ||
| 129 | DMA0_CH17, | ||
| 130 | DMA0_CH18, | ||
| 131 | DMA0_CH19, | ||
| 132 | DMA0_CH20, | ||
| 133 | DMA0_CH21, | ||
| 134 | DMA0_CH22, | ||
| 135 | DMA0_CH23, | ||
| 136 | DMA0_CH24, | ||
| 137 | DMA0_CH25, | ||
| 138 | DMA0_CH26, | ||
| 139 | DMA0_CH27, | ||
| 140 | DMA0_CH28, | ||
| 141 | DMA0_CH29, | ||
| 142 | DMA0_CH30, | ||
| 143 | DMA0_CH31, | ||
| 144 | DMA0_CH32, | ||
| 145 | DMA1, | ||
| 146 | DMA1_CH0, | ||
| 147 | DMA1_CH1, | ||
| 148 | DMA1_CH2, | ||
| 149 | DMA1_CH3, | ||
| 150 | DMA1_CH4, | ||
| 151 | DMA1_CH5, | ||
| 152 | DMA1_CH6, | ||
| 153 | DMA1_CH7, | ||
| 154 | DMA1_CH8, | ||
| 155 | DMA1_CH9, | ||
| 156 | DMA1_CH10, | ||
| 157 | DMA1_CH11, | ||
| 158 | DMA1_CH12, | ||
| 159 | DMA1_CH13, | ||
| 160 | DMA1_CH14, | ||
| 161 | DMA1_CH15, | ||
| 162 | DMA1_CH16, | ||
| 163 | DMA1_CH17, | ||
| 164 | DMA1_CH18, | ||
| 165 | DMA1_CH19, | ||
| 166 | DMA1_CH20, | ||
| 167 | DMA1_CH21, | ||
| 168 | DMA1_CH22, | ||
| 169 | DMA1_CH23, | ||
| 170 | DMA1_CH24, | ||
| 171 | DMA1_CH25, | ||
| 172 | DMA1_CH26, | ||
| 173 | DMA1_CH27, | ||
| 174 | DMA1_CH28, | ||
| 175 | DMA1_CH29, | ||
| 176 | DMA1_CH30, | ||
| 177 | DMA1_CH31, | ||
| 178 | DMA1_CH32, | ||
| 179 | DMIC0, | ||
| 180 | DSPWAKE, | ||
| 181 | FLEXCOMM0, | ||
| 182 | FLEXCOMM1, | ||
| 183 | FLEXCOMM14, | ||
| 184 | FLEXCOMM15, | ||
| 185 | FLEXCOMM2, | ||
| 186 | FLEXCOMM3, | ||
| 187 | FLEXCOMM4, | ||
| 188 | FLEXCOMM5, | ||
| 189 | FLEXCOMM6, | ||
| 190 | FLEXCOMM7, | ||
| 191 | FLEXSPI, | ||
| 192 | FREQME, | ||
| 193 | GPIO_INTA, | ||
| 194 | GPIO_INTB, | ||
| 195 | HASHCRYPT, | ||
| 196 | HSGPIO0, | ||
| 197 | HSGPIO1, | ||
| 198 | HSGPIO2, | ||
| 199 | HSGPIO3, | ||
| 200 | HSGPIO4, | ||
| 201 | HSGPIO5, | ||
| 202 | HSGPIO6, | ||
| 203 | HSGPIO7, | ||
| 204 | HWVAD0, | ||
| 205 | HYPERVISOR, | ||
| 206 | I3C0, | ||
| 207 | MRT0, | ||
| 208 | MU_A, | ||
| 209 | OS_EVENT, | ||
| 210 | PIN_INT0, | ||
| 211 | PIN_INT1, | ||
| 212 | PIN_INT2, | ||
| 213 | PIN_INT3, | ||
| 214 | PIN_INT4, | ||
| 215 | PIN_INT5, | ||
| 216 | PIN_INT6, | ||
| 217 | PIN_INT7, | ||
| 218 | PIO0_0, | ||
| 219 | PIO0_1, | ||
| 220 | PIO0_10, | ||
| 221 | PIO0_11, | ||
| 222 | PIO0_12, | ||
| 223 | PIO0_13, | ||
| 224 | PIO0_14, | ||
| 225 | PIO0_15, | ||
| 226 | PIO0_16, | ||
| 227 | PIO0_17, | ||
| 228 | PIO0_18, | ||
| 229 | PIO0_19, | ||
| 230 | PIO0_2, | ||
| 231 | PIO0_20, | ||
| 232 | PIO0_21, | ||
| 233 | PIO0_22, | ||
| 234 | PIO0_23, | ||
| 235 | PIO0_24, | ||
| 236 | PIO0_25, | ||
| 237 | PIO0_26, | ||
| 238 | PIO0_27, | ||
| 239 | PIO0_28, | ||
| 240 | PIO0_29, | ||
| 241 | PIO0_3, | ||
| 242 | PIO0_30, | ||
| 243 | PIO0_31, | ||
| 244 | PIO0_4, | ||
| 245 | PIO0_5, | ||
| 246 | PIO0_6, | ||
| 247 | PIO0_7, | ||
| 248 | PIO0_8, | ||
| 249 | PIO0_9, | ||
| 250 | PIO1_0, | ||
| 251 | PIO1_1, | ||
| 252 | PIO1_10, | ||
| 253 | PIO1_11, | ||
| 254 | PIO1_12, | ||
| 255 | PIO1_13, | ||
| 256 | PIO1_14, | ||
| 257 | PIO1_15, | ||
| 258 | PIO1_16, | ||
| 259 | PIO1_17, | ||
| 260 | PIO1_18, | ||
| 261 | PIO1_19, | ||
| 262 | PIO1_2, | ||
| 263 | PIO1_20, | ||
| 264 | PIO1_21, | ||
| 265 | PIO1_22, | ||
| 266 | PIO1_23, | ||
| 267 | PIO1_24, | ||
| 268 | PIO1_25, | ||
| 269 | PIO1_26, | ||
| 270 | PIO1_27, | ||
| 271 | PIO1_28, | ||
| 272 | PIO1_29, | ||
| 273 | PIO1_3, | ||
| 274 | PIO1_30, | ||
| 275 | PIO1_31, | ||
| 276 | PIO1_4, | ||
| 277 | PIO1_5, | ||
| 278 | PIO1_6, | ||
| 279 | PIO1_7, | ||
| 280 | PIO1_8, | ||
| 281 | PIO1_9, | ||
| 282 | PIO2_0, | ||
| 283 | PIO2_1, | ||
| 284 | PIO2_10, | ||
| 285 | PIO2_11, | ||
| 286 | PIO2_12, | ||
| 287 | PIO2_13, | ||
| 288 | PIO2_14, | ||
| 289 | PIO2_15, | ||
| 290 | PIO2_16, | ||
| 291 | PIO2_17, | ||
| 292 | PIO2_18, | ||
| 293 | PIO2_19, | ||
| 294 | PIO2_2, | ||
| 295 | PIO2_20, | ||
| 296 | PIO2_21, | ||
| 297 | PIO2_22, | ||
| 298 | PIO2_23, | ||
| 299 | PIO2_24, | ||
| 300 | PIO2_25, | ||
| 301 | PIO2_26, | ||
| 302 | PIO2_27, | ||
| 303 | PIO2_28, | ||
| 304 | PIO2_29, | ||
| 305 | PIO2_3, | ||
| 306 | PIO2_30, | ||
| 307 | PIO2_31, | ||
| 308 | PIO2_4, | ||
| 309 | PIO2_5, | ||
| 310 | PIO2_6, | ||
| 311 | PIO2_7, | ||
| 312 | PIO2_8, | ||
| 313 | PIO2_9, | ||
| 314 | PIO3_0, | ||
| 315 | PIO3_1, | ||
| 316 | PIO3_10, | ||
| 317 | PIO3_11, | ||
| 318 | PIO3_12, | ||
| 319 | PIO3_13, | ||
| 320 | PIO3_14, | ||
| 321 | PIO3_15, | ||
| 322 | PIO3_16, | ||
| 323 | PIO3_17, | ||
| 324 | PIO3_18, | ||
| 325 | PIO3_19, | ||
| 326 | PIO3_2, | ||
| 327 | PIO3_20, | ||
| 328 | PIO3_21, | ||
| 329 | PIO3_22, | ||
| 330 | PIO3_23, | ||
| 331 | PIO3_24, | ||
| 332 | PIO3_25, | ||
| 333 | PIO3_26, | ||
| 334 | PIO3_27, | ||
| 335 | PIO3_28, | ||
| 336 | PIO3_29, | ||
| 337 | PIO3_3, | ||
| 338 | PIO3_30, | ||
| 339 | PIO3_31, | ||
| 340 | PIO3_4, | ||
| 341 | PIO3_5, | ||
| 342 | PIO3_6, | ||
| 343 | PIO3_7, | ||
| 344 | PIO3_8, | ||
| 345 | PIO3_9, | ||
| 346 | PIO4_0, | ||
| 347 | PIO4_1, | ||
| 348 | PIO4_10, | ||
| 349 | PIO4_2, | ||
| 350 | PIO4_3, | ||
| 351 | PIO4_4, | ||
| 352 | PIO4_5, | ||
| 353 | PIO4_6, | ||
| 354 | PIO4_7, | ||
| 355 | PIO4_8, | ||
| 356 | PIO4_9, | ||
| 357 | PIO7_24, | ||
| 358 | PIO7_25, | ||
| 359 | PIO7_26, | ||
| 360 | PIO7_27, | ||
| 361 | PIO7_28, | ||
| 362 | PIO7_29, | ||
| 363 | PIO7_30, | ||
| 364 | PIO7_31, | ||
| 365 | PIOFC15_SCL, | ||
| 366 | PIOFC15_SDA, | ||
| 367 | PMC_PMIC, | ||
| 368 | PIMCTL, | ||
| 369 | POWERQUAD, | ||
| 370 | PUF, | ||
| 371 | RNG, | ||
| 372 | RTC, | ||
| 373 | SCT0, | ||
| 374 | SECGPIO, | ||
| 375 | SECUREVIOLATION, | ||
| 376 | SEMA42, | ||
| 377 | SGPIO_INTA, | ||
| 378 | SGPIO_INTB, | ||
| 379 | USBHSD, | ||
| 380 | USBHSH, | ||
| 381 | USBPHY, | ||
| 382 | USB_WAKEUP, | ||
| 383 | USDHC0, | ||
| 384 | USDHC1, | ||
| 385 | UTICK0, | ||
| 386 | WDT0, | ||
| 387 | WDT1, | ||
| 388 | ); | ||
diff --git a/embassy-imxrt/src/clocks.rs b/embassy-imxrt/src/clocks.rs new file mode 100644 index 000000000..1d36fb142 --- /dev/null +++ b/embassy-imxrt/src/clocks.rs | |||
| @@ -0,0 +1,1687 @@ | |||
| 1 | //! Clock configuration for the `RT6xx` | ||
| 2 | use core::sync::atomic::{AtomicU32, AtomicU8, Ordering}; | ||
| 3 | |||
| 4 | #[cfg(feature = "defmt")] | ||
| 5 | use defmt; | ||
| 6 | use paste::paste; | ||
| 7 | |||
| 8 | use crate::pac; | ||
| 9 | |||
| 10 | /// Clock configuration; | ||
| 11 | #[derive(Clone, Copy, Debug, PartialEq, Eq)] | ||
| 12 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 13 | pub enum Clocks { | ||
| 14 | /// Low power oscillator | ||
| 15 | Lposc, | ||
| 16 | /// System Frequency Resonance Oscillator (SFRO) | ||
| 17 | Sfro, | ||
| 18 | /// Real Time Clock | ||
| 19 | Rtc, | ||
| 20 | /// Feed-forward Ring Oscillator | ||
| 21 | Ffro, // This includes that div2 and div4 variations | ||
| 22 | /// External Clock Input | ||
| 23 | ClkIn, | ||
| 24 | /// AHB Clock | ||
| 25 | Hclk, | ||
| 26 | /// Main Clock | ||
| 27 | MainClk, | ||
| 28 | /// Main PLL Clock | ||
| 29 | MainPllClk, // also has aux0,aux1,dsp, and audio pll's downstream | ||
| 30 | /// System Clock | ||
| 31 | SysClk, | ||
| 32 | /// System Oscillator | ||
| 33 | SysOscClk, | ||
| 34 | /// ADC Clock | ||
| 35 | Adc, | ||
| 36 | } | ||
| 37 | |||
| 38 | /// Clock configuration. | ||
| 39 | pub struct ClockConfig { | ||
| 40 | /// low-power oscillator config | ||
| 41 | pub lposc: LposcConfig, | ||
| 42 | /// 16Mhz internal oscillator config | ||
| 43 | pub sfro: SfroConfig, | ||
| 44 | /// Real Time Clock config | ||
| 45 | pub rtc: RtcClkConfig, | ||
| 46 | /// 48/60 Mhz internal oscillator config | ||
| 47 | pub ffro: FfroConfig, | ||
| 48 | // pub pll: Option<PllPfdConfig>, //potentially covered in main pll clk | ||
| 49 | /// External Clock-In config | ||
| 50 | pub clk_in: ClkInConfig, | ||
| 51 | /// AHB bus clock config | ||
| 52 | pub hclk: HclkConfig, | ||
| 53 | /// Main Clock config | ||
| 54 | pub main_clk: MainClkConfig, | ||
| 55 | /// Main Pll clock config | ||
| 56 | pub main_pll_clk: MainPllClkConfig, | ||
| 57 | /// Software concept to be used with systick, doesn't map to a register | ||
| 58 | pub sys_clk: SysClkConfig, | ||
| 59 | /// System Oscillator Config | ||
| 60 | pub sys_osc: SysOscConfig, | ||
| 61 | // todo: move ADC here | ||
| 62 | } | ||
| 63 | |||
| 64 | impl ClockConfig { | ||
| 65 | /// Clock configuration derived from external crystal. | ||
| 66 | #[must_use] | ||
| 67 | pub fn crystal() -> Self { | ||
| 68 | const CORE_CPU_FREQ: u32 = 500_000_000; | ||
| 69 | const PLL_CLK_FREQ: u32 = 528_000_000; | ||
| 70 | const SYS_CLK_FREQ: u32 = CORE_CPU_FREQ / 2; | ||
| 71 | Self { | ||
| 72 | lposc: LposcConfig { | ||
| 73 | state: State::Enabled, | ||
| 74 | freq: AtomicU32::new(Into::into(LposcFreq::Lp1m)), | ||
| 75 | }, | ||
| 76 | sfro: SfroConfig { state: State::Enabled }, | ||
| 77 | rtc: RtcClkConfig { | ||
| 78 | state: State::Enabled, | ||
| 79 | wake_alarm_state: State::Disabled, | ||
| 80 | sub_second_state: State::Disabled, | ||
| 81 | freq: AtomicU32::new(Into::into(RtcFreq::Default1Hz)), | ||
| 82 | rtc_int: RtcInterrupts::None, | ||
| 83 | }, | ||
| 84 | ffro: FfroConfig { | ||
| 85 | state: State::Enabled, | ||
| 86 | freq: AtomicU32::new(Into::into(FfroFreq::Ffro48m)), | ||
| 87 | }, | ||
| 88 | //pll: Some(PllConfig {}),//includes aux0 and aux1 pll | ||
| 89 | clk_in: ClkInConfig { | ||
| 90 | state: State::Disabled, | ||
| 91 | // This is an externally sourced clock | ||
| 92 | // Don't give it an initial frequency | ||
| 93 | freq: Some(AtomicU32::new(0)), | ||
| 94 | }, | ||
| 95 | hclk: HclkConfig { state: State::Disabled }, | ||
| 96 | main_clk: MainClkConfig { | ||
| 97 | state: State::Enabled, | ||
| 98 | //FFRO divided by 4 is reset values of Main Clk Sel A, Sel B | ||
| 99 | src: MainClkSrc::FFRO, | ||
| 100 | div_int: AtomicU32::new(4), | ||
| 101 | freq: AtomicU32::new(CORE_CPU_FREQ), | ||
| 102 | }, | ||
| 103 | main_pll_clk: MainPllClkConfig { | ||
| 104 | state: State::Enabled, | ||
| 105 | src: MainPllClkSrc::SFRO, | ||
| 106 | freq: AtomicU32::new(PLL_CLK_FREQ), | ||
| 107 | mult: AtomicU8::new(16), | ||
| 108 | pfd0: 19, // | ||
| 109 | pfd1: 0, // future field | ||
| 110 | pfd2: 19, // 0x13 | ||
| 111 | pfd3: 0, // future field | ||
| 112 | aux0_div: 0, | ||
| 113 | aux1_div: 0, | ||
| 114 | }, | ||
| 115 | sys_clk: SysClkConfig { | ||
| 116 | sysclkfreq: AtomicU32::new(SYS_CLK_FREQ), | ||
| 117 | }, | ||
| 118 | sys_osc: SysOscConfig { state: State::Enabled }, | ||
| 119 | //adc: Some(AdcConfig {}), // TODO: add config | ||
| 120 | } | ||
| 121 | } | ||
| 122 | } | ||
| 123 | |||
| 124 | #[derive(Clone, Copy, Debug, PartialEq, Eq)] | ||
| 125 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 126 | /// Clock state enum | ||
| 127 | pub enum State { | ||
| 128 | /// Clock is enabled | ||
| 129 | Enabled, | ||
| 130 | /// Clock is disabled | ||
| 131 | Disabled, | ||
| 132 | } | ||
| 133 | |||
| 134 | #[derive(Clone, Copy, Debug, PartialEq, Eq)] | ||
| 135 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 136 | /// Low Power Oscillator valid frequencies | ||
| 137 | pub enum LposcFreq { | ||
| 138 | /// 1 `MHz` oscillator | ||
| 139 | Lp1m, | ||
| 140 | /// 32kHz oscillator | ||
| 141 | Lp32k, | ||
| 142 | } | ||
| 143 | |||
| 144 | impl From<LposcFreq> for u32 { | ||
| 145 | fn from(value: LposcFreq) -> Self { | ||
| 146 | match value { | ||
| 147 | LposcFreq::Lp1m => 1_000_000, | ||
| 148 | LposcFreq::Lp32k => 32_768, | ||
| 149 | } | ||
| 150 | } | ||
| 151 | } | ||
| 152 | |||
| 153 | impl TryFrom<u32> for LposcFreq { | ||
| 154 | type Error = ClockError; | ||
| 155 | fn try_from(value: u32) -> Result<Self, Self::Error> { | ||
| 156 | match value { | ||
| 157 | 1_000_000 => Ok(LposcFreq::Lp1m), | ||
| 158 | 32_768 => Ok(LposcFreq::Lp32k), | ||
| 159 | _ => Err(ClockError::InvalidFrequency), | ||
| 160 | } | ||
| 161 | } | ||
| 162 | } | ||
| 163 | |||
| 164 | /// Low power oscillator config | ||
| 165 | pub struct LposcConfig { | ||
| 166 | state: State, | ||
| 167 | // low power osc | ||
| 168 | freq: AtomicU32, | ||
| 169 | } | ||
| 170 | |||
| 171 | const SFRO_FREQ: u32 = 16_000_000; | ||
| 172 | /// SFRO config | ||
| 173 | pub struct SfroConfig { | ||
| 174 | state: State, | ||
| 175 | } | ||
| 176 | |||
| 177 | /// Valid RTC frequencies | ||
| 178 | pub enum RtcFreq { | ||
| 179 | /// "Alarm" aka 1Hz clock | ||
| 180 | Default1Hz, | ||
| 181 | /// "Wake" aka 1kHz clock | ||
| 182 | HighResolution1khz, | ||
| 183 | /// 32kHz clock | ||
| 184 | SubSecond32kHz, | ||
| 185 | } | ||
| 186 | |||
| 187 | impl From<RtcFreq> for u32 { | ||
| 188 | fn from(value: RtcFreq) -> Self { | ||
| 189 | match value { | ||
| 190 | RtcFreq::Default1Hz => 1, | ||
| 191 | RtcFreq::HighResolution1khz => 1_000, | ||
| 192 | RtcFreq::SubSecond32kHz => 32_768, | ||
| 193 | } | ||
| 194 | } | ||
| 195 | } | ||
| 196 | |||
| 197 | impl TryFrom<u32> for RtcFreq { | ||
| 198 | type Error = ClockError; | ||
| 199 | fn try_from(value: u32) -> Result<Self, Self::Error> { | ||
| 200 | match value { | ||
| 201 | 1 => Ok(RtcFreq::Default1Hz), | ||
| 202 | 1_000 => Ok(RtcFreq::HighResolution1khz), | ||
| 203 | 32_768 => Ok(RtcFreq::SubSecond32kHz), | ||
| 204 | _ => Err(ClockError::InvalidFrequency), | ||
| 205 | } | ||
| 206 | } | ||
| 207 | } | ||
| 208 | |||
| 209 | /// RTC Interrupt options | ||
| 210 | pub enum RtcInterrupts { | ||
| 211 | /// No interrupts are set | ||
| 212 | None, | ||
| 213 | /// 1Hz RTC clock aka Alarm interrupt set | ||
| 214 | Alarm, | ||
| 215 | /// 1kHz RTC clock aka Wake interrupt set | ||
| 216 | Wake, | ||
| 217 | } | ||
| 218 | |||
| 219 | impl From<RtcInterrupts> for u8 { | ||
| 220 | fn from(value: RtcInterrupts) -> Self { | ||
| 221 | match value { | ||
| 222 | RtcInterrupts::None => 0b00, | ||
| 223 | RtcInterrupts::Alarm => 0b01, | ||
| 224 | RtcInterrupts::Wake => 0b10, | ||
| 225 | } | ||
| 226 | } | ||
| 227 | } | ||
| 228 | /// RTC clock config. | ||
| 229 | pub struct RtcClkConfig { | ||
| 230 | /// 1 Hz Clock state | ||
| 231 | pub state: State, | ||
| 232 | /// 1kHz Clock state | ||
| 233 | pub wake_alarm_state: State, | ||
| 234 | /// 32kHz Clock state | ||
| 235 | pub sub_second_state: State, | ||
| 236 | /// RTC clock source. | ||
| 237 | pub freq: AtomicU32, | ||
| 238 | /// RTC Interrupt | ||
| 239 | pub rtc_int: RtcInterrupts, | ||
| 240 | } | ||
| 241 | |||
| 242 | /// Valid FFRO Frequencies | ||
| 243 | pub enum FfroFreq { | ||
| 244 | /// 48 Mhz Internal Oscillator | ||
| 245 | Ffro48m, | ||
| 246 | /// 60 `MHz` Internal Oscillator | ||
| 247 | Ffro60m, | ||
| 248 | } | ||
| 249 | |||
| 250 | /// FFRO Clock Config | ||
| 251 | pub struct FfroConfig { | ||
| 252 | /// FFRO Clock state | ||
| 253 | state: State, | ||
| 254 | /// FFRO Frequency | ||
| 255 | freq: AtomicU32, | ||
| 256 | } | ||
| 257 | |||
| 258 | impl From<FfroFreq> for u32 { | ||
| 259 | fn from(value: FfroFreq) -> Self { | ||
| 260 | match value { | ||
| 261 | FfroFreq::Ffro48m => 48_000_000, | ||
| 262 | FfroFreq::Ffro60m => 60_000_000, | ||
| 263 | } | ||
| 264 | } | ||
| 265 | } | ||
| 266 | |||
| 267 | impl TryFrom<u32> for FfroFreq { | ||
| 268 | type Error = ClockError; | ||
| 269 | fn try_from(value: u32) -> Result<Self, Self::Error> { | ||
| 270 | match value { | ||
| 271 | 48_000_000 => Ok(FfroFreq::Ffro48m), | ||
| 272 | 60_000_000 => Ok(FfroFreq::Ffro60m), | ||
| 273 | _ => Err(ClockError::InvalidFrequency), | ||
| 274 | } | ||
| 275 | } | ||
| 276 | } | ||
| 277 | |||
| 278 | /// PLL clock source | ||
| 279 | #[derive(Clone, Copy, Debug, PartialEq, Eq)] | ||
| 280 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 281 | pub enum MainPllClkSrc { | ||
| 282 | /// SFRO | ||
| 283 | SFRO, | ||
| 284 | /// External Clock | ||
| 285 | ClkIn, | ||
| 286 | /// FFRO | ||
| 287 | FFRO, | ||
| 288 | } | ||
| 289 | |||
| 290 | /// Transform from Source Clock enum to Clocks | ||
| 291 | impl From<MainPllClkSrc> for Clocks { | ||
| 292 | fn from(value: MainPllClkSrc) -> Self { | ||
| 293 | match value { | ||
| 294 | MainPllClkSrc::SFRO => Clocks::Sfro, | ||
| 295 | MainPllClkSrc::ClkIn => Clocks::ClkIn, | ||
| 296 | MainPllClkSrc::FFRO => Clocks::Ffro, | ||
| 297 | } | ||
| 298 | } | ||
| 299 | } | ||
| 300 | |||
| 301 | impl TryFrom<Clocks> for MainPllClkSrc { | ||
| 302 | type Error = ClockError; | ||
| 303 | fn try_from(value: Clocks) -> Result<Self, Self::Error> { | ||
| 304 | match value { | ||
| 305 | Clocks::Sfro => Ok(MainPllClkSrc::SFRO), | ||
| 306 | Clocks::Ffro => Ok(MainPllClkSrc::FFRO), | ||
| 307 | Clocks::ClkIn => Ok(MainPllClkSrc::ClkIn), | ||
| 308 | _ => Err(ClockError::ClockNotSupported), | ||
| 309 | } | ||
| 310 | } | ||
| 311 | } | ||
| 312 | |||
| 313 | /// PLL configuration. | ||
| 314 | pub struct MainPllClkConfig { | ||
| 315 | /// Clock active state | ||
| 316 | pub state: State, | ||
| 317 | /// Main clock source. | ||
| 318 | pub src: MainPllClkSrc, | ||
| 319 | /// Main clock frequency | ||
| 320 | pub freq: AtomicU32, | ||
| 321 | //TODO: numerator and denominator not used but present in register | ||
| 322 | /// Multiplication factor. | ||
| 323 | pub mult: AtomicU8, | ||
| 324 | // the following are actually 6-bits not 8 | ||
| 325 | /// Fractional divider 0, main pll clock | ||
| 326 | pub pfd0: u8, | ||
| 327 | /// Fractional divider 1 | ||
| 328 | pub pfd1: u8, | ||
| 329 | /// Fractional divider 2 | ||
| 330 | pub pfd2: u8, | ||
| 331 | /// Fractional divider 3 | ||
| 332 | pub pfd3: u8, | ||
| 333 | // Aux dividers | ||
| 334 | /// aux divider 0 | ||
| 335 | pub aux0_div: u8, | ||
| 336 | /// aux divider 1 | ||
| 337 | pub aux1_div: u8, | ||
| 338 | } | ||
| 339 | /// External input clock config | ||
| 340 | pub struct ClkInConfig { | ||
| 341 | /// External clock input state | ||
| 342 | state: State, | ||
| 343 | /// External clock input rate | ||
| 344 | freq: Option<AtomicU32>, | ||
| 345 | } | ||
| 346 | |||
| 347 | /// AHB clock config | ||
| 348 | pub struct HclkConfig { | ||
| 349 | /// divider to turn main clk into hclk for AHB bus | ||
| 350 | pub state: State, | ||
| 351 | } | ||
| 352 | |||
| 353 | /// Main clock source. | ||
| 354 | #[derive(Clone, Copy, Debug, PartialEq, Eq)] | ||
| 355 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 356 | pub enum MainClkSrc { | ||
| 357 | /// FFRO divided by 4 | ||
| 358 | FFROdiv4, // probably don't need since it'll be covered by div_int | ||
| 359 | /// External Clock | ||
| 360 | ClkIn, | ||
| 361 | /// Low Power Oscillator | ||
| 362 | Lposc, | ||
| 363 | /// FFRO | ||
| 364 | FFRO, | ||
| 365 | /// SFRO | ||
| 366 | SFRO, | ||
| 367 | /// Main PLL Clock | ||
| 368 | PllMain, | ||
| 369 | /// RTC 32kHz oscillator. | ||
| 370 | RTC32k, | ||
| 371 | } | ||
| 372 | |||
| 373 | impl From<MainClkSrc> for Clocks { | ||
| 374 | fn from(value: MainClkSrc) -> Self { | ||
| 375 | match value { | ||
| 376 | MainClkSrc::ClkIn => Clocks::ClkIn, | ||
| 377 | MainClkSrc::Lposc => Clocks::Lposc, | ||
| 378 | MainClkSrc::FFRO => Clocks::Ffro, | ||
| 379 | MainClkSrc::SFRO => Clocks::Sfro, | ||
| 380 | MainClkSrc::PllMain => Clocks::MainPllClk, | ||
| 381 | MainClkSrc::RTC32k => Clocks::Rtc, | ||
| 382 | MainClkSrc::FFROdiv4 => Clocks::Ffro, | ||
| 383 | } | ||
| 384 | } | ||
| 385 | } | ||
| 386 | |||
| 387 | impl TryFrom<Clocks> for MainClkSrc { | ||
| 388 | type Error = ClockError; | ||
| 389 | fn try_from(value: Clocks) -> Result<Self, Self::Error> { | ||
| 390 | match value { | ||
| 391 | Clocks::ClkIn => Ok(MainClkSrc::ClkIn), | ||
| 392 | Clocks::Lposc => Ok(MainClkSrc::Lposc), | ||
| 393 | Clocks::Sfro => Ok(MainClkSrc::SFRO), | ||
| 394 | Clocks::MainPllClk => Ok(MainClkSrc::PllMain), | ||
| 395 | Clocks::Rtc => Ok(MainClkSrc::RTC32k), | ||
| 396 | Clocks::Ffro => Ok(MainClkSrc::FFRO), | ||
| 397 | _ => Err(ClockError::ClockNotSupported), | ||
| 398 | } | ||
| 399 | } | ||
| 400 | } | ||
| 401 | |||
| 402 | /// Main clock config. | ||
| 403 | pub struct MainClkConfig { | ||
| 404 | /// Main clock state | ||
| 405 | pub state: State, | ||
| 406 | /// Main clock source. | ||
| 407 | pub src: MainClkSrc, | ||
| 408 | /// Main clock divider. | ||
| 409 | pub div_int: AtomicU32, | ||
| 410 | /// Clock Frequency | ||
| 411 | pub freq: AtomicU32, | ||
| 412 | } | ||
| 413 | |||
| 414 | /// System Core Clock config, SW concept for systick | ||
| 415 | pub struct SysClkConfig { | ||
| 416 | /// keeps track of the system core clock frequency | ||
| 417 | /// future use with systick | ||
| 418 | pub sysclkfreq: AtomicU32, | ||
| 419 | } | ||
| 420 | |||
| 421 | /// System Oscillator Config | ||
| 422 | pub struct SysOscConfig { | ||
| 423 | /// Clock State | ||
| 424 | pub state: State, | ||
| 425 | } | ||
| 426 | const SYS_OSC_DEFAULT_FREQ: u32 = 24_000_000; | ||
| 427 | |||
| 428 | /// Clock Errors | ||
| 429 | #[derive(Clone, Copy, Debug, PartialEq, Eq)] | ||
| 430 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 431 | pub enum ClockError { | ||
| 432 | /// Error due to attempting to change a clock with the wrong config block | ||
| 433 | ClockMismatch, | ||
| 434 | /// Error due to attempting to modify a clock that's not yet been enabled | ||
| 435 | ClockNotEnabled, | ||
| 436 | /// Error due to attempting to set a clock source that's not a supported option | ||
| 437 | ClockNotSupported, | ||
| 438 | /// Error due to attempting to set a clock to an invalid frequency | ||
| 439 | InvalidFrequency, | ||
| 440 | /// Error due to attempting to modify a clock output with an invalid divider | ||
| 441 | InvalidDiv, | ||
| 442 | /// Error due to attempting to modify a clock output with an invalid multiplier | ||
| 443 | InvalidMult, | ||
| 444 | } | ||
| 445 | |||
| 446 | /// Trait to configure one of the clocks | ||
| 447 | pub trait ConfigurableClock { | ||
| 448 | /// Reset the clock, will enable it | ||
| 449 | fn disable(&self) -> Result<(), ClockError>; | ||
| 450 | /// Enable the clock | ||
| 451 | fn enable_and_reset(&self) -> Result<(), ClockError>; | ||
| 452 | /// Return the clock rate (Hz) | ||
| 453 | fn get_clock_rate(&self) -> Result<u32, ClockError>; | ||
| 454 | /// Set the desired clock rate (Hz) | ||
| 455 | fn set_clock_rate(&mut self, div: u8, mult: u8, freq: u32) -> Result<(), ClockError>; | ||
| 456 | /// Returns whether this clock is enabled | ||
| 457 | fn is_enabled(&self) -> bool; | ||
| 458 | } | ||
| 459 | |||
| 460 | impl LposcConfig { | ||
| 461 | /// Initializes low-power oscillator. | ||
| 462 | fn init_lposc() { | ||
| 463 | // Enable low power oscillator | ||
| 464 | // SAFETY: unsafe needed to take pointer to Sysctl0, only happens once during init | ||
| 465 | let sysctl0 = unsafe { crate::pac::Sysctl0::steal() }; | ||
| 466 | sysctl0.pdruncfg0_clr().write(|w| w.lposc_pd().clr_pdruncfg0()); | ||
| 467 | |||
| 468 | // Wait for low-power oscillator to be ready (typically 64 us) | ||
| 469 | // Busy loop seems better here than trying to shoe-in an async delay | ||
| 470 | // SAFETY: unsafe needed to take pointer to Clkctl0, needed to validate HW is ready | ||
| 471 | let clkctl0 = unsafe { crate::pac::Clkctl0::steal() }; | ||
| 472 | while clkctl0.lposcctl0().read().clkrdy().bit_is_clear() {} | ||
| 473 | } | ||
| 474 | } | ||
| 475 | impl ConfigurableClock for LposcConfig { | ||
| 476 | fn enable_and_reset(&self) -> Result<(), ClockError> { | ||
| 477 | LposcConfig::init_lposc(); | ||
| 478 | Ok(()) | ||
| 479 | } | ||
| 480 | fn disable(&self) -> Result<(), ClockError> { | ||
| 481 | // SAFETY: unsafe needed to take pointer to Sysctl0, needed to power down the LPOSC HW | ||
| 482 | let sysctl0 = unsafe { crate::pac::Sysctl0::steal() }; | ||
| 483 | sysctl0.pdruncfg0_set().write(|w| w.lposc_pd().set_pdruncfg0()); | ||
| 484 | // Wait until LPOSC disabled | ||
| 485 | while !sysctl0.pdruncfg0().read().lposc_pd().is_power_down() {} | ||
| 486 | Ok(()) | ||
| 487 | } | ||
| 488 | fn get_clock_rate(&self) -> Result<u32, ClockError> { | ||
| 489 | Ok(self.freq.load(Ordering::Relaxed)) | ||
| 490 | } | ||
| 491 | fn set_clock_rate(&mut self, _div: u8, _mult: u8, freq: u32) -> Result<(), ClockError> { | ||
| 492 | if let Ok(r) = <u32 as TryInto<LposcFreq>>::try_into(freq) { | ||
| 493 | match r { | ||
| 494 | LposcFreq::Lp1m => { | ||
| 495 | self.freq | ||
| 496 | .store(LposcFreq::Lp1m as u32, core::sync::atomic::Ordering::Relaxed); | ||
| 497 | Ok(()) | ||
| 498 | } | ||
| 499 | LposcFreq::Lp32k => { | ||
| 500 | self.freq | ||
| 501 | .store(LposcFreq::Lp1m as u32, core::sync::atomic::Ordering::Relaxed); | ||
| 502 | Ok(()) | ||
| 503 | } | ||
| 504 | } | ||
| 505 | } else { | ||
| 506 | error!("failed to convert desired clock rate, {:#}, to LPOSC Freq", freq); | ||
| 507 | Err(ClockError::InvalidFrequency) | ||
| 508 | } | ||
| 509 | } | ||
| 510 | fn is_enabled(&self) -> bool { | ||
| 511 | self.state == State::Enabled | ||
| 512 | } | ||
| 513 | } | ||
| 514 | |||
| 515 | impl FfroConfig { | ||
| 516 | /// Necessary register writes to initialize the FFRO clock | ||
| 517 | pub fn init_ffro_clk() { | ||
| 518 | // SAFETY: unsafe needed to take pointer to Sysctl0, only to power up FFRO | ||
| 519 | let sysctl0 = unsafe { crate::pac::Sysctl0::steal() }; | ||
| 520 | |||
| 521 | /* Power on FFRO (48/60MHz) */ | ||
| 522 | sysctl0.pdruncfg0_clr().write(|w| w.ffro_pd().clr_pdruncfg0()); | ||
| 523 | |||
| 524 | // SAFETY: unsafe needed to take pointer to Clkctl0, only to set proper ffro update mode | ||
| 525 | let clkctl0 = unsafe { crate::pac::Clkctl0::steal() }; | ||
| 526 | |||
| 527 | clkctl0.ffroctl1().write(|w| w.update().normal_mode()); | ||
| 528 | |||
| 529 | // No FFRO enable/disable control in CLKCTL. | ||
| 530 | // Delay enough for FFRO to be stable in case it was just powered on | ||
| 531 | delay_loop_clocks(50, 12_000_000); | ||
| 532 | } | ||
| 533 | } | ||
| 534 | |||
| 535 | impl ConfigurableClock for FfroConfig { | ||
| 536 | fn enable_and_reset(&self) -> Result<(), ClockError> { | ||
| 537 | // SAFETY: should be called once | ||
| 538 | FfroConfig::init_ffro_clk(); | ||
| 539 | // default is 48 MHz | ||
| 540 | Ok(()) | ||
| 541 | } | ||
| 542 | fn disable(&self) -> Result<(), ClockError> { | ||
| 543 | // SAFETY: unsafe needed to take pointer to Sysctl0, only to power down FFRO | ||
| 544 | let sysctl0 = unsafe { crate::pac::Sysctl0::steal() }; | ||
| 545 | sysctl0.pdruncfg0_set().write(|w| w.ffro_pd().set_pdruncfg0()); | ||
| 546 | delay_loop_clocks(30, 12_000_000); | ||
| 547 | // Wait until FFRO disabled | ||
| 548 | while !sysctl0.pdruncfg0().read().ffro_pd().is_power_down() {} | ||
| 549 | Ok(()) | ||
| 550 | } | ||
| 551 | fn get_clock_rate(&self) -> Result<u32, ClockError> { | ||
| 552 | trace!("getting ffro clock rate"); | ||
| 553 | Ok(self.freq.load(Ordering::Relaxed)) | ||
| 554 | } | ||
| 555 | fn set_clock_rate(&mut self, _div: u8, _mult: u8, freq: u32) -> Result<(), ClockError> { | ||
| 556 | if let Ok(r) = <u32 as TryInto<FfroFreq>>::try_into(freq) { | ||
| 557 | match r { | ||
| 558 | FfroFreq::Ffro48m => { | ||
| 559 | // SAFETY: unsafe needed to take pointer to Clkctl0, needed to set the right HW frequency | ||
| 560 | let clkctl0 = unsafe { crate::pac::Clkctl0::steal() }; | ||
| 561 | clkctl0.ffroctl1().write(|w| w.update().update_safe_mode()); | ||
| 562 | clkctl0.ffroctl0().write(|w| w.trim_range().ffro_48mhz()); | ||
| 563 | clkctl0.ffroctl1().write(|w| w.update().normal_mode()); | ||
| 564 | |||
| 565 | self.freq | ||
| 566 | .store(FfroFreq::Ffro48m as u32, core::sync::atomic::Ordering::Relaxed); | ||
| 567 | Ok(()) | ||
| 568 | } | ||
| 569 | FfroFreq::Ffro60m => { | ||
| 570 | // SAFETY: unsafe needed to take pointer to Clkctl0, needed to set the right HW frequency | ||
| 571 | let clkctl0 = unsafe { crate::pac::Clkctl0::steal() }; | ||
| 572 | clkctl0.ffroctl1().write(|w| w.update().update_safe_mode()); | ||
| 573 | clkctl0.ffroctl0().write(|w| w.trim_range().ffro_60mhz()); | ||
| 574 | clkctl0.ffroctl1().write(|w| w.update().normal_mode()); | ||
| 575 | |||
| 576 | self.freq | ||
| 577 | .store(FfroFreq::Ffro60m as u32, core::sync::atomic::Ordering::Relaxed); | ||
| 578 | Ok(()) | ||
| 579 | } | ||
| 580 | } | ||
| 581 | } else { | ||
| 582 | error!("failed to convert desired clock rate, {:#}, to FFRO Freq", freq); | ||
| 583 | Err(ClockError::InvalidFrequency) | ||
| 584 | } | ||
| 585 | } | ||
| 586 | fn is_enabled(&self) -> bool { | ||
| 587 | self.state == State::Enabled | ||
| 588 | } | ||
| 589 | } | ||
| 590 | |||
| 591 | impl ConfigurableClock for SfroConfig { | ||
| 592 | fn enable_and_reset(&self) -> Result<(), ClockError> { | ||
| 593 | // SAFETY: unsafe needed to take pointer to Sysctl0, only to power up SFRO | ||
| 594 | let sysctl0 = unsafe { crate::pac::Sysctl0::steal() }; | ||
| 595 | sysctl0.pdruncfg0_clr().write(|w| w.sfro_pd().clr_pdruncfg0()); | ||
| 596 | // wait until ready | ||
| 597 | while !sysctl0.pdruncfg0().read().sfro_pd().is_enabled() {} | ||
| 598 | Ok(()) | ||
| 599 | } | ||
| 600 | fn disable(&self) -> Result<(), ClockError> { | ||
| 601 | // SAFETY: unsafe needed to take pointer to Sysctl0, only to power down SFRO | ||
| 602 | let sysctl0 = unsafe { crate::pac::Sysctl0::steal() }; | ||
| 603 | sysctl0.pdruncfg0_set().write(|w| w.sfro_pd().set_pdruncfg0()); | ||
| 604 | delay_loop_clocks(30, 12_000_000); | ||
| 605 | // Wait until SFRO disabled | ||
| 606 | while !sysctl0.pdruncfg0().read().sfro_pd().is_power_down() {} | ||
| 607 | Ok(()) | ||
| 608 | } | ||
| 609 | fn get_clock_rate(&self) -> Result<u32, ClockError> { | ||
| 610 | if self.state == State::Enabled { | ||
| 611 | Ok(SFRO_FREQ) | ||
| 612 | } else { | ||
| 613 | Err(ClockError::ClockNotEnabled) | ||
| 614 | } | ||
| 615 | } | ||
| 616 | fn set_clock_rate(&mut self, _div: u8, _mult: u8, freq: u32) -> Result<(), ClockError> { | ||
| 617 | if self.state == State::Enabled { | ||
| 618 | if freq == SFRO_FREQ { | ||
| 619 | trace!("Sfro frequency is already set at 16MHz"); | ||
| 620 | Ok(()) | ||
| 621 | } else { | ||
| 622 | Err(ClockError::InvalidFrequency) | ||
| 623 | } | ||
| 624 | } else { | ||
| 625 | Err(ClockError::ClockNotEnabled) | ||
| 626 | } | ||
| 627 | } | ||
| 628 | fn is_enabled(&self) -> bool { | ||
| 629 | self.state == State::Enabled | ||
| 630 | } | ||
| 631 | } | ||
| 632 | |||
| 633 | /// A Clock with multiple options for clock source | ||
| 634 | pub trait MultiSourceClock { | ||
| 635 | /// Returns which clock is being used as the clock source and its rate | ||
| 636 | fn get_clock_source_and_rate(&self, clock: &Clocks) -> Result<(Clocks, u32), ClockError>; | ||
| 637 | /// Sets a specific clock source and its associated rate | ||
| 638 | fn set_clock_source_and_rate( | ||
| 639 | &mut self, | ||
| 640 | clock_src_config: &mut impl ConfigurableClock, | ||
| 641 | clock_src: &Clocks, | ||
| 642 | rate: u32, | ||
| 643 | ) -> Result<(), ClockError>; | ||
| 644 | } | ||
| 645 | |||
| 646 | impl MultiSourceClock for MainPllClkConfig { | ||
| 647 | fn get_clock_source_and_rate(&self, clock: &Clocks) -> Result<(Clocks, u32), ClockError> { | ||
| 648 | match clock { | ||
| 649 | Clocks::MainPllClk => { | ||
| 650 | let converted_clock = Clocks::from(self.src); | ||
| 651 | Ok((converted_clock, self.freq.load(Ordering::Relaxed))) | ||
| 652 | } | ||
| 653 | _ => Err(ClockError::ClockMismatch), | ||
| 654 | } | ||
| 655 | } | ||
| 656 | fn set_clock_source_and_rate( | ||
| 657 | &mut self, | ||
| 658 | clock_src_config: &mut impl ConfigurableClock, | ||
| 659 | clock_src: &Clocks, | ||
| 660 | rate: u32, | ||
| 661 | ) -> Result<(), ClockError> { | ||
| 662 | if let Ok(c) = <Clocks as TryInto<MainPllClkSrc>>::try_into(*clock_src) { | ||
| 663 | match c { | ||
| 664 | MainPllClkSrc::ClkIn => { | ||
| 665 | self.src = MainPllClkSrc::ClkIn; | ||
| 666 | // div mult and rate don't matter since this is an external clock | ||
| 667 | self.set_clock_rate(1, 1, rate) | ||
| 668 | } | ||
| 669 | MainPllClkSrc::FFRO => { | ||
| 670 | // FFRO Clock is divided by 2 | ||
| 671 | let r = clock_src_config.get_clock_rate()?; | ||
| 672 | let base_rate = r / 2; | ||
| 673 | let m = MainPllClkConfig::calc_mult(rate, base_rate)?; | ||
| 674 | |||
| 675 | self.src = MainPllClkSrc::FFRO; | ||
| 676 | self.set_clock_rate(2, m, rate) | ||
| 677 | } | ||
| 678 | MainPllClkSrc::SFRO => { | ||
| 679 | if !clock_src_config.is_enabled() { | ||
| 680 | error!("Can't set SFRO as source for MainPll as it's not enabled"); | ||
| 681 | return Err(ClockError::ClockNotEnabled); | ||
| 682 | } | ||
| 683 | // check if desired frequency is a valid multiple of 16m SFRO clock | ||
| 684 | let m = MainPllClkConfig::calc_mult(rate, SFRO_FREQ)?; | ||
| 685 | self.src = MainPllClkSrc::SFRO; | ||
| 686 | self.set_clock_rate(1, m, rate) | ||
| 687 | } | ||
| 688 | } | ||
| 689 | } else { | ||
| 690 | Err(ClockError::ClockNotSupported) | ||
| 691 | } | ||
| 692 | } | ||
| 693 | } | ||
| 694 | |||
| 695 | impl ConfigurableClock for MainPllClkConfig { | ||
| 696 | fn enable_and_reset(&self) -> Result<(), ClockError> { | ||
| 697 | MainPllClkConfig::init_syspll(); | ||
| 698 | |||
| 699 | MainPllClkConfig::init_syspll_pfd0(self.pfd0); | ||
| 700 | |||
| 701 | MainPllClkConfig::init_syspll_pfd2(self.pfd2); | ||
| 702 | Ok(()) | ||
| 703 | } | ||
| 704 | fn disable(&self) -> Result<(), ClockError> { | ||
| 705 | if self.is_enabled() { | ||
| 706 | error!("Attempting to reset the Main Pll Clock, should be resetting its source"); | ||
| 707 | Err(ClockError::ClockNotSupported) | ||
| 708 | } else { | ||
| 709 | Err(ClockError::ClockNotEnabled) | ||
| 710 | } | ||
| 711 | } | ||
| 712 | fn get_clock_rate(&self) -> Result<u32, ClockError> { | ||
| 713 | if self.is_enabled() { | ||
| 714 | let (_c, rate) = self.get_clock_source_and_rate(&Clocks::MainPllClk)?; | ||
| 715 | Ok(rate) | ||
| 716 | } else { | ||
| 717 | Err(ClockError::ClockNotEnabled) | ||
| 718 | } | ||
| 719 | } | ||
| 720 | fn set_clock_rate(&mut self, div: u8, mult: u8, freq: u32) -> Result<(), ClockError> { | ||
| 721 | if self.is_enabled() { | ||
| 722 | trace!("attempting to set main pll clock rate"); | ||
| 723 | // SAFETY: unsafe needed to take pointers to Sysctl0 and Clkctl0 | ||
| 724 | let clkctl0 = unsafe { crate::pac::Clkctl0::steal() }; | ||
| 725 | let sysctl0 = unsafe { crate::pac::Sysctl0::steal() }; | ||
| 726 | |||
| 727 | // Power down pll before changes | ||
| 728 | sysctl0 | ||
| 729 | .pdruncfg0_set() | ||
| 730 | .write(|w| w.syspllldo_pd().set_pdruncfg0().syspllana_pd().set_pdruncfg0()); | ||
| 731 | |||
| 732 | let desired_freq: u64 = self.freq.load(Ordering::Relaxed).into(); | ||
| 733 | |||
| 734 | match self.src { | ||
| 735 | c if c == MainPllClkSrc::ClkIn || c == MainPllClkSrc::FFRO || c == MainPllClkSrc::SFRO => { | ||
| 736 | let mut base_rate; | ||
| 737 | match c { | ||
| 738 | MainPllClkSrc::ClkIn => { | ||
| 739 | clkctl0.syspll0clksel().write(|w| w.sel().sysxtal_clk()); | ||
| 740 | let r = self.get_clock_rate()?; | ||
| 741 | base_rate = r; | ||
| 742 | } | ||
| 743 | MainPllClkSrc::FFRO => { | ||
| 744 | trace!("found FFRO as source, wait a bit"); | ||
| 745 | delay_loop_clocks(1000, desired_freq); | ||
| 746 | match clkctl0.ffroctl0().read().trim_range().is_ffro_48mhz() { | ||
| 747 | true => base_rate = Into::into(FfroFreq::Ffro48m), | ||
| 748 | false => base_rate = Into::into(FfroFreq::Ffro60m), | ||
| 749 | } | ||
| 750 | trace!("found ffro rate to be: {:#}", base_rate); | ||
| 751 | if div == 2 { | ||
| 752 | trace!("dividing FFRO rate by 2"); | ||
| 753 | clkctl0.syspll0clksel().write(|w| w.sel().ffro_div_2()); | ||
| 754 | delay_loop_clocks(150, desired_freq); | ||
| 755 | base_rate /= 2; | ||
| 756 | } else { | ||
| 757 | return Err(ClockError::InvalidDiv); | ||
| 758 | } | ||
| 759 | } | ||
| 760 | MainPllClkSrc::SFRO => { | ||
| 761 | base_rate = SFRO_FREQ; | ||
| 762 | clkctl0.syspll0clksel().write(|w| w.sel().sfro_clk()); | ||
| 763 | } | ||
| 764 | }; | ||
| 765 | base_rate *= u32::from(mult); | ||
| 766 | trace!("calculated base rate at: {:#}", base_rate); | ||
| 767 | if base_rate != freq { | ||
| 768 | // make sure to power syspll back up before returning the error | ||
| 769 | error!("invalid frequency found, powering syspll back up before returning error. Check div and mult"); | ||
| 770 | // Clear System PLL reset | ||
| 771 | clkctl0.syspll0ctl0().write(|w| w.reset().normal()); | ||
| 772 | // Power up SYSPLL | ||
| 773 | sysctl0 | ||
| 774 | .pdruncfg0_clr() | ||
| 775 | .write(|w| w.syspllana_pd().clr_pdruncfg0().syspllldo_pd().clr_pdruncfg0()); | ||
| 776 | return Err(ClockError::InvalidFrequency); | ||
| 777 | } | ||
| 778 | trace!("setting default num and denom"); | ||
| 779 | // SAFETY: unsafe needed to write the bits for the num and demon fields | ||
| 780 | clkctl0.syspll0num().write(|w| unsafe { w.num().bits(0b0) }); | ||
| 781 | clkctl0.syspll0denom().write(|w| unsafe { w.denom().bits(0b1) }); | ||
| 782 | delay_loop_clocks(30, desired_freq); | ||
| 783 | self.mult.store(mult, Ordering::Relaxed); | ||
| 784 | trace!("setting self.mult as: {:#}", mult); | ||
| 785 | match mult { | ||
| 786 | 16 => { | ||
| 787 | clkctl0.syspll0ctl0().modify(|_r, w| w.mult().div_16()); | ||
| 788 | } | ||
| 789 | 17 => { | ||
| 790 | clkctl0.syspll0ctl0().modify(|_r, w| w.mult().div_17()); | ||
| 791 | } | ||
| 792 | 20 => { | ||
| 793 | clkctl0.syspll0ctl0().modify(|_r, w| w.mult().div_20()); | ||
| 794 | } | ||
| 795 | 22 => { | ||
| 796 | clkctl0.syspll0ctl0().modify(|_r, w| w.mult().div_22()); | ||
| 797 | } | ||
| 798 | 27 => { | ||
| 799 | clkctl0.syspll0ctl0().modify(|_r, w| w.mult().div_27()); | ||
| 800 | } | ||
| 801 | 33 => { | ||
| 802 | clkctl0.syspll0ctl0().modify(|_r, w| w.mult().div_33()); | ||
| 803 | } | ||
| 804 | _ => return Err(ClockError::InvalidMult), | ||
| 805 | } | ||
| 806 | trace!("clear syspll reset"); | ||
| 807 | // Clear System PLL reset | ||
| 808 | clkctl0.syspll0ctl0().modify(|_r, w| w.reset().normal()); | ||
| 809 | // Power up SYSPLL | ||
| 810 | sysctl0 | ||
| 811 | .pdruncfg0_clr() | ||
| 812 | .write(|w| w.syspllana_pd().clr_pdruncfg0().syspllldo_pd().clr_pdruncfg0()); | ||
| 813 | |||
| 814 | // Set System PLL HOLDRINGOFF_ENA | ||
| 815 | clkctl0.syspll0ctl0().modify(|_, w| w.holdringoff_ena().enable()); | ||
| 816 | delay_loop_clocks(75, desired_freq); | ||
| 817 | |||
| 818 | // Clear System PLL HOLDRINGOFF_ENA | ||
| 819 | clkctl0.syspll0ctl0().modify(|_, w| w.holdringoff_ena().dsiable()); | ||
| 820 | delay_loop_clocks(15, desired_freq); | ||
| 821 | |||
| 822 | trace!("setting new PFD0 bits"); | ||
| 823 | // gate the output and clear bits. | ||
| 824 | // SAFETY: unsafe needed to write the bits for pfd0 | ||
| 825 | clkctl0 | ||
| 826 | .syspll0pfd() | ||
| 827 | .modify(|_, w| unsafe { w.pfd0_clkgate().gated().pfd0().bits(0x0) }); | ||
| 828 | // set pfd bits and un-gate the clock output | ||
| 829 | // output is multiplied by syspll * 18/pfd0_bits | ||
| 830 | // SAFETY: unsafe needed to write the bits for pfd0 | ||
| 831 | clkctl0 | ||
| 832 | .syspll0pfd() | ||
| 833 | .modify(|_r, w| unsafe { w.pfd0_clkgate().not_gated().pfd0().bits(0x12) }); | ||
| 834 | // wait for ready bit to be set | ||
| 835 | delay_loop_clocks(50, desired_freq); | ||
| 836 | trace!("waiting for mainpll clock to be ready"); | ||
| 837 | while clkctl0.syspll0pfd().read().pfd0_clkrdy().bit_is_clear() {} | ||
| 838 | // clear by writing a 1 | ||
| 839 | clkctl0.syspll0pfd().modify(|_, w| w.pfd0_clkrdy().set_bit()); | ||
| 840 | |||
| 841 | Ok(()) | ||
| 842 | } | ||
| 843 | _ => Err(ClockError::ClockNotSupported), | ||
| 844 | } | ||
| 845 | } else { | ||
| 846 | Err(ClockError::ClockNotEnabled) | ||
| 847 | } | ||
| 848 | } | ||
| 849 | fn is_enabled(&self) -> bool { | ||
| 850 | self.state == State::Enabled | ||
| 851 | } | ||
| 852 | } | ||
| 853 | |||
| 854 | impl MainPllClkConfig { | ||
| 855 | /// Calculate the mult value of a desired frequency, return error if invalid | ||
| 856 | pub(self) fn calc_mult(rate: u32, base_freq: u32) -> Result<u8, ClockError> { | ||
| 857 | trace!("calculating mult for {:#} / {:#}", rate, base_freq); | ||
| 858 | const VALIDMULTS: [u8; 6] = [16, 17, 20, 22, 27, 33]; | ||
| 859 | if rate > base_freq && rate % base_freq == 0 { | ||
| 860 | let mult = (rate / base_freq) as u8; | ||
| 861 | trace!("verifying that calculated mult {:#} is a valid one", mult); | ||
| 862 | if VALIDMULTS.into_iter().any(|i| i == mult) { | ||
| 863 | Ok(mult) | ||
| 864 | } else { | ||
| 865 | Err(ClockError::InvalidFrequency) | ||
| 866 | } | ||
| 867 | } else { | ||
| 868 | Err(ClockError::InvalidFrequency) | ||
| 869 | } | ||
| 870 | } | ||
| 871 | pub(self) fn init_syspll() { | ||
| 872 | // SAFETY: unsafe needed to take pointers to Sysctl0 and Clkctl0 | ||
| 873 | let clkctl0 = unsafe { crate::pac::Clkctl0::steal() }; | ||
| 874 | let sysctl0 = unsafe { crate::pac::Sysctl0::steal() }; | ||
| 875 | |||
| 876 | // Power down SYSPLL before change fractional settings | ||
| 877 | sysctl0 | ||
| 878 | .pdruncfg0_set() | ||
| 879 | .write(|w| w.syspllldo_pd().set_pdruncfg0().syspllana_pd().set_pdruncfg0()); | ||
| 880 | |||
| 881 | clkctl0.syspll0clksel().write(|w| w.sel().ffro_div_2()); | ||
| 882 | // SAFETY: unsafe needed to write the bits for both num and denom | ||
| 883 | clkctl0.syspll0num().write(|w| unsafe { w.num().bits(0x0) }); | ||
| 884 | clkctl0.syspll0denom().write(|w| unsafe { w.denom().bits(0x1) }); | ||
| 885 | |||
| 886 | // kCLOCK_SysPllMult22 | ||
| 887 | clkctl0.syspll0ctl0().modify(|_, w| w.mult().div_22()); | ||
| 888 | |||
| 889 | // Clear System PLL reset | ||
| 890 | clkctl0.syspll0ctl0().modify(|_, w| w.reset().normal()); | ||
| 891 | |||
| 892 | // Power up SYSPLL | ||
| 893 | sysctl0 | ||
| 894 | .pdruncfg0_clr() | ||
| 895 | .write(|w| w.syspllldo_pd().clr_pdruncfg0().syspllana_pd().clr_pdruncfg0()); | ||
| 896 | delay_loop_clocks((150 & 0xFFFF) / 2, 12_000_000); | ||
| 897 | |||
| 898 | // Set System PLL HOLDRINGOFF_ENA | ||
| 899 | clkctl0.syspll0ctl0().modify(|_, w| w.holdringoff_ena().enable()); | ||
| 900 | delay_loop_clocks((150 & 0xFFFF) / 2, 12_000_000); | ||
| 901 | |||
| 902 | // Clear System PLL HOLDRINGOFF_ENA | ||
| 903 | clkctl0.syspll0ctl0().modify(|_, w| w.holdringoff_ena().dsiable()); | ||
| 904 | delay_loop_clocks((15 & 0xFFFF) / 2, 12_000_000); | ||
| 905 | } | ||
| 906 | /// enables default settings for pfd2 bits | ||
| 907 | pub(self) fn init_syspll_pfd2(config_bits: u8) { | ||
| 908 | // SAFETY: unsafe needed to take pointer to Clkctl0 and write specific bits | ||
| 909 | // needed to change the output of pfd0 | ||
| 910 | unsafe { | ||
| 911 | let clkctl0 = crate::pac::Clkctl0::steal(); | ||
| 912 | |||
| 913 | // Disable the clock output first. | ||
| 914 | // SAFETY: unsafe needed to write the bits for pfd2 | ||
| 915 | clkctl0 | ||
| 916 | .syspll0pfd() | ||
| 917 | .modify(|_, w| w.pfd2_clkgate().gated().pfd2().bits(0x0)); | ||
| 918 | |||
| 919 | // Set the new value and enable output. | ||
| 920 | // SAFETY: unsafe needed to write the bits for pfd2 | ||
| 921 | clkctl0 | ||
| 922 | .syspll0pfd() | ||
| 923 | .modify(|_, w| w.pfd2_clkgate().not_gated().pfd2().bits(config_bits)); | ||
| 924 | |||
| 925 | // Wait for output becomes stable. | ||
| 926 | while clkctl0.syspll0pfd().read().pfd2_clkrdy().bit_is_clear() {} | ||
| 927 | |||
| 928 | // Clear ready status flag. | ||
| 929 | clkctl0.syspll0pfd().modify(|_, w| w.pfd2_clkrdy().clear_bit()); | ||
| 930 | } | ||
| 931 | } | ||
| 932 | /// Enables default settings for pfd0 | ||
| 933 | pub(self) fn init_syspll_pfd0(config_bits: u8) { | ||
| 934 | // SAFETY: unsafe needed to take pointer to Clkctl0 and write specific bits | ||
| 935 | // needed to change the output of pfd0 | ||
| 936 | unsafe { | ||
| 937 | let clkctl0 = crate::pac::Clkctl0::steal(); | ||
| 938 | // Disable the clock output first | ||
| 939 | clkctl0 | ||
| 940 | .syspll0pfd() | ||
| 941 | .modify(|_, w| w.pfd0_clkgate().gated().pfd0().bits(0x0)); | ||
| 942 | |||
| 943 | // Set the new value and enable output | ||
| 944 | clkctl0 | ||
| 945 | .syspll0pfd() | ||
| 946 | .modify(|_, w| w.pfd0_clkgate().not_gated().pfd0().bits(config_bits)); | ||
| 947 | |||
| 948 | // Wait for output becomes stable | ||
| 949 | while clkctl0.syspll0pfd().read().pfd0_clkrdy().bit_is_clear() {} | ||
| 950 | |||
| 951 | // Clear ready status flag | ||
| 952 | clkctl0.syspll0pfd().modify(|_, w| w.pfd0_clkrdy().clear_bit()); | ||
| 953 | } | ||
| 954 | } | ||
| 955 | } | ||
| 956 | |||
| 957 | impl MainClkConfig { | ||
| 958 | fn init_main_clk() { | ||
| 959 | // SAFETY:: unsafe needed to take pointers to Clkctl0 and Clkctl1 | ||
| 960 | // used to set the right HW frequency | ||
| 961 | let clkctl0 = unsafe { crate::pac::Clkctl0::steal() }; | ||
| 962 | let clkctl1 = unsafe { crate::pac::Clkctl1::steal() }; | ||
| 963 | |||
| 964 | clkctl0.mainclkselb().write(|w| w.sel().main_pll_clk()); | ||
| 965 | |||
| 966 | // Set PFC0DIV divider to value 2, Subtract 1 since 0-> 1, 1-> 2, etc... | ||
| 967 | clkctl0.pfcdiv(0).modify(|_, w| w.reset().set_bit()); | ||
| 968 | // SAFETY: unsafe needed to write the bits for pfcdiv | ||
| 969 | clkctl0 | ||
| 970 | .pfcdiv(0) | ||
| 971 | .write(|w| unsafe { w.div().bits(2 - 1).halt().clear_bit() }); | ||
| 972 | while clkctl0.pfcdiv(0).read().reqflag().bit_is_set() {} | ||
| 973 | |||
| 974 | // Set FRGPLLCLKDIV divider to value 12, Subtract 1 since 0-> 1, 1-> 2, etc... | ||
| 975 | clkctl1.frgpllclkdiv().modify(|_, w| w.reset().set_bit()); | ||
| 976 | // SAFETY: unsafe needed to write the bits for frgpllclkdiv | ||
| 977 | clkctl1 | ||
| 978 | .frgpllclkdiv() | ||
| 979 | .write(|w| unsafe { w.div().bits(12 - 1).halt().clear_bit() }); | ||
| 980 | while clkctl1.frgpllclkdiv().read().reqflag().bit_is_set() {} | ||
| 981 | } | ||
| 982 | } | ||
| 983 | impl MultiSourceClock for MainClkConfig { | ||
| 984 | fn get_clock_source_and_rate(&self, clock: &Clocks) -> Result<(Clocks, u32), ClockError> { | ||
| 985 | match clock { | ||
| 986 | Clocks::MainClk => { | ||
| 987 | let div: u32 = if self.src == MainClkSrc::FFROdiv4 { 4 } else { 1 }; | ||
| 988 | let converted_clock = Clocks::from(self.src); | ||
| 989 | match ConfigurableClock::get_clock_rate(self) { | ||
| 990 | Ok(_rate) => { | ||
| 991 | // SAFETY: unsafe needed to take pointer to Clkctl0 | ||
| 992 | // needed to calculate the clock rate from the bits written in the registers | ||
| 993 | let clkctl0 = unsafe { crate::pac::Clkctl0::steal() }; | ||
| 994 | if self.src == MainClkSrc::PllMain && clkctl0.syspll0ctl0().read().bypass().is_programmed_clk() | ||
| 995 | { | ||
| 996 | let mut temp; | ||
| 997 | temp = self.freq.load(Ordering::Relaxed) | ||
| 998 | * u32::from(clkctl0.syspll0ctl0().read().mult().bits()); | ||
| 999 | temp = (u64::from(temp) * 18 / u64::from(clkctl0.syspll0pfd().read().pfd0().bits())) as u32; | ||
| 1000 | return Ok((converted_clock, temp)); | ||
| 1001 | } | ||
| 1002 | Ok((converted_clock, self.freq.load(Ordering::Relaxed) / div)) | ||
| 1003 | } | ||
| 1004 | Err(clk_err) => Err(clk_err), | ||
| 1005 | } | ||
| 1006 | } | ||
| 1007 | _ => Err(ClockError::ClockMismatch), | ||
| 1008 | } | ||
| 1009 | } | ||
| 1010 | fn set_clock_source_and_rate( | ||
| 1011 | &mut self, | ||
| 1012 | clock_src_config: &mut impl ConfigurableClock, | ||
| 1013 | clock_src: &Clocks, | ||
| 1014 | rate: u32, | ||
| 1015 | ) -> Result<(), ClockError> { | ||
| 1016 | if !clock_src_config.is_enabled() { | ||
| 1017 | return Err(ClockError::ClockNotEnabled); | ||
| 1018 | } | ||
| 1019 | if let Ok(c) = <Clocks as TryInto<MainClkSrc>>::try_into(*clock_src) { | ||
| 1020 | // SAFETY: unsafe needed to take pointer to Clkctl0 | ||
| 1021 | // needed to change the clock source | ||
| 1022 | let clkctl0 = unsafe { crate::pac::Clkctl0::steal() }; | ||
| 1023 | match c { | ||
| 1024 | MainClkSrc::ClkIn => { | ||
| 1025 | self.src = MainClkSrc::ClkIn; | ||
| 1026 | |||
| 1027 | clkctl0.mainclksela().write(|w| w.sel().sysxtal_clk()); | ||
| 1028 | clkctl0.mainclkselb().write(|w| w.sel().main_1st_clk()); | ||
| 1029 | Ok(()) | ||
| 1030 | } | ||
| 1031 | // the following will yield the same result as if compared to FFROdiv4 | ||
| 1032 | MainClkSrc::FFRO | MainClkSrc::FFROdiv4 => match rate { | ||
| 1033 | div4 if div4 == (FfroFreq::Ffro60m as u32) / 4 || div4 == (FfroFreq::Ffro48m as u32) / 4 => { | ||
| 1034 | self.src = MainClkSrc::FFROdiv4; | ||
| 1035 | self.freq.store(div4, Ordering::Relaxed); | ||
| 1036 | |||
| 1037 | clkctl0.mainclksela().write(|w| w.sel().ffro_div_4()); | ||
| 1038 | clkctl0.mainclkselb().write(|w| w.sel().main_1st_clk()); | ||
| 1039 | Ok(()) | ||
| 1040 | } | ||
| 1041 | div1 if div1 == FfroFreq::Ffro60m as u32 || div1 == FfroFreq::Ffro48m as u32 => { | ||
| 1042 | self.src = MainClkSrc::FFRO; | ||
| 1043 | self.freq.store(div1, Ordering::Relaxed); | ||
| 1044 | |||
| 1045 | clkctl0.mainclksela().write(|w| w.sel().ffro_clk()); | ||
| 1046 | clkctl0.mainclkselb().write(|w| w.sel().main_1st_clk()); | ||
| 1047 | Ok(()) | ||
| 1048 | } | ||
| 1049 | _ => Err(ClockError::InvalidFrequency), | ||
| 1050 | }, | ||
| 1051 | MainClkSrc::Lposc => { | ||
| 1052 | if let Ok(r) = <u32 as TryInto<LposcFreq>>::try_into(rate) { | ||
| 1053 | match r { | ||
| 1054 | LposcFreq::Lp1m => { | ||
| 1055 | self.src = MainClkSrc::Lposc; | ||
| 1056 | self.freq.store(rate, Ordering::Relaxed); | ||
| 1057 | |||
| 1058 | clkctl0.mainclksela().write(|w| w.sel().lposc()); | ||
| 1059 | clkctl0.mainclkselb().write(|w| w.sel().main_1st_clk()); | ||
| 1060 | Ok(()) | ||
| 1061 | } | ||
| 1062 | LposcFreq::Lp32k => Err(ClockError::InvalidFrequency), | ||
| 1063 | } | ||
| 1064 | } else { | ||
| 1065 | Err(ClockError::InvalidFrequency) | ||
| 1066 | } | ||
| 1067 | } | ||
| 1068 | MainClkSrc::SFRO => { | ||
| 1069 | if rate == SFRO_FREQ { | ||
| 1070 | self.src = MainClkSrc::SFRO; | ||
| 1071 | self.freq.store(rate, Ordering::Relaxed); | ||
| 1072 | clkctl0.mainclkselb().write(|w| w.sel().sfro_clk()); | ||
| 1073 | Ok(()) | ||
| 1074 | } else { | ||
| 1075 | Err(ClockError::InvalidFrequency) | ||
| 1076 | } | ||
| 1077 | } | ||
| 1078 | MainClkSrc::PllMain => { | ||
| 1079 | let r = rate; | ||
| 1080 | // From Section 4.6.1.1 Pll Limitations of the RT6xx User manual | ||
| 1081 | let pll_max = 572_000_000; | ||
| 1082 | let pll_min = 80_000_000; | ||
| 1083 | if pll_min <= r && r <= pll_max { | ||
| 1084 | clkctl0.mainclkselb().write(|w| w.sel().main_pll_clk()); | ||
| 1085 | self.src = MainClkSrc::PllMain; | ||
| 1086 | self.freq.store(r, Ordering::Relaxed); | ||
| 1087 | Ok(()) | ||
| 1088 | } else { | ||
| 1089 | Err(ClockError::InvalidFrequency) | ||
| 1090 | } | ||
| 1091 | } | ||
| 1092 | MainClkSrc::RTC32k => { | ||
| 1093 | if rate == RtcFreq::SubSecond32kHz as u32 { | ||
| 1094 | self.src = MainClkSrc::RTC32k; | ||
| 1095 | self.freq.store(rate, Ordering::Relaxed); | ||
| 1096 | clkctl0.mainclkselb().write(|w| w.sel().rtc_32k_clk()); | ||
| 1097 | Ok(()) | ||
| 1098 | } else { | ||
| 1099 | Err(ClockError::InvalidFrequency) | ||
| 1100 | } | ||
| 1101 | } | ||
| 1102 | } | ||
| 1103 | } else { | ||
| 1104 | Err(ClockError::ClockNotSupported) | ||
| 1105 | } | ||
| 1106 | } | ||
| 1107 | } | ||
| 1108 | |||
| 1109 | impl ConfigurableClock for MainClkConfig { | ||
| 1110 | fn enable_and_reset(&self) -> Result<(), ClockError> { | ||
| 1111 | MainClkConfig::init_main_clk(); | ||
| 1112 | Ok(()) | ||
| 1113 | } | ||
| 1114 | fn disable(&self) -> Result<(), ClockError> { | ||
| 1115 | error!("Attempting to reset the main clock, should NOT happen during runtime"); | ||
| 1116 | Err(ClockError::ClockNotSupported) | ||
| 1117 | } | ||
| 1118 | fn get_clock_rate(&self) -> Result<u32, ClockError> { | ||
| 1119 | let (_c, rate) = MainClkConfig::get_clock_source_and_rate(self, &Clocks::MainClk)?; | ||
| 1120 | Ok(rate) | ||
| 1121 | } | ||
| 1122 | fn set_clock_rate(&mut self, _div: u8, _mult: u8, _freq: u32) -> Result<(), ClockError> { | ||
| 1123 | error!("The multi-source set_clock_rate_and_source method should be used instead of set_clock_rate"); | ||
| 1124 | Err(ClockError::ClockNotSupported) | ||
| 1125 | } | ||
| 1126 | fn is_enabled(&self) -> bool { | ||
| 1127 | self.state == State::Enabled | ||
| 1128 | } | ||
| 1129 | } | ||
| 1130 | |||
| 1131 | impl ConfigurableClock for ClkInConfig { | ||
| 1132 | fn enable_and_reset(&self) -> Result<(), ClockError> { | ||
| 1133 | // External Input, no hw writes needed | ||
| 1134 | Ok(()) | ||
| 1135 | } | ||
| 1136 | fn disable(&self) -> Result<(), ClockError> { | ||
| 1137 | error!("Attempting to reset a clock input"); | ||
| 1138 | Err(ClockError::ClockNotSupported) | ||
| 1139 | } | ||
| 1140 | fn get_clock_rate(&self) -> Result<u32, ClockError> { | ||
| 1141 | if self.freq.is_some() { | ||
| 1142 | Ok(self.freq.as_ref().unwrap().load(Ordering::Relaxed)) | ||
| 1143 | } else { | ||
| 1144 | Err(ClockError::ClockNotEnabled) | ||
| 1145 | } | ||
| 1146 | } | ||
| 1147 | fn set_clock_rate(&mut self, _div: u8, _mult: u8, freq: u32) -> Result<(), ClockError> { | ||
| 1148 | trace!("Setting value of clk in config, this won't change the clock itself"); | ||
| 1149 | self.freq.as_ref().unwrap().store(freq, Ordering::Relaxed); | ||
| 1150 | Ok(()) | ||
| 1151 | } | ||
| 1152 | fn is_enabled(&self) -> bool { | ||
| 1153 | self.state == State::Enabled | ||
| 1154 | } | ||
| 1155 | } | ||
| 1156 | |||
| 1157 | impl RtcClkConfig { | ||
| 1158 | /// Register writes to initialize the RTC Clock | ||
| 1159 | fn init_rtc_clk() { | ||
| 1160 | // SAFETY: unsafe needed to take pointer to Clkctl0, Clkctl1, and RTC | ||
| 1161 | // needed to enable the RTC HW | ||
| 1162 | let cc0 = unsafe { pac::Clkctl0::steal() }; | ||
| 1163 | let cc1 = unsafe { pac::Clkctl1::steal() }; | ||
| 1164 | let r = unsafe { pac::Rtc::steal() }; | ||
| 1165 | // Enable the RTC peripheral clock | ||
| 1166 | cc1.pscctl2_set().write(|w| w.rtc_lite_clk_set().set_clock()); | ||
| 1167 | // Make sure the reset bit is cleared amd RTC OSC is powered up | ||
| 1168 | r.ctrl().modify(|_, w| w.swreset().not_in_reset().rtc_osc_pd().enable()); | ||
| 1169 | |||
| 1170 | // set initial match value, note that with a 15 bit count-down timer this would | ||
| 1171 | // typically be 0x8000, but we are "doing some clever things" in time-driver.rs, | ||
| 1172 | // read more about it in the comments there | ||
| 1173 | // SAFETY: unsafe needed to write the bits | ||
| 1174 | r.wake().write(|w| unsafe { w.bits(0xA) }); | ||
| 1175 | |||
| 1176 | // Enable 32K OSC | ||
| 1177 | cc0.osc32khzctl0().write(|w| w.ena32khz().enabled()); | ||
| 1178 | |||
| 1179 | // enable rtc clk | ||
| 1180 | r.ctrl().modify(|_, w| w.rtc_en().enable()); | ||
| 1181 | } | ||
| 1182 | } | ||
| 1183 | |||
| 1184 | impl ConfigurableClock for RtcClkConfig { | ||
| 1185 | fn enable_and_reset(&self) -> Result<(), ClockError> { | ||
| 1186 | // should only be called once if previously disabled | ||
| 1187 | RtcClkConfig::init_rtc_clk(); | ||
| 1188 | Ok(()) | ||
| 1189 | } | ||
| 1190 | fn disable(&self) -> Result<(), ClockError> { | ||
| 1191 | error!("Resetting the RTC clock, this should NOT happen during runtime"); | ||
| 1192 | Err(ClockError::ClockNotSupported) | ||
| 1193 | } | ||
| 1194 | fn set_clock_rate(&mut self, _div: u8, _mult: u8, freq: u32) -> Result<(), ClockError> { | ||
| 1195 | if let Ok(r) = <u32 as TryInto<RtcFreq>>::try_into(freq) { | ||
| 1196 | // SAFETY: unsafe needed to take pointer to RTC | ||
| 1197 | // needed to enable the HW for the different RTC frequencies, powered down by default | ||
| 1198 | let rtc = unsafe { crate::pac::Rtc::steal() }; | ||
| 1199 | match r { | ||
| 1200 | RtcFreq::Default1Hz => { | ||
| 1201 | if rtc.ctrl().read().rtc_en().is_enable() { | ||
| 1202 | trace!("Attempting to enable an already enabled clock, RTC 1Hz"); | ||
| 1203 | } else { | ||
| 1204 | rtc.ctrl().modify(|_r, w| w.rtc_en().enable()); | ||
| 1205 | } | ||
| 1206 | Ok(()) | ||
| 1207 | } | ||
| 1208 | RtcFreq::HighResolution1khz => { | ||
| 1209 | if rtc.ctrl().read().rtc1khz_en().is_enable() { | ||
| 1210 | trace!("Attempting to enable an already enabled clock, RTC 1Hz"); | ||
| 1211 | } else { | ||
| 1212 | rtc.ctrl().modify(|_r, w| w.rtc1khz_en().enable()); | ||
| 1213 | } | ||
| 1214 | Ok(()) | ||
| 1215 | } | ||
| 1216 | RtcFreq::SubSecond32kHz => { | ||
| 1217 | if rtc.ctrl().read().rtc_subsec_ena().is_enable() { | ||
| 1218 | trace!("Attempting to enable an already enabled clock, RTC 1Hz"); | ||
| 1219 | } else { | ||
| 1220 | rtc.ctrl().modify(|_r, w| w.rtc_subsec_ena().enable()); | ||
| 1221 | } | ||
| 1222 | Ok(()) | ||
| 1223 | } | ||
| 1224 | } | ||
| 1225 | } else { | ||
| 1226 | Err(ClockError::InvalidFrequency) | ||
| 1227 | } | ||
| 1228 | } | ||
| 1229 | // unlike the others, since this provides multiple clocks, return the fastest one | ||
| 1230 | fn get_clock_rate(&self) -> Result<u32, ClockError> { | ||
| 1231 | if self.sub_second_state == State::Enabled { | ||
| 1232 | Ok(RtcFreq::SubSecond32kHz as u32) | ||
| 1233 | } else if self.wake_alarm_state == State::Enabled { | ||
| 1234 | Ok(RtcFreq::HighResolution1khz as u32) | ||
| 1235 | } else if self.state == State::Enabled { | ||
| 1236 | Ok(RtcFreq::Default1Hz as u32) | ||
| 1237 | } else { | ||
| 1238 | Err(ClockError::ClockNotEnabled) | ||
| 1239 | } | ||
| 1240 | } | ||
| 1241 | fn is_enabled(&self) -> bool { | ||
| 1242 | self.state == State::Enabled | ||
| 1243 | } | ||
| 1244 | } | ||
| 1245 | |||
| 1246 | impl SysClkConfig { | ||
| 1247 | /// Updates the system core clock frequency, SW concept used for systick | ||
| 1248 | fn update_sys_core_clock(&self) { | ||
| 1249 | trace!( | ||
| 1250 | "System core clock has been updated to {:?}, this involves no HW reg writes", | ||
| 1251 | self.sysclkfreq.load(Ordering::Relaxed) | ||
| 1252 | ); | ||
| 1253 | } | ||
| 1254 | } | ||
| 1255 | |||
| 1256 | impl ConfigurableClock for SysOscConfig { | ||
| 1257 | fn enable_and_reset(&self) -> Result<(), ClockError> { | ||
| 1258 | if self.state == State::Enabled { | ||
| 1259 | trace!("SysOsc was already enabled"); | ||
| 1260 | return Ok(()); | ||
| 1261 | } | ||
| 1262 | |||
| 1263 | // SAFETY: unsafe needed to take pointers to Sysctl0 and Clkctl0, needed to modify clock HW | ||
| 1264 | let clkctl0 = unsafe { crate::pac::Clkctl0::steal() }; | ||
| 1265 | let sysctl0 = unsafe { crate::pac::Sysctl0::steal() }; | ||
| 1266 | |||
| 1267 | // Let CPU run on ffro for safe switching | ||
| 1268 | clkctl0.mainclksela().write(|w| w.sel().ffro_clk()); | ||
| 1269 | clkctl0.mainclksela().write(|w| w.sel().ffro_div_4()); | ||
| 1270 | |||
| 1271 | // Power on SYSXTAL | ||
| 1272 | sysctl0.pdruncfg0_clr().write(|w| w.sysxtal_pd().clr_pdruncfg0()); | ||
| 1273 | |||
| 1274 | // Enable system OSC | ||
| 1275 | clkctl0 | ||
| 1276 | .sysoscctl0() | ||
| 1277 | .write(|w| w.lp_enable().lp().bypass_enable().normal_mode()); | ||
| 1278 | |||
| 1279 | delay_loop_clocks(260, SYS_OSC_DEFAULT_FREQ.into()); | ||
| 1280 | Ok(()) | ||
| 1281 | } | ||
| 1282 | fn disable(&self) -> Result<(), ClockError> { | ||
| 1283 | // SAFETY: unsafe needed to take pointers to Sysctl0 and Clkctl0, needed to modify clock HW | ||
| 1284 | let clkctl0 = unsafe { crate::pac::Clkctl0::steal() }; | ||
| 1285 | let sysctl0 = unsafe { crate::pac::Sysctl0::steal() }; | ||
| 1286 | |||
| 1287 | // Let CPU run on ffro for safe switching | ||
| 1288 | clkctl0.mainclksela().write(|w| w.sel().ffro_clk()); | ||
| 1289 | clkctl0.mainclksela().write(|w| w.sel().ffro_div_4()); | ||
| 1290 | |||
| 1291 | // Power on SYSXTAL | ||
| 1292 | sysctl0.pdruncfg0_set().write(|w| w.sysxtal_pd().set_pdruncfg0()); | ||
| 1293 | Ok(()) | ||
| 1294 | } | ||
| 1295 | fn get_clock_rate(&self) -> Result<u32, ClockError> { | ||
| 1296 | if self.state == State::Enabled { | ||
| 1297 | Ok(SYS_OSC_DEFAULT_FREQ) | ||
| 1298 | } else { | ||
| 1299 | Err(ClockError::ClockNotEnabled) | ||
| 1300 | } | ||
| 1301 | } | ||
| 1302 | fn is_enabled(&self) -> bool { | ||
| 1303 | self.state == State::Enabled | ||
| 1304 | } | ||
| 1305 | fn set_clock_rate(&mut self, _div: u8, _mult: u8, _freq: u32) -> Result<(), ClockError> { | ||
| 1306 | Err(ClockError::ClockNotSupported) | ||
| 1307 | } | ||
| 1308 | } | ||
| 1309 | |||
| 1310 | /// Method to delay for a certain number of microseconds given a clock rate | ||
| 1311 | pub fn delay_loop_clocks(usec: u64, freq_mhz: u64) { | ||
| 1312 | let mut ticks = usec * freq_mhz / 1_000_000 / 4; | ||
| 1313 | if ticks > u64::from(u32::MAX) { | ||
| 1314 | ticks = u64::from(u32::MAX); | ||
| 1315 | } | ||
| 1316 | // won't panic since we check value above | ||
| 1317 | cortex_m::asm::delay(ticks as u32); | ||
| 1318 | } | ||
| 1319 | |||
| 1320 | /// Configure the pad voltage pmc registers for all 3 vddio ranges | ||
| 1321 | fn set_pad_voltage_range() { | ||
| 1322 | // SAFETY: unsafe needed to take pointer to PNC as well as to write specific bits | ||
| 1323 | unsafe { | ||
| 1324 | let pmc = crate::pac::Pmc::steal(); | ||
| 1325 | // Set up IO voltages | ||
| 1326 | // all 3 ranges need to be 1.71-1.98V which is 01 | ||
| 1327 | pmc.padvrange().write(|w| { | ||
| 1328 | w.vddio_0range() | ||
| 1329 | .bits(0b01) | ||
| 1330 | .vddio_1range() | ||
| 1331 | .bits(0b01) | ||
| 1332 | .vddio_2range() | ||
| 1333 | .bits(0b01) | ||
| 1334 | }); | ||
| 1335 | } | ||
| 1336 | } | ||
| 1337 | |||
| 1338 | /// Initialize AHB clock | ||
| 1339 | fn init_syscpuahb_clk() { | ||
| 1340 | // SAFETY: unsafe needed to take pointer to Clkctl0 | ||
| 1341 | let clkctl0 = unsafe { crate::pac::Clkctl0::steal() }; | ||
| 1342 | // SAFETY: unsafe needed to write the bits | ||
| 1343 | // Set syscpuahbclkdiv to value 2, Subtract 1 since 0-> 1, 1-> 2, etc... | ||
| 1344 | clkctl0.syscpuahbclkdiv().write(|w| unsafe { w.div().bits(2 - 1) }); | ||
| 1345 | |||
| 1346 | while clkctl0.syscpuahbclkdiv().read().reqflag().bit_is_set() {} | ||
| 1347 | } | ||
| 1348 | |||
| 1349 | /// `ClockOut` config | ||
| 1350 | pub struct ClockOutConfig { | ||
| 1351 | src: ClkOutSrc, | ||
| 1352 | div: u8, | ||
| 1353 | } | ||
| 1354 | |||
| 1355 | /// `ClockOut` sources | ||
| 1356 | #[derive(Clone, Copy, Debug, PartialEq, Eq)] | ||
| 1357 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 1358 | /// `ClockOut` sources | ||
| 1359 | pub enum ClkOutSrc { | ||
| 1360 | /// No Source, reduce power consumption | ||
| 1361 | None, | ||
| 1362 | /// SFRO clock | ||
| 1363 | Sfro, | ||
| 1364 | /// External input clock | ||
| 1365 | ClkIn, | ||
| 1366 | /// Low-power oscillator | ||
| 1367 | Lposc, | ||
| 1368 | /// FFRO clock | ||
| 1369 | Ffro, | ||
| 1370 | /// Main clock | ||
| 1371 | MainClk, | ||
| 1372 | /// Main DSP clock | ||
| 1373 | DspMainClk, | ||
| 1374 | /// Main Pll clock | ||
| 1375 | MainPllClk, | ||
| 1376 | /// `SysPll` Aux0 clock | ||
| 1377 | Aux0PllClk, | ||
| 1378 | /// `SysPll` DSP clock | ||
| 1379 | DspPllClk, | ||
| 1380 | /// `SysPll` Aux1 clock | ||
| 1381 | Aux1PllClk, | ||
| 1382 | /// Audio Pll clock | ||
| 1383 | AudioPllClk, | ||
| 1384 | /// 32 `KHz` RTC | ||
| 1385 | RTC32k, | ||
| 1386 | } | ||
| 1387 | |||
| 1388 | /// Initialize the `ClkOutConfig` | ||
| 1389 | impl ClockOutConfig { | ||
| 1390 | /// Default configuration for Clock out | ||
| 1391 | #[must_use] | ||
| 1392 | pub fn default_config() -> Self { | ||
| 1393 | Self { | ||
| 1394 | src: ClkOutSrc::None, | ||
| 1395 | div: 0, | ||
| 1396 | } | ||
| 1397 | } | ||
| 1398 | |||
| 1399 | /// Enable the Clock Out output | ||
| 1400 | pub fn enable_and_reset(&mut self) -> Result<(), ClockError> { | ||
| 1401 | self.set_clkout_source_and_div(self.src, self.div)?; | ||
| 1402 | Ok(()) | ||
| 1403 | } | ||
| 1404 | |||
| 1405 | /// Disable Clock Out output and select None as the source to conserve power | ||
| 1406 | pub fn disable(&mut self) -> Result<(), ClockError> { | ||
| 1407 | self.set_clkout_source_and_div(ClkOutSrc::None, 0)?; | ||
| 1408 | Ok(()) | ||
| 1409 | } | ||
| 1410 | |||
| 1411 | /// Set the source of the Clock Out pin | ||
| 1412 | fn set_clkout_source(&mut self, src: ClkOutSrc) -> Result<(), ClockError> { | ||
| 1413 | // SAFETY: unsafe needed to take pointers to Clkctl1, needed to set source in HW | ||
| 1414 | let cc1 = unsafe { pac::Clkctl1::steal() }; | ||
| 1415 | match src { | ||
| 1416 | ClkOutSrc::None => { | ||
| 1417 | cc1.clkoutsel0().write(|w| w.sel().none()); | ||
| 1418 | cc1.clkoutsel1().write(|w| w.sel().none()); | ||
| 1419 | } | ||
| 1420 | ClkOutSrc::Sfro => { | ||
| 1421 | cc1.clkoutsel0().write(|w| w.sel().sfro_clk()); | ||
| 1422 | cc1.clkoutsel1().write(|w| w.sel().clkoutsel0_output()); | ||
| 1423 | } | ||
| 1424 | ClkOutSrc::ClkIn => { | ||
| 1425 | cc1.clkoutsel0().write(|w| w.sel().xtalin_clk()); | ||
| 1426 | cc1.clkoutsel1().write(|w| w.sel().clkoutsel0_output()); | ||
| 1427 | } | ||
| 1428 | ClkOutSrc::Lposc => { | ||
| 1429 | cc1.clkoutsel0().write(|w| w.sel().lposc()); | ||
| 1430 | cc1.clkoutsel1().write(|w| w.sel().clkoutsel0_output()); | ||
| 1431 | } | ||
| 1432 | ClkOutSrc::Ffro => { | ||
| 1433 | cc1.clkoutsel0().write(|w| w.sel().ffro_clk()); | ||
| 1434 | cc1.clkoutsel1().write(|w| w.sel().clkoutsel0_output()); | ||
| 1435 | } | ||
| 1436 | ClkOutSrc::MainClk => { | ||
| 1437 | cc1.clkoutsel0().write(|w| w.sel().main_clk()); | ||
| 1438 | cc1.clkoutsel1().write(|w| w.sel().clkoutsel0_output()); | ||
| 1439 | } | ||
| 1440 | ClkOutSrc::DspMainClk => { | ||
| 1441 | cc1.clkoutsel0().write(|w| w.sel().dsp_main_clk()); | ||
| 1442 | cc1.clkoutsel1().write(|w| w.sel().clkoutsel0_output()); | ||
| 1443 | } | ||
| 1444 | ClkOutSrc::MainPllClk => { | ||
| 1445 | cc1.clkoutsel0().write(|w| w.sel().none()); | ||
| 1446 | cc1.clkoutsel1().write(|w| w.sel().main_pll_clk()); | ||
| 1447 | } | ||
| 1448 | ClkOutSrc::Aux0PllClk => { | ||
| 1449 | cc1.clkoutsel0().write(|w| w.sel().none()); | ||
| 1450 | cc1.clkoutsel1().write(|w| w.sel().syspll0_aux0_pll_clk()); | ||
| 1451 | } | ||
| 1452 | ClkOutSrc::DspPllClk => { | ||
| 1453 | cc1.clkoutsel0().write(|w| w.sel().none()); | ||
| 1454 | cc1.clkoutsel1().write(|w| w.sel().dsp_pll_clk()); | ||
| 1455 | } | ||
| 1456 | ClkOutSrc::AudioPllClk => { | ||
| 1457 | cc1.clkoutsel0().write(|w| w.sel().none()); | ||
| 1458 | cc1.clkoutsel1().write(|w| w.sel().audio_pll_clk()); | ||
| 1459 | } | ||
| 1460 | ClkOutSrc::Aux1PllClk => { | ||
| 1461 | cc1.clkoutsel0().write(|w| w.sel().none()); | ||
| 1462 | cc1.clkoutsel1().write(|w| w.sel().syspll0_aux1_pll_clk()); | ||
| 1463 | } | ||
| 1464 | ClkOutSrc::RTC32k => { | ||
| 1465 | cc1.clkoutsel0().write(|w| w.sel().none()); | ||
| 1466 | cc1.clkoutsel1().write(|w| w.sel().rtc_clk_32khz()); | ||
| 1467 | } | ||
| 1468 | } | ||
| 1469 | self.src = src; | ||
| 1470 | Ok(()) | ||
| 1471 | } | ||
| 1472 | /// set the clock out divider | ||
| 1473 | /// note that 1 will be added to div when mapping to the divider | ||
| 1474 | /// so bits(0) -> divide by 1 | ||
| 1475 | /// ... | ||
| 1476 | /// bits(255)-> divide by 256 | ||
| 1477 | pub fn set_clkout_divider(&self, div: u8) -> Result<(), ClockError> { | ||
| 1478 | // don't wait for clock to be ready if there's no source | ||
| 1479 | if self.src != ClkOutSrc::None { | ||
| 1480 | let cc1 = unsafe { pac::Clkctl1::steal() }; | ||
| 1481 | |||
| 1482 | cc1.clkoutdiv() | ||
| 1483 | .modify(|_, w| unsafe { w.div().bits(div).halt().clear_bit() }); | ||
| 1484 | while cc1.clkoutdiv().read().reqflag().bit_is_set() {} | ||
| 1485 | } | ||
| 1486 | Ok(()) | ||
| 1487 | } | ||
| 1488 | /// set the source and divider for the clockout pin | ||
| 1489 | pub fn set_clkout_source_and_div(&mut self, src: ClkOutSrc, div: u8) -> Result<(), ClockError> { | ||
| 1490 | self.set_clkout_source(src)?; | ||
| 1491 | |||
| 1492 | self.set_clkout_divider(div)?; | ||
| 1493 | |||
| 1494 | Ok(()) | ||
| 1495 | } | ||
| 1496 | } | ||
| 1497 | |||
| 1498 | /// Using the config, enables all desired clocks to desired clock rates | ||
| 1499 | fn init_clock_hw(config: ClockConfig) -> Result<(), ClockError> { | ||
| 1500 | if let Err(e) = config.rtc.enable_and_reset() { | ||
| 1501 | error!("couldn't Power on OSC for RTC, result: {:?}", e); | ||
| 1502 | return Err(e); | ||
| 1503 | } | ||
| 1504 | |||
| 1505 | if let Err(e) = config.lposc.enable_and_reset() { | ||
| 1506 | error!("couldn't Power on LPOSC, result: {:?}", e); | ||
| 1507 | return Err(e); | ||
| 1508 | } | ||
| 1509 | |||
| 1510 | if let Err(e) = config.ffro.enable_and_reset() { | ||
| 1511 | error!("couldn't Power on FFRO, result: {:?}", e); | ||
| 1512 | return Err(e); | ||
| 1513 | } | ||
| 1514 | |||
| 1515 | if let Err(e) = config.sfro.enable_and_reset() { | ||
| 1516 | error!("couldn't Power on SFRO, result: {:?}", e); | ||
| 1517 | return Err(e); | ||
| 1518 | } | ||
| 1519 | |||
| 1520 | if let Err(e) = config.sys_osc.enable_and_reset() { | ||
| 1521 | error!("Couldn't enable sys oscillator {:?}", e); | ||
| 1522 | return Err(e); | ||
| 1523 | } | ||
| 1524 | |||
| 1525 | if let Err(e) = config.main_pll_clk.enable_and_reset() { | ||
| 1526 | error!("Couldn't enable main pll clock {:?}", e); | ||
| 1527 | return Err(e); | ||
| 1528 | } | ||
| 1529 | |||
| 1530 | // Move FLEXSPI clock source from main clock to FFRO to avoid instruction/data fetch issue in XIP when | ||
| 1531 | // updating PLL and main clock. | ||
| 1532 | // SAFETY: unsafe needed to take pointers to Clkctl0 | ||
| 1533 | let cc0 = unsafe { pac::Clkctl0::steal() }; | ||
| 1534 | cc0.flexspifclksel().write(|w| w.sel().ffro_clk()); | ||
| 1535 | |||
| 1536 | // Move ESPI clock source to FFRO | ||
| 1537 | #[cfg(feature = "_espi")] | ||
| 1538 | { | ||
| 1539 | cc0.espiclksel().write(|w| w.sel().use_48_60m()); | ||
| 1540 | } | ||
| 1541 | |||
| 1542 | init_syscpuahb_clk(); | ||
| 1543 | |||
| 1544 | if let Err(e) = config.main_clk.enable_and_reset() { | ||
| 1545 | error!("Couldn't enable main clock {:?}", e); | ||
| 1546 | return Err(e); | ||
| 1547 | } | ||
| 1548 | |||
| 1549 | config.sys_clk.update_sys_core_clock(); | ||
| 1550 | Ok(()) | ||
| 1551 | } | ||
| 1552 | |||
| 1553 | /// SAFETY: must be called exactly once at bootup | ||
| 1554 | pub(crate) unsafe fn init(config: ClockConfig) -> Result<(), ClockError> { | ||
| 1555 | init_clock_hw(config)?; | ||
| 1556 | |||
| 1557 | // set VDDIO ranges 0-2 | ||
| 1558 | set_pad_voltage_range(); | ||
| 1559 | Ok(()) | ||
| 1560 | } | ||
| 1561 | |||
| 1562 | ///Trait to expose perph clocks | ||
| 1563 | trait SealedSysconPeripheral { | ||
| 1564 | fn enable_and_reset_perph_clock(); | ||
| 1565 | fn disable_perph_clock(); | ||
| 1566 | } | ||
| 1567 | |||
| 1568 | /// Clock and Reset control for peripherals | ||
| 1569 | #[allow(private_bounds)] | ||
| 1570 | pub trait SysconPeripheral: SealedSysconPeripheral + 'static {} | ||
| 1571 | /// Enables and resets peripheral `T`. | ||
| 1572 | /// | ||
| 1573 | /// # Safety | ||
| 1574 | /// | ||
| 1575 | /// Peripheral must not be in use. | ||
| 1576 | pub fn enable_and_reset<T: SysconPeripheral>() { | ||
| 1577 | T::enable_and_reset_perph_clock(); | ||
| 1578 | } | ||
| 1579 | |||
| 1580 | /// Disables peripheral `T`. | ||
| 1581 | /// | ||
| 1582 | /// # Safety | ||
| 1583 | /// | ||
| 1584 | /// Peripheral must not be in use. | ||
| 1585 | pub fn disable<T: SysconPeripheral>() { | ||
| 1586 | T::disable_perph_clock(); | ||
| 1587 | } | ||
| 1588 | macro_rules! impl_perph_clk { | ||
| 1589 | ($peripheral:ident, $clkctl:ident, $clkreg:ident, $rstctl:ident, $rstreg:ident, $bit:expr) => { | ||
| 1590 | impl SealedSysconPeripheral for crate::peripherals::$peripheral { | ||
| 1591 | fn enable_and_reset_perph_clock() { | ||
| 1592 | // SAFETY: unsafe needed to take pointers to Rstctl1 and Clkctl1 | ||
| 1593 | let cc1 = unsafe { pac::$clkctl::steal() }; | ||
| 1594 | let rc1 = unsafe { pac::$rstctl::steal() }; | ||
| 1595 | |||
| 1596 | paste! { | ||
| 1597 | // SAFETY: unsafe due to the use of bits() | ||
| 1598 | cc1.[<$clkreg _set>]().write(|w| unsafe { w.bits(1 << $bit) }); | ||
| 1599 | |||
| 1600 | // SAFETY: unsafe due to the use of bits() | ||
| 1601 | rc1.[<$rstreg _clr>]().write(|w| unsafe { w.bits(1 << $bit) }); | ||
| 1602 | } | ||
| 1603 | } | ||
| 1604 | |||
| 1605 | fn disable_perph_clock() { | ||
| 1606 | // SAFETY: unsafe needed to take pointers to Rstctl1 and Clkctl1 | ||
| 1607 | let cc1 = unsafe { pac::$clkctl::steal() }; | ||
| 1608 | let rc1 = unsafe { pac::$rstctl::steal() }; | ||
| 1609 | |||
| 1610 | paste! { | ||
| 1611 | // SAFETY: unsafe due to the use of bits() | ||
| 1612 | rc1.[<$rstreg _set>]().write(|w| unsafe { w.bits(1 << $bit) }); | ||
| 1613 | |||
| 1614 | // SAFETY: unsafe due to the use of bits() | ||
| 1615 | cc1.[<$clkreg _clr>]().write(|w| unsafe { w.bits(1 << $bit) }); | ||
| 1616 | } | ||
| 1617 | } | ||
| 1618 | } | ||
| 1619 | |||
| 1620 | impl SysconPeripheral for crate::peripherals::$peripheral {} | ||
| 1621 | }; | ||
| 1622 | } | ||
| 1623 | |||
| 1624 | // These should enabled once the relevant peripherals are implemented. | ||
| 1625 | // impl_perph_clk!(GPIOINTCTL, Clkctl1, pscctl2, Rstctl1, prstctl2, 30); | ||
| 1626 | // impl_perph_clk!(OTP, Clkctl0, pscctl0, Rstctl0, prstctl0, 17); | ||
| 1627 | |||
| 1628 | // impl_perph_clk!(ROM_CTL_128KB, Clkctl0, pscctl0, Rstctl0, prstctl0, 2); | ||
| 1629 | // impl_perph_clk!(USBHS_SRAM, Clkctl0, pscctl0, Rstctl0, prstctl0, 23); | ||
| 1630 | |||
| 1631 | impl_perph_clk!(PIMCTL, Clkctl1, pscctl2, Rstctl1, prstctl2, 31); | ||
| 1632 | impl_perph_clk!(ACMP, Clkctl0, pscctl1, Rstctl0, prstctl1, 15); | ||
| 1633 | impl_perph_clk!(ADC0, Clkctl0, pscctl1, Rstctl0, prstctl1, 16); | ||
| 1634 | impl_perph_clk!(CASPER, Clkctl0, pscctl0, Rstctl0, prstctl0, 9); | ||
| 1635 | impl_perph_clk!(CRC, Clkctl1, pscctl1, Rstctl1, prstctl1, 16); | ||
| 1636 | impl_perph_clk!(CTIMER0_COUNT_CHANNEL0, Clkctl1, pscctl2, Rstctl1, prstctl2, 0); | ||
| 1637 | impl_perph_clk!(CTIMER1_COUNT_CHANNEL0, Clkctl1, pscctl2, Rstctl1, prstctl2, 1); | ||
| 1638 | impl_perph_clk!(CTIMER2_COUNT_CHANNEL0, Clkctl1, pscctl2, Rstctl1, prstctl2, 2); | ||
| 1639 | impl_perph_clk!(CTIMER3_COUNT_CHANNEL0, Clkctl1, pscctl2, Rstctl1, prstctl2, 3); | ||
| 1640 | impl_perph_clk!(CTIMER4_COUNT_CHANNEL0, Clkctl1, pscctl2, Rstctl1, prstctl2, 4); | ||
| 1641 | impl_perph_clk!(DMA0, Clkctl1, pscctl1, Rstctl1, prstctl1, 23); | ||
| 1642 | impl_perph_clk!(DMA1, Clkctl1, pscctl1, Rstctl1, prstctl1, 24); | ||
| 1643 | impl_perph_clk!(DMIC0, Clkctl1, pscctl0, Rstctl1, prstctl0, 24); | ||
| 1644 | |||
| 1645 | #[cfg(feature = "_espi")] | ||
| 1646 | impl_perph_clk!(ESPI, Clkctl0, pscctl1, Rstctl0, prstctl1, 7); | ||
| 1647 | |||
| 1648 | impl_perph_clk!(FLEXCOMM0, Clkctl1, pscctl0, Rstctl1, prstctl0, 8); | ||
| 1649 | impl_perph_clk!(FLEXCOMM1, Clkctl1, pscctl0, Rstctl1, prstctl0, 9); | ||
| 1650 | impl_perph_clk!(FLEXCOMM14, Clkctl1, pscctl0, Rstctl1, prstctl0, 22); | ||
| 1651 | impl_perph_clk!(FLEXCOMM15, Clkctl1, pscctl0, Rstctl1, prstctl0, 23); | ||
| 1652 | impl_perph_clk!(FLEXCOMM2, Clkctl1, pscctl0, Rstctl1, prstctl0, 10); | ||
| 1653 | impl_perph_clk!(FLEXCOMM3, Clkctl1, pscctl0, Rstctl1, prstctl0, 11); | ||
| 1654 | impl_perph_clk!(FLEXCOMM4, Clkctl1, pscctl0, Rstctl1, prstctl0, 12); | ||
| 1655 | impl_perph_clk!(FLEXCOMM5, Clkctl1, pscctl0, Rstctl1, prstctl0, 13); | ||
| 1656 | impl_perph_clk!(FLEXCOMM6, Clkctl1, pscctl0, Rstctl1, prstctl0, 14); | ||
| 1657 | impl_perph_clk!(FLEXCOMM7, Clkctl1, pscctl0, Rstctl1, prstctl0, 15); | ||
| 1658 | impl_perph_clk!(FLEXSPI, Clkctl0, pscctl0, Rstctl0, prstctl0, 16); | ||
| 1659 | impl_perph_clk!(FREQME, Clkctl1, pscctl1, Rstctl1, prstctl1, 31); | ||
| 1660 | impl_perph_clk!(HASHCRYPT, Clkctl0, pscctl0, Rstctl0, prstctl0, 10); | ||
| 1661 | impl_perph_clk!(HSGPIO0, Clkctl1, pscctl1, Rstctl1, prstctl1, 0); | ||
| 1662 | impl_perph_clk!(HSGPIO1, Clkctl1, pscctl1, Rstctl1, prstctl1, 1); | ||
| 1663 | impl_perph_clk!(HSGPIO2, Clkctl1, pscctl1, Rstctl1, prstctl1, 2); | ||
| 1664 | impl_perph_clk!(HSGPIO3, Clkctl1, pscctl1, Rstctl1, prstctl1, 3); | ||
| 1665 | impl_perph_clk!(HSGPIO4, Clkctl1, pscctl1, Rstctl1, prstctl1, 4); | ||
| 1666 | impl_perph_clk!(HSGPIO5, Clkctl1, pscctl1, Rstctl1, prstctl1, 5); | ||
| 1667 | impl_perph_clk!(HSGPIO6, Clkctl1, pscctl1, Rstctl1, prstctl1, 6); | ||
| 1668 | impl_perph_clk!(HSGPIO7, Clkctl1, pscctl1, Rstctl1, prstctl1, 7); | ||
| 1669 | impl_perph_clk!(I3C0, Clkctl1, pscctl2, Rstctl1, prstctl2, 16); | ||
| 1670 | impl_perph_clk!(MRT0, Clkctl1, pscctl2, Rstctl1, prstctl2, 8); | ||
| 1671 | impl_perph_clk!(MU_A, Clkctl1, pscctl1, Rstctl1, prstctl1, 28); | ||
| 1672 | impl_perph_clk!(OS_EVENT, Clkctl1, pscctl0, Rstctl1, prstctl0, 27); | ||
| 1673 | impl_perph_clk!(POWERQUAD, Clkctl0, pscctl0, Rstctl0, prstctl0, 8); | ||
| 1674 | impl_perph_clk!(PUF, Clkctl0, pscctl0, Rstctl0, prstctl0, 11); | ||
| 1675 | impl_perph_clk!(RNG, Clkctl0, pscctl0, Rstctl0, prstctl0, 12); | ||
| 1676 | impl_perph_clk!(RTC, Clkctl1, pscctl2, Rstctl1, prstctl2, 7); | ||
| 1677 | impl_perph_clk!(SCT0, Clkctl0, pscctl0, Rstctl0, prstctl0, 24); | ||
| 1678 | impl_perph_clk!(SECGPIO, Clkctl0, pscctl1, Rstctl0, prstctl1, 24); | ||
| 1679 | impl_perph_clk!(SEMA42, Clkctl1, pscctl1, Rstctl1, prstctl1, 29); | ||
| 1680 | impl_perph_clk!(USBHSD, Clkctl0, pscctl0, Rstctl0, prstctl0, 21); | ||
| 1681 | impl_perph_clk!(USBHSH, Clkctl0, pscctl0, Rstctl0, prstctl0, 22); | ||
| 1682 | impl_perph_clk!(USBPHY, Clkctl0, pscctl0, Rstctl0, prstctl0, 20); | ||
| 1683 | impl_perph_clk!(USDHC0, Clkctl0, pscctl1, Rstctl0, prstctl1, 2); | ||
| 1684 | impl_perph_clk!(USDHC1, Clkctl0, pscctl1, Rstctl0, prstctl1, 3); | ||
| 1685 | impl_perph_clk!(UTICK0, Clkctl0, pscctl2, Rstctl0, prstctl2, 0); | ||
| 1686 | impl_perph_clk!(WDT0, Clkctl0, pscctl2, Rstctl0, prstctl2, 1); | ||
| 1687 | impl_perph_clk!(WDT1, Clkctl1, pscctl2, Rstctl1, prstctl2, 10); | ||
diff --git a/embassy-imxrt/src/fmt.rs b/embassy-imxrt/src/fmt.rs new file mode 100644 index 000000000..c65273340 --- /dev/null +++ b/embassy-imxrt/src/fmt.rs | |||
| @@ -0,0 +1,257 @@ | |||
| 1 | #![macro_use] | ||
| 2 | #![allow(unused)] | ||
| 3 | |||
| 4 | use core::fmt::{Debug, Display, LowerHex}; | ||
| 5 | |||
| 6 | #[collapse_debuginfo(yes)] | ||
| 7 | macro_rules! assert { | ||
| 8 | ($($x:tt)*) => { | ||
| 9 | { | ||
| 10 | #[cfg(not(feature = "defmt"))] | ||
| 11 | ::core::assert!($($x)*); | ||
| 12 | #[cfg(feature = "defmt")] | ||
| 13 | ::defmt::assert!($($x)*); | ||
| 14 | } | ||
| 15 | }; | ||
| 16 | } | ||
| 17 | |||
| 18 | #[collapse_debuginfo(yes)] | ||
| 19 | macro_rules! assert_eq { | ||
| 20 | ($($x:tt)*) => { | ||
| 21 | { | ||
| 22 | #[cfg(not(feature = "defmt"))] | ||
| 23 | ::core::assert_eq!($($x)*); | ||
| 24 | #[cfg(feature = "defmt")] | ||
| 25 | ::defmt::assert_eq!($($x)*); | ||
| 26 | } | ||
| 27 | }; | ||
| 28 | } | ||
| 29 | |||
| 30 | #[collapse_debuginfo(yes)] | ||
| 31 | macro_rules! assert_ne { | ||
| 32 | ($($x:tt)*) => { | ||
| 33 | { | ||
| 34 | #[cfg(not(feature = "defmt"))] | ||
| 35 | ::core::assert_ne!($($x)*); | ||
| 36 | #[cfg(feature = "defmt")] | ||
| 37 | ::defmt::assert_ne!($($x)*); | ||
| 38 | } | ||
| 39 | }; | ||
| 40 | } | ||
| 41 | |||
| 42 | #[collapse_debuginfo(yes)] | ||
| 43 | macro_rules! debug_assert { | ||
| 44 | ($($x:tt)*) => { | ||
| 45 | { | ||
| 46 | #[cfg(not(feature = "defmt"))] | ||
| 47 | ::core::debug_assert!($($x)*); | ||
| 48 | #[cfg(feature = "defmt")] | ||
| 49 | ::defmt::debug_assert!($($x)*); | ||
| 50 | } | ||
| 51 | }; | ||
| 52 | } | ||
| 53 | |||
| 54 | #[collapse_debuginfo(yes)] | ||
| 55 | macro_rules! debug_assert_eq { | ||
| 56 | ($($x:tt)*) => { | ||
| 57 | { | ||
| 58 | #[cfg(not(feature = "defmt"))] | ||
| 59 | ::core::debug_assert_eq!($($x)*); | ||
| 60 | #[cfg(feature = "defmt")] | ||
| 61 | ::defmt::debug_assert_eq!($($x)*); | ||
| 62 | } | ||
| 63 | }; | ||
| 64 | } | ||
| 65 | |||
| 66 | #[collapse_debuginfo(yes)] | ||
| 67 | macro_rules! debug_assert_ne { | ||
| 68 | ($($x:tt)*) => { | ||
| 69 | { | ||
| 70 | #[cfg(not(feature = "defmt"))] | ||
| 71 | ::core::debug_assert_ne!($($x)*); | ||
| 72 | #[cfg(feature = "defmt")] | ||
| 73 | ::defmt::debug_assert_ne!($($x)*); | ||
| 74 | } | ||
| 75 | }; | ||
| 76 | } | ||
| 77 | |||
| 78 | #[collapse_debuginfo(yes)] | ||
| 79 | macro_rules! todo { | ||
| 80 | ($($x:tt)*) => { | ||
| 81 | { | ||
| 82 | #[cfg(not(feature = "defmt"))] | ||
| 83 | ::core::todo!($($x)*); | ||
| 84 | #[cfg(feature = "defmt")] | ||
| 85 | ::defmt::todo!($($x)*); | ||
| 86 | } | ||
| 87 | }; | ||
| 88 | } | ||
| 89 | |||
| 90 | #[collapse_debuginfo(yes)] | ||
| 91 | macro_rules! unreachable { | ||
| 92 | ($($x:tt)*) => { | ||
| 93 | { | ||
| 94 | #[cfg(not(feature = "defmt"))] | ||
| 95 | ::core::unreachable!($($x)*); | ||
| 96 | #[cfg(feature = "defmt")] | ||
| 97 | ::defmt::unreachable!($($x)*); | ||
| 98 | } | ||
| 99 | }; | ||
| 100 | } | ||
| 101 | |||
| 102 | #[collapse_debuginfo(yes)] | ||
| 103 | macro_rules! panic { | ||
| 104 | ($($x:tt)*) => { | ||
| 105 | { | ||
| 106 | #[cfg(not(feature = "defmt"))] | ||
| 107 | ::core::panic!($($x)*); | ||
| 108 | #[cfg(feature = "defmt")] | ||
| 109 | ::defmt::panic!($($x)*); | ||
| 110 | } | ||
| 111 | }; | ||
| 112 | } | ||
| 113 | |||
| 114 | #[collapse_debuginfo(yes)] | ||
| 115 | macro_rules! trace { | ||
| 116 | ($s:literal $(, $x:expr)* $(,)?) => { | ||
| 117 | { | ||
| 118 | #[cfg(feature = "defmt")] | ||
| 119 | ::defmt::trace!($s $(, $x)*); | ||
| 120 | #[cfg(not(feature = "defmt"))] | ||
| 121 | let _ = ($( & $x ),*); | ||
| 122 | } | ||
| 123 | }; | ||
| 124 | } | ||
| 125 | |||
| 126 | #[collapse_debuginfo(yes)] | ||
| 127 | macro_rules! debug { | ||
| 128 | ($s:literal $(, $x:expr)* $(,)?) => { | ||
| 129 | { | ||
| 130 | #[cfg(feature = "defmt")] | ||
| 131 | ::defmt::debug!($s $(, $x)*); | ||
| 132 | #[cfg(not(feature = "defmt"))] | ||
| 133 | let _ = ($( & $x ),*); | ||
| 134 | } | ||
| 135 | }; | ||
| 136 | } | ||
| 137 | |||
| 138 | #[collapse_debuginfo(yes)] | ||
| 139 | macro_rules! info { | ||
| 140 | ($s:literal $(, $x:expr)* $(,)?) => { | ||
| 141 | { | ||
| 142 | #[cfg(feature = "defmt")] | ||
| 143 | ::defmt::info!($s $(, $x)*); | ||
| 144 | #[cfg(not(feature = "defmt"))] | ||
| 145 | let _ = ($( & $x ),*); | ||
| 146 | } | ||
| 147 | }; | ||
| 148 | } | ||
| 149 | |||
| 150 | #[collapse_debuginfo(yes)] | ||
| 151 | macro_rules! warn { | ||
| 152 | ($s:literal $(, $x:expr)* $(,)?) => { | ||
| 153 | { | ||
| 154 | #[cfg(feature = "defmt")] | ||
| 155 | ::defmt::warn!($s $(, $x)*); | ||
| 156 | #[cfg(not(feature = "defmt"))] | ||
| 157 | let _ = ($( & $x ),*); | ||
| 158 | } | ||
| 159 | }; | ||
| 160 | } | ||
| 161 | |||
| 162 | #[collapse_debuginfo(yes)] | ||
| 163 | macro_rules! error { | ||
| 164 | ($s:literal $(, $x:expr)* $(,)?) => { | ||
| 165 | { | ||
| 166 | #[cfg(feature = "defmt")] | ||
| 167 | ::defmt::error!($s $(, $x)*); | ||
| 168 | #[cfg(not(feature = "defmt"))] | ||
| 169 | let _ = ($( & $x ),*); | ||
| 170 | } | ||
| 171 | }; | ||
| 172 | } | ||
| 173 | |||
| 174 | #[cfg(feature = "defmt")] | ||
| 175 | #[collapse_debuginfo(yes)] | ||
| 176 | macro_rules! unwrap { | ||
| 177 | ($($x:tt)*) => { | ||
| 178 | ::defmt::unwrap!($($x)*) | ||
| 179 | }; | ||
| 180 | } | ||
| 181 | |||
| 182 | #[cfg(not(feature = "defmt"))] | ||
| 183 | #[collapse_debuginfo(yes)] | ||
| 184 | macro_rules! unwrap { | ||
| 185 | ($arg:expr) => { | ||
| 186 | match $crate::fmt::Try::into_result($arg) { | ||
| 187 | ::core::result::Result::Ok(t) => t, | ||
| 188 | ::core::result::Result::Err(e) => { | ||
| 189 | ::core::panic!("unwrap of `{}` failed: {:?}", ::core::stringify!($arg), e); | ||
| 190 | } | ||
| 191 | } | ||
| 192 | }; | ||
| 193 | ($arg:expr, $($msg:expr),+ $(,)? ) => { | ||
| 194 | match $crate::fmt::Try::into_result($arg) { | ||
| 195 | ::core::result::Result::Ok(t) => t, | ||
| 196 | ::core::result::Result::Err(e) => { | ||
| 197 | ::core::panic!("unwrap of `{}` failed: {}: {:?}", ::core::stringify!($arg), ::core::format_args!($($msg,)*), e); | ||
| 198 | } | ||
| 199 | } | ||
| 200 | } | ||
| 201 | } | ||
| 202 | |||
| 203 | #[derive(Debug, Copy, Clone, Eq, PartialEq)] | ||
| 204 | pub struct NoneError; | ||
| 205 | |||
| 206 | pub trait Try { | ||
| 207 | type Ok; | ||
| 208 | type Error; | ||
| 209 | fn into_result(self) -> Result<Self::Ok, Self::Error>; | ||
| 210 | } | ||
| 211 | |||
| 212 | impl<T> Try for Option<T> { | ||
| 213 | type Ok = T; | ||
| 214 | type Error = NoneError; | ||
| 215 | |||
| 216 | #[inline] | ||
| 217 | fn into_result(self) -> Result<T, NoneError> { | ||
| 218 | self.ok_or(NoneError) | ||
| 219 | } | ||
| 220 | } | ||
| 221 | |||
| 222 | impl<T, E> Try for Result<T, E> { | ||
| 223 | type Ok = T; | ||
| 224 | type Error = E; | ||
| 225 | |||
| 226 | #[inline] | ||
| 227 | fn into_result(self) -> Self { | ||
| 228 | self | ||
| 229 | } | ||
| 230 | } | ||
| 231 | |||
| 232 | pub(crate) struct Bytes<'a>(pub &'a [u8]); | ||
| 233 | |||
| 234 | impl Debug for Bytes<'_> { | ||
| 235 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { | ||
| 236 | write!(f, "{:#02x?}", self.0) | ||
| 237 | } | ||
| 238 | } | ||
| 239 | |||
| 240 | impl Display for Bytes<'_> { | ||
| 241 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { | ||
| 242 | write!(f, "{:#02x?}", self.0) | ||
| 243 | } | ||
| 244 | } | ||
| 245 | |||
| 246 | impl LowerHex for Bytes<'_> { | ||
| 247 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { | ||
| 248 | write!(f, "{:#02x?}", self.0) | ||
| 249 | } | ||
| 250 | } | ||
| 251 | |||
| 252 | #[cfg(feature = "defmt")] | ||
| 253 | impl defmt::Format for Bytes<'_> { | ||
| 254 | fn format(&self, fmt: defmt::Formatter) { | ||
| 255 | defmt::write!(fmt, "{:02x}", self.0) | ||
| 256 | } | ||
| 257 | } | ||
diff --git a/embassy-imxrt/src/gpio.rs b/embassy-imxrt/src/gpio.rs new file mode 100644 index 000000000..6883c4ee0 --- /dev/null +++ b/embassy-imxrt/src/gpio.rs | |||
| @@ -0,0 +1,1060 @@ | |||
| 1 | //! GPIO | ||
| 2 | |||
| 3 | use core::convert::Infallible; | ||
| 4 | use core::future::Future; | ||
| 5 | use core::marker::PhantomData; | ||
| 6 | use core::pin::Pin as FuturePin; | ||
| 7 | use core::task::{Context, Poll}; | ||
| 8 | |||
| 9 | use embassy_hal_internal::interrupt::InterruptExt; | ||
| 10 | use embassy_sync::waitqueue::AtomicWaker; | ||
| 11 | |||
| 12 | use crate::clocks::enable_and_reset; | ||
| 13 | use crate::iopctl::IopctlPin; | ||
| 14 | pub use crate::iopctl::{AnyPin, DriveMode, DriveStrength, Function, Inverter, Pull, SlewRate}; | ||
| 15 | use crate::sealed::Sealed; | ||
| 16 | use crate::{interrupt, peripherals, Peri, PeripheralType}; | ||
| 17 | |||
| 18 | // This should be unique per IMXRT package | ||
| 19 | const PORT_COUNT: usize = 8; | ||
| 20 | |||
| 21 | /// Digital input or output level. | ||
| 22 | #[derive(Debug, Eq, PartialEq, Copy, Clone)] | ||
| 23 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 24 | pub enum Level { | ||
| 25 | /// Logic Low | ||
| 26 | Low, | ||
| 27 | /// Logic High | ||
| 28 | High, | ||
| 29 | } | ||
| 30 | |||
| 31 | impl From<bool> for Level { | ||
| 32 | fn from(val: bool) -> Self { | ||
| 33 | match val { | ||
| 34 | true => Self::High, | ||
| 35 | false => Self::Low, | ||
| 36 | } | ||
| 37 | } | ||
| 38 | } | ||
| 39 | |||
| 40 | impl From<Level> for bool { | ||
| 41 | fn from(level: Level) -> bool { | ||
| 42 | match level { | ||
| 43 | Level::Low => false, | ||
| 44 | Level::High => true, | ||
| 45 | } | ||
| 46 | } | ||
| 47 | } | ||
| 48 | |||
| 49 | /// Interrupt trigger levels. | ||
| 50 | #[derive(Debug, Eq, PartialEq, Copy, Clone)] | ||
| 51 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 52 | pub enum InterruptType { | ||
| 53 | /// Trigger on level. | ||
| 54 | Level, | ||
| 55 | /// Trigger on edge. | ||
| 56 | Edge, | ||
| 57 | } | ||
| 58 | |||
| 59 | #[cfg(feature = "rt")] | ||
| 60 | #[interrupt] | ||
| 61 | #[allow(non_snake_case)] | ||
| 62 | fn GPIO_INTA() { | ||
| 63 | irq_handler(&GPIO_WAKERS); | ||
| 64 | } | ||
| 65 | |||
| 66 | #[cfg(feature = "rt")] | ||
| 67 | struct BitIter(u32); | ||
| 68 | |||
| 69 | #[cfg(feature = "rt")] | ||
| 70 | impl Iterator for BitIter { | ||
| 71 | type Item = u32; | ||
| 72 | |||
| 73 | fn next(&mut self) -> Option<Self::Item> { | ||
| 74 | match self.0.trailing_zeros() { | ||
| 75 | 32 => None, | ||
| 76 | b => { | ||
| 77 | self.0 &= !(1 << b); | ||
| 78 | Some(b) | ||
| 79 | } | ||
| 80 | } | ||
| 81 | } | ||
| 82 | } | ||
| 83 | |||
| 84 | #[cfg(feature = "rt")] | ||
| 85 | fn irq_handler(port_wakers: &[Option<&PortWaker>]) { | ||
| 86 | let reg = unsafe { crate::pac::Gpio::steal() }; | ||
| 87 | |||
| 88 | for (port, port_waker) in port_wakers.iter().enumerate() { | ||
| 89 | let Some(port_waker) = port_waker else { | ||
| 90 | continue; | ||
| 91 | }; | ||
| 92 | |||
| 93 | let stat = reg.intstata(port).read().bits(); | ||
| 94 | for pin in BitIter(stat) { | ||
| 95 | // Clear the interrupt from this pin | ||
| 96 | reg.intstata(port).write(|w| unsafe { w.status().bits(1 << pin) }); | ||
| 97 | // Disable interrupt from this pin | ||
| 98 | reg.intena(port) | ||
| 99 | .modify(|r, w| unsafe { w.int_en().bits(r.int_en().bits() & !(1 << pin)) }); | ||
| 100 | |||
| 101 | let Some(waker) = port_waker.get_waker(pin as usize) else { | ||
| 102 | continue; | ||
| 103 | }; | ||
| 104 | |||
| 105 | waker.wake(); | ||
| 106 | } | ||
| 107 | } | ||
| 108 | } | ||
| 109 | |||
| 110 | /// Initialization Logic | ||
| 111 | /// Note: GPIO port clocks are initialized in the clocks module. | ||
| 112 | pub(crate) fn init() { | ||
| 113 | // Enable GPIO clocks | ||
| 114 | enable_and_reset::<peripherals::HSGPIO0>(); | ||
| 115 | enable_and_reset::<peripherals::HSGPIO1>(); | ||
| 116 | enable_and_reset::<peripherals::HSGPIO2>(); | ||
| 117 | enable_and_reset::<peripherals::HSGPIO3>(); | ||
| 118 | enable_and_reset::<peripherals::HSGPIO4>(); | ||
| 119 | enable_and_reset::<peripherals::HSGPIO5>(); | ||
| 120 | enable_and_reset::<peripherals::HSGPIO6>(); | ||
| 121 | enable_and_reset::<peripherals::HSGPIO7>(); | ||
| 122 | |||
| 123 | // Enable INTA | ||
| 124 | interrupt::GPIO_INTA.unpend(); | ||
| 125 | |||
| 126 | // SAFETY: | ||
| 127 | // | ||
| 128 | // At this point, all GPIO interrupts are masked. No interrupts | ||
| 129 | // will trigger until a pin is configured as Input, which can only | ||
| 130 | // happen after initialization of the HAL | ||
| 131 | unsafe { interrupt::GPIO_INTA.enable() }; | ||
| 132 | } | ||
| 133 | |||
| 134 | /// Input Sense mode. | ||
| 135 | pub trait Sense: Sealed {} | ||
| 136 | |||
| 137 | /// Sense Enabled Flex pin. | ||
| 138 | /// | ||
| 139 | /// This is a true flex pin as the input buffer is enabled. | ||
| 140 | /// It can sense its own level when even when configured as an output pin. | ||
| 141 | pub enum SenseEnabled {} | ||
| 142 | impl Sealed for SenseEnabled {} | ||
| 143 | impl Sense for SenseEnabled {} | ||
| 144 | |||
| 145 | /// Sense Enabled Flex pin. | ||
| 146 | /// | ||
| 147 | /// This is **not** a true flex pin as the input buffer is disabled. | ||
| 148 | /// It cannot be turned into an input and it cannot see its own state, but it consumes less power. | ||
| 149 | /// Consider using a sense enabled flex pin if you need to read the pin's state or turn this into an input, | ||
| 150 | /// however note that **power consumption may be increased**. | ||
| 151 | pub enum SenseDisabled {} | ||
| 152 | impl Sealed for SenseDisabled {} | ||
| 153 | impl Sense for SenseDisabled {} | ||
| 154 | |||
| 155 | /// Flex pin. | ||
| 156 | /// | ||
| 157 | /// This pin can be either an input or output pin. The output level register bit will | ||
| 158 | /// remain set while not in output mode, so the pin's level will be 'remembered' when it is not in | ||
| 159 | /// output mode. | ||
| 160 | pub struct Flex<'d, S: Sense> { | ||
| 161 | pin: Peri<'d, AnyPin>, | ||
| 162 | _sense_mode: PhantomData<S>, | ||
| 163 | } | ||
| 164 | |||
| 165 | impl<S: Sense> Flex<'_, S> { | ||
| 166 | /// Converts pin to output pin | ||
| 167 | /// | ||
| 168 | /// The pin level will be whatever was set before (or low by default). If you want it to begin | ||
| 169 | /// at a specific level, call `set_high`/`set_low` on the pin first. | ||
| 170 | pub fn set_as_output(&mut self, mode: DriveMode, strength: DriveStrength, slew_rate: SlewRate) { | ||
| 171 | self.pin | ||
| 172 | .set_pull(Pull::None) | ||
| 173 | .set_drive_mode(mode) | ||
| 174 | .set_drive_strength(strength) | ||
| 175 | .set_slew_rate(slew_rate); | ||
| 176 | |||
| 177 | self.pin.block().dirset(self.pin.port()).write(|w| | ||
| 178 | // SAFETY: Writing a 0 to bits in this register has no effect, | ||
| 179 | // however PAC has it marked unsafe due to using the bits() method. | ||
| 180 | // There is not currently a "safe" method for setting a single-bit. | ||
| 181 | unsafe { w.dirsetp().bits(1 << self.pin.pin()) }); | ||
| 182 | } | ||
| 183 | |||
| 184 | /// Set high | ||
| 185 | pub fn set_high(&mut self) { | ||
| 186 | self.pin.block().set(self.pin.port()).write(|w| | ||
| 187 | // SAFETY: Writing a 0 to bits in this register has no effect, | ||
| 188 | // however PAC has it marked unsafe due to using the bits() method. | ||
| 189 | // There is not currently a "safe" method for setting a single-bit. | ||
| 190 | unsafe { w.setp().bits(1 << self.pin.pin()) }); | ||
| 191 | } | ||
| 192 | |||
| 193 | /// Set low | ||
| 194 | pub fn set_low(&mut self) { | ||
| 195 | self.pin.block().clr(self.pin.port()).write(|w| | ||
| 196 | // SAFETY: Writing a 0 to bits in this register has no effect, | ||
| 197 | // however PAC has it marked unsafe due to using the bits() method. | ||
| 198 | // There is not currently a "safe" method for setting a single-bit. | ||
| 199 | unsafe { w.clrp().bits(1 << self.pin.pin()) }); | ||
| 200 | } | ||
| 201 | |||
| 202 | /// Set level | ||
| 203 | pub fn set_level(&mut self, level: Level) { | ||
| 204 | match level { | ||
| 205 | Level::High => self.set_high(), | ||
| 206 | Level::Low => self.set_low(), | ||
| 207 | } | ||
| 208 | } | ||
| 209 | |||
| 210 | /// Is the output level high? | ||
| 211 | #[must_use] | ||
| 212 | pub fn is_set_high(&self) -> bool { | ||
| 213 | !self.is_set_low() | ||
| 214 | } | ||
| 215 | |||
| 216 | /// Is the output level low? | ||
| 217 | #[must_use] | ||
| 218 | pub fn is_set_low(&self) -> bool { | ||
| 219 | (self.pin.block().set(self.pin.port()).read().setp().bits() & (1 << self.pin.pin())) == 0 | ||
| 220 | } | ||
| 221 | |||
| 222 | /// Toggle | ||
| 223 | pub fn toggle(&mut self) { | ||
| 224 | self.pin.block().not(self.pin.port()).write(|w| | ||
| 225 | // SAFETY: Writing a 0 to bits in this register has no effect, | ||
| 226 | // however PAC has it marked unsafe due to using the bits() method. | ||
| 227 | // There is not currently a "safe" method for setting a single-bit. | ||
| 228 | unsafe { w.notp().bits(1 << self.pin.pin()) }); | ||
| 229 | } | ||
| 230 | } | ||
| 231 | |||
| 232 | impl<S: Sense> Drop for Flex<'_, S> { | ||
| 233 | #[inline] | ||
| 234 | fn drop(&mut self) { | ||
| 235 | critical_section::with(|_| { | ||
| 236 | self.pin.reset(); | ||
| 237 | }); | ||
| 238 | } | ||
| 239 | } | ||
| 240 | |||
| 241 | impl<'d> Flex<'d, SenseEnabled> { | ||
| 242 | /// New flex pin. | ||
| 243 | pub fn new_with_sense(pin: Peri<'d, impl GpioPin>) -> Self { | ||
| 244 | pin.set_function(Function::F0) | ||
| 245 | .disable_analog_multiplex() | ||
| 246 | .enable_input_buffer(); | ||
| 247 | |||
| 248 | Self { | ||
| 249 | pin: pin.into(), | ||
| 250 | _sense_mode: PhantomData::<SenseEnabled>, | ||
| 251 | } | ||
| 252 | } | ||
| 253 | |||
| 254 | /// Converts pin to input pin | ||
| 255 | pub fn set_as_input(&mut self, pull: Pull, inverter: Inverter) { | ||
| 256 | self.pin.set_pull(pull).set_input_inverter(inverter); | ||
| 257 | |||
| 258 | self.pin.block().dirclr(self.pin.port()).write(|w| | ||
| 259 | // SAFETY: Writing a 0 to bits in this register has no effect, | ||
| 260 | // however PAC has it marked unsafe due to using the bits() method. | ||
| 261 | // There is not currently a "safe" method for setting a single-bit. | ||
| 262 | unsafe { w.dirclrp().bits(1 << self.pin.pin()) }); | ||
| 263 | } | ||
| 264 | |||
| 265 | /// Converts pin to special function pin | ||
| 266 | /// # Safety | ||
| 267 | /// Unsafe to require justifying change from default to a special function | ||
| 268 | /// | ||
| 269 | pub unsafe fn set_as_special_function(&mut self, func: Function) { | ||
| 270 | self.pin.set_function(func); | ||
| 271 | } | ||
| 272 | |||
| 273 | /// Is high? | ||
| 274 | #[must_use] | ||
| 275 | pub fn is_high(&self) -> bool { | ||
| 276 | !self.is_low() | ||
| 277 | } | ||
| 278 | |||
| 279 | /// Is low? | ||
| 280 | #[must_use] | ||
| 281 | pub fn is_low(&self) -> bool { | ||
| 282 | self.pin.block().b(self.pin.port()).b_(self.pin.pin()).read() == 0 | ||
| 283 | } | ||
| 284 | |||
| 285 | /// Current level | ||
| 286 | #[must_use] | ||
| 287 | pub fn get_level(&self) -> Level { | ||
| 288 | self.is_high().into() | ||
| 289 | } | ||
| 290 | |||
| 291 | /// Wait until the pin is high. If it is already high, return immediately. | ||
| 292 | #[inline] | ||
| 293 | pub async fn wait_for_high(&mut self) { | ||
| 294 | InputFuture::new(self.pin.reborrow(), InterruptType::Level, Level::High).await; | ||
| 295 | } | ||
| 296 | |||
| 297 | /// Wait until the pin is low. If it is already low, return immediately. | ||
| 298 | #[inline] | ||
| 299 | pub async fn wait_for_low(&mut self) { | ||
| 300 | InputFuture::new(self.pin.reborrow(), InterruptType::Level, Level::Low).await; | ||
| 301 | } | ||
| 302 | |||
| 303 | /// Wait for the pin to undergo a transition from low to high. | ||
| 304 | #[inline] | ||
| 305 | pub async fn wait_for_rising_edge(&mut self) { | ||
| 306 | InputFuture::new(self.pin.reborrow(), InterruptType::Edge, Level::High).await; | ||
| 307 | } | ||
| 308 | |||
| 309 | /// Wait for the pin to undergo a transition from high to low. | ||
| 310 | #[inline] | ||
| 311 | pub async fn wait_for_falling_edge(&mut self) { | ||
| 312 | InputFuture::new(self.pin.reborrow(), InterruptType::Edge, Level::Low).await; | ||
| 313 | } | ||
| 314 | |||
| 315 | /// Wait for the pin to undergo any transition, i.e low to high OR high to low. | ||
| 316 | #[inline] | ||
| 317 | pub async fn wait_for_any_edge(&mut self) { | ||
| 318 | if self.is_high() { | ||
| 319 | InputFuture::new(self.pin.reborrow(), InterruptType::Edge, Level::Low).await; | ||
| 320 | } else { | ||
| 321 | InputFuture::new(self.pin.reborrow(), InterruptType::Edge, Level::High).await; | ||
| 322 | } | ||
| 323 | } | ||
| 324 | |||
| 325 | /// Return a new Flex pin instance with level sensing disabled. | ||
| 326 | /// | ||
| 327 | /// Consumes less power than a flex pin with sensing enabled. | ||
| 328 | #[must_use] | ||
| 329 | pub fn disable_sensing(self) -> Flex<'d, SenseDisabled> { | ||
| 330 | // Cloning the pin is ok since we consume self immediately | ||
| 331 | let new_pin = unsafe { self.pin.clone_unchecked() }; | ||
| 332 | drop(self); | ||
| 333 | Flex::<SenseDisabled>::new(new_pin) | ||
| 334 | } | ||
| 335 | } | ||
| 336 | |||
| 337 | impl<'d> Flex<'d, SenseDisabled> { | ||
| 338 | /// New flex pin. | ||
| 339 | pub fn new(pin: Peri<'d, impl GpioPin>) -> Self { | ||
| 340 | pin.set_function(Function::F0) | ||
| 341 | .disable_analog_multiplex() | ||
| 342 | .disable_input_buffer(); | ||
| 343 | |||
| 344 | Self { | ||
| 345 | pin: pin.into(), | ||
| 346 | _sense_mode: PhantomData::<SenseDisabled>, | ||
| 347 | } | ||
| 348 | } | ||
| 349 | |||
| 350 | /// Return a new Flex pin instance with level sensing enabled. | ||
| 351 | #[must_use] | ||
| 352 | pub fn enable_sensing(self) -> Flex<'d, SenseEnabled> { | ||
| 353 | // Cloning the pin is ok since we consume self immediately | ||
| 354 | let new_pin = unsafe { self.pin.clone_unchecked() }; | ||
| 355 | drop(self); | ||
| 356 | Flex::new_with_sense(new_pin) | ||
| 357 | } | ||
| 358 | } | ||
| 359 | |||
| 360 | /// Input pin | ||
| 361 | pub struct Input<'d> { | ||
| 362 | // When Input is dropped, Flex's drop() will make sure the pin is reset to its default state. | ||
| 363 | pin: Flex<'d, SenseEnabled>, | ||
| 364 | } | ||
| 365 | |||
| 366 | impl<'d> Input<'d> { | ||
| 367 | /// New input pin | ||
| 368 | pub fn new(pin: Peri<'d, impl GpioPin>, pull: Pull, inverter: Inverter) -> Self { | ||
| 369 | let mut pin = Flex::new_with_sense(pin); | ||
| 370 | pin.set_as_input(pull, inverter); | ||
| 371 | Self { pin } | ||
| 372 | } | ||
| 373 | |||
| 374 | /// Is high? | ||
| 375 | #[must_use] | ||
| 376 | pub fn is_high(&self) -> bool { | ||
| 377 | self.pin.is_high() | ||
| 378 | } | ||
| 379 | |||
| 380 | /// Is low? | ||
| 381 | #[must_use] | ||
| 382 | pub fn is_low(&self) -> bool { | ||
| 383 | self.pin.is_low() | ||
| 384 | } | ||
| 385 | |||
| 386 | /// Input level | ||
| 387 | #[must_use] | ||
| 388 | pub fn get_level(&self) -> Level { | ||
| 389 | self.pin.get_level() | ||
| 390 | } | ||
| 391 | |||
| 392 | /// Wait until the pin is high. If it is already high, return immediately. | ||
| 393 | #[inline] | ||
| 394 | pub async fn wait_for_high(&mut self) { | ||
| 395 | self.pin.wait_for_high().await; | ||
| 396 | } | ||
| 397 | |||
| 398 | /// Wait until the pin is low. If it is already low, return immediately. | ||
| 399 | #[inline] | ||
| 400 | pub async fn wait_for_low(&mut self) { | ||
| 401 | self.pin.wait_for_low().await; | ||
| 402 | } | ||
| 403 | |||
| 404 | /// Wait for the pin to undergo a transition from low to high. | ||
| 405 | #[inline] | ||
| 406 | pub async fn wait_for_rising_edge(&mut self) { | ||
| 407 | self.pin.wait_for_rising_edge().await; | ||
| 408 | } | ||
| 409 | |||
| 410 | /// Wait for the pin to undergo a transition from high to low. | ||
| 411 | #[inline] | ||
| 412 | pub async fn wait_for_falling_edge(&mut self) { | ||
| 413 | self.pin.wait_for_falling_edge().await; | ||
| 414 | } | ||
| 415 | |||
| 416 | /// Wait for the pin to undergo any transition, i.e low to high OR high to low. | ||
| 417 | #[inline] | ||
| 418 | pub async fn wait_for_any_edge(&mut self) { | ||
| 419 | self.pin.wait_for_any_edge().await; | ||
| 420 | } | ||
| 421 | } | ||
| 422 | |||
| 423 | #[must_use = "futures do nothing unless you `.await` or poll them"] | ||
| 424 | struct InputFuture<'d> { | ||
| 425 | pin: Peri<'d, AnyPin>, | ||
| 426 | } | ||
| 427 | |||
| 428 | impl<'d> InputFuture<'d> { | ||
| 429 | fn new(pin: Peri<'d, impl GpioPin>, int_type: InterruptType, level: Level) -> Self { | ||
| 430 | critical_section::with(|_| { | ||
| 431 | // Clear any existing pending interrupt on this pin | ||
| 432 | pin.block() | ||
| 433 | .intstata(pin.port()) | ||
| 434 | .write(|w| unsafe { w.status().bits(1 << pin.pin()) }); | ||
| 435 | |||
| 436 | /* Pin interrupt configuration */ | ||
| 437 | pin.block().intedg(pin.port()).modify(|r, w| match int_type { | ||
| 438 | InterruptType::Edge => unsafe { w.bits(r.bits() | (1 << pin.pin())) }, | ||
| 439 | InterruptType::Level => unsafe { w.bits(r.bits() & !(1 << pin.pin())) }, | ||
| 440 | }); | ||
| 441 | |||
| 442 | pin.block().intpol(pin.port()).modify(|r, w| match level { | ||
| 443 | Level::High => unsafe { w.bits(r.bits() & !(1 << pin.pin())) }, | ||
| 444 | Level::Low => unsafe { w.bits(r.bits() | (1 << pin.pin())) }, | ||
| 445 | }); | ||
| 446 | |||
| 447 | // Enable pin interrupt on GPIO INT A | ||
| 448 | pin.block() | ||
| 449 | .intena(pin.port()) | ||
| 450 | .modify(|r, w| unsafe { w.int_en().bits(r.int_en().bits() | (1 << pin.pin())) }); | ||
| 451 | }); | ||
| 452 | |||
| 453 | Self { pin: pin.into() } | ||
| 454 | } | ||
| 455 | } | ||
| 456 | |||
| 457 | impl Future for InputFuture<'_> { | ||
| 458 | type Output = (); | ||
| 459 | |||
| 460 | fn poll(self: FuturePin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { | ||
| 461 | // We need to register/re-register the waker for each poll because any | ||
| 462 | // calls to wake will deregister the waker. | ||
| 463 | if self.pin.port() >= GPIO_WAKERS.len() { | ||
| 464 | panic!("Invalid GPIO port index {}", self.pin.port()); | ||
| 465 | } | ||
| 466 | |||
| 467 | let port_waker = GPIO_WAKERS[self.pin.port()]; | ||
| 468 | if port_waker.is_none() { | ||
| 469 | panic!("Waker not present for GPIO port {}", self.pin.port()); | ||
| 470 | } | ||
| 471 | |||
| 472 | let waker = port_waker.unwrap().get_waker(self.pin.pin()); | ||
| 473 | if waker.is_none() { | ||
| 474 | panic!( | ||
| 475 | "Waker not present for GPIO pin {}, port {}", | ||
| 476 | self.pin.pin(), | ||
| 477 | self.pin.port() | ||
| 478 | ); | ||
| 479 | } | ||
| 480 | waker.unwrap().register(cx.waker()); | ||
| 481 | |||
| 482 | // Double check that the pin interrut has been disabled by IRQ handler | ||
| 483 | if self.pin.block().intena(self.pin.port()).read().bits() & (1 << self.pin.pin()) == 0 { | ||
| 484 | Poll::Ready(()) | ||
| 485 | } else { | ||
| 486 | Poll::Pending | ||
| 487 | } | ||
| 488 | } | ||
| 489 | } | ||
| 490 | |||
| 491 | /// Output pin | ||
| 492 | /// Cannot be set as an input and cannot read its own pin state! | ||
| 493 | /// Consider using a Flex pin if you want that functionality, at the cost of higher power consumption. | ||
| 494 | pub struct Output<'d> { | ||
| 495 | // When Output is dropped, Flex's drop() will make sure the pin is reset to its default state. | ||
| 496 | pin: Flex<'d, SenseDisabled>, | ||
| 497 | } | ||
| 498 | |||
| 499 | impl<'d> Output<'d> { | ||
| 500 | /// New output pin | ||
| 501 | pub fn new( | ||
| 502 | pin: Peri<'d, impl GpioPin>, | ||
| 503 | initial_output: Level, | ||
| 504 | mode: DriveMode, | ||
| 505 | strength: DriveStrength, | ||
| 506 | slew_rate: SlewRate, | ||
| 507 | ) -> Self { | ||
| 508 | let mut pin = Flex::new(pin); | ||
| 509 | pin.set_level(initial_output); | ||
| 510 | pin.set_as_output(mode, strength, slew_rate); | ||
| 511 | |||
| 512 | Self { pin } | ||
| 513 | } | ||
| 514 | |||
| 515 | /// Set high | ||
| 516 | pub fn set_high(&mut self) { | ||
| 517 | self.pin.set_high(); | ||
| 518 | } | ||
| 519 | |||
| 520 | /// Set low | ||
| 521 | pub fn set_low(&mut self) { | ||
| 522 | self.pin.set_low(); | ||
| 523 | } | ||
| 524 | |||
| 525 | /// Toggle | ||
| 526 | pub fn toggle(&mut self) { | ||
| 527 | self.pin.toggle(); | ||
| 528 | } | ||
| 529 | |||
| 530 | /// Set level | ||
| 531 | pub fn set_level(&mut self, level: Level) { | ||
| 532 | self.pin.set_level(level); | ||
| 533 | } | ||
| 534 | |||
| 535 | /// Is set high? | ||
| 536 | #[must_use] | ||
| 537 | pub fn is_set_high(&self) -> bool { | ||
| 538 | self.pin.is_set_high() | ||
| 539 | } | ||
| 540 | |||
| 541 | /// Is set low? | ||
| 542 | #[must_use] | ||
| 543 | pub fn is_set_low(&self) -> bool { | ||
| 544 | self.pin.is_set_low() | ||
| 545 | } | ||
| 546 | } | ||
| 547 | |||
| 548 | trait SealedPin: IopctlPin { | ||
| 549 | fn pin_port(&self) -> usize; | ||
| 550 | |||
| 551 | fn port(&self) -> usize { | ||
| 552 | self.pin_port() / 32 | ||
| 553 | } | ||
| 554 | |||
| 555 | fn pin(&self) -> usize { | ||
| 556 | self.pin_port() % 32 | ||
| 557 | } | ||
| 558 | |||
| 559 | fn block(&self) -> crate::pac::Gpio { | ||
| 560 | // SAFETY: Assuming GPIO pin specific registers are only accessed through this HAL, | ||
| 561 | // this is safe because the HAL ensures ownership or exclusive mutable references | ||
| 562 | // to pins. | ||
| 563 | unsafe { crate::pac::Gpio::steal() } | ||
| 564 | } | ||
| 565 | } | ||
| 566 | |||
| 567 | /// GPIO pin trait. | ||
| 568 | #[allow(private_bounds)] | ||
| 569 | pub trait GpioPin: SealedPin + Sized + PeripheralType + Into<AnyPin> + 'static { | ||
| 570 | /// Type-erase the pin. | ||
| 571 | fn degrade(self) -> AnyPin { | ||
| 572 | // SAFETY: This is only called within the GpioPin trait, which is only | ||
| 573 | // implemented within this module on valid pin peripherals and thus | ||
| 574 | // has been verified to be correct. | ||
| 575 | unsafe { AnyPin::steal(self.port() as u8, self.pin() as u8) } | ||
| 576 | } | ||
| 577 | } | ||
| 578 | |||
| 579 | impl SealedPin for AnyPin { | ||
| 580 | fn pin_port(&self) -> usize { | ||
| 581 | self.pin_port() | ||
| 582 | } | ||
| 583 | } | ||
| 584 | impl GpioPin for AnyPin {} | ||
| 585 | |||
| 586 | macro_rules! impl_pin { | ||
| 587 | ($pin_periph:ident, $pin_port:expr, $pin_no:expr) => { | ||
| 588 | impl SealedPin for crate::peripherals::$pin_periph { | ||
| 589 | fn pin_port(&self) -> usize { | ||
| 590 | $pin_port * 32 + $pin_no | ||
| 591 | } | ||
| 592 | } | ||
| 593 | impl GpioPin for crate::peripherals::$pin_periph {} | ||
| 594 | impl From<crate::peripherals::$pin_periph> for AnyPin { | ||
| 595 | fn from(value: crate::peripherals::$pin_periph) -> Self { | ||
| 596 | value.degrade() | ||
| 597 | } | ||
| 598 | } | ||
| 599 | }; | ||
| 600 | } | ||
| 601 | |||
| 602 | /// Container for pin wakers | ||
| 603 | struct PortWaker { | ||
| 604 | offset: usize, | ||
| 605 | wakers: &'static [AtomicWaker], | ||
| 606 | } | ||
| 607 | |||
| 608 | impl PortWaker { | ||
| 609 | fn get_waker(&self, pin: usize) -> Option<&AtomicWaker> { | ||
| 610 | self.wakers.get(pin - self.offset) | ||
| 611 | } | ||
| 612 | } | ||
| 613 | |||
| 614 | macro_rules! define_port_waker { | ||
| 615 | ($name:ident, $start:expr, $end:expr) => { | ||
| 616 | mod $name { | ||
| 617 | static PIN_WAKERS: [super::AtomicWaker; $end - $start + 1] = | ||
| 618 | [const { super::AtomicWaker::new() }; $end - $start + 1]; | ||
| 619 | pub static WAKER: super::PortWaker = super::PortWaker { | ||
| 620 | offset: $start, | ||
| 621 | wakers: &PIN_WAKERS, | ||
| 622 | }; | ||
| 623 | } | ||
| 624 | }; | ||
| 625 | } | ||
| 626 | |||
| 627 | // GPIO port 0 | ||
| 628 | define_port_waker!(port0_waker, 0, 31); | ||
| 629 | impl_pin!(PIO0_0, 0, 0); | ||
| 630 | impl_pin!(PIO0_1, 0, 1); | ||
| 631 | impl_pin!(PIO0_2, 0, 2); | ||
| 632 | impl_pin!(PIO0_3, 0, 3); | ||
| 633 | impl_pin!(PIO0_4, 0, 4); | ||
| 634 | impl_pin!(PIO0_5, 0, 5); | ||
| 635 | impl_pin!(PIO0_6, 0, 6); | ||
| 636 | impl_pin!(PIO0_7, 0, 7); | ||
| 637 | impl_pin!(PIO0_8, 0, 8); | ||
| 638 | impl_pin!(PIO0_9, 0, 9); | ||
| 639 | impl_pin!(PIO0_10, 0, 10); | ||
| 640 | impl_pin!(PIO0_11, 0, 11); | ||
| 641 | impl_pin!(PIO0_12, 0, 12); | ||
| 642 | impl_pin!(PIO0_13, 0, 13); | ||
| 643 | impl_pin!(PIO0_14, 0, 14); | ||
| 644 | impl_pin!(PIO0_15, 0, 15); | ||
| 645 | impl_pin!(PIO0_16, 0, 16); | ||
| 646 | impl_pin!(PIO0_17, 0, 17); | ||
| 647 | impl_pin!(PIO0_18, 0, 18); | ||
| 648 | impl_pin!(PIO0_19, 0, 19); | ||
| 649 | impl_pin!(PIO0_20, 0, 20); | ||
| 650 | impl_pin!(PIO0_21, 0, 21); | ||
| 651 | impl_pin!(PIO0_22, 0, 22); | ||
| 652 | impl_pin!(PIO0_23, 0, 23); | ||
| 653 | impl_pin!(PIO0_24, 0, 24); | ||
| 654 | impl_pin!(PIO0_25, 0, 25); | ||
| 655 | impl_pin!(PIO0_26, 0, 26); | ||
| 656 | impl_pin!(PIO0_27, 0, 27); | ||
| 657 | impl_pin!(PIO0_28, 0, 28); | ||
| 658 | impl_pin!(PIO0_29, 0, 29); | ||
| 659 | impl_pin!(PIO0_30, 0, 30); | ||
| 660 | impl_pin!(PIO0_31, 0, 31); | ||
| 661 | |||
| 662 | // GPIO port 1 | ||
| 663 | define_port_waker!(port1_waker, 0, 31); | ||
| 664 | impl_pin!(PIO1_0, 1, 0); | ||
| 665 | impl_pin!(PIO1_1, 1, 1); | ||
| 666 | impl_pin!(PIO1_2, 1, 2); | ||
| 667 | impl_pin!(PIO1_3, 1, 3); | ||
| 668 | impl_pin!(PIO1_4, 1, 4); | ||
| 669 | impl_pin!(PIO1_5, 1, 5); | ||
| 670 | impl_pin!(PIO1_6, 1, 6); | ||
| 671 | impl_pin!(PIO1_7, 1, 7); | ||
| 672 | impl_pin!(PIO1_8, 1, 8); | ||
| 673 | impl_pin!(PIO1_9, 1, 9); | ||
| 674 | impl_pin!(PIO1_10, 1, 10); | ||
| 675 | impl_pin!(PIO1_11, 1, 11); | ||
| 676 | impl_pin!(PIO1_12, 1, 12); | ||
| 677 | impl_pin!(PIO1_13, 1, 13); | ||
| 678 | impl_pin!(PIO1_14, 1, 14); | ||
| 679 | impl_pin!(PIO1_15, 1, 15); | ||
| 680 | impl_pin!(PIO1_16, 1, 16); | ||
| 681 | impl_pin!(PIO1_17, 1, 17); | ||
| 682 | impl_pin!(PIO1_18, 1, 18); | ||
| 683 | impl_pin!(PIO1_19, 1, 19); | ||
| 684 | impl_pin!(PIO1_20, 1, 20); | ||
| 685 | impl_pin!(PIO1_21, 1, 21); | ||
| 686 | impl_pin!(PIO1_22, 1, 22); | ||
| 687 | impl_pin!(PIO1_23, 1, 23); | ||
| 688 | impl_pin!(PIO1_24, 1, 24); | ||
| 689 | impl_pin!(PIO1_25, 1, 25); | ||
| 690 | impl_pin!(PIO1_26, 1, 26); | ||
| 691 | impl_pin!(PIO1_27, 1, 27); | ||
| 692 | impl_pin!(PIO1_28, 1, 28); | ||
| 693 | impl_pin!(PIO1_29, 1, 29); | ||
| 694 | impl_pin!(PIO1_30, 1, 30); | ||
| 695 | impl_pin!(PIO1_31, 1, 31); | ||
| 696 | |||
| 697 | // GPIO port 2 | ||
| 698 | define_port_waker!(port2_waker, 0, 31); | ||
| 699 | impl_pin!(PIO2_0, 2, 0); | ||
| 700 | impl_pin!(PIO2_1, 2, 1); | ||
| 701 | impl_pin!(PIO2_2, 2, 2); | ||
| 702 | impl_pin!(PIO2_3, 2, 3); | ||
| 703 | impl_pin!(PIO2_4, 2, 4); | ||
| 704 | impl_pin!(PIO2_5, 2, 5); | ||
| 705 | impl_pin!(PIO2_6, 2, 6); | ||
| 706 | impl_pin!(PIO2_7, 2, 7); | ||
| 707 | impl_pin!(PIO2_8, 2, 8); | ||
| 708 | impl_pin!(PIO2_9, 2, 9); | ||
| 709 | impl_pin!(PIO2_10, 2, 10); | ||
| 710 | impl_pin!(PIO2_11, 2, 11); | ||
| 711 | impl_pin!(PIO2_12, 2, 12); | ||
| 712 | impl_pin!(PIO2_13, 2, 13); | ||
| 713 | impl_pin!(PIO2_14, 2, 14); | ||
| 714 | impl_pin!(PIO2_15, 2, 15); | ||
| 715 | impl_pin!(PIO2_16, 2, 16); | ||
| 716 | impl_pin!(PIO2_17, 2, 17); | ||
| 717 | impl_pin!(PIO2_18, 2, 18); | ||
| 718 | impl_pin!(PIO2_19, 2, 19); | ||
| 719 | impl_pin!(PIO2_20, 2, 20); | ||
| 720 | impl_pin!(PIO2_21, 2, 21); | ||
| 721 | impl_pin!(PIO2_22, 2, 22); | ||
| 722 | impl_pin!(PIO2_23, 2, 23); | ||
| 723 | impl_pin!(PIO2_24, 2, 24); | ||
| 724 | impl_pin!(PIO2_25, 2, 25); | ||
| 725 | impl_pin!(PIO2_26, 2, 26); | ||
| 726 | impl_pin!(PIO2_27, 2, 27); | ||
| 727 | impl_pin!(PIO2_28, 2, 28); | ||
| 728 | impl_pin!(PIO2_29, 2, 29); | ||
| 729 | impl_pin!(PIO2_30, 2, 30); | ||
| 730 | impl_pin!(PIO2_31, 2, 31); | ||
| 731 | |||
| 732 | // GPIO port 3 | ||
| 733 | define_port_waker!(port3_waker, 0, 31); | ||
| 734 | impl_pin!(PIO3_0, 3, 0); | ||
| 735 | impl_pin!(PIO3_1, 3, 1); | ||
| 736 | impl_pin!(PIO3_2, 3, 2); | ||
| 737 | impl_pin!(PIO3_3, 3, 3); | ||
| 738 | impl_pin!(PIO3_4, 3, 4); | ||
| 739 | impl_pin!(PIO3_5, 3, 5); | ||
| 740 | impl_pin!(PIO3_6, 3, 6); | ||
| 741 | impl_pin!(PIO3_7, 3, 7); | ||
| 742 | impl_pin!(PIO3_8, 3, 8); | ||
| 743 | impl_pin!(PIO3_9, 3, 9); | ||
| 744 | impl_pin!(PIO3_10, 3, 10); | ||
| 745 | impl_pin!(PIO3_11, 3, 11); | ||
| 746 | impl_pin!(PIO3_12, 3, 12); | ||
| 747 | impl_pin!(PIO3_13, 3, 13); | ||
| 748 | impl_pin!(PIO3_14, 3, 14); | ||
| 749 | impl_pin!(PIO3_15, 3, 15); | ||
| 750 | impl_pin!(PIO3_16, 3, 16); | ||
| 751 | impl_pin!(PIO3_17, 3, 17); | ||
| 752 | impl_pin!(PIO3_18, 3, 18); | ||
| 753 | impl_pin!(PIO3_19, 3, 19); | ||
| 754 | impl_pin!(PIO3_20, 3, 20); | ||
| 755 | impl_pin!(PIO3_21, 3, 21); | ||
| 756 | impl_pin!(PIO3_22, 3, 22); | ||
| 757 | impl_pin!(PIO3_23, 3, 23); | ||
| 758 | impl_pin!(PIO3_24, 3, 24); | ||
| 759 | impl_pin!(PIO3_25, 3, 25); | ||
| 760 | impl_pin!(PIO3_26, 3, 26); | ||
| 761 | impl_pin!(PIO3_27, 3, 27); | ||
| 762 | impl_pin!(PIO3_28, 3, 28); | ||
| 763 | impl_pin!(PIO3_29, 3, 29); | ||
| 764 | impl_pin!(PIO3_30, 3, 30); | ||
| 765 | impl_pin!(PIO3_31, 3, 31); | ||
| 766 | |||
| 767 | // GPIO port 4 | ||
| 768 | define_port_waker!(port4_waker, 0, 10); | ||
| 769 | impl_pin!(PIO4_0, 4, 0); | ||
| 770 | impl_pin!(PIO4_1, 4, 1); | ||
| 771 | impl_pin!(PIO4_2, 4, 2); | ||
| 772 | impl_pin!(PIO4_3, 4, 3); | ||
| 773 | impl_pin!(PIO4_4, 4, 4); | ||
| 774 | impl_pin!(PIO4_5, 4, 5); | ||
| 775 | impl_pin!(PIO4_6, 4, 6); | ||
| 776 | impl_pin!(PIO4_7, 4, 7); | ||
| 777 | impl_pin!(PIO4_8, 4, 8); | ||
| 778 | impl_pin!(PIO4_9, 4, 9); | ||
| 779 | impl_pin!(PIO4_10, 4, 10); | ||
| 780 | |||
| 781 | // GPIO port 7 | ||
| 782 | define_port_waker!(port7_waker, 24, 31); | ||
| 783 | impl_pin!(PIO7_24, 7, 24); | ||
| 784 | impl_pin!(PIO7_25, 7, 25); | ||
| 785 | impl_pin!(PIO7_26, 7, 26); | ||
| 786 | impl_pin!(PIO7_27, 7, 27); | ||
| 787 | impl_pin!(PIO7_28, 7, 28); | ||
| 788 | impl_pin!(PIO7_29, 7, 29); | ||
| 789 | impl_pin!(PIO7_30, 7, 30); | ||
| 790 | impl_pin!(PIO7_31, 7, 31); | ||
| 791 | |||
| 792 | static GPIO_WAKERS: [Option<&PortWaker>; PORT_COUNT] = [ | ||
| 793 | Some(&port0_waker::WAKER), | ||
| 794 | Some(&port1_waker::WAKER), | ||
| 795 | Some(&port2_waker::WAKER), | ||
| 796 | Some(&port3_waker::WAKER), | ||
| 797 | Some(&port4_waker::WAKER), | ||
| 798 | None, | ||
| 799 | None, | ||
| 800 | Some(&port7_waker::WAKER), | ||
| 801 | ]; | ||
| 802 | |||
| 803 | impl embedded_hal_02::digital::v2::InputPin for Flex<'_, SenseEnabled> { | ||
| 804 | type Error = Infallible; | ||
| 805 | |||
| 806 | #[inline] | ||
| 807 | fn is_high(&self) -> Result<bool, Self::Error> { | ||
| 808 | Ok(self.is_high()) | ||
| 809 | } | ||
| 810 | |||
| 811 | #[inline] | ||
| 812 | fn is_low(&self) -> Result<bool, Self::Error> { | ||
| 813 | Ok(self.is_low()) | ||
| 814 | } | ||
| 815 | } | ||
| 816 | |||
| 817 | impl<S: Sense> embedded_hal_02::digital::v2::OutputPin for Flex<'_, S> { | ||
| 818 | type Error = Infallible; | ||
| 819 | |||
| 820 | #[inline] | ||
| 821 | fn set_high(&mut self) -> Result<(), Self::Error> { | ||
| 822 | self.set_high(); | ||
| 823 | Ok(()) | ||
| 824 | } | ||
| 825 | |||
| 826 | #[inline] | ||
| 827 | fn set_low(&mut self) -> Result<(), Self::Error> { | ||
| 828 | self.set_low(); | ||
| 829 | Ok(()) | ||
| 830 | } | ||
| 831 | } | ||
| 832 | |||
| 833 | impl embedded_hal_02::digital::v2::StatefulOutputPin for Flex<'_, SenseEnabled> { | ||
| 834 | #[inline] | ||
| 835 | fn is_set_high(&self) -> Result<bool, Self::Error> { | ||
| 836 | Ok(self.is_set_high()) | ||
| 837 | } | ||
| 838 | |||
| 839 | #[inline] | ||
| 840 | fn is_set_low(&self) -> Result<bool, Self::Error> { | ||
| 841 | Ok(self.is_set_low()) | ||
| 842 | } | ||
| 843 | } | ||
| 844 | |||
| 845 | impl<S: Sense> embedded_hal_02::digital::v2::ToggleableOutputPin for Flex<'_, S> { | ||
| 846 | type Error = Infallible; | ||
| 847 | |||
| 848 | #[inline] | ||
| 849 | fn toggle(&mut self) -> Result<(), Self::Error> { | ||
| 850 | self.toggle(); | ||
| 851 | Ok(()) | ||
| 852 | } | ||
| 853 | } | ||
| 854 | |||
| 855 | impl embedded_hal_02::digital::v2::InputPin for Input<'_> { | ||
| 856 | type Error = Infallible; | ||
| 857 | |||
| 858 | #[inline] | ||
| 859 | fn is_high(&self) -> Result<bool, Self::Error> { | ||
| 860 | Ok(self.is_high()) | ||
| 861 | } | ||
| 862 | |||
| 863 | #[inline] | ||
| 864 | fn is_low(&self) -> Result<bool, Self::Error> { | ||
| 865 | Ok(self.is_low()) | ||
| 866 | } | ||
| 867 | } | ||
| 868 | |||
| 869 | impl embedded_hal_02::digital::v2::OutputPin for Output<'_> { | ||
| 870 | type Error = Infallible; | ||
| 871 | |||
| 872 | #[inline] | ||
| 873 | fn set_high(&mut self) -> Result<(), Self::Error> { | ||
| 874 | self.set_high(); | ||
| 875 | Ok(()) | ||
| 876 | } | ||
| 877 | |||
| 878 | #[inline] | ||
| 879 | fn set_low(&mut self) -> Result<(), Self::Error> { | ||
| 880 | self.set_low(); | ||
| 881 | Ok(()) | ||
| 882 | } | ||
| 883 | } | ||
| 884 | |||
| 885 | impl embedded_hal_02::digital::v2::StatefulOutputPin for Output<'_> { | ||
| 886 | #[inline] | ||
| 887 | fn is_set_high(&self) -> Result<bool, Self::Error> { | ||
| 888 | Ok(self.is_set_high()) | ||
| 889 | } | ||
| 890 | |||
| 891 | #[inline] | ||
| 892 | fn is_set_low(&self) -> Result<bool, Self::Error> { | ||
| 893 | Ok(self.is_set_low()) | ||
| 894 | } | ||
| 895 | } | ||
| 896 | |||
| 897 | impl embedded_hal_02::digital::v2::ToggleableOutputPin for Output<'_> { | ||
| 898 | type Error = Infallible; | ||
| 899 | |||
| 900 | #[inline] | ||
| 901 | fn toggle(&mut self) -> Result<(), Self::Error> { | ||
| 902 | self.toggle(); | ||
| 903 | Ok(()) | ||
| 904 | } | ||
| 905 | } | ||
| 906 | |||
| 907 | impl<S: Sense> embedded_hal_1::digital::ErrorType for Flex<'_, S> { | ||
| 908 | type Error = Infallible; | ||
| 909 | } | ||
| 910 | |||
| 911 | impl embedded_hal_1::digital::InputPin for Flex<'_, SenseEnabled> { | ||
| 912 | #[inline] | ||
| 913 | fn is_high(&mut self) -> Result<bool, Self::Error> { | ||
| 914 | // Dereference of self is used here and a few other places to | ||
| 915 | // access the correct method (since different types/traits | ||
| 916 | // share method names) | ||
| 917 | Ok((*self).is_high()) | ||
| 918 | } | ||
| 919 | |||
| 920 | #[inline] | ||
| 921 | fn is_low(&mut self) -> Result<bool, Self::Error> { | ||
| 922 | Ok((*self).is_low()) | ||
| 923 | } | ||
| 924 | } | ||
| 925 | |||
| 926 | impl<S: Sense> embedded_hal_1::digital::OutputPin for Flex<'_, S> { | ||
| 927 | #[inline] | ||
| 928 | fn set_high(&mut self) -> Result<(), Self::Error> { | ||
| 929 | self.set_high(); | ||
| 930 | Ok(()) | ||
| 931 | } | ||
| 932 | |||
| 933 | #[inline] | ||
| 934 | fn set_low(&mut self) -> Result<(), Self::Error> { | ||
| 935 | self.set_low(); | ||
| 936 | Ok(()) | ||
| 937 | } | ||
| 938 | } | ||
| 939 | |||
| 940 | impl embedded_hal_1::digital::StatefulOutputPin for Flex<'_, SenseEnabled> { | ||
| 941 | #[inline] | ||
| 942 | fn is_set_high(&mut self) -> Result<bool, Self::Error> { | ||
| 943 | Ok((*self).is_set_high()) | ||
| 944 | } | ||
| 945 | |||
| 946 | #[inline] | ||
| 947 | fn is_set_low(&mut self) -> Result<bool, Self::Error> { | ||
| 948 | Ok((*self).is_set_low()) | ||
| 949 | } | ||
| 950 | } | ||
| 951 | |||
| 952 | impl<'d> embedded_hal_async::digital::Wait for Flex<'d, SenseEnabled> { | ||
| 953 | #[inline] | ||
| 954 | async fn wait_for_high(&mut self) -> Result<(), Self::Error> { | ||
| 955 | self.wait_for_high().await; | ||
| 956 | Ok(()) | ||
| 957 | } | ||
| 958 | |||
| 959 | #[inline] | ||
| 960 | async fn wait_for_low(&mut self) -> Result<(), Self::Error> { | ||
| 961 | self.wait_for_low().await; | ||
| 962 | Ok(()) | ||
| 963 | } | ||
| 964 | |||
| 965 | #[inline] | ||
| 966 | async fn wait_for_rising_edge(&mut self) -> Result<(), Self::Error> { | ||
| 967 | self.wait_for_rising_edge().await; | ||
| 968 | Ok(()) | ||
| 969 | } | ||
| 970 | |||
| 971 | #[inline] | ||
| 972 | async fn wait_for_falling_edge(&mut self) -> Result<(), Self::Error> { | ||
| 973 | self.wait_for_falling_edge().await; | ||
| 974 | Ok(()) | ||
| 975 | } | ||
| 976 | |||
| 977 | #[inline] | ||
| 978 | async fn wait_for_any_edge(&mut self) -> Result<(), Self::Error> { | ||
| 979 | self.wait_for_any_edge().await; | ||
| 980 | Ok(()) | ||
| 981 | } | ||
| 982 | } | ||
| 983 | |||
| 984 | impl embedded_hal_1::digital::ErrorType for Input<'_> { | ||
| 985 | type Error = Infallible; | ||
| 986 | } | ||
| 987 | |||
| 988 | impl embedded_hal_1::digital::InputPin for Input<'_> { | ||
| 989 | #[inline] | ||
| 990 | fn is_high(&mut self) -> Result<bool, Self::Error> { | ||
| 991 | Ok((*self).is_high()) | ||
| 992 | } | ||
| 993 | |||
| 994 | #[inline] | ||
| 995 | fn is_low(&mut self) -> Result<bool, Self::Error> { | ||
| 996 | Ok((*self).is_low()) | ||
| 997 | } | ||
| 998 | } | ||
| 999 | |||
| 1000 | impl<'d> embedded_hal_async::digital::Wait for Input<'d> { | ||
| 1001 | #[inline] | ||
| 1002 | async fn wait_for_high(&mut self) -> Result<(), Self::Error> { | ||
| 1003 | self.wait_for_high().await; | ||
| 1004 | Ok(()) | ||
| 1005 | } | ||
| 1006 | |||
| 1007 | #[inline] | ||
| 1008 | async fn wait_for_low(&mut self) -> Result<(), Self::Error> { | ||
| 1009 | self.wait_for_low().await; | ||
| 1010 | Ok(()) | ||
| 1011 | } | ||
| 1012 | |||
| 1013 | #[inline] | ||
| 1014 | async fn wait_for_rising_edge(&mut self) -> Result<(), Self::Error> { | ||
| 1015 | self.wait_for_rising_edge().await; | ||
| 1016 | Ok(()) | ||
| 1017 | } | ||
| 1018 | |||
| 1019 | #[inline] | ||
| 1020 | async fn wait_for_falling_edge(&mut self) -> Result<(), Self::Error> { | ||
| 1021 | self.wait_for_falling_edge().await; | ||
| 1022 | Ok(()) | ||
| 1023 | } | ||
| 1024 | |||
| 1025 | #[inline] | ||
| 1026 | async fn wait_for_any_edge(&mut self) -> Result<(), Self::Error> { | ||
| 1027 | self.wait_for_any_edge().await; | ||
| 1028 | Ok(()) | ||
| 1029 | } | ||
| 1030 | } | ||
| 1031 | |||
| 1032 | impl embedded_hal_1::digital::ErrorType for Output<'_> { | ||
| 1033 | type Error = Infallible; | ||
| 1034 | } | ||
| 1035 | |||
| 1036 | impl embedded_hal_1::digital::OutputPin for Output<'_> { | ||
| 1037 | #[inline] | ||
| 1038 | fn set_high(&mut self) -> Result<(), Self::Error> { | ||
| 1039 | self.set_high(); | ||
| 1040 | Ok(()) | ||
| 1041 | } | ||
| 1042 | |||
| 1043 | #[inline] | ||
| 1044 | fn set_low(&mut self) -> Result<(), Self::Error> { | ||
| 1045 | self.set_low(); | ||
| 1046 | Ok(()) | ||
| 1047 | } | ||
| 1048 | } | ||
| 1049 | |||
| 1050 | impl embedded_hal_1::digital::StatefulOutputPin for Output<'_> { | ||
| 1051 | #[inline] | ||
| 1052 | fn is_set_high(&mut self) -> Result<bool, Self::Error> { | ||
| 1053 | Ok((*self).is_set_high()) | ||
| 1054 | } | ||
| 1055 | |||
| 1056 | #[inline] | ||
| 1057 | fn is_set_low(&mut self) -> Result<bool, Self::Error> { | ||
| 1058 | Ok((*self).is_set_low()) | ||
| 1059 | } | ||
| 1060 | } | ||
diff --git a/embassy-imxrt/src/iopctl.rs b/embassy-imxrt/src/iopctl.rs new file mode 100644 index 000000000..a3b8b14d6 --- /dev/null +++ b/embassy-imxrt/src/iopctl.rs | |||
| @@ -0,0 +1,717 @@ | |||
| 1 | //! IO Pad Controller (IOPCTL) | ||
| 2 | //! | ||
| 3 | //! Also known as IO Pin Configuration (IOCON) | ||
| 4 | |||
| 5 | use crate::pac::{iopctl, Iopctl}; | ||
| 6 | |||
| 7 | // A generic pin of any type. | ||
| 8 | // | ||
| 9 | // The actual pin type used here is arbitrary, | ||
| 10 | // as all PioM_N types provide the same methods. | ||
| 11 | // | ||
| 12 | // Merely need some pin type to cast a raw pointer | ||
| 13 | // to in order to access the provided methods. | ||
| 14 | #[allow(non_camel_case_types)] | ||
| 15 | type PioM_N = iopctl::Pio0_0; | ||
| 16 | |||
| 17 | /// Pin function number. | ||
| 18 | #[derive(Debug, Copy, Clone, Eq, PartialEq)] | ||
| 19 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 20 | pub enum Function { | ||
| 21 | /// Function 0 | ||
| 22 | F0, | ||
| 23 | /// Function 1 | ||
| 24 | F1, | ||
| 25 | /// Function 2 | ||
| 26 | F2, | ||
| 27 | /// Function 3 | ||
| 28 | F3, | ||
| 29 | /// Function 4 | ||
| 30 | F4, | ||
| 31 | /// Function 5 | ||
| 32 | F5, | ||
| 33 | /// Function 6 | ||
| 34 | F6, | ||
| 35 | /// Function 7 | ||
| 36 | F7, | ||
| 37 | /// Function 8 | ||
| 38 | F8, | ||
| 39 | } | ||
| 40 | |||
| 41 | /// Internal pull-up/down resistors on a pin. | ||
| 42 | #[derive(Debug, Copy, Clone, Eq, PartialEq)] | ||
| 43 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 44 | pub enum Pull { | ||
| 45 | /// No pull-up or pull-down resistor selected | ||
| 46 | None, | ||
| 47 | /// Pull-up resistor | ||
| 48 | Up, | ||
| 49 | /// Pull-down resistor | ||
| 50 | Down, | ||
| 51 | } | ||
| 52 | |||
| 53 | /// Pin slew rate. | ||
| 54 | #[derive(Debug, Copy, Clone, Eq, PartialEq)] | ||
| 55 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 56 | pub enum SlewRate { | ||
| 57 | /// Standard slew rate | ||
| 58 | Standard, | ||
| 59 | /// Slow slew rate | ||
| 60 | Slow, | ||
| 61 | } | ||
| 62 | |||
| 63 | /// Output drive strength of a pin. | ||
| 64 | #[derive(Debug, Copy, Clone, Eq, PartialEq)] | ||
| 65 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 66 | pub enum DriveStrength { | ||
| 67 | /// Normal | ||
| 68 | Normal, | ||
| 69 | /// Full | ||
| 70 | Full, | ||
| 71 | } | ||
| 72 | |||
| 73 | /// Output drive mode of a pin. | ||
| 74 | #[derive(Debug, Copy, Clone, Eq, PartialEq)] | ||
| 75 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 76 | pub enum DriveMode { | ||
| 77 | /// Push-Pull | ||
| 78 | PushPull, | ||
| 79 | /// Pseudo Open-Drain | ||
| 80 | OpenDrain, | ||
| 81 | } | ||
| 82 | |||
| 83 | /// Input inverter of a pin. | ||
| 84 | #[derive(Debug, Copy, Clone, Eq, PartialEq)] | ||
| 85 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 86 | pub enum Inverter { | ||
| 87 | /// No inverter | ||
| 88 | Disabled, | ||
| 89 | /// Enable input inverter on the input port. A low signal will be | ||
| 90 | /// seen as a high signal by the pin. | ||
| 91 | Enabled, | ||
| 92 | } | ||
| 93 | |||
| 94 | trait SealedPin {} | ||
| 95 | trait ToAnyPin: SealedPin { | ||
| 96 | #[inline] | ||
| 97 | fn to_raw(port: u8, pin: u8) -> AnyPin { | ||
| 98 | // SAFETY: This is safe since this is only called from within the module, | ||
| 99 | // where the port and pin numbers have been verified to be correct. | ||
| 100 | unsafe { AnyPin::steal(port, pin) } | ||
| 101 | } | ||
| 102 | } | ||
| 103 | |||
| 104 | trait ToFC15Pin: SealedPin { | ||
| 105 | #[inline] | ||
| 106 | fn to_raw(pin: u8) -> FC15Pin { | ||
| 107 | // SAFETY: This is safe since this is only called from within the module, | ||
| 108 | // where the port and pin numbers have been verified to be correct. | ||
| 109 | unsafe { FC15Pin::steal(pin) } | ||
| 110 | } | ||
| 111 | } | ||
| 112 | |||
| 113 | /// A pin that can be configured via iopctl. | ||
| 114 | #[allow(private_bounds)] | ||
| 115 | pub trait IopctlPin: SealedPin { | ||
| 116 | /// Sets the function number of a pin. | ||
| 117 | /// | ||
| 118 | /// This number corresponds to a specific function that the pin supports. | ||
| 119 | /// | ||
| 120 | /// Typically, function 0 corresponds to GPIO while other numbers correspond to a special function. | ||
| 121 | /// | ||
| 122 | /// See Section 7.5.3 in reference manual for list of pins and their supported functions. | ||
| 123 | fn set_function(&self, function: Function) -> &Self; | ||
| 124 | |||
| 125 | /// Enables either a pull-up or pull-down resistor on a pin. | ||
| 126 | /// | ||
| 127 | /// Setting this to [`Pull::None`] will disable the resistor. | ||
| 128 | fn set_pull(&self, pull: Pull) -> &Self; | ||
| 129 | |||
| 130 | /// Enables the input buffer of a pin. | ||
| 131 | /// | ||
| 132 | /// This must be enabled for any pin acting as an input, | ||
| 133 | /// and some peripheral pins acting as output may need this enabled as well. | ||
| 134 | /// | ||
| 135 | /// If there is any doubt, it is best to enable the input buffer. | ||
| 136 | /// | ||
| 137 | /// See Section 7.4.2.3 of reference manual. | ||
| 138 | fn enable_input_buffer(&self) -> &Self; | ||
| 139 | |||
| 140 | /// Disables the input buffer of a pin. | ||
| 141 | fn disable_input_buffer(&self) -> &Self; | ||
| 142 | |||
| 143 | /// Sets the slew rate of a pin. | ||
| 144 | /// | ||
| 145 | /// This controls the speed at which a pin can toggle, | ||
| 146 | /// which is voltage and load dependent. | ||
| 147 | fn set_slew_rate(&self, slew_rate: SlewRate) -> &Self; | ||
| 148 | |||
| 149 | /// Sets the output drive strength of a pin. | ||
| 150 | /// | ||
| 151 | /// A drive strength of [`DriveStrength::Full`] has twice the | ||
| 152 | /// high and low drive capability of the [`DriveStrength::Normal`] setting. | ||
| 153 | fn set_drive_strength(&self, strength: DriveStrength) -> &Self; | ||
| 154 | |||
| 155 | /// Enables the analog multiplexer of a pin. | ||
| 156 | /// | ||
| 157 | /// This must be called to allow analog functionalities of a pin. | ||
| 158 | /// | ||
| 159 | /// To protect the analog input, [`IopctlPin::set_function`] should be | ||
| 160 | /// called with [`Function::F0`] to disable digital functions. | ||
| 161 | /// | ||
| 162 | /// Additionally, [`IopctlPin::disable_input_buffer`] and [`IopctlPin::set_pull`] | ||
| 163 | /// with [`Pull::None`] should be called. | ||
| 164 | fn enable_analog_multiplex(&self) -> &Self; | ||
| 165 | |||
| 166 | /// Disables the analog multiplexer of a pin. | ||
| 167 | fn disable_analog_multiplex(&self) -> &Self; | ||
| 168 | |||
| 169 | /// Sets the ouput drive mode of a pin. | ||
| 170 | /// | ||
| 171 | /// A pin configured as [`DriveMode::OpenDrain`] actually operates in | ||
| 172 | /// a "pseudo" open-drain mode which is somewhat different than true open-drain. | ||
| 173 | /// | ||
| 174 | /// See Section 7.4.2.7 of reference manual. | ||
| 175 | fn set_drive_mode(&self, mode: DriveMode) -> &Self; | ||
| 176 | |||
| 177 | /// Sets the input inverter of an input pin. | ||
| 178 | /// | ||
| 179 | /// Setting this to [`Inverter::Enabled`] will invert | ||
| 180 | /// the input signal. | ||
| 181 | fn set_input_inverter(&self, inverter: Inverter) -> &Self; | ||
| 182 | |||
| 183 | /// Returns a pin to its reset state. | ||
| 184 | fn reset(&self) -> &Self; | ||
| 185 | } | ||
| 186 | |||
| 187 | /// Represents a pin peripheral created at run-time from given port and pin numbers. | ||
| 188 | pub struct AnyPin { | ||
| 189 | pin_port: u8, | ||
| 190 | reg: &'static PioM_N, | ||
| 191 | } | ||
| 192 | |||
| 193 | impl AnyPin { | ||
| 194 | /// Creates a pin from raw port and pin numbers which can then be configured. | ||
| 195 | /// | ||
| 196 | /// This should ONLY be called when there is no other choice | ||
| 197 | /// (e.g. from a type-erased GPIO pin). | ||
| 198 | /// | ||
| 199 | /// Otherwise, pin peripherals should be configured directly. | ||
| 200 | /// | ||
| 201 | /// # Safety | ||
| 202 | /// | ||
| 203 | /// The caller MUST ensure valid port and pin numbers are provided, | ||
| 204 | /// and that multiple instances of [`AnyPin`] with the same port | ||
| 205 | /// and pin combination are not being used simultaneously. | ||
| 206 | /// | ||
| 207 | /// Failure to uphold these requirements will result in undefined behavior. | ||
| 208 | /// | ||
| 209 | /// See Table 297 in reference manual for a list of valid | ||
| 210 | /// pin and port number combinations. | ||
| 211 | #[must_use] | ||
| 212 | pub unsafe fn steal(port: u8, pin: u8) -> Self { | ||
| 213 | // Calculates the offset from the beginning of the IOPCTL register block | ||
| 214 | // address to the register address representing the pin. | ||
| 215 | // | ||
| 216 | // See Table 297 in reference manual for how this offset is calculated. | ||
| 217 | let offset = ((port as usize) << 7) + ((pin as usize) << 2); | ||
| 218 | |||
| 219 | // SAFETY: This is safe assuming the caller of this function satisfies the safety requirements above. | ||
| 220 | let reg = unsafe { &*Iopctl::ptr().byte_offset(offset as isize).cast() }; | ||
| 221 | Self { | ||
| 222 | pin_port: port * 32 + pin, | ||
| 223 | reg, | ||
| 224 | } | ||
| 225 | } | ||
| 226 | |||
| 227 | /// Returns the pin's port and pin combination. | ||
| 228 | #[must_use] | ||
| 229 | pub fn pin_port(&self) -> usize { | ||
| 230 | self.pin_port as usize | ||
| 231 | } | ||
| 232 | } | ||
| 233 | |||
| 234 | /// Represents a FC15 pin peripheral created at run-time from given pin number. | ||
| 235 | pub struct FC15Pin { | ||
| 236 | reg: &'static PioM_N, | ||
| 237 | } | ||
| 238 | |||
| 239 | impl FC15Pin { | ||
| 240 | /// Creates an FC15 pin from raw pin number which can then be configured. | ||
| 241 | /// | ||
| 242 | /// This should ONLY be called when there is no other choice | ||
| 243 | /// (e.g. from a type-erased GPIO pin). | ||
| 244 | /// | ||
| 245 | /// Otherwise, pin peripherals should be configured directly. | ||
| 246 | /// | ||
| 247 | /// # Safety | ||
| 248 | /// | ||
| 249 | /// The caller MUST ensure valid port and pin numbers are provided, | ||
| 250 | /// and that multiple instances of [`AnyPin`] with the same port | ||
| 251 | /// and pin combination are not being used simultaneously. | ||
| 252 | /// | ||
| 253 | /// Failure to uphold these requirements will result in undefined behavior. | ||
| 254 | /// | ||
| 255 | /// See Table 297 in reference manual for a list of valid | ||
| 256 | /// pin and port number combinations. | ||
| 257 | #[must_use] | ||
| 258 | pub unsafe fn steal(pin: u8) -> Self { | ||
| 259 | // Table 297: FC15_I2C_SCL offset = 0x400, FC15_I2C_SCL offset = 0x404 | ||
| 260 | let iopctl = unsafe { crate::pac::Iopctl::steal() }; | ||
| 261 | |||
| 262 | let reg = if pin == 0 { | ||
| 263 | &*iopctl.fc15_i2c_scl().as_ptr().cast() | ||
| 264 | } else { | ||
| 265 | &*iopctl.fc15_i2c_sda().as_ptr().cast() | ||
| 266 | }; | ||
| 267 | |||
| 268 | Self { reg } | ||
| 269 | } | ||
| 270 | } | ||
| 271 | |||
| 272 | // This allows AnyPin/FC15Pin to be used in HAL constructors that require types | ||
| 273 | // which impl Peripheral. Used primarily by GPIO HAL to convert type-erased | ||
| 274 | // GPIO pins back into an Output or Input pin specifically. | ||
| 275 | embassy_hal_internal::impl_peripheral!(AnyPin); | ||
| 276 | |||
| 277 | impl SealedPin for AnyPin {} | ||
| 278 | |||
| 279 | embassy_hal_internal::impl_peripheral!(FC15Pin); | ||
| 280 | |||
| 281 | impl SealedPin for FC15Pin {} | ||
| 282 | |||
| 283 | macro_rules! impl_iopctlpin { | ||
| 284 | ($pintype:ident) => { | ||
| 285 | impl IopctlPin for $pintype { | ||
| 286 | fn set_function(&self, function: Function) -> &Self { | ||
| 287 | critical_section::with(|_| match function { | ||
| 288 | Function::F0 => { | ||
| 289 | self.reg.modify(|_, w| w.fsel().function_0()); | ||
| 290 | } | ||
| 291 | Function::F1 => { | ||
| 292 | self.reg.modify(|_, w| w.fsel().function_1()); | ||
| 293 | } | ||
| 294 | Function::F2 => { | ||
| 295 | self.reg.modify(|_, w| w.fsel().function_2()); | ||
| 296 | } | ||
| 297 | Function::F3 => { | ||
| 298 | self.reg.modify(|_, w| w.fsel().function_3()); | ||
| 299 | } | ||
| 300 | Function::F4 => { | ||
| 301 | self.reg.modify(|_, w| w.fsel().function_4()); | ||
| 302 | } | ||
| 303 | Function::F5 => { | ||
| 304 | self.reg.modify(|_, w| w.fsel().function_5()); | ||
| 305 | } | ||
| 306 | Function::F6 => { | ||
| 307 | self.reg.modify(|_, w| w.fsel().function_6()); | ||
| 308 | } | ||
| 309 | Function::F7 => { | ||
| 310 | self.reg.modify(|_, w| w.fsel().function_7()); | ||
| 311 | } | ||
| 312 | Function::F8 => { | ||
| 313 | self.reg.modify(|_, w| w.fsel().function_8()); | ||
| 314 | } | ||
| 315 | }); | ||
| 316 | self | ||
| 317 | } | ||
| 318 | |||
| 319 | fn set_pull(&self, pull: Pull) -> &Self { | ||
| 320 | critical_section::with(|_| { | ||
| 321 | match pull { | ||
| 322 | Pull::None => { | ||
| 323 | self.reg.modify(|_, w| w.pupdena().disabled()); | ||
| 324 | } | ||
| 325 | Pull::Up => { | ||
| 326 | self.reg.modify(|_, w| w.pupdena().enabled().pupdsel().pull_up()); | ||
| 327 | } | ||
| 328 | Pull::Down => { | ||
| 329 | self.reg | ||
| 330 | .modify(|_, w| w.pupdena().enabled().pupdsel().pull_down()); | ||
| 331 | } | ||
| 332 | } | ||
| 333 | self | ||
| 334 | }) | ||
| 335 | } | ||
| 336 | |||
| 337 | fn enable_input_buffer(&self) -> &Self { | ||
| 338 | critical_section::with(|_| self.reg.modify(|_, w| w.ibena().enabled())); | ||
| 339 | self | ||
| 340 | } | ||
| 341 | |||
| 342 | fn disable_input_buffer(&self) -> &Self { | ||
| 343 | critical_section::with(|_| self.reg.modify(|_, w| w.ibena().disabled())); | ||
| 344 | self | ||
| 345 | } | ||
| 346 | |||
| 347 | fn set_slew_rate(&self, slew_rate: SlewRate) -> &Self { | ||
| 348 | critical_section::with(|_| match slew_rate { | ||
| 349 | SlewRate::Standard => { | ||
| 350 | self.reg.modify(|_, w| w.slewrate().normal()); | ||
| 351 | } | ||
| 352 | SlewRate::Slow => { | ||
| 353 | self.reg.modify(|_, w| w.slewrate().slow()); | ||
| 354 | } | ||
| 355 | }); | ||
| 356 | self | ||
| 357 | } | ||
| 358 | |||
| 359 | fn set_drive_strength(&self, strength: DriveStrength) -> &Self { | ||
| 360 | critical_section::with(|_| match strength { | ||
| 361 | DriveStrength::Normal => { | ||
| 362 | self.reg.modify(|_, w| w.fulldrive().normal_drive()); | ||
| 363 | } | ||
| 364 | DriveStrength::Full => { | ||
| 365 | self.reg.modify(|_, w| w.fulldrive().full_drive()); | ||
| 366 | } | ||
| 367 | }); | ||
| 368 | self | ||
| 369 | } | ||
| 370 | |||
| 371 | fn enable_analog_multiplex(&self) -> &Self { | ||
| 372 | critical_section::with(|_| self.reg.modify(|_, w| w.amena().enabled())); | ||
| 373 | self | ||
| 374 | } | ||
| 375 | |||
| 376 | fn disable_analog_multiplex(&self) -> &Self { | ||
| 377 | critical_section::with(|_| self.reg.modify(|_, w| w.amena().disabled())); | ||
| 378 | self | ||
| 379 | } | ||
| 380 | |||
| 381 | fn set_drive_mode(&self, mode: DriveMode) -> &Self { | ||
| 382 | critical_section::with(|_| match mode { | ||
| 383 | DriveMode::PushPull => { | ||
| 384 | self.reg.modify(|_, w| w.odena().disabled()); | ||
| 385 | } | ||
| 386 | DriveMode::OpenDrain => { | ||
| 387 | self.reg.modify(|_, w| w.odena().enabled()); | ||
| 388 | } | ||
| 389 | }); | ||
| 390 | self | ||
| 391 | } | ||
| 392 | |||
| 393 | fn set_input_inverter(&self, inverter: Inverter) -> &Self { | ||
| 394 | critical_section::with(|_| match inverter { | ||
| 395 | Inverter::Disabled => { | ||
| 396 | self.reg.modify(|_, w| w.iiena().disabled()); | ||
| 397 | } | ||
| 398 | Inverter::Enabled => { | ||
| 399 | self.reg.modify(|_, w| w.iiena().enabled()); | ||
| 400 | } | ||
| 401 | }); | ||
| 402 | self | ||
| 403 | } | ||
| 404 | |||
| 405 | fn reset(&self) -> &Self { | ||
| 406 | self.reg.reset(); | ||
| 407 | self | ||
| 408 | } | ||
| 409 | } | ||
| 410 | }; | ||
| 411 | } | ||
| 412 | |||
| 413 | impl_iopctlpin!(AnyPin); | ||
| 414 | impl_iopctlpin!(FC15Pin); | ||
| 415 | |||
| 416 | macro_rules! impl_FC15pin { | ||
| 417 | ($pin_periph:ident, $pin_no:expr) => { | ||
| 418 | impl SealedPin for crate::peripherals::$pin_periph {} | ||
| 419 | impl ToFC15Pin for crate::peripherals::$pin_periph {} | ||
| 420 | impl IopctlPin for crate::peripherals::$pin_periph { | ||
| 421 | #[inline] | ||
| 422 | fn set_function(&self, _function: Function) -> &Self { | ||
| 423 | //No function configuration for FC15 pin | ||
| 424 | self | ||
| 425 | } | ||
| 426 | |||
| 427 | #[inline] | ||
| 428 | fn set_pull(&self, pull: Pull) -> &Self { | ||
| 429 | Self::to_raw($pin_no).set_pull(pull); | ||
| 430 | self | ||
| 431 | } | ||
| 432 | |||
| 433 | #[inline] | ||
| 434 | fn enable_input_buffer(&self) -> &Self { | ||
| 435 | Self::to_raw($pin_no).enable_input_buffer(); | ||
| 436 | self | ||
| 437 | } | ||
| 438 | |||
| 439 | #[inline] | ||
| 440 | fn disable_input_buffer(&self) -> &Self { | ||
| 441 | Self::to_raw($pin_no).disable_input_buffer(); | ||
| 442 | self | ||
| 443 | } | ||
| 444 | |||
| 445 | #[inline] | ||
| 446 | fn set_slew_rate(&self, slew_rate: SlewRate) -> &Self { | ||
| 447 | Self::to_raw($pin_no).set_slew_rate(slew_rate); | ||
| 448 | self | ||
| 449 | } | ||
| 450 | |||
| 451 | #[inline] | ||
| 452 | fn set_drive_strength(&self, strength: DriveStrength) -> &Self { | ||
| 453 | Self::to_raw($pin_no).set_drive_strength(strength); | ||
| 454 | self | ||
| 455 | } | ||
| 456 | |||
| 457 | #[inline] | ||
| 458 | fn enable_analog_multiplex(&self) -> &Self { | ||
| 459 | Self::to_raw($pin_no).enable_analog_multiplex(); | ||
| 460 | self | ||
| 461 | } | ||
| 462 | |||
| 463 | #[inline] | ||
| 464 | fn disable_analog_multiplex(&self) -> &Self { | ||
| 465 | Self::to_raw($pin_no).disable_analog_multiplex(); | ||
| 466 | self | ||
| 467 | } | ||
| 468 | |||
| 469 | #[inline] | ||
| 470 | fn set_drive_mode(&self, mode: DriveMode) -> &Self { | ||
| 471 | Self::to_raw($pin_no).set_drive_mode(mode); | ||
| 472 | self | ||
| 473 | } | ||
| 474 | |||
| 475 | #[inline] | ||
| 476 | fn set_input_inverter(&self, inverter: Inverter) -> &Self { | ||
| 477 | Self::to_raw($pin_no).set_input_inverter(inverter); | ||
| 478 | self | ||
| 479 | } | ||
| 480 | |||
| 481 | #[inline] | ||
| 482 | fn reset(&self) -> &Self { | ||
| 483 | Self::to_raw($pin_no).reset(); | ||
| 484 | self | ||
| 485 | } | ||
| 486 | } | ||
| 487 | }; | ||
| 488 | } | ||
| 489 | |||
| 490 | macro_rules! impl_pin { | ||
| 491 | ($pin_periph:ident, $pin_port:expr, $pin_no:expr) => { | ||
| 492 | impl SealedPin for crate::peripherals::$pin_periph {} | ||
| 493 | impl ToAnyPin for crate::peripherals::$pin_periph {} | ||
| 494 | impl IopctlPin for crate::peripherals::$pin_periph { | ||
| 495 | #[inline] | ||
| 496 | fn set_function(&self, function: Function) -> &Self { | ||
| 497 | Self::to_raw($pin_port, $pin_no).set_function(function); | ||
| 498 | self | ||
| 499 | } | ||
| 500 | |||
| 501 | #[inline] | ||
| 502 | fn set_pull(&self, pull: Pull) -> &Self { | ||
| 503 | Self::to_raw($pin_port, $pin_no).set_pull(pull); | ||
| 504 | self | ||
| 505 | } | ||
| 506 | |||
| 507 | #[inline] | ||
| 508 | fn enable_input_buffer(&self) -> &Self { | ||
| 509 | Self::to_raw($pin_port, $pin_no).enable_input_buffer(); | ||
| 510 | self | ||
| 511 | } | ||
| 512 | |||
| 513 | #[inline] | ||
| 514 | fn disable_input_buffer(&self) -> &Self { | ||
| 515 | Self::to_raw($pin_port, $pin_no).disable_input_buffer(); | ||
| 516 | self | ||
| 517 | } | ||
| 518 | |||
| 519 | #[inline] | ||
| 520 | fn set_slew_rate(&self, slew_rate: SlewRate) -> &Self { | ||
| 521 | Self::to_raw($pin_port, $pin_no).set_slew_rate(slew_rate); | ||
| 522 | self | ||
| 523 | } | ||
| 524 | |||
| 525 | #[inline] | ||
| 526 | fn set_drive_strength(&self, strength: DriveStrength) -> &Self { | ||
| 527 | Self::to_raw($pin_port, $pin_no).set_drive_strength(strength); | ||
| 528 | self | ||
| 529 | } | ||
| 530 | |||
| 531 | #[inline] | ||
| 532 | fn enable_analog_multiplex(&self) -> &Self { | ||
| 533 | Self::to_raw($pin_port, $pin_no).enable_analog_multiplex(); | ||
| 534 | self | ||
| 535 | } | ||
| 536 | |||
| 537 | #[inline] | ||
| 538 | fn disable_analog_multiplex(&self) -> &Self { | ||
| 539 | Self::to_raw($pin_port, $pin_no).disable_analog_multiplex(); | ||
| 540 | self | ||
| 541 | } | ||
| 542 | |||
| 543 | #[inline] | ||
| 544 | fn set_drive_mode(&self, mode: DriveMode) -> &Self { | ||
| 545 | Self::to_raw($pin_port, $pin_no).set_drive_mode(mode); | ||
| 546 | self | ||
| 547 | } | ||
| 548 | |||
| 549 | #[inline] | ||
| 550 | fn set_input_inverter(&self, inverter: Inverter) -> &Self { | ||
| 551 | Self::to_raw($pin_port, $pin_no).set_input_inverter(inverter); | ||
| 552 | self | ||
| 553 | } | ||
| 554 | |||
| 555 | #[inline] | ||
| 556 | fn reset(&self) -> &Self { | ||
| 557 | Self::to_raw($pin_port, $pin_no).reset(); | ||
| 558 | self | ||
| 559 | } | ||
| 560 | } | ||
| 561 | }; | ||
| 562 | } | ||
| 563 | |||
| 564 | impl_pin!(PIO0_0, 0, 0); | ||
| 565 | impl_pin!(PIO0_1, 0, 1); | ||
| 566 | impl_pin!(PIO0_2, 0, 2); | ||
| 567 | impl_pin!(PIO0_3, 0, 3); | ||
| 568 | impl_pin!(PIO0_4, 0, 4); | ||
| 569 | impl_pin!(PIO0_5, 0, 5); | ||
| 570 | impl_pin!(PIO0_6, 0, 6); | ||
| 571 | impl_pin!(PIO0_7, 0, 7); | ||
| 572 | impl_pin!(PIO0_8, 0, 8); | ||
| 573 | impl_pin!(PIO0_9, 0, 9); | ||
| 574 | impl_pin!(PIO0_10, 0, 10); | ||
| 575 | impl_pin!(PIO0_11, 0, 11); | ||
| 576 | impl_pin!(PIO0_12, 0, 12); | ||
| 577 | impl_pin!(PIO0_13, 0, 13); | ||
| 578 | impl_pin!(PIO0_14, 0, 14); | ||
| 579 | impl_pin!(PIO0_15, 0, 15); | ||
| 580 | impl_pin!(PIO0_16, 0, 16); | ||
| 581 | impl_pin!(PIO0_17, 0, 17); | ||
| 582 | impl_pin!(PIO0_18, 0, 18); | ||
| 583 | impl_pin!(PIO0_19, 0, 19); | ||
| 584 | impl_pin!(PIO0_20, 0, 20); | ||
| 585 | impl_pin!(PIO0_21, 0, 21); | ||
| 586 | impl_pin!(PIO0_22, 0, 22); | ||
| 587 | impl_pin!(PIO0_23, 0, 23); | ||
| 588 | impl_pin!(PIO0_24, 0, 24); | ||
| 589 | impl_pin!(PIO0_25, 0, 25); | ||
| 590 | impl_pin!(PIO0_26, 0, 26); | ||
| 591 | impl_pin!(PIO0_27, 0, 27); | ||
| 592 | impl_pin!(PIO0_28, 0, 28); | ||
| 593 | impl_pin!(PIO0_29, 0, 29); | ||
| 594 | impl_pin!(PIO0_30, 0, 30); | ||
| 595 | impl_pin!(PIO0_31, 0, 31); | ||
| 596 | impl_pin!(PIO1_0, 1, 0); | ||
| 597 | impl_pin!(PIO1_1, 1, 1); | ||
| 598 | impl_pin!(PIO1_2, 1, 2); | ||
| 599 | impl_pin!(PIO1_3, 1, 3); | ||
| 600 | impl_pin!(PIO1_4, 1, 4); | ||
| 601 | impl_pin!(PIO1_5, 1, 5); | ||
| 602 | impl_pin!(PIO1_6, 1, 6); | ||
| 603 | impl_pin!(PIO1_7, 1, 7); | ||
| 604 | impl_pin!(PIO1_8, 1, 8); | ||
| 605 | impl_pin!(PIO1_9, 1, 9); | ||
| 606 | impl_pin!(PIO1_10, 1, 10); | ||
| 607 | impl_pin!(PIO1_11, 1, 11); | ||
| 608 | impl_pin!(PIO1_12, 1, 12); | ||
| 609 | impl_pin!(PIO1_13, 1, 13); | ||
| 610 | impl_pin!(PIO1_14, 1, 14); | ||
| 611 | impl_pin!(PIO1_15, 1, 15); | ||
| 612 | impl_pin!(PIO1_16, 1, 16); | ||
| 613 | impl_pin!(PIO1_17, 1, 17); | ||
| 614 | impl_pin!(PIO1_18, 1, 18); | ||
| 615 | impl_pin!(PIO1_19, 1, 19); | ||
| 616 | impl_pin!(PIO1_20, 1, 20); | ||
| 617 | impl_pin!(PIO1_21, 1, 21); | ||
| 618 | impl_pin!(PIO1_22, 1, 22); | ||
| 619 | impl_pin!(PIO1_23, 1, 23); | ||
| 620 | impl_pin!(PIO1_24, 1, 24); | ||
| 621 | impl_pin!(PIO1_25, 1, 25); | ||
| 622 | impl_pin!(PIO1_26, 1, 26); | ||
| 623 | impl_pin!(PIO1_27, 1, 27); | ||
| 624 | impl_pin!(PIO1_28, 1, 28); | ||
| 625 | impl_pin!(PIO1_29, 1, 29); | ||
| 626 | impl_pin!(PIO1_30, 1, 30); | ||
| 627 | impl_pin!(PIO1_31, 1, 31); | ||
| 628 | impl_pin!(PIO2_0, 2, 0); | ||
| 629 | impl_pin!(PIO2_1, 2, 1); | ||
| 630 | impl_pin!(PIO2_2, 2, 2); | ||
| 631 | impl_pin!(PIO2_3, 2, 3); | ||
| 632 | impl_pin!(PIO2_4, 2, 4); | ||
| 633 | impl_pin!(PIO2_5, 2, 5); | ||
| 634 | impl_pin!(PIO2_6, 2, 6); | ||
| 635 | impl_pin!(PIO2_7, 2, 7); | ||
| 636 | impl_pin!(PIO2_8, 2, 8); | ||
| 637 | impl_pin!(PIO2_9, 2, 9); | ||
| 638 | impl_pin!(PIO2_10, 2, 10); | ||
| 639 | impl_pin!(PIO2_11, 2, 11); | ||
| 640 | impl_pin!(PIO2_12, 2, 12); | ||
| 641 | impl_pin!(PIO2_13, 2, 13); | ||
| 642 | impl_pin!(PIO2_14, 2, 14); | ||
| 643 | impl_pin!(PIO2_15, 2, 15); | ||
| 644 | impl_pin!(PIO2_16, 2, 16); | ||
| 645 | impl_pin!(PIO2_17, 2, 17); | ||
| 646 | impl_pin!(PIO2_18, 2, 18); | ||
| 647 | impl_pin!(PIO2_19, 2, 19); | ||
| 648 | impl_pin!(PIO2_20, 2, 20); | ||
| 649 | impl_pin!(PIO2_21, 2, 21); | ||
| 650 | impl_pin!(PIO2_22, 2, 22); | ||
| 651 | impl_pin!(PIO2_23, 2, 23); | ||
| 652 | impl_pin!(PIO2_24, 2, 24); | ||
| 653 | |||
| 654 | // Note: These have have reset values of 0x41 to support SWD by default | ||
| 655 | impl_pin!(PIO2_25, 2, 25); | ||
| 656 | impl_pin!(PIO2_26, 2, 26); | ||
| 657 | |||
| 658 | impl_pin!(PIO2_27, 2, 27); | ||
| 659 | impl_pin!(PIO2_28, 2, 28); | ||
| 660 | impl_pin!(PIO2_29, 2, 29); | ||
| 661 | impl_pin!(PIO2_30, 2, 30); | ||
| 662 | impl_pin!(PIO2_31, 2, 31); | ||
| 663 | impl_pin!(PIO3_0, 3, 0); | ||
| 664 | impl_pin!(PIO3_1, 3, 1); | ||
| 665 | impl_pin!(PIO3_2, 3, 2); | ||
| 666 | impl_pin!(PIO3_3, 3, 3); | ||
| 667 | impl_pin!(PIO3_4, 3, 4); | ||
| 668 | impl_pin!(PIO3_5, 3, 5); | ||
| 669 | impl_pin!(PIO3_6, 3, 6); | ||
| 670 | impl_pin!(PIO3_7, 3, 7); | ||
| 671 | impl_pin!(PIO3_8, 3, 8); | ||
| 672 | impl_pin!(PIO3_9, 3, 9); | ||
| 673 | impl_pin!(PIO3_10, 3, 10); | ||
| 674 | impl_pin!(PIO3_11, 3, 11); | ||
| 675 | impl_pin!(PIO3_12, 3, 12); | ||
| 676 | impl_pin!(PIO3_13, 3, 13); | ||
| 677 | impl_pin!(PIO3_14, 3, 14); | ||
| 678 | impl_pin!(PIO3_15, 3, 15); | ||
| 679 | impl_pin!(PIO3_16, 3, 16); | ||
| 680 | impl_pin!(PIO3_17, 3, 17); | ||
| 681 | impl_pin!(PIO3_18, 3, 18); | ||
| 682 | impl_pin!(PIO3_19, 3, 19); | ||
| 683 | impl_pin!(PIO3_20, 3, 20); | ||
| 684 | impl_pin!(PIO3_21, 3, 21); | ||
| 685 | impl_pin!(PIO3_22, 3, 22); | ||
| 686 | impl_pin!(PIO3_23, 3, 23); | ||
| 687 | impl_pin!(PIO3_24, 3, 24); | ||
| 688 | impl_pin!(PIO3_25, 3, 25); | ||
| 689 | impl_pin!(PIO3_26, 3, 26); | ||
| 690 | impl_pin!(PIO3_27, 3, 27); | ||
| 691 | impl_pin!(PIO3_28, 3, 28); | ||
| 692 | impl_pin!(PIO3_29, 3, 29); | ||
| 693 | impl_pin!(PIO3_30, 3, 30); | ||
| 694 | impl_pin!(PIO3_31, 3, 31); | ||
| 695 | impl_pin!(PIO4_0, 4, 0); | ||
| 696 | impl_pin!(PIO4_1, 4, 1); | ||
| 697 | impl_pin!(PIO4_2, 4, 2); | ||
| 698 | impl_pin!(PIO4_3, 4, 3); | ||
| 699 | impl_pin!(PIO4_4, 4, 4); | ||
| 700 | impl_pin!(PIO4_5, 4, 5); | ||
| 701 | impl_pin!(PIO4_6, 4, 6); | ||
| 702 | impl_pin!(PIO4_7, 4, 7); | ||
| 703 | impl_pin!(PIO4_8, 4, 8); | ||
| 704 | impl_pin!(PIO4_9, 4, 9); | ||
| 705 | impl_pin!(PIO4_10, 4, 10); | ||
| 706 | impl_pin!(PIO7_24, 7, 24); | ||
| 707 | impl_pin!(PIO7_25, 7, 25); | ||
| 708 | impl_pin!(PIO7_26, 7, 26); | ||
| 709 | impl_pin!(PIO7_27, 7, 27); | ||
| 710 | impl_pin!(PIO7_28, 7, 28); | ||
| 711 | impl_pin!(PIO7_29, 7, 29); | ||
| 712 | impl_pin!(PIO7_30, 7, 30); | ||
| 713 | impl_pin!(PIO7_31, 7, 31); | ||
| 714 | |||
| 715 | // FC15 pins | ||
| 716 | impl_FC15pin!(PIOFC15_SCL, 0); | ||
| 717 | impl_FC15pin!(PIOFC15_SDA, 1); | ||
diff --git a/embassy-imxrt/src/lib.rs b/embassy-imxrt/src/lib.rs new file mode 100644 index 000000000..d56d993c3 --- /dev/null +++ b/embassy-imxrt/src/lib.rs | |||
| @@ -0,0 +1,130 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![allow(async_fn_in_trait)] | ||
| 3 | #![doc = include_str!("../README.md")] | ||
| 4 | #![warn(missing_docs)] | ||
| 5 | |||
| 6 | //! ## Feature flags | ||
| 7 | #![doc = document_features::document_features!(feature_label = r#"<span class="stab portability"><code>{feature}</code></span>"#)] | ||
| 8 | |||
| 9 | #[cfg(not(any(feature = "mimxrt633s", feature = "mimxrt685s",)))] | ||
| 10 | compile_error!( | ||
| 11 | "No chip feature activated. You must activate exactly one of the following features: | ||
| 12 | mimxrt633s, | ||
| 13 | mimxrt685s, | ||
| 14 | " | ||
| 15 | ); | ||
| 16 | |||
| 17 | // This mod MUST go first, so that the others see its macros. | ||
| 18 | pub(crate) mod fmt; | ||
| 19 | |||
| 20 | pub mod clocks; | ||
| 21 | pub mod gpio; | ||
| 22 | pub mod iopctl; | ||
| 23 | |||
| 24 | // This mod MUST go last, so that it sees all the `impl_foo!' macros | ||
| 25 | #[cfg_attr(feature = "mimxrt633s", path = "chips/mimxrt633s.rs")] | ||
| 26 | #[cfg_attr(feature = "mimxrt685s", path = "chips/mimxrt685s.rs")] | ||
| 27 | mod chip; | ||
| 28 | |||
| 29 | // Reexports | ||
| 30 | pub use chip::interrupts::*; | ||
| 31 | #[cfg(feature = "unstable-pac")] | ||
| 32 | pub use chip::pac; | ||
| 33 | #[cfg(not(feature = "unstable-pac"))] | ||
| 34 | pub(crate) use chip::pac; | ||
| 35 | pub use chip::{peripherals, Peripherals}; | ||
| 36 | pub use embassy_hal_internal::{Peri, PeripheralType}; | ||
| 37 | |||
| 38 | #[cfg(feature = "rt")] | ||
| 39 | pub use crate::pac::NVIC_PRIO_BITS; | ||
| 40 | |||
| 41 | /// Macro to bind interrupts to handlers. | ||
| 42 | /// | ||
| 43 | /// This defines the right interrupt handlers, and creates a unit struct (like `struct Irqs;`) | ||
| 44 | /// and implements the right \[`Binding`\]s for it. You can pass this struct to drivers to | ||
| 45 | /// prove at compile-time that the right interrupts have been bound. | ||
| 46 | /// | ||
| 47 | /// Example of how to bind one interrupt: | ||
| 48 | /// | ||
| 49 | /// ```rust,ignore | ||
| 50 | /// use embassy_imxrt::{bind_interrupts, flexspi, peripherals}; | ||
| 51 | /// | ||
| 52 | /// bind_interrupts!(struct Irqs { | ||
| 53 | /// FLEXSPI_IRQ => flexspi::InterruptHandler<peripherals::FLEXSPI>; | ||
| 54 | /// }); | ||
| 55 | /// ``` | ||
| 56 | /// | ||
| 57 | // developer note: this macro can't be in `embassy-hal-internal` due to the use of `$crate`. | ||
| 58 | #[macro_export] | ||
| 59 | macro_rules! bind_interrupts { | ||
| 60 | ($vis:vis struct $name:ident { $($irq:ident => $($handler:ty),*;)* }) => { | ||
| 61 | #[derive(Copy, Clone)] | ||
| 62 | $vis struct $name; | ||
| 63 | |||
| 64 | $( | ||
| 65 | #[allow(non_snake_case)] | ||
| 66 | #[no_mangle] | ||
| 67 | unsafe extern "C" fn $irq() { | ||
| 68 | $( | ||
| 69 | <$handler as $crate::interrupt::typelevel::Handler<$crate::interrupt::typelevel::$irq>>::on_interrupt(); | ||
| 70 | )* | ||
| 71 | } | ||
| 72 | |||
| 73 | $( | ||
| 74 | unsafe impl $crate::interrupt::typelevel::Binding<$crate::interrupt::typelevel::$irq, $handler> for $name {} | ||
| 75 | )* | ||
| 76 | )* | ||
| 77 | }; | ||
| 78 | } | ||
| 79 | |||
| 80 | /// HAL configuration for iMX RT600. | ||
| 81 | pub mod config { | ||
| 82 | use crate::clocks::ClockConfig; | ||
| 83 | |||
| 84 | /// HAL configuration passed when initializing. | ||
| 85 | #[non_exhaustive] | ||
| 86 | pub struct Config { | ||
| 87 | /// Clock configuration. | ||
| 88 | pub clocks: ClockConfig, | ||
| 89 | } | ||
| 90 | |||
| 91 | impl Default for Config { | ||
| 92 | fn default() -> Self { | ||
| 93 | Self { | ||
| 94 | clocks: ClockConfig::crystal(), | ||
| 95 | } | ||
| 96 | } | ||
| 97 | } | ||
| 98 | |||
| 99 | impl Config { | ||
| 100 | /// Create a new configuration with the provided clock config. | ||
| 101 | pub fn new(clocks: ClockConfig) -> Self { | ||
| 102 | Self { clocks } | ||
| 103 | } | ||
| 104 | } | ||
| 105 | } | ||
| 106 | |||
| 107 | /// Initialize the `embassy-imxrt` HAL with the provided configuration. | ||
| 108 | /// | ||
| 109 | /// This returns the peripheral singletons that can be used for creating drivers. | ||
| 110 | /// | ||
| 111 | /// This should only be called once at startup, otherwise it panics. | ||
| 112 | pub fn init(config: config::Config) -> Peripherals { | ||
| 113 | // Do this first, so that it panics if user is calling `init` a second time | ||
| 114 | // before doing anything important. | ||
| 115 | let peripherals = Peripherals::take(); | ||
| 116 | |||
| 117 | unsafe { | ||
| 118 | if let Err(e) = clocks::init(config.clocks) { | ||
| 119 | error!("unable to initialize Clocks for reason: {:?}", e); | ||
| 120 | // Panic here? | ||
| 121 | } | ||
| 122 | gpio::init(); | ||
| 123 | } | ||
| 124 | |||
| 125 | peripherals | ||
| 126 | } | ||
| 127 | |||
| 128 | pub(crate) mod sealed { | ||
| 129 | pub trait Sealed {} | ||
| 130 | } | ||
