blob: 11ffc26f07c9cd1d88f21b5389253f7fed127356 [file] [log] [blame]
/****************************************************************************
* arch/risc-v/src/common/espressif/esp_twai.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <stdio.h>
#include <sys/types.h>
#include <inttypes.h>
#include <stdint.h>
#include <stdbool.h>
#include <assert.h>
#include <errno.h>
#include <debug.h>
#include <arch/board/board.h>
#include <nuttx/irq.h>
#include <nuttx/arch.h>
#include <nuttx/spinlock.h>
#include <nuttx/can/can.h>
#include <nuttx/signal.h>
#include "riscv_internal.h"
#include "esp_gpio.h"
#include "esp_twai.h"
#include "esp_irq.h"
#include "esp_clk.h"
#include "periph_ctrl.h"
#include "hal/twai_hal.h"
#include "hal/twai_ll.h"
#include "soc/gpio_sig_map.h"
#include "soc/reg_base.h"
#if defined(CONFIG_ESPRESSIF_TWAI)
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
# if defined(CONFIG_CAN_LOOPBACK) && defined(CONFIG_ESPRESSIF_TWAI_TEST_MODE)
# define TX_PIN_ATTR (OUTPUT_FUNCTION_1 | INPUT_FUNCTION_1)
# define RX_PIN_ATTR (OUTPUT_FUNCTION_1 | INPUT_FUNCTION_1)
# else
# define TX_PIN_ATTR OUTPUT_FUNCTION_1
# define RX_PIN_ATTR INPUT_FUNCTION_1
# endif
# ifdef CONFIG_ESPRESSIF_TWAI0
# ifdef CONFIG_TWAI0_TIMING_100KBITS
#define TWAI0_TIMING_CONFIG TWAI_TIMING_CONFIG_100KBITS()
# elif CONFIG_TWAI0_TIMING_125KBITS
#define TWAI0_TIMING_CONFIG TWAI_TIMING_CONFIG_125KBITS()
# elif CONFIG_TWAI0_TIMING_250KBITS
#define TWAI0_TIMING_CONFIG TWAI_TIMING_CONFIG_250KBITS()
# elif CONFIG_TWAI0_TIMING_500KBITS
#define TWAI0_TIMING_CONFIG TWAI_TIMING_CONFIG_500KBITS()
# else
#define TWAI0_TIMING_CONFIG TWAI_TIMING_CONFIG_800KBITS()
# endif
# endif
# ifdef CONFIG_ESPRESSIF_TWAI1
# ifdef CONFIG_TWAI1_TIMING_100KBITS
#define TWAI1_TIMING_CONFIG TWAI_TIMING_CONFIG_100KBITS()
# elif CONFIG_TWAI1_TIMING_125KBITS
#define TWAI1_TIMING_CONFIG TWAI_TIMING_CONFIG_125KBITS()
# elif CONFIG_TWAI1_TIMING_250KBITS
#define TWAI1_TIMING_CONFIG TWAI_TIMING_CONFIG_250KBITS()
# elif CONFIG_TWAI1_TIMING_500KBITS
#define TWAI1_TIMING_CONFIG TWAI_TIMING_CONFIG_500KBITS()
# else
#define TWAI1_TIMING_CONFIG TWAI_TIMING_CONFIG_800KBITS()
# endif
# endif
# ifdef CONFIG_ESPRESSIF_ESP32C3
# define INT_ENA_REG(hw) hw->interrupt_enable_reg.val
# define PERIPH_TWAI0_MODULE PERIPH_TWAI_MODULE
# define TWAI0_TX_IDX TWAI_TX_IDX
# define TWAI0_RX_IDX TWAI_RX_IDX
# define ETS_TWAI0_INTR_SOURCE ETS_TWAI_INTR_SOURCE
# define ESP_IRQ_TWAI0 ESP_IRQ_TWAI
# else
# define INT_ENA_REG(hw) hw->interrupt_enable.val
# endif /* CONFIG_ESPRESSIF_ESP32C3 */
# ifdef CONFIG_ESPRESSIF_ESP32H2
# define TWAI0_TX_IDX TWAI_TX_IDX
# define TWAI0_RX_IDX TWAI_RX_IDX
# endif /* CONFIG_ESPRESSIF_ESP32H2 */
/* Configuration ************************************************************/
# ifndef CONFIG_CAN_EXTID
# define EXTID 0
# else
# define EXTID 1
# endif
# ifndef CONFIG_CAN_LOOPBACK
# define LOOPBACK 0
# else
# define LOOPBACK 1
# endif
/* Default values written to various registers on initialization */
# define TWAI_DEFAULT_INTERRUPTS 0xe7 /* Exclude data overrun (bit[3]) and brp_div (bit[4]) */
struct esp_twai_dev_s
{
/* Device configuration */
uint8_t port; /* TWAI port number */
uint8_t periph; /* Peripheral ID */
uint8_t irq; /* IRQ associated with this TWAI */
int8_t cpuint; /* CPU interrupt assigned to this TWAI */
twai_hal_context_t ctx; /* Context struct of common layer */
twai_timing_config_t t_config; /* Timing struct of common layer */
};
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
/* TWAI methods */
static void esp_twai_reset(struct can_dev_s *dev);
static int esp_twai_setup(struct can_dev_s *dev);
static void esp_twai_shutdown(struct can_dev_s *dev);
static void esp_twai_rxint(struct can_dev_s *dev, bool enable);
static void esp_twai_txint(struct can_dev_s *dev, bool enable);
static int esp_twai_ioctl(struct can_dev_s *dev, int cmd,
unsigned long arg);
static int esp_twai_remoterequest(struct can_dev_s *dev, uint16_t id);
static int esp_twai_send(struct can_dev_s *dev, struct can_msg_s *msg);
static bool esp_twai_txready(struct can_dev_s *dev);
static bool esp_twai_txempty(struct can_dev_s *dev);
/* TWAI interrupts */
static int esp_twai_interrupt(int irq, void *context, void *arg);
/****************************************************************************
* Private Data
****************************************************************************/
static const struct can_ops_s g_twaiops =
{
.co_reset = esp_twai_reset,
.co_setup = esp_twai_setup,
.co_shutdown = esp_twai_shutdown,
.co_rxint = esp_twai_rxint,
.co_txint = esp_twai_txint,
.co_ioctl = esp_twai_ioctl,
.co_remoterequest = esp_twai_remoterequest,
.co_send = esp_twai_send,
.co_txready = esp_twai_txready,
.co_txempty = esp_twai_txempty,
};
#ifdef CONFIG_ESPRESSIF_TWAI0
static struct esp_twai_dev_s g_twai0priv =
{
.port = 0,
.periph = ETS_TWAI0_INTR_SOURCE,
.irq = ESP_IRQ_TWAI0,
.cpuint = -ENOMEM,
.t_config = TWAI0_TIMING_CONFIG,
};
static struct can_dev_s g_twai0dev =
{
.cd_ops = &g_twaiops,
.cd_priv = &g_twai0priv,
};
#endif /* CONFIG_ESPRESSIF_TWAI0 */
#ifdef CONFIG_ESPRESSIF_TWAI1
static struct esp_twai_dev_s g_twai1priv =
{
.port = 1,
.periph = ETS_TWAI1_INTR_SOURCE,
.irq = ESP_IRQ_TWAI1,
.cpuint = -ENOMEM,
.t_config = TWAI1_TIMING_CONFIG,
};
static struct can_dev_s g_twai1dev =
{
.cd_ops = &g_twaiops,
.cd_priv = &g_twai1priv,
};
#endif /* CONFIG_ESPRESSIF_TWAI1 */
static const twai_filter_config_t f_config = TWAI_FILTER_CONFIG_ACCEPT_ALL();
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: esp_twai_reset
*
* Description:
* Reset the TWAI device. Called early to initialize the hardware. This
* function is called, before esp_twai_setup() and on error conditions.
*
* Input Parameters:
* dev - An instance of the "upper half" CAN driver state structure.
*
* Returned Value:
* None
*
****************************************************************************/
static void esp_twai_reset(struct can_dev_s *dev)
{
struct esp_twai_dev_s *priv = (struct esp_twai_dev_s *)dev->cd_priv;
irqstate_t flags;
int ret;
twai_hal_config_t hal_config =
{
.clock_source_hz = esp_clk_apb_freq(),
.controller_id = priv->port,
};
caninfo("TWAI%" PRIu8 "\n", priv->port);
flags = enter_critical_section();
ret = twai_hal_init(&priv->ctx, &hal_config);
ASSERT(ret);
twai_hal_configure(&priv->ctx, &priv->t_config, &f_config,
TWAI_DEFAULT_INTERRUPTS, 0);
/* Restart the TWAI */
#ifdef CONFIG_CAN_LOOPBACK
twai_hal_start(&priv->ctx, TWAI_MODE_NO_ACK); /* Leave Reset Mode, enter Test Mode */
#else
twai_hal_start(&priv->ctx, TWAI_MODE_NORMAL); /* Leave Reset Mode */
#endif
/* Abort transmission, release RX buffer and clear overrun.
* Command register can only be modified when in Operation Mode.
*/
twai_ll_set_cmd_release_rx_buffer(priv->ctx.dev);
twai_ll_set_cmd_abort_tx(priv->ctx.dev);
twai_ll_set_cmd_clear_data_overrun(priv->ctx.dev);
leave_critical_section(flags);
}
/****************************************************************************
* Name: esp_twai_setup
*
* Description:
* Configure the TWAI. This method is called the first time that the TWAI
* the device is opened and it configures and attaches the TWAI interrupts.
*
* Input Parameters:
* dev - An instance of the "upper half" CAN driver state structure.
*
* Returned Value:
* Zero on success; a negated errno on failure
*
****************************************************************************/
static int esp_twai_setup(struct can_dev_s *dev)
{
struct esp_twai_dev_s *priv = (struct esp_twai_dev_s *)dev->cd_priv;
irqstate_t flags;
int ret = OK;
caninfo("TWAI%" PRIu8 "\n", priv->port);
flags = enter_critical_section();
twai_ll_set_enabled_intrs(priv->ctx.dev, TWAI_DEFAULT_INTERRUPTS);
twai_ll_get_and_clear_intrs(priv->ctx.dev); /* clear latched interrupts */
if (priv->cpuint != -ENOMEM)
{
/* Disable the provided CPU Interrupt to configure it. */
up_disable_irq(priv->irq);
}
priv->cpuint = esp_setup_irq(priv->periph,
ESP_IRQ_PRIORITY_DEFAULT,
ESP_IRQ_TRIGGER_LEVEL);
if (priv->cpuint < 0)
{
/* Failed to allocate a CPU interrupt of this type. */
ret = priv->cpuint;
leave_critical_section(flags);
return ret;
}
ret = irq_attach(priv->irq, esp_twai_interrupt, dev);
if (ret != OK)
{
/* Failed to attach IRQ, so CPU interrupt must be freed. */
esp_teardown_irq(priv->periph, priv->cpuint);
priv->cpuint = -ENOMEM;
leave_critical_section(flags);
return ret;
}
/* Enable the CPU interrupt that is linked to the TWAI device. */
up_enable_irq(priv->irq);
leave_critical_section(flags);
return ret;
}
/****************************************************************************
* Name: esp_twai_shutdown
*
* Description:
* Disable the TWAI. This method is called when the TWAI device is closed.
* This method reverses the operation the setup method.
*
* Input Parameters:
* dev - An instance of the "upper half" CAN driver state structure.
*
* Returned Value:
* None
*
****************************************************************************/
static void esp_twai_shutdown(struct can_dev_s *dev)
{
struct esp_twai_dev_s *priv = (struct esp_twai_dev_s *)dev->cd_priv;
#ifdef CONFIG_DEBUG_CAN_INFO
caninfo("shutdown TWAI%" PRIu8 "\n", priv->port);
#endif
if (priv->cpuint != -ENOMEM)
{
/* Disable cpu interrupt */
up_disable_irq(priv->irq);
/* Dissociate the IRQ from the ISR */
irq_detach(priv->irq);
/* Free cpu interrupt that is attached to this peripheral */
esp_teardown_irq(priv->periph, priv->cpuint);
priv->cpuint = -ENOMEM;
}
}
/****************************************************************************
* Name: esp_twai_rxint
*
* Description:
* Call to enable or disable RX interrupts.
*
* Input Parameters:
* dev - An instance of the "upper half" CAN driver state structure.
* enable - Enable or disable receive interrupt.
*
* Returned Value:
* None
*
****************************************************************************/
static void esp_twai_rxint(struct can_dev_s *dev, bool enable)
{
struct esp_twai_dev_s *priv = (struct esp_twai_dev_s *)dev->cd_priv;
uint32_t regval;
irqstate_t flags;
caninfo("TWAI%" PRIu8 " enable: %d\n", priv->port, enable);
/* The INT_ENA register is also modified from the interrupt handler,
* so we have to protect this code section.
*/
flags = enter_critical_section();
regval = twai_ll_get_and_clear_intrs(priv->ctx.dev);
if (enable == true)
{
regval |= TWAI_LL_INTR_RI;
}
else
{
regval &= ~TWAI_LL_INTR_RI;
}
twai_ll_set_enabled_intrs(priv->ctx.dev, regval);
leave_critical_section(flags);
}
/****************************************************************************
* Name: esp_twai_txint
*
* Description:
* Call to enable or disable TX interrupts.
*
* Input Parameters:
* dev - An instance of the "upper half" CAN driver state structure.
* enable - Enable or disable transmit interrupt.
*
* Returned Value:
* None
*
****************************************************************************/
static void esp_twai_txint(struct can_dev_s *dev, bool enable)
{
struct esp_twai_dev_s *priv = (struct esp_twai_dev_s *)dev->cd_priv;
uint32_t regval;
irqstate_t flags;
caninfo("TWAI%" PRIu8 " enable: %d\n", priv->port, enable);
/* Only disabling of the TX interrupt is supported here. The TX interrupt
* is automatically enabled just before a message is sent in order to avoid
* lost TX interrupts.
*/
if (enable == false)
{
/* TX interrupts are also disabled from the interrupt handler, so we
* have to protect this code section.
*/
flags = enter_critical_section();
/* Disable all TX interrupts */
regval = INT_ENA_REG(priv->ctx.dev);
regval &= ~TWAI_LL_INTR_TI;
twai_ll_set_enabled_intrs(priv->ctx.dev, regval);
leave_critical_section(flags);
}
}
/****************************************************************************
* Name: esp_twai_ioctl
*
* Description:
* All ioctl calls will be routed through this method
*
* Input Parameters:
* dev - An instance of the "upper half" CAN driver state structure.
* cmd - A ioctl command.
* arg - A ioctl argument.
*
* Returned Value:
* Zero on success; a negated errno on failure
*
****************************************************************************/
static int esp_twai_ioctl(struct can_dev_s *dev, int cmd, unsigned long arg)
{
struct esp_twai_dev_s *priv = (struct esp_twai_dev_s *)dev->cd_priv;
int ret = -ENOTTY;
caninfo("TWAI%" PRIu8 " cmd=%04x arg=%lu\n", priv->port, cmd, arg);
/* Handle the command */
switch (cmd)
{
/* CANIOC_GET_BITTIMING:
* Description: Return the current bit timing settings
* Argument: A pointer to a write-able instance of struct
* canioc_bittiming_s in which current bit timing
* values will be returned.
* Returned Value: Zero (OK) is returned on success. Otherwise -1
* (ERROR) is returned with the errno variable set
* to indicate the nature of the error.
* Dependencies: None
*/
case CANIOC_GET_BITTIMING:
{
struct canioc_bittiming_s *bt =
(struct canioc_bittiming_s *)arg;
uint32_t timing0;
uint32_t timing1;
uint32_t brp;
DEBUGASSERT(bt != NULL);
brp = (priv->t_config.brp + 1) * 2;
bt->bt_sjw = priv->t_config.sjw + 1;
bt->bt_tseg1 = priv->t_config.tseg_1 + 1;
bt->bt_tseg2 = priv->t_config.tseg_2 + 1;
bt->bt_baud = esp_clk_apb_freq() /
(brp * (bt->bt_tseg1 + bt->bt_tseg2 + 1));
ret = OK;
}
break;
/* Unsupported/unrecognized command */
default:
canerr("ERROR: Unrecognized command: %04x\n", cmd);
break;
}
return ret;
}
/****************************************************************************
* Name: esp_twai_remoterequest
*
* Description:
* Send a remote request
*
* Input Parameters:
* dev - An instance of the "upper half" can driver state structure.
* id - Requested 11-bit data frame identifier
*
* Returned Value:
* Zero on success; a negated errno on failure
*
****************************************************************************/
static int esp_twai_remoterequest(struct can_dev_s *dev, uint16_t id)
{
canwarn("Remote request not implemented\n");
return -ENOSYS;
}
/****************************************************************************
* Name: esp_twai_send
*
* Description:
* Send one TWAI message.
*
* One TWAI-message consists of a maximum of 10 bytes. A message is
* composed of at least the first 2 bytes (when there are no data bytes).
*
* Byte 0: Bits 0-7: Bits 3-10 of the 11-bit TWAI identifier
* Byte 1: Bits 5-7: Bits 0-2 of the 11-bit TWAI identifier
* Bit 4: Remote Transmission Request (RTR)
* Bits 0-3: Data Length Code (DLC)
* Bytes 2-10: TWAI data
*
* Input Parameters:
* dev - An instance of the "upper half" CAN driver state structure.
* msg - A message to send.
*
* Returned Value:
* Zero on success; a negated errno on failure
*
****************************************************************************/
static int esp_twai_send(struct can_dev_s *dev, struct can_msg_s *msg)
{
struct esp_twai_dev_s *priv = (struct esp_twai_dev_s *)dev->cd_priv;
uint32_t regval;
uint32_t i;
uint32_t len;
uint32_t id;
uint32_t twai_flags;
irqstate_t flags;
int ret = OK;
caninfo("TWAI%" PRIu8 " ID: %" PRIu32 " DLC: %" PRIu8 "\n",
priv->port, (uint32_t)msg->cm_hdr.ch_id, msg->cm_hdr.ch_dlc);
len = (uint32_t)msg->cm_hdr.ch_dlc;
if (len > CAN_MAXDATALEN)
{
len = CAN_MAXDATALEN;
}
flags = enter_critical_section();
/* Make sure that TX interrupts are enabled BEFORE sending the
* message.
*
* NOTE: The INT_ENA is also modified from the interrupt handler, but the
* following is safe because interrupts are disabled here.
*/
regval = INT_ENA_REG(priv->ctx.dev);
regval |= TWAI_LL_INTR_TI;
twai_ll_set_enabled_intrs(priv->ctx.dev, regval);
twai_hal_frame_t tx_frame;
/* Adjustments from NuttX TWAI message struct to common layer TWAI struct */
twai_flags = ((EXTID << TWAI_MSG_FLAG_EXTD) |
(msg->cm_hdr.ch_rtr << TWAI_MSG_FLAG_RTR) |
(LOOPBACK << TWAI_MSG_FLAG_SELF));
/* Set up the transfer */
twai_ll_format_frame_buffer(msg->cm_hdr.ch_id, len,
msg->cm_data, twai_flags, &tx_frame);
twai_ll_set_tx_buffer(priv->ctx.dev, &tx_frame);
/* Send the message */
#ifdef CONFIG_CAN_LOOPBACK
twai_ll_set_cmd_self_rx_request(priv->ctx.dev);
#else
twai_ll_set_cmd_tx(priv->ctx.dev);
#endif
leave_critical_section(flags);
return ret;
}
/****************************************************************************
* Name: esp_twai_txready
*
* Description:
* Return true if the TWAI hardware can accept another TX message.
*
* Input Parameters:
* dev - An instance of the "upper half" CAN driver state structure.
*
* Returned Value:
* True if the TWAI hardware is ready to accept another TX message.
*
****************************************************************************/
static bool esp_twai_txready(struct can_dev_s *dev)
{
struct esp_twai_dev_s *priv = dev->cd_priv;
uint32_t regval = twai_ll_get_status(priv->ctx.dev);
caninfo("TWAI%" PRIu8 " txready: %d\n", priv->port,
((regval & TWAI_LL_STATUS_TBS) != 0));
return ((regval & TWAI_LL_STATUS_TBS) != 0);
}
/****************************************************************************
* Name: esp_twai_txempty
*
* Description:
* Return true if all message have been sent. If for example, the TWAI
* hardware implements FIFOs, then this would mean the transmit FIFO is
* empty. This method is called when the driver needs to make sure that
* all characters are "drained" from the TX hardware before calling
* co_shutdown().
*
* Input Parameters:
* dev - An instance of the "upper half" CAN driver state structure.
*
* Returned Value:
* True if there are no pending TX transfers in the TWAI hardware.
*
****************************************************************************/
static bool esp_twai_txempty(struct can_dev_s *dev)
{
struct esp_twai_dev_s *priv = dev->cd_priv;
uint32_t regval = twai_ll_get_status(priv->ctx.dev);
caninfo("TWAI%" PRIu8 " txempty: %d\n", priv->port,
((regval & TWAI_LL_STATUS_TBS) != 0));
return ((regval & TWAI_LL_STATUS_TBS) != 0);
}
/****************************************************************************
* Name: esp_twai_interrupt
*
* Description:
* TWAI RX/TX interrupt handler
*
* Input Parameters:
* irq - The IRQ number of the interrupt.
* context - The register state save array at the time of the interrupt.
* arg - The pointer to driver structure.
*
* Returned Value:
* Zero on success; a negated errno on failure
*
****************************************************************************/
static int esp_twai_interrupt(int irq, void *context, void *arg)
{
struct can_dev_s *dev = (struct can_dev_s *)arg;
struct esp_twai_dev_s *priv = dev->cd_priv;
struct can_hdr_s hdr;
uint8_t data[8];
uint32_t regval;
twai_hal_frame_t rx_frame;
uint32_t flags = 0;
uint32_t id;
uint8_t dlc;
/* Read the interrupt register results in clearing bits */
regval = twai_ll_get_and_clear_intrs(priv->ctx.dev);
/* Check for a receive interrupt */
if ((regval & TWAI_LL_INTR_RI) != 0)
{
memset(&hdr, 0, sizeof(hdr));
memset(data, 0, sizeof(data));
twai_ll_get_rx_buffer(priv->ctx.dev, &rx_frame);
/* Release the receive buffer */
twai_ll_set_cmd_release_rx_buffer(priv->ctx.dev);
twai_ll_parse_frame_buffer(&rx_frame, &id, &dlc, data, &flags);
hdr.ch_id = id;
hdr.ch_dlc = dlc;
hdr.ch_rtr = (flags && TWAI_MSG_FLAG_RTR) ? 1 : 0;
can_receive(dev, &hdr, data);
}
/* Check for TX buffer complete */
if ((regval & TWAI_LL_INTR_TI) != 0)
{
/* Disable all further TX buffer interrupts */
esp_twai_txint(dev, false);
/* Indicate that the TX is done and a new TX buffer is available */
can_txdone(dev);
}
return OK;
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: esp_twaiinitialize
*
* Description:
* Initialize TWAI peripheral
*
* Input Parameters:
* port - Port number (for hardware that has multiple TWAI interfaces)
*
* Returned Value:
* Valid TWAI device structure reference on success; a NULL on failure
*
****************************************************************************/
struct can_dev_s *esp_twaiinitialize(int port)
{
struct can_dev_s *dev;
irqstate_t flags;
caninfo("TWAI%" PRIu8 "\n", port);
flags = enter_critical_section();
#ifdef CONFIG_ESPRESSIF_TWAI0
if (port == 0)
{
/* Enable power to the TWAI module and
* Enable clocking to the TWAI module
*/
periph_module_reset(PERIPH_TWAI0_MODULE);
periph_module_enable(PERIPH_TWAI0_MODULE);
/* Configure CAN GPIO pins */
esp_gpio_matrix_out(CONFIG_ESPRESSIF_TWAI0_TXPIN, TWAI0_TX_IDX, 0, 0);
esp_configgpio(CONFIG_ESPRESSIF_TWAI0_TXPIN, TX_PIN_ATTR);
esp_configgpio(CONFIG_ESPRESSIF_TWAI0_RXPIN, RX_PIN_ATTR);
esp_gpio_matrix_in(CONFIG_ESPRESSIF_TWAI0_RXPIN, TWAI0_RX_IDX, 0);
dev = &g_twai0dev;
}
else
#endif
#ifdef CONFIG_ESPRESSIF_TWAI1
if (port == 1)
{
/* Enable power to the TWAI module and
* Enable clocking to the TWAI module
*/
periph_module_reset(PERIPH_TWAI1_MODULE);
periph_module_enable(PERIPH_TWAI1_MODULE);
/* Configure CAN GPIO pins */
esp_gpio_matrix_out(CONFIG_ESPRESSIF_TWAI1_TXPIN, TWAI1_TX_IDX, 0, 0);
esp_configgpio(CONFIG_ESPRESSIF_TWAI1_TXPIN, TX_PIN_ATTR);
esp_configgpio(CONFIG_ESPRESSIF_TWAI1_RXPIN, RX_PIN_ATTR);
esp_gpio_matrix_in(CONFIG_ESPRESSIF_TWAI1_RXPIN, TWAI1_RX_IDX, 0);
dev = &g_twai1dev;
}
else
#endif
{
canerr("ERROR: Unsupported port: %d\n", port);
leave_critical_section(flags);
return NULL;
}
/* Then just perform a TWAI reset operation */
esp_twai_reset(dev);
leave_critical_section(flags);
return dev;
}
#endif /* CONFIG_ESPRESSIF_TWAI */