STM32
直播中

李鑫

7年用户 1340经验值
私信 关注
[问答]

求助,使用STM32cube生成的HAL库CAN初始化函数HAL_CAN_Init的疑问求解

CAN初始化函数  HAL_CAN_Init(CAN_HandleTypeDef* hcan)  的步骤大致如下:
退出睡眠模式;
请求进入初始化模式,并等待初始化确认标志INAK置位;
INAK标志位置位后进行初始化配置;
然后请求退出初始化模式,并等待确认初始化模式退出;

在HAL库的CAN初始化函数中,上述红色字体部分代码如下:
HAL_StatusTypeDef HAL_CAN_Init(CAN_HandleTypeDef* hcan)
{
    。
    。
    。
    。
    。
    。

    /* Request leave initialisation */
    CLEAR_BIT(hcan->Instance->MCR, CAN_MCR_INRQ);

    /* Get timeout */
    tickstart = HAL_GetTick();   

    /* Wait the acknowledge */
    while(HAL_IS_BIT_CLR(hcan->Instance->MSR, CAN_MSR_INAK))
    {
      if((HAL_GetTick()-tickstart) > CAN_TIMEOUT_VALUE)
      {
        hcan->State= HAL_CAN_STATE_TIMEOUT;

        /* Process unlocked */
        __HAL_UNLOCK(hcan);

        return HAL_TIMEOUT;
      }
    }

    /* Check acknowledged */
    if (HAL_IS_BIT_SET(hcan->Instance->MSR, CAN_MSR_INAK))
    {
      status = CAN_INITSTATUS_SUCCESS;
    }
  }
   
}


有疑问的地方是代码中紫色字体的两行代码,因为在请求退出初始化模式之前,初始化模式标志位INAK是等于‘1’的,然后在程序
执行CLEAR_BIT(hcan->Instance->MCR, CAN_MCR_INRQ)请求退出初始化模式之后,我们期望INAK被清‘0’,所以应该是使用
while()循环等待INAK从1变为0才对,也就是INAK=1的时候等待,INAK=0时退出while()循环;但上述程序中却是INAK=0的时候等待,INAK=1的时候退出while()循环。

参考手册中对于退出初始化模式的描述如下
清除CAN_MCR寄存器的INRQ位为'0',请求bxCAN退出初始化模式,当硬件对CAN_MSR寄存
器的INAK位清'0',就确认了初始化模式的退出。

有知道原因的请指点一下,谢谢!

回帖(1)

王树林

2024-5-8 17:10:21
在STM32Cube HAL库中,CAN初始化函数`HAL_CAN_Init(CAN_HandleTypeDef* hcan)`的步骤如下:

1. 退出睡眠模式:在初始化CAN之前,需要确保CAN模块处于正常工作状态。这可以通过调用`HAL_CAN_WAKEUP()`函数实现。

2. 请求进入初始化模式:为了对CAN模块进行配置,需要将其置于初始化模式。这可以通过设置CAN_MCR寄存器的`INRQ`位实现。

3. 等待初始化确认标志INAK置位:在请求进入初始化模式后,需要等待CAN_MCR寄存器的`INAK`位置位,以确认CAN模块已进入初始化模式。

4. 进行初始化配置:在CAN模块进入初始化模式后,可以对CAN模块的时钟、滤波器、中断等进行配置。

5. 请求退出初始化模式:完成初始化配置后,需要将CAN模块置于正常工作模式。这可以通过清除CAN_MCR寄存器的`INRQ`位实现。

6. 等待确认初始化模式退出:在请求退出初始化模式后,需要等待CAN_MCR寄存器的`INAK`位清除,以确认CAN模块已退出初始化模式。

在HAL库的CAN初始化函数中,上述红色字体部分代码如下:

```c
HAL_StatusTypeDef HAL_CAN_Init(CAN_HandleTypeDef* hcan)
{
    // ...
   
    /* Request leave initialisation */
    hcan->Instance->MCR &= ~((uint32_t)CAN_MCR_INRQ);
   
    /* Wait INAK bit reset */
    if (CAN_WaitOnFlagUntilTimeout(hcan, CAN_FLAG_INAK, RESET, CAN_TIMEOUT_VALUE) != HAL_OK)
    {
        return HAL_TIMEOUT;
    }
   
    // ...
}
```

这段代码首先清除`INRQ`位以请求退出初始化模式,然后使用`CAN_WaitOnFlagUntilTimeout()`函数等待`INAK`位清除,以确认CAN模块已退出初始化模式。如果超时,则返回`HAL_TIMEOUT`。
举报

更多回帖

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