본문 바로가기
MCU/C2000

[TMS320F28388D] CAN 사용법: DriverLib API로 CAN 설정 및 코드

by linuxgo 2025. 8. 17.
반응형

소개

이 문서에서는 Texas Instruments의 TMS320F28388D 마이크로컨트롤러에서 CAN(Controller Area Network) 모듈을 DriverLib API를 사용하여 설정하고 사용하는 방법을 상세히 다룹니다. C2000 시리즈의 고성능 마이크로컨트롤러인 TMS320F28388D의 CAN 모듈을 활용하여 CAN 통신을 구현하는 방법을 배우고, 다양한 독립적인 예제 코드를 통해 actual implementation 방법을 익힐 수 있습니다. 각 코드에는 상세한 주석이 포함되어 있으며, Code Composer Studio(CCS) 환경에서 실행 가능합니다.

1. TMS320F28388D CAN 개요

TMS320F28388D는 Texas Instruments의 C2000 시리즈에 속하는 고성능 32비트 마이크로컨트롤러로, 두 개의 CAN 모듈(CAN-A, CAN-B)을 제공합니다. CAN 모듈은 ISO 11898-1 표준을 준수하며, 자동차, 산업 자동화, 모터 제어 등 다양한 실시간 통신 애플리케이션에 적합합니다.

CAN 모듈의 주요 특징

  • 통신 속도: 최대 1Mbps 지원.
  • 메시지 객체: 각 모듈은 32개의 메시지 객체(Mailbox)를 제공하여 송수신 데이터 관리.
  • 인터럽트: 인터럽트 기반 또는 폴링 방식의 데이터 송수신 지원.
  • 에러 처리: 자동 재전송, 에러 카운터, 에러 인터럽트 지원.
  • 클럭: 시스템 클럭(최대 200MHz)을 기반으로 동작, 비트 타이밍 설정 가능.
  • 고급 기능: 필터링, 마스크 설정, 우선순위 관리.

DriverLib API는 하드웨어 레지스터를 직접 조작하는 대신 추상화된 함수를 제공하여 CAN 설정을 간소화합니다.

2. 주요 CAN DriverLib API 함수

아래는 TMS320F28388D의 CAN 모듈을 제어하기 위해 자주 사용되는 DriverLib API 함수와 그 사용 방법입니다.

2.1. CAN 기본 설정 관련 함수

  • CAN_initModule(base): CAN 모듈을 초기화합니다.
    • 매개변수: base (CAN 모듈의 베이스 주소, 예: CANA_BASE).
  • CAN_setBitRate(base, clk, bitRate): CAN 비트율 설정.
    • 매개변수: clk (시스템 클럭), bitRate (원하는 비트율, 예: 500000 for 500kbps).
  • CAN_enableModule(base): CAN 모듈 활성화.
  • CAN_disableModule(base): CAN 모듈 비활성화.

2.2. 메시지 객체 설정 관련 함수

  • CAN_setupMessageObject(base, objID, msgID, frameType, msgType, mask, flags): 메시지 객체(Mailbox) 설정.
    • 매개변수: objID (메시지 객체 번호, 1~32), msgID (CAN ID), frameType (표준/확장 프레임), msgType (송신/수신).
  • CAN_sendMessage(base, objID, length, data): 메시지 전송.
    • 매개변수: objID (메시지 객체 번호), length (데이터 길이, 최대 8바이트), data (전송 데이터 배열).
  • CAN_readMessage(base, objID, data): 메시지 수신.
    • 매개변수: objID (메시지 객체 번호), data (수신 데이터 저장 배열).

2.3. 인터럽트 관련 함수

  • CAN_enableInterrupt(base, intFlags): CAN 인터럽트 활성화.
    • 매개변수: intFlags (예: CAN_INT_IE0 for 일반 인터럽트).
  • CAN_clearInterruptStatus(base, intFlags): 인터럽트 플래그 지우기.
  • Interrupt_register(intNumber, handler): 인터럽트 서비스 루틴(ISR) 등록.

3. CAN 설정 및 동작 원리

  1. 시스템 초기화: 시스템 클럭과 GPIO 초기화(Device_init(), Device_initGPIO()), 인터럽트 모듈 초기화.
  2. CAN 모듈 설정: 클럭 활성화, 비트율 설정, 메시지 객체 설정.
  3. 인터럽트 설정(선택): 인터럽트 활성화 및 ISR 등록.
  4. CAN 활성화: CAN 모듈 활성화 및 송수신 시작.

4. CAN 예제 코드

아래는 독립적인 CAN 예제 코드로, C2000Ware의 DriverLib를 기반으로 작성되었습니다. GPIO 설정은 별도의 initGPIO() 함수로 분리되어 있으며, 모든 코드는 CCS에서 바로 실행 가능합니다.

4.1. 예제 1: 기본 CAN 메시지 송신

CAN-A를 사용하여 500kbps로 표준 ID 메시지를 전송합니다.

#include "driverlib.h"
#include "device.h"

// 디버깅용 상태 변수: CAN 모듈 상태 추적
volatile uint32_t canStatus = 0; // 0: 초기화 완료, 1: CAN 동작 중, 0xFFFF: 오류

