blob: baed8627d818b60945d752032d3b26dbdd425595 [file] [log] [blame]
/* ----------------------------------------------------------------------------
* SAM Software Package License
* ----------------------------------------------------------------------------
* Copyright (c) 2012, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are 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
*----------------------------------------------------------------------------*/
#include "board.h"
#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 (3 << 30)
#define STD_FILT_SFT_RANGE (0 << 30)
#define STD_FILT_SFT_DUAL (1 << 30)
#define STD_FILT_SFT_CLASSIC (2 << 30)
#define STD_FILT_SFEC_MASK (7 << 27)
#define STD_FILT_SFEC_DISABLE (0 << 27)
#define STD_FILT_SFEC_FIFO0 (1 << 27)
#define STD_FILT_SFEC_FIFO1 (2 << 27)
#define STD_FILT_SFEC_REJECT (3 << 27)
#define STD_FILT_SFEC_PRIORITY (4 << 27)
#define STD_FILT_SFEC_PRIORITY_FIFO0 (5 << 27)
#define STD_FILT_SFEC_PRIORITY_FIFO1 (6 << 27)
#define STD_FILT_SFEC_BUFFER (7 << 27)
#define STD_FILT_SFID1_MASK (0x03FF << 16)
#define STD_FILT_SFID2_MASK (0x3FF << 0)
#define STD_FILT_SFID2_RX_BUFFER (0 << 9)
#define STD_FILT_SFID2_DEBUG_A (1 << 9)
#define STD_FILT_SFID2_DEBUG_B (2 << 9)
#define STD_FILT_SFID2_DEBUG_C (3 << 9)
#define STD_FILT_SFID2_BUFFER(nmbr) (nmbr & 0x3F)
#define EXT_FILT_EFEC_MASK (7 << 29)
#define EXT_FILT_EFEC_DISABLE (0 << 29)
#define EXT_FILT_EFEC_FIFO0 (1 << 29)
#define EXT_FILT_EFEC_FIFO1 (2 << 29)
#define EXT_FILT_EFEC_REJECT (3 << 29)
#define EXT_FILT_EFEC_PRIORITY (4 << 29)
#define EXT_FILT_EFEC_PRIORITY_FIFO0 (5 << 29)
#define EXT_FILT_EFEC_PRIORITY_FIFO1 (6 << 29)
#define EXT_FILT_EFEC_BUFFER (7 << 29)
#define EXT_FILT_EFID1_MASK (0x1FFFFFFF)
#define EXT_FILT_EFT_MASK (3 << 30)
#define EXT_FILT_EFT_RANGE (0 << 30)
#define EXT_FILT_EFT_DUAL (1 << 30)
#define EXT_FILT_EFT_CLASSIC (2 << 30)
#define EXT_FILT_EFT_RANGE_NO_XIDAM (3 << 30)
#define EXT_FILT_EFID2_MASK (0x1FFFFFFF)
#define EXT_FILT_EFID2_RX_BUFFER (0 << 9)
#define EXT_FILT_EFID2_DEBUG_A (1 << 9)
#define EXT_FILT_EFID2_DEBUG_B (2 << 9)
#define EXT_FILT_EFID2_DEBUG_C (3 << 9)
#define EXT_FILT_EFID2_BUFFER(nmbr) (nmbr & 0x3F)
/*---------------------------------------------------------------------------
* Internal variables
*---------------------------------------------------------------------------*/
static const Pin pinsMcan0[] = {PIN_MCAN0_TXD, PIN_MCAN0_RXD };
static const Pin pinsMcan1[] = {PIN_MCAN1_TXD, PIN_MCAN1_RXD };
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];
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 ) {
PIO_Configure(pinsMcan0, PIO_LISTSIZE(pinsMcan0));
// 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 ) {
PIO_Configure(pinsMcan1, PIO_LISTSIZE(pinsMcan1));
// 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) ;
}
SCB_CleanInvalidateDCache();
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 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;
for ( cnt = 0; cnt < dlc ; 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 );
}
SCB_CleanInvalidateDCache();
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;
}
}
}
SCB_CleanInvalidateDCache();
}
/**
* \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_0 ) {
*pThisRxFilt++ = EXT_FILT_EFEC_FIFO1 | id;
}
*pThisRxFilt = (uint32_t) EXT_FILT_EFT_CLASSIC | mask;
}
}
}
SCB_CleanInvalidateDCache();
}
/**
* \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;
SCB_CleanInvalidateDCache();
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
uint8_t * pRxData;
uint8_t idx;
SCB_CleanInvalidateDCache();
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
pRxMailbox->info.length = (tempRy & BUFFER_DLC_MASK) >> 16;
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++;
/* 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
uint8_t * pRxData;
uint8_t idx;
uint32_t * fifo_ack_reg;
uint32_t get_index;
uint32_t fill_level;
uint32_t element_size;
SCB_CleanInvalidateDCache();
// 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
pRxMailbox->info.length = (tempRy & BUFFER_DLC_MASK) >> 16;
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 );
}
/**@}*/