Skip to content

Commit 396d92f

Browse files
committed
esp32s2: Add canio
This works in loopback mode, though the hardware filtering only permits a single address or mask filter.
1 parent fa4c4c2 commit 396d92f

File tree

9 files changed

+627
-3
lines changed

9 files changed

+627
-3
lines changed

ports/esp32s2/Makefile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -331,10 +331,10 @@ $(BUILD)/firmware.uf2: $(BUILD)/circuitpython-firmware.bin
331331
$(Q)$(PYTHON3) $(TOP)/tools/uf2/utils/uf2conv.py -f 0xbfdd4eee -b 0x0000 -c -o $@ $^
332332

333333
flash: $(BUILD)/firmware.bin
334-
esptool.py --chip esp32s2 -p $(PORT) --no-stub -b 460800 --before=default_reset --after=hard_reset write_flash $(FLASH_FLAGS) 0x0000 $^
334+
esptool.py --chip esp32s2 -p $(PORT) -b 460800 --before=default_reset --after=hard_reset write_flash $(FLASH_FLAGS) 0x0000 $^
335335

336336
flash-circuitpython-only: $(BUILD)/circuitpython-firmware.bin
337-
esptool.py --chip esp32s2 -p $(PORT) --no-stub -b 460800 --before=default_reset --after=hard_reset write_flash $(FLASH_FLAGS) 0x10000 $^
337+
esptool.py --chip esp32s2 -p $(PORT) -b 460800 --before=default_reset --after=hard_reset write_flash $(FLASH_FLAGS) 0x10000 $^
338338

339339
include $(TOP)/py/mkrules.mk
340340

ports/esp32s2/boards/espressif_kaluga_1/mpconfigboard.mk

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ LONGINT_IMPL = MPZ
1111
CFLAGS += -DCFG_TUD_TASK_QUEUE_SZ=32
1212

1313
CIRCUITPY_ESP_FLASH_MODE=dio
14-
CIRCUITPY_ESP_FLASH_FREQ=40m
14+
CIRCUITPY_ESP_FLASH_FREQ=80m
1515
CIRCUITPY_ESP_FLASH_SIZE=4MB
1616

1717
CIRCUITPY_MODULE=wrover

ports/esp32s2/common-hal/canio/CAN.c

