Closed jessebraham closed 6 days ago
This is awesome !. I'm about to start a (Rust) project which requires TWAI (for connection to NEMA2000), on some existing ESP32 hardware. Is there an ETA for the next release ?
There are at least a couple smaller tasks that will need to be done first, but I imagine we should be able to publish new releases at some point in January. I will be back at work next week so I will evaluate where we stand at that time.
ESP32-S3 support was added in #325.
I will add support for the remaining two chips.
The ESP32-C6 seems to fail in the same way that the ESP32 and ESP32-S2 do, so this will need to be investigated as well.
I have an ESP32-C6 dev board and a motor controller with which i communicate via TWAI if you need to test anything
@noonien I think all the necessary cfg
s are in place for the ESP32-C6, I had the twai.rs
example in my local branch and while it built and ran on the device, I was not able to send/receive any data. You should be able to copy the twai.rs
example from another chip's HAL and make the necessary changes to get things building. If you were willing to look into that it would be appreciated, otherwise I'm sure somebody will get to it eventually 😁
While I was on it, I looked into ESP32 without any luck. There are quite a few chapters in the ESP32 Errata document and also esp-idf seems to include some workarounds. I tried to replicate them but no luck.
H2 would hopefully mostly just involve renaming registers/fields to match C6 and some magic applied to the pre-scaler value
I tried to send out frames periodically in the experiment code: https://github.com/zephyr-atomi/esp32-weather-kit/blob/main/examples/can_exp.rs, but don't get any signal out on GPIO 1 (TX) of my ESP32C3 board(made by WeAct). The baudrate is set as 10Kbps.
The CAN-bus runs correctly, I can see other CAN frames on it by other devices, and I assume my connection is correct. (I enabled RP2040 with CAN2040 and STM32F103 on the CANbus, both works correctly).
Please let me know anything wrong on my code. Thanks!
I also experienced problems with GPIO 1 while others work fine: https://github.com/esp-rs/esp-hal/issues/1207#issuecomment-1971291234
GPIO1 is default UART TX, meaning any logging done can corrupt the TWAI frames. I'm not sure what the best way of converying this information is, any logging via esp_println
through the UART will go over any abstraction we have in the HAL.
Ah it's C3 .... UART0 is GPIO20/21 then. I had problems with GPIO 1 and TWAI there
I'm trying Macchina A0 (which I believe is esp32
)
https://github.com/rnd-ash/Macchina-J2534/blob/main/firmware/custom_can.cpp#L57-L58
Unless I'm doing something horribly wrong, there's something wrong with the timing/registers/interrupt/something... I tell it "send 0x7E0 02 3E 00 55 55 55 55 55" and across the wire I see all sorts of different arbitration IDs come across "invalid" as if they got corrupted (0x1DA, 0x3DA, etc.)
#![no_std]
#![no_main]
#![feature(type_alias_impl_trait)]
use embassy_executor::Spawner;
use embassy_sync::{blocking_mutex::raw::NoopRawMutex, channel::Channel};
use embassy_time::{Duration, Timer};
use embedded_can::{Frame, Id, StandardId};
use esp_backtrace as _;
use esp_hal::{
clock::ClockControl,
embassy,
gpio::IO,
interrupt,
peripherals::{self, Peripherals, TWAI0},
prelude::*,
timer::TimerGroup,
twai::{self, filter::SingleStandardFilter, EspTwaiFrame, TwaiRx, TwaiTx},
};
use esp_println::{print, println};
use static_cell::make_static;
type TwaiOutbox = Channel<NoopRawMutex, EspTwaiFrame, 16>;
#[embassy_executor::task]
async fn run(channel: &'static TwaiOutbox) {
loop {
let frame = Frame::new(
Id::Standard(StandardId::new(0x7e0).unwrap()),
&[0x02, 0x3e, 0x00, 0x55, 0x55, 0x55, 0x55, 0x55],
)
.unwrap();
channel.send(frame).await;
Timer::after(Duration::from_millis(1_000)).await;
}
}
#[embassy_executor::task]
async fn receiver(
mut rx: TwaiRx<'static, TWAI0, esp_hal::Async>,
) -> ! {
loop {
let frame = rx.receive_async().await;
match frame {
Ok(frame) => {
println!("Received a frame:");
}
Err(e) => {
println!("Receive error: {:?}", e);
}
}
Timer::after(Duration::from_millis(1_000)).await;
}
}
#[embassy_executor::task]
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;
match result {
Ok(()) => {
print!("Transmitted a frame: ");
print!("frame.id = {:?} ", frame.id());
print!("frame.dlc = {:?} ", frame.dlc());
print!("frame.data = {:02x?}", frame.data());
println!("");
}
Err(e) => {
println!("Transmit error: {:?}", e);
}
}
}
}
#[main]
async fn main(spawner: Spawner) {
esp_println::println!("Init!");
let peripherals = Peripherals::take();
let system = peripherals.SYSTEM.split();
let clocks = ClockControl::boot_defaults(system.clock_control).freeze();
let timg0 = TimerGroup::new_async(peripherals.TIMG0, &clocks);
embassy::init(&clocks, timg0);
let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);
// Need to pull down GPIO 21 to unset the "S" (Silent Mode) pin on CAN Xceiver.
let mut gpio21 = io.pins.gpio21.into_push_pull_output();
gpio21.set_low();
let can_rx_pin = io.pins.gpio4;
let can_tx_pin = io.pins.gpio5;
let can_baudrate = twai::BaudRate::B500K;
let can_filter = SingleStandardFilter::new(b"xxxxxxxxxxx", b"x", [b"xxxxxxxx", b"xxxxxxxx"]);
let mut can_config = twai::TwaiConfiguration::new_async(
peripherals.TWAI0,
can_tx_pin,
can_rx_pin,
&clocks,
can_baudrate,
);
can_config.set_filter(can_filter);
let can_driver = can_config.start();
let (can_tx, can_rx) = can_driver.split();
interrupt::enable(
peripherals::Interrupt::TWAI0,
interrupt::Priority::Priority1,
)
.unwrap();
let channel = &*make_static!(Channel::new());
spawner.spawn(receiver(can_rx)).ok();
spawner.spawn(transmitter(can_tx, channel)).ok();
spawner.spawn(run(channel)).ok();
loop {
Timer::after(Duration::from_millis(1_000)).await;
}
}
[package]
name = "esp32_can_dongle"
version = "0.1.0"
edition = "2021"
[features]
esp32 = ["esp-hal/esp32", "esp-backtrace/esp32", "esp-println/esp32", "esp-hal-smartled/esp32"]
embassy = ["esp-hal/embassy"]
embassy-time-timg0 = ["esp-hal/embassy-time-timg0"]
embassy-executor-thread = ["esp-hal/embassy-executor-thread"]
embassy-generic-timers = ["embassy-time/generic-queue-8"]
async = ["esp-hal/async"]
default = ["esp32", "embassy", "embassy-time-timg0", "embassy-executor-thread", "embassy-generic-timers", "async"]
[dependencies]
esp-hal = { version = "0.17.0", features = ["log"] }
esp-hal-smartled = { version = "0.10.0" }
esp-backtrace = { version = "0.11.1", features = ["exception-handler", "panic-handler", "println"] }
esp-println = { version = "0.9.1", features = ["log"] }
embassy-executor = { version = "0.5.0", features = ["task-arena-size-40960"] }
embassy-sync = "0.5.0"
embassy-time = "0.3.0"
embedded-can = "0.4.1"
static_cell = { version = "2.0.0", features = ["nightly"] }
[profile.release]
codegen-units = 1
debug = 2
debug-assertions = false
incremental = false
opt-level = 3
lto = 'fat'
overflow-checks = false
Is it something I'm doing, is my device going bad/dying, or are the libraries just not ready for usage yet for this device?
Ah it's C3 .... UART0 is GPIO20/21 then. I had problems with GPIO 1 and TWAI there
Also discovered that this is the case for the C6 too. Pin 0 and 1 can be TWAI Tx but neither can be TWAI Rx.
Works fine on esp-idf-hal.
Tested today on the S3, it does not work
Tested today on the S3, it does not work
Did you test with transceivers or without? Last time I tested it, I used transceivers but long time since I last tried it
Tested today on the S3, it does not work
Did you test with transceivers or without? Last time I tested it, I used transceivers but long time since I last tried it
I used transceivers. Tested on a live CAN bus with traffic, with esp-hal
0.18.0, also tested with a C/C++ based (ESP-IDF) CAN example. The IDF one works. I can test again tomorrow with main
.
I believe this issue encountered by @rand12345 and @brandonros is also fixed by #1906, TWAI works by accident for some pins because these pins are previously configured as input/output 🫠
With #192 merged we now have a TWAI driver for the ESP32-C3. We should support all remaining devices as well before our next release is published. This can be done all in one swing or with a PR per device, doesn't matter. At the time of writing the ESP32-C2 is the only supported device which does not have TWAI.
In addition to supporting all devices, it would be ideal to convert the example to a "self test", not requiring any external hardware. There is an example in ESP-IDF which does just this, and can be found here. We generally prefer to avoid requiring external hardware whenever possible (I2C being the lone exception) so ideally this peripheral should be no different. If this is not possible/feasible then two ESPs talking to each other would also be an acceptable solution.