CAN 통신

MCU에서 CAN 초기화 및 설정 (ESP32 기준)

임베디드 친구 2025. 2. 24. 12:29
728x90
반응형

MCU에서 CAN 초기화 및 설정 (ESP32 기준)

1. 개요

ESP32는 다양한 통신 프로토콜을 지원하며, 그중 하나가 CAN(Controller Area Network) 입니다. CAN은 자동차, 산업 자동화, 로봇 공학 등 다양한 분야에서 사용되며, 신뢰성 높은 통신을 제공합니다.

이번 포스팅에서는 ESP32 IDF(ESP-IDF)를 활용한 CAN 초기화 및 설정 방법을 살펴보고, CAN 필터링 및 인터럽트 처리, CAN 통신 속도 설정 및 오류 처리에 대해 자세히 설명하겠습니다. 또한, 예제 코드를 통해 실전에서 활용할 수 있도록 안내하겠습니다.


2. ESP32 IDF를 활용한 CAN 설정

ESP32에서 CAN을 사용하려면 ESP-IDF(ESP32 IoT Development Framework)를 활용해야 합니다. ESP-IDF는 공식적으로 제공되는 개발 프레임워크이며, 다양한 드라이버와 API를 포함하고 있습니다.

2.1 ESP-IDF 설치 및 프로젝트 생성

ESP-IDF를 설치한 후, 새 프로젝트를 생성합니다. 만약 ESP-IDF가 아직 설치되지 않았다면, 공식 문서를 참고하여 설치를 진행하시기 바랍니다.

새로운 프로젝트를 생성하려면 다음 명령어를 사용합니다:

idf.py create-project esp32_can_project
cd esp32_can_project

이제 CAN 드라이버를 설정하겠습니다.

2.2 CAN 드라이버 초기화 및 설정

ESP-IDF에서는 twai라는 이름으로 CAN 드라이버를 제공합니다. 따라서 헤더 파일을 포함해야 합니다:

#include "driver/twai.h"

그다음, CAN 드라이버를 초기화합니다:

void can_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 Driver Installed Successfully\n");
    } else {
        printf("Failed to install CAN driver\n");
    }

    if (twai_start() == ESP_OK) {
        printf("CAN Driver Started Successfully\n");
    } else {
        printf("Failed to start CAN driver\n");
    }
}

이 코드는 다음을 수행합니다:

  1. GPIO 21을 TX, GPIO 22를 RX로 설정합니다.
  2. CAN 속도를 500Kbps로 설정합니다.
  3. 모든 메시지를 수락하는 필터 설정을 적용합니다.
  4. CAN 드라이버를 설치 및 시작합니다.

3. CAN 필터링 및 인터럽트 처리

3.1 필터링 설정

필터링을 통해 특정 ID의 CAN 메시지만 수신할 수 있습니다. 기본적으로 모든 메시지를 수락하지만, 특정 ID만 수신하려면 다음과 같이 설정할 수 있습니다:

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

위 코드는 ID가 0x123인 메시지만 수락하도록 설정합니다.

3.2 인터럽트 기반 수신 처리

인터럽트를 사용하여 CAN 메시지를 수신하려면, twai_receive()를 활용할 수 있습니다:

void can_receive_task(void *arg) {
    twai_message_t message;
    while (1) {
        if (twai_receive(&message, portMAX_DELAY) == ESP_OK) {
            printf("Received message ID: 0x%X, Data: ", message.identifier);
            for (int i = 0; i < message.data_length_code; i++) {
                printf("%02X ", message.data[i]);
            }
            printf("\n");
        }
    }
}

이제 FreeRTOS 태스크를 생성하여 백그라운드에서 CAN 메시지를 지속적으로 수신할 수 있습니다.

xTaskCreate(can_receive_task, "CAN_Receive_Task", 4096, NULL, 5, NULL);

4. CAN 통신 속도 설정 및 오류 처리

4.1 속도 설정

CAN 속도는 twai_timing_config_t를 통해 설정할 수 있습니다.

대표적인 속도 옵션은 다음과 같습니다:

twai_timing_config_t t_config = TWAI_TIMING_CONFIG_1000KBITS(); // 1Mbps
// 또는
// twai_timing_config_t t_config = TWAI_TIMING_CONFIG_250KBITS(); // 250Kbps

속도는 통신 환경과 네트워크 길이에 따라 선택해야 합니다.

4.2 오류 처리

CAN 통신 중 오류가 발생할 경우, twai_status_info_t 구조체를 통해 확인할 수 있습니다:

twai_status_info_t status;
twai_get_status_info(&status);

if (status.state == TWAI_STATE_BUS_OFF) {
    printf("CAN Bus Off 상태 발생, 재시작 중...\n");
    twai_initiate_recovery();
}

이 코드는 버스 오프(Bus Off) 상태가 발생하면 CAN 드라이버를 재시작하는 로직을 포함합니다.


5. 예제 코드 전체

#include "driver/twai.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include <stdio.h>

void can_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();

    twai_driver_install(&g_config, &t_config, &f_config);
    twai_start();
}

void can_receive_task(void *arg) {
    twai_message_t message;
    while (1) {
        if (twai_receive(&message, portMAX_DELAY) == ESP_OK) {
            printf("Received message ID: 0x%X, Data: ", message.identifier);
            for (int i = 0; i < message.data_length_code; i++) {
                printf("%02X ", message.data[i]);
            }
            printf("\n");
        }
    }
}

void app_main() {
    can_init();
    xTaskCreate(can_receive_task, "CAN_Receive_Task", 4096, NULL, 5, NULL);
}

이 예제 코드를 실행하면 ESP32에서 CAN을 초기화하고 메시지를 수신하는 기능을 구현할 수 있습니다. 이를 활용하여 다양한 CAN 네트워크 프로젝트를 진행할 수 있습니다.

반응형