Skip to content

Commit 1f20e79

Browse files
Merge pull request #70 from korken89/generic-timer-irq-example
Working timer example with IRQs
2 parents 6fe66e2 + 55708d8 commit 1f20e79

File tree

3 files changed

+170
-0
lines changed

3 files changed

+170
-0
lines changed

examples/mps3-an536/Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,3 +41,7 @@ required-features = ["gic"]
4141
[[bin]]
4242
name = "gic-unified-irq"
4343
required-features = ["gic"]
44+
45+
[[bin]]
46+
name = "generic_timer_irq"
47+
required-features = ["gic"]
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
Found PERIPHBASE 0xf0000000
2+
Creating GIC driver @ 0xf0000000 / 0xf0100000
3+
Calling git.setup(0)
4+
Configure Timer Interrupt...
5+
Enabling interrupts...
6+
CPSR: CPSR { N=0 Z=1 C=1 V=0 Q=0 J=0 E=0 A=0 I=1 F=1 T=0 MODE=Ok(Sys) }
7+
CPSR: CPSR { N=0 Z=1 C=1 V=0 Q=0 J=0 E=0 A=0 I=0 F=1 T=0 MODE=Ok(Sys) }
8+
> IRQ
9+
- Timer fired, resetting
10+
< IRQ
11+
Main loop wake up 0
12+
> IRQ
13+
- Timer fired, resetting
14+
< IRQ
15+
Main loop wake up 1
16+
> IRQ
17+
- Timer fired, resetting
18+
< IRQ
19+
Main loop wake up 2
20+
> IRQ
21+
- Timer fired, resetting
22+
< IRQ
23+
Main loop wake up 3
24+
> IRQ
25+
- Timer fired, resetting
26+
< IRQ
27+
Main loop wake up 4
28+
> IRQ
29+
- Timer fired, resetting
30+
< IRQ
31+
Main loop wake up 5
32+
> IRQ
33+
- Timer fired, resetting
34+
< IRQ
35+
Main loop wake up 6
36+
> IRQ
37+
- Timer fired, resetting
38+
< IRQ
39+
Main loop wake up 7
40+
> IRQ
41+
- Timer fired, resetting
42+
< IRQ
43+
Main loop wake up 8
44+
> IRQ
45+
- Timer fired, resetting
46+
< IRQ
47+
Main loop wake up 9
48+
Timer IRQ test completed OK
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
//! Generic-timer example for Arm Cortex-R52, with interrupts firing.
2+
3+
#![no_std]
4+
#![no_main]
5+
6+
use arm_gic::{
7+
gicv3::{GicCpuInterface, GicV3, Group, InterruptGroup},
8+
IntId, UniqueMmioPointer,
9+
};
10+
use core::ptr::NonNull;
11+
use cortex_ar::generic_timer::{El1VirtualTimer, GenericTimer};
12+
use cortex_r_rt::{entry, irq};
13+
use mps3_an536 as _;
14+
use semihosting::println;
15+
16+
/// Offset from PERIPHBASE for GIC Distributor
17+
const GICD_BASE_OFFSET: usize = 0x0000_0000usize;
18+
19+
/// Offset from PERIPHBASE for the first GIC Redistributor
20+
const GICR_BASE_OFFSET: usize = 0x0010_0000usize;
21+
22+
/// The PPI for the virutal timer, according to the Cortex-R52 Technical Reference Manual,
23+
/// Table 10-3: PPI assignments.
24+
///
25+
/// This corresponds to Interrupt ID 27.
26+
const VIRTUAL_TIMER_PPI: IntId = IntId::ppi(11);
27+
28+
/// The entry-point to the Rust application.
29+
///
30+
/// It is called by the start-up code in `cortex-r-rt`.
31+
#[entry]
32+
fn main() -> ! {
33+
// Get the GIC address by reading CBAR
34+
let periphbase = cortex_ar::register::ImpCbar::read().periphbase();
35+
println!("Found PERIPHBASE {:010p}", periphbase);
36+
let gicd_base = periphbase.wrapping_byte_add(GICD_BASE_OFFSET);
37+
let gicr_base = periphbase.wrapping_byte_add(GICR_BASE_OFFSET);
38+
39+
// Initialise the GIC.
40+
println!(
41+
"Creating GIC driver @ {:010p} / {:010p}",
42+
gicd_base, gicr_base
43+
);
44+
let gicd = unsafe { UniqueMmioPointer::new(NonNull::new(gicd_base.cast()).unwrap()) };
45+
let gicr = NonNull::new(gicr_base.cast()).unwrap();
46+
let mut gic = unsafe { GicV3::new(gicd, gicr, 1, false) };
47+
48+
println!("Calling git.setup(0)");
49+
gic.setup(0);
50+
GicCpuInterface::set_priority_mask(0x80);
51+
52+
println!("Configure Timer Interrupt...");
53+
gic.set_interrupt_priority(VIRTUAL_TIMER_PPI, Some(0), 0x31)
54+
.unwrap();
55+
gic.set_group(VIRTUAL_TIMER_PPI, Some(0), Group::Group1NS)
56+
.unwrap();
57+
gic.enable_interrupt(VIRTUAL_TIMER_PPI, Some(0), true)
58+
.unwrap();
59+
60+
// Create virtual timer, run as up-counter.
61+
let mut vgt = unsafe { El1VirtualTimer::new() };
62+
vgt.enable(true);
63+
vgt.interrupt_mask(false);
64+
vgt.counter_compare_set(vgt.counter().wrapping_add(vgt.frequency_hz() as u64));
65+
66+
drop(vgt); // Drop to free the timer handle.
67+
68+
println!("Enabling interrupts...");
69+
dump_cpsr();
70+
unsafe {
71+
cortex_ar::interrupt::enable();
72+
}
73+
dump_cpsr();
74+
75+
let mut count: u32 = 0;
76+
loop {
77+
cortex_ar::asm::wfi();
78+
println!("Main loop wake up {}", count);
79+
count = count.wrapping_add(1);
80+
81+
if count == 10 {
82+
println!("Timer IRQ test completed OK");
83+
semihosting::process::exit(0);
84+
}
85+
}
86+
}
87+
88+
fn dump_cpsr() {
89+
let cpsr = cortex_ar::register::Cpsr::read();
90+
println!("CPSR: {:?}", cpsr);
91+
}
92+
93+
#[irq]
94+
fn irq_handler() {
95+
println!(" > IRQ");
96+
while let Some(int_id) = GicCpuInterface::get_and_acknowledge_interrupt(InterruptGroup::Group1)
97+
{
98+
match int_id {
99+
VIRTUAL_TIMER_PPI => handle_timer_irq(),
100+
_ => unreachable!("We handle all enabled IRQs"),
101+
}
102+
GicCpuInterface::end_interrupt(int_id, InterruptGroup::Group1);
103+
}
104+
println!(" < IRQ");
105+
}
106+
107+
/// Run when the timer IRQ fires
108+
fn handle_timer_irq() {
109+
// SAFETY: We drop en other time handle in main, this is the only active handle.
110+
let mut vgt = unsafe { El1VirtualTimer::new() };
111+
// trigger a timer in 0.2 seconds
112+
vgt.counter_compare_set(
113+
vgt.counter_compare()
114+
.wrapping_add(vgt.frequency_hz() as u64 / 5),
115+
);
116+
117+
println!(" - Timer fired, resetting");
118+
}

0 commit comments

Comments
 (0)