FlexCAN_T4 - FlexCAN for Teensy 4

I see you setting K bus filter but not setting up the K bus, unless you posted partial code, can't help much. the filters are only updatable while the bus is deactivated, so that is fine and does as it's expected to. But if you're setting things that are not complete it could result in a lock, which is why you don't see the KBUS print in serial monitor.
 
Morning, thanks for the response. K-bus is set up, I just included some sample code to show how the existing stuff initialises things and sets filters- K/V bus very similar in terms of filters.

Will try disableFIFO() instead, hopefully that helps - not seeing a method to deactivate the bus entirely, but they're defined as:

Code:
FlexCAN_T4<CAN1, RX_SIZE_256, TX_SIZE_256> K_Bus;

Dispose of the object, perhaps?

edit: disableFIFO hasn't hung the Teensy, so will keep on with the program, maybe that's all I needed. Thanks!
 
Awesome, thank you !

Code:
Disabled KBUS
10:45:40:237 -> 0, V-Bus, MB: 4, ID: 0x18FFFB13, EXT: 1, LEN: 8, DATA: 0, 26, 4, 29, 165, 56, 0, 15, 
Sending status stuff to UDP:  ResponseCode: 174  barr length: 24  Bus: 2
10:45:40:407 -> 0, V-Bus, MB: 4, ID: 0x18FFFB13, EXT: 1, LEN: 8, DATA: 0, 26, 4, 29, 165, 56, 0, 15, 
Sending status stuff to UDP:  ResponseCode: 174  barr length: 24  Bus: 2
10:45:40:501 -> 0, V-Bus, MB: 4, ID: 0x18FFFF13, EXT: 1, LEN: 8, DATA: 118, 16, 77, 5, 161, 255, 73, 255, 
Sending status stuff to UDP:  ResponseCode: 174  barr length: 24  Bus: 2
10:45:40:623 -> 0, V-Bus, MB: 4, ID: 0x18FFFB13, EXT: 1, LEN: 8, DATA: 0, 26, 4, 29, 165, 56, 0, 15, 
Sending status stuff to UDP:  ResponseCode: 174  barr length: 24  Bus: 2
10:45:40:824 -> 0, V-Bus, MB: 4, ID: 0x18FFFB13, EXT: 1, LEN: 8, DATA: 0, 26, 4, 29, 165, 56, 0, 15, 
Sending status stuff to UDP:  ResponseCode: 174  barr length: 24  Bus: 2
 
I am trying to do a multi-thread with 4.1 teenys. Is this possible with this teensy? This is my code:

#include <Arduino.h>
#include <FlexCAN_T4.h>

FlexCAN_T4<CAN1, RX_SIZE_256, TX_SIZE_16> can1;
int state = 0;
int buzzerPin = 15;
int frequency = 1000;
bool first = false;
int N_SAMPLES = 10;

int MAX_APPS = 1024;

void control() {
if(state == 0) {
state++;
//mandar dar início ao precharge
}
else if(state == 1) {
state++;
// digitalWrite(24,HIGH); //ativar o TS
}
else if(state == 2) {
// state++;
// digitalWrite(25,HIGH); //ativar o R2D mode

analogWrite(buzzerPin, 0); // Turn off the buzzer for the other half of the period
delay(4000);
analogWrite(buzzerPin,256);
delay(4000);

}
else if(state == 3) {
state = 0;
}
}

