Skip to content

실습 목표#


  • CAN 채널을 올리고 can0, can1 사이에서 프레임을 정상적으로 주고받는다.
  • CAN FD의 설정값과 DLC 길이 규칙을 직접 확인한다.
  • Classical CAN과 CAN FD 혼용, Bus-Off, 송신 큐 포화 등 예외 상황을 재현하고 확인한다.
  • 전송 간격과 송신 큐 길이가 버스 부하율과 통신 지연에 미치는 영향을 확인한다.

실습 전 준비. CAN 인터페이스 확인#


  • 리눅스에서는 CAN 채널도 네트워크 인터페이스로 다룬다.
  • 먼저 can0, can1 인터페이스가 정상적으로 생성되어 있는지 확인한다.
라즈베리파이·터미널
ls /sys/class/net/

CAN인터페이스확인

  • 문제가 생기면 인터페이스 목록, 커널 인식 기록, 현재 상태 순서로 확인한다.
라즈베리파이·터미널
ls /sys/class/net/
dmesg | grep -i mcp
ip -br link | grep can

CAN FD 채널 설정#

  • bitrate는 중재 구간의 속도, dbitrate는 데이터 구간의 속도이다.
  • fd on을 사용하면 CAN FD를 활성화한다.
  • restart-ms 0이면 Bus-Off 이후 자동 복구하지 않고 사용자가 직접 다시 올려야 한다.
라즈베리파이·터미널
sudo ip link set can0 down
sudo ip link set can1 down
sudo ip link set can0 up type can bitrate 500000 dbitrate 2000000 fd on restart-ms 0
sudo ip link set can1 up type can bitrate 500000 dbitrate 2000000 fd on restart-ms 0
  • 이후에는 긴 설정 명령 대신 준비된 스크립트를 사용할 수 있다.
라즈베리파이·터미널
~/precheck.sh
~/canup.sh
  • ~/precheck.sh에서는 아래 값을 확인한다.
확인할 값
mtu 72
can <FD,TDC-AUTO>
state ERROR-ACTIVE
bitrate 500000
dbitrate 2000000

cansend 명령 형식 확인#

라즈베리파이·터미널
cansend --help
주요 프레임 형식
<can_id>#{data} Classical CAN 2.0
<can_id>#R{len} Classical CAN 2.0 (RTR)
<can_id>#{data}_{dlc} Classical CAN 2.0 (Raw DLC)
<can_id>##<flags>{data} CAN FD
  • # 한 개는 Classical CAN, ## 두 개는 CAN FD이다.
  • CAN FD에서 ## 뒤 첫 한 자리는 플래그 값이며, 이 실습에서는 1이면 BRS를 켠다.
  • Classical CAN은 최대 8바이트, CAN FD는 최대 64바이트까지 데이터를 보낼 수 있다.

시범. CAN 채널 송수신 확인#

  • can1은 수신 대기, can0은 프레임 송신에 사용한다.
터미널 1·관찰
candump can1
터미널 2·송신
cansend can0 123#DEADBEEF

실습 1. 반대 방향으로 보내기#


  • 이번에는 can1에서 can0으로 프레임을 보낸다.
  • 양방향 통신이 모두 되어야 이후 진단 요청과 응답이 성립한다.
터미널 1·관찰
candump can0
터미널 2·송신
cansend can1 456#DEADBEEF

실습1 결과사진

관찰 포인트

can0 관찰 창에 ID 456과 데이터 DE AD BE EF가 정상적으로 표시되는지 확인

실습 2. 설정 값 확인#


  • ip -details 명령으로 CAN 인터페이스의 상세 설정값을 확인한다.
  • 중재 구간과 데이터 구간의 속도가 어디에 표시되는지 직접 찾는다.
라즈베리파이·터미널
ip -details link show can0

실습2 결과사진

실습 2 결과 : 설정 값이 말하는 것#

  • 실습 환경에서 확인되는 기준 값은 아래와 같다.
항목
bitrate 500000 중재 구간의 속도. ID와 제어 비트가 이 속도로 지나감
dbitrate 2000000 데이터 구간의 속도. BRS가 켜진 프레임만 이 속도가 됨
sample-point 0.875 한 비트 안에서 값을 읽는 지점
mtu 72 커널이 프레임 하나에 쓰는 바이트. 72면 CAN FD, 16이면 Classical CAN
clock 40000000 HAT 오실레이터 40 MHz
state ERROR-ACTIVE 오류가 쌓이지 않은 정상 상태
berr tx / rx 0 / 0 송신·수신 에러 카운터
restart-ms 0 Bus-Off 이후 자동 복구하지 않음

