diff options
| -rw-r--r-- | embassy-rp/src/flash.rs | 56 |
1 files changed, 53 insertions, 3 deletions
diff --git a/embassy-rp/src/flash.rs b/embassy-rp/src/flash.rs index 1ff2fd195..7a26085b6 100644 --- a/embassy-rp/src/flash.rs +++ b/embassy-rp/src/flash.rs | |||
| @@ -1,5 +1,6 @@ | |||
| 1 | use embedded_storage::nor_flash::{ | 1 | use embedded_storage::nor_flash::{ |
| 2 | check_erase, check_read, check_write, ErrorType, NorFlash, NorFlashError, NorFlashErrorKind, ReadNorFlash, | 2 | check_erase, check_read, check_write, ErrorType, MultiwriteNorFlash, NorFlash, NorFlashError, NorFlashErrorKind, |
| 3 | ReadNorFlash, | ||
| 3 | }; | 4 | }; |
| 4 | 5 | ||
| 5 | pub const FLASH_BASE: usize = 0x10000000; | 6 | pub const FLASH_BASE: usize = 0x10000000; |
| @@ -9,7 +10,8 @@ pub const FLASH_BASE: usize = 0x10000000; | |||
| 9 | // These limitations are currently enforced because of using the | 10 | // These limitations are currently enforced because of using the |
| 10 | // RP2040 boot-rom flash functions, that are optimized for flash compatibility | 11 | // RP2040 boot-rom flash functions, that are optimized for flash compatibility |
| 11 | // rather than performance. | 12 | // rather than performance. |
| 12 | pub const WRITE_SIZE: usize = 256; | 13 | pub const PAGE_SIZE: usize = 256; |
| 14 | pub const WRITE_SIZE: usize = 1; | ||
| 13 | pub const READ_SIZE: usize = 1; | 15 | pub const READ_SIZE: usize = 1; |
| 14 | pub const ERASE_SIZE: usize = 4096; | 16 | pub const ERASE_SIZE: usize = 4096; |
| 15 | 17 | ||
| @@ -100,6 +102,8 @@ impl<const FLASH_SIZE: usize> ReadNorFlash for Flash<FLASH_SIZE> { | |||
| 100 | } | 102 | } |
| 101 | } | 103 | } |
| 102 | 104 | ||
| 105 | impl<const FLASH_SIZE: usize> MultiwriteNorFlash for Flash<FLASH_SIZE> {} | ||
| 106 | |||
| 103 | impl<const FLASH_SIZE: usize> NorFlash for Flash<FLASH_SIZE> { | 107 | impl<const FLASH_SIZE: usize> NorFlash for Flash<FLASH_SIZE> { |
| 104 | const WRITE_SIZE: usize = WRITE_SIZE; | 108 | const WRITE_SIZE: usize = WRITE_SIZE; |
| 105 | 109 | ||
| @@ -120,12 +124,58 @@ impl<const FLASH_SIZE: usize> NorFlash for Flash<FLASH_SIZE> { | |||
| 120 | 124 | ||
| 121 | trace!("Writing {:?} bytes to 0x{:x}", bytes.len(), offset); | 125 | trace!("Writing {:?} bytes to 0x{:x}", bytes.len(), offset); |
| 122 | 126 | ||
| 123 | unsafe { self.in_ram(|| ram_helpers::flash_range_program(offset, bytes, true)) }; | 127 | let end_offset = offset as usize + bytes.len(); |
| 128 | |||
| 129 | let padded_offset = (offset as *const u8).align_offset(PAGE_SIZE); | ||
| 130 | let start_padding = core::cmp::min(padded_offset, bytes.len()); | ||
| 131 | |||
| 132 | // Pad in the beginning | ||
| 133 | if start_padding > 0 { | ||
| 134 | let start = PAGE_SIZE - padded_offset; | ||
| 135 | let end = start + start_padding; | ||
| 136 | |||
| 137 | let mut pad_buf = [0xFF_u8; PAGE_SIZE]; | ||
| 138 | pad_buf[start..end].copy_from_slice(&bytes[..start_padding]); | ||
| 139 | |||
| 140 | let unaligned_offset = offset as usize - start; | ||
| 141 | |||
| 142 | unsafe { self.in_ram(|| ram_helpers::flash_range_program(unaligned_offset as u32, &pad_buf, true)) } | ||
| 143 | } | ||
| 144 | |||
| 145 | let remaining_len = bytes.len() - start_padding; | ||
| 146 | let end_padding = start_padding + PAGE_SIZE * (remaining_len / PAGE_SIZE); | ||
| 147 | |||
| 148 | // Write aligned slice of length in multiples of 256 bytes | ||
| 149 | // If the remaining bytes to be written is more than a full page. | ||
| 150 | if remaining_len >= PAGE_SIZE { | ||
| 151 | let aligned_data = &bytes[start_padding..end_padding]; | ||
| 152 | |||
| 153 | let aligned_offset = if start_padding > 0 { | ||
| 154 | offset as usize + padded_offset | ||
| 155 | } else { | ||
| 156 | offset as usize | ||
| 157 | }; | ||
| 158 | |||
| 159 | unsafe { self.in_ram(|| ram_helpers::flash_range_program(aligned_offset as u32, aligned_data, true)) } | ||
| 160 | } | ||
| 161 | |||
| 162 | // Pad in the end | ||
| 163 | let rem_offset = (end_offset as *const u8).align_offset(PAGE_SIZE); | ||
| 164 | let rem_padding = remaining_len % PAGE_SIZE; | ||
| 165 | if rem_padding > 0 { | ||
| 166 | let mut pad_buf = [0xFF_u8; PAGE_SIZE]; | ||
| 167 | pad_buf[..rem_padding].copy_from_slice(&bytes[end_padding..]); | ||
| 168 | |||
| 169 | let unaligned_offset = end_offset - (PAGE_SIZE - rem_offset); | ||
| 170 | |||
| 171 | unsafe { self.in_ram(|| ram_helpers::flash_range_program(unaligned_offset as u32, &pad_buf, true)) } | ||
| 172 | } | ||
| 124 | 173 | ||
| 125 | Ok(()) | 174 | Ok(()) |
| 126 | } | 175 | } |
| 127 | } | 176 | } |
| 128 | 177 | ||
| 178 | #[allow(dead_code)] | ||
| 129 | mod ram_helpers { | 179 | mod ram_helpers { |
| 130 | use core::marker::PhantomData; | 180 | use core::marker::PhantomData; |
| 131 | 181 | ||
