你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【stm32U3测评】使用FDCAN进行IAP升级----【2】FDCAN的Classic模式通信

[复制链接]
短笛君 发布时间:2026-6-21 22:33

前言

我们使用前一章节Bootloader中 APP工程 来生成FDCAN的初始化代码 本次先使用CAN2.0即FDCAN中的Classic模式

关于FDCAN和CAN对比可以参考一下表格

特性 经典CAN (Classic CAN) FDCAN (CAN FD)
最大数据传输速率 最高1M 数据段最高可达8 Mbps 甚至更高
单帧最大数据长度 8 字节 64 字节
速率可变 不支持,全帧固定速率 支持 ,仲裁段低速(保证兼容),数据段高速
错误校验 (CRC) 基础,15位 CRC校验 增强,最高21位 CRC校验,可靠性更高
兼容性 无法解析FDCAN帧 向下兼容 经典CAN,可配置为传统模式与其通信
典型应用场景 低速控制指令(如车窗、简单传感器) 高速大数据传输(如OTA升级自动驾驶数据流

使用FDCAN可以实现更快速的IAP过程,但是配置更加复杂 所以先使用CAN通信实现基本功能 然后在CAN的基础之上升级为FDCAN 整体框架逻辑是不变的 只有接收数据的部分会做一点相应改动

工程可以直接复制先前APP部分的工程 然后再初始化CAN部分

CAN部分外设配置如下

void MX_FDCAN1_Init(void)
{

  /* USER CODE BEGIN FDCAN1_Init 0 */

  /* USER CODE END FDCAN1_Init 0 */

  /* USER CODE BEGIN FDCAN1_Init 1 */

  /* USER CODE END FDCAN1_Init 1 */
  hfdcan1.Instance = FDCAN1;
  hfdcan1.Init.ClockDivider = FDCAN_CLOCK_DIV1;
  hfdcan1.Init.FrameFormat = FDCAN_FRAME_CLASSIC;
  hfdcan1.Init.Mode = FDCAN_MODE_NORMAL;
  hfdcan1.Init.AutoRetransmission = ENABLE;
  hfdcan1.Init.TransmitPause = DISABLE;
  hfdcan1.Init.ProtocolException = ENABLE;
  hfdcan1.Init.NominalPrescaler = 4;
  hfdcan1.Init.NominalSyncJumpWidth = 4;
  hfdcan1.Init.NominalTimeSeg1 = 19;
  hfdcan1.Init.NominalTimeSeg2 = 4;
  hfdcan1.Init.DataPrescaler = 4;
  hfdcan1.Init.DataSyncJumpWidth = 4;
  hfdcan1.Init.DataTimeSeg1 = 19;
  hfdcan1.Init.DataTimeSeg2 = 4;
  hfdcan1.Init.StdFiltersNbr = 1;
  hfdcan1.Init.ExtFiltersNbr = 0;
  hfdcan1.Init.TxFifoQueueMode = FDCAN_TX_FIFO_OPERATION;
  if (HAL_FDCAN_Init(&hfdcan1) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN FDCAN1_Init 2 */

  /* USER CODE END FDCAN1_Init 2 */

}

void HAL_FDCAN_MspInit(FDCAN_HandleTypeDef* fdcanHandle)
{

  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(fdcanHandle->Instance==FDCAN1)
  {
  /* USER CODE BEGIN FDCAN1_MspInit 0 */

  /* USER CODE END FDCAN1_MspInit 0 */
    /* FDCAN1 clock enable */
    __HAL_RCC_FDCAN_CLK_ENABLE();

    __HAL_RCC_GPIOB_CLK_ENABLE();
    /**FDCAN1 GPIO Configuration
    PB8     ------> FDCAN1_RX
    PB9     ------> FDCAN1_TX
    */
    GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_9;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF9_FDCAN1;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

    /* FDCAN1 interrupt Init */
    HAL_NVIC_SetPriority(FDCAN1_IT0_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(FDCAN1_IT0_IRQn);
  /* USER CODE BEGIN FDCAN1_MspInit 1 */

  /* USER CODE END FDCAN1_MspInit 1 */
  }
}

Nucleo板子CAN引脚配置为PB8和PB9 除此之外还要配置STBY引脚拉低让收发器退出休眠模式

除了外设之外 滤波器也需要配置 不然会出现无法收到消息的情况

HAL_StatusTypeDef BSP_CAN_Init(void)
{
  FDCAN_FilterTypeDef sFilterConfig = {0};

  MX_FDCAN1_Init();

  /* 接收过滤器设置为接收全部标准帧,由 Bootloader/APP 上层按 ID 再过滤。 */
  sFilterConfig.IdType = FDCAN_STANDARD_ID;
  sFilterConfig.FilterIndex = 0;
  sFilterConfig.FilterType = FDCAN_FILTER_MASK;
  sFilterConfig.FilterConfig = FDCAN_FILTER_TO_RXFIFO0;
  sFilterConfig.FilterID1 = 0x000U;
  sFilterConfig.FilterID2 = 0x000U;
  if (HAL_FDCAN_ConfigFilter(&hfdcan1, &sFilterConfig) != HAL_OK)
  {
    return HAL_ERROR;
  }

  if (HAL_FDCAN_ConfigGlobalFilter(&hfdcan1,
                                   FDCAN_ACCEPT_IN_RX_FIFO0,
                                   FDCAN_REJECT,
                                   FDCAN_REJECT_REMOTE,
                                   FDCAN_REJECT_REMOTE) != HAL_OK)
  {
    return HAL_ERROR;
  }

  if (HAL_FDCAN_ActivateNotification(&hfdcan1,
                                     FDCAN_IT_RX_FIFO0_NEW_MESSAGE |
                                     FDCAN_IT_RX_FIFO0_FULL |
                                     FDCAN_IT_RX_FIFO0_MESSAGE_LOST |
                                     FDCAN_IT_ERROR_WARNING |
                                     FDCAN_IT_ERROR_PASSIVE |
                                     FDCAN_IT_BUS_OFF |
                                     FDCAN_IT_ARB_PROTOCOL_ERROR |
                                     FDCAN_IT_DATA_PROTOCOL_ERROR,
                                     0U) != HAL_OK)
  {
    return HAL_ERROR;
  }

  if (HAL_FDCAN_Start(&hfdcan1) != HAL_OK)
  {
    return HAL_ERROR;
  }

  printf("[CAN] Classic CAN 1Mbps, RX ID=0x%03lX, TX ID=0x%03lX\r\n",
         (unsigned long)IAP_CAN_HOST_TO_BOOT_ID,
         (unsigned long)IAP_CAN_BOOT_TO_HOST_ID);
  return HAL_OK;
}

完成以上部分 就可以在main中添加滤波器初始化代码 然后打开FDCAN外设

为了方便使用库函数 这里我们对FDCAN发送函数进行一次封装

HAL_StatusTypeDef BSP_CAN_Send(uint32_t std_id, const uint8_t *data, uint8_t len)
{
  FDCAN_TxHeaderTypeDef txHeader = {0};
  uint8_t txData[8] = {0};

  if ((std_id > 0x7FFU) || (len > 8U))
  {
    return HAL_ERROR;
  }

  if ((len > 0U) && (data == NULL))
  {
    return HAL_ERROR;
  }

  if (HAL_FDCAN_GetTxFifoFreeLevel(&hfdcan1) == 0U)
  {
    return HAL_BUSY;
  }

  for (uint8_t i = 0U; i < len; i++)
  {
    txData[i] = data[i];
  }

  txHeader.Identifier = std_id;
  txHeader.IdType = FDCAN_STANDARD_ID;
  txHeader.TxFrameType = FDCAN_DATA_FRAME;
  txHeader.DataLength = FDCAN_LenToDlc(len);
  txHeader.ErrorStateIndicator = FDCAN_ESI_ACTIVE;
  txHeader.BitRateSwitch = FDCAN_BRS_OFF;
  txHeader.FDFormat = FDCAN_CLASSIC_CAN;
  txHeader.TxEventFifoControl = FDCAN_NO_TX_EVENTS;
  txHeader.MessageMarker = 0U;

  return HAL_FDCAN_AddMessageToTxFifoQ(&hfdcan1, &txHeader, txData);
}

CAN不同于串口 收发是需要ACK帧来确认消息是否到达的 否则会报总线错误 所以在使用前我们需要接好CAN分析仪来调试

  if ((HAL_GetTick() - LedLastTick) >= 500U)
  {
    LedLastTick = HAL_GetTick();
    BSP_LED_Toggle(LED_RED); /* LD2: PE14 */
        uint8_t data[8] = {0};
        BSP_CAN_Send(0x200,data,8);
  }

接下来只需要在MAIN中添加循环发送代码即可正常通信

image.png

完成这部分 就可以开始我们IAP的升级流程设计了

收藏 评论0 发布时间:2026-6-21 22:33

举报

0个回答

所属标签

相似分享

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版