diff --git a/esp-alloc/src/macros.rs b/esp-alloc/src/macros.rs index 2454ec2fa..e7d44227b 100644 --- a/esp-alloc/src/macros.rs +++ b/esp-alloc/src/macros.rs @@ -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, diff --git a/esp-hal/CHANGELOG.md b/esp-hal/CHANGELOG.md index a0e6f2ad2..881da60a1 100644 --- a/esp-hal/CHANGELOG.md +++ b/esp-hal/CHANGELOG.md @@ -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 diff --git a/esp-hal/MIGRATING-0.22.md b/esp-hal/MIGRATING-0.22.md index 8c18db3f4..671618ac1 100644 --- a/esp-hal/MIGRATING-0.22.md +++ b/esp-hal/MIGRATING-0.22.md @@ -125,3 +125,22 @@ Timer group timers have been type erased. - timg::Timer, 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. diff --git a/esp-hal/src/lib.rs b/esp-hal/src/lib.rs index ea2e91275..0d73e7dcf 100644 --- a/esp-hal/src/lib.rs +++ b/esp-hal/src/lib.rs @@ -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 } diff --git a/esp-hal/src/soc/esp32/psram.rs b/esp-hal/src/soc/esp32/psram.rs index 7843d1cc1..9b7049f02 100644 --- a/esp-hal/src/soc/esp32/psram.rs +++ b/esp-hal/src/soc/esp32/psram.rs @@ -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 { diff --git a/esp-hal/src/soc/esp32s2/psram.rs b/esp-hal/src/soc/esp32s2/psram.rs index f83262965..28983db68 100644 --- a/esp-hal/src/soc/esp32s2/psram.rs +++ b/esp-hal/src/soc/esp32s2/psram.rs @@ -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 diff --git a/esp-hal/src/soc/esp32s3/psram.rs b/esp-hal/src/soc/esp32s3/psram.rs index ced3d7570..0ece9af20 100644 --- a/esp-hal/src/soc/esp32s3/psram.rs +++ b/esp-hal/src/soc/esp32s3/psram.rs @@ -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")] diff --git a/esp-hal/src/soc/mod.rs b/esp-hal/src/soc/mod.rs index 600b6629b..7be7c1ae2 100644 --- a/esp-hal/src/soc/mod.rs +++ b/esp-hal/src/soc/mod.rs @@ -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 = 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 { +fn psram_range_internal() -> Range { 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 { const DRAM: Range = 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, + memory_range: Range, } // Indicates the state of setting the mac address @@ -108,12 +112,12 @@ pub(crate) fn is_slice_in_dram(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(slice: &[T]) -> bool { - slice_in_range(slice, psram_range()) + slice_in_range(slice, psram_range_internal()) } #[allow(unused)] diff --git a/esp-hal/src/soc/psram_common.rs b/esp-hal/src/soc/psram_common.rs index a598f86b2..eb114067f 100644 --- a/esp-hal/src/soc/psram_common.rs +++ b/esp-hal/src/soc/psram_common.rs @@ -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 { + 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) +} diff --git a/examples/src/bin/dma_extmem2mem.rs b/examples/src/bin/dma_extmem2mem.rs index 4fab1087c..bf249d9b1 100644 --- a/examples/src/bin/dma_extmem2mem.rs +++ b/examples/src/bin/dma_extmem2mem.rs @@ -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); diff --git a/examples/src/bin/psram_octal.rs b/examples/src/bin/psram_octal.rs index 3f2bc7e25..14419d201 100644 --- a/examples/src/bin/psram_octal.rs +++ b/examples/src/bin/psram_octal.rs @@ -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"); diff --git a/examples/src/bin/psram_quad.rs b/examples/src/bin/psram_quad.rs index 75222b7ef..6eb9a3db4 100644 --- a/examples/src/bin/psram_quad.rs +++ b/examples/src/bin/psram_quad.rs @@ -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");