mirror of
https://github.com/esp-rs/esp-hal.git
synced 2025-10-02 22:55:26 +00:00
Slight TWAI corrections (#2288)
* Fix ESP32 baud rate prescaler bit * Explicitly disable CLKOUT * Fix brp * Loop example * Clean up * Impl traits for BaudRate * Fix H2 125k * Avoid self-receiving transmitted frames * Fix self-reception flag * De-CAN * CI, more defmt impls * Explain raw bit manipulation * Fix spelling
This commit is contained in:
parent
08030d5541
commit
3a9abca148
@ -221,7 +221,7 @@ pub const DIS_USB_SERIAL_JTAG: EfuseField = EfuseField::new(EfuseBlock::Block0,
|
|||||||
/// `[]` Set this bit to disable the function that forces chip into download
|
/// `[]` Set this bit to disable the function that forces chip into download
|
||||||
/// mode
|
/// mode
|
||||||
pub const DIS_FORCE_DOWNLOAD: EfuseField = EfuseField::new(EfuseBlock::Block0, 44, 1);
|
pub const DIS_FORCE_DOWNLOAD: EfuseField = EfuseField::new(EfuseBlock::Block0, 44, 1);
|
||||||
/// `[DIS_CAN]` Set this bit to disable CAN function
|
/// `[DIS_CAN]` Set this bit to disable TWAI function
|
||||||
pub const DIS_TWAI: EfuseField = EfuseField::new(EfuseBlock::Block0, 46, 1);
|
pub const DIS_TWAI: EfuseField = EfuseField::new(EfuseBlock::Block0, 46, 1);
|
||||||
/// `[]` Set this bit to enable selection between usb_to_jtag and pad_to_jtag
|
/// `[]` Set this bit to enable selection between usb_to_jtag and pad_to_jtag
|
||||||
/// through strapping gpio10 when both reg_dis_usb_jtag and reg_dis_pad_jtag are
|
/// through strapping gpio10 when both reg_dis_usb_jtag and reg_dis_pad_jtag are
|
||||||
|
@ -269,7 +269,7 @@ pub const DIS_DOWNLOAD_DCACHE: EfuseField = EfuseField::new(EfuseBlock::Block0,
|
|||||||
pub const DIS_FORCE_DOWNLOAD: EfuseField = EfuseField::new(EfuseBlock::Block0, 44, 1);
|
pub const DIS_FORCE_DOWNLOAD: EfuseField = EfuseField::new(EfuseBlock::Block0, 44, 1);
|
||||||
/// `[DIS_USB]` Set this bit to disable USB function
|
/// `[DIS_USB]` Set this bit to disable USB function
|
||||||
pub const DIS_USB_OTG: EfuseField = EfuseField::new(EfuseBlock::Block0, 45, 1);
|
pub const DIS_USB_OTG: EfuseField = EfuseField::new(EfuseBlock::Block0, 45, 1);
|
||||||
/// `[DIS_CAN]` Set this bit to disable CAN function
|
/// `[DIS_CAN]` Set this bit to disable TWAI function
|
||||||
pub const DIS_TWAI: EfuseField = EfuseField::new(EfuseBlock::Block0, 46, 1);
|
pub const DIS_TWAI: EfuseField = EfuseField::new(EfuseBlock::Block0, 46, 1);
|
||||||
/// `[]` Disable app cpu
|
/// `[]` Disable app cpu
|
||||||
pub const DIS_APP_CPU: EfuseField = EfuseField::new(EfuseBlock::Block0, 47, 1);
|
pub const DIS_APP_CPU: EfuseField = EfuseField::new(EfuseBlock::Block0, 47, 1);
|
||||||
|
@ -244,6 +244,7 @@ impl embedded_can::Error for ErrorKind {
|
|||||||
|
|
||||||
/// Specifies in which mode the TWAI controller will operate.
|
/// Specifies in which mode the TWAI controller will operate.
|
||||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
pub enum TwaiMode {
|
pub enum TwaiMode {
|
||||||
/// Normal operating mode
|
/// Normal operating mode
|
||||||
Normal,
|
Normal,
|
||||||
@ -256,6 +257,7 @@ pub enum TwaiMode {
|
|||||||
|
|
||||||
/// Standard 11-bit TWAI Identifier (`0..=0x7FF`).
|
/// Standard 11-bit TWAI Identifier (`0..=0x7FF`).
|
||||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
pub struct StandardId(u16);
|
pub struct StandardId(u16);
|
||||||
|
|
||||||
impl StandardId {
|
impl StandardId {
|
||||||
@ -321,6 +323,7 @@ impl From<embedded_can::StandardId> for StandardId {
|
|||||||
|
|
||||||
/// Extended 29-bit TWAI Identifier (`0..=1FFF_FFFF`).
|
/// Extended 29-bit TWAI Identifier (`0..=1FFF_FFFF`).
|
||||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
pub struct ExtendedId(u32);
|
pub struct ExtendedId(u32);
|
||||||
|
|
||||||
impl ExtendedId {
|
impl ExtendedId {
|
||||||
@ -392,6 +395,7 @@ impl From<embedded_can::ExtendedId> for ExtendedId {
|
|||||||
|
|
||||||
/// A TWAI Identifier (standard or extended).
|
/// A TWAI Identifier (standard or extended).
|
||||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
pub enum Id {
|
pub enum Id {
|
||||||
/// Standard 11-bit Identifier (`0..=0x7FF`).
|
/// Standard 11-bit Identifier (`0..=0x7FF`).
|
||||||
Standard(StandardId),
|
Standard(StandardId),
|
||||||
@ -451,6 +455,7 @@ impl From<embedded_can::Id> for Id {
|
|||||||
|
|
||||||
/// Structure backing the embedded_hal_02::can::Frame/embedded_can::Frame trait.
|
/// Structure backing the embedded_hal_02::can::Frame/embedded_can::Frame trait.
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
pub struct EspTwaiFrame {
|
pub struct EspTwaiFrame {
|
||||||
id: Id,
|
id: Id,
|
||||||
dlc: usize,
|
dlc: usize,
|
||||||
@ -535,7 +540,7 @@ impl EspTwaiFrame {
|
|||||||
data,
|
data,
|
||||||
dlc,
|
dlc,
|
||||||
is_remote: false,
|
is_remote: false,
|
||||||
self_reception: true,
|
self_reception: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -611,6 +616,8 @@ impl embedded_can::Frame for EspTwaiFrame {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// The underlying timings for the TWAI peripheral.
|
/// The underlying timings for the TWAI peripheral.
|
||||||
|
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
pub struct TimingConfig {
|
pub struct TimingConfig {
|
||||||
/// The baudrate prescaler is used to determine the period of each time
|
/// The baudrate prescaler is used to determine the period of each time
|
||||||
/// quantum by dividing the TWAI controller's source clock.
|
/// quantum by dividing the TWAI controller's source clock.
|
||||||
@ -635,6 +642,8 @@ pub struct TimingConfig {
|
|||||||
/// A selection of pre-determined baudrates for the TWAI driver.
|
/// A selection of pre-determined baudrates for the TWAI driver.
|
||||||
/// Currently these timings are sourced from the ESP IDF C driver which assumes
|
/// Currently these timings are sourced from the ESP IDF C driver which assumes
|
||||||
/// an APB clock of 80MHz.
|
/// an APB clock of 80MHz.
|
||||||
|
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
pub enum BaudRate {
|
pub enum BaudRate {
|
||||||
/// A baud rate of 125 Kbps.
|
/// A baud rate of 125 Kbps.
|
||||||
B125K,
|
B125K,
|
||||||
@ -691,10 +700,10 @@ impl BaudRate {
|
|||||||
#[cfg(esp32h2)]
|
#[cfg(esp32h2)]
|
||||||
let timing = match self {
|
let timing = match self {
|
||||||
Self::B125K => TimingConfig {
|
Self::B125K => TimingConfig {
|
||||||
baud_rate_prescaler: 8,
|
baud_rate_prescaler: 16,
|
||||||
sync_jump_width: 3,
|
sync_jump_width: 3,
|
||||||
tseg_1: 23,
|
tseg_1: 11,
|
||||||
tseg_2: 8,
|
tseg_2: 4,
|
||||||
triple_sample: false,
|
triple_sample: false,
|
||||||
},
|
},
|
||||||
Self::B250K => TimingConfig {
|
Self::B250K => TimingConfig {
|
||||||
@ -772,17 +781,20 @@ where
|
|||||||
.modify(|r, w| unsafe { w.bits(r.bits() | 0x80) });
|
.modify(|r, w| unsafe { w.bits(r.bits() | 0x80) });
|
||||||
}
|
}
|
||||||
|
|
||||||
if no_transceiver {
|
let rx_pull = if no_transceiver {
|
||||||
tx_pin.set_to_open_drain_output(crate::private::Internal);
|
tx_pin.set_to_open_drain_output(crate::private::Internal);
|
||||||
|
tx_pin.pull_direction(Pull::Up, crate::private::Internal);
|
||||||
|
Pull::Up
|
||||||
} else {
|
} else {
|
||||||
tx_pin.set_to_push_pull_output(crate::private::Internal);
|
tx_pin.set_to_push_pull_output(crate::private::Internal);
|
||||||
}
|
Pull::None
|
||||||
|
};
|
||||||
tx_pin.connect_peripheral_to_output(T::OUTPUT_SIGNAL, crate::private::Internal);
|
tx_pin.connect_peripheral_to_output(T::OUTPUT_SIGNAL, crate::private::Internal);
|
||||||
|
|
||||||
// Setting up RX pin later allows us to use a single pin in tests.
|
// Setting up RX pin later allows us to use a single pin in tests.
|
||||||
// `set_to_push_pull_output` disables input, here we re-enable it if rx_pin
|
// `set_to_push_pull_output` disables input, here we re-enable it if rx_pin
|
||||||
// uses the same GPIO.
|
// uses the same GPIO.
|
||||||
rx_pin.init_input(Pull::None, crate::private::Internal);
|
rx_pin.init_input(rx_pull, crate::private::Internal);
|
||||||
rx_pin.connect_input_to_peripheral(T::INPUT_SIGNAL, crate::private::Internal);
|
rx_pin.connect_input_to_peripheral(T::INPUT_SIGNAL, crate::private::Internal);
|
||||||
|
|
||||||
// Freeze REC by changing to LOM mode
|
// Freeze REC by changing to LOM mode
|
||||||
@ -843,17 +855,21 @@ where
|
|||||||
|
|
||||||
#[cfg(esp32)]
|
#[cfg(esp32)]
|
||||||
{
|
{
|
||||||
|
// From <https://github.com/espressif/esp-idf/blob/6e5a178b3120dced7fa5c29c655cc22ea182df3d/components/soc/esp32/register/soc/twai_struct.h#L79>
|
||||||
|
// and <https://github.com/espressif/esp-idf/blob/6e5a178b3120dced7fa5c29c655cc22ea182df3d/components/hal/esp32/include/hal/twai_ll.h#L528-L534>:
|
||||||
if timing.baud_rate_prescaler > 128 {
|
if timing.baud_rate_prescaler > 128 {
|
||||||
// Enable /2 baudrate divider
|
// Enable /2 baudrate divider by setting `brp_div`.
|
||||||
|
// `brp_div` is not an interrupt, it will prescale BRP by 2. Only available on
|
||||||
|
// ESP32 Revision 2 or later. Reserved otherwise.
|
||||||
T::register_block()
|
T::register_block()
|
||||||
.int_ena()
|
.int_ena()
|
||||||
.modify(|r, w| unsafe { w.bits(r.bits() | 0x08) });
|
.modify(|r, w| unsafe { w.bits(r.bits() | 0x10) });
|
||||||
prescaler = timing.baud_rate_prescaler / 2;
|
prescaler = timing.baud_rate_prescaler / 2;
|
||||||
} else {
|
} else {
|
||||||
// Disable /2 baudrate divider
|
// Disable /2 baudrate divider by clearing brp_div.
|
||||||
T::register_block()
|
T::register_block()
|
||||||
.int_ena()
|
.int_ena()
|
||||||
.modify(|r, w| unsafe { w.bits(r.bits() & !0xF7) });
|
.modify(|r, w| unsafe { w.bits(r.bits() & !0x10) });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -875,6 +891,11 @@ where
|
|||||||
w.time_seg2().bits(tseg_2);
|
w.time_seg2().bits(tseg_2);
|
||||||
w.time_samp().bit(triple_sample)
|
w.time_samp().bit(triple_sample)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// disable CLKOUT
|
||||||
|
T::register_block()
|
||||||
|
.clock_divider()
|
||||||
|
.modify(|_, w| w.clock_off().set_bit());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set up the acceptance filter on the device.
|
/// Set up the acceptance filter on the device.
|
||||||
@ -1491,6 +1512,7 @@ pub trait Instance: crate::private::Sealed {
|
|||||||
|
|
||||||
let is_standard_format = data_0 & 0b1 << 7 == 0;
|
let is_standard_format = data_0 & 0b1 << 7 == 0;
|
||||||
let is_data_frame = data_0 & 0b1 << 6 == 0;
|
let is_data_frame = data_0 & 0b1 << 6 == 0;
|
||||||
|
let self_reception = data_0 & 0b1 << 4 != 0;
|
||||||
let dlc = data_0 & 0b1111;
|
let dlc = data_0 & 0b1111;
|
||||||
|
|
||||||
if dlc > 8 {
|
if dlc > 8 {
|
||||||
@ -1528,11 +1550,12 @@ pub trait Instance: crate::private::Sealed {
|
|||||||
(id, register_block.data_5().as_ptr())
|
(id, register_block.data_5().as_ptr())
|
||||||
};
|
};
|
||||||
|
|
||||||
let frame = if is_data_frame {
|
let mut frame = if is_data_frame {
|
||||||
unsafe { EspTwaiFrame::new_from_data_registers(id, data_ptr, dlc) }
|
unsafe { EspTwaiFrame::new_from_data_registers(id, data_ptr, dlc) }
|
||||||
} else {
|
} else {
|
||||||
EspTwaiFrame::new_remote(id, dlc).unwrap()
|
EspTwaiFrame::new_remote(id, dlc).unwrap()
|
||||||
};
|
};
|
||||||
|
frame.self_reception = self_reception;
|
||||||
|
|
||||||
// Release the packet we read from the FIFO, allowing the peripheral to prepare
|
// Release the packet we read from the FIFO, allowing the peripheral to prepare
|
||||||
// the next packet.
|
// the next packet.
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
//! This example demonstrates use of the twai peripheral running the embassy
|
//! This example demonstrates use of the TWAI peripheral running the embassy
|
||||||
//! executor and asynchronously receiving and transmitting twai frames.
|
//! executor and asynchronously receiving and transmitting TWAI frames.
|
||||||
//!
|
//!
|
||||||
//! The `receiver` task waits to receive a frame and puts it into a channel
|
//! The `receiver` task waits to receive a frame and puts it into a channel
|
||||||
//! which will be picked up by the `transmitter` task.
|
//! which will be picked up by the `transmitter` task.
|
||||||
@ -8,13 +8,23 @@
|
|||||||
//! it.
|
//! it.
|
||||||
//!
|
//!
|
||||||
//! This example should work with another ESP board running the `twai` example
|
//! This example should work with another ESP board running the `twai` example
|
||||||
//! with `IS_SENDER` set to `true`.
|
//! with `IS_FIRST_SENDER` set to `true`.
|
||||||
//!
|
//!
|
||||||
//! The following wiring is assumed:
|
//! The following wiring is assumed:
|
||||||
//! - TX => GPIO0
|
//! - TX/RX => GPIO2, connected internally and with internal pull-up resistor.
|
||||||
//! - RX => GPIO2
|
//!
|
||||||
|
//! ESP1/GND --- ESP2/GND
|
||||||
|
//! ESP1/GPIO2 --- ESP2/GPIO2
|
||||||
|
//!
|
||||||
|
//! Notes for external transceiver use:
|
||||||
|
//!
|
||||||
|
//! The default setup assumes that two microcontrollers are connected directly without an external
|
||||||
|
//! transceiver. If you want to use an external transceiver, you need to:
|
||||||
|
//! * uncomment the `rx_pin` line
|
||||||
|
//! * use `new()` function to create the TWAI configuration.
|
||||||
|
//! * change the `tx_pin` and `rx_pin` to the appropriate pins for your boards.
|
||||||
|
|
||||||
//% CHIPS: esp32c3 esp32c6 esp32s2 esp32s3
|
//% CHIPS: esp32 esp32c3 esp32c6 esp32h2 esp32s2 esp32s3
|
||||||
//% FEATURES: embassy embassy-generic-timers
|
//% FEATURES: embassy embassy-generic-timers
|
||||||
|
|
||||||
#![no_std]
|
#![no_std]
|
||||||
@ -29,7 +39,7 @@ use esp_hal::{
|
|||||||
interrupt,
|
interrupt,
|
||||||
peripherals::{self, TWAI0},
|
peripherals::{self, TWAI0},
|
||||||
timer::timg::TimerGroup,
|
timer::timg::TimerGroup,
|
||||||
twai::{self, EspTwaiFrame, TwaiMode, TwaiRx, TwaiTx},
|
twai::{self, EspTwaiFrame, StandardId, TwaiMode, TwaiRx, TwaiTx},
|
||||||
};
|
};
|
||||||
use esp_println::println;
|
use esp_println::println;
|
||||||
use static_cell::StaticCell;
|
use static_cell::StaticCell;
|
||||||
@ -49,7 +59,9 @@ async fn receiver(
|
|||||||
println!("Received a frame:");
|
println!("Received a frame:");
|
||||||
print_frame(&frame);
|
print_frame(&frame);
|
||||||
|
|
||||||
// repeat the frame back
|
// Send a response
|
||||||
|
let frame =
|
||||||
|
EspTwaiFrame::new(StandardId::new(1).unwrap(), &[4, 5, 6, 7, 8]).unwrap();
|
||||||
channel.send(frame).await;
|
channel.send(frame).await;
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
@ -82,6 +94,7 @@ async fn transmitter(
|
|||||||
|
|
||||||
#[esp_hal_embassy::main]
|
#[esp_hal_embassy::main]
|
||||||
async fn main(spawner: Spawner) {
|
async fn main(spawner: Spawner) {
|
||||||
|
esp_println::logger::init_logger_from_env();
|
||||||
let peripherals = esp_hal::init(esp_hal::Config::default());
|
let peripherals = esp_hal::init(esp_hal::Config::default());
|
||||||
|
|
||||||
let timg0 = TimerGroup::new(peripherals.TIMG0);
|
let timg0 = TimerGroup::new(peripherals.TIMG0);
|
||||||
@ -89,21 +102,24 @@ async fn main(spawner: Spawner) {
|
|||||||
|
|
||||||
let io = Io::new(peripherals.GPIO, peripherals.IO_MUX);
|
let io = Io::new(peripherals.GPIO, peripherals.IO_MUX);
|
||||||
|
|
||||||
let can_tx_pin = io.pins.gpio0;
|
let tx_pin = io.pins.gpio2;
|
||||||
let can_rx_pin = io.pins.gpio2;
|
// let rx_pin = io.pins.gpio0; // Uncomment if you want to use an external transceiver.
|
||||||
|
|
||||||
// The speed of the CAN bus.
|
// Without an external transceiver, we only need a single line between the two MCUs.
|
||||||
const CAN_BAUDRATE: twai::BaudRate = twai::BaudRate::B1000K;
|
let rx_pin = tx_pin.peripheral_input(); // Comment this line if you want to use an external transceiver.
|
||||||
|
|
||||||
|
// The speed of the bus.
|
||||||
|
const TWAI_BAUDRATE: twai::BaudRate = twai::BaudRate::B125K;
|
||||||
|
|
||||||
// !!! Use `new_async` when using a transceiver. `new_async_no_transceiver` sets TX to open-drain
|
// !!! Use `new_async` when using a transceiver. `new_async_no_transceiver` sets TX to open-drain
|
||||||
|
|
||||||
// Begin configuring the TWAI peripheral. The peripheral is in a reset like
|
// Begin configuring the TWAI peripheral. The peripheral is in a reset like
|
||||||
// state that prevents transmission but allows configuration.
|
// state that prevents transmission but allows configuration.
|
||||||
let mut can_config = twai::TwaiConfiguration::new_async_no_transceiver(
|
let mut twai_config = twai::TwaiConfiguration::new_async_no_transceiver(
|
||||||
peripherals.TWAI0,
|
peripherals.TWAI0,
|
||||||
can_rx_pin,
|
rx_pin,
|
||||||
can_tx_pin,
|
tx_pin,
|
||||||
CAN_BAUDRATE,
|
TWAI_BAUDRATE,
|
||||||
TwaiMode::Normal,
|
TwaiMode::Normal,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -115,15 +131,15 @@ async fn main(spawner: Spawner) {
|
|||||||
// standard ids of an even value.
|
// standard ids of an even value.
|
||||||
const FILTER: twai::filter::SingleStandardFilter =
|
const FILTER: twai::filter::SingleStandardFilter =
|
||||||
twai::filter::SingleStandardFilter::new(b"xxxxxxxxxx0", b"x", [b"xxxxxxxx", b"xxxxxxxx"]);
|
twai::filter::SingleStandardFilter::new(b"xxxxxxxxxx0", 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
|
// Start the peripheral. This locks the configuration settings of the peripheral
|
||||||
// and puts it into operation mode, allowing packets to be sent and
|
// and puts it into operation mode, allowing packets to be sent and
|
||||||
// received.
|
// received.
|
||||||
let can = can_config.start();
|
let twai = twai_config.start();
|
||||||
|
|
||||||
// Get separate transmit and receive halves of the peripheral.
|
// Get separate transmit and receive halves of the peripheral.
|
||||||
let (rx, tx) = can.split();
|
let (rx, tx) = twai.split();
|
||||||
|
|
||||||
interrupt::enable(
|
interrupt::enable(
|
||||||
peripherals::Interrupt::TWAI0,
|
peripherals::Interrupt::TWAI0,
|
||||||
|
@ -1,23 +1,25 @@
|
|||||||
//! This example sends a TWAI 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 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
|
|
||||||
//!
|
|
||||||
//! The following wiring is assumed:
|
|
||||||
//! - TX => GPIO0
|
|
||||||
//! - RX => GPIO2
|
|
||||||
//!
|
|
||||||
//! ESP1/GND --- ESP2/GND
|
|
||||||
//! ESP1/GPIO0 --- ESP1/GPIO2 --- ESP2/GPIO0 --- ESP2/GPIO2 --- 4.8kOhm --- ESP1/5V
|
|
||||||
//!
|
|
||||||
//! `IS_FIRST_SENDER` below must be set to false on one of the ESP's
|
//! `IS_FIRST_SENDER` below must be set to false on one of the ESP's
|
||||||
//!
|
//!
|
||||||
//! In case you want to use `self-testing`, get rid of everything related to the aforementioned `IS_FIRST_SENDER`
|
//! 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.
|
//! and follow the advice in the comments related to this mode.
|
||||||
|
//!
|
||||||
|
//! The following wiring is assumed:
|
||||||
|
//! - TX/RX => GPIO2, connected internally and with internal pull-up resistor.
|
||||||
|
//!
|
||||||
|
//! ESP1/GND --- ESP2/GND
|
||||||
|
//! ESP1/GPIO2 --- ESP2/GPIO2
|
||||||
|
//!
|
||||||
|
//! Notes for external transceiver use:
|
||||||
|
//!
|
||||||
|
//! The default setup assumes that two microcontrollers are connected directly without an external
|
||||||
|
//! transceiver. If you want to use an external transceiver, you need to:
|
||||||
|
//! * uncomment the `rx_pin` line
|
||||||
|
//! * use `new()` function to create the TWAI configuration.
|
||||||
|
//! * change the `tx_pin` and `rx_pin` to the appropriate pins for your boards.
|
||||||
|
|
||||||
//% CHIPS: esp32c3 esp32c6 esp32h2 esp32s2 esp32s3
|
//% CHIPS: esp32 esp32c3 esp32c6 esp32h2 esp32s2 esp32s3
|
||||||
|
|
||||||
#![no_std]
|
#![no_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
@ -26,6 +28,7 @@ const IS_FIRST_SENDER: bool = true;
|
|||||||
|
|
||||||
use esp_backtrace as _;
|
use esp_backtrace as _;
|
||||||
use esp_hal::{
|
use esp_hal::{
|
||||||
|
delay::Delay,
|
||||||
gpio::Io,
|
gpio::Io,
|
||||||
prelude::*,
|
prelude::*,
|
||||||
twai::{self, filter::SingleStandardFilter, EspTwaiFrame, StandardId, TwaiMode},
|
twai::{self, filter::SingleStandardFilter, EspTwaiFrame, StandardId, TwaiMode},
|
||||||
@ -39,11 +42,14 @@ fn main() -> ! {
|
|||||||
|
|
||||||
let io = Io::new(peripherals.GPIO, peripherals.IO_MUX);
|
let io = Io::new(peripherals.GPIO, peripherals.IO_MUX);
|
||||||
|
|
||||||
let tx_pin = io.pins.gpio0;
|
let tx_pin = io.pins.gpio2;
|
||||||
let rx_pin = io.pins.gpio2;
|
// let rx_pin = io.pins.gpio0; // Uncomment if you want to use an external transceiver.
|
||||||
|
|
||||||
// The speed of the CAN bus.
|
// Without an external transceiver, we only need a single line between the two MCUs.
|
||||||
const TWAI_BAUDRATE: twai::BaudRate = twai::BaudRate::B1000K;
|
let rx_pin = tx_pin.peripheral_input(); // Comment this line if you want to use an external transceiver.
|
||||||
|
|
||||||
|
// The speed of the bus.
|
||||||
|
const TWAI_BAUDRATE: twai::BaudRate = twai::BaudRate::B125K;
|
||||||
|
|
||||||
// !!! Use `new` when using a transceiver. `new_no_transceiver` sets TX to open-drain
|
// !!! Use `new` when using a transceiver. `new_no_transceiver` sets TX to open-drain
|
||||||
// Self-testing also works using the regular `new` function.
|
// Self-testing also works using the regular `new` function.
|
||||||
@ -66,32 +72,33 @@ fn main() -> ! {
|
|||||||
// these partial acceptance filters to exactly match.
|
// these partial acceptance filters to exactly match.
|
||||||
// A filter that matches StandardId::ZERO.
|
// A filter that matches StandardId::ZERO.
|
||||||
twai_config.set_filter(
|
twai_config.set_filter(
|
||||||
const { SingleStandardFilter::new(b"00000000000", b"x", [b"xxxxxxxx", b"xxxxxxxx"]) },
|
const { SingleStandardFilter::new(b"xxxxxxxxxx1", b"x", [b"xxxxxxxx", b"xxxxxxxx"]) },
|
||||||
);
|
);
|
||||||
|
|
||||||
// Start the peripheral. This locks the configuration settings of the peripheral
|
// Start the peripheral. This locks the configuration settings of the peripheral
|
||||||
// and puts it into operation mode, allowing packets to be sent and
|
// and puts it into operation mode, allowing packets to be sent and
|
||||||
// received.
|
// received.
|
||||||
let mut can = twai_config.start();
|
let mut twai = twai_config.start();
|
||||||
|
|
||||||
if IS_FIRST_SENDER {
|
if IS_FIRST_SENDER {
|
||||||
// Send a frame to the other ESP
|
// Send a frame to the other ESP
|
||||||
// Use `new_self_reception` if you want to use self-testing.
|
// Use `new_self_reception` if you want to use self-testing.
|
||||||
let frame = EspTwaiFrame::new(StandardId::ZERO, &[1, 2, 3]).unwrap();
|
let frame = EspTwaiFrame::new(StandardId::ZERO, &[1, 2, 3]).unwrap();
|
||||||
block!(can.transmit(&frame)).unwrap();
|
block!(twai.transmit(&frame)).unwrap();
|
||||||
println!("Sent a frame");
|
println!("Sent a frame");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait for a frame to be received.
|
let delay = Delay::new();
|
||||||
let frame = block!(can.receive()).unwrap();
|
loop {
|
||||||
|
// Wait for a frame to be received.
|
||||||
|
let frame = block!(twai.receive()).unwrap();
|
||||||
|
|
||||||
println!("Received a frame: {frame:?}");
|
println!("Received a frame: {frame:?}");
|
||||||
|
delay.delay_millis(250);
|
||||||
|
|
||||||
if !IS_FIRST_SENDER {
|
let frame = EspTwaiFrame::new(StandardId::ZERO, &[1, 2, 3]).unwrap();
|
||||||
// Transmit the frame back to the other ESP
|
// Transmit a new frame back to the other ESP
|
||||||
block!(can.transmit(&frame)).unwrap();
|
block!(twai.transmit(&frame)).unwrap();
|
||||||
println!("Sent a frame");
|
println!("Sent a frame");
|
||||||
}
|
}
|
||||||
|
|
||||||
loop {}
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user