FlexCAN_T4 - FlexCAN for Teensy 4

Actually I was sending with baudrate 1000000/2000000 as this error occured. Ealier I had the ECU connected with the Vector Box + CANalyzer and my Teensy Board only as listener on the bus. There everything with baudrate 1000000/2000000 was fine.

But what occured to me just now is, that I had a config loaded whilest this experiment, and the config may altered the baudrate and the clock to the functioning 1000000/2000000 and 60! And later when I wanted to start sending with the teensy and for debugging just connected the teensy to the CANalyzer but without a config and the default values of CANalyzer may vary! So I will look into this next week!

Much Thanks for your help and patience with me!

But still I'm a bit confused, because I was also trying to get the teensy board sending directly to the ECU, which should have the correct baudrate/clock because I was able to read the messages earlier (Or did I just read the ones from the CANalyzer script? Gotta check), but the ECU didnt answer. And it should answer once it gets some messages, so this could be that the messages I was sending were not the one the ECU expected or some other problem...

I will continue to try and keep you updated / will come back for help! Thank you very much!
 
there are also multiple timing parameters for FD in the Advanced setbaudrate config menu, it displays all the timings for the same bitrate so you can pick one from the list, by default it uses the first match. The debug output list is printed to serial monitor. Each rate can have multiple selections at different clock speeds,
 
Hello,

Does someone know about documentation on changes made to ARM Flexcan module between Teensy3 and Teensy4? If I understand correctly they went from ARM Cortex-M4 to M7.

The goal is to write CanOpenNode drivers for Teensy4 based on this code for Teensy3. Unfortunately, I don't have prior experience with ARM-chips. So I was hoping to find more sources of information on thoose changes, other than the highly technical manual for i.MX RT1060 processor.

On 07-29-2020, there were a few references on CanOpen on Teensy3 in this thread but they didn't help much.

Many thanks!


I wasn't sure if I should start a thread in "Project guidance". I guess, one should do so if there is a broader interest on the "CanOpen on Teensy4" topic.
 
the registers should be fine to port the older library to t4, however if you look at flexcan_t4's begin() you'll see the initialization routines needed, and you'll need to remap the address of can0 and can1 to that of teensy4 (can1 and can2), the other registers are just offsets of that. it can get a bit complex, but flexcan_t4 was made to work with all t3.x and 4.x processors. You'll probably have a better chance porting that library to flexcan_t4.

EDIT, thats not a library that is a driver itself, take what you can from flexcan_t4 because you'll need to fix up that code or find another library that is based off the previous flexcan.h libraries...
 
Thanks for the help. I think the remapping of addresses worked. I'm able to e.g. set FRZ bit and read back the ACK bit, which is then set.

I'm not quite sure what you mean by "porting that library to flexcan_t4".

If I understand correctly, you recommend to take as much as possible from your T4 library, right?

At the moment, the Teensy is trying to send CAN messages, until some buffer in CANopenNode is full. Next goal is now, to figure out, why those messages aren't send. At least, they don't show up on the wire.
 
most libraries depended on the original flexcan.h, however the one you are using is custom and accesses the hardware directly without depending on flexcan.h. Once you remap the addresses and figure out the initialization routine in flexcan_t4 source begin() functor, it *should* just work, also take note of the setRX and setTX functors, those pin configurations matter as well.

You can get the CAN addresses in the H files
 
Hello,

Could someone please clarify how the interrupts for this library work?

I am trying to recognize a button press in my vehicle, and create an interrupt that increments a counter every time a particular can message is received.

Code:
// New can object using can bus 0 on teensy.
FlexCAN_T4<CAN0, RX_SIZE_256, TX_SIZE_16> can1;

CAN_message_t canMsg;
CAN_message_t msgInt;

void initCanT4(void){

  can1.begin();
  can1.setBaudRate(100E3);
  can1.setMaxMB(1);

  can1.setMB(MB0, RX, STD);

  //REJECT ANY CAN MESSAGE THAT IS NOT IN THE LIST
  can1.setMBFilter(REJECT_ALL);

  // MAILBOX 0 Acts as a hardware interrupt (For button presses ONLY)
  can1.enableMBInterrupt(MB0, true);

  //Every time there is a new message, sniff the packet
  can1.onReceive(MB0,canInterruptSniff);

  
  can1.setMBFilter(MB0, 0x1D6); // Hardware interrupt, steering wheel button

}


