Another fork of FlexCAN

CollinK

Well-known member
I was saying to myself "What the world needs is yet another fork of the FlexCAN library" so, I did that.

https://github.com/collin80/FlexCAN_Library

This is a fork of a fork (I forked Pawelsky's version and Pawelsky forked Teachop's version).

People who liked the library the way it was will want to look away. I changed an awful lot. It is almost possible to use existing code as-is but some assumptions need to be re-evaluated and library initialization is completely different. Essentially I took my work on the due_can library and moved it over the FlexCAN. That means fully interrupt driven Rx and Tx of CAN frames and the ability to register callbacks so that your code gets messages immediately when they come in without any polling. due_can supported doing this both in C code and with C++ classes. I didn't bring over the C code version of callbacks because I'm trying not to over complicate the FlexCAN library. So, it's kind of like due_can but with less complication. Not everything has been well tested yet (and I haven't updated the readme file or anything) but there are two new examples and I have tested it to be stable while sending and receiving very high bus loads. Filtering will be a little odd yet but it defaults to allowing all frames through so mostly the filtering could be ignored for now.

This version of the library is much larger and more complicated than before. This brings with it additional code and RAM bloat. If you were pushing the limits before you might not like that. But, it's only about 3k in code and 2k in RAM.

I have only tested on Teensy 3.6 hardware but all the defines are in there and it should work on all the Teensy 3.x boards.

I'll work on updating the readme to match the new format. I'm open for suggestions on what you'd like to see in this version of the FlexCAN library. I know Paul would like the CAN libraries across multiple architectures to match in API. I suppose being that my repos have three different platforms (teensy, due, mcp2515 on AVR) I would be in a good position to do that if I weren't running out of round tuits.
 
Would you be willing to add some send examples? I can't recall if any of the libraries have send examples, I just remember there were lots of questions about sends in the CAN thread. Great job regardless!
 
Would you be willing to add some send examples? I can't recall if any of the libraries have send examples, I just remember there were lots of questions about sends in the CAN thread. Great job regardless!

That's not a bad idea. The two examples I included both do send. They're both for the Teensy 3.6 and use one CAN bus to send to the other. That way you can see both sending and receiving. But, both examples are rather terse. Not a lot of detail went into how to send frames though it might be somewhat apparent from the examples. I'll work on getting more and better examples put together.
 
Does this library work on Teensy 3.2 ?

I've tried it but it won't compile.

/Users/sukkinpang/Documents/Arduino/Arduino.app/Contents/Java/hardware/teensy/avr/libraries/FlexCAN/FlexCAN.cpp: In function 'void can1_message_isr()':
/Users/sukkinpang/Documents/Arduino/Arduino.app/Contents/Java/hardware/teensy/avr/libraries/FlexCAN/FlexCAN.cpp:546:5: error: 'Can1' was not declared in this scope
Can1.message_isr();
^
/Users/sukkinpang/Documents/Arduino/Arduino.app/Contents/Java/hardware/teensy/avr/libraries/FlexCAN/FlexCAN.cpp: In function 'void can1_bus_off_isr()':
/Users/sukkinpang/Documents/Arduino/Arduino.app/Contents/Java/hardware/teensy/avr/libraries/FlexCAN/FlexCAN.cpp:550:5: error: 'Can1' was not declared in this scope
Can1.bus_off_isr();
 
The T_3.6 two can buses are Can0 and Can1 - so that Can1 needs to be under: #ifdef __MK66FX1M0__

Those "#ifdef __MK66FX1M0__" should include and allow the K64 too right?

#if defined(__MK64FX512__) || defined(__MK66FX1M0__)

CollinK - you could hit 'Ctrl+R' Verify in the IDE after selecting a T_3.2 even if you don't have one to confirm they are clean.
 
The T_3.6 two can buses are Can0 and Can1 - so that Can1 needs to be under: #ifdef __MK66FX1M0__

Those "#ifdef __MK66FX1M0__" should include and allow the K64 too right?