void handleAPPS()
{
while (1) {
if(state == 0){
Serial.println("Entered state 0");
if(digitalRead(8) == HIGH) {
control();
Serial.println("Going out state 0");
delay(1000);
}
delay(1000);
}
else if(state == 1){
Serial.println("Entered state 1");
if(digitalRead(9) == HIGH) {
control();
Serial.println("Going out state 1");
delay(1000);
}
delay(1000);
}
else if(state == 2) {
Serial.println("Entered state 2");
control();

if(digitalRead(10) == HIGH) {
control();
Serial.println("Going out state 2");
}
}
else if(state == 3) {
if(!first)Serial.println("Entered state 3"); first = true;

int v_apps1 = 0;
int v_apps2 = 0;

for (int i = 0; i < N_SAMPLES; i++) {
v_apps1 += analogRead(A17);
v_apps2 += analogRead(A16);
delay(1);
}

v_apps1 /= N_SAMPLES;
v_apps2 /= N_SAMPLES;

double avg = (v_apps1 + v_apps2) / 2.0;
double value = (avg / MAX_APPS) * 100.0;
int16_t value_bamo = static_cast<int16_t>((avg/100) * 32767.0);

// desvio(v_apps1, v_apps2);

// String output = String(v_apps1, DEC) + "\t" + String(v_apps2, DEC) + "\t" + desvio(v_apps1, v_apps2) + "%";
// Serial.printf("Value being transmited: %d \n",output);

uint8_t byte1 = (value_bamo >> 8) & 0xFF; //MSB
uint8_t byte2 = value_bamo & 0xFF; //LSB

CAN_message_t msg;
// definir a mensagem de acordo com o que o BAMOCAR pede
// torque command value
msg.id = 0x201;
msg.len = 3;
msg.buf[0] = 0x90;
msg.buf[1] = byte2; //2 bytes for the value: 50% -> 16380
msg.buf[2] = byte1;
can1.write(msg);

// CAN_message_t msg;
// // definir a mensagem de acordo com o que o BAMOCAR pede
// // speed command value
// msg.id = 0x201;
// msg.len = 3;
// msg.buf[0] = 0x31;
// msg.buf[1] = 0xCD;

// msg.buf[2] = 0x0C; //2 bytes for the value: 100% -> 32767
// can1.write(msg);
delay(100);

}

delay(10); // Adjust the delay based on your task requirements
}
}

void handleDisplay()
{
while (1) {
// Handle display programming logic
// ...

delay(20); // Adjust the delay based on your task requirements
}
}

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

can1.begin();
can1.setBaudRate(125000);

pinMode(buzzerPin,OUTPUT);
pinMode(24,OUTPUT);
pinMode(25,OUTPUT);

pinMode(40,INPUT);
pinMode(18,INPUT);
pinMode(23,INPUT);
pinMode(10,INPUT);

analogWrite(buzzerPin, 256); // Set the duty cycle to 50%

// Start the multitasking system by creating separate tasks
// Each task runs in an infinite loop and cooperatively yields control to other tasks using delays

// Task 1: Handling APPS
Thread appThread(handleAPPS, "APPS", 4096, NULL, 1); // Create a thread with 4KB stack size

// Task 2: Programming the display
Thread displayThread(handleDisplay, "Display", 4096, NULL, 1); // Create a thread with 4KB stack size
}

void loop() {

}



Is it multi-threading possible with teensy 4.1? thanks you for your time
 
I am trying to do a multi-thread with 4.1 teenys. Is this possible with this teensy? This is my code:

Code:
#include <Arduino.h>
#include <FlexCAN_T4.h>

FlexCAN_T4<CAN1, RX_SIZE_256, TX_SIZE_16> can1;
int state = 0;
int buzzerPin = 15;
int frequency = 1000;
bool first = false;
int N_SAMPLES = 10;

int MAX_APPS = 1024;

void control() {
  if (state == 0) {
    state++;
    //mandar dar início ao precharge
  }
  else if (state == 1) {
    state++;
    // digitalWrite(24,HIGH); //ativar o TS
  }
  else if (state == 2) {
    // state++;
    // digitalWrite(25,HIGH); //ativar o R2D mode

    analogWrite(buzzerPin, 0); // Turn off the buzzer for the other half of the period
    delay(4000);
    analogWrite(buzzerPin, 256);
    delay(4000);

  }
  else if (state == 3) {
    state = 0;
  }
}

