Skip to content

Commit 863b9fd

Browse files
Юрий МакаровЮрий
authored andcommitted
ports/esp32/esp32_can: Add CAN bus support.
CAN bus for esp32 controller.
1 parent 05bb260 commit 863b9fd

16 files changed

+1464
-0
lines changed

docs/esp32/img/twai_blockdiag.png

9.92 KB
Loading

docs/esp32/quickref.rst

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -558,6 +558,31 @@ users is encouraged. Based on this feedback, the I2S class API and implementati
558558

559559
ESP32 has two I2S buses with id=0 and id=1
560560

561+
CAN bus
562+
-------
563+
564+
See :ref:`esp32.CAN <esp32.CAN>`
565+
566+
The CAN driver is based on hardware implementation.
567+
Any available output-capablepins can be used for TX, RX, BUS-OFF, and CLKOUT signal lines.
568+
569+
.. image:: img/twai_blockdiag.png
570+
571+
The driver is accessed via the :ref:`esp32.CAN <esp32.CAN>` class::
572+
573+
from esp32 import CAN
574+
can = CAN(0, tx=5, rx=4, mode=CAN.NORMAL, baudrate=500000)
575+
can.setfilter(0, CAN.FILTER_ADDRESS, params=[0x123], extframe=False) # set a filter to receive messages with id = 0x102
576+
can.send([1,2,3], 0x102, extframe=False) # send a message with id 123
577+
can.recv() # receive message
578+
579+
can.any() # returns True if there are any message to receive
580+
can.info() # get information about the controller’s error states and TX and RX buffers
581+
can.deinit() # turn off the can bus
582+
can.clear_rx_queue() # clear messages in the FIFO
583+
can.clear_tx_queue() # clear messages in the transmit buffer
584+
585+
561586
Real time clock (RTC)
562587
---------------------
563588

docs/library/esp32.rst

Lines changed: 262 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -351,3 +351,265 @@ supports 32-bit signed integers and blobs.
351351
.. method:: NVS.commit()
352352

