diff options
Diffstat (limited to 'embassy-nrf/src/lib.rs')
| -rw-r--r-- | embassy-nrf/src/lib.rs | 162 |
1 files changed, 141 insertions, 21 deletions
diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs index 5bce65a98..897e660b8 100644 --- a/embassy-nrf/src/lib.rs +++ b/embassy-nrf/src/lib.rs | |||
| @@ -98,8 +98,12 @@ pub mod ipc; | |||
| 98 | feature = "_nrf5340-app" | 98 | feature = "_nrf5340-app" |
| 99 | ))] | 99 | ))] |
| 100 | pub mod nfct; | 100 | pub mod nfct; |
| 101 | #[cfg(not(feature = "_nrf54l"))] // TODO | 101 | #[cfg(not(feature = "_nrf54l"))] |
| 102 | pub mod nvmc; | 102 | pub mod nvmc; |
| 103 | #[cfg(feature = "nrf54l15-app-s")] | ||
| 104 | pub mod rramc; | ||
| 105 | #[cfg(feature = "nrf54l15-app-s")] | ||
| 106 | pub use rramc as nvmc; | ||
| 103 | #[cfg(not(feature = "_nrf54l"))] // TODO | 107 | #[cfg(not(feature = "_nrf54l"))] // TODO |
| 104 | #[cfg(any( | 108 | #[cfg(any( |
| 105 | feature = "nrf52810", | 109 | feature = "nrf52810", |
| @@ -133,6 +137,17 @@ pub mod qspi; | |||
| 133 | #[cfg(not(feature = "_nrf54l"))] // TODO | 137 | #[cfg(not(feature = "_nrf54l"))] // TODO |
| 134 | #[cfg(not(any(feature = "_nrf91", feature = "_nrf5340-app")))] | 138 | #[cfg(not(any(feature = "_nrf91", feature = "_nrf5340-app")))] |
| 135 | pub mod radio; | 139 | pub mod radio; |
| 140 | |||
| 141 | #[cfg(any( | ||
| 142 | feature = "nrf52811", | ||
| 143 | feature = "nrf52820", | ||
| 144 | feature = "nrf52833", | ||
| 145 | feature = "nrf52840", | ||
| 146 | feature = "_nrf5340-net" | ||
| 147 | ))] | ||
| 148 | #[cfg(feature = "_net-driver")] | ||
| 149 | pub mod embassy_net_802154_driver; | ||
| 150 | |||
| 136 | #[cfg(not(feature = "_nrf54l"))] // TODO | 151 | #[cfg(not(feature = "_nrf54l"))] // TODO |
| 137 | #[cfg(feature = "_nrf5340")] | 152 | #[cfg(feature = "_nrf5340")] |
| 138 | pub mod reset; | 153 | pub mod reset; |
| @@ -148,8 +163,7 @@ pub mod spim; | |||
| 148 | #[cfg(not(feature = "_nrf54l"))] // TODO | 163 | #[cfg(not(feature = "_nrf54l"))] // TODO |
| 149 | #[cfg(not(feature = "_nrf51"))] | 164 | #[cfg(not(feature = "_nrf51"))] |
| 150 | pub mod spis; | 165 | pub mod spis; |
| 151 | #[cfg(not(feature = "_nrf54l"))] // TODO | 166 | #[cfg(not(any(feature = "_nrf5340-app", feature = "_nrf91")))] |
| 152 | #[cfg(not(any(feature = "_nrf5340", feature = "_nrf91")))] | ||
| 153 | pub mod temp; | 167 | pub mod temp; |
| 154 | #[cfg(not(feature = "_nrf54l"))] // TODO | 168 | #[cfg(not(feature = "_nrf54l"))] // TODO |
| 155 | pub mod timer; | 169 | pub mod timer; |
| @@ -170,7 +184,6 @@ pub mod uarte; | |||
| 170 | feature = "nrf52840" | 184 | feature = "nrf52840" |
| 171 | ))] | 185 | ))] |
| 172 | pub mod usb; | 186 | pub mod usb; |
| 173 | #[cfg(not(feature = "_nrf54l"))] // TODO | ||
| 174 | pub mod wdt; | 187 | pub mod wdt; |
| 175 | 188 | ||
| 176 | // This mod MUST go last, so that it sees all the `impl_foo!` macros | 189 | // This mod MUST go last, so that it sees all the `impl_foo!` macros |
| @@ -200,9 +213,12 @@ mod chip; | |||
| 200 | /// ```rust,ignore | 213 | /// ```rust,ignore |
| 201 | /// use embassy_nrf::{bind_interrupts, spim, peripherals}; | 214 | /// use embassy_nrf::{bind_interrupts, spim, peripherals}; |
| 202 | /// | 215 | /// |
| 203 | /// bind_interrupts!(struct Irqs { | 216 | /// bind_interrupts!( |
| 204 | /// SPIM3 => spim::InterruptHandler<peripherals::SPI3>; | 217 | /// /// Binds the SPIM3 interrupt. |
| 205 | /// }); | 218 | /// struct Irqs { |
| 219 | /// SPIM3 => spim::InterruptHandler<peripherals::SPI3>; | ||
| 220 | /// } | ||
| 221 | /// ); | ||
| 206 | /// ``` | 222 | /// ``` |
| 207 | /// | 223 | /// |
| 208 | /// Example of how to bind multiple interrupts in a single macro invocation: | 224 | /// Example of how to bind multiple interrupts in a single macro invocation: |
| @@ -219,7 +235,7 @@ mod chip; | |||
| 219 | // developer note: this macro can't be in `embassy-hal-internal` due to the use of `$crate`. | 235 | // developer note: this macro can't be in `embassy-hal-internal` due to the use of `$crate`. |
| 220 | #[macro_export] | 236 | #[macro_export] |
| 221 | macro_rules! bind_interrupts { | 237 | macro_rules! bind_interrupts { |
| 222 | ($vis:vis struct $name:ident { | 238 | ($(#[$attr:meta])* $vis:vis struct $name:ident { |
| 223 | $( | 239 | $( |
| 224 | $(#[cfg($cond_irq:meta)])? | 240 | $(#[cfg($cond_irq:meta)])? |
| 225 | $irq:ident => $( | 241 | $irq:ident => $( |
| @@ -229,6 +245,7 @@ macro_rules! bind_interrupts { | |||
| 229 | )* | 245 | )* |
| 230 | }) => { | 246 | }) => { |
| 231 | #[derive(Copy, Clone)] | 247 | #[derive(Copy, Clone)] |
| 248 | $(#[$attr])* | ||
| 232 | $vis struct $name; | 249 | $vis struct $name; |
| 233 | 250 | ||
| 234 | $( | 251 | $( |
| @@ -236,11 +253,13 @@ macro_rules! bind_interrupts { | |||
| 236 | #[no_mangle] | 253 | #[no_mangle] |
| 237 | $(#[cfg($cond_irq)])? | 254 | $(#[cfg($cond_irq)])? |
| 238 | unsafe extern "C" fn $irq() { | 255 | unsafe extern "C" fn $irq() { |
| 239 | $( | 256 | unsafe { |
| 240 | $(#[cfg($cond_handler)])? | 257 | $( |
| 241 | <$handler as $crate::interrupt::typelevel::Handler<$crate::interrupt::typelevel::$irq>>::on_interrupt(); | 258 | $(#[cfg($cond_handler)])? |
| 259 | <$handler as $crate::interrupt::typelevel::Handler<$crate::interrupt::typelevel::$irq>>::on_interrupt(); | ||
| 242 | 260 | ||
| 243 | )* | 261 | )* |
| 262 | } | ||
| 244 | } | 263 | } |
| 245 | 264 | ||
| 246 | $(#[cfg($cond_irq)])? | 265 | $(#[cfg($cond_irq)])? |
| @@ -339,7 +358,7 @@ pub mod config { | |||
| 339 | /// 3.0 V | 358 | /// 3.0 V |
| 340 | _3V0 = 4, | 359 | _3V0 = 4, |
| 341 | /// 3.3 V | 360 | /// 3.3 V |
| 342 | _3v3 = 5, | 361 | _3V3 = 5, |
| 343 | //ERASED = 7, means 1.8V | 362 | //ERASED = 7, means 1.8V |
| 344 | } | 363 | } |
| 345 | 364 | ||
| @@ -371,7 +390,7 @@ pub mod config { | |||
| 371 | /// 3.0 V | 390 | /// 3.0 V |
| 372 | _3V0 = 4, | 391 | _3V0 = 4, |
| 373 | /// 3.3 V | 392 | /// 3.3 V |
| 374 | _3v3 = 5, | 393 | _3V3 = 5, |
| 375 | //ERASED = 7, means 1.8V | 394 | //ERASED = 7, means 1.8V |
| 376 | } | 395 | } |
| 377 | 396 | ||
| @@ -580,8 +599,12 @@ pub mod config { | |||
| 580 | #[allow(unused)] | 599 | #[allow(unused)] |
| 581 | mod consts { | 600 | mod consts { |
| 582 | pub const UICR_APPROTECT: *mut u32 = 0x00FF8000 as *mut u32; | 601 | pub const UICR_APPROTECT: *mut u32 = 0x00FF8000 as *mut u32; |
| 602 | pub const UICR_HFXOSRC: *mut u32 = 0x00FF801C as *mut u32; | ||
| 603 | pub const UICR_HFXOCNT: *mut u32 = 0x00FF8020 as *mut u32; | ||
| 583 | pub const UICR_SECUREAPPROTECT: *mut u32 = 0x00FF802C as *mut u32; | 604 | pub const UICR_SECUREAPPROTECT: *mut u32 = 0x00FF802C as *mut u32; |
| 584 | pub const APPROTECT_ENABLED: u32 = 0x0000_0000; | 605 | pub const APPROTECT_ENABLED: u32 = 0x0000_0000; |
| 606 | #[cfg(feature = "_nrf9120")] | ||
| 607 | pub const APPROTECT_DISABLED: u32 = 0x50FA50FA; | ||
| 585 | } | 608 | } |
| 586 | 609 | ||
| 587 | #[cfg(feature = "_nrf5340-app")] | 610 | #[cfg(feature = "_nrf5340-app")] |
| @@ -644,13 +667,18 @@ unsafe fn uicr_write_masked(address: *mut u32, value: u32, mask: u32) -> WriteRe | |||
| 644 | return WriteResult::Failed; | 667 | return WriteResult::Failed; |
| 645 | } | 668 | } |
| 646 | 669 | ||
| 647 | let nvmc = pac::NVMC; | 670 | // Nrf9151 errata 7, need to disable interrups + use DSB https://docs.nordicsemi.com/bundle/errata_nRF9151_Rev2/page/ERR/nRF9151/Rev2/latest/anomaly_151_7.html |
| 648 | nvmc.config().write(|w| w.set_wen(pac::nvmc::vals::Wen::WEN)); | 671 | cortex_m::interrupt::free(|_cs| { |
| 649 | while !nvmc.ready().read().ready() {} | 672 | let nvmc = pac::NVMC; |
| 650 | address.write_volatile(value | !mask); | 673 | |
| 651 | while !nvmc.ready().read().ready() {} | 674 | nvmc.config().write(|w| w.set_wen(pac::nvmc::vals::Wen::WEN)); |
| 652 | nvmc.config().write(|_| {}); | 675 | while !nvmc.ready().read().ready() {} |
| 653 | while !nvmc.ready().read().ready() {} | 676 | address.write_volatile(value | !mask); |
| 677 | cortex_m::asm::dsb(); | ||
| 678 | while !nvmc.ready().read().ready() {} | ||
| 679 | nvmc.config().write(|_| {}); | ||
| 680 | while !nvmc.ready().read().ready() {} | ||
| 681 | }); | ||
| 654 | 682 | ||
| 655 | WriteResult::Written | 683 | WriteResult::Written |
| 656 | } | 684 | } |
| @@ -668,6 +696,36 @@ pub fn init(config: config::Config) -> Peripherals { | |||
| 668 | #[allow(unused_mut)] | 696 | #[allow(unused_mut)] |
| 669 | let mut needs_reset = false; | 697 | let mut needs_reset = false; |
| 670 | 698 | ||
| 699 | // Workaround used in the nrf mdk: file system_nrf91.c , function SystemInit(), after `#if !defined(NRF_SKIP_UICR_HFXO_WORKAROUND)` | ||
| 700 | #[cfg(all(feature = "_nrf91", feature = "_s"))] | ||
| 701 | { | ||
| 702 | let uicr = pac::UICR_S; | ||
| 703 | let hfxocnt = uicr.hfxocnt().read().hfxocnt().to_bits(); | ||
| 704 | let hfxosrc = uicr.hfxosrc().read().hfxosrc().to_bits(); | ||
| 705 | |||
| 706 | if hfxosrc == 1 { | ||
| 707 | unsafe { | ||
| 708 | let _ = uicr_write(consts::UICR_HFXOSRC, 0); | ||
| 709 | } | ||
| 710 | needs_reset = true; | ||
| 711 | } | ||
| 712 | |||
| 713 | if hfxocnt == 255 { | ||
| 714 | unsafe { | ||
| 715 | let _ = uicr_write(consts::UICR_HFXOCNT, 32); | ||
| 716 | } | ||
| 717 | needs_reset = true; | ||
| 718 | } | ||
| 719 | } | ||
| 720 | |||
| 721 | // GLITCHDET is only accessible for secure code | ||
| 722 | #[cfg(all(feature = "_nrf54l", feature = "_s"))] | ||
| 723 | { | ||
| 724 | // The voltage glitch detectors are automatically enabled after reset. | ||
| 725 | // To save power, the glitch detectors must be disabled when not in use. | ||
| 726 | pac::GLITCHDET.config().write(|w| w.set_enable(false)); | ||
| 727 | } | ||
| 728 | |||
| 671 | // Setup debug protection. | 729 | // Setup debug protection. |
| 672 | #[cfg(not(feature = "_nrf51"))] | 730 | #[cfg(not(feature = "_nrf51"))] |
| 673 | match config.debug { | 731 | match config.debug { |
| @@ -764,6 +822,28 @@ pub fn init(config: config::Config) -> Peripherals { | |||
| 764 | } | 822 | } |
| 765 | 823 | ||
| 766 | // nothing to do on the nrf9160, debug is allowed by default. | 824 | // nothing to do on the nrf9160, debug is allowed by default. |
| 825 | |||
| 826 | // nrf9151, nrf9161 use the new-style approtect that requires writing a register. | ||
| 827 | #[cfg(feature = "nrf9120-s")] | ||
| 828 | unsafe { | ||
| 829 | let p = pac::APPROTECT_S; | ||
| 830 | |||
| 831 | let res = uicr_write(consts::UICR_APPROTECT, consts::APPROTECT_DISABLED); | ||
| 832 | needs_reset |= res == WriteResult::Written; | ||
| 833 | p.approtect() | ||
| 834 | .disable() | ||
| 835 | .write(|w| w.set_disable(pac::approtect::vals::ApprotectDisableDisable::SW_UNPROTECTED)); | ||
| 836 | |||
| 837 | let res = uicr_write(consts::UICR_SECUREAPPROTECT, consts::APPROTECT_DISABLED); | ||
| 838 | needs_reset |= res == WriteResult::Written; | ||
| 839 | p.secureapprotect() | ||
| 840 | .disable() | ||
| 841 | .write(|w| w.set_disable(pac::approtect::vals::SecureapprotectDisableDisable::SW_UNPROTECTED)); | ||
| 842 | |||
| 843 | // TODO: maybe add workaround for this errata | ||
| 844 | // It uses extra power, not sure how to let the user choose. | ||
| 845 | // https://docs.nordicsemi.com/bundle/errata_nRF9151_Rev1/page/ERR/nRF9151/Rev1/latest/anomaly_151_36.html#anomaly_151_36 | ||
| 846 | } | ||
| 767 | } | 847 | } |
| 768 | config::Debug::Disallowed => { | 848 | config::Debug::Disallowed => { |
| 769 | // TODO: Handle nRF54L | 849 | // TODO: Handle nRF54L |
| @@ -779,6 +859,13 @@ pub fn init(config: config::Config) -> Peripherals { | |||
| 779 | let res = uicr_write(consts::UICR_SECUREAPPROTECT, consts::APPROTECT_ENABLED); | 859 | let res = uicr_write(consts::UICR_SECUREAPPROTECT, consts::APPROTECT_ENABLED); |
| 780 | needs_reset |= res == WriteResult::Written; | 860 | needs_reset |= res == WriteResult::Written; |
| 781 | } | 861 | } |
| 862 | |||
| 863 | #[cfg(feature = "nrf9120-s")] | ||
| 864 | { | ||
| 865 | let p = pac::APPROTECT_S; | ||
| 866 | p.approtect().forceprotect().write(|w| w.set_forceprotect(true)); | ||
| 867 | p.secureapprotect().forceprotect().write(|w| w.set_forceprotect(true)); | ||
| 868 | } | ||
| 782 | } | 869 | } |
| 783 | } | 870 | } |
| 784 | config::Debug::NotConfigured => {} | 871 | config::Debug::NotConfigured => {} |
| @@ -1015,6 +1102,15 @@ pub fn init(config: config::Config) -> Peripherals { | |||
| 1015 | reg.vregradio().dcdcen().write(|w| w.set_dcdcen(true)); | 1102 | reg.vregradio().dcdcen().write(|w| w.set_dcdcen(true)); |
| 1016 | } | 1103 | } |
| 1017 | } | 1104 | } |
| 1105 | #[cfg(feature = "_nrf54l")] | ||
| 1106 | { | ||
| 1107 | // Turn on DCDC | ||
| 1108 | // From Product specification: | ||
| 1109 | // "Once the device starts, the DC/DC regulator must be enabled using register VREGMAIN.DCDCEN. | ||
| 1110 | // When enabling the DC/DC regulator, the device checks if an inductor is connected to the DCC pin. | ||
| 1111 | // If an inductor is not detected, the device remains in LDO mode" | ||
| 1112 | pac::REGULATORS.vregmain().dcdcen().write(|w| w.set_val(true)); | ||
| 1113 | } | ||
| 1018 | 1114 | ||
| 1019 | // Init GPIOTE | 1115 | // Init GPIOTE |
| 1020 | #[cfg(not(feature = "_nrf54l"))] // TODO | 1116 | #[cfg(not(feature = "_nrf54l"))] // TODO |
| @@ -1035,3 +1131,27 @@ pub fn init(config: config::Config) -> Peripherals { | |||
| 1035 | 1131 | ||
| 1036 | peripherals | 1132 | peripherals |
| 1037 | } | 1133 | } |
| 1134 | |||
| 1135 | /// Operating modes for peripherals. | ||
| 1136 | pub mod mode { | ||
| 1137 | trait SealedMode {} | ||
| 1138 | |||
| 1139 | /// Operating mode for a peripheral. | ||
| 1140 | #[allow(private_bounds)] | ||
| 1141 | pub trait Mode: SealedMode {} | ||
| 1142 | |||
| 1143 | macro_rules! impl_mode { | ||
| 1144 | ($name:ident) => { | ||
| 1145 | impl SealedMode for $name {} | ||
| 1146 | impl Mode for $name {} | ||
| 1147 | }; | ||
| 1148 | } | ||
| 1149 | |||
| 1150 | /// Blocking mode. | ||
| 1151 | pub struct Blocking; | ||
| 1152 | /// Async mode. | ||
| 1153 | pub struct Async; | ||
| 1154 | |||
| 1155 | impl_mode!(Blocking); | ||
| 1156 | impl_mode!(Async); | ||
| 1157 | } | ||