void handleAPPS()
{
  while (1) {
    if (state == 0) {
      Serial.println("Entered state 0");
      if (digitalRead(8) == HIGH) {
        control();
        Serial.println("Going out state 0");
        delay(1000);
      }
      delay(1000);
    }
    else if (state == 1) {
      Serial.println("Entered state 1");
      if (digitalRead(9) == HIGH) {
        control();
        Serial.println("Going out state 1");
        delay(1000);
      }
      delay(1000);
    }
    else if (state == 2) {
      Serial.println("Entered state 2");
      control();

      if (digitalRead(10) == HIGH) {
        control();
        Serial.println("Going out state 2");
      }
    }
    else if (state == 3) {
      if (!first)Serial.println("Entered state 3"); first = true;

      int v_apps1 = 0;
      int v_apps2 = 0;

      for (int i = 0; i < N_SAMPLES; i++) {
        v_apps1 += analogRead(A17);
        v_apps2 += analogRead(A16);
        delay(1);
      }

      v_apps1 /= N_SAMPLES;
      v_apps2 /= N_SAMPLES;

      double avg = (v_apps1 + v_apps2) / 2.0;
      double value = (avg / MAX_APPS) * 100.0;
      int16_t value_bamo = static_cast<int16_t>((avg / 100) * 32767.0);

      // desvio(v_apps1, v_apps2);

      // String output = String(v_apps1, DEC) + "\t" + String(v_apps2, DEC) + "\t" + desvio(v_apps1, v_apps2) + "%";
      // Serial.printf("Value being transmited: %d \n",output);

      uint8_t byte1 = (value_bamo >> 8) & 0xFF; //MSB
      uint8_t byte2 = value_bamo & 0xFF; //LSB

      CAN_message_t msg;
      // definir a mensagem de acordo com o que o BAMOCAR pede
      // torque command value
      msg.id = 0x201;
      msg.len = 3;
      msg.buf[0] = 0x90;
      msg.buf[1] = byte2; //2 bytes for the value: 50% -> 16380
      msg.buf[2] = byte1;
      can1.write(msg);

      // CAN_message_t msg;
      // // definir a mensagem de acordo com o que o BAMOCAR pede
      // // speed command value
      // msg.id = 0x201;
      // msg.len = 3;
      // msg.buf[0] = 0x31;
      // msg.buf[1] = 0xCD;

      // msg.buf[2] = 0x0C; //2 bytes for the value: 100% -> 32767
      // can1.write(msg);
      delay(100);

    }

    delay(10); // Adjust the delay based on your task requirements
  }
}

void handleDisplay()
{
  while (1) {
    // Handle display programming logic
    // ...

    delay(20); // Adjust the delay based on your task requirements
  }
}

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

  can1.begin();
  can1.setBaudRate(125000);

  pinMode(buzzerPin, OUTPUT);
  pinMode(24, OUTPUT);
  pinMode(25, OUTPUT);

  pinMode(40, INPUT);
  pinMode(18, INPUT);
  pinMode(23, INPUT);
  pinMode(10, INPUT);

  analogWrite(buzzerPin, 256); // Set the duty cycle to 50%

  // Start the multitasking system by creating separate tasks
  // Each task runs in an infinite loop and cooperatively yields control to other tasks using delays

  // Task 1: Handling APPS
  Thread appThread(handleAPPS, "APPS", 4096, NULL, 1); // Create a thread with 4KB stack size

  // Task 2: Programming the display
  Thread displayThread(handleDisplay, "Display", 4096, NULL, 1); // Create a thread with 4KB stack size
}

void loop() {

}


Is it multi-threading possible with teensy 4.1? thanks you for your time

