Skip to content

Esp32 can driver #5310

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 62 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
62 commits
Select commit Hold shift + click to select a range
96b8646
first commit
Sep 26, 2019
4b06c23
Enabled module
nos86 Sep 28, 2019
db0bb5a
Stable basic code for module loading in Python
nos86 Sep 29, 2019
263338c
Full initialization and dummy write
nos86 Oct 6, 2019
79540e3
added function to retrieve information of CAN STATUS
nos86 Oct 6, 2019
5c6a318
Update quickref.rst
nos86 Oct 6, 2019
83297b4
Function SEND and RECV implemented
nos86 Oct 6, 2019
e184574
improve object print
nos86 Oct 6, 2019
e4abe72
remove prefix CAN_ from constants
nos86 Oct 6, 2019
872ce73
implementation of hardware filter
nos86 Oct 8, 2019
b2e7e23
update includePath
nos86 Oct 8, 2019
d175e3c
Changed author
nos86 Dec 10, 2019
11cec6d
STM32 Harmonization: rename get_state() to state(), add info() and an…
nos86 Dec 10, 2019
1baa023
STM32 Harmonization: added restart() signature
nos86 Dec 10, 2019
175073d
STM32 Harmonization: move private methods in c file
nos86 Dec 10, 2019
b8a5c0e
Enabled compiler switch for module
nos86 Dec 10, 2019
195088f
Code Cleaning: Reordered the function sequence
nos86 Dec 10, 2019
a03c23b
STM32 Harmonization: init() returns mp_const_none and raise exception…
nos86 Dec 10, 2019
c0c8c8b
STM32 Harmonization: Alignment of init function to pyCan.
nos86 Dec 12, 2019
b362179
STM32 Harmonization: Alignment of send(...) and recv(...) methods to …
nos86 Dec 12, 2019
02cadd0
removed auto_restart option since the esp32 framework doesn't have th…
nos86 Dec 12, 2019
82017a9
Added signature for RX Callback; currently this method is not impleme…
nos86 Dec 13, 2019
a65026a
Python Interface has been moved from header to source
nos86 Dec 13, 2019
de8c71b
Removed redundant function
nos86 Dec 13, 2019
1e0d857
beautify
nos86 Dec 13, 2019
bbdfa6f
STM32 Harmonization: implemented same CAN_MODE
nos86 Dec 13, 2019
cf0f92a
minor fix
nos86 Dec 17, 2019
9e00b41
manage flags for loopback and extframe
nos86 Dec 17, 2019
8e45d11
removed unused input variable from any()
nos86 Dec 17, 2019
215dd81
bugfix
nos86 Dec 17, 2019
9d01908
Improved print function
nos86 Dec 17, 2019
7fed709
Implementation of restart function
nos86 Dec 18, 2019
38b2e6c
data type bugfix
nos86 Dec 18, 2019
bb0ed63
Added alert function
nos86 Dec 19, 2019
a508f4c
Added docs for ESP32 CAN
nos86 Dec 19, 2019
11cca71
Removed filter setup from init.
nos86 Dec 19, 2019
57efe79
STM32 Harmonization
nos86 Dec 19, 2019
3f04346
Integrated you docs with existing one
nos86 Dec 19, 2019
c346b59
Code cleaning
Dec 20, 2019
d13310e
WIP: first implementation of filters
Dec 20, 2019
3405345
WIP
Dec 20, 2019
c43aef3
Syntax Correction
nos86 Dec 21, 2019
68a3880
CAN configuration is stored in object struct
nos86 Dec 22, 2019
960435c
Bugfixes
nos86 Dec 22, 2019
7b9a9a9
WIP: implementation of setfilter()
nos86 Dec 22, 2019
96721c9
Completed setfilter()
nos86 Dec 23, 2019
8920885
added clearfilter()
nos86 Dec 23, 2019
2c6b6f4
Added unittest as example
nos86 Dec 23, 2019
5432a7d
removed machine_can.h
nos86 Dec 23, 2019
2616b9e
Bugfix
nos86 Dec 23, 2019
f5ed914
Docs updated
nos86 Dec 23, 2019
ef0ae9f
Update Author name
nos86 Dec 23, 2019
e5a7e9d
remove .vscode folder
nos86 Dec 23, 2019
66c8a32
Formatting sources
nos86 Jan 9, 2020
c807e7d
Removed additional constants and added in documentation
nos86 Jan 9, 2020
b07db3a
Documentation bugfix
nos86 Jan 9, 2020
c8afef6
removed implemented methods
nos86 Jan 9, 2020
b952513
beautify: brackets inline
nos86 Jan 30, 2020
faf2e90
documentation update: from esp32 specifc module to machine module
nos86 Jan 30, 2020
d959762
revert unnecessary changes
nos86 Jan 30, 2020
3cf09b0
code beautify
nos86 Feb 4, 2020
1e7e038
Beautify
nos86 Feb 9, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions docs/esp32/quickref.rst
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,23 @@ pins can be used for SCL and SDA. The driver is accessed via the
buf = bytearray(10) # create a buffer with 10 bytes
i2c.writeto(0x3a, buf) # write the given buffer to the slave

