简而言之,手动复位 SLEEP 位时,SLAK 位不会复位。详细说明:
在尝试建立网络之前,我正在尝试以环回模式成功传输。经过大量文档阅读后,我让它在某个时候工作,但现在我遇到了一个新问题。(遗憾的是我不记得我改变了什么,也许是在玩时间)
在将外设设置为环回并提供一致的位时序值(所以我可能已经使用它们但它们恢复正常)后,我使用 Cube 生成代码。这意味着流程应该首先退出睡眠模式,进入初始化模式,进行设置,退出初始化模式,然后启动正常模式。根据参考手册:
如果在 bxCAN 处于休眠模式时软件通过设置 INRQ 位来请求进入初始化模式,它还必须清除 SLEEP 位。[...] 清除 SLEEP 位后,一旦 bxCAN与 CAN 总线同步,就会退出休眠模式[...]。一旦SLAK 位被硬件清零,就退出休眠模式
和
为了同步,bxCAN 一直等到 CAN 总线空闲,这意味着在 CANRX上已经监视了11 个连续的隐性位。
根据维基
0 数据位编码显性状态,而1 数据位编码隐性状态
所以
检查 Cube 生成的代码,这正是正在发生的事情。我在这里粘贴了 stm32f4xx_hal_can.c 的重要部分:
HAL_StatusTypeDef HAL_CAN_Init(CAN_HandleTypeDef *hcan)
{
[...]
/* 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)
{
[...]
/*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)
{
[...]
/*Error*/
}
CAN_MSR 的 SLEEP 位被复位并等待来自 CAN_MSR 的 SLAK 位被硬件复位。CAN_TIMEOUT_VALUE 设置为 10,基本上是给 11 个隐性位稳定下来的时间。
这就是我卡住的地方。SLACK 不会重置...我试图移除if ((HAL_GetTick() - tickstart) > CAN_TIMEOUT_VALUE)
,以便 MCU 无限期地等待 SLAK 重置。没有帮助。
查看 CAN_MSR RX 寄存器,给出 RX 上的当前值,同时等待 SLACK 变化,我注意到它始终为 0。所以我尝试将 GPIO 设置为 RX 和 TX 的上拉和下拉,但是我认为它没有效果,因为在环回模式下,bxCAN 的 RX 与 GPIO 隔离 :) 这也意味着,问题不应该出现在硬件方面(如布线和东西,外部事物,而不是内部硬件)。让我相信在全局 HAL_Init() 或 MX_GPIO_Init() 或其他东西期间出了点问题,但由于它是由 Cube 生成的,我没有改变任何东西,我看不出它如何对 SLAK 产生影响离开。
我的想法可能是在某事上进行软件重置,但我不知道这条路将把我带到哪里,因为关闭电源并在芯片上不能解决问题......