I have the following code in my application and every so often, the code gets stuck in the while loop. There seems to be no discernible pattern - sometimes the code just gets stuck there.
if (CAN0TFLG != 0x07)
{
CAN0TARQ = 0x07; // abort the transmission
while (!CAN0TAAK)
{
; // Wait for the message transmission to be aborted
}
}
The above code is actually a smaller piece to a bigger picture. My device requests OBD II data from a vehicle via the CAN bus. It sends messages to the vehicle and then listens for the response(s) from the vehicle. Since there are several addresses that I need to query to get the information I'm looking for, I have to change the CAN filters in order to be able to receive the responses from the different addresses. Normally, the CAN filters are configured such that no CAN filter hits are generated. They are effectively closed. I only open them up when I need to request a certain parameter and at that point, they are configured based on the address of the parameter I'm requesting.
Changing the CAN filters on the fly requires entering initialization mode. According to the data sheet, the best practice is to enter sleep mode before entering initialization mode to avoid CAN bus violations. My code currently does that. Before attempting to enter sleep mode, I check for and abort any ongoing transmissions. This must be done in order to enter sleep mode. I first found the need for aborting an ongoing transmission when my device attempted to connect to the vehicle's CAN bus. My device attempts to connect to the vehicle at CAN speeds of 250k and 500k using 11 and 29 bit identifiers. When my device attempted to connect to a 11 bit CAN 500k vehicle via 11bit CAN at 250k, it determined the CAN speed was wrong, but when it attempted to enter sleep mode, it got stuck in the busy wait loop waiting for sleep mode to be entered. I believe this was caused by error frames being generated on the bus since my device was transmitting at the wrong baud rate.
Once I added code to abort any ongoing transmissions before entering sleep mode, things seemed to work great for a while. Then I ran into the issue where the code gets stuck in the while(!CAN0TAAK) loop sometimes. I think what is happening is that at the moment I enter the if(CAN0TFLG != 0x07) statement, there is a transmission in progress and by the time the code attempts to abort the transmission, the transmission has completed so there is nothing to abort. Since there is now nothing to abort, the code gets stuck in the loop waiting for CAN0TAAK to get set.
Now the question is why would there be a transmission in progress at this point that would cause the code to enter the if(CAN0TFLG != 0x07) statement. By the time the code execution gets to the if(CAN0TFLG != 0x07) check, my device has already sent it's request and received a response so nothing else should be being sent and I would expect all of the transmit buffers to be empty, but there is obviously a situation where this is not true since the code is entering the if(CAN0TFLG != 0x07) statement.
Does anyone have any ideas as to what might be causing this behavior?
My code has the following flow:
.
. code elided
.
CAN message sent to vehicle
Wait for response from vehicle
CAN message received from vehicle
.
. code elided
.
EnterCAN0InitMode() is called that contains the following code:
if (CAN0TFLG != 0x07)
{
CAN0TARQ = 0x07;
while( !CAN0TAAK)
{
; // wait for the message transmission to be aborted
}
}
CAN0CTL0 |= SLPRQ; // Put the CAN controller to sleep before entering initialization mode to avoid CAN bus violations
while (!(CAN0CTL1 & SLPAK))
{
; // Wait for the CAN controller to go to sleep
}
CAN0CTL0 |= INITRQ // Set the INITRQ bit to request entrance into initialization mode
while (!(CAN0CTL1 & INITAK))
{
; // Wait for the CAN module to enter initialization mode
}
Here is my potential fix:
Replace this:
if (CAN0TFLG != 0x07)
{
CAN0TARQ = 0x07;
while( !CAN0TAAK)
{
; // wait for the message transmission to be aborted
}
}
with this:
while( !CAN0TAAK && (CAN0TFLG != 0x07)) // if we haven't aborted and CAN0TFLG is not 0x07, then that means a message is in the transmit buffer
{
CAN0TARQ = 0x07; // abort any ongoing transmission
}
Maybe little bit late but...
Do not use the CANTAAK to check the message was aborted, as there may be a case it was transmitted in fact so ABTAKn flag is not set. Instead use the CANTFLG; a TXEn is set when message is sent or aborted. Then the ABTAKn flag can be used to identify what was done. So try to use following code
if ((CAN0TFLG & 0x07) != 0x07)
{
CAN0TARQ = 0x07; //request to abort all transmit buffers
while ((CAN0TFLG & 0x07) != 0x07); //wait for the abort to be completed.
// you can check CAN0TAAK to see which was aborted
}
CAN0CTL0 |= SLPRQ; //request sleep mode
while (!(CAN0CTL1 & SLPAK)); //wait for acknowledge
…
Regarding entering the "if ((CAN0TFLG & 0x07) != 0x07)" statement; either you have some buffer flagged as ready for transmission (by clearing the associated TXE flag) or message was not transmitted successfully (without error).
Regards,
Petr
Thank you for your response. I hope to be able to try your suggestion soon. I will post back here when I am able to determine if your code has fixed my issue.
Thanks again