Another fork of FlexCAN

I have a question regarding usage of the Rx mailboxes, and how they can be configured to best manage incoming messages.
I have filters and masks set to receive important messages in particular mailboxes. Some messages I decode and process (first five mailboxes), some messages get passed to the other bus (next 3 mailboxes). However, all messages are logged to the SD card (remaining mailboxes). My problem is that I cannot guarantee that my important messages are processed by the correct mailbox handler as these messages can be accepted by the 'catch-all' mailboxes.
I am guessing that I have to abandon filters and masks and handle all incoming messages with the General Handler, and filter my important messages in software.
The Kinetis manual does mention:
• Selectable priority between mailboxes and Rx FIFO during matching process
• Powerful Rx FIFO ID filtering, capable of matching incoming IDs against either 128 extended, 256 standard, or 512 partial (8 bit) IDs, with up to 32 individual masking capability
Is there anything I could do to make use of the mailboxes?
I realize that I could close-down my 'catch-all' mailboxes to only receive messages outside of the 'important' message range but my application has the ability to read and write Filters to the SD, and also modify them during run-time, which would potentially make this approach quite complex.

Any suggestions much appreciated.
EDIT: It looks like configuring a pair of mailboxes for a particular message might be a solution, though this obviously reduces the number of available unique tasks to 7 ID's or ranges of ID's.
 
Last edited:
hello guys i am very new to teensy and i and have teensy3.6 and i also bought two Single CAN-Bus adapter for Teensy from TinDie and i am trying to use two teensy3.6 and get them talk to each other just basic sending and receiving messages. please if there is any help to connect the hardware that will be awesome
 
Hi
I'd really appreciate some help in setting up a mask and filters for a project I'm working on. I've read various posts and looked at example code but I'm getting lost on some of the terminology and options.

I'm using a Teensy 3.2 to read four canbus messages from a marine engine. I want to only process data in messages with ID 0x280, 0x288, 0x380 and 0x588. I have tried to work out the required mask which I think should be 0xB88 but don't know what to do next. Some posts show setting up mailboxes with filters whereas others don't seem to at all. It's all 11bit standard ID.

Once I get the hang of this I'll be using a Teensy 3.6 to get certain bytes of the can bus data from the engine and put it onto a different canbus for the navigation display (NMEA2000).

Keith
 
Ok, since my previous post I've made some progress in understanding this all a bit more. One outstanding question though is how to set listen only mode. I just want to silently sniff the bus and extract data. My code will be polling the buffered data rather than using object oriented callbacks. Where and how do I set Listen Only?
 
From the flexcan.h header file:

//new functionality added to header but not yet implemented. Fix me
void setListenOnly (bool mode); //pass true to go into listen only mode, false to be in normal mode
Looks like listen only is not yet implemented. I don't know about your specific implementation but you can probably get away with normal mode and just not write anything to the transmit buffers. As far as I know this won't be truly silent as it will send an acknowledgement packet, but it's the next best thing. I've implemented a sniffer/splitter with a Teensy 3.6 and haven't run in to any issues yet with not being able to set an explicit listen only mode.

Edit: Just looked in the flexcan.cpp file and the function appears to be there. Try Can0.setListenOnly(true); - not sure if it's been tested or not.
 
Thank you Dave. I also saw the reference to it not being implemented but also saw the bit in the .cpp file.

Any thoughts on where I should place the command? Before Can.begin or after? Or maybe in the global section.
 
I use the hardware to go into listen only mode on a SN65HVD230 (or poss is the VD231 variant) amd just pull a pin low in software.
 
Thanks Darcy. From the data sheet that would work with HVD230 but not HVD231. Guess which one my breakout board uses!
 
Code:
FlexCAN::setListenOnly

Looked at that function, that looks correct it should be in listen only mode once set. ACKs and transmit wont work but receptions will
 
Well I'm making some progress. I tried the Can0.setListenOnly but that just seemed to stop all reception too. Perhaps I had it in the wrong place in my code.

Code:
void setup(void)
{
  delay(5000);
  Serial.println(F("Hello Teensy 3.6 dual CAN Test."));

  Can0.setListenOnly (true); //hopefully set listen only mode
  
  Can0.begin(500000); //set baud. 
  
}

