FlexCAN_T4 - FlexCAN for Teensy 4

I received the MCP2562-E/SN transceivers used on skpang's board last week and have spent a fair amount of time experimenting. So far the MCP2562-E/SN acts identically to the other three chips I tried before.
Just for recap: using FIFO interrupt callback on CAN2 to transmit sequentially on CAN1 eventually gets stuck indefinitely with a message "transmitting" in the mailbox.

The original setup included a custom PCB and recorded messages being played back onto CAN2 with a Vector VN1610. Item by item I simplified this setup, but never saw any improvement.
The current setup has moved to a breadboard and involves 2x Teensy_4.0:
  • Teensy #1 has one MCP2562-E/SN connected to CAN2. It transmits bursts of 14 random messages with periods of bus idle between bursts. Bus load is ~40%.
  • Teensy #2 has three MCP2562-E/SN connected to CAN1-3. Messages from Teensy #1 are received FIFO on CAN2 and sequentially transmitted on CAN1. CAN1 is connected to CAN3 to provide ACK.

My hope is that you would be able to confirm this "lockup" behavior with 1x PJRC breakout and 1x skpang breakout.

Teensy #1 code:
Code:
#include <FlexCAN_T4.h>
#include <elapsedMillis.h>

FlexCAN_T4<CAN2, RX_SIZE_256, TX_SIZE_32> VCAN;

CAN_message_t msgRand;
elapsedMicros usBurstIntervalTimer;

uint8_t burstCount = 14;

void setup() {

  VCAN.begin();
  VCAN.setClock(CLK_60MHz);
  VCAN.setBaudRate(500000);
  VCAN.setMaxMB(32);
  for (int i; i < 32; i++) {
    VCAN.setMB((FLEXCAN_MAILBOX)i, TX);
  }

  randomSeed(0);
  usBurstIntervalTimer = 0;

  delay(1000);
}


void loop() {
  if ( usBurstIntervalTimer >= 6000 ) {   // Burst interval timer expired
    for (int i = 0; i < burstCount; i++) {
      msgRand.id = random(0x100, 0x7FF);
      msgRand.len = random(1, 8);
      msgRand.buf[0] = random(0, 255);
      VCAN.write(msgRand);
    }
    usBurstIntervalTimer = 0;
  }
}


Teensy #2 code:
Code:
#include <FlexCAN_T4.h>
#include <elapsedMillis.h>

FlexCAN_T4<CAN1, RX_SIZE_256, TX_SIZE_64> LCAN;
FlexCAN_T4<CAN2, RX_SIZE_256, TX_SIZE_16> VCAN;
FlexCAN_T4<CAN3, RX_SIZE_256, TX_SIZE_16> LCAN3;

elapsedMillis msPrintTimer;

uint32_t rxCounterVCAN = 0;
uint32_t rxCounterLCAN3 = 0;

void setup() {
  Serial.begin(500000);

  // Setup VCAN (CAN2)
  VCAN.begin();
  VCAN.setClock(CLK_60MHz);
  VCAN.setBaudRate(500000);
  VCAN.enableFIFO();
  VCAN.enableFIFOInterrupt();
  VCAN.onReceive(canV2L);

  // Setup LCAN (CAN1)
  LCAN.begin();
  LCAN.setClock(CLK_60MHz);
  LCAN.setBaudRate(500000);

  // Setup LCAN3 (CAN3) - needed to ACK TX msgs from LCAN (CAN1)
  LCAN3.begin();
  LCAN3.setClock(CLK_60MHz);
  LCAN3.setBaudRate(500000);
  LCAN3.enableFIFO();
  LCAN3.enableFIFOInterrupt();
  LCAN3.onReceive(rxIncLCAN3);

  msPrintTimer = 0;
}

void loop() {
  VCAN.events();
  LCAN.events();
  LCAN3.events();

  if ( msPrintTimer > 1000 ) {
    msPrintTimer = 0;
    Serial.print("RX Count VCAN: "); Serial.print(rxCounterVCAN);
    Serial.print("     LCAN3: "); Serial.println(rxCounterLCAN3);
  }
}

void canV2L(const CAN_message_t &msg) {
  CAN_message_t myMsg;
  myMsg = msg;
  myMsg.seq = 1;
  LCAN.write(myMsg);
  rxCounterVCAN++;
}

