Industrial Communication/CAN Bus: Protocol & Physical Layer

ESP32 CAN 통신 구현: 인터럽트 방식 송수신과 특정 ID 필터링 예제

임베디드 친구 2025. 2. 25. 09:00
반응형

1. CAN 통신 개요

CAN(Controller Area Network) 통신은 자동차, 산업 자동화, 로봇 제어 등 다양한 분야에서 사용되는 직렬 통신 프로토콜입니다. 여러 개의 마이크로컨트롤러 간에 신뢰성 높은 데이터 교환이 가능하도록 설계되었으며, 다중 마스터(Multi-Master) 방식을 지원합니다.

ESP32는 기본적으로 CAN 통신을 지원하며, Espressif의 ESP-IDF(ESP32 IoT Development Framework)를 활용하여 CAN 데이터 송수신을 구현할 수 있습니다. 이번 포스팅에서는 ESP32 IDF를 활용한 CAN 메시지 송수신 예제와 필터링 기법, 인터럽트 방식과 폴링 방식의 차이를 설명하겠습니다.


Gemini AI 생성 이미지입니다.

2. ESP32 IDF에서 CAN 드라이버 설정

ESP32의 CAN 드라이버는 기본적으로 twai 드라이버를 사용합니다. ESP-IDF에서는 twai.h 헤더를 포함하여 CAN 통신을 설정할 수 있습니다.

2.1. 프로젝트 설정

ESP32에서 CAN 통신을 사용하려면 먼저 menuconfig에서 해당 드라이버를 활성화해야 합니다.

idf.py menuconfig

메뉴에서 Component Config -> TWAI Controller로 이동하여 드라이버를 활성화합니다.

2.2. CAN 드라이버 초기화 코드

다음은 ESP32의 TWAI 드라이버를 초기화하는 코드입니다.

#include "driver/twai.h"

void can_driver_init() {
    twai_general_config_t g_config = TWAI_GENERAL_CONFIG_DEFAULT(GPIO_NUM_21, GPIO_NUM_22, TWAI_MODE_NORMAL);
    twai_timing_config_t t_config = TWAI_TIMING_CONFIG_500KBITS();
    twai_filter_config_t f_config = TWAI_FILTER_CONFIG_ACCEPT_ALL();

    if (twai_driver_install(&g_config, &t_config, &f_config) == ESP_OK) {
        printf("CAN 드라이버 설치 완료\n");
    } else {
        printf("CAN 드라이버 설치 실패\n");
        return;
    }

    if (twai_start() == ESP_OK) {
        printf("CAN 드라이버 시작\n");
    } else {
        printf("CAN 드라이버 시작 실패\n");
    }
}

위 코드는 ESP32의 GPIO 21과 22를 사용하여 CAN 통신을 활성화하는 코드입니다. 속도는 500kbps로 설정되었으며, 모든 메시지를 수신할 수 있도록 필터를 설정하였습니다.


3. CAN 메시지 송신 코드 예제

ESP32에서 CAN 메시지를 송신하려면 twai_transmit() 함수를 사용해야 합니다. 다음은 CAN 메시지를 송신하는 예제 코드입니다.

void can_send_message() {
    twai_message_t message;
    message.identifier = 0x123;
    message.flags = TWAI_MSG_FLAG_NONE;
    message.data_length_code = 4;
    message.data[0] = 0xAA;
    message.data[1] = 0xBB;
    message.data[2] = 0xCC;
    message.data[3] = 0xDD;

    if (twai_transmit(&message, pdMS_TO_TICKS(1000)) == ESP_OK) {
        printf("CAN 메시지 송신 성공\n");
    } else {
        printf("CAN 메시지 송신 실패\n");
    }
}

이 코드에서는 0x123의 ID를 가지는 메시지를 전송합니다. 데이터 바이트는 0xAA, 0xBB, 0xCC, 0xDD이며, 최대 1000ms 동안 대기하도록 설정되었습니다.


4. CAN 메시지 수신 및 필터링 코드

ESP32에서 CAN 메시지를 수신하려면 twai_receive() 함수를 사용해야 합니다.

void can_receive_message() {
    twai_message_t message;
    if (twai_receive(&message, pdMS_TO_TICKS(1000)) == ESP_OK) {
        printf("CAN 메시지 수신 성공: ID = 0x%X, 데이터 길이 = %d\n", message.identifier, message.data_length_code);
        for (int i = 0; i < message.data_length_code; i++) {
            printf("데이터[%d] = 0x%X\n", i, message.data[i]);
        }
    } else {
        printf("CAN 메시지 수신 실패\n");
    }
}

위 코드는 수신된 CAN 메시지의 ID와 데이터를 출력하는 역할을 합니다.

4.1. 특정 메시지 필터링

특정 ID만 수신하려면 필터 설정을 수정해야 합니다.

twai_filter_config_t f_config = {
    .acceptance_code = (0x123 << 21),
    .acceptance_mask = ~(0x7FF << 21),
    .single_filter = true
};

이렇게 하면 ID가 0x123인 메시지만 수신됩니다.


5. 인터럽트 방식과 폴링 방식 비교

ESP32의 CAN 드라이버는 두 가지 방식으로 메시지를 수신할 수 있습니다.

5.1. 폴링 방식 (Polling)

void polling_receive() {
    while (1) {
        twai_message_t message;
        if (twai_receive(&message, pdMS_TO_TICKS(1000)) == ESP_OK) {
            printf("메시지 수신: ID=0x%X\n", message.identifier);
        }
    }
}

이 방식은 CPU가 계속 메시지를 체크해야 하므로 비효율적일 수 있습니다.

5.2. 인터럽트 방식 (Interrupt)

void IRAM_ATTR can_isr_handler(void *arg) {
    twai_message_t message;
    if (twai_receive(&message, 0) == ESP_OK) {
        printf("CAN 인터럽트 수신: ID=0x%X\n", message.identifier);
    }
}

void setup_can_interrupt() {
    twai_intr_register(can_isr_handler, NULL);
}

이 방식은 CPU 부하를 줄일 수 있으며, 메시지가 들어오면 자동으로 처리할 수 있습니다.


6. 결론

이번 포스팅에서는 ESP32 IDF를 활용하여 CAN 데이터 송수신을 구현하는 방법을 소개하였습니다. 주요 내용은 다음과 같습니다:

  • ESP32에서 CAN 드라이버를 활성화하고 초기화하는 방법
  • CAN 메시지를 송신하는 방법
  • CAN 메시지를 수신하고 필터링하는 방법
  • 폴링 방식과 인터럽트 방식의 차이점

ESP32를 활용한 CAN 통신은 자동차 및 산업 자동화 프로젝트에서 활용될 수 있으며, 실제 응용 사례에서 안정적인 데이터 송수신을 구현하는 데 필수적인 요소입니다.

반응형