// GPIO 초기화 함수
void initGPIO(void)
{
    // GPIO30을 CAN-A TX로 설정
    GPIO_setPinConfig(GPIO_30_CANA_TX);         // CAN-A 송신 핀으로 GPIO30 설정
    GPIO_setDirectionMode(30, GPIO_DIR_MODE_OUT); // 출력 모드로 설정
    GPIO_setPadConfig(30, GPIO_PULL_UP);         // 풀업 저항 활성화 (외부 회로에 따라 조정 가능)
    
    // GPIO31을 CAN-A RX로 설정
    GPIO_setPinConfig(GPIO_31_CANA_RX);         // CAN-A 수신 핀으로 GPIO31 설정
    GPIO_setDirectionMode(31, GPIO_DIR_MODE_IN); // 입력 모드로 설정
    GPIO_setPadConfig(31, GPIO_PULL_UP);        // 풀업 저항 활성화
    
    // 디버깅용 LED 설정 (GPIO34, 예: LAUNCHXL-F28379D 기준)
    GPIO_setPinConfig(GPIO_34_GPIO34);          // GPIO34를 일반 GPIO로 설정
    GPIO_setDirectionMode(34, GPIO_DIR_MODE_OUT); // 출력 모드로 설정
    GPIO_setPadConfig(34, GPIO_PULL_UP);        // 풀업 저항 활성화
    GPIO_writePin(34, 0);                       // 초기 LED 상태 OFF
}

// CAN-A 초기화 함수
void initCAN(void)
{
    // CAN-A 클럭 활성화
    SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_CANA); // CAN-A 모듈에 클럭 공급
    
    // CAN 모듈 초기화
    CAN_initModule(CANA_BASE);                      // CAN-A 모듈 기본 초기화
    
    // 비트율 설정: 500kbps (시스템 클럭 200MHz 기준)
    CAN_setBitRate(CANA_BASE, DEVICE_SYSCLK_FREQ, 500000); // 비트율 설정
    
    // 메시지 객체 설정: 표준 ID, 송신, ID=0x123
    CAN_setupMessageObject(CANA_BASE, 1, 0x123,     // 메시지 객체 1번, ID 0x123
                          CAN_MSG_FRAME_STD,        // 표준 프레임 (11비트 ID)
                          CAN_MSG_OBJ_TYPE_TX,      // 송신용 객체
                          0,                        // 마스크 없음
                          CAN_MSG_OBJ_NO_FLAGS);    // 추가 플래그 없음
    
    // CAN 모듈 활성화
    CAN_enableModule(CANA_BASE);                    // CAN-A 모듈 동작 시작
    
    // 상태 업데이트
    canStatus = 1;                                  // CAN 동작 중 상태로 설정
}

void main(void)
{
    // 시스템 클럭 및 주변 장치 초기화
    Device_init();                                  // PLL, Watchdog, 주변 장치 클럭 설정
    
    // GPIO 기본 초기화
    Device_initGPIO();                              // GPIO 기본 설정 초기화
    
    // CAN 관련 GPIO 설정
    initGPIO();                                     // CAN 및 디버깅용 GPIO 설정
    
    // 인터럽트 모듈 초기화
    Interrupt_initModule();                         // 인터럽트 컨트롤러 초기화
    Interrupt_initVectorTable();                    // 인터럽트 벡터 테이블 초기화
    
    // 시스템 클럭 확인 (디버깅용)
    uint32_t sysClockHz = SysCtl_getClock(DEVICE_OSCSRC_FREQ); // 시스템 클럭 주파수 확인
    if (sysClockHz != 200000000)                    // 200MHz가 아닌 경우 오류 처리
    {
        canStatus = 0xFFFF;                         // 오류 상태 설정
        GPIO_writePin(34, 0);                       // LED OFF로 오류 표시
        ESTOP0;                                     // 디버깅용 정지 (CCS에서 확인 가능)
    }
    
    // CAN-A 초기화
    initCAN();                                      // CAN-A 모듈 초기화
    
    // CAN 초기화 오류 확인
    if (canStatus != 1)                             // 초기화 실패 시 오류 처리
    {
        canStatus = 0xFFFF;                         // 오류 상태 설정
        GPIO_writePin(34, 0);                       // LED OFF로 오류 표시
        ESTOP0;                                     // 디버깅용 정지
    }
    
    // 글로벌 인터럽트 활성화
    EINT;                                           // 전체 인터럽트 활성화
    
    // Watchdog 활성화
    SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_WD);  // Watchdog 클럭 활성화
    SysCtl_serviceWatchdog();                       // Watchdog 서비스 시작
    
    // 테스트 데이터 준비
    uint8_t txData[8] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}; // 송신 데이터 배열
    
    // 무한 루프
    for(;;)
    {
        // CAN 메시지 전송
        CAN_sendMessage(CANA_BASE, 1, 8, txData);   // 메시지 객체 1번으로 8바이트 데이터 전송
        
        // 디버깅용: 상태 표시
        GPIO_writePin(34, (canStatus == 1) ? 1 : 0); // 정상 동작 시 LED ON
        DEVICE_DELAY_US(1000000);                   // 1초 대기 (디버깅 및 CPU 부하 감소)
    }
}

