nopnop2002 / Arduino-STM32-CAN

Can Example for Arduino Core STM32
210 stars 53 forks source link

Can Filters #34

Open Wh1terat opened 3 years ago

Wh1terat commented 3 years ago

Hi, Firstly - thank you for the project, very nicely documented.

Just wondering if you have some examples for CANSetFilter ? I'm trying to filter messages from ID 0x681 AND the first byte of the message 0x03

So this works fine for filtering all messages from 0x681

  CANSetFilter(0, 1, 0, 0, 0x681 << 21, 0xFFE00000);

So I expected this would work for what I was trying to achieve:

  CANSetFilter(0, 1, 0, 0, 0x68103 << 13, 0xFFFFE000);

But I'm still receiving all messages to 0x681 with this which is odd.

nopnop2002 commented 3 years ago

Hello.

0x681 << 21 = 0xd0200000

0x68103 << 13 = 0xd0206000

The extended format 29-bit length ID range is 0x0 to 0x1FFFFFFF 0xd0206000 is out of range.

Filter bank format is: https://www.st.com/resource/en/reference_manual/cd00171190-stm32f101xx-stm32f102xx-stm32f103xx-stm32f105xx-and-stm32f107xx-advanced-arm-based-32-bit-mcus-stmicroelectronics.pdf

FilterBank

Wh1terat commented 3 years ago

Thanks for reply.

Yes I understand it's 29bit for extended or 11bit for standard. But unlike mcp2515, stm32 filter seems to read from MSB, not MSB+3.

11010000 00100000 00000000 00000000

Because this works to filter 0x681.

Infact, you can even see this in your own code from CANReceive function:

      out = ((CAN_tx_msg->id & CAN_STD_ID_MASK) << 21U);

Edit:

To clarify what I'm asking, is it possible to filter the first 2 data bytes of a standard frame using the 32bit filters? As data bytes 1 & 2 would be in the same position as EXTID[12:0]+IDE+RTE

nopnop2002 commented 3 years ago

is it possible to filter the first 2 data bytes of a standard frame using the 32bit filters?

The Filter bank register has 28 FiR1 and 28 FiR2 respectively.

F0R1-F27R1 F0R2-F27R2

Standard frame filter:

Set the first filter to F0R1 Set a second filter on F0R2

F0R1=first filter data
F0R2=second filter data
CANSetFilter(0, 0, 1, 0, F0R1, F0R2) 
Wh1terat commented 3 years ago

That is simply using list mode rather than mask mode to match multiple IDs ?

To explain my problem more clearly, Can ID 0x681 sends constant keepalive messages every 500ms, first byte of data ID is 0xF0.

I am only interested in messages where first byte of data is 0x04 - because of the frequency of the keepalive messages it makes ISR unsuitable.

With MCP2515's filter I am able to filter the ID and first 2 bytes of a standard frame, trying to replicate this functionality using STM32.

nopnop2002 commented 3 years ago

Standard frame filter Identifier List mode:

F0R1=1st id & 2nd id
F0R2=3rd id & 4th id
CANSetFilter(0, 0, 1, 0, F0R1, F0R2) 

Standard frame filter Identifier Mask mode:

F0R1=1st id & 2nd id
F0R2=1st mask & 2nd mask
CANSetFilter(0, 0, 0, 0, F0R1, F0R2) 

Extended frame filter Identifier List mode:

F0R1=1st id
F0R2=2nd id
CANSetFilter(0, 1, 1, 0, F0R1, F0R2) 

Extended frame filter Identifier Mask mode:

F0R1=1st id
F0R2=1st mask
CANSetFilter(0, 1, 0, 0, F0R1, F0R2) 
Wh1terat commented 3 years ago

Thank you for trying to help, but I think maybe I am being unclear about my issue or what I am trying to achieve - or maybe it is not even possible.

Elektrik1 commented 3 years ago

