From d4e2caab31c1e9802120141cebc0a00b04471c16 Mon Sep 17 00:00:00 2001 From: Valentin Trophime Date: Wed, 12 Nov 2025 13:19:42 +0100 Subject: Add docs for embassy-rp::pio::get_x assumption about autopush. --- embassy-rp/CHANGELOG.md | 2 ++ embassy-rp/src/pio/instr.rs | 16 ++++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/embassy-rp/CHANGELOG.md b/embassy-rp/CHANGELOG.md index 3b3cb5351..4b0d738a7 100644 --- a/embassy-rp/CHANGELOG.md +++ b/embassy-rp/CHANGELOG.md @@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased - ReleaseDate +- Add documentation for pio `get_x` about autopush. - Fix several minor typos in documentation - Add PIO SPI - Add PIO I2S input @@ -114,3 +115,4 @@ Small release fixing a few gnarly bugs, upgrading is strongly recommended. - rename the Channel trait to Slice and the PwmPin to PwmChannel - i2c: Fix race condition that appears on fast repeated transfers. - Add a basic "read to break" function + diff --git a/embassy-rp/src/pio/instr.rs b/embassy-rp/src/pio/instr.rs index b15d507de..304ddb20a 100644 --- a/embassy-rp/src/pio/instr.rs +++ b/embassy-rp/src/pio/instr.rs @@ -5,6 +5,10 @@ use crate::pio::{Instance, StateMachine}; impl<'d, PIO: Instance, const SM: usize> StateMachine<'d, PIO, SM> { /// Set value of scratch register X. + /// + /// SAFETY: autopull enabled else it will write undefined data. + /// Make sure to have setup the according configuration see + /// [shift_out](crate::pio::Config::shift_out) and [auto_fill](crate::pio::ShiftConfig::auto_fill). pub unsafe fn set_x(&mut self, value: u32) { const OUT: u16 = InstructionOperands::OUT { destination: OutDestination::X, @@ -16,6 +20,10 @@ impl<'d, PIO: Instance, const SM: usize> StateMachine<'d, PIO, SM> { } /// Get value of scratch register X. + /// + /// SAFETY: autopush enabled else it will read undefined data. + /// Make sure to have setup the according configurations see + /// [shift_in](crate::pio::Config::shift_in) and [auto_fill](crate::pio::ShiftConfig::auto_fill). pub unsafe fn get_x(&mut self) -> u32 { const IN: u16 = InstructionOperands::IN { source: InSource::X, @@ -27,6 +35,10 @@ impl<'d, PIO: Instance, const SM: usize> StateMachine<'d, PIO, SM> { } /// Set value of scratch register Y. + /// + /// SAFETY: autopull enabled else it will write undefined data. + /// Make sure to have setup the according configuration see + /// [shift_out](crate::pio::Config::shift_out) and [auto_fill](crate::pio::ShiftConfig::auto_fill). pub unsafe fn set_y(&mut self, value: u32) { const OUT: u16 = InstructionOperands::OUT { destination: OutDestination::Y, @@ -38,6 +50,10 @@ impl<'d, PIO: Instance, const SM: usize> StateMachine<'d, PIO, SM> { } /// Get value of scratch register Y. + /// + /// SAFETY: autopush enabled else it will read undefined data. + /// Make sure to have setup the according configurations see + /// [shift_in](crate::pio::Config::shift_in) and [auto_fill](crate::pio::ShiftConfig::auto_fill). pub unsafe fn get_y(&mut self) -> u32 { const IN: u16 = InstructionOperands::IN { source: InSource::Y, -- cgit From 4efd9fccf4259779d96c5d1a4829a90bda1a5def Mon Sep 17 00:00:00 2001 From: Wouter Geraedts Date: Wed, 12 Nov 2025 20:48:03 +0100 Subject: Fix flash erase on dualbank STM32Gxxx --- embassy-stm32/CHANGELOG.md | 1 + embassy-stm32/src/flash/g.rs | 5 ++--- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/embassy-stm32/CHANGELOG.md b/embassy-stm32/CHANGELOG.md index 3431848d3..b418faee6 100644 --- a/embassy-stm32/CHANGELOG.md +++ b/embassy-stm32/CHANGELOG.md @@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased - ReleaseDate +- fix: flash erase on dual-bank STM32Gxxx - feat: Add support for STM32N657X0 - feat: timer: Add 32-bit timer support to SimplePwm waveform_up method following waveform pattern ([#4717](https://github.com/embassy-rs/embassy/pull/4717)) - feat: Add support for injected ADC measurements for g4 ([#4840](https://github.com/embassy-rs/embassy/pull/4840)) diff --git a/embassy-stm32/src/flash/g.rs b/embassy-stm32/src/flash/g.rs index d026541a4..d7ba2f571 100644 --- a/embassy-stm32/src/flash/g.rs +++ b/embassy-stm32/src/flash/g.rs @@ -44,7 +44,6 @@ pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) } pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> { - let idx = (sector.start - super::FLASH_BASE as u32) / super::BANK1_REGION.erase_size as u32; wait_busy(); clear_all_err(); @@ -54,9 +53,9 @@ pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), E #[cfg(any(flash_g0x0, flash_g0x1, flash_g4c3))] w.set_bker(sector.bank == crate::flash::FlashBank::Bank2); #[cfg(flash_g0x0)] - w.set_pnb(idx as u16); + w.set_pnb(sector.index_in_bank as u16); #[cfg(not(flash_g0x0))] - w.set_pnb(idx as u8); + w.set_pnb(sector.index_in_bank as u8); w.set_strt(true); }); }); -- cgit From dccf185e1489c0055fcacdea59ce7837cc4d076d Mon Sep 17 00:00:00 2001 From: "Andreas Lindahl Flåten (ALF)" Date: Wed, 5 Nov 2025 16:47:09 +0100 Subject: Add c.rs flash for the stm32c0 family This is basically a copy of the `g.rs` file, with multi bank support removed (c0 is single bank only). --- embassy-stm32/src/flash/c.rs | 122 ++++++++++++++++++++++++++++++++++++++ embassy-stm32/src/flash/common.rs | 2 +- embassy-stm32/src/flash/mod.rs | 3 +- 3 files changed, 125 insertions(+), 2 deletions(-) create mode 100644 embassy-stm32/src/flash/c.rs diff --git a/embassy-stm32/src/flash/c.rs b/embassy-stm32/src/flash/c.rs new file mode 100644 index 000000000..af3d07ac6 --- /dev/null +++ b/embassy-stm32/src/flash/c.rs @@ -0,0 +1,122 @@ +use core::ptr::write_volatile; +use core::sync::atomic::{Ordering, fence}; + +use cortex_m::interrupt; + +use super::{FlashSector, WRITE_SIZE}; +use crate::flash::Error; +use crate::pac; + +pub(crate) unsafe fn lock() { + pac::FLASH.cr().modify(|w| w.set_lock(true)); +} +pub(crate) unsafe fn unlock() { + // Wait, while the memory interface is busy. + wait_busy(); + + // Unlock flash + if pac::FLASH.cr().read().lock() { + pac::FLASH.keyr().write_value(0x4567_0123); + pac::FLASH.keyr().write_value(0xCDEF_89AB); + } +} + +pub(crate) unsafe fn enable_blocking_write() { + assert_eq!(0, WRITE_SIZE % 4); + pac::FLASH.cr().write(|w| w.set_pg(true)); +} + +pub(crate) unsafe fn disable_blocking_write() { + pac::FLASH.cr().write(|w| w.set_pg(false)); +} + +pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) -> Result<(), Error> { + let mut address = start_address; + for val in buf.chunks(4) { + write_volatile(address as *mut u32, u32::from_le_bytes(unwrap!(val.try_into()))); + address += val.len() as u32; + + // prevents parallelism errors + fence(Ordering::SeqCst); + } + + wait_ready_blocking() +} + +pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> { + let idx = (sector.start - super::FLASH_BASE as u32) / super::BANK1_REGION.erase_size as u32; + + #[cfg(feature = "defmt")] + defmt::trace!("STM32C0 Erase: addr=0x{:08x}, idx={}, erase_size={}", sector.start, idx, super::BANK1_REGION.erase_size); + + + wait_busy(); + clear_all_err(); + + // Explicitly unlock before erase + unlock(); + + interrupt::free(|_| { + #[cfg(feature = "defmt")] + { + let cr_before = pac::FLASH.cr().read(); + defmt::trace!("FLASH_CR before: 0x{:08x}", cr_before.0); + } + + pac::FLASH.cr().modify(|w| { + w.set_per(true); + w.set_pnb(idx as u8); + w.set_strt(true); + }); + + #[cfg(feature = "defmt")] + { + let cr_after = pac::FLASH.cr().read(); + defmt::trace!("FLASH_CR after: 0x{:08x}, PER={}, PNB={}, STRT={}", + cr_after.0, cr_after.per(), cr_after.pnb(), cr_after.strt()); + } + }); + + let ret: Result<(), Error> = wait_ready_blocking(); + + // Clear erase bit + pac::FLASH.cr().modify(|w| w.set_per(false)); + + // Explicitly lock after erase + lock(); + + // Extra wait to ensure operation completes + wait_busy(); + + ret +} + +pub(crate) unsafe fn wait_ready_blocking() -> Result<(), Error> { + while pac::FLASH.sr().read().bsy() {} + + let sr = pac::FLASH.sr().read(); + + if sr.progerr() { + return Err(Error::Prog); + } + + if sr.wrperr() { + return Err(Error::Protected); + } + + if sr.pgaerr() { + return Err(Error::Unaligned); + } + + Ok(()) +} + +pub(crate) unsafe fn clear_all_err() { + // read and write back the same value. + // This clears all "write 1 to clear" bits. + pac::FLASH.sr().modify(|_| {}); +} + +fn wait_busy() { + while pac::FLASH.sr().read().bsy() {} +} diff --git a/embassy-stm32/src/flash/common.rs b/embassy-stm32/src/flash/common.rs index b595938a6..508bb2548 100644 --- a/embassy-stm32/src/flash/common.rs +++ b/embassy-stm32/src/flash/common.rs @@ -102,7 +102,7 @@ pub(super) unsafe fn blocking_write( } let mut address = base + offset; - trace!("Writing {} bytes at 0x{:x}", bytes.len(), address); + trace!("Writing {} bytes at 0x{:x} (base=0x{:x}, offset=0x{:x})", bytes.len(), address, base, offset); for chunk in bytes.chunks(WRITE_SIZE) { write_chunk(address, chunk)?; diff --git a/embassy-stm32/src/flash/mod.rs b/embassy-stm32/src/flash/mod.rs index 3e74d857a..39cd9b3a9 100644 --- a/embassy-stm32/src/flash/mod.rs +++ b/embassy-stm32/src/flash/mod.rs @@ -99,6 +99,7 @@ compile_error!("The 'eeprom' cfg is enabled for a non-L0/L1 chip family. This is #[cfg_attr(flash_f4, path = "f4.rs")] #[cfg_attr(flash_f7, path = "f7.rs")] #[cfg_attr(any(flash_g0x0, flash_g0x1, flash_g4c2, flash_g4c3, flash_g4c4), path = "g.rs")] +#[cfg_attr(flash_c0, path = "c.rs")] #[cfg_attr(flash_h7, path = "h7.rs")] #[cfg_attr(flash_h7ab, path = "h7.rs")] #[cfg_attr(any(flash_u5, flash_wba), path = "u5.rs")] @@ -108,7 +109,7 @@ compile_error!("The 'eeprom' cfg is enabled for a non-L0/L1 chip family. This is #[cfg_attr( not(any( flash_l0, flash_l1, flash_l4, flash_l5, flash_wl, flash_wb, flash_f0, flash_f1, flash_f2, flash_f3, flash_f4, - flash_f7, flash_g0x0, flash_g0x1, flash_g4c2, flash_g4c3, flash_g4c4, flash_h7, flash_h7ab, flash_u5, + flash_f7, flash_g0x0, flash_g0x1, flash_g4c2, flash_g4c3, flash_g4c4, flash_c0, flash_h7, flash_h7ab, flash_u5, flash_wba, flash_h50, flash_u0, flash_h5, )), path = "other.rs" -- cgit From f72349660eb30f6fc32104db60c33a732a99f6b5 Mon Sep 17 00:00:00 2001 From: "Andreas Lindahl Flåten (ALF)" Date: Thu, 13 Nov 2025 11:24:43 +0100 Subject: add changelog and fix rustfmt errors --- embassy-stm32/CHANGELOG.md | 1 + embassy-stm32/src/flash/c.rs | 17 +++++++++++++---- embassy-stm32/src/flash/common.rs | 8 +++++++- 3 files changed, 21 insertions(+), 5 deletions(-) diff --git a/embassy-stm32/CHANGELOG.md b/embassy-stm32/CHANGELOG.md index 3431848d3..7586861ef 100644 --- a/embassy-stm32/CHANGELOG.md +++ b/embassy-stm32/CHANGELOG.md @@ -55,6 +55,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - chore: Updated stm32-metapac and stm32-data dependencies - adc: reogranize and cleanup somewhat. require sample_time to be passed on conversion - fix: stm32/i2c v2 slave: prevent misaligned reads, error false positives, and incorrect counts of bytes read/written +- feat: add flash support for c0 family ([#4874](https://github.com/embassy-rs/embassy/pull/4874)) ## 0.4.0 - 2025-08-26 diff --git a/embassy-stm32/src/flash/c.rs b/embassy-stm32/src/flash/c.rs index af3d07ac6..0ad1002b0 100644 --- a/embassy-stm32/src/flash/c.rs +++ b/embassy-stm32/src/flash/c.rs @@ -47,8 +47,12 @@ pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), E let idx = (sector.start - super::FLASH_BASE as u32) / super::BANK1_REGION.erase_size as u32; #[cfg(feature = "defmt")] - defmt::trace!("STM32C0 Erase: addr=0x{:08x}, idx={}, erase_size={}", sector.start, idx, super::BANK1_REGION.erase_size); - + defmt::trace!( + "STM32C0 Erase: addr=0x{:08x}, idx={}, erase_size={}", + sector.start, + idx, + super::BANK1_REGION.erase_size + ); wait_busy(); clear_all_err(); @@ -72,8 +76,13 @@ pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), E #[cfg(feature = "defmt")] { let cr_after = pac::FLASH.cr().read(); - defmt::trace!("FLASH_CR after: 0x{:08x}, PER={}, PNB={}, STRT={}", - cr_after.0, cr_after.per(), cr_after.pnb(), cr_after.strt()); + defmt::trace!( + "FLASH_CR after: 0x{:08x}, PER={}, PNB={}, STRT={}", + cr_after.0, + cr_after.per(), + cr_after.pnb(), + cr_after.strt() + ); } }); diff --git a/embassy-stm32/src/flash/common.rs b/embassy-stm32/src/flash/common.rs index 508bb2548..60d00e766 100644 --- a/embassy-stm32/src/flash/common.rs +++ b/embassy-stm32/src/flash/common.rs @@ -102,7 +102,13 @@ pub(super) unsafe fn blocking_write( } let mut address = base + offset; - trace!("Writing {} bytes at 0x{:x} (base=0x{:x}, offset=0x{:x})", bytes.len(), address, base, offset); + trace!( + "Writing {} bytes at 0x{:x} (base=0x{:x}, offset=0x{:x})", + bytes.len(), + address, + base, + offset + ); for chunk in bytes.chunks(WRITE_SIZE) { write_chunk(address, chunk)?; -- cgit