diff --git a/esp-hal/CHANGELOG.md b/esp-hal/CHANGELOG.md index 6c42c8afc08..3ef361b9ad0 100644 --- a/esp-hal/CHANGELOG.md +++ b/esp-hal/CHANGELOG.md @@ -30,7 +30,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - USB pullup/pulldown now gets properly cleared and does not interfere anymore on esp32c3 and esp32s3 (#1244) - Fixed GPIO counts so that using async code with the higher GPIO number should no longer panic (#1361, #1362) - ESP32/ESP32-S2: Wait for I2S getting out of TX_IDLE when starting a transfer (#1375) -- Fixed writes to SPI not flushing before attemting to write, causing corrupted writes (#1381) +- Fixed writes to SPI not flushing before attempting to write, causing corrupted writes (#1381) ### Changed @@ -49,8 +49,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Runtime ISR binding for SHA,ECC and RSA (#1354) - Runtime ISR binding for I2C (#1376) - `UsbSerialJtag` can be created in async or blocking mode. The blocking constructor takes an optional interrupt handler argument (#1377) -- SYSTIMER and TIMG instances can now be created in async or blocking mode. The blocking constructor takes an optional argument to set interrupt handlers. The constructors are named `create`/`create_async` (#1348) - SYSTIMER and TIMG instances can now be created in async or blocking mode (#1348) +- Runtime ISR binding for TWAI (#1384) ### Removed diff --git a/esp-hal/src/embassy/mod.rs b/esp-hal/src/embassy/mod.rs index bd6d06c0f91..223e2f2cc89 100644 --- a/esp-hal/src/embassy/mod.rs +++ b/esp-hal/src/embassy/mod.rs @@ -82,9 +82,6 @@ use core::cell::Cell; use embassy_time_driver::{AlarmHandle, Driver}; -#[cfg(feature = "async")] -use crate::{interrupt::Priority, peripherals::Interrupt}; - #[cfg_attr( all( systimer, @@ -105,18 +102,8 @@ use time_driver::EmbassyTimer; use crate::clock::Clocks; -/// Initialise embassy, including setting up interrupts for the DMA and async -/// enabled peripherals. +/// Initialise embassy pub fn init(clocks: &Clocks, td: time_driver::TimerType) { - // only enable interrupts if the async feature is present - #[cfg(feature = "async")] - { - #[cfg(twai0)] - crate::interrupt::enable(Interrupt::TWAI0, Priority::min()).unwrap(); - #[cfg(twai1)] - crate::interrupt::enable(Interrupt::TWAI1, Priority::min()).unwrap(); - } - EmbassyTimer::init(clocks, td) } diff --git a/esp-hal/src/twai/mod.rs b/esp-hal/src/twai/mod.rs index c8ba57eacf7..0cb7f2e40c3 100644 --- a/esp-hal/src/twai/mod.rs +++ b/esp-hal/src/twai/mod.rs @@ -34,6 +34,7 @@ //! can_rx_pin, //! &clocks, //! CAN_BAUDRATE, +//! None, //! ); //! //! // Partially filter the incoming messages to reduce overhead of receiving undesired messages @@ -81,6 +82,7 @@ use self::filter::{Filter, FilterType}; use crate::{ clock::Clocks, gpio::{InputPin, InputSignal, OutputPin, OutputSignal}, + interrupt::InterruptHandler, peripheral::{Peripheral, PeripheralRef}, peripherals::twai0::RegisterBlock, system::{self, PeripheralClockControl}, @@ -627,20 +629,23 @@ impl BaudRate { } /// An inactive TWAI peripheral in the "Reset"/configuration state. -pub struct TwaiConfiguration<'d, T> { +pub struct TwaiConfiguration<'d, T, DM: crate::Mode> { peripheral: PhantomData<&'d PeripheralRef<'d, T>>, + phantom: PhantomData, } -impl<'d, T> TwaiConfiguration<'d, T> +impl<'d, T, DM> TwaiConfiguration<'d, T, DM> where T: Instance, + DM: crate::Mode, { - pub fn new( + fn new_internal( _peripheral: impl Peripheral

+ 'd, tx_pin: impl Peripheral

+ 'd, rx_pin: impl Peripheral

+ 'd, clocks: &Clocks, baud_rate: BaudRate, + interrupt: Option, ) -> Self { // Enable the peripheral clock for the TWAI peripheral. T::enable_peripheral(); @@ -652,10 +657,18 @@ where let mut cfg = TwaiConfiguration { peripheral: PhantomData, + phantom: PhantomData, }; cfg.set_baud_rate(baud_rate, clocks); + if let Some(interrupt) = interrupt { + unsafe { + crate::interrupt::bind_interrupt(T::INTERRUPT, interrupt.handler()); + crate::interrupt::enable(T::INTERRUPT, interrupt.priority()).unwrap(); + } + } + cfg } @@ -741,7 +754,7 @@ where /// Put the peripheral into Operation Mode, allowing the transmission and /// reception of packets using the new object. - pub fn start(self) -> Twai<'d, T> { + pub fn start(self) -> Twai<'d, T, DM> { // Put the peripheral into operation mode by clearing the reset mode bit. T::register_block() .mode() @@ -750,30 +763,75 @@ where Twai { tx: TwaiTx { _peripheral: PhantomData, + phantom: PhantomData, }, rx: TwaiRx { _peripheral: PhantomData, + phantom: PhantomData, }, + phantom: PhantomData, } } } +impl<'d, T> TwaiConfiguration<'d, T, crate::Blocking> +where + T: Instance, +{ + pub fn new( + peripheral: impl Peripheral

+ 'd, + tx_pin: impl Peripheral

+ 'd, + rx_pin: impl Peripheral

+ 'd, + clocks: &Clocks, + baud_rate: BaudRate, + interrupt: Option, + ) -> Self { + Self::new_internal(peripheral, tx_pin, rx_pin, clocks, baud_rate, interrupt) + } +} + +#[cfg(feature = "async")] +impl<'d, T> TwaiConfiguration<'d, T, crate::Async> +where + T: Instance, +{ + pub fn new_async( + peripheral: impl Peripheral

+ 'd, + tx_pin: impl Peripheral

+ 'd, + rx_pin: impl Peripheral

+ 'd, + clocks: &Clocks, + baud_rate: BaudRate, + ) -> Self { + let interrupt = T::async_handler(); + Self::new_internal( + peripheral, + tx_pin, + rx_pin, + clocks, + baud_rate, + Some(interrupt), + ) + } +} + /// An active TWAI peripheral in Normal Mode. /// /// In this mode, the TWAI controller can transmit and receive messages /// including error signals (such as error and overload frames). -pub struct Twai<'d, T> { - tx: TwaiTx<'d, T>, - rx: TwaiRx<'d, T>, +pub struct Twai<'d, T, DM: crate::Mode> { + tx: TwaiTx<'d, T, DM>, + rx: TwaiRx<'d, T, DM>, + phantom: PhantomData, } -impl<'d, T> Twai<'d, T> +impl<'d, T, DM> Twai<'d, T, DM> where T: OperationInstance, + DM: crate::Mode, { /// Stop the peripheral, putting it into reset mode and enabling /// reconfiguration. - pub fn stop(self) -> TwaiConfiguration<'d, T> { + pub fn stop(self) -> TwaiConfiguration<'d, T, DM> { // Put the peripheral into reset/configuration mode by setting the reset mode // bit. T::register_block() @@ -782,6 +840,7 @@ where TwaiConfiguration { peripheral: PhantomData, + phantom: PhantomData, } } @@ -838,19 +897,21 @@ where /// Consumes this `Twai` instance and splits it into transmitting and /// receiving halves. - pub fn split(self) -> (TwaiTx<'d, T>, TwaiRx<'d, T>) { + pub fn split(self) -> (TwaiTx<'d, T, DM>, TwaiRx<'d, T, DM>) { (self.tx, self.rx) } } /// Interface to the CAN transmitter part. -pub struct TwaiTx<'d, T> { +pub struct TwaiTx<'d, T, DM: crate::Mode> { _peripheral: PhantomData<&'d T>, + phantom: PhantomData, } -impl<'d, T> TwaiTx<'d, T> +impl<'d, T, DM> TwaiTx<'d, T, DM> where T: OperationInstance, + DM: crate::Mode, { /// Transmit a frame. /// @@ -884,13 +945,15 @@ where } /// Interface to the CAN receiver part. -pub struct TwaiRx<'d, T> { +pub struct TwaiRx<'d, T, DM: crate::Mode> { _peripheral: PhantomData<&'d T>, + phantom: PhantomData, } -impl<'d, T> TwaiRx<'d, T> +impl<'d, T, DM> TwaiRx<'d, T, DM> where T: OperationInstance, + DM: crate::Mode, { // Receive a frame pub fn receive(&mut self) -> nb::Result { @@ -982,9 +1045,10 @@ unsafe fn copy_to_data_register(dest: *mut u32, src: &[u8]) { } #[cfg(feature = "embedded-hal-02")] -impl<'d, T> embedded_hal_02::can::Can for Twai<'d, T> +impl<'d, T, DM> embedded_hal_02::can::Can for Twai<'d, T, DM> where T: OperationInstance, + DM: crate::Mode, { type Frame = EspTwaiFrame; type Error = EspTwaiError; @@ -1006,9 +1070,10 @@ where } #[cfg(feature = "embedded-hal")] -impl<'d, T> embedded_can::nb::Can for Twai<'d, T> +impl<'d, T, DM> embedded_can::nb::Can for Twai<'d, T, DM> where T: OperationInstance, + DM: crate::Mode, { type Frame = EspTwaiFrame; type Error = EspTwaiError; @@ -1036,6 +1101,10 @@ pub trait Instance: crate::private::Sealed { const INPUT_SIGNAL: InputSignal; const OUTPUT_SIGNAL: OutputSignal; + const INTERRUPT: crate::peripherals::Interrupt; + #[cfg(feature = "async")] + fn async_handler() -> InterruptHandler; + fn register_block() -> &'static RegisterBlock; fn enable_peripheral(); @@ -1208,6 +1277,13 @@ impl Instance for crate::peripherals::TWAI0 { const INPUT_SIGNAL: InputSignal = InputSignal::TWAI_RX; const OUTPUT_SIGNAL: OutputSignal = OutputSignal::TWAI_TX; + const INTERRUPT: crate::peripherals::Interrupt = crate::peripherals::Interrupt::TWAI0; + + #[cfg(feature = "async")] + fn async_handler() -> InterruptHandler { + asynch::twai0 + } + #[inline(always)] fn register_block() -> &'static RegisterBlock { unsafe { &*crate::peripherals::TWAI0::PTR } @@ -1245,6 +1321,13 @@ impl Instance for crate::peripherals::TWAI0 { const INPUT_SIGNAL: InputSignal = InputSignal::TWAI0_RX; const OUTPUT_SIGNAL: OutputSignal = OutputSignal::TWAI0_TX; + const INTERRUPT: crate::peripherals::Interrupt = crate::peripherals::Interrupt::TWAI0; + + #[cfg(feature = "async")] + fn async_handler() -> InterruptHandler { + asynch::twai0 + } + #[inline(always)] fn register_block() -> &'static RegisterBlock { unsafe { &*crate::peripherals::TWAI0::PTR } @@ -1282,6 +1365,13 @@ impl Instance for crate::peripherals::TWAI1 { const INPUT_SIGNAL: InputSignal = InputSignal::TWAI1_RX; const OUTPUT_SIGNAL: OutputSignal = OutputSignal::TWAI1_TX; + const INTERRUPT: crate::peripherals::Interrupt = crate::peripherals::Interrupt::TWAI1; + + #[cfg(feature = "async")] + fn async_handler() -> InterruptHandler { + asynch::twai1 + } + #[inline(always)] fn register_block() -> &'static RegisterBlock { unsafe { &*crate::peripherals::TWAI1::PTR } @@ -1320,7 +1410,7 @@ mod asynch { channel::Channel, waitqueue::AtomicWaker, }; - use procmacros::interrupt; + use procmacros::handler; use super::*; use crate::peripherals::TWAI0; @@ -1347,7 +1437,7 @@ mod asynch { const NEW_STATE: TwaiAsyncState = TwaiAsyncState::new(); pub(crate) static TWAI_STATE: [TwaiAsyncState; NUM_TWAI] = [NEW_STATE; NUM_TWAI]; - impl Twai<'_, T> + impl Twai<'_, T, crate::Async> where T: OperationInstance, { @@ -1360,7 +1450,7 @@ mod asynch { } } - impl<'d, T> TwaiTx<'d, T> + impl<'d, T> TwaiTx<'d, T, crate::Async> where T: OperationInstance, { @@ -1389,7 +1479,7 @@ mod asynch { } } - impl<'d, T> TwaiRx<'d, T> + impl<'d, T> TwaiRx<'d, T, crate::Async> where T: OperationInstance, { @@ -1422,8 +1512,8 @@ mod asynch { } #[cfg(any(esp32c3, esp32, esp32s2, esp32s3))] - #[interrupt] - fn TWAI0() { + #[handler] + pub(super) fn twai0() { let register_block = TWAI0::register_block(); let intr_enable = register_block.int_ena().read(); @@ -1467,8 +1557,8 @@ mod asynch { } #[cfg(esp32c6)] - #[interrupt] - fn TWAI0() { + #[handler] + pub(super) fn twai0() { let register_block = TWAI0::register_block(); let intr_enable = register_block.interrupt_enable().read(); @@ -1512,8 +1602,8 @@ mod asynch { } #[cfg(esp32c6)] - #[interrupt] - fn TWAI1() { + #[handler] + pub(super) fn twai1() { let register_block = TWAI1::register_block(); let intr_enable = register_block.interrupt_enable().read(); diff --git a/examples/src/bin/embassy_twai.rs b/examples/src/bin/embassy_twai.rs index 92f4e3d674a..b06a4f1bdf6 100644 --- a/examples/src/bin/embassy_twai.rs +++ b/examples/src/bin/embassy_twai.rs @@ -37,7 +37,10 @@ use static_cell::make_static; type TwaiOutbox = Channel; #[embassy_executor::task] -async fn receiver(mut rx: TwaiRx<'static, TWAI0>, channel: &'static TwaiOutbox) -> ! { +async fn receiver( + mut rx: TwaiRx<'static, TWAI0, esp_hal::Async>, + channel: &'static TwaiOutbox, +) -> ! { loop { let frame = rx.receive_async().await; @@ -57,7 +60,10 @@ async fn receiver(mut rx: TwaiRx<'static, TWAI0>, channel: &'static TwaiOutbox) } #[embassy_executor::task] -async fn transmitter(mut tx: TwaiTx<'static, TWAI0>, channel: &'static TwaiOutbox) -> ! { +async fn transmitter( + mut tx: TwaiTx<'static, TWAI0, esp_hal::Async>, + channel: &'static TwaiOutbox, +) -> ! { loop { let frame = channel.receive().await; let result = tx.transmit_async(&frame).await; @@ -94,7 +100,7 @@ async fn main(spawner: Spawner) { // Begin configuring the TWAI peripheral. The peripheral is in a reset like // state that prevents transmission but allows configuration. - let mut can_config = twai::TwaiConfiguration::new( + let mut can_config = twai::TwaiConfiguration::new_async( peripherals.TWAI0, can_tx_pin, can_rx_pin, diff --git a/examples/src/bin/twai.rs b/examples/src/bin/twai.rs index 9d98edc0324..01814b2aeb0 100644 --- a/examples/src/bin/twai.rs +++ b/examples/src/bin/twai.rs @@ -52,6 +52,7 @@ fn main() -> ! { can_rx_pin, &clocks, CAN_BAUDRATE, + None, ); // Partially filter the incoming messages to reduce overhead of receiving