Add embassy example
All checks were successful
Rust/va416xx-rs/pipeline/pr-main This commit looks good

This commit is contained in:
2024-09-17 18:07:45 +02:00
parent ed175a03fc
commit a1a83700f8
25 changed files with 721 additions and 46 deletions

View File

@ -25,6 +25,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- Fixes for the SPI implementation where the clock divider values were not calculated
correctly
- Fixes for UART IRQ handler implementation
- Add new IRQ router initialization method `irq_router::enable_and_init_irq_router`. This method
also sets the initial values of some registers to 0 where the datasheet and the actual reset
value are inconsistent, which can lead to weird bugs like IRQs not being triggered properly.
## Added

View File

@ -12,6 +12,7 @@ categories = ["embedded", "no-std", "hardware-support"]
[dependencies]
cortex-m = { version = "0.7", features = ["critical-section-single-core"] }
critical-section = "1"
nb = "1"
paste = "1"
embedded-hal-nb = "1"

View File

@ -494,7 +494,7 @@ pub struct Clocks {
impl Clocks {
/// Returns the frequency of the HBO clock
pub fn hbo(&self) -> Hertz {
pub const fn hbo(&self) -> Hertz {
HBO_FREQ
}
@ -504,23 +504,23 @@ impl Clocks {
}
/// Returns system clock divied by 2.
pub fn apb1(&self) -> Hertz {
pub const fn apb1(&self) -> Hertz {
self.apb1
}
/// Returns system clock divied by 4.
pub fn apb2(&self) -> Hertz {
pub const fn apb2(&self) -> Hertz {
self.apb2
}
/// Returns the system (core) frequency
pub fn sysclk(&self) -> Hertz {
pub const fn sysclk(&self) -> Hertz {
self.sysclk
}
/// Returns the ADC clock frequency which has a separate divider.
#[cfg(not(feature = "va41628"))]
pub fn adc_clk(&self) -> Hertz {
pub const fn adc_clk(&self) -> Hertz {
self.adc_clk
}
}

View File

@ -0,0 +1,18 @@
use crate::{
clock::{PeripheralSelect, SyscfgExt},
pac,
};
pub fn enable_and_init_irq_router(sysconfig: &mut pac::Sysconfig, irq_router: &pac::IrqRouter) {
sysconfig.enable_peripheral_clock(PeripheralSelect::IrqRouter);
sysconfig.assert_periph_reset_for_two_cycles(PeripheralSelect::IrqRouter);
unsafe {
irq_router.dmasel0().write_with_zero(|w| w);
irq_router.dmasel1().write_with_zero(|w| w);
irq_router.dmasel2().write_with_zero(|w| w);
irq_router.dmasel3().write_with_zero(|w| w);
irq_router.adcsel().write_with_zero(|w| w);
irq_router.dacsel0().write_with_zero(|w| w);
irq_router.dacsel1().write_with_zero(|w| w);
}
}

View File

@ -1,3 +1,26 @@
//! This is the **H**ardware **A**bstraction **L**ayer (HAL) for the VA416xx MCU family.
//!
//! It is an additional hardware abstraction on top of the [peripheral access API](https://egit.irs.uni-stuttgart.de/rust/va416xx-rs/src/branch/main/va416xx).
//! It is the result of reading the datasheet for the device and encoding a type-safe layer over the
//! raw PAC. This crate also implements traits specified by the
//! [embedded-hal](https://github.com/rust-embedded/embedded-hal) project, making it compatible with
//! various drivers in the embedded rust ecosystem.
//! You have to enable one of the following device features to use this crate depending on
//! which chip you are using:
//! - `va41630`
//! - `va41629`
//! - `va41628`
//! - `va41620`
//!
//! When using this HAL and writing applications for the VA416xx family in general, it is strongly
//! recommended that you set up the clock properly, because the default internal HBO clock
//! is not very accurate. You can use the [crate::clock] module for this. If you are working
//! with interrupts, it is strongly recommended to set up the IRQ router with the
//! [crate::irq_router] module at the very least because that peripheral has confusing and/or
//! faulty register reset values which might leads to weird bugs and glitches.
#![no_std]
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
#[cfg(test)]
@ -22,6 +45,7 @@ pub mod dma;
pub mod edac;
pub mod gpio;
pub mod i2c;
pub mod irq_router;
pub mod nvm;
pub mod pwm;
pub mod spi;

View File

@ -5,7 +5,8 @@
//! - [Timer MS and Second Tick Example](https://github.com/us-irs/va416xx-rs/blob/main/examples/simple/examples/timer-ticks.rs)
use core::cell::Cell;
use cortex_m::interrupt::Mutex;
use cortex_m::asm;
use critical_section::Mutex;
use crate::clock::Clocks;
use crate::gpio::{
@ -169,6 +170,14 @@ macro_rules! tim_markers {
};
}
pub const fn const_clock<Tim: ValidTim + ?Sized>(_: &Tim, clocks: &Clocks) -> Hertz {
if Tim::TIM_ID <= 15 {
clocks.apb1()
} else {
clocks.apb2()
}
}
tim_markers!(
(pac::Tim0, 0, pac::Interrupt::TIM0),
(pac::Tim1, 1, pac::Interrupt::TIM1),
@ -328,19 +337,27 @@ valid_pin_and_tims!(
///
/// Only the bit related to the corresponding TIM peripheral is modified
#[inline]
fn assert_tim_reset(syscfg: &mut pac::Sysconfig, tim_id: u8) {
pub fn assert_tim_reset(syscfg: &mut pac::Sysconfig, tim_id: u8) {
syscfg
.tim_reset()
.modify(|r, w| unsafe { w.bits(r.bits() & !(1 << tim_id as u32)) })
}
#[inline]
fn deassert_tim_reset(syscfg: &mut pac::Sysconfig, tim_id: u8) {
pub fn deassert_tim_reset(syscfg: &mut pac::Sysconfig, tim_id: u8) {
syscfg
.tim_reset()
.modify(|r, w| unsafe { w.bits(r.bits() | (1 << tim_id as u32)) })
}
#[inline]
pub fn assert_tim_reset_for_two_cycles(syscfg: &mut pac::Sysconfig, tim_id: u8) {
assert_tim_reset(syscfg, tim_id);
asm::nop();
asm::nop();
deassert_tim_reset(syscfg, tim_id);
}
pub type TimRegBlock = pac::tim0::RegisterBlock;
/// Register interface.
@ -481,7 +498,7 @@ pub struct CountdownTimer<TIM: ValidTim> {
}
#[inline]
fn enable_tim_clk(syscfg: &mut pac::Sysconfig, idx: u8) {
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)) });
@ -579,9 +596,10 @@ impl<Tim: ValidTim> CountdownTimer<Tim> {
pub fn load(&mut self, timeout: impl Into<Hertz>) {
self.tim.reg().ctrl().modify(|_, w| w.enable().clear_bit());
self.curr_freq = timeout.into();
self.rst_val = self.clock.raw() / self.curr_freq.raw();
self.rst_val = (self.clock.raw() / self.curr_freq.raw()) - 1;
self.set_reload(self.rst_val);
self.set_count(0);
// Decrementing counter, to set the reset value.
self.set_count(self.rst_val);
}
#[inline(always)]
@ -601,7 +619,7 @@ impl<Tim: ValidTim> CountdownTimer<Tim> {
#[inline(always)]
pub fn enable(&mut self) {
self.tim.reg().ctrl().modify(|_, w| w.enable().set_bit());
self.tim.reg().enable().write(|w| unsafe { w.bits(1) });
}
#[inline(always)]
@ -778,7 +796,7 @@ pub fn set_up_ms_tick<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);
@ -787,7 +805,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())
}
pub struct DelayMs<Tim: ValidTim = pac::Tim0>(CountdownTimer<Tim>);