설명:

  • 기능: CAN-A를 통해 500kbps로 표준 ID(0x123) 메시지 전송.
  • 설정: 비트율 500kbps, 메시지 객체 1번 사용, 8바이트 데이터 전송.
  • GPIO: GPIO30(CAN-A TX), GPIO31(CAN-A RX), GPIO34(LED).
  • 출력: CAN 메시지 주기적 전송, 정상 동작 시 LED ON.

4.2. 예제 2: CAN 메시지 수신 및 인터럽트

CAN-A를 사용하여 메시지를 수신하고 인터럽트를 통해 처리합니다.

#include "driverlib.h"
#include "device.h"

// 디버깅용 상태 변수: CAN 모듈 상태 추적
volatile uint32_t canStatus = 0; // 0: 초기화 완료, 1: CAN 동작 중, 0xFFFF: 오류

// 수신 데이터 저장 버퍼
uint8_t rxData[8];              // 수신된 데이터를 저장할 배열
volatile uint16_t rxFlag = 0;   // 수신 완료 플래그

// GPIO 초기화 함수
void initGPIO(void)
{
    // GPIO30을 CAN-A TX로 설정
    GPIO_setPinConfig(GPIO_30_CANA_TX);         // CAN-A 송신 핀으로 GPIO30 설정
    GPIO_setDirectionMode(30, GPIO_DIR_MODE_OUT); // 출력 모드로 설정
    GPIO_setPadConfig(30, GPIO_PULL_UP);        // 풀업 저항 활성화
    
    // GPIO31을 CAN-A RX로 설정
    GPIO_setPinConfig(GPIO_31_CANA_RX);         // CAN-A 수신 핀으로 GPIO31 설정
    GPIO_setDirectionMode(31, GPIO_DIR_MODE_IN); // 입력 모드로 설정
    GPIO_setPadConfig(31, GPIO_PULL_UP);        // 풀업 저항 활성화
    
    // 디버깅용 LED 설정 (GPIO34)
    GPIO_setPinConfig(GPIO_34_GPIO34);          // GPIO34를 일반 GPIO로 설정
    GPIO_setDirectionMode(34, GPIO_DIR_MODE_OUT); // 출력 모드로 설정
    GPIO_setPadConfig(34, GPIO_PULL_UP);        // 풀업 저항 활성화
    GPIO_writePin(34, 0);                       // 초기 LED 상태 OFF
}

// CAN 인터럽트 서비스 루틴
__interrupt void canA0ISR(void)
{
    // 메시지 수신
    CAN_readMessage(CANA_BASE, 2, rxData);      // 메시지 객체 2번에서 데이터 읽기
    rxFlag = 1;                                 // 수신 플래그 설정 (수신 완료 표시)
    
    // 인터럽트 플래그 지우기
    CAN_clearInterruptStatus(CANA_BASE, CAN_INT_IE0); // CAN 인터럽트 플래그 클리어
    Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP9);    // PIE 그룹 9 ACK
    
    // 상태 업데이트
    canStatus = 1;                              // CAN 동작 중 상태로 설정
}

void initCAN(void)
{
    // CAN-A 클럭 활성화
    SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_CANA); // CAN-A 모듈에 클럭 공급
    
    // CAN 모듈 초기화
    CAN_initModule(CANA_BASE);                      // CAN-A 모듈 기본 초기화
    
    // 비트율 설정: 500kbps
    CAN_setBitRate(CANA_BASE, DEVICE_SYSCLK_FREQ, 500000); // 비트율 설정 (200MHz 기준)
    
    // 메시지 객체 설정: 표준 ID, 수신, ID=0x456
    CAN_setupMessageObject(CANA_BASE, 2, 0x456,     // 메시지 객체 2번, ID 0x456
                          CAN_MSG_FRAME_STD,        // 표준 프레임 (11비트 ID)
                          CAN_MSG_OBJ_TYPE_RX,      // 수신용 객체
                          0,                        // 마스크 없음
                          CAN_MSG_OBJ_RX_INT_ENABLE); // 수신 인터럽트 활성화
    
    // 인터럽트 활성화
    CAN_enableInterrupt(CANA_BASE, CAN_INT_IE0);    // 일반 인터럽트 활성화
    
    // CAN 모듈 활성화
    CAN_enableModule(CANA_BASE);                    // CAN-A 모듈 동작 시작
}

