This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

F29H85X-MCAL-SDK: CAN driver fails to send frames requested by TX confirmation callback

Part Number: F29H85X-MCAL-SDK

Hello,

In F29H85xMCAL-01.03.00, subroutine Can_CheckAllTxBuffers doesn't check if a frame TX request/arbitration stills pending before calling its own TX confirmation callback.

Therefore, a request delayed by a higher priority frame can be confirmed before its TX, during the call of Can_CheckAllTxBuffers triggered for the TX confirmation management of this higher priority frame. 

As I have not seen this issue listed in the fixed issue of F29H85xMCAL-01.04.01.02, I assume that it is still present there. Could you please check?


Best regards,
François.

  • Hi François,

    This API is called in CAN ISR. I remember the checking is done by the upper layer rather than the CAN driver.

  • Hello,

    I think I can add some context to this issue.

    While evaluating the F29H85x MCAL (F29H85xMCAL-01.03.00), we ported a legacy software.
    This software sends periodically segmented CAN frames.
    The first segment is sent by the user then the TX confirmation callback is in charge of sending subsequent segments.
    When only one segmented frame is active, the transmission completes successfully.
    However, when multiple segmented frames are active concurrently, only the frame with the highest priority (lower CAN ID) and faster sending rate successfully completes.
    The slower/lower-priority frames permanently stall.

    Our analysis was:
    • The faster frame delays the physical transmission of the slower frame on the bus, but the MCAL prematurely triggers the CanIf_TxConfirmation for the slower frame.
    • Because the upper layer immediately queues the next segment into a hardware buffer that is technically still transmitting the previous segment, the transmission sequence breaks and halts.

    To fix this, we modified the static code in Can_CheckAllTxBuffers to verify the live hardware state before calling CanIf_TxConfirmation.
    adding the following code inside the for loop that checks all transmit buffers.
    We mask out any buffers that are currently pending arbitration (MCAN_TXBRP) or have an active transmit request (MCAN_TXBAR).

    txStat = txStat & (~MCAL_LIB_REG_READ32(baseAddr + MCAN_TXBAR));
    txStat = txStat & (~MCAL_LIB_REG_READ32(baseAddr + MCAN_TXBRP));
    After this fix all frames work as expected.
    Of course we have only fixed our use case and done no deep analysis.
    Best regards
  • Hello Elidio,

    Many thanks for this additional background. That's very useful.

     : Could we please analyze this customer use case, identify the root cause of what seems to be a malfunction, and devise a fix or workaround?


    Best regards,
    François.

  • Hi François,

    I am trying to produce the issue with the MCAL driver.

  • This issue should be fixed in the new release. 

  • Unfortunately, the issue is not fixed.

    Same problem, same workaround.

    The routine still fails to properly handle a pending frame that has been sent during the transmission confirmation.

  • Thank you, Elidio.

     , could you please have an investigation initiated for this issue? Please let us know if more information is required from the customer.


    Best regards,
    François.

  • HI ,

    Have you tested with the latest version (26.00.00) MCAL driver?  

    https://www.ti.com/secureresources/F29H85X-MCAL-SDK

    or

    Secure resources | TI.com

    Can you share you test case for us to produce the issue easily? Thanks

  • Hello,

    Yes, I have tested the latest version of the MCAL driver (26.00.00) and can confirm that the issue persists.

    Some frames are being confirmed before they have been transmitted.

    In my current use case, I am periodically sending three segmented frames (each consisting of three segments) at intervals of 5ms, 10ms, and 100ms. Priorities are assigned accordingly, with the 5ms frame having the highest priority.

    The transmission logic is structured as follows:

    • The first segment of each frame is initiated from a task. If a higher-priority frame is not active, any lower-priority frame is suspended and resumed once the new frame completes during the TX confirmation ISR.
    • If a higher-priority frame is active, the transmission of the new frame is triggered by the TX confirmation of that frame's final segment.
    • Within the TX confirmation ISR, the handler is configured to send the next segment of the highest-priority ongoing frame.

    I have successfully reproduced this behavior using the Can_Example_Loopback example.

    In this acquisiton: first bye of each frame contains its counter of sent frames (should be FF, 0, 1 then reaches 2 but its not send )

    • Frame 21 : byte 0 contains counter of frame 21,  byte 1 contains counter of frame 22 and byte 2 contains counter of frame 23
    • Frame 22 : byte 0 contains counter of frame 22,  byte 1 contains counter of frame 22
    • Frame 23 : byte 0 contains counter of frame 23

    I obtain an unexpected behavior (counter of frame 23 goes from 1 to 3, and frame 21 is interrupted by 22 and 23)


    while I expect something like that (this is achieved with the fix from the first post)

    Regards

    Can_Example_Loopback.zip

  • Hello  : could you please look at this issue? This is bqsed on a TI example from the latest MCAL package.

    Thank you.

  • Hi Francois, QJ is currently on site with customer and unable to support E2E.  I will see if I can find another SME else it may need to wait until he returns in 1.5 weeks.

  • Hello Francois,

    TXBAR: Tx Buffer Add Request
    Writing 1 to this bit indicate that the hardware is ready to transmit the data from the buffer. Once hardware scans the buffer for transmission, it is cleared.

    TXBRP: Tx Buffer Request Pending
    After hardware does a Tx scan and realizes the buffer is ready for transmission, TXBRP bit is set. This bit is only cleared upon successful transmission or cancellation.

    TXBTO: Tx Buffer Transmission Occurred
    This bit is set when hardware successfully transmits the message and cleared when a new TXBAR occurs.

    When you are in CanIf_TxConfirmation for any given Tx buffer, ideally

    TXBAR = 0 (cleared after Tx Scan)

    TXBRP = 0 (successful transmission clears this bit)

    TXBTO = 1 (indicates successful transmission)

    Hence with CanIf_TxConfirmation, it is unlikely to have TXBAR or TXBRP to be set as well.

    Can_CheckAllTxBuffers function is called with the status of MCAN_TXBTO.

    Only after successful transmission, CanIf_TxConfirmation is called. So, it is unlikely that the software can dispatch the CanIf_TxConfirmation pre-maturely.


    I will continue to understand the use case and debug further, in the meantime, can you please check following points in application code.
    #1. Avoid calling another Can_write in CanIf_TxConfirmation, instead you can set a Can_FramePending flag and the call the actual Can_Write in Task if flag is set. (Experiment to figure out stale values in register)
    #2. Increment the data byte before calling the Can_write. (Is this what you mean to do?)

    During your debugging have you observed TXBTO and (TXBAR or TXBRP) set at the same time?

  • Hello,

    Thank you for your feedback. I would like to clarify a few points regarding my use case:

    #1 - Calling Can_Write in a task: This approach will probably work but is not a viable solution for my application, as it would severely limit the CAN bandwidth. While my example only involves 3 segments, the actual implementation can have significantly more.
    #2 - Relevance of the data byte: The specific data byte used in the example is not relevant to the application itself. It is simply there to demonstrate the anomaly: without the fix, the system generates up to 5 confirmations for 3 transmitted frames. With the fix applied, it correctly generates exactly 3 confirmations for the 3 frames.


    Regarding your question: "During your debugging have you observed TXBTO and (TXBAR or TXBRP) set at the same time?"

    Yes, absolutely. Observing this exact condition is the reason for implementing the fix in Can_CheckAllTxBuffers.

    To verify this behavior, I added a diagnostic counter within Can_CheckAllTxBuffers for this specific condition, and I can confirm that the counter does indeed increase.

    Since a CAN frame with a high ID cannot access the CAN bus while a frame with a lower ID is transmitting, delays and collisions are expected during high-rate transmissions.

    Regards

  • Hello Elidio Moas,

    I am not able to reproduce the same error scenario where more than one of BTO, BAR and BRP bits are set. (Using the example code shared in this thread earlier)
    Can you please provide below information:

    #1. How have you implemented Exclusive Area for CAN i.e. SchM_Enter_Can_CAN_EXCLUSIVE_AREA_1/ SchM_Exit_Can_CAN_EXCLUSIVE_AREA_1
    #2. Are you running in Release mode or Debug Mode? (If there are any compiler or linker options specific to your example, please provide the details)
    #3. Are you loading the application from RAM or FLASH?
    #4. I do not see any interrupts configured in Os_Cfg files. How are you configuring/initializing the interrupts? What is the category of interrupts that you are using? (To understand the dispatch time required for interrupt, priority, nesting etc.)

  • Hello

    #1 - I use the stub from MCAL therefore protection is MCAL_LIB_DINT/MCAL_LIB_EINT

    #2 - -O2 or -O1 and fastmath

    #3 - Loading from RAM

    #4 - Interrupts are CAN_MCANA_ISR_CAT1_INT

    I would like to bring a specific technical scenario to your attention regarding the Can_CheckAllTxBuffers function.

    Can_CheckAllTxBuffers to parse the copy of the MCAN_TXBTO register (txStat) using a for-loop that iterates from LSB to MSB, covering the mailboxes for frames 0x20 through 0x23..

    If a request made by my pseudo-task for 0x23 is pending, the notification for the last segment of frame 0x21 triggers a new transmission request for 0x23.

    This action sets the corresponding bits in MCAN_TXBRP and txPendingStatus via Can_Write.

    While it successfully clears the bit in the hardware MCAN_TXBTO register, the local copy (txStat) used by the loop is not updated.

    As a result, this bit is tested in the next iteration of the same loop using the stale value, which incorrectly triggers a TX confirmation notification for frame 0x23.

    This scenario only requires at least segment of 0x23 has been previously send (setting the corresponding bit in MCAN_TXBTO).

    Find enclosed the CCS workspace I used.

    Regards.

    Can_Example_loopback_F29H85x.zip

  • Hello Elidio Moas,

    Please find my response to above sequence:

    Can_CheckAllTxBuffers to parse the copy of the MCAN_TXBTO register (txStat) using a for-loop that iterates from LSB to MSB, covering the mailboxes for frames 0x20 through 0x23

    - When we enter in ISR, we save the status registers and use the same status throughout the ISR. If the status is changing after capturing, that will be processed in next ISR. 

    If a request made by my pseudo-task for 0x23 is pending, the notification for the last segment of frame 0x21 triggers a new transmission request for 0x23.

    - In ISR of 0x21, BTO for both 0x21 and 0x23 is set

    - During TxConfirmation of 0x21, a new message transmission for 0x23 is initiated. Please note that, at this point the old message on 0x23 is already sent by hardware and we must receive the confirmation of the old transmission as well. When new transmission for 0x23 is initiated, BAR then BRP then BTO will sequentially set and will be processed in subsequent ISR.

    This action sets the corresponding bits in MCAN_TXBRP and txPendingStatus via Can_Write.

    -New message is accepted because the hardware buffer is ready to transmit the new message. Old message was transmitted successfully only the confirmation is pending.

    While it successfully clears the bit in the hardware MCAN_TXBTO register, the local copy (txStat) used by the loop is not updated.

    - This is expected because the old tx message was actually sent out by hardware and hence user must receive the confirmation for it. 

    As a result, this bit is tested in the next iteration of the same loop using the stale value, which incorrectly triggers a TX confirmation notification for frame 0x23.

    - This notification is correct as 0x23 message was actually sent out by hardware.

    ___________________________________________________________________

    #1. I counted number of messages successfully transmitted by hardware and number of TxConfirmations received, they exactly match. There are no extra TxConfirmations.

    #2. You were seeing difference in TXBAR, TXBRP and TXBTO because you were comparing stale TXBTO with latest TXBAR and TXBRP.

    ___________________________________________________________________

    Please let me know if this addresses your concern, if not we can schedule a meeting to discuss further.

  • Hello

    If it makes it clearer a frame 0x22 could be transmitting while 0x23 is waiting for the bus.

    My point is I send a frame 0x23  using Can_write during the notification of the frame 0x21.

    Therefore I expect a notification for this new frame after 110µs (at 1000Mbps).

    txStat is not cleared (since the last correct notification of 0x23) by this new frame and will not be until the next ISR.

    txPendingStatus has been set immediatly by Can_write.

    The current iteration of the for-loop manages frame 0x21 then the next iteration will manage the frame 0x22 and the next one the frame 0x23.

    As (bitPos == (canCntrlObj->txPendingStatus & bitPos)) and (bitPos == (txStat & bitPos)) are true, this new iteration will call the notification for frame 0x23 even if it is not sent yet.

    In this notification I'm supposed to be able to send the new frame segment of frame 0x23 as this notification is supposed to be called only when the frame TX is completed.

    However, since the transmission is not actually complete, the mailbox remains busy, and the operation fails.

    Regards

  • Are you expecting that if you are sending new message in TxConfirmation, the old message should not get txConfirmation and only new message should?

  • 1. The confirmation for the old 0x23 frame is received a few milliseconds prior, which is correct.
    2. The confirmation for message 0x21 is also received as expected.
    3. However, during the ISR for frame 0x21, I am also receiving a confirmation for the new 0x23 frame (which was just written to the mailbox).

    This is unexpected behavior, as the notification for frame 0x23 should only occur once the frame has actually been sent.

    Our internal software has functioned correctly for years across several microcontrollers and MCAL providers, so we did not expect this issue to arise.

    Regards

  • Hello Elidio Moas,

    Thank you for clarification and patience.

    Now we fully understand the use case and the issue of stale snapshot. The workaround that you proposed earlier will solve the issue without any side effects.

    txStat = txStat & (~MCAL_LIB_REG_READ32(baseAddr + MCAN_TXBAR));
    txStat = txStat & (~MCAL_LIB_REG_READ32(baseAddr + MCAN_TXBRP));
    This issue will only happen in interrupt mode, no update necessary for polling.
    We will continue to do thorough testing with this fix and let you know if there is any change in fix.
    The fix will be included in 26.00.01 release targeted by end of June.