CollinK - you could hit 'Ctrl+R' Verify in the IDE after selecting a T_3.2 even if you don't have one to confirm they are clean.

Yes, I should have tried to compile for 3.2 even though I don't have one in front of me. I'll put the proper defines around all of the second canbus stuff so that it actually does compile on the other boards. The MK64FX512 based board (Teensy 3.5) actually still only has a single CAN bus. Only the Teensy 3.6 has two. So, the define is correct (AFAIK) with just the MK66FX1M0 chip.

EDIT: Github has been updated. Now it compiles on the 3.2 and 3.5 boards. I included an additional example that should work on both of them as well.
 
Last edited:
I've got it now to compile and downloaded to a Teensy 3.2 ok, but it is not running right.

On the CAN-bus analyser it is showing Form and Stuff errors. On scope it is showing a frame every 550uS but the code is every 100mS.

#include <FlexCAN.h>
int led = 13;

FlexCAN CANbus(500000); // Set CAN speed to 500kbps

static CAN_message_t msg,rxmsg;
volatile uint32_t count = 0;

void setup() {
// put your setup code here, to run once:
CANbus.begin();

delay(1000);
Serial.println(F("CAN Bus Tx test"));
msg.buf[0] = 1;
msg.buf[1] = 2;
msg.buf[2] = 0;
msg.buf[3] = 0;
msg.buf[4] = 0;
msg.buf[5] = 0;
msg.buf[6] = 0;
msg.len = 8;
msg.id = 0x222;

pinMode(led,OUTPUT);

}

void loop() {
// put your main code here, to run repeatedly:

digitalWrite(led,HIGH);
msg.buf[4] = count >> 24;
msg.buf[5] = count >> 16;
msg.buf[6] = count >> 8;
msg.buf[7] = count;
CANbus.write(msg);
count++;
delay(100);
digitalWrite(led,LOW);
delay(100);

}
 
I've got it now to compile and downloaded to a Teensy 3.2 ok, but it is not running right.

On the CAN-bus analyser it is showing Form and Stuff errors. On scope it is showing a frame every 550uS but the code is every 100mS.

Are you sure you're using my version of the FlexCAN library? The sketch you posted seems to be meant for the other two versions of the library. If you really are using my version then look at the RxSingleBusWithObjects example to see how bus initialization is done now. Yes, sorry, I changed the way the library works. It's almost certain to change even more in the future. I'm really seriously considering creating a common API and porting the CAN code for AVR, Due, and Teensy 3.x to all use the same core API. They'll probably all have some specific additions to the core API for things that really are hardware specific but I hope to create a core that encompasses 90% of what people would want to do. Then sketches with CAN access would be more portable.

The changes relevant to your sketch are:

1. The object is pre-allocated for you just like the built-in Serial objects in the core. "Can0" is the name of the object you want to use
2. You set the speed in begin now because the object is already allocated.

Here is your sketch but modified to use the new API:

Code:
#include <FlexCAN.h>
int led = 13;

static CAN_message_t msg,rxmsg;
volatile uint32_t count = 0;

void setup() {
// put your setup code here, to run once:
Can0.begin(500000); //set speed here. There are other optional parameters - see Readme for details

delay(1000);
Serial.println(F("CAN Bus Tx test"));
msg.buf[0] = 1;
msg.buf[1] = 2;
msg.buf[2] = 0;
msg.buf[3] = 0;
msg.buf[4] = 0;
msg.buf[5] = 0;
msg.buf[6] = 0;
msg.len = 8;
msg.id = 0x222;

pinMode(led,OUTPUT);

}

void loop() {
// put your main code here, to run repeatedly:

digitalWrite(led,HIGH);
msg.buf[4] = count >> 24;
msg.buf[5] = count >> 16;
msg.buf[6] = count >> 8;
msg.buf[7] = count;
Can0.write(msg);
count++;
delay(100);
digitalWrite(led,LOW);
delay(100);
}
 
Please help a beginner

