Skip to content

Commit 754b443

Browse files
committed
WIP: Minor fixes to flash.rs
1 parent 85afc7d commit 754b443

File tree

2 files changed

+152
-72
lines changed

2 files changed

+152
-72
lines changed

examples/flash_read_write.rs

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,37 @@
11
#![no_main]
22
#![no_std]
33

4-
use cortex_m::Peripherals;
54
use panic_halt as _;
65
use stm32f0xx_hal as hal;
76

8-
use crate::hal::{
9-
pac::{self, flash},
10-
prelude::*,
11-
};
7+
use crate::hal::{flash::FlashExt, pac, prelude::*};
128

139
use cortex_m_rt::entry;
1410
use embedded_storage::nor_flash::NorFlash;
15-
use stm32f0xx_hal::flash::FlashExt;
16-
use stm32f0xx_hal::prelude::_stm32f0xx_hal_rcc_RccExt;
1711

1812
#[entry]
1913
fn main() -> ! {
2014
if let Some(mut p) = pac::Peripherals::take() {
2115
let _ = p.RCC.configure().freeze(&mut p.FLASH);
2216

2317
// All examples use the first 16K of flash for the program so we use the first page after that
24-
const OFFSET_START: u32 = 16 * 1024;
18+
const OFFSET_START: u32 = 32 * 1024;
2519
const OFFSET_END: u32 = OFFSET_START + 1024;
2620
// Unlock flash before writing
2721
let mut unlocked_flash = p.FLASH.unlocked();
2822

2923
NorFlash::erase(&mut unlocked_flash, OFFSET_START, OFFSET_END).unwrap();
24+
NorFlash::erase(&mut unlocked_flash, 0x10000, 0x10000 + 1024).unwrap();
3025

3126
// Write some data to the start of that page
3227
let write_data = [0xC0_u8, 0xFF_u8, 0xEE_u8, 0x00_u8];
33-
NorFlash::write(&mut unlocked_flash, OFFSET_START, &write_data).unwrap();
28+
match NorFlash::write(&mut unlocked_flash, OFFSET_START, &write_data) {
29+
Err(e) => {
30+
let err = e;
31+
loop {}
32+
}
33+
Ok(_) => (),
34+
}
3435

3536
// Lock flash by dropping it
3637
drop(unlocked_flash);

src/flash.rs

Lines changed: 142 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use core::convert::TryInto;
2-
use core::{ptr, slice};
2+
use core::{mem, ptr, slice};
33

44
use embedded_storage::nor_flash::{
55
ErrorType, MultiwriteNorFlash, NorFlash, NorFlashError, NorFlashErrorKind, ReadNorFlash,
@@ -8,11 +8,60 @@ use embedded_storage::nor_flash::{
88
use crate::pac::FLASH;
99
use crate::signature::FlashSize;
1010

11+
/// First address of the flash memory
12+
pub const FLASH_START: usize = 0x0800_0000;
13+
14+
// F03x, F04x and F05x pages are 1K long
15+
#[cfg(any(
16+
feature = "stm32f030",
17+
feature = "stm32f031",
18+
feature = "stm32f038",
19+
feature = "stm32f042",
20+
feature = "stm32f048",
21+
feature = "stm32f051",
22+
feature = "stm32f058",
23+
))]
24+
pub const PAGE_SIZE: u32 = 1024;
25+
// F03x, F04x and F05x have 64 flash pages
26+
#[cfg(any(
27+
feature = "stm32f030",
28+
feature = "stm32f031",
29+
feature = "stm32f038",
30+
feature = "stm32f042",
31+
feature = "stm32f048",
32+
feature = "stm32f051",
33+
feature = "stm32f058",
34+
))]
35+
pub const NUM_PAGES: u32 = 64;
36+
37+
// F07x and F09x pages are 2K long
38+
#[cfg(any(
39+
feature = "stm32f070",
40+
feature = "stm32f071",
41+
feature = "stm32f072",
42+
feature = "stm32f078",
43+
feature = "stm32f091",
44+
feature = "stm32f098",
45+
))]
46+
pub const PAGE_SIZE: u32 = 2048;
47+
// F07x and F09x have 128 flash pages
48+
#[cfg(any(
49+
feature = "stm32f070",
50+
feature = "stm32f071",
51+
feature = "stm32f072",
52+
feature = "stm32f078",
53+
feature = "stm32f091",
54+
feature = "stm32f098",
55+
))]
56+
pub const NUM_PAGES: u32 = 128;
57+
1158
/// Flash erase/program error
1259
#[derive(Debug, Clone, Copy)]
1360
pub enum Error {
1461
Programming,
1562
WriteProtection,
63+
/// STM32F0 can only write Half Words (16 Bit) to flash. Can not write to addresses not aligned to that.
64+
Alignment,
1665
}
1766

