rt-thread-official/bsp/gd32103c-eval/Libraries/GD32F1xx_standard_peripheral/Source/gd32f10x_can.c

1121 lines
36 KiB
C
Raw Normal View History

/**
******************************************************************************
* @brief CAN functions of the firmware library.
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "gd32f10x_can.h"
#include "gd32f10x_rcc.h"
/** @addtogroup GD32F10x_Firmware
* @{
*/
/** @defgroup CAN
* @brief CAN driver modules
* @{
*/
/** @defgroup CAN_Private_Defines
* @{
*/
/* CAN Mailbox Transmit Request */
#define CAN_TMIR_TE ((uint32_t)0x00000001)
/* CAN Filter Master Register bits */
#define FMR_FINIT ((uint32_t)0x00000001)
/* Time out for IWS bit */
#define IWS_TIMEOUT ((uint32_t)0x0000FFFF)
/* Time out for SWS bit */
#define SWS_TIMEOUT ((uint32_t)0x0000FFFF)
/* CAN TMIR_StdId masks */
#define CAN_TMIR_StdId_Mask ((uint32_t)0x000007FF)
/* CAN TMIR_ExtId masks */
#define CAN_TMIR_ExtId_Mask ((uint32_t)0x1FFFFFFF)
/* CAN TMIR_ExtId masks */
#define CAN_FLAG_Mask ((uint32_t)0x000FFFFF)
/* Flags in TSTR register */
#define CAN_FLAGS_TSTR ((uint32_t)0x08000000)
/* Flags in RFR1 register */
#define CAN_FLAGS_RFR1 ((uint32_t)0x04000000)
/* Flags in RFR0register */
#define CAN_FLAGS_RFR0 ((uint32_t)0x02000000)
/* Flags in STR register */
#define CAN_FLAGS_STR ((uint32_t)0x01000000)
/* Flags in ER register */
#define CAN_FLAGS_ER ((uint32_t)0x00F00000)
/* Mailboxes definition */
#define CAN_TXMAILBOX_0 ((uint8_t)0x00)
#define CAN_TXMAILBOX_1 ((uint8_t)0x01)
#define CAN_TXMAILBOX_2 ((uint8_t)0x02)
/* CAN Master Control Register bit */
#define MCR_DBF ((uint32_t)0x00010000)
#define CAN_MODE_MASK ((uint32_t)0x00000003)
/**
* @}
*/
/** @defgroup CAN_Private_Functions
* @{
*/
/**
* @brief Deinitialize the CAN peripheral registers.
* @param CANx: where x:[1,2] to select the CAN peripheral.
* @retval None.
*/
void CAN_DeInit(CAN_TypeDef *CANx)
{
if (CANx == CAN1) {
/* Force CAN1 reset state */
RCC_APB1PeriphReset_Enable(RCC_APB1PERIPH_CAN1, ENABLE);
/* Release CAN1 from reset state */
RCC_APB1PeriphReset_Enable(RCC_APB1PERIPH_CAN1, DISABLE);
} else {
/* Force CAN2 reset state */
RCC_APB1PeriphReset_Enable(RCC_APB1PERIPH_CAN2, ENABLE);
/* Release CAN2 from reset state */
RCC_APB1PeriphReset_Enable(RCC_APB1PERIPH_CAN2, DISABLE);
}
}
/**
* @brief Initialize the CAN peripheral according to the CAN_InitParaStruct.
* @param CANx:where x:[1,2]
* @param CAN_InitParaStruct: contain the configuration information for the CAN peripheral.
* @retval It will be returned the status of CAN_INITSTATE_FAILED or CAN_INITSTATE_SUCCESS.
*/
uint8_t CAN_Init(CAN_TypeDef *CANx, CAN_InitPara *CAN_InitParaStruct)
{
uint32_t wait_ack = 0x00000000;
/* Out of sleep mode */
CANx->CTLR &= (~(uint32_t)CAN_CTLR_SWM);
/* Enable initial working */
CANx->CTLR |= CAN_CTLR_IWM ;
/* Wait the acknowledge */
while (((CANx->STR & CAN_STR_IWS) != CAN_STR_IWS) && (wait_ack != IWS_TIMEOUT)) {
wait_ack++;
}
/* Check whether initial working is success */
if ((CANx->STR & CAN_STR_IWS) != CAN_STR_IWS) {
return CAN_INITSTATE_FAILED;
} else {
/* Set the time triggered communication mode */
if (CAN_InitParaStruct->CAN_TTC == ENABLE) {
CANx->CTLR |= CAN_CTLR_TTC;
} else {
CANx->CTLR &= ~(uint32_t)CAN_CTLR_TTC;
}
/* Set the automatic bus-off management */
if (CAN_InitParaStruct->CAN_ABOR == ENABLE) {
CANx->CTLR |= CAN_CTLR_ABOR;
} else {
CANx->CTLR &= ~(uint32_t)CAN_CTLR_ABOR;
}
/* Set the automatic wake-up mode */
if (CAN_InitParaStruct->CAN_AWK == ENABLE) {
CANx->CTLR |= CAN_CTLR_AWK;
} else {
CANx->CTLR &= ~(uint32_t)CAN_CTLR_AWK;
}
/* Set the automatic retransmission mode */
if (CAN_InitParaStruct->CAN_ARD == ENABLE) {
CANx->CTLR |= CAN_CTLR_ARD;
} else {
CANx->CTLR &= ~(uint32_t)CAN_CTLR_ARD;
}
/* Set receive FIFO overwrite mode */
if (CAN_InitParaStruct->CAN_RFOD == ENABLE) {
CANx->CTLR |= CAN_CTLR_RFOD;
} else {
CANx->CTLR &= ~(uint32_t)CAN_CTLR_RFOD;
}
/* Set the Transmit FIFO order */
if (CAN_InitParaStruct->CAN_TFO == ENABLE) {
CANx->CTLR |= CAN_CTLR_TFO;
} else {
CANx->CTLR &= ~(uint32_t)CAN_CTLR_TFO;
}
/* Set the bit timing register */
CANx->BTR = (uint32_t)((uint32_t)CAN_InitParaStruct->CAN_Mode << 30) | \
((uint32_t)CAN_InitParaStruct->CAN_SJW << 24) | \
((uint32_t)CAN_InitParaStruct->CAN_BS1 << 16) | \
((uint32_t)CAN_InitParaStruct->CAN_BS2 << 20) | \
((uint32_t)CAN_InitParaStruct->CAN_Prescaler - 1);
/* leave initialisation */
CANx->CTLR &= ~(uint32_t)CAN_CTLR_IWM;
/* Wait the acknowledge */
wait_ack = 0;
while (((CANx->STR & CAN_STR_IWS) == CAN_STR_IWS) && (wait_ack != IWS_TIMEOUT)) {
wait_ack++;
}
/* Check whether qiut initial working mode */
if ((CANx->STR & CAN_STR_IWS) == CAN_STR_IWS) {
return CAN_INITSTATE_FAILED;
} else {
return CAN_INITSTATE_SUCCESS;
}
}
}
/**
* @brief Initialize the CAN peripheral according to the CAN_FilterInitStruct.
* @param CAN_FilterInitParaStruct:contain the information for the CAN peripheral.
* @retval None.
*/
void CAN_FilterInit(CAN_FilterInitPara *CAN_FilterInitParaStruct)
{
uint32_t filter_number = 0;
filter_number = ((uint32_t)1) << CAN_FilterInitParaStruct->CAN_FilterNumber;
/* Set filter lock disable */
CAN1->FCTLR |= CAN_FCTLR_FLD;
/* Disable Filter */
CAN1->FWR &= ~(uint32_t)filter_number;
/* Filter Scale */
if (CAN_FilterInitParaStruct->CAN_FilterScale == CAN_FILTERSCALE_16BIT) {
/* Set the filter 16-bit scale*/
CAN1->FSR &= ~(uint32_t)filter_number;
/* First 16-bit list and First 16-bit mask */
/* Or First 16-bit list and Second 16-bit list */
CAN1->FilterRegister[CAN_FilterInitParaStruct->CAN_FilterNumber].FD0R =
((0x0000FFFF & (uint32_t)CAN_FilterInitParaStruct->CAN_FilterMaskListLow) << 16) |
(0x0000FFFF & (uint32_t)CAN_FilterInitParaStruct->CAN_FilterListLow);
/* Second 16-bit identifier and Second 16-bit mask */
/* Or Third 16-bit identifier and Fourth 16-bit identifier */
CAN1->FilterRegister[CAN_FilterInitParaStruct->CAN_FilterNumber].FD1R =
((0x0000FFFF & (uint32_t)CAN_FilterInitParaStruct->CAN_FilterMaskListHigh) << 16) |
(0x0000FFFF & (uint32_t)CAN_FilterInitParaStruct->CAN_FilterListHigh);
}
if (CAN_FilterInitParaStruct->CAN_FilterScale == CAN_FILTERSCALE_32BIT) {
/* 32-bit scale for the filter */
CAN1->FSR |= filter_number;
/* 32-bit identifier or First 32-bit identifier */
CAN1->FilterRegister[CAN_FilterInitParaStruct->CAN_FilterNumber].FD0R =
((0x0000FFFF & (uint32_t)CAN_FilterInitParaStruct->CAN_FilterListHigh) << 16) |
(0x0000FFFF & (uint32_t)CAN_FilterInitParaStruct->CAN_FilterListLow);
/* 32-bit mask or Second 32-bit identifier */
CAN1->FilterRegister[CAN_FilterInitParaStruct->CAN_FilterNumber].FD1R =
((0x0000FFFF & (uint32_t)CAN_FilterInitParaStruct->CAN_FilterMaskListHigh) << 16) |
(0x0000FFFF & (uint32_t)CAN_FilterInitParaStruct->CAN_FilterMaskListLow);
}
/* Filter Mode */
if (CAN_FilterInitParaStruct->CAN_FilterMode == CAN_FILTERMODE_MASK) {
/*Filter with Mask mode*/
CAN1->FMR &= ~(uint32_t)filter_number;
} else { /* CAN_FilterInitStruct->CAN_FilterMode == CAN_FILTERMODE_LIST */
/*Filter with List mode*/
CAN1->FMR |= (uint32_t)filter_number;
}
/* Filter associated with FIFO */
if (CAN_FilterInitParaStruct->CAN_FilterFIFOAssociation == CAN_FILTER_FIFO0) {
/* Filter associated with FIFO 0 */
CAN1->FAFR &= ~(uint32_t)filter_number;
}
if (CAN_FilterInitParaStruct->CAN_FilterFIFOAssociation == CAN_FILTER_FIFO1) {
/* Filter associated with FIFO 1 */
CAN1->FAFR |= (uint32_t)filter_number;
}
/* Filter working */
if (CAN_FilterInitParaStruct->CAN_FilterWork == ENABLE) {
CAN1->FWR |= filter_number;
}
/* Exit the initialisation mode for the filter */
CAN1->FCTLR &= ~CAN_FCTLR_FLD;
}
/**
* @brief Configure each CAN_InitParaStruct member with default value.
* @param CAN_InitParaStruct: pointer to a CAN_InitPara structure to initialize.
* @retval None.
*/
void CAN_StructInit(CAN_InitPara *CAN_InitParaStruct)
{
/* Set the time triggered communication mode */
CAN_InitParaStruct->CAN_TTC = DISABLE;
/* Set the automatic bus-off recovery */
CAN_InitParaStruct->CAN_ABOR = DISABLE;
/* Set the automatic wake up mode */
CAN_InitParaStruct->CAN_AWK = DISABLE;
/* Set the automatic retransmission disable */
CAN_InitParaStruct->CAN_ARD = DISABLE;
/* Set the receive FIFO overwrite mode */
CAN_InitParaStruct->CAN_RFOD = DISABLE;
/* Set the transmit FIFO order */
CAN_InitParaStruct->CAN_TFO = DISABLE;
/* Set the CAN_Mode member */
CAN_InitParaStruct->CAN_Mode = CAN_MODE_NORMAL;
/* Set the CAN_SJW member */
CAN_InitParaStruct->CAN_SJW = CAN_SJW_1TQ;
/* Set the CAN_BS1 member */
CAN_InitParaStruct->CAN_BS1 = CAN_BS1_4TQ;
/* Set the CAN_BS2 member */
CAN_InitParaStruct->CAN_BS2 = CAN_BS2_3TQ;
/* Set the CAN_Prescaler member */
CAN_InitParaStruct->CAN_Prescaler = 1;
}
/**
* @brief Set header bank of CAN2 filter.
* @param CAN2_HeaderBankNumber: Select header bank of CAN2 filter.It can be 1 to 27.
* @retval None.
*/
void CAN_HeaderBank(uint8_t CAN_HeaderBankNumber)
{
/* Set filter lock disable */
CAN1->FCTLR |= CAN_FCTLR_FLD;
/* Select filter start number for slave CAN */
CAN1->FCTLR &= (uint32_t)0xFFFFC0F1 ;
CAN1->FCTLR |= (uint32_t)(CAN_HeaderBankNumber) << 8;
/* Filter out the initialization mode */
CAN1->FCTLR |= ~CAN_FCTLR_FLD;
}
/**
* @brief Enable or disable the Debug Freeze for CAN.
* @param CANx: where x :[1,2] for selecting the CAN peripheral.
* @param NewValue: new state of the CAN peripheral.
* This parameter can be: ENABLE or DISABLE.
* @retval None.
*/
void CAN_DebugFreeze(CAN_TypeDef *CANx, TypeState NewValue)
{
if (NewValue != DISABLE) {
CANx->CTLR |= CAN_CTLR_DFZ;
} else {
CANx->CTLR &= ~CAN_CTLR_DFZ;
}
}
/**
* @brief Enable or disabe the CAN Time Triggered communication mode.
* @param CANx:where x :[1,2] for selecting the CAN peripheral.
* @param NewValue : Mode new state , This parameter can be: ENABLE or DISABLE.
* @retval None
*/
void CAN_TimeTrigComMode_Enable(CAN_TypeDef *CANx, TypeState NewValue)
{
if (NewValue != DISABLE) {
/* Enable the TTC mode */
CANx->CTLR |= CAN_CTLR_TTC;
/* Set TSEbits */
CANx->TxMailBox[0].TMPR |= ((uint32_t)CAN_TMPR0_TSE);
CANx->TxMailBox[1].TMPR |= ((uint32_t)CAN_TMPR1_TSE);
CANx->TxMailBox[2].TMPR |= ((uint32_t)CAN_TMPR2_TSE);
} else {
/* Disable the TTC mode */
CANx->CTLR &= (uint32_t)(~(uint32_t)CAN_CTLR_TTC);
/* Reset TSE bits */
CANx->TxMailBox[0].TMPR &= ((uint32_t)~CAN_TMPR0_TSE);
CANx->TxMailBox[1].TMPR &= ((uint32_t)~CAN_TMPR1_TSE);
CANx->TxMailBox[2].TMPR &= ((uint32_t)~CAN_TMPR2_TSE);
}
}
/**
* @brief Initiate to transmit a message.
* @param CANx: where x:[1,2]to to select the CAN peripheral.
* @param TxMessage: contain CAN Id, CAN DLC and CAN data for the structure.
* @retval The number of the mailbox that is used for transmission
* or CAN_TxState_NoMailBox if there is no empty mailbox.
*/
uint8_t CAN_Transmit(CAN_TypeDef *CANx, CanTxMessage *TxMessage)
{
uint8_t transmit_mailbox_number = 0;
/* Select one empty transmit mailbox */
if ((CANx->TSTR & CAN_TSTR_TME0) == CAN_TSTR_TME0) {
transmit_mailbox_number = 0;
} else if ((CANx->TSTR & CAN_TSTR_TME1) == CAN_TSTR_TME1) {
transmit_mailbox_number = 1;
} else if ((CANx->TSTR & CAN_TSTR_TME2) == CAN_TSTR_TME2) {
transmit_mailbox_number = 2;
} else {
transmit_mailbox_number = CAN_TXSTATE_NOMAILBOX;
}
if (transmit_mailbox_number != CAN_TXSTATE_NOMAILBOX) {
/* Set up the Id */
CANx->TxMailBox[transmit_mailbox_number].TMIR &= CAN_TMIR_TE;
if (TxMessage->FF == CAN_FF_STANDARD) {
CANx->TxMailBox[transmit_mailbox_number].TMIR |= ((TxMessage->StdId << 21) | \
TxMessage->FT);
} else {
CANx->TxMailBox[transmit_mailbox_number].TMIR |= ((TxMessage->ExtId << 3) | \
TxMessage->FF | \
TxMessage->FT);
}
/* Set up the DLC */
TxMessage->DLC &= ((uint8_t)CAN_TMPR0_DLC);
CANx->TxMailBox[transmit_mailbox_number].TMPR &= ((uint32_t)~CAN_TMPR0_DLC);
CANx->TxMailBox[transmit_mailbox_number].TMPR |= TxMessage->DLC;
/* Set up the data field */
CANx->TxMailBox[transmit_mailbox_number].TMD0R = (((uint32_t)TxMessage->Data[3] << 24) |
((uint32_t)TxMessage->Data[2] << 16) |
((uint32_t)TxMessage->Data[1] << 8) |
((uint32_t)TxMessage->Data[0]));
CANx->TxMailBox[transmit_mailbox_number].TMD1R = (((uint32_t)TxMessage->Data[7] << 24) |
((uint32_t)TxMessage->Data[6] << 16) |
((uint32_t)TxMessage->Data[5] << 8) |
((uint32_t)TxMessage->Data[4]));
/* Request transmission */
CANx->TxMailBox[transmit_mailbox_number].TMIR |= CAN_TMIR0_TE;
}
return transmit_mailbox_number;
}
/**
* @brief Check the state of message transmission.
* @param CANx: where x:[1,2] to to select the CAN peripheral.
* @param TransmitMailbox: the number of the used transmission mailbox.
* @retval Return CAN_TXSTATE_OK or CAN_TXSTATE_FAILED.
*/
uint8_t CAN_TransmitState(CAN_TypeDef *CANx, uint8_t TransmitMailbox)
{
uint32_t state = 0;
switch (TransmitMailbox) {
case (CAN_TXMAILBOX_0):
state = CANx->TSTR & (CAN_TSTR_MTF0 | CAN_TSTR_MTFNE0 | CAN_TSTR_TME0);
break;
case (CAN_TXMAILBOX_1):
state = CANx->TSTR & (CAN_TSTR_MTF1 | CAN_TSTR_MTFNE1 | CAN_TSTR_TME1);
break;
case (CAN_TXMAILBOX_2):
state = CANx->TSTR & (CAN_TSTR_MTF2 | CAN_TSTR_MTFNE2 | CAN_TSTR_TME2);
break;
default:
state = CAN_TXSTATE_FAILED;
break;
}
switch (state) {
/* transmit pending */
case (0x0):
state = CAN_TXSTATE_PENDING;
break;
/* transmit failed */
case (CAN_TSTR_MTF0 | CAN_TSTR_TME0):
state = CAN_TXSTATE_FAILED;
break;
case (CAN_TSTR_MTF1 | CAN_TSTR_TME1):
state = CAN_TXSTATE_FAILED;
break;
case (CAN_TSTR_MTF2 | CAN_TSTR_TME2):
state = CAN_TXSTATE_FAILED;
break;
/* transmit succeeded */
case (CAN_TSTR_MTF0 | CAN_TSTR_MTFNE0 | CAN_TSTR_TME0):
state = CAN_TXSTATE_OK;
break;
case (CAN_TSTR_MTF1 | CAN_TSTR_MTFNE1 | CAN_TSTR_TME1):
state = CAN_TXSTATE_OK;
break;
case (CAN_TSTR_MTF2 | CAN_TSTR_MTFNE2 | CAN_TSTR_TME2):
state = CAN_TXSTATE_OK;
break;
default:
state = CAN_TXSTATE_FAILED;
break;
}
return (uint8_t) state;
}
/**
* @brief Stop a transmit mission.
* @param CANx: where x:[1,2] to to select the CAN peripheral.
* @param Mailbox: Mailbox number.
* @retval None.
*/
void CAN_StopTransmit(CAN_TypeDef *CANx, uint8_t Mailbox)
{
/* Stop transmission */
switch (Mailbox) {
case (CAN_TXMAILBOX_0):
CANx->TSTR |= CAN_TSTR_MST0;
break;
case (CAN_TXMAILBOX_1):
CANx->TSTR |= CAN_TSTR_MST1;
break;
case (CAN_TXMAILBOX_2):
CANx->TSTR |= CAN_TSTR_MST2;
break;
default:
break;
}
}
/**
* @brief Receive a message.
* @param CANx: where x:[1,2] to to select the CAN peripheral.
* @param FIFONumber: Receive FIFO number, CAN_FIFO0 or CAN_FIFO1.
* @param RxMessage: a structure receive message which contains
* CAN Id, CAN DLC, CAN datas and FI number.
* @retval None.
*/
void CAN_Receive(CAN_TypeDef *CANx, uint8_t FIFONumber, CanRxMessage *RxMessage)
{
/* Get the frame identifier */
RxMessage->FF = (uint8_t)0x04 & CANx->FIFOMailBox[FIFONumber].RFMIR;
if (RxMessage->FF == CAN_FF_STANDARD) {
RxMessage->StdId = CAN_TMIR_StdId_Mask & (CANx->FIFOMailBox[FIFONumber].RFMIR >> 21);
} else {
RxMessage->ExtId = CAN_TMIR_ExtId_Mask & (CANx->FIFOMailBox[FIFONumber].RFMIR >> 3);
}
RxMessage->FT = (uint8_t)0x02 & CANx->FIFOMailBox[FIFONumber].RFMIR;
/* Get the data length code */
RxMessage->DLC = (uint8_t)0x0F & CANx->FIFOMailBox[FIFONumber].RFMPR;
/* Get the filtering index */
RxMessage->FI = (uint8_t)0xFF & (CANx->FIFOMailBox[FIFONumber].RFMPR >> 8);
/* Get FIFO mailbox data */
RxMessage->Data[0] = (uint8_t)0xFF & CANx->FIFOMailBox[FIFONumber].RFMD0R;
RxMessage->Data[1] = (uint8_t)0xFF & (CANx->FIFOMailBox[FIFONumber].RFMD0R >> 8);
RxMessage->Data[2] = (uint8_t)0xFF & (CANx->FIFOMailBox[FIFONumber].RFMD0R >> 16);
RxMessage->Data[3] = (uint8_t)0xFF & (CANx->FIFOMailBox[FIFONumber].RFMD0R >> 24);
RxMessage->Data[4] = (uint8_t)0xFF & CANx->FIFOMailBox[FIFONumber].RFMD1R;
RxMessage->Data[5] = (uint8_t)0xFF & (CANx->FIFOMailBox[FIFONumber].RFMD1R >> 8);
RxMessage->Data[6] = (uint8_t)0xFF & (CANx->FIFOMailBox[FIFONumber].RFMD1R >> 16);
RxMessage->Data[7] = (uint8_t)0xFF & (CANx->FIFOMailBox[FIFONumber].RFMD1R >> 24);
/* Release the FIFO */
if (FIFONumber == CAN_FIFO0) {
CANx->RFR0 |= CAN_RFR0_RFD0;
}
/* FIFONumber == CAN_FIFO1 */
else {
CANx->RFR1 |= CAN_RFR1_RFD1;
}
}
/**
* @brief Dequeue the FIFO.
* @param CANx: where x:[1,2] to to select the CAN peripheral.
* @param FIFONumber: FIFO to dequeue, it can be CAN_FIFO0 or CAN_FIFO1.
* @retval None.
*/
void CAN_FIFODequeue(CAN_TypeDef *CANx, uint8_t FIFONumber)
{
if (FIFONumber == CAN_FIFO0) {
/* Release FIFO 0 */
CANx->RFR0 |= CAN_RFR0_RFD0;
} else { /* FIFONumber == CAN_FIFO1 */
/* Release FIFO1 */
CANx->RFR1 |= CAN_RFR1_RFD1;
}
}
/**
* @brief Return the length of receiving messages.
* @param CANx: where x:[1,2] to to select the CAN peripheral.
* @param FIFONumber: Receive FIFO number, CAN_FIFO0 or CAN_FIFO1.
* @retval message_length : which is the Length of pending message.
*/
uint8_t CAN_MessageLength(CAN_TypeDef *CANx, uint8_t FIFONumber)
{
uint8_t message_length = 0;
if (FIFONumber == CAN_FIFO0) {
message_length = (uint8_t)(CANx->RFR0 & (uint32_t)0x03);
} else if (FIFONumber == CAN_FIFO1) {
message_length = (uint8_t)(CANx->RFR1 & (uint32_t)0x03);
} else {
message_length = 0;
}
return message_length;
}
/**
* @brief Select the CAN Working mode.
* @param CAN_WorkingMode : CAN Working Mode.It can be the following one.
* @arg CAN_WORKINGMODE_INITIAL
* @arg CAN_WORKINGMODE_NORMAL
* @arg CAN_WORKINGMODE_SLEEP
* @retval state of the requested mode which can be
* @arg CAN_MODESTATE_FAILED
* @arg CAN_MODESTATE_SUCCESS
*/
uint8_t CAN_WorkingMode(CAN_TypeDef *CANx, uint8_t CAN_WorkingMode)
{
uint8_t state = CAN_MODESTATE_FAILED;
/* Timeout for IWS or also for SWS bits*/
uint32_t timeout = IWS_TIMEOUT;
if (CAN_WorkingMode == CAN_WORKINGMODE_INITIAL) {
/* Set initialisation */
CANx->CTLR = (uint32_t)((CANx->CTLR & (uint32_t)(~(uint32_t)CAN_CTLR_SWM)) | CAN_CTLR_IWM);
/* Wait the acknowledge */
while (((CANx->STR & CAN_MODE_MASK) != CAN_STR_IWS) && (timeout != 0)) {
timeout--;
}
if ((CANx->STR & CAN_MODE_MASK) != CAN_STR_IWS) {
state = CAN_MODESTATE_FAILED;
} else {
state = CAN_MODESTATE_SUCCESS;
}
} else if (CAN_WorkingMode == CAN_WORKINGMODE_NORMAL) {
/* Enter Normal mode */
CANx->CTLR &= (uint32_t)(~(CAN_CTLR_SWM | CAN_CTLR_IWM));
/* Wait the acknowledge */
while (((CANx->STR & CAN_MODE_MASK) != 0) && (timeout != 0)) {
timeout--;
}
if ((CANx->STR & CAN_MODE_MASK) != 0) {
state = CAN_MODESTATE_FAILED;
} else {
state = CAN_MODESTATE_SUCCESS;
}
} else if (CAN_WorkingMode == CAN_WORKINGMODE_SLEEP) {
/* Set Sleep mode */
CANx->CTLR = (uint32_t)((CANx->CTLR & (uint32_t)(~(uint32_t)CAN_CTLR_IWM)) | CAN_CTLR_SWM);
/* Wait the acknowledge */
while (((CANx->STR & CAN_MODE_MASK) != CAN_STR_SWS) && (timeout != 0)) {
timeout--;
}
if ((CANx->STR & CAN_MODE_MASK) != CAN_STR_SWS) {
state = CAN_MODESTATE_FAILED;
} else {
state = CAN_MODESTATE_SUCCESS;
}
} else {
state = CAN_MODESTATE_FAILED;
}
return (uint8_t) state;
}
/**
* @brief Enter the Sleep mode.
* @param CANx: where x:[1,2] to to select the CAN peripheral.
* @retval state: CAN_SLEEP_OK or CAN_SLEEP_FAILED.
*/
uint8_t CAN_EnterSleep(CAN_TypeDef *CANx)
{
/* Set Sleep mode */
CANx->CTLR = (((CANx->CTLR) & (uint32_t)(~(uint32_t)CAN_CTLR_IWM)) | CAN_CTLR_SWM);
if ((CANx->STR & (CAN_STR_SWS | CAN_STR_IWS)) == CAN_STR_SWS) {
/* Sleep mode entered success*/
return (uint8_t)CAN_SLEEP_OK;
} else {
/* Sleep mode entered failure */
return (uint8_t)CAN_SLEEP_FAILED;
}
}
/**
* @brief Wake up CAN.
* @param CANx: where x:[1,2] to to select the CAN peripheral.
* @retval status: CAN_WAKEUP_OK or CAN_WAKEUP_FAILED.
*/
uint8_t CAN_WakeUp(CAN_TypeDef *CANx)
{
uint32_t wait_sws = SWS_TIMEOUT;
/*set wake up */
CANx->CTLR &= ~(uint32_t)CAN_CTLR_SWM;
/* Sleep mode state */
while (((CANx->CTLR & CAN_CTLR_SWM) == CAN_CTLR_SWM) && (wait_sws != 0x00)) {
wait_sws--;
}
if ((CANx->CTLR & CAN_CTLR_SWM) != CAN_CTLR_SWM) {
/*Sleep mode exited */
return (uint8_t)CAN_WAKEUP_OK;
} else {
/*Sleep mode exited failure */
return (uint8_t)CAN_WAKEUP_FAILED;
}
}
/**
* @brief Return the CANx's last error type (LEC).
* @param CANx: where x:[1,2] to to select the CAN peripheral.
* @retval CAN_ErrorType: specify the Error type:
* @arg CAN_ERRORTYPE_NOERR
* @arg CAN_ERRORTYPE_STUFFERR
* @arg CAN_ERRORTYPE_FORMERR
* @arg CAN_ERRORTYPE_ACKERR
* @arg CAN_ERRORTYPE_BITRECESSIVEERR
* @arg CAN_ERRORTYPE_BITDOMINANTERR
* @arg CAN_ERRORTYPE_CRCERR
* @arg CAN_ERRORTYPE_SOFTWARESETERR
*/
uint8_t CAN_GetErrorType(CAN_TypeDef *CANx)
{
uint8_t error_type = 0;
/* Get the error type*/
error_type = (((uint8_t)CANx->ER) & (uint8_t)CAN_ER_ET);
/* Return the error type*/
return error_type;
}
/**
* @brief Get the Counter of CANx Receive Error(REC).
* @note According to the error condition as defined by the CAN standard,
* the counter of CANx Receive Error is increased by 1 or by 8.
* When CAN received success everytime, the counter is decreased by 1
* or reset to 120 if its value was over than 128.
* When the counter value is over 127, the CAN controller enters the
* error passive state.
* @param CANx: where x:[1,2] to to select the CAN peripheral.
* @retval CAN Receive Error Counter.
*/
uint8_t CAN_GetReceiveErrorCounter(CAN_TypeDef *CANx)
{
uint8_t receive_counter = 0;
/* Get the counter of CANx Receive Error*/
receive_counter = (uint8_t)((CANx->ER & CAN_ER_REC) >> 24);
/* Return the Receive Error Counter*/
return receive_counter;
}
/**
* @brief Get the Counter of CANx Transmit Error (TEC).
* @param CANx: where x:[1,2] to to select the CAN peripheral.
* @retval CAN Transmit Error Counter.
*/
uint8_t CAN_GetTransmitErrorCounter(CAN_TypeDef *CANx)
{
uint8_t transmit_counter = 0;
/* Get the Counter of CANx Transmit Error(TEC) */
transmit_counter = (uint8_t)((CANx->ER & CAN_ER_TEC) >> 16);
/* Return the Transmit Error Counter*/
return transmit_counter;
}
/**
* @brief Enable or disable the specified CANx interrupts.
* @param CANx: where x:[1,2] to to select the CAN peripheral.
* @param CAN_INT: specify the CAN interrupt sources to be enabled or disabled.
* This parameter can be:
* @arg CAN_INT_TME
* @arg CAN_INT_RFNE0
* @arg CAN_INT_RFF0
* @arg CAN_INT_RFO0
* @arg CAN_INT_RFNE1
* @arg CAN_INT_RFF1
* @arg CAN_INT_RFO1
* @arg CAN_INT_WE
* @arg CAN_INT_PE
* @arg CAN_INT_BOE
* @arg CAN_INT_ET
* @arg CAN_INT_ERR
* @arg CAN_INT_WU
* @arg CAN_INT_SLP
* @param NewValue: new state of the CAN interrupts.
* This parameter can be: ENABLE or DISABLE.
* @retval None.
*/
void CAN_INTConfig(CAN_TypeDef *CANx, uint32_t CAN_INT, TypeState NewValue)
{
if (NewValue != DISABLE) {
/* Enable interrupt */
CANx->IER |= CAN_INT;
} else {
/* Disable interrupt */
CANx->IER &= ~CAN_INT;
}
}
/**
* @brief Check whether the specified CAN flag is set or not.
* @param CANx: where x:[1,2] to to select the CAN peripheral.
* @param CAN_FLAG: specify the flag to check.
* This parameter can be one of the following flags:
* @arg CAN_FLAG_WE: Warning error Flag
* @arg CAN_FLAG_PE: Passive error Flag
* @arg CAN_FLAG_BOE: Bus-off error Flag
* @arg CAN_FLAG_MTF0: Mailbox 0 transmit finished Flag
* @arg CAN_FLAG_MTF1: Mailbox 1 transmit finished Flag
* @arg CAN_FLAG_MTF2: Mailbox 2 transmit finished Flag
* @arg CAN_FLAG_RFL0: the length of the receive FIFO0 Flag
* @arg CAN_FLAG_RFF0: Receive FIFO 0 full Flag
* @arg CAN_FLAG_RFO0: Receive FIFO 0 overfull Flag
* @arg CAN_FLAG_RFL1: the length of the receive FIFO1 Flag
* @arg CAN_FLAG_RFF1: Receive FIFO 1 full Flag
* @arg CAN_FLAG_RFO1: Receive FIFO 0 overfull Flag
* @arg CAN_FLAG_WU: Wake up Flag
* @arg CAN_FLAG_SLP: Sleep working state Flag
* @arg CAN_FLAG_ET: Error type Flag
* @retval The new state of CAN_FLAG (SET or RESET).
*/
TypeState CAN_GetBitState(CAN_TypeDef *CANx, uint32_t CAN_FLAG)
{
if ((CAN_FLAG & CAN_FLAGS_ER) != (uint32_t)RESET) {
/* Check the state of the specified CAN flag */
if ((CANx->ER & (CAN_FLAG & CAN_FLAG_Mask)) != (uint32_t)RESET) {
/* CAN_FLAG is set */
return SET;
} else {
/* CAN_FLAG is reset */
return RESET;
}
} else if ((CAN_FLAG & CAN_FLAGS_STR) != (uint32_t)RESET) {
/* Check the state of the specified CAN flag */
if ((CANx->STR & (CAN_FLAG & CAN_FLAG_Mask)) != (uint32_t)RESET) {
/* CAN_FLAG is set */
return SET;
} else {
/* CAN_FLAG is reset */
return RESET;
}
} else if ((CAN_FLAG & CAN_FLAGS_TSTR) != (uint32_t)RESET) {
/* Check the state of the specified CAN flag */
if ((CANx->TSTR & (CAN_FLAG & CAN_FLAG_Mask)) != (uint32_t)RESET) {
/* CAN_FLAG is set */
return SET;
} else {
/* CAN_FLAG is reset */
return RESET;
}
} else if ((CAN_FLAG & CAN_FLAGS_RFR0) != (uint32_t)RESET) {
/* Check the state of the specified CAN flag */
if ((CANx->RFR0 & (CAN_FLAG & CAN_FLAG_Mask)) != (uint32_t)RESET) {
/* CAN_FLAG is set */
return SET;
} else {
/* CAN_FLAG is reset */
return RESET;
}
}
/* If(CAN_FLAG & CAN_FLAGS_RFR1 != (uint32_t)RESET) */
else {
/* Check the state of the specified CAN flag */
if ((uint32_t)(CANx->RFR1 & (CAN_FLAG & CAN_FLAG_Mask)) != (uint32_t)RESET) {
/* CAN_FLAG is set */
return SET;
} else {
/* CAN_FLAG is reset */
return RESET;
}
}
}
/**
* @brief Clear the CAN's flags.
* @param CANx: where x:[1,2] to to select the CAN peripheral.
* @param CAN_FLAG: specify the flag to clear.
* This parameter can be one of the following flags:
* @arg CAN_FLAG_MTF0: Mailbox 0 transmit finished Flag
* @arg CAN_FLAG_MTF1: Mailbox 1 transmit finished Flag
* @arg CAN_FLAG_MTF2: Mailbox 2 transmit finished Flag
* @arg CAN_FLAG_RFF0: Receive FIFO 0 full Flag
* @arg CAN_FLAG_RFO0: Receive FIFO 0 overfull Flag
* @arg CAN_FLAG_RFF1: Receive FIFO 1 full Flag
* @arg CAN_FLAG_RFO1: Receive FIFO 0 overfull Flag
* @arg CAN_FLAG_WU: Wake up Flag
* @arg CAN_FLAG_SLP: Sleep working state Flag
* @arg CAN_FLAG_ET: Error type Flag
* @retval None.
*/
void CAN_ClearBitState(CAN_TypeDef *CANx, uint32_t CAN_FLAG)
{
uint32_t temp = 0;
/* ER register */
if (CAN_FLAG == CAN_FLAG_ET) {
/* Clear the selected CAN flags */
CANx->ER = (uint32_t)RESET;
}
/* STR or TSTR or RFR0 or RFR1 */
else {
temp = CAN_FLAG & CAN_FLAG_Mask;
if ((CAN_FLAG & CAN_FLAGS_RFR0) != (uint32_t)RESET) {
/* Receive Flags */
CANx->RFR0 = (uint32_t)(temp);
} else if ((CAN_FLAG & CAN_FLAGS_RFR1) != (uint32_t)RESET) {
/* Receive Flags */
CANx->RFR1 = (uint32_t)(temp);
} else if ((CAN_FLAG & CAN_FLAGS_TSTR) != (uint32_t)RESET) {
/* Transmit Flags */
CANx->TSTR = (uint32_t)(temp);
}
/* If((CAN_FLAG & CAN_FLAGS_STR)!=(uint32_t)RESET) */
else {
CANx->STR = (uint32_t)(temp);
}
}
}
/**
* @brief Check whether the specified CANx interrupt has occurred or not.
* @param CANx: where x:[1,2] to to select the CAN peripheral.
* @param CAN_INT: specify the CAN interrupt source to check.
* This parameter can be:
* @arg CAN_INT_TME
* @arg CAN_INT_RFNE0
* @arg CAN_INT_RFF0
* @arg CAN_INT_RFO0
* @arg CAN_INT_RFNE1
* @arg CAN_INT_RFF1
* @arg CAN_INT_RFO1
* @arg CAN_INT_WE
* @arg CAN_INT_PE
* @arg CAN_INT_BOE
* @arg CAN_INT_ET
* @arg CAN_INT_ERR
* @arg CAN_INT_WU
* @arg CAN_INT_SLP
* @retval The current state of CAN_INT (SET or RESET).
*/
TypeState CAN_GetIntBitState(CAN_TypeDef *CANx, uint32_t CAN_INT)
{
TypeState intstate = RESET;
/* Get the enable interrupt bit */
if ((CANx->IER & CAN_INT) != RESET) {
switch (CAN_INT) {
case CAN_INT_TME:
/* Check CAN_TSTR_MTFx bits */
intstate = CheckINTState(CANx->TSTR, CAN_TSTR_MTF0 | CAN_TSTR_MTF1 | CAN_TSTR_MTF2);
break;
case CAN_INT_RFNE0:
/* Check CAN_RFR0_RFL0 bit */
intstate = CheckINTState(CANx->RFR0, CAN_RFR0_RFL0);
break;
case CAN_INT_RFF0:
/* Check CAN_RFR0_RFF0 bit */
intstate = CheckINTState(CANx->RFR0, CAN_RFR0_RFF0);
break;
case CAN_INT_RFO0:
/* Check CAN_RFR0_RFO0 bit */
intstate = CheckINTState(CANx->RFR0, CAN_RFR0_RFO0);
break;
case CAN_INT_RFNE1:
/* Check CAN_RFR1_RFL1 bit */
intstate = CheckINTState(CANx->RFR1, CAN_RFR1_RFL1);
break;
case CAN_INT_RFF1:
/* Check CAN_RFR1_RFF1 bit */
intstate = CheckINTState(CANx->RFR1, CAN_RFR1_RFF1);
break;
case CAN_INT_RFO1:
/* Check CAN_RFR1_RFO1 bit */
intstate = CheckINTState(CANx->RFR1, CAN_RFR1_RFO1);
break;
case CAN_INT_WU:
/* Check CAN_STR_WIF bit */
intstate = CheckINTState(CANx->STR, CAN_STR_WIF);
break;
case CAN_INT_SLP:
/* Check CAN_STR_SEIF bit */
intstate = CheckINTState(CANx->STR, CAN_STR_SEIF);
break;
case CAN_INT_WE:
/* Check CAN_INT_WE bit */
intstate = CheckINTState(CANx->ER, CAN_ER_WE);
break;
case CAN_INT_PE:
/* Check CAN_INT_EP bit */
intstate = CheckINTState(CANx->ER, CAN_ER_PE);
break;
case CAN_INT_BOE:
/* Check CAN_ER_BOE bit */
intstate = CheckINTState(CANx->ER, CAN_ER_BOE);
break;
case CAN_INT_ET:
/* Check CAN_ER_ET bit */
intstate = CheckINTState(CANx->ER, CAN_ER_ET);
break;
case CAN_INT_ERR:
/* Check CAN_STR_EIF bit */
intstate = CheckINTState(CANx->STR, CAN_STR_EIF);
break;
default :
/* in case of error, return RESET */
intstate = RESET;
break;
}
} else {
/* in case the Interrupt is not enabled, return RESET */
intstate = RESET;
}
/* Return the CAN_INT status */
return intstate;
}
/**
* @brief Clear the CANx's interrupt pending bits.
* @param CANx: where x:[1,2] to to select the CAN peripheral.
* @param CAN_INT: specify the interrupt pending bit to clear.
* This parameter can be:
* @arg CAN_INT_TME
* @arg CAN_INT_RFF0
* @arg CAN_INT_RFO0
* @arg CAN_INT_RFF1
* @arg CAN_INT_RFO1
* @arg CAN_INT_WE
* @arg CAN_INT_PE
* @arg CAN_INT_BOE
* @arg CAN_INT_ET
* @arg CAN_INT_ERR
* @arg CAN_INT_WU
* @arg CAN_INT_SLP
* @retval None.
*/
void CAN_ClearIntBitState(CAN_TypeDef *CANx, uint32_t CAN_INT)
{
switch (CAN_INT) {
case CAN_INT_TME:
/* Clear CAN_TSTR_MTFx (rc_w1)*/
CANx->TSTR = CAN_TSTR_MTF0 | CAN_TSTR_MTF1 | CAN_TSTR_MTF2;
break;
case CAN_INT_RFF0:
/* Clear CAN_RFR0_RFF0 (rc_w1)*/
CANx->RFR0 = CAN_RFR0_RFF0;
break;
case CAN_INT_RFO0:
/* Clear CAN_RFR0_RFO0 (rc_w1)*/
CANx->RFR0 = CAN_RFR0_RFO0;
break;
case CAN_INT_RFF1:
/* Clear CAN_RFR1_RFF1 (rc_w1)*/
CANx->RFR1 = CAN_RFR1_RFF1;
break;
case CAN_INT_RFO1:
/* Clear CAN_RFR1_RFO1 (rc_w1)*/
CANx->RFR1 = CAN_RFR1_RFO1;
break;
case CAN_INT_WU:
/* Clear CAN_STR_WIF (rc_w1)*/
CANx->STR = CAN_STR_WIF;
break;
case CAN_INT_SLP:
/* Clear CAN_STR_SEIF (rc_w1)*/
CANx->STR = CAN_STR_SEIF;
break;
case CAN_INT_WE:
/* Clear CAN_STR_EIF (rc_w1) */
CANx->STR = CAN_STR_EIF;
break;
case CAN_INT_PE:
/* Clear CAN_MSR_ERRI (rc_w1) */
CANx->STR = CAN_STR_EIF;
break;
case CAN_INT_BOE:
/* Clear CAN_STR_EIF (rc_w1) */
CANx->STR = CAN_STR_EIF;
break;
case CAN_INT_ET:
/* Clear ET bits */
CANx->ER = RESET;
/* Clear CAN_STR_EIF (rc_w1) */
CANx->STR = CAN_STR_EIF;
break;
case CAN_INT_ERR:
/*Clear ET bits */
CANx->ER = RESET;
/* Clear CAN_STR_EIF (rc_w1) */
CANx->STR = CAN_STR_EIF;
break;
default :
break;
}
}
/**
* @brief Check whether the CAN interrupt has occurred or not.
* @param CAN_Reg: the register of CAN interrupt to check.
* @param Int_Bit: the bit of interrupt source to check.
* @retval The new state of the CAN Interrupt (SET or RESET).
*/
static TypeState CheckINTState(uint32_t CAN_Reg, uint32_t Int_Bit)
{
if ((CAN_Reg & Int_Bit) != (uint32_t)RESET) {
/* CAN_INT is set */
return SET;
} else {
/* CAN_IT is reset */
return RESET;
}
}
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/