完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
主要是针对开发出BUSOFF管理,NXP感觉都是一个套路,无论powerpc,还是arm_m
status_t FLEXCAN_DRV_Init(uint8_t instance,flexcan_state_t *state,const flexcan_user_config_t *data) 先从这个函数起 if(FLEXCAN_IsEnabled(base)) { /* To enter Disable Mode requires FreezMode first */ FLEXCAN_EnterFreezeMode(base); FLEXCAN_Disable(base); } 首先是判断当前CAN是否ENABLE ,如果是ENABLE,比如你是从error_handle调用这个初始化函数,那么首先进入FLEXCAN_EnterFreezeMode(base);下面分析下这个函数 base->MCR = (base->MCR & ~CAN_MCR_FRZ_MASK) | CAN_MCR_FRZ(1U); base->MCR = (base->MCR & ~CAN_MCR_HALT_MASK) | CAN_MCR_HALT(1U); 首先将MCR reg中的FRZ HALT bit 清除 然后置位 if (((base->MCR & CAN_MCR_MDIS_MASK) >> CAN_MCR_MDIS_SHIFT) == 0U) { enabled = true; } else { base->MCR &= ~CAN_MCR_MDIS_MASK; } 如果enable==true,就不用开启和关闭时钟,如果enable==false,则先开启,后面又关闭时钟 /* Check Low-Power Mode Acknowledge Cleared */ while (((base->MCR & CAN_MCR_LPMACK_MASK) >> CAN_MCR_LPMACK_SHIFT) == 1U) {}//Freeze mode cannot be entered while FlexCAN is in a low power mode. 如果是从低功耗模式唤醒的话,就等待LPMACK清零,否则该位直接为0,跳过 if ((((base->ESR1 & CAN_ESR1_FLTCONF_MASK) >> CAN_ESR1_FLTCONF_SHIFT) & 2U) != 0U)//ESR1 reg Fault_Confinement_State(第26-27位),01代表主动错误状态,11代表busoff,这里只要处于这两种状态之一,就进入以下流程 { /* Save registers before Soft Reset */ uint32_t tempIMSK[2],tempMCR; tempIMSK[0] = base->IMASK1;//保存MB 中断寄存器状态 tempIMSK[1] = base->IMASK2; tempMCR = base->MCR;//将整个MCR保存 /* Soft Reset FlexCan */ base->MCR |= CAN_MCR_SOFTRST(1U);//软重启一次 while (((base->MCR & CAN_MCR_SOFTRST_MASK) >> CAN_MCR_SOFTRST_SHIFT) != 0U) {}//等待软重启完毕 /* Restore registers after Soft Reset */ base->IMASK1 = tempIMSK[0]; base->IMASK2 = tempIMSK[1]; base->MCR = tempMCR; } else { base->MCR = (base->MCR & ~CAN_MCR_HALT_MASK) | CAN_MCR_HALT(1U);//不知道为啥再次置位,注意这句 No reception or transmission is performed by FlexCAN before this bit is cleared. } while (((base->MCR & CAN_MCR_FRZACK_MASK) >> CAN_MCR_FRZACK_SHIFT) == 0U) {}//轮询该位等待确切进入frz mode if (false == enabled) { base->MCR |= CAN_MCR_MDIS_MASK; /* Wait until disable mode acknowledged */ while (((base->MCR & CAN_MCR_LPMACK_MASK) >> CAN_MCR_LPMACK_SHIFT) == 0U) {} } 然后调用void FLEXCAN_Disable(CAN_Type * base)。关闭时钟。。。。 感觉和闹着玩一样,总之BUSOFF是从err_handle 进入的,肯定是FLEXCAN_IsEnabled(base)==true 下面梳理一下这个流程,感觉只要在err_handle中调用FLEXCAN_DRV_Init,然后在这个基础上修改,比如增加定时器,增加恢复次数计数,就可以进行BUSOFF快慢恢了。 中间一些设置波特率,运行模式之类的就不说了,无非就是一会开一会关反复横跳,说一下调用到FLEXCAN_Init 函数,这个函数里面会清除所有err_flag /* Clear all error interrupt flags */ (base->ESR1) = FLEXCAN_ALL_INT; 1 2 好了,不接着上面分析了,这两天简单搞了下BUSOFF机制,直接上代码 void Xcp_Can_Init(void) { FLEXCAN_DRV_Init(INST_CANCOM1, &canCom1_State, &canCom1_InitConfig0); for(uint8_t i=0;i<16;i++) { XcpCan_Fliter_Config.isRemoteFrame=false; XcpCan_Fliter_Config.isExtendedFrame=false; XcpCan_Fliter_Config.id=XcpCan_Fliter_Table; } FLEXCAN_DRV_ConfigRxFifo(INST_CANCOM1,FLEXCAN_RX_FIFO_ID_FORMAT_A,XcpCan_Fliter_Config); CAN_2->CTRL1 |=CAN_CTRL1_BOFFREC_MASK; FLEXCAN_DRV_SetRxMaskType(INST_CANCOM1,FLEXCAN_RX_MASK_INDIVIDUAL); FLEXCAN_DRV_InstallEventCallback(INST_CANCOM1,XcpRxCallback,NULL); FLEXCAN_DRV_InstallErrorCallback(INST_CANCOM1, Xcp_err_callback, NULL); FLEXCAN_DRV_RxFifo(INST_CANCOM1,&XcpCan_RxFrame); } 初始化CAN的时候要注册FLEXCAN_DRV_InstallErrorCallback(INST_CANCOM1, Xcp_err_callback, NULL);SDK里面ERR_INT,RXWARN,TXWARN,BUSOFF中断都是默认打开的,这里如果要使用这些中断,就要注册回调函数,所有这些中断的回调函数都是同一个函数,即FLEXCAN_DRV_InstallErrorCallback注册的函数,函数名由你自己定义,反正函数名不就是个地址嘛。这里推荐一下程序小拜的blog,里面也有讲解 void Xcp_err_callback(uint8_t instance, flexcan_event_type_t eventType,flexcan_state_t *flexcanState) { uint32_t err_count=(uint32_t)(CAN_2->ECR); uint32_t rx_err_count=((err_count&0xffffffff00)>>8)&0xff; if(rx_err_count>=120) { rx_err_times++; if(pit_ch0_count >= 60) { can_bus_breakdown=1; PIT_DRV_StopChannel(INST_PIT1,0); } else { if(((PIT_0->TIMER[0].TCTRL)&0x1)==0) { PIT_DRV_StartChannel(INST_PIT1,0); } } } if(((FLEXCAN_DRV_GetErrorStatus(INST_CANCOM1)&CAN_ESR1_FLTCONF_MASK)>>4)==0x3) { busoff_count++; if(fast_recovery_times <5) { if(((PIT_0->TIMER[1].TCTRL)&0x1)==0) { pit1_ChnConfig1.period=(uint32_t)fast_recovery_delay; PIT_DRV_InitChannel(INST_PIT1, &pit1_ChnConfig1); INT_SYS_SetPriority(PIT_Ch1_IRQn, 1U); PIT_DRV_StartChannel(INST_PIT1,1); fast_recovery_times++; } } else { PIT_DRV_StopChannel(INST_PIT1,1); pit1_ChnConfig1.period=(uint32_t)slow_recovery_delay; PIT_DRV_InitChannel(INST_PIT1, &pit1_ChnConfig1); INT_SYS_SetPriority(PIT_Ch1_IRQn, 1U); PIT_DRV_StartChannel(INST_PIT1,1); slow_recovery_times++; } } }; 在err_callback里面if(((FLEXCAN_DRV_GetErrorStatus(INST_CANCOM1)&CAN_ESR1_FLTCONF_MASK)>>4)==0x3)代表ESR1寄存器FLTCONF位为0b11,表示从CAN控制器从Active_ERR状态转换为了BUSOFF状态,当然你也可以屏蔽ERR_INT,RXWARN,TXWARN这些中断,这样就只有当BUSOFF发生时才进入中断处理函数,进而进入回调函数,进入BUSOFF的原因只能是tx_err_cnt>255,也就是发送错误计数超过255,而rx_err_count最大只能增加到127,到127时使CAN控制器从Pasive_ERR进入Active_ERR,但绝不会再增加使其进入BUSOFF,这个时候就算你吧CAN_RX拔了,只要再插上,然后CAN控制器接收到一帧数据,tx_err_count就会清零,控制器又恢复到正常状态(Pasive_ERR)。 只要FLTCONF位为0b11,CAN控制器就不能收发了,相当于死机了,然后这个时候你就要关闭CAN,重新初始化,FLTCONF位直接赋值是不能清除的,即SDK中的 /* Clear all error interrupt flags */ (base->ESR1) = FLEXCAN_ALL_INT; 清除该位后CAN控制器才能从新恢复功能,然后去和总线同步,恢复通信,清除的办法就是 * Reset the FLEXCAN */ base->MCR = (base->MCR & ~CAN_MCR_SOFTRST_MASK) | CAN_MCR_SOFTRST(1U); 让CAN控制器软重启,为了不出错,所以就直接从新走一遍初始化流程,在void Xcp_Can_Init(void)中的FLEXCAN_DRV_Init这个函数中如果判断if(FLEXCAN_IsEnabled(base))(表示当前是从CAN控制器使能状态),就会有以下操作 if ((((base->ESR1 & CAN_ESR1_FLTCONF_MASK) >> CAN_ESR1_FLTCONF_SHIFT) & 2U) != 0U) { /* Save registers before Soft Reset */ uint32_t tempIMSK[2],tempMCR; tempIMSK[0] = base->IMASK1; tempIMSK[1] = base->IMASK2; tempMCR = base->MCR; /* Soft Reset FlexCan */ base->MCR |= CAN_MCR_SOFTRST(1U); while (((base->MCR & CAN_MCR_SOFTRST_MASK) >> CAN_MCR_SOFTRST_SHIFT) != 0U) {} /* Restore registers after Soft Reset */ base->IMASK1 = tempIMSK[0]; base->IMASK2 = tempIMSK[1]; base->MCR = tempMCR; #if FEATURE_CAN_HAS_MEM_ERR_DET /* Disable the Protection again because is enabled by soft reset */ FLEXCAN_DisableMemErrorDetection(base); #endif } 保存寄存器,软重启,也就清除了BUSOFF,CAN逐渐恢复正常。其实SDK中已经考虑得比较全面了,我们只要确定好调用时机就好,要做到快慢恢复,我们需要增加一个定时器,这里得定时器就用MPC5744P得PIT CH1。 #define fast_recovery_delay 100000 #define slow_recovery_delay 1000000 uint8_t fast_recovery_times=0; uint8_t slow_recovery_times=0; 定义快慢恢复时间和记录快慢恢复次数,当 if(fast_recovery_times <5) { if(((PIT_0->TIMER[1].TCTRL)&0x1)==0) { pit1_ChnConfig1.period=(uint32_t)fast_recovery_delay; PIT_DRV_InitChannel(INST_PIT1, &pit1_ChnConfig1); INT_SYS_SetPriority(PIT_Ch1_IRQn, 1U); PIT_DRV_StartChannel(INST_PIT1,1); fast_recovery_times++; } } else { PIT_DRV_StopChannel(INST_PIT1,1); pit1_ChnConfig1.period=(uint32_t)slow_recovery_delay; PIT_DRV_InitChannel(INST_PIT1, &pit1_ChnConfig1); INT_SYS_SetPriority(PIT_Ch1_IRQn, 1U); PIT_DRV_StartChannel(INST_PIT1,1); slow_recovery_times++; } 快恢复次数大于5就进入慢恢复,而恢复是在PIT得中断处理函数中进行的(计时时间到),相当于增加了一个延迟。 void PIT_Ch1_IRQHandler (void) { pit_ch1_count++; PIT_DRV_StopChannel(INST_PIT1,1); PIT_DRV_DisableChannelInterrupt(INST_PIT1,1); Xcp_Can_Init(); PIT_DRV_ClearStatusFlags(INST_PIT1, 1U); } 直接调用Xcp_Can_Init就好,记得在中断处理函数中停掉PIT,不然会一直中断,也就一直调用CAN初始化,而再次开启PIT取决于下次进入BUSOFF的时机(如果前一个BUSOFF没有被处理,即FLTCONF没有被清除,这个时候就算短接CAN_H,CAN_L也不会再次进入err_callback,相当于CAN死机了,在你下一次重启电脑之前,你对他继续破坏他也不会做出反应) 当PIT中断调用Xcp_Can_Init,CAN控制器重启后,只要同步完成(自动的,128连续11个隐性位),并成功发出去一帧数据后,说明BUSOFF恢复成功,故障清除,否则就会再次进入BUSOFF(你可以拔掉CAN_TX试试),又进入快慢恢复流程。 发出去数据后,只要使fast_recovery_times=0;就可以重设快慢恢复节奏,具体如下 void XcpRxCallback(uint8_t instance, flexcan_event_type_t eventType,uint32_t buffIdx, flexcan_state_t *flexcanState) { switch(eventType) { case FLEXCAN_EVENT_TX_COMPLETE: can_tx_count++; fast_recovery_times=0; FLEXCAN_DRV_RxFifo(instance,&XcpCan_RxFrame); break; case FLEXCAN_EVENT_RXFIFO_COMPLETE: can_rx_count++; if((XcpCan_RxFrame.msgId == Xcp_RXID) && (XcpCan_RxFrame.data[0]==0XF4)) { if(((PIT_0->TIMER[0].TCTRL)&0x1)!=0) { PIT_DRV_StopChannel(INST_PIT1,0); PIT_DRV_InitChannel(INST_PIT1, &pit1_ChnConfig0); } } FLEXCAN_DRV_RxFifo(instance,&XcpCan_RxFrame); break; default: break; } }; 这个函数是由FLEXCAN_DRV_InstallEventCallback(INST_CANCOM1,XcpRxCallback,NULL);注册的,就是CAN的发送和接收完成中断回调,在这个函数里判断event,就可以处理CAN消息。 就写这么多,如有不足,忘大神指教。 |
|
|
|
只有小组成员才能发言,加入小组>>
imx6ull 和 lan8742 工作起来不正常, ping 老是丢包
1739 浏览 0 评论
3339 浏览 9 评论
3017 浏览 16 评论
3508 浏览 1 评论
9106 浏览 16 评论
1223浏览 3评论
632浏览 2评论
const uint16_t Tab[10]={0}; const uint16_t *p; p = Tab;//报错是怎么回事?
621浏览 2评论
用NUC131单片机UART3作为打印口,但printf没有输出东西是什么原因?
2363浏览 2评论
NUC980DK61YC启动随机性出现Err-DDR是为什么?
1928浏览 2评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2025-1-14 11:19 , Processed in 0.995420 second(s), Total 47, Slave 38 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号