mirror of
https://github.com/rtic-rs/rtic.git
synced 2025-12-17 21:35:20 +01:00
Port ESP32-C3 changes to ESP32-C6 branch
This commit is contained in:
parent
0efb77300e
commit
ef09e4b65f
13 changed files with 916 additions and 454 deletions
994
examples/esp32c6/Cargo.lock
generated
994
examples/esp32c6/Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
|
@ -7,18 +7,19 @@ license = "MIT OR Apache-2.0"
|
||||||
[workspace]
|
[workspace]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
rtic = {path = "../../rtic/"}
|
rtic = { path = "../../rtic/" }
|
||||||
esp-hal = { version = "0.16.1", features = ["esp32c6", "direct-vectoring", "interrupt-preemption"] }
|
rtic-monotonics = {path = "../../rtic-monotonics/"}
|
||||||
esp-backtrace = { version = "0.11.0", features = [
|
esp-hal = { version = "0.23.1", features = ["esp32c6"] }
|
||||||
|
esp-backtrace = { version = "0.15.1", features = [
|
||||||
"esp32c6",
|
"esp32c6",
|
||||||
"panic-handler",
|
"panic-handler",
|
||||||
"exception-handler",
|
"exception-handler",
|
||||||
"println",
|
"println",
|
||||||
] }
|
] }
|
||||||
|
|
||||||
esp32c6 = {version = "0.12.0", features = ["critical-section"]}
|
esp32c6 = {version = "0.18.0", features = ["critical-section"]}
|
||||||
esp-println = { version = "0.9.0", default-features=false, features = ["esp32c6", "uart"] }
|
esp-println = { version = "0.13.1", features = ["esp32c6", "auto"] }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
test-critical-section = []
|
test-critical-section = []
|
||||||
riscv-esp32c6-backend = ["rtic/riscv-esp32c6-backend"]
|
riscv-esp32c6-backend = ["rtic/riscv-esp32c6-backend", "rtic-monotonics/esp32c6-systimer"]
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
### ESP32-C3 RTIC template
|
### ESP32-C6 RTIC template
|
||||||
This crate showcases a simple RTIC application for the ESP32-C6.
|
This crate showcases a simple RTIC application for the ESP32-C6.
|
||||||
|
|
||||||
## Prerequisites
|
## Prerequisites
|
||||||
|
|
@ -20,7 +20,7 @@ This crate uses the most convenient option in ``cargo-espflash`` and ``espflash`
|
||||||
should do the trick.
|
should do the trick.
|
||||||
|
|
||||||
# Expected behavior
|
# Expected behavior
|
||||||
The program
|
The example ``sw_and_hw``
|
||||||
- Prints ``init``
|
- Prints ``init``
|
||||||
- Enters a high prio task
|
- Enters a high prio task
|
||||||
- During the execution of the high prio task, the button should be non-functional
|
- During the execution of the high prio task, the button should be non-functional
|
||||||
|
|
@ -31,3 +31,9 @@ The program
|
||||||
- Exits the low prio task
|
- Exits the low prio task
|
||||||
- Prints ``idle``
|
- Prints ``idle``
|
||||||
|
|
||||||
|
The example ``monotonic``
|
||||||
|
- Prints ``init``
|
||||||
|
- Spawns the ``foo``, ``bar``, ``baz`` tasks (because of hardware interrupt latency dispatch, the order here may vary).
|
||||||
|
- Each task prints ``hello from $TASK`` on entry
|
||||||
|
- The tasks wait for 1, 2, 3 seconds respectively
|
||||||
|
- Once the wait period is over, each task exits printing ``bye from $TASK`` (now in the proper order).
|
||||||
|
|
|
||||||
51
examples/esp32c6/examples/monotonic.rs
Normal file
51
examples/esp32c6/examples/monotonic.rs
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
#![no_main]
|
||||||
|
#![no_std]
|
||||||
|
use esp_backtrace as _;
|
||||||
|
#[rtic::app(device = esp32c6, dispatchers = [])]
|
||||||
|
mod app {
|
||||||
|
use rtic_monotonics::esp32c6::prelude::*;
|
||||||
|
esp32c6_systimer_monotonic!(Mono);
|
||||||
|
use esp_hal as _;
|
||||||
|
use esp_println::println;
|
||||||
|
|
||||||
|
#[shared]
|
||||||
|
struct Shared {}
|
||||||
|
|
||||||
|
#[local]
|
||||||
|
struct Local {}
|
||||||
|
|
||||||
|
#[init]
|
||||||
|
fn init(cx: init::Context) -> (Shared, Local) {
|
||||||
|
println!("init");
|
||||||
|
let timer = cx.device.SYSTIMER;
|
||||||
|
|
||||||
|
Mono::start(timer);
|
||||||
|
|
||||||
|
foo::spawn().unwrap();
|
||||||
|
bar::spawn().unwrap();
|
||||||
|
baz::spawn().unwrap();
|
||||||
|
|
||||||
|
(Shared {}, Local {})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[task]
|
||||||
|
async fn foo(_cx: foo::Context) {
|
||||||
|
println!("hello from foo");
|
||||||
|
Mono::delay(2_u64.secs()).await;
|
||||||
|
println!("bye from foo");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[task]
|
||||||
|
async fn bar(_cx: bar::Context) {
|
||||||
|
println!("hello from bar");
|
||||||
|
Mono::delay(3_u64.secs()).await;
|
||||||
|
println!("bye from bar");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[task]
|
||||||
|
async fn baz(_cx: baz::Context) {
|
||||||
|
println!("hello from baz");
|
||||||
|
Mono::delay(4_u64.secs()).await;
|
||||||
|
println!("bye from baz");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -4,27 +4,23 @@
|
||||||
#[rtic::app(device = esp32c6, dispatchers=[FROM_CPU_INTR0, FROM_CPU_INTR1])]
|
#[rtic::app(device = esp32c6, dispatchers=[FROM_CPU_INTR0, FROM_CPU_INTR1])]
|
||||||
mod app {
|
mod app {
|
||||||
use esp_backtrace as _;
|
use esp_backtrace as _;
|
||||||
use esp_hal::{
|
use esp_hal::gpio::{Event, Input, Pull};
|
||||||
gpio::{Event, Gpio9, Input, PullUp, IO},
|
|
||||||
peripherals::Peripherals,
|
|
||||||
prelude::*,
|
|
||||||
};
|
|
||||||
use esp_println::println;
|
use esp_println::println;
|
||||||
|
|
||||||
#[shared]
|
#[shared]
|
||||||
struct Shared {}
|
struct Shared {}
|
||||||
|
|
||||||
#[local]
|
#[local]
|
||||||
struct Local {
|
struct Local {
|
||||||
button: Gpio9<Input<PullUp>>,
|
button: Input<'static>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// do nothing in init
|
// do nothing in init
|
||||||
#[init]
|
#[init]
|
||||||
fn init(_: init::Context) -> (Shared, Local) {
|
fn init(_: init::Context) -> (Shared, Local) {
|
||||||
println!("init");
|
println!("init");
|
||||||
let peripherals = Peripherals::take();
|
let peripherals = esp_hal::init(esp_hal::Config::default());
|
||||||
let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);
|
let mut button = Input::new(peripherals.GPIO9, Pull::Up);
|
||||||
let mut button = io.pins.gpio9.into_pull_up_input();
|
|
||||||
button.listen(Event::FallingEdge);
|
button.listen(Event::FallingEdge);
|
||||||
foo::spawn().unwrap();
|
foo::spawn().unwrap();
|
||||||
(Shared {}, Local { button })
|
(Shared {}, Local { button })
|
||||||
|
|
@ -41,17 +37,18 @@ mod app {
|
||||||
bar::spawn().unwrap(); //enqueue low prio task
|
bar::spawn().unwrap(); //enqueue low prio task
|
||||||
println!("Inside high prio task, press button now!");
|
println!("Inside high prio task, press button now!");
|
||||||
let mut x = 0;
|
let mut x = 0;
|
||||||
while x < 5000000 {
|
while x < 50000000 {
|
||||||
x += 1; //burn cycles
|
x += 1; //burn cycles
|
||||||
esp_hal::riscv::asm::nop();
|
esp_hal::riscv::asm::nop();
|
||||||
}
|
}
|
||||||
println!("Leaving high prio task.");
|
println!("Leaving high prio task.");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[task(priority = 2)]
|
#[task(priority = 2)]
|
||||||
async fn bar(_: bar::Context) {
|
async fn bar(_: bar::Context) {
|
||||||
println!("Inside low prio task, press button now!");
|
println!("Inside low prio task, press button now!");
|
||||||
let mut x = 0;
|
let mut x = 0;
|
||||||
while x < 5000000 {
|
while x < 50000000 {
|
||||||
x += 1; //burn cycles
|
x += 1; //burn cycles
|
||||||
esp_hal::riscv::asm::nop();
|
esp_hal::riscv::asm::nop();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
[toolchain]
|
[toolchain]
|
||||||
channel = "nightly-2023-11-14"
|
channel = "nightly-2023-11-14"
|
||||||
components = ["rust-src"]
|
components = ["rust-src"]
|
||||||
targets = ["riscv32imc-unknown-none-elf"]
|
targets = ["riscv32imac-unknown-none-elf"]
|
||||||
|
|
|
||||||
|
|
@ -86,23 +86,30 @@ mod esp32c6 {
|
||||||
}
|
}
|
||||||
stmts
|
stmts
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn pre_init_enable_interrupts(app: &App, analysis: &CodegenAnalysis) -> Vec<TokenStream2> {
|
pub fn pre_init_enable_interrupts(app: &App, analysis: &CodegenAnalysis) -> Vec<TokenStream2> {
|
||||||
let mut stmts = vec![];
|
let mut stmts = vec![];
|
||||||
let rt_err = util::rt_err_ident();
|
let rt_err = util::rt_err_ident();
|
||||||
let max_prio: usize = 15; //unfortunately this is not part of pac, but we know that max prio is 15.
|
let max_prio: usize = 15; //unfortunately this is not part of pac, but we know that max prio is 15.
|
||||||
|
let min_prio: usize = 1;
|
||||||
let interrupt_ids = analysis.interrupts.iter().map(|(p, (id, _))| (p, id));
|
let interrupt_ids = analysis.interrupts.iter().map(|(p, (id, _))| (p, id));
|
||||||
// Unmask interrupts and set their priorities
|
// Unmask interrupts and set their priorities
|
||||||
for ((&priority, name), curr_cpu_id) in interrupt_ids.chain(
|
for ((&priority, name), curr_cpu_id) in interrupt_ids
|
||||||
app.hardware_tasks
|
.chain(
|
||||||
.values()
|
app.hardware_tasks
|
||||||
.filter_map(|task| Some((&task.args.priority, &task.args.binds))),
|
.values()
|
||||||
).zip(EXTERNAL_INTERRUPTS) {
|
.filter_map(|task| Some((&task.args.priority, &task.args.binds))),
|
||||||
|
)
|
||||||
|
.zip(EXTERNAL_INTERRUPTS)
|
||||||
|
{
|
||||||
let es = format!(
|
let es = format!(
|
||||||
"Maximum priority used by interrupt vector '{name}' is more than supported by hardware"
|
"Maximum priority used by interrupt vector '{name}' is more than supported by hardware"
|
||||||
);
|
);
|
||||||
|
let es_zero = format!("Priority {priority} used by interrupt vector '{name}' is less than supported by hardware");
|
||||||
// Compile time assert that this priority is supported by the device
|
// Compile time assert that this priority is supported by the device
|
||||||
stmts.push(quote!(
|
stmts.push(quote!(
|
||||||
const _: () = if (#max_prio) <= #priority as usize { ::core::panic!(#es); };
|
const _: () = if (#max_prio) <= #priority as usize { ::core::panic!(#es); };
|
||||||
|
const _: () = if (#min_prio) > #priority as usize { ::core::panic!(#es_zero);};
|
||||||
));
|
));
|
||||||
stmts.push(quote!(
|
stmts.push(quote!(
|
||||||
rtic::export::enable(
|
rtic::export::enable(
|
||||||
|
|
@ -207,13 +214,11 @@ mod esp32c6 {
|
||||||
stmts
|
stmts
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn async_prio_limit(app: &App, analysis: &CodegenAnalysis) -> Vec<TokenStream2> {
|
pub fn async_prio_limit(_app: &App, analysis: &CodegenAnalysis) -> Vec<TokenStream2> {
|
||||||
let max = if let Some(max) = analysis.max_async_prio {
|
let max = if let Some(max) = analysis.max_async_prio {
|
||||||
quote!(#max)
|
quote!(#max)
|
||||||
} else {
|
} else {
|
||||||
// No limit
|
quote!(u8::MAX) // No limit
|
||||||
let device = &app.args.device;
|
|
||||||
quote!(1 << #device::NVIC_PRIO_BITS)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
vec![quote!(
|
vec![quote!(
|
||||||
|
|
@ -222,6 +227,7 @@ mod esp32c6 {
|
||||||
static RTIC_ASYNC_MAX_LOGICAL_PRIO: u8 = #max;
|
static RTIC_ASYNC_MAX_LOGICAL_PRIO: u8 = #max;
|
||||||
)]
|
)]
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn handler_config(
|
pub fn handler_config(
|
||||||
app: &App,
|
app: &App,
|
||||||
analysis: &CodegenAnalysis,
|
analysis: &CodegenAnalysis,
|
||||||
|
|
@ -229,14 +235,20 @@ mod esp32c6 {
|
||||||
) -> Vec<TokenStream2> {
|
) -> Vec<TokenStream2> {
|
||||||
let mut stmts = vec![];
|
let mut stmts = vec![];
|
||||||
let interrupt_ids = analysis.interrupts.iter().map(|(p, (id, _))| (p, id));
|
let interrupt_ids = analysis.interrupts.iter().map(|(p, (id, _))| (p, id));
|
||||||
for ((_, name), curr_cpu_id) in interrupt_ids.chain(
|
for ((_, name), curr_cpu_id) in interrupt_ids
|
||||||
app.hardware_tasks
|
.chain(
|
||||||
.values()
|
app.hardware_tasks
|
||||||
.filter_map(|task| Some((&task.args.priority, &task.args.binds))),
|
.values()
|
||||||
).zip(EXTERNAL_INTERRUPTS) {
|
.filter_map(|task| Some((&task.args.priority, &task.args.binds))),
|
||||||
if *name == dispatcher_name {
|
)
|
||||||
let ret = &("cpu_int_".to_owned() + &curr_cpu_id.to_string() + "_handler");
|
.zip(EXTERNAL_INTERRUPTS)
|
||||||
stmts.push(quote!(#[export_name = #ret]));
|
{
|
||||||
|
// interrupt1...interrupt19 are already defined in esp_hal
|
||||||
|
if curr_cpu_id > 19 {
|
||||||
|
if *name == dispatcher_name {
|
||||||
|
let ret = &("interrupt".to_owned() + &curr_cpu_id.to_string());
|
||||||
|
stmts.push(quote!(#[export_name = #ret]));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,7 @@ features = [
|
||||||
"stm32_tim5",
|
"stm32_tim5",
|
||||||
"stm32_tim15",
|
"stm32_tim15",
|
||||||
"esp32c3-systimer",
|
"esp32c3-systimer",
|
||||||
|
"esp32c6-systimer",
|
||||||
]
|
]
|
||||||
rustdoc-flags = ["--cfg", "docsrs"]
|
rustdoc-flags = ["--cfg", "docsrs"]
|
||||||
|
|
||||||
|
|
@ -66,10 +67,9 @@ stm32-metapac = { version = "15.0.0", optional = true }
|
||||||
# i.MX RT
|
# i.MX RT
|
||||||
imxrt-ral = { version = "0.5.3", optional = true }
|
imxrt-ral = { version = "0.5.3", optional = true }
|
||||||
|
|
||||||
|
|
||||||
esp32c3 = {version = "0.28.0", optional = true }
|
esp32c3 = {version = "0.28.0", optional = true }
|
||||||
riscv = {version = "0.12.1", optional = true }
|
esp32c6 = {version = "0.18.0", optional = true }
|
||||||
|
riscv = {version = "0.13.0", optional = true }
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
proc-macro2 = { version = "1.0.36", optional = true }
|
proc-macro2 = { version = "1.0.36", optional = true }
|
||||||
|
|
@ -110,8 +110,9 @@ imxrt = ["dep:cortex-m", "dep:imxrt-ral"]
|
||||||
imxrt_gpt1 = ["imxrt"]
|
imxrt_gpt1 = ["imxrt"]
|
||||||
imxrt_gpt2 = ["imxrt"]
|
imxrt_gpt2 = ["imxrt"]
|
||||||
|
|
||||||
# ESP32-C3 Timer
|
# ESP32 Timers
|
||||||
esp32c3-systimer = ["dep:esp32c3", "dep:riscv"]
|
esp32c3-systimer = ["dep:esp32c3", "dep:riscv"]
|
||||||
|
esp32c6-systimer = ["dep:esp32c6", "dep:riscv"]
|
||||||
|
|
||||||
# STM32 timers
|
# STM32 timers
|
||||||
# Use as `features = ["stm32g081kb", "stm32_tim15"]`
|
# Use as `features = ["stm32g081kb", "stm32_tim15"]`
|
||||||
|
|
|
||||||
187
rtic-monotonics/src/esp32c6.rs
Normal file
187
rtic-monotonics/src/esp32c6.rs
Normal file
|
|
@ -0,0 +1,187 @@
|
||||||
|
//! [`Monotonic`](rtic_time::Monotonic) implementation for ESP32-C6's SYSTIMER.
|
||||||
|
//!
|
||||||
|
//! Always runs at a fixed rate of 16 MHz.
|
||||||
|
//!
|
||||||
|
//! # Example
|
||||||
|
//!
|
||||||
|
//! ```
|
||||||
|
//! use rtic_monotonics::esp32c6::prelude::*;
|
||||||
|
//!
|
||||||
|
//! esp32c6_systimer_monotonic!(Mono);
|
||||||
|
//!
|
||||||
|
//! fn init() {
|
||||||
|
//! # // This is normally provided by the selected PAC
|
||||||
|
//! # let timer = unsafe { esp32c6::Peripherals::steal() }.SYSTIMER;
|
||||||
|
//! #
|
||||||
|
//! // Start the monotonic
|
||||||
|
//! Mono::start(timer);
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! async fn usage() {
|
||||||
|
//! loop {
|
||||||
|
//! // Use the monotonic
|
||||||
|
//! let timestamp = Mono::now();
|
||||||
|
//! Mono::delay(100.millis()).await;
|
||||||
|
//! }
|
||||||
|
//! }
|
||||||
|
//! ```
|
||||||
|
|
||||||
|
/// Common definitions and traits for using the ESP32-C6 timer monotonic
|
||||||
|
pub mod prelude {
|
||||||
|
pub use crate::esp32c6_systimer_monotonic;
|
||||||
|
|
||||||
|
pub use crate::Monotonic;
|
||||||
|
|
||||||
|
pub use fugit::{self, ExtU64, ExtU64Ceil};
|
||||||
|
}
|
||||||
|
use crate::TimerQueueBackend;
|
||||||
|
use esp32c6::{INTERRUPT_CORE0, INTPRI, SYSTIMER};
|
||||||
|
use rtic_time::timer_queue::TimerQueue;
|
||||||
|
|
||||||
|
/// Timer implementing [`TimerQueueBackend`].
|
||||||
|
pub struct TimerBackend;
|
||||||
|
|
||||||
|
impl TimerBackend {
|
||||||
|
/// Starts the monotonic timer.
|
||||||
|
///
|
||||||
|
/// **Do not use this function directly.**
|
||||||
|
///
|
||||||
|
/// Use the prelude macros instead.
|
||||||
|
pub fn _start(timer: SYSTIMER) {
|
||||||
|
let interrupt_number = 57 as isize;
|
||||||
|
let cpu_interrupt_number = 31 as isize;
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
(INTERRUPT_CORE0::ptr() as *mut u32)
|
||||||
|
.offset(interrupt_number as isize)
|
||||||
|
.write_volatile(cpu_interrupt_number as u32);
|
||||||
|
|
||||||
|
// Set the interrupt's priority:
|
||||||
|
(*INTPRI::ptr())
|
||||||
|
.cpu_int_pri(cpu_interrupt_number as usize)
|
||||||
|
.write(|w| w.bits(15 as u32));
|
||||||
|
|
||||||
|
// Finally, enable the CPU interrupt:
|
||||||
|
(*INTPRI::ptr())
|
||||||
|
.cpu_int_enable()
|
||||||
|
.modify(|r, w| w.bits((1 << cpu_interrupt_number) | r.bits()));
|
||||||
|
}
|
||||||
|
|
||||||
|
timer.conf().write(|w| w.timer_unit0_work_en().set_bit());
|
||||||
|
timer
|
||||||
|
.conf()
|
||||||
|
.write(|w| w.timer_unit1_core0_stall_en().clear_bit());
|
||||||
|
|
||||||
|
TIMER_QUEUE.initialize(Self {})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static TIMER_QUEUE: TimerQueue<TimerBackend> = TimerQueue::new();
|
||||||
|
use esp32c6;
|
||||||
|
impl TimerQueueBackend for TimerBackend {
|
||||||
|
type Ticks = u64;
|
||||||
|
fn now() -> Self::Ticks {
|
||||||
|
let peripherals = unsafe { esp32c6::Peripherals::steal() };
|
||||||
|
peripherals
|
||||||
|
.SYSTIMER
|
||||||
|
.unit0_op()
|
||||||
|
.write(|w| w.update().set_bit());
|
||||||
|
// this must be polled until value is valid
|
||||||
|
while peripherals.SYSTIMER.unit0_op().read().value_valid() == false {}
|
||||||
|
let instant: u64 = (peripherals.SYSTIMER.unit_value(0).lo().read().bits() as u64)
|
||||||
|
| ((peripherals.SYSTIMER.unit_value(0).hi().read().bits() as u64) << 32);
|
||||||
|
instant
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_compare(instant: Self::Ticks) {
|
||||||
|
let systimer = unsafe { esp32c6::Peripherals::steal() }.SYSTIMER;
|
||||||
|
systimer
|
||||||
|
.target0_conf()
|
||||||
|
.write(|w| w.timer_unit_sel().set_bit());
|
||||||
|
systimer
|
||||||
|
.target0_conf()
|
||||||
|
.write(|w| w.period_mode().clear_bit());
|
||||||
|
systimer
|
||||||
|
.trgt(0)
|
||||||
|
.lo()
|
||||||
|
.write(|w| unsafe { w.bits((instant & 0xFFFFFFFF).try_into().unwrap()) });
|
||||||
|
systimer
|
||||||
|
.trgt(0)
|
||||||
|
.hi()
|
||||||
|
.write(|w| unsafe { w.bits((instant >> 32).try_into().unwrap()) });
|
||||||
|
systimer.comp0_load().write(|w| w.load().set_bit()); //sync period to comp register
|
||||||
|
systimer.conf().write(|w| w.target0_work_en().set_bit());
|
||||||
|
systimer.int_ena().write(|w| w.target0().set_bit());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clear_compare_flag() {
|
||||||
|
unsafe { esp32c6::Peripherals::steal() }
|
||||||
|
.SYSTIMER
|
||||||
|
.int_clr()
|
||||||
|
.write(|w| w.target0().bit(true));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pend_interrupt() {
|
||||||
|
extern "C" {
|
||||||
|
fn interrupt31();
|
||||||
|
}
|
||||||
|
//run the timer interrupt handler in a critical section to emulate a max priority
|
||||||
|
//interrupt.
|
||||||
|
//since there is no hardware support for pending a timer interrupt.
|
||||||
|
riscv::interrupt::disable();
|
||||||
|
unsafe { interrupt31() };
|
||||||
|
unsafe { riscv::interrupt::enable() };
|
||||||
|
}
|
||||||
|
|
||||||
|
fn timer_queue() -> &'static TimerQueue<Self> {
|
||||||
|
&TIMER_QUEUE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create an ESP32-C6 SysTimer based monotonic and register the necessary interrupt for it.
|
||||||
|
///
|
||||||
|
/// See [`crate::esp32c6`] for more details.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `name` - The name that the monotonic type will have.
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! esp32c6_systimer_monotonic {
|
||||||
|
($name:ident) => {
|
||||||
|
/// A `Monotonic` based on the ESP32-C6 SysTimer peripheral.
|
||||||
|
pub struct $name;
|
||||||
|
|
||||||
|
impl $name {
|
||||||
|
/// Starts the `Monotonic`.
|
||||||
|
///
|
||||||
|
/// This method must be called only once.
|
||||||
|
pub fn start(timer: esp32c6::SYSTIMER) {
|
||||||
|
#[export_name = "interrupt31"]
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
unsafe extern "C" fn Systimer() {
|
||||||
|
use $crate::TimerQueueBackend;
|
||||||
|
$crate::esp32c6::TimerBackend::timer_queue().on_monotonic_interrupt();
|
||||||
|
}
|
||||||
|
|
||||||
|
$crate::esp32c6::TimerBackend::_start(timer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl $crate::TimerQueueBasedMonotonic for $name {
|
||||||
|
type Backend = $crate::esp32c6::TimerBackend;
|
||||||
|
type Instant = $crate::fugit::Instant<
|
||||||
|
<Self::Backend as $crate::TimerQueueBackend>::Ticks,
|
||||||
|
1,
|
||||||
|
16_000_000,
|
||||||
|
>;
|
||||||
|
type Duration = $crate::fugit::Duration<
|
||||||
|
<Self::Backend as $crate::TimerQueueBackend>::Ticks,
|
||||||
|
1,
|
||||||
|
16_000_000,
|
||||||
|
>;
|
||||||
|
}
|
||||||
|
|
||||||
|
$crate::rtic_time::impl_embedded_hal_delay_fugit!($name);
|
||||||
|
$crate::rtic_time::impl_embedded_hal_async_delay_fugit!($name);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
@ -54,6 +54,9 @@ pub use rtic_time::{
|
||||||
#[cfg(feature = "esp32c3-systimer")]
|
#[cfg(feature = "esp32c3-systimer")]
|
||||||
pub mod esp32c3;
|
pub mod esp32c3;
|
||||||
|
|
||||||
|
#[cfg(feature = "esp32c6-systimer")]
|
||||||
|
pub mod esp32c6;
|
||||||
|
|
||||||
#[cfg(feature = "cortex-m-systick")]
|
#[cfg(feature = "cortex-m-systick")]
|
||||||
pub mod systick;
|
pub mod systick;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ name = "rtic"
|
||||||
riscv-slic = { version = "0.2.0", optional = true }
|
riscv-slic = { version = "0.2.0", optional = true }
|
||||||
esp32c3 = { version = "0.28.0", optional = true }
|
esp32c3 = { version = "0.28.0", optional = true }
|
||||||
esp32c6 = { version = "0.19.0", optional = true }
|
esp32c6 = { version = "0.19.0", optional = true }
|
||||||
riscv = { version = "0.12.1", optional = true }
|
riscv = { version = "0.13.0", optional = true }
|
||||||
cortex-m = { version = "0.7.0", optional = true }
|
cortex-m = { version = "0.7.0", optional = true }
|
||||||
bare-metal = "1.0.0"
|
bare-metal = "1.0.0"
|
||||||
portable-atomic = { version = "1", default-features = false }
|
portable-atomic = { version = "1", default-features = false }
|
||||||
|
|
|
||||||
|
|
@ -72,13 +72,13 @@ pub unsafe fn lock<T, R>(ptr: *mut T, ceiling: u8, f: impl FnOnce(&mut T) -> R)
|
||||||
unsafe {
|
unsafe {
|
||||||
(*INTPRI::ptr())
|
(*INTPRI::ptr())
|
||||||
.cpu_int_thresh()
|
.cpu_int_thresh()
|
||||||
.write(|w| w.cpu_int_thresh().bits(ceiling + 1))
|
.write(|w| w.cpu_int_thresh().bits(ceiling + 1));
|
||||||
} //esp32c6 lets interrupts with prio equal to threshold through so we up it by one
|
} //esp32c6 lets interrupts with prio equal to threshold through so we up it by one
|
||||||
let r = f(&mut *ptr);
|
let r = f(&mut *ptr);
|
||||||
unsafe {
|
unsafe {
|
||||||
(*INTPRI::ptr())
|
(*INTPRI::ptr())
|
||||||
.cpu_int_thresh()
|
.cpu_int_thresh()
|
||||||
.write(|w| w.cpu_int_thresh().bits(current))
|
.write(|w| w.cpu_int_thresh().bits(current));
|
||||||
}
|
}
|
||||||
r
|
r
|
||||||
}
|
}
|
||||||
|
|
@ -107,7 +107,7 @@ pub fn pend(int: Interrupt) {
|
||||||
.cpu_intr_from_cpu_3()
|
.cpu_intr_from_cpu_3()
|
||||||
.write(|w| w.cpu_intr_from_cpu_3().bit(true)),
|
.write(|w| w.cpu_intr_from_cpu_3().bit(true)),
|
||||||
_ => panic!("Unsupported software interrupt"), //should never happen, checked at compile time
|
_ => panic!("Unsupported software interrupt"), //should never happen, checked at compile time
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -133,29 +133,25 @@ pub fn unpend(int: Interrupt) {
|
||||||
.cpu_intr_from_cpu_3()
|
.cpu_intr_from_cpu_3()
|
||||||
.write(|w| w.cpu_intr_from_cpu_3().bit(false)),
|
.write(|w| w.cpu_intr_from_cpu_3().bit(false)),
|
||||||
_ => panic!("Unsupported software interrupt"),
|
_ => panic!("Unsupported software interrupt"),
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn enable(int: Interrupt, prio: u8, cpu_int_id: u8) {
|
pub fn enable(int: Interrupt, prio: u8, cpu_int_id: u8) {
|
||||||
const INTERRUPT_MAP_BASE: *mut u32 =
|
|
||||||
unsafe { core::mem::transmute::<_, *mut u32>(INTERRUPT_CORE0::ptr()) };
|
|
||||||
let interrupt_number = int as isize;
|
|
||||||
let cpu_interrupt_number = cpu_int_id as isize;
|
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let intr_map_base = INTERRUPT_MAP_BASE as *mut u32;
|
// Map the peripheral interrupt to a CPU interrupt:
|
||||||
intr_map_base
|
(INTERRUPT_CORE0::ptr() as *mut u32)
|
||||||
.offset(interrupt_number)
|
.offset(int as isize)
|
||||||
.write_volatile(cpu_interrupt_number as u32);
|
.write_volatile(cpu_int_id as u32);
|
||||||
|
|
||||||
let intr_prio_base = (*INTPRI::ptr()).cpu_int_pri_0().as_ptr();
|
// Set the interrupt's priority:
|
||||||
intr_prio_base
|
(*INTPRI::ptr())
|
||||||
.offset(cpu_interrupt_number)
|
.cpu_int_pri(cpu_int_id as usize)
|
||||||
.write_volatile(prio as u32);
|
.write(|w| w.bits(prio as u32));
|
||||||
|
|
||||||
|
// Finally, enable the CPU interrupt:
|
||||||
(*INTPRI::ptr())
|
(*INTPRI::ptr())
|
||||||
.cpu_int_enable()
|
.cpu_int_enable()
|
||||||
.modify(|r, w| w.bits((1 << cpu_interrupt_number) | r.bits()));
|
.modify(|r, w| w.bits((1 << cpu_int_id) | r.bits()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
[toolchain]
|
[toolchain]
|
||||||
channel = "stable"
|
channel = "stable"
|
||||||
components = [ "rust-src", "rustfmt", "llvm-tools-preview" ]
|
components = [ "rust-src", "rustfmt", "llvm-tools-preview" ]
|
||||||
targets = [ "thumbv6m-none-eabi", "thumbv7m-none-eabi", "thumbv8m.base-none-eabi", "thumbv8m.main-none-eabi" ]
|
targets = [ "thumbv6m-none-eabi", "thumbv7m-none-eabi", "thumbv8m.base-none-eabi", "thumbv8m.main-none-eabi", "riscv32imc-unknown-none-elf" ]
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue