본문 바로가기

CAN

6. 데이터 수신 (풀링 방식) (1) 필터와 FMI

송신과 달리 수신 동작을 위한 컨트롤 비트는 따로 없습니다. CAN_MCR 레지스터의 SLEEP 비트와 INRQ 비트를 클리어하여 노멀 모드에 진입하면, 바로 수신 가능 상태가 됩니다. 전에도 설명했지만 필터를 통과한 데이터 프레임 또는 리모트 프레임은 STM32 CAN 컨트롤러에 의해 통과한 필터에 연결되어 있는 RX 메일박스 FIFO에 정리되어 적재됩니다. 이것은 STM32 CAN 컨트롤러만의 특징으로 알고 있습니다. 또한 STM32F091RC는 2개의 RX 메일박스 FIFO를 제공합니다. 초기 설정 파트에서 설명했지만 CAN_FFA1R 레지스터를 사용하여 필터 뱅크 단위로 필터를 RX 메일박스 FIFO에 연결시킬 수 있습니다.


RX 메일박스는 TX 메일박스와 같은 단층 구조가 아닌 FIFO 구조로 이루어져 있습니다. FIFO는 선입선출 구조로서 먼저 들어온 메시지가 먼저 읽히는 구조입니다. FIFO 구조는 여러가지 방식으로 설명될 수 있지만 여기서는 다음 그림과 같이 메시지가 처음 수신되면 맨 위의 공간에 적재되고 그 다음 수신된 메시지는 그 아래 적재되며, 데이터를 꺼내면 그 뒤에 있는 메시지가 위로 올라간다고 하겠습니다. 그리고 레지스터 맵에 있는 RX 메일박스 레지스터들은 이 RX 메일박스 FIFO에서 가장 먼저 도착한 메시지를 반영하는 레지스터 셋입니다. 아니면 그 자체라고 이해해도 상관 없습니다. 그리고 가장 먼저 들어온 메시지를 꺼내기 전에는 그 다음에 수신된 메시지 내용을 확인할 수 없습니다.

can_rixr can_rdtxr can_rlxr can_rhxr rx fifox fifo

RX 메일박스 FIFO에 데이터가 수신될 때마다 CAN_RFxR (Receive FIFO x)레지스터의 FMPx 필드의 카운트가 증가합니다. 풀링 방식의 경우 while문으로 이 필드를 검사하다가 0이 아닌 수가 검출되면 while문을 탈출하여 RX 메일박스 FIFO에서 메시지를 읽어옵니다. 인터럽트 방식의 경우 이 필드가 0이 아니게 되면 인터럽트가 발생하도록 CAN_IER 레지스터의 FMPIE0 비트 또는 FMPIE1 비트를 1로 셋하여, 메시지가 수신되어 인터럽트가 발생하면 CAN_ISR에서 RX 메일박스 FIFO를 읽습니다. 여기서는 풀링 방식에 대해서만 설명했습니다.


그리고 데이터 수신은 송신과 달리 수신을 위한 컨트롤 비트가 따로 없지만, 수신 후 FIFO에서 데이터를 읽었다는 것을(읽고 RAM 영역에 복사했다는 것을) CAN_RFxR 레지스터의 RFOMx (Release FIFO 0 output mailbox)비트를 셋하여 CAN 컨트롤러에게 알려주어야 합니다. 이 비트가 셋되면 CAN 컨트롤러는 RX 메일박스 FIFO에서 제일 먼저 수신된 메시지를 제거하고 그 다음에 수신된 메시지를 위로 올립니다. 그리고나서 FMPx 카운트를 감소시킵니다. 이것을 RX FIFO를 릴리즈(Release)한다고 합니다. FIFO 상태에 대한 그림은 RM0091 829페이지에서 확인할 수 있습니다.


각 RX 메일박스 FIFO는 최대 3개의 메시지를 저장할 수 있으며, 이를 초과하여 수신된 경우의 무시할지 덮어쓸지는 CAN_MCR 레지스터의 RFLM 비트를 통해 설정할 수 있습니다. 이것은 초기 설정 파트에서 CAN_MCR을 설명할 때 그림으로 이미 설명했습니다.