Lines changed: 297 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,297 @@
1+
/*
2+
* This file is part of the MicroPython project, http://micropython.org/
3+
*
4+
* The MIT License (MIT)
5+
*
6+
* Copyright (c) 2020 Jeff Epler for Adafruit Industries
7+
*
8+
* Permission is hereby granted, free of charge, to any person obtaining a copy
9+
* of this software and associated documentation files (the "Software"), to deal
10+
* in the Software without restriction, including without limitation the rights
11+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12+
* copies of the Software, and to permit persons to whom the Software is
13+
* furnished to do so, subject to the following conditions:
14+
*
15+
* The above copyright notice and this permission notice shall be included in
16+
* all copies or substantial portions of the Software.
17+
*
18+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24+
* THE SOFTWARE.
25+
*/
26+
27+
#include <string.h>
28+
29+
#include "py/runtime.h"
30+
#include "py/mperrno.h"
31+
32+
#include "common-hal/canio/CAN.h"
33+
#include "shared-bindings/microcontroller/Pin.h"
34+
#include "shared-bindings/util.h"
35+
#include "supervisor/port.h"
36+
#include "hal/twai_ll.h"
37+
38+
#include "hal/twai_types.h"
39+
40+
STATIC bool reserved_can;
41+
42+
twai_timing_config_t get_t_config(int baudrate) {
43+
switch(baudrate) {
44+
case 1000000:
45+
{
46+
twai_timing_config_t t_config = TWAI_TIMING_CONFIG_1MBITS();
47+
return t_config;
48+
}
49+
case 800000:
50+
{
51+
twai_timing_config_t t_config = TWAI_TIMING_CONFIG_800KBITS();
52+
return t_config;
53+
}
54+
case 500000:
55+
{
56+
twai_timing_config_t t_config = TWAI_TIMING_CONFIG_500KBITS();
57+
return t_config;
58+
}
59+
case 250000:
60+
{
61+
twai_timing_config_t t_config = TWAI_TIMING_CONFIG_250KBITS();
62+
return t_config;
63+
}
64+
case 125000:
65+
{
66+
twai_timing_config_t t_config = TWAI_TIMING_CONFIG_125KBITS();
67+
return t_config;
68+
}
69+
case 100000:
70+
{
71+
twai_timing_config_t t_config = TWAI_TIMING_CONFIG_100KBITS();
72+
return t_config;
73+
}
74+
case 50000:
75+
{
76+
twai_timing_config_t t_config = TWAI_TIMING_CONFIG_50KBITS();
77+
return t_config;
78+
}
79+
case 25000:
80+
{
81+
twai_timing_config_t t_config = TWAI_TIMING_CONFIG_25KBITS();
82+
return t_config;
83+
}
84+
case 20000:
85+
{
86+
twai_timing_config_t t_config = TWAI_TIMING_CONFIG_20KBITS();
87+
return t_config;
88+
}
89+
case 16000:
90+
{
91+
twai_timing_config_t t_config = TWAI_TIMING_CONFIG_16KBITS();
92+
return t_config;
93+
}
94+
case 12500:
95+
{
96+
twai_timing_config_t t_config = TWAI_TIMING_CONFIG_12_5KBITS();
97+
return t_config;
98+
}
99+
case 10000:
100+
{
101+
twai_timing_config_t t_config = TWAI_TIMING_CONFIG_10KBITS();
102+
return t_config;
103+
}
104+
case 5000:
105+
{
106+
twai_timing_config_t t_config = TWAI_TIMING_CONFIG_5KBITS();
107+
return t_config;
108+
}
109+
case 1000:
110+
{
111+
twai_timing_config_t t_config = TWAI_TIMING_CONFIG_1KBITS();
112+
return t_config;
113+
}
114+
default:
115+
mp_raise_ValueError(translate("Baudrate not supported by peripheral"));
116+
}
117+
}
118+
119+
__attribute__((optimize("O0")))
120+
void common_hal_canio_can_construct(canio_can_obj_t *self, mcu_pin_obj_t *tx, mcu_pin_obj_t *rx, int baudrate, bool loopback, bool silent)
121+
{
122+
#define DIV_ROUND(a, b) (((a) + (b)/2) / (b))
123+
#define DIV_ROUND_UP(a, b) (((a) + (b) - 1) / (b))
124+
if (reserved_can) {
125+
mp_raise_ValueError(translate("All CAN peripherals are in use"));
126+
}
127+
128+
if (loopback && silent) {
129+
mp_raise_ValueError(translate("loopback + silent mode not supported by peripheral"));
130+
}
131+
132+
self->t_config = get_t_config(baudrate);;
133+
twai_general_config_t g_config = TWAI_GENERAL_CONFIG_DEFAULT(-1, -1, TWAI_MODE_NORMAL);
134+
g_config.tx_io = tx->number;
135+
g_config.rx_io = rx->number;
136+
if (loopback) {
137+
g_config.mode = TWAI_MODE_NO_ACK;
138+
}
139+
if (silent) {
140+
g_config.mode = TWAI_MODE_LISTEN_ONLY;
141+
}
142+
self->g_config = g_config;
143+
144+
{
145+
twai_filter_config_t f_config = TWAI_FILTER_CONFIG_ACCEPT_ALL();
146+
self->f_config = f_config;
147+
}
148+
149+
esp_err_t result = twai_driver_install(&self->g_config, &self->t_config, &self->f_config);
150+
if (result == ESP_ERR_NO_MEM) {
151+
mp_raise_msg(&mp_type_MemoryError, translate("ESP-IDF memory allocation failed"));
152+
} else if (result == ESP_ERR_INVALID_ARG) {
153+
mp_raise_ValueError(translate("Invalid pins"));
154+
} else if (result != ESP_OK) {
155+
mp_raise_OSError_msg_varg(translate("twai_driver_install returned esp-idf error #%d"), (int)result);
156+
}
157+
158+
result = twai_start();
159+
if (result != ESP_OK) {
160+
mp_raise_OSError_msg_varg(translate("twai_start returned esp-idf error #%d"), (int)result);
161+
}
162+
163+
self->silent = silent;
164+
self->loopback = loopback;
165+
self->baudrate = baudrate;
166+
self->tx_pin = tx;
167+
self->rx_pin = rx;
168+
169+
claim_pin(tx);
170+
claim_pin(rx);
171+
172+
reserved_can = true;
173+
}
174+
175+
bool common_hal_canio_can_loopback_get(canio_can_obj_t *self)
176+
{
177+
return self->loopback;
178+
}
179+
180+
int common_hal_canio_can_baudrate_get(canio_can_obj_t *self)
181+
{
182+
return self->baudrate;
183+
}
184+
185+
int common_hal_canio_can_transmit_error_count_get(canio_can_obj_t *self)
186+
{
187+
twai_status_info_t info;
188+
twai_get_status_info(&info);
189+
return info.tx_error_counter;
190+
}
191+
192+
int common_hal_canio_can_receive_error_count_get(canio_can_obj_t *self)
193+
{
194+
twai_status_info_t info;
195+
twai_get_status_info(&info);
196+
return info.rx_error_counter;
197+
}
198+
199+
canio_bus_state_t common_hal_canio_can_state_get(canio_can_obj_t *self) {
200+
twai_status_info_t info;
201+
twai_get_status_info(&info);
202+
if (info.state == TWAI_STATE_BUS_OFF || info.state == TWAI_STATE_RECOVERING) {
203+
return BUS_STATE_OFF;
204+
}
205+
if (info.tx_error_counter > 127 || info.rx_error_counter > 127) {
206+
return BUS_STATE_ERROR_PASSIVE;
207+
}
208+
if (info.tx_error_counter > 96 || info.rx_error_counter > 96) {
209+
return BUS_STATE_ERROR_WARNING;
210+
}
211+
return BUS_STATE_ERROR_ACTIVE;
212+
}
213+
214+
static void can_restart(void) {
215+
twai_status_info_t info;
216+
twai_get_status_info(&info);
217+
if (info.state != TWAI_STATE_BUS_OFF) {
218+
return;
219+
}
220+
twai_initiate_recovery();
221+
// wait 100ms (hard coded for now) for bus to recover
222+
uint64_t deadline = port_get_raw_ticks(NULL) + 100;
223+
do {
224+
twai_get_status_info(&info);
225+
} while (port_get_raw_ticks(NULL) < deadline && (info.state == TWAI_STATE_BUS_OFF || info.state == TWAI_STATE_RECOVERING));
226+
}
227+
228+
void canio_maybe_auto_restart(canio_can_obj_t *self) {
229+
if (self->auto_restart) can_restart();
230+
}
231+
232+
void common_hal_canio_can_restart(canio_can_obj_t *self) {
233+
if (!common_hal_canio_can_auto_restart_get(self)) {
234+
can_restart();
235+
}
236+
}
237+
238+
bool common_hal_canio_can_auto_restart_get(canio_can_obj_t *self) {
239+
return self->auto_restart;
240+
}
241+
242+
void common_hal_canio_can_auto_restart_set(canio_can_obj_t *self, bool value) {
243+
self->auto_restart = value;
244+
canio_maybe_auto_restart(self);
245+
}
246+
247+
void common_hal_canio_can_send(canio_can_obj_t *self, mp_obj_t message_in)
248+
{
249+
canio_maybe_auto_restart(self);
250+
canio_message_obj_t *message = message_in;
251+
bool rtr = message->base.type == &canio_remote_transmission_request_type;
252+
twai_message_t message_out = {
253+
.extd = message->extended,
254+
.rtr = rtr,
255+
.self = self->loopback,
256+
.identifier = message->id,
257+
.data_length_code = message->size,
258+
};
259+
if (!rtr) {
260+
memcpy(message_out.data, message->data, message->size);
261+
}
262+
// Allow transmission to occur in background
263+
twai_transmit(&message_out, 0);
264+
}
265+
266+
bool common_hal_canio_can_silent_get(canio_can_obj_t *self) {
267+
return self->silent;
268+
}
269+
270+
bool common_hal_canio_can_deinited(canio_can_obj_t *self) {
271+
return !self->tx_pin;
272+
}
273+
274+
void common_hal_canio_can_check_for_deinit(canio_can_obj_t *self) {
275+
if (common_hal_canio_can_deinited(self)) {
276+
raise_deinited_error();
277+
}
278+
}
279+
280+
void common_hal_canio_can_deinit(canio_can_obj_t *self)
281+
{
282+
if (self->tx_pin) {
283+
(void)twai_stop();
284+
(void)twai_driver_uninstall();
285+
reset_pin_number(self->tx_pin->number);
286+
reset_pin_number(self->rx_pin->number);
287+
reserved_can = false;
288+
}
289+
self->tx_pin = NULL;
290+
self->rx_pin = NULL;
291+
}
292+
293+
void common_hal_canio_reset(void) {
294+
(void)twai_stop();
295+
(void)twai_driver_uninstall();
296+
reserved_can = false;
297+
}

