import can
The can module sends and receives raw 11-bit or 29-bit CAN frames. Use it when you want protocol-level control, custom CAN payloads, or a protocol that is not covered by a higher-level module. For SAE J1939 engine data, use the j1939 module instead. ESP32 and ESP32-S3 include the TWAI controller used here. You still need an external CAN transceiver between the ESP32 TX/RX pins and CANH/CANL.
Quick example
import can
import system
bus = can.CAN(tx=5, rx=4, bitrate=can.BITRATE_500K)
bus.begin()
bus.send(0x123, [1, 2, 3, 4])
def poll():
frame = bus.receive(timeout_ms=0)
if frame != None:
print(frame["id"], frame["data"])
system.schedule("can_poll", 20, 0, -1, poll)
import can
bus = can.CAN(tx=5, rx=4, mode=can.MODE_LISTEN_ONLY)
def on_frame(frame):
print(frame["id"], frame["dlc"], frame["data"])
bus.set_filter(id=0x100, mask=0x700)
bus.on_receive(on_frame)
bus.begin()
importcan
Raw CAN 2.0 bus access over the ESP32 TWAI controller.
The can module sends and receives raw 11-bit or 29-bit CAN frames. Use it when you want protocol-level control, custom CAN payloads, or a protocol that is not covered by a higher-level module. For SAE J1939 engine data, use the j1939 module instead. ESP32 and ESP32-S3 include the TWAI controller used here. You still need an external CAN transceiver between the ESP32 TX/RX pins and CANH/CANL.
can.CAN(tx: int, rx: int, bitrate: int = None, mode: str = None, rx_queue: int = None, tx_queue: int = None) -> can_bus
can.CAN(tx: int, rx: int, bitrate: int = None, mode: str = None, rx_queue: int = None, tx_queue: int = None) -> can_busCreate a raw CAN bus object.
Creating the object does not start the TWAI controller. Call ``begin()`` before sending or receiving frames. Only one raw CAN/J1939 TWAI owner should run at a time because the hardware controller is shared.
| Name | Type | Pass as | Required | Description |
|---|---|---|---|---|
tx |
int |
positional or keyword | Yes | ESP32 TWAI transmit GPIO connected to the CAN transceiver TXD pin. |
rx |
int |
positional or keyword | Yes | ESP32 TWAI receive GPIO connected to the CAN transceiver RXD pin. |
bitrate |
int |
positional or keyword | No | Optional CAN bitrate in bits per second. Defaults to can.BITRATE_500K. |
mode |
str |
positional or keyword | No | Optional controller mode. Use can.MODE_NORMAL, can.MODE_LISTEN_ONLY, or can.MODE_NO_ACK. |
rx_queue |
int |
positional or keyword | No | Optional receive queue depth for polling frames. Defaults to 32. |
tx_queue |
int |
positional or keyword | No | Optional transmit queue depth for outgoing frames. Defaults to 16. |
can_bus can_bus object.
can.CAN().begin() -> bool
can.CAN().begin() -> boolStart the TWAI controller and receive task.
can.CAN().stop() -> bool
can.CAN().stop() -> boolStop the bus, receive task, and TWAI driver.
can.CAN().is_running() -> bool
can.CAN().is_running() -> boolReturn True when the TWAI controller is active.
can.CAN().send(id, data, extended=False, rtr=False, timeout_ms=0) -> bool
can.CAN().send(id, data, extended=False, rtr=False, timeout_ms=0) -> boolSend one raw CAN frame. data may be a list of 0 to 8 byte values or a byte-like string.
| Name | Type | Pass as | Required | Description |
|---|---|---|---|---|
id |
any |
positional or keyword | Yes | Required value. |
data |
any |
positional or keyword | Yes | Required value. |
extended |
bool |
positional or keyword | No | Optional value. Defaults to False. |
rtr |
bool |
positional or keyword | No | Optional value. Defaults to False. |
timeout_ms |
int |
positional or keyword | No | Optional value. Defaults to 0. |
can.CAN().send_frame(frame, timeout_ms=0) -> bool
can.CAN().send_frame(frame, timeout_ms=0) -> boolSend a frame dict created by can.Frame() or returned by receive().
| Name | Type | Pass as | Required | Description |
|---|---|---|---|---|
frame |
any |
positional or keyword | Yes | Required value. |
timeout_ms |
int |
positional or keyword | No | Optional value. Defaults to 0. |
can.CAN().receive(timeout_ms=0) -> dict
can.CAN().receive(timeout_ms=0) -> dictReturn the next received frame dict, or None when no frame arrives before the timeout.
| Name | Type | Pass as | Required | Description |
|---|---|---|---|---|
timeout_ms |
int |
positional or keyword | No | Optional value. Defaults to 0. |
can.CAN().available() -> int
can.CAN().available() -> intReturn the number of queued frames available for polling.
can.CAN().on_receive(callback) -> bool
can.CAN().on_receive(callback) -> boolRegister a callback that receives each frame dict. Pass None to clear it. Do not mix callback and polling for the same bus.
| Name | Type | Pass as | Required | Description |
|---|---|---|---|---|
callback |
callback |
positional or keyword | Yes | Required value. |
can.CAN().set_filter(id, mask, extended=False) -> bool
can.CAN().set_filter(id, mask, extended=False) -> boolAccept frames where (frame_id & mask) equals (id & mask).
| Name | Type | Pass as | Required | Description |
|---|---|---|---|---|
id |
any |
positional or keyword | Yes | Required value. |
mask |
int |
positional or keyword | Yes | Required value. |
extended |
bool |
positional or keyword | No | Optional value. Defaults to False. |
can.CAN().set_filters(filters) -> bool
can.CAN().set_filters(filters) -> boolReplace software filters with a list of filter dicts containing id, mask, and optional extended.
| Name | Type | Pass as | Required | Description |
|---|---|---|---|---|
filters |
any |
positional or keyword | Yes | Required value. |
can.CAN().clear_filters() -> bool
can.CAN().clear_filters() -> boolAccept all incoming frames again.
can.CAN().flush(timeout_ms=1000) -> bool
can.CAN().flush(timeout_ms=1000) -> boolWait for the transmit queue to drain.
| Name | Type | Pass as | Required | Description |
|---|---|---|---|---|
timeout_ms |
int |
positional or keyword | No | Optional value. Defaults to 1000. |
can.CAN().clear_rx() -> bool
can.CAN().clear_rx() -> boolDrop queued receive frames.
can.CAN().state() -> str
can.CAN().state() -> strReturn stopped, running, warning, passive, bus_off, or recovering.
can.CAN().recover(timeout_ms=2000) -> bool
can.CAN().recover(timeout_ms=2000) -> boolAttempt TWAI bus-off recovery and wait for running state.
| Name | Type | Pass as | Required | Description |
|---|---|---|---|---|
timeout_ms |
int |
positional or keyword | No | Optional value. Defaults to 2000. |
can.CAN().stats() -> dict
can.CAN().stats() -> dictReturn tx_sent, tx_failed, rx_received, rx_dropped, rx_filtered, tx_queued, rx_queued, tx_error_count, rx_error_count, bus_errors, arbitration_lost, bus_off_count, state, running, bitrate, mode, tx, and rx.
can.CAN().reset_stats() -> bool
can.CAN().reset_stats() -> boolReset module-level counters.
can.CAN().on_state(callback) -> bool
can.CAN().on_state(callback) -> boolRegister a callback that receives the state string when it changes. Pass None to clear it.
| Name | Type | Pass as | Required | Description |
|---|---|---|---|---|
callback |
callback |
positional or keyword | Yes | Required value. |
can.Frame(id: any, data: list = None, extended: bool = None, rtr: bool = None, dlc: any = None) -> dict
can.Frame(id: any, data: list = None, extended: bool = None, rtr: bool = None, dlc: any = None) -> dictCreate a raw CAN frame dict.
| Name | Type | Pass as | Required | Description |
|---|---|---|---|---|
id |
any |
positional or keyword | Yes | CAN identifier. Use 0x000 to 0x7ff for standard frames or 0x00000000 to 0x1fffffff for extended frames. |
data |
list |
positional or keyword | No | Optional payload list containing 0 to 8 byte values. Defaults to []. |
extended |
bool |
positional or keyword | No | Optional bool. Use True for 29-bit CAN identifiers. |
rtr |
bool |
positional or keyword | No | Optional bool. Use True for a remote transmission request frame. |
dlc |
any |
positional or keyword | No | Optional data length code. Defaults to the payload length. |
dict dict with id, data, dlc, extended, rtr, and timestamp_ms.