Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

flash: fence ordering to ensure pg bit is set before write to flash memory #383

Merged
merged 4 commits into from
Aug 29, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

## [Unreleased]

* flash: Use Ordering fence to prevent inconsistency errors when writing to flash sector [#382]
* flash: Rewrite `write_sector` to correctly write data in 256 bit chunks [#371]
* iwdt: Added HAL implementation. Changed the name of the other implementation to `system_watchdog` [#376]
* pac: Upgrade to stm32-rs v0.15.1 [#370]
Expand Down
32 changes: 19 additions & 13 deletions src/flash.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
//! Note: STM32H750xB is not yet supported

use crate::stm32::{flash, FLASH};
use core::sync::atomic::{fence, Ordering};

#[cfg(all(
any(feature = "rm0433"),
Expand Down Expand Up @@ -164,8 +165,8 @@ impl Bank {
/// The number of bytes within the bank
pub fn size(&self) -> usize {
match *self {
Bank::UserBank1 => (BANK1_ADDR_END - BANK1_ADDR_START),
Bank::UserBank2 => (BANK2_ADDR_END - BANK2_ADDR_START),
Bank::UserBank1 => BANK1_ADDR_END - BANK1_ADDR_START,
Bank::UserBank2 => BANK2_ADDR_END - BANK2_ADDR_START,
}
}
/// The number of sectors within the bank, including sector zero
Expand Down Expand Up @@ -440,27 +441,31 @@ impl Flash {
// Ensure no effective write, erase or option byte change operation is ongoing
while regs.sr.read().bsy().bit_is_set() {}

// 1. Clear all the error flags due to previous programming/erase operation. Refer to Section 4.7: FLASH error management for details.
// Clear all the error flags due to previous programming/erase operation. Refer to Section 4.7: FLASH error management for details.
clear_error_flags(regs);

// 2. Unlock the FLASH_CR1/2 register, as described in Section 4.5.1: FLASH configuration protection (only if register is not already unlocked).
// Unlock the FLASH_CR1/2 register, as described in Section 4.5.1: FLASH configuration protection (only if register is not already unlocked).
self.unlock(bank)?;

// 3. Enable double-word parallelism.
// Enable double-word parallelism.
unsafe { regs.cr.modify(|_, w| w.psize().bits(0b11)) }

// 4. Enable write operations by setting the PG1/2 bit in the FLASH_CR1/2 register.
// Enable write operations by setting the PG1/2 bit in the FLASH_CR1/2 register.
regs.cr.modify(|_, w| w.pg().set_bit());

// 5. Check the protection of the targeted memory area.
// Ensure that the write to Device memory to set the appropriate PG CR bit occurs
// *before* we begin writing to Normal flash memory. This is to prevent PROGRAMMING_SEQUENCE errors
fence(Ordering::SeqCst);

// Check the protection of the targeted memory area.
// SKIP: In standard mode the entire UserBank1 and UserBank2 should have no write protections

let mut addr = bank.sector_address(sector) as *mut u32;

// Offset it by the start position
addr = unsafe { addr.add(start / 4) };

// 6. Write a double-word corresponding to 32-byte data starting at a 32-byte aligned address.
// Write a double-word corresponding to 32-byte data starting at a 32-byte aligned address.
for chunk in data.chunks_exact(32) {
if addr as usize > bank.end_address() {
// Unable to write outside of the bank end address
Expand All @@ -479,19 +484,18 @@ impl Flash {
}
}

// 7. Wait until the write buffer is complete (WBNE1/WBNE2) and all operations have finished (QW1/QW2).
// Wait until the write buffer is complete (WBNE1/WBNE2) and all operations have finished (QW1/QW2).
while {
let sr = regs.sr.read();
sr.wbne().bit_is_set() | sr.qw().bit_is_set()
} {}
}

// 8. Cleanup by clearing the PG bit
// Cleanup by clearing the PG bit and relocking the bank
regs.cr.modify(|_, w| w.pg().clear_bit());

self.lock(bank);

// 9. Check all the error flags due to previous programming/erase operation. Refer to Section 4.7: FLASH error management for details.
// Check all the error flags due to previous programming/erase operation. Refer to Section 4.7: FLASH error management for details.
handle_illegal(self.bank_registers(bank))?;

Ok(())
Expand Down Expand Up @@ -520,6 +524,8 @@ fn clear_error_flags(regs: &BANK) {
.set_bit()
.rdserr()
.set_bit()
.incerr()
.set_bit()
})
}

Expand All @@ -529,10 +535,10 @@ fn clear_error_flags(regs: &BANK) {
not(feature = "stm32h750v")
))]
/// Handle illegal status flags
/// TODO: Clear error flags
fn handle_illegal(regs: &BANK) -> Result<(), Error> {
let sr = regs.sr.read();
let mut bank_err = BankError::empty();

if sr.pgserr().bit_is_set() {
bank_err |= BankError::PROGRAMMING_SEQUENCE;
}
Expand Down