From 68d58857cfe743fbfd96cf77bcfee1cb83a69f7a Mon Sep 17 00:00:00 2001 From: occheung Date: Fri, 18 Dec 2020 17:37:56 +0800 Subject: [PATCH] flash: init abstraction --- src/flash.rs | 442 +++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 393 insertions(+), 49 deletions(-) diff --git a/src/flash.rs b/src/flash.rs index d3ce0f6..f3229c9 100644 --- a/src/flash.rs +++ b/src/flash.rs @@ -1,64 +1,408 @@ -use heapless::{String, consts::*}; -use smoltcp as net; -use embedded_nal as nal; -use core::str::FromStr; +//! Flash memory, with major reference from STM32F7xx_HAL crate, +//! as well as @Astro 's work in STM32F4xx_HAL -unsafe fn read_record_length(addr: u32) -> u32 { - core::ptr::read(addr as *const u32) +use stm32h7xx_hal::pac::FLASH; + +/// Base address of flash memory on AXIM interface. +const FLASH_BASE: *mut u8 = 0x800_0000 as *mut u8; + +/// The last valid flash address in STM32H743 +const MAX_FLASH_ADDRESS: *mut u8 = 0x81F_FFFF as *mut u8; + +/// Flash programming error. +#[derive(Debug, PartialEq, Eq)] +pub enum Error { + Busy, + Locked, + WriteProtection, + ProgrammingSequence, + Strobe, + Inconsistency, + Operation, + ErrorCorrectionCode, + ReadProtection, + ReadSecure, + WriteError } -unsafe fn read_byte(addr: u32) -> u8 { - core::ptr::read(addr as *const u8) +/// Embedded flash memory. +pub struct Flash { + registers: FLASH, } -fn read_flash_str(addr: &mut u32) -> (String, String) { - let mut key: String = String::new(); - let mut string: String = String::new(); - - let record_length = unsafe { - read_record_length(*addr) - }; - if record_length == 0xFFFFFFFF { - return (key, string); +impl Flash { + /// Creates a new Flash instance. + pub fn new(flash: FLASH) -> Self { + let mut flash = Self { registers: flash }; + // Lock both banks initially + flash.lock(); + flash } - let mut key_string_div = false; - for f_addr in (*addr)+4..((*addr)+record_length) { - if key_string_div { - string.push(unsafe {read_byte(f_addr)} as char).unwrap(); - } else { - let c = unsafe {read_byte(f_addr)}; - if c == 0 { - key_string_div = true; - } else { - key.push(c as char).unwrap(); + /// Unlocks the FLASH_CR1/2 register. + pub fn unlock(&mut self) { + // Note: Unlocking an unlocked bank will cause HardFault + + // Unlock bank 1 if needed. + if self.bank1_is_locked() { + self.registers.bank1_mut().keyr.write(|w| unsafe { + w.keyr().bits(0x45670123) + }); + self.registers.bank1_mut().keyr.write(|w| unsafe { + w.keyr().bits(0xCDEF89AB) + }); + } + + // Unlock bank 2 if needed. + if self.bank2_is_locked() { + self.registers.bank2_mut().keyr.write(|w| unsafe { + w.keyr().bits(0x45670123) + }); + self.registers.bank2_mut().keyr.write(|w| unsafe { + w.keyr().bits(0xCDEF89AB) + }); + } + } + + /// Unlocks the FLASH_OPTCR register + pub fn unlock_optcr(&mut self) { + if self.optcr_is_locked() { + self.registers.optkeyr_mut().write(|w| unsafe { + w.optkeyr().bits(0x08192A3B) + }); + self.registers.optkeyr_mut().write(|w| unsafe { + w.optkeyr().bits(0x4C5D6E7F) + }); + } + } + + /// Locks the FLASH_CR1/2 register. + pub fn lock(&mut self) { + self.registers.bank1_mut().cr.modify(|_, w| w.lock().set_bit()); + self.registers.bank2_mut().cr.modify(|_, w| w.lock().set_bit()); + } + + /// Lock the FLASH_OPTCR register + pub fn lock_optcr(&mut self) { + self.registers.optcr_mut().modify(|_, w| w.optlock().set_bit()); + } + + // More literal methods to get bank status + fn bank1_is_locked(&self) -> bool { + self.registers.bank1_mut().cr.read().lock().bit_is_set() + } + fn bank2_is_locked(&self) -> bool { + self.registers.bank2_mut().cr.read().lock().bit_is_set() + } + fn optcr_is_locked(&self) -> bool { + self.registers.optcr().read().optlock().bit_is_set() + } + + pub fn is_locked(&self) -> bool { + self.bank1_is_locked() || self.bank2_is_locked() + } + + /// Returns `true` if a write/erase operation is in progress. + fn is_busy(&self) -> bool { + let (sr1, sr2) = ( + self.registers.bank1_mut().sr.read(), + self.registers.bank2_mut().sr.read() + ); + sr1.bsy().bit_is_set() || sr2.bsy().bit_is_set() + } + + /// Returns `true` if a write/erase operation is in a command queue buffer. + fn is_queuing(&self) -> bool { + let (sr1, sr2) = ( + self.registers.bank1_mut().sr.read(), + self.registers.bank2_mut().sr.read() + ); + sr1.qw().bit_is_set() || sr2.qw().bit_is_set() + } + + /// Returns `true` if write buffer is not empty in bank 1 + fn bank1_is_buffering(&self) -> bool { + let sr1 = self.registers.bank1_mut().sr.read(); + sr1.wbne().bit_is_set() + } + + /// Returns `true` if write buffer is not empty in bank 2 + fn bank2_is_buffering(&self) -> bool { + let sr2 = self.registers.bank2_mut().sr.read(); + sr2.wbne().bit_is_set() + } + + /// Erase a sector. + pub fn erase_sector(&mut self, bank_number: u8, sector_number: u8) -> Result<(), Error> { + // Assert parameters validity + assert!(bank_number == 1 || bank_number == 2); + assert!(sector_number < 8); + // 1. Check & clear error flags + self.clear_errors(); + // 2. Unlock FLASH_CR1/2 register if necessary + self.unlock(); + // 3. Set SER1/2 & SNB1/2 bits in FLASH_CR1/2 register + // 4. Set START1/2 bit in FLASH_CR1/2 register + match bank_number { + 1 => { + self.registers.bank1_mut().cr.modify(|_, w| unsafe { + w.ser() + .set_bit() + .snb() + .bits(sector_number) + }); + self.registers.bank1_mut().cr.modify(|_, w| { + w.start().set_bit() + }); + }, + 2 => { + self.registers.bank2_mut().cr.modify(|_, w| unsafe { + w.ser() + .set_bit() + .snb() + .bits(sector_number) + }); + self.registers.bank2_mut().cr.modify(|_, w| { + w.start().set_bit() + }); + }, + _ => unreachable!() + } + // Lock the flash CR again + self.lock(); + Ok(()) + } + + /// Erase a bank. + pub fn erase_bank(&mut self, bank_number: u8) -> Result<(), Error> { + // Assert parameters validity + assert!(bank_number == 1 || bank_number == 2); + // 1. Check & clear error flags + self.clear_errors(); + // 2. Unlock FLASH_CR1/2 register if necessary + self.unlock(); + // 3 & 4. Set BER1/2 bit and START1/2 bit in FLASH_CR1/2 register + // Wait until the corresponding QW1/2 bit is cleared. + // Note: By setting BER1/2 bit alongside START1/2, + // mass erase is invoked since it supersedes sector erase. + match bank_number { + 1 => { + self.registers.bank1_mut().cr.modify(|_, w| { + w.ber() + .set_bit() + .start() + .set_bit() + }); + while self.registers.bank1_mut().sr.read().qw().bit_is_set() {} + }, + 2 => { + self.registers.bank2_mut().cr.modify(|_, w| { + w.ber() + .set_bit() + .start() + .set_bit() + }); + while self.registers.bank2_mut().sr.read().qw().bit_is_set() {} + }, + _ => unreachable!() + } + // Lock the flash CR again + self.lock(); + Ok(()) + } + + /// Mass erases of the flash memory. + pub fn mass_erase(&mut self) -> Result<(), Error> { + // 1. Check & clear error flags + self.clear_errors(); + // 2. Unlock Flash_CR1&2, FLASH_OPTCR registers + self.unlock(); + self.unlock_optcr(); + // 3. Set MER in FLASH_OPTCR to 1, wait until both QW to clear + self.registers.optcr_mut().modify(|_, w| { + w.mer().set_bit() + }); + while self.is_queuing() {} + // Lock the flash CR and OPTCR again + self.lock(); + self.lock_optcr(); + Ok(()) + } + + /// Program flash words (32-bytes). + /// Flashing incomplete flash word is "tolerated", but you have been warned.. + pub fn program<'a, 'b>( + &'a mut self, + start_offset: usize, + data: &'b [u8], + ) -> Result<(), Error> { + if (start_offset % 32 != 0) || (data.len() % 32 != 0) { + log::warn!("Warning: This flash operation might not be supported..."); + log::warn!("Consider force writing the data in buffer..."); + } + self.clear_errors(); + // Invoke single writes per 32-bytes row + let mut current_address = start_offset; + let mut remaining_data = data; + while remaining_data.len() != 0 { + let single_write_size = 32 - (current_address % 32); + // Determine the index that split the coming row and the remaining bytes. + let splitting_index = core::cmp::min( + single_write_size, + remaining_data.len() + ); + let single_row_data = &remaining_data[..splitting_index]; + // 1. Unlock FLASH_CR1/2 register if necessary + self.unlock(); + // 2. Set PG bit in FLASH_CR1/2 + self.registers.bank1_mut().cr.modify(|_, w| { + w.pg().set_bit() + }); + self.registers.bank2_mut().cr.modify(|_, w| { + w.pg().set_bit() + }); + // 3. Check Protection + // There should not be any data protection anyway... + // 4. Write data byte by byte + for (index, byte) in single_row_data.iter().enumerate() { + while self.is_busy() {} + match self.check_errors() { + Ok(_) => { + let address: *mut u8 = unsafe { + FLASH_BASE.add(current_address + index) + }; + if address > MAX_FLASH_ADDRESS { + self.registers.bank1_mut().cr.modify(|_, w| w.pg().clear_bit()); + self.registers.bank2_mut().cr.modify(|_, w| w.pg().clear_bit()); + return Err(Error::WriteError); + } else { + unsafe { + core::ptr::write_volatile(address, *byte); + } + } + }, + Err(error) => { + self.registers.bank1_mut().cr.modify(|_, w| w.pg().clear_bit()); + self.registers.bank2_mut().cr.modify(|_, w| w.pg().clear_bit()); + return Err(error); + } + } } + // 5. Wait till the command queue of the device to be empty + while self.is_queuing() {} + // Modify remaining data and the address for next 32-bytes row. + remaining_data = &remaining_data[splitting_index..]; + current_address += single_row_data.len(); } + // Reset PG1/2 + self.registers.bank1_mut().cr.modify(|_, w| w.pg().clear_bit()); + self.registers.bank2_mut().cr.modify(|_, w| w.pg().clear_bit()); + // Lock FLASH_CR1/2 register + self.lock(); + Ok(()) } - *addr += record_length; - (key, string) -} -pub fn read_flash(addr: &mut u32) - -> (net::wire::IpCidr, net::wire::EthernetAddress, nal::Ipv4Addr, String) -{ - let mut cidr = net::wire::IpCidr::Ipv6( - net::wire::Ipv6Cidr::SOLICITED_NODE_PREFIX, - ); - let mut eth = net::wire::EthernetAddress::BROADCAST; - let mut ip = nal::Ipv4Addr::unspecified(); - let mut name = String::new(); - loop { - let (key, string) = read_flash_str(addr); - if key.len() == 0 { - return (cidr, eth, ip, name); + /// Force empty the bytes buffer for flash programming + /// Warning: It can invalidate the whole flash due to invalid CRC. + pub fn force_write<'a>( + &'a mut self + ) -> Result<(), Error> { + if self.bank1_is_buffering() { + self.registers.bank1_mut().cr.modify( + |_, w| w.fw().set_bit() + ); } - match key.as_str() { - "CIDR" => cidr = net::wire::IpCidr::from_str(&string).unwrap(), - "MAC" => eth = net::wire::EthernetAddress::from_str(&string).unwrap(), - "BrokerIP" => ip = nal::Ipv4Addr::from_str(&string).unwrap(), - "Name" => name = string, - _ => {}, + if self.bank2_is_buffering() { + self.registers.bank2_mut().cr.modify( + |_, w| w.fw().set_bit() + ); + } + Ok(()) + } + + /// Read a slice from flash memory + pub fn read(&self, start_offset: usize, len: usize) -> &'static [u8] { + let address = unsafe { + FLASH_BASE.add(start_offset) + }; + unsafe { core::slice::from_raw_parts(address, len) } + } + + /// Releases the flash peripheral. + pub fn free(self) -> FLASH { + self.registers + } + + /// Checks the error flags. + fn check_errors(&self) -> Result<(), Error> { + let (sr1, sr2) = ( + self.registers.bank1_mut().sr.read(), + self.registers.bank2_mut().sr.read() + ); + + if sr1.wrperr().bit_is_set() || sr2.wrperr().bit_is_set() { + Err(Error::WriteProtection) + } else if sr1.pgserr().bit_is_set() || sr2.pgserr().bit_is_set() { + Err(Error::ProgrammingSequence) + } else if sr1.strberr().bit_is_set() || sr2.strberr().bit_is_set() { + Err(Error::Strobe) + } else if sr1.incerr().bit_is_set() || sr2.incerr().bit_is_set() { + Err(Error::Inconsistency) + } else if sr1.operr().bit_is_set() || sr2.operr().bit_is_set() { + Err(Error::Operation) + } else if sr1.sneccerr1().bit_is_set() || sr1.dbeccerr().bit_is_set() + || sr2.sneccerr1().bit_is_set() || sr2.dbeccerr().bit_is_set() { + Err(Error::ErrorCorrectionCode) + } else if sr1.rdperr().bit_is_set() || sr2.rdperr().bit_is_set() { + Err(Error::ReadProtection) + } else if sr1.rdserr().bit_is_set() || sr2.rdserr().bit_is_set() { + Err(Error::ReadSecure) + } else { + Ok(()) } } + + /// Clears all error flags. + fn clear_errors(&mut self) { + self.registers.bank1_mut().ccr.write(|w| { + w.clr_wrperr() + .set_bit() + .clr_pgserr() + .set_bit() + .clr_strberr() + .set_bit() + .clr_incerr() + .set_bit() + .clr_operr() + .set_bit() + .clr_rdperr() + .set_bit() + .clr_rdserr() + .set_bit() + .clr_sneccerr() + .set_bit() + .clr_dbeccerr() + .set_bit() + }); + self.registers.bank2_mut().ccr.write(|w| { + w.clr_wrperr() + .set_bit() + .clr_pgserr() + .set_bit() + .clr_strberr() + .set_bit() + .clr_incerr() + .set_bit() + .clr_operr() + .set_bit() + .clr_rdperr() + .set_bit() + .clr_rdserr() + .set_bit() + .clr_sneccerr() + .set_bit() + .clr_dbeccerr() + .set_bit() + }); + } }