diff options
Diffstat (limited to 'bsps/arm/atsam/contrib/libraries/libchip/source/mcan.c')
-rw-r--r-- | bsps/arm/atsam/contrib/libraries/libchip/source/mcan.c | 1175 |
1 files changed, 1175 insertions, 0 deletions
diff --git a/bsps/arm/atsam/contrib/libraries/libchip/source/mcan.c b/bsps/arm/atsam/contrib/libraries/libchip/source/mcan.c new file mode 100644 index 0000000000..e91f73e871 --- /dev/null +++ b/bsps/arm/atsam/contrib/libraries/libchip/source/mcan.c @@ -0,0 +1,1175 @@ +/* ---------------------------------------------------------------------------- */ +/* Atmel Microcontroller Software Support */ +/* SAM Software Package License */ +/* ---------------------------------------------------------------------------- */ +/* Copyright (c) 2015, Atmel Corporation */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following condition is met: */ +/* */ +/* - Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the disclaimer below. */ +/* */ +/* Atmel's name may not be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR */ +/* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE */ +/* DISCLAIMED. IN NO EVENT SHALL ATMEL 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. */ +/* ---------------------------------------------------------------------------- */ + +/** \file + * Implements functions for Controller Area Network (CAN) + * peripheral operations. + */ +/** \addtogroup can_module + *@{*/ + + +/*---------------------------------------------------------------------------- + * Headers + *----------------------------------------------------------------------------*/ +#ifndef __rtems__ +#include "board.h" +#endif /* __rtems__ */ +#include "chip.h" +#include "mcan_config.h" +#include <assert.h> +/*--------------------------------------------------------------------------- + * Definitions + *---------------------------------------------------------------------------*/ +#define MAILBOX_ADDRESS(address) (0xFFFC & (address)) + +#define CAN_CLK_FREQ_HZ MCAN_PROG_CLK_FREQ_HZ + +#define MCAN0_TSEG1 (MCAN0_PROP_SEG + MCAN0_PHASE_SEG1) +#define MCAN0_TSEG2 (MCAN0_PHASE_SEG2) +#define MCAN0_BRP ((uint32_t) (((float) CAN_CLK_FREQ_HZ / \ + ((float)(MCAN0_TSEG1 + MCAN0_TSEG2 + 3) *\ + (float) MCAN0_BIT_RATE_BPS)) - 1)) +#define MCAN0_SJW (MCAN0_SYNC_JUMP - 1) +#define MCAN0_FTSEG1 (MCAN0_FAST_PROP_SEG + MCAN0_FAST_PHASE_SEG1) +#define MCAN0_FTSEG2 (MCAN0_FAST_PHASE_SEG2) +#define MCAN0_FBRP ((uint32_t) (((float) CAN_CLK_FREQ_HZ / \ + ((float)(MCAN0_FTSEG1 + MCAN0_FTSEG2 + 3) * \ + (float) MCAN0_FAST_BIT_RATE_BPS)) - 1)) +#define MCAN0_FSJW (MCAN0_FAST_SYNC_JUMP - 1) + +#define MCAN0_STD_FLTS_WRDS (MCAN0_NMBR_STD_FLTS) +/* 128 max filters */ +#define MCAN0_EXT_FLTS_WRDS (MCAN0_NMBR_EXT_FLTS * 2) +/* 64 max filters */ +#define MCAN0_RX_FIFO0_WRDS (MCAN0_NMBR_RX_FIFO0_ELMTS * \ + ((MCAN0_RX_FIFO0_ELMT_SZ/4) + 2)) +/* 64 elements max */ +#define MCAN0_RX_FIFO1_WRDS (MCAN0_NMBR_RX_FIFO1_ELMTS *\ + ((MCAN0_RX_FIFO1_ELMT_SZ/4) + 2)) +/* 64 elements max */ +#define MCAN0_RX_DED_BUFS_WRDS (MCAN0_NMBR_RX_DED_BUF_ELMTS * \ + ((MCAN0_RX_BUF_ELMT_SZ/4) + 2)) +/* 64 elements max */ +#define MCAN0_TX_EVT_FIFO_WRDS (MCAN0_NMBR_TX_EVT_FIFO_ELMTS * 2) +/* 32 elements max */ +#define MCAN0_TX_DED_BUF_WRDS (MCAN0_NMBR_TX_DED_BUF_ELMTS * \ + ((MCAN0_TX_BUF_ELMT_SZ/4) + 2)) +/* 32 elements max */ +#define MCAN0_TX_FIFO_Q_WRDS (MCAN0_NMBR_TX_FIFO_Q_ELMTS *\ + ((MCAN0_TX_BUF_ELMT_SZ/4) + 2)) +/* 32 elements max */ + +#define MCAN1_TSEG1 (MCAN1_PROP_SEG + MCAN1_PHASE_SEG1) +#define MCAN1_TSEG2 (MCAN1_PHASE_SEG2) +#define MCAN1_BRP ((uint32_t) (((float) CAN_CLK_FREQ_HZ / \ + ((float)(MCAN1_TSEG1 + MCAN1_TSEG2 + 3) *\ + (float) MCAN1_BIT_RATE_BPS)) - 1)) +#define MCAN1_SJW (MCAN1_SYNC_JUMP - 1) +#define MCAN1_FTSEG1 (MCAN1_FAST_PROP_SEG + MCAN1_FAST_PHASE_SEG1) +#define MCAN1_FTSEG2 (MCAN1_FAST_PHASE_SEG2) +#define MCAN1_FBRP ((uint32_t) (((float) CAN_CLK_FREQ_HZ /\ + ((float)(MCAN1_FTSEG1 + MCAN1_FTSEG2 + 3) *\ + (float) MCAN1_FAST_BIT_RATE_BPS)) - 1)) +#define MCAN1_FSJW (MCAN1_FAST_SYNC_JUMP - 1) + +#define MCAN1_STD_FLTS_WRDS (MCAN1_NMBR_STD_FLTS) +/* 128 max filters */ +#define MCAN1_EXT_FLTS_WRDS (MCAN1_NMBR_EXT_FLTS * 2) +/* 64 max filters */ +#define MCAN1_RX_FIFO0_WRDS (MCAN1_NMBR_RX_FIFO0_ELMTS * \ + ((MCAN1_RX_FIFO0_ELMT_SZ/4) + 2)) +/* 64 elements max */ +#define MCAN1_RX_FIFO1_WRDS (MCAN1_NMBR_RX_FIFO1_ELMTS *\ + ((MCAN1_RX_FIFO1_ELMT_SZ/4) + 2)) +/* 64 elements max */ +#define MCAN1_RX_DED_BUFS_WRDS (MCAN1_NMBR_RX_DED_BUF_ELMTS * \ + ((MCAN1_RX_BUF_ELMT_SZ/4) + 2)) +/* 64 elements max */ +#define MCAN1_TX_EVT_FIFO_WRDS (MCAN1_NMBR_TX_EVT_FIFO_ELMTS * 2) +/* 32 elements max */ +#define MCAN1_TX_DED_BUF_WRDS (MCAN1_NMBR_TX_DED_BUF_ELMTS * \ + ((MCAN1_TX_BUF_ELMT_SZ/4) + 2)) +/* 32 elements max */ +#define MCAN1_TX_FIFO_Q_WRDS (MCAN1_NMBR_TX_FIFO_Q_ELMTS * \ + ((MCAN1_TX_BUF_ELMT_SZ/4) + 2)) +/* 32 elements max */ + +/* validate CAN0 entries */ +#if (MCAN0_TSEG1 > 63) + #error "Invalid CAN0 TSEG1" +#endif +#if (MCAN0_TSEG2 > 15) + #error "Invalid CAN0 TSEG2" +#endif +#if (MCAN0_SJW > 15) + #error "Invalid CAN0 SJW" +#endif +#if (MCAN0_FTSEG1 > 15) + #error "Invalid CAN0 FTSEG1" +#endif +#if (MCAN0_FTSEG2 > 7) + #error "Invalid CAN0 FTSEG2" +#endif +#if (MCAN0_FSJW > 3) + #error "Invalid CAN0 FSJW" +#endif + +#if (MCAN0_NMBR_STD_FLTS > 128) + #error "Invalid CAN0 # of Standard Filters" +#endif +#if (MCAN0_NMBR_EXT_FLTS > 64) + #error "Invalid CAN0 # of Extended Filters" +#endif +#if (MCAN0_NMBR_RX_FIFO0_ELMTS > 64) + #error "Invalid CAN0 # RX FIFO 0 ELEMENTS" +#endif +#if (MCAN0_NMBR_RX_FIFO1_ELMTS > 64) + #error "Invalid CAN0 # RX FIFO 0 ELEMENTS" +#endif +#if (MCAN0_NMBR_RX_DED_BUF_ELMTS > 64) + #error "Invalid CAN0 # RX BUFFER ELEMENTS" +#endif +#if (MCAN0_NMBR_TX_EVT_FIFO_ELMTS > 32) + #error "Invalid CAN0 # TX EVENT FIFO ELEMENTS" +#endif +#if ((MCAN0_NMBR_TX_DED_BUF_ELMTS + MCAN0_NMBR_TX_FIFO_Q_ELMTS) > 32) + #error "Invalid CAN0 # TX BUFFER ELEMENTS" +#endif + +#if (8 == MCAN0_RX_FIFO0_ELMT_SZ) + #define MCAN0_RX_FIFO0_DATA_SIZE (0u) +#elif (12 == MCAN0_RX_FIFO0_ELMT_SZ) + #define MCAN0_RX_FIFO0_DATA_SIZE (1u) +#elif (16 == MCAN0_RX_FIFO0_ELMT_SZ) + #define MCAN0_RX_FIFO0_DATA_SIZE (2u) +#elif (20 == MCAN0_RX_FIFO0_ELMT_SZ) + #define MCAN0_RX_FIFO0_DATA_SIZE (3u) +#elif (24 == MCAN0_RX_FIFO0_ELMT_SZ) + #define MCAN0_RX_FIFO0_DATA_SIZE (4u) +#elif (32 == MCAN0_RX_FIFO0_ELMT_SZ) + #define MCAN0_RX_FIFO0_DATA_SIZE (5u) +#elif (48 == MCAN0_RX_FIFO0_ELMT_SZ) + #define MCAN0_RX_FIFO0_DATA_SIZE (6u) +#elif (64 == MCAN0_RX_FIFO0_ELMT_SZ) + #define MCAN0_RX_FIFO0_DATA_SIZE (7u) +#else + #error "Invalid CAN0 RX FIFO0 ELEMENT SIZE" +#endif + +#if (8 == MCAN0_RX_FIFO1_ELMT_SZ) + #define MCAN0_RX_FIFO1_DATA_SIZE (0u) +#elif (12 == MCAN0_RX_FIFO1_ELMT_SZ) + #define MCAN0_RX_FIFO1_DATA_SIZE (1u) +#elif (16 == MCAN0_RX_FIFO1_ELMT_SZ) + #define MCAN0_RX_FIFO1_DATA_SIZE (2u) +#elif (20 == MCAN0_RX_FIFO1_ELMT_SZ) + #define MCAN0_RX_FIFO1_DATA_SIZE (3u) +#elif (24 == MCAN0_RX_FIFO1_ELMT_SZ) + #define MCAN0_RX_FIFO1_DATA_SIZE (4u) +#elif (32 == MCAN0_RX_FIFO1_ELMT_SZ) + #define MCAN0_RX_FIFO1_DATA_SIZE (5u) +#elif (48 == MCAN0_RX_FIFO1_ELMT_SZ) + #define MCAN0_RX_FIFO1_DATA_SIZE (6u) +#elif (64 == MCAN0_RX_FIFO1_ELMT_SZ) + #define MCAN0_RX_FIFO1_DATA_SIZE (7u) +#else + #error "Invalid CAN0 RX FIFO1 ELEMENT SIZE" +#endif + +#if (8 == MCAN0_RX_BUF_ELMT_SZ) + #define MCAN0_RX_BUF_DATA_SIZE (0u) +#elif (12 == MCAN0_RX_BUF_ELMT_SZ) + #define MCAN0_RX_BUF_DATA_SIZE (1u) +#elif (16 == MCAN0_RX_BUF_ELMT_SZ) + #define MCAN0_RX_BUF_DATA_SIZE (2u) +#elif (20 == MCAN0_RX_BUF_ELMT_SZ) + #define MCAN0_RX_BUF_DATA_SIZE (3u) +#elif (24 == MCAN0_RX_BUF_ELMT_SZ) + #define MCAN0_RX_BUF_DATA_SIZE (4u) +#elif (32 == MCAN0_RX_BUF_ELMT_SZ) + #define MCAN0_RX_BUF_DATA_SIZE (5u) +#elif (48 == MCAN0_RX_BUF_ELMT_SZ) + #define MCAN0_RX_BUF_DATA_SIZE (6u) +#elif (64 == MCAN0_RX_BUF_ELMT_SZ) + #define MCAN0_RX_BUF_DATA_SIZE (7u) +#else + #error "Invalid CAN0 RX BUFFER ELEMENT SIZE" +#endif + +#if (8 == MCAN0_TX_BUF_ELMT_SZ) + #define MCAN0_TX_BUF_DATA_SIZE (0u) +#elif (12 == MCAN0_TX_BUF_ELMT_SZ) + #define MCAN0_TX_BUF_DATA_SIZE (1u) +#elif (16 == MCAN0_TX_BUF_ELMT_SZ) + #define MCAN0_TX_BUF_DATA_SIZE (2u) +#elif (20 == MCAN0_TX_BUF_ELMT_SZ) + #define MCAN0_TX_BUF_DATA_SIZE (3u) +#elif (24 == MCAN0_TX_BUF_ELMT_SZ) + #define MCAN0_TX_BUF_DATA_SIZE (4u) +#elif (32 == MCAN0_TX_BUF_ELMT_SZ) + #define MCAN0_TX_BUF_DATA_SIZE (5u) +#elif (48 == MCAN0_TX_BUF_ELMT_SZ) + #define MCAN0_TX_BUF_DATA_SIZE (6u) +#elif (64 == MCAN0_TX_BUF_ELMT_SZ) + #define MCAN0_TX_BUF_DATA_SIZE (7u) +#else + #error "Invalid CAN0 TX BUFFER ELEMENT SIZE" +#endif + +/* validate CAN1 entries */ +#if (MCAN1_TSEG1 > 63) + #error "Invalid CAN1 TSEG1" +#endif +#if (MCAN1_TSEG2 > 15) + #error "Invalid CAN1 TSEG2" +#endif +#if (MCAN1_SJW > 15) + #error "Invalid CAN1 SJW" +#endif +#if (MCAN1_FTSEG1 > 15) + #error "Invalid CAN1 FTSEG1" +#endif +#if (MCAN1_FTSEG2 > 7) + #error "Invalid CAN1 FTSEG2" +#endif +#if (MCAN1_FSJW > 3) + #error "Invalid CAN1 FSJW" +#endif + +#if (MCAN1_NMBR_STD_FLTS > 128) + #error "Invalid CAN1 # of Standard Filters" +#endif +#if (MCAN1_NMBR_EXT_FLTS > 64) + #error "Invalid CAN1 # of Extended Filters" +#endif +#if (MCAN1_NMBR_RX_FIFO0_ELMTS > 64) + #error "Invalid CAN1 # RX FIFO 0 ELEMENTS" +#endif +#if (MCAN1_NMBR_RX_FIFO1_ELMTS > 64) + #error "Invalid CAN1 # RX FIFO 0 ELEMENTS" +#endif +#if (MCAN1_NMBR_RX_DED_BUF_ELMTS > 64) + #error "Invalid CAN1 # RX BUFFER ELEMENTS" +#endif +#if (MCAN1_NMBR_TX_EVT_FIFO_ELMTS > 32) + #error "Invalid CAN1 # TX EVENT FIFO ELEMENTS" +#endif +#if ((MCAN1_NMBR_TX_DED_BUF_ELMTS + MCAN1_NMBR_TX_FIFO_Q_ELMTS) > 32) + #error "Invalid CAN1 # TX BUFFER ELEMENTS" +#endif + +#if (8 == MCAN1_RX_FIFO0_ELMT_SZ) + #define MCAN1_RX_FIFO0_DATA_SIZE (0u) +#elif (12 == MCAN1_RX_FIFO0_ELMT_SZ) + #define MCAN1_RX_FIFO0_DATA_SIZE (1u) +#elif (16 == MCAN1_RX_FIFO0_ELMT_SZ) + #define MCAN1_RX_FIFO0_DATA_SIZE (2u) +#elif (20 == MCAN1_RX_FIFO0_ELMT_SZ) + #define MCAN1_RX_FIFO0_DATA_SIZE (3u) +#elif (24 == MCAN1_RX_FIFO0_ELMT_SZ) + #define MCAN1_RX_FIFO0_DATA_SIZE (4u) +#elif (32 == MCAN1_RX_FIFO0_ELMT_SZ) + #define MCAN1_RX_FIFO0_DATA_SIZE (5u) +#elif (48 == MCAN1_RX_FIFO0_ELMT_SZ) + #define MCAN1_RX_FIFO0_DATA_SIZE (6u) +#elif (64 == MCAN1_RX_FIFO0_ELMT_SZ) + #define MCAN1_RX_FIFO0_DATA_SIZE (7u) +#else + #error "Invalid CAN1 RX FIFO0 ELEMENT SIZE" +#endif + +#if (8 == MCAN1_RX_FIFO1_ELMT_SZ) + #define MCAN1_RX_FIFO1_DATA_SIZE (0u) +#elif (12 == MCAN1_RX_FIFO1_ELMT_SZ) + #define MCAN1_RX_FIFO1_DATA_SIZE (1u) +#elif (16 == MCAN1_RX_FIFO1_ELMT_SZ) + #define MCAN1_RX_FIFO1_DATA_SIZE (2u) +#elif (20 == MCAN1_RX_FIFO1_ELMT_SZ) + #define MCAN1_RX_FIFO1_DATA_SIZE (3u) +#elif (24 == MCAN1_RX_FIFO1_ELMT_SZ) + #define MCAN1_RX_FIFO1_DATA_SIZE (4u) +#elif (32 == MCAN1_RX_FIFO1_ELMT_SZ) + #define MCAN1_RX_FIFO1_DATA_SIZE (5u) +#elif (48 == MCAN1_RX_FIFO1_ELMT_SZ) + #define MCAN1_RX_FIFO1_DATA_SIZE (6u) +#elif (64 == MCAN1_RX_FIFO1_ELMT_SZ) + #define MCAN1_RX_FIFO1_DATA_SIZE (7u) +#else + #error "Invalid CAN1 RX FIFO1 ELEMENT SIZE" +#endif + +#if (8 == MCAN1_RX_BUF_ELMT_SZ) + #define MCAN1_RX_BUF_DATA_SIZE (0u) +#elif (12 == MCAN1_RX_BUF_ELMT_SZ) + #define MCAN1_RX_BUF_DATA_SIZE (1u) +#elif (16 == MCAN1_RX_BUF_ELMT_SZ) + #define MCAN1_RX_BUF_DATA_SIZE (2u) +#elif (20 == MCAN1_RX_BUF_ELMT_SZ) + #define MCAN1_RX_BUF_DATA_SIZE (3u) +#elif (24 == MCAN1_RX_BUF_ELMT_SZ) + #define MCAN1_RX_BUF_DATA_SIZE (4u) +#elif (32 == MCAN1_RX_BUF_ELMT_SZ) + #define MCAN1_RX_BUF_DATA_SIZE (5u) +#elif (48 == MCAN1_RX_BUF_ELMT_SZ) + #define MCAN1_RX_BUF_DATA_SIZE (6u) +#elif (64 == MCAN1_RX_BUF_ELMT_SZ) + #define MCAN1_RX_BUF_DATA_SIZE (7u) +#else + #error "Invalid CAN1 RX BUFFER ELEMENT SIZE" +#endif + +#if (8 == MCAN1_TX_BUF_ELMT_SZ) + #define MCAN1_TX_BUF_DATA_SIZE (0u) +#elif (12 == MCAN1_TX_BUF_ELMT_SZ) + #define MCAN1_TX_BUF_DATA_SIZE (1u) +#elif (16 == MCAN1_TX_BUF_ELMT_SZ) + #define MCAN1_TX_BUF_DATA_SIZE (2u) +#elif (20 == MCAN1_TX_BUF_ELMT_SZ) + #define MCAN1_TX_BUF_DATA_SIZE (3u) +#elif (24 == MCAN1_TX_BUF_ELMT_SZ) + #define MCAN1_TX_BUF_DATA_SIZE (4u) +#elif (32 == MCAN1_TX_BUF_ELMT_SZ) + #define MCAN1_TX_BUF_DATA_SIZE (5u) +#elif (48 == MCAN1_TX_BUF_ELMT_SZ) + #define MCAN1_TX_BUF_DATA_SIZE (6u) +#elif (64 == MCAN1_TX_BUF_ELMT_SZ) + #define MCAN1_TX_BUF_DATA_SIZE (7u) +#else + #error "Invalid CAN1 TX BUFFER ELEMENT SIZE" +#endif + +#define CAN_11_BIT_ID_MASK (0x7FF) +#define CAN_29_BIT_ID_MASK (0x1FFFFFFF) +#define ELMT_SIZE_MASK (0x1F) +/* max element size is 18 words, fits in 5 bits */ + +#define BUFFER_XTD_MASK (0x40000000) +#define BUFFER_EXT_ID_MASK (0x1FFFFFFF) +#define BUFFER_STD_ID_MASK (0x1FFC0000) +#define BUFFER_DLC_MASK (0x000F0000) +#define BUFFER_RXTS_MASK (0x0000FFFF) + +#define STD_FILT_SFT_MASK (3U << 30) +#define STD_FILT_SFT_RANGE (0U << 30) +#define STD_FILT_SFT_DUAL (1U << 30) +#define STD_FILT_SFT_CLASSIC (2U << 30) +#define STD_FILT_SFEC_MASK (7U << 27) +#define STD_FILT_SFEC_DISABLE (0U << 27) +#define STD_FILT_SFEC_FIFO0 (1U << 27) +#define STD_FILT_SFEC_FIFO1 (2U << 27) +#define STD_FILT_SFEC_REJECT (3U << 27) +#define STD_FILT_SFEC_PRIORITY (4U << 27) +#define STD_FILT_SFEC_PRIORITY_FIFO0 (5U << 27) +#define STD_FILT_SFEC_PRIORITY_FIFO1 (6U << 27) +#define STD_FILT_SFEC_BUFFER (7U << 27) +#define STD_FILT_SFID1_MASK (0x03FFU << 16) +#define STD_FILT_SFID2_MASK (0x3FFU << 0) +#define STD_FILT_SFID2_RX_BUFFER (0U << 9) +#define STD_FILT_SFID2_DEBUG_A (1U << 9) +#define STD_FILT_SFID2_DEBUG_B (2U << 9) +#define STD_FILT_SFID2_DEBUG_C (3U << 9) +#define STD_FILT_SFID2_BUFFER(nmbr) (nmbr & 0x3F) + +#define EXT_FILT_EFEC_MASK (7U << 29) +#define EXT_FILT_EFEC_DISABLE (0U << 29) +#define EXT_FILT_EFEC_FIFO0 (1U << 29) +#define EXT_FILT_EFEC_FIFO1 (2U << 29) +#define EXT_FILT_EFEC_REJECT (3U << 29) +#define EXT_FILT_EFEC_PRIORITY (4U << 29) +#define EXT_FILT_EFEC_PRIORITY_FIFO0 (5U << 29) +#define EXT_FILT_EFEC_PRIORITY_FIFO1 (6U << 29) +#define EXT_FILT_EFEC_BUFFER (7U << 29) +#define EXT_FILT_EFID1_MASK (0x1FFFFFFF) +#define EXT_FILT_EFT_MASK (3U << 30) +#define EXT_FILT_EFT_RANGE (0U << 30) +#define EXT_FILT_EFT_DUAL (1U << 30) +#define EXT_FILT_EFT_CLASSIC (2U << 30) +#define EXT_FILT_EFT_RANGE_NO_XIDAM (3U << 30) +#define EXT_FILT_EFID2_MASK (0x1FFFFFFF) +#define EXT_FILT_EFID2_RX_BUFFER (0U << 9) +#define EXT_FILT_EFID2_DEBUG_A (1U << 9) +#define EXT_FILT_EFID2_DEBUG_B (2U << 9) +#define EXT_FILT_EFID2_DEBUG_C (3U << 9) +#define EXT_FILT_EFID2_BUFFER(nmbr) (nmbr & 0x3F) + + +/*--------------------------------------------------------------------------- + * Internal variables + *---------------------------------------------------------------------------*/ + +#ifndef __rtems__ +static const Pin pinsMcan0[] = {PIN_MCAN0_TXD, PIN_MCAN0_RXD }; +static const Pin pinsMcan1[] = {PIN_MCAN1_TXD, PIN_MCAN1_RXD }; +#endif /* __rtems__ */ + +static uint32_t can0MsgRam[MCAN0_STD_FLTS_WRDS + + MCAN0_EXT_FLTS_WRDS + + MCAN0_RX_FIFO0_WRDS + + MCAN0_RX_FIFO1_WRDS + + MCAN0_RX_DED_BUFS_WRDS + + MCAN0_TX_EVT_FIFO_WRDS + + MCAN0_TX_DED_BUF_WRDS + + MCAN0_TX_FIFO_Q_WRDS]; + +static uint32_t can1MsgRam[MCAN1_STD_FLTS_WRDS + + MCAN1_EXT_FLTS_WRDS + + MCAN1_RX_FIFO0_WRDS + + MCAN1_RX_FIFO1_WRDS + + MCAN1_RX_DED_BUFS_WRDS + + MCAN1_TX_EVT_FIFO_WRDS + + MCAN1_TX_DED_BUF_WRDS + + MCAN1_TX_FIFO_Q_WRDS]; + +static const uint8_t dlcToMsgLength[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 12, 16, 20, 24, 32, 48, 64 }; + +const MCan_ConfigType mcan0Config = { + MCAN0, + MCAN_BTP_BRP(MCAN0_BRP) | MCAN_BTP_TSEG1(MCAN0_TSEG1) | + MCAN_BTP_TSEG2(MCAN0_TSEG2) | MCAN_BTP_SJW(MCAN0_SJW), + MCAN_FBTP_FBRP(MCAN0_FBRP) | MCAN_FBTP_FTSEG1(MCAN0_FTSEG1) | + MCAN_FBTP_FTSEG2(MCAN0_FTSEG2) | MCAN_FBTP_FSJW(MCAN0_FSJW), + MCAN0_NMBR_STD_FLTS, + MCAN0_NMBR_EXT_FLTS, + MCAN0_NMBR_RX_FIFO0_ELMTS, + MCAN0_NMBR_RX_FIFO1_ELMTS, + MCAN0_NMBR_RX_DED_BUF_ELMTS, + MCAN0_NMBR_TX_EVT_FIFO_ELMTS, + MCAN0_NMBR_TX_DED_BUF_ELMTS, + MCAN0_NMBR_TX_FIFO_Q_ELMTS, + (MCAN0_RX_FIFO0_DATA_SIZE << 29) | ((MCAN0_RX_FIFO0_ELMT_SZ / 4) + 2), + /* element size in WORDS */ + (MCAN0_RX_FIFO1_DATA_SIZE << 29) | ((MCAN0_RX_FIFO1_ELMT_SZ / 4) + 2), + /* element size in WORDS */ + (MCAN0_RX_BUF_DATA_SIZE << 29) | ((MCAN0_RX_BUF_ELMT_SZ / 4) + 2), + /* element size in WORDS */ + (MCAN0_TX_BUF_DATA_SIZE << 29) | ((MCAN0_TX_BUF_ELMT_SZ / 4) + 2), + /* element size in WORDS */ + { + &can0MsgRam[0], + &can0MsgRam[MCAN0_STD_FLTS_WRDS], + &can0MsgRam[MCAN0_STD_FLTS_WRDS + MCAN0_EXT_FLTS_WRDS], + &can0MsgRam[MCAN0_STD_FLTS_WRDS + MCAN0_EXT_FLTS_WRDS + MCAN0_RX_FIFO0_WRDS], + &can0MsgRam[MCAN0_STD_FLTS_WRDS + MCAN0_EXT_FLTS_WRDS + MCAN0_RX_FIFO0_WRDS + + MCAN0_RX_FIFO1_WRDS], + &can0MsgRam[MCAN0_STD_FLTS_WRDS + MCAN0_EXT_FLTS_WRDS + MCAN0_RX_FIFO0_WRDS + + MCAN0_RX_FIFO1_WRDS + MCAN0_RX_DED_BUFS_WRDS], + &can0MsgRam[MCAN0_STD_FLTS_WRDS + MCAN0_EXT_FLTS_WRDS + MCAN0_RX_FIFO0_WRDS + + MCAN0_RX_FIFO1_WRDS + MCAN0_RX_DED_BUFS_WRDS + MCAN0_TX_EVT_FIFO_WRDS], + &can0MsgRam[MCAN0_STD_FLTS_WRDS + MCAN0_EXT_FLTS_WRDS + MCAN0_RX_FIFO0_WRDS + + MCAN0_RX_FIFO1_WRDS + MCAN0_RX_DED_BUFS_WRDS + MCAN0_TX_EVT_FIFO_WRDS + + MCAN0_TX_DED_BUF_WRDS] + }, +}; + +const MCan_ConfigType mcan1Config = { + MCAN1, + MCAN_BTP_BRP(MCAN1_BRP) | MCAN_BTP_TSEG1(MCAN1_TSEG1) | + MCAN_BTP_TSEG2(MCAN1_TSEG2) | MCAN_BTP_SJW(MCAN1_SJW), + MCAN_FBTP_FBRP(MCAN1_FBRP) | MCAN_FBTP_FTSEG1(MCAN1_FTSEG1) | + MCAN_FBTP_FTSEG2(MCAN1_FTSEG2) | MCAN_FBTP_FSJW(MCAN1_FSJW), + MCAN1_NMBR_STD_FLTS, + MCAN1_NMBR_EXT_FLTS, + MCAN1_NMBR_RX_FIFO0_ELMTS, + MCAN1_NMBR_RX_FIFO1_ELMTS, + MCAN0_NMBR_RX_DED_BUF_ELMTS, + MCAN1_NMBR_TX_EVT_FIFO_ELMTS, + MCAN1_NMBR_TX_DED_BUF_ELMTS, + MCAN1_NMBR_TX_FIFO_Q_ELMTS, + (MCAN1_RX_FIFO0_DATA_SIZE << 29) | ((MCAN1_RX_FIFO0_ELMT_SZ / 4) + 2), + /* element size in WORDS */ + (MCAN1_RX_FIFO1_DATA_SIZE << 29) | ((MCAN1_RX_FIFO1_ELMT_SZ / 4) + 2), + /* element size in WORDS */ + (MCAN1_RX_BUF_DATA_SIZE << 29) | ((MCAN1_RX_BUF_ELMT_SZ / 4) + 2), + /* element size in WORDS */ + (MCAN1_TX_BUF_DATA_SIZE << 29) | ((MCAN1_TX_BUF_ELMT_SZ / 4) + 2), + /* element size in WORDS */ + { + &can1MsgRam[0], + &can1MsgRam[MCAN1_STD_FLTS_WRDS], + &can1MsgRam[MCAN1_STD_FLTS_WRDS + MCAN1_EXT_FLTS_WRDS], + &can1MsgRam[MCAN1_STD_FLTS_WRDS + MCAN1_EXT_FLTS_WRDS + MCAN1_RX_FIFO0_WRDS], + &can1MsgRam[MCAN1_STD_FLTS_WRDS + MCAN1_EXT_FLTS_WRDS + MCAN1_RX_FIFO0_WRDS + + MCAN1_RX_FIFO1_WRDS], + &can1MsgRam[MCAN1_STD_FLTS_WRDS + MCAN1_EXT_FLTS_WRDS + MCAN1_RX_FIFO0_WRDS + + MCAN1_RX_FIFO1_WRDS + MCAN1_RX_DED_BUFS_WRDS], + &can1MsgRam[MCAN1_STD_FLTS_WRDS + MCAN1_EXT_FLTS_WRDS + MCAN1_RX_FIFO0_WRDS + + MCAN1_RX_FIFO1_WRDS + MCAN1_RX_DED_BUFS_WRDS + MCAN1_TX_EVT_FIFO_WRDS], + &can1MsgRam[MCAN1_STD_FLTS_WRDS + MCAN1_EXT_FLTS_WRDS + MCAN1_RX_FIFO0_WRDS + + MCAN1_RX_FIFO1_WRDS + MCAN1_RX_DED_BUFS_WRDS + MCAN1_TX_EVT_FIFO_WRDS + + MCAN1_TX_DED_BUF_WRDS] + }, +}; + + +/*--------------------------------------------------------------------------- + * Exported Functions + *---------------------------------------------------------------------------*/ +/** +* \brief Initializes the MCAN hardware for giving peripheral. +* Default: Mixed mode TX Buffer + FIFO. +* +* \param mcanConfig Pointer to a MCAN instance. +*/ +void MCAN_Init(const MCan_ConfigType *mcanConfig) +{ + Mcan *mcan = mcanConfig->pMCan; + uint32_t regVal32; + uint32_t *pMsgRam; + uint32_t cntr; + IRQn_Type mCanLine0Irq; + + /* Both MCAN controllers use programmable clock 5 to derive bit rate */ + // select MCK divided by 1 as programmable clock 5 output + PMC->PMC_PCK[5] = PMC_PCK_PRES(MCAN_PROG_CLK_PRESCALER - 1) | + MCAN_PROG_CLK_SELECT; + PMC->PMC_SCER = PMC_SCER_PCK5; + + if (MCAN0 == mcan) { +#ifndef __rtems__ + PIO_Configure(pinsMcan0, PIO_LISTSIZE(pinsMcan0)); +#endif /* __rtems__ */ + // Enable MCAN peripheral clock + PMC_EnablePeripheral(ID_MCAN0); + // Configure Message RAM Base Address + regVal32 = MATRIX->CCFG_CAN0 & 0x000001FF; + MATRIX->CCFG_CAN0 = regVal32 | + ((uint32_t) mcanConfig->msgRam.pStdFilts & 0xFFFF0000); + mCanLine0Irq = MCAN0_IRQn; + } else if (MCAN1 == mcan) { +#ifndef __rtems__ + PIO_Configure(pinsMcan1, PIO_LISTSIZE(pinsMcan1)); +#endif /* __rtems__ */ + // Enable MCAN peripheral clock + PMC_EnablePeripheral(ID_MCAN1); + // Configure Message RAM Base Address + regVal32 = MATRIX->CCFG_SYSIO & 0x0000FFFF; + MATRIX->CCFG_SYSIO = regVal32 | ((uint32_t) mcanConfig->msgRam.pStdFilts & + 0xFFFF0000); + mCanLine0Irq = MCAN1_IRQn; + } else + return; + + /* Indicates Initialization state */ + mcan->MCAN_CCCR = MCAN_CCCR_INIT_ENABLED; + + do { regVal32 = mcan->MCAN_CCCR; } + while (0u == (regVal32 & MCAN_CCCR_INIT_ENABLED)); + + /* Enable writing to configuration registers */ + mcan->MCAN_CCCR = MCAN_CCCR_INIT_ENABLED | MCAN_CCCR_CCE_CONFIGURABLE; + + /* Global Filter Configuration: Reject remote frames, reject non-matching frames */ + mcan->MCAN_GFC = MCAN_GFC_RRFE_REJECT | MCAN_GFC_RRFS_REJECT + | MCAN_GFC_ANFE(2) | MCAN_GFC_ANFS(2); + + // Extended ID Filter AND mask + mcan->MCAN_XIDAM = 0x1FFFFFFF; + + /* Interrupt configuration - leave initialization with all interrupts off */ + // Disable all interrupts + mcan->MCAN_IE = 0; + mcan->MCAN_TXBTIE = 0x00000000; + // All interrupts directed to Line 0 + mcan->MCAN_ILS = 0x00000000; + // Disable both interrupt LINE 0 & LINE 1 + mcan->MCAN_ILE = 0x00; + // Clear all interrupt flags + mcan->MCAN_IR = 0xFFCFFFFF; + /* Enable NVIC - but no interrupts will happen since all sources are + disabled in MCAN_IE */ + NVIC_ClearPendingIRQ(mCanLine0Irq); + NVIC_EnableIRQ(mCanLine0Irq); + NVIC_ClearPendingIRQ((IRQn_Type) (mCanLine0Irq + 1)); + NVIC_EnableIRQ((IRQn_Type) (mCanLine0Irq + 1)); + + /* Configure CAN bit timing */ + mcan->MCAN_BTP = mcanConfig->bitTiming; + mcan->MCAN_FBTP = mcanConfig->fastBitTiming; + + /* Configure message RAM starting addresses & sizes */ + mcan->MCAN_SIDFC = MAILBOX_ADDRESS((uint32_t) mcanConfig->msgRam.pStdFilts) + | MCAN_SIDFC_LSS(mcanConfig->nmbrStdFilts); + mcan->MCAN_XIDFC = MAILBOX_ADDRESS((uint32_t) mcanConfig->msgRam.pExtFilts) + | MCAN_XIDFC_LSE(mcanConfig->nmbrExtFilts); + mcan->MCAN_RXF0C = MAILBOX_ADDRESS((uint32_t) mcanConfig->msgRam.pRxFifo0) + | MCAN_RXF0C_F0S(mcanConfig->nmbrFifo0Elmts); + // watermark interrupt off, blocking mode + mcan->MCAN_RXF1C = MAILBOX_ADDRESS((uint32_t) mcanConfig->msgRam.pRxFifo1) + | MCAN_RXF1C_F1S(mcanConfig->nmbrFifo1Elmts); + // watermark interrupt off, blocking mode + mcan->MCAN_RXBC = MAILBOX_ADDRESS((uint32_t) mcanConfig->msgRam.pRxDedBuf); + mcan->MCAN_TXEFC = MAILBOX_ADDRESS((uint32_t) mcanConfig->msgRam.pTxEvtFifo) + | MCAN_TXEFC_EFS(mcanConfig->nmbrTxEvtFifoElmts); + // watermark interrupt off + mcan->MCAN_TXBC = MAILBOX_ADDRESS((uint32_t) mcanConfig->msgRam.pTxDedBuf) + | MCAN_TXBC_NDTB(mcanConfig->nmbrTxDedBufElmts) + | MCAN_TXBC_TFQS(mcanConfig->nmbrTxFifoQElmts); + mcan->MCAN_RXESC = ((mcanConfig->rxBufElmtSize >> (29 - MCAN_RXESC_RBDS_Pos)) & + MCAN_RXESC_RBDS_Msk) | + ((mcanConfig->rxFifo1ElmtSize >> (29 - MCAN_RXESC_F1DS_Pos)) & + MCAN_RXESC_F1DS_Msk) | + ((mcanConfig->rxFifo0ElmtSize >> (29 - MCAN_RXESC_F0DS_Pos)) & + MCAN_RXESC_F0DS_Msk); + mcan->MCAN_TXESC = ((mcanConfig->txBufElmtSize >> (29 - MCAN_TXESC_TBDS_Pos)) & + MCAN_TXESC_TBDS_Msk); + + /* Configure Message Filters */ + // ...Disable all standard filters + pMsgRam = mcanConfig->msgRam.pStdFilts; + cntr = mcanConfig->nmbrStdFilts; + + while (cntr > 0) { + *pMsgRam++ = STD_FILT_SFEC_DISABLE; + cntr--; + } + + // ...Disable all extended filters + pMsgRam = mcanConfig->msgRam.pExtFilts; + cntr = mcanConfig->nmbrExtFilts; + + while (cntr > 0) { + *pMsgRam = EXT_FILT_EFEC_DISABLE; + pMsgRam = pMsgRam + 2; + cntr--; + } + + mcan->MCAN_NDAT1 = 0xFFFFFFFF; // clear new (rx) data flags + mcan->MCAN_NDAT2 = 0xFFFFFFFF; // clear new (rx) data flags + + regVal32 = mcan->MCAN_CCCR & ~(MCAN_CCCR_CME_Msk | MCAN_CCCR_CMR_Msk); + mcan->MCAN_CCCR = regVal32 | MCAN_CCCR_CME_ISO11898_1; + mcan->MCAN_CCCR = regVal32 | (MCAN_CCCR_CMR_ISO11898_1 | + MCAN_CCCR_CME_ISO11898_1); + + __DSB(); + __ISB(); +} + +/** + * \brief Enables a FUTURE switch to FD mode (tx & rx payloads up to 64 bytes) + * but transmits WITHOUT bit rate switching + * INIT must be set - so this should be called between MCAN_Init() and + * MCAN_Enable() + * \param mcanConfig Pointer to a MCAN instance. + */ +void MCAN_InitFdEnable(const MCan_ConfigType *mcanConfig) +{ + Mcan *mcan = mcanConfig->pMCan; + uint32_t regVal32; + + regVal32 = mcan->MCAN_CCCR & ~MCAN_CCCR_CME_Msk; + mcan->MCAN_CCCR = regVal32 | MCAN_CCCR_CME(1); +} + +/** + * \brief Enables a FUTURE switch to FD mode (tx & rx payloads up to 64 bytes) and transmits + * WITH bit rate switching + * INIT must be set - so this should be called between MCAN_Init() and MCAN_Enable() + * \param mcanConfig Pointer to a MCAN instance. + */ +void MCAN_InitFdBitRateSwitchEnable(const MCan_ConfigType *mcanConfig) +{ + Mcan *mcan = mcanConfig->pMCan; + uint32_t regVal32; + + regVal32 = mcan->MCAN_CCCR & ~MCAN_CCCR_CME_Msk; + mcan->MCAN_CCCR = regVal32 | MCAN_CCCR_CME(2); +} + +/** + * \brief Initializes the MCAN in loop back mode. + * INIT must be set - so this should be called between MCAN_Init() and + * MCAN_Enable() + * \param mcanConfig Pointer to a MCAN instance. + */ +void MCAN_InitLoopback(const MCan_ConfigType *mcanConfig) +{ + Mcan *mcan = mcanConfig->pMCan; + + mcan->MCAN_CCCR |= MCAN_CCCR_TEST_ENABLED; + //mcan->MCAN_CCCR |= MCAN_CCCR_MON_ENABLED; // for internal loop back + mcan->MCAN_TEST |= MCAN_TEST_LBCK_ENABLED; +} + +/** + * \brief Initializes MCAN queue for TX + * INIT must be set - so this should be called between MCAN_Init() and + * MCAN_Enable() + * \param mcanConfig Pointer to a MCAN instance. + */ +void MCAN_InitTxQueue(const MCan_ConfigType *mcanConfig) +{ + Mcan *mcan = mcanConfig->pMCan; + mcan->MCAN_TXBC |= MCAN_TXBC_TFQM; +} + +/** + * \brief Enable MCAN peripheral. + * INIT must be set - so this should be called between MCAN_Init() + * \param mcanConfig Pointer to a MCAN instance. + */ +void MCAN_Enable(const MCan_ConfigType *mcanConfig) +{ + Mcan *mcan = mcanConfig->pMCan; + mcan->MCAN_CCCR &= ~MCAN_CCCR_INIT_ENABLED; +} + +/** + * \brief Requests switch to Iso11898-1 (standard / classic) mode (tx & rx + * payloads up to 8 bytes). + * \param mcanConfig Pointer to a MCAN instance. + */ +void MCAN_RequestIso11898_1(const MCan_ConfigType *mcanConfig) +{ + Mcan *mcan = mcanConfig->pMCan; + uint32_t regVal32; + + regVal32 = mcan->MCAN_CCCR & ~MCAN_CCCR_CMR_Msk; + mcan->MCAN_CCCR = regVal32 | MCAN_CCCR_CMR_ISO11898_1; + + while ((mcan->MCAN_CCCR & (MCAN_CCCR_FDBS | MCAN_CCCR_FDO)) != 0) + { /* wait */ } +} + +/** + * \brief Requests switch to FD mode (tx & rx payloads up to 64 bytes) but + * transmits WITHOUT bit + * rate switching. requested mode should have been enabled at initialization + * \param mcanConfig Pointer to a MCAN instance. + */ +void MCAN_RequestFd(const MCan_ConfigType *mcanConfig) +{ + Mcan *mcan = mcanConfig->pMCan; + uint32_t regVal32; + + if ((mcan->MCAN_CCCR & MCAN_CCCR_CME_Msk) == MCAN_CCCR_CME(1)) { + regVal32 = mcan->MCAN_CCCR & ~MCAN_CCCR_CMR_Msk; + mcan->MCAN_CCCR = regVal32 | MCAN_CCCR_CMR_FD; + + while ((mcan->MCAN_CCCR & MCAN_CCCR_FDO) == 0) { /* wait */ } + } +} + +/** + * \brief Request switch to FD mode (tx & rx payloads up to 64 bytes) and + * transmits WITH bit rate switching. + * requested mode should have been enabled at initialization + * \param mcanConfig Pointer to a MCAN instance. + */ +void MCAN_RequestFdBitRateSwitch(const MCan_ConfigType *mcanConfig) +{ + Mcan *mcan = mcanConfig->pMCan; + uint32_t regVal32; + + if ((mcan->MCAN_CCCR & MCAN_CCCR_CME_Msk) == MCAN_CCCR_CME(2)) { + regVal32 = mcan->MCAN_CCCR & ~MCAN_CCCR_CMR_Msk; + mcan->MCAN_CCCR = regVal32 | MCAN_CCCR_CMR_FD_BITRATE_SWITCH; + + while ((mcan->MCAN_CCCR & (MCAN_CCCR_FDBS | MCAN_CCCR_FDO)) != + (MCAN_CCCR_FDBS | MCAN_CCCR_FDO)) { /* wait */ } + } +} + +/** + * \brief Switch on loop back mode. + * TEST must be set in MCAN_CCCR - e.g. by a prior call to MCAN_InitLoopback() + * \param mcanConfig Pointer to a MCAN instance. + */ +void MCAN_LoopbackOn(const MCan_ConfigType *mcanConfig) +{ + Mcan *mcan = mcanConfig->pMCan; + mcan->MCAN_TEST |= MCAN_TEST_LBCK_ENABLED; +} + +/** + * \brief Switch off loop back mode. + * \param mcanConfig Pointer to a MCAN instance. + */ +void MCAN_LoopbackOff(const MCan_ConfigType *mcanConfig) +{ + Mcan *mcan = mcanConfig->pMCan; + mcan->MCAN_TEST &= ~MCAN_TEST_LBCK_ENABLED; +} + +/** + * \brief Enable message line and message stored to Dedicated Receive Buffer + * Interrupt Line. + * \param mcanConfig Pointer to a MCAN instance. + * \param line Message line. + */ +void MCAN_IEnableMessageStoredToRxDedBuffer(const MCan_ConfigType *mcanConfig, + MCan_IntrLineType line) +{ + Mcan *mcan = mcanConfig->pMCan; + + if (line == CAN_INTR_LINE_0) { + mcan->MCAN_ILS &= ~MCAN_ILS_DRXL; + mcan->MCAN_ILE |= MCAN_ILE_EINT0; + } else { + // Interrupt Line 1 + mcan->MCAN_ILS |= MCAN_ILS_DRXL; + mcan->MCAN_ILE |= MCAN_ILE_EINT1; + } + + mcan->MCAN_IR = MCAN_IR_DRX; // clear previous flag + mcan->MCAN_IE |= MCAN_IE_DRXE; // enable it +} + +/** + * \brief Configures a Dedicated TX Buffer. + * \param mcanConfig Pointer to a MCAN instance. + * \param buffer Pointer to buffer. + * \param id Message ID. + * \param idType Type of ID + * \param dlc Type of dlc. + */ +uint8_t *MCAN_ConfigTxDedBuffer(const MCan_ConfigType *mcanConfig, + uint8_t buffer, uint32_t id, MCan_IdType idType, MCan_DlcType dlc) +{ + Mcan *mcan = mcanConfig->pMCan; + uint32_t *pThisTxBuf = 0; + + if (buffer < mcanConfig->nmbrTxDedBufElmts) { + pThisTxBuf = mcanConfig->msgRam.pTxDedBuf + (buffer * + (mcanConfig->txBufElmtSize & ELMT_SIZE_MASK)); + + if (idType == CAN_STD_ID) + *pThisTxBuf++ = ((id << 18) & (CAN_11_BIT_ID_MASK << 18)); + else + *pThisTxBuf++ = BUFFER_XTD_MASK | (id & CAN_29_BIT_ID_MASK); + + *pThisTxBuf++ = (uint32_t) dlc << 16; + /* enable transmit from buffer to set TC interrupt bit in IR, but + interrupt will not happen unless TC interrupt is enabled*/ + mcan->MCAN_TXBTIE = (1 << buffer); + } + + return (uint8_t *) pThisTxBuf; // now it points to the data field +} + +/** + * \brief Send Tx buffer. + * \param mcanConfig Pointer to a MCAN instance. + * \param buffer Pointer to buffer. + */ +void MCAN_SendTxDedBuffer(const MCan_ConfigType *mcanConfig, uint8_t buffer) +{ + Mcan *mcan = mcanConfig->pMCan; + + if (buffer < mcanConfig->nmbrTxDedBufElmts) + mcan->MCAN_TXBAR = (1 << buffer); +} + +/** + * \brief Adds Message to TX Fifo / Queue + * \param mcanConfig Pointer to a MCAN instance. + * \param id Message ID. + * \param idType Type of ID + * \param dlc Type of dlc. + * \param data Pointer to data. + */ +uint32_t MCAN_AddToTxFifoQ(const MCan_ConfigType *mcanConfig, + uint32_t id, MCan_IdType idType, MCan_DlcType dlc, uint8_t *data) +{ + Mcan *mcan = mcanConfig->pMCan; + uint32_t putIdx = 255; + uint32_t *pThisTxBuf = 0; + uint8_t *pTxData; + uint8_t msgLength; + uint8_t cnt; + + // Configured for FifoQ and FifoQ not full? + if ((mcanConfig->nmbrTxFifoQElmts > 0) && + ((mcan->MCAN_TXFQS & MCAN_TXFQS_TFQF) == 0)) { + putIdx = (mcan->MCAN_TXFQS & MCAN_TXFQS_TFQPI_Msk) >> MCAN_TXFQS_TFQPI_Pos; + pThisTxBuf = mcanConfig->msgRam.pTxDedBuf + (putIdx * + (mcanConfig->txBufElmtSize & ELMT_SIZE_MASK)); + + if (idType == CAN_STD_ID) + *pThisTxBuf++ = ((id << 18) & (CAN_11_BIT_ID_MASK << 18)); + else + *pThisTxBuf++ = BUFFER_XTD_MASK | (id & CAN_29_BIT_ID_MASK); + + *pThisTxBuf++ = (uint32_t) dlc << 16; + pTxData = (uint8_t *) pThisTxBuf; + msgLength = dlcToMsgLength[dlc]; + + for (cnt = 0; cnt < msgLength; cnt++) + *pTxData++ = *data++; + + /* enable transmit from buffer to set TC interrupt bit in IR, but + interrupt will not happen unless TC interrupt is enabled */ + mcan->MCAN_TXBTIE = (1 << putIdx); + // request to send + mcan->MCAN_TXBAR = (1 << putIdx); + } + + return putIdx; // now it points to the data field +} + +/** + * \brief Check if data transmitted from buffer/fifo/queue + * \param mcanConfig Pointer to a MCAN instance. + * \param buffer Pointer to data buffer. + */ +uint8_t MCAN_IsBufferTxd(const MCan_ConfigType *mcanConfig, uint8_t buffer) +{ + Mcan *mcan = mcanConfig->pMCan; + + return (mcan->MCAN_TXBTO & (1 << buffer)); +} + +/** + * \brief Configure RX Buffer Filter + * ID must match exactly for a RX Buffer Filter + * \param mcanConfig Pointer to a MCAN instance. + * \param buffer Pointer to data buffer. + * \param filter data of filter. + * \param idType Type of ID + */ +void MCAN_ConfigRxBufferFilter(const MCan_ConfigType *mcanConfig, + uint32_t buffer, uint32_t filter, uint32_t id, MCan_IdType idType) +{ + uint32_t *pThisRxFilt = 0; + + if (buffer < mcanConfig->nmbrRxDedBufElmts) { + if (idType == CAN_STD_ID) { + if ((filter < mcanConfig->nmbrStdFilts) + && (id <= CAN_11_BIT_ID_MASK)) { + pThisRxFilt = mcanConfig->msgRam.pStdFilts + filter; + // 1 word per filter + *pThisRxFilt = STD_FILT_SFEC_BUFFER | (id << 16) | + STD_FILT_SFID2_RX_BUFFER | buffer; + } + } else { + // extended ID + if ((filter < mcanConfig->nmbrExtFilts) && + (id <= CAN_29_BIT_ID_MASK)) { + pThisRxFilt = mcanConfig->msgRam.pExtFilts + (2 * filter); + // 2 words per filter + *pThisRxFilt++ = (uint32_t) EXT_FILT_EFEC_BUFFER | id; + *pThisRxFilt = EXT_FILT_EFID2_RX_BUFFER | buffer; + } + } + } +} + +/** + * \brief Configure Classic Filter + * Classic Filters direct accepted messages to a FIFO & include both a ID and + * a ID mask + * \param mcanConfig Pointer to a MCAN instance. + * \param buffer Pointer to data buffer. + * \param fifo fifo Number. + * \param filter data of filter. + * \param idType Type of ID + * \param mask Mask to be match + */ +void MCAN_ConfigRxClassicFilter(const MCan_ConfigType *mcanConfig, + MCan_FifoType fifo, uint8_t filter, uint32_t id, + MCan_IdType idType, uint32_t mask) +{ + uint32_t *pThisRxFilt = 0; + uint32_t filterTemp; + + if (idType == CAN_STD_ID) { + if ((filter < mcanConfig->nmbrStdFilts) && (id <= CAN_11_BIT_ID_MASK) + && (mask <= CAN_11_BIT_ID_MASK)) { + pThisRxFilt = mcanConfig->msgRam.pStdFilts + filter; + // 1 word per filter + filterTemp = (uint32_t) STD_FILT_SFT_CLASSIC | (id << 16) | mask; + + if (fifo == CAN_FIFO_0) + *pThisRxFilt = STD_FILT_SFEC_FIFO0 | filterTemp; + else if (fifo == CAN_FIFO_1) + *pThisRxFilt = STD_FILT_SFEC_FIFO1 | filterTemp; + } + } else { + // extended ID + if ((filter < mcanConfig->nmbrExtFilts) + && (id <= CAN_29_BIT_ID_MASK) + && (mask <= CAN_29_BIT_ID_MASK)) { + pThisRxFilt = mcanConfig->msgRam.pExtFilts + (2 * filter); + + // 2 words per filter + if (fifo == CAN_FIFO_0) + *pThisRxFilt++ = EXT_FILT_EFEC_FIFO0 | id; + else if (fifo == CAN_FIFO_1) + *pThisRxFilt++ = EXT_FILT_EFEC_FIFO1 | id; + + *pThisRxFilt = (uint32_t) EXT_FILT_EFT_CLASSIC | mask; + } + } +} + +/** + * \brief check if data received into buffer + * \param mcanConfig Pointer to a MCAN instance. + * \param buffer Pointer to data buffer. + */ +uint8_t MCAN_IsNewDataInRxDedBuffer(const MCan_ConfigType *mcanConfig, + uint8_t buffer) +{ + Mcan *mcan = mcanConfig->pMCan; + + if (buffer < 32) + return (mcan->MCAN_NDAT1 & (1 << buffer)); + else if (buffer < 64) + return (mcan->MCAN_NDAT1 & (1 << (buffer - 32))); + else + return 0; +} + +/** + * \brief Get Rx buffer + * \param mcanConfig Pointer to a MCAN instance. + * \param buffer Pointer to data buffer. + * \param pRxMailbox Pointer to rx Mailbox. + */ +void MCAN_GetRxDedBuffer(const MCan_ConfigType *mcanConfig, + uint8_t buffer, Mailbox64Type *pRxMailbox) +{ + Mcan *mcan = mcanConfig->pMCan; + uint32_t *pThisRxBuf = 0; + uint32_t tempRy; // temp copy of RX buffer word + uint32_t dlc; + uint8_t *pRxData; + uint8_t idx; + + if (buffer < mcanConfig->nmbrRxDedBufElmts) { + pThisRxBuf = mcanConfig->msgRam.pRxDedBuf + + (buffer * (mcanConfig->rxBufElmtSize & ELMT_SIZE_MASK)); + tempRy = *pThisRxBuf++; // word R0 contains ID + + if (tempRy & BUFFER_XTD_MASK) { + // extended ID? + pRxMailbox->info.id = tempRy & BUFFER_EXT_ID_MASK; + } else { + // standard ID + pRxMailbox->info.id = (tempRy & BUFFER_STD_ID_MASK) >> 18; + } + + tempRy = *pThisRxBuf++; // word R1 contains DLC & time stamp + dlc = (tempRy & BUFFER_DLC_MASK) >> 16; + pRxMailbox->info.length = dlcToMsgLength[dlc]; + pRxMailbox->info.timestamp = tempRy & BUFFER_RXTS_MASK; + // copy the data from the buffer to the mailbox + pRxData = (uint8_t *) pThisRxBuf; + + SCB_CleanDCache_by_Addr((uint32_t *)pRxData, pRxMailbox->info.length); + SCB_CleanDCache_by_Addr((uint32_t *) & (pRxMailbox->data[0]), + pRxMailbox->info.length); + + for (idx = 0; idx < pRxMailbox->info.length; idx++) + pRxMailbox->data[idx] = *pRxData++; + + /* clear the new data flag for the buffer */ + + if (buffer < 32) + mcan->MCAN_NDAT1 = (1 << buffer); + else + mcan->MCAN_NDAT1 = (1 << (buffer - 32)); + + } +} + +/** + * \brief Get from the receive FIFO and place in a application mailbox + * \param mcanConfig Pointer to a MCAN instance. + * \param fifo Fifo Number + * \param pRxMailbox Pointer to rx Mailbox. + * \return: # of fifo entries at the start of the function + * 0 -> FIFO was empty at start + * 1 -> FIFO had 1 entry at start, but is empty at finish + * 2 -> FIFO had 2 entries at start, has 1 entry at finish + */ +uint32_t MCAN_GetRxFifoBuffer(const MCan_ConfigType *mcanConfig, + MCan_FifoType fifo, Mailbox64Type *pRxMailbox) +{ + Mcan *mcan = mcanConfig->pMCan; + uint32_t *pThisRxBuf = 0; + uint32_t tempRy; // temp copy of RX buffer word + uint32_t dlc; + uint8_t *pRxData; + uint8_t idx; + uint32_t *fifo_ack_reg; + uint32_t get_index; + uint32_t fill_level; + uint32_t element_size; + + // default: fifo empty + fill_level = 0; + + if (fifo == CAN_FIFO_0) { + get_index = (mcan->MCAN_RXF0S & MCAN_RXF0S_F0GI_Msk) >> MCAN_RXF0S_F0GI_Pos; + fill_level = (mcan->MCAN_RXF0S & MCAN_RXF0S_F0FL_Msk) >> MCAN_RXF0S_F0FL_Pos; + pThisRxBuf = mcanConfig->msgRam.pRxFifo0; + element_size = mcanConfig->rxFifo0ElmtSize & ELMT_SIZE_MASK; + fifo_ack_reg = (uint32_t *) &mcan->MCAN_RXF0A; + } else if (fifo == CAN_FIFO_1) { + get_index = (mcan->MCAN_RXF1S & MCAN_RXF1S_F1GI_Msk) >> MCAN_RXF1S_F1GI_Pos; + fill_level = (mcan->MCAN_RXF1S & MCAN_RXF1S_F1FL_Msk) >> MCAN_RXF1S_F1FL_Pos; + pThisRxBuf = mcanConfig->msgRam.pRxFifo1; + element_size = mcanConfig->rxFifo1ElmtSize & ELMT_SIZE_MASK; + fifo_ack_reg = (uint32_t *) &mcan->MCAN_RXF1A; + } + + if (fill_level > 0) { + pThisRxBuf = pThisRxBuf + (get_index * element_size); + tempRy = *pThisRxBuf++; // word R0 contains ID + + if (tempRy & BUFFER_XTD_MASK) { + // extended ID? + pRxMailbox->info.id = tempRy & BUFFER_EXT_ID_MASK; + } else { + // standard ID + pRxMailbox->info.id = (tempRy & BUFFER_STD_ID_MASK) >> 18; + } + + tempRy = *pThisRxBuf++; // word R1 contains DLC & timestamps + dlc = (tempRy & BUFFER_DLC_MASK) >> 16; + pRxMailbox->info.length = dlcToMsgLength[dlc]; + pRxMailbox->info.timestamp = tempRy & BUFFER_RXTS_MASK; + /* copy the data from the buffer to the mailbox */ + pRxData = (uint8_t *) pThisRxBuf; + + for (idx = 0; idx < pRxMailbox->info.length; idx++) + pRxMailbox->data[idx] = *pRxData++; + + // acknowledge reading the fifo entry + *fifo_ack_reg = get_index; + /* return entries remaining in FIFO */ + } + + return (fill_level); +} + +/**@}*/ + |