void main(void)
{
    // 시스템 클럭 및 주변 장치 초기화
    Device_init();                                  // PLL, Watchdog, 주변 장치 클럭 설정
    
    // GPIO 기본 초기화
    Device_initGPIO();                              // GPIO 기본 설정 초기화
    
    // CAN 관련 GPIO 설정
    initGPIO();                                     // CAN 및 디버깅용 GPIO 설정
    
    // 인터럽트 모듈 초기화
    Interrupt_initModule();                         // 인터럽트 컨트롤러 초기화
    Interrupt_initVectorTable();                    // 인터럽트 벡터 테이블 초기화
    
    // CAN 인터럽트 ISR 등록
    Interrupt_register(INT_CANA_0, &canA0ISR);      // CAN-A 인터럽트 서비스 루틴 등록
    
    // 시스템 클럭 확인
    uint32_t sysClockHz = SysCtl_getClock(DEVICE_OSCSRC_FREQ); // 시스템 클럭 주파수 확인
    if (sysClockHz != 200000000)                    // 200MHz가 아닌 경우 오류 처리
    {
        canStatus = 0xFFFF;                         // 오류 상태 설정
        GPIO_writePin(34, 0);                       // LED OFF로 오류 표시
        ESTOP0;                                     // 디버깅용 정지
    }
    
    // CAN-A 초기화
    initCAN();                                      // CAN-A 모듈 초기화
    
    // 초기화 오류 확인
    if (canStatus != 1)                             // 초기화 실패 시 오류 처리
    {
        canStatus = 0xFFFF;                         // 오류 상태 설정
        GPIO_writePin(34, 0);                       // LED OFF로 오류 표시
        ESTOP0;                                     // 디버깅용 정지
    }
    
    // 글로벌 인터럽트 활성화
    EINT;                                           // 전체 인터럽트 활성화
    
    // Watchdog 활성화
    SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_WD);  // Watchdog 클럭 활성화
    SysCtl_serviceWatchdog();                       // Watchdog 서비스 시작
    
    // 무한 루프
    for(;;)
    {
        // 디버깅용: 상태 표시
        GPIO_writePin(34, (canStatus == 1 && rxFlag == 1) ? 1 : 0); // 메시지 수신 시 LED ON
        DEVICE_DELAY_US(1000000);                   // 1초 대기
    }
}

설명:

  • 기능: CAN-A를 통해 ID 0x456 메시지 수신, 인터럽트로 처리.
  • 설정: 비트율 500kbps, 메시지 객체 2번 사용, 수신 인터럽트 활성화.
  • GPIO: GPIO30(CAN-A TX), GPIO31(CAN-A RX), GPIO34(LED).
  • 출력: 메시지 수신 시 rxFlag 설정, LED ON.

4.3. 예제 3: CAN 송수신 및 에러 처리

CAN-A를 사용하여 송수신을 동시에 수행하고 에러를 감지합니다.

#include "driverlib.h"
#include "device.h"

// 디버깅용 상태 변수: CAN 모듈 상태 추적
volatile uint32_t canStatus = 0; // 0: 초기화 완료, 1: CAN 동작 중, 0xFFFF: 오류
volatile uint32_t errorCount = 0; // CAN 에러 카운트

// 송수신 데이터
uint8_t txData[8] = {0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x00, 0x11}; // 송신 데이터 배열
uint8_t rxData[8];              // 수신 데이터 저장 배열
volatile uint16_t rxFlag = 0;   // 수신 완료 플래그

// GPIO 초기화 함수
void initGPIO(void)
{
    // GPIO30을 CAN-A TX로 설정
    GPIO_setPinConfig(GPIO_30_CANA_TX);         // CAN-A 송신 핀으로 GPIO30 설정
    GPIO_setDirectionMode(30, GPIO_DIR_MODE_OUT); // 출력 모드로 설정
    GPIO_setPadConfig(30, GPIO_PULL_UP);        // 풀업 저항 활성화
    
    // GPIO31을 CAN-A RX로 설정
    GPIO_setPinConfig(GPIO_31_CANA_RX);         // CAN-A 수신 핀으로 GPIO31 설정
    GPIO_setDirectionMode(31, GPIO_DIR_MODE_IN); // 입력 모드로 설정
    GPIO_setPadConfig(31, GPIO_PULL_UP);        // 풀업 저항 활성화
    
    // 디버깅용 LED 설정 (GPIO34)
    GPIO_setPinConfig(GPIO_34_GPIO34);          // GPIO34를 일반 GPIO로 설정
    GPIO_setDirectionMode(34, GPIO_DIR_MODE_OUT); // 출력 모드로 설정
    GPIO_setPadConfig(34, GPIO_PULL_UP);        // 풀업 저항 활성화
    GPIO_writePin(34, 0);                       // 초기 LED 상태 OFF
}

// CAN 에러 인터럽트 서비스 루틴
__interrupt void canAErrorISR(void)
{
    // 에러 카운터 증가
    errorCount++;                               // CAN 에러 발생 시 카운터 증가
    
    // 인터럽트 플래그 지우기
    CAN_clearInterruptStatus(CANA_BASE, CAN_INT_ERROR); // 에러 인터럽트 플래그 클리어
    Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP9);      // PIE 그룹 9 ACK
    
    // 상태 업데이트
    canStatus = 0xFFFF;                         // 오류 상태 설정
}

// CAN 수신 인터럽트 서비스 루틴
__interrupt void canA0ISR(void)
{
    // 메시지 수신
    CAN_readMessage(CANA_BASE, 2, rxData);      // 메시지 객체 2번에서 데이터 읽기
    rxFlag = 1;                                 // 수신 플래그 설정
    
    // 인터럽트 플래그 지우기
    CAN_clearInterruptStatus(CANA_BASE, CAN_INT_IE0); // 수신 인터럽트 플래그 클리어
    Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP9);    // PIE 그룹 9 ACK
}