void rxIncLCAN3(const CAN_message_t &msg) {
  rxCounterLCAN3++;
}

Typical serial output on from Teensy #2:
Code:
RX Count VCAN: 5     LCAN3: 4
RX Count VCAN: 2338     LCAN3: 2338
RX Count VCAN: 4662     LCAN3: 4662
RX Count VCAN: 6997     LCAN3: 6996
RX Count VCAN: 9324     LCAN3: 9324
RX Count VCAN: 11652     LCAN3: 11651
RX Count VCAN: 13986     LCAN3: 13986
RX Count VCAN: 16310     LCAN3: 16310
RX Count VCAN: 18646     LCAN3: 18644
RX Count VCAN: 20972     LCAN3: 20972
RX Count VCAN: 23298     LCAN3: 23297
RX Count VCAN: 25634     LCAN3: 25634
RX Count VCAN: 27958     LCAN3: 27958
RX Count VCAN: 30291     LCAN3: 30289
RX Count VCAN: 32620     LCAN3: 32620
RX Count VCAN: 34944     LCAN3: 34944
RX Count VCAN: 37282     LCAN3: 37281
RX Count VCAN: 39606     LCAN3: 37939
RX Count VCAN: 41936     LCAN3: 37939
RX Count VCAN: 44268     LCAN3: 37939
RX Count VCAN: 46592     LCAN3: 37939
RX Count VCAN: 48927     LCAN3: 37939
...

Thanks, Mike
 
I believe you are transmitting too fast causing the transmit errors rising past 128. Check the ESR1 and ECR registers in the datasheet. To me it looks like you are receiving and sending frames, if this occurs (TXing) too fast, flexcan generates transmisson errors and if increments to 128, it goes into bus off state and refuses transmitting. On a 2 node network it shouldn't be possible to recover via bus recovery, but I did run some tests on it to validate what I see. Writing too fast can actually cause a bus off state. Monitor the last 8 bytes of the ECR, if it shows 128 thats why it's not working. I have not yet determined a workaround, played with interrupts, but constantly flooding transmits will render the controller to bus off. If your transmitting for every reception that is considered flooding. Unfortunately this isn't queue related either. I even tried the workaround you suggested, well, in FIFO mode, so MB8-15 is all TX, double TX inactive MB8, yet doesn't ressolve the flooding going into bus off state.

Once in bus off state like I said, with only 2 nodes, it won't recover out of bus off unless there is 3 or more nodes on the network, or, putting the controller into FRZ mode, clearing the ECR, and deasserting FRZ mode also works for recovering off a non active communication bus

I believe I can replicate it via bursting several thousand frames at same time like you did, thats how I found the transmission error counter increase to 128 in the ECR thereby making the controller go into error passive state (see ESR1 register bit 4) and while it shuts down waiting for activity the other node thinks it dissapeared and refuses to talk until it sees something as well

Hopefully it is not a hardware limitation on bursting otherwise I would remedy that with throtteling based on ECR values maybe
 
Here are the ESR1 and ECR values added to the serial monitor output:

Code:
RX Count VCAN: 2356     LCAN3: 2356
ECR_TX_ERR_COUNTER LCAN: 0
ESR1 LCAN: 0x40080

RX Count VCAN: 4691     LCAN3: 4690
ECR_TX_ERR_COUNTER LCAN: 0
ESR1 LCAN: 0x40040

RX Count VCAN: 7018     LCAN3: 7018
ECR_TX_ERR_COUNTER LCAN: 0
ESR1 LCAN: 0x40080

RX Count VCAN: 9346     LCAN3: 9344
ECR_TX_ERR_COUNTER LCAN: 0
ESR1 LCAN: 0x40040

RX Count VCAN: 11680     LCAN3: 11680
ECR_TX_ERR_COUNTER LCAN: 0
ESR1 LCAN: 0x40080

RX Count VCAN: 14004     LCAN3: 11822
ECR_TX_ERR_COUNTER LCAN: 0
ESR1 LCAN: 0x40080

RX Count VCAN: 16338     LCAN3: 11822
ECR_TX_ERR_COUNTER LCAN: 0
ESR1 LCAN: 0x40080

RX Count VCAN: 18666     LCAN3: 11822
ECR_TX_ERR_COUNTER LCAN: 0
ESR1 LCAN: 0x40080

