Skip to content

Commit 8dae56b

Browse files
Merge pull request AspeedTech-BMC#28 from stevenlee7189/timer
timer: introduce timer driver
2 parents b7b2d97 + 34d1c57 commit 8dae56b

File tree

7 files changed

+229
-4
lines changed

7 files changed

+229
-4
lines changed

Cargo.lock

Lines changed: 2 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ embedded-io = "0.6.1"
3333
fugit = "0.3.7"
3434
proposed-traits = { git = "https://github.com/rusty1968/proposed_traits.git", package = "proposed-traits", rev = "85641310df5a5276c67f81621b104322cff0286c" }
3535
hex-literal = "0.4"
36+
nb = "1.1.0"
3637
paste = "1.0"
3738

3839
cortex-m = { version = "0.7.5" }

src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,6 @@ pub mod spi;
1414
pub mod spimonitor;
1515
pub mod syscon;
1616
pub mod tests;
17+
pub mod timer;
1718
pub mod uart;
1819
pub mod watchdog;

src/main.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,15 @@ use aspeed_ddk::tests::functional::gpio_test;
2222
use aspeed_ddk::tests::functional::hash_test::run_hash_tests;
2323
use aspeed_ddk::tests::functional::hmac_test::run_hmac_tests;
2424
use aspeed_ddk::tests::functional::rsa_test::run_rsa_tests;
25+
use aspeed_ddk::tests::functional::timer_test::run_timer_tests;
2526
use panic_halt as _;
2627

2728
use proposed_traits::system_control::ResetControl;
2829

29-
use cortex_m_rt::entry;
30-
use embedded_hal::delay::DelayNs;
31-
3230
use core::ptr::{read_volatile, write_volatile};
31+
use cortex_m_rt::entry;
3332
use cortex_m_rt::pre_init;
33+
use embedded_hal::delay::DelayNs;
3434
use embedded_io::Write;
3535

