Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add basic interrupt support for ESP32C3 and ESP32 #10

Merged
merged 1 commit into from
Jan 31, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 8 additions & 4 deletions esp-hal-common/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ paste = "1.0"
riscv = { version = "0.7", optional = true }
void = { version = "1.0", default-features = false }
xtensa-lx = { version = "0.4", optional = true }
xtensa-lx-rt = { version = "0.7", features = ["lx6"], optional = true }
procmacros = { path = "../esp-hal-procmacros", package = "esp-hal-procmacros" }
# IMPORTANT:
# Each supported device MUST have its PAC included below along with a
Expand All @@ -27,7 +28,10 @@ esp32s2_pac = { package = "esp32s2", git = "https://github.com/jessebraham/esp32
esp32s3_pac = { package = "esp32s3", git = "https://github.com/jessebraham/esp32s3.git", branch = "develop", optional = true }

[features]
esp32 = ["esp32_pac", "esp32_pac/rt", "xtensa-lx/lx6", "procmacros/rtc_slow"]
esp32c3 = ["esp32c3_pac", "esp32c3_pac/rt", "riscv"]
esp32s2 = ["esp32s2_pac", "esp32s2_pac/rt", "xtensa-lx/lx6", "procmacros/rtc_slow"] # FIXME
esp32s3 = ["esp32s3_pac", "esp32s3_pac/rt", "xtensa-lx/lx6", "procmacros/rtc_slow"] # FIXME
esp32 = ["esp32_pac", "esp32_pac/rt", "xtensa-lx/lx6", "xtensa-lx-rt/lx6", "procmacros/rtc_slow", "dual_core"]
esp32c3 = ["esp32c3_pac", "esp32c3_pac/rt", "riscv", "single_core"]
esp32s2 = ["esp32s2_pac", "esp32s2_pac/rt", "xtensa-lx/lx6", "xtensa-lx-rt/lx6", "procmacros/rtc_slow", "single_core"] # FIXME
esp32s3 = ["esp32s3_pac", "esp32s3_pac/rt", "xtensa-lx/lx6", "xtensa-lx-rt/lx6", "procmacros/rtc_slow", "dual_core"] # FIXME

single_core = []
dual_core = []
4 changes: 3 additions & 1 deletion esp-hal-common/src/gpio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -330,10 +330,12 @@ macro_rules! impl_input {
_ => {}
}
}