1867
impl Error {
@@ -43,13 +92,11 @@ pub trait FlashExt {
4392
/// Unlock flash for erasing/programming until this method's
4493
/// result is dropped
4594
fn unlocked(&mut self) -> UnlockedFlash;
46-
/// Returns flash memory sector of a given offset. Returns none if offset is out of range.
47-
fn sector(&self, offset: usize) -> Option<FlashSector>;
4895
}
4996

5097
impl FlashExt for FLASH {
5198
fn address(&self) -> usize {
52-
0x0800_0000
99+
FLASH_START
53100
}
54101

55102
fn len(&self) -> usize {
@@ -60,10 +107,6 @@ impl FlashExt for FLASH {
60107
unlock(self);
61108
UnlockedFlash { flash: self }
62109
}
63-
64-
fn sector(&self, offset: usize) -> Option<FlashSector> {
65-
flash_sectors(self.len()).find(|s| s.contains(offset))
66-
}
67110
}
68111

69112
/// Read-only flash
@@ -105,10 +148,6 @@ impl FlashExt for LockedFlash {
105148
fn unlocked(&mut self) -> UnlockedFlash {
106149
self.flash.unlocked()
107150
}
108-
109-
fn sector(&self, offset: usize) -> Option<FlashSector> {
110-
self.flash.sector(offset)
111-
}
112151
}
113152

114153
/// Result of `FlashExt::unlocked()`
@@ -147,69 +186,110 @@ impl Drop for UnlockedFlash<'_> {
147186
}
148187
}
149188

189+
pub trait WriteErase {
190+
/// Native type for the flash for writing with the correct alignment and size
191+
///
192+
/// Can be `u8`, `u16`, `u32`, ... (`u16` for STM32F0xx devices)
193+
type NativeType;
194+
195+
/// The smallest possible write, depends on the platform
196+
fn program_native(&mut self, offset: usize, data: &[Self::NativeType]) -> Result<(), Error>;
197+
198+
/// Write a buffer of bytes to memory and use native writes internally.
199+
/// If it is not the same length as a set of native writes the write will be padded to fill the
200+
/// native write.
201+
fn program(&mut self, offset: usize, data: &[u8]) -> Result<(), Error>;
202+
}
203+
204+
impl WriteErase for UnlockedFlash<'_> {
205+
type NativeType = u16;
206+
207+
fn program_native(
208+
&mut self,
209+
mut offset: usize,
210+
data: &[Self::NativeType],
211+
) -> Result<(), Error> {
212+
// Wait for ready bit
213+
self.wait_ready();
214+
215+
let addr = self.flash.address() as *mut u16;
216+
217+
// Write the data to flash
218+
for &half_word in data {
219+
self.flash.cr.modify(|_, w| w.pg().set_bit());
220+
unsafe {
221+
ptr::write_volatile(addr.add(offset), half_word);
222+
}
223+
offset += mem::size_of::<Self::NativeType>();
224+
}
225+
226+
self.wait_ready();
227+
228+
// Clear programming bit
229+
self.flash.cr.modify(|_, w| w.pg().clear_bit());
230+
231+
self.ok()
232+
}
233+
234+
fn program(&mut self, mut offset: usize, data: &[u8]) -> Result<(), Error> {
235+
if offset % mem::align_of::<Self::NativeType>() != 0 {
236+
return Err(Error::Alignment);
237+
}
238+
239+
let mut chunks = data.chunks_exact(mem::size_of::<Self::NativeType>());
240+
241+
for exact_chunk in &mut chunks {
242+
let native = &[Self::NativeType::from_ne_bytes(
243+
exact_chunk.try_into().unwrap(),
244+
)];
245+
self.program_native(offset, native)?;
246+
offset += mem::size_of::<Self::NativeType>();
247+
}
248+
249+
let remainder = chunks.remainder();
250+
251+
if !remainder.is_empty() {
252+
let mut data = Self::NativeType::MAX;
253+
254+
for b in remainder.iter().rev() {
255+
data = (data << 8) | *b as Self::NativeType;
256+
}
257+
258+
let native = &[data];
259+
self.program_native(offset, native)?;
260+
}
261+
262+
self.ok()
263+
}
264+
}
265+
150266
impl UnlockedFlash<'_> {
151267
/// Erase a flash page at offset
152268
///
153269
/// Refer to the reference manual to see which sector corresponds
154270
/// to which memory address.
155271
pub fn erase(&mut self, offset: u32) -> Result<(), Error> {
272+
// Wait for ready bit
273+
self.wait_ready();
274+
275+
// Set the PER (page erase) bit in CR register
276+
self.flash.cr.modify(|_, w| w.per().set_bit());
277+
156278
// Write address into the AR register
157279
self.flash
158280
.ar
159281
.write(|w| w.far().bits(self.flash.address() as u32 + offset));
160-
#[rustfmt::skip]
161-
self.flash.cr.modify(|_, w|
162-
w
163-
// page erase
164-
.per().set_bit()
165-
// start
166-
.strt().set_bit()
167-
);
282+
// Set the STRT (start) Bit in CR register
283+
self.flash.cr.modify(|_, w| w.strt().set_bit());
284+
285+
// Wait for the operation to finish
168286
self.wait_ready();
287+
169288
// Clear PER bit after operation is finished
170289
self.flash.cr.modify(|_, w| w.per().clear_bit());
171290
self.ok()
172291
}
173292

