본문 바로가기

CAN

3. 초기 설정 (1) CAN_BTR (CAN bit timing register)

CAN 프로토콜도 다른 통신 프로토콜과 마찬가지로 여러가지 전송 옵션을 규정하고 있습니다. 따라서 CAN 컨트롤러가 송수신을 시작하기 전에 어떻게 송수신할 지 미리 설정해 두어야 합니다.

 

전송 옵션은 CAN_MCR과 CAN_BTR에서 설정할 수 있습니다. 이 두 레지스터에 대한 설명은 CAN 레퍼런스 매뉴얼에 나와있지만 좀 더 전체적인 관점에서 이해할 수 있도록 레지스터의 비트필드의 기능을 간단히 설명한 다음에 CAN 프로토콜, 제가 알고있는 것을 약간 섞어서 다시 설명해 보겠습니다.

can btr register mcr field

  • BRP (Baud rate prescaler)
    : CAN 컨트롤러에 공급되는 PCLK를 분주하여 타임 퀀텀 주기를 설정합니다.
  • TS1/2 (Time segment 1/2)
    비트 세그먼트1/2에 배정할 타임 퀀텀의 개수를 정의합니다. 즉, 비트 세그먼트1/2의 주기를 결정합니다.
  • SJW (Resynchronization jump width)
    : CAN 컨트롤러는 비트 세그먼트1의 주기를 늘리고 비트 세그먼트2의 길이를 줄이는 방식으로 재동기화를 수행하는데, 이때 늘리고 줄일 시간의 길이를 타임 퀀텀 단위로 정의하는 필드입니다.
※ 참고로 주기는 시간과 동일한 의미로 이해하면 됩니다.
 
주의할 것은 타임 퀀텀이 버스상 1비트의 주기가 아니라는 것입니다. 이것은 CAN 통신이 비동기식 통신이기 때문에 네트워크 안에서 각 노드가 개별적으로 동기를 맞춰 나가는 과정과 관련있습니다. CAN 컨트롤러는 버스상 1비트를 4개의 세그먼트로 구성하고, 다시 그 세그먼트를 몇 개의 타임 퀀텀으로 구성합니다. 하지만 타임 퀀텀은 CAN 컨트롤러 내부에서 연산되기 때문에 오실로스코프로 관찰할 수 없습니다. 타임 퀀텀은 BRP에 의해 결정되는 가장 작은 시간 단위로 TS1과 TS2를 사용하여 세그먼트에 타임 퀀텀이 몇 개를 배정하느냐에 따라 각 세그먼트의 주기가 달라지고, 나아가 전체 1비트의 주기가 달라집니다. 즉, 동일한 프리스칼라를 설정해도 각 세그먼트에 배정된 타임 퀀텀의 개수에 따라 1비트의 주기가 달라질 수 있다는 의미입니다. CAN 버스상의 각 노드는 서로 다른 길이의 타임 퀀텀을 가질 수는 있지만, 타임 퀀텀으로 구성되는 1비트의 주기는 모든 노드가 같아야 합니다. 즉, CAN 버스상의 모든 노드의 전송 속도는 동일해야 합니다.
 
4개의 세그먼트는 다음과 같습니다.
  • SYNC_SEG
    : 각 비트의 하강 엣지가 이 SYNC_SEG 안에 들어 있는지의 여부로 동기를 판정합니다. (무조건 1 타임 퀀텀, 설정 불가, 나머지 세그먼트는 설정 가능)
  • PROP_SEG
    : 네트워크의 물리적 지연시간을 보정하기 위해 사용됩니다. 1~8 타임 퀀텀
  • PHASE_SEG 1
    : 위상 오류(위상차)를 보정하기 위해 사용됩니다. (1~8 타임 퀀텀)
  • PHASE_SEG 2
    : 위상 오류(위상차)를 보정하기 위해 사용됩니다. (PHASE_SEG 1의 최대값(8) + 정보처리시간(<= 2타임 퀀텀))
※ STM32에서는 PROP_SEG와 PHASE_SEG 1을 합쳐서 비트 세그먼트 1로 정의합니다.
 
※ STM32에서는 PHASE_SEG 2는 비트 세그먼트 2로 정의합니다.
 
※ 위에 있는 타임 퀀텀의 범위는 각 세그먼트에 대한 가능한 타임 퀀텀입니다. 하지만 두개의 보드에서 동일한 설정을 해도 트랜시버에 따라 어떤 보드는 송신을 하고 어떤 보드는 송신을 못해서 어떻게 정해야 하는지는 잘 모르겠습니다. 그리고 STM32는 PROP_SEG 세그먼트와 PHASE_SEG 1 세그먼트가 비트 세그먼트 1로 정의하고 사용하는데 이 비트 세그먼트의 비트를 조절할 때 PROP_SEG 세그먼트와 PHASE_SEG 1 세그먼트의 비율이 어떻게 되는지도 잘 모르겠습니다..
 

제가 사용한 설정은 48MHz MCU 속도에서 아래 두개 입니다.