When posting code in your message, you can use the "#" button (just above the area where you enter the text") to enclose the code in "CODE" tags. Doing so will preserve the formatting, which as you can see above, makes the code much easier to read.

To answer your primary question (is this type of multi-threading possible with T4.1 ??), the answer is "maybe". I did not actually load/run your sketch, so quick my analysis may be flawed. Also, I've not used threading on the T4.x myself, so I am by no means an expert on the topic. However, I would point out a couple of things to consider:

- inside of a thread, you should probably be using some kind of thread-safe "threadDelay()" rather than "delay()"

- your current sketch appears that it will get stuck in state 2 ("state++" is commented out)

- why use threads at all ?? you could probably keep the "state-driven" logic in "handleApps()" by just calling handleApps() in your "loop()"...then, all it appears that you need is some way to decide when to call "handleDisplay()"

- if you use a physical display with a driver that allows a framebuffer, you could write to the display asynchronously, then you could call "handleDisplay()" if/as needed (when something changes, or when an update is required)

Hope that helps . . .

Mark J Culross
KD5RXT
 
EDIT: I found that my problem is with my CAN adapter, nothing else as of now. I will update this message later when I am sure there are no other issues, thanks.

Hi, I'm working on getting my first CAN program to function, and in order to troubleshoot I've set about uploading tonton81's github example "CAN2.0_example_FIFO_with_interrupts.ino" from https://github.com/tonton81/FlexCAN...rupts/CAN2.0_example_FIFO_with_interrupts.ino to my Teensy 4.1 board.

Near as I can tell, I needed to adjust the FlexCan_T4 constructor (I'm coming from the software side of things, I'm working with an electrical engineer on this project) to use the CAN2 option because the schematic I'm working with uses pins 22/23 for TX/RX. My slightly adjusted code is below.

Code:
#include <FlexCAN_T4.h>
FlexCAN_T4<CAN2, RX_SIZE_256, TX_SIZE_16> Can2; // Pin 22 = TX, Pin 23 = RX
int x = 0;

void setup(void) {
  Serial.begin(115200); delay(400);
  //pinMode(6, OUTPUT); digitalWrite(6, LOW); /* optional tranceiver enable pin; I commented this out */
  Can2.begin();
  Can2.setBaudRate(250000);
  Can2.setMaxMB(16);
  Can2.enableFIFO();
  Can2.enableFIFOInterrupt();
  Can2.onReceive(canSniff);
  
}

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() {
  Can2.events();

  static uint32_t timeout = millis();
  if ( millis() - timeout > 200 ) {
    CAN_message_t msg;
    msg.id = random(0x1,0x7FE);
    for ( uint8_t i = 0; i < 8; i++ ) msg.buf[i] = i + 1;
    Can2.write(msg);
    timeout = millis();
  }
  
  Serial.print("HELLO WORLD\n");
  delay(1000);
  Serial.print(x);
  Serial.print("\n");
  x++;
}

My serial output functions as I expect, with incrementing x values, however when I run PCAN-View software to see if there is activity on the CAN bus, I don't see any data being written (I am new to PCAN-View, but I think I have that configured correctly regardless). I have verified that the wiring on the CAN adapter is accurately hooked up according to the documentation. How can I see the CAN output that I need? Screenshots of my PCAN-View settings are below.

pcan_view_settings.PNG
pcan_view_settings2.PNG

Things I've already tried include adjusting the acceptance filter in the above settings to include Extended (29-bit) IDs and uncommenting out the pinMode(6, Output) line (in tonton81's original code, this line is not commented out, I've since read elsewhere that this line is unnecessary for what I'm doing). On another note, I am suspicious that there is something that pertains to the transceiver my electrical engineer is using that I'll need to edit, though I didn't find anything that relates to transceivers in the FlexCAN_T4 library.

I'm open to adjusting anything about my strategy, as I said I'm new to CAN buses and it is likely that, from an experienced developer's perspective, I am missing something basic. Let me know if you require more info to help and thank you for any help.
 
Last edited:
Evidently I can't edit my own message from yesterday? Regardless, this issue was solved by troubleshooting my hardware. I don't think I can delete my message either, so I guess we'll have to let it be a small monument to software engineers who haven't yet learned how to verify board functionality. Fwiw, I should have asked for help from an electrical engineer sooner...
 
Problems sending a message

Hi I am programming my teensy 4.1 in order to send messages to my motor. The goal is to change the motor's speed but nothing is happenning. I attached the CAN manual.
Basically, I am reading a value from a pontentiometer and converting to the proportion of my motor and then I send it through a CAN message. This is my code:

Code:
#include <Arduino.h>
#include <FlexCAN_T4.h>

FlexCAN_T4<CAN1, RX_SIZE_256, TX_SIZE_16> can1;

int max_v = 1023;

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

  can1.begin();
  can1.setBaudRate(500000);
}

