Hi TI Team,
I am having an issue with my CAN bus when a Bus Off interrupt fires and we get stuck. CAN communications at this point die and I can only recover with a processor reset.
Our Setup:
I am using a TI 28335. I have followed a configuration sequence following the SPRU 074F document section 3.2 as follows:
- Set GPIOs for CAN B
- Software reset of the device
- Set hardware for ECAN
- Enabled Auto Bus On mode
- Configure eCAN RX and TX pins
- Configure clock for 500k
- Configure transmit and receive mailboxes
- Clear global interrupt flags
- Setup interrupts
- RX mailboxes are set to create interrupts on message arrival
- TX mailboxes create interrupts on timeout
- Then away we go
Communications seems to operate fine most of the time. While we were submitting our equipment to EMI noise this creates so many errors on the bus that it goes into bus off mode. Once this interrupt fires we stop receiving RX interrupts while another device is actually sending messages but not getting responses.
This is my ISR code, not sure what I am missing.
void ECAN0INTB(void) { struct ECAN_REGS ECanbShadow; #ifdef DEBUG_GPIO GPIOManager_setDebugGpioState((DebugGpioIdType)DebugGpio_CAN_TX_ISR, On); #endif canOutgoingIsrCounter++; //----------------------------------------------------------- // Clearing CANGIF registers - SPRUEU1 document section 3.4.3.3 Step 1a and 1b-i to 1b-iv // There are a couple of interrupt signals what requires special processing like transmit timeout or bus off. // Then the flags are cleared by writing 1s to the bit signals. This is done by copying the content // of the register to the shadow here at the top, then after the special processing of signals of interest // we write the content back to the register which in turns clears any bit set. //----------------------------------------------------------- // Copy CAN control register to a shadow variable in a single 32-bit wide memory access ECanbShadow.CANGIF0.all = ECanbRegs.CANGIF0.all; ECanbShadow.CANMC.all = ECanbRegs.CANMC.all; // In the event the message time stamp counter overflowed clear the indication bit. // This should never happen as the time stamp counter is reset to 0 before every message // transmit operation used to detect transmit timeouts. if (ECanbShadow.CANGIF0.bit.TCOF0 == 1) { canTimestampOverflowCount++; // This indicates that the time stamp counter MSB got set ECanbShadow.CANGIF0.bit.TCOF0 = 1; ECanbShadow.CANMC.bit.TCC = 1; } // Handle Bus Off Mode - if Tx or Rx error counters ever exceed 255 the device may go bus off mode. // Here we handle it directly and return to Bus On, however this should auto recover as we set up the // device for auto bus on mode. if (ECanbShadow.CANGIF0.bit.BOIF0 == 1) { canBusOffModeCount++; // Clear CAN device bus off interrupt ECanbShadow.CANGIF0.bit.BOIF0 = 1; // Toggle CCR bit to return device to normal mode. CCR_Enable(); CCR_Disable(); } // Handle Transmit message timeout if (ECanbShadow.CANGIF0.bit.MTOF0 == 1) { canTxMailboxTimeoutCount++; // Set timeout flat to allow application to abort any outgoing response in progress. transmitTimedOut = true; // Clear Timeout bits ECanbShadow.CANTOS.all = ECanbRegs.CANTOS.all; ECanbRegs.CANTOS.all = ECanbShadow.CANTOS.all; // Write the same value we read above out to the register. // The bit that was set which got us in this ISR in the first // will be written back to 1 which clear the bit // Force out of Bus Off mode CCR_Enable(); CCR_Disable(); EALLOW; ECanbRegs.CANMC.all = ECanbShadow.CANMC.all; ECanbRegs.CANTSC = 0; // clear the running counter to make sure we do not get stuck in the ISR EDIS; } // Clear CANGIF register - write out the original content to clear the bits. ECanbRegs.CANGIF0.all = ECanbShadow.CANGIF0.all; EALLOW; ECanbRegs.CANMC.all = ECanbShadow.CANMC.all; EDIS; Clear & Re-Enable CPU Interrupts - SPRUEU1 document section 3.4.3.3 Step 2 to 4 PieCtrlRegs.PIEACK.bit.ACK9 = 1; // Enable PIE to drive a pulse into the CPU IER |= M_INT9; // Re-enable the CAN interrupt INT9 EINT; // Re-enable CPU Interrupts #ifdef DEBUG_GPIO GPIOManager_setDebugGpioState((DebugGpioIdType)DebugGpio_CAN_TX_ISR, Off); #endif }