관찰 포인트

뒤의 Bus-Off 실습에서 state, berr-counter tx/rx, restart-ms 값을 다시 확인

실습 3. 직접 프레임 만들어 보내기#


  • cansend --help에서 확인한 형식을 이용해 Classical CAN과 CAN FD 프레임을 직접 만든다.
  • 형식이 틀리면 프레임이 송신되지 않고 명령 실행 단계에서 오류가 발생한다.
터미널 1·관찰
candump can1
터미널 2·도움말 예시
cansend can0 123#DEADBEEF
cansend can0 456##0DEADBEEF
cansend can0 456##1DEADBEEF

실습3 결과사진

  • 첫 번째는 Classical CAN 4바이트이다.
  • 두 번째는 CAN FD, 플래그 0, BRS OFF이다.
  • 세 번째는 CAN FD, 플래그 1, BRS ON이다.

관찰 포인트

candump에 ID, 데이터 길이, BRS 여부가 의도한 대로 표시되는지 확인

실습 4. DLC 경계 확인#


  • CAN FD의 DLC는 모든 바이트 길이를 직접 표현하지 않는다.
  • 9, 10, 12, 15바이트를 각각 보내고 실제로 몇 바이트 길이로 전송되는지 확인한다.
  • ## 뒤 첫 자리는 CAN FD 플래그이며, 여기서는 1이 BRS 활성화를 의미한다.
터미널 2·송신
cansend can0 111##1001122334455667788
cansend can0 222##100112233445566778899
cansend can0 444##100112233445566778899AABB
cansend can0 333##100112233445566778899AABBCCDDEE

실습4 결과사진

실습 4 결과 : 패딩과 길이 경계#

  • CAN FD에서 지원하는 데이터 길이는 0~8, 12, 16, 20, 24, 32, 48, 64바이트이다.
  • 요청한 길이가 중간값이면 요청 길이 이상인 다음 CAN FD 지원 길이로 전송된다.
  • 남는 공간은 padding으로 채워진다.
길이 변환 예
9바이트  -> 12바이트
10바이트 -> 12바이트
15바이트 -> 16바이트
  • 수신 측은 찍힌 길이만 보고 원래 몇 바이트였는지 알 수 없다.
  • 실제 데이터 길이는 상위 계층이 따로 알려 주어야 한다.

실습 5. Classical CAN의 Raw DLC 확인#


  • Classical CAN은 실제 데이터 길이가 최대 8바이트이지만 DLC 필드에는 9~15 값도 기록할 수 있다.
  • Raw DLC 9~15 값을 유지하려면 cc-len8-dlc on을 활성화한다.
  • 8바이트 데이터를 전송하면서 Raw DLC 값을 0xB(11)로 지정한다.
라즈베리파이·양쪽을 Classical CAN으로 설정
sudo ip link set can0 down
sudo ip link set can1 down
sudo ip link set can0 up type can bitrate 500000 fd off cc-len8-dlc on restart-ms 0
sudo ip link set can1 up type can bitrate 500000 fd off cc-len8-dlc on restart-ms 0
터미널 1·관찰
candump -8 can1
터미널 2·송신
cansend can0 444#1122334455667788_B

실습5 결과사진

관찰 포인트

candump -8 출력에서 실제 데이터는 8바이트이지만 {B}가 표시되는지 확인. {B}는 Raw DLC 0xB(11)을 의미함

실습 5 결과 : 같은 네 비트, 다른 뜻#

DLC 비트 Classical CAN CAN FD
1000 8바이트 8바이트
1001 8바이트 12바이트
1011 8바이트 20바이트
1111 8바이트 64바이트
  • 동일한 DLC 네 비트라도 Classical CAN과 CAN FD에서 의미가 다르다.
  • 두 형식을 구분하는 것은 FDF 비트이다.

실습 6. Classical CAN과 CAN FD 혼용 시 동작 확인#


  • can0은 CAN FD 모드, can1은 Classical CAN 모드로 설정한다.
  • can0에서 Classical CAN 프레임과 CAN FD 프레임을 각각 송신한다.
  • 각 프레임의 수신 여부와 can0의 상태 변화를 확인한다.
라즈베리파이·채널 설정
sudo ip link set can0 down
sudo ip link set can1 down
sudo ip link set can0 up type can bitrate 500000 dbitrate 2000000 fd on restart-ms 0
sudo ip link set can1 up type can bitrate 500000 fd off restart-ms 0
수신 터미널
candump can1
송신 터미널
cansend can0 123#DEADBEEF
cansend can0 123##1112233445566778899AABBCC