ports/esp32s2/common-hal/canio/CAN.h

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/*
2+
* This file is part of the MicroPython project, http://micropython.org/
3+
*
4+
* The MIT License (MIT)
5+
*
6+
* Copyright (c) 2020 Jeff Epler for Adafruit Industries
7+
*
8+
* Permission is hereby granted, free of charge, to any person obtaining a copy
9+
* of this software and associated documentation files (the "Software"), to deal
10+
* in the Software without restriction, including without limitation the rights
11+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12+
* copies of the Software, and to permit persons to whom the Software is
13+
* furnished to do so, subject to the following conditions:
14+
*
15+
* The above copyright notice and this permission notice shall be included in
16+
* all copies or substantial portions of the Software.
17+
*
18+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24+
* THE SOFTWARE.
25+
*/
26+
27+
#pragma once
28+
29+
#include "py/obj.h"
30+
#include "shared-bindings/canio/__init__.h"
31+
#include "shared-bindings/canio/CAN.h"
32+
#include "common-hal/microcontroller/Pin.h"
33+
#include "common-hal/canio/__init__.h"
34+
#include "shared-module/canio/Message.h"
35+
36+
#include "driver/twai.h"
37+
38+
#define FILTER_BANK_COUNT (28)
39+
40+
typedef struct canio_can_obj {
41+
mp_obj_base_t base;
42+
int baudrate;
43+
const mcu_pin_obj_t *rx_pin;
44+
const mcu_pin_obj_t *tx_pin;
45+
bool loopback:1;
46+
bool silent:1;
47+
bool auto_restart:1;
48+
bool fifo_in_use:1;
49+
twai_filter_config_t f_config;
50+
twai_general_config_t g_config;
51+
twai_timing_config_t t_config;
52+
} canio_can_obj_t;

0 commit comments

Comments
 (0)