void initCAN(void)
{
    // CAN-A 클럭 활성화
    SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_CANA); // CAN-A 모듈에 클럭 공급
    
    // CAN 모듈 초기화
    CAN_initModule(CANA_BASE);                      // CAN-A 모듈 기본 초기화
    
    // 비트율 설정: 500kbps
    CAN_setBitRate(CANA_BASE, DEVICE_SYSCLK_FREQ, 500000); // 비트율 설정
    
    // 송신 메시지 객체 설정: ID=0x123
    CAN_setupMessageObject(CANA_BASE, 1, 0x123,     // 메시지 객체 1번, ID 0x123
                          CAN_MSG_FRAME_STD,        // 표준 프레임
                          CAN_MSG_OBJ_TYPE_TX,      // 송신용 객체
                          0,                        // 마스크 없음
                          CAN_MSG_OBJ_NO_FLAGS);    // 추가 플래그 없음
    
    // 수신 메시지 객체 설정: ID=0x456
    CAN_setupMessageObject(CANA_BASE, 2, 0x456,     // 메시지 객체 2번, ID 0x456
                          CAN_MSG_FRAME_STD,        // 표준 프레임
                          CAN_MSG_OBJ_TYPE_RX,      // 수신용 객체
                          0,                        // 마스크 없음
                          CAN_MSG_OBJ_RX_INT_ENABLE); // 수신 인터럽트 활성화
    
    // 인터럽트 활성화
    CAN_enableInterrupt(CANA_BASE, CAN_INT_IE0 | CAN_INT_ERROR); // 수신 및 에러 인터럽트 활성화
    
    // CAN 모듈 활성화
    CAN_enableModule(CANA_BASE);                    // CAN-A 모듈 동작 시작
}

void main(void)
{
    // 시스템 클럭 및 주변 장치 초기화
    Device_init();                                  // PLL, Watchdog, 주변 장치 클럭 설정
    
    // GPIO 기본 초기화
    Device_initGPIO();                              // GPIO 기본 설정 초기화
    
    // CAN 관련 GPIO 설정
    initGPIO();                                     // CAN 및 디버깅용 GPIO 설정
    
    // 인터럽트 모듈 초기화
    Interrupt_initModule();                         // 인터럽트 컨트롤러 초기화
    Interrupt_initVectorTable();                    // 인터럽트 벡터 테이블 초기화
    
    // CAN 인터럽트 ISR 등록
    Interrupt_register(INT_CANA_0, &canA0ISR);      // 수신 인터럽트 서비스 루틴 등록
    Interrupt_register(INT_CANA_1, &canAErrorISR);  // 에러 인터럽트 서비스 루틴 등록
    
    // 시스템 클럭 확인
    uint32_t sysClockHz = SysCtl_getClock(DEVICE_OSCSRC_FREQ); // 시스템 클럭 주파수 확인
    if (sysClockHz != 200000000)                    // 200MHz가 아닌 경우 오류 처리
    {
        canStatus = 0xFFFF;                         // 오류 상태 설정
        GPIO_writePin(34, 0);                       // LED OFF로 오류 표시
        ESTOP0;                                     // 디버깅용 정지
    }
    
    // CAN-A 초기화
    initCAN();                                      // CAN-A 모듈 초기화
    
    // 초기화 오류 확인
    if (canStatus != 1)                             // 초기화 실패 시 오류 처리
    {
        canStatus = 0xFFFF;                         // 오류 상태 설정
        GPIO_writePin(34, 0);                       // LED OFF로 오류 표시
        ESTOP0;                                     // 디버깅용 정지
    }
    
    // 글로벌 인터럽트 활성화
    EINT;                                           // 전체 인터럽트 활성화
    
    // Watchdog 활성화
    SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_WD);  // Watchdog 클럭 활성화
    SysCtl_serviceWatchdog();                       // Watchdog 서비스 시작
    
    // 무한 루프
    for(;;)
    {
        // CAN 메시지 전송
        CAN_sendMessage(CANA_BASE, 1, 8, txData);   // 메시지 객체 1번으로 8바이트 데이터 전송
        
        // 디버깅용: 상태 표시
        GPIO_writePin(34, (canStatus == 1 && errorCount == 0) ? 1 : 0); // 정상 동작 시 LED ON
        DEVICE_DELAY_US(1000000);                   // 1초 대기
    }
}

설명:

  • 기능: CAN-A로 송수신 동시 수행, 에러 인터럽트 처리.
  • 설정: 송신(ID 0x123), 수신(ID 0x456), 에러 인터럽트 활성화.
  • GPIO: GPIO30(CAN-A TX), GPIO31(CAN-A RX), GPIO34(LED).
  • 출력: 메시지 송수신, 에러 발생 시 LED OFF.

4.4. 예제 4: 확장 ID 메시지 송신

CAN-A를 사용하여 500kbps로 확장 ID(29비트) 메시지를 전송합니다.

#include "driverlib.h"
#include "device.h"

// 디버깅용 상태 변수: CAN 모듈 상태 추적
volatile uint32_t canStatus = 0; // 0: 초기화 완료, 1: CAN 동작 중, 0xFFFF: 오류

