Remove most PSRAM features (#2178)
* Make most of PSRAM features into run-time configs * Make CI green again * Make CI green again * Update esp-hal/MIGRATING-0.20.md Co-authored-by: Scott Mabin <scott@mabez.dev> * Use Range * CI * Rebase fixes * Update esp-hal/src/lock.rs Co-authored-by: Scott Mabin <scott@mabez.dev> --------- Co-authored-by: Scott Mabin <scott@mabez.dev>
This commit is contained in:
parent
d4e463b3ff
commit
37fa662fe7
@ -31,11 +31,11 @@ macro_rules! heap_allocator {
|
||||
macro_rules! psram_allocator {
|
||||
($peripheral:expr,$psram_module:path) => {{
|
||||
use $psram_module as _psram;
|
||||
_psram::init_psram($peripheral);
|
||||
let (start, size) = _psram::init_psram($peripheral, _psram::PsramConfig::default());
|
||||
unsafe {
|
||||
$crate::HEAP.add_region($crate::HeapRegion::new(
|
||||
_psram::psram_vaddr_start() as *mut u8,
|
||||
_psram::PSRAM_BYTES,
|
||||
start,
|
||||
size,
|
||||
$crate::MemoryCapability::External.into(),
|
||||
));
|
||||
}
|
||||
|
||||
@ -50,6 +50,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- The `NO_PIN` constant has been removed. (#2133)
|
||||
- MSRV bump to 1.79 (#2156)
|
||||
- Allow handling interrupts while trying to lock critical section on multi-core chips. (#2197)
|
||||
- Removed the PS-RAM related features, replaced by `quad-psram`/`octal-psram`, `init_psram` takes a configuration parameter, it's now possible to auto-detect PS-RAM size (#2178)
|
||||
|
||||
### Fixed
|
||||
|
||||
|
||||
@ -143,24 +143,11 @@ defmt = [
|
||||
]
|
||||
|
||||
#! ### PSRAM Feature Flags
|
||||
## Use externally connected PSRAM (2MB).
|
||||
psram-2m = []
|
||||
## Use externally connected PSRAM (4MB).
|
||||
psram-4m = []
|
||||
## Use externally connected PSRAM (8MB).
|
||||
psram-8m = []
|
||||
## PSRAM 80Mhz frequency support
|
||||
psram-80mhz = []
|
||||
## Use externally connected Quad PSRAM
|
||||
quad-psram = []
|
||||
|
||||
#! ### Octal RAM Feature Flags
|
||||
## Use externally connected Octal RAM (2MB).
|
||||
opsram-2m = []
|
||||
## Use externally connected Octal RAM (4MB).
|
||||
opsram-4m = []
|
||||
## Use externally connected Octal RAM (8MB).
|
||||
opsram-8m = []
|
||||
## Use externally connected Octal RAM (16MB).
|
||||
opsram-16m = []
|
||||
## Use externally connected Octal RAM
|
||||
octal-psram = []
|
||||
|
||||
# This feature is intended for testing; you probably don't want to enable it:
|
||||
ci = ["defmt", "bluetooth"]
|
||||
|
||||
@ -209,3 +209,49 @@ We've replaced some usage of features with [esp-config](https://docs.rs/esp-conf
|
||||
# key in .cargo/config.toml [env] section
|
||||
+ ESP_HAL_PLACE_SPI_DRIVER_IN_RAM=true
|
||||
```
|
||||
|
||||
## PS-RAM
|
||||
|
||||
Initializing PS-RAM now takes a chip specific config and returns start of the mapped memory and the size.
|
||||
|
||||
Example
|
||||
```rust
|
||||
let (start, size) = psram::init_psram(peripherals.PSRAM, psram::PsramConfig::default());
|
||||
```
|
||||
|
||||
If you don't specify the size of PS-RAM via `PsramConfig::size` the size of PS-RAM is derived from the RAM-chip id (or via probing in case of ESP32).
|
||||
|
||||
`psram::psram_vaddr_start()` and `psram::PSRAM_BYTES` are removed.
|
||||
|
||||
The features `psram-Xm` and `opsram-Xm` are removed and replaced by `quad-psram`/`octal-psram`.
|
||||
The feature `psram-80mhz` is removed and replaced by `PsramConfig`
|
||||
|
||||
Diff of the `psram_quad.rs` example
|
||||
```diff
|
||||
-//% FEATURES: psram-2m
|
||||
+//% FEATURES: esp-hal/quad-psram
|
||||
|
||||
...
|
||||
|
||||
-fn init_psram_heap() {
|
||||
+fn init_psram_heap(start: *mut u8, size: usize) {
|
||||
unsafe {
|
||||
esp_alloc::HEAP.add_region(esp_alloc::HeapRegion::new(
|
||||
- psram::psram_vaddr_start() as *mut u8,
|
||||
- psram::PSRAM_BYTES,
|
||||
+ start,
|
||||
+ size,
|
||||
esp_alloc::MemoryCapability::External.into(),
|
||||
));
|
||||
}
|
||||
|
||||
...
|
||||
|
||||
- psram::init_psram(peripherals.PSRAM);
|
||||
- init_psram_heap();
|
||||
+ let (start, size) = psram::init_psram(peripherals.PSRAM, psram::PsramConfig::default());
|
||||
+ init_psram_heap(start, size);
|
||||
|
||||
...
|
||||
|
||||
```
|
||||
|
||||
@ -58,12 +58,14 @@ fn main() -> Result<(), Box<dyn Error>> {
|
||||
let config = Config::for_chip(&chip);
|
||||
|
||||
// Check PSRAM features are only given if the target supports PSRAM:
|
||||
if !config.contains(&String::from("psram"))
|
||||
&& (cfg!(feature = "psram-2m") || cfg!(feature = "psram-4m") || cfg!(feature = "psram-8m"))
|
||||
{
|
||||
if !config.contains(&String::from("psram")) && cfg!(feature = "quad-psram") {
|
||||
panic!("The target does not support PSRAM");
|
||||
}
|
||||
|
||||
if !config.contains(&String::from("octal_psram")) && cfg!(feature = "octal-psram") {
|
||||
panic!("The target does not support Octal PSRAM");
|
||||
}
|
||||
|
||||
// Define all necessary configuration symbols for the configured device:
|
||||
config.define_symbols();
|
||||
|
||||
@ -226,11 +228,7 @@ fn generate_memory_extras() -> Vec<u8> {
|
||||
|
||||
#[cfg(feature = "esp32s2")]
|
||||
fn generate_memory_extras() -> Vec<u8> {
|
||||
let reserved_cache = if cfg!(any(
|
||||
feature = "psram-2m",
|
||||
feature = "psram-4m",
|
||||
feature = "psram-8m"
|
||||
)) {
|
||||
let reserved_cache = if cfg!(feature = "quad-psram") {
|
||||
"0x4000"
|
||||
} else {
|
||||
"0x2000"
|
||||
|
||||
@ -155,7 +155,7 @@ pub use self::soc::efuse;
|
||||
#[cfg(lp_core)]
|
||||
pub use self::soc::lp_core;
|
||||
pub use self::soc::peripherals;
|
||||
#[cfg(psram)]
|
||||
#[cfg(any(feature = "quad-psram", feature = "octal-psram"))]
|
||||
pub use self::soc::psram;
|
||||
#[cfg(ulp_riscv_core)]
|
||||
pub use self::soc::ulp_core;
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
use core::cell::UnsafeCell;
|
||||
|
||||
mod single_core {
|
||||
pub unsafe fn disable_interrupts() -> critical_section::RawRestoreState {
|
||||
cfg_if::cfg_if! {
|
||||
@ -210,6 +212,31 @@ pub(crate) fn lock<T>(lock: &Lock, f: impl FnOnce() -> T) -> T {
|
||||
f()
|
||||
}
|
||||
|
||||
/// Data protected by a [Lock]
|
||||
#[allow(unused)]
|
||||
pub(crate) struct Locked<T> {
|
||||
lock_state: Lock,
|
||||
data: UnsafeCell<T>,
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
impl<T> Locked<T> {
|
||||
/// Create a new instance
|
||||
pub(crate) const fn new(data: T) -> Self {
|
||||
Self {
|
||||
lock_state: Lock::new(),
|
||||
data: UnsafeCell::new(data),
|
||||
}
|
||||
}
|
||||
|
||||
/// Provide exclusive access to the protected data to the given closure
|
||||
pub(crate) fn with<R>(&self, f: impl FnOnce(&mut T) -> R) -> R {
|
||||
lock(&self.lock_state, || f(unsafe { &mut *self.data.get() }))
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<T> Sync for Locked<T> {}
|
||||
|
||||
struct CriticalSection;
|
||||
|
||||
critical_section::set_impl!(CriticalSection);
|
||||
|
||||
@ -13,7 +13,7 @@ pub mod cpu_control;
|
||||
pub mod efuse;
|
||||
pub mod gpio;
|
||||
pub mod peripherals;
|
||||
#[cfg(psram)]
|
||||
#[cfg(feature = "quad-psram")]
|
||||
pub mod psram;
|
||||
pub mod radio_clocks;
|
||||
pub mod trng;
|
||||
|
||||
@ -9,53 +9,98 @@
|
||||
//! present on the `ESP32` chip. `PSRAM` provides additional external memory to
|
||||
//! supplement the internal memory of the `ESP32`, allowing for increased
|
||||
//! storage capacity and improved performance in certain applications.
|
||||
//!
|
||||
//! The `PSRAM` module is accessed through a virtual address, defined as
|
||||
//! `PSRAM_VADDR`. The starting virtual address for the PSRAM module is
|
||||
//! 0x3F800000. The `PSRAM` module size depends on the configuration specified
|
||||
//! during the compilation process. The available `PSRAM` sizes are `2MB`,
|
||||
//! `4MB`, and `8MB`.
|
||||
//!
|
||||
//! NOTE: If you want to use `PSRAM` on `ESP32` or `ESP32-S3`, it'll work only
|
||||
//! in `release` mode.
|
||||
|
||||
/// The starting virtual address of the PSRAM (Pseudo-SRAM) region in memory.
|
||||
pub const PSRAM_VADDR_START: usize = 0x3F800000;
|
||||
pub use crate::soc::psram_common::*;
|
||||
|
||||
/// Retrieves the starting virtual address of the PSRAM (Pseudo-SRAM) region in
|
||||
/// memory.
|
||||
pub fn psram_vaddr_start() -> usize {
|
||||
PSRAM_VADDR_START
|
||||
const EXTMEM_ORIGIN: usize = 0x3F800000;
|
||||
|
||||
/// Cache Speed
|
||||
#[derive(PartialEq, Eq, Clone, Copy, Debug, Default)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
#[allow(missing_docs)]
|
||||
pub enum PsramCacheSpeed {
|
||||
#[default]
|
||||
PsramCacheF80mS40m = 0,
|
||||
PsramCacheF40mS40m,
|
||||
PsramCacheF80mS80m,
|
||||
}
|
||||
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(feature = "psram-2m")] {
|
||||
const PSRAM_SIZE: u32 = 2;
|
||||
} else if #[cfg(feature = "psram-4m")] {
|
||||
const PSRAM_SIZE: u32 = 4;
|
||||
} else if #[cfg(feature = "psram-8m")] {
|
||||
const PSRAM_SIZE: u32 = 8;
|
||||
} else {
|
||||
const PSRAM_SIZE: u32 = 0;
|
||||
}
|
||||
/// PSRAM configuration
|
||||
#[derive(Copy, Clone, Debug, Default)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub struct PsramConfig {
|
||||
/// PSRAM size
|
||||
pub size: PsramSize,
|
||||
/// Cache speed
|
||||
pub cache_speed: PsramCacheSpeed,
|
||||
}
|
||||
|
||||
/// The total size of the PSRAM (Pseudo-SRAM) in bytes.
|
||||
pub const PSRAM_BYTES: usize = PSRAM_SIZE as usize * 1024 * 1024;
|
||||
|
||||
/// Initializes the PSRAM memory on supported devices.
|
||||
#[cfg(any(feature = "psram-2m", feature = "psram-4m", feature = "psram-8m"))]
|
||||
pub fn init_psram(_peripheral: impl crate::peripheral::Peripheral<P = crate::peripherals::PSRAM>) {
|
||||
utils::psram_init();
|
||||
utils::s_mapping(PSRAM_VADDR_START as u32, PSRAM_BYTES as u32);
|
||||
///
|
||||
/// Returns the start of the mapped memory and the size
|
||||
pub fn init_psram(_peripheral: crate::peripherals::PSRAM, config: PsramConfig) -> (*mut u8, usize) {
|
||||
let mut config = config;
|
||||
|
||||
utils::psram_init(&config);
|
||||
|
||||
if config.size.is_auto() {
|
||||
// Reading the device-id turned out to not work as expected (some bits flipped
|
||||
// for unknown reason)
|
||||
//
|
||||
// As a workaround we just map 4m (maximum we can do) and
|
||||
// probe if we can access top of PSRAM - if not we assume it's 2m
|
||||
//
|
||||
// This currently doesn't work as expected because of https://github.com/esp-rs/esp-hal/issues/2182
|
||||
utils::s_mapping(EXTMEM_ORIGIN as u32, 4 * 1024 * 1024);
|
||||
|
||||
let guessed_size = unsafe {
|
||||
let ptr = (EXTMEM_ORIGIN + 4 * 1024 * 1024 - 36 * 1024) as *mut u8;
|
||||
for i in 0..(36 * 1024) {
|
||||
ptr.add(i).write_volatile(0x7f);
|
||||
}
|
||||
|
||||
let ptr = EXTMEM_ORIGIN as *mut u8;
|
||||
for i in 0..(36 * 1024) {
|
||||
ptr.add(i).write_volatile(0x7f);
|
||||
}
|
||||
|
||||
let mut success = true;
|
||||
let ptr = (EXTMEM_ORIGIN + 4 * 1024 * 1024 - 36 * 1024) as *mut u8;
|
||||
for i in 0..(36 * 1024) {
|
||||
if ptr.add(i).read_volatile() != 0x7f {
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if success {
|
||||
4 * 1024 * 1024
|
||||
} else {
|
||||
2 * 1024 * 1024
|
||||
}
|
||||
};
|
||||
|
||||
info!("Assuming {} bytes of PSRAM", guessed_size);
|
||||
config.size = PsramSize::Size(guessed_size);
|
||||
} else {
|
||||
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())
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "psram-2m", feature = "psram-4m", feature = "psram-8m"))]
|
||||
pub(crate) mod utils {
|
||||
use core::ptr::addr_of_mut;
|
||||
|
||||
use procmacros::ram;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[ram]
|
||||
pub(crate) fn s_mapping(v_start: u32, size: u32) {
|
||||
// Enable external RAM in MMU
|
||||
cache_sram_mmu_set(0, 0, v_start, 0, 32, size / 1024 / 32);
|
||||
@ -72,6 +117,7 @@ pub(crate) mod utils {
|
||||
|
||||
// we can use the ROM version of this: it works well enough and keeps the size
|
||||
// of the binary down.
|
||||
#[ram]
|
||||
fn cache_sram_mmu_set(
|
||||
cpu_no: u32,
|
||||
pid: u32,
|
||||
@ -198,15 +244,6 @@ pub(crate) mod utils {
|
||||
(((spi_config) >> shift) & mask) as u8
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
#[allow(unused)]
|
||||
enum PsramCacheSpeed {
|
||||
PsramCacheF80mS40m = 0,
|
||||
PsramCacheF40mS40m,
|
||||
PsramCacheF80mS80m,
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Debug, Default)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
struct PsramIo {
|
||||
@ -228,13 +265,13 @@ pub(crate) mod utils {
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
struct EspRomSpiflashChip {
|
||||
device_id: u32,
|
||||
chip_size: u32, // chip size in bytes
|
||||
block_size: u32,
|
||||
sector_size: u32,
|
||||
page_size: u32,
|
||||
status_mask: u32,
|
||||
pub(super) struct EspRomSpiflashChip {
|
||||
pub device_id: u32,
|
||||
pub chip_size: u32, // chip size in bytes
|
||||
pub block_size: u32,
|
||||
pub sector_size: u32,
|
||||
pub page_size: u32,
|
||||
pub status_mask: u32,
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
@ -253,7 +290,7 @@ pub(crate) mod utils {
|
||||
|
||||
static mut g_rom_spiflash_dummy_len_plus: u8;
|
||||
|
||||
static g_rom_flashchip: EspRomSpiflashChip;
|
||||
pub(super) static g_rom_flashchip: EspRomSpiflashChip;
|
||||
|
||||
fn cache_sram_mmu_set_rom(
|
||||
cpu_no: u32,
|
||||
@ -265,10 +302,11 @@ pub(crate) mod utils {
|
||||
) -> i32;
|
||||
}
|
||||
|
||||
pub(crate) fn psram_init() {
|
||||
#[ram]
|
||||
pub(crate) fn psram_init(config: &PsramConfig) {
|
||||
let chip = crate::efuse::Efuse::get_chip_type();
|
||||
|
||||
let mode = PsramCacheSpeed::PsramCacheF40mS40m; // How to make this configurable
|
||||
let mode = config.cache_speed;
|
||||
let mut psram_io = PsramIo::default();
|
||||
let clk_mode;
|
||||
|
||||
@ -416,6 +454,7 @@ pub(crate) mod utils {
|
||||
}
|
||||
|
||||
let extra_dummy = psram_gpio_config(&psram_io, mode);
|
||||
info!("extra dummy = {}", extra_dummy);
|
||||
|
||||
// psram_is_32mbit_ver0 would need special handling here
|
||||
|
||||
@ -615,6 +654,7 @@ pub(crate) mod utils {
|
||||
}
|
||||
|
||||
// spi param init for psram
|
||||
#[ram]
|
||||
fn psram_spi_init(
|
||||
// psram_spi_num_t spi_num = PSRAM_SPI_1,
|
||||
mode: PsramCacheSpeed,
|
||||
@ -748,7 +788,7 @@ pub(crate) mod utils {
|
||||
ps_cmd.rx_data_bit_len = 0;
|
||||
ps_cmd.dummy_bit_len = 0;
|
||||
let (backup_usr, backup_usr1, backup_usr2) = psram_cmd_config_spi1(&ps_cmd);
|
||||
psram_cmd_recv_start_spi1(core::ptr::null_mut(), PsramCmdMode::PsramCmdSpi);
|
||||
psram_cmd_recv_start_spi1(core::ptr::null_mut(), 0, PsramCmdMode::PsramCmdSpi);
|
||||
psram_cmd_end_spi1(backup_usr, backup_usr1, backup_usr2);
|
||||
}
|
||||
|
||||
@ -870,7 +910,11 @@ pub(crate) mod utils {
|
||||
|
||||
// start sending cmd/addr and optionally, receiving data
|
||||
#[ram]
|
||||
fn psram_cmd_recv_start_spi1(p_rx_data: *mut u32, cmd_mode: PsramCmdMode) {
|
||||
fn psram_cmd_recv_start_spi1(
|
||||
p_rx_data: *mut u32,
|
||||
rx_data_len_words: usize,
|
||||
cmd_mode: PsramCmdMode,
|
||||
) {
|
||||
unsafe {
|
||||
let spi = &*crate::peripherals::SPI1::PTR;
|
||||
// get cs1
|
||||
@ -942,8 +986,8 @@ pub(crate) mod utils {
|
||||
|
||||
if !p_rx_data.is_null() {
|
||||
// Read data out
|
||||
loop {
|
||||
p_rx_data.write_volatile(spi.w(0).read().bits());
|
||||
for i in 0..rx_data_len_words {
|
||||
p_rx_data.add(i).write_volatile(spi.w(i).read().bits());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1191,6 +1235,7 @@ pub(crate) mod utils {
|
||||
|
||||
let flash_id: u32 = g_rom_flashchip.device_id;
|
||||
info!("Flash-ID = {}", flash_id);
|
||||
info!("Flash size = {}", g_rom_flashchip.chip_size);
|
||||
|
||||
if flash_id == FLASH_ID_GD25LQ32C {
|
||||
// Set drive ability for 1.8v flash in 80Mhz.
|
||||
|
||||
@ -16,7 +16,7 @@ use crate::rtc_cntl::SocResetReason;
|
||||
pub mod efuse;
|
||||
pub mod gpio;
|
||||
pub mod peripherals;
|
||||
#[cfg(psram)]
|
||||
#[cfg(feature = "quad-psram")]
|
||||
pub mod psram;
|
||||
pub mod radio_clocks;
|
||||
pub mod trng;
|
||||
|
||||
@ -9,42 +9,42 @@
|
||||
//! present on the `ESP32-S2` chip. `PSRAM` provides additional external memory
|
||||
//! to supplement the internal memory of the `ESP32-S2`, allowing for increased
|
||||
//! storage capacity and improved performance in certain applications.
|
||||
//!
|
||||
//! The `PSRAM` module is accessed through a virtual address, defined as
|
||||
//! `PSRAM_VADDR`. The starting virtual address for the PSRAM module is
|
||||
//! 0x3f500000. The `PSRAM` module size depends on the configuration specified
|
||||
//! during the compilation process. The available `PSRAM` sizes are `2MB`,
|
||||
//! `4MB`, and `8MB`.
|
||||
const PSRAM_VADDR: u32 = 0x3f500000;
|
||||
|
||||
/// Returns the start address of the PSRAM virtual address space.
|
||||
pub fn psram_vaddr_start() -> usize {
|
||||
PSRAM_VADDR_START
|
||||
pub use crate::soc::psram_common::*;
|
||||
|
||||
const EXTMEM_ORIGIN: usize = 0x3f500000;
|
||||
|
||||
// Cache Speed
|
||||
#[derive(PartialEq, Eq, Debug, Copy, Clone, Default)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
#[allow(missing_docs)]
|
||||
pub enum PsramCacheSpeed {
|
||||
PsramCacheS80m = 1,
|
||||
PsramCacheS40m,
|
||||
PsramCacheS26m,
|
||||
PsramCacheS20m,
|
||||
#[default]
|
||||
PsramCacheMax,
|
||||
}
|
||||
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(feature = "psram-2m")] {
|
||||
const PSRAM_SIZE: u32 = 2;
|
||||
} else if #[cfg(feature = "psram-4m")] {
|
||||
const PSRAM_SIZE: u32 = 4;
|
||||
} else if #[cfg(feature = "psram-8m")] {
|
||||
const PSRAM_SIZE: u32 = 8;
|
||||
} else {
|
||||
const PSRAM_SIZE: u32 = 0;
|
||||
}
|
||||
/// PSRAM configuration
|
||||
#[derive(Copy, Clone, Debug, Default)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub struct PsramConfig {
|
||||
/// PSRAM size
|
||||
pub size: PsramSize,
|
||||
/// Cache Speed
|
||||
pub speed: PsramCacheSpeed,
|
||||
}
|
||||
|
||||
/// The total size of the PSRAM in bytes, calculated from the PSRAM size
|
||||
/// constant.
|
||||
pub const PSRAM_BYTES: usize = PSRAM_SIZE as usize * 1024 * 1024;
|
||||
|
||||
/// The start address of the PSRAM virtual address space.
|
||||
pub const PSRAM_VADDR_START: usize = PSRAM_VADDR as usize;
|
||||
|
||||
/// Initialize PSRAM to be used for data.
|
||||
#[cfg(any(feature = "psram-2m", feature = "psram-4m", feature = "psram-8m"))]
|
||||
///
|
||||
/// Returns the start of the mapped memory and the size
|
||||
#[procmacros::ram]
|
||||
pub fn init_psram(_peripheral: impl crate::peripheral::Peripheral<P = crate::peripherals::PSRAM>) {
|
||||
pub fn init_psram(_peripheral: crate::peripherals::PSRAM, config: PsramConfig) -> (*mut u8, usize) {
|
||||
let mut config = config;
|
||||
utils::psram_init(&mut config);
|
||||
|
||||
#[allow(unused)]
|
||||
enum CacheLayout {
|
||||
Invalid = 0,
|
||||
@ -120,10 +120,10 @@ pub fn init_psram(_peripheral: impl crate::peripheral::Peripheral<P = crate::per
|
||||
|
||||
if cache_dbus_mmu_set(
|
||||
MMU_ACCESS_SPIRAM,
|
||||
PSRAM_VADDR,
|
||||
EXTMEM_ORIGIN as u32,
|
||||
START_PAGE << 16,
|
||||
64,
|
||||
PSRAM_SIZE * 1024 / 64, // number of pages to map
|
||||
config.size.get() as u32 / 1024 / 64, // number of pages to map
|
||||
0,
|
||||
) != 0
|
||||
{
|
||||
@ -139,31 +139,94 @@ pub fn init_psram(_peripheral: impl crate::peripheral::Peripheral<P = crate::per
|
||||
.pro_dcache_mask_bus2()
|
||||
.clear_bit()
|
||||
});
|
||||
|
||||
utils::psram_init();
|
||||
}
|
||||
|
||||
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())
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "psram-2m", feature = "psram-4m", feature = "psram-8m"))]
|
||||
pub(crate) mod utils {
|
||||
use super::*;
|
||||
|
||||
const PSRAM_RESET_EN: u16 = 0x66;
|
||||
const PSRAM_RESET: u16 = 0x99;
|
||||
const PSRAM_DEVICE_ID: u16 = 0x9F;
|
||||
const CS_PSRAM_SEL: u8 = 1 << 1;
|
||||
|
||||
/// PS-RAM addressing mode
|
||||
#[derive(PartialEq, Eq, Debug, Copy, Clone, Default)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
#[allow(unused)]
|
||||
pub enum PsramVaddrMode {
|
||||
/// App and pro CPU use their own flash cache for external RAM access
|
||||
#[default]
|
||||
Normal = 0,
|
||||
/// App and pro CPU share external RAM caches: pro CPU has low2M, app
|
||||
/// CPU has high 2M
|
||||
Lowhigh,
|
||||
/// App and pro CPU share external RAM caches: pro CPU does even 32yte
|
||||
/// ranges, app does odd ones.
|
||||
Evenodd,
|
||||
}
|
||||
|
||||
// Function initializes the PSRAM by configuring GPIO pins, resetting the PSRAM,
|
||||
// and enabling Quad I/O (QIO) mode. It also calls the psram_cache_init
|
||||
// function to configure cache parameters and read/write commands.
|
||||
pub(crate) fn psram_init() {
|
||||
pub(crate) fn psram_init(config: &mut PsramConfig) {
|
||||
psram_gpio_config();
|
||||
|
||||
if config.size.is_auto() {
|
||||
// read chip id
|
||||
let mut dev_id = 0u32;
|
||||
psram_exec_cmd(
|
||||
CommandMode::PsramCmdSpi,
|
||||
PSRAM_DEVICE_ID,
|
||||
8, // command and command bit len
|
||||
0,
|
||||
24, // address and address bit len
|
||||
0, // dummy bit len
|
||||
core::ptr::null(),
|
||||
0, // tx data and tx bit len
|
||||
&mut dev_id as *mut _ as *mut u8,
|
||||
24, // rx data and rx bit len
|
||||
CS_PSRAM_SEL, // cs bit mask
|
||||
false,
|
||||
);
|
||||
info!("chip id = {:x}", dev_id);
|
||||
|
||||
const PSRAM_ID_EID_S: u32 = 16;
|
||||
const PSRAM_ID_EID_M: u32 = 0xff;
|
||||
const PSRAM_EID_SIZE_M: u32 = 0x07;
|
||||
const PSRAM_EID_SIZE_S: u32 = 5;
|
||||
|
||||
let size_id = (((dev_id) >> PSRAM_ID_EID_S) & PSRAM_ID_EID_M) >> PSRAM_EID_SIZE_S
|
||||
& PSRAM_EID_SIZE_M;
|
||||
|
||||
const PSRAM_EID_SIZE_32MBITS: u32 = 1;
|
||||
const PSRAM_EID_SIZE_64MBITS: u32 = 2;
|
||||
|
||||
let size = match size_id {
|
||||
PSRAM_EID_SIZE_64MBITS => 16 / 8 * 1024 * 1024,
|
||||
PSRAM_EID_SIZE_32MBITS => 16 / 8 * 1024 * 1024,
|
||||
_ => 16 / 8 * 1024 * 1024,
|
||||
};
|
||||
|
||||
info!("size is {}", size);
|
||||
|
||||
config.size = PsramSize::Size(size);
|
||||
}
|
||||
|
||||
psram_reset_mode();
|
||||
psram_enable_qio_mode();
|
||||
|
||||
psram_cache_init(PsramCacheSpeed::PsramCacheMax, PsramVaddrMode::Normal);
|
||||
psram_cache_init(config.speed, PsramVaddrMode::Normal);
|
||||
}
|
||||
|
||||
// send reset command to psram, in spi mode
|
||||
fn psram_reset_mode() {
|
||||
const PSRAM_RESET_EN: u16 = 0x66;
|
||||
const PSRAM_RESET: u16 = 0x99;
|
||||
const CS_PSRAM_SEL: u8 = 1 << 1;
|
||||
|
||||
psram_exec_cmd(
|
||||
CommandMode::PsramCmdSpi,
|
||||
PSRAM_RESET_EN,
|
||||
@ -224,6 +287,7 @@ pub(crate) mod utils {
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
#[inline(always)]
|
||||
fn psram_exec_cmd(
|
||||
mode: CommandMode,
|
||||
cmd: u16,
|
||||
@ -265,7 +329,7 @@ pub(crate) mod utils {
|
||||
_psram_exec_cmd(
|
||||
cmd,
|
||||
cmd_bit_len,
|
||||
addr,
|
||||
&addr,
|
||||
addr_bit_len,
|
||||
dummy_bits,
|
||||
mosi_data,
|
||||
@ -289,10 +353,11 @@ pub(crate) mod utils {
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
#[inline(always)]
|
||||
fn _psram_exec_cmd(
|
||||
cmd: u16,
|
||||
cmd_bit_len: u16,
|
||||
addr: u32,
|
||||
addr: *const u32,
|
||||
addr_bit_len: u32,
|
||||
dummy_bits: u32,
|
||||
mosi_data: *const u8,
|
||||
@ -323,7 +388,7 @@ pub(crate) mod utils {
|
||||
let conf = esp_rom_spi_cmd_t {
|
||||
cmd,
|
||||
cmd_bit_len,
|
||||
addr: addr as *const u32,
|
||||
addr,
|
||||
addr_bit_len,
|
||||
tx_data: mosi_data as *const u32,
|
||||
tx_data_bit_len: mosi_bit_len,
|
||||
@ -434,29 +499,6 @@ pub(crate) mod utils {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Debug)]
|
||||
#[allow(unused)]
|
||||
enum PsramCacheSpeed {
|
||||
PsramCacheS80m = 1,
|
||||
PsramCacheS40m,
|
||||
PsramCacheS26m,
|
||||
PsramCacheS20m,
|
||||
PsramCacheMax,
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Debug)]
|
||||
#[allow(unused)]
|
||||
enum PsramVaddrMode {
|
||||
/// App and pro CPU use their own flash cache for external RAM access
|
||||
Normal = 0,
|
||||
/// App and pro CPU share external RAM caches: pro CPU has low2M, app
|
||||
/// CPU has high 2M
|
||||
Lowhigh,
|
||||
/// App and pro CPU share external RAM caches: pro CPU does even 32yte
|
||||
/// ranges, app does odd ones.
|
||||
Evenodd,
|
||||
}
|
||||
|
||||
const PSRAM_IO_MATRIX_DUMMY_20M: u32 = 0;
|
||||
const PSRAM_IO_MATRIX_DUMMY_40M: u32 = 0;
|
||||
const PSRAM_IO_MATRIX_DUMMY_80M: u32 = 0;
|
||||
|
||||
@ -17,7 +17,7 @@ pub mod cpu_control;
|
||||
pub mod efuse;
|
||||
pub mod gpio;
|
||||
pub mod peripherals;
|
||||
#[cfg(psram)]
|
||||
#[cfg(any(feature = "quad-psram", feature = "octal-psram"))]
|
||||
pub mod psram;
|
||||
pub mod radio_clocks;
|
||||
pub mod trng;
|
||||
|
||||
@ -10,55 +10,70 @@
|
||||
//! to supplement the internal memory of the `ESP32-S3`, allowing for increased
|
||||
//! storage capacity and improved performance in certain applications.
|
||||
//!
|
||||
//! The `PSRAM` module is accessed through a virtual address, defined as
|
||||
//! `PSRAM_VADDR`. The starting virtual address for the PSRAM module is
|
||||
//! 0x3c000000. The `PSRAM` module size depends on the configuration specified
|
||||
//! during the compilation process. The available `PSRAM` sizes are `2MB`,
|
||||
//! `4MB`, and `8MB`.
|
||||
//! The mapped start address for PSRAM depends on the amount of mapped flash
|
||||
//! memory.
|
||||
|
||||
static mut PSRAM_VADDR: u32 = 0x3C000000;
|
||||
pub use crate::soc::psram_common::*;
|
||||
|
||||
/// Returns the start address of the PSRAM virtual address space.
|
||||
pub fn psram_vaddr_start() -> usize {
|
||||
unsafe { PSRAM_VADDR as usize }
|
||||
const EXTMEM_ORIGIN: u32 = 0x3C000000;
|
||||
|
||||
/// Frequency of flash memory
|
||||
#[derive(Copy, Clone, Debug, Default)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
#[allow(missing_docs)]
|
||||
pub enum FlashFreq {
|
||||
FlashFreq20m = 20,
|
||||
FlashFreq40m = 40,
|
||||
#[default]
|
||||
FlashFreq80m = 80,
|
||||
FlashFreq120m = 120,
|
||||
}
|
||||
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(feature = "psram-2m")] {
|
||||
const PSRAM_SIZE: u32 = 2;
|
||||
} else if #[cfg(feature = "psram-4m")] {
|
||||
const PSRAM_SIZE: u32 = 4;
|
||||
} else if #[cfg(feature = "psram-8m")] {
|
||||
const PSRAM_SIZE: u32 = 8;
|
||||
} else if #[cfg(feature = "opsram-2m")] {
|
||||
const PSRAM_SIZE: u32 = 2;
|
||||
} else if #[cfg(feature = "opsram-4m")] {
|
||||
const PSRAM_SIZE: u32 = 4;
|
||||
} else if #[cfg(feature = "opsram-8m")] {
|
||||
const PSRAM_SIZE: u32 = 8;
|
||||
} else if #[cfg(feature = "opsram-16m")] {
|
||||
const PSRAM_SIZE: u32 = 16;
|
||||
}else {
|
||||
const PSRAM_SIZE: u32 = 0;
|
||||
}
|
||||
/// Frequency of PSRAM memory
|
||||
#[derive(Copy, Clone, Debug, Default)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
#[allow(missing_docs)]
|
||||
pub enum SpiRamFreq {
|
||||
#[default]
|
||||
Freq40m = 40,
|
||||
Freq80m = 80,
|
||||
Freq120m = 120,
|
||||
}
|
||||
|
||||
/// The total size of the PSRAM in bytes, calculated from the PSRAM size
|
||||
/// constant.
|
||||
pub const PSRAM_BYTES: usize = PSRAM_SIZE as usize * 1024 * 1024;
|
||||
/// Core timing configuration
|
||||
#[derive(Copy, Clone, Debug, Default)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
#[allow(missing_docs)]
|
||||
pub enum SpiTimingConfigCoreClock {
|
||||
#[default]
|
||||
SpiTimingConfigCoreClock80m = 80,
|
||||
SpiTimingConfigCoreClock120m = 120,
|
||||
SpiTimingConfigCoreClock160m = 160,
|
||||
SpiTimingConfigCoreClock240m = 240,
|
||||
}
|
||||
|
||||
/// PSRAM configuration
|
||||
#[derive(Copy, Clone, Debug, Default)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub struct PsramConfig {
|
||||
/// PSRAM size
|
||||
pub size: PsramSize,
|
||||
/// Core timing configuration
|
||||
pub core_clock: SpiTimingConfigCoreClock,
|
||||
/// Frequency of flash memory
|
||||
pub flash_frequency: FlashFreq,
|
||||
/// Frequency of PSRAM memory
|
||||
pub ram_frequency: SpiRamFreq,
|
||||
}
|
||||
|
||||
/// Initialize PSRAM to be used for data.
|
||||
#[cfg(any(
|
||||
feature = "psram-2m",
|
||||
feature = "psram-4m",
|
||||
feature = "psram-8m",
|
||||
feature = "opsram-2m",
|
||||
feature = "opsram-4m",
|
||||
feature = "opsram-8m",
|
||||
feature = "opsram-16m"
|
||||
))]
|
||||
///
|
||||
/// Returns the start of the mapped memory and the size
|
||||
#[procmacros::ram]
|
||||
pub fn init_psram(_peripheral: impl crate::peripheral::Peripheral<P = crate::peripherals::PSRAM>) {
|
||||
pub fn init_psram(_peripheral: crate::peripherals::PSRAM, config: PsramConfig) -> (*mut u8, usize) {
|
||||
let mut config = config;
|
||||
utils::psram_init(&mut config);
|
||||
|
||||
const CONFIG_ESP32S3_INSTRUCTION_CACHE_SIZE: u32 = 0x4000;
|
||||
const CONFIG_ESP32S3_ICACHE_ASSOCIATED_WAYS: u8 = 8;
|
||||
const CONFIG_ESP32S3_INSTRUCTION_CACHE_LINE_SIZE: u8 = 32;
|
||||
@ -102,7 +117,8 @@ pub fn init_psram(_peripheral: impl crate::peripheral::Peripheral<P = crate::per
|
||||
fixed: u32,
|
||||
) -> i32;
|
||||
}
|
||||
unsafe {
|
||||
|
||||
let start = unsafe {
|
||||
const MMU_PAGE_SIZE: u32 = 0x10000;
|
||||
const ICACHE_MMU_SIZE: usize = 0x800;
|
||||
const FLASH_MMU_TABLE_SIZE: usize = ICACHE_MMU_SIZE / core::mem::size_of::<u32>();
|
||||
@ -110,7 +126,7 @@ pub fn init_psram(_peripheral: impl crate::peripheral::Peripheral<P = crate::per
|
||||
const DR_REG_MMU_TABLE: u32 = 0x600C5000;
|
||||
|
||||
// calculate the PSRAM start address to map
|
||||
let mut start = PSRAM_VADDR;
|
||||
let mut start = EXTMEM_ORIGIN;
|
||||
let mmu_table_ptr = DR_REG_MMU_TABLE as *const u32;
|
||||
for i in 0..FLASH_MMU_TABLE_SIZE {
|
||||
if mmu_table_ptr.add(i).read_volatile() != MMU_INVALID {
|
||||
@ -120,7 +136,6 @@ pub fn init_psram(_peripheral: impl crate::peripheral::Peripheral<P = crate::per
|
||||
}
|
||||
}
|
||||
debug!("PSRAM start address = {:x}", start);
|
||||
PSRAM_VADDR = start;
|
||||
|
||||
// Configure the mode of instruction cache : cache size, cache line size.
|
||||
rom_config_instruction_cache_mode(
|
||||
@ -141,10 +156,10 @@ pub fn init_psram(_peripheral: impl crate::peripheral::Peripheral<P = crate::per
|
||||
|
||||
if cache_dbus_mmu_set(
|
||||
MMU_ACCESS_SPIRAM,
|
||||
PSRAM_VADDR,
|
||||
start,
|
||||
START_PAGE << 16,
|
||||
64,
|
||||
PSRAM_SIZE * 1024 / 64, // number of pages to map
|
||||
config.size.get() as u32 / 1024 / 64, // number of pages to map
|
||||
0,
|
||||
) != 0
|
||||
{
|
||||
@ -160,70 +175,74 @@ pub fn init_psram(_peripheral: impl crate::peripheral::Peripheral<P = crate::per
|
||||
});
|
||||
|
||||
Cache_Resume_DCache(0);
|
||||
}
|
||||
|
||||
utils::psram_init();
|
||||
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())
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "psram-2m", feature = "psram-4m", feature = "psram-8m"))]
|
||||
#[cfg(feature = "quad-psram")]
|
||||
pub(crate) mod utils {
|
||||
use procmacros::ram;
|
||||
|
||||
// these should probably be configurable, relates to https://github.com/esp-rs/esp-hal/issues/42
|
||||
// probably also the PSRAM size shouldn't get configured via features
|
||||
const SPI_TIMING_CORE_CLOCK: SpiTimingConfigCoreClock =
|
||||
SpiTimingConfigCoreClock::SpiTimingConfigCoreClock80m;
|
||||
const FLASH_FREQ: FlashFreq = FlashFreq::FlashFreq80m;
|
||||
use super::*;
|
||||
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(feature = "psram-80mhz")] {
|
||||
const SPIRAM_SPEED: SpiRamFreq = SpiRamFreq::Freq80m;
|
||||
} else {
|
||||
const SPIRAM_SPEED: SpiRamFreq = SpiRamFreq::Freq40m;
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
enum FlashFreq {
|
||||
FlashFreq20m,
|
||||
FlashFreq40m,
|
||||
FlashFreq80m,
|
||||
FlashFreq120m,
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
enum SpiRamFreq {
|
||||
Freq40m,
|
||||
Freq80m,
|
||||
Freq120m,
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
#[derive(Debug)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
enum SpiTimingConfigCoreClock {
|
||||
SpiTimingConfigCoreClock80m,
|
||||
SpiTimingConfigCoreClock120m,
|
||||
SpiTimingConfigCoreClock160m,
|
||||
SpiTimingConfigCoreClock240m,
|
||||
}
|
||||
|
||||
impl SpiTimingConfigCoreClock {
|
||||
fn mhz(&self) -> u32 {
|
||||
match self {
|
||||
SpiTimingConfigCoreClock::SpiTimingConfigCoreClock80m => 80,
|
||||
SpiTimingConfigCoreClock::SpiTimingConfigCoreClock120m => 120,
|
||||
SpiTimingConfigCoreClock::SpiTimingConfigCoreClock160m => 160,
|
||||
SpiTimingConfigCoreClock::SpiTimingConfigCoreClock240m => 240,
|
||||
}
|
||||
}
|
||||
}
|
||||
const PSRAM_RESET_EN: u16 = 0x66;
|
||||
const PSRAM_RESET: u16 = 0x99;
|
||||
const PSRAM_DEVICE_ID: u16 = 0x9F;
|
||||
const CS_PSRAM_SEL: u8 = 1 << 1;
|
||||
|
||||
#[ram]
|
||||
pub(crate) fn psram_init() {
|
||||
pub(crate) fn psram_init(config: &mut super::PsramConfig) {
|
||||
psram_gpio_config();
|
||||
psram_set_cs_timing();
|
||||
|
||||
if config.size.is_auto() {
|
||||
// read chip id
|
||||
let mut dev_id = 0u32;
|
||||
psram_exec_cmd(
|
||||
CommandMode::PsramCmdSpi,
|
||||
PSRAM_DEVICE_ID,
|
||||
8, // command and command bit len
|
||||
0,
|
||||
24, // address and address bit len
|
||||
0, // dummy bit len
|
||||
core::ptr::null(),
|
||||
0, // tx data and tx bit len
|
||||
&mut dev_id as *mut _ as *mut u8,
|
||||
24, // rx data and rx bit len
|
||||
CS_PSRAM_SEL, // cs bit mask
|
||||
false,
|
||||
);
|
||||
info!("chip id = {:x}", dev_id);
|
||||
|
||||
const PSRAM_ID_EID_S: u32 = 16;
|
||||
const PSRAM_ID_EID_M: u32 = 0xff;
|
||||
const PSRAM_EID_SIZE_M: u32 = 0x07;
|
||||
const PSRAM_EID_SIZE_S: u32 = 5;
|
||||
|
||||
let size_id = (((dev_id) >> PSRAM_ID_EID_S) & PSRAM_ID_EID_M) >> PSRAM_EID_SIZE_S
|
||||
& PSRAM_EID_SIZE_M;
|
||||
|
||||
const PSRAM_EID_SIZE_32MBITS: u32 = 1;
|
||||
const PSRAM_EID_SIZE_64MBITS: u32 = 2;
|
||||
|
||||
let size = match size_id {
|
||||
PSRAM_EID_SIZE_64MBITS => 64 / 8 * 1024 * 1024,
|
||||
PSRAM_EID_SIZE_32MBITS => 32 / 8 * 1024 * 1024,
|
||||
_ => 16 / 8 * 1024 * 1024,
|
||||
};
|
||||
|
||||
info!("size is {}", size);
|
||||
|
||||
config.size = PsramSize::Size(size);
|
||||
}
|
||||
|
||||
// SPI1: send psram reset command
|
||||
psram_reset_mode_spi1();
|
||||
// SPI1: send QPI enable command
|
||||
@ -237,7 +256,7 @@ pub(crate) mod utils {
|
||||
config_psram_spi_phases();
|
||||
// Back to the high speed mode. Flash/PSRAM clocks are set to the clock that
|
||||
// user selected. SPI0/1 registers are all set correctly
|
||||
mspi_timing_enter_high_speed_mode(true);
|
||||
mspi_timing_enter_high_speed_mode(true, config);
|
||||
}
|
||||
|
||||
const PSRAM_CS_IO: u8 = 26;
|
||||
@ -359,10 +378,10 @@ pub(crate) mod utils {
|
||||
/// This function should always be called after `mspi_timing_flash_tuning`
|
||||
/// or `calculate_best_flash_tuning_config`
|
||||
#[ram]
|
||||
fn mspi_timing_enter_high_speed_mode(control_spi1: bool) {
|
||||
let core_clock: SpiTimingConfigCoreClock = get_mspi_core_clock();
|
||||
let flash_div: u32 = get_flash_clock_divider();
|
||||
let psram_div: u32 = get_psram_clock_divider();
|
||||
fn mspi_timing_enter_high_speed_mode(control_spi1: bool, config: &PsramConfig) {
|
||||
let core_clock: SpiTimingConfigCoreClock = get_mspi_core_clock(config);
|
||||
let flash_div: u32 = get_flash_clock_divider(config);
|
||||
let psram_div: u32 = get_psram_clock_divider(config);
|
||||
|
||||
info!(
|
||||
"PSRAM core_clock {:?}, flash_div = {}, psram_div = {}",
|
||||
@ -447,36 +466,23 @@ pub(crate) mod utils {
|
||||
}
|
||||
|
||||
#[ram]
|
||||
fn get_mspi_core_clock() -> SpiTimingConfigCoreClock {
|
||||
SPI_TIMING_CORE_CLOCK
|
||||
fn get_mspi_core_clock(config: &PsramConfig) -> SpiTimingConfigCoreClock {
|
||||
config.core_clock
|
||||
}
|
||||
|
||||
#[ram]
|
||||
fn get_flash_clock_divider() -> u32 {
|
||||
match FLASH_FREQ {
|
||||
FlashFreq::FlashFreq20m => SPI_TIMING_CORE_CLOCK.mhz() / 20,
|
||||
FlashFreq::FlashFreq40m => SPI_TIMING_CORE_CLOCK.mhz() / 40,
|
||||
FlashFreq::FlashFreq80m => SPI_TIMING_CORE_CLOCK.mhz() / 80,
|
||||
FlashFreq::FlashFreq120m => SPI_TIMING_CORE_CLOCK.mhz() / 120,
|
||||
}
|
||||
fn get_flash_clock_divider(config: &PsramConfig) -> u32 {
|
||||
config.core_clock as u32 / config.flash_frequency as u32
|
||||
}
|
||||
|
||||
#[ram]
|
||||
fn get_psram_clock_divider() -> u32 {
|
||||
match SPIRAM_SPEED {
|
||||
SpiRamFreq::Freq40m => SPI_TIMING_CORE_CLOCK.mhz() / 40,
|
||||
SpiRamFreq::Freq80m => SPI_TIMING_CORE_CLOCK.mhz() / 80,
|
||||
SpiRamFreq::Freq120m => SPI_TIMING_CORE_CLOCK.mhz() / 120,
|
||||
}
|
||||
fn get_psram_clock_divider(config: &PsramConfig) -> u32 {
|
||||
config.core_clock as u32 / config.ram_frequency as u32
|
||||
}
|
||||
|
||||
// send reset command to psram, in spi mode
|
||||
#[ram]
|
||||
fn psram_reset_mode_spi1() {
|
||||
const PSRAM_RESET_EN: u16 = 0x66;
|
||||
const PSRAM_RESET: u16 = 0x99;
|
||||
const CS_PSRAM_SEL: u8 = 1 << 1;
|
||||
|
||||
psram_exec_cmd(
|
||||
CommandMode::PsramCmdSpi,
|
||||
PSRAM_RESET_EN,
|
||||
@ -617,7 +623,7 @@ pub(crate) mod utils {
|
||||
let conf = esp_rom_spi_cmd_t {
|
||||
cmd,
|
||||
cmd_bit_len,
|
||||
addr: addr as *const u32,
|
||||
addr: &addr,
|
||||
addr_bit_len,
|
||||
tx_data: mosi_data as *const u32,
|
||||
tx_data_bit_len: mosi_bit_len,
|
||||
@ -733,64 +739,11 @@ pub(crate) mod utils {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(
|
||||
feature = "opsram-2m",
|
||||
feature = "opsram-4m",
|
||||
feature = "opsram-8m",
|
||||
feature = "opsram-16m"
|
||||
))]
|
||||
#[cfg(feature = "octal-psram")]
|
||||
pub(crate) mod utils {
|
||||
use procmacros::ram;
|
||||
|
||||
// these should probably be configurable, relates to https://github.com/esp-rs/esp-hal/issues/42
|
||||
// probably also the PSRAM size shouldn't get configured via features
|
||||
const SPI_TIMING_CORE_CLOCK: SpiTimingConfigCoreClock =
|
||||
SpiTimingConfigCoreClock::SpiTimingConfigCoreClock80m;
|
||||
const FLASH_FREQ: FlashFreq = FlashFreq::FlashFreq80m;
|
||||
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(feature = "psram-80mhz")] {
|
||||
const SPIRAM_SPEED: SpiRamFreq = SpiRamFreq::Freq80m;
|
||||
} else {
|
||||
const SPIRAM_SPEED: SpiRamFreq = SpiRamFreq::Freq40m;
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
enum FlashFreq {
|
||||
FlashFreq20m,
|
||||
FlashFreq40m,
|
||||
FlashFreq80m,
|
||||
FlashFreq120m,
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
enum SpiRamFreq {
|
||||
Freq40m,
|
||||
Freq80m,
|
||||
Freq120m,
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
#[derive(Debug)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
enum SpiTimingConfigCoreClock {
|
||||
SpiTimingConfigCoreClock80m,
|
||||
SpiTimingConfigCoreClock120m,
|
||||
SpiTimingConfigCoreClock160m,
|
||||
SpiTimingConfigCoreClock240m,
|
||||
}
|
||||
|
||||
impl SpiTimingConfigCoreClock {
|
||||
fn mhz(&self) -> u32 {
|
||||
match self {
|
||||
SpiTimingConfigCoreClock::SpiTimingConfigCoreClock80m => 80,
|
||||
SpiTimingConfigCoreClock::SpiTimingConfigCoreClock120m => 120,
|
||||
SpiTimingConfigCoreClock::SpiTimingConfigCoreClock160m => 160,
|
||||
SpiTimingConfigCoreClock::SpiTimingConfigCoreClock240m => 240,
|
||||
}
|
||||
}
|
||||
}
|
||||
use super::*;
|
||||
|
||||
const OPI_PSRAM_SYNC_READ: u16 = 0x0000;
|
||||
const OPI_PSRAM_SYNC_WRITE: u16 = 0x8080;
|
||||
@ -1077,7 +1030,7 @@ pub(crate) mod utils {
|
||||
}
|
||||
|
||||
#[ram]
|
||||
pub(crate) fn psram_init() {
|
||||
pub(crate) fn psram_init(config: &mut PsramConfig) {
|
||||
mspi_pin_init();
|
||||
init_psram_pins();
|
||||
set_psram_cs_timing();
|
||||
@ -1124,6 +1077,10 @@ pub(crate) mod utils {
|
||||
};
|
||||
info!("{} bytes of PSRAM", psram_size);
|
||||
|
||||
if config.size.is_auto() {
|
||||
config.size = PsramSize::Size(psram_size);
|
||||
}
|
||||
|
||||
// Do PSRAM timing tuning, we use SPI1 to do the tuning, and set the
|
||||
// SPI0 PSRAM timing related registers accordingly
|
||||
// this is unsupported for now
|
||||
@ -1131,7 +1088,7 @@ pub(crate) mod utils {
|
||||
|
||||
// Back to the high speed mode. Flash/PSRAM clocks are set to the clock
|
||||
// that user selected. SPI0/1 registers are all set correctly
|
||||
spi_timing_enter_mspi_high_speed_mode(true);
|
||||
spi_timing_enter_mspi_high_speed_mode(true, config);
|
||||
|
||||
// Tuning may change SPI1 regs, whereas legacy spi_flash APIs rely on
|
||||
// these regs. This function is to restore SPI1 init state.
|
||||
@ -1280,12 +1237,12 @@ pub(crate) mod utils {
|
||||
//
|
||||
// This function should always be called after `spi_timing_flash_tuning` or
|
||||
// `calculate_best_flash_tuning_config`
|
||||
fn spi_timing_enter_mspi_high_speed_mode(control_spi1: bool) {
|
||||
fn spi_timing_enter_mspi_high_speed_mode(control_spi1: bool, config: &PsramConfig) {
|
||||
// spi_timing_config_core_clock_t core_clock = get_mspi_core_clock();
|
||||
let core_clock = SpiTimingConfigCoreClock::SpiTimingConfigCoreClock80m;
|
||||
|
||||
let flash_div: u32 = get_flash_clock_divider();
|
||||
let psram_div: u32 = get_psram_clock_divider();
|
||||
let flash_div: u32 = get_flash_clock_divider(config);
|
||||
let psram_div: u32 = get_psram_clock_divider(config);
|
||||
|
||||
// Set SPI01 core clock
|
||||
spi0_timing_config_set_core_clock(core_clock); // SPI0 and SPI1 share the register for core clock. So we only set SPI0 here.
|
||||
@ -1644,21 +1601,12 @@ pub(crate) mod utils {
|
||||
}
|
||||
|
||||
#[ram]
|
||||
fn get_flash_clock_divider() -> u32 {
|
||||
match FLASH_FREQ {
|
||||
FlashFreq::FlashFreq20m => SPI_TIMING_CORE_CLOCK.mhz() / 20,
|
||||
FlashFreq::FlashFreq40m => SPI_TIMING_CORE_CLOCK.mhz() / 40,
|
||||
FlashFreq::FlashFreq80m => SPI_TIMING_CORE_CLOCK.mhz() / 80,
|
||||
FlashFreq::FlashFreq120m => SPI_TIMING_CORE_CLOCK.mhz() / 120,
|
||||
}
|
||||
fn get_flash_clock_divider(config: &PsramConfig) -> u32 {
|
||||
config.core_clock as u32 / config.flash_frequency as u32
|
||||
}
|
||||
|
||||
#[ram]
|
||||
fn get_psram_clock_divider() -> u32 {
|
||||
match SPIRAM_SPEED {
|
||||
SpiRamFreq::Freq40m => SPI_TIMING_CORE_CLOCK.mhz() / 40,
|
||||
SpiRamFreq::Freq80m => SPI_TIMING_CORE_CLOCK.mhz() / 80,
|
||||
SpiRamFreq::Freq120m => SPI_TIMING_CORE_CLOCK.mhz() / 120,
|
||||
}
|
||||
fn get_psram_clock_divider(config: &PsramConfig) -> u32 {
|
||||
config.core_clock as u32 / config.ram_frequency as u32
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
use portable_atomic::{AtomicU8, Ordering};
|
||||
|
||||
pub use self::implementation::*;
|
||||
#[cfg(psram)]
|
||||
use crate::lock::Locked;
|
||||
|
||||
#[cfg_attr(esp32, path = "esp32/mod.rs")]
|
||||
#[cfg_attr(esp32c2, path = "esp32c2/mod.rs")]
|
||||
@ -13,6 +15,17 @@ mod implementation;
|
||||
|
||||
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 });
|
||||
|
||||
#[cfg(psram)]
|
||||
pub struct MappedPsram {
|
||||
memory_range: core::ops::Range<usize>,
|
||||
}
|
||||
|
||||
// Indicates the state of setting the mac address
|
||||
// 0 -- unset
|
||||
// 1 -- in the process of being set
|
||||
@ -59,7 +72,7 @@ impl self::efuse::Efuse {
|
||||
/// Get base mac address
|
||||
///
|
||||
/// By default this reads the base mac address from eFuse, but it can be
|
||||
/// overriden by `set_mac_address`.
|
||||
/// overridden by `set_mac_address`.
|
||||
pub fn get_mac_address() -> [u8; 6] {
|
||||
if MAC_OVERRIDE_STATE.load(Ordering::Relaxed) == 2 {
|
||||
unsafe { MAC_OVERRIDE }
|
||||
@ -85,9 +98,8 @@ pub(crate) fn is_slice_in_dram<T>(slice: &[T]) -> bool {
|
||||
pub(crate) fn is_valid_psram_address(address: u32) -> bool {
|
||||
#[cfg(psram)]
|
||||
{
|
||||
let start = crate::psram::psram_vaddr_start() as u32;
|
||||
let end = start + crate::psram::PSRAM_BYTES as u32;
|
||||
(start..=end).contains(&address)
|
||||
let memory_range = MAPPED_PSRAM.with(|mapped_psram| mapped_psram.memory_range.clone());
|
||||
memory_range.contains(&(address as usize))
|
||||
}
|
||||
#[cfg(not(psram))]
|
||||
false
|
||||
|
||||
25
esp-hal/src/soc/psram_common.rs
Normal file
25
esp-hal/src/soc/psram_common.rs
Normal file
@ -0,0 +1,25 @@
|
||||
/// Size of PSRAM
|
||||
///
|
||||
/// [PsramSize::AutoDetect] will try to detect the size of PSRAM
|
||||
#[derive(Copy, Clone, Debug, Default, PartialEq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum PsramSize {
|
||||
/// Detect PSRAM size
|
||||
#[default]
|
||||
AutoDetect,
|
||||
/// A fixed PSRAM size
|
||||
Size(usize),
|
||||
}
|
||||
|
||||
impl PsramSize {
|
||||
pub(crate) fn get(&self) -> usize {
|
||||
match self {
|
||||
PsramSize::AutoDetect => 0,
|
||||
PsramSize::Size(size) => *size,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn is_auto(&self) -> bool {
|
||||
matches!(self, PsramSize::AutoDetect)
|
||||
}
|
||||
}
|
||||
@ -68,6 +68,7 @@ symbols = [
|
||||
"bt",
|
||||
"wifi",
|
||||
"psram",
|
||||
"octal_psram",
|
||||
"ulp_riscv_core",
|
||||
"timg_timer1",
|
||||
"very_large_intr_status",
|
||||
|
||||
@ -73,9 +73,6 @@ esp-wifi = ["dep:esp-wifi"]
|
||||
embassy = ["dep:esp-hal-embassy"]
|
||||
embassy-generic-timers = ["embassy-time/generic-queue-8"]
|
||||
|
||||
opsram-2m = ["esp-hal/opsram-2m"]
|
||||
psram-2m = ["esp-hal/psram-2m"]
|
||||
|
||||
[profile.release]
|
||||
codegen-units = 1
|
||||
debug = 2
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
//! Uses DMA to copy psram to internal memory.
|
||||
|
||||
//% FEATURES: esp-hal/log opsram-2m aligned
|
||||
//% FEATURES: esp-hal/log esp-hal/octal-psram aligned
|
||||
//% CHIPS: esp32s3
|
||||
|
||||
#![no_std]
|
||||
@ -42,16 +42,13 @@ macro_rules! dma_alloc_buffer {
|
||||
}};
|
||||
}
|
||||
|
||||
fn init_heap(psram: impl esp_hal::peripheral::Peripheral<P = esp_hal::peripherals::PSRAM>) {
|
||||
esp_hal::psram::init_psram(psram);
|
||||
info!(
|
||||
"init_heap: start: 0x{:0x}",
|
||||
esp_hal::psram::psram_vaddr_start()
|
||||
);
|
||||
fn init_heap(psram: esp_hal::peripherals::PSRAM) {
|
||||
let (start, size) = esp_hal::psram::init_psram(psram, esp_hal::psram::PsramConfig::default());
|
||||
info!("init_heap: start: {:p}", start);
|
||||
unsafe {
|
||||
esp_alloc::HEAP.add_region(esp_alloc::HeapRegion::new(
|
||||
esp_hal::psram::psram_vaddr_start() as *mut u8,
|
||||
esp_hal::psram::PSRAM_BYTES,
|
||||
start,
|
||||
size,
|
||||
esp_alloc::MemoryCapability::External.into(),
|
||||
));
|
||||
}
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
//! You need an ESP32-S3 with at least 2 MB of PSRAM memory.
|
||||
|
||||
//% CHIPS: esp32s3
|
||||
//% FEATURES: opsram-2m
|
||||
//% FEATURES: esp-hal/octal-psram
|
||||
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
@ -17,11 +17,11 @@ use esp_backtrace as _;
|
||||
use esp_hal::{prelude::*, psram};
|
||||
use esp_println::println;
|
||||
|
||||
fn init_psram_heap() {
|
||||
fn init_psram_heap(start: *mut u8, size: usize) {
|
||||
unsafe {
|
||||
esp_alloc::HEAP.add_region(esp_alloc::HeapRegion::new(
|
||||
psram::psram_vaddr_start() as *mut u8,
|
||||
psram::PSRAM_BYTES,
|
||||
start,
|
||||
size,
|
||||
esp_alloc::MemoryCapability::External.into(),
|
||||
));
|
||||
}
|
||||
@ -32,10 +32,11 @@ compile_error!("PSRAM example must be built in release mode!");
|
||||
|
||||
#[entry]
|
||||
fn main() -> ! {
|
||||
esp_println::logger::init_logger_from_env();
|
||||
let peripherals = esp_hal::init(esp_hal::Config::default());
|
||||
|
||||
psram::init_psram(peripherals.PSRAM);
|
||||
init_psram_heap();
|
||||
let (start, size) = psram::init_psram(peripherals.PSRAM, psram::PsramConfig::default());
|
||||
init_psram_heap(start, size);
|
||||
|
||||
println!("Going to access PSRAM");
|
||||
let mut large_vec: Vec<u32> = Vec::with_capacity(500 * 1024 / 4);
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
//! You need an ESP32, ESP32-S2 or ESP32-S3 with at least 2 MB of PSRAM memory.
|
||||
|
||||
//% CHIPS: esp32 esp32s2 esp32s3
|
||||
//% FEATURES: psram-2m
|
||||
//% FEATURES: esp-hal/quad-psram
|
||||
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
@ -17,11 +17,11 @@ use esp_backtrace as _;
|
||||
use esp_hal::{prelude::*, psram};
|
||||
use esp_println::println;
|
||||
|
||||
fn init_psram_heap() {
|
||||
fn init_psram_heap(start: *mut u8, size: usize) {
|
||||
unsafe {
|
||||
esp_alloc::HEAP.add_region(esp_alloc::HeapRegion::new(
|
||||
psram::psram_vaddr_start() as *mut u8,
|
||||
psram::PSRAM_BYTES,
|
||||
start,
|
||||
size,
|
||||
esp_alloc::MemoryCapability::External.into(),
|
||||
));
|
||||
}
|
||||
@ -32,10 +32,11 @@ compile_error!("PSRAM example must be built in release mode!");
|
||||
|
||||
#[entry]
|
||||
fn main() -> ! {
|
||||
esp_println::logger::init_logger_from_env();
|
||||
let peripherals = esp_hal::init(esp_hal::Config::default());
|
||||
|
||||
psram::init_psram(peripherals.PSRAM);
|
||||
init_psram_heap();
|
||||
let (start, size) = psram::init_psram(peripherals.PSRAM, psram::PsramConfig::default());
|
||||
init_psram_heap(start, size);
|
||||
|
||||
println!("Going to access PSRAM");
|
||||
let mut large_vec = Vec::<u32>::with_capacity(500 * 1024 / 4);
|
||||
|
||||
@ -122,8 +122,13 @@ pub fn build_documentation(
|
||||
|
||||
let mut features = vec![chip.to_string()];
|
||||
|
||||
// future enhancement: see https://github.com/esp-rs/esp-hal/issues/2195
|
||||
if matches!(package, Package::EspHal) {
|
||||
features.push("ci".to_owned())
|
||||
features.push("ci".to_owned());
|
||||
|
||||
if [Chip::Esp32, Chip::Esp32s2, Chip::Esp32s3].contains(&chip) {
|
||||
features.push("quad-psram".to_owned());
|
||||
}
|
||||
}
|
||||
|
||||
// Build up an array of command-line arguments to pass to `cargo`:
|
||||
|
||||
@ -556,7 +556,7 @@ fn lint_packages(workspace: &Path, args: LintPackagesArgs) -> Result<()> {
|
||||
}
|
||||
if device.contains("psram") {
|
||||
// TODO this doesn't test octal psram as it would require a separate build
|
||||
features.push_str(",psram-4m,psram-80mhz")
|
||||
features.push_str(",quad-psram")
|
||||
}
|
||||
if matches!(chip, Chip::Esp32c6 | Chip::Esp32h2) {
|
||||
features.push_str(",flip-link")
|
||||
|
||||
Loading…
Reference in New Issue
Block a user