However, once commented out I did start receiving data but not quite what was expected. I was trying to only poll for byte 1 in 0x288 but was also getting byte 1 of all other frames as well.

Code:
CAN bus 0: 288, 56
380, 68
480, 28
280, 0
362, 0
588, 16
488, 0
CAN bus 0:288, 56
380, 68
480, 28
280, 0
362, 0
588, 16
488, 0
CAN bus 0:288, 56
etc.....

Code:
// -------------------------------------------------------------
// Development sketch to read VW marine can bus and filter relevant data
// using polling
//
// by Collin Kidder, Based on CANTest by Pawelsky (based on CANtest by teachop)
//
// This sketch uses interrupt driven Rx. Rx frames
// are internally saved to a software buffer by the interrupt handler.
//

#include <FlexCAN.h>

//#ifndef __MK66FX1M0__
//  #error "Teensy 3.6 with dual CAN bus is required to run this example"
//#endif

static CAN_message_t msg;
static uint8_t hex[17] = "0123456789abcdef";

/*might need int not uint8_t
uint8_t coolant; //unsigned integer coolant temp
uint16_t rpm; //unsigned integer rpm
uint8_t boost; //unsigned integer boost pressure
uint8_t iat; //unsigned integer intake air temp*/

// -------------------------------------------------------------
void setup(void)
{
  delay(5000);
  Serial.println(F("Hello Teensy 3.6 dual CAN Test."));

  //Can0.setListenOnly (true); //hopefully set listen only mode
  
  Can0.begin(500000); //set baud. Change to Can1 for use on T3.6
  
  //if using enable pins on a transceiver they need to be set on
  //pinMode(2, OUTPUT);
  //pinMode(35, OUTPUT);

  //digitalWrite(2, HIGH);
  //digitalWrite(35, HIGH);
}

// -------------------------------------------------------------
void loop(void)
{
  CAN_message_t inMsg;
  while (Can0.available()) 
  {
    Can0.read(inMsg); //read message into inMsg
    if (inMsg.id == 0x288)
    Serial.print("CAN bus 0: "); 
    Serial.print(inMsg.id, HEX);
    Serial.print(", ");
    Serial.print (inMsg.buf[1], HEX);
    Serial.write('\r');
    Serial.write('\n');
  }
 }

Any thoughts please?
 
Hello keith-i

Shouldn't the 'if' statement have curly brackets around the action you require to be completed, if the statement is true i.e

if (inMsg.id == 0x288)
{ add this bracket
Serial.print("CAN bus 0: ");
Serial.print(inMsg.id, HEX);
Serial.print(", ");
Serial.print (inMsg.buf[1], HEX);
Serial.write('\r');
Serial.write('\n');
} and this one

That's what I do.
 
Looks like you've got some good answers already. I don't know if Can0.setListenOnly should go before or after the Can0.begin, but I'm sure the setup routine is where I'd put it. One thing I notice, and I don't know if it has any negative effect, but you've got a space between setListenOnly and (true). I would have thought that if this was an issue you'd get a compiler error message, but it wouldn't hurt to try without the space.

I've actually been looking at some open source marine and NMEA200 stuff as a future project, but it sounds like you're one step ahead of me since you actually have a boat. :)
 
Yes listen only SHOULD be set AFTER begin because the baudrate when set by default sets up the register with the LOM bit cleared
 
@Ceetee - thanks the bracket omission was the problem
@tonton81 - I put .setListenOnly after .begin and all seems to be working now thanks
 
Kind people, would you mind scanning over my code to make sure there's nothing obviously amiss. It compiles fine but I've yet to actually get hold of a Teensy 3.6 to try it out. The variable declarations and calculations on the data bytes are the most likely sources of any mistakes as I'm still trying to get my head round it all. I'm pretty comfortable about the N2k elements working as I've put in dummy data and that gets transmitted fine on a T3.2 testbed.
Thanks

Code:
// Convert VW Marine ECU canbus data to N2k. Oct 2019
// based on Collin80 and Timo Lappalainen code.

#include <Arduino.h>
#include <NMEA2000_CAN.h>  // This will automatically choose right CAN library and create suitable NMEA2000 object
#include <N2kMessages.h>
#include <NMEA2000_teensy.h>
#include <FlexCAN.h>


