canFilterCreate (Function)

Top  Previous  Next

Architecture:

X32 / NX32 / NX32L

Device support:

MX2 pro, DX4 pro, CX1 pro-c/warp-c, MX2 turbo/encore/warp, NX-200, NX-400, LX2, LX5

Firmware version:

1.00 / 1.00.00


This function is used to create receive filters, which are required to be able to receive any messages from the network.

A filter can either match a single message ID or a range of message IDs.

The filter ID returned when creating the filter must also be used to destroy the filter with canFilterDestroy when it is no longer needed or if it needs to be changed.

The maximum number of filters is 30 for most devices, but the RTCU NX-200 and the RTCU NX-400 have support for up to 64 filters per CAN port for a maximum of 127 filters.

 

Each receive filter is defined by a start-ID and a length. If the length is 1, it will only match the start-ID, if the length is e.g. 3, it will match start-ID, start-ID+1, and start-ID + 2.

Internally, the start-ID and the length are used to create a bit-mask that will match all the needed IDs. This mask is then used to create a hardware filter that handles the high-performance filtering.

Depending on the values chosen for start-ID and length, the hardware filter might cover additional message IDs so a second filtering is done using the start-ID and the length.
Because of filtering, care must be taken when choosing the range for the filters, it is especially necessary to consider the following two limitations:

 

Too many unwanted messages

A filter might cover too many unwanted IDs, which causes additional load on the device which can cause reduced performance for the wanted message.

The number of IDs covered by a filter is determined by the position of the highest-order bit that is different between the first and last ID in a filter. If only the LSB is different it covers 2 IDs, if the next bit is also different, it covers 4 IDs, and so on.

 

An example of this is a start-ID of 16#07FE and a length of 3.

Looking at the binary values shows the problem:


Start-ID

0000_0111_1111_1110

16#07FE


End-ID

0000_1000_0000_0000

16#0800


Mask

0000_1111_1111_1111

16#0FFF


Actual filter:

 

 


Start-ID

0000_0000_0000_0000

16#0000


End-ID

0000_1111_1111_1111

16#0FFF

The mask will match all IDs in the range from 16#0000 to 16#0FFF, a length of 4096 instead of the needed 3.

 

A better solution is to split the range into multiple filters, in this case two filters as shown below:

 

Filter 1: Start-ID 16#07FE, length 2:


Start-ID

0000_0111_1111_1110

16#07FE


End-ID

0000_0111_1111_1111

16#07FF


Mask

0000_0000_0000_0001

16#0001


Actual filter:

 

 


Start-ID

0000_0111_1111_1110

16#07FE


End-ID

0000_0111_1111_1111

16#07FF

 

Filter 2: Start-ID 16#0800, length 1:


Start-ID

0000_1000_0000_0000

16#0800


End-ID

0000_1000_0000_0000

16#0800


Mask

0000_0000_0000_0000

16#0000


Actual filter:

 

 


Start-ID

0000_1000_0000_0000

16#0800


End-ID

0000_1000_0000_0000

16#0800

 

Overlapping filters

If a hardware filter overlaps with other hardware filters, it might prevent the other filters from receiving the messages.

Different devices handle overlapping filters differently, so for a portable solution, overlapping filters should be avoided.

 

As an example, when using the following two filters, the messages for the second filter might be lost, because the mask for the first filter overlaps with the second filter while the wanted ranges do not:

 

Filter 1: Start-ID 16#0050, length 20:


Start-ID

0000_0000_0101_0000

16#0050


End-ID

0000_0000_0110_0011

16#0063


Mask

0000_0000_0011_1111

16#003F


Actual filter:

 

 


Start-ID

0000_0000_0100_0000

16#0040


End-ID

0000_0000_0111_1111

16#007F

 

Filter 2: Start-ID 16#0040, length 3:


Start-ID

0000_0000_0100_0000

16#0040


End-ID

0000_0000_0100_0010

16#0042


Mask

0000_0000_0000_0011

16#0003


Actual filter:

 

 


Start-ID

0000_0000_0100_0000

16#0040


End-ID

0000_0000_0100_0011

16#0043

 

 

A solution is to break the large filter up into two smaller filters that are better aligned:

 

Filter 1: Start-ID 16#0050, length 16:


Start-ID

0000_0000_0101_0000

16#0050


End-ID

0000_0000_0101_1111

16#005F


Mask

0000_0000_0000_1111

16#000F


Actual filter:

 

 


Start-ID

0000_0000_0101_0000

16#0050


End-ID

0000_0000_0101_1111

16#005F

 

Filter 2: Start-ID 16#0060, length 4:


Start-ID

0000_0000_0110_0000

16#0060


End-ID

0000_0000_0110_0011

16#0063


Mask

0000_0000_0000_0011

16#0003


Actual filter:

 

 


Start-ID

0000_0000_0110_0000

16#0060


End-ID

0000_0000_0110_0011

16#0063

 

Filter 3: Start-ID 16#0040, length 3:


Start-ID

0000_0000_0100_0000

16#0040


End-ID

0000_0000_0100_0010

16#0042


Mask

0000_0000_0000_0011

16#0003


Actual filter:

 

 


Start-ID

0000_0000_0100_0000

16#0040


End-ID

0000_0000_0100_0011

16#0043

 

 

Input:

port : SINT (1/2) (default 1)

The port of the CAN bus.

 

xtd : BOOL

Filter for standard or extended identifiers. Set to TRUE for extended identifiers.

 

startID : DINT (16#0...16#1FFF_FFFF)

The first identifier that is accepted.

 

length : DINT (16#1...16#2000_0000)

The length of the range of identifiers that are accepted. For a single identifier, the length should only be set to 1.

 

 

Returns: SINT

>0

- ID of the new filter.

-1

- Illegal start ID.

-2

- Illegal length.

-3

- No free filters.

-8

- The CAN bus is not open.

 

Declaration:

FUNCTION canFilterCreate : SINT;
VAR_INPUT
  port   : SINT := 1;
  xtd     : BOOL;
  startid : DINT;
  length : DINT;
END_VAR;

 

 

Example:

INCLUDE rtcu.inc
 
VAR
  canRX : canReceiveMessage;
  buf   : ARRAY [1..8] OF SINT;
END_VAR;
 
PROGRAM CANExample;
VAR
  FilterID : SINT;
  rc       : INT;
END_VAR;
 
// Open can
canOpen(baud := 250, monitor := FALSE);
canRX(data := ADDR(buf));
 
canLoopBackMode(enable := ON);
 
// startID: Priority=3 Reserved=1 Data page=0 PGN=00FDD6
FilterID := canFilterCreate(xtd:=TRUE,startID:=16#0EFDD600,length:=6);
 
rc := canSendMessage(xtd:=TRUE,ID:=16#0EFDD600,data:=ADDR(buf),datasize:=8);
IF rc = 0 THEN
  DebugMsg(message:="CAN message sent");
ELSE
  DebugFmt(message:="CAN message failed (\1)",v1:=rc);
END_IF;
 
BEGIN
  canRX();
  ...
  IF canRX.ready THEN
    DebugMsg(message:="Message received!");
    DebugFmt(message:="canRX.xtd= \1", v1:=INT(canRX.xtd));
    DebugFmt(message:="canRX.ID= \4", v4:=canRX.ID);
    DebugFmt(message:="canRX.DataSize= \1", v1:=INT(canRX.DataSize));
  END_IF;
  ...
END;
 
END_PROGRAM;