This post was last edited by Murong Xuehua on 2024-3-4 12:54
The FDCAN of the U5 series devices is very convenient and can support both CAN-FD and classic CAN 2.0. The main tools and devices used in this experiment are:
- STM32U5A5ZJ-Q
- TJA1050 CAN transceiver
- CAN LIN TOOL V5.0
CAN transmit and receive pins use PB8 and PB9:
Schematic diagram of TJA1050:
Configure in CubeIde:
FDCAN clock: 64Mhz
CAN related timing parameters and working modes:
Save and automatically generate code:
static void MX_FDCAN1_Init(void)
{
/* USER CODE BEGIN FDCAN1_Init 0 */
/* USER CODE END FDCAN1_Init 0 */
/* USER CODE BEGIN FDCAN1_Init 1 */
/* USER CODE END FDCAN1_Init 1 */
hfdcan1.Instance = FDCAN1;
hfdcan1.Init.ClockDivider = FDCAN_CLOCK_DIV1;
hfdcan1.Init.FrameFormat = FDCAN_FRAME_CLASSIC;
hfdcan1.Init.Mode = FDCAN_MODE_NORMAL;
hfdcan1.Init.AutoRetransmission = ENABLE;
hfdcan1.Init.TransmitPause = ENABLE;
hfdcan1.Init.ProtocolException = DISABLE;
hfdcan1.Init.NominalPrescaler = 16;
hfdcan1.Init.NominalSyncJumpWidth = 1;
hfdcan1.Init.NominalTimeSeg1 = 5;
hfdcan1.Init.NominalTimeSeg2 = 2;
hfdcan1.Init.DataPrescaler = 1;
hfdcan1.Init.DataSyncJumpWidth = 1;
hfdcan1.Init.DataTimeSeg1 = 1;
hfdcan1.Init.DataTimeSeg2 = 1;
hfdcan1.Init.StdFiltersNbr = 0;
hfdcan1.Init.ExtFiltersNbr = 0;
hfdcan1.Init.TxFifoQueueMode = FDCAN_TX_FIFO_OPERATION;
if (HAL_FDCAN_Init(&hfdcan1) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN FDCAN1_Init 2 */
/* USER CODE END FDCAN1_Init 2 */
}
Add custom test data:
FDCAN_FilterTypeDef sFilterConfig;
FDCAN_TxHeaderTypeDef TxHeader;
FDCAN_RxHeaderTypeDef RxHeader;
uint8_t TxData0[] = {0x10, 0x32, 0x54, 0x76, 0x98, 0x00, 0x11, 0x22};
uint8_t TxData1[] = {0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55};
uint8_t TxData2[] = {0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00};
Add the relevant filters:
void MY_FDCAN_CONFIG(void){
/*##-1 Configure the FDCAN filters ########################################*/
/* Configure standard ID reception filter to Rx FIFO 0 */
sFilterConfig.IdType = FDCAN_STANDARD_ID;
sFilterConfig.FilterIndex = 0;
sFilterConfig.FilterType = FDCAN_FILTER_DUAL;
sFilterConfig.FilterConfig = FDCAN_FILTER_TO_RXFIFO0;
sFilterConfig.FilterID1 = 0x444;
sFilterConfig.FilterID2 = 0x555;
if (HAL_FDCAN_ConfigFilter(&hfdcan1, &sFilterConfig) != HAL_OK)
{
Error_Handler();
}
/* Configure extended ID reception filter to Rx FIFO 1 */
sFilterConfig.IdType = FDCAN_EXTENDED_ID;
sFilterConfig.FilterIndex = 0;
sFilterConfig.FilterType = FDCAN_FILTER_RANGE_NO_EIDM;
sFilterConfig.FilterConfig = FDCAN_FILTER_TO_RXFIFO1;
sFilterConfig.FilterID1 = 0x1111111;
sFilterConfig.FilterID2 = 0x2222222;
if (HAL_FDCAN_ConfigFilter(&hfdcan1, &sFilterConfig) != HAL_OK)
{
Error_Handler();
}
/* Configure global filter:
Filter all remote frames with STD and EXT ID
Reject non matching frames with STD ID and EXT ID */
if (HAL_FDCAN_ConfigGlobalFilter(&hfdcan1, FDCAN_REJECT, FDCAN_REJECT, FDCAN_FILTER_REMOTE, FDCAN_FILTER_REMOTE) != HAL_OK)
{
Error_Handler();
}
/*##-2 Start FDCAN controller (continuous listening CAN bus) ##############*/
if (HAL_FDCAN_Start(&hfdcan1) != HAL_OK)
{
Error_Handler();
}
printf("\r\nBefore Add 0x444: HAL_FDCAN_GetTxFifoFreeLevel(&hfdcan1) = %d", HAL_FDCAN_GetTxFifoFreeLevel(&hfdcan1));
/*##-3 Transmit messages ##################################################*/
/* Add message to Tx FIFO */
TxHeader.Identifier = 0x444;
TxHeader.IdType = FDCAN_STANDARD_ID;
TxHeader.TxFrameType = FDCAN_DATA_FRAME;
TxHeader.DataLength = FDCAN_DLC_BYTES_8;
TxHeader.ErrorStateIndicator = FDCAN_ESI_ACTIVE;
TxHeader.BitRateSwitch = FDCAN_BRS_OFF;
TxHeader.FDFormat = FDCAN_CLASSIC_CAN;
TxHeader.TxEventFifoControl = FDCAN_STORE_TX_EVENTS;
TxHeader.MessageMarker = 0x52;
if (HAL_FDCAN_AddMessageToTxFifoQ(&hfdcan1, &TxHeader, TxData0) != HAL_OK)
{
Error_Handler();
}
printf("\r\nAfter Add 0x444: HAL_FDCAN_GetTxFifoFreeLevel(&hfdcan1) = %d", HAL_FDCAN_GetTxFifoFreeLevel(&hfdcan1));
/* Add second message to Tx FIFO */
TxHeader.Identifier = 0x1111112;
TxHeader.IdType = FDCAN_EXTENDED_ID;
TxHeader.TxFrameType = FDCAN_DATA_FRAME;
TxHeader.DataLength = FDCAN_DLC_BYTES_8;
TxHeader.ErrorStateIndicator = FDCAN_ESI_PASSIVE;
TxHeader.BitRateSwitch = FDCAN_BRS_OFF;
TxHeader.FDFormat = FDCAN_CLASSIC_CAN;
TxHeader.TxEventFifoControl = FDCAN_STORE_TX_EVENTS;
TxHeader.MessageMarker = 0xCC;
if (HAL_FDCAN_AddMessageToTxFifoQ(&hfdcan1, &TxHeader, TxData1) != HAL_OK)
{
Error_Handler();
}
printf("\r\nAfter Add 0x1111112: HAL_FDCAN_GetTxFifoFreeLevel(&hfdcan1) = %d", HAL_FDCAN_GetTxFifoFreeLevel(&hfdcan1));
/* Add third message to Tx FIFO */
TxHeader.Identifier = 0x1111113;
TxHeader.IdType = FDCAN_EXTENDED_ID;
TxHeader.TxFrameType = FDCAN_DATA_FRAME;
TxHeader.DataLength = FDCAN_DLC_BYTES_8;
TxHeader.ErrorStateIndicator = FDCAN_ESI_PASSIVE;
TxHeader.BitRateSwitch = FDCAN_BRS_OFF;
TxHeader.FDFormat = FDCAN_CLASSIC_CAN;
TxHeader.TxEventFifoControl = FDCAN_STORE_TX_EVENTS;
TxHeader.MessageMarker = 0xDD;
if (HAL_FDCAN_AddMessageToTxFifoQ(&hfdcan1, &TxHeader, TxData2) != HAL_OK)
{
Error_Handler();
}
printf("\r\nAfter Add 0x1111113: HAL_FDCAN_GetTxFifoFreeLevel(&hfdcan1) = %d", HAL_FDCAN_GetTxFifoFreeLevel(&hfdcan1));
/* Wait transmissions complete */
while (HAL_FDCAN_GetTxFifoFreeLevel(&hfdcan1) != 3) {}
printf("\r\n 3 CAN MSG Transmissions Complete.");
}//end of void MY_FDCAN_CONFIG(void)
In the main loop, the breathing light flashes once each time, and the number of times is packaged into can msg and sent to the host computer.
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
static uint16_t dcycle_pulse = 0;
static uint8_t breath_cnt = 0;
//htim3.Init.Period = 999
while(dcycle_pulse <htim3.Init.Period){
__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_2, dcycle_pulse);
dcycle_pulse += 50;
printf("\nLight Phase, Current DutyCycle = %u", dcycle_pulse*100/htim3.Init.Period);
HAL_Delay(100);
}
while(dcycle_pulse > 0){
__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_2, dcycle_pulse);
dcycle_pulse -= 50;
printf("\nDim Phase, Current DutyCycle = %u", dcycle_pulse*100/htim3.Init.Period);
HAL_Delay(100);
}
printf("\r\nBefore Add 0x555: HAL_FDCAN_GetTxFifoFreeLevel(&hfdcan1) = %d", HAL_FDCAN_GetTxFifoFreeLevel(&hfdcan1));
/* Wait for available Tx Fifo */
while (HAL_FDCAN_GetTxFifoFreeLevel(&hfdcan1) == 0) {}
TxBreathLEDCnt[7] = breath_cnt++;
if (HAL_FDCAN_AddMessageToTxFifoQ(&hfdcan1, &TxHeader, TxBreathLEDCnt) != HAL_OK)
{
Error_Handler();
}
printf("\r\nAfter Add 0x555: HAL_FDCAN_GetTxFifoFreeLevel(&hfdcan1) = %d", HAL_FDCAN_GetTxFifoFreeLevel(&hfdcan1));
printf("\r\nSTM32U5-TJA1050-USBCAN: Breath LED CAN MSG Transmissions Complete.");
}//end of while
Hardware system:
Host computer data:
First, 3 frames of test data are received, and then the number of flashes of the breathing light is transmitted through the message with ID 555.
After this experience, I feel that it is very convenient to configure CubeIDE to use the fdcan peripheral. In the future, I will consider taking a deeper look at the reception, interrupt reception and other functions.
reference:
AN5348_Application Note for the FDCAN Peripheral on STM32 Devices.pdf