Add flash example & flash HIL test
This commit is contained in:
parent
ad0eb3f4bd
commit
80e58426fc
2
ci.sh
2
ci.sh
@ -121,7 +121,7 @@ cargo batch \
|
|||||||
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h755zi --out-dir out/tests/nucleo-stm32h755zi \
|
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h755zi --out-dir out/tests/nucleo-stm32h755zi \
|
||||||
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32wb55rg --out-dir out/tests/nucleo-stm32wb55rg \
|
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32wb55rg --out-dir out/tests/nucleo-stm32wb55rg \
|
||||||
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32u585ai --out-dir out/tests/iot-stm32u585ai \
|
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32u585ai --out-dir out/tests/iot-stm32u585ai \
|
||||||
--- build --release --manifest-path tests/rp/Cargo.toml --target thumbv6m-none-eabi --features embassy-rp/time-driver --out-dir out/tests/rpi-pico \
|
--- build --release --manifest-path tests/rp/Cargo.toml --target thumbv6m-none-eabi --out-dir out/tests/rpi-pico \
|
||||||
$BUILD_EXTRA
|
$BUILD_EXTRA
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,8 +1,13 @@
|
|||||||
|
use core::marker::PhantomData;
|
||||||
|
|
||||||
|
use embassy_hal_common::Peripheral;
|
||||||
use embedded_storage::nor_flash::{
|
use embedded_storage::nor_flash::{
|
||||||
check_erase, check_read, check_write, ErrorType, MultiwriteNorFlash, NorFlash, NorFlashError, NorFlashErrorKind,
|
check_erase, check_read, check_write, ErrorType, MultiwriteNorFlash, NorFlash, NorFlashError, NorFlashErrorKind,
|
||||||
ReadNorFlash,
|
ReadNorFlash,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use crate::peripherals::FLASH;
|
||||||
|
|
||||||
pub const FLASH_BASE: usize = 0x10000000;
|
pub const FLASH_BASE: usize = 0x10000000;
|
||||||
|
|
||||||
// **NOTE**:
|
// **NOTE**:
|
||||||
@ -46,9 +51,13 @@ impl NorFlashError for Error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Flash<const FLASH_SIZE: usize>;
|
pub struct Flash<'d, T: Instance, const FLASH_SIZE: usize>(PhantomData<&'d mut T>);
|
||||||
|
|
||||||
|
impl<'d, T: Instance, const FLASH_SIZE: usize> Flash<'d, T, FLASH_SIZE> {
|
||||||
|
pub fn new(_flash: impl Peripheral<P = T> + 'd) -> Self {
|
||||||
|
Self(PhantomData)
|
||||||
|
}
|
||||||
|
|
||||||
impl<const FLASH_SIZE: usize> Flash<FLASH_SIZE> {
|
|
||||||
/// Make sure to uphold the contract points with rp2040-flash.
|
/// Make sure to uphold the contract points with rp2040-flash.
|
||||||
/// - interrupts must be disabled
|
/// - interrupts must be disabled
|
||||||
/// - DMA must not access flash memory
|
/// - DMA must not access flash memory
|
||||||
@ -81,11 +90,11 @@ impl<const FLASH_SIZE: usize> Flash<FLASH_SIZE> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<const FLASH_SIZE: usize> ErrorType for Flash<FLASH_SIZE> {
|
impl<'d, T: Instance, const FLASH_SIZE: usize> ErrorType for Flash<'d, T, FLASH_SIZE> {
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<const FLASH_SIZE: usize> ReadNorFlash for Flash<FLASH_SIZE> {
|
impl<'d, T: Instance, const FLASH_SIZE: usize> ReadNorFlash for Flash<'d, T, FLASH_SIZE> {
|
||||||
const READ_SIZE: usize = READ_SIZE;
|
const READ_SIZE: usize = READ_SIZE;
|
||||||
|
|
||||||
fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> {
|
fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> {
|
||||||
@ -102,9 +111,9 @@ impl<const FLASH_SIZE: usize> ReadNorFlash for Flash<FLASH_SIZE> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<const FLASH_SIZE: usize> MultiwriteNorFlash for Flash<FLASH_SIZE> {}
|
impl<'d, T: Instance, const FLASH_SIZE: usize> MultiwriteNorFlash for Flash<'d, T, FLASH_SIZE> {}
|
||||||
|
|
||||||
impl<const FLASH_SIZE: usize> NorFlash for Flash<FLASH_SIZE> {
|
impl<'d, T: Instance, const FLASH_SIZE: usize> NorFlash for Flash<'d, T, FLASH_SIZE> {
|
||||||
const WRITE_SIZE: usize = WRITE_SIZE;
|
const WRITE_SIZE: usize = WRITE_SIZE;
|
||||||
|
|
||||||
const ERASE_SIZE: usize = ERASE_SIZE;
|
const ERASE_SIZE: usize = ERASE_SIZE;
|
||||||
@ -112,6 +121,12 @@ impl<const FLASH_SIZE: usize> NorFlash for Flash<FLASH_SIZE> {
|
|||||||
fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> {
|
fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> {
|
||||||
check_erase(self, from, to)?;
|
check_erase(self, from, to)?;
|
||||||
|
|
||||||
|
trace!(
|
||||||
|
"Erasing from 0x{:x} to 0x{:x}",
|
||||||
|
FLASH_BASE as u32 + from,
|
||||||
|
FLASH_BASE as u32 + to
|
||||||
|
);
|
||||||
|
|
||||||
let len = to - from;
|
let len = to - from;
|
||||||
|
|
||||||
unsafe { self.in_ram(|| ram_helpers::flash_range_erase(from, len, true)) };
|
unsafe { self.in_ram(|| ram_helpers::flash_range_erase(from, len, true)) };
|
||||||
@ -122,7 +137,7 @@ impl<const FLASH_SIZE: usize> NorFlash for Flash<FLASH_SIZE> {
|
|||||||
fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> {
|
fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> {
|
||||||
check_write(self, offset, bytes.len())?;
|
check_write(self, offset, bytes.len())?;
|
||||||
|
|
||||||
trace!("Writing {:?} bytes to 0x{:x}", bytes.len(), offset);
|
trace!("Writing {:?} bytes to 0x{:x}", bytes.len(), FLASH_BASE as u32 + offset);
|
||||||
|
|
||||||
let end_offset = offset as usize + bytes.len();
|
let end_offset = offset as usize + bytes.len();
|
||||||
|
|
||||||
@ -351,6 +366,7 @@ mod ram_helpers {
|
|||||||
rom_data::flash_flush_cache();
|
rom_data::flash_flush_cache();
|
||||||
rom_data::flash_enter_cmd_xip();
|
rom_data::flash_enter_cmd_xip();
|
||||||
*/
|
*/
|
||||||
|
#[cfg(target_arch = "arm")]
|
||||||
core::arch::asm!(
|
core::arch::asm!(
|
||||||
"mov r8, r0",
|
"mov r8, r0",
|
||||||
"mov r9, r2",
|
"mov r9, r2",
|
||||||
@ -402,3 +418,12 @@ mod ram_helpers {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mod sealed {
|
||||||
|
pub trait Instance {}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait Instance: sealed::Instance {}
|
||||||
|
|
||||||
|
impl sealed::Instance for FLASH {}
|
||||||
|
impl Instance for FLASH {}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
#![macro_use]
|
#![macro_use]
|
||||||
|
|
||||||
// Credit: taken from `rp-hal` (also licensed Apache+MIT)
|
// Credit: taken from `rp-hal` (also licensed Apache+MIT)
|
||||||
// https://github.com/rp-rs/rp-hal/blob/main/rp2040-hal/src/intrinsics.rs
|
// https://github.com/rp-rs/rp-hal/blob/main/rp2040-hal/src/intrinsics.rs
|
||||||
|
|
||||||
|
@ -96,6 +96,8 @@ embassy_hal_common::peripherals! {
|
|||||||
USB,
|
USB,
|
||||||
|
|
||||||
RTC,
|
RTC,
|
||||||
|
|
||||||
|
FLASH,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[link_section = ".boot2"]
|
#[link_section = ".boot2"]
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
//! > on the device, as well as highly optimized versions of certain key
|
//! > on the device, as well as highly optimized versions of certain key
|
||||||
//! > functionality that would otherwise have to take up space in most user
|
//! > functionality that would otherwise have to take up space in most user
|
||||||
//! > binaries.
|
//! > binaries.
|
||||||
|
|
||||||
// Credit: taken from `rp-hal` (also licensed Apache+MIT)
|
// Credit: taken from `rp-hal` (also licensed Apache+MIT)
|
||||||
// https://github.com/rp-rs/rp-hal/blob/main/rp2040-hal/src/rom_data.rs
|
// https://github.com/rp-rs/rp-hal/blob/main/rp2040-hal/src/rom_data.rs
|
||||||
|
|
||||||
|
@ -30,6 +30,7 @@ byte-slice-cast = { version = "1.2.0", default-features = false }
|
|||||||
embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9" }
|
embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9" }
|
||||||
embedded-hal-async = { version = "0.1.0-alpha.1" }
|
embedded-hal-async = { version = "0.1.0-alpha.1" }
|
||||||
embedded-io = { version = "0.3.0", features = ["async", "defmt"] }
|
embedded-io = { version = "0.3.0", features = ["async", "defmt"] }
|
||||||
|
embedded-storage = { version = "0.3" }
|
||||||
static_cell = "1.0.0"
|
static_cell = "1.0.0"
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
|
84
examples/rp/src/bin/flash.rs
Normal file
84
examples/rp/src/bin/flash.rs
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
#![no_std]
|
||||||
|
#![no_main]
|
||||||
|
#![feature(type_alias_impl_trait)]
|
||||||
|
|
||||||
|
use defmt::*;
|
||||||
|
use embassy_executor::Spawner;
|
||||||
|
use embassy_rp::flash::{ERASE_SIZE, FLASH_BASE};
|
||||||
|
use embassy_rp::peripherals::FLASH;
|
||||||
|
use embedded_storage::nor_flash::{NorFlash, ReadNorFlash};
|
||||||
|
use {defmt_rtt as _, panic_probe as _};
|
||||||
|
|
||||||
|
const ADDR_OFFSET: u32 = 0x100000;
|
||||||
|
const FLASH_SIZE: usize = 2 * 1024 * 1024;
|
||||||
|
|
||||||
|
#[embassy_executor::main]
|
||||||
|
async fn main(_spawner: Spawner) {
|
||||||
|
let p = embassy_rp::init(Default::default());
|
||||||
|
info!("Hello World!");
|
||||||
|
|
||||||
|
let mut flash = embassy_rp::flash::Flash::<_, FLASH_SIZE>::new(p.FLASH);
|
||||||
|
|
||||||
|
erase_write_sector(&mut flash, 0x00);
|
||||||
|
|
||||||
|
multiwrite_bytes(&mut flash, ERASE_SIZE as u32);
|
||||||
|
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn multiwrite_bytes(flash: &mut embassy_rp::flash::Flash<'_, FLASH, FLASH_SIZE>, offset: u32) {
|
||||||
|
info!(">>>> [multiwrite_bytes]");
|
||||||
|
let mut read_buf = [0u8; ERASE_SIZE];
|
||||||
|
defmt::unwrap!(flash.read(ADDR_OFFSET + offset, &mut read_buf));
|
||||||
|
|
||||||
|
info!("Addr of flash block is {:x}", ADDR_OFFSET + offset + FLASH_BASE as u32);
|
||||||
|
info!("Contents start with {=[u8]}", read_buf[0..4]);
|
||||||
|
|
||||||
|
defmt::unwrap!(flash.erase(ADDR_OFFSET + offset, ADDR_OFFSET + offset + ERASE_SIZE as u32));
|
||||||
|
|
||||||
|
defmt::unwrap!(flash.read(ADDR_OFFSET + offset, &mut read_buf));
|
||||||
|
info!("Contents after erase starts with {=[u8]}", read_buf[0..4]);
|
||||||
|
if read_buf.iter().any(|x| *x != 0xFF) {
|
||||||
|
defmt::panic!("unexpected");
|
||||||
|
}
|
||||||
|
|
||||||
|
defmt::unwrap!(flash.write(ADDR_OFFSET + offset, &[0x01]));
|
||||||
|
defmt::unwrap!(flash.write(ADDR_OFFSET + offset + 1, &[0x02]));
|
||||||
|
defmt::unwrap!(flash.write(ADDR_OFFSET + offset + 2, &[0x03]));
|
||||||
|
defmt::unwrap!(flash.write(ADDR_OFFSET + offset + 3, &[0x04]));
|
||||||
|
|
||||||
|
defmt::unwrap!(flash.read(ADDR_OFFSET + offset, &mut read_buf));
|
||||||
|
info!("Contents after write starts with {=[u8]}", read_buf[0..4]);
|
||||||
|
if &read_buf[0..4] != &[0x01, 0x02, 0x03, 0x04] {
|
||||||
|
defmt::panic!("unexpected");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn erase_write_sector(flash: &mut embassy_rp::flash::Flash<'_, FLASH, FLASH_SIZE>, offset: u32) {
|
||||||
|
info!(">>>> [erase_write_sector]");
|
||||||
|
let mut buf = [0u8; ERASE_SIZE];
|
||||||
|
defmt::unwrap!(flash.read(ADDR_OFFSET + offset, &mut buf));
|
||||||
|
|
||||||
|
info!("Addr of flash block is {:x}", ADDR_OFFSET + offset + FLASH_BASE as u32);
|
||||||
|
info!("Contents start with {=[u8]}", buf[0..4]);
|
||||||
|
|
||||||
|
defmt::unwrap!(flash.erase(ADDR_OFFSET + offset, ADDR_OFFSET + offset + ERASE_SIZE as u32));
|
||||||
|
|
||||||
|
defmt::unwrap!(flash.read(ADDR_OFFSET + offset, &mut buf));
|
||||||
|
info!("Contents after erase starts with {=[u8]}", buf[0..4]);
|
||||||
|
if buf.iter().any(|x| *x != 0xFF) {
|
||||||
|
defmt::panic!("unexpected");
|
||||||
|
}
|
||||||
|
|
||||||
|
for b in buf.iter_mut() {
|
||||||
|
*b = 0xDA;
|
||||||
|
}
|
||||||
|
|
||||||
|
defmt::unwrap!(flash.write(ADDR_OFFSET + offset, &buf));
|
||||||
|
|
||||||
|
defmt::unwrap!(flash.read(ADDR_OFFSET + offset, &mut buf));
|
||||||
|
info!("Contents after write starts with {=[u8]}", buf[0..4]);
|
||||||
|
if buf.iter().any(|x| *x != 0xDA) {
|
||||||
|
defmt::panic!("unexpected");
|
||||||
|
}
|
||||||
|
}
|
@ -22,6 +22,7 @@ embedded-hal-async = { version = "=0.1.0-alpha.2" }
|
|||||||
panic-probe = { version = "0.3.0", features = ["print-defmt"] }
|
panic-probe = { version = "0.3.0", features = ["print-defmt"] }
|
||||||
futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
|
futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
|
||||||
embedded-io = { version = "0.3.0", features = ["async"] }
|
embedded-io = { version = "0.3.0", features = ["async"] }
|
||||||
|
embedded-storage = { version = "0.3" }
|
||||||
|
|
||||||
[profile.dev]
|
[profile.dev]
|
||||||
debug = 2
|
debug = 2
|
||||||
|
48
tests/rp/src/bin/flash.rs
Normal file
48
tests/rp/src/bin/flash.rs
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
#![no_std]
|
||||||
|
#![no_main]
|
||||||
|
#![feature(type_alias_impl_trait)]
|
||||||
|
|
||||||
|
use defmt::*;
|
||||||
|
use embassy_executor::Spawner;
|
||||||
|
use embassy_rp::flash::{ERASE_SIZE, FLASH_BASE};
|
||||||
|
use embedded_storage::nor_flash::{NorFlash, ReadNorFlash};
|
||||||
|
use {defmt_rtt as _, panic_probe as _};
|
||||||
|
|
||||||
|
const ADDR_OFFSET: u32 = 0x4000;
|
||||||
|
|
||||||
|
#[embassy_executor::main]
|
||||||
|
async fn main(_spawner: Spawner) {
|
||||||
|
let p = embassy_rp::init(Default::default());
|
||||||
|
info!("Hello World!");
|
||||||
|
|
||||||
|
let mut flash = embassy_rp::flash::Flash::<_, { 2 * 1024 * 1024 }>::new(p.FLASH);
|
||||||
|
|
||||||
|
let mut buf = [0u8; ERASE_SIZE];
|
||||||
|
defmt::unwrap!(flash.read(ADDR_OFFSET, &mut buf));
|
||||||
|
|
||||||
|
info!("Addr of flash block is {:x}", ADDR_OFFSET + FLASH_BASE as u32);
|
||||||
|
info!("Contents start with {=[u8]}", buf[0..4]);
|
||||||
|
|
||||||
|
defmt::unwrap!(flash.erase(ADDR_OFFSET, ADDR_OFFSET + ERASE_SIZE as u32));
|
||||||
|
|
||||||
|
defmt::unwrap!(flash.read(ADDR_OFFSET, &mut buf));
|
||||||
|
info!("Contents after erase starts with {=[u8]}", buf[0..4]);
|
||||||
|
if buf.iter().any(|x| *x != 0xFF) {
|
||||||
|
defmt::panic!("unexpected");
|
||||||
|
}
|
||||||
|
|
||||||
|
for b in buf.iter_mut() {
|
||||||
|
*b = 0xDA;
|
||||||
|
}
|
||||||
|
|
||||||
|
defmt::unwrap!(flash.write(ADDR_OFFSET, &mut buf));
|
||||||
|
|
||||||
|
defmt::unwrap!(flash.read(ADDR_OFFSET, &mut buf));
|
||||||
|
info!("Contents after write starts with {=[u8]}", buf[0..4]);
|
||||||
|
if buf.iter().any(|x| *x != 0xDA) {
|
||||||
|
defmt::panic!("unexpected");
|
||||||
|
}
|
||||||
|
|
||||||
|
info!("Test OK");
|
||||||
|
cortex_m::asm::bkpt();
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user