Part Number: TMS320F28335
We have a problem with re-initializing eCAN where we are waiting for the CCE bit to set after issuing a CCR request. It hangs in an infinite loop. We configure CAN for 125Kbaud and attempt to communicate with an old device. If there is no response, we reconfigure for 500Kbaud and attempt to communicate with a newer device. This configuration has worked for many years but is now failing. The first initialization after powerup always succeeds, the re-initialization now fails. The cause appears to be due to a race condition that with recent code changes, we are now failing.
The remote device is powered by the local device, so both power up at the same time. The remote device performs its power up initialization and then starts trying to communicate with the local device sending packets every 1 millisecond. Up to now, the local device was able to complete its check for the old style device and configure itself for the new device before the remote device started communicating. But now, it appears that the local device is trying to re-initialize while the remote device is communicating and the CCE bit never sets.
The code itself is very old. It was ported to the F28335 from an F2812 system. It was originally developed with Code Composer 3 and uses DSP/BIOS. Here is the initialization function:
void CAN_init(int kBaud, CAN_pIsr pISR)
{
int mbx;
Uns old;
unsigned long baud = kBaud;
// unsigned long baud = kBaud*2000UL;
unsigned long brp;
unsigned int bt = 15;
unsigned long sam=0;
unsigned long sjw=0;
unsigned int SpPercent = 80;
unsigned long tseg1;
unsigned long tseg2;
Overwrite = ~0;
brp = ((SYSCLKOUT * 500UL)/(baud*bt))-1;
// brp = ((SYSCLKOUT * 1000000UL)/(baud*bt))-1;
bt--;
tseg1 = ((SpPercent*bt)/100);
tseg2 = bt-tseg1;
tseg1--;
tseg2--;
ISR = pISR;
for (mbx = 0; mbx < NUM_MAILBOXES; mbx++){
mbxISR[mbx] = NULL;
}
asm(" EALLOW");
old = DisableInterrupts();
CANMC |= SRES; // master reset
if (kBaud && brp>=1 && brp<=255 && sjw<=3 && sam<=1 && tseg1<=15 && tseg2<=7 && tseg2<=tseg1){
PCLKCR |= ECANENCLK;
GpioCtrlRegs.GPAPUD.bit.GPIO18 = 0; // Enable pull-up for GPIO18 (CANRXA)
GpioCtrlRegs.GPAPUD.bit.GPIO19 = 0; // Enable pull-up for GPIO19 (CANTXA)
GpioCtrlRegs.GPAQSEL2.bit.GPIO18 = 3; // Asynch qual for GPIO18 (CANRXA)
GpioCtrlRegs.GPAMUX2.bit.GPIO18 = 3; // Configure GPIO18 for CANRXA operation
GpioCtrlRegs.GPAMUX2.bit.GPIO19 = 3; // Configure GPIO19 for CANTXA operation
RestoreInterrupts(old);
CANTIOC |= TXFUNC;
CANRIOC |= RXFUNC;
CANMC |= CCR | SCB | ABO | DBO;
asm(" EDIS");
while(!(CANES & CCE))
Sleep(1);
asm(" EALLOW");
CANBTC = (brp<<16)+(sjw<<8)+(sam<<7)+(tseg1<<3)+tseg2;
CANMC &= ~CCR;
CANMIL = 0xffffffff; // Set all mailbox interrupts to line 1, CAN_isr1()
// CANGIM = 0x00007f03; // Set which conditions will generate an interrupt
CANGIM = 0x00000803; // Set which conditions will generate an interrupt
asm(" EDIS");
while((CANES & CCE))
Sleep(1);
old = HWI_disable();
PIEACK = M_INT9; // Acknowledge INT9 interrupt to PIE
PIEIER9 |= INTx5; // Enable Peripheral Interrupt 9_5
PIEIER9 |= INTx6; // Enable Peripheral Interrupt 9_5
IER |= M_INT9; // Enable CPU Interrupt 9
HWI_restore(old);
}
else{
PCLKCR &= ~ECANENCLK;
RestoreInterrupts(old);
}
}
I found a bug in this code where the else clause doesn't issue an EDIS under a "disable" condition (zero baud), but this does not impact the issue. The DisableInterrupts/RestoreInterrupts functions disable all but the highest priority interrupt. I can try to rearrange our code to win the race again, but I would like to come up with a concrete solution that doesn't rely on luck. Any suggestions?