commit
79b982c941
@ -41,6 +41,11 @@ boot2-ram-memcpy = []
|
|||||||
boot2-w25q080 = []
|
boot2-w25q080 = []
|
||||||
boot2-w25x10cl = []
|
boot2-w25x10cl = []
|
||||||
|
|
||||||
|
# Indicate code is running from RAM.
|
||||||
|
# Set this if all code is in RAM, and the cores never access memory-mapped flash memory through XIP.
|
||||||
|
# This allows the flash driver to not force pausing execution on both cores when doing flash operations.
|
||||||
|
run-from-ram = []
|
||||||
|
|
||||||
# Enable nightly-only features
|
# Enable nightly-only features
|
||||||
nightly = ["embassy-executor/nightly", "embedded-hal-1", "embedded-hal-async", "embassy-embedded-hal/nightly", "dep:embassy-usb-driver", "dep:embedded-io"]
|
nightly = ["embassy-executor/nightly", "embedded-hal-1", "embedded-hal-async", "embassy-embedded-hal/nightly", "dep:embassy-usb-driver", "dep:embedded-io"]
|
||||||
|
|
||||||
|
@ -75,16 +75,17 @@ pub unsafe fn write<'a, C: Channel, W: Word>(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static DUMMY: u32 = 0;
|
||||||
|
|
||||||
pub unsafe fn write_repeated<'a, C: Channel, W: Word>(
|
pub unsafe fn write_repeated<'a, C: Channel, W: Word>(
|
||||||
ch: impl Peripheral<P = C> + 'a,
|
ch: impl Peripheral<P = C> + 'a,
|
||||||
to: *mut W,
|
to: *mut W,
|
||||||
len: usize,
|
len: usize,
|
||||||
dreq: u8,
|
dreq: u8,
|
||||||
) -> Transfer<'a, C> {
|
) -> Transfer<'a, C> {
|
||||||
let dummy: u32 = 0;
|
|
||||||
copy_inner(
|
copy_inner(
|
||||||
ch,
|
ch,
|
||||||
&dummy as *const u32,
|
&DUMMY as *const u32,
|
||||||
to as *mut u32,
|
to as *mut u32,
|
||||||
len,
|
len,
|
||||||
W::size(),
|
W::size(),
|
||||||
|
@ -9,7 +9,11 @@ use embedded_storage::nor_flash::{
|
|||||||
use crate::pac;
|
use crate::pac;
|
||||||
use crate::peripherals::FLASH;
|
use crate::peripherals::FLASH;
|
||||||
|
|
||||||
pub const FLASH_BASE: usize = 0x10000000;
|
pub const FLASH_BASE: *const u32 = 0x10000000 as _;
|
||||||
|
|
||||||
|
// If running from RAM, we might have no boot2. Use bootrom `flash_enter_cmd_xip` instead.
|
||||||
|
// TODO: when run-from-ram is set, completely skip the "pause cores and jumpp to RAM" dance.
|
||||||
|
pub const USE_BOOT2: bool = !cfg!(feature = "run-from-ram");
|
||||||
|
|
||||||
// **NOTE**:
|
// **NOTE**:
|
||||||
//
|
//
|
||||||
@ -63,8 +67,8 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Flash<'d, T, FLASH_SIZE> {
|
|||||||
pub fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> {
|
pub fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> {
|
||||||
trace!(
|
trace!(
|
||||||
"Reading from 0x{:x} to 0x{:x}",
|
"Reading from 0x{:x} to 0x{:x}",
|
||||||
FLASH_BASE + offset as usize,
|
FLASH_BASE as u32 + offset,
|
||||||
FLASH_BASE + offset as usize + bytes.len()
|
FLASH_BASE as u32 + offset + bytes.len() as u32
|
||||||
);
|
);
|
||||||
check_read(self, offset, bytes.len())?;
|
check_read(self, offset, bytes.len())?;
|
||||||
|
|
||||||
@ -89,7 +93,7 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Flash<'d, T, FLASH_SIZE> {
|
|||||||
|
|
||||||
let len = to - from;
|
let len = to - from;
|
||||||
|
|
||||||
unsafe { self.in_ram(|| ram_helpers::flash_range_erase(from, len, true))? };
|
unsafe { self.in_ram(|| ram_helpers::flash_range_erase(from, len))? };
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -114,7 +118,7 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Flash<'d, T, FLASH_SIZE> {
|
|||||||
|
|
||||||
let unaligned_offset = offset as usize - start;
|
let unaligned_offset = offset as usize - start;
|
||||||
|
|
||||||
unsafe { self.in_ram(|| ram_helpers::flash_range_program(unaligned_offset as u32, &pad_buf, true))? }
|
unsafe { self.in_ram(|| ram_helpers::flash_range_program(unaligned_offset as u32, &pad_buf))? }
|
||||||
}
|
}
|
||||||
|
|
||||||
let remaining_len = bytes.len() - start_padding;
|
let remaining_len = bytes.len() - start_padding;
|
||||||
@ -132,12 +136,12 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Flash<'d, T, FLASH_SIZE> {
|
|||||||
if bytes.as_ptr() as usize >= 0x2000_0000 {
|
if bytes.as_ptr() as usize >= 0x2000_0000 {
|
||||||
let aligned_data = &bytes[start_padding..end_padding];
|
let aligned_data = &bytes[start_padding..end_padding];
|
||||||
|
|
||||||
unsafe { self.in_ram(|| ram_helpers::flash_range_program(aligned_offset as u32, aligned_data, true))? }
|
unsafe { self.in_ram(|| ram_helpers::flash_range_program(aligned_offset as u32, aligned_data))? }
|
||||||
} else {
|
} else {
|
||||||
for chunk in bytes[start_padding..end_padding].chunks_exact(PAGE_SIZE) {
|
for chunk in bytes[start_padding..end_padding].chunks_exact(PAGE_SIZE) {
|
||||||
let mut ram_buf = [0xFF_u8; PAGE_SIZE];
|
let mut ram_buf = [0xFF_u8; PAGE_SIZE];
|
||||||
ram_buf.copy_from_slice(chunk);
|
ram_buf.copy_from_slice(chunk);
|
||||||
unsafe { self.in_ram(|| ram_helpers::flash_range_program(aligned_offset as u32, &ram_buf, true))? }
|
unsafe { self.in_ram(|| ram_helpers::flash_range_program(aligned_offset as u32, &ram_buf))? }
|
||||||
aligned_offset += PAGE_SIZE;
|
aligned_offset += PAGE_SIZE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -152,7 +156,7 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Flash<'d, T, FLASH_SIZE> {
|
|||||||
|
|
||||||
let unaligned_offset = end_offset - (PAGE_SIZE - rem_offset);
|
let unaligned_offset = end_offset - (PAGE_SIZE - rem_offset);
|
||||||
|
|
||||||
unsafe { self.in_ram(|| ram_helpers::flash_range_program(unaligned_offset as u32, &pad_buf, true))? }
|
unsafe { self.in_ram(|| ram_helpers::flash_range_program(unaligned_offset as u32, &pad_buf))? }
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -190,7 +194,7 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Flash<'d, T, FLASH_SIZE> {
|
|||||||
|
|
||||||
/// Read SPI flash unique ID
|
/// Read SPI flash unique ID
|
||||||
pub fn unique_id(&mut self, uid: &mut [u8]) -> Result<(), Error> {
|
pub fn unique_id(&mut self, uid: &mut [u8]) -> Result<(), Error> {
|
||||||
unsafe { self.in_ram(|| ram_helpers::flash_unique_id(uid, true))? };
|
unsafe { self.in_ram(|| ram_helpers::flash_unique_id(uid))? };
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -199,7 +203,7 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Flash<'d, T, FLASH_SIZE> {
|
|||||||
let mut jedec = None;
|
let mut jedec = None;
|
||||||
unsafe {
|
unsafe {
|
||||||
self.in_ram(|| {
|
self.in_ram(|| {
|
||||||
jedec.replace(ram_helpers::flash_jedec_id(true));
|
jedec.replace(ram_helpers::flash_jedec_id());
|
||||||
})?;
|
})?;
|
||||||
};
|
};
|
||||||
Ok(jedec.unwrap())
|
Ok(jedec.unwrap())
|
||||||
@ -242,6 +246,7 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> NorFlash for Flash<'d, T, FLASH_S
|
|||||||
mod ram_helpers {
|
mod ram_helpers {
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
use crate::rom_data;
|
use crate::rom_data;
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
@ -306,7 +311,7 @@ mod ram_helpers {
|
|||||||
///
|
///
|
||||||
/// `addr` and `len` must be multiples of 4096
|
/// `addr` and `len` must be multiples of 4096
|
||||||
///
|
///
|
||||||
/// If `use_boot2` is `true`, a copy of the 2nd stage boot loader
|
/// If `USE_BOOT2` is `true`, a copy of the 2nd stage boot loader
|
||||||
/// is used to re-initialize the XIP engine after flashing.
|
/// is used to re-initialize the XIP engine after flashing.
|
||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
@ -318,10 +323,10 @@ mod ram_helpers {
|
|||||||
/// - DMA must not access flash memory
|
/// - DMA must not access flash memory
|
||||||
///
|
///
|
||||||
/// `addr` and `len` parameters must be valid and are not checked.
|
/// `addr` and `len` parameters must be valid and are not checked.
|
||||||
pub unsafe fn flash_range_erase(addr: u32, len: u32, use_boot2: bool) {
|
pub unsafe fn flash_range_erase(addr: u32, len: u32) {
|
||||||
let mut boot2 = [0u32; 256 / 4];
|
let mut boot2 = [0u32; 256 / 4];
|
||||||
let ptrs = if use_boot2 {
|
let ptrs = if USE_BOOT2 {
|
||||||
rom_data::memcpy44(&mut boot2 as *mut _, super::FLASH_BASE as *const _, 256);
|
rom_data::memcpy44(&mut boot2 as *mut _, FLASH_BASE, 256);
|
||||||
flash_function_pointers_with_boot2(true, false, &boot2)
|
flash_function_pointers_with_boot2(true, false, &boot2)
|
||||||
} else {
|
} else {
|
||||||
flash_function_pointers(true, false)
|
flash_function_pointers(true, false)
|
||||||
@ -336,7 +341,7 @@ mod ram_helpers {
|
|||||||
///
|
///
|
||||||
/// `addr` and `data.len()` must be multiples of 4096
|
/// `addr` and `data.len()` must be multiples of 4096
|
||||||
///
|
///
|
||||||
/// If `use_boot2` is `true`, a copy of the 2nd stage boot loader
|
/// If `USE_BOOT2` is `true`, a copy of the 2nd stage boot loader
|
||||||
/// is used to re-initialize the XIP engine after flashing.
|
/// is used to re-initialize the XIP engine after flashing.
|
||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
@ -348,10 +353,10 @@ mod ram_helpers {
|
|||||||
/// - DMA must not access flash memory
|
/// - DMA must not access flash memory
|
||||||
///
|
///
|
||||||
/// `addr` and `len` parameters must be valid and are not checked.
|
/// `addr` and `len` parameters must be valid and are not checked.
|
||||||
pub unsafe fn flash_range_erase_and_program(addr: u32, data: &[u8], use_boot2: bool) {
|
pub unsafe fn flash_range_erase_and_program(addr: u32, data: &[u8]) {
|
||||||
let mut boot2 = [0u32; 256 / 4];
|
let mut boot2 = [0u32; 256 / 4];
|
||||||
let ptrs = if use_boot2 {
|
let ptrs = if USE_BOOT2 {
|
||||||
rom_data::memcpy44(&mut boot2 as *mut _, super::FLASH_BASE as *const _, 256);
|
rom_data::memcpy44(&mut boot2 as *mut _, FLASH_BASE, 256);
|
||||||
flash_function_pointers_with_boot2(true, true, &boot2)
|
flash_function_pointers_with_boot2(true, true, &boot2)
|
||||||
} else {
|
} else {
|
||||||
flash_function_pointers(true, true)
|
flash_function_pointers(true, true)
|
||||||
@ -371,7 +376,7 @@ mod ram_helpers {
|
|||||||
///
|
///
|
||||||
/// `addr` and `data.len()` must be multiples of 256
|
/// `addr` and `data.len()` must be multiples of 256
|
||||||
///
|
///
|
||||||
/// If `use_boot2` is `true`, a copy of the 2nd stage boot loader
|
/// If `USE_BOOT2` is `true`, a copy of the 2nd stage boot loader
|
||||||
/// is used to re-initialize the XIP engine after flashing.
|
/// is used to re-initialize the XIP engine after flashing.
|
||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
@ -383,10 +388,10 @@ mod ram_helpers {
|
|||||||
/// - DMA must not access flash memory
|
/// - DMA must not access flash memory
|
||||||
///
|
///
|
||||||
/// `addr` and `len` parameters must be valid and are not checked.
|
/// `addr` and `len` parameters must be valid and are not checked.
|
||||||
pub unsafe fn flash_range_program(addr: u32, data: &[u8], use_boot2: bool) {
|
pub unsafe fn flash_range_program(addr: u32, data: &[u8]) {
|
||||||
let mut boot2 = [0u32; 256 / 4];
|
let mut boot2 = [0u32; 256 / 4];
|
||||||
let ptrs = if use_boot2 {
|
let ptrs = if USE_BOOT2 {
|
||||||
rom_data::memcpy44(&mut boot2 as *mut _, super::FLASH_BASE as *const _, 256);
|
rom_data::memcpy44(&mut boot2 as *mut _, FLASH_BASE, 256);
|
||||||
flash_function_pointers_with_boot2(false, true, &boot2)
|
flash_function_pointers_with_boot2(false, true, &boot2)
|
||||||
} else {
|
} else {
|
||||||
flash_function_pointers(false, true)
|
flash_function_pointers(false, true)
|
||||||
@ -508,10 +513,10 @@ mod ram_helpers {
|
|||||||
/// - DMA must not access flash memory
|
/// - DMA must not access flash memory
|
||||||
///
|
///
|
||||||
/// Credit: taken from `rp2040-flash` (also licensed Apache+MIT)
|
/// Credit: taken from `rp2040-flash` (also licensed Apache+MIT)
|
||||||
pub unsafe fn flash_unique_id(out: &mut [u8], use_boot2: bool) {
|
pub unsafe fn flash_unique_id(out: &mut [u8]) {
|
||||||
let mut boot2 = [0u32; 256 / 4];
|
let mut boot2 = [0u32; 256 / 4];
|
||||||
let ptrs = if use_boot2 {
|
let ptrs = if USE_BOOT2 {
|
||||||
rom_data::memcpy44(&mut boot2 as *mut _, 0x10000000 as *const _, 256);
|
rom_data::memcpy44(&mut boot2 as *mut _, FLASH_BASE, 256);
|
||||||
flash_function_pointers_with_boot2(false, false, &boot2)
|
flash_function_pointers_with_boot2(false, false, &boot2)
|
||||||
} else {
|
} else {
|
||||||
flash_function_pointers(false, false)
|
flash_function_pointers(false, false)
|
||||||
@ -536,10 +541,10 @@ mod ram_helpers {
|
|||||||
/// - DMA must not access flash memory
|
/// - DMA must not access flash memory
|
||||||
///
|
///
|
||||||
/// Credit: taken from `rp2040-flash` (also licensed Apache+MIT)
|
/// Credit: taken from `rp2040-flash` (also licensed Apache+MIT)
|
||||||
pub unsafe fn flash_jedec_id(use_boot2: bool) -> u32 {
|
pub unsafe fn flash_jedec_id() -> u32 {
|
||||||
let mut boot2 = [0u32; 256 / 4];
|
let mut boot2 = [0u32; 256 / 4];
|
||||||
let ptrs = if use_boot2 {
|
let ptrs = if USE_BOOT2 {
|
||||||
rom_data::memcpy44(&mut boot2 as *mut _, 0x10000000 as *const _, 256);
|
rom_data::memcpy44(&mut boot2 as *mut _, FLASH_BASE, 256);
|
||||||
flash_function_pointers_with_boot2(false, false, &boot2)
|
flash_function_pointers_with_boot2(false, false, &boot2)
|
||||||
} else {
|
} else {
|
||||||
flash_function_pointers(false, false)
|
flash_function_pointers(false, false)
|
||||||
@ -586,7 +591,6 @@ mod ram_helpers {
|
|||||||
"ldr r4, [r5, #4]",
|
"ldr r4, [r5, #4]",
|
||||||
"blx r4", // flash_exit_xip()
|
"blx r4", // flash_exit_xip()
|
||||||
|
|
||||||
"mov r7, r10", // cmd
|
|
||||||
|
|
||||||
"movs r4, #0x18",
|
"movs r4, #0x18",
|
||||||
"lsls r4, r4, #24", // 0x18000000, SSI, RP2040 datasheet 4.10.13
|
"lsls r4, r4, #24", // 0x18000000, SSI, RP2040 datasheet 4.10.13
|
||||||
@ -603,8 +607,9 @@ mod ram_helpers {
|
|||||||
"str r1, [r4, #0]",
|
"str r1, [r4, #0]",
|
||||||
|
|
||||||
// Write ctrlr1 with len-1
|
// Write ctrlr1 with len-1
|
||||||
"ldr r0, [r7, #8]", // dummy_len
|
"mov r3, r10", // cmd
|
||||||
"ldr r1, [r7, #16]", // data_len
|
"ldr r0, [r3, #8]", // dummy_len
|
||||||
|
"ldr r1, [r3, #16]", // data_len
|
||||||
"add r0, r1",
|
"add r0, r1",
|
||||||
"subs r0, #1",
|
"subs r0, #1",
|
||||||
"str r0, [r4, #0x04]", // CTRLR1
|
"str r0, [r4, #0x04]", // CTRLR1
|
||||||
@ -616,8 +621,8 @@ mod ram_helpers {
|
|||||||
// Write cmd/addr phase to DR
|
// Write cmd/addr phase to DR
|
||||||
"mov r2, r4",
|
"mov r2, r4",
|
||||||
"adds r2, 0x60", // &DR
|
"adds r2, 0x60", // &DR
|
||||||
"ldr r0, [r7, #0]", // cmd_addr
|
"ldr r0, [r3, #0]", // cmd_addr
|
||||||
"ldr r1, [r7, #4]", // cmd_addr_len
|
"ldr r1, [r3, #4]", // cmd_addr_len
|
||||||
"10:",
|
"10:",
|
||||||
"ldrb r3, [r0]",
|
"ldrb r3, [r0]",
|
||||||
"strb r3, [r2]", // DR
|
"strb r3, [r2]", // DR
|
||||||
@ -626,7 +631,8 @@ mod ram_helpers {
|
|||||||
"bne 10b",
|
"bne 10b",
|
||||||
|
|
||||||
// Skip any dummy cycles
|
// Skip any dummy cycles
|
||||||
"ldr r1, [r7, #8]", // dummy_len
|
"mov r3, r10", // cmd
|
||||||
|
"ldr r1, [r3, #8]", // dummy_len
|
||||||
"cmp r1, #0",
|
"cmp r1, #0",
|
||||||
"beq 9f",
|
"beq 9f",
|
||||||
"4:",
|
"4:",
|
||||||
@ -643,8 +649,9 @@ mod ram_helpers {
|
|||||||
|
|
||||||
// Read RX fifo
|
// Read RX fifo
|
||||||
"9:",
|
"9:",
|
||||||
"ldr r0, [r7, #12]", // data
|
"mov r2, r10", // cmd
|
||||||
"ldr r1, [r7, #16]", // data_len
|
"ldr r0, [r2, #12]", // data
|
||||||
|
"ldr r1, [r2, #16]", // data_len
|
||||||
|
|
||||||
"2:",
|
"2:",
|
||||||
"ldr r3, [r4, #0x28]", // SR
|
"ldr r3, [r4, #0x28]", // SR
|
||||||
@ -678,13 +685,12 @@ mod ram_helpers {
|
|||||||
out("r2") _,
|
out("r2") _,
|
||||||
out("r3") _,
|
out("r3") _,
|
||||||
out("r4") _,
|
out("r4") _,
|
||||||
|
out("r5") _,
|
||||||
// Registers r8-r10 are used to store values
|
// Registers r8-r10 are used to store values
|
||||||
// from r0-r2 in registers not clobbered by
|
// from r0-r2 in registers not clobbered by
|
||||||
// function calls.
|
// function calls.
|
||||||
// The values can't be passed in using r8-r10 directly
|
// The values can't be passed in using r8-r10 directly
|
||||||
// due to https://github.com/rust-lang/rust/issues/99071
|
// due to https://github.com/rust-lang/rust/issues/99071
|
||||||
out("r8") _,
|
|
||||||
out("r9") _,
|
|
||||||
out("r10") _,
|
out("r10") _,
|
||||||
clobber_abi("C"),
|
clobber_abi("C"),
|
||||||
);
|
);
|
||||||
|
@ -10,7 +10,7 @@ teleprobe-meta = "1"
|
|||||||
embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] }
|
embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] }
|
||||||
embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
|
embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
|
||||||
embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt"] }
|
embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt"] }
|
||||||
embassy-rp = { version = "0.1.0", path = "../../embassy-rp", features = ["nightly", "defmt", "unstable-pac", "unstable-traits", "time-driver", "critical-section-impl", "intrinsics", "rom-v2-intrinsics"] }
|
embassy-rp = { version = "0.1.0", path = "../../embassy-rp", features = ["nightly", "defmt", "unstable-pac", "unstable-traits", "time-driver", "critical-section-impl", "intrinsics", "rom-v2-intrinsics", "run-from-ram"] }
|
||||||
embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
|
embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
|
||||||
|
|
||||||
defmt = "0.3.0"
|
defmt = "0.3.0"
|
||||||
|
Loading…
Reference in New Issue
Block a user