diff options
| author | Haobo Gu <[email protected]> | 2025-12-08 17:21:27 +0800 |
|---|---|---|
| committer | Haobo Gu <[email protected]> | 2025-12-08 17:23:47 +0800 |
| commit | 8cf8b2406d4be014d466a9318303a65c5c7ff076 (patch) | |
| tree | fcabea0e4f5800c0bb49a9961951480ec75af2d1 | |
| parent | b9e467bdfe44e51a8b633040d9fe9cd43c581d36 (diff) | |
feat: add nRF54LM20A support
Signed-off-by: Haobo Gu <[email protected]>
| -rw-r--r-- | embassy-nrf/CHANGELOG.md | 1 | ||||
| -rw-r--r-- | embassy-nrf/Cargo.toml | 5 | ||||
| -rw-r--r-- | embassy-nrf/src/chips/nrf54lm20_app.rs | 841 | ||||
| -rw-r--r-- | embassy-nrf/src/gpiote.rs | 8 | ||||
| -rw-r--r-- | embassy-nrf/src/lib.rs | 3 | ||||
| -rw-r--r-- | embassy-nrf/src/saadc.rs | 1 | ||||
| -rw-r--r-- | examples/nrf54lm20/.cargo/config.toml | 10 | ||||
| -rw-r--r-- | examples/nrf54lm20/Cargo.toml | 37 | ||||
| -rw-r--r-- | examples/nrf54lm20/build.rs | 35 | ||||
| -rw-r--r-- | examples/nrf54lm20/memory.x | 5 | ||||
| -rwxr-xr-x | examples/nrf54lm20/run.sh | 15 | ||||
| -rw-r--r-- | examples/nrf54lm20/src/bin/blinky.rs | 23 | ||||
| -rw-r--r-- | examples/nrf54lm20/src/bin/gpio.rs | 23 | ||||
| -rw-r--r-- | examples/nrf54lm20/src/bin/gpiote_channel.rs | 49 | ||||
| -rw-r--r-- | examples/nrf54lm20/src/bin/gpiote_port.rs | 33 | ||||
| -rw-r--r-- | examples/nrf54lm20/src/bin/timer.rs | 30 |
16 files changed, 1117 insertions, 2 deletions
diff --git a/embassy-nrf/CHANGELOG.md b/embassy-nrf/CHANGELOG.md index 2524464b0..9c53e66a7 100644 --- a/embassy-nrf/CHANGELOG.md +++ b/embassy-nrf/CHANGELOG.md | |||
| @@ -31,6 +31,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 | |||
| 31 | - added: add basic GRTC time driver support for nRF54L | 31 | - added: add basic GRTC time driver support for nRF54L |
| 32 | * added: support for nrf54l10 and nrf54l05 | 32 | * added: support for nrf54l10 and nrf54l05 |
| 33 | * added: expose uicr write functions | 33 | * added: expose uicr write functions |
| 34 | * added: support for nrf54lm20a | ||
| 34 | 35 | ||
| 35 | ## 0.8.0 - 2025-09-30 | 36 | ## 0.8.0 - 2025-09-30 |
| 36 | 37 | ||
diff --git a/embassy-nrf/Cargo.toml b/embassy-nrf/Cargo.toml index c51af59d2..ee070f0c0 100644 --- a/embassy-nrf/Cargo.toml +++ b/embassy-nrf/Cargo.toml | |||
| @@ -29,6 +29,7 @@ build = [ | |||
| 29 | {target = "thumbv8m.main-none-eabihf", features = ["gpiote", "nrf54l10-app-ns", "time", "time-driver-grtc"]}, | 29 | {target = "thumbv8m.main-none-eabihf", features = ["gpiote", "nrf54l10-app-ns", "time", "time-driver-grtc"]}, |
| 30 | {target = "thumbv8m.main-none-eabihf", features = ["gpiote", "nrf54l05-app-s", "time", "time-driver-grtc"]}, | 30 | {target = "thumbv8m.main-none-eabihf", features = ["gpiote", "nrf54l05-app-s", "time", "time-driver-grtc"]}, |
| 31 | {target = "thumbv8m.main-none-eabihf", features = ["gpiote", "nrf54l05-app-ns", "time", "time-driver-grtc"]}, | 31 | {target = "thumbv8m.main-none-eabihf", features = ["gpiote", "nrf54l05-app-ns", "time", "time-driver-grtc"]}, |
| 32 | {target = "thumbv8m.main-none-eabihf", features = ["gpiote", "nrf54lm20-app-s", "time", "time-driver-grtc"]}, | ||
| 32 | {target = "thumbv7em-none-eabi", features = ["gpiote", "nrf52840", "time"]}, | 33 | {target = "thumbv7em-none-eabi", features = ["gpiote", "nrf52840", "time"]}, |
| 33 | {target = "thumbv7em-none-eabi", features = ["gpiote", "nrf52840", "time-driver-rtc1"]}, | 34 | {target = "thumbv7em-none-eabi", features = ["gpiote", "nrf52840", "time-driver-rtc1"]}, |
| 34 | {target = "thumbv7em-none-eabi", features = ["gpiote", "nrf52840", "time", "time-driver-rtc1"]}, | 35 | {target = "thumbv7em-none-eabi", features = ["gpiote", "nrf52840", "time", "time-driver-rtc1"]}, |
| @@ -142,6 +143,8 @@ nrf54l10-app-ns = ["_nrf54l10-app", "_ns"] | |||
| 142 | nrf54l05-app-s = ["_nrf54l05-app", "_s", "_multi_wdt"] | 143 | nrf54l05-app-s = ["_nrf54l05-app", "_s", "_multi_wdt"] |
| 143 | ## nRF54L05 application core in Non-Secure mode | 144 | ## nRF54L05 application core in Non-Secure mode |
| 144 | nrf54l05-app-ns = ["_nrf54l05-app", "_ns"] | 145 | nrf54l05-app-ns = ["_nrf54l05-app", "_ns"] |
| 146 | ## nRF54LM20 application core in Secure mode | ||
| 147 | nrf54lm20-app-s = ["_nrf54lm20-app", "_s", "_multi_wdt"] | ||
| 145 | 148 | ||
| 146 | ## nRF9160 in Secure mode | 149 | ## nRF9160 in Secure mode |
| 147 | nrf9160-s = ["_nrf9160", "_s", "_nrf91"] | 150 | nrf9160-s = ["_nrf9160", "_s", "_nrf91"] |
| @@ -169,6 +172,8 @@ _nrf54l10-app = ["_nrf54l10", "nrf-pac/nrf54l10-app"] | |||
| 169 | _nrf54l10 = ["_nrf54l", "_gpio-p1", "_gpio-p2"] | 172 | _nrf54l10 = ["_nrf54l", "_gpio-p1", "_gpio-p2"] |
| 170 | _nrf54l05-app = ["_nrf54l05", "nrf-pac/nrf54l05-app"] | 173 | _nrf54l05-app = ["_nrf54l05", "nrf-pac/nrf54l05-app"] |
| 171 | _nrf54l05 = ["_nrf54l", "_gpio-p1", "_gpio-p2"] | 174 | _nrf54l05 = ["_nrf54l", "_gpio-p1", "_gpio-p2"] |
| 175 | _nrf54lm20-app = ["_nrf54lm20", "nrf-pac/nrf54lm20a-app"] | ||
| 176 | _nrf54lm20 = ["_nrf54l", "_gpio-p1", "_gpio-p2"] | ||
| 172 | _nrf54l = ["_dppi", "_grtc"] | 177 | _nrf54l = ["_dppi", "_grtc"] |
| 173 | 178 | ||
| 174 | _nrf9160 = ["nrf-pac/nrf9160", "_dppi", "_spi-v1"] | 179 | _nrf9160 = ["nrf-pac/nrf9160", "_dppi", "_spi-v1"] |
diff --git a/embassy-nrf/src/chips/nrf54lm20_app.rs b/embassy-nrf/src/chips/nrf54lm20_app.rs new file mode 100644 index 000000000..c5fdf02e4 --- /dev/null +++ b/embassy-nrf/src/chips/nrf54lm20_app.rs | |||
| @@ -0,0 +1,841 @@ | |||
| 1 | /// Peripheral Access Crate | ||
| 2 | #[allow(unused_imports)] | ||
| 3 | #[rustfmt::skip] | ||
| 4 | pub mod pac { | ||
| 5 | pub use nrf_pac::*; | ||
| 6 | |||
| 7 | #[cfg(feature = "_ns")] | ||
| 8 | #[doc(no_inline)] | ||
| 9 | pub use nrf_pac::{ | ||
| 10 | FICR_NS as FICR, | ||
| 11 | DPPIC00_NS as DPPIC00, | ||
| 12 | PPIB00_NS as PPIB00, | ||
| 13 | PPIB01_NS as PPIB01, | ||
| 14 | AAR00_NS as AAR00, | ||
| 15 | CCM00_NS as CCM00, | ||
| 16 | ECB00_NS as ECB00, | ||
| 17 | SPIM00_NS as SPIM00, | ||
| 18 | SPIS00_NS as SPIS00, | ||
| 19 | UARTE00_NS as UARTE00, | ||
| 20 | VPR00_NS as VPR00, | ||
| 21 | P2_NS as P2, | ||
| 22 | CTRLAP_NS as CTRLAP, | ||
| 23 | TAD_NS as TAD, | ||
| 24 | TIMER00_NS as TIMER00, | ||
| 25 | DPPIC10_NS as DPPIC10, | ||
| 26 | PPIB10_NS as PPIB10, | ||
| 27 | PPIB11_NS as PPIB11, | ||
| 28 | TIMER10_NS as TIMER10, | ||
| 29 | EGU10_NS as EGU10, | ||
| 30 | RADIO_NS as RADIO, | ||
| 31 | DPPIC20_NS as DPPIC20, | ||
| 32 | PPIB20_NS as PPIB20, | ||
| 33 | PPIB21_NS as PPIB21, | ||
| 34 | PPIB22_NS as PPIB22, | ||
| 35 | SPIM20_NS as SPIM20, | ||
| 36 | SPIS20_NS as SPIS20, | ||
| 37 | TWIM20_NS as TWIM20, | ||
| 38 | TWIS20_NS as TWIS20, | ||
| 39 | UARTE20_NS as UARTE20, | ||
| 40 | SPIM21_NS as SPIM21, | ||
| 41 | SPIS21_NS as SPIS21, | ||
| 42 | TWIM21_NS as TWIM21, | ||
| 43 | TWIS21_NS as TWIS21, | ||
| 44 | UARTE21_NS as UARTE21, | ||
| 45 | SPIM22_NS as SPIM22, | ||
| 46 | SPIS22_NS as SPIS22, | ||
| 47 | TWIM22_NS as TWIM22, | ||
| 48 | TWIS22_NS as TWIS22, | ||
| 49 | UARTE22_NS as UARTE22, | ||
| 50 | EGU20_NS as EGU20, | ||
| 51 | TIMER20_NS as TIMER20, | ||
| 52 | TIMER21_NS as TIMER21, | ||
| 53 | TIMER22_NS as TIMER22, | ||
| 54 | TIMER23_NS as TIMER23, | ||
| 55 | TIMER24_NS as TIMER24, | ||
| 56 | MEMCONF_NS as MEMCONF, | ||
| 57 | PDM20_NS as PDM20, | ||
| 58 | PDM21_NS as PDM21, | ||
| 59 | PWM20_NS as PWM20, | ||
| 60 | PWM21_NS as PWM21, | ||
| 61 | PWM22_NS as PWM22, | ||
| 62 | SAADC_NS as SAADC, | ||
| 63 | NFCT_NS as NFCT, | ||
| 64 | TEMP_NS as TEMP, | ||
| 65 | P1_NS as P1, | ||
| 66 | GPIOTE20_NS as GPIOTE20, | ||
| 67 | I2S20_NS as I2S20, | ||
| 68 | QDEC20_NS as QDEC20, | ||
| 69 | QDEC21_NS as QDEC21, | ||
| 70 | GRTC_NS as GRTC, | ||
| 71 | DPPIC30_NS as DPPIC30, | ||
| 72 | PPIB30_NS as PPIB30, | ||
| 73 | SPIM30_NS as SPIM30, | ||
| 74 | SPIS30_NS as SPIS30, | ||
| 75 | TWIM30_NS as TWIM30, | ||
| 76 | TWIS30_NS as TWIS30, | ||
| 77 | UARTE30_NS as UARTE30, | ||
| 78 | COMP_NS as COMP, | ||
| 79 | LPCOMP_NS as LPCOMP, | ||
| 80 | WDT31_NS as WDT31, | ||
| 81 | P0_NS as P0, | ||
| 82 | GPIOTE30_NS as GPIOTE30, | ||
| 83 | CLOCK_NS as CLOCK, | ||
| 84 | POWER_NS as POWER, | ||
| 85 | RESET_NS as RESET, | ||
| 86 | OSCILLATORS_NS as OSCILLATORS, | ||
| 87 | REGULATORS_NS as REGULATORS, | ||
| 88 | TPIU_NS as TPIU, | ||
| 89 | ETM_NS as ETM, | ||
| 90 | }; | ||
| 91 | |||
| 92 | #[cfg(feature = "_s")] | ||
| 93 | #[doc(no_inline)] | ||
| 94 | pub use nrf_pac::{ | ||
| 95 | FICR_NS as FICR, | ||
| 96 | SICR_S as SICR, | ||
| 97 | ICACHEDATA_S as ICACHEDATA, | ||
| 98 | ICACHEINFO_S as ICACHEINFO, | ||
| 99 | SWI00_S as SWI00, | ||
| 100 | SWI01_S as SWI01, | ||
| 101 | SWI02_S as SWI02, | ||
| 102 | SWI03_S as SWI03, | ||
| 103 | SPU00_S as SPU00, | ||
| 104 | MPC00_S as MPC00, | ||
| 105 | DPPIC00_S as DPPIC00, | ||
| 106 | PPIB00_S as PPIB00, | ||
| 107 | PPIB01_S as PPIB01, | ||
| 108 | KMU_S as KMU, | ||
| 109 | AAR00_S as AAR00, | ||
| 110 | CCM00_S as CCM00, | ||
| 111 | ECB00_S as ECB00, | ||
| 112 | CRACEN_S as CRACEN, | ||
| 113 | SPIM00_S as SPIM00, | ||
| 114 | SPIS00_S as SPIS00, | ||
| 115 | UARTE00_S as UARTE00, | ||
| 116 | GLITCHDET_S as GLITCHDET, | ||
| 117 | RRAMC_S as RRAMC, | ||
| 118 | VPR00_S as VPR00, | ||
| 119 | P2_S as P2, | ||
| 120 | CTRLAP_S as CTRLAP, | ||
| 121 | TAD_S as TAD, | ||
| 122 | TIMER00_S as TIMER00, | ||
| 123 | SPU10_S as SPU10, | ||
| 124 | DPPIC10_S as DPPIC10, | ||
| 125 | PPIB10_S as PPIB10, | ||
| 126 | PPIB11_S as PPIB11, | ||
| 127 | TIMER10_S as TIMER10, | ||
| 128 | EGU10_S as EGU10, | ||
| 129 | RADIO_S as RADIO, | ||
| 130 | SPU20_S as SPU20, | ||
| 131 | DPPIC20_S as DPPIC20, | ||
| 132 | PPIB20_S as PPIB20, | ||
| 133 | PPIB21_S as PPIB21, | ||
| 134 | PPIB22_S as PPIB22, | ||
| 135 | SPIM20_S as SPIM20, | ||
| 136 | SPIS20_S as SPIS20, | ||
| 137 | TWIM20_S as TWIM20, | ||
| 138 | TWIS20_S as TWIS20, | ||
| 139 | UARTE20_S as UARTE20, | ||
| 140 | SPIM21_S as SPIM21, | ||
| 141 | SPIS21_S as SPIS21, | ||
| 142 | TWIM21_S as TWIM21, | ||
| 143 | TWIS21_S as TWIS21, | ||
| 144 | UARTE21_S as UARTE21, | ||
| 145 | SPIM22_S as SPIM22, | ||
| 146 | SPIS22_S as SPIS22, | ||
| 147 | TWIM22_S as TWIM22, | ||
| 148 | TWIS22_S as TWIS22, | ||
| 149 | UARTE22_S as UARTE22, | ||
| 150 | EGU20_S as EGU20, | ||
| 151 | TIMER20_S as TIMER20, | ||
| 152 | TIMER21_S as TIMER21, | ||
| 153 | TIMER22_S as TIMER22, | ||
| 154 | TIMER23_S as TIMER23, | ||
| 155 | TIMER24_S as TIMER24, | ||
| 156 | MEMCONF_S as MEMCONF, | ||
| 157 | PDM20_S as PDM20, | ||
| 158 | PDM21_S as PDM21, | ||
| 159 | PWM20_S as PWM20, | ||
| 160 | PWM21_S as PWM21, | ||
| 161 | PWM22_S as PWM22, | ||
| 162 | SAADC_S as SAADC, | ||
| 163 | NFCT_S as NFCT, | ||
| 164 | TEMP_S as TEMP, | ||
| 165 | P1_S as P1, | ||
| 166 | GPIOTE20_S as GPIOTE20, | ||
| 167 | TAMPC_S as TAMPC, | ||
| 168 | QDEC20_S as QDEC20, | ||
| 169 | QDEC21_S as QDEC21, | ||
| 170 | GRTC_S as GRTC, | ||
| 171 | SPU30_S as SPU30, | ||
| 172 | DPPIC30_S as DPPIC30, | ||
| 173 | PPIB30_S as PPIB30, | ||
| 174 | SPIM30_S as SPIM30, | ||
| 175 | SPIS30_S as SPIS30, | ||
| 176 | TWIM30_S as TWIM30, | ||
| 177 | TWIS30_S as TWIS30, | ||
| 178 | UARTE30_S as UARTE30, | ||
| 179 | COMP_S as COMP, | ||
| 180 | LPCOMP_S as LPCOMP, | ||
| 181 | WDT30_S as WDT30, | ||
| 182 | WDT31_S as WDT31, | ||
| 183 | P0_S as P0, | ||
| 184 | GPIOTE30_S as GPIOTE30, | ||
| 185 | CLOCK_S as CLOCK, | ||
| 186 | POWER_S as POWER, | ||
| 187 | RESET_S as RESET, | ||
| 188 | OSCILLATORS_S as OSCILLATORS, | ||
| 189 | REGULATORS_S as REGULATORS, | ||
| 190 | CRACENCORE_S as CRACENCORE, | ||
| 191 | CPUC_S as CPUC, | ||
| 192 | ICACHE_S as ICACHE, | ||
| 193 | }; | ||
| 194 | } | ||
| 195 | |||
| 196 | /// The maximum buffer size that the EasyDMA can send/recv in one operation. | ||
| 197 | pub const EASY_DMA_SIZE: usize = (1 << 16) - 1; | ||
| 198 | pub const FORCE_COPY_BUFFER_SIZE: usize = 1024; | ||
| 199 | |||
| 200 | // 2 MB NVM | ||
| 201 | #[allow(unused)] | ||
| 202 | pub const FLASH_SIZE: usize = 2048 * 1024; | ||
| 203 | |||
| 204 | embassy_hal_internal::peripherals! { | ||
| 205 | // PPI | ||
| 206 | PPI00_CH0, | ||
| 207 | PPI00_CH1, | ||
| 208 | PPI00_CH2, | ||
| 209 | PPI00_CH3, | ||
| 210 | PPI00_CH4, | ||
| 211 | PPI00_CH5, | ||
| 212 | PPI00_CH6, | ||
| 213 | PPI00_CH7, | ||
| 214 | |||
| 215 | PPI10_CH0, | ||
| 216 | PPI10_CH1, | ||
| 217 | PPI10_CH2, | ||
| 218 | PPI10_CH3, | ||
| 219 | PPI10_CH4, | ||
| 220 | PPI10_CH5, | ||
| 221 | PPI10_CH6, | ||
| 222 | PPI10_CH7, | ||
| 223 | PPI10_CH8, | ||
| 224 | PPI10_CH9, | ||
| 225 | PPI10_CH10, | ||
| 226 | PPI10_CH11, | ||
| 227 | PPI10_CH12, | ||
| 228 | PPI10_CH13, | ||
| 229 | PPI10_CH14, | ||
| 230 | PPI10_CH15, | ||
| 231 | PPI10_CH16, | ||
| 232 | PPI10_CH17, | ||
| 233 | PPI10_CH18, | ||
| 234 | PPI10_CH19, | ||
| 235 | PPI10_CH20, | ||
| 236 | PPI10_CH21, | ||
| 237 | PPI10_CH22, | ||
| 238 | PPI10_CH23, | ||
| 239 | |||
| 240 | PPI20_CH0, | ||
| 241 | PPI20_CH1, | ||
| 242 | PPI20_CH2, | ||
| 243 | PPI20_CH3, | ||
| 244 | PPI20_CH4, | ||
| 245 | PPI20_CH5, | ||
| 246 | PPI20_CH6, | ||
| 247 | PPI20_CH7, | ||
| 248 | PPI20_CH8, | ||
| 249 | PPI20_CH9, | ||
| 250 | PPI20_CH10, | ||
| 251 | PPI20_CH11, | ||
| 252 | PPI20_CH12, | ||
| 253 | PPI20_CH13, | ||
| 254 | PPI20_CH14, | ||
| 255 | PPI20_CH15, | ||
| 256 | |||
| 257 | PPI30_CH0, | ||
| 258 | PPI30_CH1, | ||
| 259 | PPI30_CH2, | ||
| 260 | PPI30_CH3, | ||
| 261 | |||
| 262 | PPI00_GROUP0, | ||
| 263 | PPI00_GROUP1, | ||
| 264 | |||
| 265 | PPI10_GROUP0, | ||
| 266 | PPI10_GROUP1, | ||
| 267 | PPI10_GROUP2, | ||
| 268 | PPI10_GROUP3, | ||
| 269 | PPI10_GROUP4, | ||
| 270 | PPI10_GROUP5, | ||
| 271 | |||
| 272 | PPI20_GROUP0, | ||
| 273 | PPI20_GROUP1, | ||
| 274 | PPI20_GROUP2, | ||
| 275 | PPI20_GROUP3, | ||
| 276 | PPI20_GROUP4, | ||
| 277 | PPI20_GROUP5, | ||
| 278 | |||
| 279 | PPI30_GROUP0, | ||
| 280 | PPI30_GROUP1, | ||
| 281 | |||
| 282 | // PPI BRIDGE channels | ||
| 283 | PPIB00_CH0, | ||
| 284 | PPIB00_CH1, | ||
| 285 | PPIB00_CH2, | ||
| 286 | PPIB00_CH3, | ||
| 287 | PPIB00_CH4, | ||
| 288 | PPIB00_CH5, | ||
| 289 | PPIB00_CH6, | ||
| 290 | PPIB00_CH7, | ||
| 291 | |||
| 292 | PPIB01_CH0, | ||
| 293 | PPIB01_CH1, | ||
| 294 | PPIB01_CH2, | ||
| 295 | PPIB01_CH3, | ||
| 296 | PPIB01_CH4, | ||
| 297 | PPIB01_CH5, | ||
| 298 | PPIB01_CH6, | ||
| 299 | PPIB01_CH7, | ||
| 300 | |||
| 301 | PPIB10_CH0, | ||
| 302 | PPIB10_CH1, | ||
| 303 | PPIB10_CH2, | ||
| 304 | PPIB10_CH3, | ||
| 305 | PPIB10_CH4, | ||
| 306 | PPIB10_CH5, | ||
| 307 | PPIB10_CH6, | ||
| 308 | PPIB10_CH7, | ||
| 309 | |||
| 310 | PPIB11_CH0, | ||
| 311 | PPIB11_CH1, | ||
| 312 | PPIB11_CH2, | ||
| 313 | PPIB11_CH3, | ||
| 314 | PPIB11_CH4, | ||
| 315 | PPIB11_CH5, | ||
| 316 | PPIB11_CH6, | ||
| 317 | PPIB11_CH7, | ||
| 318 | PPIB11_CH8, | ||
| 319 | PPIB11_CH9, | ||
| 320 | PPIB11_CH10, | ||
| 321 | PPIB11_CH11, | ||
| 322 | PPIB11_CH12, | ||
| 323 | PPIB11_CH13, | ||
| 324 | PPIB11_CH14, | ||
| 325 | PPIB11_CH15, | ||
| 326 | |||
| 327 | PPIB20_CH0, | ||
| 328 | PPIB20_CH1, | ||
| 329 | PPIB20_CH2, | ||
| 330 | PPIB20_CH3, | ||
| 331 | PPIB20_CH4, | ||
| 332 | PPIB20_CH5, | ||
| 333 | PPIB20_CH6, | ||
| 334 | PPIB20_CH7, | ||
| 335 | |||
| 336 | PPIB21_CH0, | ||
| 337 | PPIB21_CH1, | ||
| 338 | PPIB21_CH2, | ||
| 339 | PPIB21_CH3, | ||
| 340 | PPIB21_CH4, | ||
| 341 | PPIB21_CH5, | ||
| 342 | PPIB21_CH6, | ||
| 343 | PPIB21_CH7, | ||
| 344 | PPIB21_CH8, | ||
| 345 | PPIB21_CH9, | ||
| 346 | PPIB21_CH10, | ||
| 347 | PPIB21_CH11, | ||
| 348 | PPIB21_CH12, | ||
| 349 | PPIB21_CH13, | ||
| 350 | PPIB21_CH14, | ||
| 351 | PPIB21_CH15, | ||
| 352 | |||
| 353 | PPIB22_CH0, | ||
| 354 | PPIB22_CH1, | ||
| 355 | PPIB22_CH2, | ||
| 356 | PPIB22_CH3, | ||
| 357 | |||
| 358 | PPIB30_CH0, | ||
| 359 | PPIB30_CH1, | ||
| 360 | PPIB30_CH2, | ||
| 361 | PPIB30_CH3, | ||
| 362 | |||
| 363 | // Timers | ||
| 364 | TIMER00, | ||
| 365 | TIMER10, | ||
| 366 | TIMER20, | ||
| 367 | TIMER21, | ||
| 368 | TIMER22, | ||
| 369 | TIMER23, | ||
| 370 | TIMER24, | ||
| 371 | |||
| 372 | // GPIO port 0 | ||
| 373 | P0_00, | ||
| 374 | P0_01, | ||
| 375 | P0_02, | ||
| 376 | P0_03, | ||
| 377 | P0_04, | ||
| 378 | P0_05, | ||
| 379 | P0_06, | ||
| 380 | P0_07, | ||
| 381 | P0_08, | ||
| 382 | P0_09, | ||
| 383 | |||
| 384 | // GPIO port 1 | ||
| 385 | P1_00, | ||
| 386 | P1_01, | ||
| 387 | P1_02, | ||
| 388 | P1_03, | ||
| 389 | P1_04, | ||
| 390 | P1_05, | ||
| 391 | P1_06, | ||
| 392 | P1_07, | ||
| 393 | P1_08, | ||
| 394 | P1_09, | ||
| 395 | P1_10, | ||
| 396 | P1_11, | ||
| 397 | P1_12, | ||
| 398 | P1_13, | ||
| 399 | P1_14, | ||
| 400 | P1_15, | ||
| 401 | P1_16, | ||
| 402 | P1_17, | ||
| 403 | P1_18, | ||
| 404 | P1_19, | ||
| 405 | P1_20, | ||
| 406 | P1_21, | ||
| 407 | P1_22, | ||
| 408 | P1_23, | ||
| 409 | P1_24, | ||
| 410 | P1_25, | ||
| 411 | P1_26, | ||
| 412 | P1_27, | ||
| 413 | P1_28, | ||
| 414 | P1_29, | ||
| 415 | P1_30, | ||
| 416 | P1_31, | ||
| 417 | |||
| 418 | |||
| 419 | // GPIO port 2 | ||
| 420 | P2_00, | ||
| 421 | P2_01, | ||
| 422 | P2_02, | ||
| 423 | P2_03, | ||
| 424 | P2_04, | ||
| 425 | P2_05, | ||
| 426 | P2_06, | ||
| 427 | P2_07, | ||
| 428 | P2_08, | ||
| 429 | P2_09, | ||
| 430 | P2_10, | ||
| 431 | |||
| 432 | // GPIO port 3 | ||
| 433 | P3_00, | ||
| 434 | P3_01, | ||
| 435 | P3_02, | ||
| 436 | P3_03, | ||
| 437 | P3_04, | ||
| 438 | P3_05, | ||
| 439 | P3_06, | ||
| 440 | P3_07, | ||
| 441 | P3_08, | ||
| 442 | P3_09, | ||
| 443 | P3_10, | ||
| 444 | P3_11, | ||
| 445 | P3_12, | ||
| 446 | |||
| 447 | // GRTC | ||
| 448 | GRTC_CH0, | ||
| 449 | #[cfg(not(feature = "time-driver-grtc"))] | ||
| 450 | GRTC_CH1, | ||
| 451 | GRTC_CH2, | ||
| 452 | GRTC_CH3, | ||
| 453 | GRTC_CH4, | ||
| 454 | GRTC_CH5, | ||
| 455 | GRTC_CH6, | ||
| 456 | GRTC_CH7, | ||
| 457 | GRTC_CH8, | ||
| 458 | GRTC_CH9, | ||
| 459 | GRTC_CH10, | ||
| 460 | GRTC_CH11, | ||
| 461 | |||
| 462 | // PWM | ||
| 463 | PWM20, | ||
| 464 | PWM21, | ||
| 465 | PWM22, | ||
| 466 | |||
| 467 | // SERIAL | ||
| 468 | SERIAL00, | ||
| 469 | SERIAL20, | ||
| 470 | SERIAL21, | ||
| 471 | SERIAL22, | ||
| 472 | SERIAL30, | ||
| 473 | |||
| 474 | // SAADC | ||
| 475 | SAADC, | ||
| 476 | |||
| 477 | // RADIO | ||
| 478 | RADIO, | ||
| 479 | |||
| 480 | |||
| 481 | // GPIOTE instances | ||
| 482 | GPIOTE20, | ||
| 483 | GPIOTE30, | ||
| 484 | |||
| 485 | // GPIOTE channels | ||
| 486 | GPIOTE20_CH0, | ||
| 487 | GPIOTE20_CH1, | ||
| 488 | GPIOTE20_CH2, | ||
| 489 | GPIOTE20_CH3, | ||
| 490 | GPIOTE20_CH4, | ||
| 491 | GPIOTE20_CH5, | ||
| 492 | GPIOTE20_CH6, | ||
| 493 | GPIOTE20_CH7, | ||
| 494 | GPIOTE30_CH0, | ||
| 495 | GPIOTE30_CH1, | ||
| 496 | GPIOTE30_CH2, | ||
| 497 | GPIOTE30_CH3, | ||
| 498 | |||
| 499 | // CRACEN | ||
| 500 | #[cfg(feature = "_s")] | ||
| 501 | CRACEN, | ||
| 502 | |||
| 503 | #[cfg(feature = "_s")] | ||
| 504 | // RRAMC | ||
| 505 | RRAMC, | ||
| 506 | |||
| 507 | // TEMP | ||
| 508 | TEMP, | ||
| 509 | |||
| 510 | // WDT | ||
| 511 | #[cfg(feature = "_ns")] | ||
| 512 | WDT, | ||
| 513 | #[cfg(feature = "_s")] | ||
| 514 | WDT0, | ||
| 515 | #[cfg(feature = "_s")] | ||
| 516 | WDT1, | ||
| 517 | } | ||
| 518 | |||
| 519 | impl_pin!(P0_00, 0, 0); | ||
| 520 | impl_pin!(P0_01, 0, 1); | ||
| 521 | impl_pin!(P0_02, 0, 2); | ||
| 522 | impl_pin!(P0_03, 0, 3); | ||
| 523 | impl_pin!(P0_04, 0, 4); | ||
| 524 | impl_pin!(P0_05, 0, 5); | ||
| 525 | impl_pin!(P0_06, 0, 6); | ||
| 526 | impl_pin!(P0_07, 0, 7); | ||
| 527 | impl_pin!(P0_08, 0, 8); | ||
| 528 | impl_pin!(P0_09, 0, 9); | ||
| 529 | |||
| 530 | impl_pin!(P1_00, 1, 0); | ||
| 531 | impl_pin!(P1_01, 1, 1); | ||
| 532 | impl_pin!(P1_02, 1, 2); | ||
| 533 | impl_pin!(P1_03, 1, 3); | ||
| 534 | impl_pin!(P1_04, 1, 4); | ||
| 535 | impl_pin!(P1_05, 1, 5); | ||
| 536 | impl_pin!(P1_06, 1, 6); | ||
| 537 | impl_pin!(P1_07, 1, 7); | ||
| 538 | impl_pin!(P1_08, 1, 8); | ||
| 539 | impl_pin!(P1_09, 1, 9); | ||
| 540 | impl_pin!(P1_10, 1, 10); | ||
| 541 | impl_pin!(P1_11, 1, 11); | ||
| 542 | impl_pin!(P1_12, 1, 12); | ||
| 543 | impl_pin!(P1_13, 1, 13); | ||
| 544 | impl_pin!(P1_14, 1, 14); | ||
| 545 | impl_pin!(P1_15, 1, 15); | ||
| 546 | impl_pin!(P1_16, 1, 16); | ||
| 547 | impl_pin!(P1_17, 1, 17); | ||
| 548 | impl_pin!(P1_18, 1, 18); | ||
| 549 | impl_pin!(P1_19, 1, 19); | ||
| 550 | impl_pin!(P1_20, 1, 20); | ||
| 551 | impl_pin!(P1_21, 1, 21); | ||
| 552 | impl_pin!(P1_22, 1, 22); | ||
| 553 | impl_pin!(P1_23, 1, 23); | ||
| 554 | impl_pin!(P1_24, 1, 24); | ||
| 555 | impl_pin!(P1_25, 1, 25); | ||
| 556 | impl_pin!(P1_26, 1, 26); | ||
| 557 | impl_pin!(P1_27, 1, 27); | ||
| 558 | impl_pin!(P1_28, 1, 28); | ||
| 559 | impl_pin!(P1_29, 1, 29); | ||
| 560 | impl_pin!(P1_30, 1, 30); | ||
| 561 | impl_pin!(P1_31, 1, 31); | ||
| 562 | |||
| 563 | impl_pin!(P2_00, 2, 0); | ||
| 564 | impl_pin!(P2_01, 2, 1); | ||
| 565 | impl_pin!(P2_02, 2, 2); | ||
| 566 | impl_pin!(P2_03, 2, 3); | ||
| 567 | impl_pin!(P2_04, 2, 4); | ||
| 568 | impl_pin!(P2_05, 2, 5); | ||
| 569 | impl_pin!(P2_06, 2, 6); | ||
| 570 | impl_pin!(P2_07, 2, 7); | ||
| 571 | impl_pin!(P2_08, 2, 8); | ||
| 572 | impl_pin!(P2_09, 2, 9); | ||
| 573 | impl_pin!(P2_10, 2, 10); | ||
| 574 | |||
| 575 | impl_pin!(P3_00, 3, 0); | ||
| 576 | impl_pin!(P3_01, 3, 1); | ||
| 577 | impl_pin!(P3_02, 3, 2); | ||
| 578 | impl_pin!(P3_03, 3, 3); | ||
| 579 | impl_pin!(P3_04, 3, 4); | ||
| 580 | impl_pin!(P3_05, 3, 5); | ||
| 581 | impl_pin!(P3_06, 3, 6); | ||
| 582 | impl_pin!(P3_07, 3, 7); | ||
| 583 | impl_pin!(P3_08, 3, 8); | ||
| 584 | impl_pin!(P3_09, 3, 9); | ||
| 585 | impl_pin!(P3_10, 3, 10); | ||
| 586 | impl_pin!(P3_11, 3, 11); | ||
| 587 | impl_pin!(P3_12, 3, 12); | ||
| 588 | |||
| 589 | cfg_if::cfg_if! { | ||
| 590 | if #[cfg(feature = "gpiote")] { | ||
| 591 | impl_gpiote_pin!(P0_00, GPIOTE30); | ||
| 592 | impl_gpiote_pin!(P0_01, GPIOTE30); | ||
| 593 | impl_gpiote_pin!(P0_02, GPIOTE30); | ||
| 594 | impl_gpiote_pin!(P0_03, GPIOTE30); | ||
| 595 | impl_gpiote_pin!(P0_04, GPIOTE30); | ||
| 596 | impl_gpiote_pin!(P0_05, GPIOTE30); | ||
| 597 | impl_gpiote_pin!(P0_06, GPIOTE30); | ||
| 598 | impl_gpiote_pin!(P0_07, GPIOTE30); | ||
| 599 | impl_gpiote_pin!(P0_08, GPIOTE30); | ||
| 600 | impl_gpiote_pin!(P0_09, GPIOTE30); | ||
| 601 | |||
| 602 | impl_gpiote_pin!(P1_00, GPIOTE20); | ||
| 603 | impl_gpiote_pin!(P1_01, GPIOTE20); | ||
| 604 | impl_gpiote_pin!(P1_02, GPIOTE20); | ||
| 605 | impl_gpiote_pin!(P1_03, GPIOTE20); | ||
| 606 | impl_gpiote_pin!(P1_04, GPIOTE20); | ||
| 607 | impl_gpiote_pin!(P1_05, GPIOTE20); | ||
| 608 | impl_gpiote_pin!(P1_06, GPIOTE20); | ||
| 609 | impl_gpiote_pin!(P1_07, GPIOTE20); | ||
| 610 | impl_gpiote_pin!(P1_08, GPIOTE20); | ||
| 611 | impl_gpiote_pin!(P1_09, GPIOTE20); | ||
| 612 | impl_gpiote_pin!(P1_10, GPIOTE20); | ||
| 613 | impl_gpiote_pin!(P1_11, GPIOTE20); | ||
| 614 | impl_gpiote_pin!(P1_12, GPIOTE20); | ||
| 615 | impl_gpiote_pin!(P1_13, GPIOTE20); | ||
| 616 | impl_gpiote_pin!(P1_14, GPIOTE20); | ||
| 617 | impl_gpiote_pin!(P1_15, GPIOTE20); | ||
| 618 | impl_gpiote_pin!(P1_16, GPIOTE20); | ||
| 619 | impl_gpiote_pin!(P1_17, GPIOTE20); | ||
| 620 | impl_gpiote_pin!(P1_18, GPIOTE20); | ||
| 621 | impl_gpiote_pin!(P1_19, GPIOTE20); | ||
| 622 | impl_gpiote_pin!(P1_20, GPIOTE20); | ||
| 623 | impl_gpiote_pin!(P1_21, GPIOTE20); | ||
| 624 | impl_gpiote_pin!(P1_22, GPIOTE20); | ||
| 625 | impl_gpiote_pin!(P1_23, GPIOTE20); | ||
| 626 | impl_gpiote_pin!(P1_24, GPIOTE20); | ||
| 627 | impl_gpiote_pin!(P1_25, GPIOTE20); | ||
| 628 | impl_gpiote_pin!(P1_26, GPIOTE20); | ||
| 629 | impl_gpiote_pin!(P1_27, GPIOTE20); | ||
| 630 | impl_gpiote_pin!(P1_28, GPIOTE20); | ||
| 631 | impl_gpiote_pin!(P1_29, GPIOTE20); | ||
| 632 | impl_gpiote_pin!(P1_30, GPIOTE20); | ||
| 633 | impl_gpiote_pin!(P1_31, GPIOTE20); | ||
| 634 | |||
| 635 | impl_gpiote_pin!(P3_00, GPIOTE20); | ||
| 636 | impl_gpiote_pin!(P3_01, GPIOTE20); | ||
| 637 | impl_gpiote_pin!(P3_02, GPIOTE20); | ||
| 638 | impl_gpiote_pin!(P3_03, GPIOTE20); | ||
| 639 | impl_gpiote_pin!(P3_04, GPIOTE20); | ||
| 640 | impl_gpiote_pin!(P3_05, GPIOTE20); | ||
| 641 | impl_gpiote_pin!(P3_06, GPIOTE20); | ||
| 642 | impl_gpiote_pin!(P3_07, GPIOTE20); | ||
| 643 | impl_gpiote_pin!(P3_08, GPIOTE20); | ||
| 644 | impl_gpiote_pin!(P3_09, GPIOTE20); | ||
| 645 | impl_gpiote_pin!(P3_10, GPIOTE20); | ||
| 646 | impl_gpiote_pin!(P3_11, GPIOTE20); | ||
| 647 | impl_gpiote_pin!(P3_12, GPIOTE20); | ||
| 648 | } | ||
| 649 | } | ||
| 650 | |||
| 651 | #[cfg(feature = "_ns")] | ||
| 652 | impl_wdt!(WDT, WDT31, WDT31, 0); | ||
| 653 | #[cfg(feature = "_s")] | ||
| 654 | impl_wdt!(WDT0, WDT31, WDT31, 0); | ||
| 655 | #[cfg(feature = "_s")] | ||
| 656 | impl_wdt!(WDT1, WDT30, WDT30, 1); | ||
| 657 | // DPPI00 channels | ||
| 658 | impl_ppi_channel!(PPI00_CH0, DPPIC00, 0 => configurable); | ||
| 659 | impl_ppi_channel!(PPI00_CH1, DPPIC00, 1 => configurable); | ||
| 660 | impl_ppi_channel!(PPI00_CH2, DPPIC00, 2 => configurable); | ||
| 661 | impl_ppi_channel!(PPI00_CH3, DPPIC00, 3 => configurable); | ||
| 662 | impl_ppi_channel!(PPI00_CH4, DPPIC00, 4 => configurable); | ||
| 663 | impl_ppi_channel!(PPI00_CH5, DPPIC00, 5 => configurable); | ||
| 664 | impl_ppi_channel!(PPI00_CH6, DPPIC00, 6 => configurable); | ||
| 665 | impl_ppi_channel!(PPI00_CH7, DPPIC00, 7 => configurable); | ||
| 666 | |||
| 667 | // DPPI10 channels | ||
| 668 | impl_ppi_channel!(PPI10_CH0, DPPIC10, 0 => static); | ||
| 669 | |||
| 670 | // DPPI20 channels | ||
| 671 | impl_ppi_channel!(PPI20_CH0, DPPIC20, 0 => configurable); | ||
| 672 | impl_ppi_channel!(PPI20_CH1, DPPIC20, 1 => configurable); | ||
| 673 | impl_ppi_channel!(PPI20_CH2, DPPIC20, 2 => configurable); | ||
| 674 | impl_ppi_channel!(PPI20_CH3, DPPIC20, 3 => configurable); | ||
| 675 | impl_ppi_channel!(PPI20_CH4, DPPIC20, 4 => configurable); | ||
| 676 | impl_ppi_channel!(PPI20_CH5, DPPIC20, 5 => configurable); | ||
| 677 | impl_ppi_channel!(PPI20_CH6, DPPIC20, 6 => configurable); | ||
| 678 | impl_ppi_channel!(PPI20_CH7, DPPIC20, 7 => configurable); | ||
| 679 | impl_ppi_channel!(PPI20_CH8, DPPIC20, 8 => configurable); | ||
| 680 | impl_ppi_channel!(PPI20_CH9, DPPIC20, 9 => configurable); | ||
| 681 | impl_ppi_channel!(PPI20_CH10, DPPIC20, 10 => configurable); | ||
| 682 | impl_ppi_channel!(PPI20_CH11, DPPIC20, 11 => configurable); | ||
| 683 | impl_ppi_channel!(PPI20_CH12, DPPIC20, 12 => configurable); | ||
| 684 | impl_ppi_channel!(PPI20_CH13, DPPIC20, 13 => configurable); | ||
| 685 | impl_ppi_channel!(PPI20_CH14, DPPIC20, 14 => configurable); | ||
| 686 | impl_ppi_channel!(PPI20_CH15, DPPIC20, 15 => configurable); | ||
| 687 | |||
| 688 | // DPPI30 channels | ||
| 689 | impl_ppi_channel!(PPI30_CH0, DPPIC30, 0 => configurable); | ||
| 690 | impl_ppi_channel!(PPI30_CH1, DPPIC30, 1 => configurable); | ||
| 691 | impl_ppi_channel!(PPI30_CH2, DPPIC30, 2 => configurable); | ||
| 692 | impl_ppi_channel!(PPI30_CH3, DPPIC30, 3 => configurable); | ||
| 693 | |||
| 694 | // DPPI00 groups | ||
| 695 | impl_ppi_group!(PPI00_GROUP0, DPPIC00, 0); | ||
| 696 | impl_ppi_group!(PPI00_GROUP1, DPPIC00, 1); | ||
| 697 | |||
| 698 | // DPPI10 groups | ||
| 699 | impl_ppi_group!(PPI10_GROUP0, DPPIC10, 0); | ||
| 700 | |||
| 701 | // DPPI20 groups | ||
| 702 | impl_ppi_group!(PPI20_GROUP0, DPPIC20, 0); | ||
| 703 | impl_ppi_group!(PPI20_GROUP1, DPPIC20, 1); | ||
| 704 | impl_ppi_group!(PPI20_GROUP2, DPPIC20, 2); | ||
| 705 | impl_ppi_group!(PPI20_GROUP3, DPPIC20, 3); | ||
| 706 | impl_ppi_group!(PPI20_GROUP4, DPPIC20, 4); | ||
| 707 | impl_ppi_group!(PPI20_GROUP5, DPPIC20, 5); | ||
| 708 | |||
| 709 | // DPPI30 groups | ||
| 710 | impl_ppi_group!(PPI30_GROUP0, DPPIC30, 0); | ||
| 711 | impl_ppi_group!(PPI30_GROUP1, DPPIC30, 1); | ||
| 712 | |||
| 713 | impl_timer!(TIMER00, TIMER00, TIMER00); | ||
| 714 | impl_timer!(TIMER10, TIMER10, TIMER10); | ||
| 715 | impl_timer!(TIMER20, TIMER20, TIMER20); | ||
| 716 | impl_timer!(TIMER21, TIMER21, TIMER21); | ||
| 717 | impl_timer!(TIMER22, TIMER22, TIMER22); | ||
| 718 | impl_timer!(TIMER23, TIMER23, TIMER23); | ||
| 719 | impl_timer!(TIMER24, TIMER24, TIMER24); | ||
| 720 | |||
| 721 | impl_twim!(SERIAL20, TWIM20, SERIAL20); | ||
| 722 | impl_twim!(SERIAL21, TWIM21, SERIAL21); | ||
| 723 | impl_twim!(SERIAL22, TWIM22, SERIAL22); | ||
| 724 | impl_twim!(SERIAL30, TWIM30, SERIAL30); | ||
| 725 | |||
| 726 | impl_twis!(SERIAL20, TWIS20, SERIAL20); | ||
| 727 | impl_twis!(SERIAL21, TWIS21, SERIAL21); | ||
| 728 | impl_twis!(SERIAL22, TWIS22, SERIAL22); | ||
| 729 | impl_twis!(SERIAL30, TWIS30, SERIAL30); | ||
| 730 | |||
| 731 | impl_pwm!(PWM20, PWM20, PWM20); | ||
| 732 | impl_pwm!(PWM21, PWM21, PWM21); | ||
| 733 | impl_pwm!(PWM22, PWM22, PWM22); | ||
| 734 | |||
| 735 | #[cfg(feature = "_s")] | ||
| 736 | impl_spim!( | ||
| 737 | SERIAL00, | ||
| 738 | SPIM00, | ||
| 739 | SERIAL00, | ||
| 740 | match pac::OSCILLATORS_S.pll().currentfreq().read().currentfreq() { | ||
| 741 | pac::oscillators::vals::Currentfreq::CK128M => 128_000_000, | ||
| 742 | pac::oscillators::vals::Currentfreq::CK64M => 64_000_000, | ||
| 743 | _ => unreachable!(), | ||
| 744 | } | ||
| 745 | ); | ||
| 746 | #[cfg(feature = "_ns")] | ||
| 747 | impl_spim!( | ||
| 748 | SERIAL00, | ||
| 749 | SPIM00, | ||
| 750 | SERIAL00, | ||
| 751 | match pac::OSCILLATORS_NS.pll().currentfreq().read().currentfreq() { | ||
| 752 | pac::oscillators::vals::Currentfreq::CK128M => 128_000_000, | ||
| 753 | pac::oscillators::vals::Currentfreq::CK64M => 64_000_000, | ||
| 754 | _ => unreachable!(), | ||
| 755 | } | ||
| 756 | ); | ||
| 757 | impl_spim!(SERIAL20, SPIM20, SERIAL20, 16_000_000); | ||
| 758 | impl_spim!(SERIAL21, SPIM21, SERIAL21, 16_000_000); | ||
| 759 | impl_spim!(SERIAL22, SPIM22, SERIAL22, 16_000_000); | ||
| 760 | impl_spim!(SERIAL30, SPIM30, SERIAL30, 16_000_000); | ||
| 761 | |||
| 762 | impl_spis!(SERIAL20, SPIS20, SERIAL20); | ||
| 763 | impl_spis!(SERIAL21, SPIS21, SERIAL21); | ||
| 764 | impl_spis!(SERIAL22, SPIS22, SERIAL22); | ||
| 765 | impl_spis!(SERIAL30, SPIS30, SERIAL30); | ||
| 766 | |||
| 767 | impl_uarte!(SERIAL00, UARTE00, SERIAL00); | ||
| 768 | impl_uarte!(SERIAL20, UARTE20, SERIAL20); | ||
| 769 | impl_uarte!(SERIAL21, UARTE21, SERIAL21); | ||
| 770 | impl_uarte!(SERIAL22, UARTE22, SERIAL22); | ||
| 771 | impl_uarte!(SERIAL30, UARTE30, SERIAL30); | ||
| 772 | |||
| 773 | // NB: SAADC uses "pin" abstraction, not "AIN" | ||
| 774 | impl_saadc_input!(P1_04, 1, 4); | ||
| 775 | impl_saadc_input!(P1_05, 1, 5); | ||
| 776 | impl_saadc_input!(P1_06, 1, 6); | ||
| 777 | impl_saadc_input!(P1_07, 1, 7); | ||
| 778 | impl_saadc_input!(P1_11, 1, 11); | ||
| 779 | impl_saadc_input!(P1_12, 1, 12); | ||
| 780 | impl_saadc_input!(P1_13, 1, 13); | ||
| 781 | impl_saadc_input!(P1_14, 1, 14); | ||
| 782 | |||
| 783 | #[cfg(feature = "_s")] | ||
| 784 | impl_cracen!(CRACEN, CRACEN, CRACEN); | ||
| 785 | |||
| 786 | embassy_hal_internal::interrupt_mod!( | ||
| 787 | SWI00, | ||
| 788 | SWI01, | ||
| 789 | SWI02, | ||
| 790 | SWI03, | ||
| 791 | SPU00, | ||
| 792 | MPC00, | ||
| 793 | AAR00_CCM00, | ||
| 794 | ECB00, | ||
| 795 | CRACEN, | ||
| 796 | SERIAL00, | ||
| 797 | RRAMC, | ||
| 798 | VPR00, | ||
| 799 | CTRLAP, | ||
| 800 | TIMER00, | ||
| 801 | SPU10, | ||
| 802 | TIMER10, | ||
| 803 | EGU10, | ||
| 804 | RADIO_0, | ||
| 805 | RADIO_1, | ||
| 806 | SPU20, | ||
| 807 | SERIAL20, | ||
| 808 | SERIAL21, | ||
| 809 | SERIAL22, | ||
| 810 | EGU20, | ||
| 811 | TIMER20, | ||
| 812 | TIMER21, | ||
| 813 | TIMER22, | ||
| 814 | TIMER23, | ||
| 815 | TIMER24, | ||
| 816 | PDM20, | ||
| 817 | PDM21, | ||
| 818 | PWM20, | ||
| 819 | PWM21, | ||
| 820 | PWM22, | ||
| 821 | SAADC, | ||
| 822 | NFCT, | ||
| 823 | TEMP, | ||
| 824 | GPIOTE20_0, | ||
| 825 | GPIOTE20_1, | ||
| 826 | TAMPC, | ||
| 827 | QDEC20, | ||
| 828 | QDEC21, | ||
| 829 | GRTC_0, | ||
| 830 | GRTC_1, | ||
| 831 | GRTC_2, | ||
| 832 | GRTC_3, | ||
| 833 | SPU30, | ||
| 834 | SERIAL30, | ||
| 835 | COMP_LPCOMP, | ||
| 836 | WDT30, | ||
| 837 | WDT31, | ||
| 838 | GPIOTE30_0, | ||
| 839 | GPIOTE30_1, | ||
| 840 | CLOCK_POWER, | ||
| 841 | ); | ||
diff --git a/embassy-nrf/src/gpiote.rs b/embassy-nrf/src/gpiote.rs index d4f6668f3..1f6000b13 100644 --- a/embassy-nrf/src/gpiote.rs +++ b/embassy-nrf/src/gpiote.rs | |||
| @@ -33,14 +33,18 @@ const CHANNELS_PER_PORT: usize = 8; | |||
| 33 | feature = "nrf52833", | 33 | feature = "nrf52833", |
| 34 | feature = "nrf52840", | 34 | feature = "nrf52840", |
| 35 | feature = "_nrf5340", | 35 | feature = "_nrf5340", |
| 36 | feature = "_nrf54l" | 36 | feature = "_nrf54l15", |
| 37 | feature = "_nrf54l10", | ||
| 38 | feature = "_nrf54l05" | ||
| 37 | ))] | 39 | ))] |
| 38 | const PIN_COUNT: usize = 48; | 40 | const PIN_COUNT: usize = 48; |
| 41 | #[cfg(feature = "_nrf54lm20")] | ||
| 42 | const PIN_COUNT: usize = 66; | ||
| 39 | #[cfg(not(any( | 43 | #[cfg(not(any( |
| 40 | feature = "nrf52833", | 44 | feature = "nrf52833", |
| 41 | feature = "nrf52840", | 45 | feature = "nrf52840", |
| 42 | feature = "_nrf5340", | 46 | feature = "_nrf5340", |
| 43 | feature = "_nrf54l" | 47 | feature = "_nrf54l", |
| 44 | )))] | 48 | )))] |
| 45 | const PIN_COUNT: usize = 32; | 49 | const PIN_COUNT: usize = 32; |
| 46 | 50 | ||
diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs index b3a9c19d1..db71dee10 100644 --- a/embassy-nrf/src/lib.rs +++ b/embassy-nrf/src/lib.rs | |||
| @@ -29,6 +29,7 @@ | |||
| 29 | feature = "nrf54l10-app-ns", | 29 | feature = "nrf54l10-app-ns", |
| 30 | feature = "nrf54l05-app-s", | 30 | feature = "nrf54l05-app-s", |
| 31 | feature = "nrf54l05-app-ns", | 31 | feature = "nrf54l05-app-ns", |
| 32 | feature = "nrf54lm20-app-s", | ||
| 32 | feature = "nrf9160-s", | 33 | feature = "nrf9160-s", |
| 33 | feature = "nrf9160-ns", | 34 | feature = "nrf9160-ns", |
| 34 | feature = "nrf9120-s", | 35 | feature = "nrf9120-s", |
| @@ -57,6 +58,7 @@ compile_error!( | |||
| 57 | nrf54l10-app-ns, | 58 | nrf54l10-app-ns, |
| 58 | nrf54l05-app-s, | 59 | nrf54l05-app-s, |
| 59 | nrf54l05-app-ns, | 60 | nrf54l05-app-ns, |
| 61 | nrf54lm20-app-s, | ||
| 60 | nrf9160-s, | 62 | nrf9160-s, |
| 61 | nrf9160-ns, | 63 | nrf9160-ns, |
| 62 | nrf9120-s, | 64 | nrf9120-s, |
| @@ -202,6 +204,7 @@ pub mod wdt; | |||
| 202 | #[cfg_attr(feature = "_nrf54l15-app", path = "chips/nrf54l15_app.rs")] | 204 | #[cfg_attr(feature = "_nrf54l15-app", path = "chips/nrf54l15_app.rs")] |
| 203 | #[cfg_attr(feature = "_nrf54l10-app", path = "chips/nrf54l10_app.rs")] | 205 | #[cfg_attr(feature = "_nrf54l10-app", path = "chips/nrf54l10_app.rs")] |
| 204 | #[cfg_attr(feature = "_nrf54l05-app", path = "chips/nrf54l05_app.rs")] | 206 | #[cfg_attr(feature = "_nrf54l05-app", path = "chips/nrf54l05_app.rs")] |
| 207 | #[cfg_attr(feature = "_nrf54lm20-app", path = "chips/nrf54lm20_app.rs")] | ||
| 205 | #[cfg_attr(feature = "_nrf9160", path = "chips/nrf9160.rs")] | 208 | #[cfg_attr(feature = "_nrf9160", path = "chips/nrf9160.rs")] |
| 206 | #[cfg_attr(feature = "_nrf9120", path = "chips/nrf9120.rs")] | 209 | #[cfg_attr(feature = "_nrf9120", path = "chips/nrf9120.rs")] |
| 207 | mod chip; | 210 | mod chip; |
diff --git a/embassy-nrf/src/saadc.rs b/embassy-nrf/src/saadc.rs index ab0e2b86a..e89338416 100644 --- a/embassy-nrf/src/saadc.rs +++ b/embassy-nrf/src/saadc.rs | |||
| @@ -195,6 +195,7 @@ impl<'d, const N: usize> Saadc<'d, N> { | |||
| 195 | w.set_resp(cc.resistor.into()); | 195 | w.set_resp(cc.resistor.into()); |
| 196 | #[cfg(not(feature = "_nrf54l"))] | 196 | #[cfg(not(feature = "_nrf54l"))] |
| 197 | w.set_resn(vals::Resn::BYPASS); | 197 | w.set_resn(vals::Resn::BYPASS); |
| 198 | #[cfg(not(feature = "_nrf54l"))] | ||
| 198 | w.set_burst(!matches!(oversample, Oversample::BYPASS)); | 199 | w.set_burst(!matches!(oversample, Oversample::BYPASS)); |
| 199 | }); | 200 | }); |
| 200 | } | 201 | } |
diff --git a/examples/nrf54lm20/.cargo/config.toml b/examples/nrf54lm20/.cargo/config.toml new file mode 100644 index 000000000..e26853bef --- /dev/null +++ b/examples/nrf54lm20/.cargo/config.toml | |||
| @@ -0,0 +1,10 @@ | |||
| 1 | [target.'cfg(all(target_arch = "arm", target_os = "none"))'] | ||
| 2 | # runner = "probe-rs run --chip nrf54lm20" | ||
| 3 | # probe-rs doesn't support nRF54LM20A right now, so jlink is needed | ||
| 4 | runner = "./run.sh" | ||
| 5 | |||
| 6 | [build] | ||
| 7 | target = "thumbv8m.main-none-eabihf" | ||
| 8 | |||
| 9 | [env] | ||
| 10 | DEFMT_LOG = "trace" | ||
diff --git a/examples/nrf54lm20/Cargo.toml b/examples/nrf54lm20/Cargo.toml new file mode 100644 index 000000000..5482fc77a --- /dev/null +++ b/examples/nrf54lm20/Cargo.toml | |||
| @@ -0,0 +1,37 @@ | |||
| 1 | [package] | ||
| 2 | edition = "2024" | ||
| 3 | name = "embassy-nrf54lm20-examples" | ||
| 4 | version = "0.1.0" | ||
| 5 | license = "MIT OR Apache-2.0" | ||
| 6 | publish = false | ||
| 7 | |||
| 8 | [dependencies] | ||
| 9 | embassy-futures = { version = "0.1.2", path = "../../embassy-futures" } | ||
| 10 | embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } | ||
| 11 | embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } | ||
| 12 | embassy-sync = { version = "0.7.2", path = "../../embassy-sync", features = ["defmt"] } | ||
| 13 | embassy-nrf = { version = "0.8.0", path = "../../embassy-nrf", features = ["defmt", "nrf54lm20-app-s", "time-driver-grtc", "gpiote", "unstable-pac", "time"] } | ||
| 14 | embedded-io = { version = "0.6.0", features = ["defmt-03"] } | ||
| 15 | embedded-io-async = { version = "0.6.1", features = ["defmt-03"] } | ||
| 16 | |||
| 17 | rand = { version = "0.9.0", default-features = false } | ||
| 18 | |||
| 19 | defmt = "1.0.1" | ||
| 20 | defmt-rtt = "1.0.0" | ||
| 21 | panic-probe = { version = "1.0.0", features = ["print-defmt"] } | ||
| 22 | |||
| 23 | cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } | ||
| 24 | cortex-m-rt = "0.7.0" | ||
| 25 | |||
| 26 | embedded-storage = "0.3.1" | ||
| 27 | portable-atomic = "1" | ||
| 28 | |||
| 29 | static_cell = "2" | ||
| 30 | |||
| 31 | [profile.release] | ||
| 32 | debug = 2 | ||
| 33 | |||
| 34 | [package.metadata.embassy] | ||
| 35 | build = [ | ||
| 36 | { target = "thumbv8m.main-none-eabihf", artifact-dir = "out/examples/nrf54lm20" } | ||
| 37 | ] | ||
diff --git a/examples/nrf54lm20/build.rs b/examples/nrf54lm20/build.rs new file mode 100644 index 000000000..30691aa97 --- /dev/null +++ b/examples/nrf54lm20/build.rs | |||
| @@ -0,0 +1,35 @@ | |||
| 1 | //! This build script copies the `memory.x` file from the crate root into | ||
| 2 | //! a directory where the linker can always find it at build time. | ||
| 3 | //! For many projects this is optional, as the linker always searches the | ||
| 4 | //! project root directory -- wherever `Cargo.toml` is. However, if you | ||
| 5 | //! are using a workspace or have a more complicated build setup, this | ||
| 6 | //! build script becomes required. Additionally, by requesting that | ||
| 7 | //! Cargo re-run the build script whenever `memory.x` is changed, | ||
| 8 | //! updating `memory.x` ensures a rebuild of the application with the | ||
| 9 | //! new memory settings. | ||
| 10 | |||
| 11 | use std::env; | ||
| 12 | use std::fs::File; | ||
| 13 | use std::io::Write; | ||
| 14 | use std::path::PathBuf; | ||
| 15 | |||
| 16 | fn main() { | ||
| 17 | // Put `memory.x` in our output directory and ensure it's | ||
| 18 | // on the linker search path. | ||
| 19 | let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); | ||
| 20 | File::create(out.join("memory.x")) | ||
| 21 | .unwrap() | ||
| 22 | .write_all(include_bytes!("memory.x")) | ||
| 23 | .unwrap(); | ||
| 24 | println!("cargo:rustc-link-search={}", out.display()); | ||
| 25 | |||
| 26 | // By default, Cargo will re-run a build script whenever | ||
| 27 | // any file in the project changes. By specifying `memory.x` | ||
| 28 | // here, we ensure the build script is only re-run when | ||
| 29 | // `memory.x` is changed. | ||
| 30 | println!("cargo:rerun-if-changed=memory.x"); | ||
| 31 | |||
| 32 | println!("cargo:rustc-link-arg-bins=--nmagic"); | ||
| 33 | println!("cargo:rustc-link-arg-bins=-Tlink.x"); | ||
| 34 | println!("cargo:rustc-link-arg-bins=-Tdefmt.x"); | ||
| 35 | } | ||
diff --git a/examples/nrf54lm20/memory.x b/examples/nrf54lm20/memory.x new file mode 100644 index 000000000..564f488ac --- /dev/null +++ b/examples/nrf54lm20/memory.x | |||
| @@ -0,0 +1,5 @@ | |||
| 1 | MEMORY | ||
| 2 | { | ||
| 3 | FLASH : ORIGIN = 0x00000000, LENGTH = 2036K | ||
| 4 | RAM : ORIGIN = 0x20000000, LENGTH = 512K | ||
| 5 | } | ||
diff --git a/examples/nrf54lm20/run.sh b/examples/nrf54lm20/run.sh new file mode 100755 index 000000000..2386163a7 --- /dev/null +++ b/examples/nrf54lm20/run.sh | |||
| @@ -0,0 +1,15 @@ | |||
| 1 | cp $1 $1.elf | ||
| 2 | |||
| 3 | ELF_FILE="$1.elf" | ||
| 4 | |||
| 5 | JLinkExe <<EOF | ||
| 6 | Device nrf54lm20a_m33 | ||
| 7 | SelectInterface SWD | ||
| 8 | Speed 4000 | ||
| 9 | LoadFile ${ELF_FILE} | ||
| 10 | r | ||
| 11 | g | ||
| 12 | q | ||
| 13 | EOF | ||
| 14 | |||
| 15 | defmt-print -e $1 tcp \ No newline at end of file | ||
diff --git a/examples/nrf54lm20/src/bin/blinky.rs b/examples/nrf54lm20/src/bin/blinky.rs new file mode 100644 index 000000000..962e9f5a6 --- /dev/null +++ b/examples/nrf54lm20/src/bin/blinky.rs | |||
| @@ -0,0 +1,23 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use defmt::info; | ||
| 5 | use embassy_executor::Spawner; | ||
| 6 | use embassy_nrf::gpio::{Level, Output, OutputDrive}; | ||
| 7 | use embassy_time::Timer; | ||
| 8 | use {defmt_rtt as _, panic_probe as _}; | ||
| 9 | |||
| 10 | #[embassy_executor::main] | ||
| 11 | async fn main(_spawner: Spawner) { | ||
| 12 | let p = embassy_nrf::init(Default::default()); | ||
| 13 | let mut led = Output::new(p.P1_22, Level::Low, OutputDrive::HighDrive); | ||
| 14 | |||
| 15 | loop { | ||
| 16 | info!("high!"); | ||
| 17 | led.set_high(); | ||
| 18 | Timer::after_millis(300).await; | ||
| 19 | info!("low!"); | ||
| 20 | led.set_low(); | ||
| 21 | Timer::after_millis(300).await; | ||
| 22 | } | ||
| 23 | } | ||
diff --git a/examples/nrf54lm20/src/bin/gpio.rs b/examples/nrf54lm20/src/bin/gpio.rs new file mode 100644 index 000000000..4b6b4630d --- /dev/null +++ b/examples/nrf54lm20/src/bin/gpio.rs | |||
| @@ -0,0 +1,23 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use defmt::info; | ||
| 5 | use embassy_executor::Spawner; | ||
| 6 | use embassy_nrf::gpio::{Input, Pull}; | ||
| 7 | use embassy_time::Timer; | ||
| 8 | use {defmt_rtt as _, panic_probe as _}; | ||
| 9 | |||
| 10 | #[embassy_executor::main] | ||
| 11 | async fn main(_spawner: Spawner) { | ||
| 12 | let p = embassy_nrf::init(Default::default()); | ||
| 13 | let btn = Input::new(p.P1_26, Pull::Up); | ||
| 14 | |||
| 15 | loop { | ||
| 16 | if btn.is_high() { | ||
| 17 | info!("high"); | ||
| 18 | } else { | ||
| 19 | info!("low"); | ||
| 20 | } | ||
| 21 | Timer::after_millis(100).await; | ||
| 22 | } | ||
| 23 | } | ||
diff --git a/examples/nrf54lm20/src/bin/gpiote_channel.rs b/examples/nrf54lm20/src/bin/gpiote_channel.rs new file mode 100644 index 000000000..0f30f06c7 --- /dev/null +++ b/examples/nrf54lm20/src/bin/gpiote_channel.rs | |||
| @@ -0,0 +1,49 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use defmt::info; | ||
| 5 | use embassy_executor::Spawner; | ||
| 6 | use embassy_nrf::gpio::Pull; | ||
| 7 | use embassy_nrf::gpiote::{InputChannel, InputChannelPolarity}; | ||
| 8 | use {defmt_rtt as _, panic_probe as _}; | ||
| 9 | |||
| 10 | #[embassy_executor::main] | ||
| 11 | async fn main(_spawner: Spawner) { | ||
| 12 | let p = embassy_nrf::init(Default::default()); | ||
| 13 | info!("Starting!"); | ||
| 14 | |||
| 15 | let mut ch1 = InputChannel::new(p.GPIOTE20_CH0, p.P1_26, Pull::Up, InputChannelPolarity::HiToLo); | ||
| 16 | let mut ch2 = InputChannel::new(p.GPIOTE20_CH1, p.P1_09, Pull::Up, InputChannelPolarity::LoToHi); | ||
| 17 | let mut ch3 = InputChannel::new(p.GPIOTE20_CH2, p.P1_08, Pull::Up, InputChannelPolarity::Toggle); | ||
| 18 | let mut ch4 = InputChannel::new(p.GPIOTE30_CH0, p.P0_05, Pull::Up, InputChannelPolarity::Toggle); | ||
| 19 | |||
| 20 | let button1 = async { | ||
| 21 | loop { | ||
| 22 | ch1.wait().await; | ||
| 23 | info!("Button 1 pressed") | ||
| 24 | } | ||
| 25 | }; | ||
| 26 | |||
| 27 | let button2 = async { | ||
| 28 | loop { | ||
| 29 | ch2.wait().await; | ||
| 30 | info!("Button 2 released") | ||
| 31 | } | ||
| 32 | }; | ||
| 33 | |||
| 34 | let button3 = async { | ||
| 35 | loop { | ||
| 36 | ch3.wait().await; | ||
| 37 | info!("Button 3 toggled") | ||
| 38 | } | ||
| 39 | }; | ||
| 40 | |||
| 41 | let button4 = async { | ||
| 42 | loop { | ||
| 43 | ch4.wait().await; | ||
| 44 | info!("Button 4 toggled") | ||
| 45 | } | ||
| 46 | }; | ||
| 47 | |||
| 48 | embassy_futures::join::join4(button1, button2, button3, button4).await; | ||
| 49 | } | ||
diff --git a/examples/nrf54lm20/src/bin/gpiote_port.rs b/examples/nrf54lm20/src/bin/gpiote_port.rs new file mode 100644 index 000000000..6dbd63d92 --- /dev/null +++ b/examples/nrf54lm20/src/bin/gpiote_port.rs | |||
| @@ -0,0 +1,33 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use defmt::{info, unwrap}; | ||
| 5 | use embassy_executor::Spawner; | ||
| 6 | use embassy_nrf::gpio::{Input, Pull}; | ||
| 7 | use {defmt_rtt as _, panic_probe as _}; | ||
| 8 | |||
| 9 | #[embassy_executor::task(pool_size = 4)] | ||
| 10 | async fn button_task(n: usize, mut pin: Input<'static>) { | ||
| 11 | loop { | ||
| 12 | pin.wait_for_low().await; | ||
| 13 | info!("Button {:?} pressed!", n); | ||
| 14 | pin.wait_for_high().await; | ||
| 15 | info!("Button {:?} released!", n); | ||
| 16 | } | ||
| 17 | } | ||
| 18 | |||
| 19 | #[embassy_executor::main] | ||
| 20 | async fn main(spawner: Spawner) { | ||
| 21 | let p = embassy_nrf::init(Default::default()); | ||
| 22 | info!("Starting!"); | ||
| 23 | |||
| 24 | let btn1 = Input::new(p.P1_26, Pull::Up); | ||
| 25 | let btn2 = Input::new(p.P1_09, Pull::Up); | ||
| 26 | let btn3 = Input::new(p.P1_08, Pull::Up); | ||
| 27 | let btn4 = Input::new(p.P0_05, Pull::Up); | ||
| 28 | |||
| 29 | spawner.spawn(unwrap!(button_task(1, btn1))); | ||
| 30 | spawner.spawn(unwrap!(button_task(2, btn2))); | ||
| 31 | spawner.spawn(unwrap!(button_task(3, btn3))); | ||
| 32 | spawner.spawn(unwrap!(button_task(4, btn4))); | ||
| 33 | } | ||
diff --git a/examples/nrf54lm20/src/bin/timer.rs b/examples/nrf54lm20/src/bin/timer.rs new file mode 100644 index 000000000..68acc91c1 --- /dev/null +++ b/examples/nrf54lm20/src/bin/timer.rs | |||
| @@ -0,0 +1,30 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use defmt::{info, unwrap}; | ||
| 5 | use embassy_executor::Spawner; | ||
| 6 | use embassy_time::Timer; | ||
| 7 | use {defmt_rtt as _, panic_probe as _}; | ||
| 8 | |||
| 9 | #[embassy_executor::task] | ||
| 10 | async fn run1() { | ||
| 11 | loop { | ||
| 12 | info!("BIG INFREQUENT TICK"); | ||
| 13 | Timer::after_secs(10).await; | ||
| 14 | } | ||
| 15 | } | ||
| 16 | |||
| 17 | #[embassy_executor::task] | ||
| 18 | async fn run2() { | ||
| 19 | loop { | ||
| 20 | info!("tick"); | ||
| 21 | Timer::after_secs(1).await; | ||
| 22 | } | ||
| 23 | } | ||
| 24 | |||
| 25 | #[embassy_executor::main] | ||
| 26 | async fn main(spawner: Spawner) { | ||
| 27 | let _p = embassy_nrf::init(Default::default()); | ||
| 28 | spawner.spawn(unwrap!(run1())); | ||
| 29 | spawner.spawn(unwrap!(run2())); | ||
| 30 | } | ||
