食用指南:本文主要内容为梳理CAN初始化函数主要运行逻辑及重点功能实现代码的详尽解析。函数源码在文末,建议在阅读源码之后观看。
CAN相关寄存器图:
主要逻辑分析:
下面分点梳理函数的主要逻辑(注意逻辑序号,后文依次为点进行分析):
-
首先,函数会检查传入的参数
hcan
是否为NULL,如果是NULL,则返回错误代码HAL_ERROR
。 -
接下来,函数会使用
assert_param
宏对传入的hcan
结构体的各个参数进行检查,确保它们的取值范围符合要求。 -
如果宏
USE_HAL_CAN_REGISTER_CALLBACKS
的值为1并且hcan
的状态为HAL_CAN_STATE_RESET
,则表示使用了回调函数,并且需要将回调函数重置为默认的“legacy”函数。如果hcan->MspInitCallback
为空,则将其设置为默认的初始化函数HAL_CAN_MspInit
。然后调用hcan
的MspInitCallback
函数,用于初始化底层硬件。 -
如果
USE_HAL_CAN_REGISTER_CALLBACKS
的值不为1或者hcan
的状态不为HAL_CAN_STATE_RESET
,则直接调用HAL_CAN_MspInit
函数初始化底层硬件。 -
在初始化之前,首先需要将CAN控制器从睡眠模式唤醒。通过清除
CAN_MCR_SLEEP
位实现。
-
接着,获取当前的系统滴答计数器值
tickstart
,用于超时判断。 -
检查CAN控制器是否成功离开了睡眠模式。通过检查
CAN_MSR_SLAK
位,如果该位为0,则表示成功离开了睡眠模式。如果超时时间超过了预设的超时值CAN_TIMEOUT_VALUE
,则更新错误代码并返回错误。 -
发送初始化请求,通过设置
CAN_MCR_INRQ
位实现。 -
获取当前的系统滴答计数器值
tickstart
,用于超时判断。 -
等待CAN控制器接受初始化请求。通过检查
CAN_MSR_INAK
位,如果该位为1,则表示CAN控制器已经接受了初始化请求。如果超时时间超过了预设的超时值CAN_TIMEOUT_VALUE
,则更新错误代码并返回错误。 -
根据初始化参数设置CAN控制器的各种工作模式和配置,包括时间触发通信模式、自动总线断开管理、自动唤醒模式、自动重传、接收FIFO锁定模式和传输FIFO优先级等。
-
设置位时序寄存器
BTR
,将各个参数值写入寄存器中。 -
初始化错误代码和CAN状态。
-
返回函数执行状态
HAL_OK
。
重点部分分析
逻辑 3:
#if USE_HAL_CAN_REGISTER_CALLBACKS == 1
if (hcan->State == HAL_CAN_STATE_RESET)
{
/* Reset callbacks to legacy functions */
hcan->RxFifo0MsgPendingCallback = HAL_CAN_RxFifo0MsgPendingCallback; /* Legacy weak RxFifo0MsgPendingCallback */
hcan->RxFifo0FullCallback = HAL_CAN_RxFifo0FullCallback; /* Legacy weak RxFifo0FullCallback */
hcan->RxFifo1MsgPendingCallback = HAL_CAN_RxFifo1MsgPendingCallback; /* Legacy weak RxFifo1MsgPendingCallback */
hcan->RxFifo1FullCallback = HAL_CAN_RxFifo1FullCallback; /* Legacy weak RxFifo1FullCallback */
hcan->TxMailbox0CompleteCallback = HAL_CAN_TxMailbox0CompleteCallback; /* Legacy weak TxMailbox0CompleteCallback */
hcan->TxMailbox1CompleteCallback = HAL_CAN_TxMailbox1CompleteCallback; /* Legacy weak TxMailbox1CompleteCallback */
hcan->TxMailbox2CompleteCallback = HAL_CAN_TxMailbox2CompleteCallback; /* Legacy weak TxMailbox2CompleteCallback */
hcan->TxMailbox0AbortCallback = HAL_CAN_TxMailbox0AbortCallback; /* Legacy weak TxMailbox0AbortCallback */
hcan->TxMailbox1AbortCallback = HAL_CAN_TxMailbox1AbortCallback; /* Legacy weak TxMailbox1AbortCallback */
hcan->TxMailbox2AbortCallback = HAL_CAN_TxMailbox2AbortCallback; /* Legacy weak TxMailbox2AbortCallback */
hcan->SleepCallback = HAL_CAN_SleepCallback; /* Legacy weak SleepCallback */
hcan->WakeUpFromRxMsgCallback = HAL_CAN_WakeUpFromRxMsgCallback; /* Legacy weak WakeUpFromRxMsgCallback */
hcan->ErrorCallback = HAL_CAN_ErrorCallback; /* Legacy weak ErrorCallback */
if (hcan->MspInitCallback == NULL)
{
hcan->MspInitCallback = HAL_CAN_MspInit; /* Legacy weak MspInit */
}
/* Init the low level hardware: CLOCK, NVIC */
hcan->MspInitCallback(hcan);
}
让我们一句一句地详细分析这段代码:
#if USE_HAL_CAN_REGISTER_CALLBACKS == 1
这是一个条件编译的预处理指令,它检查宏定义USE_HAL_CAN_REGISTER_CALLBACKS
是否等于1。如果等于1,则表示要使用回调函数注册功能。
if (hcan->State == HAL_CAN_STATE_RESET)
{
这是一个条件语句,它检查CAN的状态hcan->State
是否等于HAL_CAN_STATE_RESET
。只有当CAN处于复位状态时,才会执行接下来的代码块。
/* Reset callbacks to legacy functions */
hcan->RxFifo0MsgPendingCallback = HAL_CAN_RxFifo0MsgPendingCallback; /* Legacy weak RxFifo0MsgPendingCallback */
……
这一系列的语句将CAN处理器结构体hcan
中的回调函数成员设置为默认的回调函数。这些默认的回调函数被称为”Legacy weak”,表示它们是在历史版本中使用的弱定义回调函数。以第一句为例,作用是将HAL_CAN_RxFifo0MsgPendingCallback的回调函数的地址赋值给hcan->RxFifo0MsgPendingCallback,即将CAN模块的RxFIFO0消息待处理回调函数指针指向一个特定的函数。在CAN模块中,当RxFIFO0内有消息待处理时,可以通过注册一个回调函数来通知应用程序进行相应的处理。