프리스칼라 

 1024

 2

 BS1

 3

 15

 BS2

 5

 8

 SJW

 1

 1

 비트타임/속도

 192000ns/5208bps

 1000ns/1Mbps

 

※ 저는 위상이라는 개념을 어떤 동일한 신호에 대해 어떤 개체가 인식하는 신호의 발생 시점이라고 이해하고 있습니다. 따라서 위상차란 두개 이상의 개체가 인식하는 어떤 신호의 시작 시점의 차이라고 알고 있습니다. 여기서 개체는 회로에서 어떤 부품이 될 수도 있고, 회로에서의 어떤 위치도 될 수 있습니다. 만약 틀렸다면 지적 부탁드립니다.

 

※ 그리고 주의할 점은 1비트는 어떤 세그먼트를 길게하든 짧게하든 최소 8타임 퀀텀에서 최대 25타임 퀀텀으로 구성되어야 합니다. 처음에 뭣도모르고 PHASE_SEG1/2를 1타임 퀀텀으로 해서 테스트해봤는데 통신이 되지 않았습니다. 타임 퀀텀과 세그먼트는 오실로스코프로 관찰할 수 없었지만, PHASE_SEG1/2를 1타임 퀀텀으로 설정하여 1비트가 3타임 퀀텀인 상태에서 위상차가 발생하면 SJW(최소 1타임 퀀텀)만큼 늘리거나 줄이게 되는데, 최소값인 1타임 퀀텀 조차도 3타임 퀀텀에 비해 너무 길어서 그런게 아닌가 추측해봅니다. 즉, 오차를 조정했는데 너무 많이 조정해서 또 다른 오차가 발생하게 되는 것입니다.

 

STM32 CAN 컨트롤러에서 세그먼트들은 1비트에서 다음과 같이 할당됩니다.

can rx tx dominent bit segment sync_seg time

CAN RX를 사용한 이유는 앞서 설명했듯이 CAN TX에 따라 달라지는 CAN Low, CAN High 신호가 AND 게이트를 거쳐 CAN 컨트롤러와 연결된 CAN RX로 출력되면, CAN 컨트롤러가 이 신호로 버스의 상태를 모니터링하기 때문입니다. 위의 예에서 RXD는 Logic High 1비트를 출력한 후 Logic Low로 전환하고 있습니다. CAN 컨트롤러는 CAN RX 기준으로 하강 엣지(리세시브->도미넌트)가 SYNC_SEG 안에 있는지의 여부로 동기를 판정합니다. ‘전송’ 파트에서 자세히 설명하겠지만, 버스상의 어떤 노드도 신호를 보내고 있지 않은 상태(리세시브)에서 어떤 노드가 데이터 프레임을 전송하면 전송을 시작한다는 의미로 SOF 신호를 보내게 되는데 이 SOF 신호는 도미넌트 신호 입니다. 이때 CAN RX에서 하강 엣지를 탐지하게 되고 버스상의 모든 노드는 SOF 신호에 SYNC_SEG를 맞춥니다. 이때는 버스상의 모든 노드가 동기화된 상태입니다. (참고로 버스 프리 상태에서는 비트를 세그먼트로 나누어 동기를 잡지 않습니다.) 하지만 SPI 통신처럼 동기를 잡아주는 클록이 따로 없고, 신호선의 길이와 노드들의 상대적인 위치 때문에 오차가 누적되어 하강 엣지가 SYNC_SEG 밖에서 탐지되는 상황이 발생합니다. 이때 하강 엣지가 비트 세그먼트2에서 탐지되면 비트 세그먼트2의 타임 퀀텀 개수에서 SJW에서 설정한 타임 퀀텀의 개수를 빼주어 비트 세그먼트2의 주기를 줄이고, 하강 엣지가 비트 세그먼트1에서 탐지되면 비트 세그먼트1의 타임 퀀텀 개수에서 SJW에서 설정한 타임 퀀텀의 개수를 더하여 비트 세그먼트1의 주기를 늘리는 방식으로 오차를 조정합니다.

can rx bit segment sync_seg

참고로 STM32 레퍼런스 매뉴얼(RM0091 837페이지)에선 비트를 판정하는 유효한 엣지를 다음과 같이 정의하고 있습니다.

A valid edge is defined as the first transition in a bit time from dominant to recessive bus level provided the controller itself does not send a recessive bit.

 

‘컨트롤러가 리세시브 비트를 보내고 있지 않다면, 유효한 엣지는 1비트 타임 안에서 도미넌트부터 리세시브 버스 레벨까지의 첫번째 전환으로 정의된다.’ 정도로 해석될 수 있는데요. 이렇게 되면 비트를 판정하는 엣지가 상승 엣지가 되어버립니다. 하지만 어떤 CAN 문서를 찾아봐도 상승 엣지에서 비트를 판정한다는 내용을 찾을 수 없었습니다. 따라서 dominant와 recessive의 위치가 바뀌어야 할 것 같습니다. 아마 레퍼런스 매뉴얼 작성자의 실수라고 생각되지만 다른 의견이 있으면 말씀해주세요.