Skip to main content
Graduate
April 17, 2024
Solved

STM32H750XBHX - CANFD Callback problem

  • April 17, 2024
  • 6 replies
  • 4406 views

Hey, I have a problem with the callback for FDCAN1. I am sending frames through ucandevices converter but the callback for FIFO0 is not called. The frames are definitely arriving, I added a test FreeRTOS and a task to receive and send frames to CAN1 and it worked very well, frames were received and sent back to the bus.
I have NVIC interrupts set up, I fiddled with the clock for CANFD and speeds, also with no effect.

Is anyone able to help me?
I am sending my project as an attachment

    This topic has been closed for replies.
    Best answer by sqwerize

    @mƎALLEm @Karl Yamashita 
    I seem to have enjoyed the normal functioning of the project too soon....
    The bridge communication works partially for me. I send frames from one UCCB converter with a baudrate of 500kB/s, the stm32 receives these frames on CAN1 and sends them on CAN2. I have a second UCCB converter that receives these frames correctly and I can see them. The problem arises when I want to send the frames the other way, that is, when I send the frames to CAN2 the callback is not called and the frames are not sent to CAN1 on the STM32 controller. In addition, when I want to configure filters in the MX_FDCAN2_Init method, all communication goes down and sending from CAN1 to CAN2 stops working and I am left with nothing....

    6 replies

    Graduate II
    April 18, 2024

     

    Maybe your sample point could be an issue?  Try these values which is at 87%

    KarlYamashita_0-1713404977482.png

     

    You've already defined your variables as global. When you call HAL_FDCAN_GetRxMessage, the values are save into the local variables. The local variables inside the callback will get destroyed when it returns from the callback. The global variables won't get updated.

    void HAL_FDCAN_RxFifo0MsgPendingCallback(FDCAN_HandleTypeDef *hfdcan)
    {
    	LED1_ON();
     if(hfdcan->Instance == FDCAN1)
     {
     // already defined as global
     //FDCAN_RxHeaderTypeDef RxHeader;
     //uint8_t RxData[8];
    
     // Pobierz ramkę
     if(HAL_FDCAN_GetRxMessage(hfdcan, FDCAN_RX_FIFO0, &RxHeader, RxData) == HAL_OK)
     {
    
     }
     }
    }

     

    You sure that the UCAN has the same baud rate of 100kbs?

     

    Technical Moderator
    April 18, 2024

    Hello,


    I added a test FreeRTOS and a task to receive and send frames to CAN1 and it worked very well, frames were received and sent back to the bus.

    I'm confused about this statement. You said that the callback is not called but you're receiving well the frames.

    Could you please clarify this point?

    Moreover, as I see from your clock configuration, FDCAN clock is provided by PLL1Q having the clock source HSI.

    It's not recommended to use HSI for CAN/FDCAN communication. Use HSE with an external crystal instead.

    PS: You are setting your bitrate at 100kb/s. Are you sure it's not 1Mb/s?

    SofLit_0-1713439149778.png

     

    Technical Moderator
    April 18, 2024

    Another question came to my mind: are you using STM32H750B-DK board?

    If yes, there is a discrepancy with your GPIOs settings: PB8/PB9 in CubeMx vs PH13/PH14 in the schematics.

    SofLit_0-1713439742373.png

    SofLit_0-1713439961006.png

    PS: FDCAN2 GPIOs are correct.

     

     

    sqwerizeAuthor
    Graduate
    April 18, 2024

    Hello, I am using the ART-PI development board, I am sending the output schematic and documentation. I'll be back from work in 2 hours and I'll still try to change the configuration as my colleague above wrote, currently I'm at a loss.... I need to make a bridge between CAN1 and CAN2, the FreeRTOS task will not be a good solution here to transmit frames in real time. As I mentioned, such code in RTOS task works fine and I can receive and send back to the bus frames.... :(

    @EDIT
    @mƎALLEm 
    The canbus communication works, I can receive and send frames on the can bus, but only through the RTOS task or through the while() loop in the main class. I have a problem with the callback I am creating. It is not called despite the NVIC interrupt setting :(
    I've been testing different speeds, ultimately I need to work on 500 kBit/s speed, because that's the bus I'll be plugging into in my BMW.

    My RTOS task (this example is working):

    void StartDefaultTask(void *argument)
    {
      /* USER CODE BEGIN 5 */
      FDCAN_RxHeaderTypeDef RxHeader;
      uint8_t RxData[8];
      FDCAN_TxHeaderTypeDef TxHeader;
      uint8_t TxData[8];
      HAL_StatusTypeDef rxStatus;
     
      /* Infinite loop */
      for(;;)
      {
        
        rxStatus = HAL_FDCAN_GetRxMessage(&hfdcan1, FDCAN_RX_FIFO0, &RxHeader, RxData);
     
        if(rxStatus == HAL_OK) {
          LED1_ON();
          printf("frame received: ID = 0x%X, DLC = %d, Data = ", RxHeader.Identifier, RxHeader.DataLength);
          for(int i = 0; i < 8; i++) {
            printf("0x%X ", RxData[i]);
        
            TxData[i] = RxData[i];
          }
          printf("\n");
     
          TxHeader.Identifier = RxHeader.Identifier; // Echo the same ID
          TxHeader.IdType = RxHeader.IdType;
          TxHeader.TxFrameType = FDCAN_DATA_FRAME;
          TxHeader.DataLength = RxHeader.DataLength;
          TxHeader.ErrorStateIndicator = FDCAN_ESI_ACTIVE;
          TxHeader.BitRateSwitch = FDCAN_BRS_OFF;
          TxHeader.FDFormat = FDCAN_CLASSIC_CAN;
          TxHeader.TxEventFifoControl = FDCAN_NO_TX_EVENTS;
          TxHeader.MessageMarker = 0;
     
     
          if (HAL_FDCAN_AddMessageToTxFifoQ(&hfdcan1, &TxHeader, TxData) != HAL_OK)
          {
            // Obsługa błędów transmisji
            printf("Błąd wysyłania ramki!\n");
          }
      
      LED1_OFF();
        }
     
        osDelay(10); // Czas na przetwarzanie innych zadań
      }
      /* USER CODE END 5 */
    }


    I'm using TJA1050 from this site:
    Transceiver CAN TJA1050 - Sklep msalamon

    sqwerizeAuthor
    Graduate
    April 18, 2024

    I come back to you with answers. I have switched the clock for FDCAN to HSE, it is set to 25MHz.
    I switched the prescaller and Time seg1, Time seg2 to as the colleague above wrote. This unfortunately had no effect. When debugging, HAL_FDCAN_ActivateNotification does not return errors. Sending to can works or receiving when I do it in the main while loop in the main() method.
    In the HAL_FDCAN_RxFifo0MsgPendingCallback method I set the LED to light up as a signal that it has been called, no other operations there for the time being, as it makes no sense. I am sending in the attachment once again my project. The speed is scaled to 100kBit/s. I have UCAN set to 100k, so the speeds agree, besides I can see the frames sent by the stm32 from the while loop on it.

    Technical Moderator
    April 18, 2024

    Hello,

    System clock is not yet set to HSE (25MHz) in your latest attached project. Still set to HSI.

    SofLit_0-1713454368462.png

    + You lost some user code from this latest version.

    But I would understand more the case. So, let's summarize:

    You are sending frames @100kb/s from a CAN node called "ucan" to FDCAN1 of your STM32H750 MCU.

    The callback is not called (using interrupt) but when you are in polling mode (FreeRTOS / without interrupt) you are well receiving messages.

    Could you please confirm?

    sqwerizeAuthor
    Graduate
    April 18, 2024

    @mƎALLEm  Problem solved!!! I don't know what I would have done without your help, in truth you have guided me to this solution.
    I found in another topic on the forum information to add in the file stm32h7xx_hal_msp.c
    HAL_NVIC_SetPriority(FDCAN1_IT1_IRQn, 5, 0);
    HAL_NVIC_EnableIRQ(FDCAN1_IT1_IRQn;)

    Now the callback receives frames and sends back to the bus without any problems.

    One more question, as I mentioned earlier.
    I want to build a bridge between CAN1 and CAN2, I understand that for CAN1 I define FIFO0 and for CAN2 I define FIFO1 and based on the callback I transfer data between them, however, one thing bothers me that I am not completely familiar with.... Clock configuration and prescaller for 500kB/s. Can you help me still in this thread with the correct configuration of Prescaller, Time seg 1 and Time seg 2? I am very much asking...

     

    void HAL_FDCAN_MspInit(FDCAN_HandleTypeDef* hfdcan)

    {

    GPIO_InitTypeDef GPIO_InitStruct = {0};

    RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0};

    if(hfdcan->Instance==FDCAN1)

    {

    /* USER CODE BEGIN FDCAN1_MspInit 0 */

     

    /* USER CODE END FDCAN1_MspInit 0 */

     

    /** Initializes the peripherals clock

    */

    PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_FDCAN;

    PeriphClkInitStruct.FdcanClockSelection = RCC_FDCANCLKSOURCE_HSE;

    if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK)

    {

    Error_Handler();

    }

     

    /* Peripheral clock enable */

    __HAL_RCC_FDCAN_CLK_ENABLE();

     

    __HAL_RCC_GPIOB_CLK_ENABLE();

    /**FDCAN1 GPIO Configuration

    PB9 ------> FDCAN1_TX

    PB8 ------> FDCAN1_RX

    */

    GPIO_InitStruct.Pin = GPIO_PIN_9|GPIO_PIN_8;

    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;

    GPIO_InitStruct.Pull = GPIO_NOPULL;

    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;

    GPIO_InitStruct.Alternate = GPIO_AF9_FDCAN1;

    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

     

    /* FDCAN1 interrupt Init */

    HAL_NVIC_SetPriority(FDCAN1_IT0_IRQn, 5, 0);

    HAL_NVIC_EnableIRQ(FDCAN1_IT0_IRQn);

    /* USER CODE BEGIN FDCAN1_MspInit 1 */

     

    HAL_NVIC_SetPriority(FDCAN1_IT1_IRQn, 5, 0);

    HAL_NVIC_EnableIRQ(FDCAN1_IT1_IRQn);

    /* USER CODE END FDCAN1_MspInit 1 */

    }

     

    }

    Graduate II
    April 18, 2024

    If i remember your clock was 24MHz so these are the settings for 500/kbs

    KarlYamashita_0-1713460293810.png

     

     

    sqwerizeAuthor
    Graduate
    April 18, 2024

    sqwerize_0-1713460954642.png

    sqwerize_1-1713460990371.pngsqwerize_2-1713461063532.png

    I changed the clock but I don't know if I did it right.... And should the Clock for FDCAN be set to HSE?

    sqwerizeAuthorAnswer
    Graduate
    April 18, 2024

    @mƎALLEm @Karl Yamashita 
    I seem to have enjoyed the normal functioning of the project too soon....
    The bridge communication works partially for me. I send frames from one UCCB converter with a baudrate of 500kB/s, the stm32 receives these frames on CAN1 and sends them on CAN2. I have a second UCCB converter that receives these frames correctly and I can see them. The problem arises when I want to send the frames the other way, that is, when I send the frames to CAN2 the callback is not called and the frames are not sent to CAN1 on the STM32 controller. In addition, when I want to configure filters in the MX_FDCAN2_Init method, all communication goes down and sending from CAN1 to CAN2 stops working and I am left with nothing....

    Graduate II
    April 19, 2024

    Offhand I don't know why you're not getting an interrupt on FDCAN2?

     

    But as for your bridging attempt. It's really called a gateway. Not sure what your end product is going to be?

     

    I've designed a ton of interfaces that act as a gateway for different make of vehicles. I can trick the head unit into thinking that the car is in reverse buy overriding the DRIVE parameter with a REVERSE parameter so that we can feed video into the display or change to PARK parameter to allow inputting navigation destination while driving. I can trick the Radio into thinking that the Sirius radio is playing and feed a Bluetooth audio into the head unit using the same audio input using a Bluetooth audio module. This was before head units had Bluetooth capabilities. So basically you intercept the CAN message, change certain parameters and then pass it through.

     

    The best practice is to do all your processing outside of the interrupt. You should actually make a ring buffer to hold several CAN messages to parse in your main while loop. In your main while loop you can check to see if you have a new message on either FDCAN1 or FDCAN2. You can then pass that message to the opposite FDCANx or modify the data and pass it through. 

     

    sqwerizeAuthor
    Graduate
    April 19, 2024

    @Karl Yamashita  Thanks for the suggestion, I was afraid to implement the "gateway" in the while loop as you mentioned, to avoid delays in transmitting frames. I read that the best practice is to use DMA for CAN, but STM32 doesn't have this functionality... so I decided to go with interrupts, though I'm concerned about the processor load. The project is intended to act as a gateway for activating the laser in BMW G30 lamps with matrix LED functionality. The LCI versions received two lenses with matrix diodes and a separate laser section that turns using a stepper motor in the lamps. My project works great on my laptop, on which I wrote a program that acts as a gateway and modifies certain frames and sends them back to the lamps. Additionally, I already have a ready solution for matrix lamps without a laser, which is already in use in several cars. However, for the lights with lasers, I needed a more powerful processor, and as you can see, I've been struggling with it for a few days now.

    So, you suggest to implement the "gateway" in the main loop? Additionally, my adapter needs to perform a few other tasks, and the best solution for this was FreeRTOS, as I needed to perform other background tasks like leveling the laser, sending turn signals based on a 12v signal on a wire, etc. You might ask why I need to do this, so here's the answer. BMW G30 versions from 2017 to 07/2020 do not support these lamps because the BDC is of an older generation; in the LCI version, they introduced the new BDC3, which supports these lamps.

    Here is adapter for standard matrix led headlights: https://www.tiktok.com/@sqwerize/video/7343750983870172449?is_from_webapp=1&sender_device=pc&web_id=7325035726109853217

    Here is laser:
    https://www.tiktok.com/@sqwerize/video/7358763883491790113?is_from_webapp=1&sender_device=pc&web_id=7325035726109853217