FlexCAN_T4 - FlexCAN for Teensy 4

Not familiar with the Analog Discovery 2. You need to set the CANL and CANH channels as analog input and not digital channel. You should then see the waveform.

Post your sketch here and I can check it for you.
 
Not familiar with the Analog Discovery 2. You need to set the CANL and CANH channels as analog input and not digital channel. You should then see the waveform.

Post your sketch here and I can check it for you.

The sketch is literally the
CAN2.0_example_FIFO_with_interrupts
code from the github with the ID modified be able to differentiate packets from one controller vs the other.

I’ll adjust the reading to be analog and update if that changes anything, though Im still not seeing any messages at the other transceiver being received, so I assume there is still some problem in that system.

Thanks
 
There are different versions of the example sketch. Can't check it for you if you don't post your sketch here.
 
There are different versions of the example sketch. Can't check it for you if you don't post your sketch here.

My bad! Hadn't realized there were different versions. Here is the sketch I'm using,

Code:
#include <FlexCAN_T4.h>
FlexCAN_T4<CAN1, RX_SIZE_256, TX_SIZE_16> Can0;

void setup(void) {
  Serial.begin(115200); delay(400);
  pinMode(6, OUTPUT); digitalWrite(6, LOW); /* optional tranceiver enable pin */
  Can0.begin();
  Can0.setBaudRate(1000000);
  Can0.setMaxMB(16);
  Can0.enableFIFO();
  Can0.enableFIFOInterrupt();
  Can0.onReceive(canSniff);
  Can0.mailboxStatus();
}

void canSniff(const CAN_message_t &msg) {
  Serial.print("MB "); Serial.print(msg.mb);
  Serial.print("  OVERRUN: "); Serial.print(msg.flags.overrun);
  Serial.print("  LEN: "); Serial.print(msg.len);
  Serial.print(" EXT: "); Serial.print(msg.flags.extended);
  Serial.print(" TS: "); Serial.print(msg.timestamp);
  Serial.print(" ID: "); Serial.print(msg.id, HEX);
  Serial.print(" Buffer: ");
  for ( uint8_t i = 0; i < msg.len; i++ ) {
    Serial.print(msg.buf[i], HEX); Serial.print(" ");
  } Serial.println();
}

void loop() {
  Can0.events();

  static uint32_t timeout = millis();
  if ( millis() - timeout > 200 ) {
    CAN_message_t msg;
    //msg.id = random(0x1,0x7FE);
    msg.id = 0x123; // This is the only change I've made
    for ( uint8_t i = 0; i < 8; i++ ) msg.buf[i] = i + 1;
    Can0.write(msg);
    timeout = millis();
  }

}

As far as I understand, this script simply sets up the interrupt based message receive using the FIFO buffer with no specific filter applied and sends a packet every 200 ms. I can see the packet being sent on the TX line off the Teensy, but not in the logic analyzer output. I'll also try and verify if the system can read analog signals properly now.

Edit with update on logic analyzer and analog signal:

I verified on the datasheet for the SN65HVD230 chip that the CANH and CANL lines are bound between 0 and 3.3 V, see the below screenshot:

SN65HVD230 Bus Voltages.jpg

According to the following post, this should work fine with the logic analyzer:

https://forum.digilent.com/topic/9669-logic-analyzer-from-oscilloscope/

Therefore I shouldn't need to make any adjustments for the CAN bus signals.
 
The sketch works on my system.

Have you got the same sketch running on the other Teensy ?
Configure your Analog Discovery 2 as an oscilloscope and connect it to CANL and CANH. Post some pictures of the waveform.

Post some photos Teensy setup.
 
The sketch works on my system.

Have you got the same sketch running on the other Teensy ?
Configure your Analog Discovery 2 as an oscilloscope and connect it to CANL and CANH. Post some pictures of the waveform.

Post some photos Teensy setup.

Here is a screenshot that shows both the oscilloscope reading from the CANH and CANL lines, which definitely don't look right, given that they barely seem to change and are both at the same voltage. CANL is connected to the yellow signal, CANH is connected to the blue, not that they are differentiable.

Scope and Pattern screenshot.jpg

I'll follow up shortly with a photo of the board, but for now here is a pinout that describes the connections, the Teensys are each labeled as Teensy 1 and Teensy 2 and they are connected to Transceiver 1 and Transceiver 2 respectively. There is also a ground net which I'll call GND Bus.

Teensy 1:
3V <-> Transceiver 1 3V3
23 (CRX1) <-> Transceiver 1 CRX
22 (CTX1) <-> Transceiver 1 CTX
GND <-> GND Bus

Teensy 2:
3V <-> Transceiver 2 3V3
23 (CRX1) <-> Transceiver 2 CRX
22 (CTX1) <-> Transceiver 2 CTX
GND <-> GND Bus

Transceiver 1:
CANH <-> Transceiver 2 CANH
CANL <-> Transceiver 2 CANL
3V3 <-> Teensy 1 3V
GND <-> GND Bus
CTX <-> Teensy 1 22 (CTX1)
CRX <-> Teensy 1 23 (CRX1)

Transceiver 2:
CANH <-> Transceiver 1 CANH
CANL <-> Transceiver 1 CANL
3V3 <-> Teensy 2 3V
GND <-> GND Bus
CTX <-> Teensy 2 22 (CTX1)
CRX <-> Teensy 2 23 (CRX1)

That should fully define the system, note the shared ground between all devices.

I'd love to find out I'm making a dumb wiring mistake, but I believe this is correct, the only thing I would think is missing would be the resistor connecting CANH and CANL, but that is built into the SN65HVD230 breakout board.

Edit:
It doesn't seem to want to allow me to add that board photo, not sure why but its either doing nothing when I attach it or giving an error, the above pinout is correct for what I've wired, I've check all wires to confirm continuity, so I'm confident that is not the issue.
 
Last edited:
oVexlz:

As is common on many of these CAN breakout boards (I am using the exact same one, but from a different source, still obtained from Amazon), if you haven't already noticed, the bottom silkscreen has incorrect pin names . . . a good reason maybe for you to double-check your wiring one more time.

Mark J Culross
KD5RXT
 
oVexlz:

As is common on many of these CAN breakout boards (I am using the exact same one, but from a different source, still obtained from Amazon), if you haven't already noticed, the bottom silkscreen has incorrect pin names . . . a good reason maybe for you to double-check your wiring one more time.

Mark J Culross
KD5RXT

As near as I can tell mine are correct, bottom and top silkscreen match and the pinout to the chip (as much as I can see) seem correct as well, though thank you for pointing that out, I'll keep that in mind for future since that's definitely the kind of thing I would not think to check.
 
Hello, I have issues receiving extended frames, not sure what the issue is. I have no problem receving or sending STD frames. No probelm to send EXT either. My setup is like bellow.

Can2.enableMBInterrupts();
Can2.setMBFilter(REJECT_ALL);
Can2.onReceive(MB0, callback1);
Can2.setMBFilter(MB0, 0x705,);

Can2.onReceive(MB1, callback2);
Can2.setMBFilter(MB1, 0x75);

Can2.onReceive(MB2, callback3);
Can2.setMBFilter(MB2, 0xF2, 0xF3, 0xF6);
Can2.enhanceFilter(MB2);

Can2.onReceive(MB3, callback4);
Can2.setMBFilter(MB3, 0x555);

Can2.onReceive(MB4, callback5);
Can2.setMBFilter(MB4, 0xE, 0xF);
Can2.enhanceFilter(MB3);

Can2.onReceive(MB5, callback6);
Can2.setMBFilter(MB5, 0x90A);
Can2.setMB(MB10, RX, EXT);

Can2.mailboxStatus() gives "MB5 code: RX_OVERRUN"

Removing "Can2.setMB(MB10, RX, EXT);" gives the result
MB5 code: RX_EMPTY (Standard Frame) also my Callback isnt triggered.

I also tried to disabled all extended msgs on the bus. Sending one message with ID 0x90A and status gives me that the MB is full, without callback being triggered.

Anyone have an idea what might be the issue?

Thanks in advance!
 
you already posted this as an issue on github. Don't set a filter then configure the mailbox. That is backwards. also post what mailboxStatus() shows
 
Sorry for positng it on multiple places. Lets follow the discussion here.

Thank you for your reply.

I put the "Can2.setMB(MB5, RX, EXT);" Before the filter.

mailboxStatus says that the MB is full. But my callback isnt triggered by the interrupt.

MB5 code: RX_FULL

void callback6(const CAN_message_t &msg)
{
Serial.println("new message");
for (int i=0; i<8; i++) {
Serial.println(msg.buf);
}
}
 
I have successfully built a CAN monitor utility which makes use of the excellent FlexCAN_T4 library. As written, it is currently able to receive & parse/decode both standard frames & ISOTP frames using interrupts. The functions for parsing/decoding the frame contents are quite involved & lengthy (the entire sketch is over 13000 SLOC). Occasionally, while parsing/decoding (& printing out the contents of) a standard frame, before the complete standard frame has been parsed/decoded, the parsing/decoding of an ISOTP frame is started. The result is the "parsing/decoding" of the ISOTP frame is embedded in the middle of the "parsing/decoding" of the standard frame. How would one go about making sure that the parsing/decoding of either type of frame is not interrupted by the other type of frame ??

The setup() function contains the following:

Code:
   Can1.begin();
   Can1.setBaudRate(CAN_baudrate_list[CAN_baudrate_index]);
   Can1.setMaxMB(16);
   Can1.enableFIFO();
   Can1.enableFIFOInterrupt();
   Can1.onReceive(can_sniff_RX);

   isotp1.begin();
   isotp1.setWriteBus(&Can1); /* we write to this bus */
   isotp1.onReceive(can_sniff_RX_isotp); /* set callback */


The loop() function contains the following:

Code:
   Can1.events();

And finally, here are the two parser/decoder callback functions (just FYI):

