Send and receive an 11-bit CAN frame in CODESYS 3.5

7 min read · Published November 5, 2026

The store example relays frames from ID 500 to 501 and stops there. To handle your own traffic, create the 11-bit function block yourself, accept a frame only when its ID and 8-byte length match, and copy the bytes only while the receive-valid flag is set. Stop the Linux helper processes first: a thousand new threads an hour and a load average of 770 will bury any test.

The CANBus example from the CODESYS store does one thing: it receives frames with ID 500 and resends them as ID 501. Nothing in it sends your own identifier or your own data. The function block behind the example, CANBus_11bit, is the piece you need: create one instance per direction, call both from a task, and gate every incoming copy on the received ID and the received length. Before any of that, stop the two helper processes that share the can0 interface with the runtime, because no reading you take on that device means anything until their thread growth and load are gone. This page gives the receive gate, the transmit build, the arithmetic that tells you whether your task keeps up, and the checks that prove the exchange end to end.

What the relay example leaves out

The relay run proves three things: the bus wiring works, the bit rate matches on both ends, and reception works for ID 500. What it does not hand you is a filter and your own payload. The example's documentation describes CANBus_11bit as the function block for frames with 11-bit CAN IDs and states that an instance has to be created to send or receive messages, so the frame fields and the checks are yours to build.

A classic CAN frame carries an identifier, a data length code and up to 8 data bytes. The identifier labels the frame; it is not a channel. Your program decides which identifiers to accept and which one to send.

Symptoms and what each points to

  • The relay runs but your own ID never appears. Nothing filters on the received ID yet, or the peer sends extended format. An extended frame carries 29 identifier bits, so an 11-bit reader sees a number the sender never sent.
  • An ID arrives but the bytes look wrong, or they change while the bus is idle. The copy ran without the receive-valid indication, so the buffer held a stale or half-written frame.
  • The length reads below 8. The peer sent fewer bytes. Classic CAN carries 0 to 8 data bytes per frame and the length code reports what actually arrived, so read only that many and fix the payload size at the peer.
  • Frames dry up as the session runs on. At 1000 frames per second a slow task overruns any small receive queue, and a host adding about 1000 threads an hour while its load average sits at 770.4 misses frames before your task ever reads them.
  • Nothing arrives at all. Match the bit rate on every node and the frame format on both ends. Then measure the bus powered down: high-speed CAN terminates both ends in 120 ohm resistors, and the two in parallel read 60 ohms across CAN High and CAN Low. If the port is up and still silent, the walkthrough of a CAN interface that shows the port name yet receives no data covers the remaining cases.

Take the helper processes off the interface

Stop can0_rec and can0_send with the device's normal process management, and if they reappear, disable whatever launches them before you test anything. Then watch two readings for an hour: the thread count stays flat, and the load average returns to what the device shows when idle. Those two readings are what made this the first step.

With the load gone, find out what the runtime can actually hold. A load sweep gives you the real cycle-time limit, and the walkthrough of finding a soft PLC runtime cycle time limit with a load sweep shows the method.

Receive: check the ID and the length before you copy

Create the receive instance and call it once per cycle. Read the receive-valid indication every cycle. When it is set, compare the received ID with the ID you configured; the skeleton below uses 500, the ID your peer already puts on the bus, and compares the length with 8. Copy the eight data bytes only when both match, into variables your program owns. When either check fails, leave your copy untouched, so a frame from any other device can never overwrite live data. Record ID, length and all eight bytes together once at commissioning, so you can tell a new frame from a stale one at a glance.

The frame delivers its bytes in transmission order and nothing more. Grouping bytes into a word, choosing byte order and applying a scale are agreements you make with the peer; the frame itself settles none of that. The copy-once-per-new-frame habit is the same discipline that keeps serial reads honest, and the walkthrough of accumulating multiline serial reads into variables in CODESYS shows it for the serial port.

(* ST-style skeleton. CANBus_11bit is the block name from the vendor's
   CANBus example. Every field after the dot is a placeholder: use the
   matching field name your installed library prints for the receive-valid
   flag, the identifier, the length and the data array. *)
VAR
    canRx   : CANBus_11bit;          // receive instance
    rxId    : UINT;                  // identifier of the frame in the buffer
    rxDlc   : BYTE;                  // data length code, 0 to 8
    frameOk : BOOL := FALSE;         // TRUE only after a full match
    payload : ARRAY[0..7] OF BYTE;   // your copy of the data
    i       : INT;
END_VAR

canRx();                             // call once per cycle

IF canRx.valid THEN
    rxId    := canRx.id;
    rxDlc   := canRx.dlc;
    frameOk := (rxId = 500) AND (rxDlc = 8);
    IF frameOk THEN
        FOR i := 0 TO 7 DO
            payload[i] := canRx.data[i];
        END_FOR
    END_IF
END_IF

The bench test for the skeleton: the peer sends ID 500 with data 01 through 08 in hex, and after one cycle frameOk is TRUE and payload reads 01 to 08. The peer then sends ID 502, or ID 500 with a length of 7, and frameOk stays FALSE while payload keeps its previous values.