void loop() {

  int val = analogRead(15);
  
  uint16_t value_bamo = val * 32767.0 / max_v;
  
  uint8_t byte1 = (value_bamo >> 8) & 0xFF; //MSB
  uint8_t byte2 = value_bamo & 0xFF; //LSB

  Serial.print("byte1: ");
  Serial.print(byte1,HEX);
  Serial.print("\n byte2: ");
  Serial.print(byte2,HEX);
  //definir a mensagem de acordo com o que o BAMOCAR pede
  //speed command value

  Serial.printf("\n Value sent: %d",value_bamo);
  
  CAN_message_t msg;
  msg.id = 0x201;
  msg.len = 3;
  msg.buf[0] = 0x31;
  msg.buf[1] = (byte2); 
  msg.buf[2] = (byte1);
  
  can1.write(msg);

  Serial.println("\n Message sent!");
  delay(1000);

  CAN_message_t message2;
    if (can1.read(message2)) {
    Serial.print("Received message with ID 0x");
    Serial.print(message2.id, HEX);
    Serial.print(": ");
    for (int i = 0; i < message2.len; i++) {
      Serial.print(message2.buf[i]);
    }
    Serial.print('\n');
  }
}
 

Attachments

  • CAN_BAMOCAR.pdf
    1.3 MB · Views: 2,067
I am implementing the FlexCAN_T4 library, and I wanted to control that canBus.begin(); it wakes up or starts and like many other controllers... you can assign a variable: StatusCAN = canBus.begin(); and then be able to put a message.
It's not possible ?
I have seen that it worked before...
Can someone give me a bit of their wisdom.
a flying smile
 
Hello tonton81

The FlexCAN library works like a charm, setup and send & receive worked out of the box.

I would like to use the Teensy as a testing device, so I would need to switch the can tranceivers on and off with different baud rates and in listen/normal mode (e.g. to scan for baud rates). Getting also some information about error frames and bus heavy / bus dead would be great.

Is that anyhow supported by the FlexCAN library, or what else I would have to do while not interfearing the library functionality. It is possible at all?

Maybe you could give me some advice?

thanks in advance! :rolleyes:
 
well it does support self-recovery, you could just set the baudrates in listen-only mode and check if the callback fires. callbacks only fire for valid receptions
 
Good morning to Montreal :)

I'm just reading the header file.. So the magic would be to use the setBaudRate() method on an existing can object to change its baudrate and its mode (normal or listen) to switch between normal and listen?
 
I've already given it a try - it works. As you said, Bus off I can identify on not having any msgs received. So at last I need to find the error flag in the documentation :)
 
the error info has been added there if you check the source file, as per another user request, it has it's own callback
 
Hello tonton81,
I am using your great library, but I miss a function to read a specifc mailbox.

I'm using dedicated mailboxes, just receiving one single Can-Message/Identifier per Mailbox.
I want to read out that specific content of the Can-Message, even it has been received some while ago.

Thus, I'm looking for:
C++:
readMB(CAN_message_t &msg, FLEXCAN_MAILBOX mb_num)
I think it is very similar to your existing
C++:
readMB(CAN_message_t &msg)
function, but without the for-loop searching for the next received message.
It shall return even already read mailboxes (State FLEXCAN_MB_CODE_RX_EMPTY)


Do you think it is worth to implement this into your library?

Thanks for your work
 
Am I the only one who finds the pattern of FlexCAN_T4<CAN1, RX_SIZE_256, TX_SIZE_16> myCAN; very inconvenient? The generics are exploited as parameters here, which makes it very ugly to pass this variable around or even make the used CAN port dynamic.

FlexCAN_T4 myCAN = FlexCAN_T4(CAN1,RX_SIZE_256, TX_SIZE_16); would have been much better in my opinion.
 
@Srx only the syntax may look ugly at first, especially if you come from C# background where you use Generics. In C++ there are benefits in using Templates because they are generating the code (e.g. instantiating a template) with the parameters (type and values) you exactly wanted, allowing optimization that generates more performant and smaller code.
 
