ST意法半导体
直播中

kmno4

12年用户 932经验值
私信 关注
[问答]

STM32F7初始化CAN问题求解

我使用 STM32F767ZI 开展一个项目,该项目使用 3 条 CAN 总线并要求它们在特定时间打开和关闭以节省电量。
但是,由 STM32CubeFW_F7 V1.16.1(发布时的最新版本)生成的代码会生成有问题(甚至完全错误)的管理 RCC APB 时钟使能位的代码。
让我们看一下 CubeIDE 生成的 can.c(为了节省帖子的篇幅,代码略有删节,附上完整文件):        
  • static uint32_t HAL_RCC_CAN1_CLK_ENABLED=0;
  • static uint32_t HAL_RCC_CAN3_CLK_ENABLED=0;
  • static uint32_t HAL_RCC_CAN2_CLK_ENABLED=0;
  • void HAL_CAN_MspInit(CAN_HandleTypeDef* canHandle)
  • {
  •   GPIO_InitTypeDef GPIO_InitStruct = {0};
  •   if(canHandle->Instance==CAN1)
  •   {
  •         /* CAN1 clock enable */
  •         HAL_RCC_CAN1_CLK_ENABLED++;
  •         if(HAL_RCC_CAN1_CLK_ENABLED==1){
  •           __HAL_RCC_CAN1_CLK_ENABLE();
  •         }
  •         /* GPIO init here */
  •   }
  •   else if(canHandle->Instance==CAN2)
  •   {
  •         /* CAN2 clock enable */
  •         HAL_RCC_CAN3_CLK_ENABLED++;
  •         if(HAL_RCC_CAN3_CLK_ENABLED==1){
  •           __HAL_RCC_CAN3_CLK_ENABLE();
  •         }
  •         HAL_RCC_CAN2_CLK_ENABLED++;
  •         if(HAL_RCC_CAN2_CLK_ENABLED==1){
  •           __HAL_RCC_CAN2_CLK_ENABLE();
  •         }
  •         HAL_RCC_CAN1_CLK_ENABLED++;
  •         if(HAL_RCC_CAN1_CLK_ENABLED==1){
  •           __HAL_RCC_CAN1_CLK_ENABLE();
  •         }
  •         /* GPIO init here */
  •   }
  •   else if(canHandle->Instance==CAN3)
  •   {
  •         /* CAN3 clock enable */
  •         HAL_RCC_CAN3_CLK_ENABLED++;
  •         if(HAL_RCC_CAN3_CLK_ENABLED==1){
  •           __HAL_RCC_CAN3_CLK_ENABLE();
  •         }
  •         HAL_RCC_CAN2_CLK_ENABLED++;
  •         if(HAL_RCC_CAN2_CLK_ENABLED==1){
  •           __HAL_RCC_CAN2_CLK_ENABLE();
  •         }
  •         HAL_RCC_CAN1_CLK_ENABLED++;
  •         if(HAL_RCC_CAN1_CLK_ENABLED==1){
  •           __HAL_RCC_CAN1_CLK_ENABLE();
  •         }
  •         /* GPIO init here */
  •   }
  • }
  • void HAL_CAN_MspDeInit(CAN_HandleTypeDef* canHandle)
  • {
  •   if(canHandle->Instance==CAN1)
  •   {
  •         /* Peripheral clock disable */
  •         __HAL_RCC_CAN1_CLK_DISABLE();
  •         /* GPIO deinit here */
  •   }
  •   else if(canHandle->Instance==CAN2)
  •   {
  •         /* Peripheral clock disable */
  •         HAL_RCC_CAN3_CLK_ENABLED--;
  •         if(HAL_RCC_CAN3_CLK_ENABLED==0){
  •           __HAL_RCC_CAN3_CLK_DISABLE();
  •         }
  •         HAL_RCC_CAN2_CLK_ENABLED--;
  •         if(HAL_RCC_CAN2_CLK_ENABLED==0){
  •           __HAL_RCC_CAN2_CLK_DISABLE();
  •         }
  •         HAL_RCC_CAN1_CLK_ENABLED--;
  •         if(HAL_RCC_CAN1_CLK_ENABLED==0){
  •           __HAL_RCC_CAN1_CLK_DISABLE();
  •         }
  •         /* GPIO deinit here */
  •   }
  •   else if(canHandle->Instance==CAN3)
  •   {
  •         /* Peripheral clock disable */
  •         HAL_RCC_CAN3_CLK_ENABLED--;
  •         if(HAL_RCC_CAN3_CLK_ENABLED==0){
  •           __HAL_RCC_CAN3_CLK_DISABLE();
  •         }
  •         HAL_RCC_CAN2_CLK_ENABLED--;
  •         if(HAL_RCC_CAN2_CLK_ENABLED==0){
  •           __HAL_RCC_CAN2_CLK_DISABLE();
  •         }
  •         HAL_RCC_CAN1_CLK_ENABLED--;
  •         if(HAL_RCC_CAN1_CLK_ENABLED==0){
  •           __HAL_RCC_CAN1_CLK_DISABLE();
  •         }
  •         /* GPIO deinit here */
  •   }
  • }