Code:
// callback to spit out contents of CAN receive frame
void can_sniff_RX(const CAN_message_t &msg)
{
   if (CAN_RX_mode != CAN_RX_MODE_ISOTP_ONLY)
   {
      Serial.print("RX: ");
      status_append_without_NL("RX: ");

      Serial.print("MBX: ");
      status_append_without_NL("MBX: ");

      if (msg.mb < 10)
      {
         Serial.print("0");
         status_append_without_NL("0");
      } else {
         status_append_without_NL((char)((msg.mb / 10) + '0'));
      }

      status_append_without_NL((char)((msg.mb % 10) + '0'));

      Serial.print(msg.mb);

      Serial.print("  LEN: ");
      status_append_without_NL("  LEN: ");

      if (msg.len < 100)
      {
         Serial.print(" ");
         status_append_without_NL(" ");
      } else {
         status_append_without_NL((char)((msg.len / 100) + '0'));
      }

      if (msg.len < 10)
      {
         Serial.print(" ");
         status_append_without_NL(" ");
      } else {
         status_append_without_NL((char)(((msg.len / 10) % 10) + '0'));
      }

      status_append_without_NL((char)((msg.len % 10) + '0'));

      Serial.print(msg.len);

      Serial.print("  EXT: ");
      status_append_without_NL("  EXT: ");

      Serial.print(msg.flags.extended);
      status_append_without_NL((char)(msg.flags.extended + '0'));

      Serial.print("  TS: ");
      status_append_without_NL("  TS: ");

      if (msg.timestamp < 10000)
      {
         Serial.print(" ");
         status_append_without_NL(" ");
      } else {
         status_append_without_NL((char)((msg.len / 10000) + '0'));
      }

      if (msg.timestamp < 1000)
      {
         Serial.print(" ");
         status_append_without_NL(" ");
      } else {
         status_append_without_NL((char)(((msg.len / 1000) % 10) + '0'));
      }

      if (msg.timestamp < 100)
      {
         Serial.print(" ");
         status_append_without_NL(" ");
      } else {
         status_append_without_NL((char)(((msg.len / 100) % 10) + '0'));
      }

      if (msg.timestamp < 10)
      {
         Serial.print(" ");
         status_append_without_NL(" ");
      } else {
         status_append_without_NL((char)(((msg.len / 10) % 10) + '0'));
      }

      status_append_without_NL((char)((msg.timestamp % 10) + '0'));

      Serial.print(msg.timestamp);

      Serial.print("  ID: 0x");
      status_append_without_NL("  ID: 0x");

      uint32_t i = 0xF0000000;
      for (int j = 7; j >= 0; j--)
      {
         Serial.print(((msg.id & i) >> (4 * j)), HEX);
         if (((msg.id & i) >> (4 * j)) <= 9)
         {
            status_append_without_NL((char)(((msg.id & i) >> (4 * j)) + '0'));
         } else {
            status_append_without_NL((char)((((msg.id & i) >> (4 * j)) - 10) + 'A'));
         }

         i = i >> 4;
      }

      Serial.print("  OVERRUN: ");
      status_append_without_NL("  OVERRUN: ");

      Serial.println(msg.flags.overrun);
      status_append_with_NL((char)(msg.flags.overrun + '0'));

      Serial.print("   MSG: ");
      status_append_without_NL("   MSG: ");

      for ( uint8_t i = 0; i < msg.len; i++ ) {
         Serial.print("0x");
         status_append_without_NL("0x");

         Serial.print((msg.buf[i] & 0xF0) >> 4, HEX);
         if (((msg.buf[i] & 0xF0) >> 4) <= 9)
         {
            status_append_without_NL((char)(((msg.buf[i] & 0xF0) >> 4) + '0'));
         } else {
            status_append_without_NL((char)((((msg.buf[i] & 0xF0) >> 4) - 10) + 'A'));
         }

         Serial.print(msg.buf[i] & 0x0F, HEX);
         if ((msg.buf[i] & 0x0F) <= 9)
         {
            status_append_without_NL((char)((msg.buf[i] & 0x0F) + '0'));
         } else {
            status_append_without_NL((char)(((msg.buf[i] & 0x0F) - 10) + 'A'));
         }

         Serial.print(" ");
         status_append_without_NL(" ");
      }

      Serial.println("");
      status_append_with_NL("");

      LED_timer = millis();
      analogWrite(LED_PIN, led_intensity_on);

      CAN_baudrate_match_found = true;
      CAN_baudrate_match_timeout = millis();

      if (CAN_baudrate_mode == CAN_BAUDRATE_MODE_HUNT_AND_STOP)
      {
         CAN_baudrate_mode = CAN_BAUDRATE_MODE_FIXED;

         report_current_baudrate();

         // save settings to EEPROM
         save_settings();
      }
   }

   if (msg.buf[0] <= 0x07)
   {
      if (CAN_RX_mode != CAN_RX_MODE_ISOTP_ONLY)
      {
         switch (msg.buf[1])
         {
            case 0x41:
            case 0x42:
               {
                  if (msg.buf[1] == 0x41)
                  {
                     Serial.println("      0x41: service 0x01 (Show current data) request response");
                     status_append_with_NL("      0x41: service 0x01 (Show current data) request response");
                  }

                  if (msg.buf[1] == 0x42)
                  {
                     Serial.println("      0x42: service 0x02 (Show freeze frame data) request response");
                     status_append_with_NL("      0x42: service 0x02 (Show freeze frame data) request response");
                  }

                  Serial.print("      0x");
                  status_append_without_NL("      0x");

                  Serial.print((msg.buf[2] & 0xF0) >> 4, HEX);
                  if (((msg.buf[2] & 0xF0) >> 4) <= 9)
                  {
                     status_append_without_NL((char)(((msg.buf[2] & 0xF0) >> 4) + '0'));
                  } else {
                     status_append_without_NL((char)((((msg.buf[2] & 0xF0) >> 4) - 10) + 'A'));
                  }

                  Serial.print(msg.buf[2] & 0x0F, HEX);
                  if ((msg.buf[2] & 0x0F) <= 9)
                  {
                     status_append_without_NL((char)((msg.buf[2] & 0x0F) + '0'));
                  } else {
                     status_append_without_NL((char)(((msg.buf[2] & 0x0F) - 10) + 'A'));
                  }

                  Serial.print(": PID 0x");
                  status_append_without_NL(": PID 0x");

                  Serial.print((msg.buf[2] & 0xF0) >> 4, HEX);
                  if (((msg.buf[2] & 0xF0) >> 4) <= 9)
                  {
                     status_append_without_NL((char)(((msg.buf[2] & 0xF0) >> 4) + '0'));
                  } else {
                     status_append_without_NL((char)((((msg.buf[2] & 0xF0) >> 4) - 10) + 'A'));
                  }

                  Serial.print(msg.buf[2] & 0x0F, HEX);
                  if ((msg.buf[2] & 0x0F) <= 9)
                  {
                     status_append_without_NL((char)((msg.buf[2] & 0x0F) + '0'));
                  } else {
                     status_append_without_NL((char)(((msg.buf[2] & 0x0F) - 10) + 'A'));
                  }

                  Serial.print(" - ");
                  status_append_without_NL(" - ");

                  decode_service_01_02_PID_title(STATUS_MODE, msg.buf[1], msg.buf[2]);

                  Serial.println("");
                  status_append_with_NL("");

                  decode_service_01_02_PID_content(msg);

                  Serial.println("");
                  status_append_with_NL("");
               }
               break;

            case 0x43:
               {
                  Serial.println("      0x43: service 0x03 (list DTCs) request response");
                  status_append_with_NL("      0x43: service 0x03 (list DTCs) request response");

                  Serial.println("");
                  status_append_with_NL("");
               }
               break;

            case 0x44:
               {
                  Serial.println("      0x44: service 0x04 (clear DTCs) request response");
                  status_append_with_NL("      0x44: service 0x04 (clear DTCs) request response");

                  Serial.println("");
                  status_append_with_NL("");
               }
               break;

            case 0x49:
               {
                  Serial.println("      0x49: service 0x09 (vehicle info) request response");
                  status_append_with_NL("      0x49: service 0x09 (vehicle info) request response");

                  Serial.print("      0x");
                  status_append_without_NL("      0x");

                  Serial.print((msg.buf[2] & 0xF0) >> 4, HEX);
                  if (((msg.buf[2] & 0xF0) >> 4) <= 9)
                  {
                     status_append_without_NL((char)(((msg.buf[2] & 0xF0) >> 4) + '0'));
                  } else {
                     status_append_without_NL((char)((((msg.buf[2] & 0xF0) >> 4) - 10) + 'A'));
                  }

                  Serial.print(msg.buf[2] & 0x0F, HEX);
                  if ((msg.buf[2] & 0x0F) <= 9)
                  {
                     status_append_without_NL((char)((msg.buf[2] & 0x0F) + '0'));
                  } else {
                     status_append_without_NL((char)(((msg.buf[2] & 0x0F) - 10) + 'A'));
                  }

                  Serial.print(": PID 0x");
                  status_append_without_NL(": PID 0x");

                  Serial.print((msg.buf[2] & 0xF0) >> 4, HEX);
                  if (((msg.buf[2] & 0xF0) >> 4) <= 9)
                  {
                     status_append_without_NL((char)(((msg.buf[2] & 0xF0) >> 4) + '0'));
                  } else {
                     status_append_without_NL((char)((((msg.buf[2] & 0xF0) >> 4) - 10) + 'A'));
                  }

                  Serial.print(msg.buf[2] & 0x0F, HEX);
                  if ((msg.buf[2] & 0x0F) <= 9)
                  {
                     status_append_without_NL((char)((msg.buf[2] & 0x0F) + '0'));
                  } else {
                     status_append_without_NL((char)(((msg.buf[2] & 0x0F) - 10) + 'A'));
                  }

                  Serial.print(" - ");
                  status_append_without_NL(" - ");

                  decode_service_09_PID_title(STATUS_MODE, msg.buf[2]);

                  Serial.println("");
                  status_append_with_NL("");

                  decode_service_09_PID_content(msg);

                  Serial.println("");
                  status_append_with_NL("");
               }
               break;

            case 0x50:
               {
                  Serial.println("      0x50: service 0x10 (CAN diagnostic session) request response");
                  status_append_with_NL("      0x50: service 0x10 (CAN diagnostic session) request response");

                  Serial.print("      0x");
                  status_append_without_NL("      0x");

                  Serial.print((msg.buf[2] & 0xF0) >> 4, HEX);
                  if (((msg.buf[2] & 0xF0) >> 4) <= 9)
                  {
                     status_append_without_NL((char)(((msg.buf[2] & 0xF0) >> 4) + '0'));
                  } else {
                     status_append_without_NL((char)((((msg.buf[2] & 0xF0) >> 4) - 10) + 'A'));
                  }

                  Serial.print(msg.buf[2] & 0x0F, HEX);
                  if ((msg.buf[2] & 0x0F) <= 9)
                  {
                     status_append_without_NL((char)((msg.buf[2] & 0x0F) + '0'));
                  } else {
                     status_append_without_NL((char)(((msg.buf[2] & 0x0F) - 10) + 'A'));
                  }

                  Serial.print(": PID 0x");
                  status_append_without_NL(": PID 0x");

                  Serial.print((msg.buf[2] & 0xF0) >> 4, HEX);
                  if (((msg.buf[2] & 0xF0) >> 4) <= 9)
                  {
                     status_append_without_NL((char)(((msg.buf[2] & 0xF0) >> 4) + '0'));
                  } else {
                     status_append_without_NL((char)((((msg.buf[2] & 0xF0) >> 4) - 10) + 'A'));
                  }

                  Serial.print(msg.buf[2] & 0x0F, HEX);
                  if ((msg.buf[2] & 0x0F) <= 9)
                  {
                     status_append_without_NL((char)((msg.buf[2] & 0x0F) + '0'));
                  } else {
                     status_append_without_NL((char)(((msg.buf[2] & 0x0F) - 10) + 'A'));
                  }

                  Serial.print(" - ");
                  status_append_without_NL(" - ");

                  if (msg.buf[2] == 0x03)
                  {
                     Serial.print("Extended CAN diagnostic session");
                     status_append_without_NL("Extended CAN diagnostic session");
                  } else {
                     Serial.print("unexpected PID");
                     status_append_without_NL("unexpected PID");
                  }

                  Serial.println("");
                  status_append_with_NL("");
               }
               break;

            case 0x7F:
               {
                  Serial.println("      0x7F: CAN service request - NAK response");
                  status_append_with_NL("      0x7F: CAN service request - NAK response");

                  Serial.print("      0x");
                  status_append_without_NL("      0x");

                  Serial.print((msg.buf[2] & 0xF0) >> 4, HEX);
                  if (((msg.buf[2] & 0xF0) >> 4) <= 9)
                  {
                     status_append_without_NL((char)(((msg.buf[2] & 0xF0) >> 4) + '0'));
                  } else {
                     status_append_without_NL((char)((((msg.buf[2] & 0xF0) >> 4) - 10) + 'A'));
                  }

                  Serial.print(msg.buf[2] & 0x0F, HEX);
                  if ((msg.buf[2] & 0x0F) <= 9)
                  {
                     status_append_without_NL((char)((msg.buf[2] & 0x0F) + '0'));
                  } else {
                     status_append_without_NL((char)(((msg.buf[2] & 0x0F) - 10) + 'A'));
                  }

                  Serial.println(" (service number requested)");
                  status_append_with_NL(" (service number requested)");

                  Serial.print("      0x");
                  status_append_without_NL("      0x");

                  Serial.print((msg.buf[3] & 0xF0) >> 4, HEX);
                  if (((msg.buf[3] & 0xF0) >> 4) <= 9)
                  {
                     status_append_without_NL((char)(((msg.buf[3] & 0xF0) >> 4) + '0'));
                  } else {
                     status_append_without_NL((char)((((msg.buf[3] & 0xF0) >> 4) - 10) + 'A'));
                  }

                  Serial.print(msg.buf[3] & 0x0F, HEX);
                  if ((msg.buf[3] & 0x0F) <= 9)
                  {
                     status_append_without_NL((char)((msg.buf[3] & 0x0F) + '0'));
                  } else {
                     status_append_without_NL((char)(((msg.buf[3] & 0x0F) - 10) + 'A'));
                  }

                  Serial.println(" (?? additional data)");
                  status_append_with_NL(" (?? additional data)");

                  Serial.println("");
                  status_append_with_NL("");
               }
               break;

            default:
               {
                  Serial.println("");
                  status_append_with_NL("");
               }
               break;
         }

         Serial.println("");
         status_append_with_NL("");
      }
   } else {
      switch (msg.buf[0])
      {
         case 0x10:
            {
               send_CAN_isotp_flow_control();

               if (CAN_RX_mode != CAN_RX_MODE_ISOTP_ONLY)
               {
                  switch (msg.buf[2])
                  {
                     case 0x41:
                     case 0x42:
                     case 0x49:
                        {
                           if (msg.buf[2] == 0x41)
                           {
                              Serial.println("      0x41: service 0x01 (Show current data) request response");
                              status_append_with_NL("      0x41: service 0x01 (Show current data) request response");
                           }

                           if (msg.buf[2] == 0x42)
                           {
                              Serial.println("      0x42: service 0x02 (Show freeze frame data) request response");
                              status_append_with_NL("      0x42: service 0x02 (Show freeze frame data) request response");
                           }

                           if (msg.buf[2] == 0x49)
                           {
                              Serial.println("      0x49: service 0x09 (vehicle info) request response");
                              status_append_with_NL("      0x49: service 0x09 (vehicle info) request response");
                           }

                           Serial.print("      0x");
                           status_append_without_NL("      0x");

                           Serial.print((msg.buf[2] & 0xF0) >> 4, HEX);
                           if (((msg.buf[2] & 0xF0) >> 4) <= 9)
                           {
                              status_append_without_NL((char)(((msg.buf[2] & 0xF0) >> 4) + '0'));
                           } else {
                              status_append_without_NL((char)((((msg.buf[2] & 0xF0) >> 4) - 10) + 'A'));
                           }

                           Serial.print(msg.buf[2] & 0x0F, HEX);
                           if ((msg.buf[2] & 0x0F) <= 9)
                           {
                              status_append_without_NL((char)((msg.buf[2] & 0x0F) + '0'));
                           } else {
                              status_append_without_NL((char)(((msg.buf[2] & 0x0F) - 10) + 'A'));
                           }

                           Serial.print(": PID 0x");
                           status_append_without_NL(": PID 0x");

                           Serial.print((msg.buf[3] & 0xF0) >> 4, HEX);
                           if (((msg.buf[3] & 0xF0) >> 4) <= 9)
                           {
                              status_append_without_NL((char)(((msg.buf[3] & 0xF0) >> 4) + '0'));
                           } else {
                              status_append_without_NL((char)((((msg.buf[3] & 0xF0) >> 4) - 10) + 'A'));
                           }

                           Serial.print(msg.buf[3] & 0x0F, HEX);
                           if ((msg.buf[3] & 0x0F) <= 9)
                           {
                              status_append_without_NL((char)((msg.buf[3] & 0x0F) + '0'));
                           } else {
                              status_append_without_NL((char)(((msg.buf[3] & 0x0F) - 10) + 'A'));
                           }

                           Serial.print(" - ");
                           status_append_without_NL(" - ");

                           if ((msg.buf[2] == 0x41) || (msg.buf[2] == 0x42))
                           {
                              decode_service_01_02_PID_title(STATUS_MODE, msg.buf[2], msg.buf[3]);
                           }

                           if (msg.buf[2] == 0x49)
                           {
                              decode_service_09_PID_title(STATUS_MODE, msg.buf[3]);
                           }

                           Serial.println("");
                           status_append_with_NL("");
                        }
                        break;

                     default:
                        {
                           Serial.println("");
                           status_append_with_NL("");
                        }
                        break;
                  }
               }
            }
            break;

         default:
            {
               if (CAN_RX_mode != CAN_RX_MODE_ISOTP_ONLY)
               {
                  Serial.println("");
                  status_append_with_NL("");
               }
            }
            break;
      }

      if (CAN_RX_mode != CAN_RX_MODE_ISOTP_ONLY)
      {
         Serial.println("");
         status_append_with_NL("");
      }
   }

   if (CAN_RX_mode != CAN_RX_MODE_ISOTP_ONLY)
   {
      check_status_update_time = millis();
      status_update_required = true;
   }
}  // can_sniff_RX()