#ifndef __MK66FX1M0__
  #error "Teensy 3.6 with dual CAN bus is required to run this example"
#endif

// List below N2k messages your device will transmit.
const unsigned long TransmitMessages[] PROGMEM={127488L,127489,0}; //engine rapid and dynamic

static CAN_message_t msg;
static uint8_t hex[17] = "0123456789abcdef";
  
//-----------------------------------------------------------------------------------------
void setup() {
  
  delay(5000);
  // Set Product information
  NMEA2000.SetProductInformation("000300", // Manufacturer's Model serial code
                                 200, // Manufacturer's product code
                                 "Arduino VW Gateway",  // Manufacturer's Model ID
                                 "1.1 (2019)",  // Manufacturer's Software version code
                                 "1.A (2019)" // Manufacturer's Model version
                                 );
  // Det device information
  NMEA2000.SetDeviceInformation(303030, // Unique number. Use e.g. Serial number.
                                160, // Device function=engine gateway. 
                                50, // Device class=propulsion. 
                                443 // Just choosen free from code list - VDO                                
                               );
  
  // Uncomment 2 rows below to see, what device will send to bus. Use e.g. OpenSkipper or Actisense NMEA Reader                           
  //Serial.begin(115200); // uncomment to send to serial for PC use
  //NMEA2000.SetForwardStream(&Serial); // uncomment to send to serial - default is Actisense format for PC use

  // If you want to use simple ascii monitor like Arduino Serial Monitor, uncomment next line
  //NMEA2000.SetForwardType(tNMEA2000::fwdt_Text); // uncomment to send to serial as plain text - overides above Actisense format
  
  // If you also want to see all traffic on the bus use N2km_ListenAndNode instead of N2km_NodeOnly below
  NMEA2000.SetMode(tNMEA2000::N2km_NodeOnly,22);
  
  //NMEA2000.SetDebugMode(tNMEA2000::dm_Actisense); // Uncomment this, so you can test code without CAN bus chips on Arduino Mega
  // Comment out next line for Actisense PC use
  NMEA2000.EnableForward(false); // Disable all forward messaging from N2K bus to USB (=Serial) - default is True. Comment for PC use
  
  NMEA2000.ExtendTransmitMessages(TransmitMessages);
  NMEA2000.Open();

  //Can0 should be automatically set at default 250kbs for N2k
  Can1.begin(500000); //set baud for VW ECU.
  Can1.setListenOnly (true); //hopefully set listen only mode. Set after begin()
  }

  /*
   * 0x280 byte 1 = torque (*0.39)%
   * 0x280 byte 2low&3high = rpm (*0.25)/min
   * 0x288 byte 1 = coolant ((*0.75)-48)C
   * 0x380 byte 1 = IAT ((*0.75)-48)C
   * 0x480 byte 2&3 = fuel rate ul
   * 0x588 byte 4 = boost (*0.01)bar
   */
      
  //maybe use int not uint8_t
  uint8_t torque = 0; //torque %
  uint16_t rpm = 0; //rpm
  uint8_t coolant = 0; //coolant temp in degC
  uint16_t fuel = 0;  //fuel rate in ul
  uint8_t boost = 0; //boost pressure in Pa. 1bar = 100,000Pa

void PollEngineCAN()
  {
  CAN_message_t inMsg;
    
    if (Can1.available()>0) {//or maybe use while?
      Can1.read(inMsg); //read message into inMsg
      //filter and parse message here to global data
      if (inMsg.id == 0x280){
        torque = (inMsg.buf[1]*0.39);
        rpm = (inMsg.buf[3]<<8) + inMsg.buf[2];}
      if (inMsg.id == 0x288){
        coolant = ((inMsg.buf[1]*0.75)-48);}
      if (inMsg.id == 0x480)
        
      if (inMsg.id == 0x588){
        boost = (inMsg.buf[4]*0.01);} 
    }
  }
//might want a timeout to put NA if engine is off

void SendN2kEngineRapid() 
  {
  static unsigned int NextSendTime=5000;
  if ( NextSendTime<millis() )
    {
    NextSendTime+=100;
    tN2kMsg N2kMsg;
 
    SetN2kEngineParamRapid(N2kMsg, 0, rpm, boost, N2kInt8NA);
    NMEA2000.SendMsg(N2kMsg);
    }
  }