So to unpack this, ECR_TX_ERR_COUNTER is at 0 for the bus TX'ing, and ESR1 = 0x40080 equates to "bus synchronized" and "bus IDLE".

Also, while I am sending thousands of frames, these bus loads and burst sizes are representative of those measured on production vehicles. If I remove the "myMsg.seq = 1;", the bus will run indefinitely (although drop occasional messages due to lack of TX mailboxes).

I noticed another (possible related) quirk when sending sequentially regarding the interframe spacing bits. When more than one TX mailbox has a message ready to transmit and FlexCAN is handling the MB arbitration, the interframe spacing is 3 bits, the minimum per CAN spec. This makes sense since it should be trying to transmit as fast as possible. When sequentially transmitting from the queue via one TX mailbox, the shortest possible interframe spacing is 4 bits. I believe this is due to MB arbitration timing starting during CRC field of current message, which still exists in MB. The next sequential message can't be loaded into the mailbox until the initial arbitration time window has passed. Perhaps this could be improved by changing the CTRL2[TASD] register. This 3 bits vs 4 bits can become a problem during bursts, since the messages are being received faster than transmitted.

I was able to cobble together an alternate workaround that addresses both of these items, granted it does require an additional mailboxes for sequential transmission. The idea is essentially to use TX interrupts to load sequential frames to the mailboxes, while toggling which mailbox is being loaded. That way when the mailbox currently transmitting reaches the CRC field and the arbitration process begins, the next sequential message is in the other mailbox ready to win (and transmit). This method seems to fix the bus locking up without the double TX inactive mailbox routine.

Thanks for your feedback!
 
Sounds good so if we were to be bursting frames you recommend we let the ISR handle it via an interrupt enabled TX mailbox, and have regular writes use other mailboxes? Or just have sequential transfers in ISR? or both? How would we decide to configure that is the question, without breaking how users currently use it. Perhaps enabling a TX mailbox will automatically forward the TX queue to interrupts while events() skips doing that job, and what do we do about regular writes? As normal or automatically send them to queue when mailbox transmit interrupts are enabled? If thats the case, we should only offer an all TX interrupt enable or all TX poll command, ex enableTXInterrupts() ? What do you think?

I mean it wouldn't be hard if interrupts are enabled for all write() calls to queue whether sequential or not, and on dequeue any TX is selected, unless it is a seq flagged frame, in which case itll drop to absolute first TX mailbox

Obviously for the initial interrupts to occur, the mailboxes must be populated at least once else the ISR never fires. For bursting to work the first tx mailbox would fill then the ISR takes over, if no queue exists (all sent) then the new frame would have to hit mailbox before ISR retriggers again. And if we dont clear all TX interrupt flags ISR never stops firing. But maybe I have an idea, maybe we check if any mailboxes are available, if not, automatically queue. We make mailbox writing a priority and if none left everything goes to ISR from queue. We should also perhaps check if the queue exists, I think I did that along time ago on another library. If there are TX queues, immediately queue new frame, but then that dilemma leaves unused TX mailboxes from firing the ISR.. BUT, thats only for that specific mailbox the ISR flag. In the ISR we can actually have it find available TX mailboxes, it's already implemented there anyways! :) then we should just queue frames when interrupts are on and boom let ISR handle all TX mailboxes with queues
 
Last edited:
Seems like you have a good plan in mind.

From a user perspective, it could be nice if setup was performed similarly to the RX FIFO system. Perhaps enableFIFO() could have an optional argument that allow user to choose RX, TX, or RXTX for FIFOs. This would leave room for future addition (if desired) of user-assignable transmit callbacks without activating frame queueing.

FWIW, my original approach was dedicating the first 2 TX mailboxes for sequential. Normal writes use remaining TX mailboxes as usual. Sequential writes would try these two mailboxes, then add to queue. TX ISR would replenish the IFLAG'd mailbox with next msg from queue. With this method, I have some concern about the ISR firing after checking for available mailboxes but before adding the first message to queue. The ISR would see an empty queue so it would stop processing from queue (I think you mention this concern also).

I suppose the TX FIFO mailboxes wouldn't need to be reserved for FIFO only, although for my application I wouldn't want a queue of high priority sequential frames to be stuck behind a low priority non-sequential message that happened to be written first.
 