此代码使用 HAL_RCC_CANx_CLK_ENABLED 计数器来决定是否应启用时钟。
问题一:CAN1初始化时,计数器加1,只有值为1时才使能时钟。在去初始化时,时钟无条件关闭,但计数器不减。如果我再次尝试初始化 CAN1,计数器值变为 2,时钟保持禁用状态。
问题 2:为什么 CAN 2 的初始化会启用 CAN3 的时钟,反之亦然,CAN3 的初始化会启用 CAN1 和 CAN2 的时钟?我知道 CAN2 是一个从外设,它与 CAN1 共享部分功能,因此当 CAN2 初始化时,它必须启用 CAN1 的时钟。但是,根据参考手册,CAN3 是一个 Master,可以独立于 CAN1 和 CAN2 运行。
问题 3
  • void MX_CAN3_Init(void)
  • {
  •   /* USER CODE BEGIN CAN3_Init 0 */
  •   /* USER CODE END CAN3_Init 0 */
  •   /* USER CODE BEGIN CAN3_Init 1 */
  •   /* USER CODE END CAN3_Init 1 */
  •   hcan3.Instance = CAN3;
  •   hcan3.Init.Prescaler = 16;
  •   hcan3.Init.Mode = CAN_MODE_NORMAL;
  •   hcan3.Init.SyncJumpWidth = CAN_SJW_1TQ;
  •   hcan3.Init.TimeSeg1 = CAN_BS1_1TQ;
  •   hcan3.Init.TimeSeg2 = CAN_BS2_1TQ;
  •   hcan3.Init.TimeTriggeredMode = DISABLE;
  •   hcan3.Init.AutoBusOff = DISABLE;
  •   hcan3.Init.AutoWakeUp = DISABLE;
  •   hcan3.Init.AutoRetransmission = DISABLE;
  •   hcan3.Init.ReceiveFifoLocked = DISABLE;
  •   hcan3.Init.TransmitFifoPriority = DISABLE;
  •   if (HAL_CAN_Init(&hcan3) != HAL_OK)
  •   {
  •         Error_Handler();
  •   }
  •   /* USER CODE BEGIN CAN3_Init 2 */
  •   /* USER CODE END CAN3_Init 2 */
  • }
HAL_CAN_MspInit 每次都从 MX_CANx_Init 调用,如果总线保持显性状态超过 10 毫秒,这可能会失败(如果 CAN 低电平与 GND 短路,则可能由于安装错误而发生)。合乎逻辑的反应是稍后尝试重新初始化它,希望异常情况得到解决。但是,如果尝试 10 次才能成功初始化 CAN,则计数器将等于 10。现在,如果我取消初始化 CAN,时钟将不会被禁用。如何避免这种情况?







回帖(1)

李天竹

2022-12-13 11:46:58
- 要使用 CAN1:应仅启用 CAN 1 时钟。
- 要使用 CAN2:应启用 CAN 1 和 CAN2 时钟。
- 要使用 CAN3:应仅启用 CAN 3 时钟。CAN3 独立于 CAN1 和 CAN2。
这是 CubeMx 代码生成的问题。
举报

更多回帖

发帖
×
20
完善资料,
赚取积分