use crate::pac::FLASH;
use core;
use cfg_if::cfg_if;
const FLASH_KEY1: u32 = 0x4567_0123;
const FLASH_KEY2: u32 = 0xCDEF_89AB;
#[cfg(feature = "l5")]
#[derive(Clone, Copy)]
pub enum Security {
NonSecure,
Secure,
}
#[derive(Clone, Copy)]
enum _DualBank {
Dual,
Single,
}
#[derive(Clone, Copy)]
pub enum BanksToErase {
Bank1,
Bank2,
Both,
}
#[derive(Copy, Clone, Debug)]
pub enum Error {
Busy,
Illegal,
EccError,
PageOutOfRange,
Failure,
}
#[cfg(not(feature = "l5"))]
fn check_illegal(flash: &FLASH) -> Result<(), Error> {
let sr = flash.sr.read();
cfg_if::cfg_if! {
if #[cfg(any(feature = "f3"))] {
if sr.pgerr().bit_is_set() || sr.wrprterr().bit_is_set() {
return Err(Error::Illegal);
}
} else if #[cfg(any(feature = "f4"))] {
if sr.pgaerr().bit_is_set() {
return Err(Error::Illegal);
}
} else {
if sr.pgaerr().bit_is_set() || sr.progerr().bit_is_set() || sr.wrperr().bit_is_set() {
return Err(Error::Illegal);
}
}
}
Ok(())
}
#[cfg(feature = "l5")]
fn check_illegal(flash: &FLASH, security: Security) -> Result<(), Error> {
match security {
Security::NonSecure => {
let sr = flash.nssr.read();
if sr.nspgaerr().bit_is_set()
|| sr.nspgserr().bit_is_set()
|| sr.nsprogerr().bit_is_set()
|| sr.nswrperr().bit_is_set()
{
return Err(Error::Illegal);
}
}
Security::Secure => {
let sr = flash.secsr.read();
if sr.secpgaerr().bit_is_set()
|| sr.secpgaerr().bit_is_set()
|| sr.secprogerr().bit_is_set()
|| sr.secwrperr().bit_is_set()
{
return Err(Error::Illegal);
}
}
}
Ok(())
}
pub struct Flash {
pub(crate) regs: FLASH,
}
impl Flash {
pub fn new(regs: FLASH) -> Self {
Self { regs }
}
#[cfg(feature = "l5")]
pub fn unlock(&mut self, security: Security) -> Result<(), Error> {
match security {
Security::NonSecure => {
self.regs.nskeyr.write(|w| unsafe { w.bits(FLASH_KEY1) });
self.regs.nskeyr.write(|w| unsafe { w.bits(FLASH_KEY2) });
if self.regs.nscr.read().nslock().bit_is_clear() {
Ok(())
} else {
Err(Error::Failure)
}
}
Security::Secure => {
self.regs.seckeyr.write(|w| unsafe { w.bits(FLASH_KEY1) });
self.regs.seckeyr.write(|w| unsafe { w.bits(FLASH_KEY2) });
if self.regs.seccr.read().seclock().bit_is_clear() {
Ok(())
} else {
Err(Error::Failure)
}
}
}
}
#[cfg(not(feature = "l5"))]
pub fn unlock(&mut self) -> Result<(), Error> {
self.regs.keyr.write(|w| unsafe { w.bits(FLASH_KEY1) });
self.regs.keyr.write(|w| unsafe { w.bits(FLASH_KEY2) });
if self.regs.cr.read().lock().bit_is_clear() {
Ok(())
} else {
Err(Error::Failure)
}
}
#[cfg(feature = "l5")]
pub fn lock(&mut self, security: Security) {
match security {
Security::NonSecure => self.regs.nscr.modify(|_, w| w.nslock().set_bit()),
Security::Secure => self.regs.seccr.modify(|_, w| w.seclock().set_bit()),
};
}
#[cfg(not(feature = "l5"))]
pub fn lock(&mut self) {
self.regs.cr.modify(|_, w| w.lock().set_bit());
}
#[cfg(not(feature = "l5"))]
pub fn erase_page(&mut self, page: usize) -> Result<(), Error> {
self.unlock()?;
let sr = self.regs.sr.read();
if sr.bsy().bit_is_set() {
self.lock();
return Err(Error::Busy);
}
if check_illegal(&self.regs).is_err() {
self.lock();
return Err(Error::Illegal);
};
cfg_if::cfg_if! {
if #[cfg(feature = "f3")] {
self.regs.cr.modify(|_, w| w.per().set_bit());
self.regs.ar.write(|w| unsafe { w.bits(page as u32) });
} else if #[cfg(feature = "f4")] {
self.regs.cr.modify(|_, w| unsafe {
w.ser().set_bit();
w.snb().bits(page as u8)
});
} else if #[cfg(any(feature = "g0", feature = "g4"))] {
self.regs.cr.modify(|_, w| unsafe {
w.pnb()
.bits(page as u8)
.per()
.set_bit()
});
} else {
match page {
0..=255 => {
self.regs.cr.modify(|_, w| unsafe {
w.bker().clear_bit().pnb().bits(page as u8).per().set_bit()
});
}
256..=511 => {
self.regs.cr.modify(|_, w| unsafe {
w.bker()
.set_bit()
.pnb()
.bits((page - 256) as u8)
.per()
.set_bit()
});
}
_ => {
return Err(Error::PageOutOfRange);
}
}
}
}
cfg_if::cfg_if! {
if #[cfg(any(feature = "f3", feature = "f4"))] {
self.regs.cr.modify(|_, w| w.strt().set_bit());
} else {
#[cfg(any(feature = "g0", feature = "g4"))]
self.regs.cr.modify(|_, w| w.strt().set_bit());
#[cfg(not(any(feature = "g0", feature = "g4")))]
self.regs.cr.modify(|_, w| w.start().set_bit());
}
}
while self.regs.sr.read().bsy().bit_is_set() {}
cfg_if::cfg_if! {
if #[cfg(any(feature = "f3", feature = "f4"))] {
self.regs.sr.modify(|_, w| w.eop().set_bit());
} else {
self.regs.cr.modify(|_, w| w.per().clear_bit());
}
}
self.lock();
Ok(())
}
#[cfg(feature = "l5")]
pub fn erase_page(&mut self, page: usize, security: Security) -> Result<(), Error> {
self.unlock(security)?;
match security {
Security::NonSecure => {
let sr = self.regs.nssr.read();
if sr.nsbsy().bit_is_set() {
self.lock(security);
return Err(Error::Busy);
}
if check_illegal(&self.regs, security).is_err() {
self.lock(security);
return Err(Error::Illegal);
};
match page {
0..=255 => {
self.regs.nscr.modify(|_, w| unsafe {
w.nsbker()
.clear_bit()
.nspnb()
.bits(page as u8)
.nsper()
.set_bit()
});
}
256..=511 => {
self.regs.nscr.modify(|_, w| unsafe {
w.nsbker()
.set_bit()
.nspnb()
.bits((page - 256) as u8)
.nsper()
.set_bit()
});
}
_ => {
return Err(Error::PageOutOfRange);
}
}
self.regs.nscr.modify(|_, w| w.nsstrt().set_bit());
while self.regs.nssr.read().nsbsy().bit_is_set() {}
}
Security::Secure => {
let sr = self.regs.secsr.read();
if sr.secbsy().bit_is_set() {
self.lock(security);
return Err(Error::Busy);
}
if check_illegal(&self.regs, security).is_err() {
self.lock(security);
return Err(Error::Illegal);
};
match page {
0..=255 => {
self.regs.seccr.modify(|_, w| unsafe {
w.secbker()
.clear_bit()
.secpnb()
.bits(page as u8)
.secper()
.set_bit()
});
}
256..=511 => {
self.regs.seccr.modify(|_, w| unsafe {
w.secbker()
.set_bit()
.secpnb()
.bits((page - 256) as u8)
.secper()
.set_bit()
});
}
_ => {
return Err(Error::PageOutOfRange);
}
}
self.regs.seccr.modify(|_, w| w.secstrt().set_bit());
while self.regs.secsr.read().secbsy().bit_is_set() {}
}
}
self.lock(security);
Ok(())
}
#[cfg(not(feature = "l5"))]
pub fn erase_bank(&mut self, banks: BanksToErase) -> Result<(), Error> {
self.unlock()?;
let sr = self.regs.sr.read();
if sr.bsy().bit_is_set() {
self.lock();
return Err(Error::Busy);
}
if check_illegal(&self.regs).is_err() {
self.lock();
return Err(Error::Illegal);
};
cfg_if::cfg_if! {
if #[cfg(any(feature = "f3", feature = "f4"))] {
self.regs.cr.modify(|_, w| w.mer().clear_bit());
self.regs.cr.modify(|_, w| w.strt().set_bit());
} else if #[cfg(any(feature = "g0"))] {
self.regs.cr.modify(|_, w| w.mer().clear_bit());
} else if #[cfg(any(feature = "g4"))] {
self.regs.cr.modify(|_, w| w.mer1().clear_bit());
} else {
match banks {
BanksToErase::Bank1 => {
self.regs.cr.modify(|_, w| w.mer1().clear_bit());
}
BanksToErase::Bank2 => {
self.regs.cr.modify(|_, w| w.mer2().clear_bit());
}
BanksToErase::Both => {
self.regs.cr.modify(|_, w| w.mer1().clear_bit());
self.regs.cr.modify(|_, w| w.mer2().clear_bit());
}
}
#[cfg(feature = "g4")]
self.regs.cr.modify(|_, w| w.strt().set_bit());
#[cfg(not(feature = "g4"))]
self.regs.cr.modify(|_, w| w.start().set_bit());
}
}
while self.regs.sr.read().bsy().bit_is_set() {}
self.lock();
Ok(())
}
#[cfg(feature = "l5")]
pub fn erase_bank(&mut self, banks: BanksToErase, security: Security) -> Result<(), Error> {
self.unlock(security)?;
match security {
Security::NonSecure => {
let sr = self.regs.nssr.read();
if sr.nsbsy().bit_is_set() {
self.lock(security);
return Err(Error::Busy);
}
if check_illegal(&self.regs, security).is_err() {
self.lock(security);
return Err(Error::Illegal);
};
match banks {
BanksToErase::Bank1 => {
self.regs.nscr.modify(|_, w| w.nsmer1().clear_bit());
}
BanksToErase::Bank2 => {
self.regs.nscr.modify(|_, w| w.nsmer2().clear_bit());
}
BanksToErase::Both => {
self.regs.nscr.modify(|_, w| w.nsmer1().clear_bit());
self.regs.nscr.modify(|_, w| w.nsmer2().clear_bit());
}
}
self.regs.nscr.modify(|_, w| w.nsstrt().set_bit());
while self.regs.nssr.read().nsbsy().bit_is_set() {}
}
Security::Secure => {
let sr = self.regs.secsr.read();
if sr.secbsy().bit_is_set() {
self.lock(security);
return Err(Error::Busy);
}
if check_illegal(&self.regs, security).is_err() {
self.lock(security);
return Err(Error::Illegal);
};
match banks {
BanksToErase::Bank1 => {
self.regs.seccr.modify(|_, w| w.secmer1().clear_bit());
}
BanksToErase::Bank2 => {
self.regs.seccr.modify(|_, w| w.secmer2().clear_bit());
}
BanksToErase::Both => {
self.regs.seccr.modify(|_, w| w.secmer1().clear_bit());
self.regs.seccr.modify(|_, w| w.secmer2().clear_bit());
}
}
self.regs.seccr.modify(|_, w| w.secstrt().set_bit());
while self.regs.secsr.read().secbsy().bit_is_set() {}
}
}
self.lock(security);
Ok(())
}
#[cfg(not(feature = "l5"))]
pub fn write_page(&mut self, page: usize, data: &[u64]) -> Result<(), Error> {
self.unlock()?;
let sr = self.regs.sr.read();
if sr.bsy().bit_is_set() {
self.lock();
return Err(Error::Busy);
}
if check_illegal(&self.regs).is_err() {
self.lock();
return Err(Error::Illegal);
};
self.regs.cr.modify(|_, w| w.pg().set_bit());
let mut address = page_to_address(page) as *mut u32;
for dword in data {
unsafe {
core::ptr::write_volatile(address, *dword as u32);
core::ptr::write_volatile(address.add(1), (*dword >> 32) as u32);
address = address.add(2);
}
while self.regs.sr.read().bsy().bit_is_set() {}
if self.regs.sr.read().eop().bit_is_set() {
self.regs.sr.modify(|_, w| w.eop().set_bit());
}
}
self.regs.cr.modify(|_, w| w.pg().clear_bit());
self.lock();
Ok(())
}
#[cfg(feature = "l5")]
pub fn write_page(
&mut self,
page: usize,
data: &[u64],
security: Security,
) -> Result<(), Error> {
self.unlock(security)?;
match security {
Security::NonSecure => {
let sr = self.regs.nssr.read();
if sr.nsbsy().bit_is_set() {
self.lock(security);
return Err(Error::Busy);
}
if check_illegal(&self.regs, security).is_err() {
self.lock(security);
return Err(Error::Illegal);
};
self.regs.nscr.modify(|_, w| w.nspg().set_bit());
let mut address = page_to_address(page) as *mut u32;
for dword in data {
unsafe {
core::ptr::write_volatile(address, *dword as u32);
core::ptr::write_volatile(address.add(1), (*dword >> 32) as u32);
address = address.add(2);
}
while self.regs.nssr.read().nsbsy().bit_is_set() {}
if self.regs.nssr.read().nseop().bit_is_set() {
self.regs.nssr.modify(|_, w| w.nseop().set_bit());
}
}
self.regs.nscr.modify(|_, w| w.nspg().clear_bit());
}
Security::Secure => {
let sr = self.regs.secsr.read();
if sr.secbsy().bit_is_set() {
self.lock(security);
return Err(Error::Busy);
}
if check_illegal(&self.regs, security).is_err() {
self.lock(security);
return Err(Error::Illegal);
};
self.regs.seccr.modify(|_, w| w.secpg().set_bit());
let mut address = page_to_address(page) as *mut u32;
for dword in data {
unsafe {
core::ptr::write_volatile(address, *dword as u32);
core::ptr::write_volatile(address.add(1), (*dword >> 32) as u32);
address = address.add(2);
}
while self.regs.secsr.read().secbsy().bit_is_set() {}
if self.regs.secsr.read().seceop().bit_is_set() {
self.regs.secsr.modify(|_, w| w.seceop().set_bit());
}
}
self.regs.seccr.modify(|_, w| w.secpg().clear_bit());
}
}
self.lock(security);
Ok(())
}
pub fn read(&self, page: usize, offset: isize) -> u64 {
let addr = page_to_address(page) as *const u64;
unsafe { core::ptr::read(addr.offset(offset)) }
}
pub fn read_to_buffer(&self, page: usize, offset: isize, buff: &mut [u8]) {
let addr = page_to_address(page) as *const u8;
for val in buff {
*val = unsafe { core::ptr::read(addr.offset(offset)) }
}
}
}
fn page_to_address(page: usize) -> usize {
0x0800_0000 + page as usize * 2048
}