diff options
| author | Mathias <[email protected]> | 2022-10-26 10:01:52 +0200 |
|---|---|---|
| committer | Mathias <[email protected]> | 2022-10-26 12:24:04 +0200 |
| commit | 80e58426fcf40b6cea28368e43a7289e827461cf (patch) | |
| tree | 48ce94c3404b3b95c082914376d5510658a18f38 | |
| parent | ad0eb3f4bd2b124fcb7cda6d6bd88e2b12632ea7 (diff) | |
Add flash example & flash HIL test
| -rwxr-xr-x | ci.sh | 2 | ||||
| -rw-r--r-- | embassy-rp/src/flash.rs | 39 | ||||
| -rw-r--r-- | embassy-rp/src/intrinsics.rs | 1 | ||||
| -rw-r--r-- | embassy-rp/src/lib.rs | 2 | ||||
| -rw-r--r-- | embassy-rp/src/rom_data.rs | 1 | ||||
| -rw-r--r-- | examples/rp/Cargo.toml | 1 | ||||
| -rw-r--r-- | examples/rp/src/bin/flash.rs | 84 | ||||
| -rw-r--r-- | tests/rp/Cargo.toml | 1 | ||||
| -rw-r--r-- | tests/rp/src/bin/flash.rs | 48 |
9 files changed, 171 insertions, 8 deletions
| @@ -121,7 +121,7 @@ cargo batch \ | |||
| 121 | --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h755zi --out-dir out/tests/nucleo-stm32h755zi \ | 121 | --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h755zi --out-dir out/tests/nucleo-stm32h755zi \ |
| 122 | --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32wb55rg --out-dir out/tests/nucleo-stm32wb55rg \ | 122 | --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32wb55rg --out-dir out/tests/nucleo-stm32wb55rg \ |
| 123 | --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32u585ai --out-dir out/tests/iot-stm32u585ai \ | 123 | --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32u585ai --out-dir out/tests/iot-stm32u585ai \ |
| 124 | --- build --release --manifest-path tests/rp/Cargo.toml --target thumbv6m-none-eabi --features embassy-rp/time-driver --out-dir out/tests/rpi-pico \ | 124 | --- build --release --manifest-path tests/rp/Cargo.toml --target thumbv6m-none-eabi --out-dir out/tests/rpi-pico \ |
| 125 | $BUILD_EXTRA | 125 | $BUILD_EXTRA |
| 126 | 126 | ||
| 127 | 127 | ||
diff --git a/embassy-rp/src/flash.rs b/embassy-rp/src/flash.rs index 7a26085b6..62f68bd3c 100644 --- a/embassy-rp/src/flash.rs +++ b/embassy-rp/src/flash.rs | |||
| @@ -1,8 +1,13 @@ | |||
| 1 | use core::marker::PhantomData; | ||
| 2 | |||
| 3 | use embassy_hal_common::Peripheral; | ||
| 1 | use embedded_storage::nor_flash::{ | 4 | use embedded_storage::nor_flash::{ |
| 2 | check_erase, check_read, check_write, ErrorType, MultiwriteNorFlash, NorFlash, NorFlashError, NorFlashErrorKind, | 5 | check_erase, check_read, check_write, ErrorType, MultiwriteNorFlash, NorFlash, NorFlashError, NorFlashErrorKind, |
| 3 | ReadNorFlash, | 6 | ReadNorFlash, |
| 4 | }; | 7 | }; |
| 5 | 8 | ||
| 9 | use crate::peripherals::FLASH; | ||
| 10 | |||
| 6 | pub const FLASH_BASE: usize = 0x10000000; | 11 | pub const FLASH_BASE: usize = 0x10000000; |
| 7 | 12 | ||
| 8 | // **NOTE**: | 13 | // **NOTE**: |
| @@ -46,9 +51,13 @@ impl NorFlashError for Error { | |||
| 46 | } | 51 | } |
| 47 | } | 52 | } |
| 48 | 53 | ||
| 49 | pub struct Flash<const FLASH_SIZE: usize>; | 54 | pub struct Flash<'d, T: Instance, const FLASH_SIZE: usize>(PhantomData<&'d mut T>); |
| 55 | |||
| 56 | impl<'d, T: Instance, const FLASH_SIZE: usize> Flash<'d, T, FLASH_SIZE> { | ||
| 57 | pub fn new(_flash: impl Peripheral<P = T> + 'd) -> Self { | ||
| 58 | Self(PhantomData) | ||
| 59 | } | ||
| 50 | 60 | ||
| 51 | impl<const FLASH_SIZE: usize> Flash<FLASH_SIZE> { | ||
| 52 | /// Make sure to uphold the contract points with rp2040-flash. | 61 | /// Make sure to uphold the contract points with rp2040-flash. |
| 53 | /// - interrupts must be disabled | 62 | /// - interrupts must be disabled |
| 54 | /// - DMA must not access flash memory | 63 | /// - DMA must not access flash memory |
| @@ -81,11 +90,11 @@ impl<const FLASH_SIZE: usize> Flash<FLASH_SIZE> { | |||
| 81 | } | 90 | } |
| 82 | } | 91 | } |
| 83 | 92 | ||
| 84 | impl<const FLASH_SIZE: usize> ErrorType for Flash<FLASH_SIZE> { | 93 | impl<'d, T: Instance, const FLASH_SIZE: usize> ErrorType for Flash<'d, T, FLASH_SIZE> { |
| 85 | type Error = Error; | 94 | type Error = Error; |
| 86 | } | 95 | } |
| 87 | 96 | ||
| 88 | impl<const FLASH_SIZE: usize> ReadNorFlash for Flash<FLASH_SIZE> { | 97 | impl<'d, T: Instance, const FLASH_SIZE: usize> ReadNorFlash for Flash<'d, T, FLASH_SIZE> { |
| 89 | const READ_SIZE: usize = READ_SIZE; | 98 | const READ_SIZE: usize = READ_SIZE; |
| 90 | 99 | ||
| 91 | fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> { | 100 | 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> { | |||
| 102 | } | 111 | } |
| 103 | } | 112 | } |
| 104 | 113 | ||
| 105 | impl<const FLASH_SIZE: usize> MultiwriteNorFlash for Flash<FLASH_SIZE> {} | 114 | impl<'d, T: Instance, const FLASH_SIZE: usize> MultiwriteNorFlash for Flash<'d, T, FLASH_SIZE> {} |
| 106 | 115 | ||
| 107 | impl<const FLASH_SIZE: usize> NorFlash for Flash<FLASH_SIZE> { | 116 | impl<'d, T: Instance, const FLASH_SIZE: usize> NorFlash for Flash<'d, T, FLASH_SIZE> { |
| 108 | const WRITE_SIZE: usize = WRITE_SIZE; | 117 | const WRITE_SIZE: usize = WRITE_SIZE; |
| 109 | 118 | ||
| 110 | const ERASE_SIZE: usize = ERASE_SIZE; | 119 | const ERASE_SIZE: usize = ERASE_SIZE; |
| @@ -112,6 +121,12 @@ impl<const FLASH_SIZE: usize> NorFlash for Flash<FLASH_SIZE> { | |||
| 112 | fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> { | 121 | fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> { |
| 113 | check_erase(self, from, to)?; | 122 | check_erase(self, from, to)?; |
| 114 | 123 | ||
| 124 | trace!( | ||
| 125 | "Erasing from 0x{:x} to 0x{:x}", | ||
| 126 | FLASH_BASE as u32 + from, | ||
| 127 | FLASH_BASE as u32 + to | ||
| 128 | ); | ||
| 129 | |||
| 115 | let len = to - from; | 130 | let len = to - from; |
| 116 | 131 | ||
| 117 | unsafe { self.in_ram(|| ram_helpers::flash_range_erase(from, len, true)) }; | 132 | 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> { | |||
| 122 | fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> { | 137 | fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> { |
| 123 | check_write(self, offset, bytes.len())?; | 138 | check_write(self, offset, bytes.len())?; |
| 124 | 139 | ||
| 125 | trace!("Writing {:?} bytes to 0x{:x}", bytes.len(), offset); | 140 | trace!("Writing {:?} bytes to 0x{:x}", bytes.len(), FLASH_BASE as u32 + offset); |
| 126 | 141 | ||
| 127 | let end_offset = offset as usize + bytes.len(); | 142 | let end_offset = offset as usize + bytes.len(); |
| 128 | 143 | ||
| @@ -351,6 +366,7 @@ mod ram_helpers { | |||
| 351 | rom_data::flash_flush_cache(); | 366 | rom_data::flash_flush_cache(); |
| 352 | rom_data::flash_enter_cmd_xip(); | 367 | rom_data::flash_enter_cmd_xip(); |
| 353 | */ | 368 | */ |
| 369 | #[cfg(target_arch = "arm")] | ||
| 354 | core::arch::asm!( | 370 | core::arch::asm!( |
| 355 | "mov r8, r0", | 371 | "mov r8, r0", |
| 356 | "mov r9, r2", | 372 | "mov r9, r2", |
| @@ -402,3 +418,12 @@ mod ram_helpers { | |||
| 402 | ); | 418 | ); |
| 403 | } | 419 | } |
| 404 | } | 420 | } |
| 421 | |||
| 422 | mod sealed { | ||
| 423 | pub trait Instance {} | ||
| 424 | } | ||
| 425 | |||
| 426 | pub trait Instance: sealed::Instance {} | ||
| 427 | |||
| 428 | impl sealed::Instance for FLASH {} | ||
| 429 | impl Instance for FLASH {} | ||
diff --git a/embassy-rp/src/intrinsics.rs b/embassy-rp/src/intrinsics.rs index 67e8202a4..3e75fb7fc 100644 --- a/embassy-rp/src/intrinsics.rs +++ b/embassy-rp/src/intrinsics.rs | |||
| @@ -1,4 +1,5 @@ | |||
| 1 | #![macro_use] | 1 | #![macro_use] |
| 2 | |||
| 2 | // Credit: taken from `rp-hal` (also licensed Apache+MIT) | 3 | // Credit: taken from `rp-hal` (also licensed Apache+MIT) |
| 3 | // https://github.com/rp-rs/rp-hal/blob/main/rp2040-hal/src/intrinsics.rs | 4 | // https://github.com/rp-rs/rp-hal/blob/main/rp2040-hal/src/intrinsics.rs |
| 4 | 5 | ||
diff --git a/embassy-rp/src/lib.rs b/embassy-rp/src/lib.rs index 445639618..f608f1768 100644 --- a/embassy-rp/src/lib.rs +++ b/embassy-rp/src/lib.rs | |||
| @@ -96,6 +96,8 @@ embassy_hal_common::peripherals! { | |||
| 96 | USB, | 96 | USB, |
| 97 | 97 | ||
| 98 | RTC, | 98 | RTC, |
| 99 | |||
| 100 | FLASH, | ||
| 99 | } | 101 | } |
| 100 | 102 | ||
| 101 | #[link_section = ".boot2"] | 103 | #[link_section = ".boot2"] |
diff --git a/embassy-rp/src/rom_data.rs b/embassy-rp/src/rom_data.rs index 8e953dcf2..757a27114 100644 --- a/embassy-rp/src/rom_data.rs +++ b/embassy-rp/src/rom_data.rs | |||
| @@ -7,6 +7,7 @@ | |||
| 7 | //! > on the device, as well as highly optimized versions of certain key | 7 | //! > on the device, as well as highly optimized versions of certain key |
| 8 | //! > functionality that would otherwise have to take up space in most user | 8 | //! > functionality that would otherwise have to take up space in most user |
| 9 | //! > binaries. | 9 | //! > binaries. |
| 10 | |||
| 10 | // Credit: taken from `rp-hal` (also licensed Apache+MIT) | 11 | // Credit: taken from `rp-hal` (also licensed Apache+MIT) |
| 11 | // https://github.com/rp-rs/rp-hal/blob/main/rp2040-hal/src/rom_data.rs | 12 | // https://github.com/rp-rs/rp-hal/blob/main/rp2040-hal/src/rom_data.rs |
| 12 | 13 | ||
diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml index 747dde515..38355bbf8 100644 --- a/examples/rp/Cargo.toml +++ b/examples/rp/Cargo.toml | |||
| @@ -30,6 +30,7 @@ byte-slice-cast = { version = "1.2.0", default-features = false } | |||
| 30 | embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9" } | 30 | embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9" } |
| 31 | embedded-hal-async = { version = "0.1.0-alpha.1" } | 31 | embedded-hal-async = { version = "0.1.0-alpha.1" } |
| 32 | embedded-io = { version = "0.3.0", features = ["async", "defmt"] } | 32 | embedded-io = { version = "0.3.0", features = ["async", "defmt"] } |
| 33 | embedded-storage = { version = "0.3" } | ||
| 33 | static_cell = "1.0.0" | 34 | static_cell = "1.0.0" |
| 34 | 35 | ||
| 35 | [profile.release] | 36 | [profile.release] |
diff --git a/examples/rp/src/bin/flash.rs b/examples/rp/src/bin/flash.rs new file mode 100644 index 000000000..17549e4be --- /dev/null +++ b/examples/rp/src/bin/flash.rs | |||
| @@ -0,0 +1,84 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | #![feature(type_alias_impl_trait)] | ||
| 4 | |||
| 5 | use defmt::*; | ||
| 6 | use embassy_executor::Spawner; | ||
| 7 | use embassy_rp::flash::{ERASE_SIZE, FLASH_BASE}; | ||
| 8 | use embassy_rp::peripherals::FLASH; | ||
| 9 | use embedded_storage::nor_flash::{NorFlash, ReadNorFlash}; | ||
| 10 | use {defmt_rtt as _, panic_probe as _}; | ||
| 11 | |||
| 12 | const ADDR_OFFSET: u32 = 0x100000; | ||
| 13 | const FLASH_SIZE: usize = 2 * 1024 * 1024; | ||
| 14 | |||
| 15 | #[embassy_executor::main] | ||
| 16 | async fn main(_spawner: Spawner) { | ||
| 17 | let p = embassy_rp::init(Default::default()); | ||
| 18 | info!("Hello World!"); | ||
| 19 | |||
| 20 | let mut flash = embassy_rp::flash::Flash::<_, FLASH_SIZE>::new(p.FLASH); | ||
| 21 | |||
| 22 | erase_write_sector(&mut flash, 0x00); | ||
| 23 | |||
| 24 | multiwrite_bytes(&mut flash, ERASE_SIZE as u32); | ||
| 25 | |||
| 26 | loop {} | ||
| 27 | } | ||
| 28 | |||
| 29 | fn multiwrite_bytes(flash: &mut embassy_rp::flash::Flash<'_, FLASH, FLASH_SIZE>, offset: u32) { | ||
| 30 | info!(">>>> [multiwrite_bytes]"); | ||
| 31 | let mut read_buf = [0u8; ERASE_SIZE]; | ||
| 32 | defmt::unwrap!(flash.read(ADDR_OFFSET + offset, &mut read_buf)); | ||
| 33 | |||
| 34 | info!("Addr of flash block is {:x}", ADDR_OFFSET + offset + FLASH_BASE as u32); | ||
| 35 | info!("Contents start with {=[u8]}", read_buf[0..4]); | ||
| 36 | |||
| 37 | defmt::unwrap!(flash.erase(ADDR_OFFSET + offset, ADDR_OFFSET + offset + ERASE_SIZE as u32)); | ||
| 38 | |||
| 39 | defmt::unwrap!(flash.read(ADDR_OFFSET + offset, &mut read_buf)); | ||
| 40 | info!("Contents after erase starts with {=[u8]}", read_buf[0..4]); | ||
| 41 | if read_buf.iter().any(|x| *x != 0xFF) { | ||
| 42 | defmt::panic!("unexpected"); | ||
| 43 | } | ||
| 44 | |||
| 45 | defmt::unwrap!(flash.write(ADDR_OFFSET + offset, &[0x01])); | ||
| 46 | defmt::unwrap!(flash.write(ADDR_OFFSET + offset + 1, &[0x02])); | ||
| 47 | defmt::unwrap!(flash.write(ADDR_OFFSET + offset + 2, &[0x03])); | ||
| 48 | defmt::unwrap!(flash.write(ADDR_OFFSET + offset + 3, &[0x04])); | ||
| 49 | |||
| 50 | defmt::unwrap!(flash.read(ADDR_OFFSET + offset, &mut read_buf)); | ||
| 51 | info!("Contents after write starts with {=[u8]}", read_buf[0..4]); | ||
| 52 | if &read_buf[0..4] != &[0x01, 0x02, 0x03, 0x04] { | ||
| 53 | defmt::panic!("unexpected"); | ||
| 54 | } | ||
| 55 | } | ||
| 56 | |||
| 57 | fn erase_write_sector(flash: &mut embassy_rp::flash::Flash<'_, FLASH, FLASH_SIZE>, offset: u32) { | ||
| 58 | info!(">>>> [erase_write_sector]"); | ||
| 59 | let mut buf = [0u8; ERASE_SIZE]; | ||
| 60 | defmt::unwrap!(flash.read(ADDR_OFFSET + offset, &mut buf)); | ||
| 61 | |||
| 62 | info!("Addr of flash block is {:x}", ADDR_OFFSET + offset + FLASH_BASE as u32); | ||
| 63 | info!("Contents start with {=[u8]}", buf[0..4]); | ||
| 64 | |||
| 65 | defmt::unwrap!(flash.erase(ADDR_OFFSET + offset, ADDR_OFFSET + offset + ERASE_SIZE as u32)); | ||
| 66 | |||
| 67 | defmt::unwrap!(flash.read(ADDR_OFFSET + offset, &mut buf)); | ||
| 68 | info!("Contents after erase starts with {=[u8]}", buf[0..4]); | ||
| 69 | if buf.iter().any(|x| *x != 0xFF) { | ||
| 70 | defmt::panic!("unexpected"); | ||
| 71 | } | ||
| 72 | |||
| 73 | for b in buf.iter_mut() { | ||
| 74 | *b = 0xDA; | ||
| 75 | } | ||
| 76 | |||
| 77 | defmt::unwrap!(flash.write(ADDR_OFFSET + offset, &buf)); | ||
| 78 | |||
| 79 | defmt::unwrap!(flash.read(ADDR_OFFSET + offset, &mut buf)); | ||
| 80 | info!("Contents after write starts with {=[u8]}", buf[0..4]); | ||
| 81 | if buf.iter().any(|x| *x != 0xDA) { | ||
| 82 | defmt::panic!("unexpected"); | ||
| 83 | } | ||
| 84 | } | ||
diff --git a/tests/rp/Cargo.toml b/tests/rp/Cargo.toml index d6770d6e9..48c88e85b 100644 --- a/tests/rp/Cargo.toml +++ b/tests/rp/Cargo.toml | |||
| @@ -22,6 +22,7 @@ embedded-hal-async = { version = "=0.1.0-alpha.2" } | |||
| 22 | panic-probe = { version = "0.3.0", features = ["print-defmt"] } | 22 | panic-probe = { version = "0.3.0", features = ["print-defmt"] } |
| 23 | futures = { version = "0.3.17", default-features = false, features = ["async-await"] } | 23 | futures = { version = "0.3.17", default-features = false, features = ["async-await"] } |
| 24 | embedded-io = { version = "0.3.0", features = ["async"] } | 24 | embedded-io = { version = "0.3.0", features = ["async"] } |
| 25 | embedded-storage = { version = "0.3" } | ||
| 25 | 26 | ||
| 26 | [profile.dev] | 27 | [profile.dev] |
| 27 | debug = 2 | 28 | debug = 2 |
diff --git a/tests/rp/src/bin/flash.rs b/tests/rp/src/bin/flash.rs new file mode 100644 index 000000000..4cbd78fe9 --- /dev/null +++ b/tests/rp/src/bin/flash.rs | |||
| @@ -0,0 +1,48 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | #![feature(type_alias_impl_trait)] | ||
| 4 | |||
| 5 | use defmt::*; | ||
| 6 | use embassy_executor::Spawner; | ||
| 7 | use embassy_rp::flash::{ERASE_SIZE, FLASH_BASE}; | ||
| 8 | use embedded_storage::nor_flash::{NorFlash, ReadNorFlash}; | ||
| 9 | use {defmt_rtt as _, panic_probe as _}; | ||
| 10 | |||
| 11 | const ADDR_OFFSET: u32 = 0x4000; | ||
| 12 | |||
| 13 | #[embassy_executor::main] | ||
| 14 | async fn main(_spawner: Spawner) { | ||
| 15 | let p = embassy_rp::init(Default::default()); | ||
| 16 | info!("Hello World!"); | ||
| 17 | |||
| 18 | let mut flash = embassy_rp::flash::Flash::<_, { 2 * 1024 * 1024 }>::new(p.FLASH); | ||
| 19 | |||
| 20 | let mut buf = [0u8; ERASE_SIZE]; | ||
| 21 | defmt::unwrap!(flash.read(ADDR_OFFSET, &mut buf)); | ||
| 22 | |||
| 23 | info!("Addr of flash block is {:x}", ADDR_OFFSET + FLASH_BASE as u32); | ||
| 24 | info!("Contents start with {=[u8]}", buf[0..4]); | ||
| 25 | |||
| 26 | defmt::unwrap!(flash.erase(ADDR_OFFSET, ADDR_OFFSET + ERASE_SIZE as u32)); | ||
| 27 | |||
| 28 | defmt::unwrap!(flash.read(ADDR_OFFSET, &mut buf)); | ||
| 29 | info!("Contents after erase starts with {=[u8]}", buf[0..4]); | ||
| 30 | if buf.iter().any(|x| *x != 0xFF) { | ||
| 31 | defmt::panic!("unexpected"); | ||
| 32 | } | ||
| 33 | |||
| 34 | for b in buf.iter_mut() { | ||
| 35 | *b = 0xDA; | ||
| 36 | } | ||
| 37 | |||
| 38 | defmt::unwrap!(flash.write(ADDR_OFFSET, &mut buf)); | ||
| 39 | |||
| 40 | defmt::unwrap!(flash.read(ADDR_OFFSET, &mut buf)); | ||
| 41 | info!("Contents after write starts with {=[u8]}", buf[0..4]); | ||
| 42 | if buf.iter().any(|x| *x != 0xDA) { | ||
| 43 | defmt::panic!("unexpected"); | ||
| 44 | } | ||
| 45 | |||
| 46 | info!("Test OK"); | ||
| 47 | cortex_m::asm::bkpt(); | ||
| 48 | } | ||
