CAN 통신

CAN 컨트롤러(MCP2515) 사용 방법 [ ESP32 IDF ]

임베디드 친구 2025. 2. 26. 13:45
728x90
반응형

CAN 컨트롤러(MCP2515) 사용 방법 ( ESP32 IDF )

1. 개요

ESP32에는 내부 CAN 컨트롤러(TWAI)가 있지만, 일부 프로젝트에서는 외부 CAN 컨트롤러를 사용해야 할 수도 있습니다. 대표적인 외부 CAN 컨트롤러로는 MCP2515가 있으며, SPI 인터페이스를 통해 ESP32와 연결하여 사용할 수 있습니다.

이 글에서는 ESP32 IDF(ESP-IDF) 환경에서 MCP2515를 사용하여 CAN 통신을 설정하는 방법을 자세히 설명합니다.

2. MCP2515 SPI 인터페이스 설정

MCP2515는 SPI(Serial Peripheral Interface) 프로토콜을 통해 마이크로컨트롤러와 통신합니다. SPI는 빠른 데이터 전송 속도를 제공하며, MCP2515를 제어하는 데 필수적인 요소입니다.

2.1 MCP2515 핀 구성

MCP2515는 SPI 인터페이스를 사용하여 ESP32와 연결됩니다. 주요 핀은 다음과 같습니다:

MCP2515 핀 설명 ESP32 핀 예제
VCC 전원 공급 (5V 또는 3.3V) 3.3V
GND 그라운드 GND
CS SPI 칩 선택 (Chip Select) GPIO5
SCK SPI 클록 (Serial Clock) GPIO18
SI SPI 데이터 입력 (MOSI) GPIO23
SO SPI 데이터 출력 (MISO) GPIO19
INT 인터럽트 핀 GPIO4

2.2 ESP32 IDF에서 SPI 설정

ESP-IDF에서 SPI 통신을 설정하려면 spi_device_interface_config_t를 사용하여 SPI 버스를 구성해야 합니다.

#include "driver/spi_master.h"
#include "driver/gpio.h"

#define PIN_NUM_MISO 19
#define PIN_NUM_MOSI 23
#define PIN_NUM_CLK  18
#define PIN_NUM_CS   5

spi_device_handle_t mcp2515_handle;

void spi_init() {
    spi_bus_config_t buscfg = {
        .miso_io_num = PIN_NUM_MISO,
        .mosi_io_num = PIN_NUM_MOSI,
        .sclk_io_num = PIN_NUM_CLK,
        .quadwp_io_num = -1,
        .quadhd_io_num = -1,
    };
    spi_device_interface_config_t devcfg = {
        .command_bits = 0,
        .address_bits = 0,
        .dummy_bits = 0,
        .clock_speed_hz = 1 * 1000 * 1000, // 1MHz
        .mode = 0,
        .spics_io_num = PIN_NUM_CS,
        .queue_size = 1,
    };
    spi_bus_initialize(SPI2_HOST, &buscfg, SPI_DMA_CH_AUTO);
    spi_bus_add_device(SPI2_HOST, &devcfg, &mcp2515_handle);
}

3. 라이브러리 활용하여 데이터 송수신

ESP-IDF 환경에서는 직접 MCP2515 레지스터를 제어하거나, 오픈소스 라이브러리를 활용하여 MCP2515를 쉽게 사용할 수 있습니다.

3.1 MCP2515 설정

MCP2515를 사용하려면 먼저 초기화해야 합니다. 아래는 MCP2515를 초기화하는 코드 예제입니다.

#include "mcp2515.h"
#include "driver/spi_master.h"

void mcp2515_init() {
    struct mcp2515_config config;
    config.spi_handle = mcp2515_handle;
    config.cs_pin = PIN_NUM_CS;
    mcp2515_initialize(&config);
    mcp2515_set_bitrate(MCP_500KBPS, MCP_8MHZ);
    mcp2515_set_mode(MCP_NORMAL);
}

