From c78d834742152ebe88bae30a5eedacc6fb301188 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Neuh=C3=A4user?= Date: Wed, 4 Jun 2025 17:20:04 +0200 Subject: [PATCH] Refactor --- src/interrupt.rs | 34 --------- src/irq_interrupt.rs | 127 ++++++++++++++++++++++++++++++++++ src/lib.rs | 6 +- src/main.rs | 46 ++++++------ src/{ => peripherals}/gpio.rs | 15 +++- src/peripherals/mod.rs | 2 + src/{ => peripherals}/uart.rs | 5 ++ src/timer.rs | 16 ++++- 8 files changed, 190 insertions(+), 61 deletions(-) delete mode 100644 src/interrupt.rs create mode 100644 src/irq_interrupt.rs rename src/{ => peripherals}/gpio.rs (90%) create mode 100644 src/peripherals/mod.rs rename src/{ => peripherals}/uart.rs (94%) diff --git a/src/interrupt.rs b/src/interrupt.rs deleted file mode 100644 index 7d66b60..0000000 --- a/src/interrupt.rs +++ /dev/null @@ -1,34 +0,0 @@ -use core::ptr::{read_volatile, write_volatile}; - -use crate::uart::print; - -const INTERRUPT_BASE: u32 = 0x3F00_B000; -const ENABLE_IRQ_BASE: u32 = INTERRUPT_BASE + 0x210; -const DISABLE_IRQ_BASE: u32 = INTERRUPT_BASE + 0x21C; - -#[no_mangle] -pub unsafe extern "C" fn irq_handler() { - print("Interrupt\r\n"); -} - -pub fn enable_iqr_source(nr: u32) { - let register = ENABLE_IRQ_BASE + 4 * (nr / 32); - let register_offset = nr % 32; - unsafe { - let current = read_volatile(register as *const u32); - let mask = 0b1 << register_offset; - let new_val = current | mask; - write_volatile(register as *mut u32, new_val); - } -} - -pub fn disable_iqr_source(nr: u32) { - let register = DISABLE_IRQ_BASE + 4 * (nr / 32); - let register_offset = nr % 32; - unsafe { - let current = read_volatile(register as *const u32); - let mask = 0b1 << register_offset; - let new_val = current | mask; - write_volatile(register as *mut u32, new_val); - } -} diff --git a/src/irq_interrupt.rs b/src/irq_interrupt.rs new file mode 100644 index 0000000..b8311a6 --- /dev/null +++ b/src/irq_interrupt.rs @@ -0,0 +1,127 @@ +use core::{ + arch::asm, + ptr::{read_volatile, write_volatile}, + sync::atomic::{compiler_fence, Ordering}, +}; + +use crate::peripherals::uart::print; + +const INTERRUPT_BASE: u32 = 0x3F00_B000; +const IRQ_PENDING_BASE: u32 = INTERRUPT_BASE + 0x204; +const ENABLE_IRQ_BASE: u32 = INTERRUPT_BASE + 0x210; +const DISABLE_IRQ_BASE: u32 = INTERRUPT_BASE + 0x21C; + +// GPIO +const GPEDS_BASE: u32 = 0x3F20_0040; + +#[repr(u32)] +pub enum IRQState { + AuxInt = 29, + I2cSpiSlvInt = 44, + Pwa0 = 45, + Pwa1 = 46, + Smi = 48, + GpioInt0 = 49, + GpioInt1 = 50, + GpioInt2 = 51, + GpioInt3 = 52, + I2cInt = 53, + SpiInt = 54, + PcmInt = 55, + UartInt = 57, +} + +#[no_mangle] +unsafe extern "C" fn irq_handler() { + handle_gpio_interrupt(); +} + +fn handle_gpio_interrupt() { + for i in 0..=53u32 { + let val = read_gpio_event_detect_status(i); + + if val { + match i { + 26 => print("Button Pressed"), + _ => {} + } + // Reset GPIO Interrupt handler by writing a 1 + reset_gpio_event_detect_status(i); + } + } + enable_irq(); +} + +/// Get current interrupt status of a GPIO pin +pub fn read_gpio_event_detect_status(id: u32) -> bool { + let register = GPEDS_BASE + (id / 32) * 4; + let register_offset = id % 32; + + let val = unsafe { read_volatile(register as *const u32) >> register_offset }; + (val & 0b1) != 0 +} + +/// Resets current interrupt status of a GPIO pin +pub fn reset_gpio_event_detect_status(id: u32) { + let register = GPEDS_BASE + (id / 32) * 4; + let register_offset = id % 32; + + unsafe { write_volatile(register as *mut u32, 0b1 << register_offset) } + compiler_fence(Ordering::SeqCst); +} + +/// Enables IRQ Source +pub fn enable_irq_source(state: IRQState) { + let nr = state as u32; + let register = ENABLE_IRQ_BASE + 4 * (nr / 32); + let register_offset = nr % 32; + unsafe { + let current = read_volatile(register as *const u32); + let mask = 0b1 << register_offset; + let new_val = current | mask; + write_volatile(register as *mut u32, new_val); + } +} + +/// Disable IRQ Source +pub fn disable_irq_source(state: IRQState) { + let nr = state as u32; + let register = DISABLE_IRQ_BASE + 4 * (nr / 32); + let register_offset = nr % 32; + unsafe { + let current = read_volatile(register as *const u32); + let mask = 0b1 << register_offset; + let new_val = current | mask; + write_volatile(register as *mut u32, new_val); + } +} + +/// Read current IRQ Source status +pub fn read_irq_source_status(state: IRQState) -> u32 { + let nr = state as u32; + let register = ENABLE_IRQ_BASE + 4 * (nr / 32); + let register_offset = nr % 32; + unsafe { (read_volatile(register as *const u32) >> register_offset) & 0b1 } +} + +/// Status if a IRQ Source is enabled +pub fn read_irq_pending(state: IRQState) -> bool { + let nr = state as u32; + let register = IRQ_PENDING_BASE + 4 * (nr / 32); + let register_offset = nr % 32; + (unsafe { (read_volatile(register as *const u32) >> register_offset) & 0b1 }) != 0 +} + +/// Clears the IRQ DAIF Mask +/// +/// Enables IRQ interrupts +pub fn enable_irq() { + unsafe { asm!("msr DAIFClr, #0x2") } +} + +/// Clears the IRQ DAIF Mask +/// +/// Disable IRQ interrupts +pub fn disable_irq() { + unsafe { asm!("msr DAIFSet, #0x2") } +} diff --git a/src/lib.rs b/src/lib.rs index a968802..812aeb8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,6 @@ #![no_std] -pub mod gpio; -pub mod interrupt; +pub mod peripherals; + +pub mod irq_interrupt; pub mod timer; -pub mod uart; diff --git a/src/main.rs b/src/main.rs index ad9c235..207b20e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -8,13 +8,15 @@ use core::{ }; use nova::{ - gpio::{ - gpio_enable_low_detect, gpio_get_state, gpio_high, gpio_low, gpio_pull_up, set_gpio_state, - GPIOState, + irq_interrupt::enable_irq_source, + peripherals::{ + gpio::{ + gpio_get_state, gpio_high, gpio_low, gpio_pull_up, set_falling_edge_detect, + set_gpio_state, GPIOState, + }, + uart::{print, uart_init}, }, - interrupt::enable_iqr_source, - timer::{delay_nops, sleep}, - uart::{print, uart_init}, + timer::{delay_nops, sleep_ms, sleep_us}, }; global_asm!(include_str!("vector.S")); @@ -44,14 +46,11 @@ pub unsafe extern "C" fn _start() { #[no_mangle] pub extern "C" fn main() -> ! { - uart_init(); + enable_uart(); + // Set ACT Led to Outout let _ = set_gpio_state(21, GPIOState::Output); - // Set GPIO Pins to UART - let _ = set_gpio_state(14, GPIOState::Alternative0); - let _ = set_gpio_state(15, GPIOState::Alternative0); - print_current_el_str(); // Delay so clock speed can stabilize @@ -69,26 +68,26 @@ pub extern "C" fn main() -> ! { pub extern "C" fn kernel_main() -> ! { print_current_el_str(); - sleep(500_000); + sleep_us(500_000); - // Set GPIO 21 to Input - enable_iqr_source(49); //21 is on the first GPIO bank - let _ = set_gpio_state(21, GPIOState::Input); - gpio_pull_up(21); - gpio_enable_low_detect(21, true); + // Set GPIO 26 to Input + enable_irq_source(nova::irq_interrupt::IRQState::GpioInt0); //26 is on the first GPIO bank + let _ = set_gpio_state(26, GPIOState::Input); + gpio_pull_up(26); + set_falling_edge_detect(26, true); loop { let _ = gpio_high(29); - sleep(500_000); // 0.5s + sleep_ms(500); // 0.5s let _ = gpio_low(29); - sleep(500_000); // 0.5s + sleep_ms(500); // 0.5s print_gpio_state(); } } fn print_gpio_state() { - let state = gpio_get_state(21); + let state = gpio_get_state(26); let ascii_byte = b'0' + state; let data = [ascii_byte]; @@ -110,6 +109,13 @@ pub fn get_current_el() -> u64 { el >> 2 } +fn enable_uart() { + uart_init(); + // Set GPIO Pins to UART + let _ = set_gpio_state(14, GPIOState::Alternative0); + let _ = set_gpio_state(15, GPIOState::Alternative0); +} + fn print_current_el_str() { let el = get_current_el(); let el_str = match el { diff --git a/src/gpio.rs b/src/peripherals/gpio.rs similarity index 90% rename from src/gpio.rs rename to src/peripherals/gpio.rs index 354e85e..f149837 100644 --- a/src/gpio.rs +++ b/src/peripherals/gpio.rs @@ -115,7 +115,18 @@ fn gpio_pull_up_down(gpio: u8, val: u32) { } } -pub fn gpio_enable_low_detect(gpio: u8, enable: bool) { +pub fn read_falling_edge_detect(gpio: u8) -> u32 { + unsafe { + // Determine GPLEN Register + let register_addr = GPFEN_BASE + 4 * (gpio as u32 / 32); + let register_offset = gpio % 32; + + let current = read_volatile(register_addr as *const u32); + return (current >> register_offset) & 0b1; + } +} + +pub fn set_falling_edge_detect(gpio: u8, enable: bool) { unsafe { // Determine GPLEN Register let register_addr = GPFEN_BASE + 4 * (gpio as u32 / 32); @@ -133,7 +144,7 @@ pub fn gpio_enable_low_detect(gpio: u8, enable: bool) { } } -pub fn gpio_enable_high_detect(gpio: u8, enable: bool) { +pub fn set_rising_edge_detect(gpio: u8, enable: bool) { unsafe { // Determine GPHEN Register let register_addr = GPREN_BASE + 4 * (gpio as u32 / 32); diff --git a/src/peripherals/mod.rs b/src/peripherals/mod.rs new file mode 100644 index 0000000..a8699a2 --- /dev/null +++ b/src/peripherals/mod.rs @@ -0,0 +1,2 @@ +pub mod gpio; +pub mod uart; diff --git a/src/uart.rs b/src/peripherals/uart.rs similarity index 94% rename from src/uart.rs rename to src/peripherals/uart.rs index 58e3366..2d45e58 100644 --- a/src/uart.rs +++ b/src/peripherals/uart.rs @@ -16,6 +16,7 @@ const UART0_CR_TXE: u32 = 1 << 8; const UART0_LCRH: u32 = 0x3F20_102c; const UART0_LCRH_FEN: u32 = 1 << 4; +/// Print `s` over UART pub fn print(s: &str) { for byte in s.bytes() { unsafe { @@ -27,6 +28,7 @@ pub fn print(s: &str) { unsafe { while (core::ptr::read_volatile(UART0_FR as *const u32) >> 3) & 0b1 != 0 {} } } +/// Initialize UART peripheral pub fn uart_init() { let baud_div_times_64 = (UART_CLK * 4) / BAUD; @@ -50,6 +52,7 @@ pub fn uart_init() { } } +/// Enable UARTEN fn uart_enable(enable: bool) { unsafe { let mut cr = core::ptr::read_volatile(UART0_CR as *mut u32); @@ -64,6 +67,7 @@ fn uart_enable(enable: bool) { } } +/// Enable UART FIFO fn uart_fifo_enable(enable: bool) { unsafe { let mut lcrh = core::ptr::read_volatile(UART0_LCRH as *mut u32); @@ -78,6 +82,7 @@ fn uart_fifo_enable(enable: bool) { } } +/// Set UART word length and set FIFO status fn uart_set_lcrh(wlen: u32, enable_fifo: bool) { unsafe { let mut value = (wlen & 0b11) << 5; diff --git a/src/timer.rs b/src/timer.rs index b7db428..7b81dad 100644 --- a/src/timer.rs +++ b/src/timer.rs @@ -4,13 +4,25 @@ fn read_clo() -> u32 { unsafe { return core::ptr::read_volatile(TIMER_CLO as *const u32) } } -pub fn sleep(microseconds: u32) { +/// Sleep for `us` microseconds +pub fn sleep_us(us: u32) { let start = read_clo(); - while read_clo() - start < microseconds { + while read_clo() - start < us { unsafe { core::arch::asm!("nop") } } } +/// Sleep for `ms` milliseconds +pub fn sleep_ms(ms: u32) { + sleep_us(ms * 1000); +} + +/// Sleep for `s` seconds +pub fn sleep_s(s: u32) { + sleep_us(s * 1000); +} + +/// Wait for `count` operations to pass pub fn delay_nops(count: u32) { for _ in 0..count { unsafe { core::arch::asm!("nop") }