diff --git a/CHANGELOG.md b/CHANGELOG.md index 14705044..537a26e6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ - [Integration](https://crates.io/crates/mcan-core) with the [`mcan`](https://crates.io/crates/mcan) crate. - Implementation of blocking::i2c::Transactional trait from [embedded-hal](https://crates.io/crates/embedded-hal) for TWI device. +- Implementation of ReadNorFlash and NorFlash traits from [embedded-storage](https://crates.io/crates/embedded-storage) for EFC. ### Changed diff --git a/boards/atsame70_xpro/Cargo.lock b/boards/atsame70_xpro/Cargo.lock index a693e1e9..13dc7844 100644 --- a/boards/atsame70_xpro/Cargo.lock +++ b/boards/atsame70_xpro/Cargo.lock @@ -27,6 +27,7 @@ dependencies = [ "atsamx7x-hal", "cortex-m", "cortex-m-rtic", + "embedded-storage", "heapless", "panic-halt", "panic-rtt-target", @@ -52,7 +53,9 @@ dependencies = [ "cfg-if", "cortex-m", "embedded-hal", + "embedded-storage", "fugit", + "mcan-core", "nb 1.0.0", "paste", "rtic-monotonic", @@ -194,6 +197,12 @@ dependencies = [ "void", ] +[[package]] +name = "embedded-storage" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "156d7a2fdd98ebbf9ae579cbceca3058cff946e13f8e17b90e3511db0508c723" + [[package]] name = "fugit" version = "0.3.6" @@ -272,6 +281,15 @@ dependencies = [ "scopeguard", ] +[[package]] +name = "mcan-core" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b3dee4ff5269e2465cc856d37103cce916c1ef73b4377f006c963872e69f7ca" +dependencies = [ + "fugit", +] + [[package]] name = "memchr" version = "2.5.0" diff --git a/boards/atsame70_xpro/Cargo.toml b/boards/atsame70_xpro/Cargo.toml index ad85e4d3..e5024aed 100644 --- a/boards/atsame70_xpro/Cargo.toml +++ b/boards/atsame70_xpro/Cargo.toml @@ -15,6 +15,7 @@ panic-rtt-target = { version = "0.1.2", features = ["cortex-m"] } rtt-target = { version = "0.3.1", features = ["cortex-m"] } usbd-serial = "0.1.1" heapless = "0.7" +embedded-storage = "0.3" [dependencies.atsamx7x-hal] version = "0.4.2" diff --git a/boards/atsame70_xpro/examples/efc.rs b/boards/atsame70_xpro/examples/efc.rs new file mode 100644 index 00000000..03973ed3 --- /dev/null +++ b/boards/atsame70_xpro/examples/efc.rs @@ -0,0 +1,64 @@ +//! Test that system io pins behave as expected +#![no_std] +#![no_main] + +use panic_rtt_target as _; + +#[rtic::app(device = hal::pac, peripherals = true, dispatchers = [UART0])] +mod app { + use atsamx7x_hal as hal; + use embedded_storage::nor_flash::NorFlash; + use embedded_storage::nor_flash::ReadNorFlash; + use hal::efc::*; + use rtt_target::{rprintln, rtt_init_print}; + + #[shared] + struct Shared {} + + #[local] + struct Local {} + + #[init] + fn init(ctx: init::Context) -> (Shared, Local, init::Monotonics) { + rtt_init_print!(); + let efc = ctx.device.EFC; + rprintln!("0x{:x}", efc.eefc_fsr.read().bits()); + rprintln!("0x{:x}", efc.eefc_fmr.read().bits()); + let mut efc = Efc::new(efc, VddioLevel::V3); + let wdt = ctx.device.WDT; + wdt.mr.modify(|_, w| w.wddis().set_bit()); + let mut a: [u8; 4] = [0; 4]; + for i in 0..32768 { + efc.read(i * 4, &mut a).unwrap(); + let a_int: u32 = u32::from_be_bytes(a); + rprintln!("Word 0x{:x}: 0x{:x}", i, a_int); + } + + let array: [u8; 512] = [0xad; 512]; + for _j in 0..10 { + efc.write(SECTOR_SIZE as u32 * 8, &array).unwrap(); + efc.write(SECTOR_SIZE as u32 * 8 + PAGE_SIZE as u32, &array) + .unwrap(); + efc.write(SECTOR_SIZE as u32 * 8 + 2 * PAGE_SIZE as u32, &array) + .unwrap(); + efc.write(SECTOR_SIZE as u32 * 8 + 3 * PAGE_SIZE as u32, &array) + .unwrap(); + for i in 8..12 { + efc.read(SECTOR_SIZE as u32 * 8 + i * 4, &mut a).unwrap(); + let a_int: u32 = u32::from_be_bytes(a); + rprintln!("Word 0x{:x}: 0x{:x}", i, a_int); + } + rprintln!("Erasing Flash Sector..."); + efc.erase(SECTOR_SIZE as u32 * 8, SECTOR_SIZE as u32 * 9) + .unwrap(); + rprintln!("Flash Sector Erased"); + for i in 8..12 { + efc.read(SECTOR_SIZE as u32 * 8 + i * 4, &mut a).unwrap(); + let a_int: u32 = u32::from_be_bytes(a); + rprintln!("Word 0x{:x}: 0x{:x}", i, a_int); + } + } + + (Shared {}, Local {}, init::Monotonics()) + } +} diff --git a/boards/atsamv71_xult/Cargo.lock b/boards/atsamv71_xult/Cargo.lock index 48971694..f087fa71 100644 --- a/boards/atsamv71_xult/Cargo.lock +++ b/boards/atsamv71_xult/Cargo.lock @@ -26,10 +26,13 @@ version = "0.4.2" dependencies = [ "atsamx7x-hal", "cortex-m", + "cortex-m-rt", "cortex-m-rtic", "dwt-systick-monotonic", + "embedded-storage", "heapless", "mcan", + "panic-halt", "panic-rtt-target", "rtt-target", "typenum", @@ -54,6 +57,7 @@ dependencies = [ "cfg-if", "cortex-m", "embedded-hal", + "embedded-storage", "fugit", "mcan-core", "nb 1.0.0", @@ -224,6 +228,12 @@ dependencies = [ "void", ] +[[package]] +name = "embedded-storage" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "156d7a2fdd98ebbf9ae579cbceca3058cff946e13f8e17b90e3511db0508c723" + [[package]] name = "fugit" version = "0.3.6" @@ -357,6 +367,12 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "546c37ac5d9e56f55e73b677106873d9d9f5190605e41a856503623648488cae" +[[package]] +name = "panic-halt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de96540e0ebde571dc55c73d60ef407c653844e6f9a1e2fdbd40c07b9252d812" + [[package]] name = "panic-rtt-target" version = "0.1.2" diff --git a/boards/atsamv71_xult/Cargo.toml b/boards/atsamv71_xult/Cargo.toml index 5bc456ea..101b1b4f 100644 --- a/boards/atsamv71_xult/Cargo.toml +++ b/boards/atsamv71_xult/Cargo.toml @@ -10,11 +10,14 @@ license = "MIT OR Apache-2.0" [dependencies] cortex-m-rtic = "1.0" cortex-m = "0.7" +cortex-m-rt = "*" panic-rtt-target = { version = "0.1.2", features = ["cortex-m"] } +panic-halt = "*" rtt-target = { version = "0.3.1", features = ["cortex-m"] } heapless = "0.7" usbd-serial = "0.1.1" dwt-systick-monotonic = "1.0.0" +embedded-storage = "0.3" [dev-dependencies] mcan = "0.2" diff --git a/boards/atsamv71_xult/examples/bootloader.rs b/boards/atsamv71_xult/examples/bootloader.rs new file mode 100644 index 00000000..1d824e30 --- /dev/null +++ b/boards/atsamv71_xult/examples/bootloader.rs @@ -0,0 +1,169 @@ +#![no_std] +#![no_main] +use atsamx7x_hal as hal; +use cortex_m::asm::bootload; +use cortex_m_rt::entry; +use embedded_storage::nor_flash::NorFlash; +use hal::efc::*; +use hal::pac; +use panic_halt as _; + +#[entry] +fn main() -> ! { + const BLINKY_ARRAY: [u32; 1024] = [ + 0x20440000, 0x420169, 0x4204e1, 0x4209f3, 0x4204e1, 0x4204e1, 0x4204e1, 0x0, 0x0, 0x0, 0x0, + 0x4204e1, 0x4204e1, 0x0, 0x4204e1, 0x4204e1, 0x4204e1, 0x4204e1, 0x4204e1, 0x4204e1, + 0x4204e1, 0x4204e1, 0x4204e1, 0x4204e1, 0x4204e1, 0x0, 0x4204e1, 0x4204e1, 0x4204e1, + 0x4204e1, 0x4204e1, 0x4204e1, 0x4204e1, 0x4204e1, 0x4204e1, 0x4204e1, 0x4204e1, 0x4204e1, + 0x4204e1, 0x4204e1, 0x4204e1, 0x4204e1, 0x4204e1, 0x4204e1, 0x4204e1, 0x4204e1, 0x4204e1, + 0x4204e1, 0x4204e1, 0x4204e1, 0x4204e1, 0x4204e1, 0x4204e1, 0x4204e1, 0x4204e1, 0x4204e1, + 0x4204e1, 0x4204e1, 0x4204e1, 0x4204e1, 0x4204e1, 0x4204e1, 0x4204e1, 0x4204e1, 0x4204e1, + 0x4204e1, 0x4204e1, 0x4204e1, 0x4204e1, 0x4204e1, 0x0, 0x0, 0x4204e1, 0x4204e1, 0x4204e1, + 0x4204e1, 0x4204e1, 0x4204e1, 0x4204e1, 0x4204e1, 0x4204e1, 0x4204e1, 0x4204e1, 0x4204e1, + 0x4204e1, 0x4204e1, 0x4204e1, 0x4204e1, 0x4204e1, 0x4204e1, 0x34fff04f, 0xf00046a6, + 0x46a6f9b8, 0x490f480e, 0x42812200, 0xc004d001, 0x480de7fb, 0x4a0e490d, 0xd0024281, + 0xc008ca08, 0x480ce7fa, 0x170f44f, 0x430a6802, 0xf3bf6002, 0xf3bf8f4f, 0xb5008f6f, + 0xf866f000, 0xde00, 0x20400000, 0x20400440, 0x20400000, 0x20400000, 0x420a48, 0xe000ed88, + 0xbabff000, 0x466fb580, 0x2005b084, 0x4a30f240, 0xf6409001, 0xf2c02016, 0xf2c20042, + 0x90000a40, 0x4f8da, 0x8f5ff3bf, 0x4669b158, 0x21009103, 0x1008f88d, 0x5115f240, + 0xa8026802, 0x142f2c0, 0xf6404790, 0xf6406530, 0xf2c4281b, 0xf641050e, 0x68a83400, + 0xf2404629, 0xf10d5915, 0xf44f0b08, 0xf2c00600, 0xdc00842, 0x4b7f2c0, 0x182f360, 0x942f2c0, + 0xe008600e, 0x20068a8, 0xbf484628, 0x60063004, 0xf0004620, 0x2005fa80, 0x8000e9cd, 0x4f8da, + 0x8f5ff3bf, 0xd0ed2800, 0x91034669, 0xf88d2100, 0x46491008, 0x46586802, 0xe7e34790, + 0x466fb580, 0xffa4f7ff, 0xf803f000, 0xffa2f7ff, 0xb5f0defe, 0xe92daf03, 0xb0840b00, + 0x4400f240, 0x4930f240, 0x440f2c2, 0x940f2c2, 0x801f04f, 0x21304620, 0x8000f889, + 0xfb9df000, 0x2008f640, 0xf2c04626, 0xf2400042, 0xf8460200, 0xf44f0f18, 0x62206080, + 0x240f2c2, 0xf3bf6ae0, 0xf3bf8f5f, 0x25008f5f, 0x3f020, 0xf64062e0, 0xf3bf2020, 0xf2c08f5f, + 0x61e20042, 0x68007901, 0x8010f8c4, 0xf6406020, 0xf2c02028, 0x71210042, 0xe9d06165, + 0xf3bf1200, 0x68808f5f, 0xe9c460e0, 0xf0001201, 0x4604fa22, 0xfa15f000, 0xf88907e0, + 0xf8c9500c, 0xbf086008, 0xfa0ff000, 0x2034f640, 0x8f5ff3bf, 0x42f2c0, 0x4f8c9, 0xf3bf2005, + 0x90018f5f, 0x2011f640, 0x42f2c0, 0xf8d99000, 0xf3bf0004, 0xb1588f5f, 0x91034669, + 0xf88d2100, 0xf2401008, 0x68025115, 0xf2c0a802, 0x47900142, 0x10f641, 0x4100f44f, 0xef2c4, + 0x21086441, 0x5100f2ca, 0xf2406001, 0xf2c46068, 0xf64f000e, 0xf85071ff, 0xf6cf2c48, + 0xf1016100, 0x401313ff, 0x7201f64f, 0x237f2c0, 0xf8404313, 0x68033c48, 0xd10907db, + 0x7db6803, 0x6803bf04, 0x73c3ea5f, 0x6803d102, 0xd0f207db, 0x3c48f850, 0x12fff102, + 0x43114019, 0x1c48f840, 0x3c96801, 0x6801d409, 0xbf5c03c9, 0xea5f6801, 0xd40231c1, + 0x3c96801, 0xf640d5f2, 0xf24441e4, 0xf2c43300, 0xf2c4010e, 0x680a5346, 0x2fef002, + 0x600a431a, 0x2598f8d0, 0xf4222301, 0xf8c06270, 0xf8502598, 0xf3632c38, 0xf8400201, + 0x68022c38, 0xd4090712, 0x7126802, 0x6802bf5c, 0x7202ea5f, 0x6802d402, 0xd5f20712, + 0x2c38f850, 0x270f022, 0x2c38f840, 0x7126802, 0x6802d409, 0xbf5c0712, 0xea5f6802, + 0xd4027202, 0x7126802, 0xf850d5f2, 0xf4222c38, 0xf8407240, 0x68022c38, 0xd4090712, + 0x7126802, 0x6802bf5c, 0x7202ea5f, 0x6802d402, 0xd5f20712, 0x6280f44f, 0x2c58f840, + 0x2c50f850, 0xd40c0552, 0x2c50f850, 0xbf5c0552, 0x2c50f850, 0x5242ea5f, 0xf850d403, + 0x5522c50, 0x2000d5ee, 0x1a8f8c1, 0xf44f, 0x11cf8c1, 0x170f8c1, 0x12cf8c1, 0x14cf8c1, + 0xf93bf000, 0xe8bdb004, 0xbdf00b00, 0x4770e7fe, 0xaf03b5f0, 0xbd04f84d, 0x4605460c, + 0xf935f000, 0xf0004606, 0x4628f928, 0x7f047a0, 0xf85dd105, 0xe8bdbb04, 0xf00040f0, + 0xf85db920, 0xbdf0bb04, 0xaf03b5f0, 0xf00e92d, 0xf240b085, 0x78034230, 0x240f2c2, + 0x68e66894, 0x8f5ff3bf, 0xf3bf6925, 0x68a18f5f, 0xbf38428e, 0xd30a428d, 0xf3bf2600, + 0x60e68f5f, 0x8f5ff3bf, 0x8f5ff3bf, 0xf3bf6126, 0x7b118f5f, 0xc00f04f, 0x42999303, + 0x2200d101, 0x9001e075, 0x10ff003, 0xf6406890, 0xf2c02238, 0xf1a70242, 0x5c51091e, + 0x802f04f, 0xf3bf6940, 0xf8078f5f, 0x21ff1c1d, 0x3f000, 0x1c1ef807, 0xbf181ec1, 0xf1b14601, + 0xbf180b01, 0x43f0468b, 0xf3bf68e3, 0x69228f5f, 0x8f5ff3bf, 0x42ab68a5, 0x42aabf38, + 0xf3bfd30e, 0xf8c48f5f, 0xf3bfc00c, 0xf3bf8f5f, 0xf8c48f5f, 0xf3bfc010, 0x68a58f5f, + 0xe0074405, 0xd90142b2, 0xe0031815, 0xbf142a00, 0x44051bad, 0xbf884545, 0xb97d4645, + 0xf02f1bb, 0xf3bfd105, 0x60e68f5f, 0x8f5ff3bf, 0xf1bbe7d0, 0xd01c0f00, 0xf04f2001, + 0xe0010a00, 0x46aa2000, 0x68609002, 0x46524649, 0xf0004430, 0x68a0f8a1, 0xf04f4456, + 0x42860c00, 0x4666bf28, 0xf0002d00, 0x9a028088, 0xebb844d1, 0xd1b0080a, 0x2202e000, + 0x4030f240, 0xf2c29903, 0x73010040, 0x68409801, 0xb500e9d0, 0xf0006960, 0xf1b00003, + 0xbf180a03, 0x2a004682, 0x8f5ff3bf, 0x2d00d156, 0xf04fd054, 0xea6f0e00, 0x68e30c06, + 0x8f5ff3bf, 0xf3bf6922, 0x68a08f5f, 0xbf384283, 0xd30f4282, 0x8f5ff3bf, 0xe00cf8c4, + 0x8f5ff3bf, 0x8f5ff3bf, 0xe010f8c4, 0x8f5ff3bf, 0xeb0068a0, 0xe00a090c, 0xd90242b2, + 0x90ceb02, 0x2a00e005, 0xeba0bf14, 0xeb000906, 0x45a9090c, 0x46a9bf88, 0xf00f1b9, + 0xf1bad10e, 0xd1050f02, 0x8f5ff3bf, 0xf3bf60e6, 0xe7ca8f5f, 0xf00f1ba, 0xf04fd01a, + 0xe0000800, 0x686046c8, 0x46424659, 0xf0004430, 0x68a0f833, 0xf04f4446, 0x42860e00, + 0x4676bf28, 0xf00f1b9, 0x44c3bf1c, 0x508ebb5, 0xe00bd1ad, 0xd1092a02, 0x4030f240, + 0xf2c29903, 0x73010040, 0xe8bdb005, 0xbdf00f00, 0x8f5ff3bf, 0xf3bf60e6, 0xb0058f5f, + 0xf00e8bd, 0x9a02bdf0, 0xb672e77c, 0xb6624770, 0x21014770, 0x50eb01, 0xd1fd3801, + 0xf3ef4770, 0x47708010, 0xb800f000, 0xb84ef000, 0x4611460b, 0xf000461a, 0xb5d0b8ed, + 0x4613af02, 0x2904b2d2, 0x414d339, 0xe04f1a1, 0x6303ea44, 0xea432401, 0xeb042302, + 0x4413049e, 0x403f014, 0x4684d00a, 0xf84c2c01, 0xd10d3b04, 0x46714660, 0xf0cf1be, + 0xe002d219, 0xf0cf1be, 0x4660d215, 0x40d0e8bd, 0xbfd4f7ff, 0x60432c02, 0x3908d106, + 0x46843008, 0xf0cf1be, 0xe7f0d207, 0x390c6083, 0x4684300c, 0xf0cf1be, 0x3910d3e9, + 0x3300e9c0, 0x3302e9c0, 0x29033010, 0x4684d8f7, 0xe8bd4660, 0xf7ff40d0, 0x2200bfb5, + 0xbfb7f7ff, 0xaf03b5f0, 0x700e92d, 0xd9632a0f, 0xf0134243, 0xeb000403, 0xd0160c04, + 0x460e4603, 0xf8037835, 0x45635b01, 0x7875d20f, 0x5b01f803, 0xbf3e4563, 0xf80378b5, + 0x45635b01, 0x78f5d205, 0xf8033604, 0x45635b01, 0xeba2d3ea, 0xeb010e04, 0xf02e0904, + 0xeb0c0803, 0xea5f0308, 0xd03e7189, 0xf01f1b8, 0x2118db54, 0xac9ea01, 0x103f029, 0x6c9ea4f, + 0x508f101, 0x4271680a, 0x618f001, 0x1c04f855, 0xf20afa22, 0xf406fa01, 0xf84c4322, + 0x459c2b04, 0x682ad23c, 0xf10afa21, 0xf406fa02, 0xf84c4321, 0x459c1b04, 0x6869bf3f, + 0xf20afa22, 0xf406fa01, 0xbf3c4322, 0x2b04f84c, 0xd227459c, 0xfa2168aa, 0x3510f10a, + 0xf406fa02, 0xf84c4321, 0x459c1b04, 0xe01bd3d4, 0xb9f24603, 0xf1b8e033, 0xdb150f01, + 0x6821464c, 0x1b04f84c, 0xd20f459c, 0xf84c6861, 0x459c1b04, 0x68a1bf3e, 0x1b04f84c, + 0xd205459c, 0x341068e1, 0x1b04f84c, 0xd3ea459c, 0x108eb09, 0x203f00e, 0x441ab1aa, + 0xf803780e, 0x42936b01, 0x784ed20f, 0x6b01f803, 0xbf3e4293, 0xf803788e, 0x42936b01, + 0x78ced205, 0xf8033104, 0x42936b01, 0xe8bdd3ea, 0xbdf00700, 0xaf02b5d0, 0xd9362a0f, + 0xf0134243, 0xeb000e03, 0xd0100c0e, 0xf8034603, 0x45631b01, 0xf803d20b, 0x45631b01, + 0xf803bf3c, 0x45631b01, 0xf803d203, 0x45631b01, 0xeba2d3ef, 0xf02e0e0e, 0xeb0c0203, + 0x2a010302, 0xb2cadb13, 0x3401f04f, 0xf84c4362, 0x459c2b04, 0xf84cd20b, 0x459c2b04, + 0xf84cbf3c, 0x459c2b04, 0xf84cd203, 0x459c2b04, 0xf00ed3ef, 0xb9120203, 0x4603e012, + 0x441ab182, 0x1b01f803, 0xd20b4293, 0x1b01f803, 0xbf3c4293, 0x1b01f803, 0xd2034293, + 0x1b01f803, 0xd3ef4293, 0xf7ffbdd0, 0x4670bf08, 0x42082104, 0xf3efd102, 0xe0028008, + 0x8009f3ef, 0xe7fee7ff, 0x6d726554, 0x6c616e69, 0x696e4900, 0x64490a74, 0x4c0a656c, + 0xa706f6f, 0x47474553, 0x5f, 0x52205245, 0x5454, 0x0, 0x4204e5, 0x33323130, 0x37363534, + 0x42413938, 0x46454443, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + ]; + // transmute into u8 array + let blinky_array: [u8; 4096] = unsafe { core::mem::transmute(BLINKY_ARRAY) }; + let efc = pac::Peripherals::take().unwrap().EFC; + let mut efc = Efc::new(efc, VddioLevel::V3); + + efc.erase(SECTOR_SIZE as u32, 2 * SECTOR_SIZE as u32) + .unwrap(); + efc.write(SECTOR_SIZE as u32, &blinky_array).unwrap(); + + unsafe { + bootload(0x0420000 as *const u32); + } +} diff --git a/boards/atsamv71_xult/examples/efc.rs b/boards/atsamv71_xult/examples/efc.rs new file mode 100644 index 00000000..03973ed3 --- /dev/null +++ b/boards/atsamv71_xult/examples/efc.rs @@ -0,0 +1,64 @@ +//! Test that system io pins behave as expected +#![no_std] +#![no_main] + +use panic_rtt_target as _; + +#[rtic::app(device = hal::pac, peripherals = true, dispatchers = [UART0])] +mod app { + use atsamx7x_hal as hal; + use embedded_storage::nor_flash::NorFlash; + use embedded_storage::nor_flash::ReadNorFlash; + use hal::efc::*; + use rtt_target::{rprintln, rtt_init_print}; + + #[shared] + struct Shared {} + + #[local] + struct Local {} + + #[init] + fn init(ctx: init::Context) -> (Shared, Local, init::Monotonics) { + rtt_init_print!(); + let efc = ctx.device.EFC; + rprintln!("0x{:x}", efc.eefc_fsr.read().bits()); + rprintln!("0x{:x}", efc.eefc_fmr.read().bits()); + let mut efc = Efc::new(efc, VddioLevel::V3); + let wdt = ctx.device.WDT; + wdt.mr.modify(|_, w| w.wddis().set_bit()); + let mut a: [u8; 4] = [0; 4]; + for i in 0..32768 { + efc.read(i * 4, &mut a).unwrap(); + let a_int: u32 = u32::from_be_bytes(a); + rprintln!("Word 0x{:x}: 0x{:x}", i, a_int); + } + + let array: [u8; 512] = [0xad; 512]; + for _j in 0..10 { + efc.write(SECTOR_SIZE as u32 * 8, &array).unwrap(); + efc.write(SECTOR_SIZE as u32 * 8 + PAGE_SIZE as u32, &array) + .unwrap(); + efc.write(SECTOR_SIZE as u32 * 8 + 2 * PAGE_SIZE as u32, &array) + .unwrap(); + efc.write(SECTOR_SIZE as u32 * 8 + 3 * PAGE_SIZE as u32, &array) + .unwrap(); + for i in 8..12 { + efc.read(SECTOR_SIZE as u32 * 8 + i * 4, &mut a).unwrap(); + let a_int: u32 = u32::from_be_bytes(a); + rprintln!("Word 0x{:x}: 0x{:x}", i, a_int); + } + rprintln!("Erasing Flash Sector..."); + efc.erase(SECTOR_SIZE as u32 * 8, SECTOR_SIZE as u32 * 9) + .unwrap(); + rprintln!("Flash Sector Erased"); + for i in 8..12 { + efc.read(SECTOR_SIZE as u32 * 8 + i * 4, &mut a).unwrap(); + let a_int: u32 = u32::from_be_bytes(a); + rprintln!("Word 0x{:x}: 0x{:x}", i, a_int); + } + } + + (Shared {}, Local {}, init::Monotonics()) + } +} diff --git a/hal/Cargo.toml b/hal/Cargo.toml index 0a76e123..b4a10604 100644 --- a/hal/Cargo.toml +++ b/hal/Cargo.toml @@ -39,6 +39,7 @@ void = { version = "1", default-features = false } strum = { version = "0.24.1", default-features = false, features = ["derive"]} cfg-if = "1" mcan-core = { version = "0.2", optional = true } +embedded-storage = "0.3" atsame70j19b = { version = "0.25.0", path = "../pac/atsame70j19b", optional = true } atsame70j20b = { version = "0.25.0", path = "../pac/atsame70j20b", optional = true } diff --git a/hal/src/efc.rs b/hal/src/efc.rs index 74341cd4..048d4bef 100644 --- a/hal/src/efc.rs +++ b/hal/src/efc.rs @@ -1,7 +1,45 @@ -//! Flash controller configuration +/*! +Flash controller configuration +--- + +The Enhanced Embedded Flash Controller peripheral (EFC) or (EEFC) provides the interface of the Flash block with the 32-bit internal bus. +Two functions of the EFC are exposed in this HAL, the ability to set wait states, and the ability to reconfigure the flash memory. +The wait states need to be reconfigured to allow for correct operation at higher clock frequencies and is normally handled by the [clocks](crate::clocks) module. + +The flash memory can be modified using the commands in Table 22-1. +Out of these commands only the Write Page and Erase Sector commands are currently supported by the HAL. +Write Page writes a page of 512 bytes, Erase Sector erases a sector a sector of 128KB. + +That is, your writes need to be 512 byte aligned, because pages are 512 byte aligned, and your erases need to be 128KB aligned, because sectors are 128KB aligned. +# Example usage + +```no_run +# use atsamx7x_hal as hal; +use embedded_storage::nor_flash::NorFlash; +use embedded_storage::nor_flash::ReadNorFlash; +# use hal::efc::*; +# let pac = hal::pac::Peripherals::take().unwrap(); + +let mut efc = Efc::new(pac.EFC, VddioLevel::V3); + +let mut a: [u8; 128] = [0; 128]; +// Read the first 128 bytes from the flash memory +efc.read(0, &mut a).unwrap(); + +let b: [u8; 512] = [0x00; 512]; +// Write 0x00 to the first page of the second sector +efc.write(SECTOR_SIZE, &b).unwrap(); + +// erase the third sector +efc.erase(2*SECTOR_SIZE, SECTOR_SIZE*3).unwrap(); + +``` +*/ use crate::clocks::{ClockError, Megahertz}; -use crate::pac::EFC; +use crate::pac::{efc, EFC}; +use core::slice; +use embedded_storage::nor_flash::*; /// The voltage which drives the MCU. /// @@ -14,6 +52,244 @@ pub enum VddioLevel { V1, } +/// The Base Address of the Flash Memory. +pub const BASE_ADDRESS: u32 = 0x00400000; +///The Capacity in bytes of the Flash Memory. +#[cfg(feature = "flash-2M")] +pub const CAPACITY: u32 = 0x00200000; +///The Capacity in bytes of the Flash Memory. +#[cfg(feature = "flash-1M")] +pub const CAPACITY: u32 = 0x00100000; +///The Capacity in bytes of the Flash Memory. +#[cfg(feature = "flash-512K")] +pub const CAPACITY: u32 = 0x00080000; +/// The Size in bytes of a page in the Flash Memory. +pub const PAGE_SIZE: u32 = 512; +/// The Size in bytes of a sector in the Flash Memory. +pub const SECTOR_SIZE: u32 = 0x00020000; + +/// An iterator over the Flash Sectors. +struct SectorIterator { + start_offset: u32, + end_offset: u32, +} + +/// A struct representing a Sector in Flash Memory. +#[derive(Clone, Copy)] +struct Sector { + offset: u32, +} + +impl Iterator for SectorIterator { + type Item = Sector; + + fn next(&mut self) -> Option { + if self.start_offset >= self.end_offset { + return None; + } + let sector = Sector { + offset: self.start_offset, + }; + self.start_offset += SECTOR_SIZE; + + Some(sector) + } +} + +/// A struct representing a Page in Flash memory +#[derive(Clone, Copy)] +struct Page { + offset: u32, +} + +/// An iterator over the Flash Pages. +struct PageIterator { + start_offset: u32, + end_offset: u32, +} + +impl Iterator for PageIterator { + type Item = Page; + + fn next(&mut self) -> Option { + if self.start_offset >= self.end_offset { + return None; + } + let page = Page { + offset: self.start_offset, + }; + self.start_offset += PAGE_SIZE; + + Some(page) + } +} + +/// Flash Memory Read/Write/Erase Errors. +#[derive(Debug, Copy, Clone)] +pub enum Error { + /// The arguments are not properly aligned. + NotAligned, + /// The arguments are out of bounds. + OutOfBounds, + /// Attempted to execute a command when eefc is busy + FlashBusyError, + /// An invalid Command and/or a bad keyword was/were written in EEFC_FMR + FlashCommandError, + /// Programming/erase of at least one locked region has happened. + FlashLockError, + /// A Flash memory error occured at the end of programming (EraseVerify or WriteVerify + /// test has failed). + FlashError, + /// MultiError MSB + MultipleEccErrorMsb, + /// MultiEccErrorLsb + MultipleEccErrorLsb, + /// UniqueError MSB + UniqueEccErrorMsb, + /// UniqueEccErrorLsb + UniqueEccErrorLsb, + /// OtherError + OtherError, +} + +impl NorFlashError for Error { + fn kind(&self) -> NorFlashErrorKind { + match self { + Error::NotAligned => NorFlashErrorKind::NotAligned, + Error::OutOfBounds => NorFlashErrorKind::OutOfBounds, + _ => NorFlashErrorKind::Other, + } + } +} + +impl From for Error { + fn from(x: u32) -> Error { + if x & 0x00000002 != 0 { + Error::FlashCommandError + } else if x & 0x00000004 != 0 { + Error::FlashLockError + } else if x & 0x00000008 != 0 { + Error::FlashError + } else if x & 0x00010000 != 0 { + Error::UniqueEccErrorLsb + } else if x & 0x00020000 != 0 { + Error::MultipleEccErrorLsb + } else if x & 0x00040000 != 0 { + Error::UniqueEccErrorMsb + } else if x & 0x00080000 != 0 { + Error::MultipleEccErrorMsb + } else { + panic!("Unknown Error") + } + } +} + +impl From for Error { + fn from(e: NorFlashErrorKind) -> Error { + match e { + NorFlashErrorKind::NotAligned => Error::NotAligned, + NorFlashErrorKind::OutOfBounds => Error::OutOfBounds, + _ => Error::OtherError, + } + } +} + +impl Sector { + /// Erase the entire sector. + fn erase_sector(&self) -> Result<(), Error> { + if self.efc().eefc_fsr.read().frdy().bit_is_clear() { + return Err(Error::FlashBusyError); + } + self.efc().eefc_fcr.write(|w| { + w.fkey().passwd(); + w.fcmd().es(); + unsafe { w.farg().bits(self.page_number()) }; + w + }); + loop { + let status = self.efc().eefc_fsr.read(); + // Wait until frdy is set + if status.bits() == 0x00000001 { + return Ok(()); + } + // If an error is detected, return + else if status.bits() != 0x00000000 { + return Err(status.bits().into()); + } + } + } + + // #[inline(always)] fn addr(&self) -> *mut u8 { + // (BASE_ADDRESS + self.offset) as *mut u8 + // } + + #[inline(always)] + fn page_number(&self) -> u16 { + (self.offset / PAGE_SIZE) as u16 + } + + // #[inline(always)] + // fn contains(&self, offset: u32) -> bool { + // offset >= self.offset + // && offset < self.offset + SECTOR_SIZE + // } +} + +impl Page { + /// Write page to flash memory. + fn write_page(&self, data: &[u8]) -> Result<(), Error> { + if data.len() != PAGE_SIZE as usize { + return Err(Error::NotAligned); + } + if self.efc().eefc_fsr.read().frdy().bit_is_clear() { + return Err(Error::FlashBusyError); + } + unsafe { self.addr().copy_from(data.as_ptr(), PAGE_SIZE as usize) }; + + self.efc().eefc_fcr.write(|w| { + w.fkey().passwd(); + w.fcmd().wp(); + unsafe { w.farg().bits(self.page_number()) }; + w + }); + loop { + let status = self.efc().eefc_fsr.read(); + // Wait until frdy is set + if status.bits() == 0x00000001 { + return Ok(()); + } + // If an error is detected, return + else if status.bits() != 0x00000000 { + return Err(status.bits().into()); + } + } + } + + #[inline(always)] + fn addr(&self) -> *mut u8 { + (BASE_ADDRESS + self.offset) as *mut u8 + } + + #[inline(always)] + fn page_number(&self) -> u16 { + (self.offset / PAGE_SIZE) as u16 + } + + // #[inline(always)] + // fn contains(&self, offset: u32) -> bool { + // offset >= self.offset + // && offset < self.offset + PAGE_SIZE as u32 + // } +} + +trait RegisterAccess { + fn efc(&self) -> &efc::RegisterBlock { + unsafe { &*EFC::ptr() } + } +} + +impl RegisterAccess for Sector {} +impl RegisterAccess for Page {} /// [`EFC`] abstraction. pub struct Efc { pub(crate) periph: EFC, @@ -49,6 +325,85 @@ impl Efc { } } +trait Flash { + type SectorIterator; + type PageIterator; + + fn len(&self) -> u32 { + CAPACITY + } + + fn address(&self) -> u32 { + BASE_ADDRESS + } + + fn sectors(start_offset: u32, end_offset: u32) -> SectorIterator { + SectorIterator { + start_offset, + end_offset, + } + } + + fn pages(start_offset: u32, end_offset: u32) -> PageIterator { + PageIterator { + start_offset, + end_offset, + } + } +} + +impl Flash for Efc { + type SectorIterator = SectorIterator; + type PageIterator = PageIterator; +} + +impl ErrorType for Efc { + type Error = Error; +} + +impl ReadNorFlash for Efc { + const READ_SIZE: usize = 1; + + fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> { + check_read(self, offset, bytes.len())?; + let offset = offset as usize; + let ptr = self.address() as *const _; + let capacity = self.capacity(); + let flash_slice = unsafe { slice::from_raw_parts(ptr, capacity) }; + bytes.copy_from_slice(&flash_slice[offset..offset + bytes.len()]); + Ok(()) + } + + fn capacity(&self) -> usize { + self.len() as usize + } +} + +impl NorFlash for Efc { + const WRITE_SIZE: usize = PAGE_SIZE as usize; + // NOTE: This number is the sector size, there is an option to erase by page as well, but the + // minimum/maximum erase size for that varies throughout the flash memory. + const ERASE_SIZE: usize = SECTOR_SIZE as usize; + + fn erase(&mut self, offset: u32, to: u32) -> Result<(), Self::Error> { + check_erase(self, offset, to)?; + for sector in Self::sectors(offset, to) { + sector.erase_sector()?; + } + Ok(()) + } + + fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> { + check_write(self, offset, bytes.len())?; + let mut bytes_written = 0; + for page in Self::pages(offset, offset + bytes.len() as u32) { + page.write_page(&bytes[bytes_written..(bytes_written + Self::WRITE_SIZE)])?; + bytes_written += Self::WRITE_SIZE; + } + Ok(()) + } +} + /// The number of flash wait states for a read operation. /// /// Note: The number of cycles a read takes is 1 + FWS.