// GPIO 초기화 함수
void initGPIO(void)
{
    // GPIO30을 CAN-A TX로 설정
    GPIO_setPinConfig(GPIO_30_CANA_TX);         // CAN-A 송신 핀으로 GPIO30 설정
    GPIO_setDirectionMode(30, GPIO_DIR_MODE_OUT); // 출력 모드로 설정
    GPIO_setPadConfig(30, GPIO_PULL_UP);        // 풀업 저항 활성화
    
    // GPIO31을 CAN-A RX로 설정
    GPIO_setPinConfig(GPIO_31_CANA_RX);         // CAN-A 수신 핀으로 GPIO31 설정
    GPIO_setDirectionMode(31, GPIO_DIR_MODE_IN); // 입력 모드로 설정
    GPIO_setPadConfig(31, GPIO_PULL_UP);        // 풀업 저항 활성화
    
    // 디버깅용 LED 설정 (GPIO34)
    GPIO_setPinConfig(GPIO_34_GPIO34);          // GPIO34를 일반 GPIO로 설정
    GPIO_setDirectionMode(34, GPIO_DIR_MODE_OUT); // 출력 모드로 설정
    GPIO_setPadConfig(34, GPIO_PULL_UP);        // 풀업 저항 활성화
    GPIO_writePin(34, 0);                       // 초기 LED 상태 OFF
}

// CAN-A 초기화 함수
void initCAN(void)
{
    // CAN-A 클럭 활성화
    SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_CANA); // CAN-A 모듈에 클럭 공급
    
    // CAN 모듈 초기화
    CAN_initModule(CANA_BASE);                      // CAN-A 모듈 기본 초기화
    
    // 비트율 설정: 500kbps
    CAN_setBitRate(CANA_BASE, DEVICE_SYSCLK_FREQ, 500000); // 비트율 설정 (200MHz 기준)
    
    // 메시지 객체 설정: 확장 ID, 송신, ID=0x1FFFF123
    CAN_setupMessageObject(CANA_BASE, 1, 0x1FFFF123, // 메시지 객체 1번, 확장 ID
                          CAN_MSG_FRAME_EXT,         // 확장 프레임 (29비트 ID)
                          CAN_MSG_OBJ_TYPE_TX,       // 송신용 객체
                          0,                         // 마스크 없음
                          CAN_MSG_OBJ_NO_FLAGS);     // 추가 플래그 없음
    
    // CAN 모듈 활성화
    CAN_enableModule(CANA_BASE);                    // CAN-A 모듈 동작 시작
    
    // 상태 업데이트
    canStatus = 1;                                  // CAN 동작 중 상태로 설정
}

void main(void)
{
    // 시스템 클럭 및 주변 장치 초기화
    Device_init();                                  // PLL, Watchdog, 주변 장치 클럭 설정
    
    // GPIO 기본 초기화
    Device_initGPIO();                              // GPIO 기본 설정 초기화
    
    // CAN 관련 GPIO 설정
    initGPIO();                                     // CAN 및 디버깅용 GPIO 설정
    
    // 인터럽트 모듈 초기화
    Interrupt_initModule();                         // 인터럽트 컨트롤러 초기화
    Interrupt_initVectorTable();                    // 인터럽트 벡터 테이블 초기화
    
    // 시스템 클럭 확인
    uint32_t sysClockHz = SysCtl_getClock(DEVICE_OSCSRC_FREQ); // 시스템 클럭 주파수 확인
    if (sysClockHz != 200000000)                    // 200MHz가 아닌 경우 오류 처리
    {
        canStatus = 0xFFFF;                         // 오류 상태 설정
        GPIO_writePin(34, 0);                       // LED OFF로 오류 표시
        ESTOP0;                                     // 디버깅용 정지
    }
    
    // CAN-A 초기화
    initCAN();                                      // CAN-A 모듈 초기화
    
    // 초기화 오류 확인
    if (canStatus != 1)                             // 초기화 실패 시 오류 처리
    {
        canStatus = 0xFFFF;                         // 오류 상태 설정
        GPIO_writePin(34, 0);                       // LED OFF로 오류 표시
        ESTOP0;                                     // 디버깅용 정지
    }
    
    // 글로벌 인터럽트 활성화
    EINT;                                           // 전체 인터럽트 활성화
    
    // Watchdog 활성화
    SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_WD);  // Watchdog 클럭 활성화
    SysCtl_serviceWatchdog();                       // Watchdog 서비스 시작
    
    // 테스트 데이터 준비
    uint8_t txData[8] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88}; // 송신 데이터 배열
    
    // 무한 루프
    for(;;)
    {
        // CAN 메시지 전송
        CAN_sendMessage(CANA_BASE, 1, 8, txData);   // 메시지 객체 1번으로 8바이트 데이터 전송
        
        // 디버깅용: 상태 표시
        GPIO_writePin(34, (canStatus == 1) ? 1 : 0); // 정상 동작 시 LED ON
        DEVICE_DELAY_US(1000000);                   // 1초 대기
    }
}

설명:

  • 기능: CAN-A를 통해 500kbps로 확장 ID(0x1FFFF123) 메시지 전송.
  • 설정: 비트율 500kbps, 메시지 객체 1번 사용, 확장 프레임.
  • GPIO: GPIO30(CAN-A TX), GPIO31(CAN-A RX), GPIO34(LED).
  • 출력: 확장 ID 메시지 주기적 전송, 정상 동작 시 LED ON.
  • 용도: 확장 ID를 사용하는 CAN 네트워크(예: CAN-FD 호환 시스템)에서 활용.

