STM32 CAN Acceptance Filtering을 통해 특정 메시지를 수신받기

워너비임베·2024년 12월 29일

STM32

목록 보기
4/4

CAN에서 Acceptance filtering이란?
사용자가 정한 rule에 따라 CAN message를 filter하는 기능을 의미한다.
이러한 filtering이 필요한 이유로는, 원하는 메시지만 걸러 수신하는 목적도 있겠지만,
만약 모든 메시지를 다 받는다면 그 메시지를 받을 때 마다 수신 인터럽트가 발생하는데 이는 CPU의 큰 부하를 걸리게 한다.
그러므로 메시지 filtering이 필요하다.

이 Acceptance filter에는 28개의 filter banks가 존재한다.
각각의 filter bank는 독립적으로 설정값에 따라 메시지를 수신하거나 걸러주는 역할을 수행한다.
Acceptance filter는 Master와 slave CAN Peripheral간에 공유되어 사용된다.

STM MCU에서는 CAN 메시지를 전송하기 위해 각각의 CAN Peripheral 마다 3개의 TX Mailbox,2개의 Receive FIFO를 가지고 있다.

이 Mailbox 레지스터의 구성은 다음 그림과 같다.

CAN TX mailbox identifier register (CAN_TIxR) (x = 0..2)
Tx Mailbox안에 있는 CAN_TIxR레지스터는 전송할 CAN 메시지의 identifier를 설정하는데 사용되는 레지스터이다.
이 레지스터의 구조는 다음과 같다


CAN filterScale의 설정을 32bit / 16bit를 하게될 때의 차이는 다음 그림과 같다.

32bit 스케일로 처리하면, ID Register, Mask Register가 32bit로 처리된다.
16bit 스케일로 처리하면, ID Register, Mask Register가 16bit로 처리된다.

ID LIST MODE

CAN Filter 설정 ID LIST 모드는 수신받고자 하는 특정한 identifier값이 있다면 그것만을 통과시키게 하는 용도로 사용하기 좋다.
ex) 0x65D 혹은 0x651의 identifier를 가진 frame만 통과시키기

FilterIdHigh레지스터는 첫번째 필터 레지스터로 동작하고, FilterIdLow 레지스터는 첫 번째 필터 레지스터인 FilterIdHigh레지스터가 matching조건을 통과하지 못할 때 두번째 필터 레지스터로 동작하여 matching을 시작한다.

void MX_CAN1_Filter_list16(void){
	canFilter.FilterIdHigh = 0x106 << 5;
	canFilter.FilterIdLow = 0;
	canFilter.FilterMaskIdHigh = 0;
	canFilter.FilterMaskIdLow = 0;
	canFilter.FilterMode = CAN_FILTERMODE_IDLIST;
	canFilter.FilterScale = CAN_FILTERSCALE_16BIT;
	canFilter.FilterFIFOAssignment = CAN_FILTER_FIFO0;
	canFilter.FilterBank = 0;
	canFilter.FilterActivation = ENABLE;

	HAL_CAN_ConfigFilter(&hcan1, &canFilter);
	// CAN RX IT Enable
	HAL_CAN_ActivateNotification(&hcan1, CAN_IT_RX_FIFO0_MSG_PENDING);
}

예시로, FilterScale은 16bit, FilterMode는 IDLIST모드로 설정 후
0x106의 메시지 식별자를 가진 frame만 수신받고 싶을때 이렇게 코드를 사용한다 여기서 <<5를 해준 이유는 다음 사진과 같이 shift 연산을 해줌으로써 Filter결과가 STID[10:0]범위와 Mapping될 수 있게 하는 것이다.

Filter Mask Mode

Filter Mask Mode는 CAN identifier의 딱 정해진 지정값이 아닌 range(범위)를 설정하고 싶을 때 사용한다
예시로, 0x12345670 ~ 0x1234567F의 범위를 가진 identifier만 통과시키고 싶다고 가정하자.
다음 예제는 FilterScale은 32bit, FilterMode는 ID MASK모드이다.

void MX_CAN1_Filter_mask32(void){
	uint32_t addr32 = 0x12345678;
	uint32_t mask32 = 0x1ffffff0; // range : 0x12345670 ~ 0x1234567F

	canFilter.FilterIdHigh = (addr32<<3) >> 16;
	canFilter.FilterIdLow = ((addr32<<3) & 0xffff) | 0x04;
	canFilter.FilterMaskIdHigh = (mask32<<3) >> 16;
	canFilter.FilterMaskIdLow = (((mask32<<3) & 0xffff)) | 0x04;
	canFilter.FilterMode = CAN_FILTERMODE_IDMASK;
	canFilter.FilterScale = CAN_FILTERSCALE_32BIT;
	canFilter.FilterFIFOAssignment = CAN_FILTER_FIFO0;
	canFilter.FilterBank = 0;
	canFilter.FilterActivation = ENABLE;

	HAL_CAN_ConfigFilter(&hcan1, &canFilter);
	// CAN RX IT Enable
	HAL_CAN_ActivateNotification(&hcan1, CAN_IT_RX_FIFO0_MSG_PENDING);
}

EXID[28:0]까지의 구간에 맞게 FilterIdHigh(16bit), FilterIdLow(16bit)를 설정해준다.
canFilter.FilterIdHigh = (addr32<<3) >> 16;에서
<<3은 FilterIdHigh에 EXID[28:13]에 해당하는 상위 16bit를 설정해주기 위함이고 >>16을 통해 하위 8비트가 제거 되어 상위 16bit만 온전히 들어간다.
canFilter.FilterIdLow = ((addr32<<3) & 0xffff) | 0x04;에서 &0xffff를 한 이유는 and bit연산을 통해 상위 8비트를 지워 하위 16bit만 온전히 들어가게 해준다

| 0x04;를 한 이유는 2비트 index에 해당하는 IDE비트에 1을 set해줌으로써 Extended ID를 가진 Message임을 알려준다.

최종적으로, 수신할 수 있는 메시지 ID의 범위를 계산할 때, Mask Reigster의 1은 FilterId 레지스터의 값과 동일하게 나오게 하고, 0은 don't care의 의미로 0과 1 모두 나올 수 있다.
따라서 최종 계산 결과는 다음과 같다.따라서 해당 Mask Mode는 0x12345670 ~ 0x1234567F까지의 범위를 가진 메시지를 수신할 수 있다.


<참고자료>
STM32F446RE Reference Manual RM0390(p.107)
인프런 STM32 CAN통신(alex님)

0개의 댓글