GlobalTimer: add support for starting timer with interrupt #108
@ -7,6 +7,7 @@
|
||||
extern crate alloc;
|
||||
|
||||
use alloc::collections::BTreeMap;
|
||||
use embedded_hal::blocking::delay::DelayUs;
|
||||
use libasync::{
|
||||
delay,
|
||||
smoltcp::{Sockets, TcpStream},
|
||||
@ -25,6 +26,7 @@ use libboard_zynq::{
|
||||
wire::{EthernetAddress, IpAddress, IpCidr},
|
||||
},
|
||||
time::Milliseconds,
|
||||
timer::GlobalTimer,
|
||||
};
|
||||
#[cfg(feature = "target_zc706")]
|
||||
use libboard_zynq::print;
|
||||
@ -61,10 +63,19 @@ interrupt_handler!(IRQ, irq, __irq_stack0_start, __irq_stack1_start, {
|
||||
let id = gic.get_interrupt_id();
|
||||
match MPIDR.read().cpu_id(){
|
||||
0 => {
|
||||
if id.0 == 0 {
|
||||
println!("Interrupting core0...");
|
||||
gic.end_interrupt(id);
|
||||
return;
|
||||
match id.0 {
|
||||
0 => {
|
||||
println!("Interrupting core0...");
|
||||
gic.end_interrupt(id);
|
||||
return;
|
||||
},
|
||||
27 => {
|
||||
println!("GlobalTimer interrupting core0...");
|
||||
GlobalTimer::clear_isr();
|
||||
gic.end_interrupt(id);
|
||||
return;
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
},
|
||||
1 => {
|
||||
@ -137,13 +148,24 @@ pub fn main_core0() {
|
||||
clocks.cpu_1x()
|
||||
);
|
||||
|
||||
let timer = libboard_zynq::timer::GlobalTimer::start();
|
||||
let mut timer = GlobalTimer::start_with_interrupt(100_000);
|
||||
|
||||
let mut ddr = zynq::ddr::DdrRam::ddrram();
|
||||
#[cfg(not(feature = "target_zc706"))]
|
||||
ddr.memtest();
|
||||
ram::init_alloc_ddr(&mut ddr);
|
||||
|
||||
info!("Enable GlobalTimer interrupt on core0");
|
||||
interrupt_controller.enable(
|
||||
gic::InterruptId(27),
|
||||
gic::CPUCore::Core0,
|
||||
gic::InterruptSensitivity::Edge,
|
||||
0,
|
||||
);
|
||||
timer.delay_us(100_000);
|
||||
interrupt_controller.disable(gic::InterruptId(27));
|
||||
info!("Disable GlobalTimer interrupt");
|
||||
|
||||
info!("Send software interrupt to core0");
|
||||
interrupt_controller.send_sgi(gic::InterruptId(0), gic::CPUCore::Core0.into());
|
||||
info!("Core0 returned from interrupt");
|
||||
|
@ -95,6 +95,26 @@ impl InterruptController {
|
||||
}.sgiintid(id.0).satt(false));
|
||||
}
|
||||
|
||||
/// disable the interrupt
|
||||
pub fn disable(&mut self, id: InterruptId){
|
||||
|
||||
// disable
|
||||
let m = (id.0 >> 5) as usize;
|
||||
let n = (id.0 & 0x1F) as usize;
|
||||
assert!(m < 3);
|
||||
unsafe {
|
||||
self.mpcore.icdicer[m].modify(|mut icdicer| *icdicer.set_bit(n, true));
|
||||
}
|
||||
|
||||
// remove CPUs from interrupt
|
||||
let m = (id.0 >> 2) as usize;
|
||||
let n = (8 * (id.0 & 3)) as usize;
|
||||
unsafe {
|
||||
self.mpcore.icdiptr[m].modify(|mut icdiptr| *icdiptr.set_bits(n..=n+1, 0));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// enable the interrupt *for this core*.
|
||||
/// Not needed for SGI.
|
||||
pub fn enable(&mut self, id: InterruptId, target_cpu: CPUCore, sensitivity: InterruptSensitivity, priority: u8) {
|
||||
|
@ -96,12 +96,8 @@ pub struct RegisterBlock {
|
||||
/// Interrupt Set-enable Registers
|
||||
pub icdiser: [RW<u32>; 3],
|
||||
unused9: [u32; 29],
|
||||
/// Interrupt Clear-Enable Register 0
|
||||
pub icdicer0: RW<u32>,
|
||||
/// Interrupt Clear-Enable Register 1
|
||||
pub icdicer1: RW<u32>,
|
||||
/// Interrupt Clear-Enable Register 2
|
||||
pub icdicer2: RW<u32>,
|
||||
/// Interrupt Clear-Enable Register
|
||||
pub icdicer: [RW<u32>; 3],
|
||||
unused10: [u32; 29],
|
||||
/// Interrupt Set-pending Register
|
||||
pub icdispr0: RW<u32>,
|
||||
@ -262,7 +258,7 @@ register!(global_timer_control, GlobalTimerControl, RW, u32);
|
||||
register_bits!(global_timer_control, prescaler, u8, 8, 15);
|
||||
register_bit!(global_timer_control, auto_increment_mode, 3);
|
||||
register_bit!(global_timer_control, irq_enable, 2);
|
||||
register_bit!(global_timer_control, comp_enablea, 1);
|
||||
register_bit!(global_timer_control, comp_enable, 1);
|
||||
register_bit!(global_timer_control, timer_enable, 0);
|
||||
|
||||
register!(global_timer_interrupt_status, GlobalTimerInterruptStatusRegister, RW, u32);
|
||||
|
@ -24,6 +24,43 @@ impl GlobalTimer {
|
||||
pub fn start() -> GlobalTimer {
|
||||
let mut regs = mpcore::RegisterBlock::mpcore();
|
||||
Self::reset(&mut regs);
|
||||
|
||||
// Start
|
||||
regs.global_timer_control.write(
|
||||
mpcore::GlobalTimerControl::zeroed()
|
||||
.prescaler((Self::get_prescaler() - 1) as u8)
|
||||
.auto_increment_mode(true)
|
||||
.timer_enable(true)
|
||||
);
|
||||
GlobalTimer { regs }
|
||||
}
|
||||
|
||||
// Get the timer with a reset and interrupt
|
||||
pub fn start_with_interrupt(interrupt_period_us: u64) -> GlobalTimer {
|
||||
let mut regs = mpcore::RegisterBlock::mpcore();
|
||||
Self::reset(&mut regs);
|
||||
|
||||
let prescaler = Self::get_prescaler() as u64;
|
||||
let clocks = Clocks::get();
|
||||
let increment_val:u32 = (interrupt_period_us * clocks.cpu_3x2x() as u64 / (1_000_000 * (prescaler + 1))) as u32;
|
||||
|
||||
// When auto-increment and comp enable bits are set, an IRQ is generated periodically
|
||||
unsafe{
|
||||
regs.auto_increment.write(increment_val);
|
||||
}
|
||||
|
||||
// Clear event flag
|
||||
Self::clear_isr();
|
||||
|
||||
// Start
|
||||
regs.global_timer_control.write(
|
||||
mpcore::GlobalTimerControl::zeroed()
|
||||
.prescaler((prescaler - 1) as u8)
|
||||
.auto_increment_mode(true)
|
||||
.comp_enable(true)
|
||||
.irq_enable(true)
|
||||
.timer_enable(true)
|
||||
);
|
||||
GlobalTimer { regs }
|
||||
}
|
||||
|
||||
@ -40,21 +77,24 @@ impl GlobalTimer {
|
||||
regs.global_timer_counter1.write(
|
||||
mpcore::ValueRegister::zeroed()
|
||||
);
|
||||
}
|
||||
|
||||
pub fn clear_isr(){
|
||||
let regs = mpcore::RegisterBlock::mpcore();
|
||||
regs.global_timer_interrupt_status.write(
|
||||
mpcore::GlobalTimerInterruptStatusRegister::zeroed()
|
||||
.event_flag(true)
|
||||
);
|
||||
}
|
||||
|
||||
fn get_prescaler() -> u32 {
|
||||
|
||||
// find a prescaler value that matches CPU speed / 2 to us
|
||||
let clocks = Clocks::get();
|
||||
let mut prescaler = clocks.cpu_3x2x() / 1_000_000;
|
||||
while prescaler > 256 {
|
||||
prescaler /= 2;
|
||||
}
|
||||
|
||||
// Start
|
||||
regs.global_timer_control.write(
|
||||
mpcore::GlobalTimerControl::zeroed()
|
||||
.prescaler((prescaler - 1) as u8)
|
||||
.auto_increment_mode(true)
|
||||
.timer_enable(true)
|
||||
);
|
||||
prescaler
|
||||
}
|
||||
|
||||
/// read the raw counter value
|
||||
|
Loading…
Reference in New Issue
Block a user
prescaler