4.5. 예제 5: 다중 메시지 객체 사용

CAN-A를 사용하여 여러 메시지 객체로 다양한 ID의 메시지를 송수신합니다.

#include "driverlib.h"
#include "device.h"

// 디버깅용 상태 변수: CAN 모듈 상태 추적
volatile uint32_t canStatus = 0; // 0: 초기화 완료, 1: CAN 동작 중, 0xFFFF: 오류

// 송수신 데이터
uint8_t txData1[8] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}; // 송신 데이터 1
uint8_t txData2[8] = {0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10}; // 송신 데이터 2
uint8_t rxData1[8];              // 수신 데이터 1 저장 배열
uint8_t rxData2[8];              // 수신 데이터 2 저장 배열
volatile uint16_t rxFlag1 = 0;   // 수신 플래그 1
volatile uint16_t rxFlag2 = 0;   // 수신 플래그 2

// GPIO 초기화 함수
void initGPIO(void)
{
    // GPIO30을 CAN-A TX로 설정
    GPIO_setPinConfig(GPIO_30_CANA_TX);         // CAN-A 송신 핀으로 GPIO30 설정
    GPIO_setDirectionMode(30, GPIO_DIR_MODE_OUT); // 출력 모드로 설정
    GPIO_setPadConfig(30, GPIO_PULL_UP);        // 풀업 저항 활성화
    
    // GPIO31을 CAN-A RX로 설정
    GPIO_setPinConfig(GPIO_31_CANA_RX);         // CAN-A 수신 핀으로 GPIO31 설정
    GPIO_setDirectionMode(31, GPIO_DIR_MODE_IN); // 입력 모드로 설정
    GPIO_setPadConfig(31, GPIO_PULL_UP);        // 풀업 저항 활성화
    
    // 디버깅용 LED 설정 (GPIO34)
    GPIO_setPinConfig(GPIO_34_GPIO34);          // GPIO34를 일반 GPIO로 설정
    GPIO_setDirectionMode(34, GPIO_DIR_MODE_OUT); // 출력 모드로 설정
    GPIO_setPadConfig(34, GPIO_PULL_UP);        // 풀업 저항 활성화
    GPIO_writePin(34, 0);                       // 초기 LED 상태 OFF
}

// CAN 수신 인터럽트 서비스 루틴
__interrupt void canA0ISR(void)
{
    // 메시지 객체 3번에서 데이터 수신
    if (CAN_getInterruptCause(CANA_BASE) == 3)  // 메시지 객체 3번 확인
    {
        CAN_readMessage(CANA_BASE, 3, rxData1); // 데이터 읽기
        rxFlag1 = 1;                            // 수신 플래그 1 설정
    }
    // 메시지 객체 4번에서 데이터 수신
    else if (CAN_getInterruptCause(CANA_BASE) == 4) // 메시지 객체 4번 확인
    {
        CAN_readMessage(CANA_BASE, 4, rxData2); // 데이터 읽기
        rxFlag2 = 1;                            // 수신 플래그 2 설정
    }
    
    // 인터럽트 플래그 지우기
    CAN_clearInterruptStatus(CANA_BASE, CAN_INT_IE0); // 수신 인터럽트 플래그 클리어
    Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP9);    // PIE 그룹 9 ACK
}

void initCAN(void)
{
    // CAN-A 클럭 활성화
    SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_CANA); // CAN-A 모듈에 클럭 공급
    
    // CAN 모듈 초기화
    CAN_initModule(CANA_BASE);                      // CAN-A 모듈 기본 초기화
    
    // 비트율 설정: 500kbps
    CAN_setBitRate(CANA_BASE, DEVICE_SYSCLK_FREQ, 500000); // 비트율 설정
    
    // 송신 메시지 객체 설정: ID=0x123
    CAN_setupMessageObject(CANA_BASE, 1, 0x123,     // 메시지 객체 1번, ID 0x123
                          CAN_MSG_FRAME_STD,        // 표준 프레임
                          CAN_MSG_OBJ_TYPE_TX,      // 송신용 객체
                          0,                        // 마스크 없음
                          CAN_MSG_OBJ_NO_FLAGS);    // 추가 플래그 없음
    
    // 송신 메시지 객체 설정: ID=0x124
    CAN_setupMessageObject(CANA_BASE, 2, 0x124,     // 메시지 객체 2번, ID 0x124
                          CAN_MSG_FRAME_STD,        // 표준 프레임
                          CAN_MSG_OBJ_TYPE_TX,      // 송신용 객체
                          0,                        // 마스크 없음
                          CAN_MSG_OBJ_NO_FLAGS);    // 추가 플래그 없음
    
    // 수신 메시지 객체 설정: ID=0x456
    CAN_setupMessageObject(CANA_BASE, 3, 0x456,     // 메시지 객체 3번, ID 0x456
                          CAN_MSG_FRAME_STD,        // 표준 프레임
                          CAN_MSG_OBJ_TYPE_RX,      // 수신용 객체
                          0,                        // 마스크 없음
                          CAN_MSG_OBJ_RX_INT_ENABLE); // 수신 인터럽트 활성화
    
    // 수신 메시지 객체 설정: ID=0x457
    CAN_setupMessageObject(CANA_BASE, 4, 0x457,     // 메시지 객체 4번, ID 0x457
                          CAN_MSG_FRAME_STD,        // 표준 프레임
                          CAN_MSG_OBJ_TYPE_RX,      // 수신용 객체
                          0,                        // 마스크 없음
                          CAN_MSG_OBJ_RX_INT_ENABLE); // 수신 인터럽트 활성화
    
    // 인터럽트 활성화
    CAN_enableInterrupt(CANA_BASE, CAN_INT_IE0);    // 수신 인터럽트 활성화
    
    // CAN 모듈 활성화
    CAN_enableModule(CANA_BASE);                    // CAN-A 모듈 동작 시작
    
    // 상태 업데이트
    canStatus = 1;                                  // CAN 동작 중 상태로 설정
}