@Srx only the syntax may look ugly at first, especially if you come from C# background where you use Generics. In C++ there are benefits in using Templates because they are generating the code (e.g. instantiating a template) with the parameters (type and values) you exactly wanted, allowing optimization that generates more performant and smaller code.
I'm not so skilled in C++ with templates. Can you show me how to declare a method that accept any FlexCAN_T4 instance as parameter?
 
Hello everyone, first time psoting anything,

It has been a while since any communication occured here and I am not sure if this is still maintained but here goes.
I have tried using the lib and I can send CAN and CANFD Frames but I have issues when I try to send CANFD frames with brs.

Here is the code:
#include <FlexCAN_T4.h>

FlexCAN_T4FD<CAN3, RX_SIZE_256, TX_SIZE_128> can;
elapsedMillis t_ms;
CANFD_message_t msg;
uint8_t error = 0;

Code:
void setup() {
  can.begin();
  CANFD_timings_t cfg;
  cfg.clock = CLK_80MHz;
  cfg.baudrate = 500000;
  cfg.baudrateFD = 2000000;
  cfg.propdelay = 190;
  cfg.bus_length = 1;
  cfg.sample = 80;
  can.setRegions(64);
  error = can.setBaudRate(cfg);
  msg.id = 0x01;
  msg.len = 2;
  Serial.begin(115200);
  msg.brs = 1;
  msg.edl = 1;
  delay(1000);
}

void loop() {
  if (t_ms >= 1000) {
    Serial.println(error);
    t_ms = 0;
    msg.buf[0] = 0x21;
    can.write(msg);
  }
}


As you can see it is exceedingly simple.
The issue comes from sending with BRS bit set to 1.
Sending normal CAN 2.0 frames and sending CANFD frames WITHOUT the BRS bit set will work.
It doesnt even really matter at which speed 250k 500k 1000k, it always works.
But if I try to send a CANFD frame with brs enabled, with a switch from 500k to 1000K (or any other speed) it will fail.
Here is an example of a frame that is send with normal CANFD messages without BRS at 500k. (Sorry only got one probe)
This frame is totally fine and works (CAN_OK).
CAN_OK.png
I even decoded it by hand to make sure everything works as expected.
It does not look very good as the flanks are quite bad but the PCAN_USB device has no issue with sending and receiving data with the Teensy 4.1 with these settings.

It's also NO Problem to receive CANFD data with BRS up to 2Mbit, any higher and the flanks are to bad to read out but that is a separate issue. I can also receive CAN 2.0 and CANFD messages without BRS enabled.

I guess it is an issue with the BRS and stuffing bits. See what happens when I try to send a CANFD message with BRS enabled (with BRS from 500k to 500k but this also happens with switch from 500k/1M or 500k/2M). This will send 6 consecutive bits in the data section without stuffing bits. After the sixth bit with the same value the message will be canceled and the device tries to send the message again. This also fails of course.
CAN_500k_500K_Ohno.png


I even checked the documentation of the IMXRT1060/1062 and doubechecked if maybe some bits in the CTRL register or wherever are not set correctly but I cant find anything wrong. What I dont get is why I get 6 consecutive bits in the data section without bit stuffing when the BRS bit is set for the message? As far as I know there is no way to deactivate the bit stuffing on the IMXRT either.
The send data does not reflect what should be send at all either. Here is an example with BRS 500k/1M. It should have the same data as the first example with the normal CAN message except for the BRS bit and the changed speed.
CAN_500k_1M_damn.png


Does anyone know what could be the issue here?
I am using a Teensy 4.1 and the current version of the lib.
I am also using the tranceiver MCP2562FD if that is important. The Teensy is connected with a shielded twisted pair cable and I made sure that both sides are terminated with a 100Ohms resistors.

Any help would be appreciated :)
 
First the 100Ohm terminator is a bit low. They recommend 120Ohm.

Try and change the clock setting from:

cfg.clock = CLK_80MHz;

to

cfg.clock = CLK_24MHz;

I think 80MHz is too high or it is not a clean dividable to get 2Mbps.
 
SK Pang is correct regarding the clock. I ran your code with a MCP2558FD transceiver and Vector CANalyzer. Red lines are CLK_80MHz, black are CLK_24MHz.

1709070570574.png
 
Back
Top