If I already have FlexCAN library installed in the IDE, how can I assure that I will be using this new one?

Is their a process to replace the old one?
 
Please help a beginner

If I already have FlexCAN library installed in the IDE, how can I assure that I will be using this new one?

Is their a process to replace the old one?

Well, there is a copy of the FlexCAN library that gets installed with the Teensyduino files. You can override it by placing my version in your libraries folder contained within your user folder. For instance, on linux there should be a folder called ~/Arduino/libraries where your custom libraries are. If you place the new FlexCAN library in there it should override the official one. So, you would then have a folder ~/Arduino/libraries/FlexCAN where the replacement library resides. So, that's the process for replacing the library itself.

But, I also created API breaking changes. The way you initialize the library is different now so if you had a sketch meant for the official library you'd need to change the way initialization works. You can see that in the examples included with the library. Additionally, with the official version you can wait for frames to come in. You can't do that with mine. They're either there or they aren't. If there are no frames then available() will return 0 and you do nothing. If there are frames then you don't have to wait - you can grab all of the cached frames immediately. This is also shown in examples. Overall I don't think anything I did makes it really more complicated to use but it does change the way the library works a little bit.
 
When I used the Arduino IDE to install the new FlexCAN from the zip file it shows up in the libraries directory as FlexCAN_Library-master. Should I rename that directory to FlexCAN?
 
It doesn't really matter what the directory is called. The IDE finds the files just the same. The only reason to care about the folder name is so that you know what it is if/when you look at the libraries folder. FlexCAN_Library-master is kind of verbose but it lets you know what it is. You can rename it if you want.
 
OK, I am reasonably sure I am now using the correct library. But, I cannot get Can0.begin() to compile when trying to set the baud rate, defaultMask, txAlt, and rxAlt. I get a compiler error indicating a conversion error in converting the defaultMask to const. Can you please give me an example of a call to this function when setting all parameters.

I can set the baud rate without any problems. It is only when I add the second argument that it will not compile
 
So ive been trying to get FlexCan to work for a couple days now, and i feel like im missing that "AH HAA!" in my code. The code is very simple. It creates two instances of the message structures, defines one of them to be sent, sends, receives, and prints what it receives.

Yet when i run it, i get nothing. It doesnt seem to send, yet reports a "1" if i print a variable defined by the "write" function. It also only writes i believe 8 times, then i believe the buffers are full and it has no where to write. I also believe it doesnt receive properly. Though its hard to tell, because nothing seems to happen.

Hardware is a Teensy 3.6, and two TI SN65HVD230 chips on breakout boards. The TI boards are these ones.

s-l1600.jpg

Ive tried swapping the TX/RX on the teensy of both boards, no change. CanH and CanL are connected properly.

Heres the entire code ive written.

Code:
#include <FlexCAN.h>
FlexCAN CANbus0(125000, 0);
FlexCAN CANbus1(125000, 1);
static CAN_message_t rxmsg, txmsg;

void setup(){
  CANbus0.begin();
  CANbus1.begin();
  Serial.begin(115200);
  delay(1000);
  Serial.println("Hello Teensy 3.6 CAN Test.");
  txmsg.id=0xa5;
  txmsg.ext=0;
  txmsg.len=2;
  txmsg.timeout=0;
  txmsg.buf[0]=0x01;
  txmsg.buf[1]=0x02;
  txmsg.buf[2]=0x03;
  txmsg.buf[3]=0x04;
  txmsg.buf[4]=0x05;
  txmsg.buf[5]=0x06;
  txmsg.buf[6]=0x07;
  txmsg.buf[7]=0x08;
}
void loop(){
  CANbus0.write(txmsg);
  if(CANbus1.available()){
    CANbus1.read(rxmsg);
    Serial.print("ID ");
    Serial.println(rxmsg.id,HEX);
  }
  delay(1000);
}

PLEASE, someone help a brother out. I feel like its 98% there, its just missing that one line that makes it all actually work.

Thanks,
Dan
 