void SendN2kEngineDynamic() 
  {
  static unsigned int NextSendTime=5000; 
  if ( NextSendTime<millis() )
    {
    NextSendTime+=500;
    tN2kMsg N2kMsg;
 
    SetN2kEngineDynamicParam(N2kMsg, 0, N2kDoubleNA, N2kDoubleNA, coolant, 
    N2kDoubleNA, fuel, N2kDoubleNA, N2kDoubleNA, N2kDoubleNA, N2kInt8NA, torque);
    NMEA2000.SendMsg(N2kMsg);
    }
  }
//-----------------------------------------------------------------------------------------
void loop() 
  
{
  NMEA2000.ParseMessages();
  PollEngineCAN();
  SendN2kEngineRapid();
  SendN2kEngineDynamic();
  }
 
Hi, just getting started with FlexCAN on T3.6. We've got it sending and receiving, but are unclear if there is a way to simply detect that a CAN device is attached to our Teensy CAN interface? Bonus if there's a callback for that :D

Our Teensy has a lot to do besides servicing the CAN communication, so we would like to detect if its connected before bothering with it. Otherwise, we'll probably make a heartbeat protocol so we can see when someone plugs in the CAN cable.

We tried looking at what Can0.available() returns and never get anything.
 
Last edited:
Implementation with ADM3057

I am implementing a can bus using teensy 3.2 and ADM3057 as transceiver.
When connecting everything to a can Analyzer to check the connection of teensy and transceiver, I get ACK errors when I try to send Data from the Analyzer. The Bus is terminated with 120 Ohm.
To check if it is a software problem, I disconnected teensy from the setup and uploaded this code:

Code:
#include <FlexCAN.h>

static CAN_message_t msg;
static uint8_t hex[17] = "0123456789abcdef";

// -------------------------------------------------------------
static void hexDump(uint8_t dumpLen, uint8_t *bytePtr)
{
  uint8_t working;
  while( dumpLen-- ) {
    working = *bytePtr++;
    Serial.write( hex[ working>>4 ] );
    Serial.write( hex[ working&15 ] );
  }
  Serial.write('\r');
  Serial.write('\n');
}


// -------------------------------------------------------------
void setup(void)
{
  delay(1000);
  Serial.println(F("Hello Teensy 3.6 dual CAN Test."));

  Can0.begin(250E3);  

  msg.ext = 0;
  msg.id = 0x100;
  msg.len = 8;
  msg.buf[0] = 10;
  msg.buf[1] = 20;
  msg.buf[2] = 0;
  msg.buf[3] = 100;
  msg.buf[4] = 128;
  msg.buf[5] = 64;
  msg.buf[6] = 32;
  msg.buf[7] = 16;
}


// -------------------------------------------------------------
void loop(void)
{
  CAN_message_t inMsg;
  while (Can0.available()) 
  {
    Can0.read(inMsg);
    Serial.print("CAN bus 0: "); hexDump(8, inMsg.buf);
  }
  Can0.write(msg);
  delay(20);
}
This should send out messages on CAN TX. (And likely retry because it gets no ACK)
On the CAN TX pin, I get a constant 3.3 Volts on my Oscilloscope. Is this working as intended or is there another design/software error present?
 
Last edited:
if it doesn't get an ack it may go into bus off state and using an oscilloscope won't help you as it needs valid 128 bits frame to reset the error counters in order for it to return from bus off and communicate again. The bus should have a total of 60 ohms termination (120 ohms x 2, one at each furthest node of the bus).
 
if it doesn't get an ack it may go into bus off state and using an oscilloscope won't help you as it needs valid 128 bits frame to reset the error counters in order for it to return from bus off and communicate again. The bus should have a total of 60 ohms termination (120 ohms x 2, one at each furthest node of the bus).

I checked it again with an analyzer, that does an 120 Ohms termination. On the uc-side I have a 120 Ohm termination also so it's 60 Ohms in total. The analyzer does also set the ACK bit.

Is there something like an internal loopback in the teensy can module to check if the teensy-side of my hardware is working? Then I would know on what part of the hardware I have to focus.
 
Back
Top