diff options
| -rw-r--r-- | docs/pages/faq.adoc | 46 |
1 files changed, 46 insertions, 0 deletions
diff --git a/docs/pages/faq.adoc b/docs/pages/faq.adoc index d4f49bfc1..3e32563cc 100644 --- a/docs/pages/faq.adoc +++ b/docs/pages/faq.adoc | |||
| @@ -385,3 +385,49 @@ async fn idle() { | |||
| 385 | loop { embassy_futures::yield_now().await; } | 385 | loop { embassy_futures::yield_now().await; } |
| 386 | } | 386 | } |
| 387 | ---- | 387 | ---- |
| 388 | |||
| 389 | == Why is my bootloader restarting in loop? | ||
| 390 | |||
| 391 | == Troubleshooting Bootloader Restart Loops | ||
| 392 | |||
| 393 | If your bootloader restarts in a loop, there could be multiple reasons. Here are some things to check: | ||
| 394 | |||
| 395 | === Validate the `memory.x` File | ||
| 396 | The bootloader performs critical checks when creating partitions using the addresses defined in `memory.x`. Ensure the following assertions hold true: | ||
| 397 | |||
| 398 | [source,rust] | ||
| 399 | ---- | ||
| 400 | const { | ||
| 401 | core::assert!(Self::PAGE_SIZE % ACTIVE::WRITE_SIZE as u32 == 0); | ||
| 402 | core::assert!(Self::PAGE_SIZE % ACTIVE::ERASE_SIZE as u32 == 0); | ||
| 403 | core::assert!(Self::PAGE_SIZE % DFU::WRITE_SIZE as u32 == 0); | ||
| 404 | core::assert!(Self::PAGE_SIZE % DFU::ERASE_SIZE as u32 == 0); | ||
| 405 | } | ||
| 406 | |||
| 407 | // Ensure enough progress pages to store copy progress | ||
| 408 | assert_eq!(0, Self::PAGE_SIZE % aligned_buf.len() as u32); | ||
| 409 | assert!(aligned_buf.len() >= STATE::WRITE_SIZE); | ||
| 410 | assert_eq!(0, aligned_buf.len() % ACTIVE::WRITE_SIZE); | ||
| 411 | assert_eq!(0, aligned_buf.len() % DFU::WRITE_SIZE); | ||
| 412 | ---- | ||
| 413 | |||
| 414 | If any of these assertions fail, the bootloader will likely restart in a loop. This failure might not log any messages (e.g., when using `defmt`). Confirm that your `memory.x` file and flash memory align with these requirements. | ||
| 415 | |||
| 416 | === Handling Panic Logging | ||
| 417 | Some panic errors might log messages, but certain microcontrollers reset before the message is fully printed. To ensure panic messages are logged, add a delay using no-operation (NOP) instructions before the reset: | ||
| 418 | |||
| 419 | [source,rust] | ||
| 420 | ---- | ||
| 421 | #[panic_handler] | ||
| 422 | fn panic(_info: &core::panic::PanicInfo) -> ! { | ||
| 423 | for _ in 0..10_000_000 { | ||
| 424 | cortex_m::asm::nop(); | ||
| 425 | } | ||
| 426 | cortex_m::asm::udf(); | ||
| 427 | } | ||
| 428 | ---- | ||
| 429 | |||
| 430 | === Feed the watchdog | ||
| 431 | |||
| 432 | |||
| 433 | Some `embassy-boot` implementations (like `embassy-boot-nrf` and `embassy-boot-rp`) rely on a watchdog timer to detect application failure. The bootloader will restart if your application code does not properly feed the watchdog timer. Make sure to feed it correctly. | ||
