Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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" }
Expand Down
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
7 changes: 4 additions & 3 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down Expand Up @@ -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 {
Expand Down
1 change: 1 addition & 0 deletions src/tests/functional/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
54 changes: 54 additions & 0 deletions src/tests/functional/timer_test.rs
Original file line number Diff line number Diff line change
@@ -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<TimerController<Timer>> = 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::<Timer>::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);
}
166 changes: 166 additions & 0 deletions src/timer.rs
Original file line number Diff line number Diff line change
@@ -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<T: TimerInstance> {
cr: &'static ast1060_pac::timer::RegisterBlock,
gr: &'static ast1060_pac::timerg::RegisterBlock,
tick_per_us: u32,
callback: Option<fn()>,
auto_reload: TimerType,
_marker: PhantomData<T>,
}

impl<T: TimerInstance> fmt::Debug for TimerController<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("TimerController")
}
}

impl<T: TimerInstance> TimerController<T> {
/// 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<fn()>, periodic: TimerType) {
self.callback = cb;
self.auto_reload = periodic;
}
}

impl<T: TimerInstance> CountDown for TimerController<T> {
type Time = MicroSeconds;
type Error = TimerError;

fn try_start<Time>(&mut self, count: Time) -> Result<(), Self::Error>
where
Time: Into<MicroSeconds>,
{
let us = count.into().ticks();

if u64::from(us) >= u64::from(MAX_TIMEOUT_MS) * 1000 {
return Err(TimerError::TimeoutTooLarge);
}

let reload = us * self.tick_per_us;
let index = T::index();

self.gr
.timerg03c()
.write(|w| unsafe { w.bits(1 << (4 * index)) });
self.cr.timer004().write(|w| unsafe { w.bits(reload) });
self.cr
.timer008()
.write(|w| unsafe { w.bits(MATCH_DISABLE) });
self.cr
.timer00c()
.write(|w| unsafe { w.bits(MATCH_DISABLE) });

let ctrl_val = (1 << (4 * index)) | (1 << (4 * index + 2));
self.gr.timerg030().write(|w| unsafe { w.bits(ctrl_val) });

Ok(())
}

fn try_wait(&mut self) -> nb::Result<(), Self::Error> {
let index = T::index();
let status = self.gr.timerg034().read().bits();

if (status & (1 << index)) != 0 {
self.gr.timerg034().write(|w| unsafe { w.bits(1 << index) });
Ok(())
} else {
Err(nb::Error::WouldBlock)
}
}
}

impl<T: TimerInstance> Cancel for TimerController<T> {
fn try_cancel(&mut self) -> Result<(), Self::Error> {
self.stop();
Ok(())
}
}

impl<T: TimerInstance> Periodic for TimerController<T> {}