Last edited:
Termination jumper? Are you referring to the 2 pin header? I was under the impression that was access to the CanH and CanL lines for use with jumper wires?
 
Can't really see clearly from the photos. With out anything connected, using a DMM to buzz out the the resistance of CAN_H and CAN_L. It should be 120ohm. Close the jumper if not.
 
Their are two things that hooked me with this forked FlexCAN library. I work on a Mac so you may be different.

When I downloaded the library that is reference in the first post in this thread it installed in the standard directory for optional libraries. While that is supposed to take priority over the FlexCAN library that is loaded into the Arduino IDE when you install Teensyduino, in my case it did not. I had to go find the original in the applications directory and delete it. Otherwise I was using the original FlexCAN library and not this new forked one.

Also check to see that you are using the correct pins for CAN0. The default pins on the Teensy 3.6 are 3 and 4. I did not notice that and started by trying to use pins 29 and 30 for CAN0. They are on the same end of the board as CAN1 so I did not notice the others.

After I got that straighten out I was able to get the CANtest example from the example set to work. When you look at that example you will notice that the call to FlexCAN CANbus0(125000, 0); you have included in your code is not required. I think, but since I am new to this also I am not sure, that this call is from the original FlexCAN library. I think it is unfortunate that their are two libraries that are both called FlexCAN. You may be mixing code between the two libraries.

On my Mac the new forked library shows up as FlexCAN_Library-master in both the library directory and in the list of libraries in the IDE Sketch/Include Library list.
 
I'll admit, I'm not using this "forked" library, but I'm using a different one then I believe came with the teensyduino IDE so I'll have to look into removing the original flexcan library that's possibly causing an issue.

I can't believe the difficulty I'm having with getting this to work.
 
is there a working flexcan library for the teensy 3.5 as well?

oops sorry I see this one does, teachops didnt. Im guessing without the transceiver I could use them for reading data (aka not writing?)
thanks
 
Last edited:
It generally is not advisable to attempt to use the CAN hardware without a transceiver. Technically it could possibly work in some circumstances but really the CAN Rx/Tx lines were never meant to be used without a transceiver.

The pawelsky fork of FlexCAN and my fork both support Teensy 3.5 and 3.6 boards. The original Teachop version doesn't support the second canbus on 3.6 but I think it ought to work with the one CAN bus on the Teensy 3.5.

Turbo, don't feel bad. Even people who should be expert enough sometimes end up fighting with CAN bus stuff to make it work. I've got dozens of CAN boards and somehow I still sometimes scratch my head and wonder how I messed it up. It helps if you can use a DMM to look at the voltage levels. A proper CAN bus will have 60 ohms of resistance on the bus. Each end has 120 ohms of resistance. The voltage should rest at 0V between CANH and CANL. When they're pulled apart in voltage it will likely be around 2-3v between them. If you can grab a measurement from ground to CANL and CANH you should see them rest around 2 - 2.5v (both of them) switching between that and CANL = 1 - 1.5v, CANH = 3 to 3.5v when sending a 0 bit. If you have a nice DMM that has an analog style bar graph you should see it going crazy zipping back and forth between two values. If you have a Hz mode on your DMM you should be able to get a reading though it won't be anything meaningful. I can sometimes see 7KHz or so as the reading. It's irrelevant what the Hz reading is so long as it isn't 0Hz. If you have an oscilloscope then even better. There are two voltage levels and the signal is a square wave.

Lastly, it pays to have one "known good" device that you can use to test the rest. I have a Kvaser Leaf Light I use for this. You probably don't want to spring for a $300 device just for testing though (it is nice...) There are plenty of $40-100 options out there. It's nice to be able to hook up a known working device and see if it can see any traffic. If it doesn't then you're that much further away from getting it to work but at least then you know a little better where the issue is at. Also, the known good device can be used to send some traffic and see what happens. Basically, start with a known good device talking to your custom stuff one at a time. When you can get each working one at a time then you can try combining.
 
Back
Top