aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-boot/boot/src/boot_loader.rs239
-rw-r--r--embassy-boot/boot/src/lib.rs44
-rw-r--r--embassy-boot/boot/src/mem_flash.rs9
-rw-r--r--embassy-boot/nrf/src/lib.rs14
-rw-r--r--embassy-boot/rp/src/lib.rs16
-rw-r--r--embassy-boot/stm32/src/lib.rs14
-rw-r--r--examples/boot/bootloader/nrf/src/main.rs8
-rw-r--r--examples/boot/bootloader/rp/src/main.rs3
-rw-r--r--examples/boot/bootloader/stm32/src/main.rs6
9 files changed, 157 insertions, 196 deletions
diff --git a/embassy-boot/boot/src/boot_loader.rs b/embassy-boot/boot/src/boot_loader.rs
index 9d047f778..2412427c0 100644
--- a/embassy-boot/boot/src/boot_loader.rs
+++ b/embassy-boot/boot/src/boot_loader.rs
@@ -30,23 +30,16 @@ where
30 } 30 }
31} 31}
32 32
33/// Extension of the embedded-storage flash type information with block size and erase value. 33/// Trait defining the flash handles used for active and DFU partition.
34pub trait Flash: NorFlash {
35 /// The block size that should be used when writing to flash. For most builtin flashes, this is the same as the erase
36 /// size of the flash, but for external QSPI flash modules, this can be lower.
37 const BLOCK_SIZE: usize;
38 /// The erase value of the flash. Typically the default of 0xFF is used, but some flashes use a different value.
39 const ERASE_VALUE: u8 = 0xFF;
40}
41
42/// Trait defining the flash handles used for active and DFU partition
43pub trait FlashConfig { 34pub trait FlashConfig {
35 /// The erase value of the state flash. Typically the default of 0xFF is used, but some flashes use a different value.
36 const STATE_ERASE_VALUE: u8 = 0xFF;
44 /// Flash type used for the state partition. 37 /// Flash type used for the state partition.
45 type STATE: Flash; 38 type STATE: NorFlash;
46 /// Flash type used for the active partition. 39 /// Flash type used for the active partition.
47 type ACTIVE: Flash; 40 type ACTIVE: NorFlash;
48 /// Flash type used for the dfu partition. 41 /// Flash type used for the dfu partition.
49 type DFU: Flash; 42 type DFU: NorFlash;
50 43
51 /// Return flash instance used to write/read to/from active partition. 44 /// Return flash instance used to write/read to/from active partition.
52 fn active(&mut self) -> &mut Self::ACTIVE; 45 fn active(&mut self) -> &mut Self::ACTIVE;
@@ -56,8 +49,18 @@ pub trait FlashConfig {
56 fn state(&mut self) -> &mut Self::STATE; 49 fn state(&mut self) -> &mut Self::STATE;
57} 50}
58 51
59/// BootLoader works with any flash implementing embedded_storage and can also work with 52trait FlashConfigEx {
60/// different page sizes and flash write sizes. 53 fn page_size() -> usize;
54}
55
56impl<T: FlashConfig> FlashConfigEx for T {
57 /// Get the page size which is the "unit of operation" within the bootloader.
58 fn page_size() -> usize {
59 core::cmp::max(T::ACTIVE::ERASE_SIZE, T::DFU::ERASE_SIZE)
60 }
61}
62
63/// BootLoader works with any flash implementing embedded_storage.
61pub struct BootLoader { 64pub struct BootLoader {
62 // Page with current state of bootloader. The state partition has the following format: 65 // Page with current state of bootloader. The state partition has the following format:
63 // All ranges are in multiples of WRITE_SIZE bytes. 66 // All ranges are in multiples of WRITE_SIZE bytes.
@@ -91,6 +94,9 @@ impl BootLoader {
91 /// The DFU partition is assumed to be 1 page bigger than the active partition for the swap 94 /// The DFU partition is assumed to be 1 page bigger than the active partition for the swap
92 /// algorithm to work correctly. 95 /// algorithm to work correctly.
93 /// 96 ///
97 /// The provided aligned_buf argument must satisfy any alignment requirements
98 /// given by the partition flashes. All flash operations will use this buffer.
99 ///
94 /// SWAPPING 100 /// SWAPPING
95 /// 101 ///
96 /// Assume a flash size of 3 pages for the active partition, and 4 pages for the DFU partition. 102 /// Assume a flash size of 3 pages for the active partition, and 4 pages for the DFU partition.
@@ -169,87 +175,95 @@ impl BootLoader {
169 /// | DFU | 3 | 3 | 2 | 1 | 3 | 175 /// | DFU | 3 | 3 | 2 | 1 | 3 |
170 /// +-----------+--------------+--------+--------+--------+--------+ 176 /// +-----------+--------------+--------+--------+--------+--------+
171 /// 177 ///
172 pub fn prepare_boot<P: FlashConfig>( 178 pub fn prepare_boot<P: FlashConfig>(&mut self, p: &mut P, aligned_buf: &mut [u8]) -> Result<State, BootError> {
173 &mut self,
174 p: &mut P,
175 magic: &mut [u8],
176 page: &mut [u8],
177 ) -> Result<State, BootError> {
178 // Ensure we have enough progress pages to store copy progress 179 // Ensure we have enough progress pages to store copy progress
179 assert_partitions(self.active, self.dfu, self.state, page.len(), P::STATE::WRITE_SIZE); 180 assert_eq!(0, P::page_size() % aligned_buf.len());
180 assert_eq!(magic.len(), P::STATE::WRITE_SIZE); 181 assert_eq!(0, P::page_size() % P::ACTIVE::WRITE_SIZE);
182 assert_eq!(0, P::page_size() % P::ACTIVE::ERASE_SIZE);
183 assert_eq!(0, P::page_size() % P::DFU::WRITE_SIZE);
184 assert_eq!(0, P::page_size() % P::DFU::ERASE_SIZE);
185 assert!(aligned_buf.len() >= P::STATE::WRITE_SIZE);
186 assert_eq!(0, aligned_buf.len() % P::ACTIVE::WRITE_SIZE);
187 assert_eq!(0, aligned_buf.len() % P::DFU::WRITE_SIZE);
188 assert_partitions(self.active, self.dfu, self.state, P::page_size(), P::STATE::WRITE_SIZE);
181 189
182 // Copy contents from partition N to active 190 // Copy contents from partition N to active
183 let state = self.read_state(p, magic)?; 191 let state = self.read_state(p, aligned_buf)?;
184 if state == State::Swap { 192 if state == State::Swap {
185 // 193 //
186 // Check if we already swapped. If we're in the swap state, this means we should revert 194 // Check if we already swapped. If we're in the swap state, this means we should revert
187 // since the app has failed to mark boot as successful 195 // since the app has failed to mark boot as successful
188 // 196 //
189 if !self.is_swapped(p, magic, page)? { 197 if !self.is_swapped(p, aligned_buf)? {
190 trace!("Swapping"); 198 trace!("Swapping");
191 self.swap(p, magic, page)?; 199 self.swap(p, aligned_buf)?;
192 trace!("Swapping done"); 200 trace!("Swapping done");
193 } else { 201 } else {
194 trace!("Reverting"); 202 trace!("Reverting");
195 self.revert(p, magic, page)?; 203 self.revert(p, aligned_buf)?;
196 204
197 let state_flash = p.state(); 205 let state_flash = p.state();
206 let state_word = &mut aligned_buf[..P::STATE::WRITE_SIZE];
198 207
199 // Invalidate progress 208 // Invalidate progress
200 magic.fill(!P::STATE::ERASE_VALUE); 209 state_word.fill(!P::STATE_ERASE_VALUE);
201 self.state 210 self.state
202 .write_blocking(state_flash, P::STATE::WRITE_SIZE as u32, magic)?; 211 .write_blocking(state_flash, P::STATE::WRITE_SIZE as u32, state_word)?;
203 212
204 // Clear magic and progress 213 // Clear magic and progress
205 self.state.wipe_blocking(state_flash)?; 214 self.state.wipe_blocking(state_flash)?;
206 215
207 // Set magic 216 // Set magic
208 magic.fill(BOOT_MAGIC); 217 state_word.fill(BOOT_MAGIC);
209 self.state.write_blocking(state_flash, 0, magic)?; 218 self.state.write_blocking(state_flash, 0, state_word)?;
210 } 219 }
211 } 220 }
212 Ok(state) 221 Ok(state)
213 } 222 }
214 223
215 fn is_swapped<P: FlashConfig>(&mut self, p: &mut P, magic: &mut [u8], page: &mut [u8]) -> Result<bool, BootError> { 224 fn is_swapped<P: FlashConfig>(&mut self, p: &mut P, aligned_buf: &mut [u8]) -> Result<bool, BootError> {
216 let page_size = page.len(); 225 let page_count = self.active.len() / P::page_size();
217 let page_count = self.active.len() / page_size; 226 let progress = self.current_progress(p, aligned_buf)?;
218 let progress = self.current_progress(p, magic)?;
219 227
220 Ok(progress >= page_count * 2) 228 Ok(progress >= page_count * 2)
221 } 229 }
222 230
223 fn current_progress<P: FlashConfig>(&mut self, config: &mut P, aligned: &mut [u8]) -> Result<usize, BootError> { 231 fn current_progress<P: FlashConfig>(&mut self, config: &mut P, aligned_buf: &mut [u8]) -> Result<usize, BootError> {
224 let write_size = aligned.len(); 232 let max_index = ((self.state.len() - P::STATE::WRITE_SIZE) / P::STATE::WRITE_SIZE) - 2;
225 let max_index = ((self.state.len() - write_size) / write_size) - 2;
226 aligned.fill(!P::STATE::ERASE_VALUE);
227
228 let state_flash = config.state(); 233 let state_flash = config.state();
234 let state_word = &mut aligned_buf[..P::STATE::WRITE_SIZE];
229 235
230 self.state 236 self.state
231 .read_blocking(state_flash, P::STATE::WRITE_SIZE as u32, aligned)?; 237 .read_blocking(state_flash, P::STATE::WRITE_SIZE as u32, state_word)?;
232 if aligned.iter().any(|&b| b != P::STATE::ERASE_VALUE) { 238 if state_word.iter().any(|&b| b != P::STATE_ERASE_VALUE) {
233 // Progress is invalid 239 // Progress is invalid
234 return Ok(max_index); 240 return Ok(max_index);
235 } 241 }
236 242
237 for index in 0..max_index { 243 for index in 0..max_index {
238 self.state 244 self.state.read_blocking(
239 .read_blocking(state_flash, (2 + index) as u32 * P::STATE::WRITE_SIZE as u32, aligned)?; 245 state_flash,
246 (2 + index) as u32 * P::STATE::WRITE_SIZE as u32,
247 state_word,
248 )?;
240 249
241 if aligned.iter().any(|&b| b == P::STATE::ERASE_VALUE) { 250 if state_word.iter().any(|&b| b == P::STATE_ERASE_VALUE) {
242 return Ok(index); 251 return Ok(index);
243 } 252 }
244 } 253 }
245 Ok(max_index) 254 Ok(max_index)
246 } 255 }
247 256
248 fn update_progress<P: FlashConfig>(&mut self, index: usize, p: &mut P, magic: &mut [u8]) -> Result<(), BootError> { 257 fn update_progress<P: FlashConfig>(
249 let aligned = magic; 258 &mut self,
250 aligned.fill(!P::STATE::ERASE_VALUE); 259 index: usize,
260 p: &mut P,
261 aligned_buf: &mut [u8],
262 ) -> Result<(), BootError> {
263 let state_word = &mut aligned_buf[..P::STATE::WRITE_SIZE];
264 state_word.fill(!P::STATE_ERASE_VALUE);
251 self.state 265 self.state
252 .write_blocking(p.state(), (2 + index) as u32 * P::STATE::WRITE_SIZE as u32, aligned)?; 266 .write_blocking(p.state(), (2 + index) as u32 * P::STATE::WRITE_SIZE as u32, state_word)?;
253 Ok(()) 267 Ok(())
254 } 268 }
255 269
@@ -259,26 +273,22 @@ impl BootLoader {
259 from_offset: u32, 273 from_offset: u32,
260 to_offset: u32, 274 to_offset: u32,
261 p: &mut P, 275 p: &mut P,
262 magic: &mut [u8], 276 aligned_buf: &mut [u8],
263 page: &mut [u8],
264 ) -> Result<(), BootError> { 277 ) -> Result<(), BootError> {
265 let buf = page; 278 if self.current_progress(p, aligned_buf)? <= idx {
266 if self.current_progress(p, magic)? <= idx { 279 let page_size = P::page_size() as u32;
267 let mut offset = from_offset;
268 for chunk in buf.chunks_mut(P::DFU::BLOCK_SIZE) {
269 self.dfu.read_blocking(p.dfu(), offset, chunk)?;
270 offset += chunk.len() as u32;
271 }
272 280
273 self.active 281 self.active
274 .erase_blocking(p.active(), to_offset, to_offset + buf.len() as u32)?; 282 .erase_blocking(p.active(), to_offset, to_offset + page_size)?;
275 283
276 let mut offset = to_offset; 284 for offset_in_page in (0..page_size).step_by(aligned_buf.len()) {
277 for chunk in buf.chunks(P::ACTIVE::BLOCK_SIZE) { 285 self.dfu
278 self.active.write_blocking(p.active(), offset, chunk)?; 286 .read_blocking(p.dfu(), from_offset + offset_in_page as u32, aligned_buf)?;
279 offset += chunk.len() as u32; 287 self.active
288 .write_blocking(p.active(), to_offset + offset_in_page as u32, aligned_buf)?;
280 } 289 }
281 self.update_progress(idx, p, magic)?; 290
291 self.update_progress(idx, p, aligned_buf)?;
282 } 292 }
283 Ok(()) 293 Ok(())
284 } 294 }
@@ -289,32 +299,28 @@ impl BootLoader {
289 from_offset: u32, 299 from_offset: u32,
290 to_offset: u32, 300 to_offset: u32,
291 p: &mut P, 301 p: &mut P,
292 magic: &mut [u8], 302 aligned_buf: &mut [u8],
293 page: &mut [u8],
294 ) -> Result<(), BootError> { 303 ) -> Result<(), BootError> {
295 let buf = page; 304 if self.current_progress(p, aligned_buf)? <= idx {
296 if self.current_progress(p, magic)? <= idx { 305 let page_size = P::page_size() as u32;
297 let mut offset = from_offset;
298 for chunk in buf.chunks_mut(P::ACTIVE::BLOCK_SIZE) {
299 self.active.read_blocking(p.active(), offset, chunk)?;
300 offset += chunk.len() as u32;
301 }
302 306
303 self.dfu 307 self.dfu
304 .erase_blocking(p.dfu(), to_offset as u32, to_offset + buf.len() as u32)?; 308 .erase_blocking(p.dfu(), to_offset as u32, to_offset + page_size)?;
305 309
306 let mut offset = to_offset; 310 for offset_in_page in (0..page_size).step_by(aligned_buf.len()) {
307 for chunk in buf.chunks(P::DFU::BLOCK_SIZE) { 311 self.active
308 self.dfu.write_blocking(p.dfu(), offset, chunk)?; 312 .read_blocking(p.active(), from_offset + offset_in_page as u32, aligned_buf)?;
309 offset += chunk.len() as u32; 313 self.dfu
314 .write_blocking(p.dfu(), to_offset + offset_in_page as u32, aligned_buf)?;
310 } 315 }
311 self.update_progress(idx, p, magic)?; 316
317 self.update_progress(idx, p, aligned_buf)?;
312 } 318 }
313 Ok(()) 319 Ok(())
314 } 320 }
315 321
316 fn swap<P: FlashConfig>(&mut self, p: &mut P, magic: &mut [u8], page: &mut [u8]) -> Result<(), BootError> { 322 fn swap<P: FlashConfig>(&mut self, p: &mut P, aligned_buf: &mut [u8]) -> Result<(), BootError> {
317 let page_size = page.len(); 323 let page_size = P::page_size();
318 let page_count = self.active.len() / page_size; 324 let page_count = self.active.len() / page_size;
319 trace!("Page count: {}", page_count); 325 trace!("Page count: {}", page_count);
320 for page_num in 0..page_count { 326 for page_num in 0..page_count {
@@ -326,20 +332,20 @@ impl BootLoader {
326 let active_from_offset = ((page_count - 1 - page_num) * page_size) as u32; 332 let active_from_offset = ((page_count - 1 - page_num) * page_size) as u32;
327 let dfu_to_offset = ((page_count - page_num) * page_size) as u32; 333 let dfu_to_offset = ((page_count - page_num) * page_size) as u32;
328 //trace!("Copy active {} to dfu {}", active_from_offset, dfu_to_offset); 334 //trace!("Copy active {} to dfu {}", active_from_offset, dfu_to_offset);
329 self.copy_page_once_to_dfu(idx, active_from_offset, dfu_to_offset, p, magic, page)?; 335 self.copy_page_once_to_dfu(idx, active_from_offset, dfu_to_offset, p, aligned_buf)?;
330 336
331 // Copy DFU page to the active page 337 // Copy DFU page to the active page
332 let active_to_offset = ((page_count - 1 - page_num) * page_size) as u32; 338 let active_to_offset = ((page_count - 1 - page_num) * page_size) as u32;
333 let dfu_from_offset = ((page_count - 1 - page_num) * page_size) as u32; 339 let dfu_from_offset = ((page_count - 1 - page_num) * page_size) as u32;
334 //trace!("Copy dfy {} to active {}", dfu_from_offset, active_to_offset); 340 //trace!("Copy dfy {} to active {}", dfu_from_offset, active_to_offset);
335 self.copy_page_once_to_active(idx + 1, dfu_from_offset, active_to_offset, p, magic, page)?; 341 self.copy_page_once_to_active(idx + 1, dfu_from_offset, active_to_offset, p, aligned_buf)?;
336 } 342 }
337 343
338 Ok(()) 344 Ok(())
339 } 345 }
340 346
341 fn revert<P: FlashConfig>(&mut self, p: &mut P, magic: &mut [u8], page: &mut [u8]) -> Result<(), BootError> { 347 fn revert<P: FlashConfig>(&mut self, p: &mut P, aligned_buf: &mut [u8]) -> Result<(), BootError> {
342 let page_size = page.len(); 348 let page_size = P::page_size();
343 let page_count = self.active.len() / page_size; 349 let page_count = self.active.len() / page_size;
344 for page_num in 0..page_count { 350 for page_num in 0..page_count {
345 let idx = page_count * 2 + page_num * 2; 351 let idx = page_count * 2 + page_num * 2;
@@ -347,21 +353,22 @@ impl BootLoader {
347 // Copy the bad active page to the DFU page 353 // Copy the bad active page to the DFU page
348 let active_from_offset = (page_num * page_size) as u32; 354 let active_from_offset = (page_num * page_size) as u32;
349 let dfu_to_offset = (page_num * page_size) as u32; 355 let dfu_to_offset = (page_num * page_size) as u32;
350 self.copy_page_once_to_dfu(idx, active_from_offset, dfu_to_offset, p, magic, page)?; 356 self.copy_page_once_to_dfu(idx, active_from_offset, dfu_to_offset, p, aligned_buf)?;
351 357
352 // Copy the DFU page back to the active page 358 // Copy the DFU page back to the active page
353 let active_to_offset = (page_num * page_size) as u32; 359 let active_to_offset = (page_num * page_size) as u32;
354 let dfu_from_offset = ((page_num + 1) * page_size) as u32; 360 let dfu_from_offset = ((page_num + 1) * page_size) as u32;
355 self.copy_page_once_to_active(idx + 1, dfu_from_offset, active_to_offset, p, magic, page)?; 361 self.copy_page_once_to_active(idx + 1, dfu_from_offset, active_to_offset, p, aligned_buf)?;
356 } 362 }
357 363
358 Ok(()) 364 Ok(())
359 } 365 }
360 366
361 fn read_state<P: FlashConfig>(&mut self, config: &mut P, magic: &mut [u8]) -> Result<State, BootError> { 367 fn read_state<P: FlashConfig>(&mut self, config: &mut P, aligned_buf: &mut [u8]) -> Result<State, BootError> {
362 self.state.read_blocking(config.state(), 0, magic)?; 368 let state_word = &mut aligned_buf[..P::STATE::WRITE_SIZE];
369 self.state.read_blocking(config.state(), 0, state_word)?;
363 370
364 if !magic.iter().any(|&b| b != SWAP_MAGIC) { 371 if !state_word.iter().any(|&b| b != SWAP_MAGIC) {
365 Ok(State::Swap) 372 Ok(State::Swap)
366 } else { 373 } else {
367 Ok(State::Boot) 374 Ok(State::Boot)
@@ -377,16 +384,16 @@ fn assert_partitions(active: Partition, dfu: Partition, state: Partition, page_s
377} 384}
378 385
379/// A flash wrapper implementing the Flash and embedded_storage traits. 386/// A flash wrapper implementing the Flash and embedded_storage traits.
380pub struct BootFlash<F, const BLOCK_SIZE: usize, const ERASE_VALUE: u8 = 0xFF> 387pub struct BootFlash<F>
381where 388where
382 F: NorFlash + ReadNorFlash, 389 F: NorFlash,
383{ 390{
384 flash: F, 391 flash: F,
385} 392}
386 393
387impl<F, const BLOCK_SIZE: usize, const ERASE_VALUE: u8> BootFlash<F, BLOCK_SIZE, ERASE_VALUE> 394impl<F> BootFlash<F>
388where 395where
389 F: NorFlash + ReadNorFlash, 396 F: NorFlash,
390{ 397{
391 /// Create a new instance of a bootable flash 398 /// Create a new instance of a bootable flash
392 pub fn new(flash: F) -> Self { 399 pub fn new(flash: F) -> Self {
@@ -394,24 +401,16 @@ where
394 } 401 }
395} 402}
396 403
397impl<F, const BLOCK_SIZE: usize, const ERASE_VALUE: u8> Flash for BootFlash<F, BLOCK_SIZE, ERASE_VALUE> 404impl<F> ErrorType for BootFlash<F>
398where
399 F: NorFlash + ReadNorFlash,
400{
401 const BLOCK_SIZE: usize = BLOCK_SIZE;
402 const ERASE_VALUE: u8 = ERASE_VALUE;
403}
404
405impl<F, const BLOCK_SIZE: usize, const ERASE_VALUE: u8> ErrorType for BootFlash<F, BLOCK_SIZE, ERASE_VALUE>
406where 405where
407 F: ReadNorFlash + NorFlash, 406 F: NorFlash,
408{ 407{
409 type Error = F::Error; 408 type Error = F::Error;
410} 409}
411 410
412impl<F, const BLOCK_SIZE: usize, const ERASE_VALUE: u8> NorFlash for BootFlash<F, BLOCK_SIZE, ERASE_VALUE> 411impl<F> NorFlash for BootFlash<F>
413where 412where
414 F: ReadNorFlash + NorFlash, 413 F: NorFlash,
415{ 414{
416 const WRITE_SIZE: usize = F::WRITE_SIZE; 415 const WRITE_SIZE: usize = F::WRITE_SIZE;
417 const ERASE_SIZE: usize = F::ERASE_SIZE; 416 const ERASE_SIZE: usize = F::ERASE_SIZE;
@@ -425,9 +424,9 @@ where
425 } 424 }
426} 425}
427 426
428impl<F, const BLOCK_SIZE: usize, const ERASE_VALUE: u8> ReadNorFlash for BootFlash<F, BLOCK_SIZE, ERASE_VALUE> 427impl<F> ReadNorFlash for BootFlash<F>
429where 428where
430 F: ReadNorFlash + NorFlash, 429 F: NorFlash,
431{ 430{
432 const READ_SIZE: usize = F::READ_SIZE; 431 const READ_SIZE: usize = F::READ_SIZE;
433 432
@@ -443,14 +442,14 @@ where
443/// Convenience provider that uses a single flash for all partitions. 442/// Convenience provider that uses a single flash for all partitions.
444pub struct SingleFlashConfig<'a, F> 443pub struct SingleFlashConfig<'a, F>
445where 444where
446 F: Flash, 445 F: NorFlash,
447{ 446{
448 flash: &'a mut F, 447 flash: &'a mut F,
449} 448}
450 449
451impl<'a, F> SingleFlashConfig<'a, F> 450impl<'a, F> SingleFlashConfig<'a, F>
452where 451where
453 F: Flash, 452 F: NorFlash,
454{ 453{
455 /// Create a provider for a single flash. 454 /// Create a provider for a single flash.
456 pub fn new(flash: &'a mut F) -> Self { 455 pub fn new(flash: &'a mut F) -> Self {
@@ -460,7 +459,7 @@ where
460 459
461impl<'a, F> FlashConfig for SingleFlashConfig<'a, F> 460impl<'a, F> FlashConfig for SingleFlashConfig<'a, F>
462where 461where
463 F: Flash, 462 F: NorFlash,
464{ 463{
465 type STATE = F; 464 type STATE = F;
466 type ACTIVE = F; 465 type ACTIVE = F;
@@ -480,9 +479,9 @@ where
480/// Convenience flash provider that uses separate flash instances for each partition. 479/// Convenience flash provider that uses separate flash instances for each partition.
481pub struct MultiFlashConfig<'a, ACTIVE, STATE, DFU> 480pub struct MultiFlashConfig<'a, ACTIVE, STATE, DFU>
482where 481where
483 ACTIVE: Flash, 482 ACTIVE: NorFlash,
484 STATE: Flash, 483 STATE: NorFlash,
485 DFU: Flash, 484 DFU: NorFlash,
486{ 485{
487 active: &'a mut ACTIVE, 486 active: &'a mut ACTIVE,
488 state: &'a mut STATE, 487 state: &'a mut STATE,
@@ -491,9 +490,9 @@ where
491 490
492impl<'a, ACTIVE, STATE, DFU> MultiFlashConfig<'a, ACTIVE, STATE, DFU> 491impl<'a, ACTIVE, STATE, DFU> MultiFlashConfig<'a, ACTIVE, STATE, DFU>
493where 492where
494 ACTIVE: Flash, 493 ACTIVE: NorFlash,
495 STATE: Flash, 494 STATE: NorFlash,
496 DFU: Flash, 495 DFU: NorFlash,
497{ 496{
498 /// Create a new flash provider with separate configuration for all three partitions. 497 /// Create a new flash provider with separate configuration for all three partitions.
499 pub fn new(active: &'a mut ACTIVE, state: &'a mut STATE, dfu: &'a mut DFU) -> Self { 498 pub fn new(active: &'a mut ACTIVE, state: &'a mut STATE, dfu: &'a mut DFU) -> Self {
@@ -503,9 +502,9 @@ where
503 502
504impl<'a, ACTIVE, STATE, DFU> FlashConfig for MultiFlashConfig<'a, ACTIVE, STATE, DFU> 503impl<'a, ACTIVE, STATE, DFU> FlashConfig for MultiFlashConfig<'a, ACTIVE, STATE, DFU>
505where 504where
506 ACTIVE: Flash, 505 ACTIVE: NorFlash,
507 STATE: Flash, 506 STATE: NorFlash,
508 DFU: Flash, 507 DFU: NorFlash,
509{ 508{
510 type STATE = STATE; 509 type STATE = STATE;
511 type ACTIVE = ACTIVE; 510 type ACTIVE = ACTIVE;
diff --git a/embassy-boot/boot/src/lib.rs b/embassy-boot/boot/src/lib.rs
index d4078f1cb..605e5253c 100644
--- a/embassy-boot/boot/src/lib.rs
+++ b/embassy-boot/boot/src/lib.rs
@@ -11,7 +11,7 @@ mod firmware_updater;
11mod mem_flash; 11mod mem_flash;
12mod partition; 12mod partition;
13 13
14pub use boot_loader::{BootError, BootFlash, BootLoader, Flash, FlashConfig, MultiFlashConfig, SingleFlashConfig}; 14pub use boot_loader::{BootError, BootFlash, BootLoader, FlashConfig, MultiFlashConfig, SingleFlashConfig};
15pub use firmware_updater::{FirmwareUpdater, FirmwareUpdaterError}; 15pub use firmware_updater::{FirmwareUpdater, FirmwareUpdaterError};
16pub use partition::Partition; 16pub use partition::Partition;
17 17
@@ -78,12 +78,8 @@ mod tests {
78 78
79 let mut bootloader: BootLoader = BootLoader::new(ACTIVE, DFU, STATE); 79 let mut bootloader: BootLoader = BootLoader::new(ACTIVE, DFU, STATE);
80 80
81 let mut magic = [0; 4];
82 let mut page = [0; 4096]; 81 let mut page = [0; 4096];
83 assert_eq!( 82 assert_eq!(State::Boot, bootloader.prepare_boot(&mut flash, &mut page).unwrap());
84 State::Boot,
85 bootloader.prepare_boot(&mut flash, &mut magic, &mut page).unwrap()
86 );
87 } 83 }
88 84
89 #[test] 85 #[test]
@@ -104,19 +100,14 @@ mod tests {
104 100
105 let mut bootloader: BootLoader = BootLoader::new(ACTIVE, DFU, STATE); 101 let mut bootloader: BootLoader = BootLoader::new(ACTIVE, DFU, STATE);
106 let mut updater = FirmwareUpdater::new(DFU, STATE); 102 let mut updater = FirmwareUpdater::new(DFU, STATE);
107 let mut offset = 0; 103 block_on(updater.write_firmware(0, &update, &mut flash)).unwrap();
108 for chunk in update.chunks(4096) {
109 block_on(updater.write_firmware(offset, chunk, &mut flash)).unwrap();
110 offset += chunk.len();
111 }
112 block_on(updater.mark_updated(&mut flash, &mut aligned)).unwrap(); 104 block_on(updater.mark_updated(&mut flash, &mut aligned)).unwrap();
113 105
114 let mut magic = [0; 4]; 106 let mut page = [0; 1024];
115 let mut page = [0; 4096];
116 assert_eq!( 107 assert_eq!(
117 State::Swap, 108 State::Swap,
118 bootloader 109 bootloader
119 .prepare_boot(&mut SingleFlashConfig::new(&mut flash), &mut magic, &mut page) 110 .prepare_boot(&mut SingleFlashConfig::new(&mut flash), &mut page)
120 .unwrap() 111 .unwrap()
121 ); 112 );
122 113
@@ -133,7 +124,7 @@ mod tests {
133 assert_eq!( 124 assert_eq!(
134 State::Swap, 125 State::Swap,
135 bootloader 126 bootloader
136 .prepare_boot(&mut SingleFlashConfig::new(&mut flash), &mut magic, &mut page) 127 .prepare_boot(&mut SingleFlashConfig::new(&mut flash), &mut page)
137 .unwrap() 128 .unwrap()
138 ); 129 );
139 130
@@ -151,7 +142,7 @@ mod tests {
151 assert_eq!( 142 assert_eq!(
152 State::Boot, 143 State::Boot,
153 bootloader 144 bootloader
154 .prepare_boot(&mut SingleFlashConfig::new(&mut flash), &mut magic, &mut page) 145 .prepare_boot(&mut SingleFlashConfig::new(&mut flash), &mut page)
155 .unwrap() 146 .unwrap()
156 ); 147 );
157 } 148 }
@@ -177,25 +168,16 @@ mod tests {
177 168
178 let mut updater = FirmwareUpdater::new(DFU, STATE); 169 let mut updater = FirmwareUpdater::new(DFU, STATE);
179 170
180 let mut offset = 0; 171 block_on(updater.write_firmware(0, &update, &mut dfu)).unwrap();
181 for chunk in update.chunks(2048) {
182 block_on(updater.write_firmware(offset, chunk, &mut dfu)).unwrap();
183 offset += chunk.len();
184 }
185 block_on(updater.mark_updated(&mut state, &mut aligned)).unwrap(); 172 block_on(updater.mark_updated(&mut state, &mut aligned)).unwrap();
186 173
187 let mut bootloader: BootLoader = BootLoader::new(ACTIVE, DFU, STATE); 174 let mut bootloader: BootLoader = BootLoader::new(ACTIVE, DFU, STATE);
188 let mut magic = [0; 4];
189 let mut page = [0; 4096]; 175 let mut page = [0; 4096];
190 176
191 assert_eq!( 177 assert_eq!(
192 State::Swap, 178 State::Swap,
193 bootloader 179 bootloader
194 .prepare_boot( 180 .prepare_boot(&mut MultiFlashConfig::new(&mut active, &mut state, &mut dfu), &mut page)
195 &mut MultiFlashConfig::new(&mut active, &mut state, &mut dfu),
196 &mut magic,
197 &mut page
198 )
199 .unwrap() 181 .unwrap()
200 ); 182 );
201 183
@@ -230,22 +212,16 @@ mod tests {
230 212
231 let mut updater = FirmwareUpdater::new(DFU, STATE); 213 let mut updater = FirmwareUpdater::new(DFU, STATE);
232 214
233 let mut offset = 0; 215 block_on(updater.write_firmware(0, &update, &mut dfu)).unwrap();
234 for chunk in update.chunks(4096) {
235 block_on(updater.write_firmware(offset, chunk, &mut dfu)).unwrap();
236 offset += chunk.len();
237 }
238 block_on(updater.mark_updated(&mut state, &mut aligned)).unwrap(); 216 block_on(updater.mark_updated(&mut state, &mut aligned)).unwrap();
239 217
240 let mut bootloader: BootLoader = BootLoader::new(ACTIVE, DFU, STATE); 218 let mut bootloader: BootLoader = BootLoader::new(ACTIVE, DFU, STATE);
241 let mut magic = [0; 4];
242 let mut page = [0; 4096]; 219 let mut page = [0; 4096];
243 assert_eq!( 220 assert_eq!(
244 State::Swap, 221 State::Swap,
245 bootloader 222 bootloader
246 .prepare_boot( 223 .prepare_boot(
247 &mut MultiFlashConfig::new(&mut active, &mut state, &mut dfu,), 224 &mut MultiFlashConfig::new(&mut active, &mut state, &mut dfu,),
248 &mut magic,
249 &mut page 225 &mut page
250 ) 226 )
251 .unwrap() 227 .unwrap()
diff --git a/embassy-boot/boot/src/mem_flash.rs b/embassy-boot/boot/src/mem_flash.rs
index 828aad9d9..dd85405c8 100644
--- a/embassy-boot/boot/src/mem_flash.rs
+++ b/embassy-boot/boot/src/mem_flash.rs
@@ -5,8 +5,6 @@ use core::ops::{Bound, Range, RangeBounds};
5use embedded_storage::nor_flash::{ErrorType, NorFlash, NorFlashError, NorFlashErrorKind, ReadNorFlash}; 5use embedded_storage::nor_flash::{ErrorType, NorFlash, NorFlashError, NorFlashErrorKind, ReadNorFlash};
6use embedded_storage_async::nor_flash::{NorFlash as AsyncNorFlash, ReadNorFlash as AsyncReadNorFlash}; 6use embedded_storage_async::nor_flash::{NorFlash as AsyncNorFlash, ReadNorFlash as AsyncReadNorFlash};
7 7
8use crate::Flash;
9
10pub struct MemFlash<const SIZE: usize, const ERASE_SIZE: usize, const WRITE_SIZE: usize> { 8pub struct MemFlash<const SIZE: usize, const ERASE_SIZE: usize, const WRITE_SIZE: usize> {
11 pub mem: [u8; SIZE], 9 pub mem: [u8; SIZE],
12 pub pending_write_successes: Option<usize>, 10 pub pending_write_successes: Option<usize>,
@@ -44,13 +42,6 @@ impl<const SIZE: usize, const ERASE_SIZE: usize, const WRITE_SIZE: usize> Defaul
44 } 42 }
45} 43}
46 44
47impl<const SIZE: usize, const ERASE_SIZE: usize, const WRITE_SIZE: usize> Flash
48 for MemFlash<SIZE, ERASE_SIZE, WRITE_SIZE>
49{
50 const BLOCK_SIZE: usize = ERASE_SIZE;
51 const ERASE_VALUE: u8 = 0xFF;
52}
53
54impl<const SIZE: usize, const ERASE_SIZE: usize, const WRITE_SIZE: usize> ErrorType 45impl<const SIZE: usize, const ERASE_SIZE: usize, const WRITE_SIZE: usize> ErrorType
55 for MemFlash<SIZE, ERASE_SIZE, WRITE_SIZE> 46 for MemFlash<SIZE, ERASE_SIZE, WRITE_SIZE>
56{ 47{
diff --git a/embassy-boot/nrf/src/lib.rs b/embassy-boot/nrf/src/lib.rs
index f40ae62d6..a2176f609 100644
--- a/embassy-boot/nrf/src/lib.rs
+++ b/embassy-boot/nrf/src/lib.rs
@@ -11,13 +11,12 @@ use embassy_nrf::wdt;
11use embedded_storage::nor_flash::{ErrorType, NorFlash, ReadNorFlash}; 11use embedded_storage::nor_flash::{ErrorType, NorFlash, ReadNorFlash};
12 12
13/// A bootloader for nRF devices. 13/// A bootloader for nRF devices.
14pub struct BootLoader { 14pub struct BootLoader<const BUFFER_SIZE: usize = PAGE_SIZE> {
15 boot: embassy_boot::BootLoader, 15 boot: embassy_boot::BootLoader,
16 magic: AlignedBuffer<4>, 16 aligned_buf: AlignedBuffer<BUFFER_SIZE>,
17 page: AlignedBuffer<PAGE_SIZE>,
18} 17}
19 18
20impl Default for BootLoader { 19impl Default for BootLoader<PAGE_SIZE> {
21 /// Create a new bootloader instance using parameters from linker script 20 /// Create a new bootloader instance using parameters from linker script
22 fn default() -> Self { 21 fn default() -> Self {
23 extern "C" { 22 extern "C" {
@@ -56,20 +55,19 @@ impl Default for BootLoader {
56 } 55 }
57} 56}
58 57
59impl BootLoader { 58impl<const BUFFER_SIZE: usize> BootLoader<BUFFER_SIZE> {
60 /// Create a new bootloader instance using the supplied partitions for active, dfu and state. 59 /// Create a new bootloader instance using the supplied partitions for active, dfu and state.
61 pub fn new(active: Partition, dfu: Partition, state: Partition) -> Self { 60 pub fn new(active: Partition, dfu: Partition, state: Partition) -> Self {
62 Self { 61 Self {
63 boot: embassy_boot::BootLoader::new(active, dfu, state), 62 boot: embassy_boot::BootLoader::new(active, dfu, state),
64 magic: AlignedBuffer([0; 4]), 63 aligned_buf: AlignedBuffer([0; BUFFER_SIZE]),
65 page: AlignedBuffer([0; PAGE_SIZE]),
66 } 64 }
67 } 65 }
68 66
69 /// Inspect the bootloader state and perform actions required before booting, such as swapping 67 /// Inspect the bootloader state and perform actions required before booting, such as swapping
70 /// firmware. 68 /// firmware.
71 pub fn prepare<F: FlashConfig>(&mut self, flash: &mut F) -> usize { 69 pub fn prepare<F: FlashConfig>(&mut self, flash: &mut F) -> usize {
72 match self.boot.prepare_boot(flash, &mut self.magic.0, &mut self.page.0) { 70 match self.boot.prepare_boot(flash, &mut self.aligned_buf.0) {
73 Ok(_) => self.boot.boot_address(), 71 Ok(_) => self.boot.boot_address(),
74 Err(_) => panic!("boot prepare error!"), 72 Err(_) => panic!("boot prepare error!"),
75 } 73 }
diff --git a/embassy-boot/rp/src/lib.rs b/embassy-boot/rp/src/lib.rs
index 6df34133e..0031efa63 100644
--- a/embassy-boot/rp/src/lib.rs
+++ b/embassy-boot/rp/src/lib.rs
@@ -5,33 +5,31 @@
5mod fmt; 5mod fmt;
6 6
7pub use embassy_boot::{AlignedBuffer, BootFlash, FirmwareUpdater, FlashConfig, Partition, SingleFlashConfig, State}; 7pub use embassy_boot::{AlignedBuffer, BootFlash, FirmwareUpdater, FlashConfig, Partition, SingleFlashConfig, State};
8use embassy_rp::flash::{Flash, ERASE_SIZE, WRITE_SIZE}; 8use embassy_rp::flash::{Flash, ERASE_SIZE};
9use embassy_rp::peripherals::{FLASH, WATCHDOG}; 9use embassy_rp::peripherals::{FLASH, WATCHDOG};
10use embassy_rp::watchdog::Watchdog; 10use embassy_rp::watchdog::Watchdog;
11use embassy_time::Duration; 11use embassy_time::Duration;
12use embedded_storage::nor_flash::{ErrorType, NorFlash, ReadNorFlash}; 12use embedded_storage::nor_flash::{ErrorType, NorFlash, ReadNorFlash};
13 13
14/// A bootloader for RP2040 devices. 14/// A bootloader for RP2040 devices.
15pub struct BootLoader { 15pub struct BootLoader<const BUFFER_SIZE: usize = ERASE_SIZE> {
16 boot: embassy_boot::BootLoader, 16 boot: embassy_boot::BootLoader,
17 magic: AlignedBuffer<WRITE_SIZE>, 17 aligned_buf: AlignedBuffer<BUFFER_SIZE>,
18 page: AlignedBuffer<ERASE_SIZE>,
19} 18}
20 19
21impl BootLoader { 20impl<const BUFFER_SIZE: usize> BootLoader<BUFFER_SIZE> {
22 /// Create a new bootloader instance using the supplied partitions for active, dfu and state. 21 /// Create a new bootloader instance using the supplied partitions for active, dfu and state.
23 pub fn new(active: Partition, dfu: Partition, state: Partition) -> Self { 22 pub fn new(active: Partition, dfu: Partition, state: Partition) -> Self {
24 Self { 23 Self {
25 boot: embassy_boot::BootLoader::new(active, dfu, state), 24 boot: embassy_boot::BootLoader::new(active, dfu, state),
26 magic: AlignedBuffer([0; WRITE_SIZE]), 25 aligned_buf: AlignedBuffer([0; BUFFER_SIZE]),
27 page: AlignedBuffer([0; ERASE_SIZE]),
28 } 26 }
29 } 27 }
30 28
31 /// Inspect the bootloader state and perform actions required before booting, such as swapping 29 /// Inspect the bootloader state and perform actions required before booting, such as swapping
32 /// firmware. 30 /// firmware.
33 pub fn prepare<F: FlashConfig>(&mut self, flash: &mut F) -> usize { 31 pub fn prepare<F: FlashConfig>(&mut self, flash: &mut F) -> usize {
34 match self.boot.prepare_boot(flash, self.magic.as_mut(), self.page.as_mut()) { 32 match self.boot.prepare_boot(flash, self.aligned_buf.as_mut()) {
35 Ok(_) => embassy_rp::flash::FLASH_BASE + self.boot.boot_address(), 33 Ok(_) => embassy_rp::flash::FLASH_BASE + self.boot.boot_address(),
36 Err(_) => panic!("boot prepare error!"), 34 Err(_) => panic!("boot prepare error!"),
37 } 35 }
@@ -54,7 +52,7 @@ impl BootLoader {
54 } 52 }
55} 53}
56 54
57impl Default for BootLoader { 55impl Default for BootLoader<ERASE_SIZE> {
58 /// Create a new bootloader instance using parameters from linker script 56 /// Create a new bootloader instance using parameters from linker script
59 fn default() -> Self { 57 fn default() -> Self {
60 extern "C" { 58 extern "C" {
diff --git a/embassy-boot/stm32/src/lib.rs b/embassy-boot/stm32/src/lib.rs
index 82f712c4d..1f63fcd63 100644
--- a/embassy-boot/stm32/src/lib.rs
+++ b/embassy-boot/stm32/src/lib.rs
@@ -7,26 +7,24 @@ mod fmt;
7pub use embassy_boot::{AlignedBuffer, BootFlash, FirmwareUpdater, FlashConfig, Partition, SingleFlashConfig, State}; 7pub use embassy_boot::{AlignedBuffer, BootFlash, FirmwareUpdater, FlashConfig, Partition, SingleFlashConfig, State};
8 8
9/// A bootloader for STM32 devices. 9/// A bootloader for STM32 devices.
10pub struct BootLoader<const PAGE_SIZE: usize, const WRITE_SIZE: usize> { 10pub struct BootLoader<const BUFFER_SIZE: usize> {
11 boot: embassy_boot::BootLoader, 11 boot: embassy_boot::BootLoader,
12 magic: AlignedBuffer<WRITE_SIZE>, 12 aligned_buf: AlignedBuffer<BUFFER_SIZE>,
13 page: AlignedBuffer<PAGE_SIZE>,
14} 13}
15 14
16impl<const PAGE_SIZE: usize, const WRITE_SIZE: usize> BootLoader<PAGE_SIZE, WRITE_SIZE> { 15impl<const BUFFER_SIZE: usize> BootLoader<BUFFER_SIZE> {
17 /// Create a new bootloader instance using the supplied partitions for active, dfu and state. 16 /// Create a new bootloader instance using the supplied partitions for active, dfu and state.
18 pub fn new(active: Partition, dfu: Partition, state: Partition) -> Self { 17 pub fn new(active: Partition, dfu: Partition, state: Partition) -> Self {
19 Self { 18 Self {
20 boot: embassy_boot::BootLoader::new(active, dfu, state), 19 boot: embassy_boot::BootLoader::new(active, dfu, state),
21 magic: AlignedBuffer([0; WRITE_SIZE]), 20 aligned_buf: AlignedBuffer([0; BUFFER_SIZE]),
22 page: AlignedBuffer([0; PAGE_SIZE]),
23 } 21 }
24 } 22 }
25 23
26 /// Inspect the bootloader state and perform actions required before booting, such as swapping 24 /// Inspect the bootloader state and perform actions required before booting, such as swapping
27 /// firmware. 25 /// firmware.
28 pub fn prepare<F: FlashConfig>(&mut self, flash: &mut F) -> usize { 26 pub fn prepare<F: FlashConfig>(&mut self, flash: &mut F) -> usize {
29 match self.boot.prepare_boot(flash, self.magic.as_mut(), self.page.as_mut()) { 27 match self.boot.prepare_boot(flash, self.aligned_buf.as_mut()) {
30 Ok(_) => embassy_stm32::flash::FLASH_BASE + self.boot.boot_address(), 28 Ok(_) => embassy_stm32::flash::FLASH_BASE + self.boot.boot_address(),
31 Err(_) => panic!("boot prepare error!"), 29 Err(_) => panic!("boot prepare error!"),
32 } 30 }
@@ -49,7 +47,7 @@ impl<const PAGE_SIZE: usize, const WRITE_SIZE: usize> BootLoader<PAGE_SIZE, WRIT
49 } 47 }
50} 48}
51 49
52impl<const PAGE_SIZE: usize, const WRITE_SIZE: usize> Default for BootLoader<PAGE_SIZE, WRITE_SIZE> { 50impl<const BUFFER_SIZE: usize> Default for BootLoader<BUFFER_SIZE> {
53 /// Create a new bootloader instance using parameters from linker script 51 /// Create a new bootloader instance using parameters from linker script
54 fn default() -> Self { 52 fn default() -> Self {
55 extern "C" { 53 extern "C" {
diff --git a/examples/boot/bootloader/nrf/src/main.rs b/examples/boot/bootloader/nrf/src/main.rs
index aca3b857a..8818a23b8 100644
--- a/examples/boot/bootloader/nrf/src/main.rs
+++ b/examples/boot/bootloader/nrf/src/main.rs
@@ -27,9 +27,11 @@ fn main() -> ! {
27 wdt_config.run_during_sleep = true; 27 wdt_config.run_during_sleep = true;
28 wdt_config.run_during_debug_halt = false; 28 wdt_config.run_during_debug_halt = false;
29 29
30 let start = bl.prepare(&mut SingleFlashConfig::new(&mut BootFlash::<_, 4096>::new( 30 let start = bl.prepare(&mut SingleFlashConfig::new(&mut BootFlash::new(WatchdogFlash::start(
31 WatchdogFlash::start(Nvmc::new(p.NVMC), p.WDT, wdt_config), 31 Nvmc::new(p.NVMC),
32 ))); 32 p.WDT,
33 wdt_config,
34 ))));
33 unsafe { bl.load(start) } 35 unsafe { bl.load(start) }
34} 36}
35 37
diff --git a/examples/boot/bootloader/rp/src/main.rs b/examples/boot/bootloader/rp/src/main.rs
index fb7f0522b..8129591fa 100644
--- a/examples/boot/bootloader/rp/src/main.rs
+++ b/examples/boot/bootloader/rp/src/main.rs
@@ -5,7 +5,6 @@ use cortex_m_rt::{entry, exception};
5#[cfg(feature = "defmt")] 5#[cfg(feature = "defmt")]
6use defmt_rtt as _; 6use defmt_rtt as _;
7use embassy_boot_rp::*; 7use embassy_boot_rp::*;
8use embassy_rp::flash::ERASE_SIZE;
9use embassy_time::Duration; 8use embassy_time::Duration;
10 9
11const FLASH_SIZE: usize = 2 * 1024 * 1024; 10const FLASH_SIZE: usize = 2 * 1024 * 1024;
@@ -24,7 +23,7 @@ fn main() -> ! {
24 23
25 let mut bl: BootLoader = BootLoader::default(); 24 let mut bl: BootLoader = BootLoader::default();
26 let flash = WatchdogFlash::<FLASH_SIZE>::start(p.FLASH, p.WATCHDOG, Duration::from_secs(8)); 25 let flash = WatchdogFlash::<FLASH_SIZE>::start(p.FLASH, p.WATCHDOG, Duration::from_secs(8));
27 let mut flash = BootFlash::<_, ERASE_SIZE>::new(flash); 26 let mut flash = BootFlash::new(flash);
28 let start = bl.prepare(&mut SingleFlashConfig::new(&mut flash)); 27 let start = bl.prepare(&mut SingleFlashConfig::new(&mut flash));
29 core::mem::drop(flash); 28 core::mem::drop(flash);
30 29
diff --git a/examples/boot/bootloader/stm32/src/main.rs b/examples/boot/bootloader/stm32/src/main.rs
index 4b17cd799..b8027d19a 100644
--- a/examples/boot/bootloader/stm32/src/main.rs
+++ b/examples/boot/bootloader/stm32/src/main.rs
@@ -5,7 +5,7 @@ use cortex_m_rt::{entry, exception};
5#[cfg(feature = "defmt")] 5#[cfg(feature = "defmt")]
6use defmt_rtt as _; 6use defmt_rtt as _;
7use embassy_boot_stm32::*; 7use embassy_boot_stm32::*;
8use embassy_stm32::flash::{Flash, ERASE_SIZE, ERASE_VALUE, WRITE_SIZE}; 8use embassy_stm32::flash::{Flash, ERASE_SIZE};
9 9
10#[entry] 10#[entry]
11fn main() -> ! { 11fn main() -> ! {
@@ -19,9 +19,9 @@ fn main() -> ! {
19 } 19 }
20 */ 20 */
21 21
22 let mut bl: BootLoader<ERASE_SIZE, WRITE_SIZE> = BootLoader::default(); 22 let mut bl: BootLoader<ERASE_SIZE> = BootLoader::default();
23 let flash = Flash::new(p.FLASH); 23 let flash = Flash::new(p.FLASH);
24 let mut flash = BootFlash::<_, ERASE_SIZE, ERASE_VALUE>::new(flash); 24 let mut flash = BootFlash::new(flash);
25 let start = bl.prepare(&mut SingleFlashConfig::new(&mut flash)); 25 let start = bl.prepare(&mut SingleFlashConfig::new(&mut flash));
26 core::mem::drop(flash); 26 core::mem::drop(flash);
27 unsafe { bl.load(start) } 27 unsafe { bl.load(start) }