Merge pull request #3584 from jepler/can-esp32s2
esp32s2: implement canio
This commit is contained in:
commit
73162bda85
@ -8,7 +8,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2020-10-16 19:50-0500\n"
|
||||
"POT-Creation-Date: 2020-10-21 20:13-0500\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
@ -288,11 +288,16 @@ msgstr ""
|
||||
msgid "Address type out of range"
|
||||
msgstr ""
|
||||
|
||||
#: ports/esp32s2/common-hal/canio/CAN.c
|
||||
msgid "All CAN peripherals are in use"
|
||||
msgstr ""
|
||||
|
||||
#: ports/esp32s2/common-hal/busio/I2C.c ports/nrf/common-hal/busio/I2C.c
|
||||
msgid "All I2C peripherals are in use"
|
||||
msgstr ""
|
||||
|
||||
#: ports/atmel-samd/common-hal/canio/Listener.c
|
||||
#: ports/esp32s2/common-hal/canio/Listener.c
|
||||
#: ports/stm/common-hal/canio/Listener.c
|
||||
msgid "All RX FIFOs in use"
|
||||
msgstr ""
|
||||
@ -407,6 +412,10 @@ msgid ""
|
||||
"disable.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ports/esp32s2/common-hal/canio/CAN.c
|
||||
msgid "Baudrate not supported by peripheral"
|
||||
msgstr ""
|
||||
|
||||
#: shared-module/displayio/Display.c
|
||||
#: shared-module/framebufferio/FramebufferDisplay.c
|
||||
msgid "Below minimum frame rate"
|
||||
@ -775,7 +784,7 @@ msgstr ""
|
||||
msgid "ECB only operates on 16 bytes at a time"
|
||||
msgstr ""
|
||||
|
||||
#: ports/esp32s2/common-hal/busio/SPI.c
|
||||
#: ports/esp32s2/common-hal/busio/SPI.c ports/esp32s2/common-hal/canio/CAN.c
|
||||
msgid "ESP-IDF memory allocation failed"
|
||||
msgstr ""
|
||||
|
||||
@ -901,6 +910,7 @@ msgid "File exists"
|
||||
msgstr ""
|
||||
|
||||
#: ports/atmel-samd/common-hal/canio/Listener.c
|
||||
#: ports/esp32s2/common-hal/canio/Listener.c
|
||||
#: ports/stm/common-hal/canio/Listener.c
|
||||
msgid "Filters too complex"
|
||||
msgstr ""
|
||||
@ -1119,7 +1129,7 @@ msgstr ""
|
||||
#: ports/cxd56/common-hal/busio/I2C.c ports/cxd56/common-hal/busio/SPI.c
|
||||
#: ports/cxd56/common-hal/busio/UART.c ports/cxd56/common-hal/sdioio/SDCard.c
|
||||
#: ports/esp32s2/common-hal/busio/I2C.c ports/esp32s2/common-hal/busio/SPI.c
|
||||
#: ports/esp32s2/common-hal/busio/UART.c
|
||||
#: ports/esp32s2/common-hal/busio/UART.c ports/esp32s2/common-hal/canio/CAN.c
|
||||
#: ports/mimxrt10xx/common-hal/busio/I2C.c
|
||||
#: ports/mimxrt10xx/common-hal/busio/SPI.c
|
||||
#: ports/mimxrt10xx/common-hal/busio/UART.c ports/nrf/common-hal/busio/I2C.c
|
||||
@ -2837,6 +2847,10 @@ msgstr ""
|
||||
msgid "long int not supported in this build"
|
||||
msgstr ""
|
||||
|
||||
#: ports/esp32s2/common-hal/canio/CAN.c
|
||||
msgid "loopback + silent mode not supported by peripheral"
|
||||
msgstr ""
|
||||
|
||||
#: py/parse.c
|
||||
msgid "malformed f-string"
|
||||
msgstr ""
|
||||
@ -3189,6 +3203,8 @@ msgstr ""
|
||||
#: ports/esp32s2/boards/espressif_saola_1_wrover/mpconfigboard.h
|
||||
#: ports/esp32s2/boards/microdev_micro_s2/mpconfigboard.h
|
||||
#: ports/esp32s2/boards/muselab_nanoesp32_s2/mpconfigboard.h
|
||||
#: ports/esp32s2/boards/targett_module_clip_wroom/mpconfigboard.h
|
||||
#: ports/esp32s2/boards/targett_module_clip_wrover/mpconfigboard.h
|
||||
#: ports/esp32s2/boards/unexpectedmaker_feathers2/mpconfigboard.h
|
||||
#: ports/esp32s2/boards/unexpectedmaker_feathers2_prerelease/mpconfigboard.h
|
||||
msgid "pressing boot button at start up.\n"
|
||||
@ -3444,6 +3460,16 @@ msgstr ""
|
||||
msgid "tuple/list has wrong length"
|
||||
msgstr ""
|
||||
|
||||
#: ports/esp32s2/common-hal/canio/CAN.c
|
||||
#, c-format
|
||||
msgid "twai_driver_install returned esp-idf error #%d"
|
||||
msgstr ""
|
||||
|
||||
#: ports/esp32s2/common-hal/canio/CAN.c
|
||||
#, c-format
|
||||
msgid "twai_start returned esp-idf error #%d"
|
||||
msgstr ""
|
||||
|
||||
#: ports/atmel-samd/common-hal/busio/UART.c
|
||||
#: ports/esp32s2/common-hal/busio/UART.c ports/nrf/common-hal/busio/UART.c
|
||||
#: shared-bindings/busio/UART.c shared-bindings/canio/CAN.c
|
||||
|
@ -11,7 +11,7 @@ LONGINT_IMPL = MPZ
|
||||
CFLAGS += -DCFG_TUD_TASK_QUEUE_SZ=32
|
||||
|
||||
CIRCUITPY_ESP_FLASH_MODE=dio
|
||||
CIRCUITPY_ESP_FLASH_FREQ=40m
|
||||
CIRCUITPY_ESP_FLASH_FREQ=80m
|
||||
CIRCUITPY_ESP_FLASH_SIZE=4MB
|
||||
|
||||
CIRCUITPY_MODULE=wrover
|
||||
|
295
ports/esp32s2/common-hal/canio/CAN.c
Normal file
295
ports/esp32s2/common-hal/canio/CAN.c
Normal file
@ -0,0 +1,295 @@
|
||||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2020 Jeff Epler for Adafruit Industries
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "py/runtime.h"
|
||||
#include "py/mperrno.h"
|
||||
|
||||
#include "common-hal/canio/CAN.h"
|
||||
#include "shared-bindings/microcontroller/Pin.h"
|
||||
#include "shared-bindings/util.h"
|
||||
#include "supervisor/port.h"
|
||||
|
||||
#include "hal/twai_types.h"
|
||||
|
||||
STATIC bool reserved_can;
|
||||
|
||||
twai_timing_config_t get_t_config(int baudrate) {
|
||||
switch(baudrate) {
|
||||
case 1000000:
|
||||
{
|
||||
// TWAI_TIMING_CONFIG_abc expands to a C designated initializer list
|
||||
// { .brp = 4, ...}. This is only acceptable to the compiler as an
|
||||
// initializer and 'return TWAI_TIMING_CONFIG_1MBITS()` is not valid.
|
||||
// Instead, introduce a temporary, named variable and return it.
|
||||
twai_timing_config_t t_config = TWAI_TIMING_CONFIG_1MBITS();
|
||||
return t_config;
|
||||
}
|
||||
case 800000:
|
||||
{
|
||||
twai_timing_config_t t_config = TWAI_TIMING_CONFIG_800KBITS();
|
||||
return t_config;
|
||||
}
|
||||
case 500000:
|
||||
{
|
||||
twai_timing_config_t t_config = TWAI_TIMING_CONFIG_500KBITS();
|
||||
return t_config;
|
||||
}
|
||||
case 250000:
|
||||
{
|
||||
twai_timing_config_t t_config = TWAI_TIMING_CONFIG_250KBITS();
|
||||
return t_config;
|
||||
}
|
||||
case 125000:
|
||||
{
|
||||
twai_timing_config_t t_config = TWAI_TIMING_CONFIG_125KBITS();
|
||||
return t_config;
|
||||
}
|
||||
case 100000:
|
||||
{
|
||||
twai_timing_config_t t_config = TWAI_TIMING_CONFIG_100KBITS();
|
||||
return t_config;
|
||||
}
|
||||
case 50000:
|
||||
{
|
||||
twai_timing_config_t t_config = TWAI_TIMING_CONFIG_50KBITS();
|
||||
return t_config;
|
||||
}
|
||||
case 25000:
|
||||
{
|
||||
twai_timing_config_t t_config = TWAI_TIMING_CONFIG_25KBITS();
|
||||
return t_config;
|
||||
}
|
||||
case 20000:
|
||||
{
|
||||
twai_timing_config_t t_config = TWAI_TIMING_CONFIG_20KBITS();
|
||||
return t_config;
|
||||
}
|
||||
case 16000:
|
||||
{
|
||||
twai_timing_config_t t_config = TWAI_TIMING_CONFIG_16KBITS();
|
||||
return t_config;
|
||||
}
|
||||
case 12500:
|
||||
{
|
||||
twai_timing_config_t t_config = TWAI_TIMING_CONFIG_12_5KBITS();
|
||||
return t_config;
|
||||
}
|
||||
case 10000:
|
||||
{
|
||||
twai_timing_config_t t_config = TWAI_TIMING_CONFIG_10KBITS();
|
||||
return t_config;
|
||||
}
|
||||
case 5000:
|
||||
{
|
||||
twai_timing_config_t t_config = TWAI_TIMING_CONFIG_5KBITS();
|
||||
return t_config;
|
||||
}
|
||||
case 1000:
|
||||
{
|
||||
twai_timing_config_t t_config = TWAI_TIMING_CONFIG_1KBITS();
|
||||
return t_config;
|
||||
}
|
||||
default:
|
||||
mp_raise_ValueError(translate("Baudrate not supported by peripheral"));
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
#define DIV_ROUND(a, b) (((a) + (b)/2) / (b))
|
||||
#define DIV_ROUND_UP(a, b) (((a) + (b) - 1) / (b))
|
||||
if (reserved_can) {
|
||||
mp_raise_ValueError(translate("All CAN peripherals are in use"));
|
||||
}
|
||||
|
||||
if (loopback && silent) {
|
||||
mp_raise_ValueError(translate("loopback + silent mode not supported by peripheral"));
|
||||
}
|
||||
|
||||
twai_timing_config_t t_config = get_t_config(baudrate);
|
||||
twai_general_config_t g_config = TWAI_GENERAL_CONFIG_DEFAULT(-1, -1, TWAI_MODE_NORMAL);
|
||||
g_config.tx_io = tx->number;
|
||||
g_config.rx_io = rx->number;
|
||||
if (loopback) {
|
||||
g_config.mode = TWAI_MODE_NO_ACK;
|
||||
}
|
||||
if (silent) {
|
||||
g_config.mode = TWAI_MODE_LISTEN_ONLY;
|
||||
}
|
||||
|
||||
twai_filter_config_t f_config = TWAI_FILTER_CONFIG_ACCEPT_ALL();
|
||||
|
||||
esp_err_t result = twai_driver_install(&g_config, &t_config, &f_config);
|
||||
if (result == ESP_ERR_NO_MEM) {
|
||||
mp_raise_msg(&mp_type_MemoryError, translate("ESP-IDF memory allocation failed"));
|
||||
} else if (result == ESP_ERR_INVALID_ARG) {
|
||||
mp_raise_ValueError(translate("Invalid pins"));
|
||||
} else if (result != ESP_OK) {
|
||||
mp_raise_OSError_msg_varg(translate("twai_driver_install returned esp-idf error #%d"), (int)result);
|
||||
}
|
||||
|
||||
result = twai_start();
|
||||
if (result != ESP_OK) {
|
||||
mp_raise_OSError_msg_varg(translate("twai_start returned esp-idf error #%d"), (int)result);
|
||||
}
|
||||
|
||||
self->silent = silent;
|
||||
self->loopback = loopback;
|
||||
self->baudrate = baudrate;
|
||||
self->tx_pin = tx;
|
||||
self->rx_pin = rx;
|
||||
|
||||
claim_pin(tx);
|
||||
claim_pin(rx);
|
||||
|
||||
reserved_can = true;
|
||||
}
|
||||
|
||||
bool common_hal_canio_can_loopback_get(canio_can_obj_t *self)
|
||||
{
|
||||
return self->loopback;
|
||||
}
|
||||
|
||||
int common_hal_canio_can_baudrate_get(canio_can_obj_t *self)
|
||||
{
|
||||
return self->baudrate;
|
||||
}
|
||||
|
||||
int common_hal_canio_can_transmit_error_count_get(canio_can_obj_t *self)
|
||||
{
|
||||
twai_status_info_t info;
|
||||
twai_get_status_info(&info);
|
||||
return info.tx_error_counter;
|
||||
}
|
||||
|
||||
int common_hal_canio_can_receive_error_count_get(canio_can_obj_t *self)
|
||||
{
|
||||
twai_status_info_t info;
|
||||
twai_get_status_info(&info);
|
||||
return info.rx_error_counter;
|
||||
}
|
||||
|
||||
canio_bus_state_t common_hal_canio_can_state_get(canio_can_obj_t *self) {
|
||||
twai_status_info_t info;
|
||||
twai_get_status_info(&info);
|
||||
if (info.state == TWAI_STATE_BUS_OFF || info.state == TWAI_STATE_RECOVERING) {
|
||||
return BUS_STATE_OFF;
|
||||
}
|
||||
if (info.tx_error_counter > 127 || info.rx_error_counter > 127) {
|
||||
return BUS_STATE_ERROR_PASSIVE;
|
||||
}
|
||||
if (info.tx_error_counter > 96 || info.rx_error_counter > 96) {
|
||||
return BUS_STATE_ERROR_WARNING;
|
||||
}
|
||||
return BUS_STATE_ERROR_ACTIVE;
|
||||
}
|
||||
|
||||
static void can_restart(void) {
|
||||
twai_status_info_t info;
|
||||
twai_get_status_info(&info);
|
||||
if (info.state != TWAI_STATE_BUS_OFF) {
|
||||
return;
|
||||
}
|
||||
twai_initiate_recovery();
|
||||
// wait 100ms (hard coded for now) for bus to recover
|
||||
uint64_t deadline = port_get_raw_ticks(NULL) + 100;
|
||||
do {
|
||||
twai_get_status_info(&info);
|
||||
} while (port_get_raw_ticks(NULL) < deadline && (info.state == TWAI_STATE_BUS_OFF || info.state == TWAI_STATE_RECOVERING));
|
||||
}
|
||||
|
||||
void canio_maybe_auto_restart(canio_can_obj_t *self) {
|
||||
if (self->auto_restart) can_restart();
|
||||
}
|
||||
|
||||
void common_hal_canio_can_restart(canio_can_obj_t *self) {
|
||||
if (!common_hal_canio_can_auto_restart_get(self)) {
|
||||
can_restart();
|
||||
}
|
||||
}
|
||||
|
||||
bool common_hal_canio_can_auto_restart_get(canio_can_obj_t *self) {
|
||||
return self->auto_restart;
|
||||
}
|
||||
|
||||
void common_hal_canio_can_auto_restart_set(canio_can_obj_t *self, bool value) {
|
||||
self->auto_restart = value;
|
||||
canio_maybe_auto_restart(self);
|
||||
}
|
||||
|
||||
void common_hal_canio_can_send(canio_can_obj_t *self, mp_obj_t message_in)
|
||||
{
|
||||
canio_maybe_auto_restart(self);
|
||||
canio_message_obj_t *message = message_in;
|
||||
bool rtr = message->base.type == &canio_remote_transmission_request_type;
|
||||
twai_message_t message_out = {
|
||||
.extd = message->extended,
|
||||
.rtr = rtr,
|
||||
.self = self->loopback,
|
||||
.identifier = message->id,
|
||||
.data_length_code = message->size,
|
||||
};
|
||||
if (!rtr) {
|
||||
memcpy(message_out.data, message->data, message->size);
|
||||
}
|
||||
// Allow transmission to occur in background
|
||||
twai_transmit(&message_out, 0);
|
||||
}
|
||||
|
||||
bool common_hal_canio_can_silent_get(canio_can_obj_t *self) {
|
||||
return self->silent;
|
||||
}
|
||||
|
||||
bool common_hal_canio_can_deinited(canio_can_obj_t *self) {
|
||||
return !self->tx_pin;
|
||||
}
|
||||
|
||||
void common_hal_canio_can_check_for_deinit(canio_can_obj_t *self) {
|
||||
if (common_hal_canio_can_deinited(self)) {
|
||||
raise_deinited_error();
|
||||
}
|
||||
}
|
||||
|
||||
void common_hal_canio_can_deinit(canio_can_obj_t *self)
|
||||
{
|
||||
if (self->tx_pin) {
|
||||
(void)twai_stop();
|
||||
(void)twai_driver_uninstall();
|
||||
reset_pin_number(self->tx_pin->number);
|
||||
reset_pin_number(self->rx_pin->number);
|
||||
reserved_can = false;
|
||||
}
|
||||
self->tx_pin = NULL;
|
||||
self->rx_pin = NULL;
|
||||
}
|
||||
|
||||
void common_hal_canio_reset(void) {
|
||||
(void)twai_stop();
|
||||
(void)twai_driver_uninstall();
|
||||
reserved_can = false;
|
||||
}
|
49
ports/esp32s2/common-hal/canio/CAN.h
Normal file
49
ports/esp32s2/common-hal/canio/CAN.h
Normal file
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2020 Jeff Epler for Adafruit Industries
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "py/obj.h"
|
||||
#include "shared-bindings/canio/__init__.h"
|
||||
#include "shared-bindings/canio/CAN.h"
|
||||
#include "common-hal/microcontroller/Pin.h"
|
||||
#include "common-hal/canio/__init__.h"
|
||||
#include "shared-module/canio/Message.h"
|
||||
|
||||
#include "driver/twai.h"
|
||||
|
||||
#define FILTER_BANK_COUNT (28)
|
||||
|
||||
typedef struct canio_can_obj {
|
||||
mp_obj_base_t base;
|
||||
int baudrate;
|
||||
const mcu_pin_obj_t *rx_pin;
|
||||
const mcu_pin_obj_t *tx_pin;
|
||||
bool loopback:1;
|
||||
bool silent:1;
|
||||
bool auto_restart:1;
|
||||
bool fifo_in_use:1;
|
||||
} canio_can_obj_t;
|
182
ports/esp32s2/common-hal/canio/Listener.c
Normal file
182
ports/esp32s2/common-hal/canio/Listener.c
Normal file
@ -0,0 +1,182 @@
|
||||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2020 Jeff Epler for Adafruit Industries
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "py/obj.h"
|
||||
#include "py/runtime.h"
|
||||
|
||||
#include "common-hal/canio/__init__.h"
|
||||
#include "common-hal/canio/Listener.h"
|
||||
#include "shared-bindings/canio/Listener.h"
|
||||
#include "shared-bindings/util.h"
|
||||
#include "supervisor/shared/tick.h"
|
||||
#include "supervisor/shared/safe_mode.h"
|
||||
|
||||
#include "hal/twai_ll.h"
|
||||
|
||||
// IDE = "extended ID" flag of packet header. We always add this bit to the
|
||||
// mask because a match is always for just one kind of address length
|
||||
#define FILTER16_IDE (1<<3)
|
||||
#define FILTER32_IDE (1<<2)
|
||||
|
||||
// Work around a problem reported at
|
||||
// https://github.com/espressif/esp-idf/issues/6020 where
|
||||
// twai_ll_set_acc_filter does not work under -Os optimization
|
||||
__attribute__((optimize("O0")))
|
||||
__attribute__((noinline))
|
||||
static void canio_set_acc_filter(twai_dev_t* hw, uint32_t code, uint32_t mask, bool single_filter)
|
||||
{
|
||||
uint32_t code_swapped = __builtin_bswap32(code);
|
||||
uint32_t mask_swapped = __builtin_bswap32(mask);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
hw->acceptance_filter.acr[i].val = ((code_swapped >> (i * 8)) & 0xFF);
|
||||
hw->acceptance_filter.amr[i].val = ((mask_swapped >> (i * 8)) & 0xFF);
|
||||
}
|
||||
hw->mode_reg.afm = single_filter;
|
||||
}
|
||||
|
||||
STATIC void install_standard_filter(canio_listener_obj_t *self, canio_match_obj_t *match) {
|
||||
canio_set_acc_filter(&TWAI, match->id << 21, ~(match->mask << 21), true);
|
||||
self->extended = false;
|
||||
self->standard = true;
|
||||
}
|
||||
|
||||
STATIC void install_extended_filter(canio_listener_obj_t *self, canio_match_obj_t *match) {
|
||||
canio_set_acc_filter(&TWAI, match->id << 3, ~(match->mask << 3), true);
|
||||
self->extended = true;
|
||||
self->standard = false;
|
||||
}
|
||||
|
||||
STATIC void install_all_match_filter(canio_listener_obj_t *self) {
|
||||
canio_set_acc_filter(&TWAI, 0u, ~0u, true);
|
||||
self->extended = true;
|
||||
self->standard = true;
|
||||
}
|
||||
|
||||
__attribute__((noinline,optimize("O0")))
|
||||
void set_filters(canio_listener_obj_t *self, size_t nmatch, canio_match_obj_t **matches) {
|
||||
twai_ll_enter_reset_mode(&TWAI);
|
||||
|
||||
if (!nmatch) {
|
||||
install_all_match_filter(self);
|
||||
} else {
|
||||
canio_match_obj_t *match = matches[0];
|
||||
if (match->extended) {
|
||||
install_extended_filter(self, match);
|
||||
} else {
|
||||
install_standard_filter(self, match);
|
||||
}
|
||||
}
|
||||
|
||||
twai_ll_exit_reset_mode(&TWAI);
|
||||
}
|
||||
|
||||
|
||||
void common_hal_canio_listener_construct(canio_listener_obj_t *self, canio_can_obj_t *can, size_t nmatch, canio_match_obj_t **matches, float timeout) {
|
||||
if (can->fifo_in_use) {
|
||||
mp_raise_ValueError(translate("All RX FIFOs in use"));
|
||||
}
|
||||
if (nmatch > 1) {
|
||||
mp_raise_ValueError(translate("Filters too complex"));
|
||||
}
|
||||
|
||||
// Nothing can fail now so it's safe to assign self->can
|
||||
can->fifo_in_use = 1;
|
||||
self->can = can;
|
||||
self->pending = false;
|
||||
|
||||
set_filters(self, nmatch, matches);
|
||||
self->extended = self->standard = true;
|
||||
|
||||
common_hal_canio_listener_set_timeout(self, timeout);
|
||||
}
|
||||
|
||||
void common_hal_canio_listener_set_timeout(canio_listener_obj_t *self, float timeout) {
|
||||
self->timeout_ms = (int)MICROPY_FLOAT_C_FUN(ceil)(timeout * 1000);
|
||||
}
|
||||
|
||||
float common_hal_canio_listener_get_timeout(canio_listener_obj_t *self) {
|
||||
return self->timeout_ms / 1000.0f;
|
||||
}
|
||||
|
||||
void common_hal_canio_listener_check_for_deinit(canio_listener_obj_t *self) {
|
||||
if (!self->can) {
|
||||
raise_deinited_error();
|
||||
}
|
||||
common_hal_canio_can_check_for_deinit(self->can);
|
||||
}
|
||||
|
||||
// The API has no peek method so we must receive a packet into a holding area
|
||||
// and then we can say that we have 1 message pending
|
||||
int common_hal_canio_listener_in_waiting(canio_listener_obj_t *self) {
|
||||
while (!self->pending && twai_receive(&self->message_in, 0) == ESP_OK) {
|
||||
if (self->message_in.extd && self->extended) {
|
||||
self->pending = true;
|
||||
}
|
||||
if (!self->message_in.extd && self->standard) {
|
||||
self->pending = true;
|
||||
}
|
||||
}
|
||||
return self->pending;
|
||||
}
|
||||
|
||||
mp_obj_t common_hal_canio_listener_receive(canio_listener_obj_t *self) {
|
||||
if (!common_hal_canio_listener_in_waiting(self)) {
|
||||
uint64_t deadline = supervisor_ticks_ms64() + self->timeout_ms;
|
||||
do {
|
||||
if (supervisor_ticks_ms64() > deadline) {
|
||||
return NULL;
|
||||
}
|
||||
} while (!common_hal_canio_listener_in_waiting(self));
|
||||
}
|
||||
|
||||
bool rtr = self->message_in.rtr;
|
||||
|
||||
int dlc = self->message_in.data_length_code;
|
||||
canio_message_obj_t *message = m_new_obj(canio_message_obj_t);
|
||||
message->base.type = rtr ? &canio_remote_transmission_request_type : &canio_message_type;
|
||||
message->extended = self->message_in.extd;
|
||||
message->id = self->message_in.identifier;
|
||||
message->size = dlc;
|
||||
|
||||
if (!rtr) {
|
||||
MP_STATIC_ASSERT(sizeof(self->message_in.data) == sizeof(message->data));
|
||||
memcpy(message->data, self->message_in.data, sizeof(message->data));
|
||||
}
|
||||
|
||||
self->pending = false;
|
||||
|
||||
return message;
|
||||
}
|
||||
|
||||
void common_hal_canio_listener_deinit(canio_listener_obj_t *self) {
|
||||
if (self->can) {
|
||||
self->can->fifo_in_use = false;
|
||||
}
|
||||
self->can = NULL;
|
||||
}
|
40
ports/esp32s2/common-hal/canio/Listener.h
Normal file
40
ports/esp32s2/common-hal/canio/Listener.h
Normal file
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2020 Jeff Epler for Adafruit Industries
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common-hal/canio/CAN.h"
|
||||
#include "shared-module/canio/Match.h"
|
||||
|
||||
typedef struct canio_listener_obj {
|
||||
mp_obj_base_t base;
|
||||
canio_can_obj_t *can;
|
||||
bool extended:1;
|
||||
bool standard:1;
|
||||
bool pending:1;
|
||||
twai_message_t message_in;
|
||||
uint32_t timeout_ms;
|
||||
} canio_listener_obj_t;
|
25
ports/esp32s2/common-hal/canio/__init__.c
Normal file
25
ports/esp32s2/common-hal/canio/__init__.c
Normal file
@ -0,0 +1,25 @@
|
||||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2020 Jeff Epler for Adafruit Industries
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
27
ports/esp32s2/common-hal/canio/__init__.h
Normal file
27
ports/esp32s2/common-hal/canio/__init__.h
Normal file
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2020 Jeff Epler for Adafruit Industries
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
@ -16,6 +16,7 @@ LONGINT_IMPL = MPZ
|
||||
CIRCUITPY_FULL_BUILD = 1
|
||||
CIRCUITPY_AUDIOBUSIO = 0
|
||||
CIRCUITPY_AUDIOIO = 0
|
||||
CIRCUITPY_CANIO = 1
|
||||
CIRCUITPY_COUNTIO = 0
|
||||
CIRCUITPY_FREQUENCYIO = 0
|
||||
CIRCUITPY_I2CPERIPHERAL = 0
|
||||
|
@ -214,7 +214,24 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(canio_can_restart_obj, canio_can_restart);
|
||||
//|
|
||||
//| An empty filter list causes all messages to be accepted.
|
||||
//|
|
||||
//| Timeout dictates how long receive() and next() will block."""
|
||||
//| Timeout dictates how long receive() and next() will block.
|
||||
//|
|
||||
//| Platform specific notes:
|
||||
//|
|
||||
//| SAM E5x supports two Listeners. Filter blocks are shared between the two
|
||||
//| listeners. There are 4 standard filter blocks and 4 extended filter blocks.
|
||||
//| Each block can either match 2 single addresses or a mask of addresses.
|
||||
//| The number of filter blocks can be increased, up to a hardware maximum, by
|
||||
//| rebuilding CircuitPython, but this decreases the CircuitPython free
|
||||
//| memory even if canio is not used.
|
||||
//|
|
||||
//| STM32F405 supports two Listeners. Filter blocks are shared between the two listeners.
|
||||
//| There are 14 filter blocks. Each block can match 2 standard addresses with
|
||||
//| mask or 1 extended address with mask.
|
||||
//|
|
||||
//| ESP32S2 supports one Listener. There is a single filter block, which can either match a
|
||||
//| standard address with mask or an extended address with mask.
|
||||
//| """
|
||||
//| ...
|
||||
//|
|
||||
STATIC mp_obj_t canio_can_listen(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
|
Loading…
Reference in New Issue
Block a user