va108xx_embassy/
lib.rs

1//! # Embassy-rs support for the Vorago VA108xx MCU family
2//!
3//! This repository contains the [embassy-rs](https://github.com/embassy-rs/embassy) support for
4//! the VA108xx family. Currently, it contains the time driver to allow using embassy-rs. It uses
5//! the TIM peripherals provided by the VA108xx family for this purpose.
6//!
7//! ## Usage
8//!
9//! This library exposes the [init] or the [init_with_custom_irqs] functions which set up the time
10//! driver. This function must be called once at the start of the application.
11//!
12//! This implementation requires two TIM peripherals provided by the VA108xx device.
13//! The user can freely specify the two used TIM peripheral by passing the concrete TIM instances
14//! into the [init_with_custom_irqs] and [init] method.
15//!
16//! The application also requires two interrupt handlers to handle the timekeeper and alarm
17//! interrupts. By default, this library will define the interrupt handler inside the library
18//! itself by using the `irq-oc30-oc31` feature flag. This library exposes three combinations:
19//!
20//! - `irq-oc30-oc31`: Uses [pac::Interrupt::OC30] and [pac::Interrupt::OC31]
21//! - `irq-oc29-oc30`: Uses [pac::Interrupt::OC29] and [pac::Interrupt::OC30]
22//! - `irq-oc28-oc29`: Uses [pac::Interrupt::OC28] and [pac::Interrupt::OC20]
23//!
24//! You can disable the default features and then specify one of the features above to use the
25//! documented combination of IRQs. It is also possible to specify custom IRQs by importing and
26//! using the [embassy_time_driver_irqs] macro to declare the IRQ handlers in the
27//! application code. If this is done, [init_with_custom_irqs] must be used
28//! method to pass the IRQ numbers to the library.
29//!
30//! ## Examples
31//!
32//! [embassy example projects](https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/src/branch/main/examples/embassy)
33#![no_std]
34#![cfg_attr(docsrs, feature(doc_auto_cfg))]
35
36#[cfg(feature = "irqs-in-lib")]
37use va108xx_hal::pac::{self, interrupt};
38use va108xx_hal::time::Hertz;
39use va108xx_hal::timer::TimInstance;
40use vorago_shared_hal::embassy::time_driver;
41
42/// Macro to define the IRQ handlers for the time driver.
43///
44/// By default, the code generated by this macro will be defined inside the library depending on
45/// the feature flags specified. However, the macro is exported to allow users to specify the
46/// interrupt handlers themselves.
47///
48/// Please note that you have to explicitely import the [macro@va108xx_hal::pac::interrupt]
49/// macro in the application code in case this macro is used there.
50#[macro_export]
51macro_rules! embassy_time_driver_irqs {
52    (
53        timekeeper_irq = $timekeeper_irq:ident,
54        alarm_irq = $alarm_irq:ident
55    ) => {
56        const TIMEKEEPER_IRQ: pac::Interrupt = pac::Interrupt::$timekeeper_irq;
57
58        #[interrupt]
59        #[allow(non_snake_case)]
60        fn $timekeeper_irq() {
61            // Safety: We call it once here.
62            unsafe { $crate::time_driver().on_interrupt_timekeeping() }
63        }
64
65        const ALARM_IRQ: pac::Interrupt = pac::Interrupt::$alarm_irq;
66
67        #[interrupt]
68        #[allow(non_snake_case)]
69        fn $alarm_irq() {
70            // Safety: We call it once here.
71            unsafe { $crate::time_driver().on_interrupt_alarm() }
72        }
73    };
74}
75
76// Provide three combinations of IRQs for the time driver by default.
77
78#[cfg(feature = "irq-oc30-oc31")]
79embassy_time_driver_irqs!(timekeeper_irq = OC31, alarm_irq = OC30);
80#[cfg(feature = "irq-oc29-oc30")]
81embassy_time_driver_irqs!(timekeeper_irq = OC30, alarm_irq = OC29);
82#[cfg(feature = "irq-oc28-oc29")]
83embassy_time_driver_irqs!(timekeeper_irq = OC29, alarm_irq = OC28);
84
85/// Initialization method for embassy.
86///
87/// This should be used if the interrupt handler is provided by the library, which is the
88/// default case.
89#[cfg(feature = "irqs-in-lib")]
90pub fn init<TimekeeperTim: TimInstance, AlarmTim: TimInstance>(
91    timekeeper_tim: TimekeeperTim,
92    alarm_tim: AlarmTim,
93    sysclk: Hertz,
94) {
95    time_driver().__init(sysclk, timekeeper_tim, alarm_tim, TIMEKEEPER_IRQ, ALARM_IRQ)
96}
97
98/// Initialization method for embassy when using custom IRQ handlers.
99///
100/// Requires an explicit [pac::Interrupt] argument for the timekeeper and alarm IRQs.
101pub fn init_with_custom_irqs<TimekeeperTim: TimInstance, AlarmTim: TimInstance>(
102    timekeeper_tim: TimekeeperTim,
103    alarm_tim: AlarmTim,
104    sysclk: Hertz,
105    timekeeper_irq: pac::Interrupt,
106    alarm_irq: pac::Interrupt,
107) {
108    time_driver().__init(sysclk, timekeeper_tim, alarm_tim, timekeeper_irq, alarm_irq)
109}