CAN 통신

CAN 데이터 송수신 (ESP32 IDF 예제)

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

CAN 데이터 송수신 (ESP32 IDF 예제)

1. CAN 통신 개요

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

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


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

반응형