use crate::pac::{flash, FLASH};
pub const FLASH_START: u32 = 0x0800_0000;
pub const FLASH_END: u32 = 0x080F_FFFF;
const _RDPRT_KEY: u16 = 0x00A5;
const KEY1: u32 = 0x45670123;
const KEY2: u32 = 0xCDEF89AB;
pub const SZ_1K: u16 = 1024;
pub type Result<T> = core::result::Result<T, Error>;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Ord, PartialOrd)]
pub enum Error {
AddressLargerThanFlash,
AddressMisaligned,
LengthNotMultiple2,
LengthTooLong,
EraseError,
ProgrammingError,
WriteError,
VerifyError,
UnlockError,
LockError,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Ord, PartialOrd)]
pub enum SectorSize {
Sz1K = 1,
Sz2K = 2,
Sz4K = 4,
}
impl SectorSize {
const fn kbytes(self) -> u16 {
SZ_1K * self as u16
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Ord, PartialOrd)]
pub enum FlashSize {
Sz16K = 16,
Sz32K = 32,
Sz64K = 64,
Sz128K = 128,
Sz256K = 256,
Sz384K = 384,
Sz512K = 512,
Sz768K = 768,
Sz1M = 1024,
}
impl FlashSize {
const fn kbytes(self) -> u32 {
SZ_1K as u32 * self as u32
}
}
pub struct FlashWriter<'a> {
flash: &'a mut Parts,
sector_sz: SectorSize,
flash_sz: FlashSize,
verify: bool,
}
impl<'a> FlashWriter<'a> {
fn unlock(&mut self) -> Result<()> {
while self.flash.sr.sr().read().bsy().bit_is_set() {}
unsafe {
self.flash.keyr.keyr().write(|w| w.key().bits(KEY1));
}
unsafe {
self.flash.keyr.keyr().write(|w| w.key().bits(KEY2));
}
match self.flash.cr.cr().read().lock().bit_is_clear() {
true => Ok(()),
false => Err(Error::UnlockError),
}
}
fn lock(&mut self) -> Result<()> {
while self.flash.sr.sr().read().bsy().bit_is_set() {}
self.flash.cr.cr().modify(|_, w| w.lock().set_bit());
match self.flash.cr.cr().read().lock().bit_is_set() {
true => Ok(()),
false => Err(Error::LockError),
}
}
fn valid_address(&self, offset: u32) -> Result<()> {
if FLASH_START + offset > FLASH_END {
Err(Error::AddressLargerThanFlash)
} else if offset & 0x1 != 0 {
Err(Error::AddressMisaligned)
} else {
Ok(())
}
}
fn valid_length(&self, offset: u32, length: usize) -> Result<()> {
if offset + length as u32 > self.flash_sz.kbytes() as u32 {
Err(Error::LengthTooLong)
} else if length & 0x1 != 0 {
Err(Error::LengthNotMultiple2)
} else {
Ok(())
}
}
pub fn page_erase(&mut self, start_offset: u32) -> Result<()> {
self.valid_address(start_offset)?;
self.unlock()?;
self.flash.cr.cr().modify(|_, w| w.per().set_bit());
unsafe {
self.flash
.ar
.ar()
.write(|w| w.far().bits(FLASH_START + start_offset));
}
self.flash.cr.cr().modify(|_, w| w.strt().set_bit());
cortex_m::asm::nop();
while self.flash.sr.sr().read().bsy().bit_is_set() {}
let sr = self.flash.sr.sr().read();
self.flash.cr.cr().modify(|_, w| w.per().clear_bit());
self.lock()?;
if sr.wrprterr().bit_is_set() {
self.flash.sr.sr().modify(|_, w| w.wrprterr().clear_bit());
Err(Error::EraseError)
} else {
if self.verify {
let size = self.sector_sz.kbytes() as u32;
let start = start_offset & !(size - 1);
for idx in (start..start + size).step_by(2) {
let write_address = (FLASH_START + idx as u32) as *const u16;
let verify: u16 = unsafe { core::ptr::read_volatile(write_address) };
if verify != 0xFFFF {
return Err(Error::VerifyError);
}
}
}
Ok(())
}
}
pub fn erase(&mut self, start_offset: u32, length: usize) -> Result<()> {
self.valid_length(start_offset, length)?;
for offset in
(start_offset..start_offset + length as u32).step_by(self.sector_sz.kbytes() as usize)
{
self.page_erase(offset)?;
}
Ok(())
}
pub fn read(&self, offset: u32, length: usize) -> Result<&[u8]> {
self.valid_address(offset)?;
if offset + length as u32 > self.flash_sz.kbytes() as u32 {
return Err(Error::LengthTooLong);
}
let address = (FLASH_START + offset) as *const _;
Ok(
unsafe { core::slice::from_raw_parts(address, length) },
)
}
pub fn write(&mut self, offset: u32, data: &[u8]) -> Result<()> {
self.valid_length(offset, data.len())?;
self.unlock()?;
for idx in (0..data.len()).step_by(2) {
self.valid_address(offset + idx as u32)?;
let write_address = (FLASH_START + offset + idx as u32) as *mut u16;
self.flash.cr.cr().modify(|_, w| w.pg().set_bit());
while self.flash.sr.sr().read().bsy().bit_is_set() {}
let hword: u16 = (data[idx] as u16) | (data[idx + 1] as u16) << 8;
unsafe { core::ptr::write_volatile(write_address, hword) };
while self.flash.sr.sr().read().bsy().bit_is_set() {}
self.flash.cr.cr().modify(|_, w| w.pg().clear_bit());
if self.flash.sr.sr().read().pgerr().bit_is_set() {
self.flash.sr.sr().modify(|_, w| w.pgerr().clear_bit());
self.lock()?;
return Err(Error::ProgrammingError);
} else if self.flash.sr.sr().read().wrprterr().bit_is_set() {
self.flash.sr.sr().modify(|_, w| w.wrprterr().clear_bit());
self.lock()?;
return Err(Error::WriteError);
} else if self.verify {
let verify: u16 = unsafe { core::ptr::read_volatile(write_address) };
if verify != hword {
self.lock()?;
return Err(Error::VerifyError);
}
}
}
self.lock()?;
Ok(())
}
pub fn change_verification(&mut self, verify: bool) {
self.verify = verify;
}
}
pub trait FlashExt {
fn constrain(self) -> Parts;
}
impl FlashExt for FLASH {
fn constrain(self) -> Parts {
Parts {
acr: ACR { _0: () },
ar: AR { _0: () },
cr: CR { _0: () },
keyr: KEYR { _0: () },
_obr: OBR { _0: () },
_optkeyr: OPTKEYR { _0: () },
sr: SR { _0: () },
_wrpr: WRPR { _0: () },
}
}
}
pub struct Parts {
pub acr: ACR,
pub(crate) ar: AR,
pub(crate) cr: CR,
pub(crate) keyr: KEYR,
pub(crate) _obr: OBR,
pub(crate) _optkeyr: OPTKEYR,
pub(crate) sr: SR,
pub(crate) _wrpr: WRPR,
}
impl Parts {
pub fn writer(&mut self, sector_sz: SectorSize, flash_sz: FlashSize) -> FlashWriter {
FlashWriter {
flash: self,
sector_sz,
flash_sz,
verify: true,
}
}
}
pub struct ACR {
_0: (),
}
#[allow(dead_code)]
impl ACR {
pub(crate) fn acr(&mut self) -> &flash::ACR {
unsafe { &(*FLASH::ptr()).acr }
}
}
pub struct AR {
_0: (),
}
#[allow(dead_code)]
impl AR {
pub(crate) fn ar(&mut self) -> &flash::AR {
unsafe { &(*FLASH::ptr()).ar }
}
}
pub struct CR {
_0: (),
}
#[allow(dead_code)]
impl CR {
pub(crate) fn cr(&mut self) -> &flash::CR {
unsafe { &(*FLASH::ptr()).cr }
}
}
pub struct KEYR {
_0: (),
}
#[allow(dead_code)]
impl KEYR {
pub(crate) fn keyr(&mut self) -> &flash::KEYR {
unsafe { &(*FLASH::ptr()).keyr }
}
}
pub struct OBR {
_0: (),
}
#[allow(dead_code)]
impl OBR {
pub(crate) fn obr(&mut self) -> &flash::OBR {
unsafe { &(*FLASH::ptr()).obr }
}
}
pub struct OPTKEYR {
_0: (),
}
#[allow(dead_code)]
impl OPTKEYR {
pub(crate) fn optkeyr(&mut self) -> &flash::OPTKEYR {
unsafe { &(*FLASH::ptr()).optkeyr }
}
}
pub struct SR {
_0: (),
}
#[allow(dead_code)]
impl SR {
pub(crate) fn sr(&mut self) -> &flash::SR {
unsafe { &(*FLASH::ptr()).sr }
}
}
pub struct WRPR {
_0: (),
}
#[allow(dead_code)]
impl WRPR {
pub(crate) fn wrpr(&mut self) -> &flash::WRPR {
unsafe { &(*FLASH::ptr()).wrpr }
}
}