1

I want to transmit CAN frames on a Kinetis KE06. When I send the frame its payload is total junk. I have confirmed the wrong data in loopback mode and with a logic analyzer (connected to tranceiver TX pin). The identifier (both standard and extended) is always correct and the length is always correct. Junk payload stays always the same, but differs across power cycles.

This is my transmit code:

static void can_transmit(uint32_t identifier, bool identifier_is_extended,
    const uint8_t *payload, uint8_t payload_length) {

uint8_t empty_buffer_mask = MSCAN->CANTFLG & MSCAN_CANTFLG_TXE_MASK;
if (!empty_buffer_mask) {
    debugf("TX busy, dropping frame");
    return;
}

//select transmit buffer
MSCAN->CANTBSEL = MSCAN_CANTBSEL_TX(empty_buffer_mask);
debugf("Buffers available %02X selected %02X, payload length %d", empty_buffer_mask, MSCAN->CANTBSEL, payload_length);

if (identifier_is_extended) {
    MSCAN->TEIDR0 = identifier >> 21;
    MSCAN->TEIDR1 = ((identifier >> (20/*source bit position*/- 7/*destination bit position*/))
            & MSCAN_TEIDR1_TEID20_TEID18_MASK)
                    | ((identifier >> (17 - 2)) & MSCAN_TEIDR1_TEID17_TEID15_MASK)
                    | MSCAN_TEIDR1_TEIDE_MASK;
    MSCAN->TEIDR2 = identifier >> 7;
    MSCAN->TEIDR3 = identifier << 1; //TODO: check the RTR flag
} else {
    MSCAN->TSIDR0 = (uint8_t) (identifier >> 3); //this register holds bits 10-3 of the ID
    MSCAN->TSIDR1 = (identifier & 0x7) << MSCAN_TSIDR1_TSID2_TSID0_SHIFT;
    MSCAN->TSIDR1 |= MSCAN_TSIDR1_TSRTR_MASK; //set remote transmit request flag
 // ^^^^^^^^^ THIS IS WRONG - see answer ^^^^^^^^^^^^
}

for (uint8_t i = 0; i < 8; i++){
    MSCAN->TEDSR[i] = i; //transmit fixed data
    debugf("TEDSR[%ld] = %02X", i, MSCAN->TEDSR[i]);
}

MSCAN->TDLR = 8;//payload_length;
MSCAN->TBPR = 0; //priority of this buffer

_rx_busy = false;

//enable transmission of this buffer
uint8_t transmit_flag = MSCAN->CANTBSEL & MSCAN_CANTFLG_TXE_MASK;
debugf("transmit flag = %02X", transmit_flag);
MSCAN->CANTFLG = transmit_flag;
}

It seems like the write to TEDSR does not take effect. What am I doing wrong?

filo
  • 8,801
  • 1
  • 25
  • 46
  • To help in debug, replace the i with the letter A (in the "for" loop). This will really be "fixed" data. – Guill Jul 13 '17 at 22:40

2 Answers2

2

I made a dummy project using Processor Expert with a CAN driver, then I descended through all abstraction lasagna layers down to the abyss. I copied piece-by-piece parts of my driver into PE's driver until it started sending junk.

I found out that I was setting the RTR bit needlessly (remote transmit request/remote frame). I did not even want to send a remote frame in the first place...

A CAN remote frame has no payload and when sending such frame MSCAN length register must be zero. If RTR bit is set and length is not zero then junk is being sent.

filo
  • 8,801
  • 1
  • 25
  • 46
  • 1
    Well done for finding the problem! (+1) FYI that process which you followed, of starting with minimal "template" code, then adding the smallest amount of "suspect" code until the problem starts, is the "Restart from scratch" step in the "Minimal" part of the process explained in the Stack Exchange MCVE guide: "[How to create a Minimal, Complete, and Verifiable example](https://stackoverflow.com/help/mcve)". While that is only one debugging approach, and there are many others, I thought that might be a useful link. – SamGibson Jul 15 '17 at 19:16
  • This is not entirely correct. You can set the RTR bit and still specify a DLC which is not 0. Regardless of the DLC value, no data will be sent. Therefore, after receiving the frame, rx data registers will contain garbage since no data was transmitted. Sometimes RTR frames are used with a DLC that corresponds to the data length of the requested data frame. – Lundin Aug 11 '17 at 08:56
0

I'm not familiar with this part but there are a couple hints in the RM:

  • read/write to TDSER is blocked unless buffer is marked empty
  • normally hardware marks TXE after transmission

A guess, but perhaps you need to prime the pump by writing 1 to TXE? There may be a hidden (shadow) value of TXE behind the one you read to identify the buffer; I ran into similar issues with other parts in this family (but not the CAN controller).

Hope that helps, Best Regards, Dave

Dave Nadler
  • 176
  • 3