실습6 결과사진

실습 6 결과 : 수신 실패 이유#

  • Classical CAN 프레임은 정상적으로 수신된다.
  • CAN FD 프레임은 Classical CAN 노드가 FDF 이후의 구성을 정상적으로 해석하지 못해 수신에 실패한다.
  • 해석 실패는 오류 알림으로 이어지고 송신 측은 재전송을 시도한다.
  • 반복 재전송 과정에서 에러 카운터가 증가하며 Bus-Off 상태로 이어질 수 있다.
실습 종료 후 상태 확인
~/precheck.sh
PPT의 실습 예시
can0 : tx 256 / rx 0  -> BUS-OFF
can1 : tx 0 / rx 16   -> ERROR-ACTIVE

실습 7. CAN Bus-Off 상태 재현 및 확인#


  • can0, can1을 모두 되살린 뒤 can0은 CAN FD, can1은 Classical CAN으로 설정한다.
  • CAN FD 프레임 한 개를 보내고 candump의 오류 프레임으로 상태 변화를 확인한다.
준비·양쪽 인터페이스 되살리기
~/canup.sh
sudo ip link set can1 down
sudo ip link set can1 up type can bitrate 500000 fd off
터미널 1·오류 프레임만 관찰
candump -e -td can0,0~0,'#FFFFFFFF'
터미널 2·CAN FD 프레임 한 개 송신
cansend can0 123##1112233445566778899AABBCC
  • 오류 프레임의 8바이트 중 이번 실습에서는 data[1]data[6]을 확인한다.
  • data[1]은 컨트롤러 상태, data[6]은 송신 에러 카운터이다.

실습7 결과사진

실습 7 결과 : 로그에서 찾은 세 상태#

candump -e -td 출력 예시
Error class 0x204 is invalid
(000.000000) can0 20000204 [8] 00 08 00 00 00 00 68 00 ERRORFRAME
Error class 0x204 is invalid
(000.000506) can0 20000204 [8] 00 20 00 00 00 00 80 00 ERRORFRAME
(004.847749) can0 20000040 [8] 00 00 00 00 00 00 00 00 ERRORFRAME bus-off
data[1]
0x04 수신 경고
0x08 송신 경고
0x10 수신 소극
0x20 송신 소극
예시 로그 해석
1번 : data[1] = 08, data[6] = 0x68 = 104 -> 송신 경고
2번 : data[1] = 20, data[6] = 0x80 = 128 -> 송신 소극
3번 : bus-off
  • 세 번째 Bus-Off 프레임은 데이터가 모두 0이다.
  • 첫 번째와 두 번째 상태 변화 사이 간격은 약 500 µs 수준이며 Bus-Off까지의 시간은 측정마다 달라질 수 있다.

실습 7 결과 : Bus-Off 복구 방식#

  • 송신 에러 카운터가 256에 도달하면 노드는 Bus-Off 상태로 전환된다.
  • restart-ms 설정값에 따라 Bus-Off 이후 복구 방식이 달라진다.
설정 동작
restart-ms 0 Bus-Off 상태 유지. 사용자가 직접 인터페이스를 다시 올려야 함
restart-ms 100 약 0.1초 뒤 자동 복구 시도
  • 오류 원인이 남아 있으면 자동 복구 후 다시 Bus-Off가 반복될 수 있다.

실습 8. Bus-Off 상태에서 송신 결과 확인#


  • Bus-Off 상태에서 프레임 송신을 시도하고 명령 실행 결과를 확인한다.
  • cansend가 정상 종료되더라도 실제 프레임 전송 여부는 별도로 확인한다.
터미널 2
cansend can0 123#DEADBEEF
ip -statistics link show can0 | tail -3

실습8 결과사진

관찰 포인트

송신 전후의 TX packetsTX dropped 값을 비교. 보내기 전에 dropped 값을 먼저 적어 둘 것

실습 8 결과 : 조용히 실패하는 송신#

  • Bus-Off 상태에서는 cansend가 오류 메시지 없이 끝날 수 있다.
  • 하지만 실제 프레임은 버스로 나가지 않는다.
  • 이 경우 TX packets는 그대로이고 TX dropped만 증가한다.