Same issue here, transitioning from MCP2515, it is completely unclear how to configure CANSetFilter to allow particular (or range) of ID`s, also it's unclear how to filter on 0,1,2..n bytes of data, for example filter only particular (or range) where data[0] or data[n] corresponds.

For example: I want to allow only packets with ID=0x101 and data[0]=0x6B. How to set the filter? Tried this, no success: CANSetFilter(0, 1, 0, 0, 0x101 << 21, 0x6B << 24);

nopnop2002 commented 3 years ago

From RM0008 Reference manual

24.4.1 Initialization mode

The software initialization can be done while the hardware is in Initialization mode. To enter this mode the software sets the INRQ bit in the CAN_MCR register and waits until the hardware has confirmed the request by setting the INAK bit in the CAN_MSR register. To leave Initialization mode, the software clears the INRQ bit. bxCAN has left Initialization mode once the INAK bit has been cleared by hardware. While in Initialization Mode, all message transfers to and from the CAN bus are stopped and the status of the CAN bus output CANTX is recessive (high). Entering Initialization Mode does not change any of the configuration registers. To initialize the CAN Controller, software has to set up the Bit Timing (CAN_BTR) and CAN options (CAN_MCR) registers.

To initialize the registers associated with the CAN filter banks (mode, scale, FIFO _assignment, activation and filter values), software has to set the FINIT bit (CAN_FMR). Filter__ initialization also can be done outside the initialization mode.___

Case of STM32F103:

  // Configure Filters to default values
  CAN1->FMR  |=   0x1UL;                // Set to filter initialization mode
  CAN1->FMR  &= 0xFFFFC0FF;             // Clear CAN2 start bank

  // bxCAN has 28 filters.
  // These filters are used for both CAN1 and CAN2.
  // STM32F103 has only CAN1, so all 28 are used for CAN1
  CAN1->FMR  |= 0x1C << 8;              // Assign all filters to CAN1

  // Set fileter 0
  // Single 32-bit scale configuration 
  // Two 32-bit registers of filter bank x are in Identifier Mask mode
  // Filter assigned to FIFO 0 
  // Filter bank register to all 0
  CANSetFilter(0, 1, 0, 0, 0x0UL, 0x0UL); 

  CAN1->FMR   &= ~(0x1UL);              // Deactivate initialization mode
va7wv commented 2 years ago

I don't understand this either. I want to filter only 7E8 diagnostic response messages from OBDII.

No go even when directly editing the code as highlighted in the previous response:

CANSetFilter(0, 1, 0, 0, 0x7E8, 0x7E8);

nopnop2002 commented 2 years ago

FilterBank

FilterBank

If you want to filter only ID=0x7E8


Mask bit0 indicates that you don't care.

Mask bit1 indicates that you care.

v-ivanyshyn commented 1 year ago

If anyone still struggles with setting up filters in list mode for 16bit IDs, here is how it should look:

uint32_t bank1 = (filterId1<<21) | (filterId2<<5);
uint32_t bank2 = (filterId3<<21) | (filterId4<<5);
rmoscoloni commented 1 year ago

Please, could i ask how can i filter a range of std ids? ie 0 to 7?, list mode from v-ivanyshyn works well, but im getting confused by bitshift places. for mask mode.

I cant get why bank 2 is 0xFFE00006 In the example above:

 uint32_t bank1, bank2;
 bank1 = 0x7E8 << 21;
 bank2 = 0xFFE00006; // Must be IDE=0 RTR=0
 CANSetFilter(0, 1, 0, 0, bank1, bank2);
nopnop2002 commented 1 year ago

I cant get why bank 2 is 0xFFE00006 In the example above:

About STM32 CAN Identifier Filtering

https://schulz-m.github.io/2017/03/23/stm32-can-id-filter/

rmoscoloni commented 1 year ago

Thanks for the answer nopnop2002: first I have to thank you for the code you have made and shared, thank you very much! Have the link bookmarked for a long time and I wanted to follow the example of filtering from 0 to 7 but in std id. I was trying to understand how to include in your code to filter the mentioned range.

Answering my own question and for reference to future readers, 0xFFE00006 --> 0x7ff << 21 + 0x06 11111111111000000000000000000000+ 00000000000000000000000000000110= 11111111111000000000000000000110

why include 0x06 in the filter? 0x7ff<<21 is not enough?

nopnop2002 commented 1 year ago

why include 0x06 in the filter? 0x7ff<<21 is not enough?

This is because IDE and RTR are used to distinguish between frame types.

Bit 2 IDE: Identifier extension
This bit defines the identifier type of message in the mailbox.
0: Standard identifier.
1: Extended identifier.
Bit 1 RTR: Remote transmission request
0: Data frame
1: Remote frame

|<------->| Can ID for Standard
|<------------------------->| Can ID for Extended
11111111111000000000000000000110
                             ||
                             |+-->RTR
                             +-->IDE

There are 4 frames type

If you don't include 0x06 in your filter, these will match

ID=0x467 and ID=0x119C000 pass the filter even though only ID=0x467 is needed.

   ID=100-0110-0111=0x467
<----------->
1000 1100 1110 0000 0000 0000 0000 0000 // Standard data frame

   ID=0x467
<----------->
1000 1100 1110 0000 0000 0000 0000 0010 // Standard remote frame

   ID=1-0001-1001-1100-0000-0000-0000==0x119C000
<---------------------------------->
1000 1100 1110 0000 0000 0000 0000 0100 // Extended data frame

   ID=0x119C000
<---------------------------------->
1000 1100 1110 0000 0000 0000 0000 0110 // Extended remote frame

168242049-5020bdec-d6b6-4279-bf89-151da9c5526f

martin323232 commented 1 year ago

Having issues with filter settings,

receiving id 0x101 and 0x206, how to setup a filter to just receive these messages.

Tried :

uint32_t bank1 = (0x101<<21) | (0x206<<5);
uint32_t bank2 = (0x0<<21) | (0x0<<5);

CANSetFilter(0, 0, 1, 0, bank1, bank2);
uint32_t bank1 = (0x101<<21) | (0x101<<5);
uint32_t bank2 = (0x206<<21) | (0x206<<5);

CANSetFilter(0, 0, 1, 0, bank1, bank2);
nopnop2002 commented 1 year ago

Case of STM32F103:

CAN1->FMR  |=   0x1UL;                // Set to filter initialization mode

fileter setting

CAN1->FMR   &= ~(0x1UL);              // Deactivate initialization mode

Otherwise: Look at the source.

FilterBank

/*
Bit IDE: Identifier extension
This bit defines the identifier type of message in the mailbox.
0: Standard identifier.
1: Extended identifier.
Bit RTR: Remote transmission request
0: Data frame
1: Remote frame
*/

int IDE1=0;
int IDE2=0;
int IDE3=0;
int IDE4=0;
int RTR1=0or1;
int RTR2=0or1;
int RTR3=0or1;
int RTR4=0or1;

uint32_t bank1 = (STID1<<21) | (RTR1<<20) | (IDE1<<19) | (STID2<<5) | (RTR2<<4) | (IDE2<<3);
uint32_t bank2 = (STID3<<21) | (RTR3<<20) | (IDE3<<19) | (STID4<<5) | (RTR4<<4) | (IDE4<<3);