353353
Commits changes made by *set_xxx* methods to flash.
354+
355+
.. _esp32.CAN:
356+
357+
class CAN -- controller area network communication bus
358+
======================================================
359+
360+
CAN implements the standard CAN communications protocol. At
361+
the physical level it consists of 2 lines: RX and TX. Note that
362+
to connect the microcontroller to a CAN bus you must use a CAN transceiver
363+
to convert the CAN logic signals from the microcontroller to the correct
364+
voltage levels on the bus.
365+
366+
Example usage (works without anything connected)::
367+
368+
from esp32 import CAN
369+
BAUDRATE_500k = 500000
370+
can = CAN(0, tx=5, rx=4, mode=CAN.NORMAL, baudrate=BAUDRATE_500k)
371+
can.setfilter(0, CAN.FILTER_ADDRESS, params=[0x123], extframe=False) # set a filter to receive messages with id = 0x102
372+
can.send([1,2,3], 0x102, extframe=False) # send a message with id 123
373+
if can.any():
374+
can.recv() # receive message
375+
376+
377+
Constructors
378+
------------
379+
380+
.. class:: esp32.CAN(bus, ...)
381+
382+
Construct a CAN object on the given bus(controller). *bus* must be 0 for ESP32.
383+
With no additional parameters, the CAN object is created but not
384+
initialised (it has the settings from the last initialisation of
385+
the bus, if any). If extra arguments are given, the bus is initialised.
386+
See :meth:`CAN.init` for parameters of initialisation.
387+
388+
The physical pins of the CAN bus can be assigned during init.
389+
390+
Methods
391+
-------
392+
393+
.. method:: CAN.init(mode, *, tx=5, rx=4, baudrate=500000, prescaler=8, sjw=3, bs1=15, bs2=4, auto_restart=False, tx_queue=1, rx_queue=1)
394+
395+
Initialise the CAN bus with the given parameters:
396+
397+
- *mode* is one of: NORMAL, LOOPBACK, SILENT, SILENT_LOOPBACK
398+
- *tx* defines the gpio used for transmission
399+
- *rx* defines the gpio used for receiving
400+
- *baudrate* is used to define a standard speed. If it is defined, the *prescaler*, *sjw*, *bs1*, *bs2*
401+
will be ignored. Standard speeds are 25000, 50000, 100000, 125000, 250000, 500000, 1000000. Some versions
402+
of esp32 supports non-standard speeds: 1000, 5000, 10000, 12500, 16000, 20000.
403+
- *prescaler* is used to set the duration of 1 time quanta; the time quanta
404+
will be the input clock divided by the prescaler
405+
- *sjw* is the resynchronisation jump width in units of the time quanta;
406+
it can be 1, 2, 3, 4
407+
- *bs1* defines the location of the sample point in units of the time quanta;
408+
it can be between 1 and 1024 inclusive
409+
- *bs2* defines the location of the transmit point in units of the time quanta;
410+
it can be between 1 and 16 inclusive
411+
- *bus_off* defines the gpio used for BUS-OFF signal line(optional)
412+
- *clkout* defines the gpio used for CLKOUT signal line(optional)
413+
- *tx_queue* defines the number of waiting tx messages can be stored
414+
- *rx_queue* defines the number of received messages can be stored
415+
- *auto_restart* sets whether the controller will automatically try and restart
416+
communications after entering the bus-off state; if this is disabled then
417+
:meth:`~CAN.restart()` can be used to leave the bus-off state.
418+
This parameter is currently not implemented and it must be set to False
419+
420+
421+
.. method:: CAN.deinit()
422+
423+
Turn off the CAN bus.
424+
425+
.. method:: CAN.restart()
426+
427+
Force a software restart of the CAN controller without resetting its
428+
configuration.
429+
430+
If the controller enters the bus-off state then it will no longer participate
431+
in bus activity. If the controller is not configured to automatically restart
432+
(see :meth:`~CAN.init()`) then this method can be used to trigger a restart,
433+
and the controller will follow the CAN protocol to leave the bus-off state and
434+
go into the error active state.
435+
436+
.. method:: CAN.state()
437+
438+
Return the state of the controller. The return value can be one of:
439+
440+
- ``CAN.STOPPED`` -- the controller is completely off and reset;
441+
- ``CAN.ERROR_ACTIVE`` -- the controller is on and in the Error Active state
442+
(both TEC and REC are less than 96);
443+
- ``CAN.BUS_OFF`` -- the controller is on but not participating in bus activity
444+
(TEC overflowed beyond 255).
445+
- ``CAN.RECOVERING`` -- the controller is under recover from bus-off state;
446+
447+
448+
.. method:: CAN.info()
449+
450+
Get information about the controller's error states and TX and RX buffers.
451+
If *list* is provided then it should be a list object with at least 8 entries,
452+
which will be filled in with the information. Otherwise a new list will be
453+
created and filled in. In both cases the return value of the method is the
454+
populated list.
455+
456+
The values in the list are:
457+
458+
- TEC value
459+
- REC value
460+
- number of times the controller enterted the Error Warning state (wrapped around to 0 after 65535)
461+
- number of times the controller enterted the Error Passive state (wrapped around to 0 after 65535)
462+
- number of times the controller enterted the Bus Off state (wrapped around to 0 after 65535)
463+
- number of pending TX messages
464+
- number of pending RX messages
465+
466+
467+
.. method:: CAN.setfilter(bank, mode, params, *, rtr=False, extframe=False)
468+
469+
Configure a filter bank:
470+
471+
- *bank* is the filter bank that is to be configured (esp32 supports only 0 bank)
472+
- *mode* is the mode the filter should operate in.
473+
- *params* is an array of values the defines the filter.
474+
The contents of the array depends on the *mode* and *extframe* arguments.
475+
476+
+-----------------------+----------------------------------------------------------------------------+
477+
| *mode* | contents of *params* array |
478+
+=======================+============================================================================+
479+
| CAN.FILTER_RAW_SINGLE | *params* will be copied in hardware variable |
480+
| | and single_filter_mode will be selected |
481+
| | In this mode, *bank* will be ignored |
482+
+-----------------------+----------------------------------------------------------------------------+
483+
| CAN.FILTER_RAW_DUAL | *params* will be copied in hardware variable |
484+
| | and single_filter_mode will be cleared |
485+
| | In this mode, *bank* will be ignored |
486+
+-----------------------+----------------------------------------------------------------------------+
487+
| CAN.FILTER_ADDRESS | *params* could be: |
488+
| | |
489+
| | If ``extframe=True`` and *params* length of 1 -- filter 29 bit identifier |
490+
| | of message. |
491+
| | |
492+
| | if ``extframe=False``: |
493+
| | |
494+
| | * length of 1 filter 11 bit identifier of message |
495+
| | * length of 2 filter 11 bit identifier and first byte of message |
496+
| | * length of 3 filter 11 bit identifier first and second bytes of message |
497+
+-----------------------+----------------------------------------------------------------------------+
498+
499+
- *rtr* For classic CAN controllers, this is an array of booleans that states if
500+
a filter should accept a remote transmission request message. If this argument
501+
is not given then it defaults to ``False`` for all entries.
502+
503+
.. method:: CAN.clearfilter(bank)
504+
505+
Clear and disables all filters
506+
507+
.. method:: CAN.any(fifo)
508+
509+
Return ``True`` if any message waiting on the FIFO, else ``False``.
510+
511+
.. method:: CAN.recv(list=None, *, timeout=5000)
512+
513+
Receive data on the bus:
514+
515+
- *list* is an optional list object to be used as the return value
516+
- *timeout* is the timeout in milliseconds to wait for the receive.
517+
518+
Return value: A tuple containing four values.
519+
520+
- The id of the message.
521+
- A boolean that indicates if the message is an RTR message.
522+
- Reserved.
523+
- An array containing the data.
524+
525+
If *list* is ``None`` then a new tuple will be allocated, as well as a new
526+
bytes object to contain the data (as the fourth element in the tuple).
527+
528+
If *list* is not ``None`` then it should be a list object with at least four
529+
elements. The fourth element should be a memoryview object which is created
530+
from either a bytearray or an array of type 'B' or 'b', and this array must
531+
have enough room for at least 8 bytes. The list object will then be
532+
populated with the first three return values above, and the memoryview object
533+
will be resized inplace to the size of the data and filled in with that data.
534+
The same list and memoryview objects can be reused in subsequent calls to
535+
this method, providing a way of receiving data without using the heap.
536+
For example::
537+
538+
buf = bytearray(8)
539+
lst = [0, 0, 0, memoryview(buf)]
540+
# No heap memory is allocated in the following call
541+
can.recv(lst, timeout=0)
542+
543+
*list* values are:
544+
545+
- identifier of can packet (int)
546+
- extended packet (bool)
547+
- rtr packet (bool)
548+
- data frame (0..8 bytes)
549+
550+
551+
.. method:: CAN.send(data, id, *, timeout=0, rtr=False, extframe=false)
552+
553+
Send a message on the bus:
554+
555+
- *data* is the data to send (an integer to send, or a buffer object).
556+
- *id* is the id of the message to be sent.
557+
- *timeout* is the timeout in milliseconds to wait for the send.
558+
- *rtr* is a boolean that specifies if the message shall be sent as
559+
a remote transmission request. If *rtr* is True then only the length
560+
of *data* is used to fill in the DLC slot of the frame; the actual
561+
bytes in *data* are unused.
562+
563+
If timeout is 0 the message is placed in a buffer and the method returns
564+
immediately. If all three buffers are in use an exception is thrown.
565+
If timeout is not 0, the method waits until the message is transmitted.
566+
If the message can't be transmitted within the specified time an exception
567+
is thrown.
568+
569+
Return value: ``None``.
570+
571+
.. method:: CAN.clear_tx_queue()
572+
573+
Clear all messages from transmitting queue.
574+
575+
.. method:: CAN.clear_rx_queue()
576+
577+
Clear all messages from receiving queue.
578+
579+
580+
Constants
581+
---------
582+
583+
.. data:: CAN.NORMAL
584+
CAN.LOOPBACK
585+
CAN.SILENT
586+
CAN.SILENT_LOOPBACK
587+
588+
589+
The mode of the CAN bus used in :meth:`~CAN.init()`.
590+
591+
+---------------------+---------------------------------------------+-------+-------+
592+
| *mode* | \ | STM32 | ESP32 |
593+
+=====================+=============================================+=======+=======+
594+
| CAN.NORMAL | .. image:: img/can_mode_normal.png | + | + |
595+
+---------------------+---------------------------------------------+-------+-------+
596+
| CAN.LOOPBACK | .. image:: img/can_mode_loopback.png | + | + |
597+
+---------------------+---------------------------------------------+-------+-------+
598+
| CAN.SILENT | .. image:: img/can_mode_silent.png | + | + |
599+
+---------------------+---------------------------------------------+-------+-------+
600+
| CAN.SILENT_LOOPBACK | .. image:: img/can_mode_silent_loopback.png | + | + |
601+
+---------------------+---------------------------------------------+-------+-------+
602+
603+
604+
.. data:: CAN.STOPPED
605+
CAN.ERROR_ACTIVE
606+
CAN.BUS_OFF
607+
CAN.RECOVERING
608+
609+
Possible states of the CAN controller returned from :meth:`~CAN.state()`.
610+
611+
.. data:: CAN.FILTER_RAW_SINGLE
612+
CAN.FILTER_RAW_DUAL
613+
CAN.FILTER_ADDRESS
614+
615+
The operation mode of a filter used in :meth:`~CAN.setfilter()`.
3.58 KB
Loading