3636
#[pre_init]
@@ -165,6 +165,7 @@ fn main() -> ! {
165165
run_rsa_tests(&mut uart_controller, &mut rsa);
166166
gpio_test::test_gpioa(&mut uart_controller);
167167
test_wdt(&mut uart_controller);
168+
run_timer_tests(&mut uart_controller);
168169

169170
let test_spicontroller = false;
170171
if test_spicontroller {

src/tests/functional/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@ pub mod hash_test;
66
pub mod hmac_test;
77
pub mod rsa_test;
88
pub mod rsa_test_vec;
9+
pub mod timer_test;

src/tests/functional/timer_test.rs

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// Licensed under the Apache-2.0 license
2+
3+
use crate::timer::{TimerController, TimerType};
4+
use crate::uart::UartController;
5+
use ast1060_pac::Timer;
6+
use cortex_m::peripheral::NVIC;
7+
use embedded_hal_old::timer::CountDown;
8+
use fugit::MicrosDurationU32;
9+
10+
use embedded_io::Write;
11+
12+
static mut UART_PTR: Option<&'static mut UartController<'static>> = None;
13+
static mut TIMER_INSTANCE: Option<TimerController<Timer>> = None;
14+
15+
#[no_mangle]
16+
pub extern "C" fn timer() {
17+
unsafe {
18+
if let Some(uart) = UART_PTR.as_mut() {
19+
let _ = uart.write_all(b"[ISR] Timer\r\n");
20+
}
21+
if let Some(timer) = TIMER_INSTANCE.as_mut() {
22+
let () = timer.handle_interrupt();
23+
}
24+
}
25+
}
26+
27+
pub fn test_timer_isr(uart: &mut UartController<'_>) {
28+
let mut timer = TimerController::<Timer>::new(50); // tick_per_us
29+
timer.set_callback(Some(timer_callback), TimerType::Periodic);
30+
timer.try_start(MicrosDurationU32::millis(1000)).unwrap();
31+
32+
unsafe {
33+
UART_PTR = Some(core::mem::transmute::<
34+
&mut UartController<'_>,
35+
&'static mut UartController<'static>,
36+
>(uart));
37+
38+
TIMER_INSTANCE = Some(timer);
39+
NVIC::unmask(ast1060_pac::Interrupt::timer);
40+
}
41+
}
42+
43+
fn timer_callback() {
44+
unsafe {
45+
if let Some(uart) = UART_PTR.as_mut() {
46+
let _ = uart.write_all(b"[CB] Triggered!\r\n");
47+
}
48+
}
49+
}
50+
51+
pub fn run_timer_tests(uart: &mut UartController) {
52+
writeln!(uart, "\r\nRunning Timer ISR test").unwrap();
53+
test_timer_isr(uart);
54+
}

src/timer.rs

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
// Licensed under the Apache-2.0 license
2+
3+
use core::fmt;
4+
use core::marker::PhantomData;
5+
use embedded_hal_old::timer::{Cancel, CountDown, Periodic};
6+
use fugit::MicrosDurationU32 as MicroSeconds;
7+
8+
/// Timer type: One-shot or periodic
9+
#[derive(Debug, Clone, Copy, PartialEq)]
10+
pub enum TimerType {
11+
OneShot,
12+
Periodic,
13+
}
14+
15+
/// Timer error type
16+
#[derive(Debug)]
17+
pub enum TimerError {
18+
TimeoutTooLarge,
19+
InvalidConfig,
20+
}
21+
22+
const MAX_TIMEOUT_MS: u32 = 4_294_967;
23+
const MATCH_DISABLE: u32 = 0xffff_ffff;
24+
25+
/// Trait to abstract timer register base + index
26+
pub trait TimerInstance {
27+
fn cr() -> &'static ast1060_pac::timer::RegisterBlock;
28+
fn gr() -> &'static ast1060_pac::timerg::RegisterBlock;
29+
fn index() -> usize;
30+
}
31+
32+
/// Timer0 instance (only one currently supported)
33+
impl TimerInstance for ast1060_pac::Timer {
34+
fn cr() -> &'static ast1060_pac::timer::RegisterBlock {
35+
unsafe { &*ast1060_pac::Timer::ptr() }
36+
}
37+
38+
fn gr() -> &'static ast1060_pac::timerg::RegisterBlock {
39+
unsafe { &*ast1060_pac::Timerg::ptr() }
40+
}
41+
42+
fn index() -> usize {
43+
0
44+
}
45+
}
46+
47+
/// Timer controller
48+
pub struct TimerController<T: TimerInstance> {
49+
cr: &'static ast1060_pac::timer::RegisterBlock,
50+
gr: &'static ast1060_pac::timerg::RegisterBlock,
51+
tick_per_us: u32,
52+
callback: Option<fn()>,
53+
auto_reload: TimerType,
54+
_marker: PhantomData<T>,
55+
}
56+
57+
impl<T: TimerInstance> fmt::Debug for TimerController<T> {
58+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
59+
f.write_str("TimerController")
60+
}
61+
}
62+
63+
impl<T: TimerInstance> TimerController<T> {
64+
/// Create a new timer controller
65+
#[must_use]
66+
pub fn new(tick_per_us: u32) -> Self {
67+
Self {
68+
cr: T::cr(),
69+
gr: T::gr(),
70+
tick_per_us,
71+
callback: None,
72+
auto_reload: TimerType::OneShot,
73+
_marker: PhantomData,
74+
}
75+
}
76+
77+
/// Get current counter value
78+
#[must_use]
79+
pub fn counter(&self) -> u32 {
80+
self.cr.timer000().read().bits()
81+
}
82+
83+
/// Stop the timer and clear reload
84+
pub fn stop(&mut self) {
85+
let index = T::index();
86+
self.gr
87+
.timerg03c()
88+
.write(|w| unsafe { w.bits(1 << (4 * index)) });
89+
self.cr.timer004().write(|w| unsafe { w.bits(0) });
90+
}
91+
92+
/// Handle timer interrupt (user calls this in IRQ handler)
93+
pub fn handle_interrupt(&mut self) {
94+
let index = T::index();
95+
self.gr.timerg034().write(|w| unsafe { w.bits(1 << index) });
96+
97+
if self.auto_reload == TimerType::OneShot {
98+
self.stop();
99+
}
100+
101+
if let Some(cb) = self.callback {
102+
cb();
103+
}
104+
}
105+
106+
pub fn set_callback(&mut self, cb: Option<fn()>, periodic: TimerType) {
107+
self.callback = cb;
108+
self.auto_reload = periodic;
109+
}
110+
}
111+
112+
impl<T: TimerInstance> CountDown for TimerController<T> {
113+
type Time = MicroSeconds;
114+
type Error = TimerError;
115+
116+
fn try_start<Time>(&mut self, count: Time) -> Result<(), Self::Error>
117+
where
118+
Time: Into<MicroSeconds>,
119+
{
120+
let us = count.into().ticks();
121+
122+
if u64::from(us) >= u64::from(MAX_TIMEOUT_MS) * 1000 {
123+
return Err(TimerError::TimeoutTooLarge);
124+
}
125+
126+
let reload = us * self.tick_per_us;
127+
let index = T::index();
128+
129+
self.gr
130+
.timerg03c()
131+
.write(|w| unsafe { w.bits(1 << (4 * index)) });
132+
self.cr.timer004().write(|w| unsafe { w.bits(reload) });
133+
self.cr
134+
.timer008()
135+
.write(|w| unsafe { w.bits(MATCH_DISABLE) });
136+
self.cr
137+
.timer00c()
138+
.write(|w| unsafe { w.bits(MATCH_DISABLE) });
139+
140+
let ctrl_val = (1 << (4 * index)) | (1 << (4 * index + 2));
141+
self.gr.timerg030().write(|w| unsafe { w.bits(ctrl_val) });
142+
143+
Ok(())
144+
}
145+
146+
fn try_wait(&mut self) -> nb::Result<(), Self::Error> {
147+
let index = T::index();
148+
let status = self.gr.timerg034().read().bits();
149+
150+
if (status & (1 << index)) != 0 {
151+
self.gr.timerg034().write(|w| unsafe { w.bits(1 << index) });
152+
Ok(())
153+
} else {
154+
Err(nb::Error::WouldBlock)
155+
}
156+
}
157+
}
158+
159+
impl<T: TimerInstance> Cancel for TimerController<T> {
160+
fn try_cancel(&mut self) -> Result<(), Self::Error> {
161+
self.stop();
162+
Ok(())
163+
}
164+
}
165+
166+
impl<T: TimerInstance> Periodic for TimerController<T> {}

0 commit comments

Comments
 (0)