stm32duino / Arduino_Core_STM32

STM32 core support for Arduino
https://github.com/stm32duino/Arduino_Core_STM32/wiki
Other
2.81k stars 966 forks source link

Possible bug with CANFD on STM32G0B1xx #2531

Closed 0x0fe closed 2 weeks ago

0x0fe commented 2 weeks ago

So, while testing the CANFD interfaces of STM32G0B1CB and CC on this core i found a rather strange bug, i am not sure what cause this : When initializing the CANFD interfaces, 2 interfaces in the case of this variant, for some reason the HAL_FDCAN_MspInit function is only called for the first instance, but it should be called for each instance, otherwise the GPIOs are not initialized correctly (at the very least), the second instance won't work at all.

Below is my test code, which simply set the two CANFD ports up for a local test, port 1 to port 2 and port2 to port1 etc. As you can see, in HAL_FDCAN_MspInit i had to disable the condition on the CANFD2 init so that it is executed at the first call (when CANFD1 is initialized) because HAL_FDCAN_MspInit will never be called again when CANFD2 is initialized, despite HAL_FDCAN_Start(phfdcan2) is correctly called in my code.

As a side note, could you please clarify what is the best practice to override the default clock init from the sketch because i noticed the default clock init from variants sets the system clock to 48M from the HSI, not optimal when we have an HSE and want to run at max speed (64M for the G0B1). Thanks.

#include <Arduino.h>
#include "stm32g0xx_hal.h"
#include "stm32g0xx_hal_fdcan.h"

#define CAN1_VCC  PB10
#define CAN1_TX   PA12 
#define CAN1_RX   PA11
#define CAN1_MODE PC7
#define CAN2_VCC  PB12
#define CAN2_TX   PB1
#define CAN2_RX   PB0
#define CAN2_MODE PB15
#define RX5       PD2   // DBG RX
#define TX5       PD3   // DBG TX
#define LED1      PA6   // LED blue
#define LED2      PA7   // LED purple

FDCAN_HandleTypeDef *phfdcan1;
FDCAN_HandleTypeDef *phfdcan2;
FDCAN_TxHeaderTypeDef TxHeader;
FDCAN_RxHeaderTypeDef RxHeader;
uint8_t TxData[8];
uint8_t RxData[8];
static uint32_t HAL_RCC_FDCAN_CLK_ENABLED=0; 

// void HAL_FDCAN_RxFifo0Callback(FDCAN_HandleTypeDef *hfdcan, uint32_t RxFifo0ITs) {
//     if ((RxFifo0ITs & FDCAN_IT_RX_FIFO0_NEW_MESSAGE) != RESET) {
//         // Retrieve Rx messages from RX FIFO0
//         if (HAL_FDCAN_GetRxMessage(hfdcan, FDCAN_RX_FIFO0, &RxHeader, RxData) == HAL_OK) {
//             Serial.print("Received message ID: ");
//             Serial.println(RxHeader.Identifier, HEX);
//             Serial.print("Data: ");
//             printHexData(RxData, RxHeader.DataLength);
//         } else {
//             error_handler_();
//         }
//     }
// }

void error_handler_(void) {
  Serial.println("Error");
}