Ahh but the queue library is FIFO/LIFO, plus it also has a feature to pull in-between queues, although thats something I wouldn't touch while mixing loop() with ISR. I could however put normal writes at end of queue and sequential frames at front of queue, or better yet, no need to make additional code bloat. If TX interrupts are enabled, it doesn't matter what is in queue. The ISR itself will reserve the first mailbox for sequential frames and drop the rest in any of the others available (7 leftover mailboxes)

This can be more elegant and cleaner, else if we do FIFO/LIFO we'd have to turn off interrupt to push to front or back of queue then reenable, which I want to avoid. The ISR sees all the mailboxes so the queue will be depleted pretty fast while keeping it seq priority to 1st and any other tx queue goes to other MBs.

If we go down this path, keep in mind one more thing
If there are seq frames side by side in the queue the ISR will not dequeue until the priority frame is completely sent in the first mailbox. The only time the regular frames dequeue is if theres NO seq frame next in queue. This should be beneficial as well since that mailbox will be doing bus arbitration without others trying as well :)

On another point, do you really want transmit callbacks? I mean, whats the point, to show which messages were sent? If the queue dequeues, which callback does it goto if it sends a frame to any mailbox. Also setMB() can be used to change mailboxes after enableFIFO() is initiated. If a user wants specific mailboxes for interrupt receptions while anything else goes to FIFO thats possible already.

I wouldnt worry about the concern we had over sending frames. I like to keep the code simple. We should be able to queue directly without checking any mailboxes if tx interrupts are enabled. The ISR is always running during message receptions, and there is already a mailbox scan code in it. We can use this same system as a bonus for dequeueing transmissions and offloading them to TX mailboxes, with or without IFLAGS set, as long as theyre INACTIVE. My PC monitor is broke atm else I'd work on this, but taking notes with you on the approach before I get working on it :)
 
Last edited:
If there are seq frames side by side in the queue the ISR will not dequeue until the priority frame is completely sent in the first mailbox.
This is my understanding of how the current queue handles sending strictly sequential frames, or am I misunderstanding something? The main difference you are suggesting is whether the next frame is dequeued and written by events() or the ISR?

I believe the only way to get 3 bit interframe spaced bursts is to have the next sequential frame in a different mailbox waiting to participate in mailbox arbitration when the current transmission reaches the CRC field.
From the manual:
If the arbitration process does not manage to evaluate all Mailboxes before the CAN bus has reached the first bit of the Intermission field the temporary arbitration winner is invalidated and the FlexCAN will not compete for the CAN bus in the next opportunity.

Am I understanding that correctly?
 
Events() only queues sequentials. Normal writes are sent if mailboxes are available. However, we will handle interrupted TX differently. All seq and normal writes are immediately queued. Once the ISR fires, mailboxes are checked & scanned for received flags. We will use this same system for the following:

The first TX mb found in the scan gets flagged locally, and the queue is checked for available frames with seq bit. If the next queue is a seq frame, it will be dequeued and written to that mailbox. If it was a normal frame, during the same mailbox scan code, it will be dropped into the next available tx mailbox. This should be able to push out at most 8 transmits (if first queue was seq and rest were 7 normal writes) per ISR intermission. One of the queue's ability is we can scan any indice in the array for that magic seq bit. If there are none, then that first mailbox becomes a free for all for normal writes until someone sneaks in a seq frame, then dedication takes over :)

If tx interrupts will be enabled, events() will not touch the queue, it will need to ignore it while it stays dedicated to ISR.

Essentially, for every ISR interrupt, the queue will always be prepared to populate the TX mailboxes before exiting the ISR, so there should be tx mailboxes with many frames ready for action
 
That clarified much of my confusion. I'm almost there, just one more question:
When you say "The first TX mb found in the scan" do you mean the first TX with IFLAG asserted or first MB set as TX?
 
The first mailbox found, iflag or not is irrelevant, as long as it is seen as a TX mailbox. If its state is TX_INACTIVE, only then will queue populate it.

The iflag wont be set on the initial transfer, we clear the iflag after its transmission, so we dont scan by iflag we scan by mailbox type and check availability
 
FlexCAN_T4 teensy 4 transmit problems

Hi guys, I've been trying with little success to transmit can data from TEENSY 4.0 using a SN65HVD230 can transceiver attached to can2 pins. I can with a different program read can data from my ecu so i know the hardware is working and there are 120 ohm resistors on both ends of the bus. I have tried modifying a few different examples posted us here and i cant get any output even with the examples posted here.

