This commit is contained in:
2025-06-04 17:20:04 +02:00
parent a289dcfd17
commit c78d834742
8 changed files with 190 additions and 61 deletions

View File

@@ -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);
}
}

127
src/irq_interrupt.rs Normal file
View File

@@ -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") }
}

View File

@@ -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;

View File

@@ -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 {

View File

@@ -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);

2
src/peripherals/mod.rs Normal file
View File

@@ -0,0 +1,2 @@
pub mod gpio;
pub mod uart;

View File

@@ -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;

View File

@@ -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") }