Auto-initialize PSRAM (#2546)

This commit is contained in:
Dániel Buga 2024-11-23 15:10:44 +01:00 committed by GitHub
parent 09511c750a
commit fe482bdd05
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 83 additions and 37 deletions

View File

@ -29,9 +29,9 @@ macro_rules! heap_allocator {
/// ```
#[macro_export]
macro_rules! psram_allocator {
($peripheral:expr,$psram_module:path) => {{
($peripheral:expr, $psram_module:path) => {{
use $psram_module as _psram;
let (start, size) = _psram::init_psram($peripheral, _psram::PsramConfig::default());
let (start, size) = _psram::psram_raw_parts(&$peripheral);
unsafe {
$crate::HEAP.add_region($crate::HeapRegion::new(
start,

View File

@ -17,6 +17,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- `dma::{Channel, ChannelRx, ChannelTx}::set_priority` for GDMA devices (#2403)
- `esp_hal::asynch::AtomicWaker` that does not hold a global critical section (#2555)
- `esp_hal::sync::RawMutex` for embassy-sync. (#2555)
- ESP32-C6, H2, S3: Added `split` function to the `DmaChannel` trait. (#2526)
- Added PSRAM configuration to `esp_hal::Config` if `quad-psram` or `octal-psram` is enabled (#2546)
- Added `esp_hal::psram::psram_raw_parts` (#2546)
### Changed
@ -31,6 +34,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- `dma::{Channel, ChannelRx, ChannelTx}::set_priority` for GDMA devices (#2403)
- `SystemTimer`s `Alarm`s are now type erased (#2576)
- `TimerGroup` `Timer`s are now type erased (#2581)
- PSRAM is now initialized automatically if `quad-psram` or `octal-psram` is enabled (#2546)
### Fixed
@ -40,6 +44,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- The DMA channel objects no longer have `tx` and `rx` fields. (#2526)
- `SysTimerAlarms` has been removed, alarms are now part of the `SystemTimer` struct (#2576)
- `FrozenUnit`, `AnyUnit`, `SpecificUnit`, `SpecificComparator`, `AnyComparator` have been removed from `systimer` (#2576)
- `esp_hal::psram::psram_range` (#2546)
## [0.22.0] - 2024-11-20

View File

@ -125,3 +125,22 @@ Timer group timers have been type erased.
- timg::Timer<timg::Timer0<crate::peripherals::TIMG0>, Blocking>
+ timg::Timer
```
## PSRAM is now initialized automatically
Calling `esp_hal::initialize` will now configure PSRAM if either the `quad-psram` or `octal-psram`
is enabled. To retrieve the address and size of the initialized external memory, use
`esp_hal::psram::psram_raw_parts`, which returns a pointer and a length.
```diff
-let peripherals = esp_hal::init(esp_hal::Config::default());
-let (start, size) = esp_hal::psram::init_psram(peripherals.PSRAM, psram_config);
+let peripherals = esp_hal::init({
+ let mut config = esp_hal::Config::default();
+ config.psram = psram_config;
+ config
+});
+let (start, size) = esp_hal::psram::psram_raw_parts(&peripherals.PSRAM, psram);
```
The usage of `esp_alloc::psram_allocator!` remains unchanged.

View File

@ -508,8 +508,13 @@ use crate::{
pub struct Config {
/// The CPU clock configuration.
pub cpu_clock: CpuClock,
/// Enable watchdog timer(s).
pub watchdog: WatchdogConfig,
/// PSRAM configuration.
#[cfg(any(feature = "quad-psram", feature = "octal-psram"))]
pub psram: psram::PsramConfig,
}
/// Initialize the system.
@ -572,5 +577,8 @@ pub fn init(config: Config) -> Peripherals {
crate::gpio::bind_default_interrupt_handler();
#[cfg(any(feature = "quad-psram", feature = "octal-psram"))]
crate::psram::init_psram(config.psram);
peripherals
}

View File

@ -38,7 +38,7 @@ pub struct PsramConfig {
/// Initializes the PSRAM memory on supported devices.
///
/// Returns the start of the mapped memory and the size
pub fn init_psram(_peripheral: crate::peripherals::PSRAM, config: PsramConfig) -> (*mut u8, usize) {
pub(crate) fn init_psram(config: PsramConfig) {
let mut config = config;
utils::psram_init(&config);
@ -86,11 +86,9 @@ pub fn init_psram(_peripheral: crate::peripherals::PSRAM, config: PsramConfig) -
utils::s_mapping(EXTMEM_ORIGIN as u32, config.size.get() as u32);
}
crate::soc::MAPPED_PSRAM.with(|mapped_psram| {
mapped_psram.memory_range = EXTMEM_ORIGIN..EXTMEM_ORIGIN + config.size.get();
});
(EXTMEM_ORIGIN as *mut u8, config.size.get())
unsafe {
crate::soc::MAPPED_PSRAM.memory_range = EXTMEM_ORIGIN..EXTMEM_ORIGIN + config.size.get();
}
}
pub(crate) mod utils {

View File

@ -41,7 +41,7 @@ pub struct PsramConfig {
///
/// Returns the start of the mapped memory and the size
#[procmacros::ram]
pub fn init_psram(_peripheral: crate::peripherals::PSRAM, config: PsramConfig) -> (*mut u8, usize) {
pub(crate) fn init_psram(config: PsramConfig) {
let mut config = config;
utils::psram_init(&mut config);
@ -65,7 +65,7 @@ pub fn init_psram(_peripheral: crate::peripherals::PSRAM, config: PsramConfig) -
///
/// [`sram0_layout`]: u32 the usage of first 8KB internal memory block,
/// can be CACHE_MEMORY_INVALID,
/// CACHE_MEMORY_ICACHE_LOW,
/// CACHE_MEMORY_ICACHE_LOW,
/// CACHE_MEMORY_ICACHE_HIGH, CACHE_MEMORY_DCACHE_LOW and
/// CACHE_MEMORY_DCACHE_HIGH
/// [`sram1_layout`]: the usage of second 8KB internal memory block,
@ -141,11 +141,9 @@ pub fn init_psram(_peripheral: crate::peripherals::PSRAM, config: PsramConfig) -
});
}
crate::soc::MAPPED_PSRAM.with(|mapped_psram| {
mapped_psram.memory_range = EXTMEM_ORIGIN..EXTMEM_ORIGIN + config.size.get();
});
(EXTMEM_ORIGIN as *mut u8, config.size.get())
unsafe {
crate::soc::MAPPED_PSRAM.memory_range = EXTMEM_ORIGIN..EXTMEM_ORIGIN + config.size.get();
}
}
pub(crate) mod utils {
@ -366,6 +364,7 @@ pub(crate) mod utils {
miso_bit_len: u32,
) {
#[repr(C)]
#[allow(non_camel_case_types)]
struct esp_rom_spi_cmd_t {
cmd: u16, // Command value
cmd_bit_len: u16, // Command byte length

View File

@ -70,7 +70,7 @@ pub struct PsramConfig {
///
/// Returns the start of the mapped memory and the size
#[procmacros::ram]
pub fn init_psram(_peripheral: crate::peripherals::PSRAM, config: PsramConfig) -> (*mut u8, usize) {
pub(crate) fn init_psram(config: PsramConfig) {
let mut config = config;
utils::psram_init(&mut config);
@ -179,11 +179,9 @@ pub fn init_psram(_peripheral: crate::peripherals::PSRAM, config: PsramConfig) -
start
};
crate::soc::MAPPED_PSRAM.with(|mapped_psram| {
mapped_psram.memory_range = start as usize..start as usize + config.size.get();
});
(start as *mut u8, config.size.get())
unsafe {
crate::soc::MAPPED_PSRAM.memory_range = start as usize..start as usize + config.size.get();
}
}
#[cfg(feature = "quad-psram")]

View File

@ -3,8 +3,6 @@ use core::ops::Range;
use portable_atomic::{AtomicU8, Ordering};
pub use self::implementation::*;
#[cfg(psram)]
use crate::sync::Locked;
#[cfg_attr(esp32, path = "esp32/mod.rs")]
#[cfg_attr(esp32c2, path = "esp32c2/mod.rs")]
@ -20,13 +18,19 @@ mod efuse_field;
#[cfg(any(feature = "quad-psram", feature = "octal-psram"))]
mod psram_common;
#[cfg(psram)]
static MAPPED_PSRAM: Locked<MappedPsram> = Locked::new(MappedPsram { memory_range: 0..0 });
// Using static mut should be fine since we are only writing to it once during
// initialization. As other tasks and interrupts are not running yet, the worst
// that can happen is, that the user creates a DMA buffer before initializing
// the HAL. This will access the PSRAM range, returning an empty range - which
// is, at that point, true. The user has no (safe) means to allocate in PSRAM
// before initializing the HAL.
#[cfg(any(feature = "quad-psram", feature = "octal-psram"))]
static mut MAPPED_PSRAM: MappedPsram = MappedPsram { memory_range: 0..0 };
fn psram_range() -> Range<usize> {
fn psram_range_internal() -> Range<usize> {
cfg_if::cfg_if! {
if #[cfg(psram)] {
MAPPED_PSRAM.with(|mapped_psram| mapped_psram.memory_range.clone())
if #[cfg(any(feature = "quad-psram", feature = "octal-psram"))] {
unsafe { MAPPED_PSRAM.memory_range.clone() }
} else {
0..0
}
@ -35,9 +39,9 @@ fn psram_range() -> Range<usize> {
const DRAM: Range<usize> = self::constants::SOC_DRAM_LOW..self::constants::SOC_DRAM_HIGH;
#[cfg(psram)]
#[cfg(any(feature = "quad-psram", feature = "octal-psram"))]
pub struct MappedPsram {
memory_range: core::ops::Range<usize>,
memory_range: Range<usize>,
}
// Indicates the state of setting the mac address
@ -108,12 +112,12 @@ pub(crate) fn is_slice_in_dram<T>(slice: &[T]) -> bool {
#[allow(unused)]
pub(crate) fn is_valid_psram_address(address: usize) -> bool {
addr_in_range(address, psram_range())
addr_in_range(address, psram_range_internal())
}
#[allow(unused)]
pub(crate) fn is_slice_in_psram<T>(slice: &[T]) -> bool {
slice_in_range(slice, psram_range())
slice_in_range(slice, psram_range_internal())
}
#[allow(unused)]

View File

@ -1,3 +1,5 @@
use core::ops::Range;
/// Size of PSRAM
///
/// [PsramSize::AutoDetect] will try to detect the size of PSRAM
@ -23,3 +25,16 @@ impl PsramSize {
matches!(self, PsramSize::AutoDetect)
}
}
/// Returns the address range available in external memory.
#[cfg(any(feature = "quad-psram", feature = "octal-psram"))]
pub(crate) fn psram_range(_psram: &crate::peripherals::PSRAM) -> Range<usize> {
unsafe { super::MAPPED_PSRAM.memory_range.clone() }
}
/// Returns the address and size of the available in external memory.
#[cfg(any(feature = "quad-psram", feature = "octal-psram"))]
pub fn psram_raw_parts(psram: &crate::peripherals::PSRAM) -> (*mut u8, usize) {
let range = psram_range(psram);
(range.start as *mut u8, range.end - range.start)
}

View File

@ -42,8 +42,8 @@ macro_rules! dma_alloc_buffer {
}};
}
fn init_heap(psram: esp_hal::peripherals::PSRAM) {
let (start, size) = esp_hal::psram::init_psram(psram, esp_hal::psram::PsramConfig::default());
fn init_heap(psram: &esp_hal::peripherals::PSRAM) {
let (start, size) = esp_hal::psram::psram_raw_parts(psram);
info!("init_heap: start: {:p}", start);
unsafe {
esp_alloc::HEAP.add_region(esp_alloc::HeapRegion::new(
@ -59,8 +59,8 @@ fn main() -> ! {
esp_println::logger::init_logger(log::LevelFilter::Info);
let peripherals = esp_hal::init(esp_hal::Config::default());
init_heap(&peripherals.PSRAM);
init_heap(peripherals.PSRAM);
let delay = Delay::new();
let mut extram_buffer: &mut [u8] = dma_alloc_buffer!(DATA_SIZE, 64);

View File

@ -35,7 +35,7 @@ fn main() -> ! {
esp_println::logger::init_logger_from_env();
let peripherals = esp_hal::init(esp_hal::Config::default());
let (start, size) = psram::init_psram(peripherals.PSRAM, psram::PsramConfig::default());
let (start, size) = psram::psram_raw_parts(&peripherals.PSRAM);
init_psram_heap(start, size);
println!("Going to access PSRAM");

View File

@ -35,7 +35,7 @@ fn main() -> ! {
esp_println::logger::init_logger_from_env();
let peripherals = esp_hal::init(esp_hal::Config::default());
let (start, size) = psram::init_psram(peripherals.PSRAM, psram::PsramConfig::default());
let (start, size) = psram::psram_raw_parts(&peripherals.PSRAM);
init_psram_heap(start, size);
println!("Going to access PSRAM");