aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2023-02-20 01:29:12 +0100
committerDario Nieuwenhuis <[email protected]>2023-02-20 01:31:02 +0100
commit7fa478358ac117557af778d12d7812da5521fdfd (patch)
tree08d8016484e096d4b6c8dcbde9f7fdeab1035703
parent3f88bf6f9b998e209c6bfe860930fc82516f3f9c (diff)
nrf: warn if uicr configuration could not be written.
If the user requests some configuration, but UICR is already programmed to something else, detect this and warn the user. We don't do it for the debug port settings, because if they are wrong then the user will simply not be able to read debug logs.
-rw-r--r--embassy-nrf/src/lib.rs78
1 files changed, 65 insertions, 13 deletions
diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs
index 0fa1c0f66..a9683df44 100644
--- a/embassy-nrf/src/lib.rs
+++ b/embassy-nrf/src/lib.rs
@@ -235,10 +235,26 @@ mod consts {
235 pub const APPROTECT_DISABLED: u32 = 0x0000_005a; 235 pub const APPROTECT_DISABLED: u32 = 0x0000_005a;
236} 236}
237 237
238unsafe fn uicr_write(address: *mut u32, value: u32) -> bool { 238#[derive(Debug, Copy, Clone, Eq, PartialEq)]
239#[cfg_attr(feature = "defmt", derive(defmt::Format))]
240enum WriteResult {
241 /// Word was written successfully, needs reset.
242 Written,
243 /// Word was already set to the value we wanted to write, nothing was done.
244 Noop,
245 /// Word is already set to something else, we couldn't write the desired value.
246 Failed,
247}
248
249unsafe fn uicr_write(address: *mut u32, value: u32) -> WriteResult {
239 let curr_val = address.read_volatile(); 250 let curr_val = address.read_volatile();
240 if curr_val == value { 251 if curr_val == value {
241 return false; 252 return WriteResult::Noop;
253 }
254
255 // We can only change `1` bits to `0` bits.
256 if curr_val & value != value {
257 return WriteResult::Failed;
242 } 258 }
243 259
244 // Writing to UICR can only change `1` bits to `0` bits. 260 // Writing to UICR can only change `1` bits to `0` bits.
@@ -257,7 +273,7 @@ unsafe fn uicr_write(address: *mut u32, value: u32) -> bool {
257 nvmc.config.reset(); 273 nvmc.config.reset();
258 while nvmc.ready.read().ready().is_busy() {} 274 while nvmc.ready.read().ready().is_busy() {}
259 275
260 true 276 WriteResult::Written
261} 277}
262 278
263/// Initialize peripherals with the provided configuration. This should only be called once at startup. 279/// Initialize peripherals with the provided configuration. This should only be called once at startup.
@@ -283,7 +299,8 @@ pub fn init(config: config::Config) -> Peripherals {
283 // which needs explicit action by the firmware to keep it unlocked 299 // which needs explicit action by the firmware to keep it unlocked
284 300
285 // UICR.APPROTECT = SwDisabled 301 // UICR.APPROTECT = SwDisabled
286 needs_reset |= uicr_write(consts::UICR_APPROTECT, consts::APPROTECT_DISABLED); 302 let res = uicr_write(consts::UICR_APPROTECT, consts::APPROTECT_DISABLED);
303 needs_reset |= res == WriteResult::Written;
287 // APPROTECT.DISABLE = SwDisabled 304 // APPROTECT.DISABLE = SwDisabled
288 (0x4000_0558 as *mut u32).write_volatile(consts::APPROTECT_DISABLED); 305 (0x4000_0558 as *mut u32).write_volatile(consts::APPROTECT_DISABLED);
289 } else { 306 } else {
@@ -295,12 +312,14 @@ pub fn init(config: config::Config) -> Peripherals {
295 unsafe { 312 unsafe {
296 let p = &*pac::CTRLAP::ptr(); 313 let p = &*pac::CTRLAP::ptr();
297 314
298 needs_reset |= uicr_write(consts::UICR_APPROTECT, consts::APPROTECT_DISABLED); 315 let res = uicr_write(consts::UICR_APPROTECT, consts::APPROTECT_DISABLED);
316 needs_reset |= res == WriteResult::Written;
299 p.approtect.disable.write(|w| w.bits(consts::APPROTECT_DISABLED)); 317 p.approtect.disable.write(|w| w.bits(consts::APPROTECT_DISABLED));
300 318
301 #[cfg(feature = "_nrf5340-app")] 319 #[cfg(feature = "_nrf5340-app")]
302 { 320 {
303 needs_reset |= uicr_write(consts::UICR_SECUREAPPROTECT, consts::APPROTECT_DISABLED); 321 let res = uicr_write(consts::UICR_SECUREAPPROTECT, consts::APPROTECT_DISABLED);
322 needs_reset |= res == WriteResult::Written;
304 p.secureapprotect.disable.write(|w| w.bits(consts::APPROTECT_DISABLED)); 323 p.secureapprotect.disable.write(|w| w.bits(consts::APPROTECT_DISABLED));
305 } 324 }
306 } 325 }
@@ -309,24 +328,57 @@ pub fn init(config: config::Config) -> Peripherals {
309 } 328 }
310 config::Debug::Disallowed => unsafe { 329 config::Debug::Disallowed => unsafe {
311 // UICR.APPROTECT = Enabled 330 // UICR.APPROTECT = Enabled
312 needs_reset |= uicr_write(consts::UICR_APPROTECT, consts::APPROTECT_ENABLED); 331 let res = uicr_write(consts::UICR_APPROTECT, consts::APPROTECT_ENABLED);
332 needs_reset |= res == WriteResult::Written;
313 #[cfg(any(feature = "_nrf5340-app", feature = "_nrf9160"))] 333 #[cfg(any(feature = "_nrf5340-app", feature = "_nrf9160"))]
314 { 334 {
315 needs_reset |= uicr_write(consts::UICR_SECUREAPPROTECT, consts::APPROTECT_ENABLED); 335 let res = uicr_write(consts::UICR_SECUREAPPROTECT, consts::APPROTECT_ENABLED);
336 needs_reset |= res == WriteResult::Written;
316 } 337 }
317 }, 338 },
318 config::Debug::NotConfigured => {} 339 config::Debug::NotConfigured => {}
319 } 340 }
320 341
321 #[cfg(all(feature = "_nrf52", not(feature = "reset-pin-as-gpio")))] 342 #[cfg(feature = "_nrf52")]
322 unsafe { 343 unsafe {
323 needs_reset |= uicr_write(consts::UICR_PSELRESET1, chip::RESET_PIN); 344 let value = if cfg!(feature = "reset-pin-as-gpio") {
324 needs_reset |= uicr_write(consts::UICR_PSELRESET2, chip::RESET_PIN); 345 !0
346 } else {
347 chip::RESET_PIN
348 };
349 let res1 = uicr_write(consts::UICR_PSELRESET1, value);
350 let res2 = uicr_write(consts::UICR_PSELRESET2, value);
351 needs_reset |= res1 == WriteResult::Written || res2 == WriteResult::Written;
352 if res1 == WriteResult::Failed || res2 == WriteResult::Failed {
353 #[cfg(not(feature = "reset-pin-as-gpio"))]
354 warn!(
355 "You have requested enabling chip reset functionality on the reset pin, by not enabling the Cargo feature `reset-pin-as-gpio`.\n\
356 However, UICR is already programmed to some other setting, and can't be changed without erasing it.\n\
357 To fix this, erase UICR manually, for example using `probe-rs-cli erase` or `nrfjprog --eraseuicr`."
358 );
359 #[cfg(feature = "reset-pin-as-gpio")]
360 warn!(
361 "You have requested using the reset pin as GPIO, by enabling the Cargo feature `reset-pin-as-gpio`.\n\
362 However, UICR is already programmed to some other setting, and can't be changed without erasing it.\n\
363 To fix this, erase UICR manually, for example using `probe-rs-cli erase` or `nrfjprog --eraseuicr`."
364 );
365 }
325 } 366 }
326 367
327 #[cfg(all(any(feature = "_nrf52", feature = "_nrf5340-app"), feature = "nfc-pins-as-gpio"))] 368 #[cfg(any(feature = "_nrf52", feature = "_nrf5340-app"))]
328 unsafe { 369 unsafe {
329 needs_reset |= uicr_write(consts::UICR_NFCPINS, 0); 370 let value = if cfg!(feature = "nfc-pins-as-gpio") { 0 } else { !0 };
371 let res = uicr_write(consts::UICR_NFCPINS, value);
372 needs_reset |= res == WriteResult::Written;
373 if res == WriteResult::Failed {
374 // with nfc-pins-as-gpio, this can never fail because we're writing all zero bits.
375 #[cfg(not(feature = "nfc-pins-as-gpio"))]
376 warn!(
377 "You have requested to use P0.09 and P0.10 pins for NFC, by not enabling the Cargo feature `nfc-pins-as-gpio`.\n\
378 However, UICR is already programmed to some other setting, and can't be changed without erasing it.\n\
379 To fix this, erase UICR manually, for example using `probe-rs-cli erase` or `nrfjprog --eraseuicr`."
380 );
381 }
330 } 382 }
331 383
332 if needs_reset { 384 if needs_reset {