use crate::pac::{
flash::regs::{Ar, Keyr},
FLASH,
};
pub const FLASH_APP_START_ADDR: u32 = 0x08000000;
pub const FLASH_PAGE_SIZE: u32 = 256;
pub const FLASH_APP_SIZE_ALL: u32 = 64 * 1024;
pub const FLASH_APP_SIZE_DEFAULT: u32 = 61 * 1024;
pub const FLASH_PAGE_NUM_ALL: u32 = FLASH_APP_SIZE_ALL / FLASH_PAGE_SIZE;
pub const FLASH_PAGE_NUM_DEFAULT: u32 = FLASH_APP_SIZE_DEFAULT / FLASH_PAGE_SIZE;
const FLASH_KEY1: Keyr = Keyr(0x45670123);
const FLASH_KEY2: Keyr = Keyr(0xCDEF89AB);
const FLASH_OPTKEY1: Keyr = Keyr(0x45670123);
const FLASH_OPTKEY2: Keyr = Keyr(0xCDEF89AB);
const FLASH_ER_PRG_TIMEOUT: u32 = 0x000B0000;
pub fn flash_clear_flags() {
if FLASH.cr().read().lock() {
FLASH.keyr().write_value(FLASH_KEY1);
FLASH.keyr().write_value(FLASH_KEY2);
FLASH.sr().write(|w| {
w.set_pgerr(true);
w.set_wrprterr(true);
w.set_eop(true);
});
FLASH.cr().modify(|w| w.set_lock(true));
} else {
FLASH.sr().write(|w| {
w.set_pgerr(true);
w.set_wrprterr(true);
w.set_eop(true);
});
}
}
pub fn flash_unlock() {
if FLASH.cr().read().lock() {
FLASH.keyr().write_value(FLASH_KEY1);
FLASH.keyr().write_value(FLASH_KEY2);
}
}
pub fn flash_lock() {
FLASH.cr().modify(|w| w.set_lock(true));
}
pub fn flash_ob_unlock() {
if !FLASH.cr().read().optwre() {
FLASH.keyr().write_value(FLASH_OPTKEY1);
FLASH.keyr().write_value(FLASH_OPTKEY2);
}
}
pub fn flash_ob_lock() {
FLASH.cr().modify(|w| w.set_optwre(false));
}
pub fn flash_erase_page(page: u32) -> FlashStatus {
let mut status = flash_wait_for_last_operation(FLASH_ER_PRG_TIMEOUT);
if status == FlashStatus::Complete {
FLASH.cr().modify(|w| w.set_per(true));
FLASH.ar().write_value(Ar(page));
FLASH.cr().modify(|w| w.set_strt(true));
status = flash_wait_for_last_operation(FLASH_ER_PRG_TIMEOUT);
FLASH.cr().modify(|w| w.set_per(false));
}
return status;
}
pub fn flash_program_word(address: u32, data: u32) -> FlashStatus {
let mut status = flash_wait_for_last_operation(FLASH_ER_PRG_TIMEOUT);
if status == FlashStatus::Complete {
#[cfg(feature = "hk32c030xx")]
FLASH.cr().modify(|w| w.set_wpg(true));
#[cfg(feature = "hk32f0301mxxc")]
FLASH.cr().modify(|w| w.set_pg(true));
unsafe { (address as *mut u32).write_volatile(data) }
status = flash_wait_for_last_operation(FLASH_ER_PRG_TIMEOUT);
#[cfg(feature = "hk32c030xx")]
FLASH.cr().modify(|w| w.set_wpg(false));
#[cfg(feature = "hk32f0301mxxc")]
FLASH.cr().modify(|w| w.set_pg(false));
}
return status;
}
pub fn flash_int_vec_offset(offset: u32) {
FLASH.int_vec_offset().write(|w| w.0 = offset);
}
#[derive(Debug, PartialEq)]
pub enum FlashStatus {
Busy,
ErrorWRP,
ErrorProgram,
Complete,
Timeout,
}
fn flash_get_status() -> FlashStatus {
let sr = FLASH.sr().read();
let status;
if sr.bsy() {
status = FlashStatus::Busy;
} else {
if sr.wrprterr() {
status = FlashStatus::ErrorWRP;
} else {
if sr.pgerr() {
status = FlashStatus::ErrorProgram;
} else {
status = FlashStatus::Complete;
}
}
}
return status;
}
fn flash_wait_for_last_operation(mut timeout: u32) -> FlashStatus {
let mut status = flash_get_status();
while status == FlashStatus::Busy && timeout > 0 {
status = flash_get_status();
timeout -= 1;
}
if timeout == 0 {
status = FlashStatus::Timeout;
}
return status;
}