From fccd3821dd40b451a267fc351b6117c3eea56530 Mon Sep 17 00:00:00 2001 From: Gunar Schorcht Date: Thu, 14 Jul 2022 15:51:35 +0200 Subject: [PATCH] cpu/esp32: port periph/can to ESP-IDF twai HAL --- cpu/esp32/include/can_esp.h | 16 +- cpu/esp32/periph/can.c | 551 +++++++++++++++++------------------- 2 files changed, 259 insertions(+), 308 deletions(-) diff --git a/cpu/esp32/include/can_esp.h b/cpu/esp32/include/can_esp.h index 935153232d..565d9788f5 100644 --- a/cpu/esp32/include/can_esp.h +++ b/cpu/esp32/include/can_esp.h @@ -74,19 +74,9 @@ typedef struct can { uint32_t rx_frames_num; /**< number of frames in ring buffer */ uint32_t rx_filter_num; /**< number of acceptance filters */ - bool powered_up; /**< device is powered up */ - - gpio_t tx_pin; /**< CAN transceiver TX pin */ - gpio_t rx_pin; /**< CAN transceiver RX pin */ -#ifdef ESP_CAN_CLK_OUT - gpio_t clk_out_pin; /**< optional CLK_OUT pin */ -#endif -#ifdef ESP_CAN_BUS_ON_OFF - gpio_t bus_on_off_pin; /**< optional BUS_ON_OFF pin */ -#endif + bool powered_up; /**< device is powered up */ uint32_t events; /**< events triggered by the last interrupt */ - } can_t; /** CAN device type can_t is redefined by ESP CAN */ @@ -99,10 +89,10 @@ typedef struct { uint32_t bitrate; /**< Bitrate */ gpio_t tx_pin; /**< CAN transceiver TX pin */ gpio_t rx_pin; /**< CAN transceiver RX pin */ -#ifdef ESP_CAN_CLK_OUT +#ifdef CAN_CLK_OUT gpio_t clk_out_pin; /**< optional CLK_OUT pin */ #endif -#ifdef ESP_CAN_BUS_ON_OFF +#ifdef CAN_BUS_ON_OFF gpio_t bus_on_off_pin; /**< optional BUS_ON_OFF pin */ #endif } can_conf_t; diff --git a/cpu/esp32/periph/can.c b/cpu/esp32/periph/can.c index 30a827ac35..1f81a0f3f1 100644 --- a/cpu/esp32/periph/can.c +++ b/cpu/esp32/periph/can.c @@ -22,28 +22,17 @@ #include "can_esp.h" #include "can_params.h" #include "esp_attr.h" -#include "esp_common.h" #include "gpio_arch.h" #include "irq_arch.h" -#include "tools.h" -#include "can/common.h" -#include "can/device.h" #include "driver/periph_ctrl.h" -#include "freertos/FreeRTOS.h" +#include "esp_rom_gpio.h" +#include "hal/interrupt_controller_types.h" +#include "hal/interrupt_controller_ll.h" +#include "hal/twai_hal.h" #include "log.h" #include "rom/ets_sys.h" - -#include "periph/can.h" -#include "periph/gpio.h" - -#include "hal/twai_ll.h" #include "soc/gpio_sig_map.h" -#include "soc/gpio_struct.h" -#include "soc/twai_struct.h" -#include "soc/soc.h" - -#include "xtensa/xtensa_api.h" #define ENABLE_DEBUG 0 #include "debug.h" @@ -88,28 +77,13 @@ #define ESP_CAN_MAX_DATA_LEN 8 /* 8 data bytes at maximum */ #define ESP_CAN_FRAME_LEN 13 /* 13 bytes at maximum */ -typedef union esp_can_frame { - struct { - struct { - uint8_t dlc :4; /* frame payload length */ - uint8_t zero:2; /* don't care, should be zero */ - uint8_t rtr :1; /* remote transmission request frame */ - uint8_t eff :1; /* extended ID frame format */ - }; - union { - struct { - uint8_t id[ESP_CAN_SFF_ID_LEN]; /* 11 bit standard frame identifier */ - uint8_t data[ESP_CAN_MAX_DATA_LEN]; /* data bytes */ - uint8_t reserved8[2]; - } standard; - struct { - uint8_t id[ESP_CAN_EFF_ID_LEN]; /* 29 bit standard frame identifier */ - uint8_t data[ESP_CAN_MAX_DATA_LEN]; /* data bytes */ - } extended; - }; - }; - uint8_t bytes[ESP_CAN_FRAME_LEN]; -} _esp_can_frame_t; +#if !defined(CAN_CLK_OUT) && !defined(CAN_CLK_OUT_DIV) +/* if CAN_CLK_OUT is not used, CAN_CLKOUT_DIV is set to 0 */ +#define CAN_CLK_OUT_DIV 0 +#elif defined(CAN_CLK_OUT) && !defined(CAN_CLK_OUT_DIV) +/* if CAN_CLK_OUT is used, CAN_CLK_OUT_DIV has to be defined */ +#error "CAN_CLK_OUT pin defined but not the CAN_CLK_OUT_DIV" +#endif /* driver interface functions */ static int _esp_can_init(candev_t *candev); @@ -121,13 +95,16 @@ static int _esp_can_abort(candev_t *candev, const struct can_frame *frame); static int _esp_can_set_filter(candev_t *candev, const struct can_filter *filter); static int _esp_can_remove_filter(candev_t *candev, const struct can_filter *filter); -/* internal function declarations, we don't need device since we habe only one */ -static void _esp_can_set_bittiming (can_t *dev); +/* internal function declarations, we don't need the device since we have only one */ +static void _esp_can_set_bittiming(can_t *dev); +static void _esp_can_start(can_t *dev); +static void _esp_can_stop(can_t *dev); static void _esp_can_power_up(can_t *dev); static void _esp_can_power_down(can_t *dev); -static void _esp_can_init_pins(can_t *dev); static int _esp_can_set_mode(can_t *dev, canopt_state_t state); -static void IRAM_ATTR _esp_can_intr_handler (void *arg); +static void _esp_can_init_pins(void); +static void _esp_can_deinit_pins(void); +static void IRAM_ATTR _esp_can_intr_handler(void *arg); /** ESP32 CAN low level device driver data */ static const candev_driver_t _esp_can_driver = { @@ -221,6 +198,8 @@ static void _esp_can_isr(candev_t *candev) } } +twai_hal_context_t hw; + static int _esp_can_init(candev_t *candev) { can_t *dev = container_of(candev, can_t, candev); @@ -229,12 +208,12 @@ static int _esp_can_init(candev_t *candev) assert(dev); - /* initialize used GPIOs */ - _esp_can_init_pins(dev); - - /* power up and configure the CAN controller */ + /* power up and configure the CAN controller and initialize the pins */ _esp_can_power_up(dev); + /* start the CAN controller in configured operation mode */ + _esp_can_start(dev); + return 0; } @@ -259,18 +238,18 @@ static int _esp_can_send(candev_t *candev, const struct can_frame *frame) dev->tx_frame = (struct can_frame*)frame; /* prepare the frame as expected by ESP32 */ - _esp_can_frame_t esp_frame = {}; + twai_hal_frame_t esp_frame = { }; esp_frame.dlc = frame->can_dlc; esp_frame.rtr = (frame->can_id & CAN_RTR_FLAG); - esp_frame.eff = (frame->can_id & CAN_EFF_FLAG); + esp_frame.frame_format = (frame->can_id & CAN_EFF_FLAG); /* esp_frame is a union that provides two views on the same memory: one * tailored for efficient access and the other for readable code. Likely * due to cppcheck not finding all headers it wrongly assumes that values * are assigned but never read again (unreadVariable). But the union members * are read via the aliases to the same memory. */ - if (esp_frame.eff) { + if (esp_frame.frame_format) { uint32_t id = frame->can_id & CAN_EFF_MASK; /* cppcheck-suppress unreadVariable */ esp_frame.extended.id[0] = (id >> 21) & 0xff; @@ -289,16 +268,17 @@ static int _esp_can_send(candev_t *candev, const struct can_frame *frame) esp_frame.standard.id[1] = (id << 5) & 0xff; } - memcpy(esp_frame.eff ? &esp_frame.extended.data - : &esp_frame.standard.data, frame->data, ESP_CAN_MAX_DATA_LEN); - - /* place the frame in TX buffer of ESP32 */ - for (unsigned i = 0; i < ESP_CAN_FRAME_LEN; i++) { - CAN.tx_rx_buffer[i].val = esp_frame.bytes[i]; - } + /* copy data from can_frame to esp_frame */ + memcpy(esp_frame.frame_format ? &esp_frame.extended.data + : &esp_frame.standard.data, + frame->data, ESP_CAN_MAX_DATA_LEN); /* set the single shot transmit command without self-receiption */ - CAN.command_reg.val = ESP_CMD_TX_SINGLE_SHOT; + esp_frame.single_shot = 1; + esp_frame.self_reception = 0; + + /* place the frame in TX buffer and trigger the command */ + twai_hal_set_tx_buffer_and_transmit(&hw, &esp_frame); critical_exit(); @@ -322,32 +302,48 @@ static int _esp_can_set(candev_t *candev, canopt_t opt, void *value, size_t valu return -EOVERFLOW; } dev->candev.bittiming = *((struct can_bittiming*)value); + _esp_can_stop(dev); _esp_can_set_bittiming(dev); + _esp_can_start(dev); res = sizeof(struct can_bittiming); break; case CANOPT_STATE: - DEBUG("%s CANOPT_STATE\n", __func__); + DEBUG("%s CANOPT_STATE %d\n", __func__, *((canopt_state_t *)value)); + if (dev->powered_up) { + _esp_can_stop(dev); + } res = _esp_can_set_mode(dev, *((canopt_state_t *)value)); + if (dev->powered_up) { + _esp_can_start(dev); + } if (res == 0) { res = sizeof(uint16_t); } break; case CANOPT_TEC: - case CANOPT_REC: - DEBUG("%s %s\n", __func__, (opt == CANOPT_TEC) ? "CANOPT_TEC" : "CANOPT_REC"); + DEBUG("%s %s\n", __func__, "CANOPT_TEC"); if (value_len < sizeof(uint16_t)) { DEBUG("%s size error\n", __func__); return -EOVERFLOW; } - if (opt == CANOPT_TEC) { - CAN.tx_error_counter_reg.txerr = *((uint16_t*)value); - } - else { - CAN.rx_error_counter_reg.rxerr = *((uint16_t*)value); + _esp_can_stop(dev); + twai_ll_set_tec(hw.dev, *((uint16_t*)value)); + _esp_can_start(dev); + res = sizeof(uint16_t); + break; + + case CANOPT_REC: + DEBUG("%s %s\n", __func__, "CANOPT_REC"); + if (value_len < sizeof(uint16_t)) { + DEBUG("%s size error\n", __func__); + return -EOVERFLOW; } + _esp_can_stop(dev); + twai_ll_set_rec(hw.dev, *((uint16_t*)value)); + _esp_can_start(dev); res = sizeof(uint16_t); break; @@ -406,20 +402,26 @@ static int _esp_can_get(candev_t *candev, canopt_t opt, void *value, size_t max_ break; case CANOPT_TEC: - case CANOPT_REC: - DEBUG("%s %s\n", __func__, (opt == CANOPT_TEC) ? "CANOPT_TEC" : "CANOPT_REC"); + DEBUG("%s %s\n", __func__, "CANOPT_TEC"); if (max_len < sizeof(uint16_t)) { res = EOVERFLOW; break; } - if (opt == CANOPT_TEC) { - *((uint16_t *)value) = CAN.tx_error_counter_reg.txerr; - } - else { - *((uint16_t *)value) = CAN.rx_error_counter_reg.rxerr; + *((uint16_t *)value) = twai_ll_get_tec(hw.dev); + + res = sizeof(uint16_t); + break; + + case CANOPT_REC: + DEBUG("%s %s\n", __func__, "CANOPT_REC"); + if (max_len < sizeof(uint16_t)) { + res = EOVERFLOW; + break; } + *((uint16_t *)value) = twai_ll_get_rec(hw.dev); + res = sizeof(uint16_t); break; @@ -461,7 +463,7 @@ static int _esp_can_abort(candev_t *candev, const struct can_frame *frame) assert(frame); /* abort transmission command */ - CAN.command_reg.val = ESP_CMD_ABORT_TX; + twai_ll_set_cmd_abort_tx(hw.dev); /* mark the transmitter as free */ dev->tx_frame = NULL; @@ -503,6 +505,7 @@ static int _esp_can_set_filter(candev_t *candev, const struct can_filter *filter /* set the filter and return the filter index */ dev->rx_filters[i] = *filter; dev->rx_filter_num++; + return i; } @@ -530,90 +533,52 @@ static int _esp_can_remove_filter(candev_t *candev, const struct can_filter *fil } /** - * Internal functions. All these functions have no dev parameter since - * they directly access the only one existing CAN controller. + * Internal functions. */ -static void _esp_can_set_reset_mode(void) -{ - DEBUG("%s\n", __func__); - - while (CAN.mode_reg.rm != 1) { - CAN.mode_reg.rm = 1; - } -} - -static void _esp_can_set_operating_mode(void) -{ - DEBUG("%s\n", __func__); - - while (CAN.mode_reg.rm != 0) { - CAN.mode_reg.rm = 0; - } -} - -static int _esp_can_config(can_t *dev) +static void _esp_can_start(can_t *dev) { DEBUG("%s dev=%p\n", __func__, dev); - assert(dev); - critical_enter(); + /* start the CAN controller in configured mode */ + switch (dev->state) { + case CANOPT_STATE_LISTEN_ONLY: + twai_hal_start(&hw, TWAI_MODE_LISTEN_ONLY); + break; + case CANOPT_STATE_SLEEP: + /* sleep mode is not supported, the normal mode is used instead */ + case CANOPT_STATE_ON: + twai_hal_start(&hw, TWAI_MODE_NORMAL); + break; + default: + break; + } +} - /* reset mode to be able to write configuration registers */ - _esp_can_set_reset_mode(); +static void _esp_can_stop(can_t *dev) +{ + DEBUG("%s dev=%p\n", __func__, dev); + assert(dev); - /* configuration is done in listen only mode */ - CAN.mode_reg.stm = 0; - CAN.mode_reg.lom = 1; - - /* Use SJA1000 PeliCAN mode and registers layout */ - CAN.clock_divider_reg.cm = 1; - -#ifndef ESP_CAN_CLK_OUT - CAN.clock_divider_reg.co = 1; - CAN.clock_divider_reg.cd = 0; -#else - uint32_t clk_out_div = ESP_CAN_CLK_OUT_DIV / 2 - 1; - clk_out_div = (clk_out_div < 7) ? clk_out_div : 7; - CAN.clock_divider_reg.co = 0; - CAN.clock_divider_reg.cd = clk_out_div; -#endif - - /* set error counter values and warning limits */ - CAN.error_warning_limit_reg.ewl = ESP_CAN_ERROR_WARNING_LIMIT; - CAN.tx_error_counter_reg.txerr = 0; - CAN.rx_error_counter_reg.rxerr = 0; - - /* accept all CAN messages, filtering is done by software */ - CAN.mode_reg.afm = 0; /* single filter */ - CAN.acceptance_filter.amr[0].byte = 0xff; /* all bits masked */ - CAN.acceptance_filter.amr[1].byte = 0xff; - CAN.acceptance_filter.amr[2].byte = 0xff; - CAN.acceptance_filter.amr[3].byte = 0xff; - - /* clear interrupt status register by read and enable all interrupts */ - uint32_t tmp = CAN.interrupt_reg.val; (void)tmp; - CAN.interrupt_enable_reg.val = ESP_CAN_INTR_MASK; - - /* route CAN interrupt source to CPU interrupt and enable it */ - intr_matrix_set(PRO_CPU_NUM, ETS_CAN_INTR_SOURCE, CPU_INUM_CAN); - xt_set_interrupt_handler(CPU_INUM_CAN, _esp_can_intr_handler, (void*)(uintptr_t)dev); - xt_ints_on(BIT(CPU_INUM_CAN)); - - /* set bittiming from parameters as given in device data */ - _esp_can_set_bittiming(dev); - - /* switch to operating mode */ - _esp_can_set_operating_mode(); - - critical_exit(); - - return 0; + /* stop the CAN controller by entering the reset mode */ + twai_hal_stop(&hw); } static void _esp_can_power_up(can_t *dev) { + /** + * Function esp_can_power_up + * - powers up the CAN controller, + * - initializes the HAL context, + * - sets the timing and the acceptance filters according to configuration + * - resets the error counters and sets the warning limit + * + * The CAN controller must be started in configured mode explicitly + * afterwards using function _esp_can_start(). + */ + + DEBUG("%s dev=%p\n", __func__, dev); assert(dev); /* just return when already powered up */ @@ -621,20 +586,42 @@ static void _esp_can_power_up(can_t *dev) return; } - DEBUG("%s dev=%p\n", __func__, dev); - critical_enter(); - /* power up and (re)configure the CAN controller */ - periph_module_enable(PERIPH_CAN_MODULE); + /* power up the peripheral */ + periph_module_reset(PERIPH_TWAI_MODULE); + periph_module_enable(PERIPH_TWAI_MODULE); + + /* initialize the HAL context, on return the CAN controller is in listen + * only mode but not yet started, the error counters are reset and + * pending interrupts cleared */ + + if (!twai_hal_init(&hw)) { + assert(false); + } + + /* set bittiming from parameters as given in device data */ + _esp_can_set_bittiming(dev); + + /* set warning limit */ + twai_ll_set_err_warn_lim(hw.dev, ESP_CAN_ERROR_WARNING_LIMIT); + + /* route CAN interrupt source to CPU interrupt and enable it */ + intr_matrix_set(PRO_CPU_NUM, ETS_TWAI_INTR_SOURCE, CPU_INUM_CAN); + intr_cntrl_ll_set_int_handler(CPU_INUM_CAN, _esp_can_intr_handler, (void*)(uintptr_t)dev); + intr_cntrl_ll_enable_interrupts(BIT(CPU_INUM_CAN)); + + /* initialize used GPIOs */ + _esp_can_init_pins(); + dev->powered_up = true; - _esp_can_config (dev); critical_exit(); } static void _esp_can_power_down(can_t *dev) { + DEBUG("%s dev=%p\n", __func__, dev); assert(dev); /* just return when already powered down */ @@ -642,43 +629,76 @@ static void _esp_can_power_down(can_t *dev) return; } - DEBUG("%s dev=%p\n", __func__, dev); + /* deinitialize used GPIOs */ + _esp_can_deinit_pins(); + + /* stop the CAN controller and deinitialize the HAL context */ + twai_hal_stop(&hw); + twai_hal_deinit(&hw); /* power down the CAN controller */ periph_module_disable(PERIPH_CAN_MODULE); + dev->powered_up = false; } -static void _esp_can_init_pins(can_t *dev) +static void _esp_can_init_pins(void) { - DEBUG("%s dev=%p\n", __func__, dev); + DEBUG("%s\n", __func__); - assert(dev); + const can_conf_t *cfg = &candev_conf[0]; /* Init TX pin */ - gpio_init(dev->tx_pin, GPIO_OUT); - gpio_set_pin_usage(dev->tx_pin, _CAN); - GPIO.func_out_sel_cfg[dev->tx_pin].func_sel = TWAI_TX_IDX; + gpio_init(cfg->tx_pin, GPIO_OUT); + esp_rom_gpio_connect_out_signal(cfg->tx_pin, TWAI_TX_IDX, false, false); + esp_rom_gpio_pad_select_gpio(cfg->tx_pin); + gpio_set_pin_usage(cfg->tx_pin, _CAN); /* Init RX pin */ - gpio_init(dev->rx_pin, GPIO_IN); - gpio_set_pin_usage(dev->rx_pin, _CAN); - GPIO.func_in_sel_cfg[CAN_RX_IDX].sig_in_sel = 1; - GPIO.func_in_sel_cfg[CAN_RX_IDX].sig_in_inv = 0; - GPIO.func_in_sel_cfg[CAN_RX_IDX].func_sel = dev->rx_pin; + gpio_init(cfg->rx_pin, GPIO_IN); + esp_rom_gpio_connect_in_signal(cfg->rx_pin, TWAI_RX_IDX, false); + esp_rom_gpio_pad_select_gpio(cfg->rx_pin); + gpio_set_pin_usage(cfg->rx_pin, _CAN); -#ifdef ESP_CAN_CLK_OUT +#ifdef CAN_CLK_OUT /* Init CLK_OUT pin (optional) if defined */ - gpio_init(dev->clk_out_pin, GPIO_OD); - gpio_set_pin_usage(dev->clk_out_pin, _CAN); - GPIO.func_out_sel_cfg[dev->clk_out_pin].func_sel = TWAI_CLKOUT_IDX; + gpio_init(cfg->clk_out_pin, GPIO_OD); + esp_rom_gpio_connect_out_signal(cfg->clk_out_pin, TWAI_CLKOUT_IDX, false, false); + esp_rom_gpio_pad_select_gpio(cfg->clk_out_pin); + gpio_set_pin_usage(cfg->clk_out_pin, _CAN); #endif +#ifdef CAN_BUS_ON_OFF /* Init BUS_ON_OFF pin pin (optional) if defined */ -#ifdef ESP_CAN_BUS_ON_OFF - gpio_init(dev->bus_on_of_pin, GPIO_OD); - gpio_set_pin_usage(dev->bus_on_of_pin, _CAN); - GPIO.func_out_sel_cfg[dev->bus_on_of_pin].func_sel = TWAI_BUS_OFF_ON_IDX; + gpio_init(cfg->bus_on_of_pin, GPIO_OD); + esp_rom_gpio_connect_out_signal(cfg->bus_on_of_pin, TWAI_BUS_OFF_ON_IDX, false, false); + esp_rom_gpio_pad_select_gpio(cfg->bus_on_of_pin); + gpio_set_pin_usage(cfg->bus_on_of_pin, _CAN); +#endif +} + +static void _esp_can_deinit_pins(void) +{ + const can_conf_t *cfg = &candev_conf[0]; + + /* Reset TX pin */ + gpio_set_pin_usage(cfg->tx_pin, _GPIO); + gpio_init(cfg->tx_pin, GPIO_IN_PU); + + /* Reset RX pin */ + gpio_set_pin_usage(cfg->rx_pin, _GPIO); + gpio_init(cfg->rx_pin, GPIO_IN_PU); + +#ifdef CAN_CLK_OUT + /* Reset CLK_OUT pin (optional) if defined */ + gpio_set_pin_usage(cfg->clk_out_pin, _GPIO); + gpio_init(cfg->clk_out_pin, GPIO_IN); +#endif + +#ifdef CAN_BUS_ON_OFF + /* Reset BUS_ON_OFF pin pin (optional) if defined */ + gpio_set_pin_usage(cfg->bus_on_of_pin, _GPIO); + gpio_init(cfg->bus_on_of_pin, GPIO_IN_PD); #endif } @@ -690,48 +710,30 @@ static int _esp_can_set_mode(can_t *dev, canopt_state_t state) critical_enter(); + /* set the new mode */ + dev->state = state; + switch (state) { case CANOPT_STATE_OFF: - /* just power down the CAN controller */ + /* stop and power down the CAN controller */ _esp_can_power_down(dev); break; - case CANOPT_STATE_LISTEN_ONLY: - /* power up and (re)configure the CAN controller if necessary */ - _esp_can_power_up(dev); - /* set the new mode (has to be done in reset mode) */ - _esp_can_set_reset_mode(); - CAN.mode_reg.stm = 0; - CAN.mode_reg.lom = 1; - _esp_can_set_operating_mode (); - break; - case CANOPT_STATE_SLEEP: - /* Sleep mode is not supported by ESP32, State On is used instead. */ - #if 0 - /* power up and (re)configure the CAN controller if necessary */ - _esp_can_power_up(dev); - /* set the sleep mode (not necessary to set reset mode before) */ - CAN.mode_reg.sleep_mode = 1; - break; - #endif - + /* sleep mode is not supported, so CAN can't be powered down */ + case CANOPT_STATE_LISTEN_ONLY: case CANOPT_STATE_ON: /* power up and (re)configure the CAN controller if necessary */ _esp_can_power_up(dev); - /* set the new mode (has to be done in reset mode) */ - _esp_can_set_reset_mode(); - CAN.mode_reg.stm = 0; - CAN.mode_reg.lom = 0; - _esp_can_set_operating_mode (); + /* restart the CAN controller in new mode */ + _esp_can_stop(dev); + _esp_can_start(dev); break; default: LOG_TAG_ERROR ("esp_can", "state value %d not supported\n", state); break; } - dev->state = state; - critical_exit(); return 0; @@ -745,99 +747,71 @@ static void IRAM_ATTR _esp_can_intr_handler(void *arg) critical_enter(); - /* read the registers to clear them */ - uint32_t sta_reg = CAN.status_reg.val; - uint32_t int_reg = CAN.interrupt_reg.val; + uint32_t events = twai_hal_get_events(&hw); - DEBUG("%s int=%08x sta=%08x\n", __func__, int_reg, sta_reg); - - /* Wake-Up Interrupt (not supported by ESP32) */ - if (int_reg & BIT(4)) { - DEBUG("%s wake-up interrupt\n", __func__); - dev->events |= ESP_CAN_EVENT_WAKE_UP; - } + DEBUG("%s events=%08"PRIx32"\n", __func__, events); /* Arbitration Lost Interrupt */ - if (int_reg & TWAI_LL_INTR_ALI) { + if (events & TWAI_HAL_EVENT_ARB_LOST) { DEBUG("%s arbitration lost interrupt\n", __func__); /* can only happen during transmission, handle it as error in single shot transmission */ dev->events |= ESP_CAN_EVENT_TX_ERROR; } - /* bus or error status has changed, handle this first */ - if (int_reg & TWAI_LL_INTR_EI) { + /* BUS_OFF state condition */ + if (events & TWAI_HAL_EVENT_BUS_OFF) { + DEBUG("%s bus-off state interrupt\n", __func__); + /* save the event */ + dev->events |= ESP_CAN_EVENT_BUS_OFF; + } - /* BUS_OFF state condition */ - if ((sta_reg & TWAI_LL_STATUS_ES) && (sta_reg & TWAI_LL_STATUS_BS)) { - DEBUG("%s bus-off state interrupt\n", __func__); - /* switch to listen only mode to freeze the RX error counter */ - _esp_can_set_mode (dev, CANOPT_STATE_LISTEN_ONLY); - /* save the event */ - dev->events |= ESP_CAN_EVENT_BUS_OFF; - } - - /* ERROR_WARNING state condition, RX/TX error counter are > 96 */ - else if ((sta_reg & TWAI_LL_STATUS_ES) && !(sta_reg & TWAI_LL_STATUS_BS)) { - DEBUG("%s error warning interrupt\n", __func__); - /* save the event */ - dev->events |= ESP_CAN_EVENT_ERROR_WARNING; - } + /* ERROR_WARNING state condition, RX/TX error counter are > 96 */ + if (events & TWAI_HAL_EVENT_ABOVE_EWL) { + DEBUG("%s error warning interrupt\n", __func__); + /* save the event */ + dev->events |= ESP_CAN_EVENT_ERROR_WARNING; } /* enter to / return from ERROR_PASSIVE state */ - if (int_reg & TWAI_LL_INTR_EPI) { - /* enter to the ERROR_PASSIVE state when one of the error counters is >= 128 */ - if (CAN.tx_error_counter_reg.txerr >= ESP_CAN_ERROR_PASSIVE_LIMIT || - CAN.rx_error_counter_reg.rxerr >= ESP_CAN_ERROR_PASSIVE_LIMIT) { - DEBUG("%s error passive interrupt %d %d\n", __func__, - CAN.tx_error_counter_reg.txerr, - CAN.rx_error_counter_reg.rxerr); - /* save the event */ - dev->events |= ESP_CAN_EVENT_ERROR_PASSIVE; - } + if (events & TWAI_HAL_EVENT_ERROR_PASSIVE) { + DEBUG("%s error passive interrupt %"PRIu32" %"PRIu32"\n", __func__, + twai_ll_get_tec(hw.dev), twai_ll_get_rec(hw.dev)); + /* save the event */ + dev->events |= ESP_CAN_EVENT_ERROR_PASSIVE; } /* * Bus Error Interrupt (bit, stuff, crc, form, ack), details are captured * in ECC register (see SJA1000 Data sheet, Table 20 and 21) */ - - if (int_reg & TWAI_LL_INTR_BEI) { + if (events & TWAI_HAL_EVENT_BUS_ERR) { + DEBUG("%s bus error interrupt\n", __func__); /* save the event */ - DEBUG("%s bus error interrupt, ecc=%08x\n", __func__, - CAN.error_code_capture_reg.val); - dev->events |= CAN.error_code_capture_reg.dir ? ESP_CAN_EVENT_RX_ERROR - : ESP_CAN_EVENT_TX_ERROR; + dev->events |= ESP_CAN_EVENT_TX_ERROR; } /* TX buffer becomes free */ - if (int_reg & TWAI_LL_INTR_TI) { + if (events & TWAI_HAL_EVENT_TX_BUFF_FREE) { DEBUG("%s transmit interrupt\n", __func__); /* save the event */ dev->events |= ESP_CAN_EVENT_TX_CONFIRMATION; } /* RX buffer has one or more frames */ - if (int_reg & TWAI_LL_INTR_RI) { + if (events & TWAI_HAL_EVENT_RX_BUFF_FRAME) { /* get the number of messages in receive buffer */ - uint32_t msg_cnt = CAN.rx_message_counter_reg.val; + uint32_t msg_cnt = twai_hal_get_rx_msg_count(&hw); - DEBUG("%s receive interrupt, msg_cnt=%d\n", __func__, msg_cnt); + DEBUG("%s receive interrupt, msg_cnt=%"PRIu32"\n", __func__, msg_cnt); for (unsigned i = 0; i < msg_cnt; i++) { - _esp_can_frame_t esp_frame; - /* fetch the frame from RX buffer of ESP32 */ - for (unsigned j = 0; j < ESP_CAN_FRAME_LEN; j++) { - esp_frame.bytes[j] = CAN.tx_rx_buffer[j].val; - } - /* clear RX buffer at read position */ - CAN.command_reg.val = ESP_CMD_RELEASE_RX_BUFF; - - if (dev->rx_frames_num < ESP_CAN_MAX_RX_FRAMES) { + twai_hal_frame_t esp_frame; + if (twai_hal_read_rx_buffer_and_clear(&hw, &esp_frame) && + (dev->rx_frames_num < ESP_CAN_MAX_RX_FRAMES)) { /* prepare the CAN frame from ESP32 CAN frame */ struct can_frame frame = {}; - if (esp_frame.eff) { + if (esp_frame.frame_format) { frame.can_id = esp_frame.extended.id[0]; frame.can_id = (frame.can_id << 8) | esp_frame.extended.id[1]; frame.can_id = (frame.can_id << 8) | esp_frame.extended.id[2]; @@ -850,7 +824,7 @@ static void IRAM_ATTR _esp_can_intr_handler(void *arg) memcpy(frame.data, &esp_frame.standard.data, CAN_MAX_DLEN); } frame.can_id |= esp_frame.rtr ? CAN_RTR_FLAG : 0; - frame.can_id |= esp_frame.eff ? CAN_EFF_FLAG : 0; + frame.can_id |= esp_frame.frame_format ? CAN_EFF_FLAG : 0; frame.can_dlc = esp_frame.dlc; /* apply acceptance filters only if they are set */ @@ -877,27 +851,20 @@ static void IRAM_ATTR _esp_can_intr_handler(void *arg) dev->rx_frames_num++; dev->rx_frames_wptr++; dev->rx_frames_wptr &= ESP_CAN_MAX_RX_FRAMES-1; - } + + /* at least one RX frame has been saved */ + dev->events |= ESP_CAN_EVENT_RX_INDICATION; + } } else { DEBUG("%s receive buffer overrun\n", __func__); /* we use rx error since there is no separate overrun error */ dev->events |= ESP_CAN_EVENT_RX_ERROR; } - } - /* save the event */ - dev->events |= ESP_CAN_EVENT_RX_INDICATION; } - /* data overrun interrupts are not handled */ - if (int_reg & BIT(3)) { - DEBUG("%s data overrun interrupt\n", __func__); - /* we use rx error since there is no separate overrun error */ - dev->events |= ESP_CAN_EVENT_RX_INDICATION; - } - - DEBUG("%s events=%08x\n", __func__, dev->events); + DEBUG("%s events=%08"PRIx32"\n", __func__, dev->events); /* inform the upper layer that there are events to be handled */ if (dev->events && dev->candev.event_callback) { @@ -907,34 +874,38 @@ static void IRAM_ATTR _esp_can_intr_handler(void *arg) critical_exit(); } +/* accept all CAN messages by default, filtering is done by software */ +static const twai_filter_config_t twai_filter = { + .single_filter = false, /* single filter */ + .acceptance_mask = UINT32_MAX, /* all bits masked */ +}; + static void _esp_can_set_bittiming(can_t *dev) { + /* sets the bus timing, the CAN controller has to stopped before using + * function _esp_can_stop(dev) and has to be restartet using + * function _esp_can_start() afterwards */ + assert(dev); struct can_bittiming* timing = &dev->candev.bittiming; - DEBUG("%s %p bitrate=%d, brp=%d, sample_point=%d, tq=%d, " - "prop_seg=%d phase_seg1=%d, phase_seg2=%d, sjw =%d\n", __func__, dev, + DEBUG("%s %p bitrate=%"PRIu32", brp=%"PRIu32", sample_point=%"PRIu32", " + "tq=%"PRIu32", prop_seg=%"PRIu32" phase_seg1=%"PRIu32", " + "phase_seg2=%"PRIu32", sjw =%"PRIu32"\n", __func__, dev, timing->bitrate, timing->brp, timing->sample_point, timing->tq, timing->prop_seg, timing->phase_seg1, timing->phase_seg2, timing->sjw); - _esp_can_set_reset_mode(); + twai_timing_config_t twai_timing = { + .brp = timing->brp, + .sjw = timing->sjw, + .tseg_1 = timing->prop_seg + timing->phase_seg1, + .tseg_2 = timing->phase_seg2, + }; - /* Again cppcheck gets off rails due to missing concept of union (see - * explanation above), so we suppress false unreadVariable here */ - /* cppcheck-suppress unreadVariable */ - CAN.bus_timing_0_reg.brp = (timing->brp / 2) - 1; - /* cppcheck-suppress unreadVariable */ - CAN.bus_timing_0_reg.sjw = timing->sjw - 1; - /* cppcheck-suppress unreadVariable */ - CAN.bus_timing_1_reg.tseg1 = (timing->prop_seg + timing->phase_seg1) - 1; - /* cppcheck-suppress unreadVariable */ - CAN.bus_timing_1_reg.tseg2 = timing->phase_seg2 - 1; - /* cppcheck-suppress unreadVariable */ - CAN.bus_timing_1_reg.sam = 0; - - _esp_can_set_operating_mode(); + twai_hal_configure(&hw, &twai_timing, &twai_filter, + ESP_CAN_INTR_MASK, CAN_CLK_OUT_DIV); } void can_init(can_t *dev, const can_conf_t *conf) @@ -947,20 +918,11 @@ void can_init(can_t *dev, const can_conf_t *conf) dev->candev.driver = &_esp_can_driver; dev->candev.bittiming.bitrate = conf->bitrate; - dev->tx_pin = conf->tx_pin; - dev->rx_pin = conf->rx_pin; -#ifdef ESP_CAN_CLK_OUT - dev->clk_out_pin = conf->clk_out_pin; -#endif -#ifdef ESP_CAN_BUS_ON_OFF - dev->bus_on_off_pin = conf->bus_on_off_pin; -#endif - /* determine the hardware bittiming constants */ struct can_bittiming_const timing_const = bittiming_const; /* calculate the initial bittimings from the bittiming constants */ - can_device_calc_bittiming (ESP_CAN_CLOCK, &timing_const, &dev->candev.bittiming); + can_device_calc_bittiming(ESP_CAN_CLOCK, &timing_const, &dev->candev.bittiming); /* initialize other members */ dev->state = CAN_STATE_SLEEPING; @@ -970,7 +932,6 @@ void can_init(can_t *dev, const can_conf_t *conf) dev->rx_frames_num = 0; dev->rx_filter_num = 0; dev->powered_up = false; - } void can_print_config(void)