diff --git a/Cargo.lock b/Cargo.lock index ea23f02..3816246 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -70,6 +70,7 @@ dependencies = [ "embedded-io", "fugit", "hex-literal", + "nb 1.1.0", "panic-halt", "paste", "proposed-traits", @@ -78,7 +79,7 @@ dependencies = [ [[package]] name = "ast1060-pac" version = "0.1.0" -source = "git+https://github.com/AspeedTech-BMC/ast1060-pac.git#1ad5938648ccdc702afcd51651c90b3d71b11735" +source = "git+https://github.com/AspeedTech-BMC/ast1060-pac.git#f6fd1c82a3d4ca05ed921ecac24356637ab53b7d" dependencies = [ "cortex-m", "cortex-m-rt", diff --git a/Cargo.toml b/Cargo.toml index 0b117f2..9297001 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,6 +33,7 @@ embedded-io = "0.6.1" fugit = "0.3.7" proposed-traits = { git = "https://github.com/rusty1968/proposed_traits.git", package = "proposed-traits", rev = "85641310df5a5276c67f81621b104322cff0286c" } hex-literal = "0.4" +nb = "1.1.0" paste = "1.0" cortex-m = { version = "0.7.5" } diff --git a/src/lib.rs b/src/lib.rs index 62425c5..50b97fe 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -14,5 +14,6 @@ pub mod spi; pub mod spimonitor; pub mod syscon; pub mod tests; +pub mod timer; pub mod uart; pub mod watchdog; diff --git a/src/main.rs b/src/main.rs index def120d..e153a3c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -22,15 +22,15 @@ use aspeed_ddk::tests::functional::gpio_test; use aspeed_ddk::tests::functional::hash_test::run_hash_tests; use aspeed_ddk::tests::functional::hmac_test::run_hmac_tests; use aspeed_ddk::tests::functional::rsa_test::run_rsa_tests; +use aspeed_ddk::tests::functional::timer_test::run_timer_tests; use panic_halt as _; use proposed_traits::system_control::ResetControl; -use cortex_m_rt::entry; -use embedded_hal::delay::DelayNs; - use core::ptr::{read_volatile, write_volatile}; +use cortex_m_rt::entry; use cortex_m_rt::pre_init; +use embedded_hal::delay::DelayNs; use embedded_io::Write; #[pre_init] @@ -165,6 +165,7 @@ fn main() -> ! { run_rsa_tests(&mut uart_controller, &mut rsa); gpio_test::test_gpioa(&mut uart_controller); test_wdt(&mut uart_controller); + run_timer_tests(&mut uart_controller); let test_spicontroller = false; if test_spicontroller { diff --git a/src/tests/functional/mod.rs b/src/tests/functional/mod.rs index 3206b64..0330332 100644 --- a/src/tests/functional/mod.rs +++ b/src/tests/functional/mod.rs @@ -6,3 +6,4 @@ pub mod hash_test; pub mod hmac_test; pub mod rsa_test; pub mod rsa_test_vec; +pub mod timer_test; diff --git a/src/tests/functional/timer_test.rs b/src/tests/functional/timer_test.rs new file mode 100644 index 0000000..43a1744 --- /dev/null +++ b/src/tests/functional/timer_test.rs @@ -0,0 +1,54 @@ +// Licensed under the Apache-2.0 license + +use crate::timer::{TimerController, TimerType}; +use crate::uart::UartController; +use ast1060_pac::Timer; +use cortex_m::peripheral::NVIC; +use embedded_hal_old::timer::CountDown; +use fugit::MicrosDurationU32; + +use embedded_io::Write; + +static mut UART_PTR: Option<&'static mut UartController<'static>> = None; +static mut TIMER_INSTANCE: Option> = None; + +#[no_mangle] +pub extern "C" fn timer() { + unsafe { + if let Some(uart) = UART_PTR.as_mut() { + let _ = uart.write_all(b"[ISR] Timer\r\n"); + } + if let Some(timer) = TIMER_INSTANCE.as_mut() { + let () = timer.handle_interrupt(); + } + } +} + +pub fn test_timer_isr(uart: &mut UartController<'_>) { + let mut timer = TimerController::::new(50); // tick_per_us + timer.set_callback(Some(timer_callback), TimerType::Periodic); + timer.try_start(MicrosDurationU32::millis(1000)).unwrap(); + + unsafe { + UART_PTR = Some(core::mem::transmute::< + &mut UartController<'_>, + &'static mut UartController<'static>, + >(uart)); + + TIMER_INSTANCE = Some(timer); + NVIC::unmask(ast1060_pac::Interrupt::timer); + } +} + +fn timer_callback() { + unsafe { + if let Some(uart) = UART_PTR.as_mut() { + let _ = uart.write_all(b"[CB] Triggered!\r\n"); + } + } +} + +pub fn run_timer_tests(uart: &mut UartController) { + writeln!(uart, "\r\nRunning Timer ISR test").unwrap(); + test_timer_isr(uart); +} diff --git a/src/timer.rs b/src/timer.rs new file mode 100644 index 0000000..171f48e --- /dev/null +++ b/src/timer.rs @@ -0,0 +1,166 @@ +// Licensed under the Apache-2.0 license + +use core::fmt; +use core::marker::PhantomData; +use embedded_hal_old::timer::{Cancel, CountDown, Periodic}; +use fugit::MicrosDurationU32 as MicroSeconds; + +/// Timer type: One-shot or periodic +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum TimerType { + OneShot, + Periodic, +} + +/// Timer error type +#[derive(Debug)] +pub enum TimerError { + TimeoutTooLarge, + InvalidConfig, +} + +const MAX_TIMEOUT_MS: u32 = 4_294_967; +const MATCH_DISABLE: u32 = 0xffff_ffff; + +/// Trait to abstract timer register base + index +pub trait TimerInstance { + fn cr() -> &'static ast1060_pac::timer::RegisterBlock; + fn gr() -> &'static ast1060_pac::timerg::RegisterBlock; + fn index() -> usize; +} + +/// Timer0 instance (only one currently supported) +impl TimerInstance for ast1060_pac::Timer { + fn cr() -> &'static ast1060_pac::timer::RegisterBlock { + unsafe { &*ast1060_pac::Timer::ptr() } + } + + fn gr() -> &'static ast1060_pac::timerg::RegisterBlock { + unsafe { &*ast1060_pac::Timerg::ptr() } + } + + fn index() -> usize { + 0 + } +} + +/// Timer controller +pub struct TimerController { + cr: &'static ast1060_pac::timer::RegisterBlock, + gr: &'static ast1060_pac::timerg::RegisterBlock, + tick_per_us: u32, + callback: Option, + auto_reload: TimerType, + _marker: PhantomData, +} + +impl fmt::Debug for TimerController { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("TimerController") + } +} + +impl TimerController { + /// Create a new timer controller + #[must_use] + pub fn new(tick_per_us: u32) -> Self { + Self { + cr: T::cr(), + gr: T::gr(), + tick_per_us, + callback: None, + auto_reload: TimerType::OneShot, + _marker: PhantomData, + } + } + + /// Get current counter value + #[must_use] + pub fn counter(&self) -> u32 { + self.cr.timer000().read().bits() + } + + /// Stop the timer and clear reload + pub fn stop(&mut self) { + let index = T::index(); + self.gr + .timerg03c() + .write(|w| unsafe { w.bits(1 << (4 * index)) }); + self.cr.timer004().write(|w| unsafe { w.bits(0) }); + } + + /// Handle timer interrupt (user calls this in IRQ handler) + pub fn handle_interrupt(&mut self) { + let index = T::index(); + self.gr.timerg034().write(|w| unsafe { w.bits(1 << index) }); + + if self.auto_reload == TimerType::OneShot { + self.stop(); + } + + if let Some(cb) = self.callback { + cb(); + } + } + + pub fn set_callback(&mut self, cb: Option, periodic: TimerType) { + self.callback = cb; + self.auto_reload = periodic; + } +} + +impl CountDown for TimerController { + type Time = MicroSeconds; + type Error = TimerError; + + fn try_start