//! # Embassy-rs support for the Vorago VA416xx MCU family //! //! This repository contains the [embassy-rs](https://github.com/embassy-rs/embassy) support for the //! VA416xx family. Currently, it contains the time driver to allow using embassy-rs. It uses the TIM //! peripherals provided by the VA416xx family for this purpose. //! //! ## Usage //! //! This library only exposes the [embassy::init] method which sets up the time driver. This //! function must be called once at the start of the application. //! //! This implementation requires two TIM peripherals provided by the VA108xx device. //! The user can freely specify the two used TIM peripheral by passing the concrete TIM instances //! into the [init] method. If the interrupt handlers are provided by the library, the ID of the //! used TIM peripherals has to match the ID of the passed timer peripherals. Currently, this //! can only be checked at run-time, and a run-time assertion will panic on the embassy //! initialization in case of a missmatch. //! //! The application also requires two interrupt handlers to handle the timekeeper and alarm //! interrupts. By default, this library will define the interrupt handler inside the library //! itself by using the `irq-tim14-tim15` feature flag. This library exposes three combinations: //! //! - `irq-tim14-tim15`: Uses [pac::Interrupt::TIM14] for alarm and [pac::Interrupt::TIM15] //! for timekeeper //! - `irq-tim13-tim14`: Uses [pac::Interrupt::TIM13] for alarm and [pac::Interrupt::TIM14] //! for timekeeper //! - `irq-tim22-tim23`: Uses [pac::Interrupt::TIM22] for alarm and [pac::Interrupt::TIM23] //! for timekeeper //! //! You can disable the default features and then specify one of the features above to use the //! documented combination of IRQs. It is also possible to specify custom IRQs by importing and //! using the [embassy_time_driver_irqs] macro to declare the IRQ handlers in the //! application code. If this is done, [embassy::init_with_custom_irqs] must be used //! method to pass the IRQ numbers to the library. //! //! ## Examples //! //! [embassy example projects](https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/src/branch/main/examples/embassy) #![no_std] #![cfg_attr(docsrs, feature(doc_auto_cfg))] use va416xx_hal::{ clock::Clocks, irq_router::enable_and_init_irq_router, pac::{self, interrupt}, timer::{TimMarker, TIM_IRQ_OFFSET}, }; use vorago_shared_periphs::embassy::time_driver; /// Macro to define the IRQ handlers for the time driver. /// /// By default, the code generated by this macro will be defined inside the library depending on /// the feature flags specified. However, the macro is exported to allow users to specify the /// interrupt handlers themselves. /// /// Please note that you have to explicitely import the [macro@va108xx_hal::pac::interrupt] /// macro in the application code in case this macro is used there. #[macro_export] macro_rules! embassy_time_driver_irqs { ( timekeeper_irq = $timekeeper_irq:ident, alarm_irq = $alarm_irq:ident ) => { const TIMEKEEPER_IRQ: pac::Interrupt = pac::Interrupt::$timekeeper_irq; #[interrupt] #[allow(non_snake_case)] fn $timekeeper_irq() { // Safety: We call it once here. unsafe { $crate::time_driver().on_interrupt_timekeeping() } } const ALARM_IRQ: pac::Interrupt = pac::Interrupt::$alarm_irq; #[interrupt] #[allow(non_snake_case)] fn $alarm_irq() { // Safety: We call it once here. unsafe { $crate::time_driver().on_interrupt_alarm() } } }; } // Provide three combinations of IRQs for the time driver by default. #[cfg(feature = "irq-tim14-tim15")] embassy_time_driver_irqs!(timekeeper_irq = TIM15, alarm_irq = TIM14); #[cfg(feature = "irq-tim13-tim14")] embassy_time_driver_irqs!(timekeeper_irq = TIM14, alarm_irq = TIM13); #[cfg(feature = "irq-tim22-tim23")] embassy_time_driver_irqs!(timekeeper_irq = TIM23, alarm_irq = TIM22); /// Initialization method for embassy /// /// If the interrupt handlers are provided by the library, the ID of the /// used TIM peripherals has to match the ID of the passed timer peripherals. Currently, this /// can only be checked at run-time, and a run-time assertion will panic on the embassy /// initialization in case of a missmatch. pub fn init( timekeeper: TimekeeperTim, alarm: AlarmTim, clocks: &Clocks, ) { #[cfg(feature = "_irqs-in-lib")] assert_eq!( TimekeeperTim::ID.value(), TIMEKEEPER_IRQ as u8 - TIM_IRQ_OFFSET as u8, "Timekeeper TIM and IRQ missmatch" ); #[cfg(feature = "_irqs-in-lib")] assert_eq!( AlarmTim::ID.value(), ALARM_IRQ as u8 - TIM_IRQ_OFFSET as u8, "Alarm TIM and IRQ missmatch" ); enable_and_init_irq_router(); time_driver().__init(timekeeper, alarm, clocks) }