aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xci.sh5
-rw-r--r--embassy-boot-stm32/Cargo.toml2
-rw-r--r--embassy-stm32/build.rs42
-rw-r--r--embassy-stm32/src/flash/eeprom.rs236
-rw-r--r--embassy-stm32/src/flash/l.rs2
-rw-r--r--embassy-stm32/src/flash/mod.rs10
-rw-r--r--examples/boot/application/stm32f3/Cargo.toml2
-rw-r--r--examples/boot/application/stm32f7/Cargo.toml2
-rw-r--r--examples/boot/application/stm32h7/Cargo.toml2
-rw-r--r--examples/boot/application/stm32l0/Cargo.toml2
-rw-r--r--examples/boot/application/stm32l1/Cargo.toml2
-rw-r--r--examples/boot/application/stm32l4/Cargo.toml2
-rw-r--r--examples/boot/application/stm32wb-dfu/Cargo.toml2
-rw-r--r--examples/boot/application/stm32wl/Cargo.toml2
-rw-r--r--examples/stm32l0/src/bin/eeprom.rs32
-rw-r--r--examples/stm32l1/src/bin/eeprom.rs32
-rw-r--r--tests/stm32/Cargo.toml10
-rw-r--r--tests/stm32/src/bin/eeprom.rs30
18 files changed, 404 insertions, 13 deletions
diff --git a/ci.sh b/ci.sh
index dce0d7b13..d21c1c97b 100755
--- a/ci.sh
+++ b/ci.sh
@@ -363,6 +363,11 @@ rm out/tests/pimoroni-pico-plus-2/flash
363rm out/tests/pimoroni-pico-plus-2/i2c 363rm out/tests/pimoroni-pico-plus-2/i2c
364# The pico2 plus doesn't have the adcs hooked up like the picoW does. 364# The pico2 plus doesn't have the adcs hooked up like the picoW does.
365rm out/tests/pimoroni-pico-plus-2/adc 365rm out/tests/pimoroni-pico-plus-2/adc
366# temporarily disabled
367rm out/tests/pimoroni-pico-plus-2/pwm
368
369# temporarily disabled, bad hardware connection.
370rm -f out/tests/rpi-pico/*
366 371
367if [[ -z "${TELEPROBE_TOKEN-}" ]]; then 372if [[ -z "${TELEPROBE_TOKEN-}" ]]; then
368 echo No teleprobe token found, skipping running HIL tests 373 echo No teleprobe token found, skipping running HIL tests
diff --git a/embassy-boot-stm32/Cargo.toml b/embassy-boot-stm32/Cargo.toml
index a24921291..11ad453b8 100644
--- a/embassy-boot-stm32/Cargo.toml
+++ b/embassy-boot-stm32/Cargo.toml
@@ -1,7 +1,7 @@
1[package] 1[package]
2edition = "2021" 2edition = "2021"
3name = "embassy-boot-stm32" 3name = "embassy-boot-stm32"
4version = "0.2.0" 4version = "0.3.0"
5description = "Bootloader lib for STM32 chips" 5description = "Bootloader lib for STM32 chips"
6license = "MIT OR Apache-2.0" 6license = "MIT OR Apache-2.0"
7repository = "https://github.com/embassy-rs/embassy" 7repository = "https://github.com/embassy-rs/embassy"
diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs
index b00b6a7ac..bb5ef53d7 100644
--- a/embassy-stm32/build.rs
+++ b/embassy-stm32/build.rs
@@ -1923,6 +1923,48 @@ fn main() {
1923 )); 1923 ));
1924 1924
1925 // ======== 1925 // ========
1926 // Generate EEPROM constants
1927
1928 cfgs.declare("eeprom");
1929
1930 let eeprom_memory_regions: Vec<&MemoryRegion> =
1931 memory.iter().filter(|x| x.kind == MemoryRegionKind::Eeprom).collect();
1932
1933 if !eeprom_memory_regions.is_empty() {
1934 cfgs.enable("eeprom");
1935
1936 let mut sorted_eeprom_regions = eeprom_memory_regions.clone();
1937 sorted_eeprom_regions.sort_by_key(|r| r.address);
1938
1939 let first_eeprom_address = sorted_eeprom_regions[0].address;
1940 let mut total_eeprom_size = 0;
1941 let mut current_expected_address = first_eeprom_address;
1942
1943 for region in sorted_eeprom_regions.iter() {
1944 if region.address != current_expected_address {
1945 // For STM32L0 and STM32L1, EEPROM regions (if multiple) are expected to be contiguous.
1946 // If they are not, this indicates an issue with the chip metadata or an unsupported configuration.
1947 panic!(
1948 "EEPROM regions for chip {} are not contiguous, which is unexpected for L0/L1 series. \
1949 First region: '{}' at {:#X}. Found next non-contiguous region: '{}' at {:#X}. \
1950 Please verify chip metadata. Embassy currently assumes contiguous EEPROM for these series.",
1951 chip_name, sorted_eeprom_regions[0].name, first_eeprom_address, region.name, region.address
1952 );
1953 }
1954 total_eeprom_size += region.size;
1955 current_expected_address += region.size;
1956 }
1957
1958 let eeprom_base_usize = first_eeprom_address as usize;
1959 let total_eeprom_size_usize = total_eeprom_size as usize;
1960
1961 g.extend(quote! {
1962 pub const EEPROM_BASE: usize = #eeprom_base_usize;
1963 pub const EEPROM_SIZE: usize = #total_eeprom_size_usize;
1964 });
1965 }
1966
1967 // ========
1926 // Generate macro-tables 1968 // Generate macro-tables
1927 1969
1928 for irq in METADATA.interrupts { 1970 for irq in METADATA.interrupts {
diff --git a/embassy-stm32/src/flash/eeprom.rs b/embassy-stm32/src/flash/eeprom.rs
new file mode 100644
index 000000000..cc3529eb9
--- /dev/null
+++ b/embassy-stm32/src/flash/eeprom.rs
@@ -0,0 +1,236 @@
1use embassy_hal_internal::drop::OnDrop;
2
3use super::{family, Blocking, Error, Flash, EEPROM_BASE, EEPROM_SIZE};
4
5#[cfg(eeprom)]
6impl<'d> Flash<'d, Blocking> {
7 // --- Internal helpers ---
8
9 /// Checks if the given offset and size are within the EEPROM bounds.
10 fn check_eeprom_offset(&self, offset: u32, size: u32) -> Result<(), Error> {
11 if offset
12 .checked_add(size)
13 .filter(|&end| end <= EEPROM_SIZE as u32)
14 .is_some()
15 {
16 Ok(())
17 } else {
18 Err(Error::Size)
19 }
20 }
21
22 // --- Unlocked (unsafe, internal) functions ---
23
24 /// Writes a slice of bytes to EEPROM at the given offset without locking.
25 ///
26 /// # Safety
27 /// Caller must ensure EEPROM is unlocked and offset is valid.
28 unsafe fn eeprom_write_u8_slice_unlocked(&self, offset: u32, data: &[u8]) -> Result<(), Error> {
29 for (i, &byte) in data.iter().enumerate() {
30 let addr = EEPROM_BASE as u32 + offset + i as u32;
31 core::ptr::write_volatile(addr as *mut u8, byte);
32 family::wait_ready_blocking()?;
33 family::clear_all_err();
34 }
35 Ok(())
36 }
37
38 /// Writes a slice of u16 values to EEPROM at the given offset without locking.
39 ///
40 /// # Safety
41 /// Caller must ensure EEPROM is unlocked and offset is valid and aligned.
42 unsafe fn eeprom_write_u16_slice_unlocked(&self, offset: u32, data: &[u16]) -> Result<(), Error> {
43 for (i, &value) in data.iter().enumerate() {
44 let addr = EEPROM_BASE as u32 + offset + i as u32 * 2;
45 core::ptr::write_volatile(addr as *mut u16, value);
46 family::wait_ready_blocking()?;
47 family::clear_all_err();
48 }
49 Ok(())
50 }
51
52 /// Writes a slice of u32 values to EEPROM at the given offset without locking.
53 ///
54 /// # Safety
55 /// Caller must ensure EEPROM is unlocked and offset is valid and aligned.
56 unsafe fn eeprom_write_u32_slice_unlocked(&self, offset: u32, data: &[u32]) -> Result<(), Error> {
57 for (i, &value) in data.iter().enumerate() {
58 let addr = EEPROM_BASE as u32 + offset + i as u32 * 4;
59 core::ptr::write_volatile(addr as *mut u32, value);
60 family::wait_ready_blocking()?;
61 family::clear_all_err();
62 }
63 Ok(())
64 }
65
66 // --- Public, safe API ---
67
68 /// Writes a single byte to EEPROM at the given offset.
69 pub fn eeprom_write_u8(&mut self, offset: u32, value: u8) -> Result<(), Error> {
70 self.check_eeprom_offset(offset, 1)?;
71 unsafe {
72 family::unlock();
73 let _on_drop = OnDrop::new(|| family::lock());
74 self.eeprom_write_u8_slice_unlocked(offset, core::slice::from_ref(&value))?;
75 }
76 Ok(())
77 }
78
79 /// Writes a single 16-bit value to EEPROM at the given offset.
80 ///
81 /// Returns an error if the offset is not 2-byte aligned.
82 pub fn eeprom_write_u16(&mut self, offset: u32, value: u16) -> Result<(), Error> {
83 if offset % 2 != 0 {
84 return Err(Error::Unaligned);
85 }
86 self.check_eeprom_offset(offset, 2)?;
87 unsafe {
88 family::unlock();
89 let _on_drop = OnDrop::new(|| family::lock());
90 self.eeprom_write_u16_slice_unlocked(offset, core::slice::from_ref(&value))?;
91 }
92 Ok(())
93 }
94
95 /// Writes a single 32-bit value to EEPROM at the given offset.
96 ///
97 /// Returns an error if the offset is not 4-byte aligned.
98 pub fn eeprom_write_u32(&mut self, offset: u32, value: u32) -> Result<(), Error> {
99 if offset % 4 != 0 {
100 return Err(Error::Unaligned);
101 }
102 self.check_eeprom_offset(offset, 4)?;
103 unsafe {
104 family::unlock();
105 let _on_drop = OnDrop::new(|| family::lock());
106 self.eeprom_write_u32_slice_unlocked(offset, core::slice::from_ref(&value))?;
107 }
108 Ok(())
109 }
110
111 /// Writes a slice of bytes to EEPROM at the given offset.
112 pub fn eeprom_write_u8_slice(&mut self, offset: u32, data: &[u8]) -> Result<(), Error> {
113 self.check_eeprom_offset(offset, data.len() as u32)?;
114 unsafe {
115 family::unlock();
116 let _on_drop = OnDrop::new(|| family::lock());
117 self.eeprom_write_u8_slice_unlocked(offset, data)?;
118 }
119 Ok(())
120 }
121
122 /// Writes a slice of 16-bit values to EEPROM at the given offset.
123 ///
124 /// Returns an error if the offset is not 2-byte aligned.
125 pub fn eeprom_write_u16_slice(&mut self, offset: u32, data: &[u16]) -> Result<(), Error> {
126 if offset % 2 != 0 {
127 return Err(Error::Unaligned);
128 }
129 self.check_eeprom_offset(offset, data.len() as u32 * 2)?;
130 unsafe {
131 family::unlock();
132 let _on_drop = OnDrop::new(|| family::lock());
133 self.eeprom_write_u16_slice_unlocked(offset, data)?;
134 }
135 Ok(())
136 }
137
138 /// Writes a slice of 32-bit values to EEPROM at the given offset.
139 ///
140 /// Returns an error if the offset is not 4-byte aligned.
141 pub fn eeprom_write_u32_slice(&mut self, offset: u32, data: &[u32]) -> Result<(), Error> {
142 if offset % 4 != 0 {
143 return Err(Error::Unaligned);
144 }
145 self.check_eeprom_offset(offset, data.len() as u32 * 4)?;
146 unsafe {
147 family::unlock();
148 let _on_drop = OnDrop::new(|| family::lock());
149 self.eeprom_write_u32_slice_unlocked(offset, data)?;
150 }
151 Ok(())
152 }
153
154 /// Writes a byte slice to EEPROM at the given offset, handling alignment.
155 ///
156 /// This method will write unaligned prefix and suffix as bytes, and aligned middle as u32.
157 pub fn eeprom_write_slice(&mut self, offset: u32, data: &[u8]) -> Result<(), Error> {
158 self.check_eeprom_offset(offset, data.len() as u32)?;
159 let start = offset;
160 let misalign = (start % 4) as usize;
161 let prefix_len = if misalign == 0 {
162 0
163 } else {
164 (4 - misalign).min(data.len())
165 };
166 let (prefix, rest) = data.split_at(prefix_len);
167 let aligned_len = (rest.len() / 4) * 4;
168 let (bytes_for_u32_write, suffix) = rest.split_at(aligned_len);
169
170 unsafe {
171 family::unlock();
172 let _on_drop = OnDrop::new(|| family::lock());
173
174 if !prefix.is_empty() {
175 self.eeprom_write_u8_slice_unlocked(start, prefix)?;
176 }
177 if !bytes_for_u32_write.is_empty() {
178 let aligned_eeprom_offset = start + prefix_len as u32;
179 let base_eeprom_addr = EEPROM_BASE as u32 + aligned_eeprom_offset;
180 for (i, chunk) in bytes_for_u32_write.chunks_exact(4).enumerate() {
181 // Safely read a u32 from a potentially unaligned pointer into the chunk.
182 let value = (chunk.as_ptr() as *const u32).read_unaligned();
183 let current_eeprom_addr = base_eeprom_addr + (i * 4) as u32;
184 core::ptr::write_volatile(current_eeprom_addr as *mut u32, value);
185 family::wait_ready_blocking()?;
186 family::clear_all_err();
187 }
188 }
189 if !suffix.is_empty() {
190 let suffix_offset = start + (prefix_len + aligned_len) as u32;
191 self.eeprom_write_u8_slice_unlocked(suffix_offset, suffix)?;
192 }
193 }
194 Ok(())
195 }
196
197 /// Reads a single byte from EEPROM at the given offset.
198 pub fn eeprom_read_u8(&self, offset: u32) -> Result<u8, Error> {
199 self.check_eeprom_offset(offset, 1)?;
200 let addr = EEPROM_BASE as u32 + offset;
201 Ok(unsafe { core::ptr::read_volatile(addr as *const u8) })
202 }
203
204 /// Reads a single 16-bit value from EEPROM at the given offset.
205 ///
206 /// Returns an error if the offset is not 2-byte aligned.
207 pub fn eeprom_read_u16(&self, offset: u32) -> Result<u16, Error> {
208 if offset % 2 != 0 {
209 return Err(Error::Unaligned);
210 }
211 self.check_eeprom_offset(offset, 2)?;
212 let addr = EEPROM_BASE as u32 + offset;
213 Ok(unsafe { core::ptr::read_volatile(addr as *const u16) })
214 }
215
216 /// Reads a single 32-bit value from EEPROM at the given offset.
217 ///
218 /// Returns an error if the offset is not 4-byte aligned.
219 pub fn eeprom_read_u32(&self, offset: u32) -> Result<u32, Error> {
220 if offset % 4 != 0 {
221 return Err(Error::Unaligned);
222 }
223 self.check_eeprom_offset(offset, 4)?;
224 let addr = EEPROM_BASE as u32 + offset;
225 Ok(unsafe { core::ptr::read_volatile(addr as *const u32) })
226 }
227
228 /// Reads a slice of bytes from EEPROM at the given offset into the provided buffer.
229 pub fn eeprom_read_slice(&self, offset: u32, buf: &mut [u8]) -> Result<(), Error> {
230 self.check_eeprom_offset(offset, buf.len() as u32)?;
231 let addr = EEPROM_BASE as u32 + offset;
232 let src = unsafe { core::slice::from_raw_parts(addr as *const u8, buf.len()) };
233 buf.copy_from_slice(src);
234 Ok(())
235 }
236}
diff --git a/embassy-stm32/src/flash/l.rs b/embassy-stm32/src/flash/l.rs
index 65cea005c..1b82704ec 100644
--- a/embassy-stm32/src/flash/l.rs
+++ b/embassy-stm32/src/flash/l.rs
@@ -162,7 +162,7 @@ pub(crate) unsafe fn clear_all_err() {
162 pac::FLASH.nssr().modify(|_| {}); 162 pac::FLASH.nssr().modify(|_| {});
163} 163}
164 164
165unsafe fn wait_ready_blocking() -> Result<(), Error> { 165pub(crate) unsafe fn wait_ready_blocking() -> Result<(), Error> {
166 loop { 166 loop {
167 #[cfg(not(flash_l5))] 167 #[cfg(not(flash_l5))]
168 { 168 {
diff --git a/embassy-stm32/src/flash/mod.rs b/embassy-stm32/src/flash/mod.rs
index adc45db9c..a3f9e00f7 100644
--- a/embassy-stm32/src/flash/mod.rs
+++ b/embassy-stm32/src/flash/mod.rs
@@ -5,13 +5,20 @@ use embedded_storage::nor_flash::{NorFlashError, NorFlashErrorKind};
5mod asynch; 5mod asynch;
6#[cfg(flash)] 6#[cfg(flash)]
7mod common; 7mod common;
8#[cfg(eeprom)]
9mod eeprom;
8 10
9#[cfg(flash_f4)] 11#[cfg(flash_f4)]
10pub use asynch::InterruptHandler; 12pub use asynch::InterruptHandler;
11#[cfg(flash)] 13#[cfg(flash)]
12pub use common::*; 14pub use common::*;
15#[cfg(eeprom)]
16#[allow(unused_imports)]
17pub use eeprom::*;
13 18
14pub use crate::_generated::flash_regions::*; 19pub use crate::_generated::flash_regions::*;
20#[cfg(eeprom)]
21pub use crate::_generated::{EEPROM_BASE, EEPROM_SIZE};
15pub use crate::_generated::{FLASH_BASE, FLASH_SIZE, MAX_ERASE_SIZE, WRITE_SIZE}; 22pub use crate::_generated::{FLASH_BASE, FLASH_SIZE, MAX_ERASE_SIZE, WRITE_SIZE};
16 23
17/// Get all flash regions. 24/// Get all flash regions.
@@ -83,7 +90,8 @@ pub enum FlashBank {
83 /// OTP region, 90 /// OTP region,
84 Otp, 91 Otp,
85} 92}
86 93#[cfg(all(eeprom, not(any(flash_l0, flash_l1))))]
94compile_error!("The 'eeprom' cfg is enabled for a non-L0/L1 chip family. This is an unsupported configuration.");
87#[cfg_attr(any(flash_l0, flash_l1, flash_l4, flash_l5, flash_wl, flash_wb), path = "l.rs")] 95#[cfg_attr(any(flash_l0, flash_l1, flash_l4, flash_l5, flash_wl, flash_wb), path = "l.rs")]
88#[cfg_attr(flash_f0, path = "f0.rs")] 96#[cfg_attr(flash_f0, path = "f0.rs")]
89#[cfg_attr(any(flash_f1, flash_f3), path = "f1f3.rs")] 97#[cfg_attr(any(flash_f1, flash_f3), path = "f1f3.rs")]
diff --git a/examples/boot/application/stm32f3/Cargo.toml b/examples/boot/application/stm32f3/Cargo.toml
index 87f97071b..b3466e288 100644
--- a/examples/boot/application/stm32f3/Cargo.toml
+++ b/examples/boot/application/stm32f3/Cargo.toml
@@ -9,7 +9,7 @@ embassy-sync = { version = "0.7.0", path = "../../../../embassy-sync" }
9embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread"] } 9embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread"] }
10embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } 10embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] }
11embassy-stm32 = { version = "0.2.0", path = "../../../../embassy-stm32", features = ["stm32f303re", "time-driver-any", "exti"] } 11embassy-stm32 = { version = "0.2.0", path = "../../../../embassy-stm32", features = ["stm32f303re", "time-driver-any", "exti"] }
12embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32" } 12embassy-boot-stm32 = { version = "0.3.0", path = "../../../../embassy-boot-stm32" }
13embassy-embedded-hal = { version = "0.3.0", path = "../../../../embassy-embedded-hal" } 13embassy-embedded-hal = { version = "0.3.0", path = "../../../../embassy-embedded-hal" }
14 14
15defmt = { version = "1.0.1", optional = true } 15defmt = { version = "1.0.1", optional = true }
diff --git a/examples/boot/application/stm32f7/Cargo.toml b/examples/boot/application/stm32f7/Cargo.toml
index d593a568e..72dbded5f 100644
--- a/examples/boot/application/stm32f7/Cargo.toml
+++ b/examples/boot/application/stm32f7/Cargo.toml
@@ -9,7 +9,7 @@ embassy-sync = { version = "0.7.0", path = "../../../../embassy-sync" }
9embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread"] } 9embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread"] }
10embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } 10embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] }
11embassy-stm32 = { version = "0.2.0", path = "../../../../embassy-stm32", features = ["stm32f767zi", "time-driver-any", "exti", "single-bank"] } 11embassy-stm32 = { version = "0.2.0", path = "../../../../embassy-stm32", features = ["stm32f767zi", "time-driver-any", "exti", "single-bank"] }
12embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } 12embassy-boot-stm32 = { version = "0.3.0", path = "../../../../embassy-boot-stm32", features = [] }
13embassy-embedded-hal = { version = "0.3.0", path = "../../../../embassy-embedded-hal" } 13embassy-embedded-hal = { version = "0.3.0", path = "../../../../embassy-embedded-hal" }
14 14
15defmt = { version = "1.0.1", optional = true } 15defmt = { version = "1.0.1", optional = true }
diff --git a/examples/boot/application/stm32h7/Cargo.toml b/examples/boot/application/stm32h7/Cargo.toml
index 7653d82ed..57fb8312c 100644
--- a/examples/boot/application/stm32h7/Cargo.toml
+++ b/examples/boot/application/stm32h7/Cargo.toml
@@ -9,7 +9,7 @@ embassy-sync = { version = "0.7.0", path = "../../../../embassy-sync" }
9embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread"] } 9embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread"] }
10embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } 10embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] }
11embassy-stm32 = { version = "0.2.0", path = "../../../../embassy-stm32", features = ["stm32h743zi", "time-driver-any", "exti"] } 11embassy-stm32 = { version = "0.2.0", path = "../../../../embassy-stm32", features = ["stm32h743zi", "time-driver-any", "exti"] }
12embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } 12embassy-boot-stm32 = { version = "0.3.0", path = "../../../../embassy-boot-stm32", features = [] }
13embassy-embedded-hal = { version = "0.3.0", path = "../../../../embassy-embedded-hal" } 13embassy-embedded-hal = { version = "0.3.0", path = "../../../../embassy-embedded-hal" }
14 14
15defmt = { version = "1.0.1", optional = true } 15defmt = { version = "1.0.1", optional = true }
diff --git a/examples/boot/application/stm32l0/Cargo.toml b/examples/boot/application/stm32l0/Cargo.toml
index d1cace246..7dbbba138 100644
--- a/examples/boot/application/stm32l0/Cargo.toml
+++ b/examples/boot/application/stm32l0/Cargo.toml
@@ -9,7 +9,7 @@ embassy-sync = { version = "0.7.0", path = "../../../../embassy-sync" }
9embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread"] } 9embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread"] }
10embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } 10embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] }
11embassy-stm32 = { version = "0.2.0", path = "../../../../embassy-stm32", features = ["stm32l072cz", "time-driver-any", "exti", "memory-x"] } 11embassy-stm32 = { version = "0.2.0", path = "../../../../embassy-stm32", features = ["stm32l072cz", "time-driver-any", "exti", "memory-x"] }
12embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } 12embassy-boot-stm32 = { version = "0.3.0", path = "../../../../embassy-boot-stm32", features = [] }
13embassy-embedded-hal = { version = "0.3.0", path = "../../../../embassy-embedded-hal" } 13embassy-embedded-hal = { version = "0.3.0", path = "../../../../embassy-embedded-hal" }
14 14
15defmt = { version = "1.0.1", optional = true } 15defmt = { version = "1.0.1", optional = true }
diff --git a/examples/boot/application/stm32l1/Cargo.toml b/examples/boot/application/stm32l1/Cargo.toml
index 034bf39af..9549b2048 100644
--- a/examples/boot/application/stm32l1/Cargo.toml
+++ b/examples/boot/application/stm32l1/Cargo.toml
@@ -9,7 +9,7 @@ embassy-sync = { version = "0.7.0", path = "../../../../embassy-sync" }
9embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread"] } 9embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread"] }
10embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } 10embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] }
11embassy-stm32 = { version = "0.2.0", path = "../../../../embassy-stm32", features = ["stm32l151cb-a", "time-driver-any", "exti"] } 11embassy-stm32 = { version = "0.2.0", path = "../../../../embassy-stm32", features = ["stm32l151cb-a", "time-driver-any", "exti"] }
12embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } 12embassy-boot-stm32 = { version = "0.3.0", path = "../../../../embassy-boot-stm32", features = [] }
13embassy-embedded-hal = { version = "0.3.0", path = "../../../../embassy-embedded-hal" } 13embassy-embedded-hal = { version = "0.3.0", path = "../../../../embassy-embedded-hal" }
14 14
15defmt = { version = "1.0.1", optional = true } 15defmt = { version = "1.0.1", optional = true }
diff --git a/examples/boot/application/stm32l4/Cargo.toml b/examples/boot/application/stm32l4/Cargo.toml
index d32cbca97..03daeb0bc 100644
--- a/examples/boot/application/stm32l4/Cargo.toml
+++ b/examples/boot/application/stm32l4/Cargo.toml
@@ -9,7 +9,7 @@ embassy-sync = { version = "0.7.0", path = "../../../../embassy-sync" }
9embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread"] } 9embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread"] }
10embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } 10embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] }
11embassy-stm32 = { version = "0.2.0", path = "../../../../embassy-stm32", features = ["stm32l475vg", "time-driver-any", "exti"] } 11embassy-stm32 = { version = "0.2.0", path = "../../../../embassy-stm32", features = ["stm32l475vg", "time-driver-any", "exti"] }
12embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } 12embassy-boot-stm32 = { version = "0.3.0", path = "../../../../embassy-boot-stm32", features = [] }
13embassy-embedded-hal = { version = "0.3.0", path = "../../../../embassy-embedded-hal" } 13embassy-embedded-hal = { version = "0.3.0", path = "../../../../embassy-embedded-hal" }
14 14
15defmt = { version = "1.0.1", optional = true } 15defmt = { version = "1.0.1", optional = true }
diff --git a/examples/boot/application/stm32wb-dfu/Cargo.toml b/examples/boot/application/stm32wb-dfu/Cargo.toml
index 49b35f681..e582628aa 100644
--- a/examples/boot/application/stm32wb-dfu/Cargo.toml
+++ b/examples/boot/application/stm32wb-dfu/Cargo.toml
@@ -9,7 +9,7 @@ embassy-sync = { version = "0.7.0", path = "../../../../embassy-sync" }
9embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread"] } 9embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread"] }
10embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } 10embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] }
11embassy-stm32 = { version = "0.2.0", path = "../../../../embassy-stm32", features = ["stm32wb55rg", "time-driver-any", "exti"] } 11embassy-stm32 = { version = "0.2.0", path = "../../../../embassy-stm32", features = ["stm32wb55rg", "time-driver-any", "exti"] }
12embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } 12embassy-boot-stm32 = { version = "0.3.0", path = "../../../../embassy-boot-stm32", features = [] }
13embassy-embedded-hal = { version = "0.3.0", path = "../../../../embassy-embedded-hal" } 13embassy-embedded-hal = { version = "0.3.0", path = "../../../../embassy-embedded-hal" }
14embassy-usb = { version = "0.4.0", path = "../../../../embassy-usb" } 14embassy-usb = { version = "0.4.0", path = "../../../../embassy-usb" }
15embassy-usb-dfu = { version = "0.1.0", path = "../../../../embassy-usb-dfu", features = ["application", "cortex-m"] } 15embassy-usb-dfu = { version = "0.1.0", path = "../../../../embassy-usb-dfu", features = ["application", "cortex-m"] }
diff --git a/examples/boot/application/stm32wl/Cargo.toml b/examples/boot/application/stm32wl/Cargo.toml
index e44d9859a..3ed04b472 100644
--- a/examples/boot/application/stm32wl/Cargo.toml
+++ b/examples/boot/application/stm32wl/Cargo.toml
@@ -9,7 +9,7 @@ embassy-sync = { version = "0.7.0", path = "../../../../embassy-sync" }
9embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread"] } 9embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread"] }
10embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } 10embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] }
11embassy-stm32 = { version = "0.2.0", path = "../../../../embassy-stm32", features = ["stm32wl55jc-cm4", "time-driver-any", "exti"] } 11embassy-stm32 = { version = "0.2.0", path = "../../../../embassy-stm32", features = ["stm32wl55jc-cm4", "time-driver-any", "exti"] }
12embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } 12embassy-boot-stm32 = { version = "0.3.0", path = "../../../../embassy-boot-stm32", features = [] }
13embassy-embedded-hal = { version = "0.3.0", path = "../../../../embassy-embedded-hal" } 13embassy-embedded-hal = { version = "0.3.0", path = "../../../../embassy-embedded-hal" }
14 14
15defmt = { version = "1.0.1", optional = true } 15defmt = { version = "1.0.1", optional = true }
diff --git a/examples/stm32l0/src/bin/eeprom.rs b/examples/stm32l0/src/bin/eeprom.rs
new file mode 100644
index 000000000..370246644
--- /dev/null
+++ b/examples/stm32l0/src/bin/eeprom.rs
@@ -0,0 +1,32 @@
1#![no_std]
2#![no_main]
3
4use defmt::{info, unwrap};
5use embassy_executor::Spawner;
6use embassy_stm32::flash::{Flash, EEPROM_BASE, EEPROM_SIZE};
7use {defmt_rtt as _, panic_probe as _};
8
9#[embassy_executor::main]
10async fn main(_spawner: Spawner) {
11 let p = embassy_stm32::init(Default::default());
12
13 info!("Hello Eeprom! Start: {}, Size: {}", EEPROM_BASE, EEPROM_SIZE);
14
15 const ADDR: u32 = 0x0;
16
17 let mut f = Flash::new_blocking(p.FLASH);
18
19 info!("Reading...");
20 let mut buf = [0u8; 8];
21 unwrap!(f.eeprom_read_slice(ADDR, &mut buf));
22 info!("Read: {=[u8]:x}", buf);
23
24 info!("Writing...");
25 unwrap!(f.eeprom_write_slice(ADDR, &[1, 2, 3, 4, 5, 6, 7, 8]));
26
27 info!("Reading...");
28 let mut buf = [0u8; 8];
29 unwrap!(f.eeprom_read_slice(ADDR, &mut buf));
30 info!("Read: {=[u8]:x}", buf);
31 assert_eq!(&buf[..], &[1, 2, 3, 4, 5, 6, 7, 8]);
32}
diff --git a/examples/stm32l1/src/bin/eeprom.rs b/examples/stm32l1/src/bin/eeprom.rs
new file mode 100644
index 000000000..370246644
--- /dev/null
+++ b/examples/stm32l1/src/bin/eeprom.rs
@@ -0,0 +1,32 @@
1#![no_std]
2#![no_main]
3
4use defmt::{info, unwrap};
5use embassy_executor::Spawner;
6use embassy_stm32::flash::{Flash, EEPROM_BASE, EEPROM_SIZE};
7use {defmt_rtt as _, panic_probe as _};
8
9#[embassy_executor::main]
10async fn main(_spawner: Spawner) {
11 let p = embassy_stm32::init(Default::default());
12
13 info!("Hello Eeprom! Start: {}, Size: {}", EEPROM_BASE, EEPROM_SIZE);
14
15 const ADDR: u32 = 0x0;
16
17 let mut f = Flash::new_blocking(p.FLASH);
18
19 info!("Reading...");
20 let mut buf = [0u8; 8];
21 unwrap!(f.eeprom_read_slice(ADDR, &mut buf));
22 info!("Read: {=[u8]:x}", buf);
23
24 info!("Writing...");
25 unwrap!(f.eeprom_write_slice(ADDR, &[1, 2, 3, 4, 5, 6, 7, 8]));
26
27 info!("Reading...");
28 let mut buf = [0u8; 8];
29 unwrap!(f.eeprom_read_slice(ADDR, &mut buf));
30 info!("Read: {=[u8]:x}", buf);
31 assert_eq!(&buf[..], &[1, 2, 3, 4, 5, 6, 7, 8]);
32}
diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml
index e78520e40..8d10f6593 100644
--- a/tests/stm32/Cargo.toml
+++ b/tests/stm32/Cargo.toml
@@ -19,8 +19,8 @@ stm32h563zi = ["embassy-stm32/stm32h563zi", "spi-v345", "chrono", "eth", "rng",
19stm32h753zi = ["embassy-stm32/stm32h753zi", "spi-v345", "chrono", "not-gpdma", "eth", "rng", "fdcan", "hash", "cryp"] 19stm32h753zi = ["embassy-stm32/stm32h753zi", "spi-v345", "chrono", "not-gpdma", "eth", "rng", "fdcan", "hash", "cryp"]
20stm32h755zi = ["embassy-stm32/stm32h755zi-cm7", "spi-v345", "chrono", "not-gpdma", "eth", "dac", "rng", "fdcan", "hash", "cryp"] 20stm32h755zi = ["embassy-stm32/stm32h755zi-cm7", "spi-v345", "chrono", "not-gpdma", "eth", "dac", "rng", "fdcan", "hash", "cryp"]
21stm32h7a3zi = ["embassy-stm32/stm32h7a3zi", "spi-v345", "not-gpdma", "rng", "fdcan"] 21stm32h7a3zi = ["embassy-stm32/stm32h7a3zi", "spi-v345", "not-gpdma", "rng", "fdcan"]
22stm32l073rz = ["embassy-stm32/stm32l073rz", "cm0", "not-gpdma", "rng"] 22stm32l073rz = ["embassy-stm32/stm32l073rz", "cm0", "not-gpdma", "rng", "eeprom"]
23stm32l152re = ["embassy-stm32/stm32l152re", "spi-v1", "chrono", "not-gpdma"] 23stm32l152re = ["embassy-stm32/stm32l152re", "spi-v1", "chrono", "not-gpdma", "eeprom"]
24stm32l496zg = ["embassy-stm32/stm32l496zg", "not-gpdma", "rng"] 24stm32l496zg = ["embassy-stm32/stm32l496zg", "not-gpdma", "rng"]
25stm32l4a6zg = ["embassy-stm32/stm32l4a6zg", "chrono", "not-gpdma", "rng", "hash"] 25stm32l4a6zg = ["embassy-stm32/stm32l4a6zg", "chrono", "not-gpdma", "rng", "hash"]
26stm32l4r5zi = ["embassy-stm32/stm32l4r5zi", "chrono", "not-gpdma", "rng", "dual-bank"] 26stm32l4r5zi = ["embassy-stm32/stm32l4r5zi", "chrono", "not-gpdma", "rng", "dual-bank"]
@@ -55,6 +55,7 @@ ucpd = []
55cordic = ["dep:num-traits"] 55cordic = ["dep:num-traits"]
56dual-bank = ["embassy-stm32/dual-bank"] 56dual-bank = ["embassy-stm32/dual-bank"]
57single-bank = ["embassy-stm32/single-bank"] 57single-bank = ["embassy-stm32/single-bank"]
58eeprom = []
58 59
59cm0 = ["portable-atomic/unsafe-assume-single-core"] 60cm0 = ["portable-atomic/unsafe-assume-single-core"]
60 61
@@ -120,6 +121,11 @@ path = "src/bin/dac_l1.rs"
120required-features = [ "stm32l152re",] 121required-features = [ "stm32l152re",]
121 122
122[[bin]] 123[[bin]]
124name = "eeprom"
125path = "src/bin/eeprom.rs"
126required-features = [ "eeprom",]
127
128[[bin]]
123name = "eth" 129name = "eth"
124path = "src/bin/eth.rs" 130path = "src/bin/eth.rs"
125required-features = [ "eth",] 131required-features = [ "eth",]
diff --git a/tests/stm32/src/bin/eeprom.rs b/tests/stm32/src/bin/eeprom.rs
new file mode 100644
index 000000000..61d249fd7
--- /dev/null
+++ b/tests/stm32/src/bin/eeprom.rs
@@ -0,0 +1,30 @@
1#![no_std]
2#![no_main]
3
4// required-features: eeprom
5
6#[path = "../common.rs"]
7mod common;
8
9use common::*;
10use defmt::assert_eq;
11use embassy_executor::Spawner;
12use embassy_stm32::flash::Flash;
13use {defmt_rtt as _, panic_probe as _};
14
15#[embassy_executor::main]
16async fn main(_spawner: Spawner) {
17 // Initialize the board and obtain a Peripherals instance
18 let p: embassy_stm32::Peripherals = init();
19
20 let mut f = Flash::new_blocking(p.FLASH);
21 const ADDR: u32 = 0x0;
22
23 unwrap!(f.eeprom_write_slice(ADDR, &[1, 2, 3, 4, 5, 6, 7, 8]));
24 let mut buf = [0u8; 8];
25 unwrap!(f.eeprom_read_slice(ADDR, &mut buf));
26 assert_eq!(&buf[..], &[1, 2, 3, 4, 5, 6, 7, 8]);
27
28 info!("Test OK");
29 cortex_m::asm::bkpt();
30}