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 {
|
macro_rules! psram_allocator {
|
||||||
($peripheral:expr,$psram_module:path) => {{
|
($peripheral:expr,$psram_module:path) => {{
|
||||||
use $psram_module as _psram;
|
use $psram_module as _psram;
|
||||||
_psram::init_psram($peripheral);
|
let (start, size) = _psram::init_psram($peripheral, _psram::PsramConfig::default());
|
||||||
unsafe {
|
unsafe {
|
||||||
$crate::HEAP.add_region($crate::HeapRegion::new(
|
$crate::HEAP.add_region($crate::HeapRegion::new(
|
||||||
_psram::psram_vaddr_start() as *mut u8,
|
start,
|
||||||
_psram::PSRAM_BYTES,
|
size,
|
||||||
$crate::MemoryCapability::External.into(),
|
$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)
|
- The `NO_PIN` constant has been removed. (#2133)
|
||||||
- MSRV bump to 1.79 (#2156)
|
- MSRV bump to 1.79 (#2156)
|
||||||
- Allow handling interrupts while trying to lock critical section on multi-core chips. (#2197)
|
- 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
|
### Fixed
|
||||||
|
|
||||||
|
|||||||
@ -143,24 +143,11 @@ defmt = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
#! ### PSRAM Feature Flags
|
#! ### PSRAM Feature Flags
|
||||||
## Use externally connected PSRAM (2MB).
|
## Use externally connected Quad PSRAM
|
||||||
psram-2m = []
|
quad-psram = []
|
||||||
## Use externally connected PSRAM (4MB).
|
|
||||||
psram-4m = []
|
|
||||||
## Use externally connected PSRAM (8MB).
|
|
||||||
psram-8m = []
|
|
||||||
## PSRAM 80Mhz frequency support
|
|
||||||
psram-80mhz = []
|
|
||||||
|
|
||||||
#! ### Octal RAM Feature Flags
|
## Use externally connected Octal RAM
|
||||||
## Use externally connected Octal RAM (2MB).
|
octal-psram = []
|
||||||
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 = []
|
|
||||||
|
|
||||||
# This feature is intended for testing; you probably don't want to enable it:
|
# This feature is intended for testing; you probably don't want to enable it:
|
||||||
ci = ["defmt", "bluetooth"]
|
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
|
# key in .cargo/config.toml [env] section
|
||||||
+ ESP_HAL_PLACE_SPI_DRIVER_IN_RAM=true
|
+ 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);
|
let config = Config::for_chip(&chip);
|
||||||
|
|
||||||
// Check PSRAM features are only given if the target supports PSRAM:
|
// Check PSRAM features are only given if the target supports PSRAM:
|
||||||
if !config.contains(&String::from("psram"))
|
if !config.contains(&String::from("psram")) && cfg!(feature = "quad-psram") {
|
||||||
&& (cfg!(feature = "psram-2m") || cfg!(feature = "psram-4m") || cfg!(feature = "psram-8m"))
|
|
||||||
{
|
|
||||||
panic!("The target does not support 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:
|
// Define all necessary configuration symbols for the configured device:
|
||||||
config.define_symbols();
|
config.define_symbols();
|
||||||
|
|
||||||
@ -226,11 +228,7 @@ fn generate_memory_extras() -> Vec<u8> {
|
|||||||
|
|
||||||
#[cfg(feature = "esp32s2")]
|
#[cfg(feature = "esp32s2")]
|
||||||
fn generate_memory_extras() -> Vec<u8> {
|
fn generate_memory_extras() -> Vec<u8> {
|
||||||
let reserved_cache = if cfg!(any(
|
let reserved_cache = if cfg!(feature = "quad-psram") {
|
||||||
feature = "psram-2m",
|
|
||||||
feature = "psram-4m",
|
|
||||||
feature = "psram-8m"
|
|
||||||
)) {
|
|
||||||
"0x4000"
|
"0x4000"
|
||||||
} else {
|
} else {
|
||||||
"0x2000"
|
"0x2000"
|
||||||
|
|||||||
@ -155,7 +155,7 @@ pub use self::soc::efuse;
|
|||||||
#[cfg(lp_core)]
|
#[cfg(lp_core)]
|
||||||
pub use self::soc::lp_core;
|
pub use self::soc::lp_core;
|
||||||
pub use self::soc::peripherals;
|
pub use self::soc::peripherals;
|
||||||
#[cfg(psram)]
|
#[cfg(any(feature = "quad-psram", feature = "octal-psram"))]
|
||||||
pub use self::soc::psram;
|
pub use self::soc::psram;
|
||||||
#[cfg(ulp_riscv_core)]
|
#[cfg(ulp_riscv_core)]
|
||||||
pub use self::soc::ulp_core;
|
pub use self::soc::ulp_core;
|
||||||
|
|||||||
@ -1,3 +1,5 @@
|
|||||||
|
use core::cell::UnsafeCell;
|
||||||
|
|
||||||
mod single_core {
|
mod single_core {
|
||||||
pub unsafe fn disable_interrupts() -> critical_section::RawRestoreState {
|
pub unsafe fn disable_interrupts() -> critical_section::RawRestoreState {
|
||||||
cfg_if::cfg_if! {
|
cfg_if::cfg_if! {
|
||||||
@ -210,6 +212,31 @@ pub(crate) fn lock<T>(lock: &Lock, f: impl FnOnce() -> T) -> T {
|
|||||||
f()
|
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;
|
struct CriticalSection;
|
||||||
|
|
||||||
critical_section::set_impl!(CriticalSection);
|
critical_section::set_impl!(CriticalSection);
|
||||||
|
|||||||
@ -13,7 +13,7 @@ pub mod cpu_control;
|
|||||||
pub mod efuse;
|
pub mod efuse;
|
||||||
pub mod gpio;
|
pub mod gpio;
|
||||||
pub mod peripherals;
|
pub mod peripherals;
|
||||||
#[cfg(psram)]
|
#[cfg(feature = "quad-psram")]
|
||||||
pub mod psram;
|
pub mod psram;
|
||||||
pub mod radio_clocks;
|
pub mod radio_clocks;
|
||||||
pub mod trng;
|
pub mod trng;
|
||||||
|
|||||||
@ -9,53 +9,98 @@
|
|||||||
//! present on the `ESP32` chip. `PSRAM` provides additional external memory to
|
//! present on the `ESP32` chip. `PSRAM` provides additional external memory to
|
||||||
//! supplement the internal memory of the `ESP32`, allowing for increased
|
//! supplement the internal memory of the `ESP32`, allowing for increased
|
||||||
//! storage capacity and improved performance in certain applications.
|
//! 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 use crate::soc::psram_common::*;
|
||||||
pub const PSRAM_VADDR_START: usize = 0x3F800000;
|
|
||||||
|
|
||||||
/// Retrieves the starting virtual address of the PSRAM (Pseudo-SRAM) region in
|
const EXTMEM_ORIGIN: usize = 0x3F800000;
|
||||||
/// memory.
|
|
||||||
pub fn psram_vaddr_start() -> usize {
|
/// Cache Speed
|
||||||
PSRAM_VADDR_START
|
#[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! {
|
/// PSRAM configuration
|
||||||
if #[cfg(feature = "psram-2m")] {
|
#[derive(Copy, Clone, Debug, Default)]
|
||||||
const PSRAM_SIZE: u32 = 2;
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
} else if #[cfg(feature = "psram-4m")] {
|
pub struct PsramConfig {
|
||||||
const PSRAM_SIZE: u32 = 4;
|
/// PSRAM size
|
||||||
} else if #[cfg(feature = "psram-8m")] {
|
pub size: PsramSize,
|
||||||
const PSRAM_SIZE: u32 = 8;
|
/// Cache speed
|
||||||
} else {
|
pub cache_speed: PsramCacheSpeed,
|
||||||
const PSRAM_SIZE: u32 = 0;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// 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.
|
/// 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>) {
|
/// Returns the start of the mapped memory and the size
|
||||||
utils::psram_init();
|
pub fn init_psram(_peripheral: crate::peripherals::PSRAM, config: PsramConfig) -> (*mut u8, usize) {
|
||||||
utils::s_mapping(PSRAM_VADDR_START as u32, PSRAM_BYTES as u32);
|
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 {
|
pub(crate) mod utils {
|
||||||
use core::ptr::addr_of_mut;
|
use core::ptr::addr_of_mut;
|
||||||
|
|
||||||
use procmacros::ram;
|
use procmacros::ram;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[ram]
|
||||||
pub(crate) fn s_mapping(v_start: u32, size: u32) {
|
pub(crate) fn s_mapping(v_start: u32, size: u32) {
|
||||||
// Enable external RAM in MMU
|
// Enable external RAM in MMU
|
||||||
cache_sram_mmu_set(0, 0, v_start, 0, 32, size / 1024 / 32);
|
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
|
// we can use the ROM version of this: it works well enough and keeps the size
|
||||||
// of the binary down.
|
// of the binary down.
|
||||||
|
#[ram]
|
||||||
fn cache_sram_mmu_set(
|
fn cache_sram_mmu_set(
|
||||||
cpu_no: u32,
|
cpu_no: u32,
|
||||||
pid: u32,
|
pid: u32,
|
||||||
@ -198,15 +244,6 @@ pub(crate) mod utils {
|
|||||||
(((spi_config) >> shift) & mask) as u8
|
(((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)]
|
#[derive(PartialEq, Eq, Debug, Default)]
|
||||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
struct PsramIo {
|
struct PsramIo {
|
||||||
@ -228,13 +265,13 @@ pub(crate) mod utils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
struct EspRomSpiflashChip {
|
pub(super) struct EspRomSpiflashChip {
|
||||||
device_id: u32,
|
pub device_id: u32,
|
||||||
chip_size: u32, // chip size in bytes
|
pub chip_size: u32, // chip size in bytes
|
||||||
block_size: u32,
|
pub block_size: u32,
|
||||||
sector_size: u32,
|
pub sector_size: u32,
|
||||||
page_size: u32,
|
pub page_size: u32,
|
||||||
status_mask: u32,
|
pub status_mask: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
@ -253,7 +290,7 @@ pub(crate) mod utils {
|
|||||||
|
|
||||||
static mut g_rom_spiflash_dummy_len_plus: u8;
|
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(
|
fn cache_sram_mmu_set_rom(
|
||||||
cpu_no: u32,
|
cpu_no: u32,
|
||||||
@ -265,10 +302,11 @@ pub(crate) mod utils {
|
|||||||
) -> i32;
|
) -> i32;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn psram_init() {
|
#[ram]
|
||||||
|
pub(crate) fn psram_init(config: &PsramConfig) {
|
||||||
let chip = crate::efuse::Efuse::get_chip_type();
|
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 mut psram_io = PsramIo::default();
|
||||||
let clk_mode;
|
let clk_mode;
|
||||||
|
|
||||||
@ -416,6 +454,7 @@ pub(crate) mod utils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let extra_dummy = psram_gpio_config(&psram_io, mode);
|
let extra_dummy = psram_gpio_config(&psram_io, mode);
|
||||||
|
info!("extra dummy = {}", extra_dummy);
|
||||||
|
|
||||||
// psram_is_32mbit_ver0 would need special handling here
|
// psram_is_32mbit_ver0 would need special handling here
|
||||||
|
|
||||||
@ -615,6 +654,7 @@ pub(crate) mod utils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// spi param init for psram
|
// spi param init for psram
|
||||||
|
#[ram]
|
||||||
fn psram_spi_init(
|
fn psram_spi_init(
|
||||||
// psram_spi_num_t spi_num = PSRAM_SPI_1,
|
// psram_spi_num_t spi_num = PSRAM_SPI_1,
|
||||||
mode: PsramCacheSpeed,
|
mode: PsramCacheSpeed,
|
||||||
@ -748,7 +788,7 @@ pub(crate) mod utils {
|
|||||||
ps_cmd.rx_data_bit_len = 0;
|
ps_cmd.rx_data_bit_len = 0;
|
||||||
ps_cmd.dummy_bit_len = 0;
|
ps_cmd.dummy_bit_len = 0;
|
||||||
let (backup_usr, backup_usr1, backup_usr2) = psram_cmd_config_spi1(&ps_cmd);
|
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);
|
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
|
// start sending cmd/addr and optionally, receiving data
|
||||||
#[ram]
|
#[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 {
|
unsafe {
|
||||||
let spi = &*crate::peripherals::SPI1::PTR;
|
let spi = &*crate::peripherals::SPI1::PTR;
|
||||||
// get cs1
|
// get cs1
|
||||||
@ -942,8 +986,8 @@ pub(crate) mod utils {
|
|||||||
|
|
||||||
if !p_rx_data.is_null() {
|
if !p_rx_data.is_null() {
|
||||||
// Read data out
|
// Read data out
|
||||||
loop {
|
for i in 0..rx_data_len_words {
|
||||||
p_rx_data.write_volatile(spi.w(0).read().bits());
|
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;
|
let flash_id: u32 = g_rom_flashchip.device_id;
|
||||||
info!("Flash-ID = {}", flash_id);
|
info!("Flash-ID = {}", flash_id);
|
||||||
|
info!("Flash size = {}", g_rom_flashchip.chip_size);
|
||||||
|
|
||||||
if flash_id == FLASH_ID_GD25LQ32C {
|
if flash_id == FLASH_ID_GD25LQ32C {
|
||||||
// Set drive ability for 1.8v flash in 80Mhz.
|
// Set drive ability for 1.8v flash in 80Mhz.
|
||||||
|
|||||||
@ -16,7 +16,7 @@ use crate::rtc_cntl::SocResetReason;
|
|||||||
pub mod efuse;
|
pub mod efuse;
|
||||||
pub mod gpio;
|
pub mod gpio;
|
||||||
pub mod peripherals;
|
pub mod peripherals;
|
||||||
#[cfg(psram)]
|
#[cfg(feature = "quad-psram")]
|
||||||
pub mod psram;
|
pub mod psram;
|
||||||
pub mod radio_clocks;
|
pub mod radio_clocks;
|
||||||
pub mod trng;
|
pub mod trng;
|
||||||
|
|||||||
@ -9,42 +9,42 @@
|
|||||||
//! present on the `ESP32-S2` chip. `PSRAM` provides additional external memory
|
//! present on the `ESP32-S2` chip. `PSRAM` provides additional external memory
|
||||||
//! to supplement the internal memory of the `ESP32-S2`, allowing for increased
|
//! to supplement the internal memory of the `ESP32-S2`, allowing for increased
|
||||||
//! storage capacity and improved performance in certain applications.
|
//! 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 use crate::soc::psram_common::*;
|
||||||
pub fn psram_vaddr_start() -> usize {
|
|
||||||
PSRAM_VADDR_START
|
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! {
|
/// PSRAM configuration
|
||||||
if #[cfg(feature = "psram-2m")] {
|
#[derive(Copy, Clone, Debug, Default)]
|
||||||
const PSRAM_SIZE: u32 = 2;
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
} else if #[cfg(feature = "psram-4m")] {
|
pub struct PsramConfig {
|
||||||
const PSRAM_SIZE: u32 = 4;
|
/// PSRAM size
|
||||||
} else if #[cfg(feature = "psram-8m")] {
|
pub size: PsramSize,
|
||||||
const PSRAM_SIZE: u32 = 8;
|
/// Cache Speed
|
||||||
} else {
|
pub speed: PsramCacheSpeed,
|
||||||
const PSRAM_SIZE: u32 = 0;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// 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.
|
/// 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]
|
#[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)]
|
#[allow(unused)]
|
||||||
enum CacheLayout {
|
enum CacheLayout {
|
||||||
Invalid = 0,
|
Invalid = 0,
|
||||||
@ -120,10 +120,10 @@ pub fn init_psram(_peripheral: impl crate::peripheral::Peripheral<P = crate::per
|
|||||||
|
|
||||||
if cache_dbus_mmu_set(
|
if cache_dbus_mmu_set(
|
||||||
MMU_ACCESS_SPIRAM,
|
MMU_ACCESS_SPIRAM,
|
||||||
PSRAM_VADDR,
|
EXTMEM_ORIGIN as u32,
|
||||||
START_PAGE << 16,
|
START_PAGE << 16,
|
||||||
64,
|
64,
|
||||||
PSRAM_SIZE * 1024 / 64, // number of pages to map
|
config.size.get() as u32 / 1024 / 64, // number of pages to map
|
||||||
0,
|
0,
|
||||||
) != 0
|
) != 0
|
||||||
{
|
{
|
||||||
@ -139,31 +139,94 @@ pub fn init_psram(_peripheral: impl crate::peripheral::Peripheral<P = crate::per
|
|||||||
.pro_dcache_mask_bus2()
|
.pro_dcache_mask_bus2()
|
||||||
.clear_bit()
|
.clear_bit()
|
||||||
});
|
});
|
||||||
|
|
||||||
utils::psram_init();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(feature = "psram-2m", feature = "psram-4m", feature = "psram-8m"))]
|
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())
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) mod utils {
|
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,
|
// 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
|
// and enabling Quad I/O (QIO) mode. It also calls the psram_cache_init
|
||||||
// function to configure cache parameters and read/write commands.
|
// 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();
|
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_reset_mode();
|
||||||
psram_enable_qio_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
|
// send reset command to psram, in spi mode
|
||||||
fn psram_reset_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(
|
psram_exec_cmd(
|
||||||
CommandMode::PsramCmdSpi,
|
CommandMode::PsramCmdSpi,
|
||||||
PSRAM_RESET_EN,
|
PSRAM_RESET_EN,
|
||||||
@ -224,6 +287,7 @@ pub(crate) mod utils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
|
#[inline(always)]
|
||||||
fn psram_exec_cmd(
|
fn psram_exec_cmd(
|
||||||
mode: CommandMode,
|
mode: CommandMode,
|
||||||
cmd: u16,
|
cmd: u16,
|
||||||
@ -265,7 +329,7 @@ pub(crate) mod utils {
|
|||||||
_psram_exec_cmd(
|
_psram_exec_cmd(
|
||||||
cmd,
|
cmd,
|
||||||
cmd_bit_len,
|
cmd_bit_len,
|
||||||
addr,
|
&addr,
|
||||||
addr_bit_len,
|
addr_bit_len,
|
||||||
dummy_bits,
|
dummy_bits,
|
||||||
mosi_data,
|
mosi_data,
|
||||||
@ -289,10 +353,11 @@ pub(crate) mod utils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
|
#[inline(always)]
|
||||||
fn _psram_exec_cmd(
|
fn _psram_exec_cmd(
|
||||||
cmd: u16,
|
cmd: u16,
|
||||||
cmd_bit_len: u16,
|
cmd_bit_len: u16,
|
||||||
addr: u32,
|
addr: *const u32,
|
||||||
addr_bit_len: u32,
|
addr_bit_len: u32,
|
||||||
dummy_bits: u32,
|
dummy_bits: u32,
|
||||||
mosi_data: *const u8,
|
mosi_data: *const u8,
|
||||||
@ -323,7 +388,7 @@ pub(crate) mod utils {
|
|||||||
let conf = esp_rom_spi_cmd_t {
|
let conf = esp_rom_spi_cmd_t {
|
||||||
cmd,
|
cmd,
|
||||||
cmd_bit_len,
|
cmd_bit_len,
|
||||||
addr: addr as *const u32,
|
addr,
|
||||||
addr_bit_len,
|
addr_bit_len,
|
||||||
tx_data: mosi_data as *const u32,
|
tx_data: mosi_data as *const u32,
|
||||||
tx_data_bit_len: mosi_bit_len,
|
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_20M: u32 = 0;
|
||||||
const PSRAM_IO_MATRIX_DUMMY_40M: u32 = 0;
|
const PSRAM_IO_MATRIX_DUMMY_40M: u32 = 0;
|
||||||
const PSRAM_IO_MATRIX_DUMMY_80M: u32 = 0;
|
const PSRAM_IO_MATRIX_DUMMY_80M: u32 = 0;
|
||||||
|
|||||||
@ -17,7 +17,7 @@ pub mod cpu_control;
|
|||||||
pub mod efuse;
|
pub mod efuse;
|
||||||
pub mod gpio;
|
pub mod gpio;
|
||||||
pub mod peripherals;
|
pub mod peripherals;
|
||||||
#[cfg(psram)]
|
#[cfg(any(feature = "quad-psram", feature = "octal-psram"))]
|
||||||
pub mod psram;
|
pub mod psram;
|
||||||
pub mod radio_clocks;
|
pub mod radio_clocks;
|
||||||
pub mod trng;
|
pub mod trng;
|
||||||
|
|||||||
@ -10,55 +10,70 @@
|
|||||||
//! to supplement the internal memory of the `ESP32-S3`, allowing for increased
|
//! to supplement the internal memory of the `ESP32-S3`, allowing for increased
|
||||||
//! storage capacity and improved performance in certain applications.
|
//! storage capacity and improved performance in certain applications.
|
||||||
//!
|
//!
|
||||||
//! The `PSRAM` module is accessed through a virtual address, defined as
|
//! The mapped start address for PSRAM depends on the amount of mapped flash
|
||||||
//! `PSRAM_VADDR`. The starting virtual address for the PSRAM module is
|
//! memory.
|
||||||
//! 0x3c000000. The `PSRAM` module size depends on the configuration specified
|
|
||||||
//! during the compilation process. The available `PSRAM` sizes are `2MB`,
|
|
||||||
//! `4MB`, and `8MB`.
|
|
||||||
|
|
||||||
static mut PSRAM_VADDR: u32 = 0x3C000000;
|
pub use crate::soc::psram_common::*;
|
||||||
|
|
||||||
/// Returns the start address of the PSRAM virtual address space.
|
const EXTMEM_ORIGIN: u32 = 0x3C000000;
|
||||||
pub fn psram_vaddr_start() -> usize {
|
|
||||||
unsafe { PSRAM_VADDR as usize }
|
/// 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! {
|
/// Frequency of PSRAM memory
|
||||||
if #[cfg(feature = "psram-2m")] {
|
#[derive(Copy, Clone, Debug, Default)]
|
||||||
const PSRAM_SIZE: u32 = 2;
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
} else if #[cfg(feature = "psram-4m")] {
|
#[allow(missing_docs)]
|
||||||
const PSRAM_SIZE: u32 = 4;
|
pub enum SpiRamFreq {
|
||||||
} else if #[cfg(feature = "psram-8m")] {
|
#[default]
|
||||||
const PSRAM_SIZE: u32 = 8;
|
Freq40m = 40,
|
||||||
} else if #[cfg(feature = "opsram-2m")] {
|
Freq80m = 80,
|
||||||
const PSRAM_SIZE: u32 = 2;
|
Freq120m = 120,
|
||||||
} 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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The total size of the PSRAM in bytes, calculated from the PSRAM size
|
/// Core timing configuration
|
||||||
/// constant.
|
#[derive(Copy, Clone, Debug, Default)]
|
||||||
pub const PSRAM_BYTES: usize = PSRAM_SIZE as usize * 1024 * 1024;
|
#[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.
|
/// Initialize PSRAM to be used for data.
|
||||||
#[cfg(any(
|
///
|
||||||
feature = "psram-2m",
|
/// Returns the start of the mapped memory and the size
|
||||||
feature = "psram-4m",
|
|
||||||
feature = "psram-8m",
|
|
||||||
feature = "opsram-2m",
|
|
||||||
feature = "opsram-4m",
|
|
||||||
feature = "opsram-8m",
|
|
||||||
feature = "opsram-16m"
|
|
||||||
))]
|
|
||||||
#[procmacros::ram]
|
#[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_INSTRUCTION_CACHE_SIZE: u32 = 0x4000;
|
||||||
const CONFIG_ESP32S3_ICACHE_ASSOCIATED_WAYS: u8 = 8;
|
const CONFIG_ESP32S3_ICACHE_ASSOCIATED_WAYS: u8 = 8;
|
||||||
const CONFIG_ESP32S3_INSTRUCTION_CACHE_LINE_SIZE: u8 = 32;
|
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,
|
fixed: u32,
|
||||||
) -> i32;
|
) -> i32;
|
||||||
}
|
}
|
||||||
unsafe {
|
|
||||||
|
let start = unsafe {
|
||||||
const MMU_PAGE_SIZE: u32 = 0x10000;
|
const MMU_PAGE_SIZE: u32 = 0x10000;
|
||||||
const ICACHE_MMU_SIZE: usize = 0x800;
|
const ICACHE_MMU_SIZE: usize = 0x800;
|
||||||
const FLASH_MMU_TABLE_SIZE: usize = ICACHE_MMU_SIZE / core::mem::size_of::<u32>();
|
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;
|
const DR_REG_MMU_TABLE: u32 = 0x600C5000;
|
||||||
|
|
||||||
// calculate the PSRAM start address to map
|
// 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;
|
let mmu_table_ptr = DR_REG_MMU_TABLE as *const u32;
|
||||||
for i in 0..FLASH_MMU_TABLE_SIZE {
|
for i in 0..FLASH_MMU_TABLE_SIZE {
|
||||||
if mmu_table_ptr.add(i).read_volatile() != MMU_INVALID {
|
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);
|
debug!("PSRAM start address = {:x}", start);
|
||||||
PSRAM_VADDR = start;
|
|
||||||
|
|
||||||
// Configure the mode of instruction cache : cache size, cache line size.
|
// Configure the mode of instruction cache : cache size, cache line size.
|
||||||
rom_config_instruction_cache_mode(
|
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(
|
if cache_dbus_mmu_set(
|
||||||
MMU_ACCESS_SPIRAM,
|
MMU_ACCESS_SPIRAM,
|
||||||
PSRAM_VADDR,
|
start,
|
||||||
START_PAGE << 16,
|
START_PAGE << 16,
|
||||||
64,
|
64,
|
||||||
PSRAM_SIZE * 1024 / 64, // number of pages to map
|
config.size.get() as u32 / 1024 / 64, // number of pages to map
|
||||||
0,
|
0,
|
||||||
) != 0
|
) != 0
|
||||||
{
|
{
|
||||||
@ -160,70 +175,74 @@ pub fn init_psram(_peripheral: impl crate::peripheral::Peripheral<P = crate::per
|
|||||||
});
|
});
|
||||||
|
|
||||||
Cache_Resume_DCache(0);
|
Cache_Resume_DCache(0);
|
||||||
|
|
||||||
|
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())
|
||||||
}
|
}
|
||||||
|
|
||||||
utils::psram_init();
|
#[cfg(feature = "quad-psram")]
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(any(feature = "psram-2m", feature = "psram-4m", feature = "psram-8m"))]
|
|
||||||
pub(crate) mod utils {
|
pub(crate) mod utils {
|
||||||
use procmacros::ram;
|
use procmacros::ram;
|
||||||
|
|
||||||
// these should probably be configurable, relates to https://github.com/esp-rs/esp-hal/issues/42
|
use super::*;
|
||||||
// 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! {
|
const PSRAM_RESET_EN: u16 = 0x66;
|
||||||
if #[cfg(feature = "psram-80mhz")] {
|
const PSRAM_RESET: u16 = 0x99;
|
||||||
const SPIRAM_SPEED: SpiRamFreq = SpiRamFreq::Freq80m;
|
const PSRAM_DEVICE_ID: u16 = 0x9F;
|
||||||
} else {
|
const CS_PSRAM_SEL: u8 = 1 << 1;
|
||||||
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,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[ram]
|
#[ram]
|
||||||
pub(crate) fn psram_init() {
|
pub(crate) fn psram_init(config: &mut super::PsramConfig) {
|
||||||
psram_gpio_config();
|
psram_gpio_config();
|
||||||
psram_set_cs_timing();
|
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
|
// SPI1: send psram reset command
|
||||||
psram_reset_mode_spi1();
|
psram_reset_mode_spi1();
|
||||||
// SPI1: send QPI enable command
|
// SPI1: send QPI enable command
|
||||||
@ -237,7 +256,7 @@ pub(crate) mod utils {
|
|||||||
config_psram_spi_phases();
|
config_psram_spi_phases();
|
||||||
// Back to the high speed mode. Flash/PSRAM clocks are set to the clock that
|
// Back to the high speed mode. Flash/PSRAM clocks are set to the clock that
|
||||||
// user selected. SPI0/1 registers are all set correctly
|
// 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;
|
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`
|
/// This function should always be called after `mspi_timing_flash_tuning`
|
||||||
/// or `calculate_best_flash_tuning_config`
|
/// or `calculate_best_flash_tuning_config`
|
||||||
#[ram]
|
#[ram]
|
||||||
fn mspi_timing_enter_high_speed_mode(control_spi1: bool) {
|
fn mspi_timing_enter_high_speed_mode(control_spi1: bool, config: &PsramConfig) {
|
||||||
let core_clock: SpiTimingConfigCoreClock = get_mspi_core_clock();
|
let core_clock: SpiTimingConfigCoreClock = get_mspi_core_clock(config);
|
||||||
let flash_div: u32 = get_flash_clock_divider();
|
let flash_div: u32 = get_flash_clock_divider(config);
|
||||||
let psram_div: u32 = get_psram_clock_divider();
|
let psram_div: u32 = get_psram_clock_divider(config);
|
||||||
|
|
||||||
info!(
|
info!(
|
||||||
"PSRAM core_clock {:?}, flash_div = {}, psram_div = {}",
|
"PSRAM core_clock {:?}, flash_div = {}, psram_div = {}",
|
||||||
@ -447,36 +466,23 @@ pub(crate) mod utils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[ram]
|
#[ram]
|
||||||
fn get_mspi_core_clock() -> SpiTimingConfigCoreClock {
|
fn get_mspi_core_clock(config: &PsramConfig) -> SpiTimingConfigCoreClock {
|
||||||
SPI_TIMING_CORE_CLOCK
|
config.core_clock
|
||||||
}
|
}
|
||||||
|
|
||||||
#[ram]
|
#[ram]
|
||||||
fn get_flash_clock_divider() -> u32 {
|
fn get_flash_clock_divider(config: &PsramConfig) -> u32 {
|
||||||
match FLASH_FREQ {
|
config.core_clock as u32 / config.flash_frequency as u32
|
||||||
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,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[ram]
|
#[ram]
|
||||||
fn get_psram_clock_divider() -> u32 {
|
fn get_psram_clock_divider(config: &PsramConfig) -> u32 {
|
||||||
match SPIRAM_SPEED {
|
config.core_clock as u32 / config.ram_frequency as u32
|
||||||
SpiRamFreq::Freq40m => SPI_TIMING_CORE_CLOCK.mhz() / 40,
|
|
||||||
SpiRamFreq::Freq80m => SPI_TIMING_CORE_CLOCK.mhz() / 80,
|
|
||||||
SpiRamFreq::Freq120m => SPI_TIMING_CORE_CLOCK.mhz() / 120,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// send reset command to psram, in spi mode
|
// send reset command to psram, in spi mode
|
||||||
#[ram]
|
#[ram]
|
||||||
fn psram_reset_mode_spi1() {
|
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(
|
psram_exec_cmd(
|
||||||
CommandMode::PsramCmdSpi,
|
CommandMode::PsramCmdSpi,
|
||||||
PSRAM_RESET_EN,
|
PSRAM_RESET_EN,
|
||||||
@ -617,7 +623,7 @@ pub(crate) mod utils {
|
|||||||
let conf = esp_rom_spi_cmd_t {
|
let conf = esp_rom_spi_cmd_t {
|
||||||
cmd,
|
cmd,
|
||||||
cmd_bit_len,
|
cmd_bit_len,
|
||||||
addr: addr as *const u32,
|
addr: &addr,
|
||||||
addr_bit_len,
|
addr_bit_len,
|
||||||
tx_data: mosi_data as *const u32,
|
tx_data: mosi_data as *const u32,
|
||||||
tx_data_bit_len: mosi_bit_len,
|
tx_data_bit_len: mosi_bit_len,
|
||||||
@ -733,64 +739,11 @@ pub(crate) mod utils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(
|
#[cfg(feature = "octal-psram")]
|
||||||
feature = "opsram-2m",
|
|
||||||
feature = "opsram-4m",
|
|
||||||
feature = "opsram-8m",
|
|
||||||
feature = "opsram-16m"
|
|
||||||
))]
|
|
||||||
pub(crate) mod utils {
|
pub(crate) mod utils {
|
||||||
use procmacros::ram;
|
use procmacros::ram;
|
||||||
|
|
||||||
// these should probably be configurable, relates to https://github.com/esp-rs/esp-hal/issues/42
|
use super::*;
|
||||||
// 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,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const OPI_PSRAM_SYNC_READ: u16 = 0x0000;
|
const OPI_PSRAM_SYNC_READ: u16 = 0x0000;
|
||||||
const OPI_PSRAM_SYNC_WRITE: u16 = 0x8080;
|
const OPI_PSRAM_SYNC_WRITE: u16 = 0x8080;
|
||||||
@ -1077,7 +1030,7 @@ pub(crate) mod utils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[ram]
|
#[ram]
|
||||||
pub(crate) fn psram_init() {
|
pub(crate) fn psram_init(config: &mut PsramConfig) {
|
||||||
mspi_pin_init();
|
mspi_pin_init();
|
||||||
init_psram_pins();
|
init_psram_pins();
|
||||||
set_psram_cs_timing();
|
set_psram_cs_timing();
|
||||||
@ -1124,6 +1077,10 @@ pub(crate) mod utils {
|
|||||||
};
|
};
|
||||||
info!("{} bytes of PSRAM", psram_size);
|
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
|
// Do PSRAM timing tuning, we use SPI1 to do the tuning, and set the
|
||||||
// SPI0 PSRAM timing related registers accordingly
|
// SPI0 PSRAM timing related registers accordingly
|
||||||
// this is unsupported for now
|
// 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
|
// Back to the high speed mode. Flash/PSRAM clocks are set to the clock
|
||||||
// that user selected. SPI0/1 registers are all set correctly
|
// 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
|
// Tuning may change SPI1 regs, whereas legacy spi_flash APIs rely on
|
||||||
// these regs. This function is to restore SPI1 init state.
|
// 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
|
// This function should always be called after `spi_timing_flash_tuning` or
|
||||||
// `calculate_best_flash_tuning_config`
|
// `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();
|
// spi_timing_config_core_clock_t core_clock = get_mspi_core_clock();
|
||||||
let core_clock = SpiTimingConfigCoreClock::SpiTimingConfigCoreClock80m;
|
let core_clock = SpiTimingConfigCoreClock::SpiTimingConfigCoreClock80m;
|
||||||
|
|
||||||
let flash_div: u32 = get_flash_clock_divider();
|
let flash_div: u32 = get_flash_clock_divider(config);
|
||||||
let psram_div: u32 = get_psram_clock_divider();
|
let psram_div: u32 = get_psram_clock_divider(config);
|
||||||
|
|
||||||
// Set SPI01 core clock
|
// 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.
|
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]
|
#[ram]
|
||||||
fn get_flash_clock_divider() -> u32 {
|
fn get_flash_clock_divider(config: &PsramConfig) -> u32 {
|
||||||
match FLASH_FREQ {
|
config.core_clock as u32 / config.flash_frequency as u32
|
||||||
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,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[ram]
|
#[ram]
|
||||||
fn get_psram_clock_divider() -> u32 {
|
fn get_psram_clock_divider(config: &PsramConfig) -> u32 {
|
||||||
match SPIRAM_SPEED {
|
config.core_clock as u32 / config.ram_frequency as u32
|
||||||
SpiRamFreq::Freq40m => SPI_TIMING_CORE_CLOCK.mhz() / 40,
|
|
||||||
SpiRamFreq::Freq80m => SPI_TIMING_CORE_CLOCK.mhz() / 80,
|
|
||||||
SpiRamFreq::Freq120m => SPI_TIMING_CORE_CLOCK.mhz() / 120,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
use portable_atomic::{AtomicU8, Ordering};
|
use portable_atomic::{AtomicU8, Ordering};
|
||||||
|
|
||||||
pub use self::implementation::*;
|
pub use self::implementation::*;
|
||||||
|
#[cfg(psram)]
|
||||||
|
use crate::lock::Locked;
|
||||||
|
|
||||||
#[cfg_attr(esp32, path = "esp32/mod.rs")]
|
#[cfg_attr(esp32, path = "esp32/mod.rs")]
|
||||||
#[cfg_attr(esp32c2, path = "esp32c2/mod.rs")]
|
#[cfg_attr(esp32c2, path = "esp32c2/mod.rs")]
|
||||||
@ -13,6 +15,17 @@ mod implementation;
|
|||||||
|
|
||||||
mod efuse_field;
|
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
|
// Indicates the state of setting the mac address
|
||||||
// 0 -- unset
|
// 0 -- unset
|
||||||
// 1 -- in the process of being set
|
// 1 -- in the process of being set
|
||||||
@ -59,7 +72,7 @@ impl self::efuse::Efuse {
|
|||||||
/// Get base mac address
|
/// Get base mac address
|
||||||
///
|
///
|
||||||
/// By default this reads the base mac address from eFuse, but it can be
|
/// 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] {
|
pub fn get_mac_address() -> [u8; 6] {
|
||||||
if MAC_OVERRIDE_STATE.load(Ordering::Relaxed) == 2 {
|
if MAC_OVERRIDE_STATE.load(Ordering::Relaxed) == 2 {
|
||||||
unsafe { MAC_OVERRIDE }
|
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 {
|
pub(crate) fn is_valid_psram_address(address: u32) -> bool {
|
||||||
#[cfg(psram)]
|
#[cfg(psram)]
|
||||||
{
|
{
|
||||||
let start = crate::psram::psram_vaddr_start() as u32;
|
let memory_range = MAPPED_PSRAM.with(|mapped_psram| mapped_psram.memory_range.clone());
|
||||||
let end = start + crate::psram::PSRAM_BYTES as u32;
|
memory_range.contains(&(address as usize))
|
||||||
(start..=end).contains(&address)
|
|
||||||
}
|
}
|
||||||
#[cfg(not(psram))]
|
#[cfg(not(psram))]
|
||||||
false
|
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",
|
"bt",
|
||||||
"wifi",
|
"wifi",
|
||||||
"psram",
|
"psram",
|
||||||
|
"octal_psram",
|
||||||
"ulp_riscv_core",
|
"ulp_riscv_core",
|
||||||
"timg_timer1",
|
"timg_timer1",
|
||||||
"very_large_intr_status",
|
"very_large_intr_status",
|
||||||
|
|||||||
@ -73,9 +73,6 @@ esp-wifi = ["dep:esp-wifi"]
|
|||||||
embassy = ["dep:esp-hal-embassy"]
|
embassy = ["dep:esp-hal-embassy"]
|
||||||
embassy-generic-timers = ["embassy-time/generic-queue-8"]
|
embassy-generic-timers = ["embassy-time/generic-queue-8"]
|
||||||
|
|
||||||
opsram-2m = ["esp-hal/opsram-2m"]
|
|
||||||
psram-2m = ["esp-hal/psram-2m"]
|
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
codegen-units = 1
|
codegen-units = 1
|
||||||
debug = 2
|
debug = 2
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
//! Uses DMA to copy psram to internal memory.
|
//! 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
|
//% CHIPS: esp32s3
|
||||||
|
|
||||||
#![no_std]
|
#![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>) {
|
fn init_heap(psram: esp_hal::peripherals::PSRAM) {
|
||||||
esp_hal::psram::init_psram(psram);
|
let (start, size) = esp_hal::psram::init_psram(psram, esp_hal::psram::PsramConfig::default());
|
||||||
info!(
|
info!("init_heap: start: {:p}", start);
|
||||||
"init_heap: start: 0x{:0x}",
|
|
||||||
esp_hal::psram::psram_vaddr_start()
|
|
||||||
);
|
|
||||||
unsafe {
|
unsafe {
|
||||||
esp_alloc::HEAP.add_region(esp_alloc::HeapRegion::new(
|
esp_alloc::HEAP.add_region(esp_alloc::HeapRegion::new(
|
||||||
esp_hal::psram::psram_vaddr_start() as *mut u8,
|
start,
|
||||||
esp_hal::psram::PSRAM_BYTES,
|
size,
|
||||||
esp_alloc::MemoryCapability::External.into(),
|
esp_alloc::MemoryCapability::External.into(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
//! You need an ESP32-S3 with at least 2 MB of PSRAM memory.
|
//! You need an ESP32-S3 with at least 2 MB of PSRAM memory.
|
||||||
|
|
||||||
//% CHIPS: esp32s3
|
//% CHIPS: esp32s3
|
||||||
//% FEATURES: opsram-2m
|
//% FEATURES: esp-hal/octal-psram
|
||||||
|
|
||||||
#![no_std]
|
#![no_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
@ -17,11 +17,11 @@ use esp_backtrace as _;
|
|||||||
use esp_hal::{prelude::*, psram};
|
use esp_hal::{prelude::*, psram};
|
||||||
use esp_println::println;
|
use esp_println::println;
|
||||||
|
|
||||||
fn init_psram_heap() {
|
fn init_psram_heap(start: *mut u8, size: usize) {
|
||||||
unsafe {
|
unsafe {
|
||||||
esp_alloc::HEAP.add_region(esp_alloc::HeapRegion::new(
|
esp_alloc::HEAP.add_region(esp_alloc::HeapRegion::new(
|
||||||
psram::psram_vaddr_start() as *mut u8,
|
start,
|
||||||
psram::PSRAM_BYTES,
|
size,
|
||||||
esp_alloc::MemoryCapability::External.into(),
|
esp_alloc::MemoryCapability::External.into(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
@ -32,10 +32,11 @@ compile_error!("PSRAM example must be built in release mode!");
|
|||||||
|
|
||||||
#[entry]
|
#[entry]
|
||||||
fn main() -> ! {
|
fn main() -> ! {
|
||||||
|
esp_println::logger::init_logger_from_env();
|
||||||
let peripherals = esp_hal::init(esp_hal::Config::default());
|
let peripherals = esp_hal::init(esp_hal::Config::default());
|
||||||
|
|
||||||
psram::init_psram(peripherals.PSRAM);
|
let (start, size) = psram::init_psram(peripherals.PSRAM, psram::PsramConfig::default());
|
||||||
init_psram_heap();
|
init_psram_heap(start, size);
|
||||||
|
|
||||||
println!("Going to access PSRAM");
|
println!("Going to access PSRAM");
|
||||||
let mut large_vec: Vec<u32> = Vec::with_capacity(500 * 1024 / 4);
|
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.
|
//! You need an ESP32, ESP32-S2 or ESP32-S3 with at least 2 MB of PSRAM memory.
|
||||||
|
|
||||||
//% CHIPS: esp32 esp32s2 esp32s3
|
//% CHIPS: esp32 esp32s2 esp32s3
|
||||||
//% FEATURES: psram-2m
|
//% FEATURES: esp-hal/quad-psram
|
||||||
|
|
||||||
#![no_std]
|
#![no_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
@ -17,11 +17,11 @@ use esp_backtrace as _;
|
|||||||
use esp_hal::{prelude::*, psram};
|
use esp_hal::{prelude::*, psram};
|
||||||
use esp_println::println;
|
use esp_println::println;
|
||||||
|
|
||||||
fn init_psram_heap() {
|
fn init_psram_heap(start: *mut u8, size: usize) {
|
||||||
unsafe {
|
unsafe {
|
||||||
esp_alloc::HEAP.add_region(esp_alloc::HeapRegion::new(
|
esp_alloc::HEAP.add_region(esp_alloc::HeapRegion::new(
|
||||||
psram::psram_vaddr_start() as *mut u8,
|
start,
|
||||||
psram::PSRAM_BYTES,
|
size,
|
||||||
esp_alloc::MemoryCapability::External.into(),
|
esp_alloc::MemoryCapability::External.into(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
@ -32,10 +32,11 @@ compile_error!("PSRAM example must be built in release mode!");
|
|||||||
|
|
||||||
#[entry]
|
#[entry]
|
||||||
fn main() -> ! {
|
fn main() -> ! {
|
||||||
|
esp_println::logger::init_logger_from_env();
|
||||||
let peripherals = esp_hal::init(esp_hal::Config::default());
|
let peripherals = esp_hal::init(esp_hal::Config::default());
|
||||||
|
|
||||||
psram::init_psram(peripherals.PSRAM);
|
let (start, size) = psram::init_psram(peripherals.PSRAM, psram::PsramConfig::default());
|
||||||
init_psram_heap();
|
init_psram_heap(start, size);
|
||||||
|
|
||||||
println!("Going to access PSRAM");
|
println!("Going to access PSRAM");
|
||||||
let mut large_vec = Vec::<u32>::with_capacity(500 * 1024 / 4);
|
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()];
|
let mut features = vec![chip.to_string()];
|
||||||
|
|
||||||
|
// future enhancement: see https://github.com/esp-rs/esp-hal/issues/2195
|
||||||
if matches!(package, Package::EspHal) {
|
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`:
|
// 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") {
|
if device.contains("psram") {
|
||||||
// TODO this doesn't test octal psram as it would require a separate build
|
// 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) {
|
if matches!(chip, Chip::Esp32c6 | Chip::Esp32h2) {
|
||||||
features.push_str(",flip-link")
|
features.push_str(",flip-link")
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user