Hardware: i.MX8M Plus EVK
Kernel: [Your kernel version - check with uname -r]
Interface: FlexCAN (can0/can1)
Issue Summary: CAN FD socket configuration fails in C code with EINVAL (errno 22) but identical operation succeeds in Python on the same system.
Problem Details:
Interface properly configured with CAN FD support:
ip link set can0 up type can bitrate 500000 dbitrate 2000000 fd on ip -details link show can0 # Shows <FD> flag and dbitrate parameters
Python succeeds:
import socket sock = socket.socket(socket.PF_CAN, socket.SOCK_RAW, socket.CAN_RAW) sock.setsockopt(101, 5, 1) # SOL_CAN_RAW, CAN_RAW_FD_FRAMES - SUCCESS
C code fails with identical parameters:
int sock = socket(PF_CAN, SOCK_RAW, CAN_RAW); int enable = 1; setsockopt(sock, SOL_CAN_RAW, CAN_RAW_FD_FRAMES, &enable, sizeof(enable)); // Returns -1, errno = 22 (EINVAL)
Debugging Performed:
Question: Is there a known issue with FlexCAN CAN FD socket configuration in C applications on i.MX8M Plus? Are there specific compilation flags, kernel modules, or driver configurations required for C programs to enable CAN FD frames via setsockopt()?
System Info:
can0: <FD> state ERROR-ACTIVE (berr-counter tx 0 rx 0) bitrate 500000 sample-point 0.875 dbitrate 2000000 dsample-point 0.750 flexcan: dtseg1 2..39 dtseg2 2..8 dsjw 1..4 dbrp 1..1024
Any insights or recommendations would be greatly appreciated.
Additional Context: This is for a Power Distribution Unit (PDU) firmware project requiring CAN FD with BRS (Bit Rate Switching) for high-speed data transmission (225 frames every 500ms).
Thanks for your support!
Hi
CAN-FD is not supported on the consumer version of i.MX 8M Plus, it is only available on the Industrial version.
Unfortunately on the 8MP EVK, the consumer version is installed, so i.MX 8M Plus EVK not support CAN-FD feature.
Regards
Daniel
Hi,
Actually i think we are having industrial version of i.MX 8M Plus we have checked via pyhton script we can see canfd frames in candump can0 command .
But when i use my c program to open a socket and enable canfd frames it's not happening and receiving error code 22.
Currently i am using :
what is the version number of your board? can you send me the scripts you are using for me to reproduce this issue on my side? if there is a bug, I will report it to our software team. Thanks.
Hi,
We are using MIMX8ML4CVNKZAB part.
I have attached python script with the query.
This is the C-program configurations :
socket(PF_CAN, SOCK_RAW , CAN_RAW);
#!/usr/bin/env python3
"""
CAN FD Listener Script for i.MX8
Opens socket and listens for CAN FD frames on can0
Similar to your PDU firmware's receive thread functionality
"""
import socket
import struct
import time
import signal
import sys
import os
from datetime import datetime
# CAN constants
SOL_CAN_RAW = 101
CAN_RAW_FD_FRAMES = 5
CAN_RAW_FILTER = 1
# CAN frame flags
CAN_EFF_FLAG = 0x80000000 # Extended frame format
CAN_RTR_FLAG = 0x40000000 # Remote transmission request
CAN_ERR_FLAG = 0x20000000 # Error frame
# CAN FD flags
CANFD_BRS = 0x01 # Bit Rate Switch
CANFD_ESI = 0x02 # Error State Indicator
CANFD_FDF = 0x04 # FD Format indicator
class CANFDListener:
"""CAN FD frame listener - similar to your PDU receive thread"""
def __init__(self, interface="can0", bitrate=500000, data_bitrate=2000000):
self.interface = interface
self.bitrate = bitrate
self.data_bitrate = data_bitrate
self.socket = None
self.running = False
self.frame_count = 0
self.start_time = None
# Statistics
self.can20_frames = 0
self.canfd_frames = 0
self.error_frames = 0
def setup_interface(self):
"""Configure CAN interface - like your PDU initialization"""
print(f"🔧 Setting up {self.interface}...")
try:
# Bring interface down
os.system(f"ip link set {self.interface} down 2>/dev/null")
# Configure with CAN FD support
cmd = (f"ip link set {self.interface} up type can "
f"bitrate {self.bitrate} "
f"dbitrate {self.data_bitrate} "
f"fd on")
print(f"📠Running: {cmd}")
result = os.system(cmd)
if result != 0:
print(f"⌠Failed to configure {self.interface}")
return False
# Verify interface is UP
time.sleep(0.5)
status = os.popen(f"ip link show {self.interface}").read()
if "state UP" in status:
print(f"✅ {self.interface} configured successfully")
print(f" Arbitration bitrate: {self.bitrate}")
print(f" Data bitrate: {self.data_bitrate}")
return True
else:
print(f"⌠{self.interface} failed to come UP")
return False
except Exception as e:
print(f"⌠Interface setup error: {e}")
return False
def create_socket(self):
"""Create and configure CAN FD socket - like your create_canfd_socket()"""
print(f"🔌 Creating CAN FD socket...")
try:
# Create CAN socket
self.socket = socket.socket(socket.PF_CAN, socket.SOCK_RAW, socket.CAN_RAW)
print("✅ CAN socket created")
# Enable CAN FD frames
self.socket.setsockopt(SOL_CAN_RAW, CAN_RAW_FD_FRAMES, 1)
print("✅ CAN FD frames enabled")
# Bind to interface
self.socket.bind((self.interface,))
print(f"✅ Socket bound to {self.interface}")
return True
except OSError as e:
if e.errno == 22: # EINVAL
print("⌠CAN FD not supported on this interface")
elif e.errno == 100: # ENETDOWN
print("⌠Network interface is down")
else:
print(f"⌠Socket error: {e}")
return False
except Exception as e:
print(f"⌠Unexpected error: {e}")
return False
def set_filters(self, filters=None):
"""Set CAN filters - like your set_can_filters()"""
if not filters:
print("📡 No filters set - will receive ALL CAN frames")
return True
try:
# Convert filters to binary format
filter_data = b''
for can_id, mask in filters:
filter_data += struct.pack("II", can_id, mask)
self.socket.setsockopt(SOL_CAN_RAW, CAN_RAW_FILTER, filter_data)
print(f"✅ Set {len(filters)} CAN filters")
for can_id, mask in filters:
print(f" Filter: ID=0x{can_id:03X}, Mask=0x{mask:03X}")
return True
except Exception as e:
print(f"⌠Failed to set filters: {e}")
return False
def parse_frame(self, frame_data):
"""Parse received CAN FD frame - like your process_pdc3_can_frame()"""
try:
# Unpack frame header (first 8 bytes)
can_id, dlc, flags, res0, res1 = struct.unpack("<IBBBB", frame_data[:8])
# Extract data (up to 64 bytes)
data = frame_data[8:8+dlc] if dlc > 0 else b''
# Determine frame type
is_extended = bool(can_id & CAN_EFF_FLAG)
is_rtr = bool(can_id & CAN_RTR_FLAG)
is_error = bool(can_id & CAN_ERR_FLAG)
# Clean CAN ID (remove flags)
clean_id = can_id & 0x1FFFFFFF if is_extended else can_id & 0x7FF
# CAN FD specific flags
is_fd = bool(flags & CANFD_FDF)
has_brs = bool(flags & CANFD_BRS)
has_esi = bool(flags & CANFD_ESI)
return {
'can_id': clean_id,
'dlc': dlc,
'data': data,
'is_extended': is_extended,
'is_rtr': is_rtr,
'is_error': is_error,
'is_fd': is_fd,
'has_brs': has_brs,
'has_esi': has_esi,
'raw_id': can_id,
'flags': flags
}
except Exception as e:
print(f"⌠Frame parsing error: {e}")
return None
def format_frame_output(self, frame):
"""Format frame for display - educational output"""
timestamp = datetime.now().strftime("%H:%M:%S.%f")[:-3]
# Frame type
frame_type = "CAN-FD" if frame['is_fd'] else "CAN2.0"
if frame['is_error']:
frame_type = "ERROR"
elif frame['is_rtr']:
frame_type += "-RTR"
# ID format
id_format = "EXT" if frame['is_extended'] else "STD"
# Flags
flags = []
if frame['is_fd']:
flags.append("FD")
if frame['has_brs']:
flags.append("BRS")
if frame['has_esi']:
flags.append("ESI")
flag_str = f"[{','.join(flags)}]" if flags else ""
# Data formatting
data_hex = frame['data'].hex().upper()
data_ascii = ''.join(chr(b) if 32 <= b < 127 else '.' for b in frame['data'])
# Build output line
output = f"{timestamp} {self.interface} {frame_type:>7} {id_format} "
output += f"0x{frame['can_id']:03X} [{frame['dlc']:2d}] "
output += f"{data_hex:<32} {flag_str:<12} '{data_ascii}'"
return output
def listen(self, max_frames=None, timeout=None):
"""Main listening loop - like your receive thread"""
print(f"\n🎧 Starting CAN FD listener on {self.interface}...")
print("📊 Frame format: TIMESTAMP INTERFACE TYPE FORMAT ID [DLC] DATA FLAGS 'ASCII'")
print("-" * 100)
self.running = True
self.start_time = time.time()
try:
while self.running:
# Set socket timeout if specified
if timeout:
self.socket.settimeout(timeout)
try:
# Receive frame (like your read() in receive thread)
frame_data = self.socket.recv(72) # CAN FD frame size
if len(frame_data) < 8:
print(f"âš ï¸ Incomplete frame received: {len(frame_data)} bytes")
continue
# Parse frame
frame = self.parse_frame(frame_data)
if not frame:
continue
# Update statistics
self.frame_count += 1
if frame['is_fd']:
self.canfd_frames += 1
elif frame['is_error']:
self.error_frames += 1
else:
self.can20_frames += 1
# Display frame
print(self.format_frame_output(frame))
# Check max frames limit
if max_frames and self.frame_count >= max_frames:
print(f"\n✅ Received {max_frames} frames, stopping...")
break
except socket.timeout:
print(f"\nâ° Timeout: No frames received for {timeout} seconds")
break
except KeyboardInterrupt:
print(f"\n\n🛑 Stopped by user")
break
except Exception as e:
print(f"\n⌠Receive error: {e}")
break
finally:
self.running = False
self.print_statistics()
def print_statistics(self):
"""Print reception statistics"""
if self.start_time:
duration = time.time() - self.start_time
rate = self.frame_count / duration if duration > 0 else 0
print("\n" + "=" * 60)
print("📊 RECEPTION STATISTICS")
print("=" * 60)
print(f"Duration: {duration:.1f} seconds")
print(f"Total frames: {self.frame_count}")
print(f"CAN 2.0 frames: {self.can20_frames}")
print(f"CAN FD frames: {self.canfd_frames}")
print(f"Error frames: {self.error_frames}")
print(f"Average rate: {rate:.1f} frames/second")
print("=" * 60)
def close(self):
"""Cleanup socket"""
self.running = False
if self.socket:
self.socket.close()
self.socket = None
print(f"✅ Socket closed")
def signal_handler(sig, frame):
"""Handle Ctrl+C gracefully"""
print("\n\n🛑 Shutting down...")
sys.exit(0)
def main():
import argparse
parser = argparse.ArgumentParser(description='CAN FD Listener for i.MX8')
parser.add_argument('-i', '--interface', default='can0',
help='CAN interface (default: can0)')
parser.add_argument('-b', '--bitrate', type=int, default=500000,
help='Arbitration bitrate (default: 500000)')
parser.add_argument('-d', '--dbitrate', type=int, default=2000000,
help='Data bitrate (default: 2000000)')
parser.add_argument('-n', '--count', type=int,
help='Stop after N frames')
parser.add_argument('-t', '--timeout', type=int,
help='Timeout in seconds')
parser.add_argument('--filter', action='append', nargs=2, metavar=('ID', 'MASK'),
help='Add CAN filter: ID MASK (can use multiple times)')
parser.add_argument('--no-setup', action='store_true',
help='Skip interface configuration')
args = parser.parse_args()
# Check if running as root
if not args.no_setup and os.geteuid() != 0:
print("⌠Run as root to configure CAN interface")
print(" Or use --no-setup if interface is already configured")
sys.exit(1)
# Setup signal handler
signal.signal(signal.SIGINT, signal_handler)
# Create listener
listener = CANFDListener(args.interface, args.bitrate, args.dbitrate)
try:
# Setup interface
if not args.no_setup:
if not listener.setup_interface():
sys.exit(1)
# Create socket
if not listener.create_socket():
sys.exit(1)
# Setup filters if specified
if args.filter:
filters = []
for id_str, mask_str in args.filter:
can_id = int(id_str, 0) # Auto-detect hex/decimal
mask = int(mask_str, 0)
filters.append((can_id, mask))
listener.set_filters(filters)
# Start listening
listener.listen(max_frames=args.count, timeout=args.timeout)
except Exception as e:
print(f"⌠Error: {e}")
sys.exit(1)
finally:
listener.close()
if __name__ == "__main__":
main()
CAN FD is supported in imx8mp can driver, but I have difficulty to test this feature with 8MP EVK board.
Now I am using imx93 EVK to test this feature, since i.mx93 and i.mx8mp share the same driver. The python script works for i.MX93 EVK. Do you have C script for CAN FD ?
Regards
Daniel
I tried the setsockopt function (C-program) on i.MX 8MP evk in my side, CAN FD socket configuration succeeds without errors.
Regards
Daniel