diff --git a/esp-hal/CHANGELOG.md b/esp-hal/CHANGELOG.md index d05b1ee533a..d4716178dc8 100644 --- a/esp-hal/CHANGELOG.md +++ b/esp-hal/CHANGELOG.md @@ -25,6 +25,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Added APIs to allow connecting signals through the GPIO matrix. (#2128) - Implement `TryFrom` for `ledc::timer::config::Duty` (#1984) - Expose `RtcClock::get_xtal_freq` and `RtcClock::get_slow_freq` publically for all chips (#2183) +- TWAI support for ESP32-H2 (#2199) ### Changed diff --git a/esp-hal/src/twai/mod.rs b/esp-hal/src/twai/mod.rs index 30c451cd1a3..c01737382d1 100644 --- a/esp-hal/src/twai/mod.rs +++ b/esp-hal/src/twai/mod.rs @@ -662,8 +662,8 @@ impl BaudRate { /// Convert the BaudRate into the timings that the peripheral needs. // See: https://github.com/espressif/esp-idf/tree/master/components/hal/include/hal/twai_types.h const fn timing(self) -> TimingConfig { - #[allow(unused_mut)] - let mut timing = match self { + #[cfg(not(esp32h2))] + let timing = match self { Self::B125K => TimingConfig { baud_rate_prescaler: 32, sync_jump_width: 3, @@ -695,11 +695,45 @@ impl BaudRate { Self::Custom(timing_config) => timing_config, }; + #[cfg(esp32h2)] + let timing = match self { + Self::B125K => TimingConfig { + baud_rate_prescaler: 8, + sync_jump_width: 3, + tseg_1: 23, + tseg_2: 8, + triple_sample: false, + }, + Self::B250K => TimingConfig { + baud_rate_prescaler: 8, + sync_jump_width: 3, + tseg_1: 11, + tseg_2: 4, + triple_sample: false, + }, + Self::B500K => TimingConfig { + baud_rate_prescaler: 4, + sync_jump_width: 3, + tseg_1: 11, + tseg_2: 4, + triple_sample: false, + }, + Self::B1000K => TimingConfig { + baud_rate_prescaler: 2, + sync_jump_width: 3, + tseg_1: 11, + tseg_2: 4, + triple_sample: false, + }, + Self::Custom(timing_config) => timing_config, + }; + + // clock source on ESP32-C6 is xtal (40MHz) #[cfg(esp32c6)] - { - // clock source on ESP32-C6 is xtal (40MHz) - timing.baud_rate_prescaler /= 2; - } + let timing = TimingConfig { + baud_rate_prescaler: timing.baud_rate_prescaler / 2, + ..timing + }; timing } @@ -802,7 +836,7 @@ where fn set_baud_rate(&mut self, baud_rate: BaudRate) { // TWAI is clocked from the APB_CLK according to Table 6-4 [ESP32C3 Reference Manual](https://www.espressif.com/sites/default/files/documentation/esp32-c3_technical_reference_manual_en.pdf) // Included timings are all for 80MHz so assert that we are running at 80MHz. - #[cfg(not(esp32c6))] + #[cfg(not(any(esp32h2, esp32c6)))] { let apb_clock = crate::clock::Clocks::get().apb_clock; assert!(apb_clock == fugit::HertzU32::MHz(80)); @@ -820,22 +854,17 @@ where let tseg_2 = timing.tseg_2 - 1; let triple_sample = timing.triple_sample; - #[cfg(esp32)] - let prescale = prescale as u8; - // Set up the prescaler and sync jump width. - T::register_block() - .bus_timing_0() - .modify(|_, w| unsafe { w.baud_presc().bits(prescale).sync_jump_width().bits(sjw) }); + T::register_block().bus_timing_0().modify(|_, w| unsafe { + w.baud_presc().bits(prescale as _); + w.sync_jump_width().bits(sjw) + }); // Set up the time segment 1, time segment 2, and triple sample. T::register_block().bus_timing_1().modify(|_, w| unsafe { - w.time_seg1() - .bits(tseg_1) - .time_seg2() - .bits(tseg_2) - .time_samp() - .bit(triple_sample) + w.time_seg1().bits(tseg_1); + w.time_seg2().bits(tseg_2); + w.time_samp().bit(triple_sample) }); } @@ -1510,7 +1539,7 @@ impl Instance for crate::peripherals::TWAI0 { #[cfg(any(esp32, esp32c3, esp32s2, esp32s3))] impl OperationInstance for crate::peripherals::TWAI0 {} -#[cfg(esp32c6)] +#[cfg(any(esp32h2, esp32c6))] impl Instance for crate::peripherals::TWAI0 { const SYSTEM_PERIPHERAL: system::Peripheral = system::Peripheral::Twai0; const NUMBER: usize = 0; @@ -1554,7 +1583,7 @@ impl Instance for crate::peripherals::TWAI0 { } } -#[cfg(esp32c6)] +#[cfg(any(esp32h2, esp32c6))] impl OperationInstance for crate::peripherals::TWAI0 {} #[cfg(esp32c6)] @@ -1641,7 +1670,7 @@ mod asynch { } } - const NUM_TWAI: usize = 2; + const NUM_TWAI: usize = 1 + cfg!(twai1) as usize; #[allow(clippy::declare_interior_mutable_const)] const NEW_STATE: TwaiAsyncState = TwaiAsyncState::new(); pub(crate) static TWAI_STATE: [TwaiAsyncState; NUM_TWAI] = [NEW_STATE; NUM_TWAI]; @@ -1768,7 +1797,7 @@ mod asynch { } } - #[cfg(esp32c6)] + #[cfg(any(esp32h2, esp32c6))] #[handler] pub(super) fn twai0() { let register_block = TWAI0::register_block(); diff --git a/esp-metadata/devices/esp32h2.toml b/esp-metadata/devices/esp32h2.toml index 886c4bf67db..901f4bd8ef9 100644 --- a/esp-metadata/devices/esp32h2.toml +++ b/esp-metadata/devices/esp32h2.toml @@ -54,7 +54,7 @@ peripherals = [ "timg0", "timg1", "trace0", - # "twai0", + "twai0", "uart0", "uart1", "uhci0", diff --git a/examples/src/bin/twai.rs b/examples/src/bin/twai.rs index de01a2a5e2a..14d690f4e22 100644 --- a/examples/src/bin/twai.rs +++ b/examples/src/bin/twai.rs @@ -1,6 +1,6 @@ -//! This example sends a CAN message to another ESP and receives it back. +//! This example sends a TWAI message to another ESP and receives it back. //! -//! This example works without CAN Transceivers by: +//! This example works without TWAI transceivers by: //! * setting the tx pins to open drain //! * connecting all rx and tx pins together //! * adding a pull-up to the signal pins @@ -17,7 +17,7 @@ //! In case you want to use `self-testing`, get rid of everything related to the aforementioned `IS_FIRST_SENDER` //! and follow the advice in the comments related to this mode. -//% CHIPS: esp32c3 esp32c6 esp32s2 esp32s3 +//% CHIPS: esp32c3 esp32c6 esp32h2 esp32s2 esp32s3 #![no_std] #![no_main] @@ -39,11 +39,11 @@ fn main() -> ! { let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); - let can_tx_pin = io.pins.gpio0; - let can_rx_pin = io.pins.gpio2; + let tx_pin = io.pins.gpio0; + let rx_pin = io.pins.gpio2; // The speed of the CAN bus. - const CAN_BAUDRATE: twai::BaudRate = twai::BaudRate::B1000K; + const TWAI_BAUDRATE: twai::BaudRate = twai::BaudRate::B1000K; // !!! Use `new` when using a transceiver. `new_no_transceiver` sets TX to open-drain // Self-testing also works using the regular `new` function. @@ -51,11 +51,11 @@ fn main() -> ! { // Begin configuring the TWAI peripheral. The peripheral is in a reset like // state that prevents transmission but allows configuration. // For self-testing use `SelfTest` mode of the TWAI peripheral. - let mut can_config = twai::TwaiConfiguration::new_no_transceiver( + let mut twai_config = twai::TwaiConfiguration::new_no_transceiver( peripherals.TWAI0, - can_rx_pin, - can_tx_pin, - CAN_BAUDRATE, + rx_pin, + tx_pin, + TWAI_BAUDRATE, TwaiMode::Normal, ); @@ -67,12 +67,12 @@ fn main() -> ! { // A filter that matches StandardId::ZERO. const FILTER: SingleStandardFilter = SingleStandardFilter::new(b"00000000000", b"x", [b"xxxxxxxx", b"xxxxxxxx"]); - can_config.set_filter(FILTER); + twai_config.set_filter(FILTER); // Start the peripheral. This locks the configuration settings of the peripheral // and puts it into operation mode, allowing packets to be sent and // received. - let mut can = can_config.start(); + let mut can = twai_config.start(); if IS_FIRST_SENDER { // Send a frame to the other ESP diff --git a/hil-test/tests/delay.rs b/hil-test/tests/delay.rs index 69e1186d99d..53a8daac625 100644 --- a/hil-test/tests/delay.rs +++ b/hil-test/tests/delay.rs @@ -1,6 +1,6 @@ //! Delay Test -//% CHIPS: esp32 esp32c2 esp32c3 esp32c6 esp32s2 esp32s3 +//% CHIPS: esp32 esp32c2 esp32c3 esp32c6 esp32h2 esp32s2 esp32s3 #![no_std] #![no_main] diff --git a/hil-test/tests/twai.rs b/hil-test/tests/twai.rs index 5c476789ec8..508c74d1143 100644 --- a/hil-test/tests/twai.rs +++ b/hil-test/tests/twai.rs @@ -1,6 +1,6 @@ //! TWAI test -//% CHIPS: esp32c3 esp32c6 esp32s2 esp32s3 +//% CHIPS: esp32c3 esp32c6 esp32h2 esp32s2 esp32s3 #![no_std] #![no_main] @@ -33,12 +33,12 @@ mod tests { let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); - let (can_tx_pin, can_rx_pin) = hil_test::common_test_pins!(io); + let (tx_pin, rx_pin) = hil_test::common_test_pins!(io); let mut config = twai::TwaiConfiguration::new( peripherals.TWAI0, - can_rx_pin, - can_tx_pin, + rx_pin, + tx_pin, twai::BaudRate::B1000K, TwaiMode::SelfTest, );