Merge #24
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:
commit
54e016f0e3
@ -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]
|
||||||
|
|
||||||
|
@ -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"
|
||||||
|
@ -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 => {
|
||||||
|
@ -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();
|
||||||
|
@ -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,
|
||||||
|
18
src/clock.rs
18
src/clock.rs
@ -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 {
|
||||||
|
40
src/pwm.rs
40
src/pwm.rs
@ -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) });
|
||||||
|
268
src/timer.rs
268
src/timer.rs
@ -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,29 +344,26 @@ 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
|
|
||||||
// even if the `$TIM` are non overlapping (compare to the `free` function below
|
|
||||||
// which just works)
|
|
||||||
/// Configures a TIM peripheral as a periodic count down timer
|
/// Configures a TIM peripheral as a periodic count down timer
|
||||||
pub fn $tim(
|
pub fn new(syscfg: &mut SYSCONFIG, sys_clk: Hertz, tim: TIM) -> Self {
|
||||||
syscfg: &mut SYSCONFIG, sys_clk: Hertz, tim: $TIM
|
enable_tim_clk(syscfg, TIM::TIM_ID);
|
||||||
) -> Self {
|
let cd_timer = CountDownTimer {
|
||||||
enable_tim_clk(syscfg, $i);
|
tim: unsafe { TimRegister::new(tim) },
|
||||||
tim.ctrl.modify(|_, w| w.enable().set_bit());
|
|
||||||
CountDownTimer {
|
|
||||||
tim,
|
|
||||||
sys_clk,
|
sys_clk,
|
||||||
rst_val: 0,
|
rst_val: 0,
|
||||||
curr_freq: 0.hz(),
|
curr_freq: 0.hz(),
|
||||||
listening: false,
|
listening: false,
|
||||||
last_cnt: 0,
|
last_cnt: 0,
|
||||||
}
|
};
|
||||||
|
cd_timer.tim.reg().ctrl.modify(|_, w| w.enable().set_bit());
|
||||||
|
cd_timer
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Listen for events. This also actives the IRQ in the IRQSEL register
|
/// Listen for events. This also actives the IRQ in the IRQSEL register
|
||||||
@ -315,48 +379,58 @@ macro_rules! timers {
|
|||||||
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(
|
pub fn unlisten(&mut self, event: Event, syscfg: &mut SYSCONFIG, irqsel: &mut IRQSEL) {
|
||||||
&mut self, event: Event, syscfg: &mut SYSCONFIG, irqsel: &mut IRQSEL
|
|
||||||
) {
|
|
||||||
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(IRQ_DST_NONE) });
|
irqsel.tim[TIM::TIM_ID as usize].write(|w| unsafe { w.bits(IRQ_DST_NONE) });
|
||||||
self.tim.ctrl.modify(|_, w| w.irq_enb().clear_bit());
|
self.tim.reg().ctrl.modify(|_, w| w.irq_enb().clear_bit());
|
||||||
self.listening = false;
|
self.listening = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn release(self, syscfg: &mut SYSCONFIG) -> $TIM {
|
pub fn release(self, syscfg: &mut SYSCONFIG) -> TIM {
|
||||||
self.tim.ctrl.write(|w| w.enable().clear_bit());
|
self.tim.reg().ctrl.write(|w| w.enable().clear_bit());
|
||||||
syscfg
|
syscfg
|
||||||
.tim_clk_enable
|
.tim_clk_enable
|
||||||
.modify(|r, w| unsafe { w.bits(r.bits() & !(1 << $i)) });
|
.modify(|r, w| unsafe { w.bits(r.bits() & !(1 << TIM::TIM_ID)) });
|
||||||
self.tim
|
self.tim.release()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn auto_disable(self, enable: bool) -> Self {
|
pub fn auto_disable(self, enable: bool) -> Self {
|
||||||
if enable {
|
if enable {
|
||||||
self.tim.ctrl.modify(|_, w| w.auto_disable().set_bit());
|
self.tim
|
||||||
|
.reg()
|
||||||
|
.ctrl
|
||||||
|
.modify(|_, w| w.auto_disable().set_bit());
|
||||||
} else {
|
} else {
|
||||||
self.tim.ctrl.modify(|_, w| w.auto_disable().clear_bit());
|
self.tim
|
||||||
|
.reg()
|
||||||
|
.ctrl
|
||||||
|
.modify(|_, w| w.auto_disable().clear_bit());
|
||||||
}
|
}
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn auto_deactivate(self, enable: bool) -> Self {
|
pub fn auto_deactivate(self, enable: bool) -> Self {
|
||||||
if enable {
|
if enable {
|
||||||
self.tim.ctrl.modify(|_, w| w.auto_deactivate().set_bit());
|
self.tim
|
||||||
|
.reg()
|
||||||
|
.ctrl
|
||||||
|
.modify(|_, w| w.auto_deactivate().set_bit());
|
||||||
} else {
|
} else {
|
||||||
self.tim.ctrl.modify(|_, w| w.auto_deactivate().clear_bit());
|
self.tim
|
||||||
|
.reg()
|
||||||
|
.ctrl
|
||||||
|
.modify(|_, w| w.auto_deactivate().clear_bit());
|
||||||
}
|
}
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
@ -368,34 +442,31 @@ macro_rules! timers {
|
|||||||
pub fn listening(&self) -> bool {
|
pub fn listening(&self) -> bool {
|
||||||
self.listening
|
self.listening
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// CountDown implementation for TIMx
|
/// CountDown implementation for TIMx
|
||||||
impl CountDown for CountDownTimer<$TIM> {
|
impl<TIM: ValidTim> CountDown for CountDownTimer<TIM> {
|
||||||
type Time = Hertz;
|
type Time = Hertz;
|
||||||
|
|
||||||
fn start<T>(&mut self, timeout: T)
|
fn start<T>(&mut self, timeout: T)
|
||||||
where
|
where
|
||||||
T: Into<Hertz>,
|
T: Into<Hertz>,
|
||||||
{
|
{
|
||||||
self.tim.ctrl.modify(|_, w| w.enable().clear_bit());
|
self.tim.reg().ctrl.modify(|_, w| w.enable().clear_bit());
|
||||||
self.curr_freq = timeout.into();
|
self.curr_freq = timeout.into();
|
||||||
self.rst_val = self.sys_clk.0 / self.curr_freq.0;
|
self.rst_val = self.sys_clk.0 / self.curr_freq.0;
|
||||||
unsafe {
|
unsafe {
|
||||||
self.tim.rst_value.write(|w| w.bits(self.rst_val));
|
self.tim.reg().rst_value.write(|w| w.bits(self.rst_val));
|
||||||
self.tim.cnt_value.write(|w| w.bits(self.rst_val));
|
self.tim.reg().cnt_value.write(|w| w.bits(self.rst_val));
|
||||||
}
|
}
|
||||||
self.tim.ctrl.modify(|_, w| w.enable().set_bit());
|
self.tim.reg().ctrl.modify(|_, w| w.enable().set_bit());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return `Ok` if the timer has wrapped. Peripheral will automatically clear the
|
/// Return `Ok` if the timer has wrapped. Peripheral will automatically clear the
|
||||||
/// flag and restart the time if configured correctly
|
/// flag and restart the time if configured correctly
|
||||||
fn wait(&mut self) -> nb::Result<(), Void> {
|
fn wait(&mut self) -> nb::Result<(), Void> {
|
||||||
let cnt = self.tim.cnt_value.read().bits();
|
let cnt = self.tim.reg().cnt_value.read().bits();
|
||||||
if cnt > self.last_cnt {
|
if (cnt > self.last_cnt) || cnt == 0 {
|
||||||
self.last_cnt = self.rst_val;
|
|
||||||
Ok(())
|
|
||||||
} else if cnt == 0 {
|
|
||||||
self.last_cnt = self.rst_val;
|
self.last_cnt = self.rst_val;
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
@ -403,30 +474,30 @@ macro_rules! timers {
|
|||||||
Err(nb::Error::WouldBlock)
|
Err(nb::Error::WouldBlock)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Periodic for CountDownTimer<$TIM> {}
|
impl<TIM: ValidTim> Periodic for CountDownTimer<TIM> {}
|
||||||
|
|
||||||
impl Cancel for CountDownTimer<$TIM> {
|
impl<TIM: ValidTim> Cancel for CountDownTimer<TIM> {
|
||||||
type Error = TimerErrors;
|
type Error = TimerErrors;
|
||||||
fn cancel(&mut self) -> Result<(), Self::Error> {
|
fn cancel(&mut self) -> Result<(), Self::Error> {
|
||||||
if !self.tim.ctrl.read().enable().bit_is_set() {
|
if !self.tim.reg().ctrl.read().enable().bit_is_set() {
|
||||||
return Err(TimerErrors::Canceled);
|
return Err(TimerErrors::Canceled);
|
||||||
}
|
}
|
||||||
self.tim.ctrl.write(|w| w.enable().clear_bit());
|
self.tim.reg().ctrl.write(|w| w.enable().clear_bit());
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Delay for microseconds.
|
/// Delay for microseconds.
|
||||||
///
|
///
|
||||||
/// For delays less than 100 us, an assembly delay will be used.
|
/// For delays less than 100 us, an assembly delay will be used.
|
||||||
/// For larger delays, the timer peripheral will be used.
|
/// For larger delays, the timer peripheral will be used.
|
||||||
/// Please note that the delay using the peripheral might not
|
/// Please note that the delay using the peripheral might not
|
||||||
/// work properly in debug mode.
|
/// work properly in debug mode.
|
||||||
impl delay::DelayUs<u32> for CountDownTimer<$TIM> {
|
impl<TIM: ValidTim> delay::DelayUs<u32> for CountDownTimer<TIM> {
|
||||||
fn delay_us(&mut self, us: u32) {
|
fn delay_us(&mut self, us: u32) {
|
||||||
if(us < 100) {
|
if us < 100 {
|
||||||
cortex_m::asm::delay(us * (self.sys_clk.0 / 2_000_000));
|
cortex_m::asm::delay(us * (self.sys_clk.0 / 2_000_000));
|
||||||
} else {
|
} else {
|
||||||
// Configuring the peripheral for higher frequencies is unstable
|
// Configuring the peripheral for higher frequencies is unstable
|
||||||
@ -438,41 +509,37 @@ macro_rules! timers {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Forwards call to u32 variant of delay
|
/// Forwards call to u32 variant of delay
|
||||||
impl delay::DelayUs<u16> for CountDownTimer<$TIM> {
|
impl<TIM: ValidTim> delay::DelayUs<u16> for CountDownTimer<TIM> {
|
||||||
fn delay_us(&mut self, us: u16) {
|
fn delay_us(&mut self, us: u16) {
|
||||||
self.delay_us(u32::from(us));
|
self.delay_us(u32::from(us));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Forwards call to u32 variant of delay
|
/// Forwards call to u32 variant of delay
|
||||||
impl delay::DelayUs<u8> for CountDownTimer<$TIM> {
|
impl<TIM: ValidTim> delay::DelayUs<u8> for CountDownTimer<TIM> {
|
||||||
fn delay_us(&mut self, us: u8) {
|
fn delay_us(&mut self, us: u8) {
|
||||||
self.delay_us(u32::from(us));
|
self.delay_us(u32::from(us));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl delay::DelayMs<u32> for CountDownTimer<$TIM> {
|
impl<TIM: ValidTim> delay::DelayMs<u32> for CountDownTimer<TIM> {
|
||||||
fn delay_ms(&mut self, ms: u32) {
|
fn delay_ms(&mut self, ms: u32) {
|
||||||
self.start(1000.hz());
|
self.start(1000.hz());
|
||||||
for _ in 0..ms {
|
for _ in 0..ms {
|
||||||
nb::block!(self.wait()).unwrap();
|
nb::block!(self.wait()).unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl delay::DelayMs<u16> for CountDownTimer<$TIM> {
|
impl<TIM: ValidTim> delay::DelayMs<u16> for CountDownTimer<TIM> {
|
||||||
fn delay_ms(&mut self, ms: u16) {
|
fn delay_ms(&mut self, ms: u16) {
|
||||||
self.delay_ms(u32::from(ms));
|
self.delay_ms(u32::from(ms));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl embedded_hal::blocking::delay::DelayMs<u8> for CountDownTimer<$TIM> {
|
impl<TIM: ValidTim> embedded_hal::blocking::delay::DelayMs<u8> for CountDownTimer<TIM> {
|
||||||
fn delay_ms(&mut self, ms: u8) {
|
fn delay_ms(&mut self, ms: u8) {
|
||||||
self.delay_ms(u32::from(ms));
|
self.delay_ms(u32::from(ms));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
)+
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set up a millisecond timer on TIM0. Please note that you still need to unmask the related IRQ
|
// Set up a millisecond timer on TIM0. Please note that you still need to unmask the related IRQ
|
||||||
@ -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
|
||||||
//==================================================================================================
|
//==================================================================================================
|
||||||
|
@ -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)) });
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user