CAN bus
-------

See :ref:`machine.CAN <machine.CAN>` ::

The CAN driver is based on hardware implementation.
Any available output-capablepins can be used for SCL and SDA.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/output-capablepins/output-capable pins/ (space missing)

I know almost nothing about CAN, but I do find "SCL" and "SDA" suspicious names. The Esp-IDF docs state "The CAN controller’s interface consists of 4 signal lines known as TX, RX, BUS-OFF, and CLKOUT."...

The driver is accessed via the :ref:`machine.CAN <machine.CAN>` class::

from machine import CAN
BAUDRATE_500k = 500
can = CAN(0, extframe=True, mode=CAN.LOOPBACK, baudrate=BAUDRATE_500k)
dev.setfilter(0, CAN.FILTER_ADDRESS, [0x102, 0]) # set a filter to receive messages with id = 0x102
can.send([1,2,3], 0x102) # send a message with id 123
can.recv() # receive message


Real time clock (RTC)
---------------------

Expand Down
2 changes: 1 addition & 1 deletion docs/library/esp32.rst
Original file line number Diff line number Diff line change
Expand Up @@ -108,4 +108,4 @@ Constants
.. data:: esp32.WAKEUP_ALL_LOW
esp32.WAKEUP_ANY_HIGH

Selects the wake level for pins.
Selects the wake level for pins.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does this change?

257 changes: 257 additions & 0 deletions docs/library/machine.CAN.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,257 @@
.. currentmodule:: machine
.. _machine.CAN:

class CAN -- controller area network communication bus
======================================================

CAN implements the standard CAN communications protocol. At
the physical level it consists of 2 lines: RX and TX. Note that
to connect the microcontroller to a CAN bus you must use a CAN transceiver
to convert the CAN logic signals from the microcontroller to the correct
voltage levels on the bus.

Example usage (works without anything connected)::

from machine import CAN
BAUDRATE_500k = 500
can = CAN(0, extframe=True, mode=CAN.LOOPBACK, baudrate=BAUDRATE_500k)
dev.setfilter(0, CAN.FILTER_ADDRESS, [0x102, 0]) # set a filter to receive messages with id = 0x102
can.send([1,2,3], 0x102) # send a message with id 123
can.recv() # receive message


Constructors
------------

.. class:: machine.CAN(bus, ...)

Construct a CAN object on the given bus. *bus* can be 0 or 1 (for compatibility with STM32). It will point at the same device
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does "It will point at the same device" [missing punctuation] mean? If the esp32 only has one CAN controller then IMHO it should only accept bus==0. Also, these docs are for all ports, so esp32 peculiarities should be noted as such.

With no additional parameters, the CAN object is created but not
initialised (it has the settings from the last initialisation of
the bus, if any). If extra arguments are given, the bus is initialised.
See :meth:`CAN.init` for parameters of initialisation.

The physical pins of the CAN bus can be assigned during init.

Methods
-------

.. method:: CAN.init(mode, extframe=False, baudrate, prescaler, \*, sjw=1, bs1=6, bs2=8, auto_restart=False)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tx_io, rx_io, tx_queue, rx_queue are missing


Initialise the CAN bus with the given parameters:

