┬ÁTasker Forum

┬ÁTasker Forum => ┬ÁTasker general => Topic started by: AlexS on January 14, 2020, 01:08:08 PM

Title: CAN TX Timeout
Post by: AlexS on January 14, 2020, 01:08:08 PM

Using uTasker (with excellent results) on an automotive project. On the CAN-side of things I'm seeing a peculiar behaviour in a specific corner case. The corner case is one where my device is the only device switched on the CAN bus with another, that should receive my messages, being turned on a few seconds later. What happens is that the TX buffers quickly get filled up, but, oddly, they don't ever timeout, contrary to what's described in the documentation. The documentation suggests that the buffers will be freed after a certain number of retries.

After looking through the code, I noticed that the CAN_TX_BUF_ACTIVE flag is only cleared in case there's no ACK coming, not if the message can't be sent. Page 10 of the uTasker CAN documentation suggests that the expected behaviour is for the buffer to be returned to an inactive state by the driver, informing the application that the message couldn't be delivered.

        if ((ulError & CAN_ACK_ERR) != 0) {                              // a transmission received no ack
            while (i-- != 0) {
                if ((ptrCanQue->ucMode & CAN_TX_BUF_ACTIVE) != 0) {      // this buffer is presently transmitting a message
                    if (++(ptrCanQue->ucErrors) >= MAX_TX_CAN_TRIES) {   // we allow a few attempts before quitting (it also filters counting normal active buffers)
                        ptrMessageBuffer->ulCode_Len_TimeStamp = ((ptrMessageBuffer->ulCode_Len_TimeStamp & ~CAN_CODE_FIELD) | MB_TX_INACTIVE); // stop transmission
                        can_error_int_message[MSG_DESTINATION_TASK] = ptrCanQue->TaskToWake;
                        if ((ptrCanQue->ucMode & CAN_TX_BUF_REMOTE) != 0) {
                            can_error_int_message[MSG_INTERRUPT_EVENT] = CAN_TX_REMOTE_ERROR;
                            ptrCanQue->ucMode = (CAN_TX_BUF | CAN_RX_BUF_FULL | CAN_TX_BUF_REMOTE); // mark that it is an errored transmission buffer
                        else {
                            can_error_int_message[MSG_INTERRUPT_EVENT] = CAN_TX_ERROR;
                            ptrCanQue->ucMode = (CAN_TX_BUF | CAN_RX_BUF_FULL); // mark that it is an errored transmission buffer

Title: Re: CAN TX Timeout
Post by: mark on January 15, 2020, 02:07:28 PM

What is the state of the bus that doesn't allow the frame to be sent?
Do you see that there is an error interrupt that occurs that could be used to clear the buffer?

If it is a passive error (never can send and continuously waits until it can) it may be necessary to monitor with an application timer and subsequently abort/flush buffers.


Title: Re: CAN TX Timeout
Post by: AlexS on January 15, 2020, 02:27:05 PM
Very happy to monitor with the application, but not sure how I can abort and flush the buffers. It is indeed a passive error, where the other device on the bus (and the termination resistor as a consequence) are not active initially after my device starts.

Title: Re: CAN TX Timeout
Post by: mark on January 16, 2020, 03:46:18 PM
Hi Alex

I will look into a method to identify and clear blocked tx buffers - it has been quite some time since working at the CAN driver level so I'll need a little time to refresh on the details.


Title: Re: CAN TX Timeout
Post by: AlexS on January 17, 2020, 06:13:57 AM
Thanks, Mark! Looking forward to it as it's a bit of a blocker at the moment. :) I did a bit of my own digging and it seems like there's no code path to handle a flush request on a CAN interface.  As you know I'm on the old uTasker version (Jan 2019), so not sure if you've added anything in between.

Title: Re: CAN TX Timeout
Post by: AlexS on January 30, 2020, 11:13:55 AM
Hi Mark,

Did you get a chance to look into this? If not, I'll just modify my code so that the first set of messages always go with TX_ACK set on and do that.
Title: Re: CAN TX Timeout
Post by: mark on February 03, 2020, 02:30:24 AM
Hi Alex

I have added a call that you can test (my tests on a K66 were Ok but I don't know whether the situation/state is identical to yours).

Assuming you have set a CAN tx output handle with 5  buffers and you find that all 5 buffers are blocked (they will presumably be attempting to transmit but can't due to the state of the bus - you may also be receiving error events, but maybe not) you can use the flush method:

Code: [Select]
        QUEUE_TRANSFER freed = fnFlush(CAN_interface, FLUSH_RX);
        fnDebugDec(freed, 0);
        fnDebugMsg(" Tx buffers freed\r\n");

It will return the number of blocked tx buffers found belonging to this handle - 5 if all were freed - and afterwards the buffers are available for use again.

You will need to enable
Code: [Select]
#define SUPPORT_FLUSH                                                // allow flush command to be usedin config.h to use the driver flush command.

I'll send you the modified files per mail so you can verify that the method is suitable; if all goes well I'll then check it into the repository.