the code is for a fuel flow differential meter to transmit flow and consumption data for a dashboard display. I'm not an expert but i have generally been able to modify and make most things work until now. if you could point me in the right direction your expertise would be much appreciated. code as follows

/* Teensy 4.0
* CAN2 using SN65HVD230 can tranciever
*/

#include <EEPROM.h>
#include <FlexCAN_T4.h>
FlexCAN_T4<CAN2, RX_SIZE_256, TX_SIZE_256> myCan;

CAN_message_t msg, rxmsg;

#define FEED 3 // oval gear flow meter hall effect digital input pin
#define RETURN 4 // oval gear flow meter hall effect digital input pin
#define Calibrate 5 // calibrate button

boolean EEPROM_INIT = 0;

unsigned long prevMillis;
unsigned long txIntervalMillis = 20; // send once per second

byte Data[8];

volatile unsigned long FLOWIN_COUNT = 0;
volatile unsigned long FLOWOUT_COUNT = 0;
unsigned long CURRENT_millis = 0;
unsigned long LAST_millis = 0;
unsigned long LAST_eeprom = 0;

int PPLIN;
int PPLOUT;
float UPDATE = 50.00; // ms between update cycles
float PPL = 1448.00;
float PPLin = 1448.00; // pulses per litre
float PPLout = 1448.00; // pulses per litre
float LPM = 0;
float FLOW_IN = 0;
float FLOW_RET = 0;
float FLOW_USED = 0;
float LASTFLOW = 0;
float LPMFACTOR;
boolean CALIBRATION_MODE = false;
boolean CAL = false;
float per_diff;
int PPLI1, PPLI2, PPLO1, PPLO2;
int AVE_COUNT = 0;
boolean AVE_RUNNING = false;
static uint32_t timeout;

void setup() {

pinMode(FEED, INPUT); // yellow
pinMode(RETURN, INPUT); // blue
pinMode(Calibrate, INPUT_PULLUP);
// pinMode(1, OUTPUT);
// digitalWrite(1, LOW);
Serial.begin(115200);
attachInterrupt(digitalPinToInterrupt(FEED), FLOW_INP, FALLING); // FEED LINE FLOW METER INTERRUPT
attachInterrupt(digitalPinToInterrupt(RETURN), FLOW_OUT, FALLING); // FEED LINE FLOW METER INTERRUPT
LPMFACTOR = ((PPL / 60.00)/1000.00); // L/M = ((PULSES PER LITRE / 60 SEC) /1000ms) ==> pulses per ms for 1 L/min flow

Serial.println("SimpleRxAckPayload Starting");


myCan.begin();
myCan.setBaudRate(500000);

if( EEPROM_INIT == true)
{
EEPROM_INITIALISE();
}

READ_EEPROM();

}

void READ_EEPROM(){

PPLIN = EEPROM.read(0)<<8;
PPLIN |= EEPROM.read(1);
PPLin = PPLIN / 10.00;
PPLOUT = EEPROM.read(2)<<8;
PPLOUT |= EEPROM.read(3);
PPLout = PPLOUT / 10.00;
Serial.print("PPLin = ");Serial.print(PPLin); Serial.print(" "); Serial.println(PPLIN);
Serial.print("PPLout = ");Serial.print(PPLout); Serial.print(" "); Serial.println(PPLOUT);
}

void EEPROM_INITIALISE(){ // enable in setup to write initial values to eeprom

PPLIN = 1448.00;
PPLOUT = 1448.00;
PPLI1 = (byte)((PPLIN>>8) & 0xFFu); //split pulse per litre input into msb
PPLI2 = (byte)(PPLIN & 0xFFu); //split pulse per litre input into lsb
PPLO1 = (byte)((PPLOUT>>8) & 0xFFu); //split pulse per litre output into msb
PPLO2 = (byte)(PPLOUT & 0xFFu); //split pulse per litre output into lsb

EEPROM.write(0, PPLI1); // Write values to EEPROM
EEPROM.write(1, PPLI2); // Write values to EEPROM
EEPROM.write(2, PPLO1); // Write values to EEPROM
EEPROM.write(3, PPLO2); // Write values to EEPROM

}