docs/library/img/can_mode_normal.png

3.43 KB
Loading

docs/library/img/can_mode_silent.png

3.55 KB
Loading
3.56 KB
Loading

examples/esp32_can.py

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
from esp32 import CAN
2+
import time
3+
4+
5+
def send_and_check(can_bus, name, id, expected_result=True, extended=False):
6+
can_bus.clear_tx_queue()
7+
can_bus.clear_rx_queue()
8+
can_bus.send([], id, extframe=extended)
9+
time.sleep_ms(100)
10+
if can_bus.any() == expected_result:
11+
print("{}: OK".format(name))
12+
if expected_result:
13+
can_bus.recv()
14+
else:
15+
print("{}: FAILED".format(name))
16+
17+
18+
# 4 and 5 pins must be connected to each other, see documentation
19+
dev = CAN(0, tx=5, rx=4, mode=CAN.SILENT_LOOPBACK, baudrate=50000)
20+
21+
# Test send/receive message
22+
print("Loopback Test: no filter - STD")
23+
send_and_check(dev, "No filter", 0x100, True)
24+
25+
# Set filter1
26+
print("Loopback Test: one filter - STD")
27+
dev.setfilter(0, CAN.FILTER_ADDRESS, [0x101, 0])
28+
send_and_check(dev, "Passing Message", 0x101, True)
29+
send_and_check(dev, "Blocked Message", 0x100, False)
30+
31+
# Set filter2
32+
print("Loopback Test: second filter - STD")
33+
dev.setfilter(0, CAN.FILTER_ADDRESS, [0x102, 0])
34+
send_and_check(dev, "Passing Message - Bank 1", 0x102, True)
35+
send_and_check(dev, "Passing Message - Bank 0", 0x101, True)
36+
send_and_check(dev, "Blocked Message", 0x100, False)
37+
38+
# Remove filter
39+
print("Loopback Test: clear filter - STD")
40+
dev.clearfilter()
41+
send_and_check(dev, "Passing Message - Bank 1", 0x102, True)
42+
send_and_check(dev, "Passing Message - Bank 0", 0x101, True)
43+
send_and_check(dev, "Passing any Message", 0x100, True)
44+
45+
# Extended message tests
46+
# Test send/receive message
47+
print("Loopback Test: no filter - Extd")
48+
send_and_check(dev, "No filter", 0x100, True, extended=True)
49+
50+
# Set filter1
51+
print("Loopback Test: one filter - Extd")
52+
dev.setfilter(0, CAN.FILTER_ADDRESS, [0x101], extframe=True)
53+
send_and_check(dev, "Passing Message", 0x101, True, extended=True)
54+
send_and_check(dev, "Blocked Message", 0x100, False, extended=True)
55+
56+
# Remove filter
57+
print("Loopback Test: clear filter - Extd")
58+
dev.clearfilter()
59+
send_and_check(dev, "Passing Message - Bank 0", 0x101, True, extended=True)
60+
send_and_check(dev, "Passing any Message", 0x100, True, extended=True)

0 commit comments

Comments
 (0)