食用指南:本文主要内容为梳理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内有消息待处理时,可以通过注册一个回调函数来通知应用程序进行相应的处理。
if (hcan->MspInitCallback == NULL)
{
hcan->MspInitCallback = HAL_CAN_MspInit; /* Legacy weak MspInit */
}
这个条件语句检查用户是否已经定义了自己的MspInitCallback回调函数。如果hcan->MspInitCallback
为NULL,表示用户没有定义自己的回调函数,则将hcan->MspInitCallback
设置为默认的回调函数HAL_CAN_MspInit
。这个回调函数被命名为”Legacy weak MspInit”,表示它是在历史版本中使用的弱定义回调函数。
/* Init the low level hardware: CLOCK, NVIC */
hcan->MspInitCallback(hcan);
这行代码调用用户自定义的MspInitCallback回调函数,用于初始化CAN的底层硬件。这个回调函数在用户代码中实现,用于配置CAN控制器的时钟和中断等底层硬件设置。
逻辑4:
#else
if (hcan->State == HAL_CAN_STATE_RESET)
{
/* Init the low level hardware: CLOCK, NVIC */
HAL_CAN_MspInit(hcan);
}
这段代码是在宏定义USE_HAL_CAN_REGISTER_CALLBACKS
不等于1时执行的条件分支。它也用于初始化CAN的底层硬件,但是没有使用回调函数注册功能。
-
如果
USE_HAL_CAN_REGISTER_CALLBACKS
不等于1,表示不使用回调函数注册功能。 -
如果CAN的状态
hcan->State
等于HAL_CAN_STATE_RESET
,表示CAN处于复位状态。在这种情况下,仍然需要初始化底层硬件。 -
调用默认的MspInit函数
HAL_CAN_MspInit(hcan)
,用于初始化CAN的底层硬件。这个函数是在HAL库中定义的,用于配置CAN控制器的时钟和中断等底层硬件设置。
通过这段代码,可以看出当不使用回调函数注册功能时,仍然可以通过调用默认的MspInit函数来初始化CAN的底层硬件。这样,用户仍然可以在初始化之前对硬件进行必要的配置。
逻辑7
while ((hcan->Instance->MSR & CAN_MSR_SLAK) != 0U)
{
if ((HAL_GetTick() - tickstart) > CAN_TIMEOUT_VALUE)
{
/* Update error code */
hcan->ErrorCode |= HAL_CAN_ERROR_TIMEOUT;
/* Change CAN state */
hcan->State = HAL_CAN_STATE_ERROR;
return HAL_ERROR;
}
}
这段代码是一个循环,用于等待CAN进入睡眠模式解锁状态。
-
hcan->Instance->MSR & CAN_MSR_SLAK
用于检查CAN状态寄存器(MSR)中的SLAK位是否被置位。SLAK位表示CAN是否处于睡眠模式。 -
循环条件
(hcan->Instance->MSR & CAN_MSR_SLAK) != 0U
表示只要CAN处于睡眠模式,就继续循环等待。 -
在循环内部,首先使用
(HAL_GetTick() - tickstart)
计算自循环开始以来经过的时间。HAL_GetTick()
函数用于获取系统的滴答计数值,返回的是自系统启动以来的毫秒数。 -
如果经过的时间超过了CAN_TIMEOUT_VALUE,表示CAN等待超时。在这种情况下,会执行以下步骤:
- 更新错误代码
hcan->ErrorCode
,将HAL_CAN_ERROR_TIMEOUT添加到错误代码中,表示超时错误。 - 修改CAN的状态为HAL_CAN_STATE_ERROR,表示CAN进入错误状态。
- 返回HAL_ERROR,表示操作失败。
- 更新错误代码
-
如果CAN没有超时,继续循环等待CAN解除睡眠模式的状态。
这段代码的作用是等待CAN进入睡眠模式解锁状态。它通过查询CAN的状态寄存器中的SLAK位,并设置超时时间,确保CAN在一定时间内解锁。如果超时时间内仍然没有解锁,将返回错误。这样可以确保在使用CAN之前,CAN已经解除睡眠模式并准备好进行通信。
逻辑10
SET_BIT(hcan->Instance->MCR, CAN_MCR_INRQ);
/* Get tick */
tickstart = HAL_GetTick();
/* Wait initialisation acknowledge */
while ((hcan->Instance->MSR & CAN_MSR_INAK) == 0U)
{
if ((HAL_GetTick() - tickstart) > CAN_TIMEOUT_VALUE)
{
/* Update error code */
hcan->ErrorCode |= HAL_CAN_ERROR_TIMEOUT;
/* Change CAN state */
hcan->State = HAL_CAN_STATE_ERROR;
return HAL_ERROR;
}
}
这段代码的作用是发送CAN初始化请求,并等待CAN初始化的确认。它通过设置CAN模式控制寄存器中的INRQ位,请求CAN初始化。然后使用轮询方式等待CAN状态寄存器中的INAK位被置位,表示CAN已经完成初始化。如果超时时间内仍然没有完成初始化,将返回错误。这样可以确保在使用CAN之前,CAN已经完成了必要的初始化。
-
SET_BIT(hcan->Instance->MCR, CAN_MCR_INRQ)
用于设置CAN模式控制寄存器(MCR)中的INRQ位。INRQ位用于请求CAN初始化。 -
tickstart = HAL_GetTick()
用于获取当前的系统滴答计数值,即从系统启动以来的毫秒数。 -
循环条件
(hcan->Instance->MSR & CAN_MSR_INAK) == 0U
表示只要CAN处于初始化确认状态,就继续循环等待。 -
在循环内部,首先使用
(HAL_GetTick() - tickstart)
计算自循环开始以来经过的时间。 -
如果经过的时间超过了CAN_TIMEOUT_VALUE,表示CAN初始化超时。在这种情况下,会执行以下步骤:
- 更新错误代码
hcan->ErrorCode
,将HAL_CAN_ERROR_TIMEOUT添加到错误代码中,表示超时错误。 - 修改CAN的状态为HAL_CAN_STATE_ERROR,表示CAN进入错误状态。
- 返回HAL_ERROR,表示操作失败。
- 更新错误代码
-
如果CAN在超时时间内完成了初始化确认,继续循环等待CAN初始化完成。
逻辑11
/* Set the time triggered communication mode */ if (hcan->Init.TimeTriggeredMode == ENABLE) { SET_BIT(hcan->Instance->MCR, CAN_MCR_TTCM); } else { CLEAR_BIT(hcan->Instance->MCR, CAN_MCR_TTCM); } /* Set the automatic bus-off management */ if (hcan->Init.AutoBusOff == ENABLE) { SET_BIT(hcan->Instance->MCR, CAN_MCR_ABOM); } else { CLEAR_BIT(hcan->Instance->MCR, CAN_MCR_ABOM); } /* Set the automatic wake-up mode */ if (hcan->Init.AutoWakeUp == ENABLE) { SET_BIT(hcan->Instance->MCR, CAN_MCR_AWUM); } else { CLEAR_BIT(hcan->Instance->MCR, CAN_MCR_AWUM); } /* Set the automatic retransmission */ if (hcan->Init.AutoRetransmission == ENABLE) { CLEAR_BIT(hcan->Instance->MCR, CAN_MCR_NART); } else { SET_BIT(hcan->Instance->MCR, CAN_MCR_NART); } /* Set the receive FIFO locked mode */ if (hcan->Init.ReceiveFifoLocked == ENABLE) { SET_BIT(hcan->Instance->MCR, CAN_MCR_RFLM); } else { CLEAR_BIT(hcan->Instance->MCR, CAN_MCR_RFLM); } /* Set the transmit FIFO priority */ if (hcan->Init.TransmitFifoPriority == ENABLE) { SET_BIT(hcan->Instance->MCR, CAN_MCR_TXFP); } else { CLEAR_BIT(hcan->Instance->MCR, CAN_MCR_TXFP); }
通过这段代码,可以根据用户在
hcan->Init
结构体中的配置,设置或清除CAN控制器的不同模式和功能位。这样可以根据应用需求灵活地配置CAN控制器的行为。 -
hcan->Init.TimeTriggeredMode
用于判断是否启用时间触发通信模式。如果启用,会设置CAN模式控制寄存器(MCR)中的TTCM位;否则会清除TTCM位。 -
hcan->Init.AutoBusOff
用于判断是否启用自动总线关闭管理。如果启用,会设置MCR寄存器中的ABOM位;否则会清除ABOM位。 -
hcan->Init.AutoWakeUp
用于判断是否启用自动唤醒模式。如果启用,会设置MCR寄存器中的AWUM位;否则会清除AWUM位。 -
hcan->Init.AutoRetransmission
用于判断是否启用自动重传功能。如果启用,会清除MCR寄存器中的NART位;否则会设置NART位。 -
hcan->Init.ReceiveFifoLocked
用于判断是否启用接收FIFO锁定模式。如果启用,会设置MCR寄存器中的RFLM位;否则会清除RFLM位。 -
hcan->Init.TransmitFifoPriority
用于判断是否启用发送FIFO优先级功能。如果启用,会设置MCR寄存器中的TXFP位;否则会清除TXFP位。逻辑12
WRITE_REG(hcan->Instance->BTR, (uint32_t)(hcan->Init.Mode | hcan->Init.SyncJumpWidth | hcan->Init.TimeSeg1 | hcan->Init.TimeSeg2 | (hcan->Init.Prescaler - 1U)));
通过这段代码,可以根据用户在
hcan->Init
结构体中的配置,计算并设置CAN的位时序和预分频器值,以配置CAN的波特率和位时序参数。这样可以根据应用需求灵活地配置CAN通信的速率和时序。 -
(uint32_t)(hcan->Init.Mode | hcan->Init.SyncJumpWidth | hcan->Init.TimeSeg1 | hcan->Init.TimeSeg2 | (hcan->Init.Prescaler - 1U))
是一个表达式,用于计算要写入BTR寄存器的值。它将CAN的工作模式(Mode)、同步跳跃宽度(SyncJumpWidth)、时间段1(TimeSeg1)、时间段2(TimeSeg2)和预分频器(Prescaler)的值合并为一个32位的值。 -
WRITE_REG(hcan->Instance->BTR, ...)
宏用于将计算得到的值写入CAN的BTR寄存器,以配置CAN的位时序和波特率。WRITE_REG 是一个宏定义,它将给定的值写入指定的寄存器。
函数源码
HAL_StatusTypeDef HAL_CAN_Init(CAN_HandleTypeDef *hcan)
{
uint32_t tickstart;
/* Check CAN handle */
if (hcan == NULL)
{
return HAL_ERROR;
}
/* Check the parameters */
assert_param(IS_CAN_ALL_INSTANCE(hcan->Instance));
assert_param(IS_FUNCTIONAL_STATE(hcan->Init.TimeTriggeredMode));
assert_param(IS_FUNCTIONAL_STATE(hcan->Init.AutoBusOff));
assert_param(IS_FUNCTIONAL_STATE(hcan->Init.AutoWakeUp));
assert_param(IS_FUNCTIONAL_STATE(hcan->Init.AutoRetransmission));
assert_param(IS_FUNCTIONAL_STATE(hcan->Init.ReceiveFifoLocked));
assert_param(IS_FUNCTIONAL_STATE(hcan->Init.TransmitFifoPriority));
assert_param(IS_CAN_MODE(hcan->Init.Mode));
assert_param(IS_CAN_SJW(hcan->Init.SyncJumpWidth));
assert_param(IS_CAN_BS1(hcan->Init.TimeSeg1));
assert_param(IS_CAN_BS2(hcan->Init.TimeSeg2));
assert_param(IS_CAN_PRESCALER(hcan->Init.Prescaler));
#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);
}
#else
if (hcan->State == HAL_CAN_STATE_RESET)
{
/* Init the low level hardware: CLOCK, NVIC */
HAL_CAN_MspInit(hcan);
}
#endif /* (USE_HAL_CAN_REGISTER_CALLBACKS) */
/* Exit from sleep mode */
CLEAR_BIT(hcan->Instance->MCR, CAN_MCR_SLEEP);
/* Get tick */
tickstart = HAL_GetTick();
/* Check Sleep mode leave acknowledge */
while ((hcan->Instance->MSR & CAN_MSR_SLAK) != 0U)
{
if ((HAL_GetTick() - tickstart) > CAN_TIMEOUT_VALUE)
{
/* Update error code */
hcan->ErrorCode |= HAL_CAN_ERROR_TIMEOUT;
/* Change CAN state */
hcan->State = HAL_CAN_STATE_ERROR;
return HAL_ERROR;
}
}
/* Request initialisation */
SET_BIT(hcan->Instance->MCR, CAN_MCR_INRQ);
/* Get tick */
tickstart = HAL_GetTick();
/* Wait initialisation acknowledge */
while ((hcan->Instance->MSR & CAN_MSR_INAK) == 0U)
{
if ((HAL_GetTick() - tickstart) > CAN_TIMEOUT_VALUE)
{
/* Update error code */
hcan->ErrorCode |= HAL_CAN_ERROR_TIMEOUT;
/* Change CAN state */
hcan->State = HAL_CAN_STATE_ERROR;
return HAL_ERROR;
}
}
/* Set the time triggered communication mode */
if (hcan->Init.TimeTriggeredMode == ENABLE)
{
SET_BIT(hcan->Instance->MCR, CAN_MCR_TTCM);
}
else
{
CLEAR_BIT(hcan->Instance->MCR, CAN_MCR_TTCM);
}
/* Set the automatic bus-off management */
if (hcan->Init.AutoBusOff == ENABLE)
{
SET_BIT(hcan->Instance->MCR, CAN_MCR_ABOM);
}
else
{
CLEAR_BIT(hcan->Instance->MCR, CAN_MCR_ABOM);
}
/* Set the automatic wake-up mode */
if (hcan->Init.AutoWakeUp == ENABLE)
{
SET_BIT(hcan->Instance->MCR, CAN_MCR_AWUM);
}
else
{
CLEAR_BIT(hcan->Instance->MCR, CAN_MCR_AWUM);
}
/* Set the automatic retransmission */
if (hcan->Init.AutoRetransmission == ENABLE)
{
CLEAR_BIT(hcan->Instance->MCR, CAN_MCR_NART);
}
else
{
SET_BIT(hcan->Instance->MCR, CAN_MCR_NART);
}
/* Set the receive FIFO locked mode */
if (hcan->Init.ReceiveFifoLocked == ENABLE)
{
SET_BIT(hcan->Instance->MCR, CAN_MCR_RFLM);
}
else
{
CLEAR_BIT(hcan->Instance->MCR, CAN_MCR_RFLM);
}
/* Set the transmit FIFO priority */
if (hcan->Init.TransmitFifoPriority == ENABLE)
{
SET_BIT(hcan->Instance->MCR, CAN_MCR_TXFP);
}
else
{
CLEAR_BIT(hcan->Instance->MCR, CAN_MCR_TXFP);
}
/* Set the bit timing register */
WRITE_REG(hcan->Instance->BTR, (uint32_t)(hcan->Init.Mode |
hcan->Init.SyncJumpWidth |
hcan->Init.TimeSeg1 |
hcan->Init.TimeSeg2 |
(hcan->Init.Prescaler - 1U)));
/* Initialize the error code */
hcan->ErrorCode = HAL_CAN_ERROR_NONE;
/* Initialize the CAN state */
hcan->State = HAL_CAN_STATE_READY;
/* Return function status */
return HAL_OK;
}
/**
* @brief Deinitializes the CAN peripheral registers to their default
* reset values.
* @param hcan pointer to a CAN_HandleTypeDef structure that contains
* the configuration information for the specified CAN.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_CAN_DeInit(CAN_HandleTypeDef *hcan)
{
/* Check CAN handle */
if (hcan == NULL)
{
return HAL_ERROR;
}
/* Check the parameters */
assert_param(IS_CAN_ALL_INSTANCE(hcan->Instance));
/* Stop the CAN module */
(void)HAL_CAN_Stop(hcan);
#if USE_HAL_CAN_REGISTER_CALLBACKS == 1
if (hcan->MspDeInitCallback == NULL)
{
hcan->MspDeInitCallback = HAL_CAN_MspDeInit; /* Legacy weak MspDeInit */
}
/* DeInit the low level hardware: CLOCK, NVIC */
hcan->MspDeInitCallback(hcan);
#else
/* DeInit the low level hardware: CLOCK, NVIC */
HAL_CAN_MspDeInit(hcan);
#endif /* (USE_HAL_CAN_REGISTER_CALLBACKS) */
/* Reset the CAN peripheral */
SET_BIT(hcan->Instance->MCR, CAN_MCR_RESET);
/* Reset the CAN ErrorCode */
hcan->ErrorCode = HAL_CAN_ERROR_NONE;
/* Change CAN state */
hcan->State = HAL_CAN_STATE_RESET;
/* Return function status */
return HAL_OK;
}
评论(0)
您还未登录,请登录后发表或查看评论