Skip to content

Commit d893e11

Browse files
committed
implement embedded_hal's Timer trait for each channel of k210's hardware timer.
1 parent 98fb515 commit d893e11

File tree

4 files changed

+156
-7
lines changed

4 files changed

+156
-7
lines changed

src/clock.rs

-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
//! Clock configuration
22
//use crate::pac::PRCI;
3-
use crate::sysctl::ACLK;
43
use crate::time::Hertz;
54

65
/// Frozen clock frequencies

src/lib.rs

+7-6
Original file line numberDiff line numberDiff line change
@@ -19,23 +19,24 @@ pub mod gpio;
1919
pub mod gpiohs;
2020
pub mod plic;
2121
pub mod serial;
22-
pub mod spi;
2322
pub mod sha256;
23+
pub mod spi;
2424
pub mod stdout;
2525
pub mod sysctl;
2626
pub mod time;
27+
pub mod timer;
2728

2829
/// Prelude
2930
pub mod prelude {
30-
pub use embedded_hal::prelude::*;
31-
pub use crate::serial::SerialExt as _k210_hal_serial_SerialExt;
32-
pub use crate::stdout::Write as _k210_hal_stdout_Write;
33-
pub use crate::time::U32Ext as _k210_hal_time_U32Ext;
3431
pub use crate::fpioa::FpioaExt as _k210_hal_fpioa_FpioaExt;
35-
pub use crate::sysctl::SysctlExt as _k210_hal_sysctl_SysctlExt;
3632
pub use crate::gpio::GpioExt as _k210_hal_gpio_GpioExt;
3733
pub use crate::gpiohs::GpiohsExt as _k210_hal_gpiohs_GpiohsExt;
3834
pub use crate::plic::PlicExt as _k210_hal_plic_PlicExt;
35+
pub use crate::serial::SerialExt as _k210_hal_serial_SerialExt;
36+
pub use crate::stdout::Write as _k210_hal_stdout_Write;
37+
pub use crate::sysctl::SysctlExt as _k210_hal_sysctl_SysctlExt;
38+
pub use crate::time::U32Ext as _k210_hal_time_U32Ext;
39+
pub use embedded_hal::prelude::*;
3940
}
4041

4142
mod bit_utils {

src/sysctl.rs

+74
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ impl SysctlExt for SYSCTL {
7575
aclk: ACLK { _ownership: () },
7676
apb0: APB0 { _ownership: () },
7777
pll0: PLL0 { _ownership: () },
78+
timer0: Timer0 { _ownership: () },
7879
}
7980
}
8081
}
@@ -87,6 +88,8 @@ pub struct Parts {
8788
pub pll0: PLL0,
8889
/// entry for controlling the enable/disable/frequency of apb0
8990
pub apb0: APB0,
91+
/// entry for controlling the enable/disable/frequency of Timer
92+
pub timer0: Timer0,
9093
// todo: SRAM, APB-bus, ROM, DMA, AI, PLL1, PLL2, APB1, APB2
9194
}
9295