- *mode* is one of: NORMAL, LOOPBACK, SILENT, SILENT_LOOPBACK
- if *extframe* is True then the bus uses extended identifiers in the frames
(29 bits); otherwise it uses standard 11 bit identifiers
- *baudrate* is used to define a standard speed. If it is defined, the *prescaler*, *sjw*, *bs1*, *bs2*
will be ignored. Standard speeds are 25, 50, 100, 125, 250, 500, 1000
- *prescaler* is used to set the duration of 1 time quanta; the time quanta
will be the input clock divided by the prescaler
- *sjw* is the resynchronisation jump width in units of the time quanta;
it can be 1, 2, 3, 4
- *bs1* defines the location of the sample point in units of the time quanta;
it can be between 1 and 1024 inclusive
- *bs2* defines the location of the transmit point in units of the time quanta;
it can be between 1 and 16 inclusive
- *tx_io* defines the gpio used for transmission
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please drop the _io suffix. No other drivers do that. The uart uses tx and rx, i2c uses sda and scl (not sda_io, and scl_io), etc.
The esp-idf docs mention 4 signal lines, two of which are optional. Can those not be used with this driver? What are the implications?
Specifying the pins is only supported on the esp32, right? Docs should note that.

- *rx_io* defines the gpio used for receiving
- *tx_queue* defines the number of waiting tx messages can be stored
- *rx_queue* defines the number of received messages can be stored
- *auto_restart* sets whether the controller will automatically try and restart
communications after entering the bus-off state; if this is disabled then
:meth:`~CAN.restart()` can be used to leave the bus-off state.
This parameter is currently not implemented and it must be set to False
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not implemented is an esp32 peculiarity.



.. method:: CAN.deinit()

Turn off the CAN bus.

.. method:: CAN.restart()

Force a software restart of the CAN controller without resetting its
configuration.

If the controller enters the bus-off state then it will no longer participate
in bus activity. If the controller is not configured to automatically restart
(see :meth:`~CAN.init()`) then this method can be used to trigger a restart,
and the controller will follow the CAN protocol to leave the bus-off state and
go into the error active state.

.. method:: CAN.state()

Return the state of the controller. The return value can be one of:

- ``CAN.STOPPED`` -- the controller is completely off and reset;
- ``CAN.ERROR_ACTIVE`` -- the controller is on and in the Error Active state
(both TEC and REC are less than 96);
- ``CAN.BUS_OFF`` -- the controller is on but not participating in bus activity
(TEC overflowed beyond 255).
- ``CAN.RECOVERING`` -- the controller is under recover from bus-off state;


.. method:: CAN.info([list])
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The stm32 module signature has a fifo arg?


Get information about the controller's error states and TX and RX buffers.
If *list* is provided then it should be a list object with at least 8 entries,
which will be filled in with the information. Otherwise a new list will be
created and filled in. In both cases the return value of the method is the
populated list.

The values in the list are:

- TEC value
- REC value
- number of times the controller enterted the Error Warning state (wrapped
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/enterted/entered/ also of subsequent lines

around to 0 after 65535) - CURRENTLY NOT IMPLEMENTED
- number of times the controller enterted the Error Passive state (wrapped
around to 0 after 65535) - CURRENTLY NOT IMPLEMENTED
- number of times the controller enterted the Bus Off state (wrapped
around to 0 after 65535) - CURRENTLY NOT IMPLEMENTED
- number of pending TX messages
- number of pending RX messages
- Reserved
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why have an 8-entry list with missing values in the middle? why not a 4-entry list for now? in the future it can be expanded and the method can fill in either 4 or 8 depending on what is passed in.


.. method:: CAN.setfilter(bank, mode, fifo, params, \*, rtr)

Configure a filter bank:

- *bank* is the filter bank that is to be configured (0 for extended, 0 or 1 for standard msg)
- *mode* is the mode the filter should operate in.
- *params* is an array of two values that defines the filter.
The first element will be the id to filter and the second element will be the mask to apply.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/will be/is/ also in following lines and table

mask bit implementation considers 1 as a don't care state and 0 as a check state.