int mcp2515_send_message(struct can_frame *frame) {
    uint8_t tx_buffer[13];
    tx_buffer[0] = (uint8_t)(frame->can_id >> 3);
    tx_buffer[1] = (uint8_t)((frame->can_id & 0x07) << 5);
    tx_buffer[2] = 0; // Standard frame, no extended ID
    tx_buffer[3] = 0; // No RTR
    tx_buffer[4] = frame->can_dlc & 0x0F;
    memcpy(&tx_buffer[5], frame->data, frame->can_dlc);

    spi_transaction_t t;
    memset(&t, 0, sizeof(t));
    t.length = (5 + frame->can_dlc) * 8;
    t.tx_buffer = tx_buffer;
    return spi_device_transmit(mcp2515_handle, &t);
}

int mcp2515_receive_message(struct can_frame *frame) {
    uint8_t rx_buffer[13];
    spi_transaction_t t;
    memset(&t, 0, sizeof(t));
    t.length = 13 * 8;
    t.rx_buffer = rx_buffer;

    if (spi_device_transmit(mcp2515_handle, &t) != ESP_OK) {
        return -1;
    }

    frame->can_id = (rx_buffer[0] << 3) | (rx_buffer[1] >> 5);
    frame->can_dlc = rx_buffer[4] & 0x0F;
    memcpy(frame->data, &rx_buffer[5], frame->can_dlc);

    return 0;
}

3.2 데이터 전송 예제

CAN 버스를 통해 데이터를 송신하려면 CAN 메시지를 작성한 후 MCP2515에 전송 요청을 해야 합니다.

void send_can_message() {
    struct can_frame frame;
    frame.can_id = 0x100;
    frame.can_dlc = 2;
    frame.data[0] = 0xAB;
    frame.data[1] = 0xCD;
    mcp2515_send_message(&frame);
}

3.3 데이터 수신 예제

CAN 메시지를 수신하려면 MCP2515의 인터럽트를 사용하거나 폴링 방식으로 데이터를 읽어올 수 있습니다.

void receive_can_message() {
    struct can_frame frame;
    if (mcp2515_receive_message(&frame) == MCP2515_OK) {
        printf("CAN ID: 0x%X\n", frame.can_id);
        printf("Data: ");
        for (int i = 0; i < frame.can_dlc; i++) {
            printf("%02X ", frame.data[i]);
        }
        printf("\n");
    }
}

4. MCP2515 ESP32 IDF 예제 코드

아래는 ESP32 IDF 환경에서 MCP2515를 초기화하고, CAN 메시지를 송수신하는 전체 예제 코드입니다.

#include "driver/spi_master.h"
#include "mcp2515.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"

#define PIN_NUM_MISO 19
#define PIN_NUM_MOSI 23
#define PIN_NUM_CLK  18
#define PIN_NUM_CS   5

spi_device_handle_t mcp2515_handle;

void app_main() {
    // SPI 초기화
    spi_init();

    // MCP2515 초기화
    mcp2515_init();

    // CAN 메시지 송신
    send_can_message();

    // 주기적으로 CAN 메시지 수신
    while (1) {
        receive_can_message();
        vTaskDelay(pdMS_TO_TICKS(1000));
    }
}

5. 결론

이 글에서는 ESP32 IDF 환경에서 MCP2515를 SPI를 통해 설정하고, CAN 데이터를 송수신하는 방법을 설명하였습니다.

  • SPI 인터페이스 설정: ESP32와 MCP2515 간 SPI 통신을 설정하는 방법을 설명하였습니다.
  • 라이브러리 활용: MCP2515를 설정하고 CAN 메시지를 송수신하는 방법을 설명하였습니다.
  • 예제 코드 제공: MCP2515를 사용한 전체 코드를 제공하여 실제 프로젝트에서 활용할 수 있도록 하였습니다.

이를 통해 ESP32 IDF 환경에서 외부 CAN 컨트롤러를 활용하여 다양한 프로젝트를 진행할 수 있을 것입니다.

반응형