Code:
void canInterruptSniff(const CAN_message_t &msgInt) {

    Serial.print("INTERRUPTED CAN1 "); 
    Serial.print("MB: "); Serial.print(msgInt.mb);
    Serial.print("  ID: 0x"); Serial.print(msgInt.id, HEX );
    Serial.print("  EXT: "); Serial.print(msgInt.flags.extended );
    Serial.print("  LEN: "); Serial.print(msgInt.len);
    Serial.print(" DATA: ");
    for ( uint8_t i = 0; i < 8; i++ ) {
      Serial.print(msgInt.buf[i]); Serial.print(" ");
    }
    Serial.print("  TS: "); Serial.println(msgInt.timestamp);

  Serial.println("END READ INTERRUPT CAN MSG");
  
  if (lastClickTime - millis() > 800) { //Essentially, this is to eliminate "bouncing of the button press"
    parseCanInterruptedMessage(msgInt.id, msgInt.buf, msgInt.len);
  }

}

Code:
unsigned volatile long lastClickTime = 0;
volatile int clickCount = 0;
static uint32_t STEERING_WHEEL_ID = 470; //1D6 HEX

void parseCanInterruptedMessage(uint32_t id, const uint8_t message[], uint8_t messageLength){

    if (id == STEERING_WHEEL_ID){
    Serial.println("STEERING WHEEL BUTTON!!!!!");   
        if (message[0] == 192 && message[1] == 13 && lastClickTime - millis() > 800){ // IF the particular voice button is pressed...
            lastClickTime = millis();  // Reset button press timer
            Serial.println("STEERING WHEEL BUTTON!!!!!****************PRESSED!");   
            clickCount += 1;
        }
    }
}


So I want to run the above two functions whenever a can bus message with ID 470 is received, no matter what the microcontroller is doing. In this case, the interrupt would increment a counter, and the teensy would be running a while loop checking for the number of clicks. The interrupt should increment the number of clicks. My current code does not trigger an interrupt to increment the counter though.

Code:
void checkNumClicks(void){
static unsigned long max_delay = 3000;

      Serial.println("");
      Serial.print("internal Fn click Counter: ");
      Serial.println(clickCount);

      while((millis() - lastClickTime < max_delay) && clickCount == 1){
          if (clickCount >= 2){
            //returnVal = 2;
            clickCount = 0;
            Serial.println("DOUBLECLICK************************");
            lastClickTime = millis();
            break;
            }
      }
      if ((clickCount == 1) && (millis() - lastClickTime >= max_delay)){
          clickCount = 0;
          Serial.println("***********************SINGLECLICK");
          advanceScreen();
          lastClickTime = millis();

          //returnVal = 1;
          //lastClickTime = millis();
      }
}

I am hoping there is a very simple solution I am overlooking. The code works perfectly with a traditional "pin rising" interrupt and a standard button.
 
I can't see all your code but just remove events() from the loop() if you have it so the callback will fire directly rather from the events() queue system, this will disable the RX queue system and fire directly to the callback

polling: read() // (without enableMBInterrupts())

interrupt queue // (with events(), stores all messages to the queue, where events() will process one queue at a time to the callback. depending on where you put events() in your code, the latency depends on your code processing obviously