+----------------------+----------------------------------------------+
|*mode* |contents of *params* array |
+======================+==============================================+
|CAN.FILTER_RAW_SINGLE | *params* will be copied in hardware variable |
| | and single_filter_mode will be selected |
| | In this mode, *bank* will be ignored |
+----------------------+----------------------------------------------+
|CAN.FILTER_RAW_DUAL | *params* will be copied in hardware variable |
| | and single_filter_mode will be cleared |
| | In this mode, *bank* will be ignored |
+----------------------+----------------------------------------------+
|CAN.FILTER_ADDRESS | *params* will be set in hardware registers |
| | according to *bank* selection |
+----------------------+----------------------------------------------+

- *rtr* is bool that states if a filter should accept a remote transmission request message.
If this argument is not given then it defaults to ``False``.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be illustrated by using rtr=False in the method signature.


.. method:: CAN.clearfilter(bank)

Clear and disables all filters

.. method:: CAN.any(fifo)

Return ``True`` if any message waiting on the FIFO, else ``False``.

.. method:: CAN.recv(list=None, \*, timeout=5000)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The signature on stm32 seems to be recv(fifo, list=None, *, timeout=5000) am I missing something?


Receive data on the bus:

- *list* is an optional list object to be used as the return value
- *timeout* is the timeout in milliseconds to wait for the receive.

Return value: A tuple containing four values.

- The id of the message.
- A boolean that indicates if the message is an RTR message.
- Reserved.
- An array containing the data.

If *list* is ``None`` then a new tuple will be allocated, as well as a new
bytes object to contain the data (as the fourth element in the tuple).

If *list* is not ``None`` then it should be a list object with a least four
elements. The fourth element should be a memoryview object which is created
from either a bytearray or an array of type 'B' or 'b', and this array must
have enough room for at least 8 bytes. The list object will then be
populated with the first three return values above, and the memoryview object
will be resized inplace to the size of the data and filled in with that data.
The same list and memoryview objects can be reused in subsequent calls to
this method, providing a way of receiving data without using the heap.
For example::

buf = bytearray(8)
lst = [0, 0, 0, memoryview(buf)]
# No heap memory is allocated in the following call
can.recv(0, lst)

.. method:: CAN.send(data, id, \*, timeout=0, rtr=False)

Send a message on the bus:

- *data* is the data to send (an integer to send, or a buffer object).
- *id* is the id of the message to be sent.
- *timeout* is the timeout in milliseconds to wait for the send.
- *rtr* is a boolean that specifies if the message shall be sent as
a remote transmission request. If *rtr* is True then only the length
of *data* is used to fill in the DLC slot of the frame; the actual
bytes in *data* are unused.

If timeout is 0 the message is placed in a buffer and the method returns
immediately. If all three buffers are in use an exception is thrown.
If timeout is not 0, the method waits until the message is transmitted.
If the message can't be transmitted within the specified time an exception
is thrown.

Return value: ``None``.

.. method:: CAN.clear_tx_queue()

Clear all messages from transmitting queue.

.. method:: CAN.clear_rx_queue()

Clear all messages from receiving queue.

.. method:: CAN.get_alerts()

Read the alert status word directly from hardware.
In order to save space in the firmware, the constants for the result decoding are not included on the :mod:`machine.CAN` module. Add the ones that you need from the list below to your program.

The event codes are::

from micropython import const
CAN_ALERT_TX_IDLE = const(0x0001)
CAN_ALERT_TX_SUCCESS = const(0x0002)
CAN_ALERT_BELOW_ERR_WARN = const(0x0004)
CAN_ALERT_ERR_ACTIVE = const(0x0008)
CAN_ALERT_RECOVERY_IN_PROGRESS = const(0x0010)
CAN_ALERT_BUS_RECOVERED = const(0x0020)
CAN_ALERT_ARB_LOST = const(0x0040)
CAN_ALERT_ABOVE_ERR_WARN = const(0x0080)
CAN_ALERT_BUS_ERROR = const(0x0100)
CAN_ALERT_TX_FAILED = const(0x0200)
CAN_ALERT_RX_QUEUE_FULL = const(0x0400)
CAN_ALERT_ERR_PASS = const(0x0800)
CAN_ALERT_BUS_OFF = const(0x1000)


Constants
---------

