Files
test/drivers/source/flexcan/sdrv_flexcan.c
2025-11-07 20:19:23 +08:00

2145 lines
71 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* @file sdrv_flexcan.c
* @brief low level sdrv flexcan driver file.
*
* @Copyright (c) 2021 Semidrive Semiconductor.
* @All rights reserved.
*
**/
#include <bits.h>
#include <debug.h>
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include "sdrv_flexcan.h"
#include "app/app_frm_signal.h"
#include "sdrv_flexcan_priv.h"
/***************Internal function prototypes***************/
static inline flexcan_status_e flexcan_enter_freeze_mode(CAN_Type *base,
bool allowTimeout);
static inline flexcan_status_e flexcan_exit_freeze_mode(CAN_Type *base,
bool allowTimeout);
static inline void flexcan_fd_clean_smb_region(CAN_Type *base);
static void flexcan_pnet_init(CAN_Type *base,
const flexcan_pn_config_t *config);
static void flexcan_fd_init(CAN_Type *base, const flexcan_fd_config_t *config);
static inline bool flexcan_is_fd_enabled(CAN_Type *base);
static uint32_t *flexcan_get_msg_buf_addr(CAN_Type *base, uint8_t msgBufId);
static void flexcan_enable_mb_int(CAN_Type *base, uint8_t msgBufId);
static void flexcan_disable_mb_int(CAN_Type *base, uint8_t msgBufId);
static uint8_t flexcan_compute_dlc_val(uint8_t payloadSize);
static uint8_t flexcan_compute_payload_len(uint8_t dlc_val);
static inline uint32_t flexcan_get_mb_int_req(CAN_Type *base, uint8_t group);
static uint32_t flexcan_get_mb_int_status_flag(CAN_Type *base,
uint8_t msgBufId);
static inline void flexcan_clear_mb_int_flag(CAN_Type *base, uint8_t msgBufId);
static void flexcan_copy_from_mb(uint32_t *addr, uint8_t *data, uint8_t len);
static void flexcan_copy_to_mb(uint32_t *addr, uint8_t *data, uint8_t len);
#if FLEXCAN_COPY_USE_BURST
static inline void flexcan_copy8(uint32_t *src, uint32_t *dest);
static inline void flexcan_copy16(uint32_t *src, uint32_t *dest);
static inline void flexcan_copy32(uint32_t *src, uint32_t *dest);
#endif
static inline bool flexcan_ext_nominal_bit_timing(
const flexcan_timing_config_t *nominal_bit_timing);
/***************Function implementation***************/
/* Internal function implementation start */
static inline flexcan_status_e flexcan_enter_freeze_mode(CAN_Type *base,
bool allowTimeout)
{
ASSERT(base);
uint32_t timeoutCnt = FLEXCAN_TIMEOUT_COUNTER;
flexcan_status_e retVal = FLEXCAN_SUCCESS;
/* Set Freeze, Halt bits. */
base->MCR |= CAN_MCR_FRZ_MASK | CAN_MCR_HALT_MASK;
/* Wait until the FlexCAN Module enter freeze mode. */
while ((!(base->MCR & CAN_MCR_FRZACK_MASK)) && (timeoutCnt > 0U)) {
if (allowTimeout) {
timeoutCnt--;
}
}
/* Return failed status if timeout. */
if (!(base->MCR & CAN_MCR_FRZACK_MASK)) {
ssdk_printf(SSDK_ERR, "\r\nEnter freeze mode timeout\r\n");
retVal = FLEXCAN_FAIL;
}
return retVal;
}
static inline flexcan_status_e flexcan_exit_freeze_mode(CAN_Type *base,
bool allowTimeout)
{
ASSERT(base);
uint32_t timeoutCnt = FLEXCAN_TIMEOUT_COUNTER;
flexcan_status_e retVal = FLEXCAN_SUCCESS;
/* Clear Freeze, Halt bits. */
base->MCR &= ~(CAN_MCR_FRZ_MASK | CAN_MCR_HALT_MASK);
/* Wait until the FlexCAN Module exit freeze mode. */
while ((base->MCR & CAN_MCR_FRZACK_MASK) && (timeoutCnt > 0U)) {
if (allowTimeout) {
timeoutCnt--;
}
}
/* Return failed status if timeout. */
if (base->MCR & CAN_MCR_FRZACK_MASK) {
ssdk_printf(SSDK_ERR, "\r\nExit freeze mode timeout\r\n");
retVal = FLEXCAN_FAIL;
}
return retVal;
}
static inline void flexcan_fd_clean_smb_region(CAN_Type *base)
{
ASSERT(base);
uint16_t start = CAN_FD_SMB_START_ADDR_OFFSET;
/* Enable unrestricted write access to FlexCAN memory. */
base->CTRL2 |= CAN_CTRL2_WRMFRZ_MASK;
/* Clear CAN FD SMB region to avoid non-correctable errors. */
while (start < CAN_FD_SMB_END_ADDR_OFFSET) {
*((uint32_t *)((uint8_t *)base + start)) = 0U;
start += 4U;
}
/* Enable write access restriction. */
base->CTRL2 &= ~CAN_CTRL2_WRMFRZ_MASK;
}
static void flexcan_pnet_init(CAN_Type *base, const flexcan_pn_config_t *config)
{
ASSERT(base && config);
/* Configure CTRL1_PN with the filter criteria to
* be used to receive wakeup messages.
*/
base->CTRL1_PN &=
~(CAN_CTRL1_PN_WTOF_MSK_MASK | CAN_CTRL1_PN_WUMF_MSK_MASK |
CAN_CTRL1_PN_NMATCH_MASK | CAN_CTRL1_PN_PLFS_MASK |
CAN_CTRL1_PN_IDFS_MASK | CAN_CTRL1_PN_FCS_MASK);
base->CTRL1_PN |=
(CAN_CTRL1_PN_WTOF_MSK(config->wakeUpTimeout ? 1UL : 0UL) |
CAN_CTRL1_PN_WUMF_MSK(config->wakeUpMatch ? 1UL : 0UL) |
CAN_CTRL1_PN_NMATCH(config->numMatches) |
CAN_CTRL1_PN_FCS(config->filterComb) |
CAN_CTRL1_PN_IDFS(config->idFilterType) |
CAN_CTRL1_PN_PLFS(config->payloadFilterType));
/* Set timeout value under PNET. */
base->CTRL2_PN = (base->CTRL2_PN & ~CAN_CTRL2_PN_MATCHTO_MASK) |
CAN_CTRL2_PN_MATCHTO(config->matchTimeout);
/* Configures values used to filter incoming message ID either
* for equal to, smaller than, greater than comparisons,
* or as the lower limit value in an ID range detection.
*/
base->FLT_ID1 &= ~(CAN_FLT_ID1_FLT_IDE_MASK | CAN_FLT_ID1_FLT_RTR_MASK |
CAN_FLT_ID1_FLT_ID1_MASK);
base->FLT_ID1 |=
(CAN_FLT_ID1_FLT_IDE(config->idFilter1.extendedId ? 1UL : 0UL) |
CAN_FLT_ID1_FLT_RTR(config->idFilter1.remoteFrame ? 1UL : 0UL));
if (config->idFilter1.extendedId) {
base->FLT_ID1 |= CAN_FLT_ID1_FLT_ID1(config->idFilter1.id);
} else {
base->FLT_ID1 |=
CAN_FLT_ID1_FLT_ID1(config->idFilter1.id << CAN_ID_STD_SHIFT);
}
if ((config->idFilterType == FLEXCAN_FILTER_MATCH_EXACT) ||
(config->idFilterType == FLEXCAN_FILTER_MATCH_RANGE)) {
/* Configures values either for upper limit value in ID range detection
* or for ID mask in ID exact match.
*/
base->FLT_ID2_IDMASK &= ~(CAN_FLT_ID2_IDMASK_IDE_MSK_MASK |
CAN_FLT_ID2_IDMASK_RTR_MSK_MASK |
CAN_FLT_ID2_IDMASK_FLT_ID2_IDMASK_MASK);
base->FLT_ID2_IDMASK |=
(CAN_FLT_ID2_IDMASK_IDE_MSK(config->idFilter2.extendedId ? 1UL
: 0UL) |
CAN_FLT_ID2_IDMASK_RTR_MSK(config->idFilter2.remoteFrame ? 1UL
: 0UL));
if (config->idFilter2.extendedId) {
base->FLT_ID2_IDMASK |=
CAN_FLT_ID2_IDMASK_FLT_ID2_IDMASK(config->idFilter2.id);
} else {
base->FLT_ID2_IDMASK |= CAN_FLT_ID2_IDMASK_FLT_ID2_IDMASK(
config->idFilter2.id << CAN_ID_STD_SHIFT);
}
} else {
/* need to check only. */
base->FLT_ID2_IDMASK |=
CAN_FLT_ID2_IDMASK_IDE_MSK_MASK | CAN_FLT_ID2_IDMASK_RTR_MSK_MASK;
}
/* Config criteria if payload filtering selected. */
if ((config->filterComb == FLEXCAN_FILTER_ID_PAYLOAD) ||
(config->filterComb == FLEXCAN_FILTER_ID_PAYLOAD_NTIMES)) {
base->FLT_DLC &=
~(CAN_FLT_DLC_FLT_DLC_HI_MASK | CAN_FLT_DLC_FLT_DLC_HI_MASK);
base->FLT_DLC |=
(CAN_FLT_DLC_FLT_DLC_HI(config->payloadFilter.dlcLow) |
CAN_FLT_DLC_FLT_DLC_LO(config->payloadFilter.dlcHigh));
base->PL1_HI =
CAN_PL1_HI_Data_byte_4(config->payloadFilter.payload1[4]) |
CAN_PL1_HI_Data_byte_5(config->payloadFilter.payload1[5]) |
CAN_PL1_HI_Data_byte_6(config->payloadFilter.payload1[6]) |
CAN_PL1_HI_Data_byte_7(config->payloadFilter.payload1[7]);
base->PL1_LO =
CAN_PL1_LO_Data_byte_0(config->payloadFilter.payload1[0]) |
CAN_PL1_LO_Data_byte_1(config->payloadFilter.payload1[1]) |
CAN_PL1_LO_Data_byte_2(config->payloadFilter.payload1[2]) |
CAN_PL1_LO_Data_byte_3(config->payloadFilter.payload1[3]);
/* Configures values either for upper limit value in payload range
* detection or for payload mask in payload exact match.
*/
if ((config->payloadFilterType == FLEXCAN_FILTER_MATCH_EXACT) ||
(config->idFilterType == FLEXCAN_FILTER_MATCH_RANGE)) {
base->PL2_PLMASK_HI = CAN_PL2_PLMASK_HI_Data_byte_4(
config->payloadFilter.payload2[4]) |
CAN_PL2_PLMASK_HI_Data_byte_5(
config->payloadFilter.payload2[5]) |
CAN_PL2_PLMASK_HI_Data_byte_6(
config->payloadFilter.payload2[6]) |
CAN_PL2_PLMASK_HI_Data_byte_7(
config->payloadFilter.payload2[7]);
base->PL2_PLMASK_LO = CAN_PL2_PLMASK_LO_Data_byte_0(
config->payloadFilter.payload2[0]) |
CAN_PL2_PLMASK_LO_Data_byte_1(
config->payloadFilter.payload2[1]) |
CAN_PL2_PLMASK_LO_Data_byte_2(
config->payloadFilter.payload2[2]) |
CAN_PL2_PLMASK_LO_Data_byte_3(
config->payloadFilter.payload2[3]);
}
}
}
static void flexcan_fd_init(CAN_Type *base, const flexcan_fd_config_t *config)
{
ASSERT(base && config);
uint32_t fdctrlTemp = base->FDCTRL;
/* Enable Bit Rate Switch? */
if (config->enableBRS) {
fdctrlTemp |= CAN_FDCTRL_FDRATE_MASK;
} else {
fdctrlTemp &= ~CAN_FDCTRL_FDRATE_MASK;
}
/* Enable Transceiver Delay Compensation? */
if (config->enableTDC) {
fdctrlTemp |= CAN_FDCTRL_TDCEN_MASK;
/* Set TDC offset. */
fdctrlTemp &= ~CAN_FDCTRL_TDCOFF_MASK;
fdctrlTemp |= CAN_FDCTRL_TDCOFF(config->TDCOffset);
} else {
fdctrlTemp &= ~CAN_FDCTRL_TDCEN_MASK;
}
/* Set message buffer data size for region 0. */
fdctrlTemp &= ~CAN_FDCTRL_MBDSR0_MASK;
fdctrlTemp |= CAN_FDCTRL_MBDSR0(config->r0_mb_data_size);
#if FLEXCAN_HAS_MESSAGE_BUFFER_MAX_NUMBER > 32
/* Set message buffer data size for region 1. */
fdctrlTemp &= ~CAN_FDCTRL_MBDSR1_MASK;
fdctrlTemp |= CAN_FDCTRL_MBDSR1(config->r1_mb_data_size);
#endif
#if FLEXCAN_HAS_MESSAGE_BUFFER_MAX_NUMBER > 64
/* Set message buffer data size for region 2. */
fdctrlTemp &= ~CAN_FDCTRL_MBDSR2_MASK;
fdctrlTemp |= CAN_FDCTRL_MBDSR2(config->r2_mb_data_size);
#endif
#if FLEXCAN_HAS_MESSAGE_BUFFER_MAX_NUMBER > 96
/* Set message buffer data size for region 3. */
fdctrlTemp &= ~CAN_FDCTRL_MBDSR3_MASK;
fdctrlTemp |= CAN_FDCTRL_MBDSR3(config->r3_mb_data_size);
#endif
/* Update FDCTRL register. */
base->FDCTRL = fdctrlTemp;
/* Enable ISO CAN FD? */
if (config->enableISOCANFD) {
base->CTRL2 |= CAN_CTRL2_ISOCANFDEN_MASK;
}
}
static inline bool flexcan_is_fd_enabled(CAN_Type *base)
{
ASSERT(base);
return (((base->MCR & CAN_MCR_FDEN_MASK) >> CAN_MCR_FDEN_SHIFT) != 0U);
}
static uint32_t *flexcan_get_msg_buf_addr(CAN_Type *base, uint8_t msgBufId)
{
ASSERT(base);
uint32_t *msgBufAddr;
if (flexcan_is_fd_enabled(base)) {
uint8_t msgBufRegionIdx;
uint8_t fdctrl_mbdsrx;
uint8_t payloadSize;
uint8_t msgBufSize;
uint8_t regionMaxMBNum;
msgBufAddr = (uint32_t *)base->MB;
for (msgBufRegionIdx = 0U; msgBufRegionIdx < REGION_NUM;
msgBufRegionIdx++) {
/* Get MBDSRx bits from FDCTRL register. */
fdctrl_mbdsrx =
(((base->FDCTRL) >> (16U + msgBufRegionIdx * 3U)) & 3U);
/* Get message buffer data size in bytes. */
payloadSize = 1U << (fdctrl_mbdsrx + 3U);
/* Get message buffer size in words. */
msgBufSize = (payloadSize + 8U) >> 2U;
/* Maxium MB index in the region. */
if (fdctrl_mbdsrx == 0U) {
regionMaxMBNum = REGION_8BYTES_MB_NUM;
} else if (fdctrl_mbdsrx == 1U) {
regionMaxMBNum = REGION_16BYTES_MB_NUM;
} else if (fdctrl_mbdsrx == 2U) {
regionMaxMBNum = REGION_32BYTES_MB_NUM;
} else {
regionMaxMBNum = REGION_64BYTES_MB_NUM;
}
if (msgBufId < regionMaxMBNum) {
msgBufAddr += (msgBufId * msgBufSize);
break;
} else {
msgBufAddr += PER_REGION_SIZE_IN_WORD;
msgBufId -= regionMaxMBNum;
}
}
} else {
msgBufAddr = (uint32_t *)&base->MB[msgBufId];
}
return msgBufAddr;
}
static inline void flexcan_enable_mb_int(CAN_Type *base, uint8_t msgBufId)
{
uint8_t regionId = msgBufId / 32U;
uint8_t bitOffset = msgBufId % 32U;
switch (regionId) {
case 0U:
base->IMASK1 |= (uint32_t)(1U << bitOffset);
break;
case 1U:
base->IMASK2 |= (uint32_t)(1U << bitOffset);
break;
case 2U:
base->IMASK3 |= (uint32_t)(1U << bitOffset);
break;
case 3U:
base->IMASK4 |= (uint32_t)(1U << bitOffset);
break;
default:
break;
}
}
static inline void flexcan_disable_mb_int(CAN_Type *base, uint8_t msgBufId)
{
uint8_t regionId = msgBufId / 32U;
uint8_t bitOffset = msgBufId % 32U;
switch (regionId) {
case 0U:
base->IMASK1 &= (uint32_t)(~(1U << bitOffset));
break;
case 1U:
base->IMASK2 &= (uint32_t)(~(1U << bitOffset));
break;
case 2U:
base->IMASK3 &= (uint32_t)(~(1U << bitOffset));
break;
case 3U:
base->IMASK4 &= (uint32_t)(~(1U << bitOffset));
break;
default:
break;
}
}
static uint8_t flexcan_compute_dlc_val(uint8_t payloadSize)
{
uint8_t ret_dlc_val = 0xFFU;
static const uint8_t payload_code[65] = {
0U, 1U, 2U, 3U, 4U, 5U, 6U, 7U, 8U,
/* 9 to 12 payload have DLC Code 12 Bytes */
CAN_DLC_VALUE_12_BYTES, CAN_DLC_VALUE_12_BYTES, CAN_DLC_VALUE_12_BYTES,
CAN_DLC_VALUE_12_BYTES,
/* 13 to 16 payload have DLC Code 16 Bytes */
CAN_DLC_VALUE_16_BYTES, CAN_DLC_VALUE_16_BYTES, CAN_DLC_VALUE_16_BYTES,
CAN_DLC_VALUE_16_BYTES,
/* 17 to 20 payload have DLC Code 20 Bytes */
CAN_DLC_VALUE_20_BYTES, CAN_DLC_VALUE_20_BYTES, CAN_DLC_VALUE_20_BYTES,
CAN_DLC_VALUE_20_BYTES,
/* 21 to 24 payload have DLC Code 24 Bytes */
CAN_DLC_VALUE_24_BYTES, CAN_DLC_VALUE_24_BYTES, CAN_DLC_VALUE_24_BYTES,
CAN_DLC_VALUE_24_BYTES,
/* 25 to 32 payload have DLC Code 32 Bytes */
CAN_DLC_VALUE_32_BYTES, CAN_DLC_VALUE_32_BYTES, CAN_DLC_VALUE_32_BYTES,
CAN_DLC_VALUE_32_BYTES, CAN_DLC_VALUE_32_BYTES, CAN_DLC_VALUE_32_BYTES,
CAN_DLC_VALUE_32_BYTES, CAN_DLC_VALUE_32_BYTES,
/* 33 to 48 payload have DLC Code 48 Bytes */
CAN_DLC_VALUE_48_BYTES, CAN_DLC_VALUE_48_BYTES, CAN_DLC_VALUE_48_BYTES,
CAN_DLC_VALUE_48_BYTES, CAN_DLC_VALUE_48_BYTES, CAN_DLC_VALUE_48_BYTES,
CAN_DLC_VALUE_48_BYTES, CAN_DLC_VALUE_48_BYTES, CAN_DLC_VALUE_48_BYTES,
CAN_DLC_VALUE_48_BYTES, CAN_DLC_VALUE_48_BYTES, CAN_DLC_VALUE_48_BYTES,
CAN_DLC_VALUE_48_BYTES, CAN_DLC_VALUE_48_BYTES, CAN_DLC_VALUE_48_BYTES,
CAN_DLC_VALUE_48_BYTES,
/* 49 to 64 payload have DLC Code 64 Bytes */
CAN_DLC_VALUE_64_BYTES, CAN_DLC_VALUE_64_BYTES, CAN_DLC_VALUE_64_BYTES,
CAN_DLC_VALUE_64_BYTES, CAN_DLC_VALUE_64_BYTES, CAN_DLC_VALUE_64_BYTES,
CAN_DLC_VALUE_64_BYTES, CAN_DLC_VALUE_64_BYTES, CAN_DLC_VALUE_64_BYTES,
CAN_DLC_VALUE_64_BYTES, CAN_DLC_VALUE_64_BYTES, CAN_DLC_VALUE_64_BYTES,
CAN_DLC_VALUE_64_BYTES, CAN_DLC_VALUE_64_BYTES, CAN_DLC_VALUE_64_BYTES,
CAN_DLC_VALUE_64_BYTES};
if (payloadSize <= 64U) {
ret_dlc_val = payload_code[payloadSize];
} else {
/* The argument is not a valid payload size,
so return invalid value 0xFF. */
}
return ret_dlc_val;
}
static uint8_t flexcan_compute_payload_len(uint8_t dlc_val)
{
uint8_t ret_payload_len = 0U;
if (dlc_val <= 8U) {
ret_payload_len = dlc_val;
} else if (dlc_val == CAN_DLC_VALUE_12_BYTES) {
ret_payload_len = 12U;
} else if (dlc_val == CAN_DLC_VALUE_16_BYTES) {
ret_payload_len = 16U;
} else if (dlc_val == CAN_DLC_VALUE_20_BYTES) {
ret_payload_len = 20U;
} else if (dlc_val == CAN_DLC_VALUE_24_BYTES) {
ret_payload_len = 24U;
} else if (dlc_val == CAN_DLC_VALUE_32_BYTES) {
ret_payload_len = 32U;
} else if (dlc_val == CAN_DLC_VALUE_48_BYTES) {
ret_payload_len = 48U;
} else if (dlc_val == CAN_DLC_VALUE_64_BYTES) {
ret_payload_len = 64U;
} else {
/* Do nothing. */
}
return ret_payload_len;
}
static inline uint32_t flexcan_get_mb_int_req(CAN_Type *base, uint8_t group)
{
uint32_t int_iflag = 0, int_req = 0;
switch (group) {
case 0U:
int_iflag = base->IFLAG1;
int_req = int_iflag & base->IMASK1;
break;
case 1U:
int_iflag = base->IFLAG2;
int_req = int_iflag & base->IMASK2;
break;
case 2U:
int_iflag = base->IFLAG3;
int_req = int_iflag & base->IMASK3;
break;
case 3U:
int_iflag = base->IFLAG4;
int_req = int_iflag & base->IMASK4;
break;
default:
break;
}
return int_req;
}
static inline uint32_t flexcan_get_mb_int_status_flag(CAN_Type *base,
uint8_t msgBufId)
{
uint32_t int_iflag = 0, ret_flag;
if (msgBufId <= 31U) {
int_iflag = base->IFLAG1;
ret_flag = ((int_iflag & base->IMASK1) >> msgBufId) & 1U;
} else if (msgBufId <= 63U) {
int_iflag = base->IFLAG2;
ret_flag = ((int_iflag & base->IMASK2) >> (msgBufId % 32U)) & 1U;
} else if (msgBufId <= 95U) {
int_iflag = base->IFLAG3;
ret_flag = ((int_iflag & base->IMASK3) >> (msgBufId % 32U)) & 1U;
} else if (msgBufId <= 127U) {
int_iflag = base->IFLAG4;
ret_flag = ((int_iflag & base->IMASK4) >> (msgBufId % 32U)) & 1U;
} else {
/* Invalid msgBufId value means check if any message buffer
interrupt is active. */
int_iflag = base->IFLAG1;
ret_flag = int_iflag & base->IMASK1;
int_iflag = base->IFLAG2;
ret_flag |= int_iflag & base->IMASK2;
int_iflag = base->IFLAG3;
ret_flag |= int_iflag & base->IMASK3;
int_iflag = base->IFLAG4;
ret_flag |= int_iflag & base->IMASK4;
}
return ret_flag;
}
static inline void flexcan_clear_mb_int_flag(CAN_Type *base, uint8_t msgBufId)
{
uint32_t mask = 1U << (msgBufId % 32U);
if (msgBufId <= 31U) {
base->IFLAG1 = mask;
} else if (msgBufId <= 63U) {
base->IFLAG2 = mask;
} else if (msgBufId <= 95U) {
base->IFLAG3 = mask;
} else if (msgBufId <= 127U) {
base->IFLAG4 = mask;
} else {
/* Do nothing. */
}
}
static void flexcan_copy_from_mb(uint32_t *addr, uint8_t *data, uint8_t len)
{
uint8_t temp_buf[64];
#if FLEXCAN_COPY_USE_BURST
if (IS_ALIGNED(addr, 4) && IS_ALIGNED(temp_buf, 4)) {
if (len <= 8U) {
flexcan_copy8(addr, (uint32_t *)temp_buf);
} else if (len <= 16U) {
flexcan_copy16(addr, (uint32_t *)temp_buf);
} else if (len <= 32U) {
flexcan_copy32(addr, (uint32_t *)temp_buf);
} else {
flexcan_copy32(addr, (uint32_t *)temp_buf);
flexcan_copy32(addr + 8U, (uint32_t *)(temp_buf + 32U));
}
} else {
uint8_t *mb_addr = (uint8_t *)addr;
for (uint8_t Idx = 0u; Idx < len; Idx++) {
temp_buf[Idx] = mb_addr[IDX_CONVERT(Idx)];
}
}
#else
uint8_t *mb_addr = (uint8_t *)addr;
for (uint8_t Idx = 0u; Idx < len; Idx++) {
temp_buf[Idx] = mb_addr[IDX_CONVERT(Idx)];
}
#endif
memcpy(data, temp_buf, len);
}
static void flexcan_copy_to_mb(uint32_t *addr, uint8_t *data, uint8_t len)
{
#if FLEXCAN_COPY_USE_BURST
if (IS_ALIGNED(addr, 4) && IS_ALIGNED(data, 4)) {
if (len <= 8U) {
flexcan_copy8((uint32_t *)data, addr);
} else if (len <= 16U) {
flexcan_copy16((uint32_t *)data, addr);
} else if (len <= 32U) {
flexcan_copy32((uint32_t *)data, addr);
} else {
flexcan_copy32((uint32_t *)data, addr);
flexcan_copy32((uint32_t *)(data + 32U), addr + 8U);
}
} else {
uint8_t *mb_addr = (uint8_t *)addr;
for (uint8_t Idx = 0u; Idx < len; Idx++) {
mb_addr[IDX_CONVERT(Idx)] = data[Idx];
}
}
#else
uint8_t *mb_addr = (uint8_t *)addr;
for (uint8_t Idx = 0u; Idx < len; Idx++) {
mb_addr[IDX_CONVERT(Idx)] = data[Idx];
}
#endif
}
#if FLEXCAN_COPY_USE_BURST
static inline void flexcan_copy8(uint32_t *src, uint32_t *dest)
{
uint32_t word0 = 0U, word1 = 0U;
__ASM volatile("ldmia %2, {%0, %1} \n"
#if CORE_LITTLE_ENDIAN
"rev %0, %0 \n"
"rev %1, %1 \n"
#endif
"stmia %3, {%0, %1} "
:"+r"(word0), "+r"(word1)
: "r"(src), "r"(dest)
: );
}
static inline void flexcan_copy16(uint32_t *src, uint32_t *dest)
{
uint32_t word0 = 0U, word1 = 0U, word2 = 0U, word3 = 0U;
__ASM volatile("ldmia %4, {%0, %1, %2, %3} \n"
#if CORE_LITTLE_ENDIAN
"rev %0, %0 \n"
"rev %1, %1 \n"
"rev %2, %2 \n"
"rev %3, %3 \n"
#endif
"stmia %5, {%0, %1, %2, %3} "
: "+r"(word0), "+r"(word1), "+r"(word2), "+r"(word3)
: "r"(src), "r"(dest)
: );
}
static inline void flexcan_copy32(uint32_t *src, uint32_t *dest)
{
__ASM volatile("ldmia %0, {r4-r11}\n"
#if CORE_LITTLE_ENDIAN
"rev r4, r4 \n"
"rev r5, r5 \n"
"rev r6, r6 \n"
"rev r7, r7 \n"
"rev r8, r8 \n"
"rev r9, r9 \n"
"rev r10, r10 \n"
"rev r11, r11 \n"
#endif
"stmia %1, {r4-r11} "
:
: "r"(src), "r"(dest)
: "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11",
"memory");
}
#endif
static inline bool flexcan_ext_nominal_bit_timing(
const flexcan_timing_config_t *nominal_bit_timing)
{
if ((nominal_bit_timing->preDivider - 1U > 0xFFU) ||
(nominal_bit_timing->rJumpwidth - 1U > 3U) ||
(nominal_bit_timing->propSeg - 1U > 7U) ||
(nominal_bit_timing->phaseSeg1 - 1U > 7U) ||
(nominal_bit_timing->phaseSeg2 - 1U > 7U)) {
return true;
} else {
return false;
}
}
/* Internal function implementation end */
/***************API Function implementation***************/
/* API function implementation start */
flexcan_status_e flexcan_init(flexcan_handle_t *handle,
const flexcan_config_t *config)
{
ASSERT(handle);
CAN_Type *base = (CAN_Type *)(handle->base_addr);
uint32_t mcrTemp;
uint32_t ctrl1Temp;
flexcan_status_e retVal = FLEXCAN_SUCCESS;
/* Assertion. */
ASSERT(config && base);
ASSERT((config->maxMbNum > 0) &&
(config->maxMbNum <= FLEXCAN_HAS_MESSAGE_BUFFER_MAX_NUMBER));
/* operate soft reset of SemidDrive enhancements. */
base->SOFT_RESET = 0x0;
/* Reset to known status.*/
(void)flexcan_reset(handle);
/* Check if FlexCAN Module already Enabled before calling Module_Config. */
if (!(base->MCR & CAN_MCR_MDIS_MASK)) {
retVal = flexcan_enable(handle, false);
}
if (retVal != FLEXCAN_SUCCESS)
return retVal;
/* Protocol-Engine clock source selection, This bit must be set
* when FlexCAN Module in Disable Mode.
*/
if (FLEXCAN_ClkSrcOsc == config->clkSrc) {
base->CTRL1 &= ~CAN_CTRL1_CLKSRC_MASK;
} else {
base->CTRL1 |= CAN_CTRL1_CLKSRC_MASK;
}
/* Enable FlexCAN Module before configuration. */
retVal = flexcan_enable(handle, true);
if (retVal != FLEXCAN_SUCCESS)
return retVal;
/* Enter Freeze Mode. */
retVal = flexcan_enter_freeze_mode(base, true);
if (retVal != FLEXCAN_SUCCESS)
return retVal;
/* Save current MCR value. */
mcrTemp = base->MCR;
/* Save current CTRL1 value. */
ctrl1Temp = base->CTRL1;
/* Set the maximum number of Message Buffers */
mcrTemp =
(mcrTemp & ~CAN_MCR_MAXMB_MASK) | CAN_MCR_MAXMB(config->maxMbNum - 1);
/* Disable busoff automatic recovering. */
ctrl1Temp |= CAN_CTRL1_BOFFREC_MASK;
/* Enable Loop Back Mode? */
if (config->enableLoopBack) {
ctrl1Temp &= ~CAN_CTRL1_LOM_MASK;
ctrl1Temp |= CAN_CTRL1_LPB_MASK;
mcrTemp &= ~CAN_MCR_SRXDIS_MASK;
} else {
ctrl1Temp &= ~CAN_CTRL1_LPB_MASK;
/* Disable the self reception feature when FlexCAN is not in loopback
* mode. */
mcrTemp |= CAN_MCR_SRXDIS_MASK;
/* Enable Listen-Only Mode? */
if (config->enableListenOnly) {
ctrl1Temp |= CAN_CTRL1_LOM_MASK;
} else {
ctrl1Temp &= ~CAN_CTRL1_LOM_MASK;
}
}
/* Enable Self Wake Up Mode? */
if (config->enableSelfWakeup) {
mcrTemp |= CAN_MCR_SLFWAK_MASK;
} else {
mcrTemp &= ~CAN_MCR_SLFWAK_MASK;
}
/* Enable Individual Rx Masking? */
if (config->enableIndividMask) {
mcrTemp |= CAN_MCR_IRMQ_MASK;
} else {
mcrTemp &= ~CAN_MCR_IRMQ_MASK;
}
#if FLEXCAN_HAS_DOZE_MODE_SUPPORT
/* Enable Doze Mode? */
if (config->enableDoze) {
mcrTemp |= CAN_MCR_DOZE_MASK;
handle->enableDoze = true;
} else {
mcrTemp &= ~CAN_MCR_DOZE_MASK;
handle->enableDoze = false;
}
#endif
/* Enable CAN FD operation? */
if (config->enableCANFD) {
mcrTemp |= CAN_MCR_FDEN_MASK;
flexcan_fd_init(base, &config->can_fd_cfg);
} else {
mcrTemp &= ~CAN_MCR_FDEN_MASK;
ctrl1Temp |= CAN_CTRL1_SMP_MASK;
}
/* Enable PNET setting? */
if (config->enablePretendedNetworking) {
mcrTemp |= CAN_MCR_PNET_EN_MASK;
flexcan_pnet_init(base, &config->pnet_cfg);
} else {
mcrTemp &= ~CAN_MCR_PNET_EN_MASK;
}
/* Select ordering mechanism for mb transmission. */
if (config->enableLBUFTransmittedFirst) {
ctrl1Temp |= CAN_CTRL1_LBUF_MASK;
} else {
ctrl1Temp &= ~CAN_CTRL1_LBUF_MASK;
}
/* Save CTRL1 Configuration. */
base->CTRL1 = ctrl1Temp;
/* Save MCR Configuation. */
base->MCR = mcrTemp;
/* Baud Rate Configuration.*/
if (config->enableCANFD) {
flexcan_fd_set_timing_config(handle, &config->nominalBitTiming,
&config->dataBitTiming);
} else {
flexcan_classic_set_timing_config(handle, &config->nominalBitTiming);
}
/* mask access reserved address(0xc) error */
base->ERR_IRQ_STATUS_EN &= ~ERR_IRQ_STATUS_PSLVERR_INT_EN_MASK;
/* Re-freeze FlexCAN Module after Config finish,
* because it may be unfreezed during config.
* It's upper layer software's responsibility
* to unfreeze FlexCAN when ready to take part
* in communication on the bus.
*/
retVal = flexcan_enter_freeze_mode(base, true);
if (retVal != FLEXCAN_SUCCESS)
return retVal;
return retVal;
}
flexcan_status_e flexcan_enable(flexcan_handle_t *handle, bool enable)
{
ASSERT(handle);
CAN_Type *base = (CAN_Type *)(handle->base_addr);
ASSERT(base);
uint32_t timeoutCnt = FLEXCAN_TIMEOUT_COUNTER;
flexcan_status_e retVal = FLEXCAN_SUCCESS;
if (enable) {
base->MCR &= ~CAN_MCR_MDIS_MASK;
/* Wait FlexCAN exit from low-power mode. */
while ((base->MCR & CAN_MCR_LPMACK_MASK) && (timeoutCnt > 0)) {
timeoutCnt--;
}
if (base->MCR & CAN_MCR_LPMACK_MASK) {
retVal = FLEXCAN_FAIL;
ssdk_printf(SSDK_ERR, "\r\nExit low-power mode timeout\r\n");
}
} else {
base->MCR |= CAN_MCR_MDIS_MASK;
/* Wait FlexCAN enter low-power mode. */
while (!(base->MCR & CAN_MCR_LPMACK_MASK) && (timeoutCnt > 0)) {
timeoutCnt--;
}
if (!(base->MCR & CAN_MCR_LPMACK_MASK)) {
retVal = FLEXCAN_FAIL;
ssdk_printf(SSDK_ERR, "\r\nEnter low-power mode timeout\r\n");
}
}
return retVal;
}
flexcan_status_e flexcan_freeze(flexcan_handle_t *handle, bool freeze)
{
ASSERT(handle);
CAN_Type *base = (CAN_Type *)(handle->base_addr);
ASSERT(base);
flexcan_status_e retVal;
if (freeze) {
retVal = flexcan_enter_freeze_mode(base, true);
} else {
retVal = flexcan_exit_freeze_mode(base, true);
}
return retVal;
}
flexcan_status_e flexcan_reset(flexcan_handle_t *handle)
{
ASSERT(handle);
CAN_Type *base = (CAN_Type *)(handle->base_addr);
ASSERT(base);
uint8_t i;
bool moduleEnabled;
uint32_t timeoutCnt = FLEXCAN_TIMEOUT_COUNTER;
flexcan_status_e retVal = FLEXCAN_SUCCESS;
/* The module must should be first exit from low power
* mode, and then soft reset can be applied.
*/
if (base->MCR & CAN_MCR_MDIS_MASK) {
moduleEnabled = false;
(void)flexcan_enable(handle, true);
} else {
/* Enter Disable mode and then exit,
* to force exiting from any low power mode.
*/
(void)flexcan_enable(handle, false);
(void)flexcan_enable(handle, true);
moduleEnabled = true;
}
#if (FLEXCAN_HAS_DOZE_MODE_SUPPORT != 0)
/* De-ASSERT DOZE Enable Bit. */
base->MCR &= ~CAN_MCR_DOZE_MASK;
#endif
/* Assert Soft Reset Signal. */
base->MCR |= CAN_MCR_SOFTRST_MASK;
/* Wait until FlexCAN reset completes. */
while ((base->MCR & CAN_MCR_SOFTRST_MASK) && (timeoutCnt > 0)) {
timeoutCnt--;
}
if (base->MCR & CAN_MCR_SOFTRST_MASK) {
retVal = FLEXCAN_FAIL;
ssdk_printf(SSDK_ERR, "\r\nFlexCAN reset operation timeout\r\n");
return retVal;
}
/* Reset MCR rigister. */
#if FLEXCAN_HAS_GLITCH_FILTER
base->MCR |= CAN_MCR_WRNEN_MASK | CAN_MCR_WAKSRC_MASK |
CAN_MCR_MAXMB(FLEXCAN_HAS_MESSAGE_BUFFER_MAX_NUMBER - 1);
#else
base->MCR |= CAN_MCR_WRNEN_MASK |
CAN_MCR_MAXMB(FLEXCAN_HAS_MESSAGE_BUFFER_MAX_NUMBER - 1);
#endif
/* Reset CTRL1 and CTRL2 rigister. */
base->CTRL1 = 0U;
base->CTRL2 =
CAN_CTRL2_TASD(0x16) | CAN_CTRL2_RRS_MASK | CAN_CTRL2_EACEN_MASK;
/* Clean all individual Rx Mask of Message Buffers. */
for (i = 0; i < FLEXCAN_HAS_MESSAGE_BUFFER_MAX_NUMBER; i++) {
base->RXIMR[i] = 0x3FFFFFFF;
}
/* Enable unrestricted write access to FlexCAN memory. */
base->CTRL2 |= CAN_CTRL2_WRMFRZ_MASK;
/* avoid ecc error, clean reserved area 96Byte */
for (uint8_t i = 0; i < 24; i++) {
*(((uint32_t *)&base->RESERVED_4[0]) + i) = 0x0U;
}
/* Clean Global Mask of Message Buffers. */
base->RXMGMASK = 0x3FFFFFFF;
/* Clean Global Mask of Message Buffer 14. */
base->RX14MASK = 0x3FFFFFFF;
/* Clean Global Mask of Message Buffer 15. */
base->RX15MASK = 0x3FFFFFFF;
/* Clean Global Mask of Rx FIFO. */
base->RXFGMASK = 0x3FFFFFFF;
/* Reset FDCTRL register. */
base->FDCTRL = 0x80000000;
/* Clean Message Buffer region. */
for (i = 0; i < FLEXCAN_HAS_MESSAGE_BUFFER_MAX_NUMBER; i++) {
base->MB[i].CS = 0x0;
base->MB[i].ID = 0x0;
base->MB[i].WORD0 = 0x0;
base->MB[i].WORD1 = 0x0;
}
/* Clean CAN FD SMB region. */
flexcan_fd_clean_smb_region(base);
/* Enable write access restriction. */
base->CTRL2 &= ~CAN_CTRL2_WRMFRZ_MASK;
if (!moduleEnabled) {
retVal = flexcan_enable(handle, false);
}
return retVal;
}
void flexcan_classic_set_timing_config(flexcan_handle_t *handle,
const flexcan_timing_config_t *config)
{
/* Assertion. */
ASSERT(handle);
CAN_Type *base = (CAN_Type *)(handle->base_addr);
ASSERT(config && base);
/* Enter Freeze Mode. */
(void)flexcan_enter_freeze_mode(base, true);
if (!flexcan_ext_nominal_bit_timing(config)) {
base->CBT &= ~CAN_CBT_BTF_MASK;
/* Cleaning previous Timing Setting. */
base->CTRL1 &= ~(CAN_CTRL1_PRESDIV_MASK | CAN_CTRL1_RJW_MASK |
CAN_CTRL1_PSEG1_MASK | CAN_CTRL1_PSEG2_MASK |
CAN_CTRL1_PROPSEG_MASK);
/* Updating Timing Setting according to configuration structure. */
base->CTRL1 |= (CAN_CTRL1_PRESDIV(config->preDivider - 1U) |
CAN_CTRL1_RJW(config->rJumpwidth - 1U) |
CAN_CTRL1_PROPSEG(config->propSeg - 1U) |
CAN_CTRL1_PSEG1(config->phaseSeg1 - 1U) |
CAN_CTRL1_PSEG2(config->phaseSeg2 - 1U));
} else {
if ((config->preDivider - 1 > 0x3FFU) ||
(config->rJumpwidth - 1 > 0x1FU) ||
(config->propSeg - 1 > 0x3FU) ||
(config->phaseSeg1 - 1 > 0x1FU ||
(config->phaseSeg2 - 1 > 0x1FU))) {
ssdk_printf(SSDK_ERR, "\r\nwrong arbitration phase Timing Setting\r\n");
}
/* Cleaning previous arbitration phase Timing Setting. */
base->CBT &=
~(CAN_CBT_EPRESDIV_MASK | CAN_CBT_ERJW_MASK | CAN_CBT_EPSEG1_MASK |
CAN_CBT_EPSEG2_MASK | CAN_CBT_EPROPSEG_MASK);
/* Updating arbitration phase Timing Setting according to configuration
* structure. */
base->CBT |= (CAN_CBT_BTF(1U) | /* Use CBT instead of CTRL1. */
CAN_CBT_EPRESDIV(config->preDivider - 1U) |
CAN_CBT_ERJW(config->rJumpwidth - 1U) |
CAN_CBT_EPROPSEG(config->propSeg - 1U) |
CAN_CBT_EPSEG1(config->phaseSeg1 - 1U) |
CAN_CBT_EPSEG2(config->phaseSeg2 - 1U));
}
/* Exit Freeze Mode. */
(void)flexcan_exit_freeze_mode(base, true);
}
void flexcan_fd_set_timing_config(
flexcan_handle_t *handle, const flexcan_timing_config_t *arbitrPhaseConfig,
const flexcan_timing_config_t *dataPhaseConfig)
{
/* Assertion. */
ASSERT(handle && arbitrPhaseConfig && dataPhaseConfig);
CAN_Type *base = (CAN_Type *)(handle->base_addr);
ASSERT(base);
/* Enter Freeze Mode. */
(void)flexcan_enter_freeze_mode(base, true);
if ((arbitrPhaseConfig->preDivider - 1 > 0x3FFU) ||
(arbitrPhaseConfig->rJumpwidth - 1 > 0x1FU) ||
(arbitrPhaseConfig->propSeg - 1 > 0x3FU) ||
(arbitrPhaseConfig->phaseSeg1 - 1 > 0x1FU ||
(arbitrPhaseConfig->phaseSeg2 - 1 > 0x1FU))) {
ssdk_printf(SSDK_ERR, "\r\nwrong arbitration phase Timing Setting\r\n");
}
if ((dataPhaseConfig->preDivider - 1 > 0x3FFU) ||
(dataPhaseConfig->rJumpwidth - 1 > 0x7U) ||
(dataPhaseConfig->propSeg > 0x1FU) ||
(dataPhaseConfig->phaseSeg1 - 1 > 0x7U ||
(dataPhaseConfig->phaseSeg2 - 1 > 0x7U))) {
ssdk_printf(SSDK_ERR, "\r\nwrong data phase Timing Setting\r\n");
}
/* Cleaning previous arbitration phase Timing Setting. */
base->CBT &=
~(CAN_CBT_EPRESDIV_MASK | CAN_CBT_ERJW_MASK | CAN_CBT_EPSEG1_MASK |
CAN_CBT_EPSEG2_MASK | CAN_CBT_EPROPSEG_MASK);
/* Updating arbitration phase Timing Setting according to configuration
* structure. */
base->CBT |= (CAN_CBT_BTF(1U) | /* Use CBT instead of CTRL1. */
CAN_CBT_EPRESDIV(arbitrPhaseConfig->preDivider - 1U) |
CAN_CBT_ERJW(arbitrPhaseConfig->rJumpwidth - 1U) |
CAN_CBT_EPROPSEG(arbitrPhaseConfig->propSeg - 1U) |
CAN_CBT_EPSEG1(arbitrPhaseConfig->phaseSeg1 - 1U) |
CAN_CBT_EPSEG2(arbitrPhaseConfig->phaseSeg2 - 1U));
/* Cleaning previous data phase Timing Setting. */
base->FDCBT &= ~(CAN_FDCBT_FPRESDIV_MASK | CAN_FDCBT_FRJW_MASK |
CAN_FDCBT_FPSEG1_MASK | CAN_FDCBT_FPSEG2_MASK |
CAN_FDCBT_FPROPSEG_MASK);
/* Updating data phase Timing Setting according to configuration structure.
*/
base->FDCBT |= (CAN_FDCBT_FPRESDIV(dataPhaseConfig->preDivider - 1U) |
CAN_FDCBT_FRJW(dataPhaseConfig->rJumpwidth - 1U) |
CAN_FDCBT_FPROPSEG(dataPhaseConfig->propSeg) |
CAN_FDCBT_FPSEG1(dataPhaseConfig->phaseSeg1 - 1U) |
CAN_FDCBT_FPSEG2(dataPhaseConfig->phaseSeg2 - 1U));
/* Exit Freeze Mode. */
(void)flexcan_exit_freeze_mode(base, true);
}
void flexcan_read_wmb(flexcan_handle_t *handle, uint8_t wmbIndex,
flexcan_frame_t *wmb)
{
/* Assertion. */
ASSERT(handle && wmb);
ASSERT(wmbIndex < FLEXCAN_HAS_WAKEUP_MESSAGE_BUFFER_NUMBER);
CAN_Type *base = (CAN_Type *)(handle->base_addr);
ASSERT(base);
uint32_t *payloadAddr;
uint32_t cs_temp;
cs_temp = base->WMB[wmbIndex].WMB_CS;
wmb->format = (cs_temp & CAN_WMBn_CS_IDE_MASK) >> CAN_WMBn_CS_IDE_SHIFT;
wmb->type = (cs_temp & CAN_WMBn_CS_RTR_MASK) >> CAN_WMBn_CS_RTR_SHIFT;
wmb->length = (cs_temp & CAN_WMBn_CS_DLC_MASK) >> CAN_WMBn_CS_DLC_SHIFT;
if (wmb->format) {
wmb->id = base->WMB[wmbIndex].WMB_ID;
} else {
wmb->id = (base->WMB[wmbIndex].WMB_ID >> CAN_ID_STD_SHIFT);
}
/* store wakeup message payload. */
payloadAddr = (uint32_t *)(&base->WMB[wmbIndex].WMB_D03);
flexcan_copy_from_mb(payloadAddr, wmb->dataBuffer, wmb->length);
}
void flexcan_deinit(flexcan_handle_t *handle)
{
ASSERT(handle);
(void)flexcan_freeze(handle, true);
/* Reset all Register Contents. */
(void)flexcan_reset(handle);
/* Disable FlexCAN module. */
(void)flexcan_enable(handle, false);
for (size_t i = 0; i < FLEXCAN_HAS_MESSAGE_BUFFER_MAX_NUMBER; i++) {
handle->mbState[i] = FLEXCAN_StateIdle;
}
/* Clear MB-used bitmap. */
handle->mb_used_mask[0] = 0x0;
handle->mb_used_mask[1] = 0x0;
handle->rxFifoState = FLEXCAN_StateIdle;
}
flexcan_status_e flexcan_request_sleep(flexcan_handle_t *handle, bool request)
{
ASSERT(handle);
CAN_Type *base = (CAN_Type *)(handle->base_addr);
ASSERT(base);
uint32_t timeoutCnt = FLEXCAN_TIMEOUT_COUNTER;
flexcan_status_e retVal = FLEXCAN_SUCCESS;
/* {lowpower_en, register mode} */
base->LOWPOWER_MODE = (!!request) << 1 | 0x1;
if (request) {
/* Wait FlexCAN enter low-power mode. */
while (!(base->MCR & CAN_MCR_LPMACK_MASK) && (timeoutCnt > 0)) {
timeoutCnt--;
}
if (!(base->MCR & CAN_MCR_LPMACK_MASK)) {
retVal = FLEXCAN_FAIL;
ssdk_printf(SSDK_ERR, "\r\nEnter low-power mode timeout\r\n");
}
} else {
#if FLEXCAN_HAS_DOZE_MODE_SUPPORT
if (handle->enableDoze) {
base->MCR |= CAN_MCR_DOZE_MASK;
}
#endif
/* Wait FlexCAN exit from low-power mode. */
while ((base->MCR & CAN_MCR_LPMACK_MASK) && (timeoutCnt > 0)) {
timeoutCnt--;
}
if (base->MCR & CAN_MCR_LPMACK_MASK) {
retVal = FLEXCAN_FAIL;
ssdk_printf(SSDK_ERR, "\r\nExit low-power mode timeout\r\n");
}
}
return retVal;
}
void flexcan_set_rx_mb_global_mask(flexcan_handle_t *handle, uint32_t mask)
{
ASSERT(handle);
CAN_Type *base = (CAN_Type *)(handle->base_addr);
ASSERT(base);
/* Enter Freeze Mode. */
(void)flexcan_enter_freeze_mode(base, true);
/* Setting Global Mask value. */
base->RXMGMASK = mask;
base->RX14MASK = mask;
base->RX15MASK = mask;
/* Exit Freeze Mode. */
(void)flexcan_exit_freeze_mode(base, true);
}
void flexcan_set_rx_fifo_global_mask(flexcan_handle_t *handle, uint32_t mask)
{
ASSERT(handle);
CAN_Type *base = (CAN_Type *)(handle->base_addr);
ASSERT(base);
/* Enter Freeze Mode. */
(void)flexcan_enter_freeze_mode(base, true);
/* Setting Rx FIFO Global Mask value. */
base->RXFGMASK = mask;
/* Exit Freeze Mode. */
(void)flexcan_exit_freeze_mode(base, true);
}
void flexcan_set_rx_individual_mask(flexcan_handle_t *handle, uint8_t maskIdx,
uint32_t mask)
{
ASSERT(handle);
CAN_Type *base = (CAN_Type *)(handle->base_addr);
ASSERT(base);
ASSERT(maskIdx <= (base->MCR & CAN_MCR_MAXMB_MASK));
/* Enter Freeze Mode. */
(void)flexcan_enter_freeze_mode(base, true);
/* Setting Rx Individual Mask value. */
base->RXIMR[maskIdx] = mask;
/* Exit Freeze Mode. */
(void)flexcan_exit_freeze_mode(base, true);
}
void flexcan_set_tx_mb_config(flexcan_handle_t *handle, uint8_t mbIdx,
bool tx_by_interrupt)
{
/* Assertion. */
ASSERT(handle);
CAN_Type *base = (CAN_Type *)(handle->base_addr);
ASSERT(base);
ASSERT(mbIdx <= (base->MCR & CAN_MCR_MAXMB_MASK));
ASSERT(!flexcan_is_mb_occupied(handle, mbIdx));
uint32_t *msgBufAddr;
/* Get message buffer address. */
msgBufAddr = flexcan_get_msg_buf_addr(base, mbIdx);
/* CS filed: Inactivate Message Buffer. */
mb_cs_field(msgBufAddr) = 0U;
/* Clean ID filed. */
mb_id_field(msgBufAddr) = 0U;
/* Tx by interrupt or polling? */
if (tx_by_interrupt) {
/* Enable Message Buffer Interrupt. */
flexcan_enable_mb_int(base, mbIdx);
} else {
/* Disable Message Buffer Interrupt. */
flexcan_disable_mb_int(base, mbIdx);
}
/* Set MB is used. */
handle->mb_used_mask[BITMAP_INT(mbIdx)] |= 1U << BITMAP_BIT_IN_INT(mbIdx);
}
void flexcan_set_rx_mb_config(flexcan_handle_t *handle, uint8_t mbIdx,
const flexcan_rx_mb_config_t *config)
{
/* Assertion. */
ASSERT(handle);
CAN_Type *base = (CAN_Type *)(handle->base_addr);
ASSERT(base);
ASSERT(mbIdx <= (base->MCR & CAN_MCR_MAXMB_MASK));
ASSERT(!flexcan_is_mb_occupied(handle, mbIdx));
ASSERT(config);
uint32_t *msgBufAddr;
uint32_t cs_temp = 0U;
/* Get message buffer address. */
msgBufAddr = flexcan_get_msg_buf_addr(base, mbIdx);
/* CS field: Inactivate Message Buffer. */
mb_cs_field(msgBufAddr) = 0U;
/* ID field: Clean Message Buffer content. */
mb_id_field(msgBufAddr) = 0U;
if (config->format == FLEXCAN_EXTEND_FRAME) {
/* Setup Message Buffer ID. */
mb_id_field(msgBufAddr) =
(config->id) & (CAN_ID_EXT_MASK | CAN_ID_STD_MASK);
/* Setup Message Buffer format. */
cs_temp |= CAN_CS_IDE_MASK;
} else {
/* Setup Message Buffer ID. */
mb_id_field(msgBufAddr) =
((config->id) << CAN_ID_STD_SHIFT) & CAN_ID_STD_MASK;
}
/* Activate Rx Message Buffer. */
cs_temp |= CAN_CS_CODE(FLEXCAN_RxMbEmpty);
mb_cs_field(msgBufAddr) = cs_temp;
/* Set MB is used. */
handle->mb_used_mask[BITMAP_INT(mbIdx)] |= 1U << BITMAP_BIT_IN_INT(mbIdx);
}
void flexcan_set_rx_fifo_config(flexcan_handle_t *handle,
const flexcan_rx_fifo_config_t *config)
{
/* Assertion. */
ASSERT(handle);
CAN_Type *base = (CAN_Type *)(handle->base_addr);
ASSERT(base);
ASSERT(config);
ASSERT(config->idFilterNum <= 128);
/* Rx FIFO can only be enabled when CAN FD feature is disabled. */
ASSERT(!(base->MCR & CAN_MCR_FDEN_MASK));
volatile uint32_t *idFilterRegion = (volatile uint32_t *)(&base->MB[6].CS);
uint8_t setup_mb, i, rffn = 0;
/* Get the setup_mb value. */
setup_mb = (base->MCR & CAN_MCR_MAXMB_MASK) >> CAN_MCR_MAXMB_SHIFT;
setup_mb = (setup_mb < FLEXCAN_HAS_MESSAGE_BUFFER_MAX_NUMBER)
? setup_mb
: FLEXCAN_HAS_MESSAGE_BUFFER_MAX_NUMBER;
/* Enter Freeze Mode. */
(void)flexcan_enter_freeze_mode(base, true);
/* Determine RFFN value. */
for (i = 0; i <= 0xF; i++) {
if ((8 * (i + 1)) >= config->idFilterNum) {
rffn = i;
ASSERT(((setup_mb - 8) - (2 * rffn)) > 0);
base->CTRL2 =
(base->CTRL2 & ~CAN_CTRL2_RFFN_MASK) | CAN_CTRL2_RFFN(rffn);
break;
}
}
/* Clean ID filter table occuyied Message Buffer Region. */
rffn = (rffn + 1) * 8;
for (i = 0; i < rffn; i++) {
idFilterRegion[i] = 0x0;
}
/* Disable unused Rx FIFO Filter. */
for (i = config->idFilterNum; i < rffn; i++) {
idFilterRegion[i] = 0xFFFFFFFFU;
}
/* Copy ID filter table to Message Buffer Region. */
for (i = 0; i < config->idFilterNum; i++) {
idFilterRegion[i] = config->filter_tab[i].filter_code;
ssdk_printf(SSDK_DEBUG, "\r\nCAN Rx FIFO ID filter table[%d] = %x\r\n", i,
idFilterRegion[i]);
}
/* Setup ID Fitlter Type. */
switch (config->idFilterType) {
case FLEXCAN_RxFifoFilterTypeA:
base->MCR = (base->MCR & ~CAN_MCR_IDAM_MASK) | CAN_MCR_IDAM(0x0);
break;
case FLEXCAN_RxFifoFilterTypeB:
base->MCR = (base->MCR & ~CAN_MCR_IDAM_MASK) | CAN_MCR_IDAM(0x1);
break;
case FLEXCAN_RxFifoFilterTypeC:
base->MCR = (base->MCR & ~CAN_MCR_IDAM_MASK) | CAN_MCR_IDAM(0x2);
break;
case FLEXCAN_RxFifoFilterTypeD:
/* All frames rejected. */
base->MCR = (base->MCR & ~CAN_MCR_IDAM_MASK) | CAN_MCR_IDAM(0x3);
break;
default:
break;
}
/* Setting Message Reception Priority. */
if (config->priority == FLEXCAN_RxFifoPrioHigh) {
/* Matching starts from Rx FIFO and continues on Mailboxes. */
base->CTRL2 &= ~CAN_CTRL2_MRP_MASK;
} else {
/* Matching starts from Mailboxes and continues on Rx FIFO. */
base->CTRL2 |= CAN_CTRL2_MRP_MASK;
}
/* Enable Rx Message FIFO. */
base->MCR |= CAN_MCR_RFEN_MASK;
/* Exit Freeze Mode. */
(void)flexcan_exit_freeze_mode(base, true);
/* Set MB 5&6&7 is used. */
handle->mb_used_mask[0] |= (1U << 5) | (1U << 6) | (1U << 7);
}
void flexcan_create_handle(flexcan_handle_t *handle, uint8_t controller_id,
void *reg_base, uint8_t irq_num,
flexcan_transfer_callback_t callback, void *userData)
{
ASSERT(handle);
ASSERT(controller_id < MAX_FLEXCAN_CH);
ASSERT(reg_base);
/* Clean FlexCAN transfer handle. */
memset(handle, 0, sizeof(*handle));
handle->controller_id = controller_id;
handle->irq_num = irq_num;
/* Register base address. */
handle->base_addr = reg_base;
/* Register Callback function. */
handle->callback = callback;
handle->userData = userData;
}
void flexcan_enable_interrupts(flexcan_handle_t *handle, uint32_t mask)
{
ASSERT(handle);
CAN_Type *base = (CAN_Type *)(handle->base_addr);
ASSERT(base);
/* Solve Wake Up Interrupt. */
if (mask & FLEXCAN_WakeUpInterruptEnable) {
base->MCR |= CAN_MCR_WAKMSK_MASK;
}
/* Solve others. */
base->CTRL1 |= (mask & (~((uint32_t)FLEXCAN_WakeUpInterruptEnable)));
}
void flexcan_disable_interrupts(flexcan_handle_t *handle, uint32_t mask)
{
ASSERT(handle);
CAN_Type *base = (CAN_Type *)(handle->base_addr);
ASSERT(base);
/* Solve Wake Up Interrupt. */
if (mask & FLEXCAN_WakeUpInterruptEnable) {
base->MCR &= ~CAN_MCR_WAKMSK_MASK;
}
/* Solve others. */
base->CTRL1 &= ~(mask & (~((uint32_t)FLEXCAN_WakeUpInterruptEnable)));
}
uint32_t flexcan_get_mb_iflag(flexcan_handle_t *handle, uint8_t msgBufId)
{
ASSERT(handle);
CAN_Type *base = (CAN_Type *)(handle->base_addr);
ASSERT(base);
uint32_t int_flag = 0;
if (msgBufId <= 31U) {
int_flag = (base->IFLAG1 >> msgBufId) & 1U;
} else if (msgBufId <= 63U) {
int_flag = (base->IFLAG2 >> (msgBufId % 32U)) & 1U;
} else if (msgBufId <= 95U) {
int_flag = (base->IFLAG3 >> (msgBufId % 32U)) & 1U;
} else if (msgBufId <= 127U) {
int_flag = (base->IFLAG4 >> (msgBufId % 32U)) & 1U;
} else {
/* Invalid msgBufId value means check if any message buffer
interrupt is active. */
int_flag = base->IFLAG1;
int_flag |= base->IFLAG2;
int_flag |= base->IFLAG3;
int_flag |= base->IFLAG4;
}
return int_flag;
}
flexcan_status_e flexcan_send_nonblocking(flexcan_handle_t *handle,
flexcan_mb_transfer_t *xfer,
uint8_t padding_val)
{
/* Assertion. */
ASSERT(handle);
ASSERT(xfer);
CAN_Type *base = (CAN_Type *)(handle->base_addr);
ASSERT(xfer->mbIdx <= (base->MCR & CAN_MCR_MAXMB_MASK));
ASSERT(!flexcan_is_mb_occupied(handle, xfer->mbIdx));
/* Check if Message Buffer is idle. */
if (FLEXCAN_StateIdle == handle->mbState[xfer->mbIdx]) {
/* Distinguish transmit type. */
if (FLEXCAN_FrameTypeRemote == xfer->pFrame->type) {
handle->mbState[xfer->mbIdx] = FLEXCAN_StateTxRemote;
/* Register user Frame buffer to receive remote Frame. */
handle->pMBFrameBuf[xfer->mbIdx] = xfer->pFrame;
} else {
handle->mbState[xfer->mbIdx] = FLEXCAN_StateTxData;
}
if (FLEXCAN_SUCCESS == flexcan_write_tx_mb(handle, xfer->mbIdx,
xfer->pFrame, padding_val)) {
return FLEXCAN_SUCCESS;
} else {
handle->mbState[xfer->mbIdx] = FLEXCAN_StateIdle;
return FLEXCAN_FAIL;
}
} else {
return FLEXCAN_TX_BUSY;
}
}
flexcan_status_e flexcan_receive_nonblocking(flexcan_handle_t *handle,
flexcan_mb_transfer_t *xfer)
{
/* Assertion. */
ASSERT(handle);
CAN_Type *base = (CAN_Type *)(handle->base_addr);
/* Assertion. */
ASSERT(xfer);
ASSERT(xfer->mbIdx <= (base->MCR & CAN_MCR_MAXMB_MASK));
ASSERT(!flexcan_is_mb_occupied(handle, xfer->mbIdx));
/* Check if Message Buffer is idle. */
if (FLEXCAN_StateIdle == handle->mbState[xfer->mbIdx]) {
handle->mbState[xfer->mbIdx] = FLEXCAN_StateRxData;
/* Register Message Buffer. */
handle->pMBFrameBuf[xfer->mbIdx] = xfer->pFrame;
/* Enable Message Buffer Interrupt. */
flexcan_enable_mb_int(base, xfer->mbIdx);
return FLEXCAN_SUCCESS;
} else {
return FLEXCAN_RX_BUSY;
}
}
flexcan_status_e flexcan_receive_fifo_nonblocking(flexcan_handle_t *handle,
flexcan_fifo_transfer_t *xfer)
{
/* Assertion. */
ASSERT(handle);
ASSERT(xfer);
CAN_Type *base = (CAN_Type *)(handle->base_addr);
/* Check if Message Buffer is idle. */
if (FLEXCAN_StateIdle == handle->rxFifoState) {
handle->rxFifoState = FLEXCAN_StateRxFifo;
/* Register Message Buffer. */
handle->pRxFifoFrameBuf = xfer->pFrame;
/* Enable Message Buffer Interrupt. */
flexcan_enable_mb_int(base, RX_FIFO_FRAME_AVL_MB_ID);
flexcan_enable_mb_int(base, RX_FIFO_ALMOST_FULL_MB_ID);
flexcan_enable_mb_int(base, RX_FIFO_OVERFLOW_MB_ID);
return FLEXCAN_SUCCESS;
} else {
return FLEXCAN_RX_FIFO_BUSY;
}
}
flexcan_status_e flexcan_write_tx_mb(flexcan_handle_t *handle, uint8_t mbIdx,
const flexcan_frame_t *txFrame,
uint8_t padding_val)
{
/* Assertion. */
ASSERT(handle);
CAN_Type *base = (CAN_Type *)(handle->base_addr);
ASSERT(base);
ASSERT(mbIdx <= (base->MCR & CAN_MCR_MAXMB_MASK));
ASSERT(!flexcan_is_mb_occupied(handle, mbIdx));
ASSERT(txFrame);
ASSERT(((!txFrame->isCANFDFrame) && (txFrame->length <= 8)) ||
((txFrame->isCANFDFrame) && (txFrame->length <= 64)));
uint32_t cs_temp = 0;
uint32_t *msgBufAddr = flexcan_get_msg_buf_addr(base, mbIdx);
uint8_t dlc_val = flexcan_compute_dlc_val(txFrame->length);
uint8_t payload_len = flexcan_compute_payload_len(dlc_val);
uint32_t *mb_data = mb_data_field(msgBufAddr);
/* Check if Message Buffer is activated. */
if (CAN_CS_CODE(FLEXCAN_TxMbDataOrRemote) !=
(mb_cs_field(msgBufAddr) & CAN_CS_CODE_MASK)) {
/* Inactive Tx Message Buffer. */
mb_cs_field(msgBufAddr) =
(mb_cs_field(msgBufAddr) & ~CAN_CS_CODE_MASK) |
CAN_CS_CODE(FLEXCAN_TxMbInactive);
if (FLEXCAN_EXTEND_FRAME == txFrame->format) {
/* Fill Message ID field. */
mb_id_field(msgBufAddr) = txFrame->id;
/* Fill Message Format field. */
cs_temp |= CAN_CS_SRR_MASK | CAN_CS_IDE_MASK;
} else {
/* Fill Message ID field. */
mb_id_field(msgBufAddr) =
((txFrame->id) << CAN_ID_STD_SHIFT) & CAN_ID_STD_MASK;
}
/* Fill Message Type field. */
if (txFrame->isCANFDFrame) {
cs_temp |= CAN_CS_EDL_MASK | CAN_CS_SRR_MASK;
if (txFrame->isCANFDBrsEn) {
cs_temp |= CAN_CS_BRS_MASK;
}
} else {
if (txFrame->type == FLEXCAN_FrameTypeRemote) {
cs_temp |= CAN_CS_RTR_MASK;
}
}
if (txFrame->length < payload_len) {
/* Pad unspecified data in CAN FD frames > 8 bytes. */
memset((void *)(txFrame->dataBuffer + txFrame->length), padding_val,
payload_len - txFrame->length);
}
cs_temp |= CAN_CS_CODE(FLEXCAN_TxMbDataOrRemote) | CAN_CS_DLC(dlc_val);
flexcan_copy_to_mb(mb_data, (uint8_t *)txFrame->dataBuffer,
payload_len);
/* Activate Tx Message Buffer. */
mb_cs_field(msgBufAddr) = cs_temp;
return FLEXCAN_SUCCESS;
} else {
/* Tx Message Buffer is activated, return immediately. */
ssdk_printf(SSDK_DEBUG, "Write MB[%d] failed, MB cs field = 0x%x\r\n",
mbIdx, mb_cs_field(msgBufAddr));
return FLEXCAN_FAIL;
}
}
flexcan_status_e flexcan_read_rx_mb(flexcan_handle_t *handle, uint8_t mbIdx,
flexcan_frame_t *rxFrame)
{
/* Assertion. */
ASSERT(handle);
CAN_Type *base = (CAN_Type *)(handle->base_addr);
ASSERT(base);
ASSERT(mbIdx <= (base->MCR & CAN_MCR_MAXMB_MASK));
ASSERT(!flexcan_is_mb_occupied(handle, mbIdx));
ASSERT(rxFrame);
uint32_t cs_temp;
uint8_t rx_code;
uint32_t *msgBufAddr = flexcan_get_msg_buf_addr(base, mbIdx);
uint8_t rx_len;
uint32_t *mb_data = mb_data_field(msgBufAddr);
/* 1.Read CS field of Rx Message Buffer to lock Message Buffer. */
cs_temp = mb_cs_field(msgBufAddr);
/* Get Rx Message Buffer Code field. */
rx_code = (cs_temp & CAN_CS_CODE_MASK) >> CAN_CS_CODE_SHIFT;
/* 2.Check to see if Rx Message Buffer is busy. */
if ((rx_code == FLEXCAN_RxMbFull) || (rx_code == FLEXCAN_RxMbOverrun)) {
/* Get the message ID and format. */
if (cs_temp & CAN_CS_IDE_MASK) {
/* Solve Extend ID. */
rxFrame->format = FLEXCAN_EXTEND_FRAME;
/* Store Message ID. */
rxFrame->id =
mb_id_field(msgBufAddr) & (CAN_ID_EXT_MASK | CAN_ID_STD_MASK);
} else {
/* Solve Standard ID. */
rxFrame->format = FLEXCAN_STANDARD_FRAME;
/* Store Message ID. */
rxFrame->id =
(mb_id_field(msgBufAddr) & CAN_ID_STD_MASK) >> CAN_ID_STD_SHIFT;
}
if (cs_temp & CAN_CS_EDL_MASK) {
rxFrame->isCANFDFrame = true;
/* CAN FD doesn't support remote frame. */
rxFrame->type = FLEXCAN_FrameTypeData;
if (cs_temp & CAN_CS_BRS_MASK) {
rxFrame->isCANFDBrsEn = 1;
} else {
rxFrame->isCANFDBrsEn = 0;
}
} else {
rxFrame->isCANFDFrame = false;
/* Get the message type. */
if (cs_temp & CAN_CS_RTR_MASK) {
rxFrame->type = FLEXCAN_FrameTypeRemote;
} else {
rxFrame->type = FLEXCAN_FrameTypeData;
}
}
/* 3. Read the contents of the mailbox.After the mailbox is locked,
* its contents won't be modified by FlexCAN Move-in processes.
*
* Get the message length and then store message payload.
*/
rx_len = (cs_temp & CAN_CS_DLC_MASK) >> CAN_CS_DLC_SHIFT;
rxFrame->length = flexcan_compute_payload_len(rx_len);
flexcan_copy_from_mb(mb_data, rxFrame->dataBuffer, rxFrame->length);
/* 4. Acknowledge the proper flag at the CAN_IFLAG registers.
* Then clear corresponding IFLAG.
*/
flexcan_clear_mb_int_flag(base, mbIdx);
/* 5. Read free-running timer to unlock Rx Message Buffer. */
(void)base->TIMER;
if (rx_code == FLEXCAN_RxMbFull) {
return FLEXCAN_SUCCESS;
} else {
return FLEXCAN_RX_OVERFLOW;
}
} else {
/* Read free-running timer to unlock Rx Message Buffer. */
(void)base->TIMER;
ssdk_printf(SSDK_DEBUG,
"Read CAN MB[%d] failed, MB cs field = 0x%x\r\n", mbIdx,
mb_cs_field(msgBufAddr));
return FLEXCAN_FAIL;
}
}
flexcan_status_e flexcan_read_rx_fifo(flexcan_handle_t *handle,
flexcan_frame_t *rxFrame)
{
/* Assertion. */
ASSERT(handle);
CAN_Type *base = (CAN_Type *)(handle->base_addr);
ASSERT(base && rxFrame);
uint32_t cs_temp;
uint32_t *msgBufAddr = flexcan_get_msg_buf_addr(base, RX_FIFO_MB_ID);
uint32_t *mb_data = mb_data_field(msgBufAddr);
/* Check if Rx FIFO is Enabled. */
if (base->MCR & CAN_MCR_RFEN_MASK) {
/* Read CS field of Rx Message Buffer to lock Message Buffer. */
cs_temp = base->MB[0].CS;
/* Read data from Rx FIFO output port. */
/* Get the message ID and format. */
if (cs_temp & CAN_CS_IDE_MASK) {
/* Solve Extend ID. */
rxFrame->format = FLEXCAN_EXTEND_FRAME;
/* Store Message ID. */
rxFrame->id = base->MB[0].ID & (CAN_ID_EXT_MASK | CAN_ID_STD_MASK);
} else {
/* Solve Standard ID. */
rxFrame->format = FLEXCAN_STANDARD_FRAME;
/* Store Message ID. */
rxFrame->id =
(base->MB[0].ID & CAN_ID_STD_MASK) >> CAN_ID_STD_SHIFT;
}
/* Get the message type. */
if (cs_temp & CAN_CS_RTR_MASK) {
rxFrame->type = FLEXCAN_FrameTypeRemote;
} else {
rxFrame->type = FLEXCAN_FrameTypeData;
}
/* Get the message length. */
rxFrame->length = (cs_temp & CAN_CS_DLC_MASK) >> CAN_CS_DLC_SHIFT;
/* Store Message Payload. */
flexcan_copy_from_mb(mb_data, rxFrame->dataBuffer, rxFrame->length);
/* Read free-running timer to unlock Rx Message Buffer. */
(void)base->TIMER;
/* Store ID Filter Hit Index. */
rxFrame->idHit = (uint8_t)(base->RXFIR & CAN_RXFIR_IDHIT_MASK);
return FLEXCAN_SUCCESS;
} else {
return FLEXCAN_FAIL;
}
}
uint8_t flexcan_get_mb_state(flexcan_handle_t *handle, uint8_t mbIdx)
{
/* Assertion. */
ASSERT(handle);
return handle->mbState[mbIdx];
}
bool flexcan_is_mb_occupied(flexcan_handle_t *handle, uint8_t mbIdx)
{
/* Assertion. */
ASSERT(handle);
CAN_Type *base = (CAN_Type *)(handle->base_addr);
ASSERT(base);
uint8_t lastOccupiedMb;
/* Is Rx FIFO enabled? */
if (base->MCR & CAN_MCR_RFEN_MASK) {
/* Get RFFN value. */
lastOccupiedMb =
((base->CTRL2 & CAN_CTRL2_RFFN_MASK) >> CAN_CTRL2_RFFN_SHIFT);
/* Calculate the number of last Message Buffer occupied by Rx FIFO. */
lastOccupiedMb = ((lastOccupiedMb + 1) * 2) + 5;
if (mbIdx <= lastOccupiedMb) {
return true;
} else {
return false;
}
} else {
return false;
}
}
uint32_t flexcan_get_error_status(flexcan_handle_t *handle)
{
/* Assertion. */
ASSERT(handle);
CAN_Type *base = (CAN_Type *)(handle->base_addr);
ASSERT(base);
return (uint32_t)(base->ESR1);
}
void flexcan_clear_err_status_flag(flexcan_handle_t *handle, uint32_t mask)
{
/* Assertion. */
ASSERT(handle);
CAN_Type *base = (CAN_Type *)(handle->base_addr);
ASSERT(base);
base->ESR1 = mask;
}
uint32_t flexcan_read_mb_int_status(flexcan_handle_t *handle, uint8_t mbIdx)
{
/* Assertion. */
ASSERT(handle);
CAN_Type *base = (CAN_Type *)(handle->base_addr);
ASSERT(base);
return flexcan_get_mb_int_status_flag(base, mbIdx);
}
void flexcan_abort_mb_send(flexcan_handle_t *handle, uint8_t mbIdx)
{
/* Assertion. */
ASSERT(handle);
CAN_Type *base = (CAN_Type *)(handle->base_addr);
ASSERT(base);
ASSERT(mbIdx <= (base->MCR & CAN_MCR_MAXMB_MASK));
ASSERT(!flexcan_is_mb_occupied(handle, mbIdx));
/* Disable Message Buffer Interrupt. */
flexcan_disable_mb_int(base, mbIdx);
/* Un-register handle. */
handle->pMBFrameBuf[mbIdx] = 0U;
/* Clean Message Buffer. */
flexcan_set_tx_mb_config(handle, mbIdx, false);
handle->mbState[mbIdx] = FLEXCAN_StateIdle;
}
void flexcan_abort_mb_receive(flexcan_handle_t *handle, uint8_t mbIdx)
{
ASSERT(handle);
CAN_Type *base = (CAN_Type *)(handle->base_addr);
ASSERT(base);
ASSERT(mbIdx <= (base->MCR & CAN_MCR_MAXMB_MASK));
ASSERT(!flexcan_is_mb_occupied(handle, mbIdx));
/* Disable Message Buffer Interrupt. */
flexcan_disable_mb_int(base, mbIdx);
/* Un-register handle. */
handle->pMBFrameBuf[mbIdx] = 0U;
handle->mbState[mbIdx] = FLEXCAN_StateIdle;
}
void flexcan_abort_receive_fifo(flexcan_handle_t *handle)
{
/* Assertion. */
ASSERT(handle);
CAN_Type *base = (CAN_Type *)(handle->base_addr);
ASSERT(base);
/* Check if Rx FIFO is enabled. */
if (base->MCR & CAN_MCR_RFEN_MASK) {
/* Disable Rx Message FIFO Interrupts. */
flexcan_disable_mb_int(base, FLEXCAN_RxFifoOverflowFlag |
FLEXCAN_RxFifoWarningFlag |
FLEXCAN_RxFifoFrameAvlFlag);
/* Un-register handle. */
handle->pRxFifoFrameBuf = 0x0;
}
handle->rxFifoState = FLEXCAN_StateIdle;
}
int flexcan_irq_handler(uint32_t irq, void *arg)
{
irq_state_t state = enter_critical_section();//20250426 <20><><EFBFBD><EFBFBD><EFBFBD>жϱ<D0B6><CFB1><EFBFBD>
flexcan_handle_t *handle = (flexcan_handle_t *)arg;
ASSERT(handle);
CAN_Type *base = (CAN_Type *)(handle->base_addr);
ASSERT(base);
uint32_t errStatus = base->ESR1;
uint8_t mb_num = ((base->MCR) & CAN_MCR_MAXMB_MASK) + 1U;
flexcan_status_e status;
uint8_t mbIdx;
bool get_int_req = false;
uint32_t int_req = 0U;
/* Common frame buffer used when no buffer defined by user. */
uint8_t rxDataBuf[64];
flexcan_frame_t frameBuf = {.dataBuffer = rxDataBuf};
errStatus &= (FLEXCAN_TxWarningIntFlag | FLEXCAN_RxWarningIntFlag |
FLEXCAN_BusOffIntFlag | FLEXCAN_ErrorIntFlag |
FLEXCAN_WakeUpIntFlag | FLEXCAN_ErrorFlag);
/* FlexCAN error interrupt handling. */
if (errStatus) {
status = FLEXCAN_ERROR_STATUS;
/* Calling Callback Function if has one. */
if (handle->callback != NULL) {
handle->callback(handle, status, errStatus, handle->userData);
}
/* Clear error interrupt flags. */
flexcan_clear_err_status_flag(handle, errStatus);
}
if (base->MCR & CAN_MCR_PNET_EN_MASK) {
if (base->WU_MTC & CAN_WU_MTC_WTOF_MASK) {
if (handle->callback != NULL) {
handle->callback(handle, FLEXCAN_WAKEUP_TIMEOUT, 0x0, NULL);
}
base->WU_MTC |= CAN_WU_MTC_WTOF_MASK;
}
if (base->WU_MTC & CAN_WU_MTC_WUMF_MASK) {
if (handle->callback != NULL) {
handle->callback(handle, FLEXCAN_WAKEUP_MATCH, 0x0, NULL);
}
base->WU_MTC |= CAN_WU_MTC_WUMF_MASK;
}
}
uint32_t err_irq_status = base->ERR_IRQ_STATUS;
if (err_irq_status) {
ssdk_printf(SSDK_DEBUG, "ERR_IRQ_STATUS = %#x\r\n", err_irq_status);
base->ERR_IRQ_STATUS = err_irq_status;
if (err_irq_status & ERR_IRQ_STATUS_PSLVERR_MASK) {
ssdk_printf(SSDK_DEBUG,
"access to reserved address results in error\r\n");
}
}
/* FlexCAN message buffer interrupt handling. */
for (mbIdx = 0U; mbIdx < mb_num; mbIdx++) {
/* Every 32 MBs share one IMASK register and one IFLAG register. */
if ((mbIdx & 31U) == 0U) {
get_int_req = true;
}
if (get_int_req) {
/* Read interrupt status: IMASK & IFLAG. */
int_req = flexcan_get_mb_int_req(base, mbIdx >> 5);
get_int_req = false;
}
/* Check if the MB's interrupt is generated. */
if (int_req & (1U << (mbIdx & 31U))) {
/* Frame buffer defined by user. */
flexcan_frame_t *rxMBFrame = handle->pMBFrameBuf[mbIdx];
flexcan_frame_t *rxFifoFrame = handle->pRxFifoFrameBuf;
/* Rx FIFO interrupt handling. */
if ((handle->rxFifoState != FLEXCAN_StateIdle) &&
(mbIdx >= RX_FIFO_FRAME_AVL_MB_ID) &&
(mbIdx <= RX_FIFO_OVERFLOW_MB_ID)) {
do {
switch (1U << mbIdx) {
case FLEXCAN_RxFifoOverflowFlag:
status = FLEXCAN_RX_FIFO_OVERFLOW;
break;
case FLEXCAN_RxFifoWarningFlag:
status = FLEXCAN_RX_FIFO_WARNING;
break;
case FLEXCAN_RxFifoFrameAvlFlag:
status = flexcan_read_rx_fifo(
handle, rxFifoFrame ? rxFifoFrame : &frameBuf);
if (FLEXCAN_SUCCESS == status) {
status = FLEXCAN_RX_FIFO_IDLE;
}
break;
default:
status = FLEXCAN_UNHANDLED;
break;
}
/* Clear message buffer interrupt flag. */
flexcan_clear_mb_int_flag(base, mbIdx);
/* Calling Callback Function if has one. */
if (handle->callback != NULL) {
handle->callback(handle, status, mbIdx,
(void *)(rxFifoFrame ? rxFifoFrame
: &frameBuf));
}
} while (flexcan_get_mb_int_status_flag(base, mbIdx) != 0U);
} else {
switch (handle->mbState[mbIdx]) {
case FLEXCAN_StateRxData:
case FLEXCAN_StateRxRemote:
/* According to recommended procedure to read the frame received in a mailbox,
* clear rx mb int before unlock rx mb.
*/
status = flexcan_read_rx_mb(
handle, mbIdx, rxMBFrame ? rxMBFrame : &frameBuf);
if (status == FLEXCAN_SUCCESS) {
status = FLEXCAN_RX_IDLE;
}
break;
case FLEXCAN_StateTxData:
handle->mbState[mbIdx] = FLEXCAN_StateIdle;
status = FLEXCAN_TX_IDLE;
/* Clear message buffer interrupt flag. */
flexcan_clear_mb_int_flag(base, mbIdx);
break;
case FLEXCAN_StateTxRemote:
handle->mbState[mbIdx] = FLEXCAN_StateRxRemote;
status = FLEXCAN_TX_SWITCH_TO_RX;
/* Clear message buffer interrupt flag. */
flexcan_clear_mb_int_flag(base, mbIdx);
break;
default:
status = FLEXCAN_UNHANDLED;
/* Clear message buffer interrupt flag. */
flexcan_clear_mb_int_flag(base, mbIdx);
break;
}
/* Calling Callback Function if has one. */
if (handle->callback != NULL) {
handle->callback(
handle, status, mbIdx,
(void *)(rxMBFrame ? rxMBFrame : &frameBuf));
}
}
}
}
exit_critical_section(state);//20250426 <20><><EFBFBD><EFBFBD><EFBFBD>жϱ<D0B6><CFB1><EFBFBD>
return 0;
}
/* API function implementation end */