void WRITE_EEPROM(){

PPLIN = PPLin * 10;
PPLOUT = PPLout * 10;
PPLI1 = (byte)((PPLIN>>8) & 0xFFu); //msb
PPLI2 = (byte)(PPLIN & 0xFFu); //lsb
PPLO1 = (byte)((PPLOUT>>8) & 0xFFu); //msb
PPLO2 = (byte)(PPLOUT & 0xFFu); //lsb

EEPROM.write(0, PPLI1);
EEPROM.write(1, PPLI2);
EEPROM.write(2, PPLO1);
EEPROM.write(3, PPLO2);

}

void loop() {

if(digitalRead(Calibrate) == LOW && CALIBRATION_MODE == false)
{
AVE_RUNNING = true;
CALIBRATION_MODE = true;
}

CURRENT_millis = millis();

if( CURRENT_millis - LAST_millis > UPDATE)
{
LPM = FLOWIN_COUNT - LASTFLOW; // calculate how many pulses have occured since last calculation
CURRENT_millis = millis(); // update millis
LPM = LPM / ((CURRENT_millis - LAST_millis)/10.00); // divide by elapsed milliseconds
LPM = LPM / LPMFACTOR; // divide by the 1 L/min factor
FLOW_IN = FLOWIN_COUNT / PPLin; // TOTAL FLOW = #OF PULSES / PULSES PER LITRE
FLOW_RET = FLOWOUT_COUNT / PPLout; // TOTAL RETURN = #OF PULSES / PULSES PER LITRE
FLOW_USED = FLOW_IN - FLOW_RET; // USED = in - out count

per_diff = abs(((FLOW_RET / FLOW_IN)*100.00));
Serial.print(" FLOW DIFF PERCENTAGE = "); Serial.print(per_diff);


int LPMSEND = LPM * 100;
int FLOWSEND = FLOW_USED * 100;

//prepare data for can send . split into 2 bytes of most and least significant bits
Data[0] = (byte)((LPMSEND>>8) & 0xFFu); // Litres per minute msb
Data[1] = (byte)(LPMSEND & 0xFFu); // Litres per minute lsb
Data[2] = (byte)((FLOWSEND>>8) & 0xFFu); // flow msb
Data[3] = (byte)(FLOWSEND & 0xFFu); // flow lsb
Data[4] = 0;
Data[5] = 0;
Data[6] = 0;

Serial.print(" FLOWIN_COUNT = "); Serial.print(FLOWIN_COUNT);
Serial.print(" FLOWOUT_COUNT = "); Serial.print(FLOWOUT_COUNT);
Serial.print(" FLOW_IN = "); Serial.print(FLOW_IN);
Serial.print(" FLOW_RET = "); Serial.print(FLOW_RET);
Serial.print(" FLOW_USED = "); Serial.print(FLOW_USED);
Serial.print(" LPM = "); Serial.print(LPM);Serial.print(" LPMfactor = " );Serial.println(LPMFACTOR);

LAST_millis = millis();
LASTFLOW = FLOWIN_COUNT;

if(AVE_RUNNING == true) // runs with pumps on engine off to zero differential reading
{
if(AVE_COUNT < 1000)
{
PPLout = PPLout * (per_diff/100);
Serial.print("PPLout = "); Serial.println(PPLout);
AVE_COUNT ++;
}
else if(AVE_COUNT == 100)
{
WRITE_EEPROM(); // save new factor for calculations
AVE_RUNNING = false; // disable function
}
}
}


if (CURRENT_millis - prevMillis >= txIntervalMillis)
{
SEND_CAN();
}

}

void SEND_CAN(){


if ( millis() - timeout > 200 )

{ // send random frame every 1000ms
CAN_message_t msg;
msg.id = 0x236; // address ID 566
msg.buf[0] = Data[0];
msg.buf[1] = Data[1];
msg.buf[2] = Data[2];
msg.buf[3] = Data[3];
msg.buf[4] = Data[4];
msg.buf[5] = Data[5];
msg.buf[6] = Data[6];
msg.buf[7] = Data[7];
msg.len = 8;
msg.flags.extended = 0;
msg.flags.remote = 0;
myCan.write(msg);
timeout = millis();

Serial.print("SEND: ");
Serial.print(" ID: "); Serial.print(msg.id);
Serial.print(" Buffer: ");
for ( uint8_t i = 0; i < msg.len; i++ )
{
Serial.print(msg.buf); Serial.print(" ");
}
Serial.println();

}

// send data: ID 566 = 0x236, Standard CAN Frame, Data length = 8 bytes, 'data' = array of data bytes to send
// byte sndStat = myCan.sendMsgBuf(0x236, 0, 8, Data);
// if(sndStat == CAN_OK){
// Serial.println("Message Sent Successfully! --> ");
// Serial.print(Data[0]);
// Serial.print(", ");
// Serial.print(Data[1]);
// Serial.print(", ");
// Serial.print(Data[2]);
// Serial.print(", ");
// Serial.print(Data[3]);
// Serial.print(", ");
// Serial.print(Data[4]);
// Serial.print(", ");
// Serial.print(Data[5]);
// Serial.print(", ");
// Serial.print(Data[6]);
// Serial.print(", ");
// Serial.print(Data[7]);
// Serial.println(" || ");
// } else {
// Serial.println("Error Sending Message...");
// }

}

