STM32 CAN 32비트 멀티 필터 설정

J1939 프로토콜의 CAN 데이터를 수신하여 처리하려면 CAN 통신속도 250kbps, 샘플포인트 87%로 설정해야 한다. 내부클럭(HSI)을 사용할 경우 MCU의 상태에 따라 클럭이 틀어져서 CAN 데이터를 수신 못하는 문제가 발생하기 때문에 아래 이미지와 같이 외부 크리스탈을 사용하도록 한다.

STM32F429 데모보드의 최대 클럭은 180MHz이므로, 위 클럭설정처럼 최대 클럭을 사용하도록 한다. CAN1이 사용하는 APB1 버스클럭은 45MHz으로 설정된다.

 

CAN에서 통신속도 및 샘플포인트를 설정하는 것이 가장 중요하며, 아래 PPT 파일 내용과 동영상을 참고하여 J1939 프로토콜에서 사용하는 통신속도와 샘플포인트를 설정해야 한다.

250kbps의 1비트 타임은 4us이며, 20개의 타임퀀텀으로 구성할 경우 BS1 = 16, BS2 = 3으로 설정하면 샘플포인트가 85%로 설정된다. J1939 스펙인 87%를 맞추면 좋겠지만, 어떤 조합으로 구성해도 정확하게 떨어지지 않아 85%로 설정하였다. 만약 87%로 설정에 성공하신 분은 공유 부탁드려요.

 

J1939 프로토콜에는 수많은 데이터를 나타내며, 이것을 PGN으로 관리하며, 특정 PGN의 데이터만 수신하려면 PGN 값으로 필터를 설정할 수 있다. 또한 유사한 PGN 값을 논리연산하여 제한된 필터 개수 제한을 극복할 수 있다. J1939 프로토콜에 대한 자세한 설명은 아래 글을 참고하도록 한다.

 

SAE J1939 노하우 | Vector

SAE J1939는 상용차 분야의 네트워킹 및 통신을 위한 개방형 표준입니다. 주요 응용 분야는 파워트레인의 네트워킹입니다.

www.vector.com

 

J1939의 EEC1(Electronic Engine Control 1)과 EEC2(Electronic Engine Control 2)의 PGN 값은 0xF004, 0xF003이며, 각각 필터를 설정하여 데이터를 수신할 수  있지만, 유사한 PGN 값은 같은 필터로 설정하는 것이 필터 낭비를 줄일 수 있다.

 

EEC1(0xF004) PGN과 EEC2(0xF003)의 AND 연산 값은 0xF000이며, 맨 마지막 바이트만 서로 틀리기 때문에 마지막 바이트는 filter mask에서 Don't care 처리를 하도록 설정하고, 나머지 바이트는 반드시 일치하도록 나머지 바이트를 설정하면 최종 Filter Mask의 값은 0xFFF8이 된다. Filter Mask에 대한 자세한 설명은 위 동영상 CAN 강의를 참고하도록 한다.

 

따라서, J1939 프로토콜에서 CAN으로 받을 특정 데이터에 대해 다음과 같이 CAN ID에 대한 필터를 설정할 수 있다.

static void MX_CAN1_Init(void)
{
    int result = 0;

    hcan1.Instance = CAN1;
    hcan1.Init.Mode = CAN_MODE_NORMAL;
    hcan1.Init.Prescaler = 9;
    hcan1.Init.SyncJumpWidth = CAN_SJW_1TQ;
    hcan1.Init.TimeSeg1 = CAN_BS1_16TQ;
    hcan1.Init.TimeSeg2 = CAN_BS2_3TQ;
    hcan1.Init.TimeTriggeredMode = DISABLE;
    hcan1.Init.AutoBusOff = DISABLE;
    hcan1.Init.AutoWakeUp = DISABLE;
    hcan1.Init.AutoRetransmission = DISABLE;
    hcan1.Init.ReceiveFifoLocked = DISABLE;
    hcan1.Init.TransmitFifoPriority = DISABLE;
    if (HAL_CAN_Init(&hcan1) != HAL_OK)
    {
        Error_Handler();
    }

    result |= set_can_filter(0, 0x00F00000, 0x00FFF800);    /* 0x00F00x00 : EEC1, EEC2 */
    result |= set_can_filter(1, 0x00FD0000, 0x00FF0000);    /* 0x00FDxx00 : AT1S1, DLCC1, DPFC1, ECUID, EOI */
    result |= set_can_filter(2, 0x00FE0000, 0x00FF0000);    /* 0x00FExx00 : AMB, AT1T1I, CCVS1, DM1, EC1, EEC3, EPLP1, EPLP2, ET1, ET2, HOURS, IC1, LFC, IO, SHUTDN, TCI2 */
    result |= set_can_filter(3, 0x00FF4800, 0x00FFF800);    /* 0x00FF4x00 : E2M4A, E2M4C */
    result |= HAL_CAN_ActivateNotification(&hcan1, CAN_IT_RX_FIFO0_MSG_PENDING);
    if(result != 0)
    {
        printf("ERROR :: %s() : set_can_filter() fail\r\n", __func__);
        Error_Handler();
    }
}