// callback to spit out contents of CAN ISOTP receive frame
void can_sniff_RX_isotp(const ISOTP_data &config, const uint8_t *buf)
{
   if (CAN_RX_mode != CAN_RX_MODE_STD_ONLY)
   {
      Serial.print("RX: (isotp)");
      status_append_without_NL("RX: (isotp)");

      Serial.print("  LEN: ");
      status_append_without_NL("  LEN: ");

      if (config.len < 100)
      {
         Serial.print(" ");
         status_append_without_NL(" ");
      } else {
         status_append_without_NL((char)(((config.len / 100) % 10) + '0'));
      }

      if (config.len < 10)
      {
         Serial.print(" ");
         status_append_without_NL(" ");
      } else {
         status_append_without_NL((char)(((config.len / 10) % 10) + '0'));
      }

      Serial.print(config.len);
      status_append_without_NL((char)((config.len % 10) + '0'));

      Serial.print("  EXT: ");
      status_append_without_NL("  EXT: ");

      Serial.print(config.flags.extended);
      status_append_without_NL((char)(config.flags.extended + '0'));

      Serial.print("             ID: 0x");
      status_append_without_NL("             ID: 0x");

      uint32_t i = 0xF0000000;
      for (int j = 7; j >= 0; j--)
      {
         Serial.print(((config.id & i) >> (4 * j)), HEX);
         if (((config.id & i) >> (4 * j)) <= 9)
         {
            status_append_without_NL((char)(((config.id & i) >> (4 * j)) + '0'));
         } else {
            status_append_without_NL((char)((((config.id & i) >> (4 * j)) - 10) + 'A'));
         }

         i = i >> 4;
      }

      Serial.println("");
      status_append_with_NL("");

      Serial.print("   MSG: ");
      status_append_without_NL("   MSG: ");

      for (int i = 0; i < config.len; i++) {
         Serial.print("0x");
         status_append_without_NL("0x");

         Serial.print((buf[i] & 0xF0) >> 4, HEX);
         if (((buf[i] & 0xF0) >> 4) <= 9)
         {
            status_append_without_NL((char)(((buf[i] & 0xF0) >> 4) + '0'));
         } else {
            status_append_without_NL((char)((((buf[i] & 0xF0) >> 4) - 10) + 'A'));
         }

         Serial.print(buf[i] & 0x0F, HEX);
         if ((buf[i] & 0x0F) <= 9)
         {
            status_append_without_NL((char)((buf[i] & 0x0F) + '0'));
         } else {
            status_append_without_NL((char)(((buf[i] & 0x0F) - 10) + 'A'));
         }

         if ((i != 0) && ((i % 8) == 0))
         {
            Serial.println("");
            status_append_with_NL("");

            Serial.print("        ");
            status_append_without_NL("        ");
         } else {
            Serial.print(" ");
            status_append_without_NL(" ");
         }
      }
      Serial.println("");
      status_append_with_NL("");

      LED_timer = millis();
      analogWrite(LED_PIN, led_intensity_on);

      CAN_baudrate_match_found = true;
      CAN_baudrate_match_timeout = millis();

      if (CAN_baudrate_mode == CAN_BAUDRATE_MODE_HUNT_AND_STOP)
      {
         CAN_baudrate_mode = CAN_BAUDRATE_MODE_FIXED;

         report_current_baudrate();

         // save settings to EEPROM
         save_settings();
      }

      switch (buf[0])
      {
         case 0x41:
         case 0x42:
            {
               if (buf[0] == 0x41)
               {
                  Serial.println("      0x41: service 0x01 (Show current data) request response - isotp frame");
                  status_append_with_NL("      0x41: service 0x01 (Show current data) request response - isotp frame");
               }

               if (buf[0] == 0x42)
               {
                  Serial.println("      0x42: service 0x02 (Show freeze frame data) request response - isotp frame");
                  status_append_with_NL("      0x42: service 0x02 (Show freeze frame data) request response - isotp frame");
               }

               Serial.print("      0x");
               status_append_without_NL("      0x");

               Serial.print((buf[1] & 0xF0) >> 4, HEX);
               if (((buf[1] & 0xF0) >> 4) <= 9)
               {
                  status_append_without_NL((char)(((buf[1] & 0xF0) >> 4) + '0'));
               } else {
                  status_append_without_NL((char)((((buf[1] & 0xF0) >> 4) - 10) + 'A'));
               }

               Serial.print(buf[1] & 0x0F, HEX);
               if ((buf[0] & 0x0F) <= 9)
               {
                  status_append_without_NL((char)((buf[1] & 0x0F) + '0'));
               } else {
                  status_append_without_NL((char)(((buf[1] & 0x0F) - 10) + 'A'));
               }

               Serial.print(": PID 0x");
               status_append_without_NL(": PID 0x");

               Serial.print((buf[1] & 0xF0) >> 4, HEX);
               if (((buf[1] & 0xF0) >> 4) <= 9)
               {
                  status_append_without_NL((char)(((buf[1] & 0xF0) >> 4) + '0'));
               } else {
                  status_append_without_NL((char)((((buf[1] & 0xF0) >> 4) - 10) + 'A'));
               }

               Serial.print(buf[1] & 0x0F, HEX);
               if ((buf[1] & 0x0F) <= 9)
               {
                  status_append_without_NL((char)((buf[1] & 0x0F) + '0'));
               } else {
                  status_append_without_NL((char)(((buf[1] & 0x0F) - 10) + 'A'));
               }

               Serial.print(" - ");
               status_append_without_NL(" - ");

               decode_service_01_02_PID_title(STATUS_MODE, buf[0], buf[1]);

               Serial.println("");
               status_append_with_NL("");

               decode_isotp_service_01_PID_content(config.len, buf);

               Serial.println("");
               status_append_with_NL("");
            }
            break;

         case 0x43:
            {
               Serial.println("      0x43: service 0x03 (list DTCs) request response - isotp frame");
               status_append_with_NL("      0x43: service 0x03 (list DTCs) request response - isotp frame");

               Serial.println("");
               status_append_with_NL("");
            }
            break;

         case 0x44:
            {
               Serial.println("      0x44: service 0x04 (clear DTCs) request response - isotp frame");
               status_append_with_NL("      0x44: service 0x04 (clear DTCs) request response - isotp frame");

               Serial.println("");
               status_append_with_NL("");
            }
            break;

         case 0x49:
            {
               Serial.println("      0x49: service 0x09 (vehicle info) request response - isotp frame");
               status_append_with_NL("      0x49: service 0x09 (vehicle info) request response - isotp frame");

               Serial.print("      0x");
               status_append_without_NL("      0x");

               Serial.print((buf[1] & 0xF0) >> 4, HEX);
               if (((buf[1] & 0xF0) >> 4) <= 9)
               {
                  status_append_without_NL((char)(((buf[1] & 0xF0) >> 4) + '0'));
               } else {
                  status_append_without_NL((char)((((buf[1] & 0xF0) >> 4) - 10) + 'A'));
               }

               Serial.print(buf[1] & 0x0F, HEX);
               if ((buf[1] & 0x0F) <= 9)
               {
                  status_append_without_NL((char)((buf[1] & 0x0F) + '0'));
               } else {
                  status_append_without_NL((char)(((buf[1] & 0x0F) - 10) + 'A'));
               }

               Serial.print(": PID 0x");
               status_append_without_NL(": PID 0x");

               Serial.print((buf[1] & 0xF0) >> 4, HEX);
               if (((buf[1] & 0xF0) >> 4) <= 9)
               {
                  status_append_without_NL((char)(((buf[1] & 0xF0) >> 4) + '0'));
               } else {
                  status_append_without_NL((char)((((buf[1] & 0xF0) >> 4) - 10) + 'A'));
               }

               Serial.print(buf[1] & 0x0F, HEX);
               if ((buf[1] & 0x0F) <= 9)
               {
                  status_append_without_NL((char)((buf[1] & 0x0F) + '0'));
               } else {
                  status_append_without_NL((char)(((buf[1] & 0x0F) - 10) + 'A'));
               }

               Serial.print(" - ");
               status_append_without_NL(" - ");

               decode_service_09_PID_title(STATUS_MODE, buf[1]);

               Serial.println("");
               status_append_with_NL("");

               decode_isotp_service_09_PID_content(config.len, buf);

               Serial.println("");
               status_append_with_NL("");
            }
            break;

         case 0x50:
            {
               Serial.println("      0x50: service 0x10 (CAN diagnostic session) request response - isotp frame");
               status_append_with_NL("      0x50: service 0x10 (CAN diagnostic session) request response - isotp frame");

               Serial.print("      0x");
               status_append_without_NL("      0x");

               Serial.print((buf[1] & 0xF0) >> 4, HEX);
               if (((buf[1] & 0xF0) >> 4) <= 9)
               {
                  status_append_without_NL((char)(((buf[1] & 0xF0) >> 4) + '0'));
               } else {
                  status_append_without_NL((char)((((buf[1] & 0xF0) >> 4) - 10) + 'A'));
               }

               Serial.print(buf[1] & 0x0F, HEX);
               if ((buf[1] & 0x0F) <= 9)
               {
                  status_append_without_NL((char)((buf[1] & 0x0F) + '0'));
               } else {
                  status_append_without_NL((char)(((buf[1] & 0x0F) - 10) + 'A'));
               }

               Serial.print(": PID 0x");
               status_append_without_NL(": PID 0x");

               Serial.print((buf[1] & 0xF0) >> 4, HEX);
               if (((buf[1] & 0xF0) >> 4) <= 9)
               {
                  status_append_without_NL((char)(((buf[1] & 0xF0) >> 4) + '0'));
               } else {
                  status_append_without_NL((char)((((buf[1] & 0xF0) >> 4) - 10) + 'A'));
               }

               Serial.print(buf[1] & 0x0F, HEX);
               if ((buf[1] & 0x0F) <= 9)
               {
                  status_append_without_NL((char)((buf[1] & 0x0F) + '0'));
               } else {
                  status_append_without_NL((char)(((buf[1] & 0x0F) - 10) + 'A'));
               }

               Serial.print(" - ");
               status_append_without_NL(" - ");

               if (buf[1] == 0x03)
               {
                  Serial.print("Extended CAN diagnostic session");
                  status_append_without_NL("Extended CAN diagnostic session");
               } else {
                  Serial.print("unexpected PID");
                  status_append_without_NL("unexpected PID");
               }

               Serial.println("");
               status_append_with_NL("");
            }
            break;

         case 0x7F:
            {
               Serial.println("      0x7F: CAN service request - NAK response - isotp frame");
               status_append_with_NL("      0x7F: CAN service request - NAK response - isotp frame");

               Serial.print("      0x");
               status_append_without_NL("      0x");

               Serial.print((buf[1] & 0xF0) >> 4, HEX);
               if (((buf[1] & 0xF0) >> 4) <= 9)
               {
                  status_append_without_NL((char)(((buf[1] & 0xF0) >> 4) + '0'));
               } else {
                  status_append_without_NL((char)((((buf[1] & 0xF0) >> 4) - 10) + 'A'));
               }

               Serial.print(buf[1] & 0x0F, HEX);
               if ((buf[1] & 0x0F) <= 9)
               {
                  status_append_without_NL((char)((buf[1] & 0x0F) + '0'));
               } else {
                  status_append_without_NL((char)(((buf[1] & 0x0F) - 10) + 'A'));
               }

               Serial.println(" (service number requested)");
               status_append_with_NL(" (service number requested)");

               Serial.print("      0x");
               status_append_without_NL("      0x");

               Serial.print((buf[2] & 0xF0) >> 4, HEX);
               if (((buf[2] & 0xF0) >> 4) <= 9)
               {
                  status_append_without_NL((char)(((buf[2] & 0xF0) >> 4) + '0'));
               } else {
                  status_append_without_NL((char)((((buf[2] & 0xF0) >> 4) - 10) + 'A'));
               }

               Serial.print(buf[2] & 0x0F, HEX);
               if ((buf[2] & 0x0F) <= 9)
               {
                  status_append_without_NL((char)((buf[2] & 0x0F) + '0'));
               } else {
                  status_append_without_NL((char)(((buf[2] & 0x0F) - 10) + 'A'));
               }

               Serial.println(" (?? additional data)");
               status_append_with_NL(" (?? additional data)");

               Serial.println("");
               status_append_with_NL("");
            }
            break;

         default:
            {
               Serial.print("      0x");
               status_append_without_NL("      0x");

               Serial.print((buf[0] & 0xF0) >> 4, HEX);
               if (((buf[0] & 0xF0) >> 4) <= 9)
               {
                  status_append_without_NL((char)(((buf[0] & 0xF0) >> 4) + '0'));
               } else {
                  status_append_without_NL((char)((((buf[0] & 0xF0) >> 4) - 10) + 'A'));
               }

               Serial.print(buf[0] & 0x0F, HEX);
               if ((buf[0] & 0x0F) <= 9)
               {
                  status_append_without_NL((char)((buf[0] & 0x0F) + '0'));
               } else {
                  status_append_without_NL((char)(((buf[0] & 0x0F) - 10) + 'A'));
               }

               Serial.println(": unexpected isotp CAN service request response");
               status_append_with_NL(": unexpected isotp CAN service request response");

               Serial.println("");
               status_append_with_NL("");
            }
            break;
      }

      check_status_update_time = millis();
      status_update_required = true;
   }
}  // can_sniff_RX_isotp()

