Teensy 4.1 FlexCAN_t4 ext ID setMBFilter() 18 bits only?

Nicc

Member
Hello,

Recently I was working with the FlexCAN_t4 library but I encountered some behaviour that I was not expecting based on how I understand the filtering to work. I made a test script that displays the behaviour that I experienced. The behaviour is that only the 18 LSB of an extended CAN ID is used in the filter. So If the ID is 0x00070000 then other messages will alias with it such as 0x0003000 since they have the same 18 LSB. I looked at some of the library code and it appears that the ID is masked against 0x0003FFFF in FLEXCAN_MB_ID_IDEXT() so I'm assuming this is a known and required choice. My questions are:
1. Are the 18 LSB the bits that can be used on a HW filter of a non-FIFO, ie MB, when receiving extended ID CAN frames (even if I'm not using the FIFO, and each mailbox only has a single ID not a range); can I match a full 29 bits extended ID?
2. If it's not a HW limitation? I'm then curious on this design decision; otherwise then that makes a lot of sense but I swear I couldn't find anything on it in the manual (Rev 3). To me it looked like all of the FLEXCANx_RXIMRn registers are available.

Oh yeah, I should mention that I do know about the handy enhanceFilter() method available and I am able to use that. Just seemed odd that it would not be possible to use all 29 bits in a filter, especially since the FIFO can.


Code:
#include <FlexCAN_T4.h>

FlexCAN_T4<CAN1, RX_SIZE_256, TX_SIZE_16> can1;
FlexCAN_T4<CAN2, RX_SIZE_256, TX_SIZE_16> can2;

#define p(msg) Serial.print(msg)
#define pl(msg) Serial.println(msg)
#define ph(msg) Serial.print(msg, HEX)
#define phl(msg) Serial.println(msg, HEX)

#define myCAN_ID          0x00070000
#define mb_rx_test        MB0
#define NUMBER_RX_MB      1
#define NUMBER_TX_MB      1
#define CAN_ID_START      0x20000000
#define CAN_ID_END        0x0
#define CAN_ID_INC        0x0001000

CAN_message_t get_ID_CAN_msg(const int id) {
    CAN_message_t msg;
    msg.len = 0;
    msg.flags.extended = 1;
    msg.id = id;
    return msg;
}

CAN_message_t get_ID_CAN_msg_STD(const int id) {
    CAN_message_t msg;
    msg.len = 0;
    msg.flags.extended = 0;
    msg.id = id;
    return msg;
}

CAN_message_t msg;
long sum = 0;

void setup() {
    Serial.begin(9600);
    while ((!Serial) && (millis() < 4000) );
    
    can1.begin();
    can1.setBaudRate(1000000);
    can1.setMaxMB(NUMBER_TX_MB);
    can1.setMB(MB0,TX);
    can1.setMBFilter(REJECT_ALL);

    can2.begin();
    can2.setBaudRate(1000000);
    can2.setMaxMB(NUMBER_RX_MB);
    can2.setMB(mb_rx_test, RX, EXT);
    can2.setMBFilter(mb_rx_test, myCAN_ID);
    //can2.enhanceFilter(mb_rx_test);

    pl("begin test");
    /*for (int id = 0x20000000; id >= 0 ; --id) {*/
    can1.write(get_ID_CAN_msg(myCAN_ID));
    for (int id = CAN_ID_START; id >= CAN_ID_END ; id -= CAN_ID_INC) {
        //if (id % 5000000 == 0) { p("Progess report: "); ph(id); p(" "); pl(sum); }
        can1.write(get_ID_CAN_msg(id));
        delayMicroseconds(500);
        if(can2.read(msg)) {
            ++sum;
            p(msg.mb); p(": "); phl(msg.id); 
        }
        delayMicroseconds(500);
    }
    p("Sum: "); pl(sum);
    pl("End test");
}

void loop() {}
 
The macro FLEXCAN_MB_ID_IDEXT() is used in conjunction with FLEXCAN_MB_ID_IDSTD(), which checks the 11 MSB of the extended ID. I haven't had a chance to look over your code yet
 
Ah yes, I see what you mean. FLEXCAN_MB_ID_IDEXT() and FLEXCAN_MB_ID_IDSTD() are for separate banks of bits within the ID field. I didn't catch this the first time and it makes sense based on how it's laid out in HW.
That being said those are used in a ternary operation meaning their application are mutually exclusive; it should only be STD ID or EXT ID though ideally I'd like to use all the bits to filter against 29 bits. I'm assuming the filter in HW is being set with FLEXCANb_MBn_ID() in setMBFilterProcessing() in which it selects a STD ID or EXT ID.
I tired setting an extended ID filter followed by a STD ID filter to see if I could force it to set all the bits but that didn't work. :p
 
Oh ok, I understand now. It's like the standard bits should always be set and then extended bits only if IDE==1. Since my uses of the library have never included extended frames with filters, I'm a out of my depth. I'd suggest posting an issue in the GitHub repo.
 
Thanks for the suggestion, I submitted an issue on the GitHub: Issue 60
Furthermore I did some testing and found that changing FLEXCAN_MB_ID_IDEXT() to (filter_id & 0x1FFFFFFF) seems to have solved the issue in this case :D. I'll include the code here as well.

Code:
FCTP_FUNC void FCTP_OPT::setMBFilterProcessing(FLEXCAN_MAILBOX mb_num, uint32_t filter_id, uint32_t calculated_mask) {
  bool frz_flag_negate = !(FLEXCANb_MCR(_bus) & FLEXCAN_MCR_FRZ_ACK);
  FLEXCAN_EnterFreezeMode();
  FLEXCANb_RXIMR(_bus, mb_num) = calculated_mask | ((FLEXCANb_CTRL2(_bus) & FLEXCAN_CTRL2_EACEN) ? (1UL << 30) : 0);
  FLEXCANb_MBn_ID(_bus, mb_num) = ((!(FLEXCANb_MBn_CS(_bus, mb_num) & FLEXCAN_MB_CS_IDE)) ? FLEXCAN_MB_ID_IDSTD(filter_id) : (filter_id & 0x1FFFFFFF));
  if ( frz_flag_negate ) FLEXCAN_ExitFreezeMode();
}

FCTP_FUNC bool FCTP_OPT::setMBFilter(FLEXCAN_MAILBOX mb_num, uint32_t id1) {
  if ( mb_num < mailboxOffset() || mb_num >= FLEXCANb_MAXMB_SIZE(_bus) ) return 0; /* mailbox not available */
  if ( (FLEXCAN_get_code(FLEXCANb_MBn_CS(_bus, mb_num)) >> 3) ) return 0; /* exit on TX mailbox */ 
  uint32_t mask = ( !(FLEXCANb_MBn_CS(_bus, mb_num) & FLEXCAN_MB_CS_IDE) ) ? FLEXCAN_MB_ID_IDSTD(((id1) ^ (id1)) ^ 0x7FF) : ((((id1) ^ (id1)) ^ 0x1FFFFFFF) & 0x1FFFFFFF);
  setMBFilterProcessing2(mb_num,id1,mask);
  filter_store(FLEXCAN_MULTI, mb_num, 1, id1, 0, 0, 0, 0);
  return 1;
}
 
Back
Top