parent
430bf508e2
commit
07aa9a0686
@ -0,0 +1,61 @@
|
|||||||
|
use super::IO_BASE;
|
||||||
|
use volatile::{ReadOnly, Volatile};
|
||||||
|
|
||||||
|
const INT_BASE: usize = IO_BASE + 0xB000 + 0x200;
|
||||||
|
|
||||||
|
/// Allowed interrupts (ref: peripherals 7.5, page 113)
|
||||||
|
#[derive(Copy, Clone, PartialEq, Debug)]
|
||||||
|
pub enum Interrupt {
|
||||||
|
Timer1 = 1,
|
||||||
|
Timer3 = 3,
|
||||||
|
Usb = 9,
|
||||||
|
Aux = 29,
|
||||||
|
Gpio0 = 49,
|
||||||
|
Gpio1 = 50,
|
||||||
|
Gpio2 = 51,
|
||||||
|
Gpio3 = 52,
|
||||||
|
Uart = 57,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Interrupts registers starting from `INT_BASE` (ref: peripherals 7.5, page 112)
|
||||||
|
#[repr(C)]
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
struct Registers {
|
||||||
|
IRQBasicPending: ReadOnly<u32>,
|
||||||
|
IRQPending: [ReadOnly<u32>; 2],
|
||||||
|
FIQControl: Volatile<u32>,
|
||||||
|
EnableIRQ: [Volatile<u32>; 2],
|
||||||
|
EnableBasicIRQ: Volatile<u32>,
|
||||||
|
DisableIRQ: [Volatile<u32>; 2],
|
||||||
|
DisableBasicIRQ: Volatile<u32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An interrupt controller. Used to enable and disable interrupts as well as to
|
||||||
|
/// check if an interrupt is pending.
|
||||||
|
pub struct Controller {
|
||||||
|
registers: &'static mut Registers,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Controller {
|
||||||
|
/// Returns a new handle to the interrupt controller.
|
||||||
|
pub fn new() -> Controller {
|
||||||
|
Controller {
|
||||||
|
registers: unsafe { &mut *(INT_BASE as *mut Registers) },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Enables the interrupt `int`.
|
||||||
|
pub fn enable(&mut self, int: Interrupt) {
|
||||||
|
self.registers.EnableIRQ[int as usize / 32].write(1 << (int as usize) % 32);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Disables the interrupt `int`.
|
||||||
|
pub fn disable(&mut self, int: Interrupt) {
|
||||||
|
self.registers.DisableIRQ[int as usize / 32].write(1 << (int as usize) % 32);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns `true` if `int` is pending. Otherwise, returns `false`.
|
||||||
|
pub fn is_pending(&self, int: Interrupt) -> bool {
|
||||||
|
self.registers.IRQPending[int as usize / 32].read() & (1 << (int as usize) % 32) != 0
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,68 @@
|
|||||||
|
use super::IO_BASE;
|
||||||
|
use volatile::{ReadOnly, Volatile};
|
||||||
|
|
||||||
|
/// The base address for the ARM system timer registers.
|
||||||
|
const TIMER_REG_BASE: usize = IO_BASE + 0x3000;
|
||||||
|
|
||||||
|
/// System timer registers (ref: peripherals 12.1, page 172)
|
||||||
|
#[repr(C)]
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
struct Registers {
|
||||||
|
CS: Volatile<u32>,
|
||||||
|
CLO: ReadOnly<u32>,
|
||||||
|
CHI: ReadOnly<u32>,
|
||||||
|
COMPARE: [Volatile<u32>; 4],
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(u8)]
|
||||||
|
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
|
||||||
|
pub enum SystemTimer {
|
||||||
|
Timer0 = 0,
|
||||||
|
Timer1 = 1,
|
||||||
|
Timer2 = 2,
|
||||||
|
Timer3 = 3,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The Raspberry Pi ARM system timer.
|
||||||
|
pub struct Timer {
|
||||||
|
registers: &'static mut Registers,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Timer {
|
||||||
|
/// Returns a new instance of `Timer`.
|
||||||
|
pub fn new() -> Timer {
|
||||||
|
Timer {
|
||||||
|
registers: unsafe { &mut *(TIMER_REG_BASE as *mut Registers) },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Reads the system timer's counter and returns the 64-bit counter value.
|
||||||
|
/// The returned value is the number of elapsed microseconds.
|
||||||
|
pub fn read(&self) -> u64 {
|
||||||
|
let low = self.registers.CLO.read();
|
||||||
|
let high = self.registers.CHI.read();
|
||||||
|
((high as u64) << 32) | (low as u64)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets up a match in timer 1 to occur `us` microseconds from now. If
|
||||||
|
/// interrupts for timer 1 are enabled and IRQs are unmasked, then a timer
|
||||||
|
/// interrupt will be issued in `us` microseconds.
|
||||||
|
pub fn tick_in(&mut self, st: SystemTimer, us: u32) {
|
||||||
|
let current_low = self.registers.CLO.read();
|
||||||
|
let compare = current_low.wrapping_add(us);
|
||||||
|
self.registers.COMPARE[st as usize].write(compare);
|
||||||
|
self.registers.CS.write(1 << (st as usize)); // unmask
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the current time in microseconds.
|
||||||
|
pub fn current_time() -> u64 {
|
||||||
|
Timer::new().read()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets up a match in timer 1 to occur `us` microseconds from now. If
|
||||||
|
/// interrupts for timer 1 are enabled and IRQs are unmasked, then a timer
|
||||||
|
/// interrupt will be issued in `us` microseconds.
|
||||||
|
pub fn tick_in(st: SystemTimer, us: u32) {
|
||||||
|
Timer::new().tick_in(st, us)
|
||||||
|
}
|
@ -0,0 +1,10 @@
|
|||||||
|
use super::bcm2837::interrupt::{Controller, Interrupt};
|
||||||
|
|
||||||
|
pub fn handle_irq() {
|
||||||
|
let controller = Controller::new();
|
||||||
|
if controller.is_pending(Interrupt::Timer1) {
|
||||||
|
println!("Timer tick...");
|
||||||
|
super::timer::set_next();
|
||||||
|
// ::trap::timer();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
use super::bcm2837::timer;
|
||||||
|
use super::bcm2837::interrupt::{Controller, Interrupt};
|
||||||
|
|
||||||
|
pub fn init() {
|
||||||
|
Controller::new().enable(Interrupt::Timer1);
|
||||||
|
set_next();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_cycle() -> u64 {
|
||||||
|
timer::current_time()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_next() {
|
||||||
|
// 1000 ms
|
||||||
|
timer::tick_in(timer::SystemTimer::Timer1, 1000 * 1000);
|
||||||
|
}
|
Loading…
Reference in new issue