STM32H7: Implement basic FDCAN support
Add stm32h7 support for FDCAN peripheral. Source level compatibility is provided with stm32g4. Additional features of stm32h7 such as configurable buffers are supported. Implementation offers feature parity with stm32g4 implementation.
This commit is contained in:
committed by
Karl Palsson
parent
0d72e6739c
commit
32354846bd
@@ -1,17 +1,7 @@
|
||||
/** @defgroup fdcan_defines FDCAN Defines
|
||||
|
||||
@ingroup STM32G_defines
|
||||
|
||||
@brief <b>libopencm3 Defined Constants and Types for STM32 FD-CAN</b>
|
||||
|
||||
@author @htmlonly © @endhtmlonly 2021 Eduard Drusa <ventyl8 at netkosice dot sk>
|
||||
|
||||
LGPL License Terms @ref lgpl_license
|
||||
*/
|
||||
/*
|
||||
* This file is part of the libopencm3 project.
|
||||
*
|
||||
* Copyright (C) 2021 Eduard Drusa <ventyl86@netkosice.sk>
|
||||
* Copyright (C) 2021 Eduard Drusa <ventyl86 at netkosice dot sk>
|
||||
*
|
||||
* This library is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
@@ -27,26 +17,20 @@ LGPL License Terms @ref lgpl_license
|
||||
* along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#ifndef LIBOPENCM3_FDCAN_H
|
||||
#define LIBOPENCM3_FDCAN_H
|
||||
#pragma once
|
||||
|
||||
#include <libopencm3/stm32/memorymap.h>
|
||||
#include <libopencm3/cm3/common.h>
|
||||
|
||||
/** @{ */
|
||||
#if defined(STM32G4)
|
||||
# include <libopencm3/stm32/g4/fdcan.h>
|
||||
#elif defined(STM32H7)
|
||||
# include <libopencm3/stm32/h7/fdcan.h>
|
||||
#endif
|
||||
|
||||
/* FDCAN block base addresses. Used in functions to identify FDCAN block being manipulated. */
|
||||
|
||||
/** @defgroup fdcan_block FDCAN block base addresses
|
||||
/** @addtogroup fdcan_defines
|
||||
* @{
|
||||
*/
|
||||
#define CAN1 FDCAN1_BASE
|
||||
#define CAN2 FDCAN2_BASE
|
||||
#define CAN3 FDCAN3_BASE
|
||||
/**@}*/
|
||||
|
||||
|
||||
/** @defgroup fdcan_fifo Named constants for FIFOs
|
||||
* @{
|
||||
@@ -55,6 +39,7 @@ LGPL License Terms @ref lgpl_license
|
||||
#define FDCAN_FIFO1 1
|
||||
/**@}*/
|
||||
|
||||
#define FDCAN_BLOCK_ID(can_base) (((can_base) - CAN1)/(CAN2 - CAN1))
|
||||
|
||||
/** @defgroup FDCAN registers file in each FDCAN block. */
|
||||
|
||||
@@ -76,38 +61,29 @@ LGPL License Terms @ref lgpl_license
|
||||
#define FDCAN_IE(can_base) MMIO32(can_base + 0x0054)
|
||||
#define FDCAN_ILS(can_base) MMIO32(can_base + 0x0058)
|
||||
#define FDCAN_ILE(can_base) MMIO32(can_base + 0x005C)
|
||||
#define FDCAN_RXGFC(can_base) MMIO32(can_base + 0x0080)
|
||||
#define FDCAN_XIDAM(can_base) MMIO32(can_base + 0x0084)
|
||||
#define FDCAN_HPMS(can_base) MMIO32(can_base + 0x0088)
|
||||
|
||||
|
||||
/** Generic access to Rx FIFO status registers.
|
||||
* @param can_base FDCAN block base address @ref fdcan_block
|
||||
* @param fifo_id ID of FIFO, 0 or 1
|
||||
*/
|
||||
#define FDCAN_RXFIS(can_base, fifo_id) MMIO32(can_base + 0x0090 + (8 * fifo_id))
|
||||
#define FDCAN_RXFIS(can_base, fifo_id) \
|
||||
MMIO32(can_base + FDCAN_RXFIS_BASE + (FDCAN_RXFI_OFFSET * fifo_id))
|
||||
|
||||
#define FDCAN_RXF0S(can_base) FDCAN_RXFIS(can_base, 0)
|
||||
#define FDCAN_RXF1S(can_base) FDCAN_RXFIS(can_base, 1)
|
||||
|
||||
|
||||
/** Generic access to Rx FIFO acknowledge registers.
|
||||
* @param can_base FDCAN block base address @ref fdcan_block
|
||||
* @param fifo_id ID of FIFO, 0 or 1
|
||||
*/
|
||||
#define FDCAN_RXFIA(can_base, fifo_id) MMIO32(can_base + 0x0094 + (8 * fifo_id))
|
||||
#define FDCAN_RXFIA(can_base, fifo_id) MMIO32(can_base + 0x0094 + (FDCAN_RXFI_OFFSET * fifo_id))
|
||||
#define FDCAN_RXF0A(can_base) FDCAN_RXFIA(can_base, 0)
|
||||
#define FDCAN_RXF1A(can_base) FDCAN_RXFIA(can_base, 1)
|
||||
|
||||
#define FDCAN_TXBC(can_base) MMIO32(can_base + 0x00C0)
|
||||
#define FDCAN_TXFQS(can_base) MMIO32(can_base + 0x00C4)
|
||||
#define FDCAN_TXBRP(can_base) MMIO32(can_base + 0x00C8)
|
||||
#define FDCAN_TXBAR(can_base) MMIO32(can_base + 0x00CC)
|
||||
#define FDCAN_TXBCR(can_base) MMIO32(can_base + 0x00D0)
|
||||
#define FDCAN_TXBTO(can_base) MMIO32(can_base + 0x00D4)
|
||||
#define FDCAN_TXBCF(can_base) MMIO32(can_base + 0x00D8)
|
||||
#define FDCAN_TXBTIE(can_base) MMIO32(can_base + 0x00DC)
|
||||
#define FDCAN_TXBCIE(can_base) MMIO32(can_base + 0x00E0)
|
||||
#define FDCAN_TXEFS(can_base) MMIO32(can_base + 0x00E4)
|
||||
#define FDCAN_TXEFA(can_base) MMIO32(can_base + 0x00E8)
|
||||
#define FDCAN_CKDIV(can_base) MMIO32(can_base + 0x0100)
|
||||
|
||||
/* DAY[7:0]: FDCAN core revision date */
|
||||
#define FDCAN_CREL_DAY_SHIFT 0
|
||||
@@ -360,26 +336,6 @@ LGPL License Terms @ref lgpl_license
|
||||
#define FDCAN_ILE_INT0 (1 << 0)
|
||||
#define FDCAN_ILE_INT1 (1 << 1)
|
||||
|
||||
#define FDCAN_RXGFC_RRFE (1 << 0)
|
||||
#define FDCAN_RXGFC_RRFS (1 << 1)
|
||||
/* ANFE[1:0]: Accept non-matching frames w/ extended ID */
|
||||
#define FDCAN_RXGFC_ANFE_SHIFT 2
|
||||
#define FDCAN_RXGFC_ANFE_MASK 0x3
|
||||
|
||||
/* ANFS[1:0]: Accept non-matching frames w/ standard ID */
|
||||
#define FDCAN_RXGFC_ANFS_SHIFT 4
|
||||
#define FDCAN_RXGFC_ANFS_MASK 0x3
|
||||
|
||||
#define FDCAN_RXGFC_F1OM (1 << 8)
|
||||
#define FDCAN_RXGFC_F0OM (1 << 9)
|
||||
/* LSS[4:0]: List size of standard ID filters */
|
||||
#define FDCAN_RXGFC_LSS_SHIFT 16
|
||||
#define FDCAN_RXGFC_LSS_MASK 0x1F
|
||||
|
||||
/* LSE[3:0]: List size of extended ID filters */
|
||||
#define FDCAN_RXGFC_LSE_SHIFT 24
|
||||
#define FDCAN_RXGFC_LSE_MASK 0xF
|
||||
|
||||
|
||||
/* EIDM[28:0]: Extended ID mask for filtering */
|
||||
#define FDCAN_XIDAM_EIDM_SHIFT 0
|
||||
@@ -402,15 +358,12 @@ LGPL License Terms @ref lgpl_license
|
||||
|
||||
/* Fill level of Rx FIFOs */
|
||||
#define FDCAN_RXFIFO_FL_SHIFT 0
|
||||
#define FDCAN_RXFIFO_FL_MASK 0xF
|
||||
|
||||
/* Get index of Rx FIFOs */
|
||||
#define FDCAN_RXFIFO_GI_SHIFT 8
|
||||
#define FDCAN_RXFIFO_GI_MASK 0x3
|
||||
|
||||
/* Put index of Rx FIFOs */
|
||||
#define FDCAN_RXFIFO_PI_SHIFT 16
|
||||
#define FDCAN_RXFIFO_PI_MASK 0x3
|
||||
|
||||
#define FDCAN_RXFIFO_FF (1 << 24)
|
||||
#define FDCAN_RXFIFO_RFL (1 << 25)
|
||||
@@ -432,7 +385,6 @@ LGPL License Terms @ref lgpl_license
|
||||
|
||||
/* Rx FIFOs acknowledge index */
|
||||
#define FDCAN_RXFIFO_AI_SHIFT 0
|
||||
#define FDCAN_RXFIFO_AI_MASK 0x7
|
||||
|
||||
/* R0AI[2:0]: Rx FIFO 0 acknowledge index */
|
||||
#define FDCAN_RXF0A_R0AI_SHIFT FDCAN_RXFIFO_AI_SHIFT
|
||||
@@ -461,17 +413,14 @@ LGPL License Terms @ref lgpl_license
|
||||
|
||||
/* TFFL[2:0]: Tx FIFO free level */
|
||||
#define FDCAN_TXFQS_TFFL_SHIFT 0
|
||||
#define FDCAN_TXFQS_TFFL_MASK 0x7
|
||||
|
||||
/* TFGI[1:0]: Tx FIFO get index */
|
||||
#define FDCAN_TXFQS_TFGI_SHIFT 0
|
||||
#define FDCAN_TXFQS_TFGI_MASK 0x3
|
||||
#define FDCAN_TXFQS_TFGI_SHIFT 8
|
||||
|
||||
/* TFQPI[1:0]: Tx FIFO put index */
|
||||
#define FDCAN_TXFQS_TFQPI_SHIFT 0
|
||||
#define FDCAN_TXFQS_TFQPI_MASK 0x3
|
||||
#define FDCAN_TXFQS_TFQPI_SHIFT 16
|
||||
|
||||
#define FDCAN_TXFQS_TFQF (1 << 0)
|
||||
#define FDCAN_TXFQS_TFQF (1 << 21)
|
||||
|
||||
/** @defgroup fdcan_txbrp FDCAN_TXBRP Transmit request pending bits
|
||||
* @{
|
||||
@@ -527,7 +476,7 @@ LGPL License Terms @ref lgpl_license
|
||||
/** @defgroup fdcan_txbcie FDCAN_TXBCIE Transmit cancelled interrupt enable bits
|
||||
*
|
||||
* Each bit enables or disables transmit cancelled interrupt for transmit buffer
|
||||
* slot.
|
||||
* slot.
|
||||
* @{
|
||||
*/
|
||||
#define FDCAN_TXBCIE_CFIE0 (1 << 0)
|
||||
@@ -537,15 +486,12 @@ LGPL License Terms @ref lgpl_license
|
||||
|
||||
/* EFFL[2:0]: Event FIFO fill level*/
|
||||
#define FDCAN_TXEFS_EFFL_SHIFT 0
|
||||
#define FDCAN_TXEFS_EFFL_MASK 0x7
|
||||
|
||||
/* EFG[1:0]: Event FIFO get index */
|
||||
#define FDCAN_TXEFS_EFGI_SHIFT 8
|
||||
#define FDCAN_TXEFS_EFGI_MASK 0x3
|
||||
|
||||
/* EFPI[1:0]: Event FIFO put index */
|
||||
#define FDCAN_TXEFS_EFPI_SHIFT 16
|
||||
#define FDCAN_TXEFS_EFPI_MASK 0x3
|
||||
|
||||
#define FDCAN_TXEFS_EFF (1 << 24)
|
||||
#define FDCAN_TXEFS_TEF (1 << 25)
|
||||
@@ -555,10 +501,6 @@ LGPL License Terms @ref lgpl_license
|
||||
#define FDCAN_TXEFA_EFAI_MASK 0x3
|
||||
|
||||
|
||||
/* PDIV[3:0]: Input clock divider */
|
||||
#define FDCAN_CKDIV_PDIV_SHIFT 0
|
||||
#define FDCAN_CKDIV_PDIV_MASK 0xF
|
||||
|
||||
/* --- FD-CAN memory block defines------------------------------------------ */
|
||||
|
||||
/** Structure describing standard ID filter.
|
||||
@@ -626,12 +568,6 @@ struct fdcan_standard_filter {
|
||||
#define FDCAN_SFEC_PRIO_FIFO1 0x6
|
||||
/**@}*/
|
||||
|
||||
/** Amount of standard filters allocated in Message RAM
|
||||
* This number may vary between devices. 28 is value valid
|
||||
* for STM32G4
|
||||
**/
|
||||
#define FDCAN_SFT_MAX_NR 28
|
||||
|
||||
/* SFEC = 0x7 is unused */
|
||||
|
||||
#define FDCAN_SFID1_SHIFT 16
|
||||
@@ -706,7 +642,7 @@ struct fdcan_extended_filter {
|
||||
* using id2. */
|
||||
#define FDCAN_EFT_ID_MASK 0x2
|
||||
|
||||
/** Similar to @ref FDCAN_EFT_RANGE except of ignoring global mask
|
||||
/** Similar to @ref FDCAN_EFT_RANGE except of ignoring global mask
|
||||
* set using @ref FDCAN_XIDAM register.
|
||||
*/
|
||||
#define FDCAN_EFT_RANGE_NOXIDAM 0x3
|
||||
@@ -715,12 +651,6 @@ struct fdcan_extended_filter {
|
||||
#define FDCAN_EFID2_SHIFT 0
|
||||
#define FDCAN_EFID2_MASK 0x1FFFFFFF
|
||||
|
||||
/** Amount of extended filters allocated in Message RAM
|
||||
* This number may vary between devices. 8 is value valid
|
||||
* for STM32G4
|
||||
**/
|
||||
#define FDCAN_EFT_MAX_NR 8
|
||||
|
||||
/** Structure describing receive FIFO element.
|
||||
* Receive FIFO element consists of 2 32bit values for header
|
||||
* and 16 32bit values for message payload.
|
||||
@@ -792,29 +722,6 @@ struct fdcan_tx_buffer_element {
|
||||
#define FDCAN_FIFO_RXTS_SHIFT 0
|
||||
#define FDCAN_FIFO_RXTS_MASK 0xFFFF
|
||||
|
||||
/** Message RAM layout for one FDCAN block.
|
||||
* There are as many memory blocks as there are FDCAN blocks
|
||||
*/
|
||||
struct fdcan_message_ram {
|
||||
/* List of standard ID filters */
|
||||
struct fdcan_standard_filter lfssa[FDCAN_SFT_MAX_NR];
|
||||
|
||||
/* List of extended ID filters */
|
||||
struct fdcan_extended_filter lfesa[FDCAN_EFT_MAX_NR];
|
||||
|
||||
/* Buffer area for two receive FIFOs each having space for three messages */
|
||||
struct fdcan_rx_fifo_element rx_fifo[2][3];
|
||||
|
||||
/* Buffer area for transmit event buffers */
|
||||
struct fdcan_tx_event_element tx_event[3];
|
||||
|
||||
/* Buffer area for transmitted messages. May act either as FIFO or as queue
|
||||
* depending on configuration
|
||||
*/
|
||||
struct fdcan_tx_buffer_element tx_buffer[3];
|
||||
};
|
||||
|
||||
|
||||
/* --- FD-CAN error returns ------------------------------------------------- */
|
||||
|
||||
/** FDCAN error return values
|
||||
@@ -886,7 +793,18 @@ void fdcan_release_fifo(uint32_t canport, uint8_t fifo);
|
||||
bool fdcan_available_tx(uint32_t canport);
|
||||
bool fdcan_available_rx(uint32_t canport, uint8_t fifo);
|
||||
|
||||
int fdcan_cccr_init_cfg(uint32_t canport, bool set, uint32_t timeout);
|
||||
struct fdcan_standard_filter *fdcan_get_flssa_addr(uint32_t canport);
|
||||
struct fdcan_extended_filter *fdcan_get_flesa_addr(uint32_t canport);
|
||||
|
||||
struct fdcan_rx_fifo_element *fdcan_get_rxfifo_addr(uint32_t canport,
|
||||
unsigned fifo_id, unsigned element_id);
|
||||
|
||||
struct fdcan_tx_event_element *fdcan_get_txevt_addr(uint32_t canport);
|
||||
struct fdcan_tx_buffer_element *fdcan_get_txbuf_addr(uint32_t canport, unsigned element_id);
|
||||
void fdcan_set_fifo_locked_mode(uint32_t canport, bool locked);
|
||||
uint32_t fdcan_length_to_dlc(uint8_t length);
|
||||
uint8_t fdcan_dlc_to_length(uint32_t dlc);
|
||||
|
||||
END_DECLS
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
132
include/libopencm3/stm32/g4/fdcan.h
Normal file
132
include/libopencm3/stm32/g4/fdcan.h
Normal file
@@ -0,0 +1,132 @@
|
||||
/** @defgroup fdcan_defines FDCAN Defines
|
||||
|
||||
@ingroup STM32G4xx_defines
|
||||
|
||||
@author @htmlonly © @endhtmlonly 2021 Eduard Drusa <ventyl86 at netkosice dot sk>
|
||||
|
||||
LGPL License Terms @ref lgpl_license
|
||||
*/
|
||||
/*
|
||||
* This file is part of the libopencm3 project.
|
||||
*
|
||||
* Copyright (C) 2021 Eduard Drusa <ventyl86 at netkosice dot sk>
|
||||
*
|
||||
* This library is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
/** @{ */
|
||||
|
||||
/* FDCAN block base addresses. Used in functions to identify FDCAN block being manipulated. */
|
||||
|
||||
/** @defgroup fdcan_block FDCAN block base addresses
|
||||
* @{
|
||||
*/
|
||||
#define CAN1 FDCAN1_BASE
|
||||
#define CAN2 FDCAN2_BASE
|
||||
#define CAN3 FDCAN3_BASE
|
||||
/**@}*/
|
||||
|
||||
#define CAN_MSG_BASE FDCAN1_RAM_BASE
|
||||
|
||||
#define FDCAN_RXFIS_BASE 0x0090
|
||||
#define FDCAN_RXFIA_BASE 0x0094
|
||||
#define FDCAN_RXFI_OFFSET 0x0008
|
||||
|
||||
#define FDCAN_RXGFC(can_base) MMIO32(can_base + 0x0080)
|
||||
#define FDCAN_XIDAM(can_base) MMIO32(can_base + 0x0084)
|
||||
#define FDCAN_HPMS(can_base) MMIO32(can_base + 0x0088)
|
||||
|
||||
#define FDCAN_TXBRP(can_base) MMIO32(can_base + 0x00C8)
|
||||
#define FDCAN_TXBAR(can_base) MMIO32(can_base + 0x00CC)
|
||||
#define FDCAN_TXBCR(can_base) MMIO32(can_base + 0x00D0)
|
||||
#define FDCAN_TXBTO(can_base) MMIO32(can_base + 0x00D4)
|
||||
#define FDCAN_TXBCF(can_base) MMIO32(can_base + 0x00D8)
|
||||
#define FDCAN_TXBTIE(can_base) MMIO32(can_base + 0x00DC)
|
||||
#define FDCAN_TXBCIE(can_base) MMIO32(can_base + 0x00E0)
|
||||
#define FDCAN_TXEFS(can_base) MMIO32(can_base + 0x00E4)
|
||||
#define FDCAN_TXEFA(can_base) MMIO32(can_base + 0x00E8)
|
||||
|
||||
#define FDCAN_CKDIV(can_base) MMIO32(can_base + 0x0100)
|
||||
|
||||
#define FDCAN_RXGFC_RRFE (1 << 0)
|
||||
#define FDCAN_RXGFC_RRFS (1 << 1)
|
||||
/* ANFE[1:0]: Accept non-matching frames w/ extended ID */
|
||||
#define FDCAN_RXGFC_ANFE_SHIFT 2
|
||||
#define FDCAN_RXGFC_ANFE_MASK 0x3
|
||||
|
||||
/* ANFS[1:0]: Accept non-matching frames w/ standard ID */
|
||||
#define FDCAN_RXGFC_ANFS_SHIFT 4
|
||||
#define FDCAN_RXGFC_ANFS_MASK 0x3
|
||||
|
||||
#define FDCAN_RXGFC_F1OM (1 << 8)
|
||||
#define FDCAN_RXGFC_F0OM (1 << 9)
|
||||
/* LSS[4:0]: List size of standard ID filters */
|
||||
#define FDCAN_RXGFC_LSS_SHIFT 16
|
||||
#define FDCAN_RXGFC_LSS_MASK 0x1F
|
||||
|
||||
/* LSE[3:0]: List size of extended ID filters */
|
||||
#define FDCAN_RXGFC_LSE_SHIFT 24
|
||||
#define FDCAN_RXGFC_LSE_MASK 0xF
|
||||
|
||||
#define FDCAN_RXFIFO_FL_MASK 0xF
|
||||
#define FDCAN_RXFIFO_GI_MASK 0x3
|
||||
#define FDCAN_RXFIFO_PI_MASK 0x3
|
||||
#define FDCAN_RXFIFO_AI_MASK 0x3
|
||||
|
||||
#define FDCAN_TXFQS_TFFL_MASK 0x7
|
||||
#define FDCAN_TXFQS_TFGI_MASK 0x3
|
||||
#define FDCAN_TXFQS_TFQPI_MASK 0x3
|
||||
|
||||
#define FDCAN_TXEFS_EFFL_MASK 0x7
|
||||
#define FDCAN_TXEFS_EFGI_MASK 0x3
|
||||
#define FDCAN_TXEFS_EFPI_MASK 0x3
|
||||
|
||||
/* PDIV[3:0]: Input clock divider */
|
||||
#define FDCAN_CKDIV_PDIV_SHIFT 0
|
||||
#define FDCAN_CKDIV_PDIV_MASK 0xF
|
||||
|
||||
/** Amount of standard filters allocated in Message RAM
|
||||
* This number may vary between devices. 28 is value valid
|
||||
* for STM32G4
|
||||
**/
|
||||
#define FDCAN_SFT_MAX_NR 28
|
||||
|
||||
/** Amount of extended filters allocated in Message RAM
|
||||
* This number may vary between devices. 8 is value valid
|
||||
* for STM32G4
|
||||
**/
|
||||
#define FDCAN_EFT_MAX_NR 8
|
||||
|
||||
#define FDCAN_LFSSA_OFFSET(can_base) ((FDCAN_BLOCK_ID(can_base) * 0x0350) + 0x0000)
|
||||
#define FDCAN_LFESA_OFFSET(can_base) ((FDCAN_BLOCK_ID(can_base) * 0x0350) + 0x0070)
|
||||
|
||||
#define FDCAN_RXFIFOS_OFFSET(can_base) ((FDCAN_BLOCK_ID(can_base) * 0x0350) + 0x00B0)
|
||||
|
||||
#define FDCAN_RXFIFO_OFFSET(can_base, fifo_id) \
|
||||
(FDCAN_RXFIFOS_OFFSET(can_base) + (0x00D8 * (fifo_id)))
|
||||
|
||||
#define FDCAN_TXEVT_OFFSET(can_base) ((FDCAN_BLOCK_ID(can_base) * 0x0350) + 0x0260)
|
||||
|
||||
#define FDCAN_TXBUF_OFFSET(can_base) ((FDCAN_BLOCK_ID(can_base) * 0x0350) + 0x0278)
|
||||
|
||||
BEGIN_DECLS
|
||||
|
||||
unsigned fdcan_get_fifo_element_size(uint32_t canport, unsigned fifo_id);
|
||||
unsigned fdcan_get_txbuf_element_size(uint32_t canport);
|
||||
|
||||
END_DECLS
|
||||
|
||||
|
||||
257
include/libopencm3/stm32/h7/fdcan.h
Normal file
257
include/libopencm3/stm32/h7/fdcan.h
Normal file
@@ -0,0 +1,257 @@
|
||||
/** @defgroup fdcan_defines FDCAN Defines
|
||||
|
||||
@ingroup STM32H7xx_defines
|
||||
|
||||
|
||||
@author @htmlonly © @endhtmlonly 2021 Eduard Drusa <ventyl86 at netkosice dot sk>
|
||||
|
||||
LGPL License Terms @ref lgpl_license
|
||||
*/
|
||||
/*
|
||||
* This file is part of the libopencm3 project.
|
||||
*
|
||||
* Copyright (C) 2021 Eduard Drusa <ventyl86 at netkosice dot sk>
|
||||
*
|
||||
* This library is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
/** @{ */
|
||||
|
||||
/* FDCAN block base addresses. Used in functions to identify FDCAN block being manipulated. */
|
||||
|
||||
/** @defgroup fdcan_block FDCAN block base addresses
|
||||
* @{
|
||||
*/
|
||||
#define CAN1 FDCAN1_BASE
|
||||
#define CAN2 FDCAN2_BASE
|
||||
/**@}*/
|
||||
|
||||
/* Size of FDCAN peripheral message RAM in bytes */
|
||||
#define CAN_MSG_SIZE 0x2800
|
||||
|
||||
#define FDCAN_GFC(can_base) MMIO32(can_base + 0x0080)
|
||||
|
||||
#define FDCAN_SIDFC(can_base) MMIO32(can_base + 0x0084)
|
||||
#define FDCAN_XIDFC(can_base) MMIO32(can_base + 0x0088)
|
||||
#define FDCAN_XIDAM(can_base) MMIO32(can_base + 0x0090)
|
||||
|
||||
#define FDCAN_HPMS(can_base) MMIO32(can_base + 0x0094)
|
||||
#define FDCAN_NDAT1(can_base) MMIO32(can_base + 0x0098)
|
||||
#define FDCAN_HDAT2(can_base) MMIO32(can_base + 0x009C)
|
||||
|
||||
#define FDCAN_RXFIC_BASE 0x00A0
|
||||
#define FDCAN_RXFI_OFFSET 0x0010
|
||||
|
||||
#define FDCAN_RXFIC(can_base, fifo_id) \
|
||||
MMIO32((can_base) + FDCAN_RXFIC_BASE + (FDCAN_RXFI_OFFSET * (fifo_id)))
|
||||
|
||||
#define FDCAN_RXF0C(can_base) FDCAN_RXFIC(can_base, 0)
|
||||
#define FDCAN_RXF1C(can_base) FDCAN_RXFIC(can_base, 1)
|
||||
|
||||
#define FDCAN_RXFIS_BASE 0x00A4
|
||||
#define FDCAN_RXFIA_BASE 0x00A8
|
||||
|
||||
#define FDCAN_RXBC(can_base) MMIO32(can_base + 0x00AC)
|
||||
|
||||
#define FDCAN_RXESC(can_base) MMIO32(can_base + 0x00BC)
|
||||
#define FDCAN_TXESC(can_base) MMIO32(can_base + 0x00C8)
|
||||
#define FDCAN_TXBRP(can_base) MMIO32(can_base + 0x00CC)
|
||||
#define FDCAN_TXBAR(can_base) MMIO32(can_base + 0x00D0)
|
||||
#define FDCAN_TXBCR(can_base) MMIO32(can_base + 0x00D4)
|
||||
#define FDCAN_TXBTO(can_base) MMIO32(can_base + 0x00D8)
|
||||
#define FDCAN_TXBCF(can_base) MMIO32(can_base + 0x00DC)
|
||||
#define FDCAN_TXBTIE(can_base) MMIO32(can_base + 0x00E0)
|
||||
#define FDCAN_TXBCIE(can_base) MMIO32(can_base + 0x00E4)
|
||||
#define FDCAN_TXEFC(can_base) MMIO32(can_base + 0x00F0)
|
||||
#define FDCAN_TXEFS(can_base) MMIO32(can_base + 0x00F4)
|
||||
#define FDCAN_TXEFA(can_base) MMIO32(can_base + 0x00F8)
|
||||
|
||||
#define FDCAN_TTTMC(can_base) MMIO32(can_base + 0x0100)
|
||||
#define FDCAN_TTRMC(can_base) MMIO32(can_base + 0x0104)
|
||||
#define FDCAN_TTOCF(can_base) MMIO32(can_base + 0x0108)
|
||||
#define FDCAN_TTMLM(can_base) MMIO32(can_base + 0x010C)
|
||||
#define FDCAN_TURCF(can_base) MMIO32(can_base + 0x0110)
|
||||
#define FDCAN_TTOCN(can_base) MMIO32(can_base + 0x0114)
|
||||
#define FDCAN_TTGTP(can_base) MMIO32(can_base + 0x0118)
|
||||
#define FDCAN_TTTMK(can_base) MMIO32(can_base + 0x011C)
|
||||
#define FDCAN_TTTIR(can_base) MMIO32(can_base + 0x0120)
|
||||
#define FDCAN_TTIE(can_base) MMIO32(can_base + 0x0124)
|
||||
#define FDCAN_TTILS(can_base) MMIO32(can_base + 0x0128)
|
||||
#define FDCAN_TTOST(can_base) MMIO32(can_base + 0x012C)
|
||||
#define FDCAN_TURNA(can_base) MMIO32(can_base + 0x0130)
|
||||
#define FDCAN_TTLGT(can_base) MMIO32(can_base + 0x0134)
|
||||
#define FDCAN_TTCTC(can_base) MMIO32(can_base + 0x0138)
|
||||
#define FDCAN_TTCPT(can_base) MMIO32(can_base + 0x013C)
|
||||
#define FDCAN_TTCSM(can_base) MMIO32(can_base + 0x0140)
|
||||
#define FDCAN_TTTS(can_base) MMIO32(can_base + 0x0300)
|
||||
|
||||
#define FDCAN_CCU_CCFG MMIO32(CAN_CCU_BASE + 0x0004)
|
||||
#define FDCAN_CCU_CREL MMIO32(CAN_CCU_BASE + 0x0000)
|
||||
|
||||
#define FDCAN_GFC_RRFE (1 << 0)
|
||||
#define FDCAN_GFC_RRFS (1 << 1)
|
||||
|
||||
/* ANFE[1:0]: Accept non-matching frames w/ extended ID */
|
||||
#define FDCAN_GFC_ANFE_SHIFT 2
|
||||
#define FDCAN_GFC_ANFE_MASK 0x3
|
||||
|
||||
/* ANFS[1:0]: Accept non-matching frames w/ standard ID */
|
||||
#define FDCAN_GFC_ANFS_SHIFT 4
|
||||
#define FDCAN_GFC_ANFS_MASK 0x3
|
||||
|
||||
#define FDCAN_FXS_MASK 0xFF
|
||||
#define FDCAN_FXS_SHIFT 16
|
||||
|
||||
/* Position of start address of relocatable object within register */
|
||||
#define FDCAN_FXSA_MASK 0x3FFF
|
||||
#define FDCAN_FXSA_SHIFT 2
|
||||
|
||||
/* LSS[7:0]: List size of standard ID filters */
|
||||
#define FDCAN_SIDFC_LSS_MASK FDCAN_FXS_MASK
|
||||
#define FDCAN_SIDFC_LSS_SHIFT FDCAN_FXS_SHIFT
|
||||
|
||||
/* LFSSA[13:0]: Filter List standard start address */
|
||||
#define FDCAN_SIDFC_FLSSA_MASK FDCAN_FXSA_MASK
|
||||
#define FDCAN_SIDFC_FLSSA_SHIFT FDCAN_FXSA_SHIFT
|
||||
|
||||
/* LSE[7:0]: List size of extended ID filters */
|
||||
#define FDCAN_XIDFC_LSE_MASK FDCAN_FXS_MASK
|
||||
#define FDCAN_XIDFC_LSE_SHIFT FDCAN_FXS_SHIFT
|
||||
|
||||
/* LFSSA[7:0]: Filter List extended start address */
|
||||
#define FDCAN_XIDFC_FLESA_MASK FDCAN_FXSA_MASK
|
||||
#define FDCAN_XIDFC_FLESA_SHIFT FDCAN_FXSA_SHIFT
|
||||
|
||||
/* TFQS[5:0]: Tx FIFO/Queue size */
|
||||
#define FDCAN_TXBC_TFQS_MASK 0x3F
|
||||
#define FDCAN_TXBC_TFQS_SHIFT 24
|
||||
|
||||
/* TBSA[7:0]: Transmit buffer start address */
|
||||
#define FDCAN_TXBC_TBSA_MASK FDCAN_FXSA_MASK
|
||||
#define FDCAN_TXBC_TBSA_SHIFT FDCAN_FXSA_SHIFT
|
||||
|
||||
#define FDCAN_TXEFC_EFS_MASK 0x3F
|
||||
#define FDCAN_TXEFC_EFS_SHIFT 16
|
||||
|
||||
/* EFSA[7:0]: (Transmit) event FIFO start address */
|
||||
#define FDCAN_TXEFC_EFSA_MASK FDCAN_FXSA_MASK
|
||||
#define FDCAN_TXEFC_EFSA_SHIFT FDCAN_FXSA_SHIFT
|
||||
|
||||
#define FDCAN_RXFIC_FIOM (1 << 31)
|
||||
|
||||
#define FDCAN_RXFIC_FIWM_MASK 0x7F
|
||||
#define FDCAN_RXFIC_FIWM_SHIFT 24
|
||||
|
||||
#define FDCAN_RXFIC_FIS_MASK 0x7F
|
||||
#define FDCAN_RXFIC_FIS_SHIFT 16
|
||||
|
||||
|
||||
#define FDCAN_RXFIC_FISA_MASK FDCAN_FXSA_MASK
|
||||
#define FDCAN_RXFIC_FISA_SHIFT FDCAN_FXSA_SHIFT
|
||||
|
||||
#define FDCAN_RXF0C_F0OM FDCAN_RXFIC_FIOM
|
||||
|
||||
/* F0WM[6:0]: FIFO0 watermark mode */
|
||||
#define FDCAN_RXF0C_F0WM_MASK FDCAN_RXFIC_FIWM_MASK
|
||||
#define FDCAN_RXF0C_F0WM_SHIFT FDCAN_RXFIC_FIWM_SHIFT
|
||||
|
||||
/* F0S[6:0]: FIFO0 size */
|
||||
#define FDCAN_RXF0C_F0S_MASK FDCAN_RXFIC_FIS_MASK
|
||||
#define FDCAN_RXF0C_F0S_SHIFT FDCAN_RXFIC_FIS_SHIFT
|
||||
|
||||
/* F0SA[13:0]: FIFO0 start address */
|
||||
#define FDCAN_RXF0C_F0SA_MASK FDCAN_RXFIC_FISA_MASK
|
||||
#define FDCAN_RXF0C_F0SA_SHIFT FDCAN_RXFIC_FISA_SHIFT
|
||||
|
||||
#define FDCAN_RXF1C_F1OM FDCAN_RXFIC_FIOM
|
||||
|
||||
/* F1WM[6:0]: FIFO1 watermark mode */
|
||||
#define FDCAN_RXF1C_F1WM_MASK FDCAN_RXFIC_FIWM_MASK
|
||||
#define FDCAN_RXF1C_F1WM_SHIFT FDCAN_RXFIC_FIWM_SHIFT
|
||||
|
||||
/* F1S[6:0]: FIFO1 size */
|
||||
#define FDCAN_RXF1C_F1S_MASK FDCAN_RXFIC_FIS_MASK
|
||||
#define FDCAN_RXF1C_F1S_SHIFT FDCAN_RXFIC_FIS_SHIFT
|
||||
|
||||
/* F1SA[13:0]: FIFO1 start address */
|
||||
#define FDCAN_RXF1C_F1SA_MASK FDCAN_RXFIC_FISA_MASK
|
||||
#define FDCAN_RXF1C_F1SA_SHIFT FDCAN_RXFIC_FISA_SHIFT
|
||||
|
||||
/* RBDS[3:0]: RX buffer data field size */
|
||||
#define FDCAN_RXESC_RBDS_MASK 0x7
|
||||
#define FDCAN_RXESC_RBDS_SHIFT 8
|
||||
|
||||
/* F0DS[3:0]: FIFO0 data field size */
|
||||
#define FDCAN_RXESC_F0DS_MASK 0x7
|
||||
#define FDCAN_RXESC_F0DS_SHIFT 0
|
||||
|
||||
/* F1DS[3:0]: FIFO1 data field size */
|
||||
#define FDCAN_RXESC_F1DS_MASK 0x7
|
||||
#define FDCAN_RXESC_F1DS_SHIFT 4
|
||||
|
||||
/* TBDS[3:0]: TX buffer data field size */
|
||||
#define FDCAN_TXESC_TBDS_MASK 0x7
|
||||
#define FDCAN_TXESC_TBDS_SHIFT 0
|
||||
|
||||
#define FDCAN_RXFIFO_FL_MASK 0x7F
|
||||
#define FDCAN_RXFIFO_GI_MASK 0x3F
|
||||
#define FDCAN_RXFIFO_PI_MASK 0x3F
|
||||
|
||||
#define FDCAN_RXFIFO_AI_MASK 0x3F
|
||||
|
||||
#define FDCAN_TXFQS_TFFL_MASK 0x3F
|
||||
#define FDCAN_TXFQS_TFGI_MASK 0x1F
|
||||
#define FDCAN_TXFQS_TFQPI_MASK 0x1F
|
||||
|
||||
#define FDCAN_TXEFS_EFFL_MASK 0x3F
|
||||
#define FDCAN_TXEFS_EFGI_MASK 0x1F
|
||||
#define FDCAN_TXEFS_EFPI_MASK 0x1F
|
||||
|
||||
/* PDIV[3:0]: Input clock divider */
|
||||
#define FDCAN_CCU_CCFG_CDIV_SHIFT 16
|
||||
#define FDCAN_CCU_CCFG_CDIV_MASK 0xF
|
||||
|
||||
|
||||
|
||||
#define FDCAN_LFSSA_OFFSET(can_base) \
|
||||
(FDCAN_SIDFC(can_base) & (FDCAN_SIDFC_FLSSA_MASK << FDCAN_SIDFC_FLSSA_SHIFT))
|
||||
|
||||
#define FDCAN_LFESA_OFFSET(can_base) \
|
||||
(FDCAN_XIDFC(can_base) & (FDCAN_XIDFC_FLESA_MASK << FDCAN_XIDFC_FLESA_SHIFT))
|
||||
|
||||
#define FDCAN_RXFIFO_OFFSET(can_base, fifo_id) \
|
||||
(FDCAN_RXFIC(can_base, fifo_id) & (FDCAN_FXSA_MASK << FDCAN_FXSA_SHIFT))
|
||||
|
||||
#define FDCAN_TXBUF_OFFSET(can_base) \
|
||||
(FDCAN_TXBC(can_base) & (FDCAN_TXBC_TBSA_MASK << FDCAN_TXBC_TBSA_SHIFT))
|
||||
|
||||
#define FDCAN_TXEVT_OFFSET(can_base) \
|
||||
(FDCAN_TXEFC(can_base) & (FDCAN_TXEFC_EFSA_MASK << FDCAN_TXEFC_EFSA_SHIFT))
|
||||
|
||||
BEGIN_DECLS
|
||||
|
||||
void fdcan_init_std_filter_ram(uint32_t canport, uint32_t flssa, uint8_t lss);
|
||||
void fdcan_init_ext_filter_ram(uint32_t canport, uint32_t flesa, uint8_t lse);
|
||||
void fdcan_init_fifo_ram(uint32_t canport, unsigned fifo_id, uint32_t fxsa, uint8_t fxs);
|
||||
void fdcan_init_tx_event_ram(uint32_t canport, uint32_t tesa, uint8_t tes);
|
||||
void fdcan_init_tx_buffer_ram(uint32_t canport, uint32_t tbsa, uint8_t tbs);
|
||||
unsigned fdcan_get_fifo_element_size(uint32_t canport, unsigned fifo_id);
|
||||
unsigned fdcan_get_txbuf_element_size(uint32_t canport);
|
||||
int fdcan_set_rx_element_size(uint32_t canport, uint8_t rxbuf, uint8_t rxfifo0, uint8_t rxfifo1);
|
||||
int fdcan_set_tx_element_size(uint32_t canport, uint8_t txbuf);
|
||||
|
||||
END_DECLS
|
||||
|
||||
@@ -1,22 +1,3 @@
|
||||
/** @defgroup fdcan_file FDCAN peripheral API
|
||||
*
|
||||
* @ingroup peripheral_apis
|
||||
*
|
||||
* @brief <b>libopencm3 STM32 FDCAN</b>
|
||||
*
|
||||
* @version 1.0.0
|
||||
*
|
||||
* @author @htmlonly © @endhtmlonly 2021 Eduard Drusa <ventyl86 at netkosice dot sk>
|
||||
*
|
||||
* Devices can have up to three FDCAN peripherals residing in one FDCAN block. The peripherals
|
||||
* support both CAN 2.0 A and B standard and Bosch FDCAN standard. FDCAN frame format and
|
||||
* bitrate switching is supported. The peripheral has several filters for incoming messages that
|
||||
* can be distributed between two FIFOs and three transmit mailboxes. For transmitted messages
|
||||
* it is possible to opt for event notification once message is transmitted.
|
||||
*
|
||||
* LGPL License Terms @ref lgpl_license
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is part of the libopencm3 project.
|
||||
*
|
||||
@@ -53,11 +34,11 @@
|
||||
* @param [in] canport FDCAN block base address. See @ref fdcan_block.
|
||||
* @param [in] set new value of INIT, true means set
|
||||
* @param [in] timeout Amount of busyloop cycles, function will wait for FDCAN
|
||||
* to switch it's state. If set to 0, then function returns immediately.
|
||||
* to switch it's state. If set to 0, then function returns immediately.
|
||||
* @returns FDCAN_E_OK on success, FDCAN_E_TIMEOUT if INIT bit value
|
||||
* didn't change before timeout has expired.
|
||||
*/
|
||||
static int fdcan_cccr_init_cfg(uint32_t canport, bool set, uint32_t timeout)
|
||||
int fdcan_cccr_init_cfg(uint32_t canport, bool set, uint32_t timeout)
|
||||
{
|
||||
uint32_t expected;
|
||||
uint32_t wait_ack;
|
||||
@@ -135,43 +116,71 @@ static void fdcan_get_fill_rxfifo(uint32_t canport, uint8_t fifo_id, unsigned *g
|
||||
& FDCAN_RXFIFO_FL_MASK;
|
||||
}
|
||||
|
||||
/** Obtain address of FDCAN Message RAM for certain FDCAN block.
|
||||
/** Returns standard filter start address in message RAM
|
||||
*
|
||||
* @param [in] canport identification of FDCAN block. See @ref fdcan_block.
|
||||
* @return Address of Message RAM for given FDCAN block or null pointer
|
||||
* if FDCAN block identification is invalid.
|
||||
* @param [in] canport FDCAN block base address. See @ref fdcan_block.
|
||||
* @returns Base address of standard filter configuration block.
|
||||
*/
|
||||
static struct fdcan_message_ram *fdcan_get_msgram_addr(uint32_t canport)
|
||||
struct fdcan_standard_filter *fdcan_get_flssa_addr(uint32_t canport)
|
||||
{
|
||||
/* This piece of code may look wrong, after one examines
|
||||
* STM32G4 datasheet and/or g4/memorymap.h. There are three
|
||||
* memory regions defined for FDCANx_RAM_BASE. They are 0x400
|
||||
* bytes apart as per chapter 2.2.2 of [RM0440].
|
||||
*
|
||||
* It turns out, that these addresses are not in line with what
|
||||
* is specified later in chapter 44.3.3 of [RM0440]. There it is
|
||||
* stated, that message RAMs are packed and in case of multiple
|
||||
* FDCAN blocks, message RAM for n-th FDCAN starts at address
|
||||
* end of (n-1)-th block + 4 (explicitly, offset 0x354).
|
||||
*
|
||||
* It turns out, that this statement is also false! In fact FDCAN
|
||||
* message RAMs are packed tightly and n-th block starts immediately
|
||||
* after (n-1)-th block ends. Thus offset is going to be computed
|
||||
* using formula:
|
||||
*
|
||||
* FDCAN1_RAM_BASE + (block_id * sizeof(struct fdcan_message_ram))
|
||||
*/
|
||||
if (canport == CAN1) {
|
||||
return (struct fdcan_message_ram *) (FDCAN1_RAM_BASE + 0);
|
||||
} else if (canport == CAN2) {
|
||||
return (struct fdcan_message_ram *)
|
||||
(FDCAN1_RAM_BASE + sizeof(struct fdcan_message_ram));
|
||||
} else if (canport == CAN3) {
|
||||
return (struct fdcan_message_ram *)
|
||||
(FDCAN1_RAM_BASE + (2 * sizeof(struct fdcan_message_ram)));
|
||||
}
|
||||
struct fdcan_standard_filter *lfssa = (struct fdcan_standard_filter *)
|
||||
(CAN_MSG_BASE + FDCAN_LFSSA_OFFSET(canport));
|
||||
return lfssa;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
/** Returns extended filter start address in message RAM
|
||||
*
|
||||
* @param [in] canport FDCAN block base address. See @ref fdcan_block.
|
||||
* @returns Base address of extended filter configuration block.
|
||||
*/
|
||||
struct fdcan_extended_filter *fdcan_get_flesa_addr(uint32_t canport)
|
||||
{
|
||||
struct fdcan_extended_filter *lfesa = (struct fdcan_extended_filter *)
|
||||
(CAN_MSG_BASE + FDCAN_LFESA_OFFSET(canport));
|
||||
return lfesa;
|
||||
}
|
||||
|
||||
/** Returns FIFO start address in message RAM
|
||||
*
|
||||
* @param [in] canport FDCAN block base address. See @ref fdcan_block.
|
||||
* @param [in] fifo_id ID of FIFO whose address is requested
|
||||
* @returns Base address of FIFO block.
|
||||
*/
|
||||
struct fdcan_rx_fifo_element *fdcan_get_rxfifo_addr(uint32_t canport,
|
||||
unsigned fifo_id, unsigned element_id)
|
||||
{
|
||||
struct fdcan_rx_fifo_element *rxfifo = (struct fdcan_rx_fifo_element *)
|
||||
(CAN_MSG_BASE + FDCAN_RXFIFO_OFFSET(canport, fifo_id)
|
||||
+ (element_id * fdcan_get_fifo_element_size(canport, fifo_id))
|
||||
);
|
||||
return rxfifo;
|
||||
}
|
||||
|
||||
/** Returns transmit event start address in message RAM
|
||||
*
|
||||
* @param [in] canport FDCAN block base address. See @ref fdcan_block.
|
||||
* @returns Base address of transmit event block.
|
||||
*/
|
||||
struct fdcan_tx_event_element *fdcan_get_txevt_addr(uint32_t canport)
|
||||
{
|
||||
struct fdcan_tx_event_element *rxfifo = (struct fdcan_tx_event_element *)
|
||||
(CAN_MSG_BASE + FDCAN_TXEVT_OFFSET(canport));
|
||||
return rxfifo;
|
||||
}
|
||||
|
||||
/** Returns transmit buffer start address in message RAM
|
||||
*
|
||||
* @param [in] canport FDCAN block base address. See @ref fdcan_block.
|
||||
* @returns Base address of transmit buffer block.
|
||||
*/
|
||||
struct fdcan_tx_buffer_element *fdcan_get_txbuf_addr(uint32_t canport, unsigned element_id)
|
||||
{
|
||||
struct fdcan_tx_buffer_element *rxfifo = (struct fdcan_tx_buffer_element *)
|
||||
(CAN_MSG_BASE + FDCAN_TXBUF_OFFSET(canport)
|
||||
+ (element_id * fdcan_get_txbuf_element_size(canport))
|
||||
);
|
||||
|
||||
return rxfifo;
|
||||
}
|
||||
|
||||
/** Converts frame length to DLC value.
|
||||
@@ -183,7 +192,7 @@ static struct fdcan_message_ram *fdcan_get_msgram_addr(uint32_t canport)
|
||||
* @returns DLC value representing lengths or 0xFF if length cannot
|
||||
* be encoded into DLC format (applies only to FDCAN frame lengths)
|
||||
*/
|
||||
static uint32_t fdcan_length_to_dlc(uint8_t length)
|
||||
uint32_t fdcan_length_to_dlc(uint8_t length)
|
||||
{
|
||||
if (length <= 8) {
|
||||
return length;
|
||||
@@ -207,7 +216,7 @@ static uint32_t fdcan_length_to_dlc(uint8_t length)
|
||||
* @param [in] dlc DLC value
|
||||
* @returns data payload length in bytes
|
||||
*/
|
||||
static uint8_t fdcan_dlc_to_length(uint32_t dlc)
|
||||
uint8_t fdcan_dlc_to_length(uint32_t dlc)
|
||||
{
|
||||
if (dlc <= 8) {
|
||||
return dlc;
|
||||
@@ -237,13 +246,13 @@ static uint8_t fdcan_dlc_to_length(uint32_t dlc)
|
||||
* * @ref fdcan_init_filter
|
||||
* * @ref fdcan_set_test
|
||||
*
|
||||
* You can check if FDCAN block is in INIT mode or it is started using
|
||||
* You can check if FDCAN block is in INIT mode or it is started using
|
||||
* @ref fdcan_get_init_state.
|
||||
*
|
||||
* @param[in] canport CAN register base address. See @ref fdcan_block.
|
||||
* @param [in] timeout Amount of empty busy loops, which routine should wait for FDCAN
|
||||
* confirming that it entered INIT mode. If set to 0, function will return
|
||||
* immediately.
|
||||
* confirming that it entered INIT mode. If set to 0, function will
|
||||
* return immediately.
|
||||
* @returns Operation error status. See @ref fdcan_error.
|
||||
*/
|
||||
int fdcan_init(uint32_t canport, uint32_t timeout)
|
||||
@@ -309,16 +318,11 @@ void fdcan_set_can(uint32_t canport, bool auto_retry_disable, bool rx_fifo_locke
|
||||
FDCAN_CCCR(canport) &= ~FDCAN_CCCR_MON;
|
||||
}
|
||||
|
||||
if (rx_fifo_locked) {
|
||||
FDCAN_RXGFC(canport) &= ~(FDCAN_RXGFC_F1OM | FDCAN_RXGFC_F0OM);
|
||||
} else {
|
||||
FDCAN_RXGFC(canport) |= FDCAN_RXGFC_F1OM | FDCAN_RXGFC_F0OM;
|
||||
}
|
||||
|
||||
fdcan_set_fifo_locked_mode(canport, rx_fifo_locked);
|
||||
}
|
||||
|
||||
/** Set FDCAN block parameters for FDCAN transmission
|
||||
*
|
||||
*
|
||||
* Enables and configures parameters related to FDCAN transmission. This function
|
||||
* allows configuration of bitrate switching, FDCAN frame format and fast mode
|
||||
* timing. This function can only be called if FDCAN block is in INIT mode.
|
||||
@@ -381,36 +385,6 @@ void fdcan_set_test(uint32_t canport, bool testing, bool loopback)
|
||||
}
|
||||
}
|
||||
|
||||
/** Enable FDCAN operation after FDCAN block has been set up.
|
||||
*
|
||||
* This function will disable FDCAN configuration effectively
|
||||
* allowing FDCAN to sync up with the bus. After calling this function
|
||||
* it is not possible to reconfigure amount of filter rules, yet
|
||||
* it is possible to configure rules themselves. FDCAN block operation
|
||||
* state can be checked using @ref fdcan_get_init_state.
|
||||
*
|
||||
* @param [in] canport FDCAN block base address. See @ref fdcan_block.
|
||||
* @param [in] timeout Amount of empty busy loops, which routine should wait for FDCAN
|
||||
* confirming that it left INIT mode. If set to 0, function will return
|
||||
* immediately.
|
||||
* @returns Operation error status. See @ref fdcan_error.
|
||||
* @note If this function returns with timeout, it usually means that
|
||||
* FDCAN_clk is not set up properly.
|
||||
*/
|
||||
int fdcan_start(uint32_t canport, uint32_t timeout)
|
||||
{
|
||||
/* Error here usually means, that FDCAN_clk is not set up
|
||||
* correctly, or at all. This usually can't be seen above
|
||||
* when INIT is set to 1, because default value for INIT is
|
||||
* 1 as long as one has FDCAN_pclk configured properly.
|
||||
**/
|
||||
if (fdcan_cccr_init_cfg(canport, false, timeout) != 0) {
|
||||
return FDCAN_E_TIMEOUT;
|
||||
}
|
||||
|
||||
return FDCAN_E_OK;
|
||||
}
|
||||
|
||||
/** Return current FDCAN block operation state.
|
||||
*
|
||||
* This function effectively returns value of FDCAN_CCCR's INIT bit.
|
||||
@@ -422,59 +396,6 @@ int fdcan_get_init_state(uint32_t canport)
|
||||
return ((FDCAN_CCCR(canport) & FDCAN_CCCR_INIT) == FDCAN_CCCR_INIT);
|
||||
}
|
||||
|
||||
/** Configure amount of filters and initialize filtering block.
|
||||
*
|
||||
* This function allows to configure global amount of filters present.
|
||||
* FDCAN block will only ever check as many filters as this function configures.
|
||||
* Function will also clear all filter blocks to zero values. This function
|
||||
* can be only called after @ref fdcan_init has already been called and
|
||||
* @ref fdcan_start has not been called yet as registers holding filter
|
||||
* count are write-protected unless FDCAN block is in INIT mode. It is possible
|
||||
* to reconfigure filters (@ref fdcan_set_std_filter and @ref fdcan_set_ext_filter)
|
||||
* after FDCAN block has already been started.
|
||||
*
|
||||
* @param [in] canport FDCAN block base address. See @ref fdcan_block.
|
||||
* @param [in] std_filt requested amount of standard ID filter rules (0-28)
|
||||
* @param [in] ext_filt requested amount of extended ID filter rules (0-8)
|
||||
*/
|
||||
void fdcan_init_filter(uint32_t canport, uint8_t std_filt, uint8_t ext_filt)
|
||||
{
|
||||
struct fdcan_message_ram *ram = fdcan_get_msgram_addr(canport);
|
||||
|
||||
/* Only perform initialization of message RAM if there are
|
||||
* any filters required
|
||||
*/
|
||||
if (std_filt > 0) {
|
||||
FDCAN_RXGFC(canport) =
|
||||
(FDCAN_RXGFC(canport) & ~(FDCAN_RXGFC_LSS_MASK << FDCAN_RXGFC_LSS_SHIFT))
|
||||
| (std_filt << FDCAN_RXGFC_LSS_SHIFT);
|
||||
|
||||
|
||||
for (int q = 0; q < FDCAN_SFT_MAX_NR; ++q) {
|
||||
ram->lfssa[q].type_id1_conf_id2 = 0;
|
||||
}
|
||||
} else {
|
||||
/* Reset filter count to zero */
|
||||
FDCAN_RXGFC(canport) =
|
||||
(FDCAN_RXGFC(canport) & ~(FDCAN_RXGFC_LSS_MASK << FDCAN_RXGFC_LSS_SHIFT));
|
||||
}
|
||||
|
||||
if (ext_filt > 0) {
|
||||
FDCAN_RXGFC(canport) =
|
||||
(FDCAN_RXGFC(canport) & ~(FDCAN_RXGFC_LSE_MASK << FDCAN_RXGFC_LSE_SHIFT))
|
||||
| (ext_filt << FDCAN_RXGFC_LSE_SHIFT);
|
||||
|
||||
for (int q = 0; q < FDCAN_EFT_MAX_NR; ++q) {
|
||||
ram->lfesa[q].conf_id1 = 0;
|
||||
ram->lfesa[q].type_id2 = 0;
|
||||
}
|
||||
} else {
|
||||
/* Reset filter count to zero */
|
||||
FDCAN_RXGFC(canport) =
|
||||
(FDCAN_RXGFC(canport) & ~(FDCAN_RXGFC_LSE_MASK << FDCAN_RXGFC_LSE_SHIFT));
|
||||
}
|
||||
}
|
||||
|
||||
/** Configure filter rule for standard ID frames.
|
||||
*
|
||||
* Sets up filter rule for frames having standard ID. Each FDCAN block can
|
||||
@@ -483,20 +404,20 @@ void fdcan_init_filter(uint32_t canport, uint8_t std_filt, uint8_t ext_filt)
|
||||
*
|
||||
* @param [in] canport FDCAN block base address. See @ref fdcan_block.
|
||||
* @param [in] nr number of filter to be configured
|
||||
* @param [in] id_list_mode Mode in which id1 and id2 are used to match the rule.
|
||||
* See @ref fdcan_sft.
|
||||
* @param [in] id_list_mode Mode in which id1 and id2 are used to match the rule.
|
||||
* See @ref fdcan_sft.
|
||||
* @param [in] id1 standard ID for matching. Used as exact value, lower bound or bit
|
||||
* pattern depending on matching mode selected
|
||||
* @param [in] id2 standard ID or bitmask. Used as exact value, upper bound or bit mask
|
||||
* depending on matching mode selected
|
||||
* @param [in] action Action performed if filtering rule matches frame ID.
|
||||
* See @ref fdcan_sfec.
|
||||
* @param [in] action Action performed if filtering rule matches frame ID.
|
||||
* See @ref fdcan_sfec.
|
||||
*/
|
||||
void fdcan_set_std_filter(uint32_t canport, uint32_t nr,
|
||||
uint8_t id_list_mode, uint32_t id1, uint32_t id2,
|
||||
uint8_t action)
|
||||
{
|
||||
struct fdcan_message_ram *ram = fdcan_get_msgram_addr(canport);
|
||||
struct fdcan_standard_filter *lfssa = fdcan_get_flssa_addr(canport);
|
||||
|
||||
/* id_list_mode and action are passed unguarded. Simply use
|
||||
* defines and it will be OK. id1 and id2 are masked for
|
||||
@@ -506,7 +427,7 @@ void fdcan_set_std_filter(uint32_t canport, uint32_t nr,
|
||||
* overflow into flags. This tends to be extremely time
|
||||
* consuming to debug.
|
||||
*/
|
||||
ram->lfssa[nr].type_id1_conf_id2 =
|
||||
lfssa[nr].type_id1_conf_id2 =
|
||||
(id_list_mode << FDCAN_SFT_SHIFT)
|
||||
| (action << FDCAN_SFEC_SHIFT)
|
||||
| ((id1 & FDCAN_SFID1_MASK) << FDCAN_SFID1_SHIFT)
|
||||
@@ -524,25 +445,25 @@ void fdcan_set_std_filter(uint32_t canport, uint32_t nr,
|
||||
* @param [in] canport FDCAN block base address. See @ref fdcan_block.
|
||||
* @param [in] nr number of filter to be configured
|
||||
* @param [in] id_list_mode mode in which id1 and id2 are used to match the rule.
|
||||
* See @ref fdcan_eft.
|
||||
* See @ref fdcan_eft.
|
||||
* @param [in] id1 extended ID for matching. Used as exact value, lower bound or bit
|
||||
* pattern depending on matching mode selected
|
||||
* @param [in] id2 extended ID or bitmask. Used as exact value, upper bound or bit mask
|
||||
* depending on matching mode selected
|
||||
* @param [in] action Action performed if filtering rule matches frame ID.
|
||||
* See @ref fdcan_efec.
|
||||
* See @ref fdcan_efec.
|
||||
*/
|
||||
void fdcan_set_ext_filter(uint32_t canport, uint32_t nr,
|
||||
uint8_t id_list_mode, uint32_t id1, uint32_t id2,
|
||||
uint8_t action)
|
||||
{
|
||||
struct fdcan_message_ram *ram = fdcan_get_msgram_addr(canport);
|
||||
struct fdcan_extended_filter *lfesa = fdcan_get_flesa_addr(canport);
|
||||
|
||||
ram->lfesa[nr].conf_id1 =
|
||||
lfesa[nr].conf_id1 =
|
||||
(action << FDCAN_EFEC_SHIFT)
|
||||
| ((id1 & FDCAN_EFID1_MASK) << FDCAN_EFID1_SHIFT);
|
||||
|
||||
ram->lfesa[nr].type_id2 =
|
||||
lfesa[nr].type_id2 =
|
||||
(id_list_mode << FDCAN_EFT_SHIFT)
|
||||
| ((id2 & FDCAN_EFID2_MASK) << FDCAN_EFID2_SHIFT);
|
||||
}
|
||||
@@ -572,7 +493,7 @@ int fdcan_transmit(uint32_t canport, uint32_t id, bool ext, bool rtr,
|
||||
return mailbox;
|
||||
}
|
||||
|
||||
struct fdcan_message_ram *ram = fdcan_get_msgram_addr(canport);
|
||||
struct fdcan_tx_buffer_element *tx_buffer = fdcan_get_txbuf_addr(canport, mailbox);
|
||||
|
||||
/* Early check: if FDCAN message lentgh is > 8, it must be
|
||||
* a multiple of 4 *and* fdcan format must be enabled.
|
||||
@@ -584,15 +505,15 @@ int fdcan_transmit(uint32_t canport, uint32_t id, bool ext, bool rtr,
|
||||
}
|
||||
|
||||
if (ext) {
|
||||
ram->tx_buffer[mailbox].identifier_flags = FDCAN_FIFO_XTD
|
||||
tx_buffer->identifier_flags = FDCAN_FIFO_XTD
|
||||
| ((id & FDCAN_FIFO_EID_MASK) << FDCAN_FIFO_EID_SHIFT);
|
||||
} else {
|
||||
ram->tx_buffer[mailbox].identifier_flags =
|
||||
tx_buffer->identifier_flags =
|
||||
(id & FDCAN_FIFO_SID_MASK) << FDCAN_FIFO_SID_SHIFT;
|
||||
}
|
||||
|
||||
if (rtr) {
|
||||
ram->tx_buffer[mailbox].identifier_flags |= FDCAN_FIFO_RTR;
|
||||
tx_buffer->identifier_flags |= FDCAN_FIFO_RTR;
|
||||
}
|
||||
|
||||
if (fdcan_fmt) {
|
||||
@@ -603,11 +524,11 @@ int fdcan_transmit(uint32_t canport, uint32_t id, bool ext, bool rtr,
|
||||
flags |= FDCAN_FIFO_BRS;
|
||||
}
|
||||
|
||||
ram->tx_buffer[mailbox].evt_fmt_dlc_res =
|
||||
tx_buffer->evt_fmt_dlc_res =
|
||||
(dlc << FDCAN_FIFO_DLC_SHIFT) | flags;
|
||||
|
||||
for (int q = 0; q < length; q += 4) {
|
||||
ram->tx_buffer[mailbox].data[q / 4] = *((uint32_t *) &data[q]);
|
||||
tx_buffer->data[q / 4] = *((uint32_t *) &data[q]);
|
||||
}
|
||||
|
||||
FDCAN_TXBAR(canport) |= 1 << mailbox;
|
||||
@@ -640,52 +561,49 @@ int fdcan_receive(uint32_t canport, uint8_t fifo_id, bool release, uint32_t *id,
|
||||
bool *ext, bool *rtr, uint8_t *fmi, uint8_t *length,
|
||||
uint8_t *data, uint16_t *timestamp)
|
||||
{
|
||||
const struct fdcan_message_ram *ram = fdcan_get_msgram_addr(canport);
|
||||
|
||||
const struct fdcan_rx_fifo_element *fifo;
|
||||
|
||||
unsigned pending_frames, get_index, dlc, len;
|
||||
|
||||
fdcan_get_fill_rxfifo(canport, fifo_id, &get_index, &pending_frames);
|
||||
|
||||
fifo = ram->rx_fifo[fifo_id];
|
||||
|
||||
if (pending_frames == 0) {
|
||||
return FDCAN_E_NOTAVAIL;
|
||||
}
|
||||
|
||||
dlc = (fifo[get_index].filt_fmt_dlc_ts >> FDCAN_FIFO_DLC_SHIFT)
|
||||
const struct fdcan_rx_fifo_element *fifo = fdcan_get_rxfifo_addr(canport,
|
||||
fifo_id, get_index);
|
||||
|
||||
dlc = (fifo->filt_fmt_dlc_ts >> FDCAN_FIFO_DLC_SHIFT)
|
||||
& FDCAN_FIFO_DLC_MASK;
|
||||
|
||||
len = fdcan_dlc_to_length(dlc);
|
||||
|
||||
*length = len;
|
||||
if ((fifo[get_index].identifier_flags & FDCAN_FIFO_XTD) == FDCAN_FIFO_XTD) {
|
||||
if ((fifo->identifier_flags & FDCAN_FIFO_XTD) == FDCAN_FIFO_XTD) {
|
||||
*ext = true;
|
||||
*id = (fifo[get_index].identifier_flags >> FDCAN_FIFO_EID_SHIFT)
|
||||
*id = (fifo->identifier_flags >> FDCAN_FIFO_EID_SHIFT)
|
||||
& FDCAN_FIFO_EID_MASK;
|
||||
} else {
|
||||
*ext = false;
|
||||
*id = (fifo[get_index].identifier_flags >> FDCAN_FIFO_SID_SHIFT)
|
||||
*id = (fifo->identifier_flags >> FDCAN_FIFO_SID_SHIFT)
|
||||
& FDCAN_FIFO_SID_MASK;
|
||||
}
|
||||
|
||||
if (timestamp) {
|
||||
*timestamp = (uint16_t) (fifo[get_index].filt_fmt_dlc_ts >> FDCAN_FIFO_RXTS_SHIFT)
|
||||
*timestamp = (uint16_t) (fifo->filt_fmt_dlc_ts >> FDCAN_FIFO_RXTS_SHIFT)
|
||||
& FDCAN_FIFO_RXTS_MASK;
|
||||
}
|
||||
|
||||
if (fmi) {
|
||||
*fmi = (uint8_t) (fifo[get_index].filt_fmt_dlc_ts >> FDCAN_FIFO_MM_SHIFT)
|
||||
*fmi = (uint8_t) (fifo->filt_fmt_dlc_ts >> FDCAN_FIFO_MM_SHIFT)
|
||||
& FDCAN_FIFO_MM_MASK;
|
||||
}
|
||||
|
||||
if (rtr) {
|
||||
*rtr = ((fifo[get_index].identifier_flags & FDCAN_FIFO_RTR) == FDCAN_FIFO_RTR);
|
||||
*rtr = ((fifo->identifier_flags & FDCAN_FIFO_RTR) == FDCAN_FIFO_RTR);
|
||||
}
|
||||
|
||||
for (unsigned int q = 0; q < len; q += 4) {
|
||||
*((uint32_t *) &data[q]) = fifo[get_index].data[q / 4];
|
||||
*((uint32_t *) &data[q]) = fifo->data[q / 4];
|
||||
}
|
||||
|
||||
if (release) {
|
||||
@@ -40,7 +40,7 @@ OBJS += crs_common_all.o
|
||||
OBJS += dac_common_all.o dac_common_v2.o
|
||||
OBJS += dma_common_l1f013.o
|
||||
OBJS += dmamux.o
|
||||
OBJS += fdcan.o
|
||||
OBJS += fdcan.o fdcan_common.o
|
||||
OBJS += flash.o flash_common_all.o flash_common_f.o flash_common_idcache.o
|
||||
OBJS += gpio_common_all.o gpio_common_f0234.o
|
||||
OBJS += opamp_common_all.o opamp_common_v2.o
|
||||
|
||||
187
lib/stm32/g4/fdcan.c
Normal file
187
lib/stm32/g4/fdcan.c
Normal file
@@ -0,0 +1,187 @@
|
||||
/** @addtogroup fdcan_file FDCAN peripheral API
|
||||
*
|
||||
* @ingroup peripheral_apis
|
||||
*
|
||||
* @brief <b>libopencm3 STM32 FDCAN</b>
|
||||
*
|
||||
* @version 1.0.0
|
||||
*
|
||||
* @author @htmlonly © @endhtmlonly 2021 Eduard Drusa <ventyl86 at netkosice dot sk>
|
||||
*
|
||||
* Devices can have up to three FDCAN peripherals residing in one FDCAN block. The peripherals
|
||||
* support both CAN 2.0 A and B standard and Bosch FDCAN standard. FDCAN frame format and
|
||||
* bitrate switching is supported. The peripheral has several filters for incoming messages that
|
||||
* can be distributed between two FIFOs and three transmit mailboxes. For transmitted messages
|
||||
* it is possible to opt for event notification once message is transmitted.
|
||||
*
|
||||
* LGPL License Terms @ref lgpl_license
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is part of the libopencm3 project.
|
||||
*
|
||||
* Copyright (C) 2021 Eduard Drusa <ventyl86 at netkosice dot sk>
|
||||
*
|
||||
* This library is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <libopencm3/stm32/fdcan.h>
|
||||
#include <libopencm3/stm32/rcc.h>
|
||||
#include <stddef.h>
|
||||
|
||||
/* --- FD-CAN functions ----------------------------------------------------- */
|
||||
|
||||
/** @ingroup fdcan_file */
|
||||
/**@{
|
||||
* */
|
||||
|
||||
/** Returns actual size of FIFO entry in FIFO for given CAN port and FIFO.
|
||||
*
|
||||
* Obtains value of FIFO entry length. For G4 it returns constant value as
|
||||
* G4 has FIFO element length hardcoded.
|
||||
* @param [in] canport FDCAN block base address. See @ref fdcan_block. Unused.
|
||||
* @param [in] fifo_id ID of FIFO whole length is queried. Unused.
|
||||
* @returns Length of FIFO entry length covering frame header and frame payload.
|
||||
*/
|
||||
unsigned fdcan_get_fifo_element_size(uint32_t canport, unsigned fifo_id)
|
||||
{
|
||||
/* Silences compiler. Variables are present for API compatibility
|
||||
* with STM32H7
|
||||
*/
|
||||
(void) (canport);
|
||||
(void) (fifo_id);
|
||||
return sizeof(struct fdcan_rx_fifo_element);
|
||||
}
|
||||
|
||||
/** Returns actual size of transmit entry in transmit queue/FIFO for given CAN port.
|
||||
*
|
||||
* Obtains value of entry length in transmit queue/FIFO. For G4 it returns constant value
|
||||
* as G4 has transmit buffer entries of fixed length.
|
||||
*
|
||||
* @param [in] canport FDCAN block base address. See @ref fdcan_block. Unused.
|
||||
* @param [in] fifo_id ID of FIFO whole length is queried. Unused.
|
||||
* @returns Length of FIFO entry length covering frame header and frame payload.
|
||||
*/
|
||||
unsigned fdcan_get_txbuf_element_size(uint32_t canport)
|
||||
{
|
||||
/* Silences compiler. Variables are present for API compatibility
|
||||
* with STM32H7
|
||||
*/
|
||||
(void) (canport);
|
||||
return sizeof(struct fdcan_tx_buffer_element);
|
||||
}
|
||||
|
||||
/** Configure amount of filters and initialize filtering block.
|
||||
*
|
||||
* This function allows to configure global amount of filters present.
|
||||
* FDCAN block will only ever check as many filters as this function configures.
|
||||
* Function will also clear all filter blocks to zero values. This function
|
||||
* can be only called after @ref fdcan_init has already been called and
|
||||
* @ref fdcan_start has not been called yet as registers holding filter
|
||||
* count are write-protected unless FDCAN block is in INIT mode. It is possible
|
||||
* to reconfigure filters (@ref fdcan_set_std_filter and @ref fdcan_set_ext_filter)
|
||||
* after FDCAN block has already been started.
|
||||
*
|
||||
* @param [in] canport FDCAN block base address. See @ref fdcan_block.
|
||||
* @param [in] std_filt requested amount of standard ID filter rules (0-28)
|
||||
* @param [in] ext_filt requested amount of extended ID filter rules (0-8)
|
||||
*/
|
||||
void fdcan_init_filter(uint32_t canport, uint8_t std_filt, uint8_t ext_filt)
|
||||
{
|
||||
struct fdcan_standard_filter *lfssa = fdcan_get_flssa_addr(canport);
|
||||
struct fdcan_extended_filter *lfesa = fdcan_get_flesa_addr(canport);
|
||||
|
||||
/* Only perform initialization of message RAM if there are
|
||||
* any filters required
|
||||
*/
|
||||
if (std_filt > 0) {
|
||||
FDCAN_RXGFC(canport) =
|
||||
(FDCAN_RXGFC(canport) & ~(FDCAN_RXGFC_LSS_MASK << FDCAN_RXGFC_LSS_SHIFT))
|
||||
| (std_filt << FDCAN_RXGFC_LSS_SHIFT);
|
||||
|
||||
|
||||
for (int q = 0; q < FDCAN_SFT_MAX_NR; ++q) {
|
||||
lfssa[q].type_id1_conf_id2 = 0;
|
||||
}
|
||||
} else {
|
||||
/* Reset filter count to zero */
|
||||
FDCAN_RXGFC(canport) =
|
||||
(FDCAN_RXGFC(canport) & ~(FDCAN_RXGFC_LSS_MASK << FDCAN_RXGFC_LSS_SHIFT));
|
||||
}
|
||||
|
||||
if (ext_filt > 0) {
|
||||
FDCAN_RXGFC(canport) =
|
||||
(FDCAN_RXGFC(canport) & ~(FDCAN_RXGFC_LSE_MASK << FDCAN_RXGFC_LSE_SHIFT))
|
||||
| (ext_filt << FDCAN_RXGFC_LSE_SHIFT);
|
||||
|
||||
for (int q = 0; q < FDCAN_EFT_MAX_NR; ++q) {
|
||||
lfesa[q].conf_id1 = 0;
|
||||
lfesa[q].type_id2 = 0;
|
||||
}
|
||||
} else {
|
||||
/* Reset filter count to zero */
|
||||
FDCAN_RXGFC(canport) =
|
||||
(FDCAN_RXGFC(canport) & ~(FDCAN_RXGFC_LSE_MASK << FDCAN_RXGFC_LSE_SHIFT));
|
||||
}
|
||||
}
|
||||
|
||||
/** Enable FDCAN operation after FDCAN block has been set up.
|
||||
*
|
||||
* This function will disable FDCAN configuration effectively
|
||||
* allowing FDCAN to sync up with the bus. After calling this function
|
||||
* it is not possible to reconfigure amount of filter rules, yet
|
||||
* it is possible to configure rules themselves. FDCAN block operation
|
||||
* state can be checked using @ref fdcan_get_init_state.
|
||||
*
|
||||
* @param [in] canport FDCAN block base address. See @ref fdcan_block.
|
||||
* @param [in] timeout Amount of empty busy loops, which routine should wait for FDCAN
|
||||
* confirming that it left INIT mode. If set to 0, function will return
|
||||
* immediately.
|
||||
* @returns Operation error status. See @ref fdcan_error.
|
||||
* @note If this function returns with timeout, it usually means that
|
||||
* FDCAN_clk is not set up properly.
|
||||
*/
|
||||
int fdcan_start(uint32_t canport, uint32_t timeout)
|
||||
{
|
||||
/* Error here usually means, that FDCAN_clk is not set up
|
||||
* correctly, or at all. This usually can't be seen above
|
||||
* when INIT is set to 1, because default value for INIT is
|
||||
* 1 as long as one has FDCAN_pclk configured properly.
|
||||
**/
|
||||
if (fdcan_cccr_init_cfg(canport, false, timeout) != 0) {
|
||||
return FDCAN_E_TIMEOUT;
|
||||
}
|
||||
|
||||
return FDCAN_E_OK;
|
||||
}
|
||||
|
||||
/** Configure FDCAN FIFO lock mode
|
||||
*
|
||||
* This function allows to choose between locked and overewrite mode of FIFOs. In locked mode,
|
||||
* whenever FIFO is full and new frame arrives, which would normally been stored into given
|
||||
* FIFO, then frame is dropped. If overwrite mode is active, then most recent message in FIFO
|
||||
* is rewritten by frame just received.
|
||||
* @param [in] canport FDCAN block base address. See @ref fdcan_block.
|
||||
* @param [in] locked true activates locked mode, false activates overwrite mode
|
||||
*/
|
||||
void fdcan_set_fifo_locked_mode(uint32_t canport, bool locked)
|
||||
{
|
||||
if (locked) {
|
||||
FDCAN_RXGFC(canport) &= ~(FDCAN_RXGFC_F1OM | FDCAN_RXGFC_F0OM);
|
||||
} else {
|
||||
FDCAN_RXGFC(canport) |= FDCAN_RXGFC_F1OM | FDCAN_RXGFC_F0OM;
|
||||
}
|
||||
}
|
||||
|
||||
/** @} */
|
||||
@@ -39,6 +39,7 @@ ARFLAGS = rcs
|
||||
|
||||
OBJS += dac_common_all.o dac_common_v2.o
|
||||
OBJS += exti_common_all.o
|
||||
OBJS += fdcan.o fdcan_common.o
|
||||
OBJS += flash_common_all.o flash_common_f.o flash_common_f24.o
|
||||
OBJS += fmc_common_f47.o
|
||||
OBJS += gpio_common_all.o gpio_common_f0234.o
|
||||
|
||||
473
lib/stm32/h7/fdcan.c
Normal file
473
lib/stm32/h7/fdcan.c
Normal file
@@ -0,0 +1,473 @@
|
||||
/** @addtogroup fdcan_file FDCAN peripheral API
|
||||
*
|
||||
* @ingroup peripheral_apis
|
||||
*
|
||||
* @brief <b>libopencm3 STM32 FDCAN</b>
|
||||
*
|
||||
* @version 1.0.0
|
||||
*
|
||||
* @author @htmlonly © @endhtmlonly 2021 Eduard Drusa <ventyl86 at netkosice dot sk>
|
||||
*
|
||||
* Device is equipped with two FDCAN peripherals residing in one FDCAN block. The peripherals
|
||||
* support both CAN 2.0 A and B standard and Bosch FDCAN standard. FDCAN frame format and
|
||||
* bitrate switching is supported. The peripheral has several filters for incoming messages that
|
||||
* can be distributed between two FIFOs and transmit buffer all of configurable amount of
|
||||
* entries. For transmitted messages it is possible to opt for event notification once message
|
||||
* is transmitted.
|
||||
*
|
||||
* The FDCAN peripheral present in STM32 H7 is a superset of FDCAN peripheral found in other MCUs
|
||||
* such as STM32 G4. It allows more fine-grade control over buffer and filter allocation and
|
||||
* supports TTCAN on CAN1, etc. This driver provides source-level backwards compatible
|
||||
* implementation of driver, which allows build of unmodified software originally written for
|
||||
* STM32 G4 on STM32 H7.
|
||||
*
|
||||
* LGPL License Terms @ref lgpl_license
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is part of the libopencm3 project.
|
||||
*
|
||||
* Copyright (C) 2021 Eduard Drusa <ventyl86 at netkosice dot sk>
|
||||
*
|
||||
* This library is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <libopencm3/stm32/fdcan.h>
|
||||
#include <libopencm3/stm32/rcc.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#define FDCAN_LSS_COUNT(can_base) \
|
||||
((FDCAN_SIDFC(can_base) >> FDCAN_SIDFC_LSS_SHIFT) & FDCAN_SIDFC_LSS_MASK)
|
||||
|
||||
#define FDCAN_LSE_COUNT(can_base) \
|
||||
((FDCAN_XIDFC(can_base) >> FDCAN_XIDFC_LSE_SHIFT) & FDCAN_XIDFC_LSE_MASK)
|
||||
|
||||
/* --- FD-CAN functions ----------------------------------------------------- */
|
||||
|
||||
/** @ingroup fdcan_file */
|
||||
/**@{
|
||||
* */
|
||||
|
||||
/** Returns actual size of FIFO entry in FIFO for given CAN port and FIFO.
|
||||
*
|
||||
* Obtains value of FIFO entry length. This value covers both fixed-size frame
|
||||
* header block and payload buffer. User can configure payload buffer size individually
|
||||
* for each FIFO and designated RX buffer.
|
||||
*
|
||||
* @param [in] canport FDCAN block base address. See @ref fdcan_block.
|
||||
* @param [in] fifo_id ID of FIFO whole length is queried.
|
||||
* @returns Length of FIFO entry length covering frame header and frame payload.
|
||||
*/
|
||||
unsigned fdcan_get_fifo_element_size(uint32_t canport, unsigned fifo_id)
|
||||
{
|
||||
unsigned element_size;
|
||||
if (fifo_id == 0) {
|
||||
element_size = FDCAN_RXESC(canport) >> FDCAN_RXESC_F0DS_SHIFT;
|
||||
} else {
|
||||
element_size = FDCAN_RXESC(canport) >> FDCAN_RXESC_F1DS_SHIFT;
|
||||
}
|
||||
|
||||
/* Mask is unshifted and at this point, element_size is unshifted too */
|
||||
return 8 + fdcan_dlc_to_length((element_size & FDCAN_RXESC_F0DS_MASK) | 0x7);
|
||||
}
|
||||
|
||||
/** Returns actual size of transmit entry in transmit queue/FIFO for given CAN port.
|
||||
*
|
||||
* Obtains value of entry length in transmit queue/FIFO. This value covers both
|
||||
* fixed-sized frame header block and payload buffer. User can configure payload buffer
|
||||
* size.
|
||||
*
|
||||
* @param [in] canport FDCAN block base address. See @ref fdcan_block.
|
||||
* @param [in] fifo_id ID of FIFO whole length is queried.
|
||||
* @returns Length of FIFO entry length covering frame header and frame payload.
|
||||
*/
|
||||
unsigned fdcan_get_txbuf_element_size(uint32_t canport)
|
||||
{
|
||||
unsigned element_size;
|
||||
element_size = (FDCAN_TXESC(canport) >> FDCAN_TXESC_TBDS_SHIFT) & FDCAN_TXESC_TBDS_MASK;
|
||||
return 8 + fdcan_dlc_to_length((element_size & FDCAN_TXESC_TBDS_MASK) | 0x7);
|
||||
}
|
||||
|
||||
/** Initialize allocation of standard filter block in CAN message RAM.
|
||||
*
|
||||
* Allows specifying size of standard filtering block (in term of available filtering
|
||||
* rules and filter base address within CAN message RAM. Note, that there are no limitations
|
||||
* nor checking on address provided. It is possible to share whole filtering block or
|
||||
* portion of it between multiple CAN interfaces.
|
||||
* @param [in] canport FDCAN block base address. See @ref fdcan_block.
|
||||
* @param [in] flssa standard filtering block start address offset in message RAM
|
||||
* @param [in] lss amount of standard filters
|
||||
*/
|
||||
void fdcan_init_std_filter_ram(uint32_t canport, uint32_t flssa, uint8_t lss)
|
||||
{
|
||||
FDCAN_SIDFC(canport) = flssa << FDCAN_SIDFC_FLSSA_SHIFT
|
||||
| lss << FDCAN_SIDFC_LSS_SHIFT;
|
||||
}
|
||||
|
||||
/** Initialize allocation of extended filter block in CAN message RAM.
|
||||
*
|
||||
* Allows specifying size of extended filtering block (in term of available filtering
|
||||
* rules and filter base address within CAN message RAM. Note, that there are no limitations
|
||||
* nor checking on address provided. It is possible to share whole filtering block or
|
||||
* portion of it between multiple CAN interfaces.
|
||||
* @param [in] canport FDCAN block base address. See @ref fdcan_block.
|
||||
* @param [in] flesa extended filtering block start address offset in message RAM
|
||||
* @param [in] lse amount of extended filters
|
||||
*/
|
||||
void fdcan_init_ext_filter_ram(uint32_t canport, uint32_t flesa, uint8_t lse)
|
||||
{
|
||||
FDCAN_XIDFC(canport) = flesa << FDCAN_XIDFC_FLESA_SHIFT
|
||||
| lse << FDCAN_XIDFC_LSE_SHIFT;
|
||||
}
|
||||
|
||||
/** Initialize allocation of FIFO block in CAN message RAM.
|
||||
*
|
||||
* Allows specifying size of FIFO block (in term of available messages in FIFO
|
||||
* and FIFO base address within CAN message RAM. Note, that there are no limitations
|
||||
* nor checking on address provided.
|
||||
* @param [in] canport FDCAN block base address. See @ref fdcan_block.
|
||||
* @param [in] fifo_id ID of fifo being configured
|
||||
* @param [in] fxsa FIFO block start address offset in message RAM
|
||||
* @param [in] fxs amount of entries allocated in FIFO
|
||||
*/
|
||||
void fdcan_init_fifo_ram(uint32_t canport, unsigned fifo_id, uint32_t fxsa, uint8_t fxs)
|
||||
{
|
||||
FDCAN_RXFIC(canport, fifo_id) = (FDCAN_RXFIC(canport, fifo_id)
|
||||
& ~(
|
||||
(FDCAN_RXFIC_FIS_MASK << FDCAN_RXFIC_FIS_SHIFT)
|
||||
| (FDCAN_RXFIC_FISA_MASK << FDCAN_RXFIC_FISA_SHIFT)
|
||||
))
|
||||
| (fxs << FDCAN_RXFIC_FIS_SHIFT)
|
||||
| (fxsa & (FDCAN_RXFIC_FISA_MASK << FDCAN_RXFIC_FISA_SHIFT));
|
||||
}
|
||||
|
||||
/** Initialize allocation of transmit event block in CAN message RAM.
|
||||
*
|
||||
* Allows specifying size of transmit event block (in term of allocated events and block
|
||||
* base address within CAN message RAM. Note, that there are no limitations
|
||||
* nor checking on address provided.
|
||||
* @param [in] canport FDCAN block base address. See @ref fdcan_block.
|
||||
* @param [in] fifo_id ID of fifo being configured
|
||||
* @param [in] fxsa FIFO block start address offset in message RAM
|
||||
* @param [in] fxs amount of entries allocated in FIFO
|
||||
*/
|
||||
void fdcan_init_tx_event_ram(uint32_t canport, uint32_t tesa, uint8_t tes)
|
||||
{
|
||||
FDCAN_TXEFC(canport) = (FDCAN_TXEFC(canport)
|
||||
& ~(
|
||||
(FDCAN_TXEFC_EFS_MASK << FDCAN_TXEFC_EFS_SHIFT)
|
||||
| (FDCAN_TXEFC_EFSA_MASK << FDCAN_TXEFC_EFSA_SHIFT)
|
||||
))
|
||||
| (tes << FDCAN_TXEFC_EFS_SHIFT)
|
||||
| (tesa & (FDCAN_TXEFC_EFSA_MASK << FDCAN_TXEFC_EFSA_SHIFT));
|
||||
}
|
||||
|
||||
/** Initialize allocation of transmit queue block in CAN message RAM.
|
||||
*
|
||||
* Allows specifying size of transmit queue block (in term of allocated buffers and block
|
||||
* base address within CAN message RAM. Note, that there are no limitations
|
||||
* nor checking on address provided.
|
||||
* @param [in] canport FDCAN block base address. See @ref fdcan_block.
|
||||
* @param [in] fifo_id ID of fifo being configured
|
||||
* @param [in] fxsa FIFO block start address offset in message RAM
|
||||
* @param [in] fxs amount of entries allocated in FIFO
|
||||
*/
|
||||
void fdcan_init_tx_buffer_ram(uint32_t canport, uint32_t tbsa, uint8_t tbs)
|
||||
{
|
||||
FDCAN_TXBC(canport) = (FDCAN_TXBC(canport)
|
||||
& ~(
|
||||
(FDCAN_TXBC_TFQS_MASK << FDCAN_TXBC_TFQS_SHIFT)
|
||||
| (FDCAN_TXBC_TBSA_MASK << FDCAN_TXBC_TBSA_SHIFT)
|
||||
))
|
||||
| (tbs << FDCAN_TXBC_TFQS_SHIFT)
|
||||
| (tbsa & (FDCAN_TXBC_TBSA_MASK << FDCAN_TXBC_TBSA_SHIFT));
|
||||
}
|
||||
|
||||
/** Initialize size of data fields in reception buffers.
|
||||
*
|
||||
* Configures maximum size of message payload, which can be stored in different
|
||||
* reception buffers. Each buffer can have maximum payload size configured independently.
|
||||
* Buffers can only be configured to sizes which are valid sizes of FDCAN payload. Sizes smaller
|
||||
* than 8 are automatically padded to 8.
|
||||
* @note If you change these values, then content of reception buffers is invalidated. You may
|
||||
* also want to recalculate base addresses of objects in message RAM as their size might have
|
||||
* changed.
|
||||
* @param [in] canport FDCAN block base address. See @ref fdcan_block.
|
||||
* @param [in] rxbuf maximum storable payload size of dedicated RX buffer
|
||||
* @param [in] rxfifo0 maximum storable payload size of RX FIFO 0
|
||||
* @param [in] rxfifo1 maximum storable payload size of RX FIFO 1
|
||||
* @returns operation return status. See @ref fdcan_error.
|
||||
*/
|
||||
int fdcan_set_rx_element_size(uint32_t canport, uint8_t rxbuf, uint8_t rxfifo0, uint8_t rxfifo1)
|
||||
{
|
||||
unsigned rxbufdlc = fdcan_length_to_dlc(rxbuf);
|
||||
unsigned rxfifo0dlc = fdcan_length_to_dlc(rxfifo0);
|
||||
unsigned rxfifo1dlc = fdcan_length_to_dlc(rxfifo1);
|
||||
|
||||
if (rxbufdlc == 0xFF || rxfifo0dlc == 0xFF || rxfifo1dlc == 0xFF) {
|
||||
return FDCAN_E_INVALID;
|
||||
}
|
||||
|
||||
/* RXESC fields use format of FDCAN DLC, albeit using only
|
||||
* three LSBs. DLC < 8 is always allocated as 8 bytes and is always
|
||||
* encoded as 0.
|
||||
*/
|
||||
if (rxbufdlc <= 8) {
|
||||
rxbufdlc = 0;
|
||||
} else {
|
||||
rxbufdlc &= ~(1 << 4);
|
||||
}
|
||||
|
||||
if (rxfifo0dlc <= 8) {
|
||||
rxfifo0dlc = 0;
|
||||
} else {
|
||||
rxfifo0dlc &= ~(1 << 4);
|
||||
}
|
||||
|
||||
if (rxfifo1dlc <= 8) {
|
||||
rxfifo1dlc = 0;
|
||||
} else {
|
||||
rxfifo1dlc &= ~(1 << 4);
|
||||
}
|
||||
|
||||
FDCAN_RXESC(canport) = rxbufdlc << FDCAN_RXESC_RBDS_SHIFT
|
||||
| rxfifo1dlc << FDCAN_RXESC_F1DS_SHIFT
|
||||
| rxfifo0dlc << FDCAN_RXESC_F0DS_SHIFT;
|
||||
|
||||
return FDCAN_E_OK;
|
||||
}
|
||||
|
||||
/** Initialize size of data fields in transmit buffers.
|
||||
*
|
||||
* Configures maximum size of message payload, which can be stored either in dedicated
|
||||
* transmit buffer or into transmit queue/FIFO. One size is applied both to transmit buffer
|
||||
* and transmit queue / FIFO. Buffers can only be configured to sizes which are valid sizes
|
||||
* of FDCAN payload. Sizes smaller than 8 are automatically padded to 8 bytes.
|
||||
* @note If you change these values, then content of transmission buffers is invalidated. You may
|
||||
* also want to recalculate base addresses of objects in message RAM as their size might have
|
||||
* changed.
|
||||
* @param [in] canport FDCAN block base address. See @ref fdcan_block.
|
||||
* @param [in] txbuf maximum storable payload size of TX buffer / FIFO / queue
|
||||
* @returns operation return status. See @ref fdcan_error.
|
||||
*/
|
||||
int fdcan_set_tx_element_size(uint32_t canport, uint8_t txbuf)
|
||||
{
|
||||
unsigned txbufdlc = fdcan_length_to_dlc(txbuf);
|
||||
|
||||
if (txbufdlc == 0xFF) {
|
||||
return FDCAN_E_INVALID;
|
||||
}
|
||||
|
||||
if (txbufdlc <= 8) {
|
||||
txbufdlc = 0;
|
||||
} else {
|
||||
txbufdlc &= ~(1 << 4);
|
||||
}
|
||||
|
||||
FDCAN_TXESC(canport) = txbufdlc << FDCAN_TXESC_TBDS_SHIFT;
|
||||
|
||||
return FDCAN_E_OK;
|
||||
}
|
||||
|
||||
/** Configure amount of filters and initialize filtering block.
|
||||
*
|
||||
* This function allows to configure global amount of filters present.
|
||||
* FDCAN block will only ever check as many filters as this function configures.
|
||||
* Function will also clear all filter blocks to zero values. This function
|
||||
* can be only called after @ref fdcan_init has already been called and
|
||||
* @ref fdcan_start has not been called yet as registers holding filter
|
||||
* count are write-protected unless FDCAN block is in INIT mode. It is possible
|
||||
* to reconfigure filters (@ref fdcan_set_std_filter and @ref fdcan_set_ext_filter)
|
||||
* after FDCAN block has already been started.
|
||||
*
|
||||
* This function is provided for source level compatibility with code written for
|
||||
* STM32G4. As an alternative, you can use @ref fdcan_init_std_filter_ram() and
|
||||
* @ref fdcan_init_ext_filter_ram() to have more control over filtering configuration.
|
||||
* Note that if you do so, your code won't be compatible with STM32G4 controllers.
|
||||
*
|
||||
* @param [in] canport FDCAN block base address. See @ref fdcan_block.
|
||||
* @param [in] std_filt requested amount of standard ID filter rules (0-28)
|
||||
* @param [in] ext_filt requested amount of extended ID filter rules (0-8)
|
||||
*/
|
||||
void fdcan_init_filter(uint32_t canport, uint8_t std_filt, uint8_t ext_filt)
|
||||
{
|
||||
struct fdcan_standard_filter *lfssa;
|
||||
struct fdcan_extended_filter *lfesa;
|
||||
|
||||
int can_id = FDCAN_BLOCK_ID(canport);
|
||||
|
||||
int lfsofs = 0;
|
||||
int lfeofs = 0;
|
||||
int lfssize = std_filt * sizeof(struct fdcan_standard_filter);
|
||||
int lfesize = ext_filt * sizeof(struct fdcan_extended_filter);
|
||||
|
||||
if (can_id == 0) {
|
||||
lfsofs = 0;
|
||||
lfeofs = lfssize;
|
||||
} else {
|
||||
lfsofs = CAN_MSG_BASE + CAN_MSG_SIZE - lfssize;
|
||||
lfeofs = lfsofs - lfesize;
|
||||
}
|
||||
|
||||
fdcan_init_std_filter_ram(canport, lfsofs, 28);
|
||||
fdcan_init_ext_filter_ram(canport, lfeofs, 8);
|
||||
|
||||
lfssa = fdcan_get_flssa_addr(canport);
|
||||
lfesa = fdcan_get_flesa_addr(canport);
|
||||
|
||||
/* Only perform initialization of message RAM if there are
|
||||
* any filters required
|
||||
*/
|
||||
if (std_filt > 0) {
|
||||
for (int q = 0; q < 28; ++q) {
|
||||
lfssa[q].type_id1_conf_id2 = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (ext_filt > 0) {
|
||||
for (int q = 0; q < 8; ++q) {
|
||||
lfesa[q].conf_id1 = 0;
|
||||
lfesa[q].type_id2 = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Enable FDCAN operation after FDCAN block has been set up.
|
||||
*
|
||||
* This function will disable FDCAN configuration effectively
|
||||
* allowing FDCAN to sync up with the bus. After calling this function
|
||||
* it is not possible to reconfigure amount of filter rules, yet
|
||||
* it is possible to configure rules themselves. FDCAN block operation
|
||||
* state can be checked using @ref fdcan_get_init_state.
|
||||
*
|
||||
* @param [in] canport FDCAN block base address. See @ref fdcan_block.
|
||||
* @param [in] timeout Amount of empty busy loops, which routine should wait for FDCAN
|
||||
* confirming that it left INIT mode. If set to 0, function will return
|
||||
* immediately.
|
||||
* @returns Operation error status. See @ref fdcan_error.
|
||||
* @note If this function returns with timeout, it usually means that
|
||||
* FDCAN_clk is not set up properly.
|
||||
*/
|
||||
int fdcan_start(uint32_t canport, uint32_t timeout)
|
||||
{
|
||||
/* This block detects obviously invalid configuration of
|
||||
* RX FIFOs and TX buffers. Such situation may happen
|
||||
* if code originally targeted for STM32G4 is compiled for
|
||||
* STM32H7. This code is not aware of H7 abilities and
|
||||
* leaves this stuff unconfigured. We pick up here and
|
||||
* assume, that the code wants the FDCAN to behave as if
|
||||
* it was STM32G4. Therefore we will configure two three entry
|
||||
* long RX FIFOs, three entry long TX event buffer and three
|
||||
* entry long TX FIFO/queue here.
|
||||
*/
|
||||
if (FDCAN_RXFIFO_OFFSET(canport, 0) == 0
|
||||
&& FDCAN_RXFIFO_OFFSET(canport, 1) == 0
|
||||
&& FDCAN_TXBUF_OFFSET(canport) == 0
|
||||
&& FDCAN_TXEVT_OFFSET(canport) == 0
|
||||
&& FDCAN_RXESC(canport) == 0
|
||||
&& FDCAN_TXESC(canport) == 0
|
||||
) {
|
||||
/* These sizes are fixed based on what G4 contains. */
|
||||
int fifo0_size = 3 * sizeof(struct fdcan_rx_fifo_element);
|
||||
int fifo1_size = fifo0_size;
|
||||
int txevt_size = 3 * sizeof(struct fdcan_tx_event_element);
|
||||
int txbuf_size = 3 * sizeof(struct fdcan_tx_buffer_element);
|
||||
|
||||
fdcan_set_rx_element_size(canport, 0, 64, 64);
|
||||
fdcan_set_tx_element_size(canport, 64);
|
||||
|
||||
/* At this point we simply assume that FLSSA and FLESA were
|
||||
* set up by calling fdcan_init_filter(). It they weren't,
|
||||
* there just won't be allocated any space for them.
|
||||
* That's not a problem as after fdcan_start returns, it is
|
||||
* not possible to configure filter amount anymore.
|
||||
*
|
||||
* Default approach is to configure CAN1 to occupy bottom
|
||||
* of message RAM and CAN1 to occupy top of message RAM keeping
|
||||
* large unused space in between. This ensures that even if someone
|
||||
* starts playing with CAN1, "implicit" configuration of CAN2 done
|
||||
* here won't break things magically.
|
||||
*/
|
||||
if (FDCAN_BLOCK_ID(canport) == 0) {
|
||||
/* CAN1 will use bottom-up layout with
|
||||
* FLSSA < FLESA < F0SA < F1SA < TXESA < TXBSA
|
||||
* Rx buffer is not used.
|
||||
*/
|
||||
fdcan_init_fifo_ram(canport, 0,
|
||||
FDCAN_LFESA_OFFSET(canport)
|
||||
+ FDCAN_LSE_COUNT(canport) * sizeof(struct fdcan_extended_filter),
|
||||
3);
|
||||
fdcan_init_fifo_ram(canport, 1,
|
||||
FDCAN_RXFIFO_OFFSET(canport, 0) + fifo0_size, 3);
|
||||
fdcan_init_tx_event_ram(canport,
|
||||
FDCAN_RXFIFO_OFFSET(canport, 1) + fifo1_size, 3);
|
||||
fdcan_init_tx_buffer_ram(canport,
|
||||
FDCAN_TXEVT_OFFSET(canport) + txevt_size, 3);
|
||||
} else {
|
||||
/* LFESA might be uninitialized. In such case
|
||||
* we forge it's address at the end of MSG RAM
|
||||
*/
|
||||
int lfesa_offs = FDCAN_LFESA_OFFSET(canport);
|
||||
if (lfesa_offs == 0) {
|
||||
lfesa_offs = CAN_MSG_SIZE;
|
||||
}
|
||||
/* CAN2 will use top-down layout with
|
||||
* TXBSA < TXESA < F1SA < F0SA < FLESA < FLSSA
|
||||
* Rx buffer is not used.
|
||||
* This arrangement should ensure that even if
|
||||
* CAN1 was configured manually, CAN2 default
|
||||
* configuration should not break CAN1.
|
||||
*/
|
||||
fdcan_init_fifo_ram(canport, 0, lfesa_offs - fifo0_size, 3);
|
||||
fdcan_init_fifo_ram(canport, 1,
|
||||
FDCAN_RXFIFO_OFFSET(canport, 0) - fifo1_size, 3);
|
||||
fdcan_init_tx_event_ram(canport,
|
||||
FDCAN_RXFIFO_OFFSET(canport, 1) - txevt_size, 3);
|
||||
fdcan_init_tx_buffer_ram(canport,
|
||||
FDCAN_TXEVT_OFFSET(canport) - txbuf_size, 3);
|
||||
}
|
||||
|
||||
}
|
||||
/* Error here usually means, that FDCAN_clk is not set up
|
||||
* correctly, or at all. This usually can't be seen above
|
||||
* when INIT is set to 1, because default value for INIT is
|
||||
* 1 as long as one has FDCAN_pclk configured properly.
|
||||
**/
|
||||
if (fdcan_cccr_init_cfg(canport, false, timeout) != 0) {
|
||||
return FDCAN_E_TIMEOUT;
|
||||
}
|
||||
|
||||
return FDCAN_E_OK;
|
||||
}
|
||||
|
||||
/** Configure FDCAN FIFO lock mode
|
||||
*
|
||||
* This function allows to choose between locked and overewrite mode of FIFOs. In locked mode,
|
||||
* whenever FIFO is full and new frame arrives, which would normally been stored into given
|
||||
* FIFO, then frame is dropped. If overwrite mode is active, then most recent message in FIFO
|
||||
* is rewritten by frame just received.
|
||||
* @param [in] canport FDCAN block base address. See @ref fdcan_block.
|
||||
* @param [in] locked true activates locked mode, false activates overwrite mode
|
||||
*/
|
||||
void fdcan_set_fifo_locked_mode(uint32_t canport, bool locked)
|
||||
{
|
||||
if (locked) {
|
||||
FDCAN_RXF0C(canport) &= ~(FDCAN_RXF0C_F0OM);
|
||||
FDCAN_RXF1C(canport) &= ~(FDCAN_RXF1C_F1OM);
|
||||
} else {
|
||||
FDCAN_RXF0C(canport) |= FDCAN_RXF0C_F0OM;
|
||||
FDCAN_RXF1C(canport) |= FDCAN_RXF1C_F1OM;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user