use embedded_storage::nor_flash::{MultiwriteNorFlash, NorFlash, ReadNorFlash};
use crate::pac::FLASH;
use crate::signature::FlashSize;
use core::{ptr, slice};
#[derive(Debug, Clone, Copy)]
pub enum Error {
ProgrammingSequence,
ProgrammingParallelism,
ProgrammingAlignment,
WriteProtection,
Operation,
}
impl Error {
fn read(flash: &FLASH) -> Option<Self> {
let sr = flash.sr.read();
if sr.pgserr().bit() {
Some(Error::ProgrammingSequence)
} else if sr.pgperr().bit() {
Some(Error::ProgrammingParallelism)
} else if sr.pgaerr().bit() {
Some(Error::ProgrammingAlignment)
} else if sr.wrperr().bit() {
Some(Error::WriteProtection)
} else if sr.operr().bit() {
Some(Error::Operation)
} else {
None
}
}
}
#[allow(clippy::len_without_is_empty)]
pub trait FlashExt {
fn address(&self) -> usize;
fn len(&self) -> usize;
fn read(&self) -> &[u8] {
let ptr = self.address() as *const _;
unsafe { slice::from_raw_parts(ptr, self.len()) }
}
fn unlocked(&mut self) -> UnlockedFlash;
fn dual_bank(&self) -> bool;
fn sector(&self, offset: usize) -> Option<FlashSector>;
}
impl FlashExt for FLASH {
fn address(&self) -> usize {
0x0800_0000
}
fn len(&self) -> usize {
FlashSize::get().bytes()
}
fn unlocked(&mut self) -> UnlockedFlash {
unlock(self);
UnlockedFlash { flash: self }
}
fn dual_bank(&self) -> bool {
match self.len() / 1024 {
1024 => {
if cfg!(any(
feature = "stm32f427",
feature = "stm32f429",
feature = "stm32f437",
feature = "stm32f439",
feature = "stm32f469",
feature = "stm32f479",
)) {
self.optcr.read().bits() & (1 << 30) != 0
} else {
false
}
}
2048 => true,
_ => false,
}
}
fn sector(&self, offset: usize) -> Option<FlashSector> {
flash_sectors(self.len(), self.dual_bank()).find(|s| s.contains(offset))
}
}
const PSIZE_X8: u8 = 0b00;
pub struct LockedFlash {
flash: FLASH,
}
impl LockedFlash {
pub fn new(flash: FLASH) -> Self {
Self { flash }
}
}
impl FlashExt for LockedFlash {
fn address(&self) -> usize {
self.flash.address()
}
fn len(&self) -> usize {
self.flash.len()
}
fn unlocked(&mut self) -> UnlockedFlash {
self.flash.unlocked()
}
fn dual_bank(&self) -> bool {
self.flash.dual_bank()
}
fn sector(&self, offset: usize) -> Option<FlashSector> {
self.flash.sector(offset)
}
}
pub struct UnlockedFlash<'a> {
flash: &'a mut FLASH,
}
impl Drop for UnlockedFlash<'_> {
fn drop(&mut self) {
lock(self.flash);
}
}
impl UnlockedFlash<'_> {
pub fn erase(&mut self, sector: u8) -> Result<(), Error> {
let snb = if sector < 12 { sector } else { sector + 4 };
#[rustfmt::skip]
self.flash.cr.modify(|_, w| unsafe {
w
.strt().set_bit()
.psize().bits(PSIZE_X8)
.snb().bits(snb)
.ser().set_bit()
.pg().clear_bit()
});
self.wait_ready();
self.ok()
}
pub fn program<'a, I>(&mut self, mut offset: usize, mut bytes: I) -> Result<(), Error>
where
I: Iterator<Item = &'a u8>,
{
let ptr = self.flash.address() as *mut u8;
let mut bytes_written = 1;
while bytes_written > 0 {
bytes_written = 0;
let amount = 16 - (offset % 16);
#[rustfmt::skip]
#[allow(unused_unsafe)]
self.flash.cr.modify(|_, w| unsafe {
w
.psize().bits(PSIZE_X8)
.ser().clear_bit()
.pg().set_bit()
});
for _ in 0..amount {
match bytes.next() {
Some(byte) => {
unsafe {
ptr::write_volatile(ptr.add(offset), *byte);
}
offset += 1;
bytes_written += 1;
}
None => break,
}
}
self.wait_ready();
self.ok()?;
}
self.flash.cr.modify(|_, w| w.pg().clear_bit());
Ok(())
}
fn ok(&self) -> Result<(), Error> {
Error::read(self.flash).map(Err).unwrap_or(Ok(()))
}
fn wait_ready(&self) {
while self.flash.sr.read().bsy().bit() {}
}
}
const UNLOCK_KEY1: u32 = 0x45670123;
const UNLOCK_KEY2: u32 = 0xCDEF89AB;
#[allow(unused_unsafe)]
fn unlock(flash: &FLASH) {
flash.keyr.write(|w| unsafe { w.key().bits(UNLOCK_KEY1) });
flash.keyr.write(|w| unsafe { w.key().bits(UNLOCK_KEY2) });
assert!(!flash.cr.read().lock().bit())
}
fn lock(flash: &FLASH) {
flash.cr.modify(|_, w| w.lock().set_bit());
}
pub struct FlashSector {
pub number: u8,
pub offset: usize,
pub size: usize,
}
impl FlashSector {
pub fn contains(&self, offset: usize) -> bool {
self.offset <= offset && offset < self.offset + self.size
}
}
pub struct FlashSectorIterator {
index: u8,
start_sector: u8,
start_offset: usize,
end_offset: usize,
}
impl FlashSectorIterator {
fn new(start_sector: u8, start_offset: usize, end_offset: usize) -> Self {
Self {
index: 0,
start_sector,
start_offset,
end_offset,
}
}
}
impl Iterator for FlashSectorIterator {
type Item = FlashSector;
fn next(&mut self) -> Option<Self::Item> {
if self.start_offset >= self.end_offset {
None
} else {
let size = match self.index {
0..=3 => 16 * 1024,
4 => 64 * 1024,
_ => 128 * 1024,
};
let sector = FlashSector {
number: self.start_sector + self.index,
offset: self.start_offset,
size,
};
self.index += 1;
self.start_offset += size;
Some(sector)
}
}
}
pub fn flash_sectors(flash_size: usize, dual_bank: bool) -> impl Iterator<Item = FlashSector> {
if dual_bank {
FlashSectorIterator::new(0, 0, flash_size / 2).chain(FlashSectorIterator::new(
12,
flash_size / 2,
flash_size,
))
} else {
FlashSectorIterator::new(0, 0, flash_size).chain(FlashSectorIterator::new(0, 0, 0))
}
}
impl ReadNorFlash for LockedFlash {
type Error = Error;
const READ_SIZE: usize = 1;
fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> {
let offset = offset as usize;
bytes.copy_from_slice(&self.flash.read()[offset..offset + bytes.len()]);
Ok(())
}
fn capacity(&self) -> usize {
self.flash.len()
}
}
impl<'a> ReadNorFlash for UnlockedFlash<'a> {
type Error = Error;
const READ_SIZE: usize = 1;
fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> {
let offset = offset as usize;
bytes.copy_from_slice(&self.flash.read()[offset..offset + bytes.len()]);
Ok(())
}
fn capacity(&self) -> usize {
self.flash.len()
}
}
impl<'a> NorFlash for UnlockedFlash<'a> {
const WRITE_SIZE: usize = 1;
const ERASE_SIZE: usize = 128 * 1024;
fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> {
let mut current = from as usize;
for sector in flash_sectors(self.flash.len(), self.flash.dual_bank()) {
if sector.contains(current) {
UnlockedFlash::erase(self, sector.number)?;
current += sector.size;
}
if current >= to as usize {
break;
}
}
Ok(())
}
fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> {
self.program(offset as usize, bytes.iter())
}
}
impl<'a> MultiwriteNorFlash for UnlockedFlash<'a> {}