FlexCAN_T4 - FlexCAN for Teensy 4

thats weird, I just left the house and it was working using the 2 sketches posted, ill check it again when i get home from work
 
When you said try with my code, I thought you meant the code I posted. Using your reduced version of my code, it does work. However, with a serial.print in the flexcan_interrupt() function, it loops forever after the first call. Because every message RX and TX is being handled by the VCAN ISR, it works out in your version.

When running the code I posted, this causes the code to stop responding, since the code can never get to the LCAN's ISR to transmit the next message.

Comparing update3 and update4, you relocated the clear iflag line towards the end of the function. After successful transmission, if the txBuffer is empty, the flag will never be cleared before continuing to next MB.

If I move the clear iflag line back to where it was in update3, it functions properly.
Code:
    if ( FLEXCAN_get_code(code) == FLEXCAN_MB_CODE_TX_INACTIVE ) {
      if (!(imask & (1ULL << mb_num))) writeIMASKBit(mb_num); /* enable interrupt for MB if not enabled */
      
      writeIFLAGBit(mb_num); /* clear IFLAG  <--- this line  */
      if ( !txBuffer.size() ) continue; /* no queues available, continue next mailbox check */
 
only reason i moved it was because something was throwing off between sequential or remote frames, but that may have been fixed somewhere else or that line was necessary, Im testing 3 types to make sure itll work. so with the last update4 and the edit above, it's fine? if so i will need to test it later against seq, normal, and remote frames, for consistancy
 
After more testing of Update4 with the edit above, it still requires LCAN.events() to keep outgoing traffic. It fixes the ISR getting stuck looping, but something else still requires events() to avoid overrunning the TX queue.
 
yes this is why these are tests for new update later on, thats why I didn't want to touch the repo, I'm a bit busy this week but I'll try to work on it more
 
I reverted the interrupt transmits as it wasn't stable compared to the loop, and made all transmits not able to occupy a mailbox into the TX queue, not just sequential ones. Loopback mode and wake up mode have been kept intact.
So we are back to using events().

specific mailboxes are queued if not able to send, unlike the old method which included a 100ms blocking timeout. events() will retain the mailbox to send when available without the 100ms block.
sequential frames work as before, absolute first mailbox, queued if not sent
any other writes go to any found TX mailbox, if none found

Code:
[ATTACH]20258._xfImport[/ATTACH]
 
I believe I just found the source of the interrupt based instabilities. I think it's due to new interrupts being fired while flexcan_interrupt() is in process (due to a call from events()).
To test this theory, I tried clearing imask at the beginning of flexcan_interrupt() and resetting at the end.

After making the following 4 changes to flexcan_interrupt(), Update4 has performed well.

Code:
FCTP_FUNC void FCTP_OPT::flexcan_interrupt() {
  CAN_message_t msg; // setup a temporary storage buffer
  uint64_t imask = readIMASK(), iflag = readIFLAG();
  [COLOR="#FF0000"]writeIMASK(0ULL); /* Added by MSADIE - prevent preemption by FlexCAN (I think!?) */[/COLOR]
  
  if ( !(FLEXCANb_MCR(_bus) & (1UL << 15)) ) { /* if DMA is disabled, ONLY THEN you can handle FIFO in ISR */
    if ( (FLEXCANb_MCR(_bus) & FLEXCAN_MCR_FEN) && (imask & FLEXCAN_IMASK1_BUF5M) && (iflag & FLEXCAN_IFLAG1_BUF5I) ) { /* FIFO is enabled, capture frames if triggered */
      volatile uint32_t *mbxAddr = &(*(volatile uint32_t*)(_bus + 0x80 + (0 * 0x10)));
      uint32_t code = mbxAddr[0];
      msg.len = (code & 0xF0000) >> 16;
      msg.flags.remote = (bool)(code & (1UL << 20));
      msg.flags.extended = (bool)(code & (1UL << 21));
      msg.timestamp = code & 0xFFFF;
      msg.id = (mbxAddr[1] & 0x1FFFFFFF) >> ((msg.flags.extended) ? 0 : 18);
      msg.idhit = code >> 23;
      for ( uint8_t i = 0; i < (8 >> 2); i++ ) for ( int8_t d = 0; d < 4 ; d++ ) msg.buf[(4 * i) + 3 - d] = (uint8_t)(mbxAddr[2 + i] >> (8 * d));
      msg.bus = busNumber;
      msg.mb = FIFO; /* store the mailbox the message came from (for callback reference) */
      (void)FLEXCANb_TIMER(_bus);
      writeIFLAGBit(5); /* clear FIFO bit only! */
      if ( iflag & FLEXCAN_IFLAG1_BUF6I ) writeIFLAGBit(6); /* clear FIFO bit only! */
      if ( iflag & FLEXCAN_IFLAG1_BUF7I ) writeIFLAGBit(7); /* clear FIFO bit only! */
      frame_distribution(msg);
      ext_output1(msg);
      ext_output2(msg);
      ext_output3(msg);
      if (fifo_filter_match(msg.id)) struct2queueRx(msg);
    }
  }

  uint8_t exit_point = 64 - __builtin_clzll(iflag | 1); /* break from MSB's if unset, add 1 to prevent undefined behaviour in clz for 0 check */
  int8_t first_tx_found = -1;

  for ( uint8_t mb_num = mailboxOffset(); mb_num < FLEXCANb_MAXMB_SIZE(_bus); mb_num++ ) {

    if ( !txBuffer.size() ) { /* if transmits exist, don't skip any mailboxes */
      if ( mb_num >= exit_point ) break; /* early exit from higher unflagged mailboxes */
      if (!(imask & (1ULL << mb_num))) continue; /* don't read non-interrupt mailboxes */
      if (!(iflag & (1ULL << mb_num))) continue; /* don't read unflagged mailboxes */
    }

    volatile uint32_t *mbxAddr = &(*(volatile uint32_t*)(_bus + 0x80 + (mb_num * 0x10)));
    uint32_t code = mbxAddr[0];

    if ( (FLEXCAN_get_code(code) >> 3) && (first_tx_found == -1) ) first_tx_found = mb_num; /* set absolute first TX mailbox found */

    if ( FLEXCAN_get_code(code) == FLEXCAN_MB_CODE_RX_EMPTY ) {
      /* there are no flags for EMPTY reception boxes, however, when sending remote
         frames, the mailboxes switch to RX_EMPTY and trigger the flag */
      if (!(iflag & (1ULL << mb_num))) continue; /* only process the flagged RX_EMPTY mailboxes */
      writeIFLAGBit(mb_num); /* clear IFLAG */
      mbxAddr[0] = FLEXCAN_MB_CS_CODE(FLEXCAN_MB_CODE_TX_INACTIVE);
    }

    if ( FLEXCAN_get_code(code) == FLEXCAN_MB_CODE_TX_INACTIVE ) {
[COLOR="#FF0000"]      if (!(imask & (1ULL << mb_num))) {	
        imask |= (1ULL << mb_num); /* enable interrupt for MB if not enabled */
      }		/* Changed by MSADIE - enable via "imask" instead of "writeIMASKBit()"*/[/COLOR]
      
      if ( !txBuffer.size() ) {
        [COLOR="#FF0000"]writeIFLAGBit(mb_num); /* Added by MSADIE - clear IFLAG */[/COLOR]
        [COLOR="#FF0000"]/* This fixes what I believe is an unrelated bug */[/COLOR]
        continue; /* no queues available, continue next mailbox check */
      }
      
      uint8_t buf[sizeof(CAN_message_t)];
      txBuffer.peek_front(buf, sizeof(CAN_message_t));
      memmove(&msg, buf, sizeof(msg));
		
      if ( (msg.seq) && (mb_num != first_tx_found) && (!msg.flags.remote) ) continue; /* only offload sequential frames to absolute first mailbox */
      else if ( msg.mb == -1 ); /* write to any available mailbox */
      else if ( msg.mb == mb_num ); /* write to a specific mailbox */
      else continue; /* if it didn't pass last condition, it is not the specific mailbox, keep scanning till then */
      
      /* if transmitting sequential frames, don't assume pending remote frame transmissions
         arn't processing, otherwise the swap to RX_EMPTY would cause the next MB to transmit
         the sequential, essentially consuming 2 mailboxes for sequential writes. This prevents
         this issue by checking next cycle after current transmissions in the status register */
      if ( msg.seq && FLEXCANb_ESR1(_bus) & (1UL << 6) ) continue;
      
      txBuffer.pop_front(); /* clear on write */
      
      writeIFLAGBit(mb_num); /* clear IFLAG */
      mbxAddr[0] = FLEXCAN_MB_CS_CODE(FLEXCAN_MB_CODE_TX_INACTIVE);
      mbxAddr[1] = (( msg.flags.extended ) ? ( msg.id & FLEXCAN_MB_ID_EXT_MASK ) : FLEXCAN_MB_ID_IDSTD(msg.id));
      code = msg.len << 16;
      if ( msg.flags.remote ) code |= (1UL << 20);
      if ( msg.flags.extended ) code |= (3UL << 21);
      for ( uint8_t i = 0; i < (8 >> 2); i++ ) mbxAddr[2 + i] = (msg.buf[0 + i * 4] << 24) | (msg.buf[1 + i * 4] << 16) | (msg.buf[2 + i * 4] << 8) | msg.buf[3 + i * 4];
      mbxAddr[0] = code | FLEXCAN_MB_CS_CODE(FLEXCAN_MB_CODE_TX_ONCE);
    }

    else if ( ( FLEXCAN_get_code(code) == FLEXCAN_MB_CODE_RX_FULL ) ||
         ( FLEXCAN_get_code(code) == FLEXCAN_MB_CODE_RX_OVERRUN ) ) {

      /* treat receptions normally if transmit queue exists */
      if (!(imask & (1ULL << mb_num))) continue; /* don't read non-interrupt mailboxes */
      if (!(iflag & (1ULL << mb_num))) continue; /* don't read unflagged mailboxes */

      msg.flags.extended = (bool)(code & (1UL << 21));
      msg.id = (mbxAddr[1] & 0x1FFFFFFF) >> ((msg.flags.extended) ? 0 : 18);
      if ( FLEXCAN_get_code(code) == FLEXCAN_MB_CODE_RX_OVERRUN ) msg.flags.overrun = 1;
      msg.len = (code & 0xF0000) >> 16;
      msg.mb = mb_num;
      msg.timestamp = code & 0xFFFF;
      msg.bus = busNumber;
      for ( uint8_t i = 0; i < (8 >> 2); i++ ) for ( int8_t d = 0; d < 4 ; d++ ) msg.buf[(4 * i) + 3 - d] = (uint8_t)(mbxAddr[2 + i] >> (8 * d));
      mbxAddr[0] = FLEXCAN_MB_CS_CODE(FLEXCAN_MB_CODE_RX_EMPTY) | ((msg.flags.extended) ? (FLEXCAN_MB_CS_SRR | FLEXCAN_MB_CS_IDE) : 0);
      (void)FLEXCANb_TIMER(_bus);
      writeIFLAGBit(mb_num);
      if ( filter_match((FLEXCAN_MAILBOX)mb_num, msg.id) ) struct2queueRx(msg); /* store frame in queue */
      frame_distribution(msg);
      ext_output1(msg);
      ext_output2(msg);
      ext_output3(msg);
    }
  }

  FLEXCANb_ESR1(_bus) |= FLEXCANb_ESR1(_bus);
  asm volatile ("dsb");
  [COLOR="#FF0000"]writeIMASK(imask); /* Added by MSADIE disable new interrupts */[/COLOR]
}

Files:
Code:
[ATTACH]20262._xfImport[/ATTACH]
 
no dont do that, that puts the controller in HALT mode, the imask bits need to stop the controller to change them, and you also disabled any mailbox interrupts as well

events() wasnt used during my tests, so it can be crossed out of being a cause.

the imask bit tells the controller what mailboxes are interrupt enabled, disabling them causes reception to drop to polling mode, plus cycling the flexcan in freeze mode for the imask bits will cause frames to go missing during that phase

the other thing i realized is if we want to issue a frame we want it done right away in write() with events() as a backup for the TX queues, rather than causing more latency in the ISR.

I think we should stick with what we have now without adding more overhead and extra mailbox scans into the ISR. If I can manage to meet the ISR half way with events() without extra scans to mailboxes, it would be okay, but right now as it stands the transmit interrupts were unstable and caused extra ISR overhead, plus playing with the imasks causes confusion while cycling the controller that may miss frames.
 
Last edited:
Here is a new test of transmit interrupts! redesigned starting from the github copy. Transmit interrupts are enforced now, there is no way to disable them without breaking isr & loop handling of TX queues. Test ran without events().
Not using events(), RX interrupts fire directly to callback, no RX queues. Doesn't participate in TX dequeues.
Using events(), RX queue is pushed to callback from loop, and loop() works with ISR for offloading TX queues, as a safety measure, the NVIC IRQ is disabled and enabled if the events() dequeue happens before the ISR, to prevent potential race conditions.

Code:
[ATTACH]20278._xfImport[/ATTACH]
 
Last edited:
OK. Update6 seems to be working well so far for a simple gateway program writing to an quiet bus.

I'm a bit concerned with the 1 bit of bus idle between sequential writes from queue. This allows lower priority frames from non-seq MB's or other controllers to sneak ahead of higher priority frames.

The most basic program writing a sequential message in a for-loop produces the following:
Code:
     Time       Chn     ID    Dir    DLC   Data                        Bus Idle    Frame Duration        Diff Time   
     5.776020   CAN 1   123   Rx     8     00 00 00 00 00 00 00 00                0.250 ms (125 bits)   0.000000    
     5.776272   CAN 1   123   Rx     8     00 00 00 00 00 00 00 00     0.002 ms   0.250 ms (125 bits)   0.000252    
     5.776524   CAN 1   123   Rx     8     00 00 00 00 00 00 00 00     0.002 ms   0.250 ms (125 bits)   0.000252    
     5.776776   CAN 1   123   Rx     8     00 00 00 00 00 00 00 00     0.002 ms   0.250 ms (125 bits)   0.000252    
     5.777029   CAN 1   123   Rx     8     00 00 00 00 00 00 00 00     0.002 ms   0.250 ms (125 bits)   0.000252

Same program with non-sequential message:
Code:
     Time       Chn     ID    Dir    DLC   Data                        Bus Idle    Frame Duration        Diff Time   
     4.537827   CAN 1   123   Rx     8     00 00 00 00 00 00 00 00                0.250 ms (125 bits)   0.000000    
     4.538077   CAN 1   123   Rx     8     00 00 00 00 00 00 00 00     0.000 ms   0.250 ms (125 bits)   0.000250    
     4.538328   CAN 1   123   Rx     8     00 00 00 00 00 00 00 00     0.000 ms   0.250 ms (125 bits)   0.000250    
     4.538578   CAN 1   123   Rx     8     00 00 00 00 00 00 00 00     0.000 ms   0.250 ms (125 bits)   0.000250    
     4.538828   CAN 1   123   Rx     8     00 00 00 00 00 00 00 00     0.000 ms   0.250 ms (125 bits)   0.000250

To illustrate this more clearly, I set up a program to perform 6x sequential highest priority writes (0x000) followed by 3 non-sequential lowest priority (0x7FF) writes. Also, an external node is competing to write 0x7FE frames. The result is:
Code:
     Time       Chn     ID    Dir    DLC   Data                       Bus Idle    Frame Duration        Diff Time   
     3.452732   CAN 1   0     Rx     8     08 00 00 00 00 00 00 00                0.254 ms (127 bits)   0.000000    
     3.452984   CAN 1   7FF   Rx     8     00 00 00 00 00 00 00 00     0.000 ms   0.252 ms (126 bits)   0.000252    
     3.453237   CAN 1   0     Rx     8     09 00 00 00 00 00 00 00     0.000 ms   0.252 ms (126 bits)   0.000252    
     3.453493   CAN 1   7FE   Tx     8     00 00 00 00 00 00 00 00     0.000 ms   0.254 ms (127 bits)   0.000256    
     3.453745   CAN 1   0     Rx     8     08 01 00 00 00 00 00 00     0.000 ms   0.254 ms (127 bits)   0.000252    
     3.454001   CAN 1   7FE   Tx     8     00 00 00 00 00 00 00 00     0.000 ms   0.254 ms (127 bits)   0.000256    
     3.454251   CAN 1   0     Rx     8     09 01 00 00 00 00 00 00     0.000 ms   0.252 ms (126 bits)   0.000250    
     3.454501   CAN 1   7FF   Rx     8     00 01 00 00 00 00 00 00     0.000 ms   0.250 ms (125 bits)   0.000250    
     3.454755   CAN 1   0     Rx     8     08 02 00 00 00 00 00 00     0.000 ms   0.254 ms (127 bits)   0.000254    
     3.455007   CAN 1   7FF   Rx     8     00 02 00 00 00 00 00 00     0.000 ms   0.252 ms (126 bits)   0.000252    
     3.455257   CAN 1   0     Rx     8     09 02 00 00 00 00 00 00     0.000 ms   0.250 ms (125 bits)   0.000250
Since the non-sequential messages are loaded into MBs and ready for arbitration, they are sent during the 1-bit bus idle between seq messages.

If I instead set seq = 0 and manually specify two alternating MB numbers for the high priority messages, they are forced to queue and dequeue sequentially (for this example, at least). The result as expected:
Code:
     Time       Chn     ID    Dir    DLC   Data                       Bus Idle    Frame Duration        Diff Time   
     2.995827   CAN 1   0     Rx     8     08 00 00 00 00 00 00 00                0.254 ms (127 bits)   0.000000    
     2.996079   CAN 1   0     Rx     8     09 00 00 00 00 00 00 00     0.000 ms   0.252 ms (126 bits)   0.000252    
     2.996333   CAN 1   0     Rx     8     08 01 00 00 00 00 00 00     0.000 ms   0.254 ms (127 bits)   0.000254    
     2.996585   CAN 1   0     Rx     8     09 01 00 00 00 00 00 00     0.000 ms   0.252 ms (126 bits)   0.000252    
     2.996839   CAN 1   0     Rx     8     08 02 00 00 00 00 00 00     0.000 ms   0.254 ms (127 bits)   0.000254    
     2.997089   CAN 1   0     Rx     8     09 02 00 00 00 00 00 00     0.000 ms   0.250 ms (125 bits)   0.000250    
     2.997345   CAN 1   7FE   Tx     8     00 00 00 00 00 00 00 00     0.000 ms   0.254 ms (127 bits)   0.000256    
     2.997599   CAN 1   7FE   Tx     8     00 00 00 00 00 00 00 00     0.000 ms   0.254 ms (127 bits)   0.000254    
     2.997849   CAN 1   7FF   Rx     8     00 02 00 00 00 00 00 00     0.000 ms   0.252 ms (126 bits)   0.000250    
     2.998101   CAN 1   7FF   Rx     8     00 00 00 00 00 00 00 00     0.000 ms   0.252 ms (126 bits)   0.000252    
     2.998352   CAN 1   7FF   Rx     8     00 01 00 00 00 00 00 00     0.000 ms   0.250 ms (125 bits)   0.000250

For this example, I simply used fixed MB numbers MB8 and MB9. This is just a proof-of-concept made using what I could to make it work outside the library.

Just brainstorming: one or both of these could be dynamically assigned to the first available TX mailbox(es). Subsequent sequential messages would have MBs set to alternate these MB numbers. When these sequential MBs flag as TX_INACTIVE, the assignments could be cleared.

I suppose if I'm the only one with an application that would benefit, at least now I've figured out how to make it work without hacking up the library, which may be good enough for me.


Source code for posterity:
Code:
#include <FlexCAN_T4.h>

FlexCAN_T4<CAN1, RX_SIZE_256, TX_SIZE_16> myCan;


void sendSeqBurst() {
  CAN_message_t myMsgMB8;
  CAN_message_t myMsgMB9;
  CAN_message_t myMsg7FF;

  // High priority messages
  myMsgMB8.id = 0x000;
  myMsgMB8.seq = 0;   // Set to 1 -> bus idle for 1 bit between messages
  myMsgMB8.mb = 8;
  myMsgMB8.buf[0] = 8;

  myMsgMB9.id = 0x000;
  myMsgMB9.seq = 0;   // Set to 1 -> bus idle for 1 bit between messages
  myMsgMB9.mb = 9;
  myMsgMB9.buf[0] = 9;

  // Low priority message acting as "interference"
  myMsg7FF.id = 0x7FF;
  myMsg7FF.seq = 0;
  myMsg7FF.mb = -1;


  // Write series of high priority messages
  for ( int i = 0; i < 3; i++) {
    myCan.write(myMsgMB8);
    myCan.write(myMsgMB9);
    myMsgMB8.buf[1]++;
    myMsgMB9.buf[1]++;
  }

  // Write series of low priority messages
  for ( int i = 0; i < 3; i++) {
    myCan.write(myMsg7FF);
    myMsg7FF.buf[1]++;
  }
}



void setup() {
  pinMode(20, OUTPUT); digitalWriteFast(20, LOW);   /* optional tranceiver silent pin: HIGH = Silent */
  pinMode(13, OUTPUT);

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

  delay(1000);

  sendSeqBurst();


}

void loop() {
// do nothing
}



Thanks, Mike
 
I'm glad the transmit from ISR is working for you, that shows progress. I am not too technical on the 1 bit term, or why you need 2 mailboxes for sequential, or which of the 2 would release first, but in the isr (per fire) a seq frame in queue is pushed to the mailbox if its free, if there is a consecutive seq frame, it will push on the next interrupt (when MB8 fires) when the MB is inactive. non sequential frames should distribute immediately to all available TX mailboxes

the intent of sequential frames is for a single ID single file data, even if other frames are sending. also, maybe you can try mailbox priority flag per the reference manual, maybe we could flag the seq mailboxes as high priority then unflag them in ISR hit so they dont be active for regular frames.
 
I'm glad too. Thanks for your efforts! I think the interrupt driven TX resolves the weird lockup issue I was having a while back.

My objective is to be able to replicate the bus activity as accurately as possible, be it for stimulating an ECU on the bench or acting as a gateway on the bus. Since the ECUs generating the CAN traffic are likely using task timers to transmit at regular intervals, each ECU is (generally) creating a burst of 1+ messages. So rather than the intended usage for large packet transmitting like ISO-TP, I'm trying to transmit messages with different IDs single file with no bus idle if that's how they are received. Whether including this use case is worth the complexity, I'm not sure.
 
not sure how to approach that, still confused on your explanation. ohhhhh i see what you are saying, well FIFO for RX receives in order as long as you dont have any RX mbs taking frames from it, then seq them to the gateway node, for in and out ordering, im still lost on your explanation though

dont forget if you want less mailboxes, or more, thats adjustable.
T4 has 64 mailbox support, T3 has 16. we use 16 for setup because the less you have the faster/higher priority they are scanned for arbitration. if you wanna mimic an MCP with 2 mailboxes with FIFO disabled, and 1 TX mailbox, 3 total, thats possible

your configuration is always visible with mailboxStatus()
 
Last edited:
After lots of reconsideration, I'm now thinking sending the messages by ID priority is more important for this application than forcing them to transmit sequentially. That said, everything seems to be working well so far with Update6. Please disregard my last confusing posts.

A more straightforward request: Since events() is no longer required, can you please add another way to query rx/tx buffer size?

Thanks again for your help and for making this library!
 
I assumed it would be best to just return the same uint64_t that events returns, for sake of consistency. If someone is using the current library and making use of the returned queue size from events(), when upgrading to ISR based, they can seamlessly replace events() with the queue size function. But personally, I'm all for separate TX/RX functions to reduce the redundant masking and shifting.

I'm partial to the get/set prefixed function names just for consistency with existing function names (getClock(), getBaudRate()).

It would be nice to find a way to describe the number of messages in queue differently than "size", since this is used to specify queue capacity. Maybe something like count, for instance getTxQueueCount().
 
New update:

getRXQueueCount() and getTXQueueCount() added.

As requested over at github by jeremy: https://github.com/tonton81/FlexCAN_T4/issues/9
It adds the ability to filter based on arbitrary masks, very helpful in the J1939 world.
Added support for up to 4 IDs per filter for arbitrary masking.
I also added the ability to enhanceFilter in a multi ID user mask as well as distribution support.

Code:
    bool setMBUserFilter(FLEXCAN_MAILBOX mb_num, uint32_t id1, uint32_t mask);
    bool setMBUserFilter(FLEXCAN_MAILBOX mb_num, uint32_t id1, uint32_t id2, uint32_t mask);
    bool setMBUserFilter(FLEXCAN_MAILBOX mb_num, uint32_t id1, uint32_t id2, uint32_t id3, uint32_t mask);
    bool setMBUserFilter(FLEXCAN_MAILBOX mb_num, uint32_t id1, uint32_t id2, uint32_t id3, uint32_t id4, uint32_t mask);

    bool setFIFOUserFilter(uint8_t filter, uint32_t id1, uint32_t mask, const FLEXCAN_IDE &ide, const FLEXCAN_IDE &remote = NONE);
    bool setFIFOUserFilter(uint8_t filter, uint32_t id1, uint32_t id2, uint32_t mask, const FLEXCAN_IDE &ide, const FLEXCAN_IDE &remote = NONE);
    bool setFIFOUserFilter(uint8_t filter, uint32_t id1, uint32_t id2, uint32_t id3, uint32_t mask, const FLEXCAN_IDE &ide, const FLEXCAN_IDE &remote = NONE);
    bool setFIFOUserFilter(uint8_t filter, uint32_t id1, uint32_t id2, uint32_t id3, uint32_t id4, uint32_t mask, const FLEXCAN_IDE &ide, const FLEXCAN_IDE &remote = NONE);

Code:
[ATTACH]20405._xfImport[/ATTACH]
 
hello everyone. I'm am fairly new to micro controllers so don't have much knowledge of them (have dabbled with some arduino nano as temp controllers and neo pixel drivers)

i'm looking to build a display/data logger for my car (2015 VW).

i've got got 2 teensy' (4.0 and 4.1), 2 SN65HVD230 Transceivers(on a breakout board) and a ST7798 240x240 display.

what i'm looking to do is bench test the idea (rather than keep going to the car). i've got the display working enough so far (sort of boot screen, then it just cycles through 3 "pages" of data)

what i can't seem to work out is if the transceivers are working (read up that there maybe a problem with these. I have removed the resistor that was on the rs or rx pin (pin 8) and tied it direct to ground.

so is there an example i can use that will give a serial output of just a fixed or random string. (on either just one teensy or one tx and one rx )

i've tried all of the examples but i either get nothing on serial or data that doesn't change if i disconnect the transceivers.

this is how i had the connections on the 4.0 trying some of the examples that looked like they used just one teensy.

thanks dink
teensy40.jpg
 
if there is a transceiver issue, you may not be able to see data between teensies. usually if you can test it reading on the car bus, if it works there you should be able to communicate without problems knowing the transceiver is good. The demos show mostly receiving, but you can make and send a frame using:

CAN_message_t msg;
msg.id = 0x123;
msg.flags.extended = 0;
msg.len = 8;
msg.buf[0] = 0x1;
msg.buf[1] = 0x2;
Can0.write(msg);
 
thanks tonton81, i tried that but I failed completely trying to work out where to add that to some example code.

i think I've got them working using an arduino nano and and mcp2515 as a transmitter and i got this serial output on the teensy 4.0 using the beta_sample example

output.jpg

This was the code on the nano (looks like it just increments the data by 1 each loop)
Code:
// demo: CAN-BUS Shield, send data
// loovee@seeed.cc

#include <mcp_can.h>
#include <SPI.h>

/*SAMD core*/
#ifdef ARDUINO_SAMD_VARIANT_COMPLIANCE
    #define SERIAL SerialUSB
#else
    #define SERIAL Serial
#endif

// the cs pin of the version after v1.1 is default to D9
// v0.9b and v1.0 is default D10
const int SPI_CS_PIN = 9;

MCP_CAN CAN(SPI_CS_PIN);                                    // Set CS pin

void setup() {
    SERIAL.begin(115200);

    while (CAN_OK != CAN.begin(CAN_500KBPS)) {            // init can bus : baudrate = 500k
        SERIAL.println("CAN BUS Shield init fail");
        SERIAL.println(" Init CAN BUS Shield again");
        delay(100);
    }
    SERIAL.println("CAN BUS Shield init ok!");
}

unsigned char stmp[8] = {0, 0, 0, 0, 0, 0, 0, 0};
void loop() {
    // send data:  id = 0x00, standrad frame, data len = 8, stmp: data buf
    stmp[7] = stmp[7] + 1;
    if (stmp[7] == 100) {
        stmp[7] = 0;
        stmp[6] = stmp[6] + 1;

        if (stmp[6] == 100) {
            stmp[6] = 0;
            stmp[5] = stmp[6] + 1;
        }
    }

    CAN.sendMsgBuf(0x00, 0, 8, stmp);
    delay(100);                       // send data per 100ms
}

// END FILE
 
i see you are using delay(100) in your loop() for the MCP. You can copy the frame i posted earlier to the loop and add delay(100) as well, but later on dont use delay() as its blocking, unless you dont plan on adding other code
 
Just added wake up on traffic support.

You can call:
Code:
asm(" wfi");
in your code to goto sleep. The loop() will stop scrolling after shorting out the CAN lines when the wfi enters sleep. Removing the short on the CAN lines restores the CAN network, and Teensy 4 will self-wake when data starts rolling on the bus

Code:
[ATTACH]20158[/ATTACH]

Hi Tony,

Only got to test this now.
I replaced the .h and .tpp files from the zip you provided in the standard FlexCAN_T4 library folder.
I get a compile error for the T4, seems to be related to the CAN FD constructor?

Code:
In file included from /Applications/Teensyduino.app/Contents/Java/hardware/teensy/avr/libraries/FlexCAN_T4/FlexCAN_T4.h:500:0,
                 from /Users/Rezo/Documents/Arduino/T4/CAN_T4_MB_interval_3.5_v2.5.2.03/CAN_T4_MB_interval_3.5_v2.5.2.03.ino:8:
/Applications/Teensyduino.app/Contents/Java/hardware/teensy/avr/libraries/FlexCAN_T4/FlexCAN_T4FD.tpp: In member function 'void FlexCAN_T4FD<_bus, _rxSize, _txSize>::begin()':
/Applications/Teensyduino.app/Contents/Java/hardware/teensy/avr/libraries/FlexCAN_T4/FlexCAN_T4FD.tpp:67:9: warning: there are no arguments to 'setTx' that depend on a template parameter, so a declaration of 'setTx' must be available [-fpermissive]
   setTx(); setRx();

         ^
/Applications/Teensyduino.app/Contents/Java/hardware/teensy/avr/libraries/FlexCAN_T4/FlexCAN_T4FD.tpp:67:18: warning: there are no arguments to 'setRx' that depend on a template parameter, so a declaration of 'setRx' must be available [-fpermissive]
   setTx(); setRx();

                  ^
In file included from /Applications/Teensyduino.app/Contents/Java/hardware/teensy/avr/libraries/FlexCAN_T4/FlexCAN_T4.h:500:0,
                 from /Users/re/Documents/Arduino/T4/CAN_T4_MB_interval_3.5_v2.5.2.03/CAN_T4_MB_interval_3.5_v2.5.2.03.ino:8:
/Applications/Teensyduino.app/Contents/Java/hardware/teensy/avr/libraries/FlexCAN_T4/FlexCAN_T4FD.tpp: At global scope:
/Applications/Teensyduino.app/Contents/Java/hardware/teensy/avr/libraries/FlexCAN_T4/FlexCAN_T4FD.tpp:313:52: error: no 'void FlexCAN_T4FD<_bus, _rxSize, _txSize>::setTx(FLEXCAN_PINS)' member function declared in class 'FlexCAN_T4FD<_bus, _rxSize, _txSize>'
 FCTPFD_FUNC void FCTPFD_OPT::setTx(FLEXCAN_PINS pin) {

                                                    ^
/Applications/Teensyduino.app/Contents/Java/hardware/teensy/avr/libraries/FlexCAN_T4/FlexCAN_T4FD.tpp:334:52: error: no 'void FlexCAN_T4FD<_bus, _rxSize, _txSize>::setRx(FLEXCAN_PINS)' member function declared in class 'FlexCAN_T4FD<_bus, _rxSize, _txSize>'
 FCTPFD_FUNC void FCTPFD_OPT::setRx(FLEXCAN_PINS pin) {

                                                    ^
Error compiling for board Teensy 4.0.
 
just checked repo, you have an outdated version your overriding. setTx was changed to setTX couple updates ago. use github copy with latest patch
 
Back
Top