(1) 필터와 FMI


CAN_FFA1R 레지스터를 사용하여 필터 뱅크 단위로 필터를 RX 메일박스 FIFO에 연결시킬 수 있습니다. CAN_FFA1R 레지스터의 비트1이 1로 설정되어 있다면 필터 뱅크 1에 있는 필터를 통과한 메시지는 RX 메일박스 FIFO 1에 저장됩니다. 만약 비트2가 0으로 설정되어 있다면 필터 뱅크 2에 있는 필터를 통과한 메시지는 RX 메일박스 FIFO 0에 저장됩니다.


그런데 레퍼런스 매뉴얼에 보면 TX 메일박스에는 없고 RX 메일박스에만 있는 FMI라는 용어가 나옵니다. Filter Match Index의 약자로 하나의 필터 또는 하나의 필터 범위마다 순서대로 하나씩 부여되고, STM32 CAN 에서는 이 FMI를 통하여 해당 메시지가 어떤 필터를 통과해 왔는지 알 수 있습니다. 이 FMI 값이 RX 메일박스에 저장되기 때문입니다. 제 생각입니다만, 메시지를 수신할 때마다 11비트 또는 29비트 식별자를 비교하는 것보다 사용자 어플리케이션이 어떤 식별자에 대응하는 FMI를 미리 알고 있는 상태에서 FMI 값만 확인한다면 어떤 식별자인지 더 빠르게 판단할 수 있을 것 같습니다. 아니면 FMI를 배열의 인덱스로 사용해서 수신된 데이터를 데이터가 통과한 필터에 대응하는 배열에 빠르게 넣는 용도로 사용할 수 있다고 합니다. 특히 마스크 필터를 통과했을 때 효과가 있을 것 같습니다. 하지만 각 RX 메일박스 FIFO마다 독립적입니다. 즉, 각 RX 메일박스 FIFO 내에서만 고유한 번호를 갖기 때문에 복수의 RX 메일박스 FIFO가 있다면, 현재 이용중인 RX 메일박스 FIFO 번호를 확실하고 알고 있는 상태에서 사용해야 합니다. 이해를 돕기 위해 RM0091 833페이지에 나오는 FMI 그림을 분석해 보겠습니다.

can rx mail box registers filter numbering

필터 뱅크 0, 1, 3, 5, 6, 9, 13은 RX 메일박스 FIFO 0에 연결되어 있습니다. 필터 뱅크 2, 4, 7, 8, 10, 11, 12는 RX 메일박스 FIFO 1에 연결되어 있습니다. 즉, CAN_FFA1R 레지스터의 비트0, 1, 3, 5, 6, 9, 13은 0이고, 비트2, 4, 7, 8, 10, 11, 12는 1입니다. 따라서 CAN_FFA1R 레지스터의 현재 값은 0x1D94일 것입니다. 필터 뱅크 0은 32비트 리스트 모드입니다. 따라서 독립된 32비트 필터 2개가 존재하므로 각 필터에 FMI가 하나씩 총 2개가 배정되었습니다. 필터 뱅크 1은 32비트 마스크 모드입니다. 따라서 하나의 32비트 필터 범위가 존재하고, 이 필터 범위에 FMI가 하나 배정되었습니다. 필터 뱅크 3은 16비트 리스트 모드입니다. 따라서 독립된 16비트 필터 4개가 존재하므로 각 필터에 FMI가 하나씩 총 4개가 배정되었습니다. 필터 뱅크 6은 16비트 마스크 모드입니다. 따라서 두개의 16비트 필터 범위가 존재하고, 각 필터 범위마다 FMI가 하나씩 총 2개가 배정되었습니다. RX 메일박스 FIFO 0에 연결된 필터를 통과하면 그 필터의 FMI가 CAN_RDT0R 레지스터의 FMI 필드에 저장되고, RX 메일박스 FIFO 1에 연결된 필터를 통과하면 그 필터의 FMI가 CAN_RDT1R 레지스터의 FMI 필드에 저장됩니다. 참고로 필터가 활성화되어 있는지의 여부는 FMI 배정과 상관 없습니다.