aboutsummaryrefslogtreecommitdiff
path: root/embassy-nrf/src/lib.rs
diff options
context:
space:
mode:
Diffstat (limited to 'embassy-nrf/src/lib.rs')
-rw-r--r--embassy-nrf/src/lib.rs162
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))]
100pub mod nfct; 100pub mod nfct;
101#[cfg(not(feature = "_nrf54l"))] // TODO 101#[cfg(not(feature = "_nrf54l"))]
102pub mod nvmc; 102pub mod nvmc;
103#[cfg(feature = "nrf54l15-app-s")]
104pub mod rramc;
105#[cfg(feature = "nrf54l15-app-s")]
106pub 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")))]
135pub mod radio; 139pub 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")]
149pub 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")]
138pub mod reset; 153pub 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"))]
150pub mod spis; 165pub 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")))]
153pub mod temp; 167pub mod temp;
154#[cfg(not(feature = "_nrf54l"))] // TODO 168#[cfg(not(feature = "_nrf54l"))] // TODO
155pub mod timer; 169pub mod timer;
@@ -170,7 +184,6 @@ pub mod uarte;
170 feature = "nrf52840" 184 feature = "nrf52840"
171))] 185))]
172pub mod usb; 186pub mod usb;
173#[cfg(not(feature = "_nrf54l"))] // TODO
174pub mod wdt; 187pub 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]
221macro_rules! bind_interrupts { 237macro_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)]
581mod consts { 600mod 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.
1136pub 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}