From eaab3a20228506c5b5da35e945d55c9deea6865e Mon Sep 17 00:00:00 2001 From: JacobCrabill Date: Fri, 15 Apr 2022 15:11:52 -0700 Subject: [PATCH 01/43] [BACKPORT] arch/stm32h7: Add FDCAN SocketCAN driver Adds an FDCAN driver for STM32H7 MCUs using the SocketCAN interface --- arch/arm/src/stm32h7/Kconfig | 167 +- arch/arm/src/stm32h7/Make.defs | 4 + arch/arm/src/stm32h7/hardware/stm32_fdcan.h | 1579 ++++++++++++ arch/arm/src/stm32h7/stm32.h | 1 + arch/arm/src/stm32h7/stm32_fdcan_sock.c | 2529 +++++++++++++++++++ arch/arm/src/stm32h7/stm32_fdcan_sock.h | 107 + arch/arm/src/stm32h7/stm32h7x3xx_rcc.c | 8 +- 7 files changed, 4390 insertions(+), 5 deletions(-) create mode 100644 arch/arm/src/stm32h7/hardware/stm32_fdcan.h create mode 100644 arch/arm/src/stm32h7/stm32_fdcan_sock.c create mode 100644 arch/arm/src/stm32h7/stm32_fdcan_sock.h diff --git a/arch/arm/src/stm32h7/Kconfig b/arch/arm/src/stm32h7/Kconfig index 29a9e858180..77ca948017d 100644 --- a/arch/arm/src/stm32h7/Kconfig +++ b/arch/arm/src/stm32h7/Kconfig @@ -17,6 +17,8 @@ config ARCH_CHIP_STM32H743AG select STM32H7_STM32H7X3XX select STM32H7_FLASH_CONFIG_G select STM32H7_IO_CONFIG_A + select STM32H7_HAVE_FDCAN1 + select STM32H7_HAVE_FDCAN2 ---help--- STM32 H7 Cortex M7, 1024 Kb FLASH, 1024K Kb SRAM, UFBGA169 @@ -35,6 +37,8 @@ config ARCH_CHIP_STM32H743BG select STM32H7_STM32H7X3XX select STM32H7_FLASH_CONFIG_G select STM32H7_IO_CONFIG_B + select STM32H7_HAVE_FDCAN1 + select STM32H7_HAVE_FDCAN2 ---help--- STM32 H7 Cortex M7, 1024 Kb FLASH, 1024K Kb SRAM, LQFP208 @@ -44,6 +48,8 @@ config ARCH_CHIP_STM32H743BI select STM32H7_STM32H7X3XX select STM32H7_FLASH_CONFIG_I select STM32H7_IO_CONFIG_B + select STM32H7_HAVE_FDCAN1 + select STM32H7_HAVE_FDCAN2 ---help--- STM32 H7 Cortex M7, 2048 Kb FLASH, 1024K Kb SRAM, LQFP208 @@ -53,6 +59,8 @@ config ARCH_CHIP_STM32H743IG select STM32H7_STM32H7X3XX select STM32H7_FLASH_CONFIG_G select STM32H7_IO_CONFIG_I + select STM32H7_HAVE_FDCAN1 + select STM32H7_HAVE_FDCAN2 ---help--- STM32 H7 Cortex M7, 1024 Kb FLASH, 1024K Kb SRAM, LQFP176 or UFBGA176 @@ -62,6 +70,8 @@ config ARCH_CHIP_STM32H743II select STM32H7_STM32H7X3XX select STM32H7_FLASH_CONFIG_I select STM32H7_IO_CONFIG_I + select STM32H7_HAVE_FDCAN1 + select STM32H7_HAVE_FDCAN2 ---help--- STM32 H7 Cortex M7, 2048 Kb FLASH, 1024K Kb SRAM, LQFP176 or UFBGA176 @@ -71,6 +81,8 @@ config ARCH_CHIP_STM32H743VG select STM32H7_STM32H7X3XX select STM32H7_FLASH_CONFIG_G select STM32H7_IO_CONFIG_V + select STM32H7_HAVE_FDCAN1 + select STM32H7_HAVE_FDCAN2 ---help--- STM32 H7 Cortex M7, 1024 Kb FLASH, 1024K Kb SRAM, LQFP100 or TFBGA100 @@ -80,6 +92,8 @@ config ARCH_CHIP_STM32H743VI select STM32H7_STM32H7X3XX select STM32H7_FLASH_CONFIG_I select STM32H7_IO_CONFIG_V + select STM32H7_HAVE_FDCAN1 + select STM32H7_HAVE_FDCAN2 ---help--- STM32 H7 Cortex M7, 2048 Kb FLASH, 1024K Kb SRAM, LQFP100 or TFBGA100 @@ -89,6 +103,8 @@ config ARCH_CHIP_STM32H743XG select STM32H7_STM32H7X3XX select STM32H7_FLASH_CONFIG_G select STM32H7_IO_CONFIG_X + select STM32H7_HAVE_FDCAN1 + select STM32H7_HAVE_FDCAN2 ---help--- STM32 H7 Cortex M7, 1024 Kb FLASH, 1024K Kb SRAM, TFBGA240 @@ -98,6 +114,8 @@ config ARCH_CHIP_STM32H743XI select STM32H7_STM32H7X3XX select STM32H7_FLASH_CONFIG_I select STM32H7_IO_CONFIG_X + select STM32H7_HAVE_FDCAN1 + select STM32H7_HAVE_FDCAN2 ---help--- STM32 H7 Cortex M7, 2048 Kb FLASH, 1024K Kb SRAM, TFBGA240 @@ -107,6 +125,8 @@ config ARCH_CHIP_STM32H743ZG select STM32H7_STM32H7X3XX select STM32H7_FLASH_CONFIG_G select STM32H7_IO_CONFIG_Z + select STM32H7_HAVE_FDCAN1 + select STM32H7_HAVE_FDCAN2 ---help--- STM32 H7 Cortex M7, 1024 Kb FLASH, 1024K Kb SRAM, LQFP144 @@ -116,6 +136,8 @@ config ARCH_CHIP_STM32H743ZI select STM32H7_STM32H7X3XX select STM32H7_FLASH_CONFIG_I select STM32H7_IO_CONFIG_Z + select STM32H7_HAVE_FDCAN1 + select STM32H7_HAVE_FDCAN2 ---help--- STM32 H7 Cortex M7, 2048 Kb FLASH, 1024K Kb SRAM, LQFP144 @@ -125,6 +147,8 @@ config ARCH_CHIP_STM32H747XI select STM32H7_STM32H7X7XX select STM32H7_FLASH_CONFIG_I select STM32H7_IO_CONFIG_X + select STM32H7_HAVE_FDCAN1 + select STM32H7_HAVE_FDCAN2 ---help--- Dual core STM32 H7 Cortex M7+M4, 2048 Kb FLASH, 1024K Kb SRAM TFBGA240 @@ -134,6 +158,8 @@ config ARCH_CHIP_STM32H753AI select STM32H7_STM32H7X3XX select STM32H7_FLASH_CONFIG_I select STM32H7_IO_CONFIG_A + select STM32H7_HAVE_FDCAN1 + select STM32H7_HAVE_FDCAN2 ---help--- STM32 H7 Cortex M7, 2048 Kb FLASH, 1024K Kb SRAM, with cryptographic accelerator, UFBGA169 @@ -153,6 +179,8 @@ config ARCH_CHIP_STM32H753II select STM32H7_STM32H7X3XX select STM32H7_FLASH_CONFIG_I select STM32H7_IO_CONFIG_I + select STM32H7_HAVE_FDCAN1 + select STM32H7_HAVE_FDCAN2 ---help--- STM32 H7 Cortex M7, 2048 Kb FLASH, 1024K Kb SRAM, with cryptographic accelerator, LQFP176/UFBGA176 @@ -162,6 +190,8 @@ config ARCH_CHIP_STM32H753VI select STM32H7_STM32H7X3XX select STM32H7_FLASH_CONFIG_I select STM32H7_IO_CONFIG_V + select STM32H7_HAVE_FDCAN1 + select STM32H7_HAVE_FDCAN2 ---help--- STM32 H7 Cortex M7, 2048 Kb FLASH, 1024K Kb SRAM, with cryptographic accelerator, LQFP100/TFBGA100 @@ -180,6 +210,8 @@ config ARCH_CHIP_STM32H753ZI select STM32H7_STM32H7X3XX select STM32H7_FLASH_CONFIG_I select STM32H7_IO_CONFIG_Z + select STM32H7_HAVE_FDCAN1 + select STM32H7_HAVE_FDCAN2 ---help--- STM32 H7 Cortex M7, 2048 Kb FLASH, 1024K Kb SRAM, with cryptographic accelerator, LQFP144 @@ -366,6 +398,14 @@ config STM32H7_HAVE_SPI6 bool default n +config STM32H7_HAVE_FDCAN1 + bool + default n + +config STM32H7_HAVE_FDCAN2 + bool + default n + # These "hidden" settings are the OR of individual peripheral selections # indicating that the general capability is required. @@ -373,8 +413,11 @@ config STM32H7_ADC bool default n -config STM32H7_CAN +config STM32H7_FDCAN bool + select NET_CAN_HAVE_CANFD + select NET_CAN_EXTID + select NET_CAN_HAVE_TX_DEADLINE default n config STM32H7_DAC @@ -563,6 +606,18 @@ config STM32H7_WWDG default n select WATCHDOG +config STM32H7_FDCAN1 + bool "FDCAN1" + select STM32H7_FDCAN + default n + depends on STM32H7_HAVE_FDCAN1 + +config STM32H7_FDCAN2 + bool "FDCAN2" + select STM32H7_FDCAN + default n + depends on STM32H7_HAVE_FDCAN2 + menu "STM32H7 I2C Selection" config STM32H7_I2C1 @@ -5275,6 +5330,114 @@ config STM32H7_QENCODER_SAMPLE_EVENT_8 endchoice -endmenu +endmenu # QEncoder Driver + +menu "FDCAN Driver Configuration" + depends on STM32H7_FDCAN1 || STM32H7_FDCAN2 + +menu "FDCAN1 Configuration" + depends on STM32H7_FDCAN1 + +config FDCAN1_BITRATE + int "CAN bitrate" + depends on !NET_CAN_CANFD + default 1000000 + +config FDCAN1_ARBI_BITRATE + int "CAN FD Arbitration phase bitrate" + depends on NET_CAN_CANFD + default 1000000 + +config FDCAN1_DATA_BITRATE + int "CAN FD Data phase bitrate" + depends on NET_CAN_CANFD + default 4000000 + +endmenu # STM32H7_FDCAN1 + +menu "FDCAN2 Configuration" + depends on STM32H7_FDCAN2 + +config FDCAN2_BITRATE + int "CAN bitrate" + depends on !NET_CAN_CANFD + default 1000000 + +config FDCAN2_ARBI_BITRATE + int "CAN FD Arbitration phase bitrate" + depends on NET_CAN_CANFD + default 1000000 + +config FDCAN2_DATA_BITRATE + int "CAN FD Data phase bitrate" + depends on NET_CAN_CANFD + default 4000000 + +endmenu # STM32H7_FDCAN2 + +config STM32H7_FDCAN_REGDEBUG + bool "Enable register dump debugging" + depends on DEBUG_CAN_INFO + depends on DEBUG_NET_INFO + default n + ---help--- + Output detailed register-level CAN device debug information. + Requires also CONFIG_DEBUG_CAN_INFO and CONFIG_DEBUG_NET_INFO. + +config STM32H7_FDCAN_LOOPBACK + bool "Enable FDCAN loopback mode" + default n + ---help--- + Enable the FDCAN local loopback mode for testing purposes. + Requires a further choice of internal or external loopback mode. + + TODO: Enable separately for FDCAN1 and FDCAN2 + +choice + prompt "FDCAN Loopback Mode" + depends on STM32H7_FDCAN_LOOPBACK + default STM32H7_FDCAN_LOOPBACK_INTERNAL + +config STM32H7_FDCAN_LOOPBACK_INTERNAL + bool "Internal loopback mode" + ---help--- + Enable internal loopback mode, where both Tx and Rx are + disconnected from the CAN bus. This can be used for a "Hot Selftest", + meaning the FDCAN can be used without affecting a running CAN bus. + + All transmitted frames are treated as received frames and processed + accordingly. + +config STM32H7_FDCAN_LOOPBACK_EXTERNAL + bool "External loopback mode" + ---help--- + Enable external loopback mode, where the Rx pin is disconnected from + the CAN bus but the Tx pin remains connected. + + All transmitted frames are treated as received frames and processed + accordingly. + +endchoice # CAN Loopback Mode + +choice + prompt "FDCAN WorkQueue Selection" + default STM32H7_FDCAN_LPWORK + +config STM32H7_FDCAN_LPWORK + bool "Use LP work queue" + ---help--- + Use the low-priority (LP) work queue for reception and transmission + of new frames and for processing of transmission timeouts. + +config STM32H7_FDCAN_HPWORK + bool "Use HP work queue" + ---help--- + Use the high-priority (HP) work queue for reception and transmission + of new frames and for processing of transmission timeouts. + +endchoice + +endmenu # FDCAN Driver + endif # ARCH_CHIP_STM32H7 diff --git a/arch/arm/src/stm32h7/Make.defs b/arch/arm/src/stm32h7/Make.defs index ef8ae46728c..f5deae3b45c 100644 --- a/arch/arm/src/stm32h7/Make.defs +++ b/arch/arm/src/stm32h7/Make.defs @@ -107,6 +107,10 @@ ifeq ($(CONFIG_STM32H7_ADC),y) CHIP_CSRCS += stm32_adc.c endif +ifeq ($(CONFIG_STM32H7_FDCAN),y) +CHIP_CSRCS += stm32_fdcan_sock.c +endif + ifeq ($(CONFIG_STM32H7_BBSRAM),y) CHIP_CSRCS += stm32_bbsram.c endif diff --git a/arch/arm/src/stm32h7/hardware/stm32_fdcan.h b/arch/arm/src/stm32h7/hardware/stm32_fdcan.h new file mode 100644 index 00000000000..e7842c01023 --- /dev/null +++ b/arch/arm/src/stm32h7/hardware/stm32_fdcan.h @@ -0,0 +1,1579 @@ +/**************************************************************************** + * arch/arm/src/stm32h7/hardware/stm32_fdcan.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_ARM_SRC_STM32H7_HARDWARE_STM32_FDCAN_H +#define __ARCH_ARM_SRC_STM32H7_HARDWARE_STM32_FDCAN_H + +/* ************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include "chip.h" + +/* ************************************************************************** + * * + * Flexible Datarate Controller Area Network * + * * + ****************************************************************************/ + +/* Register Offsets *********************************************************/ + +#define STM32_FDCAN_CREL_OFFSET 0x0000 /* FDCAN Core Release register */ +#define STM32_FDCAN_ENDN_OFFSET 0x0004 /* FDCAN Endian register */ +#define STM32_FDCAN_DBTP_OFFSET 0x000C /* FDCAN Data Bit Timing & Prescaler register */ +#define STM32_FDCAN_TEST_OFFSET 0x0010 /* FDCAN Test register */ +#define STM32_FDCAN_RWD_OFFSET 0x0014 /* FDCAN RAM Watchdog register */ +#define STM32_FDCAN_CCCR_OFFSET 0x0018 /* FDCAN CC Control register */ +#define STM32_FDCAN_NBTP_OFFSET 0x001C /* FDCAN Nominal Bit Timing & Prescaler register */ +#define STM32_FDCAN_TSCC_OFFSET 0x0020 /* FDCAN Timestamp Counter Configuration register */ +#define STM32_FDCAN_TSCV_OFFSET 0x0024 /* FDCAN Timestamp Counter Value register */ +#define STM32_FDCAN_TOCC_OFFSET 0x0028 /* FDCAN Timeout Counter Configuration register */ +#define STM32_FDCAN_TOCV_OFFSET 0x002C /* FDCAN Timeout Counter Value register */ +#define STM32_FDCAN_ECR_OFFSET 0x0040 /* FDCAN Error Counter register */ +#define STM32_FDCAN_PSR_OFFSET 0x0044 /* FDCAN Protocol Status register */ +#define STM32_FDCAN_TDCR_OFFSET 0x0048 /* FDCAN Transmitter Delay Compensation register */ +#define STM32_FDCAN_IR_OFFSET 0x0050 /* FDCAN Interrupt register */ +#define STM32_FDCAN_IE_OFFSET 0x0054 /* FDCAN Interrupt Enable register */ +#define STM32_FDCAN_ILS_OFFSET 0x0058 /* FDCAN Interrupt Line Select register */ +#define STM32_FDCAN_ILE_OFFSET 0x005C /* FDCAN Interrupt Line Enable register */ +#define STM32_FDCAN_GFC_OFFSET 0x0080 /* FDCAN Global Filter Configuration register */ +#define STM32_FDCAN_SIDFC_OFFSET 0x0084 /* FDCAN Standard ID Filter Configuration register */ +#define STM32_FDCAN_XIDFC_OFFSET 0x0088 /* FDCAN Extended ID Filter Configuration register */ +#define STM32_FDCAN_XIDAM_OFFSET 0x0090 /* FDCAN Extended ID AND Mask register */ +#define STM32_FDCAN_HPMS_OFFSET 0x0094 /* FDCAN High Priority Message Status register */ +#define STM32_FDCAN_NDAT1_OFFSET 0x0098 /* FDCAN New Data 1 register */ +#define STM32_FDCAN_NDAT2_OFFSET 0x009C /* FDCAN New Data 2 register */ +#define STM32_FDCAN_RXF0C_OFFSET 0x00A0 /* FDCAN Rx FIFO 0 Configuration register */ +#define STM32_FDCAN_RXF0S_OFFSET 0x00A4 /* FDCAN Rx FIFO 0 Status register */ +#define STM32_FDCAN_RXF0A_OFFSET 0x00A8 /* FDCAN Rx FIFO 0 Acknowledge register */ +#define STM32_FDCAN_RXBC_OFFSET 0x00AC /* FDCAN Rx Buffer Configuration register */ +#define STM32_FDCAN_RXF1C_OFFSET 0x00B0 /* FDCAN Rx FIFO 1 Configuration register */ +#define STM32_FDCAN_RXF1S_OFFSET 0x00B4 /* FDCAN Rx FIFO 1 Status register */ +#define STM32_FDCAN_RXF1A_OFFSET 0x00B8 /* FDCAN Rx FIFO 1 Acknowledge register */ +#define STM32_FDCAN_RXESC_OFFSET 0x00BC /* FDCAN Rx Buffer/FIFO Element Size Configuration register */ +#define STM32_FDCAN_TXBC_OFFSET 0x00C0 /* FDCAN Tx Buffer Configuration register */ +#define STM32_FDCAN_TXFQS_OFFSET 0x00C4 /* FDCAN Tx FIFO/Queue Status register */ +#define STM32_FDCAN_TXESC_OFFSET 0x00C8 /* FDCAN Tx Buffer Element Size Configuration register */ +#define STM32_FDCAN_TXBRP_OFFSET 0x00CC /* FDCAN Tx Buffer Request Pending register */ +#define STM32_FDCAN_TXBAR_OFFSET 0x00D0 /* FDCAN Tx Buffer Add Request register */ +#define STM32_FDCAN_TXBCR_OFFSET 0x00D4 /* FDCAN Tx Buffer Cancellation Request register */ +#define STM32_FDCAN_TXBTO_OFFSET 0x00D8 /* FDCAN Tx Buffer Transmission Occurred register */ +#define STM32_FDCAN_TXBCF_OFFSET 0x00DC /* FDCAN Tx Buffer Cancellation Finished register */ +#define STM32_FDCAN_TXBTIE_OFFSET 0x00E0 /* FDCAN Tx Buffer Transmission Interrupt Enable register */ +#define STM32_FDCAN_TXBCIE_OFFSET 0x00E4 /* FDCAN Tx Buffer Cancellation Finished Interrupt Enable register */ +#define STM32_FDCAN_TXEFC_OFFSET 0x00F0 /* FDCAN Tx Event FIFO Configuration register */ +#define STM32_FDCAN_TXEFS_OFFSET 0x00F4 /* FDCAN Tx Event FIFO Status register */ +#define STM32_FDCAN_TXEFA_OFFSET 0x00F8 /* FDCAN Tx Event FIFO Acknowledge register */ + +/* Register Addresses *******************************************************/ + +#define STM32_FDCAN1_CREL (STM32_FDCAN1_BASE + STM32_FDCAN_CREL_OFFSET) +#define STM32_FDCAN1_ENDN (STM32_FDCAN1_BASE + STM32_FDCAN_ENDN_OFFSET) +#define STM32_FDCAN1_DBTP (STM32_FDCAN1_BASE + STM32_FDCAN_DBTP_OFFSET) +#define STM32_FDCAN1_TEST (STM32_FDCAN1_BASE + STM32_FDCAN_TEST_OFFSET) +#define STM32_FDCAN1_RWD (STM32_FDCAN1_BASE + STM32_FDCAN_RWD_OFFSET) +#define STM32_FDCAN1_CCCR (STM32_FDCAN1_BASE + STM32_FDCAN_CCCR_OFFSET) +#define STM32_FDCAN1_NBTP (STM32_FDCAN1_BASE + STM32_FDCAN_NBTP_OFFSET) +#define STM32_FDCAN1_TSCC (STM32_FDCAN1_BASE + STM32_FDCAN_TSCC_OFFSET) +#define STM32_FDCAN1_TSCV (STM32_FDCAN1_BASE + STM32_FDCAN_TSCV_OFFSET) +#define STM32_FDCAN1_TOCC (STM32_FDCAN1_BASE + STM32_FDCAN_TOCC_OFFSET) +#define STM32_FDCAN1_TOCV (STM32_FDCAN1_BASE + STM32_FDCAN_TOCV_OFFSET) +#define STM32_FDCAN1_ECR (STM32_FDCAN1_BASE + STM32_FDCAN_ECR_OFFSET) +#define STM32_FDCAN1_PSR (STM32_FDCAN1_BASE + STM32_FDCAN_PSR_OFFSET) +#define STM32_FDCAN1_TDCR (STM32_FDCAN1_BASE + STM32_FDCAN_TDCR_OFFSET) +#define STM32_FDCAN1_IR (STM32_FDCAN1_BASE + STM32_FDCAN_IR_OFFSET) +#define STM32_FDCAN1_IE (STM32_FDCAN1_BASE + STM32_FDCAN_IE_OFFSET) +#define STM32_FDCAN1_ILS (STM32_FDCAN1_BASE + STM32_FDCAN_ILS_OFFSET) +#define STM32_FDCAN1_ILE (STM32_FDCAN1_BASE + STM32_FDCAN_ILE_OFFSET) +#define STM32_FDCAN1_GFC (STM32_FDCAN1_BASE + STM32_FDCAN_GFC_OFFSET) +#define STM32_FDCAN1_SIDFC (STM32_FDCAN1_BASE + STM32_FDCAN_SIDFC_OFFSET) +#define STM32_FDCAN1_XIDFC (STM32_FDCAN1_BASE + STM32_FDCAN_XIDFC_OFFSET) +#define STM32_FDCAN1_XIDAM (STM32_FDCAN1_BASE + STM32_FDCAN_XIDAM_OFFSET) +#define STM32_FDCAN1_HPMS (STM32_FDCAN1_BASE + STM32_FDCAN_HPMS_OFFSET) +#define STM32_FDCAN1_NDAT1 (STM32_FDCAN1_BASE + STM32_FDCAN_NDAT1_OFFSET) +#define STM32_FDCAN1_NDAT2 (STM32_FDCAN1_BASE + STM32_FDCAN_NDAT2_OFFSET) +#define STM32_FDCAN1_RXF0C (STM32_FDCAN1_BASE + STM32_FDCAN_RXF0C_OFFSET) +#define STM32_FDCAN1_RXF0S (STM32_FDCAN1_BASE + STM32_FDCAN_RXF0S_OFFSET) +#define STM32_FDCAN1_RXF0A (STM32_FDCAN1_BASE + STM32_FDCAN_RXF0A_OFFSET) +#define STM32_FDCAN1_RXBC (STM32_FDCAN1_BASE + STM32_FDCAN_RXBC_OFFSET) +#define STM32_FDCAN1_RXF1C (STM32_FDCAN1_BASE + STM32_FDCAN_RXF1C_OFFSET) +#define STM32_FDCAN1_RXF1S (STM32_FDCAN1_BASE + STM32_FDCAN_RXF1S_OFFSET) +#define STM32_FDCAN1_RXF1A (STM32_FDCAN1_BASE + STM32_FDCAN_RXF1A_OFFSET) +#define STM32_FDCAN1_RXESC (STM32_FDCAN1_BASE + STM32_FDCAN_RXESC_OFFSET) +#define STM32_FDCAN1_TXBC (STM32_FDCAN1_BASE + STM32_FDCAN_TXBC_OFFSET) +#define STM32_FDCAN1_TXFQS (STM32_FDCAN1_BASE + STM32_FDCAN_TXFQS_OFFSET) +#define STM32_FDCAN1_TXESC (STM32_FDCAN1_BASE + STM32_FDCAN_TXESC_OFFSET) +#define STM32_FDCAN1_TXBRP (STM32_FDCAN1_BASE + STM32_FDCAN_TXBRP_OFFSET) +#define STM32_FDCAN1_TXBAR (STM32_FDCAN1_BASE + STM32_FDCAN_TXBAR_OFFSET) +#define STM32_FDCAN1_TXBCR (STM32_FDCAN1_BASE + STM32_FDCAN_TXBCR_OFFSET) +#define STM32_FDCAN1_TXBTO (STM32_FDCAN1_BASE + STM32_FDCAN_TXBTO_OFFSET) +#define STM32_FDCAN1_TXBCF (STM32_FDCAN1_BASE + STM32_FDCAN_TXBCF_OFFSET) +#define STM32_FDCAN1_TXBTIE (STM32_FDCAN1_BASE + STM32_FDCAN_TXBTIE_OFFSET) +#define STM32_FDCAN1_TXBCIE (STM32_FDCAN1_BASE + STM32_FDCAN_TXBCIE_OFFSET) +#define STM32_FDCAN1_TXEFC (STM32_FDCAN1_BASE + STM32_FDCAN_TXEFC_OFFSET) +#define STM32_FDCAN1_TXEFS (STM32_FDCAN1_BASE + STM32_FDCAN_TXEFS_OFFSET) +#define STM32_FDCAN1_TXEFA (STM32_FDCAN1_BASE + STM32_FDCAN_TXEFA_OFFSET) + +#define STM32_FDCAN2_CREL (STM32_FDCAN2_BASE + STM32_FDCAN_CREL_OFFSET) +#define STM32_FDCAN2_ENDN (STM32_FDCAN2_BASE + STM32_FDCAN_ENDN_OFFSET) +#define STM32_FDCAN2_DBTP (STM32_FDCAN2_BASE + STM32_FDCAN_DBTP_OFFSET) +#define STM32_FDCAN2_TEST (STM32_FDCAN2_BASE + STM32_FDCAN_TEST_OFFSET) +#define STM32_FDCAN2_RWD (STM32_FDCAN2_BASE + STM32_FDCAN_RWD_OFFSET) +#define STM32_FDCAN2_CCCR (STM32_FDCAN2_BASE + STM32_FDCAN_CCCR_OFFSET) +#define STM32_FDCAN2_NBTP (STM32_FDCAN2_BASE + STM32_FDCAN_NBTP_OFFSET) +#define STM32_FDCAN2_TSCC (STM32_FDCAN2_BASE + STM32_FDCAN_TSCC_OFFSET) +#define STM32_FDCAN2_TSCV (STM32_FDCAN2_BASE + STM32_FDCAN_TSCV_OFFSET) +#define STM32_FDCAN2_TOCC (STM32_FDCAN2_BASE + STM32_FDCAN_TOCC_OFFSET) +#define STM32_FDCAN2_TOCV (STM32_FDCAN2_BASE + STM32_FDCAN_TOCV_OFFSET) +#define STM32_FDCAN2_ECR (STM32_FDCAN2_BASE + STM32_FDCAN_ECR_OFFSET) +#define STM32_FDCAN2_PSR (STM32_FDCAN2_BASE + STM32_FDCAN_PSR_OFFSET) +#define STM32_FDCAN2_TDCR (STM32_FDCAN2_BASE + STM32_FDCAN_TDCR_OFFSET) +#define STM32_FDCAN2_IR (STM32_FDCAN2_BASE + STM32_FDCAN_IR_OFFSET) +#define STM32_FDCAN2_IE (STM32_FDCAN2_BASE + STM32_FDCAN_IE_OFFSET) +#define STM32_FDCAN2_ILS (STM32_FDCAN2_BASE + STM32_FDCAN_ILS_OFFSET) +#define STM32_FDCAN2_ILE (STM32_FDCAN2_BASE + STM32_FDCAN_ILE_OFFSET) +#define STM32_FDCAN2_GFC (STM32_FDCAN2_BASE + STM32_FDCAN_GFC_OFFSET) +#define STM32_FDCAN2_SIDFC (STM32_FDCAN2_BASE + STM32_FDCAN_SIDFC_OFFSET) +#define STM32_FDCAN2_XIDFC (STM32_FDCAN2_BASE + STM32_FDCAN_XIDFC_OFFSET) +#define STM32_FDCAN2_XIDAM (STM32_FDCAN2_BASE + STM32_FDCAN_XIDAM_OFFSET) +#define STM32_FDCAN2_HPMS (STM32_FDCAN2_BASE + STM32_FDCAN_HPMS_OFFSET) +#define STM32_FDCAN2_NDAT1 (STM32_FDCAN2_BASE + STM32_FDCAN_NDAT1_OFFSET) +#define STM32_FDCAN2_NDAT2 (STM32_FDCAN2_BASE + STM32_FDCAN_NDAT2_OFFSET) +#define STM32_FDCAN2_RXF0C (STM32_FDCAN2_BASE + STM32_FDCAN_RXF0C_OFFSET) +#define STM32_FDCAN2_RXF0S (STM32_FDCAN2_BASE + STM32_FDCAN_RXF0S_OFFSET) +#define STM32_FDCAN2_RXF0A (STM32_FDCAN2_BASE + STM32_FDCAN_RXF0A_OFFSET) +#define STM32_FDCAN2_RXBC (STM32_FDCAN2_BASE + STM32_FDCAN_RXBC_OFFSET) +#define STM32_FDCAN2_RXF1C (STM32_FDCAN2_BASE + STM32_FDCAN_RXF1C_OFFSET) +#define STM32_FDCAN2_RXF1S (STM32_FDCAN2_BASE + STM32_FDCAN_RXF1S_OFFSET) +#define STM32_FDCAN2_RXF1A (STM32_FDCAN2_BASE + STM32_FDCAN_RXF1A_OFFSET) +#define STM32_FDCAN2_RXESC (STM32_FDCAN2_BASE + STM32_FDCAN_RXESC_OFFSET) +#define STM32_FDCAN2_TXBC (STM32_FDCAN2_BASE + STM32_FDCAN_TXBC_OFFSET) +#define STM32_FDCAN2_TXFQS (STM32_FDCAN2_BASE + STM32_FDCAN_TXFQS_OFFSET) +#define STM32_FDCAN2_TXESC (STM32_FDCAN2_BASE + STM32_FDCAN_TXESC_OFFSET) +#define STM32_FDCAN2_TXBRP (STM32_FDCAN2_BASE + STM32_FDCAN_TXBRP_OFFSET) +#define STM32_FDCAN2_TXBAR (STM32_FDCAN2_BASE + STM32_FDCAN_TXBAR_OFFSET) +#define STM32_FDCAN2_TXBCR (STM32_FDCAN2_BASE + STM32_FDCAN_TXBCR_OFFSET) +#define STM32_FDCAN2_TXBTO (STM32_FDCAN2_BASE + STM32_FDCAN_TXBTO_OFFSET) +#define STM32_FDCAN2_TXBCF (STM32_FDCAN2_BASE + STM32_FDCAN_TXBCF_OFFSET) +#define STM32_FDCAN2_TXBTIE (STM32_FDCAN2_BASE + STM32_FDCAN_TXBTIE_OFFSET) +#define STM32_FDCAN2_TXBCIE (STM32_FDCAN2_BASE + STM32_FDCAN_TXBCIE_OFFSET) +#define STM32_FDCAN2_TXEFC (STM32_FDCAN2_BASE + STM32_FDCAN_TXEFC_OFFSET) +#define STM32_FDCAN2_TXEFS (STM32_FDCAN2_BASE + STM32_FDCAN_TXEFS_OFFSET) +#define STM32_FDCAN2_TXEFA (STM32_FDCAN2_BASE + STM32_FDCAN_TXEFA_OFFSET) + +/* FDCAN control and status registers */ +#define FDCAN_CREL_DAY_SHIFT (0U) +#define FDCAN_CREL_DAY_MASK (0xFFU << FDCAN_CREL_DAY_SHIFT) /* 0x000000FF */ +#define FDCAN_CREL_DAY FDCAN_CREL_DAY_MASK /* Timestamp Day */ +#define FDCAN_CREL_MON_SHIFT (8U) +#define FDCAN_CREL_MON_MASK (0xFFU << FDCAN_CREL_MON_SHIFT) /* 0x0000FF00 */ +#define FDCAN_CREL_MON FDCAN_CREL_MON_MASK /* Timestamp Month */ +#define FDCAN_CREL_YEAR_SHIFT (16U) +#define FDCAN_CREL_YEAR_MASK (0xFU << FDCAN_CREL_YEAR_SHIFT) /* 0x000F0000 */ +#define FDCAN_CREL_YEAR FDCAN_CREL_YEAR_MASK /* Timestamp Year */ +#define FDCAN_CREL_SUBSTEP_SHIFT (20U) +#define FDCAN_CREL_SUBSTEP_MASK (0xFU << FDCAN_CREL_SUBSTEP_SHIFT) /* 0x00F00000 */ +#define FDCAN_CREL_SUBSTEP FDCAN_CREL_SUBSTEP_MASK /* Sub-step of Core release */ +#define FDCAN_CREL_STEP_SHIFT (24U) +#define FDCAN_CREL_STEP_MASK (0xFU << FDCAN_CREL_STEP_SHIFT) /* 0x0F000000 */ +#define FDCAN_CREL_STEP FDCAN_CREL_STEP_MASK /* Step of Core release */ +#define FDCAN_CREL_REL_SHIFT (28U) +#define FDCAN_CREL_REL_MASK (0xFU << FDCAN_CREL_REL_SHIFT) /* 0xF0000000 */ +#define FDCAN_CREL_REL FDCAN_CREL_REL_MASK /* Core release */ + +/* *************** Bit definition for FDCAN_ENDN register *****************/ +#define FDCAN_ENDN_ETV_SHIFT (0U) +#define FDCAN_ENDN_ETV_MASK (0xFFFFFFFFU << FDCAN_ENDN_ETV_SHIFT) /* 0xFFFFFFFF */ +#define FDCAN_ENDN_ETV FDCAN_ENDN_ETV_MASK /* Endiannes Test Value */ + +/* *************** Bit definition for FDCAN_DBTP register *****************/ +#define FDCAN_DBTP_DSJW_SHIFT (0U) +#define FDCAN_DBTP_DSJW_MASK (0xFU << FDCAN_DBTP_DSJW_SHIFT) /* 0x0000000F */ +#define FDCAN_DBTP_DSJW FDCAN_DBTP_DSJW_MASK /* Synchronization Jump Width */ +#define FDCAN_DBTP_DTSEG2_SHIFT (4U) +#define FDCAN_DBTP_DTSEG2_MASK (0xFU << FDCAN_DBTP_DTSEG2_SHIFT) /* 0x000000F0 */ +#define FDCAN_DBTP_DTSEG2 FDCAN_DBTP_DTSEG2_MASK /* Data time segment after sample point */ +#define FDCAN_DBTP_DTSEG1_SHIFT (8U) +#define FDCAN_DBTP_DTSEG1_MASK (0xFU << FDCAN_DBTP_DTSEG1_SHIFT) /* 0x00000F00 */ +#define FDCAN_DBTP_DTSEG1 FDCAN_DBTP_DTSEG1_MASK /* Data time segment before sample point */ +#define FDCAN_DBTP_DBRP_SHIFT (16U) +#define FDCAN_DBTP_DBRP_MASK (0x1FU << FDCAN_DBTP_DBRP_SHIFT) /* 0x001F0000 */ +#define FDCAN_DBTP_DBRP FDCAN_DBTP_DBRP_MASK /* Data BIt Rate Prescaler */ +#define FDCAN_DBTP_TDC_SHIFT (23U) +#define FDCAN_DBTP_TDC_MASK (0x1U << FDCAN_DBTP_TDC_SHIFT) /* 0x00800000 */ +#define FDCAN_DBTP_TDC FDCAN_DBTP_TDC_MASK /* Transceiver Delay Compensation */ + +/* *************** Bit definition for FDCAN_TEST register *****************/ +#define FDCAN_TEST_LBCK_SHIFT (4U) +#define FDCAN_TEST_LBCK_MASK (0x1U << FDCAN_TEST_LBCK_SHIFT) /* 0x00000010 */ +#define FDCAN_TEST_LBCK FDCAN_TEST_LBCK_MASK /* Loop Back mode */ +#define FDCAN_TEST_TX_SHIFT (5U) +#define FDCAN_TEST_TX_MASK (0x3U << FDCAN_TEST_TX_SHIFT) /* 0x00000060 */ +#define FDCAN_TEST_TX FDCAN_TEST_TX_MASK /* Control of Transmit Pin */ +#define FDCAN_TEST_RX_SHIFT (7U) +#define FDCAN_TEST_RX_MASK (0x1U << FDCAN_TEST_RX_SHIFT) /* 0x00000080 */ +#define FDCAN_TEST_RX FDCAN_TEST_RX_MASK /* Receive Pin */ + +/* *************** Bit definition for FDCAN_RWD register ******************/ +#define FDCAN_RWD_WDC_SHIFT (0U) +#define FDCAN_RWD_WDC_MASK (0xFU << FDCAN_RWD_WDC_SHIFT) /* 0x0000000F */ +#define FDCAN_RWD_WDC FDCAN_RWD_WDC_MASK /* Watchdog configuration */ +#define FDCAN_RWD_WDV_SHIFT (4U) +#define FDCAN_RWD_WDV_MASK (0xFU << FDCAN_RWD_WDV_SHIFT) /* 0x000000F0 */ +#define FDCAN_RWD_WDV FDCAN_RWD_WDV_MASK /* Watchdog value */ + +/* *************** Bit definition for FDCAN_CCCR register *****************/ +#define FDCAN_CCCR_INIT_SHIFT (0U) +#define FDCAN_CCCR_INIT_MASK (0x1U << FDCAN_CCCR_INIT_SHIFT) /* 0x00000001 */ +#define FDCAN_CCCR_INIT FDCAN_CCCR_INIT_MASK /* Initialization */ +#define FDCAN_CCCR_CCE_SHIFT (1U) +#define FDCAN_CCCR_CCE_MASK (0x1U << FDCAN_CCCR_CCE_SHIFT) /* 0x00000002 */ +#define FDCAN_CCCR_CCE FDCAN_CCCR_CCE_MASK /* Configuration Change Enable */ +#define FDCAN_CCCR_ASM_SHIFT (2U) +#define FDCAN_CCCR_ASM_MASK (0x1U << FDCAN_CCCR_ASM_SHIFT) /* 0x00000004 */ +#define FDCAN_CCCR_ASM FDCAN_CCCR_ASM_MASK /* ASM Restricted Operation Mode */ +#define FDCAN_CCCR_CSA_SHIFT (3U) +#define FDCAN_CCCR_CSA_MASK (0x1U << FDCAN_CCCR_CSA_SHIFT) /* 0x00000008 */ +#define FDCAN_CCCR_CSA FDCAN_CCCR_CSA_MASK /* Clock Stop Acknowledge */ +#define FDCAN_CCCR_CSR_SHIFT (4U) +#define FDCAN_CCCR_CSR_MASK (0x1U << FDCAN_CCCR_CSR_SHIFT) /* 0x00000010 */ +#define FDCAN_CCCR_CSR FDCAN_CCCR_CSR_MASK /* Clock Stop Request */ +#define FDCAN_CCCR_MON_SHIFT (5U) +#define FDCAN_CCCR_MON_MASK (0x1U << FDCAN_CCCR_MON_SHIFT) /* 0x00000020 */ +#define FDCAN_CCCR_MON FDCAN_CCCR_MON_MASK /* Bus Monitoring Mode */ +#define FDCAN_CCCR_DAR_SHIFT (6U) +#define FDCAN_CCCR_DAR_MASK (0x1U << FDCAN_CCCR_DAR_SHIFT) /* 0x00000040 */ +#define FDCAN_CCCR_DAR FDCAN_CCCR_DAR_MASK /* Disable Automatic Retransmission */ +#define FDCAN_CCCR_TEST_SHIFT (7U) +#define FDCAN_CCCR_TEST_MASK (0x1U << FDCAN_CCCR_TEST_SHIFT) /* 0x00000080 */ +#define FDCAN_CCCR_TEST FDCAN_CCCR_TEST_MASK /* Test Mode Enable */ +#define FDCAN_CCCR_FDOE_SHIFT (8U) +#define FDCAN_CCCR_FDOE_MASK (0x1U << FDCAN_CCCR_FDOE_SHIFT) /* 0x00000100 */ +#define FDCAN_CCCR_FDOE FDCAN_CCCR_FDOE_MASK /* FD Operation Enable */ +#define FDCAN_CCCR_BRSE_SHIFT (9U) +#define FDCAN_CCCR_BRSE_MASK (0x1U << FDCAN_CCCR_BRSE_SHIFT) /* 0x00000200 */ +#define FDCAN_CCCR_BRSE FDCAN_CCCR_BRSE_MASK /* FDCAN Bit Rate Switching */ +#define FDCAN_CCCR_PXHD_SHIFT (12U) +#define FDCAN_CCCR_PXHD_MASK (0x1U << FDCAN_CCCR_PXHD_SHIFT) /* 0x00001000 */ +#define FDCAN_CCCR_PXHD FDCAN_CCCR_PXHD_MASK /* Protocol Exception Handling Disable */ +#define FDCAN_CCCR_EFBI_SHIFT (13U) +#define FDCAN_CCCR_EFBI_MASK (0x1U << FDCAN_CCCR_EFBI_SHIFT) /* 0x00002000 */ +#define FDCAN_CCCR_EFBI FDCAN_CCCR_EFBI_MASK /* Edge Filtering during Bus Integration */ +#define FDCAN_CCCR_TXP_SHIFT (14U) +#define FDCAN_CCCR_TXP_MASK (0x1U << FDCAN_CCCR_TXP_SHIFT) /* 0x00004000 */ +#define FDCAN_CCCR_TXP FDCAN_CCCR_TXP_MASK /* Two CAN bit times Pause */ +#define FDCAN_CCCR_NISO_SHIFT (15U) +#define FDCAN_CCCR_NISO_MASK (0x1U << FDCAN_CCCR_NISO_SHIFT) /* 0x00008000 */ +#define FDCAN_CCCR_NISO FDCAN_CCCR_NISO_MASK /* Non ISO Operation */ + +/* *************** Bit definition for FDCAN_NBTP register *****************/ +#define FDCAN_NBTP_TSEG2_SHIFT (0U) +#define FDCAN_NBTP_TSEG2_MASK (0x7FU << FDCAN_NBTP_TSEG2_SHIFT) /* 0x0000007F */ +#define FDCAN_NBTP_TSEG2 FDCAN_NBTP_TSEG2_MASK /* Nominal Time segment after sample point */ +#define FDCAN_NBTP_NTSEG1_SHIFT (8U) +#define FDCAN_NBTP_NTSEG1_MASK (0xFFU << FDCAN_NBTP_NTSEG1_SHIFT) /* 0x0000FF00 */ +#define FDCAN_NBTP_NTSEG1 FDCAN_NBTP_NTSEG1_MASK /* Nominal Time segment before sample point */ +#define FDCAN_NBTP_NBRP_SHIFT (16U) +#define FDCAN_NBTP_NBRP_MASK (0x1FFU << FDCAN_NBTP_NBRP_SHIFT) /* 0x01FF0000 */ +#define FDCAN_NBTP_NBRP FDCAN_NBTP_NBRP_MASK /* Bit Rate Prescaler */ +#define FDCAN_NBTP_NSJW_SHIFT (25U) +#define FDCAN_NBTP_NSJW_MASK (0x7FU << FDCAN_NBTP_NSJW_SHIFT) /* 0xFE000000 */ +#define FDCAN_NBTP_NSJW FDCAN_NBTP_NSJW_MASK /* Nominal (Re)Synchronization Jump Width */ + +/* *************** Bit definition for FDCAN_TSCC register *****************/ +#define FDCAN_TSCC_TSS_SHIFT (0U) +#define FDCAN_TSCC_TSS_MASK (0x3U << FDCAN_TSCC_TSS_SHIFT) /* 0x00000003 */ +#define FDCAN_TSCC_TSS FDCAN_TSCC_TSS_MASK /* Timestamp Select */ +#define FDCAN_TSCC_TCP_SHIFT (16U) +#define FDCAN_TSCC_TCP_MASK (0xFU << FDCAN_TSCC_TCP_SHIFT) /* 0x000F0000 */ +#define FDCAN_TSCC_TCP FDCAN_TSCC_TCP_MASK /* Timestamp Counter Prescaler */ + +/* *************** Bit definition for FDCAN_TSCV register *****************/ +#define FDCAN_TSCV_TSC_SHIFT (0U) +#define FDCAN_TSCV_TSC_MASK (0xFFFFU << FDCAN_TSCV_TSC_SHIFT) /* 0x0000FFFF */ +#define FDCAN_TSCV_TSC FDCAN_TSCV_TSC_MASK /* Timestamp Counter */ + +/* *************** Bit definition for FDCAN_TOCC register *****************/ +#define FDCAN_TOCC_ETOC_SHIFT (0U) +#define FDCAN_TOCC_ETOC_MASK (0x1U << FDCAN_TOCC_ETOC_SHIFT) /* 0x00000001 */ +#define FDCAN_TOCC_ETOC FDCAN_TOCC_ETOC_MASK /* Enable Timeout Counter */ +#define FDCAN_TOCC_TOS_SHIFT (1U) +#define FDCAN_TOCC_TOS_MASK (0x3U << FDCAN_TOCC_TOS_SHIFT) /* 0x00000006 */ +#define FDCAN_TOCC_TOS FDCAN_TOCC_TOS_MASK /* Timeout Select */ +#define FDCAN_TOCC_TOP_SHIFT (16U) +#define FDCAN_TOCC_TOP_MASK (0xFFFFU << FDCAN_TOCC_TOP_SHIFT) /* 0xFFFF0000 */ +#define FDCAN_TOCC_TOP FDCAN_TOCC_TOP_MASK /* Timeout Period */ + +/* *************** Bit definition for FDCAN_TOCV register *****************/ +#define FDCAN_TOCV_TOC_SHIFT (0U) +#define FDCAN_TOCV_TOC_MASK (0xFFFFU << FDCAN_TOCV_TOC_SHIFT) /* 0x0000FFFF */ +#define FDCAN_TOCV_TOC FDCAN_TOCV_TOC_MASK /* Timeout Counter */ + +/* *************** Bit definition for FDCAN_ECR register ******************/ +#define FDCAN_ECR_TEC_SHIFT (0U) +#define FDCAN_ECR_TEC_MASK (0xFU << FDCAN_ECR_TEC_SHIFT) /* 0x0000000F */ +#define FDCAN_ECR_TEC FDCAN_ECR_TEC_MASK /* Transmit Error Counter */ +#define FDCAN_ECR_TREC_SHIFT (8U) +#define FDCAN_ECR_TREC_MASK (0x7FU << FDCAN_ECR_TREC_SHIFT) /* 0x00007F00 */ +#define FDCAN_ECR_TREC FDCAN_ECR_TREC_MASK /* Receive Error Counter */ +#define FDCAN_ECR_RP_SHIFT (15U) +#define FDCAN_ECR_RP_MASK (0 x1U << FDCAN_ECR_RP_SHIFT) /* 0x00008000 */ +#define FDCAN_ECR_RP FDCAN_ECR_RP_MASK /* Receive Error Passive */ +#define FDCAN_ECR_CEL_SHIFT (16U) +#define FDCAN_ECR_CEL_MASK (0xFFU << FDCAN_ECR_CEL_SHIFT) /* 0x00FF0000 */ +#define FDCAN_ECR_CEL FDCAN_ECR_CEL_MASK /* CAN Error Logging */ + +/* *************** Bit definition for FDCAN_PSR register ******************/ +#define FDCAN_PSR_LEC_SHIFT (0U) +#define FDCAN_PSR_LEC_MASK (0x7U << FDCAN_PSR_LEC_SHIFT) /* 0x00000007 */ +#define FDCAN_PSR_LEC FDCAN_PSR_LEC_MASK /* Last Error Code */ +#define FDCAN_PSR_ACT_SHIFT (3U) +#define FDCAN_PSR_ACT_MASK (0x3U << FDCAN_PSR_ACT_SHIFT) /* 0x00000018 */ +#define FDCAN_PSR_ACT FDCAN_PSR_ACT_MASK /* Activity */ +#define FDCAN_PSR_EP_SHIFT (5U) +#define FDCAN_PSR_EP_MASK (0x1U << FDCAN_PSR_EP_SHIFT) /* 0x00000020 */ +#define FDCAN_PSR_EP FDCAN_PSR_EP_MASK /* Error Passive */ +#define FDCAN_PSR_EW_SHIFT (6U) +#define FDCAN_PSR_EW_MASK (0x1U << FDCAN_PSR_EW_SHIFT) /* 0x00000040 */ +#define FDCAN_PSR_EW FDCAN_PSR_EW_MASK /* Warning Status */ +#define FDCAN_PSR_BO_SHIFT (7U) +#define FDCAN_PSR_BO_MASK (0x1U << FDCAN_PSR_BO_SHIFT) /* 0x00000080 */ +#define FDCAN_PSR_BO FDCAN_PSR_BO_MASK /* Bus_Off Status */ +#define FDCAN_PSR_DLEC_SHIFT (8U) +#define FDCAN_PSR_DLEC_MASK (0x7U << FDCAN_PSR_DLEC_SHIFT) /* 0x00000700 */ +#define FDCAN_PSR_DLEC FDCAN_PSR_DLEC_MASK /* Data Last Error Code */ +#define FDCAN_PSR_RESI_SHIFT (11U) +#define FDCAN_PSR_RESI_MASK (0x1U << FDCAN_PSR_RESI_SHIFT) /* 0x00000800 */ +#define FDCAN_PSR_RESI FDCAN_PSR_RESI_MASK /* ESI flag of last received FDCAN Message */ +#define FDCAN_PSR_RBRS_SHIFT (12U) +#define FDCAN_PSR_RBRS_MASK (0x1U << FDCAN_PSR_RBRS_SHIFT) /* 0x00001000 */ +#define FDCAN_PSR_RBRS FDCAN_PSR_RBRS_MASK /* BRS flag of last received FDCAN Message */ +#define FDCAN_PSR_REDL_SHIFT (13U) +#define FDCAN_PSR_REDL_MASK (0x1U << FDCAN_PSR_REDL_SHIFT) /* 0x00002000 */ +#define FDCAN_PSR_REDL FDCAN_PSR_REDL_MASK /* Received FDCAN Message */ +#define FDCAN_PSR_PXE_SHIFT (14U) +#define FDCAN_PSR_PXE_MASK (0x1U << FDCAN_PSR_PXE_SHIFT) /* 0x00004000 */ +#define FDCAN_PSR_PXE FDCAN_PSR_PXE_MASK /* Protocol Exception Event */ +#define FDCAN_PSR_TDCV_SHIFT (16U) +#define FDCAN_PSR_TDCV_MASK (0x7FU << FDCAN_PSR_TDCV_SHIFT) /* 0x007F0000 */ +#define FDCAN_PSR_TDCV FDCAN_PSR_TDCV_MASK /* Transmitter Delay Compensation Value */ + +/* *************** Bit definition for FDCAN_TDCR register *****************/ +#define FDCAN_TDCR_TDCF_SHIFT (0U) +#define FDCAN_TDCR_TDCF_MASK (0x7FU << FDCAN_TDCR_TDCF_SHIFT) /* 0x0000007F */ +#define FDCAN_TDCR_TDCF FDCAN_TDCR_TDCF_MASK /* Transmitter Delay Compensation Filter */ +#define FDCAN_TDCR_TDCO_SHIFT (8U) +#define FDCAN_TDCR_TDCO_MASK (0x7FU << FDCAN_TDCR_TDCO_SHIFT) /* 0x00007F00 */ +#define FDCAN_TDCR_TDCO FDCAN_TDCR_TDCO_MASK /* Transmitter Delay Compensation Offset */ + +/* *************** Bit definition for FDCAN_IR register *******************/ +#define FDCAN_IR_RF0N_SHIFT (0U) +#define FDCAN_IR_RF0N_MASK (0x1U << FDCAN_IR_RF0N_SHIFT) /* 0x00000001 */ +#define FDCAN_IR_RF0N FDCAN_IR_RF0N_MASK /* Rx FIFO 0 New Message */ +#define FDCAN_IR_RF0W_SHIFT (1U) +#define FDCAN_IR_RF0W_MASK (0x1U << FDCAN_IR_RF0W_SHIFT) /* 0x00000002 */ +#define FDCAN_IR_RF0W FDCAN_IR_RF0W_MASK /* Rx FIFO 0 Watermark Reached */ +#define FDCAN_IR_RF0F_SHIFT (2U) +#define FDCAN_IR_RF0F_MASK (0x1U << FDCAN_IR_RF0F_SHIFT) /* 0x00000004 */ +#define FDCAN_IR_RF0F FDCAN_IR_RF0F_MASK /* Rx FIFO 0 Full */ +#define FDCAN_IR_RF0L_SHIFT (3U) +#define FDCAN_IR_RF0L_MASK (0x1U << FDCAN_IR_RF0L_SHIFT) /* 0x00000008 */ +#define FDCAN_IR_RF0L FDCAN_IR_RF0L_MASK /* Rx FIFO 0 Message Lost */ +#define FDCAN_IR_RF1N_SHIFT (4U) +#define FDCAN_IR_RF1N_MASK (0x1U << FDCAN_IR_RF1N_SHIFT) /* 0x00000010 */ +#define FDCAN_IR_RF1N FDCAN_IR_RF1N_MASK /* Rx FIFO 1 New Message */ +#define FDCAN_IR_RF1W_SHIFT (5U) +#define FDCAN_IR_RF1W_MASK (0x1U << FDCAN_IR_RF1W_SHIFT) /* 0x00000020 */ +#define FDCAN_IR_RF1W FDCAN_IR_RF1W_MASK /* Rx FIFO 1 Watermark Reached */ +#define FDCAN_IR_RF1F_SHIFT (6U) +#define FDCAN_IR_RF1F_MASK (0x1U << FDCAN_IR_RF1F_SHIFT) /* 0x00000040 */ +#define FDCAN_IR_RF1F FDCAN_IR_RF1F_MASK /* Rx FIFO 1 Full */ +#define FDCAN_IR_RF1L_SHIFT (7U) +#define FDCAN_IR_RF1L_MASK (0x1U << FDCAN_IR_RF1L_SHIFT) /* 0x00000080 */ +#define FDCAN_IR_RF1L FDCAN_IR_RF1L_MASK /* Rx FIFO 1 Message Lost */ +#define FDCAN_IR_HPM_SHIFT (8U) +#define FDCAN_IR_HPM_MASK (0x1U << FDCAN_IR_HPM_SHIFT) /* 0x00000100 */ +#define FDCAN_IR_HPM FDCAN_IR_HPM_MASK /* High Priority Message */ +#define FDCAN_IR_TC_SHIFT (9U) +#define FDCAN_IR_TC_MASK (0x1U << FDCAN_IR_TC_SHIFT) /* 0x00000200 */ +#define FDCAN_IR_TC FDCAN_IR_TC_MASK /* Transmission Completed */ +#define FDCAN_IR_TCF_SHIFT (10U) +#define FDCAN_IR_TCF_MASK (0x1U << FDCAN_IR_TCF_SHIFT) /* 0x00000400 */ +#define FDCAN_IR_TCF FDCAN_IR_TCF_MASK /* Transmission Cancellation Finished */ +#define FDCAN_IR_TFE_SHIFT (11U) +#define FDCAN_IR_TFE_MASK (0x1U << FDCAN_IR_TFE_SHIFT) /* 0x00000800 */ +#define FDCAN_IR_TFE FDCAN_IR_TFE_MASK /* Tx FIFO Empty */ +#define FDCAN_IR_TEFN_SHIFT (12U) +#define FDCAN_IR_TEFN_MASK (0x1U << FDCAN_IR_TEFN_SHIFT) /* 0x00001000 */ +#define FDCAN_IR_TEFN FDCAN_IR_TEFN_MASK /* Tx Event FIFO New Entry */ +#define FDCAN_IR_TEFW_SHIFT (13U) +#define FDCAN_IR_TEFW_MASK (0x1U << FDCAN_IR_TEFW_SHIFT) /* 0x00002000 */ +#define FDCAN_IR_TEFW FDCAN_IR_TEFW_MASK /* Tx Event FIFO Watermark Reached */ +#define FDCAN_IR_TEFF_SHIFT (14U) +#define FDCAN_IR_TEFF_MASK (0x1U << FDCAN_IR_TEFF_SHIFT) /* 0x00004000 */ +#define FDCAN_IR_TEFF FDCAN_IR_TEFF_MASK /* Tx Event FIFO Full */ +#define FDCAN_IR_TEFL_SHIFT (15U) +#define FDCAN_IR_TEFL_MASK (0x1U << FDCAN_IR_TEFL_SHIFT) /* 0x00008000 */ +#define FDCAN_IR_TEFL FDCAN_IR_TEFL_MASK /* Tx Event FIFO Element Lost */ +#define FDCAN_IR_TSW_SHIFT (16U) +#define FDCAN_IR_TSW_MASK (0x1U << FDCAN_IR_TSW_SHIFT) /* 0x00010000 */ +#define FDCAN_IR_TSW FDCAN_IR_TSW_MASK /* Timestamp Wraparound */ +#define FDCAN_IR_MRAF_SHIFT (17U) +#define FDCAN_IR_MRAF_MASK (0x1U << FDCAN_IR_MRAF_SHIFT) /* 0x00020000 */ +#define FDCAN_IR_MRAF FDCAN_IR_MRAF_MASK /* Message RAM Access Failure */ +#define FDCAN_IR_TOO_SHIFT (18U) +#define FDCAN_IR_TOO_MASK (0x1U << FDCAN_IR_TOO_SHIFT) /* 0x00040000 */ +#define FDCAN_IR_TOO FDCAN_IR_TOO_MASK /* Timeout Occurred */ +#define FDCAN_IR_DRX_SHIFT (19U) +#define FDCAN_IR_DRX_MASK (0x1U << FDCAN_IR_DRX_SHIFT) /* 0x00080000 */ +#define FDCAN_IR_DRX FDCAN_IR_DRX_MASK /* Message stored to Dedicated Rx Buffer */ +#define FDCAN_IR_ELO_SHIFT (22U) +#define FDCAN_IR_ELO_MASK (0x1U << FDCAN_IR_ELO_SHIFT) /* 0x00400000 */ +#define FDCAN_IR_ELO FDCAN_IR_ELO_MASK /* Error Logging Overflow */ +#define FDCAN_IR_EP_SHIFT (23U) +#define FDCAN_IR_EP_MASK (0x1U << FDCAN_IR_EP_SHIFT) /* 0x00800000 */ +#define FDCAN_IR_EP FDCAN_IR_EP_MASK /* Error Passive */ +#define FDCAN_IR_EW_SHIFT (24U) +#define FDCAN_IR_EW_MASK (0x1U << FDCAN_IR_EW_SHIFT) /* 0x01000000 */ +#define FDCAN_IR_EW FDCAN_IR_EW_MASK /* Warning Status */ +#define FDCAN_IR_BO_SHIFT (25U) +#define FDCAN_IR_BO_MASK (0x1U << FDCAN_IR_BO_SHIFT) /* 0x02000000 */ +#define FDCAN_IR_BO FDCAN_IR_BO_MASK /* Bus_Off Status */ +#define FDCAN_IR_WDI_SHIFT (26U) +#define FDCAN_IR_WDI_MASK (0x1U << FDCAN_IR_WDI_SHIFT) /* 0x04000000 */ +#define FDCAN_IR_WDI FDCAN_IR_WDI_MASK /* Watchdog Interrupt */ +#define FDCAN_IR_PEA_SHIFT (27U) +#define FDCAN_IR_PEA_MASK (0x1U << FDCAN_IR_PEA_SHIFT) /* 0x08000000 */ +#define FDCAN_IR_PEA FDCAN_IR_PEA_MASK /* Protocol Error in Arbitration Phase */ +#define FDCAN_IR_PED_SHIFT (28U) +#define FDCAN_IR_PED_MASK (0x1U << FDCAN_IR_PED_SHIFT) /* 0x10000000 */ +#define FDCAN_IR_PED FDCAN_IR_PED_MASK /* Protocol Error in Data Phase */ +#define FDCAN_IR_ARA_SHIFT (29U) +#define FDCAN_IR_ARA_MASK (0x1U << FDCAN_IR_ARA_SHIFT) /* 0x20000000 */ +#define FDCAN_IR_ARA FDCAN_IR_ARA_MASK /* Access to Reserved Address */ + +/* *************** Bit definition for FDCAN_IE register *******************/ +#define FDCAN_IE_RF0NE_SHIFT (0U) +#define FDCAN_IE_RF0NE_MASK (0x1U << FDCAN_IE_RF0NE_SHIFT) /* 0x00000001 */ +#define FDCAN_IE_RF0NE FDCAN_IE_RF0NE_MASK /* Rx FIFO 0 New Message Enable */ +#define FDCAN_IE_RF0WE_SHIFT (1U) +#define FDCAN_IE_RF0WE_MASK (0x1U << FDCAN_IE_RF0WE_SHIFT) /* 0x00000002 */ +#define FDCAN_IE_RF0WE FDCAN_IE_RF0WE_MASK /* Rx FIFO 0 Watermark Reached Enable */ +#define FDCAN_IE_RF0FE_SHIFT (2U) +#define FDCAN_IE_RF0FE_MASK (0x1U << FDCAN_IE_RF0FE_SHIFT) /* 0x00000004 */ +#define FDCAN_IE_RF0FE FDCAN_IE_RF0FE_MASK /* Rx FIFO 0 Full Enable */ +#define FDCAN_IE_RF0LE_SHIFT (3U) +#define FDCAN_IE_RF0LE_MASK (0x1U << FDCAN_IE_RF0LE_SHIFT) /* 0x00000008 */ +#define FDCAN_IE_RF0LE FDCAN_IE_RF0LE_MASK /* Rx FIFO 0 Message Lost Enable */ +#define FDCAN_IE_RF1NE_SHIFT (4U) +#define FDCAN_IE_RF1NE_MASK (0x1U << FDCAN_IE_RF1NE_SHIFT) /* 0x00000010 */ +#define FDCAN_IE_RF1NE FDCAN_IE_RF1NE_MASK /* Rx FIFO 1 New Message Enable */ +#define FDCAN_IE_RF1WE_SHIFT (5U) +#define FDCAN_IE_RF1WE_MASK (0x1U << FDCAN_IE_RF1WE_SHIFT) /* 0x00000020 */ +#define FDCAN_IE_RF1WE FDCAN_IE_RF1WE_MASK /* Rx FIFO 1 Watermark Reached Enable */ +#define FDCAN_IE_RF1FE_SHIFT (6U) +#define FDCAN_IE_RF1FE_MASK (0x1U << FDCAN_IE_RF1FE_SHIFT) /* 0x00000040 */ +#define FDCAN_IE_RF1FE FDCAN_IE_RF1FE_MASK /* Rx FIFO 1 Full Enable */ +#define FDCAN_IE_RF1LE_SHIFT (7U) +#define FDCAN_IE_RF1LE_MASK (0x1U << FDCAN_IE_RF1LE_SHIFT) /* 0x00000080 */ +#define FDCAN_IE_RF1LE FDCAN_IE_RF1LE_MASK /* Rx FIFO 1 Message Lost Enable */ +#define FDCAN_IE_HPME_SHIFT (8U) +#define FDCAN_IE_HPME_MASK (0x1U << FDCAN_IE_HPME_SHIFT) /* 0x00000100 */ +#define FDCAN_IE_HPME FDCAN_IE_HPME_MASK /* High Priority Message Enable */ +#define FDCAN_IE_TCE_SHIFT (9U) +#define FDCAN_IE_TCE_MASK (0x1U << FDCAN_IE_TCE_SHIFT) /* 0x00000200 */ +#define FDCAN_IE_TCE FDCAN_IE_TCE_MASK /* Transmission Completed Enable */ +#define FDCAN_IE_TCFE_SHIFT (10U) +#define FDCAN_IE_TCFE_MASK (0x1U << FDCAN_IE_TCFE_SHIFT) /* 0x00000400 */ +#define FDCAN_IE_TCFE FDCAN_IE_TCFE_MASK /* Transmission Cancellation Finished Enable */ +#define FDCAN_IE_TFEE_SHIFT (11U) +#define FDCAN_IE_TFEE_MASK (0x1U << FDCAN_IE_TFEE_SHIFT) /* 0x00000800 */ +#define FDCAN_IE_TFEE FDCAN_IE_TFEE_MASK /* Tx FIFO Empty Enable */ +#define FDCAN_IE_TEFNE_SHIFT (12U) +#define FDCAN_IE_TEFNE_MASK (0x1U << FDCAN_IE_TEFNE_SHIFT) /* 0x00001000 */ +#define FDCAN_IE_TEFNE FDCAN_IE_TEFNE_MASK /* Tx Event FIFO New Entry Enable */ +#define FDCAN_IE_TEFWE_SHIFT (13U) +#define FDCAN_IE_TEFWE_MASK (0x1U << FDCAN_IE_TEFWE_SHIFT) /* 0x00002000 */ +#define FDCAN_IE_TEFWE FDCAN_IE_TEFWE_MASK /* Tx Event FIFO Watermark Reached Enable */ +#define FDCAN_IE_TEFFE_SHIFT (14U) +#define FDCAN_IE_TEFFE_MASK (0x1U << FDCAN_IE_TEFFE_SHIFT) /* 0x00004000 */ +#define FDCAN_IE_TEFFE FDCAN_IE_TEFFE_MASK /* Tx Event FIFO Full Enable */ +#define FDCAN_IE_TEFLE_SHIFT (15U) +#define FDCAN_IE_TEFLE_MASK (0x1U << FDCAN_IE_TEFLE_SHIFT) /* 0x00008000 */ +#define FDCAN_IE_TEFLE FDCAN_IE_TEFLE_MASK /* Tx Event FIFO Element Lost Enable */ +#define FDCAN_IE_TSWE_SHIFT (16U) +#define FDCAN_IE_TSWE_MASK (0x1U << FDCAN_IE_TSWE_SHIFT) /* 0x00010000 */ +#define FDCAN_IE_TSWE FDCAN_IE_TSWE_MASK /* Timestamp Wraparound Enable */ +#define FDCAN_IE_MRAFE_SHIFT (17U) +#define FDCAN_IE_MRAFE_MASK (0x1U << FDCAN_IE_MRAFE_SHIFT) /* 0x00020000 */ +#define FDCAN_IE_MRAFE FDCAN_IE_MRAFE_MASK /* Message RAM Access Failure Enable */ +#define FDCAN_IE_TOOE_SHIFT (18U) +#define FDCAN_IE_TOOE_MASK (0x1U << FDCAN_IE_TOOE_SHIFT) /* 0x00040000 */ +#define FDCAN_IE_TOOE FDCAN_IE_TOOE_MASK /* Timeout Occurred Enable */ +#define FDCAN_IE_DRXE_SHIFT (19U) +#define FDCAN_IE_DRXE_MASK (0x1U << FDCAN_IE_DRXE_SHIFT) /* 0x00080000 */ +#define FDCAN_IE_DRXE FDCAN_IE_DRXE_MASK /* Message stored to Dedicated Rx Buffer Enable */ +#define FDCAN_IE_BECE_SHIFT (20U) +#define FDCAN_IE_BECE_MASK (0x1U << FDCAN_IE_BECE_SHIFT) /* 0x00100000 */ +#define FDCAN_IE_BECE FDCAN_IE_BECE_MASK /* Bit Error Corrected Interrupt Enable */ +#define FDCAN_IE_BEUE_SHIFT (21U) +#define FDCAN_IE_BEUE_MASK (0x1U << FDCAN_IE_BEUE_SHIFT) /* 0x00200000 */ +#define FDCAN_IE_BEUE FDCAN_IE_BEUE_MASK /* Bit Error Uncorrected Interrupt Enable */ +#define FDCAN_IE_ELOE_SHIFT (22U) +#define FDCAN_IE_ELOE_MASK (0x1U << FDCAN_IE_ELOE_SHIFT) /* 0x00400000 */ +#define FDCAN_IE_ELOE FDCAN_IE_ELOE_MASK /* Error Logging Overflow Enable */ +#define FDCAN_IE_EPE_SHIFT (23U) +#define FDCAN_IE_EPE_MASK (0x1U << FDCAN_IE_EPE_SHIFT) /* 0x00800000 */ +#define FDCAN_IE_EPE FDCAN_IE_EPE_MASK /* Error Passive Enable */ +#define FDCAN_IE_EWE_SHIFT (24U) +#define FDCAN_IE_EWE_MASK (0x1U << FDCAN_IE_EWE_SHIFT) /* 0x01000000 */ +#define FDCAN_IE_EWE FDCAN_IE_EWE_MASK /* Warning Status Enable */ +#define FDCAN_IE_BOE_SHIFT (25U) +#define FDCAN_IE_BOE_MASK (0x1U << FDCAN_IE_BOE_SHIFT) /* 0x02000000 */ +#define FDCAN_IE_BOE FDCAN_IE_BOE_MASK /* Bus_Off Status Enable */ +#define FDCAN_IE_WDIE_SHIFT (26U) +#define FDCAN_IE_WDIE_MASK (0x1U << FDCAN_IE_WDIE_SHIFT) /* 0x04000000 */ +#define FDCAN_IE_WDIE FDCAN_IE_WDIE_MASK /* Watchdog Interrupt Enable */ +#define FDCAN_IE_PEAE_SHIFT (27U) +#define FDCAN_IE_PEAE_MASK (0x1U << FDCAN_IE_PEAE_SHIFT) /* 0x08000000 */ +#define FDCAN_IE_PEAE FDCAN_IE_PEAE_MASK /* Protocol Error in Arbitration Phase Enable */ +#define FDCAN_IE_PEDE_SHIFT (28U) +#define FDCAN_IE_PEDE_MASK (0x1U << FDCAN_IE_PEDE_SHIFT) /* 0x10000000 */ +#define FDCAN_IE_PEDE FDCAN_IE_PEDE_MASK /* Protocol Error in Data Phase Enable */ +#define FDCAN_IE_ARAE_SHIFT (29U) +#define FDCAN_IE_ARAE_MASK (0x1U << FDCAN_IE_ARAE_SHIFT) /* 0x20000000 */ +#define FDCAN_IE_ARAE FDCAN_IE_ARAE_MASK /* Access to Reserved Address Enable */ + +/* *************** Bit definition for FDCAN_ILS register ******************/ +#define FDCAN_ILS_RF0NL_SHIFT (0U) +#define FDCAN_ILS_RF0NL_MASK (0x1U << FDCAN_ILS_RF0NL_SHIFT) /* 0x00000001 */ +#define FDCAN_ILS_RF0NL FDCAN_ILS_RF0NL_MASK /* Rx FIFO 0 New Message Line */ +#define FDCAN_ILS_RF0WL_SHIFT (1U) +#define FDCAN_ILS_RF0WL_MASK (0x1U << FDCAN_ILS_RF0WL_SHIFT) /* 0x00000002 */ +#define FDCAN_ILS_RF0WL FDCAN_ILS_RF0WL_MASK /* Rx FIFO 0 Watermark Reached Line */ +#define FDCAN_ILS_RF0FL_SHIFT (2U) +#define FDCAN_ILS_RF0FL_MASK (0x1U << FDCAN_ILS_RF0FL_SHIFT) /* 0x00000004 */ +#define FDCAN_ILS_RF0FL FDCAN_ILS_RF0FL_MASK /* Rx FIFO 0 Full Line */ +#define FDCAN_ILS_RF0LL_SHIFT (3U) +#define FDCAN_ILS_RF0LL_MASK (0x1U << FDCAN_ILS_RF0LL_SHIFT) /* 0x00000008 */ +#define FDCAN_ILS_RF0LL FDCAN_ILS_RF0LL_MASK /* Rx FIFO 0 Message Lost Line */ +#define FDCAN_ILS_RF1NL_SHIFT (4U) +#define FDCAN_ILS_RF1NL_MASK (0x1U << FDCAN_ILS_RF1NL_SHIFT) /* 0x00000010 */ +#define FDCAN_ILS_RF1NL FDCAN_ILS_RF1NL_MASK /* Rx FIFO 1 New Message Line */ +#define FDCAN_ILS_RF1WL_SHIFT (5U) +#define FDCAN_ILS_RF1WL_MASK (0x1U << FDCAN_ILS_RF1WL_SHIFT) /* 0x00000020 */ +#define FDCAN_ILS_RF1WL FDCAN_ILS_RF1WL_MASK /* Rx FIFO 1 Watermark Reached Line */ +#define FDCAN_ILS_RF1FL_SHIFT (6U) +#define FDCAN_ILS_RF1FL_MASK (0x1U << FDCAN_ILS_RF1FL_SHIFT) /* 0x00000040 */ +#define FDCAN_ILS_RF1FL FDCAN_ILS_RF1FL_MASK /* Rx FIFO 1 Full Line */ +#define FDCAN_ILS_RF1LL_SHIFT (7U) +#define FDCAN_ILS_RF1LL_MASK (0x1U << FDCAN_ILS_RF1LL_SHIFT) /* 0x00000080 */ +#define FDCAN_ILS_RF1LL FDCAN_ILS_RF1LL_MASK /* Rx FIFO 1 Message Lost Line */ +#define FDCAN_ILS_HPML_SHIFT (8U) +#define FDCAN_ILS_HPML_MASK (0x1U << FDCAN_ILS_HPML_SHIFT) /* 0x00000100 */ +#define FDCAN_ILS_HPML FDCAN_ILS_HPML_MASK /* High Priority Message Line */ +#define FDCAN_ILS_TCL_SHIFT (9U) +#define FDCAN_ILS_TCL_MASK (0x1U << FDCAN_ILS_TCL_SHIFT) /* 0x00000200 */ +#define FDCAN_ILS_TCL FDCAN_ILS_TCL_MASK /* Transmission Completed Line */ +#define FDCAN_ILS_TCFL_SHIFT (10U) +#define FDCAN_ILS_TCFL_MASK (0x1U << FDCAN_ILS_TCFL_SHIFT) /* 0x00000400 */ +#define FDCAN_ILS_TCFL FDCAN_ILS_TCFL_MASK /* Transmission Cancellation Finished Line */ +#define FDCAN_ILS_TFEL_SHIFT (11U) +#define FDCAN_ILS_TFEL_MASK (0x1U << FDCAN_ILS_TFEL_SHIFT) /* 0x00000800 */ +#define FDCAN_ILS_TFEL FDCAN_ILS_TFEL_MASK /* Tx FIFO Empty Line */ +#define FDCAN_ILS_TEFNL_SHIFT (12U) +#define FDCAN_ILS_TEFNL_MASK (0x1U << FDCAN_ILS_TEFNL_SHIFT) /* 0x00001000 */ +#define FDCAN_ILS_TEFNL FDCAN_ILS_TEFNL_MASK /* Tx Event FIFO New Entry Line */ +#define FDCAN_ILS_TEFWL_SHIFT (13U) +#define FDCAN_ILS_TEFWL_MASK (0x1U << FDCAN_ILS_TEFWL_SHIFT) /* 0x00002000 */ +#define FDCAN_ILS_TEFWL FDCAN_ILS_TEFWL_MASK /* Tx Event FIFO Watermark Reached Line */ +#define FDCAN_ILS_TEFFL_SHIFT (14U) +#define FDCAN_ILS_TEFFL_MASK (0x1U << FDCAN_ILS_TEFFL_SHIFT) /* 0x00004000 */ +#define FDCAN_ILS_TEFFL FDCAN_ILS_TEFFL_MASK /* Tx Event FIFO Full Line */ +#define FDCAN_ILS_TEFLL_SHIFT (15U) +#define FDCAN_ILS_TEFLL_MASK (0x1U << FDCAN_ILS_TEFLL_SHIFT) /* 0x00008000 */ +#define FDCAN_ILS_TEFLL FDCAN_ILS_TEFLL_MASK /* Tx Event FIFO Element Lost Line */ +#define FDCAN_ILS_TSWL_SHIFT (16U) +#define FDCAN_ILS_TSWL_MASK (0x1U << FDCAN_ILS_TSWL_SHIFT) /* 0x00010000 */ +#define FDCAN_ILS_TSWL FDCAN_ILS_TSWL_MASK /* Timestamp Wraparound Line */ +#define FDCAN_ILS_MRAFE_SHIFT (17U) +#define FDCAN_ILS_MRAFE_MASK (0x1U << FDCAN_ILS_MRAFE_SHIFT) /* 0x00020000 */ +#define FDCAN_ILS_MRAFE FDCAN_ILS_MRAFE_MASK /* Message RAM Access Failure Line */ +#define FDCAN_ILS_TOOE_SHIFT (18U) +#define FDCAN_ILS_TOOE_MASK (0x1U << FDCAN_ILS_TOOE_SHIFT) /* 0x00040000 */ +#define FDCAN_ILS_TOOE FDCAN_ILS_TOOE_MASK /* Timeout Occurred Line */ +#define FDCAN_ILS_DRXE_SHIFT (19U) +#define FDCAN_ILS_DRXE_MASK (0x1U << FDCAN_ILS_DRXE_SHIFT) /* 0x00080000 */ +#define FDCAN_ILS_DRXE FDCAN_ILS_DRXE_MASK /* Message stored to Dedicated Rx Buffer Line */ +#define FDCAN_ILS_BECE_SHIFT (20U) +#define FDCAN_ILS_BECE_MASK (0x1U << FDCAN_ILS_BECE_SHIFT) /* 0x00100000 */ +#define FDCAN_ILS_BECE FDCAN_ILS_BECE_MASK /* Bit Error Corrected Interrupt Line */ +#define FDCAN_ILS_BEUE_SHIFT (21U) +#define FDCAN_ILS_BEUE_MASK (0x1U << FDCAN_ILS_BEUE_SHIFT) /* 0x00200000 */ +#define FDCAN_ILS_BEUE FDCAN_ILS_BEUE_MASK /* Bit Error Uncorrected Interrupt Line */ +#define FDCAN_ILS_ELOE_SHIFT (22U) +#define FDCAN_ILS_ELOE_MASK (0x1U << FDCAN_ILS_ELOE_SHIFT) /* 0x00400000 */ +#define FDCAN_ILS_ELOE FDCAN_ILS_ELOE_MASK /* Error Logging Overflow Line */ +#define FDCAN_ILS_EPE_SHIFT (23U) +#define FDCAN_ILS_EPE_MASK (0x1U << FDCAN_ILS_EPE_SHIFT) /* 0x00800000 */ +#define FDCAN_ILS_EPE FDCAN_ILS_EPE_MASK /* Error Passive Line */ +#define FDCAN_ILS_EWE_SHIFT (24U) +#define FDCAN_ILS_EWE_MASK (0x1U << FDCAN_ILS_EWE_SHIFT) /* 0x01000000 */ +#define FDCAN_ILS_EWE FDCAN_ILS_EWE_MASK /* Warning Status Line */ +#define FDCAN_ILS_BOE_SHIFT (25U) +#define FDCAN_ILS_BOE_MASK (0x1U << FDCAN_ILS_BOE_SHIFT) /* 0x02000000 */ +#define FDCAN_ILS_BOE FDCAN_ILS_BOE_MASK /* Bus_Off Status Line */ +#define FDCAN_ILS_WDIE_SHIFT (26U) +#define FDCAN_ILS_WDIE_MASK (0x1U << FDCAN_ILS_WDIE_SHIFT) /* 0x04000000 */ +#define FDCAN_ILS_WDIE FDCAN_ILS_WDIE_MASK /* Watchdog Interrupt Line */ +#define FDCAN_ILS_PEAE_SHIFT (27U) +#define FDCAN_ILS_PEAE_MASK (0x1U << FDCAN_ILS_PEAE_SHIFT) /* 0x08000000 */ +#define FDCAN_ILS_PEAE FDCAN_ILS_PEAE_MASK /* Protocol Error in Arbitration Phase Line */ +#define FDCAN_ILS_PEDE_SHIFT (28U) +#define FDCAN_ILS_PEDE_MASK (0x1U << FDCAN_ILS_PEDE_SHIFT) /* 0x10000000 */ +#define FDCAN_ILS_PEDE FDCAN_ILS_PEDE_MASK /* Protocol Error in Data Phase Line */ +#define FDCAN_ILS_ARAE_SHIFT (29U) +#define FDCAN_ILS_ARAE_MASK (0x1U << FDCAN_ILS_ARAE_SHIFT) /* 0x20000000 */ +#define FDCAN_ILS_ARAE FDCAN_ILS_ARAE_MASK /* Access to Reserved Address Line */ + +/* *************** Bit definition for FDCAN_ILE register ******************/ +#define FDCAN_ILE_EINT0_SHIFT (0U) +#define FDCAN_ILE_EINT0_MASK (0x1U << FDCAN_ILE_EINT0_SHIFT) /* 0x00000001 */ +#define FDCAN_ILE_EINT0 FDCAN_ILE_EINT0_MASK /* Enable Interrupt Line 0 */ +#define FDCAN_ILE_EINT1_SHIFT (1U) +#define FDCAN_ILE_EINT1_MASK (0x1U << FDCAN_ILE_EINT1_SHIFT) /* 0x00000002 */ +#define FDCAN_ILE_EINT1 FDCAN_ILE_EINT1_MASK /* Enable Interrupt Line 1 */ + +/* *************** Bit definition for FDCAN_GFC register ******************/ +#define FDCAN_GFC_RRFE_SHIFT (0U) +#define FDCAN_GFC_RRFE_MASK (0x1U << FDCAN_GFC_RRFE_SHIFT) /* 0x00000001 */ +#define FDCAN_GFC_RRFE FDCAN_GFC_RRFE_MASK /* Reject Remote Frames Extended */ +#define FDCAN_GFC_RRFS_SHIFT (1U) +#define FDCAN_GFC_RRFS_MASK (0x1U << FDCAN_GFC_RRFS_SHIFT) /* 0x00000002 */ +#define FDCAN_GFC_RRFS FDCAN_GFC_RRFS_MASK /* Reject Remote Frames Standard */ +#define FDCAN_GFC_ANFE_SHIFT (2U) +#define FDCAN_GFC_ANFE_MASK (0x3U << FDCAN_GFC_ANFE_SHIFT) /* 0x0000000C */ +#define FDCAN_GFC_ANFE FDCAN_GFC_ANFE_MASK /* Accept Non-matching Frames Extended */ +#define FDCAN_GFC_ANFS_SHIFT (4U) +#define FDCAN_GFC_ANFS_MASK (0x3U << FDCAN_GFC_ANFS_SHIFT) /* 0x00000030 */ +#define FDCAN_GFC_ANFS FDCAN_GFC_ANFS_MASK /* Accept Non-matching Frames Standard */ + +/* *************** Bit definition for FDCAN_SIDFC register ****************/ +#define FDCAN_SIDFC_FLSSA_SHIFT (2U) +#define FDCAN_SIDFC_FLSSA_MASK (0x3FFFU << FDCAN_SIDFC_FLSSA_SHIFT) /* 0x0000FFFC */ +#define FDCAN_SIDFC_FLSSA FDCAN_SIDFC_FLSSA_MASK /* Filter List Standard Start Address */ +#define FDCAN_SIDFC_LSS_SHIFT (16U) +#define FDCAN_SIDFC_LSS_MASK (0xFFU << FDCAN_SIDFC_LSS_SHIFT) /* 0x00FF0000 */ +#define FDCAN_SIDFC_LSS FDCAN_SIDFC_LSS_MASK /* List Size Standard */ + +/* *************** Bit definition for FDCAN_XIDFC register ****************/ +#define FDCAN_XIDFC_FLESA_SHIFT (2U) +#define FDCAN_XIDFC_FLESA_MASK (0x3FFFU << FDCAN_XIDFC_FLESA_SHIFT) /* 0x0000FFFC */ +#define FDCAN_XIDFC_FLESA FDCAN_XIDFC_FLESA_MASK /* Filter List Standard Start Address */ +#define FDCAN_XIDFC_LSE_SHIFT (16U) +#define FDCAN_XIDFC_LSE_MASK (0xFFU << FDCAN_XIDFC_LSE_SHIFT) /* 0x00FF0000 */ +#define FDCAN_XIDFC_LSE FDCAN_XIDFC_LSE_MASK /* List Size Extended */ + +/* *************** Bit definition for FDCAN_XIDAM register ****************/ +#define FDCAN_XIDAM_EIDM_SHIFT (0U) +#define FDCAN_XIDAM_EIDM_MASK (0x1FFFFFFFU << FDCAN_XIDAM_EIDM_SHIFT) /* 0x1FFFFFFF */ +#define FDCAN_XIDAM_EIDM FDCAN_XIDAM_EIDM_MASK /* Extended ID Mask */ + +/* *************** Bit definition for FDCAN_HPMS register *****************/ +#define FDCAN_HPMS_BIDX_SHIFT (0U) +#define FDCAN_HPMS_BIDX_MASK (0x3FU << FDCAN_HPMS_BIDX_SHIFT) /* 0x0000003F */ +#define FDCAN_HPMS_BIDX FDCAN_HPMS_BIDX_MASK /* Buffer Index */ +#define FDCAN_HPMS_MSI_SHIFT (6U) +#define FDCAN_HPMS_MSI_MASK (0x3U << FDCAN_HPMS_MSI_SHIFT) /* 0x000000C0 */ +#define FDCAN_HPMS_MSI FDCAN_HPMS_MSI_MASK /* Message Storage Indicator */ +#define FDCAN_HPMS_FIDX_SHIFT (8U) +#define FDCAN_HPMS_FIDX_MASK (0x7FU << FDCAN_HPMS_FIDX_SHIFT) /* 0x00007F00 */ +#define FDCAN_HPMS_FIDX FDCAN_HPMS_FIDX_MASK /* Filter Index */ +#define FDCAN_HPMS_FLST_SHIFT (15U) +#define FDCAN_HPMS_FLST_MASK (0x1U << FDCAN_HPMS_FLST_SHIFT) /* 0x00008000 */ +#define FDCAN_HPMS_FLST FDCAN_HPMS_FLST_MASK /* Filter List */ + +/* *************** Bit definition for FDCAN_NDAT1 register ****************/ +#define FDCAN_NDAT1_ND0_SHIFT (0U) +#define FDCAN_NDAT1_ND0_MASK (0x1U << FDCAN_NDAT1_ND0_SHIFT) /* 0x00000001 */ +#define FDCAN_NDAT1_ND0 FDCAN_NDAT1_ND0_MASK /* New Data flag of Rx Buffer 0 */ +#define FDCAN_NDAT1_ND1_SHIFT (1U) +#define FDCAN_NDAT1_ND1_MASK (0x1U << FDCAN_NDAT1_ND1_SHIFT) /* 0x00000002 */ +#define FDCAN_NDAT1_ND1 FDCAN_NDAT1_ND1_MASK /* New Data flag of Rx Buffer 1 */ +#define FDCAN_NDAT1_ND2_SHIFT (2U) +#define FDCAN_NDAT1_ND2_MASK (0x1U << FDCAN_NDAT1_ND2_SHIFT) /* 0x00000004 */ +#define FDCAN_NDAT1_ND2 FDCAN_NDAT1_ND2_MASK /* New Data flag of Rx Buffer 2 */ +#define FDCAN_NDAT1_ND3_SHIFT (3U) +#define FDCAN_NDAT1_ND3_MASK (0x1U << FDCAN_NDAT1_ND3_SHIFT) /* 0x00000008 */ +#define FDCAN_NDAT1_ND3 FDCAN_NDAT1_ND3_MASK /* New Data flag of Rx Buffer 3 */ +#define FDCAN_NDAT1_ND4_SHIFT (4U) +#define FDCAN_NDAT1_ND4_MASK (0x1U << FDCAN_NDAT1_ND4_SHIFT) /* 0x00000010 */ +#define FDCAN_NDAT1_ND4 FDCAN_NDAT1_ND4_MASK /* New Data flag of Rx Buffer 4 */ +#define FDCAN_NDAT1_ND5_SHIFT (5U) +#define FDCAN_NDAT1_ND5_MASK (0x1U << FDCAN_NDAT1_ND5_SHIFT) /* 0x00000020 */ +#define FDCAN_NDAT1_ND5 FDCAN_NDAT1_ND5_MASK /* New Data flag of Rx Buffer 5 */ +#define FDCAN_NDAT1_ND6_SHIFT (6U) +#define FDCAN_NDAT1_ND6_MASK (0x1U << FDCAN_NDAT1_ND6_SHIFT) /* 0x00000040 */ +#define FDCAN_NDAT1_ND6 FDCAN_NDAT1_ND6_MASK /* New Data flag of Rx Buffer 6 */ +#define FDCAN_NDAT1_ND7_SHIFT (7U) +#define FDCAN_NDAT1_ND7_MASK (0x1U << FDCAN_NDAT1_ND7_SHIFT) /* 0x00000080 */ +#define FDCAN_NDAT1_ND7 FDCAN_NDAT1_ND7_MASK /* New Data flag of Rx Buffer 7 */ +#define FDCAN_NDAT1_ND8_SHIFT (8U) +#define FDCAN_NDAT1_ND8_MASK (0x1U << FDCAN_NDAT1_ND8_SHIFT) /* 0x00000100 */ +#define FDCAN_NDAT1_ND8 FDCAN_NDAT1_ND8_MASK /* New Data flag of Rx Buffer 8 */ +#define FDCAN_NDAT1_ND9_SHIFT (9U) +#define FDCAN_NDAT1_ND9_MASK (0x1U << FDCAN_NDAT1_ND9_SHIFT) /* 0x00000200 */ +#define FDCAN_NDAT1_ND9 FDCAN_NDAT1_ND9_MASK /* New Data flag of Rx Buffer 9 */ +#define FDCAN_NDAT1_ND10_SHIFT (10U) +#define FDCAN_NDAT1_ND10_MASK (0x1U << FDCAN_NDAT1_ND10_SHIFT) /* 0x00000400 */ +#define FDCAN_NDAT1_ND10 FDCAN_NDAT1_ND10_MASK /* New Data flag of Rx Buffer 10 */ +#define FDCAN_NDAT1_ND11_SHIFT (11U) +#define FDCAN_NDAT1_ND11_MASK (0x1U << FDCAN_NDAT1_ND11_SHIFT) /* 0x00000800 */ +#define FDCAN_NDAT1_ND11 FDCAN_NDAT1_ND11_MASK /* New Data flag of Rx Buffer 11 */ +#define FDCAN_NDAT1_ND12_SHIFT (12U) +#define FDCAN_NDAT1_ND12_MASK (0x1U << FDCAN_NDAT1_ND12_SHIFT) /* 0x00001000 */ +#define FDCAN_NDAT1_ND12 FDCAN_NDAT1_ND12_MASK /* New Data flag of Rx Buffer 12 */ +#define FDCAN_NDAT1_ND13_SHIFT (13U) +#define FDCAN_NDAT1_ND13_MASK (0x1U << FDCAN_NDAT1_ND13_SHIFT) /* 0x00002000 */ +#define FDCAN_NDAT1_ND13 FDCAN_NDAT1_ND13_MASK /* New Data flag of Rx Buffer 13 */ +#define FDCAN_NDAT1_ND14_SHIFT (14U) +#define FDCAN_NDAT1_ND14_MASK (0x1U << FDCAN_NDAT1_ND14_SHIFT) /* 0x00004000 */ +#define FDCAN_NDAT1_ND14 FDCAN_NDAT1_ND14_MASK /* New Data flag of Rx Buffer 14 */ +#define FDCAN_NDAT1_ND15_SHIFT (15U) +#define FDCAN_NDAT1_ND15_MASK (0x1U << FDCAN_NDAT1_ND15_SHIFT) /* 0x00008000 */ +#define FDCAN_NDAT1_ND15 FDCAN_NDAT1_ND15_MASK /* New Data flag of Rx Buffer 15 */ +#define FDCAN_NDAT1_ND16_SHIFT (16U) +#define FDCAN_NDAT1_ND16_MASK (0x1U << FDCAN_NDAT1_ND16_SHIFT) /* 0x00010000 */ +#define FDCAN_NDAT1_ND16 FDCAN_NDAT1_ND16_MASK /* New Data flag of Rx Buffer 16 */ +#define FDCAN_NDAT1_ND17_SHIFT (17U) +#define FDCAN_NDAT1_ND17_MASK (0x1U << FDCAN_NDAT1_ND17_SHIFT) /* 0x00020000 */ +#define FDCAN_NDAT1_ND17 FDCAN_NDAT1_ND17_MASK /* New Data flag of Rx Buffer 17 */ +#define FDCAN_NDAT1_ND18_SHIFT (18U) +#define FDCAN_NDAT1_ND18_MASK (0x1U << FDCAN_NDAT1_ND18_SHIFT) /* 0x00040000 */ +#define FDCAN_NDAT1_ND18 FDCAN_NDAT1_ND18_MASK /* New Data flag of Rx Buffer 18 */ +#define FDCAN_NDAT1_ND19_SHIFT (19U) +#define FDCAN_NDAT1_ND19_MASK (0x1U << FDCAN_NDAT1_ND19_SHIFT) /* 0x00080000 */ +#define FDCAN_NDAT1_ND19 FDCAN_NDAT1_ND19_MASK /* New Data flag of Rx Buffer 19 */ +#define FDCAN_NDAT1_ND20_SHIFT (20U) +#define FDCAN_NDAT1_ND20_MASK (0x1U << FDCAN_NDAT1_ND20_SHIFT) /* 0x00100000 */ +#define FDCAN_NDAT1_ND20 FDCAN_NDAT1_ND20_MASK /* New Data flag of Rx Buffer 20 */ +#define FDCAN_NDAT1_ND21_SHIFT (21U) +#define FDCAN_NDAT1_ND21_MASK (0x1U << FDCAN_NDAT1_ND21_SHIFT) /* 0x00200000 */ +#define FDCAN_NDAT1_ND21 FDCAN_NDAT1_ND21_MASK /* New Data flag of Rx Buffer 21 */ +#define FDCAN_NDAT1_ND22_SHIFT (22U) +#define FDCAN_NDAT1_ND22_MASK (0x1U << FDCAN_NDAT1_ND22_SHIFT) /* 0x00400000 */ +#define FDCAN_NDAT1_ND22 FDCAN_NDAT1_ND22_MASK /* New Data flag of Rx Buffer 22 */ +#define FDCAN_NDAT1_ND23_SHIFT (23U) +#define FDCAN_NDAT1_ND23_MASK (0x1U << FDCAN_NDAT1_ND23_SHIFT) /* 0x00800000 */ +#define FDCAN_NDAT1_ND23 FDCAN_NDAT1_ND23_MASK /* New Data flag of Rx Buffer 23 */ +#define FDCAN_NDAT1_ND24_SHIFT (24U) +#define FDCAN_NDAT1_ND24_MASK (0x1U << FDCAN_NDAT1_ND24_SHIFT) /* 0x01000000 */ +#define FDCAN_NDAT1_ND24 FDCAN_NDAT1_ND24_MASK /* New Data flag of Rx Buffer 24 */ +#define FDCAN_NDAT1_ND25_SHIFT (25U) +#define FDCAN_NDAT1_ND25_MASK (0x1U << FDCAN_NDAT1_ND25_SHIFT) /* 0x02000000 */ +#define FDCAN_NDAT1_ND25 FDCAN_NDAT1_ND25_MASK /* New Data flag of Rx Buffer 25 */ +#define FDCAN_NDAT1_ND26_SHIFT (26U) +#define FDCAN_NDAT1_ND26_MASK (0x1U << FDCAN_NDAT1_ND26_SHIFT) /* 0x04000000 */ +#define FDCAN_NDAT1_ND26 FDCAN_NDAT1_ND26_MASK /* New Data flag of Rx Buffer 26 */ +#define FDCAN_NDAT1_ND27_SHIFT (27U) +#define FDCAN_NDAT1_ND27_MASK (0x1U << FDCAN_NDAT1_ND27_SHIFT) /* 0x08000000 */ +#define FDCAN_NDAT1_ND27 FDCAN_NDAT1_ND27_MASK /* New Data flag of Rx Buffer 27 */ +#define FDCAN_NDAT1_ND28_SHIFT (28U) +#define FDCAN_NDAT1_ND28_MASK (0x1U << FDCAN_NDAT1_ND28_SHIFT) /* 0x10000000 */ +#define FDCAN_NDAT1_ND28 FDCAN_NDAT1_ND28_MASK /* New Data flag of Rx Buffer 28 */ +#define FDCAN_NDAT1_ND29_SHIFT (29U) +#define FDCAN_NDAT1_ND29_MASK (0x1U << FDCAN_NDAT1_ND29_SHIFT) /* 0x20000000 */ +#define FDCAN_NDAT1_ND29 FDCAN_NDAT1_ND29_MASK /* New Data flag of Rx Buffer 29 */ +#define FDCAN_NDAT1_ND30_SHIFT (30U) +#define FDCAN_NDAT1_ND30_MASK (0x1U << FDCAN_NDAT1_ND30_SHIFT) /* 0x40000000 */ +#define FDCAN_NDAT1_ND30 FDCAN_NDAT1_ND30_MASK /* New Data flag of Rx Buffer 30 */ +#define FDCAN_NDAT1_ND31_SHIFT (31U) +#define FDCAN_NDAT1_ND31_MASK (0x1U << FDCAN_NDAT1_ND31_SHIFT) /* 0x80000000 */ +#define FDCAN_NDAT1_ND31 FDCAN_NDAT1_ND31_MASK /* New Data flag of Rx Buffer 31 */ + +/* *************** Bit definition for FDCAN_NDAT2 register ****************/ +#define FDCAN_NDAT2_ND32_SHIFT (0U) +#define FDCAN_NDAT2_ND32_MASK (0x1U << FDCAN_NDAT2_ND32_SHIFT) /* 0x00000001 */ +#define FDCAN_NDAT2_ND32 FDCAN_NDAT2_ND32_MASK /* New Data flag of Rx Buffer 32 */ +#define FDCAN_NDAT2_ND33_SHIFT (1U) +#define FDCAN_NDAT2_ND33_MASK (0x1U << FDCAN_NDAT2_ND33_SHIFT) /* 0x00000002 */ +#define FDCAN_NDAT2_ND33 FDCAN_NDAT2_ND33_MASK /* New Data flag of Rx Buffer 33 */ +#define FDCAN_NDAT2_ND34_SHIFT (2U) +#define FDCAN_NDAT2_ND34_MASK (0x1U << FDCAN_NDAT2_ND34_SHIFT) /* 0x00000004 */ +#define FDCAN_NDAT2_ND34 FDCAN_NDAT2_ND34_MASK /* New Data flag of Rx Buffer 34 */ +#define FDCAN_NDAT2_ND35_SHIFT (3U) +#define FDCAN_NDAT2_ND35_MASK (0x1U << FDCAN_NDAT2_ND35_SHIFT) /* 0x00000008 */ +#define FDCAN_NDAT2_ND35 FDCAN_NDAT2_ND35_MASK /* New Data flag of Rx Buffer 35 */ +#define FDCAN_NDAT2_ND36_SHIFT (4U) +#define FDCAN_NDAT2_ND36_MASK (0x1U << FDCAN_NDAT2_ND36_SHIFT) /* 0x00000010 */ +#define FDCAN_NDAT2_ND36 FDCAN_NDAT2_ND36_MASK /* New Data flag of Rx Buffer 36 */ +#define FDCAN_NDAT2_ND37_SHIFT (5U) +#define FDCAN_NDAT2_ND37_MASK (0x1U << FDCAN_NDAT2_ND37_SHIFT) /* 0x00000020 */ +#define FDCAN_NDAT2_ND37 FDCAN_NDAT2_ND37_MASK /* New Data flag of Rx Buffer 37 */ +#define FDCAN_NDAT2_ND38_SHIFT (6U) +#define FDCAN_NDAT2_ND38_MASK (0x1U << FDCAN_NDAT2_ND38_SHIFT) /* 0x00000040 */ +#define FDCAN_NDAT2_ND38 FDCAN_NDAT2_ND38_MASK /* New Data flag of Rx Buffer 38 */ +#define FDCAN_NDAT2_ND39_SHIFT (7U) +#define FDCAN_NDAT2_ND39_MASK (0x1U << FDCAN_NDAT2_ND39_SHIFT) /* 0x00000080 */ +#define FDCAN_NDAT2_ND39 FDCAN_NDAT2_ND39_MASK /* New Data flag of Rx Buffer 39 */ +#define FDCAN_NDAT2_ND40_SHIFT (8U) +#define FDCAN_NDAT2_ND40_MASK (0x1U << FDCAN_NDAT2_ND40_SHIFT) /* 0x00000100 */ +#define FDCAN_NDAT2_ND40 FDCAN_NDAT2_ND40_MASK /* New Data flag of Rx Buffer 40 */ +#define FDCAN_NDAT2_ND41_SHIFT (9U) +#define FDCAN_NDAT2_ND41_MASK (0x1U << FDCAN_NDAT2_ND41_SHIFT) /* 0x00000200 */ +#define FDCAN_NDAT2_ND41 FDCAN_NDAT2_ND41_MASK /* New Data flag of Rx Buffer 41 */ +#define FDCAN_NDAT2_ND42_SHIFT (10U) +#define FDCAN_NDAT2_ND42_MASK (0x1U << FDCAN_NDAT2_ND42_SHIFT) /* 0x00000400 */ +#define FDCAN_NDAT2_ND42 FDCAN_NDAT2_ND42_MASK /* New Data flag of Rx Buffer 42 */ +#define FDCAN_NDAT2_ND43_SHIFT (11U) +#define FDCAN_NDAT2_ND43_MASK (0x1U << FDCAN_NDAT2_ND43_SHIFT) /* 0x00000800 */ +#define FDCAN_NDAT2_ND43 FDCAN_NDAT2_ND43_MASK /* New Data flag of Rx Buffer 43 */ +#define FDCAN_NDAT2_ND44_SHIFT (12U) +#define FDCAN_NDAT2_ND44_MASK (0x1U << FDCAN_NDAT2_ND44_SHIFT) /* 0x00001000 */ +#define FDCAN_NDAT2_ND44 FDCAN_NDAT2_ND44_MASK /* New Data flag of Rx Buffer 44 */ +#define FDCAN_NDAT2_ND45_SHIFT (13U) +#define FDCAN_NDAT2_ND45_MASK (0x1U << FDCAN_NDAT2_ND45_SHIFT) /* 0x00002000 */ +#define FDCAN_NDAT2_ND45 FDCAN_NDAT2_ND45_MASK /* New Data flag of Rx Buffer 45 */ +#define FDCAN_NDAT2_ND46_SHIFT (14U) +#define FDCAN_NDAT2_ND46_MASK (0x1U << FDCAN_NDAT2_ND46_SHIFT) /* 0x00004000 */ +#define FDCAN_NDAT2_ND46 FDCAN_NDAT2_ND46_MASK /* New Data flag of Rx Buffer 46 */ +#define FDCAN_NDAT2_ND47_SHIFT (15U) +#define FDCAN_NDAT2_ND47_MASK (0x1U << FDCAN_NDAT2_ND47_SHIFT) /* 0x00008000 */ +#define FDCAN_NDAT2_ND47 FDCAN_NDAT2_ND47_MASK /* New Data flag of Rx Buffer 47 */ +#define FDCAN_NDAT2_ND48_SHIFT (16U) +#define FDCAN_NDAT2_ND48_MASK (0x1U << FDCAN_NDAT2_ND48_SHIFT) /* 0x00010000 */ +#define FDCAN_NDAT2_ND48 FDCAN_NDAT2_ND48_MASK /* New Data flag of Rx Buffer 48 */ +#define FDCAN_NDAT2_ND49_SHIFT (17U) +#define FDCAN_NDAT2_ND49_MASK (0x1U << FDCAN_NDAT2_ND49_SHIFT) /* 0x00020000 */ +#define FDCAN_NDAT2_ND49 FDCAN_NDAT2_ND49_MASK /* New Data flag of Rx Buffer 49 */ +#define FDCAN_NDAT2_ND50_SHIFT (18U) +#define FDCAN_NDAT2_ND50_MASK (0x1U << FDCAN_NDAT2_ND50_SHIFT) /* 0x00040000 */ +#define FDCAN_NDAT2_ND50 FDCAN_NDAT2_ND50_MASK /* New Data flag of Rx Buffer 50 */ +#define FDCAN_NDAT2_ND51_SHIFT (19U) +#define FDCAN_NDAT2_ND51_MASK (0x1U << FDCAN_NDAT2_ND51_SHIFT) /* 0x00080000 */ +#define FDCAN_NDAT2_ND51 FDCAN_NDAT2_ND51_MASK /* New Data flag of Rx Buffer 51 */ +#define FDCAN_NDAT2_ND52_SHIFT (20U) +#define FDCAN_NDAT2_ND52_MASK (0x1U << FDCAN_NDAT2_ND52_SHIFT) /* 0x00100000 */ +#define FDCAN_NDAT2_ND52 FDCAN_NDAT2_ND52_MASK /* New Data flag of Rx Buffer 52 */ +#define FDCAN_NDAT2_ND53_SHIFT (21U) +#define FDCAN_NDAT2_ND53_MASK (0x1U << FDCAN_NDAT2_ND53_SHIFT) /* 0x00200000 */ +#define FDCAN_NDAT2_ND53 FDCAN_NDAT2_ND53_MASK /* New Data flag of Rx Buffer 53 */ +#define FDCAN_NDAT2_ND54_SHIFT (22U) +#define FDCAN_NDAT2_ND54_MASK (0x1U << FDCAN_NDAT2_ND54_SHIFT) /* 0x00400000 */ +#define FDCAN_NDAT2_ND54 FDCAN_NDAT2_ND54_MASK /* New Data flag of Rx Buffer 54 */ +#define FDCAN_NDAT2_ND55_SHIFT (23U) +#define FDCAN_NDAT2_ND55_MASK (0x1U << FDCAN_NDAT2_ND55_SHIFT) /* 0x00800000 */ +#define FDCAN_NDAT2_ND55 FDCAN_NDAT2_ND55_MASK /* New Data flag of Rx Buffer 55 */ +#define FDCAN_NDAT2_ND56_SHIFT (24U) +#define FDCAN_NDAT2_ND56_MASK (0x1U << FDCAN_NDAT2_ND56_SHIFT) /* 0x01000000 */ +#define FDCAN_NDAT2_ND56 FDCAN_NDAT2_ND56_MASK /* New Data flag of Rx Buffer 56 */ +#define FDCAN_NDAT2_ND57_SHIFT (25U) +#define FDCAN_NDAT2_ND57_MASK (0x1U << FDCAN_NDAT2_ND57_SHIFT) /* 0x02000000 */ +#define FDCAN_NDAT2_ND57 FDCAN_NDAT2_ND57_MASK /* New Data flag of Rx Buffer 57 */ +#define FDCAN_NDAT2_ND58_SHIFT (26U) +#define FDCAN_NDAT2_ND58_MASK (0x1U << FDCAN_NDAT2_ND58_SHIFT) /* 0x04000000 */ +#define FDCAN_NDAT2_ND58 FDCAN_NDAT2_ND58_MASK /* New Data flag of Rx Buffer 58 */ +#define FDCAN_NDAT2_ND59_SHIFT (27U) +#define FDCAN_NDAT2_ND59_MASK (0x1U << FDCAN_NDAT2_ND59_SHIFT) /* 0x08000000 */ +#define FDCAN_NDAT2_ND59 FDCAN_NDAT2_ND59_MASK /* New Data flag of Rx Buffer 59 */ +#define FDCAN_NDAT2_ND60_SHIFT (28U) +#define FDCAN_NDAT2_ND60_MASK (0x1U << FDCAN_NDAT2_ND60_SHIFT) /* 0x10000000 */ +#define FDCAN_NDAT2_ND60 FDCAN_NDAT2_ND60_MASK /* New Data flag of Rx Buffer 60 */ +#define FDCAN_NDAT2_ND61_SHIFT (29U) +#define FDCAN_NDAT2_ND61_MASK (0x1U << FDCAN_NDAT2_ND61_SHIFT) /* 0x20000000 */ +#define FDCAN_NDAT2_ND61 FDCAN_NDAT2_ND61_MASK /* New Data flag of Rx Buffer 61 */ +#define FDCAN_NDAT2_ND62_SHIFT (30U) +#define FDCAN_NDAT2_ND62_MASK (0x1U << FDCAN_NDAT2_ND62_SHIFT) /* 0x40000000 */ +#define FDCAN_NDAT2_ND62 FDCAN_NDAT2_ND62_MASK /* New Data flag of Rx Buffer 62 */ +#define FDCAN_NDAT2_ND63_SHIFT (31U) +#define FDCAN_NDAT2_ND63_MASK (0x1U << FDCAN_NDAT2_ND63_SHIFT) /* 0x80000000 */ +#define FDCAN_NDAT2_ND63 FDCAN_NDAT2_ND63_MASK /* New Data flag of Rx Buffer 63 */ + +/* *************** Bit definition for FDCAN_RXF0C register ****************/ +#define FDCAN_RXF0C_F0SA_SHIFT (2U) +#define FDCAN_RXF0C_F0SA_MASK (0x3FFFU << FDCAN_RXF0C_F0SA_SHIFT) /* 0x0000FFFC */ +#define FDCAN_RXF0C_F0SA FDCAN_RXF0C_F0SA_MASK /* Rx FIFO 0 Start Address */ +#define FDCAN_RXF0C_F0S_SHIFT (16U) +#define FDCAN_RXF0C_F0S_MASK (0x7FU << FDCAN_RXF0C_F0S_SHIFT) /* 0x007F0000 */ +#define FDCAN_RXF0C_F0S FDCAN_RXF0C_F0S_MASK /* Number of Rx FIFO 0 elements */ +#define FDCAN_RXF0C_F0WM_SHIFT (24U) +#define FDCAN_RXF0C_F0WM_MASK (0x7FU << FDCAN_RXF0C_F0WM_SHIFT) /* 0x7F000000 */ +#define FDCAN_RXF0C_F0WM FDCAN_RXF0C_F0WM_MASK /* FIFO 0 Watermark */ +#define FDCAN_RXF0C_F0OM_SHIFT (31U) +#define FDCAN_RXF0C_F0OM_MASK (0x1U << FDCAN_RXF0C_F0OM_SHIFT) /* 0x80000000 */ +#define FDCAN_RXF0C_F0OM FDCAN_RXF0C_F0OM_MASK /* FIFO 0 Operation Mode */ + +/* *************** Bit definition for FDCAN_RXF0S register ****************/ +#define FDCAN_RXF0S_F0FL_SHIFT (0U) +#define FDCAN_RXF0S_F0FL_MASK (0x7FU << FDCAN_RXF0S_F0FL_SHIFT) /* 0x0000007F */ +#define FDCAN_RXF0S_F0FL FDCAN_RXF0S_F0FL_MASK /* Rx FIFO 0 Fill Level */ +#define FDCAN_RXF0S_F0GI_SHIFT (8U) +#define FDCAN_RXF0S_F0GI_MASK (0x3FU << FDCAN_RXF0S_F0GI_SHIFT) /* 0x00003F00 */ +#define FDCAN_RXF0S_F0GI FDCAN_RXF0S_F0GI_MASK /* Rx FIFO 0 Get Index */ +#define FDCAN_RXF0S_F0PI_SHIFT (16U) +#define FDCAN_RXF0S_F0PI_MASK (0x3FU << FDCAN_RXF0S_F0PI_SHIFT) /* 0x003F0000 */ +#define FDCAN_RXF0S_F0PI FDCAN_RXF0S_F0PI_MASK /* Rx FIFO 0 Put Index */ +#define FDCAN_RXF0S_F0F_SHIFT (24U) +#define FDCAN_RXF0S_F0F_MASK (0x1U << FDCAN_RXF0S_F0F_SHIFT) /* 0x01000000 */ +#define FDCAN_RXF0S_F0F FDCAN_RXF0S_F0F_MASK /* Rx FIFO 0 Full */ +#define FDCAN_RXF0S_RF0L_SHIFT (25U) +#define FDCAN_RXF0S_RF0L_MASK (0x1U << FDCAN_RXF0S_RF0L_SHIFT) /* 0x02000000 */ +#define FDCAN_RXF0S_RF0L FDCAN_RXF0S_RF0L_MASK /* Rx FIFO 0 Message Lost */ + +/* *************** Bit definition for FDCAN_RXF0A register ****************/ +#define FDCAN_RXF0A_F0AI_SHIFT (0U) +#define FDCAN_RXF0A_F0AI_MASK (0x3FU << FDCAN_RXF0A_F0AI_SHIFT) /* 0x0000003F */ +#define FDCAN_RXF0A_F0AI FDCAN_RXF0A_F0AI_MASK /* Rx FIFO 0 Acknowledge Index */ + +/* *************** Bit definition for FDCAN_RXBC register *****************/ +#define FDCAN_RXBC_RBSA_SHIFT (2U) +#define FDCAN_RXBC_RBSA_MASK (0x3FU << FDCAN_RXBC_RBSA_SHIFT) /* 0x000000FC */ +#define FDCAN_RXBC_RBSA FDCAN_RXBC_RBSA_MASK /* Rx Buffer Start Address */ + +/* *************** Bit definition for FDCAN_RXF1C register ****************/ +#define FDCAN_RXF1C_F1SA_SHIFT (2U) +#define FDCAN_RXF1C_F1SA_MASK (0x3FU << FDCAN_RXF1C_F1SA_SHIFT) /* 0x000000FC */ +#define FDCAN_RXF1C_F1SA FDCAN_RXF1C_F1SA_MASK /* Rx FIFO 1 Start Address */ +#define FDCAN_RXF1C_F1S_SHIFT (16U) +#define FDCAN_RXF1C_F1S_MASK (0x7FU << FDCAN_RXF1C_F1S_SHIFT) /* 0x007F0000 */ +#define FDCAN_RXF1C_F1S FDCAN_RXF1C_F1S_MASK /* Number of Rx FIFO 1 elements */ +#define FDCAN_RXF1C_F1WM_SHIFT (24U) +#define FDCAN_RXF1C_F1WM_MASK (0x7FU << FDCAN_RXF1C_F1WM_SHIFT) /* 0x7F000000 */ +#define FDCAN_RXF1C_F1WM FDCAN_RXF1C_F1WM_MASK /* Rx FIFO 1 Watermark */ +#define FDCAN_RXF1C_F1OM_SHIFT (31U) +#define FDCAN_RXF1C_F1OM_MASK (0x1U << FDCAN_RXF1C_F1OM_SHIFT) /* 0x80000000 */ +#define FDCAN_RXF1C_F1OM FDCAN_RXF1C_F1OM_MASK /* FIFO 1 Operation Mode */ + +/* *************** Bit definition for FDCAN_RXF1S register ****************/ +#define FDCAN_RXF1S_F1FL_SHIFT (0U) +#define FDCAN_RXF1S_F1FL_MASK (0x7FU << FDCAN_RXF1S_F1FL_SHIFT) /* 0x0000007F */ +#define FDCAN_RXF1S_F1FL FDCAN_RXF1S_F1FL_MASK /* Rx FIFO 1 Fill Level */ +#define FDCAN_RXF1S_F1GI_SHIFT (8U) +#define FDCAN_RXF1S_F1GI_MASK (0x3FU << FDCAN_RXF1S_F1GI_SHIFT) /* 0x00003F00 */ +#define FDCAN_RXF1S_F1GI FDCAN_RXF1S_F1GI_MASK /* Rx FIFO 1 Get Index */ +#define FDCAN_RXF1S_F1PI_SHIFT (16U) +#define FDCAN_RXF1S_F1PI_MASK (0x3FU << FDCAN_RXF1S_F1PI_SHIFT) /* 0x003F0000 */ +#define FDCAN_RXF1S_F1PI FDCAN_RXF1S_F1PI_MASK /* Rx FIFO 1 Put Index */ +#define FDCAN_RXF1S_F1F_SHIFT (24U) +#define FDCAN_RXF1S_F1F_MASK (0x1U << FDCAN_RXF1S_F1F_SHIFT) /* 0x01000000 */ +#define FDCAN_RXF1S_F1F FDCAN_RXF1S_F1F_MASK /* Rx FIFO 1 Full */ +#define FDCAN_RXF1S_RF1L_SHIFT (25U) +#define FDCAN_RXF1S_RF1L_MASK (0x1U << FDCAN_RXF1S_RF1L_SHIFT) /* 0x02000000 */ +#define FDCAN_RXF1S_RF1L FDCAN_RXF1S_RF1L_MASK /* Rx FIFO 1 Message Lost */ + +/* *************** Bit definition for FDCAN_RXF1A register ****************/ +#define FDCAN_RXF1A_F1AI_SHIFT (0U) +#define FDCAN_RXF1A_F1AI_MASK (0x3FU << FDCAN_RXF1A_F1AI_SHIFT) /* 0x0000003F */ +#define FDCAN_RXF1A_F1AI FDCAN_RXF1A_F1AI_MASK /* Rx FIFO 1 Acknowledge Index */ + +/* *************** Bit definition for FDCAN_RXESC register ****************/ +#define FDCAN_RXESC_F0DS_SHIFT (0U) +#define FDCAN_RXESC_F0DS_MASK (0x7U << FDCAN_RXESC_F0DS_SHIFT) /* 0x00000007 */ +#define FDCAN_RXESC_F0DS FDCAN_RXESC_F0DS_MASK /* Rx FIFO 1 Data Field Size */ +#define FDCAN_RXESC_F1DS_SHIFT (4U) +#define FDCAN_RXESC_F1DS_MASK (0x7U << FDCAN_RXESC_F1DS_SHIFT) /* 0x00000070 */ +#define FDCAN_RXESC_F1DS FDCAN_RXESC_F1DS_MASK /* Rx FIFO 0 Data Field Size */ +#define FDCAN_RXESC_RBDS_SHIFT (8U) +#define FDCAN_RXESC_RBDS_MASK (0x7U << FDCAN_RXESC_RBDS_SHIFT) /* 0x00000700 */ +#define FDCAN_RXESC_RBDS FDCAN_RXESC_RBDS_MASK /* Rx Buffer Data Field Size */ + +/* *************** Bit definition for FDCAN_TXBC register *****************/ +#define FDCAN_TXBC_TBSA_SHIFT (2U) +#define FDCAN_TXBC_TBSA_MASK (0x3FFFU << FDCAN_TXBC_TBSA_SHIFT) /* 0x0000FFFC */ +#define FDCAN_TXBC_TBSA FDCAN_TXBC_TBSA_MASK /* Tx Buffers Start Address */ +#define FDCAN_TXBC_NDTB_SHIFT (16U) +#define FDCAN_TXBC_NDTB_MASK (0x3FU << FDCAN_TXBC_NDTB_SHIFT) /* 0x003F0000 */ +#define FDCAN_TXBC_NDTB FDCAN_TXBC_NDTB_MASK /* Number of Dedicated Transmit Buffers */ +#define FDCAN_TXBC_TFQS_SHIFT (24U) +#define FDCAN_TXBC_TFQS_MASK (0x3FU << FDCAN_TXBC_TFQS_SHIFT) /* 0x3F000000 */ +#define FDCAN_TXBC_TFQS FDCAN_TXBC_TFQS_MASK /* Transmit FIFO/Queue Size */ +#define FDCAN_TXBC_TFQM_SHIFT (30U) +#define FDCAN_TXBC_TFQM_MASK (0x1U << FDCAN_TXBC_TFQM_SHIFT) /* 0x40000000 */ +#define FDCAN_TXBC_TFQM FDCAN_TXBC_TFQM_MASK /* Tx FIFO/Queue Mode */ + +/* *************** Bit definition for FDCAN_TXFQS register ****************/ +#define FDCAN_TXFQS_TFFL_SHIFT (0U) +#define FDCAN_TXFQS_TFFL_MASK (0x3FU << FDCAN_TXFQS_TFFL_SHIFT) /* 0x0000003F */ +#define FDCAN_TXFQS_TFFL FDCAN_TXFQS_TFFL_MASK /* Tx FIFO Free Level */ +#define FDCAN_TXFQS_TFGI_SHIFT (8U) +#define FDCAN_TXFQS_TFGI_MASK (0x1FU << FDCAN_TXFQS_TFGI_SHIFT) /* 0x00001F00 */ +#define FDCAN_TXFQS_TFGI FDCAN_TXFQS_TFGI_MASK /* Tx FIFO Get Index */ +#define FDCAN_TXFQS_TFQPI_SHIFT (16U) +#define FDCAN_TXFQS_TFQPI_MASK (0x1FU << FDCAN_TXFQS_TFQPI_SHIFT) /* 0x001F0000 */ +#define FDCAN_TXFQS_TFQPI FDCAN_TXFQS_TFQPI_MASK /* Tx FIFO/Queue Put Index */ +#define FDCAN_TXFQS_TFQF_SHIFT (21U) +#define FDCAN_TXFQS_TFQF_MASK (0x1U << FDCAN_TXFQS_TFQF_SHIFT) /* 0x00200000 */ +#define FDCAN_TXFQS_TFQF FDCAN_TXFQS_TFQF_MASK /* Tx FIFO/Queue Full */ + +/* *************** Bit definition for FDCAN_TXESC register ****************/ +#define FDCAN_TXESC_TBDS_SHIFT (0U) +#define FDCAN_TXESC_TBDS_MASK (0x7U << FDCAN_TXESC_TBDS_SHIFT) /* 0x00000007 */ +#define FDCAN_TXESC_TBDS FDCAN_TXESC_TBDS_MASK /* Tx Buffer Data Field Size */ + +/* *************** Bit definition for FDCAN_TXBRP register ****************/ +#define FDCAN_TXBRP_TRP_SHIFT (0U) +#define FDCAN_TXBRP_TRP_MASK (0xFFFFFFFFU << FDCAN_TXBRP_TRP_SHIFT) /* 0xFFFFFFFF */ +#define FDCAN_TXBRP_TRP FDCAN_TXBRP_TRP_MASK /* Transmission Request Pending */ + +/* *************** Bit definition for FDCAN_TXBAR register ****************/ +#define FDCAN_TXBAR_AR_SHIFT (0U) +#define FDCAN_TXBAR_AR_MASK (0xFFFFFFFFU << FDCAN_TXBAR_AR_SHIFT) /* 0xFFFFFFFF */ +#define FDCAN_TXBAR_AR FDCAN_TXBAR_AR_MASK /* Add Request */ + +/* *************** Bit definition for FDCAN_TXBCR register ****************/ +#define FDCAN_TXBCR_CR_SHIFT (0U) +#define FDCAN_TXBCR_CR_MASK (0xFFFFFFFFU << FDCAN_TXBCR_CR_SHIFT) /* 0xFFFFFFFF */ +#define FDCAN_TXBCR_CR FDCAN_TXBCR_CR_MASK /* Cancellation Request */ + +/* *************** Bit definition for FDCAN_TXBTO register ****************/ +#define FDCAN_TXBTO_TO_SHIFT (0U) +#define FDCAN_TXBTO_TO_MASK (0xFFFFFFFFU << FDCAN_TXBTO_TO_SHIFT) /* 0xFFFFFFFF */ +#define FDCAN_TXBTO_TO FDCAN_TXBTO_TO_MASK /* Transmission Occurred */ + +/* *************** Bit definition for FDCAN_TXBCF register ****************/ +#define FDCAN_TXBCF_CF_SHIFT (0U) +#define FDCAN_TXBCF_CF_MASK (0xFFFFFFFFU << FDCAN_TXBCF_CF_SHIFT) /* 0xFFFFFFFF */ +#define FDCAN_TXBCF_CF FDCAN_TXBCF_CF_MASK /* Cancellation Finished */ + +/* *************** Bit definition for FDCAN_TXBTIE register ***************/ +#define FDCAN_TXBTIE_TIE_SHIFT (0U) +#define FDCAN_TXBTIE_TIE_MASK (0xFFFFFFFFU << FDCAN_TXBTIE_TIE_SHIFT) /* 0xFFFFFFFF */ +#define FDCAN_TXBTIE_TIE FDCAN_TXBTIE_TIE_MASK /* Transmission Interrupt Enable */ + +/* *************** Bit definition for FDCAN_ TXBCIE register **************/ +#define FDCAN_TXBCIE_CF_SHIFT (0U) +#define FDCAN_TXBCIE_CF_MASK (0xFFFFFFFFU << FDCAN_TXBCIE_CF_SHIFT) /* 0xFFFFFFFF */ +#define FDCAN_TXBCIE_CF FDCAN_TXBCIE_CF_MASK /* Cancellation Finished Interrupt Enable */ + +/* *************** Bit definition for FDCAN_TXEFC register ****************/ +#define FDCAN_TXEFC_EFSA_SHIFT (2U) +#define FDCAN_TXEFC_EFSA_MASK (0x3FU << FDCAN_TXEFC_EFSA_SHIFT) /* 0x000000FC */ +#define FDCAN_TXEFC_EFSA FDCAN_TXEFC_EFSA_MASK /* Event FIFO Start Address */ +#define FDCAN_TXEFC_EFS_SHIFT (8U) +#define FDCAN_TXEFC_EFS_MASK (0x3FU << FDCAN_TXEFC_EFS_SHIFT) /* 0x00003F00 */ +#define FDCAN_TXEFC_EFS FDCAN_TXEFC_EFS_MASK /* Event FIFO Size */ +#define FDCAN_TXEFC_EFWM_SHIFT (24U) +#define FDCAN_TXEFC_EFWM_MASK (0x3FU << FDCAN_TXEFC_EFWM_SHIFT) /* 0x3F000000 */ +#define FDCAN_TXEFC_EFWM FDCAN_TXEFC_EFWM_MASK /* Event FIFO Watermark */ + +/* *************** Bit definition for FDCAN_TXEFS register ****************/ +#define FDCAN_TXEFS_EFFL_SHIFT (0U) +#define FDCAN_TXEFS_EFFL_MASK (0x3FU << FDCAN_TXEFS_EFFL_SHIFT) /* 0x0000003F */ +#define FDCAN_TXEFS_EFFL FDCAN_TXEFS_EFFL_MASK /* Event FIFO Fill Level */ +#define FDCAN_TXEFS_EFGI_SHIFT (8U) +#define FDCAN_TXEFS_EFGI_MASK (0x1FU << FDCAN_TXEFS_EFGI_SHIFT) /* 0x00001F00 */ +#define FDCAN_TXEFS_EFGI FDCAN_TXEFS_EFGI_MASK /* Event FIFO Get Index */ +#define FDCAN_TXEFS_EFPI_SHIFT (16U) +#define FDCAN_TXEFS_EFPI_MASK (0x1FU << FDCAN_TXEFS_EFPI_SHIFT) /* 0x001F0000 */ +#define FDCAN_TXEFS_EFPI FDCAN_TXEFS_EFPI_MASK /* Event FIFO Put Index */ +#define FDCAN_TXEFS_EFF_SHIFT (24U) +#define FDCAN_TXEFS_EFF_MASK (0x1U << FDCAN_TXEFS_EFF_SHIFT) /* 0x01000000 */ +#define FDCAN_TXEFS_EFF FDCAN_TXEFS_EFF_MASK /* Event FIFO Full */ +#define FDCAN_TXEFS_TEFL_SHIFT (25U) +#define FDCAN_TXEFS_TEFL_MASK (0x1U << FDCAN_TXEFS_TEFL_SHIFT) /* 0x02000000 */ +#define FDCAN_TXEFS_TEFL FDCAN_TXEFS_TEFL_MASK /* Tx Event FIFO Element Lost */ + +/* *************** Bit definition for FDCAN_TXEFA register ****************/ +#define FDCAN_TXEFA_EFAI_SHIFT (0U) +#define FDCAN_TXEFA_EFAI_MASK (0x1FU << FDCAN_TXEFA_EFAI_SHIFT) /* 0x0000001F */ +#define FDCAN_TXEFA_EFAI FDCAN_TXEFA_EFAI_MASK /* Event FIFO Acknowledge Index */ + +/* *************** Bit definition for FDCAN_TTTMC register ****************/ +#define FDCAN_TTTMC_TMSA_SHIFT (2U) +#define FDCAN_TTTMC_TMSA_MASK (0x3FFFU << FDCAN_TTTMC_TMSA_SHIFT) /* 0x0000FFFC */ +#define FDCAN_TTTMC_TMSA FDCAN_TTTMC_TMSA_MASK /* Trigger Memory Start Address */ +#define FDCAN_TTTMC_TME_SHIFT (16U) +#define FDCAN_TTTMC_TME_MASK (0x7FU << FDCAN_TTTMC_TME_SHIFT) /* 0x007F0000 */ +#define FDCAN_TTTMC_TME FDCAN_TTTMC_TME_MASK /* Trigger Memory Elements */ + +/* *************** Bit definition for FDCAN_TTRMC register ****************/ +#define FDCAN_TTRMC_RID_SHIFT (0U) +#define FDCAN_TTRMC_RID_MASK (0x1FFFFFFFU << FDCAN_TTRMC_RID_SHIFT) /* 0x1FFFFFFF */ +#define FDCAN_TTRMC_RID FDCAN_TTRMC_RID_MASK /* Reference Identifier */ +#define FDCAN_TTRMC_XTD_SHIFT (30U) +#define FDCAN_TTRMC_XTD_MASK (0x1U << FDCAN_TTRMC_XTD_SHIFT) /* 0x40000000 */ +#define FDCAN_TTRMC_XTD FDCAN_TTRMC_XTD_MASK /* Extended Identifier */ +#define FDCAN_TTRMC_RMPS_SHIFT (31U) +#define FDCAN_TTRMC_RMPS_MASK (0x1U << FDCAN_TTRMC_RMPS_SHIFT) /* 0x80000000 */ +#define FDCAN_TTRMC_RMPS FDCAN_TTRMC_RMPS_MASK /* Reference Message Payload Select */ + +/* *************** Bit definition for FDCAN_TTOCF register ****************/ +#define FDCAN_TTOCF_OM_SHIFT (0U) +#define FDCAN_TTOCF_OM_MASK (0x3U << FDCAN_TTOCF_OM_SHIFT) /* 0x00000003 */ +#define FDCAN_TTOCF_OM FDCAN_TTOCF_OM_MASK /* Operation Mode */ +#define FDCAN_TTOCF_GEN_SHIFT (3U) +#define FDCAN_TTOCF_GEN_MASK (0x1U << FDCAN_TTOCF_GEN_SHIFT) /* 0x00000008 */ +#define FDCAN_TTOCF_GEN FDCAN_TTOCF_GEN_MASK /* Gap Enable */ +#define FDCAN_TTOCF_TM_SHIFT (4U) +#define FDCAN_TTOCF_TM_MASK (0x1U << FDCAN_TTOCF_TM_SHIFT) /* 0x00000010 */ +#define FDCAN_TTOCF_TM FDCAN_TTOCF_TM_MASK /* Time Master */ +#define FDCAN_TTOCF_LDSDL_SHIFT (5U) +#define FDCAN_TTOCF_LDSDL_MASK (0x7U << FDCAN_TTOCF_LDSDL_SHIFT) /* 0x000000E0 */ +#define FDCAN_TTOCF_LDSDL FDCAN_TTOCF_LDSDL_MASK /* LD of Synchronization Deviation Limit */ +#define FDCAN_TTOCF_IRTO_SHIFT (8U) +#define FDCAN_TTOCF_IRTO_MASK (0x7FU << FDCAN_TTOCF_IRTO_SHIFT) /* 0x00007F00 */ +#define FDCAN_TTOCF_IRTO FDCAN_TTOCF_IRTO_MASK /* Initial Reference Trigger Offset */ +#define FDCAN_TTOCF_EECS_SHIFT (15U) +#define FDCAN_TTOCF_EECS_MASK (0x1U << FDCAN_TTOCF_EECS_SHIFT) /* 0x00008000 */ +#define FDCAN_TTOCF_EECS FDCAN_TTOCF_EECS_MASK /* Enable External Clock Synchronization */ +#define FDCAN_TTOCF_AWL_SHIFT (16U) +#define FDCAN_TTOCF_AWL_MASK (0xFFU << FDCAN_TTOCF_AWL_SHIFT) /* 0x00FF0000 */ +#define FDCAN_TTOCF_AWL FDCAN_TTOCF_AWL_MASK /* Application Watchdog Limit */ +#define FDCAN_TTOCF_EGTF_SHIFT (24U) +#define FDCAN_TTOCF_EGTF_MASK (0x1U << FDCAN_TTOCF_EGTF_SHIFT) /* 0x01000000 */ +#define FDCAN_TTOCF_EGTF FDCAN_TTOCF_EGTF_MASK /* Enable Global Time Filtering */ +#define FDCAN_TTOCF_ECC_SHIFT (25U) +#define FDCAN_TTOCF_ECC_MASK (0x1U << FDCAN_TTOCF_ECC_SHIFT) /* 0x02000000 */ +#define FDCAN_TTOCF_ECC FDCAN_TTOCF_ECC_MASK /* Enable Clock Calibration */ +#define FDCAN_TTOCF_EVTP_SHIFT (26U) +#define FDCAN_TTOCF_EVTP_MASK (0x1U << FDCAN_TTOCF_EVTP_SHIFT) /* 0x04000000 */ +#define FDCAN_TTOCF_EVTP FDCAN_TTOCF_EVTP_MASK /* Event Trigger Polarity */ + +/* *************** Bit definition for FDCAN_TTMLM register ****************/ +#define FDCAN_TTMLM_CCM_SHIFT (0U) +#define FDCAN_TTMLM_CCM_MASK (0x3FU << FDCAN_TTMLM_CCM_SHIFT) /* 0x0000003F */ +#define FDCAN_TTMLM_CCM FDCAN_TTMLM_CCM_MASK /* Cycle Count Max */ +#define FDCAN_TTMLM_CSS_SHIFT (6U) +#define FDCAN_TTMLM_CSS_MASK (0x3U << FDCAN_TTMLM_CSS_SHIFT) /* 0x000000C0 */ +#define FDCAN_TTMLM_CSS FDCAN_TTMLM_CSS_MASK /* Cycle Start Synchronization */ +#define FDCAN_TTMLM_TXEW_SHIFT (8U) +#define FDCAN_TTMLM_TXEW_MASK (0xFU << FDCAN_TTMLM_TXEW_SHIFT) /* 0x00000F00 */ +#define FDCAN_TTMLM_TXEW FDCAN_TTMLM_TXEW_MASK /* Tx Enable Window */ +#define FDCAN_TTMLM_ENTT_SHIFT (16U) +#define FDCAN_TTMLM_ENTT_MASK (0xFFFU << FDCAN_TTMLM_ENTT_SHIFT) /* 0x0FFF0000 */ +#define FDCAN_TTMLM_ENTT FDCAN_TTMLM_ENTT_MASK /* Expected Number of Tx Triggers */ + +/* *************** Bit definition for FDCAN_TURCF register ****************/ +#define FDCAN_TURCF_NCL_SHIFT (0U) +#define FDCAN_TURCF_NCL_MASK (0xFFFFU << FDCAN_TURCF_NCL_SHIFT) /* 0x0000FFFF */ +#define FDCAN_TURCF_NCL FDCAN_TURCF_NCL_MASK /* Numerator Configuration Low */ +#define FDCAN_TURCF_DC_SHIFT (16U) +#define FDCAN_TURCF_DC_MASK (0x3FFFU << FDCAN_TURCF_DC_SHIFT) /* 0x3FFF0000 */ +#define FDCAN_TURCF_DC FDCAN_TURCF_DC_MASK /* Denominator Configuration */ +#define FDCAN_TURCF_ELT_SHIFT (31U) +#define FDCAN_TURCF_ELT_MASK (0x1U << FDCAN_TURCF_ELT_SHIFT) /* 0x80000000 */ +#define FDCAN_TURCF_ELT FDCAN_TURCF_ELT_MASK /* Enable Local Time */ + +/* *************** Bit definition for FDCAN_TTOCN register ****************/ +#define FDCAN_TTOCN_SGT_SHIFT (0U) +#define FDCAN_TTOCN_SGT_MASK (0x1U << FDCAN_TTOCN_SGT_SHIFT) /* 0x00000001 */ +#define FDCAN_TTOCN_SGT FDCAN_TTOCN_SGT_MASK /* Set Global time */ +#define FDCAN_TTOCN_ECS_SHIFT (1U) +#define FDCAN_TTOCN_ECS_MASK (0x1U << FDCAN_TTOCN_ECS_SHIFT) /* 0x00000002 */ +#define FDCAN_TTOCN_ECS FDCAN_TTOCN_ECS_MASK /* External Clock Synchronization */ +#define FDCAN_TTOCN_SWP_SHIFT (2U) +#define FDCAN_TTOCN_SWP_MASK (0x1U << FDCAN_TTOCN_SWP_SHIFT) /* 0x00000004 */ +#define FDCAN_TTOCN_SWP FDCAN_TTOCN_SWP_MASK /* Stop Watch Polarity */ +#define FDCAN_TTOCN_SWS_SHIFT (3U) +#define FDCAN_TTOCN_SWS_MASK (0x3U << FDCAN_TTOCN_SWS_SHIFT) /* 0x00000018 */ +#define FDCAN_TTOCN_SWS FDCAN_TTOCN_SWS_MASK /* Stop Watch Source */ +#define FDCAN_TTOCN_RTIE_SHIFT (5U) +#define FDCAN_TTOCN_RTIE_MASK (0x1U << FDCAN_TTOCN_RTIE_SHIFT) /* 0x00000020 */ +#define FDCAN_TTOCN_RTIE FDCAN_TTOCN_RTIE_MASK /* Register Time Mark Interrupt Pulse Enable */ +#define FDCAN_TTOCN_TMC_SHIFT (6U) +#define FDCAN_TTOCN_TMC_MASK (0x3U << FDCAN_TTOCN_TMC_SHIFT) /* 0x000000C0 */ +#define FDCAN_TTOCN_TMC FDCAN_TTOCN_TMC_MASK /* Register Time Mark Compare */ +#define FDCAN_TTOCN_TTIE_SHIFT (8U) +#define FDCAN_TTOCN_TTIE_MASK (0x1U << FDCAN_TTOCN_TTIE_SHIFT) /* 0x00000100 */ +#define FDCAN_TTOCN_TTIE FDCAN_TTOCN_TTIE_MASK /* Trigger Time Mark Interrupt Pulse Enable */ +#define FDCAN_TTOCN_GCS_SHIFT (9U) +#define FDCAN_TTOCN_GCS_MASK (0x1U << FDCAN_TTOCN_GCS_SHIFT) /* 0x00000200 */ +#define FDCAN_TTOCN_GCS FDCAN_TTOCN_GCS_MASK /* Gap Control Select */ +#define FDCAN_TTOCN_FGP_SHIFT (10U) +#define FDCAN_TTOCN_FGP_MASK (0x1U << FDCAN_TTOCN_FGP_SHIFT) /* 0x00000400 */ +#define FDCAN_TTOCN_FGP FDCAN_TTOCN_FGP_MASK /* Finish Gap */ +#define FDCAN_TTOCN_TMG_SHIFT (11U) +#define FDCAN_TTOCN_TMG_MASK (0x1U << FDCAN_TTOCN_TMG_SHIFT) /* 0x00000800 */ +#define FDCAN_TTOCN_TMG FDCAN_TTOCN_TMG_MASK /* Time Mark Gap */ +#define FDCAN_TTOCN_NIG_SHIFT (12U) +#define FDCAN_TTOCN_NIG_MASK (0x1U << FDCAN_TTOCN_NIG_SHIFT) /* 0x00001000 */ +#define FDCAN_TTOCN_NIG FDCAN_TTOCN_NIG_MASK /* Next is Gap */ +#define FDCAN_TTOCN_ESCN_SHIFT (13U) +#define FDCAN_TTOCN_ESCN_MASK (0x1U << FDCAN_TTOCN_ESCN_SHIFT) /* 0x00002000 */ +#define FDCAN_TTOCN_ESCN FDCAN_TTOCN_ESCN_MASK /* External Synchronization Control */ +#define FDCAN_TTOCN_LCKC_SHIFT (15U) +#define FDCAN_TTOCN_LCKC_MASK (0x1U << FDCAN_TTOCN_LCKC_SHIFT) /* 0x00008000 */ +#define FDCAN_TTOCN_LCKC FDCAN_TTOCN_LCKC_MASK /* TT Operation Control Register Locked */ + +/* *************** Bit definition for FDCAN_TTGTP register ****************/ +#define FDCAN_TTGTP_TP_SHIFT (0U) +#define FDCAN_TTGTP_TP_MASK (0xFFFFU << FDCAN_TTGTP_TP_SHIFT) /* 0x0000FFFF */ +#define FDCAN_TTGTP_TP FDCAN_TTGTP_TP_MASK /* Time Preset */ +#define FDCAN_TTGTP_CTP_SHIFT (16U) +#define FDCAN_TTGTP_CTP_MASK (0xFFFFU << FDCAN_TTGTP_CTP_SHIFT) /* 0xFFFF0000 */ +#define FDCAN_TTGTP_CTP FDCAN_TTGTP_CTP_MASK /* Cycle Time Target Phase */ + +/* *************** Bit definition for FDCAN_TTTMK register ****************/ +#define FDCAN_TTTMK_TM_SHIFT (0U) +#define FDCAN_TTTMK_TM_MASK (0xFFFFU << FDCAN_TTTMK_TM_SHIFT) /* 0x0000FFFF */ +#define FDCAN_TTTMK_TM FDCAN_TTTMK_TM_MASK /* Time Mark */ +#define FDCAN_TTTMK_TICC_SHIFT (16U) +#define FDCAN_TTTMK_TICC_MASK (0x7FU << FDCAN_TTTMK_TICC_SHIFT) /* 0x007F0000 */ +#define FDCAN_TTTMK_TICC FDCAN_TTTMK_TICC_MASK /* Time Mark Cycle Code */ +#define FDCAN_TTTMK_LCKM_SHIFT (31U) +#define FDCAN_TTTMK_LCKM_MASK (0x1U << FDCAN_TTTMK_LCKM_SHIFT) /* 0x80000000 */ +#define FDCAN_TTTMK_LCKM FDCAN_TTTMK_LCKM_MASK /* TT Time Mark Register Locked */ + +/* *************** Bit definition for FDCAN_TTIR register *****************/ +#define FDCAN_TTIR_SBC_SHIFT (0U) +#define FDCAN_TTIR_SBC_MASK (0x1U << FDCAN_TTIR_SBC_SHIFT) /* 0x00000001 */ +#define FDCAN_TTIR_SBC FDCAN_TTIR_SBC_MASK /* Start of Basic Cycle */ +#define FDCAN_TTIR_SMC_SHIFT (1U) +#define FDCAN_TTIR_SMC_MASK (0x1U << FDCAN_TTIR_SMC_SHIFT) /* 0x00000002 */ +#define FDCAN_TTIR_SMC FDCAN_TTIR_SMC_MASK /* Start of Matrix Cycle */ +#define FDCAN_TTIR_CSM_SHIFT (2U) +#define FDCAN_TTIR_CSM_MASK (0x1U << FDCAN_TTIR_CSM_SHIFT) /* 0x00000004 */ +#define FDCAN_TTIR_CSM FDCAN_TTIR_CSM_MASK /* Change of Synchronization Mode */ +#define FDCAN_TTIR_SOG_SHIFT (3U) +#define FDCAN_TTIR_SOG_MASK (0x1U << FDCAN_TTIR_SOG_SHIFT) /* 0x00000008 */ +#define FDCAN_TTIR_SOG FDCAN_TTIR_SOG_MASK /* Start of Gap */ +#define FDCAN_TTIR_RTMI_SHIFT (4U) +#define FDCAN_TTIR_RTMI_MASK (0x1U << FDCAN_TTIR_RTMI_SHIFT) /* 0x00000010 */ +#define FDCAN_TTIR_RTMI FDCAN_TTIR_RTMI_MASK /* Register Time Mark Interrupt */ +#define FDCAN_TTIR_TTMI_SHIFT (5U) +#define FDCAN_TTIR_TTMI_MASK (0x1U << FDCAN_TTIR_TTMI_SHIFT) /* 0x00000020 */ +#define FDCAN_TTIR_TTMI FDCAN_TTIR_TTMI_MASK /* Trigger Time Mark Event Internal */ +#define FDCAN_TTIR_SWE_SHIFT (6U) +#define FDCAN_TTIR_SWE_MASK (0x1U << FDCAN_TTIR_SWE_SHIFT) /* 0x00000040 */ +#define FDCAN_TTIR_SWE FDCAN_TTIR_SWE_MASK /* Stop Watch Event */ +#define FDCAN_TTIR_GTW_SHIFT (7U) +#define FDCAN_TTIR_GTW_MASK (0x1U << FDCAN_TTIR_GTW_SHIFT) /* 0x00000080 */ +#define FDCAN_TTIR_GTW FDCAN_TTIR_GTW_MASK /* Global Time Wrap */ +#define FDCAN_TTIR_GTD_SHIFT (8U) +#define FDCAN_TTIR_GTD_MASK (0x1U << FDCAN_TTIR_GTD_SHIFT) /* 0x00000100 */ +#define FDCAN_TTIR_GTD FDCAN_TTIR_GTD_MASK /* Global Time Discontinuity */ +#define FDCAN_TTIR_GTE_SHIFT (9U) +#define FDCAN_TTIR_GTE_MASK (0x1U << FDCAN_TTIR_GTE_SHIFT) /* 0x00000200 */ +#define FDCAN_TTIR_GTE FDCAN_TTIR_GTE_MASK /* Global Time Error */ +#define FDCAN_TTIR_TXU_SHIFT (10U) +#define FDCAN_TTIR_TXU_MASK (0x1U << FDCAN_TTIR_TXU_SHIFT) /* 0x00000400 */ +#define FDCAN_TTIR_TXU FDCAN_TTIR_TXU_MASK /* Tx Count Underflow */ +#define FDCAN_TTIR_TXO_SHIFT (11U) +#define FDCAN_TTIR_TXO_MASK (0x1U << FDCAN_TTIR_TXO_SHIFT) /* 0x00000800 */ +#define FDCAN_TTIR_TXO FDCAN_TTIR_TXO_MASK /* Tx Count Overflow */ +#define FDCAN_TTIR_SE1_SHIFT (12U) +#define FDCAN_TTIR_SE1_MASK (0x1U << FDCAN_TTIR_SE1_SHIFT) /* 0x00001000 */ +#define FDCAN_TTIR_SE1 FDCAN_TTIR_SE1_MASK /* Scheduling Error 1 */ +#define FDCAN_TTIR_SE2_SHIFT (13U) +#define FDCAN_TTIR_SE2_MASK (0x1U << FDCAN_TTIR_SE2_SHIFT) /* 0x00002000 */ +#define FDCAN_TTIR_SE2 FDCAN_TTIR_SE2_MASK /* Scheduling Error 2 */ +#define FDCAN_TTIR_ELC_SHIFT (14U) +#define FDCAN_TTIR_ELC_MASK (0x1U << FDCAN_TTIR_ELC_SHIFT) /* 0x00004000 */ +#define FDCAN_TTIR_ELC FDCAN_TTIR_ELC_MASK /* Error Level Changed */ +#define FDCAN_TTIR_IWT_SHIFT (15U) +#define FDCAN_TTIR_IWT_MASK (0x1U << FDCAN_TTIR_IWT_SHIFT) /* 0x00008000 */ +#define FDCAN_TTIR_IWT FDCAN_TTIR_IWT_MASK /* Initialization Watch Trigger */ +#define FDCAN_TTIR_WT_SHIFT (16U) +#define FDCAN_TTIR_WT_MASK (0x1U << FDCAN_TTIR_WT_SHIFT) /* 0x00010000 */ +#define FDCAN_TTIR_WT FDCAN_TTIR_WT_MASK /* Watch Trigger */ +#define FDCAN_TTIR_AW_SHIFT (17U) +#define FDCAN_TTIR_AW_MASK (0x1U << FDCAN_TTIR_AW_SHIFT) /* 0x00020000 */ +#define FDCAN_TTIR_AW FDCAN_TTIR_AW_MASK /* Application Watchdog */ +#define FDCAN_TTIR_CER_SHIFT (18U) +#define FDCAN_TTIR_CER_MASK (0x1U << FDCAN_TTIR_CER_SHIFT) /* 0x00040000 */ +#define FDCAN_TTIR_CER FDCAN_TTIR_CER_MASK /* Configuration Error */ + +/* *************** Bit definition for FDCAN_TTIE register *****************/ +#define FDCAN_TTIE_SBCE_SHIFT (0U) +#define FDCAN_TTIE_SBCE_MASK (0x1U << FDCAN_TTIE_SBCE_SHIFT) /* 0x00000001 */ +#define FDCAN_TTIE_SBCE FDCAN_TTIE_SBCE_MASK /* Start of Basic Cycle Interrupt Enable */ +#define FDCAN_TTIE_SMCE_SHIFT (1U) +#define FDCAN_TTIE_SMCE_MASK (0x1U << FDCAN_TTIE_SMCE_SHIFT) /* 0x00000002 */ +#define FDCAN_TTIE_SMCE FDCAN_TTIE_SMCE_MASK /* Start of Matrix Cycle Interrupt Enable */ +#define FDCAN_TTIE_CSME_SHIFT (2U) +#define FDCAN_TTIE_CSME_MASK (0x1U << FDCAN_TTIE_CSME_SHIFT) /* 0x00000004 */ +#define FDCAN_TTIE_CSME FDCAN_TTIE_CSME_MASK /* Change of Synchronization Mode Interrupt Enable */ +#define FDCAN_TTIE_SOGE_SHIFT (3U) +#define FDCAN_TTIE_SOGE_MASK (0x1U << FDCAN_TTIE_SOGE_SHIFT) /* 0x00000008 */ +#define FDCAN_TTIE_SOGE FDCAN_TTIE_SOGE_MASK /* Start of Gap Interrupt Enable */ +#define FDCAN_TTIE_RTMIE_SHIFT (4U) +#define FDCAN_TTIE_RTMIE_MASK (0x1U << FDCAN_TTIE_RTMIE_SHIFT) /* 0x00000010 */ +#define FDCAN_TTIE_RTMIE FDCAN_TTIE_RTMIE_MASK /* Register Time Mark Interrupt Interrupt Enable */ +#define FDCAN_TTIE_TTMIE_SHIFT (5U) +#define FDCAN_TTIE_TTMIE_MASK (0x1U << FDCAN_TTIE_TTMIE_SHIFT) /* 0x00000020 */ +#define FDCAN_TTIE_TTMIE FDCAN_TTIE_TTMIE_MASK /* Trigger Time Mark Event Internal Interrupt Enable */ +#define FDCAN_TTIE_SWEE_SHIFT (6U) +#define FDCAN_TTIE_SWEE_MASK (0x1U << FDCAN_TTIE_SWEE_SHIFT) /* 0x00000040 */ +#define FDCAN_TTIE_SWEE FDCAN_TTIE_SWEE_MASK /* Stop Watch Event Interrupt Enable */ +#define FDCAN_TTIE_GTWE_SHIFT (7U) +#define FDCAN_TTIE_GTWE_MASK (0x1U << FDCAN_TTIE_GTWE_SHIFT) /* 0x00000080 */ +#define FDCAN_TTIE_GTWE FDCAN_TTIE_GTWE_MASK /* Global Time Wrap Interrupt Enable */ +#define FDCAN_TTIE_GTDE_SHIFT (8U) +#define FDCAN_TTIE_GTDE_MASK (0x1U << FDCAN_TTIE_GTDE_SHIFT) /* 0x00000100 */ +#define FDCAN_TTIE_GTDE FDCAN_TTIE_GTDE_MASK /* Global Time Discontinuity Interrupt Enable */ +#define FDCAN_TTIE_GTEE_SHIFT (9U) +#define FDCAN_TTIE_GTEE_MASK (0x1U << FDCAN_TTIE_GTEE_SHIFT) /* 0x00000200 */ +#define FDCAN_TTIE_GTEE FDCAN_TTIE_GTEE_MASK /* Global Time Error Interrupt Enable */ +#define FDCAN_TTIE_TXUE_SHIFT (10U) +#define FDCAN_TTIE_TXUE_MASK (0x1U << FDCAN_TTIE_TXUE_SHIFT) /* 0x00000400 */ +#define FDCAN_TTIE_TXUE FDCAN_TTIE_TXUE_MASK /* Tx Count Underflow Interrupt Enable */ +#define FDCAN_TTIE_TXOE_SHIFT (11U) +#define FDCAN_TTIE_TXOE_MASK (0x1U << FDCAN_TTIE_TXOE_SHIFT) /* 0x00000800 */ +#define FDCAN_TTIE_TXOE FDCAN_TTIE_TXOE_MASK /* Tx Count Overflow Interrupt Enable */ +#define FDCAN_TTIE_SE1E_SHIFT (12U) +#define FDCAN_TTIE_SE1E_MASK (0x1U << FDCAN_TTIE_SE1E_SHIFT) /* 0x00001000 */ +#define FDCAN_TTIE_SE1E FDCAN_TTIE_SE1E_MASK /* Scheduling Error 1 Interrupt Enable */ +#define FDCAN_TTIE_SE2E_SHIFT (13U) +#define FDCAN_TTIE_SE2E_MASK (0x1U << FDCAN_TTIE_SE2E_SHIFT) /* 0x00002000 */ +#define FDCAN_TTIE_SE2E FDCAN_TTIE_SE2E_MASK /* Scheduling Error 2 Interrupt Enable */ +#define FDCAN_TTIE_ELCE_SHIFT (14U) +#define FDCAN_TTIE_ELCE_MASK (0x1U << FDCAN_TTIE_ELCE_SHIFT) /* 0x00004000 */ +#define FDCAN_TTIE_ELCE FDCAN_TTIE_ELCE_MASK /* Error Level Changed Interrupt Enable */ +#define FDCAN_TTIE_IWTE_SHIFT (15U) +#define FDCAN_TTIE_IWTE_MASK (0x1U << FDCAN_TTIE_IWTE_SHIFT) /* 0x00008000 */ +#define FDCAN_TTIE_IWTE FDCAN_TTIE_IWTE_MASK /* Initialization Watch Trigger Interrupt Enable */ +#define FDCAN_TTIE_WTE_SHIFT (16U) +#define FDCAN_TTIE_WTE_MASK (0x1U << FDCAN_TTIE_WTE_SHIFT) /* 0x00010000 */ +#define FDCAN_TTIE_WTE FDCAN_TTIE_WTE_MASK /* Watch Trigger Interrupt Enable */ +#define FDCAN_TTIE_AWE_SHIFT (17U) +#define FDCAN_TTIE_AWE_MASK (0x1U << FDCAN_TTIE_AWE_SHIFT) /* 0x00020000 */ +#define FDCAN_TTIE_AWE FDCAN_TTIE_AWE_MASK /* Application Watchdog Interrupt Enable */ +#define FDCAN_TTIE_CERE_SHIFT (18U) +#define FDCAN_TTIE_CERE_MASK (0x1U << FDCAN_TTIE_CERE_SHIFT) /* 0x00040000 */ +#define FDCAN_TTIE_CERE FDCAN_TTIE_CERE_MASK /* Configuration Error Interrupt Enable */ + +/* *************** Bit definition for FDCAN_TTILS register ****************/ +#define FDCAN_TTILS_SBCS_SHIFT (0U) +#define FDCAN_TTILS_SBCS_MASK (0x1U << FDCAN_TTILS_SBCS_SHIFT) /* 0x00000001 */ +#define FDCAN_TTILS_SBCS FDCAN_TTILS_SBCS_MASK /* Start of Basic Cycle Interrupt Line */ +#define FDCAN_TTILS_SMCS_SHIFT (1U) +#define FDCAN_TTILS_SMCS_MASK (0x1U << FDCAN_TTILS_SMCS_SHIFT) /* 0x00000002 */ +#define FDCAN_TTILS_SMCS FDCAN_TTILS_SMCS_MASK /* Start of Matrix Cycle Interrupt Line */ +#define FDCAN_TTILS_CSMS_SHIFT (2U) +#define FDCAN_TTILS_CSMS_MASK (0x1U << FDCAN_TTILS_CSMS_SHIFT) /* 0x00000004 */ +#define FDCAN_TTILS_CSMS FDCAN_TTILS_CSMS_MASK /* Change of Synchronization Mode Interrupt Line */ +#define FDCAN_TTILS_SOGS_SHIFT (3U) +#define FDCAN_TTILS_SOGS_MASK (0x1U << FDCAN_TTILS_SOGS_SHIFT) /* 0x00000008 */ +#define FDCAN_TTILS_SOGS FDCAN_TTILS_SOGS_MASK /* Start of Gap Interrupt Line */ +#define FDCAN_TTILS_RTMIS_SHIFT (4U) +#define FDCAN_TTILS_RTMIS_MASK (0x1U << FDCAN_TTILS_RTMIS_SHIFT) /* 0x00000010 */ +#define FDCAN_TTILS_RTMIS FDCAN_TTILS_RTMIS_MASK /* Register Time Mark Interrupt Interrupt Line */ +#define FDCAN_TTILS_TTMIS_SHIFT (5U) +#define FDCAN_TTILS_TTMIS_MASK (0x1U << FDCAN_TTILS_TTMIS_SHIFT) /* 0x00000020 */ +#define FDCAN_TTILS_TTMIS FDCAN_TTILS_TTMIS_MASK /* Trigger Time Mark Event Internal Interrupt Line */ +#define FDCAN_TTILS_SWES_SHIFT (6U) +#define FDCAN_TTILS_SWES_MASK (0x1U << FDCAN_TTILS_SWES_SHIFT) /* 0x00000040 */ +#define FDCAN_TTILS_SWES FDCAN_TTILS_SWES_MASK /* Stop Watch Event Interrupt Line */ +#define FDCAN_TTILS_GTWS_SHIFT (7U) +#define FDCAN_TTILS_GTWS_MASK (0x1U << FDCAN_TTILS_GTWS_SHIFT) /* 0x00000080 */ +#define FDCAN_TTILS_GTWS FDCAN_TTILS_GTWS_MASK /* Global Time Wrap Interrupt Line */ +#define FDCAN_TTILS_GTDS_SHIFT (8U) +#define FDCAN_TTILS_GTDS_MASK (0x1U << FDCAN_TTILS_GTDS_SHIFT) /* 0x00000100 */ +#define FDCAN_TTILS_GTDS FDCAN_TTILS_GTDS_MASK /* Global Time Discontinuity Interrupt Line */ +#define FDCAN_TTILS_GTES_SHIFT (9U) +#define FDCAN_TTILS_GTES_MASK (0x1U << FDCAN_TTILS_GTES_SHIFT) /* 0x00000200 */ +#define FDCAN_TTILS_GTES FDCAN_TTILS_GTES_MASK /* Global Time Error Interrupt Line */ +#define FDCAN_TTILS_TXUS_SHIFT (10U) +#define FDCAN_TTILS_TXUS_MASK (0x1U << FDCAN_TTILS_TXUS_SHIFT) /* 0x00000400 */ +#define FDCAN_TTILS_TXUS FDCAN_TTILS_TXUS_MASK /* Tx Count Underflow Interrupt Line */ +#define FDCAN_TTILS_TXOS_SHIFT (11U) +#define FDCAN_TTILS_TXOS_MASK (0x1U << FDCAN_TTILS_TXOS_SHIFT) /* 0x00000800 */ +#define FDCAN_TTILS_TXOS FDCAN_TTILS_TXOS_MASK /* Tx Count Overflow Interrupt Line */ +#define FDCAN_TTILS_SE1S_SHIFT (12U) +#define FDCAN_TTILS_SE1S_MASK (0x1U << FDCAN_TTILS_SE1S_SHIFT) /* 0x00001000 */ +#define FDCAN_TTILS_SE1S FDCAN_TTILS_SE1S_MASK /* Scheduling Error 1 Interrupt Line */ +#define FDCAN_TTILS_SE2S_SHIFT (13U) +#define FDCAN_TTILS_SE2S_MASK (0x1U << FDCAN_TTILS_SE2S_SHIFT) /* 0x00002000 */ +#define FDCAN_TTILS_SE2S FDCAN_TTILS_SE2S_MASK /* Scheduling Error 2 Interrupt Line */ +#define FDCAN_TTILS_ELCS_SHIFT (14U) +#define FDCAN_TTILS_ELCS_MASK (0x1U << FDCAN_TTILS_ELCS_SHIFT) /* 0x00004000 */ +#define FDCAN_TTILS_ELCS FDCAN_TTILS_ELCS_MASK /* Error Level Changed Interrupt Line */ +#define FDCAN_TTILS_IWTS_SHIFT (15U) +#define FDCAN_TTILS_IWTS_MASK (0x1U << FDCAN_TTILS_IWTS_SHIFT) /* 0x00008000 */ +#define FDCAN_TTILS_IWTS FDCAN_TTILS_IWTS_MASK /* Initialization Watch Trigger Interrupt Line */ +#define FDCAN_TTILS_WTS_SHIFT (16U) +#define FDCAN_TTILS_WTS_MASK (0x1U << FDCAN_TTILS_WTS_SHIFT) /* 0x00010000 */ +#define FDCAN_TTILS_WTS FDCAN_TTILS_WTS_MASK /* Watch Trigger Interrupt Line */ +#define FDCAN_TTILS_AWS_SHIFT (17U) +#define FDCAN_TTILS_AWS_MASK (0x1U << FDCAN_TTILS_AWS_SHIFT) /* 0x00020000 */ +#define FDCAN_TTILS_AWS FDCAN_TTILS_AWS_MASK /* Application Watchdog Interrupt Line */ +#define FDCAN_TTILS_CERS_SHIFT (18U) +#define FDCAN_TTILS_CERS_MASK (0x1U << FDCAN_TTILS_CERS_SHIFT) /* 0x00040000 */ +#define FDCAN_TTILS_CERS FDCAN_TTILS_CERS_MASK /* Configuration Error Interrupt Line */ + +/* *************** Bit definition for FDCAN_TTOST register ****************/ +#define FDCAN_TTOST_EL_SHIFT (0U) +#define FDCAN_TTOST_EL_MASK (0x3U << FDCAN_TTOST_EL_SHIFT) /* 0x00000003 */ +#define FDCAN_TTOST_EL FDCAN_TTOST_EL_MASK /* Error Level */ +#define FDCAN_TTOST_MS_SHIFT (2U) +#define FDCAN_TTOST_MS_MASK (0x3U << FDCAN_TTOST_MS_SHIFT) /* 0x0000000C */ +#define FDCAN_TTOST_MS FDCAN_TTOST_MS_MASK /* Master State */ +#define FDCAN_TTOST_SYS_SHIFT (4U) +#define FDCAN_TTOST_SYS_MASK (0x3U << FDCAN_TTOST_SYS_SHIFT) /* 0x00000030 */ +#define FDCAN_TTOST_SYS FDCAN_TTOST_SYS_MASK /* Synchronization State */ +#define FDCAN_TTOST_QGTP_SHIFT (6U) +#define FDCAN_TTOST_QGTP_MASK (0x1U << FDCAN_TTOST_QGTP_SHIFT) /* 0x00000040 */ +#define FDCAN_TTOST_QGTP FDCAN_TTOST_QGTP_MASK /* Quality of Global Time Phase */ +#define FDCAN_TTOST_QCS_SHIFT (7U) +#define FDCAN_TTOST_QCS_MASK (0x1U << FDCAN_TTOST_QCS_SHIFT) /* 0x00000080 */ +#define FDCAN_TTOST_QCS FDCAN_TTOST_QCS_MASK /* Quality of Clock Speed */ +#define FDCAN_TTOST_RTO_SHIFT (8U) +#define FDCAN_TTOST_RTO_MASK (0xFFU << FDCAN_TTOST_RTO_SHIFT) /* 0x0000FF00 */ +#define FDCAN_TTOST_RTO FDCAN_TTOST_RTO_MASK /* Reference Trigger Offset */ +#define FDCAN_TTOST_WGTD_SHIFT (22U) +#define FDCAN_TTOST_WGTD_MASK (0x1U << FDCAN_TTOST_WGTD_SHIFT) /* 0x00400000 */ +#define FDCAN_TTOST_WGTD FDCAN_TTOST_WGTD_MASK /* Wait for Global Time Discontinuity */ +#define FDCAN_TTOST_GFI_SHIFT (23U) +#define FDCAN_TTOST_GFI_MASK (0x1U << FDCAN_TTOST_GFI_SHIFT) /* 0x00800000 */ +#define FDCAN_TTOST_GFI FDCAN_TTOST_GFI_MASK /* Gap Finished Indicator */ +#define FDCAN_TTOST_TMP_SHIFT (24U) +#define FDCAN_TTOST_TMP_MASK (0x7U << FDCAN_TTOST_TMP_SHIFT) /* 0x07000000 */ +#define FDCAN_TTOST_TMP FDCAN_TTOST_TMP_MASK /* Time Master Priority */ +#define FDCAN_TTOST_GSI_SHIFT (27U) +#define FDCAN_TTOST_GSI_MASK (0x1U << FDCAN_TTOST_GSI_SHIFT) /* 0x08000000 */ +#define FDCAN_TTOST_GSI FDCAN_TTOST_GSI_MASK /* Gap Started Indicator */ +#define FDCAN_TTOST_WFE_SHIFT (28U) +#define FDCAN_TTOST_WFE_MASK (0x1U << FDCAN_TTOST_WFE_SHIFT) /* 0x10000000 */ +#define FDCAN_TTOST_WFE FDCAN_TTOST_WFE_MASK /* Wait for Event */ +#define FDCAN_TTOST_AWE_SHIFT (29U) +#define FDCAN_TTOST_AWE_MASK (0x1U << FDCAN_TTOST_AWE_SHIFT) /* 0x20000000 */ +#define FDCAN_TTOST_AWE FDCAN_TTOST_AWE_MASK /* Application Watchdog Event */ +#define FDCAN_TTOST_WECS_SHIFT (30U) +#define FDCAN_TTOST_WECS_MASK (0x1U << FDCAN_TTOST_WECS_SHIFT) /* 0x40000000 */ +#define FDCAN_TTOST_WECS FDCAN_TTOST_WECS_MASK /* Wait for External Clock Synchronization */ +#define FDCAN_TTOST_SPL_SHIFT (31U) +#define FDCAN_TTOST_SPL_MASK (0x1U << FDCAN_TTOST_SPL_SHIFT) /* 0x80000000 */ +#define FDCAN_TTOST_SPL FDCAN_TTOST_SPL_MASK /* Schedule Phase Lock */ + +/* *************** Bit definition for FDCAN_TURNA register ****************/ +#define FDCAN_TURNA_NAV_SHIFT (0U) +#define FDCAN_TURNA_NAV_MASK (0x3FFFFU << FDCAN_TURNA_NAV_SHIFT) /* 0x0003FFFF */ +#define FDCAN_TURNA_NAV FDCAN_TURNA_NAV_MASK /* Numerator Actual Value */ + +/* *************** Bit definition for FDCAN_TTLGT register ****************/ +#define FDCAN_TTLGT_LT_SHIFT (0U) +#define FDCAN_TTLGT_LT_MASK (0xFFFFU << FDCAN_TTLGT_LT_SHIFT) /* 0x0000FFFF */ +#define FDCAN_TTLGT_LT FDCAN_TTLGT_LT_MASK /* Local Time */ +#define FDCAN_TTLGT_GT_SHIFT (16U) +#define FDCAN_TTLGT_GT_MASK (0xFFFFU << FDCAN_TTLGT_GT_SHIFT) /* 0xFFFF0000 */ +#define FDCAN_TTLGT_GT FDCAN_TTLGT_GT_MASK /* Global Time */ + +/* *************** Bit definition for FDCAN_TTCTC register ****************/ +#define FDCAN_TTCTC_CT_SHIFT (0U) +#define FDCAN_TTCTC_CT_MASK (0xFFFFU << FDCAN_TTCTC_CT_SHIFT) /* 0x0000FFFF */ +#define FDCAN_TTCTC_CT FDCAN_TTCTC_CT_MASK /* Cycle Time */ +#define FDCAN_TTCTC_CC_SHIFT (16U) +#define FDCAN_TTCTC_CC_MASK (0x3FU << FDCAN_TTCTC_CC_SHIFT) /* 0x003F0000 */ +#define FDCAN_TTCTC_CC FDCAN_TTCTC_CC_MASK /* Cycle Count */ + +/* *************** Bit definition for FDCAN_TTCPT register ****************/ +#define FDCAN_TTCPT_CCV_SHIFT (0U) +#define FDCAN_TTCPT_CCV_MASK (0x3FU << FDCAN_TTCPT_CCV_SHIFT) /* 0x0000003F */ +#define FDCAN_TTCPT_CCV FDCAN_TTCPT_CCV_MASK /* Cycle Count Value */ +#define FDCAN_TTCPT_SWV_SHIFT (16U) +#define FDCAN_TTCPT_SWV_MASK (0xFFFFU << FDCAN_TTCPT_SWV_SHIFT) /* 0xFFFF0000 */ +#define FDCAN_TTCPT_SWV FDCAN_TTCPT_SWV_MASK /* Stop Watch Value */ + +/* *************** Bit definition for FDCAN_TTCSM register ****************/ +#define FDCAN_TTCSM_CSM_SHIFT (0U) +#define FDCAN_TTCSM_CSM_MASK (0xFFFFU << FDCAN_TTCSM_CSM_SHIFT) /* 0x0000FFFF */ +#define FDCAN_TTCSM_CSM FDCAN_TTCSM_CSM_MASK /* Cycle Sync Mark */ + +/* *************** Bit definition for FDCAN_TTTS register *****************/ +#define FDCAN_TTTS_SWTSEL_SHIFT (0U) +#define FDCAN_TTTS_SWTSEL_MASK (0x3U << FDCAN_TTTS_SWTSEL_SHIFT) /* 0x00000003 */ +#define FDCAN_TTTS_SWTSEL FDCAN_TTTS_SWTSEL_MASK /* Stop watch trigger input selection */ +#define FDCAN_TTTS_EVTSEL_SHIFT (4U) +#define FDCAN_TTTS_EVTSEL_MASK (0x3U << FDCAN_TTTS_EVTSEL_SHIFT) /* 0x00000030 */ +#define FDCAN_TTTS_EVTSEL FDCAN_TTTS_EVTSEL_MASK /* Event trigger input selection */ + +/* ************************************************************************** + * * + * FDCANCCU (Clock Calibration unit) * + * * + * **************************************************************************/ + +/* *************** Bit definition for FDCANCCU_CREL register **************/ +#define FDCANCCU_CREL_DAY_SHIFT (0U) +#define FDCANCCU_CREL_DAY_MASK (0xFFU << FDCANCCU_CREL_DAY_SHIFT) /* 0x000000FF */ +#define FDCANCCU_CREL_DAY FDCANCCU_CREL_DAY_MASK /* Timestamp Day */ +#define FDCANCCU_CREL_MON_SHIFT (8U) +#define FDCANCCU_CREL_MON_MASK (0xFFU << FDCANCCU_CREL_MON_SHIFT) /* 0x0000FF00 */ +#define FDCANCCU_CREL_MON FDCANCCU_CREL_MON_MASK /* Timestamp Month */ +#define FDCANCCU_CREL_YEAR_SHIFT (16U) +#define FDCANCCU_CREL_YEAR_MASK (0xFU << FDCANCCU_CREL_YEAR_SHIFT) /* 0x000F0000 */ +#define FDCANCCU_CREL_YEAR FDCANCCU_CREL_YEAR_MASK /* Timestamp Year */ +#define FDCANCCU_CREL_SUBSTEP_SHIFT (20U) +#define FDCANCCU_CREL_SUBSTEP_MASK (0xFU << FDCANCCU_CREL_SUBSTEP_SHIFT) /* 0x00F00000 */ +#define FDCANCCU_CREL_SUBSTEP FDCANCCU_CREL_SUBSTEP_MASK /* Sub-step of Core release */ +#define FDCANCCU_CREL_STEP_SHIFT (24U) +#define FDCANCCU_CREL_STEP_MASK (0xFU << FDCANCCU_CREL_STEP_SHIFT) /* 0x0F000000 */ +#define FDCANCCU_CREL_STEP FDCANCCU_CREL_STEP_MASK /* Step of Core release */ +#define FDCANCCU_CREL_REL_SHIFT (28U) +#define FDCANCCU_CREL_REL_MASK (0xFU << FDCANCCU_CREL_REL_SHIFT) /* 0xF0000000 */ +#define FDCANCCU_CREL_REL FDCANCCU_CREL_REL_MASK /* Core release */ + +/* *************** Bit definition for FDCANCCU_CCFG register **************/ +#define FDCANCCU_CCFG_TQBT_SHIFT (0U) +#define FDCANCCU_CCFG_TQBT_MASK (0x1FU << FDCANCCU_CCFG_TQBT_SHIFT) /* 0x0000001F */ +#define FDCANCCU_CCFG_TQBT FDCANCCU_CCFG_TQBT_MASK /* Time Quanta per Bit Time */ +#define FDCANCCU_CCFG_BCC_SHIFT (6U) +#define FDCANCCU_CCFG_BCC_MASK (0x1U << FDCANCCU_CCFG_BCC_SHIFT) /* 0x00000040 */ +#define FDCANCCU_CCFG_BCC FDCANCCU_CCFG_BCC_MASK /* Bypass Clock Calibration */ +#define FDCANCCU_CCFG_CFL_SHIFT (7U) +#define FDCANCCU_CCFG_CFL_MASK (0x1U << FDCANCCU_CCFG_CFL_SHIFT) /* 0x00000080 */ +#define FDCANCCU_CCFG_CFL FDCANCCU_CCFG_CFL_MASK /* Calibration Field Length */ +#define FDCANCCU_CCFG_OCPM_SHIFT (8U) +#define FDCANCCU_CCFG_OCPM_MASK (0xFFU << FDCANCCU_CCFG_OCPM_SHIFT) /* 0x0000FF00 */ +#define FDCANCCU_CCFG_OCPM FDCANCCU_CCFG_OCPM_MASK /* Oscillator Clock Periods Minimum */ +#define FDCANCCU_CCFG_CDIV_SHIFT (16U) +#define FDCANCCU_CCFG_CDIV_MASK (0xFU << FDCANCCU_CCFG_CDIV_SHIFT) /* 0x000F0000 */ +#define FDCANCCU_CCFG_CDIV FDCANCCU_CCFG_CDIV_MASK /* Clock Divider */ +#define FDCANCCU_CCFG_SWR_SHIFT (31U) +#define FDCANCCU_CCFG_SWR_MASK (0x1U << FDCANCCU_CCFG_SWR_SHIFT) /* 0x80000000 */ +#define FDCANCCU_CCFG_SWR FDCANCCU_CCFG_SWR_MASK /* Software Reset */ + +/* *************** Bit definition for FDCANCCU_CSTAT register *************/ +#define FDCANCCU_CSTAT_OCPC_SHIFT (0U) +#define FDCANCCU_CSTAT_OCPC_MASK (0x3FFFFU << FDCANCCU_CSTAT_OCPC_SHIFT) /* 0x0003FFFF */ +#define FDCANCCU_CSTAT_OCPC FDCANCCU_CSTAT_OCPC_MASK /* Oscillator Clock Period Counter */ +#define FDCANCCU_CSTAT_TQC_SHIFT (18U) +#define FDCANCCU_CSTAT_TQC_MASK (0x7FFU << FDCANCCU_CSTAT_TQC_SHIFT) /* 0x1FFC0000 */ +#define FDCANCCU_CSTAT_TQC FDCANCCU_CSTAT_TQC_MASK /* Time Quanta Counter */ +#define FDCANCCU_CSTAT_CALS_SHIFT (30U) +#define FDCANCCU_CSTAT_CALS_MASK (0x3U << FDCANCCU_CSTAT_CALS_SHIFT) /* 0xC0000000 */ +#define FDCANCCU_CSTAT_CALS FDCANCCU_CSTAT_CALS_MASK /* Calibration State */ + +/* **************** Bit definition for FDCANCCU_CWD register **************/ +#define FDCANCCU_CWD_WDC_SHIFT (0U) +#define FDCANCCU_CWD_WDC_MASK (0xFFFFU << FDCANCCU_CWD_WDC_SHIFT) /* 0x0000FFFF */ +#define FDCANCCU_CWD_WDC FDCANCCU_CWD_WDC_MASK /* Watchdog Configuration */ +#define FDCANCCU_CWD_WDV_SHIFT (16U) +#define FDCANCCU_CWD_WDV_MASK (0xFFFFU << FDCANCCU_CWD_WDV_SHIFT) /* 0xFFFF0000 */ +#define FDCANCCU_CWD_WDV FDCANCCU_CWD_WDV_MASK /* Watchdog Value */ + +/* **************** Bit definition for FDCANCCU_IR register ***************/ +#define FDCANCCU_IR_CWE_SHIFT (0U) +#define FDCANCCU_IR_CWE_MASK (0x1U << FDCANCCU_IR_CWE_SHIFT) /* 0x00000001 */ +#define FDCANCCU_IR_CWE FDCANCCU_IR_CWE_MASK /* Calibration Watchdog Event */ +#define FDCANCCU_IR_CSC_SHIFT (1U) +#define FDCANCCU_IR_CSC_MASK (0x1U << FDCANCCU_IR_CSC_SHIFT) /* 0x00000002 */ +#define FDCANCCU_IR_CSC FDCANCCU_IR_CSC_MASK /* Calibration State Changed */ + +/* **************** Bit definition for FDCANCCU_IE register ***************/ +#define FDCANCCU_IE_CWEE_SHIFT (0U) +#define FDCANCCU_IE_CWEE_MASK (0x1U << FDCANCCU_IE_CWEE_SHIFT) /* 0x00000001 */ +#define FDCANCCU_IE_CWEE FDCANCCU_IE_CWEE_MASK /* Calibration Watchdog Event Enable */ +#define FDCANCCU_IE_CSCE_SHIFT (1U) +#define FDCANCCU_IE_CSCE_MASK (0x1U << FDCANCCU_IE_CSCE_SHIFT) /* 0x00000002 */ +#define FDCANCCU_IE_CSCE FDCANCCU_IE_CSCE_MASK /* Calibration State Changed Enable */ + +#endif /* __ARCH_ARM_SRC_STM32H7_HARDWARE_STM32_FDCAN_H */ diff --git a/arch/arm/src/stm32h7/stm32.h b/arch/arm/src/stm32h7/stm32.h index 4bcec036d8f..b3b7fe9c057 100644 --- a/arch/arm/src/stm32h7/stm32.h +++ b/arch/arm/src/stm32h7/stm32.h @@ -36,6 +36,7 @@ #include "chip.h" #include "stm32_gpio.h" +#include "stm32_fdcan_sock.h" #include "stm32_fmc.h" #include "stm32_i2c.h" #include "stm32_spi.h" diff --git a/arch/arm/src/stm32h7/stm32_fdcan_sock.c b/arch/arm/src/stm32h7/stm32_fdcan_sock.c new file mode 100644 index 00000000000..269daaf370b --- /dev/null +++ b/arch/arm/src/stm32h7/stm32_fdcan_sock.c @@ -0,0 +1,2529 @@ +/**************************************************************************** + * arch/arm/src/stm32h7/stm32_fdcan_sock.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 +#include +#include +#include +#include + +#ifdef CONFIG_NET_CAN_RAW_TX_DEADLINE +#include +#endif + +#include + +#include "arm_internal.h" +#include "chip.h" +#include "stm32.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* General Configuration ****************************************************/ + +#if !defined(CONFIG_SCHED_WORKQUEUE) +# error Work queue support is required; HPWORK is recommended +#else + +/* If processing is not done at the interrupt level, then work queue support + * is required. + * + * The high-priority work queue is suggested in order to minimize latency of + * critical Rx/Tx transactions on the CAN bus. + */ + +# if defined(CONFIG_STM32H7_FDCAN_HPWORK) +# define CANWORK HPWORK +# elif defined(CONFIG_STM32H7_FDCAN_LPWORK) +# define CANWORK LPWORK +# else +# define CANWORK LPWORK +# endif +#endif + +#ifdef CONFIG_NET_CAN_RAW_TX_DEADLINE +# define TX_TIMEOUT_WQ +#endif + +/* Message RAM Configuration ************************************************/ + +#define WORD_LENGTH 4U + +/* Define number of Rx / Tx elements in message RAM; note that elements are + * given sizes in number of words (4-byte chunks) + * + * Up to 64 Rx elements and 32 Tx elements may be configured per interface + * + * Note there are a total of 2560 words available shared between all FDCAN + * interfaces for Rx, Tx, and filter storage + */ + +#ifdef CONFIG_NET_CAN_CANFD +# define FIFO_ELEMENT_SIZE 18 /* size (in Words) of a FIFO element in message RAM (CANFD_MTU / 4) */ +# define NUM_RX_FIFO0 14 /* 14 elements max for RX FIFO0 */ +# define NUM_RX_FIFO1 0 /* No elements for RX FIFO1 */ +# define NUM_TX_FIFO 7 /* 7 elements max for TX FIFO */ +#else +# define FIFO_ELEMENT_SIZE 4 /* size (in Words) of a FIFO element in message RAM (CAN_MTU / 4) */ +# define NUM_RX_FIFO0 64 /* 64 elements max for RX FIFO0 */ +# define NUM_RX_FIFO1 0 /* No elements for RX FIFO1 */ +# define NUM_TX_FIFO 32 /* 32 elements max for TX FIFO */ +#endif + +/* Intermediate message buffering *******************************************/ + +#define POOL_SIZE 1 + +#ifdef CONFIG_NET_CAN_RAW_TX_DEADLINE +#define MSG_DATA sizeof(struct timeval) +#else +#define MSG_DATA 0 +#endif + +#ifdef CONFIG_NET_CAN_CANFD +# define FRAME_TYPE struct canfd_frame +#else +# define FRAME_TYPE struct can_frame +#endif + +/* CAN Clock Configuration **************************************************/ + +#define STM32_FDCANCLK STM32_HSE_FREQUENCY +#define CLK_FREQ STM32_FDCANCLK +#define PRESDIV_MAX 256 + +/* Interrupts ***************************************************************/ + +#define FDCAN_IR_MASK 0x3fcfffff /* Mask of all non-reserved bits in FDCAN_IR */ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* CAN ID word, as defined by FDCAN device (Note xtd/rtr/esi bit positions) */ + +union can_id_u +{ + volatile uint32_t can_id; + struct + { + volatile uint32_t extid : 29; + volatile uint32_t resex : 3; + }; + struct + { + volatile uint32_t res : 18; + volatile uint32_t stdid : 11; + volatile uint32_t rtr : 1; + volatile uint32_t xtd : 1; + volatile uint32_t esi : 1; + }; +}; + +/* Union of 4 bytes as 1 register */ + +union payload_u +{ + volatile uint32_t word; + struct + { + volatile uint32_t b00 : 8; + volatile uint32_t b01 : 8; + volatile uint32_t b02 : 8; + volatile uint32_t b03 : 8; + }; +}; + +/* Message RAM Structures ***************************************************/ + +/* Rx FIFO Element Header -- RM0433 pg 2536 */ + +union rx_fifo_header_u +{ + struct + { + volatile uint32_t w0; + volatile uint32_t w1; + }; + + struct + { + /* First word */ + + union can_id_u id; + + /* Second word */ + + volatile uint32_t rxts : 16; /* Rx timestamp */ + volatile uint32_t dlc : 4; /* Data length code */ + volatile uint32_t brs : 1; /* Bitrate switching */ + volatile uint32_t fdf : 1; /* FD frame */ + volatile uint32_t res : 2; /* Reserved for Tx Event */ + volatile uint32_t fidx : 7; /* Filter index */ + volatile uint32_t anmf : 1; /* Accepted non-matching frame */ + }; +}; + +/* Tx FIFO Element Header -- RM0433 pg 2538 */ + +union tx_fifo_header_u +{ + struct + { + volatile uint32_t w0; + volatile uint32_t w1; + }; + + struct + { + /* First word */ + + union can_id_u id; + + /* Second word */ + + volatile uint32_t res1 : 16; /* Reserved for Tx Event timestamp */ + volatile uint32_t dlc : 4; /* Data length code */ + volatile uint32_t brs : 1; /* Bitrate switching */ + volatile uint32_t fdf : 1; /* FD frame */ + volatile uint32_t res2 : 1; /* Reserved for Tx Event */ + volatile uint32_t efc : 1; /* Event FIFO control */ + volatile uint32_t mm : 8; /* Message marker (user data; copied to Tx Event) */ + }; +}; + +/* Rx FIFO Element */ + +struct rx_fifo_s +{ + union rx_fifo_header_u header; +#ifdef CONFIG_NET_CAN_CANFD + union payload_u data[16]; /* 64-byte FD payload */ +#else + union payload_u data[2]; /* 8-byte Classic payload */ +#endif +}; + +/* Tx FIFO Element */ + +struct tx_fifo_s +{ + union tx_fifo_header_u header; +#ifdef CONFIG_NET_CAN_CANFD + union payload_u data[16]; /* 64-byte FD payload */ +#else + union payload_u data[2]; /* 8-byte Classic payload */ +#endif +}; + +/* Tx Mailbox Status Tracking */ + +#define TX_ABORT -1 +#define TX_FREE 0 +#define TX_BUSY 1 + +struct txmbstats +{ +#ifdef CONFIG_NET_CAN_RAW_TX_DEADLINE + struct timeval deadline; + struct wdog_s txtimeout; +#endif + int8_t pending; +}; + +/* FDCAN Device hardware configuration **************************************/ + +struct fdcan_config_s +{ + uint32_t tx_pin; /* GPIO configuration for TX */ + uint32_t rx_pin; /* GPIO configuration for RX */ + uint32_t mb_irq[2]; /* FDCAN Interrupt 0, 1 (Rx, Tx) */ +}; + +struct fdcan_bitseg +{ + uint32_t bitrate; + uint8_t sjw; + uint8_t bs1; + uint8_t bs2; + uint8_t prescaler; +}; + +struct fdcan_message_ram +{ + uint32_t filt_stdid_addr; + uint32_t filt_extid_addr; + uint32_t rxfifo0_addr; + uint32_t rxfifo1_addr; + uint32_t txfifo_addr; + uint8_t n_stdfilt; + uint8_t n_extfilt; + uint8_t n_rxfifo0; + uint8_t n_rxfifo1; + uint8_t n_txfifo; +}; + +/* FDCAN device structures **************************************************/ + +#ifdef CONFIG_STM32H7_FDCAN1 +static const struct fdcan_config_s stm32_fdcan0_config = +{ + .tx_pin = GPIO_CAN1_TX, + .rx_pin = GPIO_CAN1_RX, + .mb_irq = + { + STM32_IRQ_FDCAN1_0, + STM32_IRQ_FDCAN1_1, + }, +}; +#endif + +#ifdef CONFIG_STM32H7_FDCAN2 +static const struct fdcan_config_s stm32_fdcan1_config = +{ + .tx_pin = GPIO_CAN2_TX, + .rx_pin = GPIO_CAN2_RX, + .mb_irq = + { + STM32_IRQ_FDCAN2_0, + STM32_IRQ_FDCAN2_1 , + }, +}; +#endif + +#ifdef CONFIG_STM32H7_FDCAN3 +# error "FDCAN3 support not yet added to stm32h7x3xx header files (pinmap, irq, etc.)" +static const struct fdcan_config_s stm32_fdcan2_config = +{ + .tx_pin = GPIO_CAN3_TX, + .rx_pin = GPIO_CAN3_RX, + .mb_irq = + { + STM32_IRQ_FDCAN3_0, + STM32_IRQ_FDCAN3_1 , + }, +}; +#endif + +/* The fdcan_driver_s encapsulates all state information for a single + * hardware interface + */ + +struct fdcan_driver_s +{ + const struct fdcan_config_s *config; /* Pin config */ + uint8_t iface_idx; /* FDCAN interface index (0 or 1) */ + uint32_t base; /* FDCAN base address */ + + struct fdcan_bitseg arbi_timing; /* Timing for arbitration phase */ +#ifdef CONFIG_NET_CAN_CANFD + struct fdcan_bitseg data_timing; /* Timing for data phase */ +#endif + + struct fdcan_message_ram message_ram; /* Start addresses for each reagion of Message RAM */ + struct rx_fifo_s *rx; /* Pointer to Rx FIFO0 in Message RAM */ + struct tx_fifo_s *tx; /* Pointer to Tx mailboxes in Message RAM */ + + /* Work queue configs for deferring interrupt and poll work */ + + struct work_s rxwork; + struct work_s txcwork; + struct work_s txdwork; + struct work_s pollwork; + + uint32_t irflags; /* Used to copy IR flags from IRQ context to work_queue */ + + /* Intermediate storage of Tx / Rx frames outside of Message RAM */ + + uint8_t tx_pool[(sizeof(FRAME_TYPE)+MSG_DATA)*POOL_SIZE]; + uint8_t rx_pool[(sizeof(FRAME_TYPE)+MSG_DATA)*POOL_SIZE]; + + struct net_driver_s dev; /* Interface understood by the network */ + bool bifup; /* true:ifup false:ifdown */ + + struct txmbstats txmb[NUM_TX_FIFO]; /* Track deadline and status of every Tx entry */ +}; + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +#ifdef CONFIG_STM32H7_FDCAN1 +static struct fdcan_driver_s g_fdcan0; +#endif + +#ifdef CONFIG_STM32H7_FDCAN2 +static struct fdcan_driver_s g_fdcan1; +#endif + +#ifdef CONFIG_STM32H7_FDCAN3 +static struct fdcan_driver_s g_fdcan2; +#endif + +static bool g_apb1h_init = false; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* Common TX logic */ + +static bool fdcan_txringfull(FAR struct fdcan_driver_s *priv); +static int fdcan_transmit(FAR struct fdcan_driver_s *priv); +static int fdcan_txpoll(struct net_driver_s *dev); + +/* Helper functions */ + +#ifdef CONFIG_STM32H7_FDCAN_REGDEBUG +static void fdcan_dumpregs(FAR struct fdcan_driver_s *priv); +#endif + +int32_t fdcan_bittiming(struct fdcan_bitseg *timing); + +static void fdcan_apb1hreset(void); +static void fdcan_setinit(uint32_t base, uint32_t init); +static void fdcan_setenable(uint32_t base, uint32_t enable); +static void fdcan_setconfig(uint32_t base, uint32_t config_enable); +static bool fdcan_waitccr_change(uint32_t base, + uint32_t mask, + uint32_t target_state); + +static void fdcan_enable_interrupts(struct fdcan_driver_s *priv); +static void fdcan_disable_interrupts(struct fdcan_driver_s *priv); + +/* Interrupt handling */ + +static void fdcan_receive(FAR struct fdcan_driver_s *priv); +static void fdcan_receive_work(FAR void *arg); +static void fdcan_txdone(FAR struct fdcan_driver_s *priv); +static void fdcan_txdone_work(FAR void *arg); + +static int fdcan_interrupt(int irq, FAR void *context, + FAR void *arg); + +static void fdcan_check_errors(FAR struct fdcan_driver_s *priv); + +/* Watchdog timer expirations */ + +#ifdef TX_TIMEOUT_WQ +static void fdcan_txtimeout_work(FAR void *arg); +static void fdcan_txtimeout_expiry(wdparm_t arg); +#endif + +/* NuttX networking stack callback functions */ + +static int fdcan_ifup(struct net_driver_s *dev); +static int fdcan_ifdown(struct net_driver_s *dev); + +static void fdcan_txavail_work(FAR void *arg); +static int fdcan_txavail(struct net_driver_s *dev); + +#ifdef CONFIG_NETDEV_IOCTL +static int fdcan_netdev_ioctl(struct net_driver_s *dev, int cmd, + unsigned long arg); +#endif + +/* Initialization and Reset */ + +static int fdcan_initialize(struct fdcan_driver_s *priv); +static void fdcan_reset(struct fdcan_driver_s *priv); + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: fdcan_dumpregs + * + * Dump common register values to the console for debugging purposes. + ****************************************************************************/ + +#ifdef CONFIG_STM32H7_FDCAN_REGDEBUG +static void fdcan_dumpregs(FAR struct fdcan_driver_s *priv) +{ + printf("-------------- FDCAN Reg Dump ----------------\n"); + printf("CAN%d Base: 0x%lx\n", priv->iface_idx, priv->base); + + uint32_t regval; + regval = getreg32(priv->base + STM32_FDCAN_CCCR_OFFSET); + printf("CCCR = 0x%lx\n", regval); + regval = getreg32(priv->base + STM32_FDCAN_ECR_OFFSET); + printf("ECR = 0x%lx\n", regval); + + regval = getreg32(priv->base + STM32_FDCAN_NBTP_OFFSET); + printf("NBTP = 0x%lx\n", regval); + regval = getreg32(priv->base + STM32_FDCAN_DBTP_OFFSET); + printf("DBTP = 0x%lx\n", regval); + + regval = getreg32(priv->base + STM32_FDCAN_TXBC_OFFSET); + printf("TXBC = 0x%lx\n", regval); + regval = getreg32(priv->base + STM32_FDCAN_RXF0C_OFFSET); + printf("RXF0C = 0x%lx\n", regval); + + regval = getreg32(priv->base + STM32_FDCAN_TXESC_OFFSET); + printf("TXESC = 0x%lx\n", regval); + regval = getreg32(priv->base + STM32_FDCAN_RXESC_OFFSET); + printf("RXESC = 0x%lx\n", regval); + + regval = getreg32(priv->base + STM32_FDCAN_IE_OFFSET); + printf("IE = 0x%lx\n", regval); + regval = getreg32(priv->base + STM32_FDCAN_ILE_OFFSET); + printf("ILE = 0x%lx\n", regval); + regval = getreg32(priv->base + STM32_FDCAN_ILS_OFFSET); + printf("ILS = 0x%lx\n", regval); + + /* Print out some possibly interesting unhandled interrupts */ + + regval = getreg32(priv->base + STM32_FDCAN_IR_OFFSET); + printf("IR = 0x%lx\n", regval); + + if (regval & FDCAN_IR_PEA || regval & FDCAN_IR_PED) + { + /* Protocol error -- check protocol status register for details */ + + regval = getreg32(priv->base + STM32_FDCAN_PSR_OFFSET); + printf("--PSR.LEC = %d\n", regval & FDCAN_PSR_LEC); + } +} +#endif + +/**************************************************************************** + * Name: fdcan_bittiming + * + * Description: + * Convert desired bitrate to FDCAN bit segment values + * The computed values apply to both data and arbitration phases + * + * Input Parameters: + * timing - structure to store bit timing + * + * Returned Value: + * OK on success; >0 on failure. + ****************************************************************************/ + +int32_t fdcan_bittiming(struct fdcan_bitseg *timing) +{ + /* Implementation ported from PX4's uavcan_drivers/stm32[h7] + * + * Ref. "Automatic Baudrate Detection in CANopen Networks", U. Koppe + * MicroControl GmbH & Co. KG + * CAN in Automation, 2003 + * + * According to the source, optimal quanta per bit are: + * Bitrate Optimal Maximum + * 1000 kbps 8 10 + * 500 kbps 16 17 + * 250 kbps 16 17 + * 125 kbps 16 17 + */ + + const uint32_t target_bitrate = timing->bitrate; + static const int32_t max_bs1 = 16; + static const int32_t max_bs2 = 8; + const uint8_t max_quanta_per_bit = (timing->bitrate >= 1000000) ? 10 : 17; + static const int max_sp_location = 900; + + /* Computing (prescaler * BS): + * BITRATE = 1 / (PRESCALER * (1 / PCLK) * (1 + BS1 + BS2)) + * BITRATE = PCLK / (PRESCALER * (1 + BS1 + BS2)) + * let: + * BS = 1 + BS1 + BS2 + * (BS == total number of time quanta per bit) + * PRESCALER_BS = PRESCALER * BS + * ==> + * PRESCALER_BS = PCLK / BITRATE + */ + + const uint32_t prescaler_bs = CLK_FREQ / target_bitrate; + + /* Find prescaler value such that the number of quanta per bit is highest */ + + uint8_t bs1_bs2_sum = max_quanta_per_bit - 1; + + while ((prescaler_bs % (1 + bs1_bs2_sum)) != 0) + { + if (bs1_bs2_sum <= 2) + { + nerr("Target bitrate too high - no solution possible."); + return 1; /* No solution */ + } + + bs1_bs2_sum--; + } + + const uint32_t prescaler = prescaler_bs / (1 + bs1_bs2_sum); + + if ((prescaler < 1U) || (prescaler > 1024U)) + { + nerr("Target bitrate invalid - bad prescaler."); + return 2; /* No solution */ + } + + /* Now we have a constraint: (BS1 + BS2) == bs1_bs2_sum. + * We need to find the values so that the sample point is as close as + * possible to the optimal value. + * + * Solve[(1 + bs1)/(1 + bs1 + bs2) == 7/8, bs2] + * (Where 7/8 is 0.875, the recommended sample point location) + * {{bs2 -> (1 + bs1)/7}} + * + * Hence: + * bs2 = (1 + bs1) / 7 + * bs1 = (7 * bs1_bs2_sum - 1) / 8 + * + * Sample point location can be computed as follows: + * Sample point location = (1 + bs1) / (1 + bs1 + bs2) + * + * Since the optimal solution is so close to the maximum, we prepare two + * solutions, and then pick the best one: + * - With rounding to nearest + * - With rounding to zero + */ + + /* First attempt with rounding to nearest */ + + uint8_t bs1 = (uint8_t)((7 * bs1_bs2_sum - 1) + 4) / 8; + uint8_t bs2 = (uint8_t)(bs1_bs2_sum - bs1); + uint16_t sample_point_permill = + (uint16_t)(1000 * (1 + bs1) / (1 + bs1 + bs2)); + + if (sample_point_permill > max_sp_location) + { + /* Second attempt with rounding to zero */ + + bs1 = (7 * bs1_bs2_sum - 1) / 8; + bs2 = bs1_bs2_sum - bs1; + } + + bool valid = (bs1 >= 1) && (bs1 <= max_bs1) && (bs2 >= 1) && + (bs2 <= max_bs2); + + /* Final validation + * Helpful Python: + * def sample_point_from_btr(x): + * assert 0b0011110010000000111111000000000 & x == 0 + * ts2,ts1,brp = (x>>20)&7, (x>>16)&15, x&511 + * return (1+ts1+1)/(1+ts1+1+ts2+1) + */ + + if (target_bitrate != (CLK_FREQ / (prescaler * (1 + bs1 + bs2))) || !valid) + { + nerr("Target bitrate invalid - solution does not match."); + return 3; /* Solution not found */ + } + +#ifdef CONFIG_STM32H7_FDCAN_REGDEBUG + ninfo("[fdcan] CLK_FREQ %lu, target_bitrate %lu, prescaler %lu, bs1 %d" + ", bs2 %d\n", CLK_FREQ, target_bitrate, prescaler_bs, bs1 - 1, + bs2 - 1); +#endif + + timing->bs1 = (uint8_t)(bs1 - 1); + timing->bs2 = (uint8_t)(bs2 - 1); + timing->prescaler = (uint16_t)(prescaler - 1); + timing->sjw = 0; /* Which means one */ + + return 0; +} + +/**************************************************************************** + * Function: fdcan_txringfull + * + * Description: + * Check if all of the TX descriptors are in use. + * + * Input Parameters: + * priv - Reference to the driver state structure + * + * Returned Value: + * true is the TX ring is full; false if there are free slots at the + * head index. + * + ****************************************************************************/ + +static bool fdcan_txringfull(FAR struct fdcan_driver_s *priv) +{ + /* TODO: Decide if this needs to be checked every time, or just during init + * Check that we even _have_ a Tx FIFO allocated + */ + + uint32_t regval = getreg32(priv->base + STM32_FDCAN_TXBC_OFFSET); + if ((regval & FDCAN_TXBC_TFQS) == 0) + { + nerr("No Tx FIFO buffers assigned? Check your message RAM config\n"); + return true; + } + + /* Check if the Tx queue is full */ + + regval = getreg32(priv->base + STM32_FDCAN_TXFQS_OFFSET); + if ((regval & FDCAN_TXFQS_TFQF) == FDCAN_TXFQS_TFQF) + { + return true; /* Sorry, out of room, try back later */ + } + + return false; +} + +/**************************************************************************** + * Function: fdcan_transmit + * + * Description: + * Start hardware transmission of the data contained in priv->d_buf. Called + * either from the txdone interrupt handling or from watchdog based polling + * + * Input Parameters: + * priv - Reference to the driver state structure + * + * Returned Value: + * OK on success; a negated errno on failure + * + * Assumptions: + * May or may not be called from an interrupt handler. In either case, + * global interrupts are disabled, either explicitly or indirectly through + * interrupt handling logic. + * + ****************************************************************************/ + +static int fdcan_transmit(FAR struct fdcan_driver_s *priv) +{ + irqstate_t flags = enter_critical_section(); + + /* First, check if there are any slots available in the queue */ + + uint32_t regval = getreg32(priv->base + STM32_FDCAN_TXFQS_OFFSET); + if ((regval & FDCAN_TXFQS_TFQF) == FDCAN_TXFQS_TFQF) + { + /* Tx FIFO / Queue is full */ + + leave_critical_section(flags); + return -EBUSY; + } + + /* Next, get the next available FIFO index from the controller */ + + regval = getreg32(priv->base + STM32_FDCAN_TXFQS_OFFSET); + const uint8_t mbi = (regval & FDCAN_TXFQS_TFQPI) >> + FDCAN_TXFQS_TFQPI_SHIFT; + + /* Now, we can copy the CAN frame to the FIFO (in message RAM) */ + + if (mbi >= NUM_TX_FIFO) + { + nerr("Invalid Tx mailbox index encountered in transmit\n"); + leave_critical_section(flags); + return -EIO; + } + + struct tx_fifo_s *mb = &priv->tx[mbi]; + + /* Setup timeout deadline if enabled */ + +#ifdef CONFIG_NET_CAN_RAW_TX_DEADLINE + int32_t timeout = 0; + struct timespec ts; + clock_systime_timespec(&ts); + + if (priv->dev.d_sndlen > priv->dev.d_len) + { + /* Tx deadline is stored in d_buf after frame data */ + + struct timeval *tv = + (struct timeval *)(priv->dev.d_buf + priv->dev.d_len); + priv->txmb[mbi].deadline = *tv; + timeout = (tv->tv_sec - ts.tv_sec)*CLK_TCK + + ((tv->tv_usec - ts.tv_nsec / 1000)*CLK_TCK) / 1000000; + if (timeout < 0) + { + leave_critical_section(flags); + return 0; /* No transmission for you! */ + } + } + else + { + /* Default TX deadline defined in NET_CAN_RAW_DEFAULT_TX_DEADLINE */ + + if (CONFIG_NET_CAN_RAW_DEFAULT_TX_DEADLINE > 0) + { + timeout = ((CONFIG_NET_CAN_RAW_DEFAULT_TX_DEADLINE / 1000000) + *CLK_TCK); + priv->txmb[mbi].deadline.tv_sec = ts.tv_sec + + CONFIG_NET_CAN_RAW_DEFAULT_TX_DEADLINE / 1000000; + priv->txmb[mbi].deadline.tv_usec = (ts.tv_nsec / 1000) + + CONFIG_NET_CAN_RAW_DEFAULT_TX_DEADLINE % 1000000; + } + else + { + priv->txmb[mbi].deadline.tv_sec = 0; + priv->txmb[mbi].deadline.tv_usec = 0; + } + } +#endif + + /* Attempt to write frame */ + + union tx_fifo_header_u header; + + if (priv->dev.d_len == sizeof(struct can_frame)) + { + struct can_frame *frame = (struct can_frame *)priv->dev.d_buf; + + if (frame->can_id & CAN_EFF_FLAG) + { + header.id.xtd = 1; + header.id.extid = frame->can_id & CAN_EFF_MASK; + } + else + { + header.id.xtd = 0; + header.id.stdid = frame->can_id & CAN_SFF_MASK; + } + + header.id.esi = frame->can_id & CAN_ERR_FLAG ? 1 : 0; + header.id.rtr = frame->can_id & CAN_RTR_FLAG ? 1 : 0; + header.dlc = frame->can_dlc; + header.brs = 0; /* No bitrate switching */ + header.fdf = 0; /* Classic CAN frame, not CAN-FD */ + header.efc = 0; /* Don't store Tx events */ + header.mm = mbi; /* Mailbox Marker for our own use; just store FIFO index */ + + /* Store into message RAM */ + + mb->header.w0 = header.w0; + mb->header.w1 = header.w1; + mb->data[0].word = *(uint32_t *)&frame->data[0]; + mb->data[1].word = *(uint32_t *)&frame->data[4]; + } +#ifdef CONFIG_NET_CAN_CANFD + else /* CAN FD frame */ + { + struct canfd_frame *frame = (struct canfd_frame *)priv->dev.d_buf; + + if (frame->can_id & CAN_EFF_FLAG) + { + header.id.xtd = 1; + header.id.extid = frame->can_id & CAN_EFF_MASK; + } + else + { + header.id.xtd = 0; + header.id.stdid = frame->can_id & CAN_SFF_MASK; + } + + const bool brs = + (priv->arbi_timing.bitrate == priv->data_timing.bitrate) ? 0 : 1; + + header.id.esi = (frame->can_id & CAN_ERR_FLAG) ? 1 : 0; + header.id.rtr = (frame->can_id & CAN_RTR_FLAG) ? 1 : 0; + header.dlc = len_to_can_dlc[frame->len]; + header.brs = brs; /* Bitrate switching */ + header.fdf = 1; /* CAN-FD frame */ + header.efc = 0; /* Don't store Tx events */ + header.mm = mbi; /* Mailbox Marker for our own use; just store FIFO index */ + + /* Store into message RAM */ + + mb->header.w1 = header.w1; + mb->header.w0 = header.w0; + + uint32_t *frame_data_word = (uint32_t *)&frame->data[0]; + + for (int i = 0; i < (frame->len + 4 - 1) / 4; i++) + { + mb->data[i].word = frame_data_word[i]; + } + } +#endif + + /* GO - Submit the transmission request for this element */ + + putreg32(1 << mbi, priv->base + STM32_FDCAN_TXBAR_OFFSET); + + /* Increment statistics */ + + NETDEV_TXPACKETS(&priv->dev); + + priv->txmb[mbi].pending = TX_BUSY; + +#ifdef TX_TIMEOUT_WQ + /* Setup the TX timeout watchdog (perhaps restarting the timer) */ + + if (timeout > 0) + { + wd_start(&priv->txmb[mbi].txtimeout, timeout + 1, + fdcan_txtimeout_expiry, (wdparm_t)priv); + } +#endif + + leave_critical_section(flags); + + return OK; +} + +/**************************************************************************** + * Function: fdcan_txpoll + * + * Description: + * The transmitter is available, check if the network has any outgoing + * packets ready to send. This is a callback from devif_poll(). + * devif_poll() may be called: + * + * 1. When the preceding TX packet send is complete, + * 2. When the preceding TX packet send timesout and the interface is reset + * 3. During normal TX polling + * + * Input Parameters: + * dev - Reference to the NuttX driver state structure + * + * Returned Value: + * OK on success; a negated errno on failure + * + * Assumptions: + * May or may not be called from an interrupt handler. In either case, + * global interrupts are disabled, either explicitly or indirectly through + * interrupt handling logic. + * + ****************************************************************************/ + +static int fdcan_txpoll(struct net_driver_s *dev) +{ + FAR struct fdcan_driver_s *priv = + (FAR struct fdcan_driver_s *)dev->d_private; + + /* If the polling resulted in data that should be sent out on the network, + * the field d_len is set to a value > 0. + */ + + if (priv->dev.d_len > 0) + { + if (!devif_loopback(&priv->dev)) + { + /* Send the packet */ + + fdcan_transmit(priv); + + /* Check if there is room in the device to hold another packet. If + * not, return a non-zero value to terminate the poll. + */ + + if (fdcan_txringfull(priv)) + { + return -EBUSY; + } + } + } + + /* If zero is returned, the polling will continue until all connections + * have been examined. + */ + + return 0; +} + +/**************************************************************************** + * Function: fdcan_receive + * + * Description: + * An interrupt was received indicating the availability of a new RX packet + * Schedule the message receipt and socket notification + * + * Input Parameters: + * priv - Reference to the driver state structure + * + ****************************************************************************/ + +static void fdcan_receive(FAR struct fdcan_driver_s *priv) +{ + /* Check the interrupt value to determine which FIFO to read */ + + uint32_t regval = getreg32(priv->base + STM32_FDCAN_IR_OFFSET); + + const uint32_t ir_fifo0 = FDCAN_IR_RF0N | FDCAN_IR_RF0F; + const uint32_t ir_fifo1 = FDCAN_IR_RF1N | FDCAN_IR_RF1F; + + if (regval & ir_fifo0) + { + regval = ir_fifo0; + } + else if (regval & ir_fifo1) + { + regval = ir_fifo1; + } + else + { + nerr("ERROR: Bad RX IR flags"); + return; + } + + /* Store the Rx FIFO IR flags for use in the deferred work function */ + + priv->irflags = regval; + + /* Write the corresponding interrupt bits to reset these interrupts */ + + putreg32(regval, priv->base + STM32_FDCAN_IR_OFFSET); + + /* Schedule the actual Rx work immediately from HPWORK context */ + + work_queue(CANWORK, &priv->rxwork, fdcan_receive_work, priv, 0); +} + +/**************************************************************************** + * Function: fdcan_receive_work + * + * Description: + * An frame was received; read the frame into the intermediate rx_pool and + * notify the upper-half driver. + * While we're here, also check for errors and timeouts. + * + * Input Parameters: + * priv - Reference to the driver state structure + * + * Returned Value: + * None + * + * Assumptions: + * Scheduled in worker thread (HPWORK / LPWORK) + * + ****************************************************************************/ + +static void fdcan_receive_work(FAR void *arg) +{ + irqstate_t flags = enter_critical_section(); + + FAR struct fdcan_driver_s *priv = (FAR struct fdcan_driver_s *)arg; + + /* Check which FIFO triggered this work */ + + uint32_t irflags = priv->irflags; + + const uint32_t ir_fifo0 = FDCAN_IR_RF0N | FDCAN_IR_RF0F; + const uint32_t ir_fifo1 = FDCAN_IR_RF1N | FDCAN_IR_RF1F; + uint8_t fifo_id; + + if (irflags & ir_fifo0) + { + fifo_id = 0; + } + else if (irflags & ir_fifo1) + { + fifo_id = 1; + } + else + { + nerr("ERROR: Bad RX IR flags"); + leave_critical_section(flags); + return; + } + + /* Bitwise register definitions are the same for FIFO 0/1 + * + * FDCAN_RXFnC_F0S: Rx FIFO Size + * FDCAN_RXFnS_RF0L: Rx Message Lost + * FDCAN_RXFnS_F0FL: Rx FIFO Fill Level + * FDCAN_RXFnS_F0GI: Rx FIFO Get Index + * + * So we will use only the RX FIFO0 register definitions for simplicity + */ + + uint32_t offset_rxfnc = (fifo_id == 0) ? STM32_FDCAN_RXF0C_OFFSET + : STM32_FDCAN_RXF1C_OFFSET; + uint32_t offset_rxfns = (fifo_id == 0) ? STM32_FDCAN_RXF0S_OFFSET + : STM32_FDCAN_RXF1S_OFFSET; + uint32_t offset_rxfna = (fifo_id == 0) ? STM32_FDCAN_RXF0A_OFFSET + : STM32_FDCAN_RXF1A_OFFSET; + + volatile uint32_t *const rxfnc = (uint32_t *)(priv->base + offset_rxfnc); + volatile uint32_t *const rxfns = (uint32_t *)(priv->base + offset_rxfns); + volatile uint32_t *const rxfna = (uint32_t *)(priv->base + offset_rxfna); + + /* Check number of elements in message RAM allocated to this FIFO */ + + if ((*rxfnc & FDCAN_RXF0C_F0S) == 0) + { + nerr("ERROR: No RX FIFO elements allocated"); + leave_critical_section(flags); + return; + } + + /* Check for message lost; count an error */ + + if ((*rxfns & FDCAN_RXF0S_RF0L) != 0) + { + NETDEV_RXERRORS(&priv->dev); + } + + /* Check number of elements available (fill level) */ + + const uint8_t n_elem = (*rxfns & FDCAN_RXF0S_F0FL); + + if (n_elem == 0) + { + nerr("RX interrupt but 0 frames available"); + leave_critical_section(flags); + return; + } + + struct rx_fifo_s *rf = NULL; + + while ((*rxfns & FDCAN_RXF0S_F0FL) > 0) + { + /* Copy the frame from message RAM */ + + const uint8_t index = (*rxfns & FDCAN_RXF0S_F0GI) >> + FDCAN_RXF0S_F0GI_SHIFT; + + rf = &priv->rx[index]; + + /* Read the frame contents */ + +#ifdef CONFIG_NET_CAN_CANFD + if (rf->header.fdf) /* CAN FD frame */ + { + struct canfd_frame *frame = (struct canfd_frame *)priv->rx_pool; + + if (rf->header.id.xtd) + { + frame->can_id = CAN_EFF_MASK & rf->header.id.extid; + frame->can_id |= CAN_EFF_FLAG; + } + else + { + frame->can_id = CAN_SFF_MASK & rf->header.id.stdid; + } + + if (rf->header.id.rtr) + { + frame->can_id |= CAN_RTR_FLAG; + } + + frame->len = can_dlc_to_len[rf->header.dlc]; + + uint32_t *frame_data_word = (uint32_t *)&frame->data[0]; + + for (int i = 0; i < (frame->len + 4 - 1) / 4; i++) + { + frame_data_word[i] = rf->data[i].word; + } + + /* Acknowledge receipt of this FIFO element */ + + putreg32(index, rxfna); + + /* Copy the buffer pointer to priv->dev + * Set amount of data in priv->dev.d_len + */ + + priv->dev.d_len = sizeof(struct canfd_frame); + priv->dev.d_buf = (uint8_t *)frame; + } + else /* CAN 2.0 Frame */ +#endif + { + struct can_frame *frame = (struct can_frame *)priv->rx_pool; + + if (rf->header.id.xtd) + { + frame->can_id = CAN_EFF_MASK & rf->header.id.extid; + frame->can_id |= CAN_EFF_FLAG; + } + else + { + frame->can_id = CAN_SFF_MASK & rf->header.id.stdid; + } + + if (rf->header.id.rtr) + { + frame->can_id |= CAN_RTR_FLAG; + } + + frame->can_dlc = rf->header.dlc; + + *(uint32_t *)&frame->data[0] = rf->data[0].word; + *(uint32_t *)&frame->data[4] = rf->data[1].word; + + /* Acknowledge receipt of this FIFO element */ + + putreg32(index, rxfna); + + /* Copy the buffer pointer to priv->dev + * Set amount of data in priv->dev.d_len + */ + + priv->dev.d_len = sizeof(struct can_frame); + priv->dev.d_buf = (uint8_t *)frame; + } + + /* Send to socket interface */ + + can_input(&priv->dev); + + /* Update iface statistics */ + + NETDEV_RXPACKETS(&priv->dev); + + /* Point the packet buffer back to the next Tx buffer that will be + * used during the next write. If the write queue is full, then + * this will point at an active buffer, which must not be written + * to. This is OK because devif_poll won't be called unless the + * queue is not full. + */ + + priv->dev.d_buf = priv->tx_pool; + } + + /* Check for errors and abort-transmission requests */ + + fdcan_check_errors(priv); + + leave_critical_section(flags); +} + +/**************************************************************************** + * Function: fdcan_txdone + * + * Description: + * An interrupt was received indicating that the last TX packet(s) is done + * + * Input Parameters: + * priv - Reference to the driver state structure + * + * Returned Value: + * None + * + * Assumptions: + * Called from interrupt context + * + ****************************************************************************/ + +static void fdcan_txdone(FAR struct fdcan_driver_s *priv) +{ + /* Read and reset the interrupt flag */ + + uint32_t ir = getreg32(priv->base + STM32_FDCAN_IR_OFFSET); + if (ir & FDCAN_IR_TC) + { + putreg32(FDCAN_IR_TC, priv->base + STM32_FDCAN_IR_OFFSET); + } + else + { + nerr("Unexpected FCAN interrupt on line 1\n"); + return; + } + + /* Schedule to perform the TX timeout processing on the worker thread */ + + work_queue(CANWORK, &priv->txdwork, fdcan_txdone_work, priv, 0); +} + +/**************************************************************************** + * Function: fdcan_txdone_work + * + * Description: + * Process completed transmissions, including canceling their watchdog + * timers if applicable + * + * Input Parameters: + * priv - Reference to the driver state structure + * + * Returned Value: + * None + * + * Assumptions: + * Scheduled in worker thread (HPWORK / LPWORK) + * + ****************************************************************************/ + +static void fdcan_txdone_work(FAR void *arg) +{ + irqstate_t flags = enter_critical_section(); + + FAR struct fdcan_driver_s *priv = (FAR struct fdcan_driver_s *)arg; + + /* Update counters for successful transmissions */ + + for (uint8_t i = 0; i < NUM_TX_FIFO; i++) + { + if ((getreg32(priv->base + STM32_FDCAN_TXBTO_OFFSET) & (1 << i)) > 0) + { + /* Transmission Occurred in buffer i + * (Not necessarily a 'new' transmission, however) + * Check that it's a new transmission, not a previously handled + * transmission + */ + + struct txmbstats *txi = &priv->txmb[i]; + + if (txi->pending == TX_BUSY) + { + /* This is a transmission that just now completed */ + + NETDEV_TXDONE(&priv->dev); + + txi->pending = TX_FREE; + +#ifdef TX_TIMEOUT_WQ + /* We are here because a transmission completed, so the + * corresponding watchdog can be canceled. + */ + + wd_cancel(&priv->txmb[i].txtimeout); +#endif + } + } + } + + /* Check for errors and abort-transmission requests */ + + fdcan_check_errors(priv); + + /* There should be space for a new TX in any event + * Poll the network for new data to transmit + */ + + devif_poll(&priv->dev, fdcan_txpoll); + + leave_critical_section(flags); +} + +/**************************************************************************** + * Function: fdcan_interrupt + * + * Description: + * Common handler for all enabled FDCAN interrupts + * + * Input Parameters: + * irq - Number of the IRQ that generated the interrupt + * context - Interrupt register state save info (architecture-specific) + * arg - Unused + * + * Returned Value: + * Zero on success; a negated errno on failure + * + ****************************************************************************/ + +static int fdcan_interrupt(int irq, FAR void *context, + FAR void *arg) +{ + switch (irq) + { +#ifdef CONFIG_STM32H7_FDCAN1 + case STM32_IRQ_FDCAN1_0: + fdcan_receive(&g_fdcan0); + break; + + case STM32_IRQ_FDCAN1_1: + fdcan_txdone(&g_fdcan0); + break; +#endif + +#ifdef CONFIG_STM32H7_FDCAN2 + case STM32_IRQ_FDCAN2_0: + fdcan_receive(&g_fdcan1); + break; + + case STM32_IRQ_FDCAN2_1: + fdcan_txdone(&g_fdcan1); + break; +#endif + +#ifdef CONFIG_STM32H7_FDCAN3 + case STM32_IRQ_FDCAN3_0: + fdcan_receive(&g_fdcan2); + break; + + case STM32_IRQ_FDCAN3_1: + fdcan_txdone(&g_fdcan2); + break; +#endif + + default: + nerr("Unexpected IRQ [%d]\n", irq); + return -EINVAL; + } + + return OK; +} + +/**************************************************************************** + * Function: fdcan_check_errors + * + * Description: + * Check error flags and cancel any timed out transmissions + * + * Input Parameters: + * priv - Reference to the driver state structure + * + * Assumptions: + * May or may not be called from an interrupt handler. In either case, + * global interrupts are disabled, either explicitly or indirectly through + * interrupt handling logic. + * + ****************************************************************************/ + +static void fdcan_check_errors(FAR struct fdcan_driver_s *priv) +{ + /* Read CAN Error Logging counter (This also resets the error counter) */ + + uint32_t regval = getreg32(priv->base + STM32_FDCAN_ECR_OFFSET) + & FDCAN_ECR_CEL; + const uint8_t cel = (uint8_t)(regval >> FDCAN_ECR_CEL_SHIFT); + + if (cel > 0) + { + /* We've had some errors; check the status of the device */ + + regval = getreg32(priv->base + STM32_FDCAN_CCCR_OFFSET); + bool restricted_op_mode = (regval & FDCAN_CCCR_ASM) > 0; + + if (restricted_op_mode) + { + nerr("Tx handler message RAM error -- resctricted mode enabled\n"); + + /* Reset the CCCR.ASM register to exit restricted op mode */ + + putreg32(regval & ~FDCAN_CCCR_ASM, + priv->base + STM32_FDCAN_CCCR_OFFSET); + } + } + + /* Serve abort requests */ + + for (uint8_t i = 0; i < NUM_TX_FIFO; i++) + { + struct txmbstats *txi = &priv->txmb[i]; + + regval = getreg32(priv->base + STM32_FDCAN_TXBRP_OFFSET); + if (txi->pending == TX_ABORT && ((1 << i) & regval)) + { + /* Request to Cancel Tx item */ + + putreg32(1 << i, priv->base + STM32_FDCAN_TXBCR_OFFSET); + txi->pending = TX_FREE; + NETDEV_TXERRORS(&priv->dev); +#ifdef TX_TIMEOUT_WQ + wd_cancel(&priv->txmb[i].txtimeout); +#endif + } + } +} + +#ifdef TX_TIMEOUT_WQ +/**************************************************************************** + * Function: fdcan_txtimeout_work + * + * Description: + * Perform TX timeout related work from the worker thread + * + * Input Parameters: + * arg - The argument passed when work_queue() as called. + * + * Assumptions: + * + ****************************************************************************/ + +static void fdcan_txtimeout_work(FAR void *arg) +{ + FAR struct fdcan_driver_s *priv = (FAR struct fdcan_driver_s *)arg; + + struct timespec ts; + struct timeval *now = (struct timeval *)&ts; + clock_systime_timespec(&ts); + now->tv_usec = ts.tv_nsec / 1000; /* timespec to timeval conversion */ + + /* The watchdog timed out, yet we still check mailboxes in case the + * transmit function transmitted a new frame + */ + + for (int mbi = 0; mbi < NUM_TX_FIFO; mbi++) + { + if (priv->txmb[mbi].deadline.tv_sec != 0 + && (now->tv_sec > priv->txmb[mbi].deadline.tv_sec + || now->tv_usec > priv->txmb[mbi].deadline.tv_usec)) + { + NETDEV_TXTIMEOUTS(&priv->dev); + priv->txmb[mbi].pending = TX_ABORT; + } + } + + fdcan_check_errors(priv); +} + +/**************************************************************************** + * Function: fdcan_txtimeout_expiry + * + * Description: + * Our TX watchdog timed out. Called from the timer interrupt handler. + * + * Input Parameters: + * arg - Pointer to the private FDCAN driver state structure + * + * Assumptions: + * Global interrupts are disabled by the watchdog logic. + * + ****************************************************************************/ + +static void fdcan_txtimeout_expiry(wdparm_t arg) +{ + FAR struct fdcan_driver_s *priv = (FAR struct fdcan_driver_s *)arg; + + /* Schedule to perform the TX timeout processing on the worker thread */ + + work_queue(CANWORK, &priv->txcwork, fdcan_txtimeout_work, priv, 0); +} +#endif + +/**************************************************************************** + * Function: fdcan_apb1hreset + * + * Description: + * Reset the periheral bus clock used by FDCAN + * Note that this will reset all configuration of all FDCAN peripherals + * + ****************************************************************************/ + +static void fdcan_apb1hreset(void) +{ + /* Reset the FDCAN's peripheral bus clock */ + + modifyreg32(STM32_RCC_APB1HRSTR, 0, RCC_APB1HRSTR_FDCANRST); + modifyreg32(STM32_RCC_APB1HRSTR, RCC_APB1HRSTR_FDCANRST, 0); +} + +/**************************************************************************** + * Function: fdcan_setinit + * + * Description: + * Enter / Exit initialization mode + * + * Input Parameters: + * base - The base pointer of the FDCAN peripheral + * init - true: Enter init mode; false: Exit init mode + * + ****************************************************************************/ + +static void fdcan_setinit(uint32_t base, uint32_t init) +{ + if (init) + { + /* Enter hardware initialization mode */ + + modifyreg32(base + STM32_FDCAN_CCCR_OFFSET, 0, FDCAN_CCCR_INIT); + fdcan_waitccr_change(base, FDCAN_CCCR_INIT, FDCAN_CCCR_INIT); + } + else + { + /* Exit hardware initialization mode */ + + modifyreg32(base + STM32_FDCAN_CCCR_OFFSET, FDCAN_CCCR_INIT, 0); + fdcan_waitccr_change(base, FDCAN_CCCR_INIT, 0); + } +} + +/**************************************************************************** + * Function: fdcan_setenable + * + * Description: + * Power On / Power Off the device with the Clock Stop Request bit + * + * Input Parameters: + * base - The base pointer of the FDCAN peripheral + * init - true: Power on the device; false: Power off the device + * + ****************************************************************************/ + +static void fdcan_setenable(uint32_t base, uint32_t enable) +{ + if (enable) + { + /* Clear CSR bit */ + + modifyreg32(base + STM32_FDCAN_CCCR_OFFSET, FDCAN_CCCR_CSR, 0); + fdcan_waitccr_change(base, FDCAN_CCCR_CSA, 0); + } + else + { + /* Set CSR bit */ + + modifyreg32(base + STM32_FDCAN_CCCR_OFFSET, 0, FDCAN_CCCR_CSR); + fdcan_waitccr_change(base, FDCAN_CCCR_CSA, 1); + } +} + +/**************************************************************************** + * Function: fdcan_setconfig + * + * Description: + * Enter / Exit Configuration Changes Enabled mode + * + * Input Parameters: + * base - The base pointer of the FDCAN peripheral + * init - true: Enter config mode; false: Exit config mode + * + ****************************************************************************/ + +static void fdcan_setconfig(uint32_t base, uint32_t config_enable) +{ + if (config_enable) + { + /* Configuration Changes Enabled (CCE) mode */ + + modifyreg32(base + STM32_FDCAN_CCCR_OFFSET, 0, FDCAN_CCCR_CCE); + fdcan_waitccr_change(base, FDCAN_CCCR_CCE, 1); + } + else + { + /* Exit CCE mode */ + + modifyreg32(base + STM32_FDCAN_CCCR_OFFSET, FDCAN_CCCR_CCE, 0); + fdcan_waitccr_change(base, FDCAN_CCCR_CCE, 0); + } +} + +/**************************************************************************** + * Function: fdcan_waitccr_change + * + * Description: + * Wait for the CCR register to accept a requested change. + * Timeout after ~10ms. + * + * Input Parameters: + * base - The base pointer of the FDCAN peripheral + * mask - Mask to apply to the CCR register value + * target_state - Target masked value to wait for + * + * Returned Value: + * true on success; false on timeout + * + ****************************************************************************/ + +static bool fdcan_waitccr_change(uint32_t base, uint32_t mask, + uint32_t target_state) +{ + const unsigned timeout = 1000; + for (unsigned wait_ack = 0; wait_ack < timeout; wait_ack++) + { + const bool state = (getreg32(base + STM32_FDCAN_CCCR_OFFSET) & mask); + if (state == target_state) + { + return true; + } + + up_udelay(10); + } + + return false; +} + +/**************************************************************************** + * Function: fdcan_enable_interrupts + * + * Description: + * Enable all interrupts used by this driver + * + * Input Parameters: + * priv - Pointer to the private FDCAN driver state structure + * + * Assumptions: + * The peripheral is in Configuration Changes Enabled (CCE) mode + * + ****************************************************************************/ + +static void fdcan_enable_interrupts(struct fdcan_driver_s *priv) +{ + /* Enable both interrupt lines at the device level */ + + const uint32_t ile = FDCAN_ILE_EINT0 | FDCAN_ILE_EINT1; + modifyreg32(priv->base + STM32_FDCAN_ILE_OFFSET, 0, ile); + + /* Enable both lines at the NVIC level */ + + up_enable_irq(priv->config->mb_irq[0]); + up_enable_irq(priv->config->mb_irq[1]); +} + +/**************************************************************************** + * Function: fdcan_disable_interrupts + * + * Description: + * Disable all interrupts used by this driver + * + * Input Parameters: + * priv - Pointer to the private FDCAN driver state structure + * + * Assumptions: + * The peripheral is in Configuration Changes Enabled (CCE) mode + * + ****************************************************************************/ + +static void fdcan_disable_interrupts(struct fdcan_driver_s *priv) +{ + /* Disable both lines at the NVIC level */ + + up_disable_irq(priv->config->mb_irq[0]); + up_disable_irq(priv->config->mb_irq[1]); + + /* Disable both interrupt lines at the device level */ + + const uint32_t ile = FDCAN_ILE_EINT0 | FDCAN_ILE_EINT1; + modifyreg32(priv->base + STM32_FDCAN_ILE_OFFSET, ile, 0); +} + +/**************************************************************************** + * Function: fdcan_ifup + * + * Description: + * NuttX Callback: Bring up the CAN interface when a socket is opened + * + * Input Parameters: + * dev - Reference to the NuttX driver state structure + * + * Returned Value: + * None + * + * Assumptions: + * The device is initialized and waiting to be brought online + ****************************************************************************/ + +static int fdcan_ifup(struct net_driver_s *dev) +{ + FAR struct fdcan_driver_s *priv = + (FAR struct fdcan_driver_s *)dev->d_private; + + /* Wake up the device and perform all initialization */ + + irqstate_t flags = enter_critical_section(); + + fdcan_initialize(priv); + + fdcan_setinit(priv->base, 1); + fdcan_setconfig(priv->base, 1); + + /* Enable interrupts (at both device and NVIC level) */ + + fdcan_enable_interrupts(priv); + + /* Leave init mode */ + + fdcan_setinit(priv->base, 0); + +#ifdef CONFIG_STM32H7_FDCAN_REGDEBUG + fdcan_dumpregs(priv); +#endif + + leave_critical_section(flags); + + priv->bifup = true; + + return OK; +} + +/**************************************************************************** + * Function: fdcan_ifdown + * + * Description: + * NuttX Callback: Stop the interface. + * + * Input Parameters: + * dev - Reference to the NuttX driver state structure + * + * Returned Value: + * None + * + * Assumptions: + * + ****************************************************************************/ + +static int fdcan_ifdown(struct net_driver_s *dev) +{ + FAR struct fdcan_driver_s *priv = + (FAR struct fdcan_driver_s *)dev->d_private; + + fdcan_reset(priv); + + priv->bifup = false; + + return OK; +} + +/**************************************************************************** + * Function: fdcan_txavail_work + * + * Description: + * Perform an out-of-cycle poll on the worker thread. + * + * Input Parameters: + * arg - Reference to the NuttX driver state structure (cast to void*) + * + * Returned Value: + * None + * + * Assumptions: + * Called on the higher priority worker thread. + * + ****************************************************************************/ + +static void fdcan_txavail_work(FAR void *arg) +{ + FAR struct fdcan_driver_s *priv = (FAR struct fdcan_driver_s *)arg; + + /* Ignore the notification if the interface is not yet up */ + + net_lock(); + if (priv->bifup) + { + /* Check if there is room in the hardware to hold another outgoing + * packet. + */ + + if (!fdcan_txringfull(priv)) + { + /* There is space for another transfer. Poll the network for + * new XMIT data. + */ + + devif_poll(&priv->dev, fdcan_txpoll); + } + } + + net_unlock(); +} + +/**************************************************************************** + * Function: fdcan_txavail + * + * Description: + * Driver callback invoked when new TX data is available. This is a + * stimulus to perform an out-of-cycle poll and, thereby, reduce the TX + * latency. + * + * Input Parameters: + * dev - Reference to the NuttX driver state structure + * + * Returned Value: + * None + * + * Assumptions: + * Called in normal user mode + * + ****************************************************************************/ + +static int fdcan_txavail(struct net_driver_s *dev) +{ + FAR struct fdcan_driver_s *priv = + (FAR struct fdcan_driver_s *)dev->d_private; + + /* Is our single work structure available? It may not be if there are + * pending interrupt actions and we will have to ignore the Tx + * availability action. + */ + + if (work_available(&priv->pollwork)) + { + /* Schedule to serialize the poll on the worker thread. */ + + fdcan_txavail_work(priv); + } + + return OK; +} + +/**************************************************************************** + * Function: fdcan_netdev_ioctl + * + * Description: + * PHY ioctl command handler + * + * Input Parameters: + * dev - Reference to the NuttX driver state structure + * cmd - ioctl command + * arg - Argument accompanying the command + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + * Assumptions: + * + ****************************************************************************/ + +#ifdef CONFIG_NETDEV_IOCTL +static int fdcan_netdev_ioctl(struct net_driver_s *dev, int cmd, + unsigned long arg) +{ + FAR struct fdcan_driver_s *priv = dev->d_private; + + int ret; + + switch (cmd) + { +#ifdef CONFIG_NETDEV_CAN_BITRATE_IOCTL + case SIOCGCANBITRATE: /* Get bitrate from a CAN controller */ + { + struct can_ioctl_data_s *req = + (struct can_ioctl_data_s *)((uintptr_t)arg); + req->arbi_bitrate = priv->arbi_timing.bitrate / 1000; /* kbit/s */ +#ifdef CONFIG_NET_CAN_CANFD + req->data_bitrate = priv->data_timing.bitrate / 1000; /* kbit/s */ +#else + req->data_bitrate = 0; +#endif + ret = OK; + } + break; + + case SIOCSCANBITRATE: /* Set bitrate of a CAN controller */ + { + struct can_ioctl_data_s *req = + (struct can_ioctl_data_s *)((uintptr_t)arg); + + priv->arbi_timing.bitrate = req->arbi_bitrate * 1000; +#ifdef CONFIG_NET_CAN_CANFD + priv->data_timing.bitrate = req->data_bitrate * 1000; +#endif + + /* Reset CAN controller and start with new timings */ + + ret = fdcan_initialize(priv); + + if (ret == OK) + { + ret = fdcan_ifup(dev); + } + } + break; +#endif /* CONFIG_NETDEV_CAN_BITRATE_IOCTL */ + +#ifdef CONFIG_NETDEV_CAN_FILTER_IOCTL + case SIOCACANEXTFILTER: + { + /* TODO: Add hardware-level filter... */ + + stm32_addextfilter(priv, (FAR struct canioc_extfilter_s *)arg); + } + break; + + case SIOCDCANEXTFILTER: + { + /* TODO: Delete hardware-level filter... */ + + stm32_delextfilter(priv, (FAR struct canioc_extfilter_s *)arg); + } + break; + + case SIOCACANSTDFILTER: + { + /* TODO: Add hardware-level filter... */ + + stm32_addstdfilter(priv, (FAR struct canioc_stdfilter_s *)arg); + } + break; + + case SIOCDCANSTDFILTER: + { + /* TODO: Delete hardware-level filter... */ + + stm32_delstdfilter(priv, (FAR struct canioc_stdfilter_s *)arg); + } + break; +#endif + + default: + ret = -ENOTSUP; + break; + } + + return ret; +} +#endif /* CONFIG_NETDEV_IOCTL */ + +/**************************************************************************** + * Function: fdcan_initialize + * + * Description: + * Initialize FDCAN device + * + * Input Parameters: + * priv - Pointer to the private FDCAN driver state structure + * + * Returned Value: + * OK on success; Negated errno on failure. + * + * Assumptions: + * + ****************************************************************************/ + +int fdcan_initialize(struct fdcan_driver_s *priv) +{ + uint32_t regval; + + irqstate_t flags = enter_critical_section(); + + /* Reset the peripheral clock bus (only do this once) */ + + if (!g_apb1h_init) + { + fdcan_apb1hreset(); + g_apb1h_init = true; + } + + /* Exit Power-down / Sleep mode */ + + fdcan_setenable(priv->base, 1); + + /* Enter Initialization mode */ + + fdcan_setinit(priv->base, 1); + + /* Enter Configuration Changes Enabled mode */ + + fdcan_setconfig(priv->base, 1); + + /* Disable interrupts while we configure the hardware */ + + putreg32(0, priv->base + STM32_FDCAN_IE_OFFSET); + + /* Compute CAN bit timings for this bitrate */ + + /* Nominal / arbitration phase bitrate */ + + if (fdcan_bittiming(&priv->arbi_timing) != OK) + { + fdcan_setinit(priv->base, 0); + leave_critical_section(flags); + return -EIO; + } + +#ifdef CONFIG_STM32H7_FDCAN_REGDEBUG + const fdcan_bitseg *tim = &priv->arbi_timing; + ninfo("[fdcan][arbi] Timings: presc=%u sjw=%u bs1=%u bs2=%u\r\n", + tim->prescaler, tim->sjw, tim->bs1, tim->bs2); +#endif + + /* Set bit timings and prescalers (Nominal bitrate) */ + + regval = ((priv->arbi_timing.sjw << FDCAN_NBTP_NSJW_SHIFT) | + (priv->arbi_timing.bs1 << FDCAN_NBTP_NTSEG1_SHIFT) | + (priv->arbi_timing.bs2 << FDCAN_NBTP_TSEG2_SHIFT) | + (priv->arbi_timing.prescaler << FDCAN_NBTP_NBRP_SHIFT)); + putreg32(regval, priv->base + STM32_FDCAN_NBTP_OFFSET); + +#ifdef CONFIG_NET_CAN_CANFD + /* CAN-FD Data phase bitrate */ + + if (fdcan_bittiming(&priv->data_timing) != OK) + { + fdcan_setinit(priv->base, 0); + leave_critical_section(flags); + return -EIO; + } + +#ifdef CONFIG_STM32H7_FDCAN_REGDEBUG + const fdcan_bitseg *tim = &priv->data_timing; + ninfo("[fdcan][data] Timings: presc=%u sjw=%u bs1=%u bs2=%u\r\n", + tim->prescaler, tim->sjw, tim->bs1, tim->bs2); +#endif + + /* Set bit timings and prescalers (Data bitrate) */ + + regval = ((priv->data_timing.sjw << FDCAN_DBTP_DSJW_SHIFT) | + (priv->data_timing.bs1 << FDCAN_DBTP_DTSEG1_SHIFT) | + (priv->data_timing.bs2 << FDCAN_DBTP_DTSEG2_SHIFT) | + (priv->data_timing.prescaler << FDCAN_DBTP_DBRP_SHIFT)); +#endif /* CONFIG_NET_CAN_CANFD */ + + /* Be sure to fill data-phase register even if we're not using CAN FD */ + + putreg32(regval, priv->base + STM32_FDCAN_DBTP_OFFSET); + + /* Operation Configuration */ + +#ifdef STM32H7_FDCAN_LOOPBACK + /* Enable External Loopback Mode (Rx pin disconnected) (RM0433 pg 2494) */ + + modifyreg32(priv->base + STM32_FDCAN_CCCR_OFFSET, 0, FDCAN_CCCR_TEST); + modifyreg32(priv->base + STM32_FDCAN_TEST_OFFSET, 0, FDCAN_TEST_LBCK); +#endif + +#ifdef STM32H7_FDCAN_LOOPBACK_INTERNAL + /* Enable Bus Monitoring / Restricted Op Mode (RM0433 pg 2492, 2494) */ + + modifyreg32(priv->base + STM32_FDCAN_CCCR_OFFSET, 0, FDCAN_CCCR_MON); +#endif + +#ifdef CONFIG_NET_CAN_CANFD + /* Enable CAN-FD frames, including bitrate switching if needed */ + + modifyreg32(priv->base + STM32_FDCAN_CCCR_OFFSET, 0, FDCAN_CCCR_FDOE); + if (priv->arbi_timing.bitrate != priv->data_timing.bitrate) + { + modifyreg32(priv->base + STM32_FDCAN_CCCR_OFFSET, 0, FDCAN_CCCR_BRSE); + } +#else + /* Disable CAN-FD communications ("classic" CAN only) */ + + modifyreg32(priv->base + STM32_FDCAN_CCCR_OFFSET, FDCAN_CCCR_FDOE, 0); +#endif + +#if 0 + /* Disable Automatic Retransmission of frames upon error + * NOTE: This will even disable automatic retry due to lost arbitration!! + */ + + modifyreg32(priv->base + STM32_FDCAN_CCCR_OFFSET, 0, FDCAN_CCCR_DAR); +#endif + + /* Configure Interrupts */ + + /* Clear all interrupt flags + * Note: A flag is cleared by writing a 1 to the corresponding bit position + */ + + putreg32(FDCAN_IR_MASK, priv->base + STM32_FDCAN_IR_OFFSET); + + /* Enable relevant interrupts */ + + regval = FDCAN_IE_TCE /* Transmit Complete */ + | FDCAN_IE_RF0NE /* Rx FIFO 0 new message */ + | FDCAN_IE_RF0FE /* Rx FIFO 0 FIFO full */ + | FDCAN_IE_RF1NE /* Rx FIFO 1 new message */ + | FDCAN_IE_RF1FE; /* Rx FIFO 1 FIFO full */ + putreg32(regval, priv->base + STM32_FDCAN_IE_OFFSET); + + /* Keep Rx interrupts on Line 0; move Tx to Line 1 + * TC (Tx Complete) interrupt on line 1 + */ + + regval = getreg32(priv->base + STM32_FDCAN_ILS_OFFSET); + regval |= FDCAN_ILS_TCL; + putreg32(FDCAN_ILS_TCL, priv->base + STM32_FDCAN_ILS_OFFSET); + + /* Enable Tx buffer transmission interrupts + * Note: Still need fdcan_enable_interrupts() to set ILE (IR line enable) + */ + + putreg32(FDCAN_TXBTIE_TIE, priv->base + STM32_FDCAN_TXBTIE_OFFSET); + + /* Configure Message RAM + * + * The available 2560 words (10 kiB) of RAM are shared between both FDCAN + * interfaces. It is up to us to ensure each interface has its own non- + * overlapping region of RAM assigned to it by properly assigning the start + * and end addresses for all regions of RAM. + * + * We will give each interface half of the available RAM. + * + * Rx buffers are only used in conjunction with acceptance filters; we + * don't have any specific need for this, so we will only use Rx FIFOs. + * + * Each FIFO can hold up to 64 elements, where each element (for a classic + * CAN 2.0B frame) is up to 4 words long (8 bytes data + header bits) + * + * Let's make use of the full 64 FIFO elements for FIFO0. We have no need + * to separate messages between FIFO0 and FIFO1, so ignore FIFO1 for + * simplicity. + * + * Note that the start addresses given to FDCAN are in terms of _words_, + * not bytes, so when we go to read/write to/from the message RAM, there + * will be a factor of 4 necessary in the address relative to the SA + * register values. + */ + + /* Location of this interface's message RAM - address in CPU memory address + * and relative address (in words) used for configuration + */ + + const uint32_t iface_ram_base = (2560 / 2) * priv->iface_idx; + const uint32_t gl_ram_base = STM32_CANRAM_BASE; + uint32_t ram_offset = iface_ram_base; + + /* Standard ID Filters: Allow space for 128 filters (128 words) */ + + const uint8_t n_stdid = 128; + priv->message_ram.filt_stdid_addr = gl_ram_base + ram_offset * WORD_LENGTH; + + regval = (n_stdid << FDCAN_SIDFC_LSS_SHIFT) & FDCAN_SIDFC_LSS_MASK; + regval |= ram_offset << FDCAN_SIDFC_FLSSA_SHIFT; + putreg32(regval, priv->base + STM32_FDCAN_SIDFC_OFFSET); + ram_offset += n_stdid; + + /* Extended ID Filters: Allow space for 128 filters (128 words) */ + + const uint8_t n_extid = 128; + priv->message_ram.filt_extid_addr = gl_ram_base + ram_offset * WORD_LENGTH; + + regval = (n_extid << FDCAN_XIDFC_LSE_SHIFT) & FDCAN_XIDFC_LSE_MASK; + regval |= ram_offset << FDCAN_XIDFC_FLESA_SHIFT; + putreg32(regval, priv->base + STM32_FDCAN_XIDFC_OFFSET); + ram_offset += n_extid; + + /* Set size of each element in the Rx/Tx buffers and FIFOs */ + +#ifdef CONFIG_NET_CAN_CANFD + /* Set full 64 byte space for every Rx/Tx FIFO element */ + + modifyreg32(priv->base + STM32_FDCAN_RXESC_OFFSET, 0, FDCAN_RXESC_RBDS); /* Rx Buffer */ + modifyreg32(priv->base + STM32_FDCAN_RXESC_OFFSET, 0, FDCAN_RXESC_F0DS); /* Rx FIFO 0 */ + modifyreg32(priv->base + STM32_FDCAN_RXESC_OFFSET, 0, FDCAN_RXESC_F1DS); /* Rx FIFO 1 */ + modifyreg32(priv->base + STM32_FDCAN_TXESC_OFFSET, 0, FDCAN_TXESC_TBDS); /* Tx Buffer */ +#else + putreg32(0, priv->base + STM32_FDCAN_RXESC_OFFSET); /* 8 byte space for every element (Rx buffer, FIFO1, FIFO0) */ + putreg32(0, priv->base + STM32_FDCAN_TXESC_OFFSET); /* 8 byte space for every element (Tx buffer) */ +#endif + + priv->message_ram.n_rxfifo0 = NUM_RX_FIFO0; + priv->message_ram.n_rxfifo1 = NUM_RX_FIFO1; + priv->message_ram.n_txfifo = NUM_TX_FIFO; + + /* Assign Rx Mailbox pointer in the driver structure */ + + priv->message_ram.rxfifo0_addr = gl_ram_base + ram_offset * WORD_LENGTH; + priv->rx = (struct rx_fifo_s *)(priv->message_ram.rxfifo0_addr); + + /* Set Rx FIFO0 size (64 elements max) */ + + regval = (ram_offset << FDCAN_RXF0C_F0SA_SHIFT) & FDCAN_RXF0C_F0SA_MASK; + regval |= (NUM_RX_FIFO0 << FDCAN_RXF0C_F0S_SHIFT) & FDCAN_RXF0C_F0S_MASK; + putreg32(regval, priv->base + STM32_FDCAN_RXF0C_OFFSET); + ram_offset += NUM_RX_FIFO0 * FIFO_ELEMENT_SIZE; + + /* Not using Rx FIFO1 */ + + /* Assign Tx Mailbox pointer in the driver structure */ + + priv->message_ram.txfifo_addr = gl_ram_base + ram_offset * WORD_LENGTH; + priv->tx = (struct tx_fifo_s *)(priv->message_ram.txfifo_addr); + + /* Set Tx FIFO size (32 elements max) */ + + regval = (NUM_TX_FIFO << FDCAN_TXBC_TFQS_SHIFT) & FDCAN_TXBC_TFQS_MASK; + regval &= ~FDCAN_TXBC_TFQM; /* Use FIFO */ + regval |= (ram_offset << FDCAN_TXBC_TBSA_SHIFT) & FDCAN_TXBC_TBSA_MASK; + putreg32(regval, priv->base + STM32_FDCAN_TXBC_OFFSET); + + /* Default filter configuration - Accept all messages into Rx FIFO0 */ + + regval = getreg32(priv->base + STM32_FDCAN_GFC_OFFSET); + regval &= ~FDCAN_GFC_ANFS; /* Accept non-matching stdid frames into FIFO0 */ + regval &= ~FDCAN_GFC_ANFE; /* Accept non-matching extid frames into FIFO0 */ + putreg32(regval, priv->base + STM32_FDCAN_GFC_OFFSET); + +#ifdef CONFIG_STM32H7_FDCAN_REGDEBUG + fdcan_dumpregs(priv); +#endif + + /* Exit Initialization mode */ + + fdcan_setinit(priv->base, 0); + +#ifdef CONFIG_STM32H7_FDCAN_REGDEBUG + fdcan_dumpregs(priv); +#endif + + leave_critical_section(flags); + + return 0; +} + +/**************************************************************************** + * Function: fdcan_reset + * + * Description: + * Put the device in the non-operational, reset state + * + * Input Parameters: + * priv - Pointer to the private FDCAN driver state structure + * + * Returned Value: + * None + * + * Assumptions: + * The device has previously been initialized, including message RAM + ****************************************************************************/ + +static void fdcan_reset(struct fdcan_driver_s *priv) +{ + /* Request Init Mode */ + + irqstate_t flags = enter_critical_section(); + + fdcan_setenable(priv->base, 1); + fdcan_setinit(priv->base, 1); + + /* Enable Configuration Change Mode */ + + fdcan_setconfig(priv->base, 1); + + /* Disable interrupts and clear all interrupt flags */ + + fdcan_disable_interrupts(priv); + + putreg32(FDCAN_IR_MASK, priv->base + STM32_FDCAN_IR_OFFSET); + + /* Clear all message RAM mailboxes if initialized */ + +#ifdef CONFIG_NET_CAN_CANFD + const uint8_t n_data_words = 16; +#else + const uint8_t n_data_words = 2; +#endif + + if (priv->rx) + { + for (uint32_t i = 0; i < NUM_RX_FIFO0; i++) + { + #ifdef CONFIG_STM32H7_FDCAN_REGDEBUG + ninfo("[fdcan] MB RX %i %p\r\n", i, &priv->rx[i]); + #endif + priv->rx[i].header.w1 = 0x0; + priv->rx[i].header.w0 = 0x0; + for (uint8_t j = 0; j < n_data_words; j++) + { + priv->rx[i].data[j].word = 0x0; + } + } + } + + if (priv->tx) + { + for (uint32_t i = 0; i < NUM_TX_FIFO; i++) + { + #ifdef CONFIG_STM32H7_FDCAN_REGDEBUG + ninfo("[fdcan] MB TX %i %p\r\n", i, &priv->tx[i]); + #endif + priv->tx[i].header.w1 = 0x0; + priv->tx[i].header.w0 = 0x0; + for (uint8_t j = 0; j < n_data_words; j++) + { + priv->tx[i].data[j].word = 0x0; + } + } + } + + /* Power off the device -- See RM0433 pg 2493 */ + + fdcan_setinit(priv->base, 0); + fdcan_setenable(priv->base, 0); + + leave_critical_section(flags); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Function: stm32_fdcansockinitialize + * + * Description: + * Initialize the selected CAN peripheral and network (socket) interface + * + * Input Parameters: + * intf - In the case where there are multiple interfaces, this value + * identifies which interface is to be initialized. + * + * Returned Value: + * OK on success; Negated errno on failure. + * + * Assumptions: + * + ****************************************************************************/ + +int stm32_fdcansockinitialize(int intf) +{ + struct fdcan_driver_s *priv; + + switch (intf) + { +#ifdef CONFIG_STM32H7_FDCAN1 + case 0: + priv = &g_fdcan0; + memset(priv, 0, sizeof(struct fdcan_driver_s)); + priv->base = STM32_FDCAN1_BASE; + priv->iface_idx = 0; + priv->config = &stm32_fdcan0_config; + + /* Default bitrate configuration */ + +# ifdef CONFIG_NET_CAN_CANFD + priv->arbi_timing.bitrate = CONFIG_FDCAN1_ARBI_BITRATE; + priv->data_timing.bitrate = CONFIG_FDCAN1_DATA_BITRATE; +# else + priv->arbi_timing.bitrate = CONFIG_FDCAN1_BITRATE; +# endif + break; +#endif + +#ifdef CONFIG_STM32H7_FDCAN2 + case 1: + priv = &g_fdcan1; + memset(priv, 0, sizeof(struct fdcan_driver_s)); + priv->base = STM32_FDCAN2_BASE; + priv->iface_idx = 1; + priv->config = &stm32_fdcan1_config; + + /* Default bitrate configuration */ + +# ifdef CONFIG_NET_CAN_CANFD + priv->arbi_timing.bitrate = CONFIG_FDCAN2_ARBI_BITRATE; + priv->data_timing.bitrate = CONFIG_FDCAN2_DATA_BITRATE; +# else + priv->arbi_timing.bitrate = CONFIG_FDCAN2_BITRATE; +# endif + break; +#endif + +#ifdef CONFIG_STM32H7_FDCAN3 + case 2: + priv = &g_fdcan2 + memset(priv, 0, sizeof(struct fdcan_driver_s)); + priv->base = STM32_FDCAN3_BASE; + priv->iface_idx = 2; + priv->config = &stm32_fdcan2_config; + + /* Default bitrate configuration */ + +# ifdef CONFIG_NET_CAN_CANFD + priv->arbi_timing.bitrate = CONFIG_FDCAN3_ARBI_BITRATE; + priv->data_timing.bitrate = CONFIG_FDCAN3_DATA_BITRATE; +# else + priv->arbi_timing.bitrate = CONFIG_FDCAN3_BITRATE; +# endif + break; +#endif + + default: + return -ENODEV; + } + + if (fdcan_bittiming(&priv->arbi_timing) != OK) + { + printf("ERROR: Invalid CAN timings\n"); + return -1; + } + +#ifdef CONFIG_NET_CAN_CANFD + if (fdcan_bittiming(&priv->data_timing) != OK) + { + printf("ERROR: Invalid CAN data phase timings\n"); + return -1; + } +#endif + + /* Configure the pins we're using to interface to the controller */ + + stm32_configgpio(priv->config->tx_pin); + stm32_configgpio(priv->config->rx_pin); + + /* Attach the fdcan interrupt handlers */ + + if (irq_attach(priv->config->mb_irq[0], fdcan_interrupt, NULL)) + { + /* We could not attach the ISR to the interrupt */ + + printf("ERROR: Failed to attach CAN RX IRQ\n"); + return -EAGAIN; + } + + if (irq_attach(priv->config->mb_irq[1], fdcan_interrupt, NULL)) + { + /* We could not attach the ISR to the interrupt */ + + printf("ERROR: Failed to attach CAN TX IRQ\n"); + return -EAGAIN; + } + + /* Initialize the driver structure */ + + priv->dev.d_ifup = fdcan_ifup; /* I/F up callback */ + priv->dev.d_ifdown = fdcan_ifdown; /* I/F down callback */ + priv->dev.d_txavail = fdcan_txavail; /* New TX data callback */ +#ifdef CONFIG_NETDEV_IOCTL + priv->dev.d_ioctl = fdcan_netdev_ioctl; /* Support CAN ioctl() calls */ +#endif + priv->dev.d_private = (void *)priv; /* Used to recover private state from dev */ + + priv->dev.d_buf = priv->tx_pool; + + priv->rx = NULL; + priv->tx = NULL; + + /* Put the interface in the down state (disable interrupts, power off) */ + + fdcan_ifdown(&priv->dev); + + /* Register the device with the OS so that socket IOCTLs can be performed */ + + netdev_register(&priv->dev, NET_LL_CAN); + +#ifdef CONFIG_STM32H7_FDCAN_REGDEBUG + fdcan_dumpregs(priv); +#endif + + return OK; +} + +/**************************************************************************** + * Name: arm_netinitialize + * + * Description: + * Initialize the CAN device interfaces. If there is more than one device + * interface in the chip, then board-specific logic will have to provide + * this function to determine which, if any, CAN interfaces should be + * initialized. + * + ****************************************************************************/ + +#if !defined(CONFIG_NETDEV_LATEINIT) +void arm_netinitialize(void) +{ +#ifdef CONFIG_STM32H7_FDCAN1 + stm32_fdcansockinitialize(0); +#endif + +#ifdef CONFIG_STM32H7_FDCAN2 + stm32_fdcansockinitialize(1); +#endif + +#ifdef CONFIG_STM32H7_FDCAN3 + stm32_fdcansockinitialize(2); +#endif +} +#endif diff --git a/arch/arm/src/stm32h7/stm32_fdcan_sock.h b/arch/arm/src/stm32h7/stm32_fdcan_sock.h new file mode 100644 index 00000000000..8325cb34187 --- /dev/null +++ b/arch/arm/src/stm32h7/stm32_fdcan_sock.h @@ -0,0 +1,107 @@ +/**************************************************************************** + * arch/arm/src/stm32h7/stm32_fdcan_sock.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_ARM_SRC_STM32H7_STM32_FDCAN_SOCK_H +#define __ARCH_ARM_SRC_STM32H7_STM32_FDCAN_SOCK_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include "hardware/stm32_fdcan.h" + +#ifdef CONFIG_STM32H7_FDCAN + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +#ifndef CONFIG_NETDEV_LATEINIT + +/**************************************************************************** + * Function: arm_netinitialize + * + * Description: + * Initialize the first network interface. If there is more than one + * interface in the chip, then board-specific logic will have to provide + * this function to determine which, if any, CAN interfaces should be + * initialized. Also prototyped in up_internal.h. + * + * Input Parameters: + * None + * + * Returned Value: + * OK on success; Negated errno on failure. + * + * Assumptions: + * Called very early in the initialization sequence. + * + ****************************************************************************/ + +void arm_netinitialize(void); + +#else + +/**************************************************************************** + * Function: stm32_fdcansockinitialize + * + * Description: + * Initialize the CAN controller and driver + * + * Input Parameters: + * intf - In the case where there are multiple CAN interfaces, this value + * identifies which CAN interface is to be initialized. + * + * Returned Value: + * OK on success; Negated errno on failure. + * + * Assumptions: + * + ****************************************************************************/ + +int stm32_fdcansockinitialize(int intf); + +#endif + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +#endif /* __ASSEMBLY__ */ +#endif /* CONFIG_STM32H7_FDCAN */ +#endif /* __ARCH_ARM_SRC_STM32H7_STM32_FDCAN_SOCK_H */ diff --git a/arch/arm/src/stm32h7/stm32h7x3xx_rcc.c b/arch/arm/src/stm32h7/stm32h7x3xx_rcc.c index 9218861409c..c6a5f457b8b 100644 --- a/arch/arm/src/stm32h7/stm32h7x3xx_rcc.c +++ b/arch/arm/src/stm32h7/stm32h7x3xx_rcc.c @@ -432,13 +432,15 @@ static inline void rcc_enableapb1(void) regval |= RCC_APB1LENR_I2C3EN; #endif - /* TODO: ... */ - putreg32(regval, STM32_RCC_APB1LENR); /* Enable APB1L peripherals */ regval = getreg32(STM32_RCC_APB1HENR); - /* TODO: ... */ +#ifdef CONFIG_STM32H7_FDCAN + /* FDCAN clock enable */ + + regval |= RCC_APB1HENR_FDCANEN; +#endif putreg32(regval, STM32_RCC_APB1HENR); /* Enable APB1H peripherals */ } From c29b7424effe95e736f074f88764d387a7034186 Mon Sep 17 00:00:00 2001 From: JacobCrabill Date: Fri, 15 Apr 2022 14:35:40 -0700 Subject: [PATCH 02/43] [BACKPORT] boards/stm32h7: Add socketcan config to nucleo-h743zi2 --- boards/arm/stm32h7/nucleo-h743zi2/README.txt | 1 + .../configs/socketcan/defconfig | 73 +++++++++++++++++++ .../stm32h7/nucleo-h743zi2/include/board.h | 15 ++++ .../nucleo-h743zi2/src/stm32_bringup.c | 16 ++++ 4 files changed, 105 insertions(+) create mode 100644 boards/arm/stm32h7/nucleo-h743zi2/configs/socketcan/defconfig diff --git a/boards/arm/stm32h7/nucleo-h743zi2/README.txt b/boards/arm/stm32h7/nucleo-h743zi2/README.txt index 1dd337acc0a..ffd1bc77b78 100644 --- a/boards/arm/stm32h7/nucleo-h743zi2/README.txt +++ b/boards/arm/stm32h7/nucleo-h743zi2/README.txt @@ -92,6 +92,7 @@ Configurations - Syslog with process name, priority, and timestamp - Process Snapshot with stack usage, cpu usage, and signal information - Interrupt Statistics + - procfs filesystem (required for ifconfig, ifup/ifdown) Networking: - IPv4 Networking diff --git a/boards/arm/stm32h7/nucleo-h743zi2/configs/socketcan/defconfig b/boards/arm/stm32h7/nucleo-h743zi2/configs/socketcan/defconfig new file mode 100644 index 00000000000..5101756e2a0 --- /dev/null +++ b/boards/arm/stm32h7/nucleo-h743zi2/configs/socketcan/defconfig @@ -0,0 +1,73 @@ +# +# 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_NET_ETHERNET is not set +# CONFIG_NET_IPv4 is not set +# CONFIG_STANDARD_SERIAL is not set +CONFIG_ALLOW_GPL_COMPONENTS=y +CONFIG_ARCH="arm" +CONFIG_ARCH_BOARD="nucleo-h743zi2" +CONFIG_ARCH_BOARD_NUCLEO_H743ZI2=y +CONFIG_ARCH_CHIP="stm32h7" +CONFIG_ARCH_CHIP_STM32H743ZI=y +CONFIG_ARCH_CHIP_STM32H7=y +CONFIG_ARCH_STACKDUMP=y +CONFIG_ARMV7M_DCACHE=y +CONFIG_ARMV7M_DCACHE_WRITETHROUGH=y +CONFIG_ARMV7M_DTCM=y +CONFIG_ARMV7M_ICACHE=y +CONFIG_BOARD_LATE_INITIALIZE=y +CONFIG_BOARD_LOOPSPERMSEC=43103 +CONFIG_BUILTIN=y +CONFIG_CANUTILS_CANDUMP=y +CONFIG_CANUTILS_CANSEND=y +CONFIG_CAN_CONNS=2 +CONFIG_DEBUG_ERROR=y +CONFIG_DEBUG_FEATURES=y +CONFIG_DEBUG_INFO=y +CONFIG_DEBUG_NET=y +CONFIG_DEBUG_NET_ERROR=y +CONFIG_DEBUG_NET_INFO=y +CONFIG_DEBUG_NET_WARN=y +CONFIG_DEBUG_SYMBOLS=y +CONFIG_DEBUG_WARN=y +CONFIG_FS_PROCFS=y +CONFIG_INIT_ENTRYPOINT="nsh_main" +CONFIG_INTELHEX_BINARY=y +CONFIG_MM_REGIONS=4 +CONFIG_NET=y +CONFIG_NETDEV_CAN_BITRATE_IOCTL=y +CONFIG_NETDEV_IFINDEX=y +CONFIG_NETDEV_LATEINIT=y +CONFIG_NET_CAN=y +CONFIG_NET_CAN_RAW_DEFAULT_TX_DEADLINE=500 +CONFIG_NET_CAN_RAW_TX_DEADLINE=y +CONFIG_NET_CAN_SOCK_OPTS=y +CONFIG_NSH_BUILTIN_APPS=y +CONFIG_NSH_FILEIOSIZE=512 +CONFIG_NSH_LINELEN=64 +CONFIG_NSH_READLINE=y +CONFIG_PREALLOC_TIMERS=4 +CONFIG_RAMLOG=y +CONFIG_RAMLOG_SYSLOG=y +CONFIG_RAM_SIZE=245760 +CONFIG_RAM_START=0x20010000 +CONFIG_RAW_BINARY=y +CONFIG_RR_INTERVAL=200 +CONFIG_SCHED_HPWORK=y +CONFIG_SCHED_LPWORK=y +CONFIG_SCHED_WAITPID=y +CONFIG_START_DAY=6 +CONFIG_START_MONTH=12 +CONFIG_START_YEAR=2011 +CONFIG_STM32H7_FDCAN1=y +CONFIG_STM32H7_FDCAN2=y +CONFIG_STM32H7_USART3=y +CONFIG_SYSLOG_TIMESTAMP=y +CONFIG_SYSTEM_NSH=y +CONFIG_TASK_NAME_SIZE=0 +CONFIG_USART3_SERIAL_CONSOLE=y diff --git a/boards/arm/stm32h7/nucleo-h743zi2/include/board.h b/boards/arm/stm32h7/nucleo-h743zi2/include/board.h index 2046c389be2..a4def19fccc 100644 --- a/boards/arm/stm32h7/nucleo-h743zi2/include/board.h +++ b/boards/arm/stm32h7/nucleo-h743zi2/include/board.h @@ -1,5 +1,6 @@ /**************************************************************************** * boards/arm/stm32h7/nucleo-h743zi2/include/board.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 @@ -241,6 +242,10 @@ #define STM32_RCC_D3CCIPR_ADCSEL RCC_D3CCIPR_ADCSEL_PLL2 +/* FDCAN 1 2 clock source - HSE (TODO: Not the best choice for this board?) */ + +#define STM32_RCC_D2CCIP1R_FDCANSEL RCC_D2CCIP1R_FDCANSEL_HSE /* FDCAN 1 2 clock source */ + /* FLASH wait states * * ------------ ---------- ----------- @@ -388,6 +393,16 @@ #define GPIO_TIM1_CH3NOUT GPIO_TIM1_CH3NOUT_3 /* PE12 - D39 */ #define GPIO_TIM1_CH4OUT GPIO_TIM1_CH4OUT_2 /* PE14 - D38 */ +/* FDCAN1 */ + +#define GPIO_CAN1_RX GPIO_CAN1_RX_3 /* PD0 */ +#define GPIO_CAN1_TX GPIO_CAN1_TX_3 /* PD1 */ + +/* FDCAN2 */ + +#define GPIO_CAN2_RX GPIO_CAN2_RX_2 /* PB5 - D11 */ +#define GPIO_CAN2_TX GPIO_CAN2_TX_2 /* PB6 - D1 */ + /* DMA **********************************************************************/ #define DMAMAP_SPI3_RX DMAMAP_DMA12_SPI3RX_0 /* DMA1 */ diff --git a/boards/arm/stm32h7/nucleo-h743zi2/src/stm32_bringup.c b/boards/arm/stm32h7/nucleo-h743zi2/src/stm32_bringup.c index 5d81cc4d04d..1a925e19be4 100644 --- a/boards/arm/stm32h7/nucleo-h743zi2/src/stm32_bringup.c +++ b/boards/arm/stm32h7/nucleo-h743zi2/src/stm32_bringup.c @@ -37,6 +37,10 @@ #include "stm32_usbhost.h" #endif +#ifdef CONFIG_STM32H7_FDCAN +#include "stm32_fdcan_sock.h" +#endif + #include "nucleo-h743zi2.h" /**************************************************************************** @@ -172,6 +176,18 @@ int stm32_bringup(void) "ERROR: Failed to start USB monitor: %d\n", ret); } +#endif + +#ifdef CONFIG_NETDEV_LATEINIT + +# ifdef CONFIG_STM32H7_FDCAN1 + stm32_fdcansockinitialize(0); +# endif + +# ifdef CONFIG_STM32H7_FDCAN2 + stm32_fdcansockinitialize(1); +# endif + #endif return OK; From b4b9542d017306d91a0e3ea28a61c786105fd071 Mon Sep 17 00:00:00 2001 From: JacobCrabill Date: Fri, 15 Apr 2022 14:40:00 -0700 Subject: [PATCH 03/43] [BACKPORT] net/netdev: Add CONFIG_NETDEV_CAN_FILTER_IOCTL --- include/net/if.h | 79 ++++++++++++++++++++++++--------------- include/netpacket/can.h | 16 ++++++++ include/nuttx/net/ioctl.h | 8 +++- net/can/Kconfig | 2 +- net/netdev/Kconfig | 9 +++++ net/netdev/netdev_ioctl.c | 20 +++++++++- 6 files changed, 99 insertions(+), 35 deletions(-) diff --git a/include/net/if.h b/include/net/if.h index 28da8d73242..0dde170c008 100644 --- a/include/net/if.h +++ b/include/net/if.h @@ -149,6 +149,20 @@ struct can_ioctl_data_s uint16_t data_samplep; /* Data phase sample point % */ }; +/* Structure passed to add or remove hardware-level CAN ID filters + * SIOCxCANSTDFILTER / SIOCxCANEXTFILTER ioctl commands. + */ + +struct can_ioctl_filter_s +{ + uint32_t fid1; /* 11- or 29-bit ID (context dependent). For dual match or + * for the lower address in a range of addresses */ + uint32_t fid2; /* 11- or 29-bit ID. For dual match, address mask or for + * upper address in address range */ + uint8_t ftype; /* See CAN_FILTER_* definitions */ + uint8_t fprio; /* See CAN_MSGPRIO_* definitions */ +}; + /* There are two forms of the I/F request structure. * One for IPv6 and one for IPv4. * Notice that they are (and must be) cast compatible and really different @@ -159,20 +173,22 @@ struct can_ioctl_data_s struct lifreq { - char lifr_name[IFNAMSIZ]; /* Network device name (e.g. "eth0") */ + char lifr_name[IFNAMSIZ]; /* Network device name (e.g. "eth0") */ + int16_t lifr_ifindex; /* Interface index */ union { - struct sockaddr_storage lifru_addr; /* IP Address */ - struct sockaddr_storage lifru_dstaddr; /* P-to-P Address */ - struct sockaddr_storage lifru_broadaddr; /* Broadcast address */ - struct sockaddr_storage lifru_netmask; /* Netmask */ - struct sockaddr lifru_hwaddr; /* MAC address */ - int lifru_count; /* Number of devices */ - int lifru_mtu; /* MTU size */ - uint8_t lifru_flags; /* Interface flags */ - struct mii_ioctl_notify_s llfru_mii_notify; /* PHY event notification */ - struct mii_ioctl_data_s lifru_mii_data; /* MII request data */ - struct can_ioctl_data_s lifru_can_data; /* CAN bitrate request data */ + struct sockaddr_storage lifru_addr; /* IP Address */ + struct sockaddr_storage lifru_dstaddr; /* P-to-P Address */ + struct sockaddr_storage lifru_broadaddr; /* Broadcast address */ + struct sockaddr_storage lifru_netmask; /* Netmask */ + struct sockaddr lifru_hwaddr; /* MAC address */ + int lifru_count; /* Number of devices */ + int lifru_mtu; /* MTU size */ + uint8_t lifru_flags; /* Interface flags */ + struct mii_ioctl_notify_s llfru_mii_notify; /* PHY event notification */ + struct mii_ioctl_data_s lifru_mii_data; /* MII request data */ + struct can_ioctl_data_s lifru_can_data; /* CAN bitrate request data */ + struct can_ioctl_filter_s lifru_can_filter; /* CAN filter request data */ } lifr_ifru; }; @@ -195,36 +211,37 @@ struct lifreq struct lifconf { - size_t lifc_len; /* Size of buffer */ + size_t lifc_len; /* Size of buffer */ union { - FAR char *lifcu_buf; /* Buffer address */ - FAR struct lifreq *lifcu_req; /* Array of ifreq structures */ + FAR char *lifcu_buf; /* Buffer address */ + FAR struct lifreq *lifcu_req; /* Array of ifreq structures */ } lifc_ifcu; }; -#define lifc_buf lifc_ifcu.lifcu_buf /* Buffer address */ -#define lifc_req lifc_ifcu.lifcu_req /* Array of ifreq structures */ +#define lifc_buf lifc_ifcu.lifcu_buf /* Buffer address */ +#define lifc_req lifc_ifcu.lifcu_req /* Array of ifreq structures */ /* This is the I/F request that should be used with IPv4. */ struct ifreq { - char ifr_name[IFNAMSIZ]; /* Network device name (e.g. "eth0") */ - int16_t ifr_ifindex; /* Interface index */ + char ifr_name[IFNAMSIZ]; /* Network device name (e.g. "eth0") */ + int16_t ifr_ifindex; /* Interface index */ union { - struct sockaddr ifru_addr; /* IP Address */ - struct sockaddr ifru_dstaddr; /* P-to-P Address */ - struct sockaddr ifru_broadaddr; /* Broadcast address */ - struct sockaddr ifru_netmask; /* Netmask */ - struct sockaddr ifru_hwaddr; /* MAC address */ - int ifru_count; /* Number of devices */ - int ifru_mtu; /* MTU size */ - uint8_t ifru_flags; /* Interface flags */ - struct mii_ioctl_notify_s ifru_mii_notify; /* PHY event notification */ - struct mii_ioctl_data_s ifru_mii_data; /* MII request data */ - struct can_ioctl_data_s ifru_can_data; /* CAN bitrate request data */ + struct sockaddr ifru_addr; /* IP Address */ + struct sockaddr ifru_dstaddr; /* P-to-P Address */ + struct sockaddr ifru_broadaddr; /* Broadcast address */ + struct sockaddr ifru_netmask; /* Netmask */ + struct sockaddr ifru_hwaddr; /* MAC address */ + int ifru_count; /* Number of devices */ + int ifru_mtu; /* MTU size */ + uint8_t ifru_flags; /* Interface flags */ + struct mii_ioctl_notify_s ifru_mii_notify; /* PHY event notification */ + struct mii_ioctl_data_s ifru_mii_data; /* MII request data */ + struct can_ioctl_data_s ifru_can_data; /* CAN bitrate request data */ + struct can_ioctl_filter_s ifru_can_filter; /* CAN filter request data */ } ifr_ifru; }; @@ -247,7 +264,7 @@ struct ifreq struct ifconf { - size_t ifc_len; /* Size of buffer */ + size_t ifc_len; /* Size of buffer */ union { FAR char *ifcu_buf; /* Buffer address */ diff --git a/include/netpacket/can.h b/include/netpacket/can.h index 775e0dd05f4..1d1f730cdcd 100644 --- a/include/netpacket/can.h +++ b/include/netpacket/can.h @@ -82,6 +82,22 @@ #define CAN_RAW_TX_DEADLINE (__SO_PROTOCOL + 6) /* Abort frame when deadline passed */ +/* CAN filter support (Hardware level filtering) ****************************/ + +/* Some CAN hardware supports a notion of prioritizing messages that match + * filters. Only two priority levels are currently supported and are encoded + * as defined below: + */ + +#define CAN_MSGPRIO_LOW 0 +#define CAN_MSGPRIO_HIGH 1 + +/* Filter type. Not all CAN hardware will support all filter types. */ + +#define CAN_FILTER_MASK 0 /* Address match under a mask */ +#define CAN_FILTER_DUAL 1 /* Dual address match */ +#define CAN_FILTER_RANGE 2 /* Match a range of addresses */ + /**************************************************************************** * Public Types ****************************************************************************/ diff --git a/include/nuttx/net/ioctl.h b/include/nuttx/net/ioctl.h index 450e7522f8f..6dcec0f2832 100644 --- a/include/nuttx/net/ioctl.h +++ b/include/nuttx/net/ioctl.h @@ -112,8 +112,12 @@ /* SocketCAN ****************************************************************/ -#define SIOCGCANBITRATE _SIOC(0x002C) /* Get bitrate from a CAN controller */ -#define SIOCSCANBITRATE _SIOC(0x002D) /* Set bitrate of a CAN controller */ +#define SIOCGCANBITRATE _SIOC(0x002C) /* Get bitrate from a CAN controller */ +#define SIOCSCANBITRATE _SIOC(0x002D) /* Set bitrate of a CAN controller */ +#define SIOCACANEXTFILTER _SIOC(0x002E) /* Add hardware-level exteneded ID filter */ +#define SIOCDCANEXTFILTER _SIOC(0x002F) /* Delete hardware-level exteneded ID filter */ +#define SIOCACANSTDFILTER _SIOC(0x0030) /* Add hardware-level standard ID filter */ +#define SIOCDCANSTDFILTER _SIOC(0x0031) /* Delete hardware-level standard ID filter */ /**************************************************************************** * Public Type Definitions diff --git a/net/can/Kconfig b/net/can/Kconfig index 45e41c56e20..6a02a0c3d64 100644 --- a/net/can/Kconfig +++ b/net/can/Kconfig @@ -27,7 +27,7 @@ config NET_CAN_HAVE_CANFD default n config CAN_CONNS - int "Number of CAN connections" + int "Max number of CAN socket connections" default 4 ---help--- Maximum number of CAN connections (all tasks). diff --git a/net/netdev/Kconfig b/net/netdev/Kconfig index 6944f5d2e5d..d04b7a38ceb 100644 --- a/net/netdev/Kconfig +++ b/net/netdev/Kconfig @@ -24,6 +24,15 @@ config NETDEV_CAN_BITRATE_IOCTL ---help--- Enable support for ioctl() commands to change CAN bitrate +config NETDEV_CAN_FILTER_IOCTL + bool "Enable CAN filter ioctl()" + default n + select NETDEV_IOCTL + depends on NET_CAN + ---help--- + Enable support for ioctl() commands to add/remove CAN hardware-level + filters (NOTE: Not supported by all drivers) + config NETDEV_WIRELESS_IOCTL bool "Enable Wireless ioctl()" default n diff --git a/net/netdev/netdev_ioctl.c b/net/netdev/netdev_ioctl.c index 1189b55e5a4..368b42a51a0 100644 --- a/net/netdev/netdev_ioctl.c +++ b/net/netdev/netdev_ioctl.c @@ -1083,7 +1083,7 @@ static int netdev_ifr_ioctl(FAR struct socket *psock, int cmd, if (dev && dev->d_ioctl) { struct can_ioctl_data_s *can_bitrate_data = - &req->ifr_ifru.ifru_can_data; + &req->ifr_ifru.ifru_can_data; ret = dev->d_ioctl(dev, cmd, (unsigned long)(uintptr_t)can_bitrate_data); } @@ -1091,6 +1091,24 @@ static int netdev_ifr_ioctl(FAR struct socket *psock, int cmd, break; #endif +#if defined(CONFIG_NETDEV_IOCTL) && defined(CONFIG_NETDEV_CAN_FILTER_IOCTL) + case SIOCACANEXTFILTER: /* Add an extended-ID filter */ + case SIOCDCANEXTFILTER: /* Delete an extended-ID filter */ + case SIOCACANSTDFILTER: /* Add a standard-ID filter */ + case SIOCDCANSTDFILTER: /* Delete a standard-ID filter */ + { + dev = netdev_ifr_dev(req); + if (dev && dev->d_ioctl) + { + struct can_ioctl_filter_s *can_filter = + &req->ifr_ifru.ifru_can_filter; + ret = dev->d_ioctl(dev, cmd, + (unsigned long)(uintptr_t)can_filter); + } + } + break; +#endif + #ifdef CONFIG_NETDEV_IFINDEX case SIOCGIFNAME: /* Get interface name */ { From 101663f15e3393e9de4be3ab3fd1c44e7fd31122 Mon Sep 17 00:00:00 2001 From: JacobCrabill Date: Fri, 15 Apr 2022 14:53:29 -0700 Subject: [PATCH 04/43] [BACKPORT] net/can: Fix CONFIG errors in can_recvmsg --- net/can/can_recvmsg.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/can/can_recvmsg.c b/net/can/can_recvmsg.c index 36bacaecad2..81022edcc9c 100644 --- a/net/can/can_recvmsg.c +++ b/net/can/can_recvmsg.c @@ -410,7 +410,9 @@ static uint16_t can_recvfrom_eventhandler(FAR struct net_driver_s *dev, FAR void *pvpriv, uint16_t flags) { struct can_recvfrom_s *pstate = (struct can_recvfrom_s *)pvpriv; +#if defined(CONFIG_NET_CANPROTO_OPTIONS) || defined(CONFIG_NET_TIMESTAMP) struct can_conn_s *conn = (struct can_conn_s *)pstate->pr_sock->s_conn; +#endif /* 'priv' might be null in some race conditions (?) */ From 6d7fea1d25322925aeef18744ec6a9fdc03b5bd7 Mon Sep 17 00:00:00 2001 From: JacobCrabill Date: Sun, 10 Apr 2022 21:55:09 -0700 Subject: [PATCH 05/43] [BACKPORT] stm32h7: Add FDCAN3_BASE to memorymap.h Note that pinmap.h, irq.h, fdcan.h still need to be updated with proper register definitions for the FDCAN3 peripheral present in STM32H7[2|3][3|5] MCUs --- arch/arm/src/stm32h7/hardware/stm32h7x3xx_memorymap.h | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/src/stm32h7/hardware/stm32h7x3xx_memorymap.h b/arch/arm/src/stm32h7/hardware/stm32h7x3xx_memorymap.h index 9a9b499b275..b1ab7e0d922 100644 --- a/arch/arm/src/stm32h7/hardware/stm32h7x3xx_memorymap.h +++ b/arch/arm/src/stm32h7/hardware/stm32h7x3xx_memorymap.h @@ -116,6 +116,7 @@ #define STM32_MDIOS_BASE 0x40009400 /* 0x40009400 - 0x400097ff MDIOS Section */ #define STM32_FDCAN1_BASE 0x4000a000 /* 0x4000a000 - 0x4000a3ff FDCAN1 Section */ #define STM32_FDCAN2_BASE 0x4000a400 /* 0x4000a400 - 0x4000A7ff FDCAN2 Section */ +#define STM32_FDCAN3_BASE 0x4000D400 /* 0x4000D400 - 0x4000D7FF FDCAN3 Section */ #define STM32_CANCCU_BASE 0x4000a800 /* 0x4000a800 - 0x4000abff CAN CCU Section */ #define STM32_CANRAM_BASE 0x4000ac00 /* 0x4000ac00 - 0x4000d3ff CAN Message RAM */ From 740637766aac503c882d0e0fbe4d029dd18351dc Mon Sep 17 00:00:00 2001 From: JacobCrabill Date: Wed, 30 Mar 2022 12:47:50 -0700 Subject: [PATCH 06/43] [BACKPORT] net: Fix typos, update comments in Kconfigs --- net/Kconfig | 4 ++-- net/can/Kconfig | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/net/Kconfig b/net/Kconfig index 481fa65c6f2..1264e26bd4f 100644 --- a/net/Kconfig +++ b/net/Kconfig @@ -255,7 +255,7 @@ config NETDEV_LATEINIT Normally, networking initialization occur in the later phase of the boot process in the function up_initialize() when it calls the driver initialization function, up_netinitialize(). This - initialization occurs after a sufficient about of the OS has been + initialization occurs after a sufficient amount of the OS has been initialized so that driver registration can be performed, but before the completion of OS initialization and before the first application is started. @@ -271,7 +271,7 @@ config NETDEV_LATEINIT dependencies so that the hardware is not in an appropriate state for up_netinitialize() to be called. - Examples of this latter situation includes such things as network + Examples of this latter situation include such things as network drivers that required some setup via an I2C I/O expander, or network drivers that depend on USB, SPI, I2C, PCI, serial, or other interfaces that may not be ready when up_netinitialize() is normally diff --git a/net/can/Kconfig b/net/can/Kconfig index 6a02a0c3d64..cd36680e506 100644 --- a/net/can/Kconfig +++ b/net/can/Kconfig @@ -11,10 +11,10 @@ config NET_CAN select NET_READAHEAD depends on NET ---help--- - Enable support for SocketCAN sockets that will permit. + Enable support for SocketCAN sockets. - This logic is a WIP. Currently only fragmentary support is - available, not enough to actually do anything of consequence. + This requires a lower-half driver compatible with the SocketCAN + API. if NET_CAN From c7d4b238c2ef872d94b5122591117e241407245f Mon Sep 17 00:00:00 2001 From: JacobCrabill Date: Mon, 23 May 2022 17:41:06 -0700 Subject: [PATCH 07/43] nucleo-h743zi2: Fix socketcan backport (CONFIG renames) --- boards/arm/stm32h7/nucleo-h743zi2/configs/socketcan/defconfig | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/boards/arm/stm32h7/nucleo-h743zi2/configs/socketcan/defconfig b/boards/arm/stm32h7/nucleo-h743zi2/configs/socketcan/defconfig index 5101756e2a0..abd53212898 100644 --- a/boards/arm/stm32h7/nucleo-h743zi2/configs/socketcan/defconfig +++ b/boards/arm/stm32h7/nucleo-h743zi2/configs/socketcan/defconfig @@ -8,7 +8,6 @@ # CONFIG_NET_ETHERNET is not set # CONFIG_NET_IPv4 is not set # CONFIG_STANDARD_SERIAL is not set -CONFIG_ALLOW_GPL_COMPONENTS=y CONFIG_ARCH="arm" CONFIG_ARCH_BOARD="nucleo-h743zi2" CONFIG_ARCH_BOARD_NUCLEO_H743ZI2=y @@ -36,7 +35,6 @@ CONFIG_DEBUG_NET_WARN=y CONFIG_DEBUG_SYMBOLS=y CONFIG_DEBUG_WARN=y CONFIG_FS_PROCFS=y -CONFIG_INIT_ENTRYPOINT="nsh_main" CONFIG_INTELHEX_BINARY=y CONFIG_MM_REGIONS=4 CONFIG_NET=y @@ -71,3 +69,4 @@ CONFIG_SYSLOG_TIMESTAMP=y CONFIG_SYSTEM_NSH=y CONFIG_TASK_NAME_SIZE=0 CONFIG_USART3_SERIAL_CONSOLE=y +CONFIG_USER_ENTRYPOINT="nsh_main" From de18616e2d0e5ec7bf8f360a5f80d034ec4c0a46 Mon Sep 17 00:00:00 2001 From: Alin Jerpelea Date: Mon, 16 Aug 2021 15:16:20 +0200 Subject: [PATCH 08/43] [BACKPORT] include: can: move error.h to apps/canutils This file is used by the libcanutils and can be isolated in apps Signed-off-by: Alin Jerpelea --- include/nuttx/can/error.h | 131 -------------------------------------- 1 file changed, 131 deletions(-) delete mode 100644 include/nuttx/can/error.h diff --git a/include/nuttx/can/error.h b/include/nuttx/can/error.h deleted file mode 100644 index 01ab7e0359c..00000000000 --- a/include/nuttx/can/error.h +++ /dev/null @@ -1,131 +0,0 @@ -/* SPDX-License-Identifier: - * include/nuttx/can/error.h - */ - -/**************************************************************************** - * linux/can/error.h - * - * Definitions of the CAN error messages to be filtered and passed to the - * user. - * - * Author: Oliver Hartkopp - * Copyright (c) 2002-2007 Volkswagen Group Electronic Research - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Volkswagen nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * Alternatively, provided that this notice is retained in full, this - * software may be distributed under the terms of the GNU General - * Public License ("GPL") version 2, in which case the provisions of the - * GPL apply INSTEAD OF those given above. - * - * The provided data structures and external interfaces from this code - * are not restricted to be used by modules with a GPL compatible license. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - ****************************************************************************/ - -#ifndef _UAPI_CAN_ERROR_H -#define _UAPI_CAN_ERROR_H - -#define CAN_ERR_DLC 8 /* dlc for error message frames */ - -/* error class (mask) in can_id */ -#define CAN_ERR_TX_TIMEOUT 0x00000001U /* TX timeout (by netdevice driver) */ -#define CAN_ERR_LOSTARB 0x00000002U /* lost arbitration / data[0] */ -#define CAN_ERR_CRTL 0x00000004U /* controller problems / data[1] */ -#define CAN_ERR_PROT 0x00000008U /* protocol violations / data[2..3] */ -#define CAN_ERR_TRX 0x00000010U /* transceiver status / data[4] */ -#define CAN_ERR_ACK 0x00000020U /* received no ACK on transmission */ -#define CAN_ERR_BUSOFF 0x00000040U /* bus off */ -#define CAN_ERR_BUSERROR 0x00000080U /* bus error (may flood!) */ -#define CAN_ERR_RESTARTED 0x00000100U /* controller restarted */ - -/* arbitration lost in bit ... / data[0] */ -#define CAN_ERR_LOSTARB_UNSPEC 0x00 /* unspecified */ - -/* else bit number in bitstream */ - -/* error status of CAN-controller / data[1] */ -#define CAN_ERR_CRTL_UNSPEC 0x00 /* unspecified */ -#define CAN_ERR_CRTL_RX_OVERFLOW 0x01 /* RX buffer overflow */ -#define CAN_ERR_CRTL_TX_OVERFLOW 0x02 /* TX buffer overflow */ -#define CAN_ERR_CRTL_RX_WARNING 0x04 /* reached warning level for RX errors */ -#define CAN_ERR_CRTL_TX_WARNING 0x08 /* reached warning level for TX errors */ -#define CAN_ERR_CRTL_RX_PASSIVE 0x10 /* reached error passive status RX */ -#define CAN_ERR_CRTL_TX_PASSIVE 0x20 /* reached error passive status TX */ - /* (at least one error counter exceeds */ - /* the protocol-defined level of 127) */ -#define CAN_ERR_CRTL_ACTIVE 0x40 /* recovered to error active state */ - -/* error in CAN protocol (type) / data[2] */ -#define CAN_ERR_PROT_UNSPEC 0x00 /* unspecified */ -#define CAN_ERR_PROT_BIT 0x01 /* single bit error */ -#define CAN_ERR_PROT_FORM 0x02 /* frame format error */ -#define CAN_ERR_PROT_STUFF 0x04 /* bit stuffing error */ -#define CAN_ERR_PROT_BIT0 0x08 /* unable to send dominant bit */ -#define CAN_ERR_PROT_BIT1 0x10 /* unable to send recessive bit */ -#define CAN_ERR_PROT_OVERLOAD 0x20 /* bus overload */ -#define CAN_ERR_PROT_ACTIVE 0x40 /* active error announcement */ -#define CAN_ERR_PROT_TX 0x80 /* error occurred on transmission */ - -/* error in CAN protocol (location) / data[3] */ -#define CAN_ERR_PROT_LOC_UNSPEC 0x00 /* unspecified */ -#define CAN_ERR_PROT_LOC_SOF 0x03 /* start of frame */ -#define CAN_ERR_PROT_LOC_ID28_21 0x02 /* ID bits 28 - 21 (SFF: 10 - 3) */ -#define CAN_ERR_PROT_LOC_ID20_18 0x06 /* ID bits 20 - 18 (SFF: 2 - 0 )*/ -#define CAN_ERR_PROT_LOC_SRTR 0x04 /* substitute RTR (SFF: RTR) */ -#define CAN_ERR_PROT_LOC_IDE 0x05 /* identifier extension */ -#define CAN_ERR_PROT_LOC_ID17_13 0x07 /* ID bits 17-13 */ -#define CAN_ERR_PROT_LOC_ID12_05 0x0f /* ID bits 12-5 */ -#define CAN_ERR_PROT_LOC_ID04_00 0x0e /* ID bits 4-0 */ -#define CAN_ERR_PROT_LOC_RTR 0x0c /* RTR */ -#define CAN_ERR_PROT_LOC_RES1 0x0d /* reserved bit 1 */ -#define CAN_ERR_PROT_LOC_RES0 0x09 /* reserved bit 0 */ -#define CAN_ERR_PROT_LOC_DLC 0x0b /* data length code */ -#define CAN_ERR_PROT_LOC_DATA 0x0a /* data section */ -#define CAN_ERR_PROT_LOC_CRC_SEQ 0x08 /* CRC sequence */ -#define CAN_ERR_PROT_LOC_CRC_DEL 0x18 /* CRC delimiter */ -#define CAN_ERR_PROT_LOC_ACK 0x19 /* ACK slot */ -#define CAN_ERR_PROT_LOC_ACK_DEL 0x1b /* ACK delimiter */ -#define CAN_ERR_PROT_LOC_EOF 0x1a /* end of frame */ -#define CAN_ERR_PROT_LOC_INTERM 0x12 /* intermission */ - -/* error status of CAN-transceiver / data[4] */ - - /* CANH CANL */ -#define CAN_ERR_TRX_UNSPEC 0x00 /* 0000 0000 */ -#define CAN_ERR_TRX_CANH_NO_WIRE 0x04 /* 0000 0100 */ -#define CAN_ERR_TRX_CANH_SHORT_TO_BAT 0x05 /* 0000 0101 */ -#define CAN_ERR_TRX_CANH_SHORT_TO_VCC 0x06 /* 0000 0110 */ -#define CAN_ERR_TRX_CANH_SHORT_TO_GND 0x07 /* 0000 0111 */ -#define CAN_ERR_TRX_CANL_NO_WIRE 0x40 /* 0100 0000 */ -#define CAN_ERR_TRX_CANL_SHORT_TO_BAT 0x50 /* 0101 0000 */ -#define CAN_ERR_TRX_CANL_SHORT_TO_VCC 0x60 /* 0110 0000 */ -#define CAN_ERR_TRX_CANL_SHORT_TO_GND 0x70 /* 0111 0000 */ -#define CAN_ERR_TRX_CANL_SHORT_TO_CANH 0x80 /* 1000 0000 */ - -/* controller specific additional information / data[5..7] */ - -#endif /* _UAPI_CAN_ERROR_H */ From c4ceffbd695374a9bb5747928dff0ced9ed4e0ef Mon Sep 17 00:00:00 2001 From: Michal Lenc Date: Sun, 29 Aug 2021 22:13:18 +0200 Subject: [PATCH 09/43] [BACKPORT] arch/arm/src/imxrt/imxrt_flexcan.c: use SW control to check free MBs CAN_ESR2 register was having problems of havng the correct values when the bus was busy (with 3 and more nods). The register bit fields were incorrectly indicating that there is no free MB and would not updated itself from this state which was causing the applications to freeze on write. This change relies only on a software control which should avoid the problems described above. Signed-off-by: Michal Lenc --- arch/arm/src/imxrt/imxrt_flexcan.c | 58 +++++++++--------------------- 1 file changed, 16 insertions(+), 42 deletions(-) diff --git a/arch/arm/src/imxrt/imxrt_flexcan.c b/arch/arm/src/imxrt/imxrt_flexcan.c index b2ef5dacda7..ee2c2bc02fd 100644 --- a/arch/arm/src/imxrt/imxrt_flexcan.c +++ b/arch/arm/src/imxrt/imxrt_flexcan.c @@ -470,9 +470,6 @@ static void imxrt_setfreeze(uint32_t base, uint32_t freeze); static uint32_t imxrt_waitmcr_change(uint32_t base, uint32_t mask, uint32_t target_state); -static uint32_t imxrt_waitesr2_change(uint32_t base, - uint32_t mask, - uint32_t target_state); static struct mb_s *flexcan_get_mb(FAR struct imxrt_driver_s *priv, uint32_t mbi); @@ -531,10 +528,10 @@ static void imxrt_reset(struct imxrt_driver_s *priv); static bool imxrt_txringfull(FAR struct imxrt_driver_s *priv) { - uint32_t mbi = RXMBCOUNT; + uint32_t mbi = RXMBCOUNT + 1; struct mb_s *mb; - while (mbi < TXMBCOUNT) + while (mbi < TOTALMBCOUNT) { mb = flexcan_get_mb(priv, mbi); if (mb->cs.code != CAN_TXMB_DATAORREMOTE) @@ -583,18 +580,13 @@ static int imxrt_transmit(FAR struct imxrt_driver_s *priv) int32_t timeout; #endif - if ((getreg32(priv->base + IMXRT_CAN_ESR2_OFFSET) & - (CAN_ESR2_IMB | CAN_ESR2_VPS)) == - (CAN_ESR2_IMB | CAN_ESR2_VPS)) - { - mbi = ((getreg32(priv->base + IMXRT_CAN_ESR2_OFFSET) & - CAN_ESR2_LPTM_MASK) >> CAN_ESR2_LPTM_SHIFT); - } - + mbi = RXMBCOUNT + 1; mb_bit = 1 << mbi; while (mbi < TOTALMBCOUNT) { + /* Check whether message buffer is not currently transmitting */ + struct mb_s *mb = flexcan_get_mb(priv, mbi); if (mb->cs.code != CAN_TXMB_DATAORREMOTE) { @@ -771,11 +763,14 @@ static int imxrt_txpoll(struct net_driver_s *dev) { FAR struct imxrt_driver_s *priv = (FAR struct imxrt_driver_s *)dev->d_private; + irqstate_t flags; /* If the polling resulted in data that should be sent out on the network, * the field d_len is set to a value > 0. */ + flags = spin_lock_irqsave(NULL); + if (priv->dev.d_len > 0) { if (!devif_loopback(&priv->dev)) @@ -790,15 +785,16 @@ static int imxrt_txpoll(struct net_driver_s *dev) * not, return a non-zero value to terminate the poll. */ - if (!((getreg32(priv->base + IMXRT_CAN_ESR2_OFFSET) & - (CAN_ESR2_IMB | CAN_ESR2_VPS)) == - (CAN_ESR2_IMB | CAN_ESR2_VPS)) || (imxrt_txringfull(priv))) - { - return -EBUSY; - } + if (imxrt_txringfull(priv)) + { + spin_unlock_irqrestore(NULL, flags); + return -EBUSY; + } } } + spin_unlock_irqrestore(NULL, flags); + /* If zero is returned, the polling will continue until all connections * have been examined. */ @@ -1268,26 +1264,6 @@ static uint32_t imxrt_waitfreezeack_change(uint32_t base, return imxrt_waitmcr_change(base, CAN_MCR_FRZACK, target_state); } -static uint32_t imxrt_waitesr2_change(uint32_t base, uint32_t mask, - uint32_t target_state) -{ - const uint32_t timeout = 1000; - uint32_t wait_ack; - - for (wait_ack = 0; wait_ack < timeout; wait_ack++) - { - uint32_t state = (getreg32(base + IMXRT_CAN_ESR2_OFFSET) & mask); - if (state == target_state) - { - return true; - } - - up_udelay(10); - } - - return false; -} - static struct mb_s *flexcan_get_mb(FAR struct imxrt_driver_s *priv, uint32_t mbi) { @@ -1401,9 +1377,7 @@ static void imxrt_txavail_work(FAR void *arg) * packet. */ - if (imxrt_waitesr2_change(priv->base, - (CAN_ESR2_IMB | CAN_ESR2_VPS), - (CAN_ESR2_IMB | CAN_ESR2_VPS))) + if (!imxrt_txringfull(priv)) { /* No, there is space for another transfer. Poll the network for * new XMIT data. From 9e0c61be7cb8a190bdb8a9d6f3cc77e0042da6e2 Mon Sep 17 00:00:00 2001 From: Michal Lenc Date: Sun, 29 Aug 2021 22:59:14 +0200 Subject: [PATCH 10/43] [BACKPORT] boards/arm/imxrt/teensy-4.x: add option to have CAN3 as can0 This commit adds option for Teensy 4.x board to initialize CAN3 as can0. The reason of this is the CAN FD capability of CAN3. This commit also disables tickless mode support for pikron-bb configuration as this option started causing hard faults which are yet to be solved. Signed-off-by: Michal Lenc --- boards/arm/imxrt/teensy-4.x/Kconfig | 6 ++++++ .../teensy-4.x/configs/pikron-bb/defconfig | 15 +++++++-------- boards/arm/imxrt/teensy-4.x/src/imxrt_flexcan.c | 17 ++++++++++++++++- 3 files changed, 29 insertions(+), 9 deletions(-) diff --git a/boards/arm/imxrt/teensy-4.x/Kconfig b/boards/arm/imxrt/teensy-4.x/Kconfig index 9b330f66afa..74faef1da76 100644 --- a/boards/arm/imxrt/teensy-4.x/Kconfig +++ b/boards/arm/imxrt/teensy-4.x/Kconfig @@ -24,4 +24,10 @@ config TEENSY_41 endchoice # Board configuration +config IMXRT_FLEXCAN3_AS_CAN0 + bool "Initialize CAN3 bus as can0" + ---help--- + This configuration option ensures that if more that one CAN bus is set on + that CAN 3 (with FD capability) will be initialized as can0. + endif diff --git a/boards/arm/imxrt/teensy-4.x/configs/pikron-bb/defconfig b/boards/arm/imxrt/teensy-4.x/configs/pikron-bb/defconfig index de4e35f89b6..2165488d4fd 100644 --- a/boards/arm/imxrt/teensy-4.x/configs/pikron-bb/defconfig +++ b/boards/arm/imxrt/teensy-4.x/configs/pikron-bb/defconfig @@ -9,6 +9,7 @@ # CONFIG_NSH_DISABLE_DATE is not set # CONFIG_NSH_DISABLE_PRINTF is not set # CONFIG_NSH_DISABLE_TRUNCATE is not set +CONFIG_ALLOW_GPL_COMPONENTS=y CONFIG_ARCH="arm" CONFIG_ARCH_BOARD="teensy-4.x" CONFIG_ARCH_BOARD_TEENSY_4X=y @@ -31,11 +32,6 @@ CONFIG_CANUTILS_CANDUMP=y CONFIG_CANUTILS_CANSEND=y CONFIG_CAN_FD=y CONFIG_CLOCK_MONOTONIC=y -CONFIG_DEBUG_ERROR=y -CONFIG_DEBUG_FEATURES=y -CONFIG_DEBUG_FULLOPT=y -CONFIG_DEBUG_SYMBOLS=y -CONFIG_DEBUG_WARN=y CONFIG_DEV_LOOP=y CONFIG_DEV_ZERO=y CONFIG_DRIVERS_VIDEO=y @@ -58,7 +54,11 @@ CONFIG_IDLETHREAD_STACKSIZE=2048 CONFIG_IMXRT_ENET=y CONFIG_IMXRT_ENET_NRXBUFFERS=16 CONFIG_IMXRT_ENET_NTXBUFFERS=8 +CONFIG_IMXRT_FLEXCAN1=y +CONFIG_IMXRT_FLEXCAN2=y CONFIG_IMXRT_FLEXCAN3=y +CONFIG_IMXRT_FLEXCAN3_AS_CAN0=y +CONFIG_IMXRT_FLEXCAN_TXMB=1 CONFIG_IMXRT_LPSPI4=y CONFIG_IMXRT_LPUART1=y CONFIG_IMXRT_SNVS_LPSRTC=y @@ -128,9 +128,8 @@ CONFIG_RAM_START=0x20200000 CONFIG_READLINE_CMD_HISTORY=y CONFIG_RR_INTERVAL=10 CONFIG_SCHED_CPULOAD=y +CONFIG_SCHED_CPULOAD_EXTCLK=y CONFIG_SCHED_LPWORK=y -CONFIG_SCHED_TICKLESS=y -CONFIG_SCHED_TICKLESS_ALARM=y CONFIG_SCHED_USER_IDENTITY=y CONFIG_SCHED_WAITPID=y CONFIG_SERIAL_TERMIOS=y @@ -147,6 +146,6 @@ CONFIG_SYSTEM_PING6=y CONFIG_SYSTEM_PING=y CONFIG_SYSTEM_TEE=y CONFIG_TEENSY_41=y -CONFIG_USEC_PER_TICK=10 +CONFIG_USEC_PER_TICK=1000 CONFIG_USER_ENTRYPOINT="nsh_main" CONFIG_VIDEO_FB=y diff --git a/boards/arm/imxrt/teensy-4.x/src/imxrt_flexcan.c b/boards/arm/imxrt/teensy-4.x/src/imxrt_flexcan.c index 8d08c464c8a..729ce7fe2a8 100644 --- a/boards/arm/imxrt/teensy-4.x/src/imxrt_flexcan.c +++ b/boards/arm/imxrt/teensy-4.x/src/imxrt_flexcan.c @@ -50,6 +50,19 @@ int imxrt_can_setup(void) { int ret; + +#ifdef CONFIG_IMXRT_FLEXCAN3_AS_CAN0 +# ifdef CONFIG_IMXRT_FLEXCAN3 + ret = imxrt_caninitialize(3); + if (ret < 0) + { + canerr("ERROR: Failed to get CAN interface\n"); + return -ENODEV; + } + +# endif +#endif + #ifdef CONFIG_IMXRT_FLEXCAN1 /* Call arm_caninitialize() to get an instance of the CAN interface */ @@ -70,7 +83,8 @@ int imxrt_can_setup(void) } #endif -#ifdef CONFIG_IMXRT_FLEXCAN3 +#ifndef CONFIG_IMXRT_FLEXCAN3_AS_CAN0 +# ifdef CONFIG_IMXRT_FLEXCAN3 ret = imxrt_caninitialize(3); if (ret < 0) { @@ -78,6 +92,7 @@ int imxrt_can_setup(void) return -ENODEV; } +# endif #endif UNUSED(ret); return OK; From 6cd67d6d60657cdd8053c388b0f78b3d5ade774b Mon Sep 17 00:00:00 2001 From: "P.Brier" Date: Tue, 21 Sep 2021 12:28:38 +0200 Subject: [PATCH 11/43] [BACKPORT] Fixed imxrt flexcan driver compilation error due to incorrect scope of variable --- arch/arm/src/imxrt/imxrt_flexcan.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/arch/arm/src/imxrt/imxrt_flexcan.c b/arch/arm/src/imxrt/imxrt_flexcan.c index ee2c2bc02fd..c0b4981a4e7 100644 --- a/arch/arm/src/imxrt/imxrt_flexcan.c +++ b/arch/arm/src/imxrt/imxrt_flexcan.c @@ -1453,7 +1453,7 @@ static int imxrt_ioctl(struct net_driver_s *dev, int cmd, { FAR struct imxrt_driver_s *priv = (FAR struct imxrt_driver_s *)dev->d_private; - + struct flexcan_timeseg data_timing; int ret; switch (cmd) @@ -1499,7 +1499,6 @@ static int imxrt_ioctl(struct net_driver_s *dev, int cmd, if (priv->canfd_capable) { - struct flexcan_timeseg data_timing; data_timing.bitrate = req->data_bitrate * 1000; data_timing.samplep = req->data_samplep; From d3f889fd2768974fc4635fe9ac70799349b6c7ed Mon Sep 17 00:00:00 2001 From: Alexander Lunev Date: Sat, 2 Oct 2021 03:47:08 +0300 Subject: [PATCH 12/43] [BACKPORT] net/can,icmp,icmpv6,tcp,tcp_timer,udp: device should poll only those connections that are bound to the device. tcp_timer: eliminated false decrements of conn->timer in case of multiple network adapters. The false timer decrements sometimes provoked TCP spurious retransmissions due to premature timeouts. --- net/can/can_poll.c | 29 +++-- net/devif/devif_poll.c | 101 +++++++++------ net/icmp/icmp_poll.c | 5 + net/icmpv6/icmpv6_poll.c | 6 + net/tcp/tcp_devpoll.c | 50 ++++---- net/tcp/tcp_timer.c | 267 ++++++++++++++++++--------------------- net/udp/udp_devpoll.c | 11 ++ 7 files changed, 247 insertions(+), 222 deletions(-) diff --git a/net/can/can_poll.c b/net/can/can_poll.c index c968fe202b5..3caed22544a 100644 --- a/net/can/can_poll.c +++ b/net/can/can_poll.c @@ -26,6 +26,7 @@ #include #if defined(CONFIG_NET) && defined(CONFIG_NET_CAN) +#include #include #include @@ -53,31 +54,31 @@ * * Assumptions: * The network is locked. + * dev is not NULL. + * conn is not NULL. + * The connection (conn) is bound to the polling device (dev). * ****************************************************************************/ void can_poll(FAR struct net_driver_s *dev, FAR struct can_conn_s *conn) { - /* Verify that the packet connection is valid */ + DEBUGASSERT(dev != NULL && conn != NULL && dev == conn->dev); - if (conn != NULL) - { - /* Setup for the application callback */ + /* Setup for the application callback */ - dev->d_appdata = &dev->d_buf[NET_LL_HDRLEN(dev)]; - dev->d_len = 0; - dev->d_sndlen = 0; + dev->d_appdata = &dev->d_buf[NET_LL_HDRLEN(dev)]; + dev->d_len = 0; + dev->d_sndlen = 0; - /* Perform the application callback */ + /* Perform the application callback */ - can_callback(dev, conn, CAN_POLL); + can_callback(dev, conn, CAN_POLL); - /* Check if the application has data to send */ + /* Check if the application has data to send */ - if (dev->d_sndlen > 0) - { - return; - } + if (dev->d_sndlen > 0) + { + return; } /* Make sure that d_len is zero meaning that there is nothing to be sent */ diff --git a/net/devif/devif_poll.c b/net/devif/devif_poll.c index 6865742eec6..4b14c735b0c 100644 --- a/net/devif/devif_poll.c +++ b/net/devif/devif_poll.c @@ -248,10 +248,12 @@ static int devif_poll_can_connections(FAR struct net_driver_s *dev, while (!bstop && (can_conn = can_nextconn(can_conn))) { - /* Perform the packet TX poll */ + /* Skip connections that are bound to other polling devices */ if (dev == can_conn->dev) { + /* Perform the packet TX poll */ + can_poll(dev, can_conn); /* Call back into the driver */ @@ -361,17 +363,22 @@ static inline int devif_poll_icmp(FAR struct net_driver_s *dev, while (!bstop && (conn = icmp_nextconn(conn)) != NULL) { - /* Perform the ICMP poll */ + /* Skip ICMP connections that are bound to other polling devices */ - icmp_poll(dev, conn); + if (dev == conn->dev) + { + /* Perform the ICMP poll */ - /* Perform any necessary conversions on outgoing packets */ + icmp_poll(dev, conn); - devif_packet_conversion(dev, DEVIF_ICMP); + /* Perform any necessary conversions on outgoing packets */ - /* Call back into the driver */ + devif_packet_conversion(dev, DEVIF_ICMP); - bstop = callback(dev); + /* Call back into the driver */ + + bstop = callback(dev); + } } return bstop; @@ -393,27 +400,32 @@ static inline int devif_poll_icmpv6(FAR struct net_driver_s *dev, FAR struct icmpv6_conn_s *conn = NULL; int bstop = 0; - /* Traverse all of the allocated ICMPV6 connections and perform the poll + /* Traverse all of the allocated ICMPv6 connections and perform the poll * action. */ do { - /* Perform the ICMPV6 poll - * Note: conn equal NULL in the first iteration means poll dev's - * callback list since icmpv6_autoconfig and icmpv6_neighbor still - * append it's callback into this list. - */ + /* Skip ICMPv6 connections that are bound to other polling devices */ - icmpv6_poll(dev, conn); + if (conn == NULL || dev == conn->dev) + { + /* Perform the ICMPV6 poll + * Note: conn equal NULL in the first iteration means poll dev's + * callback list since icmpv6_autoconfig and icmpv6_neighbor still + * append it's callback into this list. + */ - /* Perform any necessary conversions on outgoing packets */ + icmpv6_poll(dev, conn); - devif_packet_conversion(dev, DEVIF_ICMP6); + /* Perform any necessary conversions on outgoing packets */ - /* Call back into the driver */ + devif_packet_conversion(dev, DEVIF_ICMP6); - bstop = callback(dev); + /* Call back into the driver */ + + bstop = callback(dev); + } } while (!bstop && (conn = icmpv6_nextconn(conn)) != NULL); @@ -533,17 +545,24 @@ static int devif_poll_udp_connections(FAR struct net_driver_s *dev, while (!bstop && (conn = udp_nextconn(conn))) { - /* Perform the UDP TX poll */ +#ifdef CONFIG_NET_UDP_WRITE_BUFFERS + /* Skip UDP connections that are bound to other polling devices */ - udp_poll(dev, conn); + if (dev == conn->dev) +#endif + { + /* Perform the UDP TX poll */ - /* Perform any necessary conversions on outgoing packets */ + udp_poll(dev, conn); - devif_packet_conversion(dev, DEVIF_UDP); + /* Perform any necessary conversions on outgoing packets */ - /* Call back into the driver */ + devif_packet_conversion(dev, DEVIF_UDP); - bstop = callback(dev); + /* Call back into the driver */ + + bstop = callback(dev); + } } return bstop; @@ -573,17 +592,22 @@ static inline int devif_poll_tcp_connections(FAR struct net_driver_s *dev, while (!bstop && (conn = tcp_nextconn(conn))) { - /* Perform the TCP TX poll */ + /* Skip TCP connections that are bound to other polling devices */ - tcp_poll(dev, conn); + if (dev == conn->dev) + { + /* Perform the TCP TX poll */ - /* Perform any necessary conversions on outgoing packets */ + tcp_poll(dev, conn); - devif_packet_conversion(dev, DEVIF_TCP); + /* Perform any necessary conversions on outgoing packets */ - /* Call back into the driver */ + devif_packet_conversion(dev, DEVIF_TCP); - bstop = callback(dev); + /* Call back into the driver */ + + bstop = callback(dev); + } } return bstop; @@ -619,17 +643,22 @@ static inline int devif_poll_tcp_timer(FAR struct net_driver_s *dev, while (!bstop && (conn = tcp_nextconn(conn))) { - /* Perform the TCP timer poll */ + /* Skip TCP connections that are bound to other polling devices */ - tcp_timer(dev, conn, hsec); + if (dev == conn->dev) + { + /* Perform the TCP timer poll */ - /* Perform any necessary conversions on outgoing packets */ + tcp_timer(dev, conn, hsec); - devif_packet_conversion(dev, DEVIF_TCP); + /* Perform any necessary conversions on outgoing packets */ - /* Call back into the driver */ + devif_packet_conversion(dev, DEVIF_TCP); - bstop = callback(dev); + /* Call back into the driver */ + + bstop = callback(dev); + } } return bstop; diff --git a/net/icmp/icmp_poll.c b/net/icmp/icmp_poll.c index f0f76c65cb0..bd0f761341d 100644 --- a/net/icmp/icmp_poll.c +++ b/net/icmp/icmp_poll.c @@ -54,11 +54,16 @@ * * Assumptions: * The network is locked. + * dev is not NULL. + * conn is not NULL. + * The connection (conn) is bound to the polling device (dev). * ****************************************************************************/ void icmp_poll(FAR struct net_driver_s *dev, FAR struct icmp_conn_s *conn) { + DEBUGASSERT(dev != NULL && conn != NULL && dev == conn->dev); + /* Setup for the application callback */ dev->d_appdata = &dev->d_buf[NET_LL_HDRLEN(dev) + IPICMP_HDRLEN]; diff --git a/net/icmpv6/icmpv6_poll.c b/net/icmpv6/icmpv6_poll.c index 63d89f64deb..5124739028c 100644 --- a/net/icmpv6/icmpv6_poll.c +++ b/net/icmpv6/icmpv6_poll.c @@ -53,12 +53,18 @@ * * Assumptions: * The network is locked. + * dev is not NULL. + * conn may be NULL. + * The connection (conn), if not NULL, is bound to + * the polling device (dev). * ****************************************************************************/ void icmpv6_poll(FAR struct net_driver_s *dev, FAR struct icmpv6_conn_s *conn) { + DEBUGASSERT(dev != NULL && (conn == NULL || dev == conn->dev)); + /* Setup for the application callback */ dev->d_appdata = &dev->d_buf[NET_LL_HDRLEN(dev) + IPICMPv6_HDRLEN]; diff --git a/net/tcp/tcp_devpoll.c b/net/tcp/tcp_devpoll.c index e1b7da28d67..30fd278ebe8 100644 --- a/net/tcp/tcp_devpoll.c +++ b/net/tcp/tcp_devpoll.c @@ -74,7 +74,10 @@ * None * * Assumptions: - * Called with the network locked. + * It is called with the network locked. + * dev is not NULL. + * conn is not NULL. + * The connection (conn) is bound to the polling device (dev). * ****************************************************************************/ @@ -82,6 +85,8 @@ void tcp_poll(FAR struct net_driver_s *dev, FAR struct tcp_conn_s *conn) { uint16_t result; + DEBUGASSERT(dev != NULL && conn != NULL && dev == conn->dev); + /* Discard any currently buffered data */ dev->d_len = 0; @@ -91,43 +96,34 @@ void tcp_poll(FAR struct net_driver_s *dev, FAR struct tcp_conn_s *conn) if ((conn->tcpstateflags & TCP_STATE_MASK) == TCP_ESTABLISHED) { - /* The TCP connection is established and, hence, should be bound - * to a device. Make sure that the polling device is the one that - * we are bound to. + /* Set up for the callback. We can't know in advance if the + * application is going to send a IPv4 or an IPv6 packet, so this + * setup may not actually be used. */ - DEBUGASSERT(conn->dev != NULL); - if (dev == conn->dev) - { - /* Set up for the callback. We can't know in advance if the - * application is going to send a IPv4 or an IPv6 packet, so this - * setup may not actually be used. - */ - #if defined(CONFIG_NET_IPv6) && defined(CONFIG_NET_IPv4) - if (conn->domain == PF_INET) - { - tcp_ipv4_select(dev); - } - else - { - tcp_ipv6_select(dev); - } + if (conn->domain == PF_INET) + { + tcp_ipv4_select(dev); + } + else + { + tcp_ipv6_select(dev); + } #elif defined(CONFIG_NET_IPv4) - tcp_ipv4_select(dev); + tcp_ipv4_select(dev); #else /* if defined(CONFIG_NET_IPv6) */ - tcp_ipv6_select(dev); + tcp_ipv6_select(dev); #endif - /* Perform the callback */ + /* Perform the callback */ - result = tcp_callback(dev, conn, TCP_POLL); + result = tcp_callback(dev, conn, TCP_POLL); - /* Handle the callback response */ + /* Handle the callback response */ - tcp_appsend(dev, conn, result); - } + tcp_appsend(dev, conn, result); } } diff --git a/net/tcp/tcp_timer.c b/net/tcp/tcp_timer.c index 9c063b0f5f2..11e3eca7606 100644 --- a/net/tcp/tcp_timer.c +++ b/net/tcp/tcp_timer.c @@ -94,6 +94,9 @@ * * Assumptions: * The network is locked. + * dev is not NULL. + * conn is not NULL. + * The connection (conn) is bound to the polling device (dev). * ****************************************************************************/ @@ -103,6 +106,14 @@ void tcp_timer(FAR struct net_driver_s *dev, FAR struct tcp_conn_s *conn, uint16_t result; uint8_t hdrlen; + /* NOTE: It is important to decrease conn->timer at "hsec" pace, + * not faster. Excessive (false) decrements of conn->timer are not allowed + * here. Otherwise, it breaks TCP timings and leads to TCP spurious + * retransmissions and other issues due to premature timeouts. + */ + + DEBUGASSERT(dev != NULL && conn != NULL && dev == conn->dev); + /* Set up for the callback. We can't know in advance if the application * is going to send a IPv4 or an IPv6 packet, so this setup may not * actually be used. Furthermore, the TCP logic is required to call @@ -140,6 +151,13 @@ void tcp_timer(FAR struct net_driver_s *dev, FAR struct tcp_conn_s *conn, dev->d_len = 0; dev->d_sndlen = 0; + if (conn->tcpstateflags == TCP_CLOSED) + { + /* Nothing to be done */ + + return; + } + /* Check if the connection is in a state in which we simply wait * for the connection to time out. If so, we increase the * connection's timer and remove the connection if it times @@ -162,30 +180,13 @@ void tcp_timer(FAR struct net_driver_s *dev, FAR struct tcp_conn_s *conn, /* Set the timer to the maximum value */ conn->timer = TCP_TIME_WAIT_TIMEOUT * HSEC_PER_SEC; + conn->tcpstateflags = TCP_CLOSED; - /* The TCP connection was established and, hence, should be bound - * to a device. Make sure that the polling device is the one that - * we are bound to. - * - * If not, then we will catch the timeout on the next poll from - * the correct device. - */ - - DEBUGASSERT(conn->dev != NULL); - if (dev != conn->dev) - { - ninfo("TCP: TCP_CLOSED pending\n"); - } - else - { - conn->tcpstateflags = TCP_CLOSED; - - /* Notify upper layers about the timeout */ + /* Notify upper layers about the timeout */ - tcp_callback(dev, conn, TCP_TIMEDOUT); + tcp_callback(dev, conn, TCP_TIMEDOUT); - ninfo("TCP state: TCP_CLOSED\n"); - } + ninfo("TCP state: TCP_CLOSED\n"); } else { @@ -217,21 +218,6 @@ void tcp_timer(FAR struct net_driver_s *dev, FAR struct tcp_conn_s *conn, conn->timer = 0; - /* The TCP is connected and, hence, should be bound to a - * device. Make sure that the polling device is the one that - * we are bound to. - * - * If not, then we will catch the timeout on the next poll - * from the correct device. - */ - - DEBUGASSERT(conn->dev != NULL); - if (dev != conn->dev) - { - ninfo("TCP: TCP_CLOSED pending\n"); - goto done; - } - /* Check for a timeout on connection in the TCP_SYN_RCVD state. * On such timeouts, we would normally resend the SYNACK until * the ACK is received, completing the 3-way handshake. But if @@ -369,157 +355,148 @@ void tcp_timer(FAR struct net_driver_s *dev, FAR struct tcp_conn_s *conn, else if ((conn->tcpstateflags & TCP_STATE_MASK) == TCP_ESTABLISHED) { - /* The TCP connection is established and, hence, should be bound - * to a device. Make sure that the polling device is the one that - * we are bound to. - */ +#ifdef CONFIG_NET_TCP_KEEPALIVE + /* Is this an established connected with KeepAlive enabled? */ - DEBUGASSERT(conn->dev != NULL); - if (dev == conn->dev) + if (conn->keepalive) { -#ifdef CONFIG_NET_TCP_KEEPALIVE - /* Is this an established connected with KeepAlive enabled? */ + socktimeo_t timeo; + uint32_t saveseq; - if (conn->keepalive) + /* If this is the first probe, then the keepstart time is + * the time that the last ACK or data was received from the + * remote. + * + * On subsequent retries, keepstart is the time that the + * last probe was sent. + */ + + if (conn->keepretries > 0) { - socktimeo_t timeo; - uint32_t saveseq; - - /* If this is the first probe, then the keepstart time is - * the time that the last ACK or data was received from the - * remote. - * - * On subsequent retries, keepstart is the time that the - * last probe was sent. - */ + timeo = (socktimeo_t)conn->keepintvl; + } + else + { + timeo = (socktimeo_t)conn->keepidle; + } - if (conn->keepretries > 0) - { - timeo = (socktimeo_t)conn->keepintvl; - } - else - { - timeo = (socktimeo_t)conn->keepidle; - } + /* Yes... has the idle period elapsed with no data or ACK + * received from the remote peer? + */ - /* Yes... has the idle period elapsed with no data or ACK - * received from the remote peer? - */ + if (net_timeo(conn->keeptime, timeo)) + { + /* Yes.. Has the retry count expired? */ - if (net_timeo(conn->keeptime, timeo)) + if (conn->keepretries >= conn->keepcnt) { - /* Yes.. Has the retry count expired? */ - - if (conn->keepretries >= conn->keepcnt) - { - /* Yes... stop the network monitor, closing the - * connection and all sockets associated with the - * connection. - */ + /* Yes... stop the network monitor, closing the + * connection and all sockets associated with the + * connection. + */ - tcp_stop_monitor(conn, TCP_ABORT); - } - else - { - unsigned int tcpiplen; + tcp_stop_monitor(conn, TCP_ABORT); + } + else + { + unsigned int tcpiplen; - /* No.. we need to send another probe. - * Get the size of the IP and TCP header. - */ + /* No.. we need to send another probe. + * Get the size of the IP and TCP header. + */ #ifdef CONFIG_NET_IPv4 #ifdef CONFIG_NET_IPv6 - if (conn->domain == PF_INET) + if (conn->domain == PF_INET) #endif - { - tcpiplen = IPv4_HDRLEN + TCP_HDRLEN; - } + { + tcpiplen = IPv4_HDRLEN + TCP_HDRLEN; + } #endif #ifdef CONFIG_NET_IPv6 #ifdef CONFIG_NET_IPv4 - else + else #endif - { - tcpiplen = IPv6_HDRLEN + TCP_HDRLEN; - } + { + tcpiplen = IPv6_HDRLEN + TCP_HDRLEN; + } #endif - /* And send the probe. - * The packet we send must have these properties: - * - * - TCP_ACK flag (only) is set. - * - Sequence number is the sequence number of - * previously ACKed data, i.e., the expected - * sequence number minus one. - * - * tcp_send() will send the TCP sequence number as - * conn->sndseq. Rather than creating a new - * interface, we spoof tcp_end() here: - */ + /* And send the probe. + * The packet we send must have these properties: + * + * - TCP_ACK flag (only) is set. + * - Sequence number is the sequence number of + * previously ACKed data, i.e., the expected + * sequence number minus one. + * + * tcp_send() will send the TCP sequence number as + * conn->sndseq. Rather than creating a new + * interface, we spoof tcp_end() here: + */ - saveseq = tcp_getsequence(conn->sndseq); - tcp_setsequence(conn->sndseq, saveseq - 1); + saveseq = tcp_getsequence(conn->sndseq); + tcp_setsequence(conn->sndseq, saveseq - 1); - tcp_send(dev, conn, TCP_ACK, tcpiplen); + tcp_send(dev, conn, TCP_ACK, tcpiplen); - tcp_setsequence(conn->sndseq, saveseq); + tcp_setsequence(conn->sndseq, saveseq); #ifdef CONFIG_NET_TCP_WRITE_BUFFERS - /* Increment the un-ACKed sequence number */ + /* Increment the un-ACKed sequence number */ - conn->sndseq_max++; + conn->sndseq_max++; #endif - /* Update for the next probe */ - - conn->keeptime = clock_systime_ticks(); - conn->keepretries++; - } + /* Update for the next probe */ - goto done; + conn->keeptime = clock_systime_ticks(); + conn->keepretries++; } + + goto done; } + } #endif #ifdef CONFIG_NET_TCP_DELAYED_ACK - /* Handle delayed acknowledgments. Is there a segment with a - * delayed acknowledgment? - */ + /* Handle delayed acknowledgments. Is there a segment with a + * delayed acknowledgment? + */ - if (conn->rx_unackseg > 0) - { - /* Increment the ACK delay. */ + if (conn->rx_unackseg > 0) + { + /* Increment the ACK delay. */ - conn->rx_acktimer += hsec; + conn->rx_acktimer += hsec; - /* Per RFC 1122: "...an ACK should not be excessively - * delayed; in particular, the delay must be less than - * 0.5 seconds..." - */ + /* Per RFC 1122: "...an ACK should not be excessively + * delayed; in particular, the delay must be less than + * 0.5 seconds..." + */ - if (conn->rx_acktimer >= ACK_DELAY) - { - /* Reset the delayed ACK state and send the ACK - * packet. - */ + if (conn->rx_acktimer >= ACK_DELAY) + { + /* Reset the delayed ACK state and send the ACK + * packet. + */ - conn->rx_unackseg = 0; - conn->rx_acktimer = 0; - tcp_synack(dev, conn, TCP_ACK); - goto done; - } + conn->rx_unackseg = 0; + conn->rx_acktimer = 0; + tcp_synack(dev, conn, TCP_ACK); + goto done; } + } #endif - /* There was no need for a retransmission and there was no - * need to probe the remote peer and there was no need to - * send a delayed ACK. We poll the application for new - * outgoing data. - */ + /* There was no need for a retransmission and there was no + * need to probe the remote peer and there was no need to + * send a delayed ACK. We poll the application for new + * outgoing data. + */ - result = tcp_callback(dev, conn, TCP_POLL); - tcp_appsend(dev, conn, result); - goto done; - } + result = tcp_callback(dev, conn, TCP_POLL); + tcp_appsend(dev, conn, result); + goto done; } } diff --git a/net/udp/udp_devpoll.c b/net/udp/udp_devpoll.c index 92eaf042ce0..7796f8f5e17 100644 --- a/net/udp/udp_devpoll.c +++ b/net/udp/udp_devpoll.c @@ -45,6 +45,7 @@ #include #if defined(CONFIG_NET) && defined(CONFIG_NET_UDP) +#include #include #include @@ -73,11 +74,21 @@ * * Assumptions: * The network is locked. + * dev is not NULL. + * conn is not NULL. + * The connection (conn) is bound to the polling device (dev) in case of + * enabled CONFIG_NET_UDP_WRITE_BUFFERS option. * ****************************************************************************/ void udp_poll(FAR struct net_driver_s *dev, FAR struct udp_conn_s *conn) { + DEBUGASSERT(dev != NULL && conn != NULL); + +#ifdef CONFIG_NET_UDP_WRITE_BUFFERS + DEBUGASSERT(dev == conn->dev); +#endif + /* Verify that the UDP connection is valid */ if (conn->lport != 0) From 323cc48d0312106892bada767a3414ebf271f1bf Mon Sep 17 00:00:00 2001 From: Matthew Trescott Date: Sat, 2 Jan 2021 09:38:59 -0500 Subject: [PATCH 13/43] [BACKPORT] can: WIP: Cleanup usage of soft fifo semaphore --- drivers/can/can.c | 88 ++++++++++++++++++++++++----------------- include/nuttx/can/can.h | 8 +++- 2 files changed, 59 insertions(+), 37 deletions(-) diff --git a/drivers/can/can.c b/drivers/can/can.c index 4ee1554c325..76369c82fe9 100644 --- a/drivers/can/can.c +++ b/drivers/can/can.c @@ -391,7 +391,7 @@ static FAR struct can_reader_s *init_can_reader(FAR struct file *filep) reader->fifo.rx_head = 0; reader->fifo.rx_tail = 0; - nxsem_init(&reader->fifo.rx_sem, 0, 1); + nxsem_init(&reader->fifo.rx_sem, 0, 0); nxsem_set_protocol(&reader->fifo.rx_sem, SEM_PRIO_NONE); filep->f_priv = reader; @@ -628,24 +628,24 @@ static ssize_t can_read(FAR struct file *filep, FAR char *buffer, fifo = &reader->fifo; - while (fifo->rx_head == fifo->rx_tail) + if (filep->f_oflags & O_NONBLOCK) + { + ret = nxsem_trywait(&fifo->rx_sem); + } + else { - /* The receive FIFO is empty -- was non-blocking mode selected? */ - - if (filep->f_oflags & O_NONBLOCK) - { - ret = -EAGAIN; - goto return_with_irqdisabled; - } - - /* Wait for a message to be received */ - ret = can_takesem(&fifo->rx_sem); + } - if (ret < 0) - { - goto return_with_irqdisabled; - } + if (ret < 0) + { + goto return_with_irqdisabled; + } + + if (fifo->rx_head == fifo->rx_tail) + { + canerr("RX FIFO sem posted but FIFO is empty.\n"); + goto return_with_irqdisabled; } /* The cd_recv FIFO is not empty. Copy all buffered data that will fit @@ -680,9 +680,17 @@ static ssize_t can_read(FAR struct file *filep, FAR char *buffer, } while (fifo->rx_head != fifo->rx_tail); - /* All on the messages have bee transferred. Return the number of - * bytes that were read. - */ + if (fifo->rx_head != fifo->rx_tail) + { + /* The user's buffer was too small, so some messages remain in the + * FIFO. Post the semaphore so future calls to poll() or read() + * don't block. + */ + + can_givesem(&fifo->rx_sem); + } + + /* Return the number of bytes that were read. */ ret = nread; @@ -1070,6 +1078,7 @@ static int can_poll(FAR struct file *filep, FAR struct pollfd *fds, FAR struct can_reader_s *reader = NULL; pollevent_t eventset; int ndx; + int sval; irqstate_t flags; int ret; int i; @@ -1083,6 +1092,10 @@ static int can_poll(FAR struct file *filep, FAR struct pollfd *fds, } #endif + /* Ensure exclusive access to FIFO indices - don't want can_receive or + * can_read changing them in the middle of the comparison + */ + flags = enter_critical_section(); DEBUGASSERT(filep->f_priv != NULL); @@ -1161,25 +1174,28 @@ static int can_poll(FAR struct file *filep, FAR struct pollfd *fds, can_givesem(&dev->cd_xmit.tx_sem); - /* Check if the receive buffer is empty. - * - * Get exclusive access to the cd_recv buffer indices. NOTE: that - * we do not let this wait be interrupted by a signal (we probably - * should, but that would be a little awkward). - */ + /* Check whether there are messages in the RX FIFO. */ - do - { - ret = can_takesem(&reader->fifo.rx_sem); - } - while (ret < 0); + ret = nxsem_get_value(&reader->fifo.rx_sem, &sval); - if (reader->fifo.rx_head != reader->fifo.rx_tail) + if (ret < 0) { - eventset |= fds->events & POLLIN; + DEBUGASSERT(false); + goto return_with_irqdisabled; } + else if (sval > 0) + { + if (reader->fifo.rx_head != reader->fifo.rx_tail) + { + /* No need to wait, just notify the application immediately */ - can_givesem(&reader->fifo.rx_sem); + eventset |= fds->events & POLLIN; + } + else + { + canerr("RX FIFO sem not locked but FIFO is empty.\n"); + } + } if (eventset != 0) { @@ -1413,9 +1429,9 @@ int can_receive(FAR struct can_dev_s *dev, FAR struct can_hdr_s *hdr, return -EINVAL; } - /* Increment the counting semaphore. The maximum value should - * be CONFIG_CAN_FIFOSIZE -- one possible count for each allocated - * message buffer. + /* Unlock the binary semaphore, waking up can_read if it is + * blocked. If can_read were not blocked, we would not be + * executing this because interrupts would be disabled. */ if (sval <= 0) diff --git a/include/nuttx/can/can.h b/include/nuttx/can/can.h index aebb6ae00c2..2df331001e7 100644 --- a/include/nuttx/can/can.h +++ b/include/nuttx/can/can.h @@ -491,7 +491,13 @@ begin_packed_struct struct can_msg_s struct can_rxfifo_s { - sem_t rx_sem; /* Counting semaphore */ + /* Binary semaphore. Indicates whether FIFO is available for reading + * AND not empty. Only take this sem inside a critical section to guarantee + * exclusive access to both the semaphore and the head/tail FIFO indices. + */ + + sem_t rx_sem; + uint8_t rx_head; /* Index to the head [IN] in the circular buffer */ uint8_t rx_tail; /* Index to the tail [OUT] in the circular buffer */ /* Circular buffer of CAN messages */ From 42f912fc43fce74bdf15a4fc3944d838f90a06fb Mon Sep 17 00:00:00 2001 From: raiden00pl Date: Thu, 30 Dec 2021 09:55:15 +0100 Subject: [PATCH 14/43] [BACKPORT] include/nuttx/can.h: include nuttx/config.h --- include/nuttx/can.h | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/include/nuttx/can.h b/include/nuttx/can.h index 47a29efab8b..ef0d6027c56 100644 --- a/include/nuttx/can.h +++ b/include/nuttx/can.h @@ -18,13 +18,15 @@ * ****************************************************************************/ -#ifndef __INCLUDE_NUTTX_CAN_CAN_H -#define __INCLUDE_NUTTX_CAN_CAN_H +#ifndef __INCLUDE_NUTTX_CAN_H +#define __INCLUDE_NUTTX_CAN_H /**************************************************************************** * Included Files ****************************************************************************/ +#include + #ifdef CONFIG_CAN_TXREADY # include #endif @@ -307,4 +309,4 @@ extern "C" #endif #endif /* CONFIG_CAN */ -#endif /* __INCLUDE_NUTTX_CAN_CAN_H */ +#endif /* __INCLUDE_NUTTX_CAN_H */ From 334e7caf5ea78e03a6a9845370ac2536d1ab55c3 Mon Sep 17 00:00:00 2001 From: raiden00pl Date: Mon, 3 Jan 2022 11:45:42 +0100 Subject: [PATCH 15/43] [BACKPORT] net/devif/devif_cansend.c: fix assertion for max data len --- net/devif/devif_cansend.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/devif/devif_cansend.c b/net/devif/devif_cansend.c index 60325a5cdf9..b82956c8515 100644 --- a/net/devif/devif_cansend.c +++ b/net/devif/devif_cansend.c @@ -83,7 +83,7 @@ void devif_can_send(FAR struct net_driver_s *dev, FAR const void *buf, unsigned int len) { - DEBUGASSERT(dev && len > 0 && len < NETDEV_PKTSIZE(dev)); + DEBUGASSERT(dev && len > 0 && len <= NETDEV_PKTSIZE(dev)); /* Copy the data into the device packet buffer */ From 248efed34f8694e53f33eb88104af5df7615c096 Mon Sep 17 00:00:00 2001 From: raiden00pl Date: Wed, 5 Jan 2022 10:10:20 +0100 Subject: [PATCH 16/43] [BACKPORT] include/nuttx/can/can.h: fix typo --- include/nuttx/can/can.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/nuttx/can/can.h b/include/nuttx/can/can.h index 2df331001e7..0f7db306a54 100644 --- a/include/nuttx/can/can.h +++ b/include/nuttx/can/can.h @@ -293,7 +293,7 @@ # define CAN_ERROR_TXTIMEOUT (1 << 0) /* Bit 0: TX timeout */ # define CAN_ERROR_LOSTARB (1 << 1) /* Bit 1: Lost arbitration (See CAN_ERROR0_* definitions) */ # define CAN_ERROR_CONTROLLER (1 << 2) /* Bit 2: Controller error (See CAN_ERROR1_* definitions) */ -# define CAN_ERROR_PROTOCOL (1 << 3) /* Bit 3: Protocol error (see CAN_ERROR1_* and CAN_ERROR3_* definitions) */ +# define CAN_ERROR_PROTOCOL (1 << 3) /* Bit 3: Protocol error (see CAN_ERROR2_* and CAN_ERROR3_* definitions) */ # define CAN_ERROR_TRANSCEIVER (1 << 4) /* Bit 4: Transceiver error (See CAN_ERROR4_* definitions) */ # define CAN_ERROR_NOACK (1 << 5) /* Bit 5: No ACK received on transmission */ # define CAN_ERROR_BUSOFF (1 << 6) /* Bit 6: Bus off */ From 6ef0905071c4eb7692d0a01f0e2e671de2703c1e Mon Sep 17 00:00:00 2001 From: raiden00pl Date: Wed, 5 Jan 2022 10:11:16 +0100 Subject: [PATCH 17/43] [BACKPORT] SocketCAN: add CAN error definitions --- include/nuttx/can.h | 79 ++++++++++++++++++++++++++++++++++++++++++++- net/can/Kconfig | 11 +++++++ 2 files changed, 89 insertions(+), 1 deletion(-) diff --git a/include/nuttx/can.h b/include/nuttx/can.h index ef0d6027c56..7cd1da20654 100644 --- a/include/nuttx/can.h +++ b/include/nuttx/can.h @@ -208,6 +208,83 @@ #define CAN_INV_FILTER 0x20000000U /* to be set in can_filter.can_id */ +/* CAN Error Indications ****************************************************/ + +#ifdef CONFIG_NET_CAN_ERRORS + +/* Error class in can_id */ + +# define CAN_ERR_TXTIMEOUT (1 << 0) /* Bit 0: TX timeout */ +# define CAN_ERR_LOSTARB (1 << 1) /* Bit 1: Lost arbitration (See CAN_ERR_LOSTARB_* definitions) */ +# define CAN_ERR_CTRL (1 << 2) /* Bit 2: Controller error (See CAN_ERR_CTRL_* definitions) */ +# define CAN_ERR_PROT (1 << 3) /* Bit 3: Protocol error (see CAN_ERR_PROT_* definitions) */ +# define CAN_ERR_TRX (1 << 4) /* Bit 4: Transceiver error (See CAN_TRX_* definitions) */ +# define CAN_ERR_ACK (1 << 5) /* Bit 5: No ACK received on transmission */ +# define CAN_ERR_BUSOFF (1 << 6) /* Bit 6: Bus off */ +# define CAN_ERR_BUSERROR (1 << 7) /* Bit 7: Bus error */ +# define CAN_ERR_RESTARTED (1 << 8) /* Bit 8: Controller restarted */ + +/* The remaining definitions described the error report payload that follows + * the CAN header. + */ + +# define CAN_ERR_DLC (8) /* DLC of error report */ + +/* Data[0]: Arbitration lost in ch_error. */ + +# define CAN_ERR_LOSTARB_UNSPEC 0x00 /* Unspecified error */ +# define CAN_ERR_LOSTARB_BIT(n) (n) /* Bit number in the bit stream */ + +/* Data[1]: Error status of CAN-controller */ + +# define CAN_ERR_CTRL_UNSPEC 0x00 /* Unspecified error */ +# define CAN_ERR_CTRL_RX_OVERFLOW (1 << 0) /* Bit 0: RX buffer overflow */ +# define CAN_ERR_CTRL_TX_OVERFLOW (1 << 1) /* Bit 1: TX buffer overflow */ +# define CAN_ERR_CTRL_RX_WARNING (1 << 2) /* Bit 2: Reached warning level for RX errors */ +# define CAN_ERR_CTRL_TX_WARNING (1 << 3) /* Bit 3: Reached warning level for TX errors */ +# define CAN_ERR_CTRL_RX_PASSIVE (1 << 4) /* Bit 4: Reached passive level for RX errors */ +# define CAN_ERR_CTRL_TX_PASSIVE (1 << 5) /* Bit 5: Reached passive level for TX errors */ + +/* Data[2]: Error in CAN protocol. This provides the type of the error. */ + +# define CAN_ERR_PROT_UNSPEC 0x00 /* Unspecified error */ +# define CAN_ERR_PROT_BIT (1 << 0) /* Bit 0: Single bit error */ +# define CAN_ERR_PROT_FORM (1 << 1) /* Bit 1: Frame format error */ +# define CAN_ERR_PROT_STUFF (1 << 2) /* Bit 2: Bit stuffing error */ +# define CAN_ERR_PROT_BIT0 (1 << 3) /* Bit 3: Unable to send dominant bit */ +# define CAN_ERR_PROT_BIT1 (1 << 4) /* Bit 4: Unable to send recessive bit */ +# define CAN_ERR_PROT_OVERLOAD (1 << 5) /* Bit 5: Bus overload */ +# define CAN_ERR_PROT_ACTIVE (1 << 6) /* Bit 6: Active error announcement */ +# define CAN_ERR_PROT_TX (1 << 7) /* Bit 7: Error occurred on transmission */ + +/* Data[3]: Error in CAN protocol. This provides the loation of the error */ + +# define CAN_ERR_PROT_LOC_UNSPEC 0x00 /* Unspecified error */ +# define CAN_ERR_PROT_LOC_SOF 0x01 /* start of frame */ +# define CAN_ERR_PROT_LOC_ID0 0x02 /* ID bits 0-4 */ +# define CAN_ERR_PROT_LOC_ID1 0x03 /* ID bits 5-12 */ +# define CAN_ERR_PROT_LOC_ID2 0x04 /* ID bits 13-17 */ +# define CAN_ERR_PROT_LOC_ID3 0x05 /* ID bits 21-28 */ +# define CAN_ERR_PROT_LOC_ID4 0x06 /* ID bits 18-20 */ +# define CAN_ERR_PROT_LOC_IDE 0x07 /* Identifier extension */ +# define CAN_ERR_PROT_LOC_RTR 0x08 /* RTR */ +# define CAN_ERR_PROT_LOC_SRTR 0x09 /* Substitute RTR */ +# define CAN_ERR_PROT_LOC_RES0 0x0a /* Reserved bit 0 */ +# define CAN_ERR_PROT_LOC_RES1 0x0b /* Reserved bit 1 */ +# define CAN_ERR_PROT_LOC_DLC 0x0c /* Data length code */ +# define CAN_ERR_PROT_LOC_DATA 0x0d /* Data section */ +# define CAN_ERR_PROT_LOC_CRCSEQ 0x0e /* CRC sequence */ +# define CAN_ERR_PROT_LOC_CRCDEL 0x0f /* CRC delimiter */ +# define CAN_ERR_PROT_LOC_ACK 0x10 /* ACK slot */ +# define CAN_ERR_PROT_LOC_ACKDEL 0x11 /* ACK delimiter */ +# define CAN_ERR_PROT_LOC_EOF 0x12 /* End of frame */ +# define CAN_ERR_PROT_LOC_INTERM 0x13 /* Intermission */ + +/* Data[4]: Error status of CAN-transceiver */ + +# define CAN_ERR_TRX_UNSPEC 0x00 /* Unspecified error */ +#endif /* CONFIG_NET_CAN_ERRORS */ + /**************************************************************************** * Public Types ****************************************************************************/ @@ -225,7 +302,7 @@ typedef uint32_t canid_t; /* Controller Area Network Error Message Frame Mask structure * - * bit 0-28 : error class mask (see include/uapi/linux/can/error.h) + * bit 0-28 : error class mask * bit 29-31 : set to zero */ diff --git a/net/can/Kconfig b/net/can/Kconfig index cd36680e506..695dcee550d 100644 --- a/net/can/Kconfig +++ b/net/can/Kconfig @@ -26,6 +26,10 @@ config NET_CAN_HAVE_CANFD bool default n +config NET_CAN_HAVE_ERRORS + bool + default n + config CAN_CONNS int "Max number of CAN socket connections" default 4 @@ -39,6 +43,13 @@ config NET_CAN_CANFD ---help--- Enable CAN FD support in SocketCAN stack +config NET_CAN_ERRORS + bool "Enable CAN errors support" + default n + depends on NET_CAN_HAVE_ERRORS + ---help--- + Enable CAN errors support in SocketCAN stack + config NET_CAN_SOCK_OPTS bool "sockopt support" default n From 3dea2bd971da7acc70c3a0d14dbfdd2464ca5e53 Mon Sep 17 00:00:00 2001 From: raiden00pl Date: Wed, 5 Jan 2022 09:57:18 +0100 Subject: [PATCH 18/43] [BACKPORT] stm32: add CAN error support --- arch/arm/src/stm32/Kconfig | 1 + arch/arm/src/stm32/stm32_can.c | 272 ++++++++++++++++++++++++++++++++- 2 files changed, 266 insertions(+), 7 deletions(-) diff --git a/arch/arm/src/stm32/Kconfig b/arch/arm/src/stm32/Kconfig index e2bce0f551c..bd3fa46f5eb 100644 --- a/arch/arm/src/stm32/Kconfig +++ b/arch/arm/src/stm32/Kconfig @@ -3361,6 +3361,7 @@ config STM32_I2C config STM32_CAN bool + select ARCH_HAVE_CAN_ERRORS config STM32_TIM bool diff --git a/arch/arm/src/stm32/stm32_can.c b/arch/arm/src/stm32/stm32_can.c index f0b398ebb9a..8e7725c193c 100644 --- a/arch/arm/src/stm32/stm32_can.c +++ b/arch/arm/src/stm32/stm32_can.c @@ -85,6 +85,14 @@ # undef CONFIG_STM32_CAN_REGDEBUG #endif +/* CAN error interrupts */ + +#ifdef CONFIG_CAN_ERRORS +# define STM32_CAN_ERRINT (CAN_IER_LECIE | CAN_IER_ERRIE | \ + CAN_IER_BOFIE | CAN_IER_EPVIE | \ + CAN_IER_EWGIE) +#endif + /**************************************************************************** * Private Types ****************************************************************************/ @@ -94,6 +102,9 @@ struct stm32_can_s uint8_t port; /* CAN port number (1 or 2) */ uint8_t canrx[2]; /* CAN RX FIFO 0/1 IRQ number */ uint8_t cantx; /* CAN TX IRQ number */ +#ifdef CONFIG_CAN_ERRORS + uint8_t cansce; /* CAN SCE IRQ number */ +#endif uint8_t filter; /* Filter number */ uint32_t base; /* Base address of the CAN control registers */ uint32_t fbase; /* Base address of the CAN filter registers */ @@ -156,12 +167,19 @@ static int stm32can_send(FAR struct can_dev_s *dev, static bool stm32can_txready(FAR struct can_dev_s *dev); static bool stm32can_txempty(FAR struct can_dev_s *dev); +#ifdef CONFIG_CAN_ERRORS +static void stm32can_errint(FAR struct can_dev_s *dev, bool enable); +#endif + /* CAN interrupt handling */ static int stm32can_rxinterrupt(FAR struct can_dev_s *dev, int rxmb); static int stm32can_rx0interrupt(int irq, FAR void *context, FAR void *arg); static int stm32can_rx1interrupt(int irq, FAR void *context, FAR void *arg); static int stm32can_txinterrupt(int irq, FAR void *context, FAR void *arg); +#ifdef CONFIG_CAN_ERRORS +static int stm32can_sceinterrupt(int irq, FAR void *context, FAR void *arg); +#endif /* Initialization */ @@ -205,6 +223,9 @@ static struct stm32_can_s g_can1priv = STM32_IRQ_CAN1RX1, }, .cantx = STM32_IRQ_CAN1TX, +#ifdef CONFIG_CAN_ERRORS + .cansce = STM32_IRQ_CAN1SCE, +#endif .filter = 0, .base = STM32_CAN1_BASE, .fbase = STM32_CAN1_BASE, @@ -228,6 +249,9 @@ static struct stm32_can_s g_can2priv = STM32_IRQ_CAN2RX1, }, .cantx = STM32_IRQ_CAN2TX, +#ifdef CONFIG_CAN_ERRORS + .cansce = STM32_IRQ_CAN2SCE, +#endif .filter = CAN_NFILTERS / 2, .base = STM32_CAN2_BASE, .fbase = STM32_CAN1_BASE, @@ -633,9 +657,16 @@ static int stm32can_setup(FAR struct can_dev_s *dev) FAR struct stm32_can_s *priv = dev->cd_priv; int ret; - caninfo("CAN%" PRIu8 " RX0 irq: %" PRIu8 " RX1 irq: %" PRIu8 - " TX irq: %" PRIu8 "\n", - priv->port, priv->canrx[0], priv->canrx[1], priv->cantx); +#ifdef CONFIG_CAN_ERRORS + ninfo("CAN%" PRIu8 " RX0 irq: %" PRIu8 " RX1 irq: %" PRIu8 + " TX irq: %" PRIu8 " SCE irq: %" PRIu8 "\n", + priv->port, priv->canrx[0], priv->canrx[1], priv->cantx, + priv->cansce); +#else + ninfo("CAN%" PRIu8 " RX0 irq: %" PRIu8 " RX1 irq: %" PRIu8 + " TX irq: %" PRIu8 "\n", + priv->port, priv->canrx[0], priv->canrx[1], priv->cantx); +#endif /* CAN cell initialization */ @@ -690,6 +721,20 @@ static int stm32can_setup(FAR struct can_dev_s *dev) return ret; } +#ifdef CONFIG_CAN_ERRORS + ret = irq_attach(priv->cansce, stm32can_sceinterrupt, dev); + if (ret < 0) + { + nerr("ERROR: Failed to attach CAN%" PRIu8 " SCE IRQ (%" PRIu8 ")", + priv->port, priv->cansce); + return ret; + } + + /* Enable CAN error interrupts */ + + stm32can_errint(dev, true); +#endif + /* Enable the interrupts at the NVIC. Interrupts are still disabled in * the CAN module. Since we coming out of reset here, there should be * no pending interrupts. @@ -698,6 +743,9 @@ static int stm32can_setup(FAR struct can_dev_s *dev) up_enable_irq(priv->canrx[0]); up_enable_irq(priv->canrx[1]); up_enable_irq(priv->cantx); +#ifdef CONFIG_CAN_ERRORS + up_enable_irq(priv->cansce); +#endif return OK; } @@ -722,17 +770,23 @@ static void stm32can_shutdown(FAR struct can_dev_s *dev) caninfo("CAN%" PRIu8 "\n", priv->port); - /* Disable the RX FIFO 0/1 and TX interrupts */ + /* Disable the RX FIFO 0/1, TX and SCE interrupts */ up_disable_irq(priv->canrx[0]); up_disable_irq(priv->canrx[1]); up_disable_irq(priv->cantx); +#ifdef CONFIG_CAN_ERRORS + up_disable_irq(priv->cansce); +#endif - /* Detach the RX FIFO 0/1 and TX interrupts */ + /* Detach the RX FIFO 0/1, TX and SCE interrupts */ irq_detach(priv->canrx[0]); irq_detach(priv->canrx[1]); irq_detach(priv->cantx); +#ifdef CONFIG_CAN_ERRORS + irq_detach(priv->cansce); +#endif /* And reset the hardware */ @@ -758,7 +812,7 @@ static void stm32can_rxint(FAR struct can_dev_s *dev, bool enable) FAR struct stm32_can_s *priv = dev->cd_priv; uint32_t regval; - caninfo("CAN%" PRIu8 " enable: %d\n", priv->port, enable); + caninfo("CAN%" PRIu8 " rxint enable: %d\n", priv->port, enable); /* Enable/disable the FIFO 0/1 message pending interrupt */ @@ -794,7 +848,7 @@ static void stm32can_txint(FAR struct can_dev_s *dev, bool enable) FAR struct stm32_can_s *priv = dev->cd_priv; uint32_t regval; - caninfo("CAN%" PRIu8 " enable: %d\n", priv->port, enable); + caninfo("CAN%" PRIu8 " txint enable: %d\n", priv->port, enable); /* Support only disabling the transmit mailbox interrupt */ @@ -806,6 +860,44 @@ static void stm32can_txint(FAR struct can_dev_s *dev, bool enable) } } +#ifdef CONFIG_CAN_ERRORS +/**************************************************************************** + * Name: stm32can_errint + * + * Description: + * Call to enable or disable CAN error interrupts. + * + * Input Parameters: + * dev - An instance of the "upper half" can driver state structure. + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void stm32can_errint(FAR struct can_dev_s *dev, bool enable) +{ + FAR struct stm32_can_s *priv = dev->cd_priv; + uint32_t regval = 0; + + caninfo("CAN%" PRIu8 " errint enable: %d\n", priv->port, enable); + + /* Enable/disable the transmit mailbox interrupt */ + + regval = stm32can_getreg(priv, STM32_CAN_IER_OFFSET); + if (enable) + { + regval |= STM32_CAN_ERRINT; + } + else + { + regval &= ~STM32_CAN_ERRINT; + } + + stm32can_putreg(priv, STM32_CAN_IER_OFFSET, regval); +} +#endif + /**************************************************************************** * Name: stm32can_ioctl * @@ -1667,6 +1759,172 @@ static int stm32can_txinterrupt(int irq, FAR void *context, FAR void *arg) return OK; } +#ifdef CONFIG_CAN_ERRORS +/**************************************************************************** + * Name: stm32can_sceinterrupt + * + * Description: + * CAN status change interrupt handler + * + * Input Parameters: + * irq - The IRQ number of the interrupt. + * context - The register state save array at the time of the interrupt. + * + * Returned Value: + * Zero on success; a negated errno on failure + * + ****************************************************************************/ + +static int stm32can_sceinterrupt(int irq, FAR void *context, FAR void *arg) +{ + FAR struct can_dev_s *dev = (FAR struct can_dev_s *)arg; + FAR struct stm32_can_s *priv = NULL; + struct can_hdr_s hdr; + uint32_t regval = 0; + uint16_t errbits = 0; + uint8_t data[CAN_ERROR_DLC]; + int ret = OK; + + DEBUGASSERT(dev != NULL && dev->cd_priv != NULL); + priv = dev->cd_priv; + + /* Check Error Interrupt flag */ + + regval = stm32can_getreg(priv, STM32_CAN_MSR_OFFSET); + if (regval & CAN_MSR_ERRI) + { + /* Encode error bits */ + + errbits = 0; + memset(data, 0, sizeof(data)); + + /* Get Error statur register */ + + regval = stm32can_getreg(priv, STM32_CAN_ESR_OFFSET); + + if (regval & CAN_ESR_EWGF) + { + /* Error warning flag */ + + data[1] |= (CAN_ERROR1_RXWARNING | CAN_ERROR1_TXWARNING); + errbits |= CAN_ERROR_CONTROLLER; + } + + if (regval & CAN_ESR_EPVF) + { + /* Error passive flag */ + + data[1] |= (CAN_ERROR1_RXPASSIVE | CAN_ERROR1_TXPASSIVE); + errbits |= CAN_ERROR_CONTROLLER; + } + + if (regval & CAN_ESR_BOFF) + { + /* Bus-off flag */ + + errbits |= CAN_ERROR_BUSOFF; + } + + /* Last error code */ + + if (regval & CAN_ESR_LEC_MASK) + { + if (regval & CAN_ESR_STUFFERROR) + { + /* Stuff Error */ + + errbits |= CAN_ERROR_PROTOCOL; + data[2] |= CAN_ERROR2_STUFF; + } + else if (regval & CAN_ESR_FORMERROR) + { + /* Format Error */ + + errbits |= CAN_ERROR_PROTOCOL; + data[2] |= CAN_ERROR2_FORM; + } + else if (regval & CAN_ESR_ACKERROR) + { + /* Acknowledge Error */ + + errbits |= CAN_ERROR_NOACK; + } + else if (regval & CAN_ESR_BRECERROR) + { + /* Bit recessive Error */ + + errbits |= CAN_ERROR_PROTOCOL; + data[2] |= CAN_ERROR2_BIT1; + } + else if (regval & CAN_ESR_BDOMERROR) + { + /* Bit dominant Error */ + + errbits |= CAN_ERROR_PROTOCOL; + data[2] |= CAN_ERROR2_BIT0; + } + else if (regval & CAN_ESR_CRCERRPR) + { + /* Receive CRC Error */ + + errbits |= CAN_ERROR_PROTOCOL; + data[3] |= CAN_ERROR3_CRCSEQ; + } + } + + /* Get transmit status register */ + + regval = stm32can_getreg(priv, STM32_CAN_TSR_OFFSET); + + if (regval & CAN_TSR_ALST0 || regval & CAN_TSR_ALST1 || + regval & CAN_TSR_ALST2) + { + /* Lost arbitration Error */ + + errbits |= CAN_ERROR_LOSTARB; + } + + /* Clear TSR register */ + + stm32can_putreg(priv, STM32_CAN_TSR_OFFSET, regval); + + /* Clear ERRI flag */ + + stm32can_putreg(priv, STM32_CAN_MSR_OFFSET, CAN_MSR_ERRI); + } + + /* TODO: RX overflow and TX overflow */ + + /* Report a CAN error */ + + if (errbits != 0) + { + canerr("ERROR: errbits = %08" PRIx16 "\n", errbits); + + /* Format the CAN header for the error report. */ + + hdr.ch_id = errbits; + hdr.ch_dlc = CAN_ERROR_DLC; + hdr.ch_rtr = 0; + hdr.ch_error = 1; +#ifdef CONFIG_CAN_EXTID + hdr.ch_extid = 0; +#endif + hdr.ch_unused = 0; + + /* And provide the error report to the upper half logic */ + + ret = can_receive(dev, &hdr, data); + if (ret < 0) + { + canerr("ERROR: can_receive failed: %d\n", ret); + } + } + + return ret; +} +#endif + /**************************************************************************** * Name: stm32can_bittiming * From c0b5f3e0353a73d8320da4d2358b7d126ab691cd Mon Sep 17 00:00:00 2001 From: raiden00pl Date: Wed, 5 Jan 2022 10:28:47 +0100 Subject: [PATCH 19/43] [BACKPORT] stm32: add SocketCAN support, based on stm32_can.c --- arch/arm/src/stm32/Kconfig | 14 + arch/arm/src/stm32/Make.defs | 5 + arch/arm/src/stm32/stm32_can.h | 28 +- arch/arm/src/stm32/stm32_can_sock.c | 2465 +++++++++++++++++++++++++++ 4 files changed, 2507 insertions(+), 5 deletions(-) create mode 100644 arch/arm/src/stm32/stm32_can_sock.c diff --git a/arch/arm/src/stm32/Kconfig b/arch/arm/src/stm32/Kconfig index bd3fa46f5eb..1857035c31e 100644 --- a/arch/arm/src/stm32/Kconfig +++ b/arch/arm/src/stm32/Kconfig @@ -10655,6 +10655,20 @@ config STM32_USB_ITRMP menu "CAN driver configuration" depends on STM32_CAN +choice + prompt "CAN character driver or SocketCAN support" + default STM32_CAN_CHARDRIVER + +config STM32_CAN_CHARDRIVER + bool "STM32 CAN character driver support" + select ARCH_HAVE_CAN_ERRORS + +config STM32_CAN_SOCKET + bool "STM32 CAN SocketCAN support" + select NET_CAN_HAVE_ERRORS + +endchoice # CAN character driver or SocketCAN support + config STM32_CAN1_BAUD int "CAN1 BAUD" default 250000 diff --git a/arch/arm/src/stm32/Make.defs b/arch/arm/src/stm32/Make.defs index 3bb9339b0e2..60e753632de 100644 --- a/arch/arm/src/stm32/Make.defs +++ b/arch/arm/src/stm32/Make.defs @@ -233,8 +233,13 @@ CHIP_CSRCS += stm32_qencoder.c endif ifeq ($(CONFIG_STM32_CAN),y) +ifeq ($(CONFIG_STM32_CAN_CHARDRIVER),y) CHIP_CSRCS += stm32_can.c endif +ifeq ($(CONFIG_STM32_CAN_SOCKET),y) +CHIP_CSRCS += stm32_can_sock.c +endif +endif ifeq ($(CONFIG_STM32_IWDG),y) CHIP_CSRCS += stm32_iwdg.c diff --git a/arch/arm/src/stm32/stm32_can.h b/arch/arm/src/stm32/stm32_can.h index 7beefda91d7..37ef72daf29 100644 --- a/arch/arm/src/stm32/stm32_can.h +++ b/arch/arm/src/stm32/stm32_can.h @@ -48,9 +48,6 @@ # undef CONFIG_STM32_CAN1 #endif -#if defined(CONFIG_CAN) && \ - (defined(CONFIG_STM32_CAN1) || defined(CONFIG_STM32_CAN2)) - /* CAN BAUD */ #if defined(CONFIG_STM32_CAN1) && !defined(CONFIG_STM32_CAN1_BAUD) @@ -107,11 +104,13 @@ extern "C" * Public Function Prototypes ****************************************************************************/ +#ifdef CONFIG_STM32_CAN_CHARDRIVER + /**************************************************************************** * Name: stm32_caninitialize * * Description: - * Initialize the selected CAN port + * Initialize the selected CAN port as character device * * Input Parameters: * Port number (for hardware that has multiple CAN interfaces) @@ -123,6 +122,26 @@ extern "C" struct can_dev_s; FAR struct can_dev_s *stm32_caninitialize(int port); +#endif + +#ifdef CONFIG_STM32_CAN_SOCKET + +/**************************************************************************** + * Name: stm32_cansockinitialize + * + * Description: + * Initialize the selected CAN port as SocketCAN interface + * + * Input Parameters: + * Port number (for hardware that has multiple CAN interfaces) + * + * Returned Value: + * OK on success; Negated errno on failure. + * + ****************************************************************************/ + +int stm32_cansockinitialize(int port); +#endif #undef EXTERN #if defined(__cplusplus) @@ -130,5 +149,4 @@ FAR struct can_dev_s *stm32_caninitialize(int port); #endif #endif /* __ASSEMBLY__ */ -#endif /* CONFIG_CAN && (CONFIG_STM32_CAN1 || CONFIG_STM32_CAN2) */ #endif /* __ARCH_ARM_SRC_STM32_STM32_CAN_H */ diff --git a/arch/arm/src/stm32/stm32_can_sock.c b/arch/arm/src/stm32/stm32_can_sock.c new file mode 100644 index 00000000000..c04505ab4f3 --- /dev/null +++ b/arch/arm/src/stm32/stm32_can_sock.c @@ -0,0 +1,2465 @@ +/**************************************************************************** + * arch/arm/src/stm32/stm32_can_sock.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 +#include +#include +#include + +#include "arm_internal.h" +#include "arm_arch.h" + +#include "chip.h" +#include "stm32.h" +#include "stm32_rcc.h" +#include "stm32_can.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Delays *******************************************************************/ + +/* Time out for INAK bit */ + +#define INAK_TIMEOUT 65535 + +/* Bit timing ***************************************************************/ + +#define CAN_BIT_QUANTA (CONFIG_STM32_CAN_TSEG1 + CONFIG_STM32_CAN_TSEG2 + 1) + +#ifndef CONFIG_DEBUG_CAN_INFO +# undef CONFIG_STM32_CAN_REGDEBUG +#endif + +/* Pool configuration *******************************************************/ + +#define POOL_SIZE (1) + +/* Work queue support is required. */ + +#if !defined(CONFIG_SCHED_WORKQUEUE) +# error Work queue support is required +#endif + +/* The low priority work queue is preferred. If it is not enabled, LPWORK + * will be the same as HPWORK. + * + * NOTE: However, the network should NEVER run on the high priority work + * queue! That queue is intended only to service short back end interrupt + * processing that never suspends. Suspending the high priority work queue + * may bring the system to its knees! + */ + +#define CANWORK LPWORK + +/* CAN error interrupts */ + +#ifdef CONFIG_NET_CAN_ERRORS +# define STM32_CAN_ERRINT (CAN_IER_LECIE | CAN_IER_ERRIE | \ + CAN_IER_BOFIE | CAN_IER_EPVIE | \ + CAN_IER_EWGIE) +#endif + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct stm32_can_s +{ + uint8_t port; /* CAN port number (1 or 2) */ + uint8_t canrx[2]; /* CAN RX FIFO 0/1 IRQ number */ + uint8_t cantx; /* CAN TX IRQ number */ +#ifdef CONFIG_NET_CAN_ERRORS + uint8_t cansce; /* CAN SCE IRQ number */ +#endif + uint8_t filter; /* Filter number */ + uint32_t base; /* Base address of the CAN control registers */ + uint32_t fbase; /* Base address of the CAN filter registers */ + uint32_t baud; /* Configured baud */ + + bool bifup; /* true:ifup false:ifdown */ + struct net_driver_s dev; /* Interface understood by the network */ + + struct work_s irqwork; /* For deferring interrupt work to the wq */ + struct work_s pollwork; /* For deferring poll work to the work wq */ + + /* A pointers to the list of TX/RX descriptors */ + + FAR struct can_frame *txdesc; + FAR struct can_frame *rxdesc; + + /* TX/RX pool */ + + uint8_t tx_pool[sizeof(struct can_frame)*POOL_SIZE]; + uint8_t rx_pool[sizeof(struct can_frame)*POOL_SIZE]; +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* CAN Register access */ + +static uint32_t stm32can_getreg(FAR struct stm32_can_s *priv, + int offset); +static uint32_t stm32can_getfreg(FAR struct stm32_can_s *priv, + int offset); +static void stm32can_putreg(FAR struct stm32_can_s *priv, int offset, + uint32_t value); +static void stm32can_putfreg(FAR struct stm32_can_s *priv, int offset, + uint32_t value); +#ifdef CONFIG_STM32_CAN_REGDEBUG +static void stm32can_dumpctrlregs(FAR struct stm32_can_s *priv, + FAR const char *msg); +static void stm32can_dumpmbregs(FAR struct stm32_can_s *priv, + FAR const char *msg); +static void stm32can_dumpfiltregs(FAR struct stm32_can_s *priv, + FAR const char *msg); +#else +# define stm32can_dumpctrlregs(priv,msg) +# define stm32can_dumpmbregs(priv,msg) +# define stm32can_dumpfiltregs(priv,msg) +#endif + +/* CAN interrupt enable functions */ + +static void stm32can_rx0int(FAR struct stm32_can_s *priv, bool enable); +static void stm32can_rx1int(FAR struct stm32_can_s *priv, bool enable); +static void stm32can_txint(FAR struct stm32_can_s *priv, bool enable); +#ifdef CONFIG_NET_CAN_ERRORS +static void stm32can_errint(FAR struct stm32_can_s *priv, bool enable); +#endif + +/* Common TX logic */ + +static int stm32can_transmit(FAR struct stm32_can_s *priv); +static bool stm32can_txready(FAR struct stm32_can_s *priv); +static int stm32can_txpoll(struct net_driver_s *dev); + +/* CAN RX interrupt handling */ + +static int stm32can_rxinterrupt_work(FAR struct stm32_can_s *priv, + int rxmb); + +static void stm32can_rx0interrupt_work(FAR void *arg); +static void stm32can_rx1interrupt_work(FAR void *arg); +static int stm32can_rxinterrupt(FAR struct stm32_can_s *priv, int rxmb); + +static int stm32can_rx0interrupt(int irq, FAR void *context, FAR void *arg); +static int stm32can_rx1interrupt(int irq, FAR void *context, FAR void *arg); + +/* CAN TX interrupt handling */ + +static int stm32can_txinterrupt(int irq, FAR void *context, FAR void *arg); +static void stm32can_txdone_work(FAR void *arg); +static void stm32can_txdone(FAR struct stm32_can_s *priv); + +#ifdef CONFIG_NET_CAN_ERRORS +/* CAN errors interrupt handling */ + +static void stm32can_sceinterrupt_work(FAR void *arg); +static int stm32can_sceinterrupt(int irq, FAR void *context, FAR void *arg); +#endif + +/* Initialization */ + +static int stm32can_setup(FAR struct stm32_can_s *priv); +static void stm32can_shutdown(FAR struct stm32_can_s *priv); +static void stm32can_reset(FAR struct stm32_can_s *priv); +static int stm32can_enterinitmode(FAR struct stm32_can_s *priv); +static int stm32can_exitinitmode(FAR struct stm32_can_s *priv); +static int stm32can_bittiming(FAR struct stm32_can_s *priv); +static int stm32can_cellinit(FAR struct stm32_can_s *priv); +static int stm32can_filterinit(FAR struct stm32_can_s *priv); + +/* TX mailbox status */ + +static bool stm32can_txmb0empty(uint32_t tsr_regval); +static bool stm32can_txmb1empty(uint32_t tsr_regval); +static bool stm32can_txmb2empty(uint32_t tsr_regval); + +/* NuttX callback functions */ + +static int stm32can_ifup(struct net_driver_s *dev); +static int stm32can_ifdown(struct net_driver_s *dev); + +static void stm32can_txavail_work(FAR void *arg); +static int stm32can_txavail(struct net_driver_s *dev); + +#ifdef CONFIG_NETDEV_IOCTL +static int stm32can_netdev_ioctl(struct net_driver_s *dev, int cmd, + unsigned long arg); +#endif + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +#ifdef CONFIG_STM32_CAN1 + +static struct stm32_can_s g_can1priv = +{ + .port = 1, + .canrx = + { + STM32_IRQ_CAN1RX0, + STM32_IRQ_CAN1RX1, + }, + .cantx = STM32_IRQ_CAN1TX, +#ifdef CONFIG_NET_CAN_ERRORS + .cansce = STM32_IRQ_CAN1SCE, +#endif + .filter = 0, + .base = STM32_CAN1_BASE, + .fbase = STM32_CAN1_BASE, + .baud = CONFIG_STM32_CAN1_BAUD, +}; + +#endif + +#ifdef CONFIG_STM32_CAN2 + +static struct stm32_can_s g_can2priv = +{ + .port = 2, + .canrx = + { + STM32_IRQ_CAN2RX0, + STM32_IRQ_CAN2RX1, + }, + .cantx = STM32_IRQ_CAN2TX, +#ifdef CONFIG_NET_CAN_ERRORS + .cansce = STM32_IRQ_CAN2SCE, +#endif + .filter = CAN_NFILTERS / 2, + .base = STM32_CAN2_BASE, + .fbase = STM32_CAN1_BASE, + .baud = CONFIG_STM32_CAN2_BAUD, +}; + +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: stm32can_getreg + * Name: stm32can_getfreg + * + * Description: + * Read the value of a CAN register or filter block register. + * + ****************************************************************************/ + +#ifdef CONFIG_STM32_CAN_REGDEBUG +static uint32_t stm32can_vgetreg(uint32_t addr) +{ + static uint32_t prevaddr = 0; + static uint32_t preval = 0; + static uint32_t count = 0; + + /* Read the value from the register */ + + uint32_t val = getreg32(addr); + + /* 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 && val == preval) + { + if (count == 0xffffffff || ++count > 3) + { + if (count == 4) + { + ninfo("...\n"); + } + + return val; + } + } + + /* 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 */ + + ninfo("[repeats %" PRIu32 " more times]\n", count - 3); + } + + /* Save the new address, value, and count */ + + prevaddr = addr; + preval = val; + count = 1; + } + + /* Show the register value read */ + + ninfo("%08" PRIx32 "->%08" PRIx32 "\n", addr, val); + return val; +} + +static uint32_t stm32can_getreg(FAR struct stm32_can_s *priv, int offset) +{ + return stm32can_vgetreg(priv->base + offset); +} + +static uint32_t stm32can_getfreg(FAR struct stm32_can_s *priv, int offset) +{ + return stm32can_vgetreg(priv->fbase + offset); +} + +#else +static uint32_t stm32can_getreg(FAR struct stm32_can_s *priv, int offset) +{ + return getreg32(priv->base + offset); +} + +static uint32_t stm32can_getfreg(FAR struct stm32_can_s *priv, int offset) +{ + return getreg32(priv->fbase + offset); +} + +#endif + +/**************************************************************************** + * Name: stm32can_putreg + * Name: stm32can_putfreg + * + * Description: + * Set the value of a CAN register or filter block register. + * + ****************************************************************************/ + +#ifdef CONFIG_STM32_CAN_REGDEBUG +static void stm32can_vputreg(uint32_t addr, uint32_t value) +{ + /* Show the register value being written */ + + ninfo("%08" PRIx32 "->%08" PRIx32 "\n", addr, val); + + /* Write the value */ + + putreg32(value, addr); +} + +static void stm32can_putreg(FAR struct stm32_can_s *priv, int offset, + uint32_t value) +{ + stm32can_vputreg(priv->base + offset, value); +} + +static void stm32can_putfreg(FAR struct stm32_can_s *priv, int offset, + uint32_t value) +{ + stm32can_vputreg(priv->fbase + offset, value); +} + +#else +static void stm32can_putreg(FAR struct stm32_can_s *priv, int offset, + uint32_t value) +{ + putreg32(value, priv->base + offset); +} + +static void stm32can_putfreg(FAR struct stm32_can_s *priv, int offset, + uint32_t value) +{ + putreg32(value, priv->fbase + offset); +} +#endif + +/**************************************************************************** + * Name: stm32can_dumpctrlregs + * + * Description: + * Dump the contents of all CAN control registers + * + * Input Parameters: + * priv - reference to the private CAN driver state structure + * msg - message + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef CONFIG_STM32_CAN_REGDEBUG +static void stm32can_dumpctrlregs(FAR struct stm32_can_s *priv, + FAR const char *msg) +{ + if (msg) + { + ninfo("Control Registers: %s\n", msg); + } + else + { + ninfo("Control Registers:\n"); + } + + /* CAN control and status registers */ + + ninfo(" MCR: %08" PRIx32 " MSR: %08" PRIx32 " TSR: %08" PRIx32 "\n", + getreg32(priv->base + STM32_CAN_MCR_OFFSET), + getreg32(priv->base + STM32_CAN_MSR_OFFSET), + getreg32(priv->base + STM32_CAN_TSR_OFFSET)); + + ninfo(" RF0R: %08" PRIx32 " RF1R: %08" PRIx32 "\n", + getreg32(priv->base + STM32_CAN_RF0R_OFFSET), + getreg32(priv->base + STM32_CAN_RF1R_OFFSET)); + + ninfo(" IER: %08" PRIx32 " ESR: %08" PRIx32 " BTR: %08" PRIx32 "\n", + getreg32(priv->base + STM32_CAN_IER_OFFSET), + getreg32(priv->base + STM32_CAN_ESR_OFFSET), + getreg32(priv->base + STM32_CAN_BTR_OFFSET)); +} +#endif + +/**************************************************************************** + * Name: stm32can_dumpmbregs + * + * Description: + * Dump the contents of all CAN mailbox registers + * + * Input Parameters: + * priv - reference to the private CAN driver state structure + * msg - message + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef CONFIG_STM32_CAN_REGDEBUG +static void stm32can_dumpmbregs(FAR struct stm32_can_s *priv, + FAR const char *msg) +{ + if (msg) + { + ninfo("Mailbox Registers: %s\n", msg); + } + else + { + ninfo("Mailbox Registers:\n"); + } + + /* CAN mailbox registers (3 TX and 2 RX) */ + + ninfo(" TI0R: %08" PRIx32 " TDT0R: %08" PRIx32 " TDL0R: %08" + PRIx32 " TDH0R: %08" PRIx32 "\n", + getreg32(priv->base + STM32_CAN_TI0R_OFFSET), + getreg32(priv->base + STM32_CAN_TDT0R_OFFSET), + getreg32(priv->base + STM32_CAN_TDL0R_OFFSET), + getreg32(priv->base + STM32_CAN_TDH0R_OFFSET)); + + ninfo(" TI1R: %08" PRIx32 " TDT1R: %08" PRIx32 " TDL1R: %08" + PRIx32 " TDH1R: %08" PRIx32 "\n", + getreg32(priv->base + STM32_CAN_TI1R_OFFSET), + getreg32(priv->base + STM32_CAN_TDT1R_OFFSET), + getreg32(priv->base + STM32_CAN_TDL1R_OFFSET), + getreg32(priv->base + STM32_CAN_TDH1R_OFFSET)); + + ninfo(" TI2R: %08" PRIx32 " TDT2R: %08" PRIx32 " TDL2R: %08" + PRIx32 " TDH2R: %08" PRIx32 "\n", + getreg32(priv->base + STM32_CAN_TI2R_OFFSET), + getreg32(priv->base + STM32_CAN_TDT2R_OFFSET), + getreg32(priv->base + STM32_CAN_TDL2R_OFFSET), + getreg32(priv->base + STM32_CAN_TDH2R_OFFSET)); + + ninfo(" RI0R: %08" PRIx32 " RDT0R: %08" PRIx32 " RDL0R: %08" + PRIx32 " RDH0R: %08" PRIx32 "\n", + getreg32(priv->base + STM32_CAN_RI0R_OFFSET), + getreg32(priv->base + STM32_CAN_RDT0R_OFFSET), + getreg32(priv->base + STM32_CAN_RDL0R_OFFSET), + getreg32(priv->base + STM32_CAN_RDH0R_OFFSET)); + + ninfo(" RI1R: %08" PRIx32 " RDT1R: %08" PRIx32 " RDL1R: %08" + PRIx32 " RDH1R: %08" PRIx32 "\n", + getreg32(priv->base + STM32_CAN_RI1R_OFFSET), + getreg32(priv->base + STM32_CAN_RDT1R_OFFSET), + getreg32(priv->base + STM32_CAN_RDL1R_OFFSET), + getreg32(priv->base + STM32_CAN_RDH1R_OFFSET)); +} +#endif + +/**************************************************************************** + * Name: stm32can_dumpfiltregs + * + * Description: + * Dump the contents of all CAN filter registers + * + * Input Parameters: + * priv - reference to the private CAN driver state structure + * msg - message + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef CONFIG_STM32_CAN_REGDEBUG +static void stm32can_dumpfiltregs(FAR struct stm32_can_s *priv, + FAR const char *msg) +{ + int i; + + if (msg) + { + ninfo("Filter Registers: %s\n", msg); + } + else + { + ninfo("Filter Registers:\n"); + } + + ninfo(" FMR: %08" PRIx32 " FM1R: %08" PRIx32 " FS1R: %08" + PRIx32 " FFA1R: %08" PRIx32 " FA1R: %08" PRIx32 "\n", + getreg32(priv->base + STM32_CAN_FMR_OFFSET), + getreg32(priv->base + STM32_CAN_FM1R_OFFSET), + getreg32(priv->base + STM32_CAN_FS1R_OFFSET), + getreg32(priv->base + STM32_CAN_FFA1R_OFFSET), + getreg32(priv->base + STM32_CAN_FA1R_OFFSET)); + + for (i = 0; i < CAN_NFILTERS; i++) + { + ninfo(" F%dR1: %08" PRIx32 " F%dR2: %08" PRIx32 "\n", + i, getreg32(priv->base + STM32_CAN_FIR_OFFSET(i, 1)), + i, getreg32(priv->base + STM32_CAN_FIR_OFFSET(i, 2))); + } +} +#endif + +/**************************************************************************** + * Name: stm32can_rx0int + * + * Description: + * Call to enable or disable RX0 interrupts. + * + * Input Parameters: + * priv - reference to the private CAN driver state structure + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void stm32can_rx0int(FAR struct stm32_can_s *priv, bool enable) +{ + uint32_t regval = 0; + + ninfo("CAN%" PRIu8 "RX0 enable: %d\n", priv->port, enable); + + /* Enable/disable the FIFO 0 message pending interrupt */ + + regval = stm32can_getreg(priv, STM32_CAN_IER_OFFSET); + if (enable) + { + regval |= CAN_IER_FMPIE0; + } + else + { + regval &= ~CAN_IER_FMPIE0; + } + + stm32can_putreg(priv, STM32_CAN_IER_OFFSET, regval); +} + +/**************************************************************************** + * Name: stm32can_rx1int + * + * Description: + * Call to enable or disable RX1 interrupts. + * + * Input Parameters: + * priv - reference to the private CAN driver state structure + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void stm32can_rx1int(FAR struct stm32_can_s *priv, bool enable) +{ + uint32_t regval = 0; + + ninfo("CAN%" PRIu8 "RX1 enable: %d\n", priv->port, enable); + + /* Enable/disable the FIFO 1 message pending interrupt */ + + regval = stm32can_getreg(priv, STM32_CAN_IER_OFFSET); + if (enable) + { + regval |= CAN_IER_FMPIE1; + } + else + { + regval &= ~CAN_IER_FMPIE1; + } + + stm32can_putreg(priv, STM32_CAN_IER_OFFSET, regval); +} + +/**************************************************************************** + * Name: stm32can_txint + * + * Description: + * Call to enable or disable TX interrupts. + * + * Input Parameters: + * priv - reference to the private CAN driver state structure + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void stm32can_txint(FAR struct stm32_can_s *priv, bool enable) +{ + uint32_t regval = 0; + + ninfo("CAN%" PRIu8 " txint enable: %d\n", priv->port, enable); + + /* Enable/disable the transmit mailbox interrupt */ + + regval = stm32can_getreg(priv, STM32_CAN_IER_OFFSET); + if (enable) + { + regval |= CAN_IER_TMEIE; + } + else + { + regval &= ~CAN_IER_TMEIE; + } + + stm32can_putreg(priv, STM32_CAN_IER_OFFSET, regval); +} + +#ifdef CONFIG_NET_CAN_ERRORS +/**************************************************************************** + * Name: stm32can_txint + * + * Description: + * Call to enable or disable CAN SCE interrupts. + * + * Input Parameters: + * priv - reference to the private CAN driver state structure + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void stm32can_errint(FAR struct stm32_can_s *priv, bool enable) +{ + uint32_t regval = 0; + + /* Enable/disable the transmit mailbox interrupt */ + + regval = stm32can_getreg(priv, STM32_CAN_IER_OFFSET); + if (enable) + { + regval |= STM32_CAN_ERRINT; + } + else + { + regval &= ~STM32_CAN_ERRINT; + } + + stm32can_putreg(priv, STM32_CAN_IER_OFFSET, regval); +} +#endif + +/**************************************************************************** + * Function: stm32can_ifup + * + * Description: + * NuttX Callback: Bring up the Ethernet interface when an IP address is + * provided + * + * Input Parameters: + * dev - Reference to the NuttX driver state structure + * + * Returned Value: + * None + * + * Assumptions: + * + ****************************************************************************/ + +static int stm32can_ifup(struct net_driver_s *dev) +{ + FAR struct stm32_can_s *priv = (FAR struct stm32_can_s *)dev->d_private; + + /* Setup CAN */ + + stm32can_setup(priv); + + /* Enable interrupts */ + + stm32can_rx0int(priv, true); + stm32can_rx1int(priv, true); + stm32can_txint(priv, true); +#ifdef CONFIG_NET_CAN_ERRORS + stm32can_errint(priv, true); +#endif + + /* Enable the interrupts at the NVIC */ + + up_enable_irq(priv->canrx[0]); + up_enable_irq(priv->canrx[1]); + up_enable_irq(priv->cantx); +#ifdef CONFIG_NET_CAN_ERRORS + up_enable_irq(priv->cansce); +#endif + + priv->bifup = true; + + priv->txdesc = (struct can_frame *)priv->tx_pool; + priv->rxdesc = (struct can_frame *)priv->rx_pool; + + priv->dev.d_buf = (uint8_t *)priv->txdesc; + + return OK; +} + +/**************************************************************************** + * Function: stm32can_ifdown + * + * Description: + * NuttX Callback: Stop the interface. + * + * Input Parameters: + * dev - Reference to the NuttX driver state structure + * + * Returned Value: + * None + * + * Assumptions: + * + ****************************************************************************/ + +static int stm32can_ifdown(struct net_driver_s *dev) +{ + FAR struct stm32_can_s *priv = (FAR struct stm32_can_s *)dev->d_private; + + /* Disable CAN interrupts */ + + stm32can_shutdown(priv); + + /* Reset CAN */ + + stm32can_reset(priv); + + return OK; +} + +/**************************************************************************** + * Name: stm32can_txready + * + * Description: + * Return true if the CAN hardware can accept another TX message. + * + ****************************************************************************/ + +static bool stm32can_txready(FAR struct stm32_can_s *priv) +{ + uint32_t regval; + + /* Return true if any mailbox is available */ + + regval = stm32can_getreg(priv, STM32_CAN_TSR_OFFSET); + ninfo("CAN%" PRIu8 " TSR: %08" PRIx32 "\n", priv->port, regval); + + return (stm32can_txmb0empty(regval) || stm32can_txmb1empty(regval) || + stm32can_txmb2empty(regval)); +} + +/**************************************************************************** + * Name: stm32can_transmit + * + * Description: + * Start hardware transmission. Called either from the txdone interrupt + * handling or from watchdog based polling. + * + * Input Parameters: + * priv - reference to the private CAN driver state structure + * + * Returned Value: + * OK on success; a negated errno on failure + * + * Assumptions: + * May or may not be called from an interrupt handler. In either case, + * global interrupts are disabled, either explicitly or indirectly through + * interrupt handling logic. + * + ****************************************************************************/ + +static int stm32can_transmit(FAR struct stm32_can_s *priv) +{ + struct can_frame *frame = (struct can_frame *)priv->dev.d_buf; + FAR uint8_t *ptr; + uint32_t regval; + uint32_t tmp; + int dlc; + int txmb; + + ninfo("CAN%" PRIu8 " ID: %" PRIu32 " DLC: %" PRIu8 "\n", + priv->port, (uint32_t)frame->can_id, frame->can_dlc); + + /* Select one empty transmit mailbox */ + + regval = stm32can_getreg(priv, STM32_CAN_TSR_OFFSET); + if (stm32can_txmb0empty(regval)) + { + txmb = 0; + } + else if (stm32can_txmb1empty(regval)) + { + txmb = 1; + } + else if (stm32can_txmb2empty(regval)) + { + txmb = 2; + } + else + { + canerr("ERROR: No available mailbox\n"); + return -EBUSY; + } + + /* Clear TXRQ, RTR, IDE, EXID, and STID fields */ + + regval = stm32can_getreg(priv, STM32_CAN_TIR_OFFSET(txmb)); + regval &= ~(CAN_TIR_TXRQ | CAN_TIR_RTR | CAN_TIR_IDE | + CAN_TIR_EXID_MASK | CAN_TIR_STID_MASK); + stm32can_putreg(priv, STM32_CAN_TIR_OFFSET(txmb), regval); + + /* Set up the ID, standard 11-bit or extended 29-bit. */ + +#ifdef CONFIG_CAN_EXTID + regval &= ~CAN_TIR_EXID_MASK; + if (frame->can_id & CAN_EFF_FLAG) + { + DEBUGASSERT(frame->can_id < (1 << 29)); + regval |= (frame->can_id << CAN_TIR_EXID_SHIFT) | CAN_TIR_IDE; + } + else + { + DEBUGASSERT(frame->can_id < (1 << 11)); + regval |= frame->can_id << CAN_TIR_STID_SHIFT; + } + +#else + regval |= (((uint32_t) frame->can_id << CAN_TIR_STID_SHIFT) & + CAN_TIR_STID_MASK); + +#endif + +#ifdef CONFIG_CAN_USE_RTR + regval |= ((frame->can_id & CAN_RTR_FLAG) ? CAN_TIR_RTR : 0); +#endif + + stm32can_putreg(priv, STM32_CAN_TIR_OFFSET(txmb), regval); + + /* Set up the DLC */ + + dlc = frame->can_dlc; + regval = stm32can_getreg(priv, STM32_CAN_TDTR_OFFSET(txmb)); + regval &= ~(CAN_TDTR_DLC_MASK | CAN_TDTR_TGT); + regval |= (uint32_t)dlc << CAN_TDTR_DLC_SHIFT; + stm32can_putreg(priv, STM32_CAN_TDTR_OFFSET(txmb), regval); + + /* Set up the data fields */ + + ptr = frame->data; + regval = 0; + + if (dlc > 0) + { + tmp = (uint32_t)*ptr++; + regval = tmp << CAN_TDLR_DATA0_SHIFT; + + if (dlc > 1) + { + tmp = (uint32_t)*ptr++; + regval |= tmp << CAN_TDLR_DATA1_SHIFT; + + if (dlc > 2) + { + tmp = (uint32_t)*ptr++; + regval |= tmp << CAN_TDLR_DATA2_SHIFT; + + if (dlc > 3) + { + tmp = (uint32_t)*ptr++; + regval |= tmp << CAN_TDLR_DATA3_SHIFT; + } + } + } + } + + stm32can_putreg(priv, STM32_CAN_TDLR_OFFSET(txmb), regval); + + regval = 0; + if (dlc > 4) + { + tmp = (uint32_t)*ptr++; + regval = tmp << CAN_TDHR_DATA4_SHIFT; + + if (dlc > 5) + { + tmp = (uint32_t)*ptr++; + regval |= tmp << CAN_TDHR_DATA5_SHIFT; + + if (dlc > 6) + { + tmp = (uint32_t)*ptr++; + regval |= tmp << CAN_TDHR_DATA6_SHIFT; + + if (dlc > 7) + { + tmp = (uint32_t)*ptr++; + regval |= tmp << CAN_TDHR_DATA7_SHIFT; + } + } + } + } + + stm32can_putreg(priv, STM32_CAN_TDHR_OFFSET(txmb), regval); + + /* Enable the transmit mailbox empty interrupt (may already be enabled) */ + + regval = stm32can_getreg(priv, STM32_CAN_IER_OFFSET); + regval |= CAN_IER_TMEIE; + stm32can_putreg(priv, STM32_CAN_IER_OFFSET, regval); + + /* Request transmission */ + + regval = stm32can_getreg(priv, STM32_CAN_TIR_OFFSET(txmb)); + regval |= CAN_TIR_TXRQ; /* Transmit Mailbox Request */ + stm32can_putreg(priv, STM32_CAN_TIR_OFFSET(txmb), regval); + + stm32can_dumpmbregs(priv, "After send"); + return OK; +} + +/**************************************************************************** + * Function: stm32can_txpoll + * + * Description: + * The transmitter is available, check if the network has any outgoing + * packets ready to send. This is a callback from devif_poll(). + * devif_poll() may be called: + * + * 1. When the preceding TX packet send is complete, + * 2. When the preceding TX packet send timesout and the interface is reset + * 3. During normal TX polling + * + * Input Parameters: + * dev - Reference to the NuttX driver state structure + * + * Returned Value: + * OK on success; a negated errno on failure + * + * Assumptions: + * May or may not be called from an interrupt handler. In either case, + * global interrupts are disabled, either explicitly or indirectly through + * interrupt handling logic. + * + ****************************************************************************/ + +static int stm32can_txpoll(struct net_driver_s *dev) +{ + FAR struct stm32_can_s *priv = (FAR struct stm32_can_s *)dev->d_private; + + /* If the polling resulted in data that should be sent out on the network, + * the field d_len is set to a value > 0. + */ + + if (priv->dev.d_len > 0) + { + if (!devif_loopback(&priv->dev)) + { + stm32can_txdone(priv); + + /* Send the packet */ + + stm32can_transmit(priv); + + /* Check if there is room in the device to hold another packet. If + * not, return a non-zero value to terminate the poll. + */ + + if (stm32can_txready(priv) == false) + { + return -EBUSY; + } + } + } + + /* If zero is returned, the polling will continue until all connections + * have been examined. + */ + + return 0; +} + +/**************************************************************************** + * Function: stm32can_txavail_work + * + * Description: + * Perform an out-of-cycle poll on the worker thread. + * + * Input Parameters: + * arg - Reference to the NuttX driver state structure (cast to void*) + * + * Returned Value: + * None + * + * Assumptions: + * Called on the higher priority worker thread. + * + ****************************************************************************/ + +static void stm32can_txavail_work(FAR void *arg) +{ + FAR struct stm32_can_s *priv = (FAR struct stm32_can_s *)arg; + + /* Ignore the notification if the interface is not yet up */ + + net_lock(); + if (priv->bifup) + { + /* Check if there is room in the hardware to hold another outgoing + * packet. + */ + + if (stm32can_txready(priv)) + { + /* No, there is space for another transfer. Poll the network for + * new XMIT data. + */ + + devif_timer(&priv->dev, 0, stm32can_txpoll); + } + } + + net_unlock(); +} + +/**************************************************************************** + * Function: stm32can_txavail + * + * Description: + * Driver callback invoked when new TX data is available. This is a + * stimulus perform an out-of-cycle poll and, thereby, reduce the TX + * latency. + * + * Input Parameters: + * dev - Reference to the NuttX driver state structure + * + * Returned Value: + * None + * + * Assumptions: + * Called in normal user mode + * + ****************************************************************************/ + +static int stm32can_txavail(struct net_driver_s *dev) +{ + FAR struct stm32_can_s *priv = (FAR struct stm32_can_s *)dev->d_private; + + /* Is our single work structure available? It may not be if there are + * pending interrupt actions and we will have to ignore the Tx + * availability action. + */ + + if (work_available(&priv->pollwork)) + { + /* Schedule to serialize the poll on the worker thread. */ + + stm32can_txavail_work(priv); + } + + return OK; +} + +/**************************************************************************** + * Function: stm32can_ioctl + * + * Description: + * PHY ioctl command handler + * + * Input Parameters: + * dev - Reference to the NuttX driver state structure + * cmd - ioctl command + * arg - Argument accompanying the command + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + * Assumptions: + * + ****************************************************************************/ + +#ifdef CONFIG_NETDEV_IOCTL +static int stm32can_netdev_ioctl(struct net_driver_s *dev, int cmd, + unsigned long arg) +{ + FAR struct stm32_can_s *priv = (FAR struct stm32_can_s *)dev->d_private; + int ret = OK; + + switch (cmd) + { + /* TODO */ + + default: + ret = -ENOTTY; + break; + } + + return ret; +} +#endif /* CONFIG_NETDEV_IOCTL */ + +/**************************************************************************** + * Name: stm32can_rxinterrupt_work + * + * Description: + * CAN RX FIFO 0/1 interrupt handler + * + * Input Parameters: + * irq - The IRQ number of the interrupt. + * context - The register state save array at the time of the interrupt. + * rxmb - The RX mailbox number. + * + * Returned Value: + * Zero on success; a negated errno on failure + * + ****************************************************************************/ + +static int stm32can_rxinterrupt_work(FAR struct stm32_can_s *priv, int rxmb) +{ + FAR struct can_frame *frame = (struct can_frame *)priv->rxdesc; + uint32_t regval; + int ret = OK; + + DEBUGASSERT(priv != NULL); + + if (rxmb == 0) + { + stm32can_dumpmbregs(priv, "RX0 interrupt"); + } + else + { + stm32can_dumpmbregs(priv, "RX1 interrupt"); + } + + /* Get the CAN identifier. */ + + regval = stm32can_getreg(priv, STM32_CAN_RIR_OFFSET(rxmb)); + +#ifdef CONFIG_CAN_EXTID + if ((regval & CAN_RIR_IDE) != 0) + { + frame->can_id = (regval & CAN_RIR_EXID_MASK) >> CAN_RIR_EXID_SHIFT; + frame->can_id &= ~CAN_EFF_FLAG; + } + else + { + frame->can_id = (regval & CAN_RIR_STID_MASK) >> CAN_RIR_STID_SHIFT; + frame->can_id |= CAN_EFF_FLAG; + } +#else + if ((regval & CAN_RIR_IDE) != 0) + { + nerr("ERROR: Received message with extended identifier. Dropped\n"); + ret = -ENOSYS; + goto errout; + } + + frame->can_id = (regval & CAN_RIR_STID_MASK) >> CAN_RIR_STID_SHIFT; +#endif + + /* Extract the RTR bit */ + + if ((regval & CAN_RIR_RTR) != 0) + { + frame->can_id |= CAN_RTR_FLAG; + } + + /* Get the DLC */ + + regval = stm32can_getreg(priv, STM32_CAN_RDTR_OFFSET(rxmb)); + frame->can_dlc = (regval & CAN_RDTR_DLC_MASK) >> CAN_RDTR_DLC_SHIFT; + + /* Save the message data */ + + regval = stm32can_getreg(priv, STM32_CAN_RDLR_OFFSET(rxmb)); + frame->data[0] = (regval & CAN_RDLR_DATA0_MASK) >> CAN_RDLR_DATA0_SHIFT; + frame->data[1] = (regval & CAN_RDLR_DATA1_MASK) >> CAN_RDLR_DATA1_SHIFT; + frame->data[2] = (regval & CAN_RDLR_DATA2_MASK) >> CAN_RDLR_DATA2_SHIFT; + frame->data[3] = (regval & CAN_RDLR_DATA3_MASK) >> CAN_RDLR_DATA3_SHIFT; + + regval = stm32can_getreg(priv, STM32_CAN_RDHR_OFFSET(rxmb)); + frame->data[4] = (regval & CAN_RDHR_DATA4_MASK) >> CAN_RDHR_DATA4_SHIFT; + frame->data[5] = (regval & CAN_RDHR_DATA5_MASK) >> CAN_RDHR_DATA5_SHIFT; + frame->data[6] = (regval & CAN_RDHR_DATA6_MASK) >> CAN_RDHR_DATA6_SHIFT; + frame->data[7] = (regval & CAN_RDHR_DATA7_MASK) >> CAN_RDHR_DATA7_SHIFT; + + /* Copy the buffer pointer to priv->dev.. Set amount of data + * in priv->dev.d_len + */ + + priv->dev.d_len = sizeof(struct can_frame); + priv->dev.d_buf = (uint8_t *)frame; + + /* Send to socket interface */ + + NETDEV_RXPACKETS(&priv->dev); + + can_input(&priv->dev); + + /* Point the packet buffer back to the next Tx buffer that will be + * used during the next write. If the write queue is full, then + * this will point at an active buffer, which must not be written + * to. This is OK because devif_poll won't be called unless the + * queue is not full. + */ + + priv->dev.d_buf = (uint8_t *)priv->txdesc; + + /* Release the FIFO */ + +#ifndef CONFIG_CAN_EXTID +errout: +#endif + regval = stm32can_getreg(priv, STM32_CAN_RFR_OFFSET(rxmb)); + regval |= CAN_RFR_RFOM; + stm32can_putreg(priv, STM32_CAN_RFR_OFFSET(rxmb), regval); + + /* Re-enable CAN RX interrupts */ + + if (rxmb == 0) + { + stm32can_rx0int(priv, true); + } + else if (rxmb == 1) + { + stm32can_rx1int(priv, true); + } + else + { + DEBUGASSERT(0); + } + + return ret; +} + +/**************************************************************************** + * Name: stm32can_rx0interrupt_work + ****************************************************************************/ + +static void stm32can_rx0interrupt_work(FAR void *arg) +{ + FAR struct stm32_can_s *priv = (FAR struct stm32_can_s *)arg; + stm32can_rxinterrupt_work(priv, 0); +} + +/**************************************************************************** + * Name: stm32can_rx1interrupt_work + ****************************************************************************/ + +static void stm32can_rx1interrupt_work(FAR void *arg) +{ + FAR struct stm32_can_s *priv = (FAR struct stm32_can_s *)arg; + stm32can_rxinterrupt_work(priv, 1); +} + +/**************************************************************************** + * Name: stm32can_rxinterrupt + * + * Description: + * CAN RX FIFO common interrupt handler + * + ****************************************************************************/ + +static int stm32can_rxinterrupt(FAR struct stm32_can_s *priv, int rxmb) +{ + uint32_t regval = 0; + int npending = 0; + + /* Verify that a message is pending in the FIFO */ + + regval = stm32can_getreg(priv, STM32_CAN_RFR_OFFSET(rxmb)); + npending = (regval & CAN_RFR_FMP_MASK) >> CAN_RFR_FMP_SHIFT; + if (npending < 1) + { + nwarn("WARNING: No messages pending\n"); + return OK; + } + + /* Disable further CAN RX interrupts and schedule to perform the + * interrupt processing on the worker thread + */ + + if (rxmb == 0) + { + stm32can_rx0int(priv, false); + work_queue(CANWORK, &priv->irqwork, + stm32can_rx0interrupt_work, priv, 0); + } + else if (rxmb == 1) + { + stm32can_rx1int(priv, false); + work_queue(CANWORK, &priv->irqwork, + stm32can_rx1interrupt_work, priv, 0); + } + else + { + DEBUGASSERT(0); + } + + return OK; +} + +/**************************************************************************** + * Name: stm32can_rx0interrupt + * + * Description: + * CAN RX FIFO 0 interrupt handler + * + * Input Parameters: + * irq - The IRQ number of the interrupt. + * context - The register state save array at the time of the interrupt. + * + * Returned Value: + * Zero on success; a negated errno on failure + * + ****************************************************************************/ + +static int stm32can_rx0interrupt(int irq, FAR void *context, FAR void *arg) +{ + FAR struct stm32_can_s *priv = (FAR struct stm32_can_s *)arg; + return stm32can_rxinterrupt(priv, 0); +} + +/**************************************************************************** + * Name: stm32can_rx1interrupt + * + * Description: + * CAN RX FIFO 1 interrupt handler + * + * Input Parameters: + * irq - The IRQ number of the interrupt. + * context - The register state save array at the time of the interrupt. + * + * Returned Value: + * Zero on success; a negated errno on failure + * + ****************************************************************************/ + +static int stm32can_rx1interrupt(int irq, FAR void *context, FAR void *arg) +{ + FAR struct stm32_can_s *priv = (FAR struct stm32_can_s *)arg; + return stm32can_rxinterrupt(priv, 1); +} + +/**************************************************************************** + * Name: stm32can_txinterrupt + * + * Description: + * CAN TX mailbox complete interrupt handler + * + * Input Parameters: + * irq - The IRQ number of the interrupt. + * context - The register state save array at the time of the interrupt. + * + * Returned Value: + * Zero on success; a negated errno on failure + * + ****************************************************************************/ + +static int stm32can_txinterrupt(int irq, FAR void *context, FAR void *arg) +{ + FAR struct stm32_can_s *priv = (FAR struct stm32_can_s *)arg; + uint32_t regval; + + DEBUGASSERT(priv != NULL); + + /* Get the transmit status */ + + regval = stm32can_getreg(priv, STM32_CAN_TSR_OFFSET); + + /* Check for RQCP0: Request completed mailbox 0 */ + + if ((regval & CAN_TSR_RQCP0) != 0) + { + /* Writing '1' to RCP0 clears RCP0 and all the status bits (TXOK0, + * ALST0 and TERR0) for Mailbox 0. + */ + + stm32can_putreg(priv, STM32_CAN_TSR_OFFSET, CAN_TSR_RQCP0); + + /* Tell the upper half that the transfer is finished. */ + + /* Disable further TX CAN interrupts. here can be no race + * condition here. + */ + + stm32can_txint(priv, false); + work_queue(CANWORK, &priv->irqwork, stm32can_txdone_work, priv, 0); + } + + /* Check for RQCP1: Request completed mailbox 1 */ + + if ((regval & CAN_TSR_RQCP1) != 0) + { + /* Writing '1' to RCP1 clears RCP1 and all the status bits (TXOK1, + * ALST1 and TERR1) for Mailbox 1. + */ + + stm32can_putreg(priv, STM32_CAN_TSR_OFFSET, CAN_TSR_RQCP1); + + /* Tell the upper half that the transfer is finished. */ + + /* Disable further TX CAN interrupts. here can be no race + * condition here. + */ + + stm32can_txint(priv, false); + work_queue(CANWORK, &priv->irqwork, stm32can_txdone_work, priv, 0); + } + + /* Check for RQCP2: Request completed mailbox 2 */ + + if ((regval & CAN_TSR_RQCP2) != 0) + { + /* Writing '1' to RCP2 clears RCP2 and all the status bits (TXOK2, + * ALST2 and TERR2) for Mailbox 2. + */ + + stm32can_putreg(priv, STM32_CAN_TSR_OFFSET, CAN_TSR_RQCP2); + + /* Disable further TX CAN interrupts. here can be no race + * condition here. + */ + + stm32can_txint(priv, false); + work_queue(CANWORK, &priv->irqwork, stm32can_txdone_work, priv, 0); + } + + return OK; +} + +/**************************************************************************** + * Name: stm32can_txdone_work + ****************************************************************************/ + +static void stm32can_txdone_work(FAR void *arg) +{ + FAR struct stm32_can_s *priv = (FAR struct stm32_can_s *)arg; + + stm32can_txdone(priv); + + /* There should be space for a new TX in any event. Poll the network for + * new XMIT data + */ + + net_lock(); + devif_timer(&priv->dev, 0, stm32can_txpoll); + net_unlock(); +} + +/**************************************************************************** + * Name: stm32can_txdone + ****************************************************************************/ + +static void stm32can_txdone(FAR struct stm32_can_s *priv) +{ + stm32can_txint(priv, true); + + NETDEV_TXDONE(&priv->dev); +} + +#ifdef CONFIG_NET_CAN_ERRORS + +/**************************************************************************** + * Name: stm32can_sceinterrupt_work + * + * Description: + * CAN status change interrupt work + * + * Input Parameters: + * arg - reference to the driver state structure + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void stm32can_sceinterrupt_work(FAR void *arg) +{ + FAR struct stm32_can_s *priv = (FAR struct stm32_can_s *)arg; + struct can_frame *frame = (struct can_frame *)priv->rxdesc; + uint32_t regval = 0; + uint16_t errbits = 0; + uint8_t data[CAN_ERR_DLC]; + + DEBUGASSERT(priv != NULL); + + /* Check Error Interrupt flag */ + + regval = stm32can_getreg(priv, STM32_CAN_MSR_OFFSET); + if (regval & CAN_MSR_ERRI) + { + /* Encode error bits */ + + errbits = 0; + memset(data, 0, sizeof(data)); + + /* Get Error statur register */ + + regval = stm32can_getreg(priv, STM32_CAN_ESR_OFFSET); + + if (regval & CAN_ESR_EWGF) + { + /* Error warning flag */ + + data[1] |= (CAN_ERR_CTRL_RX_WARNING | CAN_ERR_CTRL_TX_WARNING); + errbits |= CAN_ERR_CTRL; + } + + if (regval & CAN_ESR_EPVF) + { + /* Error passive flag */ + + data[1] |= (CAN_ERR_CTRL_RX_PASSIVE | CAN_ERR_CTRL_TX_PASSIVE); + errbits |= CAN_ERR_CTRL; + } + + if (regval & CAN_ESR_BOFF) + { + /* Bus-off flag */ + + errbits |= CAN_ERR_BUSOFF; + } + + /* Last error code */ + + if (regval & CAN_ESR_LEC_MASK) + { + if (regval & CAN_ESR_STUFFERROR) + { + /* Stuff Error */ + + errbits |= CAN_ERR_PROT; + data[2] |= CAN_ERR_PROT_STUFF; + } + else if (regval & CAN_ESR_FORMERROR) + { + /* Format Error */ + + errbits |= CAN_ERR_PROT; + data[2] |= CAN_ERR_PROT_FORM; + } + else if (regval & CAN_ESR_ACKERROR) + { + /* Acknowledge Error */ + + errbits |= CAN_ERR_ACK; + } + else if (regval & CAN_ESR_BRECERROR) + { + /* Bit recessive Error */ + + errbits |= CAN_ERR_PROT; + data[2] |= CAN_ERR_PROT_BIT1; + } + else if (regval & CAN_ESR_BDOMERROR) + { + /* Bit dominant Error */ + + errbits |= CAN_ERR_PROT; + data[2] |= CAN_ERR_PROT_BIT0; + } + else if (regval & CAN_ESR_CRCERRPR) + { + /* Receive CRC Error */ + + errbits |= CAN_ERR_PROT; + data[3] |= CAN_ERR_PROT_LOC_CRCSEQ; + } + } + + /* Get transmit status register */ + + regval = stm32can_getreg(priv, STM32_CAN_TSR_OFFSET); + + if (regval & CAN_TSR_ALST0 || regval & CAN_TSR_ALST1 || + regval & CAN_TSR_ALST2) + { + /* Lost arbitration Error */ + + errbits |= CAN_ERR_LOSTARB; + } + + /* Clear TSR register */ + + stm32can_putreg(priv, STM32_CAN_TSR_OFFSET, regval); + + /* Clear ERRI flag */ + + stm32can_putreg(priv, STM32_CAN_MSR_OFFSET, CAN_MSR_ERRI); + } + + /* Report a CAN error */ + + if (errbits != 0) + { + canerr("ERROR: errbits = %08" PRIx16 "\n", errbits); + + /* Copy frame */ + + frame->can_id = errbits; + frame->can_dlc = CAN_ERR_DLC; + + memcpy(frame->data, data, CAN_ERR_DLC); + + /* Copy the buffer pointer to priv->dev.. Set amount of data + * in priv->dev.d_len + */ + + priv->dev.d_len = sizeof(struct can_frame); + priv->dev.d_buf = (uint8_t *)frame; + + /* Send to socket interface */ + + NETDEV_ERRORS(&priv->dev); + + can_input(&priv->dev); + + /* Point the packet buffer back to the next Tx buffer that will be + * used during the next write. If the write queue is full, then + * this will point at an active buffer, which must not be written + * to. This is OK because devif_poll won't be called unless the + * queue is not full. + */ + + priv->dev.d_buf = (uint8_t *)priv->txdesc; + } + + /* Re-enable CAN SCE interrupts */ + + stm32can_errint(priv, true); +} + +/**************************************************************************** + * Name: stm32can_sceinterrupt + * + * Description: + * CAN status change interrupt handler + * + * Input Parameters: + * irq - The IRQ number of the interrupt. + * context - The register state save array at the time of the interrupt. + * + * Returned Value: + * Zero on success; a negated errno on failure + * + ****************************************************************************/ + +static int stm32can_sceinterrupt(int irq, FAR void *context, FAR void *arg) +{ + FAR struct stm32_can_s *priv = (FAR struct stm32_can_s *)arg; + + /* Disable further CAN SCE interrupts and schedule to perform the + * interrupt processing on the worker thread + */ + + stm32can_errint(priv, false); + work_queue(CANWORK, &priv->irqwork, + stm32can_sceinterrupt_work, priv, 0); + + return OK; +} +#endif + +/**************************************************************************** + * Name: stm32can_bittiming + * + * Description: + * Set the CAN bit timing register (BTR) based on the configured BAUD. + * + * "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 * Tpclk1 + * baud = Fpclk1 / (brp * (1 + ts1 + ts2)) + * + * Where: + * Tpclk1 is the period of the APB1 clock (PCLK1). + * + * Input Parameters: + * priv - reference to the private CAN driver state structure + * + * Returned Value: + * Zero on success; a negated errno on failure + * + ****************************************************************************/ + +static int stm32can_bittiming(FAR struct stm32_can_s *priv) +{ + uint32_t tmp; + uint32_t brp; + uint32_t ts1; + uint32_t ts2; + + ninfo("CAN%" PRIu8 " PCLK1: %lu baud: %" PRIu32 "\n", + priv->port, (unsigned long) STM32_PCLK1_FREQUENCY, priv->baud); + + /* Try to get CAN_BIT_QUANTA quanta in one bit_time. + * + * bit_time = Tq*(ts1 + ts2 + 1) + * nquanta = bit_time / Tq + * nquanta = (ts1 + ts2 + 1) + * + * bit_time = brp * Tpclk1 * (ts1 + ts2 + 1) + * nquanta = bit_time / brp / Tpclk1 + * = PCLK1 / baud / brp + * brp = PCLK1 / baud / nquanta; + * + * Example: + * PCLK1 = 42,000,000 baud = 1,000,000 nquanta = 14 : brp = 3 + * PCLK1 = 42,000,000 baud = 700,000 nquanta = 14 : brp = 4 + */ + + tmp = STM32_PCLK1_FREQUENCY / priv->baud; + if (tmp < CAN_BIT_QUANTA) + { + /* At the smallest brp value (1), there are already too few bit times + * (PCLCK1 / baud) to meet our goal. brp must be one and we need + * make some reasonable guesses about ts1 and ts2. + */ + + brp = 1; + + /* In this case, we have to guess a good value for ts1 and ts2 */ + + ts1 = (tmp - 1) >> 1; + ts2 = tmp - ts1 - 1; + if (ts1 == ts2 && ts1 > 1 && ts2 < CAN_BTR_TSEG2_MAX) + { + ts1--; + ts2++; + } + } + + /* Otherwise, nquanta is CAN_BIT_QUANTA, ts1 is CONFIG_STM32_CAN_TSEG1, + * ts2 is CONFIG_STM32_CAN_TSEG2 and we calculate brp to achieve + * CAN_BIT_QUANTA quanta in the bit time + */ + + else + { + ts1 = CONFIG_STM32_CAN_TSEG1; + ts2 = CONFIG_STM32_CAN_TSEG2; + brp = (tmp + (CAN_BIT_QUANTA / 2)) / CAN_BIT_QUANTA; + DEBUGASSERT(brp >= 1 && brp <= CAN_BTR_BRP_MAX); + } + + ninfo("TS1: %" PRIu32 " TS2: %" PRIu32 " BRP: %" PRIu32 "\n", + ts1, ts2, brp); + + /* Configure bit timing. This also does the following, less obvious + * things. Unless loopback mode is enabled, it: + * + * - Disables silent mode. + * - Disables loopback mode. + * + * NOTE that for the time being, SJW is set to 1 just because I don't + * know any better. + */ + + tmp = ((brp - 1) << CAN_BTR_BRP_SHIFT) | ((ts1 - 1) << CAN_BTR_TS1_SHIFT) | + ((ts2 - 1) << CAN_BTR_TS2_SHIFT) | ((1 - 1) << CAN_BTR_SJW_SHIFT); +#ifdef CONFIG_CAN_LOOPBACK + /* tmp |= (CAN_BTR_LBKM | CAN_BTR_SILM); */ + + tmp |= CAN_BTR_LBKM; +#endif + + stm32can_putreg(priv, STM32_CAN_BTR_OFFSET, tmp); + return OK; +} + +/**************************************************************************** + * Name: stm32can_setup + ****************************************************************************/ + +static int stm32can_setup(FAR struct stm32_can_s *priv) +{ + int ret; + +#ifdef CONFIG_NET_CAN_ERRORS + ninfo("CAN%" PRIu8 " RX0 irq: %" PRIu8 " RX1 irq: %" PRIu8 + " TX irq: %" PRIu8 " SCE irq: %" PRIu8 "\n", + priv->port, priv->canrx[0], priv->canrx[1], priv->cantx, + priv->cansce); +#else + ninfo("CAN%" PRIu8 " RX0 irq: %" PRIu8 " RX1 irq: %" PRIu8 + " TX irq: %" PRIu8 "\n", + priv->port, priv->canrx[0], priv->canrx[1], priv->cantx); +#endif + + /* CAN cell initialization */ + + ret = stm32can_cellinit(priv); + if (ret < 0) + { + nerr("ERROR: CAN%" PRId8 " cell initialization failed: %d\n", + priv->port, ret); + return ret; + } + + stm32can_dumpctrlregs(priv, "After cell initialization"); + stm32can_dumpmbregs(priv, NULL); + + /* CAN filter initialization */ + + ret = stm32can_filterinit(priv); + if (ret < 0) + { + nerr("ERROR: CAN%" PRIu8 " filter initialization failed: %d\n", + priv->port, ret); + return ret; + } + + stm32can_dumpfiltregs(priv, "After filter initialization"); + + /* Attach the CAN RX FIFO 0/1 interrupts and TX interrupts. + * The others are not used. + */ + + ret = irq_attach(priv->canrx[0], stm32can_rx0interrupt, priv); + if (ret < 0) + { + nerr("ERROR: Failed to attach CAN%" PRIu8 " RX0 IRQ (%" PRIu8 ")", + priv->port, priv->canrx[0]); + return ret; + } + + ret = irq_attach(priv->canrx[1], stm32can_rx1interrupt, priv); + if (ret < 0) + { + nerr("ERROR: Failed to attach CAN%" PRIu8 " RX1 IRQ (%" PRIu8 ")", + priv->port, priv->canrx[1]); + return ret; + } + + ret = irq_attach(priv->cantx, stm32can_txinterrupt, priv); + if (ret < 0) + { + nerr("ERROR: Failed to attach CAN%" PRIu8 " TX IRQ (%" PRIu8 ")", + priv->port, priv->cantx); + return ret; + } + +#ifdef CONFIG_NET_CAN_ERRORS + ret = irq_attach(priv->cansce, stm32can_sceinterrupt, priv); + if (ret < 0) + { + nerr("ERROR: Failed to attach CAN%" PRIu8 " SCE IRQ (%" PRIu8 ")", + priv->port, priv->cansce); + return ret; + } +#endif + + return OK; +} + +/**************************************************************************** + * Name: stm32can_shutdown + ****************************************************************************/ + +static void stm32can_shutdown(FAR struct stm32_can_s *priv) +{ + ninfo("CAN%" PRIu8 "\n", priv->port); + + /* Disable the RX FIFO 0/1 and TX interrupts */ + + up_disable_irq(priv->canrx[0]); + up_disable_irq(priv->canrx[1]); + up_disable_irq(priv->cantx); +#ifdef CONFIG_NET_CAN_ERRORS + up_disable_irq(priv->cansce); +#endif + + /* Detach the RX FIFO 0/1 and TX interrupts */ + + irq_detach(priv->canrx[0]); + irq_detach(priv->canrx[1]); + irq_detach(priv->cantx); +#ifdef CONFIG_NET_CAN_ERRORS + irq_detach(priv->cansce); +#endif +} + +/**************************************************************************** + * Name: stm32can_reset + * + * Description: + * Put the CAN device in the non-operational, reset state + * + * Input Parameters: + * priv - reference to the private CAN driver state structure + * + * Returned Value: + * None + * + * Assumptions: + * + ****************************************************************************/ + +static void stm32can_reset(FAR struct stm32_can_s *priv) +{ + uint32_t regval; + uint32_t regbit = 0; + irqstate_t flags; + + ninfo("CAN%" PRIu8 "\n", priv->port); + + /* Get the bits in the AHB1RSTR register needed to reset this CAN device */ + +#ifdef CONFIG_STM32_CAN1 + if (priv->port == 1) + { + regbit = RCC_APB1RSTR_CAN1RST; + } + else +#endif +#ifdef CONFIG_STM32_CAN2 + if (priv->port == 2) + { + regbit = RCC_APB1RSTR_CAN2RST; + } + else +#endif + { + nerr("ERROR: Unsupported port %d\n", priv->port); + return; + } + + /* Disable interrupts momentarily to stop any ongoing CAN event processing + * and to prevent any concurrent access to the AHB1RSTR register. + */ + + flags = enter_critical_section(); + + /* Reset the CAN */ + + regval = getreg32(STM32_RCC_APB1RSTR); + regval |= regbit; + putreg32(regval, STM32_RCC_APB1RSTR); + + regval &= ~regbit; + putreg32(regval, STM32_RCC_APB1RSTR); + leave_critical_section(flags); +} + +/**************************************************************************** + * Name: stm32can_enterinitmode + * + * Description: + * Put the CAN cell in Initialization mode. This only disconnects the CAN + * peripheral, no registers are changed. The initialization mode is + * required to change the baud rate. + * + * Input Parameters: + * priv - reference to the private CAN driver state structure + * + * Returned Value: + * Zero on success; a negated errno value on failure. + * + ****************************************************************************/ + +static int stm32can_enterinitmode(FAR struct stm32_can_s *priv) +{ + uint32_t regval; + volatile uint32_t timeout; + + ninfo("CAN%" PRIu8 "\n", priv->port); + + /* Enter initialization mode */ + + regval = stm32can_getreg(priv, STM32_CAN_MCR_OFFSET); + regval |= CAN_MCR_INRQ; + stm32can_putreg(priv, STM32_CAN_MCR_OFFSET, regval); + + /* Wait until initialization mode is acknowledged */ + + for (timeout = INAK_TIMEOUT; timeout > 0; timeout--) + { + regval = stm32can_getreg(priv, STM32_CAN_MSR_OFFSET); + if ((regval & CAN_MSR_INAK) != 0) + { + /* We are in initialization mode */ + + break; + } + } + + /* Check for a timeout */ + + if (timeout < 1) + { + nerr("ERROR: Timed out waiting to enter initialization mode\n"); + return -ETIMEDOUT; + } + + return OK; +} + +/**************************************************************************** + * Name: stm32can_exitinitmode + * + * Description: + * Put the CAN cell out of the Initialization mode (to Normal mode) + * + * Input Parameters: + * priv - reference to the private CAN driver state structure + * + * Returned Value: + * Zero on success; a negated errno value on failure. + * + ****************************************************************************/ + +static int stm32can_exitinitmode(FAR struct stm32_can_s *priv) +{ + uint32_t regval; + volatile uint32_t timeout; + + /* Exit Initialization mode, enter Normal mode */ + + regval = stm32can_getreg(priv, STM32_CAN_MCR_OFFSET); + regval &= ~CAN_MCR_INRQ; + stm32can_putreg(priv, STM32_CAN_MCR_OFFSET, regval); + + /* Wait until the initialization mode exit is acknowledged */ + + for (timeout = INAK_TIMEOUT; timeout > 0; timeout--) + { + regval = stm32can_getreg(priv, STM32_CAN_MSR_OFFSET); + if ((regval & CAN_MSR_INAK) == 0) + { + /* We are out of initialization mode */ + + break; + } + } + + /* Check for a timeout */ + + if (timeout < 1) + { + nerr("ERROR: Timed out waiting to exit initialization mode: %08" + PRIx32 "\n", regval); + return -ETIMEDOUT; + } + + return OK; +} + +/**************************************************************************** + * Name: stm32can_cellinit + * + * Description: + * CAN cell initialization + * + * Input Parameters: + * priv - reference to the private CAN driver state structure + * + * Returned Value: + * Zero on success; a negated errno value on failure. + * + ****************************************************************************/ + +static int stm32can_cellinit(FAR struct stm32_can_s *priv) +{ + uint32_t regval; + int ret; + + ninfo("CAN%" PRIu8 "\n", priv->port); + + /* Exit from sleep mode */ + + regval = stm32can_getreg(priv, STM32_CAN_MCR_OFFSET); + regval &= ~CAN_MCR_SLEEP; + stm32can_putreg(priv, STM32_CAN_MCR_OFFSET, regval); + + ret = stm32can_enterinitmode(priv); + if (ret != 0) + { + return ret; + } + + /* Disable the following modes: + * + * - Time triggered communication mode + * - Automatic bus-off management + * - Automatic wake-up mode + * - No automatic retransmission + * - Receive FIFO locked mode + * + * Enable: + * + * - Transmit FIFO priority + */ + + regval = stm32can_getreg(priv, STM32_CAN_MCR_OFFSET); + regval &= ~(CAN_MCR_RFLM | CAN_MCR_NART | CAN_MCR_AWUM | + CAN_MCR_ABOM | CAN_MCR_TTCM); + regval |= CAN_MCR_TXFP; + stm32can_putreg(priv, STM32_CAN_MCR_OFFSET, regval); + + /* Configure bit timing. */ + + ret = stm32can_bittiming(priv); + if (ret < 0) + { + nerr("ERROR: Failed to set bit timing: %d\n", ret); + return ret; + } + + return stm32can_exitinitmode(priv); +} + +/**************************************************************************** + * Name: stm32can_filterinit + * + * Description: + * CAN filter initialization. CAN filters are not currently used by this + * driver. The CAN filters can be configured in a different way: + * + * 1. As a match of specific IDs in a list (IdList mode), or as + * 2. And ID and a mask (IdMask mode). + * + * Filters can also be configured as: + * + * 3. 16- or 32-bit. The advantage of 16-bit filters is that you get + * more filters; The advantage of 32-bit filters is that you get + * finer control of the filtering. + * + * One filter is set up for each CAN. The filter resources are shared + * between the two CAN modules: CAN1 uses only filter 0 (but reserves + * 0 through CAN_NFILTERS/2-1); CAN2 uses only filter CAN_NFILTERS/2 + * (but reserves CAN_NFILTERS/2 through CAN_NFILTERS-1). + * + * 32-bit IdMask mode is configured. However, both the ID and the MASK + * are set to zero thus suppressing all filtering because anything masked + * with zero matches zero. + * + * Input Parameters: + * priv - reference to the private CAN driver state structure + * + * Returned Value: + * Zero on success; a negated errno value on failure. + * + ****************************************************************************/ + +static int stm32can_filterinit(FAR struct stm32_can_s *priv) +{ + uint32_t regval; + uint32_t bitmask; + + ninfo("CAN%" PRIu8 " filter: %" PRIu8 "\n", priv->port, priv->filter); + + /* Get the bitmask associated with the filter used by this CAN block */ + + bitmask = (uint32_t)1 << priv->filter; + + /* Enter filter initialization mode */ + + regval = stm32can_getfreg(priv, STM32_CAN_FMR_OFFSET); + regval |= CAN_FMR_FINIT; + stm32can_putfreg(priv, STM32_CAN_FMR_OFFSET, regval); + + /* Assign half the filters to CAN1, half to CAN2 */ + +#if defined(CONFIG_STM32_CONNECTIVITYLINE) || \ + defined(CONFIG_STM32_STM32F20XX) || \ + defined(CONFIG_STM32_STM32F4XXX) + regval = stm32can_getfreg(priv, STM32_CAN_FMR_OFFSET); + regval &= CAN_FMR_CAN2SB_MASK; + regval |= (CAN_NFILTERS / 2) << CAN_FMR_CAN2SB_SHIFT; + stm32can_putfreg(priv, STM32_CAN_FMR_OFFSET, regval); +#endif + + /* Disable the filter */ + + regval = stm32can_getfreg(priv, STM32_CAN_FA1R_OFFSET); + regval &= ~bitmask; + stm32can_putfreg(priv, STM32_CAN_FA1R_OFFSET, regval); + + /* Select the 32-bit scale for the filter */ + + regval = stm32can_getfreg(priv, STM32_CAN_FS1R_OFFSET); + regval |= bitmask; + stm32can_putfreg(priv, STM32_CAN_FS1R_OFFSET, regval); + + /* There are 14 or 28 filter banks (depending) on the device. + * Each filter bank is composed of two 32-bit registers, CAN_FiR: + */ + + stm32can_putfreg(priv, STM32_CAN_FIR_OFFSET(priv->filter, 1), 0); + stm32can_putfreg(priv, STM32_CAN_FIR_OFFSET(priv->filter, 2), 0); + + /* Set Id/Mask mode for the filter */ + + regval = stm32can_getfreg(priv, STM32_CAN_FM1R_OFFSET); + regval &= ~bitmask; + stm32can_putfreg(priv, STM32_CAN_FM1R_OFFSET, regval); + + /* Assign FIFO 0 for the filter */ + + regval = stm32can_getfreg(priv, STM32_CAN_FFA1R_OFFSET); + regval &= ~bitmask; + stm32can_putfreg(priv, STM32_CAN_FFA1R_OFFSET, regval); + + /* Enable the filter */ + + regval = stm32can_getfreg(priv, STM32_CAN_FA1R_OFFSET); + regval |= bitmask; + stm32can_putfreg(priv, STM32_CAN_FA1R_OFFSET, regval); + + /* Exit filter initialization mode */ + + regval = stm32can_getfreg(priv, STM32_CAN_FMR_OFFSET); + regval &= ~CAN_FMR_FINIT; + stm32can_putfreg(priv, STM32_CAN_FMR_OFFSET, regval); + return OK; +} + +/**************************************************************************** + * Name: stm32can_txmb0empty + * + * Input Parameters: + * tsr_regval - value of CAN transmit status register + * + * Returned Value: + * Returns true if mailbox 0 is empty and can be used for sending. + * + ****************************************************************************/ + +static bool stm32can_txmb0empty(uint32_t tsr_regval) +{ + return (tsr_regval & CAN_TSR_TME0) != 0 && + (tsr_regval & CAN_TSR_RQCP0) == 0; +} + +/**************************************************************************** + * Name: stm32can_txmb1empty + * + * Input Parameters: + * tsr_regval - value of CAN transmit status register + * + * Returned Value: + * Returns true if mailbox 1 is empty and can be used for sending. + * + ****************************************************************************/ + +static bool stm32can_txmb1empty(uint32_t tsr_regval) +{ + return (tsr_regval & CAN_TSR_TME1) != 0 && + (tsr_regval & CAN_TSR_RQCP1) == 0; +} + +/**************************************************************************** + * Name: stm32can_txmb2empty + * + * Input Parameters: + * tsr_regval - value of CAN transmit status register + * + * Returned Value: + * Returns true if mailbox 2 is empty and can be used for sending. + * + ****************************************************************************/ + +static bool stm32can_txmb2empty(uint32_t tsr_regval) +{ + return (tsr_regval & CAN_TSR_TME2) != 0 && + (tsr_regval & CAN_TSR_RQCP2) == 0; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: stm32_cansockinitialize + * + * Description: + * Initialize the selected CAN port as CAN socket interface + * + * Input Parameters: + * Port number (for hardware that has multiple CAN interfaces) + * + * Returned Value: + * OK on success; Negated errno on failure. + * + ****************************************************************************/ + +int stm32_cansockinitialize(int port) +{ + struct stm32_can_s *priv = NULL; + int ret = OK; + + ninfo("CAN%" PRIu8 "\n", port); + + /* NOTE: Peripherical clocking for CAN1 and/or CAN2 was already provided + * by stm32_clockconfig() early in the reset sequence. + */ + +#ifdef CONFIG_STM32_CAN1 + if (port == 1) + { + /* Select the CAN1 device structure */ + + priv = &g_can1priv; + + /* Configure CAN1 pins. The ambiguous settings in the stm32*_pinmap.h + * file must have been disambiguated in the board.h file. + */ + + stm32_configgpio(GPIO_CAN1_RX); + stm32_configgpio(GPIO_CAN1_TX); + } + else +#endif +#ifdef CONFIG_STM32_CAN2 + if (port == 2) + { + /* Select the CAN2 device structure */ + + priv = &g_can2priv; + + /* Configure CAN2 pins. The ambiguous settings in the stm32*_pinmap.h + * file must have been disambiguated in the board.h file. + */ + + stm32_configgpio(GPIO_CAN2_RX); + stm32_configgpio(GPIO_CAN2_TX); + } + else +#endif + { + nerr("ERROR: Unsupported port %d\n", port); + ret = -EINVAL; + goto errout; + } + + /* Initialize the driver structure */ + + priv->dev.d_ifup = stm32can_ifup; + priv->dev.d_ifdown = stm32can_ifdown; + priv->dev.d_txavail = stm32can_txavail; +#ifdef CONFIG_NETDEV_IOCTL + priv->dev.d_ioctl = stm32can_netdev_ioctl; +#endif + priv->dev.d_private = priv; + + /* Put the interface in the down state. This usually amounts to resetting + * the device and/or calling stm32can_ifdown(). + */ + + ninfo("callbacks done\n"); + + stm32can_ifdown(&priv->dev); + + /* Register the device with the OS so that socket IOCTLs can be performed */ + + ret = netdev_register(&priv->dev, NET_LL_CAN); + +errout: + return ret; +} From 5950e6335f78fcdc5277a6634303c2ff7f02e484 Mon Sep 17 00:00:00 2001 From: raiden00pl Date: Wed, 5 Jan 2022 10:47:05 +0100 Subject: [PATCH 20/43] [BACKPORT] boards/stm32: register CAN character device if configured --- boards/arm/stm32/clicker2-stm32/src/Make.defs | 2 +- boards/arm/stm32/clicker2-stm32/src/clicker2-stm32.h | 2 +- boards/arm/stm32/clicker2-stm32/src/stm32_bringup.c | 2 +- boards/arm/stm32/nucleo-f303re/src/Make.defs | 2 +- boards/arm/stm32/nucleo-f303re/src/nucleo-f303re.h | 2 +- boards/arm/stm32/nucleo-f303re/src/stm32_appinitialize.c | 2 +- boards/arm/stm32/nucleo-f334r8/src/nucleo-f334r8.h | 2 +- boards/arm/stm32/nucleo-f446re/src/Make.defs | 2 +- boards/arm/stm32/nucleo-f446re/src/nucleo-f446re.h | 2 +- boards/arm/stm32/nucleo-f446re/src/stm32_bringup.c | 2 +- boards/arm/stm32/olimex-stm32-h405/src/Make.defs | 2 +- boards/arm/stm32/olimex-stm32-h405/src/olimex-stm32-h405.h | 2 +- boards/arm/stm32/olimex-stm32-h405/src/stm32_appinit.c | 2 +- boards/arm/stm32/olimex-stm32-h407/src/Make.defs | 2 +- boards/arm/stm32/olimex-stm32-h407/src/olimex-stm32-h407.h | 2 +- boards/arm/stm32/olimex-stm32-h407/src/stm32_bringup.c | 2 +- boards/arm/stm32/olimex-stm32-p107/src/Make.defs | 2 +- boards/arm/stm32/olimex-stm32-p107/src/olimex-stm32-p107.h | 2 +- boards/arm/stm32/olimex-stm32-p107/src/stm32_appinit.c | 2 +- boards/arm/stm32/olimex-stm32-p207/src/Make.defs | 2 +- boards/arm/stm32/olimex-stm32-p207/src/olimex-stm32-p207.h | 2 +- boards/arm/stm32/olimex-stm32-p207/src/stm32_appinit.c | 2 +- boards/arm/stm32/olimex-stm32-p407/src/Make.defs | 2 +- boards/arm/stm32/olimex-stm32-p407/src/olimex-stm32-p407.h | 2 +- boards/arm/stm32/olimex-stm32-p407/src/stm32_bringup.c | 2 +- boards/arm/stm32/olimexino-stm32/src/Make.defs | 2 +- boards/arm/stm32/olimexino-stm32/src/olimexino-stm32.h | 2 +- boards/arm/stm32/olimexino-stm32/src/stm32_appinit.c | 2 +- boards/arm/stm32/omnibusf4/src/omnibusf4.h | 2 +- boards/arm/stm32/omnibusf4/src/stm32_bringup.c | 2 +- boards/arm/stm32/shenzhou/src/Make.defs | 2 +- boards/arm/stm32/shenzhou/src/shenzhou.h | 2 +- boards/arm/stm32/shenzhou/src/stm32_appinit.c | 2 +- boards/arm/stm32/stm3210e-eval/src/Make.defs | 2 +- boards/arm/stm32/stm3210e-eval/src/stm3210e-eval.h | 2 +- boards/arm/stm32/stm3210e-eval/src/stm32_bringup.c | 2 +- boards/arm/stm32/stm3220g-eval/src/Make.defs | 2 +- boards/arm/stm32/stm3220g-eval/src/stm3220g-eval.h | 2 +- boards/arm/stm32/stm3220g-eval/src/stm32_appinit.c | 2 +- boards/arm/stm32/stm3240g-eval/src/Make.defs | 2 +- boards/arm/stm32/stm3240g-eval/src/stm3240g-eval.h | 2 +- boards/arm/stm32/stm3240g-eval/src/stm32_bringup.c | 2 +- boards/arm/stm32/stm32f334-disco/src/Make.defs | 2 +- boards/arm/stm32/stm32f334-disco/src/stm32f334-disco.h | 2 +- boards/arm/stm32/stm32f4discovery/src/Make.defs | 2 +- boards/arm/stm32/stm32f4discovery/src/stm32_bringup.c | 2 +- boards/arm/stm32/stm32f4discovery/src/stm32f4discovery.h | 2 +- boards/arm/stm32/viewtool-stm32f107/src/Make.defs | 2 +- boards/arm/stm32/viewtool-stm32f107/src/stm32_bringup.c | 2 +- boards/arm/stm32/viewtool-stm32f107/src/viewtool_stm32f107.h | 2 +- 50 files changed, 50 insertions(+), 50 deletions(-) diff --git a/boards/arm/stm32/clicker2-stm32/src/Make.defs b/boards/arm/stm32/clicker2-stm32/src/Make.defs index 7f442d7a363..0026ce09772 100644 --- a/boards/arm/stm32/clicker2-stm32/src/Make.defs +++ b/boards/arm/stm32/clicker2-stm32/src/Make.defs @@ -60,7 +60,7 @@ ifeq ($(CONFIG_ADC),y) CSRCS += stm32_adc.c endif -ifeq ($(CONFIG_CAN),y) +ifeq ($(CONFIG_STM32_CAN_CHARDRIVER),y) CSRCS += stm32_can.c endif diff --git a/boards/arm/stm32/clicker2-stm32/src/clicker2-stm32.h b/boards/arm/stm32/clicker2-stm32/src/clicker2-stm32.h index 605e305227b..b076d6330ef 100644 --- a/boards/arm/stm32/clicker2-stm32/src/clicker2-stm32.h +++ b/boards/arm/stm32/clicker2-stm32/src/clicker2-stm32.h @@ -312,7 +312,7 @@ int stm32_adc_setup(void); * ****************************************************************************/ -#ifdef CONFIG_CAN +#ifdef CONFIG_STM32_CAN_CHARDRIVER int stm32_can_setup(void); #endif diff --git a/boards/arm/stm32/clicker2-stm32/src/stm32_bringup.c b/boards/arm/stm32/clicker2-stm32/src/stm32_bringup.c index 499161f9d13..9b79c93f865 100644 --- a/boards/arm/stm32/clicker2-stm32/src/stm32_bringup.c +++ b/boards/arm/stm32/clicker2-stm32/src/stm32_bringup.c @@ -87,7 +87,7 @@ int stm32_bringup(void) } #endif -#ifdef CONFIG_CAN +#ifdef CONFIG_STM32_CAN_CHARDRIVER /* Initialize CAN and register the CAN driver. */ ret = stm32_can_setup(); diff --git a/boards/arm/stm32/nucleo-f303re/src/Make.defs b/boards/arm/stm32/nucleo-f303re/src/Make.defs index 83d48b50077..c0f841b07ef 100644 --- a/boards/arm/stm32/nucleo-f303re/src/Make.defs +++ b/boards/arm/stm32/nucleo-f303re/src/Make.defs @@ -57,7 +57,7 @@ ifeq ($(CONFIG_ADC),y) CSRCS += stm32_adc.c endif -ifeq ($(CONFIG_CAN),y) +ifeq ($(CONFIG_STM32_CAN_CHARDRIVER),y) CSRCS += stm32_can.c endif diff --git a/boards/arm/stm32/nucleo-f303re/src/nucleo-f303re.h b/boards/arm/stm32/nucleo-f303re/src/nucleo-f303re.h index b16c814c12c..02d01a65da0 100644 --- a/boards/arm/stm32/nucleo-f303re/src/nucleo-f303re.h +++ b/boards/arm/stm32/nucleo-f303re/src/nucleo-f303re.h @@ -203,7 +203,7 @@ int stm32_adc_setup(void); * ****************************************************************************/ -#ifdef CONFIG_CAN +#ifdef CONFIG_STM32_CAN_CHARDRIVER int stm32_can_setup(void); #endif diff --git a/boards/arm/stm32/nucleo-f303re/src/stm32_appinitialize.c b/boards/arm/stm32/nucleo-f303re/src/stm32_appinitialize.c index f0a9405404c..848512e7a90 100644 --- a/boards/arm/stm32/nucleo-f303re/src/stm32_appinitialize.c +++ b/boards/arm/stm32/nucleo-f303re/src/stm32_appinitialize.c @@ -141,7 +141,7 @@ int board_app_initialize(uintptr_t arg) } #endif -#ifdef CONFIG_CAN +#ifdef CONFIG_STM32_CAN_CHARDRIVER /* Initialize CAN and register the CAN driver. */ ret = stm32_can_setup(); diff --git a/boards/arm/stm32/nucleo-f334r8/src/nucleo-f334r8.h b/boards/arm/stm32/nucleo-f334r8/src/nucleo-f334r8.h index 9abb52d8466..024b529e6f8 100644 --- a/boards/arm/stm32/nucleo-f334r8/src/nucleo-f334r8.h +++ b/boards/arm/stm32/nucleo-f334r8/src/nucleo-f334r8.h @@ -175,7 +175,7 @@ int stm32_adc_setup(void); * ****************************************************************************/ -#ifdef CONFIG_CAN +#ifdef CONFIG_STM32_CAN_CHARDRIVER int stm32_can_setup(void); #endif diff --git a/boards/arm/stm32/nucleo-f446re/src/Make.defs b/boards/arm/stm32/nucleo-f446re/src/Make.defs index 7e8267c02bd..7d73467a9f4 100644 --- a/boards/arm/stm32/nucleo-f446re/src/Make.defs +++ b/boards/arm/stm32/nucleo-f446re/src/Make.defs @@ -45,7 +45,7 @@ endif endif endif -ifeq ($(CONFIG_CAN),y) +ifeq ($(CONFIG_STM32_CAN_CHARDRIVER),y) CSRCS += stm32_can.c endif diff --git a/boards/arm/stm32/nucleo-f446re/src/nucleo-f446re.h b/boards/arm/stm32/nucleo-f446re/src/nucleo-f446re.h index f503727d02f..bb946a6388e 100644 --- a/boards/arm/stm32/nucleo-f446re/src/nucleo-f446re.h +++ b/boards/arm/stm32/nucleo-f446re/src/nucleo-f446re.h @@ -315,7 +315,7 @@ int stm32_adc_setup(void); * ****************************************************************************/ -#ifdef CONFIG_CAN +#ifdef CONFIG_STM32_CAN_CHARDRIVER int stm32_can_setup(void); #endif diff --git a/boards/arm/stm32/nucleo-f446re/src/stm32_bringup.c b/boards/arm/stm32/nucleo-f446re/src/stm32_bringup.c index 118429ee1ed..8a9a5febd2f 100644 --- a/boards/arm/stm32/nucleo-f446re/src/stm32_bringup.c +++ b/boards/arm/stm32/nucleo-f446re/src/stm32_bringup.c @@ -136,7 +136,7 @@ int stm32_bringup(void) } #endif -#ifdef CONFIG_CAN +#ifdef CONFIG_STM32_CAN_CHARDRIVER /* Initialize CAN and register the CAN driver. */ ret = stm32_can_setup(); diff --git a/boards/arm/stm32/olimex-stm32-h405/src/Make.defs b/boards/arm/stm32/olimex-stm32-h405/src/Make.defs index ad17b5d1e3e..5743e8f0eef 100644 --- a/boards/arm/stm32/olimex-stm32-h405/src/Make.defs +++ b/boards/arm/stm32/olimex-stm32-h405/src/Make.defs @@ -44,7 +44,7 @@ ifeq ($(CONFIG_ADC),y) CSRCS += stm32_adc.c endif -ifeq ($(CONFIG_CAN),y) +ifeq ($(CONFIG_STM32_CAN_CHARDRIVER),y) CSRCS += stm32_can.c endif diff --git a/boards/arm/stm32/olimex-stm32-h405/src/olimex-stm32-h405.h b/boards/arm/stm32/olimex-stm32-h405/src/olimex-stm32-h405.h index 68fd5e1b403..5de70f2672a 100644 --- a/boards/arm/stm32/olimex-stm32-h405/src/olimex-stm32-h405.h +++ b/boards/arm/stm32/olimex-stm32-h405/src/olimex-stm32-h405.h @@ -94,7 +94,7 @@ int stm32_adc_setup(void); * ****************************************************************************/ -#ifdef CONFIG_CAN +#ifdef CONFIG_STM32_CAN_CHARDRIVER int stm32_can_setup(void); #endif diff --git a/boards/arm/stm32/olimex-stm32-h405/src/stm32_appinit.c b/boards/arm/stm32/olimex-stm32-h405/src/stm32_appinit.c index 3f1010588a6..224b5757c4f 100644 --- a/boards/arm/stm32/olimex-stm32-h405/src/stm32_appinit.c +++ b/boards/arm/stm32/olimex-stm32-h405/src/stm32_appinit.c @@ -100,7 +100,7 @@ int board_app_initialize(uintptr_t arg) } #endif -#ifdef CONFIG_CAN +#ifdef CONFIG_STM32_CAN_CHARDRIVER /* Initialize CAN and register the CAN driver. */ ret = stm32_can_setup(); diff --git a/boards/arm/stm32/olimex-stm32-h407/src/Make.defs b/boards/arm/stm32/olimex-stm32-h407/src/Make.defs index ddcf2b5adfa..7995107628f 100644 --- a/boards/arm/stm32/olimex-stm32-h407/src/Make.defs +++ b/boards/arm/stm32/olimex-stm32-h407/src/Make.defs @@ -56,7 +56,7 @@ ifeq ($(CONFIG_ADC),y) CSRCS += stm32_adc.c endif -ifeq ($(CONFIG_CAN),y) +ifeq ($(CONFIG_STM32_CAN_CHARDRIVER),y) CSRCS += stm32_can.c endif diff --git a/boards/arm/stm32/olimex-stm32-h407/src/olimex-stm32-h407.h b/boards/arm/stm32/olimex-stm32-h407/src/olimex-stm32-h407.h index 05ff939b2ba..fa7ee3230a9 100644 --- a/boards/arm/stm32/olimex-stm32-h407/src/olimex-stm32-h407.h +++ b/boards/arm/stm32/olimex-stm32-h407/src/olimex-stm32-h407.h @@ -254,7 +254,7 @@ int stm32_adc_setup(void); * ****************************************************************************/ -#ifdef CONFIG_CAN +#ifdef CONFIG_STM32_CAN_CHARDRIVER int stm32_can_setup(void); #endif diff --git a/boards/arm/stm32/olimex-stm32-h407/src/stm32_bringup.c b/boards/arm/stm32/olimex-stm32-h407/src/stm32_bringup.c index 7cc5dc6455c..71e3dc1485f 100644 --- a/boards/arm/stm32/olimex-stm32-h407/src/stm32_bringup.c +++ b/boards/arm/stm32/olimex-stm32-h407/src/stm32_bringup.c @@ -82,7 +82,7 @@ int stm32_bringup(void) #endif int ret; -#ifdef CONFIG_CAN +#ifdef CONFIG_STM32_CAN_CHARDRIVER /* Initialize CAN and register the CAN driver. */ ret = stm32_can_setup(); diff --git a/boards/arm/stm32/olimex-stm32-p107/src/Make.defs b/boards/arm/stm32/olimex-stm32-p107/src/Make.defs index 5d568a0493b..2751ff5b5f9 100644 --- a/boards/arm/stm32/olimex-stm32-p107/src/Make.defs +++ b/boards/arm/stm32/olimex-stm32-p107/src/Make.defs @@ -26,7 +26,7 @@ ifeq ($(CONFIG_LIB_BOARDCTL),y) CSRCS += stm32_appinit.c endif -ifeq ($(CONFIG_CAN),y) +ifeq ($(CONFIG_STM32_CAN_CHARDRIVER),y) CSRCS += stm32_can.c endif diff --git a/boards/arm/stm32/olimex-stm32-p107/src/olimex-stm32-p107.h b/boards/arm/stm32/olimex-stm32-p107/src/olimex-stm32-p107.h index d6a83502206..91dae798d3a 100644 --- a/boards/arm/stm32/olimex-stm32-p107/src/olimex-stm32-p107.h +++ b/boards/arm/stm32/olimex-stm32-p107/src/olimex-stm32-p107.h @@ -77,7 +77,7 @@ void weak_function stm32_spidev_initialize(void); * ****************************************************************************/ -#ifdef CONFIG_CAN +#ifdef CONFIG_STM32_CAN_CHARDRIVER int stm32_can_setup(void); #endif diff --git a/boards/arm/stm32/olimex-stm32-p107/src/stm32_appinit.c b/boards/arm/stm32/olimex-stm32-p107/src/stm32_appinit.c index 2310731dfad..98628a0a9c4 100644 --- a/boards/arm/stm32/olimex-stm32-p107/src/stm32_appinit.c +++ b/boards/arm/stm32/olimex-stm32-p107/src/stm32_appinit.c @@ -73,7 +73,7 @@ int board_app_initialize(uintptr_t arg) { int ret; -#ifdef CONFIG_CAN +#ifdef CONFIG_STM32_CAN_CHARDRIVER /* Initialize CAN and register the CAN driver. */ ret = stm32_can_setup(); diff --git a/boards/arm/stm32/olimex-stm32-p207/src/Make.defs b/boards/arm/stm32/olimex-stm32-p207/src/Make.defs index f39b6aa0c1a..9db929b9053 100644 --- a/boards/arm/stm32/olimex-stm32-p207/src/Make.defs +++ b/boards/arm/stm32/olimex-stm32-p207/src/Make.defs @@ -44,7 +44,7 @@ ifeq ($(CONFIG_ADC),y) CSRCS += stm32_adc.c endif -ifeq ($(CONFIG_CAN),y) +ifeq ($(CONFIG_STM32_CAN_CHARDRIVER),y) CSRCS += stm32_can.c endif diff --git a/boards/arm/stm32/olimex-stm32-p207/src/olimex-stm32-p207.h b/boards/arm/stm32/olimex-stm32-p207/src/olimex-stm32-p207.h index 605a69f723c..c18c868502f 100644 --- a/boards/arm/stm32/olimex-stm32-p207/src/olimex-stm32-p207.h +++ b/boards/arm/stm32/olimex-stm32-p207/src/olimex-stm32-p207.h @@ -131,7 +131,7 @@ int stm32_adc_setup(void); * ****************************************************************************/ -#ifdef CONFIG_CAN +#ifdef CONFIG_STM32_CAN_CHARDRIVER int stm32_can_setup(void); #endif diff --git a/boards/arm/stm32/olimex-stm32-p207/src/stm32_appinit.c b/boards/arm/stm32/olimex-stm32-p207/src/stm32_appinit.c index 081a9e9716f..33f247e1cf1 100644 --- a/boards/arm/stm32/olimex-stm32-p207/src/stm32_appinit.c +++ b/boards/arm/stm32/olimex-stm32-p207/src/stm32_appinit.c @@ -130,7 +130,7 @@ int board_app_initialize(uintptr_t arg) { int ret; -#ifdef CONFIG_CAN +#ifdef CONFIG_STM32_CAN_CHARDRIVER /* Initialize CAN and register the CAN driver. */ ret = stm32_can_setup(); diff --git a/boards/arm/stm32/olimex-stm32-p407/src/Make.defs b/boards/arm/stm32/olimex-stm32-p407/src/Make.defs index 48d23d1b491..321d212e692 100644 --- a/boards/arm/stm32/olimex-stm32-p407/src/Make.defs +++ b/boards/arm/stm32/olimex-stm32-p407/src/Make.defs @@ -48,7 +48,7 @@ ifeq ($(CONFIG_ADC),y) CSRCS += stm32_adc.c endif -ifeq ($(CONFIG_CAN),y) +ifeq ($(CONFIG_STM32_CAN_CHARDRIVER),y) CSRCS += stm32_can.c endif diff --git a/boards/arm/stm32/olimex-stm32-p407/src/olimex-stm32-p407.h b/boards/arm/stm32/olimex-stm32-p407/src/olimex-stm32-p407.h index 415b1b59509..ef066d58fa7 100644 --- a/boards/arm/stm32/olimex-stm32-p407/src/olimex-stm32-p407.h +++ b/boards/arm/stm32/olimex-stm32-p407/src/olimex-stm32-p407.h @@ -316,7 +316,7 @@ int stm32_adc_setup(void); * ****************************************************************************/ -#ifdef CONFIG_CAN +#ifdef CONFIG_STM32_CAN_CHARDRIVER int stm32_can_setup(void); #endif diff --git a/boards/arm/stm32/olimex-stm32-p407/src/stm32_bringup.c b/boards/arm/stm32/olimex-stm32-p407/src/stm32_bringup.c index e33963c2b42..0f7285ac431 100644 --- a/boards/arm/stm32/olimex-stm32-p407/src/stm32_bringup.c +++ b/boards/arm/stm32/olimex-stm32-p407/src/stm32_bringup.c @@ -137,7 +137,7 @@ int stm32_bringup(void) sdio_mediachange(sdio, true); #endif -#ifdef CONFIG_CAN +#ifdef CONFIG_STM32_CAN_CHARDRIVER /* Initialize CAN and register the CAN driver. */ ret = stm32_can_setup(); diff --git a/boards/arm/stm32/olimexino-stm32/src/Make.defs b/boards/arm/stm32/olimexino-stm32/src/Make.defs index 95cd24b0a45..06b9ac45531 100644 --- a/boards/arm/stm32/olimexino-stm32/src/Make.defs +++ b/boards/arm/stm32/olimexino-stm32/src/Make.defs @@ -22,7 +22,7 @@ include $(TOPDIR)/Make.defs CSRCS = stm32_boot.c stm32_spi.c stm32_leds.c -ifeq ($(CONFIG_CAN),y) +ifeq ($(CONFIG_STM32_CAN_CHARDRIVER),y) CSRCS += stm32_can.c endif diff --git a/boards/arm/stm32/olimexino-stm32/src/olimexino-stm32.h b/boards/arm/stm32/olimexino-stm32/src/olimexino-stm32.h index 30d4ebb3d03..de4ce6d20c8 100644 --- a/boards/arm/stm32/olimexino-stm32/src/olimexino-stm32.h +++ b/boards/arm/stm32/olimexino-stm32/src/olimexino-stm32.h @@ -224,7 +224,7 @@ int board_usbmsc_initialize(int port); * ****************************************************************************/ -#ifdef CONFIG_CAN +#ifdef CONFIG_STM32_CAN_CHARDRIVER int stm32_can_setup(void); #endif diff --git a/boards/arm/stm32/olimexino-stm32/src/stm32_appinit.c b/boards/arm/stm32/olimexino-stm32/src/stm32_appinit.c index 8dfa03ed9f9..9c34de3bb3e 100644 --- a/boards/arm/stm32/olimexino-stm32/src/stm32_appinit.c +++ b/boards/arm/stm32/olimexino-stm32/src/stm32_appinit.c @@ -87,7 +87,7 @@ int board_app_initialize(uintptr_t arg) ret = board_composite_initialize(0); #endif -#ifdef CONFIG_CAN +#ifdef CONFIG_STM32_CAN_CHARDRIVER /* Initialize CAN and register the CAN driver. */ ret = stm32_can_setup(); diff --git a/boards/arm/stm32/omnibusf4/src/omnibusf4.h b/boards/arm/stm32/omnibusf4/src/omnibusf4.h index 2f2045dbf16..8022c0f524f 100644 --- a/boards/arm/stm32/omnibusf4/src/omnibusf4.h +++ b/boards/arm/stm32/omnibusf4/src/omnibusf4.h @@ -185,7 +185,7 @@ int weak_function stm32_pwm_setup(void); * ****************************************************************************/ -#ifdef CONFIG_CAN +#ifdef CONFIG_STM32_CAN_CHARDRIVER int stm32_can_setup(void); #endif diff --git a/boards/arm/stm32/omnibusf4/src/stm32_bringup.c b/boards/arm/stm32/omnibusf4/src/stm32_bringup.c index 8f125e4cc07..7b073afc89c 100644 --- a/boards/arm/stm32/omnibusf4/src/stm32_bringup.c +++ b/boards/arm/stm32/omnibusf4/src/stm32_bringup.c @@ -204,7 +204,7 @@ int stm32_bringup(void) } #endif -#ifdef CONFIG_CAN +#ifdef CONFIG_STM32_CAN_CHARDRIVER /* Initialize CAN and register the CAN driver. */ ret = stm32_can_setup(); diff --git a/boards/arm/stm32/shenzhou/src/Make.defs b/boards/arm/stm32/shenzhou/src/Make.defs index bd27dafe09f..5c4b9c503d1 100644 --- a/boards/arm/stm32/shenzhou/src/Make.defs +++ b/boards/arm/stm32/shenzhou/src/Make.defs @@ -52,7 +52,7 @@ ifeq ($(CONFIG_USBMSC),y) CSRCS += stm32_usbmsc.c endif -ifeq ($(CONFIG_CAN),y) +ifeq ($(CONFIG_STM32_CAN_CHARDRIVER),y) CSRCS += stm32_can.c endif diff --git a/boards/arm/stm32/shenzhou/src/shenzhou.h b/boards/arm/stm32/shenzhou/src/shenzhou.h index ed23fc9d0ba..cc2593a3972 100644 --- a/boards/arm/stm32/shenzhou/src/shenzhou.h +++ b/boards/arm/stm32/shenzhou/src/shenzhou.h @@ -486,7 +486,7 @@ int stm32_adc_setup(void); * ****************************************************************************/ -#ifdef CONFIG_CAN +#ifdef CONFIG_STM32_CAN_CHARDRIVER int stm32_can_setup(void); #endif diff --git a/boards/arm/stm32/shenzhou/src/stm32_appinit.c b/boards/arm/stm32/shenzhou/src/stm32_appinit.c index 13d49d539e3..cb29d93ab4c 100644 --- a/boards/arm/stm32/shenzhou/src/stm32_appinit.c +++ b/boards/arm/stm32/shenzhou/src/stm32_appinit.c @@ -212,7 +212,7 @@ int board_app_initialize(uintptr_t arg) } #endif -#ifdef CONFIG_CAN +#ifdef CONFIG_STM32_CAN_CHARDRIVER /* Initialize CAN and register the CAN driver. */ ret = stm32_can_setup(); diff --git a/boards/arm/stm32/stm3210e-eval/src/Make.defs b/boards/arm/stm32/stm3210e-eval/src/Make.defs index 5412c598d7d..aa330f56992 100644 --- a/boards/arm/stm32/stm3210e-eval/src/Make.defs +++ b/boards/arm/stm32/stm3210e-eval/src/Make.defs @@ -44,7 +44,7 @@ ifeq ($(CONFIG_USBDEV_COMPOSITE),y) CSRCS += stm32_composite.c endif -ifeq ($(CONFIG_CAN),y) +ifeq ($(CONFIG_STM32_CAN_CHARDRIVER),y) CSRCS += stm32_can.c endif diff --git a/boards/arm/stm32/stm3210e-eval/src/stm3210e-eval.h b/boards/arm/stm32/stm3210e-eval/src/stm3210e-eval.h index 15f7fbe1264..5464cd3c7ab 100644 --- a/boards/arm/stm32/stm3210e-eval/src/stm3210e-eval.h +++ b/boards/arm/stm32/stm3210e-eval/src/stm3210e-eval.h @@ -221,7 +221,7 @@ int stm32_adc_setup(void); * ****************************************************************************/ -#ifdef CONFIG_CAN +#ifdef CONFIG_STM32_CAN_CHARDRIVER int stm32_can_setup(void); #endif diff --git a/boards/arm/stm32/stm3210e-eval/src/stm32_bringup.c b/boards/arm/stm32/stm3210e-eval/src/stm32_bringup.c index ac137847f55..bd5a64ae36c 100644 --- a/boards/arm/stm32/stm3210e-eval/src/stm32_bringup.c +++ b/boards/arm/stm32/stm3210e-eval/src/stm32_bringup.c @@ -279,7 +279,7 @@ int stm32_bringup(void) } #endif -#ifdef CONFIG_CAN +#ifdef CONFIG_STM32_CAN_CHARDRIVER /* Initialize CAN and register the CAN driver. */ ret = stm32_can_setup(); diff --git a/boards/arm/stm32/stm3220g-eval/src/Make.defs b/boards/arm/stm32/stm3220g-eval/src/Make.defs index 68c3f4cbd17..788ae75874f 100644 --- a/boards/arm/stm32/stm3220g-eval/src/Make.defs +++ b/boards/arm/stm32/stm3220g-eval/src/Make.defs @@ -48,7 +48,7 @@ ifeq ($(CONFIG_PWM),y) CSRCS += stm32_pwm.c endif -ifeq ($(CONFIG_CAN),y) +ifeq ($(CONFIG_STM32_CAN_CHARDRIVER),y) CSRCS += stm32_can.c endif diff --git a/boards/arm/stm32/stm3220g-eval/src/stm3220g-eval.h b/boards/arm/stm32/stm3220g-eval/src/stm3220g-eval.h index e90bdd0dfe6..774f950c5c1 100644 --- a/boards/arm/stm32/stm3220g-eval/src/stm3220g-eval.h +++ b/boards/arm/stm32/stm3220g-eval/src/stm3220g-eval.h @@ -305,7 +305,7 @@ int stm32_adc_setup(void); * ****************************************************************************/ -#ifdef CONFIG_CAN +#ifdef CONFIG_STM32_CAN_CHARDRIVER int stm32_can_setup(void); #endif diff --git a/boards/arm/stm32/stm3220g-eval/src/stm32_appinit.c b/boards/arm/stm32/stm3220g-eval/src/stm32_appinit.c index 77a27737b04..4de80deb863 100644 --- a/boards/arm/stm32/stm3220g-eval/src/stm32_appinit.c +++ b/boards/arm/stm32/stm3220g-eval/src/stm32_appinit.c @@ -309,7 +309,7 @@ int board_app_initialize(uintptr_t arg) } #endif -#ifdef CONFIG_CAN +#ifdef CONFIG_STM32_CAN_CHARDRIVER /* Initialize CAN and register the CAN driver. */ ret = stm32_can_setup(); diff --git a/boards/arm/stm32/stm3240g-eval/src/Make.defs b/boards/arm/stm32/stm3240g-eval/src/Make.defs index d752b848821..1e1b149489a 100644 --- a/boards/arm/stm32/stm3240g-eval/src/Make.defs +++ b/boards/arm/stm32/stm3240g-eval/src/Make.defs @@ -49,7 +49,7 @@ ifeq ($(CONFIG_PWM),y) CSRCS += stm32_pwm.c endif -ifeq ($(CONFIG_CAN),y) +ifeq ($(CONFIG_STM32_CAN_CHARDRIVER),y) CSRCS += stm32_can.c endif diff --git a/boards/arm/stm32/stm3240g-eval/src/stm3240g-eval.h b/boards/arm/stm32/stm3240g-eval/src/stm3240g-eval.h index d241100395f..b2f0e2b5fc6 100644 --- a/boards/arm/stm32/stm3240g-eval/src/stm3240g-eval.h +++ b/boards/arm/stm32/stm3240g-eval/src/stm3240g-eval.h @@ -333,7 +333,7 @@ int stm32_adc_setup(void); * ****************************************************************************/ -#ifdef CONFIG_CAN +#ifdef CONFIG_STM32_CAN_CHARDRIVER int stm32_can_setup(void); #endif diff --git a/boards/arm/stm32/stm3240g-eval/src/stm32_bringup.c b/boards/arm/stm32/stm3240g-eval/src/stm32_bringup.c index 68a5336027d..b0e048aba22 100644 --- a/boards/arm/stm32/stm3240g-eval/src/stm32_bringup.c +++ b/boards/arm/stm32/stm3240g-eval/src/stm32_bringup.c @@ -376,7 +376,7 @@ int stm32_bringup(void) } #endif -#ifdef CONFIG_CAN +#ifdef CONFIG_STM32_CAN_CHARDRIVER /* Initialize CAN and register the CAN driver. */ ret = stm32_can_setup(); diff --git a/boards/arm/stm32/stm32f334-disco/src/Make.defs b/boards/arm/stm32/stm32f334-disco/src/Make.defs index 7ae87bea9f5..32d2121f3a1 100644 --- a/boards/arm/stm32/stm32f334-disco/src/Make.defs +++ b/boards/arm/stm32/stm32f334-disco/src/Make.defs @@ -30,7 +30,7 @@ ifeq ($(CONFIG_LIB_BOARDCTL),y) CSRCS += stm32_appinit.c endif -ifeq ($(CONFIG_CAN),y) +ifeq ($(CONFIG_STM32_CAN_CHARDRIVER),y) CSRCS += stm32_can.c endif diff --git a/boards/arm/stm32/stm32f334-disco/src/stm32f334-disco.h b/boards/arm/stm32/stm32f334-disco/src/stm32f334-disco.h index d7ee6cb3f0d..62b05c710ab 100644 --- a/boards/arm/stm32/stm32f334-disco/src/stm32f334-disco.h +++ b/boards/arm/stm32/stm32f334-disco/src/stm32f334-disco.h @@ -154,7 +154,7 @@ int stm32_adc_setup(void); * ****************************************************************************/ -#ifdef CONFIG_CAN +#ifdef CONFIG_STM32_CAN_CHARDRIVER int stm32_can_setup(void); #endif diff --git a/boards/arm/stm32/stm32f4discovery/src/Make.defs b/boards/arm/stm32/stm32f4discovery/src/Make.defs index fae7279db13..e5b5accaafb 100644 --- a/boards/arm/stm32/stm32f4discovery/src/Make.defs +++ b/boards/arm/stm32/stm32f4discovery/src/Make.defs @@ -40,7 +40,7 @@ ifeq ($(CONFIG_ARCH_BUTTONS),y) CSRCS += stm32_buttons.c endif -ifeq ($(CONFIG_CAN),y) +ifeq ($(CONFIG_STM32_CAN_CHARDRIVER),y) CSRCS += stm32_can.c endif diff --git a/boards/arm/stm32/stm32f4discovery/src/stm32_bringup.c b/boards/arm/stm32/stm32f4discovery/src/stm32_bringup.c index cafe505c0cb..e39728ca363 100644 --- a/boards/arm/stm32/stm32f4discovery/src/stm32_bringup.c +++ b/boards/arm/stm32/stm32f4discovery/src/stm32_bringup.c @@ -332,7 +332,7 @@ int stm32_bringup(void) } #endif -#ifdef CONFIG_CAN +#ifdef CONFIG_STM32_CAN_CHARDRIVER /* Initialize CAN and register the CAN driver. */ ret = stm32_can_setup(); diff --git a/boards/arm/stm32/stm32f4discovery/src/stm32f4discovery.h b/boards/arm/stm32/stm32f4discovery/src/stm32f4discovery.h index 417fd02167e..f0b6fc45839 100644 --- a/boards/arm/stm32/stm32f4discovery/src/stm32f4discovery.h +++ b/boards/arm/stm32/stm32f4discovery/src/stm32f4discovery.h @@ -563,7 +563,7 @@ int stm32_pwm_setup(void); * ****************************************************************************/ -#ifdef CONFIG_CAN +#ifdef CONFIG_STM32_CAN_CHARDRIVER int stm32_can_setup(void); #endif diff --git a/boards/arm/stm32/viewtool-stm32f107/src/Make.defs b/boards/arm/stm32/viewtool-stm32f107/src/Make.defs index 4dff107f84c..92805675f65 100644 --- a/boards/arm/stm32/viewtool-stm32f107/src/Make.defs +++ b/boards/arm/stm32/viewtool-stm32f107/src/Make.defs @@ -22,7 +22,7 @@ include $(TOPDIR)/Make.defs CSRCS = stm32_boot.c stm32_bringup.c stm32_leds.c stm32_spi.c -ifeq ($(CONFIG_CAN),y) +ifeq ($(CONFIG_STM32_CAN_CHARDRIVER),y) CSRCS += stm32_can.c endif diff --git a/boards/arm/stm32/viewtool-stm32f107/src/stm32_bringup.c b/boards/arm/stm32/viewtool-stm32f107/src/stm32_bringup.c index f76db4d2431..f71b9df7036 100644 --- a/boards/arm/stm32/viewtool-stm32f107/src/stm32_bringup.c +++ b/boards/arm/stm32/viewtool-stm32f107/src/stm32_bringup.c @@ -164,7 +164,7 @@ int stm32_bringup(void) } #endif -#ifdef CONFIG_CAN +#ifdef CONFIG_STM32_CAN_CHARDRIVER /* Initialize CAN and register the CAN driver. */ ret = stm32_can_setup(); diff --git a/boards/arm/stm32/viewtool-stm32f107/src/viewtool_stm32f107.h b/boards/arm/stm32/viewtool-stm32f107/src/viewtool_stm32f107.h index c03579e0c17..9f4a0ca3c7d 100644 --- a/boards/arm/stm32/viewtool-stm32f107/src/viewtool_stm32f107.h +++ b/boards/arm/stm32/viewtool-stm32f107/src/viewtool_stm32f107.h @@ -442,7 +442,7 @@ int stm32_sdinitialize(int minor); * ****************************************************************************/ -#ifdef CONFIG_CAN +#ifdef CONFIG_STM32_CAN_CHARDRIVER int stm32_can_setup(void); #endif From 5e41affb13c7170fc8eceed4b79e96cfea9db437 Mon Sep 17 00:00:00 2001 From: raiden00pl Date: Sat, 15 Jan 2022 14:34:44 +0100 Subject: [PATCH 21/43] [BACKPORT] boards/nucleo-f302r8: add CAN and SocketCAN examples --- .../stm32/nucleo-f302r8/configs/can/defconfig | 63 ++++++++++++++++ .../nucleo-f302r8/configs/cansock/defconfig | 62 ++++++++++++++++ .../arm/stm32/nucleo-f302r8/include/board.h | 5 ++ boards/arm/stm32/nucleo-f302r8/src/Make.defs | 9 +++ .../stm32/nucleo-f302r8/src/nucleo-f302r8.h | 24 +++++++ .../stm32/nucleo-f302r8/src/stm32_bringup.c | 20 ++++++ .../arm/stm32/nucleo-f302r8/src/stm32_can.c | 71 +++++++++++++++++++ .../stm32/nucleo-f302r8/src/stm32_cansock.c | 57 +++++++++++++++ 8 files changed, 311 insertions(+) create mode 100644 boards/arm/stm32/nucleo-f302r8/configs/can/defconfig create mode 100644 boards/arm/stm32/nucleo-f302r8/configs/cansock/defconfig create mode 100644 boards/arm/stm32/nucleo-f302r8/src/stm32_can.c create mode 100644 boards/arm/stm32/nucleo-f302r8/src/stm32_cansock.c diff --git a/boards/arm/stm32/nucleo-f302r8/configs/can/defconfig b/boards/arm/stm32/nucleo-f302r8/configs/can/defconfig new file mode 100644 index 00000000000..c195c9827d1 --- /dev/null +++ b/boards/arm/stm32/nucleo-f302r8/configs/can/defconfig @@ -0,0 +1,63 @@ +# +# 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="arm" +CONFIG_ARCH_BOARD="nucleo-f302r8" +CONFIG_ARCH_BOARD_NUCLEO_F302R8=y +CONFIG_ARCH_BUTTONS=y +CONFIG_ARCH_CHIP="stm32" +CONFIG_ARCH_CHIP_STM32=y +CONFIG_ARCH_CHIP_STM32F302R8=y +CONFIG_ARCH_STACKDUMP=y +CONFIG_BOARD_LOOPSPERMSEC=16717 +CONFIG_BUILTIN=y +CONFIG_CAN_ERRORS=y +CONFIG_CAN_EXTID=y +CONFIG_DEBUG_FULLOPT=y +CONFIG_DEBUG_SYMBOLS=y +CONFIG_DEFAULT_SMALL=y +CONFIG_EXAMPLES_CAN=y +CONFIG_EXAMPLES_CAN_WRITE=y +CONFIG_FDCLONE_STDIO=y +CONFIG_FS_LARGEFILE=y +CONFIG_INIT_ENTRYPOINT="nsh_main" +CONFIG_INIT_STACKSIZE=1024 +CONFIG_INTELHEX_BINARY=y +CONFIG_NAME_MAX=16 +CONFIG_NSH_ARCHINIT=y +CONFIG_NSH_ARGCAT=y +CONFIG_NSH_BUILTIN_APPS=y +CONFIG_NSH_CMDPARMS=y +CONFIG_NSH_FILEIOSIZE=256 +CONFIG_NSH_QUOTE=y +CONFIG_POSIX_SPAWN_PROXY_STACKSIZE=512 +CONFIG_PREALLOC_TIMERS=2 +CONFIG_PTHREAD_MUTEX_ROBUST=y +CONFIG_PTHREAD_STACK_DEFAULT=1024 +CONFIG_PTHREAD_STACK_MIN=1024 +CONFIG_RAM_SIZE=16386 +CONFIG_RAM_START=0x20000000 +CONFIG_RAW_BINARY=y +CONFIG_RR_INTERVAL=200 +CONFIG_SCHED_WAITPID=y +CONFIG_SDCLONE_DISABLE=y +CONFIG_SIG_PREALLOC_IRQ_ACTIONS=8 +CONFIG_START_DAY=6 +CONFIG_START_MONTH=12 +CONFIG_START_YEAR=2011 +CONFIG_STDIO_BUFFER_SIZE=255 +CONFIG_STM32_CAN1=y +CONFIG_STM32_CAN_TSEG1=15 +CONFIG_STM32_CAN_TSEG2=2 +CONFIG_STM32_JTAG_SW_ENABLE=y +CONFIG_STM32_PWR=y +CONFIG_STM32_USART2=y +CONFIG_SYSTEM_NSH=y +CONFIG_SYSTEM_TIME64=y +CONFIG_TASK_NAME_SIZE=0 +CONFIG_TASK_SPAWN_DEFAULT_STACKSIZE=512 +CONFIG_USART2_SERIAL_CONSOLE=y diff --git a/boards/arm/stm32/nucleo-f302r8/configs/cansock/defconfig b/boards/arm/stm32/nucleo-f302r8/configs/cansock/defconfig new file mode 100644 index 00000000000..d4a132386d5 --- /dev/null +++ b/boards/arm/stm32/nucleo-f302r8/configs/cansock/defconfig @@ -0,0 +1,62 @@ +# +# 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_NET_ETHERNET is not set +# CONFIG_NET_IPv4 is not set +CONFIG_ARCH="arm" +CONFIG_ARCH_BOARD="nucleo-f302r8" +CONFIG_ARCH_BOARD_NUCLEO_F302R8=y +CONFIG_ARCH_BUTTONS=y +CONFIG_ARCH_CHIP="stm32" +CONFIG_ARCH_CHIP_STM32=y +CONFIG_ARCH_CHIP_STM32F302R8=y +CONFIG_ARCH_INTERRUPTSTACK=1024 +CONFIG_ARCH_STACKDUMP=y +CONFIG_BOARD_LATE_INITIALIZE=y +CONFIG_BOARD_LOOPSPERMSEC=8499 +CONFIG_BUILTIN=y +CONFIG_DEBUG_FULLOPT=y +CONFIG_DEBUG_SYMBOLS=y +CONFIG_DEFAULT_SMALL=y +CONFIG_DEFAULT_TASK_STACKSIZE=1024 +CONFIG_FS_LARGEFILE=y +CONFIG_INIT_ENTRYPOINT="nsh_main" +CONFIG_INIT_STACKSIZE=2048 +CONFIG_INTELHEX_BINARY=y +CONFIG_IOB_BUFSIZE=128 +CONFIG_IOB_NBUFFERS=10 +CONFIG_LIBC_LONG_LONG=y +CONFIG_NET=y +CONFIG_NETDEVICES=y +CONFIG_NETDEV_IFINDEX=y +CONFIG_NETDEV_LATEINIT=y +CONFIG_NET_CAN=y +CONFIG_NET_CAN_ERRORS=y +CONFIG_NET_NACTIVESOCKETS=16 +CONFIG_NET_SOCKOPTS=y +CONFIG_NET_STATISTICS=y +CONFIG_NSH_BUILTIN_APPS=y +CONFIG_PTHREAD_MUTEX_ROBUST=y +CONFIG_RAM_SIZE=16386 +CONFIG_RAM_START=0x20000000 +CONFIG_RAW_BINARY=y +CONFIG_RR_INTERVAL=200 +CONFIG_SCHED_LPWORK=y +CONFIG_SCHED_WAITPID=y +CONFIG_SDCLONE_DISABLE=y +CONFIG_SIG_PREALLOC_IRQ_ACTIONS=8 +CONFIG_START_DAY=14 +CONFIG_START_MONTH=10 +CONFIG_START_YEAR=2014 +CONFIG_STM32_CAN1=y +CONFIG_STM32_CAN_SOCKET=y +CONFIG_STM32_JTAG_SW_ENABLE=y +CONFIG_STM32_PWR=y +CONFIG_STM32_USART2=y +CONFIG_SYSTEM_NSH=y +CONFIG_TASK_NAME_SIZE=0 +CONFIG_USART2_SERIAL_CONSOLE=y diff --git a/boards/arm/stm32/nucleo-f302r8/include/board.h b/boards/arm/stm32/nucleo-f302r8/include/board.h index bb9f5594e52..7738d753f9b 100644 --- a/boards/arm/stm32/nucleo-f302r8/include/board.h +++ b/boards/arm/stm32/nucleo-f302r8/include/board.h @@ -208,6 +208,11 @@ #define GPIO_USART1_RX GPIO_USART1_RX_2 /* PB7 */ #define GPIO_USART1_TX GPIO_USART1_TX_2 /* PB6 */ +/* CAN */ + +#define GPIO_CAN1_RX GPIO_CAN_RX_3 /* PB8 */ +#define GPIO_CAN1_TX GPIO_CAN_TX_3 /* PB9 */ + /* PWM configuration ********************************************************/ /* TIM1 PWM */ diff --git a/boards/arm/stm32/nucleo-f302r8/src/Make.defs b/boards/arm/stm32/nucleo-f302r8/src/Make.defs index aee173753bb..135dcf0b14e 100644 --- a/boards/arm/stm32/nucleo-f302r8/src/Make.defs +++ b/boards/arm/stm32/nucleo-f302r8/src/Make.defs @@ -48,6 +48,15 @@ ifeq ($(CONFIG_BOARD_STM32_IHM07M1),y) CSRCS += stm32_foc_ihm07m1.c endif +ifeq ($(CONFIG_STM32_CAN),y) +ifeq ($(CONFIG_STM32_CAN_CHARDRIVER),y) +CSRCS += stm32_can.c +endif +ifeq ($(CONFIG_STM32_CAN_SOCKET),y) +CSRCS += stm32_cansock.c +endif +endif + DEPPATH += --dep-path board VPATH += :board CFLAGS += $(shell $(INCDIR) "$(CC)" $(TOPDIR)$(DELIM)arch$(DELIM)$(CONFIG_ARCH)$(DELIM)src$(DELIM)board$(DELIM)board) diff --git a/boards/arm/stm32/nucleo-f302r8/src/nucleo-f302r8.h b/boards/arm/stm32/nucleo-f302r8/src/nucleo-f302r8.h index 224be0a894f..f3c9a4ae17a 100644 --- a/boards/arm/stm32/nucleo-f302r8/src/nucleo-f302r8.h +++ b/boards/arm/stm32/nucleo-f302r8/src/nucleo-f302r8.h @@ -158,4 +158,28 @@ int stm32_foc_setup(void); int stm32_adc_setup(void); #endif +/**************************************************************************** + * Name: stm32_can_setup + * + * Description: + * Initialize CAN and register the CAN device + * + ****************************************************************************/ + +#ifdef CONFIG_STM32_CAN_CHARDRIVER +int stm32_can_setup(void); +#endif + +/**************************************************************************** + * Name: stm32_cansock_setup + * + * Description: + * Initialize CAN socket interface + * + ****************************************************************************/ + +#ifdef CONFIG_STM32_CAN_SOCKET +int stm32_cansock_setup(void); +#endif + #endif /* __BOARDS_ARM_STM32_NUCLEO_F302R8_SRC_NUCLEO_F302R8_H */ diff --git a/boards/arm/stm32/nucleo-f302r8/src/stm32_bringup.c b/boards/arm/stm32/nucleo-f302r8/src/stm32_bringup.c index 1a3285eb0c0..56d7276c6cc 100644 --- a/boards/arm/stm32/nucleo-f302r8/src/stm32_bringup.c +++ b/boards/arm/stm32/nucleo-f302r8/src/stm32_bringup.c @@ -127,6 +127,26 @@ int stm32_bringup(void) } #endif +#ifdef CONFIG_STM32_CAN_CHARDRIVER + /* Initialize CAN and register the CAN driver. */ + + ret = stm32_can_setup(); + if (ret < 0) + { + syslog(LOG_ERR, "ERROR: stm32_can_setup failed: %d\n", ret); + } +#endif + +#ifdef CONFIG_STM32_CAN_SOCKET + /* Initialize CAN socket interface */ + + ret = stm32_cansock_setup(); + if (ret < 0) + { + syslog(LOG_ERR, "ERROR: stm32_cansock_setup failed: %d\n", ret); + } +#endif + UNUSED(ret); return OK; } diff --git a/boards/arm/stm32/nucleo-f302r8/src/stm32_can.c b/boards/arm/stm32/nucleo-f302r8/src/stm32_can.c new file mode 100644 index 00000000000..95932a71f3b --- /dev/null +++ b/boards/arm/stm32/nucleo-f302r8/src/stm32_can.c @@ -0,0 +1,71 @@ +/**************************************************************************** + * boards/arm/stm32/nucleo-f302r8/src/stm32_can.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 "stm32.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: stm32_can_setup + * + * Description: + * Initialize CAN and register the CAN device + * + ****************************************************************************/ + +int stm32_can_setup(void) +{ + struct can_dev_s *can; + int ret; + + /* Call stm32_caninitialize() to get an instance of the CAN interface */ + + can = stm32_caninitialize(1); + if (can == NULL) + { + canerr("ERROR: Failed to get CAN interface\n"); + return -ENODEV; + } + + /* Register the CAN driver at "/dev/can0" */ + + ret = can_register("/dev/can0", can); + if (ret < 0) + { + canerr("ERROR: can_register failed: %d\n", ret); + return ret; + } + + return OK; +} diff --git a/boards/arm/stm32/nucleo-f302r8/src/stm32_cansock.c b/boards/arm/stm32/nucleo-f302r8/src/stm32_cansock.c new file mode 100644 index 00000000000..8290936d843 --- /dev/null +++ b/boards/arm/stm32/nucleo-f302r8/src/stm32_cansock.c @@ -0,0 +1,57 @@ +/**************************************************************************** + * boards/arm/stm32/nucleo-f302r8/src/stm32_cansock.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 "stm32_can.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: stm32_cansock_setup + * + * Description: + * Initialize CAN socket interface + * + ****************************************************************************/ + +int stm32_cansock_setup(void) +{ + int ret; + + /* Call stm32_caninitialize() to get an instance of the CAN interface */ + + ret = stm32_cansockinitialize(1); + if (ret < 0) + { + canerr("ERROR: Failed to get CAN interface %d\n", ret); + return ret; + } + + return OK; +} From 3086179cfd0ac3ea780649f160ea7ca9bc9bb0bd Mon Sep 17 00:00:00 2001 From: raiden00pl Date: Sat, 15 Jan 2022 14:38:06 +0100 Subject: [PATCH 22/43] [BACKPORT] boards/nucleo-f446re: add SocketCAN example --- .../nucleo-f446re/configs/cansock/defconfig | 71 ++++++++++++++++ boards/arm/stm32/nucleo-f446re/src/Make.defs | 5 ++ .../stm32/nucleo-f446re/src/nucleo-f446re.h | 12 +++ .../stm32/nucleo-f446re/src/stm32_bringup.c | 10 +++ .../stm32/nucleo-f446re/src/stm32_cansock.c | 83 +++++++++++++++++++ 5 files changed, 181 insertions(+) create mode 100644 boards/arm/stm32/nucleo-f446re/configs/cansock/defconfig create mode 100644 boards/arm/stm32/nucleo-f446re/src/stm32_cansock.c diff --git a/boards/arm/stm32/nucleo-f446re/configs/cansock/defconfig b/boards/arm/stm32/nucleo-f446re/configs/cansock/defconfig new file mode 100644 index 00000000000..c5b7bf0b28d --- /dev/null +++ b/boards/arm/stm32/nucleo-f446re/configs/cansock/defconfig @@ -0,0 +1,71 @@ +# +# 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_FPU is not set +# CONFIG_NET_ETHERNET is not set +# CONFIG_NET_IPv4 is not set +# CONFIG_NSH_ARGCAT is not set +# CONFIG_NSH_CMDOPT_HEXDUMP is not set +# CONFIG_NSH_CMDPARMS is not set +# CONFIG_STM32_FLASH_PREFETCH is not set +CONFIG_ARCH="arm" +CONFIG_ARCH_BOARD="nucleo-f446re" +CONFIG_ARCH_BOARD_NUCLEO_F446RE=y +CONFIG_ARCH_BUTTONS=y +CONFIG_ARCH_CHIP="stm32" +CONFIG_ARCH_CHIP_STM32=y +CONFIG_ARCH_CHIP_STM32F446R=y +CONFIG_ARCH_INTERRUPTSTACK=2048 +CONFIG_ARCH_STACKDUMP=y +CONFIG_BOARD_LATE_INITIALIZE=y +CONFIG_BOARD_LOOPSPERMSEC=8499 +CONFIG_BUILTIN=y +CONFIG_CAN_EXTID=y +CONFIG_DEBUG_FULLOPT=y +CONFIG_DEBUG_SYMBOLS=y +CONFIG_FS_PROCFS=y +CONFIG_INIT_ENTRYPOINT="nsh_main" +CONFIG_INTELHEX_BINARY=y +CONFIG_IOB_BUFSIZE=16 +CONFIG_IOB_NBUFFERS=1024 +CONFIG_NET=y +CONFIG_NETDEVICES=y +CONFIG_NETDEV_IFINDEX=y +CONFIG_NETDEV_LATEINIT=y +CONFIG_NET_CAN=y +CONFIG_NET_SOCKOPTS=y +CONFIG_NET_STATISTICS=y +CONFIG_NSH_BUILTIN_APPS=y +CONFIG_NSH_DISABLE_IFUPDOWN=y +CONFIG_NSH_FILEIOSIZE=512 +CONFIG_NSH_LINELEN=64 +CONFIG_NSH_READLINE=y +CONFIG_PREALLOC_TIMERS=4 +CONFIG_RAM_SIZE=131072 +CONFIG_RAM_START=0x20000000 +CONFIG_RAW_BINARY=y +CONFIG_RR_INTERVAL=200 +CONFIG_SCHED_LPWORK=y +CONFIG_SCHED_LPWORKPRIORITY=176 +CONFIG_SCHED_WAITPID=y +CONFIG_SDCLONE_DISABLE=y +CONFIG_SPI=y +CONFIG_START_DAY=14 +CONFIG_START_MONTH=10 +CONFIG_START_YEAR=2014 +CONFIG_STM32_CAN1=y +CONFIG_STM32_CAN_SOCKET=y +CONFIG_STM32_CAN_TSEG1=13 +CONFIG_STM32_CAN_TSEG2=2 +CONFIG_STM32_CRC=y +CONFIG_STM32_JTAG_SW_ENABLE=y +CONFIG_STM32_OTGFS=y +CONFIG_STM32_PWR=y +CONFIG_STM32_USART2=y +CONFIG_SYSTEM_NSH=y +CONFIG_TASK_NAME_SIZE=0 +CONFIG_USART2_SERIAL_CONSOLE=y diff --git a/boards/arm/stm32/nucleo-f446re/src/Make.defs b/boards/arm/stm32/nucleo-f446re/src/Make.defs index 7d73467a9f4..cfbe1f7e12f 100644 --- a/boards/arm/stm32/nucleo-f446re/src/Make.defs +++ b/boards/arm/stm32/nucleo-f446re/src/Make.defs @@ -45,9 +45,14 @@ endif endif endif +ifeq ($(CONFIG_STM32_CAN),y) ifeq ($(CONFIG_STM32_CAN_CHARDRIVER),y) CSRCS += stm32_can.c endif +ifeq ($(CONFIG_STM32_CAN_SOCKET),y) +CSRCS += stm32_cansock.c +endif +endif ifeq ($(CONFIG_STM32_PWM),y) CSRCS += stm32_pwm.c diff --git a/boards/arm/stm32/nucleo-f446re/src/nucleo-f446re.h b/boards/arm/stm32/nucleo-f446re/src/nucleo-f446re.h index bb946a6388e..ddcfbdb15c4 100644 --- a/boards/arm/stm32/nucleo-f446re/src/nucleo-f446re.h +++ b/boards/arm/stm32/nucleo-f446re/src/nucleo-f446re.h @@ -319,6 +319,18 @@ int stm32_adc_setup(void); int stm32_can_setup(void); #endif +/**************************************************************************** + * Name: stm32_cansock_setup + * + * Description: + * Initialize CAN socket interface + * + ****************************************************************************/ + +#ifdef CONFIG_STM32_CAN_SOCKET +int stm32_cansock_setup(void); +#endif + /**************************************************************************** * Name: board_ajoy_initialize * diff --git a/boards/arm/stm32/nucleo-f446re/src/stm32_bringup.c b/boards/arm/stm32/nucleo-f446re/src/stm32_bringup.c index 8a9a5febd2f..e49c2e4caad 100644 --- a/boards/arm/stm32/nucleo-f446re/src/stm32_bringup.c +++ b/boards/arm/stm32/nucleo-f446re/src/stm32_bringup.c @@ -146,6 +146,16 @@ int stm32_bringup(void) } #endif +#ifdef CONFIG_STM32_CAN_SOCKET + /* Initialize CAN socket interface */ + + ret = stm32_cansock_setup(); + if (ret < 0) + { + syslog(LOG_ERR, "ERROR: stm32_cansock_setup failed: %d\n", ret); + } +#endif + #ifdef CONFIG_VIDEO_FB /* Initialize and register the framebuffer driver */ diff --git a/boards/arm/stm32/nucleo-f446re/src/stm32_cansock.c b/boards/arm/stm32/nucleo-f446re/src/stm32_cansock.c new file mode 100644 index 00000000000..b05ca76d215 --- /dev/null +++ b/boards/arm/stm32/nucleo-f446re/src/stm32_cansock.c @@ -0,0 +1,83 @@ +/**************************************************************************** + * boards/arm/stm32/nucleo-f446re/src/stm32_cansock.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 "stm32_can.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Configuration ************************************************************/ + +#if !defined(CONFIG_STM32_CAN1) && !defined(CONFIG_STM32_CAN2) +# error "No CAN is enable. Please eneable at least one CAN device" +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: stm32_cansock_setup + * + * Description: + * Initialize CAN socket interface + * + ****************************************************************************/ + +int stm32_cansock_setup(void) +{ + int ret = OK; + + UNUSED(ret); + +#ifdef CONFIG_STM32_CAN1 + /* Call stm32_caninitialize() to get an instance of the CAN interface */ + + ret = stm32_cansockinitialize(1); + if (ret < 0) + { + canerr("ERROR: Failed to get CAN interface %d\n", ret); + goto errout; + } +#endif + +#ifdef CONFIG_STM32_CAN2 + /* Call stm32_caninitialize() to get an instance of the CAN interface */ + + ret = stm32_cansockinitialize(2); + if (ret < 0) + { + canerr("ERROR: Failed to get CAN interface %d\n", ret); + goto errout; + } +#endif + +errout: + return ret; +} From 3a8a220aae5d54f077fd821cc3c372ebdad9d8e2 Mon Sep 17 00:00:00 2001 From: raiden00pl Date: Tue, 11 Jan 2022 17:59:10 +0100 Subject: [PATCH 23/43] [BACKPORT] stm32: add FDCAN support based on PR #2987 --- arch/arm/src/stm32/Kconfig | 382 +- arch/arm/src/stm32/Make.defs | 6 + arch/arm/src/stm32/hardware/stm32_fdcan.h | 586 +++ .../stm32/hardware/stm32g4xxxx_memorymap.h | 2 +- arch/arm/src/stm32/stm32_fdcan.c | 3453 +++++++++++++++++ arch/arm/src/stm32/stm32_fdcan.h | 90 + arch/arm/src/stm32/stm32g4xxxx_rcc.c | 9 + 7 files changed, 4526 insertions(+), 2 deletions(-) create mode 100644 arch/arm/src/stm32/hardware/stm32_fdcan.h create mode 100644 arch/arm/src/stm32/stm32_fdcan.c create mode 100644 arch/arm/src/stm32/stm32_fdcan.h diff --git a/arch/arm/src/stm32/Kconfig b/arch/arm/src/stm32/Kconfig index 1857035c31e..694c0c51ede 100644 --- a/arch/arm/src/stm32/Kconfig +++ b/arch/arm/src/stm32/Kconfig @@ -2887,16 +2887,19 @@ config STM32_FDCAN1 bool "FDCAN1" default n depends on STM32_HAVE_FDCAN1 + select STM32_FDCAN config STM32_FDCAN2 bool "FDCAN2" default n depends on STM32_HAVE_FDCAN2 + select STM32_FDCAN config STM32_FDCAN3 bool "FDCAN3" default n depends on STM32_HAVE_FDCAN3 + select STM32_FDCAN config STM32_FSMC bool "FSMC" @@ -3363,6 +3366,10 @@ config STM32_CAN bool select ARCH_HAVE_CAN_ERRORS +config STM32_FDCAN + bool + select ARCH_HAVE_CAN_ERRORS + config STM32_TIM bool default n @@ -10703,7 +10710,380 @@ config STM32_CAN_REGDEBUG Output detailed register-level CAN device debug information. Requires also CONFIG_DEBUG_CAN_INFO. -endmenu +endmenu # "CAN driver configuration" + +menu "FDCAN driver configuration" + depends on STM32_FDCAN + +choice + prompt "FDCAN character driver or SocketCAN support" + default STM32_FDCAN_CHARDRIVER + +config STM32_FDCAN_CHARDRIVER + bool "STM32 FDCAN character driver support" + select ARCH_HAVE_FDCAN_ERRORS + +config STM32_FDCAN_SOCKET + bool "STM32 FDCAN SocketCAN support (not supported yet)" + select NET_FDCAN_HAVE_ERRORS + +endchoice # FDCAN character driver or SocketCAN support + +config STM32_FDCAN_REGDEBUG + bool "CAN Register level debug" + depends on DEBUG_CAN_INFO + default n + ---help--- + Output detailed register-level CAN device debug information. + Requires also CONFIG_DEBUG_CAN_INFO. + +config STM32_FDCAN_QUEUE_MODE + bool "FDCAN QUEUE mode (vs FIFO mode)" + default n + +menu "FDCAN1 device driver options" + depends on STM32_FDCAN1 + +choice + prompt "FDCAN1 frame format" + default STM32_FDCAN1_ISO11898_1 + +config STM32_FDCAN1_ISO11898_1 + bool "ISO11898-1" + ---help--- + Enable ISO11898-1 frame format + +config STM32_FDCAN1_NONISO_FORMAT + bool "Non ISO" + ---help--- + Enable Non ISO, Bosch CAN FD Specification V1.0 + +endchoice # FDCAN1 frame format + +choice + prompt "FDCAN1 mode" + default STM32_FDCAN1_CLASSIC + +config STM32_FDCAN1_CLASSIC + bool "Classic CAN" + ---help--- + Enable Clasic CAN mode + +config STM32_FDCAN1_FD + bool "CAN FD" + depends on CAN_FD || NET_CAN_CANFD + ---help--- + Enable CAN FD mode + +config STM32_FDCAN1_FD_BRS + bool "CAN FD with fast bit rate switching" + depends on CAN_FD || NET_CAN_CANFD + ---help--- + Enable CAN FD mode with fast bit rate switching mode. + +endchoice # FDCAN1 mode + +config STM32_FDCAN1_LOOPBACK + bool "Enable FDCAN1 loopback mode" + default n + ---help--- + Enable the FDCAN1 local loopback mode for testing purposes. + +comment "Nominal Bit Timing" + +config STM32_FDCAN1_BITRATE + int "FDCAN bitrate" + default 500000 + range 0 1000000 + ---help--- + FDCAN1 bitrate in bits per second. Required if STM32_FDCAN1 is defined. + +config STM32_FDCAN1_NTSEG1 + int "FDCAN1 NTSEG1 (PropSeg + PhaseSeg1)" + default 6 + range 1 256 if STM32_STM32G4XXX + ---help--- + The length of the bit time is Tquanta * (SyncSeg + PropSeg + PhaseSeg1 + PhaseSeg2). + +config STM32_FDCAN1_NTSEG2 + int "FDCAN1 NTSEG2 (PhaseSeg2)" + default 7 + range 1 128 if STM32_STM32G4XXX + ---help--- + The length of the bit time is Tquanta * (SyncSeg + PropSeg + PhaseSeg1 + PhaseSeg2). + +config STM32_FDCAN1_NSJW + int "FDCAN1 synchronization jump width" + default 1 + range 1 128 if STM32_STM32G4XXX + ---help--- + The length of the bit time is Tquanta * (SyncSeg + PropSeg + PhaseSeg1 + PhaseSeg2). + +comment "Data Bit Timing" + depends on CAN_FD && STM32_FDCAN1_FD_BRS + +config STM32_FDCAN1_DBITRATE + int "FDCAN1 data bitrate" + default 2000000 + depends on CAN_FD && STM32_FDCAN1_FD_BRS + ---help--- + FDCAN1 bitrate in bits per second. Required if operating in FD mode with bit rate switching (BRS). + +config STM32_FDCAN1_DTSEG1 + int "FDCAN1 DTSEG1 (PropSeg + PhaseSeg1 of data phase)" + default 4 + range 1 31 if STM32_STM32G4XXX + depends on CAN_FD && STM32_FDCAN1_FD_BRS + ---help--- + The length of the bit time is Tquanta * (SyncSeg + PropSeg + PhaseSeg1 + PhaseSeg2). + +config STM32_FDCAN1_DTSEG2 + int "FDCAN1 DTSEG2 (PhaseSeg2 of data phase)" + default 4 + range 1 15 if STM32_STM32G4XXX + depends on CAN_FD && STM32_FDCAN1_FD_BRS + ---help--- + The length of the bit time is Tquanta * (SyncSeg + PropSeg + PhaseSeg1 + PhaseSeg2). + +config STM32_FDCAN1_DSJW + int "FDCAN1 fast synchronization jump width" + default 2 + range 1 15 if STM32_STM32G4XXX + depends on CAN_FD && STM32_FDCAN1_FD_BRS + ---help--- + The duration of a synchronization jump is Tcan_clk x DSJW. + +endmenu # FDCAN1 device driver options + +menu "FDCAN2 device driver options" + depends on STM32_FDCAN2 + +choice + prompt "FDCAN2 frame format" + default STM32_FDCAN2_ISO11898_1 + +config STM32_FDCAN2_ISO11898_1 + bool "ISO11898-1" + ---help--- + Enable ISO11898-1 frame format + +config STM32_FDCAN2_NONISO_FORMAT + bool "Non ISO" + ---help--- + Enable Non ISO, Bosch CAN FD Specification V1.0 + +endchoice # FDCAN2 frame format + +choice + prompt "FDCAN2 mode" + default STM32_FDCAN2_CLASSIC + +config STM32_FDCAN2_CLASSIC + bool "Classic CAN" + ---help--- + Enable Clasic CAN mode + +config STM32_FDCAN2_FD + bool "CAN FD" + depends on CAN_FD || NET_CAN_CANFD + ---help--- + Enable CAN FD mode + +config STM32_FDCAN2_FD_BRS + bool "CAN FD with fast bit rate switching" + depends on CAN_FD || NET_CAN_CANFD + ---help--- + Enable CAN FD mode with fast bit rate switching mode. + +endchoice # FDCAN2 mode + +config STM32_FDCAN2_LOOPBACK + bool "Enable FDCAN2 loopback mode" + default n + ---help--- + Enable the FDCAN2 local loopback mode for testing purposes. + +comment "Nominal Bit Timing" + +config STM32_FDCAN2_BITRATE + int "FDCAN bitrate" + default 500000 + range 0 1000000 + ---help--- + FDCAN2 bitrate in bits per second. Required if STM32_FDCAN2 is defined. + +config STM32_FDCAN2_NTSEG1 + int "FDCAN2 NTSEG1 (PropSeg + PhaseSeg1)" + default 6 + range 1 256 if STM32_STM32G4XXX + ---help--- + The length of the bit time is Tquanta * (SyncSeg + PropSeg + PhaseSeg1 + PhaseSeg2). + +config STM32_FDCAN2_NTSEG2 + int "FDCAN2 NTSEG2 (PhaseSeg2)" + default 7 + range 1 128 if STM32_STM32G4XXX + ---help--- + The length of the bit time is Tquanta * (SyncSeg + PropSeg + PhaseSeg1 + PhaseSeg2). + +config STM32_FDCAN2_NSJW + int "FDCAN2 synchronization jump width" + default 1 + range 1 128 if STM32_STM32G4XXX + ---help--- + The length of the bit time is Tquanta * (SyncSeg + PropSeg + PhaseSeg1 + PhaseSeg2). + +comment "Data Bit Timing" + depends on CAN_FD && STM32_FDCAN2_FD_BRS + +config STM32_FDCAN2_DBITRATE + int "FDCAN2 data bitrate" + default 2000000 + depends on CAN_FD && STM32_FDCAN2_FD_BRS + ---help--- + FDCAN2 bitrate in bits per second. Required if operating in FD mode with bit rate switching (BRS). + +config STM32_FDCAN2_DTSEG1 + int "FDCAN2 DTSEG1 (PropSeg + PhaseSeg1 of data phase)" + default 4 + range 1 31 if STM32_STM32G4XXX + depends on CAN_FD && STM32_FDCAN2_FD_BRS + ---help--- + The length of the bit time is Tquanta * (SyncSeg + PropSeg + PhaseSeg1 + PhaseSeg2). + +config STM32_FDCAN2_DTSEG2 + int "FDCAN2 DTSEG2 (PhaseSeg2 of data phase)" + default 4 + range 1 15 if STM32_STM32G4XXX + depends on CAN_FD && STM32_FDCAN2_FD_BRS + ---help--- + The length of the bit time is Tquanta * (SyncSeg + PropSeg + PhaseSeg1 + PhaseSeg2). + +config STM32_FDCAN2_DSJW + int "FDCAN2 fast synchronization jump width" + default 2 + range 1 15 if STM32_STM32G4XXX + depends on CAN_FD && STM32_FDCAN2_FD_BRS + ---help--- + The duration of a synchronization jump is Tcan_clk x DSJW. + +endmenu # FDCAN2 device driver options + +menu "FDCAN3 device driver options" + depends on STM32_FDCAN3 + +choice + prompt "FDCAN3 frame format" + default STM32_FDCAN3_ISO11898_1 + +config STM32_FDCAN3_ISO11898_1 + bool "ISO11898-1" + ---help--- + Enable ISO11898-1 frame format + +config STM32_FDCAN3_NONISO_FORMAT + bool "Non ISO" + ---help--- + Enable Non ISO, Bosch CAN FD Specification V1.0 + +endchoice # FDCAN3 frame format + +choice + prompt "FDCAN3 mode" + default STM32_FDCAN3_CLASSIC + +config STM32_FDCAN3_CLASSIC + bool "Classic CAN" + ---help--- + Enable Clasic CAN mode + +config STM32_FDCAN3_FD + bool "CAN FD" + depends on CAN_FD || NET_CAN_CANFD + ---help--- + Enable CAN FD mode + +config STM32_FDCAN3_FD_BRS + bool "CAN FD with fast bit rate switching" + depends on CAN_FD || NET_CAN_CANFD + ---help--- + Enable CAN FD mode with fast bit rate switching mode. + +endchoice # FDCAN3 mode + +config STM32_FDCAN3_LOOPBACK + bool "Enable FDCAN3 loopback mode" + default n + ---help--- + Enable the FDCAN3 local loopback mode for testing purposes. + +comment "Nominal Bit Timing" + +config STM32_FDCAN3_BITRATE + int "FDCAN bitrate" + default 500000 + range 0 1000000 + ---help--- + FDCAN3 bitrate in bits per second. Required if STM32_FDCAN3 is defined. + +config STM32_FDCAN3_NTSEG1 + int "FDCAN3 NTSEG1 (PropSeg + PhaseSeg1)" + default 6 + range 1 256 if STM32_STM32G4XXX + ---help--- + The length of the bit time is Tquanta * (SyncSeg + PropSeg + PhaseSeg1 + PhaseSeg2). + +config STM32_FDCAN3_NTSEG2 + int "FDCAN3 NTSEG2 (PhaseSeg2)" + default 7 + range 1 128 if STM32_STM32G4XXX + ---help--- + The length of the bit time is Tquanta * (SyncSeg + PropSeg + PhaseSeg1 + PhaseSeg2). + +config STM32_FDCAN3_NSJW + int "FDCAN3 synchronization jump width" + default 1 + range 1 128 if STM32_STM32G4XXX + ---help--- + The length of the bit time is Tquanta * (SyncSeg + PropSeg + PhaseSeg1 + PhaseSeg2). + +comment "Data Bit Timing" + depends on CAN_FD && STM32_FDCAN3_FD_BRS + +config STM32_FDCAN3_DBITRATE + int "FDCAN3 data bitrate" + default 2000000 + depends on CAN_FD && STM32_FDCAN3_FD_BRS + ---help--- + FDCAN3 bitrate in bits per second. Required if operating in FD mode with bit rate switching (BRS). + +config STM32_FDCAN3_DTSEG1 + int "FDCAN3 DTSEG1 (PropSeg + PhaseSeg1 of data phase)" + default 4 + range 1 31 if STM32_STM32G4XXX + depends on CAN_FD && STM32_FDCAN3_FD_BRS + ---help--- + The length of the bit time is Tquanta * (SyncSeg + PropSeg + PhaseSeg1 + PhaseSeg2). + +config STM32_FDCAN3_DTSEG2 + int "FDCAN3 DTSEG2 (PhaseSeg2 of data phase)" + default 4 + range 1 15 if STM32_STM32G4XXX + depends on CAN_FD && STM32_FDCAN3_FD_BRS + ---help--- + The length of the bit time is Tquanta * (SyncSeg + PropSeg + PhaseSeg1 + PhaseSeg2). + +config STM32_FDCAN3_DSJW + int "FDCAN3 fast synchronization jump width" + default 2 + range 1 15 if STM32_STM32G4XXX + depends on CAN_FD && STM32_FDCAN3_FD_BRS + ---help--- + The duration of a synchronization jump is Tcan_clk x DSJW. + +endmenu # FDCAN3 device driver options + +endmenu # "FDCAN driver configuration" if STM32_LTDC diff --git a/arch/arm/src/stm32/Make.defs b/arch/arm/src/stm32/Make.defs index 60e753632de..72364491451 100644 --- a/arch/arm/src/stm32/Make.defs +++ b/arch/arm/src/stm32/Make.defs @@ -241,6 +241,12 @@ CHIP_CSRCS += stm32_can_sock.c endif endif +ifeq ($(CONFIG_STM32_FDCAN),y) +ifeq ($(CONFIG_STM32_FDCAN_CHARDRIVER),y) +CHIP_CSRCS += stm32_fdcan.c +endif +endif + ifeq ($(CONFIG_STM32_IWDG),y) CHIP_CSRCS += stm32_iwdg.c endif diff --git a/arch/arm/src/stm32/hardware/stm32_fdcan.h b/arch/arm/src/stm32/hardware/stm32_fdcan.h new file mode 100644 index 00000000000..d135ab3137e --- /dev/null +++ b/arch/arm/src/stm32/hardware/stm32_fdcan.h @@ -0,0 +1,586 @@ +/**************************************************************************** + * arch/arm/src/stm32/hardware/stm32_fdcan.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_ARM_SRC_STM32_HARDWARE_STM32_FDCAN_H +#define __ARCH_ARM_SRC_STM32_HARDWARE_STM32_FDCAN_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include "chip.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Only for STM32G4 */ + +#ifndef CONFIG_STM32_STM32G4XXX +# error STM32 FDCAN was tested only for STM32G4 +#endif + +/* Register Offsets *********************************************************/ + +#define STM32_FDCAN_CREL_OFFSET 0x0000 /* FDCAN core release register */ +#define STM32_FDCAN_ENDN_OFFSET 0x0004 /* FDCAN endian register */ + /* 0x0008 Reserved */ +#define STM32_FDCAN_DBTP_OFFSET 0x000c /* FDCAN data bit timing and prescaler register */ +#define STM32_FDCAN_TEST_OFFSET 0x0010 /* FDCAN test register */ +#define STM32_FDCAN_RWD_OFFSET 0x0014 /* FDCAN RAM watchdog register */ +#define STM32_FDCAN_CCCR_OFFSET 0x0018 /* FDCAN CC control register */ +#define STM32_FDCAN_NBTP_OFFSET 0x001c /* FDCAN nominal bit timing and prescaler register */ +#define STM32_FDCAN_TSCC_OFFSET 0x0020 /* FDCAN timestamp counter configuration register */ +#define STM32_FDCAN_TSCV_OFFSET 0x0024 /* FDCAN timestamp counter value register */ +#define STM32_FDCAN_TOCC_OFFSET 0x0028 /* FDCAN timeout counter configuration register */ +#define STM32_FDCAN_TOCV_OFFSET 0x002c /* FDCAN timeout counter value register */ + /* 0x0030 to 0x003c Reserved */ +#define STM32_FDCAN_ECR_OFFSET 0x0040 /* FDCAN error counter register */ +#define STM32_FDCAN_PSR_OFFSET 0x0044 /* FDCAN protocol status register */ +#define STM32_FDCAN_TDCR_OFFSET 0x0048 /* FDCAN transmitter delay compensation register */ + /* 0x004c Reserved */ +#define STM32_FDCAN_IR_OFFSET 0x0050 /* FDCAN interrupt register */ +#define STM32_FDCAN_IE_OFFSET 0x0054 /* FDCAN interrupt enable register */ +#define STM32_FDCAN_ILS_OFFSET 0x0058 /* FDCAN interrupt line select register */ +#define STM32_FDCAN_ILE_OFFSET 0x005c /* FDCAN interrupt line enable register */ + /* 0x0060 to 0x007c Reserved */ +#define STM32_FDCAN_RXGFC_OFFSET 0x0080 /* FDCAN global filter configuration register */ +#define STM32_FDCAN_XIDAM_OFFSET 0x0084 /* FDCAN extended ID and mask register */ +#define STM32_FDCAN_HPMS_OFFSET 0x0088 /* FDCAN high-priority message status register */ +#define STM32_FDCAN_RXFS_OFFSET(f) (0x0090 + ((f) << 3) +#define STM32_FDCAN_RXFA_OFFSET(f) (0x0094 + ((f) << 3) +#define STM32_FDCAN_RXF0S_OFFSET 0x0090 /* FDCAN Rx FIFO 0 status register */ +#define STM32_FDCAN_RXF0A_OFFSET 0x0094 /* CAN Rx FIFO 0 acknowledge register */ +#define STM32_FDCAN_RXF1S_OFFSET 0x0098 /* FDCAN Rx FIFO 1 status register */ +#define STM32_FDCAN_RXF1A_OFFSET 0x009c /* FDCAN Rx FIFO 1 acknowledge register */ + /* 0x00a0 to 0x00bc Reserved */ +#define STM32_FDCAN_TXBC_OFFSET 0x00c0 /* FDCAN Tx buffer configuration register */ +#define STM32_FDCAN_TXFQS_OFFSET 0x00c4 /* FDCAN Tx FIFO/queue status register */ +#define STM32_FDCAN_TXBRP_OFFSET 0x00c8 /* FDCAN Tx buffer request pending register */ +#define STM32_FDCAN_TXBAR_OFFSET 0x00cc /* FDCAN Tx buffer add request register */ +#define STM32_FDCAN_TXBCR_OFFSET 0x00d0 /* FDCAN Tx buffer cancellation request register */ +#define STM32_FDCAN_TXBTO_OFFSET 0x00d4 /* FDCAN Tx buffer transmission occurred register */ +#define STM32_FDCAN_TXBCNF_OFFSET 0x00d8 /* FDCAN Tx buffer cancellation finished register */ +#define STM32_FDCAN_TXBTIE_OFFSET 0x00dc /* FDCAN Tx buffer transmission interrupt enable register */ +#define STM32_FDCAN_TXBCIE_OFFSET 0x00e0 /* FDCAN Tx buffer cancellation finished interrupt enable register */ +#define STM32_FDCAN_TXEFS_OFFSET 0x00e4 /* FDCAN Tx event FIFO status register */ +#define STM32_FDCAN_TXEFA_OFFSET 0x00e8 /* FDCAN Tx event FIFO acknowledge register */ +#define STM32_FDCAN_CKDIV_OFFSET 0x0100 /* FDCAN CFG clock divider register */ + +/* Register Bitfield Definitions ********************************************/ + +/* FDCAN core release register */ + +#define FDCAN_CREL_DAY_SHIFT (0) /* Bits 0-7: DAY */ +#define FDCAN_CREL_DAY_MASK (0xff << FDCAN_CREL_DAY_SHIFT) +#define FDCAN_CREL_MON_SHIFT (8) /* Bits 8-15: MON */ +#define FDCAN_CREL_MON_MASK (0xff << FDCAN_CREL_MON_SHIFT) +#define FDCAN_CREL_YEAR_SHIFT (16) /* Bits 8-15: YEAR */ +#define FDCAN_CREL_YEAR_MASK (0x0f << FDCAN_CREL_YEAR_SHIFT) +#define FDCAN_CREL_SUBSTEP_SHIFT (20) /* Bits 20-23: SUBSTEP */ +#define FDCAN_CREL_SUBSTEP_MASK (0x0f << FDCAN_CREL_SUBSTEP_SHIFT) +#define FDCAN_CREL_STEP_SHIFT (24) /* Bits 24-27: STEP */ +#define FDCAN_CREL_STEP_MASK (0x0f << FDCAN_CREL_STEP_SHIFT) +#define FDCAN_CREL_REL_SHIFT (28) /* Bits 28-31: REL */ +#define FDCAN_CREL_REL_MASK (0x0f << FDCAN_CREL_REL_SHIFT) + +/* FDCAN data bit timing and prescaler register */ + +#define FDCAN_DBTP_DSJW_SHIFT (0) /* Bits 0-3: Synchronization jump width */ +#define FDCAN_DBTP_DSJW_MASK (0x0f << FDCAN_DBTP_DSJW_SHIFT) +# define FDCAN_DBTP_DSJW(value) ((value) << FDCAN_DBTP_DSJW_SHIFT) +# define FDCAN_DBTP_DSJW_MAX (15) +#define FDCAN_DBTP_DTSEG2_SHIFT (4) /* Bits 4-7: Data time segment after sample point*/ +#define FDCAN_DBTP_DTSEG2_MASK (0x0f << FDCAN_DBTP_DTSEG2_SHIFT) +# define FDCAN_DBTP_DTSEG2(value) ((value) << FDCAN_DBTP_DTSEG2_SHIFT) +# define FDCAN_DBTP_DTSEG2_MAX (15) +#define FDCAN_DBTP_DTSEG1_SHIFT (8) /* Bits 8-12: Data time segment before sample point*/ +#define FDCAN_DBTP_DTSEG1_MASK (0x1f << FDCAN_DBTP_DTSEG1_SHIFT) +# define FDCAN_DBTP_DTSEG1(value) ((value) << FDCAN_DBTP_DTSEG1_SHIFT) +# define FDCAN_DBTP_DTSEG1_MAX (31) +#define FDCAN_DBTP_DBRP_SHIFT (16) /* Bits 16-20: Data bitrate prescaler */ +#define FDCAN_DBTP_DBRP_MASK (0x1f << FDCAN_DBTP_DBRP_SHIFT) +# define FDCAN_DBTP_DBRP(value) ((value) << FDCAN_DBTP_DBRP_SHIFT) +# define FDCAN_DBTP_DBRP_MAX (31) +#define FDCAN_DBTP_TDC_EN (1 << 23) /* Bit 23: Transceiver delay compensation enable */ + +/* FDCAN test register */ + +#define FDCAN_TEST_LBCK (1 << 4) /* Bit 4: Loop back mode */ +#define FDCAN_TEST_TX_SHIFT (5) /* Bits 5-6: Control of transmit pin */ +#define FDCAN_TEST_TX_MASK (0x3 << FDCAN_TEST_TX_SHIFT) +# define FDCAN_TEST_TX_RESET (0 << FDCAN_TEST_TX_SHIFT) /* 00: TX is controlled by CAN core */ +# define FDCAN_TEST_TX_SP (1 << FDCAN_TEST_TX_SHIFT) /* 01: Sample point can be monitored at TX pin */ +# define FDCAN_TEST_TX_DLVL (2 << FDCAN_TEST_TX_SHIFT) /* 10: Dominant (0) level at TX pin */ +# define FDCAN_TEST_TX_RLVL (3 << FDCAN_TEST_TX_SHIFT) /* 11: Recesive (1) level at TX pin */ +#define FDCAN_TEST_RX (1 << 7) /* Bit 7: Receive pin */ + +/* FDCAN RAM watchdog register */ + +#define FDCAN_RWD_WDC_SHIFT (0) /* Bits 0-7: RAM watchdog counter start value */ +#define FDCAN_RWD_WDC_MASK (0xff << FDCAN_RWD_WDC_SHIFT) +# define FDCAN_RWD_WDC_DIS (0 << FDCAN_RWD_WDC_SHIFT) /* Counter disabled */ +# define FDCAN_RWD_WDC(value) ((value) << FDCAN_RWD_WDC_SHIFT) +#define FDCAN_RWD_WDV_SHIFT (8) /* Bits 8-15: RAM watchdog counter value */ +#define FDCAN_RWD_WDV_MASK (0xff << FDCAN_RWD_WDV_SHIFT) + +/* FDCAN CC control register */ + +#define FDCAN_CCCR_INIT (1 << 0) /* Bit 0: Initialization */ +#define FDCAN_CCCR_CCE (1 << 1) /* Bit 1: Configuration change enable */ +#define FDCAN_CCCR_ASM (1 << 2) /* Bit 2: ASM restricted operation mode */ +#define FDCAN_CCCR_CSA (1 << 3) /* Bit 3: Clock stop acknowledge */ +#define FDCAN_CCCR_CSR (1 << 4) /* Bit 4: Clock stop request */ +#define FDCAN_CCCR_MON (1 << 5) /* Bit 5: Bus monitoring mode */ +#define FDCAN_CCCR_DAR (1 << 6) /* Bit 6: Disable automatic retransmission */ +#define FDCAN_CCCR_TEST (1 << 7) /* Bit 7: Test mode enable */ +#define FDCAN_CCCR_FDOE (1 << 8) /* Bit 8: FD operation enable */ +#define FDCAN_CCCR_BRSE (1 << 9) /* Bit 9: FDCAN Bitrate switching */ + /* Bits 10-11: Reserved */ +#define FDCAN_CCCR_PXHD (1 << 12) /* Bit 12: Protocol exception handling disable */ +#define FDCAN_CCCR_EFBI (1 << 13) /* Bit 13: Edge filtering during bus integration */ +#define FDCAN_CCCR_TXP (1 << 14) /* Bit 14: Tx pause */ +#define FDCAN_CCCR_NISO (1 << 15) /* Bit 15: Non ISO operation */ + +/* FDCAN nominal bit timing and prescaler register */ + +#define FDCAN_NBTP_NTSEG2_SHIFT (0) /* Bits 0-6: Nominal time segment after sample point */ +#define FDCAN_NBTP_NTSEG2_MASK (0x7f << FDCAN_NBTP_NTSEG2_SHIFT) +# define FDCAN_NBTP_NTSEG2(value) ((value) << FDCAN_NBTP_NTSEG2_SHIFT) +# define FDCAN_NBTP_NTSEG2_MAX (127) +#define FDCAN_NBTP_NTSEG1_SHIFT (8) /* Bits 8-15: Nominal time segment before sample point */ +#define FDCAN_NBTP_NTSEG1_MASK (0xff << FDCAN_NBTP_NTSEG1_SHIFT) +# define FDCAN_NBTP_NTSEG1(value) ((value) << FDCAN_NBTP_NTSEG1_SHIFT) +# define FDCAN_NBTP_NTSEG1_MAX (255) +#define FDCAN_NBTP_NBRP_SHIFT (16) /* Bits 16-24: Bitrate prescaler */ +#define FDCAN_NBTP_NBRP_MASK (0x1ff << FDCAN_NBTP_NBRP_SHIFT) +# define FDCAN_NBTP_NBRP(value) ((value) << FDCAN_NBTP_NBRP_SHIFT) +# define FDCAN_NBTP_NBRP_MAX (511) +#define FDCAN_NBTP_NSJW_SHIFT (25) /* Bits 25-31: Nominal (re)synchronization jump width */ +#define FDCAN_NBTP_NSJW_MASK (0x7f << FDCAN_NBTP_NSJW_SHIFT) +# define FDCAN_NBTP_NSJW(value) ((value) << FDCAN_NBTP_NSJW_SHIFT) +# define FDCAN_NBTP_NSJW_MAX (127) + +/* FDCAN timestamp counter configuration register */ + +#define FDCAN_TSCC_TSS_SHIFT (0) /* Bits 0-1: Timestamp counter select */ +#define FDCAN_TSCC_TSS_MASK (0x3 << FDCAN_TSCC_TSS_SHIFT) +# define FDCAN_TSCC_TSS_ZERO (0 << FDCAN_TSCC_TSS_SHIFT) /* 00: Always 0 */ +# define FDCAN_TSCC_TSS_TCP (1 << FDCAN_TSCC_TSS_SHIFT) /* 01: Incremented based on TCP */ +# define FDCAN_TSCC_TSS_TIM3 (2 << FDCAN_TSCC_TSS_SHIFT) /* 10: Value from TIM3 used */ +#define FDCAN_TSCC_TCP_SHIFT (16) /* Bits 16-19: Timestamp counter prescaler */ +#define FDCAN_TSCC_TCP_MASK (0x0f << FDCAN_TSCC_TCP_SHIFT) +# define FDCAN_TSCC_TCP(value) ((value) << FDCAN_TSCC_TCP_SHIFT) + +/* FDCAN timestamp counter value register */ + +#define FDCAN_TSCV_TSC_SHIFT (0) /* Bits 0-15: Timestamp counter */ +#define FDCAN_TSCV_TSC_MASK (0xffff << FDCAN_TSCV_TSC_SHIFT) + +/* FDCAN timeout counter configuration register */ + +#define FDCAN_TOCC_ETOC (1 << 0) /* Bit 0: Enable timeout counter */ +#define FDCAN_TOCC_TOS_SHIFT (1) /* Bits 1-2: Timeout select */ +#define FDCAN_TOCC_TOS_MASK (0x03 << FDCAN_TOCC_TOS_SHIFT) +# define FDCAN_TOCC_TOS_CONT (0 << FDCAN_TOCC_TOS_SHIFT) /* 00: Continuous operation */ +# define FDCAN_TOCC_TOS_TXFIFO (1 << FDCAN_TOCC_TOS_SHIFT) /* 01: Tx event FIFO */ +# define FDCAN_TOCC_TOS_RX_FIFO0 (2 << FDCAN_TOCC_TOS_SHIFT) /* 10: Rx FIFO 0 */ +# define FDCAN_TOCC_TOS_RX_FIFO1 (3 << FDCAN_TOCC_TOS_SHIFT) /* 11: Rx FIFO 1 */ +#define FDCAN_TOCC_TOP_SHIFT (16) /* Bits 16-31: Timeout period counter start value */ +#define FDCAN_TOCC_TOP_MASK (0xffff << FDCAN_TOCC_TOP_SHIFT) +# define FDCAN_TOCC_TOP(value) ((value) << FDCAN_TOCC_TOP_SHIFT) + +/* FDCAN timeout counter value register */ + +#define FDCAN_TOCV_TOC_SHIFT (0) /* Bits 0-15: Timestamp counter */ +#define FDCAN_TOCV_TOC_MASK (0xffff << FDCAN_TOCV_TOC_SHIFT) + +/* FDCAN error counter register */ + +#define FDCAN_ECR_TEC_SHIFT (0) /* Bits 0-7: Transmit error counter */ +#define FDCAN_CR_TEC_MASK (0xff << FDCAN_ECR_TEC_SHIFT) +#define FDCAN_ECR_REC_SHIFT (8) /* Bits 8-14: Receive error counter */ +#define FDCAN_ECR_REC_MASK (0x7f << FDCAN_ECR_REC_SHIFT) +#define FDCAN_ECR_RP (1 << 15) /* Bit 15: Receive error passive */ +#define FDCAN_ECR_CEL_SHIFT (16) /* Bits 16-23: CAN error logging */ +#define FDCAN_ECR_CEL_MASK (0xff << FDCAN_ECR_CEL_SHIFT) + +/* FDCAN protocol status register */ + +/* Error codes */ + +#define FDCAN_PSR_EC_NO_ERROR (0) /* No error occurred since LEC has been reset */ +#define FDCAN_PSR_EC_STUFF_ERROR (1) /* More than 5 equal bits in a sequence */ +#define FDCAN_PSR_EC_FORM_ERROR (2) /* Part of a received frame has wrong format */ +#define FDCAN_PSR_EC_ACK_ERROR (3) /* Message not acknowledged by another node */ +#define FDCAN_PSR_EC_BIT1_ERROR (4) /* Send with recessive level, but bus value was dominant */ +#define FDCAN_PSR_EC_BIT0_ERROR (5) /* Send with dominant level, but bus value was recessive */ +#define FDCAN_PSR_EC_CRC_ERROR (6) /* CRC received message incorrect */ +#define FDCAN_PSR_EC_NO_CHANGE (7) /* No CAN bus event was detected since last read */ + +#define FDCAN_PSR_LEC_SHIFT (0) /* Bits 0-2: Last error code */ +#define FDCAN_PSR_LEC_MASK (0x7 << FDCAN_PSR_LEC_SHIFT) +# define FDCAN_PSR_LEC(n) ((uint32_t)(n) << FDCAN_PSR_LEC_SHIFT) /* See error codes above */ +#define FDCAN_PSR_ACT_SHIFT (3) /* Bits 3-4: Activity */ +#define FDCAN_PSR_ACT_MASK (3 << FDCAN_PSR_ACT_SHIFT) +# define FDCAN_PSR_ACT_SYNC (0 << FDCAN_PSR_ACT_SHIFT) /* 00: Synchronizing */ +# define FDCAN_PSR_ACT_IDLE (1 << FDCAN_PSR_ACT_SHIFT) /* 01: Idle */ +# define FDCAN_PSR_ACT_RECV (2 << FDCAN_PSR_ACT_SHIFT) /* 10: Receiver */ +# define FDCAN_PSR_ACT_TRANS (3 << FDCAN_PSR_ACT_SHIFT) /* 11: Transmitter */ +#define FDCAN_PSR_EP (1 << 5) /* Bit 5: Error passive */ +#define FDCAN_PSR_EW (1 << 6) /* Bit 6: Warning status */ +#define FDCAN_PSR_BO (1 << 7) /* Bit 7: Bus_off status */ +#define FDCAN_PSR_DLEC_SHIFT (8) /* Bits 8-10: Data last error code */ +#define FDCAN_PSR_DLEC_MASK (0x7 << FDCAN_PSR_DLEC_SHIFT) +# define FDCAN_PSR_DLEC(n) ((uint32_t)(n) << FDCAN_PSR_DLEC_SHIFT) /* See error codes above */ +#define FDCAN_PSR_RESI (1 << 11) /* Bit 11: ESI flag of last message */ +#define FDCAN_PSR_RBRS (1 << 12) /* Bit 12: BRS flag of last message */ +#define FDCAN_PSR_REDL (1 << 13) /* Bit 13: Received message */ +#define FDCAN_PSR_PXE (1 << 14) /* Bit 14: Protocol exception event */ +#define FDCAN_PSR_TDCV_SHIFT (16) /* Bits 16-22: Transmitter delay compensation */ +#define FDCAN_PSR_TDCV_MASK (0x7f << FDCAN_PSR_TDCV_SHIFT) + +/* FDCAN transmitter delay compensation register */ + +#define FDCAN_TDCR_TDCF_SHIFT (0) /* Bits 0-6: Transmitter delay compensation filter window length */ +#define FDCAN_TDCR_TDCF_MASK (0x7f << FDCAN_TDCR_TDCF_SHIFT) +# define FDCAN_TDCR_TDCF(value) ((value) << FDCAN_TDCR_TDCF_SHIFT) +#define FDCAN_TDCR_TDCO_SHIFT (8) /* Bits 8-14: Transmiiter delay compensation offset */ +#define FDCAN_TDCR_TDCO_MASK (0x7f << FDCAN_TDCR_TDCO_SHIFT) +# define FDCAN_TDCR_TDCO(value) ((value) << FDCAN_TDCR_TDCO_SHIFT) + +/* FDCAN interrupt register and interrupt enable register */ + +#define FDCAN_INT_RF0N (1 << 0) /* Bit 0: Rx FIFO 0 new message */ +#define FDCAN_INT_RF0F (1 << 1) /* Bit 1: Rx FIFO 0 full */ +#define FDCAN_INT_RF0L (1 << 2) /* Bit 2: Rx FIFO 0 message lost */ +#define FDCAN_INT_RF1N (1 << 3) /* Bit 3: Rx FIFO 1 new message */ +#define FDCAN_INT_RF1F (1 << 4) /* Bit 4: Rx FIFO 1 full */ +#define FDCAN_INT_RF1L (1 << 5) /* Bit 5: Rx FIFO 1 message lost */ +#define FDCAN_INT_HPM (1 << 6) /* Bit 6: High priority message */ +#define FDCAN_INT_TC (1 << 7) /* Bit 7: Transmission completed */ +#define FDCAN_INT_TCF (1 << 8) /* Bit 8: Transmission cancellation finished */ +#define FDCAN_INT_TFE (1 << 9) /* Bit 9: Tx FIFO empty */ +#define FDCAN_INT_TEFN (1 << 10) /* Bit 10: Tx event FIFO new entry */ +#define FDCAN_INT_TEFF (1 << 11) /* Bit 11: Tx event FIFO full */ +#define FDCAN_INT_TEFL (1 << 12) /* Bit 12: Tx event FIFO element lost */ +#define FDCAN_INT_TSW (1 << 13) /* Bit 13: Timestamp wraparound */ +#define FDCAN_INT_MRAF (1 << 14) /* Bit 14: Message RAM access failure */ +#define FDCAN_INT_TOO (1 << 15) /* Bit 15: Timeout occurred */ +#define FDCAN_INT_ELO (1 << 16) /* Bit 16: Error logging overflow */ +#define FDCAN_INT_EP (1 << 17) /* Bit 17: Error_passive status */ +#define FDCAN_INT_EW (1 << 18) /* Bit 18: Error_warning status */ +#define FDCAN_INT_BO (1 << 19) /* Bit 19: Buss_off status */ +#define FDCAN_INT_WDI (1 << 20) /* Bit 20: Watchdog interrupt */ +#define FDCAN_INT_PEA (1 << 21) /* Bit 21: Protocol error arbitration phase */ +#define FDCAN_INT_PED (1 << 22) /* Bit 22: Protocol error data phase */ +#define FDCAN_INT_ARA (1 << 23) /* Bit 23: Access to reserved address */ + +/* FDCAN interrupt line select register */ + +#define FDCAN_ILS_RXFIFO0 (1 << 0) /* Bit 0: RXFIFO 0 */ +#define FDCAN_ILS_RXFIFO1 (1 << 1) /* Bit 1: RXFIFO 1 */ +#define FDCAN_ILS_SMG (1 << 2) /* Bit 2: SMSG */ +#define FDCAN_ILS_TFERR (1 << 3) /* Bit 3: TFERR */ +#define FDCAN_ILS_MISC (1 << 4) /* Bit 4: MISC */ +#define FDCAN_ILS_BERR (1 << 5) /* Bit 5: BERR */ +#define FDCAN_ILS_PERR (1 << 6) /* Bit 6: PERR */ + +/* FDCAN interrupt line enable register */ + +#define FDCAN_ILE_EINT0 (1 << 0) /* Bit 0: Enable interrupt line 0 */ +#define FDCAN_ILE_EINT1 (1 << 1) /* Bit 1: Enable interrupt line 1 */ + +/* FDCAN global filter configuration register */ + +#define FDCAN_RXGFC_RRFE (1 << 0) /* Bit 0: Reject remote frames ext */ +#define FDCAN_RXGFC_RRFS (1 << 1) /* Bit 1: Reject remote frames std */ +#define FDCAN_RXGFC_ANFE_SHIFT (2) /* Bits 2-3: Accept non-matching frames ext */ +#define FDCAN_RXGFC_ANFE_MASK (0x3 << FDCAN_RXGFC_ANFE_SHIFT) +# define FDCAN_RXGFC_ANFE_RX_FIFO0 (0 << FDCAN_RXGFC_ANFE_SHIFT) /* 00: Accept in Rx FIFO 0 */ +# define FDCAN_RXGFC_ANFE_RX_FIFO1 (1 << FDCAN_RXGFC_ANFE_SHIFT) /* 01: Accept in Rx FIFO 1 */ +# define FDCAN_RXGFC_ANFE_REJECTED (2 << FDCAN_RXGFC_ANFE_SHIFT) /* 10: Reject */ +#define FDCAN_RXGFC_ANFS_SHIFT (4) /* Bits 5-4: Accept non-matching frames std */ +#define FDCAN_RXGFC_ANFS_MASK (0x3 << FDCAN_RXGFC_ANFS_SHIFT) +# define FDCAN_RXGFC_ANFS_RX_FIFO0 (0 << FDCAN_RXGFC_ANFS_SHIFT) /* 00: Accept in Rx FIFO 0 */ +# define FDCAN_RXGFC_ANFS_RX_FIFO1 (1 << FDCAN_RXGFC_ANFS_SHIFT) /* 01: Accept in Rx FIFO 1 */ +# define FDCAN_RXGFC_ANFS_REJECTED (2 << FDCAN_RXGFC_ANFS_SHIFT) /* 10: Reject */ +#define FDCAN_RXGFC_F1OM (1 << 8) /* Bit 8: FIFO 1 operation mode */ +#define FDCAN_RXGFC_F0OM (1 << 9) /* Bit 9: FIFO 0 operation mode */ +#define FDCAN_RXGFC_LSS_SHIFT (16) /* Bits 16-20: List size std */ +#define FDCAN_RXGFC_LSS_MASK (0x1f << FDCAN_RXGFC_LSS_SHIFT) +# define FDCAN_RXGFC_LSS(value) ((value) << FDCAN_RXGFC_LSS_SHIFT) +# define FDCAN_RXGFC_LSS_MAX (28) +#define FDCAN_RXGFC_LSE_SHIFT (24) /* Bits 24-27: List size ext */ +#define FDCAN_RXGFC_LSE_MASK (0x1f << FDCAN_RXGFC_LSE_SHIFT) +# define FDCAN_RXGFC_LSE(value) ((value) << FDCAN_RXGFC_LSE_SHIFT) +# define FDCAN_RXGFC_LSE_MAX (8) + +/* FDCAN extended ID and mask register */ + +#define FDCAN_XIDAM_EIDM_SHIFT (0) /* Bits 0-28: Extended ID mask */ +#define FDCAN_XIDAM_EIDM_MASK (0x1fffffff << FDCAN_XIDAM_EIDM_SHIFT) + +/* FDCAN high-priority message status register */ + +#define FDCAN_HPMS_BIDX_SHIFT (0) /* Bits 0-2: Buffer index */ +#define FDCAN_HPMS_BIDX_MASK (0x7 << FDCAN_HPMS_BIDX_SHIFT) +# define FDCAN_HPMS_BIDX(value) ((value) << FDCAN_HPMS_BIDX_SHIFT) +#define FDCAN_HPMS_MSI_SHIFT (6) /* Bits 6-7: Message storage indicator */ +#define FDCAN_HPMS_MSI_MASK (0x3 << FDCAN_HPMS_MSI_SHIFT) +# define FDCAN_HPMS_MSI(value) ((value) << FDCAN_HPMS_MSI_SHIFT) +#define FDCAN_HPMS_FIDX_SHIFT (8) /* Bits 8-12: Filter index */ +#define FDCAN_HPMS_FIDX_MASK (0x1f << FDCAN_HPMS_FIDX_SHIFT) +# define FDCAN_HPMS_FIDX(value) ((value) << FDCAN_HPMS_FIDX_SHIFT) +#define FDCAN_HPMS_FLST (1 << 15) /* Bit 15: Filter list */ + +/* FDCAN Rx FIFO x status register */ + +#define FDCAN_RXFS_FFL_SHIFT (0) /* Bits 0-3: FIFO fill level */ +#define FDCAN_RXFS_FFL_MASK (0xf << FDCAN_RXFS_FFL_SHIFT) +# define FDCAN_RXFS_FFL(value) ((value) << FDCAN_RXFS_FFL_SHIFT) +#define FDCAN_RXFS_FGI_SHIFT (8) /* Bits 8-9: FIFO get index */ +#define FDCAN_RXFS_FGI_MASK (0x3 << FDCAN_RXFS_FGI_SHIFT) +# define FDCAN_RXFS_FGI(value) ((value) << FDCAN_RXFS_FGI_SHIFT) +#define FDCAN_RXFS_FPI_SHIFT (16) /* Bits 16-17: FIFO put index */ +#define FDCAN_RXFS_FPI_MASK (0x3 << FDCAN_RXFS_FPI_SHIFT) +# define FDCAN_RXFS_FPI(value) ((value) << FDCAN_RXFS_FPI_SHIFT) +#define FDCAN_RXFS_FF (1 << 24) /* Bit 24: FIFO full */ +#define FDCAN_RXFS_RFL (1 << 25) /* Bit 25: FIFO message lost */ + +/* FDCAN Rx FIFO x acknowledge register */ + +#define FDCAN_RXFA_FAI_SHIFT (0) /* Bits 0-2: FIFO 0 acknowledge index */ +#define FDCAN_RXFA_FAI_MASK (0x7 << FDCAN_RXFA_FAI_SHIFT) + +/* FDCAN Tx buffer configuration register */ + +#define FDCAN_TXBC_TFQM (1 << 24) /* Bit 24: FIFO/queue mode */ + +/* FDCAN Tx FIFO/queue status register */ + +#define FDCAN_TXFQS_TFFL_SHIFT (0) /* Bits 0-2: FIFO free level */ +#define FDCAN_TXFQS_TFFL_MASK (0x7 << FDCAN_TXFQS_TFFL_SHIFT) +#define FDCAN_TXFQS_TFGI_SHIFT (8) /* Bits 8-9: FIFO get index */ +#define FDCAN_TXFQS_TFGI_MASK (0x3 << FDCAN_TXFQS_TFGI_SHIFT) +#define FDCAN_TXFQS_TFQPI_SHIFT (16) /* Bits 20-16: FIFO/queue put index */ +#define FDCAN_TXFQS_TFQPI_MASK (0x3 << FDCAN_TXFQS_TFQPI_SHIFT) +#define FDCAN_TXFQS_TFQF (1 << 21) /* Bit 21: FIFO/queue full */ + +/* FDCAN Tx buffer request pending register */ + +#define FDCAN_TXBRP_TRP_SHIFT (0) /* Bits 0-2: Transmission request pending */ +#define FDCAN_TXBRP_TRP_MASK (0x7 << FDCAN_TXBRP_TRP_SHIFT) +# define FDCAN_TXBRP_TRP(value) ((value) << FDCAN_TXBRP_TRP_SHIFT) + +/* FDCAN Tx buffer add request register */ + +#define FDCAN_TXBAR_AR_SHIFT (0) /* Bits 0-2: Add request */ +#define FDCAN_TXBAR_AR_MASK (0x7 << FDCAN_TXBAR_AR_SHIFT) +# define FDCAN_TXBAR_AR(value) ((value) << FDCAN_TXBAR_AR_SHIFT) + +/* FDCAN Tx buffer cancellation request register */ + +#define FDCAN_TXBCR_CR_SHIFT (0) /* Bits 0-2: Cancellation request */ +#define FDCAN_TXBCR_CR_MASK (0x7 << FDCAN_TXBCR_CR_SHIFT) +# define FDCAN_TXBCR_CR(value) ((value) << FDCAN_TXBCR_CR_SHIFT) + +/* FDCAN Tx buffer transmission occurred register */ + +#define FDCAN_TXBTO_TO_SHIFT (0) /* Bits 0-2: Transmission occurred */ +#define FDCAN_TXBTO_TO_MASK (0x7 << FDCAN_TXBTO_TO_SHIFT) + +/* FDCAN Tx buffer cancellation finished register */ + +#define FDCAN_TXBCF_CF_SHIFT (0) /* Bits 0-2: Cancellation finished */ +#define FDCAN_TXBCF_CF_MASK (0x7 << FDCAN_TXBCF_CF_SHIFT) + +/* FDCAN Tx buffer transmission interrupt enable register */ + +#define FDCAN_TXBTIE_TIE_SHIFT (0) /* Bits 0-2: Transmission interrupt enable */ +#define FDCAN_TXBTIE_TIE_MASK (0x7 << FDCAN_TXBTIE_TIE_SHIFT) +# define FDCAN_TXBTIE_TIE(value) ((value) << FDCAN_TXBTIE_TIE_SHIFT) + +/* FDCAN Tx buffer cancellation finished interrupt enable register */ + +#define FDCAN_TXBCIE_CFIE_SHIFT (0) /* Bits 0-2: Cancellation finished interrupt enable */ +#define FDCAN_TXBCIE_CFIE_MASK (0x7 << FDCAN_TXBCIE_CFIE_SHIFT) +# define FDCAN_TXBCIE_CFIE(value) ((value) << FDCAN_TXBCIE_CFIE_SHIFT) + +/* FDCAN Tx event FIFO status register */ + +#define FDCAN_TXEFS_EFFL_SHIFT (2) /* Bits 0-2: Event FIFO fill level */ +#define FDCAN_TXEFS_EFFL_MASK (0x7 << FDCAN_TXEFC_EFFL_SHIFT) +# define FDCAN_TXEFC_EFFL(value) ((value) << FDCAN_TXEFC_EFFL_SHIFT) +#define FDCAN_TXEFS_EFGI_SHIFT (8) /* Bits 8-9: Event FIFO get index */ +#define FDCAN_TXEFS_EFGI_MASK (0x3 << FDCAN_TXEFS_EFGI_SHIFT) +# define FDCAN_TXEFS_EFGI(value) ((value) << FDCAN_TXEFS_EFGI_SHIFT) +#define FDCAN_TXEFS_EFPI_SHIFT (16) /* Bits 16-17: Event FIFO put index */ +#define FDCAN_TXEFS_EFPI_MASK (0x3 << FDCAN_TXEFS_EFPI_SHIFT) +# define FDCAN_TXEFS_EFPI(value) ((value) << FDCAN_TXEFS_EFPI_SHIFT) +#define FDCAN_TXEFS_EFF (1 << 24) /* Bit 24: Event FIFO full */ +#define FDCAN_TXEFS_TEFL (1 << 25) /* Bit 25: Tx Event FIFO element lost */ + /* Bits 26-31: Reserved */ + +/* FDCAN Tx event FIFO acknowledge register */ + +#define FDCAN_TXEFA_EFAI_SHIFT (0) /* Bits 0-3: Event FIFO acknowledge index */ +#define FDCAN_TXEFA_EFAI_MASK (0x3 << FDCAN_TXEFA_EFAI_SHIFT) + +/* FDCAN CFG clock divider register */ + +#define FDCAN_CKDIV_PDIV_SHIFT (0) /* Bits 0-3: Input clock divider */ +#define FDCAN_CKDIV_PDIV_MASK (0xf << FDCAN_CKDIV_PDIV_SHIFT) + +/* Message RAM Definitions **************************************************/ + +/* Common Buffer and FIFO element bit definitions: + * + * --------------- ------------------- -------------------------------- + * RESOURCE R0 R1 + * --------------- ------------------- -------------------------------- + * RX FIFO: ESI, XTD, RTR, ID, ANMF, FIDX, EDL, BRS, DLC, RXTS + * TX buffer: XTD, RTR, ID, MM, EFC, DLC + * TX Event FIFO: ESI, XTD, RTR, ID, MM, ET, EDL, BRS, DLC, TXTS + * --------------- ------------------- -------------------------------- + */ + +/* Common */ + +#define BUFFER_R0_EXTID_SHIFT (0) /* Bits 0-28: Extended identifier */ +#define BUFFER_R0_EXTID_MASK (0x1fffffff << BUFFER_R0_EXTID_SHIFT) +# define BUFFER_R0_EXTID(n) ((uint32_t)(n) << BUFFER_R0_EXTID_SHIFT) +#define BUFFER_R0_STDID_SHIFT (18) /* Bits 18-28: Standard identifier */ +#define BUFFER_R0_STDID_MASK (0x7ff << BUFFER_R0_STDID_SHIFT) +# define BUFFER_R0_STDID(n) ((uint32_t)(n) << BUFFER_R0_STDID_SHIFT) +#define BUFFER_R0_RTR (1 << 29) /* Bit 29: Remote Transmission Request */ +#define BUFFER_R0_XTD (1 << 30) /* Bit 30: Extended Identifier */ +#define BUFFER_R0_ESI (1 << 31) /* Bit 31: Error State Indicator */ + +/* Common */ + +#define BUFFER_R1_DLC_SHIFT (16) /* Bits 16-19: Date length code */ +#define BUFFER_R1_DLC_MASK (15 << BUFFER_R1_DLC_SHIFT) +# define BUFFER_R1_DLC(n) ((uint32_t)(n) << BUFFER_R1_DLC_SHIFT) +#define BUFFER_R1_BRS (1 << 20) /* Bit 20: Bit Rate Switch */ +#define BUFFER_R1_FDF (1 << 21) /* Bit 21: FD Format */ + +/* RX buffer/RX FIFOs */ + +#define BUFFER_R1_RXTS_SHIFT (0) /* Bits 0-15: RX Timestamp */ +#define BUFFER_R1_RXTS_MASK (0xffff << BUFFER_R1_RXTS_SHIFT) +# define BUFFER_R1_RXTS(n) ((uint32_t)(n) << BUFFER_R1_RXTS_SHIFT) +#define BUFFER_R1_FIDX_SHIFT (24) /* Bits 24-30: Filter index */ +#define BUFFER_R1_FIDX_MASK (0x7f << BUFFER_R1_FIDX_SHIFT) +# define BUFFER_R1_FIDX(n) ((uint32_t)(n) << BUFFER_R1_FIDX_SHIFT) +#define BUFFER_R1_ANMF (1 << 31) /* Bit 31: Accepted Non-matching Frame */ + +/* TX buffer/TX Event FIFO */ + +#define BUFFER_R1_MM_SHIFT (24) /* Bits 24-31: Message Marker */ +#define BUFFER_R1_MM_MASK (0xff << BUFFER_R1_MM_SHIFT) +# define BUFFER_R1_MM(n) ((uint32_t)(n) << BUFFER_R1_MM_SHIFT) + +/* TX buffer */ + +#define BUFFER_R1_EFC (1 << 23) /* Bit 23: Event FIFO Control */ + +/* TX Event FIFO */ + +#define BUFFER_R1_TXTS_SHIFT (0) /* Bits 0-15: TX Timestamp */ +#define BUFFER_R1_TXTS_MASK (0xffff << BUFFER_R1_TXTS_SHIFT) +# define BUFFER_R1_TXTS(n) ((uint32_t)(n) << BUFFER_R1_TXTS_SHIFT) +#define BUFFER_R1_EDL (1 << 21) /* Bit 21: Extended Data Length */ +#define BUFFER_R1_ET_SHIFT (22) /* Bits 22-23: Event Type */ +#define BUFFER_R1_ET_MASK (3 << BUFFER_R1_ET_SHIFT) +# define BUFFER_R1_ET_TXEVENT (1 << BUFFER_R1_ET_SHIFT) /* Tx event */ +# define BUFFER_R1_ET_TXCANCEL (2 << BUFFER_R1_ET_SHIFT) /* Transmission despite cancellation */ + +/* Standard Message ID Filter Element */ + +#define STDFILTER_S0_SFID2_SHIFT (0) /* Bits 0-10: Standard Filter ID 2 */ +#define STDFILTER_S0_SFID2_MASK (0x7ff << STDFILTER_S0_SFID2_SHIFT) +# define STDFILTER_S0_SFID2(n ) ((uint32_t)(n) << STDFILTER_S0_SFID2_SHIFT) +#define STDFILTER_S0_BUFFER_SHIFT (0) /* Bits 0-5: RX buffer start address */ +#define STDFILTER_S0_BUFFER_MASK (63 << STDFILTER_S0_BUFFER_SHIFT) +# define STDFILTER_S0_BUFFER(n) ((uint32_t)(n) << STDFILTER_S0_BUFFER_SHIFT) +#define STDFILTER_S0_ACTION_SHIFT (9) /* Bits 9-10: Action taken */ +#define STDFILTER_S0_ACTION_MASK (3 << STDFILTER_S0_ACTION_SHIFT) +# define STDFILTER_S0_RXBUFFER (0 << STDFILTER_S0_ACTION_SHIFT) /* Store message in a Rx buffer */ +# define STDFILTER_S0_DEBUGA (1 << STDFILTER_S0_ACTION_SHIFT) /* Debug Message A */ +# define STDFILTER_S0_DEBUGB (2 << STDFILTER_S0_ACTION_SHIFT) /* Debug Message B */ +# define STDFILTER_S0_DEBUGC (3 << STDFILTER_S0_ACTION_SHIFT) /* Debug Message C */ +#define STDFILTER_S0_SFID1_SHIFT (16) /* Bits 16-26: Standard Filter ID 2 */ +#define STDFILTER_S0_SFID1_MASK (0x7ff << STDFILTER_S0_SFID1_SHIFT) +# define STDFILTER_S0_SFID1(n) ((uint32_t)(n) << STDFILTER_S0_SFID1_SHIFT) +#define STDFILTER_S0_SFEC_SHIFT (27) /* Bits 27-29: Standard Filter Element Configuration */ +#define STDFILTER_S0_SFEC_MASK (7 << STDFILTER_S0_SFEC_SHIFT) +# define STDFILTER_S0_SFEC_DISABLE (0 << STDFILTER_S0_SFEC_SHIFT) /* Disable filter element */ +# define STDFILTER_S0_SFEC_FIFO0 (1 << STDFILTER_S0_SFEC_SHIFT) /* Store in Rx FIFO 0 on match */ +# define STDFILTER_S0_SFEC_FIFO1 (2 << STDFILTER_S0_SFEC_SHIFT) /* Store in Rx FIFO 1 on match */ +# define STDFILTER_S0_SFEC_REJECT (3 << STDFILTER_S0_SFEC_SHIFT) /* Reject ID on match */ +# define STDFILTER_S0_SFEC_PRIORITY (4 << STDFILTER_S0_SFEC_SHIFT) /* Set priority ion match */ +# define STDFILTER_S0_SFEC_PRIOFIFO0 (5 << STDFILTER_S0_SFEC_SHIFT) /* Set priority and store in FIFO 0 on match */ +# define STDFILTER_S0_SFEC_PRIOFIFO1 (6 << STDFILTER_S0_SFEC_SHIFT) /* Set priority and store in FIFO 1 on match */ +# define STDFILTER_S0_SFEC_BUFFER (7 << STDFILTER_S0_SFEC_SHIFT) /* Store into Rx Buffer or as debug message */ +#define STDFILTER_S0_SFT_SHIFT (30) /* Bits 30-31: Standard Filter Type */ +#define STDFILTER_S0_SFT_MASK (3 << STDFILTER_S0_SFT_SHIFT) +# define STDFILTER_S0_SFT_RANGE (0 << STDFILTER_S0_SFT_SHIFT) /* Range filter from SF1ID to SF2ID */ +# define STDFILTER_S0_SFT_DUAL (1 << STDFILTER_S0_SFT_SHIFT) /* Dual ID filter for SF1ID or SF2ID */ +# define STDFILTER_S0_SFT_CLASSIC (2 << STDFILTER_S0_SFT_SHIFT) /* Classic filter: SF1ID=filter SF2ID=mask */ + +/* Extended Message ID Filter Element */ + +#define EXTFILTER_F0_EFID1_SHIFT (0) /* Bits 0-28: Extended Filter ID 1 */ +#define EXTFILTER_F0_EFID1_MASK (0x1fffffff << EXTFILTER_F0_EFID1_SHIFT) +# define EXTFILTER_F0_EFID1(n) ((uint32_t)(n) << EXTFILTER_F0_EFID1_SHIFT) +#define EXTFILTER_F0_EFEC_SHIFT (29) /* Bits 29-31: Extended Filter Element Configuration */ +#define EXTFILTER_F0_EFEC_MASK (7 << EXTFILTER_F0_EFEC_SHIFT) +# define EXTFILTER_F0_EFEC_DISABLE (0 << EXTFILTER_F0_EFEC_SHIFT) /* Disable filter element */ +# define EXTFILTER_F0_EFEC_FIFO0 (1 << EXTFILTER_F0_EFEC_SHIFT) /* Store in Rx FIFO 0 on match */ +# define EXTFILTER_F0_EFEC_FIFO1 (2 << EXTFILTER_F0_EFEC_SHIFT) /* Store in Rx FIFO 1 on match */ +# define EXTFILTER_F0_EFEC_REJECT (3 << EXTFILTER_F0_EFEC_SHIFT) /* Reject ID on match */ +# define EXTFILTER_F0_EFEC_PRIORITY (4 << EXTFILTER_F0_EFEC_SHIFT) /* Set priority on match */ +# define EXTFILTER_F0_EFEC_PRIOFIFO0 (5 << EXTFILTER_F0_EFEC_SHIFT) /* Set priority and store in FIFO 0 on match */ +# define EXTFILTER_F0_EFEC_PRIOFIFO1 (6 << EXTFILTER_F0_EFEC_SHIFT) /* Set priority and store in FIFO 1 on match */ +# define EXTFILTER_F0_EFEC_BUFFER (7 << EXTFILTER_F0_EFEC_SHIFT) /* Store into Rx Buffer or as debug message */ + +#define EXTFILTER_F1_EFID2_SHIFT (0) /* Bits 0-28: Extended Filter ID 2 */ +#define EXTFILTER_F1_EFID2_MASK (0x1fffffff << EXTFILTER_F1_EFID2_SHIFT) +# define EXTFILTER_F1_EFID2(n) ((uint32_t)(n) << EXTFILTER_F1_EFID2_SHIFT) +#define EXTFILTER_F1_BUFFER_SHIFT (0) /* Bits 0-5: RX buffer start address */ +#define EXTFILTER_F1_BUFFER_MASK (63 << EXTFILTER_F1_BUFFER_SHIFT) +# define EXTFILTER_F1_BUFFER(n) ((uint32_t)(n) << EXTFILTER_F1_BUFFER_SHIFT) +#define EXTFILTER_F1_ACTION_SHIFT (9) /* Bits 9-10: Action taken */ +#define EXTFILTER_F1_ACTION_MASK (3 << EXTFILTER_F1_ACTION_SHIFT) +# define EXTFILTER_F1_RXBUFFER (0 << EXTFILTER_F1_ACTION_SHIFT) /* Store message in a Rx buffer */ +# define EXTFILTER_F1_DEBUGA (1 << EXTFILTER_F1_ACTION_SHIFT) /* Debug Message A */ +# define EXTFILTER_F1_DEBUGB (2 << EXTFILTER_F1_ACTION_SHIFT) /* Debug Message B */ +# define EXTFILTER_F1_DEBUGC (3 << EXTFILTER_F1_ACTION_SHIFT) /* Debug Message C */ +#define EXTFILTER_F1_EFT_SHIFT (30) /* Bits 30-31: Extended Filter Type */ +#define EXTFILTER_F1_EFT_MASK (3 << EXTFILTER_F1_EFT_SHIFT) +# define EXTFILTER_F1_EFT_RANGE (0 << EXTFILTER_F1_EFT_SHIFT) /* Range filter from SF1ID to SF2ID */ +# define EXTFILTER_F1_EFT_DUAL (1 << EXTFILTER_F1_EFT_SHIFT) /* Dual ID filter for SF1ID or SF2ID */ +# define EXTFILTER_F1_EFT_CLASSIC (2 << EXTFILTER_F1_EFT_SHIFT) /* Classic filter: SF1ID=filter SF2ID=mask */ +# define EXTFILTER_F1_EFT_NOXIDAM (3 << EXTFILTER_F1_EFT_SHIFT) /* Range filter from EF1ID to EF2ID, no XIDAM */ + +#endif /* __ARCH_ARM_SRC_STM32_HARDWARE_STM32_FDCAN_H */ diff --git a/arch/arm/src/stm32/hardware/stm32g4xxxx_memorymap.h b/arch/arm/src/stm32/hardware/stm32g4xxxx_memorymap.h index 2ced9d421c1..036f550ba4b 100644 --- a/arch/arm/src/stm32/hardware/stm32g4xxxx_memorymap.h +++ b/arch/arm/src/stm32/hardware/stm32g4xxxx_memorymap.h @@ -112,7 +112,7 @@ #define STM32_LPUART1_BASE 0x40008000 /* 0x40008000-0x400083ff: LPUART1 */ #define STM32_I2C4_BASE 0x40008400 /* 0x40008400-0x400087ff: I2C4 */ #define STM32_UCPD1_BASE 0x4000a000 /* 0x4000a000-0x4000a3ff: UCPD1 */ -#define STM32_SRAMCAN_BASE 0x4000a400 /* 0x4000a400-0x4000afff: FDCANs Message RAM */ +#define STM32_CANRAM_BASE 0x4000a400 /* 0x4000a400-0x4000afff: FDCANs Message RAM */ /* APB2 Base Addresses ******************************************************/ diff --git a/arch/arm/src/stm32/stm32_fdcan.c b/arch/arm/src/stm32/stm32_fdcan.c new file mode 100644 index 00000000000..f1174892c95 --- /dev/null +++ b/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 + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#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: + regval |= STDFILTER_S0_SFT_RANGE; + break; + } + + *stdfilter = regval; + + /* Is this the first standard filter? */ + + if (priv->nstdalloc == 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. + * + * ANFS=2: Discard all rejected frames + */ + + regval = fdcan_getreg(priv, STM32_FDCAN_RXGFC_OFFSET); + regval &= ~FDCAN_RXGFC_ANFS_MASK; + regval |= FDCAN_RXGFC_ANFS_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->nstdalloc == priv->config->nstdfilters); + return -EAGAIN; +} + +/**************************************************************************** + * Name: fdcan_del_stdfilter + * + * 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_stdfilter(). + * + * Returned Value: + * Zero (OK) is returned on success. Otherwise a negated errno value is + * returned to indicate the nature of the error. + * + ****************************************************************************/ + +static int fdcan_del_stdfilter(FAR struct stm32_fdcan_s *priv, int ndx) +{ + FAR const struct stm32_config_s *config = NULL; + FAR uint32_t *stdfilter = NULL; + uint32_t regval = 0; + int word = 0; + int bit = 0; + + DEBUGASSERT(priv != NULL && priv->config != NULL); + config = priv->config; + + /* Check Userspace Parameters */ + + DEBUGASSERT(ndx >= 0 || ndx < config->nstdfilters); + + if (ndx < 0 || ndx >= config->nstdfilters) + { + return -EINVAL; + } + + word = ndx >> 5; + bit = ndx & 0x1f; + + /* Check if this filter is really assigned */ + + if ((priv->stdfilters[word] & (1 << bit)) == 0) + { + /* No, error out */ + + return -ENOENT; + } + + /* Release the filter */ + + priv->stdfilters[word] &= ~(1 << bit); + + DEBUGASSERT(priv->nstdalloc > 0); + priv->nstdalloc--; + + /* Was that the last standard filter? */ + + if (priv->nstdalloc == 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 standard filters, then modify Global Filter + * Configuration so that all rejected messages are places in RX + * FIFO0. + * + * ANFS=0: Store all rejected extended frame in RX FIFO0 + */ + + regval = fdcan_getreg(priv, STM32_FDCAN_RXGFC_OFFSET); + regval &= ~FDCAN_RXGFC_ANFS_MASK; + regval |= FDCAN_RXGFC_ANFS_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. */ + + stdfilter = config->msgram.stdfilters + ndx; + *stdfilter = 0; + + return OK; +} + +/**************************************************************************** + * Name: fdcan_start_busoff_recovery_sequence + * + * Description: + * This function initiates the BUS-OFF recovery sequence. + * CAN Specification Rev. 2.0 or ISO11898-1:2015 + * According the SAMV71 datasheet: + * + * "If the device goes Bus_Off, it will set FDCAN_CCCR.INIT of its own + * accord, stopping all bus activities. Once FDCAN_CCCR.INIT has been + * cleared by the processor (application), the device will then wait for + * 129 occurrences of Bus Idle (129 * 11 consecutive recessive bits) + * before resuming normal operation. At the end of the Bus_Off recovery + * sequence, the Error Management Counters will be reset. During the + * waiting time after the resetting of FDCAN_CCCR.INIT, each time a + * sequence of 11 recessive bits has been monitored, a Bit0 Error code is + * written to FDCAN_PSR.LEC, enabling the processor to readily check up + * whether the CAN bus is stuck at dominant or continuously disturbed and + * to monitor the Bus_Off recovery sequence. FDCAN_ECR.REC is used to + * count these sequences." + * + * Input Parameters: + * priv - An instance of the FDCAN driver state structure. + * + * Returned Value: + * Zero (OK) is returned on success. Otherwise a negated errno value is + * returned to indicate the nature of the error. + * + ****************************************************************************/ + +static int +fdcan_start_busoff_recovery_sequence(FAR struct stm32_fdcan_s *priv) +{ + uint32_t regval = 0; + + DEBUGASSERT(priv); + + /* Only start BUS-OFF recovery if we are in BUS-OFF state */ + + regval = fdcan_getreg(priv, STM32_FDCAN_PSR_OFFSET); + if (!(regval & FDCAN_PSR_BO)) + { + return -EPERM; + } + + /* Disable initialization mode to issue the recovery sequence */ + + regval = fdcan_getreg(priv, STM32_FDCAN_CCCR_OFFSET); + regval &= ~FDCAN_CCCR_INIT; + fdcan_putreg(priv, STM32_FDCAN_CCCR_OFFSET, regval); + + return OK; +} + +/**************************************************************************** + * Name: fdcan_reset + * + * Description: + * Reset the FDCAN device. Called early to initialize the hardware. This + * function is called, before fdcan_setup() and on error conditions. + * + * Input Parameters: + * dev - An instance of the "upper half" can driver state structure. + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void fdcan_reset(FAR struct can_dev_s *dev) +{ + FAR struct stm32_fdcan_s *priv = NULL; + FAR const struct stm32_config_s *config = NULL; + uint32_t regval = 0; + irqstate_t flags; + + DEBUGASSERT(dev); + priv = dev->cd_priv; + DEBUGASSERT(priv); + config = priv->config; + DEBUGASSERT(config); + + caninfo("FDCAN%d\n", config->port); + UNUSED(config); + + /* Disable all interrupts */ + + fdcan_putreg(priv, STM32_FDCAN_IE_OFFSET, 0); + fdcan_putreg(priv, STM32_FDCAN_TXBTIE_OFFSET, 0); + + /* Make sure that all buffers are released. + * + * REVISIT: What if a thread is waiting for a buffer? The following + * will not wake up any waiting threads. + */ + + /* Disable the FDCAN controller. + * REVISIT: Should fdcan_shutdown() be called here? + */ + + /* Reset the FD CAN. + * REVISIT: Since there is only a single reset for both FDCAN + * controllers, do we really want to use the RCC reset here? + * This will nuke operation of the second controller if another + * device is registered. + */ + + flags = enter_critical_section(); + regval = getreg32(STM32_RCC_APB1RSTR1); + regval |= RCC_APB1RSTR1_FDCANRST; + putreg32(regval, STM32_RCC_APB1RSTR1); + + regval &= ~RCC_APB1RSTR1_FDCANRST; + putreg32(regval, STM32_RCC_APB1RSTR1); + leave_critical_section(flags); + + priv->state = FDCAN_STATE_RESET; +} + +/**************************************************************************** + * Name: fdcan_setup + * + * Description: + * Configure the FDCAN. This method is called the first time that the FDCAN + * device is opened. This will occur when the port is first opened. + * This setup includes configuring and attaching FDCAN interrupts. + * All FDCAN interrupts are disabled upon return. + * + * 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 fdcan_setup(FAR struct can_dev_s *dev) +{ + FAR struct stm32_fdcan_s *priv = NULL; + FAR const struct stm32_config_s *config = NULL; + int ret = 0; + + DEBUGASSERT(dev); + priv = dev->cd_priv; + DEBUGASSERT(priv); + config = priv->config; + DEBUGASSERT(config); + + caninfo("FDCAN%d\n", config->port); + + /* FDCAN hardware initialization */ + + ret = fdcan_hw_initialize(priv); + if (ret < 0) + { + canerr("ERROR: FDCAN%d H/W initialization failed: %d\n", + config->port, ret); + return ret; + } + + fdcan_dumpregs(priv, "After hardware initialization"); + + /* Attach the FDCAN interrupt handlers */ + + ret = irq_attach(config->irq0, fdcan_interrupt, dev); + if (ret < 0) + { + canerr("ERROR: Failed to attach FDCAN%d line 0 IRQ (%d)", + config->port, config->irq0); + return ret; + } + + ret = irq_attach(config->irq1, fdcan_interrupt, dev); + if (ret < 0) + { + canerr("ERROR: Failed to attach FDCAN%d line 1 IRQ (%d)", + config->port, config->irq1); + return ret; + } + + priv->state = FDCAN_STATE_SETUP; + + /* Enable the interrupts at the NVIC (they are still disabled at the FDCAN + * peripheral). + */ + + up_enable_irq(config->irq0); + up_enable_irq(config->irq1); + + return OK; +} + +/**************************************************************************** + * Name: fdcan_shutdown + * + * Description: + * Disable the FDCAN. This method is called when the FDCAN 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 fdcan_shutdown(FAR struct can_dev_s *dev) +{ + FAR struct stm32_fdcan_s *priv = NULL; + FAR const struct stm32_config_s *config = NULL; + uint32_t regval = 0; + + DEBUGASSERT(dev); + priv = dev->cd_priv; + DEBUGASSERT(priv); + config = priv->config; + DEBUGASSERT(config); + + caninfo("FDCAN%d\n", config->port); + + /* Disable FDCAN interrupts at the NVIC */ + + up_disable_irq(config->irq0); + up_disable_irq(config->irq1); + + /* Disable all interrupts from the FDCAN peripheral */ + + fdcan_putreg(priv, STM32_FDCAN_IE_OFFSET, 0); + fdcan_putreg(priv, STM32_FDCAN_TXBTIE_OFFSET, 0); + + /* Detach the FDCAN interrupt handler */ + + irq_detach(config->irq0); + irq_detach(config->irq1); + + /* Disable device by setting the Clock Stop Request bit */ + + regval = fdcan_getreg(priv, STM32_FDCAN_CCCR_OFFSET); + regval |= FDCAN_CCCR_CSR; + fdcan_putreg(priv, STM32_FDCAN_CCCR_OFFSET, regval); + + /* Wait for Init and Clock Stop Acknowledge bits to verify + * device is in the powered down state + */ + + while ((fdcan_getreg(priv, STM32_FDCAN_CCCR_OFFSET) & FDCAN_CCCR_INIT) + == 0); + while ((fdcan_getreg(priv, STM32_FDCAN_CCCR_OFFSET) & FDCAN_CCCR_CSA) + == 0); + priv->state = FDCAN_STATE_DISABLED; +} + +/**************************************************************************** + * Name: fdcan_rxint + * + * Description: + * Call to enable or disable RX interrupts. + * + * Input Parameters: + * dev - An instance of the "upper half" can driver state structure. + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void fdcan_rxint(FAR struct can_dev_s *dev, bool enable) +{ + FAR struct stm32_fdcan_s *priv = dev->cd_priv; + uint32_t regval = 0; + + DEBUGASSERT(priv && priv->config); + + caninfo("FDCAN%d enable: %d\n", priv->config->port, enable); + + /* Enable/disable the receive interrupts */ + + regval = fdcan_getreg(priv, STM32_FDCAN_IE_OFFSET); + + if (enable) + { + regval |= priv->rxints | FDCAN_COMMON_INTS; + } + else + { + regval &= ~priv->rxints; + } + + fdcan_putreg(priv, STM32_FDCAN_IE_OFFSET, regval); +} + +/**************************************************************************** + * Name: fdcan_txint + * + * Description: + * Call to enable or disable TX interrupts. + * + * Input Parameters: + * dev - An instance of the "upper half" can driver state structure. + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void fdcan_txint(FAR struct can_dev_s *dev, bool enable) +{ + FAR struct stm32_fdcan_s *priv = dev->cd_priv; + uint32_t regval = 0; + + DEBUGASSERT(priv && priv->config); + + caninfo("FDCAN%d enable: %d\n", priv->config->port, enable); + + /* Enable/disable the receive interrupts */ + + regval = fdcan_getreg(priv, STM32_FDCAN_IE_OFFSET); + + if (enable) + { + regval |= priv->txints | FDCAN_COMMON_INTS; + } + else + { + regval &= ~priv->txints; + } + + fdcan_putreg(priv, STM32_FDCAN_IE_OFFSET, regval); +} + +/**************************************************************************** + * Name: fdcan_ioctl + * + * Description: + * All ioctl calls will be routed through this method + * + * 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 fdcan_ioctl(FAR struct can_dev_s *dev, int cmd, unsigned long arg) +{ + FAR struct stm32_fdcan_s *priv = NULL; + int ret = -ENOTTY; + + caninfo("cmd=%04x arg=%lu\n", cmd, arg); + + DEBUGASSERT(dev && dev->cd_priv); + priv = dev->cd_priv; + + /* 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: + { + FAR struct canioc_bittiming_s *bt = + (FAR struct canioc_bittiming_s *)arg; + uint32_t regval; + uint32_t nbrp; + + DEBUGASSERT(bt != NULL); + + regval = fdcan_getreg(priv, STM32_FDCAN_NBTP_OFFSET); + bt->bt_sjw = ((regval & FDCAN_NBTP_NSJW_MASK) >> + FDCAN_NBTP_NSJW_SHIFT) + 1; + bt->bt_tseg1 = ((regval & FDCAN_NBTP_NTSEG1_MASK) >> + FDCAN_NBTP_NTSEG1_SHIFT) + 1; + bt->bt_tseg2 = ((regval & FDCAN_NBTP_NTSEG2_MASK) >> + FDCAN_NBTP_NTSEG2_SHIFT) + 1; + + nbrp = ((regval & FDCAN_NBTP_NBRP_MASK) >> + FDCAN_NBTP_NBRP_SHIFT) + 1; + bt->bt_baud = STM32_FDCANCLK_FREQUENCY / nbrp / + (bt->bt_tseg1 + bt->bt_tseg2 + 1); + ret = OK; + } + break; + + /* CANIOC_SET_BITTIMING: + * Description: Set new current bit timing values + * Argument: A pointer to a read-able instance of struct + * canioc_bittiming_s in which the new bit timing + * values are provided. + * 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 + * + * REVISIT: There is probably a limitation here: If there are + * multiple threads trying to send CAN packets, when one of these + * threads reconfigures the bitrate, the FDCAN hardware will be reset + * and the context of operation will be lost. Hence, this IOCTL can + * only safely be executed in quiescent time periods. + */ + + case CANIOC_SET_BITTIMING: + { + FAR const struct canioc_bittiming_s *bt = + (FAR const struct canioc_bittiming_s *)arg; + uint32_t nbrp; + uint32_t ntseg1; + uint32_t ntseg2; + uint32_t nsjw; + uint32_t ie; + uint8_t state; + + DEBUGASSERT(bt != NULL); + DEBUGASSERT(bt->bt_baud < STM32_FDCANCLK_FREQUENCY); + DEBUGASSERT(bt->bt_sjw > 0 && bt->bt_sjw <= 16); + DEBUGASSERT(bt->bt_tseg1 > 1 && bt->bt_tseg1 <= 64); + DEBUGASSERT(bt->bt_tseg2 > 0 && bt->bt_tseg2 <= 16); + + /* Extract bit timing data */ + + ntseg1 = bt->bt_tseg1 - 1; + ntseg2 = bt->bt_tseg2 - 1; + nsjw = bt->bt_sjw - 1; + + nbrp = (uint32_t) + (((float) STM32_FDCANCLK_FREQUENCY / + ((float)(ntseg1 + ntseg2 + 3) * (float)bt->bt_baud)) - 1); + + /* Save the value of the new bit timing register */ + + priv->nbtp = FDCAN_NBTP_NBRP(nbrp) | FDCAN_NBTP_NTSEG1(ntseg1) | + FDCAN_NBTP_NTSEG2(ntseg2) | FDCAN_NBTP_NSJW(nsjw); + + /* We need to reset to instantiate the new timing. Save + * current state information so that recover to this + * state. + */ + + ie = fdcan_getreg(priv, STM32_FDCAN_IE_OFFSET); + state = priv->state; + + /* Reset the FDCAN */ + + fdcan_reset(dev); + ret = OK; + + /* If we have previously been setup, then setup again */ + + if (state == FDCAN_STATE_SETUP) + { + ret = fdcan_setup(dev); + } + + /* We we have successfully re-initialized, then restore the + * interrupt state. + * + * REVISIT: Since the hardware was reset, any pending TX + * activity was lost. Should we disable TX interrupts? + */ + + if (ret == OK) + { + fdcan_putreg(priv, STM32_FDCAN_IE_OFFSET, ie & ~priv->txints); + } + } + break; + +#ifdef CONFIG_CAN_EXTID + /* CANIOC_ADD_EXTFILTER: + * Description: Add an address filter for a extended 29 bit + * address. + * Argument: A reference to struct canioc_extfilter_s + * Returned Value: A non-negative filter ID is returned on success. + * Otherwise -1 (ERROR) is returned with the errno + * variable set to indicate the nature of the error. + */ + + case CANIOC_ADD_EXTFILTER: + { + DEBUGASSERT(arg != 0); + + ret = fdcan_add_extfilter(priv, + (FAR struct canioc_extfilter_s *)arg); + } + break; + + /* CANIOC_DEL_EXTFILTER: + * Description: Remove an address filter for a standard 29 bit + * address. + * Argument: The filter index previously returned by the + * CANIOC_ADD_EXTFILTER command + * 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. + */ + + case CANIOC_DEL_EXTFILTER: + { + DEBUGASSERT(arg <= priv->config->nextfilters); + ret = fdcan_del_extfilter(priv, (int)arg); + } + break; +#endif + + /* CANIOC_ADD_STDFILTER: + * Description: Add an address filter for a standard 11 bit + * address. + * Argument: A reference to struct canioc_stdfilter_s + * Returned Value: A non-negative filter ID is returned on success. + * Otherwise -1 (ERROR) is returned with the errno + * variable set to indicate the nature of the error. + */ + + case CANIOC_ADD_STDFILTER: + { + DEBUGASSERT(arg != 0); + + ret = fdcan_add_stdfilter(priv, + (FAR struct canioc_stdfilter_s *)arg); + } + break; + + /* CANIOC_DEL_STDFILTER: + * Description: Remove an address filter for a standard 11 bit + * address. + * Argument: The filter index previously returned by the + * CANIOC_ADD_STDFILTER command + * 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. + */ + + case CANIOC_DEL_STDFILTER: + { + DEBUGASSERT(arg <= priv->config->nstdfilters); + ret = fdcan_del_stdfilter(priv, (int)arg); + } + break; + + /* CANIOC_BUSOFF_RECOVERY: + * Description : Initiates the BUS - OFF recovery sequence + * Argument : None + * 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_BUSOFF_RECOVERY: + { + ret = fdcan_start_busoff_recovery_sequence(priv); + } + break; + + /* Unsupported/unrecognized command */ + + default: + canerr("ERROR: Unrecognized command: %04x\n", cmd); + break; + } + + return ret; +} + +/**************************************************************************** + * Name: fdcan_remoterequest + * + * Description: + * Send a remote request + * + * 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 fdcan_remoterequest(FAR struct can_dev_s *dev, uint16_t id) +{ + /* REVISIT: Remote request not implemented */ + + return -ENOSYS; +} + +/**************************************************************************** + * Name: fdcan_send + * + * Description: + * Send one can message. + * + * One CAN-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 CAN identifier + * Byte 1: Bits 5-7: Bits 0-2 of the 11-bit CAN identifier + * Bit 4: Remote Transmission Request (RTR) + * Bits 0-3: Data Length Code (DLC) + * Bytes 2-10: CAN data + * + * 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 fdcan_send(FAR struct can_dev_s *dev, FAR struct can_msg_s *msg) +{ + FAR struct stm32_fdcan_s *priv = NULL; + FAR const struct stm32_config_s *config = NULL; + FAR uint32_t *txbuffer = NULL; + FAR const uint8_t *src = NULL; + FAR uint32_t *dest = NULL; + uint32_t regval = 0; + unsigned int ndx = 0; + unsigned int nbytes = 0; + uint32_t wordbuffer = 0; + unsigned int i = 0; + + DEBUGASSERT(dev); + priv = dev->cd_priv; + DEBUGASSERT(priv && priv->config); + config = priv->config; + + caninfo("CAN%" PRIu8 " ID: %" PRIu32 " DLC: %" PRIu8 "\n", + config->port, (uint32_t)msg->cm_hdr.ch_id, msg->cm_hdr.ch_dlc); + + fdcan_dumptxregs(priv, "Before send"); + + /* That that FIFO elements were configured */ + + DEBUGASSERT(config->ntxfifoq > 0); + + /* Get our reserved Tx FIFO/queue put index */ + + regval = fdcan_getreg(priv, STM32_FDCAN_TXFQS_OFFSET); + DEBUGASSERT((regval & FDCAN_TXFQS_TFQF) == 0); + + ndx = (regval & FDCAN_TXFQS_TFQPI_MASK) >> FDCAN_TXFQS_TFQPI_SHIFT; + + /* And the TX buffer corresponding to this index */ + + txbuffer = (config->msgram.txfifoq + ndx * config->txbufferesize); + + /* Format the TX FIFOQ entry + * + * Format word T0: + * Transfer message ID (ID) - Value from message structure + * Remote Transmission Request (RTR) - Value from message structure + * Extended Identifier (XTD) - Depends on configuration. + */ + +#ifdef CONFIG_CAN_EXTID + if (msg->cm_hdr.ch_extid) + { + DEBUGASSERT(msg->cm_hdr.ch_id <= CAN_MAX_EXTMSGID); + + regval = BUFFER_R0_EXTID(msg->cm_hdr.ch_id) | BUFFER_R0_XTD; + } + else +#endif + { + DEBUGASSERT(msg->cm_hdr.ch_id <= CAN_MAX_STDMSGID); + + regval = BUFFER_R0_STDID(msg->cm_hdr.ch_id); + } + + if (msg->cm_hdr.ch_rtr) + { + regval |= BUFFER_R0_RTR; + } + + txbuffer[0] = regval; + + /* Format word T1: + * Data Length Code (DLC) - Value from message structure + * Event FIFO Control (EFC) - Do not store events. + * Message Marker (MM) - Always zero + */ + + txbuffer[1] = BUFFER_R1_DLC(msg->cm_hdr.ch_dlc); + + /* Followed by the amount of data corresponding to the DLC (T2..) */ + + dest = &txbuffer[2]; + src = msg->cm_data; + nbytes = fdcan_dlc2bytes(priv, msg->cm_hdr.ch_dlc); + + /* Writes must be word length */ + + for (i = 0; i < nbytes; i += 4) + { + /* Little endian is assumed */ + + wordbuffer = src[0] | + (src[1] << 8) | + (src[2] << 16) | + (src[3] << 24); + src += 4; + + *dest++ = wordbuffer; + } + + /* Enable transmit interrupts from the TX FIFOQ buffer by setting TC + * interrupt bit in IR (also requires that the TC interrupt is enabled) + */ + + fdcan_putreg(priv, STM32_FDCAN_TXBTIE_OFFSET, (1 << ndx)); + + /* And request to send the packet */ + + fdcan_putreg(priv, STM32_FDCAN_TXBAR_OFFSET, (1 << ndx)); + + return OK; +} + +/**************************************************************************** + * Name: fdcan_txready + * + * Description: + * Return true if the FDCAN hardware can accept another TX message. + * + * Input Parameters: + * dev - An instance of the "upper half" can driver state structure. + * + * Returned Value: + * True if the FDCAN hardware is ready to accept another TX message. + * + ****************************************************************************/ + +static bool fdcan_txready(FAR struct can_dev_s *dev) +{ + FAR struct stm32_fdcan_s *priv = dev->cd_priv; + uint32_t regval = 0; + bool notfull = false; + + /* Return the state of the TX FIFOQ. Return TRUE if the TX FIFO/Queue is + * not full. + */ + + regval = fdcan_getreg(priv, STM32_FDCAN_TXFQS_OFFSET); + notfull = ((regval & FDCAN_TXFQS_TFQF) == 0); + + return notfull; +} + +/**************************************************************************** + * Name: fdcan_txempty + * + * Description: + * Return true if all message have been sent. If for example, the FDCAN + * 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 FDCAN hardware. + * + ****************************************************************************/ + +static bool fdcan_txempty(FAR struct can_dev_s *dev) +{ + FAR struct stm32_fdcan_s *priv = dev->cd_priv; + uint32_t regval = 0; + int tffl = 0; + bool empty = false; + + DEBUGASSERT(priv != NULL && priv->config != NULL); + + /* Return the state of the TX FIFOQ. Return TRUE if the TX FIFO/Queue is + * empty. We don't have a reliable indication that the FIFO is empty, so + * we have to use some heuristics. + */ + + regval = fdcan_getreg(priv, STM32_FDCAN_TXFQS_OFFSET); + if (((regval & FDCAN_TXFQS_TFQF) != 0)) + { + return false; + } + + /* Tx FIFO Free Level */ + + tffl = (regval & FDCAN_TXFQS_TFFL_MASK) >> FDCAN_TXFQS_TFFL_SHIFT; + empty = (tffl >= priv->config->ntxfifoq); + + return empty; +} + +/**************************************************************************** + * Name: fdcan_error + * + * Description: + * Report a CAN error + * + * Input Parameters: + * dev - CAN-common state data + * status - Interrupt status with error bits set + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef CONFIG_CAN_ERRORS +static void fdcan_error(FAR struct can_dev_s *dev, uint32_t status) +{ + FAR struct stm32_fdcan_s *priv = dev->cd_priv; + struct can_hdr_s hdr; + uint32_t psr = 0; + uint16_t errbits = 0; + uint8_t data[CAN_ERROR_DLC]; + int ret = 0; + + /* Encode error bits */ + + errbits = 0; + memset(data, 0, sizeof(data)); + + /* Always fill in "static" error conditions, but set the signaling bit + * only if the condition has changed (see IRQ-Flags below) + * They have to be filled in every time CAN_ERROR_CONTROLLER is set. + */ + + psr = fdcan_getreg(priv, STM32_FDCAN_PSR_OFFSET); + if ((psr & FDCAN_PSR_EP) != 0) + { + data[1] |= (CAN_ERROR1_RXPASSIVE | CAN_ERROR1_TXPASSIVE); + } + + if (psr & FDCAN_PSR_EW) + { + data[1] |= (CAN_ERROR1_RXWARNING | CAN_ERROR1_TXWARNING); + } + + if ((status & (FDCAN_INT_EP | FDCAN_INT_EW)) != 0) + { + /* "Error Passive" or "Error Warning" status changed */ + + errbits |= CAN_ERROR_CONTROLLER; + } + + if ((status & FDCAN_INT_PEA) != 0) + { + /* Protocol Error in Arbitration Phase */ + + if (psr & FDCAN_PSR_LEC_MASK) + { + /* Error code present */ + + if ((psr & FDCAN_PSR_LEC(FDCAN_PSR_EC_STUFF_ERROR)) != 0) + { + /* Stuff Error */ + + errbits |= CAN_ERROR_PROTOCOL; + data[2] |= CAN_ERROR2_STUFF; + } + + if ((psr & FDCAN_PSR_LEC(FDCAN_PSR_EC_FORM_ERROR)) != 0) + { + /* Format Error */ + + errbits |= CAN_ERROR_PROTOCOL; + data[2] |= CAN_ERROR2_FORM; + } + + if ((psr & FDCAN_PSR_LEC(FDCAN_PSR_EC_ACK_ERROR)) != 0) + { + /* Acknowledge Error */ + + errbits |= CAN_ERROR_NOACK; + } + + if ((psr & FDCAN_PSR_LEC(FDCAN_PSR_EC_BIT0_ERROR)) != 0) + { + /* Bit0 Error */ + + errbits |= CAN_ERROR_PROTOCOL; + data[2] |= CAN_ERROR2_BIT0; + } + + if ((psr & FDCAN_PSR_LEC(FDCAN_PSR_EC_BIT1_ERROR)) != 0) + { + /* Bit1 Error */ + + errbits |= CAN_ERROR_PROTOCOL; + data[2] |= CAN_ERROR2_BIT1; + } + + if ((psr & FDCAN_PSR_LEC(FDCAN_PSR_EC_CRC_ERROR)) != 0) + { + /* Receive CRC Error */ + + errbits |= CAN_ERROR_PROTOCOL; + data[3] |= (CAN_ERROR3_CRCSEQ | CAN_ERROR3_CRCDEL); + } + + if ((psr & FDCAN_PSR_LEC(FDCAN_PSR_EC_NO_CHANGE)) != 0) + { + /* No Change in Error */ + + errbits |= CAN_ERROR_PROTOCOL; + data[2] |= CAN_ERROR2_UNSPEC; + } + } + } + + if ((status & FDCAN_INT_PED) != 0) + { + /* Protocol Error in Data Phase */ + + if (psr & FDCAN_PSR_DLEC_MASK) + { + /* Error code present */ + + if ((psr & FDCAN_PSR_DLEC(FDCAN_PSR_EC_STUFF_ERROR)) != 0) + { + /* Stuff Error */ + + errbits |= CAN_ERROR_PROTOCOL; + data[2] |= CAN_ERROR2_STUFF; + } + + if ((psr & FDCAN_PSR_DLEC(FDCAN_PSR_EC_FORM_ERROR)) != 0) + { + /* Format Error */ + + errbits |= CAN_ERROR_PROTOCOL; + data[2] |= CAN_ERROR2_FORM; + } + + if ((psr & FDCAN_PSR_DLEC(FDCAN_PSR_EC_ACK_ERROR)) != 0) + { + /* Acknowledge Error */ + + errbits |= CAN_ERROR_NOACK; + } + + if ((psr & FDCAN_PSR_DLEC(FDCAN_PSR_EC_BIT0_ERROR)) != 0) + { + /* Bit0 Error */ + + errbits |= CAN_ERROR_PROTOCOL; + data[2] |= CAN_ERROR2_BIT0; + } + + if ((psr & FDCAN_PSR_DLEC(FDCAN_PSR_EC_BIT1_ERROR)) != 0) + { + /* Bit1 Error */ + + errbits |= CAN_ERROR_PROTOCOL; + data[2] |= CAN_ERROR2_BIT1; + } + + if ((psr & FDCAN_PSR_DLEC(FDCAN_PSR_EC_CRC_ERROR)) != 0) + { + /* Receive CRC Error */ + + errbits |= CAN_ERROR_PROTOCOL; + data[3] |= (CAN_ERROR3_CRCSEQ | CAN_ERROR3_CRCDEL); + } + + if ((psr & FDCAN_PSR_DLEC(FDCAN_PSR_EC_NO_CHANGE)) != 0) + { + /* No Change in Error */ + + errbits |= CAN_ERROR_PROTOCOL; + data[2] |= CAN_ERROR2_UNSPEC; + } + } + } + + if ((status & FDCAN_INT_BO) != 0) + { + /* Bus_Off Status changed */ + + if ((psr & FDCAN_PSR_BO) != 0) + { + errbits |= CAN_ERROR_BUSOFF; + } + else + { + errbits |= CAN_ERROR_RESTARTED; + } + } + + if ((status & (FDCAN_INT_RF0L | FDCAN_INT_RF1L)) != 0) + { + /* Receive FIFO 0/1 Message Lost + * Receive FIFO 1 Message Lost + */ + + errbits |= CAN_ERROR_CONTROLLER; + data[1] |= CAN_ERROR1_RXOVERFLOW; + } + + if ((status & FDCAN_INT_TEFL) != 0) + { + /* Tx Event FIFO Element Lost */ + + errbits |= CAN_ERROR_CONTROLLER; + data[1] |= CAN_ERROR1_TXOVERFLOW; + } + + if ((status & FDCAN_INT_TOO) != 0) + { + /* Timeout Occurred */ + + errbits |= CAN_ERROR_TXTIMEOUT; + } + + if ((status & (FDCAN_INT_MRAF | FDCAN_INT_ELO)) != 0) + { + /* Message RAM Access Failure + * Error Logging Overflow + */ + + errbits |= CAN_ERROR_CONTROLLER; + data[1] |= CAN_ERROR1_UNSPEC; + } + + if (errbits != 0) + { + /* Format the CAN header for the error report. */ + + hdr.ch_id = errbits; + hdr.ch_dlc = CAN_ERROR_DLC; + hdr.ch_rtr = 0; + hdr.ch_error = 1; +#ifdef CONFIG_CAN_EXTID + hdr.ch_extid = 0; +#endif + hdr.ch_unused = 0; + + /* And provide the error report to the upper half logic */ + + ret = can_receive(dev, &hdr, data); + if (ret < 0) + { + canerr("ERROR: can_receive failed: %d\n", ret); + } + } +} +#endif /* CONFIG_CAN_ERRORS */ + +/**************************************************************************** + * Name: fdcan_receive + * + * Description: + * Receive an FDCAN messages + * + * Input Parameters: + * dev - CAN-common state data + * rxbuffer - The RX buffer containing the received messages + * nwords - The length of the RX buffer (element size in words). + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void fdcan_receive(FAR struct can_dev_s *dev, FAR uint32_t *rxbuffer, + unsigned long nwords) +{ + struct can_hdr_s hdr; + uint32_t regval = 0; + int ret = 0; + + fdcan_dumprxregs(dev->cd_priv, "Before receive"); + + /* Format the CAN header */ + + /* Work R0 contains the CAN ID */ + + regval = *rxbuffer++; + +#ifdef CONFIG_CAN_ERRORS + hdr.ch_error = 0; +#endif + hdr.ch_unused = 0; + + if ((regval & BUFFER_R0_RTR) != 0) + { + hdr.ch_rtr = true; + } + else + { + hdr.ch_rtr = false; + } + +#ifdef CONFIG_CAN_EXTID + if ((regval & BUFFER_R0_XTD) != 0) + { + /* Save the extended ID of the newly received message */ + + hdr.ch_id = (regval & BUFFER_R0_EXTID_MASK) >> + BUFFER_R0_EXTID_SHIFT; + hdr.ch_extid = true; + } + else + { + hdr.ch_id = (regval & BUFFER_R0_STDID_MASK) >> + BUFFER_R0_STDID_SHIFT; + hdr.ch_extid = false; + } + +#else + if ((regval & BUFFER_R0_XTD) != 0) + { + /* Drop any messages with extended IDs */ + + return; + } + + /* Save the standard ID of the newly received message */ + + hdr.ch_id = (regval & BUFFER_R0_STDID_MASK) >> BUFFER_R0_STDID_SHIFT; +#endif + + /* Word R1 contains the DLC and timestamp */ + + regval = *rxbuffer++; + + hdr.ch_dlc = (regval & BUFFER_R1_DLC_MASK) >> BUFFER_R1_DLC_SHIFT; + + /* And provide the CAN message to the upper half logic */ + + ret = can_receive(dev, &hdr, (FAR uint8_t *)rxbuffer); + if (ret < 0) + { + canerr("ERROR: can_receive failed: %d\n", ret); + } +} + +/**************************************************************************** + * Name: fdcan_interrupt + * + * Description: + * Common FDCAN interrupt handler + * + * Input Parameters: + * dev - CAN-common state data + * + * Returned Value: + * None + * + ****************************************************************************/ + +static int fdcan_interrupt(int irq, void *context, FAR void *arg) +{ + FAR struct can_dev_s *dev = (FAR struct can_dev_s *)arg; + FAR struct stm32_fdcan_s *priv = NULL; + FAR const struct stm32_config_s *config = NULL; + uint32_t ir = 0; + uint32_t ie = 0; + uint32_t pending = 0; + uint32_t regval = 0; + uint32_t psr = 0; + unsigned int nelem = 0; + unsigned int ndx = 0; + + DEBUGASSERT(dev != NULL); + priv = dev->cd_priv; + DEBUGASSERT(priv && priv->config); + config = priv->config; + + /* Get the set of pending interrupts. */ + + ir = fdcan_getreg(priv, STM32_FDCAN_IR_OFFSET); + ie = fdcan_getreg(priv, STM32_FDCAN_IE_OFFSET); + + pending = (ir & ie); + + /* Check for any errors */ + + if ((pending & FDCAN_ANYERR_INTS) != 0) + { + /* Check for common errors */ + + if ((pending & FDCAN_CMNERR_INTS) != 0) + { + canerr("ERROR: Common %08" PRIx32 "\n", + pending & FDCAN_CMNERR_INTS); + + /* When a protocol error ocurrs, the problem is recorded in + * the LEC/DLEC fields of the PSR register. In lieu of + * seprate interrupt flags for each error, the hardware + * groups procotol errors under a single interrupt each for + * arbitration and data phases. + * + * These errors have a tendency to flood the system with + * interrupts, so they are disabled here until we get a + * successful transfer/receive on the hardware + */ + + psr = fdcan_getreg(priv, STM32_FDCAN_PSR_OFFSET); + + if ((psr & FDCAN_PSR_LEC_MASK) != 0) + { + canerr("ERROR: PSR %08" PRIx32 "\n", psr); + ie &= ~(FDCAN_INT_PEA | FDCAN_INT_PED); + fdcan_putreg(priv, STM32_FDCAN_IE_OFFSET, ie); + caninfo("disabled protocol error intterupts\n"); + } + + /* Clear the error indications */ + + fdcan_putreg(priv, STM32_FDCAN_IR_OFFSET, FDCAN_CMNERR_INTS); + } + + /* Check for transmission errors */ + + if ((pending & FDCAN_TXERR_INTS) != 0) + { + canerr("ERROR: TX %08" PRIx32 "\n", + pending & FDCAN_TXERR_INTS); + + /* An Acknowledge-Error will occur if for example the device + * is not connected to the bus. + * + * The CAN-Standard states that the Chip has to retry the + * message forever, which will produce an ACKE every time. + * To prevent this Interrupt-Flooding and the high CPU-Load + * we disable the ACKE here as long we didn't transfer at + * least one message successfully (see FDCAN_INT_TC below). + */ + + /* Clear the error indications */ + + fdcan_putreg(priv, STM32_FDCAN_IR_OFFSET, FDCAN_TXERR_INTS); + } + + /* Check for reception errors */ + + if ((pending & FDCAN_RXERR_INTS) != 0) + { + canerr("ERROR: RX %08" PRIx32 "\n", + pending & FDCAN_RXERR_INTS); + + /* To prevent Interrupt-Flooding the current active + * RX error interrupts are disabled. After successfully + * receiving at least one CAN packet all RX error interrupts + * are turned back on. + * + * The Interrupt-Flooding can for example occur if the + * configured CAN speed does not match the speed of the other + * CAN nodes in the network. + */ + + ie &= ~(pending & FDCAN_RXERR_INTS); + fdcan_putreg(priv, STM32_FDCAN_IE_OFFSET, ie); + + /* Clear the error indications */ + + fdcan_putreg(priv, STM32_FDCAN_IR_OFFSET, FDCAN_RXERR_INTS); + } + +#ifdef CONFIG_CAN_ERRORS + /* Report errors */ + + fdcan_error(dev, pending & FDCAN_ANYERR_INTS); +#endif + } + + /* Check for successful completion of a transmission */ + + if ((pending & FDCAN_INT_TC) != 0) + { + /* Check if we have disabled the ACKE in the error-handling above + * (see FDCAN_TXERR_INTS) to prevent Interrupt-Flooding and + * re-enable the error interrupt here again. + */ + + if ((ie & (FDCAN_INT_PEA | FDCAN_INT_PED)) == 0) + { + ie |= (FDCAN_INT_PEA | FDCAN_INT_PED); + fdcan_putreg(priv, STM32_FDCAN_IE_OFFSET, ie); + caninfo("Renabled protocol error intterupts\n"); + } + + /* Clear the pending TX completion interrupt (and all + * other TX-related interrupts) + */ + + fdcan_putreg(priv, STM32_FDCAN_IR_OFFSET, priv->txints); + + /* Check all TX buffers */ + + regval = fdcan_getreg(priv, STM32_FDCAN_TXBTO_OFFSET); + for (ndx = 0; ndx < config->ntxfifoq; ndx += 1) + { + if (regval & (1 << ndx)) + { + /* Tell the upper half that the transfer is finished. */ + + can_txdone(dev); + } + } + } + else if ((pending & priv->txints) != 0) + { + /* Clear unhandled TX events */ + + fdcan_putreg(priv, STM32_FDCAN_IR_OFFSET, priv->txints); + } + + /* Clear the RX FIFO1 new message interrupt */ + + fdcan_putreg(priv, STM32_FDCAN_IR_OFFSET, FDCAN_INT_RF1N); + pending &= ~FDCAN_INT_RF1N; + + /* We treat RX FIFO1 as the "high priority" queue: We will process + * all messages in RX FIFO1 before processing any message from RX + * FIFO0. + */ + + for (; ; ) + { + /* Check if there is anything in RX FIFO1 */ + + regval = fdcan_getreg(priv, STM32_FDCAN_RXF1S_OFFSET); + nelem = (regval & FDCAN_RXFS_FFL_MASK) >> FDCAN_RXFS_FFL_SHIFT; + if (nelem == 0) + { + /* Break out of the loop if RX FIFO1 is empty */ + + break; + } + + /* Clear the RX FIFO1 interrupt (and all other FIFO1-related + * interrupts) + */ + + /* Handle the newly received message in FIFO1 */ + + ndx = (regval & FDCAN_RXFS_FGI_MASK) >> FDCAN_RXFS_FGI_SHIFT; + + if ((regval & FDCAN_RXFS_RFL) != 0) + { + canerr("ERROR: Message lost: %08" PRIx32 "\n", regval); + } + else + { + fdcan_receive(dev, + config->msgram.rxfifo1 + + (ndx * priv->config->rxfifo1esize), + priv->config->rxfifo1esize); + + /* Turning back on all configured RX error interrupts */ + + ie |= (priv->rxints & FDCAN_RXERR_INTS); + fdcan_putreg(priv, STM32_FDCAN_IE_OFFSET, ie); + } + + /* Acknowledge reading the FIFO entry */ + + fdcan_putreg(priv, STM32_FDCAN_RXF1A_OFFSET, ndx); + } + + /* Check for successful reception of a new message in RX FIFO0 */ + + /* Clear the RX FIFO0 new message interrupt */ + + fdcan_putreg(priv, STM32_FDCAN_IR_OFFSET, FDCAN_INT_RF0N); + pending &= ~FDCAN_INT_RF0N; + + /* Check if there is anything in RX FIFO0 */ + + regval = fdcan_getreg(priv, STM32_FDCAN_RXF0S_OFFSET); + nelem = (regval & FDCAN_RXFS_FFL_MASK) >> FDCAN_RXFS_FFL_SHIFT; + if (nelem > 0) + { + /* Handle the newly received message in FIFO0 */ + + ndx = (regval & FDCAN_RXFS_FGI_MASK) >> FDCAN_RXFS_FGI_SHIFT; + + if ((regval & FDCAN_RXFS_RFL) != 0) + { + canerr("ERROR: Message lost: %08" PRIx32 "\n", regval); + } + else + { + fdcan_receive(dev, + config->msgram.rxfifo0 + + (ndx * priv->config->rxfifo0esize), + priv->config->rxfifo0esize); + + /* Turning back on all configured RX error interrupts */ + + ie |= (priv->rxints & FDCAN_RXERR_INTS); + fdcan_putreg(priv, STM32_FDCAN_IE_OFFSET, ie); + } + + /* Acknowledge reading the FIFO entry */ + + fdcan_putreg(priv, STM32_FDCAN_RXF0A_OFFSET, ndx); + } + + /* Clear unhandled RX interrupts */ + + if ((pending & priv->rxints) != 0) + { + fdcan_putreg(priv, STM32_FDCAN_IR_OFFSET, priv->rxints); + } + + return OK; +} + +/**************************************************************************** + * Name: fdcan_hw_initialize + * + * Description: + * FDCAN hardware initialization + * + * Input Parameters: + * priv - A pointer to the private data structure for this FDCAN peripheral + * + * Returned Value: + * Zero on success; a negated errno value on failure. + * + ****************************************************************************/ + +static int fdcan_hw_initialize(struct stm32_fdcan_s *priv) +{ + FAR const struct stm32_config_s *config = priv->config; + FAR uint32_t *msgram = NULL; + uint32_t regval = 0; + uint32_t cntr = 0; + + caninfo("FDCAN%d\n", config->port); + + /* Clean message RAM */ + + msgram = config->msgram.stdfilters; + cntr = (FDCAN_MSGRAM_WORDS + 1); + while (cntr > 0) + { + *msgram++ = 0; + cntr--; + } + + /* Configure FDCAN pins */ + + stm32_configgpio(config->rxpinset); + stm32_configgpio(config->txpinset); + + /* Renable device if previosuly disabled in fdcan_shutdown() */ + + if (priv->state == FDCAN_STATE_DISABLED) + { + /* Reset Clock Stop Request bit */ + + regval = fdcan_getreg(priv, STM32_FDCAN_CCCR_OFFSET); + regval &= ~FDCAN_CCCR_CSR; + fdcan_putreg(priv, STM32_FDCAN_CCCR_OFFSET, regval); + + /* Wait for Clock Stop Acknowledge bit reset to indicate + * device is operational + */ + + while ((fdcan_getreg(priv, STM32_FDCAN_CCCR_OFFSET) & FDCAN_CCCR_CSA) + != 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_CCE; + fdcan_putreg(priv, STM32_FDCAN_CCCR_OFFSET, regval); + + /* Global Filter Configuration: + * + * ANFS=0: Store all non matching standard frame in RX FIFO0 + * ANFE=0: Store all non matching extended frame in RX FIFO0 + */ + + regval = FDCAN_RXGFC_ANFE_RX_FIFO0 | FDCAN_RXGFC_ANFS_RX_FIFO0; + fdcan_putreg(priv, STM32_FDCAN_RXGFC_OFFSET, regval); + + /* Extended ID Filter AND mask */ + + fdcan_putreg(priv, STM32_FDCAN_XIDAM_OFFSET, 0x1fffffff); + + /* Disable all interrupts */ + + fdcan_putreg(priv, STM32_FDCAN_IE_OFFSET, 0); + fdcan_putreg(priv, STM32_FDCAN_TXBTIE_OFFSET, 0); + + /* All interrupts directed to Line 0. But disable both interrupt lines 0 + * and 1 for now. + * + * REVISIT: Only interrupt line 0 is used by this driver. + */ + + fdcan_putreg(priv, STM32_FDCAN_ILS_OFFSET, 0); + fdcan_putreg(priv, STM32_FDCAN_ILE_OFFSET, 0); + + /* Clear all pending interrupts. */ + + fdcan_putreg(priv, STM32_FDCAN_IR_OFFSET, FDCAN_INT_ALL); + + /* Configure FDCAN bit timing */ + + fdcan_putreg(priv, STM32_FDCAN_NBTP_OFFSET, priv->nbtp); + fdcan_putreg(priv, STM32_FDCAN_DBTP_OFFSET, priv->dbtp); + + /* Configure message RAM starting addresses and sizes. */ + + regval = FDCAN_RXGFC_LSS(config->nstdfilters); + regval |= FDCAN_RXGFC_LSE(config->nextfilters); + fdcan_putreg(priv, STM32_FDCAN_RXGFC_OFFSET, regval); + + /* Dump RAM layout */ + + fdcan_dumpramlayout(priv); + + /* Configure Message Filters */ + + /* Disable all standard filters */ + + msgram = config->msgram.stdfilters; + cntr = config->nstdfilters; + while (cntr > 0) + { + *msgram++ = STDFILTER_S0_SFEC_DISABLE; + cntr--; + } + + /* Disable all extended filters */ + + msgram = config->msgram.extfilters; + cntr = config->nextfilters; + while (cntr > 0) + { + *msgram = EXTFILTER_F0_EFEC_DISABLE; + msgram = msgram + 2; + cntr--; + } + + /* Input clock divider configuration */ + + regval = FDCANCLK_PDIV; + fdcan_putreg(priv, STM32_FDCAN_CKDIV_OFFSET, regval); + + /* CC control register */ + + regval = fdcan_getreg(priv, STM32_FDCAN_CCCR_OFFSET); + regval &= ~(FDCAN_CCCR_NISO | FDCAN_CCCR_FDOE | FDCAN_CCCR_BRSE); + + /* Select ISO11898-1 or Non ISO Bosch CAN FD Specification V1.0 */ + + switch (config->format) + { + default: + case FDCAN_ISO11898_1_FORMAT: + break; + + case FDCAN_NONISO_BOSCH_V1_FORMAT: + regval |= FDCAN_CCCR_NISO; + break; + } + + /* Select Classic CAN mode or FD mode with or without fast bit rate + * switching + */ + + switch (config->mode) + { + default: + case FDCAN_CLASSIC_MODE: + break; + +#ifdef CONFIG_CAN_FD + case FDCAN_FD_MODE: + regval |= FDCAN_CCCR_FDOE; + break; + + case FDCAN_FD_BRS_MODE: + regval |= (FDCAN_CCCR_FDOE | FDCAN_CCCR_BRSE); + break; +#endif + } + + /* Set the initial CAN mode */ + + fdcan_putreg(priv, STM32_FDCAN_CCCR_OFFSET, regval); + + /* Enable FIFO/Queue mode */ + + regval = fdcan_getreg(priv, STM32_FDCAN_TXBC_OFFSET); +#ifdef CONFIG_STM32_FDCAN_QUEUE_MODE + regval |= FDCAN_TXBC_TFQM; +#else + regval &= ~FDCAN_TXBC_TFQM; +#endif + fdcan_putreg(priv, STM32_FDCAN_TXBC_OFFSET, regval); + +#ifdef STM32_FDCAN_LOOPBACK + /* Is loopback mode selected for this peripheral? */ + + if (config->loopback) + { + /* FDCAN_CCCR_TEST - Test mode enable + * FDCAN_CCCR_MON - Bus monitoring mode (for internal loopback) + * FDCAN_TEST_LBCK - Loopback mode + */ + + regval = fdcan_getreg(priv, STM32_FDCAN_CCCR_OFFSET); + regval |= (FDCAN_CCCR_TEST | FDCAN_CCCR_MON); + fdcan_putreg(priv, STM32_FDCAN_CCCR_OFFSET, regval); + + regval = fdcan_getreg(priv, STM32_FDCAN_TEST_OFFSET); + regval |= FDCAN_TEST_LBCK; + fdcan_putreg(priv, STM32_FDCAN_TEST_OFFSET, regval); + } +#endif + + /* Configure interrupt lines */ + + /* Select RX-related interrupts */ + + priv->rxints = FDCAN_RXFIFO_INTS; + + /* Select TX-related interrupts */ + + priv->txints = FDCAN_TXFIFOQ_INTS; + + /* Direct all interrupts to Line 0. + * + * Bits in the ILS register correspond to each FDCAN interrupt; A bit + * set to '1' is directed to interrupt line 1; a bit cleared to '0' + * is directed interrupt line 0. + * + * REVISIT: Nothing is done here. Only interrupt line 0 is used by + * this driver and ILS was already cleared above. + */ + + /* Enable only interrupt line 0. */ + + fdcan_putreg(priv, STM32_FDCAN_ILE_OFFSET, FDCAN_ILE_EINT0); + + /* Disable initialization mode to enable normal operation */ + + regval = fdcan_getreg(priv, STM32_FDCAN_CCCR_OFFSET); + regval &= ~FDCAN_CCCR_INIT; + fdcan_putreg(priv, STM32_FDCAN_CCCR_OFFSET, regval); + + return OK; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: stm32_fdcaninitialize + * + * Description: + * Initialize the selected FDCAN port + * + * Input Parameters: + * port - Port number (for hardware that has multiple FDCAN interfaces), + * 1=FDCAN1, 2=FDCAN2, 3=FDCAN3 + * + * Returned Value: + * Valid CAN device structure reference on success; a NULL on failure + * + ****************************************************************************/ + +FAR struct can_dev_s *stm32_fdcaninitialize(int port) +{ + FAR struct can_dev_s *dev = NULL; + FAR struct stm32_fdcan_s *priv = NULL; + FAR const struct stm32_config_s *config = NULL; + + caninfo("FDCAN%d\n", port); + + /* Select FDCAN peripheral to be initialized */ + +#ifdef CONFIG_STM32_FDCAN1 + if (port == FDCAN1) + { + /* Select the FDCAN1 device structure */ + + dev = &g_fdcan1dev; + priv = &g_fdcan1priv; + config = &g_fdcan1const; + } + else +#endif +#ifdef CONFIG_STM32_FDCAN2 + if (port == FDCAN2) + { + /* Select the FDCAN2 device structure */ + + dev = &g_fdcan2dev; + priv = &g_fdcan2priv; + config = &g_fdcan2const; + } + else +#endif +#ifdef CONFIG_STM32_FDCAN3 + if (port == FDCAN3) + { + /* Select the FDCAN3 device structure */ + + dev = &g_fdcan3dev; + priv = &g_fdcan3priv; + config = &g_fdcan3const; + } + else +#endif + { + canerr("ERROR: Unsupported port %d\n", port); + return NULL; + } + + /* Perform one time data initialization */ + + memset(priv, 0, sizeof(struct stm32_fdcan_s)); + priv->config = config; + + /* Set the initial bit timing. This might change subsequently + * due to IOCTL command processing. + */ + + priv->nbtp = config->nbtp; + priv->dbtp = config->dbtp; + + dev->cd_ops = &g_fdcanops; + dev->cd_priv = (FAR void *)priv; + + /* And put the hardware in the initial state */ + + fdcan_reset(dev); + + return dev; +} diff --git a/arch/arm/src/stm32/stm32_fdcan.h b/arch/arm/src/stm32/stm32_fdcan.h new file mode 100644 index 00000000000..34d2794f746 --- /dev/null +++ b/arch/arm/src/stm32/stm32_fdcan.h @@ -0,0 +1,90 @@ +/**************************************************************************** + * arch/arm/src/stm32/stm32_fdcan.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_ARM_SRC_STM32_STM32_FDCAN_H +#define __ARCH_ARM_SRC_STM32_STM32_FDCAN_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include "chip.h" +#include "hardware/stm32_fdcan.h" + +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Port numbers for use with stm32_fdcan_initialize() */ + +#define FDCAN1 1 +#define FDCAN2 2 +#define FDCAN3 3 + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: stm32_fdcaninitialize + * + * Description: + * Initialize the selected FDCAN port + * + * Input Parameters: + * Port number (for hardware that has multiple FDCAN interfaces) + * + * Returned Value: + * Valid FDCAN device structure reference on success; a NULL on failure + * + ****************************************************************************/ + +FAR struct can_dev_s *stm32_fdcaninitialize(int port); + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +#endif /* __ASSEMBLY__ */ +#endif /* __ARCH_ARM_SRC_STM32_STM32_FDCAN_H */ diff --git a/arch/arm/src/stm32/stm32g4xxxx_rcc.c b/arch/arm/src/stm32/stm32g4xxxx_rcc.c index 7d5878b1e02..c2307427686 100644 --- a/arch/arm/src/stm32/stm32g4xxxx_rcc.c +++ b/arch/arm/src/stm32/stm32g4xxxx_rcc.c @@ -952,6 +952,15 @@ static void stm32_stdclockconfig(void) regval &= ~(RCC_CFGR_PPRE1_MASK | RCC_CFGR_PPRE2_MASK); regval |= (STM32_RCC_CFGR_PPRE1 | STM32_RCC_CFGR_PPRE2); putreg32(regval, STM32_RCC_CFGR); + + /* Configure FDCAN source clock */ + +#if defined(STM32_CCIPR_FDCANSRC) + regval = getreg32(STM32_RCC_CCIPR); + regval &= ~RCC_CCIPR_FDCANSEL_MASK; + regval |= STM32_CCIPR_FDCANSRC; + putreg32(regval, STM32_RCC_CCIPR); +#endif } /**************************************************************************** From a406270fa5440fd08deb39eb4b824b9aed3b4417 Mon Sep 17 00:00:00 2001 From: raiden00pl Date: Sat, 15 Jan 2022 12:20:43 +0100 Subject: [PATCH 24/43] [BACKPORT] arch/stm32: fdcan cosmetics --- arch/arm/src/stm32/hardware/stm32_fdcan.h | 80 +++--- arch/arm/src/stm32/stm32_fdcan.c | 317 ++++++++++++---------- 2 files changed, 208 insertions(+), 189 deletions(-) diff --git a/arch/arm/src/stm32/hardware/stm32_fdcan.h b/arch/arm/src/stm32/hardware/stm32_fdcan.h index d135ab3137e..ad417a50fea 100644 --- a/arch/arm/src/stm32/hardware/stm32_fdcan.h +++ b/arch/arm/src/stm32/hardware/stm32_fdcan.h @@ -326,14 +326,14 @@ # define FDCAN_RXGFC_ANFS_REJECTED (2 << FDCAN_RXGFC_ANFS_SHIFT) /* 10: Reject */ #define FDCAN_RXGFC_F1OM (1 << 8) /* Bit 8: FIFO 1 operation mode */ #define FDCAN_RXGFC_F0OM (1 << 9) /* Bit 9: FIFO 0 operation mode */ -#define FDCAN_RXGFC_LSS_SHIFT (16) /* Bits 16-20: List size std */ -#define FDCAN_RXGFC_LSS_MASK (0x1f << FDCAN_RXGFC_LSS_SHIFT) -# define FDCAN_RXGFC_LSS(value) ((value) << FDCAN_RXGFC_LSS_SHIFT) -# define FDCAN_RXGFC_LSS_MAX (28) -#define FDCAN_RXGFC_LSE_SHIFT (24) /* Bits 24-27: List size ext */ -#define FDCAN_RXGFC_LSE_MASK (0x1f << FDCAN_RXGFC_LSE_SHIFT) -# define FDCAN_RXGFC_LSE(value) ((value) << FDCAN_RXGFC_LSE_SHIFT) -# define FDCAN_RXGFC_LSE_MAX (8) +#define FDCAN_RXGFC_LSS_SHIFT (16) /* Bits 16-20: List size std */ +#define FDCAN_RXGFC_LSS_MASK (0x1f << FDCAN_RXGFC_LSS_SHIFT) +# define FDCAN_RXGFC_LSS(value) ((value) << FDCAN_RXGFC_LSS_SHIFT) +# define FDCAN_RXGFC_LSS_MAX (28) +#define FDCAN_RXGFC_LSE_SHIFT (24) /* Bits 24-27: List size ext */ +#define FDCAN_RXGFC_LSE_MASK (0x1f << FDCAN_RXGFC_LSE_SHIFT) +# define FDCAN_RXGFC_LSE(value) ((value) << FDCAN_RXGFC_LSE_SHIFT) +# define FDCAN_RXGFC_LSE_MAX (8) /* FDCAN extended ID and mask register */ @@ -550,37 +550,37 @@ /* Extended Message ID Filter Element */ -#define EXTFILTER_F0_EFID1_SHIFT (0) /* Bits 0-28: Extended Filter ID 1 */ -#define EXTFILTER_F0_EFID1_MASK (0x1fffffff << EXTFILTER_F0_EFID1_SHIFT) -# define EXTFILTER_F0_EFID1(n) ((uint32_t)(n) << EXTFILTER_F0_EFID1_SHIFT) -#define EXTFILTER_F0_EFEC_SHIFT (29) /* Bits 29-31: Extended Filter Element Configuration */ -#define EXTFILTER_F0_EFEC_MASK (7 << EXTFILTER_F0_EFEC_SHIFT) -# define EXTFILTER_F0_EFEC_DISABLE (0 << EXTFILTER_F0_EFEC_SHIFT) /* Disable filter element */ -# define EXTFILTER_F0_EFEC_FIFO0 (1 << EXTFILTER_F0_EFEC_SHIFT) /* Store in Rx FIFO 0 on match */ -# define EXTFILTER_F0_EFEC_FIFO1 (2 << EXTFILTER_F0_EFEC_SHIFT) /* Store in Rx FIFO 1 on match */ -# define EXTFILTER_F0_EFEC_REJECT (3 << EXTFILTER_F0_EFEC_SHIFT) /* Reject ID on match */ -# define EXTFILTER_F0_EFEC_PRIORITY (4 << EXTFILTER_F0_EFEC_SHIFT) /* Set priority on match */ -# define EXTFILTER_F0_EFEC_PRIOFIFO0 (5 << EXTFILTER_F0_EFEC_SHIFT) /* Set priority and store in FIFO 0 on match */ -# define EXTFILTER_F0_EFEC_PRIOFIFO1 (6 << EXTFILTER_F0_EFEC_SHIFT) /* Set priority and store in FIFO 1 on match */ -# define EXTFILTER_F0_EFEC_BUFFER (7 << EXTFILTER_F0_EFEC_SHIFT) /* Store into Rx Buffer or as debug message */ - -#define EXTFILTER_F1_EFID2_SHIFT (0) /* Bits 0-28: Extended Filter ID 2 */ -#define EXTFILTER_F1_EFID2_MASK (0x1fffffff << EXTFILTER_F1_EFID2_SHIFT) -# define EXTFILTER_F1_EFID2(n) ((uint32_t)(n) << EXTFILTER_F1_EFID2_SHIFT) -#define EXTFILTER_F1_BUFFER_SHIFT (0) /* Bits 0-5: RX buffer start address */ -#define EXTFILTER_F1_BUFFER_MASK (63 << EXTFILTER_F1_BUFFER_SHIFT) -# define EXTFILTER_F1_BUFFER(n) ((uint32_t)(n) << EXTFILTER_F1_BUFFER_SHIFT) -#define EXTFILTER_F1_ACTION_SHIFT (9) /* Bits 9-10: Action taken */ -#define EXTFILTER_F1_ACTION_MASK (3 << EXTFILTER_F1_ACTION_SHIFT) -# define EXTFILTER_F1_RXBUFFER (0 << EXTFILTER_F1_ACTION_SHIFT) /* Store message in a Rx buffer */ -# define EXTFILTER_F1_DEBUGA (1 << EXTFILTER_F1_ACTION_SHIFT) /* Debug Message A */ -# define EXTFILTER_F1_DEBUGB (2 << EXTFILTER_F1_ACTION_SHIFT) /* Debug Message B */ -# define EXTFILTER_F1_DEBUGC (3 << EXTFILTER_F1_ACTION_SHIFT) /* Debug Message C */ -#define EXTFILTER_F1_EFT_SHIFT (30) /* Bits 30-31: Extended Filter Type */ -#define EXTFILTER_F1_EFT_MASK (3 << EXTFILTER_F1_EFT_SHIFT) -# define EXTFILTER_F1_EFT_RANGE (0 << EXTFILTER_F1_EFT_SHIFT) /* Range filter from SF1ID to SF2ID */ -# define EXTFILTER_F1_EFT_DUAL (1 << EXTFILTER_F1_EFT_SHIFT) /* Dual ID filter for SF1ID or SF2ID */ -# define EXTFILTER_F1_EFT_CLASSIC (2 << EXTFILTER_F1_EFT_SHIFT) /* Classic filter: SF1ID=filter SF2ID=mask */ -# define EXTFILTER_F1_EFT_NOXIDAM (3 << EXTFILTER_F1_EFT_SHIFT) /* Range filter from EF1ID to EF2ID, no XIDAM */ +#define EXTFILTER_F0_EFID1_SHIFT (0) /* Bits 0-28: Extended Filter ID 1 */ +#define EXTFILTER_F0_EFID1_MASK (0x1fffffff << EXTFILTER_F0_EFID1_SHIFT) +# define EXTFILTER_F0_EFID1(n) ((uint32_t)(n) << EXTFILTER_F0_EFID1_SHIFT) +#define EXTFILTER_F0_EFEC_SHIFT (29) /* Bits 29-31: Extended Filter Element Configuration */ +#define EXTFILTER_F0_EFEC_MASK (7 << EXTFILTER_F0_EFEC_SHIFT) +# define EXTFILTER_F0_EFEC_DISABLE (0 << EXTFILTER_F0_EFEC_SHIFT) /* Disable filter element */ +# define EXTFILTER_F0_EFEC_FIFO0 (1 << EXTFILTER_F0_EFEC_SHIFT) /* Store in Rx FIFO 0 on match */ +# define EXTFILTER_F0_EFEC_FIFO1 (2 << EXTFILTER_F0_EFEC_SHIFT) /* Store in Rx FIFO 1 on match */ +# define EXTFILTER_F0_EFEC_REJECT (3 << EXTFILTER_F0_EFEC_SHIFT) /* Reject ID on match */ +# define EXTFILTER_F0_EFEC_PRIORITY (4 << EXTFILTER_F0_EFEC_SHIFT) /* Set priority on match */ +# define EXTFILTER_F0_EFEC_PRIOFIFO0 (5 << EXTFILTER_F0_EFEC_SHIFT) /* Set priority and store in FIFO 0 on match */ +# define EXTFILTER_F0_EFEC_PRIOFIFO1 (6 << EXTFILTER_F0_EFEC_SHIFT) /* Set priority and store in FIFO 1 on match */ +# define EXTFILTER_F0_EFEC_BUFFER (7 << EXTFILTER_F0_EFEC_SHIFT) /* Store into Rx Buffer or as debug message */ + +#define EXTFILTER_F1_EFID2_SHIFT (0) /* Bits 0-28: Extended Filter ID 2 */ +#define EXTFILTER_F1_EFID2_MASK (0x1fffffff << EXTFILTER_F1_EFID2_SHIFT) +# define EXTFILTER_F1_EFID2(n) ((uint32_t)(n) << EXTFILTER_F1_EFID2_SHIFT) +#define EXTFILTER_F1_BUFFER_SHIFT (0) /* Bits 0-5: RX buffer start address */ +#define EXTFILTER_F1_BUFFER_MASK (63 << EXTFILTER_F1_BUFFER_SHIFT) +# define EXTFILTER_F1_BUFFER(n) ((uint32_t)(n) << EXTFILTER_F1_BUFFER_SHIFT) +#define EXTFILTER_F1_ACTION_SHIFT (9) /* Bits 9-10: Action taken */ +#define EXTFILTER_F1_ACTION_MASK (3 << EXTFILTER_F1_ACTION_SHIFT) +# define EXTFILTER_F1_RXBUFFER (0 << EXTFILTER_F1_ACTION_SHIFT) /* Store message in a Rx buffer */ +# define EXTFILTER_F1_DEBUGA (1 << EXTFILTER_F1_ACTION_SHIFT) /* Debug Message A */ +# define EXTFILTER_F1_DEBUGB (2 << EXTFILTER_F1_ACTION_SHIFT) /* Debug Message B */ +# define EXTFILTER_F1_DEBUGC (3 << EXTFILTER_F1_ACTION_SHIFT) /* Debug Message C */ +#define EXTFILTER_F1_EFT_SHIFT (30) /* Bits 30-31: Extended Filter Type */ +#define EXTFILTER_F1_EFT_MASK (3 << EXTFILTER_F1_EFT_SHIFT) +# define EXTFILTER_F1_EFT_RANGE (0 << EXTFILTER_F1_EFT_SHIFT) /* Range filter from SF1ID to SF2ID */ +# define EXTFILTER_F1_EFT_DUAL (1 << EXTFILTER_F1_EFT_SHIFT) /* Dual ID filter for SF1ID or SF2ID */ +# define EXTFILTER_F1_EFT_CLASSIC (2 << EXTFILTER_F1_EFT_SHIFT) /* Classic filter: SF1ID=filter SF2ID=mask */ +# define EXTFILTER_F1_EFT_NOXIDAM (3 << EXTFILTER_F1_EFT_SHIFT) /* Range filter from EF1ID to EF2ID, no XIDAM */ #endif /* __ARCH_ARM_SRC_STM32_HARDWARE_STM32_FDCAN_H */ diff --git a/arch/arm/src/stm32/stm32_fdcan.c b/arch/arm/src/stm32/stm32_fdcan.c index f1174892c95..af3acde2b15 100644 --- a/arch/arm/src/stm32/stm32_fdcan.c +++ b/arch/arm/src/stm32/stm32_fdcan.c @@ -148,17 +148,17 @@ # 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) +# 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 +# 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 @@ -215,17 +215,17 @@ # 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) +# 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 +# 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 @@ -282,17 +282,17 @@ # 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) +# 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 +# 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 @@ -368,7 +368,7 @@ #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) + FDCAN_INT_HPM | FDCAN_RXCOMMON_INTS) #define FDCAN_RXERR_INTS (FDCAN_INT_RF0L | FDCAN_INT_RF1L) @@ -391,7 +391,7 @@ #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) + FDCAN_INT_TEFL) #define FDCAN_TXDEDBUF_INTS FDCAN_TXCOMMON_INTS #define FDCAN_TXERR_INTS (FDCAN_INT_TEFL | FDCAN_INT_PEA | FDCAN_INT_PED) @@ -420,39 +420,41 @@ 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 */ + 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 */ + FDCAN_CLASSIC_MODE = 0, /* Classic CAN operation */ +#ifdef CONFIG_CAN_FD + FDCAN_FD_MODE = 1, /* CAN FD operation */ + FDCAN_FD_BRS_MODE = 2 /* CAN FD operation with bit rate switching */ +#endif }; /* 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() */ + 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 */ + volatile uint32_t *stdfilters; /* Standard filters */ + volatile uint32_t *extfilters; /* Extended filters */ + volatile uint32_t *rxfifo0; /* RX FIFO0 */ + volatile uint32_t *rxfifo1; /* RX FIFO1 */ + volatile uint32_t *txeventfifo; /* TX event FIFO */ + volatile uint32_t *txfifoq; /* TX FIFO queue */ }; /* This structure provides the constant configuration of a FDCAN peripheral */ @@ -481,7 +483,7 @@ struct stm32_config_s uint8_t txeventesize; /* TXevent element size (words) */ uint8_t txbufferesize; /* TX buffer element size (words) */ #ifdef STM32_FDCAN_LOOPBACK - bool loopback; /* True: Loopback mode */ + bool loopback; /* True: Loopback mode */ #endif /* FDCAN message RAM layout */ @@ -527,7 +529,7 @@ struct stm32_fdcan_s 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); + uint32_t regval); #ifdef CONFIG_STM32_FDCAN_REGDEBUG static void fdcan_dumpregs(FAR struct stm32_fdcan_s *priv, FAR const char *msg); @@ -549,11 +551,11 @@ 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); + 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); + FAR struct canioc_stdfilter_s *stdconfig); static int fdcan_del_stdfilter(FAR struct stm32_fdcan_s *priv, int ndx); static int @@ -579,7 +581,7 @@ static bool fdcan_txempty(FAR struct can_dev_s *dev); 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, + FAR volatile uint32_t *rxbuffer, unsigned long nwords); static int fdcan_interrupt(int irq, void *context, FAR void *arg); @@ -912,7 +914,7 @@ static uint32_t fdcan_getreg(FAR struct stm32_fdcan_s *priv, int offset) #ifdef CONFIG_STM32_FDCAN_REGDEBUG static void fdcan_putreg(FAR struct stm32_fdcan_s *priv, int offset, - uint32_t regval) + uint32_t regval) { FAR const struct stm32_config_s *config = priv->config; uintptr_t regaddr = config->base + offset; @@ -928,7 +930,7 @@ static void fdcan_putreg(FAR struct stm32_fdcan_s *priv, int offset, #else static void fdcan_putreg(FAR struct stm32_fdcan_s *priv, int offset, - uint32_t regval) + uint32_t regval) { FAR const struct stm32_config_s *config = priv->config; putreg32(regval, config->base + offset); @@ -952,7 +954,7 @@ static void fdcan_putreg(FAR struct stm32_fdcan_s *priv, int offset, #ifdef CONFIG_STM32_FDCAN_REGDEBUG static void fdcan_dumpregs(FAR struct stm32_fdcan_s *priv, - FAR const char *msg) + FAR const char *msg) { FAR const struct stm32_config_s *config = priv->config; @@ -998,7 +1000,7 @@ static void fdcan_dumpregs(FAR struct stm32_fdcan_s *priv, #ifdef CONFIG_STM32_FDCAN_REGDEBUG static void fdcan_dumprxregs(FAR struct stm32_fdcan_s *priv, - FAR const char *msg) + FAR const char *msg) { FAR const struct stm32_config_s *config = priv->config; @@ -1104,7 +1106,7 @@ static void fdcan_dumpramlayout(FAR struct stm32_fdcan_s *priv) 1); } - if (config->nextfilters) + if (config->nextfilters > 0) { caninfo("EXT filters %p %4d %2d\n", config->msgram.extfilters, @@ -1112,7 +1114,7 @@ static void fdcan_dumpramlayout(FAR struct stm32_fdcan_s *priv) 2); } - if (config->nrxfifo0) + if (config->nrxfifo0 > 0) { caninfo("RX FIFO 0 %p %4d %2d\n", config->msgram.rxfifo0, @@ -1120,7 +1122,7 @@ static void fdcan_dumpramlayout(FAR struct stm32_fdcan_s *priv) config->rxfifo0esize); } - if (config->nrxfifo1) + if (config->nrxfifo1 > 0) { caninfo("RX FIFO 1 %p %4d %2d\n", config->msgram.rxfifo1, @@ -1128,7 +1130,7 @@ static void fdcan_dumpramlayout(FAR struct stm32_fdcan_s *priv) config->rxfifo1esize); } - if (config->ntxeventfifo) + if (config->ntxeventfifo > 0) { caninfo("TX EVENT %p %4d %2d\n", config->msgram.txeventfifo, @@ -1136,7 +1138,7 @@ static void fdcan_dumpramlayout(FAR struct stm32_fdcan_s *priv) config->txeventesize); } - if (config->ntxfifoq) + if (config->ntxfifoq > 0) { caninfo("TX FIFO %p %4d %2d\n", config->msgram.txfifoq, @@ -1220,10 +1222,10 @@ 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) + FAR struct canioc_extfilter_s *extconfig) { FAR const struct stm32_config_s *config = NULL; - FAR uint32_t *extfilter = NULL; + FAR volatile uint32_t *extfilter = NULL; uint32_t regval = 0; int word = 0; int bit = 0; @@ -1234,7 +1236,7 @@ static int fdcan_add_extfilter(FAR struct stm32_fdcan_s *priv, /* Find an unused standard filter */ - for (ndx = 0; ndx < config->nextfilters; ndx++) + for (ndx = 0; ndx < config->nextfilters; ndx++) { /* Is this filter assigned? */ @@ -1262,7 +1264,7 @@ static int fdcan_add_extfilter(FAR struct stm32_fdcan_s *priv, } else { - regval |= EXTFILTER_F0_EFEC_FIFO0; + regval |= EXTFILTER_F0_EFEC_FIFO1; } extfilter[0] = regval; @@ -1274,17 +1276,28 @@ static int fdcan_add_extfilter(FAR struct stm32_fdcan_s *priv, switch (extconfig->xf_type) { - default: case CAN_FILTER_DUAL: - regval |= EXTFILTER_F1_EFT_DUAL; - break; + { + regval |= EXTFILTER_F1_EFT_DUAL; + break; + } case CAN_FILTER_MASK: - regval |= EXTFILTER_F1_EFT_CLASSIC; - break; + { + regval |= EXTFILTER_F1_EFT_CLASSIC; + break; + } + case CAN_FILTER_RANGE: - regval |= EXTFILTER_F1_EFT_RANGE; - break; + { + regval |= EXTFILTER_F1_EFT_RANGE; + break; + } + + default: + { + return -EINVAL; + } } extfilter[1] = regval; @@ -1360,7 +1373,7 @@ static int fdcan_add_extfilter(FAR struct stm32_fdcan_s *priv, 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; + FAR volatile uint32_t *extfilter = NULL; uint32_t regval = 0; int word = 0; int bit = 0; @@ -1409,9 +1422,7 @@ static int fdcan_del_extfilter(FAR struct stm32_fdcan_s *priv, int ndx) /* Wait for initialization mode to take effect */ while ((fdcan_getreg(priv, STM32_FDCAN_CCCR_OFFSET) & - FDCAN_CCCR_INIT) == 0) - { - } + FDCAN_CCCR_INIT) == 0); /* Enable writing to configuration registers */ @@ -1465,10 +1476,10 @@ static int fdcan_del_extfilter(FAR struct stm32_fdcan_s *priv, int ndx) ****************************************************************************/ static int fdcan_add_stdfilter(FAR struct stm32_fdcan_s *priv, - FAR struct canioc_stdfilter_s *stdconfig) + FAR struct canioc_stdfilter_s *stdconfig) { FAR const struct stm32_config_s *config = NULL; - FAR uint32_t *stdfilter = NULL; + FAR volatile uint32_t *stdfilter = NULL; uint32_t regval = 0; int word = 0; int bit = 0; @@ -1515,17 +1526,28 @@ static int fdcan_add_stdfilter(FAR struct stm32_fdcan_s *priv, switch (stdconfig->sf_type) { - default: case CAN_FILTER_DUAL: - regval |= STDFILTER_S0_SFT_DUAL; - break; + { + regval |= STDFILTER_S0_SFT_DUAL; + break; + } case CAN_FILTER_MASK: - regval |= STDFILTER_S0_SFT_CLASSIC; - break; + { + regval |= STDFILTER_S0_SFT_CLASSIC; + break; + } + case CAN_FILTER_RANGE: - regval |= STDFILTER_S0_SFT_RANGE; - break; + { + regval |= STDFILTER_S0_SFT_RANGE; + break; + } + + default: + { + return -EINVAL; + } } *stdfilter = regval; @@ -1543,9 +1565,7 @@ static int fdcan_add_stdfilter(FAR struct stm32_fdcan_s *priv, /* Wait for initialization mode to take effect */ while ((fdcan_getreg(priv, STM32_FDCAN_CCCR_OFFSET) & - FDCAN_CCCR_INIT) == 0) - { - } + FDCAN_CCCR_INIT) == 0); /* Enable writing to configuration registers */ @@ -1600,7 +1620,7 @@ static int fdcan_add_stdfilter(FAR struct stm32_fdcan_s *priv, static int fdcan_del_stdfilter(FAR struct stm32_fdcan_s *priv, int ndx) { FAR const struct stm32_config_s *config = NULL; - FAR uint32_t *stdfilter = NULL; + FAR volatile uint32_t *stdfilter = NULL; uint32_t regval = 0; int word = 0; int bit = 0; @@ -1649,9 +1669,7 @@ static int fdcan_del_stdfilter(FAR struct stm32_fdcan_s *priv, int ndx) /* Wait for initialization mode to take effect */ while ((fdcan_getreg(priv, STM32_FDCAN_CCCR_OFFSET) & - FDCAN_CCCR_INIT) == 0) - { - } + FDCAN_CCCR_INIT) == 0); /* Enable writing to configuration registers */ @@ -1691,21 +1709,8 @@ static int fdcan_del_stdfilter(FAR struct stm32_fdcan_s *priv, int ndx) * * Description: * This function initiates the BUS-OFF recovery sequence. - * CAN Specification Rev. 2.0 or ISO11898-1:2015 - * According the SAMV71 datasheet: - * - * "If the device goes Bus_Off, it will set FDCAN_CCCR.INIT of its own - * accord, stopping all bus activities. Once FDCAN_CCCR.INIT has been - * cleared by the processor (application), the device will then wait for - * 129 occurrences of Bus Idle (129 * 11 consecutive recessive bits) - * before resuming normal operation. At the end of the Bus_Off recovery - * sequence, the Error Management Counters will be reset. During the - * waiting time after the resetting of FDCAN_CCCR.INIT, each time a - * sequence of 11 recessive bits has been monitored, a Bit0 Error code is - * written to FDCAN_PSR.LEC, enabling the processor to readily check up - * whether the CAN bus is stuck at dominant or continuously disturbed and - * to monitor the Bus_Off recovery sequence. FDCAN_ECR.REC is used to - * count these sequences." + * CAN Specification Rev. 2.0 or ISO11898-1:2015. + * According the STM32G4 datasheet section 44.3.2 Software initialziation. * * Input Parameters: * priv - An instance of the FDCAN driver state structure. @@ -1726,7 +1731,7 @@ fdcan_start_busoff_recovery_sequence(FAR struct stm32_fdcan_s *priv) /* Only start BUS-OFF recovery if we are in BUS-OFF state */ regval = fdcan_getreg(priv, STM32_FDCAN_PSR_OFFSET); - if (!(regval & FDCAN_PSR_BO)) + if ((regval & FDCAN_PSR_BO) == 0) { return -EPERM; } @@ -2309,7 +2314,7 @@ static int fdcan_send(FAR struct can_dev_s *dev, FAR struct can_msg_s *msg) { FAR struct stm32_fdcan_s *priv = NULL; FAR const struct stm32_config_s *config = NULL; - FAR uint32_t *txbuffer = NULL; + FAR volatile uint32_t *txbuffer = NULL; FAR const uint8_t *src = NULL; FAR uint32_t *dest = NULL; uint32_t regval = 0; @@ -2383,7 +2388,7 @@ static int fdcan_send(FAR struct can_dev_s *dev, FAR struct can_msg_s *msg) /* Followed by the amount of data corresponding to the DLC (T2..) */ - dest = &txbuffer[2]; + dest = (FAR uint32_t *)&txbuffer[2]; src = msg->cm_data; nbytes = fdcan_dlc2bytes(priv, msg->cm_hdr.ch_dlc); @@ -2478,7 +2483,7 @@ static bool fdcan_txempty(FAR struct can_dev_s *dev) */ regval = fdcan_getreg(priv, STM32_FDCAN_TXFQS_OFFSET); - if (((regval & FDCAN_TXFQS_TFQF) != 0)) + if ((regval & FDCAN_TXFQS_TFQF) != 0) { return false; } @@ -2532,7 +2537,7 @@ static void fdcan_error(FAR struct can_dev_s *dev, uint32_t status) data[1] |= (CAN_ERROR1_RXPASSIVE | CAN_ERROR1_TXPASSIVE); } - if (psr & FDCAN_PSR_EW) + if ((psr & FDCAN_PSR_EW) != 0) { data[1] |= (CAN_ERROR1_RXWARNING | CAN_ERROR1_TXWARNING); } @@ -2548,7 +2553,7 @@ static void fdcan_error(FAR struct can_dev_s *dev, uint32_t status) { /* Protocol Error in Arbitration Phase */ - if (psr & FDCAN_PSR_LEC_MASK) + if ((psr & FDCAN_PSR_LEC_MASK) != 0) { /* Error code present */ @@ -2613,7 +2618,7 @@ static void fdcan_error(FAR struct can_dev_s *dev, uint32_t status) { /* Protocol Error in Data Phase */ - if (psr & FDCAN_PSR_DLEC_MASK) + if ((psr & FDCAN_PSR_DLEC_MASK) != 0) { /* Error code present */ @@ -2763,8 +2768,9 @@ static void fdcan_error(FAR struct can_dev_s *dev, uint32_t status) * ****************************************************************************/ -static void fdcan_receive(FAR struct can_dev_s *dev, FAR uint32_t *rxbuffer, - unsigned long nwords) +static void fdcan_receive(FAR struct can_dev_s *dev, + FAR volatile uint32_t *rxbuffer, + unsigned long nwords) { struct can_hdr_s hdr; uint32_t regval = 0; @@ -2783,14 +2789,9 @@ static void fdcan_receive(FAR struct can_dev_s *dev, FAR uint32_t *rxbuffer, #endif hdr.ch_unused = 0; - if ((regval & BUFFER_R0_RTR) != 0) - { - hdr.ch_rtr = true; - } - else - { - hdr.ch_rtr = false; - } + /* Extract the RTR bit */ + + hdr.ch_rtr = ((regval & BUFFER_R0_RTR) != 0); #ifdef CONFIG_CAN_EXTID if ((regval & BUFFER_R0_XTD) != 0) @@ -2799,13 +2800,13 @@ static void fdcan_receive(FAR struct can_dev_s *dev, FAR uint32_t *rxbuffer, hdr.ch_id = (regval & BUFFER_R0_EXTID_MASK) >> BUFFER_R0_EXTID_SHIFT; - hdr.ch_extid = true; + hdr.ch_extid = 1; } else { hdr.ch_id = (regval & BUFFER_R0_STDID_MASK) >> BUFFER_R0_STDID_SHIFT; - hdr.ch_extid = false; + hdr.ch_extid = 0; } #else @@ -2991,9 +2992,9 @@ static int fdcan_interrupt(int irq, void *context, FAR void *arg) /* Check all TX buffers */ regval = fdcan_getreg(priv, STM32_FDCAN_TXBTO_OFFSET); - for (ndx = 0; ndx < config->ntxfifoq; ndx += 1) + for (ndx = 0; ndx < config->ntxfifoq; ndx++) { - if (regval & (1 << ndx)) + if ((regval & (1 << ndx)) != 0) { /* Tell the upper half that the transfer is finished. */ @@ -3127,7 +3128,7 @@ static int fdcan_interrupt(int irq, void *context, FAR void *arg) static int fdcan_hw_initialize(struct stm32_fdcan_s *priv) { FAR const struct stm32_config_s *config = priv->config; - FAR uint32_t *msgram = NULL; + FAR volatile uint32_t *msgram = NULL; uint32_t regval = 0; uint32_t cntr = 0; @@ -3264,15 +3265,23 @@ static int fdcan_hw_initialize(struct stm32_fdcan_s *priv) /* Select ISO11898-1 or Non ISO Bosch CAN FD Specification V1.0 */ - switch (config->format) + switch (config->format) { - default: - case FDCAN_ISO11898_1_FORMAT: - break; + case FDCAN_ISO11898_1_FORMAT: + { + break; + } + + case FDCAN_NONISO_BOSCH_V1_FORMAT: + { + regval |= FDCAN_CCCR_NISO; + break; + } - case FDCAN_NONISO_BOSCH_V1_FORMAT: - regval |= FDCAN_CCCR_NISO; - break; + default: + { + return -EINVAL; + } } /* Select Classic CAN mode or FD mode with or without fast bit rate @@ -3281,19 +3290,29 @@ static int fdcan_hw_initialize(struct stm32_fdcan_s *priv) switch (config->mode) { - default: - case FDCAN_CLASSIC_MODE: - break; + case FDCAN_CLASSIC_MODE: + { + break; + } #ifdef CONFIG_CAN_FD - case FDCAN_FD_MODE: - regval |= FDCAN_CCCR_FDOE; - break; + case FDCAN_FD_MODE: + { + regval |= FDCAN_CCCR_FDOE; + break; + } - case FDCAN_FD_BRS_MODE: - regval |= (FDCAN_CCCR_FDOE | FDCAN_CCCR_BRSE); - break; + case FDCAN_FD_BRS_MODE: + { + regval |= (FDCAN_CCCR_FDOE | FDCAN_CCCR_BRSE); + break; + } #endif + + default: + { + return -EINVAL; + } } /* Set the initial CAN mode */ @@ -3315,10 +3334,10 @@ static int fdcan_hw_initialize(struct stm32_fdcan_s *priv) if (config->loopback) { - /* FDCAN_CCCR_TEST - Test mode enable - * FDCAN_CCCR_MON - Bus monitoring mode (for internal loopback) - * FDCAN_TEST_LBCK - Loopback mode - */ + /* FDCAN_CCCR_TEST - Test mode enable + * FDCAN_CCCR_MON - Bus monitoring mode (for internal loopback) + * FDCAN_TEST_LBCK - Loopback mode + */ regval = fdcan_getreg(priv, STM32_FDCAN_CCCR_OFFSET); regval |= (FDCAN_CCCR_TEST | FDCAN_CCCR_MON); From f1b5c76e32331d47ce8e75bac2ee52dee0ba1d73 Mon Sep 17 00:00:00 2001 From: raiden00pl Date: Sat, 15 Jan 2022 13:51:58 +0100 Subject: [PATCH 25/43] [BACKPORT] boards/b-g431b-esc1: add CAN example --- boards/arm/stm32/b-g431b-esc1/Kconfig | 4 + boards/arm/stm32/b-g431b-esc1/README.txt | 3 + .../stm32/b-g431b-esc1/configs/can/defconfig | 57 ++++++++++ boards/arm/stm32/b-g431b-esc1/include/board.h | 14 +++ boards/arm/stm32/b-g431b-esc1/src/Make.defs | 4 + .../arm/stm32/b-g431b-esc1/src/b-g431b-esc1.h | 17 +++ .../stm32/b-g431b-esc1/src/stm32_bringup.c | 10 ++ boards/arm/stm32/b-g431b-esc1/src/stm32_can.c | 104 ++++++++++++++++++ 8 files changed, 213 insertions(+) create mode 100644 boards/arm/stm32/b-g431b-esc1/configs/can/defconfig create mode 100644 boards/arm/stm32/b-g431b-esc1/src/stm32_can.c diff --git a/boards/arm/stm32/b-g431b-esc1/Kconfig b/boards/arm/stm32/b-g431b-esc1/Kconfig index 54c75faa436..1fdc237bf84 100644 --- a/boards/arm/stm32/b-g431b-esc1/Kconfig +++ b/boards/arm/stm32/b-g431b-esc1/Kconfig @@ -17,4 +17,8 @@ config BOARD_STM32_BG431BESC1_FOC_POT endif # STM32_FOC +config BOARD_STM32_BG431BESC1_CANTERM + bool "B-G431B-ESC1 use on-board CAN terminator resistor" + default y + endif # ARCH_BOARD_B_G431B_ESC1 diff --git a/boards/arm/stm32/b-g431b-esc1/README.txt b/boards/arm/stm32/b-g431b-esc1/README.txt index 4b846366bc1..72b07980382 100644 --- a/boards/arm/stm32/b-g431b-esc1/README.txt +++ b/boards/arm/stm32/b-g431b-esc1/README.txt @@ -48,6 +48,9 @@ Configuration Sub-directories ENCO_Z/HALL_H3 PB8 BUTTON GPIO_PC10 PC10 PWM PA15 + CAN_RX PA11 + CAN_TX PB9 + CAN_TERM PC14 Current shunt resistance = 0.003 PGA gain = 16 diff --git a/boards/arm/stm32/b-g431b-esc1/configs/can/defconfig b/boards/arm/stm32/b-g431b-esc1/configs/can/defconfig new file mode 100644 index 00000000000..65af7ee7e79 --- /dev/null +++ b/boards/arm/stm32/b-g431b-esc1/configs/can/defconfig @@ -0,0 +1,57 @@ +# +# 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_FPU is not set +# CONFIG_NSH_ARGCAT is not set +# CONFIG_NSH_CMDOPT_HEXDUMP is not set +# CONFIG_NSH_CMDPARMS is not set +# CONFIG_NSH_DISABLE_IFCONFIG is not set +# CONFIG_NSH_DISABLE_PS is not set +CONFIG_ARCH="arm" +CONFIG_ARCH_BOARD="b-g431b-esc1" +CONFIG_ARCH_BOARD_B_G431B_ESC1=y +CONFIG_ARCH_BUTTONS=y +CONFIG_ARCH_CHIP="stm32" +CONFIG_ARCH_CHIP_STM32=y +CONFIG_ARCH_CHIP_STM32G431C=y +CONFIG_ARCH_INTERRUPTSTACK=2048 +CONFIG_ARCH_STACKDUMP=y +CONFIG_BOARD_LOOPSPERMSEC=8499 +CONFIG_BOARD_STM32_BG431BESC1_USE_HSE=y +CONFIG_BUILTIN=y +CONFIG_CAN=y +CONFIG_CAN_ERRORS=y +CONFIG_CAN_EXTID=y +CONFIG_DEBUG_FULLOPT=y +CONFIG_DEBUG_SYMBOLS=y +CONFIG_EXAMPLES_CAN=y +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=22528 +CONFIG_RAM_START=0x20000000 +CONFIG_RAW_BINARY=y +CONFIG_RR_INTERVAL=200 +CONFIG_SCHED_WAITPID=y +CONFIG_SDCLONE_DISABLE=y +CONFIG_START_DAY=14 +CONFIG_START_MONTH=10 +CONFIG_START_YEAR=2014 +CONFIG_STM32_FDCAN1=y +CONFIG_STM32_FDCAN1_BITRATE=250000 +CONFIG_STM32_FDCAN1_NTSEG1=13 +CONFIG_STM32_FDCAN1_NTSEG2=2 +CONFIG_STM32_JTAG_SW_ENABLE=y +CONFIG_STM32_USART2=y +CONFIG_SYSTEM_NSH=y +CONFIG_TASK_NAME_SIZE=0 +CONFIG_USART2_SERIAL_CONSOLE=y diff --git a/boards/arm/stm32/b-g431b-esc1/include/board.h b/boards/arm/stm32/b-g431b-esc1/include/board.h index 67946a45992..9bf9f5cb4fe 100644 --- a/boards/arm/stm32/b-g431b-esc1/include/board.h +++ b/boards/arm/stm32/b-g431b-esc1/include/board.h @@ -159,6 +159,15 @@ #define BOARD_TIM17_FREQUENCY (STM32_PCLK2_FREQUENCY) #define BOARD_TIM20_FREQUENCY (STM32_PCLK2_FREQUENCY) +#ifdef CONFIG_STM32_FDCAN +# ifdef CONFIG_BOARD_STM32_BG431BESC1_USE_HSE +# define STM32_CCIPR_FDCANSRC (RCC_CCIPR_FDCANSEL_HSE) +# define STM32_FDCAN_FREQUENCY (STM32_HSE_FREQUENCY) +# else +# error For now FDCAN supported only if HSE enabled +# endif +#endif + /* LED definitions **********************************************************/ /* The B-G431B-ESC1 has four user LEDs. @@ -240,4 +249,9 @@ #define DMACHAN_USART2_TX DMAMAP_DMA12_USART2TX_0 /* DMA1 */ #define DMACHAN_USART2_RX DMAMAP_DMA12_USART2RX_0 /* DMA1 */ +/* CAN configuration ********************************************************/ + +#define GPIO_FDCAN1_RX GPIO_FDCAN1_RX_1 /* PA11 */ +#define GPIO_FDCAN1_TX GPIO_FDCAN1_TX_2 /* PB9 */ + #endif /* __BOARDS_ARM_STM32_B_G431B_ESC1_INCLUDE_BOARD_H */ diff --git a/boards/arm/stm32/b-g431b-esc1/src/Make.defs b/boards/arm/stm32/b-g431b-esc1/src/Make.defs index c1a08b29ef9..d3a1fbc4c40 100644 --- a/boards/arm/stm32/b-g431b-esc1/src/Make.defs +++ b/boards/arm/stm32/b-g431b-esc1/src/Make.defs @@ -41,6 +41,10 @@ ifeq ($(CONFIG_STM32_FOC),y) CSRCS += stm32_foc.c endif +ifeq ($(CONFIG_STM32_FDCAN_CHARDRIVER),y) +CSRCS += stm32_can.c +endif + DEPPATH += --dep-path board VPATH += :board CFLAGS += $(shell $(INCDIR) "$(CC)" $(TOPDIR)$(DELIM)arch$(DELIM)$(CONFIG_ARCH)$(DELIM)src$(DELIM)board$(DELIM)board) diff --git a/boards/arm/stm32/b-g431b-esc1/src/b-g431b-esc1.h b/boards/arm/stm32/b-g431b-esc1/src/b-g431b-esc1.h index be372df84da..6e133f8c3d6 100644 --- a/boards/arm/stm32/b-g431b-esc1/src/b-g431b-esc1.h +++ b/boards/arm/stm32/b-g431b-esc1/src/b-g431b-esc1.h @@ -70,6 +70,11 @@ #define GPIO_BTN_USER (GPIO_INPUT|GPIO_FLOAT|GPIO_EXTI|GPIO_PORTC|GPIO_PIN10) +/* CAN_TERM - PC14 */ + +#define GPIO_CANTERM (GPIO_OUTPUT|GPIO_PUSHPULL|GPIO_SPEED_50MHz| \ + GPIO_OUTPUT_CLEAR|GPIO_PORTC|GPIO_PIN14) + /**************************************************************************** * Public Data ****************************************************************************/ @@ -122,4 +127,16 @@ int stm32_adc_setup(void); int stm32_foc_setup(void); #endif +/**************************************************************************** + * Name: stm32_can_setup + * + * Description: + * Initialize CAN and register the CAN device + * + ****************************************************************************/ + +#ifdef CONFIG_STM32_FDCAN_CHARDRIVER +int stm32_can_setup(void); +#endif + #endif /* __BOARDS_ARM_STM32_B_G431B_ESC1_SRC_B_G431B_ESC1_H */ diff --git a/boards/arm/stm32/b-g431b-esc1/src/stm32_bringup.c b/boards/arm/stm32/b-g431b-esc1/src/stm32_bringup.c index edd66adcf88..7c3fbc2068f 100644 --- a/boards/arm/stm32/b-g431b-esc1/src/stm32_bringup.c +++ b/boards/arm/stm32/b-g431b-esc1/src/stm32_bringup.c @@ -112,6 +112,16 @@ int stm32_bringup(void) } #endif +#ifdef CONFIG_STM32_FDCAN_CHARDRIVER + /* Initialize CAN and register the CAN driver. */ + + ret = stm32_can_setup(); + if (ret < 0) + { + syslog(LOG_ERR, "ERROR: stm32_fdcan_setup failed: %d\n", ret); + } +#endif + UNUSED(ret); return OK; } diff --git a/boards/arm/stm32/b-g431b-esc1/src/stm32_can.c b/boards/arm/stm32/b-g431b-esc1/src/stm32_can.c new file mode 100644 index 00000000000..bf5e483c842 --- /dev/null +++ b/boards/arm/stm32/b-g431b-esc1/src/stm32_can.c @@ -0,0 +1,104 @@ +/**************************************************************************** + * boards/arm/stm32/b-g431b-esc1/src/stm32_can.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 "arm_arch.h" + +#include "stm32.h" +#include "stm32_fdcan.h" +#include "b-g431b-esc1.h" + +#ifdef CONFIG_CAN + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Configuration ************************************************************/ + +#if !defined(CONFIG_STM32_FDCAN1) +# error "No CAN is enable. Please eneable at least one CAN device" +#endif + +#ifdef CONFIG_BOARD_STM32_BG431BESC1_CANTERM +# define BG431BESC1_CANTERM (true) +#else +# define BG431BESC1_CANTERM (false) +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: stm32_can_setup + * + * Description: + * Initialize CAN and register the CAN device + * + ****************************************************************************/ + +int stm32_can_setup(void) +{ + struct can_dev_s *can; + int ret; + + /* Call stm32_fdcaninitialize() to get an instance of the CAN interface */ + + can = stm32_fdcaninitialize(1); + if (can == NULL) + { + canerr("ERROR: Failed to get CAN interface\n"); + return -ENODEV; + } + + /* Register the CAN driver at "/dev/can0" */ + + ret = can_register("/dev/can0", can); + if (ret < 0) + { + canerr("ERROR: can_register failed: %d\n", ret); + return ret; + } + + /* Configure CAN_TERM pin for output */ + + stm32_configgpio(GPIO_CANTERM); + + /* Set CAN_TERM pin high or low */ + + stm32_gpiowrite(GPIO_CANTERM, BG431BESC1_CANTERM); + + return OK; +} + +#endif /* CONFIG_CAN */ From 39f09f1675b23d49bc59b9a5ed84b23f1708ce3e Mon Sep 17 00:00:00 2001 From: raiden00pl Date: Sat, 15 Jan 2022 13:56:50 +0100 Subject: [PATCH 26/43] [BACKPORT] boards/nucleo-g431rb: add CAN example --- .../stm32/nucleo-g431rb/configs/can/defconfig | 58 ++++++++++++ .../arm/stm32/nucleo-g431rb/include/board.h | 14 +++ boards/arm/stm32/nucleo-g431rb/src/Make.defs | 4 + .../stm32/nucleo-g431rb/src/nucleo-g431rb.h | 12 +++ .../stm32/nucleo-g431rb/src/stm32_bringup.c | 10 +++ .../arm/stm32/nucleo-g431rb/src/stm32_can.c | 90 +++++++++++++++++++ 6 files changed, 188 insertions(+) create mode 100644 boards/arm/stm32/nucleo-g431rb/configs/can/defconfig create mode 100644 boards/arm/stm32/nucleo-g431rb/src/stm32_can.c diff --git a/boards/arm/stm32/nucleo-g431rb/configs/can/defconfig b/boards/arm/stm32/nucleo-g431rb/configs/can/defconfig new file mode 100644 index 00000000000..22c2934f0dc --- /dev/null +++ b/boards/arm/stm32/nucleo-g431rb/configs/can/defconfig @@ -0,0 +1,58 @@ +# +# 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_FPU is not set +# CONFIG_NSH_ARGCAT is not set +# CONFIG_NSH_CMDOPT_HEXDUMP is not set +# CONFIG_NSH_CMDPARMS is not set +# CONFIG_NSH_DISABLE_IFCONFIG is not set +# CONFIG_NSH_DISABLE_PS is not set +CONFIG_ARCH="arm" +CONFIG_ARCH_BOARD="nucleo-g431rb" +CONFIG_ARCH_BOARD_NUCLEO_G431RB=y +CONFIG_ARCH_BUTTONS=y +CONFIG_ARCH_CHIP="stm32" +CONFIG_ARCH_CHIP_STM32=y +CONFIG_ARCH_CHIP_STM32G431R=y +CONFIG_ARCH_INTERRUPTSTACK=2048 +CONFIG_ARCH_STACKDUMP=y +CONFIG_BOARD_LOOPSPERMSEC=8499 +CONFIG_BOARD_NUCLEO_G431RB_USE_HSE=y +CONFIG_BUILTIN=y +CONFIG_CAN=y +CONFIG_CAN_ERRORS=y +CONFIG_CAN_EXTID=y +CONFIG_DEBUG_FULLOPT=y +CONFIG_DEBUG_SYMBOLS=y +CONFIG_EXAMPLES_CAN=y +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=22528 +CONFIG_RAM_START=0x20000000 +CONFIG_RAW_BINARY=y +CONFIG_RR_INTERVAL=200 +CONFIG_SCHED_WAITPID=y +CONFIG_SDCLONE_DISABLE=y +CONFIG_START_DAY=14 +CONFIG_START_MONTH=10 +CONFIG_START_YEAR=2014 +CONFIG_STDIO_BUFFER_SIZE=512 +CONFIG_STM32_FDCAN1=y +CONFIG_STM32_FDCAN1_BITRATE=250000 +CONFIG_STM32_FDCAN1_NTSEG1=13 +CONFIG_STM32_FDCAN1_NTSEG2=2 +CONFIG_STM32_JTAG_SW_ENABLE=y +CONFIG_STM32_USART2=y +CONFIG_SYSTEM_NSH=y +CONFIG_TASK_NAME_SIZE=0 +CONFIG_USART2_SERIAL_CONSOLE=y diff --git a/boards/arm/stm32/nucleo-g431rb/include/board.h b/boards/arm/stm32/nucleo-g431rb/include/board.h index 030ba13d13d..788d1a69c72 100644 --- a/boards/arm/stm32/nucleo-g431rb/include/board.h +++ b/boards/arm/stm32/nucleo-g431rb/include/board.h @@ -159,6 +159,15 @@ #define BOARD_TIM17_FREQUENCY (STM32_PCLK2_FREQUENCY) #define BOARD_TIM20_FREQUENCY (STM32_PCLK2_FREQUENCY) +#ifdef CONFIG_STM32_FDCAN +# ifdef CONFIG_BOARD_NUCLEO_G431RB_USE_HSE +# define STM32_CCIPR_FDCANSRC (RCC_CCIPR_FDCANSEL_HSE) +# define STM32_FDCAN_FREQUENCY (STM32_HSE_FREQUENCY) +# else +# error For now FDCAN supported only if HSE enabled +# endif +#endif + /* LED definitions **********************************************************/ /* The NUCLEO-G431RB has four user LEDs. @@ -236,6 +245,11 @@ #define GPIO_TIM1_CH3NOUT GPIO_TIM1_CH3NOUT_1 /* PB1 */ #define GPIO_TIM1_CH4OUT GPIO_TIM1_CH4OUT_2 /* PC3 */ +/* CAN configuration ********************************************************/ + +#define GPIO_FDCAN1_RX GPIO_FDCAN1_RX_2 /* PB8 */ +#define GPIO_FDCAN1_TX GPIO_FDCAN1_TX_2 /* PB9 */ + /* DMA channels *************************************************************/ /* ADC */ diff --git a/boards/arm/stm32/nucleo-g431rb/src/Make.defs b/boards/arm/stm32/nucleo-g431rb/src/Make.defs index 586119505d0..3ca40eb1344 100644 --- a/boards/arm/stm32/nucleo-g431rb/src/Make.defs +++ b/boards/arm/stm32/nucleo-g431rb/src/Make.defs @@ -51,6 +51,10 @@ ifeq ($(CONFIG_BOARD_STM32_IHM16M1),y) CSRCS += stm32_foc_ihm16m1.c endif +ifeq ($(CONFIG_STM32_FDCAN_CHARDRIVER),y) +CSRCS += stm32_can.c +endif + DEPPATH += --dep-path board VPATH += :board CFLAGS += $(shell $(INCDIR) "$(CC)" $(TOPDIR)$(DELIM)arch$(DELIM)$(CONFIG_ARCH)$(DELIM)src$(DELIM)board$(DELIM)board) diff --git a/boards/arm/stm32/nucleo-g431rb/src/nucleo-g431rb.h b/boards/arm/stm32/nucleo-g431rb/src/nucleo-g431rb.h index 92154be09fb..a7a1d69f798 100644 --- a/boards/arm/stm32/nucleo-g431rb/src/nucleo-g431rb.h +++ b/boards/arm/stm32/nucleo-g431rb/src/nucleo-g431rb.h @@ -143,4 +143,16 @@ int stm32_adc_setup(void); int stm32_foc_setup(void); #endif +/**************************************************************************** + * Name: stm32_can_setup + * + * Description: + * Initialize CAN and register the CAN device + * + ****************************************************************************/ + +#ifdef CONFIG_STM32_FDCAN_CHARDRIVER +int stm32_can_setup(void); +#endif + #endif /* __BOARDS_ARM_STM32_NUCLEO_G431RB_SRC_NUCLEO_G431RB_H */ diff --git a/boards/arm/stm32/nucleo-g431rb/src/stm32_bringup.c b/boards/arm/stm32/nucleo-g431rb/src/stm32_bringup.c index 7e7ad766030..6787e9e4370 100644 --- a/boards/arm/stm32/nucleo-g431rb/src/stm32_bringup.c +++ b/boards/arm/stm32/nucleo-g431rb/src/stm32_bringup.c @@ -122,6 +122,16 @@ int stm32_bringup(void) } #endif +#ifdef CONFIG_STM32_FDCAN_CHARDRIVER + /* Initialize CAN and register the CAN driver. */ + + ret = stm32_can_setup(); + if (ret < 0) + { + syslog(LOG_ERR, "ERROR: stm32_fdcan_setup failed: %d\n", ret); + } +#endif + UNUSED(ret); return OK; } diff --git a/boards/arm/stm32/nucleo-g431rb/src/stm32_can.c b/boards/arm/stm32/nucleo-g431rb/src/stm32_can.c new file mode 100644 index 00000000000..0afb654985c --- /dev/null +++ b/boards/arm/stm32/nucleo-g431rb/src/stm32_can.c @@ -0,0 +1,90 @@ +/**************************************************************************** + * boards/arm/stm32/nucleo-g431rb/src/stm32_can.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 "arm_arch.h" + +#include "stm32.h" +#include "stm32_fdcan.h" +#include "nucleo-g431rb.h" + +#ifdef CONFIG_CAN + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Configuration ************************************************************/ + +#if !defined(CONFIG_STM32_FDCAN1) +# error "No CAN is enable. Please eneable at least one CAN device" +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: stm32_can_setup + * + * Description: + * Initialize CAN and register the CAN device + * + ****************************************************************************/ + +int stm32_can_setup(void) +{ + struct can_dev_s *can; + int ret; + + /* Call stm32_fdcaninitialize() to get an instance of the CAN interface */ + + can = stm32_fdcaninitialize(1); + if (can == NULL) + { + canerr("ERROR: Failed to get CAN interface\n"); + return -ENODEV; + } + + /* Register the CAN driver at "/dev/can0" */ + + ret = can_register("/dev/can0", can); + if (ret < 0) + { + canerr("ERROR: can_register failed: %d\n", ret); + return ret; + } + + return OK; +} + +#endif /* CONFIG_CAN */ From de03f4322c8c35fbefb391ef43bc985931a911b7 Mon Sep 17 00:00:00 2001 From: raiden00pl Date: Sat, 22 Jan 2022 17:17:51 +0100 Subject: [PATCH 27/43] [BACKPORT] include/nuttx/can.h: make SocketCAN error definitions always available --- include/nuttx/can.h | 101 +++++++++++++++++++++----------------------- 1 file changed, 49 insertions(+), 52 deletions(-) diff --git a/include/nuttx/can.h b/include/nuttx/can.h index 7cd1da20654..6d2e67af649 100644 --- a/include/nuttx/can.h +++ b/include/nuttx/can.h @@ -210,80 +210,77 @@ /* CAN Error Indications ****************************************************/ -#ifdef CONFIG_NET_CAN_ERRORS - /* Error class in can_id */ -# define CAN_ERR_TXTIMEOUT (1 << 0) /* Bit 0: TX timeout */ -# define CAN_ERR_LOSTARB (1 << 1) /* Bit 1: Lost arbitration (See CAN_ERR_LOSTARB_* definitions) */ -# define CAN_ERR_CTRL (1 << 2) /* Bit 2: Controller error (See CAN_ERR_CTRL_* definitions) */ -# define CAN_ERR_PROT (1 << 3) /* Bit 3: Protocol error (see CAN_ERR_PROT_* definitions) */ -# define CAN_ERR_TRX (1 << 4) /* Bit 4: Transceiver error (See CAN_TRX_* definitions) */ -# define CAN_ERR_ACK (1 << 5) /* Bit 5: No ACK received on transmission */ -# define CAN_ERR_BUSOFF (1 << 6) /* Bit 6: Bus off */ -# define CAN_ERR_BUSERROR (1 << 7) /* Bit 7: Bus error */ -# define CAN_ERR_RESTARTED (1 << 8) /* Bit 8: Controller restarted */ +#define CAN_ERR_TXTIMEOUT (1 << 0) /* Bit 0: TX timeout */ +#define CAN_ERR_LOSTARB (1 << 1) /* Bit 1: Lost arbitration (See CAN_ERR_LOSTARB_* definitions) */ +#define CAN_ERR_CTRL (1 << 2) /* Bit 2: Controller error (See CAN_ERR_CTRL_* definitions) */ +#define CAN_ERR_PROT (1 << 3) /* Bit 3: Protocol error (see CAN_ERR_PROT_* definitions) */ +#define CAN_ERR_TRX (1 << 4) /* Bit 4: Transceiver error (See CAN_TRX_* definitions) */ +#define CAN_ERR_ACK (1 << 5) /* Bit 5: No ACK received on transmission */ +#define CAN_ERR_BUSOFF (1 << 6) /* Bit 6: Bus off */ +#define CAN_ERR_BUSERROR (1 << 7) /* Bit 7: Bus error */ +#define CAN_ERR_RESTARTED (1 << 8) /* Bit 8: Controller restarted */ /* The remaining definitions described the error report payload that follows * the CAN header. */ -# define CAN_ERR_DLC (8) /* DLC of error report */ +#define CAN_ERR_DLC (8) /* DLC of error report */ /* Data[0]: Arbitration lost in ch_error. */ -# define CAN_ERR_LOSTARB_UNSPEC 0x00 /* Unspecified error */ -# define CAN_ERR_LOSTARB_BIT(n) (n) /* Bit number in the bit stream */ +#define CAN_ERR_LOSTARB_UNSPEC 0x00 /* Unspecified error */ +#define CAN_ERR_LOSTARB_BIT(n) (n) /* Bit number in the bit stream */ /* Data[1]: Error status of CAN-controller */ -# define CAN_ERR_CTRL_UNSPEC 0x00 /* Unspecified error */ -# define CAN_ERR_CTRL_RX_OVERFLOW (1 << 0) /* Bit 0: RX buffer overflow */ -# define CAN_ERR_CTRL_TX_OVERFLOW (1 << 1) /* Bit 1: TX buffer overflow */ -# define CAN_ERR_CTRL_RX_WARNING (1 << 2) /* Bit 2: Reached warning level for RX errors */ -# define CAN_ERR_CTRL_TX_WARNING (1 << 3) /* Bit 3: Reached warning level for TX errors */ -# define CAN_ERR_CTRL_RX_PASSIVE (1 << 4) /* Bit 4: Reached passive level for RX errors */ -# define CAN_ERR_CTRL_TX_PASSIVE (1 << 5) /* Bit 5: Reached passive level for TX errors */ +#define CAN_ERR_CTRL_UNSPEC 0x00 /* Unspecified error */ +#define CAN_ERR_CTRL_RX_OVERFLOW (1 << 0) /* Bit 0: RX buffer overflow */ +#define CAN_ERR_CTRL_TX_OVERFLOW (1 << 1) /* Bit 1: TX buffer overflow */ +#define CAN_ERR_CTRL_RX_WARNING (1 << 2) /* Bit 2: Reached warning level for RX errors */ +#define CAN_ERR_CTRL_TX_WARNING (1 << 3) /* Bit 3: Reached warning level for TX errors */ +#define CAN_ERR_CTRL_RX_PASSIVE (1 << 4) /* Bit 4: Reached passive level for RX errors */ +#define CAN_ERR_CTRL_TX_PASSIVE (1 << 5) /* Bit 5: Reached passive level for TX errors */ /* Data[2]: Error in CAN protocol. This provides the type of the error. */ -# define CAN_ERR_PROT_UNSPEC 0x00 /* Unspecified error */ -# define CAN_ERR_PROT_BIT (1 << 0) /* Bit 0: Single bit error */ -# define CAN_ERR_PROT_FORM (1 << 1) /* Bit 1: Frame format error */ -# define CAN_ERR_PROT_STUFF (1 << 2) /* Bit 2: Bit stuffing error */ -# define CAN_ERR_PROT_BIT0 (1 << 3) /* Bit 3: Unable to send dominant bit */ -# define CAN_ERR_PROT_BIT1 (1 << 4) /* Bit 4: Unable to send recessive bit */ -# define CAN_ERR_PROT_OVERLOAD (1 << 5) /* Bit 5: Bus overload */ -# define CAN_ERR_PROT_ACTIVE (1 << 6) /* Bit 6: Active error announcement */ -# define CAN_ERR_PROT_TX (1 << 7) /* Bit 7: Error occurred on transmission */ +#define CAN_ERR_PROT_UNSPEC 0x00 /* Unspecified error */ +#define CAN_ERR_PROT_BIT (1 << 0) /* Bit 0: Single bit error */ +#define CAN_ERR_PROT_FORM (1 << 1) /* Bit 1: Frame format error */ +#define CAN_ERR_PROT_STUFF (1 << 2) /* Bit 2: Bit stuffing error */ +#define CAN_ERR_PROT_BIT0 (1 << 3) /* Bit 3: Unable to send dominant bit */ +#define CAN_ERR_PROT_BIT1 (1 << 4) /* Bit 4: Unable to send recessive bit */ +#define CAN_ERR_PROT_OVERLOAD (1 << 5) /* Bit 5: Bus overload */ +#define CAN_ERR_PROT_ACTIVE (1 << 6) /* Bit 6: Active error announcement */ +#define CAN_ERR_PROT_TX (1 << 7) /* Bit 7: Error occurred on transmission */ /* Data[3]: Error in CAN protocol. This provides the loation of the error */ -# define CAN_ERR_PROT_LOC_UNSPEC 0x00 /* Unspecified error */ -# define CAN_ERR_PROT_LOC_SOF 0x01 /* start of frame */ -# define CAN_ERR_PROT_LOC_ID0 0x02 /* ID bits 0-4 */ -# define CAN_ERR_PROT_LOC_ID1 0x03 /* ID bits 5-12 */ -# define CAN_ERR_PROT_LOC_ID2 0x04 /* ID bits 13-17 */ -# define CAN_ERR_PROT_LOC_ID3 0x05 /* ID bits 21-28 */ -# define CAN_ERR_PROT_LOC_ID4 0x06 /* ID bits 18-20 */ -# define CAN_ERR_PROT_LOC_IDE 0x07 /* Identifier extension */ -# define CAN_ERR_PROT_LOC_RTR 0x08 /* RTR */ -# define CAN_ERR_PROT_LOC_SRTR 0x09 /* Substitute RTR */ -# define CAN_ERR_PROT_LOC_RES0 0x0a /* Reserved bit 0 */ -# define CAN_ERR_PROT_LOC_RES1 0x0b /* Reserved bit 1 */ -# define CAN_ERR_PROT_LOC_DLC 0x0c /* Data length code */ -# define CAN_ERR_PROT_LOC_DATA 0x0d /* Data section */ -# define CAN_ERR_PROT_LOC_CRCSEQ 0x0e /* CRC sequence */ -# define CAN_ERR_PROT_LOC_CRCDEL 0x0f /* CRC delimiter */ -# define CAN_ERR_PROT_LOC_ACK 0x10 /* ACK slot */ -# define CAN_ERR_PROT_LOC_ACKDEL 0x11 /* ACK delimiter */ -# define CAN_ERR_PROT_LOC_EOF 0x12 /* End of frame */ -# define CAN_ERR_PROT_LOC_INTERM 0x13 /* Intermission */ +#define CAN_ERR_PROT_LOC_UNSPEC 0x00 /* Unspecified error */ +#define CAN_ERR_PROT_LOC_SOF 0x01 /* start of frame */ +#define CAN_ERR_PROT_LOC_ID0 0x02 /* ID bits 0-4 */ +#define CAN_ERR_PROT_LOC_ID1 0x03 /* ID bits 5-12 */ +#define CAN_ERR_PROT_LOC_ID2 0x04 /* ID bits 13-17 */ +#define CAN_ERR_PROT_LOC_ID3 0x05 /* ID bits 21-28 */ +#define CAN_ERR_PROT_LOC_ID4 0x06 /* ID bits 18-20 */ +#define CAN_ERR_PROT_LOC_IDE 0x07 /* Identifier extension */ +#define CAN_ERR_PROT_LOC_RTR 0x08 /* RTR */ +#define CAN_ERR_PROT_LOC_SRTR 0x09 /* Substitute RTR */ +#define CAN_ERR_PROT_LOC_RES0 0x0a /* Reserved bit 0 */ +#define CAN_ERR_PROT_LOC_RES1 0x0b /* Reserved bit 1 */ +#define CAN_ERR_PROT_LOC_DLC 0x0c /* Data length code */ +#define CAN_ERR_PROT_LOC_DATA 0x0d /* Data section */ +#define CAN_ERR_PROT_LOC_CRCSEQ 0x0e /* CRC sequence */ +#define CAN_ERR_PROT_LOC_CRCDEL 0x0f /* CRC delimiter */ +#define CAN_ERR_PROT_LOC_ACK 0x10 /* ACK slot */ +#define CAN_ERR_PROT_LOC_ACKDEL 0x11 /* ACK delimiter */ +#define CAN_ERR_PROT_LOC_EOF 0x12 /* End of frame */ +#define CAN_ERR_PROT_LOC_INTERM 0x13 /* Intermission */ /* Data[4]: Error status of CAN-transceiver */ -# define CAN_ERR_TRX_UNSPEC 0x00 /* Unspecified error */ -#endif /* CONFIG_NET_CAN_ERRORS */ +#define CAN_ERR_TRX_UNSPEC 0x00 /* Unspecified error */ /**************************************************************************** * Public Types From e263e0ef0a96ea9c8e1dccf8194227f75c8d695b Mon Sep 17 00:00:00 2001 From: raiden00pl Date: Sat, 22 Jan 2022 17:19:54 +0100 Subject: [PATCH 28/43] [BACKPORT] include/nuttx/can.h: rename CAN_ERR_CTRL to CAN_ERR_CRTL for compatibility with libcanutils --- arch/arm/src/stm32/stm32_can_sock.c | 8 ++++---- include/nuttx/can.h | 16 ++++++++-------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/arch/arm/src/stm32/stm32_can_sock.c b/arch/arm/src/stm32/stm32_can_sock.c index c04505ab4f3..ff13b54297b 100644 --- a/arch/arm/src/stm32/stm32_can_sock.c +++ b/arch/arm/src/stm32/stm32_can_sock.c @@ -1572,16 +1572,16 @@ static void stm32can_sceinterrupt_work(FAR void *arg) { /* Error warning flag */ - data[1] |= (CAN_ERR_CTRL_RX_WARNING | CAN_ERR_CTRL_TX_WARNING); - errbits |= CAN_ERR_CTRL; + data[1] |= (CAN_ERR_CRTL_RX_WARNING | CAN_ERR_CRTL_TX_WARNING); + errbits |= CAN_ERR_CRTL; } if (regval & CAN_ESR_EPVF) { /* Error passive flag */ - data[1] |= (CAN_ERR_CTRL_RX_PASSIVE | CAN_ERR_CTRL_TX_PASSIVE); - errbits |= CAN_ERR_CTRL; + data[1] |= (CAN_ERR_CRTL_RX_PASSIVE | CAN_ERR_CRTL_TX_PASSIVE); + errbits |= CAN_ERR_CRTL; } if (regval & CAN_ESR_BOFF) diff --git a/include/nuttx/can.h b/include/nuttx/can.h index 6d2e67af649..8522bedaa20 100644 --- a/include/nuttx/can.h +++ b/include/nuttx/can.h @@ -214,7 +214,7 @@ #define CAN_ERR_TXTIMEOUT (1 << 0) /* Bit 0: TX timeout */ #define CAN_ERR_LOSTARB (1 << 1) /* Bit 1: Lost arbitration (See CAN_ERR_LOSTARB_* definitions) */ -#define CAN_ERR_CTRL (1 << 2) /* Bit 2: Controller error (See CAN_ERR_CTRL_* definitions) */ +#define CAN_ERR_CRTL (1 << 2) /* Bit 2: Controller error (See CAN_ERR_CRTL_* definitions) */ #define CAN_ERR_PROT (1 << 3) /* Bit 3: Protocol error (see CAN_ERR_PROT_* definitions) */ #define CAN_ERR_TRX (1 << 4) /* Bit 4: Transceiver error (See CAN_TRX_* definitions) */ #define CAN_ERR_ACK (1 << 5) /* Bit 5: No ACK received on transmission */ @@ -235,13 +235,13 @@ /* Data[1]: Error status of CAN-controller */ -#define CAN_ERR_CTRL_UNSPEC 0x00 /* Unspecified error */ -#define CAN_ERR_CTRL_RX_OVERFLOW (1 << 0) /* Bit 0: RX buffer overflow */ -#define CAN_ERR_CTRL_TX_OVERFLOW (1 << 1) /* Bit 1: TX buffer overflow */ -#define CAN_ERR_CTRL_RX_WARNING (1 << 2) /* Bit 2: Reached warning level for RX errors */ -#define CAN_ERR_CTRL_TX_WARNING (1 << 3) /* Bit 3: Reached warning level for TX errors */ -#define CAN_ERR_CTRL_RX_PASSIVE (1 << 4) /* Bit 4: Reached passive level for RX errors */ -#define CAN_ERR_CTRL_TX_PASSIVE (1 << 5) /* Bit 5: Reached passive level for TX errors */ +#define CAN_ERR_CRTL_UNSPEC 0x00 /* Unspecified error */ +#define CAN_ERR_CRTL_RX_OVERFLOW (1 << 0) /* Bit 0: RX buffer overflow */ +#define CAN_ERR_CRTL_TX_OVERFLOW (1 << 1) /* Bit 1: TX buffer overflow */ +#define CAN_ERR_CRTL_RX_WARNING (1 << 2) /* Bit 2: Reached warning level for RX errors */ +#define CAN_ERR_CRTL_TX_WARNING (1 << 3) /* Bit 3: Reached warning level for TX errors */ +#define CAN_ERR_CRTL_RX_PASSIVE (1 << 4) /* Bit 4: Reached passive level for RX errors */ +#define CAN_ERR_CRTL_TX_PASSIVE (1 << 5) /* Bit 5: Reached passive level for TX errors */ /* Data[2]: Error in CAN protocol. This provides the type of the error. */ From fb88aa87e7b5bd60d7bfb0b81c184bf4c9b2e62b Mon Sep 17 00:00:00 2001 From: raiden00pl Date: Sat, 22 Jan 2022 15:10:27 +0100 Subject: [PATCH 29/43] [BACKPORT] arch/stm32: add FDCAN SocketCAN support --- arch/arm/src/stm32/Kconfig | 12 +- arch/arm/src/stm32/Make.defs | 3 + arch/arm/src/stm32/stm32_fdcan.h | 22 + arch/arm/src/stm32/stm32_fdcan_sock.c | 3196 +++++++++++++++++++++++++ 4 files changed, 3226 insertions(+), 7 deletions(-) create mode 100644 arch/arm/src/stm32/stm32_fdcan_sock.c diff --git a/arch/arm/src/stm32/Kconfig b/arch/arm/src/stm32/Kconfig index 694c0c51ede..ef2dd8814f0 100644 --- a/arch/arm/src/stm32/Kconfig +++ b/arch/arm/src/stm32/Kconfig @@ -2766,14 +2766,12 @@ config STM32_BKPSRAM config STM32_CAN1 bool "CAN1" default n - select CAN select STM32_CAN depends on STM32_HAVE_CAN1 config STM32_CAN2 bool "CAN2" default n - select CAN select STM32_CAN depends on STM32_HAVE_CAN2 @@ -3364,11 +3362,9 @@ config STM32_I2C config STM32_CAN bool - select ARCH_HAVE_CAN_ERRORS config STM32_FDCAN bool - select ARCH_HAVE_CAN_ERRORS config STM32_TIM bool @@ -10669,6 +10665,7 @@ choice config STM32_CAN_CHARDRIVER bool "STM32 CAN character driver support" select ARCH_HAVE_CAN_ERRORS + select CAN config STM32_CAN_SOCKET bool "STM32 CAN SocketCAN support" @@ -10721,11 +10718,12 @@ choice config STM32_FDCAN_CHARDRIVER bool "STM32 FDCAN character driver support" - select ARCH_HAVE_FDCAN_ERRORS + select ARCH_HAVE_CAN_ERRORS + select CAN config STM32_FDCAN_SOCKET - bool "STM32 FDCAN SocketCAN support (not supported yet)" - select NET_FDCAN_HAVE_ERRORS + bool "STM32 FDCAN SocketCAN support" + select NET_CAN_HAVE_ERRORS endchoice # FDCAN character driver or SocketCAN support diff --git a/arch/arm/src/stm32/Make.defs b/arch/arm/src/stm32/Make.defs index 72364491451..b0298ed1783 100644 --- a/arch/arm/src/stm32/Make.defs +++ b/arch/arm/src/stm32/Make.defs @@ -245,6 +245,9 @@ ifeq ($(CONFIG_STM32_FDCAN),y) ifeq ($(CONFIG_STM32_FDCAN_CHARDRIVER),y) CHIP_CSRCS += stm32_fdcan.c endif +ifeq ($(CONFIG_STM32_FDCAN_SOCKET),y) +CHIP_CSRCS += stm32_fdcan_sock.c +endif endif ifeq ($(CONFIG_STM32_IWDG),y) diff --git a/arch/arm/src/stm32/stm32_fdcan.h b/arch/arm/src/stm32/stm32_fdcan.h index 34d2794f746..e895e2b0fe6 100644 --- a/arch/arm/src/stm32/stm32_fdcan.h +++ b/arch/arm/src/stm32/stm32_fdcan.h @@ -65,6 +65,8 @@ extern "C" * Public Function Prototypes ****************************************************************************/ +#ifdef CONFIG_STM32_FDCAN_CHARDRIVER + /**************************************************************************** * Name: stm32_fdcaninitialize * @@ -80,6 +82,26 @@ extern "C" ****************************************************************************/ FAR struct can_dev_s *stm32_fdcaninitialize(int port); +#endif + +#ifdef CONFIG_STM32_FDCAN_SOCKET + +/**************************************************************************** + * Name: stm32_fdcansockinitialize + * + * Description: + * Initialize the selected FDCAN port as SocketCAN interface + * + * Input Parameters: + * Port number (for hardware that has multiple FDCAN interfaces) + * + * Returned Value: + * OK on success; Negated errno on failure. + * + ****************************************************************************/ + +int stm32_fdcansockinitialize(int port); +#endif #undef EXTERN #if defined(__cplusplus) diff --git a/arch/arm/src/stm32/stm32_fdcan_sock.c b/arch/arm/src/stm32/stm32_fdcan_sock.c new file mode 100644 index 00000000000..fafecbedf0a --- /dev/null +++ b/arch/arm/src/stm32/stm32_fdcan_sock.c @@ -0,0 +1,3196 @@ +/**************************************************************************** + * arch/arm/src/stm32/stm32_fdcan_sock.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 + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +#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 + ****************************************************************************/ + +/* Pool configuration *******************************************************/ + +#define POOL_SIZE (1) + +/* Work queue support is required. */ + +#if !defined(CONFIG_SCHED_WORKQUEUE) +# error Work queue support is required +#endif + +/* The low priority work queue is preferred. If it is not enabled, LPWORK + * will be the same as HPWORK. + * + * NOTE: However, the network should NEVER run on the high priority work + * queue! That queue is intended only to service short back end interrupt + * processing that never suspends. Suspending the high priority work queue + * may bring the system to its knees! + */ + +#define CANWORK LPWORK + +/* 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) + +/* 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_RXFIFO0_INTS (FDCAN_INT_RF0N | FDCAN_INT_RF0L) +#define FDCAN_RXFIFO1_INTS (FDCAN_INT_RF1N | FDCAN_INT_RF1L) + +#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_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_NET_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 */ +#ifdef CONFIG_CAN_FD + FDCAN_FD_MODE = 1, /* CAN FD operation */ + FDCAN_FD_BRS_MODE = 2 /* CAN FD operation with bit rate switching */ +#endif +}; + +/* 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 +{ + volatile uint32_t *stdfilters; /* Standard filters */ + volatile uint32_t *extfilters; /* Extended filters */ + volatile uint32_t *rxfifo0; /* RX FIFO0 */ + volatile uint32_t *rxfifo1; /* RX FIFO1 */ + volatile uint32_t *txeventfifo; /* TX event FIFO */ + volatile 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 */ + +#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 + + bool bifup; /* true:ifup false:ifdown */ + struct net_driver_s dev; /* Interface understood by the network */ + + struct work_s irqwork; /* For deferring interrupt work to the wq */ + struct work_s pollwork; /* For deferring poll work to the work wq */ + + /* A pointers to the list of TX/RX descriptors */ + + FAR struct can_frame *txdesc; + FAR struct can_frame *rxdesc; + + /* TX/RX pool */ + + uint8_t tx_pool[sizeof(struct can_frame)*POOL_SIZE]; + uint8_t rx_pool[sizeof(struct can_frame)*POOL_SIZE]; +}; + +/**************************************************************************** + * 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 + +/* CAN interrupt enable functions */ + +static void fdcan_rx0int(FAR struct stm32_fdcan_s *priv, bool enable); +static void fdcan_rx1int(FAR struct stm32_fdcan_s *priv, bool enable); +static void fdcan_txint(FAR struct stm32_fdcan_s *priv, bool enable); +#ifdef CONFIG_NET_CAN_ERRORS +static void fdcan_errint(FAR struct stm32_fdcan_s *priv, bool enable); +#endif + +/* Common TX logic */ + +static int fdcan_send(FAR struct stm32_fdcan_s *priv); +static bool fdcan_txready(FAR struct stm32_fdcan_s *priv); +static int fdcan_txpoll(struct net_driver_s *dev); + +/* CAN RX interrupt handling */ + +static void fdcan_rx0interrupt_work(FAR void *arg); +static void fdcan_rx1interrupt_work(FAR void *arg); + +/* CAN TX interrupt handling */ + +static void fdcan_txdone_work(FAR void *arg); +static void fdcan_txdone(FAR struct stm32_fdcan_s *priv); + +#ifdef CONFIG_NET_CAN_ERRORS +/* CAN errors interrupt handling */ + +static void fdcan_error_work(FAR void *arg); +#endif + +/* FDCAN interrupt handling */ + +#ifdef CONFIG_NET_CAN_ERRORS +static void fdcan_error(FAR struct stm32_fdcan_s *priv, uint32_t status); +#endif +static void fdcan_receive(FAR struct stm32_fdcan_s *priv, + FAR volatile uint32_t *rxbuffer, + unsigned long nwords); +static int fdcan_interrupt(int irq, void *context, FAR void *arg); + +/* Initialization */ + +static void fdcan_reset(FAR struct stm32_fdcan_s *priv); +static int fdcan_setup(FAR struct stm32_fdcan_s *priv); +static void fdcan_shutdown(FAR struct stm32_fdcan_s *priv); + +/* FDCAN helpers */ + +static uint8_t fdcan_dlc2bytes(FAR struct stm32_fdcan_s *priv, uint8_t dlc); + +#if 0 /* not used for now */ +static int +fdcan_start_busoff_recovery_sequence(FAR struct stm32_fdcan_s *priv); +#endif + +/* Hardware initialization */ + +static int fdcan_hw_initialize(FAR struct stm32_fdcan_s *priv); + +/* NuttX callback functions */ + +static int fdcan_ifup(struct net_driver_s *dev); +static int fdcan_ifdown(struct net_driver_s *dev); + +static void fdcan_txavail_work(FAR void *arg); +static int fdcan_txavail(struct net_driver_s *dev); + +#ifdef CONFIG_NETDEV_IOCTL +static int fdcan_netdev_ioctl(struct net_driver_s *dev, int cmd, + unsigned long arg); +#endif + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +#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; + +#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; + +#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; + +#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) + { + ninfo("...\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 */ + + ninfo("[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 */ + + ninfo("%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 */ + + ninfo("%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; + + ninfo("CAN%d Control and Status Registers: %s\n", config->port, msg); + ninfo(" Base: %08" PRIx32 "\n", config->base); + + /* CAN control and status registers */ + + ninfo(" CCCR: %08" PRIx32 " TEST: %08" PRIx32 "\n", + getreg32(config->base + STM32_FDCAN_CCCR_OFFSET), + getreg32(config->base + STM32_FDCAN_TEST_OFFSET)); + + ninfo(" NBTP: %08" PRIx32 " DBTP: %08" PRIx32 "\n", + getreg32(config->base + STM32_FDCAN_NBTP_OFFSET), + getreg32(config->base + STM32_FDCAN_DBTP_OFFSET)); + + ninfo(" IE: %08" PRIx32 " TIE: %08" PRIx32 "\n", + getreg32(config->base + STM32_FDCAN_IE_OFFSET), + getreg32(config->base + STM32_FDCAN_TXBTIE_OFFSET)); + + ninfo(" ILE: %08" PRIx32 " ILS: %08" PRIx32 "\n", + getreg32(config->base + STM32_FDCAN_ILE_OFFSET), + getreg32(config->base + STM32_FDCAN_ILS_OFFSET)); + + ninfo(" TXBC: %08" PRIx32 "\n", + getreg32(config->base + STM32_FDCAN_TXBC_OFFSET)); +} +#endif + +/**************************************************************************** + * Name: fdcan_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; + + ninfo("CAN%d Rx Registers: %s\n", config->port, msg); + ninfo(" Base: %08" PRIx32 "\n", config->base); + + ninfo(" 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)); + + ninfo(" RXF0S: %08" PRIx32 " RXF0A: %08" PRIx32 "\n", + getreg32(config->base + STM32_FDCAN_RXF0S_OFFSET), + getreg32(config->base + STM32_FDCAN_RXF0A_OFFSET)); + + ninfo(" RXF1S: %08" PRIx32 " RXF1A: %08" PRIx32 "\n", + getreg32(config->base + STM32_FDCAN_RXF1S_OFFSET), + getreg32(config->base + STM32_FDCAN_RXF1A_OFFSET)); + + ninfo(" IR: %08" PRIx32 " IE: %08" PRIx32 "\n", + getreg32(config->base + STM32_FDCAN_IR_OFFSET), + getreg32(config->base + STM32_FDCAN_IE_OFFSET)); +} +#endif + +/**************************************************************************** + * Name: fdcan_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; + + ninfo("CAN%d Tx Registers: %s\n", config->port, msg); + ninfo(" Base: %08" PRIx32 "\n", config->base); + + ninfo(" PSR: %08" PRIx32 " ECR: %08" PRIx32 "\n", + getreg32(config->base + STM32_FDCAN_PSR_OFFSET), + getreg32(config->base + STM32_FDCAN_ECR_OFFSET)); + + ninfo(" 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)); + + ninfo(" TXBTO: %08" PRIx32 " TXBCR: %08" PRIx32 "\n", + getreg32(config->base + STM32_FDCAN_TXBTO_OFFSET), + getreg32(config->base + STM32_FDCAN_TXBCR_OFFSET)); + + ninfo(" TXEFS: %08" PRIx32 " TXEFA: %08" PRIx32 "\n", + getreg32(config->base + STM32_FDCAN_TXEFS_OFFSET), + getreg32(config->base + STM32_FDCAN_TXEFA_OFFSET)); + + ninfo(" 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: fdcan_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; + + ninfo(" ******* FDCAN%d Message RAM layout *******\n", config->port); + ninfo(" Start # Elmnt Elmnt size (words)\n"); + + if (config->nstdfilters > 0) + { + ninfo("STD filters %p %4d %2d\n", + config->msgram.stdfilters, + config->nstdfilters, + 1); + } + + if (config->nextfilters > 0) + { + ninfo("EXT filters %p %4d %2d\n", + config->msgram.extfilters, + config->nextfilters, + 2); + } + + if (config->nrxfifo0 > 0) + { + ninfo("RX FIFO 0 %p %4d %2d\n", + config->msgram.rxfifo0, + config->nrxfifo0, + config->rxfifo0esize); + } + + if (config->nrxfifo1 > 0) + { + ninfo("RX FIFO 1 %p %4d %2d\n", + config->msgram.rxfifo1, + config->nrxfifo1, + config->rxfifo1esize); + } + + if (config->ntxeventfifo > 0) + { + ninfo("TX EVENT %p %4d %2d\n", + config->msgram.txeventfifo, + config->ntxeventfifo, + config->txeventesize); + } + + if (config->ntxfifoq > 0) + { + ninfo("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_start_busoff_recovery_sequence + * + * Description: + * This function initiates the BUS-OFF recovery sequence. + * CAN Specification Rev. 2.0 or ISO11898-1:2015. + * According the STM32G4 datasheet section 44.3.2 Software initialziation. + * + * Input Parameters: + * priv - An instance of the FDCAN driver state structure. + * + * Returned Value: + * Zero (OK) is returned on success. Otherwise a negated errno value is + * returned to indicate the nature of the error. + * + ****************************************************************************/ + +#if 0 /* not used for now */ +static int +fdcan_start_busoff_recovery_sequence(FAR struct stm32_fdcan_s *priv) +{ + uint32_t regval = 0; + + DEBUGASSERT(priv); + + /* Only start BUS-OFF recovery if we are in BUS-OFF state */ + + regval = fdcan_getreg(priv, STM32_FDCAN_PSR_OFFSET); + if ((regval & FDCAN_PSR_BO) == 0) + { + return -EPERM; + } + + /* Disable initialization mode to issue the recovery sequence */ + + regval = fdcan_getreg(priv, STM32_FDCAN_CCCR_OFFSET); + regval &= ~FDCAN_CCCR_INIT; + fdcan_putreg(priv, STM32_FDCAN_CCCR_OFFSET, regval); + + return OK; +} +#endif + +/**************************************************************************** + * Name: fdcan_reset + * + * Description: + * Reset the FDCAN device. Called early to initialize the hardware. This + * function is called, before fdcan_setup() and on error conditions. + * + * Input Parameters: + * dev - An instance of the "upper half" can driver state structure. + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void fdcan_reset(FAR struct stm32_fdcan_s *priv) +{ + FAR const struct stm32_config_s *config = NULL; + uint32_t regval = 0; + irqstate_t flags; + + DEBUGASSERT(priv); + config = priv->config; + DEBUGASSERT(config); + + ninfo("FDCAN%d\n", config->port); + UNUSED(config); + + /* Disable all interrupts */ + + fdcan_putreg(priv, STM32_FDCAN_IE_OFFSET, 0); + fdcan_putreg(priv, STM32_FDCAN_TXBTIE_OFFSET, 0); + + /* Make sure that all buffers are released. + * + * REVISIT: What if a thread is waiting for a buffer? The following + * will not wake up any waiting threads. + */ + + /* Disable the FDCAN controller. + * REVISIT: Should fdcan_shutdown() be called here? + */ + + /* Reset the FD CAN. + * REVISIT: Since there is only a single reset for both FDCAN + * controllers, do we really want to use the RCC reset here? + * This will nuke operation of the second controller if another + * device is registered. + */ + + flags = enter_critical_section(); + regval = getreg32(STM32_RCC_APB1RSTR1); + regval |= RCC_APB1RSTR1_FDCANRST; + putreg32(regval, STM32_RCC_APB1RSTR1); + + regval &= ~RCC_APB1RSTR1_FDCANRST; + putreg32(regval, STM32_RCC_APB1RSTR1); + leave_critical_section(flags); + + priv->state = FDCAN_STATE_RESET; +} + +/**************************************************************************** + * Name: fdcan_setup + * + * Description: + * Configure the FDCAN. This method is called the first time that the FDCAN + * device is opened. This will occur when the port is first opened. + * This setup includes configuring and attaching FDCAN interrupts. + * All FDCAN interrupts are disabled upon return. + * + * 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 fdcan_setup(FAR struct stm32_fdcan_s *priv) +{ + FAR const struct stm32_config_s *config = NULL; + int ret = 0; + + DEBUGASSERT(priv); + config = priv->config; + DEBUGASSERT(config); + + ninfo("FDCAN%d\n", config->port); + + /* FDCAN hardware initialization */ + + ret = fdcan_hw_initialize(priv); + if (ret < 0) + { + nerr("ERROR: FDCAN%d H/W initialization failed: %d\n", + config->port, ret); + return ret; + } + + fdcan_dumpregs(priv, "After hardware initialization"); + + /* Attach the FDCAN interrupt handlers */ + + ret = irq_attach(config->irq0, fdcan_interrupt, priv); + if (ret < 0) + { + nerr("ERROR: Failed to attach FDCAN%d line 0 IRQ (%d)", + config->port, config->irq0); + return ret; + } + + ret = irq_attach(config->irq1, fdcan_interrupt, priv); + if (ret < 0) + { + nerr("ERROR: Failed to attach FDCAN%d line 1 IRQ (%d)", + config->port, config->irq1); + return ret; + } + + priv->state = FDCAN_STATE_SETUP; + + /* Enable the interrupts at the NVIC (they are still disabled at the FDCAN + * peripheral). + */ + + up_enable_irq(config->irq0); + up_enable_irq(config->irq1); + + return OK; +} + +/**************************************************************************** + * Name: fdcan_shutdown + * + * Description: + * Disable the FDCAN. This method is called when the FDCAN 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 fdcan_shutdown(FAR struct stm32_fdcan_s *priv) +{ + FAR const struct stm32_config_s *config = NULL; + uint32_t regval = 0; + + DEBUGASSERT(priv); + config = priv->config; + DEBUGASSERT(config); + + ninfo("FDCAN%d\n", config->port); + + /* Disable FDCAN interrupts at the NVIC */ + + up_disable_irq(config->irq0); + up_disable_irq(config->irq1); + + /* Disable all interrupts from the FDCAN peripheral */ + + fdcan_putreg(priv, STM32_FDCAN_IE_OFFSET, 0); + fdcan_putreg(priv, STM32_FDCAN_TXBTIE_OFFSET, 0); + + /* Detach the FDCAN interrupt handler */ + + irq_detach(config->irq0); + irq_detach(config->irq1); + + /* Disable device by setting the Clock Stop Request bit */ + + regval = fdcan_getreg(priv, STM32_FDCAN_CCCR_OFFSET); + regval |= FDCAN_CCCR_CSR; + fdcan_putreg(priv, STM32_FDCAN_CCCR_OFFSET, regval); + + /* Wait for Init and Clock Stop Acknowledge bits to verify + * device is in the powered down state + */ + + while ((fdcan_getreg(priv, STM32_FDCAN_CCCR_OFFSET) & FDCAN_CCCR_INIT) + == 0); + while ((fdcan_getreg(priv, STM32_FDCAN_CCCR_OFFSET) & FDCAN_CCCR_CSA) + == 0); + priv->state = FDCAN_STATE_DISABLED; +} + +/**************************************************************************** + * Name: fdcan_rx0int + * + * Description: + * Call to enable or disable RX0 interrupts. + * + * Input Parameters: + * priv - reference to the private CAN driver state structure + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void fdcan_rx0int(FAR struct stm32_fdcan_s *priv, bool enable) +{ + FAR const struct stm32_config_s *config = NULL; + uint32_t regval = 0; + + DEBUGASSERT(priv); + config = priv->config; + DEBUGASSERT(config); + + ninfo("CAN%" PRIu8 "RX0 enable: %d\n", config->port, enable); + + /* Enable/disable the FIFO 0 message pending interrupt */ + + regval = fdcan_getreg(priv, STM32_FDCAN_IE_OFFSET); + + if (enable) + { + regval |= FDCAN_RXFIFO0_INTS; + } + else + { + regval &= ~FDCAN_RXFIFO0_INTS; + } + + fdcan_putreg(priv, STM32_FDCAN_IE_OFFSET, regval); +} + +/**************************************************************************** + * Name: fdcan_rx1int + * + * Description: + * Call to enable or disable RX1 interrupts. + * + * Input Parameters: + * priv - reference to the private CAN driver state structure + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void fdcan_rx1int(FAR struct stm32_fdcan_s *priv, bool enable) +{ + FAR const struct stm32_config_s *config = NULL; + uint32_t regval = 0; + + DEBUGASSERT(priv); + config = priv->config; + DEBUGASSERT(config); + + ninfo("CAN%" PRIu8 "RX1 enable: %d\n", config->port, enable); + + /* Enable/disable the FIFO 1 message pending interrupt */ + + regval = fdcan_getreg(priv, STM32_FDCAN_IE_OFFSET); + + if (enable) + { + regval |= FDCAN_RXFIFO1_INTS; + } + else + { + regval &= ~FDCAN_RXFIFO1_INTS; + } + + fdcan_putreg(priv, STM32_FDCAN_IE_OFFSET, regval); +} + +/**************************************************************************** + * Name: fdcan_txint + * + * Description: + * Call to enable or disable TX interrupts. + * + * Input Parameters: + * dev - An instance of the "upper half" can driver state structure. + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void fdcan_txint(FAR struct stm32_fdcan_s *priv, bool enable) +{ + FAR const struct stm32_config_s *config = NULL; + uint32_t regval = 0; + + DEBUGASSERT(priv); + config = priv->config; + DEBUGASSERT(config); + + ninfo("CAN%" PRIu8 "TX enable: %d\n", config->port, enable); + + /* Enable/disable the receive interrupts */ + + regval = fdcan_getreg(priv, STM32_FDCAN_IE_OFFSET); + + if (enable) + { + regval |= FDCAN_TXFIFOQ_INTS; + } + else + { + regval &= ~FDCAN_TXFIFOQ_INTS; + } + + fdcan_putreg(priv, STM32_FDCAN_IE_OFFSET, regval); +} + +#ifdef CONFIG_NET_CAN_ERRORS +/**************************************************************************** + * Name: fdcan_txint + * + * Description: + * Call to enable or disable CAN SCE interrupts. + * + * Input Parameters: + * priv - reference to the private CAN driver state structure + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void fdcan_errint(FAR struct stm32_fdcan_s *priv, bool enable) +{ + FAR const struct stm32_config_s *config = NULL; + uint32_t regval = 0; + + DEBUGASSERT(priv); + config = priv->config; + DEBUGASSERT(config); + + ninfo("CAN%" PRIu8 "ERR enable: %d\n", config->port, enable); + + /* Enable/disable the transmit mailbox interrupt */ + + regval = fdcan_getreg(priv, STM32_FDCAN_IE_OFFSET); + if (enable) + { + regval |= FDCAN_ANYERR_INTS; + } + else + { + regval &= ~FDCAN_ANYERR_INTS; + } + + fdcan_putreg(priv, STM32_FDCAN_IE_OFFSET, regval); +} +#endif + +/**************************************************************************** + * Name: fdcan_send + * + * Description: + * Send one can message. + * + * One CAN-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 CAN identifier + * Byte 1: Bits 5-7: Bits 0-2 of the 11-bit CAN identifier + * Bit 4: Remote Transmission Request (RTR) + * Bits 0-3: Data Length Code (DLC) + * Bytes 2-10: CAN data + * + * 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 fdcan_send(FAR struct stm32_fdcan_s *priv) +{ + struct can_frame *frame = NULL; + FAR const struct stm32_config_s *config = NULL; + FAR volatile uint32_t *txbuffer = NULL; + FAR const uint8_t *src = NULL; + FAR uint32_t *dest = NULL; + uint32_t regval = 0; + unsigned int ndx = 0; + unsigned int nbytes = 0; + uint32_t wordbuffer = 0; + unsigned int i = 0; + + DEBUGASSERT(priv); + config = priv->config; + DEBUGASSERT(config); + + frame = (struct can_frame *)priv->dev.d_buf; + + ninfo("CAN%" PRIu8 " ID: %" PRIu32 " DLC: %" PRIu8 "\n", + config->port, (uint32_t)frame->can_id, frame->can_dlc); + + fdcan_dumptxregs(priv, "Before send"); + + /* That that FIFO elements were configured */ + + DEBUGASSERT(config->ntxfifoq > 0); + + /* Get our reserved Tx FIFO/queue put index */ + + regval = fdcan_getreg(priv, STM32_FDCAN_TXFQS_OFFSET); + DEBUGASSERT((regval & FDCAN_TXFQS_TFQF) == 0); + + ndx = (regval & FDCAN_TXFQS_TFQPI_MASK) >> FDCAN_TXFQS_TFQPI_SHIFT; + + /* And the TX buffer corresponding to this index */ + + txbuffer = (config->msgram.txfifoq + ndx * config->txbufferesize); + + /* Format the TX FIFOQ entry + * + * Format word T0: + * Transfer message ID (ID) - Value from message structure + * Remote Transmission Request (RTR) - Value from message structure + * Extended Identifier (XTD) - Depends on configuration. + */ + +#ifdef CONFIG_CAN_EXTID + if (frame->can_id & CAN_EFF_FLAG) + { + DEBUGASSERT(frame->can_id < (1 << 29)); + + regval = BUFFER_R0_EXTID(frame->can_id) | BUFFER_R0_XTD; + } + else +#endif + { + DEBUGASSERT(frame->can_id < (1 << 11)); + + regval = BUFFER_R0_STDID(frame->can_id); + } + + if (frame->can_id & CAN_RTR_FLAG) + { + regval |= BUFFER_R0_RTR; + } + + txbuffer[0] = regval; + + /* Format word T1: + * Data Length Code (DLC) - Value from message structure + * Event FIFO Control (EFC) - Do not store events. + * Message Marker (MM) - Always zero + */ + + txbuffer[1] = BUFFER_R1_DLC(frame->can_dlc); + + /* Followed by the amount of data corresponding to the DLC (T2..) */ + + dest = (FAR uint32_t *)&txbuffer[2]; + src = frame->data; + nbytes = fdcan_dlc2bytes(priv, frame->can_dlc); + + /* Writes must be word length */ + + for (i = 0; i < nbytes; i += 4) + { + /* Little endian is assumed */ + + wordbuffer = src[0] | + (src[1] << 8) | + (src[2] << 16) | + (src[3] << 24); + src += 4; + + *dest++ = wordbuffer; + } + + /* Enable transmit interrupts from the TX FIFOQ buffer by setting TC + * interrupt bit in IR (also requires that the TC interrupt is enabled) + */ + + fdcan_putreg(priv, STM32_FDCAN_TXBTIE_OFFSET, (1 << ndx)); + + /* And request to send the packet */ + + fdcan_putreg(priv, STM32_FDCAN_TXBAR_OFFSET, (1 << ndx)); + + return OK; +} + +/**************************************************************************** + * Name: fdcan_txready + * + * Description: + * Return true if the FDCAN hardware can accept another TX message. + * + * Input Parameters: + * dev - An instance of the "upper half" can driver state structure. + * + * Returned Value: + * True if the FDCAN hardware is ready to accept another TX message. + * + ****************************************************************************/ + +static bool fdcan_txready(FAR struct stm32_fdcan_s *priv) +{ + uint32_t regval = 0; + bool notfull = false; + + /* Return the state of the TX FIFOQ. Return TRUE if the TX FIFO/Queue is + * not full. + */ + + regval = fdcan_getreg(priv, STM32_FDCAN_TXFQS_OFFSET); + notfull = ((regval & FDCAN_TXFQS_TFQF) == 0); + + return notfull; +} + +/**************************************************************************** + * Name: fdcan_rx0interrupt_work + * + * Description: + * CAN RX FIFO 0 worker + * + ****************************************************************************/ + +static void fdcan_rx0interrupt_work(FAR void *arg) +{ + FAR struct stm32_fdcan_s *priv = (FAR struct stm32_fdcan_s *)arg; + FAR const struct stm32_config_s *config = NULL; + uint32_t regval = 0; + unsigned int nelem = 0; + unsigned int ndx = 0; + + DEBUGASSERT(priv); + config = priv->config; + DEBUGASSERT(config); + + /* Clear the RX FIFO0 new message interrupt */ + + fdcan_putreg(priv, STM32_FDCAN_IR_OFFSET, FDCAN_INT_RF0N); + + regval = fdcan_getreg(priv, STM32_FDCAN_RXF0S_OFFSET); + nelem = (regval & FDCAN_RXFS_FFL_MASK) >> FDCAN_RXFS_FFL_SHIFT; + if (nelem > 0) + { + /* Handle the newly received message in FIFO0 */ + + ndx = (regval & FDCAN_RXFS_FGI_MASK) >> FDCAN_RXFS_FGI_SHIFT; + + if ((regval & FDCAN_RXFS_RFL) != 0) + { + nerr("ERROR: Message lost: %08" PRIx32 "\n", regval); + } + else + { + fdcan_receive(priv, + config->msgram.rxfifo0 + + (ndx * priv->config->rxfifo0esize), + priv->config->rxfifo0esize); + +#ifdef CONFIG_NET_CAN_ERRORS + /* Turning back on all configured RX error interrupts */ + + regval = fdcan_getreg(priv, STM32_FDCAN_IE_OFFSET); + regval |= FDCAN_RXERR_INTS; + fdcan_putreg(priv, STM32_FDCAN_IE_OFFSET, regval); +#endif + } + + /* Acknowledge reading the FIFO entry */ + + fdcan_putreg(priv, STM32_FDCAN_RXF0A_OFFSET, ndx); + } + + /* Re-enable CAN RX interrupts */ + + fdcan_rx0int(priv, true); +} + +/**************************************************************************** + * Name: fdcan_rx1interrupt_work + * + * Description: + * CAN RX FIFO 1 worker + * + ****************************************************************************/ + +static void fdcan_rx1interrupt_work(FAR void *arg) +{ + FAR struct stm32_fdcan_s *priv = (FAR struct stm32_fdcan_s *)arg; + FAR const struct stm32_config_s *config = NULL; + uint32_t regval = 0; + unsigned int nelem = 0; + unsigned int ndx = 0; + + DEBUGASSERT(priv); + config = priv->config; + DEBUGASSERT(config); + + /* Clear the RX FIFO1 new message interrupt */ + + fdcan_putreg(priv, STM32_FDCAN_IR_OFFSET, FDCAN_INT_RF1N); + + /* Check if there is anything in RX FIFO1 */ + + regval = fdcan_getreg(priv, STM32_FDCAN_RXF1S_OFFSET); + nelem = (regval & FDCAN_RXFS_FFL_MASK) >> FDCAN_RXFS_FFL_SHIFT; + if (nelem == 0) + { + /* Clear the RX FIFO1 interrupt (and all other FIFO1-related + * interrupts) + */ + + /* Handle the newly received message in FIFO1 */ + + ndx = (regval & FDCAN_RXFS_FGI_MASK) >> FDCAN_RXFS_FGI_SHIFT; + + if ((regval & FDCAN_RXFS_RFL) != 0) + { + nerr("ERROR: Message lost: %08" PRIx32 "\n", regval); + } + else + { + fdcan_receive(priv, + config->msgram.rxfifo1 + + (ndx * priv->config->rxfifo1esize), + priv->config->rxfifo1esize); + +#ifdef CONFIG_NET_CAN_ERRORS + /* Turning back on all configured RX error interrupts */ + + regval = fdcan_getreg(priv, STM32_FDCAN_IE_OFFSET); + regval |= FDCAN_RXERR_INTS; + fdcan_putreg(priv, STM32_FDCAN_IE_OFFSET, regval); +#endif + } + + /* Acknowledge reading the FIFO entry */ + + fdcan_putreg(priv, STM32_FDCAN_RXF1A_OFFSET, ndx); + } + + /* Re-enable CAN RX interrupts */ + + fdcan_rx1int(priv, true); +} + +/**************************************************************************** + * Name: fdcan_txdone_work + ****************************************************************************/ + +static void fdcan_txdone_work(FAR void *arg) +{ + FAR struct stm32_fdcan_s *priv = (FAR struct stm32_fdcan_s *)arg; + + fdcan_txdone(priv); + + /* There should be space for a new TX in any event. Poll the network for + * new XMIT data + */ + + net_lock(); + devif_timer(&priv->dev, 0, fdcan_txpoll); + net_unlock(); +} + +/**************************************************************************** + * Name: fdcan_txdone + ****************************************************************************/ + +static void fdcan_txdone(FAR struct stm32_fdcan_s *priv) +{ + FAR const struct stm32_config_s *config = NULL; + unsigned int ndx = 0; + uint32_t regval = 0; + + DEBUGASSERT(priv); + config = priv->config; + DEBUGASSERT(config); + + /* Clear the pending TX completion interrupt (and all + * other TX-related interrupts) + */ + + fdcan_putreg(priv, STM32_FDCAN_IR_OFFSET, FDCAN_TXFIFOQ_INTS); + + /* Check all TX buffers */ + + regval = fdcan_getreg(priv, STM32_FDCAN_TXBTO_OFFSET); + for (ndx = 0; ndx < config->ntxfifoq; ndx++) + { + if ((regval & (1 << ndx)) != 0) + { + /* Tell the upper half that the transfer is finished. */ + + NETDEV_TXDONE(&priv->dev); + } + } + +#ifdef CONFIG_NET_CAN_ERRORS + /* Turning back on PEA and PED error interrupts */ + + regval = fdcan_getreg(priv, STM32_FDCAN_IE_OFFSET); + regval |= (FDCAN_INT_PEA | FDCAN_INT_PED); + fdcan_putreg(priv, STM32_FDCAN_IE_OFFSET, regval); +#endif + + /* Re-enable TX interrupts */ + + fdcan_txint(priv, true); +} + +#ifdef CONFIG_NET_CAN_ERRORS +/**************************************************************************** + * Name: fdcan_error_work + ****************************************************************************/ + +static void fdcan_error_work(FAR void *arg) +{ + FAR struct stm32_fdcan_s *priv = (FAR struct stm32_fdcan_s *)arg; + uint32_t pending = 0; + uint32_t ir = 0; + uint32_t ie = 0; + uint32_t psr = 0; + + /* Get the set of pending interrupts. */ + + ir = fdcan_getreg(priv, STM32_FDCAN_IR_OFFSET); + ie = fdcan_getreg(priv, STM32_FDCAN_IE_OFFSET); + + pending = (ir & ie); + + /* Check for common errors */ + + if ((pending & FDCAN_CMNERR_INTS) != 0) + { + /* When a protocol error ocurrs, the problem is recorded in + * the LEC/DLEC fields of the PSR register. In lieu of + * seprate interrupt flags for each error, the hardware + * groups procotol errors under a single interrupt each for + * arbitration and data phases. + * + * These errors have a tendency to flood the system with + * interrupts, so they are disabled here until we get a + * successful transfer/receive on the hardware + */ + + psr = fdcan_getreg(priv, STM32_FDCAN_PSR_OFFSET); + + if ((psr & FDCAN_PSR_LEC_MASK) != 0) + { + ie &= ~(FDCAN_INT_PEA | FDCAN_INT_PED); + fdcan_putreg(priv, STM32_FDCAN_IE_OFFSET, ie); + } + + /* Clear the error indications */ + + fdcan_putreg(priv, STM32_FDCAN_IR_OFFSET, FDCAN_CMNERR_INTS); + } + + /* Check for transmission errors */ + + if ((pending & FDCAN_TXERR_INTS) != 0) + { + /* An Acknowledge-Error will occur if for example the device + * is not connected to the bus. + * + * The CAN-Standard states that the Chip has to retry the + * message forever, which will produce an ACKE every time. + * To prevent this Interrupt-Flooding and the high CPU-Load + * we disable the ACKE here as long we didn't transfer at + * least one message successfully (see FDCAN_INT_TC below). + */ + + /* Clear the error indications */ + + fdcan_putreg(priv, STM32_FDCAN_IR_OFFSET, FDCAN_TXERR_INTS); + } + + /* Check for reception errors */ + + if ((pending & FDCAN_RXERR_INTS) != 0) + { + /* To prevent Interrupt-Flooding the current active + * RX error interrupts are disabled. After successfully + * receiving at least one CAN packet all RX error interrupts + * are turned back on. + * + * The Interrupt-Flooding can for example occur if the + * configured CAN speed does not match the speed of the other + * CAN nodes in the network. + */ + + ie &= ~(pending & FDCAN_RXERR_INTS); + fdcan_putreg(priv, STM32_FDCAN_IE_OFFSET, ie); + + /* Clear the error indications */ + + fdcan_putreg(priv, STM32_FDCAN_IR_OFFSET, FDCAN_RXERR_INTS); + } + + /* Report errors */ + + fdcan_error(priv, pending & FDCAN_ANYERR_INTS); + + /* Re-enable ERROR interrupts */ + + fdcan_errint(priv, true); +} + +/**************************************************************************** + * Name: fdcan_error + * + * Description: + * Report a CAN error + * + * Input Parameters: + * dev - CAN-common state data + * status - Interrupt status with error bits set + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void fdcan_error(FAR struct stm32_fdcan_s *priv, uint32_t status) +{ + struct can_frame *frame = (struct can_frame *)priv->rxdesc; + uint32_t psr = 0; + uint16_t errbits = 0; + uint8_t data[CAN_ERR_DLC]; + + DEBUGASSERT(priv != NULL); + + /* Encode error bits */ + + errbits = 0; + memset(data, 0, sizeof(data)); + + /* Always fill in "static" error conditions, but set the signaling bit + * only if the condition has changed (see IRQ-Flags below) + * They have to be filled in every time CAN_ERROR_CONTROLLER is set. + */ + + psr = fdcan_getreg(priv, STM32_FDCAN_PSR_OFFSET); + if ((psr & FDCAN_PSR_EP) != 0) + { + data[1] |= (CAN_ERR_CRTL_RX_PASSIVE | CAN_ERR_CRTL_TX_PASSIVE); + } + + if ((psr & FDCAN_PSR_EW) != 0) + { + data[1] |= (CAN_ERR_CRTL_RX_WARNING | CAN_ERR_CRTL_TX_WARNING); + } + + if ((status & (FDCAN_INT_EP | FDCAN_INT_EW)) != 0) + { + /* "Error Passive" or "Error Warning" status changed */ + + errbits |= CAN_ERR_CRTL; + } + + if ((status & FDCAN_INT_PEA) != 0) + { + /* Protocol Error in Arbitration Phase */ + + if ((psr & FDCAN_PSR_LEC_MASK) != 0) + { + /* Error code present */ + + if ((psr & FDCAN_PSR_LEC(FDCAN_PSR_EC_STUFF_ERROR)) != 0) + { + /* Stuff Error */ + + errbits |= CAN_ERR_PROT; + data[2] |= CAN_ERR_PROT_STUFF; + } + + if ((psr & FDCAN_PSR_LEC(FDCAN_PSR_EC_FORM_ERROR)) != 0) + { + /* Format Error */ + + errbits |= CAN_ERR_PROT; + data[2] |= CAN_ERR_PROT_FORM; + } + + if ((psr & FDCAN_PSR_LEC(FDCAN_PSR_EC_ACK_ERROR)) != 0) + { + /* Acknowledge Error */ + + errbits |= CAN_ERR_ACK; + } + + if ((psr & FDCAN_PSR_LEC(FDCAN_PSR_EC_BIT0_ERROR)) != 0) + { + /* Bit0 Error */ + + errbits |= CAN_ERR_PROT; + data[2] |= CAN_ERR_PROT_BIT0; + } + + if ((psr & FDCAN_PSR_LEC(FDCAN_PSR_EC_BIT1_ERROR)) != 0) + { + /* Bit1 Error */ + + errbits |= CAN_ERR_PROT; + data[2] |= CAN_ERR_PROT_BIT1; + } + + if ((psr & FDCAN_PSR_LEC(FDCAN_PSR_EC_CRC_ERROR)) != 0) + { + /* Receive CRC Error */ + + errbits |= CAN_ERR_PROT; + data[3] |= (CAN_ERR_PROT_LOC_CRCSEQ | CAN_ERR_PROT_LOC_CRCDEL); + } + + if ((psr & FDCAN_PSR_LEC(FDCAN_PSR_EC_NO_CHANGE)) != 0) + { + /* No Change in Error */ + + errbits |= CAN_ERR_PROT; + data[2] |= CAN_ERR_PROT_UNSPEC; + } + } + } + + if ((status & FDCAN_INT_PED) != 0) + { + /* Protocol Error in Data Phase */ + + if ((psr & FDCAN_PSR_DLEC_MASK) != 0) + { + /* Error code present */ + + if ((psr & FDCAN_PSR_DLEC(FDCAN_PSR_EC_STUFF_ERROR)) != 0) + { + /* Stuff Error */ + + errbits |= CAN_ERR_PROT; + data[2] |= CAN_ERR_PROT_STUFF; + } + + if ((psr & FDCAN_PSR_DLEC(FDCAN_PSR_EC_FORM_ERROR)) != 0) + { + /* Format Error */ + + errbits |= CAN_ERR_PROT; + data[2] |= CAN_ERR_PROT_FORM; + } + + if ((psr & FDCAN_PSR_DLEC(FDCAN_PSR_EC_ACK_ERROR)) != 0) + { + /* Acknowledge Error */ + + errbits |= CAN_ERR_ACK; + } + + if ((psr & FDCAN_PSR_DLEC(FDCAN_PSR_EC_BIT0_ERROR)) != 0) + { + /* Bit0 Error */ + + errbits |= CAN_ERR_PROT; + data[2] |= CAN_ERR_PROT_BIT0; + } + + if ((psr & FDCAN_PSR_DLEC(FDCAN_PSR_EC_BIT1_ERROR)) != 0) + { + /* Bit1 Error */ + + errbits |= CAN_ERR_PROT; + data[2] |= CAN_ERR_PROT_BIT1; + } + + if ((psr & FDCAN_PSR_DLEC(FDCAN_PSR_EC_CRC_ERROR)) != 0) + { + /* Receive CRC Error */ + + errbits |= CAN_ERR_PROT; + data[3] |= (CAN_ERR_PROT_LOC_CRCSEQ | CAN_ERR_PROT_LOC_CRCDEL); + } + + if ((psr & FDCAN_PSR_DLEC(FDCAN_PSR_EC_NO_CHANGE)) != 0) + { + /* No Change in Error */ + + errbits |= CAN_ERR_PROT; + data[2] |= CAN_ERR_PROT_UNSPEC; + } + } + } + + if ((status & FDCAN_INT_BO) != 0) + { + /* Bus_Off Status changed */ + + if ((psr & FDCAN_PSR_BO) != 0) + { + errbits |= CAN_ERR_BUSOFF; + } + else + { + errbits |= CAN_ERR_RESTARTED; + } + } + + if ((status & (FDCAN_INT_RF0L | FDCAN_INT_RF1L)) != 0) + { + /* Receive FIFO 0/1 Message Lost + * Receive FIFO 1 Message Lost + */ + + errbits |= CAN_ERR_CRTL; + data[1] |= CAN_ERR_CRTL_RX_OVERFLOW; + } + + if ((status & FDCAN_INT_TEFL) != 0) + { + /* Tx Event FIFO Element Lost */ + + errbits |= CAN_ERR_CRTL; + data[1] |= CAN_ERR_CRTL_TX_OVERFLOW; + } + + if ((status & FDCAN_INT_TOO) != 0) + { + /* Timeout Occurred */ + + errbits |= CAN_ERR_TXTIMEOUT; + } + + if ((status & (FDCAN_INT_MRAF | FDCAN_INT_ELO)) != 0) + { + /* Message RAM Access Failure + * Error Logging Overflow + */ + + errbits |= CAN_ERR_CRTL; + data[1] |= CAN_ERR_CRTL_UNSPEC; + } + + if (errbits != 0) + { + nerr("ERROR: errbits = %08" PRIx16 "\n", errbits); + + /* Copy frame */ + + frame->can_id = errbits; + frame->can_dlc = CAN_ERR_DLC; + + memcpy(frame->data, data, CAN_ERR_DLC); + + /* Copy the buffer pointer to priv->dev.. Set amount of data + * in priv->dev.d_len + */ + + priv->dev.d_len = sizeof(struct can_frame); + priv->dev.d_buf = (uint8_t *)frame; + + /* Send to socket interface */ + + NETDEV_ERRORS(&priv->dev); + + can_input(&priv->dev); + + /* Point the packet buffer back to the next Tx buffer that will be + * used during the next write. If the write queue is full, then + * this will point at an active buffer, which must not be written + * to. This is OK because devif_poll won't be called unless the + * queue is not full. + */ + + priv->dev.d_buf = (uint8_t *)priv->txdesc; + } +} +#endif /* CONFIG_NET_CAN_ERRORS */ + +/**************************************************************************** + * Name: fdcan_receive + * + * Description: + * Receive an FDCAN messages + * + * Input Parameters: + * dev - CAN-common state data + * rxbuffer - The RX buffer containing the received messages + * nwords - The length of the RX buffer (element size in words). + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void fdcan_receive(FAR struct stm32_fdcan_s *priv, + FAR volatile uint32_t *rxbuffer, + unsigned long nwords) +{ + FAR struct can_frame *frame = (struct can_frame *)priv->rxdesc; + uint32_t regval = 0; + + fdcan_dumprxregs(dev->cd_priv, "Before receive"); + + /* Format the CAN header */ + + /* Work R0 contains the CAN ID */ + + regval = *rxbuffer++; + + /* Extract the RTR bit */ + + if ((regval & BUFFER_R0_RTR) != 0) + { + frame->can_id |= CAN_RTR_FLAG; + } + +#ifdef CONFIG_CAN_EXTID + if ((regval & BUFFER_R0_XTD) != 0) + { + /* Save the extended ID of the newly received message */ + + frame->can_id = (regval & BUFFER_R0_EXTID_MASK) >> + BUFFER_R0_EXTID_SHIFT; + frame->can_id |= CAN_EFF_FLAG; + } + else + { + frame->can_id = (regval & BUFFER_R0_STDID_MASK) >> + BUFFER_R0_STDID_SHIFT; + frame->can_id &= ~CAN_EFF_FLAG; + } +#else + if ((regval & BUFFER_R0_XTD) != 0) + { + /* Drop any messages with extended IDs */ + + return; + } + + /* Save the standard ID of the newly received message */ + + frame->can_id = (regval & BUFFER_R0_STDID_MASK) >> BUFFER_R0_STDID_SHIFT; +#endif + + /* Word R1 contains the DLC and timestamp */ + + regval = *rxbuffer++; + + frame->can_dlc = (regval & BUFFER_R1_DLC_MASK) >> BUFFER_R1_DLC_SHIFT; + + /* Save the message data */ + + memcpy(frame->data, (void *)rxbuffer, frame->can_dlc); + + /* Copy the buffer pointer to priv->dev.. Set amount of data + * in priv->dev.d_len + */ + + priv->dev.d_len = sizeof(struct can_frame); + priv->dev.d_buf = (uint8_t *)frame; + + /* Send to socket interface */ + + NETDEV_RXPACKETS(&priv->dev); + + can_input(&priv->dev); + + /* Point the packet buffer back to the next Tx buffer that will be + * used during the next write. If the write queue is full, then + * this will point at an active buffer, which must not be written + * to. This is OK because devif_poll won't be called unless the + * queue is not full. + */ + + priv->dev.d_buf = (uint8_t *)priv->txdesc; +} + +/**************************************************************************** + * Name: fdcan_interrupt + * + * Description: + * Common FDCAN interrupt handler + * + * irq - The IRQ number of the interrupt. + * context - The register state save array at the time of the interrupt. + * + * Returned Value: + * Zero on success; a negated errno on failure + * + ****************************************************************************/ + +static int fdcan_interrupt(int irq, void *context, FAR void *arg) +{ + FAR struct stm32_fdcan_s *priv = (FAR struct stm32_fdcan_s *)arg; + uint32_t pending = 0; + + DEBUGASSERT(priv != NULL); + + /* Get the set of pending interrupts. */ + + pending = fdcan_getreg(priv, STM32_FDCAN_IR_OFFSET); + +#ifdef CONFIG_NET_CAN_ERRORS + /* Check for any errors */ + + if ((pending & FDCAN_ANYERR_INTS) != 0) + { + /* Disable further CAN ERROR interrupts and schedule to perform the + * interrupt processing on the worker thread + */ + + fdcan_errint(priv, false); + work_queue(CANWORK, &priv->irqwork, fdcan_error_work, priv, 0); + } +#endif + + /* Check for successful completion of a transmission */ + + if ((pending & FDCAN_INT_TC) != 0) + { + /* Disable further TX CAN interrupts. here can be no race + * condition here. + */ + + fdcan_txint(priv, false); + work_queue(CANWORK, &priv->irqwork, fdcan_txdone_work, priv, 0); + } + else if ((pending & FDCAN_TXFIFOQ_INTS) != 0) + { + /* Clear unhandled TX events */ + + fdcan_putreg(priv, STM32_FDCAN_IR_OFFSET, FDCAN_TXFIFOQ_INTS); + } + + if (pending & FDCAN_INT_RF1N) + { + /* Disable further CAN RX interrupts and schedule to perform the + * interrupt processing on the worker thread + */ + + fdcan_rx1int(priv, false); + work_queue(CANWORK, &priv->irqwork, + fdcan_rx1interrupt_work, priv, 0); + } + + /* Clear the RX FIFO0 new message interrupt */ + + if (pending & FDCAN_INT_RF0N) + { + /* Disable further CAN RX interrupts and schedule to perform the + * interrupt processing on the worker thread + */ + + fdcan_rx0int(priv, false); + work_queue(CANWORK, &priv->irqwork, + fdcan_rx0interrupt_work, priv, 0); + } + + return OK; +} + +/**************************************************************************** + * Name: fdcan_hw_initialize + * + * Description: + * FDCAN hardware initialization + * + * Input Parameters: + * priv - A pointer to the private data structure for this FDCAN peripheral + * + * Returned Value: + * Zero on success; a negated errno value on failure. + * + ****************************************************************************/ + +static int fdcan_hw_initialize(struct stm32_fdcan_s *priv) +{ + FAR const struct stm32_config_s *config = NULL; + FAR volatile uint32_t *msgram = NULL; + uint32_t regval = 0; + uint32_t cntr = 0; + + DEBUGASSERT(priv); + config = priv->config; + DEBUGASSERT(config); + + ninfo("FDCAN%d\n", config->port); + + /* Clean message RAM */ + + msgram = config->msgram.stdfilters; + cntr = (FDCAN_MSGRAM_WORDS + 1); + while (cntr > 0) + { + *msgram++ = 0; + cntr--; + } + + /* Configure FDCAN pins */ + + stm32_configgpio(config->rxpinset); + stm32_configgpio(config->txpinset); + + /* Renable device if previosuly disabled in fdcan_shutdown() */ + + if (priv->state == FDCAN_STATE_DISABLED) + { + /* Reset Clock Stop Request bit */ + + regval = fdcan_getreg(priv, STM32_FDCAN_CCCR_OFFSET); + regval &= ~FDCAN_CCCR_CSR; + fdcan_putreg(priv, STM32_FDCAN_CCCR_OFFSET, regval); + + /* Wait for Clock Stop Acknowledge bit reset to indicate + * device is operational + */ + + while ((fdcan_getreg(priv, STM32_FDCAN_CCCR_OFFSET) & FDCAN_CCCR_CSA) + != 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_CCE; + fdcan_putreg(priv, STM32_FDCAN_CCCR_OFFSET, regval); + + /* Global Filter Configuration: + * + * ANFS=0: Store all non matching standard frame in RX FIFO0 + * ANFE=0: Store all non matching extended frame in RX FIFO0 + */ + + regval = FDCAN_RXGFC_ANFE_RX_FIFO0 | FDCAN_RXGFC_ANFS_RX_FIFO0; + fdcan_putreg(priv, STM32_FDCAN_RXGFC_OFFSET, regval); + + /* Extended ID Filter AND mask */ + + fdcan_putreg(priv, STM32_FDCAN_XIDAM_OFFSET, 0x1fffffff); + + /* Disable all interrupts */ + + fdcan_putreg(priv, STM32_FDCAN_IE_OFFSET, 0); + fdcan_putreg(priv, STM32_FDCAN_TXBTIE_OFFSET, 0); + + /* All interrupts directed to Line 0. But disable both interrupt lines 0 + * and 1 for now. + * + * REVISIT: Only interrupt line 0 is used by this driver. + */ + + fdcan_putreg(priv, STM32_FDCAN_ILS_OFFSET, 0); + fdcan_putreg(priv, STM32_FDCAN_ILE_OFFSET, 0); + + /* Clear all pending interrupts. */ + + fdcan_putreg(priv, STM32_FDCAN_IR_OFFSET, FDCAN_INT_ALL); + + /* Configure FDCAN bit timing */ + + fdcan_putreg(priv, STM32_FDCAN_NBTP_OFFSET, priv->nbtp); + fdcan_putreg(priv, STM32_FDCAN_DBTP_OFFSET, priv->dbtp); + + /* Configure message RAM starting addresses and sizes. */ + + regval = FDCAN_RXGFC_LSS(config->nstdfilters); + regval |= FDCAN_RXGFC_LSE(config->nextfilters); + fdcan_putreg(priv, STM32_FDCAN_RXGFC_OFFSET, regval); + + /* Dump RAM layout */ + + fdcan_dumpramlayout(priv); + + /* Configure Message Filters */ + + /* Disable all standard filters */ + + msgram = config->msgram.stdfilters; + cntr = config->nstdfilters; + while (cntr > 0) + { + *msgram++ = STDFILTER_S0_SFEC_DISABLE; + cntr--; + } + + /* Disable all extended filters */ + + msgram = config->msgram.extfilters; + cntr = config->nextfilters; + while (cntr > 0) + { + *msgram = EXTFILTER_F0_EFEC_DISABLE; + msgram = msgram + 2; + cntr--; + } + + /* Input clock divider configuration */ + + regval = FDCANCLK_PDIV; + fdcan_putreg(priv, STM32_FDCAN_CKDIV_OFFSET, regval); + + /* CC control register */ + + regval = fdcan_getreg(priv, STM32_FDCAN_CCCR_OFFSET); + regval &= ~(FDCAN_CCCR_NISO | FDCAN_CCCR_FDOE | FDCAN_CCCR_BRSE); + + /* Select ISO11898-1 or Non ISO Bosch CAN FD Specification V1.0 */ + + switch (config->format) + { + case FDCAN_ISO11898_1_FORMAT: + { + break; + } + + case FDCAN_NONISO_BOSCH_V1_FORMAT: + { + regval |= FDCAN_CCCR_NISO; + break; + } + + default: + { + return -EINVAL; + } + } + + /* Select Classic CAN mode or FD mode with or without fast bit rate + * switching + */ + + switch (config->mode) + { + case FDCAN_CLASSIC_MODE: + { + break; + } + +#ifdef CONFIG_CAN_FD + case FDCAN_FD_MODE: + { + regval |= FDCAN_CCCR_FDOE; + break; + } + + case FDCAN_FD_BRS_MODE: + { + regval |= (FDCAN_CCCR_FDOE | FDCAN_CCCR_BRSE); + break; + } +#endif + + default: + { + return -EINVAL; + } + } + + /* Set the initial CAN mode */ + + fdcan_putreg(priv, STM32_FDCAN_CCCR_OFFSET, regval); + + /* Enable FIFO/Queue mode */ + + regval = fdcan_getreg(priv, STM32_FDCAN_TXBC_OFFSET); +#ifdef CONFIG_STM32_FDCAN_QUEUE_MODE + regval |= FDCAN_TXBC_TFQM; +#else + regval &= ~FDCAN_TXBC_TFQM; +#endif + fdcan_putreg(priv, STM32_FDCAN_TXBC_OFFSET, regval); + +#ifdef STM32_FDCAN_LOOPBACK + /* Is loopback mode selected for this peripheral? */ + + if (config->loopback) + { + /* FDCAN_CCCR_TEST - Test mode enable + * FDCAN_CCCR_MON - Bus monitoring mode (for internal loopback) + * FDCAN_TEST_LBCK - Loopback mode + */ + + regval = fdcan_getreg(priv, STM32_FDCAN_CCCR_OFFSET); + regval |= (FDCAN_CCCR_TEST | FDCAN_CCCR_MON); + fdcan_putreg(priv, STM32_FDCAN_CCCR_OFFSET, regval); + + regval = fdcan_getreg(priv, STM32_FDCAN_TEST_OFFSET); + regval |= FDCAN_TEST_LBCK; + fdcan_putreg(priv, STM32_FDCAN_TEST_OFFSET, regval); + } +#endif + + /* Configure interrupt lines */ + + /* Direct all interrupts to Line 0. + * + * Bits in the ILS register correspond to each FDCAN interrupt; A bit + * set to '1' is directed to interrupt line 1; a bit cleared to '0' + * is directed interrupt line 0. + * + * REVISIT: Nothing is done here. Only interrupt line 0 is used by + * this driver and ILS was already cleared above. + */ + + /* Enable only interrupt line 0. */ + + fdcan_putreg(priv, STM32_FDCAN_ILE_OFFSET, FDCAN_ILE_EINT0); + + /* Disable initialization mode to enable normal operation */ + + regval = fdcan_getreg(priv, STM32_FDCAN_CCCR_OFFSET); + regval &= ~FDCAN_CCCR_INIT; + fdcan_putreg(priv, STM32_FDCAN_CCCR_OFFSET, regval); + + return OK; +} + +/**************************************************************************** + * Function: fdcan_ifup + * + * Description: + * NuttX Callback: Bring up the Ethernet interface when an IP address is + * provided + * + * Input Parameters: + * dev - Reference to the NuttX driver state structure + * + * Returned Value: + * None + * + * Assumptions: + * + ****************************************************************************/ + +static int fdcan_ifup(struct net_driver_s *dev) +{ + FAR struct stm32_fdcan_s *priv = + (FAR struct stm32_fdcan_s *)dev->d_private; + FAR const struct stm32_config_s *config = NULL; + + DEBUGASSERT(priv); + config = priv->config; + DEBUGASSERT(config); + + /* Setup CAN */ + + fdcan_setup(priv); + + /* Enable interrupts */ + + fdcan_rx0int(priv, true); + fdcan_rx1int(priv, true); + fdcan_txint(priv, true); +#ifdef CONFIG_NET_CAN_ERRORS + fdcan_errint(priv, true); +#endif + + /* Enable the interrupts at the NVIC */ + + up_enable_irq(config->irq0); + up_enable_irq(config->irq1); + + priv->bifup = true; + + priv->txdesc = (struct can_frame *)priv->tx_pool; + priv->rxdesc = (struct can_frame *)priv->rx_pool; + + priv->dev.d_buf = (uint8_t *)priv->txdesc; + + return OK; +} + +/**************************************************************************** + * Function: fdcan_ifdown + * + * Description: + * NuttX Callback: Stop the interface. + * + * Input Parameters: + * dev - Reference to the NuttX driver state structure + * + * Returned Value: + * None + * + * Assumptions: + * + ****************************************************************************/ + +static int fdcan_ifdown(struct net_driver_s *dev) +{ + FAR struct stm32_fdcan_s *priv = + (FAR struct stm32_fdcan_s *)dev->d_private; + + /* Disable CAN interrupts */ + + fdcan_shutdown(priv); + + /* Reset CAN */ + + fdcan_reset(priv); + + return OK; +} + +/**************************************************************************** + * Function: fdcan_txpoll + * + * Description: + * The transmitter is available, check if the network has any outgoing + * packets ready to send. This is a callback from devif_poll(). + * devif_poll() may be called: + * + * 1. When the preceding TX packet send is complete, + * 2. When the preceding TX packet send timesout and the interface is reset + * 3. During normal TX polling + * + * Input Parameters: + * dev - Reference to the NuttX driver state structure + * + * Returned Value: + * OK on success; a negated errno on failure + * + * Assumptions: + * May or may not be called from an interrupt handler. In either case, + * global interrupts are disabled, either explicitly or indirectly through + * interrupt handling logic. + * + ****************************************************************************/ + +static int fdcan_txpoll(struct net_driver_s *dev) +{ + FAR struct stm32_fdcan_s *priv = + (FAR struct stm32_fdcan_s *)dev->d_private; + + /* If the polling resulted in data that should be sent out on the network, + * the field d_len is set to a value > 0. + */ + + if (priv->dev.d_len > 0) + { + if (!devif_loopback(&priv->dev)) + { + fdcan_txdone(priv); + + /* Send the packet */ + + fdcan_send(priv); + + /* Check if there is room in the device to hold another packet. If + * not, return a non-zero value to terminate the poll. + */ + + if (fdcan_txready(priv) == false) + { + return -EBUSY; + } + } + } + + /* If zero is returned, the polling will continue until all connections + * have been examined. + */ + + return 0; +} + +/**************************************************************************** + * Function: fdcan_txavail_work + * + * Description: + * Perform an out-of-cycle poll on the worker thread. + * + * Input Parameters: + * arg - Reference to the NuttX driver state structure (cast to void*) + * + * Returned Value: + * None + * + * Assumptions: + * Called on the higher priority worker thread. + * + ****************************************************************************/ + +static void fdcan_txavail_work(FAR void *arg) +{ + FAR struct stm32_fdcan_s *priv = (FAR struct stm32_fdcan_s *)arg; + + /* Ignore the notification if the interface is not yet up */ + + net_lock(); + if (priv->bifup) + { + /* Check if there is room in the hardware to hold another outgoing + * packet. + */ + + if (fdcan_txready(priv)) + { + /* No, there is space for another transfer. Poll the network for + * new XMIT data. + */ + + devif_timer(&priv->dev, 0, fdcan_txpoll); + } + } + + net_unlock(); +} + +/**************************************************************************** + * Function: fdcan_txavail + * + * Description: + * Driver callback invoked when new TX data is available. This is a + * stimulus perform an out-of-cycle poll and, thereby, reduce the TX + * latency. + * + * Input Parameters: + * dev - Reference to the NuttX driver state structure + * + * Returned Value: + * None + * + * Assumptions: + * Called in normal user mode + * + ****************************************************************************/ + +static int fdcan_txavail(struct net_driver_s *dev) +{ + FAR struct stm32_fdcan_s *priv = + (FAR struct stm32_fdcan_s *)dev->d_private; + + /* Is our single work structure available? It may not be if there are + * pending interrupt actions and we will have to ignore the Tx + * availability action. + */ + + if (work_available(&priv->pollwork)) + { + /* Schedule to serialize the poll on the worker thread. */ + + fdcan_txavail_work(priv); + } + + return OK; +} + +/**************************************************************************** + * Function: fdcan_ioctl + * + * Description: + * PHY ioctl command handler + * + * Input Parameters: + * dev - Reference to the NuttX driver state structure + * cmd - ioctl command + * arg - Argument accompanying the command + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + * Assumptions: + * + ****************************************************************************/ + +#ifdef CONFIG_NETDEV_IOCTL +static int fdcan_netdev_ioctl(struct net_driver_s *dev, int cmd, + unsigned long arg); +{ + FAR struct stm32_fdcan_s *priv = + (FAR struct stm32_fdcan_s *)dev->d_private; + int ret = OK; + + DEBUGASSERT(priv); + + switch (cmd) + { + /* TODO */ + + default: + ret = -ENOTTY; + break; + } + + return ret; +} +#endif /* CONFIG_NETDEV_IOCTL */ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: stm32_cansockinitialize + * + * Description: + * Initialize the selected FDCAN port as CAN socket interface + * + * Input Parameters: + * Port number (for hardware that has multiple FDCAN interfaces) + * + * Returned Value: + * OK on success; Negated errno on failure. + * + ****************************************************************************/ + +int stm32_fdcansockinitialize(int port) +{ + FAR struct stm32_fdcan_s *priv = NULL; + FAR const struct stm32_config_s *config = NULL; + int ret = OK; + + ninfo("FDCAN%d\n", port); + + /* Select FDCAN peripheral to be initialized */ + +#ifdef CONFIG_STM32_FDCAN1 + if (port == FDCAN1) + { + /* Select the FDCAN1 device structure */ + + priv = &g_fdcan1priv; + config = &g_fdcan1const; + } + else +#endif +#ifdef CONFIG_STM32_FDCAN2 + if (port == FDCAN2) + { + /* Select the FDCAN2 device structure */ + + priv = &g_fdcan2priv; + config = &g_fdcan2const; + } + else +#endif +#ifdef CONFIG_STM32_FDCAN3 + if (port == FDCAN3) + { + /* Select the FDCAN3 device structure */ + + priv = &g_fdcan3priv; + config = &g_fdcan3const; + } + else +#endif + { + nerr("ERROR: Unsupported port %d\n", port); + ret = -EINVAL; + goto errout; + } + + /* Perform one time data initialization */ + + memset(priv, 0, sizeof(struct stm32_fdcan_s)); + priv->config = config; + + /* Set the initial bit timing. This might change subsequently + * due to IOCTL command processing. + */ + + priv->nbtp = config->nbtp; + priv->dbtp = config->dbtp; + + /* Initialize the driver structure */ + + priv->dev.d_ifup = fdcan_ifup; + priv->dev.d_ifdown = fdcan_ifdown; + priv->dev.d_txavail = fdcan_txavail; +#ifdef CONFIG_NETDEV_IOCTL + priv->dev.d_ioctl = fdcan_netdev_ioctl; +#endif + priv->dev.d_private = priv; + + /* Put the interface in the down state. This usually amounts to resetting + * the device and/or calling fdcan_ifdown(). + */ + + ninfo("callbacks done\n"); + + fdcan_ifdown(&priv->dev); + + /* Register the device with the OS so that socket IOCTLs can be performed */ + + ret = netdev_register(&priv->dev, NET_LL_CAN); + +errout: + return ret; +} From 0889493bee78357d8ee2400c5e29b0b95f9818a8 Mon Sep 17 00:00:00 2001 From: raiden00pl Date: Sat, 5 Feb 2022 14:46:34 +0100 Subject: [PATCH 30/43] [BACKPORT] boards/arm/stm32g4: normalize CAN configs --- boards/arm/stm32/b-g431b-esc1/configs/can/defconfig | 1 - boards/arm/stm32/nucleo-g431rb/configs/can/defconfig | 1 - 2 files changed, 2 deletions(-) diff --git a/boards/arm/stm32/b-g431b-esc1/configs/can/defconfig b/boards/arm/stm32/b-g431b-esc1/configs/can/defconfig index 65af7ee7e79..a644da19354 100644 --- a/boards/arm/stm32/b-g431b-esc1/configs/can/defconfig +++ b/boards/arm/stm32/b-g431b-esc1/configs/can/defconfig @@ -23,7 +23,6 @@ CONFIG_ARCH_STACKDUMP=y CONFIG_BOARD_LOOPSPERMSEC=8499 CONFIG_BOARD_STM32_BG431BESC1_USE_HSE=y CONFIG_BUILTIN=y -CONFIG_CAN=y CONFIG_CAN_ERRORS=y CONFIG_CAN_EXTID=y CONFIG_DEBUG_FULLOPT=y diff --git a/boards/arm/stm32/nucleo-g431rb/configs/can/defconfig b/boards/arm/stm32/nucleo-g431rb/configs/can/defconfig index 22c2934f0dc..8576a34268e 100644 --- a/boards/arm/stm32/nucleo-g431rb/configs/can/defconfig +++ b/boards/arm/stm32/nucleo-g431rb/configs/can/defconfig @@ -23,7 +23,6 @@ CONFIG_ARCH_STACKDUMP=y CONFIG_BOARD_LOOPSPERMSEC=8499 CONFIG_BOARD_NUCLEO_G431RB_USE_HSE=y CONFIG_BUILTIN=y -CONFIG_CAN=y CONFIG_CAN_ERRORS=y CONFIG_CAN_EXTID=y CONFIG_DEBUG_FULLOPT=y From 57b627f14f62b985b08fb8f14736e7cc957642dd Mon Sep 17 00:00:00 2001 From: raiden00pl Date: Sat, 5 Feb 2022 16:40:43 +0100 Subject: [PATCH 31/43] [BACKPORT] net/can: add an option to control CAN EXTID support --- arch/arm/src/stm32/stm32_can_sock.c | 6 +++--- arch/arm/src/stm32/stm32_fdcan_sock.c | 8 ++++---- boards/arm/stm32/nucleo-f446re/configs/cansock/defconfig | 2 +- net/can/Kconfig | 7 +++++++ 4 files changed, 15 insertions(+), 8 deletions(-) diff --git a/arch/arm/src/stm32/stm32_can_sock.c b/arch/arm/src/stm32/stm32_can_sock.c index ff13b54297b..8b35726215a 100644 --- a/arch/arm/src/stm32/stm32_can_sock.c +++ b/arch/arm/src/stm32/stm32_can_sock.c @@ -881,7 +881,7 @@ static int stm32can_transmit(FAR struct stm32_can_s *priv) /* Set up the ID, standard 11-bit or extended 29-bit. */ -#ifdef CONFIG_CAN_EXTID +#ifdef CONFIG_NET_CAN_EXTID regval &= ~CAN_TIR_EXID_MASK; if (frame->can_id & CAN_EFF_FLAG) { @@ -1205,7 +1205,7 @@ static int stm32can_rxinterrupt_work(FAR struct stm32_can_s *priv, int rxmb) regval = stm32can_getreg(priv, STM32_CAN_RIR_OFFSET(rxmb)); -#ifdef CONFIG_CAN_EXTID +#ifdef CONFIG_NET_CAN_EXTID if ((regval & CAN_RIR_IDE) != 0) { frame->can_id = (regval & CAN_RIR_EXID_MASK) >> CAN_RIR_EXID_SHIFT; @@ -1277,7 +1277,7 @@ static int stm32can_rxinterrupt_work(FAR struct stm32_can_s *priv, int rxmb) /* Release the FIFO */ -#ifndef CONFIG_CAN_EXTID +#ifndef CONFIG_NET_CAN_EXTID errout: #endif regval = stm32can_getreg(priv, STM32_CAN_RFR_OFFSET(rxmb)); diff --git a/arch/arm/src/stm32/stm32_fdcan_sock.c b/arch/arm/src/stm32/stm32_fdcan_sock.c index fafecbedf0a..6d61d065605 100644 --- a/arch/arm/src/stm32/stm32_fdcan_sock.c +++ b/arch/arm/src/stm32/stm32_fdcan_sock.c @@ -520,14 +520,14 @@ struct stm32_fdcan_s const struct stm32_config_s *config; uint8_t state; /* See enum can_state_s */ -#ifdef CONFIG_CAN_EXTID +#ifdef CONFIG_NET_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 */ -#ifdef CONFIG_CAN_EXTID +#ifdef CONFIG_NET_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 */ @@ -1718,7 +1718,7 @@ static int fdcan_send(FAR struct stm32_fdcan_s *priv) * Extended Identifier (XTD) - Depends on configuration. */ -#ifdef CONFIG_CAN_EXTID +#ifdef CONFIG_NET_CAN_EXTID if (frame->can_id & CAN_EFF_FLAG) { DEBUGASSERT(frame->can_id < (1 << 29)); @@ -2409,7 +2409,7 @@ static void fdcan_receive(FAR struct stm32_fdcan_s *priv, frame->can_id |= CAN_RTR_FLAG; } -#ifdef CONFIG_CAN_EXTID +#ifdef CONFIG_NET_CAN_EXTID if ((regval & BUFFER_R0_XTD) != 0) { /* Save the extended ID of the newly received message */ diff --git a/boards/arm/stm32/nucleo-f446re/configs/cansock/defconfig b/boards/arm/stm32/nucleo-f446re/configs/cansock/defconfig index c5b7bf0b28d..7b39247c570 100644 --- a/boards/arm/stm32/nucleo-f446re/configs/cansock/defconfig +++ b/boards/arm/stm32/nucleo-f446re/configs/cansock/defconfig @@ -24,7 +24,6 @@ CONFIG_ARCH_STACKDUMP=y CONFIG_BOARD_LATE_INITIALIZE=y CONFIG_BOARD_LOOPSPERMSEC=8499 CONFIG_BUILTIN=y -CONFIG_CAN_EXTID=y CONFIG_DEBUG_FULLOPT=y CONFIG_DEBUG_SYMBOLS=y CONFIG_FS_PROCFS=y @@ -37,6 +36,7 @@ CONFIG_NETDEVICES=y CONFIG_NETDEV_IFINDEX=y CONFIG_NETDEV_LATEINIT=y CONFIG_NET_CAN=y +CONFIG_NET_CAN_EXTID=y CONFIG_NET_SOCKOPTS=y CONFIG_NET_STATISTICS=y CONFIG_NSH_BUILTIN_APPS=y diff --git a/net/can/Kconfig b/net/can/Kconfig index 695dcee550d..cb649bf37e7 100644 --- a/net/can/Kconfig +++ b/net/can/Kconfig @@ -36,6 +36,13 @@ config CAN_CONNS ---help--- Maximum number of CAN connections (all tasks). +config NET_CAN_EXTID + bool "Enable CAN extended IDs" + default n + ---help--- + Enables support for the 29-bit extended ID in SocketCAN stack. + Default Standard 11-bit IDs. + config NET_CAN_CANFD bool "Enable CAN FD support" default y From c625824b55a2853b6a14fd6ccd5f2c96e720ae6f Mon Sep 17 00:00:00 2001 From: raiden00pl Date: Sat, 22 Jan 2022 17:11:46 +0100 Subject: [PATCH 32/43] [BACKPORT] boards/b-g431b-esc1: add SocketCAN example --- .../b-g431b-esc1/configs/cansock/defconfig | 56 ++++++++++++++++++ boards/arm/stm32/b-g431b-esc1/src/Make.defs | 5 ++ .../arm/stm32/b-g431b-esc1/src/b-g431b-esc1.h | 22 +++++++ .../stm32/b-g431b-esc1/src/stm32_bringup.c | 22 +++++++ .../stm32/b-g431b-esc1/src/stm32_cansock.c | 57 +++++++++++++++++++ 5 files changed, 162 insertions(+) create mode 100644 boards/arm/stm32/b-g431b-esc1/configs/cansock/defconfig create mode 100644 boards/arm/stm32/b-g431b-esc1/src/stm32_cansock.c diff --git a/boards/arm/stm32/b-g431b-esc1/configs/cansock/defconfig b/boards/arm/stm32/b-g431b-esc1/configs/cansock/defconfig new file mode 100644 index 00000000000..18ba9202c8c --- /dev/null +++ b/boards/arm/stm32/b-g431b-esc1/configs/cansock/defconfig @@ -0,0 +1,56 @@ +# +# 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_NET_ETHERNET is not set +# CONFIG_NET_IPv4 is not set +CONFIG_ARCH="arm" +CONFIG_ARCH_BOARD="b-g431b-esc1" +CONFIG_ARCH_BOARD_B_G431B_ESC1=y +CONFIG_ARCH_BUTTONS=y +CONFIG_ARCH_CHIP="stm32" +CONFIG_ARCH_CHIP_STM32=y +CONFIG_ARCH_CHIP_STM32G431C=y +CONFIG_ARCH_INTERRUPTSTACK=1024 +CONFIG_ARCH_STACKDUMP=y +CONFIG_BOARD_LATE_INITIALIZE=y +CONFIG_BOARD_LOOPSPERMSEC=8499 +CONFIG_BOARD_STM32_BG431BESC1_USE_HSE=y +CONFIG_BUILTIN=y +CONFIG_DEFAULT_TASK_STACKSIZE=1024 +CONFIG_FS_PROCFS=y +CONFIG_INIT_ENTRYPOINT="nsh_main" +CONFIG_INIT_STACKSIZE=2048 +CONFIG_INTELHEX_BINARY=y +CONFIG_IOB_BUFSIZE=128 +CONFIG_IOB_NBUFFERS=10 +CONFIG_NET=y +CONFIG_NETDEVICES=y +CONFIG_NETDEV_IFINDEX=y +CONFIG_NETDEV_LATEINIT=y +CONFIG_NET_CAN=y +CONFIG_NET_SOCKOPTS=y +CONFIG_NET_STATISTICS=y +CONFIG_NSH_BUILTIN_APPS=y +CONFIG_NSH_FILEIOSIZE=512 +CONFIG_NSH_LINELEN=64 +CONFIG_NSH_READLINE=y +CONFIG_RAM_SIZE=22528 +CONFIG_RAM_START=0x20000000 +CONFIG_RAW_BINARY=y +CONFIG_RR_INTERVAL=200 +CONFIG_SCHED_LPWORK=y +CONFIG_SCHED_WAITPID=y +CONFIG_START_DAY=14 +CONFIG_START_MONTH=10 +CONFIG_START_YEAR=2014 +CONFIG_STM32_FDCAN1=y +CONFIG_STM32_FDCAN_SOCKET=y +CONFIG_STM32_JTAG_SW_ENABLE=y +CONFIG_STM32_USART2=y +CONFIG_SYSTEM_NSH=y +CONFIG_TASK_NAME_SIZE=0 +CONFIG_USART2_SERIAL_CONSOLE=y diff --git a/boards/arm/stm32/b-g431b-esc1/src/Make.defs b/boards/arm/stm32/b-g431b-esc1/src/Make.defs index d3a1fbc4c40..5695555df55 100644 --- a/boards/arm/stm32/b-g431b-esc1/src/Make.defs +++ b/boards/arm/stm32/b-g431b-esc1/src/Make.defs @@ -41,9 +41,14 @@ ifeq ($(CONFIG_STM32_FOC),y) CSRCS += stm32_foc.c endif +ifeq ($(CONFIG_STM32_FDCAN),y) ifeq ($(CONFIG_STM32_FDCAN_CHARDRIVER),y) CSRCS += stm32_can.c endif +ifeq ($(CONFIG_STM32_FDCAN_SOCKET),y) +CSRCS += stm32_cansock.c +endif +endif DEPPATH += --dep-path board VPATH += :board diff --git a/boards/arm/stm32/b-g431b-esc1/src/b-g431b-esc1.h b/boards/arm/stm32/b-g431b-esc1/src/b-g431b-esc1.h index 6e133f8c3d6..a2b7d467dcb 100644 --- a/boards/arm/stm32/b-g431b-esc1/src/b-g431b-esc1.h +++ b/boards/arm/stm32/b-g431b-esc1/src/b-g431b-esc1.h @@ -31,6 +31,16 @@ * Pre-processor Definitions ****************************************************************************/ +/* procfs File System */ + +#ifdef CONFIG_FS_PROCFS +# ifdef CONFIG_NSH_PROC_MOUNTPOINT +# define STM32_PROCFS_MOUNTPOINT CONFIG_NSH_PROC_MOUNTPOINT +# else +# define STM32_PROCFS_MOUNTPOINT "/proc" +# endif +#endif + /* LED definitions **********************************************************/ /* LED definitions **********************************************************/ @@ -139,4 +149,16 @@ int stm32_foc_setup(void); int stm32_can_setup(void); #endif +/**************************************************************************** + * Name: stm32_cansock_setup + * + * Description: + * Initialize CAN socket interface + * + ****************************************************************************/ + +#ifdef CONFIG_STM32_FDCAN_SOCKET +int stm32_cansock_setup(void); +#endif + #endif /* __BOARDS_ARM_STM32_B_G431B_ESC1_SRC_B_G431B_ESC1_H */ diff --git a/boards/arm/stm32/b-g431b-esc1/src/stm32_bringup.c b/boards/arm/stm32/b-g431b-esc1/src/stm32_bringup.c index 7c3fbc2068f..9a408f76c9b 100644 --- a/boards/arm/stm32/b-g431b-esc1/src/stm32_bringup.c +++ b/boards/arm/stm32/b-g431b-esc1/src/stm32_bringup.c @@ -28,6 +28,7 @@ #include #include +#include #ifdef CONFIG_USERLED # include @@ -71,6 +72,17 @@ int stm32_bringup(void) { int ret; +#ifdef CONFIG_FS_PROCFS + /* Mount the procfs file system */ + + ret = nx_mount(NULL, STM32_PROCFS_MOUNTPOINT, "procfs", 0, NULL); + if (ret < 0) + { + syslog(LOG_ERR, + "ERROR: Failed to mount the PROC filesystem: %d\n", ret); + } +#endif /* CONFIG_FS_PROCFS */ + #ifdef CONFIG_INPUT_BUTTONS /* Register the BUTTON driver */ @@ -122,6 +134,16 @@ int stm32_bringup(void) } #endif +#ifdef CONFIG_STM32_FDCAN_SOCKET + /* Initialize CAN socket interface */ + + ret = stm32_cansock_setup(); + if (ret < 0) + { + syslog(LOG_ERR, "ERROR: stm32_cansock_setup failed: %d\n", ret); + } +#endif + UNUSED(ret); return OK; } diff --git a/boards/arm/stm32/b-g431b-esc1/src/stm32_cansock.c b/boards/arm/stm32/b-g431b-esc1/src/stm32_cansock.c new file mode 100644 index 00000000000..5c645809592 --- /dev/null +++ b/boards/arm/stm32/b-g431b-esc1/src/stm32_cansock.c @@ -0,0 +1,57 @@ +/**************************************************************************** + * boards/arm/stm32/b-g431b-esc1/src/stm32_cansock.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 "stm32_fdcan.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: stm32_cansock_setup + * + * Description: + * Initialize CAN socket interface + * + ****************************************************************************/ + +int stm32_cansock_setup(void) +{ + int ret; + + /* Call stm32_fdcaninitialize() to get an instance of the FDCAN interface */ + + ret = stm32_fdcansockinitialize(1); + if (ret < 0) + { + canerr("ERROR: Failed to get FDCAN interface %d\n", ret); + return ret; + } + + return OK; +} From 1aa879cd6430e0692d8be3d0be0e195b7d679854 Mon Sep 17 00:00:00 2001 From: raiden00pl Date: Sat, 22 Jan 2022 17:12:05 +0100 Subject: [PATCH 33/43] [BACKPORT] boards/nucleo-g431rb: add SocketCAN example --- .../nucleo-g431rb/configs/cansock/defconfig | 56 ++++++++++++++++++ boards/arm/stm32/nucleo-g431rb/src/Make.defs | 5 ++ .../stm32/nucleo-g431rb/src/nucleo-g431rb.h | 22 +++++++ .../stm32/nucleo-g431rb/src/stm32_bringup.c | 22 +++++++ .../stm32/nucleo-g431rb/src/stm32_cansock.c | 57 +++++++++++++++++++ 5 files changed, 162 insertions(+) create mode 100644 boards/arm/stm32/nucleo-g431rb/configs/cansock/defconfig create mode 100644 boards/arm/stm32/nucleo-g431rb/src/stm32_cansock.c diff --git a/boards/arm/stm32/nucleo-g431rb/configs/cansock/defconfig b/boards/arm/stm32/nucleo-g431rb/configs/cansock/defconfig new file mode 100644 index 00000000000..44326688ccb --- /dev/null +++ b/boards/arm/stm32/nucleo-g431rb/configs/cansock/defconfig @@ -0,0 +1,56 @@ +# +# 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_NET_ETHERNET is not set +# CONFIG_NET_IPv4 is not set +CONFIG_ARCH="arm" +CONFIG_ARCH_BOARD="nucleo-g431rb" +CONFIG_ARCH_BOARD_NUCLEO_G431RB=y +CONFIG_ARCH_BUTTONS=y +CONFIG_ARCH_CHIP="stm32" +CONFIG_ARCH_CHIP_STM32=y +CONFIG_ARCH_CHIP_STM32G431R=y +CONFIG_ARCH_INTERRUPTSTACK=1024 +CONFIG_ARCH_STACKDUMP=y +CONFIG_BOARD_LATE_INITIALIZE=y +CONFIG_BOARD_LOOPSPERMSEC=8499 +CONFIG_BOARD_NUCLEO_G431RB_USE_HSE=y +CONFIG_BUILTIN=y +CONFIG_DEFAULT_TASK_STACKSIZE=1024 +CONFIG_FS_PROCFS=y +CONFIG_INIT_ENTRYPOINT="nsh_main" +CONFIG_INIT_STACKSIZE=2048 +CONFIG_INTELHEX_BINARY=y +CONFIG_IOB_BUFSIZE=128 +CONFIG_IOB_NBUFFERS=10 +CONFIG_NET=y +CONFIG_NETDEVICES=y +CONFIG_NETDEV_IFINDEX=y +CONFIG_NETDEV_LATEINIT=y +CONFIG_NET_CAN=y +CONFIG_NET_SOCKOPTS=y +CONFIG_NET_STATISTICS=y +CONFIG_NSH_BUILTIN_APPS=y +CONFIG_NSH_FILEIOSIZE=512 +CONFIG_NSH_LINELEN=64 +CONFIG_NSH_READLINE=y +CONFIG_RAM_SIZE=22528 +CONFIG_RAM_START=0x20000000 +CONFIG_RAW_BINARY=y +CONFIG_RR_INTERVAL=200 +CONFIG_SCHED_LPWORK=y +CONFIG_SCHED_WAITPID=y +CONFIG_START_DAY=14 +CONFIG_START_MONTH=10 +CONFIG_START_YEAR=2014 +CONFIG_STM32_FDCAN1=y +CONFIG_STM32_FDCAN_SOCKET=y +CONFIG_STM32_JTAG_SW_ENABLE=y +CONFIG_STM32_USART2=y +CONFIG_SYSTEM_NSH=y +CONFIG_TASK_NAME_SIZE=0 +CONFIG_USART2_SERIAL_CONSOLE=y diff --git a/boards/arm/stm32/nucleo-g431rb/src/Make.defs b/boards/arm/stm32/nucleo-g431rb/src/Make.defs index 3ca40eb1344..bb60c5e55e5 100644 --- a/boards/arm/stm32/nucleo-g431rb/src/Make.defs +++ b/boards/arm/stm32/nucleo-g431rb/src/Make.defs @@ -51,9 +51,14 @@ ifeq ($(CONFIG_BOARD_STM32_IHM16M1),y) CSRCS += stm32_foc_ihm16m1.c endif +ifeq ($(CONFIG_STM32_FDCAN),y) ifeq ($(CONFIG_STM32_FDCAN_CHARDRIVER),y) CSRCS += stm32_can.c endif +ifeq ($(CONFIG_STM32_FDCAN_SOCKET),y) +CSRCS += stm32_cansock.c +endif +endif DEPPATH += --dep-path board VPATH += :board diff --git a/boards/arm/stm32/nucleo-g431rb/src/nucleo-g431rb.h b/boards/arm/stm32/nucleo-g431rb/src/nucleo-g431rb.h index a7a1d69f798..417eed4ede6 100644 --- a/boards/arm/stm32/nucleo-g431rb/src/nucleo-g431rb.h +++ b/boards/arm/stm32/nucleo-g431rb/src/nucleo-g431rb.h @@ -31,6 +31,16 @@ * Pre-processor Definitions ****************************************************************************/ +/* procfs File System */ + +#ifdef CONFIG_FS_PROCFS +# ifdef CONFIG_NSH_PROC_MOUNTPOINT +# define STM32_PROCFS_MOUNTPOINT CONFIG_NSH_PROC_MOUNTPOINT +# else +# define STM32_PROCFS_MOUNTPOINT "/proc" +# endif +#endif + /* LED definitions **********************************************************/ /* LED definitions **********************************************************/ @@ -155,4 +165,16 @@ int stm32_foc_setup(void); int stm32_can_setup(void); #endif +/**************************************************************************** + * Name: stm32_cansock_setup + * + * Description: + * Initialize CAN socket interface + * + ****************************************************************************/ + +#ifdef CONFIG_STM32_FDCAN_SOCKET +int stm32_cansock_setup(void); +#endif + #endif /* __BOARDS_ARM_STM32_NUCLEO_G431RB_SRC_NUCLEO_G431RB_H */ diff --git a/boards/arm/stm32/nucleo-g431rb/src/stm32_bringup.c b/boards/arm/stm32/nucleo-g431rb/src/stm32_bringup.c index 6787e9e4370..02e49a1547c 100644 --- a/boards/arm/stm32/nucleo-g431rb/src/stm32_bringup.c +++ b/boards/arm/stm32/nucleo-g431rb/src/stm32_bringup.c @@ -28,6 +28,7 @@ #include #include +#include #ifdef CONFIG_USERLED # include @@ -71,6 +72,17 @@ int stm32_bringup(void) { int ret; +#ifdef CONFIG_FS_PROCFS + /* Mount the procfs file system */ + + ret = nx_mount(NULL, STM32_PROCFS_MOUNTPOINT, "procfs", 0, NULL); + if (ret < 0) + { + syslog(LOG_ERR, + "ERROR: Failed to mount the PROC filesystem: %d\n", ret); + } +#endif /* CONFIG_FS_PROCFS */ + #ifdef CONFIG_INPUT_BUTTONS /* Register the BUTTON driver */ @@ -132,6 +144,16 @@ int stm32_bringup(void) } #endif +#ifdef CONFIG_STM32_FDCAN_SOCKET + /* Initialize CAN socket interface */ + + ret = stm32_cansock_setup(); + if (ret < 0) + { + syslog(LOG_ERR, "ERROR: stm32_cansock_setup failed: %d\n", ret); + } +#endif + UNUSED(ret); return OK; } diff --git a/boards/arm/stm32/nucleo-g431rb/src/stm32_cansock.c b/boards/arm/stm32/nucleo-g431rb/src/stm32_cansock.c new file mode 100644 index 00000000000..e446a548e26 --- /dev/null +++ b/boards/arm/stm32/nucleo-g431rb/src/stm32_cansock.c @@ -0,0 +1,57 @@ +/**************************************************************************** + * boards/arm/stm32/nucleo-g431rb/src/stm32_cansock.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 "stm32_fdcan.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: stm32_cansock_setup + * + * Description: + * Initialize CAN socket interface + * + ****************************************************************************/ + +int stm32_cansock_setup(void) +{ + int ret; + + /* Call stm32_fdcaninitialize() to get an instance of the FDCAN interface */ + + ret = stm32_fdcansockinitialize(1); + if (ret < 0) + { + canerr("ERROR: Failed to get FDCAN interface %d\n", ret); + return ret; + } + + return OK; +} From 0e12b3cb1226452c876344787ab0a9cae18ad802 Mon Sep 17 00:00:00 2001 From: "chao.an" Date: Fri, 11 Feb 2022 20:13:35 +0800 Subject: [PATCH 34/43] [BACKPORT] net/can: remove psock reference from can connect remove the psock back reference since timestamp has been migrated to can_conn_s Signed-off-by: chao.an --- net/can/can.h | 4 ---- net/can/can_sockif.c | 6 ------ 2 files changed, 10 deletions(-) diff --git a/net/can/can.h b/net/can/can.h index b2b51b778de..ea67fe1c948 100644 --- a/net/can/can.h +++ b/net/can/can.h @@ -117,10 +117,6 @@ struct can_conn_s int32_t tx_deadline; # endif #endif - -#ifdef CONFIG_NET_TIMESTAMP - FAR struct socket *psock; /* Needed to get SO_TIMESTAMP value */ -#endif }; /**************************************************************************** diff --git a/net/can/can_sockif.c b/net/can/can_sockif.c index 60b38bba11e..780641f9727 100644 --- a/net/can/can_sockif.c +++ b/net/can/can_sockif.c @@ -221,12 +221,6 @@ static int can_setup(FAR struct socket *psock, int protocol) return -ENOMEM; } -#ifdef CONFIG_NET_TIMESTAMP - /* Store psock in conn se we can read the SO_TIMESTAMP value */ - - conn->psock = psock; -#endif - /* Initialize the connection instance */ conn->protocol = (uint8_t)protocol; From 1bf174d857319053b363f11cc758eddf8525e99c Mon Sep 17 00:00:00 2001 From: raiden00pl Date: Sat, 12 Feb 2022 22:27:52 +0100 Subject: [PATCH 35/43] [BACKPORT] net/can/can_setsockopt.c: fix assertion, value can be NULL --- net/can/can_setsockopt.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/net/can/can_setsockopt.c b/net/can/can_setsockopt.c index b5c4576e874..edd6e07c513 100644 --- a/net/can/can_setsockopt.c +++ b/net/can/can_setsockopt.c @@ -76,7 +76,9 @@ int can_setsockopt(FAR struct socket *psock, int option, int ret = OK; int count = 0; - DEBUGASSERT(psock != NULL && value != NULL && psock->s_conn != NULL); + DEBUGASSERT(psock != NULL && psock->s_conn != NULL); + DEBUGASSERT(value_len == 0 || value != NULL); + conn = (FAR struct can_conn_s *)psock->s_conn; if (psock->s_type != SOCK_RAW) @@ -147,9 +149,9 @@ int can_setsockopt(FAR struct socket *psock, int option, return -EINVAL; } - conn->fd_frames = *(FAR int32_t *)value; + conn->fd_frames = *(FAR int32_t *)value; - break; + break; #endif case CAN_RAW_JOIN_FILTERS: From e21e4f901a6d13349dbf79d76cfec5727576ea2f Mon Sep 17 00:00:00 2001 From: raiden00pl Date: Sat, 12 Feb 2022 13:26:13 +0100 Subject: [PATCH 36/43] [BACKPORT] stm32/fdcan: use array indexes when accessing RX/TX FIFO --- arch/arm/src/stm32/stm32_fdcan.c | 52 +++++++++++++-------------- arch/arm/src/stm32/stm32_fdcan_sock.c | 48 ++++++++++++------------- 2 files changed, 49 insertions(+), 51 deletions(-) diff --git a/arch/arm/src/stm32/stm32_fdcan.c b/arch/arm/src/stm32/stm32_fdcan.c index af3acde2b15..61e937f3cb6 100644 --- a/arch/arm/src/stm32/stm32_fdcan.c +++ b/arch/arm/src/stm32/stm32_fdcan.c @@ -2354,37 +2354,40 @@ static int fdcan_send(FAR struct can_dev_s *dev, FAR struct can_msg_s *msg) * Transfer message ID (ID) - Value from message structure * Remote Transmission Request (RTR) - Value from message structure * Extended Identifier (XTD) - Depends on configuration. + * Error state indicator (ESI) - ESI bit in CAN FD + * + * Format word T1: + * Data Length Code (DLC) - Value from message structure + * Bit Rate Switch (BRS) - Bit rate switching for CAN FD + * FD format (FDF) - Frame transmited in CAN FD format + * Event FIFO Control (EFC) - Do not store events. + * Message Marker (MM) - Always zero */ + txbuffer[0] = 0; + txbuffer[1] = 0; + #ifdef CONFIG_CAN_EXTID if (msg->cm_hdr.ch_extid) { DEBUGASSERT(msg->cm_hdr.ch_id <= CAN_MAX_EXTMSGID); - regval = BUFFER_R0_EXTID(msg->cm_hdr.ch_id) | BUFFER_R0_XTD; + txbuffer[0] |= BUFFER_R0_EXTID(msg->cm_hdr.ch_id) | BUFFER_R0_XTD; } else #endif { DEBUGASSERT(msg->cm_hdr.ch_id <= CAN_MAX_STDMSGID); - regval = BUFFER_R0_STDID(msg->cm_hdr.ch_id); + txbuffer[0] |= BUFFER_R0_STDID(msg->cm_hdr.ch_id); } if (msg->cm_hdr.ch_rtr) { - regval |= BUFFER_R0_RTR; + txbuffer[0] |= BUFFER_R0_RTR; } - txbuffer[0] = regval; - - /* Format word T1: - * Data Length Code (DLC) - Value from message structure - * Event FIFO Control (EFC) - Do not store events. - * Message Marker (MM) - Always zero - */ - - txbuffer[1] = BUFFER_R1_DLC(msg->cm_hdr.ch_dlc); + txbuffer[1] |= BUFFER_R1_DLC(msg->cm_hdr.ch_dlc); /* Followed by the amount of data corresponding to the DLC (T2..) */ @@ -2773,16 +2776,13 @@ static void fdcan_receive(FAR struct can_dev_s *dev, unsigned long nwords) { struct can_hdr_s hdr; - uint32_t regval = 0; int ret = 0; fdcan_dumprxregs(dev->cd_priv, "Before receive"); /* Format the CAN header */ - /* Work R0 contains the CAN ID */ - - regval = *rxbuffer++; + /* Word R0 contains the CAN ID */ #ifdef CONFIG_CAN_ERRORS hdr.ch_error = 0; @@ -2791,46 +2791,46 @@ static void fdcan_receive(FAR struct can_dev_s *dev, /* Extract the RTR bit */ - hdr.ch_rtr = ((regval & BUFFER_R0_RTR) != 0); + hdr.ch_rtr = ((rxbuffer[0] & BUFFER_R0_RTR) != 0); #ifdef CONFIG_CAN_EXTID - if ((regval & BUFFER_R0_XTD) != 0) + if ((rxbuffer[0] & BUFFER_R0_XTD) != 0) { /* Save the extended ID of the newly received message */ - hdr.ch_id = (regval & BUFFER_R0_EXTID_MASK) >> + hdr.ch_id = (rxbuffer[0] & BUFFER_R0_EXTID_MASK) >> BUFFER_R0_EXTID_SHIFT; hdr.ch_extid = 1; } else { - hdr.ch_id = (regval & BUFFER_R0_STDID_MASK) >> + hdr.ch_id = (rxbuffer[0] & BUFFER_R0_STDID_MASK) >> BUFFER_R0_STDID_SHIFT; hdr.ch_extid = 0; } #else - if ((regval & BUFFER_R0_XTD) != 0) + if ((rxbuffer[0] & BUFFER_R0_XTD) != 0) { /* Drop any messages with extended IDs */ + canerr("ERROR: Received message with extended identifier. Dropped\n"); + return; } /* Save the standard ID of the newly received message */ - hdr.ch_id = (regval & BUFFER_R0_STDID_MASK) >> BUFFER_R0_STDID_SHIFT; + hdr.ch_id = (rxbuffer[0] & BUFFER_R0_STDID_MASK) >> BUFFER_R0_STDID_SHIFT; #endif /* Word R1 contains the DLC and timestamp */ - regval = *rxbuffer++; - - hdr.ch_dlc = (regval & BUFFER_R1_DLC_MASK) >> BUFFER_R1_DLC_SHIFT; + hdr.ch_dlc = (rxbuffer[1] & BUFFER_R1_DLC_MASK) >> BUFFER_R1_DLC_SHIFT; /* And provide the CAN message to the upper half logic */ - ret = can_receive(dev, &hdr, (FAR uint8_t *)rxbuffer); + ret = can_receive(dev, &hdr, (FAR uint8_t *)&rxbuffer[2]); if (ret < 0) { canerr("ERROR: can_receive failed: %d\n", ret); diff --git a/arch/arm/src/stm32/stm32_fdcan_sock.c b/arch/arm/src/stm32/stm32_fdcan_sock.c index 6d61d065605..e80e512a727 100644 --- a/arch/arm/src/stm32/stm32_fdcan_sock.c +++ b/arch/arm/src/stm32/stm32_fdcan_sock.c @@ -1716,36 +1716,39 @@ static int fdcan_send(FAR struct stm32_fdcan_s *priv) * Transfer message ID (ID) - Value from message structure * Remote Transmission Request (RTR) - Value from message structure * Extended Identifier (XTD) - Depends on configuration. + * Error state indicator (ESI) - ESI bit in CAN FD + * + * Format word T1: + * Data Length Code (DLC) - Value from message structure + * Bit Rate Switch (BRS) - Bit rate switching for CAN FD + * FD format (FDF) - Frame transmited in CAN FD format + * Event FIFO Control (EFC) - Do not store events. + * Message Marker (MM) - Always zero */ + txbuffer[0] = 0; + txbuffer[1] = 0; + #ifdef CONFIG_NET_CAN_EXTID if (frame->can_id & CAN_EFF_FLAG) { DEBUGASSERT(frame->can_id < (1 << 29)); - regval = BUFFER_R0_EXTID(frame->can_id) | BUFFER_R0_XTD; + txbuffer[0] |= BUFFER_R0_EXTID(frame->can_id) | BUFFER_R0_XTD; } else #endif { DEBUGASSERT(frame->can_id < (1 << 11)); - regval = BUFFER_R0_STDID(frame->can_id); + txbuffer[0] |= BUFFER_R0_STDID(frame->can_id); } if (frame->can_id & CAN_RTR_FLAG) { - regval |= BUFFER_R0_RTR; + txbuffer[0] |= BUFFER_R0_RTR; } - txbuffer[0] = regval; - - /* Format word T1: - * Data Length Code (DLC) - Value from message structure - * Event FIFO Control (EFC) - Do not store events. - * Message Marker (MM) - Always zero - */ - txbuffer[1] = BUFFER_R1_DLC(frame->can_dlc); /* Followed by the amount of data corresponding to the DLC (T2..) */ @@ -2392,40 +2395,37 @@ static void fdcan_receive(FAR struct stm32_fdcan_s *priv, unsigned long nwords) { FAR struct can_frame *frame = (struct can_frame *)priv->rxdesc; - uint32_t regval = 0; fdcan_dumprxregs(dev->cd_priv, "Before receive"); /* Format the CAN header */ - /* Work R0 contains the CAN ID */ - - regval = *rxbuffer++; + /* Word R0 contains the CAN ID */ /* Extract the RTR bit */ - if ((regval & BUFFER_R0_RTR) != 0) + if ((rxbuffer[0] & BUFFER_R0_RTR) != 0) { frame->can_id |= CAN_RTR_FLAG; } #ifdef CONFIG_NET_CAN_EXTID - if ((regval & BUFFER_R0_XTD) != 0) + if ((rxbuffer[0] & BUFFER_R0_XTD) != 0) { /* Save the extended ID of the newly received message */ - frame->can_id = (regval & BUFFER_R0_EXTID_MASK) >> + frame->can_id = (rxbuffer[0] & BUFFER_R0_EXTID_MASK) >> BUFFER_R0_EXTID_SHIFT; frame->can_id |= CAN_EFF_FLAG; } else { - frame->can_id = (regval & BUFFER_R0_STDID_MASK) >> + frame->can_id = (rxbuffer[0] & BUFFER_R0_STDID_MASK) >> BUFFER_R0_STDID_SHIFT; frame->can_id &= ~CAN_EFF_FLAG; } #else - if ((regval & BUFFER_R0_XTD) != 0) + if ((rxbuffer[0] & BUFFER_R0_XTD) != 0) { /* Drop any messages with extended IDs */ @@ -2434,18 +2434,16 @@ static void fdcan_receive(FAR struct stm32_fdcan_s *priv, /* Save the standard ID of the newly received message */ - frame->can_id = (regval & BUFFER_R0_STDID_MASK) >> BUFFER_R0_STDID_SHIFT; + frame->can_id = (rxbuffer[0] & BUFFER_R0_STDID_MASK) >> BUFFER_R0_STDID_SHIFT; #endif /* Word R1 contains the DLC and timestamp */ - regval = *rxbuffer++; - - frame->can_dlc = (regval & BUFFER_R1_DLC_MASK) >> BUFFER_R1_DLC_SHIFT; + frame->can_dlc = (rxbuffer[1] & BUFFER_R1_DLC_MASK) >> BUFFER_R1_DLC_SHIFT; /* Save the message data */ - memcpy(frame->data, (void *)rxbuffer, frame->can_dlc); + memcpy(frame->data, (void *)&rxbuffer[2], frame->can_dlc); /* Copy the buffer pointer to priv->dev.. Set amount of data * in priv->dev.d_len From 79a623a33730fffcb3f484ba3f6e1498de28576c Mon Sep 17 00:00:00 2001 From: raiden00pl Date: Sat, 12 Feb 2022 20:11:08 +0100 Subject: [PATCH 37/43] [BACKPORT] stm32/fdcan: add CAN FD frames support --- arch/arm/src/stm32/Kconfig | 1 + arch/arm/src/stm32/stm32_fdcan.c | 47 +++- arch/arm/src/stm32/stm32_fdcan_sock.c | 339 +++++++++++++++++--------- 3 files changed, 267 insertions(+), 120 deletions(-) diff --git a/arch/arm/src/stm32/Kconfig b/arch/arm/src/stm32/Kconfig index ef2dd8814f0..b06be53131c 100644 --- a/arch/arm/src/stm32/Kconfig +++ b/arch/arm/src/stm32/Kconfig @@ -10724,6 +10724,7 @@ config STM32_FDCAN_CHARDRIVER config STM32_FDCAN_SOCKET bool "STM32 FDCAN SocketCAN support" select NET_CAN_HAVE_ERRORS + select NET_CAN_HAVE_CANFD endchoice # FDCAN character driver or SocketCAN support diff --git a/arch/arm/src/stm32/stm32_fdcan.c b/arch/arm/src/stm32/stm32_fdcan.c index 61e937f3cb6..e25ca0f276a 100644 --- a/arch/arm/src/stm32/stm32_fdcan.c +++ b/arch/arm/src/stm32/stm32_fdcan.c @@ -2368,7 +2368,7 @@ static int fdcan_send(FAR struct can_dev_s *dev, FAR struct can_msg_s *msg) txbuffer[1] = 0; #ifdef CONFIG_CAN_EXTID - if (msg->cm_hdr.ch_extid) + if (msg->cm_hdr.ch_extid == 1) { DEBUGASSERT(msg->cm_hdr.ch_id <= CAN_MAX_EXTMSGID); @@ -2382,13 +2382,39 @@ static int fdcan_send(FAR struct can_dev_s *dev, FAR struct can_msg_s *msg) txbuffer[0] |= BUFFER_R0_STDID(msg->cm_hdr.ch_id); } - if (msg->cm_hdr.ch_rtr) + if (msg->cm_hdr.ch_rtr == 1) { txbuffer[0] |= BUFFER_R0_RTR; } txbuffer[1] |= BUFFER_R1_DLC(msg->cm_hdr.ch_dlc); +#ifdef CONFIG_CAN_FD + /* CAN FD Format */ + + if (msg->cm_hdr.ch_edl == 1) + { + txbuffer[1] |= BUFFER_R1_FDF; + + if (msg->cm_hdr.ch_brs == 1) + { + txbuffer[1] |= BUFFER_R1_BRS; + } + + if (msg->cm_hdr.ch_esi == 1) + { + txbuffer[0] |= BUFFER_R0_ESI; + } + } + else +#else + { + txbuffer[0] &= ~BUFFER_R0_ESI; + txbuffer[1] &= ~BUFFER_R1_FDF; + txbuffer[1] &= ~BUFFER_R1_BRS; + } +#endif + /* Followed by the amount of data corresponding to the DLC (T2..) */ dest = (FAR uint32_t *)&txbuffer[2]; @@ -2828,6 +2854,23 @@ static void fdcan_receive(FAR struct can_dev_s *dev, hdr.ch_dlc = (rxbuffer[1] & BUFFER_R1_DLC_MASK) >> BUFFER_R1_DLC_SHIFT; +#ifdef CONFIG_CAN_FD + /* CAN FD format */ + + hdr.ch_esi = ((rxbuffer[0] & BUFFER_R0_ESI) != 0); + hdr.ch_edl = ((rxbuffer[1] & BUFFER_R1_FDF) != 0); + hdr.ch_brs = ((rxbuffer[1] & BUFFER_R1_BRS) != 0); +#else + if ((rxbuffer[1] & BUFFER_R1_FDF) != 0) + { + /* Drop any FD CAN messages if not supported */ + + canerr("ERROR: Received CAN FD message. Dropped\n"); + + return; + } +#endif + /* And provide the CAN message to the upper half logic */ ret = can_receive(dev, &hdr, (FAR uint8_t *)&rxbuffer[2]); diff --git a/arch/arm/src/stm32/stm32_fdcan_sock.c b/arch/arm/src/stm32/stm32_fdcan_sock.c index e80e512a727..f5cf125d377 100644 --- a/arch/arm/src/stm32/stm32_fdcan_sock.c +++ b/arch/arm/src/stm32/stm32_fdcan_sock.c @@ -449,7 +449,7 @@ enum stm32_frameformat_e enum stm32_canmode_e { FDCAN_CLASSIC_MODE = 0, /* Classic CAN operation */ -#ifdef CONFIG_CAN_FD +#ifdef CONFIG_NET_CAN_CANFD FDCAN_FD_MODE = 1, /* CAN FD operation */ FDCAN_FD_BRS_MODE = 2 /* CAN FD operation with bit rate switching */ #endif @@ -551,8 +551,13 @@ struct stm32_fdcan_s /* TX/RX pool */ +#ifdef CONFIG_NET_CAN_CANFD + uint8_t tx_pool[sizeof(struct canfd_frame)*POOL_SIZE]; + uint8_t rx_pool[sizeof(struct canfd_frame)*POOL_SIZE]; +#else uint8_t tx_pool[sizeof(struct can_frame)*POOL_SIZE]; uint8_t rx_pool[sizeof(struct can_frame)*POOL_SIZE]; +#endif }; /**************************************************************************** @@ -628,8 +633,6 @@ static void fdcan_shutdown(FAR struct stm32_fdcan_s *priv); /* FDCAN helpers */ -static uint8_t fdcan_dlc2bytes(FAR struct stm32_fdcan_s *priv, uint8_t dlc); - #if 0 /* not used for now */ static int fdcan_start_busoff_recovery_sequence(FAR struct stm32_fdcan_s *priv); @@ -1194,62 +1197,6 @@ static void fdcan_dumpramlayout(FAR struct stm32_fdcan_s *priv) } #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_start_busoff_recovery_sequence * @@ -1673,7 +1620,6 @@ static void fdcan_errint(FAR struct stm32_fdcan_s *priv, bool enable) static int fdcan_send(FAR struct stm32_fdcan_s *priv) { - struct can_frame *frame = NULL; FAR const struct stm32_config_s *config = NULL; FAR volatile uint32_t *txbuffer = NULL; FAR const uint8_t *src = NULL; @@ -1688,11 +1634,6 @@ static int fdcan_send(FAR struct stm32_fdcan_s *priv) config = priv->config; DEBUGASSERT(config); - frame = (struct can_frame *)priv->dev.d_buf; - - ninfo("CAN%" PRIu8 " ID: %" PRIu32 " DLC: %" PRIu8 "\n", - config->port, (uint32_t)frame->can_id, frame->can_dlc); - fdcan_dumptxregs(priv, "Before send"); /* That that FIFO elements were configured */ @@ -1729,33 +1670,116 @@ static int fdcan_send(FAR struct stm32_fdcan_s *priv) txbuffer[0] = 0; txbuffer[1] = 0; -#ifdef CONFIG_NET_CAN_EXTID - if (frame->can_id & CAN_EFF_FLAG) + /* CAN 2.0 or CAN FD */ + + if (priv->dev.d_len == sizeof(struct can_frame)) { - DEBUGASSERT(frame->can_id < (1 << 29)); + struct can_frame *frame = NULL; - txbuffer[0] |= BUFFER_R0_EXTID(frame->can_id) | BUFFER_R0_XTD; - } - else + frame = (struct can_frame *)priv->dev.d_buf; + + ninfo("CAN%" PRIu8 " 2.0 ID: %" PRIu32 " DLC: %" PRIu8 "\n", + config->port, (uint32_t)frame->can_id, frame->can_dlc); + + /* Extended or standard ID */ + +#ifdef CONFIG_NET_CAN_EXTID + if ((frame->can_id & CAN_EFF_FLAG) != 0) + { + DEBUGASSERT(frame->can_id < (1 << 29)); + + txbuffer[0] |= BUFFER_R0_EXTID(frame->can_id) | BUFFER_R0_XTD; + } + else #endif - { - DEBUGASSERT(frame->can_id < (1 << 11)); + { + DEBUGASSERT(frame->can_id < (1 << 11)); - txbuffer[0] |= BUFFER_R0_STDID(frame->can_id); - } + txbuffer[0] |= BUFFER_R0_STDID(frame->can_id); + } - if (frame->can_id & CAN_RTR_FLAG) - { - txbuffer[0] |= BUFFER_R0_RTR; + /* Set DLC */ + + txbuffer[1] |= BUFFER_R1_DLC(frame->can_dlc); + + /* Set flags */ + + if ((frame->can_id & CAN_RTR_FLAG) != 0) + { + txbuffer[0] |= BUFFER_R0_RTR; + } + + /* Reset CAN FD bits */ + + txbuffer[0] &= ~BUFFER_R0_ESI; + txbuffer[1] &= ~BUFFER_R1_FDF; + txbuffer[1] &= ~BUFFER_R1_BRS; + + /* Followed by the amount of data corresponding to the DLC (T2..) */ + + src = frame->data; + nbytes = frame->can_dlc; } +#ifdef CONFIG_NET_CAN_CANFD + else /* CAN FD frame */ + { + struct canfd_frame *frame = (struct canfd_frame *)priv->dev.d_buf; + + frame = (struct canfd_frame *)priv->dev.d_buf; + + ninfo("CAN%" PRIu8 " FD ID: %" PRIu32 " len: %" PRIu8 "\n", + config->port, (uint32_t)frame->can_id, frame->len); + + /* Extended or standard ID */ + +#ifdef CONFIG_NET_CAN_EXTID + if ((frame->can_id & CAN_EFF_FLAG) != 0) + { + DEBUGASSERT(frame->can_id < (1 << 29)); + + txbuffer[0] |= BUFFER_R0_EXTID(frame->can_id) | BUFFER_R0_XTD; + } + else +#endif + { + DEBUGASSERT(frame->can_id < (1 << 11)); + + txbuffer[0] |= BUFFER_R0_STDID(frame->can_id); + } + + /* CANFD frame */ + + txbuffer[1] |= BUFFER_R1_FDF; + + /* Set DLC */ + + txbuffer[1] |= BUFFER_R1_DLC(len_to_can_dlc[frame->len]); + + /* Set flags */ - txbuffer[1] = BUFFER_R1_DLC(frame->can_dlc); + if ((frame->can_id & CAN_RTR_FLAG) != 0) + { + txbuffer[0] |= BUFFER_R0_RTR; + } + + if ((frame->flags & CANFD_BRS) != 0) + { + txbuffer[1] |= BUFFER_R1_BRS; + } - /* Followed by the amount of data corresponding to the DLC (T2..) */ + if ((frame->flags & CANFD_ESI) != 0) + { + txbuffer[0] |= BUFFER_R0_ESI; + } + + /* Followed by the amount of data corresponding to the DLC (T2..) */ + + src = frame->data; + nbytes = frame->len; + } +#endif dest = (FAR uint32_t *)&txbuffer[2]; - src = frame->data; - nbytes = fdcan_dlc2bytes(priv, frame->can_dlc); /* Writes must be word length */ @@ -2394,63 +2418,142 @@ static void fdcan_receive(FAR struct stm32_fdcan_s *priv, FAR volatile uint32_t *rxbuffer, unsigned long nwords) { - FAR struct can_frame *frame = (struct can_frame *)priv->rxdesc; - fdcan_dumprxregs(dev->cd_priv, "Before receive"); - /* Format the CAN header */ + /* CAN 2.0 or CAN FD */ - /* Word R0 contains the CAN ID */ +#ifdef CONFIG_NET_CAN_CANFD + if ((rxbuffer[1] & BUFFER_R1_FDF) != 0) + { + struct canfd_frame *frame = (struct canfd_frame *)priv->rxdesc; - /* Extract the RTR bit */ + /* Format the CAN FD header */ - if ((rxbuffer[0] & BUFFER_R0_RTR) != 0) - { - frame->can_id |= CAN_RTR_FLAG; - } + /* Extract the RTR bit */ + + if ((rxbuffer[0] & BUFFER_R0_RTR) != 0) + { + frame->can_id |= CAN_RTR_FLAG; + } #ifdef CONFIG_NET_CAN_EXTID - if ((rxbuffer[0] & BUFFER_R0_XTD) != 0) - { - /* Save the extended ID of the newly received message */ + if ((rxbuffer[0] & BUFFER_R0_XTD) != 0) + { + /* Save the extended ID of the newly received message */ + + frame->can_id = ((rxbuffer[0] & BUFFER_R0_EXTID_MASK) >> + BUFFER_R0_EXTID_SHIFT); + frame->can_id |= CAN_EFF_FLAG; + } + else + { + frame->can_id = ((rxbuffer[0] & BUFFER_R0_STDID_MASK) >> + BUFFER_R0_STDID_SHIFT); + frame->can_id &= ~CAN_EFF_FLAG; + } +#else + if ((rxbuffer[0] & BUFFER_R0_XTD) != 0) + { + /* Drop any messages with extended IDs */ + + return; + } - frame->can_id = (rxbuffer[0] & BUFFER_R0_EXTID_MASK) >> - BUFFER_R0_EXTID_SHIFT; - frame->can_id |= CAN_EFF_FLAG; + /* Save the standard ID of the newly received message */ + + frame->can_id = ((rxbuffer[0] & BUFFER_R0_STDID_MASK) >> + BUFFER_R0_STDID_SHIFT); +#endif + + /* Word R1 contains the DLC and timestamp */ + + frame->len = can_dlc_to_len[((rxbuffer[1] & BUFFER_R1_DLC_MASK) >> + BUFFER_R1_DLC_SHIFT)]; + + /* Get CANFD flags */ + + frame->flags = 0; + + if ((rxbuffer[0] & BUFFER_R0_ESI) != 0) + { + frame->flags |= CANFD_ESI; + } + + if ((rxbuffer[1] & BUFFER_R1_BRS) != 0) + { + frame->flags |= CANFD_BRS; + } + + /* Save the message data */ + + memcpy(frame->data, (void *)&rxbuffer[2], frame->len); + + /* Copy the buffer pointer to priv->dev.. Set amount of data + * in priv->dev.d_len + */ + + priv->dev.d_len = sizeof(struct canfd_frame); + priv->dev.d_buf = (uint8_t *)frame; } else +#endif { - frame->can_id = (rxbuffer[0] & BUFFER_R0_STDID_MASK) >> - BUFFER_R0_STDID_SHIFT; - frame->can_id &= ~CAN_EFF_FLAG; - } + FAR struct can_frame *frame = (struct can_frame *)priv->rxdesc; + + /* Format the CAN header */ + + /* Extract the RTR bit */ + + if ((rxbuffer[0] & BUFFER_R0_RTR) != 0) + { + frame->can_id |= CAN_RTR_FLAG; + } + +#ifdef CONFIG_NET_CAN_EXTID + if ((rxbuffer[0] & BUFFER_R0_XTD) != 0) + { + /* Save the extended ID of the newly received message */ + + frame->can_id = ((rxbuffer[0] & BUFFER_R0_EXTID_MASK) >> + BUFFER_R0_EXTID_SHIFT); + frame->can_id |= CAN_EFF_FLAG; + } + else + { + frame->can_id = ((rxbuffer[0] & BUFFER_R0_STDID_MASK) >> + BUFFER_R0_STDID_SHIFT); + frame->can_id &= ~CAN_EFF_FLAG; + } #else - if ((rxbuffer[0] & BUFFER_R0_XTD) != 0) - { - /* Drop any messages with extended IDs */ + if ((rxbuffer[0] & BUFFER_R0_XTD) != 0) + { + /* Drop any messages with extended IDs */ - return; - } + return; + } - /* Save the standard ID of the newly received message */ + /* Save the standard ID of the newly received message */ - frame->can_id = (rxbuffer[0] & BUFFER_R0_STDID_MASK) >> BUFFER_R0_STDID_SHIFT; + frame->can_id = ((rxbuffer[0] & BUFFER_R0_STDID_MASK) >> + BUFFER_R0_STDID_SHIFT); #endif - /* Word R1 contains the DLC and timestamp */ + /* Word R1 contains the DLC and timestamp */ - frame->can_dlc = (rxbuffer[1] & BUFFER_R1_DLC_MASK) >> BUFFER_R1_DLC_SHIFT; + frame->can_dlc = ((rxbuffer[1] & BUFFER_R1_DLC_MASK) >> + BUFFER_R1_DLC_SHIFT); - /* Save the message data */ + /* Save the message data */ - memcpy(frame->data, (void *)&rxbuffer[2], frame->can_dlc); + memcpy(frame->data, (void *)&rxbuffer[2], frame->can_dlc); - /* Copy the buffer pointer to priv->dev.. Set amount of data - * in priv->dev.d_len - */ + /* Copy the buffer pointer to priv->dev.. Set amount of data + * in priv->dev.d_len + */ - priv->dev.d_len = sizeof(struct can_frame); - priv->dev.d_buf = (uint8_t *)frame; + priv->dev.d_len = sizeof(struct can_frame); + priv->dev.d_buf = (uint8_t *)frame; + } /* Send to socket interface */ @@ -2740,7 +2843,7 @@ static int fdcan_hw_initialize(struct stm32_fdcan_s *priv) break; } -#ifdef CONFIG_CAN_FD +#ifdef CONFIG_NET_CAN_CANFD case FDCAN_FD_MODE: { regval |= FDCAN_CCCR_FDOE; From a0c05c243c844b4a2b14b7d7ca6db57d2a59e7d4 Mon Sep 17 00:00:00 2001 From: Oleg Evseev Date: Thu, 3 Mar 2022 18:38:28 +0300 Subject: [PATCH 38/43] [BACKPORT] arch/arm/src/stm32f7/stm32_can.c: fix CAN3 receiving by fixing filter initialization. STM32F7 CAN3 works in single peripheral configuration and there is only 14 filter banks: 0-13. Previously not available 14 indexed filter (CAN_NFILTERS/2) was wrongly used for for receiving to FIFO. Now zero indexed filter is correctly used instead. --- arch/arm/src/stm32f7/stm32_can.c | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/arch/arm/src/stm32f7/stm32_can.c b/arch/arm/src/stm32f7/stm32_can.c index 727aaaaa3ec..4e8c1d0b990 100644 --- a/arch/arm/src/stm32f7/stm32_can.c +++ b/arch/arm/src/stm32f7/stm32_can.c @@ -254,7 +254,7 @@ static struct stm32_can_s g_can3priv = STM32_IRQ_CAN3RX1, }, .cantx = STM32_IRQ_CAN3TX, - .filter = CAN_NFILTERS / 2, + .filter = 0, .base = STM32_CAN3_BASE, .fbase = STM32_CAN3_BASE, .baud = CONFIG_STM32F7_CAN3_BAUD, @@ -2022,10 +2022,11 @@ static int stm32can_cellinit(FAR struct stm32_can_s *priv) * more filters; The advantage of 32-bit filters is that you get * finer control of the filtering. * - * One filter is set up for each CAN. The filter resources are shared - * between the two CAN modules: CAN1 uses only filter 0 (but reserves + * One filter is set up for each CAN. The filter resources are shared + * between CAN1 and CAN2 modules: CAN1 uses only filter 0 (but reserves * 0 through CAN_NFILTERS/2-1); CAN2 uses only filter CAN_NFILTERS/2 * (but reserves CAN_NFILTERS/2 through CAN_NFILTERS-1). + * CAN3 works in single peripheral configuration and uses only filter 0. * * 32-bit IdMask mode is configured. However, both the ID and the MASK * are set to zero thus suppressing all filtering because anything masked @@ -2056,12 +2057,17 @@ static int stm32can_filterinit(FAR struct stm32_can_s *priv) regval |= CAN_FMR_FINIT; stm32can_putfreg(priv, STM32_CAN_FMR_OFFSET, regval); - /* Assign half the filters to CAN1, half to CAN2 */ +#if defined(CONFIG_STM32F7_CAN1) || defined(CONFIG_STM32F7_CAN2) + if (priv->port == 1 || priv->port == 2) + { + /* Assign half the filters to CAN1, half to CAN2 */ - regval = stm32can_getfreg(priv, STM32_CAN_FMR_OFFSET); - regval &= CAN_FMR_CAN2SB_MASK; - regval |= (CAN_NFILTERS / 2) << CAN_FMR_CAN2SB_SHIFT; - stm32can_putfreg(priv, STM32_CAN_FMR_OFFSET, regval); + regval = stm32can_getfreg(priv, STM32_CAN_FMR_OFFSET); + regval &= CAN_FMR_CAN2SB_MASK; + regval |= (CAN_NFILTERS / 2) << CAN_FMR_CAN2SB_SHIFT; + stm32can_putfreg(priv, STM32_CAN_FMR_OFFSET, regval); + } +#endif /* Disable the filter */ @@ -2339,4 +2345,4 @@ FAR struct can_dev_s *stm32_caninitialize(int port) return dev; } -#endif /* CONFIG_CAN && (CONFIG_STM32_CAN1 || CONFIG_STM32_CAN2) */ +#endif /* CONFIG_CAN && (CONFIG_STM32_CAN1 || CONFIG_STM32_CAN2 || CONFIG_STM32_CAN3) */ From e59645042d9a8ff2892e30de348a3c20f750dec9 Mon Sep 17 00:00:00 2001 From: Petro Karashchenko Date: Fri, 11 Mar 2022 16:46:20 +0100 Subject: [PATCH 39/43] [BACKPORT] drivers/can: optimize can driver reader side Signed-off-by: Petro Karashchenko --- arch/arm/src/lpc43xx/lpc43_can.c | 2 +- drivers/can/can.c | 96 ++++++++++++++++++-------------- include/nuttx/can/can.h | 6 +- 3 files changed, 60 insertions(+), 44 deletions(-) diff --git a/arch/arm/src/lpc43xx/lpc43_can.c b/arch/arm/src/lpc43xx/lpc43_can.c index 48e0b90ec90..07cf9f631db 100644 --- a/arch/arm/src/lpc43xx/lpc43_can.c +++ b/arch/arm/src/lpc43xx/lpc43_can.c @@ -186,7 +186,7 @@ static int can_bittiming(struct up_dev_s *priv); static const struct can_ops_s g_canops = { .co_reset = can_reset, - .co_setup = can_setup, + .co_setup = can_setup, .co_shutdown = can_shutdown, .co_rxint = can_rxint, .co_txint = can_txint, diff --git a/drivers/can/can.c b/drivers/can/can.c index 76369c82fe9..981c077b56b 100644 --- a/drivers/can/can.c +++ b/drivers/can/can.c @@ -411,7 +411,6 @@ static int can_open(FAR struct file *filep) FAR struct inode *inode = filep->f_inode; FAR struct can_dev_s *dev = inode->i_private; irqstate_t flags; - int tmp; int ret; /* If the port is the middle of closing, wait until the close is finished */ @@ -426,46 +425,48 @@ static int can_open(FAR struct file *filep) * for this device, then perform hardware initialization. */ - if (list_is_empty(&dev->cd_readers)) + caninfo("ocount: %u\n", dev->cd_crefs); + + if (dev->cd_crefs >= 255) { - caninfo("ocount: %d\n", 0); + /* Limit to no more than 255 opens */ + ret = -EMFILE; + goto errout; + } + else + { flags = enter_critical_section(); - ret = dev_setup(dev); - if (ret >= 0) + + if (dev->cd_crefs == 0) { - /* Mark the FIFOs empty */ + ret = dev_setup(dev); + if (ret == OK) + { + /* Mark the FIFOs empty */ - dev->cd_xmit.tx_head = 0; - dev->cd_xmit.tx_queue = 0; - dev->cd_xmit.tx_tail = 0; + dev->cd_xmit.tx_head = 0; + dev->cd_xmit.tx_queue = 0; + dev->cd_xmit.tx_tail = 0; - /* Finally, Enable the CAN RX interrupt */ + /* Finally, Enable the CAN RX interrupt */ - dev_rxint(dev, true); + dev_rxint(dev, true); + } } - list_add_head(&dev->cd_readers, - (FAR struct list_node *)init_can_reader(filep)); - - leave_critical_section(flags); - } - else - { - tmp = list_length(&dev->cd_readers); - caninfo("ocount: %d\n", tmp); - - if (tmp >= 255) + if (ret == OK) { - /* Limit to no more than 255 opens */ + dev->cd_crefs++; - ret = -EMFILE; - goto errout; - } + /* Update the reader list only if driver was open for reading */ - flags = enter_critical_section(); - list_add_head(&dev->cd_readers, - (FAR struct list_node *)init_can_reader(filep)); + if ((filep->f_oflags & O_RDOK) != 0) + { + list_add_head(&dev->cd_readers, + (FAR struct list_node *)init_can_reader(filep)); + } + } leave_critical_section(flags); } @@ -494,7 +495,7 @@ static int can_close(FAR struct file *filep) int ret; #ifdef CONFIG_DEBUG_CAN_INFO - caninfo("ocount: %d\n", list_length(&dev->cd_readers)); + caninfo("ocount: %u\n", dev->cd_crefs); #endif ret = can_takesem(&dev->cd_closesem); @@ -515,10 +516,11 @@ static int can_close(FAR struct file *filep) } filep->f_priv = NULL; + dev->cd_crefs--; - /* Uninitialize the driver if there are no more readers */ + /* De-initialize the driver if there are no more readers */ - if (!list_is_empty(&dev->cd_readers)) + if (dev->cd_crefs > 0) { goto errout; } @@ -563,7 +565,7 @@ static int can_close(FAR struct file *filep) static ssize_t can_read(FAR struct file *filep, FAR char *buffer, size_t buflen) { - FAR struct can_reader_s *reader = NULL; + FAR struct can_reader_s *reader; FAR struct can_rxfifo_s *fifo; size_t nread; irqstate_t flags; @@ -582,11 +584,25 @@ static ssize_t can_read(FAR struct file *filep, FAR char *buffer, if (buflen >= CAN_MSGLEN(0)) { + DEBUGASSERT(filep->f_priv != NULL); + reader = (FAR struct can_reader_s *)filep->f_priv; + + fifo = &reader->fifo; + /* Interrupts must be disabled while accessing the cd_recv FIFO */ flags = enter_critical_section(); #ifdef CONFIG_CAN_ERRORS + + /* Check for reader fifo overflow */ + + if (fifo->rx_overflow) + { + dev->cd_error |= CAN_ERROR5_RXOVERFLOW; + fifo->rx_overflow = false; + } + /* Check for internal errors */ if (dev->cd_error != 0) @@ -623,12 +639,7 @@ static ssize_t can_read(FAR struct file *filep, FAR char *buffer, } #endif /* CONFIG_CAN_ERRORS */ - DEBUGASSERT(filep->f_priv != NULL); - reader = (FAR struct can_reader_s *)filep->f_priv; - - fifo = &reader->fifo; - - if (filep->f_oflags & O_NONBLOCK) + if ((filep->f_oflags & O_NONBLOCK) != 0) { ret = nxsem_trywait(&fifo->rx_sem); } @@ -1248,12 +1259,13 @@ int can_register(FAR const char *path, FAR struct can_dev_s *dev) /* Initialize the CAN device structure */ - list_initialize(&dev->cd_readers); - dev->cd_ntxwaiters = 0; + dev->cd_crefs = 0; dev->cd_npendrtr = 0; + dev->cd_ntxwaiters = 0; #ifdef CONFIG_CAN_ERRORS dev->cd_error = 0; #endif + list_initialize(&dev->cd_readers); /* Initialize semaphores */ @@ -1446,7 +1458,7 @@ int can_receive(FAR struct can_dev_s *dev, FAR struct can_hdr_s *hdr, { /* Report rx overflow error */ - dev->cd_error |= CAN_ERROR5_RXOVERFLOW; + fifo->rx_overflow = true; } #endif } diff --git a/include/nuttx/can/can.h b/include/nuttx/can/can.h index 0f7db306a54..0b5d28287a7 100644 --- a/include/nuttx/can/can.h +++ b/include/nuttx/can/can.h @@ -498,6 +498,9 @@ struct can_rxfifo_s sem_t rx_sem; +#ifdef CONFIG_CAN_ERRORS + bool rx_overflow; /* Indicates the RX FIFO overflow event */ +#endif uint8_t rx_head; /* Index to the head [IN] in the circular buffer */ uint8_t rx_tail; /* Index to the tail [OUT] in the circular buffer */ /* Circular buffer of CAN messages */ @@ -606,12 +609,13 @@ struct can_reader_s struct can_dev_s { + uint8_t cd_crefs; /* References counts on number of opens */ uint8_t cd_npendrtr; /* Number of pending RTR messages */ volatile uint8_t cd_ntxwaiters; /* Number of threads waiting to enqueue a message */ - struct list_node cd_readers; /* List of readers */ #ifdef CONFIG_CAN_ERRORS uint8_t cd_error; /* Flags to indicate internal device errors */ #endif + struct list_node cd_readers; /* List of readers */ sem_t cd_closesem; /* Locks out new opens while close is in progress */ sem_t cd_pollsem; /* Manages exclusive access to cd_fds[] */ struct can_txfifo_s cd_xmit; /* Describes transmit FIFO */ From 74f1170352d1566ff6875c0d5eba6f361aa99df9 Mon Sep 17 00:00:00 2001 From: JacobCrabill Date: Wed, 25 May 2022 15:06:04 -0700 Subject: [PATCH 40/43] Revert "[BACKPORT] net/can: remove psock reference from can connect" This reverts commit 9ce3fab0ecffade260a886473097b3fc3b1100ea. PR reference: https://github.com/apache/incubator-nuttx/pull/5467 In order for this commit to be valid, the following other PRs must also be back-ported first: - https://github.com/apache/incubator-nuttx/pull/5434 Additional PRs that fix related bugs: - https://github.com/apache/incubator-nuttx/pull/5462 - https://github.com/apache/incubator-nuttx/pull/5466 --- net/can/can.h | 4 ++++ net/can/can_sockif.c | 6 ++++++ 2 files changed, 10 insertions(+) diff --git a/net/can/can.h b/net/can/can.h index ea67fe1c948..b2b51b778de 100644 --- a/net/can/can.h +++ b/net/can/can.h @@ -117,6 +117,10 @@ struct can_conn_s int32_t tx_deadline; # endif #endif + +#ifdef CONFIG_NET_TIMESTAMP + FAR struct socket *psock; /* Needed to get SO_TIMESTAMP value */ +#endif }; /**************************************************************************** diff --git a/net/can/can_sockif.c b/net/can/can_sockif.c index 780641f9727..60b38bba11e 100644 --- a/net/can/can_sockif.c +++ b/net/can/can_sockif.c @@ -221,6 +221,12 @@ static int can_setup(FAR struct socket *psock, int protocol) return -ENOMEM; } +#ifdef CONFIG_NET_TIMESTAMP + /* Store psock in conn se we can read the SO_TIMESTAMP value */ + + conn->psock = psock; +#endif + /* Initialize the connection instance */ conn->protocol = (uint8_t)protocol; From 98a3962b6ed218ae3656a8b08a37337521b9fed7 Mon Sep 17 00:00:00 2001 From: JacobCrabill Date: Thu, 28 Jul 2022 14:06:23 -0700 Subject: [PATCH 41/43] stm32: Add definition of 'arm_netinitialize()' for SocketCAN --- arch/arm/src/stm32/stm32.h | 1 + arch/arm/src/stm32/stm32_can_sock.c | 24 +++++++ arch/arm/src/stm32/stm32_can_sock.h | 105 ++++++++++++++++++++++++++++ 3 files changed, 130 insertions(+) create mode 100644 arch/arm/src/stm32/stm32_can_sock.h diff --git a/arch/arm/src/stm32/stm32.h b/arch/arm/src/stm32/stm32.h index 313422a7175..47cd0a6e6e2 100644 --- a/arch/arm/src/stm32/stm32.h +++ b/arch/arm/src/stm32/stm32.h @@ -37,6 +37,7 @@ #include "chip.h" #include "stm32_adc.h" #include "stm32_can.h" +#include "stm32_can_sock.h" #include "stm32_comp.h" #include "stm32_dbgmcu.h" #include "stm32_dma.h" diff --git a/arch/arm/src/stm32/stm32_can_sock.c b/arch/arm/src/stm32/stm32_can_sock.c index 8b35726215a..a6ad6fd73bf 100644 --- a/arch/arm/src/stm32/stm32_can_sock.c +++ b/arch/arm/src/stm32/stm32_can_sock.c @@ -2463,3 +2463,27 @@ int stm32_cansockinitialize(int port) errout: return ret; } + +/**************************************************************************** + * Name: arm_netinitialize + * + * Description: + * Initialize the CAN device interfaces. If there is more than one device + * interface in the chip, then board-specific logic will have to provide + * this function to determine which, if any, CAN interfaces should be + * initialized. + * + ****************************************************************************/ + +#if !defined(CONFIG_NETDEV_LATEINIT) +void arm_netinitialize(void) +{ +#ifdef CONFIG_STM32_CAN1 + stm32_cansockinitialize(0); +#endif + +#ifdef CONFIG_STM32_CAN2 + stm32_cansockinitialize(1); +#endif +} +#endif diff --git a/arch/arm/src/stm32/stm32_can_sock.h b/arch/arm/src/stm32/stm32_can_sock.h new file mode 100644 index 00000000000..2c6d829da9d --- /dev/null +++ b/arch/arm/src/stm32/stm32_can_sock.h @@ -0,0 +1,105 @@ +/**************************************************************************** + * arch/arm/src/stm32h7/stm32_can_sock.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_ARM_SRC_STM32_STM32_CAN_SOCK_H +#define __ARCH_ARM_SRC_STM32_STM32_CAN_SOCK_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#ifdef CONFIG_STM32_FDCAN + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +#ifndef CONFIG_NETDEV_LATEINIT + +/**************************************************************************** + * Function: arm_netinitialize + * + * Description: + * Initialize the first network interface. If there is more than one + * interface in the chip, then board-specific logic will have to provide + * this function to determine which, if any, CAN interfaces should be + * initialized. Also prototyped in up_internal.h. + * + * Input Parameters: + * None + * + * Returned Value: + * OK on success; Negated errno on failure. + * + * Assumptions: + * Called very early in the initialization sequence. + * + ****************************************************************************/ + +void arm_netinitialize(void); + +#else + +/**************************************************************************** + * Function: stm32_cansockinitialize + * + * Description: + * Initialize the CAN controller and driver + * + * Input Parameters: + * intf - In the case where there are multiple CAN interfaces, this value + * identifies which CAN interface is to be initialized. + * + * Returned Value: + * OK on success; Negated errno on failure. + * + * Assumptions: + * + ****************************************************************************/ + +int stm32_cansockinitialize(int intf); + +#endif + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +#endif /* __ASSEMBLY__ */ +#endif /* CONFIG_STM32_CAN */ +#endif /* __ARCH_ARM_SRC_STM32_STM32_CAN_SOCK_H */ From 67ad6ab0770f53efb4a2db55cfaeb74a1505ed71 Mon Sep 17 00:00:00 2001 From: JacobCrabill Date: Thu, 28 Jul 2022 16:33:03 -0700 Subject: [PATCH 42/43] stm32: Fix unused variable in can_netdev_ioctl --- arch/arm/src/stm32/stm32_can_sock.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/arm/src/stm32/stm32_can_sock.c b/arch/arm/src/stm32/stm32_can_sock.c index a6ad6fd73bf..092bace5ba7 100644 --- a/arch/arm/src/stm32/stm32_can_sock.c +++ b/arch/arm/src/stm32/stm32_can_sock.c @@ -1152,7 +1152,8 @@ static int stm32can_txavail(struct net_driver_s *dev) static int stm32can_netdev_ioctl(struct net_driver_s *dev, int cmd, unsigned long arg) { - FAR struct stm32_can_s *priv = (FAR struct stm32_can_s *)dev->d_private; + /* FAR struct stm32_can_s *priv = (FAR struct stm32_can_s *)dev->d_private; */ + int ret = OK; switch (cmd) From 601722dc4b436d04f641be782f23aea34a1aeb5a Mon Sep 17 00:00:00 2001 From: Jari van Ewijk Date: Fri, 22 Jul 2022 10:23:20 +0200 Subject: [PATCH 43/43] SocketCAN: add non-blocking write Co-authored-by: Peter van der Perk --- net/can/can.h | 26 ++++++++++++++++++++++ net/can/can_input.c | 52 ++++++++++++++++++++----------------------- net/can/can_sendmsg.c | 48 +++++++++++++++++++++++++++++++++++++-- net/can/can_sockif.c | 10 +++------ 4 files changed, 99 insertions(+), 37 deletions(-) diff --git a/net/can/can.h b/net/can/can.h index b2b51b778de..f0602954dfb 100644 --- a/net/can/can.h +++ b/net/can/can.h @@ -277,6 +277,32 @@ ssize_t can_recvmsg(FAR struct socket *psock, FAR struct msghdr *msg, void can_poll(FAR struct net_driver_s *dev, FAR struct can_conn_s *conn); +/**************************************************************************** + * Name: psock_can_cansend + * + * Description: + * psock_can_cansend() returns a value indicating if a write to the socket + * would block. It is still possible that the write may block if another + * write occurs first. + * + * Input Parameters: + * psock An instance of the internal socket structure. + * + * Returned Value: + * OK + * At least one byte of data could be successfully written. + * -EWOULDBLOCK + * There is no room in the output buffer. + * -EBADF + * An invalid descriptor was specified. + * + * Assumptions: + * None + * + ****************************************************************************/ + +int psock_can_cansend(FAR struct socket *psock); + /**************************************************************************** * Name: can_sendmsg * diff --git a/net/can/can_input.c b/net/can/can_input.c index 024bb9aad52..7a073d566d7 100644 --- a/net/can/can_input.c +++ b/net/can/can_input.c @@ -155,48 +155,44 @@ int can_input(struct net_driver_s *dev) { FAR struct can_conn_s *conn = NULL; int ret = OK; + uint16_t buflen = dev->d_len; do { - /* FIXME Support for multiple sockets??? */ - conn = can_nextconn(conn); - } - while (conn && conn->dev != 0 && dev != conn->dev); - - if (conn) - { - uint16_t flags; - /* Setup for the application callback */ + if (conn && (conn->dev == 0x0 || dev == conn->dev)) + { + uint16_t flags; - dev->d_appdata = dev->d_buf; - dev->d_sndlen = 0; + /* Setup for the application callback */ - /* Perform the application callback */ + dev->d_appdata = dev->d_buf; + dev->d_sndlen = 0; + dev->d_len = buflen; - flags = can_callback(dev, conn, CAN_NEWDATA); + /* Perform the application callback */ - /* If the operation was successful, the CAN_NEWDATA flag is removed - * and thus the packet can be deleted (OK will be returned). - */ + flags = can_callback(dev, conn, CAN_NEWDATA); - if ((flags & CAN_NEWDATA) != 0) - { - /* No.. the packet was not processed now. Return -EAGAIN so - * that the driver may retry again later. We still need to - * set d_len to zero so that the driver is aware that there - * is nothing to be sent. + /* If the operation was successful, the CAN_NEWDATA flag is removed + * and thus the packet can be deleted (OK will be returned). */ - nwarn("WARNING: Packet not processed\n"); - ret = -EAGAIN; + if ((flags & CAN_NEWDATA) != 0) + { + /* No.. the packet was not processed now. Return -EAGAIN so + * that the driver may retry again later. We still need to + * set d_len to zero so that the driver is aware that there + * is nothing to be sent. + */ + + nwarn("WARNING: Packet not processed\n"); + ret = -EAGAIN; + } } } - else - { - ninfo("No CAN listener\n"); - } + while (conn); return ret; } diff --git a/net/can/can_sendmsg.c b/net/can/can_sendmsg.c index a7912d99d1d..3ccea61826c 100644 --- a/net/can/can_sendmsg.c +++ b/net/can/can_sendmsg.c @@ -259,10 +259,17 @@ ssize_t can_sendmsg(FAR struct socket *psock, FAR struct msghdr *msg, netdev_txnotify_dev(dev); /* Wait for the send to complete or an error to occur. - * net_lockedwait will also terminate if a signal is received. + * net_timedwait will also terminate if a signal is received. */ - ret = net_lockedwait(&state.snd_sem); + if (_SS_ISNONBLOCK(conn->sconn.s_flags) || (flags & MSG_DONTWAIT) != 0) + { + ret = net_timedwait(&state.snd_sem, 0); + } + else + { + ret = net_timedwait(&state.snd_sem, UINT_MAX); + } /* Make sure that no further events are processed */ @@ -296,4 +303,41 @@ ssize_t can_sendmsg(FAR struct socket *psock, FAR struct msghdr *msg, return state.snd_sent; } +/**************************************************************************** + * Name: psock_can_cansend + * + * Description: + * psock_can_cansend() returns a value indicating if a write to the socket + * would block. No space in the buffer is actually reserved, so it is + * possible that the write may still block if the buffer is filled by + * another means. + * + * Input Parameters: + * psock An instance of the internal socket structure. + * + * Returned Value: + * OK + * At least one byte of data could be successfully written. + * -EWOULDBLOCK + * There is no room in the output buffer. + * -EBADF + * An invalid descriptor was specified. + * + ****************************************************************************/ + +int psock_can_cansend(FAR struct socket *psock) +{ + /* Verify that we received a valid socket */ + + if (psock == NULL || psock->s_conn == NULL) + { + nerr("ERROR: Invalid socket\n"); + return -EBADF; + } + + /* TODO Query CAN driver mailboxes to see if there's mailbox available */ + + return OK; +} + #endif /* CONFIG_NET && CONFIG_NET_CAN */ diff --git a/net/can/can_sockif.c b/net/can/can_sockif.c index 60b38bba11e..e728e9dc1fd 100644 --- a/net/can/can_sockif.c +++ b/net/can/can_sockif.c @@ -139,15 +139,13 @@ static uint16_t can_poll_eventhandler(FAR struct net_driver_s *dev, eventset |= (POLLHUP | POLLERR); } -#if 0 /* A poll is a sign that we are free to send data. */ else if ((flags & CAN_POLL) != 0 && - psock_udp_cansend(info->psock) >= 0) + psock_can_cansend(info->psock) >= 0) { eventset |= (POLLOUT & info->fds->events); } -#endif /* Awaken the caller of poll() is requested event occurred. */ @@ -614,14 +612,12 @@ static int can_poll_local(FAR struct socket *psock, FAR struct pollfd *fds, fds->revents |= (POLLRDNORM & fds->events); } - #if 0 - if (psock_udp_cansend(psock) >= 0) + if (psock_can_cansend(psock) >= 0) { - /* Normal data may be sent without blocking (at least one byte). */ + /* A CAN frame may be sent without blocking. */ fds->revents |= (POLLWRNORM & fds->events); } - #endif /* Check if any requested events are already in effect */