mirror of
https://github.com/esp-rs/esp-hal.git
synced 2025-09-28 12:50:53 +00:00
Runtime ISR binding for TWAI (#1384)
* Runtime ISR binding for TWAI * CHANGELOG.md * Fix EH-0.2 TWAI implementation
This commit is contained in:
parent
efcf7d4074
commit
ba73154c36
@ -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
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
|
@ -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<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();
|
||||
@ -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<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()
|
||||
@ -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<DM>,
|
||||
}
|
||||
|
||||
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<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> {
|
||||
@ -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<T> Twai<'_, T>
|
||||
impl<T> 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();
|
||||
|
@ -37,7 +37,10 @@ use static_cell::make_static;
|
||||
type TwaiOutbox = Channel<NoopRawMutex, EspTwaiFrame, 16>;
|
||||
|
||||
#[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,
|
||||
|
@ -52,6 +52,7 @@ fn main() -> ! {
|
||||
can_rx_pin,
|
||||
&clocks,
|
||||
CAN_BAUDRATE,
|
||||
None,
|
||||
);
|
||||
|
||||
// Partially filter the incoming messages to reduce overhead of receiving
|
||||
|
Loading…
x
Reference in New Issue
Block a user