Skip to content
Open
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
22 changes: 21 additions & 1 deletion packages/kernel/src/hardware/uart.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use core::convert::Infallible;
use core::{convert::Infallible, ffi::c_void};

use embedded_io::{ErrorType, Read, Write};
use snafu::Snafu;
Expand Down Expand Up @@ -44,6 +44,8 @@ pub struct UartDriver {
}

impl UartDriver {
pub const INTERRUPT_ID: u32 = 82;

/// Initialize the UART driver with the given base address.
///
/// # Parameters
Expand Down Expand Up @@ -75,6 +77,24 @@ impl UartDriver {
UartDriverError::try_from_xst_status(status)
}

pub fn set_interrupt_mask(&mut self, mask: u32) {
unsafe {
XUartPs_SetInterruptMask(&mut self.instance, mask);
}
}

#[allow(clippy::not_unsafe_ptr_arg_deref)]
pub fn set_handler(&mut self, handler: XUartPs_Handler, data: *mut c_void) {
unsafe {
XUartPs_SetHandler(&mut self.instance, handler, data);
}
}

#[inline]
pub unsafe extern "C" fn interrupt_handler(data: *mut c_void) {
unsafe { XUartPs_InterruptHandler(core::mem::transmute::<*mut c_void, *mut XUartPs>(data)) }
}

pub fn raw_mut(&mut self) -> &mut XUartPs {
&mut self.instance
}
Expand Down
12 changes: 2 additions & 10 deletions packages/kernel/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,17 +72,9 @@ pub extern "C" fn _start() -> ! {
allocator::init_heap();
}

// Force-initialize all peripherals.
//
// If they fail to initialize, we want them to fail now rather than whenever
// they're first accessed.
GIC.force();
PRIVATE_TIMER.force();
// The watchdog timer isn't locked until vexSystemWatchdogReinitRtos, which could be
// a while into program execution so we'll force initialize it here.
WATCHDOG_TIMER.force();
UART1.force();

// Initialize UART kernel logger
LOGGER.init(LevelFilter::Debug).unwrap();

// Setup private timer peripheral and register a tick interrupt handler using
// the GIC.
Expand Down
33 changes: 32 additions & 1 deletion packages/kernel/src/peripherals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use crate::{
XScuTimer, XScuTimer_ClearInterruptStatus, XScuTimer_IsExpired,
XPAR_XSCUTIMER_0_BASEADDR,
},
uart::XPAR_XUARTPS_1_BASEADDR,
uart::{XUartPs, XPAR_XUARTPS_1_BASEADDR, XUARTPS_EVENT_RECV_DATA, XUARTPS_IXR_MASK, XUARTPS_IXR_RXOVR, XUARTPS_IXR_TTRIG},
wdt::XPAR_XSCUWDT_0_BASEADDR,
},
};
Expand Down Expand Up @@ -78,6 +78,12 @@ pub extern "C" fn timer_interrupt_handler(timer: *mut c_void) {
// [`vexSystemTimerReinitForRtos`] anyways...
}

pub extern "C" fn uart_interrupt_handler(_: *mut c_void, event: u32, event_data: u32) {
assert!(event == XUARTPS_EVENT_RECV_DATA);

log::debug!("UART Interrupt");
}

/// Configures the Private Timer peripheral and registers an interrupt handler
/// for timer ticks using the Generic Interrupt Controller (GIC).
pub fn setup_private_timer() -> Result<(), GicError> {
Expand Down Expand Up @@ -126,3 +132,28 @@ pub fn setup_private_timer() -> Result<(), GicError> {

Ok(())
}

pub fn setup_uart1() -> Result<(), GicError> {
let mut uart = UART1.lock();
let mut gic = GIC.lock();

// Mask out all interrupts except receives.
uart.set_interrupt_mask(XUARTPS_IXR_MASK | XUARTPS_IXR_RXOVR);

// Register the driver's interrupt handler with the GIC.
gic.set_handler(
UartDriver::INTERRUPT_ID,
0, // priority
InterruptTrigger::RisingEdge,
UartDriver::interrupt_handler,
uart.raw_mut() as *mut XUartPs as _,
)?;

// Handle interrupts through [`uart_interrupt_handler`].
uart.set_handler(uart_interrupt_handler, core::ptr::null_mut());

// Enable UART IRQ.
gic.enable_interrupt(UartDriver::INTERRUPT_ID);

Ok(())
}