@@ -302,3 +305,74 @@ impl ACLK {
302305
}
303306
}
304307
}
308+
309+
pub struct Timer0 {
310+
_ownership: (),
311+
}
312+
313+
impl Timer0 {
314+
pub fn enable(&mut self, apb0: &mut APB0) {
315+
apb0.enable();
316+
clk_en_peri().modify(|_, w| w.timer0_clk_en().set_bit());
317+
}
318+
319+
pub fn disable(&mut self) {
320+
clk_en_peri().modify(|_, w| w.timer0_clk_en().clear_bit());
321+
}
322+
323+
fn use_external(&mut self) {
324+
sysctl()
325+
.clk_sel0
326+
.modify(|_, w| w.timer0_clk_sel().clear_bit());
327+
}
328+
329+
fn use_pll0(&mut self) {
330+
sysctl()
331+
.clk_sel0
332+
.modify(|_, w| w.timer0_clk_sel().set_bit());
333+
}
334+
335+
pub fn set_frequency(&mut self, resolution: impl Into<Hertz>) -> Hertz {
336+
let resolution = resolution.into().0;
337+
// resolution = input / ((timer0_clk + 1) * 2), timer0_clk is 8 bits
338+
339+
// find a nearest input
340+
let in0_nearest_clk = (CLOCK_FREQ_IN0 / resolution / 2 - 1).min(255);
341+
let in0_result = CLOCK_FREQ_IN0 / ((in0_nearest_clk + 1) * 2);
342+
let in0_diff = (in0_result as i64 - resolution as i64).abs();
343+
344+
let pll0_freq = PLL0::steal().get_frequency().0;
345+
let pll0_nearest_clk = (pll0_freq / resolution / 2 - 1).min(255);
346+
let pll0_result = pll0_freq / ((pll0_nearest_clk + 1) * 2);
347+
let pll0_diff = (pll0_result as i64 - resolution as i64).abs();
348+
349+
if in0_diff <= pll0_diff {
350+
unsafe {
351+
self.use_external();
352+
sysctl()
353+
.clk_th2
354+
.modify(|_, w| w.timer0_clk().bits(in0_nearest_clk as u8));
355+
}
356+
Hertz(in0_result)
357+
} else {
358+
self.use_pll0();
359+
unsafe {
360+
sysctl()
361+
.clk_th2
362+
.modify(|_, w| w.timer0_clk().bits(pll0_nearest_clk as u8));
363+
}
364+
Hertz(pll0_result)
365+
}
366+
}
367+
pub fn get_frequency(&self) -> Hertz {
368+
let threshold = sysctl().clk_th2.read().timer0_clk().bits() as u32;
369+
let input = if sysctl().clk_sel0.read().timer0_clk_sel().bit() {
370+
PLL0::steal().get_frequency().0
371+
} else {
372+
CLOCK_FREQ_IN0
373+
};
374+
Hertz(input / ((threshold + 1) * 2))
375+
}
376+
}
377+
378+
// todo: Timer1, Timer2, maybe with a macro

src/timer.rs

+75
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
use crate::pac::TIMER0;
2+
use crate::sysctl::{self, APB0};
3+
use crate::time::Hertz;
4+
5+
macro_rules! timer {
6+
($Timer: ident, $timer: ident, $TIMER: ident) => {
7+
pub struct $Timer<'a> {
8+
timer: &'a $TIMER,
9+
channel_id: usize,
10+
resolution: u32,
11+
}
12+
13+
impl<'a> $Timer<'a> {
14+
pub fn new(
15+
timer: &'a $TIMER,
16+
channel_id: usize,
17+
$timer: &mut sysctl::$Timer,
18+
apb0: &mut APB0,
19+
) -> Self {
20+
$timer.enable(apb0);
21+
timer.channel[channel_id]
22+
.control
23+
.modify(|_, w| w.enable().set_bit().interrupt().set_bit().mode().user());
24+
Self {
25+
timer,
26+
channel_id,
27+
resolution: $timer.get_frequency().0,
28+
}
29+
}
30+
}
31+
32+
impl<'a> embedded_hal::timer::Periodic for $Timer<'a> {}
33+
34+
impl<'a> embedded_hal::timer::CountDown for $Timer<'a> {
35+
type Error = ();
36+
type Time = Hertz;
37+
38+
fn try_start<T>(&mut self, count: T) -> Result<(), Self::Error>
39+
where
40+
T: Into<Self::Time>,
41+
{
42+
self.timer.channel[self.channel_id]
43+
.control
44+
.modify(|_, w| w.enable().clear_bit());
45+
let count = count.into().0;
46+
let ticks = self.resolution / count;
47+
unsafe {
48+
self.timer.channel[self.channel_id]
49+
.current_value
50+
.write(|w| w.bits(0));
51+
self.timer.channel[self.channel_id]
52+
.load_count
53+
.write(|w| w.bits(ticks));
54+
}
55+
self.timer.channel[self.channel_id]
56+
.control
57+
.modify(|_, w| w.enable().set_bit());
58+
Ok(())
59+
}
60+
61+
fn try_wait(&mut self) -> nb::Result<(), Self::Error> {
62+
if self.timer.raw_intr_stat.read().bits() & (1 << self.channel_id) == 0 {
63+
Err(nb::Error::WouldBlock)
64+
} else {
65+
let _ = self.timer.channel[self.channel_id].eoi.read().bits();
66+
Ok(())
67+
}
68+
}
69+
}
70+
};
71+
}
72+
73+
timer!(Timer0, timer0, TIMER0);
74+
// todo: timer!(Timer1, timer1, TIMER1);
75+
// todo: timer!(Timer2, timer2, TIMER2);

0 commit comments

Comments
 (0)