[FM33LG0 Series Development Board Review] 06.CAN
[Copy link]
1. Introduction
FM33LG048 has one CNA (Controller Area Network) interface, supports CAN 2.0A and CAN 2.0B standards, supports 11-bit standard ID and 29-bit extended ID; the maximum transmission rate can reach 1Mbps, and it has 2 transmit FIFOs, 2 receive FIFOs and 4 receive filters; in the case of bus error or transmission arbitration failure, it also supports automatic retransmission function.
The CAN interface of FM33LG048 is connected through pin headers on the FM33LG0xx DEMO V1.1 development board, namely PD10 (CAN_RX) and PE9 (CAN_TX), corresponding to the J17 interface on the development board;
There are many options for the CAN clock source of FM33LG048: RCHF, XTHF, PLL, APBCLK; the selection of which clock source can be configured by software; in order to improve the accuracy of the communication rate, the clock frequency used needs to meet the tolerance range specified in ISO11898-1. In this example, the XTHF external crystal oscillator is used as the CAN clock source, so when initializing the CAN configuration parameters, you need to configure XTHF to enable it first .
2. Software function
Use XTHF external crystal oscillator as the clock source of CAN, configure the communication rate of CAN to 100kbps, send a test data to the CAN bus every 500ms in the program; turn on CAN receive interrupt, and print out the data information received by CAN through the serial port when new data is received;
3. Implementation code
/*******************************************************************************
* @file CAN.c
* @author King
* [url=home.php?mod=space&uid=252314]@version[/url] V1.00
* [url=home.php?mod=space&uid=311857]@date[/url] 27-Nov-2021
* [url=home.php?mod=space&uid=159083]@brief[/url] ......
*******************************************************************************/
/* Define to prevent recursive inclusion -------------------------------------*/
#define __CAN_C__
/* Includes ------------------------------------------------------------------*/
#include "CAN.h"
#if CAN_ENABLE
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
/* Exported variables --------------------------------------------------------*/
/* Exported function prototypes ----------------------------------------------*/
/*******************************************************************************
* @brief
* @param
* @retval
* [url=home.php?mod=space&uid=1020061]@attention[/url] *******************************************************************************/
void CAN_Configure(void)
{
FL_GPIO_InitTypeDef GPIO_InitStruct;
FL_CAN_InitTypeDef CAN_InitStruct;
FL_CAN_FilterInitTypeDef CAN_FilterInitStruct;
//---Enable XTHF For CAN Clock Source
FL_GPIO_StructInit(&GPIO_InitStruct);
GPIO_InitStruct.pin = FL_GPIO_PIN_2 | FL_GPIO_PIN_3;
GPIO_InitStruct.mode = FL_GPIO_MODE_ANALOG;
GPIO_InitStruct.outputType = FL_GPIO_OUTPUT_PUSHPULL;
FL_GPIO_Init(GPIOC, &GPIO_InitStruct);
FL_CMU_XTHF_Enable();
FL_CMU_XTHF_WriteDriverStrength(0x1F);
FL_DelayMs(3);
FL_GPIO_StructInit(&GPIO_InitStruct);
GPIO_InitStruct.pin = FL_GPIO_PIN_9;
GPIO_InitStruct.mode = FL_GPIO_MODE_DIGITAL;
GPIO_InitStruct.outputType = FL_GPIO_OUTPUT_PUSHPULL;
GPIO_InitStruct.pull = FL_ENABLE;
FL_GPIO_Init(GPIOE, &GPIO_InitStruct);
FL_GPIO_StructInit(&GPIO_InitStruct);
GPIO_InitStruct.pin = FL_GPIO_PIN_10;
GPIO_InitStruct.mode = FL_GPIO_MODE_DIGITAL;
GPIO_InitStruct.outputType = FL_GPIO_OUTPUT_PUSHPULL;
GPIO_InitStruct.pull = FL_ENABLE;
FL_GPIO_Init(GPIOD, &GPIO_InitStruct);
/* CAN Baudrate = CAN_CLK / (BRP + 1) / (TS1 + TS2 + 1) */
FL_CAN_StructInit(&CAN_InitStruct);
CAN_InitStruct.mode = FL_CAN_MODE_NORMAL;
CAN_InitStruct.BRP = 7;
CAN_InitStruct.clockSource = FL_CMU_CAN_CLK_SOURCE_XTHF;
CAN_InitStruct.SJW = FL_CAN_SJW_1Tq;
CAN_InitStruct.TS1 = FL_CAN_TS1_5Tq;
CAN_InitStruct.TS2 = FL_CAN_TS2_4Tq;
FL_CAN_Init(CAN, &CAN_InitStruct);
FL_CAN_StructFilterInit(&CAN_FilterInitStruct);
CAN_FilterInitStruct.filterIdStandard = 0x6AD;
CAN_FilterInitStruct.filterIdSRR = 0;
CAN_FilterInitStruct.filterIdIDE = 0;
CAN_FilterInitStruct.filterIdRTR = 0;
CAN_FilterInitStruct.filterMaskIdHigh = 0x7FF;
CAN_FilterInitStruct.filterMaskIdSRR = 0x01;
CAN_FilterInitStruct.filterMaskIdIDE = 0x01;
CAN_FilterInitStruct.filterMaskIdRTR = 0x01;
CAN_FilterInitStruct.filterEn = FL_ENABLE;
FL_CAN_FilterInit(CAN, &CAN_FilterInitStruct, FL_CAN_FILTER1);
FL_CAN_ClearFlag_CRXOK(CAN);
FL_CAN_EnableIT_RXOK(CAN);
NVIC_DisableIRQ(CAN_IRQn);
NVIC_SetPriority(CAN_IRQn, 2);
NVIC_EnableIRQ(CAN_IRQn);
TASK_Append(TASK_ID_CAN, CAN_Handler, 500);
}
/*******************************************************************************
* @brief
* @param
* @retval
* @attention
*******************************************************************************/
void FL_CAN_FIFO_Write(uint32_t ID, uint32_t Length, uint32_t Data1, uint32_t Data2)
{
uint32_t Timeout = 5;
while((FL_CAN_IsActiveFlag_TXBuffFull(CAN) != FL_RESET) & Timeout)
{
Timeout--;
FL_DelayMs(1);
}
FL_CAN_WriteTXMessageID(CAN, ID);
FL_CAN_WriteTXMessageLength(CAN, Length);
FL_CAN_WriteTXMessageWord1(CAN, Data1);
FL_CAN_WriteTXMessageWord2(CAN, Data2);
}
/*******************************************************************************
* @brief
* @param
* @retval
* @attention
*******************************************************************************/
void FL_CAN_HPBUF_Write(uint32_t ID, uint32_t Length, uint32_t Data1, uint32_t Data2)
{
uint32_t Timeout = 5;
while((FL_CAN_IsActiveFlag_TXHighPriorBuffFull(CAN) != FL_RESET) & Timeout)
{
Timeout--;
FL_DelayMs(1);
}
FL_CAN_WriteHighPriorTXMessageID(CAN, ID);
FL_CAN_WriteHighPriorMessageLength(CAN, Length);
FL_CAN_WriteHighPriorMessageWord1(CAN, Data1);
FL_CAN_WriteHighPriorMessageWord2(CAN, Data2);
}
/*******************************************************************************
* @brief
* @param
* @retval
* @attention
*******************************************************************************/
void FL_CAN_Receive(void)
{
uint32_t Data1 = 0;
uint32_t Data2 = 0;
CAN_MSG_TypeDef RxMessage;
RxMessage.StdId = FL_CAN_ReadRXMessageID(CAN);
RxMessage.DLC = FL_CAN_ReadRXMessageLength(CAN);
Data1 = FL_CAN_ReadRXMessageWord1(CAN);
Data2 = FL_CAN_ReadRXMessageWord2(CAN);
RxMessage.Data[0] = (uint8_t)(Data1 >> 0x00) & 0xFF;
RxMessage.Data[1] = (uint8_t)(Data1 >> 0x08) & 0xFF;
RxMessage.Data[2] = (uint8_t)(Data1 >> 0x10) & 0xFF;
RxMessage.Data[3] = (uint8_t)(Data1 >> 0x18) & 0xFF;
RxMessage.Data[4] = (uint8_t)(Data2 >> 0x00) & 0xFF;
RxMessage.Data[5] = (uint8_t)(Data2 >> 0x08) & 0xFF;
RxMessage.Data[6] = (uint8_t)(Data2 >> 0x10) & 0xFF;
RxMessage.Data[7] = (uint8_t)(Data2 >> 0x18) & 0xFF;
printf("\r\nCAN Receive : 0x%x, %d, ", RxMessage.StdId, RxMessage.DLC);
for(uint32_t i = 0; i < 8; i++)
{
printf("%02x ", RxMessage.Data[i]);
}
printf("\r\n");
}
/*******************************************************************************
* @brief
* @param
* @retval
* @attention
*******************************************************************************/
void FL_CAN_Transmit(uint32_t FrameFormat, CAN_MSG_TypeDef *TxMessage)
{
uint32_t ID = 0;
uint32_t Length = 0;
uint32_t Data1 = 0;
uint32_t Data2 = 0;
if(FrameFormat == FL_CAN_FORMAT_STANDARD_DATA)
{
ID = TxMessage->StdId & 0x7FF;
}
else if(FrameFormat == FL_CAN_FORMAT_STANDARD_REMOTE)
{
ID = (TxMessage->StdId & 0x7FF) | (1 << 11);
}
else if(FrameFormat == FL_CAN_FORMAT_EXTEND_DATA)
{
ID = ((TxMessage->ExtId & 0x3FFFF) << 13) |
((uint32_t)1 << 12) |
((uint32_t)1 << 11) |
((TxMessage->ExtId & 0x1FFC0000) >> 18);
}
else if(FrameFormat == FL_CAN_FORMAT_EXTEND_REMOTE)
{
ID = ((TxMessage->ExtId & 0x3FFFF) << 13) |
((uint32_t)1 << 12) |
((uint32_t)1 << 31) |
((TxMessage->ExtId & 0x1FFC0000) >> 18);
}
Length = TxMessage->DLC;
Data1 = ((uint32_t)TxMessage->Data[3] << 0x18) |
((uint32_t)TxMessage->Data[2] << 0x10) |
((uint32_t)TxMessage->Data[1] << 0x08) |
((uint32_t)TxMessage->Data[0] << 0x00);
Data2 = ((uint32_t)TxMessage->Data[7] << 0x18) |
((uint32_t)TxMessage->Data[6] << 0x10) |
((uint32_t)TxMessage->Data[5] << 0x08) |
((uint32_t)TxMessage->Data[4] << 0x00);
#if 1
FL_CAN_FIFO_Write(ID, Length, Data1, Data2);
#else
FL_CAN_HPBUF_Write(ID, Length, Data1, Data2);
#endif
}
/*******************************************************************************
* @brief
* @param
* @retval
* @attention
*******************************************************************************/
void CAN_Handler(void)
{
CAN_MSG_TypeDef TxMessage;
TxMessage.StdId = 0x6AD;
TxMessage.DLC = 8;
for(uint8_t i = 0; i < TxMessage.DLC; i++)
{
TxMessage.Data[i] = i;
}
FL_CAN_Transmit(FL_CAN_FORMAT_STANDARD_DATA, &TxMessage);
}
/*******************************************************************************
* @brief
* @param
* @retval
* @attention
*******************************************************************************/
void CAN_IRQHandler(void)
{
if((FL_ENABLE == FL_CAN_IsEnabledIT_RXOK(CAN)) &&
(FL_SET == FL_CAN_IsActiveFlag_RXOK(CAN)))
{
FL_CAN_Receive();
FL_CAN_ClearFlag_CRXOK(CAN);
}
}
#endif
/******************* (C) COPYRIGHT 2021 *************************END OF FILE***/
4. Debugging and running
Since the development board itself does not have a CAN transceiver, we need to connect an external CAN transceiver module when conducting CAN experiments. The VP230 chip used in this experiment supports the same 3.3V operating voltage as the MCU. In addition, a CAN debugging tool is connected to cooperate with the PC software to view the data transmitted on the CAN bus, or send test data to the CAN bus.
4.1. Hardware Connection
Monitoring data
4.3. Receiving Data
5. Project source code
Project_CAN.zip
(382.16 KB, downloads: 31)
|