我目前正在尝试在 STM32U575 微控制器上初始化和配置 FDCAN,以与 microchip CAN 总线分析仪进行通信。所有编码都是使用 Keil uVision studio 在低级嵌入式 C 语言中完成的。我的设置包括 1x STM32U575 微控制器、1x Can 总线分析器以及连接到板上 Rx 和 Tx 引脚的两根电缆。我能够初始化基本参数,例如位时序、FIFO 操作、操作模式。然而,当涉及到配置数据长度代码 (DLC)、标准 ID 和要传输的实际消息时,我并不完全确定如何执行此操作,因为没有专用于这些参数的寄存器。我相信我必须按照参考手册here中的建议与存储这些参数的RAM进行通信,但它没有指出哪些寄存器需要更改。因此,我对这里需要什么程序感到困惑,因为我以前使用过的微控制器 (STM32F303) 有专用寄存器用于对 DLC、标准 ID 和要传输的消息进行编程。该芯片的工作原理显然有点不同。
这是我到目前为止生成的代码:
#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;
}
我尝试对 STM32CubeMX (FDCAN_LOOPBACK.uvprojx) 中的 HAL 示例代码之一进行逆向工程,并遵循逻辑以查看正在使用哪些寄存器,但我没有成功。理想情况下,我希望有类似于 HAL 示例代码的东西,但转换为低级嵌入式 c。
这是我尝试查看的 HAL 代码的主体:
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 */
}
更新:我已经成功地在 STM32U575 微控制器上完全使用低级嵌入式 c 设置了 FDCAN 外设。事实证明,该微控制器不提供邮箱或任何可用于将配置和消息写入 RAM 的寄存器。您必须计算您写入的每个地址!此 FDCAN document 列出了有关某些 RAM 地址计算的一些信息。我将把下面的代码发布给将来遇到同样问题的其他人。
#include "stm32u575xx.h"
#define SET_BIT(REG, BIT) ((REG) |= (BIT))
#define CLEAR_BIT(REG, BIT) ((REG) &= ~(BIT))
#define READ_BIT(REG, BIT) ((REG) & (BIT))
#define CLEAR_REG(REG) ((REG) = (0x0))
#define WRITE_REG(REG, VAL) ((REG) = (VAL))
#define READ_REG(REG) ((REG))
#define MODIFY_REG(REG, CLEARMASK, SETMASK) WRITE_REG((REG), (((READ_REG(REG)) & (~(CLEARMASK))) | (SETMASK)))
/*** RAM defines ***/
#define SRAMCAN_FLS_NBR (28U) /* Max. Filter List Standard Number */
#define SRAMCAN_FLE_NBR ( 8U) /* Max. Filter List Extended Number */
#define SRAMCAN_RF0_NBR ( 3U) /* RX FIFO 0 Elements Number */
#define SRAMCAN_RF1_NBR ( 3U) /* RX FIFO 1 Elements Number */
#define SRAMCAN_TEF_NBR ( 3U) /* TX Event FIFO Elements Number */
#define SRAMCAN_TFQ_NBR ( 3U) /* TX FIFO/Queue Elements Number */
#define SRAMCAN_FLS_SIZE ( 1U * 4U) /* Filter Standard Element Size in bytes */
#define SRAMCAN_FLE_SIZE ( 2U * 4U) /* Filter Extended Element Size in bytes */
#define SRAMCAN_RF0_SIZE (18U * 4U) /* RX FIFO 0 Elements Size in bytes */
#define SRAMCAN_RF1_SIZE (18U * 4U) /* RX FIFO 1 Elements Size in bytes */
#define SRAMCAN_TEF_SIZE ( 2U * 4U) /* TX Event FIFO Elements Size in bytes */
#define SRAMCAN_TFQ_SIZE (18U * 4U) /* TX FIFO/Queue Elements Size in bytes */
#define SRAMCAN_FLSSA ((uint32_t)0) /* Filter List Standard Start
Address */
#define SRAMCAN_FLESA ((uint32_t)(SRAMCAN_FLSSA + (SRAMCAN_FLS_NBR * SRAMCAN_FLS_SIZE))) /* Filter List Extended Start
Address */
#define SRAMCAN_RF0SA ((uint32_t)(SRAMCAN_FLESA + (SRAMCAN_FLE_NBR * SRAMCAN_FLE_SIZE))) /* Rx FIFO 0 Start Address */
#define SRAMCAN_RF1SA ((uint32_t)(SRAMCAN_RF0SA + (SRAMCAN_RF0_NBR * SRAMCAN_RF0_SIZE))) /* Rx FIFO 1 Start Address */
#define SRAMCAN_TEFSA ((uint32_t)(SRAMCAN_RF1SA + (SRAMCAN_RF1_NBR * SRAMCAN_RF1_SIZE))) /* Tx Event FIFO Start
Address */
#define SRAMCAN_TFQSA ((uint32_t)(SRAMCAN_TEFSA + (SRAMCAN_TEF_NBR * SRAMCAN_TEF_SIZE))) /* Tx FIFO/Queue Start
Address */
#define SRAMCAN_SIZE ((uint32_t)(SRAMCAN_TFQSA + (SRAMCAN_TFQ_NBR * SRAMCAN_TFQ_SIZE))) /* Message RAM size */
#define Tx_Buffer_element_size (18U * 4U)
#define FDCAN_ELEMENT_MASK_DLC ((uint32_t)0x000F0000U) /* Data Length Code */
/***************** ------------------------------- Local Types ---------------------------------------------- **************/
typedef struct
{
uint32_t IdType; /*!< Specifies the identifier type.
This parameter can be a value of @ref FDCAN_id_type */
uint32_t FilterIndex; /*!< Specifies the filter which will be initialized.
This parameter must be a number between:
- 0 and (SRAMCAN_FLS_NBR-1), if IdType is FDCAN_STANDARD_ID
- 0 and (SRAMCAN_FLE_NBR-1), if IdType is FDCAN_EXTENDED_ID */
uint32_t FilterType; /*!< Specifies the filter type.
This parameter can be a value of @ref FDCAN_filter_type.
The value FDCAN_FILTER_RANGE_NO_EIDM is permitted
only when IdType is FDCAN_EXTENDED_ID. */
uint32_t FilterConfig; /*!< Specifies the filter configuration.
This parameter can be a value of @ref FDCAN_filter_config */
uint32_t FilterID1; /*!< Specifies the filter identification 1.
This parameter must be a number between:
- 0 and 0x7FF, if IdType is FDCAN_STANDARD_ID
- 0 and 0x1FFFFFFF, if IdType is FDCAN_EXTENDED_ID */
uint32_t FilterID2; /*!< Specifies the filter identification 2.
This parameter must be a number between:
- 0 and 0x7FF, if IdType is FDCAN_STANDARD_ID
- 0 and 0x1FFFFFFF, if IdType is FDCAN_EXTENDED_ID */
} FDCAN_FilterTypeDef;
typedef struct
{
uint32_t Identifier; /*!< Specifies the identifier.
This parameter must be a number between:
- 0 and 0x7FF, if IdType is FDCAN_STANDARD_ID
- 0 and 0x1FFFFFFF, if IdType is FDCAN_EXTENDED_ID */
uint32_t IdType; /*!< Specifies the identifier type for the message that will be
transmitted.
This parameter can be a value of @ref FDCAN_id_type */
uint32_t TxFrameType; /*!< Specifies the frame type of the message that will be transmitted.
This parameter can be a value of @ref FDCAN_frame_type */
uint32_t DataLength; /*!< Specifies the length of the frame that will be transmitted.
This parameter can be a value of @ref FDCAN_data_length_code */
uint32_t ErrorStateIndicator; /*!< Specifies the error state indicator.
This parameter can be a value of @ref FDCAN_error_state_indicator */
uint32_t BitRateSwitch; /*!< Specifies whether the Tx frame will be transmitted with or without
bit rate switching.
This parameter can be a value of @ref FDCAN_bit_rate_switching */
uint32_t FDFormat; /*!< Specifies whether the Tx frame will be transmitted in classic or
FD format.
This parameter can be a value of @ref FDCAN_format */
uint32_t TxEventFifoControl; /*!< Specifies the event FIFO control.
This parameter can be a value of @ref FDCAN_EFC */
uint32_t MessageMarker; /*!< Specifies the message marker to be copied into Tx Event FIFO
element for identification of Tx message status.
This parameter must be a number between 0 and 0xFF */
} FDCAN_TxHeaderTypeDef;
typedef struct
{
uint32_t StandardFilterSA; /*!< Specifies the Standard Filter List Start Address.
This parameter must be a 32-bit word address */
uint32_t ExtendedFilterSA; /*!< Specifies the Extended Filter List Start Address.
This parameter must be a 32-bit word address */
uint32_t RxFIFO0SA; /*!< Specifies the Rx FIFO 0 Start Address.
This parameter must be a 32-bit word address */
uint32_t RxFIFO1SA; /*!< Specifies the Rx FIFO 1 Start Address.
This parameter must be a 32-bit word address */
uint32_t TxEventFIFOSA; /*!< Specifies the Tx Event FIFO Start Address.
This parameter must be a 32-bit word address */
uint32_t TxFIFOQSA; /*!< Specifies the Tx FIFO/Queue Start Address.
This parameter must be a 32-bit word address */
} FDCAN_MsgRamAddressTypeDef;
typedef struct
{
uint32_t Identifier; /*!< Specifies the identifier.
This parameter must be a number between:
- 0 and 0x7FF, if IdType is FDCAN_STANDARD_ID
- 0 and 0x1FFFFFFF, if IdType is FDCAN_EXTENDED_ID */
uint32_t DataLength; /*!< Specifies the received frame length.
This parameter can be a value of @ref FDCAN_data_length_code */
} FDCAN_RxHeaderTypeDef;
/************* ----------------------------------- Local Variables -------------------------------------------- ****************/
static FDCAN_MsgRamAddressTypeDef RAM;
static FDCAN_FilterTypeDef sFilterConfig;
static FDCAN_TxHeaderTypeDef TxMailBox;
static FDCAN_RxHeaderTypeDef RxMailBox;
static const uint8_t DLCtoBytes[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 12, 16, 20, 24, 32, 48, 64};
/************* ----------------------------------- Local Functions ---------------------------------------------- **************/
__STATIC_INLINE void LL_RCC_PLL1_ConfigDomain_SYS(uint32_t Source, uint32_t PLLM, uint32_t PLLN, uint32_t PLLR);
void SystemCoreClockConfigure(void);
void gpio_pins(void);
void FDCAN1_Init(void);
void FDCAN_CalcultateRamBlockAddresses(void);
void StandardFilterConfig(void);
void ExitFDCANInit(void);
void SendMessageToRAM(const uint8_t *TxData);
void TransmissionPending(void);
void ReceiveMessage(void);
void ReadMessage(uint8_t *pRxData);
/************* ----------------------------------- Main Code --------------------------------------------------- **************/
int main(void)
{
uint8_t TxData0[] = {0x10, 0x32, 0x54, 0x76, 0x98, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66};
uint8_t RxData[12];
RCC -> AHB3ENR |= RCC_AHB3ENR_PWREN;
SystemCoreClockConfigure();
gpio_pins();
FDCAN1_Init();
StandardFilterConfig();
ExitFDCANInit();
SendMessageToRAM(TxData0);
TransmissionPending();
ReceiveMessage();
ReadMessage(RxData);
}
void ReadMessage(uint8_t *pRxData)
{
uint32_t *RxAddress;
uint32_t GetIndex = 0;
uint8_t *pData;
uint32_t ByteCounter;
/* Check RxFifo not empty */
while(!(FDCAN1->RXF0S & FDCAN_RXF0S_F0FL));
/* Calculate Rx FIFO 0 element index */
GetIndex += ((FDCAN1->RXF0S & FDCAN_RXF0S_F0GI) >> FDCAN_RXF0S_F0GI_Pos);
/* Calculate Rx FIFO 0 element address */
RxAddress = (uint32_t *)(SRAMCAN_BASE + SRAMCAN_RF0SA + (GetIndex * SRAMCAN_RF0_SIZE));
/**** You can Read First word of RxHeader here with mask values ****/
/* Increment RxAddress */
RxAddress++;
/**** You can Read Second word of RxHeader here with mask values ****/
/* Retrieve DataLength */
RxMailBox.DataLength = ((*RxAddress & FDCAN_ELEMENT_MASK_DLC) >> 16U);
/* Increment Rx Address to read received data */
RxAddress++;
/* Retrieve Rx payload */
pData = (uint8_t *)RxAddress;
for (ByteCounter = 0; ByteCounter < DLCtoBytes[RxMailBox.DataLength]; ByteCounter++)
{
pRxData[ByteCounter] = pData[ByteCounter];
}
/* Acknowledge the Rx FIFO 0 that the oldest element is read so that it increments the GetIndex */
FDCAN1->RXF0A = GetIndex;
}
void ReceiveMessage(void)
{
/* Check one message is received in Rx FIFO 0 */
while((FDCAN1->RXF0S & FDCAN_RXF0S_F0FL) == 0);
}
void TransmissionPending(void)
{
/* Wait for transmissions to complete */
while((FDCAN1 ->TXFQS & FDCAN_TXFQS_TFFL) != 3);
}
void SendMessageToRAM(const uint8_t *TxData)
{
uint32_t TxElementW1;
uint32_t TxElementW2;
volatile uint32_t *TxAddress;
uint32_t ByteCounter;
uint32_t PutIndex;
/* Configure a message to Rx FIF0 */
TxMailBox.Identifier = 0x444;
TxMailBox.IdType = 0x00000000U;
TxMailBox.TxFrameType = ((uint32_t)0x00000000U); // Classic frame
TxMailBox.DataLength = ((uint32_t)0x00000009U); //12 bytes data
TxMailBox.ErrorStateIndicator = ((uint32_t)0x00000000U); // Transmission node error-active
TxMailBox.BitRateSwitch = ((uint32_t)0x00100000U); //BRS ON
TxMailBox.FDFormat = ((uint32_t)0x00200000U); //FD ON
TxMailBox.TxEventFifoControl = ((uint32_t)0x00800000U); // Store Tx events
TxMailBox.MessageMarker = 0x52;
/* Copy message to RAM */
while((FDCAN1->TXFQS & FDCAN_TXFQS_TFQF) != 0U); /* Check that the Tx FIFO/Queue is not full */
/* Retrieve the Tx FIFO PutIndex */
PutIndex = ((FDCAN1->TXFQS & FDCAN_TXFQS_TFQPI) >> FDCAN_TXFQS_TFQPI_Pos);
/* Add the message to the Tx FIFO/Queue */
TxElementW1 = (TxMailBox.ErrorStateIndicator | (TxMailBox.Identifier << 18U) | TxMailBox.TxFrameType | (TxMailBox.IdType ));
TxElementW2 = ((TxMailBox.MessageMarker << 24U) | TxMailBox.TxEventFifoControl | TxMailBox.FDFormat | TxMailBox.BitRateSwitch | (TxMailBox.DataLength <<16U) );
/* Calculate Tx element address */
TxAddress = (uint32_t *)(SRAMCAN_BASE + SRAMCAN_TFQSA + (PutIndex * Tx_Buffer_element_size ));
/* Write Tx element header to the message RAM */
*TxAddress = TxElementW1;
TxAddress++;
*TxAddress = TxElementW2;
TxAddress++;
/* Send Data to RAM */
for (ByteCounter = 0; ByteCounter < DLCtoBytes[TxMailBox.DataLength]; ByteCounter += 4U)
{
*TxAddress = (((uint32_t)TxData[ByteCounter + 3U] << 24U) |
((uint32_t)TxData[ByteCounter + 2U] << 16U) |
((uint32_t)TxData[ByteCounter + 1U] << 8U) |
((uint32_t)TxData[ByteCounter]));
TxAddress++;
}
/* Activate the corresponding transmission request */
FDCAN1->TXBAR = ((uint32_t)1 << PutIndex);
}
void ExitFDCANInit(void)
{
FDCAN1 -> CCCR &= ~ FDCAN_CCCR_INIT;
while ((FDCAN1->CCCR & FDCAN_CCCR_INIT) != 0U); // wait for FDCAN1 to exit
}
void StandardFilterConfig(void)
{
volatile uint32_t FilterElementW1;
volatile uint32_t *FilterAddress;
/* Configure Rx FIF0 Filter */
sFilterConfig.IdType = ((uint32_t)0x00000000U);
sFilterConfig.FilterIndex = 0;
sFilterConfig.FilterType = ((uint32_t)0x00000001U); /*!< Dual ID filter for FilterID1 or FilterID2 */
sFilterConfig.FilterConfig = ((uint32_t)0x00000001U); /*!< Store in Rx FIFO 0 if filter matches */
sFilterConfig.FilterID1 = 0x444; // Filter ID1
sFilterConfig.FilterID2 = 0x555; // Filter ID2
/* Build Rx FIF0 Filter */
FilterElementW1 = ( (sFilterConfig.FilterType << 30U) | /* Build filter element */
(sFilterConfig.FilterConfig << 27U) |
(sFilterConfig.FilterID1 << 16U)|
sFilterConfig.FilterID2);
FilterAddress = (volatile uint32_t *)(SRAMCAN_BASE + (sFilterConfig.FilterIndex * SRAMCAN_FLS_SIZE)); /* Calculate filter address */
*FilterAddress = FilterElementW1; /* Write filter element to the message RAM */
}
void FDCAN_CalcultateRamBlockAddresses(void)
{
uint32_t SramCanInstanceBase = SRAMCAN_BASE;
uint32_t RAMcounter;
/* Standard filter list start address */
RAM.StandardFilterSA = SramCanInstanceBase + SRAMCAN_FLSSA;
/* Tx FIFO/queue start address */
RAM.TxFIFOQSA = SramCanInstanceBase + SRAMCAN_TFQSA;
/* Flush the allocated Message RAM area */
for (RAMcounter = SramCanInstanceBase; RAMcounter < (SramCanInstanceBase + SRAMCAN_SIZE); RAMcounter += 4U)
{
*(uint32_t *)(RAMcounter) = 0x00000000U;
}
}
void FDCAN1_Init(void)
{
/* Enable preipheral & kernal clock for FDCAN1 */
RCC -> APB1ENR2 |= RCC_APB1ENR2_FDCAN1EN;
RCC -> CCIPR1 |= RCC_CCIPR1_FDCANSEL_0;
/* Enter initialisation mode */
FDCAN1 -> CCCR &= ~ FDCAN_CCCR_INIT;
FDCAN1 -> CCCR |= FDCAN_CCCR_INIT;
while ((FDCAN1->CCCR & FDCAN_CCCR_INIT) == 0U); // wait for FDCAN1
FDCAN1 -> CCCR |= FDCAN_CCCR_CCE; // Enable configuration change
/* Configure FDCAN1 */
FDCAN1 -> CCCR &= ~ FDCAN_CCCR_CSR; // Stop clock request
FDCAN_CONFIG->CKDIV |= (0x0 << FDCAN_CKDIV_PDIV_Pos); // Set clock divider to 1
FDCAN1 -> CCCR &= ~ FDCAN_CCCR_DAR; // Enable autoRetransmission
FDCAN1 -> CCCR |= FDCAN_CCCR_TXP; // Enable transmitpause
FDCAN1 -> CCCR |= FDCAN_CCCR_PXHD; // ProtocolException = DISABLE;
FDCAN1 -> CCCR |= (FDCAN_CCCR_FDOE | FDCAN_CCCR_BRSE); // Enable Bit-rate switching & fast data operation
FDCAN1 -> CCCR |= FDCAN_CCCR_TEST; // Enable test mode
FDCAN1 -> TEST |= FDCAN_TEST_LBCK; // LOOPBACK mode
FDCAN1->NBTP = 0x1E003E0F; // Set Nominal bit timing
/* Configure FDCAN1 bit timings (assuming 500kbps) */
FDCAN1->DBTP = 0x00000433;
FDCAN1 -> TXBC &= ~ FDCAN_TXBC_TFQM; // TX FIFO operation mode
FDCAN1 -> XIDAM |= 0x00000001; // Extended ID mask
/* Configure Global Filter */
FDCAN1 -> RXGFC |= FDCAN_RXGFC_LSS_Msk; // List size
FDCAN1 -> RXGFC |= 0x00000020;
FDCAN1 -> RXGFC |= 0x00000008;
FDCAN1 -> RXGFC |= FDCAN_RXGFC_RRFE;
FDCAN1 -> RXGFC &= ~ FDCAN_RXGFC_RRFS_Pos;
/* Calculate Ram Block Addrresses For FDCAN */
FDCAN_CalcultateRamBlockAddresses();
}
void gpio_pins(void)
{
/* USER CODE BEGIN MX_GPIO_Init_2 */
RCC -> AHB2ENR1 |= RCC_AHB2ENR1_GPIODEN;
//PORT D CONFIGURATION
GPIOD -> MODER &= ~ (GPIO_MODER_MODE0 | GPIO_MODER_MODE1 | GPIO_MODER_MODE14);
GPIOD -> MODER |= (GPIO_MODER_MODE1_1 | GPIO_MODER_MODE0_1); /* < CAN_BUS: PD0-Rx, PD1-Tx > */
GPIOD->AFR[0] |= 0x00000099;
}
void SystemCoreClockConfigure(void)
{
/* Set Flash Latency To 4 & Enable Prefetch Buffer */
FLASH -> ACR |= FLASH_ACR_LATENCY_4WS;
while(!(FLASH -> ACR & FLASH_ACR_LATENCY_4WS));
FLASH -> ACR |= FLASH_ACR_PRFTEN;
/* Turn on VOS */
PWR -> VOSR |= PWR_VOSR_VOS;
while(!(PWR->VOSR & PWR_VOSR_VOSRDY))
{
//Wait
}
/* Turn on MSI Clock */
RCC -> CR |= RCC_CR_MSISON;
while(!(RCC -> CR & RCC_CR_MSISRDY));
/* Configure MSI Clock */
RCC -> ICSCR1 |= RCC_ICSCR1_MSIRGSEL;
RCC -> ICSCR1 |= RCC_ICSCR1_MSISRANGE_2;
RCC -> ICSCR2 |= RCC_ICSCR2_MSITRIM0 >> 0x00000005U;
//RCC -> ICSCR2 |= (16U << (RCC_ICSCR2_MSITRIM0_Pos - RCC_ICSCR2_MSITRIM0));
/* Configure PLL as System clock */
RCC -> PLL1CFGR |= RCC_PLL1CFGR_PLL1SRC_0;
RCC -> PLL1CFGR |= RCC_PLL1CFGR_PLL1M;
LL_RCC_PLL1_ConfigDomain_SYS(RCC_PLL1CFGR_PLL1SRC_0, 1, 80, 2);
RCC -> PLL1CFGR |= RCC_PLL1CFGR_PLL1REN;
RCC -> PLL1CFGR |= RCC_PLL1CFGR_PLL1QEN;
/* Turn on PLL */
RCC -> CR |= RCC_CR_PLL1ON;
/* Wait till PLL is ready */
while(!(RCC -> CR & RCC_CR_PLL1RDY));
/*AHB prescaler = 3 ---- Clock = 50MHz/2 */
RCC -> CFGR2 |= RCC_CFGR2_HPRE_3;
RCC -> CFGR1 |= (RCC_CFGR1_SW_1 | RCC_CFGR1_SW_0); // Select source clock as PLL1
/* Wait till System clock is ready */
while(!(RCC-> CFGR1 & RCC_CFGR1_SWS));
/* Ensure 1us transition state at intermediate medium speed clock */
for (__IO uint32_t i = (160 >> 1); i !=0; i--);
/* Configure APB prescalers */
RCC -> CFGR2 &= ~ RCC_CFGR2_HPRE;
RCC -> CFGR2 &= ~ RCC_CFGR2_PPRE1;
RCC -> CFGR2 &= ~ RCC_CFGR2_PPRE2;
RCC -> CFGR3 &= ~ RCC_CFGR3_PPRE3;
}
__STATIC_INLINE void LL_RCC_PLL1_ConfigDomain_SYS(uint32_t Source, uint32_t PLLM, uint32_t PLLN, uint32_t PLLR)
{
MODIFY_REG(RCC->PLL1CFGR, RCC_PLL1CFGR_PLL1SRC | RCC_PLL1CFGR_PLL1M, Source | \
((PLLM - 1UL) << RCC_PLL1CFGR_PLL1M_Pos));
MODIFY_REG(RCC->PLL1DIVR, RCC_PLL1DIVR_PLL1N | RCC_PLL1DIVR_PLL1R, ((PLLN - 1UL) << \
RCC_PLL1DIVR_PLL1N_Pos) | ((PLLR - 1UL) << \
RCC_PLL1DIVR_PLL1R_Pos));
}
感谢您的代码。我可以从随附的代码中知道“SRAMCAN_BASE”的值吗