pkarashchenko commented on a change in pull request #5206:
URL: https://github.com/apache/incubator-nuttx/pull/5206#discussion_r782893163



##########
File path: arch/arm/src/stm32/stm32_fdcan.c
##########
@@ -0,0 +1,3453 @@
+/****************************************************************************
+ * arch/arm/src/stm32/stm32_fdcan.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
+ *s
+ * 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 <stdint.h>
+#include <stdbool.h>
+#include <string.h>
+#include <errno.h>
+#include <debug.h>
+#include <assert.h>
+
+#include <arch/board/board.h>
+#include <nuttx/irq.h>
+#include <nuttx/arch.h>
+#include <nuttx/semaphore.h>
+#include <nuttx/can/can.h>
+
+#include "arm_internal.h"
+#include "arm_arch.h"
+
+#include "stm32_fdcan.h"
+#include "hardware/stm32_pinmap.h"
+#include "stm32_gpio.h"
+#include "stm32_rcc.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Clock source *************************************************************/
+
+#define FDCANCLK_PDIV              (0)
+
+#if FDCANCLK_PDIV == 0
+#  define STM32_FDCANCLK_FREQUENCY (STM32_FDCAN_FREQUENCY / (1))
+#else
+#  define STM32_FDCANCLK_FREQUENCY (STM32_FDCAN_FREQUENCY / (2 * 
FDCANCLK_PDIV))
+#endif
+
+/* General Configuration ****************************************************/
+
+#if defined(CONFIG_STM32_STM32G4XXX)
+
+/* FDCAN Message RAM */
+
+#  define FDCAN_MSGRAM_WORDS         (212)
+#  define STM32_CANRAM1_BASE         (STM32_CANRAM_BASE + 0x0000)
+#  define STM32_CANRAM2_BASE         (STM32_CANRAM_BASE + 
1*(FDCAN_MSGRAM_WORDS * 4) + 4)
+#  define STM32_CANRAM3_BASE         (STM32_CANRAM_BASE + 
2*(FDCAN_MSGRAM_WORDS * 4) + 4)
+
+#  ifdef CONFIG_STM32_FDCAN1
+#    define FDCAN1_STDFILTER_SIZE    (28)
+#    define FDCAN1_EXTFILTER_SIZE    (8)
+#    define FDCAN1_RXFIFO0_SIZE      (3)
+#    define FDCAN1_RXFIFO1_SIZE      (3)
+#    define FDCAN1_TXEVENTFIFO_SIZE  (3)
+#    define FDCAN1_TXFIFIOQ_SIZE     (3)
+
+#    define FDCAN1_STDFILTER_WORDS   (28)
+#    define FDCAN1_EXTFILTER_WORDS   (16)
+#    define FDCAN1_RXFIFO0_WORDS     (54)
+#    define FDCAN1_RXFIFO1_WORDS     (54)
+#    define FDCAN1_TXEVENTFIFO_WORDS (6)
+#    define FDCAN1_TXFIFIOQ_WORDS    (54)
+#  endif
+#  ifdef CONFIG_STM32_FDCAN2
+#    define FDCAN2_STDFILTER_SIZE    (28)
+#    define FDCAN2_EXTFILTER_SIZE    (8)
+#    define FDCAN2_RXFIFO0_SIZE      (3)
+#    define FDCAN2_RXFIFO1_SIZE      (3)
+#    define FDCAN2_TXEVENTFIFO_SIZE  (3)
+#    define FDCAN2_TXFIFIOQ_SIZE     (3)
+
+#    define FDCAN2_STDFILTER_WORDS   (28)
+#    define FDCAN2_EXTFILTER_WORDS   (16)
+#    define FDCAN2_RXFIFO0_WORDS     (54)
+#    define FDCAN2_RXFIFO1_WORDS     (54)
+#    define FDCAN2_TXEVENTFIFO_WORDS (6)
+#    define FDCAN2_TXFIFIOQ_WORDS    (54)
+#  endif
+#  ifdef CONFIG_STM32_FDCAN3
+#    define FDCAN3_STDFILTER_SIZE    (28)
+#    define FDCAN3_EXTFILTER_SIZE    (8)
+#    define FDCAN3_RXFIFO0_SIZE      (3)
+#    define FDCAN3_RXFIFO1_SIZE      (3)
+#    define FDCAN3_TXEVENTFIFO_SIZE  (3)
+#    define FDCAN3_TXFIFIOQ_SIZE     (3)
+
+#    define FDCAN3_STDFILTER_WORDS   (28)
+#    define FDCAN3_EXTFILTER_WORDS   (16)
+#    define FDCAN3_RXFIFO0_WORDS     (54)
+#    define FDCAN3_RXFIFO1_WORDS     (54)
+#    define FDCAN3_TXEVENTFIFO_WORDS (6)
+#    define FDCAN3_TXFIFIOQ_WORDS    (54)
+#  endif
+#else
+#  error
+#endif
+
+/* FDCAN1 Configuration *****************************************************/
+
+#ifdef CONFIG_STM32_FDCAN1
+
+/* Bit timing */
+
+#  define FDCAN1_NTSEG1  (CONFIG_STM32_FDCAN1_NTSEG1 - 1)
+#  define FDCAN1_NTSEG2  (CONFIG_STM32_FDCAN1_NTSEG2 - 1)
+#  define FDCAN1_NBRP    ((STM32_FDCANCLK_FREQUENCY /             \
+                           ((FDCAN1_NTSEG1 + FDCAN1_NTSEG2 + 3) * \
+                            CONFIG_STM32_FDCAN1_BITRATE)) - 1)
+#  define FDCAN1_NSJW    (CONFIG_STM32_FDCAN1_NSJW - 1)
+
+#  if FDCAN1_NTSEG1 > FDCAN_NBTP_NTSEG1_MAX
+#    error Invalid FDCAN1 NTSEG1
+#  endif
+#  if FDCAN1_NTSEG2 > FDCAN_NBTP_NTSEG2_MAX
+#    error Invalid FDCAN1 NTSEG2
+#  endif
+#  if FDCAN1_NSJW > FDCAN_NBTP_NSJW_MAX
+#    error Invalid FDCAN1 NSJW
+#  endif
+#  if FDCAN1_NBRP > FDCAN_NBTP_NBRP_MAX
+#    error Invalid FDCAN1 NBRP
+#  endif
+
+#  ifdef CONFIG_STM32_FDCAN1_FD_BRS
+#  define FDCAN1_DTSEG1 (CONFIG_STM32_FDCAN1_DTSEG1 - 1)
+#  define FDCAN1_DTSEG2 (CONFIG_STM32_FDCAN1_DTSEG2 - 1)
+#  define FDCAN1_DBRP   ((STM32_FDCANCLK_FREQUENCY /             \
+                          ((FDCAN1_DTSEG1 + FDCAN1_DTSEG2 + 3) * \
+                           CONFIG_STM32_FDCAN1_DBITRATE)) - 1)
+#  define FDCAN1_DSJW   (CONFIG_STM32_FDCAN1_DSJW - 1)
+#  else
+#  define FDCAN1_DTSEG1 1
+#  define FDCAN1_DTSEG2 1
+#  define FDCAN1_DBRP   1
+#  define FDCAN1_DSJW   1
+#  endif /* CONFIG_STM32_FDCAN1_FD_BRS */
+
+#  if FDCAN1_DTSEG1 > FDCAN_DBTP_DTSEG1_MAX
+#    error Invalid FDCAN1 DTSEG1
+#  endif
+#  if FDCAN1_DTSEG2 > FDCAN_DBTP_DTSEG2_MAX
+#    error Invalid FDCAN1 DTSEG2
+#  endif
+#  if FDCAN1_DBRP > FDCAN_DBTP_DBRP_MAX
+#    error Invalid FDCAN1 DBRP
+#  endif
+#  if FDCAN1_DSJW > FDCAN_DBTP_DSJW_MAX
+#    error Invalid FDCAN1 DSJW
+#  endif
+
+/* FDCAN1 Message RAM Configuration *****************************************/
+
+/* FDCAN1 Message RAM Layout */
+
+#  define FDCAN1_STDFILTER_INDEX   0
+#  define FDCAN1_EXTFILTERS_INDEX  (FDCAN1_STDFILTER_INDEX + 
FDCAN1_STDFILTER_WORDS)
+#  define FDCAN1_RXFIFO0_INDEX     (FDCAN1_EXTFILTERS_INDEX + 
FDCAN1_EXTFILTER_WORDS)
+#  define FDCAN1_RXFIFO1_INDEX     (FDCAN1_RXFIFO0_INDEX + 
FDCAN1_RXFIFO0_WORDS)
+#  define FDCAN1_TXEVENTFIFO_INDEX (FDCAN1_RXFIFO1_INDEX + 
FDCAN1_RXFIFO1_WORDS)
+#  define FDCAN1_TXFIFOQ_INDEX     (FDCAN1_TXEVENTFIFO_INDEX + 
FDCAN1_TXEVENTFIFO_WORDS)
+#  define FDCAN1_MSGRAM_WORDS      (FDCAN1_TXFIFOQ_INDEX + 
FDCAN1_TXFIFIOQ_WORDS)
+
+#endif /* CONFIG_STM32_FDCAN1 */
+
+/* FDCAN2 Configuration *****************************************************/
+
+#ifdef CONFIG_STM32_FDCAN2
+
+/* Bit timing */
+
+#  define FDCAN2_NTSEG1  (CONFIG_STM32_FDCAN2_NTSEG1 - 1)
+#  define FDCAN2_NTSEG2  (CONFIG_STM32_FDCAN2_NTSEG2 - 1)
+#  define FDCAN2_NBRP    (((STM32_FDCANCLK_FREQUENCY /              \
+                            ((FDCAN2_NTSEG1 + FDCAN2_NTSEG2 + 3) *  \
+                             CONFIG_STM32_FDCAN2_BITRATE)) - 1))
+#  define FDCAN2_NSJW    (CONFIG_STM32_FDCAN2_NSJW - 1)
+
+#  if FDCAN2_NTSEG1 > FDCAN_NBTP_NTSEG1_MAX
+#    error Invalid FDCAN2 NTSEG1
+#  endif
+#  if FDCAN2_NTSEG2 > FDCAN_NBTP_NTSEG2_MAX
+#    error Invalid FDCAN2 NTSEG2
+#  endif
+#  if FDCAN2_NSJW > FDCAN_NBTP_NSJW_MAX
+#    error Invalid FDCAN2 NSJW
+#  endif
+#  if FDCAN2_NBRP > FDCAN_NBTP_NBRP_MAX
+#    error Invalid FDCAN1 NBRP
+#  endif
+
+#  ifdef CONFIG_STM32_FDCAN2_FD_BRS
+#  define FDCAN2_DTSEG1 (CONFIG_STM32_FDCAN2_DTSEG1 - 1)
+#  define FDCAN2_DTSEG2 (CONFIG_STM32_FDCAN2_DTSEG2 - 1)
+#  define FDCAN2_DBRP   (((STM32_FDCANCLK_FREQUENCY /                   \
+                           ((FDCAN2_DTSEG1 + FDCAN2_DTSEG2 + 3) *       \
+                            CONFIG_STM32_FDCAN2_DBITRATE)) - 1))
+#  define FDCAN2_DSJW   (CONFIG_STM32_FDCAN2_DSJW - 1)
+#  else
+#  define FDCAN2_DTSEG1 1
+#  define FDCAN2_DTSEG2 1
+#  define FDCAN2_DBRP   1
+#  define FDCAN2_DSJW   1
+#  endif /* CONFIG_STM32_FDCAN2_FD_BRS */
+
+#  if FDCAN2_DTSEG1 > FDCAN_DBTP_DTSEG1_MAX
+#    error Invalid FDCAN2 DTSEG1
+#  endif
+#  if FDCAN2_DTSEG2 > FDCAN_DBTP_DTSEG2_MAX
+#    error Invalid FDCAN2 DTSEG2
+#  endif
+#  if FDCAN2_DBRP > FDCAN_DBTP_DBRP_MAX
+#    error Invalid FDCAN2 DBRP
+#  endif
+#  if FDCAN2_DSJW > FDCAN_DBTP_DSJW_MAX
+#    error Invalid FDCAN2 DSJW
+#  endif
+
+/* FDCAN2 Message RAM Configuration *****************************************/
+
+/* FDCAN2 Message RAM Layout */
+
+#  define FDCAN2_STDFILTER_INDEX   0
+#  define FDCAN2_EXTFILTERS_INDEX  (FDCAN2_STDFILTER_INDEX + 
FDCAN2_STDFILTER_WORDS)
+#  define FDCAN2_RXFIFO0_INDEX     (FDCAN2_EXTFILTERS_INDEX + 
FDCAN2_EXTFILTER_WORDS)
+#  define FDCAN2_RXFIFO1_INDEX     (FDCAN2_RXFIFO0_INDEX + 
FDCAN2_RXFIFO0_WORDS)
+#  define FDCAN2_TXEVENTFIFO_INDEX (FDCAN2_RXFIFO1_INDEX + 
FDCAN2_RXFIFO1_WORDS)
+#  define FDCAN2_TXFIFOQ_INDEX     (FDCAN2_TXEVENTFIFO_INDEX + 
FDCAN2_TXEVENTFIFO_WORDS)
+#  define FDCAN2_MSGRAM_WORDS      (FDCAN2_TXFIFOQ_INDEX + 
FDCAN2_TXFIFIOQ_WORDS)
+
+#endif /* CONFIG_STM32_FDCAN2 */
+
+/* FDCAN3 Configuration *****************************************************/
+
+#ifdef CONFIG_STM32_FDCAN3
+
+/* Bit timing */
+
+#  define FDCAN3_NTSEG1  (CONFIG_STM32_FDCAN3_NTSEG1 - 1)
+#  define FDCAN3_NTSEG2  (CONFIG_STM32_FDCAN3_NTSEG2 - 1)
+#  define FDCAN3_NBRP    (((STM32_FDCANCLK_FREQUENCY /              \
+                            ((FDCAN3_NTSEG1 + FDCAN3_NTSEG2 + 3) *  \
+                             CONFIG_STM32_FDCAN3_BITRATE)) - 1))
+#  define FDCAN3_NSJW    (CONFIG_STM32_FDCAN3_NSJW - 1)
+
+#  if FDCAN3_NTSEG1 > FDCAN_NBTP_NTSEG1_MAX
+#    error Invalid FDCAN3 NTSEG1
+#  endif
+#  if FDCAN3_NTSEG2 > FDCAN_NBTP_NTSEG2_MAX
+#    error Invalid FDCAN3 NTSEG2
+#  endif
+#  if FDCAN3_NSJW > FDCAN_NBTP_NSJW_MAX
+#    error Invalid FDCAN3 NSJW
+#  endif
+#  if FDCAN3_NBRP > FDCAN_NBTP_NBRP_MAX
+#    error Invalid FDCAN1 NBRP
+#  endif
+
+#  ifdef CONFIG_STM32_FDCAN3_FD_BRS
+#  define FDCAN3_DTSEG1 (CONFIG_STM32_FDCAN3_DTSEG1 - 1)
+#  define FDCAN3_DTSEG2 (CONFIG_STM32_FDCAN3_DTSEG2 - 1)
+#  define FDCAN3_DBRP   (((STM32_FDCANCLK_FREQUENCY /                   \
+                           ((FDCAN3_DTSEG1 + FDCAN3_DTSEG2 + 3) *       \
+                            CONFIG_STM32_FDCAN3_DBITRATE)) - 1))
+#  define FDCAN3_DSJW   (CONFIG_STM32_FDCAN3_DSJW - 1)
+#  else
+#  define FDCAN3_DTSEG1 1
+#  define FDCAN3_DTSEG2 1
+#  define FDCAN3_DBRP   1
+#  define FDCAN3_DSJW   1
+#  endif /* CONFIG_STM32_FDCAN3_FD_BRS */
+
+#  if FDCAN3_DTSEG1 > FDCAN_DBTP_DTSEG1_MAX
+#    error Invalid FDCAN3 DTSEG1
+#  endif
+#  if FDCAN3_DTSEG2 > FDCAN_DBTP_DTSEG2_MAX
+#    error Invalid FDCAN3 DTSEG2
+#  endif
+#  if FDCAN3_DBRP > FDCAN_DBTP_DBRP_MAX
+#    error Invalid FDCAN3 DBRP
+#  endif
+#  if FDCAN3_DSJW > FDCAN_DBTP_DSJW_MAX
+#    error Invalid FDCAN3 DSJW
+#  endif
+
+/* FDCAN3 Message RAM Configuration *****************************************/
+
+/* FDCAN3 Message RAM Layout */
+
+#  define FDCAN3_STDFILTER_INDEX   0
+#  define FDCAN3_EXTFILTERS_INDEX  (FDCAN3_STDFILTER_INDEX + 
FDCAN3_STDFILTER_WORDS)
+#  define FDCAN3_RXFIFO0_INDEX     (FDCAN3_EXTFILTERS_INDEX + 
FDCAN3_EXTFILTER_WORDS)
+#  define FDCAN3_RXFIFO1_INDEX     (FDCAN3_RXFIFO0_INDEX + 
FDCAN3_RXFIFO0_WORDS)
+#  define FDCAN3_TXEVENTFIFO_INDEX (FDCAN3_RXFIFO1_INDEX + 
FDCAN3_RXFIFO1_WORDS)
+#  define FDCAN3_TXFIFOQ_INDEX     (FDCAN3_TXEVENTFIFO_INDEX + 
FDCAN3_TXEVENTFIFO_WORDS)
+#  define FDCAN3_MSGRAM_WORDS      (FDCAN3_TXFIFOQ_INDEX + 
FDCAN3_TXFIFIOQ_WORDS)
+
+#endif /* CONFIG_STM32_FDCAN3 */
+
+/* Loopback mode */
+
+#undef STM32_FDCAN_LOOPBACK
+#if defined(CONFIG_STM32_FDCAN1_LOOPBACK) ||   \
+    defined(CONFIG_STM32_FDCAN2_LOOPBACK) ||   \
+    defined(CONFIG_STM32_FDCAN3_LOOPBACK)
+#  define STM32_FDCAN_LOOPBACK 1
+#endif
+
+/* Interrupts ***************************************************************/
+
+/* Common interrupts
+ *
+ *   FDCAN_INT_TSW  - Timestamp Wraparound
+ *   FDCAN_INT_MRAF - Message RAM Access Failure
+ *   FDCAN_INT_TOO  - Timeout Occurred
+ *   FDCAN_INT_ELO  - Error Logging Overflow
+ *   FDCAN_INT_EP   - Error Passive
+ *   FDCAN_INT_EW   - Warning Status
+ *   FDCAN_INT_BO   - Bus_Off Status
+ *   FDCAN_INT_WDI  - Watchdog Interrupt
+ *   FDCAN_INT_PEA  - Protocol Error in Arbritration Phase
+ *   FDCAN_INT_PED  - Protocol Error in Data Phase
+ */
+
+#define FDCAN_CMNERR_INTS   (FDCAN_INT_MRAF | FDCAN_INT_TOO | FDCAN_INT_EP | \
+                            FDCAN_INT_BO | FDCAN_INT_WDI | FDCAN_INT_PEA | \
+                            FDCAN_INT_PED)
+#define FDCAN_COMMON_INTS   FDCAN_CMNERR_INTS
+
+/* RXFIFO mode interrupts
+ *
+ *   FDCAN_INT_RF0N - Receive FIFO 0 New Message
+ *   FDCAN_INT_RF0F - Receive FIFO 0 Full
+ *   FDCAN_INT_RF0L - Receive FIFO 0 Message Lost
+ *   FDCAN_INT_RF1N - Receive FIFO 1 New Message
+ *   FDCAN_INT_RF1F - Receive FIFO 1 Full
+ *   FDCAN_INT_RF1L - Receive FIFO 1 Message Lost
+ *   FDCAN_INT_HPM  - High Priority Message Received
+ *
+ */
+
+#define FDCAN_RXCOMMON_INTS  0
+#define FDCAN_RXFIFO0_INTS  (FDCAN_INT_RF0N | FDCAN_INT_RF0L)
+#define FDCAN_RXFIFO1_INTS  (FDCAN_INT_RF1N | FDCAN_INT_RF1L)
+#define FDCAN_RXFIFO_INTS   (FDCAN_RXFIFO0_INTS | FDCAN_RXFIFO1_INTS | \
+                            FDCAN_INT_HPM | FDCAN_RXCOMMON_INTS)
+
+#define FDCAN_RXERR_INTS    (FDCAN_INT_RF0L | FDCAN_INT_RF1L)
+
+/* TX FIFOQ mode interrupts
+ *
+ *   FDCAN_INT_TFE  - Tx FIFO Empty
+ *
+ * TX Event FIFO interrupts
+ *
+ *   FDCAN_INT_TEFN - Tx Event FIFO New Entry
+ *   FDCAN_INT_TEFF - Tx Event FIFO Full
+ *   FDCAN_INT_TEFL - Tx Event FIFO Element Lost
+ *
+ * Mode-independent TX-related interrupts
+ *
+ *   FDCAN_INT_TC   - Transmission Completed
+ *   FDCAN_INT_TCF  - Transmission Cancellation Finished
+ */
+
+#define FDCAN_TXCOMMON_INTS (FDCAN_INT_TC | FDCAN_INT_TCF)
+#define FDCAN_TXFIFOQ_INTS  (FDCAN_INT_TFE | FDCAN_TXCOMMON_INTS)
+#define FDCAN_TXEVFIFO_INTS (FDCAN_INT_TEFN | FDCAN_INT_TEFF | \
+                            FDCAN_INT_TEFL)
+#define FDCAN_TXDEDBUF_INTS FDCAN_TXCOMMON_INTS
+
+#define FDCAN_TXERR_INTS    (FDCAN_INT_TEFL | FDCAN_INT_PEA | FDCAN_INT_PED)
+
+/* Common-, TX- and RX-Error-Mask */
+
+#define FDCAN_ANYERR_INTS (FDCAN_CMNERR_INTS | FDCAN_RXERR_INTS | 
FDCAN_TXERR_INTS)
+
+/* Convenience macro for clearing all interrupts */
+
+#define FDCAN_INT_ALL     0x3fcfffff
+
+/* Debug ********************************************************************/
+
+/* Debug configurations that may be enabled just for testing FDCAN */
+
+#ifndef CONFIG_DEBUG_CAN_INFO
+#  undef CONFIG_STM32_FDCAN_REGDEBUG
+#endif
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/* CAN frame format */
+
+enum stm32_frameformat_e
+{
+  FDCAN_ISO11898_1_FORMAT        = 0,  /* Frame format according to ISO11898-1 
*/
+  FDCAN_NONISO_BOSCH_V1_FORMAT   = 1   /* Frame format according to Bosch CAN 
FD V1.0 */
+};
+
+/* CAN mode of operation */
+
+enum stm32_canmode_e
+{
+  FDCAN_CLASSIC_MODE    = 0, /* Classic CAN operation */
+  FDCAN_FD_MODE         = 1, /* CAN FD operation */
+  FDCAN_FD_BRS_MODE     = 2  /* CAN FD operation with bit rate switching */
+};
+
+/* CAN driver state */
+
+enum can_state_s
+{
+  FDCAN_STATE_UNINIT = 0,    /* Not yet initialized */
+  FDCAN_STATE_RESET,         /* Initialized, reset state */
+  FDCAN_STATE_SETUP,         /* fdcan_setup() has been called */
+  FDCAN_STATE_DISABLED       /* Disabled by a fdcan_shutdown() */
+};
+
+/* This structure describes the FDCAN message RAM layout */
+
+struct stm32_msgram_s
+{
+  uint32_t *stdfilters;    /* Standard filters */
+  uint32_t *extfilters;    /* Extended filters */
+  uint32_t *rxfifo0;       /* RX FIFO0 */
+  uint32_t *rxfifo1;       /* RX FIFO1 */
+  uint32_t *txeventfifo;   /* TX event FIFO */
+  uint32_t *txfifoq;       /* TX FIFO queue */
+};
+
+/* This structure provides the constant configuration of a FDCAN peripheral */
+
+struct stm32_config_s
+{
+  uint32_t rxpinset;        /* RX pin configuration */
+  uint32_t txpinset;        /* TX pin configuration */
+  uintptr_t base;           /* Base address of the FDCAN registers */
+  uint32_t baud;            /* Configured baud */
+  uint32_t nbtp;            /* Nominal bit timing/prescaler register setting */
+  uint32_t dbtp;            /* Data bit timing/prescaler register setting */
+  uint8_t port;             /* FDCAN port number (1 or 2) */
+  uint8_t irq0;             /* FDCAN peripheral IRQ number for interrupt line 
0 */
+  uint8_t irq1;             /* FDCAN peripheral IRQ number for interrupt line 
1 */
+  uint8_t mode;             /* See enum stm32_canmode_e */
+  uint8_t format;           /* See enum stm32_frameformat_e */
+  uint8_t nstdfilters;      /* Number of standard filters */
+  uint8_t nextfilters;      /* Number of extended filters */
+  uint8_t nrxfifo0;         /* Number of RX FIFO0 elements */
+  uint8_t nrxfifo1;         /* Number of RX FIFO1 elements */
+  uint8_t ntxeventfifo;     /* Number of TXevent FIFO elements */
+  uint8_t ntxfifoq;         /* Number of TX FIFO queue elements */
+  uint8_t rxfifo0esize;     /* RX FIFO0 element size (words) */
+  uint8_t rxfifo1esize;     /* RX FIFO1 element size (words) */
+  uint8_t txeventesize;     /* TXevent element size (words) */
+  uint8_t txbufferesize;    /* TX buffer element size (words) */
+#ifdef STM32_FDCAN_LOOPBACK
+  bool    loopback;         /* True: Loopback mode */
+#endif
+
+  /* FDCAN message RAM layout */
+
+  struct stm32_msgram_s msgram;
+};
+
+/* This structure provides the current state of a FDCAN peripheral */
+
+struct stm32_fdcan_s
+{
+  /* The constant configuration */
+
+  const struct stm32_config_s *config;
+
+  uint8_t state;            /* See enum can_state_s */
+#ifdef CONFIG_CAN_EXTID
+  uint8_t nextalloc;        /* Number of allocated extended filters */
+#endif
+  uint8_t nstdalloc;        /* Number of allocated standard filters */
+  uint32_t nbtp;            /* Current nominal bit timing */
+  uint32_t dbtp;            /* Current data bit timing */
+  uint32_t rxints;          /* Configured RX interrupts */
+  uint32_t txints;          /* Configured TX interrupts */
+
+#ifdef CONFIG_CAN_EXTID
+  uint32_t extfilters[2];   /* Extended filter bit allocator.  2*32=64 */
+#endif
+  uint32_t stdfilters[4];   /* Standard filter bit allocator.  4*32=128 */
+
+#ifdef CONFIG_STM32_FDCAN_REGDEBUG
+  uintptr_t regaddr;        /* Last register address read */
+  uint32_t regval;          /* Last value read from the register */
+  unsigned int count;       /* Number of times that the value was read */
+#endif
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/* FDCAN Register access */
+
+static uint32_t fdcan_getreg(FAR struct stm32_fdcan_s *priv, int offset);
+static void fdcan_putreg(FAR struct stm32_fdcan_s *priv, int offset,
+              uint32_t regval);
+#ifdef CONFIG_STM32_FDCAN_REGDEBUG
+static void fdcan_dumpregs(FAR struct stm32_fdcan_s *priv,
+                           FAR const char *msg);
+static void fdcan_dumprxregs(FAR struct stm32_fdcan_s *priv,
+                             FAR const char *msg);
+static void fdcan_dumptxregs(FAR struct stm32_fdcan_s *priv,
+                             FAR const char *msg);
+static void fdcan_dumpramlayout(FAR struct stm32_fdcan_s *priv);
+#else
+#  define fdcan_dumpregs(priv,msg)
+#  define fdcan_dumprxregs(priv,msg)
+#  define fdcan_dumptxregs(priv,msg)
+#  define fdcan_dumpramlayout(priv)
+#endif
+
+/* FDCAN helpers */
+
+static uint8_t fdcan_dlc2bytes(FAR struct stm32_fdcan_s *priv, uint8_t dlc);
+
+#ifdef CONFIG_CAN_EXTID
+static int fdcan_add_extfilter(FAR struct stm32_fdcan_s *priv,
+              FAR struct canioc_extfilter_s *extconfig);
+static int fdcan_del_extfilter(FAR struct stm32_fdcan_s *priv, int ndx);
+#endif
+static int fdcan_add_stdfilter(FAR struct stm32_fdcan_s *priv,
+              FAR struct canioc_stdfilter_s *stdconfig);
+static int fdcan_del_stdfilter(FAR struct stm32_fdcan_s *priv, int ndx);
+
+static int
+fdcan_start_busoff_recovery_sequence(FAR struct stm32_fdcan_s *priv);
+
+/* CAN driver methods */
+
+static void fdcan_reset(FAR struct can_dev_s *dev);
+static int  fdcan_setup(FAR struct can_dev_s *dev);
+static void fdcan_shutdown(FAR struct can_dev_s *dev);
+static void fdcan_rxint(FAR struct can_dev_s *dev, bool enable);
+static void fdcan_txint(FAR struct can_dev_s *dev, bool enable);
+static int  fdcan_ioctl(FAR struct can_dev_s *dev, int cmd,
+                        unsigned long arg);
+static int  fdcan_remoterequest(FAR struct can_dev_s *dev, uint16_t id);
+static int  fdcan_send(FAR struct can_dev_s *dev, FAR struct can_msg_s *msg);
+static bool fdcan_txready(FAR struct can_dev_s *dev);
+static bool fdcan_txempty(FAR struct can_dev_s *dev);
+
+/* FDCAN interrupt handling */
+
+#ifdef CONFIG_CAN_ERRORS
+static void fdcan_error(FAR struct can_dev_s *dev, uint32_t status);
+#endif
+static void fdcan_receive(FAR struct can_dev_s *dev,
+                          FAR uint32_t *rxbuffer,
+                          unsigned long nwords);
+static int  fdcan_interrupt(int irq, void *context, FAR void *arg);
+
+/* Hardware initialization */
+
+static int  fdcan_hw_initialize(FAR struct stm32_fdcan_s *priv);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const struct can_ops_s g_fdcanops =
+{
+  .co_reset         = fdcan_reset,
+  .co_setup         = fdcan_setup,
+  .co_shutdown      = fdcan_shutdown,
+  .co_rxint         = fdcan_rxint,
+  .co_txint         = fdcan_txint,
+  .co_ioctl         = fdcan_ioctl,
+  .co_remoterequest = fdcan_remoterequest,
+  .co_send          = fdcan_send,
+  .co_txready       = fdcan_txready,
+  .co_txempty       = fdcan_txempty,
+};
+
+#ifdef CONFIG_STM32_FDCAN1
+/* Message RAM allocation */
+
+/* Constant configuration */
+
+static const struct stm32_config_s g_fdcan1const =
+{
+  .rxpinset         = GPIO_FDCAN1_RX,
+  .txpinset         = GPIO_FDCAN1_TX,
+  .base             = STM32_FDCAN1_BASE,
+  .baud             = CONFIG_STM32_FDCAN1_BITRATE,
+  .nbtp             = FDCAN_NBTP_NBRP(FDCAN1_NBRP) |
+                      FDCAN_NBTP_NTSEG1(FDCAN1_NTSEG1) |
+                      FDCAN_NBTP_NTSEG2(FDCAN1_NTSEG2) |
+                      FDCAN_NBTP_NSJW(FDCAN1_NSJW),
+  .dbtp             = FDCAN_DBTP_DBRP(FDCAN1_DBRP) |
+                      FDCAN_DBTP_DTSEG1(FDCAN1_DTSEG1) |
+                      FDCAN_DBTP_DTSEG2(FDCAN1_DTSEG2) |
+                      FDCAN_DBTP_DSJW(FDCAN1_DSJW),
+  .port             = 1,
+  .irq0             = STM32_IRQ_FDCAN1_0,
+  .irq1             = STM32_IRQ_FDCAN1_1,
+#if defined(CONFIG_STM32_FDCAN1_CLASSIC)
+  .mode             = FDCAN_CLASSIC_MODE,
+#elif defined(CONFIG_STM32_FDCAN1_FD)
+  .mode             = FDCAN_FD_MODE,
+#else
+  .mode             = FDCAN_FD_BRS_MODE,
+#endif
+#if defined(CONFIG_STM32_FDCAN1_NONISO_FORMAT)
+  .format           = FDCAN_NONISO_BOSCH_V1_FORMAT,
+#else
+  .format           = FDCAN_ISO11898_1_FORMAT,
+#endif
+  .nstdfilters      = FDCAN1_STDFILTER_SIZE,
+  .nextfilters      = FDCAN1_EXTFILTER_SIZE,
+  .nrxfifo0         = FDCAN1_RXFIFO0_SIZE,
+  .nrxfifo1         = FDCAN1_RXFIFO1_SIZE,
+  .ntxeventfifo     = FDCAN1_TXEVENTFIFO_SIZE,
+  .ntxfifoq         = FDCAN1_TXFIFIOQ_SIZE,
+  .rxfifo0esize     = (FDCAN1_RXFIFO0_WORDS / FDCAN1_RXFIFO0_SIZE),
+  .rxfifo1esize     = (FDCAN1_RXFIFO1_WORDS / FDCAN1_RXFIFO1_SIZE),
+  .txeventesize     = (FDCAN1_TXEVENTFIFO_WORDS / FDCAN1_TXEVENTFIFO_SIZE),
+  .txbufferesize    = (FDCAN1_TXFIFIOQ_WORDS / FDCAN1_TXFIFIOQ_SIZE),
+
+#ifdef CONFIG_STM32_FDCAN1_LOOPBACK
+  .loopback         = true,
+#endif
+
+  /* FDCAN1 Message RAM */
+
+  .msgram =
+  {
+    (uint32_t *)(STM32_CANRAM1_BASE + (FDCAN1_STDFILTER_INDEX << 2)),
+    (uint32_t *)(STM32_CANRAM1_BASE + (FDCAN1_EXTFILTERS_INDEX << 2)),
+    (uint32_t *)(STM32_CANRAM1_BASE + (FDCAN1_RXFIFO0_INDEX << 2)),
+    (uint32_t *)(STM32_CANRAM1_BASE + (FDCAN1_RXFIFO1_INDEX << 2)),
+    (uint32_t *)(STM32_CANRAM1_BASE + (FDCAN1_TXEVENTFIFO_INDEX << 2)),
+    (uint32_t *)(STM32_CANRAM1_BASE + (FDCAN1_TXFIFOQ_INDEX << 2))
+  }
+};
+
+/* FDCAN1 variable driver state */
+
+static struct stm32_fdcan_s g_fdcan1priv;
+static struct can_dev_s g_fdcan1dev;
+
+#endif /* CONFIG_STM32_FDCAN1 */
+
+#ifdef CONFIG_STM32_FDCAN2
+/* FDCAN2 message RAM allocation */
+
+/* FDCAN2 constant configuration */
+
+static const struct stm32_config_s g_fdcan2const =
+{
+  .rxpinset         = GPIO_FDCAN2_RX,
+  .txpinset         = GPIO_FDCAN2_TX,
+  .base             = STM32_FDCAN2_BASE,
+  .baud             = CONFIG_STM32_FDCAN2_BITRATE,
+  .nbtp             = FDCAN_NBTP_NBRP(FDCAN2_NBRP) |
+                      FDCAN_NBTP_NTSEG1(FDCAN2_NTSEG1) |
+                      FDCAN_NBTP_NTSEG2(FDCAN2_NTSEG2) |
+                      FDCAN_NBTP_NSJW(FDCAN2_NSJW),
+  .dbtp             = FDCAN_DBTP_DBRP(FDCAN2_DBRP) |
+                      FDCAN_DBTP_DTSEG1(FDCAN2_DTSEG1) |
+                      FDCAN_DBTP_DTSEG2(FDCAN2_DTSEG2) |
+                      FDCAN_DBTP_DSJW(FDCAN2_DSJW),
+  .port             = 2,
+  .irq0             = STM32_IRQ_FDCAN2_0,
+  .irq1             = STM32_IRQ_FDCAN2_1,
+#if defined(CONFIG_STM32_FDCAN2_CLASSIC)
+  .mode             = FDCAN_CLASSIC_MODE,
+#elif defined(CONFIG_STM32_FDCAN2_FD)
+  .mode             = FDCAN_FD_MODE,
+#else
+  .mode             = FDCAN_FD_BRS_MODE,
+#endif
+#if defined(CONFIG_STM32_FDCAN2_NONISO_FORMAT)
+  .format           = FDCAN_NONISO_BOSCH_V1_FORMAT,
+#else
+  .format           = FDCAN_ISO11898_1_FORMAT,
+#endif
+  .nstdfilters      = FDCAN2_STDFILTER_SIZE,
+  .nextfilters      = FDCAN2_EXTFILTER_SIZE,
+  .nrxfifo0         = FDCAN2_RXFIFO0_SIZE,
+  .nrxfifo1         = FDCAN2_RXFIFO1_SIZE,
+  .ntxeventfifo     = FDCAN2_TXEVENTFIFO_SIZE,
+  .ntxfifoq         = FDCAN2_TXFIFIOQ_SIZE,
+  .rxfifo0esize     = (FDCAN2_RXFIFO0_WORDS / FDCAN2_RXFIFO0_SIZE),
+  .rxfifo1esize     = (FDCAN2_RXFIFO1_WORDS / FDCAN2_RXFIFO1_SIZE),
+  .txeventesize     = (FDCAN2_TXEVENTFIFO_WORDS / FDCAN2_TXEVENTFIFO_SIZE),
+  .txbufferesize    = (FDCAN2_TXFIFIOQ_WORDS / FDCAN2_TXFIFIOQ_SIZE),
+
+#ifdef CONFIG_STM32_FDCAN2_LOOPBACK
+  .loopback         = true,
+#endif
+
+  /* FDCAN2 Message RAM */
+
+  .msgram =
+  {
+    (uint32_t *)(STM32_CANRAM2_BASE + (FDCAN2_STDFILTER_INDEX << 2)),
+    (uint32_t *)(STM32_CANRAM2_BASE + (FDCAN2_EXTFILTERS_INDEX << 2)),
+    (uint32_t *)(STM32_CANRAM2_BASE + (FDCAN2_RXFIFO0_INDEX << 2)),
+    (uint32_t *)(STM32_CANRAM2_BASE + (FDCAN2_RXFIFO1_INDEX << 2)),
+    (uint32_t *)(STM32_CANRAM2_BASE + (FDCAN2_TXEVENTFIFO_INDEX << 2)),
+    (uint32_t *)(STM32_CANRAM2_BASE + (FDCAN2_TXFIFOQ_INDEX << 2))
+  }
+};
+
+/* FDCAN2 variable driver state */
+
+static struct stm32_fdcan_s g_fdcan2priv;
+static struct can_dev_s g_fdcan2dev;
+
+#endif /* CONFIG_STM32_FDCAN2 */
+
+#ifdef CONFIG_STM32_FDCAN3
+/* FDCAN3 message RAM allocation */
+
+/* FDCAN3 constant configuration */
+
+static const struct stm32_config_s g_fdcan3const =
+{
+  .rxpinset         = GPIO_FDCAN3_RX,
+  .txpinset         = GPIO_FDCAN3_TX,
+  .base             = STM32_FDCAN3_BASE,
+  .baud             = CONFIG_STM32_FDCAN3_BITRATE,
+  .nbtp             = FDCAN_NBTP_NBRP(FDCAN3_NBRP) |
+                      FDCAN_NBTP_NTSEG1(FDCAN3_NTSEG1) |
+                      FDCAN_NBTP_NTSEG2(FDCAN3_NTSEG2) |
+                      FDCAN_NBTP_NSJW(FDCAN3_NSJW),
+  .dbtp             = FDCAN_DBTP_DBRP(FDCAN3_DBRP) |
+                      FDCAN_DBTP_DTSEG1(FDCAN3_DTSEG1) |
+                      FDCAN_DBTP_DTSEG2(FDCAN3_DTSEG2) |
+                      FDCAN_DBTP_DSJW(FDCAN3_DSJW),
+  .port             = 3,
+  .irq0             = STM32_IRQ_FDCAN3_0,
+  .irq1             = STM32_IRQ_FDCAN3_1,
+#if defined(CONFIG_STM32_FDCAN3_CLASSIC)
+  .mode             = FDCAN_CLASSIC_MODE,
+#elif defined(CONFIG_STM32_FDCAN3_FD)
+  .mode             = FDCAN_FD_MODE,
+#else
+  .mode             = FDCAN_FD_BRS_MODE,
+#endif
+#if defined(CONFIG_STM32_FDCAN3_NONISO_FORMAT)
+  .format           = FDCAN_NONISO_BOSCH_V1_FORMAT,
+#else
+  .format           = FDCAN_ISO11898_1_FORMAT,
+#endif
+  .nstdfilters      = FDCAN3_STDFILTER_SIZE,
+  .nextfilters      = FDCAN3_EXTFILTER_SIZE,
+  .nrxfifo0         = FDCAN3_RXFIFO0_SIZE,
+  .nrxfifo1         = FDCAN3_RXFIFO1_SIZE,
+  .ntxeventfifo     = FDCAN3_TXEVENTFIFO_SIZE,
+  .ntxfifoq         = FDCAN3_TXFIFIOQ_SIZE,
+  .rxfifo0esize     = (FDCAN3_RXFIFO0_WORDS / FDCAN3_RXFIFO0_SIZE),
+  .rxfifo1esize     = (FDCAN3_RXFIFO1_WORDS / FDCAN3_RXFIFO1_SIZE),
+  .txeventesize     = (FDCAN3_TXEVENTFIFO_WORDS / FDCAN3_TXEVENTFIFO_SIZE),
+  .txbufferesize    = (FDCAN3_TXFIFIOQ_WORDS / FDCAN3_TXFIFIOQ_SIZE),
+
+#ifdef CONFIG_STM32_FDCAN3_LOOPBACK
+  .loopback         = true,
+#endif
+
+  /* FDCAN3 Message RAM */
+
+  .msgram =
+  {
+    (uint32_t *)(STM32_CANRAM3_BASE + (FDCAN3_STDFILTER_INDEX << 2)),
+    (uint32_t *)(STM32_CANRAM3_BASE + (FDCAN3_EXTFILTERS_INDEX << 2)),
+    (uint32_t *)(STM32_CANRAM3_BASE + (FDCAN3_RXFIFO0_INDEX << 2)),
+    (uint32_t *)(STM32_CANRAM3_BASE + (FDCAN3_RXFIFO1_INDEX << 2)),
+    (uint32_t *)(STM32_CANRAM3_BASE + (FDCAN3_TXEVENTFIFO_INDEX << 2)),
+    (uint32_t *)(STM32_CANRAM3_BASE + (FDCAN3_TXFIFOQ_INDEX << 2))
+  }
+};
+
+/* FDCAN3 variable driver state */
+
+static struct stm32_fdcan_s g_fdcan3priv;
+static struct can_dev_s g_fdcan3dev;
+
+#endif /* CONFIG_STM32_FDCAN3 */
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: fdcan_getreg
+ *
+ * Description:
+ *   Read the value of a FDCAN register.
+ *
+ * Input Parameters:
+ *   priv - A reference to the FDCAN peripheral state
+ *   offset - The offset to the register to read
+ *
+ * Returned Value:
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_STM32_FDCAN_REGDEBUG
+static uint32_t fdcan_getreg(FAR struct stm32_fdcan_s *priv, int offset)
+{
+  FAR const struct stm32_config_s *config  = priv->config;
+  uintptr_t                        regaddr = 0;
+  uint32_t                         regval  = 0;
+
+  /* Read the value from the register */
+
+  regaddr = config->base + offset;
+  regval  = getreg32(regaddr);
+
+  /* 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 (regaddr == priv->regaddr && regval == priv->regval)
+    {
+      if (priv->count == 0xffffffff || ++priv->count > 3)
+        {
+          if (priv->count == 4)
+            {
+              caninfo("...\n");
+            }
+
+          return regval;
+        }
+    }
+
+  /* No this is a new address or value */
+
+  else
+    {
+      /* Did we print "..." for the previous value? */
+
+      if (priv->count > 3)
+        {
+          /* Yes.. then show how many times the value repeated */
+
+          caninfo("[repeats %d more times]\n", priv->count - 3);
+        }
+
+      /* Save the new address, value, and count */
+
+      priv->regaddr = regaddr;
+      priv->regval  = regval;
+      priv->count   = 1;
+    }
+
+  /* Show the register value read */
+
+  caninfo("%08" PRIx32 "->%08" PRIx32 "\n", regaddr, regval);
+  return regval;
+}
+
+#else
+static uint32_t fdcan_getreg(FAR struct stm32_fdcan_s *priv, int offset)
+{
+  FAR const struct stm32_config_s *config = priv->config;
+  return getreg32(config->base + offset);
+}
+
+#endif
+
+/****************************************************************************
+ * Name: fdcan_putreg
+ *
+ * Description:
+ *   Set the value of a FDCAN register.
+ *
+ * Input Parameters:
+ *   priv - A reference to the FDCAN peripheral state
+ *   offset - The offset to the register to write
+ *   regval - The value to write to the register
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_STM32_FDCAN_REGDEBUG
+static void fdcan_putreg(FAR struct stm32_fdcan_s *priv, int offset,
+                        uint32_t regval)
+{
+  FAR const struct stm32_config_s *config = priv->config;
+  uintptr_t regaddr = config->base + offset;
+
+  /* Show the register value being written */
+
+  caninfo("%08" PRIx32 "->%08" PRIx32 "\n", regaddr, regval);
+
+  /* Write the value */
+
+  putreg32(regval, regaddr);
+}
+
+#else
+static void fdcan_putreg(FAR struct stm32_fdcan_s *priv, int offset,
+                        uint32_t regval)
+{
+  FAR const struct stm32_config_s *config = priv->config;
+  putreg32(regval, config->base + offset);
+}
+
+#endif
+
+/****************************************************************************
+ * Name: fdcan_dumpctrlregs
+ *
+ * Description:
+ *   Dump the contents of all CAN control registers
+ *
+ * Input Parameters:
+ *   priv - A reference to the CAN block status
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_STM32_FDCAN_REGDEBUG
+static void fdcan_dumpregs(FAR struct stm32_fdcan_s *priv,
+                                  FAR const char *msg)
+{
+  FAR const struct stm32_config_s *config = priv->config;
+
+  caninfo("CAN%d Control and Status Registers: %s\n", config->port, msg);
+  caninfo("  Base:  %08" PRIx32 "\n", config->base);
+
+  /* CAN control and status registers */
+
+  caninfo("  CCCR:  %08" PRIx32 "   TEST:  %08" PRIx32 "\n",
+          getreg32(config->base + STM32_FDCAN_CCCR_OFFSET),
+          getreg32(config->base + STM32_FDCAN_TEST_OFFSET));
+
+  caninfo("  NBTP:  %08" PRIx32 "   DBTP:  %08" PRIx32 "\n",
+          getreg32(config->base + STM32_FDCAN_NBTP_OFFSET),
+          getreg32(config->base + STM32_FDCAN_DBTP_OFFSET));
+
+  caninfo("  IE:    %08" PRIx32 "   TIE:   %08" PRIx32 "\n",
+          getreg32(config->base + STM32_FDCAN_IE_OFFSET),
+          getreg32(config->base + STM32_FDCAN_TXBTIE_OFFSET));
+
+  caninfo("  ILE:   %08" PRIx32 "   ILS:   %08" PRIx32 "\n",
+          getreg32(config->base + STM32_FDCAN_ILE_OFFSET),
+          getreg32(config->base + STM32_FDCAN_ILS_OFFSET));
+
+  caninfo("  TXBC:  %08" PRIx32 "\n",
+          getreg32(config->base + STM32_FDCAN_TXBC_OFFSET));
+}
+#endif
+
+/****************************************************************************
+ * Name: stm32can_dumprxregs
+ *
+ * Description:
+ *   Dump the contents of all Rx status registers
+ *
+ * Input Parameters:
+ *   priv - A reference to the CAN block status
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_STM32_FDCAN_REGDEBUG
+static void fdcan_dumprxregs(FAR struct stm32_fdcan_s *priv,
+                                FAR const char *msg)
+{
+  FAR const struct stm32_config_s *config = priv->config;
+
+  caninfo("CAN%d Rx Registers: %s\n", config->port, msg);
+  caninfo("  Base:  %08" PRIx32 "\n", config->base);
+
+  caninfo("  PSR:   %08" PRIx32 "   ECR:   %08" PRIx32
+          "   HPMS: %08" PRIx32 "\n",
+          getreg32(config->base + STM32_FDCAN_PSR_OFFSET),
+          getreg32(config->base + STM32_FDCAN_ECR_OFFSET),
+          getreg32(config->base + STM32_FDCAN_HPMS_OFFSET));
+
+  caninfo("  RXF0S: %08" PRIx32 "   RXF0A: %08" PRIx32 "\n",
+          getreg32(config->base + STM32_FDCAN_RXF0S_OFFSET),
+          getreg32(config->base + STM32_FDCAN_RXF0A_OFFSET));
+
+  caninfo("  RXF1S: %08" PRIx32 "   RXF1A: %08" PRIx32 "\n",
+          getreg32(config->base + STM32_FDCAN_RXF1S_OFFSET),
+          getreg32(config->base + STM32_FDCAN_RXF1A_OFFSET));
+
+  caninfo("  IR:    %08" PRIx32 "   IE:    %08" PRIx32 "\n",
+          getreg32(config->base + STM32_FDCAN_IR_OFFSET),
+          getreg32(config->base + STM32_FDCAN_IE_OFFSET));
+}
+#endif
+
+/****************************************************************************
+ * Name: stm32can_dumptxregs
+ *
+ * Description:
+ *   Dump the contents of all Tx buffer registers
+ *
+ * Input Parameters:
+ *   priv - A reference to the CAN block status
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_STM32_FDCAN_REGDEBUG
+static void fdcan_dumptxregs(FAR struct stm32_fdcan_s *priv,
+                             FAR const char *msg)
+{
+  FAR const struct stm32_config_s *config = priv->config;
+
+  caninfo("CAN%d Tx Registers: %s\n", config->port, msg);
+  caninfo("  Base:  %08" PRIx32 "\n", config->base);
+
+  caninfo("  PSR:   %08" PRIx32 "   ECR:   %08" PRIx32 "\n",
+          getreg32(config->base + STM32_FDCAN_PSR_OFFSET),
+          getreg32(config->base + STM32_FDCAN_ECR_OFFSET));
+
+  caninfo("  TXQFS: %08" PRIx32 "   TXBAR: %08" PRIx32
+          "   TXBRP: %08" PRIx32 "\n",
+          getreg32(config->base + STM32_FDCAN_TXFQS_OFFSET),
+          getreg32(config->base + STM32_FDCAN_TXBAR_OFFSET),
+          getreg32(config->base + STM32_FDCAN_TXBRP_OFFSET));
+
+  caninfo("  TXBTO: %08" PRIx32 "   TXBCR: %08" PRIx32 "\n",
+          getreg32(config->base + STM32_FDCAN_TXBTO_OFFSET),
+          getreg32(config->base + STM32_FDCAN_TXBCR_OFFSET));
+
+  caninfo("   TXEFS: %08" PRIx32 "   TXEFA: %08" PRIx32 "\n",
+          getreg32(config->base + STM32_FDCAN_TXEFS_OFFSET),
+          getreg32(config->base + STM32_FDCAN_TXEFA_OFFSET));
+
+  caninfo("  IR:    %08" PRIx32 "   IE:    %08" PRIx32
+          "   TIE:   %08" PRIx32 "\n",
+          getreg32(config->base + STM32_FDCAN_IR_OFFSET),
+          getreg32(config->base + STM32_FDCAN_IE_OFFSET),
+          getreg32(config->base + STM32_FDCAN_TXBTIE_OFFSET));
+}
+#endif
+
+/****************************************************************************
+ * Name: stm32can_dumpramlayout
+ *
+ * Description:
+ *   Print the layout of the message RAM
+ *
+ * Input Parameters:
+ *   priv - A reference to the CAN block status
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_STM32_FDCAN_REGDEBUG
+static void fdcan_dumpramlayout(FAR struct stm32_fdcan_s *priv)
+{
+  FAR const struct stm32_config_s *config = priv->config;
+
+  caninfo(" ******* FDCAN%d Message RAM layout *******\n", config->port);
+  caninfo("                Start     # Elmnt  Elmnt size (words)\n");
+
+  if (config->nstdfilters > 0)
+    {
+      caninfo("STD filters   %p   %4d        %2d\n",
+              config->msgram.stdfilters,
+              config->nstdfilters,
+              1);
+    }
+
+  if (config->nextfilters)
+    {
+      caninfo("EXT filters   %p   %4d        %2d\n",
+              config->msgram.extfilters,
+              config->nextfilters,
+              2);
+    }
+
+  if (config->nrxfifo0)
+    {
+      caninfo("RX FIFO 0     %p   %4d        %2d\n",
+              config->msgram.rxfifo0,
+              config->nrxfifo0,
+              config->rxfifo0esize);
+    }
+
+  if (config->nrxfifo1)
+    {
+      caninfo("RX FIFO 1     %p   %4d        %2d\n",
+              config->msgram.rxfifo1,
+              config->nrxfifo1,
+              config->rxfifo1esize);
+    }
+
+  if (config->ntxeventfifo)
+    {
+      caninfo("TX EVENT      %p   %4d        %2d\n",
+              config->msgram.txeventfifo,
+              config->ntxeventfifo,
+              config->txeventesize);
+    }
+
+  if (config->ntxfifoq)
+    {
+      caninfo("TX FIFO       %p   %4d        %2d\n",
+              config->msgram.txfifoq,
+              config->ntxfifoq,
+              config->txbufferesize);
+    }
+}
+#endif
+
+/****************************************************************************
+ * Name: fdcan_dlc2bytes
+ *
+ * Description:
+ *   In the CAN FD format, the coding of the DLC differs from the standard
+ *   CAN format. The DLC codes 0 to 8 have the same coding as in standard
+ *   CAN.  But the codes 9 to 15 all imply a data field of 8 bytes with
+ *   standard CAN.  In CAN FD mode, the values 9 to 15 are encoded to values
+ *   in the range 12 to 64.
+ *
+ * Input Parameters:
+ *   dlc    - the DLC value to convert to a byte count
+ *
+ * Returned Value:
+ *   The number of bytes corresponding to the DLC value.
+ *
+ ****************************************************************************/
+
+static uint8_t fdcan_dlc2bytes(FAR struct stm32_fdcan_s *priv, uint8_t dlc)
+{
+  if (dlc > 8)
+    {
+#ifdef CONFIG_CAN_FD
+      if (priv->config->mode == FDCAN_CLASSIC_MODE)
+        {
+          return 8;
+        }
+      else
+        {
+          switch (dlc)
+            {
+              case 9:
+                return 12;
+              case 10:
+                return 16;
+              case 11:
+                return 20;
+              case 12:
+                return 24;
+              case 13:
+                return 32;
+              case 14:
+                return 48;
+              default:
+              case 15:
+                return 64;
+            }
+        }
+#else
+      return 8;
+#endif
+    }
+
+  return dlc;
+}
+
+/****************************************************************************
+ * Name: fdcan_add_extfilter
+ *
+ * Description:
+ *   Add an address filter for a extended 29 bit address.
+ *
+ * Input Parameters:
+ *   priv      - An instance of the FDCAN driver state structure.
+ *   extconfig - The configuration of the extended filter
+ *
+ * Returned Value:
+ *   A non-negative filter ID is returned on success.  Otherwise a negated
+ *   errno value is returned to indicate the nature of the error.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_CAN_EXTID
+static int fdcan_add_extfilter(FAR struct stm32_fdcan_s *priv,
+                              FAR struct canioc_extfilter_s *extconfig)
+{
+  FAR const struct stm32_config_s *config    = NULL;
+  FAR uint32_t                    *extfilter = NULL;
+  uint32_t                         regval    = 0;
+  int                              word      = 0;
+  int                              bit       = 0;
+  int                              ndx       = 0;
+
+  DEBUGASSERT(priv != NULL && priv->config != NULL && extconfig != NULL);
+  config = priv->config;
+
+  /* Find an unused standard filter */
+
+  for (ndx = 0; ndx <  config->nextfilters; ndx++)
+    {
+      /* Is this filter assigned? */
+
+      word = ndx >> 5;
+      bit  = ndx & 0x1f;
+
+      if ((priv->extfilters[word] & (1 << bit)) == 0)
+        {
+          /* No, assign the filter */
+
+          DEBUGASSERT(priv->nextalloc < priv->config->nstdfilters);
+          priv->extfilters[word] |= (1 << bit);
+          priv->nextalloc++;
+
+          extfilter = config->msgram.extfilters + (ndx << 1);
+
+          /* Format and write filter word F0 */
+
+          DEBUGASSERT(extconfig->xf_id1 <= CAN_MAX_EXTMSGID);
+          regval = EXTFILTER_F0_EFID1(extconfig->xf_id1);
+
+          if (extconfig->xf_prio == 0)
+            {
+              regval |= EXTFILTER_F0_EFEC_FIFO0;
+            }
+          else
+            {
+              regval |= EXTFILTER_F0_EFEC_FIFO0;
+            }
+
+          extfilter[0] = regval;
+
+          /* Format and write filter word F1 */
+
+          DEBUGASSERT(extconfig->xf_id2 <= CAN_MAX_EXTMSGID);
+          regval = EXTFILTER_F1_EFID2(extconfig->xf_id2);
+
+          switch (extconfig->xf_type)
+            {
+              default:
+              case CAN_FILTER_DUAL:
+                regval |= EXTFILTER_F1_EFT_DUAL;
+                break;
+
+              case CAN_FILTER_MASK:
+                regval |= EXTFILTER_F1_EFT_CLASSIC;
+                break;
+              case CAN_FILTER_RANGE:
+                regval |= EXTFILTER_F1_EFT_RANGE;
+                break;
+            }
+
+          extfilter[1] = regval;
+
+          /* Is this the first extended filter? */
+
+          if (priv->nextalloc == 1)
+            {
+              /* Enable the Initialization state */
+
+              regval  = fdcan_getreg(priv, STM32_FDCAN_CCCR_OFFSET);
+              regval |= FDCAN_CCCR_INIT;
+              fdcan_putreg(priv, STM32_FDCAN_CCCR_OFFSET, regval);
+
+              /* Wait for initialization mode to take effect */
+
+              while ((fdcan_getreg(priv, STM32_FDCAN_CCCR_OFFSET) &
+                      FDCAN_CCCR_INIT) == 0);
+
+              /* Enable writing to configuration registers */
+
+              regval  = fdcan_getreg(priv, STM32_FDCAN_CCCR_OFFSET);
+              regval |= (FDCAN_CCCR_INIT | FDCAN_CCCR_CCE);
+              fdcan_putreg(priv, STM32_FDCAN_CCCR_OFFSET, regval);
+
+             /* Update the Global Filter Configuration so that received
+              * messages are rejected if they do not match the acceptance
+              * filter.
+              *
+              *   ANFE=2: Discard all rejected frames
+              */
+
+              regval  = fdcan_getreg(priv, STM32_FDCAN_RXGFC_OFFSET);
+              regval &= ~FDCAN_RXGFC_ANFE_MASK;
+              regval |= FDCAN_RXGFC_ANFE_REJECTED;
+              fdcan_putreg(priv, STM32_FDCAN_RXGFC_OFFSET, regval);
+
+              /* Disable writing to configuration registers */
+
+              regval  = fdcan_getreg(priv, STM32_FDCAN_CCCR_OFFSET);
+              regval &= ~(FDCAN_CCCR_INIT | FDCAN_CCCR_CCE);
+              fdcan_putreg(priv, STM32_FDCAN_CCCR_OFFSET, regval);
+            }
+
+          return ndx;
+        }
+    }
+
+  DEBUGASSERT(priv->nextalloc == priv->config->nextfilters);
+
+  return -EAGAIN;
+}
+#endif
+
+/****************************************************************************
+ * Name: fdcan_del_extfilter
+ *
+ * Description:
+ *   Remove an address filter for a standard 29 bit address.
+ *
+ * Input Parameters:
+ *   priv - An instance of the FDCAN driver state structure.
+ *   ndx  - The filter index previously returned by the
+ *          fdcan_add_extfilter().
+ *
+ * Returned Value:
+ *   Zero (OK) is returned on success.  Otherwise a negated errno value is
+ *   returned to indicate the nature of the error.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_CAN_EXTID
+static int fdcan_del_extfilter(FAR struct stm32_fdcan_s *priv, int ndx)
+{
+  FAR const struct stm32_config_s *config    = NULL;
+  FAR uint32_t                    *extfilter = NULL;
+  uint32_t                         regval    = 0;
+  int                              word      = 0;
+  int                              bit       = 0;
+
+  DEBUGASSERT(priv != NULL && priv->config != NULL);
+  config = priv->config;
+
+  /* Check user Parameters */
+
+  DEBUGASSERT(ndx >= 0 || ndx < config->nextfilters);
+
+  if (ndx < 0 || ndx >= config->nextfilters)
+    {
+      return -EINVAL;
+    }
+
+  word = ndx >> 5;
+  bit  = ndx & 0x1f;
+
+  /* Check if this filter is really assigned */
+
+  if ((priv->extfilters[word] & (1 << bit)) == 0)
+    {
+      /* No, error out */
+
+      return -ENOENT;
+    }
+
+  /* Release the filter */
+
+  priv->extfilters[word] &= ~(1 << bit);
+
+  DEBUGASSERT(priv->nextalloc > 0);
+  priv->nextalloc--;
+
+  /* Was that the last extended filter? */
+
+  if (priv->nextalloc == 0)
+    {
+      /* Enable the Initialization state */
+
+      regval  = fdcan_getreg(priv, STM32_FDCAN_CCCR_OFFSET);
+      regval |= FDCAN_CCCR_INIT;
+      fdcan_putreg(priv, STM32_FDCAN_CCCR_OFFSET, regval);
+
+      /* Wait for initialization mode to take effect */
+
+      while ((fdcan_getreg(priv, STM32_FDCAN_CCCR_OFFSET) &
+             FDCAN_CCCR_INIT) == 0)
+        {
+        }
+
+      /* Enable writing to configuration registers */
+
+      regval  = fdcan_getreg(priv, STM32_FDCAN_CCCR_OFFSET);
+      regval |= (FDCAN_CCCR_INIT | FDCAN_CCCR_CCE);
+      fdcan_putreg(priv, STM32_FDCAN_CCCR_OFFSET, regval);
+
+      /* If there are no extended filters, then modify Global Filter
+       * Configuration so that all rejected messages are places in RX
+       * FIFO0.
+       *
+       *   ANFE=0: Store all rejected extended frame in RX FIFO0
+       */
+
+      regval  = fdcan_getreg(priv, STM32_FDCAN_RXGFC_OFFSET);
+      regval &= ~FDCAN_RXGFC_ANFE_MASK;
+      regval |= FDCAN_RXGFC_ANFE_RX_FIFO0;
+      fdcan_putreg(priv, STM32_FDCAN_RXGFC_OFFSET, regval);
+
+      /* Disable writing to configuration registers */
+
+      regval  = fdcan_getreg(priv, STM32_FDCAN_CCCR_OFFSET);
+      regval &= ~(FDCAN_CCCR_INIT | FDCAN_CCCR_CCE);
+      fdcan_putreg(priv, STM32_FDCAN_CCCR_OFFSET, regval);
+    }
+
+  /* Deactivate the filter last so that no messages are lost. */
+
+  extfilter    = config->msgram.extfilters + (ndx << 1);
+  *extfilter++ = 0;
+  *extfilter   = 0;
+
+  return OK;
+}
+#endif
+
+/****************************************************************************
+ * Name: fdcan_add_stdfilter
+ *
+ * Description:
+ *   Add an address filter for a standard 11 bit address.
+ *
+ * Input Parameters:
+ *   priv      - An instance of the FDCAN driver state structure.
+ *   stdconfig - The configuration of the standard filter
+ *
+ * Returned Value:
+ *   A non-negative filter ID is returned on success.  Otherwise a negated
+ *   errno value is returned to indicate the nature of the error.
+ *
+ ****************************************************************************/
+
+static int fdcan_add_stdfilter(FAR struct stm32_fdcan_s *priv,
+                              FAR struct canioc_stdfilter_s *stdconfig)
+{
+  FAR const struct stm32_config_s *config    = NULL;
+  FAR uint32_t                    *stdfilter = NULL;
+  uint32_t                         regval    = 0;
+  int                              word      = 0;
+  int                              bit       = 0;
+  int                              ndx       = 0;
+
+  DEBUGASSERT(priv != NULL && priv->config != NULL);
+  config = priv->config;
+
+  /* Find an unused standard filter */
+
+  for (ndx = 0; ndx < config->nstdfilters; ndx++)
+    {
+      /* Is this filter assigned? */
+
+      word = ndx >> 5;
+      bit  = ndx & 0x1f;
+
+      if ((priv->stdfilters[word] & (1 << bit)) == 0)
+        {
+          /* No, assign the filter */
+
+          DEBUGASSERT(priv->nstdalloc < priv->config->nstdfilters);
+          priv->stdfilters[word] |= (1 << bit);
+          priv->nstdalloc++;
+
+          /* Format and write filter word S0 */
+
+          stdfilter = config->msgram.stdfilters + ndx;
+
+          DEBUGASSERT(stdconfig->sf_id1 <= CAN_MAX_STDMSGID);
+          regval = STDFILTER_S0_SFID1(stdconfig->sf_id1);
+
+          DEBUGASSERT(stdconfig->sf_id2 <= CAN_MAX_STDMSGID);
+          regval |= STDFILTER_S0_SFID2(stdconfig->sf_id2);
+
+          if (stdconfig->sf_prio == 0)
+            {
+              regval |= STDFILTER_S0_SFEC_FIFO0;
+            }
+          else
+            {
+              regval |= STDFILTER_S0_SFEC_FIFO1;
+            }
+
+          switch (stdconfig->sf_type)
+            {
+              default:
+              case CAN_FILTER_DUAL:
+                regval |= STDFILTER_S0_SFT_DUAL;
+                break;
+
+              case CAN_FILTER_MASK:
+                regval |= STDFILTER_S0_SFT_CLASSIC;
+                break;
+              case CAN_FILTER_RANGE:

Review comment:
       ```suggestion
   
                 case CAN_FILTER_RANGE:
   ```




-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscr...@nuttx.apache.org

For queries about this service, please contact Infrastructure at:
us...@infra.apache.org


Reply via email to