// a crate using this macro needs to provide gpio_intr_enable
unsafe {
(&*GPIO::ptr()).pin[$pin_num].modify(|_, w|
w
.pin_int_ena().bits(int_enable as u8 | ((nmi_enable as u8) << 1))
.pin_int_ena().bits(crate::gpio_intr_enable(int_enable, nmi_enable))
.pin_int_type().bits(event as u8)
.pin_wakeup_enable().bit(wake_up_from_light_sleep)
);
Expand Down
295 changes: 295 additions & 0 deletions esp-hal-common/src/interrupt/riscv.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,295 @@
use riscv::register::mcause;

use crate::{pac::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
// future
extern "C" {
fn interrupt1(frame: &mut TrapFrame);
fn interrupt2(frame: &mut TrapFrame);
fn interrupt3(frame: &mut TrapFrame);
fn interrupt4(frame: &mut TrapFrame);
fn interrupt5(frame: &mut TrapFrame);
fn interrupt6(frame: &mut TrapFrame);
fn interrupt7(frame: &mut TrapFrame);
fn interrupt8(frame: &mut TrapFrame);
fn interrupt9(frame: &mut TrapFrame);
fn interrupt10(frame: &mut TrapFrame);
fn interrupt11(frame: &mut TrapFrame);
fn interrupt12(frame: &mut TrapFrame);
fn interrupt13(frame: &mut TrapFrame);
fn interrupt14(frame: &mut TrapFrame);
fn interrupt15(frame: &mut TrapFrame);
fn interrupt16(frame: &mut TrapFrame);
fn interrupt17(frame: &mut TrapFrame);
fn interrupt18(frame: &mut TrapFrame);
fn interrupt19(frame: &mut TrapFrame);
fn interrupt20(frame: &mut TrapFrame);
fn interrupt21(frame: &mut TrapFrame);
fn interrupt22(frame: &mut TrapFrame);
fn interrupt23(frame: &mut TrapFrame);
fn interrupt24(frame: &mut TrapFrame);
fn interrupt25(frame: &mut TrapFrame);
fn interrupt26(frame: &mut TrapFrame);
fn interrupt27(frame: &mut TrapFrame);
fn interrupt28(frame: &mut TrapFrame);
fn interrupt29(frame: &mut TrapFrame);
fn interrupt30(frame: &mut TrapFrame);
fn interrupt31(frame: &mut TrapFrame);
}

/// Interrupt kind
pub enum InterruptKind {
/// Level interrupt
Level,
/// Edge interrupt
Edge,
}

/// Enumeration of available CPU interrupts.
/// It is possible to create a handler for each of the interrupts. (e.g. `interrupt3`)
pub enum CpuInterrupt {
Interrupt1 = 1,
Interrupt2,
Interrupt3,
Interrupt4,
Interrupt5,
Interrupt6,
Interrupt7,
Interrupt8,
Interrupt9,
Interrupt10,
Interrupt11,
Interrupt12,
Interrupt13,
Interrupt14,
Interrupt15,
Interrupt16,
Interrupt17,
Interrupt18,
Interrupt19,
Interrupt20,
Interrupt21,
Interrupt22,
Interrupt23,
Interrupt24,
Interrupt25,
Interrupt26,
Interrupt27,
Interrupt28,
Interrupt29,
Interrupt30,
Interrupt31,
}

/// Interrupt priority levels.
pub enum Priority {
None,
Priority1,
Priority2,
Priority3,
Priority4,
Priority5,
Priority6,
Priority7,
Priority8,
Priority9,
Priority10,
Priority11,
Priority12,
Priority13,
Priority14,
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);

// enable interrupt
intr.cpu_int_enable
.write(|w| w.bits(1 << cpu_interrupt_number));
}
}

/// Disable the given peripheral interrupt.
pub fn disable(_core: Cpu, interrupt: Interrupt) {
unsafe {
let interrupt_number = interrupt 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(0);
}
}

/// Set the interrupt kind (i.e. level or edge) of an CPU interrupt
pub fn set_kind(_core: Cpu, which: CpuInterrupt, kind: InterruptKind) {
unsafe {
let intr = &*crate::pac::INTERRUPT_CORE0::ptr();
let cpu_interrupt_number = which as isize;

let interrupt_type = match kind {
InterruptKind::Level => 0,
InterruptKind::Edge => 1,
};
intr.cpu_int_type.modify(|r, w| {
w.bits(
r.bits() & !(1 << cpu_interrupt_number) | (interrupt_type << cpu_interrupt_number),
)
});
}
}

/// 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();

intr_prio_base
.offset(cpu_interrupt_number as isize)
.write_volatile(priority as u32);
}
}

/// Clear a CPU interrupt
pub fn clear(_core: Cpu, which: CpuInterrupt) {
unsafe {
let cpu_interrupt_number = which as isize;
let intr = &*crate::pac::INTERRUPT_CORE0::ptr();
intr.cpu_int_clear
.write(|w| w.bits(1 << cpu_interrupt_number));
}
}

/// Get status of peripheral interrupts
pub fn get_status(_core: Cpu) -> u128 {
unsafe {
((*crate::pac::INTERRUPT_CORE0::ptr())
.intr_status_reg_0
.read()
.bits() as u128)
| ((*crate::pac::INTERRUPT_CORE0::ptr())
.intr_status_reg_1
.read()
.bits() as u128)
<< 32
}
}

