24: Bump to v0.2.3 r=robamu a=robamu

- Added API to reset peripherals
- Improved API of timer.
- Separation of TIM reg and TIM pin interface

Co-authored-by: Robin Mueller <robin.mueller.m@gmail.com>
This commit is contained in:
bors[bot] 2021-12-05 22:05:29 +00:00 committed by GitHub
commit 54e016f0e3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 322 additions and 272 deletions

View File

@ -6,12 +6,17 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/) The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/). and this project adheres to [Semantic Versioning](http://semver.org/).
## [unreleased] ## [0.2.3]
### Added ### Added
- Basic API for EDAC functionality - Basic API for EDAC functionality
- PWM implementation and example - PWM implementation and example
- API to perform peripheral resets
### Changed
- Improved Timer API. It is now possible to simply use `new` on `CountDownTimer`
## [0.2.2] ## [0.2.2]

View File

@ -1,6 +1,6 @@
[package] [package]
name = "va108xx-hal" name = "va108xx-hal"
version = "0.2.2" version = "0.2.3"
authors = ["Robin Mueller <robin.mueller.m@gmail.com>"] authors = ["Robin Mueller <robin.mueller.m@gmail.com>"]
edition = "2021" edition = "2021"
description = "HAL for the Vorago VA108xx family of microcontrollers" description = "HAL for the Vorago VA108xx family of microcontrollers"

View File

@ -139,7 +139,7 @@ fn main() -> ! {
} }
// Application logic // Application logic
let mut delay_tim = CountDownTimer::tim1(&mut dp.SYSCONFIG, 50.mhz().into(), dp.TIM1); let mut delay_tim = CountDownTimer::new(&mut dp.SYSCONFIG, 50.mhz().into(), dp.TIM1);
loop { loop {
match SPI_BUS_SEL { match SPI_BUS_SEL {
SpiBusSelect::SpiAPortA | SpiBusSelect::SpiAPortB => { SpiBusSelect::SpiAPortA | SpiBusSelect::SpiAPortB => {

View File

@ -163,7 +163,7 @@ fn main() -> ! {
delay.delay_ms(500); delay.delay_ms(500);
} }
let mut delay_timer = CountDownTimer::tim1(&mut dp.SYSCONFIG, 50.mhz().into(), dp.TIM1); let mut delay_timer = CountDownTimer::new(&mut dp.SYSCONFIG, 50.mhz().into(), dp.TIM1);
let mut pa0 = pinsa.pa0.into_push_pull_output(); let mut pa0 = pinsa.pa0.into_push_pull_output();
for _ in 0..5 { for _ in 0..5 {
led1.toggle().ok(); led1.toggle().ok();

View File

@ -72,7 +72,7 @@ fn main() -> ! {
interrupt::OC0, interrupt::OC0,
); );
let mut second_timer = let mut second_timer =
CountDownTimer::tim1(&mut dp.SYSCONFIG, get_sys_clock().unwrap(), dp.TIM1); CountDownTimer::new(&mut dp.SYSCONFIG, get_sys_clock().unwrap(), dp.TIM1);
second_timer.listen( second_timer.listen(
Event::TimeOut, Event::TimeOut,
&mut dp.SYSCONFIG, &mut dp.SYSCONFIG,

View File

@ -2,28 +2,14 @@
//! //!
//! This also includes functionality to enable the peripheral clocks //! This also includes functionality to enable the peripheral clocks
use crate::time::Hertz; use crate::time::Hertz;
use crate::utility::PeripheralSelect;
use cortex_m::interrupt::{self, Mutex}; use cortex_m::interrupt::{self, Mutex};
use once_cell::unsync::OnceCell; use once_cell::unsync::OnceCell;
use va108xx::SYSCONFIG; use va108xx::SYSCONFIG;
static SYS_CLOCK: Mutex<OnceCell<Hertz>> = Mutex::new(OnceCell::new()); static SYS_CLOCK: Mutex<OnceCell<Hertz>> = Mutex::new(OnceCell::new());
#[derive(Copy, Clone, PartialEq)] pub type PeripheralClocks = PeripheralSelect;
pub enum PeripheralClocks {
PortA = 0,
PortB = 1,
Spi0 = 4,
Spi1 = 5,
Spi2 = 6,
Uart0 = 8,
Uart1 = 9,
I2c0 = 16,
I2c1 = 17,
Irqsel = 21,
Ioconfig = 22,
Utility = 23,
Gpio = 24,
}
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
pub enum FilterClkSel { pub enum FilterClkSel {

View File

@ -41,7 +41,7 @@ macro_rules! pwm_common_func {
#[inline] #[inline]
fn enable_pwm_a(&mut self) { fn enable_pwm_a(&mut self) {
self.reg self.reg
.get_reg_block() .reg()
.ctrl .ctrl
.modify(|_, w| unsafe { w.status_sel().bits(StatusSelPwm::PwmA as u8) }); .modify(|_, w| unsafe { w.status_sel().bits(StatusSelPwm::PwmA as u8) });
} }
@ -49,7 +49,7 @@ macro_rules! pwm_common_func {
#[inline] #[inline]
fn enable_pwm_b(&mut self) { fn enable_pwm_b(&mut self) {
self.reg self.reg
.get_reg_block() .reg()
.ctrl .ctrl
.modify(|_, w| unsafe { w.status_sel().bits(StatusSelPwm::PwmB as u8) }); .modify(|_, w| unsafe { w.status_sel().bits(StatusSelPwm::PwmB as u8) });
} }
@ -69,7 +69,7 @@ macro_rules! pwm_common_func {
self.pwm_base.current_rst_val = self.pwm_base.current_rst_val =
self.pwm_base.sys_clk.0 / self.pwm_base.current_period.0; self.pwm_base.sys_clk.0 / self.pwm_base.current_period.0;
self.reg self.reg
.get_reg_block() .reg()
.rst_value .rst_value
.write(|w| unsafe { w.bits(self.pwm_base.current_rst_val) }); .write(|w| unsafe { w.bits(self.pwm_base.current_rst_val) });
} }
@ -98,7 +98,7 @@ macro_rules! pwmb_func {
* self.pwm_base.current_lower_limit as u64) * self.pwm_base.current_lower_limit as u64)
/ DUTY_MAX as u64; / DUTY_MAX as u64;
self.reg self.reg
.get_reg_block() .reg()
.pwmb_value .pwmb_value
.write(|w| unsafe { w.bits(pwmb_val as u32) }); .write(|w| unsafe { w.bits(pwmb_val as u32) });
} }
@ -115,7 +115,7 @@ macro_rules! pwmb_func {
* self.pwm_base.current_duty as u64) * self.pwm_base.current_duty as u64)
/ DUTY_MAX as u64; / DUTY_MAX as u64;
self.reg self.reg
.get_reg_block() .reg()
.pwma_value() .pwma_value()
.write(|w| unsafe { w.bits(pwma_val as u32) }); .write(|w| unsafe { w.bits(pwma_val as u32) });
} }
@ -127,7 +127,7 @@ macro_rules! pwmb_func {
//================================================================================================== //==================================================================================================
pub struct PwmPin<PIN: TimPin, TIM: ValidTim, MODE = PWMA> { pub struct PwmPin<PIN: TimPin, TIM: ValidTim, MODE = PWMA> {
reg: TimRegister<PIN, TIM>, reg: TimAndPinRegister<PIN, TIM>,
pwm_base: PwmBase, pwm_base: PwmBase,
_mode: PhantomData<MODE>, _mode: PhantomData<MODE>,
} }
@ -151,7 +151,7 @@ where
current_rst_val: 0, current_rst_val: 0,
sys_clk: sys_clk.into(), sys_clk: sys_clk.into(),
}, },
reg: unsafe { TimRegister::new(vtp.0, vtp.1) }, reg: unsafe { TimAndPinRegister::new(vtp.0, vtp.1) },
_mode: PhantomData, _mode: PhantomData,
}; };
enable_peripheral_clock(sys_cfg, crate::clock::PeripheralClocks::Gpio); enable_peripheral_clock(sys_cfg, crate::clock::PeripheralClocks::Gpio);
@ -308,18 +308,12 @@ macro_rules! pwm_pin_impl {
() => { () => {
#[inline] #[inline]
fn disable(&mut self) { fn disable(&mut self) {
self.reg self.reg.reg().ctrl.modify(|_, w| w.enable().clear_bit());
.get_reg_block()
.ctrl
.modify(|_, w| w.enable().clear_bit());
} }
#[inline] #[inline]
fn enable(&mut self) { fn enable(&mut self) {
self.reg self.reg.reg().ctrl.modify(|_, w| w.enable().set_bit());
.get_reg_block()
.ctrl
.modify(|_, w| w.enable().set_bit());
} }
#[inline] #[inline]
@ -329,7 +323,7 @@ macro_rules! pwm_pin_impl {
* (DUTY_MAX as u64 - self.pwm_base.current_duty as u64)) * (DUTY_MAX as u64 - self.pwm_base.current_duty as u64))
/ DUTY_MAX as u64; / DUTY_MAX as u64;
self.reg self.reg
.get_reg_block() .reg()
.pwma_value() .pwma_value()
.write(|w| unsafe { w.bits(pwma_val as u32) }); .write(|w| unsafe { w.bits(pwma_val as u32) });
} }
@ -350,18 +344,12 @@ macro_rules! pwm_impl {
() => { () => {
#[inline] #[inline]
fn disable(&mut self, _channel: Self::Channel) { fn disable(&mut self, _channel: Self::Channel) {
self.reg self.reg.reg().ctrl.modify(|_, w| w.enable().clear_bit());
.get_reg_block()
.ctrl
.modify(|_, w| w.enable().clear_bit());
} }
#[inline] #[inline]
fn enable(&mut self, _channel: Self::Channel) { fn enable(&mut self, _channel: Self::Channel) {
self.reg self.reg.reg().ctrl.modify(|_, w| w.enable().set_bit());
.get_reg_block()
.ctrl
.modify(|_, w| w.enable().set_bit());
} }
#[inline] #[inline]
@ -376,7 +364,7 @@ macro_rules! pwm_impl {
* (DUTY_MAX as u64 - self.pwm_base.current_duty as u64)) * (DUTY_MAX as u64 - self.pwm_base.current_duty as u64))
/ DUTY_MAX as u64; / DUTY_MAX as u64;
self.reg self.reg
.get_reg_block() .reg()
.pwma_value() .pwma_value()
.write(|w| unsafe { w.bits(pwma_val as u32) }); .write(|w| unsafe { w.bits(pwma_val as u32) });
} }
@ -393,7 +381,7 @@ macro_rules! pwm_impl {
} }
self.pwm_base.current_rst_val = self.pwm_base.current_rst_val =
self.pwm_base.sys_clk.0 / self.pwm_base.current_period.0; self.pwm_base.sys_clk.0 / self.pwm_base.current_period.0;
let reg_block = self.reg.get_reg_block(); let reg_block = self.reg.reg();
reg_block reg_block
.rst_value .rst_value
.write(|w| unsafe { w.bits(self.pwm_base.current_rst_val) }); .write(|w| unsafe { w.bits(self.pwm_base.current_rst_val) });

View File

@ -11,7 +11,10 @@ use crate::{
PA9, PB0, PB1, PB10, PB11, PB12, PB13, PB14, PB15, PB16, PB17, PB18, PB19, PB2, PB20, PB21, PA9, PB0, PB1, PB10, PB11, PB12, PB13, PB14, PB15, PB16, PB17, PB18, PB19, PB2, PB20, PB21,
PB22, PB23, PB3, PB4, PB5, PB6, PB22, PB23, PB3, PB4, PB5, PB6,
}, },
pac::{self, tim0}, pac::{
self, tim0, TIM0, TIM1, TIM10, TIM11, TIM12, TIM13, TIM14, TIM15, TIM16, TIM17, TIM18,
TIM19, TIM2, TIM20, TIM21, TIM22, TIM23, TIM3, TIM4, TIM5, TIM6, TIM7, TIM8, TIM9,
},
prelude::*, prelude::*,
private::Sealed, private::Sealed,
time::Hertz, time::Hertz,
@ -161,7 +164,7 @@ pin_and_tim!(PB1, AltFunc3, 1, TIM1);
pin_and_tim!(PB0, AltFunc3, 0, TIM0); pin_and_tim!(PB0, AltFunc3, 0, TIM0);
//================================================================================================== //==================================================================================================
// Register Interface // Register Interface for TIM registers and TIM pins
//================================================================================================== //==================================================================================================
pub type TimRegBlock = tim0::RegisterBlock; pub type TimRegBlock = tim0::RegisterBlock;
@ -173,20 +176,19 @@ pub type TimRegBlock = tim0::RegisterBlock;
/// ///
/// # Safety /// # Safety
/// ///
/// Users should only implement the [`id`] function. No default function /// Users should only implement the [`tim_id`] function. No default function
/// implementations should be overridden. The implementing type must also have /// implementations should be overridden. The implementing type must also have
/// "control" over the corresponding pin ID, i.e. it must guarantee that a each /// "control" over the corresponding pin ID, i.e. it must guarantee that a each
/// pin ID is a singleton. /// pin ID is a singleton.
pub(super) unsafe trait TimRegInterface { pub(super) unsafe trait TimRegInterface {
fn tim_id(&self) -> u8; fn tim_id(&self) -> u8;
fn pin_id(&self) -> DynPinId;
const PORT_BASE: *const tim0::RegisterBlock = TIM0::ptr() as *const _; const PORT_BASE: *const tim0::RegisterBlock = TIM0::ptr() as *const _;
/// All 24 TIM blocks are identical. This helper functions returns the correct /// All 24 TIM blocks are identical. This helper functions returns the correct
/// memory mapped peripheral depending on the TIM ID. /// memory mapped peripheral depending on the TIM ID.
#[inline(always)] #[inline(always)]
fn get_reg_block(&self) -> &TimRegBlock { fn reg(&self) -> &TimRegBlock {
unsafe { &*Self::PORT_BASE.offset(self.tim_id() as isize) } unsafe { &*Self::PORT_BASE.offset(self.tim_id() as isize) }
} }
@ -194,24 +196,85 @@ pub(super) unsafe trait TimRegInterface {
fn mask_32(&self) -> u32 { fn mask_32(&self) -> u32 {
1 << self.tim_id() 1 << self.tim_id()
} }
/// Clear the reset bit of the TIM, holding it in reset
///
/// # Safety
///
/// Only the bit related to the corresponding TIM peripheral is modified
#[inline]
fn clear_tim_reset_bit(&self) {
unsafe {
va108xx::Peripherals::steal()
.SYSCONFIG
.tim_reset
.modify(|r, w| w.bits(r.bits() & !self.mask_32()))
}
}
#[inline]
fn set_tim_reset_bit(&self) {
unsafe {
va108xx::Peripherals::steal()
.SYSCONFIG
.tim_reset
.modify(|r, w| w.bits(r.bits() | self.mask_32()))
}
}
}
/// Register interface.
///
/// This interface provides an interface for TIM pins to access their corresponding
/// configuration
///
/// # Safety
///
/// Users should only implement the [`pin_id`] function. No default function
/// implementations should be overridden. The implementing type must also have
/// "control" over the corresponding pin ID, i.e. it must guarantee that a each
/// pin ID is a singleton.
pub(super) unsafe trait TimPinInterface {
fn pin_id(&self) -> DynPinId;
} }
/// Provide a safe register interface for [`ValidTimAndPin`]s /// Provide a safe register interface for [`ValidTimAndPin`]s
/// ///
/// This `struct` takes ownership of a [`ValidTimAndPin`] and provides an API to /// This `struct` takes ownership of a [`ValidTimAndPin`] and provides an API to
/// access the corresponding registers. /// access the corresponding registers.
pub(super) struct TimRegister<PIN: TimPin, TIM: ValidTim> { pub(super) struct TimAndPinRegister<PIN: TimPin, TIM: ValidTim> {
pin: PIN, pin: PIN,
tim: TIM, tim: TIM,
} }
impl<PIN: TimPin, TIM: ValidTim> TimRegister<PIN, TIM> pub(super) struct TimRegister<TIM: ValidTim> {
tim: TIM,
}
impl<TIM: ValidTim> TimRegister<TIM> {
#[inline]
pub(super) unsafe fn new(tim: TIM) -> Self {
TimRegister { tim }
}
pub(super) fn release(self) -> TIM {
self.tim
}
}
unsafe impl<TIM: ValidTim> TimRegInterface for TimRegister<TIM> {
fn tim_id(&self) -> u8 {
TIM::TIM_ID
}
}
impl<PIN: TimPin, TIM: ValidTim> TimAndPinRegister<PIN, TIM>
where where
(PIN, TIM): ValidTimAndPin<PIN, TIM>, (PIN, TIM): ValidTimAndPin<PIN, TIM>,
{ {
#[inline] #[inline]
pub(super) unsafe fn new(pin: PIN, tim: TIM) -> Self { pub(super) unsafe fn new(pin: PIN, tim: TIM) -> Self {
TimRegister { pin, tim } TimAndPinRegister { pin, tim }
} }
pub(super) fn release(self) -> (PIN, TIM) { pub(super) fn release(self) -> (PIN, TIM) {
@ -219,12 +282,14 @@ where
} }
} }
unsafe impl<PIN: TimPin, TIM: ValidTim> TimRegInterface for TimRegister<PIN, TIM> { unsafe impl<PIN: TimPin, TIM: ValidTim> TimRegInterface for TimAndPinRegister<PIN, TIM> {
#[inline(always)] #[inline(always)]
fn tim_id(&self) -> u8 { fn tim_id(&self) -> u8 {
TIM::TIM_ID TIM::TIM_ID
} }
}
unsafe impl<PIN: TimPin, TIM: ValidTim> TimPinInterface for TimAndPinRegister<PIN, TIM> {
#[inline(always)] #[inline(always)]
fn pin_id(&self) -> DynPinId { fn pin_id(&self) -> DynPinId {
PIN::DYN PIN::DYN
@ -236,8 +301,8 @@ pub(super) struct TimDynRegister {
pin_id: DynPinId, pin_id: DynPinId,
} }
impl<PIN: TimPin, TIM: ValidTim> From<TimRegister<PIN, TIM>> for TimDynRegister { impl<PIN: TimPin, TIM: ValidTim> From<TimAndPinRegister<PIN, TIM>> for TimDynRegister {
fn from(_reg: TimRegister<PIN, TIM>) -> Self { fn from(_reg: TimAndPinRegister<PIN, TIM>) -> Self {
Self { Self {
tim_id: TIM::TIM_ID, tim_id: TIM::TIM_ID,
pin_id: PIN::DYN, pin_id: PIN::DYN,
@ -250,7 +315,9 @@ unsafe impl TimRegInterface for TimDynRegister {
fn tim_id(&self) -> u8 { fn tim_id(&self) -> u8 {
self.tim_id self.tim_id
} }
}
unsafe impl TimPinInterface for TimDynRegister {
#[inline(always)] #[inline(always)]
fn pin_id(&self) -> DynPinId { fn pin_id(&self) -> DynPinId {
self.pin_id self.pin_id
@ -262,8 +329,8 @@ unsafe impl TimRegInterface for TimDynRegister {
//================================================================================================== //==================================================================================================
/// Hardware timers /// Hardware timers
pub struct CountDownTimer<TIM> { pub struct CountDownTimer<TIM: ValidTim> {
tim: TIM, tim: TimRegister<TIM>,
curr_freq: Hertz, curr_freq: Hertz,
sys_clk: Hertz, sys_clk: Hertz,
rst_val: u32, rst_val: u32,
@ -277,201 +344,201 @@ fn enable_tim_clk(syscfg: &mut SYSCONFIG, idx: u8) {
.modify(|r, w| unsafe { w.bits(r.bits() | (1 << idx)) }); .modify(|r, w| unsafe { w.bits(r.bits() | (1 << idx)) });
} }
macro_rules! timers { unsafe impl<TIM: ValidTim> TimRegInterface for CountDownTimer<TIM> {
($($TIM:ident: ($tim:ident, $i:expr),)+) => { fn tim_id(&self) -> u8 {
$( TIM::TIM_ID
use crate::pac::$TIM; }
}
impl CountDownTimer<$TIM> { impl<TIM: ValidTim> CountDownTimer<TIM> {
// XXX(why not name this `new`?) bummer: constructors need to have different names /// Configures a TIM peripheral as a periodic count down timer
// even if the `$TIM` are non overlapping (compare to the `free` function below pub fn new(syscfg: &mut SYSCONFIG, sys_clk: Hertz, tim: TIM) -> Self {
// which just works) enable_tim_clk(syscfg, TIM::TIM_ID);
/// Configures a TIM peripheral as a periodic count down timer let cd_timer = CountDownTimer {
pub fn $tim( tim: unsafe { TimRegister::new(tim) },
syscfg: &mut SYSCONFIG, sys_clk: Hertz, tim: $TIM sys_clk,
) -> Self { rst_val: 0,
enable_tim_clk(syscfg, $i); curr_freq: 0.hz(),
tim.ctrl.modify(|_, w| w.enable().set_bit()); listening: false,
CountDownTimer { last_cnt: 0,
tim, };
sys_clk, cd_timer.tim.reg().ctrl.modify(|_, w| w.enable().set_bit());
rst_val: 0, cd_timer
curr_freq: 0.hz(), }
listening: false,
last_cnt: 0,
}
}
/// Listen for events. This also actives the IRQ in the IRQSEL register /// Listen for events. This also actives the IRQ in the IRQSEL register
/// for the provided interrupt. It also actives the peripheral clock for /// for the provided interrupt. It also actives the peripheral clock for
/// IRQSEL /// IRQSEL
pub fn listen( pub fn listen(
&mut self, &mut self,
event: Event, event: Event,
syscfg: &mut SYSCONFIG, syscfg: &mut SYSCONFIG,
irqsel: &mut IRQSEL, irqsel: &mut IRQSEL,
interrupt: Interrupt, interrupt: Interrupt,
) { ) {
match event { match event {
Event::TimeOut => { Event::TimeOut => {
enable_peripheral_clock(syscfg, PeripheralClocks::Irqsel); enable_peripheral_clock(syscfg, PeripheralClocks::Irqsel);
irqsel.tim[$i].write(|w| unsafe { w.bits(interrupt as u32) }); irqsel.tim[TIM::TIM_ID as usize].write(|w| unsafe { w.bits(interrupt as u32) });
self.tim.ctrl.modify(|_, w| w.irq_enb().set_bit()); self.tim.reg().ctrl.modify(|_, w| w.irq_enb().set_bit());
self.listening = true; self.listening = true;
}
}
}
pub fn unlisten(
&mut self, event: Event, syscfg: &mut SYSCONFIG, irqsel: &mut IRQSEL
) {
match event {
Event::TimeOut => {
enable_peripheral_clock(syscfg, PeripheralClocks::Irqsel);
irqsel.tim[$i].write(|w| unsafe { w.bits(IRQ_DST_NONE) });
self.tim.ctrl.modify(|_, w| w.irq_enb().clear_bit());
self.listening = false;
}
}
}
pub fn release(self, syscfg: &mut SYSCONFIG) -> $TIM {
self.tim.ctrl.write(|w| w.enable().clear_bit());
syscfg
.tim_clk_enable
.modify(|r, w| unsafe { w.bits(r.bits() & !(1 << $i)) });
self.tim
}
pub fn auto_disable(self, enable: bool) -> Self {
if enable {
self.tim.ctrl.modify(|_, w| w.auto_disable().set_bit());
} else {
self.tim.ctrl.modify(|_, w| w.auto_disable().clear_bit());
}
self
}
pub fn auto_deactivate(self, enable: bool) -> Self {
if enable {
self.tim.ctrl.modify(|_, w| w.auto_deactivate().set_bit());
} else {
self.tim.ctrl.modify(|_, w| w.auto_deactivate().clear_bit());
}
self
}
pub fn curr_freq(&self) -> Hertz {
self.curr_freq
}
pub fn listening(&self) -> bool {
self.listening
}
} }
}
}
/// CountDown implementation for TIMx pub fn unlisten(&mut self, event: Event, syscfg: &mut SYSCONFIG, irqsel: &mut IRQSEL) {
impl CountDown for CountDownTimer<$TIM> { match event {
type Time = Hertz; Event::TimeOut => {
enable_peripheral_clock(syscfg, PeripheralClocks::Irqsel);
irqsel.tim[TIM::TIM_ID as usize].write(|w| unsafe { w.bits(IRQ_DST_NONE) });
self.tim.reg().ctrl.modify(|_, w| w.irq_enb().clear_bit());
self.listening = false;
}
}
}
fn start<T>(&mut self, timeout: T) pub fn release(self, syscfg: &mut SYSCONFIG) -> TIM {
where self.tim.reg().ctrl.write(|w| w.enable().clear_bit());
T: Into<Hertz>, syscfg
{ .tim_clk_enable
self.tim.ctrl.modify(|_, w| w.enable().clear_bit()); .modify(|r, w| unsafe { w.bits(r.bits() & !(1 << TIM::TIM_ID)) });
self.curr_freq = timeout.into(); self.tim.release()
self.rst_val = self.sys_clk.0 / self.curr_freq.0; }
unsafe {
self.tim.rst_value.write(|w| w.bits(self.rst_val));
self.tim.cnt_value.write(|w| w.bits(self.rst_val));
}
self.tim.ctrl.modify(|_, w| w.enable().set_bit());
}
/// Return `Ok` if the timer has wrapped. Peripheral will automatically clear the pub fn auto_disable(self, enable: bool) -> Self {
/// flag and restart the time if configured correctly if enable {
fn wait(&mut self) -> nb::Result<(), Void> { self.tim
let cnt = self.tim.cnt_value.read().bits(); .reg()
if cnt > self.last_cnt { .ctrl
self.last_cnt = self.rst_val; .modify(|_, w| w.auto_disable().set_bit());
Ok(()) } else {
} else if cnt == 0 { self.tim
self.last_cnt = self.rst_val; .reg()
Ok(()) .ctrl
} else { .modify(|_, w| w.auto_disable().clear_bit());
self.last_cnt = cnt; }
Err(nb::Error::WouldBlock) self
} }
}
}
impl Periodic for CountDownTimer<$TIM> {} pub fn auto_deactivate(self, enable: bool) -> Self {
if enable {
self.tim
.reg()
.ctrl
.modify(|_, w| w.auto_deactivate().set_bit());
} else {
self.tim
.reg()
.ctrl
.modify(|_, w| w.auto_deactivate().clear_bit());
}
self
}
impl Cancel for CountDownTimer<$TIM> { pub fn curr_freq(&self) -> Hertz {
type Error = TimerErrors; self.curr_freq
fn cancel(&mut self) -> Result<(), Self::Error> { }
if !self.tim.ctrl.read().enable().bit_is_set() {
return Err(TimerErrors::Canceled);
}
self.tim.ctrl.write(|w| w.enable().clear_bit());
Ok(())
}
}
/// Delay for microseconds. pub fn listening(&self) -> bool {
/// self.listening
/// For delays less than 100 us, an assembly delay will be used. }
/// For larger delays, the timer peripheral will be used. }
/// Please note that the delay using the peripheral might not
/// work properly in debug mode.
impl delay::DelayUs<u32> for CountDownTimer<$TIM> {
fn delay_us(&mut self, us: u32) {
if(us < 100) {
cortex_m::asm::delay(us * (self.sys_clk.0 / 2_000_000));
} else {
// Configuring the peripheral for higher frequencies is unstable
self.start(1000.khz());
// The subtracted value is an empirical value measures by using tests with
// an oscilloscope.
for _ in 0..us - 7 {
nb::block!(self.wait()).unwrap();
}
}
}
}
/// Forwards call to u32 variant of delay
impl delay::DelayUs<u16> for CountDownTimer<$TIM> {
fn delay_us(&mut self, us: u16) {
self.delay_us(u32::from(us));
}
}
/// Forwards call to u32 variant of delay
impl delay::DelayUs<u8> for CountDownTimer<$TIM> {
fn delay_us(&mut self, us: u8) {
self.delay_us(u32::from(us));
}
}
impl delay::DelayMs<u32> for CountDownTimer<$TIM> { /// CountDown implementation for TIMx
fn delay_ms(&mut self, ms: u32) { impl<TIM: ValidTim> CountDown for CountDownTimer<TIM> {
self.start(1000.hz()); type Time = Hertz;
for _ in 0..ms {
nb::block!(self.wait()).unwrap();
}
}
}
impl delay::DelayMs<u16> for CountDownTimer<$TIM> {
fn delay_ms(&mut self, ms: u16) {
self.delay_ms(u32::from(ms));
}
}
impl embedded_hal::blocking::delay::DelayMs<u8> for CountDownTimer<$TIM> {
fn delay_ms(&mut self, ms: u8) {
self.delay_ms(u32::from(ms));
}
}
)+ fn start<T>(&mut self, timeout: T)
where
T: Into<Hertz>,
{
self.tim.reg().ctrl.modify(|_, w| w.enable().clear_bit());
self.curr_freq = timeout.into();
self.rst_val = self.sys_clk.0 / self.curr_freq.0;
unsafe {
self.tim.reg().rst_value.write(|w| w.bits(self.rst_val));
self.tim.reg().cnt_value.write(|w| w.bits(self.rst_val));
}
self.tim.reg().ctrl.modify(|_, w| w.enable().set_bit());
}
/// Return `Ok` if the timer has wrapped. Peripheral will automatically clear the
/// flag and restart the time if configured correctly
fn wait(&mut self) -> nb::Result<(), Void> {
let cnt = self.tim.reg().cnt_value.read().bits();
if (cnt > self.last_cnt) || cnt == 0 {
self.last_cnt = self.rst_val;
Ok(())
} else {
self.last_cnt = cnt;
Err(nb::Error::WouldBlock)
}
}
}
impl<TIM: ValidTim> Periodic for CountDownTimer<TIM> {}
impl<TIM: ValidTim> Cancel for CountDownTimer<TIM> {
type Error = TimerErrors;
fn cancel(&mut self) -> Result<(), Self::Error> {
if !self.tim.reg().ctrl.read().enable().bit_is_set() {
return Err(TimerErrors::Canceled);
}
self.tim.reg().ctrl.write(|w| w.enable().clear_bit());
Ok(())
}
}
/// Delay for microseconds.
///
/// For delays less than 100 us, an assembly delay will be used.
/// For larger delays, the timer peripheral will be used.
/// Please note that the delay using the peripheral might not
/// work properly in debug mode.
impl<TIM: ValidTim> delay::DelayUs<u32> for CountDownTimer<TIM> {
fn delay_us(&mut self, us: u32) {
if us < 100 {
cortex_m::asm::delay(us * (self.sys_clk.0 / 2_000_000));
} else {
// Configuring the peripheral for higher frequencies is unstable
self.start(1000.khz());
// The subtracted value is an empirical value measures by using tests with
// an oscilloscope.
for _ in 0..us - 7 {
nb::block!(self.wait()).unwrap();
}
}
}
}
/// Forwards call to u32 variant of delay
impl<TIM: ValidTim> delay::DelayUs<u16> for CountDownTimer<TIM> {
fn delay_us(&mut self, us: u16) {
self.delay_us(u32::from(us));
}
}
/// Forwards call to u32 variant of delay
impl<TIM: ValidTim> delay::DelayUs<u8> for CountDownTimer<TIM> {
fn delay_us(&mut self, us: u8) {
self.delay_us(u32::from(us));
}
}
impl<TIM: ValidTim> delay::DelayMs<u32> for CountDownTimer<TIM> {
fn delay_ms(&mut self, ms: u32) {
self.start(1000.hz());
for _ in 0..ms {
nb::block!(self.wait()).unwrap();
}
}
}
impl<TIM: ValidTim> delay::DelayMs<u16> for CountDownTimer<TIM> {
fn delay_ms(&mut self, ms: u16) {
self.delay_ms(u32::from(ms));
}
}
impl<TIM: ValidTim> embedded_hal::blocking::delay::DelayMs<u8> for CountDownTimer<TIM> {
fn delay_ms(&mut self, ms: u8) {
self.delay_ms(u32::from(ms));
} }
} }
@ -484,7 +551,7 @@ pub fn set_up_ms_timer(
tim0: TIM0, tim0: TIM0,
irq: pac::Interrupt, irq: pac::Interrupt,
) -> CountDownTimer<TIM0> { ) -> CountDownTimer<TIM0> {
let mut ms_timer = CountDownTimer::tim0(syscfg, sys_clk, tim0); let mut ms_timer = CountDownTimer::new(syscfg, sys_clk, tim0);
ms_timer.listen(timer::Event::TimeOut, syscfg, irqsel, irq); ms_timer.listen(timer::Event::TimeOut, syscfg, irqsel, irq);
ms_timer.start(1000.hz()); ms_timer.start(1000.hz());
ms_timer ms_timer
@ -505,33 +572,6 @@ pub fn get_ms_ticks() -> u32 {
cortex_m::interrupt::free(|cs| MS_COUNTER.borrow(cs).get()) cortex_m::interrupt::free(|cs| MS_COUNTER.borrow(cs).get())
} }
timers! {
TIM0: (tim0, 0),
TIM1: (tim1, 1),
TIM2: (tim2, 2),
TIM3: (tim3, 3),
TIM4: (tim4, 4),
TIM5: (tim5, 5),
TIM6: (tim6, 6),
TIM7: (tim7, 7),
TIM8: (tim8, 8),
TIM9: (tim9, 9),
TIM10: (tim10, 10),
TIM11: (tim11, 11),
TIM12: (tim12, 12),
TIM13: (tim13, 13),
TIM14: (tim14, 14),
TIM15: (tim15, 15),
TIM16: (tim16, 16),
TIM17: (tim17, 17),
TIM18: (tim18, 18),
TIM19: (tim19, 19),
TIM20: (tim20, 20),
TIM21: (tim21, 21),
TIM22: (tim22, 22),
TIM23: (tim23, 23),
}
//================================================================================================== //==================================================================================================
// Delay implementations // Delay implementations
//================================================================================================== //==================================================================================================

View File

@ -10,6 +10,23 @@ pub enum UtilityError {
InvalidCounterResetVal, InvalidCounterResetVal,
} }
#[derive(Copy, Clone, PartialEq)]
pub enum PeripheralSelect {
PortA = 0,
PortB = 1,
Spi0 = 4,
Spi1 = 5,
Spi2 = 6,
Uart0 = 8,
Uart1 = 9,
I2c0 = 16,
I2c1 = 17,
Irqsel = 21,
Ioconfig = 22,
Utility = 23,
Gpio = 24,
}
/// Enable scrubbing for the ROM /// Enable scrubbing for the ROM
/// ///
/// Returns [`UtilityError::InvalidCounterResetVal`] if the scrub rate is 0 /// Returns [`UtilityError::InvalidCounterResetVal`] if the scrub rate is 0
@ -41,3 +58,17 @@ pub fn enable_ram_scrubbing(syscfg: &mut SYSCONFIG, scrub_rate: u32) -> Result<(
pub fn disable_ram_scrubbing(syscfg: &mut SYSCONFIG) { pub fn disable_ram_scrubbing(syscfg: &mut SYSCONFIG) {
syscfg.ram_scrub.write(|w| unsafe { w.bits(0) }) syscfg.ram_scrub.write(|w| unsafe { w.bits(0) })
} }
/// Clear the reset bit. This register is active low, so doing this will hold the peripheral
/// in a reset state
pub fn clear_reset_bit(syscfg: &mut SYSCONFIG, periph_sel: PeripheralSelect) {
syscfg
.peripheral_reset
.modify(|r, w| unsafe { w.bits(r.bits() & !(1 << periph_sel as u8)) });
}
pub fn set_reset_bit(syscfg: &mut SYSCONFIG, periph_sel: PeripheralSelect) {
syscfg
.peripheral_reset
.modify(|r, w| unsafe { w.bits(r.bits() | (1 << periph_sel as u8)) });
}