I'm curently trying to initialise and configure FDCAN on the STM32U575 microcontroller to communicate with a microchip CAN Bus Analyzer. All coding is done with Keil uVision studio in low level embedded C. My set up consists of 1x STM32U575 microcontroller, 1x Can Bus Analyzer, and two cables which connect to the Rx and Tx pins on the board. I am able to intisialise basic parameters such as the bit timing, FIFO operation, mode of operation. However, when it comes to configuring the data length code (DLC), standard ID, and the actual message to transmit, I'm not entirely certain how to do this as there are no registers dedicated for these parameters. I believe I have to communicate to the RAM which stores these parameters as suggested in the reference manual here, but it does not point to which registers need changing. As such, I'm confused as to what I need program here, because a previous microcontroller I've used (STM32F303) had dedicated registers for programming the DLC, standard ID, and message to transmit. This chip clearly works a bit different.
[FDCAN RX FIFO Element](As you can see, the information stored in the RX FIFO element contains DLC and ID data fields which
I need to program.)
[RX FIFO Registers](The only dedicated registers to Rx FIFO are the Rx FIFO acknowledge and Rx status. I cannot write the DLC and ID into those registers)
This is the code I've generated so far:
#include "stm32u575xx.h"
typedef struct {
uint32_t identifier; // Message identifier
uint8_t dataLength; // Number of data bytes (up to 64)
uint8_t data[64]; // Data bytes
} FDCAN_Message;
FDCAN_Message message;
void FDCAN_SendMessage(FDCAN_Message* message);
static void FDCAN1_Init(void);
int main(void)
{
FDCAN1_Init();
message.identifier = 0x123; // Set the message identifier
message.dataLength = 8; // Set the number of data bytes
message.data[0] = 0xAA; // Set the data bytes (example values)
message.data[1] = 0xBB;
}
static void FDCAN1_Init(void)
{
RCC -> APB1ENR2 |= RCC_APB1ENR2_FDCAN1EN;
RCC -> CCIPR1 &= ~ RCC_CCIPR1_FDCANSEL_0;
FDCAN1 -> CCCR &= ~ FDCAN_CCCR_INIT;
FDCAN1 -> CCCR |= FDCAN_CCCR_INIT; // Set INIT and CCE bits
while ((FDCAN1->CCCR & FDCAN_CCCR_INIT) == 0U);
FDCAN1 -> CCCR |= FDCAN_CCCR_CCE;
FDCAN1 -> CCCR &= ~ FDCAN_CCCR_CSR;//FDCAN1 -> CFGR |= FDCAN_CKDIV_PDIV_Pos;
FDCAN1 -> CCCR &= ~ FDCAN_CCCR_DAR; //AutoRetransmission = ENABLE; F FDCAN1 -> CCCR |= FDCAN_CCCR_TXP; //TransmitPause = ENABLE;
FDCAN1 -> CCCR &= ~ FDCAN_CCCR_PXHD_Pos; //ProtocolException = DISABLE;
FDCAN1 -> CCCR |= (FDCAN_CCCR_FDOE | FDCAN_CCCR_BRSE); //Frame Format
FDCAN1 -> CCCR |= FDCAN_CCCR_TEST;
FDCAN1 -> TEST |= FDCAN_TEST_LBCK; //LOOPBACK mode
FDCAN1->NBTP = 0x000B0905;
// Configure FDCAN1 bit timings (assuming 500kbps)
FDCAN1->DBTP = FDCAN_DBTP_DSJW_Pos | FDCAN_DBTP_DTSEG2_Pos| FDCAN_DBTP_DTSEG1_Pos | FDCAN_DBTP_DBRP_Pos;
FDCAN1 -> TXBC &= ~ FDCAN_TXBC_TFQM; // TX FIFO operation mode
FDCAN1 -> XIDAM &= ~ 0x00000001;
FDCAN1 -> XIDAM |= 0x00000001; //Extended ID mask
FDCAN1 -> RXGFC |= FDCAN_RXGFC_LSS_Msk;
FDCAN1 -> RXGFC |= 0x00000020;
FDCAN1 -> RXGFC |= FDCAN_RXGFC_RRFE;
FDCAN1 -> RXGFC &= ~ FDCAN_RXGFC_RRFS_Pos;
FDCAN1 -> CCCR &= ~ FDCAN_CCCR_INIT;
}
I've attempted is to reverse engineer one of the HAL example codes from STM32CubeMX (FDCAN_LOOPBACK.uvprojx), and follow through the logic to see which registers are being used, but I had no success in that. Ideally I would want to have something similar as the HAL example code, but translated into low-level embedded c.
This is the main body of the HAL code I attempted to look at:
int main(void)
{
/* USER CODE BEGIN 1 */
/* STM32U5xx HAL library initialization:
- Configure the Flash prefetch
- Configure the Systick to generate an interrupt each 1 msec
- Set NVIC Group Priority to 3
- Low Level Initialization
*/
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* Configure the System Power */
SystemPower_Config();
/* USER CODE BEGIN SysInit */
/* Configure LED5 and LED6 */
BSP_LED_Init(LED5);
BSP_LED_Init(LED6);
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_ICACHE_Init();
MX_FDCAN1_Init();
/* USER CODE BEGIN 2 */
/*##-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();
}
/*##-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_12;
TxHeader.ErrorStateIndicator = FDCAN_ESI_ACTIVE;
TxHeader.BitRateSwitch = FDCAN_BRS_ON;
TxHeader.FDFormat = FDCAN_FD_CAN;
TxHeader.TxEventFifoControl = FDCAN_STORE_TX_EVENTS;
TxHeader.MessageMarker = 0x52;
if (HAL_FDCAN_AddMessageToTxFifoQ(&hfdcan1, &TxHeader, TxData0) != HAL_OK)
{
Error_Handler();
}
/* Add second message to Tx FIFO */
TxHeader.Identifier = 0x1111112;
TxHeader.IdType = FDCAN_EXTENDED_ID;
TxHeader.TxFrameType = FDCAN_DATA_FRAME;
TxHeader.DataLength = FDCAN_DLC_BYTES_12;
TxHeader.ErrorStateIndicator = FDCAN_ESI_PASSIVE;
TxHeader.BitRateSwitch = FDCAN_BRS_ON;
TxHeader.FDFormat = FDCAN_FD_CAN;
TxHeader.TxEventFifoControl = FDCAN_STORE_TX_EVENTS;
TxHeader.MessageMarker = 0xCC;
if (HAL_FDCAN_AddMessageToTxFifoQ(&hfdcan1, &TxHeader, TxData1) != HAL_OK)
{
Error_Handler();
}
/* Add third message to Tx FIFO */
TxHeader.Identifier = 0x1111113;
TxHeader.IdType = FDCAN_EXTENDED_ID;
TxHeader.TxFrameType = FDCAN_DATA_FRAME;
TxHeader.DataLength = FDCAN_DLC_BYTES_12;
TxHeader.ErrorStateIndicator = FDCAN_ESI_PASSIVE;
TxHeader.BitRateSwitch = FDCAN_BRS_OFF;
TxHeader.FDFormat = FDCAN_FD_CAN;
TxHeader.TxEventFifoControl = FDCAN_STORE_TX_EVENTS;
TxHeader.MessageMarker = 0xDD;
if (HAL_FDCAN_AddMessageToTxFifoQ(&hfdcan1, &TxHeader, TxData2) != HAL_OK)
{
Error_Handler();
}
/* Wait transmissions complete */
while (HAL_FDCAN_GetTxFifoFreeLevel(&hfdcan1) != 3) {}
/*##-4 Receive messages ###################################################*/
/* Check one message is received in Rx FIFO 0 */
if(HAL_FDCAN_GetRxFifoFillLevel(&hfdcan1, FDCAN_RX_FIFO0) != 1)
{
Error_Handler();
}
/* Retrieve message from Rx FIFO 0 */
if (HAL_FDCAN_GetRxMessage(&hfdcan1, FDCAN_RX_FIFO0, &RxHeader, RxData) != HAL_OK)
{
Error_Handler();
}
/* Compare payload to expected data */
if (BufferCmp8b(TxData0, RxData, 12) != 0)
{
Error_Handler();
}
/* Check two messages are received in Rx FIFO 1 */
if(HAL_FDCAN_GetRxFifoFillLevel(&hfdcan1, FDCAN_RX_FIFO1) != 2)
{
Error_Handler();
}
/* Retrieve message from Rx FIFO 1 */
if (HAL_FDCAN_GetRxMessage(&hfdcan1, FDCAN_RX_FIFO1, &RxHeader, RxData) != HAL_OK)
{
Error_Handler();
}
/* Compare payload to expected data */
if (BufferCmp8b(TxData1, RxData, 12) != 0)
{
Error_Handler();
}
/* Retrieve next message from Rx FIFO 1 */
if (HAL_FDCAN_GetRxMessage(&hfdcan1, FDCAN_RX_FIFO1, &RxHeader, RxData) != HAL_OK)
{
Error_Handler();
}
/* Compare payload to expected data */
if (BufferCmp8b(TxData2, RxData, 12) != 0)
{
Error_Handler();
}
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* Toggle LED5 */
BSP_LED_Toggle(LED5);
HAL_Delay(100);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}