mirror of
https://github.com/esp-rs/esp-hal.git
synced 2025-09-30 05:40:39 +00:00
Bare-bones support to run code on ULP-RV/LP core (#631)
* Bare-bones support to run code on ULP-RV/LP core * Add CHANGELOG.md entry
This commit is contained in:
parent
a86c2ac310
commit
996da27f30
@ -31,6 +31,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- Add octal PSRAM support for ESP32-S3 (#610)
|
||||
- Add MD5 functions from ESP ROM (#618)
|
||||
- Add embassy async `read` support for `uart` (#620)
|
||||
- Add bare-bones support to run code on ULP-RISCV / LP core (#631)
|
||||
|
||||
### Changed
|
||||
|
||||
|
@ -79,6 +79,7 @@ peripherals = [
|
||||
"bt",
|
||||
"wifi",
|
||||
"ieee802154",
|
||||
"lp_core",
|
||||
|
||||
# ROM capabilities
|
||||
"rom_crc_le",
|
||||
|
@ -54,6 +54,7 @@ peripherals = [
|
||||
"phy",
|
||||
"wifi",
|
||||
"psram",
|
||||
"ulp_riscv_core",
|
||||
|
||||
# ROM capabilities
|
||||
"rom_crc_le",
|
||||
|
@ -66,6 +66,7 @@ peripherals = [
|
||||
"bt",
|
||||
"wifi",
|
||||
"psram",
|
||||
"ulp_riscv_core",
|
||||
|
||||
# ROM capabilities
|
||||
"rom_crc_le",
|
||||
|
@ -62,9 +62,13 @@ pub use self::rtc_cntl::{Rtc, Rwdt};
|
||||
pub use self::soc::cpu_control;
|
||||
#[cfg(efuse)]
|
||||
pub use self::soc::efuse;
|
||||
#[cfg(lp_core)]
|
||||
pub use self::soc::lp_core;
|
||||
pub use self::soc::peripherals;
|
||||
#[cfg(psram)]
|
||||
pub use self::soc::psram;
|
||||
#[cfg(ulp_riscv_core)]
|
||||
pub use self::soc::ulp_core;
|
||||
#[cfg(any(spi0, spi1, spi2, spi3))]
|
||||
pub use self::spi::Spi;
|
||||
#[cfg(any(timg0, timg1))]
|
||||
|
79
esp-hal-common/src/soc/esp32c6/lp_core.rs
Normal file
79
esp-hal-common/src/soc/esp32c6/lp_core.rs
Normal file
@ -0,0 +1,79 @@
|
||||
//! Control the LP core
|
||||
|
||||
use esp32c6 as pac;
|
||||
|
||||
use crate::peripheral::{Peripheral, PeripheralRef};
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum LpCoreWakeupSource {
|
||||
HpCpu,
|
||||
}
|
||||
|
||||
pub struct LpCore<'d> {
|
||||
_lp_core: PeripheralRef<'d, crate::soc::peripherals::LP_CORE>,
|
||||
}
|
||||
|
||||
impl<'d> LpCore<'d> {
|
||||
pub fn new(lp_core: impl Peripheral<P = crate::soc::peripherals::LP_CORE> + 'd) -> Self {
|
||||
crate::into_ref!(lp_core);
|
||||
Self { _lp_core: lp_core }
|
||||
}
|
||||
|
||||
pub fn stop(&mut self) {
|
||||
ulp_lp_core_stop();
|
||||
}
|
||||
|
||||
pub fn run(&mut self, wakeup_src: LpCoreWakeupSource) {
|
||||
ulp_lp_core_run(wakeup_src);
|
||||
}
|
||||
}
|
||||
|
||||
fn ulp_lp_core_stop() {
|
||||
let pmu = unsafe { &*pac::PMU::PTR };
|
||||
pmu.lp_cpu_pwr1
|
||||
.modify(|_, w| unsafe { w.lp_cpu_wakeup_en().bits(0) });
|
||||
pmu.lp_cpu_pwr1
|
||||
.modify(|_, w| w.lp_cpu_sleep_req().set_bit());
|
||||
}
|
||||
|
||||
fn ulp_lp_core_run(wakeup_src: LpCoreWakeupSource) {
|
||||
let lp_aon = unsafe { &*pac::LP_AON::PTR };
|
||||
let pmu = unsafe { &*pac::PMU::PTR };
|
||||
let lp_peri = unsafe { &*pac::LP_PERI::PTR };
|
||||
|
||||
// Enable LP-Core
|
||||
lp_aon.lpcore.modify(|_, w| w.disable().clear_bit());
|
||||
|
||||
// Allow LP core to access LP memory during sleep
|
||||
lp_aon.lpbus.modify(|_, w| w.fast_mem_mux_sel().clear_bit());
|
||||
lp_aon
|
||||
.lpbus
|
||||
.modify(|_, w| w.fast_mem_mux_sel_update().set_bit());
|
||||
|
||||
// Enable stall at sleep request
|
||||
pmu.lp_cpu_pwr0
|
||||
.modify(|_, w| w.lp_cpu_slp_stall_en().set_bit());
|
||||
|
||||
// Enable reset after wake-up
|
||||
pmu.lp_cpu_pwr0
|
||||
.modify(|_, w| w.lp_cpu_slp_reset_en().set_bit());
|
||||
|
||||
// Set wake-up sources
|
||||
let src = match wakeup_src {
|
||||
LpCoreWakeupSource::HpCpu => 0x01,
|
||||
};
|
||||
pmu.lp_cpu_pwr1
|
||||
.modify(|_, w| w.lp_cpu_wakeup_en().variant(src));
|
||||
|
||||
// Enable JTAG debugging
|
||||
lp_peri
|
||||
.cpu
|
||||
.modify(|_, w| w.lpcore_dbgm_unavaliable().clear_bit());
|
||||
|
||||
// wake up
|
||||
match wakeup_src {
|
||||
LpCoreWakeupSource::HpCpu => {
|
||||
pmu.hp_lp_cpu_comm.write(|w| w.hp_trigger_lp().set_bit());
|
||||
}
|
||||
}
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
pub mod efuse;
|
||||
pub mod gpio;
|
||||
pub mod lp_core;
|
||||
pub mod peripherals;
|
||||
pub mod radio_clocks;
|
||||
|
||||
|
@ -71,4 +71,5 @@ crate::peripherals! {
|
||||
UHCI0 => true,
|
||||
USB_DEVICE => true,
|
||||
RADIO => false,
|
||||
LP_CORE => false,
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ pub mod peripherals;
|
||||
#[cfg(psram)]
|
||||
pub mod psram;
|
||||
pub mod radio_clocks;
|
||||
pub mod ulp_core;
|
||||
|
||||
pub(crate) mod constants {
|
||||
pub const I2S_SCLK: u32 = 160_000_000;
|
||||
|
@ -51,4 +51,5 @@ crate::peripherals! {
|
||||
XTS_AES => true,
|
||||
RADIO => false,
|
||||
PSRAM => false,
|
||||
ULP_RISCV_CORE => false,
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
const PSRAM_VADDR: u32 = 0x3f500000;
|
||||
|
||||
pub fn psram_vaddr_start() -> usize {
|
||||
unsafe { PSRAM_VADDR_START as usize }
|
||||
PSRAM_VADDR_START as usize
|
||||
}
|
||||
|
||||
cfg_if::cfg_if! {
|
||||
|
109
esp-hal-common/src/soc/esp32s2/ulp_core.rs
Normal file
109
esp-hal-common/src/soc/esp32s2/ulp_core.rs
Normal file
@ -0,0 +1,109 @@
|
||||
//! Control the ULP RISCV core
|
||||
|
||||
use esp32s2 as pac;
|
||||
|
||||
use crate::peripheral::{Peripheral, PeripheralRef};
|
||||
|
||||
extern "C" {
|
||||
fn ets_delay_us(delay: u32);
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum UlpCoreWakeupSource {
|
||||
HpCpu,
|
||||
}
|
||||
|
||||
pub struct UlpCore<'d> {
|
||||
_lp_core: PeripheralRef<'d, crate::soc::peripherals::ULP_RISCV_CORE>,
|
||||
}
|
||||
|
||||
impl<'d> UlpCore<'d> {
|
||||
pub fn new(lp_core: impl Peripheral<P = crate::soc::peripherals::ULP_RISCV_CORE> + 'd) -> Self {
|
||||
crate::into_ref!(lp_core);
|
||||
Self { _lp_core: lp_core }
|
||||
}
|
||||
|
||||
// currently stopping the ULP doesn't work (while following the proedures
|
||||
// outlines in the TRM) - so don't offer this funtion for now
|
||||
//
|
||||
// pub fn stop(&mut self) {
|
||||
// ulp_stop();
|
||||
// }
|
||||
|
||||
pub fn run(&mut self, wakeup_src: UlpCoreWakeupSource) {
|
||||
ulp_run(wakeup_src);
|
||||
}
|
||||
}
|
||||
|
||||
fn ulp_stop() {
|
||||
let rtc_cntl = unsafe { &*pac::RTC_CNTL::PTR };
|
||||
rtc_cntl
|
||||
.ulp_cp_timer
|
||||
.modify(|_, w| w.ulp_cp_slp_timer_en().clear_bit());
|
||||
|
||||
// suspends the ulp operation
|
||||
rtc_cntl.cocpu_ctrl.modify(|_, w| w.cocpu_done().set_bit());
|
||||
|
||||
// Resets the processor
|
||||
rtc_cntl
|
||||
.cocpu_ctrl
|
||||
.modify(|_, w| w.cocpu_shut_reset_en().set_bit());
|
||||
}
|
||||
|
||||
fn ulp_run(wakeup_src: UlpCoreWakeupSource) {
|
||||
let rtc_cntl = unsafe { &*pac::RTC_CNTL::PTR };
|
||||
|
||||
// Reset COCPU when power on
|
||||
rtc_cntl
|
||||
.cocpu_ctrl
|
||||
.modify(|_, w| w.cocpu_shut_reset_en().set_bit());
|
||||
|
||||
// Disable ULP timer
|
||||
rtc_cntl
|
||||
.ulp_cp_timer
|
||||
.modify(|_, w| w.ulp_cp_slp_timer_en().clear_bit());
|
||||
|
||||
// wait for at least 1 RTC_SLOW_CLK cycle
|
||||
unsafe {
|
||||
ets_delay_us(20);
|
||||
}
|
||||
|
||||
// Select ULP-RISC-V to send the DONE signal
|
||||
rtc_cntl
|
||||
.cocpu_ctrl
|
||||
.modify(|_, w| w.cocpu_done_force().set_bit());
|
||||
|
||||
ulp_config_wakeup_source(wakeup_src);
|
||||
|
||||
// Select RISC-V as the ULP_TIMER trigger target
|
||||
rtc_cntl.cocpu_ctrl.modify(|_, w| w.cocpu_sel().clear_bit());
|
||||
|
||||
// Clear any spurious wakeup trigger interrupts upon ULP startup
|
||||
unsafe {
|
||||
ets_delay_us(20);
|
||||
}
|
||||
|
||||
rtc_cntl.int_clr_rtc.write(|w| {
|
||||
w.cocpu_int_clr()
|
||||
.set_bit()
|
||||
.cocpu_trap_int_clr()
|
||||
.set_bit()
|
||||
.ulp_cp_int_clr()
|
||||
.set_bit()
|
||||
});
|
||||
}
|
||||
|
||||
fn ulp_config_wakeup_source(wakeup_src: UlpCoreWakeupSource) {
|
||||
match wakeup_src {
|
||||
UlpCoreWakeupSource::HpCpu => {
|
||||
// use timer to wake up
|
||||
let rtc_cntl = unsafe { &*pac::RTC_CNTL::PTR };
|
||||
rtc_cntl
|
||||
.ulp_cp_ctrl
|
||||
.modify(|_, w| w.ulp_cp_force_start_top().clear_bit());
|
||||
rtc_cntl
|
||||
.ulp_cp_timer
|
||||
.modify(|_, w| w.ulp_cp_slp_timer_en().set_bit());
|
||||
}
|
||||
}
|
||||
}
|
@ -5,6 +5,7 @@ pub mod peripherals;
|
||||
#[cfg(psram)]
|
||||
pub mod psram;
|
||||
pub mod radio_clocks;
|
||||
pub mod ulp_core;
|
||||
|
||||
pub(crate) mod constants {
|
||||
pub const I2S_SCLK: u32 = 160_000_000;
|
||||
|
@ -62,4 +62,5 @@ crate::peripherals! {
|
||||
XTS_AES => true,
|
||||
RADIO => false,
|
||||
PSRAM => false,
|
||||
ULP_RISCV_CORE => false,
|
||||
}
|
||||
|
138
esp-hal-common/src/soc/esp32s3/ulp_core.rs
Normal file
138
esp-hal-common/src/soc/esp32s3/ulp_core.rs
Normal file
@ -0,0 +1,138 @@
|
||||
//! Control the ULP RISCV core
|
||||
|
||||
use esp32s3 as pac;
|
||||
|
||||
use crate::peripheral::{Peripheral, PeripheralRef};
|
||||
|
||||
extern "C" {
|
||||
fn ets_delay_us(delay: u32);
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum UlpCoreWakeupSource {
|
||||
HpCpu,
|
||||
}
|
||||
|
||||
pub struct UlpCore<'d> {
|
||||
_lp_core: PeripheralRef<'d, crate::soc::peripherals::ULP_RISCV_CORE>,
|
||||
}
|
||||
|
||||
impl<'d> UlpCore<'d> {
|
||||
pub fn new(lp_core: impl Peripheral<P = crate::soc::peripherals::ULP_RISCV_CORE> + 'd) -> Self {
|
||||
crate::into_ref!(lp_core);
|
||||
Self { _lp_core: lp_core }
|
||||
}
|
||||
|
||||
pub fn stop(&mut self) {
|
||||
ulp_stop();
|
||||
}
|
||||
|
||||
pub fn run(&mut self, wakeup_src: UlpCoreWakeupSource) {
|
||||
ulp_run(wakeup_src);
|
||||
}
|
||||
}
|
||||
|
||||
fn ulp_stop() {
|
||||
let rtc_cntl = unsafe { &*pac::RTC_CNTL::PTR };
|
||||
rtc_cntl
|
||||
.ulp_cp_timer
|
||||
.modify(|_, w| w.ulp_cp_slp_timer_en().clear_bit());
|
||||
|
||||
// suspends the ulp operation
|
||||
rtc_cntl.cocpu_ctrl.modify(|_, w| w.cocpu_done().set_bit());
|
||||
|
||||
// Resets the processor
|
||||
rtc_cntl
|
||||
.cocpu_ctrl
|
||||
.modify(|_, w| w.cocpu_shut_reset_en().set_bit());
|
||||
|
||||
unsafe {
|
||||
ets_delay_us(20);
|
||||
}
|
||||
|
||||
// above doesn't seem to halt the ULP core - this will
|
||||
rtc_cntl
|
||||
.cocpu_ctrl
|
||||
.modify(|_, w| w.cocpu_clkgate_en().clear_bit());
|
||||
}
|
||||
|
||||
fn ulp_run(wakeup_src: UlpCoreWakeupSource) {
|
||||
let rtc_cntl = unsafe { &*pac::RTC_CNTL::PTR };
|
||||
|
||||
// Reset COCPU when power on
|
||||
rtc_cntl
|
||||
.cocpu_ctrl
|
||||
.modify(|_, w| w.cocpu_shut_reset_en().set_bit());
|
||||
|
||||
// The coprocessor cpu trap signal doesnt have a stable reset value,
|
||||
// force ULP-RISC-V clock on to stop RTC_COCPU_TRAP_TRIG_EN from waking the CPU
|
||||
rtc_cntl
|
||||
.cocpu_ctrl
|
||||
.modify(|_, w| w.cocpu_clk_fo().set_bit());
|
||||
|
||||
// Disable ULP timer
|
||||
rtc_cntl
|
||||
.ulp_cp_timer
|
||||
.modify(|_, w| w.ulp_cp_slp_timer_en().clear_bit());
|
||||
|
||||
// wait for at least 1 RTC_SLOW_CLK cycle
|
||||
unsafe {
|
||||
ets_delay_us(20);
|
||||
}
|
||||
|
||||
// We do not select RISC-V as the Coprocessor here as this could lead to a hang
|
||||
// in the main CPU. Instead, we reset RTC_CNTL_COCPU_SEL after we have enabled
|
||||
// the ULP timer.
|
||||
//
|
||||
// IDF-4510
|
||||
|
||||
// Select ULP-RISC-V to send the DONE signal
|
||||
rtc_cntl
|
||||
.cocpu_ctrl
|
||||
.modify(|_, w| w.cocpu_done_force().set_bit());
|
||||
|
||||
// Set the CLKGATE_EN signal
|
||||
rtc_cntl
|
||||
.cocpu_ctrl
|
||||
.modify(|_, w| w.cocpu_clkgate_en().set_bit());
|
||||
|
||||
ulp_config_wakeup_source(wakeup_src);
|
||||
|
||||
// Select RISC-V as the ULP_TIMER trigger target
|
||||
// Selecting the RISC-V as the Coprocessor at the end is a workaround
|
||||
// for the hang issue recorded in IDF-4510.
|
||||
rtc_cntl.cocpu_ctrl.modify(|_, w| w.cocpu_sel().clear_bit());
|
||||
|
||||
// Clear any spurious wakeup trigger interrupts upon ULP startup
|
||||
unsafe {
|
||||
ets_delay_us(20);
|
||||
}
|
||||
|
||||
rtc_cntl.int_clr_rtc.write(|w| {
|
||||
w.cocpu_int_clr()
|
||||
.set_bit()
|
||||
.cocpu_trap_int_clr()
|
||||
.set_bit()
|
||||
.ulp_cp_int_clr()
|
||||
.set_bit()
|
||||
});
|
||||
|
||||
rtc_cntl
|
||||
.cocpu_ctrl
|
||||
.modify(|_, w| w.cocpu_clkgate_en().set_bit());
|
||||
}
|
||||
|
||||
fn ulp_config_wakeup_source(wakeup_src: UlpCoreWakeupSource) {
|
||||
match wakeup_src {
|
||||
UlpCoreWakeupSource::HpCpu => {
|
||||
// use timer to wake up
|
||||
let rtc_cntl = unsafe { &*pac::RTC_CNTL::PTR };
|
||||
rtc_cntl
|
||||
.ulp_cp_ctrl
|
||||
.modify(|_, w| w.ulp_cp_force_start_top().clear_bit());
|
||||
rtc_cntl
|
||||
.ulp_cp_timer
|
||||
.modify(|_, w| w.ulp_cp_slp_timer_en().set_bit());
|
||||
}
|
||||
}
|
||||
}
|
83
esp32c6-hal/examples/lp_core_basic.rs
Normal file
83
esp32c6-hal/examples/lp_core_basic.rs
Normal file
@ -0,0 +1,83 @@
|
||||
//! This shows a very basic example of running code on the LP core.
|
||||
//!
|
||||
//! Code on LP core just increments a counter. The current value is printed by
|
||||
//! the HP core.
|
||||
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
use esp32c6_hal::{
|
||||
clock::ClockControl,
|
||||
peripherals::Peripherals,
|
||||
prelude::*,
|
||||
timer::TimerGroup,
|
||||
Rtc,
|
||||
};
|
||||
use esp_backtrace as _;
|
||||
use esp_hal_common::lp_core;
|
||||
use esp_println::println;
|
||||
|
||||
// 50000000 <_start>:
|
||||
// 50000000: 00000517 auipc a0,0x0
|
||||
// 50000004: 01050513 addi a0,a0,16 # 50000010 <data>
|
||||
// 50000008: 4581 li a1,0
|
||||
//
|
||||
// 5000000a <_loop>:
|
||||
// 5000000a: 0585 addi a1,a1,1
|
||||
// 5000000c: c10c sw a1,0(a0)
|
||||
// 5000000e: bff5 j 5000000a <_loop>
|
||||
//
|
||||
// 50000010 <data>:
|
||||
// 50000010: 0000 0000
|
||||
|
||||
const CODE: &[u8] = &[
|
||||
0x17, 0x05, 0x00, 0x00, 0x13, 0x05, 0x05, 0x01, 0x81, 0x45, 0x85, 0x05, 0x0c, 0xc1, 0xf5, 0xbf,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
];
|
||||
|
||||
#[entry]
|
||||
fn main() -> ! {
|
||||
let peripherals = Peripherals::take();
|
||||
let mut system = peripherals.PCR.split();
|
||||
let clocks = ClockControl::boot_defaults(system.clock_control).freeze();
|
||||
|
||||
let mut rtc = Rtc::new(peripherals.LP_CLKRST);
|
||||
let timer_group0 = TimerGroup::new(
|
||||
peripherals.TIMG0,
|
||||
&clocks,
|
||||
&mut system.peripheral_clock_control,
|
||||
);
|
||||
let mut wdt0 = timer_group0.wdt;
|
||||
let timer_group1 = TimerGroup::new(
|
||||
peripherals.TIMG1,
|
||||
&clocks,
|
||||
&mut system.peripheral_clock_control,
|
||||
);
|
||||
let mut wdt1 = timer_group1.wdt;
|
||||
|
||||
// Disable watchdog timers
|
||||
rtc.swd.disable();
|
||||
rtc.rwdt.disable();
|
||||
wdt0.disable();
|
||||
wdt1.disable();
|
||||
|
||||
let mut lp_core = esp32c6_hal::lp_core::LpCore::new(peripherals.LP_CORE);
|
||||
lp_core.stop();
|
||||
println!("lp core stopped");
|
||||
|
||||
// copy code to LP ram
|
||||
let lp_ram = 0x5000_0000 as *mut u8;
|
||||
unsafe {
|
||||
core::ptr::copy_nonoverlapping(CODE as *const _ as *const u8, lp_ram, CODE.len());
|
||||
}
|
||||
println!("copied code (len {})", CODE.len());
|
||||
|
||||
// start LP core
|
||||
lp_core.run(lp_core::LpCoreWakeupSource::HpCpu);
|
||||
println!("lpcore run");
|
||||
|
||||
let data = (0x5000_0010 - 0) as *mut u32;
|
||||
loop {
|
||||
println!("Current {}", unsafe { data.read_volatile() });
|
||||
}
|
||||
}
|
72
esp32s2-hal/examples/ulp_riscv_core_basic.rs
Normal file
72
esp32s2-hal/examples/ulp_riscv_core_basic.rs
Normal file
@ -0,0 +1,72 @@
|
||||
//! This shows a very basic example of running code on the ULP RISCV core.
|
||||
//!
|
||||
//! Code on ULP core just increments a counter. The current value is printed by
|
||||
//! the HP core.
|
||||
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
use esp32s2_hal::{
|
||||
clock::ClockControl,
|
||||
peripherals::Peripherals,
|
||||
prelude::*,
|
||||
timer::TimerGroup,
|
||||
Rtc,
|
||||
};
|
||||
use esp_backtrace as _;
|
||||
use esp_println::println;
|
||||
|
||||
// 50000000 <_start>:
|
||||
// 50000000: 00000517 auipc a0,0x0
|
||||
// 50000004: 01050513 addi a0,a0,16 # 50000010 <data>
|
||||
// 50000008: 4581 li a1,0
|
||||
//
|
||||
// 5000000a <_loop>:
|
||||
// 5000000a: 0585 addi a1,a1,1
|
||||
// 5000000c: c10c sw a1,0(a0)
|
||||
// 5000000e: bff5 j 5000000a <_loop>
|
||||
//
|
||||
// 50000010 <data>:
|
||||
// 50000010: 0000 0000
|
||||
|
||||
const CODE: &[u8] = &[
|
||||
0x17, 0x05, 0x00, 0x00, 0x13, 0x05, 0x05, 0x01, 0x81, 0x45, 0x85, 0x05, 0x0c, 0xc1, 0xf5, 0xbf,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
];
|
||||
|
||||
#[entry]
|
||||
fn main() -> ! {
|
||||
let peripherals = Peripherals::take();
|
||||
let mut system = peripherals.SYSTEM.split();
|
||||
let clocks = ClockControl::boot_defaults(system.clock_control).freeze();
|
||||
|
||||
let timer_group0 = TimerGroup::new(
|
||||
peripherals.TIMG0,
|
||||
&clocks,
|
||||
&mut system.peripheral_clock_control,
|
||||
);
|
||||
let mut wdt = timer_group0.wdt;
|
||||
let mut rtc = Rtc::new(peripherals.RTC_CNTL);
|
||||
|
||||
// Disable MWDT and RWDT (Watchdog) flash boot protection
|
||||
wdt.disable();
|
||||
rtc.rwdt.disable();
|
||||
|
||||
let mut ulp_core = esp32s2_hal::ulp_core::UlpCore::new(peripherals.ULP_RISCV_CORE);
|
||||
|
||||
// copy code to RTC ram
|
||||
let lp_ram = 0x5000_0000 as *mut u8;
|
||||
unsafe {
|
||||
core::ptr::copy_nonoverlapping(CODE as *const _ as *const u8, lp_ram, CODE.len());
|
||||
}
|
||||
println!("copied code (len {})", CODE.len());
|
||||
|
||||
// start ULP core
|
||||
ulp_core.run(esp32s2_hal::ulp_core::UlpCoreWakeupSource::HpCpu);
|
||||
println!("ulpcore run");
|
||||
|
||||
let data = (0x5000_0010 - 0) as *mut u32;
|
||||
loop {
|
||||
println!("Current {}", unsafe { data.read_volatile() });
|
||||
}
|
||||
}
|
74
esp32s3-hal/examples/ulp_riscv_core_basic.rs
Normal file
74
esp32s3-hal/examples/ulp_riscv_core_basic.rs
Normal file
@ -0,0 +1,74 @@
|
||||
//! This shows a very basic example of running code on the ULP RISCV core.
|
||||
//!
|
||||
//! Code on ULP core just increments a counter. The current value is printed by
|
||||
//! the HP core.
|
||||
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
use esp32s3_hal::{
|
||||
clock::ClockControl,
|
||||
peripherals::Peripherals,
|
||||
prelude::*,
|
||||
timer::TimerGroup,
|
||||
Rtc,
|
||||
};
|
||||
use esp_backtrace as _;
|
||||
use esp_println::println;
|
||||
|
||||
// 50000000 <_start>:
|
||||
// 50000000: 00000517 auipc a0,0x0
|
||||
// 50000004: 01050513 addi a0,a0,16 # 50000010 <data>
|
||||
// 50000008: 4581 li a1,0
|
||||
//
|
||||
// 5000000a <_loop>:
|
||||
// 5000000a: 0585 addi a1,a1,1
|
||||
// 5000000c: c10c sw a1,0(a0)
|
||||
// 5000000e: bff5 j 5000000a <_loop>
|
||||
//
|
||||
// 50000010 <data>:
|
||||
// 50000010: 0000 0000
|
||||
|
||||
const CODE: &[u8] = &[
|
||||
0x17, 0x05, 0x00, 0x00, 0x13, 0x05, 0x05, 0x01, 0x81, 0x45, 0x85, 0x05, 0x0c, 0xc1, 0xf5, 0xbf,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
];
|
||||
|
||||
#[entry]
|
||||
fn main() -> ! {
|
||||
let peripherals = Peripherals::take();
|
||||
let mut system = peripherals.SYSTEM.split();
|
||||
let clocks = ClockControl::boot_defaults(system.clock_control).freeze();
|
||||
|
||||
let timer_group0 = TimerGroup::new(
|
||||
peripherals.TIMG0,
|
||||
&clocks,
|
||||
&mut system.peripheral_clock_control,
|
||||
);
|
||||
let mut wdt = timer_group0.wdt;
|
||||
let mut rtc = Rtc::new(peripherals.RTC_CNTL);
|
||||
|
||||
// Disable MWDT and RWDT (Watchdog) flash boot protection
|
||||
wdt.disable();
|
||||
rtc.rwdt.disable();
|
||||
|
||||
let mut ulp_core = esp32s3_hal::ulp_core::UlpCore::new(peripherals.ULP_RISCV_CORE);
|
||||
ulp_core.stop();
|
||||
println!("ulp core stopped");
|
||||
|
||||
// copy code to RTC ram
|
||||
let lp_ram = 0x5000_0000 as *mut u8;
|
||||
unsafe {
|
||||
core::ptr::copy_nonoverlapping(CODE as *const _ as *const u8, lp_ram, CODE.len());
|
||||
}
|
||||
println!("copied code (len {})", CODE.len());
|
||||
|
||||
// start ULP core
|
||||
ulp_core.run(esp32s3_hal::ulp_core::UlpCoreWakeupSource::HpCpu);
|
||||
println!("ulpcore run");
|
||||
|
||||
let data = (0x5000_0010 - 0) as *mut u32;
|
||||
loop {
|
||||
println!("Current {}", unsafe { data.read_volatile() });
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user