Mark J Culross
KD5RXT
 
Just use ISOTP for everything.
It can handle standard frames as well.
My setup consists of one regular callback that takes care pf flow control if needed, and an isotp callback for all the data.
If the length of the final isotp output is 7 bytes or less its a standard frame, but handled just like an long “frame”
 
Just use ISOTP for everything.

@Rezo:

Thanks for your reply. Although my primary target vehicles are a 2020 Honda Civic & a 2020 Honda CR-V, I wasn't sure if limiting my Teensy CAN bus monitor utility to ISOTP would prevent me from using it on older vehicles or not.

Thanks again !!

Mark J Culross
KD5RXT
 
@Mark I was referring to using the isotp library in general.
When a single frame is received it will come through the isotp callback without the first byte (payload length), bit that is found in the message.len variable, so it’s still there.
For me it works like a charm. I handle both single frames and long frames in a single callback.

Your code should work on most vehicles as long as it’s requesting OBD2 stuff.
As soon as you go into mode 22 data and the likes it becomes manufacture specific.
 
Hi, I'm having a challenging time trying to get CAN FD working between two Teensys.

On the sender side, I am using this code:
Code:
/* CAN Bus */
FlexCAN_T4FD<CAN3, RX_SIZE_256, TX_SIZE_16> can3;

CANFD_message_t msg;

void setup() {
  Serial.begin(115200);
  while (!Serial) {}
  /* CAN bus config */
  can3.begin();
  CANFD_timings_t config;
  config.clock = CLK_24MHz;
  config.baudrate = 1000000;
  config.baudrateFD = 1000000;
  config.propdelay = 190;
  config.bus_length = 1;
  config.sample = 70;
  can3.setBaudRate(config);
  msg.id = 1;
  msg.brs = true;
  msg.edl = true;
  msg.len = 12;
  int i = 0;
}

void loop() {
    int j = i++;
    for (int k = 0; k < 12; k++) {
      msg.buf[k] = j++;
    }
    can3.write(msg);
    delay(100);
}

On the receiver side, I am using this code:

Code:
/* CAN Bus */
FlexCAN_T4FD<CAN3, RX_SIZE_256, TX_SIZE_16> can3;

CANFD_message_t msg;

void setup() {
  Serial.begin(115200);
  while (!Serial) {}
  /* CAN bus config */
  can3.begin();
  CANFD_timings_t config;
  config.clock = CLK_24MHz;
  config.baudrate = 1000000;
  config.baudrateFD = 1000000;
  config.propdelay = 190;
  config.bus_length = 1;
  config.sample = 70;
  can3.setBaudRate(config);
}