void FLOW_INP(){
FLOWIN_COUNT++;
}

void FLOW_OUT(){
FLOWOUT_COUNT++;
}
 
Is your Rs pin tied low on the transceiver? When you say output, do you see any data reception on the bus to confirm your seeing the stream? What pins are you using on T4 for the transceiver?

I don't see any callbacks set, are you only using this to transmit messages and not receive any?
 
I assume you mean the Rx pin and i haven't tied low. The transceiver is connected as per the Teensy 4 pinout card to pins 0 and 1 for CAN2. I am using a teensy 3.5 to read can and verify however no output what so ever and no activity on when i have scoped the output of the CAN HI pin either.
 
Use a receive demo to make sure your receiving traffic, to make sure transceiver works before transmitting, I was referring to the standby pin on transceiver, if its not held low the traffic may not flow
 
Ok, i just checked the transceiver board and rs pin was not connected to anything. i have run a jumper wire from Rs pin (8) on the SN230 to ground. I have the teensy 3.5 and teensy 4 connected to the engine management to check receive data stream on both boards and both are receiving data correctly. After loading the flowmeter sketch back in and watching output on the teensy 3.5 i still have nothing coming out of the teensy 4. could it be something in the initiation i have missed?

FlexCAN_T4<CAN2, RX_SIZE_256, TX_SIZE_16> myCan;

myCan.begin();
myCan.setBaudRate(500000);
 
Maybe try simple transmitting code in addition from a receiving sketch to check if their are transfers, if you still cant see any transmits, try printing mailboxStatus() after awhile to see if the transmit mailboxes are stuck
 
I reloaded the github release onto my car's T4 to make sure it was the latest loaded, and it's still transmitting fine on the bus. I didn't like the faint chirp of the beeper in the back so when arming the car i send the horn signal over canbus twice for a double confirmation beep. It seems to be working fine here. The timing between horn on and off frames is about 17ms gap so the horn sort of chirps briefly rather than give a loud honk.
 
Thanks for the help so far tonton81, i double checked everything after i had a few minutes spare. I can see the signal coming out of the Teensy 4 on the TX pins on both CAN1 and CAN2 but nothing is being transmitted by the transceiver chips. Can read perfectly on both CAN1/2 with two identical transceivers but nothing out. What transceivers have you played with that actually work?? Or is there anything else i can try to make these work??
 
My tests are ran off the pjrc and skpang breakout boards, CAN1 is connected to BCAN of vehicle at 125kbps and CAN2 is connected to FCAN of vehicle at 500kbps. Did you check if mailboxStatus() displays TX info pending on transmit mailboxes but never sent while you are receiving?
 
Micky,
I've confirmed FIFO message reception and standard mailbox transmission for the following transceivers:
TI TCAN330GD
MCP2562-E/SN
Microchip MCP2551-I/SN
TI SN65HVD232D

Out of curiousity, what CAN library are you running on the T3.5?

When you are testing the T4.0's output with the T3.5, are their any other CAN devices on the bus? Is the Rs pin on the T3.5 pulled to ground? Something needs to ACK messages the T4.0 is trying to transmit.
 
Hi msadie,
So on the Teensy 3.5 i am running the IFCT library with a can sniffer sketch. i have connected the Engine management on the same bus as the Teensy 3.5 and the Teensy 4.0 with transceivers on both Can1 and Can2 ports. When i power the ECU up and the data stream starts, i can watch the Data appear on the Teensy 3.5 monitor and i can switch between can1 and can2 on the Teensy 4 and see the data coming in over each of the two transceivers.
I have also tried to connect only the the two transceivers on the teensy 4 together and loaded read/write programs to no avail.
when i run the Flow counter program i posted above, i can see activity on the TX pin from the teensy on both can1 and can2 channels when i change between them but there is no driven differential output on the can lines after the transceiver.

