embeddedstm32microcontrollercan-buslow-level

STM32 FDCAN Communication: How do you set up FDCAN using low level programming on STM32U5?


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 */
}

Solution

  • Update: I have managed to set up the FDCAN peripheral on the STM32U575 microcontroller entirely in low level embedded c. It turns out that this microcontroller does not provide a mailbox or any registers which can be used to write your configuration and messages to the RAM. You have to calculate every address that you write to! This FDCAN document lists some information about some of the RAM address calculations. I will post the code below for other people that run into the same issue in the future.

        #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));
    }