Add basic interrupt support for ESP32C3 and ESP32
This commit is contained in:
parent
ef5d1ac7f4
commit
cac30b7544
@ -17,6 +17,7 @@ paste = "1.0"
|
|||||||
riscv = { version = "0.7", optional = true }
|
riscv = { version = "0.7", optional = true }
|
||||||
void = { version = "1.0", default-features = false }
|
void = { version = "1.0", default-features = false }
|
||||||
xtensa-lx = { version = "0.4", optional = true }
|
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" }
|
procmacros = { path = "../esp-hal-procmacros", package = "esp-hal-procmacros" }
|
||||||
# IMPORTANT:
|
# IMPORTANT:
|
||||||
# Each supported device MUST have its PAC included below along with a
|
# Each supported device MUST have its PAC included below along with a
|
||||||
@ -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 }
|
esp32s3_pac = { package = "esp32s3", git = "https://github.com/jessebraham/esp32s3.git", branch = "develop", optional = true }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
esp32 = ["esp32_pac", "esp32_pac/rt", "xtensa-lx/lx6", "procmacros/rtc_slow"]
|
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"]
|
esp32c3 = ["esp32c3_pac", "esp32c3_pac/rt", "riscv", "single_core"]
|
||||||
esp32s2 = ["esp32s2_pac", "esp32s2_pac/rt", "xtensa-lx/lx6", "procmacros/rtc_slow"] # FIXME
|
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", "procmacros/rtc_slow"] # FIXME
|
esp32s3 = ["esp32s3_pac", "esp32s3_pac/rt", "xtensa-lx/lx6", "xtensa-lx-rt/lx6", "procmacros/rtc_slow", "dual_core"] # FIXME
|
||||||
|
|
||||||
|
single_core = []
|
||||||
|
dual_core = []
|
||||||
|
|||||||
@ -330,10 +330,12 @@ macro_rules! impl_input {
|
|||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// a crate using this macro needs to provide gpio_intr_enable
|
||||||
unsafe {
|
unsafe {
|
||||||
(&*GPIO::ptr()).pin[$pin_num].modify(|_, w|
|
(&*GPIO::ptr()).pin[$pin_num].modify(|_, w|
|
||||||
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_int_type().bits(event as u8)
|
||||||
.pin_wakeup_enable().bit(wake_up_from_light_sleep)
|
.pin_wakeup_enable().bit(wake_up_from_light_sleep)
|
||||||
);
|
);
|
||||||
|
|||||||
295
esp-hal-common/src/interrupt/riscv.rs
Normal file
295
esp-hal-common/src/interrupt/riscv.rs
Normal file
@ -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);
|
||||||
|
};
|
||||||
|
}
|
||||||
144
esp-hal-common/src/interrupt/xtensa.rs
Normal file
144
esp-hal-common/src/interrupt/xtensa.rs
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
use crate::{pac::Interrupt, Cpu};
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
fn level1_interrupt();
|
||||||
|
fn level2_interrupt();
|
||||||
|
fn level3_interrupt();
|
||||||
|
fn level4_interrupt();
|
||||||
|
fn level5_interrupt();
|
||||||
|
fn level6_interrupt();
|
||||||
|
fn level7_interrupt();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Enumeration of available CPU interrupts
|
||||||
|
/// It's possible to create one handler per priority level. (e.g `level1_interrupt`)
|
||||||
|
#[allow(unused)]
|
||||||
|
pub enum CpuInterrupt {
|
||||||
|
Interrupt0LevelPriority1 = 0,
|
||||||
|
Interrupt1LevelPriority1,
|
||||||
|
Interrupt2LevelPriority1,
|
||||||
|
Interrupt3LevelPriority1,
|
||||||
|
Interrupt4LevelPriority1,
|
||||||
|
Interrupt5LevelPriority1,
|
||||||
|
Interrupt6Timer0Priority1,
|
||||||
|
Interrupt7SoftwarePriority1,
|
||||||
|
Interrupt8LevelPriority1,
|
||||||
|
Interrupt9LevelPriority1,
|
||||||
|
Interrupt10EdgePriority1,
|
||||||
|
Interrupt11ProfilingPriority3,
|
||||||
|
Interrupt12LevelPriority1,
|
||||||
|
Interrupt13LevelPriority1,
|
||||||
|
Interrupt14NmiPriority7,
|
||||||
|
Interrupt15Timer1Priority3,
|
||||||
|
Interrupt16Timer2Priority3,
|
||||||
|
Interrupt17LevelPriority1,
|
||||||
|
Interrupt18LevelPriority1,
|
||||||
|
Interrupt19LevelPriority2,
|
||||||
|
Interrupt20LevelPriority2,
|
||||||
|
Interrupt21LevelPriority2,
|
||||||
|
Interrupt22EdgePriority3,
|
||||||
|
Interrupt23LevelPriority3,
|
||||||
|
Interrupt24LevelPriority4,
|
||||||
|
Interrupt25LevelPriority4,
|
||||||
|
Interrupt26LevelPriority5,
|
||||||
|
Interrupt27LevelPriority3,
|
||||||
|
Interrupt28EdgePriority4,
|
||||||
|
Interrupt29SoftwarePriority3,
|
||||||
|
Interrupt30EdgePriority4,
|
||||||
|
Interrupt31EdgePriority5,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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::DPORT::ptr();
|
||||||
|
let intr_map_base = match core {
|
||||||
|
Cpu::ProCpu => intr.pro_mac_intr_map.as_ptr(),
|
||||||
|
#[cfg(feature = "dual_core")]
|
||||||
|
Cpu::AppCpu => intr.app_mac_intr_map.as_ptr(),
|
||||||
|
#[cfg(feature = "single_core")]
|
||||||
|
Cpu::AppCpu => intr.pro_mac_intr_map.as_ptr(),
|
||||||
|
};
|
||||||
|
intr_map_base
|
||||||
|
.offset(interrupt_number)
|
||||||
|
.write_volatile(cpu_interrupt_number as u32);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Disable the given peripheral interrupt.
|
||||||
|
pub fn disable(core: Cpu, interrupt: Interrupt) {
|
||||||
|
unsafe {
|
||||||
|
let interrupt_number = interrupt as isize;
|
||||||
|
let intr = &*crate::pac::DPORT::ptr();
|
||||||
|
let intr_map_base = match core {
|
||||||
|
Cpu::ProCpu => intr.pro_mac_intr_map.as_ptr(),
|
||||||
|
#[cfg(feature = "dual_core")]
|
||||||
|
Cpu::AppCpu => intr.app_mac_intr_map.as_ptr(),
|
||||||
|
#[cfg(feature = "single_core")]
|
||||||
|
Cpu::AppCpu => intr.pro_mac_intr_map.as_ptr(),
|
||||||
|
};
|
||||||
|
intr_map_base.offset(interrupt_number).write_volatile(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Clear the given CPU interrupt
|
||||||
|
pub fn clear(_core: Cpu, which: CpuInterrupt) {
|
||||||
|
unsafe {
|
||||||
|
xtensa_lx::interrupt::clear(1 << which as u32);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get status of peripheral interrupts
|
||||||
|
pub fn get_status(core: Cpu) -> u128 {
|
||||||
|
unsafe {
|
||||||
|
match core {
|
||||||
|
Cpu::ProCpu => {
|
||||||
|
((*crate::pac::DPORT::ptr()).pro_intr_status_0.read().bits() as u128)
|
||||||
|
| ((*crate::pac::DPORT::ptr()).pro_intr_status_1.read().bits() as u128) << 32
|
||||||
|
| ((*crate::pac::DPORT::ptr()).pro_intr_status_2.read().bits() as u128) << 64
|
||||||
|
}
|
||||||
|
Cpu::AppCpu => {
|
||||||
|
((*crate::pac::DPORT::ptr()).app_intr_status_0.read().bits() as u128)
|
||||||
|
| ((*crate::pac::DPORT::ptr()).app_intr_status_1.read().bits() as u128) << 32
|
||||||
|
| ((*crate::pac::DPORT::ptr()).app_intr_status_2.read().bits() as u128) << 64
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[xtensa_lx_rt::interrupt(1)]
|
||||||
|
fn _level1_interrupt() {
|
||||||
|
unsafe { level1_interrupt() };
|
||||||
|
}
|
||||||
|
|
||||||
|
#[xtensa_lx_rt::interrupt(2)]
|
||||||
|
fn _level2_interrupt() {
|
||||||
|
unsafe { level2_interrupt() };
|
||||||
|
}
|
||||||
|
|
||||||
|
#[xtensa_lx_rt::interrupt(3)]
|
||||||
|
fn _level3_interrupt() {
|
||||||
|
unsafe { level3_interrupt() };
|
||||||
|
}
|
||||||
|
|
||||||
|
#[xtensa_lx_rt::interrupt(4)]
|
||||||
|
fn _level4_interrupt() {
|
||||||
|
unsafe { level4_interrupt() };
|
||||||
|
}
|
||||||
|
|
||||||
|
#[xtensa_lx_rt::interrupt(5)]
|
||||||
|
fn _level5_interrupt() {
|
||||||
|
unsafe { level5_interrupt() };
|
||||||
|
}
|
||||||
|
|
||||||
|
#[xtensa_lx_rt::interrupt(6)]
|
||||||
|
fn _level6_interrupt() {
|
||||||
|
unsafe { level6_interrupt() };
|
||||||
|
}
|
||||||
|
|
||||||
|
#[xtensa_lx_rt::interrupt(7)]
|
||||||
|
fn _level7_interrupt() {
|
||||||
|
unsafe { level7_interrupt() };
|
||||||
|
}
|
||||||
@ -29,14 +29,26 @@ pub use esp32s3_pac as pac;
|
|||||||
|
|
||||||
pub mod delay;
|
pub mod delay;
|
||||||
pub mod gpio;
|
pub mod gpio;
|
||||||
|
#[cfg_attr(feature = "esp32", path = "interrupt/xtensa.rs")]
|
||||||
|
#[cfg_attr(feature = "esp32c3", path = "interrupt/riscv.rs")]
|
||||||
|
pub mod interrupt;
|
||||||
pub mod prelude;
|
pub mod prelude;
|
||||||
pub mod serial;
|
pub mod serial;
|
||||||
pub mod timer;
|
pub mod timer;
|
||||||
|
|
||||||
pub use delay::Delay;
|
pub use delay::Delay;
|
||||||
pub use gpio::*;
|
pub use gpio::*;
|
||||||
|
pub use interrupt::*;
|
||||||
|
use procmacros;
|
||||||
|
pub use procmacros::ram;
|
||||||
pub use serial::Serial;
|
pub use serial::Serial;
|
||||||
pub use timer::Timer;
|
pub use timer::Timer;
|
||||||
|
|
||||||
use procmacros;
|
/// Enumeration of CPU cores
|
||||||
pub use procmacros::ram;
|
/// The actual number of available cores depends on the target.
|
||||||
|
pub enum Cpu {
|
||||||
|
/// The fist core
|
||||||
|
ProCpu = 0,
|
||||||
|
/// The second core
|
||||||
|
AppCpu,
|
||||||
|
}
|
||||||
|
|||||||
16
esp32-hal/.vscode/settings.json
vendored
Normal file
16
esp32-hal/.vscode/settings.json
vendored
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"rust-analyzer.cargo.features": [],
|
||||||
|
"rust-analyzer.cargo.allFeatures": false,
|
||||||
|
"editor.formatOnSave": true,
|
||||||
|
"rust-analyzer.checkOnSave.allTargets": false,
|
||||||
|
"rust-analyzer.checkOnSave.allFeatures": false,
|
||||||
|
"rust-analyzer.cargo.runBuildScripts": false,
|
||||||
|
"rust-analyzer.checkOnSave.overrideCommand": [
|
||||||
|
"cargo",
|
||||||
|
"check",
|
||||||
|
"--message-format=json",
|
||||||
|
"-Z",
|
||||||
|
"build-std=core",
|
||||||
|
"--examples"
|
||||||
|
]
|
||||||
|
}
|
||||||
@ -13,6 +13,13 @@ fn main() {
|
|||||||
.write_all(include_bytes!("rom.x"))
|
.write_all(include_bytes!("rom.x"))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
File::create(out.join("hal-defaults.x"))
|
||||||
|
.unwrap()
|
||||||
|
.write_all(include_bytes!("hal-defaults.x"))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
println!("cargo:rustc-link-arg=-Thal-defaults.x");
|
||||||
|
|
||||||
println!("cargo:rustc-link-search={}", out.display());
|
println!("cargo:rustc-link-search={}", out.display());
|
||||||
|
|
||||||
// Only re-run the build script when memory.x is changed,
|
// Only re-run the build script when memory.x is changed,
|
||||||
|
|||||||
95
esp32-hal/examples/gpio_interrupt.rs
Normal file
95
esp32-hal/examples/gpio_interrupt.rs
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
#![no_std]
|
||||||
|
#![no_main]
|
||||||
|
|
||||||
|
use core::{cell::RefCell, fmt::Write};
|
||||||
|
|
||||||
|
use esp32_hal::{
|
||||||
|
gpio::{Gpio0, IO},
|
||||||
|
pac::{self, Peripherals, UART0},
|
||||||
|
prelude::*,
|
||||||
|
Delay,
|
||||||
|
Serial,
|
||||||
|
Timer,
|
||||||
|
};
|
||||||
|
use esp_hal_common::{
|
||||||
|
gpio::{Event, Pin},
|
||||||
|
interrupt,
|
||||||
|
Cpu,
|
||||||
|
Input,
|
||||||
|
PullDown,
|
||||||
|
};
|
||||||
|
use panic_halt as _;
|
||||||
|
use xtensa_lx::mutex::{Mutex, SpinLockMutex};
|
||||||
|
use xtensa_lx_rt::entry;
|
||||||
|
|
||||||
|
static mut SERIAL: SpinLockMutex<RefCell<Option<Serial<UART0>>>> =
|
||||||
|
SpinLockMutex::new(RefCell::new(None));
|
||||||
|
static mut BUTTON: SpinLockMutex<RefCell<Option<Gpio0<Input<PullDown>>>>> =
|
||||||
|
SpinLockMutex::new(RefCell::new(None));
|
||||||
|
|
||||||
|
#[entry]
|
||||||
|
fn main() -> ! {
|
||||||
|
let peripherals = Peripherals::take().unwrap();
|
||||||
|
|
||||||
|
// Disable the TIMG watchdog timer.
|
||||||
|
let mut timer0 = Timer::new(peripherals.TIMG0);
|
||||||
|
let serial0 = Serial::new(peripherals.UART0).unwrap();
|
||||||
|
|
||||||
|
timer0.disable();
|
||||||
|
|
||||||
|
// Set GPIO15 as an output, and set its state high initially.
|
||||||
|
let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);
|
||||||
|
let mut led = io.pins.gpio15.into_push_pull_output();
|
||||||
|
let mut button = io.pins.gpio0.into_pull_down_input();
|
||||||
|
button.listen(Event::FallingEdge);
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
(&SERIAL).lock(|data| (*data).replace(Some(serial0)));
|
||||||
|
(&BUTTON).lock(|data| (*data).replace(Some(button)));
|
||||||
|
}
|
||||||
|
|
||||||
|
interrupt::enable(
|
||||||
|
Cpu::ProCpu,
|
||||||
|
pac::Interrupt::GPIO,
|
||||||
|
interrupt::CpuInterrupt::Interrupt1LevelPriority1,
|
||||||
|
);
|
||||||
|
|
||||||
|
led.set_high().unwrap();
|
||||||
|
|
||||||
|
// Initialize the Delay peripheral, and use it to toggle the LED state in a
|
||||||
|
// loop.
|
||||||
|
let mut delay = Delay::new();
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
xtensa_lx::interrupt::enable();
|
||||||
|
}
|
||||||
|
|
||||||
|
loop {
|
||||||
|
led.toggle().unwrap();
|
||||||
|
delay.delay_ms(500u32);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub fn level1_interrupt() {
|
||||||
|
unsafe {
|
||||||
|
(&SERIAL).lock(|data| {
|
||||||
|
let mut serial = data.borrow_mut();
|
||||||
|
let serial = serial.as_mut().unwrap();
|
||||||
|
writeln!(serial, "Interrupt").ok();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
interrupt::clear(
|
||||||
|
Cpu::ProCpu,
|
||||||
|
interrupt::CpuInterrupt::Interrupt1LevelPriority1,
|
||||||
|
);
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
(&BUTTON).lock(|data| {
|
||||||
|
let mut button = data.borrow_mut();
|
||||||
|
let button = button.as_mut().unwrap();
|
||||||
|
button.clear_interrupt();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
7
esp32-hal/hal-defaults.x
Normal file
7
esp32-hal/hal-defaults.x
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
PROVIDE(level1_interrupt = DefaultHandler);
|
||||||
|
PROVIDE(level2_interrupt = DefaultHandler);
|
||||||
|
PROVIDE(level3_interrupt = DefaultHandler);
|
||||||
|
PROVIDE(level4_interrupt = DefaultHandler);
|
||||||
|
PROVIDE(level5_interrupt = DefaultHandler);
|
||||||
|
PROVIDE(level6_interrupt = DefaultHandler);
|
||||||
|
PROVIDE(level7_interrupt = DefaultHandler);
|
||||||
@ -7,7 +7,7 @@ pub use self::gpio::IO;
|
|||||||
|
|
||||||
pub mod gpio;
|
pub mod gpio;
|
||||||
|
|
||||||
pub use esp_hal_common::ram;
|
pub use esp_hal_common::{interrupt, ram, Cpu};
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
extern "C" fn DefaultHandler(_level: u32, _interrupt: pac::Interrupt) {}
|
extern "C" fn DefaultHandler(_level: u32, _interrupt: pac::Interrupt) {}
|
||||||
@ -55,3 +55,10 @@ pub unsafe extern "C" fn ESP32Reset() -> ! {
|
|||||||
pub extern "Rust" fn __init_data() -> bool {
|
pub extern "Rust" fn __init_data() -> bool {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn gpio_intr_enable(int_enable: bool, nmi_enable: bool) -> u8 {
|
||||||
|
int_enable as u8
|
||||||
|
| ((nmi_enable as u8) << 1)
|
||||||
|
| (int_enable as u8) << 2
|
||||||
|
| ((nmi_enable as u8) << 3)
|
||||||
|
}
|
||||||
|
|||||||
@ -4,3 +4,6 @@ rustflags = [
|
|||||||
|
|
||||||
[build]
|
[build]
|
||||||
target = "riscv32imc-unknown-none-elf"
|
target = "riscv32imc-unknown-none-elf"
|
||||||
|
|
||||||
|
[unstable]
|
||||||
|
build-std = [ "core" ]
|
||||||
|
|||||||
16
esp32c3-hal/.vscode/settings.json
vendored
Normal file
16
esp32c3-hal/.vscode/settings.json
vendored
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"rust-analyzer.cargo.features": [],
|
||||||
|
"rust-analyzer.cargo.allFeatures": false,
|
||||||
|
"editor.formatOnSave": true,
|
||||||
|
"rust-analyzer.checkOnSave.allTargets": false,
|
||||||
|
"rust-analyzer.checkOnSave.allFeatures": false,
|
||||||
|
"rust-analyzer.cargo.runBuildScripts": false,
|
||||||
|
"rust-analyzer.checkOnSave.overrideCommand": [
|
||||||
|
"cargo",
|
||||||
|
"check",
|
||||||
|
"--message-format=json",
|
||||||
|
"-Z",
|
||||||
|
"build-std=core",
|
||||||
|
"--examples"
|
||||||
|
]
|
||||||
|
}
|
||||||
@ -43,6 +43,9 @@ git = "https://github.com/MabezDev/riscv-rt"
|
|||||||
rev = "6b55e4aa3895924e31bcd151f2f0ab840836fa07"
|
rev = "6b55e4aa3895924e31bcd151f2f0ab840836fa07"
|
||||||
optional = true
|
optional = true
|
||||||
|
|
||||||
|
[build-dependencies]
|
||||||
|
riscv-target = "0.1.2"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
panic-halt = "0.2"
|
panic-halt = "0.2"
|
||||||
|
|
||||||
|
|||||||
101
esp32c3-hal/asm.S
Normal file
101
esp32c3-hal/asm.S
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
#define STORE sw
|
||||||
|
#define LOAD lw
|
||||||
|
#define LOG_REGBYTES 2
|
||||||
|
#define REGBYTES (1 << LOG_REGBYTES)
|
||||||
|
|
||||||
|
/*
|
||||||
|
Trap entry point (_start_trap)
|
||||||
|
Saves registers and calls _start_trap_rust_hal,
|
||||||
|
restores registers and then returns.
|
||||||
|
*/
|
||||||
|
.section .trap, "ax"
|
||||||
|
.global _start_trap_hal
|
||||||
|
.option norelax
|
||||||
|
.align 6
|
||||||
|
|
||||||
|
_start_trap_hal:
|
||||||
|
addi sp, sp, -32*REGBYTES
|
||||||
|
|
||||||
|
STORE ra, 0*REGBYTES(sp)
|
||||||
|
STORE t0, 1*REGBYTES(sp)
|
||||||
|
STORE t1, 2*REGBYTES(sp)
|
||||||
|
STORE t2, 3*REGBYTES(sp)
|
||||||
|
STORE t3, 4*REGBYTES(sp)
|
||||||
|
STORE t4, 5*REGBYTES(sp)
|
||||||
|
STORE t5, 6*REGBYTES(sp)
|
||||||
|
STORE t6, 7*REGBYTES(sp)
|
||||||
|
STORE a0, 8*REGBYTES(sp)
|
||||||
|
STORE a1, 9*REGBYTES(sp)
|
||||||
|
STORE a2, 10*REGBYTES(sp)
|
||||||
|
STORE a3, 11*REGBYTES(sp)
|
||||||
|
STORE a4, 12*REGBYTES(sp)
|
||||||
|
STORE a5, 13*REGBYTES(sp)
|
||||||
|
STORE a6, 14*REGBYTES(sp)
|
||||||
|
STORE a7, 15*REGBYTES(sp)
|
||||||
|
STORE s0, 16*REGBYTES(sp)
|
||||||
|
STORE s1, 17*REGBYTES(sp)
|
||||||
|
STORE s2, 18*REGBYTES(sp)
|
||||||
|
STORE s3, 19*REGBYTES(sp)
|
||||||
|
STORE s4, 20*REGBYTES(sp)
|
||||||
|
STORE s5, 21*REGBYTES(sp)
|
||||||
|
STORE s6, 22*REGBYTES(sp)
|
||||||
|
STORE s7, 23*REGBYTES(sp)
|
||||||
|
STORE s8, 24*REGBYTES(sp)
|
||||||
|
STORE s9, 25*REGBYTES(sp)
|
||||||
|
STORE s10, 26*REGBYTES(sp)
|
||||||
|
STORE s11, 27*REGBYTES(sp)
|
||||||
|
STORE gp, 28*REGBYTES(sp)
|
||||||
|
STORE tp, 29*REGBYTES(sp)
|
||||||
|
|
||||||
|
addi s0, sp, 32*REGBYTES
|
||||||
|
STORE s0, 30*REGBYTES(sp)
|
||||||
|
|
||||||
|
add a0, sp, zero
|
||||||
|
jal ra, _start_trap_rust_hal
|
||||||
|
|
||||||
|
LOAD ra, 0*REGBYTES(sp)
|
||||||
|
LOAD t0, 1*REGBYTES(sp)
|
||||||
|
LOAD t1, 2*REGBYTES(sp)
|
||||||
|
LOAD t2, 3*REGBYTES(sp)
|
||||||
|
LOAD t3, 4*REGBYTES(sp)
|
||||||
|
LOAD t4, 5*REGBYTES(sp)
|
||||||
|
LOAD t5, 6*REGBYTES(sp)
|
||||||
|
LOAD t6, 7*REGBYTES(sp)
|
||||||
|
LOAD a0, 8*REGBYTES(sp)
|
||||||
|
LOAD a1, 9*REGBYTES(sp)
|
||||||
|
LOAD a2, 10*REGBYTES(sp)
|
||||||
|
LOAD a3, 11*REGBYTES(sp)
|
||||||
|
LOAD a4, 12*REGBYTES(sp)
|
||||||
|
LOAD a5, 13*REGBYTES(sp)
|
||||||
|
LOAD a6, 14*REGBYTES(sp)
|
||||||
|
LOAD a7, 15*REGBYTES(sp)
|
||||||
|
LOAD s0, 16*REGBYTES(sp)
|
||||||
|
LOAD s1, 17*REGBYTES(sp)
|
||||||
|
LOAD s2, 18*REGBYTES(sp)
|
||||||
|
LOAD s3, 19*REGBYTES(sp)
|
||||||
|
LOAD s4, 20*REGBYTES(sp)
|
||||||
|
LOAD s5, 21*REGBYTES(sp)
|
||||||
|
LOAD s6, 22*REGBYTES(sp)
|
||||||
|
LOAD s7, 23*REGBYTES(sp)
|
||||||
|
LOAD s8, 24*REGBYTES(sp)
|
||||||
|
LOAD s9, 25*REGBYTES(sp)
|
||||||
|
LOAD s10, 26*REGBYTES(sp)
|
||||||
|
LOAD s11, 27*REGBYTES(sp)
|
||||||
|
LOAD gp, 28*REGBYTES(sp)
|
||||||
|
LOAD tp, 29*REGBYTES(sp)
|
||||||
|
LOAD sp, 30*REGBYTES(sp)
|
||||||
|
|
||||||
|
# SP was restored from the original SP
|
||||||
|
mret
|
||||||
|
|
||||||
|
.section .trap, "ax"
|
||||||
|
.balign 0x100
|
||||||
|
.global _vector_table
|
||||||
|
.type _vector_table, @function
|
||||||
|
|
||||||
|
_vector_table:
|
||||||
|
.option push
|
||||||
|
.option norvc
|
||||||
|
.rept 31
|
||||||
|
j _start_trap_hal
|
||||||
|
.endr
|
||||||
3
esp32c3-hal/asm.bat
Normal file
3
esp32c3-hal/asm.bat
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
riscv32-esp-elf-gcc -ggdb3 -c -mabi=ilp32 -march=rv32i asm.S -o bin/esp32c3asm.o
|
||||||
|
riscv32-esp-elf-ar crs bin/asm_riscv32i-unknown-none-elf.a bin/esp32c3asm.o
|
||||||
|
del bin\esp32c3asm.o
|
||||||
BIN
esp32c3-hal/bin/asm_riscv32i-unknown-none-elf.a
Normal file
BIN
esp32c3-hal/bin/asm_riscv32i-unknown-none-elf.a
Normal file
Binary file not shown.
@ -1,4 +1,11 @@
|
|||||||
use std::{env, fs::File, io::Write, path::PathBuf};
|
use std::{
|
||||||
|
env,
|
||||||
|
fs::{self, File},
|
||||||
|
io::Write,
|
||||||
|
path::PathBuf,
|
||||||
|
};
|
||||||
|
|
||||||
|
use riscv_target::Target;
|
||||||
|
|
||||||
#[cfg(not(feature = "normalboot"))]
|
#[cfg(not(feature = "normalboot"))]
|
||||||
fn main() {
|
fn main() {
|
||||||
@ -26,6 +33,9 @@ fn main() {
|
|||||||
// instead of when any part of the source code changes.
|
// instead of when any part of the source code changes.
|
||||||
println!("cargo:rerun-if-changed=memory.x");
|
println!("cargo:rerun-if-changed=memory.x");
|
||||||
println!("cargo:rustc-link-arg=-Tesp32c3-link.x");
|
println!("cargo:rustc-link-arg=-Tesp32c3-link.x");
|
||||||
|
|
||||||
|
add_defaults();
|
||||||
|
prepare_trap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "normalboot")]
|
#[cfg(feature = "normalboot")]
|
||||||
@ -49,4 +59,40 @@ fn main() {
|
|||||||
println!("cargo:rerun-if-changed=memory.x");
|
println!("cargo:rerun-if-changed=memory.x");
|
||||||
println!("cargo:rustc-link-arg=-Tmemory.x");
|
println!("cargo:rustc-link-arg=-Tmemory.x");
|
||||||
println!("cargo:rustc-link-arg=-Tbl-riscv-link.x");
|
println!("cargo:rustc-link-arg=-Tbl-riscv-link.x");
|
||||||
|
|
||||||
|
add_defaults();
|
||||||
|
prepare_trap();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_defaults() {
|
||||||
|
let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
|
||||||
|
File::create(out.join("hal-defaults.x"))
|
||||||
|
.unwrap()
|
||||||
|
.write_all(include_bytes!("hal-defaults.x"))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
println!("cargo:rustc-link-search={}", out.display());
|
||||||
|
println!("cargo:rustc-link-arg=-Thal-defaults.x");
|
||||||
|
}
|
||||||
|
|
||||||
|
fn prepare_trap() {
|
||||||
|
let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
|
||||||
|
let name = env::var("CARGO_PKG_NAME").unwrap();
|
||||||
|
let target = env::var("TARGET").unwrap();
|
||||||
|
|
||||||
|
if target.starts_with("riscv") {
|
||||||
|
let mut target = Target::from_target_str(&target);
|
||||||
|
target.retain_extensions("if");
|
||||||
|
|
||||||
|
let target = target.to_string();
|
||||||
|
|
||||||
|
fs::copy(
|
||||||
|
format!("bin/asm_{}.a", target),
|
||||||
|
out.join(format!("lib{}.a", name)),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
println!("cargo:rustc-link-lib=static={}", name);
|
||||||
|
println!("cargo:rustc-link-search={}", out.display());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
99
esp32c3-hal/examples/gpio_interrupt.rs
Normal file
99
esp32c3-hal/examples/gpio_interrupt.rs
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
#![no_std]
|
||||||
|
#![no_main]
|
||||||
|
|
||||||
|
use core::{cell::RefCell, fmt::Write};
|
||||||
|
|
||||||
|
use bare_metal::Mutex;
|
||||||
|
use esp32c3_hal::{
|
||||||
|
gpio::{Gpio9, IO},
|
||||||
|
pac::{self, Peripherals, UART0},
|
||||||
|
prelude::*,
|
||||||
|
Delay,
|
||||||
|
RtcCntl,
|
||||||
|
Serial,
|
||||||
|
Timer,
|
||||||
|
};
|
||||||
|
use esp_hal_common::{
|
||||||
|
interrupt::{self},
|
||||||
|
Cpu,
|
||||||
|
Event,
|
||||||
|
Input,
|
||||||
|
Pin,
|
||||||
|
PullDown,
|
||||||
|
};
|
||||||
|
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]
|
||||||
|
fn main() -> ! {
|
||||||
|
let peripherals = Peripherals::take().unwrap();
|
||||||
|
|
||||||
|
// Disable the watchdog timers. For the ESP32-C3, this includes the Super WDT,
|
||||||
|
// the RTC WDT, and the TIMG WDTs.
|
||||||
|
let rtc_cntl = RtcCntl::new(peripherals.RTC_CNTL);
|
||||||
|
let mut timer0 = Timer::new(peripherals.TIMG0);
|
||||||
|
let mut timer1 = Timer::new(peripherals.TIMG1);
|
||||||
|
let serial0 = Serial::new(peripherals.UART0).unwrap();
|
||||||
|
|
||||||
|
rtc_cntl.set_super_wdt_enable(false);
|
||||||
|
rtc_cntl.set_wdt_enable(false);
|
||||||
|
timer0.disable();
|
||||||
|
timer1.disable();
|
||||||
|
|
||||||
|
// Set GPIO5 as an output
|
||||||
|
let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);
|
||||||
|
let mut led = io.pins.gpio5.into_push_pull_output();
|
||||||
|
|
||||||
|
// Set GPIO9 as an input
|
||||||
|
let mut button = io.pins.gpio9.into_pull_down_input();
|
||||||
|
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,
|
||||||
|
);
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
riscv::interrupt::enable();
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut delay = Delay::new(peripherals.SYSTIMER);
|
||||||
|
loop {
|
||||||
|
led.toggle().unwrap();
|
||||||
|
delay.delay_ms(500u32);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub fn interrupt3() {
|
||||||
|
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);
|
||||||
|
button.clear_interrupt();
|
||||||
|
});
|
||||||
|
}
|
||||||
31
esp32c3-hal/hal-defaults.x
Normal file
31
esp32c3-hal/hal-defaults.x
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
PROVIDE(interrupt1 = DefaultHandler);
|
||||||
|
PROVIDE(interrupt2 = DefaultHandler);
|
||||||
|
PROVIDE(interrupt3 = DefaultHandler);
|
||||||
|
PROVIDE(interrupt4 = DefaultHandler);
|
||||||
|
PROVIDE(interrupt5 = DefaultHandler);
|
||||||
|
PROVIDE(interrupt6 = DefaultHandler);
|
||||||
|
PROVIDE(interrupt7 = DefaultHandler);
|
||||||
|
PROVIDE(interrupt8 = DefaultHandler);
|
||||||
|
PROVIDE(interrupt9 = DefaultHandler);
|
||||||
|
PROVIDE(interrupt10 = DefaultHandler);
|
||||||
|
PROVIDE(interrupt11 = DefaultHandler);
|
||||||
|
PROVIDE(interrupt12 = DefaultHandler);
|
||||||
|
PROVIDE(interrupt13 = DefaultHandler);
|
||||||
|
PROVIDE(interrupt14 = DefaultHandler);
|
||||||
|
PROVIDE(interrupt15 = DefaultHandler);
|
||||||
|
PROVIDE(interrupt16 = DefaultHandler);
|
||||||
|
PROVIDE(interrupt17 = DefaultHandler);
|
||||||
|
PROVIDE(interrupt18 = DefaultHandler);
|
||||||
|
PROVIDE(interrupt19 = DefaultHandler);
|
||||||
|
PROVIDE(interrupt20 = DefaultHandler);
|
||||||
|
PROVIDE(interrupt21 = DefaultHandler);
|
||||||
|
PROVIDE(interrupt22 = DefaultHandler);
|
||||||
|
PROVIDE(interrupt23 = DefaultHandler);
|
||||||
|
PROVIDE(interrupt24 = DefaultHandler);
|
||||||
|
PROVIDE(interrupt25 = DefaultHandler);
|
||||||
|
PROVIDE(interrupt26 = DefaultHandler);
|
||||||
|
PROVIDE(interrupt27 = DefaultHandler);
|
||||||
|
PROVIDE(interrupt28 = DefaultHandler);
|
||||||
|
PROVIDE(interrupt29 = DefaultHandler);
|
||||||
|
PROVIDE(interrupt30 = DefaultHandler);
|
||||||
|
PROVIDE(interrupt31 = DefaultHandler);
|
||||||
@ -8,7 +8,7 @@ use riscv_rt::pre_init;
|
|||||||
pub mod gpio;
|
pub mod gpio;
|
||||||
pub mod rtc_cntl;
|
pub mod rtc_cntl;
|
||||||
|
|
||||||
pub use esp_hal_common::ram;
|
pub use esp_hal_common::{interrupt, ram, Cpu};
|
||||||
|
|
||||||
pub use self::{gpio::IO, rtc_cntl::RtcCntl};
|
pub use self::{gpio::IO, rtc_cntl::RtcCntl};
|
||||||
|
|
||||||
@ -40,6 +40,7 @@ extern "C" {
|
|||||||
#[cfg(not(feature = "normalboot"))]
|
#[cfg(not(feature = "normalboot"))]
|
||||||
#[pre_init]
|
#[pre_init]
|
||||||
#[cfg(not(feature = "normalboot"))]
|
#[cfg(not(feature = "normalboot"))]
|
||||||
|
#[doc(hidden)]
|
||||||
unsafe fn init() {
|
unsafe fn init() {
|
||||||
r0::init_data(&mut _srwtext, &mut _erwtext, &_irwtext);
|
r0::init_data(&mut _srwtext, &mut _erwtext, &_irwtext);
|
||||||
|
|
||||||
@ -54,6 +55,7 @@ unsafe fn init() {
|
|||||||
|
|
||||||
#[allow(unreachable_code)]
|
#[allow(unreachable_code)]
|
||||||
#[export_name = "_mp_hook"]
|
#[export_name = "_mp_hook"]
|
||||||
|
#[doc(hidden)]
|
||||||
pub fn mp_hook() -> bool {
|
pub fn mp_hook() -> bool {
|
||||||
unsafe {
|
unsafe {
|
||||||
r0::zero_bss(&mut _rtc_fast_bss_start, &mut _rtc_fast_bss_end);
|
r0::zero_bss(&mut _rtc_fast_bss_start, &mut _rtc_fast_bss_end);
|
||||||
@ -69,3 +71,7 @@ pub fn mp_hook() -> bool {
|
|||||||
|
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn gpio_intr_enable(int_enable: bool, nmi_enable: bool) -> u8 {
|
||||||
|
int_enable as u8 | ((nmi_enable as u8) << 1)
|
||||||
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user