void fdcan1Init() {

  phfdcan1 = new FDCAN_HandleTypeDef;
  Serial.println("FDCAN1 init");
  digitalWrite(CAN1_MODE, LOW);

  phfdcan1->Instance = FDCAN1;
  phfdcan1->Init.ClockDivider = FDCAN_CLOCK_DIV1;
  phfdcan1->Init.FrameFormat = FDCAN_FRAME_FD_BRS;
  phfdcan1->Init.Mode = FDCAN_MODE_NORMAL;
  phfdcan1->Init.AutoRetransmission = ENABLE;
  phfdcan1->Init.TransmitPause = ENABLE;
  phfdcan1->Init.ProtocolException = DISABLE;
  phfdcan1->Init.NominalPrescaler = 1;
  phfdcan1->Init.NominalSyncJumpWidth = 16;
  phfdcan1->Init.NominalTimeSeg1 = 63;
  phfdcan1->Init.NominalTimeSeg2 = 16;
  phfdcan1->Init.DataPrescaler = 1;
  phfdcan1->Init.DataSyncJumpWidth = 4;
  phfdcan1->Init.DataTimeSeg1 = 5;
  phfdcan1->Init.DataTimeSeg2 = 4;
  phfdcan1->Init.StdFiltersNbr = 0;
  phfdcan1->Init.ExtFiltersNbr = 0;
  phfdcan1->Init.TxFifoQueueMode = FDCAN_TX_FIFO_OPERATION;

  if (HAL_FDCAN_Init(phfdcan1) != HAL_OK) {
    error_handler_();
  }

  FDCAN_FilterTypeDef sFilterConfig;

  sFilterConfig.IdType = FDCAN_STANDARD_ID;
  sFilterConfig.FilterIndex = 0;
  sFilterConfig.FilterType = FDCAN_FILTER_MASK;
  sFilterConfig.FilterConfig = FDCAN_FILTER_TO_RXFIFO0;
  sFilterConfig.FilterID1 = 0x000; 
  sFilterConfig.FilterID2 = 0x000;

  // sFilterConfig.IdType = FDCAN_STANDARD_ID;
  // sFilterConfig.FilterIndex = 0;
  // sFilterConfig.FilterType = FDCAN_FILTER_MASK;
  // sFilterConfig.FilterConfig = FDCAN_FILTER_TO_RXFIFO0;
  // sFilterConfig.FilterID1 = 0x321;
  // sFilterConfig.FilterID2 = 0x7FF;

  // if (HAL_FDCAN_ConfigFilter(phfdcan1, &sFilterConfig) != HAL_OK) {
  //   error_handler_();
  // }

  // if (HAL_FDCAN_ConfigGlobalFilter(phfdcan1, FDCAN_REJECT, FDCAN_REJECT, FDCAN_FILTER_REMOTE, FDCAN_FILTER_REMOTE) != HAL_OK)
  // {
  //   Error_Handler();
  // }

  if (HAL_FDCAN_Start(phfdcan1) != HAL_OK) {
    error_handler_();
  }

  if (HAL_FDCAN_ActivateNotification(phfdcan1, FDCAN_IT_RX_FIFO0_NEW_MESSAGE, 0) != HAL_OK) {
    error_handler_();
  }
}