174-
/// Program bytes with offset into flash memory
175-
pub fn program<'a, I>(&mut self, mut offset: usize, mut bytes: I) -> Result<(), Error>
176-
where
177-
I: Iterator<Item = &'a u8>,
178-
{
179-
if self.flash.cr.read().lock().bit_is_set() {
180-
return Err(Error::Programming);
181-
}
182-
let ptr = self.flash.address() as *mut u8;
183-
let mut bytes_written = 1;
184-
while bytes_written > 0 {
185-
bytes_written = 0;
186-
let amount = 2 - (offset % 2);
187-
188-
#[allow(unused_unsafe)]
189-
self.flash.cr.modify(|_, w| unsafe {
190-
// programming
191-
w.pg().set_bit()
192-
});
193-
for _ in 0..amount {
194-
match bytes.next() {
195-
Some(byte) => {
196-
unsafe {
197-
ptr::write_volatile(ptr.add(offset), *byte);
198-
}
199-
offset += 1;
200-
bytes_written += 1;
201-
}
202-
None => break,
203-
}
204-
}
205-
self.wait_ready();
206-
self.ok()?;
207-
}
208-
self.flash.cr.modify(|_, w| w.pg().clear_bit());
209-
210-
Ok(())
211-
}
212-
213293
fn ok(&self) -> Result<(), Error> {
214294
Error::read(self.flash).map(Err).unwrap_or(Ok(()))
215295
}
@@ -364,10 +444,9 @@ impl<'a> ReadNorFlash for UnlockedFlash<'a> {
364444
}
365445

366446
impl<'a> NorFlash for UnlockedFlash<'a> {
367-
const WRITE_SIZE: usize = 1;
447+
const WRITE_SIZE: usize = 2;
368448

369-
// Use largest sector size of 128 KB. All smaller sectors will be erased together.
370-
const ERASE_SIZE: usize = 128 * 1024;
449+
const ERASE_SIZE: usize = PAGE_SIZE as usize;
371450

372451
fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> {
373452
let mut current = from as usize;
@@ -387,7 +466,7 @@ impl<'a> NorFlash for UnlockedFlash<'a> {
387466
}
388467

389468
fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> {
390-
self.program(offset as usize, bytes.iter())
469+
self.program(offset as usize, bytes)
391470
}
392471
}
393472

0 commit comments

Comments
 (0)