diff options
| author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2022-07-11 01:37:19 +0000 |
|---|---|---|
| committer | GitHub <[email protected]> | 2022-07-11 01:37:19 +0000 |
| commit | 99f4fd33b493f11ec3202eb98fc3ae9e18b9d589 (patch) | |
| tree | 931e4ebbb9927011c885779cc3339072b129d34c | |
| parent | 9753f767946d79c5987c166e513150aca98ec042 (diff) | |
| parent | 3271ba36e439b037a9f775ccc9b7de8511cbcf7a (diff) | |
Merge #859
859: Add F4 flash driver r=Dirbaio a=chemicstry
Pending on https://github.com/embassy-rs/stm32-data/pull/152
Co-authored-by: chemicstry <[email protected]>
| -rw-r--r-- | embassy-stm32/src/flash/f4.rs | 168 | ||||
| -rw-r--r-- | embassy-stm32/src/flash/mod.rs | 1 | ||||
| -rw-r--r-- | embassy-stm32/src/lib.rs | 4 | ||||
| -rw-r--r-- | examples/stm32f4/Cargo.toml | 1 | ||||
| -rw-r--r-- | examples/stm32f4/src/bin/flash.rs | 57 | ||||
| m--------- | stm32-data | 0 |
6 files changed, 230 insertions, 1 deletions
diff --git a/embassy-stm32/src/flash/f4.rs b/embassy-stm32/src/flash/f4.rs new file mode 100644 index 000000000..f6dc7e955 --- /dev/null +++ b/embassy-stm32/src/flash/f4.rs | |||
| @@ -0,0 +1,168 @@ | |||
| 1 | use core::convert::TryInto; | ||
| 2 | use core::ptr::write_volatile; | ||
| 3 | |||
| 4 | use atomic_polyfill::{fence, Ordering}; | ||
| 5 | |||
| 6 | use super::{ERASE_SIZE, FLASH_BASE, FLASH_SIZE}; | ||
| 7 | use crate::flash::Error; | ||
| 8 | use crate::pac; | ||
| 9 | |||
| 10 | // Only available on some devices | ||
| 11 | const SECOND_BANK_OFFSET: usize = FLASH_SIZE / 2; | ||
| 12 | const SECOND_BANK_SECTOR_START: u32 = 12; | ||
| 13 | |||
| 14 | unsafe fn is_dual_bank() -> bool { | ||
| 15 | match FLASH_SIZE / 1024 { | ||
| 16 | // 1 MB devices depend on configuration | ||
| 17 | 1024 => { | ||
| 18 | if cfg!(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f469, stm32f479)) { | ||
| 19 | pac::FLASH.optcr().read().db1m() | ||
| 20 | } else { | ||
| 21 | false | ||
| 22 | } | ||
| 23 | } | ||
| 24 | // 2 MB devices are always dual bank | ||
| 25 | 2048 => true, | ||
| 26 | // All other devices are single bank | ||
| 27 | _ => false, | ||
| 28 | } | ||
| 29 | } | ||
| 30 | |||
| 31 | pub(crate) unsafe fn lock() { | ||
| 32 | pac::FLASH.cr().modify(|w| w.set_lock(true)); | ||
| 33 | } | ||
| 34 | |||
| 35 | pub(crate) unsafe fn unlock() { | ||
| 36 | pac::FLASH.keyr().write(|w| w.set_key(0x4567_0123)); | ||
| 37 | pac::FLASH.keyr().write(|w| w.set_key(0xCDEF_89AB)); | ||
| 38 | } | ||
| 39 | |||
| 40 | pub(crate) unsafe fn blocking_write(offset: u32, buf: &[u8]) -> Result<(), Error> { | ||
| 41 | pac::FLASH.cr().write(|w| { | ||
| 42 | w.set_pg(true); | ||
| 43 | w.set_psize(pac::flash::vals::Psize::PSIZE32); | ||
| 44 | }); | ||
| 45 | |||
| 46 | let ret = { | ||
| 47 | let mut ret: Result<(), Error> = Ok(()); | ||
| 48 | let mut offset = offset; | ||
| 49 | for chunk in buf.chunks(super::WRITE_SIZE) { | ||
| 50 | for val in chunk.chunks(4) { | ||
| 51 | write_volatile(offset as *mut u32, u32::from_le_bytes(val[0..4].try_into().unwrap())); | ||
| 52 | offset += val.len() as u32; | ||
| 53 | |||
| 54 | // prevents parallelism errors | ||
| 55 | fence(Ordering::SeqCst); | ||
| 56 | } | ||
| 57 | |||
| 58 | ret = blocking_wait_ready(); | ||
| 59 | if ret.is_err() { | ||
| 60 | break; | ||
| 61 | } | ||
| 62 | } | ||
| 63 | ret | ||
| 64 | }; | ||
| 65 | |||
| 66 | pac::FLASH.cr().write(|w| w.set_pg(false)); | ||
| 67 | |||
| 68 | ret | ||
| 69 | } | ||
| 70 | |||
| 71 | unsafe fn get_sector(addr: u32) -> u8 { | ||
| 72 | let offset = addr - FLASH_BASE as u32; | ||
| 73 | |||
| 74 | let sector = if is_dual_bank() { | ||
| 75 | let bank = offset / SECOND_BANK_OFFSET as u32; | ||
| 76 | let offset_in_bank = offset % SECOND_BANK_OFFSET as u32; | ||
| 77 | |||
| 78 | let sector_in_bank = if offset_in_bank >= ERASE_SIZE as u32 / 2 { | ||
| 79 | 4 + offset_in_bank / ERASE_SIZE as u32 | ||
| 80 | } else { | ||
| 81 | offset_in_bank / (ERASE_SIZE as u32 / 8) | ||
| 82 | }; | ||
| 83 | |||
| 84 | if bank == 1 { | ||
| 85 | SECOND_BANK_SECTOR_START + sector_in_bank | ||
| 86 | } else { | ||
| 87 | sector_in_bank | ||
| 88 | } | ||
| 89 | } else { | ||
| 90 | if offset >= ERASE_SIZE as u32 / 2 { | ||
| 91 | 4 + offset / ERASE_SIZE as u32 | ||
| 92 | } else { | ||
| 93 | offset / (ERASE_SIZE as u32 / 8) | ||
| 94 | } | ||
| 95 | }; | ||
| 96 | |||
| 97 | sector as u8 | ||
| 98 | } | ||
| 99 | |||
| 100 | pub(crate) unsafe fn blocking_erase(from: u32, to: u32) -> Result<(), Error> { | ||
| 101 | let start_sector = get_sector(from); | ||
| 102 | let end_sector = get_sector(to); | ||
| 103 | |||
| 104 | for sector in start_sector..end_sector { | ||
| 105 | let ret = erase_sector(sector as u8); | ||
| 106 | if ret.is_err() { | ||
| 107 | return ret; | ||
| 108 | } | ||
| 109 | } | ||
| 110 | |||
| 111 | Ok(()) | ||
| 112 | } | ||
| 113 | |||
| 114 | unsafe fn erase_sector(sector: u8) -> Result<(), Error> { | ||
| 115 | let bank = sector / SECOND_BANK_SECTOR_START as u8; | ||
| 116 | let snb = (bank << 4) + (sector % SECOND_BANK_SECTOR_START as u8); | ||
| 117 | |||
| 118 | pac::FLASH.cr().modify(|w| { | ||
| 119 | w.set_ser(true); | ||
| 120 | w.set_snb(snb) | ||
| 121 | }); | ||
| 122 | |||
| 123 | pac::FLASH.cr().modify(|w| { | ||
| 124 | w.set_strt(true); | ||
| 125 | }); | ||
| 126 | |||
| 127 | let ret: Result<(), Error> = blocking_wait_ready(); | ||
| 128 | |||
| 129 | clear_all_err(); | ||
| 130 | |||
| 131 | ret | ||
| 132 | } | ||
| 133 | |||
| 134 | pub(crate) unsafe fn clear_all_err() { | ||
| 135 | pac::FLASH.sr().write(|w| { | ||
| 136 | w.set_pgserr(true); | ||
| 137 | w.set_pgperr(true); | ||
| 138 | w.set_pgaerr(true); | ||
| 139 | w.set_wrperr(true); | ||
| 140 | w.set_eop(true); | ||
| 141 | }); | ||
| 142 | } | ||
| 143 | |||
| 144 | pub(crate) unsafe fn blocking_wait_ready() -> Result<(), Error> { | ||
| 145 | loop { | ||
| 146 | let sr = pac::FLASH.sr().read(); | ||
| 147 | |||
| 148 | if !sr.bsy() { | ||
| 149 | if sr.pgserr() { | ||
| 150 | return Err(Error::Seq); | ||
| 151 | } | ||
| 152 | |||
| 153 | if sr.pgperr() { | ||
| 154 | return Err(Error::Parallelism); | ||
| 155 | } | ||
| 156 | |||
| 157 | if sr.pgaerr() { | ||
| 158 | return Err(Error::Unaligned); | ||
| 159 | } | ||
| 160 | |||
| 161 | if sr.wrperr() { | ||
| 162 | return Err(Error::Protected); | ||
| 163 | } | ||
| 164 | |||
| 165 | return Ok(()); | ||
| 166 | } | ||
| 167 | } | ||
| 168 | } | ||
diff --git a/embassy-stm32/src/flash/mod.rs b/embassy-stm32/src/flash/mod.rs index 31ca243a6..59ca59f65 100644 --- a/embassy-stm32/src/flash/mod.rs +++ b/embassy-stm32/src/flash/mod.rs | |||
| @@ -10,6 +10,7 @@ const FLASH_END: usize = FLASH_BASE + FLASH_SIZE; | |||
| 10 | 10 | ||
| 11 | #[cfg_attr(any(flash_wl, flash_wb, flash_l0, flash_l1, flash_l4), path = "l.rs")] | 11 | #[cfg_attr(any(flash_wl, flash_wb, flash_l0, flash_l1, flash_l4), path = "l.rs")] |
| 12 | #[cfg_attr(flash_f3, path = "f3.rs")] | 12 | #[cfg_attr(flash_f3, path = "f3.rs")] |
| 13 | #[cfg_attr(flash_f4, path = "f4.rs")] | ||
| 13 | #[cfg_attr(flash_f7, path = "f7.rs")] | 14 | #[cfg_attr(flash_f7, path = "f7.rs")] |
| 14 | #[cfg_attr(flash_h7, path = "h7.rs")] | 15 | #[cfg_attr(flash_h7, path = "h7.rs")] |
| 15 | mod family; | 16 | mod family; |
diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index 7be0c77ea..8b8168589 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs | |||
| @@ -39,7 +39,9 @@ pub mod i2c; | |||
| 39 | 39 | ||
| 40 | #[cfg(crc)] | 40 | #[cfg(crc)] |
| 41 | pub mod crc; | 41 | pub mod crc; |
| 42 | #[cfg(any(flash_l0, flash_l1, flash_wl, flash_wb, flash_l4, flash_f3, flash_f7, flash_h7))] | 42 | #[cfg(any( |
| 43 | flash_l0, flash_l1, flash_wl, flash_wb, flash_l4, flash_f3, flash_f4, flash_f7, flash_h7 | ||
| 44 | ))] | ||
| 43 | pub mod flash; | 45 | pub mod flash; |
| 44 | pub mod pwm; | 46 | pub mod pwm; |
| 45 | #[cfg(rng)] | 47 | #[cfg(rng)] |
diff --git a/examples/stm32f4/Cargo.toml b/examples/stm32f4/Cargo.toml index de33ffad8..100c0e608 100644 --- a/examples/stm32f4/Cargo.toml +++ b/examples/stm32f4/Cargo.toml | |||
| @@ -19,6 +19,7 @@ panic-probe = { version = "0.3", features = ["print-defmt"] } | |||
| 19 | futures = { version = "0.3.17", default-features = false, features = ["async-await"] } | 19 | futures = { version = "0.3.17", default-features = false, features = ["async-await"] } |
| 20 | heapless = { version = "0.7.5", default-features = false } | 20 | heapless = { version = "0.7.5", default-features = false } |
| 21 | nb = "1.0.0" | 21 | nb = "1.0.0" |
| 22 | embedded-storage = "0.3.0" | ||
| 22 | 23 | ||
| 23 | usb-device = "0.2" | 24 | usb-device = "0.2" |
| 24 | usbd-serial = "0.1.1" | 25 | usbd-serial = "0.1.1" |
diff --git a/examples/stm32f4/src/bin/flash.rs b/examples/stm32f4/src/bin/flash.rs new file mode 100644 index 000000000..b531d6f13 --- /dev/null +++ b/examples/stm32f4/src/bin/flash.rs | |||
| @@ -0,0 +1,57 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | #![feature(type_alias_impl_trait)] | ||
| 4 | |||
| 5 | use defmt::{info, unwrap}; | ||
| 6 | use embassy::executor::Spawner; | ||
| 7 | use embassy::time::{Duration, Timer}; | ||
| 8 | use embassy_stm32::flash::Flash; | ||
| 9 | use embassy_stm32::Peripherals; | ||
| 10 | use embedded_storage::nor_flash::{NorFlash, ReadNorFlash}; | ||
| 11 | use {defmt_rtt as _, panic_probe as _}; | ||
| 12 | |||
| 13 | #[embassy::main] | ||
| 14 | async fn main(_spawner: Spawner, p: Peripherals) { | ||
| 15 | info!("Hello Flash!"); | ||
| 16 | |||
| 17 | const ADDR: u32 = 0x10_0000; | ||
| 18 | |||
| 19 | // wait a bit before accessing the flash | ||
| 20 | Timer::after(Duration::from_millis(300)).await; | ||
| 21 | |||
| 22 | let mut f = Flash::unlock(p.FLASH); | ||
| 23 | |||
| 24 | info!("Reading..."); | ||
| 25 | let mut buf = [0u8; 32]; | ||
| 26 | unwrap!(f.read(ADDR, &mut buf)); | ||
| 27 | info!("Read: {=[u8]:x}", buf); | ||
| 28 | |||
| 29 | info!("Erasing..."); | ||
| 30 | unwrap!(f.erase(ADDR, ADDR + 128 * 1024)); | ||
| 31 | |||
| 32 | info!("Reading..."); | ||
| 33 | let mut buf = [0u8; 32]; | ||
| 34 | unwrap!(f.read(ADDR, &mut buf)); | ||
| 35 | info!("Read after erase: {=[u8]:x}", buf); | ||
| 36 | |||
| 37 | info!("Writing..."); | ||
| 38 | unwrap!(f.write( | ||
| 39 | ADDR, | ||
| 40 | &[ | ||
| 41 | 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, | ||
| 42 | 30, 31, 32 | ||
| 43 | ] | ||
| 44 | )); | ||
| 45 | |||
| 46 | info!("Reading..."); | ||
| 47 | let mut buf = [0u8; 32]; | ||
| 48 | unwrap!(f.read(ADDR, &mut buf)); | ||
| 49 | info!("Read: {=[u8]:x}", buf); | ||
| 50 | assert_eq!( | ||
| 51 | &buf[..], | ||
| 52 | &[ | ||
| 53 | 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, | ||
| 54 | 30, 31, 32 | ||
| 55 | ] | ||
| 56 | ); | ||
| 57 | } | ||
diff --git a/stm32-data b/stm32-data | |||
| Subproject b90d7cf8cb0610e333e4eef7127ae8c51955860 | Subproject b13ba26f6f9b7049097e39ccc7e5e246ac023d1 | ||
