aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRasmus Melchior Jacobsen <[email protected]>2023-03-29 13:37:10 +0200
committerRasmus Melchior Jacobsen <[email protected]>2023-03-29 13:37:45 +0200
commitddbd5098658612e1421cdd081956c3e6ee3c92f8 (patch)
tree034c1bd8447aad4646bcd658cbfbf29d6be90201
parent69944675a3c35a8479fa3b1499246c0f3f971d95 (diff)
Move as much logic from families to shared module as possible
-rw-r--r--embassy-stm32/src/flash/f3.rs40
-rw-r--r--embassy-stm32/src/flash/f4.rs15
-rw-r--r--embassy-stm32/src/flash/f7.rs14
-rw-r--r--embassy-stm32/src/flash/h7.rs17
-rw-r--r--embassy-stm32/src/flash/l.rs81
-rw-r--r--embassy-stm32/src/flash/mod.rs135
6 files changed, 122 insertions, 180 deletions
diff --git a/embassy-stm32/src/flash/f3.rs b/embassy-stm32/src/flash/f3.rs
index 3da3962e8..7b339ccc5 100644
--- a/embassy-stm32/src/flash/f3.rs
+++ b/embassy-stm32/src/flash/f3.rs
@@ -41,33 +41,31 @@ pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE])
41 blocking_wait_ready() 41 blocking_wait_ready()
42} 42}
43 43
44pub(crate) unsafe fn blocking_erase(start_address: u32, end_address: u32) -> Result<(), Error> { 44pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> {
45 for page in (start_address..end_address).step_by(ERASE_SIZE) { 45 pac::FLASH.cr().modify(|w| {
46 pac::FLASH.cr().modify(|w| { 46 w.set_per(true);
47 w.set_per(true); 47 });
48 });
49 48
50 pac::FLASH.ar().write(|w| w.set_far(page)); 49 pac::FLASH.ar().write(|w| w.set_far(sector.first));
51 50
52 pac::FLASH.cr().modify(|w| { 51 pac::FLASH.cr().modify(|w| {
53 w.set_strt(true); 52 w.set_strt(true);
54 }); 53 });
55 54
56 let mut ret: Result<(), Error> = blocking_wait_ready(); 55 let mut ret: Result<(), Error> = blocking_wait_ready();
57 56
58 if !pac::FLASH.sr().read().eop() { 57 if !pac::FLASH.sr().read().eop() {
59 trace!("FLASH: EOP not set"); 58 trace!("FLASH: EOP not set");
60 ret = Err(Error::Prog); 59 ret = Err(Error::Prog);
61 } else { 60 } else {
62 pac::FLASH.sr().write(|w| w.set_eop(true)); 61 pac::FLASH.sr().write(|w| w.set_eop(true));
63 } 62 }
64 63
65 pac::FLASH.cr().modify(|w| w.set_per(false)); 64 pac::FLASH.cr().modify(|w| w.set_per(false));
66 65
67 clear_all_err(); 66 clear_all_err();
68 if ret.is_err() { 67 if ret.is_err() {
69 return ret; 68 return ret;
70 }
71 } 69 }
72 Ok(()) 70 Ok(())
73} 71}
diff --git a/embassy-stm32/src/flash/f4.rs b/embassy-stm32/src/flash/f4.rs
index 306359be1..cb420c69f 100644
--- a/embassy-stm32/src/flash/f4.rs
+++ b/embassy-stm32/src/flash/f4.rs
@@ -63,17 +63,8 @@ pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE])
63 blocking_wait_ready() 63 blocking_wait_ready()
64} 64}
65 65
66pub(crate) unsafe fn blocking_erase(start_address: u32, end_address: u32) -> Result<(), Error> { 66pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> {
67 let mut address = start_address; 67 let sector = sector.index;
68 while address < end_address {
69 let sector = get_sector(address);
70 erase_sector(sector.index)?;
71 address += sector.size;
72 }
73 Ok(())
74}
75
76unsafe fn erase_sector(sector: u8) -> Result<(), Error> {
77 let bank = sector / SECOND_BANK_SECTOR_OFFSET as u8; 68 let bank = sector / SECOND_BANK_SECTOR_OFFSET as u8;
78 let snb = (bank << 4) + (sector % SECOND_BANK_SECTOR_OFFSET as u8); 69 let snb = (bank << 4) + (sector % SECOND_BANK_SECTOR_OFFSET as u8);
79 70
@@ -132,7 +123,7 @@ unsafe fn blocking_wait_ready() -> Result<(), Error> {
132} 123}
133 124
134pub(crate) fn get_sector(address: u32) -> FlashSector { 125pub(crate) fn get_sector(address: u32) -> FlashSector {
135 get_sector_inner(address, is_dual_bank(), FLASH_SIZE) 126 get_sector_inner(address, is_dual_bank(), FLASH_SIZE as u32)
136} 127}
137 128
138fn get_sector_inner(address: u32, dual_bank: bool, flash_size: u32) -> FlashSector { 129fn get_sector_inner(address: u32, dual_bank: bool, flash_size: u32) -> FlashSector {
diff --git a/embassy-stm32/src/flash/f7.rs b/embassy-stm32/src/flash/f7.rs
index 588fc7a59..eba7df467 100644
--- a/embassy-stm32/src/flash/f7.rs
+++ b/embassy-stm32/src/flash/f7.rs
@@ -45,20 +45,10 @@ pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE])
45 blocking_wait_ready() 45 blocking_wait_ready()
46} 46}
47 47
48pub(crate) unsafe fn blocking_erase(start_address: u32, end_address: u32) -> Result<(), Error> { 48pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> {
49 let mut address = start_address;
50 while address < end_address {
51 let sector = get_sector(address);
52 erase_sector(sector.index)?;
53 address += sector.size;
54 }
55 Ok(())
56}
57
58unsafe fn erase_sector(sector: u8) -> Result<(), Error> {
59 pac::FLASH.cr().modify(|w| { 49 pac::FLASH.cr().modify(|w| {
60 w.set_ser(true); 50 w.set_ser(true);
61 w.set_snb(sector) 51 w.set_snb(sector.index)
62 }); 52 });
63 53
64 pac::FLASH.cr().modify(|w| { 54 pac::FLASH.cr().modify(|w| {
diff --git a/embassy-stm32/src/flash/h7.rs b/embassy-stm32/src/flash/h7.rs
index 732af8539..28999999d 100644
--- a/embassy-stm32/src/flash/h7.rs
+++ b/embassy-stm32/src/flash/h7.rs
@@ -78,20 +78,9 @@ pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE])
78 res.unwrap() 78 res.unwrap()
79} 79}
80 80
81pub(crate) unsafe fn blocking_erase(start_address: u32, end_address: u32) -> Result<(), Error> { 81pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> {
82 let start_sector = (start_address - super::FLASH_BASE as u32) / ERASE_SIZE as u32; 82 let bank = pac::FLASH::bank(if sector.index >= 8 { 1 } else { 0 });
83 let end_sector = (end_address - super::FLASH_BASE as u32) / ERASE_SIZE as u32; 83 let sector = sector.index % 8;
84 for sector in start_sector..end_sector {
85 let bank = if sector >= 8 { 1 } else { 0 };
86 let ret = erase_sector(pac::FLASH.bank(bank), (sector % 8) as u8);
87 if ret.is_err() {
88 return ret;
89 }
90 }
91 Ok(())
92}
93
94unsafe fn erase_sector(bank: pac::flash::Bank, sector: u8) -> Result<(), Error> {
95 bank.cr().modify(|w| { 84 bank.cr().modify(|w| {
96 w.set_ser(true); 85 w.set_ser(true);
97 w.set_snb(sector) 86 w.set_snb(sector)
diff --git a/embassy-stm32/src/flash/l.rs b/embassy-stm32/src/flash/l.rs
index 56a21885e..c8d060f0a 100644
--- a/embassy-stm32/src/flash/l.rs
+++ b/embassy-stm32/src/flash/l.rs
@@ -62,55 +62,50 @@ pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE])
62 blocking_wait_ready() 62 blocking_wait_ready()
63} 63}
64 64
65pub(crate) unsafe fn blocking_erase(start_address: u32, end_address: u32) -> Result<(), Error> { 65pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> {
66 for page in (start_address..end_address).step_by(ERASE_SIZE) { 66 #[cfg(any(flash_l0, flash_l1))]
67 #[cfg(any(flash_l0, flash_l1))] 67 {
68 { 68 pac::FLASH.pecr().modify(|w| {
69 pac::FLASH.pecr().modify(|w| { 69 w.set_erase(true);
70 w.set_erase(true); 70 w.set_prog(true);
71 w.set_prog(true); 71 });
72 });
73
74 write_volatile(page as *mut u32, 0xFFFFFFFF);
75 }
76 72
77 #[cfg(any(flash_wl, flash_wb, flash_l4))] 73 write_volatile(sector.start as *mut u32, 0xFFFFFFFF);
78 { 74 }
79 let idx = (page - super::FLASH_BASE as u32) / ERASE_SIZE as u32; 75
80 76 #[cfg(any(flash_wl, flash_wb, flash_l4))]
81 #[cfg(flash_l4)] 77 {
82 let (idx, bank) = if idx > 255 { (idx - 256, true) } else { (idx, false) }; 78 let idx = (sector.start - super::FLASH_BASE as u32) / ERASE_SIZE as u32;
83 79
84 pac::FLASH.cr().modify(|w| { 80 #[cfg(flash_l4)]
85 w.set_per(true); 81 let (idx, bank) = if idx > 255 { (idx - 256, true) } else { (idx, false) };
86 w.set_pnb(idx as u8); 82
87 #[cfg(any(flash_wl, flash_wb))] 83 pac::FLASH.cr().modify(|w| {
88 w.set_strt(true); 84 w.set_per(true);
89 #[cfg(any(flash_l4))] 85 w.set_pnb(idx as u8);
90 w.set_start(true); 86 #[cfg(any(flash_wl, flash_wb))]
91 #[cfg(any(flash_l4))] 87 w.set_strt(true);
92 w.set_bker(bank); 88 #[cfg(any(flash_l4))]
93 }); 89 w.set_start(true);
94 } 90 #[cfg(any(flash_l4))]
91 w.set_bker(bank);
92 });
93 }
95 94
96 let ret: Result<(), Error> = blocking_wait_ready(); 95 let ret: Result<(), Error> = blocking_wait_ready();
97 96
98 #[cfg(any(flash_wl, flash_wb, flash_l4))] 97 #[cfg(any(flash_wl, flash_wb, flash_l4))]
99 pac::FLASH.cr().modify(|w| w.set_per(false)); 98 pac::FLASH.cr().modify(|w| w.set_per(false));
100 99
101 #[cfg(any(flash_l0, flash_l1))] 100 #[cfg(any(flash_l0, flash_l1))]
102 pac::FLASH.pecr().modify(|w| { 101 pac::FLASH.pecr().modify(|w| {
103 w.set_erase(false); 102 w.set_erase(false);
104 w.set_prog(false); 103 w.set_prog(false);
105 }); 104 });
106 105
107 clear_all_err(); 106 clear_all_err();
108 if ret.is_err() {
109 return ret;
110 }
111 }
112 107
113 Ok(()) 108 ret
114} 109}
115 110
116pub(crate) unsafe fn clear_all_err() { 111pub(crate) unsafe fn clear_all_err() {
diff --git a/embassy-stm32/src/flash/mod.rs b/embassy-stm32/src/flash/mod.rs
index 29cf3cc51..89fdabd4d 100644
--- a/embassy-stm32/src/flash/mod.rs
+++ b/embassy-stm32/src/flash/mod.rs
@@ -1,3 +1,4 @@
1use embassy_hal_common::drop::OnDrop;
1use embassy_hal_common::{into_ref, PeripheralRef}; 2use embassy_hal_common::{into_ref, PeripheralRef};
2use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; 3use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
3use embassy_sync::mutex::{Mutex, MutexGuard}; 4use embassy_sync::mutex::{Mutex, MutexGuard};
@@ -14,7 +15,6 @@ use crate::Peripheral;
14#[cfg_attr(flash_f7, path = "f7.rs")] 15#[cfg_attr(flash_f7, path = "f7.rs")]
15#[cfg_attr(flash_h7, path = "h7.rs")] 16#[cfg_attr(flash_h7, path = "h7.rs")]
16mod family; 17mod family;
17
18pub struct Flash<'d> { 18pub struct Flash<'d> {
19 inner: PeripheralRef<'d, FLASH>, 19 inner: PeripheralRef<'d, FLASH>,
20} 20}
@@ -49,73 +49,93 @@ impl<'d> Flash<'d> {
49 } 49 }
50 50
51 pub fn blocking_read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { 51 pub fn blocking_read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> {
52 if offset as usize + bytes.len() > FLASH_SIZE { 52 Self::blocking_read_inner(FLASH_BASE as u32 + offset, bytes)
53 }
54
55 fn blocking_read_inner(start_address: u32, bytes: &mut [u8]) -> Result<(), Error> {
56 assert!(start_address >= FLASH_BASE as u32);
57 if start_address as usize + bytes.len() > FLASH_BASE + FLASH_SIZE {
53 return Err(Error::Size); 58 return Err(Error::Size);
54 } 59 }
55 60
56 let first_address = FLASH_BASE as u32 + offset; 61 let flash_data = unsafe { core::slice::from_raw_parts(start_address as *const u8, bytes.len()) };
57 let flash_data = unsafe { core::slice::from_raw_parts(first_address as *const u8, bytes.len()) };
58 bytes.copy_from_slice(flash_data); 62 bytes.copy_from_slice(flash_data);
59 Ok(()) 63 Ok(())
60 } 64 }
61 65
62 pub fn blocking_write(&mut self, offset: u32, buf: &[u8]) -> Result<(), Error> { 66 pub fn blocking_write(&mut self, offset: u32, buf: &[u8]) -> Result<(), Error> {
63 if offset as usize + buf.len() > FLASH_SIZE { 67 let start_address = FLASH_BASE as u32 + offset;
68
69 // No need to take lock here as we only have one mut flash reference.
70
71 unsafe { Flash::blocking_write_inner(start_address, buf) }
72 }
73
74 unsafe fn blocking_write_inner(start_address: u32, buf: &[u8]) -> Result<(), Error> {
75 assert!(start_address >= FLASH_BASE as u32);
76 if start_address as usize + buf.len() > FLASH_BASE + FLASH_SIZE {
64 return Err(Error::Size); 77 return Err(Error::Size);
65 } 78 }
66 if offset as usize % WRITE_SIZE != 0 || buf.len() as usize % WRITE_SIZE != 0 { 79 if (start_address as usize - FLASH_BASE) % WRITE_SIZE != 0 || buf.len() as usize % WRITE_SIZE != 0 {
67 return Err(Error::Unaligned); 80 return Err(Error::Unaligned);
68 } 81 }
69 82
70 let start_address = FLASH_BASE as u32 + offset;
71 trace!("Writing {} bytes at 0x{:x}", buf.len(), start_address); 83 trace!("Writing {} bytes at 0x{:x}", buf.len(), start_address);
72 84
73 // No need to take lock here as we only have one mut flash reference. 85 family::clear_all_err();
86 family::unlock();
87 family::begin_write();
74 88
75 unsafe { 89 let _ = OnDrop::new(|| {
76 family::clear_all_err(); 90 family::end_write();
77 family::unlock();
78 let res = Flash::blocking_write_all(start_address, buf);
79 family::lock(); 91 family::lock();
80 res 92 });
81 }
82 }
83 93
84 unsafe fn blocking_write_all(start_address: u32, buf: &[u8]) -> Result<(), Error> {
85 family::begin_write();
86 let mut address = start_address; 94 let mut address = start_address;
87 for chunk in buf.chunks(WRITE_SIZE) { 95 for chunk in buf.chunks(WRITE_SIZE) {
88 let res = unsafe { family::blocking_write(address, chunk.try_into().unwrap()) }; 96 unsafe { family::blocking_write(address, chunk.try_into().unwrap())? };
89 if res.is_err() {
90 family::end_write();
91 return res;
92 }
93 address += WRITE_SIZE as u32; 97 address += WRITE_SIZE as u32;
94 } 98 }
95
96 family::end_write();
97 Ok(()) 99 Ok(())
98 } 100 }
99 101
100 pub fn blocking_erase(&mut self, from: u32, to: u32) -> Result<(), Error> { 102 pub fn blocking_erase(&mut self, from: u32, to: u32) -> Result<(), Error> {
101 if to < from || to as usize > FLASH_SIZE {
102 return Err(Error::Size);
103 }
104
105 let start_address = FLASH_BASE as u32 + from; 103 let start_address = FLASH_BASE as u32 + from;
106 let end_address = FLASH_BASE as u32 + to; 104 let end_address = FLASH_BASE as u32 + to;
107 if !is_eraseable_range(start_address, end_address) { 105
106 unsafe { Flash::blocking_erase_inner(start_address, end_address) }
107 }
108
109 unsafe fn blocking_erase_inner(start_address: u32, end_address: u32) -> Result<(), Error> {
110 // Test if the address range is aligned at sector base addresses
111 let mut address = start_address;
112 while address < end_address {
113 let sector = family::get_sector(address);
114 if sector.start != address {
115 return Err(Error::Unaligned);
116 }
117 address += sector.size;
118 }
119 if address != end_address {
108 return Err(Error::Unaligned); 120 return Err(Error::Unaligned);
109 } 121 }
122
110 trace!("Erasing from 0x{:x} to 0x{:x}", start_address, end_address); 123 trace!("Erasing from 0x{:x} to 0x{:x}", start_address, end_address);
111 124
112 unsafe { 125 family::clear_all_err();
113 family::clear_all_err(); 126 family::unlock();
114 family::unlock(); 127
115 let res = family::blocking_erase(start_address, end_address); 128 let _ = OnDrop::new(|| {
116 family::lock(); 129 family::lock();
117 res 130 });
131
132 let mut address = start_address;
133 while address < end_address {
134 let sector = family::get_sector(address);
135 family::blocking_erase_sector(&sector)?;
136 address += sector.size;
118 } 137 }
138 Ok(())
119 } 139 }
120} 140}
121 141
@@ -135,74 +155,33 @@ pub trait FlashRegion {
135 const SETTINGS: FlashRegionSettings; 155 const SETTINGS: FlashRegionSettings;
136 156
137 fn blocking_read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { 157 fn blocking_read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> {
138 if offset as usize + bytes.len() > Self::SETTINGS.size { 158 Flash::blocking_read_inner(Self::SETTINGS.base as u32 + offset, bytes)
139 return Err(Error::Size);
140 }
141
142 let first_address = Self::SETTINGS.base as u32 + offset;
143 let flash_data = unsafe { core::slice::from_raw_parts(first_address as *const u8, bytes.len()) };
144 bytes.copy_from_slice(flash_data);
145 Ok(())
146 } 159 }
147 160
148 fn blocking_write(&mut self, offset: u32, buf: &[u8]) -> Result<(), Error> { 161 fn blocking_write(&mut self, offset: u32, buf: &[u8]) -> Result<(), Error> {
149 if offset as usize + buf.len() > Self::SETTINGS.size {
150 return Err(Error::Size);
151 }
152 if offset as usize % Self::SETTINGS.write_size != 0 || buf.len() as usize % Self::SETTINGS.write_size != 0 {
153 return Err(Error::Unaligned);
154 }
155
156 let start_address = Self::SETTINGS.base as u32 + offset; 162 let start_address = Self::SETTINGS.base as u32 + offset;
157 trace!("Writing {} bytes from 0x{:x}", buf.len(), start_address);
158 163
159 // Protect agains simultaneous write/erase to multiple regions. 164 // Protect agains simultaneous write/erase to multiple regions.
160 let _guard = take_lock_spin(); 165 let _guard = take_lock_spin();
161 166
162 unsafe { 167 unsafe {
163 family::clear_all_err(); 168 family::clear_all_err();
164 family::unlock(); 169 Flash::blocking_write_inner(start_address, buf)
165 let res = Flash::blocking_write_all(start_address, buf);
166 family::lock();
167 res
168 } 170 }
169 } 171 }
170 172
171 fn blocking_erase(&mut self, from: u32, to: u32) -> Result<(), Error> { 173 fn blocking_erase(&mut self, from: u32, to: u32) -> Result<(), Error> {
172 if to < from || to as usize > Self::SETTINGS.size {
173 return Err(Error::Size);
174 }
175 if (from as usize % Self::SETTINGS.erase_size) != 0 || (to as usize % Self::SETTINGS.erase_size) != 0 {
176 return Err(Error::Unaligned);
177 }
178
179 let start_address = Self::SETTINGS.base as u32 + from; 174 let start_address = Self::SETTINGS.base as u32 + from;
180 let end_address = Self::SETTINGS.base as u32 + to; 175 let end_address = Self::SETTINGS.base as u32 + to;
181 trace!("Erasing from 0x{:x} to 0x{:x}", start_address, end_address);
182 176
183 // Protect agains simultaneous write/erase to multiple regions. 177 // Protect agains simultaneous write/erase to multiple regions.
184 let _guard = take_lock_spin(); 178 let _guard = take_lock_spin();
185 179
186 unsafe { 180 unsafe {
187 family::clear_all_err(); 181 family::clear_all_err();
188 family::unlock(); 182 Flash::blocking_erase_inner(start_address, end_address)
189 let res = family::blocking_erase(start_address, end_address);
190 family::lock();
191 res
192 }
193 }
194}
195
196fn is_eraseable_range(start_address: u32, end_address: u32) -> bool {
197 let mut address = start_address;
198 while address < end_address {
199 let sector = family::get_sector(address);
200 if sector.start != address {
201 return false;
202 } 183 }
203 address += sector.size;
204 } 184 }
205 address == end_address
206} 185}
207 186
208fn take_lock_spin() -> MutexGuard<'static, CriticalSectionRawMutex, ()> { 187fn take_lock_spin() -> MutexGuard<'static, CriticalSectionRawMutex, ()> {