Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Runtime ISR binding for TWAI #1384

Merged
merged 3 commits into from
Apr 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions esp-hal/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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

Expand Down
15 changes: 1 addition & 14 deletions esp-hal/src/embassy/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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)
}

Expand Down
142 changes: 116 additions & 26 deletions esp-hal/src/twai/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
//! can_rx_pin,
//! &clocks,
//! CAN_BAUDRATE,
//! None,
//! );
//!
//! // Partially filter the incoming messages to reduce overhead of receiving undesired messages
Expand Down Expand Up @@ -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},
Expand Down Expand Up @@ -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<DM>,
}

impl<'d, T> TwaiConfiguration<'d, T>
impl<'d, T, DM> TwaiConfiguration<'d, T, DM>
where
T: Instance,
DM: crate::Mode,
{
pub fn new<TX: OutputPin, RX: InputPin>(
fn new_internal<TX: OutputPin, RX: InputPin>(
_peripheral: impl Peripheral<P = T> + 'd,
tx_pin: impl Peripheral<P = TX> + 'd,
rx_pin: impl Peripheral<P = RX> + 'd,
clocks: &Clocks,
baud_rate: BaudRate,
interrupt: Option<InterruptHandler>,
) -> Self {
// Enable the peripheral clock for the TWAI peripheral.
T::enable_peripheral();
Expand All @@ -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
}

Expand Down Expand Up @@ -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()
Expand All @@ -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<TX: OutputPin, RX: InputPin>(
peripheral: impl Peripheral<P = T> + 'd,
tx_pin: impl Peripheral<P = TX> + 'd,
rx_pin: impl Peripheral<P = RX> + 'd,
clocks: &Clocks,
baud_rate: BaudRate,
interrupt: Option<InterruptHandler>,
) -> 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<TX: OutputPin, RX: InputPin>(
peripheral: impl Peripheral<P = T> + 'd,
tx_pin: impl Peripheral<P = TX> + 'd,
rx_pin: impl Peripheral<P = RX> + '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<DM>,
}

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()
Expand All @@ -782,6 +840,7 @@ where

TwaiConfiguration {
peripheral: PhantomData,
phantom: PhantomData,
}
}

Expand Down Expand Up @@ -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<DM>,
}

impl<'d, T> TwaiTx<'d, T>
impl<'d, T, DM> TwaiTx<'d, T, DM>
where
T: OperationInstance,
DM: crate::Mode,
{
/// Transmit a frame.
///
Expand Down Expand Up @@ -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<DM>,
}

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<EspTwaiFrame, EspTwaiError> {
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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 }
Expand Down Expand Up @@ -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 }
Expand Down Expand Up @@ -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 }
Expand Down Expand Up @@ -1320,7 +1410,7 @@ mod asynch {
channel::Channel,
waitqueue::AtomicWaker,
};
use procmacros::interrupt;
use procmacros::handler;

use super::*;
use crate::peripherals::TWAI0;
Expand All @@ -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<T> Twai<'_, T>
impl<T> Twai<'_, T, crate::Async>
where
T: OperationInstance,
{
Expand All @@ -1360,7 +1450,7 @@ mod asynch {
}
}

impl<'d, T> TwaiTx<'d, T>
impl<'d, T> TwaiTx<'d, T, crate::Async>
where
T: OperationInstance,
{
Expand Down Expand Up @@ -1389,7 +1479,7 @@ mod asynch {
}
}

impl<'d, T> TwaiRx<'d, T>
impl<'d, T> TwaiRx<'d, T, crate::Async>
where
T: OperationInstance,
{
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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();
Expand Down
Loading
Loading