- Add embassy example - improve timer API - restructure examples
This commit is contained in:
@ -6,6 +6,11 @@ All notable changes to this project will be documented in this file.
|
||||
The format is based on [Keep a Changelog](http://keepachangelog.com/)
|
||||
and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
## [unreleased]
|
||||
|
||||
- Improves `CascardSource` handling and general API when chosing cascade sources.
|
||||
- Replaced `utility::unmask_irq` by `enable_interrupt` and `disable_interrupt` API.
|
||||
|
||||
## [v0.7.0] 2024-07-04
|
||||
|
||||
- Replace `uarta` and `uartb` `Uart` constructors by `new` constructor
|
||||
|
@ -19,7 +19,7 @@ embedded-hal-nb = "1"
|
||||
embedded-io = "0.6"
|
||||
fugit = "0.3"
|
||||
typenum = "1"
|
||||
defmt = { version = "0.3", optional = true }
|
||||
critical-section = "1"
|
||||
delegate = "0.12"
|
||||
|
||||
[dependencies.va108xx]
|
||||
@ -38,9 +38,14 @@ default-features = false
|
||||
version = "1.14"
|
||||
default-features = false
|
||||
|
||||
[dependencies.defmt]
|
||||
version = "0.3"
|
||||
optional = true
|
||||
|
||||
[features]
|
||||
default = ["rt"]
|
||||
rt = ["va108xx/rt"]
|
||||
defmt = ["dep:defmt", "fugit/defmt"]
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
all-features = true
|
||||
|
@ -15,7 +15,6 @@ pub mod time;
|
||||
pub mod timer;
|
||||
pub mod typelevel;
|
||||
pub mod uart;
|
||||
pub mod utility;
|
||||
|
||||
#[derive(Debug, Eq, Copy, Clone, PartialEq)]
|
||||
pub enum FunSel {
|
||||
@ -98,3 +97,21 @@ pub fn port_mux(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Enable a specific interrupt using the NVIC peripheral.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This function is `unsafe` because it can break mask-based critical sections.
|
||||
#[inline]
|
||||
pub unsafe fn enable_interrupt(irq: pac::Interrupt) {
|
||||
unsafe {
|
||||
cortex_m::peripheral::NVIC::unmask(irq);
|
||||
}
|
||||
}
|
||||
|
||||
/// Disable a specific interrupt using the NVIC peripheral.
|
||||
#[inline]
|
||||
pub fn disable_interrupt(irq: pac::Interrupt) {
|
||||
cortex_m::peripheral::NVIC::mask(irq);
|
||||
}
|
||||
|
@ -7,6 +7,7 @@
|
||||
pub use crate::IrqCfg;
|
||||
use crate::{
|
||||
clock::{enable_peripheral_clock, PeripheralClocks},
|
||||
enable_interrupt,
|
||||
gpio::{
|
||||
AltFunc1, AltFunc2, AltFunc3, DynPinId, Pin, PinId, PA0, PA1, PA10, PA11, PA12, PA13, PA14,
|
||||
PA15, PA2, PA24, PA25, PA26, PA27, PA28, PA29, PA3, PA30, PA31, PA4, PA5, PA6, PA7, PA8,
|
||||
@ -17,10 +18,9 @@ use crate::{
|
||||
time::Hertz,
|
||||
timer,
|
||||
typelevel::Sealed,
|
||||
utility::unmask_irq,
|
||||
};
|
||||
use core::cell::Cell;
|
||||
use cortex_m::interrupt::Mutex;
|
||||
use critical_section::Mutex;
|
||||
use fugit::RateExtU32;
|
||||
|
||||
const IRQ_DST_NONE: u32 = 0xffffffff;
|
||||
@ -72,25 +72,46 @@ pub enum CascadeSel {
|
||||
Csd2 = 2,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub struct InvalidCascadeSourceId;
|
||||
|
||||
/// The numbers are the base numbers for bundles like PORTA, PORTB or TIM
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
#[repr(u8)]
|
||||
pub enum CascadeSource {
|
||||
PortABase = 0,
|
||||
PortBBase = 32,
|
||||
TimBase = 64,
|
||||
PortA(u8),
|
||||
PortB(u8),
|
||||
Tim(u8),
|
||||
RamSbe = 96,
|
||||
RamMbe = 97,
|
||||
RomSbe = 98,
|
||||
RomMbe = 99,
|
||||
Txev = 100,
|
||||
ClockDividerBase = 120,
|
||||
ClockDivider(u8),
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub enum TimerErrors {
|
||||
Canceled,
|
||||
/// Invalid input for Cascade source
|
||||
InvalidCsdSourceInput,
|
||||
impl CascadeSource {
|
||||
fn id(&self) -> Result<u8, InvalidCascadeSourceId> {
|
||||
let port_check = |base: u8, id: u8, len: u8| {
|
||||
if id > len - 1 {
|
||||
return Err(InvalidCascadeSourceId);
|
||||
}
|
||||
Ok(base + id)
|
||||
};
|
||||
match self {
|
||||
CascadeSource::PortA(id) => port_check(0, *id, 32),
|
||||
CascadeSource::PortB(id) => port_check(32, *id, 32),
|
||||
CascadeSource::Tim(id) => port_check(64, *id, 24),
|
||||
CascadeSource::RamSbe => Ok(96),
|
||||
CascadeSource::RamMbe => Ok(97),
|
||||
CascadeSource::RomSbe => Ok(98),
|
||||
CascadeSource::RomMbe => Ok(99),
|
||||
CascadeSource::Txev => Ok(100),
|
||||
CascadeSource::ClockDivider(id) => port_check(120, *id, 8),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==================================================================================================
|
||||
@ -360,89 +381,26 @@ pub struct CountDownTimer<TIM: ValidTim> {
|
||||
listening: bool,
|
||||
}
|
||||
|
||||
fn enable_tim_clk(syscfg: &mut pac::Sysconfig, idx: u8) {
|
||||
#[inline(always)]
|
||||
pub fn enable_tim_clk(syscfg: &mut pac::Sysconfig, idx: u8) {
|
||||
syscfg
|
||||
.tim_clk_enable()
|
||||
.modify(|r, w| unsafe { w.bits(r.bits() | (1 << idx)) });
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn disable_tim_clk(syscfg: &mut pac::Sysconfig, idx: u8) {
|
||||
syscfg
|
||||
.tim_clk_enable()
|
||||
.modify(|r, w| unsafe { w.bits(r.bits() & !(1 << idx)) });
|
||||
}
|
||||
|
||||
unsafe impl<TIM: ValidTim> TimRegInterface for CountDownTimer<TIM> {
|
||||
fn tim_id(&self) -> u8 {
|
||||
TIM::TIM_ID
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! csd_sel {
|
||||
($func_name:ident, $csd_reg:ident) => {
|
||||
/// Configure the Cascade sources
|
||||
pub fn $func_name(
|
||||
&mut self,
|
||||
src: CascadeSource,
|
||||
id: Option<u8>,
|
||||
) -> Result<(), TimerErrors> {
|
||||
let mut id_num = 0;
|
||||
if let CascadeSource::PortABase
|
||||
| CascadeSource::PortBBase
|
||||
| CascadeSource::ClockDividerBase
|
||||
| CascadeSource::TimBase = src
|
||||
{
|
||||
if id.is_none() {
|
||||
return Err(TimerErrors::InvalidCsdSourceInput);
|
||||
}
|
||||
}
|
||||
if id.is_some() {
|
||||
id_num = id.unwrap();
|
||||
}
|
||||
match src {
|
||||
CascadeSource::PortABase => {
|
||||
if id_num > 55 {
|
||||
return Err(TimerErrors::InvalidCsdSourceInput);
|
||||
}
|
||||
self.tim.reg().$csd_reg().write(|w| unsafe {
|
||||
w.cassel().bits(CascadeSource::PortABase as u8 + id_num)
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
CascadeSource::PortBBase => {
|
||||
if id_num > 23 {
|
||||
return Err(TimerErrors::InvalidCsdSourceInput);
|
||||
}
|
||||
self.tim.reg().$csd_reg().write(|w| unsafe {
|
||||
w.cassel().bits(CascadeSource::PortBBase as u8 + id_num)
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
CascadeSource::TimBase => {
|
||||
if id_num > 23 {
|
||||
return Err(TimerErrors::InvalidCsdSourceInput);
|
||||
}
|
||||
self.tim.reg().$csd_reg().write(|w| unsafe {
|
||||
w.cassel().bits(CascadeSource::TimBase as u8 + id_num)
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
CascadeSource::ClockDividerBase => {
|
||||
if id_num > 7 {
|
||||
return Err(TimerErrors::InvalidCsdSourceInput);
|
||||
}
|
||||
self.tim.reg().cascade0().write(|w| unsafe {
|
||||
w.cassel()
|
||||
.bits(CascadeSource::ClockDividerBase as u8 + id_num)
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
_ => {
|
||||
self.tim
|
||||
.reg()
|
||||
.$csd_reg()
|
||||
.write(|w| unsafe { w.cassel().bits(src as u8) });
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl<TIM: ValidTim> CountDownTimer<TIM> {
|
||||
/// Configures a TIM peripheral as a periodic count down timer
|
||||
pub fn new(syscfg: &mut pac::Sysconfig, sys_clk: impl Into<Hertz>, tim: TIM) -> Self {
|
||||
@ -554,18 +512,18 @@ impl<TIM: ValidTim> CountDownTimer<TIM> {
|
||||
|
||||
#[inline(always)]
|
||||
pub fn enable(&mut self) {
|
||||
self.tim.reg().ctrl().modify(|_, w| w.enable().set_bit());
|
||||
if let Some(irq_cfg) = self.irq_cfg {
|
||||
self.enable_interrupt();
|
||||
if irq_cfg.enable {
|
||||
unmask_irq(irq_cfg.irq);
|
||||
unsafe { enable_interrupt(irq_cfg.irq) };
|
||||
}
|
||||
}
|
||||
self.tim.reg().enable().write(|w| unsafe { w.bits(1) });
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn disable(&mut self) {
|
||||
self.tim.reg().ctrl().modify(|_, w| w.enable().clear_bit());
|
||||
self.tim.reg().enable().write(|w| unsafe { w.bits(0) });
|
||||
}
|
||||
|
||||
/// Disable the counter, setting both enable and active bit to 0
|
||||
@ -619,9 +577,32 @@ impl<TIM: ValidTim> CountDownTimer<TIM> {
|
||||
});
|
||||
}
|
||||
|
||||
csd_sel!(cascade_0_source, cascade0);
|
||||
csd_sel!(cascade_1_source, cascade1);
|
||||
csd_sel!(cascade_2_source, cascade2);
|
||||
pub fn cascade_0_source(&mut self, src: CascadeSource) -> Result<(), InvalidCascadeSourceId> {
|
||||
let id = src.id()?;
|
||||
self.tim
|
||||
.reg()
|
||||
.cascade0()
|
||||
.write(|w| unsafe { w.cassel().bits(id) });
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn cascade_1_source(&mut self, src: CascadeSource) -> Result<(), InvalidCascadeSourceId> {
|
||||
let id = src.id()?;
|
||||
self.tim
|
||||
.reg()
|
||||
.cascade1()
|
||||
.write(|w| unsafe { w.cassel().bits(id) });
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn cascade_2_source(&mut self, src: CascadeSource) -> Result<(), InvalidCascadeSourceId> {
|
||||
let id = src.id()?;
|
||||
self.tim
|
||||
.reg()
|
||||
.cascade2()
|
||||
.write(|w| unsafe { w.cassel().bits(id) });
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn curr_freq(&self) -> Hertz {
|
||||
self.curr_freq
|
||||
@ -656,12 +637,13 @@ impl<TIM: ValidTim> CountDownTimer<TIM> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn cancel(&mut self) -> Result<(), TimerErrors> {
|
||||
/// Returns [false] if the timer was not active, and true otherwise.
|
||||
pub fn cancel(&mut self) -> bool {
|
||||
if !self.tim.reg().ctrl().read().enable().bit_is_set() {
|
||||
return Err(TimerErrors::Canceled);
|
||||
return false;
|
||||
}
|
||||
self.tim.reg().ctrl().write(|w| w.enable().clear_bit());
|
||||
Ok(())
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
@ -747,7 +729,7 @@ pub fn set_up_ms_delay_provider<TIM: ValidTim>(
|
||||
/// This function can be called in a specified interrupt handler to increment
|
||||
/// the MS counter
|
||||
pub fn default_ms_irq_handler() {
|
||||
cortex_m::interrupt::free(|cs| {
|
||||
critical_section::with(|cs| {
|
||||
let mut ms = MS_COUNTER.borrow(cs).get();
|
||||
ms += 1;
|
||||
MS_COUNTER.borrow(cs).set(ms);
|
||||
@ -756,7 +738,7 @@ pub fn default_ms_irq_handler() {
|
||||
|
||||
/// Get the current MS tick count
|
||||
pub fn get_ms_ticks() -> u32 {
|
||||
cortex_m::interrupt::free(|cs| MS_COUNTER.borrow(cs).get())
|
||||
critical_section::with(|cs| MS_COUNTER.borrow(cs).get())
|
||||
}
|
||||
|
||||
//==================================================================================================
|
||||
|
@ -3,7 +3,7 @@
|
||||
//! ## Examples
|
||||
//!
|
||||
//! - [UART simple example](https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/src/branch/main/examples/simple/examples/uart.rs)
|
||||
//! - [UART with IRQ and RTIC](https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/src/branch/main/examples/simple/examples/uart-irq-rtic.rs)
|
||||
//! - [UART with IRQ and RTIC](https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/src/branch/main/examples/rtic/bin/uart-rtic.rs)
|
||||
use core::{marker::PhantomData, ops::Deref};
|
||||
use embedded_hal_nb::serial::Read;
|
||||
use fugit::RateExtU32;
|
||||
@ -11,13 +11,13 @@ use fugit::RateExtU32;
|
||||
pub use crate::IrqCfg;
|
||||
use crate::{
|
||||
clock::{enable_peripheral_clock, PeripheralClocks},
|
||||
enable_interrupt,
|
||||
gpio::pin::{
|
||||
AltFunc1, AltFunc2, AltFunc3, Pin, PA16, PA17, PA18, PA19, PA2, PA26, PA27, PA3, PA30,
|
||||
PA31, PA8, PA9, PB18, PB19, PB20, PB21, PB22, PB23, PB6, PB7, PB8, PB9,
|
||||
},
|
||||
pac::{self, uarta as uart_base},
|
||||
time::Hertz,
|
||||
utility::unmask_irq,
|
||||
PeripheralSelect,
|
||||
};
|
||||
|
||||
@ -638,7 +638,7 @@ impl Instance for pac::Uartb {
|
||||
const PERIPH_SEL: PeripheralSelect = PeripheralSelect::Uart1;
|
||||
}
|
||||
|
||||
impl<UART: Instance> UartWithIrqBase<UART> {
|
||||
impl<Uart: Instance> UartWithIrqBase<Uart> {
|
||||
fn init(self, sys_cfg: Option<&mut pac::Sysconfig>, irq_sel: Option<&mut pac::Irqsel>) -> Self {
|
||||
if let Some(sys_cfg) = sys_cfg {
|
||||
enable_peripheral_clock(sys_cfg, PeripheralClocks::Irqsel)
|
||||
@ -646,7 +646,7 @@ impl<UART: Instance> UartWithIrqBase<UART> {
|
||||
if let Some(irq_sel) = irq_sel {
|
||||
if self.irq_info.irq_cfg.route {
|
||||
irq_sel
|
||||
.uart0(UART::IDX as usize)
|
||||
.uart0(Uart::IDX as usize)
|
||||
.write(|w| unsafe { w.bits(self.irq_info.irq_cfg.irq as u32) });
|
||||
}
|
||||
}
|
||||
@ -676,7 +676,9 @@ impl<UART: Instance> UartWithIrqBase<UART> {
|
||||
self.uart.enable_tx();
|
||||
self.enable_rx_irq_sources(enb_timeout_irq);
|
||||
if self.irq_info.irq_cfg.enable {
|
||||
unmask_irq(self.irq_info.irq_cfg.irq);
|
||||
unsafe {
|
||||
enable_interrupt(self.irq_info.irq_cfg.irq);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@ -839,7 +841,7 @@ impl<UART: Instance> UartWithIrqBase<UART> {
|
||||
self.irq_info.rx_len = 0;
|
||||
}
|
||||
|
||||
pub fn release(self) -> UART {
|
||||
pub fn release(self) -> Uart {
|
||||
self.uart.release()
|
||||
}
|
||||
}
|
||||
|
@ -1,16 +0,0 @@
|
||||
//! # API for utility functions like the Error Detection and Correction (EDAC) block
|
||||
//!
|
||||
//! Some more information about the recommended scrub rates can be found on the
|
||||
//! [Vorago White Paper website](https://www.voragotech.com/resources) in the
|
||||
//! application note AN1212
|
||||
use crate::pac;
|
||||
|
||||
/// Unmask and enable an IRQ with the given interrupt number
|
||||
///
|
||||
/// ## Safety
|
||||
///
|
||||
/// The unmask function can break mask-based critical sections
|
||||
#[inline]
|
||||
pub(crate) fn unmask_irq(irq: pac::Interrupt) {
|
||||
unsafe { cortex_m::peripheral::NVIC::unmask(irq) };
|
||||
}
|
Reference in New Issue
Block a user