1600 lines
38 KiB
C
1600 lines
38 KiB
C
/*
|
|
* codrv_mcan - driver for mcan
|
|
*
|
|
* Copyright (c) 2017-2020 emotas embedded communication GmbH
|
|
*-------------------------------------------------------------------
|
|
* SVN $Id: codrv_mcan.c 51556 2023-12-18 09:35:01Z ro $
|
|
*
|
|
*
|
|
*-------------------------------------------------------------------
|
|
*
|
|
*
|
|
*/
|
|
|
|
/*
|
|
Functionality Singleline:
|
|
- extended and standard id
|
|
- rtr
|
|
- software auto bus on
|
|
- CAN-FD ISO
|
|
- id filter
|
|
- id group filter
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
/***************************************************************************/
|
|
/**
|
|
* \file
|
|
* \brief mCAN CAN driver (e.g. STM32, LPC, Atmel)
|
|
*
|
|
*
|
|
*
|
|
* Note: This settings should be part of gen_define.h!
|
|
*
|
|
*/
|
|
|
|
/* #define CO_DRV_FILTER 1 */
|
|
/* #define CO_DRV_GROUP_FILTER 1 */
|
|
|
|
|
|
|
|
|
|
|
|
/* header of standard C - libraries
|
|
---------------------------------------------------------------------------*/
|
|
#include <stdio.h>
|
|
#include <stddef.h>
|
|
#include <string.h>
|
|
|
|
/* header of project specific types
|
|
---------------------------------------------------------------------------*/
|
|
#include <gen_define.h>
|
|
|
|
#include <co_datatype.h>
|
|
#include <co_drv.h>
|
|
#include <codrv_error.h>
|
|
#include <co_commtask.h>
|
|
|
|
#include "codrv_mcan.h"
|
|
|
|
|
|
/* constant definitions
|
|
---------------------------------------------------------------------------*/
|
|
/*
|
|
* Below is the message RAM setting, it will be stored in the system RAM.
|
|
* Please adjust the message size according to your application.
|
|
*/
|
|
#if defined(CODRV_MCAN_STM32_L5) || defined(CODRV_MCAN_STM32_G0) || defined(CODRV_MCAN_STM32_G4) || defined(CODRV_MCAN_STM32_U5) || defined(CODRV_MCAN_STM32_H5)
|
|
# define CODRV_MCAN_FIXED_MSG_RAM 1u
|
|
# define CODRV_MCAN_FILTER_STD_SIZE 28u
|
|
# define CODRV_MCAN_FILTER_EXT_SIZE 8u
|
|
# define CODRV_MCAN_RXFIFO_SIZE 3u
|
|
# define CODRV_MCAN_ELEMENT_DATA_SIZE 64u
|
|
# define CODRV_MCAN_TXBUFFER_SIZE 3u
|
|
# define CODRV_RX0L_IR_POS 2u
|
|
#endif /* defined(CODRV_MCAN_STM32_L5) || defined(CODRV_MCAN_STM32_G0) || defined(CODRV_MCAN_STM32_G4) || defined(CODRV_MCAN_STM32_U5) || defined(CODRV_MCAN_STM32_H5) */
|
|
|
|
/* The value should be 8/12/16/20/24/32/48/64. */
|
|
# ifndef CODRV_MCAN_ELEMENT_DATA_SIZE
|
|
# define CODRV_MCAN_ELEMENT_DATA_SIZE 8u
|
|
# define CODRV_MCAN_ELEMENT_SIZE_CODE 0u
|
|
# endif /*CODRV_MCAN_ELEMENT_DATA_SIZE*/
|
|
|
|
/**
|
|
* \define CODRV_MCAN_RXFIFO_SIZE
|
|
* Number of rx fifo elements
|
|
*/
|
|
#ifndef CODRV_MCAN_RXFIFO_SIZE
|
|
# define CODRV_MCAN_RXFIFO_SIZE (10u)
|
|
#endif /* CODRV_MCAN_RXFIFO_SIZE */
|
|
|
|
|
|
/**
|
|
* \define CODRV_RX0L_IR_POS
|
|
* RX-fifo message lost flag position
|
|
*/
|
|
#ifndef CODRV_RX0L_IR_POS
|
|
# define CODRV_RX0L_IR_POS 3u
|
|
#endif /* CODRV_RX0L_IR_POS */
|
|
|
|
/**
|
|
* \define CODRV_MCAN_TXBUFFER_SIZE
|
|
* Number of tx buffer elements
|
|
*/
|
|
#ifndef CODRV_MCAN_TXBUFFER_SIZE
|
|
# define CODRV_MCAN_TXBUFFER_SIZE 1u
|
|
#endif /* CODRV_MCAN_TXBUFFER_SIZE */
|
|
|
|
/**
|
|
* \define CODRV_MCAN_FILTER_STD_SIZE
|
|
* Number of std id filter elements
|
|
*/
|
|
#ifndef CODRV_MCAN_FILTER_STD_SIZE
|
|
# ifdef CO_DRV_FILTER
|
|
# define CODRV_MCAN_FILTER_STD_SIZE (28u)
|
|
# else /* CO_DRV_FILTER */
|
|
# define CODRV_MCAN_FILTER_STD_SIZE 0u
|
|
# endif /* CO_DRV_FILTER */
|
|
#endif /* CODRV_MCAN_FILTER_STD_SIZE */
|
|
|
|
/**
|
|
* \define CODRV_MCAN_FILTER_EXT_SIZE
|
|
* Number of ext id filter elements
|
|
*/
|
|
#ifndef CODRV_MCAN_FILTER_EXT_SIZE
|
|
# ifdef CO_DRV_FILTER
|
|
# define CODRV_MCAN_FILTER_EXT_SIZE (28u)
|
|
# else /* CO_DRV_FILTER */
|
|
# define CODRV_MCAN_FILTER_EXT_SIZE 0u
|
|
# endif /* CO_DRV_FILTER */
|
|
#endif /* CODRV_MCAN_FILTER_EXT_SIZE */
|
|
|
|
|
|
#define MCAN_SIDF_SIZE 4u /* standard id filter */
|
|
#define MCAN_XIDF_SIZE 8u /* extended id filter */
|
|
#define MCAN_RXF0_SIZE (MCAN_XIDF_SIZE + CODRV_MCAN_ELEMENT_DATA_SIZE) /* rx fifo 0 */
|
|
#define MCAN_RXB_SIZE (MCAN_XIDF_SIZE + CODRV_MCAN_ELEMENT_DATA_SIZE) /* rx buffer */
|
|
#define MCAN_TXE_SIZE 8u /* tx event */
|
|
#define MCAN_TXB_SIZE (MCAN_XIDF_SIZE + CODRV_MCAN_ELEMENT_DATA_SIZE) /* tx buffer */
|
|
|
|
/**
|
|
* \define CODRV_DEBUG
|
|
* UART Debug output
|
|
*/
|
|
/* #define CODRV_DEBUG 1 */
|
|
|
|
/**
|
|
* \define POLLING
|
|
* work without interrupts
|
|
* !! Seldom tested - support is not guaranteed !!
|
|
*/
|
|
/* #define POLLING 1 */
|
|
|
|
|
|
/* OS related macros - default definition */
|
|
#ifdef CO_OS_SIGNAL_CAN_TRANSMIT
|
|
#else
|
|
# define CO_OS_SIGNAL_CAN_TRANSMIT
|
|
#endif
|
|
|
|
#ifdef CO_OS_SIGNAL_CAN_RECEIVE
|
|
#else
|
|
# define CO_OS_SIGNAL_CAN_RECEIVE
|
|
#endif
|
|
|
|
|
|
/* local defined data types
|
|
---------------------------------------------------------------------------*/
|
|
typedef struct {
|
|
UNSIGNED32 id;
|
|
UNSIGNED32 ctrl;
|
|
UNSIGNED8 data[CODRV_MCAN_ELEMENT_DATA_SIZE];
|
|
}MCAN_FIFO_ELEMENT_T;
|
|
|
|
typedef struct {
|
|
UNSIGNED32 F0;
|
|
UNSIGNED32 F1;
|
|
}MCAN_EXT_FILTER_ELEMENT_T;
|
|
|
|
typedef struct {
|
|
#if defined(CO_DRV_FILTER) || defined(CODRV_MCAN_FIXED_MSG_RAM)
|
|
UNSIGNED32 stdIdFilter[CODRV_MCAN_FILTER_STD_SIZE];
|
|
MCAN_EXT_FILTER_ELEMENT_T extIdFilter[CODRV_MCAN_FILTER_EXT_SIZE];
|
|
#endif /* CO_DRV_FILTER || CODRV_MCAN_FIXED_MSG_RAM */
|
|
MCAN_FIFO_ELEMENT_T rxFifo[CODRV_MCAN_RXFIFO_SIZE];
|
|
#ifdef CODRV_MCAN_FIXED_MSG_RAM
|
|
MCAN_FIFO_ELEMENT_T rxFifo2[CODRV_MCAN_RXFIFO_SIZE];
|
|
UNSIGNED8 eventfifo[8 * 3];
|
|
#endif /* CODRV_MCAN_FIXED_MSG_RAM */
|
|
MCAN_FIFO_ELEMENT_T txBuf[CODRV_MCAN_TXBUFFER_SIZE];
|
|
} MCAN_MSGRAM_T;
|
|
|
|
/* list of external used functions, if not in headers
|
|
---------------------------------------------------------------------------*/
|
|
|
|
/* list of global defined functions
|
|
---------------------------------------------------------------------------*/
|
|
#ifdef CODRV_DEBUG
|
|
# ifdef CO_DRV_FILTER
|
|
void printFilter(void);
|
|
# endif /* CO_DRV_FILTER */
|
|
#endif /* CODRV_DEBUG */
|
|
|
|
/* list of local defined functions
|
|
---------------------------------------------------------------------------*/
|
|
|
|
static RET_T codrvCanInitController(UNSIGNED16 nomBitrate, UNSIGNED16 datBitrate);
|
|
|
|
static RET_T codrvCanTransmit(CO_CONST CO_CAN_TR_MSG_T * pBuf);
|
|
static CO_CONST CODRV_BTR_T * codrvCanGetBtrSettings(UNSIGNED16 bitRate);
|
|
|
|
static void codrvCanResetRam(void);
|
|
|
|
#ifdef CO_DRV_FILTER
|
|
# ifdef CO_DRV_GROUP_FILTER
|
|
static BOOL_T codrvCanCheckGroupFilter(CO_CONST CO_CAN_COB_T * CO_CONST pCob);
|
|
# endif /* CO_DRV_GROUP_FILTER */
|
|
static RET_T codrvCanEnableExtIdFilter(CO_CAN_COB_T * CO_CONST pCob);
|
|
static RET_T codrvCanEnableStdIdFilter(CO_CAN_COB_T * CO_CONST pCob);
|
|
static RET_T codrvCanDisableExtIdFilter(CO_CAN_COB_T * CO_CONST pCob);
|
|
static RET_T codrvCanDisableStdIdFilter(CO_CAN_COB_T * CO_CONST pCob);
|
|
#endif
|
|
|
|
#ifdef CODRV_AUTOBAUD
|
|
RET_T codrvAutoBaudNextBitrate(void);
|
|
UNSIGNED16 codrvAutoBaudGetActualBitrate(void);
|
|
#endif /* CODRV_AUTOBAUD */
|
|
|
|
/* external variables
|
|
---------------------------------------------------------------------------*/
|
|
|
|
/* global variables
|
|
---------------------------------------------------------------------------*/
|
|
|
|
/* local defined variables
|
|
---------------------------------------------------------------------------*/
|
|
|
|
|
|
|
|
static BOOL_T canEnabled = { CO_FALSE };
|
|
static volatile BOOL_T transmissionIsActive = { CO_FALSE };
|
|
|
|
static UNSIGNED32 oldEsrValue;
|
|
|
|
/** currently TX message buffer */
|
|
static CO_CAN_TR_MSG_T *pTxBuf = { NULL };
|
|
|
|
|
|
/** CAN Controller address */
|
|
#ifdef CODRV_MCAN_STM32_H7
|
|
# define CODRV_MCAN0_ADDR ((CODRV_MCANFD_T*)0x4000A000ul)
|
|
# define CODRV_MCAN1_ADDR ((CODRV_MCANFD_T*)0x4000A400ul)
|
|
#endif /* CODRV_MCAN_STM32_H7 */
|
|
|
|
#ifdef CODRV_MCAN_STM32_MP1
|
|
# define CODRV_MCAN0_ADDR ((CODRV_MCANFD_T*)0x4400E000ul)
|
|
# define CODRV_MCAN1_ADDR ((CODRV_MCANFD_T*)0x4400F000ul)
|
|
#endif /* CODRV_MCAN_STM32_MP1 */
|
|
|
|
#if defined(CODRV_MCAN_STM32_G0) || defined(CODRV_MCAN_STM32_G4)
|
|
# define CODRV_MCAN0_ADDR ((CODRV_MCANFD_T*)0x40006400ul)
|
|
# define CODRV_MCAN1_ADDR ((CODRV_MCANFD_T*)0x40006800ul)
|
|
# if defined(CODRV_MCAN_STM32_G4)
|
|
# define CODRV_MCAN2_ADDR ((CODRV_MCANFD_T*)0x40006C00ul)
|
|
# endif /* defined(CODRV_MCAN_STM32_G4) */
|
|
#endif /* defined(CODRV_MCAN_STM32_G0) || defined(CODRV_MCAN_STM32_G4) */
|
|
|
|
/* STM32L5 - only CPUs with 1 FDCAN out at the moment! */
|
|
#if defined(CODRV_MCAN_STM32_L5)
|
|
# define CODRV_MCAN0_ADDR ((CODRV_MCANFD_T*)0x4000A400ul)
|
|
#endif /* defined(CODRV_MCAN_STM32_L5) */
|
|
|
|
/* STM32U5 - only CPUs with 1 FDCAN out at the moment! */
|
|
#if defined(CODRV_MCAN_STM32_U5)
|
|
# define CODRV_MCAN0_ADDR ((CODRV_MCANFD_T*)0x4000A400ul)
|
|
#endif /* defined(CODRV_MCAN_STM32_U5) */
|
|
|
|
#ifdef CODRV_MCAN_STM32_H5
|
|
# define CODRV_MCAN0_ADDR ((CODRV_MCANFD_T*)0x4000A400ul)
|
|
# define CODRV_MCAN1_ADDR ((CODRV_MCANFD_T*)0x4000A800ul)
|
|
#endif /* CODRV_MCAN_STM32_MP1 */
|
|
|
|
#ifndef CODRV_MCAN0_ADDR
|
|
# error select MCAN configuration first!
|
|
#endif /* CODRV_MCAN0_ADDR */
|
|
|
|
|
|
/** \var pCan - used CAN controller address */
|
|
# ifdef CONFIG_MCAN0
|
|
static volatile CODRV_MCANFD_T * const pCan = CODRV_MCAN0_ADDR; /*lint !e923 CAN controller address */
|
|
# endif /* CONFIG_MCAN0 */
|
|
# ifdef CONFIG_MCAN1
|
|
static volatile CODRV_MCANFD_T * const pCan = CODRV_MCAN1_ADDR; /*lint !e923 CAN controller address */
|
|
# endif /* CONFIG_MCAN1 */
|
|
# ifdef CONFIG_MCAN2
|
|
static volatile CODRV_MCANFD_T * const pCan = CODRV_MCAN2_ADDR; /*lint !e923 CAN controller address */
|
|
# endif /* CONFIG_MCAN2 */
|
|
|
|
/** CAN message RAM address */
|
|
#define CODRV_MCAN_STATIC_MSG_RAM
|
|
|
|
# ifdef CONFIG_MCAN0
|
|
static const UNSIGNED8 mcanMsgRamOffs = 0u;
|
|
# endif /* CONFIG_MCAN0 */
|
|
# ifdef CONFIG_MCAN1
|
|
static const UNSIGNED8 mcanMsgRamOffs = 1u;
|
|
# endif /* CONFIG_MCAN1 */
|
|
# ifdef CONFIG_MCAN2
|
|
static const UNSIGNED8 mcanMsgRamOffs = 2u;
|
|
# endif /* CONFIG_MCAN2 */
|
|
|
|
#ifdef CODRV_MCAN_STATIC_MSG_RAM
|
|
# ifdef CODRV_MCAN_STM32_H7
|
|
static volatile MCAN_MSGRAM_T * const pMcanMsgRam = (MCAN_MSGRAM_T*)(0x4000AC00u);
|
|
# endif /* CODRV_MCAN_STM32_H7 */
|
|
|
|
# ifdef CODRV_MCAN_STM32_MP1
|
|
static volatile MCAN_MSGRAM_T * const pMcanMsgRam = (MCAN_MSGRAM_T*)(0x44011000u);
|
|
# endif /* CODRV_MCAN_STM32_MP1 */
|
|
|
|
# ifdef CODRV_MCAN_STM32_G0
|
|
static volatile MCAN_MSGRAM_T * const pMcanMsgRam = (MCAN_MSGRAM_T*)(0x4000B400u);
|
|
# endif /* CODRV_MCAN_STM32_G0 */
|
|
|
|
# ifdef CODRV_MCAN_STM32_G4
|
|
static volatile MCAN_MSGRAM_T * const pMcanMsgRam = (MCAN_MSGRAM_T*)(0x4000A400u);
|
|
# endif /* CODRV_MCAN_STM32_G4 */
|
|
|
|
# ifdef CODRV_MCAN_STM32_L5
|
|
static volatile MCAN_MSGRAM_T * const pMcanMsgRam = (MCAN_MSGRAM_T*)(0x4000AC00u);
|
|
# endif /* CODRV_MCAN_STM32_L5 */
|
|
|
|
# ifdef CODRV_MCAN_STM32_U5
|
|
static volatile MCAN_MSGRAM_T * const pMcanMsgRam = (MCAN_MSGRAM_T*)(0x4000AC00u);
|
|
# endif /* CODRV_MCAN_STM32_U5 */
|
|
|
|
# ifdef CODRV_MCAN_STM32_H5
|
|
static volatile MCAN_MSGRAM_T * const pMcanMsgRam = (MCAN_MSGRAM_T*)(0x4000AC00u);
|
|
# endif /* CODRV_MCAN_STM32_U5 */
|
|
|
|
# else /* CODRV_MCAN_STATIC_MSG_RAM */
|
|
static volatile MCAN_MSGRAM_T mcanMsgRam __attribute__((section(".MCAN_SECTION")));
|
|
static volatile MCAN_MSGRAM_T * volatile pMcanMsgRam = &mcanMsgRam;
|
|
|
|
# ifdef CONFIG_MCAN0
|
|
static volatile UNSIGNED32* pMcanMRBA = (UNSIGNED32 *)0x4009D200ul;
|
|
# endif /* CONFIG_MCAN0 */
|
|
# ifdef CONFIG_MCAN1
|
|
static volatile UNSIGNED32* pMcanMRBA = (UNSIGNED32 *)0x4009e200ul;
|
|
# endif /* CONFIG_MCAN1 */
|
|
#endif /* CODRV_MCAN_STATIC_MSG_RAM */
|
|
|
|
|
|
|
|
#ifdef CODRV_BIT_TABLE_EXTERN
|
|
|
|
extern CO_CONST CODRV_BTR_T codrvCanBittimingTable[];
|
|
|
|
#else /* CODRV_BIT_TABLE_EXTERN */
|
|
/** CAN bittiming table */
|
|
static CO_CONST CODRV_BTR_T codrvCanBittimingTable[] = {
|
|
# ifdef CODRV_CANCLOCK_PRE_10BIT
|
|
/* 80MHz table */
|
|
{ 10u, 500u, 0u, 13u, 2u }, /* 87.5% */
|
|
{ 20u, 250u, 0u, 13u, 2u }, /* 87.5% */
|
|
{ 50u, 100u, 0u, 13u, 2u }, /* 87.5% */
|
|
# endif /* CODRV_CANCLOCK_PRE_10BIT */
|
|
{ 100u, 50u, 0u, 13u, 2u }, /* 87.5% */
|
|
{ 125u, 40u, 0u, 13u, 2u }, /* 87.5% */
|
|
{ 250u, 20u, 0u, 13u, 2u }, /* 87.5% */
|
|
{ 500u, 10u, 0u, 13u, 2u }, /* 87.5% */
|
|
{ 800u, 10u, 0u, 8u, 1u }, /* 90.0% */
|
|
{ 1000u, 5u, 0u, 13u, 2u }, /* 87.5% */
|
|
{ 0u, 0u, 0u, 0u, 0u } /* last */
|
|
};
|
|
#endif /* CODRV_BIT_TABLE_EXTERN */
|
|
|
|
#ifdef CODRV_AUTOBAUD
|
|
static UNSIGNED16 autoBaudBitRateIdx = { 0u };
|
|
static UNSIGNED8 autoBaudActive = { 0u };
|
|
#endif /* CODRV_AUTOBAUD */
|
|
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/* #define DEBUG_SEND_TESTMESSAGE */
|
|
#ifdef DEBUG_SEND_TESTMESSAGE
|
|
static void codrvSendTestMessage(
|
|
void /* no parameter */
|
|
)
|
|
{
|
|
MCAN_MSGRAM_T * pRam;
|
|
|
|
pRam = (MCAN_MSGRAM_T *)(pMcanMsgRam + mcanMsgRamOffs);
|
|
|
|
pRam->txBuf[0].id = (0x555 << 18u);
|
|
pRam->txBuf[0].ctrl = (9u << 16u);/* | (3u << 20u)*/;
|
|
pRam->txBuf[0].data[0] = 0x01;
|
|
pRam->txBuf[0].data[7] = 0x08;
|
|
|
|
pCan->TXBTIE = 0x01;
|
|
pCan->TXBAR = 0x01;
|
|
}
|
|
#endif /* DEBUG_SEND_TESTMESSAGE */
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
|
|
|
|
/***************************************************************************/
|
|
/**
|
|
* \brief codrvCanInit - init CAN controller
|
|
*
|
|
* This Function inits the CAN controller and setup the bitrate
|
|
* After that, the CAN controller is disabled.
|
|
*
|
|
* \param
|
|
* bitrate - CANopen bitrate
|
|
* \results
|
|
* RET_T
|
|
*/
|
|
RET_T codrvCanInit(
|
|
UNSIGNED16 bitRate /**< Bitrate */
|
|
)
|
|
{
|
|
RET_T retVal;
|
|
|
|
/* clear the FD RAM */
|
|
codrvCanResetRam();
|
|
|
|
#ifdef CO_DRV_FILTER
|
|
/* start of ID filter */
|
|
#endif /* CO_DRV_FILTER */
|
|
|
|
|
|
retVal = codrvCanInitController(bitRate, 0u);
|
|
|
|
return(retVal);
|
|
}
|
|
|
|
|
|
|
|
|
|
/***************************************************************************/
|
|
/**
|
|
* \brief codrvCanReInit - reinit CAN controller
|
|
*
|
|
* This Function reinits the CAN controller after deactivation.
|
|
*
|
|
* In Filter mode: After this function call all Filter are reset and must
|
|
* be reconfigured!
|
|
*
|
|
* At the end of the function, the CAN controller should be in state disabled.
|
|
*
|
|
* \param
|
|
* bitrate - CANopen bitrate
|
|
* \results
|
|
* RET_T
|
|
*/
|
|
RET_T codrvCanReInit(
|
|
UNSIGNED16 bitRate /**< Bitrate */
|
|
)
|
|
{
|
|
RET_T retVal;
|
|
|
|
|
|
retVal = codrvCanInitController(bitRate,0u);
|
|
|
|
return(retVal);
|
|
}
|
|
|
|
|
|
|
|
|
|
/***************************************************************************/
|
|
/**
|
|
* \brief codrvCanInitController - init CAN controller
|
|
*
|
|
* \internal
|
|
*
|
|
* This Function inits the CAN controller and setup the bitrate
|
|
* After that, the CAN controller is disabled.
|
|
*
|
|
* \param
|
|
* bitrate - CANopen bitrate
|
|
* \results
|
|
* RET_T
|
|
*/
|
|
static RET_T codrvCanInitController(
|
|
UNSIGNED16 nomBitrate,
|
|
UNSIGNED16 datBitrate
|
|
)
|
|
{
|
|
RET_T retVal = RET_OK;
|
|
|
|
#ifdef CODRV_MCAN_FIXED_MSG_RAM
|
|
#else /* CODRV_MCAN_FIXED_MSG_RAM */
|
|
UNSIGNED32 ramOffset = (sizeof(MCAN_MSGRAM_T) * mcanMsgRamOffs);
|
|
#endif /* CODRV_MCAN_FIXED_MSG_RAM */
|
|
|
|
/* exit from sleep mode */
|
|
pCan->CCCR &= ~MCAN_CCCR_BIT_CSR;
|
|
/* wait for sleep mode acknowledge */
|
|
while((pCan->CCCR & MCAN_CCCR_BIT_CSA) == MCAN_CCCR_BIT_CSA) {
|
|
;
|
|
}
|
|
|
|
/* Request initialization */
|
|
pCan->CCCR |= MCAN_CCCR_BIT_INIT;
|
|
while((pCan->CCCR & MCAN_CCCR_BIT_INIT) != MCAN_CCCR_BIT_INIT) {
|
|
;
|
|
}
|
|
|
|
/* Enable configuration change */
|
|
pCan->CCCR |= MCAN_CCCR_BIT_CCE;
|
|
while((pCan->CCCR & MCAN_CCCR_BIT_CCE) != MCAN_CCCR_BIT_CCE) {
|
|
;
|
|
}
|
|
|
|
/* set the ram address for message ram */
|
|
#ifdef CODRV_MCAN_STATIC_MSG_RAM
|
|
#else /* CODRV_MCAN_STATIC_MSG_RAM */
|
|
*pMcanMRBA = (UNSIGNED32)pMcanMsgRam;
|
|
#endif /* CODRV_MCAN_STATIC_MSG_RAM */
|
|
|
|
/* setup filter */
|
|
#ifdef CODRV_MCAN_FIXED_MSG_RAM
|
|
#else /* CODRV_MCAN_FIXED_MSG_RAM */
|
|
pCan->SIDFC = ((UNSIGNED32)CODRV_MCAN_FILTER_STD_SIZE << 16u) | ramOffset;
|
|
ramOffset += MCAN_SIDF_SIZE * CODRV_MCAN_FILTER_STD_SIZE;
|
|
pCan->XIDFC = ((UNSIGNED32)CODRV_MCAN_FILTER_EXT_SIZE << 16u) | ramOffset;
|
|
ramOffset += MCAN_XIDF_SIZE * CODRV_MCAN_FILTER_EXT_SIZE;
|
|
|
|
/* RX Buffer/FIFO Element Size 64 bytes data field */
|
|
pCan->RXESC |= (UNSIGNED32)CODRV_MCAN_ELEMENT_SIZE_CODE;
|
|
|
|
/* RX Buffer/FIFO configuration */
|
|
pCan->RXF0C = ((UNSIGNED32)CODRV_MCAN_RXFIFO_SIZE << 16u) | ramOffset;
|
|
ramOffset += CODRV_MCAN_RXFIFO_SIZE * MCAN_RXF0_SIZE;
|
|
#endif /* CODRV_MCAN_FIXED_MSG_RAM */
|
|
|
|
#ifdef CO_DRV_FILTER
|
|
/* the GFC register differs if the message ram is fixed or not.
|
|
This has to be checked if new STM32 derivatives are released,
|
|
that this is still the case! */
|
|
# ifdef CODRV_MCAN_FIXED_MSG_RAM
|
|
pCan->GFC = (UNSIGNED32)(0x3c | (CODRV_MCAN_FILTER_EXT_SIZE << 24) | (CODRV_MCAN_FILTER_STD_SIZE << 16)) ;
|
|
# else /* CODRV_MCAN_FIXED_MSG_RAM */
|
|
pCan->GFC = (UNSIGNED32)0x3c;
|
|
# endif /* CODRV_MCAN_FIXED_MSG_RAM */
|
|
#else /* CO_DRV_FILTER */
|
|
/* Accept Non-matching Frames Into FIFO 0 */
|
|
pCan->GFC = (UNSIGNED32)0x0;
|
|
#endif /* CO_DRV_FILTER */
|
|
|
|
#ifdef CODRV_MCAN_FIXED_MSG_RAM
|
|
#else /* CODRV_MCAN_FIXED_MSG_RAM */
|
|
|
|
/* only support one Tx Buffer currently */
|
|
pCan->TXBC = ((UNSIGNED32)1u << 16u) | ramOffset;
|
|
|
|
/* support up to 64 bytes payload */
|
|
pCan->TXESC = ((UNSIGNED32)CODRV_MCAN_ELEMENT_SIZE_CODE);
|
|
#endif /* CODRV_MCAN_FIXED_MSG_RAM */
|
|
|
|
|
|
/* Set the automatic retransmission */
|
|
pCan->CCCR &= ~MCAN_CCCR_BIT_DAR;
|
|
|
|
|
|
/* init req. variables */
|
|
canEnabled = CO_FALSE;
|
|
transmissionIsActive = CO_FALSE;
|
|
|
|
/* error states */
|
|
codrvCanErrorInit();
|
|
|
|
/* set bitrate */
|
|
retVal = codrvCanSetBitRate(nomBitrate); /*lint !e838 initialization for long function */
|
|
(void)datBitrate;
|
|
|
|
#ifdef DEBUG_SEND_TESTMESSAGE
|
|
if (retVal == RET_OK) {
|
|
codrvCanEnable();
|
|
codrvSendTestMessage();
|
|
}
|
|
#endif /* DEBUG_SEND_TESTMESSAGE */
|
|
|
|
return(retVal);
|
|
}
|
|
|
|
|
|
#ifdef CODRV_AUTOBAUD
|
|
/***************************************************************************/
|
|
/**
|
|
*
|
|
* codrvAutoBaudNextBitrate - set next bitrate for autobaud
|
|
*
|
|
* \internal
|
|
*
|
|
* \returns
|
|
* RET_T
|
|
*/
|
|
RET_T codrvAutoBaudNextBitrate(
|
|
void /* no parameter */
|
|
)
|
|
{
|
|
RET_T retVal;
|
|
|
|
autoBaudBitRateIdx++;
|
|
if (codrvCanBittimingTable[autoBaudBitRateIdx].bitRate == 0u) {
|
|
autoBaudBitRateIdx = 0u;
|
|
}
|
|
|
|
retVal = codrvCanSetBitRate(codrvCanBittimingTable[autoBaudBitRateIdx].bitRate); /*lint !e838 initialization for long function */
|
|
|
|
return(retVal);
|
|
}
|
|
|
|
|
|
/***********************************************************************/
|
|
/**
|
|
* codrvAutoBaudGetActualBitrate - get actual used bitrate
|
|
*
|
|
* This function returns the actual used bitrate.
|
|
* They haven't be valid.
|
|
*
|
|
*
|
|
* \returns
|
|
* bitrate
|
|
*/
|
|
UNSIGNED16 codrvAutoBaudGetActualBitrate(
|
|
void /* no parameter */
|
|
)
|
|
{
|
|
return(codrvCanBittimingTable[autoBaudBitRateIdx].bitRate);
|
|
}
|
|
#endif /* CODRV_AUTOBAUD */
|
|
|
|
|
|
/***************************************************************************/
|
|
/**
|
|
* codrvCanGetBtrSettings - get pointer to the btr value structure
|
|
*
|
|
* \internal
|
|
*
|
|
* \returns
|
|
* pointer to an btr table entry
|
|
*/
|
|
|
|
static CO_CONST CODRV_BTR_T * codrvCanGetBtrSettings(
|
|
UNSIGNED16 bitRate /**< required bitrate */
|
|
)
|
|
{
|
|
CO_CONST CODRV_BTR_T * pBtrEntry = NULL;
|
|
UNSIGNED8 i = 0u;
|
|
|
|
while (codrvCanBittimingTable[i].bitRate != 0u) {
|
|
if (codrvCanBittimingTable[i].bitRate == bitRate) {
|
|
pBtrEntry = &codrvCanBittimingTable[i];
|
|
break;
|
|
}
|
|
i++;
|
|
}
|
|
|
|
return(pBtrEntry);
|
|
}
|
|
|
|
|
|
/***************************************************************************/
|
|
/**
|
|
* codrvCanSetBitRate - sets the CAN bit rate
|
|
*
|
|
* \internal
|
|
*
|
|
* Changing the Bitrate only if the CAN controller is in Reset
|
|
*
|
|
* \param
|
|
* bitRate in kbit/s
|
|
* \results
|
|
* RET_T
|
|
*
|
|
*/
|
|
RET_T codrvCanSetBitRate(
|
|
UNSIGNED16 bitRate /**< bit rate in kbit/s */
|
|
)
|
|
{
|
|
CO_CONST CODRV_BTR_T * pBtrEntry;
|
|
|
|
UNSIGNED32 pre;
|
|
UNSIGNED32 seg1;
|
|
UNSIGNED32 seg2;
|
|
|
|
/* stop CAN controller */
|
|
(void)codrvCanDisable();
|
|
|
|
pBtrEntry = codrvCanGetBtrSettings(bitRate);
|
|
|
|
if (pBtrEntry == NULL) {
|
|
/* if bitrate not supported */
|
|
return(RET_DRV_WRONG_BITRATE);
|
|
}
|
|
|
|
/* Enable configuration change */
|
|
pCan->CCCR |= MCAN_CCCR_BIT_CCE;
|
|
while((pCan->CCCR & MCAN_CCCR_BIT_CCE) != MCAN_CCCR_BIT_CCE) {
|
|
;
|
|
}
|
|
|
|
pre = (UNSIGNED32)pBtrEntry->pre;
|
|
seg1 = (UNSIGNED32)pBtrEntry->seg1 + (UNSIGNED32)pBtrEntry->prop;
|
|
seg2 = (UNSIGNED32)pBtrEntry->seg2;
|
|
|
|
#ifdef CODRV_AUTOBAUD
|
|
# warning "autobaud not supported yet"
|
|
#endif
|
|
pCan->NBTP = ((UNSIGNED32)(seg2 - 1u) << 25) | /*use same size for sjw as seg2*/\
|
|
((UNSIGNED32)(pre - 1u) << 16) | \
|
|
((UNSIGNED32)(seg1 - 1u) << 8) | \
|
|
((UNSIGNED32)(seg2 - 1u));
|
|
|
|
return(RET_OK);
|
|
}
|
|
|
|
|
|
|
|
|
|
/***************************************************************************/
|
|
/**
|
|
* codrvCanEnable - enable CAN controller
|
|
*
|
|
* \internal
|
|
*
|
|
* \param
|
|
* none
|
|
* \results
|
|
* RET_T
|
|
*/
|
|
RET_T codrvCanEnable(
|
|
void /* no parameter */
|
|
)
|
|
{
|
|
pCan->CCCR &= ~MCAN_CCCR_BIT_INIT;
|
|
/* Error active is later checked */
|
|
|
|
/* enable interrupts */
|
|
codrvCanEnableInterrupt();
|
|
/* enable interrupt line 0 */
|
|
pCan->ILE = 1u;
|
|
|
|
pCan->IE = MCAN_IE_BIT_RF0NE | MCAN_IE_BIT_TCE | MCAN_IE_BIT_BO | MCAN_IE_BIT_EP;
|
|
|
|
#ifdef CO_DRV_FILTER
|
|
# ifdef CODRV_DEBUG
|
|
printFilter();
|
|
# endif /* CODRV_DEBUG */
|
|
#endif /* CO_DRV_FILTER */
|
|
canEnabled = CO_TRUE;
|
|
oldEsrValue = 0xFFffFFffu;
|
|
|
|
return(RET_OK);
|
|
}
|
|
|
|
|
|
/***************************************************************************/
|
|
/**
|
|
* codrvCanDisable - disable CAN controller
|
|
*
|
|
* This function disables the CAN controller. The function waits
|
|
* for the CAN controller being disabled. Code calling this function
|
|
* typically expects that after returning the CAN controller is in Init mode.
|
|
*
|
|
* But note, the time the CAN controller needs to enter the Init mode
|
|
* can be as long as the duration of one CAN frame.
|
|
*
|
|
* \internal
|
|
*
|
|
* \param
|
|
* none
|
|
* \results
|
|
* RET_OK CAN controller is set to be disabled
|
|
*/
|
|
RET_T codrvCanDisable(
|
|
void /* no parameter */
|
|
)
|
|
{
|
|
/* disable CAN controller */
|
|
pCan->CCCR |= MCAN_CCCR_BIT_INIT;
|
|
while ((pCan->CCCR & MCAN_CCCR_BIT_INIT) == 0u) {
|
|
/* 500us on 250kbit/s */
|
|
}
|
|
|
|
pCan->ILE = 0u;
|
|
|
|
pCan->IE &= ~MCAN_IE_BIT_RF0NE;
|
|
pCan->IE &= ~MCAN_IE_BIT_TCE;
|
|
pCan->IE &= ~MCAN_IE_BIT_BO;
|
|
pCan->IE &= ~MCAN_IE_BIT_EP;
|
|
|
|
canEnabled = CO_FALSE;
|
|
|
|
return(RET_OK);
|
|
}
|
|
|
|
|
|
#ifdef CO_DRV_FILTER
|
|
# ifdef CO_DRV_GROUP_FILTER
|
|
/***********************************************************************/
|
|
/**
|
|
* \brief codrvCheckGroupFilter - check, if the canId part of the group filter
|
|
*
|
|
* Depend of some settings the group filter are for the IDs
|
|
* 0x700..0x77F - Heartbeat
|
|
* 0x80..0xFF - Emergency (and default Sync)
|
|
*
|
|
* \return BOOL_T
|
|
* \retval CO_TRUE
|
|
* The ID is part of the group filter.
|
|
* \retval CO_FALSE
|
|
* The ID is not part of the group filter.
|
|
*
|
|
*
|
|
*
|
|
*/
|
|
static BOOL_T codrvCanCheckGroupFilter(
|
|
CO_CONST CO_CAN_COB_T * CO_CONST pCob
|
|
)
|
|
{
|
|
BOOL_T retval;
|
|
UNSIGNED32 canId = pCob->canId;
|
|
|
|
retval = CO_FALSE;
|
|
|
|
|
|
if ((pCob->flags & CO_COBFLAG_RTR) != CO_COBFLAG_RTR)
|
|
{
|
|
# ifdef CO_HB_CONSUMER_CNT
|
|
if ((canId & 0x0780u) == 0x700u) {
|
|
/* part of the group filter */
|
|
retval = CO_TRUE;
|
|
}
|
|
# endif /* CO_HB_CONSUMER_CNT */
|
|
# ifdef CO_EMCY_CONSUMER_CNT
|
|
if ((canId & 0x0780u) == 0x80u) {
|
|
/* part of the group filter */
|
|
retval = CO_TRUE;
|
|
}
|
|
# endif /* CO_EMCY_CONSUMER_CNT */
|
|
}
|
|
|
|
return(retval);
|
|
}
|
|
# endif /* CO_DRV_GROUP_FILTER */
|
|
|
|
|
|
/***************************************************************************/
|
|
/* codrvCanDisableExtIdFilter -disables an extended filter element
|
|
*
|
|
* This function disables an extended filter element from a given cob. The
|
|
* element number is coded in the upper 8bits of the canChan member.
|
|
*
|
|
* \internal
|
|
*
|
|
* \results
|
|
* RET_T
|
|
*/
|
|
static RET_T codrvCanDisableExtIdFilter(
|
|
CO_CAN_COB_T * CO_CONST pCob
|
|
)
|
|
{
|
|
UNSIGNED16 chan;
|
|
MCAN_MSGRAM_T * pRam;
|
|
|
|
pRam = (MCAN_MSGRAM_T *)(pMcanMsgRam + mcanMsgRamOffs);
|
|
|
|
if ((pCob->canChan & 0xff00) == 0xff00) {
|
|
/* already disabled */
|
|
return(RET_OK); /*lint !e904 function entry check */
|
|
}
|
|
chan = pCob->canChan >> 8u;
|
|
pRam->extIdFilter[chan].F0 = 0u;
|
|
pRam->extIdFilter[chan].F1= 0u;
|
|
pCob->canChan |= 0xff00;
|
|
|
|
return(RET_OK);
|
|
}
|
|
|
|
|
|
/***************************************************************************/
|
|
/* codrvCanDisableStdIdFilter -disables an standard filter element
|
|
*
|
|
* This function disables an standard filter element from a given cob. The
|
|
* element number is coded in the lower 8bits of the canChan member.
|
|
*
|
|
* \internal
|
|
*
|
|
* \results
|
|
* RET_T
|
|
*/
|
|
static RET_T codrvCanDisableStdIdFilter(
|
|
CO_CAN_COB_T * CO_CONST pCob
|
|
)
|
|
{
|
|
UNSIGNED16 chan;
|
|
MCAN_MSGRAM_T * pRam;
|
|
|
|
pRam = (MCAN_MSGRAM_T *)(pMcanMsgRam + mcanMsgRamOffs);
|
|
|
|
if ((pCob->canChan & 0x00ff) == 0x00ff) {
|
|
/* already disabled */
|
|
return(RET_OK); /*lint !e904 function entry check */
|
|
}
|
|
chan = pCob->canChan & 0x00ff;
|
|
pRam->stdIdFilter[chan] = 0x00000000u;
|
|
pCob->canChan |= 0x00ff;
|
|
|
|
return(RET_OK);
|
|
}
|
|
|
|
|
|
static RET_T codrvCanEnableExtIdFilter(
|
|
CO_CAN_COB_T * CO_CONST pCob
|
|
)
|
|
{
|
|
UNSIGNED16 chan;
|
|
UNSIGNED32 mask;
|
|
MCAN_MSGRAM_T * pRam;
|
|
|
|
pRam = (MCAN_MSGRAM_T *)(pMcanMsgRam + mcanMsgRamOffs);
|
|
|
|
chan = pCob->canChan >> 8u;
|
|
|
|
if (chan == 0xff) {
|
|
/* search next free entry */
|
|
for (chan = 0u; chan < CODRV_MCAN_FILTER_EXT_SIZE; chan++) {
|
|
if (pRam->extIdFilter[chan].F0 == 0u) {
|
|
break;
|
|
}
|
|
}
|
|
if (chan == CODRV_MCAN_FILTER_EXT_SIZE) {
|
|
return(RET_DRV_ERROR);
|
|
}
|
|
}
|
|
pRam->extIdFilter[chan].F0 = pCob->canId & 0x1fffffff;
|
|
|
|
mask = ~(pCob->ignore);
|
|
mask &= 0x1fffffff;
|
|
|
|
pRam->extIdFilter[chan].F1 = 0x2u << 30u;
|
|
pRam->extIdFilter[chan].F1 |= mask;
|
|
|
|
/* enable filter */
|
|
pRam->extIdFilter[chan].F0 |= 0x20000000;
|
|
|
|
pCob->canChan &= 0x00ff;
|
|
pCob->canChan |= (chan << 8u);
|
|
|
|
|
|
return(RET_OK);
|
|
}
|
|
|
|
|
|
|
|
static RET_T codrvCanEnableStdIdFilter(
|
|
CO_CAN_COB_T * CO_CONST pCob
|
|
)
|
|
{
|
|
UNSIGNED16 chan;
|
|
UNSIGNED32 mask;
|
|
MCAN_MSGRAM_T * pRam;
|
|
|
|
pRam = (MCAN_MSGRAM_T *)(pMcanMsgRam + mcanMsgRamOffs);
|
|
|
|
chan = pCob->canChan & 0xff;
|
|
|
|
if (chan == 0xff) {
|
|
/* search next free entry */
|
|
for (chan = 0u; chan < CODRV_MCAN_FILTER_STD_SIZE; chan++) {
|
|
if (pRam->stdIdFilter[chan] == 0x00000000u) {
|
|
break;
|
|
}
|
|
}
|
|
if (chan == CODRV_MCAN_FILTER_STD_SIZE) {
|
|
return(RET_DRV_ERROR);
|
|
}
|
|
}
|
|
pRam->stdIdFilter[chan] = pCob->canId & 0x7ff;
|
|
pRam->stdIdFilter[chan] <<= 16u;
|
|
|
|
mask = ~(pCob->ignore);
|
|
mask &= 0x7ff;
|
|
|
|
pRam->stdIdFilter[chan] |= mask;
|
|
|
|
/* enable filter */
|
|
pRam->stdIdFilter[chan] |= (1u<<27);
|
|
pRam->stdIdFilter[chan] |= (2u<<30);
|
|
|
|
pCob->canChan &= 0xff00;
|
|
pCob->canChan |= chan;
|
|
|
|
|
|
return(RET_OK);
|
|
}
|
|
|
|
|
|
/***********************************************************************/
|
|
/**
|
|
* codrvCanSetFilter - activate and configure the receive filter
|
|
*
|
|
* Depend of the COB entry's the driver specific filter will
|
|
* be configured.
|
|
*
|
|
* For the bxCan only Base Identifiere are allowed.
|
|
*
|
|
*
|
|
* \retval RET_OK
|
|
* OK
|
|
* \retval RET_INVALID_PARAMETER
|
|
* invalid COB reference
|
|
* \retval RET_DRV_ERROR
|
|
* filter cannot be set, e.g. no free entry
|
|
*
|
|
*/
|
|
|
|
RET_T codrvCanSetFilter(
|
|
CO_CAN_COB_T * pCanCob /**< COB reference */
|
|
)
|
|
{
|
|
|
|
# ifdef CODRV_DEBUG
|
|
printf("codrvCanSetFilter: 0x%04x rtr: %d enabled: %d\n", pCanCob->canId, (pCanCob->flags & CO_COBFLAG_RTR), (pCanCob->flags & CO_COBFLAG_ENABLED));
|
|
# endif
|
|
|
|
|
|
|
|
/* get a filter entry in case of:
|
|
* - COB has a filter entry from older setting or
|
|
* - COB is enabled and
|
|
* - COB is a Receive Data Frame or
|
|
* - COB is a Transmit Data Frame, but can be query by RTR
|
|
*/
|
|
(void)codrvCanDisableExtIdFilter(pCanCob);
|
|
(void)codrvCanDisableStdIdFilter(pCanCob);
|
|
|
|
if ((pCanCob->flags & CO_COBFLAG_ENABLED) == CO_COBFLAG_ENABLED) {
|
|
if ((pCanCob->flags & CO_COBFLAG_EXTENDED) == CO_COBFLAG_EXTENDED) {
|
|
return(codrvCanEnableExtIdFilter(pCanCob));
|
|
} else {
|
|
return(codrvCanEnableStdIdFilter(pCanCob));
|
|
}
|
|
}
|
|
|
|
|
|
# ifdef CODRV_DEBUG
|
|
printFilter();
|
|
# endif
|
|
|
|
return(RET_OK);
|
|
}
|
|
#endif /* CO_DRV_FILTER */
|
|
|
|
|
|
/***********************************************************************/
|
|
/**
|
|
* codrvCanStartTransmission - start can transmission if not active
|
|
*
|
|
* Transmission of CAN messages should be interrupt driven.
|
|
* If a message was sent, the Transmit Interrupt is called
|
|
* and the next message can be transmitted.
|
|
* To start the transmission of the first message,
|
|
* this function is called from the stack.
|
|
*
|
|
* The easiest way to implement this function is
|
|
* to trigger the transmit interrupt,
|
|
* but only if the transmission is not already active.
|
|
*
|
|
* \internal
|
|
*
|
|
* \return RET_T
|
|
*
|
|
*/
|
|
RET_T codrvCanStartTransmission(
|
|
void /* no parameter */
|
|
)
|
|
{
|
|
RET_T retVal = RET_DRV_BUSY;
|
|
|
|
/* if can is not enabled, return with error */
|
|
if (canEnabled != CO_TRUE) {
|
|
return(RET_DRV_ERROR); /*lint !e904 function entry check */
|
|
}
|
|
|
|
if (transmissionIsActive == CO_FALSE) {
|
|
/* trigger transmit interrupt */
|
|
#ifdef POLLING
|
|
retVal = codrvCanTransmitInterrupt();
|
|
#else /* POLLING */
|
|
/* enable global interrupt pending bit to call interrupt */
|
|
codrvCanSetTxInterrupt();
|
|
#endif /* POLLING */
|
|
} else {
|
|
codrvCanDriverHandler();
|
|
}
|
|
|
|
return(retVal);
|
|
}
|
|
|
|
|
|
/***************************************************************************/
|
|
/* codrvCanTransmit - transmit can message
|
|
*
|
|
* This function writes a new message to the CAN controller and transmits it.
|
|
* Normally called from transmit Interrupt
|
|
*
|
|
* \internal
|
|
*
|
|
* \results
|
|
* RET_T
|
|
*/
|
|
static RET_T codrvCanTransmit(
|
|
CO_CONST CO_CAN_TR_MSG_T * pBuf /**< pointer to data */
|
|
)
|
|
{
|
|
RET_T retVal = RET_OK;
|
|
/* currently, general MB 0 */
|
|
UNSIGNED32 ctrl;
|
|
UNSIGNED8 i;
|
|
MCAN_MSGRAM_T * pRam;
|
|
|
|
pRam = (MCAN_MSGRAM_T *)(pMcanMsgRam + mcanMsgRamOffs);
|
|
|
|
/* return if device is not initialized or enabled */
|
|
if (canEnabled == CO_FALSE) {
|
|
return(RET_DRV_ERROR);
|
|
}
|
|
|
|
/* busy check */
|
|
if (pCan->TXBRP != 0ul) {
|
|
return(RET_DRV_BUSY); /*lint !e904 function entry check */
|
|
}
|
|
|
|
ctrl = pBuf->len;
|
|
if (ctrl > 8u) {
|
|
ctrl = 8u;
|
|
}
|
|
pRam->txBuf[0u].ctrl = (ctrl << 16u);
|
|
|
|
/* extended CAN ID */
|
|
if ((pBuf->flags & CO_COBFLAG_EXTENDED) == CO_COBFLAG_EXTENDED) {
|
|
/* message with 29 bit identifier */
|
|
pRam->txBuf[0u].id = pBuf->canId;
|
|
pRam->txBuf[0u].id |= MCAN_CANID_BIT_XTD;
|
|
} else {
|
|
/* message with 11 bit identifier */
|
|
pRam->txBuf[0u].id = (pBuf->canId << 18u);
|
|
}
|
|
|
|
/* remote transmission request */
|
|
if ((pBuf->flags & CO_COBFLAG_RTR) == CO_COBFLAG_RTR) {
|
|
/* message is remote frame */
|
|
pRam->txBuf[0u].id |= MCAN_CANID_BIT_RTR;
|
|
}
|
|
|
|
/* copy message data */
|
|
if ((pBuf->flags & CO_COBFLAG_RTR) != CO_COBFLAG_RTR) {
|
|
for (i = 0u; i < CODRV_MCAN_ELEMENT_DATA_SIZE; i = i + 4u) {
|
|
*((UNSIGNED32*)&(pRam->txBuf[0u].data[i])) =
|
|
(UNSIGNED32)pBuf->data[i] | \
|
|
((UNSIGNED32)pBuf->data[i + 1] << 8u) | \
|
|
((UNSIGNED32)pBuf->data[i + 2] << 16u) | \
|
|
((UNSIGNED32)pBuf->data[i + 3] << 24u);
|
|
}
|
|
}
|
|
|
|
/* transmit it */
|
|
/* currently, general MB 0 */
|
|
pCan->TXBAR = 1ul;
|
|
pCan->TXBTIE = 0x01;
|
|
|
|
transmissionIsActive = CO_TRUE;
|
|
|
|
return(retVal);
|
|
}
|
|
|
|
|
|
/***************************************************************************/
|
|
/* codrvCanDriverTransmitInterrupt - can driver transmit interrupt
|
|
*
|
|
* \internal
|
|
*
|
|
* This function is called, after message was transmitted.
|
|
* As first, inform stack about message transmission.
|
|
* Get the next message from the transmit buffer, write it to the CAN controller
|
|
* and transmit it.
|
|
*
|
|
* \param
|
|
* none
|
|
* \results
|
|
* none
|
|
*/
|
|
RET_T codrvCanTransmitInterrupt(
|
|
void /* no parameter */
|
|
)
|
|
{
|
|
RET_T retVal = RET_OK;
|
|
|
|
/* reset interrupt request
|
|
* => currently reset all possible TX IRQ requests
|
|
*
|
|
* -> very simple implementation
|
|
*/
|
|
|
|
if (pCan->TXBRP == 0ul) {
|
|
transmissionIsActive = CO_FALSE;
|
|
|
|
/* inform stack about transmitted message */
|
|
if (pTxBuf != NULL) {
|
|
coQueueMsgTransmitted(pTxBuf);
|
|
pTxBuf = NULL;
|
|
|
|
/* signal transmitted message */
|
|
CO_OS_SIGNAL_CAN_TRANSMIT
|
|
}
|
|
|
|
/* get next message from transmit queue */
|
|
pTxBuf = coQueueGetNextTransmitMessage();
|
|
if (pTxBuf != NULL) {
|
|
/* and transmit it - CAN message buffer is free */
|
|
retVal = codrvCanTransmit(pTxBuf);
|
|
}
|
|
/* clear interrupt flag */
|
|
pCan->IR = MCAN_IE_BIT_TCE;
|
|
} else {
|
|
retVal = RET_DRV_BUSY;
|
|
}
|
|
|
|
return(retVal);
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* codrvCanReceiveInterrupt - can driver receive interrupt
|
|
*
|
|
* \internal
|
|
*
|
|
* This function is called, if a new message was received
|
|
* As first get the pointer to the receive buffer
|
|
* and save the message there.
|
|
* Then set the buffer as filled and inform the library about new data.
|
|
*
|
|
*
|
|
* \param
|
|
* none
|
|
* \results
|
|
* none
|
|
*/
|
|
void codrvCanReceiveInterrupt(
|
|
void /* no parameter */
|
|
)
|
|
{
|
|
UNSIGNED8 *pRecBuf;
|
|
UNSIGNED8 coFlags;
|
|
UNSIGNED8 len;
|
|
UNSIGNED8 mbNr = 0u;
|
|
UNSIGNED32 id;
|
|
CAN_ERROR_FLAGS_T * pError;
|
|
UNSIGNED8 i;
|
|
MCAN_MSGRAM_T * pRam;
|
|
#ifdef CO_CAN_TIMESTAMP_SUPPORTED
|
|
CO_CAN_TIMESTAMP_T timestamp;
|
|
#endif /* CO_CAN_TIMESTAMP_SUPPORTED */
|
|
|
|
pRam = (MCAN_MSGRAM_T *)(pMcanMsgRam + mcanMsgRamOffs);
|
|
|
|
pCan->IR = MCAN_IE_BIT_RF0NE;
|
|
|
|
if ((pCan->RXF0S & 0x7f) == 0u) {
|
|
return;
|
|
}
|
|
|
|
|
|
do {
|
|
/* delete pending interrupt */
|
|
pCan->IR = MCAN_IE_BIT_RF0NE;
|
|
/* initialize COB flag */
|
|
coFlags = CO_COBFLAG_NONE;
|
|
|
|
/* currently only Fifo 0 */
|
|
mbNr = ((pCan->RXF0S >> 8u) & 0x3f);
|
|
|
|
/* get Identifier */
|
|
id = pRam->rxFifo[mbNr].id;
|
|
|
|
/* extended CAN-ID */
|
|
if ((id & MCAN_CANID_BIT_XTD) == MCAN_CANID_BIT_XTD) {
|
|
coFlags |= CO_COBFLAG_EXTENDED;
|
|
}
|
|
|
|
/* remote transmission request */
|
|
if ((id & MCAN_CANID_BIT_RTR) == MCAN_CANID_BIT_RTR) {
|
|
coFlags |= CO_COBFLAG_RTR;
|
|
}
|
|
|
|
len = (pRam->rxFifo[mbNr].ctrl >> 16) & 0x0f;
|
|
/* FD frame */
|
|
if (((pRam->rxFifo[mbNr].ctrl >> 21) & 0x01) == 1u) {
|
|
continue;
|
|
} else {
|
|
if (len > 8u) {
|
|
len = 8u;
|
|
}
|
|
}
|
|
|
|
/* save 11/29 bit CAN-ID */
|
|
if ((id & MCAN_CANID_BIT_XTD) != MCAN_CANID_BIT_XTD) {
|
|
/* save 11 bit CAN-ID */
|
|
id = (id >> 18u) & 0x7FFul;
|
|
} else {
|
|
/* save 29 bit CAN-ID */
|
|
id = id & 0x1FFFFFFFul;
|
|
}
|
|
|
|
#ifdef CO_CAN_TIMESTAMP_SUPPORTED
|
|
/* get RX timestamp */
|
|
timestamp = (UNSIGNED32)(pRam->rxFifo[mbNr].ctrl & 0xffFF);
|
|
#endif /* CO_CAN_TIMESTAMP_SUPPORTED */
|
|
|
|
/* get receiveBuffer */
|
|
pRecBuf = coQueueGetReceiveBuffer(id, len, coFlags
|
|
#ifdef CO_CAN_TIMESTAMP_SUPPORTED
|
|
, timestamp
|
|
#endif /* CO_CAN_TIMESTAMP_SUPPORTED */
|
|
);
|
|
if (pRecBuf == NULL) {
|
|
/* error, no buffer available */
|
|
|
|
/* release mailbox */
|
|
pCan->RXF0A = mbNr;
|
|
|
|
/* signal received message - but there was generated
|
|
* signals for all older received messages
|
|
* that are in the buffer
|
|
*/
|
|
/* CO_OS_SIGNAL_CAN_RECEIVE */
|
|
|
|
return; /*lint !e904 no buffer possible */
|
|
}
|
|
|
|
/* save message at buffer */
|
|
if ((id & MCAN_CANID_BIT_RTR) != MCAN_CANID_BIT_RTR) {
|
|
for (i = 0u; i < len; i++) {
|
|
pRecBuf[i] = pRam->rxFifo[mbNr].data[i];
|
|
}
|
|
}
|
|
|
|
if ((pCan->RXF0S & (1u << 25u)) == (1u << 25u)) {
|
|
pError = codrvCanErrorGetFlags();
|
|
pError->canErrorRxOverrun = CO_TRUE;
|
|
|
|
/* reset message lost error */
|
|
pCan->IR |= (1u << CODRV_RX0L_IR_POS);
|
|
}
|
|
|
|
/* release mailbox */
|
|
pCan->RXF0A = mbNr;
|
|
|
|
/* set buffer filled */
|
|
coQueueReceiveBufferIsFilled();
|
|
} while (pCan->RXF0S & 0x7f);
|
|
|
|
/* signal received message */
|
|
CO_OS_SIGNAL_CAN_RECEIVE
|
|
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* codrvCanErrorInterrupt - can driver error interrupt
|
|
*
|
|
* \internal
|
|
*
|
|
* This function is called, if a error passive or Busoff event
|
|
* occurs.
|
|
*
|
|
* \param
|
|
* none
|
|
* \results
|
|
* none
|
|
*/
|
|
void codrvCanErrorInterrupt(
|
|
void /* no parameter */
|
|
)
|
|
{
|
|
if ((pCan->IR & (MCAN_IE_BIT_BO | MCAN_IE_BIT_EP)) != 0u) {
|
|
CAN_ERROR_FLAGS_T * pError;
|
|
|
|
/* set flag to signal the state change */
|
|
pError = codrvCanErrorGetFlags();
|
|
if ((pCan->IR & MCAN_IE_BIT_BO) != 0) {
|
|
pError->canErrorBusoff = CO_TRUE;
|
|
/* clear init bit to get buss on again */
|
|
pCan->CCCR &= ~MCAN_CCCR_BIT_INIT;
|
|
} else
|
|
if ((pCan->IR & MCAN_IE_BIT_EP) != 0) {
|
|
pError->canErrorPassive = CO_TRUE;
|
|
} else {
|
|
/* never occur, because the error interrupt is not
|
|
* calling for this state change */
|
|
pError->canErrorActive = CO_TRUE;
|
|
}
|
|
|
|
/* clear interrupt bit */
|
|
pCan->IR = (MCAN_IE_BIT_BO | MCAN_IE_BIT_EP);
|
|
}
|
|
}
|
|
|
|
|
|
/***************************************************************************/
|
|
/**
|
|
* codrvCanErrorHandler - Error handler
|
|
*
|
|
* This function polls the current state of the CAN controller
|
|
* and checks explicitly all situation that are not signaled
|
|
* within the interrupts.
|
|
*
|
|
* Call outside of interrupts!
|
|
* Typical call in codrvCanDriverHandler().
|
|
*/
|
|
|
|
static void codrvCanErrorHandler(
|
|
void /* no parameter */
|
|
)
|
|
{
|
|
|
|
UNSIGNED32 err;
|
|
UNSIGNED32 change;
|
|
CAN_ERROR_FLAGS_T * pError;
|
|
BOOL_T fStartTransmission = CO_FALSE;
|
|
|
|
pError = codrvCanErrorGetFlags();
|
|
|
|
/*
|
|
* Error active/passive/busoff check
|
|
*/
|
|
err = pCan->PSR;
|
|
|
|
|
|
/* check only changes of passive and busoff */
|
|
change = err ^ oldEsrValue;
|
|
change &= ((MCAN_PSR_BIT_BO) | (MCAN_PSR_BIT_EP));
|
|
|
|
if (change != 0ul) {
|
|
if ((err & MCAN_PSR_BIT_BO) != 0ul) {
|
|
/* busoff */
|
|
/* canErrorBusoff = CO_TRUE;*/
|
|
pError->canNewState = Error_Busoff; /* current state */
|
|
} else
|
|
if ((err & MCAN_PSR_BIT_EP) != 0ul) {
|
|
/* error passive */
|
|
/* canErrorPassive = CO_TRUE; */
|
|
pError->canNewState = Error_Passive; /* current state */
|
|
} else {
|
|
/* error active */
|
|
/* canErrorActive = CO_TRUE; */
|
|
pError->canNewState = Error_Active; /* current state */
|
|
}
|
|
}
|
|
oldEsrValue = err;
|
|
|
|
/* busoff recovery */
|
|
if ((err & MCAN_PSR_BIT_BO) != 0ul) {
|
|
/* busoff */
|
|
pCan->CCCR &= ~MCAN_CCCR_BIT_INIT;
|
|
}
|
|
|
|
/* more for polling - software interrupt, but TX object was sended */
|
|
if (pCan->TXBRP == 0ul) {
|
|
/* correct possible Errors -> CAN has deactivated the transmission */
|
|
transmissionIsActive = CO_FALSE;
|
|
}
|
|
|
|
if (canEnabled == CO_TRUE) {
|
|
/* check for stopped transmissions */
|
|
if ((transmissionIsActive == CO_FALSE) && (pTxBuf != NULL)) {
|
|
/* transmission aborted, e.g. busoff,
|
|
* discard message -> is done within the tx interrupt
|
|
*/
|
|
fStartTransmission = CO_TRUE;
|
|
}
|
|
}
|
|
|
|
if (fStartTransmission == CO_TRUE) {
|
|
(void)codrvCanStartTransmission(); /* -> call Interrupt at this point */
|
|
}
|
|
}
|
|
|
|
|
|
/***************************************************************************/
|
|
/** codrvCanDriverHandler - can driver handler
|
|
*
|
|
* \internal
|
|
*
|
|
* is cyclically called from stack to get actual CAN state
|
|
* (BUS_OFF, PASSIVE, ACTIVE)
|
|
* and return to bus on again after bus off was occurred.
|
|
*
|
|
* \param
|
|
* none
|
|
* \results
|
|
* none
|
|
*/
|
|
void codrvCanDriverHandler(
|
|
void /* no parameter */
|
|
)
|
|
{
|
|
/* check current state */
|
|
codrvCanErrorHandler();
|
|
|
|
/*
|
|
* inform the CANopen Stack about state changes
|
|
*/
|
|
(void)codrvCanErrorInformStack();
|
|
|
|
#ifdef POLLING
|
|
codrvCanReceiveInterrupt();
|
|
codrvCanTransmitInterrupt();
|
|
#endif /* POLLING */
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
#ifdef CODRV_DEBUG
|
|
#include <stdio.h>
|
|
void printFilter(void)
|
|
{
|
|
# ifdef CODRV_DEBUG_MAX
|
|
int i,j;
|
|
volatile UNSIGNED32 *pCanFilter = pCanFilterAddr;
|
|
|
|
printf("\nFiltersettings:\n");
|
|
printf("FINIT %d\n", pCanFilter[BXCAN_CANFMR] & BXCAN_CANFMR_FINIT );
|
|
printf("Filter active (0 off 1 on) 0x%08lx\n", pCanFilter[BXCAN_CANFA1R]);
|
|
printf("Filtermode (0 mask 1 list) 0x%08lx\n", pCanFilter[BXCAN_CANFM1R]);
|
|
printf("Filterscale (0 16-bit 1 32-bit) 0x%08lx\n", pCanFilter[BXCAN_CANFS1R]);
|
|
printf("Filter assignm (0 fifo0 1 fifo1) 0x%08lx\n", pCanFilter[BXCAN_CANFFA1R]);
|
|
|
|
printf("\n");
|
|
//for(i = 0; i < 14; i++)
|
|
for(i = 0; i <= 0; i++)
|
|
{
|
|
for (j = 1; j <= 2; j++) {
|
|
printf("\n");
|
|
printf("Filterbank %d Register %d\n", i,j );
|
|
printf("Adr: 0x%08lx\n", &pCanFilter[BXCAN_CANFIRX(i,j)]);
|
|
|
|
printf(" ID 0x%04x\n", (pCanFilter[BXCAN_CANFIRX(i,j)] & 0xFFFFul) >> 5 );
|
|
if( (pCanFilter[BXCAN_CANFM1R] & (1ul << i)) != 0) {
|
|
printf(" ID 0x%04x\n", (pCanFilter[BXCAN_CANFIRX(i,j)] >> (16 + 5) )& 0xFFFFul);
|
|
} else {
|
|
printf("Mask 0x%04x\n", (pCanFilter[BXCAN_CANFIRX(i,j)] >> (16 + 5) )& 0xFFFFul);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
for(i = 1; i < 14; i++)
|
|
{
|
|
if( (pCanFilter[BXCAN_CANFA1R] & (1ul << i)) != 0) {
|
|
for (j = 1; j <= 2; j++) {
|
|
printf("\n");
|
|
printf("Filterbank %d Register %d Val 0x%08lx\n", i,j, pCanFilter[BXCAN_CANFIRX(i,j)] );
|
|
|
|
printf(" ID 0x%04x\n", (pCanFilter[BXCAN_CANFIRX(i,j)] & 0xFFFFul) >> 5);
|
|
|
|
|
|
printf(" ID 0x%04x\n", ((pCanFilter[BXCAN_CANFIRX(i,j)] >> 16 )& 0xFFFFul) >> 5);
|
|
}
|
|
}
|
|
|
|
}
|
|
# endif
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
static void codrvCanResetRam(
|
|
void /* no parameter */
|
|
)
|
|
{
|
|
volatile MCAN_MSGRAM_T *pOffset;
|
|
|
|
pOffset = (MCAN_MSGRAM_T *)(pMcanMsgRam + mcanMsgRamOffs);
|
|
memset((void*)pOffset, 0x00u, sizeof(MCAN_MSGRAM_T));
|
|
}
|
|
|