本应用笔记讨论了MAX33011E的控制局域网(CAN)总线故障检测特性,并通过示例代码演示了如何在固件中实现故障检测算法。
介绍
在数据未传输或接收时对控制区域网络 (CAN) 进行故障排除可能会令人沮丧。Maxim在CAN收发器中开发了内置故障检测机制,可帮助用户快速确定根本原因。本应用笔记介绍了故障检测机制的功能,解释了其工作原理,并通过示例代码演示了如何在固件中实现故障检测算法。
使能故障检测电路
MAX33011E CAN收发器需要100 TXD上升沿(通常为几个CAN协议消息)来启用故障检测电路。故障检测电路使能后,收发器仍可正常传输消息。
读取和清除故障代码
当检测到故障情况时,发射器将被禁用,FAULT引脚将通过外部上拉电阻器拉高。当系统控制器接收到FAULT引脚信号时,TXD上需要16次从低到高的转换来移出故障代码,如表1所示。另外 10 个从低到高的 TXD 转换可清除故障并禁用故障检测电路。例如,过流故障代码为101010,其时序图如图1所示。
图1.过流故障报告时序图
故障条件
MAX33011E是首款内置故障检测电路的CAN收发器。当故障检测电路使能时,它可以检测CAN总线上的三种常见故障条件(过压、过流和传输故障),如表1所示。
故障 | 条件(启用故障检测) | 故障代码 | 可能的原因 |
过电流 | CANH 输出电流和 CANL 输入电流均> 85mA | 101010 |
CANH 缩短为 CANL CANH 连接到 GND 和 CANL 连接到 VDD |
电压 | CANH > +29V 或 CANL < -29V | 101100 | CMR 故障 |
传输故障 | RXD 在 10 个连续 TXD 脉冲内保持不变,建议最低频率 = 200kHz | 110010 |
CANH 和 CANL 上的开路负载(两个终端电阻器均缺失) 超出驱动器的共模范围 连接到固定电压源的 CANH 和/或 CANL |
过流故障
当CANH的源电流和CANL的灌电流均高于85mA(典型值)时,检测到过流故障。故障的更可能原因是总线上的CANH和CANL短路。但是,如果短路远离CAN节点,则由于电缆阻抗高,可能无法检测到。减慢CAN信号频率可以降低电缆阻抗,并有助于从更远的距离检测短路。但是,如果电缆的总电阻变得明显高,即使CAN信号始终处于主导模式,也无法检测到短路。图2显示了过流检测的最大工作频率与作为参考的电缆长度的关系。使用 Cat5E 铜包铝电缆。最大频率因电缆类型而异。
图2.过流检测的最大工作频率与电缆长度的关系
过压故障
MAX33011E共模输入范围(CMR)为±25V。当CANH高于29V或CANH低于-29V时,检测到过压故障。这是由于 CMR 超出规范造成的。
传输故障故障
故障检测电路使能后,收发器仍可传输消息。在正常工作条件下,RXD 会回显 TXD 信号。如果RXD连续10个脉冲没有回显TXD信号,则检测电路会产生传输故障。有几个常见的可能原因使 RXD 无法回显 TXD:
如果CANH和CANL短路至电源,并且收发器无法过驱电源,则接收器将始终在CAN总线上看到固定信号。
当共模电压超过驱动器的共模范围(-5V至+10V)时,驱动器关断。当驱动器关闭时,CANH/CANL输出不会在TXD上反射信号,接收器将在CAN总线上看到固定信号。
如果终端电阻未连接到CAN节点,则可能导致传输故障。终端电阻在隐性模式下使CANH和CANL达到相同的电压电平方面起着非常重要的作用。如果没有端接电阻,收发器的内部共模电压缓冲器仍然可以将CANH和CANL连接在一起,但速度要慢得多。总线上的容性负载也会减慢CANH和CANL电压的合并速度。当控制器向TXD发送脉冲时,如果隐性间隔不够长,差分电压(CANH – CANL)连续10个脉冲周期低于输入低阈值(RXD在10个TXD脉冲中保持低电平),则将报告传输故障故障。这也意味着如果TXD高电平时间过长,CAN总线信号可能进入隐性模式,RXD将变为高电平,不会报告传输故障故障。检测传输故障故障的推荐最小TXD脉冲频率为200kHz。
故障检测算法
Maxim开发了一种算法,能够利用MAX33011E可靠地检测CAN总线上的故障条件,而不会中断正常的CAN通信。以下所有示例 Mbed 代码都是为 NUCLEO-F303K8 平台开发的。®
通常,CAN网络的每个节点都使用带有CAN外设的微控制器。要执行故障检测,微控制器的 TXD 和 RXD 引脚必须配置为 GPIO,以对 TXD 信号进行位冲击并从 RXD 读取故障代码。需要中断引脚连接到MAX33011E的故障信号。
为避免中断正常通信,该算法在进入故障检测模式前需要对通信故障进行强指示。如果发生以下情况之一,算法将进入故障检测模式:
故障很高。
发射器生成误码帧。
发射器错误计数器升至255以上,节点进入总线关闭状态。
以下示例代码在上述任何条件变为 GP 时将微控制器引脚配置为 GPIO。
我们使用STM32F303K8 MCU作为CAN控制器。此参考代码是在 Mbed-OS 上开发的,Mbed-OS 是一个免费的开源嵌入式操作系统。有关更多详细信息,请访问:https://os.mbed.com/mbed-os/
Mbed 提供 API 将微控制器的 IO 配置为数字输入/输出引脚。也可以使用任何其他类似的低级 API。
DigitalOut txd (PA_12); // Configures PA_12 of MCU (TXD of CAN controller) as digital o/p pin DigitalIn rxd (PA_11); // Configures PA_11 of MCU (RXD of CAN controller) as digital i/p pin
在故障检测模式下,应使用2μs TXD正脉冲。在正脉冲之后,只要需要处理算法,TXD 就可以保持低电平。这使得故障检测电路能够可靠地检测过流和传输故障故障。为确保TXD脉冲宽度准确,应使用定时器。下面是设置计时器的示例代码。
首选低级 API 来配置分辨率为 2μs 的定时器。Mbed 定时器提供最低 8μs 分辨率。在本例中,使用了STM2F32K303控制器中的TIM8定时器。有关寄存器设置说明的更多详细信息,请参阅STM32F303K8编程手册。
static TIM_HandleTypeDef s_TimerInstance = { //Creates a timer instance (TIM2) . Instance = TIM2 }; __HAL_RCC_TIM2_CLK_ENABLE (); //Enable TIM2 APB clock (72MHz) s_TimerInstance.Init.Period.Prescalar = 16; //Set the counter prescalar value s_TimerInstance.Init.CounterMode = TIM_COUNTERMODE_UP; // Set the counter in "UP" mode s_TimerInstance.Init.Period = 500; //Set the counter period s_TimerInstance.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; // Set the clock divisor value to none s_TimerInstance.Init.RepetitionCounter = 0; //Disable the auto-reload HAL_TIM_Base_Init(&s_TimerInstance); // Initializes TIM base unit according to specified parameters HAL_TIM_Base_Start(&s_TimerInstance); //Start the timer in time-base mode
如果故障变为高电平,则在CAN报文传输中,它随时可能变为高电平。这意味着消息最有可能在 FAULT 为高电平后结束,因此从下一个故障检测周期读取错误代码更可靠。故障变为高电平后,CAN外设引脚配置为GPIO。故障检测算法将重复产生2μs TXD正脉冲,直到FAULT引脚上升沿后RXD变为高电平。建议在TXD的下降沿之后对RXD进行采样。RXD变为高电平后,还需要五个TXD脉冲来移出故障代码。另外<>个TXD脉冲用于禁用故障检测。下面是 FAULT 变高时的算法示例代码:
InterruptIn fault (PA_0); //Configure Fault pin as interrupt pin fault.rise(&fault_init); // Attach an interrupt callback function when fault pin goes high int state=0; // This is the state of state machine for fault detection void fault_init() { fault.rise (NULL); //Detach an interrupt till state machine gets completed toggle_txd_i_ticker.attach_us(&toggle_txd_i,6); // Initiate a state machine to detect a fault, each cycle is 6us } void toggle_txd_i() { DigitalOut txd(PA_12); //Configure CAN TXD pin as digital o/p DigitalIn rxd(PA_11); // Configure CAN RXD pin as digital i/p DigitalIn fault_pin(PA_0); //Configure fault pin as digital i/p int status = fault_pin.read(); //Fault pin status is stored in status variable static int count,N; do { //This code toggles TXD for 2us duration using TIM2 timer txd = 1; } while (__HAL_TIM_GET_COUNTER(&s_TimerInstance) < 9); txd=0; count++; switch (state ){ //State machine for fault detection case 0: // Ignore the first high fault, giving txd pulses to clear the fault without reading fault code if (count >= 26 && status == 0 ) { count = 0; state = 1; } break; case 1: // Fault pin is low and giving 100 fault pulses/waiting for fault pin to go High for second time if (count>=100 && status == 1 ) { count = 0; state = 2; } break; case 2: // Second time fault activated, need to read the fault code(10 pulses + 6 pulses to read the rxd + +10 pulses to clear the fault if (status == 1){ if( (rxd.read() == 1 || rxd_read == 1) && i<6) { arr[k] = rxd.read(); //Read RXD (fault code bit) and store in array k++; rxd_read = 1; //Flag to indicate that fault has been read i++; } } else if ( status == 0 ) { // Once fault pin becomes 0, move to state 3 fault_read = 1; rxd_read = 1; count = 0; state = 3; } break; case 3: if (status == 0) { InterruptIn fault (PA_0); //Configure fault pin as interrupt pin Fault.rise(&fautl_init); //Enable fault interrupt toggle_txd_i_ticker.detach(); //Disable state machine } break; } }
对于其他两种情况(误码帧和发射器错误计数>255),FAULT不一定会变高。该算法将CAN外设引脚配置为GPIO,并将重复产生2μs TXD正脉冲,直到RXD在故障上升沿后变为高电平。建议在TXD的下降沿之后对RXD进行采样。RXD变为高电平后,还需要五个TXD脉冲来移出故障代码。另外 110 个 TXD 脉冲禁用故障检测。如果 FAULT 在 <> TXD 脉冲后没有变为高电平,则表示未检测到故障,故障检测模式将退出。下面是该算法的示例代码:
在STM32F303K8 CAN控制器中,ESR(错误状态寄存器)具有7:0的发送器错误计数器[TEC]位。如果此计数器超过 255,则启动用于检测故障的状态机。此外,ESR 具有 2 位 LEC[2:0](最后一个错误代码)来指示错误条件,例如误码帧。
Int tec_count= ((CAN1->ESR) && (0x00FF0000))>>16; //Get the transmit error counter value from ESR register Int error_code= ((CAN1->ESR) && (0X00000070)>>4; //Get the error code value from ESR register if((tec_count >255) || (error_code !=0 )) { fault_init(); //Run the fault detection algorithm as implemented in above section }
审核编辑:郭婷
全部0条评论
快来发表一下你的评论吧 !