Example: keeping up with 1000 frames per second at 500 kbit/s

Inputs, and where each comes from:

  • Peer rate of 1000 frames per second and a bus at 500 kbit/s: the rates in the reported SocketCAN case where a receiver dropped frames.
  • Frame size: a standard 11-bit frame with 8 data bytes is about 110 bits unstuffed, up to about 130 bits with worst-case bit stuffing. The example uses the 130-bit worst case.
  • Task period of 10 ms: a common choice for frame handling and this example's own input; scale the result by your real period.

The rule in words: bit time equals one over the bit rate. Frame time equals frame bits times bit time. Frames landing between two reads equal task period over peer interval. Bus load equals frame time over peer interval.

The arithmetic:

  • Bit time: 1 ÷ 500,000 bit/s = 2 µs
  • Worst-case frame: 130 bits × 2 µs = 260 µs
  • Peer interval: 1000 ms ÷ 1000 frames = 1 ms
  • Frames per task pass: 10 ms ÷ 1 ms = 10 frames
  • Bus load: 260 µs ÷ 1000 µs = 26 %

Result: 10 frames land between two reads of a 10 ms task, so a receive queue holding fewer than 10 loses frames. Size it at 32 or read the block every cycle.

Bit rate Bit time Frame time, 130 bits Load at 1000 frames/s Verdict
500 kbit/s 2 µs 260 µs 26 % Comfortable; queue of 32 or read every cycle
250 kbit/s 4 µs 520 µs 52 % Workable; still size the queue for 10
125 kbit/s 8 µs 1040 µs 104 % Frames lost; the peer allows only 1000 µs between frames

Decision: keep this peer at 500 kbit/s, where it owns 26 % of the bus in the worst case. At 125 kbit/s one frame takes 1040 µs, longer than the 1000 µs the peer allows between frames, so frames drop no matter what your program does; the cap there is about 960 frames per second, from 1000 ÷ 1.04. Lower the peer rate or move the bus to 500 kbit/s.

Send your own frame and read the status

Fill the transmit frame with explicit values: the identifier, anywhere in the 0 to 2047 range that 11 bits allow and unused by every other device on the bus; the format flag set for standard; the length, 8; and data bytes 0 to 7. Call the transmit block once per request, from a condition you define: a cycle tick, a received frame that commands a reply, an operator action. An unconditioned call in a fast task fills the transmit queue and buries the status.

Read the status after every call. A queue-accepted status tells you the controller took the request. Where the library distinguishes a queued request from a transmitted frame, log both during commissioning. The exchange is complete when the peer reports your identifier, a length of 8 and the byte sequence you sent.

Verify the exchange end to end

  1. Incoming frame. The peer transmits ID 500, length 8, bytes 01 to 08 in hex. Every frame sets the receive-valid indication, the received ID reads 500, the length reads 8, and your copy reads 01 through 08.
  2. Wrong frame. The peer transmits ID 502, or ID 500 with length 7. The accept flag stays FALSE and your copy keeps its previous values.
  3. Outgoing frame. You request one transmit on ID 600, standard format, length 8. The peer reports ID 600, length 8 and identical bytes.
  4. Host health. The thread count holds flat for an hour and the load average is back to the device's idle figure. If a bus load reading refuses to move while the bus clearly runs, the walkthrough of a stuck CODESYS CANbus status bus load reading covers that case.

Recommendation: Stop can0_rec and can0_send now and leave them off until the thread count holds flat for an hour and the load average is back to idle. Then run CANBus_11bit in a task that cycles at 10 ms or faster, accept an incoming frame only when its ID matches your configured ID and its length reads 8, copy the eight bytes only while the receive-valid indication is set, and trigger each transmit from a defined condition with the status read after every call.

Questions

Can 11-bit and 29-bit frames share one CAN bus?

Yes. The two formats are compatible and frames of both kinds may exist on the same network. Each frame announces its own format, and a receiver set to standard format filters extended frames out. That makes mixed traffic normal and not a fault, so an unexpected identifier points at the format setting on one of the nodes first. Agree the format per node before you touch wiring or timing.

Do I need one CANBus_11bit instance or two?

The documentation for the vendor's CANBus example states that an instance of CANBus_11bit has to be created to send or receive messages. Give the receive path its own instance and the transmit path its own, and call both every cycle in the same task. That keeps the receive indication and the transmit status refreshing at the same pace as your logic, so no decision runs on a status a cycle old.

What data lengths can a classic CAN frame carry?

In classic CAN the data length code runs from 0 to 8 bytes per frame, and 8 is the largest payload a standard 11-bit frame can carry. A code below 8 simply means the peer sent fewer bytes. Accept only 8 when your application needs all eight values, never read past the received code, and fix the payload size at the sending device when a frame arrives short.

Planning information, not legal or engineering advice. Rules differ by place: check codes and permits with your local authority and your licensed trades.

Keep reading

Build your signAsk for a quote