void fdcan2Init() {

  digitalWrite(CAN2_MODE, LOW);
  Serial.println("FDCAN2 init");
  phfdcan2 = new FDCAN_HandleTypeDef;

  // phfdcan2->Instance = FDCAN2;
  // phfdcan2->Init.FrameFormat = FDCAN_FRAME_FD_NO_BRS;
  // phfdcan2->Init.Mode = FDCAN_MODE_NORMAL;
  // phfdcan2->Init.AutoRetransmission = DISABLE;
  // phfdcan2->Init.TransmitPause = DISABLE;
  // phfdcan2->Init.ProtocolException = DISABLE;

  // phfdcan2->Init.NominalPrescaler = 8;
  // phfdcan2->Init.NominalSyncJumpWidth = 4;
  // phfdcan2->Init.NominalTimeSeg1 = 11;
  // phfdcan2->Init.NominalTimeSeg2 = 4;

  // phfdcan2->Init.DataPrescaler = 2;
  // phfdcan2->Init.DataSyncJumpWidth = 1;
  // phfdcan2->Init.DataTimeSeg1 = 15;
  // phfdcan2->Init.DataTimeSeg2 = 4;

  phfdcan2->Instance = FDCAN2;
  phfdcan2->Init.ClockDivider = FDCAN_CLOCK_DIV1;
  phfdcan2->Init.FrameFormat = FDCAN_FRAME_FD_BRS;
  phfdcan2->Init.Mode = FDCAN_MODE_NORMAL;
  phfdcan2->Init.AutoRetransmission = ENABLE;
  phfdcan2->Init.TransmitPause = ENABLE;
  phfdcan2->Init.ProtocolException = DISABLE;
  phfdcan2->Init.NominalPrescaler = 1;
  phfdcan2->Init.NominalSyncJumpWidth = 16;
  phfdcan2->Init.NominalTimeSeg1 = 63;
  phfdcan2->Init.NominalTimeSeg2 = 16;
  phfdcan2->Init.DataPrescaler = 1;
  phfdcan2->Init.DataSyncJumpWidth = 4;
  phfdcan2->Init.DataTimeSeg1 = 5;
  phfdcan2->Init.DataTimeSeg2 = 4;
  phfdcan2->Init.StdFiltersNbr = 0;
  phfdcan2->Init.ExtFiltersNbr = 0;
  phfdcan2->Init.TxFifoQueueMode = FDCAN_TX_FIFO_OPERATION;

  if (HAL_FDCAN_Init(phfdcan2) != HAL_OK) {
    error_handler_();
  }

  FDCAN_FilterTypeDef sFilterConfig;

  sFilterConfig.IdType = FDCAN_STANDARD_ID;
  sFilterConfig.FilterIndex = 0;
  sFilterConfig.FilterType = FDCAN_FILTER_MASK;
  sFilterConfig.FilterConfig = FDCAN_FILTER_TO_RXFIFO0;
  sFilterConfig.FilterID1 = 0x000;
  sFilterConfig.FilterID2 = 0x000;

  // sFilterConfig.IdType = FDCAN_STANDARD_ID;
  // sFilterConfig.FilterIndex = 0;
  // sFilterConfig.FilterType = FDCAN_FILTER_MASK;
  // sFilterConfig.FilterConfig = FDCAN_FILTER_TO_RXFIFO0;
  // sFilterConfig.FilterID1 = 0x321;
  // sFilterConfig.FilterID2 = 0x7FF;

  // if (HAL_FDCAN_ConfigFilter(phfdcan2, &sFilterConfig) != HAL_OK) {
  //   error_handler_();
  // }

  // if (HAL_FDCAN_ConfigGlobalFilter(phfdcan2, FDCAN_REJECT, FDCAN_REJECT, FDCAN_FILTER_REMOTE, FDCAN_FILTER_REMOTE) != HAL_OK)
  // {
  //   Error_Handler();
  // }

  if (HAL_FDCAN_Start(phfdcan2) != HAL_OK) {
    error_handler_();
  }
}

void checkCANErrors(FDCAN_HandleTypeDef* phfdcan) {

    FDCAN_ProtocolStatusTypeDef protocolStatus;
    HAL_FDCAN_GetProtocolStatus(phfdcan, &protocolStatus);

    Serial.print("Code: ");
    Serial.print(protocolStatus.LastErrorCode);  // Last Error Code (LEC)

    Serial.print("  Protocol: ");
    if (protocolStatus.ErrorPassive) {
        Serial.print("Error Passive");
    } else {
        Serial.print("Error Active");
    }

    Serial.print("  Bus Off: ");
    if (protocolStatus.BusOff) {
        Serial.print("Yes");
    } else {
        Serial.print("No");
    }

    Serial.print("  Warning Status: ");
    if (protocolStatus.Warning) {
        Serial.println("Warning");
    } else {
        Serial.println("Normal");
    }
}

void printHexData(const uint8_t *data, size_t length) {
  for (size_t i = 0; i < length; ++i) {
    if (data[i] < 0x10) { Serial.print("0"); }
    Serial.print(data[i], HEX);
  }
  Serial.println();
}