.. data:: CAN.NORMAL
CAN.LOOPBACK
CAN.SILENT
CAN.SILENT_LOOPBACK
CAN.LISTEN_ONLY

The mode of the CAN bus used in :meth:`~CAN.init()`.

.. data:: CAN.STOPPED
CAN.ERROR_ACTIVE
CAN.BUS_OFF
CAN.RECOVERING

Possible states of the CAN controller returned from :meth:`~CAN.state()`.

.. data:: CAN.FILTER_RAW_SINGLE
CAN.FILTER_RAW_DUAL
CAN.FILTER_ADDRESS

The operation mode of a filter used in :meth:`~CAN.setfilter()`.

69 changes: 69 additions & 0 deletions examples/esp32_can.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
from machine import CAN
import time


def sendAndCheck(dev, name, id, expectedLP=True):
dev.clear_tx_queue()
dev.clear_rx_queue()
dev.send([], id)
time.sleep_ms(100)
if dev.any() == expectedLP:
print("{}: OK".format(name))
if expectedLP:
dev.recv()
else:
print("{}: FAILED".format(name))


dev = CAN(0,
extframe=False,
mode=CAN.SILENT_LOOPBACK,
baudrate=CAN.BAUDRATE_500k,
tx_io=18, rx_io=19, auto_restart=False)

# Test send/receive message
print("Loopback Test: no filter - STD")
sendAndCheck(dev, "No filter", 0x100, True)

# Set filter1
print("Loopback Test: one filter - STD")
dev.setfilter(0, CAN.FILTER_ADDRESS, [0x101, 0])
sendAndCheck(dev, "Passing Message", 0x101, True)
sendAndCheck(dev, "Blocked Message", 0x100, False)

# Set filter2
print("Loopback Test: second filter - STD")
dev.setfilter(0, CAN.FILTER_ADDRESS, [0x102, 0])
sendAndCheck(dev, "Passing Message - Bank 1", 0x102, True)
sendAndCheck(dev, "Passing Message - Bank 0", 0x101, True)
sendAndCheck(dev, "Blocked Message", 0x100, False)

# Remove filter
print("Loopback Test: clear filter - STD")
dev.clearfilter()
sendAndCheck(dev, "Passing Message - Bank 1", 0x102, True)
sendAndCheck(dev, "Passing Message - Bank 0", 0x101, True)
sendAndCheck(dev, "Passing any Message", 0x100, True)

# Move to Extended
dev = CAN(0,
extframe=True,
mode=CAN.SILENT_LOOPBACK,
baudrate=CAN.BAUDRATE_500k,
tx_io=18, rx_io=19, auto_restart=False)

# Test send/receive message
print("Loopback Test: no filter - Extd")
sendAndCheck(dev, "No filter", 0x100, True)

# Set filter1
print("Loopback Test: one filter - Extd")
dev.setfilter(0, CAN.FILTER_ADDRESS, [0x101, 0])
sendAndCheck(dev, "Passing Message", 0x101, True)
sendAndCheck(dev, "Blocked Message", 0x100, False)

# Remove filter
print("Loopback Test: clear filter - Extd")
dev.clearfilter()
sendAndCheck(dev, "Passing Message - Bank 0", 0x101, True)
sendAndCheck(dev, "Passing any Message", 0x100, True)
2 changes: 2 additions & 0 deletions ports/esp32/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@ INC_ESPCOMP += -I$(ESPCOMP)/app_update/include
INC_ESPCOMP += -I$(ESPCOMP)/pthread/include
INC_ESPCOMP += -I$(ESPCOMP)/smartconfig_ack/include
INC_ESPCOMP += -I$(ESPCOMP)/sdmmc/include
INC_ESPCOMP += -I$(ESPCOMP)/can/include

ifeq ($(ESPIDF_CURHASH),$(ESPIDF_SUPHASH_V4))
INC_ESPCOMP += -I$(ESPCOMP)/esp_common/include
Expand Down Expand Up @@ -266,6 +267,7 @@ SRC_C = \
machine_i2c.c \
machine_pwm.c \
machine_uart.c \
machine_can.c \
modmachine.c \
modnetwork.c \
network_lan.c \
Expand Down
Loading
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy