Looks like I needed to add this to both the sender and receiver to use the longer length:
Code:can3.setRegions(64);
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!
Circling back that I got this working up to 5 Mb/s by setting the peripheral clock to 60 MHz after reading this thread:
https://forum.pjrc.com/threads/67261...l=1#post279951
EDIT: Actually, I can get 6 MB/s. Not sure what's preventing reaching 8 MB/s.
Last edited by brtaylor; 11-20-2022 at 10:09 PM.
I've got it working at 10Mbps with these settings:
Tested with the PCAN-USB Pro from Peak System.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);
Cable length is about 5m between the two Teensy boards.
Teensy 4.0 is fast !!
Thanks, updating the peripheral clock to 80 MHz does enable 8 Mb/s to work for me too.
Greetings --
New to the board. Is there a more detailed programming document for this library available other than what is posted on GitHub?
Thanks
I have a youtube demo (source in the description) https://www.youtube.com/watch?v=N8t9_0dAKvQ
I've run into another stumbling block. I'm trying to receive CAN-FD messages in an interrupt context.
Example sender code is:
Receiver code is:Code:#include <FlexCAN_T4.h> #include <elapsedMillis.h> FlexCAN_T4FD<CAN3, RX_SIZE_256, TX_SIZE_128> can; elapsedMillis t_ms; CANFD_message_t msg; void setup() { can.begin(); CANFD_timings_t cfg; cfg.clock = CLK_80MHz; cfg.baudrate = 1000000; cfg.baudrateFD = 8000000; cfg.propdelay = 190; cfg.bus_length = 1; cfg.sample = 70; can.setRegions(64); can.setBaudRate(cfg); msg.id = 0x01; msg.len = 5; Serial.begin(115200); delay(1000); } void loop() { if (t_ms >= 1000) { t_ms = 0; msg.buf[0]++; can.write(msg); } }
My expectation is that I would see "RECEIVED INT" in the serial monitor, but I don't. I don't really care to do anything fancy with the mailboxes, I just want to receive all of the messages in the interrupt context because I plan to use the loop to do some other tasks. I would use the FIFO, but my understanding is that CAN-FD doesn't have a FIFO buffer (even though there is an enableFIFO method, so maybe my assumption is wrong). What do I need to do to make this work?Code:#include <FlexCAN_T4.h> FlexCAN_T4FD<CAN3, RX_SIZE_256, TX_SIZE_64> can; CANFD_message_t msg; void setup(void) { Serial.begin(115200); delay(400); can.begin(); CANFD_timings_t cfg; cfg.clock = CLK_80MHz; cfg.baudrate = 1000000; cfg.baudrateFD = 8000000; cfg.propdelay = 190; cfg.bus_length = 1; cfg.sample = 70; can.setRegions(64); can.setBaudRate(cfg); can.setMBFilter(REJECT_ALL); can.enableMBInterrupts(); can.onReceive(MB0, isr); can.setMBFilterRange(MB0, 0x00, 0xFF); can.mailboxStatus(); } void isr(const CANFD_message_t &msg) { Serial.println("RECEIVED INT"); } void loop() { if (can.read(msg)) { Serial.println("RECEIVED LOOP"); } }
If I comment the following lines from setup, then I can receive the message in loop with "RECEIVED LOOP" printed to the serial monitor, which shows that my hardware setup is correct.
Code:can.setMBFilter(REJECT_ALL); can.enableMBInterrupts(); can.onReceive(MB0, isr); can.setMBFilterRange(MB0, 0x00, 0xFF); can.mailboxStatus();
Hello,
Haven't hit this issue yet. Perhaps some ideas on making this code work could be found in the example code:
mailbox_filtering_example_with_interrupts
#include <FlexCAN_T4.h>
FlexCAN_T4<CAN1, RX_SIZE_256, TX_SIZE_16> Can0;
#define NUM_TX_MAILBOXES 2
#define NUM_RX_MAILBOXES 6
void setup(void) {
Serial.begin(115200); delay(400);
Can0.begin();
Can0.setBaudRate(250000);
Can0.setMaxMB(NUM_TX_MAILBOXES + NUM_RX_MAILBOXES);
for (int i = 0; i<NUM_RX_MAILBOXES; i++){
Can0.setMB(i,RX,EXT);
}
for (int i = NUM_RX_MAILBOXES; i<(NUM_TX_MAILBOXES + NUM_RX_MAILBOXES); i++){
Can0.setMB(i,TX,EXT);
}
Can0.setMBFilter(REJECT_ALL);
Can0.enableMBInterrupts();
Can0.onReceive(MB0,canSniff);
Can0.onReceive(MB1,canSniff);
Can0.onReceive(MB2,canSniff);
Can0.setMBFilterProcessing(MB0,0x00,0xFF);
Can0.setMBFilterProcessing(MB1,0x03,0xFF);
Can0.setMBFilterProcessing(MB2,0x0B,0xFF);
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();
}
It's my understanding the MCP2517FD chip logic controller code has and SPI command interface in the FlexCAN SPI code that sets the FD message send and recieve processing by mailboxes and interrupts.
Interrupts are intended to control and signal the mailbox events as they occor and are processed and the priorities of those send and recieve chip events for the mailboxes connevted to the FD CAN message bus.
FIFO processing is handled at the chip level (see the Microchip documentation) where the chip logic stages and controls the internal messaging buffers are used by send and recieve message commands. FIFO mailboxes for FD CAN 2.0B is recommended in most automotive CAN Bus designs.
From:
FlexCAN_T4.h
typedef*struct*CANFD_timings_t*{
**double*baudrate*=*1000000;
**double*baudrateFD*=*2000000;
**double*propdelay*=*190;
**double*bus_length*=*1;
**double*sample*=*75;
**FLEXCAN_CLOCK*clock*=*CLK_24MHz;*
}*CANFD_timings_t;
You are referring to this when you asked for an explanation..?
Taken from:
https://github.com/tonton81/FlexCAN_...r/FlexCAN_T4.h
Just FYI --
According to the FLEXCAN docs on GitHub..
Note that there is no FIFO support in CANFD for Teensy 4.0. FIFO is only supported in CAN2.0 mode on Teensy 3.x and Teensy 4.0
Can you please enclose any posted code between CODE tags using the # button at the top of the post form.Code:#include <FlexCAN_T4.h> FlexCAN_T4<CAN1, RX_SIZE_256, TX_SIZE_16> Can0; #define NUM_TX_MAILBOXES 2 #define NUM_RX_MAILBOXES 6 void setup(void) { Serial.begin(115200); delay(400); Can0.begin(); Can0.setBaudRate(250000); Can0.setMaxMB(NUM_TX_MAILBOXES + NUM_RX_MAILBOXES); for (int i = 0; i < NUM_RX_MAILBOXES; i++) { Can0.setMB(i, RX, EXT); } for (int i = NUM_RX_MAILBOXES; i < (NUM_TX_MAILBOXES + NUM_RX_MAILBOXES); i++) { Can0.setMB(i, TX, EXT); } Can0.setMBFilter(REJECT_ALL); Can0.enableMBInterrupts(); Can0.onReceive(MB0, canSniff); Can0.onReceive(MB1, canSniff); Can0.onReceive(MB2, canSniff); Can0.setMBFilterProcessing(MB0, 0x00, 0xFF); Can0.setMBFilterProcessing(MB1, 0x03, 0xFF); Can0.setMBFilterProcessing(MB2, 0x0B, 0xFF); 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(); }
It presents your work in a much more readable and understandable manner making it much easier for people to help you.
FYI, I just wanted to follow up that I've been working this issue on GitHub here:
https://github.com/tonton81/FlexCAN_T4/issues/56
Just in case someone runs into a similar problem and is looking for a solution. I'm suspecting that it's a bug in the library and issued a pull request with a fix.
Hi!
I'm trying to use can bus FD on my Teensy 4.0 thriple can bus board to send frames to rsp3, but it doesn't show any message while I use candump can0 on my rsp3. Can you help me out? Thx!!
I'm using the demo code below:
#include <FlexCAN_T4.h>
FlexCAN_T4FD<CAN3, RX_SIZE_256, TX_SIZE_16> FD; // can3 port
IntervalTimer timer;
uint8_t d=0;
void setup(void) {
Serial.begin(115200); delay(1000);
Serial.println("Teensy 4.0 Triple CAN test");
FD.begin();
CANFD_timings_t config;
config.clock = CLK_24MHz;
config.baudrate = 500000; // 500kbps arbitration rate
config.baudrateFD = 2000000; // 2000kbps data rate
config.propdelay = 190;
config.bus_length = 1;
config.sample = 75;
FD.setRegions(64);
FD.setBaudRateAdvanced(config, 1, 1);
FD.onReceive(canSniff);
FD.setMBFilter(ACCEPT_ALL);
FD.setMBFilter(MB13, 0x1);
FD.setMBFilter(MB12, 0x1, 0x3);
FD.setMBFilterRange(MB8, 0x1, 0x04);
FD.enableMBInterrupt(MB8);
FD.enableMBInterrupt(MB12);
FD.enableMBInterrupt(MB13);
FD.enhanceFilter(MB8);
FD.enhanceFilter(MB10);
FD.distribute();
FD.mailboxStatus();
timer.begin(sendframe, 500000); // Send frame every 500ms
}
void sendframe()
{
CANFD_message_t msg;
msg.len = 64;
msg.id = 0x4fd;
msg.seq = 1;
for ( uint8_t i = 0; i < 64; i++ ) {
msg.buf[i] = i + 1;
//Serial.println(i);
}
msg.buf[0] = d;
FD.write(msg); // write to can3
//Serial.println();
}
void canSniff(const CANFD_message_t &msg) {
Serial.print("ISR - 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() {
CANFD_message_t msg;
FD.events(); /* needed for sequential frame transmit and callback queues */
if ( FD.readMB(msg) ) {
Serial.print("MB: "); Serial.print(msg.mb);
Serial.print(" OVERRUN: "); Serial.print(msg.flags.overrun);
Serial.print(" ID: 0x"); Serial.print(msg.id, HEX );
Serial.print(" EXT: "); Serial.print(msg.flags.extended );
Serial.print(" LEN: "); Serial.print(msg.len);
Serial.print(" BRS: "); Serial.print(msg.brs);
Serial.print(" EDL: "); Serial.print(msg.edl);
Serial.print(" DATA: ");
for ( uint8_t i = 0; i <msg.len ; i++ ) {
Serial.print(msg.buf[i]); Serial.print(" ");
}
Serial.print(" TS: "); Serial.println(msg.timestamp);
}
}
Hi All,
I have been doing searching and haven't managed to find it anywhere so thought I would ask here. I have a Teensy 4.1 that I am using as a body/chassis ECU that sends data to a Raspberry Pi for a digital dash in my car. I am switching from an OEM ECU using OBD to an aftermarket ECU. The new ECU uses Haltech CAN bus protocol. Does anyone know how I alter the code so that the Teensy will read the Haltech CAN bus messages? I have added the code from Arduino IDE below. Many Thanks in advance
Some info on Haltech:Code:#ifndef CANBUS_H #define CANBUS_H #include <FlexCAN_T4.h> #include "values.h" extern FlexCAN_T4<CAN1, RX_SIZE_256, TX_SIZE_16> can1; extern Values values; void canSend(uint8_t activeByte){ CAN_message_t msgTx; msgTx.len = 3; // number of bytes in request msgTx.id = 0x7E0; // Request Header // msgTx.flags.extended = 0; // 11 bit header, not 29 bit // msgTx.flags.remote = 0; msgTx.buf[0] = 0x02; // Number of bytes in request msgTx.buf[1] = 0x01; // Mode of request (0x01 = OBD2) msgTx.buf[2] = activeByte; msgTx.buf[4] = 0x00; msgTx.buf[5] = 0x00; msgTx.buf[6] = 0x00; msgTx.buf[7] = 0x00; can1.write(msgTx); } void canReceive(const CAN_message_t &msg){ // Serial.print("MB: "); // Serial.print(msg.mb); // Serial.print(" ID: 0x"); // Serial.print(msg.id, HEX); // Serial.print(" EXT: "); // Serial.print(msg.flags.extended); // Serial.print(" LEN: "); // Serial.print(msg.len); // Serial.print(" DATA: "); // for (uint8_t i = 0; i < 8; i++) { // Serial.print(msg.buf[i], HEX); // Serial.print(" "); // } // Serial.println(""); // Handle mode 41 messages if (msg.id == 0x7E8 && msg.buf[1] == 0x41) { switch (msg.buf[2]) { // RPM case 0x0c: { if (msg.buf[0] == 4) { values.rpm = ((msg.buf[3] * 256 + msg.buf[4]) / 4); } } break; // Coolant case 0x05: { if (msg.buf[0] == 3) { values.coolantTemp = (int)((((float)msg.buf[3] - 40.0f) * 1.8f) + 32.0f); } } break; // MAP case 0x0B: { if (msg.buf[0] == 3) { values.boostPressure = ((float)msg.buf[3] * 0.145038f) - values.barometricPressure; } } break; // Barometric pressure case 0x33: { if (msg.buf[0] == 3) { values.barometricPressure = (float)msg.buf[3] * 0.145038f; } } break; } } // Engine Fluid Level/Pressure 1 if (msg.id == 0x18FEEF00) { // Oil pressure values.oilPressure = (float)msg.buf[3] * 4.0f * 0.145038f; } } void canInit() { can1.begin(); can1.setBaudRate(500000); can1.enableFIFO(); can1.enableFIFOInterrupt(); can1.onReceive(canReceive); } #endif
Key Information
The Haltech CAN bus operates at 1MBit and uses 11-bit IDs. IDs are expressed in Hexadecimal.
The first byte in a packet is considered byte 0, and the 8th byte is byte 7. The most significant bit in a byte is considered bit 7 and the least significant bit is
bit 0.
Data is encoded as big endian.
![]()
Last edited by mikesmif; 01-04-2023 at 11:17 AM.
This is something I found when Googling Haltech Can Protocol.
The general idea is to replace your canRecieve function with code that just checks for IDs you want. If ID matches 0x361 (for example), grab the correct bytes and join them, then convert to physical units. Also, be sure to correct the baud rate in canInit.
Here's an example of how to get oilPressure:
*Note: I haven't checked or tested this code in any way*Code:void canReceive(const CAN_message_t &msg){ // Handle 0x361 messages (~50Hz) if (msg.id == 0x361) { // Oil Pressure values.oilPressure = (float)(msg.buf[2]<<8 + msg.buf[3])/10.0f - 101.3f; } }
If the numbers you are receiving don't make sense, try switching the byte order.
Hi, I have been succesfully using Teensy 4.0's as the can bridges based on modified code of the samples. Works great with 500k speed. But now I am struggling with the same software and hardware but using 83.3k speed. I have tried different clock speeds, bu no difference. by plugging in the device, seem to halt the canbus traffic.
Any tips, what is it I am missing here?Code:#include <FlexCAN_T4.h> FlexCAN_T4<CAN1, RX_SIZE_256, TX_SIZE_16> can1; FlexCAN_T4<CAN2, RX_SIZE_256, TX_SIZE_16> can2; CAN_message_t msg; void setup(void) { Serial.begin(115200); delay(400); pinMode(2, OUTPUT); digitalWrite(2, LOW); /* optional tranceiver enable pin */ pinMode(3, OUTPUT); digitalWrite(3, LOW); /* optional tranceiver enable pin */ can1.begin(); can1.setClock(CLK_60MHz); // can1.setBaudRate(500000); can1.setBaudRate(83330); can2.begin(); can2.setClock(CLK_60MHz); // can2.setBaudRate(500000); can2.setBaudRate(83330); } void loop() { if ( can1.read(msg) ) { Serial.print("CAN1 "); Serial.print("MB: "); Serial.print(msg.mb); Serial.print(" ID: 0x"); Serial.print(msg.id, HEX ); Serial.print(" EXT: "); Serial.print(msg.flags.extended ); Serial.print(" LEN: "); Serial.print(msg.len); Serial.print(" DATA: "); for ( uint8_t i = 0; i < 8; i++ ) { Serial.print(msg.buf[i]); Serial.print(" "); } Serial.print(" TS: "); Serial.println(msg.timestamp); can2.write(msg); // echo to can2 } else if ( can2.read(msg) ) { Serial.print("CAN2 "); Serial.print("MB: "); Serial.print(msg.mb); Serial.print(" ID: 0x"); Serial.print(msg.id, HEX ); Serial.print(" EXT: "); Serial.print(msg.flags.extended ); Serial.print(" LEN: "); Serial.print(msg.len); Serial.print(" DATA: "); for ( uint8_t i = 0; i < 8; i++ ) { Serial.print(msg.buf[i]); Serial.print(" "); } Serial.print(" TS: "); Serial.println(msg.timestamp); } }
Thanks!
Hi not sure if this is the right place, but I set up a CAN logger, but I want to start and stop with a pushbutton. I've been able to start it on command, but it won't shut off. How would I deconstruct/disable the CAN object?