void loop() {
    if (can3.read(msg)) {
      for (int i = 0; i < 13; i++) {
        Serial.print(msg.buf[i]);
        Serial.print("\t");
      }
      Serial.println();
    }
}

I'm trying to test sending packets over 8 bytes long; unfortunately, in the serial monitor on the receiving side, I only see the first 8 bytes. I'm guessing something is wrong with the way my CAN flags are setup, but I'm not sure what it is. Also would like to get to higher baudrates after I solve this issue, any hints for the config to make that work would be appreciated.

Thanks!

EDIT: this is between two Teensy MMOD using CAN3.
 
Looks like I needed to add this to both the sender and receiver to use the longer length:

Code:
can3.setRegions(64);
 
I've got it working with 2MBaud. Not sure how to go higher and still have everything work reliably. I have 8 MBaud transceivers, 120 Ohm terminators and a twister pair of wires between the boards with a length of about 6 inches. Then again, I'm unsure what all of the flags in the CANFD_timings_t struct mean. Could anyone shed light on the CANFD_timings_t struct members and what each does?

Thanks much!
 
I've got it working at 10Mbps with these settings:

Code:
  FD.begin();
  CANFD_timings_t config;
  config.clock = CLK_80MHz;
  config.baudrate =   1000000;     // 1000kbps Nominal data rate
  config.baudrateFD = 10000000;    // 10000kpbs Data rate
  config.propdelay = 190;
  config.bus_length = 1;
  config.sample = 70;
  FD.setRegions(64);
  FD.setBaudRate(config);

Tested with the PCAN-USB Pro from Peak System.

IMG_8800.jpg
192_168_1_28.jpg

Cable length is about 5m between the two Teensy boards.
Teensy 4.0 is fast !!
 
Back
Top