diff options
| author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2021-10-23 08:28:25 +0000 |
|---|---|---|
| committer | GitHub <[email protected]> | 2021-10-23 08:28:25 +0000 |
| commit | f3f3858328ed4f13efb3790e32ee4fba772b57a2 (patch) | |
| tree | 2efed3b61dbd91881ba5227c2887316adb97241d | |
| parent | a8797f84f69b7668a3f89b6cba3e39bce5649079 (diff) | |
| parent | e78d226acd5e2dc5f2eecfc98269747daf7e0633 (diff) | |
Merge #444
444: nrf: add NVMC driver. r=lulf a=Dirbaio
I haven't implemented `embassy_traits::Flash` because I want to change it to match embedded_storage, which is much better designed.
Either way, NVMC can't do async anyway, so the best we could do is implementing the async trait in a blocking way...
Co-authored-by: Dario Nieuwenhuis <[email protected]>
| -rw-r--r-- | embassy-nrf/Cargo.toml | 1 | ||||
| -rw-r--r-- | embassy-nrf/src/chips/nrf52805.rs | 5 | ||||
| -rw-r--r-- | embassy-nrf/src/chips/nrf52810.rs | 5 | ||||
| -rw-r--r-- | embassy-nrf/src/chips/nrf52811.rs | 5 | ||||
| -rw-r--r-- | embassy-nrf/src/chips/nrf52820.rs | 5 | ||||
| -rw-r--r-- | embassy-nrf/src/chips/nrf52832.rs | 9 | ||||
| -rw-r--r-- | embassy-nrf/src/chips/nrf52833.rs | 5 | ||||
| -rw-r--r-- | embassy-nrf/src/chips/nrf52840.rs | 5 | ||||
| -rw-r--r-- | embassy-nrf/src/lib.rs | 2 | ||||
| -rw-r--r-- | embassy-nrf/src/nvmc.rs | 123 | ||||
| -rw-r--r-- | examples/nrf/Cargo.toml | 1 | ||||
| -rw-r--r-- | examples/nrf/src/bin/nvmc.rs | 44 |
12 files changed, 210 insertions, 0 deletions
diff --git a/embassy-nrf/Cargo.toml b/embassy-nrf/Cargo.toml index d4d4ab8d8..fc1ec6b01 100644 --- a/embassy-nrf/Cargo.toml +++ b/embassy-nrf/Cargo.toml | |||
| @@ -49,6 +49,7 @@ futures = { version = "0.3.17", default-features = false } | |||
| 49 | critical-section = "0.2.3" | 49 | critical-section = "0.2.3" |
| 50 | rand_core = "0.6.3" | 50 | rand_core = "0.6.3" |
| 51 | fixed = "1.10.0" | 51 | fixed = "1.10.0" |
| 52 | embedded-storage = "0.2.0" | ||
| 52 | 53 | ||
| 53 | nrf52805-pac = { version = "0.10.1", optional = true, features = [ "rt" ] } | 54 | nrf52805-pac = { version = "0.10.1", optional = true, features = [ "rt" ] } |
| 54 | nrf52810-pac = { version = "0.10.1", optional = true, features = [ "rt" ] } | 55 | nrf52810-pac = { version = "0.10.1", optional = true, features = [ "rt" ] } |
diff --git a/embassy-nrf/src/chips/nrf52805.rs b/embassy-nrf/src/chips/nrf52805.rs index 317e6ed66..d68697936 100644 --- a/embassy-nrf/src/chips/nrf52805.rs +++ b/embassy-nrf/src/chips/nrf52805.rs | |||
| @@ -4,6 +4,8 @@ pub use nrf52805_pac as pac; | |||
| 4 | pub const EASY_DMA_SIZE: usize = (1 << 14) - 1; | 4 | pub const EASY_DMA_SIZE: usize = (1 << 14) - 1; |
| 5 | pub const FORCE_COPY_BUFFER_SIZE: usize = 256; | 5 | pub const FORCE_COPY_BUFFER_SIZE: usize = 256; |
| 6 | 6 | ||
| 7 | pub const FLASH_SIZE: usize = 192 * 1024; | ||
| 8 | |||
| 7 | embassy_hal_common::peripherals! { | 9 | embassy_hal_common::peripherals! { |
| 8 | // RTC | 10 | // RTC |
| 9 | RTC0, | 11 | RTC0, |
| @@ -12,6 +14,9 @@ embassy_hal_common::peripherals! { | |||
| 12 | // WDT | 14 | // WDT |
| 13 | WDT, | 15 | WDT, |
| 14 | 16 | ||
| 17 | // NVMC | ||
| 18 | NVMC, | ||
| 19 | |||
| 15 | // RNG | 20 | // RNG |
| 16 | RNG, | 21 | RNG, |
| 17 | 22 | ||
diff --git a/embassy-nrf/src/chips/nrf52810.rs b/embassy-nrf/src/chips/nrf52810.rs index b26f30cbf..c119e7cdb 100644 --- a/embassy-nrf/src/chips/nrf52810.rs +++ b/embassy-nrf/src/chips/nrf52810.rs | |||
| @@ -4,6 +4,8 @@ pub use nrf52810_pac as pac; | |||
| 4 | pub const EASY_DMA_SIZE: usize = (1 << 10) - 1; | 4 | pub const EASY_DMA_SIZE: usize = (1 << 10) - 1; |
| 5 | pub const FORCE_COPY_BUFFER_SIZE: usize = 256; | 5 | pub const FORCE_COPY_BUFFER_SIZE: usize = 256; |
| 6 | 6 | ||
| 7 | pub const FLASH_SIZE: usize = 192 * 1024; | ||
| 8 | |||
| 7 | embassy_hal_common::peripherals! { | 9 | embassy_hal_common::peripherals! { |
| 8 | // RTC | 10 | // RTC |
| 9 | RTC0, | 11 | RTC0, |
| @@ -12,6 +14,9 @@ embassy_hal_common::peripherals! { | |||
| 12 | // WDT | 14 | // WDT |
| 13 | WDT, | 15 | WDT, |
| 14 | 16 | ||
| 17 | // NVMC | ||
| 18 | NVMC, | ||
| 19 | |||
| 15 | // RNG | 20 | // RNG |
| 16 | RNG, | 21 | RNG, |
| 17 | 22 | ||
diff --git a/embassy-nrf/src/chips/nrf52811.rs b/embassy-nrf/src/chips/nrf52811.rs index 9fbe3594e..3c9df40fe 100644 --- a/embassy-nrf/src/chips/nrf52811.rs +++ b/embassy-nrf/src/chips/nrf52811.rs | |||
| @@ -4,6 +4,8 @@ pub use nrf52811_pac as pac; | |||
| 4 | pub const EASY_DMA_SIZE: usize = (1 << 14) - 1; | 4 | pub const EASY_DMA_SIZE: usize = (1 << 14) - 1; |
| 5 | pub const FORCE_COPY_BUFFER_SIZE: usize = 256; | 5 | pub const FORCE_COPY_BUFFER_SIZE: usize = 256; |
| 6 | 6 | ||
| 7 | pub const FLASH_SIZE: usize = 192 * 1024; | ||
| 8 | |||
| 7 | embassy_hal_common::peripherals! { | 9 | embassy_hal_common::peripherals! { |
| 8 | // RTC | 10 | // RTC |
| 9 | RTC0, | 11 | RTC0, |
| @@ -12,6 +14,9 @@ embassy_hal_common::peripherals! { | |||
| 12 | // WDT | 14 | // WDT |
| 13 | WDT, | 15 | WDT, |
| 14 | 16 | ||
| 17 | // NVMC | ||
| 18 | NVMC, | ||
| 19 | |||
| 15 | // RNG | 20 | // RNG |
| 16 | RNG, | 21 | RNG, |
| 17 | 22 | ||
diff --git a/embassy-nrf/src/chips/nrf52820.rs b/embassy-nrf/src/chips/nrf52820.rs index abbdba7ac..8a8e23a9e 100644 --- a/embassy-nrf/src/chips/nrf52820.rs +++ b/embassy-nrf/src/chips/nrf52820.rs | |||
| @@ -4,6 +4,8 @@ pub use nrf52820_pac as pac; | |||
| 4 | pub const EASY_DMA_SIZE: usize = (1 << 15) - 1; | 4 | pub const EASY_DMA_SIZE: usize = (1 << 15) - 1; |
| 5 | pub const FORCE_COPY_BUFFER_SIZE: usize = 512; | 5 | pub const FORCE_COPY_BUFFER_SIZE: usize = 512; |
| 6 | 6 | ||
| 7 | pub const FLASH_SIZE: usize = 256 * 1024; | ||
| 8 | |||
| 7 | embassy_hal_common::peripherals! { | 9 | embassy_hal_common::peripherals! { |
| 8 | // RTC | 10 | // RTC |
| 9 | RTC0, | 11 | RTC0, |
| @@ -12,6 +14,9 @@ embassy_hal_common::peripherals! { | |||
| 12 | // WDT | 14 | // WDT |
| 13 | WDT, | 15 | WDT, |
| 14 | 16 | ||
| 17 | // NVMC | ||
| 18 | NVMC, | ||
| 19 | |||
| 15 | // RNG | 20 | // RNG |
| 16 | RNG, | 21 | RNG, |
| 17 | 22 | ||
diff --git a/embassy-nrf/src/chips/nrf52832.rs b/embassy-nrf/src/chips/nrf52832.rs index de6dd7a8c..c1b02a0bf 100644 --- a/embassy-nrf/src/chips/nrf52832.rs +++ b/embassy-nrf/src/chips/nrf52832.rs | |||
| @@ -4,6 +4,12 @@ pub use nrf52832_pac as pac; | |||
| 4 | pub const EASY_DMA_SIZE: usize = (1 << 8) - 1; | 4 | pub const EASY_DMA_SIZE: usize = (1 << 8) - 1; |
| 5 | pub const FORCE_COPY_BUFFER_SIZE: usize = 255; | 5 | pub const FORCE_COPY_BUFFER_SIZE: usize = 255; |
| 6 | 6 | ||
| 7 | // There are two variants. We set the higher size to make the entire flash | ||
| 8 | // usable in xxAA, but we'll probably split this in two cargi features later. | ||
| 9 | // nrf52832xxAA = 512kb | ||
| 10 | // nrf52832xxAB = 256kb | ||
| 11 | pub const FLASH_SIZE: usize = 512 * 1024; | ||
| 12 | |||
| 7 | embassy_hal_common::peripherals! { | 13 | embassy_hal_common::peripherals! { |
| 8 | // RTC | 14 | // RTC |
| 9 | RTC0, | 15 | RTC0, |
| @@ -13,6 +19,9 @@ embassy_hal_common::peripherals! { | |||
| 13 | // WDT | 19 | // WDT |
| 14 | WDT, | 20 | WDT, |
| 15 | 21 | ||
| 22 | // NVMC | ||
| 23 | NVMC, | ||
| 24 | |||
| 16 | // RNG | 25 | // RNG |
| 17 | RNG, | 26 | RNG, |
| 18 | 27 | ||
diff --git a/embassy-nrf/src/chips/nrf52833.rs b/embassy-nrf/src/chips/nrf52833.rs index c5e1c9d33..4f5c26002 100644 --- a/embassy-nrf/src/chips/nrf52833.rs +++ b/embassy-nrf/src/chips/nrf52833.rs | |||
| @@ -4,6 +4,8 @@ pub use nrf52833_pac as pac; | |||
| 4 | pub const EASY_DMA_SIZE: usize = (1 << 16) - 1; | 4 | pub const EASY_DMA_SIZE: usize = (1 << 16) - 1; |
| 5 | pub const FORCE_COPY_BUFFER_SIZE: usize = 512; | 5 | pub const FORCE_COPY_BUFFER_SIZE: usize = 512; |
| 6 | 6 | ||
| 7 | pub const FLASH_SIZE: usize = 512 * 1024; | ||
| 8 | |||
| 7 | embassy_hal_common::peripherals! { | 9 | embassy_hal_common::peripherals! { |
| 8 | // RTC | 10 | // RTC |
| 9 | RTC0, | 11 | RTC0, |
| @@ -13,6 +15,9 @@ embassy_hal_common::peripherals! { | |||
| 13 | // WDT | 15 | // WDT |
| 14 | WDT, | 16 | WDT, |
| 15 | 17 | ||
| 18 | // NVMC | ||
| 19 | NVMC, | ||
| 20 | |||
| 16 | // RNG | 21 | // RNG |
| 17 | RNG, | 22 | RNG, |
| 18 | 23 | ||
diff --git a/embassy-nrf/src/chips/nrf52840.rs b/embassy-nrf/src/chips/nrf52840.rs index 76cabe6f1..1006acd95 100644 --- a/embassy-nrf/src/chips/nrf52840.rs +++ b/embassy-nrf/src/chips/nrf52840.rs | |||
| @@ -4,6 +4,8 @@ pub use nrf52840_pac as pac; | |||
| 4 | pub const EASY_DMA_SIZE: usize = (1 << 16) - 1; | 4 | pub const EASY_DMA_SIZE: usize = (1 << 16) - 1; |
| 5 | pub const FORCE_COPY_BUFFER_SIZE: usize = 512; | 5 | pub const FORCE_COPY_BUFFER_SIZE: usize = 512; |
| 6 | 6 | ||
| 7 | pub const FLASH_SIZE: usize = 1024 * 1024; | ||
| 8 | |||
| 7 | embassy_hal_common::peripherals! { | 9 | embassy_hal_common::peripherals! { |
| 8 | // RTC | 10 | // RTC |
| 9 | RTC0, | 11 | RTC0, |
| @@ -13,6 +15,9 @@ embassy_hal_common::peripherals! { | |||
| 13 | // WDT | 15 | // WDT |
| 14 | WDT, | 16 | WDT, |
| 15 | 17 | ||
| 18 | // NVMC | ||
| 19 | NVMC, | ||
| 20 | |||
| 16 | // RNG | 21 | // RNG |
| 17 | RNG, | 22 | RNG, |
| 18 | 23 | ||
diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs index 961a97ce9..c21c4d398 100644 --- a/embassy-nrf/src/lib.rs +++ b/embassy-nrf/src/lib.rs | |||
| @@ -29,6 +29,8 @@ pub mod buffered_uarte; | |||
| 29 | pub mod gpio; | 29 | pub mod gpio; |
| 30 | #[cfg(feature = "gpiote")] | 30 | #[cfg(feature = "gpiote")] |
| 31 | pub mod gpiote; | 31 | pub mod gpiote; |
| 32 | #[cfg(not(feature = "nrf9160"))] | ||
| 33 | pub mod nvmc; | ||
| 32 | pub mod ppi; | 34 | pub mod ppi; |
| 33 | #[cfg(not(any(feature = "nrf52805", feature = "nrf52820")))] | 35 | #[cfg(not(any(feature = "nrf52805", feature = "nrf52820")))] |
| 34 | pub mod pwm; | 36 | pub mod pwm; |
diff --git a/embassy-nrf/src/nvmc.rs b/embassy-nrf/src/nvmc.rs new file mode 100644 index 000000000..312e1d5a6 --- /dev/null +++ b/embassy-nrf/src/nvmc.rs | |||
| @@ -0,0 +1,123 @@ | |||
| 1 | //! Nvmcerature sensor interface. | ||
| 2 | |||
| 3 | use crate::pac; | ||
| 4 | use crate::peripherals::NVMC; | ||
| 5 | |||
| 6 | use core::marker::PhantomData; | ||
| 7 | use core::ptr; | ||
| 8 | use core::slice; | ||
| 9 | use embassy::util::Unborrow; | ||
| 10 | use embassy_hal_common::unborrow; | ||
| 11 | use embedded_storage::nor_flash::{MultiwriteNorFlash, NorFlash, ReadNorFlash}; | ||
| 12 | |||
| 13 | const PAGE_SIZE: usize = 4096; | ||
| 14 | const FLASH_SIZE: usize = crate::chip::FLASH_SIZE; | ||
| 15 | |||
| 16 | #[derive(Debug, Copy, Clone, PartialEq, Eq)] | ||
| 17 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 18 | pub enum Error { | ||
| 19 | OutOfBounds, | ||
| 20 | Unaligned, | ||
| 21 | } | ||
| 22 | |||
| 23 | pub struct Nvmc<'d> { | ||
| 24 | _p: PhantomData<&'d NVMC>, | ||
| 25 | } | ||
| 26 | |||
| 27 | impl<'d> Nvmc<'d> { | ||
| 28 | pub fn new(_p: impl Unborrow<Target = NVMC> + 'd) -> Self { | ||
| 29 | unborrow!(_p); | ||
| 30 | |||
| 31 | Self { _p: PhantomData } | ||
| 32 | } | ||
| 33 | |||
| 34 | fn regs() -> &'static pac::nvmc::RegisterBlock { | ||
| 35 | unsafe { &*pac::NVMC::ptr() } | ||
| 36 | } | ||
| 37 | |||
| 38 | fn wait_ready(&mut self) { | ||
| 39 | let p = Self::regs(); | ||
| 40 | while p.ready.read().ready().is_busy() {} | ||
| 41 | } | ||
| 42 | } | ||
| 43 | |||
| 44 | impl<'d> MultiwriteNorFlash for Nvmc<'d> {} | ||
| 45 | |||
| 46 | impl<'d> ReadNorFlash for Nvmc<'d> { | ||
| 47 | type Error = Error; | ||
| 48 | |||
| 49 | const READ_SIZE: usize = 1; | ||
| 50 | |||
| 51 | fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> { | ||
| 52 | if offset as usize >= FLASH_SIZE || offset as usize + bytes.len() > FLASH_SIZE { | ||
| 53 | return Err(Error::OutOfBounds); | ||
| 54 | } | ||
| 55 | |||
| 56 | let flash_data = unsafe { slice::from_raw_parts(offset as *const u8, bytes.len()) }; | ||
| 57 | bytes.copy_from_slice(flash_data); | ||
| 58 | Ok(()) | ||
| 59 | } | ||
| 60 | |||
| 61 | fn capacity(&self) -> usize { | ||
| 62 | FLASH_SIZE | ||
| 63 | } | ||
| 64 | } | ||
| 65 | |||
| 66 | impl<'d> NorFlash for Nvmc<'d> { | ||
| 67 | const WRITE_SIZE: usize = 4; | ||
| 68 | const ERASE_SIZE: usize = PAGE_SIZE; | ||
| 69 | |||
| 70 | fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> { | ||
| 71 | if to < from || to as usize > FLASH_SIZE { | ||
| 72 | return Err(Error::OutOfBounds); | ||
| 73 | } | ||
| 74 | if from as usize % PAGE_SIZE != 0 || to as usize % PAGE_SIZE != 0 { | ||
| 75 | return Err(Error::Unaligned); | ||
| 76 | } | ||
| 77 | |||
| 78 | let p = Self::regs(); | ||
| 79 | |||
| 80 | p.config.write(|w| w.wen().een()); | ||
| 81 | self.wait_ready(); | ||
| 82 | |||
| 83 | for page in (from..to).step_by(PAGE_SIZE) { | ||
| 84 | p.erasepage().write(|w| unsafe { w.bits(page) }); | ||
| 85 | self.wait_ready(); | ||
| 86 | } | ||
| 87 | |||
| 88 | p.config.reset(); | ||
| 89 | self.wait_ready(); | ||
| 90 | |||
| 91 | Ok(()) | ||
| 92 | } | ||
| 93 | |||
| 94 | fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> { | ||
| 95 | if offset as usize + bytes.len() > FLASH_SIZE { | ||
| 96 | return Err(Error::OutOfBounds); | ||
| 97 | } | ||
| 98 | if offset as usize % 4 != 0 || bytes.len() as usize % 4 != 0 { | ||
| 99 | return Err(Error::Unaligned); | ||
| 100 | } | ||
| 101 | |||
| 102 | let p = Self::regs(); | ||
| 103 | |||
| 104 | p.config.write(|w| w.wen().wen()); | ||
| 105 | self.wait_ready(); | ||
| 106 | |||
| 107 | unsafe { | ||
| 108 | let p_src = bytes.as_ptr() as *const u32; | ||
| 109 | let p_dst = offset as *mut u32; | ||
| 110 | let words = bytes.len() / 4; | ||
| 111 | for i in 0..words { | ||
| 112 | let w = ptr::read_unaligned(p_src.add(i)); | ||
| 113 | ptr::write_volatile(p_dst.add(i), w); | ||
| 114 | self.wait_ready(); | ||
| 115 | } | ||
| 116 | } | ||
| 117 | |||
| 118 | p.config.reset(); | ||
| 119 | self.wait_ready(); | ||
| 120 | |||
| 121 | Ok(()) | ||
| 122 | } | ||
| 123 | } | ||
diff --git a/examples/nrf/Cargo.toml b/examples/nrf/Cargo.toml index b71dfa0d4..b89aa513f 100644 --- a/examples/nrf/Cargo.toml +++ b/examples/nrf/Cargo.toml | |||
| @@ -30,3 +30,4 @@ embedded-hal = "0.2.6" | |||
| 30 | panic-probe = { version = "0.2.0", features = ["print-defmt"] } | 30 | panic-probe = { version = "0.2.0", features = ["print-defmt"] } |
| 31 | futures = { version = "0.3.17", default-features = false, features = ["async-await"] } | 31 | futures = { version = "0.3.17", default-features = false, features = ["async-await"] } |
| 32 | rand = { version = "0.8.4", default-features = false } | 32 | rand = { version = "0.8.4", default-features = false } |
| 33 | embedded-storage = "0.2.0" | ||
diff --git a/examples/nrf/src/bin/nvmc.rs b/examples/nrf/src/bin/nvmc.rs new file mode 100644 index 000000000..f36895636 --- /dev/null +++ b/examples/nrf/src/bin/nvmc.rs | |||
| @@ -0,0 +1,44 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | #![feature(type_alias_impl_trait)] | ||
| 4 | |||
| 5 | #[path = "../example_common.rs"] | ||
| 6 | mod example_common; | ||
| 7 | use embassy::executor::Spawner; | ||
| 8 | use embassy::time::{Duration, Timer}; | ||
| 9 | use embassy_nrf::nvmc::Nvmc; | ||
| 10 | use embassy_nrf::Peripherals; | ||
| 11 | use embedded_storage::nor_flash::{NorFlash, ReadNorFlash}; | ||
| 12 | use example_common::*; | ||
| 13 | |||
| 14 | #[embassy::main] | ||
| 15 | async fn main(_spawner: Spawner, p: Peripherals) { | ||
| 16 | info!("Hello NVMC!"); | ||
| 17 | |||
| 18 | // probe-run breaks without this, I'm not sure why. | ||
| 19 | Timer::after(Duration::from_secs(1)).await; | ||
| 20 | |||
| 21 | let mut f = Nvmc::new(p.NVMC); | ||
| 22 | const ADDR: u32 = 0x80000; | ||
| 23 | |||
| 24 | info!("Reading..."); | ||
| 25 | let mut buf = [0u8; 4]; | ||
| 26 | unwrap!(f.read(ADDR, &mut buf)); | ||
| 27 | info!("Read: {=[u8]:x}", buf); | ||
| 28 | |||
| 29 | info!("Erasing..."); | ||
| 30 | unwrap!(f.erase(ADDR, ADDR + 4096)); | ||
| 31 | |||
| 32 | info!("Reading..."); | ||
| 33 | let mut buf = [0u8; 4]; | ||
| 34 | unwrap!(f.read(ADDR, &mut buf)); | ||
| 35 | info!("Read: {=[u8]:x}", buf); | ||
| 36 | |||
| 37 | info!("Writing..."); | ||
| 38 | unwrap!(f.write(ADDR, &[1, 2, 3, 4])); | ||
| 39 | |||
| 40 | info!("Reading..."); | ||
| 41 | let mut buf = [0u8; 4]; | ||
| 42 | unwrap!(f.read(ADDR, &mut buf)); | ||
| 43 | info!("Read: {=[u8]:x}", buf); | ||
| 44 | } | ||