그리고 29비트를 사용하는 CAN 2.0B의 ID의 필터를 설정하려면 아래 코드를 참고하도록 한다.

static int set_can_filter(uint8_t filter_index, uint32_t filter_id, uint32_t filter_mask)
{
    uint32_t id   = filter_id   << 3;
    uint32_t mask = filter_mask << 3;
    CAN_FilterTypeDef filter;

    filter.FilterIdHigh         = (id & 0xFFFF0000) >> 16;
    filter.FilterIdLow          = id  & 0x0000FFF8;
    filter.FilterMaskIdHigh     = (mask & 0xFFFF0000) >> 16;
    filter.FilterMaskIdLow      = mask  & 0x0000FFF8;
    filter.FilterScale          = CAN_FILTERSCALE_32BIT;
    filter.FilterMode           = CAN_FILTERMODE_IDMASK;
    filter.FilterFIFOAssignment = CAN_FILTER_FIFO0;
    filter.FilterBank           = filter_index;
    filter.FilterActivation     = ENABLE;
    filter.SlaveStartFilterBank = 14;

    if(HAL_CAN_ConfigFilter(&hcan1, &filter) != HAL_OK)
    {
        printf("ERROR ::%s() : filter_index = %d, filter_id = 0x%lx, filter_mask = 0x%lx\r\n", __func__, filter_index, filter_id, filter_mask);
        return -1;
    }

    return 0;
}

STM32는 CAN ID 32비트 중, 필터에 사용되는 비트는 29비트이기 때문에 3비트 shift 시킨 후, 상위 16비트, 하위 16비트로 구분하여 필터를 설정한다. 하위 16비트에서 마지막 3비트는 CAN ID와 무관하기 때문에 연산에서 제외시킨다.

 

그리고 STM32F429는 2개의 CAN을 제공하며, 각 CAN마다 14개의 필터를 설정할 수 있으며, CAN1은 0 ~ 13, CAN2는 14 ~ 27까지 설정이 가능하다. 참고로, SlaveStartFilterBank 값을 설정하지 않아 이상한 값으로 설정된 경우 설정한 필터에서 인터럽트가 발생하지 않을 수 있다. 이것 때문에 3-4시간을 꽃삽질을 하였다. 덕분에 CAN Filter 설정에 대한 자료는 많이 살펴보았지만, 언제나 그랬듯 문제의 해결은 전혀 엉뚱한 곳에서 단순하게 해결하였다.

 

웹 검색으로 CAN에 대한 자료도 많이 찾을 수 있고 이 포스트보다 더 자세히 설명한 글도 있지만, CAN 필터 설정에 대해 핵심적인 부분은 이정도의 내용이면 빠르게 이해할 수 있을 것 같다. 나중에 필요할 때 참고하도록 하자.

 

추가로 위 테스트 코드는 아래 GitHub에서 다운받아 확인할 수 있으며, CAN Filter 설정 및 데이터 수신에 대한 코드를 간단하게 작성한 것이다.

 

highgon2/STM32

STM32 TestCode. Contribute to highgon2/STM32 development by creating an account on GitHub.

github.com

참고로, USB2CAN 모듈을 사용하면 데스크탑 환경에서 CAN 데이터를 만들어 송수신할 수 있으며, 아래 이미지는 우분투 환경에서 USB2CAN 모듈을 사용하여 데스크탑에서 생성(송신) 메시지가 STM32에서 수신되는 것을 확인한 것이다.

USB2CAN 모듈을 Peak-System에서 판매하는 제품을 사용할 수 있지만, 가격이 비싼 관계로 ALiExpress에서 저렴한 가격에 구입한 MicroBus 제품으로 확인하였고, 기능상 두 제품의 차이는 없으며, 두 제품 모두 비슷한 유틸리티가 제공한다.

 

AliExpress 구입한 USB2CAN 모듈 사용 - MicroBus

지난 포스트에서 잠깐 언급한 USB2CAN 모듈이 알리에서 오늘 배송되었다. 약 19000원이라는 금액으로 저렴하게 구입하였는데, 늦은 배송과 제대로 동작할지 살짝 걱정이 되긴 했는데, 속는 셈 치고

memories.tistory.com