Skip to content

Commit 7f40e5e

Browse files
Add gic-timer example.
Shows how to use the Physical Timer and the Virtual Timer interrupts.
1 parent 6fe66e2 commit 7f40e5e

File tree

3 files changed

+242
-0
lines changed

3 files changed

+242
-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 = "gic-timer"
47+
required-features = ["gic"]
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
Found PERIPHBASE 0xf0000000
2+
Creating GIC driver @ 0xf0000000 / 0xf0100000
3+
Calling git.setup(0)
4+
Configure Physical Timer Interrupt...
5+
Configure Virtual Timer Interrupt...
6+
Physical timer frequency 62500000 Hz, interrupt every 3125000
7+
Virtual timer frequency 62500000 Hz, interrupt every 3125000
8+
Enabling interrupts...
9+
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) }
10+
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) }
11+
> IRQ
12+
- IRQ handle PPI 14
13+
- Physical Timer handled
14+
- IRQ handle PPI 11
15+
- Virtual Timer handled
16+
< IRQ
17+
Main loop wake up 1
18+
> IRQ
19+
- IRQ handle PPI 14
20+
- Physical Timer handled
21+
- IRQ handle PPI 11
22+
- Virtual Timer handled
23+
< IRQ
24+
Main loop wake up 2
25+
> IRQ
26+
- IRQ handle PPI 14
27+
- Physical Timer handled
28+
- IRQ handle PPI 11
29+
- Virtual Timer handled
30+
< IRQ
31+
Main loop wake up 3
32+
> IRQ
33+
- IRQ handle PPI 14
34+
- Physical Timer handled
35+
- IRQ handle PPI 11
36+
- Virtual Timer handled
37+
< IRQ
38+
Main loop wake up 4
39+
> IRQ
40+
- IRQ handle PPI 14
41+
- Physical Timer handled
42+
- IRQ handle PPI 11
43+
- Virtual Timer handled
44+
< IRQ
45+
Main loop wake up 5
46+
> IRQ
47+
- IRQ handle PPI 14
48+
- Physical Timer handled
49+
- IRQ handle PPI 11
50+
- Virtual Timer handled
51+
< IRQ
52+
Main loop wake up 6
53+
> IRQ
54+
- IRQ handle PPI 14
55+
- Physical Timer handled
56+
- IRQ handle PPI 11
57+
- Virtual Timer handled
58+
< IRQ
59+
Main loop wake up 7
60+
> IRQ
61+
- IRQ handle PPI 14
62+
- Physical Timer handled
63+
- IRQ handle PPI 11
64+
- Virtual Timer handled
65+
< IRQ
66+
Main loop wake up 8
67+
> IRQ
68+
- IRQ handle PPI 14
69+
- Physical Timer handled
70+
- IRQ handle PPI 11
71+
- Virtual Timer handled
72+
< IRQ
73+
Main loop wake up 9
74+
> IRQ
75+
- IRQ handle PPI 14
76+
- Physical Timer handled
77+
- IRQ handle PPI 11
78+
- Virtual Timer handled
79+
< IRQ
80+
Main loop wake up 10
Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
//! GICv3 + Generic Timer example
2+
3+
#![no_std]
4+
#![no_main]
5+
6+
use core::ptr::NonNull;
7+
8+
// pull in our start-up code
9+
use cortex_r_rt::{entry, irq};
10+
11+
// pull in our library
12+
use mps3_an536 as _;
13+
14+
use arm_gic::{
15+
gicv3::{GicCpuInterface, GicV3, Group, InterruptGroup},
16+
IntId, UniqueMmioPointer,
17+
};
18+
use cortex_ar::generic_timer::{El1PhysicalTimer, El1VirtualTimer, GenericTimer};
19+
use semihosting::println;
20+
21+
/// Offset from PERIPHBASE for GIC Distributor
22+
const GICD_BASE_OFFSET: usize = 0x0000_0000usize;
23+
24+
/// Offset from PERIPHBASE for the first GIC Redistributor
25+
const GICR_BASE_OFFSET: usize = 0x0010_0000usize;
26+
27+
/// The PPI for the physical timer, according to the Cortex-R52 Reference Manual
28+
///
29+
/// This corresponds to Interrupt ID 30.
30+
const PHYSICAL_TIMER_PPI: IntId = IntId::ppi(14);
31+
32+
/// The PPI for the virutal timer, according to the Cortex-R52 Reference Manual
33+
///
34+
/// This corresponds to Interrupt ID 27.
35+
const VIRTUAL_TIMER_PPI: IntId = IntId::ppi(11);
36+
37+
/// How many tick interrupts per second
38+
const TICKS_PER_SECOND: u32 = 20;
39+
40+
/// The entry-point to the Rust application.
41+
///
42+
/// It is called by the start-up code in `cortex-r-rt`.
43+
#[entry]
44+
fn main() -> ! {
45+
// Get the GIC address by reading CBAR
46+
let periphbase = cortex_ar::register::ImpCbar::read().periphbase();
47+
println!("Found PERIPHBASE {:010p}", periphbase);
48+
let gicd_base = periphbase.wrapping_byte_add(GICD_BASE_OFFSET);
49+
let gicr_base = periphbase.wrapping_byte_add(GICR_BASE_OFFSET);
50+
51+
// Initialise the GIC.
52+
println!(
53+
"Creating GIC driver @ {:010p} / {:010p}",
54+
gicd_base, gicr_base
55+
);
56+
let gicd = unsafe { UniqueMmioPointer::new(NonNull::new(gicd_base.cast()).unwrap()) };
57+
let gicr_base = NonNull::new(gicr_base.cast()).unwrap();
58+
let mut gic: GicV3 = unsafe { GicV3::new(gicd, gicr_base, 1, false) };
59+
println!("Calling git.setup(0)");
60+
gic.setup(0);
61+
GicCpuInterface::set_priority_mask(0x80);
62+
63+
println!("Configure Physical Timer Interrupt...");
64+
gic.set_interrupt_priority(PHYSICAL_TIMER_PPI, Some(0), 0x30)
65+
.expect("Timer set_interrupt_priority");
66+
gic.set_group(PHYSICAL_TIMER_PPI, Some(0), Group::Group1NS)
67+
.expect("Timer set_group");
68+
gic.enable_interrupt(PHYSICAL_TIMER_PPI, Some(0), true)
69+
.expect("Timer enable_interrupt");
70+
71+
println!("Configure Virtual Timer Interrupt...");
72+
gic.set_interrupt_priority(VIRTUAL_TIMER_PPI, Some(0), 0x31)
73+
.expect("Timer set_interrupt_priority");
74+
gic.set_group(VIRTUAL_TIMER_PPI, Some(0), Group::Group1NS)
75+
.expect("Timer set_group");
76+
gic.enable_interrupt(VIRTUAL_TIMER_PPI, Some(0), true)
77+
.expect("Timer enable_interrupt");
78+
79+
let mut pgt = unsafe { El1PhysicalTimer::new() };
80+
pgt.enable(true);
81+
pgt.interrupt_mask(false);
82+
pgt.counter_compare_set(u64::MAX);
83+
println!(
84+
"Physical timer frequency {} Hz, interrupt every {}",
85+
pgt.frequency_hz(),
86+
pgt.frequency_hz() / TICKS_PER_SECOND
87+
);
88+
pgt.countdown_set(pgt.frequency_hz() / TICKS_PER_SECOND);
89+
90+
let mut vgt = unsafe { El1VirtualTimer::new() };
91+
vgt.enable(true);
92+
vgt.interrupt_mask(false);
93+
vgt.counter_compare_set(u64::MAX);
94+
println!(
95+
"Virtual timer frequency {} Hz, interrupt every {}",
96+
vgt.frequency_hz(),
97+
vgt.frequency_hz() / TICKS_PER_SECOND
98+
);
99+
vgt.countdown_set(vgt.frequency_hz() / TICKS_PER_SECOND);
100+
101+
println!("Enabling interrupts...");
102+
dump_cpsr();
103+
unsafe {
104+
cortex_ar::interrupt::enable();
105+
}
106+
dump_cpsr();
107+
108+
for count in 1..=10 {
109+
cortex_ar::asm::wfi();
110+
println!("Main loop wake up {}", count);
111+
}
112+
113+
semihosting::process::exit(0);
114+
}
115+
116+
fn dump_cpsr() {
117+
let cpsr = cortex_ar::register::Cpsr::read();
118+
println!("CPSR: {:?}", cpsr);
119+
}
120+
121+
/// Called when the Arm core gets an IRQ
122+
#[irq]
123+
fn irq_handler() {
124+
println!("> IRQ");
125+
while let Some(int_id) = GicCpuInterface::get_and_acknowledge_interrupt(InterruptGroup::Group1)
126+
{
127+
println!("- IRQ handle {:?}", int_id);
128+
if int_id == PHYSICAL_TIMER_PPI {
129+
handle_physical_timer_irq();
130+
} else if int_id == VIRTUAL_TIMER_PPI {
131+
handle_virtual_timer_irq();
132+
}
133+
GicCpuInterface::end_interrupt(int_id, InterruptGroup::Group1);
134+
}
135+
println!("< IRQ");
136+
}
137+
138+
/// Run when the virtual timer IRQ fires
139+
fn handle_virtual_timer_irq() {
140+
// SAFETY: No other code writes to this peripheral, so this won't race
141+
let mut vgt = unsafe { El1VirtualTimer::new() };
142+
if vgt.interrupt_status() {
143+
println!("- Virtual Timer handled");
144+
let delta = vgt.frequency_hz() / TICKS_PER_SECOND;
145+
vgt.countdown_set(vgt.countdown().wrapping_add(delta));
146+
}
147+
}
148+
149+
/// Run when the physical timer IRQ fires
150+
fn handle_physical_timer_irq() {
151+
// SAFETY: No other code writes to this peripheral, so this won't race
152+
let mut pgt = unsafe { El1PhysicalTimer::new() };
153+
if pgt.interrupt_status() {
154+
println!("- Physical Timer handled");
155+
let delta = pgt.frequency_hz() / TICKS_PER_SECOND;
156+
pgt.countdown_set(pgt.countdown().wrapping_add(delta));
157+
}
158+
}

0 commit comments

Comments
 (0)