void main(void)
{
    // 시스템 클럭 및 주변 장치 초기화
    Device_init();                                  // PLL, Watchdog, 주변 장치 클럭 설정
    
    // GPIO 기본 초기화
    Device_initGPIO();                              // GPIO 기본 설정 초기화
    
    // CAN 관련 GPIO 설정
    initGPIO();                                     // CAN 및 디버깅용 GPIO 설정
    
    // 인터럽트 모듈 초기화
    Interrupt_initModule();                         // 인터럽트 컨트롤러 초기화
    Interrupt_initVectorTable();                    // 인터럽트 벡터 테이블 초기화
    
    // CAN 인터럽트 ISR 등록
    Interrupt_register(INT_CANA_0, &canA0ISR);      // 수신 인터럽트 서비스 루틴 등록
    
    // 시스템 클럭 확인
    uint32_t sysClockHz = SysCtl_getClock(DEVICE_OSCSRC_FREQ); // 시스템 클럭 주파수 확인
    if (sysClockHz != 200000000)                    // 200MHz가 아닌 경우 오류 처리
    {
        canStatus = 0xFFFF;                         // 오류 상태 설정
        GPIO_writePin(34, 0);                       // LED OFF로 오류 표시
        ESTOP0;                                     // 디버깅용 정지
    }
    
    // CAN-A 초기화
    initCAN();                                      // CAN-A 모듈 초기화
    
    // 초기화 오류 확인
    if (canStatus != 1)                             // 초기화 실패 시 오류 처리
    {
        canStatus = 0xFFFF;                         // 오류 상태 설정
        GPIO_writePin(34, 0);                       // LED OFF로 오류 표시
        ESTOP0;                                     // 디버깅용 정지
    }
    
    // 글로벌 인터럽트 활성화
    EINT;                                           // 전체 인터럽트 활성화
    
    // Watchdog 활성화
    SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_WD);  // Watchdog 클럭 활성화
    SysCtl_serviceWatchdog();                       // Watchdog 서비스 시작
    
    // 무한 루프
    for(;;)
    {
        // CAN 메시지 전송 (ID=0x123)
        CAN_sendMessage(CANA_BASE, 1, 8, txData1);  // 메시지 객체 1번으로 데이터 전송
        
        // CAN 메시지 전송 (ID=0x124)
        CAN_sendMessage(CANA_BASE, 2, 8, txData2);  // 메시지 객체 2번으로 데이터 전송
        
        // 디버깅용: 상태 표시
        GPIO_writePin(34, (canStatus == 1 && (rxFlag1 || rxFlag2)) ? 1 : 0); // 메시지 수신 시 LED ON
        DEVICE_DELAY_US(1000000);                   // 1초 대기
    }
}

설명:

  • 기능: CAN-A로 다중 메시지 객체를 사용해 두 개의 송신(ID 0x123, 0x124) 및 두 개의 수신(ID 0x456, 0x457) 처리.
  • 설정: 비트율 500kbps, 메시지 객체 1~4번 사용, 수신 인터럽트 활성화.
  • GPIO: GPIO30(CAN-A TX), GPIO31(CAN-A RX), GPIO34(LED).
  • 출력: 다중 ID 메시지 송수신, 수신 시 LED ON.
  • 용도: 복잡한 CAN 네트워크에서 여러 노드와 통신.

5. 추가 고려 사항

  • 비트율 계산: 비트율은 SYSCLK / (BRP * (TSEG1 + TSEG2 + 1))로 계산. 예: 200MHz 클럭, 500kbps → BRP=20, TSEG1=15, TSEG2=4.
  • CAN 트랜시버: 외부 CAN 트랜시버(SN65HVD230 등) 필요.
  • 메시지 필터링: ID 마스크로 특정 ID만 수신 가능.
  • GPIO 설정: CAN TX/RX 핀은 고속 신호를 위해 풀업 저항 조정 필요.
  • C2000Ware: 예제 코드는 C2000Ware의 DriverLib 기반. C:\ti\c2000에 설치.
  • 디버깅: CAN 분석기(예: PCAN)로 메시지 확인 권장.

키워드: TMS320F28388D, CAN, DriverLib, C2000, Controller Area Network, Code Composer Studio, 메시지 객체, 비트율, 인터럽트, 에러 처리, CAN 트랜시버, 확장 ID, 다중 메시지 객체

반응형