va416xx-hal 0.7.0

HAL for the Vorago VA416xx family of MCUs
Documentation
//! # Embassy-rs support for the Vorago VA416xx MCU family
//!
//! This module exposes the [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:
//!
//! - `time-driver-tim14-tim15`: Uses [crate::pac::Interrupt::TIM14] for alarm and [crate::pac::Interrupt::TIM15]
//!   for timekeeper
//! - `time-driver-tim13-tim14`: Uses [crate::pac::Interrupt::TIM13] for alarm and [crate::pac::Interrupt::TIM14]
//!   for timekeeper
//! - `time-driver-tim22-tim23`: Uses [crate::pac::Interrupt::TIM22] for alarm and [crate::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 [crate::embassy_time_driver_irqs] macro to declare the IRQ handlers in the
//! application code.
#[cfg(feature = "_irqs-in-lib")]
use crate::pac::{self, interrupt};
#[cfg(feature = "_irqs-in-lib")]
use crate::timer::TIM_IRQ_OFFSET;
use crate::{clock::Clocks, irq_router::enable_and_init_irq_router, timer::TimInstance};

use vorago_shared_hal::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@crate::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::embassy_time::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::embassy_time::time_driver().on_interrupt_alarm() }
        }
    };
}

// Provide three combinations of IRQs for the time driver by default.

#[cfg(feature = "time-driver-tim14-tim15")]
embassy_time_driver_irqs!(timekeeper_irq = TIM15, alarm_irq = TIM14);
#[cfg(feature = "time-driver-tim13-tim14")]
embassy_time_driver_irqs!(timekeeper_irq = TIM14, alarm_irq = TIM13);
#[cfg(feature = "time-driver-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<TimekeeperTim: TimInstance, AlarmTim: TimInstance>(
    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)
}