interrupts direct firing to callback, (without events(), disables the RX queue and processes the callback immediately when a message arrives


Also, do not forget some modules repeat frames, maybe every 100ms, it's different per vehicle. If you have repetitive frames, have a static local variable keep track if the bit/byte changes and only proceed to process it if it changed from last value. That's how i keep track of held down keyfob buttons and touched buttons.

Code:
static uint8_t last_value = msg.buf[4];
if ( msg.buf[4] != last_value ) {
  // DoSomething()
  last_value = msg.buf[4]
}

if, of course, multiple bits are changing and you're only interested in one bit, mask it:
if ( (msg.buf[4] & 0x4) != last_value ) { ........
 
Last edited:
I can't see all your code but just remove events() from the loop() if you have it so the callback will fire directly rather from the events() queue system, this will disable the RX queue system and fire directly to the callback

polling: read() // (without enableMBInterrupts())

interrupt queue // (with events(), stores all messages to the queue, where events() will process one queue at a time to the callback. depending on where you put events() in your code, the latency depends on your code processing obviously

interrupts direct firing to callback, (without events(), disables the RX queue and processes the callback immediately when a message arrives


Also, do not forget some modules repeat frames, maybe every 100ms, it's different per vehicle. If you have repetitive frames, have a static local variable keep track if the bit/byte changes and only proceed to process it if it changed from last value. That's how i keep track of held down keyfob buttons and touched buttons.

Code:
static uint8_t last_value = msg.buf[4];
if ( msg.buf[4] != last_value ) {
  // DoSomething()
  last_value = msg.buf[4]
}

if, of course, multiple bits are changing and you're only interested in one bit, mask it:
if ( (msg.buf[4] & 0x4) != last_value ) { ........

Yup. Removing events() from the main loop fixed everything. Haha, took longer to undo all of my debugging code. Thanks for your help!

Also, all of your suggestions are great. Looking forward to making my project cleaner/more efficient.
 
This is more how-to use question ...

I've been using FlexCan_T4 with one can bus for a while and want to extend my code to use a second bus.

FlexCAN_T4<CAN1, RX_SIZE_256, TX_SIZE_16> CanBus;

I have code that uses the CAN bus in a subroutine that gets called with an address

void Fire(unsigned int address) {

CAN_message_t aem_msg, response;
bool done = false;
int count = 0;

if ( address == 0 ) return;

aem_msg.id = address;
aem_msg.flags.extended = 1;
aem_msg.len = 3;
aem_msg.buf[0] = 0x1E;
aem_msg.buf[1] = 0xFF;
aem_msg.buf[2] = 0x4;

CanBus.write(aem_msg);

return;

}

This is a simple example, the subroutines that perform complex operations but my question is the same.
Rather than duplicate the code for the second can bus, I'd like change the subroutine to take the bus as
a parameter. This way I can call the routine and pass CanBus1 or CanBus2 as the target bus.

Ex

FlexCAN_T4<CAN1, RX_SIZE_256, TX_SIZE_16> CanBus1;
FlexCAN_T4<CAN2, RX_SIZE_256, TX_SIZE_16> CanBus2;

Then change the subroutine

void Fire(SomeObjectType* CanBus, unsigned int address) {

CAN_message_t aem_msg, response;
bool done = false;
int count = 0;

if ( address == 0 ) return;

aem_msg.id = address;
aem_msg.flags.extended = 1;
aem_msg.len = 3;
aem_msg.buf[0] = 0x1E;
aem_msg.buf[1] = 0xFF;
aem_msg.buf[2] = 0x4;

CanBus->write(aem_msg);

return;

}

I have not been able to figure out the type object that the template creates in order to make this work. What am I missing ? Someone
must have done this already ...
 
I wrote a post regarding using template objects, it just replicates your function for X busses without doubling it in the sketch.

https://forum.pjrc.com/threads/6983...-regular-functions?highlight=template+objects

Take the code at the end of the post for your purpose


This worked just fine but I'd like to use this with a runnable thread class that encapsulates a set of operations on a particular CAN bus. In short, I want the bus
to be a private member of the class either passed to the constructor or created at instantiation in the constructor. I'd instantiate a new object for each CAN
bus 1,2,3 and then they would run concurrently.

class TestClass : public Runnable {
private:

template <class T>
T bus; // holds the CAN bus this thread class operates on

// Thread object
std::thread *wThread;

protected:
// Runnable function that we need to implement
void runTarget(void *arg);

public:
// Constructor/Destructor

TestClass(uint32_t BusId ); // constructor

~TestClass();

};


Then in the main thread I would pass the Bus ID ( CAN0, CAN1 ... ) to the constructor


myObj = new TestClass( CAN3 );

The constructor would do somthing like

TestClass::TestClass(uint32_t id) {

FlexCAN_T4<id, RX_SIZE_256, TX_SIZE_16> this->bus;

}

Unfortunately I cannot create a member variable in the TestClass that references the template object
 
You can use the base class as an alternative

Code:
FlexCAN_T4<CAN1, RX_SIZE_256, TX_SIZE_16> Can0;

class TestClass {
  private:
    FlexCAN_T4_Base* bus = nullptr;
    std::thread *wThread;
  protected:
    void runTarget(void *arg);
  public:
    TestClass(FlexCAN_T4_Base* _bus) {
      bus = _bus;
    }
    ~TestClass();
};

TestClass dsgsdgzs = TestClass(&Can0);
 
You can use the base class as an alternative

Code:
FlexCAN_T4<CAN1, RX_SIZE_256, TX_SIZE_16> Can0;

class TestClass {
  private:
    FlexCAN_T4_Base* bus = nullptr;
    std::thread *wThread;
  protected:
    void runTarget(void *arg);
  public:
    TestClass(FlexCAN_T4_Base* _bus) {
      bus = _bus;
    }
    ~TestClass();
};

TestClass dsgsdgzs = TestClass(&Can0);

The base class has no read method.
 
is that the only method you need working? if so, you can temporarily add it as a virtual method in FlexCAN_T4_Base class (virtual method(args) = 0) and it will work until i figure out a template option

Code:
class FlexCAN_T4_Base {
  public:
    virtual void flexcan_interrupt() = 0;
    virtual void setBaudRate(uint32_t baud = 1000000, FLEXCAN_RXTX listen_only = TX) = 0;
    virtual uint64_t events() = 0;
    virtual int write(const CANFD_message_t &msg) = 0;
    virtual int write(const CAN_message_t &msg) = 0;
    virtual bool isFD() = 0;
    virtual uint8_t getFirstTxBoxSize();
[COLOR="#008000"]    virtual int read(CAN_message_t &msg);[/COLOR]
};
 
Can do ...

I can call begin and setBaudrate() in the main before passing the object to the constructor.

This should work OK ...
 
Question on mailboxes. I have a 10 devices that I would like to sort into their own mailboxes. If I setup 10 receive mailboxes, I would like the latest packet for each corresponding mailbox to be read when I poll the mailbox. Is this the default behavior of the mailboxes or would I have to do something to ensure this behavior? Also, how many packets are stored in each mailbox?

Thanks!
 
each hardware mailbox stores only one frame during poll mode. if you use interrupts, a queue system automatically collects the mailboxes so they can receive another frame. From that queue, the appropriate mailbox callback will fire.
You are free to poll as much as you want but until you read that mailbox another incomming frame wont be able to write to it, or it might overwrite it in some circumnstances. Most people use interrupts.
 
Hi tonton81

I am using a Teensy 4.1 CAN with MCP2551 transceiver and I was playing around the examples given.

When attempting to transmit a message, the frame stays in the mailbox after calling the function can2.write(msgA). I need to call the function can2.setMB(MB8, TX, STD) in order to activate the mailbox. Is there a faster way to send messages instead of calling this function?

Code:
#include <FlexCAN_T4.h>

FlexCAN_T4<CAN2, RX_SIZE_256, TX_SIZE_16> can2;
CAN_message_t msgA;
CAN_message_t msgB;

void can2mb() {
  Serial.println("==================================");
  Serial.println("Can 2:");
  can2.mailboxStatus();
  Serial.println("==================================");
}

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();
}


CAN_message_t createMsg1() {
  CAN_message_t msg;
    msg.id = 0x236; // address ID 566
    msg.buf[0] = lowByte(millis());
    msg.buf[1] = 0x12;
    msg.buf[2] = 34;
    msg.buf[3] = 56;
    msg.buf[4] = 78;
    msg.buf[5] = 90;
    msg.buf[6] = 21;
    msg.buf[7] = 43;
    msg.len = 8;
    msg.flags.extended = 0;
    msg.flags.remote = 0;
    
    Serial.print("Message 1 set up -->  ");
    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);

    return msg;
}


CAN_message_t createMsg2() {
  CAN_message_t msg;
    msg.id = 0x103; // address ID 566
    msg.buf[0] = 11;
    msg.buf[1] = 11;
    msg.buf[2] = 11;
    msg.buf[3] = 11;
    msg.buf[4] = 11;
    msg.buf[5] = 11;
    msg.buf[6] = 11;
    msg.buf[7] = 11;
    msg.len = 8;
    msg.flags.extended = 0;
    msg.flags.remote = 0;
    Serial.print("Message 2 set up -->  ");
    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);

    return msg;
}
void setup(void) {
  Serial.begin(250000);
  
  can2.begin();
  can2.setBaudRate(250000);

  msgA = createMsg1();
  msgB = createMsg2();

  can2.setMaxMB(16);
  can2.enableMBInterrupt(1);
  can2.onReceive(canSniff);
  can2.mailboxStatus();
  can2.setMBFilter(0x7FF);
}

void loop() {
  can2.events();
  static uint32_t timeout = millis();
  if ( millis() - timeout > 200 ) {
    can2.write(msgA);
    can2mb(); // print mailbox status
    // can2.setMB(MB8, TX, STD);
    timeout = millis();
  }
}
 
do a mailboxStatus(), if it still stays there after you stop transmitting, verify your baudrate, terminations, transceiver connections. it will stay in the mailbox and software has no control over that, it sits there because you have a connection issue, even with a node that doesn't ACK it, that's an expected behaviour.
 
Hi thanks for the reply.

Inside my loop(), there is a function called can2.mb() that calls the mailboxStatus(). The message is transmitting as I have hooked up a Mircrochip CAN Bus Analyser to the bus and verified that it is transmitting.

But the message is only transmitting when I call the function can2.setMB(MB8, TX, STD), which I am trying to figure out why. Messages stay in the mailbox but are not transmitted when the setMB() is not called.
 
I am looking for a short explanation of how to properly use the mailboxes, write function and sequential flag to send regular timed can messages.

Maybe you could point me to a previous post or take a look at my use case below!

I am implementing a very limited CAN open library... very limited. Only passing a few messages to a motor controller to program it to self report it's position.
Below is a class responsible for holding a collection of CAN_message_t objects and a couple methods for operating on them. My goal is to be able to create my Instruction class with the particular messages in it that I want to send them in order with a short delay between each one.

After some testing I have determined I am not using the library correctly. As when I us the .write() method I end up continually writing to the can bus.

Qs:
* Is there a way to send just one message at a time?
* How do I create delays in-between messages?
=> I have seen the example code with the timeout code however this is not quite the functionality I am looking for.
* How do you send messages in a particular order?
=> I have identified the sequential transmission flag, however I am not sure exactly how this works

As I have spent more time learning about this library I have really seen how it is crafted well, so I want to express my appreciation in advance for any help you can provide

full source code:

Code:
#ifndef _CANOPEN_
#define _CANOPEN_

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

/*
 * Contains several individual
 * CANopen messages that can
 * be sent sequentially
 */
template <size_t N>
class Instruction
{
public:
    template <CAN_DEV_TABLE _bus,
              FLEXCAN_RXQUEUE_TABLE _rxSize,
              FLEXCAN_TXQUEUE_TABLE _txSize>
    void sendInstruction(FlexCAN_T4<_bus, _rxSize, _txSize> canBus);
    void printInstruction();
    void addFrame(uint32_t header, uint8_t buf[8]);

private:
    CAN_message_t msgs[N]; // array of messages to send
    int index = 0;
    template <CAN_DEV_TABLE _bus,
              FLEXCAN_RXQUEUE_TABLE _rxSize,
              FLEXCAN_TXQUEUE_TABLE _txSize>
    void transmitFrame(FlexCAN_T4<_bus, _rxSize, _txSize> canBus, CAN_message_t &msg);
    void errorHandler(int e);
};

template <size_t N>
template <CAN_DEV_TABLE _bus,
          FLEXCAN_RXQUEUE_TABLE _rxSize,
          FLEXCAN_TXQUEUE_TABLE _txSize>
void Instruction<N>::sendInstruction(FlexCAN_T4<_bus, _rxSize, _txSize> canBus)
{
    for (unsigned int i = 0; i < N; i++)
    {
        transmitFrame(canBus, this->msgs[i]);
        // TODO delay or find a way to only send one message or delay
        // TODO send in sequential order
    }
    return;
}

template <size_t N>
template <CAN_DEV_TABLE _bus,
          FLEXCAN_RXQUEUE_TABLE _rxSize,
          FLEXCAN_TXQUEUE_TABLE _txSize>
void Instruction<N>::transmitFrame(FlexCAN_T4<_bus, _rxSize, _txSize> canBus, 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();
    canBus.write(msg);
    return;
}

template <size_t N>
void Instruction<N>::addFrame(uint32_t header, uint8_t buf[8])
{

    CAN_message_t msg;

    msg.id = header;

    for (int i = 0; i < 8; i++)
    {
        msg.buf[i] = buf[i]; // copy buf into new message
    }

    this->msgs[this->index] = msg; // assign member var and increment index
    this->index++;
    return;
};

template <size_t N>
void Instruction<N>::printInstruction()
{
    Serial.println("=======================");
    Serial.print("index: ");
    Serial.println(this->index);
    for (int i = 0; i < this->index; i++)
    {
        Serial.print(i);
        Serial.print(" : ");
        Serial.println(this->msgs[i].id, HEX);
        for (int j = 0; j < 8; j++)
        {
            Serial.print(" =>");
            Serial.println(this->msgs[i].buf[j], HEX);
        }
    }

    return;
}

template <size_t N>
void Instruction<N>::errorHandler(int e)
{
    switch (e)
    {
    case 102: // too may frames added
        Serial.println("**ERROR**");
        Serial.println("Attempted to add too many frames,");
        Serial.print("   => Current frame limit: ");
        Serial.println(N);
        Serial.println("Increase your instruction size...");
        break;
    default:
        Serial.println("Something went wrong");
        break;
    }
    return;
}

#endif

#ifndef _CANOPEN_MSGS_
#define _CANOPEN_MSGS_
/* this would most likely be moved to a file */

/* set Number of mapped objects TPDO 1 to 0x00 */
uint8_t msg0[] = {
    0x2f,
    0x00,
    0x1A,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00};

/* set TPDO 1 mapping information 1 to 0x60640020 */
uint8_t msg1[] = {
    0x23,
    0x00,
    0x1a,
    0x01,
    0x20,
    0x00,
    0x64,
    0x60};

/* set Number of mapped objects TPDO 1 to 0x01 */

uint8_t msg2[] = {
    0x2f,
    0x00,
    0x1a,
    0x00,
    0x01,
    0x00,
    0x00,
    0x00};

/* set Transmission type TPDO 1 to 0x01 */
uint8_t msg3[] = {
    0x2f,
    0x00,
    0x18,
    0x02,
    0x01,
    0x00,
    0x00,
    0x00};

/* set Communication Cycle Period to 0x000186a0 */
uint8_t msg4[] = {
    0x23,
    0x06,
    0x10,
    0x00,
    0xa0,
    0x86,
    0x01,
    0x00};

/* set COB-ID  SYNC message to 0xc0000080 */
uint8_t msg5[] = {
    0x23,
    0x05,
    0x10,
    0x00,
    0x80,
    0x00,
    0x00,
    0xc0};

/* start remote node - node 1 */
uint8_t msg6[] = {
    0x01,
    0x01,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00};

#endif
 
Hardware only sends transmission once but only if it is successful. It will retry until a valid ACK occurs and then it can continue to next frame. Be sure a node is on the bus to ACK it and check the wiring to make sure all is good. I don't see any loop code above so cant see if your sending endlessly or it being an ACK issue. If msg.seq = True, messages will be queued and sent in order, this uses the absolute first mailbox to do so. without seq bit set, it will sent to any tx mailboxes, and that order of transmission between multiple transmits cannot be controlled
 
Hello guys,
I've been using latest flexcan for a while but only now I've identified a strange behaviour that is driving me crazy.
The hardware is pretty standard and used it before without teensy, so I assume no problem there.
The problem is, after a while CAN communication stop working, even if I reflash or restart teensy, does not work.
Only when I power cycle the teensy the CAN starts working again.
I've tried to CAN.begin() or CAN.reset() or even create a new instance when the comunnication is lost without sucess.
Doest anybody have this problem and can help me to solve it?
 
Back
Top