aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-stm32/src/flash/h50.rs50
1 files changed, 47 insertions, 3 deletions
diff --git a/embassy-stm32/src/flash/h50.rs b/embassy-stm32/src/flash/h50.rs
index 5b15be261..56ea7a421 100644
--- a/embassy-stm32/src/flash/h50.rs
+++ b/embassy-stm32/src/flash/h50.rs
@@ -61,9 +61,12 @@ pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), E
61 61
62 interrupt::free(|_| { 62 interrupt::free(|_| {
63 pac::FLASH.nscr().modify(|w| { 63 pac::FLASH.nscr().modify(|w| {
64 w.set_bksel(match sector.bank { 64 // BKSEL ignores SWAP_BANK, so we must take it into account here
65 FlashBank::Bank1 => Bksel::BANK1, 65 w.set_bksel(match (sector.bank, banks_swapped()) {
66 FlashBank::Bank2 => Bksel::BANK2, 66 (FlashBank::Bank1, false) => Bksel::BANK1,
67 (FlashBank::Bank2, true) => Bksel::BANK1,
68 (FlashBank::Bank2, false) => Bksel::BANK2,
69 (FlashBank::Bank1, true) => Bksel::BANK2,
67 }); 70 });
68 w.set_snb(sector.index_in_bank); 71 w.set_snb(sector.index_in_bank);
69 w.set_ser(true); 72 w.set_ser(true);
@@ -111,6 +114,47 @@ pub(crate) unsafe fn clear_all_err() {
111 }) 114 })
112} 115}
113 116
117/// Get the current SWAP_BANK option.
118///
119/// This value is only loaded on system or power-on reset. `perform_bank_swap()`
120/// will not reflect here.
121pub fn banks_swapped() -> bool {
122 pac::FLASH.optcr().read().swap_bank()
123}
124
125/// Logical, persistent swap of flash banks 1 and 2.
126///
127/// This allows the application to write a new firmware blob into bank 2, then
128/// swap the banks and perform a reset, loading the new firmware.
129///
130/// Swap does not take effect until system or power-on reset.
131///
132/// PLEASE READ THE REFERENCE MANUAL - there are nuances to this feature. For
133/// instance, erase commands and interrupt enables which take a flash bank as a
134/// parameter ignore the swap!
135pub fn perform_bank_swap() {
136 while busy() {}
137
138 unsafe {
139 clear_all_err();
140 }
141
142 // unlock OPTLOCK
143 pac::FLASH.optkeyr().write(|w| *w = 0x0819_2A3B);
144 pac::FLASH.optkeyr().write(|w| *w = 0x4C5D_6E7F);
145 while pac::FLASH.optcr().read().optlock() {}
146
147 // toggle SWAP_BANK option
148 pac::FLASH.optsr_prg().modify(|w| w.set_swap_bank(!banks_swapped()));
149
150 // load option bytes
151 pac::FLASH.optcr().modify(|w| w.set_optstrt(true));
152 while pac::FLASH.optcr().read().optstrt() {}
153
154 // re-lock OPTLOCK
155 pac::FLASH.optcr().modify(|w| w.set_optlock(true));
156}
157
114fn sr_busy(sr: Nssr) -> bool { 158fn sr_busy(sr: Nssr) -> bool {
115 // Note: RM0492 sometimes incorrectly refers to WBNE as NSWBNE 159 // Note: RM0492 sometimes incorrectly refers to WBNE as NSWBNE
116 sr.bsy() || sr.dbne() || sr.wbne() 160 sr.bsy() || sr.dbne() || sr.wbne()