void HAL_FDCAN_MspInit(FDCAN_HandleTypeDef* hfdcan){

  GPIO_InitTypeDef GPIO_InitStruct = {0};
  RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
  if(hfdcan->Instance==FDCAN1)
  {
    Serial.println("MspInit FDCAN1");
    PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_FDCAN;
    PeriphClkInit.FdcanClockSelection = RCC_FDCANCLKSOURCE_PCLK1;

    if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
    {
      Error_Handler();
    }

    HAL_RCC_FDCAN_CLK_ENABLED++;
    if(HAL_RCC_FDCAN_CLK_ENABLED==1){
      __HAL_RCC_FDCAN_CLK_ENABLE();
    }

    __HAL_RCC_GPIOA_CLK_ENABLE();
    /**FDCAN1 GPIO Configuration
    PA11 [PA9]     ------> FDCAN1_RX
    PA12 [PA10]     ------> FDCAN1_TX
    */
    GPIO_InitStruct.Pin = GPIO_PIN_11|GPIO_PIN_12;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    GPIO_InitStruct.Alternate = GPIO_AF3_FDCAN1;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
  }
  //else if(hfdcan->Instance==FDCAN2)
  {
    Serial.println("MspInit FDCAN2");
    PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_FDCAN;
    PeriphClkInit.FdcanClockSelection = RCC_FDCANCLKSOURCE_PCLK1;

    if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
    {
      Error_Handler();
    }

    HAL_RCC_FDCAN_CLK_ENABLED++;
    if(HAL_RCC_FDCAN_CLK_ENABLED==1){
      __HAL_RCC_FDCAN_CLK_ENABLE();
    }

    __HAL_RCC_GPIOB_CLK_ENABLE();
    /**FDCAN2 GPIO Configuration
    PB0     ------> FDCAN2_RX
    PB1     ------> FDCAN2_TX
    */
    GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    GPIO_InitStruct.Alternate = GPIO_AF3_FDCAN2;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
  }
}

void setup() {

  Serial.setTx(TX5);
  Serial.setRx(RX5);
  Serial.begin(115200);

  delay(2000);

  pinMode(CAN1_MODE, OUTPUT);
  pinMode(CAN2_MODE, OUTPUT);

  pinMode(CAN1_VCC, OUTPUT);
  pinMode(CAN2_VCC, OUTPUT);

  digitalWrite(CAN1_VCC, HIGH);
  digitalWrite(CAN2_VCC, HIGH);

  pinMode(LED1, OUTPUT);
  pinMode(LED2, OUTPUT);

  fdcan1Init();
  fdcan2Init();
}

void loop() {
  // Set up transmission message
  // TxHeader.Identifier = 0x123;
  // 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_FRAME_FD_NO_BRS;
  // TxHeader.TxEventFifoControl = FDCAN_NO_TX_EVENTS;
  // TxHeader.MessageMarker = 0;

  TxHeader.Identifier = 0x321;
  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_NO_TX_EVENTS;
  TxHeader.MessageMarker = 0;

  TxData[0] = 0x01; TxData[1] = 0x02; TxData[2] = 0x03; TxData[3] = 0x04;
  TxData[4] = 0x05; TxData[5] = 0x06; TxData[6] = 0x07; TxData[7] = 0x08;

  if (HAL_FDCAN_AddMessageToTxFifoQ(phfdcan1, &TxHeader, TxData) != HAL_OK) {
    error_handler_();
  } else {
    Serial.println("> FDCAN1 TX 0102030405060708");
  }

  //while ((phfdcan1->Instance->IR & FDCAN_IR_TFE) != FDCAN_IR_TFE) {} //wait fifo empty 
  //phfdcan1->Instance->IR &= FDCAN_IR_TFE; //clear complete flag

  if (HAL_FDCAN_GetRxMessage(phfdcan2, FDCAN_RX_FIFO0, &RxHeader, RxData) == HAL_OK) {
    Serial.print("< FDCAN2 RX ");
    printHexData(RxData, 8);
  } 
  else checkCANErrors(phfdcan2);

  delay(10);

  if (HAL_FDCAN_AddMessageToTxFifoQ(phfdcan2, &TxHeader, TxData) != HAL_OK) {
    error_handler_();
  } else {
    Serial.println("> FDCAN2 TX 0102030405060708");
  }

  if (HAL_FDCAN_GetRxMessage(phfdcan1, FDCAN_RX_FIFO0, &RxHeader, RxData) == HAL_OK) {
    Serial.print("< FDCAN1 RX ");
    printHexData(RxData, 8);
  } 
  else checkCANErrors(phfdcan1);

  delay(1000);
}
fpistm commented 2 weeks ago

Hi @0x0fe This issue is not related STM32 core as it is purely HAL usage. You should report to the HAL repository. About the clock config, it is described in the Wiki: https://github.com/stm32duino/Arduino_Core_STM32/wiki/Custom-definitions#systemclock_config