diff --git a/firmware/src/main.rs b/firmware/src/main.rs index 2be3dda..22eb0af 100644 --- a/firmware/src/main.rs +++ b/firmware/src/main.rs @@ -7,7 +7,6 @@ extern crate panic_halt; use core::fmt::Write; use core::{ - arch::asm, ptr::{read_volatile, write_volatile}, }; @@ -33,11 +32,12 @@ mod mcp4726; mod proto; mod uart; mod sampler; +mod timer; + +use timer::millis; const MAC: [u8; 6] = [0xA0, 0xBB, 0xCC, 0xDD, 0xEE, 0xF0]; -static mut SECONDS: u32 = 0; - // use `main` as the entry point of this application // `main` is not allowed to return #[entry] @@ -111,13 +111,7 @@ fn main() -> ! { //defmt::info!("Done setup"); // Set up timer for polling events - unsafe { - // Timer stuff - write_reg(0xf000_3808, 0u32); // Disable timer - write_reg(0xf000_3800, 0u32); // Set LOAD value - write_reg(0xf000_3804, 60_000_000u32); // Set RELOAD value - write_reg(0xf000_3808, 1u32); // Enable timer - } + timer::init(); let mut cmd = command_interface::CommandInterface::new(); @@ -156,33 +150,11 @@ fn main() -> ! { // TODO I think the timer might actually stop until the event is cleared? this may pose // problems, might explain why moving this above the smoltcp stuff "broke" things - handle_timer_event(); + timer::poll(); } } -fn handle_timer_event() { - unsafe { - if read_reg::(0xf000_3818) == 0 { - // No event yet, continue - return; - } - - // Clear TIMER0 event status, and update time - write_reg(0xf000_3818, 1u32); - SECONDS += 1; - } -} - -fn busy_wait(ms: u32) { - let start = millis(); - while millis() - start < ms { - unsafe { - asm!("nop"); - } - } -} - fn write_led(val: u32) { unsafe { write_reg(0xf000_2000, val); @@ -196,16 +168,3 @@ unsafe fn write_reg(addr: u32, value: T) { unsafe fn read_reg(addr: u32) -> T { return read_volatile(addr as *mut T); } - -fn millis() -> u32 { - riscv::interrupt::free(|| { - unsafe { - // Latch timer value - write_reg(0xf000_380c, 1u32); - // Read timer value - let val: u32 = read_reg(0xf000_3810); - let val = 60_000_000 - val; - (SECONDS * 1000) + val / 60_000 - } - }) -} diff --git a/firmware/src/timer.rs b/firmware/src/timer.rs new file mode 100644 index 0000000..951a467 --- /dev/null +++ b/firmware/src/timer.rs @@ -0,0 +1,79 @@ +//! Simple module to use LiteX TIMER0 for simple timekeeping + +use crate::{read_reg, write_reg}; +use core::arch::asm; + +/// Initializes the timer to use for polling events as a wall clock. +/// +/// Timer is running at system frequency (60MHz) +pub fn init() { + unsafe { + write_reg(0xf000_3808, 0u32); // Disable timer + write_reg(0xf000_3800, 0u32); // Set LOAD value + write_reg(0xf000_3804, 60_000_000u32); // Set RELOAD value + write_reg(0xf000_3808, 1u32); // Enable timer + } +} + +// Storage for overflow time +static mut SECONDS: u32 = 0; + +/// Processes potential timer events. Must be polled regularly +pub fn poll() { + unsafe { + if read_reg::(0xf000_3818) == 0 { + // No event yet, continue + return; + } + + // Clear TIMER0 event status, and update time + write_reg(0xf000_3818, 1u32); + SECONDS += 1; + } +} + +/// Gets system time in milliseconds +pub fn millis() -> u32 { + riscv::interrupt::free(|| { + unsafe { + // Latch timer value + write_reg(0xf000_380c, 1u32); + // Read timer value + let val: u32 = read_reg(0xf000_3810); + let val = 60_000_000 - val; + (SECONDS * 1000) + val / 60_000 + } + }) +} + +/// Gets system time in microseconds +pub fn micros() -> u64 { + riscv::interrupt::free(|| { + unsafe { + // Latch timer value + write_reg(0xf000_380c, 1u32); + // Read timer value + let val: u32 = read_reg(0xf000_3810); + let val = 60_000_000 - val; + (SECONDS as u64 * 1_000_000) + (val as u64 / 60) + } + }) +} + +pub fn busy_wait_ms(ms: u32) { + let start = millis(); + while millis() - start < ms { + unsafe { + asm!("nop"); + } + } +} + +pub fn busy_wait_us(us: u64) { + let start = micros(); + while micros() - start < us { + unsafe { + asm!("nop"); + } + } +}