diff options
| -rw-r--r-- | embassy-stm32/src/flash/h50.rs | 50 |
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. | ||
| 121 | pub 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! | ||
| 135 | pub 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 | |||
| 114 | fn sr_busy(sr: Nssr) -> bool { | 158 | fn 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() |