PPT의 실제 출력 예
$ cansend can0 123#DEADBEEF
$ ip -statistics link show can0 | tail -3
96 14 0 0 0 0
TX: bytes packets errors dropped carrier collsns
96 14 0 15 0 0
단계 어떻게 됐나
소켓 write() 성공. 그래서 cansend가 조용히 끝남
송신 큐 통과
드라이버 Bus-Off 상태이므로 버림. TX dropped 증가
실제 버스 아무것도 나가지 않음
  • 명령의 반환값만으로 실제 전송 성공 여부를 판단하면 안 된다.

다음 실습 준비#

  • can0, can1을 Classical CAN 모드로 다시 설정한다.
라즈베리파이·터미널
sudo ip link set can0 down
sudo ip link set can1 down
sudo ip link set can0 up type can bitrate 500000 fd off restart-ms 0
sudo ip link set can1 up type can bitrate 500000 fd off restart-ms 0

실습 9. 전송 주기에 따른 CAN 버스 부하 측정#


  • cangen-g 옵션으로 프레임 사이 전송 간격을 바꾸고 canbusload로 버스 부하율을 확인한다.
  • -g 값의 단위는 ms이다.
  • 100 → 10 → 1 → 0 순서로 전송 간격을 줄이며 부하율 변화를 관찰한다.
터미널 1·부하 측정
canbusload can0@500000 -r -t -b -c
터미널 2·부하 주입
cangen can0 -g 100
cangen can0 -g 10
cangen can0 -g 1
cangen can0 -g 0
  • 각 명령은 측정 후 Ctrl+C로 중단하고 다음 조건으로 넘어간다.

실습9-1 결과사진 실습9-2 결과사진 실습9-3 결과사진 실습9-4 결과사진

실습 9 결과 : 전송 간격과 부하 변화#

  • 전송 간격이 짧아질수록 버스 부하율이 증가한다.
  • -g 0에서는 프레임을 가능한 한 빠르게 생성하므로 송신 큐가 포화될 수 있다.
  • 송신 큐가 가득 차면 아래 오류가 발생할 수 있다.
오류 예
No buffer space available
  • -g 0에서 발생하는 오류는 단순히 높은 버스 부하율만으로 설명하기 어렵다.
  • 송신 큐의 처리 한계도 함께 고려해야 한다.

실습 10. 송신 큐 길이에 따른 동작 확인#


  • 송신 큐는 전송 대기 중인 프레임을 임시로 저장하는 공간이다.
  • 현재 qlen을 확인한 뒤 송신 큐 길이를 1000으로 늘리고 동일한 cangen -g 0 조건에서 다시 시험한다.
터미널 2
ip -details link show can0 | head -1
sudo ip link set can0 txqueuelen 1000
cangen can0 -g 0

실습10 결과사진

관찰 포인트

No buffer space available 오류가 줄어들거나 사라지는지 확인하고 실습 9와 버스 부하율을 비교

실습 10 결과 : 큐 길이와 전송 지연#

  • 송신 큐를 늘리면 순간적으로 몰린 프레임을 더 많이 대기시킬 수 있다.
  • 따라서 송신 버퍼 부족으로 인한 오류 발생 가능성을 줄일 수 있다.
  • 하지만 CAN 버스 자체의 bitrate는 그대로이므로 실제 전송 속도가 빨라지는 것은 아니다.
  • 큐 뒤쪽에 쌓인 프레임은 더 오래 기다려야 하므로 전송 지연이 증가할 수 있다.
큐 길이 설정의 의미
큐가 너무 작음 ->  포화  송신 오류 발생 가능
큐가 너무  ->  많은 프레임 대기 가능, 전송 지연 증가 가능
적정값 -> 오류와 지연을 함께 고려하여 선택

정리#


  • 송신 명령이 오류 없이 끝나도 실제 CAN 프레임이 버스로 나갔다는 뜻은 아니다.
  • Bus-Off와 송신 큐 포화는 모두 프레임이 나가지 않지만 나타나는 현상이 다르다.
항목 Bus-Off 송신 큐 포화
명령 결과 조용히 성공할 수 있음 No buffer space available
TX dropped 증가 증가하지 않음
어디서 막혔나 큐를 지나 드라이버에서 버려짐 송신 큐에 들어가지 못함
실제 프레임 나가지 않음 나가지 않음
  • 인터페이스를 다시 올려도 일부 설정이 남아 있을 수 있으므로 실습 사이 설정 상태를 확인한다.
  • 특히 실습 5에서 사용한 cc-len8-dlc 설정이 이후에도 남아 있을 수 있다.
마지막 송신 통계 확인
ip -statistics link show can0 | tail -3