mirror of
https://github.com/esp-rs/esp-hal.git
synced 2025-09-28 04:40:52 +00:00
Unstabilize CPU-related functionality, merge modules (#3099)
* Move Cpu to a new module * Move cpu_control's contents into cpu * Merge raw_core functions * Hide cpu control APIs * Move reset into cpu * Fix software_reset_cpu * Allow inlining cpu functions * Changelog * Mark software_reset no-return * Move WakeupReason * Remove PeripheralIter * Move cpu into system * Mark system stable
This commit is contained in:
parent
bb92715f6b
commit
392d5ccdc1
@ -5,7 +5,7 @@ use core::{cell::UnsafeCell, mem::MaybeUninit};
|
||||
use embassy_executor::SendSpawner;
|
||||
use esp_hal::{
|
||||
interrupt::{self, software::SoftwareInterrupt, InterruptHandler},
|
||||
Cpu,
|
||||
system::Cpu,
|
||||
};
|
||||
use portable_atomic::{AtomicUsize, Ordering};
|
||||
|
||||
|
@ -5,7 +5,7 @@ use core::marker::PhantomData;
|
||||
use embassy_executor::Spawner;
|
||||
#[cfg(all(low_power_wait, multi_core))]
|
||||
use esp_hal::interrupt::software::SoftwareInterrupt;
|
||||
use esp_hal::{interrupt::Priority, Cpu};
|
||||
use esp_hal::{interrupt::Priority, system::Cpu};
|
||||
#[cfg(low_power_wait)]
|
||||
use portable_atomic::{AtomicBool, Ordering};
|
||||
|
||||
|
@ -40,6 +40,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- Removed features `psram-quad` and `psram-octal` - replaced by `psram` and the `ESP_HAL_CONFIG_PSRAM_MODE` (`quad`/`octal`) (#3001)
|
||||
- The `esp_hal::time` module no longer reexports `fugit` types (#3083)
|
||||
- The `system::RadioClockController` trait has been replaced by the `clock::RadioClockController` struct. (#3100)
|
||||
- The `Cpu` struct and contents of the `reset` and `cpu_control` modules have been moved into `cpu`. (#)
|
||||
- The `software_reset_cpu` now takes which CPU to reset as parameter. (#)
|
||||
|
||||
- I2C: Async functions are postfixed with `_async`, non-async functions are available in async-mode (#3056)
|
||||
|
||||
|
@ -534,7 +534,7 @@ impl<ADCI> crate::private::Sealed for Adc<'_, ADCI, Blocking> {}
|
||||
|
||||
impl<ADCI> InterruptConfigurable for Adc<'_, ADCI, Blocking> {
|
||||
fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
|
||||
for core in crate::Cpu::other() {
|
||||
for core in crate::system::Cpu::other() {
|
||||
crate::interrupt::disable(core, InterruptSource);
|
||||
}
|
||||
unsafe { crate::interrupt::bind_interrupt(InterruptSource, handler.handler()) };
|
||||
@ -643,7 +643,7 @@ where
|
||||
pub fn into_blocking(self) -> Adc<'d, ADCI, Blocking> {
|
||||
if asynch::release_async_adc() {
|
||||
// Disable ADC interrupt on all cores if the last async ADC instance is disabled
|
||||
for cpu in crate::Cpu::all() {
|
||||
for cpu in crate::system::Cpu::all() {
|
||||
crate::interrupt::disable(cpu, InterruptSource);
|
||||
}
|
||||
}
|
||||
|
@ -52,7 +52,7 @@ impl<'d> DebugAssist<'d> {
|
||||
/// handlers.
|
||||
#[instability::unstable]
|
||||
pub fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
|
||||
for core in crate::Cpu::other() {
|
||||
for core in crate::system::Cpu::other() {
|
||||
crate::interrupt::disable(core, Interrupt::ASSIST_DEBUG);
|
||||
}
|
||||
unsafe { crate::interrupt::bind_interrupt(Interrupt::ASSIST_DEBUG, handler.handler()) };
|
||||
|
@ -66,9 +66,9 @@ use crate::{
|
||||
peripherals::Interrupt,
|
||||
soc::{is_slice_in_dram, is_valid_memory_address, is_valid_ram_address},
|
||||
system,
|
||||
system::Cpu,
|
||||
Async,
|
||||
Blocking,
|
||||
Cpu,
|
||||
DriverMode,
|
||||
};
|
||||
|
||||
@ -1873,7 +1873,7 @@ where
|
||||
self.clear_in(EnumSet::all());
|
||||
|
||||
if let Some(interrupt) = self.rx_impl.peripheral_interrupt() {
|
||||
for core in crate::Cpu::other() {
|
||||
for core in crate::system::Cpu::other() {
|
||||
crate::interrupt::disable(core, interrupt);
|
||||
}
|
||||
unsafe { crate::interrupt::bind_interrupt(interrupt, handler.handler()) };
|
||||
@ -2168,7 +2168,7 @@ where
|
||||
self.clear_out(EnumSet::all());
|
||||
|
||||
if let Some(interrupt) = self.tx_impl.peripheral_interrupt() {
|
||||
for core in crate::Cpu::other() {
|
||||
for core in crate::system::Cpu::other() {
|
||||
crate::interrupt::disable(core, interrupt);
|
||||
}
|
||||
unsafe { crate::interrupt::bind_interrupt(interrupt, handler.handler()) };
|
||||
|
@ -992,7 +992,7 @@ impl<Dm: DriverMode> Ecc<'_, Dm> {
|
||||
/// handlers.
|
||||
#[instability::unstable]
|
||||
pub fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
|
||||
for core in crate::Cpu::other() {
|
||||
for core in crate::system::Cpu::other() {
|
||||
crate::interrupt::disable(core, Interrupt::ECC);
|
||||
}
|
||||
unsafe { crate::interrupt::bind_interrupt(Interrupt::ECC, handler.handler()) };
|
||||
|
@ -717,7 +717,8 @@ pub(crate) fn bind_default_interrupt_handler() {
|
||||
}
|
||||
// The vector table doesn't contain a custom entry.Still, the
|
||||
// peripheral interrupt may already be bound to something else.
|
||||
if interrupt::bound_cpu_interrupt_for(crate::Cpu::current(), Interrupt::GPIO).is_some() {
|
||||
if interrupt::bound_cpu_interrupt_for(crate::system::Cpu::current(), Interrupt::GPIO).is_some()
|
||||
{
|
||||
info!("Not using default GPIO interrupt handler: peripheral interrupt already in use");
|
||||
return;
|
||||
}
|
||||
@ -773,7 +774,7 @@ impl Io {
|
||||
/// `None`)
|
||||
#[instability::unstable]
|
||||
pub fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
|
||||
for core in crate::Cpu::other() {
|
||||
for core in crate::system::Cpu::other() {
|
||||
crate::interrupt::disable(core, Interrupt::GPIO);
|
||||
}
|
||||
self.set_interrupt_priority(handler.priority());
|
||||
|
@ -1332,7 +1332,7 @@ impl Info {
|
||||
}
|
||||
|
||||
fn set_interrupt_handler(&self, handler: InterruptHandler) {
|
||||
for core in crate::Cpu::other() {
|
||||
for core in crate::system::Cpu::other() {
|
||||
crate::interrupt::disable(core, self.interrupt);
|
||||
}
|
||||
self.enable_listen(EnumSet::all(), false);
|
||||
@ -1342,7 +1342,7 @@ impl Info {
|
||||
}
|
||||
|
||||
fn disable_interrupts(&self) {
|
||||
crate::interrupt::disable(crate::Cpu::current(), self.interrupt);
|
||||
crate::interrupt::disable(crate::system::Cpu::current(), self.interrupt);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1518,7 +1518,7 @@ mod private {
|
||||
|
||||
impl RegisterAccessPrivate for I2S0 {
|
||||
fn set_interrupt_handler(&self, handler: InterruptHandler) {
|
||||
for core in crate::Cpu::other() {
|
||||
for core in crate::system::Cpu::other() {
|
||||
crate::interrupt::disable(core, Interrupt::I2S0);
|
||||
}
|
||||
unsafe { crate::peripherals::I2S0::steal() }.bind_i2s0_interrupt(handler.handler());
|
||||
@ -1627,7 +1627,7 @@ mod private {
|
||||
#[cfg(i2s1)]
|
||||
impl RegisterAccessPrivate for I2S1 {
|
||||
fn set_interrupt_handler(&self, handler: InterruptHandler) {
|
||||
for core in crate::Cpu::other() {
|
||||
for core in crate::system::Cpu::other() {
|
||||
crate::interrupt::disable(core, Interrupt::I2S1);
|
||||
}
|
||||
unsafe { crate::peripherals::I2S1::steal() }.bind_i2s1_interrupt(handler.handler());
|
||||
|
@ -25,7 +25,7 @@ use super::InterruptStatus;
|
||||
use crate::{
|
||||
pac,
|
||||
peripherals::{Interrupt, INTERRUPT_CORE0},
|
||||
Cpu,
|
||||
system::Cpu,
|
||||
};
|
||||
|
||||
/// Interrupt Error
|
||||
@ -560,7 +560,7 @@ mod vectored {
|
||||
#[cfg(not(plic))]
|
||||
mod classic {
|
||||
use super::{CpuInterrupt, InterruptKind, Priority};
|
||||
use crate::{peripherals::INTERRUPT_CORE0, Cpu};
|
||||
use crate::{peripherals::INTERRUPT_CORE0, system::Cpu};
|
||||
|
||||
#[cfg_attr(place_switch_tables_in_ram, link_section = ".rwtext")]
|
||||
pub(super) static DISABLED_CPU_INTERRUPT: u32 = 0;
|
||||
@ -710,7 +710,7 @@ mod classic {
|
||||
#[cfg(plic)]
|
||||
mod plic {
|
||||
use super::{CpuInterrupt, InterruptKind, Priority};
|
||||
use crate::{peripherals::PLIC_MX, Cpu};
|
||||
use crate::{peripherals::PLIC_MX, system::Cpu};
|
||||
|
||||
#[cfg_attr(place_switch_tables_in_ram, link_section = ".rwtext")]
|
||||
pub(super) static DISABLED_CPU_INTERRUPT: u32 = 31;
|
||||
|
@ -66,7 +66,7 @@ impl<const NUM: u8> SoftwareInterrupt<NUM> {
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
for core in crate::Cpu::other() {
|
||||
for core in crate::system::Cpu::other() {
|
||||
crate::interrupt::disable(core, interrupt);
|
||||
}
|
||||
unsafe { crate::interrupt::bind_interrupt(interrupt, handler.handler()) };
|
||||
|
@ -6,7 +6,7 @@ use xtensa_lx_rt::exception::Context;
|
||||
|
||||
pub use self::vectored::*;
|
||||
use super::InterruptStatus;
|
||||
use crate::{pac, peripherals::Interrupt, Cpu};
|
||||
use crate::{pac, peripherals::Interrupt, system::Cpu};
|
||||
|
||||
/// Interrupt Error
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
|
@ -17,10 +17,9 @@ use crate::{
|
||||
lcd_cam::{cam::Cam, lcd::Lcd},
|
||||
peripheral::Peripheral,
|
||||
peripherals::{Interrupt, LCD_CAM},
|
||||
system::GenericPeripheralGuard,
|
||||
system::{Cpu, GenericPeripheralGuard},
|
||||
Async,
|
||||
Blocking,
|
||||
Cpu,
|
||||
};
|
||||
|
||||
/// Represents a combined LCD and Camera interface.
|
||||
@ -71,7 +70,7 @@ impl<'d> LcdCam<'d, Blocking> {
|
||||
/// handlers.
|
||||
#[instability::unstable]
|
||||
pub fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
|
||||
for core in crate::Cpu::other() {
|
||||
for core in crate::system::Cpu::other() {
|
||||
crate::interrupt::disable(core, Interrupt::LCD_CAM);
|
||||
}
|
||||
unsafe { crate::interrupt::bind_interrupt(Interrupt::LCD_CAM, handler.handler()) };
|
||||
|
@ -155,8 +155,6 @@ pub use esp_riscv_rt::{self, riscv};
|
||||
pub use xtensa_lx_rt::{self, xtensa_lx};
|
||||
|
||||
// TODO what should we reexport stably?
|
||||
#[cfg(any(esp32, esp32s3))]
|
||||
pub use self::soc::cpu_control;
|
||||
#[cfg(efuse)]
|
||||
#[instability::unstable]
|
||||
#[cfg_attr(not(feature = "unstable"), allow(unused))]
|
||||
@ -186,6 +184,7 @@ pub mod peripheral;
|
||||
mod reg_access;
|
||||
#[cfg(any(spi0, spi1, spi2, spi3))]
|
||||
pub mod spi;
|
||||
pub mod system;
|
||||
pub mod time;
|
||||
#[cfg(any(uart0, uart1, uart2))]
|
||||
pub mod uart;
|
||||
@ -262,8 +261,6 @@ unstable_module! {
|
||||
pub mod parl_io;
|
||||
#[cfg(pcnt)]
|
||||
pub mod pcnt;
|
||||
#[cfg(any(lp_clkrst, rtc_cntl))]
|
||||
pub mod reset;
|
||||
#[cfg(rmt)]
|
||||
pub mod rmt;
|
||||
#[cfg(rng)]
|
||||
@ -277,8 +274,6 @@ unstable_module! {
|
||||
pub mod sha;
|
||||
#[doc(hidden)]
|
||||
pub mod sync;
|
||||
#[cfg(any(dport, hp_sys, pcr, system))]
|
||||
pub mod system;
|
||||
#[cfg(any(systimer, timg0, timg1))]
|
||||
pub mod timer;
|
||||
#[cfg(touch)]
|
||||
@ -294,6 +289,8 @@ unstable_module! {
|
||||
}
|
||||
|
||||
/// State of the CPU saved when entering exception or interrupt
|
||||
#[instability::unstable]
|
||||
#[allow(unused_imports)]
|
||||
pub mod trapframe {
|
||||
#[cfg(riscv)]
|
||||
pub use esp_riscv_rt::TrapFrame;
|
||||
@ -404,97 +401,6 @@ pub mod __macro_implementation {
|
||||
pub use xtensa_lx_rt::entry as __entry;
|
||||
}
|
||||
|
||||
/// Available CPU cores
|
||||
///
|
||||
/// The actual number of available cores depends on the target.
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, strum::FromRepr)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
#[repr(C)]
|
||||
pub enum Cpu {
|
||||
/// The first core
|
||||
ProCpu = 0,
|
||||
/// The second core
|
||||
#[cfg(multi_core)]
|
||||
AppCpu = 1,
|
||||
}
|
||||
|
||||
impl Cpu {
|
||||
/// The number of available cores.
|
||||
pub const COUNT: usize = 1 + cfg!(multi_core) as usize;
|
||||
|
||||
/// Returns the core the application is currently executing on
|
||||
#[inline(always)]
|
||||
pub fn current() -> Self {
|
||||
// This works for both RISCV and Xtensa because both
|
||||
// get_raw_core functions return zero, _or_ something
|
||||
// greater than zero; 1 in the case of RISCV and 0x2000
|
||||
// in the case of Xtensa.
|
||||
match raw_core() {
|
||||
0 => Cpu::ProCpu,
|
||||
#[cfg(all(multi_core, riscv))]
|
||||
1 => Cpu::AppCpu,
|
||||
#[cfg(all(multi_core, xtensa))]
|
||||
0x2000 => Cpu::AppCpu,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns an iterator over the "other" cores.
|
||||
#[inline(always)]
|
||||
pub(crate) fn other() -> impl Iterator<Item = Self> {
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(multi_core)] {
|
||||
match Self::current() {
|
||||
Cpu::ProCpu => [Cpu::AppCpu].into_iter(),
|
||||
Cpu::AppCpu => [Cpu::ProCpu].into_iter(),
|
||||
}
|
||||
} else {
|
||||
[].into_iter()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns an iterator over all cores.
|
||||
#[inline(always)]
|
||||
pub(crate) fn all() -> impl Iterator<Item = Self> {
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(multi_core)] {
|
||||
[Cpu::ProCpu, Cpu::AppCpu].into_iter()
|
||||
} else {
|
||||
[Cpu::ProCpu].into_iter()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the raw value of the mhartid register.
|
||||
///
|
||||
/// Safety: This method should never return UNUSED_THREAD_ID_VALUE
|
||||
#[cfg(riscv)]
|
||||
#[inline(always)]
|
||||
fn raw_core() -> usize {
|
||||
#[cfg(multi_core)]
|
||||
{
|
||||
riscv::register::mhartid::read()
|
||||
}
|
||||
|
||||
#[cfg(not(multi_core))]
|
||||
0
|
||||
}
|
||||
|
||||
/// Returns the result of reading the PRID register logically ANDed with 0x2000,
|
||||
/// the 13th bit in the register. Espressif Xtensa chips use this bit to
|
||||
/// determine the core id.
|
||||
///
|
||||
/// Returns either 0 or 0x2000
|
||||
///
|
||||
/// Safety: This method should never return UNUSED_THREAD_ID_VALUE
|
||||
#[cfg(xtensa)]
|
||||
#[inline(always)]
|
||||
fn raw_core() -> usize {
|
||||
(xtensa_lx::get_processor_id() & 0x2000) as usize
|
||||
}
|
||||
|
||||
#[cfg(riscv)]
|
||||
#[export_name = "hal_main"]
|
||||
fn hal_main(a0: usize, a1: usize, a2: usize) -> ! {
|
||||
|
@ -147,7 +147,7 @@ pub mod asynch {
|
||||
use procmacros::handler;
|
||||
|
||||
use super::*;
|
||||
use crate::Cpu;
|
||||
use crate::system::Cpu;
|
||||
|
||||
// From ESP32-S3 TRM:
|
||||
// Six additional endpoints (endpoint numbers 1 to 6), configurable as IN or OUT
|
||||
|
@ -985,7 +985,7 @@ fn internal_set_interrupt_handler(handler: InterruptHandler) {
|
||||
let mut peri = unsafe { PARL_IO::steal() };
|
||||
#[cfg(esp32c6)]
|
||||
{
|
||||
for core in crate::Cpu::other() {
|
||||
for core in crate::system::Cpu::other() {
|
||||
crate::interrupt::disable(core, Interrupt::PARL_IO);
|
||||
}
|
||||
internal_listen(EnumSet::all(), false);
|
||||
@ -999,7 +999,7 @@ fn internal_set_interrupt_handler(handler: InterruptHandler) {
|
||||
}
|
||||
#[cfg(esp32h2)]
|
||||
{
|
||||
for core in crate::Cpu::other() {
|
||||
for core in crate::system::Cpu::other() {
|
||||
crate::interrupt::disable(core, Interrupt::PARL_IO_RX);
|
||||
crate::interrupt::disable(core, Interrupt::PARL_IO_TX);
|
||||
}
|
||||
@ -1107,7 +1107,7 @@ impl<'d> ParlIoFullDuplex<'d, Blocking> {
|
||||
|
||||
/// Convert to an async version.
|
||||
pub fn into_async(self) -> ParlIoFullDuplex<'d, Async> {
|
||||
for core in crate::Cpu::other() {
|
||||
for core in crate::system::Cpu::other() {
|
||||
#[cfg(esp32c6)]
|
||||
{
|
||||
crate::interrupt::disable(core, Interrupt::PARL_IO);
|
||||
@ -1244,7 +1244,7 @@ impl<'d> ParlIoTxOnly<'d, Blocking> {
|
||||
|
||||
/// Converts to Async mode.
|
||||
pub fn into_async(self) -> ParlIoTxOnly<'d, Async> {
|
||||
for core in crate::Cpu::other() {
|
||||
for core in crate::system::Cpu::other() {
|
||||
#[cfg(esp32c6)]
|
||||
{
|
||||
crate::interrupt::disable(core, Interrupt::PARL_IO);
|
||||
@ -1372,7 +1372,7 @@ impl<'d> ParlIoRxOnly<'d, Blocking> {
|
||||
|
||||
/// Converts to Async mode.
|
||||
pub fn into_async(self) -> ParlIoRxOnly<'d, Async> {
|
||||
for core in crate::Cpu::other() {
|
||||
for core in crate::system::Cpu::other() {
|
||||
#[cfg(esp32c6)]
|
||||
{
|
||||
crate::interrupt::disable(core, Interrupt::PARL_IO);
|
||||
|
@ -188,7 +188,7 @@ impl<'d> Pcnt<'d> {
|
||||
/// handlers.
|
||||
#[instability::unstable]
|
||||
pub fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
|
||||
for core in crate::Cpu::other() {
|
||||
for core in crate::system::Cpu::other() {
|
||||
crate::interrupt::disable(core, Interrupt::PCNT);
|
||||
}
|
||||
unsafe { interrupt::bind_interrupt(Interrupt::PCNT, handler.handler()) };
|
||||
|
@ -1,112 +0,0 @@
|
||||
//! # Hardware and Software Reset
|
||||
//!
|
||||
//! ## Overview
|
||||
//! Espressif chips provide four types of reset that occur at different levels,
|
||||
//! namely CPU Reset, Core Reset, System Reset, and Chip Reset. All reset types
|
||||
//! mentioned above (except Chip Reset) preserve the data stored in internal
|
||||
//! memory.
|
||||
//!
|
||||
//! The Hardware and Software Reset module provides functions for
|
||||
//! performing hardware and software resets and includes functions for
|
||||
//! retrieving the reset reason and the wakeup cause after a reset.
|
||||
//!
|
||||
//! The module defines a set of sleep sources (`SleepSource`) that indicate the
|
||||
//! source of the wakeup event. It also includes a set of flags (`WakeupReason`)
|
||||
//! that represent different wakeup sources and enable/disable wakeup triggers
|
||||
//! for specific events.
|
||||
|
||||
use crate::rtc_cntl::SocResetReason;
|
||||
|
||||
/// Source of the wakeup event
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub enum SleepSource {
|
||||
/// In case of deep sleep, reset was not caused by exit from deep sleep
|
||||
Undefined = 0,
|
||||
/// Not a wakeup cause, used to disable all wakeup sources with
|
||||
/// esp_sleep_disable_wakeup_source
|
||||
All,
|
||||
/// Wakeup caused by external signal using RTC_IO
|
||||
Ext0,
|
||||
/// Wakeup caused by external signal using RTC_CNTL
|
||||
Ext1,
|
||||
/// Wakeup caused by timer
|
||||
Timer,
|
||||
/// Wakeup caused by touchpad
|
||||
TouchPad,
|
||||
/// Wakeup caused by ULP program
|
||||
Ulp,
|
||||
/// Wakeup caused by GPIO (light sleep only on ESP32, S2 and S3)
|
||||
Gpio,
|
||||
/// Wakeup caused by UART (light sleep only)
|
||||
Uart,
|
||||
/// Wakeup caused by WIFI (light sleep only)
|
||||
Wifi,
|
||||
/// Wakeup caused by COCPU int
|
||||
Cocpu,
|
||||
/// Wakeup caused by COCPU crash
|
||||
CocpuTrapTrig,
|
||||
/// Wakeup caused by BT (light sleep only)
|
||||
BT,
|
||||
}
|
||||
|
||||
bitflags::bitflags! {
|
||||
#[allow(unused)]
|
||||
pub(crate) struct WakeupReason: u32 {
|
||||
const NoSleep = 0;
|
||||
#[cfg(pm_support_ext0_wakeup)]
|
||||
/// EXT0 GPIO wakeup
|
||||
const ExtEvent0Trig = 1 << 0;
|
||||
#[cfg(pm_support_ext1_wakeup)]
|
||||
/// EXT1 GPIO wakeup
|
||||
const ExtEvent1Trig = 1 << 1;
|
||||
/// GPIO wakeup (light sleep only)
|
||||
const GpioTrigEn = 1 << 2;
|
||||
#[cfg(not(any(esp32c6, esp32h2)))]
|
||||
/// Timer wakeup
|
||||
const TimerTrigEn = 1 << 3;
|
||||
#[cfg(any(esp32c6, esp32h2))]
|
||||
/// Timer wakeup
|
||||
const TimerTrigEn = 1 << 4;
|
||||
#[cfg(pm_support_wifi_wakeup)]
|
||||
/// MAC wakeup (light sleep only)
|
||||
const WifiTrigEn = 1 << 5;
|
||||
/// UART0 wakeup (light sleep only)
|
||||
const Uart0TrigEn = 1 << 6;
|
||||
/// UART1 wakeup (light sleep only)
|
||||
const Uart1TrigEn = 1 << 7;
|
||||
#[cfg(pm_support_touch_sensor_wakeup)]
|
||||
/// Touch wakeup
|
||||
const TouchTrigEn = 1 << 8;
|
||||
#[cfg(ulp_supported)]
|
||||
/// ULP wakeup
|
||||
const UlpTrigEn = 1 << 9;
|
||||
#[cfg(pm_support_bt_wakeup)]
|
||||
/// BT wakeup (light sleep only)
|
||||
const BtTrigEn = 1 << 10;
|
||||
#[cfg(riscv_coproc_supported)]
|
||||
const CocpuTrigEn = 1 << 11;
|
||||
#[cfg(riscv_coproc_supported)]
|
||||
const CocpuTrapTrigEn = 1 << 13;
|
||||
}
|
||||
}
|
||||
|
||||
/// Performs a software reset on the chip.
|
||||
pub fn software_reset() {
|
||||
crate::rom::software_reset();
|
||||
}
|
||||
|
||||
/// Performs a software reset on the CPU.
|
||||
pub fn software_reset_cpu() {
|
||||
crate::rom::software_reset_cpu();
|
||||
}
|
||||
|
||||
/// Retrieves the reason for the last reset as a SocResetReason enum value.
|
||||
/// Returns `None` if the reset reason cannot be determined.
|
||||
pub fn reset_reason() -> Option<SocResetReason> {
|
||||
crate::rtc_cntl::reset_reason(crate::Cpu::current())
|
||||
}
|
||||
|
||||
/// Retrieves the cause of the last wakeup event as a SleepSource enum value.
|
||||
pub fn wakeup_cause() -> SleepSource {
|
||||
crate::rtc_cntl::wakeup_cause()
|
||||
}
|
@ -449,7 +449,7 @@ impl<'d> Rmt<'d, Blocking> {
|
||||
/// handlers.
|
||||
#[instability::unstable]
|
||||
pub fn set_interrupt_handler(&mut self, handler: crate::interrupt::InterruptHandler) {
|
||||
for core in crate::Cpu::other() {
|
||||
for core in crate::system::Cpu::other() {
|
||||
crate::interrupt::disable(core, Interrupt::RMT);
|
||||
}
|
||||
unsafe { crate::interrupt::bind_interrupt(Interrupt::RMT, handler.handler()) };
|
||||
|
@ -113,21 +113,21 @@ pub(crate) fn rtc_get_reset_reason(cpu_num: u32) -> u32 {
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub(crate) fn software_reset_cpu() {
|
||||
pub(crate) fn software_reset_cpu(cpu_num: u32) {
|
||||
extern "C" {
|
||||
fn software_reset_cpu();
|
||||
fn software_reset_cpu(cpu_num: u32);
|
||||
}
|
||||
|
||||
unsafe { software_reset_cpu() };
|
||||
unsafe { software_reset_cpu(cpu_num) };
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub(crate) fn software_reset() {
|
||||
pub(crate) fn software_reset() -> ! {
|
||||
extern "C" {
|
||||
fn software_reset();
|
||||
fn software_reset() -> !;
|
||||
}
|
||||
|
||||
unsafe { software_reset() };
|
||||
unsafe { software_reset() }
|
||||
}
|
||||
|
||||
#[cfg(esp32s3)]
|
||||
|
@ -28,10 +28,9 @@ use crate::{
|
||||
pac,
|
||||
peripheral::{Peripheral, PeripheralRef},
|
||||
peripherals::{Interrupt, RSA},
|
||||
system::{GenericPeripheralGuard, Peripheral as PeripheralEnable},
|
||||
system::{Cpu, GenericPeripheralGuard, Peripheral as PeripheralEnable},
|
||||
Async,
|
||||
Blocking,
|
||||
Cpu,
|
||||
};
|
||||
|
||||
#[cfg_attr(esp32s2, path = "esp32sX.rs")]
|
||||
@ -75,7 +74,7 @@ impl<'d> Rsa<'d, Blocking> {
|
||||
/// handlers.
|
||||
#[instability::unstable]
|
||||
pub fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
|
||||
for core in crate::Cpu::other() {
|
||||
for core in crate::system::Cpu::other() {
|
||||
crate::interrupt::disable(core, Interrupt::RSA);
|
||||
}
|
||||
unsafe { crate::interrupt::bind_interrupt(Interrupt::RSA, handler.handler()) };
|
||||
|
@ -126,9 +126,8 @@ use crate::{
|
||||
interrupt::{self, InterruptHandler},
|
||||
peripheral::{Peripheral, PeripheralRef},
|
||||
peripherals::Interrupt,
|
||||
reset::{SleepSource, WakeupReason},
|
||||
system::{Cpu, SleepSource},
|
||||
time::Duration,
|
||||
Cpu,
|
||||
};
|
||||
#[cfg(not(any(esp32c6, esp32h2)))]
|
||||
use crate::{
|
||||
@ -160,6 +159,47 @@ cfg_if::cfg_if! {
|
||||
}
|
||||
}
|
||||
|
||||
bitflags::bitflags! {
|
||||
#[allow(unused)]
|
||||
struct WakeupReason: u32 {
|
||||
const NoSleep = 0;
|
||||
#[cfg(pm_support_ext0_wakeup)]
|
||||
/// EXT0 GPIO wakeup
|
||||
const ExtEvent0Trig = 1 << 0;
|
||||
#[cfg(pm_support_ext1_wakeup)]
|
||||
/// EXT1 GPIO wakeup
|
||||
const ExtEvent1Trig = 1 << 1;
|
||||
/// GPIO wakeup (light sleep only)
|
||||
const GpioTrigEn = 1 << 2;
|
||||
#[cfg(not(any(esp32c6, esp32h2)))]
|
||||
/// Timer wakeup
|
||||
const TimerTrigEn = 1 << 3;
|
||||
#[cfg(any(esp32c6, esp32h2))]
|
||||
/// Timer wakeup
|
||||
const TimerTrigEn = 1 << 4;
|
||||
#[cfg(pm_support_wifi_wakeup)]
|
||||
/// MAC wakeup (light sleep only)
|
||||
const WifiTrigEn = 1 << 5;
|
||||
/// UART0 wakeup (light sleep only)
|
||||
const Uart0TrigEn = 1 << 6;
|
||||
/// UART1 wakeup (light sleep only)
|
||||
const Uart1TrigEn = 1 << 7;
|
||||
#[cfg(pm_support_touch_sensor_wakeup)]
|
||||
/// Touch wakeup
|
||||
const TouchTrigEn = 1 << 8;
|
||||
#[cfg(ulp_supported)]
|
||||
/// ULP wakeup
|
||||
const UlpTrigEn = 1 << 9;
|
||||
#[cfg(pm_support_bt_wakeup)]
|
||||
/// BT wakeup (light sleep only)
|
||||
const BtTrigEn = 1 << 10;
|
||||
#[cfg(riscv_coproc_supported)]
|
||||
const CocpuTrigEn = 1 << 11;
|
||||
#[cfg(riscv_coproc_supported)]
|
||||
const CocpuTrapTrigEn = 1 << 13;
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(any(esp32c6, esp32h2)))]
|
||||
#[allow(unused)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
@ -474,7 +514,7 @@ impl<'d> Rtc<'d> {
|
||||
let interrupt = Interrupt::RTC_CORE;
|
||||
}
|
||||
}
|
||||
for core in crate::Cpu::other() {
|
||||
for core in crate::system::Cpu::other() {
|
||||
crate::interrupt::disable(core, interrupt);
|
||||
}
|
||||
unsafe { interrupt::bind_interrupt(interrupt, handler.handler()) };
|
||||
|
@ -56,7 +56,7 @@ pub enum WakeupLevel {
|
||||
/// # use core::time::Duration;
|
||||
/// # use esp_hal::delay::Delay;
|
||||
/// # use esp_hal::rtc_cntl::{reset_reason, sleep::TimerWakeupSource, wakeup_cause, Rtc, SocResetReason};
|
||||
/// # use esp_hal::Cpu;
|
||||
/// # use esp_hal::system::Cpu;
|
||||
///
|
||||
/// let delay = Delay::new();
|
||||
/// let mut rtc = Rtc::new(peripherals.LPWR);
|
||||
@ -104,7 +104,7 @@ pub enum Error {
|
||||
/// # use core::time::Duration;
|
||||
/// # use esp_hal::delay::Delay;
|
||||
/// # use esp_hal::rtc_cntl::{reset_reason, sleep::{Ext0WakeupSource, TimerWakeupSource, WakeupLevel}, wakeup_cause, Rtc, SocResetReason};
|
||||
/// # use esp_hal::Cpu;
|
||||
/// # use esp_hal::system::Cpu;
|
||||
/// # use esp_hal::gpio::{Input, InputConfig, Pull};
|
||||
///
|
||||
/// let delay = Delay::new();
|
||||
@ -157,7 +157,7 @@ impl<'a, P: RtcIoWakeupPinType> Ext0WakeupSource<'a, P> {
|
||||
/// # use core::time::Duration;
|
||||
/// # use esp_hal::delay::Delay;
|
||||
/// # use esp_hal::rtc_cntl::{reset_reason, sleep::{Ext1WakeupSource, TimerWakeupSource, WakeupLevel}, wakeup_cause, Rtc, SocResetReason};
|
||||
/// # use esp_hal::Cpu;
|
||||
/// # use esp_hal::system::Cpu;
|
||||
/// # use esp_hal::gpio::{Input, InputConfig, Pull, RtcPin};
|
||||
/// # use esp_hal::peripheral::Peripheral;
|
||||
///
|
||||
@ -214,7 +214,7 @@ impl<'a, 'b> Ext1WakeupSource<'a, 'b> {
|
||||
/// # use core::time::Duration;
|
||||
/// # use esp_hal::delay::Delay;
|
||||
/// # use esp_hal::rtc_cntl::{reset_reason, sleep::{Ext1WakeupSource, TimerWakeupSource, WakeupLevel}, wakeup_cause, Rtc, SocResetReason};
|
||||
/// # use esp_hal::Cpu;
|
||||
/// # use esp_hal::system::Cpu;
|
||||
/// # use esp_hal::gpio::{Input, InputConfig, Pull, RtcPinWithResistors};
|
||||
/// # use esp_hal::peripheral::Peripheral;
|
||||
///
|
||||
@ -276,7 +276,7 @@ impl<'a, 'b> Ext1WakeupSource<'a, 'b> {
|
||||
/// # use esp_hal::delay::Delay;
|
||||
/// # use esp_hal::gpio::{self, Input, InputConfig, Pull};
|
||||
/// # use esp_hal::rtc_cntl::{reset_reason, sleep::{RtcioWakeupSource, TimerWakeupSource, WakeupLevel}, wakeup_cause, Rtc, SocResetReason};
|
||||
/// # use esp_hal::Cpu;
|
||||
/// # use esp_hal::system::Cpu;
|
||||
/// # use esp_hal::peripheral::Peripheral;
|
||||
///
|
||||
/// let mut rtc = Rtc::new(peripherals.LPWR);
|
||||
|
@ -111,7 +111,7 @@ impl crate::private::Sealed for Sha<'_> {}
|
||||
#[instability::unstable]
|
||||
impl crate::interrupt::InterruptConfigurable for Sha<'_> {
|
||||
fn set_interrupt_handler(&mut self, handler: crate::interrupt::InterruptHandler) {
|
||||
for core in crate::Cpu::other() {
|
||||
for core in crate::system::Cpu::other() {
|
||||
crate::interrupt::disable(core, Interrupt::SHA);
|
||||
}
|
||||
unsafe { crate::interrupt::bind_interrupt(Interrupt::SHA, handler.handler()) };
|
||||
|
@ -4,53 +4,6 @@
|
||||
//! This module provides essential functionality for controlling
|
||||
//! and managing the APP (second) CPU core on the `ESP32` chip. It is used to
|
||||
//! start and stop program execution on the APP core.
|
||||
//!
|
||||
//! ## Examples
|
||||
//! ```rust, no_run
|
||||
#![doc = crate::before_snippet!()]
|
||||
//! # use esp_hal::delay::Delay;
|
||||
//! # use esp_hal::cpu_control::{CpuControl, Stack};
|
||||
//! # use core::{cell::RefCell, ptr::addr_of_mut};
|
||||
//! # use critical_section::Mutex;
|
||||
//! static mut APP_CORE_STACK: Stack<8192> = Stack::new();
|
||||
//!
|
||||
//! # let delay = Delay::new();
|
||||
//!
|
||||
//! let counter = Mutex::new(RefCell::new(0));
|
||||
//!
|
||||
//! let mut cpu_control = CpuControl::new(peripherals.CPU_CTRL);
|
||||
//! let cpu1_fnctn = || {
|
||||
//! cpu1_task(&delay, &counter);
|
||||
//! };
|
||||
//! let _guard = cpu_control
|
||||
//! .start_app_core(
|
||||
//! unsafe { &mut *addr_of_mut!(APP_CORE_STACK) },
|
||||
//! cpu1_fnctn
|
||||
//! )?;
|
||||
//!
|
||||
//! loop {
|
||||
//! delay.delay(Duration::from_secs(1));
|
||||
//! let count = critical_section::with(|cs| *counter.borrow_ref(cs));
|
||||
//! }
|
||||
//! # }
|
||||
//!
|
||||
//! // Where `cpu1_task()` may be defined as:
|
||||
//! # use esp_hal::delay::Delay;
|
||||
//! # use core::cell::RefCell;
|
||||
//! fn cpu1_task(
|
||||
//! delay: &Delay,
|
||||
//! counter: &critical_section::Mutex<RefCell<i32>>,
|
||||
//! ) -> ! {
|
||||
//! loop {
|
||||
//! delay.delay(Duration::from_millis(500));
|
||||
//!
|
||||
//! critical_section::with(|cs| {
|
||||
//! let mut val = counter.borrow_ref_mut(cs);
|
||||
//! *val = val.wrapping_add(1);
|
||||
//! });
|
||||
//! }
|
||||
//! }
|
||||
//! ```
|
||||
|
||||
use core::{
|
||||
marker::PhantomData,
|
||||
@ -60,7 +13,7 @@ use core::{
|
||||
use crate::{
|
||||
peripheral::{Peripheral, PeripheralRef},
|
||||
peripherals::{CPU_CTRL, DPORT, LPWR, SPI0},
|
||||
Cpu,
|
||||
system::Cpu,
|
||||
};
|
||||
|
||||
/// Data type for a properly aligned stack of N bytes
|
||||
@ -77,6 +30,7 @@ use crate::{
|
||||
// Stack frame alignment depends on the SIZE as well as the placement of the
|
||||
// array.
|
||||
#[repr(C, align(16))]
|
||||
#[instability::unstable]
|
||||
pub struct Stack<const SIZE: usize> {
|
||||
/// Memory to be used for the stack
|
||||
pub mem: MaybeUninit<[u8; SIZE]>,
|
||||
@ -91,6 +45,7 @@ impl<const SIZE: usize> Default for Stack<SIZE> {
|
||||
#[allow(clippy::len_without_is_empty)]
|
||||
impl<const SIZE: usize> Stack<SIZE> {
|
||||
/// Construct a stack of length SIZE, uninitialized
|
||||
#[instability::unstable]
|
||||
pub const fn new() -> Stack<SIZE> {
|
||||
::core::assert!(SIZE % 16 == 0); // Make sure stack top is aligned, too.
|
||||
|
||||
@ -99,17 +54,20 @@ impl<const SIZE: usize> Stack<SIZE> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the size of the stack.
|
||||
/// Returns the length of the stack in bytes.
|
||||
#[instability::unstable]
|
||||
pub const fn len(&self) -> usize {
|
||||
SIZE
|
||||
}
|
||||
|
||||
/// Provides a mutable pointer to the bottom of the stack.
|
||||
/// Returns a mutable pointer to the bottom of the stack.
|
||||
#[instability::unstable]
|
||||
pub fn bottom(&mut self) -> *mut u32 {
|
||||
self.mem.as_mut_ptr() as *mut u32
|
||||
}
|
||||
|
||||
/// Provides a mutable pointer to the top of the stack.
|
||||
/// Returns a mutable pointer to the top of the stack.
|
||||
#[instability::unstable]
|
||||
pub fn top(&mut self) -> *mut u32 {
|
||||
unsafe { self.bottom().add(SIZE / 4) }
|
||||
}
|
||||
@ -118,53 +76,102 @@ impl<const SIZE: usize> Stack<SIZE> {
|
||||
// Pointer to the closure that will be executed on the second core. The closure
|
||||
// is copied to the core's stack.
|
||||
static mut START_CORE1_FUNCTION: Option<*mut ()> = None;
|
||||
|
||||
static mut APP_CORE_STACK_TOP: Option<*mut u32> = None;
|
||||
|
||||
/// Will park the APP (second) core when dropped
|
||||
#[must_use]
|
||||
#[must_use = "Dropping this guard will park the APP core"]
|
||||
#[instability::unstable]
|
||||
pub struct AppCoreGuard<'a> {
|
||||
phantom: PhantomData<&'a ()>,
|
||||
}
|
||||
|
||||
impl Drop for AppCoreGuard<'_> {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
internal_park_core(Cpu::AppCpu);
|
||||
}
|
||||
unsafe { internal_park_core(Cpu::AppCpu, true) };
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents errors that can occur while working with the core.
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
#[instability::unstable]
|
||||
pub enum Error {
|
||||
/// The core is already running.
|
||||
CoreAlreadyRunning,
|
||||
}
|
||||
|
||||
/// Control CPU Cores
|
||||
///
|
||||
/// ## Examples
|
||||
/// ```rust, no_run
|
||||
#[doc = crate::before_snippet!()]
|
||||
/// # use esp_hal::delay::Delay;
|
||||
/// # use esp_hal::system::{CpuControl, Stack};
|
||||
/// # use core::{cell::RefCell, ptr::addr_of_mut};
|
||||
/// # use critical_section::Mutex;
|
||||
/// # let delay = Delay::new();
|
||||
/// static mut APP_CORE_STACK: Stack<8192> = Stack::new();
|
||||
///
|
||||
/// let counter = Mutex::new(RefCell::new(0));
|
||||
///
|
||||
/// let mut cpu_control = CpuControl::new(peripherals.CPU_CTRL);
|
||||
/// let cpu1_fnctn = || {
|
||||
/// cpu1_task(&delay, &counter);
|
||||
/// };
|
||||
/// let _guard = cpu_control
|
||||
/// .start_app_core(
|
||||
/// unsafe { &mut *addr_of_mut!(APP_CORE_STACK) },
|
||||
/// cpu1_fnctn
|
||||
/// )?;
|
||||
///
|
||||
/// loop {
|
||||
/// delay.delay(Duration::from_secs(1));
|
||||
/// let count = critical_section::with(|cs| *counter.borrow_ref(cs));
|
||||
/// }
|
||||
/// # }
|
||||
///
|
||||
/// // Where `cpu1_task()` may be defined as:
|
||||
/// # use esp_hal::delay::Delay;
|
||||
/// # use core::cell::RefCell;
|
||||
///
|
||||
/// fn cpu1_task(
|
||||
/// delay: &Delay,
|
||||
/// counter: &critical_section::Mutex<RefCell<i32>>,
|
||||
/// ) -> ! {
|
||||
/// loop {
|
||||
/// delay.delay(Duration::from_millis(500));
|
||||
///
|
||||
/// critical_section::with(|cs| {
|
||||
/// let mut val = counter.borrow_ref_mut(cs);
|
||||
/// *val = val.wrapping_add(1);
|
||||
/// });
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
#[instability::unstable]
|
||||
pub struct CpuControl<'d> {
|
||||
_cpu_control: PeripheralRef<'d, CPU_CTRL>,
|
||||
}
|
||||
|
||||
unsafe fn internal_park_core(core: Cpu) {
|
||||
unsafe fn internal_park_core(core: Cpu, park: bool) {
|
||||
let c1_value = if park { 0x21 } else { 0 };
|
||||
let c0_value = if park { 0x02 } else { 0 };
|
||||
match core {
|
||||
Cpu::ProCpu => {
|
||||
LPWR::regs()
|
||||
.sw_cpu_stall()
|
||||
.modify(|_, w| w.sw_stall_procpu_c1().bits(0x21));
|
||||
.modify(|_, w| w.sw_stall_procpu_c1().bits(c1_value));
|
||||
LPWR::regs()
|
||||
.options0()
|
||||
.modify(|_, w| w.sw_stall_procpu_c0().bits(0x02));
|
||||
.modify(|_, w| w.sw_stall_procpu_c0().bits(c0_value));
|
||||
}
|
||||
Cpu::AppCpu => {
|
||||
LPWR::regs()
|
||||
.sw_cpu_stall()
|
||||
.modify(|_, w| w.sw_stall_appcpu_c1().bits(0x21));
|
||||
.modify(|_, w| w.sw_stall_appcpu_c1().bits(c1_value));
|
||||
LPWR::regs()
|
||||
.options0()
|
||||
.modify(|_, w| w.sw_stall_appcpu_c0().bits(0x02));
|
||||
.modify(|_, w| w.sw_stall_appcpu_c0().bits(c0_value));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -186,30 +193,15 @@ impl<'d> CpuControl<'d> {
|
||||
///
|
||||
/// The user must ensure that the core being parked is not the core which is
|
||||
/// currently executing their code.
|
||||
#[instability::unstable]
|
||||
pub unsafe fn park_core(&mut self, core: Cpu) {
|
||||
internal_park_core(core);
|
||||
internal_park_core(core, true);
|
||||
}
|
||||
|
||||
/// Unpark the given core
|
||||
#[instability::unstable]
|
||||
pub fn unpark_core(&mut self, core: Cpu) {
|
||||
match core {
|
||||
Cpu::ProCpu => {
|
||||
LPWR::regs()
|
||||
.sw_cpu_stall()
|
||||
.modify(|_, w| unsafe { w.sw_stall_procpu_c1().bits(0) });
|
||||
LPWR::regs()
|
||||
.options0()
|
||||
.modify(|_, w| unsafe { w.sw_stall_procpu_c0().bits(0) });
|
||||
}
|
||||
Cpu::AppCpu => {
|
||||
LPWR::regs()
|
||||
.sw_cpu_stall()
|
||||
.modify(|_, w| unsafe { w.sw_stall_appcpu_c1().bits(0) });
|
||||
LPWR::regs()
|
||||
.options0()
|
||||
.modify(|_, w| unsafe { w.sw_stall_appcpu_c0().bits(0) });
|
||||
}
|
||||
}
|
||||
unsafe { internal_park_core(core, false) };
|
||||
}
|
||||
|
||||
fn flush_cache(&mut self, core: Cpu) {
|
||||
@ -323,7 +315,7 @@ impl<'d> CpuControl<'d> {
|
||||
let entry = unsafe { ManuallyDrop::take(&mut *entry.cast::<ManuallyDrop<F>>()) };
|
||||
entry();
|
||||
loop {
|
||||
unsafe { internal_park_core(Cpu::current()) };
|
||||
unsafe { internal_park_core(Cpu::current(), true) };
|
||||
}
|
||||
}
|
||||
None => panic!("No start function set"),
|
||||
@ -336,6 +328,7 @@ impl<'d> CpuControl<'d> {
|
||||
/// closure exits, the core will be parked.
|
||||
///
|
||||
/// Dropping the returned guard will park the core.
|
||||
#[instability::unstable]
|
||||
pub fn start_app_core<'a, const SIZE: usize, F>(
|
||||
&mut self,
|
||||
stack: &'static mut Stack<SIZE>,
|
||||
|
@ -46,7 +46,7 @@ use crate::{
|
||||
gpio::{AlternateFunction, GpioPin},
|
||||
pac::io_mux,
|
||||
peripherals::{GPIO, IO_MUX},
|
||||
Cpu,
|
||||
system::Cpu,
|
||||
};
|
||||
|
||||
/// The total number of GPIO pins available.
|
||||
|
@ -97,7 +97,7 @@ pub unsafe extern "C" fn ESP32Reset() -> ! {
|
||||
addr_of_mut!(_rtc_slow_bss_end),
|
||||
);
|
||||
if matches!(
|
||||
crate::reset::reset_reason(),
|
||||
crate::system::reset_reason(),
|
||||
None | Some(SocResetReason::ChipPowerOn)
|
||||
) {
|
||||
xtensa_lx_rt::zero_bss(
|
||||
|
@ -101,7 +101,7 @@ pub unsafe extern "C" fn ESP32Reset() -> ! {
|
||||
addr_of_mut!(_rtc_slow_bss_end),
|
||||
);
|
||||
if matches!(
|
||||
crate::reset::reset_reason(),
|
||||
crate::system::reset_reason(),
|
||||
None | Some(SocResetReason::ChipPowerOn)
|
||||
) {
|
||||
xtensa_lx_rt::zero_bss(
|
||||
|
@ -5,53 +5,6 @@
|
||||
//! This module provides essential functionality for controlling
|
||||
//! and managing the APP (second) CPU core on the `ESP32-S3` chip. It is used to
|
||||
//! start and stop program execution on the APP core.
|
||||
//!
|
||||
//! ## Examples
|
||||
//! ```rust, no_run
|
||||
#![doc = crate::before_snippet!()]
|
||||
//! # use esp_hal::delay::Delay;
|
||||
//! # use esp_hal::cpu_control::{CpuControl, Stack};
|
||||
//! # use core::{cell::RefCell, ptr::addr_of_mut};
|
||||
//! # use critical_section::Mutex;
|
||||
//! # let delay = Delay::new();
|
||||
//! static mut APP_CORE_STACK: Stack<8192> = Stack::new();
|
||||
//!
|
||||
//! let counter = Mutex::new(RefCell::new(0));
|
||||
//!
|
||||
//! let mut cpu_control = CpuControl::new(peripherals.CPU_CTRL);
|
||||
//! let cpu1_fnctn = || {
|
||||
//! cpu1_task(&delay, &counter);
|
||||
//! };
|
||||
//! let _guard = cpu_control
|
||||
//! .start_app_core(
|
||||
//! unsafe { &mut *addr_of_mut!(APP_CORE_STACK) },
|
||||
//! cpu1_fnctn
|
||||
//! )?;
|
||||
//!
|
||||
//! loop {
|
||||
//! delay.delay(Duration::from_secs(1));
|
||||
//! let count = critical_section::with(|cs| *counter.borrow_ref(cs));
|
||||
//! }
|
||||
//! # }
|
||||
//!
|
||||
//! // Where `cpu1_task()` may be defined as:
|
||||
//! # use esp_hal::delay::Delay;
|
||||
//! # use core::cell::RefCell;
|
||||
//!
|
||||
//! fn cpu1_task(
|
||||
//! delay: &Delay,
|
||||
//! counter: &critical_section::Mutex<RefCell<i32>>,
|
||||
//! ) -> ! {
|
||||
//! loop {
|
||||
//! delay.delay(Duration::from_millis(500));
|
||||
//!
|
||||
//! critical_section::with(|cs| {
|
||||
//! let mut val = counter.borrow_ref_mut(cs);
|
||||
//! *val = val.wrapping_add(1);
|
||||
//! });
|
||||
//! }
|
||||
//! }
|
||||
//! ```
|
||||
|
||||
use core::{
|
||||
marker::PhantomData,
|
||||
@ -60,8 +13,8 @@ use core::{
|
||||
|
||||
use crate::{
|
||||
peripheral::{Peripheral, PeripheralRef},
|
||||
peripherals::CPU_CTRL,
|
||||
Cpu,
|
||||
peripherals::{CPU_CTRL, LPWR, SYSTEM},
|
||||
system::Cpu,
|
||||
};
|
||||
|
||||
/// Data type for a properly aligned stack of N bytes
|
||||
@ -78,6 +31,7 @@ use crate::{
|
||||
// Stack frame alignment depends on the SIZE as well as the placement of the
|
||||
// array.
|
||||
#[repr(C, align(16))]
|
||||
#[instability::unstable]
|
||||
pub struct Stack<const SIZE: usize> {
|
||||
/// Memory to be used for the stack
|
||||
pub mem: MaybeUninit<[u8; SIZE]>,
|
||||
@ -92,6 +46,7 @@ impl<const SIZE: usize> Default for Stack<SIZE> {
|
||||
#[allow(clippy::len_without_is_empty)]
|
||||
impl<const SIZE: usize> Stack<SIZE> {
|
||||
/// Construct a stack of length SIZE, uninitialized
|
||||
#[instability::unstable]
|
||||
pub const fn new() -> Stack<SIZE> {
|
||||
::core::assert!(SIZE % 16 == 0); // Make sure stack top is aligned, too.
|
||||
|
||||
@ -101,16 +56,19 @@ impl<const SIZE: usize> Stack<SIZE> {
|
||||
}
|
||||
|
||||
/// Returns the length of the stack in bytes.
|
||||
#[instability::unstable]
|
||||
pub const fn len(&self) -> usize {
|
||||
SIZE
|
||||
}
|
||||
|
||||
/// Returns a mutable pointer to the bottom of the stack.
|
||||
#[instability::unstable]
|
||||
pub fn bottom(&mut self) -> *mut u32 {
|
||||
self.mem.as_mut_ptr() as *mut u32
|
||||
}
|
||||
|
||||
/// Returns a mutable pointer to the top of the stack.
|
||||
#[instability::unstable]
|
||||
pub fn top(&mut self) -> *mut u32 {
|
||||
unsafe { self.bottom().add(SIZE / 4) }
|
||||
}
|
||||
@ -122,51 +80,99 @@ static mut START_CORE1_FUNCTION: Option<*mut ()> = None;
|
||||
static mut APP_CORE_STACK_TOP: Option<*mut u32> = None;
|
||||
|
||||
/// Will park the APP (second) core when dropped
|
||||
#[must_use]
|
||||
#[must_use = "Dropping this guard will park the APP core"]
|
||||
#[instability::unstable]
|
||||
pub struct AppCoreGuard<'a> {
|
||||
phantom: PhantomData<&'a ()>,
|
||||
}
|
||||
|
||||
impl Drop for AppCoreGuard<'_> {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
internal_park_core(Cpu::AppCpu);
|
||||
}
|
||||
unsafe { internal_park_core(Cpu::AppCpu, true) };
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents errors that can occur while working with the core.
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
#[instability::unstable]
|
||||
pub enum Error {
|
||||
/// The core is already running.
|
||||
CoreAlreadyRunning,
|
||||
}
|
||||
|
||||
/// Control CPU Cores
|
||||
///
|
||||
/// ## Examples
|
||||
/// ```rust, no_run
|
||||
#[doc = crate::before_snippet!()]
|
||||
/// # use esp_hal::delay::Delay;
|
||||
/// # use esp_hal::system::{CpuControl, Stack};
|
||||
/// # use core::{cell::RefCell, ptr::addr_of_mut};
|
||||
/// # use critical_section::Mutex;
|
||||
/// # let delay = Delay::new();
|
||||
/// static mut APP_CORE_STACK: Stack<8192> = Stack::new();
|
||||
///
|
||||
/// let counter = Mutex::new(RefCell::new(0));
|
||||
///
|
||||
/// let mut cpu_control = CpuControl::new(peripherals.CPU_CTRL);
|
||||
/// let cpu1_fnctn = || {
|
||||
/// cpu1_task(&delay, &counter);
|
||||
/// };
|
||||
/// let _guard = cpu_control
|
||||
/// .start_app_core(
|
||||
/// unsafe { &mut *addr_of_mut!(APP_CORE_STACK) },
|
||||
/// cpu1_fnctn
|
||||
/// )?;
|
||||
///
|
||||
/// loop {
|
||||
/// delay.delay(Duration::from_secs(1));
|
||||
/// let count = critical_section::with(|cs| *counter.borrow_ref(cs));
|
||||
/// }
|
||||
/// # }
|
||||
///
|
||||
/// // Where `cpu1_task()` may be defined as:
|
||||
/// # use esp_hal::delay::Delay;
|
||||
/// # use core::cell::RefCell;
|
||||
///
|
||||
/// fn cpu1_task(
|
||||
/// delay: &Delay,
|
||||
/// counter: &critical_section::Mutex<RefCell<i32>>,
|
||||
/// ) -> ! {
|
||||
/// loop {
|
||||
/// delay.delay(Duration::from_millis(500));
|
||||
///
|
||||
/// critical_section::with(|cs| {
|
||||
/// let mut val = counter.borrow_ref_mut(cs);
|
||||
/// *val = val.wrapping_add(1);
|
||||
/// });
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
#[instability::unstable]
|
||||
pub struct CpuControl<'d> {
|
||||
_cpu_control: PeripheralRef<'d, CPU_CTRL>,
|
||||
}
|
||||
|
||||
unsafe fn internal_park_core(core: Cpu) {
|
||||
let rtc_control = crate::peripherals::LPWR::regs();
|
||||
|
||||
unsafe fn internal_park_core(core: Cpu, park: bool) {
|
||||
let c1_value = if park { 0x21 } else { 0 };
|
||||
let c0_value = if park { 0x02 } else { 0 };
|
||||
match core {
|
||||
Cpu::ProCpu => {
|
||||
rtc_control
|
||||
LPWR::regs()
|
||||
.sw_cpu_stall()
|
||||
.modify(|_, w| w.sw_stall_procpu_c1().bits(0x21));
|
||||
rtc_control
|
||||
.modify(|_, w| w.sw_stall_procpu_c1().bits(c1_value));
|
||||
LPWR::regs()
|
||||
.options0()
|
||||
.modify(|_, w| w.sw_stall_procpu_c0().bits(0x02));
|
||||
.modify(|_, w| w.sw_stall_procpu_c0().bits(c0_value));
|
||||
}
|
||||
Cpu::AppCpu => {
|
||||
rtc_control
|
||||
LPWR::regs()
|
||||
.sw_cpu_stall()
|
||||
.modify(|_, w| w.sw_stall_appcpu_c1().bits(0x21));
|
||||
rtc_control
|
||||
.modify(|_, w| w.sw_stall_appcpu_c1().bits(c1_value));
|
||||
LPWR::regs()
|
||||
.options0()
|
||||
.modify(|_, w| w.sw_stall_appcpu_c0().bits(0x02));
|
||||
.modify(|_, w| w.sw_stall_appcpu_c0().bits(c0_value));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -188,32 +194,15 @@ impl<'d> CpuControl<'d> {
|
||||
///
|
||||
/// The user must ensure that the core being parked is not the core which is
|
||||
/// currently executing their code.
|
||||
#[instability::unstable]
|
||||
pub unsafe fn park_core(&mut self, core: Cpu) {
|
||||
internal_park_core(core);
|
||||
internal_park_core(core, true);
|
||||
}
|
||||
|
||||
/// Unpark the given core
|
||||
#[instability::unstable]
|
||||
pub fn unpark_core(&mut self, core: Cpu) {
|
||||
let rtc_control = crate::peripherals::LPWR::regs();
|
||||
|
||||
match core {
|
||||
Cpu::ProCpu => {
|
||||
rtc_control
|
||||
.sw_cpu_stall()
|
||||
.modify(|_, w| unsafe { w.sw_stall_procpu_c1().bits(0) });
|
||||
rtc_control
|
||||
.options0()
|
||||
.modify(|_, w| unsafe { w.sw_stall_procpu_c0().bits(0) });
|
||||
}
|
||||
Cpu::AppCpu => {
|
||||
rtc_control
|
||||
.sw_cpu_stall()
|
||||
.modify(|_, w| unsafe { w.sw_stall_appcpu_c1().bits(0) });
|
||||
rtc_control
|
||||
.options0()
|
||||
.modify(|_, w| unsafe { w.sw_stall_appcpu_c0().bits(0) });
|
||||
}
|
||||
}
|
||||
unsafe { internal_park_core(core, false) };
|
||||
}
|
||||
|
||||
/// When we get here, the core is out of reset, with a stack setup by ROM
|
||||
@ -265,19 +254,20 @@ impl<'d> CpuControl<'d> {
|
||||
let entry = unsafe { ManuallyDrop::take(&mut *entry.cast::<ManuallyDrop<F>>()) };
|
||||
entry();
|
||||
loop {
|
||||
unsafe { internal_park_core(Cpu::current()) };
|
||||
unsafe { internal_park_core(Cpu::current(), true) };
|
||||
}
|
||||
}
|
||||
None => panic!("No start function set"),
|
||||
}
|
||||
}
|
||||
|
||||
/// Start the APP (second) core
|
||||
/// Start the APP (second) core.
|
||||
///
|
||||
/// The second core will start running the closure `entry`. Note that if the
|
||||
/// closure exits, the core will be parked.
|
||||
///
|
||||
/// Dropping the returned guard will park the core.
|
||||
#[instability::unstable]
|
||||
pub fn start_app_core<'a, const SIZE: usize, F>(
|
||||
&mut self,
|
||||
stack: &'static mut Stack<SIZE>,
|
||||
@ -287,7 +277,7 @@ impl<'d> CpuControl<'d> {
|
||||
F: FnOnce(),
|
||||
F: Send + 'a,
|
||||
{
|
||||
let system_control = crate::peripherals::SYSTEM::regs();
|
||||
let system_control = SYSTEM::regs();
|
||||
|
||||
if !xtensa_lx::is_debugger_attached()
|
||||
&& system_control
|
||||
|
@ -140,7 +140,7 @@ pub unsafe extern "C" fn ESP32Reset() -> ! {
|
||||
addr_of_mut!(_rtc_slow_bss_end),
|
||||
);
|
||||
if matches!(
|
||||
crate::reset::reset_reason(),
|
||||
crate::system::reset_reason(),
|
||||
None | Some(SocResetReason::ChipPowerOn)
|
||||
) {
|
||||
xtensa_lx_rt::zero_bss(
|
||||
|
@ -59,11 +59,10 @@ use crate::{
|
||||
peripheral::{Peripheral, PeripheralRef},
|
||||
private::{self, Sealed},
|
||||
spi::AnySpi,
|
||||
system::PeripheralGuard,
|
||||
system::{Cpu, PeripheralGuard},
|
||||
time::Rate,
|
||||
Async,
|
||||
Blocking,
|
||||
Cpu,
|
||||
DriverMode,
|
||||
};
|
||||
|
||||
@ -1345,7 +1344,7 @@ mod dma {
|
||||
/// Interrupts are not enabled at the peripheral level here.
|
||||
fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
|
||||
let interrupt = self.driver().info.interrupt;
|
||||
for core in crate::Cpu::other() {
|
||||
for core in crate::system::Cpu::other() {
|
||||
crate::interrupt::disable(core, interrupt);
|
||||
}
|
||||
unsafe { crate::interrupt::bind_interrupt(interrupt, handler.handler()) };
|
||||
|
@ -128,7 +128,7 @@ mod multicore {
|
||||
const UNUSED_THREAD_ID_VALUE: usize = 0x100;
|
||||
|
||||
pub fn thread_id() -> usize {
|
||||
crate::raw_core()
|
||||
crate::system::raw_core()
|
||||
}
|
||||
|
||||
pub(super) struct AtomicLock {
|
||||
|
@ -3,19 +3,9 @@
|
||||
use core::cell::RefCell;
|
||||
|
||||
use critical_section::{CriticalSection, Mutex};
|
||||
use strum::{EnumCount, EnumIter, IntoEnumIterator};
|
||||
|
||||
use crate::peripherals::SYSTEM;
|
||||
|
||||
pub(crate) const KEEP_ENABLED: &[Peripheral] = &[
|
||||
Peripheral::Uart0,
|
||||
#[cfg(usb_device)]
|
||||
Peripheral::UsbDevice,
|
||||
#[cfg(systimer)]
|
||||
Peripheral::Systimer,
|
||||
Peripheral::Timg0,
|
||||
];
|
||||
|
||||
/// Peripherals which can be enabled via `PeripheralClockControl`.
|
||||
///
|
||||
/// This enum represents various hardware peripherals that can be enabled
|
||||
@ -24,7 +14,7 @@ pub(crate) const KEEP_ENABLED: &[Peripheral] = &[
|
||||
// FIXME: This enum needs to be public because it's exposed via a bunch of traits, but it's not
|
||||
// useful to users.
|
||||
#[doc(hidden)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, EnumCount, EnumIter)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
#[repr(u8)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum Peripheral {
|
||||
@ -132,6 +122,90 @@ pub enum Peripheral {
|
||||
Tsens,
|
||||
}
|
||||
|
||||
impl Peripheral {
|
||||
const KEEP_ENABLED: &[Peripheral] = &[
|
||||
Peripheral::Uart0,
|
||||
#[cfg(usb_device)]
|
||||
Peripheral::UsbDevice,
|
||||
#[cfg(systimer)]
|
||||
Peripheral::Systimer,
|
||||
Peripheral::Timg0,
|
||||
];
|
||||
|
||||
const COUNT: usize = Self::ALL.len();
|
||||
|
||||
const ALL: &[Self] = &[
|
||||
#[cfg(spi2)]
|
||||
Self::Spi2,
|
||||
#[cfg(spi3)]
|
||||
Self::Spi3,
|
||||
#[cfg(i2c0)]
|
||||
Self::I2cExt0,
|
||||
#[cfg(i2c1)]
|
||||
Self::I2cExt1,
|
||||
#[cfg(rmt)]
|
||||
Self::Rmt,
|
||||
#[cfg(ledc)]
|
||||
Self::Ledc,
|
||||
#[cfg(mcpwm0)]
|
||||
Self::Mcpwm0,
|
||||
#[cfg(mcpwm1)]
|
||||
Self::Mcpwm1,
|
||||
#[cfg(pcnt)]
|
||||
Self::Pcnt,
|
||||
#[cfg(apb_saradc)]
|
||||
Self::ApbSarAdc,
|
||||
#[cfg(gdma)]
|
||||
Self::Gdma,
|
||||
#[cfg(pdma)]
|
||||
Self::Dma,
|
||||
#[cfg(i2s0)]
|
||||
Self::I2s0,
|
||||
#[cfg(i2s1)]
|
||||
Self::I2s1,
|
||||
#[cfg(usb0)]
|
||||
Self::Usb,
|
||||
#[cfg(aes)]
|
||||
Self::Aes,
|
||||
#[cfg(twai0)]
|
||||
Self::Twai0,
|
||||
#[cfg(twai1)]
|
||||
Self::Twai1,
|
||||
#[cfg(timg0)]
|
||||
Self::Timg0,
|
||||
#[cfg(timg1)]
|
||||
Self::Timg1,
|
||||
#[cfg(sha)]
|
||||
Self::Sha,
|
||||
#[cfg(usb_device)]
|
||||
Self::UsbDevice,
|
||||
#[cfg(uart0)]
|
||||
Self::Uart0,
|
||||
#[cfg(uart1)]
|
||||
Self::Uart1,
|
||||
#[cfg(uart2)]
|
||||
Self::Uart2,
|
||||
#[cfg(rsa)]
|
||||
Self::Rsa,
|
||||
#[cfg(parl_io)]
|
||||
Self::ParlIo,
|
||||
#[cfg(hmac)]
|
||||
Self::Hmac,
|
||||
#[cfg(ecc)]
|
||||
Self::Ecc,
|
||||
#[cfg(soc_etm)]
|
||||
Self::Etm,
|
||||
#[cfg(trace0)]
|
||||
Self::Trace0,
|
||||
#[cfg(lcd_cam)]
|
||||
Self::LcdCam,
|
||||
#[cfg(systimer)]
|
||||
Self::Systimer,
|
||||
#[cfg(tsens)]
|
||||
Self::Tsens,
|
||||
];
|
||||
}
|
||||
|
||||
impl Peripheral {
|
||||
pub fn try_from(value: u8) -> Option<Peripheral> {
|
||||
if value >= Peripheral::COUNT as u8 {
|
||||
@ -151,11 +225,11 @@ static PERIPHERAL_REF_COUNT: Mutex<RefCell<[usize; Peripheral::COUNT]>> =
|
||||
pub(crate) fn disable_peripherals() {
|
||||
// Take the critical section up front to avoid taking it multiple times.
|
||||
critical_section::with(|cs| {
|
||||
for p in Peripheral::iter() {
|
||||
if KEEP_ENABLED.contains(&p) {
|
||||
for p in Peripheral::ALL {
|
||||
if Peripheral::KEEP_ENABLED.contains(p) {
|
||||
continue;
|
||||
}
|
||||
PeripheralClockControl::enable_forced_with_cs(p, false, true, cs);
|
||||
PeripheralClockControl::enable_forced_with_cs(*p, false, true, cs);
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -168,7 +242,7 @@ pub(crate) struct PeripheralGuard {
|
||||
|
||||
impl PeripheralGuard {
|
||||
pub(crate) fn new_with(p: Peripheral, init: fn()) -> Self {
|
||||
if !KEEP_ENABLED.contains(&p) && PeripheralClockControl::enable(p) {
|
||||
if !Peripheral::KEEP_ENABLED.contains(&p) && PeripheralClockControl::enable(p) {
|
||||
PeripheralClockControl::reset(p);
|
||||
init();
|
||||
}
|
||||
@ -183,7 +257,7 @@ impl PeripheralGuard {
|
||||
|
||||
impl Drop for PeripheralGuard {
|
||||
fn drop(&mut self) {
|
||||
if !KEEP_ENABLED.contains(&self.peripheral) {
|
||||
if !Peripheral::KEEP_ENABLED.contains(&self.peripheral) {
|
||||
PeripheralClockControl::disable(self.peripheral);
|
||||
}
|
||||
}
|
||||
@ -197,7 +271,7 @@ impl<const P: u8> GenericPeripheralGuard<P> {
|
||||
pub(crate) fn new_with(init: fn(CriticalSection<'_>)) -> Self {
|
||||
let peripheral = unwrap!(Peripheral::try_from(P));
|
||||
critical_section::with(|cs| {
|
||||
if !KEEP_ENABLED.contains(&peripheral)
|
||||
if !Peripheral::KEEP_ENABLED.contains(&peripheral)
|
||||
&& PeripheralClockControl::enable_with_cs(peripheral, cs)
|
||||
{
|
||||
PeripheralClockControl::reset(peripheral);
|
||||
@ -216,7 +290,7 @@ impl<const P: u8> GenericPeripheralGuard<P> {
|
||||
impl<const P: u8> Drop for GenericPeripheralGuard<P> {
|
||||
fn drop(&mut self) {
|
||||
let peripheral = unwrap!(Peripheral::try_from(P));
|
||||
if !KEEP_ENABLED.contains(&peripheral) {
|
||||
if !Peripheral::KEEP_ENABLED.contains(&peripheral) {
|
||||
PeripheralClockControl::disable(peripheral);
|
||||
}
|
||||
}
|
||||
@ -1075,3 +1149,155 @@ impl PeripheralClockControl {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(esp32, esp32s3))]
|
||||
#[allow(unused_imports)]
|
||||
pub use crate::soc::cpu_control::*;
|
||||
|
||||
/// Available CPU cores
|
||||
///
|
||||
/// The actual number of available cores depends on the target.
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, strum::FromRepr)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
#[repr(C)]
|
||||
pub enum Cpu {
|
||||
/// The first core
|
||||
ProCpu = 0,
|
||||
/// The second core
|
||||
#[cfg(multi_core)]
|
||||
AppCpu = 1,
|
||||
}
|
||||
|
||||
impl Cpu {
|
||||
/// The number of available cores.
|
||||
pub const COUNT: usize = 1 + cfg!(multi_core) as usize;
|
||||
|
||||
/// Returns the core the application is currently executing on
|
||||
#[inline(always)]
|
||||
pub fn current() -> Self {
|
||||
// This works for both RISCV and Xtensa because both
|
||||
// get_raw_core functions return zero, _or_ something
|
||||
// greater than zero; 1 in the case of RISCV and 0x2000
|
||||
// in the case of Xtensa.
|
||||
match raw_core() {
|
||||
0 => Cpu::ProCpu,
|
||||
#[cfg(all(multi_core, riscv))]
|
||||
1 => Cpu::AppCpu,
|
||||
#[cfg(all(multi_core, xtensa))]
|
||||
0x2000 => Cpu::AppCpu,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns an iterator over the "other" cores.
|
||||
#[inline(always)]
|
||||
pub(crate) fn other() -> impl Iterator<Item = Self> {
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(multi_core)] {
|
||||
match Self::current() {
|
||||
Cpu::ProCpu => [Cpu::AppCpu].into_iter(),
|
||||
Cpu::AppCpu => [Cpu::ProCpu].into_iter(),
|
||||
}
|
||||
} else {
|
||||
[].into_iter()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns an iterator over all cores.
|
||||
#[inline(always)]
|
||||
pub(crate) fn all() -> impl Iterator<Item = Self> {
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(multi_core)] {
|
||||
[Cpu::ProCpu, Cpu::AppCpu].into_iter()
|
||||
} else {
|
||||
[Cpu::ProCpu].into_iter()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the raw value of the mhartid register.
|
||||
///
|
||||
/// On RISC-V, this is the hardware thread ID.
|
||||
///
|
||||
/// On Xtensa, this returns the result of reading the PRID register logically
|
||||
/// ANDed with 0x2000, the 13th bit in the register. Espressif Xtensa chips use
|
||||
/// this bit to determine the core id.
|
||||
#[inline(always)]
|
||||
pub(crate) fn raw_core() -> usize {
|
||||
// This method must never return UNUSED_THREAD_ID_VALUE
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(all(multi_core, riscv))] {
|
||||
riscv::register::mhartid::read()
|
||||
} else if #[cfg(all(multi_core, xtensa))] {
|
||||
(xtensa_lx::get_processor_id() & 0x2000) as usize
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
use crate::rtc_cntl::SocResetReason;
|
||||
|
||||
/// Source of the wakeup event
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
#[instability::unstable]
|
||||
pub enum SleepSource {
|
||||
/// In case of deep sleep, reset was not caused by exit from deep sleep
|
||||
Undefined = 0,
|
||||
/// Not a wakeup cause, used to disable all wakeup sources with
|
||||
/// esp_sleep_disable_wakeup_source
|
||||
All,
|
||||
/// Wakeup caused by external signal using RTC_IO
|
||||
Ext0,
|
||||
/// Wakeup caused by external signal using RTC_CNTL
|
||||
Ext1,
|
||||
/// Wakeup caused by timer
|
||||
Timer,
|
||||
/// Wakeup caused by touchpad
|
||||
TouchPad,
|
||||
/// Wakeup caused by ULP program
|
||||
Ulp,
|
||||
/// Wakeup caused by GPIO (light sleep only on ESP32, S2 and S3)
|
||||
Gpio,
|
||||
/// Wakeup caused by UART (light sleep only)
|
||||
Uart,
|
||||
/// Wakeup caused by WIFI (light sleep only)
|
||||
Wifi,
|
||||
/// Wakeup caused by COCPU int
|
||||
Cocpu,
|
||||
/// Wakeup caused by COCPU crash
|
||||
CocpuTrapTrig,
|
||||
/// Wakeup caused by BT (light sleep only)
|
||||
BT,
|
||||
}
|
||||
|
||||
/// Performs a software reset on the chip.
|
||||
#[inline]
|
||||
pub fn software_reset() -> ! {
|
||||
crate::rom::software_reset()
|
||||
}
|
||||
|
||||
/// Resets the given CPU, leaving peripherals unchanged.
|
||||
#[instability::unstable]
|
||||
#[inline]
|
||||
pub fn software_reset_cpu(cpu: Cpu) {
|
||||
crate::rom::software_reset_cpu(cpu as u32)
|
||||
}
|
||||
|
||||
/// Retrieves the reason for the last reset as a SocResetReason enum value.
|
||||
/// Returns `None` if the reset reason cannot be determined.
|
||||
#[instability::unstable]
|
||||
#[inline]
|
||||
pub fn reset_reason() -> Option<SocResetReason> {
|
||||
crate::rtc_cntl::reset_reason(Cpu::current())
|
||||
}
|
||||
|
||||
/// Retrieves the cause of the last wakeup event as a SleepSource enum value.
|
||||
#[instability::unstable]
|
||||
#[inline]
|
||||
pub fn wakeup_cause() -> SleepSource {
|
||||
crate::rtc_cntl::wakeup_cause()
|
||||
}
|
||||
|
@ -52,10 +52,10 @@ use crate::{
|
||||
interrupt::{InterruptConfigurable, InterruptHandler},
|
||||
peripheral::{Peripheral, PeripheralRef},
|
||||
peripherals::Interrupt,
|
||||
system::Cpu,
|
||||
time::{Duration, Instant},
|
||||
Async,
|
||||
Blocking,
|
||||
Cpu,
|
||||
DriverMode,
|
||||
};
|
||||
|
||||
|
@ -26,9 +26,8 @@ use crate::{
|
||||
peripheral::Peripheral,
|
||||
peripherals::{Interrupt, SYSTIMER},
|
||||
sync::{lock, RawMutex},
|
||||
system::{Peripheral as PeripheralEnable, PeripheralClockControl},
|
||||
system::{Cpu, Peripheral as PeripheralEnable, PeripheralClockControl},
|
||||
time::{Duration, Instant},
|
||||
Cpu,
|
||||
};
|
||||
|
||||
/// The configuration of a unit.
|
||||
@ -397,7 +396,7 @@ impl Alarm {
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
for core in crate::Cpu::other() {
|
||||
for core in crate::system::Cpu::other() {
|
||||
crate::interrupt::disable(core, interrupt);
|
||||
}
|
||||
|
||||
|
@ -391,7 +391,7 @@ impl Timer {
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
for core in crate::Cpu::other() {
|
||||
for core in crate::system::Cpu::other() {
|
||||
crate::interrupt::disable(core, interrupt);
|
||||
}
|
||||
unsafe { interrupt::bind_interrupt(interrupt, handler.handler()) };
|
||||
|
@ -131,7 +131,7 @@ use crate::{
|
||||
interrupt::InterruptHandler,
|
||||
pac::twai0::RegisterBlock,
|
||||
peripheral::{Peripheral, PeripheralRef},
|
||||
system::PeripheralGuard,
|
||||
system::{Cpu, PeripheralGuard},
|
||||
twai::filter::SingleStandardFilter,
|
||||
Async,
|
||||
Blocking,
|
||||
@ -745,7 +745,7 @@ where
|
||||
}
|
||||
|
||||
fn internal_set_interrupt_handler(&mut self, handler: InterruptHandler) {
|
||||
for core in crate::Cpu::other() {
|
||||
for core in Cpu::other() {
|
||||
crate::interrupt::disable(core, self.twai.interrupt());
|
||||
}
|
||||
unsafe { crate::interrupt::bind_interrupt(self.twai.interrupt(), handler.handler()) };
|
||||
@ -986,7 +986,7 @@ impl<'d> TwaiConfiguration<'d, Blocking> {
|
||||
impl<'d> TwaiConfiguration<'d, Async> {
|
||||
/// Convert the configuration into a blocking configuration.
|
||||
pub fn into_blocking(self) -> TwaiConfiguration<'d, Blocking> {
|
||||
use crate::{interrupt, Cpu};
|
||||
use crate::{interrupt, system::Cpu};
|
||||
|
||||
interrupt::disable(Cpu::current(), self.twai.interrupt());
|
||||
|
||||
|
@ -2234,7 +2234,7 @@ impl Info {
|
||||
}
|
||||
|
||||
fn set_interrupt_handler(&self, handler: InterruptHandler) {
|
||||
for core in crate::Cpu::other() {
|
||||
for core in crate::system::Cpu::other() {
|
||||
crate::interrupt::disable(core, self.interrupt);
|
||||
}
|
||||
self.enable_listen(EnumSet::all(), false);
|
||||
@ -2244,7 +2244,7 @@ impl Info {
|
||||
}
|
||||
|
||||
fn disable_interrupts(&self) {
|
||||
crate::interrupt::disable(crate::Cpu::current(), self.interrupt);
|
||||
crate::interrupt::disable(crate::system::Cpu::current(), self.interrupt);
|
||||
}
|
||||
|
||||
fn apply_config(&self, config: &Config) -> Result<(), ConfigError> {
|
||||
|
@ -132,10 +132,9 @@ use crate::{
|
||||
pac::usb_device::RegisterBlock,
|
||||
peripheral::{Peripheral, PeripheralRef},
|
||||
peripherals::{Interrupt, USB_DEVICE},
|
||||
system::PeripheralClockControl,
|
||||
system::{Cpu, PeripheralClockControl},
|
||||
Async,
|
||||
Blocking,
|
||||
Cpu,
|
||||
DriverMode,
|
||||
};
|
||||
|
||||
@ -447,7 +446,7 @@ where
|
||||
/// handlers.
|
||||
#[instability::unstable]
|
||||
pub fn set_interrupt_handler(&mut self, handler: crate::interrupt::InterruptHandler) {
|
||||
for core in crate::Cpu::other() {
|
||||
for core in crate::system::Cpu::other() {
|
||||
crate::interrupt::disable(core, Interrupt::USB_DEVICE);
|
||||
}
|
||||
unsafe { crate::interrupt::bind_interrupt(Interrupt::USB_DEVICE, handler.handler()) };
|
||||
|
@ -306,7 +306,7 @@ pub(crate) unsafe extern "C" fn interrupt_on(intr_num: i32) -> i32 {
|
||||
pub(crate) unsafe extern "C" fn interrupt_off(intr_num: i32) -> i32 {
|
||||
trace!("interrupt_off {}", intr_num);
|
||||
interrupt::disable(
|
||||
crate::hal::Cpu::ProCpu,
|
||||
crate::hal::system::Cpu::ProCpu,
|
||||
Interrupt::try_from(intr_num as u16).unwrap(),
|
||||
);
|
||||
|
||||
|
@ -53,7 +53,7 @@ pub(crate) fn setup_multitasking() {
|
||||
}
|
||||
|
||||
pub(crate) fn disable_multitasking() {
|
||||
interrupt::disable(crate::hal::Cpu::ProCpu, Interrupt::FROM_CPU_INTR3);
|
||||
interrupt::disable(crate::hal::system::Cpu::ProCpu, Interrupt::FROM_CPU_INTR3);
|
||||
}
|
||||
|
||||
extern "C" fn handler(trap_frame: &mut TrapFrame) {
|
||||
|
@ -7,16 +7,28 @@ pub(crate) fn setup_radio_isr() {
|
||||
{
|
||||
// It's a mystery why these interrupts are enabled now since it worked without
|
||||
// this before Now at least without disabling these nothing will work
|
||||
interrupt::disable(crate::hal::Cpu::ProCpu, peripherals::Interrupt::ETH_MAC);
|
||||
interrupt::disable(crate::hal::Cpu::ProCpu, peripherals::Interrupt::UART0);
|
||||
interrupt::disable(
|
||||
crate::hal::system::Cpu::ProCpu,
|
||||
peripherals::Interrupt::ETH_MAC,
|
||||
);
|
||||
interrupt::disable(
|
||||
crate::hal::system::Cpu::ProCpu,
|
||||
peripherals::Interrupt::UART0,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn shutdown_radio_isr() {
|
||||
#[cfg(feature = "ble")]
|
||||
{
|
||||
interrupt::disable(crate::hal::Cpu::ProCpu, peripherals::Interrupt::RWBT);
|
||||
interrupt::disable(crate::hal::Cpu::ProCpu, peripherals::Interrupt::BT_BB);
|
||||
interrupt::disable(
|
||||
crate::hal::system::Cpu::ProCpu,
|
||||
peripherals::Interrupt::RWBT,
|
||||
);
|
||||
interrupt::disable(
|
||||
crate::hal::system::Cpu::ProCpu,
|
||||
peripherals::Interrupt::BT_BB,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -12,8 +12,8 @@ pub(crate) fn setup_radio_isr() {
|
||||
pub(crate) fn shutdown_radio_isr() {
|
||||
#[cfg(feature = "ble")]
|
||||
{
|
||||
interrupt::disable(crate::hal::Cpu::ProCpu, Interrupt::LP_TIMER);
|
||||
interrupt::disable(crate::hal::Cpu::ProCpu, Interrupt::BT_MAC);
|
||||
interrupt::disable(crate::hal::system::Cpu::ProCpu, Interrupt::LP_TIMER);
|
||||
interrupt::disable(crate::hal::system::Cpu::ProCpu, Interrupt::BT_MAC);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -12,9 +12,9 @@ pub(crate) fn setup_radio_isr() {
|
||||
pub(crate) fn shutdown_radio_isr() {
|
||||
#[cfg(feature = "ble")]
|
||||
{
|
||||
interrupt::disable(crate::hal::Cpu::ProCpu, Interrupt::RWBT);
|
||||
interrupt::disable(crate::hal::Cpu::ProCpu, Interrupt::RWBLE);
|
||||
interrupt::disable(crate::hal::Cpu::ProCpu, Interrupt::BT_BB);
|
||||
interrupt::disable(crate::hal::system::Cpu::ProCpu, Interrupt::RWBT);
|
||||
interrupt::disable(crate::hal::system::Cpu::ProCpu, Interrupt::RWBLE);
|
||||
interrupt::disable(crate::hal::system::Cpu::ProCpu, Interrupt::BT_BB);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -23,8 +23,8 @@ pub(crate) fn setup_radio_isr() {
|
||||
pub(crate) fn shutdown_radio_isr() {
|
||||
#[cfg(feature = "ble")]
|
||||
{
|
||||
interrupt::disable(crate::hal::Cpu::ProCpu, Interrupt::LP_TIMER);
|
||||
interrupt::disable(crate::hal::Cpu::ProCpu, Interrupt::BT_MAC);
|
||||
interrupt::disable(crate::hal::system::Cpu::ProCpu, Interrupt::LP_TIMER);
|
||||
interrupt::disable(crate::hal::system::Cpu::ProCpu, Interrupt::BT_MAC);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -11,8 +11,8 @@ pub(crate) fn setup_radio_isr() {
|
||||
pub(crate) fn shutdown_radio_isr() {
|
||||
#[cfg(feature = "ble")]
|
||||
{
|
||||
interrupt::disable(crate::hal::Cpu::ProCpu, Interrupt::LP_BLE_TIMER);
|
||||
interrupt::disable(crate::hal::Cpu::ProCpu, Interrupt::BT_MAC);
|
||||
interrupt::disable(crate::hal::system::Cpu::ProCpu, Interrupt::LP_BLE_TIMER);
|
||||
interrupt::disable(crate::hal::system::Cpu::ProCpu, Interrupt::BT_MAC);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -9,8 +9,8 @@ pub(crate) fn setup_radio_isr() {
|
||||
pub(crate) fn shutdown_radio_isr() {
|
||||
#[cfg(feature = "ble")]
|
||||
{
|
||||
interrupt::disable(crate::hal::Cpu::ProCpu, Interrupt::BT_BB);
|
||||
interrupt::disable(crate::hal::Cpu::ProCpu, Interrupt::RWBLE);
|
||||
interrupt::disable(crate::hal::system::Cpu::ProCpu, Interrupt::BT_BB);
|
||||
interrupt::disable(crate::hal::system::Cpu::ProCpu, Interrupt::RWBLE);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -19,10 +19,9 @@ use embassy_sync::{blocking_mutex::raw::CriticalSectionRawMutex, signal::Signal}
|
||||
use embassy_time::{Duration, Ticker};
|
||||
use esp_backtrace as _;
|
||||
use esp_hal::{
|
||||
cpu_control::{CpuControl, Stack},
|
||||
gpio::{Level, Output, OutputConfig},
|
||||
system::{Cpu, CpuControl, Stack},
|
||||
timer::{timg::TimerGroup, AnyTimer},
|
||||
Cpu,
|
||||
};
|
||||
use esp_hal_embassy::Executor;
|
||||
use esp_println::println;
|
||||
|
@ -18,12 +18,11 @@ use embassy_sync::{blocking_mutex::raw::CriticalSectionRawMutex, signal::Signal}
|
||||
use embassy_time::{Duration, Ticker};
|
||||
use esp_backtrace as _;
|
||||
use esp_hal::{
|
||||
cpu_control::{CpuControl, Stack},
|
||||
gpio::{Level, Output, OutputConfig},
|
||||
interrupt::{software::SoftwareInterruptControl, Priority},
|
||||
main,
|
||||
system::{Cpu, CpuControl, Stack},
|
||||
timer::{timg::TimerGroup, AnyTimer},
|
||||
Cpu,
|
||||
};
|
||||
use esp_hal_embassy::InterruptExecutor;
|
||||
use esp_println::println;
|
||||
|
@ -11,7 +11,7 @@
|
||||
use esp_backtrace as _;
|
||||
use esp_hal::{
|
||||
main,
|
||||
reset::software_reset,
|
||||
system::software_reset,
|
||||
uart::{self, Uart},
|
||||
};
|
||||
use esp_ieee802154::{Config, Ieee802154};
|
||||
|
@ -15,7 +15,7 @@
|
||||
|
||||
use embassy_sync::{blocking_mutex::raw::CriticalSectionRawMutex, signal::Signal};
|
||||
#[cfg(multi_core)]
|
||||
use esp_hal::cpu_control::{CpuControl, Stack};
|
||||
use esp_hal::system::{CpuControl, Stack};
|
||||
use esp_hal::{
|
||||
interrupt::{
|
||||
software::{SoftwareInterrupt, SoftwareInterruptControl},
|
||||
|
@ -308,7 +308,7 @@ mod test {
|
||||
}
|
||||
};
|
||||
|
||||
use esp_hal::cpu_control::{CpuControl, Stack};
|
||||
use esp_hal::system::{CpuControl, Stack};
|
||||
const DISPLAY_STACK_SIZE: usize = 8192;
|
||||
let app_core_stack = mk_static!(Stack<DISPLAY_STACK_SIZE>, Stack::new());
|
||||
let cpu_control = CpuControl::new(peripherals.CPU_CTRL);
|
||||
|
@ -42,11 +42,10 @@ cfg_if::cfg_if! {
|
||||
if #[cfg(multi_core)] {
|
||||
use core::sync::atomic::{AtomicBool, Ordering};
|
||||
|
||||
use esp_hal::cpu_control::CpuControl;
|
||||
use esp_hal::system::{CpuControl, Stack};
|
||||
|
||||
static DONE: AtomicBool = AtomicBool::new(false);
|
||||
static mut APP_CORE_STACK: esp_hal::cpu_control::Stack<8192> =
|
||||
esp_hal::cpu_control::Stack::new();
|
||||
static mut APP_CORE_STACK: Stack<8192> = Stack::new();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -12,7 +12,7 @@ use esp_hal::{
|
||||
delay::Delay,
|
||||
main,
|
||||
rtc_cntl::{reset_reason, sleep::TimerWakeupSource, wakeup_cause, Rtc, SocResetReason},
|
||||
Cpu,
|
||||
system::Cpu,
|
||||
};
|
||||
use esp_println::println;
|
||||
|
||||
|
@ -22,7 +22,7 @@ use esp_hal::{
|
||||
Rtc,
|
||||
SocResetReason,
|
||||
},
|
||||
Cpu,
|
||||
system::Cpu,
|
||||
};
|
||||
use esp_println::println;
|
||||
|
||||
|
@ -22,7 +22,7 @@ use esp_hal::{
|
||||
Rtc,
|
||||
SocResetReason,
|
||||
},
|
||||
Cpu,
|
||||
system::Cpu,
|
||||
};
|
||||
use esp_println::println;
|
||||
|
||||
|
@ -23,7 +23,7 @@ use esp_hal::{
|
||||
Rtc,
|
||||
SocResetReason,
|
||||
},
|
||||
Cpu,
|
||||
system::Cpu,
|
||||
};
|
||||
use esp_println::println;
|
||||
|
||||
|
@ -27,7 +27,7 @@ use esp_hal::{
|
||||
Rtc,
|
||||
SocResetReason,
|
||||
},
|
||||
Cpu,
|
||||
system::Cpu,
|
||||
};
|
||||
use esp_println::println;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user