mirror of
https://github.com/esp-rs/esp-hal.git
synced 2025-09-28 04:40:52 +00:00
RISCV vectored interrupts (#118)
* RISCV interrupt vectoring - Adds support for vectoring peripheral interrupts to PAC handlers - Currently supports level interrupts with priorities from 1-15 - Updated the gpio interrupt example to reflect the new changes * remove .vscode files * Support vectored edge interrupts This is as simple as making sure we clear the CPU interrupt whenever we receive one. This also documents further what APIs are safe to call when the `vectored` feature is enabled. * fix all examples to use vectoring * doc & cleanup * run handlers from ram * make xtensa::interrupt::vectored private, we rexport public items * fix default handlers * pass interrupt into EspDefaultHandler
This commit is contained in:
parent
1789780d06
commit
1d02bf87c3
28
.vscode/settings.json
vendored
28
.vscode/settings.json
vendored
@ -1,28 +0,0 @@
|
||||
{
|
||||
"editor.formatOnSave": true,
|
||||
"rust-analyzer.cargo.buildScripts.enable": true,
|
||||
"rust-analyzer.cargo.noDefaultFeatures": true,
|
||||
"rust-analyzer.checkOnSave.allTargets": false,
|
||||
"rust-analyzer.imports.granularity.enforce": true,
|
||||
"rust-analyzer.imports.granularity.group": "crate",
|
||||
"rust-analyzer.procMacro.attributes.enable": false,
|
||||
"rust-analyzer.procMacro.enable": true,
|
||||
// -----------------------------------------------------------------------
|
||||
// Since we have to handle multiple toolchains AND multiple targets, we
|
||||
// we need to give Rust Analyzer some directions.
|
||||
//
|
||||
// Enable ONE target and linked project based on which chip you are
|
||||
// developing for. This will propagate to the `esp-hal-common` crate too,
|
||||
// as it is a dependency. Changing target/project requires reloading
|
||||
// Rust Analyzer.
|
||||
"rust-analyzer.cargo.target": "xtensa-esp32-none-elf",
|
||||
// "rust-analyzer.cargo.target": "riscv32imc-unknown-none-elf",
|
||||
// "rust-analyzer.cargo.target": "xtensa-esp32s2-none-elf",
|
||||
// "rust-analyzer.cargo.target": "xtensa-esp32s3-none-elf",
|
||||
"rust-analyzer.linkedProjects": [
|
||||
"esp32-hal/Cargo.toml",
|
||||
// "esp32c3-hal/Cargo.toml",
|
||||
// "esp32s2-hal/Cargo.toml",
|
||||
// "esp32s3-hal/Cargo.toml",
|
||||
],
|
||||
}
|
@ -1,6 +1,21 @@
|
||||
//! Interrupt handling - RISCV
|
||||
//!
|
||||
//! When the `vectored` feature is enabled, CPU interrupts 1 through 15 are
|
||||
//! reserved for each of the possible interrupt priorities.
|
||||
//!
|
||||
//! ```rust
|
||||
//! interrupt1() => Priority::Priority1
|
||||
//! interrupt2() => Priority::Priority2
|
||||
//! ...
|
||||
//! interrupt15() => Priority::Priority15
|
||||
//! ```
|
||||
|
||||
use riscv::register::mcause;
|
||||
|
||||
use crate::{pac::Interrupt, Cpu};
|
||||
use crate::{
|
||||
pac::{self, Interrupt},
|
||||
Cpu,
|
||||
};
|
||||
|
||||
// User code shouldn't usually take the mutable TrapFrame or the TrapFrame in
|
||||
// general. However this makes things like preemtive multitasking easier in
|
||||
@ -50,6 +65,8 @@ pub enum InterruptKind {
|
||||
/// Enumeration of available CPU interrupts.
|
||||
/// It is possible to create a handler for each of the interrupts. (e.g.
|
||||
/// `interrupt3`)
|
||||
#[repr(u32)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub enum CpuInterrupt {
|
||||
Interrupt1 = 1,
|
||||
Interrupt2,
|
||||
@ -85,6 +102,7 @@ pub enum CpuInterrupt {
|
||||
}
|
||||
|
||||
/// Interrupt priority levels.
|
||||
#[repr(u8)]
|
||||
pub enum Priority {
|
||||
None,
|
||||
Priority1,
|
||||
@ -104,21 +122,26 @@ pub enum Priority {
|
||||
Priority15,
|
||||
}
|
||||
|
||||
/// Enable and assign a peripheral interrupt to an CPU interrupt.
|
||||
pub fn enable(_core: Cpu, interrupt: Interrupt, which: CpuInterrupt) {
|
||||
unsafe {
|
||||
let interrupt_number = interrupt as isize;
|
||||
let cpu_interrupt_number = which as isize;
|
||||
let intr = &*crate::pac::INTERRUPT_CORE0::PTR;
|
||||
let intr_map_base = intr.mac_intr_map.as_ptr();
|
||||
intr_map_base
|
||||
.offset(interrupt_number)
|
||||
.write_volatile(cpu_interrupt_number as u32);
|
||||
/// Assign a peripheral interrupt to an CPU interrupt.
|
||||
///
|
||||
/// Great care must be taken when using the `vectored` feature (enabled by
|
||||
/// default). Avoid interrupts 1 - 15 when interrupt vectoring is enabled.
|
||||
pub unsafe fn map(_core: Cpu, interrupt: Interrupt, which: CpuInterrupt) {
|
||||
let interrupt_number = interrupt as isize;
|
||||
let cpu_interrupt_number = which as isize;
|
||||
let intr = &*crate::pac::INTERRUPT_CORE0::PTR;
|
||||
let intr_map_base = intr.mac_intr_map.as_ptr();
|
||||
intr_map_base
|
||||
.offset(interrupt_number)
|
||||
.write_volatile(cpu_interrupt_number as u32);
|
||||
}
|
||||
|
||||
// enable interrupt
|
||||
intr.cpu_int_enable
|
||||
.modify(|r, w| w.bits((1 << cpu_interrupt_number) | r.bits()));
|
||||
}
|
||||
/// Enable a CPU interrupt
|
||||
pub unsafe fn enable_cpu_interrupt(which: CpuInterrupt) {
|
||||
let cpu_interrupt_number = which as isize;
|
||||
let intr = &*crate::pac::INTERRUPT_CORE0::PTR;
|
||||
intr.cpu_int_enable
|
||||
.modify(|r, w| w.bits((1 << cpu_interrupt_number) | r.bits()));
|
||||
}
|
||||
|
||||
/// Disable the given peripheral interrupt.
|
||||
@ -132,6 +155,9 @@ pub fn disable(_core: Cpu, interrupt: Interrupt) {
|
||||
}
|
||||
|
||||
/// Set the interrupt kind (i.e. level or edge) of an CPU interrupt
|
||||
///
|
||||
/// This is safe to call when the `vectored` feature is enabled. The vectored
|
||||
/// interrupt handler will take care of clearing edge interrupt bits.
|
||||
pub fn set_kind(_core: Cpu, which: CpuInterrupt, kind: InterruptKind) {
|
||||
unsafe {
|
||||
let intr = &*crate::pac::INTERRUPT_CORE0::PTR;
|
||||
@ -150,19 +176,22 @@ pub fn set_kind(_core: Cpu, which: CpuInterrupt, kind: InterruptKind) {
|
||||
}
|
||||
|
||||
/// Set the priority level of an CPU interrupt
|
||||
pub fn set_priority(_core: Cpu, which: CpuInterrupt, priority: Priority) {
|
||||
unsafe {
|
||||
let intr = &*crate::pac::INTERRUPT_CORE0::PTR;
|
||||
let cpu_interrupt_number = which as isize;
|
||||
let intr_prio_base = intr.cpu_int_pri_0.as_ptr();
|
||||
///
|
||||
/// Great care must be taken when using the `vectored` feature (enabled by
|
||||
/// default). Avoid changing the priority of interrupts 1 - 15 when interrupt
|
||||
/// vectoring is enabled.
|
||||
pub unsafe fn set_priority(_core: Cpu, which: CpuInterrupt, priority: Priority) {
|
||||
let intr = &*crate::pac::INTERRUPT_CORE0::PTR;
|
||||
let cpu_interrupt_number = which as isize;
|
||||
let intr_prio_base = intr.cpu_int_pri_0.as_ptr();
|
||||
|
||||
intr_prio_base
|
||||
.offset(cpu_interrupt_number as isize)
|
||||
.write_volatile(priority as u32);
|
||||
}
|
||||
intr_prio_base
|
||||
.offset(cpu_interrupt_number as isize)
|
||||
.write_volatile(priority as u32);
|
||||
}
|
||||
|
||||
/// Clear a CPU interrupt
|
||||
#[inline]
|
||||
pub fn clear(_core: Cpu, which: CpuInterrupt) {
|
||||
unsafe {
|
||||
let cpu_interrupt_number = which as isize;
|
||||
@ -173,6 +202,7 @@ pub fn clear(_core: Cpu, which: CpuInterrupt) {
|
||||
}
|
||||
|
||||
/// Get status of peripheral interrupts
|
||||
#[inline]
|
||||
pub fn get_status(_core: Cpu) -> u128 {
|
||||
unsafe {
|
||||
((*crate::pac::INTERRUPT_CORE0::PTR)
|
||||
@ -187,6 +217,204 @@ pub fn get_status(_core: Cpu) -> u128 {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "vectored")]
|
||||
pub use vectored::*;
|
||||
|
||||
#[cfg(feature = "vectored")]
|
||||
mod vectored {
|
||||
use procmacros::ram;
|
||||
|
||||
use super::*;
|
||||
|
||||
// Setup interrupts 1-15 ready for vectoring
|
||||
#[doc(hidden)]
|
||||
pub(crate) unsafe fn init_vectoring() {
|
||||
for i in 1..=15 {
|
||||
set_kind(
|
||||
crate::get_core(),
|
||||
core::mem::transmute(i),
|
||||
InterruptKind::Level,
|
||||
);
|
||||
set_priority(
|
||||
crate::get_core(),
|
||||
core::mem::transmute(i),
|
||||
core::mem::transmute(i as u8),
|
||||
);
|
||||
enable_cpu_interrupt(core::mem::transmute(i));
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the interrupts configured for the core
|
||||
#[inline]
|
||||
fn get_configured_interrupts(_core: Cpu) -> [u128; 15] {
|
||||
unsafe {
|
||||
let intr = &*crate::pac::INTERRUPT_CORE0::PTR;
|
||||
let intr_map_base = intr.mac_intr_map.as_ptr();
|
||||
let intr_prio_base = intr.cpu_int_pri_0.as_ptr();
|
||||
|
||||
let mut prios = [0u128; 15];
|
||||
|
||||
for i in 0..get_interrupt_count() {
|
||||
let i = i as isize;
|
||||
let cpu_interrupt = intr_map_base.offset(i).read_volatile();
|
||||
// safety: cast is safe because of repr(u32)
|
||||
let cpu_interrupt: CpuInterrupt = core::mem::transmute(cpu_interrupt);
|
||||
let prio = intr_prio_base
|
||||
.offset(cpu_interrupt as isize)
|
||||
.read_volatile();
|
||||
|
||||
prios[prio as usize] |= 1 << i;
|
||||
}
|
||||
|
||||
prios
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn get_interrupt_count() -> usize {
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(feature = "esp32c3")] {
|
||||
62
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Interrupt Error
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub enum Error {
|
||||
InvalidInterruptPriority,
|
||||
}
|
||||
|
||||
/// Enables a interrupt at a given priority
|
||||
///
|
||||
/// Note that interrupts still need to be enabled globally for interrupts
|
||||
/// to be serviced.
|
||||
pub fn enable(interrupt: Interrupt, level: Priority) -> Result<(), Error> {
|
||||
if matches!(level, Priority::None) {
|
||||
return Err(Error::InvalidInterruptPriority);
|
||||
}
|
||||
unsafe {
|
||||
let cpu_interrupt = core::mem::transmute(level as u8 as u32);
|
||||
map(crate::get_core(), interrupt, cpu_interrupt);
|
||||
enable_cpu_interrupt(cpu_interrupt);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[ram]
|
||||
unsafe fn handle_interrupts(cpu_intr: CpuInterrupt, context: &mut TrapFrame) {
|
||||
let status = get_status(crate::get_core());
|
||||
|
||||
// this has no effect on level interrupts, but the interrupt may be an edge one
|
||||
// so we clear it anyway
|
||||
clear(crate::get_core(), cpu_intr);
|
||||
|
||||
let configured_interrupts = get_configured_interrupts(crate::get_core());
|
||||
let mut interrupt_mask = status & configured_interrupts[cpu_intr as usize];
|
||||
while interrupt_mask != 0 {
|
||||
let interrupt_nr = interrupt_mask.trailing_zeros();
|
||||
// Interrupt::try_from can fail if interrupt already de-asserted:
|
||||
// silently ignore
|
||||
if let Ok(interrupt) = pac::Interrupt::try_from(interrupt_nr as u8) {
|
||||
handle_interrupt(interrupt, context)
|
||||
}
|
||||
interrupt_mask &= !(1u128 << interrupt_nr);
|
||||
}
|
||||
}
|
||||
|
||||
#[ram]
|
||||
unsafe fn handle_interrupt(interrupt: Interrupt, save_frame: &mut TrapFrame) {
|
||||
extern "C" {
|
||||
// defined in each hal
|
||||
fn EspDefaultHandler(interrupt: Interrupt);
|
||||
}
|
||||
let handler = pac::__EXTERNAL_INTERRUPTS[interrupt as usize]._handler;
|
||||
if handler as *const _ == EspDefaultHandler as *const unsafe extern "C" fn() {
|
||||
EspDefaultHandler(interrupt);
|
||||
} else {
|
||||
let handler: fn(&mut TrapFrame) = core::mem::transmute(handler);
|
||||
handler(save_frame);
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[ram]
|
||||
pub unsafe fn interrupt1(context: &mut TrapFrame) {
|
||||
handle_interrupts(CpuInterrupt::Interrupt1, context)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[ram]
|
||||
pub unsafe fn interrupt2(context: &mut TrapFrame) {
|
||||
handle_interrupts(CpuInterrupt::Interrupt2, context)
|
||||
}
|
||||
#[no_mangle]
|
||||
#[ram]
|
||||
pub unsafe fn interrupt3(context: &mut TrapFrame) {
|
||||
handle_interrupts(CpuInterrupt::Interrupt3, context)
|
||||
}
|
||||
#[no_mangle]
|
||||
#[ram]
|
||||
pub unsafe fn interrupt4(context: &mut TrapFrame) {
|
||||
handle_interrupts(CpuInterrupt::Interrupt4, context)
|
||||
}
|
||||
#[no_mangle]
|
||||
#[ram]
|
||||
pub unsafe fn interrupt5(context: &mut TrapFrame) {
|
||||
handle_interrupts(CpuInterrupt::Interrupt5, context)
|
||||
}
|
||||
#[no_mangle]
|
||||
#[ram]
|
||||
pub unsafe fn interrupt6(context: &mut TrapFrame) {
|
||||
handle_interrupts(CpuInterrupt::Interrupt6, context)
|
||||
}
|
||||
#[no_mangle]
|
||||
#[ram]
|
||||
pub unsafe fn interrupt7(context: &mut TrapFrame) {
|
||||
handle_interrupts(CpuInterrupt::Interrupt7, context)
|
||||
}
|
||||
#[no_mangle]
|
||||
#[ram]
|
||||
pub unsafe fn interrupt8(context: &mut TrapFrame) {
|
||||
handle_interrupts(CpuInterrupt::Interrupt8, context)
|
||||
}
|
||||
#[no_mangle]
|
||||
#[ram]
|
||||
pub unsafe fn interrupt9(context: &mut TrapFrame) {
|
||||
handle_interrupts(CpuInterrupt::Interrupt9, context)
|
||||
}
|
||||
#[no_mangle]
|
||||
#[ram]
|
||||
pub unsafe fn interrupt10(context: &mut TrapFrame) {
|
||||
handle_interrupts(CpuInterrupt::Interrupt10, context)
|
||||
}
|
||||
#[no_mangle]
|
||||
#[ram]
|
||||
pub unsafe fn interrupt11(context: &mut TrapFrame) {
|
||||
handle_interrupts(CpuInterrupt::Interrupt11, context)
|
||||
}
|
||||
#[no_mangle]
|
||||
#[ram]
|
||||
pub unsafe fn interrupt12(context: &mut TrapFrame) {
|
||||
handle_interrupts(CpuInterrupt::Interrupt12, context)
|
||||
}
|
||||
#[no_mangle]
|
||||
#[ram]
|
||||
pub unsafe fn interrupt13(context: &mut TrapFrame) {
|
||||
handle_interrupts(CpuInterrupt::Interrupt13, context)
|
||||
}
|
||||
#[no_mangle]
|
||||
#[ram]
|
||||
pub unsafe fn interrupt14(context: &mut TrapFrame) {
|
||||
handle_interrupts(CpuInterrupt::Interrupt14, context)
|
||||
}
|
||||
#[no_mangle]
|
||||
#[ram]
|
||||
pub unsafe fn interrupt15(context: &mut TrapFrame) {
|
||||
handle_interrupts(CpuInterrupt::Interrupt15, context)
|
||||
}
|
||||
}
|
||||
|
||||
/// Registers saved in trap handler
|
||||
#[doc(hidden)]
|
||||
#[allow(missing_docs)]
|
||||
@ -234,6 +462,7 @@ pub struct TrapFrame {
|
||||
#[export_name = "_start_trap_rust_hal"]
|
||||
pub unsafe extern "C" fn start_trap_rust_hal(trap_frame: *mut TrapFrame) {
|
||||
extern "C" {
|
||||
// defined in riscv-rt
|
||||
pub fn DefaultHandler();
|
||||
}
|
||||
|
||||
@ -385,5 +614,8 @@ pub fn _setup_interrupts() {
|
||||
unsafe {
|
||||
let vec_table = &_vector_table_hal as *const _ as usize;
|
||||
riscv::register::mtvec::write(vec_table, riscv::register::mtvec::TrapMode::Vectored);
|
||||
|
||||
#[cfg(feature = "vectored")]
|
||||
crate::interrupt::init_vectoring();
|
||||
};
|
||||
}
|
||||
|
@ -184,7 +184,7 @@ unsafe fn core1_interrupt_peripheral() -> *const crate::pac::interrupt_core1::Re
|
||||
pub use vectored::*;
|
||||
|
||||
#[cfg(feature = "vectored")]
|
||||
pub mod vectored {
|
||||
mod vectored {
|
||||
use procmacros::ram;
|
||||
|
||||
use super::*;
|
||||
@ -429,12 +429,12 @@ pub mod vectored {
|
||||
unsafe fn handle_interrupt(level: u32, interrupt: Interrupt, save_frame: &mut Context) {
|
||||
extern "C" {
|
||||
// defined in each hal
|
||||
fn DefaultHandler(level: u32, interrupt: Interrupt);
|
||||
fn EspDefaultHandler(level: u32, interrupt: Interrupt);
|
||||
}
|
||||
|
||||
let handler = pac::__INTERRUPTS[interrupt.number() as usize]._handler;
|
||||
if handler as *const _ == DefaultHandler as *const unsafe extern "C" fn() {
|
||||
DefaultHandler(level, interrupt);
|
||||
if handler as *const _ == EspDefaultHandler as *const unsafe extern "C" fn() {
|
||||
EspDefaultHandler(level, interrupt);
|
||||
} else {
|
||||
let handler: fn(&mut Context) = core::mem::transmute(handler);
|
||||
handler(save_frame);
|
||||
|
@ -54,7 +54,7 @@ fn main() -> ! {
|
||||
|
||||
interrupt::enable(
|
||||
pac::Interrupt::GPIO,
|
||||
interrupt::vectored::Priority::Priority2,
|
||||
interrupt::Priority::Priority2,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
|
@ -36,7 +36,10 @@ pub mod analog {
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn DefaultHandler(_level: u32, _interrupt: pac::Interrupt) {}
|
||||
extern "C" fn EspDefaultHandler(_level: u32, _interrupt: pac::Interrupt) {}
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn DefaultHandler() {}
|
||||
|
||||
/// Function initializes ESP32 specific memories (RTC slow and fast) and
|
||||
/// then calls original Reset function
|
||||
|
16
esp32c3-hal/.vscode/settings.json
vendored
16
esp32c3-hal/.vscode/settings.json
vendored
@ -1,16 +0,0 @@
|
||||
{
|
||||
"rust-analyzer.cargo.features": [],
|
||||
"rust-analyzer.cargo.allFeatures": false,
|
||||
"editor.formatOnSave": true,
|
||||
"rust-analyzer.checkOnSave.allTargets": false,
|
||||
"rust-analyzer.checkOnSave.allFeatures": false,
|
||||
"rust-analyzer.checkOnSave.overrideCommand": [
|
||||
"cargo",
|
||||
"check",
|
||||
"--message-format=json",
|
||||
"-Z",
|
||||
"build-std=core",
|
||||
"--examples"
|
||||
],
|
||||
"rust-analyzer.cargo.buildScripts.enable": false
|
||||
}
|
@ -43,12 +43,13 @@ smart-leds = "0.3"
|
||||
esp-println = { version = "0.2.0", features = ["esp32c3"] }
|
||||
|
||||
[features]
|
||||
default = ["rt"]
|
||||
default = ["rt", "vectored"]
|
||||
direct-boot = []
|
||||
eh1 = ["esp-hal-common/eh1"]
|
||||
rt = ["riscv-rt"]
|
||||
smartled = ["esp-hal-common/smartled"]
|
||||
ufmt = ["esp-hal-common/ufmt"]
|
||||
vectored = ["esp-hal-common/vectored"]
|
||||
|
||||
[[example]]
|
||||
name = "hello_rgb"
|
||||
|
@ -6,7 +6,7 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
use core::{cell::RefCell, fmt::Write};
|
||||
use core::cell::RefCell;
|
||||
|
||||
use bare_metal::Mutex;
|
||||
use esp32c3_hal::{
|
||||
@ -14,18 +14,15 @@ use esp32c3_hal::{
|
||||
gpio::{Gpio9, IO},
|
||||
gpio_types::{Event, Input, Pin, PullDown},
|
||||
interrupt,
|
||||
pac::{self, Peripherals, UART0},
|
||||
pac::{self, Peripherals},
|
||||
prelude::*,
|
||||
timer::TimerGroup,
|
||||
Cpu,
|
||||
Delay,
|
||||
RtcCntl,
|
||||
Serial,
|
||||
};
|
||||
use panic_halt as _;
|
||||
use riscv_rt::entry;
|
||||
|
||||
static mut SERIAL: Mutex<RefCell<Option<Serial<UART0>>>> = Mutex::new(RefCell::new(None));
|
||||
static mut BUTTON: Mutex<RefCell<Option<Gpio9<Input<PullDown>>>>> = Mutex::new(RefCell::new(None));
|
||||
|
||||
#[entry]
|
||||
@ -41,7 +38,6 @@ fn main() -> ! {
|
||||
let mut wdt0 = timer_group0.wdt;
|
||||
let timer_group1 = TimerGroup::new(peripherals.TIMG1, &clocks);
|
||||
let mut wdt1 = timer_group1.wdt;
|
||||
let serial0 = Serial::new(peripherals.UART0);
|
||||
|
||||
rtc_cntl.set_super_wdt_enable(false);
|
||||
rtc_cntl.set_wdt_enable(false);
|
||||
@ -57,25 +53,10 @@ fn main() -> ! {
|
||||
button.listen(Event::FallingEdge);
|
||||
|
||||
riscv::interrupt::free(|_cs| unsafe {
|
||||
SERIAL.get_mut().replace(Some(serial0));
|
||||
BUTTON.get_mut().replace(Some(button));
|
||||
});
|
||||
|
||||
interrupt::enable(
|
||||
Cpu::ProCpu,
|
||||
pac::Interrupt::GPIO,
|
||||
interrupt::CpuInterrupt::Interrupt3,
|
||||
);
|
||||
interrupt::set_kind(
|
||||
Cpu::ProCpu,
|
||||
interrupt::CpuInterrupt::Interrupt3,
|
||||
interrupt::InterruptKind::Level,
|
||||
);
|
||||
interrupt::set_priority(
|
||||
Cpu::ProCpu,
|
||||
interrupt::CpuInterrupt::Interrupt3,
|
||||
interrupt::Priority::Priority1,
|
||||
);
|
||||
interrupt::enable(pac::Interrupt::GPIO, interrupt::Priority::Priority3).unwrap();
|
||||
|
||||
unsafe {
|
||||
riscv::interrupt::enable();
|
||||
@ -88,17 +69,12 @@ fn main() -> ! {
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub fn interrupt3() {
|
||||
#[interrupt]
|
||||
fn GPIO() {
|
||||
riscv::interrupt::free(|cs| unsafe {
|
||||
let mut serial = SERIAL.borrow(*cs).borrow_mut();
|
||||
let serial = serial.as_mut().unwrap();
|
||||
let mut button = BUTTON.borrow(*cs).borrow_mut();
|
||||
let button = button.as_mut().unwrap();
|
||||
|
||||
writeln!(serial, "Interrupt").ok();
|
||||
|
||||
interrupt::clear(Cpu::ProCpu, interrupt::CpuInterrupt::Interrupt3);
|
||||
esp_println::println!("GPIO interrupt");
|
||||
button.clear_interrupt();
|
||||
});
|
||||
}
|
||||
|
@ -56,21 +56,12 @@ fn main() -> ! {
|
||||
SERIAL.get_mut().replace(Some(serial0));
|
||||
});
|
||||
|
||||
interrupt::enable(
|
||||
Cpu::ProCpu,
|
||||
pac::Interrupt::UART0,
|
||||
interrupt::CpuInterrupt::Interrupt3,
|
||||
);
|
||||
interrupt::enable(pac::Interrupt::UART0, interrupt::Priority::Priority1).unwrap();
|
||||
interrupt::set_kind(
|
||||
Cpu::ProCpu,
|
||||
interrupt::CpuInterrupt::Interrupt3,
|
||||
interrupt::CpuInterrupt::Interrupt1, // Interrupt 1 handles priority one interrupts
|
||||
interrupt::InterruptKind::Edge,
|
||||
);
|
||||
interrupt::set_priority(
|
||||
Cpu::ProCpu,
|
||||
interrupt::CpuInterrupt::Interrupt3,
|
||||
interrupt::Priority::Priority1,
|
||||
);
|
||||
|
||||
unsafe {
|
||||
riscv::interrupt::enable();
|
||||
@ -88,8 +79,8 @@ fn main() -> ! {
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub fn interrupt3() {
|
||||
#[interrupt]
|
||||
fn UART0() {
|
||||
riscv::interrupt::free(|cs| unsafe {
|
||||
let mut serial = SERIAL.borrow(*cs).borrow_mut();
|
||||
let serial = serial.as_mut().unwrap();
|
||||
@ -110,6 +101,5 @@ pub fn interrupt3() {
|
||||
|
||||
serial.reset_at_cmd_interrupt();
|
||||
serial.reset_rx_fifo_full_interrupt();
|
||||
interrupt::clear(Cpu::ProCpu, interrupt::CpuInterrupt::Interrupt3);
|
||||
});
|
||||
}
|
||||
|
@ -4,24 +4,22 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
use core::{cell::RefCell, fmt::Write};
|
||||
use core::cell::RefCell;
|
||||
|
||||
use bare_metal::Mutex;
|
||||
use esp32c3_hal::{
|
||||
clock::ClockControl,
|
||||
interrupt,
|
||||
pac::{self, Peripherals, UART0},
|
||||
pac::{self, Peripherals},
|
||||
prelude::*,
|
||||
systimer::{Alarm, SystemTimer, Target},
|
||||
timer::TimerGroup,
|
||||
Cpu,
|
||||
RtcCntl,
|
||||
Serial,
|
||||
};
|
||||
use panic_halt as _;
|
||||
use riscv_rt::entry;
|
||||
|
||||
static mut SERIAL: Mutex<RefCell<Option<Serial<UART0>>>> = Mutex::new(RefCell::new(None));
|
||||
static mut ALARM0: Mutex<RefCell<Option<Alarm<Target, 0>>>> = Mutex::new(RefCell::new(None));
|
||||
static mut ALARM1: Mutex<RefCell<Option<Alarm<Target, 1>>>> = Mutex::new(RefCell::new(None));
|
||||
static mut ALARM2: Mutex<RefCell<Option<Alarm<Target, 2>>>> = Mutex::new(RefCell::new(None));
|
||||
@ -40,18 +38,14 @@ fn main() -> ! {
|
||||
let timer_group1 = TimerGroup::new(peripherals.TIMG1, &clocks);
|
||||
let mut wdt1 = timer_group1.wdt;
|
||||
|
||||
let mut serial0 = Serial::new(peripherals.UART0);
|
||||
|
||||
rtc_cntl.set_super_wdt_enable(false);
|
||||
rtc_cntl.set_wdt_enable(false);
|
||||
wdt0.disable();
|
||||
wdt1.disable();
|
||||
|
||||
writeln!(serial0, "SYSTIMER Demo start!").ok();
|
||||
|
||||
let syst = SystemTimer::new(peripherals.SYSTIMER);
|
||||
|
||||
writeln!(serial0, "SYSTIMER Current value = {}", SystemTimer::now()).ok();
|
||||
esp_println::println!("SYSTIMER Current value = {}", SystemTimer::now());
|
||||
|
||||
let alarm0 = syst.alarm0;
|
||||
alarm0.set_target(40_000_000);
|
||||
@ -66,53 +60,22 @@ fn main() -> ! {
|
||||
alarm2.enable_interrupt();
|
||||
|
||||
interrupt::enable(
|
||||
Cpu::ProCpu,
|
||||
pac::Interrupt::SYSTIMER_TARGET0,
|
||||
interrupt::CpuInterrupt::Interrupt1,
|
||||
);
|
||||
interrupt::Priority::Priority1,
|
||||
)
|
||||
.unwrap();
|
||||
interrupt::enable(
|
||||
Cpu::ProCpu,
|
||||
pac::Interrupt::SYSTIMER_TARGET1,
|
||||
interrupt::CpuInterrupt::Interrupt2,
|
||||
);
|
||||
interrupt::Priority::Priority1,
|
||||
)
|
||||
.unwrap();
|
||||
interrupt::enable(
|
||||
Cpu::ProCpu,
|
||||
pac::Interrupt::SYSTIMER_TARGET2,
|
||||
interrupt::CpuInterrupt::Interrupt3,
|
||||
);
|
||||
interrupt::set_kind(
|
||||
Cpu::ProCpu,
|
||||
interrupt::CpuInterrupt::Interrupt1,
|
||||
interrupt::InterruptKind::Level,
|
||||
);
|
||||
interrupt::set_kind(
|
||||
Cpu::ProCpu,
|
||||
interrupt::CpuInterrupt::Interrupt2,
|
||||
interrupt::InterruptKind::Level,
|
||||
);
|
||||
interrupt::set_kind(
|
||||
Cpu::ProCpu,
|
||||
interrupt::CpuInterrupt::Interrupt3,
|
||||
interrupt::InterruptKind::Level,
|
||||
);
|
||||
interrupt::set_priority(
|
||||
Cpu::ProCpu,
|
||||
interrupt::CpuInterrupt::Interrupt1,
|
||||
interrupt::Priority::Priority1,
|
||||
);
|
||||
interrupt::set_priority(
|
||||
Cpu::ProCpu,
|
||||
interrupt::CpuInterrupt::Interrupt2,
|
||||
interrupt::Priority::Priority1,
|
||||
);
|
||||
interrupt::set_priority(
|
||||
Cpu::ProCpu,
|
||||
interrupt::CpuInterrupt::Interrupt3,
|
||||
interrupt::Priority::Priority1,
|
||||
);
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
riscv::interrupt::free(|_cs| unsafe {
|
||||
SERIAL.get_mut().replace(Some(serial0));
|
||||
ALARM0.get_mut().replace(Some(alarm0));
|
||||
ALARM1.get_mut().replace(Some(alarm1));
|
||||
ALARM2.get_mut().replace(Some(alarm2));
|
||||
@ -125,12 +88,10 @@ fn main() -> ! {
|
||||
loop {}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub fn interrupt1() {
|
||||
#[interrupt]
|
||||
fn SYSTIMER_TARGET0() {
|
||||
riscv::interrupt::free(|cs| unsafe {
|
||||
let mut serial = SERIAL.borrow(*cs).borrow_mut();
|
||||
let serial = serial.as_mut().unwrap();
|
||||
writeln!(serial, "Interrupt 1 = {}", SystemTimer::now()).ok();
|
||||
esp_println::println!("Interrupt 1 = {}", SystemTimer::now());
|
||||
|
||||
let mut alarm = ALARM0.borrow(*cs).borrow_mut();
|
||||
let alarm = alarm.as_mut().unwrap();
|
||||
@ -140,12 +101,10 @@ pub fn interrupt1() {
|
||||
});
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub fn interrupt2() {
|
||||
#[interrupt]
|
||||
fn SYSTIMER_TARGET1() {
|
||||
riscv::interrupt::free(|cs| unsafe {
|
||||
let mut serial = SERIAL.borrow(*cs).borrow_mut();
|
||||
let serial = serial.as_mut().unwrap();
|
||||
writeln!(serial, "Interrupt 2 = {}", SystemTimer::now()).ok();
|
||||
esp_println::println!("Interrupt 2 = {}", SystemTimer::now());
|
||||
|
||||
let mut alarm = ALARM1.borrow(*cs).borrow_mut();
|
||||
let alarm = alarm.as_mut().unwrap();
|
||||
@ -155,12 +114,10 @@ pub fn interrupt2() {
|
||||
});
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub fn interrupt3() {
|
||||
#[interrupt]
|
||||
fn SYSTIMER_TARGET2() {
|
||||
riscv::interrupt::free(|cs| unsafe {
|
||||
let mut serial = SERIAL.borrow(*cs).borrow_mut();
|
||||
let serial = serial.as_mut().unwrap();
|
||||
writeln!(serial, "Interrupt 3 = {}", SystemTimer::now()).ok();
|
||||
esp_println::println!("Interrupt 3 = {}", SystemTimer::now());
|
||||
|
||||
let mut alarm = ALARM2.borrow(*cs).borrow_mut();
|
||||
let alarm = alarm.as_mut().unwrap();
|
||||
|
@ -5,24 +5,21 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
use core::{cell::RefCell, fmt::Write};
|
||||
use core::cell::RefCell;
|
||||
|
||||
use bare_metal::Mutex;
|
||||
use esp32c3_hal::{
|
||||
clock::ClockControl,
|
||||
interrupt,
|
||||
pac::{self, Peripherals, TIMG0, TIMG1, UART0},
|
||||
pac::{self, Peripherals, TIMG0, TIMG1},
|
||||
prelude::*,
|
||||
timer::{Timer0, TimerGroup},
|
||||
Cpu,
|
||||
RtcCntl,
|
||||
Serial,
|
||||
};
|
||||
use esp_hal_common::Timer;
|
||||
use panic_halt as _;
|
||||
use riscv_rt::entry;
|
||||
|
||||
static mut SERIAL: Mutex<RefCell<Option<Serial<UART0>>>> = Mutex::new(RefCell::new(None));
|
||||
static mut TIMER0: Mutex<RefCell<Option<Timer<Timer0<TIMG0>>>>> = Mutex::new(RefCell::new(None));
|
||||
static mut TIMER1: Mutex<RefCell<Option<Timer<Timer0<TIMG1>>>>> = Mutex::new(RefCell::new(None));
|
||||
|
||||
@ -42,53 +39,20 @@ fn main() -> ! {
|
||||
let mut timer1 = timer_group1.timer0;
|
||||
let mut wdt1 = timer_group1.wdt;
|
||||
|
||||
let serial0 = Serial::new(peripherals.UART0);
|
||||
|
||||
rtc_cntl.set_super_wdt_enable(false);
|
||||
rtc_cntl.set_wdt_enable(false);
|
||||
wdt0.disable();
|
||||
wdt1.disable();
|
||||
|
||||
interrupt::enable(
|
||||
Cpu::ProCpu,
|
||||
pac::Interrupt::TG0_T0_LEVEL,
|
||||
interrupt::CpuInterrupt::Interrupt1,
|
||||
);
|
||||
interrupt::set_kind(
|
||||
Cpu::ProCpu,
|
||||
interrupt::CpuInterrupt::Interrupt1,
|
||||
interrupt::InterruptKind::Level,
|
||||
);
|
||||
interrupt::set_priority(
|
||||
Cpu::ProCpu,
|
||||
interrupt::CpuInterrupt::Interrupt1,
|
||||
interrupt::Priority::Priority1,
|
||||
);
|
||||
|
||||
interrupt::enable(pac::Interrupt::TG0_T0_LEVEL, interrupt::Priority::Priority1).unwrap();
|
||||
timer0.start(500u64.millis());
|
||||
timer0.listen();
|
||||
|
||||
interrupt::enable(
|
||||
Cpu::ProCpu,
|
||||
pac::Interrupt::TG1_T0_LEVEL,
|
||||
interrupt::CpuInterrupt::Interrupt11,
|
||||
);
|
||||
interrupt::set_kind(
|
||||
Cpu::ProCpu,
|
||||
interrupt::CpuInterrupt::Interrupt11,
|
||||
interrupt::InterruptKind::Level,
|
||||
);
|
||||
interrupt::set_priority(
|
||||
Cpu::ProCpu,
|
||||
interrupt::CpuInterrupt::Interrupt11,
|
||||
interrupt::Priority::Priority1,
|
||||
);
|
||||
|
||||
interrupt::enable(pac::Interrupt::TG1_T0_LEVEL, interrupt::Priority::Priority1).unwrap();
|
||||
timer1.start(1u64.secs());
|
||||
timer1.listen();
|
||||
|
||||
riscv::interrupt::free(|_cs| unsafe {
|
||||
SERIAL.get_mut().replace(Some(serial0));
|
||||
TIMER0.get_mut().replace(Some(timer0));
|
||||
TIMER1.get_mut().replace(Some(timer1));
|
||||
});
|
||||
@ -100,36 +64,28 @@ fn main() -> ! {
|
||||
loop {}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub fn interrupt1() {
|
||||
#[interrupt]
|
||||
fn TG0_T0_LEVEL() {
|
||||
riscv::interrupt::free(|cs| unsafe {
|
||||
let mut serial = SERIAL.borrow(*cs).borrow_mut();
|
||||
let serial = serial.as_mut().unwrap();
|
||||
writeln!(serial, "Interrupt 1").ok();
|
||||
esp_println::println!("Interrupt 1");
|
||||
|
||||
let mut timer0 = TIMER0.borrow(*cs).borrow_mut();
|
||||
let timer0 = timer0.as_mut().unwrap();
|
||||
|
||||
interrupt::clear(Cpu::ProCpu, interrupt::CpuInterrupt::Interrupt1);
|
||||
timer0.clear_interrupt();
|
||||
|
||||
timer0.start(500u64.millis());
|
||||
});
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub fn interrupt11() {
|
||||
#[interrupt]
|
||||
fn TG1_T0_LEVEL() {
|
||||
riscv::interrupt::free(|cs| unsafe {
|
||||
let mut serial = SERIAL.borrow(*cs).borrow_mut();
|
||||
let serial = serial.as_mut().unwrap();
|
||||
writeln!(serial, "Interrupt 11").ok();
|
||||
esp_println::println!("Interrupt 11");
|
||||
|
||||
let mut timer1 = TIMER1.borrow(*cs).borrow_mut();
|
||||
let timer1 = timer1.as_mut().unwrap();
|
||||
|
||||
interrupt::clear(Cpu::ProCpu, interrupt::CpuInterrupt::Interrupt11);
|
||||
timer1.clear_interrupt();
|
||||
|
||||
timer1.start(1u64.secs());
|
||||
});
|
||||
}
|
||||
|
@ -29,3 +29,5 @@ PROVIDE(interrupt28 = DefaultHandler);
|
||||
PROVIDE(interrupt29 = DefaultHandler);
|
||||
PROVIDE(interrupt30 = DefaultHandler);
|
||||
PROVIDE(interrupt31 = DefaultHandler);
|
||||
|
||||
INCLUDE "device.x"
|
||||
|
@ -310,3 +310,6 @@ pub fn mp_hook() -> bool {
|
||||
fn gpio_intr_enable(int_enable: bool, nmi_enable: bool) -> u8 {
|
||||
int_enable as u8 | ((nmi_enable as u8) << 1)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn EspDefaultHandler(_interrupt: pac::Interrupt) {}
|
||||
|
@ -54,7 +54,7 @@ fn main() -> ! {
|
||||
|
||||
interrupt::enable(
|
||||
pac::Interrupt::GPIO,
|
||||
interrupt::vectored::Priority::Priority2,
|
||||
interrupt::Priority::Priority2,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
|
@ -36,7 +36,10 @@ pub mod analog {
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn DefaultHandler(_level: u32, _interrupt: pac::Interrupt) {}
|
||||
extern "C" fn EspDefaultHandler(_level: u32, _interrupt: pac::Interrupt) {}
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn DefaultHandler() {}
|
||||
|
||||
/// Function initializes ESP32 specific memories (RTC slow and fast) and
|
||||
/// then calls original Reset function
|
||||
|
@ -54,7 +54,7 @@ fn main() -> ! {
|
||||
|
||||
interrupt::enable(
|
||||
pac::Interrupt::GPIO,
|
||||
interrupt::vectored::Priority::Priority2,
|
||||
interrupt::Priority::Priority2,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
|
@ -34,7 +34,10 @@ pub use self::gpio::IO;
|
||||
pub mod gpio;
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn DefaultHandler(_level: u32, _interrupt: pac::Interrupt) {}
|
||||
extern "C" fn EspDefaultHandler(_level: u32, _interrupt: pac::Interrupt) {}
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn DefaultHandler() {}
|
||||
|
||||
#[cfg(all(feature = "rt", feature = "direct-boot"))]
|
||||
#[doc(hidden)]
|
||||
|
Loading…
x
Reference in New Issue
Block a user