From a26996fb3be02c9d666f62856d1373fe72eaa6b9 Mon Sep 17 00:00:00 2001 From: Eren Terzioglu Date: Tue, 29 Aug 2023 13:43:30 +0300 Subject: [PATCH] xtensa/esp32s3: Add support to TWAI/CANBus controller --- .../esp32s3/boards/esp32s3-devkit/index.rst | 18 + .../platforms/xtensa/esp32s3/index.rst | 2 +- arch/xtensa/include/esp32s3/irq.h | 4 +- arch/xtensa/src/esp32s3/Kconfig | 56 + arch/xtensa/src/esp32s3/Make.defs | 4 + arch/xtensa/src/esp32s3/esp32s3_twai.c | 1263 +++++++++++++++++ arch/xtensa/src/esp32s3/esp32s3_twai.h | 77 + .../src/esp32s3/hardware/esp32s3_system.h | 4 +- .../src/esp32s3/hardware/esp32s3_twai.h | 792 +++++++++++ .../esp32s3-devkit/configs/twai/defconfig | 49 + .../esp32s3/esp32s3-devkit/src/Make.defs | 4 + .../esp32s3-devkit/src/esp32s3-devkit.h | 4 + .../esp32s3-devkit/src/esp32s3_bringup.c | 11 + .../esp32s3/esp32s3-devkit/src/esp32s3_twai.c | 90 ++ 14 files changed, 2373 insertions(+), 5 deletions(-) create mode 100644 arch/xtensa/src/esp32s3/esp32s3_twai.c create mode 100644 arch/xtensa/src/esp32s3/esp32s3_twai.h create mode 100644 arch/xtensa/src/esp32s3/hardware/esp32s3_twai.h create mode 100644 boards/xtensa/esp32s3/esp32s3-devkit/configs/twai/defconfig create mode 100644 boards/xtensa/esp32s3/esp32s3-devkit/src/esp32s3_twai.c diff --git a/Documentation/platforms/xtensa/esp32s3/boards/esp32s3-devkit/index.rst b/Documentation/platforms/xtensa/esp32s3/boards/esp32s3-devkit/index.rst index 130cfc8ab2..1f638d03d6 100644 --- a/Documentation/platforms/xtensa/esp32s3/boards/esp32s3-devkit/index.rst +++ b/Documentation/platforms/xtensa/esp32s3/boards/esp32s3-devkit/index.rst @@ -412,6 +412,24 @@ To test it, just run the following:: Where x in the timer instance. +twai +---- + +This configuration enables the support for the TWAI (Two-Wire Automotive Interface) driver. +You can test it by connecting TWAI RX and TWAI TX pins which are GPIO0 and GPIO2 by default +to a external transceiver or connecting TWAI RX to TWAI TX pin by enabling +the ``Device Drivers -> CAN Driver Support -> CAN loopback mode`` option and running the ``can`` example:: + + nsh> can + nmsgs: 0 + min ID: 1 max ID: 2047 + Bit timing: + Baud: 1000000 + TSEG1: 15 + TSEG2: 4 + SJW: 3 + ID: 1 DLC: 1 + usbnsh ------ diff --git a/Documentation/platforms/xtensa/esp32s3/index.rst b/Documentation/platforms/xtensa/esp32s3/index.rst index 72546bdc72..b2560f5747 100644 --- a/Documentation/platforms/xtensa/esp32s3/index.rst +++ b/Documentation/platforms/xtensa/esp32s3/index.rst @@ -93,7 +93,7 @@ ADC No AES No Bluetooth No CAMERA No -CAN/TWAI No +CAN/TWAI Yes DMA Yes eFuse No GPIO Yes diff --git a/arch/xtensa/include/esp32s3/irq.h b/arch/xtensa/include/esp32s3/irq.h index ee9e6b799d..5419d49aaf 100644 --- a/arch/xtensa/include/esp32s3/irq.h +++ b/arch/xtensa/include/esp32s3/irq.h @@ -99,7 +99,7 @@ #define ESP32S3_PERIPH_PWM1 32 #define ESP32S3_PERIPH_LEDC 35 #define ESP32S3_PERIPH_EFUSE 36 -#define ESP32S3_PERIPH_CAN 37 +#define ESP32S3_PERIPH_TWAI 37 #define ESP32S3_PERIPH_USB 38 #define ESP32S3_PERIPH_RTC_CORE 39 @@ -239,7 +239,7 @@ #define ESP32S3_IRQ_PWM1 (XTENSA_IRQ_FIRSTPERIPH + ESP32S3_PERIPH_PWM1) #define ESP32S3_IRQ_LEDC (XTENSA_IRQ_FIRSTPERIPH + ESP32S3_PERIPH_LEDC) #define ESP32S3_IRQ_EFUSE (XTENSA_IRQ_FIRSTPERIPH + ESP32S3_PERIPH_EFUSE) -#define ESP32S3_IRQ_CAN (XTENSA_IRQ_FIRSTPERIPH + ESP32S3_PERIPH_CAN) +#define ESP32S3_IRQ_TWAI (XTENSA_IRQ_FIRSTPERIPH + ESP32S3_PERIPH_TWAI) #define ESP32S3_IRQ_USB (XTENSA_IRQ_FIRSTPERIPH + ESP32S3_PERIPH_USB) #define ESP32S3_IRQ_RTC_CORE (XTENSA_IRQ_FIRSTPERIPH + ESP32S3_PERIPH_RTC_CORE) diff --git a/arch/xtensa/src/esp32s3/Kconfig b/arch/xtensa/src/esp32s3/Kconfig index 9aabec31d2..9de68c92b2 100644 --- a/arch/xtensa/src/esp32s3/Kconfig +++ b/arch/xtensa/src/esp32s3/Kconfig @@ -624,6 +624,11 @@ config ESP32S3_I2C1 select ESP32S3_I2C select I2C +config ESP32S3_TWAI + bool "TWAI (CAN)" + default n + select CAN + config ESP32S3_LEDC bool "LEDC (PWM)" default n @@ -1093,6 +1098,57 @@ config ESP32S3_I2CTIMEOMS endmenu # I2C Configuration +menu "TWAI driver options" + depends on ESP32S3_TWAI + +if ESP32S3_TWAI + +config ESP32S3_TWAI_TXPIN + int "TWAI TX Pin" + default 0 + +config ESP32S3_TWAI_RXPIN + int "TWAI RX Pin" + default 2 + +config ESP32S3_TWAI_BITRATE + int "TWAI bitrate" + default 1000000 + ---help--- + TWAI bit rate. + +config ESP32S3_TWAI_SAMPLEP + int "TWAI sample point" + default 80 + ---help--- + TWAI sample point location as a percent value. + +config ESP32S3_TWAI_SJW + int "TWAI synchronization jump width" + default 3 + ---help--- + SJW limits the number of Time Quanta corrections during bit + Resynchronization. + +config ESP32S3_TWAI_SAM + bool "TWAI sampling" + default n + ---help--- + The bus is sampled 3 times (recommended for low to medium speed buses + to spikes on the bus-line). + +endif # ESP32S3_TWAI + +config ESP32S3_TWAI_REGDEBUG + bool "TWAI register level debug" + depends on DEBUG_CAN_INFO + default n + ---help--- + Output detailed register-level TWAI debug information. Requires also + CONFIG_DEBUG_CAN_INFO. + +endmenu #ESP32S3_TWAI + menu "Wi-Fi Configuration" depends on ESP32S3_WIFI diff --git a/arch/xtensa/src/esp32s3/Make.defs b/arch/xtensa/src/esp32s3/Make.defs index 775edc822c..0a9752a8ec 100644 --- a/arch/xtensa/src/esp32s3/Make.defs +++ b/arch/xtensa/src/esp32s3/Make.defs @@ -57,6 +57,10 @@ ifeq ($(CONFIG_ESP32S3_RNG),y) CHIP_CSRCS += esp32s3_rng.c endif +ifeq ($(CONFIG_ESP32S3_TWAI),y) +CHIP_CSRCS += esp32s3_twai.c +endif + ifeq ($(CONFIG_ESP32S3_LEDC),y) CHIP_CSRCS += esp32s3_ledc.c endif diff --git a/arch/xtensa/src/esp32s3/esp32s3_twai.c b/arch/xtensa/src/esp32s3/esp32s3_twai.c new file mode 100644 index 0000000000..d7fb0adb0e --- /dev/null +++ b/arch/xtensa/src/esp32s3/esp32s3_twai.c @@ -0,0 +1,1263 @@ +/**************************************************************************** + * arch/xtensa/src/esp32s3/esp32s3_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 + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "xtensa.h" + +#include "esp32s3_gpio.h" +#include "esp32s3_twai.h" +#include "esp32s3_irq.h" +#include "esp32s3_clockconfig.h" +#include "esp32s3_periph.h" + +#include "hardware/esp32s3_system.h" +#include "hardware/esp32s3_gpio_sigmap.h" + +#if defined(CONFIG_ESP32S3_TWAI) + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Configuration ************************************************************/ + +/* Default values written to various registers on initialization */ + +#define TWAI_INIT_TEC 0 +#define TWAI_INIT_REC 0 +#define TWAI_INIT_EWL 96 + +/* Exclude data overrun (bit[3]) and brp_div (bit[4]) */ + +#define TWAI_DEFAULT_INTERRUPTS 0x1e7 + +#define TWAI_ACCEPTANCE_CODE 0x0 /* 32-bit address to match */ +#define TWAI_ACCEPTANCE_MASK 0xffffffff /* 32-bit address mask */ + +#ifdef CONFIG_ESP32S3_TWAI + +/* A TWAI bit rate must be provided */ + +# ifndef CONFIG_ESP32S3_TWAI_BITRATE +# error "CONFIG_ESP32S3_TWAI_BITRATE is not defined" +# endif + +/* If no sample point is provided, use a sample point of 80 */ + +# ifndef CONFIG_ESP32S3_TWAI_SAMPLEP +# define CONFIG_ESP32S3_TWAI_SAMPLEP 80 +# endif +#endif + +/* If no Synchronization Jump Width is provided, use a SJW of 13 */ + +#ifndef CONFIG_ESP32S3_TWAI_SJW +# define CONFIG_ESP32S3_TWAI_SJW 3 +#endif + +/* Debug ********************************************************************/ + +/* Non-standard debug that may be enabled just for testing TWAI */ + +#ifndef CONFIG_DEBUG_CAN_INFO +# undef CONFIG_ESP32S3_TWAI_REGDEBUG +#endif + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* CAN hardware-dependent bit-timing constant + * Used for calculating and checking bit-timing parameters + */ + +struct can_bittiming_const +{ + uint32_t tseg1_min; /* Time segment 1 */ + uint32_t tseg1_max; + uint32_t tseg2_min; /* Time segment 2 */ + uint32_t tseg2_max; + uint32_t sjw_min; /* Synchronization jump width */ + uint32_t sjw_max; + uint32_t brp_min; /* Bit-rate prescaler */ + uint32_t brp_max; + uint32_t brp_inc; +}; + +struct twai_dev_s +{ + /* Device configuration */ + + const struct can_bittiming_const *bittiming_const; + uint8_t port; /* TWAI port number */ + uint8_t periph; /* Peripheral ID */ + uint8_t irq; /* IRQ associated with this TWAI */ + uint8_t cpu; /* CPU ID */ + uint8_t cpuint; /* CPU interrupt assigned to this TWAI */ + uint32_t bitrate; /* Configured bit rate */ + uint32_t samplep; /* Configured sample point */ + uint32_t sjw; /* Synchronization jump width */ + uint32_t base; /* TWAI register base address */ + spinlock_t lock; /* Device specific lock */ +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* TWAI Register access */ + +#ifdef CONFIG_ESP32S3_TWAI_REGDEBUG +static void twai_printreg(uint32_t addr, uint32_t value); +#endif + +static uint32_t twai_getreg(uint32_t addr); +static void twai_putreg(uint32_t addr, uint32_t value); + +/* TWAI methods */ + +static void esp32s3twai_reset(struct can_dev_s *dev); +static int esp32s3twai_setup(struct can_dev_s *dev); +static void esp32s3twai_shutdown(struct can_dev_s *dev); +static void esp32s3twai_rxint(struct can_dev_s *dev, bool enable); +static void esp32s3twai_txint(struct can_dev_s *dev, bool enable); +static int esp32s3twai_ioctl(struct can_dev_s *dev, int cmd, + unsigned long arg); +static int esp32s3twai_remoterequest(struct can_dev_s *dev, + uint16_t id); +static int esp32s3twai_send(struct can_dev_s *dev, + struct can_msg_s *msg); +static bool esp32s3twai_txready(struct can_dev_s *dev); +static bool esp32s3twai_txempty(struct can_dev_s *dev); + +/* TWAI interrupts */ + +static int esp32s3twai_interrupt(int irq, void *context, void *arg); + +/* TWAI acceptance filter */ + +static void esp32s3twai_set_acc_filter(uint32_t code, uint32_t mask, + bool single_filter); + +/* TWAI bit-timing initialization */ + +static int twai_baud_rate(struct twai_dev_s *priv, int rate, int clock, + int sjw, int sampl_pt, int flags); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const struct can_bittiming_const esp32s3_twai_bittiming_const = +{ + .tseg1_min = 1, + .tseg1_max = 16, + .tseg2_min = 1, + .tseg2_max = 8, + .sjw_min = 1, + .sjw_max = 3, + .brp_min = 1, + .brp_max = 8192, + .brp_inc = 1, +}; + +static const struct can_ops_s g_twaiops = +{ + .co_reset = esp32s3twai_reset, + .co_setup = esp32s3twai_setup, + .co_shutdown = esp32s3twai_shutdown, + .co_rxint = esp32s3twai_rxint, + .co_txint = esp32s3twai_txint, + .co_ioctl = esp32s3twai_ioctl, + .co_remoterequest = esp32s3twai_remoterequest, + .co_send = esp32s3twai_send, + .co_txready = esp32s3twai_txready, + .co_txempty = esp32s3twai_txempty, +}; + +#ifdef CONFIG_ESP32S3_TWAI +static struct twai_dev_s g_twaipriv = +{ + .bittiming_const = &esp32s3_twai_bittiming_const, + .port = 0, + .periph = ESP32S3_PERIPH_TWAI, + .irq = ESP32S3_IRQ_TWAI, + .cpuint = -ENOMEM, + .bitrate = CONFIG_ESP32S3_TWAI_BITRATE, + .samplep = CONFIG_ESP32S3_TWAI_SAMPLEP, + .sjw = CONFIG_ESP32S3_TWAI_SJW, + .base = DR_REG_TWAI_BASE, + .lock = SP_UNLOCKED, +}; + +static struct can_dev_s g_twaidev = +{ + .cd_ops = &g_twaiops, + .cd_priv = &g_twaipriv, +}; +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: twai_printreg + * + * Description: + * Print the value read from a register. + * + * Input Parameters: + * addr - The register address + * value - The register value + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef CONFIG_ESP32S3_TWAI_REGDEBUG +static void twai_printreg(uint32_t addr, uint32_t value) +{ + static uint32_t prevaddr = 0; + static uint32_t preval = 0; + static uint32_t count = 0; + + /* Is this the same value that we read from the same register last time? + * Are we polling the register? If so, suppress some of the output. + */ + + if (addr == prevaddr && value == preval) + { + if (count == 0xffffffff || ++count > 3) + { + if (count == 4) + { + caninfo("...\n"); + } + + return; + } + } + + /* No this is a new address or value */ + + else + { + /* Did we print "..." for the previous value? */ + + if (count > 3) + { + /* Yes.. then show how many times the value repeated */ + + caninfo("[repeats %d more times]\n", count - 3); + } + + /* Save the new address, value, and count */ + + prevaddr = addr; + preval = value; + count = 1; + } + + /* Show the register value read */ + + caninfo("%08x->%08x\n", addr, value); +} +#endif + +/**************************************************************************** + * Name: twai_getreg + * + * Description: + * Read the value of an TWAI register. + * + * Input Parameters: + * addr - The address to the register to read + * + * Returned Value: + * + ****************************************************************************/ + +#ifdef CONFIG_ESP32S3_TWAI_REGDEBUG +static uint32_t twai_getreg(uint32_t addr) +{ + uint32_t value; + + /* Read the value from the register */ + + value = getreg32(addr); + twai_printreg(addr, value); + return value; +} +#else +static uint32_t twai_getreg(uint32_t addr) +{ + return getreg32(addr); +} +#endif + +/**************************************************************************** + * Name: twai_putreg + * + * Description: + * Set the value of an TWAI register. + * + * Input Parameters: + * addr - The address to the register to write + * value - The value to write to the register + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef CONFIG_ESP32S3_TWAI_REGDEBUG +static void twai_putreg(uint32_t addr, uint32_t value) +{ + /* Show the register value being written */ + + caninfo("%08x<-%08x\n", addr, value); + + /* Write the value */ + + putreg32(value, addr); +} +#else +static void twai_putreg(uint32_t addr, uint32_t value) +{ + putreg32(value, addr); +} +#endif + +/**************************************************************************** + * Name: esp32s3twai_reset + * + * Description: + * Reset the TWAI device. Called early to initialize the hardware. This + * function is called, before esp32s3_twai_setup() and on error conditions. + * + * Input Parameters: + * dev - An instance of the "upper half" CAN driver state structure. + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void esp32s3twai_reset(struct can_dev_s *dev) +{ + struct twai_dev_s *priv = (struct twai_dev_s *)dev->cd_priv; + irqstate_t flags; + int ret; + + caninfo("TWAI\n"); + + flags = spin_lock_irqsave(&priv->lock); + + /* Disable the TWAI and stop ongoing transmissions */ + + uint32_t mode_value = TWAI_RESET_MODE_M | TWAI_LISTEN_ONLY_MODE_M; + twai_putreg(TWAI_MODE_REG, mode_value); /* Enter Reset Mode */ + + twai_putreg(TWAI_INT_ENA_REG, 0); /* Disable interrupts */ + twai_getreg(TWAI_STATUS_REG); /* Clear status bits */ + + twai_putreg(TWAI_TX_ERR_CNT_REG, TWAI_INIT_TEC); /* TEC */ + twai_putreg(TWAI_RX_ERR_CNT_REG, TWAI_INIT_REC); /* REC */ + twai_putreg(TWAI_ERR_WARNING_LIMIT_REG, TWAI_INIT_EWL); /* EWL */ + + esp32s3twai_set_acc_filter(TWAI_ACCEPTANCE_CODE, + TWAI_ACCEPTANCE_MASK, true); + + /* Set bit timing */ + + ret = twai_baud_rate(priv, priv->bitrate, esp_clk_apb_freq(), + priv->sjw, priv->samplep, 0); + + if (ret != OK) + { + canerr("ERROR: Failed to set bit timing: %d\n", ret); + } + + /* Restart the TWAI */ + +#ifdef CONFIG_CAN_LOOPBACK + twai_putreg(TWAI_MODE_REG, TWAI_SELF_TEST_MODE_M); /* Leave Reset Mode, enter Test Mode */ +#else + twai_putreg(TWAI_MODE_REG, 0); /* Leave Reset Mode */ +#endif + + /* Abort transmission, release RX buffer and clear overrun. + * Command register can only be modified when in Operation Mode. + */ + + twai_putreg(TWAI_CMD_REG, TWAI_ABORT_TX_M | TWAI_RELEASE_BUF_M | + TWAI_CLR_OVERRUN_M); + spin_unlock_irqrestore(&priv->lock, flags); +} + +/**************************************************************************** + * Name: esp32s3twai_setup + * + * Description: + * Configure the TWAI. This method is called the first time that the TWAI + * device is opened. This will occur when the port is first opened. + * This setup includes configuring and attaching 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 esp32s3twai_setup(struct can_dev_s *dev) +{ + struct twai_dev_s *priv = (struct twai_dev_s *)dev->cd_priv; + irqstate_t flags; + int ret = OK; + + caninfo("TWAI\n"); + + flags = spin_lock_irqsave(&priv->lock); + + twai_putreg(TWAI_INT_ENA_REG, TWAI_DEFAULT_INTERRUPTS); + + twai_getreg(TWAI_INT_RAW_REG); /* clear latched interrupts */ + + if (priv->cpuint != -ENOMEM) + { + /* Disable the provided CPU Interrupt to configure it. */ + + up_disable_irq(priv->irq); + } + + priv->cpu = up_cpu_index(); + priv->cpuint = esp32s3_setup_irq(priv->cpu, priv->periph, + 1, ESP32S3_CPUINT_LEVEL); + if (priv->cpuint < 0) + { + /* Failed to allocate a CPU interrupt of this type. */ + + ret = priv->cpuint; + spin_unlock_irqrestore(&priv->lock, flags); + + return ret; + } + + ret = irq_attach(priv->irq, esp32s3twai_interrupt, dev); + if (ret != OK) + { + /* Failed to attach IRQ, so CPU interrupt must be freed. */ + + esp32s3_teardown_irq(priv->cpu, priv->periph, priv->cpuint); + priv->cpuint = -ENOMEM; + spin_unlock_irqrestore(&priv->lock, flags); + + return ret; + } + + /* Enable the CPU interrupt that is linked to the TWAI device. */ + + up_enable_irq(priv->irq); + + spin_unlock_irqrestore(&priv->lock, flags); + + return ret; +} + +/**************************************************************************** + * Name: esp32s3twai_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 esp32s3twai_shutdown(struct can_dev_s *dev) +{ + struct twai_dev_s *priv = (struct twai_dev_s *)dev->cd_priv; + +#ifdef CONFIG_DEBUG_CAN_INFO + caninfo("shutdown TWAI\n"); +#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 */ + + esp32s3_teardown_irq(priv->cpu, priv->periph, priv->cpuint); + priv->cpuint = -ENOMEM; + } +} + +/**************************************************************************** + * Name: esp32s3twai_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 esp32s3twai_rxint(struct can_dev_s *dev, bool enable) +{ + struct twai_dev_s *priv = (struct twai_dev_s *)dev->cd_priv; + uint32_t regval; + irqstate_t flags; + + caninfo("TWAI enable: %d\n", enable); + + /* The INT_ENA register is also modified from the interrupt handler, + * so we have to protect this code section. + */ + + flags = spin_lock_irqsave(&priv->lock); + + regval = twai_getreg(TWAI_INT_ENA_REG); + if (enable) + { + regval |= TWAI_RX_INT_ENA_M; + } + else + { + regval &= ~TWAI_RX_INT_ENA_M; + } + + twai_putreg(TWAI_INT_ENA_REG, regval); + spin_unlock_irqrestore(&priv->lock, flags); +} + +/**************************************************************************** + * Name: esp32s3twai_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 esp32s3twai_txint(struct can_dev_s *dev, bool enable) +{ + struct twai_dev_s *priv = (struct twai_dev_s *)dev->cd_priv; + uint32_t regval; + irqstate_t flags; + + caninfo("TWAI enable: %d\n", 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) + { + /* TX interrupts are also disabled from the interrupt handler, so we + * have to protect this code section. + */ + + flags = spin_lock_irqsave(&priv->lock); + + /* Disable all TX interrupts */ + + regval = twai_getreg(TWAI_INT_ENA_REG); + regval &= ~(TWAI_TX_INT_ENA_M); + twai_putreg(TWAI_INT_ENA_REG, regval); + spin_unlock_irqrestore(&priv->lock, flags); + } +} + +/**************************************************************************** + * Name: esp32s3twai_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 esp32s3twai_ioctl(struct can_dev_s *dev, int cmd, + unsigned long arg) +{ + struct twai_dev_s *priv = (struct twai_dev_s *)dev->cd_priv; + int ret = -ENOTTY; + + caninfo("TWAI cmd=%04x arg=%lu\n", 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); + + timing0 = twai_getreg(TWAI_BUS_TIMING_0_REG); + timing1 = twai_getreg(TWAI_BUS_TIMING_1_REG); + + brp = ((timing0 & TWAI_BAUD_PRESC_M) + 1) * 2; + bt->bt_sjw = ((timing0 & TWAI_SYNC_JUMP_WIDTH_M) >> + TWAI_SYNC_JUMP_WIDTH_S) + 1; + + bt->bt_tseg1 = ((timing1 & TWAI_TIME_SEG1_M) >> + TWAI_TIME_SEG1_S) + 1; + bt->bt_tseg2 = ((timing1 & TWAI_TIME_SEG2_M) >> + TWAI_TIME_SEG2_S)+ 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: esp32s3twai_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 esp32s3twai_remoterequest(struct can_dev_s *dev, uint16_t id) +{ + canwarn("Remote request not implemented\n"); + return -ENOSYS; +} + +/**************************************************************************** + * Name: esp32s3twai_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 esp32s3twai_send(struct can_dev_s *dev, + struct can_msg_s *msg) +{ + struct twai_dev_s *priv = (struct twai_dev_s *)dev->cd_priv; + uint32_t regval; + uint32_t i; + uint32_t len; + uint32_t id; + uint32_t frame_info; + irqstate_t flags; + int ret = OK; + + caninfo("TWAI ID: %" PRIu32 " DLC: %" PRIu8 "\n", + (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; + + frame_info = len; + + if (msg->cm_hdr.ch_rtr) + { + frame_info |= (1 << 6); + } + + flags = spin_lock_irqsave(&priv->lock); + + /* 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 = twai_getreg(TWAI_INT_ENA_REG); + regval |= TWAI_TX_INT_ENA_M; + twai_putreg(TWAI_INT_ENA_REG, regval); + + /* Set up the transfer */ + +#ifdef CONFIG_CAN_EXTID + if (msg->cm_hdr.ch_extid) + { + /* The provided ID should be 29 bits */ + + id = (uint32_t)msg->cm_hdr.ch_id; + DEBUGASSERT((id & ~CAN_MAX_EXTMSGID) == 0); + frame_info |= (1 << 7); + twai_putreg(TWAI_DATA_0_REG, frame_info); + + id <<= 3; + twai_putreg(TWAI_DATA_4_REG, id & 0xff); + id >>= 8; + twai_putreg(TWAI_DATA_3_REG, id & 0xff); + id >>= 8; + twai_putreg(TWAI_DATA_2_REG, id & 0xff); + id >>= 8; + twai_putreg(TWAI_DATA_1_REG, id & 0xff); + for (i = 0; i < len; i++) + { + twai_putreg(TWAI_DATA_5_REG + (i * 4), msg->cm_data[i]); + } + } + else +#endif + { + /* The provided ID should be 11 bits */ + + id = (uint32_t)msg->cm_hdr.ch_id; + DEBUGASSERT((id & ~CAN_MAX_STDMSGID) == 0); + twai_putreg(TWAI_DATA_0_REG, frame_info); + id <<= 5; + twai_putreg(TWAI_DATA_1_REG, (id >> 8) & 0xff); + twai_putreg(TWAI_DATA_2_REG, id & 0xff); + for (i = 0; i < len; i++) + { + twai_putreg(TWAI_DATA_3_REG + (i * 4), msg->cm_data[i]); + } + } + + /* Send the message */ + +#ifdef CONFIG_CAN_LOOPBACK + twai_putreg(TWAI_CMD_REG, TWAI_SELF_RX_REQ_M | TWAI_ABORT_TX_M); +#else + twai_putreg(TWAI_CMD_REG, TWAI_TX_REQ_M); +#endif + spin_unlock_irqrestore(&priv->lock, flags); + + return ret; +} + +/**************************************************************************** + * Name: esp32s3twai_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 esp32s3twai_txready(struct can_dev_s *dev) +{ + struct twai_dev_s *priv = dev->cd_priv; + uint32_t regval = twai_getreg(TWAI_STATUS_REG); + + caninfo("TWAI txready: %d\n", ((regval & TWAI_TX_BUF_ST_M) != 0)); + return ((regval & TWAI_TX_BUF_ST_M) != 0); +} + +/**************************************************************************** + * Name: esp32s3twai_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 esp32s3twai_txempty(struct can_dev_s *dev) +{ + struct twai_dev_s *priv = dev->cd_priv; + uint32_t regval = twai_getreg(TWAI_STATUS_REG); + + caninfo("TWAI txempty: %d\n", ((regval & TWAI_TX_BUF_ST_M) != 0)); + return ((regval & TWAI_TX_BUF_ST_M) != 0); +} + +/**************************************************************************** + * Name: esp32s3twai_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 esp32s3twai_interrupt(int irq, void *context, void *arg) +{ +#ifdef CONFIG_ESP32S3_TWAI + struct can_dev_s *dev = (struct can_dev_s *)arg; + struct can_hdr_s hdr; + uint8_t data[8]; + uint32_t frame_info; + uint32_t len; + uint32_t datastart; + uint32_t regval; + uint32_t i; + + /* Read the interrupt register results in clearing bits */ + + regval = twai_getreg(TWAI_INT_RAW_REG); + + /* Check for a receive interrupt */ + + if ((regval & TWAI_RX_INT_ST_M) != 0) + { + memset(&hdr, 0, sizeof(hdr)); + memset(data, 0, sizeof(data)); + + frame_info = twai_getreg(TWAI_DATA_0_REG); + + /* Construct the TWAI header */ + + if (frame_info & (1 << 6)) + { + hdr.ch_rtr = 1; + } + +#ifdef CONFIG_CAN_EXTID + if (frame_info & (1 << 7)) + { + /* The provided ID should be 29 bits */ + + hdr.ch_extid = 1; + hdr.ch_id = + (twai_getreg(TWAI_DATA_1_REG) << 21) + + (twai_getreg(TWAI_DATA_2_REG) << 13) + + (twai_getreg(TWAI_DATA_3_REG) << 5) + + (twai_getreg(TWAI_DATA_4_REG) >> 3); + datastart = TWAI_DATA_5_REG; + } + else +#endif + { + /* The provided ID should be 11 bits */ + + hdr.ch_id = + (twai_getreg(TWAI_DATA_1_REG) << 3) + + (twai_getreg(TWAI_DATA_2_REG) >> 5); + datastart = TWAI_DATA_3_REG; + } + + len = frame_info & 0xf; + if (len > CAN_MAXDATALEN) len = CAN_MAXDATALEN; + hdr.ch_dlc = len; + + for (i = 0; i < len; i++) + { + data[i] = twai_getreg(datastart + (i * 4)); + } + + /* Release the receive buffer */ + + twai_putreg(TWAI_CMD_REG, TWAI_RELEASE_BUF_M); + +#ifdef CONFIG_CAN_ERRORS + hdr.ch_error = 0; /* Error reporting not supported */ +#endif + can_receive(dev, &hdr, data); + } + + /* Check for TX buffer complete */ + + if ((regval & TWAI_TX_INT_ST_M) != 0) + { + /* Disable all further TX buffer interrupts */ + + regval = twai_getreg(TWAI_INT_ENA_REG); + regval &= ~TWAI_TX_INT_ENA_M; + twai_putreg(TWAI_INT_ENA_REG, regval); + + /* Indicate that the TX is done and a new TX buffer is available */ + + can_txdone(dev); + } + +#endif + return OK; +} + +/**************************************************************************** + * Name: esp32s3twai_set_acc_filter + * + * Description: + * Call to set acceptance filter. + * Must be called in reset mode. + * + * Input Parameters: + * code - Acceptance Code. + * mask - Acceptance Mask. + * single_filter - Whether to enable single filter mode. + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void esp32s3twai_set_acc_filter(uint32_t code, uint32_t mask, + bool single_filter) +{ + uint32_t regval; + uint32_t code_swapped = __builtin_bswap32(code); + uint32_t mask_swapped = __builtin_bswap32(mask); + + regval = twai_getreg(TWAI_MODE_REG); + if (single_filter) + { + regval |= TWAI_RX_FILTER_MODE_M; + } + else + { + regval &= ~(TWAI_RX_FILTER_MODE_M); + } + + twai_putreg(TWAI_MODE_REG, regval); + + for (int i = 0; i < 4; i++) + { + twai_putreg(TWAI_DATA_0_REG + (i * 4), + ((code_swapped >> (i * 8)) & 0xff)); + twai_putreg(TWAI_DATA_4_REG + (i * 4), + ((mask_swapped >> (i * 8)) & 0xff)); + } +} + +/**************************************************************************** + * Name: twai_baud_rate + * + * Description: + * Set the CAN bus timing registers based on the configured bit-rate and + * sample point position. + * + * The bit timing logic monitors the serial bus-line and performs sampling + * and adjustment of the sample point by synchronizing on the start-bit edge + * and resynchronizing on the following edges. + * + * Its operation may be explained simply by splitting nominal bit time into + * three segments as follows: + * + * 1. Synchronization segment (SYNC_SEG): a bit change is expected to occur + * within this time segment. It has a fixed length of one time quantum + * (1 x tCAN). + * 2. Bit segment 1 (BS1): defines the location of the sample point. It + * includes the PROP_SEG and PHASE_SEG1 of the CAN standard. Its duration + * is programmable between 1 and 16 time quanta but may be automatically + * lengthened to compensate for positive phase drifts due to differences + * in the frequency of the various nodes of the network. + * 3. Bit segment 2 (BS2): defines the location of the transmit point. It + * represents the PHASE_SEG2 of the CAN standard. Its duration is + * programmable between 1 and 8 time quanta but may also be automatically + * shortened to compensate for negative phase drifts. + * + * Pictorially: + * + * |<----------------- NOMINAL BIT TIME ----------------->| + * |<- SYNC_SEG ->|<------ BS1 ------>|<------ BS2 ------>| + * |<---- Tq ---->|<----- Tbs1 ------>|<----- Tbs2 ------>| + * + * Where + * Tbs1 is the duration of the BS1 segment + * Tbs2 is the duration of the BS2 segment + * Tq is the "Time Quantum" + * + * Relationships: + * + * baud = 1 / bit_time + * bit_time = Tq + Tbs1 + Tbs2 + * Tbs1 = Tq * ts1 + * Tbs2 = Tq * ts2 + * Tq = brp * Tcan + * + * Where: + * Tcan is the period of the APB clock + * + * Input Parameters: + * priv - A reference to the CAN block status + * rate - The resolution of one timing quanta, in Hz + * clock - Clock source frequency + * sjw - Max time quanta jump for synchronize + * sampl_pt - Enables triple sampling + * flags - Flag for configuration + * + * Returned Value: + * Zero on success; a negated errno on failure + * + ****************************************************************************/ + +static int twai_baud_rate(struct twai_dev_s *priv, int rate, int clock, + int sjw, int sampl_pt, int flags) +{ + const struct can_bittiming_const *timing = + &esp32s3_twai_bittiming_const; + int best_error = 1000000000; + int error; + int best_tseg = 0; + int best_brp = 0; + int best_rate = 0; + int brp = 0; + int tseg = 0; + int tseg1 = 0; + int tseg2 = 0; + uint32_t timing0; + uint32_t timing1; + + /* tseg even = round down, odd = round up */ + + for (tseg = (0 + 0 + 2) * 2; + tseg <= (timing->tseg2_max + timing->tseg1_max + 2) * 2 + 1; tseg++) + { + brp = clock / ((1 + tseg / 2) * rate) + tseg % 2; + if (brp == 0 || brp > 64) + { + continue; + } + + error = rate - clock / (brp * (1 + tseg / 2)); + if (error < 0) + { + error = -error; + } + + if (error <= best_error) + { + best_error = error; + best_tseg = tseg / 2; + best_brp = brp; + best_rate = clock / (brp * (1 + tseg / 2)); + } + } + + if (best_error && (rate / best_error < 10)) + { + canerr("baud rate %d is not possible with %d Hz clock\n", + rate, clock); + canerr("%d bps. brp=%d, best_tseg=%d, tseg1=%d, tseg2=%d\n", + best_rate, best_brp, best_tseg, tseg1, tseg2); + return -EINVAL; + } + + tseg2 = best_tseg - (sampl_pt * (best_tseg + 1)) / 100 + 1; + if (tseg2 < 0) + { + tseg2 = 0; + } + + if (tseg2 > timing->tseg2_max) + { + tseg2 = timing->tseg2_max; + } + + tseg1 = best_tseg - tseg2; + if (tseg1 > timing->tseg1_max) + { + tseg1 = timing->tseg1_max; + tseg2 = best_tseg - tseg1; + } + + caninfo("TS1: %d TS2: %d BRP: %d\n", tseg1, tseg2, best_brp); + + /* Configure bit timing */ + + timing0 = (best_brp / 2) - 1; + timing0 |= (sjw - 1) << TWAI_SYNC_JUMP_WIDTH_S; + + timing1 = tseg1 - 1; + timing1 |= (tseg2 - 1) << TWAI_TIME_SEG2_S; + +#ifdef CONFIG_ESP32S3_TWAI_SAM + /* The bus is sampled 3 times (recommended for low to medium speed buses + * to spikes on the bus-line). + */ + + timing1 |= CONFIG_ESP32S3_TWAI_SAM << TWAI_TIME_SAMP_S; +#endif + + twai_putreg(TWAI_BUS_TIMING_0_REG, timing0); + twai_putreg(TWAI_BUS_TIMING_1_REG, timing1); + + return OK; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: esp32s3_twaiinitialize + * + * Description: + * Initialize TWAI peripheral + * + * Input Parameters: + * None + * + * Returned Value: + * Valid TWAI device structure reference on success; a NULL on failure + * + ****************************************************************************/ + +struct can_dev_s *esp32s3_twaiinitialize(void) +{ + struct can_dev_s *twaidev; + irqstate_t flags; + + caninfo("TWAI\n"); + +#ifdef CONFIG_ESP32S3_TWAI + twaidev = &g_twaidev; + + flags = spin_lock_irqsave(&g_twaipriv.lock); + + /* Enable power to the TWAI module and + * Enable clocking to the TWAI module + */ + + esp32s3_periph_module_enable(PERIPH_TWAI_MODULE); + + /* Configure CAN GPIO pins */ + + esp32s3_configgpio(CONFIG_ESP32S3_TWAI_TXPIN, OUTPUT_FUNCTION_2); + esp32s3_gpio_matrix_out(CONFIG_ESP32S3_TWAI_TXPIN, TWAI_TX_IDX, 0, 0); + + esp32s3_configgpio(CONFIG_ESP32S3_TWAI_RXPIN, INPUT_FUNCTION_2); + esp32s3_gpio_matrix_in(CONFIG_ESP32S3_TWAI_RXPIN, TWAI_RX_IDX, 0); + + spin_unlock_irqrestore(&g_twaipriv.lock, flags); +#endif + + /* Then just perform a TWAI reset operation */ + + esp32s3twai_reset(twaidev); + + return twaidev; +} +#endif diff --git a/arch/xtensa/src/esp32s3/esp32s3_twai.h b/arch/xtensa/src/esp32s3/esp32s3_twai.h new file mode 100644 index 0000000000..7d1cb0ec03 --- /dev/null +++ b/arch/xtensa/src/esp32s3/esp32s3_twai.h @@ -0,0 +1,77 @@ +/**************************************************************************** + * arch/xtensa/src/esp32s3/esp32s3_twai.h + * + * 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. + * + ****************************************************************************/ + +#ifndef __ARCH_XTENSA_SRC_ESP32S3_ESP32S3_TWAI_H +#define __ARCH_XTENSA_SRC_ESP32S3_ESP32S3_TWAI_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include "hardware/esp32s3_twai.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#ifndef __ASSEMBLY__ +#ifdef __cplusplus +extern "C" +{ +#endif + +/**************************************************************************** + * Public Functions Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: esp32s3_twaiinitialize + * + * Description: + * Initialize the selected CAN port + * + * Input Parameters: + * Port number (for hardware that has multiple TWAI interfaces) + * + * Returned Value: + * Valid TWAI device structure reference on success; a NULL on failure + * + ****************************************************************************/ + +#if defined(CONFIG_CAN) && defined(CONFIG_ESP32S3_TWAI) +struct can_dev_s *esp32s3_twaiinitialize(void); +#endif + +#ifdef __cplusplus +} +#endif +#endif /* __ASSEMBLY__ */ + +#endif /* __ARCH_XTENSA_SRC_ESP32S3_ESP32S3_TWAI_H */ diff --git a/arch/xtensa/src/esp32s3/hardware/esp32s3_system.h b/arch/xtensa/src/esp32s3/hardware/esp32s3_system.h index 4fbe00207f..a207e931d8 100644 --- a/arch/xtensa/src/esp32s3/hardware/esp32s3_system.h +++ b/arch/xtensa/src/esp32s3/hardware/esp32s3_system.h @@ -300,7 +300,7 @@ #define SYSTEM_PWM1_CLK_EN_S 20 /* SYSTEM_TWAI_CLK_EN : R/W; bitpos: [19]; default: 0; - * Set 1 to enable CAN clock + * Set 1 to enable TWAI clock */ #define SYSTEM_TWAI_CLK_EN (BIT(19)) @@ -699,7 +699,7 @@ #define SYSTEM_PWM1_RST_S 20 /* SYSTEM_TWAI_RST : R/W; bitpos: [19]; default: 0; - * Set 1 to let CAN reset + * Set 1 to let TWAI reset */ #define SYSTEM_TWAI_RST (BIT(19)) diff --git a/arch/xtensa/src/esp32s3/hardware/esp32s3_twai.h b/arch/xtensa/src/esp32s3/hardware/esp32s3_twai.h new file mode 100644 index 0000000000..4a8e764541 --- /dev/null +++ b/arch/xtensa/src/esp32s3/hardware/esp32s3_twai.h @@ -0,0 +1,792 @@ +/**************************************************************************** + * arch/xtensa/src/esp32s3/hardware/esp32s3_twai.h + * + * 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. + * + ****************************************************************************/ + +#ifndef __ARCH_XTENSA_SRC_ESP32S3_HARDWARE_ESP32S3_TWAI_H +#define __ARCH_XTENSA_SRC_ESP32S3_HARDWARE_ESP32S3_TWAI_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include "esp32s3_soc.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* TWAI_MODE_REG register + * Mode Register + */ + +#define TWAI_MODE_REG (DR_REG_TWAI_BASE + 0x0) + +/* TWAI_RX_FILTER_MODE : R/W; bitpos: [3]; default: 0; + * This bit is used to configure the filter mode. 0: Dual filter mode; 1: + * Single filter mode. + */ + +#define TWAI_RX_FILTER_MODE (BIT(3)) +#define TWAI_RX_FILTER_MODE_M (TWAI_RX_FILTER_MODE_V << TWAI_RX_FILTER_MODE_S) +#define TWAI_RX_FILTER_MODE_V 0x00000001 +#define TWAI_RX_FILTER_MODE_S 3 + +/* TWAI_SELF_TEST_MODE : R/W; bitpos: [2]; default: 0; + * 1: Self test mode. In this mode the TX nodes can perform a successful + * transmission without receiving the acknowledge signal. This mode is often + * used to test a single node with the self reception request command. + */ + +#define TWAI_SELF_TEST_MODE (BIT(2)) +#define TWAI_SELF_TEST_MODE_M (TWAI_SELF_TEST_MODE_V << TWAI_SELF_TEST_MODE_S) +#define TWAI_SELF_TEST_MODE_V 0x00000001 +#define TWAI_SELF_TEST_MODE_S 2 + +/* TWAI_LISTEN_ONLY_MODE : R/W; bitpos: [1]; default: 0; + * 1: Listen only mode. In this mode the nodes will only receive messages + * from the bus, without generating the acknowledge signal nor updating the + * RX error counter. + */ + +#define TWAI_LISTEN_ONLY_MODE (BIT(1)) +#define TWAI_LISTEN_ONLY_MODE_M (TWAI_LISTEN_ONLY_MODE_V << TWAI_LISTEN_ONLY_MODE_S) +#define TWAI_LISTEN_ONLY_MODE_V 0x00000001 +#define TWAI_LISTEN_ONLY_MODE_S 1 + +/* TWAI_RESET_MODE : R/W; bitpos: [0]; default: 1; + * This bit is used to configure the operating mode of the TWAI Controller. + * 1: Reset mode; 0: Operating mode. + */ + +#define TWAI_RESET_MODE (BIT(0)) +#define TWAI_RESET_MODE_M (TWAI_RESET_MODE_V << TWAI_RESET_MODE_S) +#define TWAI_RESET_MODE_V 0x00000001 +#define TWAI_RESET_MODE_S 0 + +/* TWAI_CMD_REG register + * Command Register + */ + +#define TWAI_CMD_REG (DR_REG_TWAI_BASE + 0x4) + +/* TWAI_SELF_RX_REQ : WO; bitpos: [4]; default: 0; + * Self reception request command. Set the bit to 1 to allow a message be + * transmitted and received simultaneously. + */ + +#define TWAI_SELF_RX_REQ (BIT(4)) +#define TWAI_SELF_RX_REQ_M (TWAI_SELF_RX_REQ_V << TWAI_SELF_RX_REQ_S) +#define TWAI_SELF_RX_REQ_V 0x00000001 +#define TWAI_SELF_RX_REQ_S 4 + +/* TWAI_CLR_OVERRUN : WO; bitpos: [3]; default: 0; + * Set the bit to 1 to clear the data overrun status bit. + */ + +#define TWAI_CLR_OVERRUN (BIT(3)) +#define TWAI_CLR_OVERRUN_M (TWAI_CLR_OVERRUN_V << TWAI_CLR_OVERRUN_S) +#define TWAI_CLR_OVERRUN_V 0x00000001 +#define TWAI_CLR_OVERRUN_S 3 + +/* TWAI_RELEASE_BUF : WO; bitpos: [2]; default: 0; + * Set the bit to 1 to release the RX buffer. + */ + +#define TWAI_RELEASE_BUF (BIT(2)) +#define TWAI_RELEASE_BUF_M (TWAI_RELEASE_BUF_V << TWAI_RELEASE_BUF_S) +#define TWAI_RELEASE_BUF_V 0x00000001 +#define TWAI_RELEASE_BUF_S 2 + +/* TWAI_ABORT_TX : WO; bitpos: [1]; default: 0; + * Set the bit to 1 to cancel a pending transmission request. + */ + +#define TWAI_ABORT_TX (BIT(1)) +#define TWAI_ABORT_TX_M (TWAI_ABORT_TX_V << TWAI_ABORT_TX_S) +#define TWAI_ABORT_TX_V 0x00000001 +#define TWAI_ABORT_TX_S 1 + +/* TWAI_TX_REQ : WO; bitpos: [0]; default: 0; + * Set the bit to 1 to allow the driving nodes start transmission. + */ + +#define TWAI_TX_REQ (BIT(0)) +#define TWAI_TX_REQ_M (TWAI_TX_REQ_V << TWAI_TX_REQ_S) +#define TWAI_TX_REQ_V 0x00000001 +#define TWAI_TX_REQ_S 0 + +/* TWAI_STATUS_REG register + * Status register + */ + +#define TWAI_STATUS_REG (DR_REG_TWAI_BASE + 0x8) + +/* TWAI_MISS_ST : RO; bitpos: [8]; default: 0; + * This bit reflects whether the data packet in the RX FIFO is complete. 1: + * The current packet is missing; 0: The current packet is complete + */ + +#define TWAI_MISS_ST (BIT(8)) +#define TWAI_MISS_ST_M (TWAI_MISS_ST_V << TWAI_MISS_ST_S) +#define TWAI_MISS_ST_V 0x00000001 +#define TWAI_MISS_ST_S 8 + +/* TWAI_BUS_OFF_ST : RO; bitpos: [7]; default: 0; + * 1: In bus-off status, the TWAI Controller is no longer involved in bus + * activities. + */ + +#define TWAI_BUS_OFF_ST (BIT(7)) +#define TWAI_BUS_OFF_ST_M (TWAI_BUS_OFF_ST_V << TWAI_BUS_OFF_ST_S) +#define TWAI_BUS_OFF_ST_V 0x00000001 +#define TWAI_BUS_OFF_ST_S 7 + +/* TWAI_ERR_ST : RO; bitpos: [6]; default: 0; + * 1: At least one of the RX/TX error counter has reached or exceeded the + * value set in register TWAI_ERR_WARNING_LIMIT_REG. + */ + +#define TWAI_ERR_ST (BIT(6)) +#define TWAI_ERR_ST_M (TWAI_ERR_ST_V << TWAI_ERR_ST_S) +#define TWAI_ERR_ST_V 0x00000001 +#define TWAI_ERR_ST_S 6 + +/* TWAI_TX_ST : RO; bitpos: [5]; default: 0; + * 1: The TWAI Controller is transmitting a message to the bus. + */ + +#define TWAI_TX_ST (BIT(5)) +#define TWAI_TX_ST_M (TWAI_TX_ST_V << TWAI_TX_ST_S) +#define TWAI_TX_ST_V 0x00000001 +#define TWAI_TX_ST_S 5 + +/* TWAI_RX_ST : RO; bitpos: [4]; default: 0; + * 1: The TWAI Controller is receiving a message from the bus. + */ + +#define TWAI_RX_ST (BIT(4)) +#define TWAI_RX_ST_M (TWAI_RX_ST_V << TWAI_RX_ST_S) +#define TWAI_RX_ST_V 0x00000001 +#define TWAI_RX_ST_S 4 + +/* TWAI_TX_COMPLETE : RO; bitpos: [3]; default: 0; + * 1: The TWAI controller has successfully received a packet from the bus. + */ + +#define TWAI_TX_COMPLETE (BIT(3)) +#define TWAI_TX_COMPLETE_M (TWAI_TX_COMPLETE_V << TWAI_TX_COMPLETE_S) +#define TWAI_TX_COMPLETE_V 0x00000001 +#define TWAI_TX_COMPLETE_S 3 + +/* TWAI_TX_BUF_ST : RO; bitpos: [2]; default: 0; + * 1: The TX buffer is empty, the CPU may write a message into it. + */ + +#define TWAI_TX_BUF_ST (BIT(2)) +#define TWAI_TX_BUF_ST_M (TWAI_TX_BUF_ST_V << TWAI_TX_BUF_ST_S) +#define TWAI_TX_BUF_ST_V 0x00000001 +#define TWAI_TX_BUF_ST_S 2 + +/* TWAI_OVERRUN_ST : RO; bitpos: [1]; default: 0; + * 1: The RX FIFO is full and data overrun has occurred. + */ + +#define TWAI_OVERRUN_ST (BIT(1)) +#define TWAI_OVERRUN_ST_M (TWAI_OVERRUN_ST_V << TWAI_OVERRUN_ST_S) +#define TWAI_OVERRUN_ST_V 0x00000001 +#define TWAI_OVERRUN_ST_S 1 + +/* TWAI_RX_BUF_ST : RO; bitpos: [0]; default: 0; + * 1: The data in the RX buffer is not empty, with at least one received + * data packet. + */ + +#define TWAI_RX_BUF_ST (BIT(0)) +#define TWAI_RX_BUF_ST_M (TWAI_RX_BUF_ST_V << TWAI_RX_BUF_ST_S) +#define TWAI_RX_BUF_ST_V 0x00000001 +#define TWAI_RX_BUF_ST_S 0 + +/* TWAI_INT_RAW_REG register + * Interrupt Register + */ + +#define TWAI_INT_RAW_REG (DR_REG_TWAI_BASE + 0xc) + +/* TWAI_BUS_ERR_INT_ST : RO; bitpos: [7]; default: 0; + * Error interrupt. If this bit is set to 1, it indicates an error is + * detected on the bus. + */ + +#define TWAI_BUS_ERR_INT_ST (BIT(7)) +#define TWAI_BUS_ERR_INT_ST_M (TWAI_BUS_ERR_INT_ST_V << TWAI_BUS_ERR_INT_ST_S) +#define TWAI_BUS_ERR_INT_ST_V 0x00000001 +#define TWAI_BUS_ERR_INT_ST_S 7 + +/* TWAI_ARB_LOST_INT_ST : RO; bitpos: [6]; default: 0; + * Arbitration lost interrupt. If this bit is set to 1, it indicates an + * arbitration lost interrupt is generated. + */ + +#define TWAI_ARB_LOST_INT_ST (BIT(6)) +#define TWAI_ARB_LOST_INT_ST_M (TWAI_ARB_LOST_INT_ST_V << TWAI_ARB_LOST_INT_ST_S) +#define TWAI_ARB_LOST_INT_ST_V 0x00000001 +#define TWAI_ARB_LOST_INT_ST_S 6 + +/* TWAI_ERR_PASSIVE_INT_ST : RO; bitpos: [5]; default: 0; + * Error passive interrupt. If this bit is set to 1, it indicates the TWAI + * Controller is switched between error active status and error passive + * status due to the change of error counters. + */ + +#define TWAI_ERR_PASSIVE_INT_ST (BIT(5)) +#define TWAI_ERR_PASSIVE_INT_ST_M (TWAI_ERR_PASSIVE_INT_ST_V << TWAI_ERR_PASSIVE_INT_ST_S) +#define TWAI_ERR_PASSIVE_INT_ST_V 0x00000001 +#define TWAI_ERR_PASSIVE_INT_ST_S 5 + +/* TWAI_OVERRUN_INT_ST : RO; bitpos: [3]; default: 0; + * Data overrun interrupt. If this bit is set to 1, it indicates a data + * overrun interrupt is generated in the RX FIFO. + */ + +#define TWAI_OVERRUN_INT_ST (BIT(3)) +#define TWAI_OVERRUN_INT_ST_M (TWAI_OVERRUN_INT_ST_V << TWAI_OVERRUN_INT_ST_S) +#define TWAI_OVERRUN_INT_ST_V 0x00000001 +#define TWAI_OVERRUN_INT_ST_S 3 + +/* TWAI_ERR_WARN_INT_ST : RO; bitpos: [2]; default: 0; + * Error warning interrupt. If this bit is set to 1, it indicates the error + * status signal and the bus-off status signal of Status register have + * changed (e.g., switched from 0 to 1 or from 1 to 0). + */ + +#define TWAI_ERR_WARN_INT_ST (BIT(2)) +#define TWAI_ERR_WARN_INT_ST_M (TWAI_ERR_WARN_INT_ST_V << TWAI_ERR_WARN_INT_ST_S) +#define TWAI_ERR_WARN_INT_ST_V 0x00000001 +#define TWAI_ERR_WARN_INT_ST_S 2 + +/* TWAI_TX_INT_ST : RO; bitpos: [1]; default: 0; + * Transmit interrupt. If this bit is set to 1, it indicates the message + * transmitting mis- sion is finished and a new transmission is able to + * execute. + */ + +#define TWAI_TX_INT_ST (BIT(1)) +#define TWAI_TX_INT_ST_M (TWAI_TX_INT_ST_V << TWAI_TX_INT_ST_S) +#define TWAI_TX_INT_ST_V 0x00000001 +#define TWAI_TX_INT_ST_S 1 + +/* TWAI_RX_INT_ST : RO; bitpos: [0]; default: 0; + * Receive interrupt. If this bit is set to 1, it indicates there are + * messages to be handled in the RX FIFO. + */ + +#define TWAI_RX_INT_ST (BIT(0)) +#define TWAI_RX_INT_ST_M (TWAI_RX_INT_ST_V << TWAI_RX_INT_ST_S) +#define TWAI_RX_INT_ST_V 0x00000001 +#define TWAI_RX_INT_ST_S 0 + +/* TWAI_INT_ENA_REG register + * Interrupt Enable Register + */ + +#define TWAI_INT_ENA_REG (DR_REG_TWAI_BASE + 0x10) + +/* TWAI_BUS_ERR_INT_ENA : R/W; bitpos: [7]; default: 0; + * Set this bit to 1 to enable error interrupt. + */ + +#define TWAI_BUS_ERR_INT_ENA (BIT(7)) +#define TWAI_BUS_ERR_INT_ENA_M (TWAI_BUS_ERR_INT_ENA_V << TWAI_BUS_ERR_INT_ENA_S) +#define TWAI_BUS_ERR_INT_ENA_V 0x00000001 +#define TWAI_BUS_ERR_INT_ENA_S 7 + +/* TWAI_ARB_LOST_INT_ENA : R/W; bitpos: [6]; default: 0; + * Set this bit to 1 to enable arbitration lost interrupt. + */ + +#define TWAI_ARB_LOST_INT_ENA (BIT(6)) +#define TWAI_ARB_LOST_INT_ENA_M (TWAI_ARB_LOST_INT_ENA_V << TWAI_ARB_LOST_INT_ENA_S) +#define TWAI_ARB_LOST_INT_ENA_V 0x00000001 +#define TWAI_ARB_LOST_INT_ENA_S 6 + +/* TWAI_ERR_PASSIVE_INT_ENA : R/W; bitpos: [5]; default: 0; + * Set this bit to 1 to enable error passive interrupt. + */ + +#define TWAI_ERR_PASSIVE_INT_ENA (BIT(5)) +#define TWAI_ERR_PASSIVE_INT_ENA_M (TWAI_ERR_PASSIVE_INT_ENA_V << TWAI_ERR_PASSIVE_INT_ENA_S) +#define TWAI_ERR_PASSIVE_INT_ENA_V 0x00000001 +#define TWAI_ERR_PASSIVE_INT_ENA_S 5 + +/* TWAI_OVERRUN_INT_ENA : R/W; bitpos: [3]; default: 0; + * Set this bit to 1 to enable data overrun interrupt. + */ + +#define TWAI_OVERRUN_INT_ENA (BIT(3)) +#define TWAI_OVERRUN_INT_ENA_M (TWAI_OVERRUN_INT_ENA_V << TWAI_OVERRUN_INT_ENA_S) +#define TWAI_OVERRUN_INT_ENA_V 0x00000001 +#define TWAI_OVERRUN_INT_ENA_S 3 + +/* TWAI_ERR_WARN_INT_ENA : R/W; bitpos: [2]; default: 0; + * Set this bit to 1 to enable error warning interrupt. + */ + +#define TWAI_ERR_WARN_INT_ENA (BIT(2)) +#define TWAI_ERR_WARN_INT_ENA_M (TWAI_ERR_WARN_INT_ENA_V << TWAI_ERR_WARN_INT_ENA_S) +#define TWAI_ERR_WARN_INT_ENA_V 0x00000001 +#define TWAI_ERR_WARN_INT_ENA_S 2 + +/* TWAI_TX_INT_ENA : R/W; bitpos: [1]; default: 0; + * Set this bit to 1 to enable transmit interrupt. + */ + +#define TWAI_TX_INT_ENA (BIT(1)) +#define TWAI_TX_INT_ENA_M (TWAI_TX_INT_ENA_V << TWAI_TX_INT_ENA_S) +#define TWAI_TX_INT_ENA_V 0x00000001 +#define TWAI_TX_INT_ENA_S 1 + +/* TWAI_RX_INT_ENA : R/W; bitpos: [0]; default: 0; + * Set this bit to 1 to enable receive interrupt. + */ + +#define TWAI_RX_INT_ENA (BIT(0)) +#define TWAI_RX_INT_ENA_M (TWAI_RX_INT_ENA_V << TWAI_RX_INT_ENA_S) +#define TWAI_RX_INT_ENA_V 0x00000001 +#define TWAI_RX_INT_ENA_S 0 + +/* TWAI_BUS_TIMING_0_REG register + * Bus Timing Register 0 + */ + +#define TWAI_BUS_TIMING_0_REG (DR_REG_TWAI_BASE + 0x18) + +/* TWAI_SYNC_JUMP_WIDTH : RO | R/W; bitpos: [15:14]; default: 0; + * Synchronization Jump Width (SJW), 1 \verb+~+ 14 Tq wide. + */ + +#define TWAI_SYNC_JUMP_WIDTH 0x00000003 +#define TWAI_SYNC_JUMP_WIDTH_M (TWAI_SYNC_JUMP_WIDTH_V << TWAI_SYNC_JUMP_WIDTH_S) +#define TWAI_SYNC_JUMP_WIDTH_V 0x00000003 +#define TWAI_SYNC_JUMP_WIDTH_S 14 + +/* TWAI_BAUD_PRESC : RO | R/W; bitpos: [12:0]; default: 0; + * Baud Rate Prescaler, determines the frequency dividing ratio. + */ + +#define TWAI_BAUD_PRESC 0x00001fff +#define TWAI_BAUD_PRESC_M (TWAI_BAUD_PRESC_V << TWAI_BAUD_PRESC_S) +#define TWAI_BAUD_PRESC_V 0x00001fff +#define TWAI_BAUD_PRESC_S 0 + +/* TWAI_BUS_TIMING_1_REG register + * Bus Timing Register 1 + */ + +#define TWAI_BUS_TIMING_1_REG (DR_REG_TWAI_BASE + 0x1c) + +/* TWAI_TIME_SAMP : RO | R/W; bitpos: [7]; default: 0; + * The number of sample points. 0: the bus is sampled once; 1: the bus is + * sampled three times + */ + +#define TWAI_TIME_SAMP (BIT(7)) +#define TWAI_TIME_SAMP_M (TWAI_TIME_SAMP_V << TWAI_TIME_SAMP_S) +#define TWAI_TIME_SAMP_V 0x00000001 +#define TWAI_TIME_SAMP_S 7 + +/* TWAI_TIME_SEG2 : RO | R/W; bitpos: [6:4]; default: 0; + * The width of PBS2. + */ + +#define TWAI_TIME_SEG2 0x00000007 +#define TWAI_TIME_SEG2_M (TWAI_TIME_SEG2_V << TWAI_TIME_SEG2_S) +#define TWAI_TIME_SEG2_V 0x00000007 +#define TWAI_TIME_SEG2_S 4 + +/* TWAI_TIME_SEG1 : RO | R/W; bitpos: [3:0]; default: 0; + * The width of PBS1. + */ + +#define TWAI_TIME_SEG1 0x0000000f +#define TWAI_TIME_SEG1_M (TWAI_TIME_SEG1_V << TWAI_TIME_SEG1_S) +#define TWAI_TIME_SEG1_V 0x0000000f +#define TWAI_TIME_SEG1_S 0 + +/* TWAI_ARB_LOST_CAP_REG register + * Arbitration Lost Capture Register + */ + +#define TWAI_ARB_LOST_CAP_REG (DR_REG_TWAI_BASE + 0x2c) + +/* TWAI_ARB_LOST_CAP : RO; bitpos: [4:0]; default: 0; + * This register contains information about the bit position of lost + * arbitration. + */ + +#define TWAI_ARB_LOST_CAP 0x0000001f +#define TWAI_ARB_LOST_CAP_M (TWAI_ARB_LOST_CAP_V << TWAI_ARB_LOST_CAP_S) +#define TWAI_ARB_LOST_CAP_V 0x0000001f +#define TWAI_ARB_LOST_CAP_S 0 + +/* TWAI_ERR_CODE_CAP_REG register + * Error Code Capture Register + */ + +#define TWAI_ERR_CODE_CAP_REG (DR_REG_TWAI_BASE + 0x30) + +/* TWAI_ECC_TYPE : RO; bitpos: [7:6]; default: 0; + * This register contains information about error types: 00: bit error; 01: + * form error; 10: stuff error; 11: other type of error + */ + +#define TWAI_ECC_TYPE 0x00000003 +#define TWAI_ECC_TYPE_M (TWAI_ECC_TYPE_V << TWAI_ECC_TYPE_S) +#define TWAI_ECC_TYPE_V 0x00000003 +#define TWAI_ECC_TYPE_S 6 + +/* TWAI_ECC_DIRECTION : RO; bitpos: [5]; default: 0; + * This register contains information about transmission direction of the + * node when error occurs. 1: Error occurs when receiving a message; 0: + * Error occurs when transmitting a message + */ + +#define TWAI_ECC_DIRECTION (BIT(5)) +#define TWAI_ECC_DIRECTION_M (TWAI_ECC_DIRECTION_V << TWAI_ECC_DIRECTION_S) +#define TWAI_ECC_DIRECTION_V 0x00000001 +#define TWAI_ECC_DIRECTION_S 5 + +/* TWAI_ECC_SEGMENT : RO; bitpos: [4:0]; default: 0; + * This register contains information about the location of errors, see + * Table 181 for details. + */ + +#define TWAI_ECC_SEGMENT 0x0000001f +#define TWAI_ECC_SEGMENT_M (TWAI_ECC_SEGMENT_V << TWAI_ECC_SEGMENT_S) +#define TWAI_ECC_SEGMENT_V 0x0000001f +#define TWAI_ECC_SEGMENT_S 0 + +/* TWAI_ERR_WARNING_LIMIT_REG register + * Error Warning Limit Register + */ + +#define TWAI_ERR_WARNING_LIMIT_REG (DR_REG_TWAI_BASE + 0x34) + +/* TWAI_ERR_WARNING_LIMIT : RO | R/W; bitpos: [7:0]; default: 96; + * Error warning threshold. In the case when any of a error counter value + * exceeds the threshold, or all the error counter values are below the + * threshold, an error warning interrupt will be triggered (given the enable + * signal is valid). + */ + +#define TWAI_ERR_WARNING_LIMIT 0x000000ff +#define TWAI_ERR_WARNING_LIMIT_M (TWAI_ERR_WARNING_LIMIT_V << TWAI_ERR_WARNING_LIMIT_S) +#define TWAI_ERR_WARNING_LIMIT_V 0x000000ff +#define TWAI_ERR_WARNING_LIMIT_S 0 + +/* TWAI_RX_ERR_CNT_REG register + * Receive Error Counter Register + */ + +#define TWAI_RX_ERR_CNT_REG (DR_REG_TWAI_BASE + 0x38) + +/* TWAI_RX_ERR_CNT : RO | R/W; bitpos: [7:0]; default: 0; + * The RX error counter register, reflects value changes under reception + * status. + */ + +#define TWAI_RX_ERR_CNT 0x000000ff +#define TWAI_RX_ERR_CNT_M (TWAI_RX_ERR_CNT_V << TWAI_RX_ERR_CNT_S) +#define TWAI_RX_ERR_CNT_V 0x000000ff +#define TWAI_RX_ERR_CNT_S 0 + +/* TWAI_TX_ERR_CNT_REG register + * Transmit Error Counter Register + */ + +#define TWAI_TX_ERR_CNT_REG (DR_REG_TWAI_BASE + 0x3c) + +/* TWAI_TX_ERR_CNT : RO | R/W; bitpos: [7:0]; default: 0; + * The TX error counter register, reflects value changes under transmission + * status. + */ + +#define TWAI_TX_ERR_CNT 0x000000ff +#define TWAI_TX_ERR_CNT_M (TWAI_TX_ERR_CNT_V << TWAI_TX_ERR_CNT_S) +#define TWAI_TX_ERR_CNT_V 0x000000ff +#define TWAI_TX_ERR_CNT_S 0 + +/* TWAI_DATA_0_REG register + * Data register 0 + */ + +#define TWAI_DATA_0_REG (DR_REG_TWAI_BASE + 0x40) + +/* TWAI_TX_BYTE_0 : WO; bitpos: [7:0]; default: 0; + * In reset mode, it is acceptance code register 0 with R/W Permission. In + * operation mode, it stores the 0th byte information of the data to be + * transmitted under operating mode. + */ + +#define TWAI_TX_BYTE_0 0x000000ff +#define TWAI_TX_BYTE_0_M (TWAI_TX_BYTE_0_V << TWAI_TX_BYTE_0_S) +#define TWAI_TX_BYTE_0_V 0x000000ff +#define TWAI_TX_BYTE_0_S 0 + +/* TWAI_DATA_1_REG register + * Data register 1 + */ + +#define TWAI_DATA_1_REG (DR_REG_TWAI_BASE + 0x44) + +/* TWAI_TX_BYTE_1 : WO; bitpos: [7:0]; default: 0; + * In reset mode, it is acceptance code register 1 with R/W Permission. In + * operation mode, it stores the 1st byte information of the data to be + * transmitted under operating mode. + */ + +#define TWAI_TX_BYTE_1 0x000000ff +#define TWAI_TX_BYTE_1_M (TWAI_TX_BYTE_1_V << TWAI_TX_BYTE_1_S) +#define TWAI_TX_BYTE_1_V 0x000000ff +#define TWAI_TX_BYTE_1_S 0 + +/* TWAI_DATA_2_REG register + * Data register 2 + */ + +#define TWAI_DATA_2_REG (DR_REG_TWAI_BASE + 0x48) + +/* TWAI_TX_BYTE_2 : WO; bitpos: [7:0]; default: 0; + * In reset mode, it is acceptance code register 2 with R/W Permission. In + * operation mode, it stores the 2nd byte information of the data to be + * transmitted under operating mode. + */ + +#define TWAI_TX_BYTE_2 0x000000ff +#define TWAI_TX_BYTE_2_M (TWAI_TX_BYTE_2_V << TWAI_TX_BYTE_2_S) +#define TWAI_TX_BYTE_2_V 0x000000ff +#define TWAI_TX_BYTE_2_S 0 + +/* TWAI_DATA_3_REG register + * Data register 3 + */ + +#define TWAI_DATA_3_REG (DR_REG_TWAI_BASE + 0x4c) + +/* TWAI_TX_BYTE_3 : WO; bitpos: [7:0]; default: 0; + * In reset mode, it is acceptance code register 3 with R/W Permission. In + * operation mode, it stores the 3rd byte information of the data to be + * transmitted under operating mode. + */ + +#define TWAI_TX_BYTE_3 0x000000ff +#define TWAI_TX_BYTE_3_M (TWAI_TX_BYTE_3_V << TWAI_TX_BYTE_3_S) +#define TWAI_TX_BYTE_3_V 0x000000ff +#define TWAI_TX_BYTE_3_S 0 + +/* TWAI_DATA_4_REG register + * Data register 4 + */ + +#define TWAI_DATA_4_REG (DR_REG_TWAI_BASE + 0x50) + +/* TWAI_TX_BYTE_4 : WO; bitpos: [7:0]; default: 0; + * In reset mode, it is acceptance mask register 0 with R/W Permission. In + * operation mode, it stores the 4th byte information of the data to be + * transmitted under operating mode. + */ + +#define TWAI_TX_BYTE_4 0x000000ff +#define TWAI_TX_BYTE_4_M (TWAI_TX_BYTE_4_V << TWAI_TX_BYTE_4_S) +#define TWAI_TX_BYTE_4_V 0x000000ff +#define TWAI_TX_BYTE_4_S 0 + +/* TWAI_DATA_5_REG register + * Data register 5 + */ + +#define TWAI_DATA_5_REG (DR_REG_TWAI_BASE + 0x54) + +/* TWAI_TX_BYTE_5 : WO; bitpos: [7:0]; default: 0; + * In reset mode, it is acceptance mask register 1 with R/W Permission. In + * operation mode, it stores the 5th byte information of the data to be + * transmitted under operating mode. + */ + +#define TWAI_TX_BYTE_5 0x000000ff +#define TWAI_TX_BYTE_5_M (TWAI_TX_BYTE_5_V << TWAI_TX_BYTE_5_S) +#define TWAI_TX_BYTE_5_V 0x000000ff +#define TWAI_TX_BYTE_5_S 0 + +/* TWAI_DATA_6_REG register + * Data register 6 + */ + +#define TWAI_DATA_6_REG (DR_REG_TWAI_BASE + 0x58) + +/* TWAI_TX_BYTE_6 : WO; bitpos: [7:0]; default: 0; + * In reset mode, it is acceptance mask register 2 with R/W Permission. In + * operation mode, it stores the 6th byte information of the data to be + * transmitted under operating mode. + */ + +#define TWAI_TX_BYTE_6 0x000000ff +#define TWAI_TX_BYTE_6_M (TWAI_TX_BYTE_6_V << TWAI_TX_BYTE_6_S) +#define TWAI_TX_BYTE_6_V 0x000000ff +#define TWAI_TX_BYTE_6_S 0 + +/* TWAI_DATA_7_REG register + * Data register 7 + */ + +#define TWAI_DATA_7_REG (DR_REG_TWAI_BASE + 0x5c) + +/* TWAI_TX_BYTE_7 : WO; bitpos: [7:0]; default: 0; + * In reset mode, it is acceptance mask register 3 with R/W Permission. In + * operation mode, it stores the 7th byte information of the data to be + * transmitted under operating mode. + */ + +#define TWAI_TX_BYTE_7 0x000000ff +#define TWAI_TX_BYTE_7_M (TWAI_TX_BYTE_7_V << TWAI_TX_BYTE_7_S) +#define TWAI_TX_BYTE_7_V 0x000000ff +#define TWAI_TX_BYTE_7_S 0 + +/* TWAI_DATA_8_REG register + * Data register 8 + */ + +#define TWAI_DATA_8_REG (DR_REG_TWAI_BASE + 0x60) + +/* TWAI_TX_BYTE_8 : WO; bitpos: [7:0]; default: 0; + * Stored the 8th byte information of the data to be transmitted under + * operating mode. + */ + +#define TWAI_TX_BYTE_8 0x000000ff +#define TWAI_TX_BYTE_8_M (TWAI_TX_BYTE_8_V << TWAI_TX_BYTE_8_S) +#define TWAI_TX_BYTE_8_V 0x000000ff +#define TWAI_TX_BYTE_8_S 0 + +/* TWAI_DATA_9_REG register + * Data register 9 + */ + +#define TWAI_DATA_9_REG (DR_REG_TWAI_BASE + 0x64) + +/* TWAI_TX_BYTE_9 : WO; bitpos: [7:0]; default: 0; + * Stored the 9th byte information of the data to be transmitted under + * operating mode. + */ + +#define TWAI_TX_BYTE_9 0x000000ff +#define TWAI_TX_BYTE_9_M (TWAI_TX_BYTE_9_V << TWAI_TX_BYTE_9_S) +#define TWAI_TX_BYTE_9_V 0x000000ff +#define TWAI_TX_BYTE_9_S 0 + +/* TWAI_DATA_10_REG register + * Data register 10 + */ + +#define TWAI_DATA_10_REG (DR_REG_TWAI_BASE + 0x68) + +/* TWAI_TX_BYTE_10 : WO; bitpos: [7:0]; default: 0; + * Stored the 10th byte information of the data to be transmitted under + * operating mode. + */ + +#define TWAI_TX_BYTE_10 0x000000ff +#define TWAI_TX_BYTE_10_M (TWAI_TX_BYTE_10_V << TWAI_TX_BYTE_10_S) +#define TWAI_TX_BYTE_10_V 0x000000ff +#define TWAI_TX_BYTE_10_S 0 + +/* TWAI_DATA_11_REG register + * Data register 11 + */ + +#define TWAI_DATA_11_REG (DR_REG_TWAI_BASE + 0x6c) + +/* TWAI_TX_BYTE_11 : WO; bitpos: [7:0]; default: 0; + * Stored the 11th byte information of the data to be transmitted under + * operating mode. + */ + +#define TWAI_TX_BYTE_11 0x000000ff +#define TWAI_TX_BYTE_11_M (TWAI_TX_BYTE_11_V << TWAI_TX_BYTE_11_S) +#define TWAI_TX_BYTE_11_V 0x000000ff +#define TWAI_TX_BYTE_11_S 0 + +/* TWAI_DATA_12_REG register + * Data register 12 + */ + +#define TWAI_DATA_12_REG (DR_REG_TWAI_BASE + 0x70) + +/* TWAI_TX_BYTE_12 : WO; bitpos: [7:0]; default: 0; + * Stored the 12th byte information of the data to be transmitted under + * operating mode. + */ + +#define TWAI_TX_BYTE_12 0x000000ff +#define TWAI_TX_BYTE_12_M (TWAI_TX_BYTE_12_V << TWAI_TX_BYTE_12_S) +#define TWAI_TX_BYTE_12_V 0x000000ff +#define TWAI_TX_BYTE_12_S 0 + +/* TWAI_RX_MESSAGE_CNT_REG register + * Receive Message Counter Register + */ + +#define TWAI_RX_MESSAGE_CNT_REG (DR_REG_TWAI_BASE + 0x74) + +/* TWAI_RX_MESSAGE_COUNTER : RO; bitpos: [6:0]; default: 0; + * This register reflects the number of messages available within the RX + * FIFO. + */ + +#define TWAI_RX_MESSAGE_COUNTER 0x0000007f +#define TWAI_RX_MESSAGE_COUNTER_M (TWAI_RX_MESSAGE_COUNTER_V << TWAI_RX_MESSAGE_COUNTER_S) +#define TWAI_RX_MESSAGE_COUNTER_V 0x0000007f +#define TWAI_RX_MESSAGE_COUNTER_S 0 + +/* TWAI_CLOCK_DIVIDER_REG register + * Clock Divider register + */ + +#define TWAI_CLOCK_DIVIDER_REG (DR_REG_TWAI_BASE + 0x7c) + +/* TWAI_CLOCK_OFF : RO | R/W; bitpos: [8]; default: 0; + * This bit can be configured under reset mode. 1: Disable the external + * CLKOUT pin; 0: Enable the external CLKOUT pin + */ + +#define TWAI_CLOCK_OFF (BIT(8)) +#define TWAI_CLOCK_OFF_M (TWAI_CLOCK_OFF_V << TWAI_CLOCK_OFF_S) +#define TWAI_CLOCK_OFF_V 0x00000001 +#define TWAI_CLOCK_OFF_S 8 + +/* TWAI_CD : R/W; bitpos: [7:0]; default: 0; + * These bits are used to configure frequency dividing coefficients of the + * external CLKOUT pin. + */ + +#define TWAI_CD 0x000000ff +#define TWAI_CD_M (TWAI_CD_V << TWAI_CD_S) +#define TWAI_CD_V 0x000000ff +#define TWAI_CD_S 0 + +#endif /* __ARCH_XTENSA_SRC_ESP32S3_HARDWARE_ESP32S3_TWAI_H */ diff --git a/boards/xtensa/esp32s3/esp32s3-devkit/configs/twai/defconfig b/boards/xtensa/esp32s3/esp32s3-devkit/configs/twai/defconfig new file mode 100644 index 0000000000..8d526d053b --- /dev/null +++ b/boards/xtensa/esp32s3/esp32s3-devkit/configs/twai/defconfig @@ -0,0 +1,49 @@ +# +# This file is autogenerated: PLEASE DO NOT EDIT IT. +# +# You can use "make menuconfig" to make any modifications to the installed .config file. +# You can then do "make savedefconfig" to generate a new defconfig file that includes your +# modifications. +# +# CONFIG_ARCH_LEDS is not set +# CONFIG_NSH_ARGCAT is not set +# CONFIG_NSH_CMDOPT_HEXDUMP is not set +CONFIG_ARCH="xtensa" +CONFIG_ARCH_BOARD="esp32s3-devkit" +CONFIG_ARCH_BOARD_COMMON=y +CONFIG_ARCH_BOARD_ESP32S3_DEVKIT=y +CONFIG_ARCH_CHIP="esp32s3" +CONFIG_ARCH_CHIP_ESP32S3=y +CONFIG_ARCH_CHIP_ESP32S3WROOM1=y +CONFIG_ARCH_INTERRUPTSTACK=2048 +CONFIG_ARCH_STACKDUMP=y +CONFIG_ARCH_XTENSA=y +CONFIG_BOARD_LOOPSPERMSEC=16717 +CONFIG_BUILTIN=y +CONFIG_DEBUG_FULLOPT=y +CONFIG_DEBUG_SYMBOLS=y +CONFIG_ESP32S3_TWAI=y +CONFIG_ESP32S3_UART0=y +CONFIG_EXAMPLES_CAN=y +CONFIG_FS_PROCFS=y +CONFIG_HAVE_CXX=y +CONFIG_HAVE_CXXINITIALIZE=y +CONFIG_IDLETHREAD_STACKSIZE=3072 +CONFIG_INIT_ENTRYPOINT="nsh_main" +CONFIG_INTELHEX_BINARY=y +CONFIG_NSH_ARCHINIT=y +CONFIG_NSH_BUILTIN_APPS=y +CONFIG_NSH_FILEIOSIZE=512 +CONFIG_NSH_LINELEN=64 +CONFIG_NSH_READLINE=y +CONFIG_PREALLOC_TIMERS=4 +CONFIG_RAM_SIZE=114688 +CONFIG_RAM_START=0x20000000 +CONFIG_RR_INTERVAL=200 +CONFIG_SCHED_WAITPID=y +CONFIG_START_DAY=6 +CONFIG_START_MONTH=12 +CONFIG_START_YEAR=2011 +CONFIG_SYSLOG_BUFFER=y +CONFIG_SYSTEM_NSH=y +CONFIG_UART0_SERIAL_CONSOLE=y diff --git a/boards/xtensa/esp32s3/esp32s3-devkit/src/Make.defs b/boards/xtensa/esp32s3/esp32s3-devkit/src/Make.defs index c660b4354b..809a1acea3 100644 --- a/boards/xtensa/esp32s3/esp32s3-devkit/src/Make.defs +++ b/boards/xtensa/esp32s3/esp32s3-devkit/src/Make.defs @@ -41,6 +41,10 @@ ifeq ($(CONFIG_ESP32S3_SPI),y) CSRCS += esp32s3_board_spi.c endif +ifeq ($(CONFIG_ESP32S3_TWAI),y) +CSRCS += esp32s3_twai.c +endif + ifeq ($(CONFIG_PWM),y) CSRCS += esp32s3_ledc.c endif diff --git a/boards/xtensa/esp32s3/esp32s3-devkit/src/esp32s3-devkit.h b/boards/xtensa/esp32s3/esp32s3-devkit/src/esp32s3-devkit.h index 31257b5ebf..0b06e2c26c 100644 --- a/boards/xtensa/esp32s3/esp32s3-devkit/src/esp32s3-devkit.h +++ b/boards/xtensa/esp32s3/esp32s3-devkit/src/esp32s3-devkit.h @@ -190,5 +190,9 @@ int esp32s3_djoy_initialize(void); int esp32s3_pwm_setup(void); #endif +#ifdef CONFIG_ESP32S3_TWAI +int esp32s3_twai_setup(void); +#endif + #endif /* __ASSEMBLY__ */ #endif /* __BOARDS_XTENSA_ESP32S3_ESP32S3_DEVKIT_SRC_ESP32S3_DEVKIT_H */ diff --git a/boards/xtensa/esp32s3/esp32s3-devkit/src/esp32s3_bringup.c b/boards/xtensa/esp32s3/esp32s3-devkit/src/esp32s3_bringup.c index d6853d4f00..479f189271 100644 --- a/boards/xtensa/esp32s3/esp32s3-devkit/src/esp32s3_bringup.c +++ b/boards/xtensa/esp32s3/esp32s3-devkit/src/esp32s3_bringup.c @@ -205,6 +205,17 @@ int esp32s3_bringup(void) } #endif +#ifdef CONFIG_ESP32S3_TWAI + + /* Initialize TWAI and register the TWAI driver. */ + + ret = esp32s3_twai_setup(); + if (ret < 0) + { + syslog(LOG_ERR, "ERROR: esp32s3_twai_setup failed: %d\n", ret); + } +#endif + #ifdef CONFIG_SENSORS_BMP180 /* Try to register BMP180 device in I2C0 */ diff --git a/boards/xtensa/esp32s3/esp32s3-devkit/src/esp32s3_twai.c b/boards/xtensa/esp32s3/esp32s3-devkit/src/esp32s3_twai.c new file mode 100644 index 0000000000..998a49c2e2 --- /dev/null +++ b/boards/xtensa/esp32s3/esp32s3-devkit/src/esp32s3_twai.c @@ -0,0 +1,90 @@ +/**************************************************************************** + * boards/xtensa/esp32s3/esp32s3-devkit/src/esp32s3_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 + +#include +#include + +#include +#include + +#include "chip.h" + +#include "esp32s3_twai.h" +#include "esp32s3-devkit.h" + +#ifdef CONFIG_CAN + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Configuration ************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: esp32s3_twai_setup + * + * Description: + * Initialize TWAI and register the TWAI device + * + ****************************************************************************/ + +int esp32s3_twai_setup(void) +{ +#ifdef CONFIG_ESP32S3_TWAI + struct can_dev_s *twai; + int ret; + + /* Call esp32s3_twaiinitialize() to get an instance of the TWAI + * interface + * */ + + twai = esp32s3_twaiinitialize(); + if (twai == NULL) + { + canerr("ERROR: Failed to get TWAI interface\n"); + return -ENODEV; + } + + /* Register the TWAI driver at "/dev/can0" */ + + ret = can_register("/dev/can0", twai); + if (ret < 0) + { + canerr("ERROR: TWAI1 register failed: %d\n", ret); + return ret; + } + + return OK; +#else + return -ENODEV; +#endif +} + +#endif /* CONFIG_CAN */