// TODO should this be aligned with Atomic Emulation Trap Handler in future?
/// Registers saved in trap handler
#[doc(hidden)]
#[allow(missing_docs)]
#[derive(Debug, Default, Clone, Copy)]
#[repr(C)]
pub struct TrapFrame {
pub ra: usize,
pub t0: usize,
pub t1: usize,
pub t2: usize,
pub t3: usize,
pub t4: usize,
pub t5: usize,
pub t6: usize,
pub a0: usize,
pub a1: usize,
pub a2: usize,
pub a3: usize,
pub a4: usize,
pub a5: usize,
pub a6: usize,
pub a7: usize,
pub s0: usize,
pub s1: usize,
pub s2: usize,
pub s3: usize,
pub s4: usize,
pub s5: usize,
pub s6: usize,
pub s7: usize,
pub s8: usize,
pub s9: usize,
pub s10: usize,
pub s11: usize,
pub gp: usize,
pub tp: usize,
pub sp: usize,
}

/// # Safety
///
/// This function is called from an assembly trap handler.
#[doc(hidden)]
#[link_section = ".trap.rust"]
#[export_name = "_start_trap_rust_hal"]
pub unsafe extern "C" fn start_trap_rust_hal(trap_frame: *mut TrapFrame) {
extern "C" {
pub fn _start_trap_rust(trap_frame: *const TrapFrame);

pub fn DefaultHandler();
}

let cause = mcause::read();
if cause.is_exception() {
_start_trap_rust(trap_frame);
} else {
let code = riscv::register::mcause::read().code();
match code {
1 => interrupt1(trap_frame.as_mut().unwrap()),
2 => interrupt2(trap_frame.as_mut().unwrap()),
3 => interrupt3(trap_frame.as_mut().unwrap()),
4 => interrupt4(trap_frame.as_mut().unwrap()),
5 => interrupt5(trap_frame.as_mut().unwrap()),
6 => interrupt6(trap_frame.as_mut().unwrap()),
7 => interrupt7(trap_frame.as_mut().unwrap()),
8 => interrupt8(trap_frame.as_mut().unwrap()),
9 => interrupt9(trap_frame.as_mut().unwrap()),
10 => interrupt10(trap_frame.as_mut().unwrap()),
11 => interrupt11(trap_frame.as_mut().unwrap()),
12 => interrupt12(trap_frame.as_mut().unwrap()),
13 => interrupt13(trap_frame.as_mut().unwrap()),
14 => interrupt14(trap_frame.as_mut().unwrap()),
16 => interrupt16(trap_frame.as_mut().unwrap()),
15 => interrupt15(trap_frame.as_mut().unwrap()),
17 => interrupt17(trap_frame.as_mut().unwrap()),
18 => interrupt18(trap_frame.as_mut().unwrap()),
19 => interrupt19(trap_frame.as_mut().unwrap()),
20 => interrupt20(trap_frame.as_mut().unwrap()),
21 => interrupt21(trap_frame.as_mut().unwrap()),
22 => interrupt22(trap_frame.as_mut().unwrap()),
23 => interrupt23(trap_frame.as_mut().unwrap()),
24 => interrupt24(trap_frame.as_mut().unwrap()),
25 => interrupt25(trap_frame.as_mut().unwrap()),
26 => interrupt26(trap_frame.as_mut().unwrap()),
27 => interrupt27(trap_frame.as_mut().unwrap()),
28 => interrupt28(trap_frame.as_mut().unwrap()),
29 => interrupt29(trap_frame.as_mut().unwrap()),
30 => interrupt30(trap_frame.as_mut().unwrap()),
31 => interrupt31(trap_frame.as_mut().unwrap()),
_ => DefaultHandler(),
};
}
}

#[doc(hidden)]
#[no_mangle]
pub fn _setup_interrupts() {
extern "C" {
static _vector_table: *const u32;
}

unsafe {
let vec_table = &_vector_table as *const _ as usize;
riscv::register::mtvec::write(vec_table, riscv::register::mtvec::TrapMode::Vectored);
};
}
Loading