As for the transceiver, the pcb has a 10K pull down to ground on the Rs pin which enables slope mode according to the datasheet as it is a VD230 chip on the board.

And tonton81,
I honestly am a little out of my depth with the mailbox system. What would i have to include in the program and where to check the mailboxStatus()? i assume we need to include something along the lines of myCan.mailboxStatus(); in the setup but after that i wouldn't know what to include.

if its not too much trouble would you be able to make the changes to the program and post it back so i can run it tonight an see if there are any changes? Or could someone run the program on a Teensy 4 with a can transducer and test if they have can output to rule out the software?
 
You just need to add the following line. Anytime it is called, it will print the status of all mailboxes to the serial monitor.
Code:
myCan.mailboxStatus();

I suggest adding it a couple places:
1. In setup after setting baud rate. This will show you what it returns for empty mailboxes.
Code:
myCan.begin();
myCan.setBaudRate(500000);
myCan.mailboxStatus();
2. In your loop(), add the following to print mailbox status every 2 sec
Code:
static uint32_t timeoutMBStatus = millis();
if ( millis() - timeoutMBStatus > 2000 ) {
  myCan.mailboxStatus();
  timeoutMBStatus= millis();
}

I can look at running an abbreviated version of your code tomorrow.
 
msadie is correct, if you start seeing the transmit buffers fill but not actually transfer, yet reception works, there is an issue with the transceiver. I have yet no evidence to suspect any software in play here between a transceiver working on T3.5/3.6 but not playing nice on T4, the baudrate code is the exact same as IFCT except for the flexcan clock on T3 being 16MHz and T4 defaults to 24MHz.

Perhaps try using Can0.setClock(CLK_16MHz) before or after setBaudRate, it SHOULD work before or after, if a clock isnt defined before setBaudRate 24MHz is selected, if the clock is changed after setBaudrate, setBaudrate will be called automatically on the new clock based on your last bitrate. Worth a try :)

FlexCAN_T4 is also backwards compatible with T3.2,3.5,3.6, basically an updated version of IFCT
 
Last edited:
Ok, so tried the suggested myCan.mailboxStatus(); in the setup and loop and this is what i am getting in the monitor;

FIFO Disabled
Mailboxes:
MB0 code: RX_EMPTY (Standard Frame)
MB1 code: RX_EMPTY (Standard Frame)
MB2 code: RX_EMPTY (Standard Frame)
MB3 code: RX_EMPTY (Standard Frame)
MB4 code: RX_EMPTY (Extended Frame)
MB5 code: RX_EMPTY (Extended Frame)
MB6 code: RX_EMPTY (Extended Frame)
MB7 code: RX_EMPTY (Extended Frame)
MB8 code: TX_DATA (Transmitting)(Standard Frame)(ID: 0x236)(Payload: 0 0 0 0 F 11 13 16)
MB9 code: TX_DATA (Transmitting)(Standard Frame)(ID: 0x236)(Payload: 0 0 0 0 F 11 13 16)
MB10 code: TX_DATA (Transmitting)(Standard Frame)(ID: 0x236)(Payload: 0 0 0 0 F 11 13 16)
MB11 code: TX_DATA (Transmitting)(Standard Frame)(ID: 0x236)(Payload: 0 0 0 0 F 11 13 16)
MB12 code: TX_DATA (Transmitting)(Standard Frame)(ID: 0x236)(Payload: 0 0 0 0 F 11 13 16)
MB13 code: TX_DATA (Transmitting)(Standard Frame)(ID: 0x236)(Payload: 0 0 0 0 F 11 13 16)
MB14 code: TX_DATA (Transmitting)(Standard Frame)(ID: 0x236)(Payload: 0 0 0 0 F 11 13 16)
MB15 code: TX_DATA (Transmitting)(Standard Frame)(ID: 0x236)(Payload: 0 0 0 0 F 11 13 16)

I aslo tried to set the clock speed to 16Mhz but the program would not run unless it was set back to 24Mhz.

still seeing Tx pin activity on both Can1 and Can2 when i switch between them but no output on the bus lines themselves
 
Back
Top