CAN Module Sources¶
can.c¶
/**
*
* @copyright © 2010 - 2020, Fraunhofer-Gesellschaft zur Foerderung der
* angewandten Forschung e.V. All rights reserved.
*
* BSD 3-Clause License
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* We kindly request you to use one or more of the following phrases to refer
* to foxBMS in your hardware, software, documentation or advertising
* materials:
*
* ″This product uses parts of foxBMS®″
*
* ″This product includes parts of foxBMS®″
*
* ″This product is derived from foxBMS®″
*
*/
/**
* @file can.c
* @author foxBMS Team
* @date 12.07.2015 (date of creation)
* @ingroup DRIVERS
* @prefix CAN
*
* @brief Driver for the CAN module
*
* Implementation of the CAN Interrupts, initialization, buffers,
* receive and transmit interfaces.
*
*/
/*================== Includes =============================================*/
#include "can.h"
/*================== Macros and Definitions ===============================*/
#define ID_16BIT_FIFO0 (0U)
#define ID_16BIT_FIFO1 (1U)
#define ID_32BIT_FIFO0 (2U)
#define ID_32BIT_FIFO1 (3U)
#define MSK_16BIT_FIFO0 (4U)
#define MSK_16BIT_FIFO1 (5U)
#define MSK_32BIT (6U)
/*================== Constant and Variable Definitions ====================*/
uint8_t canNode0_listenonly_mode = 0;
uint8_t canNode1_listenonly_mode = 0;
#if CAN_USE_CAN_NODE0
#if CAN0_USE_TX_BUFFER
CAN_TX_BUFFERELEMENT_s can0_txbufferelements[CAN0_TX_BUFFER_LENGTH];
CAN_TX_BUFFER_s can0_txbuffer = {
.length = CAN0_TX_BUFFER_LENGTH,
.buffer = &can0_txbufferelements[0],
};
#endif /* CAN0_USE_TX_BUFFER */
#if CAN0_USE_RX_BUFFER
CAN_RX_BUFFERELEMENT_s can0_rxbufferelements[CAN0_RX_BUFFER_LENGTH];
CAN_RX_BUFFER_s can0_rxbuffer = {
.length = CAN0_RX_BUFFER_LENGTH,
.buffer = &can0_rxbufferelements[0],
};
#endif /* CAN0_USE_RX_BUFFER */
#if CAN0_BUFFER_BYPASS_NUMBER_OF_IDs > 0
uint8_t can0_fastLinkIndex[CAN0_BUFFER_BYPASS_NUMBER_OF_IDs]; /* Link Table for bufferBypassing */
#endif
CAN_ERROR_s CAN0_errorStruct = {
.canError = HAL_CAN_ERROR_NONE,
.canErrorCounter = { 0, 0, 0, 0, 0, 0, 0, 0, 0 },
};
#endif /* CAN_USE_CAN_NODE0 */
#if CAN_USE_CAN_NODE1
#if CAN1_USE_TX_BUFFER
CAN_TX_BUFFERELEMENT_s can1_txbufferelements[CAN1_TX_BUFFER_LENGTH];
CAN_TX_BUFFER_s can1_txbuffer = {
.length = CAN1_TX_BUFFER_LENGTH,
.buffer = &can1_txbufferelements[0],
};
#endif /* CAN1_USE_TX_BUFFER */
#if CAN1_USE_RX_BUFFER
CAN_RX_BUFFERELEMENT_s can1_rxbufferelements[CAN1_RX_BUFFER_LENGTH];
CAN_RX_BUFFER_s can1_rxbuffer = {
.length = CAN1_RX_BUFFER_LENGTH,
.buffer = &can1_rxbufferelements[0],
};
#endif /* CAN1_USE_RX_BUFFER */
#if CAN1_BUFFER_BYPASS_NUMBER_OF_IDs > 0
uint8_t can1_fastLinkIndex[CAN1_BUFFER_BYPASS_NUMBER_OF_IDs]; /* Link Table for bufferBypassing */
#endif
CAN_ERROR_s CAN1_errorStruct = {
.canError = HAL_CAN_ERROR_NONE,
.canErrorCounter = { 0, 0, 0, 0, 0, 0, 0, 0, 0 },
};
#endif /* CAN_USE_CAN_NODE1 */
/* ***********************************************************
* Dummies for filter initialization and message reception
*************************************************************/
CAN_FilterTypeDef sFilterConfig = {
/* No need to insert here something */
.FilterActivation = ENABLE, /* enable the filter */
};
/*================== Function Prototypes ==================================*/
/* Inits */
static uint8_t CAN_GetNextID(CAN_MSG_RX_TYPE_s* can_RxMsgs, uint8_t numberOfRxIDs, uint8_t startIndex,
uint8_t filterCase);
static uint8_t CAN_NumberOfNeededFilters(CAN_MSG_RX_TYPE_s* can_RxMsgs, uint8_t* numberOfDifferentIDs, uint32_t* error);
static uint32_t CAN_InitFilter(CAN_HandleTypeDef* ptrHcan, CAN_MSG_RX_TYPE_s* can_RxMsgs, uint8_t numberOfRxMsgs);
/* Interrupts */
static void CAN_TxCpltCallback(CAN_NodeTypeDef_e canNode);
static void CAN_RxMsg(CAN_NodeTypeDef_e canNode, CAN_HandleTypeDef* ptrHcan, uint8_t FIFONumber);
/* Buffer/Interpreter */
static STD_RETURN_TYPE_e CAN_BufferBypass(CAN_NodeTypeDef_e canNode, uint32_t msgID, uint8_t* rxData, uint8_t DLC,
uint8_t RTR);
static STD_RETURN_TYPE_e CAN_InterpretReceivedMsg(CAN_NodeTypeDef_e canNode, uint32_t msgID, uint8_t* data, uint8_t DLC,
uint8_t RTR);
/*================== Function Implementations =============================*/
/* ***************************************
* Initialization
****************************************/
uint32_t CAN_Init(void) {
uint32_t retval = 0;
#if CAN_USE_CAN_NODE0
/* DeInit CAN0 handle */
if (HAL_CAN_DeInit(&hcan0) != HAL_OK) {
/* Error deintializing handle -> set error bit */
retval |= STD_ERR_BIT_0;
}
/* Init CAN0-handle */
if (HAL_CAN_Init(&hcan0) != HAL_OK) {
/* Error intializing handle -> set error bit */
retval |= STD_ERR_BIT_1;
}
/* Configure CAN0 hardware filter */
retval |= CAN_InitFilter(&hcan0, &can0_RxMsgs[0], can_CAN0_rx_length);
/* Check if more rx messages are bypassed than received */
#pragma GCC diagnostic push
/* configurations might exist that use this comparison */
#pragma GCC diagnostic ignored "-Wtype-limits"
if (CAN0_BUFFER_BYPASS_NUMBER_OF_IDs > can_CAN0_rx_length) {
#pragma GCC diagnostic pop
retval |= STD_ERR_BIT_7;
}
/* Enable CAN0 message receive interrupt FIFO0 */
if (HAL_CAN_ActivateNotification(&hcan0, CAN_IT_RX_FIFO0_MSG_PENDING) != HAL_OK) {
retval |= STD_ERR_BIT_8;
}
hcan0.State = HAL_CAN_STATE_READY;
/* Enable CAN0 message receive interrupt FIFO1 */
if (HAL_CAN_ActivateNotification(&hcan0, CAN_IT_RX_FIFO1_MSG_PENDING) != HAL_OK) {
retval |= STD_ERR_BIT_9;
}
/* Enable CAN0 Transmit mailbox empty interrupt */
if (HAL_CAN_ActivateNotification(&hcan0, CAN_IT_TX_MAILBOX_EMPTY) != HAL_OK) {
retval |= STD_ERR_BIT_10;
}
/* set DBF bit to 0 for CAN activity while in debug mode */
CLEAR_BIT(hcan0.Instance->MCR, CAN_MCR_DBF);
#if CAN_USE_STANDBY_CONTROL == 1
IO_WritePin(CAN_0_TRANS_STANDBY_CONTROL, IO_PIN_SET);
#endif /* CAN_USE_STANDBY_CONTROL == 1 */
/* Start CAN */
HAL_CAN_Start(&hcan0);
#endif /* CAN_USE_CAN_NODE0 */
#if CAN_USE_CAN_NODE1
/* DeInit CAN1 handle */
if (HAL_CAN_DeInit(&hcan1) != HAL_OK) {
/* Error deintializing handle -> set error bit */
retval |= STD_ERR_BIT_11;
}
/* Init CAN1-handle */
if (HAL_CAN_Init(&hcan1) != HAL_OK) {
/* Error intializing handle -> set error bit */
retval |= STD_ERR_BIT_12;
}
/* Configure CAN1 hardware filter */
retval |= CAN_InitFilter(&hcan1, &can1_RxMsgs[0], can_CAN1_rx_length);
/* Check if more RX messages are bypassed than received */
#pragma GCC diagnostic push
/* configurations might exist that use this comparison */
#pragma GCC diagnostic ignored "-Wtype-limits"
if (CAN1_BUFFER_BYPASS_NUMBER_OF_IDs > can_CAN1_rx_length) {
#pragma GCC diagnostic pop
retval |= STD_ERR_BIT_13;
}
/* Enable CAN1 message receive interrupt FIFO0 */
if (HAL_CAN_ActivateNotification(&hcan1, CAN_IT_RX_FIFO0_MSG_PENDING) != HAL_OK) {
retval |= STD_ERR_BIT_14;
}
/* Enable CAN1 message receive interrupt FIFO1 */
hcan1.State = HAL_CAN_STATE_READY;
if (HAL_CAN_ActivateNotification(&hcan1, CAN_IT_RX_FIFO1_MSG_PENDING) != HAL_OK) {
retval |= STD_ERR_BIT_15;
}
/* Enable CAN1 Transmit mailbox empty interrupt */
if (HAL_CAN_ActivateNotification(&hcan1, CAN_IT_TX_MAILBOX_EMPTY) != HAL_OK) {
retval |= STD_ERR_BIT_16;
}
/* set DBF bit to 0 for CAN activity while in debug mode */
CLEAR_BIT(hcan1.Instance->MCR, CAN_MCR_DBF);
#if CAN_USE_STANDBY_CONTROL == 1
IO_WritePin(CAN_1_TRANS_STANDBY_CONTROL, IO_PIN_SET);
#endif /* CAN_USE_STANDBY_CONTROL == 1 */
/* Start CAN */
HAL_CAN_Start(&hcan1);
#endif /* CAN_USE_CAN_NODE1 */
return retval;
}
/**
* @brief Initializes message filtering
* @retval 0: if no error occurred, otherwise error code
*/
static uint32_t CAN_InitFilter(CAN_HandleTypeDef* ptrHcan, CAN_MSG_RX_TYPE_s* can_RxMsgs, uint8_t numberOfRxMsgs) {
/* Contains the occurrence of of the different filter cases *
* [0] - ID List mode 16bit routed on FIFO0 *
* [1] - ID List mode 16bit routed on FIFO1 *
* [2] - ID List mode 32bit routed on FIFO0 *
* [3] - ID List mode 32bit routed on FIFO1 *
* [4] - Mask mode 16bit routed on FIFO0 *
* [5] - Mask mode 16bit routed on FIFO1 *
* [6] - Mask mode 32bit */
uint8_t numberOfDifferentIDs[7] = { 0, 0, 0, 0, 0, 0, 0 };
static uint8_t filterNumber = 0; /* Number of the filter to be initialized */
uint32_t retval = 0;
/* Calculate number of needed filter banks */
uint8_t numberNeededFilters = CAN_NumberOfNeededFilters(can_RxMsgs, &numberOfDifferentIDs[0], &retval);
numberNeededFilters--; /* Decrement by one because IS_CAN_FILTER_BANK_DUAL checks filter bank numbers starting with 0 */
if (IS_CAN_FILTER_BANK_DUAL(numberNeededFilters)) {
uint8_t j = 0; /* Counts the number of initialized instances per case */
uint8_t posRxMsgs = 0; /* Iterator for can_RxMsgs[] */
uint8_t numberRegistersUsed = 0; /* Counts how many register space is already used in each filter bank (max. 64bit) */
uint8_t caseID = 0; /* indicates the actual filter mode that will be initialized */
if (ptrHcan->Instance == CAN2) {
/* Set start slave bank filter */
sFilterConfig.FilterBank = filterNumber;
}
for (caseID = 0; caseID < 2u; caseID++) {
/* ID List mode 16bit routed on FIFO0 or FIFO1 */
if (numberOfDifferentIDs[caseID] > 0U) {
j = 0;
while (j < numberOfDifferentIDs[caseID]) {
/* Until all IDs in that filter case are treated */
posRxMsgs = CAN_GetNextID(can_RxMsgs, numberOfRxMsgs, posRxMsgs, caseID); /* Get array position of next ID */
switch (numberRegistersUsed) {
case 0: /* 1st ID per filter bank */
sFilterConfig.FilterIdHigh = ((can_RxMsgs[posRxMsgs].ID << 5)
| can_RxMsgs[posRxMsgs].RTR << 4);
j++;
break;
case 1: /* 2nd ID */
sFilterConfig.FilterIdLow = ((can_RxMsgs[posRxMsgs].ID << 5)
| can_RxMsgs[posRxMsgs].RTR << 4);
j++;
break;
case 2: /* 3rd ID */
sFilterConfig.FilterMaskIdHigh = ((can_RxMsgs[posRxMsgs].ID << 5)
| can_RxMsgs[posRxMsgs].RTR << 4);
j++;
break;
case 3: /* 4th ID */
sFilterConfig.FilterMaskIdLow = ((can_RxMsgs[posRxMsgs].ID << 5)
| can_RxMsgs[posRxMsgs].RTR << 4);
j++;
break;
}
numberRegistersUsed = j % 4U; /* space for 4 IDs a 16 bit in one filter bank */
if ((numberRegistersUsed == 0 && j > 1U) || (j == numberOfDifferentIDs[caseID])) {
/* all registers in filter bank used OR no more IDs in that case */
sFilterConfig.FilterMode = CAN_FILTERMODE_IDLIST;
sFilterConfig.FilterScale = CAN_FILTERSCALE_16BIT;
if (caseID == ID_16BIT_FIFO0) {
sFilterConfig.FilterFIFOAssignment = CAN_FILTER_FIFO0;
} else if (caseID == ID_16BIT_FIFO1) {
sFilterConfig.FilterFIFOAssignment = CAN_FILTER_FIFO1;
}
sFilterConfig.FilterBank = filterNumber;
HAL_CAN_ConfigFilter(ptrHcan, &sFilterConfig); /* initialize filter bank */
filterNumber++; /* increment filter number */
}
posRxMsgs++; /* increment array position to find next valid ID */
}
posRxMsgs = 0; /* reset variables for next case */
numberRegistersUsed = 0;
}
}
for (caseID = 2; caseID < 6U; caseID++) {
/* ID List mode 32bit routed on FIFO0 or FIFO1; Mask mode 16bit routed on FIFO0 or FIFO1 */
j = 0;
if (numberOfDifferentIDs[caseID] > 0U) {
while (j < numberOfDifferentIDs[caseID]) {
/* Until all IDs in that filter case are treated */
posRxMsgs = CAN_GetNextID(can_RxMsgs, numberOfRxMsgs, posRxMsgs, caseID); /* Get array position of next ID */
switch (numberRegistersUsed) {
case 0: /* first 32bit per filter bank */
if (caseID == ID_32BIT_FIFO0 || caseID == ID_32BIT_FIFO1) { /* list mode 32bit */
sFilterConfig.FilterIdHigh = ((can_RxMsgs[posRxMsgs].ID << 3) >> 16); /* 1 << 2 is for setting IDE bit to receive extended identifiers */
sFilterConfig.FilterIdLow = (uint16_t)((can_RxMsgs[posRxMsgs].ID << 3) | 1 << 2
| can_RxMsgs[posRxMsgs].RTR << 1);
} else if (caseID == MSK_16BIT_FIFO0 || caseID == MSK_16BIT_FIFO1) { /* mask mode 16bit */
sFilterConfig.FilterIdHigh = ((can_RxMsgs[posRxMsgs].ID << 5)
| can_RxMsgs[posRxMsgs].RTR << 4);
sFilterConfig.FilterMaskIdHigh = can_RxMsgs[posRxMsgs].mask;
sFilterConfig.FilterIdLow = 0x0000; /* set second register to 0xFFFF, */
sFilterConfig.FilterMaskIdLow = 0xFFFF; /* otherwise all messages would be received */
}
j++;
break;
case 1: /* second 32bit per filter bank */
if (caseID == ID_32BIT_FIFO0 || caseID == ID_32BIT_FIFO1) { /* list mode 32bit */
sFilterConfig.FilterMaskIdHigh = ((can_RxMsgs[posRxMsgs].ID << 3) >> 16); /* 1 << 2 is for setting IDE bit to receive extended identifiers */
sFilterConfig.FilterMaskIdLow = (uint16_t)((can_RxMsgs[posRxMsgs].ID << 3) | 1 << 2
| can_RxMsgs[posRxMsgs].RTR << 1);
} else if (caseID == MSK_16BIT_FIFO0 || caseID == MSK_16BIT_FIFO1) { /* mask mode 16bit */
sFilterConfig.FilterIdLow = ((can_RxMsgs[posRxMsgs].ID << 5)
| can_RxMsgs[posRxMsgs].RTR << 4);
sFilterConfig.FilterMaskIdLow = can_RxMsgs[posRxMsgs].mask;
}
j++;
break;
}
numberRegistersUsed = j % 2; /* Space for two IDs a 32bit or two mask a 16bit */
if ((numberRegistersUsed == 0 && j > 1U) || (j == numberOfDifferentIDs[caseID])) {
/* all registers in filter bank used OR no more IDs in that case */
if (caseID == ID_32BIT_FIFO0 || caseID == ID_32BIT_FIFO1) {
sFilterConfig.FilterMode = CAN_FILTERMODE_IDLIST;
sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT;
if (caseID == ID_32BIT_FIFO0)
sFilterConfig.FilterFIFOAssignment = CAN_FILTER_FIFO0;
else
sFilterConfig.FilterFIFOAssignment = CAN_FILTER_FIFO1;
} else if (caseID == MSK_16BIT_FIFO0 || caseID == MSK_16BIT_FIFO1) {
sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;
sFilterConfig.FilterScale = CAN_FILTERSCALE_16BIT;
if (caseID == MSK_16BIT_FIFO0)
sFilterConfig.FilterFIFOAssignment = CAN_FILTER_FIFO0;
else
sFilterConfig.FilterFIFOAssignment = CAN_FILTER_FIFO1;
}
sFilterConfig.FilterBank = filterNumber;
HAL_CAN_ConfigFilter(ptrHcan, &sFilterConfig); /* initialize filter bank */
filterNumber++; /* increment filter number */
}
posRxMsgs++; /* increment array position to find next valid ID */
}
posRxMsgs = 0; /* reset variables for next case */
numberRegistersUsed = 0;
}
}
j = 0;
if (numberOfDifferentIDs[MSK_32BIT] > 0U) {
/* Mask mode 32bit */
while (j < numberOfDifferentIDs[MSK_32BIT]) { /* Get array position of next ID */
/* Until all IDs in that filter case are treated */
posRxMsgs = CAN_GetNextID(can_RxMsgs, numberOfRxMsgs, posRxMsgs, MSK_32BIT);
sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;
sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT;
sFilterConfig.FilterIdHigh = ((can_RxMsgs[posRxMsgs].ID << 3) >> 16); /* 1 << 2 is for setting IDE bit to receive extended identifiers */
sFilterConfig.FilterIdLow = (uint16_t)((can_RxMsgs[posRxMsgs].ID << 3) | 1 << 2
| can_RxMsgs[posRxMsgs].RTR << 1);
sFilterConfig.FilterMaskIdHigh = can_RxMsgs[posRxMsgs].mask >> 16;
sFilterConfig.FilterMaskIdLow = (uint16_t)(can_RxMsgs[posRxMsgs].mask);
sFilterConfig.FilterFIFOAssignment = can_RxMsgs[posRxMsgs].fifo;
sFilterConfig.FilterBank = filterNumber;
HAL_CAN_ConfigFilter(ptrHcan, &sFilterConfig);
filterNumber++;
posRxMsgs++;
j++;
}
}
} else {
/* Too many filterbanks needed! Check the value of CAN_NUMBER_OF_FILTERBANKS */
/* If correct, try to reduce the IDs through masks or optimize used filter bank space. */
/* Number of different filter cases can be evaluated in numberOfDifferentIDs[]. One */
/* filter bank can filter as many messages as followed: */
/* 4 IDs in list mode 16bit */
/* 2 IDs in list mode 32bit and mask mode 16bit */
/* 1 ID in 32bit mask mode */
retval |= STD_ERR_BIT_6;
}
return retval;
}
/**
* @brief Returns the number of filters that have to be initialized
*
* @param can_RxMsgs: pointer to receive message struct
* @param numberOfDifferentIDs: pointer to array, where to store the specific number of different IDs
*
* @retval number of needed filters
*/
static uint8_t CAN_NumberOfNeededFilters(CAN_MSG_RX_TYPE_s* can_RxMsgs, uint8_t* numberOfDifferentIDs, uint32_t* error) {
static uint8_t retVal = 0; /* static so save the number of filters from CAN0 and add to the ones from CAN1 */
uint16_t can_rx_length = 0;
if (can_RxMsgs == &can0_RxMsgs[0]) {
can_rx_length = can_CAN0_rx_length;
} else if (can_RxMsgs == &can1_RxMsgs[0]) {
can_rx_length = can_CAN1_rx_length;
} else {
can_rx_length = 0;
}
for (uint8_t i = 0; i < can_rx_length; i++) {
#if (CAN0_BUFFER_BYPASS_NUMBER_OF_IDs > 0) && (CAN_USE_CAN_NODE0 == 1)
if (can_RxMsgs == &can0_RxMsgs[0]) {
/* Set buffer bypass IDs link table */
for (uint8_t k = 0; k < CAN0_BUFFER_BYPASS_NUMBER_OF_IDs; k++) {
if (can_RxMsgs[i].ID == can0_bufferBypass_RxMsgs[k]) {
/* bypass ID == ID in message receive struct */
can0_fastLinkIndex[k] = i; /* set for can_bufferBypass_RxMsgs[k] link to array index */
break;
}
}
}
#endif /* (CAN0_BUFFER_BYPASS_NUMBER_OF_IDs > 0) && (CAN_USE_CAN_NODE0 == 1) */
#if (CAN1_BUFFER_BYPASS_NUMBER_OF_IDs > 0) && (CAN_USE_CAN_NODE1 == 1)
if (can_RxMsgs == &can1_RxMsgs[0]) {
/* Set buffer bypass IDs link table */
for (int k = 0; k < CAN1_BUFFER_BYPASS_NUMBER_OF_IDs; k++) {
if (can1_RxMsgs[i].ID == can1_bufferBypass_RxMsgs[k]) {
/* bypass ID == ID in message receive struct */
can1_fastLinkIndex[k] = i; /* set for can1_bufferBypass_RxMsgs[k] link to array index */
break;
}
}
}
#endif /* (CAN1_BUFFER_BYPASS_NUMBER_OF_IDs > 0) && (CAN_USE_CAN_NODE1 == 1) */
if (can_RxMsgs[i].mask == 0 && IS_CAN_STDID(can_RxMsgs[i].ID)) {
/* ID List mode 16bit */
if (can_RxMsgs[i].fifo == CAN_FILTER_FIFO0) {
numberOfDifferentIDs[ID_16BIT_FIFO0]++;
} else if (can_RxMsgs[i].fifo == CAN_FILTER_FIFO1) {
numberOfDifferentIDs[ID_16BIT_FIFO1]++;
} else {
/* Invalid FIFO selection; check can_RxMsgs[i].fifo value */
*error |= STD_ERR_BIT_2;
}
} else if ((can_RxMsgs[i].mask == 0) && IS_CAN_EXTID(can_RxMsgs[i].ID)) {
/* ID List mode 32bit */
if (can_RxMsgs[i].fifo == CAN_FILTER_FIFO0) {
numberOfDifferentIDs[ID_32BIT_FIFO0]++;
} else if (can_RxMsgs[i].fifo == CAN_FILTER_FIFO1) {
numberOfDifferentIDs[ID_32BIT_FIFO1]++;
} else {
/* Invalid FIFO selection; check can_RxMsgs[i].fifo value */
*error |= STD_ERR_BIT_3;
}
} else if (can_RxMsgs[i].mask > 0 && IS_CAN_STDID(can_RxMsgs[i].ID)) {
/* Mask mode 16bit */
if (can_RxMsgs[i].fifo == CAN_FILTER_FIFO0) {
numberOfDifferentIDs[MSK_16BIT_FIFO0]++;
} else if (can_RxMsgs[i].fifo == CAN_FILTER_FIFO1) {
numberOfDifferentIDs[MSK_16BIT_FIFO1]++;
} else {
/* Invalid FIFO selection; check can_RxMsgs[i].fifo value */
*error |= STD_ERR_BIT_4;
}
} else if ((can_RxMsgs[i].mask > 0U) && IS_CAN_EXTID(can_RxMsgs[i].ID)) {
/* Mask mode 32bit */
numberOfDifferentIDs[MSK_32BIT]++;
} else {
/* Invalid ID > IS_CAN_EXTID; check can_RxMsgs[i].ID value */
*error |= STD_ERR_BIT_5;
break;
}
}
for (uint8_t i = 0; i < 2U; i++) {
if (numberOfDifferentIDs[i] > 0U) {
retVal += (numberOfDifferentIDs[i] + 2) / 4; /* 4 IDs per filter; rounding up */
}
}
for (uint8_t i = 2; i < 6U; i++) {
if (numberOfDifferentIDs[i] > 0U) {
retVal += (numberOfDifferentIDs[i] + 1) / 2; /* 2 IDs per filter; rounding up */
}
}
if (numberOfDifferentIDs[MSK_32BIT] > 0U) {
retVal += numberOfDifferentIDs[6]; /* 1 ID per filter */
}
return retVal;
}
/**
* @brief Returns the next index of wished filter ID setting in CAN_MSG_RX_TYPE_t can_RxMsgs[CAN_NUMBER_OF_RX_IDs]
*
* @param can_RxMsgs: pointer to receive message struct
* @param numberOfRxIDs: count of that type of receive message in can_RxMsgs struct
* @param startIndex: index where to start searching
* @param filterCase: specifies the object what will be found
*
* @retval returns index
*/
static uint8_t CAN_GetNextID(CAN_MSG_RX_TYPE_s* can_RxMsgs, uint8_t numberOfRxIDs, uint8_t startIndex,
uint8_t filterCase) {
uint8_t retVal = 0;
uint8_t i = startIndex;
while (i < numberOfRxIDs) {
if ((filterCase == ID_16BIT_FIFO0 && can_RxMsgs[i].mask == 0U) && IS_CAN_STDID(can_RxMsgs[i].ID) && (can_RxMsgs[i].fifo == CAN_FILTER_FIFO0)) {
retVal = i;
break;
} else if ((filterCase == ID_16BIT_FIFO1) && (can_RxMsgs[i].mask == 0U) && IS_CAN_STDID(can_RxMsgs[i].ID) && (can_RxMsgs[i].fifo == CAN_FILTER_FIFO1)) {
retVal = i;
break;
} else if ((filterCase == ID_32BIT_FIFO0) && (can_RxMsgs[i].mask == 0U) && !IS_CAN_STDID(can_RxMsgs[i].ID) && IS_CAN_EXTID(can_RxMsgs[i].ID) && (can_RxMsgs[i].fifo == CAN_FILTER_FIFO0)) {
retVal = i;
break;
} else if ((filterCase == ID_32BIT_FIFO1) && (can_RxMsgs[i].mask == 0U) && !IS_CAN_STDID(can_RxMsgs[i].ID) && IS_CAN_EXTID(can_RxMsgs[i].ID) && (can_RxMsgs[i].fifo == CAN_FILTER_FIFO1)) {
retVal = i;
break;
} else if ((filterCase == MSK_16BIT_FIFO0) && (can_RxMsgs[i].mask > 0U) && IS_CAN_STDID(can_RxMsgs[i].ID) && (can_RxMsgs[i].fifo == CAN_FILTER_FIFO0)) {
retVal = i;
break;
} else if ((filterCase == MSK_16BIT_FIFO1) && (can_RxMsgs[i].mask > 0U) && IS_CAN_STDID(can_RxMsgs[i].ID) && (can_RxMsgs[i].fifo == CAN_FILTER_FIFO1)) {
retVal = i;
break;
} else if ((filterCase == MSK_32BIT) && (can_RxMsgs[i].mask > 0U) && !IS_CAN_STDID(can_RxMsgs[i].ID) && IS_CAN_EXTID(can_RxMsgs[i].ID)) {
retVal = i;
break;
}
i++;
}
return retVal;
}
/* ***************************************
* Interrupt handling
****************************************/
/**
* @brief Transmission Mailbox 0 complete callback.
* @param hcan pointer to a CAN_HandleTypeDef structure that contains
* the configuration information for the specified CAN.
* @retval None
*/
void HAL_CAN_TxMailbox0CompleteCallback(CAN_HandleTypeDef *hcan) {
#if CAN0_USE_TX_BUFFER
if (hcan->Instance == CAN2) {
CAN_TxCpltCallback(CAN_NODE0);
}
#endif /* CAN0_USE_TX_BUFFER */
#if CAN1_USE_TX_BUFFER
/* No need for callback, if no buffer is used */
if (hcan->Instance == CAN1) {
/* Transmission complete callback */
CAN_TxCpltCallback(CAN_NODE1);
}
#endif /* CAN1_USE_TX_BUFFER */
}
/**
* @brief Transmission Mailbox 1 complete callback.
* @param hcan pointer to a CAN_HandleTypeDef structure that contains
* the configuration information for the specified CAN.
* @retval None
*/
void HAL_CAN_TxMailbox1CompleteCallback(CAN_HandleTypeDef *hcan) {
#if CAN0_USE_TX_BUFFER
if (hcan->Instance == CAN2) {
CAN_TxCpltCallback(CAN_NODE0);
}
#endif /* CAN0_USE_TX_BUFFER */
#if CAN1_USE_TX_BUFFER
/* No need for callback, if no buffer is used */
if (hcan->Instance == CAN1) {
/* Transmission complete callback */
CAN_TxCpltCallback(CAN_NODE1);
}
#endif /* CAN1_USE_TX_BUFFER */
}
/**
* @brief Transmission Mailbox 2 complete callback.
* @param hcan pointer to a CAN_HandleTypeDef structure that contains
* the configuration information for the specified CAN.
* @retval None
*/
void HAL_CAN_TxMailbox2CompleteCallback(CAN_HandleTypeDef *hcan) {
#if CAN0_USE_TX_BUFFER
if (hcan->Instance == CAN2) {
CAN_TxCpltCallback(CAN_NODE0);
}
#endif /* CAN0_USE_TX_BUFFER */
#if CAN1_USE_TX_BUFFER
/* No need for callback, if no buffer is used */
if (hcan->Instance == CAN1) {
/* Transmission complete callback */
CAN_TxCpltCallback(CAN_NODE1);
}
#endif /* CAN1_USE_TX_BUFFER */
}
/**
* @brief Rx FIFO 0 message pending callback.
* @param hcan pointer to a CAN_HandleTypeDef structure that contains
* the configuration information for the specified CAN.
* @retval None
*/
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan) {
/* Call callback function to interpret or save RX message in buffer */
if (hcan->Instance == CAN2) {
CAN_RxMsg(CAN_NODE0, hcan, CAN_RX_FIFO0); /* change towards HAL_CAN_IRQHandler */
}
if (hcan->Instance == CAN1) {
CAN_RxMsg(CAN_NODE1, hcan, CAN_RX_FIFO0); /* change towards HAL_CAN_IRQHandler */
}
}
/**
* @brief Rx FIFO 1 message pending callback.
* @param hcan pointer to a CAN_HandleTypeDef structure that contains
* the configuration information for the specified CAN.
* @retval None
*/
void HAL_CAN_RxFifo1MsgPendingCallback(CAN_HandleTypeDef *hcan) {
/* Call callback function to interpret or save RX message in buffer */
if (hcan->Instance == CAN2) {
CAN_RxMsg(CAN_NODE0, hcan, CAN_RX_FIFO1); /* change towards HAL_CAN_IRQHandler */
}
if (hcan->Instance == CAN1) {
CAN_RxMsg(CAN_NODE1, hcan, CAN_RX_FIFO1); /* change towards HAL_CAN_IRQHandler */
}
}
/**
* @brief Error CAN callback.
* @param hcan pointer to a CAN_HandleTypeDef structure that contains
* the configuration information for the specified CAN.
* @retval None
*/
void HAL_CAN_ErrorCallback(CAN_HandleTypeDef *hcan) {
CAN_ERROR_s* errorStruct = NULL_PTR;
if (hcan->Instance == CAN1) {
#if CAN_USE_CAN_NODE1 == 1
errorStruct = &CAN1_errorStruct;
#endif /* CAN_USE_CAN_NODE1 == 1 */
} else {
#if CAN_USE_CAN_NODE0 == 1
errorStruct = &CAN0_errorStruct;
#endif /* CAN_USE_CAN_NODE0 == 1 */
}
/* Check Error Warning flag and set error codes */
if (errorStruct != NULL_PTR) {
/* Check Error Warning Flag */
if ((hcan->ErrorCode & HAL_CAN_ERROR_EWG) != 0) {
/* This bit is set by hardware when the warning limit has been
* reached (Receive Error Counter or Transmit Error Counter>=96
* until error counter 127 write error frames dominant on can bus
* increment error occurrence of error warning state */
errorStruct->canErrorCounter[0]++;
}
/* Check Error Passive Flag */
if ((hcan->ErrorCode & HAL_CAN_ERROR_EPV) != 0) {
/* This bit is set by hardware when the Error Passive limit has
* been reached (Receive Error Counter or Transmit Error Counter
* > 127) write error frames recessive on can bus increment error
* occurrence of error passive state */
errorStruct->canErrorCounter[1]++;
}
/* Check Bus-Off Flag */
if ((hcan->ErrorCode & HAL_CAN_ERROR_BOF) != 0) {
/* This bit is set by hardware when it enters the bus-off state.
* The bus-off state is entered on TEC overflow, greater than 255
* increment error occurrence of bus-off state */
errorStruct->canErrorCounter[2]++;
}
/* Check stuff error flag */
if ((hcan->ErrorCode & HAL_CAN_ERROR_STF) != 0) {
/* When five consecutive bits of the same level have been
* transmitted by a node, it will add a sixth bit of the opposite
* level to the outgoing bit stream. The receivers will remove this
* extra bit.This is done to avoid excessive DC components on the
* bus, but it also gives the receivers an extra opportunity to
* detect errors: if more than five consecutive bits of the same
* level occurs on the bus, a Stuff Error is signaled. */
errorStruct->canErrorCounter[3]++;
}
if ((hcan->ErrorCode & HAL_CAN_ERROR_FOR) != 0) {
/* FORM ERROR --- Some parts of the CAN message have a fixed format,
* i.e. the standard defines exactly what levels must occur and
* when. (Those parts are the CRC Delimiter, ACK Delimiter, End of
* Frame, and also the Intermission, but there are some extra
* special error checking rules for that.) If a CAN controller
* detects an invalid value in one of these fixed fields, a Form
* Error is signaled. */
errorStruct->canErrorCounter[4]++;
}
if ((hcan->ErrorCode & HAL_CAN_ERROR_ACK) != 0) {
/* ACKNOWLEDGMENT ERROR --- All nodes on the bus that correctly
* receives a message (regardless of their being interested of its
* contents or not) are expected to send a dominant level in the
* so-called Acknowledgement Slot in the message. The transmitter
* will transmit a recessive level here. If the transmitter can
* detect a dominant level in the ACK slot, an Acknowledgement
* Error is signaled. */
errorStruct->canErrorCounter[5]++;
}
if ((hcan->ErrorCode & HAL_CAN_ERROR_BR) != 0) {
/* BIT RECESSIVE ERROR --- Each transmitter on the CAN bus monitors
* (i.e. reads back) the transmitted signal level. If the bit level
* actually read differs from the one transmitted, a Bit Error (No
* bit error is raised during the arbitration process.) */
errorStruct->canErrorCounter[6]++;
}
if ((hcan->ErrorCode & HAL_CAN_ERROR_BD) != 0) {
/* BIT DOMINANT ERROR --- Each transmitter on the CAN bus monitors
* (i.e. reads back) the transmitted signal level. If the bit level
* actually read differs from the one transmitted, a Bit Error (No
* bit error is raised during the arbitration process.) */
errorStruct->canErrorCounter[7]++;
}
if ((hcan->ErrorCode & HAL_CAN_ERROR_CRC) != 0) {
/* CRC ERROR --- Each message features a 15-bit Cyclic Redundancy
* Checksum (CRC), and any node that detects a different CRC in the
* message than what it has calculated itself will signal an CRC
* Error. */
errorStruct->canErrorCounter[8]++;
}
if ((hcan->ErrorCode & HAL_CAN_ERROR_RX_FOV0) != 0) {
/* Rx FIFO0 overrun error */
errorStruct->canErrorCounter[9]++;
}
if ((hcan->ErrorCode & HAL_CAN_ERROR_RX_FOV1) != 0) {
/* Rx FIFO1 overrun error */
errorStruct->canErrorCounter[10]++;
}
if ((hcan->ErrorCode & HAL_CAN_ERROR_TX_ALST0) != 0) {
/* TxMailbox 0 transmit failure due to arbitration lost */
errorStruct->canErrorCounter[11]++;
}
if ((hcan->ErrorCode & HAL_CAN_ERROR_TX_TERR0) != 0) {
/* TxMailbox 1 transmit failure due to transmit error */
errorStruct->canErrorCounter[12]++;
}
if ((hcan->ErrorCode & HAL_CAN_ERROR_TX_ALST1) != 0) {
/* TxMailbox 0 transmit failure due to arbitration lost */
errorStruct->canErrorCounter[13]++;
}
if ((hcan->ErrorCode & HAL_CAN_ERROR_TX_TERR1) != 0) {
/* TxMailbox 1 transmit failure due to transmit error */
errorStruct->canErrorCounter[14]++;
}
if ((hcan->ErrorCode & HAL_CAN_ERROR_TX_ALST2) != 0) {
/* TxMailbox 0 transmit failure due to arbitration lost */
errorStruct->canErrorCounter[15]++;
}
if ((hcan->ErrorCode & HAL_CAN_ERROR_TX_TERR2) != 0) {
/* TxMailbox 1 transmit failure due to transmit error */
errorStruct->canErrorCounter[16]++;
}
if ((hcan->ErrorCode & HAL_CAN_ERROR_TIMEOUT) != 0) {
/* Timeout error */
errorStruct->canErrorCounter[17]++;
}
if ((hcan->ErrorCode & HAL_CAN_ERROR_NOT_INITIALIZED) != 0) {
/* Peripheral not initialized */
errorStruct->canErrorCounter[18]++;
}
if ((hcan->ErrorCode & HAL_CAN_ERROR_NOT_READY) != 0) {
/* Peripheral not ready */
errorStruct->canErrorCounter[19]++;
}
if ((hcan->ErrorCode & HAL_CAN_ERROR_NOT_STARTED) != 0) {
/* Peripheral not started */
errorStruct->canErrorCounter[20]++;
}
if ((hcan->ErrorCode & HAL_CAN_ERROR_PARAM) != 0) {
/* Parameter error */
errorStruct->canErrorCounter[21]++;
}
}
}
/**
* @brief Transmission complete callback in non blocking mode
*
* @param canNode: canNode that transmitted a message
*
* @retval none (void)
*/
static void CAN_TxCpltCallback(CAN_NodeTypeDef_e canNode) {
STD_RETURN_TYPE_e retVal = E_NOT_OK;
CAN_TX_BUFFER_s* can_txbuffer = NULL;
if (canNode == CAN_NODE0) {
#if CAN_USE_CAN_NODE0 == 1
can_txbuffer = &can0_txbuffer;
#endif /* #if CAN_USE_CAN_NODE0 == 1 */
} else if (canNode == CAN_NODE1) {
#if CAN_USE_CAN_NODE1 == 1
can_txbuffer = &can1_txbuffer;
#endif /* CAN_USE_CAN_NODE1 == 1 */
}
/* Transmit buffer existing, check if message is ready for transmission */
if (can_txbuffer != NULL) {
/* No Error during start of transmission */
if ((can_txbuffer->ptrWrite == can_txbuffer->ptrRead)
&& (can_txbuffer->buffer[can_txbuffer->ptrRead].newMsg == 0)) {
/* nothing to transmit, buffer is empty */
retVal = E_NOT_OK;
} else {
retVal = CAN_TxMsgBuffer(canNode);
if (retVal != E_OK) {
/* Error during transmission, retransmit message later */
retVal = E_NOT_OK;
}
}
} else {
/* no transmit buffer active */
retVal = E_NOT_OK;
}
}
/* ***************************************
* Transmit message
****************************************/
STD_RETURN_TYPE_e CAN_TxMsg(CAN_NodeTypeDef_e canNode, uint32_t msgID, uint8_t* ptrMsgData, uint32_t msgLength,
uint32_t RTR) {
STD_RETURN_TYPE_e retVal = E_NOT_OK;
CAN_TxHeaderTypeDef canMessage;
CAN_HandleTypeDef *ptrHcan;
uint32_t freeMailboxes = 0;
uint32_t *ptrMailbox = NULL_PTR;
if (canNode == CAN_NODE0) {
if (canNode0_listenonly_mode) {
ptrHcan = NULL;
} else {
/* Check if at least one mailbox is free */
freeMailboxes = HAL_CAN_GetTxMailboxesFreeLevel(&hcan0);
if (freeMailboxes != 0) {
ptrHcan = &hcan0;
} else {
ptrHcan = NULL;
}
}
} else if (canNode == CAN_NODE1) {
if (canNode1_listenonly_mode) {
ptrHcan = NULL;
} else {
/* Check if at least one mailbox is free */
freeMailboxes = HAL_CAN_GetTxMailboxesFreeLevel(&hcan1);
if (freeMailboxes != 0) {
ptrHcan = &hcan1;
} else {
ptrHcan = NULL;
}
}
} else {
ptrHcan = NULL;
}
if ((IS_CAN_STDID(msgID) || IS_CAN_EXTID(msgID)) && IS_CAN_DLC(msgLength) && ptrHcan != NULL) {
if (IS_CAN_STDID(msgID)) {
canMessage.StdId = msgID;
canMessage.IDE = CAN_ID_STD;
} else {
canMessage.ExtId = msgID;
canMessage.IDE = CAN_ID_EXT;
}
canMessage.DLC = msgLength;
canMessage.RTR = RTR;
canMessage.TransmitGlobalTime = DISABLE;
/* Copy message in TX mailbox and transmit it */
HAL_CAN_AddTxMessage(ptrHcan, &canMessage, ptrMsgData, ptrMailbox);
} else {
retVal = E_NOT_OK;
}
return retVal;
}
STD_RETURN_TYPE_e CAN_Send(CAN_NodeTypeDef_e canNode, uint32_t msgID, uint8_t* ptrMsgData, uint32_t msgLength,
uint32_t RTR) {
STD_RETURN_TYPE_e retVal = E_NOT_OK;
uint8_t tmptxbuffer_wr = 0;
CAN_TX_BUFFER_s* can_txbuffer = NULL_PTR;
if (canNode == CAN_NODE0) {
#if CAN_USE_CAN_NODE0 == 1
can_txbuffer = &can0_txbuffer;
#endif /* #if CAN_USE_CAN_NODE0 == 1 */
} else if (canNode == CAN_NODE1) {
#if CAN_USE_CAN_NODE1 == 1
can_txbuffer = &can1_txbuffer;
#endif /* #if CAN_USE_CAN_NODE1 == 1 */
}
/* Transmit buffer exisiting */
if (can_txbuffer != NULL_PTR) {
tmptxbuffer_wr = can_txbuffer->ptrWrite;
if (tmptxbuffer_wr == can_txbuffer->ptrRead) {
if (can_txbuffer->buffer[tmptxbuffer_wr].newMsg == 0) {
/* free buffer space for message */
can_txbuffer->ptrWrite++;
can_txbuffer->ptrWrite = can_txbuffer->ptrWrite % can_txbuffer->length;
retVal = E_OK;
} else {
/* buffer full */
retVal = E_NOT_OK;
}
} else {
can_txbuffer->ptrWrite++;
can_txbuffer->ptrWrite = can_txbuffer->ptrWrite % can_txbuffer->length;
retVal = E_OK;
}
} else {
retVal = E_NOT_OK;
}
if ((can_txbuffer != NULL_PTR) &&
(retVal == E_OK) &&
(IS_CAN_STDID(msgID) || IS_CAN_EXTID(msgID)) &&
(IS_CAN_DLC(msgLength))) {
/* if buffer free and valid CAN identifier */
if (IS_CAN_STDID(msgID)) {
can_txbuffer->buffer[tmptxbuffer_wr].msg.StdId = msgID;
can_txbuffer->buffer[tmptxbuffer_wr].msg.IDE = 0;
} else {
can_txbuffer->buffer[tmptxbuffer_wr].msg.ExtId = msgID;
can_txbuffer->buffer[tmptxbuffer_wr].msg.IDE = 1;
}
can_txbuffer->buffer[tmptxbuffer_wr].newMsg = 1;
can_txbuffer->buffer[tmptxbuffer_wr].msg.RTR = RTR;
can_txbuffer->buffer[tmptxbuffer_wr].msg.DLC = msgLength; /* Data length of the frame that will be transmitted */
can_txbuffer->buffer[tmptxbuffer_wr].msg.TransmitGlobalTime = DISABLE;
/* copy message data in handle transmit structure */
can_txbuffer->buffer[tmptxbuffer_wr].data[0] = ptrMsgData[0];
can_txbuffer->buffer[tmptxbuffer_wr].data[1] = ptrMsgData[1];
can_txbuffer->buffer[tmptxbuffer_wr].data[2] = ptrMsgData[2];
can_txbuffer->buffer[tmptxbuffer_wr].data[3] = ptrMsgData[3];
can_txbuffer->buffer[tmptxbuffer_wr].data[4] = ptrMsgData[4];
can_txbuffer->buffer[tmptxbuffer_wr].data[5] = ptrMsgData[5];
can_txbuffer->buffer[tmptxbuffer_wr].data[6] = ptrMsgData[6];
can_txbuffer->buffer[tmptxbuffer_wr].data[7] = ptrMsgData[7];
retVal = E_OK;
} else {
retVal = E_NOT_OK;
}
return retVal;
}
STD_RETURN_TYPE_e CAN_TxMsgBuffer(CAN_NodeTypeDef_e canNode) {
STD_RETURN_TYPE_e retVal = E_NOT_OK;
HAL_StatusTypeDef retHal = HAL_ERROR;
CAN_TX_BUFFER_s* can_txbuffer = NULL;
CAN_HandleTypeDef* ptrHcan = NULL;
uint32_t freeMailboxes = 0;
uint32_t *ptrMailbox = NULL_PTR;
if (canNode == CAN_NODE0) {
#if CAN_USE_CAN_NODE0 == 1
if (!canNode0_listenonly_mode) {
can_txbuffer = &can0_txbuffer;
ptrHcan = &hcan0;
}
#endif /* #if CAN_USE_CAN_NODE0 == 1 */
} else if (canNode == CAN_NODE1) {
#if CAN_USE_CAN_NODE1 == 1
if (!canNode1_listenonly_mode) {
can_txbuffer = &can1_txbuffer;
ptrHcan = &hcan1;
}
#endif /* CAN_USE_CAN_NODE1 == 1 */
}
/* Check if at least one mailbox is free */
freeMailboxes = HAL_CAN_GetTxMailboxesFreeLevel(&hcan0);
if ((can_txbuffer != NULL) && (freeMailboxes != 0)) {
if ((can_txbuffer->ptrWrite == can_txbuffer->ptrRead)
&& (can_txbuffer->buffer[can_txbuffer->ptrRead].newMsg == 0)) {
/* nothing to transmit, buffer is empty */
retVal = E_NOT_OK;
} else {
/* Copy message into TX mailbox and transmit it */
retHal = HAL_CAN_AddTxMessage(ptrHcan, &can_txbuffer->buffer[can_txbuffer->ptrRead].msg, can_txbuffer->buffer[can_txbuffer->ptrRead].data, ptrMailbox);
if (retHal == HAL_OK) {
/* No Error during start of transmission */
can_txbuffer->buffer[can_txbuffer->ptrRead].newMsg = 0; /* Msg is sent, set newMsg to 0, to allow writing of new data in buffer space */
can_txbuffer->ptrRead++;
can_txbuffer->ptrRead = can_txbuffer->ptrRead % can_txbuffer->length;
retVal = E_OK;
} else {
retVal = E_NOT_OK; /* Error during transmission, retransmit message later */
}
}
} else {
/* no transmit buffer active or TX mailboxes full */
retVal = E_NOT_OK;
}
return retVal;
}
/* ***************************************
* Receive message
****************************************/
/**
* @brief Receives CAN messages and stores them either in RxBuffer or in hcan
*
* @param canNode: canNode which received the message
* @param ptrHcan: pointer to a CAN_HandleTypeDef structure that contains
* the message information of the specified CAN.
* @param FIFONumber: FIFO in which the message has been received
* @retval none (void)
*/
static void CAN_RxMsg(CAN_NodeTypeDef_e canNode, CAN_HandleTypeDef* ptrHcan, uint8_t FIFONumber) {
uint8_t bypassLinkIndex = 0;
CAN_RX_BUFFERELEMENT_s tmpMsgBuffer;
uint32_t msgID = 0;
#if CAN0_USE_RX_BUFFER || CAN1_USE_RX_BUFFER
uint32_t* can_bufferbypass_rxmsgs = NULL;
uint32_t bufferbypasslength = 0;
CAN_RX_BUFFER_s* can_rxbuffer = NULL;
CAN_MSG_RX_TYPE_s* can_rxmsgs = NULL;
uint8_t* can_fastLinkIndex = NULL;
#endif /* CAN0_USE_RX_BUFFER || CAN1_USE_RX_BUFFER */
/* Set pointer on respective RxBuffer */
if (canNode == CAN_NODE1) {
#if CAN1_USE_RX_BUFFER && CAN_USE_CAN_NODE1 == 1
can_rxbuffer = &can1_rxbuffer;
#if (CAN1_BUFFER_BYPASS_NUMBER_OF_IDs > 0u)
can_rxmsgs = &can1_RxMsgs[0];
can_bufferbypass_rxmsgs = &can1_bufferBypass_RxMsgs[0];
bufferbypasslength = CAN1_BUFFER_BYPASS_NUMBER_OF_IDs;
can_fastLinkIndex = &can1_fastLinkIndex[0];
#endif /* (CAN1_BUFFER_BYPASS_NUMBER_OF_IDs > 0u) */
#endif /* CAN1_USE_RX_BUFFER && CAN_USE_CAN_NODE1 == 1 */
} else if (canNode == CAN_NODE0) {
#if CAN0_USE_RX_BUFFER && CAN_USE_CAN_NODE0 == 1
can_rxbuffer = &can0_rxbuffer;
#if (CAN0_BUFFER_BYPASS_NUMBER_OF_IDs > 0U)
can_rxmsgs = &can0_RxMsgs[0];
can_bufferbypass_rxmsgs = &can0_bufferBypass_RxMsgs[0];
bufferbypasslength = CAN0_BUFFER_BYPASS_NUMBER_OF_IDs;
can_fastLinkIndex = &can0_fastLinkIndex[0];
#endif /* (CAN0_BUFFER_BYPASS_NUMBER_OF_IDs > 0u) */
#endif /* CAN0_USE_RX_BUFFER && CAN_USE_CAN_NODE0 == 1 */
}
/* Get message ID */
HAL_CAN_GetRxMessage(ptrHcan, FIFONumber, &tmpMsgBuffer.msg , &tmpMsgBuffer.data[0]);
#if (CAN1_BUFFER_BYPASS_NUMBER_OF_IDs > 0) || (CAN0_BUFFER_BYPASS_NUMBER_OF_IDs > 0)
if (can_bufferbypass_rxmsgs != NULL) {
/* only needed when messages are bypassed */
for (bypassLinkIndex = 0; bypassLinkIndex < bufferbypasslength; bypassLinkIndex++) {
if ((tmpMsgBuffer.msg.StdId == can_bufferbypass_rxmsgs[bypassLinkIndex]) ||
(tmpMsgBuffer.msg.ExtId == can_bufferbypass_rxmsgs[bypassLinkIndex])) {
break;
}
}
}
#endif /* #if (CAN1_BUFFER_BYPASS_NUMBER_OF_IDs > 0) || (CAN0_BUFFER_BYPASS_NUMBER_OF_IDs > 0) */
if (bypassLinkIndex >= bufferbypasslength && can_rxbuffer != NULL) {
/* ##### Use buffer / Copy data in buffer ##### */
#if CAN0_USE_RX_BUFFER || CAN1_USE_RX_BUFFER
/* NO NEED TO DISABLE INTERRUPTS, BECAUSE FUNCTION IS CALLED FROM ISR */
/* Set to 1 to mark message as new received. Set to 0 when reading message from buffer */
can_rxbuffer->buffer[can_rxbuffer->ptrWrite].newMsg = 1;
/* Get message header */
can_rxbuffer->buffer[can_rxbuffer->ptrWrite].msg = tmpMsgBuffer.msg;
/* Get the data field */
for (uint8_t i = 0; i < can_rxbuffer->buffer[can_rxbuffer->ptrWrite].msg.DLC; i++) {
can_rxbuffer->buffer[can_rxbuffer->ptrWrite].data[i] = tmpMsgBuffer.data[i];
}
/* Increment write pointer */
can_rxbuffer->ptrWrite++;
can_rxbuffer->ptrWrite = can_rxbuffer->ptrWrite % can_rxbuffer->length;
#endif /* CAN0_USE_RX_BUFFER || CAN1_USE_RX_BUFFER */
} else if (bypassLinkIndex < bufferbypasslength && can_rxmsgs != NULL && can_fastLinkIndex != NULL) {
/* ##### Buffer active but bypassed ##### */
#if ((CAN1_BUFFER_BYPASS_NUMBER_OF_IDs > 0) || (CAN0_BUFFER_BYPASS_NUMBER_OF_IDs > 0)) && ((CAN_USE_CAN_NODE0 == 1) || (CAN_USE_CAN_NODE1 == 1))
/* call buffer bypass callback function */
if (tmpMsgBuffer.msg.IDE == 0U) {
if (can_rxmsgs[can_fastLinkIndex[bypassLinkIndex]].func != NULL) {
can_rxmsgs[can_fastLinkIndex[bypassLinkIndex]].func(tmpMsgBuffer.msg.StdId,
tmpMsgBuffer.data,
tmpMsgBuffer.msg.DLC,
tmpMsgBuffer.msg.RTR);
} else {
/* No callback function defined */
CAN_BufferBypass(canNode, tmpMsgBuffer.msg.StdId, tmpMsgBuffer.data, tmpMsgBuffer.msg.DLC, tmpMsgBuffer.msg.RTR);
}
} else {
if (can_rxmsgs[can_fastLinkIndex[bypassLinkIndex]].func != NULL) {
can_rxmsgs[can_fastLinkIndex[bypassLinkIndex]].func(tmpMsgBuffer.msg.ExtId,
tmpMsgBuffer.data,
tmpMsgBuffer.msg.DLC,
tmpMsgBuffer.msg.RTR);
} else {
/* No callback function defined */
CAN_BufferBypass(canNode, tmpMsgBuffer.msg.ExtId, tmpMsgBuffer.data, tmpMsgBuffer.msg.DLC, tmpMsgBuffer.msg.RTR);
}
}
#endif /* ((CAN1_BUFFER_BYPASS_NUMBER_OF_IDs > 0) || (CAN0_BUFFER_BYPASS_NUMBER_OF_IDs > 0)) && ((CAN_USE_CAN_NODE0 == 1) || (CAN_USE_CAN_NODE1 == 1)) */
} else {
/* ##### Buffer not active ##### */
CAN_MSG_RX_TYPE_s* msgRXstruct;
uint8_t length;
if (canNode == CAN_NODE0) {
msgRXstruct = &can0_RxMsgs[0];
length = can_CAN0_rx_length;
} else {
msgRXstruct = &can1_RxMsgs[0];
length = can_CAN1_rx_length;
}
if (tmpMsgBuffer.msg.IDE == 0U) {
msgID = tmpMsgBuffer.msg.StdId;
} else {
msgID = tmpMsgBuffer.msg.ExtId;
}
/* Search for correct message in RX message array to check for callback */
uint8_t rxMsg = 0;
for (; rxMsg < length; rxMsg++) {
if (msgRXstruct[rxMsg].ID == msgID) {
break;
}
}
/* Interpret received message */
if (msgRXstruct[rxMsg].func != NULL) {
msgRXstruct[rxMsg].func(msgID, &tmpMsgBuffer.data[0], tmpMsgBuffer.msg.DLC, tmpMsgBuffer.msg.RTR);
} else {
CAN_InterpretReceivedMsg(canNode, msgID, &tmpMsgBuffer.data[0], tmpMsgBuffer.msg.DLC, tmpMsgBuffer.msg.RTR);
}
}
}
STD_RETURN_TYPE_e CAN_ReceiveBuffer(CAN_NodeTypeDef_e canNode, Can_PduType* msg) {
/* E_OK is returned, if buffer is empty and interpret function is called successful */
STD_RETURN_TYPE_e retVal = E_NOT_OK;
#if CAN0_USE_RX_BUFFER || CAN1_USE_RX_BUFFER
CAN_RX_BUFFER_s* can_rxbuffer = NULL;
#if CAN0_USE_RX_BUFFER && CAN_USE_CAN_NODE0 == 1
if (canNode == CAN_NODE0) {
can_rxbuffer = &can0_rxbuffer;
}
#endif /* CAN0_USE_RX_BUFFER && CAN_USE_CAN_NODE0 == 1 */
#if CAN1_USE_RX_BUFFER && CAN_USE_CAN_NODE1 == 1
if (canNode == CAN_NODE1) {
can_rxbuffer = &can1_rxbuffer;
}
#endif /* CAN1_USE_RX_BUFFER && CAN_USE_CAN_NODE1 == 1 */
if (msg == NULL) {
/* null pointer to message data struct */
can_rxbuffer = NULL;
}
if ((can_rxbuffer->ptrWrite != can_rxbuffer->ptrRead) &&
(can_rxbuffer->buffer[can_rxbuffer->ptrRead].newMsg == 1) &&
(can_rxbuffer != NULL)) {
/* buffer not empty -> read message */
if (can_rxbuffer->buffer[can_rxbuffer->ptrRead].msg.IDE == 1) {
/* Extended ID used */
msg->id = can_rxbuffer->buffer[can_rxbuffer->ptrRead].msg.ExtId;
} else {
msg->id = can_rxbuffer->buffer[can_rxbuffer->ptrRead].msg.StdId;
}
msg->dlc = can_rxbuffer->buffer[can_rxbuffer->ptrRead].msg.DLC;
for (uint8_t i = 0; i < 8U; i++) {
msg->sdu[i] = can_rxbuffer->buffer[can_rxbuffer->ptrRead].data[i];
}
/* Set to 0 to mark buffer entry as read. Set to 1 when writing message into buffer */
can_rxbuffer->buffer[can_rxbuffer->ptrRead].newMsg = 0;
/* Move to next buffer element */
can_rxbuffer->ptrRead++;
can_rxbuffer->ptrRead = can_rxbuffer->ptrRead % can_rxbuffer->length;
retVal = E_OK;
}
#endif /* CAN0_USE_RX_BUFFER || CAN1_USE_RX_BUFFER */
return retVal;
}
/**
* @brief Receives a bypassed CAN message and interprets it
*
* @param canNode: canNode on which the message has been received
* @param msgID: message ID
* @param data: pointer to the message data
* @param DLC: length of received data
* @param RTR: RTR bit of received message
*
* @retval E_OK if interpreting was successful, otherwise E_NOT_OK
*/
static STD_RETURN_TYPE_e CAN_BufferBypass(CAN_NodeTypeDef_e canNode, uint32_t msgID, uint8_t* rxData, uint8_t DLC,
uint8_t RTR) {
STD_RETURN_TYPE_e retVal = E_OK;
/* ***************************************************************
* Implement wished functionality of received messages here,
*
* if no callback function in CAN_MSG_RX_TYPE_s struct is defined
*****************************************************************/
/* Perform SW reset */
if (msgID == CAN_ID_SOFTWARE_RESET_MSG && DLC == 8) {
uint8_t reset = 0;
/* CAN data = FF FF FF FF FF FF FF FF */
for (uint8_t i = 0; i < DLC; i++) {
if (rxData[i] != 0xFF) {
reset = 1;
}
}
#if CAN_SW_RESET_WITH_DEVICE_ID == 1
/* CAN data = MCU Device ID Byte [0] [1] [2] [3] [4] [5] [6] [7] */
/* if (rxData[0] == (uint8_t)mcu_unique_deviceID.off0 && data[1] == (uint8_t)(mcu_unique_deviceID.off0 >> 8) &&
rxData[2] == (uint8_t)(mcu_unique_deviceID.off0 >> 16) && rxData[3] == (uint8_t)(mcu_unique_deviceID.off0 >> 24) &&
rxData[4] == (uint8_t)mcu_unique_deviceID.off32 && rxData[5] == (uint8_t)(mcu_unique_deviceID.off32 >> 8) &&
rxData[6] == (uint8_t)(mcu_unique_deviceID.off32 >> 16) && rxData[7] == (uint8_t)(mcu_unique_deviceID.off32 >> 24)) {
reset = 1;
}
*/
if (rxData[0] == 0) {
if ((CAN_CheckNodeID(&data[5]) == E_OK) || (CAN_CheckUniqueDeviceID(&data[1]) == E_OK) || (CAN_CheckBroadcastID(&data[5]) == E_OK)) {
reset = 1;
}
}
#else /* CAN_SW_RESET_WITH_DEVICE_ID != 1 */
reset = 1;
#endif /* CAN_SW_RESET_WITH_DEVICE_ID == 1 */
if (reset == 1)
HAL_NVIC_SystemReset();
}
return retVal;
}
/**
* @brief Interprets the received message
*
* @param canNode: canNode on which the message has been received
* @param msgID: message ID
* @param data: pointer to the message data
* @param DLC: length of received data
* @param RTR: RTR bit of received message
*
* @return E_OK if interpretation successful, otherwise E_NOT_OK
*/
static STD_RETURN_TYPE_e CAN_InterpretReceivedMsg(CAN_NodeTypeDef_e canNode, uint32_t msgID, uint8_t* data, uint8_t DLC,
uint8_t RTR) {
STD_RETURN_TYPE_e retVal = E_NOT_OK;
/* ***************************************************************
* Implement wished functionality of received messages here,
*
* if no callback function in CAN_MSG_RX_TYPE_s struct is defined
*****************************************************************/
return retVal;
}
/* ***************************************
* Sleep mode
****************************************/
void CAN_SetSleepMode(CAN_NodeTypeDef_e canNode) {
if (canNode == CAN_NODE0) {
HAL_CAN_RequestSleep(&hcan0);
} else if (canNode == CAN_NODE1) {
HAL_CAN_RequestSleep(&hcan1);
}
return;
}
void CAN_WakeUp(CAN_NodeTypeDef_e canNode) {
if (canNode == CAN_NODE0) {
HAL_CAN_WakeUp(&hcan0);
} else if (canNode == CAN_NODE1) {
HAL_CAN_WakeUp(&hcan1);
}
return;
}
can.h¶
/**
*
* @copyright © 2010 - 2020, Fraunhofer-Gesellschaft zur Foerderung der
* angewandten Forschung e.V. All rights reserved.
*
* BSD 3-Clause License
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* We kindly request you to use one or more of the following phrases to refer
* to foxBMS in your hardware, software, documentation or advertising
* materials:
*
* ″This product uses parts of foxBMS®″
*
* ″This product includes parts of foxBMS®″
*
* ″This product is derived from foxBMS®″
*
*/
/**
* @file can.h
* @author foxBMS Team
* @date 12.07.2015 (date of creation)
* @ingroup DRIVERS
* @prefix CAN
*
* @brief Header for the driver for the CAN module
*
* Provides the interfaces for initialization, receive
* and transmit handling
*
*/
#ifndef CAN_H_
#define CAN_H_
/*================== Includes =============================================*/
#include "can_cfg.h"
/*================== Macros and Definitions ===============================*/
#define CAN0_USE_TX_BUFFER CAN0_USE_TRANSMIT_BUFFER
#define CAN0_USE_RX_BUFFER CAN0_USE_RECEIVE_BUFFER
#define CAN0_TX_BUFFER_LENGTH CAN0_TRANSMIT_BUFFER_LENGTH
#define CAN0_RX_BUFFER_LENGTH CAN0_RECEIVE_BUFFER_LENGTH
#define CAN1_USE_TX_BUFFER CAN1_USE_TRANSMIT_BUFFER
#define CAN1_USE_RX_BUFFER CAN1_USE_RECEIVE_BUFFER
#define CAN1_TX_BUFFER_LENGTH CAN1_TRANSMIT_BUFFER_LENGTH
#define CAN1_RX_BUFFER_LENGTH CAN1_RECEIVE_BUFFER_LENGTH
typedef enum {
CAN_ERROR_NONE = HAL_CAN_ERROR_NONE, /*!< No error */
CAN_ERROR_EWG = HAL_CAN_ERROR_EWG, /*!< EWG error */
CAN_ERROR_EPV = HAL_CAN_ERROR_EPV, /*!< EPV error */
CAN_ERROR_BOF = HAL_CAN_ERROR_BOF, /*!< BOF error */
CAN_ERROR_STF = HAL_CAN_ERROR_STF, /*!< Stuff error */
CAN_ERROR_FOR = HAL_CAN_ERROR_FOR, /*!< Form error */
CAN_ERROR_ACK = HAL_CAN_ERROR_ACK, /*!< Acknowledgment error */
CAN_ERROR_BR = HAL_CAN_ERROR_BR, /*!< Bit recessive */
CAN_ERROR_BD = HAL_CAN_ERROR_BD, /*!< LEC dominant */
CAN_ERROR_CRC = HAL_CAN_ERROR_CRC, /*!< LEC transfer error */
} CAN_ErrorTypeDef_e;
typedef enum {
CAN_NODE1 = 0, /* CAN1 */
CAN_NODE0 = 1, /* CAN0 */
} CAN_NodeTypeDef_e;
typedef struct CAN_ERROR {
CAN_ErrorTypeDef_e canError;
uint16_t canErrorCounter[23 - 1]; /* One slot for every error from CAN_Error_Code; */
/* No space for NoError */
} CAN_ERROR_s;
typedef struct CAN_RX_BUFFERELEMENT {
CAN_RxHeaderTypeDef msg;
uint8_t data[8];
uint8_t newMsg;
} CAN_RX_BUFFERELEMENT_s;
typedef struct CAN_TX_BUFFERELEMENT {
CAN_TxHeaderTypeDef msg;
uint8_t data[8];
uint8_t newMsg;
} CAN_TX_BUFFERELEMENT_s;
typedef struct CAN_RX_BUFFER {
uint8_t ptrRead;
uint8_t ptrWrite;
uint8_t length;
CAN_RX_BUFFERELEMENT_s* buffer;
} CAN_RX_BUFFER_s;
typedef struct CAN_TX_BUFFER {
uint8_t ptrRead;
uint8_t ptrWrite;
uint8_t length;
CAN_TX_BUFFERELEMENT_s* buffer;
} CAN_TX_BUFFER_s;
/*================== Constant and Variable Definitions ====================*/
/**
* @brief CAN listen only transceiver mode of CAN node 0
*/
extern uint8_t canNode0_listenonly_mode;
/**
* @brief CAN listen only transceiver mode of CAN node 1
*/
extern uint8_t canNode1_listenonly_mode;
/*================== Function Prototypes ==================================*/
/* Init */
/**
* @brief Initializes CAN settings and message filtering
*
* @retval 0: if initialization successful, otherwise errorcode
*/
extern uint32_t CAN_Init(void);
/* Interrupt handling */
/**
* @brief Handles CAN TX interrupt request
* @param ptrHcan: pointer to a CAN_HandleTypeDef structure that contains
* the configuration information for the specified CAN.
* @retval none (void)
*/
extern void CAN_TX_IRQHandler(CAN_HandleTypeDef* ptrHcan);
/**
* @brief Handles CAN RX interrupt request
*
* @param canNode: canNode that received a message
* @param ptrHcan: pointer to a CAN_HandleTypeDef structure that contains
* the configuration information for the specified CAN.
*
* @retval None
*/
extern void CAN_RX_IRQHandler(CAN_NodeTypeDef_e canNode, CAN_HandleTypeDef* ptrHcan);
/**
* @brief Handles CAN error interrupt request
*
* @param canNode:
* @param ptrHcan: pointer to a CAN_HandleTypeDef structure that contains
* the configuration information for the specified CAN.
*
* @retval None
*/
extern void CAN_Error_IRQHandler(CAN_NodeTypeDef_e canNode, CAN_HandleTypeDef* ptrHcan);
/* Transmit Message */
/**
* @brief Transmits message directly on the CAN bus
*
* @param canNode: canNode on which the message shall be transmitted
* @param msgID: ID of the message that will be transmitted
* @param ptrMsgData: pointer to the data that shall be transmitted
* @param msgLength: Specifies the data length
* @param RTR: Specifies the type of frame for the message that will be transmitted.
*
* @retval E_OK if transmission successful, otherwise E_NOT_OK
*/
extern STD_RETURN_TYPE_e CAN_TxMsg(CAN_NodeTypeDef_e canNode, uint32_t msgID, uint8_t* ptrMsgData,
uint32_t msgLength, uint32_t RTR);
/**
* @brief Add message to transmit buffer, message will be transmitted shortly after.
*
* ------------------------ IMPORTANT!!!! --------------------------------
* Make sure that this function is not interrupted by the operating system
* during its execution.
*
* @param canNode: canNode on which the message shall be transmitted
* @param msgID: ID of the message that will be transmitted
* @param ptrMsgData: pointer to a uint8_t array that contains the message that will be transmitted
* @param msgLength: length of the message that will be transmitted
* This parameter can be a value of CAN_identifier_type.
* @param RTR Specifies the type of frame for the message that will be transmitted.
* This parameter can be a value of CAN_remote_transmission_request
*
* @retval E_OK if successful, E_NOT_OK if buffer is full or error occurred
*/
extern STD_RETURN_TYPE_e CAN_Send(CAN_NodeTypeDef_e canNode, uint32_t msgID, uint8_t* ptrMsgData,
uint32_t msgLength, uint32_t RTR);
/**
* @brief Transmits a can message from transmit buffer
*
* ------------------------ IMPORTANT!!!! --------------------------------
* Make sure that this function is not interrupted by the operating system
* during its execution.
*
* @param canNode: canNode on which the message shall be transmitted
*
* @retval E_OK if transmission successful, otherwise E_NOT_OK
*/
extern STD_RETURN_TYPE_e CAN_TxMsgBuffer(CAN_NodeTypeDef_e canNode);
/* Read Message */
/**
* @brief Reads a can message from RxBuffer
*
* @param canNode canNode on which a message has been received
* @param msg message that has been received
*
* @retval E_OK if reception successful, if buffer empty or invalid pointer E_NOT_OK
*/
extern STD_RETURN_TYPE_e CAN_ReceiveBuffer(CAN_NodeTypeDef_e canNode, Can_PduType* msg);
/* Sleep mode */
/**
* @brief Set CAN to sleep mode
*
* @param canNode canNode which shall be put to sleep mode
*
* @retval none (void)
*/
extern void CAN_SetSleepMode(CAN_NodeTypeDef_e canNode);
/**
* @brief Wake CAN up from sleep mode
*
* @param canNode canNode which shall be waken up from sleep mode
*
* @retval none.
*/
extern void CAN_WakeUp(CAN_NodeTypeDef_e canNode);
/*================== Function Implementations =============================*/
/* ***************************************
* CAN Fault Confinement
****************************************/
/* Fault confinement is a checking mechanism that makes it possible to distinguish between short disturbances
(e.g. switching noise from a nearby power cable couples into the transmission media) and permanent failures
(e.g. a node is malfunctioning and disturbs the bus).
Manipulation of the error counters is asymmetric. On a successful transmission, or reception, of a message,
the respective error counter is decremented if it had not been at zero. In the case of a transmit or receive
error the counters are incremented, but by a value greater than the value they would be decrement by following
a successful message transaction.
If a node detects a local error condition (e.g. due to local conducted noise, application software, etc.),
its resulting error flag (primary error flag) will subsequently cause all other nodes to respond with an error
flag too (secondary error flags). It is important that a distinction is made between the nodes that detected an
error first and the nodes which responded to the primary error flag. If a node transmits an active error frame,
and it monitors a dominant bit after the sixth bit of its error flag, it considers itself as the node that has
detected the error first. In the case where a node detects errors first too often, it is regarded as malfunctioning,
and its impact to the network has to be limited. Therefore, a node can be in one of three possible error states:
ERROR ACTIVE - Both of its error counters are less than 128. It takes part fully in bus communication and signals
an error by transmission of an active error frame.This consists of sequence of 6 dominant bits followed
by 8 recessive bits, all other nodes respond with the appropriate error flag, in response to the
violation of the bit stuffing rule.
ERROR PASSIVE - A node goes into error passive state if at least one of its error counters is greater than 127. It
still takes part in bus activities, but it sends a passive error frame only, on errors. Furthermore,
an error passive node has to wait an additional time (Suspend Transmission Field, 8 recessive bits after
Intermission Field) after transmission of a message, before it can initiate a new data transfer. The
primary passive error flag consists of 6 passive bits and thus is transparent on the bus and will
not jam communications.
BUS OFF - If the Transmit Error Counter of a CAN controller exceeds 255, it goes into the bus off state. It is
disconnected from the bus (using internal logic) and does not take part in bus activities anymore. In order
to reconnect the protocol controller, a so-called Bus Off recovery sequence has to be executed. This usually
involves the re-initialization and configuration of the CAN controller by the host system, after which it
will wait for 128 * 11 recessive bit times before it commences communication.
*/
/* ***************************************
* CAN Error Confinement Rules
****************************************/
/* REC: Receive Error Counter, TEC: Transmit Error Counter */
/* - When a receiver detects an error, the REC will be increased by 1, except when the detected error was a Bit Error
during the sending of an Active error Flag or an Overload Flag.
- When a receiver detects a dominant bit as the first bit after sending an Error Flag, the REC will be increased by 8.
- When a transmitter sends an Error Flag, the TEC is increased by 8.
Exception 1: If the transmitter is Error Passive and detects an ACK Error because of not detecting a dominant ACK
and does not detect a dominant bit while sending its Passive Error Flag.
Exception 2: If the transmitter sends an Error Flag because a Stuff Error occurred during arbitration, and should
have been recessive, and has been sent as recessive but monitored as dominant.
- If the transmitter detects a Bit Error while sending an Active Error Flag or an Overload Frame, the TEC is increased by 8.
- If a receiver detects a Bit Error while sending an Active Error Flag or an Overload Flag, the REC is increased by 8.
- Any node tolerates up to 7 consecutive dominant bits after sending an Active Error Flag, Passive Error Flag or Overload Flag.
After detecting the fourteenth consecutive dominant bit (in case of an Active Error Flag or an Overload Flag) or after
detecting the eighth consecutive dominant bit following a Passive Error Flag, and after each sequence of additional eight
consecutive dominant bits, ever y transmitter increases its TEC by 8 and every receiver increases its REC by 8.
- After successful transmission of a frame (getting ACK and no error until EOF is finished), the TEC is decreased by 1 unless it was already 0.
- After the successful reception of a frame (reception without error up to the ACK Slot and the successful sending of the ACK bit),
the REC is decreased by 1, if it was between 1 and 127. If the REC was 0, it stays 0, and if it was greater than 127, then it
will be set to a value between 119 and 127.
- A node is Error Passive when the TEC equals or exceeds 128, or when the REC equals or exceeds 128. An error condition
letting a node become Error Passive causes the node to send an Active Error Flag.
- A node is Bus Off when the TEC is greater than or equal to 256.
- An Error Passive node becomes Error Active again when both the TEC and the REC are less than or equal to 127.
- A node which is Bus Off is permitted to become Error Active (no longer Bus Off) with its error counters both set to 0
after 128 occurrence of 11 consecutive recessive bits have been monitored on the bus.
*/
#endif /* CAN_H_ */
can_cfg.c¶
/**
*
* @copyright © 2010 - 2020, Fraunhofer-Gesellschaft zur Foerderung der
* angewandten Forschung e.V. All rights reserved.
*
* BSD 3-Clause License
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* We kindly request you to use one or more of the following phrases to refer
* to foxBMS in your hardware, software, documentation or advertising
* materials:
*
* ″This product uses parts of foxBMS®″
*
* ″This product includes parts of foxBMS®″
*
* ″This product is derived from foxBMS®″
*
*/
/**
* @file can_cfg.c
* @author foxBMS Team
* @date 12.07.2015 (date of creation)
* @ingroup DRIVERS_CONF
* @prefix CAN
*
* @brief Configuration for the CAN module
*
* The CAN bus settings and the received messages and their
* reception handling are to be specified here.
*
*/
/*================== Includes =============================================*/
#include "can_cfg.h"
#include "batterysystem_cfg.h"
#include "mcu.h"
#include "rcc_cfg.h"
/*================== Macros and Definitions ===============================*/
/*================== Constant and Variable Definitions ====================*/
/*================== Function Prototypes ==================================*/
/*================== Function Implementations =============================*/
/* ***************************************
* Set CAN settings here
****************************************/
CAN_HandleTypeDef hcan0 = {
.Instance = CAN2,
.State = HAL_CAN_STATE_RESET,
.ErrorCode = HAL_CAN_ERROR_NONE,
#if (CAN0_BAUDRATE == 1000000)
#if (RCC_APB1_CLOCK == 45000000)
.Init.Prescaler = 3, /* CAN_CLOCK = APB1 = 45MHz */
/* resulting CAN speed: APB1/prescaler/sumOfTimequants */
/* sum: 1tq for sync + TimeSeg1 + TimeSeg2 */
.Init.TimeSeg1 = CAN_BS1_6TQ, /* --> CAN = 45MHz/3/15 = 1.0MHz */
.Init.TimeSeg2 = CAN_BS2_8TQ,
#elif(RCC_APB1_CLOCK == 42000000)
.Init.Prescaler = 3, /* CAN_CLOCK = APB1 = 42MHz */
/* resulting CAN speed: APB1/prescaler/sumOfTimequants */
/* sum: 1tq for sync + TimeSeg1 + TimeSeg2 */
.Init.TimeSeg1 = CAN_BS1_6TQ, /* --> CAN = 42MHz/3/14 = 1.0MHz */
.Init.TimeSeg2 = CAN_BS2_7TQ,
#elif RCC_APB1_CLOCK == 32000000
.Init.Prescaler = 4, /* CAN_CLOCK = APB1 = 32MHz */
/* resulting CAN speed: APB1/prescaler/sumOfTimequants */
/* sum: 1tq for sync + TimeSeg1 + TimeSeg2 */
.Init.TimeSeg1 = CAN_BS1_5TQ, /* --> CAN = 32MHz/4/8 = 1.0MHz */
.Init.TimeSeg2 = CAN_BS2_2TQ,
#else
#error "Please configure CAN Baudrate according to your clock configuration "
#endif
#elif(CAN0_BAUDRATE == 500000)
#if (RCC_APB1_CLOCK == 45000000)
.Init.Prescaler = 6, /* CAN_CLOCK = APB1 = 45MHz */
/* resulting CAN speed: APB1/prescaler/sumOfTimequants */
/* sum: 1tq for sync + TimeSeg1 + TimeSeg2 */
.Init.TimeSeg1 = CAN_BS1_6TQ, /* --> CAN = 45MHz/6/15 = 0.5MHz */
.Init.TimeSeg2 = CAN_BS2_8TQ,
#elif(RCC_APB1_CLOCK == 42000000)
.Init.Prescaler = 6, /* CAN_CLOCK = APB1 = 42MHz */
/* resulting CAN speed: APB1/prescaler/sumOfTimequants */
/* sum: 1tq for sync + TimeSeg1 + TimeSeg2 */
.Init.TimeSeg1 = CAN_BS1_6TQ, /* --> CAN = 42MHz/6/14 = 0.5MHz */
.Init.TimeSeg2 = CAN_BS2_7TQ,
#elif RCC_APB1_CLOCK == 32000000
.Init.Prescaler = 8, /* CAN_CLOCK = APB1 = 32MHz */
/* resulting CAN speed: APB1/prescaler/sumOfTimequants */
/* sum: 1tq for sync + TimeSeg1 + TimeSeg2 */
.Init.TimeSeg1 = CAN_BS1_5TQ, /* --> CAN = 32MHz/8/8 = 0.5MHz */
.Init.TimeSeg2 = CAN_BS2_2TQ,
#else
#error "Please configure CAN Baudrate according to your clock configuration "
#endif
#elif(CAN0_BAUDRATE == 250000)
#if (RCC_APB1_CLOCK == 45000000)
.Init.Prescaler = 12, /* CAN_CLOCK = APB1 = 45MHz */
/* resulting CAN speed: APB1/prescaler/sumOfTimequants */
/* sum: 1tq for sync + TimeSeg1 + TimeSeg2 */
.Init.TimeSeg1 = CAN_BS1_6TQ, /* --> CAN = 45MHz/12/15 = 0.25MHz */
.Init.TimeSeg2 = CAN_BS2_8TQ,
#elif(RCC_APB1_CLOCK == 42000000)
.Init.Prescaler = 12, /* CAN_CLOCK = APB1 = 42MHz */
/* resulting CAN speed: APB1/prescaler/sumOfTimequants */
/* sum: 1tq for sync + TimeSeg1 + TimeSeg2 */
.Init.TimeSeg1 = CAN_BS1_6TQ, /* --> CAN = 42MHz/12/14 = 0.25MHz */
.Init.TimeSeg2 = CAN_BS2_7TQ,
#elif RCC_APB1_CLOCK == 32000000
.Init.Prescaler = 16, /* CAN_CLOCK = APB1 = 32MHz */
/* resulting CAN speed: APB1/prescaler/sumOfTimequants */
/* sum: 1tq for sync + TimeSeg1 + TimeSeg2 */
.Init.TimeSeg1 = CAN_BS1_2TQ, /* --> CAN = 32MHz/16/8 = 0.25MHz */
.Init.TimeSeg2 = CAN_BS2_5TQ,
#else
#error "Please configure CAN Baudrate according to your clock configuration "
#endif
#elif(CAN0_BAUDRATE == 125000)
#if (RCC_APB1_CLOCK == 45000000)
.Init.Prescaler = 24, /* CAN_CLOCK = APB1 = 45MHz */
/* resulting CAN speed: APB1/prescaler/sumOfTimequants */
/* sum: 1tq for sync + TimeSeg1 + TimeSeg2 */
.Init.TimeSeg1 = CAN_BS1_6TQ, /* --> CAN = 45MHz/12/14 = 0.125MHz */
.Init.TimeSeg2 = CAN_BS2_8TQ,
#elif(RCC_APB1_CLOCK == 42000000)
.Init.Prescaler = 24, /* CAN_CLOCK = APB1 = 42MHz */
/* resulting CAN speed: APB1/prescaler/sumOfTimequants */
/* sum: 1tq for sync + TimeSeg1 + TimeSeg2 */
.Init.TimeSeg1 = CAN_BS1_6TQ, /* --> CAN = 42MHz/12/14 = 0.125MHz */
.Init.TimeSeg2 = CAN_BS2_7TQ,
#elif RCC_APB1_CLOCK == 32000000
.Init.Prescaler = 32, /* CAN_CLOCK = APB1 = 32MHz */
/* resulting CAN speed: APB1/prescaler/sumOfTimequants */
/* sum: 1tq for sync + TimeSeg1 + TimeSeg2 */
.Init.TimeSeg1 = CAN_BS1_2TQ, /* --> CAN = 32MHz/16/8 = 0.125MHz */
.Init.TimeSeg2 = CAN_BS2_5TQ,
#else
#error "Please configure CAN Baudrate according to your clock configuration "
#endif
#endif
.Init.Mode = CAN_MODE_NORMAL, /* for test purpose, without connected can-bus use LOOPBACK mode */
.Init.SyncJumpWidth = CAN_SJW_1TQ,
.Init.TimeTriggeredMode = DISABLE, /* time triggerd communication mode */
/* DISABLE: no influence */
/* ENABLE: saves timestamps for received and transmitted messages. See reference manual for more information. */
/* DISABLE: Manually re-initialize CAN and wait for 128 * 11 recessive bits */
.Init.AutoBusOff = ENABLE, /* automatic bus-off management */
/* ENABLE: automatically leave bus-off mode after 128 * 11 recessive bits */
.Init.AutoWakeUp = ENABLE, /* automatic wake-up mode */
/* ENABLE: automatically leave sleep mode on message receiving */
/* DISABLE: SLEEP bit needs to be deleted by software */
.Init.AutoRetransmission = DISABLE, /* automatic retransition mode; */
/* DISABLE: retransmit the message until it has been successfully transmitted */
/* ENABLE: transmit only once, independently of transmission result */
.Init.ReceiveFifoLocked = ENABLE, /* Receive FIFO locked against overrun. */
/* DISABLE: A new incoming message overwrites the last received message. */
/* ENABLE: Once a receive FIFO is full the next incoming message will be discarded. */
.Init.TransmitFifoPriority = ENABLE, /* Transmit FIFO priority */
/* DISABLE: driven by identifier of message. Lower identifier equals higher priority */
/* ENABLE: driven chronologically */
};
CAN_HandleTypeDef hcan1 = {
.Instance = CAN1,
.State = HAL_CAN_STATE_RESET,
.ErrorCode = HAL_CAN_ERROR_NONE,
#if (CAN1_BAUDRATE == 1000000)
#if (RCC_APB1_CLOCK == 45000000)
.Init.Prescaler = 3, /* CAN_CLOCK = APB1 = 45MHz */
/* resulting CAN speed: APB1/prescaler/sumOfTimequants */
/* sum: 1tq for sync + TimeSeg1 + TimeSeg2 */
.Init.TimeSeg1 = CAN_BS1_6TQ, /* --> CAN = 45MHz/3/15 = 1.0MHz */
.Init.TimeSeg2 = CAN_BS2_8TQ,
#elif(RCC_APB1_CLOCK == 42000000)
.Init.Prescaler = 3, /* CAN_CLOCK = APB1 = 42MHz */
/* resulting CAN speed: APB1/prescaler/sumOfTimequants */
/* sum: 1tq for sync + TimeSeg1 + TimeSeg2 */
.Init.TimeSeg1 = CAN_BS1_6TQ, /* --> CAN = 42MHz/3/14 = 1.0MHz */
.Init.TimeSeg2 = CAN_BS2_7TQ,
#elif RCC_APB1_CLOCK == 32000000
.Init.Prescaler = 4, /* CAN_CLOCK = APB1 = 32MHz */
/* resulting CAN speed: APB1/prescaler/sumOfTimequants */
/* sum: 1tq for sync + TimeSeg1 + TimeSeg2 */
.Init.TimeSeg1 = CAN_BS1_5TQ, /* --> CAN = 32MHz/4/8 = 1.0MHz */
.Init.TimeSeg2 = CAN_BS2_2TQ,
#else
#error "Please configure CAN Baudrate according to your clock configuration "
#endif
#elif(CAN1_BAUDRATE == 500000)
#if (RCC_APB1_CLOCK == 45000000)
.Init.Prescaler = 6, /* CAN_CLOCK = APB1 = 45MHz */
/* resulting CAN speed: APB1/prescaler/sumOfTimequants */
/* sum: 1tq for sync + TimeSeg1 + TimeSeg2 */
.Init.TimeSeg1 = CAN_BS1_6TQ, /* --> CAN = 45MHz/6/15 = 0.5MHz */
.Init.TimeSeg2 = CAN_BS2_8TQ,
#elif(RCC_APB1_CLOCK == 42000000)
.Init.Prescaler = 6, /* CAN_CLOCK = APB1 = 42MHz */
/* resulting CAN speed: APB1/prescaler/sumOfTimequants */
/* sum: 1tq for sync + TimeSeg1 + TimeSeg2 */
.Init.TimeSeg1 = CAN_BS1_6TQ, /* --> CAN = 42MHz/6/14 = 0.5MHz */
.Init.TimeSeg2 = CAN_BS2_7TQ,
#elif RCC_APB1_CLOCK == 32000000
.Init.Prescaler = 8, /* CAN_CLOCK = APB1 = 32MHz */
/* resulting CAN speed: APB1/prescaler/sumOfTimequants */
/* sum: 1tq for sync + TimeSeg1 + TimeSeg2 */
.Init.TimeSeg1 = CAN_BS1_5TQ, /* --> CAN = 32MHz/8/8 = 0.5MHz */
.Init.TimeSeg2 = CAN_BS2_2TQ,
#else
#error "Please configure CAN Baudrate according to your clock configuration "
#endif
#elif(CAN1_BAUDRATE == 250000)
#if (RCC_APB1_CLOCK == 45000000)
.Init.Prescaler = 12, /* CAN_CLOCK = APB1 = 45MHz */
/* resulting CAN speed: APB1/prescaler/sumOfTimequants */
/* sum: 1tq for sync + TimeSeg1 + TimeSeg2 */
.Init.TimeSeg1 = CAN_BS1_6TQ, /* --> CAN = 45MHz/12/15 = 0.25MHz */
.Init.TimeSeg2 = CAN_BS2_8TQ,
#elif(RCC_APB1_CLOCK == 42000000)
.Init.Prescaler = 12, /* CAN_CLOCK = APB1 = 42MHz */
/* resulting CAN speed: APB1/prescaler/sumOfTimequants */
/* sum: 1tq for sync + TimeSeg1 + TimeSeg2 */
.Init.TimeSeg1 = CAN_BS1_6TQ, /* --> CAN = 42MHz/12/14 = 0.25MHz */
.Init.TimeSeg2 = CAN_BS2_7TQ,
#elif RCC_APB1_CLOCK == 32000000
.Init.Prescaler = 16, /* CAN_CLOCK = APB1 = 32MHz */
/* resulting CAN speed: APB1/prescaler/sumOfTimequants */
/* sum: 1tq for sync + TimeSeg1 + TimeSeg2 */
.Init.TimeSeg1 = CAN_BS1_5TQ, /* --> CAN = 32MHz/16/8 = 0.25MHz */
.Init.TimeSeg2 = CAN_BS2_2TQ,
#else
#error "Please configure CAN Baudrate according to your clock configuration "
#endif
#elif(CAN1_BAUDRATE == 125000)
#if (RCC_APB1_CLOCK == 45000000)
.Init.Prescaler = 24, /* CAN_CLOCK = APB1 = 45MHz */
/* resulting CAN speed: APB1/prescaler/sumOfTimequants */
/* sum: 1tq for sync + TimeSeg1 + TimeSeg2 */
.Init.TimeSeg1 = CAN_BS1_6TQ, /* --> CAN = 45MHz/12/14 = 0.125MHz */
.Init.TimeSeg2 = CAN_BS2_8TQ,
#elif(RCC_APB1_CLOCK == 42000000)
.Init.Prescaler = 24, /* CAN_CLOCK = APB1 = 42MHz */
/* resulting CAN speed: APB1/prescaler/sumOfTimequants */
/* sum: 1tq for sync + TimeSeg1 + TimeSeg2 */
.Init.TimeSeg1 = CAN_BS1_6TQ, /* --> CAN = 42MHz/12/14 = 0.125MHz */
.Init.TimeSeg2 = CAN_BS2_7TQ,
#elif RCC_APB1_CLOCK == 32000000
.Init.Prescaler = 32, /* CAN_CLOCK = APB1 = 32MHz */
/* resulting CAN speed: APB1/prescaler/sumOfTimequants */
/* sum: 1tq for sync + TimeSeg1 + TimeSeg2 */
.Init.TimeSeg1 = CAN_BS1_5TQ, /* --> CAN = 32MHz/16/8 = 0.125MHz */
.Init.TimeSeg2 = CAN_BS2_2TQ,
#else
#error "Please configure CAN Baudrate according to your clock configuration "
#endif
#endif
.Init.Mode = CAN_MODE_NORMAL, /* for test purpose, without connected can-bus use LOOPBACK mode */
.Init.SyncJumpWidth = CAN_SJW_1TQ,
.Init.TimeTriggeredMode = DISABLE, /* time triggerd communication mode */
/* DISABLE: no influence */
/* ENABLE: saves timestamps for received and transmitted messages. See reference manual for more information. */
.Init.AutoBusOff = ENABLE, /* automatic bus-off management */
/* DISABLE: Manually re-initialize CAN and wait for 128 * 11 recessive bits */
/* ENABLE: automatically leave bus-off mode after 128 * 11 recessive bits */
.Init.AutoWakeUp = ENABLE, /* automatic wake-up mode */
/* ENABLE: automatically leave sleep mode on message receiving */
/* DISABLE: SLEEP bit needs to be deleted by software */
.Init.AutoRetransmission = DISABLE, /* automatic retransition mode; */
/* DISABLE: retransmit the message until it has been successfully transmitted */
/* ENABLE: transmit only once, independently of transmission result */
.Init.ReceiveFifoLocked = ENABLE, /* Receive FIFO locked against overrun. */
/* DISABLE: A new incoming message overwrites the last received message. */
/* ENABLE: Once a receive FIFO is full the next incoming message will be discarded. */
.Init.TransmitFifoPriority = ENABLE, /* Transmit FIFO priority */
/* DISABLE: driven by identifier of message. Lower identifier equals higher priority */
/* ENABLE: driven chronologically */
};
/* ***************************************
* Configure TX messages here
****************************************/
const CAN_MSG_TX_TYPE_s can_CAN0_messages_tx[] = {
{ 0x110, 8, 100, 0, NULL_PTR }, /*!< BMS system state 0 */
{ 0x111, 8, 100, 0, NULL_PTR }, /*!< BMS system state 1 */
{ 0x112, 8, 100, 0, NULL_PTR }, /*!< BMS system state 2 */
{ 0x115, 8, 100, 0, NULL_PTR }, /*!< BMS slave state 0 */
{ 0x116, 8, 100, 0, NULL_PTR }, /*!< BMS slave state 1 */
{ 0x130, 8, 100, 30, NULL_PTR }, /*!< Maximum allowed current */
{ 0x131, 8, 100, 30, NULL_PTR }, /*!< SOP */
{ 0x140, 8, 1000, 30, NULL_PTR }, /*!< SOC */
{ 0x150, 8, 5000, 30, NULL_PTR }, /*!< SOH */
{ 0x160, 8, 1000, 30, NULL_PTR }, /*!< SOE */
{ 0x170, 8, 100, 30, NULL_PTR }, /*!< Cell voltages Min Max Average */
{ 0x171, 8, 100, 30, NULL_PTR }, /*!< SOV */
{ 0x180, 8, 100, 30, NULL_PTR }, /*!< Cell temperatures Min Max Average */
{ 0x190, 8, 1000, 30, NULL_PTR }, /*!< Tempering */
{ 0x1A0, 8, 1000, 30, NULL_PTR }, /*!< Insulation */
{ 0x1D0, 8, 1000, 40, NULL_PTR }, /*!< Running average power 0 */
{ 0x1D1, 8, 1000, 40, NULL_PTR }, /*!< Running average power 1 */
{ 0x1D2, 8, 1000, 40, NULL_PTR }, /*!< Running average power 2 */
{ 0x1E0, 8, 1000, 40, NULL_PTR }, /*!< Running average current 0 */
{ 0x1E1, 8, 1000, 40, NULL_PTR }, /*!< Running average current 1 */
{ 0x1E2, 8, 1000, 40, NULL_PTR }, /*!< Running average current 2 */
{ 0x1F0, 8, 1000, 40, NULL_PTR }, /*!< Pack voltage */
{ 0x200, 8, 200, 20, NULL_PTR }, /*!< Cell voltages module 0 cells 0 1 2 */
{ 0x201, 8, 200, 20, NULL_PTR }, /*!< Cell voltages module 0 cells 3 4 5 */
{ 0x202, 8, 200, 20, NULL_PTR }, /*!< Cell voltages module 0 cells 6 7 8 */
{ 0x203, 8, 200, 20, NULL_PTR }, /*!< Cell voltages module 0 cells 9 10 11 */
{ 0x204, 8, 200, 20, NULL_PTR }, /*!< Cell voltages module 0 cells 12 13 14 */
{ 0x205, 8, 200, 20, NULL_PTR }, /*!< Cell voltages module 0 cells 15 16 17 */
{ 0x210, 8, 200, 30, NULL_PTR }, /*!< Cell temperatures module 0 cells 0 1 2 */
{ 0x211, 8, 200, 30, NULL_PTR }, /*!< Cell temperatures module 0 cells 3 4 5 */
{ 0x212, 8, 200, 30, NULL_PTR }, /*!< Cell temperatures module 0 cells 6 7 8 */
{ 0x213, 8, 200, 30, NULL_PTR }, /*!< Cell temperatures module 0 cells 9 10 11 */
{ 0x220, 8, 200, 40, NULL_PTR }, /*!< Cell voltages module 1 cells 0 1 2 */
{ 0x221, 8, 200, 40, NULL_PTR }, /*!< Cell voltages module 1 cells 3 4 5 */
{ 0x222, 8, 200, 40, NULL_PTR }, /*!< Cell voltages module 1 cells 6 7 8 */
{ 0x223, 8, 200, 40, NULL_PTR }, /*!< Cell voltages module 1 cells 9 10 11 */
{ 0x224, 8, 200, 40, NULL_PTR }, /*!< Cell voltages module 1 cells 12 13 14 */
{ 0x225, 8, 200, 40, NULL_PTR }, /*!< Cell voltages module 1 cells 15 16 17 */
{ 0x230, 8, 200, 50, NULL_PTR }, /*!< Cell temperatures module 1 cells 0 1 2 */
{ 0x231, 8, 200, 50, NULL_PTR }, /*!< Cell temperatures module 1 cells 3 4 5 */
{ 0x232, 8, 200, 50, NULL_PTR }, /*!< Cell temperatures module 1 cells 6 7 8 */
{ 0x233, 8, 200, 50, NULL_PTR }, /*!< Cell temperatures module 1 cells 9 10 11 */
{ 0x240, 8, 200, 60, NULL_PTR }, /*!< Cell voltages module 2 cells 0 1 2 */
{ 0x241, 8, 200, 60, NULL_PTR }, /*!< Cell voltages module 2 cells 3 4 5 */
{ 0x242, 8, 200, 60, NULL_PTR }, /*!< Cell voltages module 2 cells 6 7 8 */
{ 0x243, 8, 200, 60, NULL_PTR }, /*!< Cell voltages module 2 cells 9 10 11 */
{ 0x244, 8, 200, 60, NULL_PTR }, /*!< Cell voltages module 2 cells 12 13 14 */
{ 0x245, 8, 200, 60, NULL_PTR }, /*!< Cell voltages module 2 cells 15 16 17 */
{ 0x250, 8, 200, 70, NULL_PTR }, /*!< Cell temperatures module 2 cells 0 1 2 */
{ 0x251, 8, 200, 70, NULL_PTR }, /*!< Cell temperatures module 2 cells 3 4 5 */
{ 0x252, 8, 200, 70, NULL_PTR }, /*!< Cell temperatures module 2 cells 6 7 8 */
{ 0x253, 8, 200, 70, NULL_PTR }, /*!< Cell temperatures module 2 cells 9 10 11 */
{ 0x260, 8, 200, 80, NULL_PTR }, /*!< Cell voltages module 3 cells 0 1 2 */
{ 0x261, 8, 200, 80, NULL_PTR }, /*!< Cell voltages module 3 cells 3 4 5 */
{ 0x262, 8, 200, 80, NULL_PTR }, /*!< Cell voltages module 3 cells 6 7 8 */
{ 0x263, 8, 200, 80, NULL_PTR }, /*!< Cell voltages module 3 cells 9 10 11 */
{ 0x264, 8, 200, 80, NULL_PTR }, /*!< Cell voltages module 3 cells 12 13 14 */
{ 0x265, 8, 200, 80, NULL_PTR }, /*!< Cell voltages module 3 cells 15 16 17 */
{ 0x270, 8, 200, 90, NULL_PTR }, /*!< Cell temperatures module 3 cells 0 1 2 */
{ 0x271, 8, 200, 90, NULL_PTR }, /*!< Cell temperatures module 3 cells 3 4 5 */
{ 0x272, 8, 200, 90, NULL_PTR }, /*!< Cell temperatures module 3 cells 6 7 8 */
{ 0x273, 8, 200, 90, NULL_PTR }, /*!< Cell temperatures module 3 cells 9 10 11 */
{ 0x280, 8, 200, 100, NULL_PTR }, /*!< Cell voltages module 4 cells 0 1 2 */
{ 0x281, 8, 200, 100, NULL_PTR }, /*!< Cell voltages module 4 cells 3 4 5 */
{ 0x282, 8, 200, 100, NULL_PTR }, /*!< Cell voltages module 4 cells 6 7 8 */
{ 0x283, 8, 200, 100, NULL_PTR }, /*!< Cell voltages module 4 cells 9 10 11 */
{ 0x284, 8, 200, 100, NULL_PTR }, /*!< Cell voltages module 4 cells 12 13 14 */
{ 0x285, 8, 200, 100, NULL_PTR }, /*!< Cell voltages module 4 cells 15 16 17 */
{ 0x290, 8, 200, 110, NULL_PTR }, /*!< Cell temperatures module 4 cells 0 1 2 */
{ 0x291, 8, 200, 110, NULL_PTR }, /*!< Cell temperatures module 4 cells 3 4 5 */
{ 0x292, 8, 200, 110, NULL_PTR }, /*!< Cell temperatures module 4 cells 6 7 8 */
{ 0x293, 8, 200, 110, NULL_PTR }, /*!< Cell temperatures module 4 cells 9 10 11 */
{ 0x2A0, 8, 200, 120, NULL_PTR }, /*!< Cell voltages module 5 cells 0 1 2 */
{ 0x2A1, 8, 200, 120, NULL_PTR }, /*!< Cell voltages module 5 cells 3 4 5 */
{ 0x2A2, 8, 200, 120, NULL_PTR }, /*!< Cell voltages module 5 cells 6 7 8 */
{ 0x2A3, 8, 200, 120, NULL_PTR }, /*!< Cell voltages module 5 cells 9 10 11 */
{ 0x2A4, 8, 200, 120, NULL_PTR }, /*!< Cell voltages module 5 cells 12 13 14 */
{ 0x2A5, 8, 200, 120, NULL_PTR }, /*!< Cell voltages module 5 cells 15 16 17 */
{ 0x2B0, 8, 200, 130, NULL_PTR }, /*!< Cell temperatures module 5 cells 0 1 2 */
{ 0x2B1, 8, 200, 130, NULL_PTR }, /*!< Cell temperatures module 5 cells 3 4 5 */
{ 0x2B2, 8, 200, 130, NULL_PTR }, /*!< Cell temperatures module 5 cells 6 7 8 */
{ 0x2B3, 8, 200, 130, NULL_PTR }, /*!< Cell temperatures module 5 cells 9 10 11 */
{ 0x2C0, 8, 200, 140, NULL_PTR }, /*!< Cell voltages module 6 cells 0 1 2 */
{ 0x2C1, 8, 200, 140, NULL_PTR }, /*!< Cell voltages module 6 cells 3 4 5 */
{ 0x2C2, 8, 200, 140, NULL_PTR }, /*!< Cell voltages module 6 cells 6 7 8 */
{ 0x2C3, 8, 200, 140, NULL_PTR }, /*!< Cell voltages module 6 cells 9 10 11 */
{ 0x2C4, 8, 200, 140, NULL_PTR }, /*!< Cell voltages module 6 cells 12 13 14 */
{ 0x2C5, 8, 200, 140, NULL_PTR }, /*!< Cell voltages module 6 cells 15 16 17 */
{ 0x2D0, 8, 200, 150, NULL_PTR }, /*!< Cell temperatures module 6 cells 0 1 2 */
{ 0x2D1, 8, 200, 150, NULL_PTR }, /*!< Cell temperatures module 6 cells 3 4 5 */
{ 0x2D2, 8, 200, 150, NULL_PTR }, /*!< Cell temperatures module 6 cells 6 7 8 */
{ 0x2D3, 8, 200, 150, NULL_PTR }, /*!< Cell temperatures module 6 cells 9 10 11 */
{ 0x2E0, 8, 200, 160, NULL_PTR }, /*!< Cell voltages module 7 cells 0 1 2 */
{ 0x2E1, 8, 200, 160, NULL_PTR }, /*!< Cell voltages module 7 cells 3 4 5 */
{ 0x2E2, 8, 200, 160, NULL_PTR }, /*!< Cell voltages module 7 cells 6 7 8 */
{ 0x2E3, 8, 200, 160, NULL_PTR }, /*!< Cell voltages module 7 cells 9 10 11 */
{ 0x2E4, 8, 200, 160, NULL_PTR }, /*!< Cell voltages module 7 cells 12 13 14 */
{ 0x2E5, 8, 200, 160, NULL_PTR }, /*!< Cell voltages module 7 cells 15 16 17 */
{ 0x2F0, 8, 200, 170, NULL_PTR }, /*!< Cell temperatures module 7 cells 0 1 2 */
{ 0x2F1, 8, 200, 170, NULL_PTR }, /*!< Cell temperatures module 7 cells 3 4 5 */
{ 0x2F2, 8, 200, 170, NULL_PTR }, /*!< Cell temperatures module 7 cells 6 7 8 */
{ 0x2F3, 8, 200, 170, NULL_PTR }, /*!< Cell temperatures module 7 cells 9 10 11 */
#ifdef CURRENT_SENSOR_ISABELLENHUETTE_TRIGGERED
, { 0x35B, 8, 100, 20, NULL_PTR } /*!< Current Sensor Trigger */
#endif /* CURRENT_SENSOR_ISABELLENHUETTE_TRIGGERED */
};
const CAN_MSG_TX_TYPE_s can_CAN1_messages_tx[] = {
};
const uint8_t can_CAN0_tx_length = sizeof(can_CAN0_messages_tx)/sizeof(can_CAN0_messages_tx[0]);
const uint8_t can_CAN1_tx_length = sizeof(can_CAN1_messages_tx)/sizeof(can_CAN1_messages_tx[0]);
/* ***************************************
* Configure RX messages here
****************************************/
/* Bypassed messages are --- ALSO --- to be configured here. See further down for bypass ID setting! */
CAN_MSG_RX_TYPE_s can0_RxMsgs[] = {
{ 0x120, 0xFFFF, 8, 0, CAN_FILTER_FIFO0, NULL }, /*!< state request */
{ CAN_ID_SOFTWARE_RESET_MSG, 0xFFFF, 8, 0, CAN_FILTER_FIFO0, NULL }, /*!< software reset */
#ifdef CURRENT_SENSOR_ISABELLENHUETTE_TRIGGERED
{ 0x35C, 0xFFFF, 8, 0, CAN_FILTER_FIFO0, NULL }, /*!< current sensor I */
{ 0x35D, 0xFFFF, 8, 0, CAN_FILTER_FIFO0, NULL }, /*!< current sensor U1 */
{ 0x35E, 0xFFFF, 8, 0, CAN_FILTER_FIFO0, NULL }, /*!< current sensor U2 */
{ 0x35F, 0xFFFF, 8, 0, CAN_FILTER_FIFO0, NULL }, /*!< current sensor U3 */
{ 0x525, 0xFFFF, 8, 0, CAN_FILTER_FIFO0, NULL }, /*!< current sensor T in cyclic mode */
{ 0x526, 0xFFFF, 8, 0, CAN_FILTER_FIFO0, NULL }, /*!< current sensor Power in cyclic mode */
{ 0x527, 0xFFFF, 8, 0, CAN_FILTER_FIFO0, NULL }, /*!< current sensor C-C in cyclic mode */
{ 0x528, 0xFFFF, 8, 0, CAN_FILTER_FIFO0, NULL }, /*!< current sensor E-C in cyclic mode */
#else /* CURRENT_SENSOR_ISABELLENHUETTE_CYCLIC */
{ 0x521, 0xFFFF, 8, 0, CAN_FILTER_FIFO0, NULL }, /*!< current sensor I in cyclic mode */
{ 0x522, 0xFFFF, 8, 0, CAN_FILTER_FIFO0, NULL }, /*!< current sensor U1 in cyclic mode */
{ 0x523, 0xFFFF, 8, 0, CAN_FILTER_FIFO0, NULL }, /*!< current sensor U2 in cyclic mode */
{ 0x524, 0xFFFF, 8, 0, CAN_FILTER_FIFO0, NULL }, /*!< current sensor U3 in cyclic mode */
{ 0x525, 0xFFFF, 8, 0, CAN_FILTER_FIFO0, NULL }, /*!< current sensor T in cyclic mode */
{ 0x526, 0xFFFF, 8, 0, CAN_FILTER_FIFO0, NULL }, /*!< current sensor Power in cyclic mode */
{ 0x527, 0xFFFF, 8, 0, CAN_FILTER_FIFO0, NULL }, /*!< current sensor C-C in cyclic mode */
{ 0x528, 0xFFFF, 8, 0, CAN_FILTER_FIFO0, NULL }, /*!< current sensor E-C in cyclic mode */
#endif /* CURRENT_SENSOR_ISABELLENHUETTE_TRIGGERED */
{ 0x100, 0xFFFF, 8, 0, CAN_FILTER_FIFO0, NULL }, /*!< debug message */
{ 0x777, 0xFFFF, 8, 0, CAN_FILTER_FIFO0, NULL }, /*!< request SW version */
};
CAN_MSG_RX_TYPE_s can1_RxMsgs[] = {
};
const uint8_t can_CAN0_rx_length = sizeof(can0_RxMsgs)/sizeof(can0_RxMsgs[0]);
const uint8_t can_CAN1_rx_length = sizeof(can1_RxMsgs)/sizeof(can1_RxMsgs[0]);
/* ***************************************
* Set bypass message IDs here
****************************************/
/* These IDs have to be included in the configuration for the filters in can_RxMsgs[]! */
uint32_t can0_bufferBypass_RxMsgs[CAN0_BUFFER_BYPASS_NUMBER_OF_IDs] = { CAN_ID_SOFTWARE_RESET_MSG };
uint32_t can1_bufferBypass_RxMsgs[CAN1_BUFFER_BYPASS_NUMBER_OF_IDs] = {};
can_cfg.h¶
/**
*
* @copyright © 2010 - 2020, Fraunhofer-Gesellschaft zur Foerderung der
* angewandten Forschung e.V. All rights reserved.
*
* BSD 3-Clause License
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* We kindly request you to use one or more of the following phrases to refer
* to foxBMS in your hardware, software, documentation or advertising
* materials:
*
* ″This product uses parts of foxBMS®″
*
* ″This product includes parts of foxBMS®″
*
* ″This product is derived from foxBMS®″
*
*/
/**
* @file can_cfg.h
* @author foxBMS Team
* @date 12.07.2015 (date of creation)
* @ingroup DRIVERS_CONF
* @prefix CAN
*
* @brief Headers for the configuration for the CAN module
*
* The activation and the length of the message buffers as well as the number of
* the messages that are received are to be configured here
*
*/
#ifndef CAN_CFG_H_
#define CAN_CFG_H_
/*================== Includes =============================================*/
#include "general.h"
#include "cpu_cfg.h"
#include "io.h"
/*================== Macros and Definitions ===============================*/
#define CAN_0_TRANS_STANDBY_CONTROL IO_PIN_CAN_0_TRANS_STANDBY_CONTROL
#define CAN_1_TRANS_STANDBY_CONTROL IO_PIN_CAN_1_TRANS_STANDBY_CONTROL
/* **************************************************************************************
* CAN BUFFER OPTIONS
*****************************************************************************************/
/**
* @ingroup CONFIG_CAN
* CAN0 bus baudrate. CAN peripheral prescaler and time quantums on microcontroller
* will be configured accordingly. See STM32 Reference Manual p. 1097 for more
*
* \par Type:
* select(4)
* \par Default:
* 1
*/
/**
* defines the BAUD rate of the CAN0
*/
/* #define CAN0_BAUDRATE (1000000U) */
#define CAN0_BAUDRATE (500000U)
/* #define CAN0_BAUDRATE (250000U) */
/* #define CAN0_BAUDRATE (125000U) */
/**
* @ingroup CONFIG_CAN
* CAN1 bus baudrate. CAN peripheral prescaler and time quantums on microcontroller
* will be configured accordingly. See STM32 Reference Manual p. 1097 for more
*
* \par Type:
* select(4)
* \par Default:
* 1
*/
/**
* defines the BAUD rate of the CAN1
*/
/* #define CAN1_BAUDRATE (1000000U) */
#define CAN1_BAUDRATE (500000U)
/* #define CAN1_BAUDRATE (250000U) */
/* #define CAN1_BAUDRATE (125000U) */
/* CAN enabling */
/**
* @ingroup CONFIG_CAN
* Enables or disables CAN0
* \par Type:
* int
* \par Range:
* x == 0 or x == 1
* \par Default:
* 1
*/
#define CAN_USE_CAN_NODE0 (1U)
/**
* @ingroup CONFIG_CAN
* Enables or disables CAN1
* \par Type:
* int
* \par Range:
* x == 0 or x == 1
* \par Default:
* 1
*/
#define CAN_USE_CAN_NODE1 (1U)
/**
* @ingroup CONFIG_CAN
* Enables or disables transmitter standby control
* \par Type:
* int
* \par Range:
* x == 0 or x == 1
* \par Default:
* 1
*/
#define CAN_USE_STANDBY_CONTROL (1U)
/* transmit buffer */
/**
* @ingroup CONFIG_CAN
* Enables or disables CAN0 transmit buffer
* \par Type:
* int
* \par Range:
* x == 0 or x == 1
* \par Default:
* 1
*/
#define CAN0_USE_TRANSMIT_BUFFER (1U)
/**
* @ingroup CONFIG_CAN
* Defines CAN0 transmit buffer length
* \par Type:
* int
* \par Range:
* 0 < x
* \par Default:
* 16
*/
#define CAN0_TRANSMIT_BUFFER_LENGTH (24U)
/**
* @ingroup CONFIG_CAN
* Enables or disables CAN1 transmit buffer
* \par Type:
* int
* \par Range:
* x == 0 or x == 1
* \par Default:
* 1
*/
#define CAN1_USE_TRANSMIT_BUFFER (1U)
/**
* @ingroup CONFIG_CAN
* Defines CAN1 transmit buffer length
* \par Type:
* int
* \par Range:
* 0 < x
* \par Default:
* 16
*/
#define CAN1_TRANSMIT_BUFFER_LENGTH (16U)
/* receive buffer */
/**
* @ingroup CONFIG_CAN
* Enables or disables CAN0 receive buffer
* \par Type:
* int
* \par Range:
* x == 0 or x == 1
* \par Default:
* 1
*/
#define CAN0_USE_RECEIVE_BUFFER (1U)
/**
* @ingroup CONFIG_CAN
* Defines CAN0 receive buffer length
* \par Type:
* int
* \par Range:
* 0 < x
* \par Default:
* 16
*/
#define CAN0_RECEIVE_BUFFER_LENGTH (16U)
/**
* @ingroup CONFIG_CAN
* Enables or disables CAN1 receive buffer
* \par Type:
* int
* \par Range:
* x == 0 or x == 1
* \par Default:
* 1
*/
#define CAN1_USE_RECEIVE_BUFFER (1U)
/**
* @ingroup CONFIG_CAN
* Defines CAN1 receive buffer length
* \par Type:
* int
* \par Range:
* 0 < x
* \par Default:
* 16
*/
#define CAN1_RECEIVE_BUFFER_LENGTH (16U)
/* Number of messages that will bypass the receive buffer and will be interpreted right on reception.
* Set the respective IDs and implement the wished functionality either in individual callback
* function or in default STD_RETURN_TYPE_e CAN_BufferBypass(CAN_NodeTypeDef_e canNode, uint32_t msgID,
* uint8_t* data, uint8_t DLC, uint8_t RTR) function in the can.c file. Use bypassing only for
* important messages because of handling during ISR */
/**
* @ingroup CONFIG_CAN
* Defines number of RX messages that bypass receive buffer on CAN0 bus
* \par Type:
* int
* \par Range:
* 0 <= x
* \par Default:
* 0
*/
#define CAN0_BUFFER_BYPASS_NUMBER_OF_IDs (1U)
/**
* @ingroup CONFIG_CAN
* Defines number of RX messages that bypass receive buffer on CAN1 bus
* \par Type:
* int
* \par Range:
* 0 <= x
* \par Default:
* 0
*/
#define CAN1_BUFFER_BYPASS_NUMBER_OF_IDs (0U)
/**
* @ingroup CONFIG_CAN
* Defines CAN message ID to perform a software reset
* \par Type:
* int
* \par Default:
* 351
*/
#define CAN_ID_SOFTWARE_RESET_MSG (0x95U)
/**
* @ingroup CONFIG_CAN
* When enabled unique device ID is need as can data to perform SW reset
* \par Type:
* int
* \par Range:
* [0,1]
* \par Default:
* 0
*/
/* #define CAN_SW_RESET_WITH_DEVICE_ID (01) */
#define CAN_SW_RESET_WITH_DEVICE_ID (0U)
typedef struct CAN_MSG_RX_TYPE {
uint32_t ID; /*!< message ID */
uint32_t mask; /*!< mask or 0x0000 to select list mode */
uint8_t DLC; /*!< data length */
uint8_t RTR; /*!< rtr bit */
uint32_t fifo; /*!< selected CAN hardware (CAN_FILTER_FIFO0 or CAN_FILTER_FIFO1) */
STD_RETURN_TYPE_e (*func)(uint32_t ID, uint8_t*, uint8_t, uint8_t); /*!< callback function */
} CAN_MSG_RX_TYPE_s;
typedef uint32_t (*can_callback_funcPtr)(uint32_t idx, void * value);
/**
* type definition for structure of a CAN message with its
* ID,
* data length code,
* repetition rate (stated in number of calls of CANS mainfunction = ticks),
* the initial phase,
* a callback function if transfer of TX message to CAN module is successful
*/
typedef struct {
uint32_t ID; /*!< CAN message id */
uint8_t DLC; /*!< CAN message data length code */
uint32_t repetition_time; /*!< CAN message cycle time */
uint32_t repetition_phase; /*!< CAN message startup (first send) offset */
can_callback_funcPtr cbk_func; /*!< CAN message callback after message is sent or received */
} CAN_MSG_TX_TYPE_s;
typedef struct CanPdu {
uint8_t sdu[8];
uint32_t id;
uint8_t dlc;
} Can_PduType;
/*================== Constant and Variable Definitions ====================*/
extern CAN_HandleTypeDef hcan0;
extern CAN_HandleTypeDef hcan1;
extern CAN_MSG_RX_TYPE_s can0_RxMsgs[];
extern CAN_MSG_RX_TYPE_s can1_RxMsgs[];
extern uint32_t can0_bufferBypass_RxMsgs[CAN0_BUFFER_BYPASS_NUMBER_OF_IDs];
extern uint32_t can1_bufferBypass_RxMsgs[CAN1_BUFFER_BYPASS_NUMBER_OF_IDs];
extern const CAN_MSG_TX_TYPE_s can_CAN0_messages_tx[];
extern const CAN_MSG_TX_TYPE_s can_CAN1_messages_tx[];
/**
* array length for receiving CAN0 message definition
*/
extern const uint8_t can_CAN0_rx_length;
/**
* array length for receiving CAN1 message definition
*/
extern const uint8_t can_CAN1_rx_length;
/**
* array length for transmission CAN0 message definition
*/
extern const uint8_t can_CAN0_tx_length;
/**
* array length for transmission CAN1 message definition
*/
extern const uint8_t can_CAN1_tx_length;
/*================== Function Prototypes ==================================*/
/*================== Function Implementations =============================*/
#endif /* CAN_CFG_H_ */