Microprocessor/DSP (TMS320F28x)

TR28335 개발 KIT CAN 통신

Dexter_- 2017. 6. 21. 16:13
728x90
반응형

 

 

CAN (Controller Area Network) ?

  • Bosch사에서 자동차 전장용으로 개발한 비동기식 직렬 통신의 한 방식
  • 2가닥(CAN H, CAN L)의 CAN BUS에 접속된 다수의 주변 장치들 간에 Half-Duplex 통신이 가능함
  • 멀티 마스터 구조를 가지며 N : N 통신이 가능함
  • Differential 신호 방식을 사용해 전기적인 노이즈에 매우 강하고, 하드웨어적인 오류 검출 및 처리 기능이 있기 때문에 높은 신뢰성을 가지고 있다. 주로 자동차에서 사용되지만 항공기, 각종 산업용 제어기, 빌딩 관리 등 사용 분야가 확대되는 추세임

 

 

TMS320F28335 eCAN Module 

 

  • CAN protocol version 2.0B
  • 지원 데이터 속도 최대 1Mbps
  • 32개의 사서함
    • 수신 또는 전송 구성 가능
    • 0 또는 8byte 데이터 구성
  • 저전력 모드 지원
  • Self-test 모드 지원

 

CAN Data Frame

 

32-bit Access 컨트롤 레지스터 및 Status 레지스터 사용법 

 

위 그림과 같이 ECanaRegs 레지스터에 값을 넣기 위해서 ECanaShadow 레지스터를 생성하여 원하는 레지스터 값을 세팅 후 대입하여 값을 쓴다.

 

 

SOURCE TR28335_Can.h

/*===============================================
 *
 * FILE  : TR28335_Can.h .2017
 * TITLE : TR28335 CAN (Controller Area Network)
 *
 *===============================================*/ 
#ifndef __TR28335_CAN_H__
#define __TR28335_CAN_H__
#ifdef _cplusplus
extern "C" {
#endif
#include <main.h>

#define SELF_TEST_MODE_DN   0
#define SELF_TEST_MODE_EN   1

void Initcan(void);
void CanLpb(void);
void SetCanStm(Uint16 mode);

#ifdef _cplusplus
}
#endif  /* extern "C"        */
#endif  /* __TR28335_CAN_H__ */
 

 

 

SOURCE TR28335_Can.c

/*===============================================
 *
 * FILE  : TR28335_Can.c .2017
 * TITLE : TR28335 CAN (Controller Area Network)
 *
 *===============================================*/ 
#include <TR28335_Can.h>

struct ECAN_REGS ECanaShadow;

static Uint16 gCanTxBuff[8];
static Uint16 gCanRxBuff[8];
static Uint16 gCanErrorCount;
static Uint16 gXint1Count;

static interrupt void can_rx_isr(void);
static void CanWData(Uint16 *data);

/*=======================================
*
* Name        : Initcan
* Type        : Fucntion
* Description : CAN Initialization
*
=========================================*/
void Initcan(void)
{
    Uint32 i;
    
    /* Vector Remapping */
    EALLOW;
    PieVectTable.ECAN0INTA = &can_rx_isr;
    EDIS;

    /* CAN setting */
    InitECanaGpio();                                /* Peripheral Bootload Pins Init */
    InitECana();

    /* 0번 MailBox 설정 */
    ECanaMboxes.MBOX0.MSGID.bit.IDE = 0;            /* ID 확장 여부 설정 : 11Bit ID 사용                            */
    ECanaMboxes.MBOX0.MSGID.bit.AAM = 0;            /* 응답모드 설정 (송신 메일박스만 유효함) : Nomal transmit mode */
    ECanaMboxes.MBOX0.MSGID.bit.STDMSGID = 0x555;   /* Mailbox ID 설정 : CAN2.0A 기준 11Bit ID                      */
    ECanaMboxes.MBOX0.MSGCTRL.bit.DLC = 8;          /* Mailbox Data-Lenth 설정 (최대 8byte 설정 가능) : 8 Byte      */
    ECanaMboxes.MBOX0.MDL.all = 0x00000000;         /* Mailbox 데이터 초기화                                        */
    ECanaMboxes.MBOX0.MDH.all = 0x00000000;         /* Mailbox 데이터 초기화                                        */

    /* 1번 MailBox 설정 */
    ECanaMboxes.MBOX1.MSGID.bit.IDE = 0;            /* ID 확장 여부 설정 : 11Bit ID 사용                            */
    ECanaMboxes.MBOX1.MSGID.bit.AME = 0;            /* Acceptance Mask 설정 : 사용안함                              */
    ECanaMboxes.MBOX1.MSGID.bit.STDMSGID = 0x555;   /* Mailbox ID 설정 : CAN2.0A 기준 11Bit ID                      */
    ECanaMboxes.MBOX1.MSGCTRL.bit.DLC = 8;          /* Mailbox Data-Lenth 설정 (최대 8byte 설정 가능) : 8 Byte      */
    ECanaMboxes.MBOX1.MDL.all = 0x00000000;         /* Mailbox 데이터 초기화                                        */
    ECanaMboxes.MBOX1.MDH.all = 0x00000000;         /* Mailbox 데이터 초기화                                        */

    /* 메일박스 송수신 설정 */
    ECanaShadow.CANMD.all = ECanaRegs.CANMD.all;
    ECanaShadow.CANMD.bit.MD0 = 0;                  /* Mailbox 0번 : 송신 */
    ECanaShadow.CANMD.bit.MD1 = 1;                  /* Mailbox 1번 : 수신 */
    ECanaRegs.CANMD.all = ECanaShadow.CANMD.all;

    /* 메일박스 Enable/Disable 설정 */
    ECanaShadow.CANME.all = ECanaRegs.CANME.all;
    ECanaShadow.CANME.bit.ME0 = 1;                  /* Mailbox 0번 : Enable */
    ECanaShadow.CANME.bit.ME1 = 1;                  /* Mailbox 1번 : Enable */
    ECanaRegs.CANME.all = ECanaShadow.CANME.all;    

    SetCanStm(SELF_TEST_MODE_EN);

    EALLOW;
    /* 메일박스 인터럽트 마스크 설정 */
    ECanaShadow.CANMIM.all = ECanaRegs.CANMIM.all;
    ECanaShadow.CANMIM.bit.MIM1 = 1;                /* Mailbox 1번 인터럽트 : Enable */
    ECanaRegs.CANMIM.all = ECanaShadow.CANMIM.all;

    /* 메일박스 인터럽트 라인 설정 */
    ECanaShadow.CANMIL.all = ECanaRegs.CANMIL.all;
    ECanaShadow.CANMIL.bit.MIL1 = 0;                /* Mailbox 1번 : 0번 인터럽트 라인 */
    ECanaRegs.CANMIL.all = ECanaShadow.CANMIL.all;

    /* 인터럽트 라인 Enable/Disable 설정 */
    ECanaShadow.CANGIM.all = ECanaRegs.CANGIM.all;
    ECanaShadow.CANGIM.bit.I0EN = 1;                /* 0번 인터럽트 라인 : Enable */
    ECanaRegs.CANGIM.all = ECanaShadow.CANGIM.all;
    EDIS;

    PieCtrlRegs.PIEIER9.bit.INTx5 = 1;              /* PIE 인터럽트 (ECAN0INTA) Enable */
    IER |= M_INT9;                                  /* CPU 인터럽트 (INT9) Enable      */
    
    for (i = 0; i < 8; i++)
        gCanTxBuff[i] = i;        
    for (i = 0; i < 8; i++)
        gCanRxBuff[i] = 0;

    gCanErrorCount = 0;
    gXint1Count = 0;    
}

/*====================================================
*
* Name        : can_rx_isr
* Type        : Interrupt
* Description : CAN Receive Interrupt Service Routine 
*
======================================================*/
static interrupt void can_rx_isr(void)
{
    /* 메일박스에 수신된 데이터를 메모리에 저장 */
    gCanRxBuff[0] = ECanaMboxes.MBOX1.MDL.byte.BYTE0;
    gCanRxBuff[1] = ECanaMboxes.MBOX1.MDL.byte.BYTE1;
    gCanRxBuff[2] = ECanaMboxes.MBOX1.MDL.byte.BYTE2;
    gCanRxBuff[3] = ECanaMboxes.MBOX1.MDL.byte.BYTE3;
    gCanRxBuff[4] = ECanaMboxes.MBOX1.MDH.byte.BYTE4;
    gCanRxBuff[5] = ECanaMboxes.MBOX1.MDH.byte.BYTE5;
    gCanRxBuff[6] = ECanaMboxes.MBOX1.MDH.byte.BYTE6;
    gCanRxBuff[7] = ECanaMboxes.MBOX1.MDH.byte.BYTE7;        

    /* CAN 메일박스에 데이터가 수신되면 해당 CANRMP 레지스터 비트를 클리어 */
    ECanaShadow.CANRMP.all = 0;
    ECanaShadow.CANRMP.bit.RMP1 = 1;
    ECanaRegs.CANRMP.all = ECanaShadow.CANRMP.all;

    PieCtrlRegs.PIEACK.all = PIEACK_GROUP9;         /* Acknowledge interrupt to PIE */    
}

/*=======================================
*
* Name        : CanWData
* Type        : Fucntion
* Description : CAN Write Data
*
=========================================*/
static void CanWData(Uint16 *data)
{
    /* CAN으로 송신할 데이터를 메일박스에 저장 */
    ECanaMboxes.MBOX0.MDL.byte.BYTE0 = data[0];
    ECanaMboxes.MBOX0.MDL.byte.BYTE1 = data[1];
    ECanaMboxes.MBOX0.MDL.byte.BYTE2 = data[2]; 
    ECanaMboxes.MBOX0.MDL.byte.BYTE3 = data[3]; 
    ECanaMboxes.MBOX0.MDH.byte.BYTE4 = data[4];
    ECanaMboxes.MBOX0.MDH.byte.BYTE5 = data[5];
    ECanaMboxes.MBOX0.MDH.byte.BYTE6 = data[6]; 
    ECanaMboxes.MBOX0.MDH.byte.BYTE7 = data[7];     
    
    /* 메일박스 데이터 전송 요청 */
    ECanaShadow.CANTRS.all = 0;
    ECanaShadow.CANTRS.bit.TRS0 = 1;
    ECanaRegs.CANTRS.all = ECanaShadow.CANTRS.all;

    /* 메일박스 데이터 송신 완료 플래그 대기 */
    do {
        ECanaShadow.CANTA.all = ECanaRegs.CANTA.all;
    } while (!ECanaShadow.CANTA.bit.TA0);

    /* 메일박스 데이터 송신 완료 플래그 초기화 */
    ECanaShadow.CANTA.all = 0;
    ECanaShadow.CANTA.bit.TA0 = 1;
    ECanaRegs.CANTA.all = ECanaShadow.CANTA.all;    
}

/*=======================================
*
* Name        : CanLpb
* Type        : Fucntion
* Description : CAN Loop-Back Test
*
=========================================*/
void CanLpb(void)
{
    Uint32 i;
    
    CanWData(gCanTxBuff);
    for (i = 0 ; i < 20000000; i++);

    for (i = 0; i < 8; i++) {
        if (gCanTxBuff[i] != gCanRxBuff[i])
            gCanErrorCount++;    
    }

    for (i = 0; i < 8; i++) {
        gCanTxBuff[i] += 1;
        gCanTxBuff[i] &= 0xFF;
    }
}

/*=========================================
*
* Name        : SetCanStm
* Type        : Fucntion
* Description : CAN Self Test Mode Setting
*
===========================================*/
void SetCanStm(Uint16 mode)
{
    /* 자체 LoopBack 테스트를 위한 설정 */
    EALLOW;
    ECanaShadow.CANMC.all = ECanaRegs.CANMC.all;
    if (mode == SELF_TEST_MODE_EN)
        ECanaShadow.CANMC.bit.STM = 1;                 /* CAN Self-test Mode 설정 */
    else
        ECanaShadow.CANMC.bit.STM = 0;
    ECanaRegs.CANMC.all = ECanaShadow.CANMC.all;
    EDIS;       
}
 

 

 

코드분석 

Step .1 ECAN0INTA : PIE Vector Table 에 Interrupt Service Routine 을 등록 한다.

 

 

 

Step .2 MSGID - IDE : ID 확장 여부 설정 비트이다. AMI 비트에 따라 상태가 바뀌며, 현재 코드에서는 Standard 모드로 설정한다.

 

 

 

Step .3 MSGID - AAM : 자동 응답 모드 비트이다. 1을 넣으면 자동응답 모드이고, 0을 넣으면 일반 모드를 전송 합니다. 이 모드는 송신 메일박스에만 유효하다.

 

Step .4 MSGID - STDMSGID : 이 비트는 CAN2.0A 기준 이라 데이터 시트에 나와 있지 않으나, 메일박스의 ID를 설정하는 비트이다.

 

 

 

Step .5 MSGCTRL - DLC : 데이터의 길이를 결정하는 비트이다. 송/수신 바이트 길이를 결정한다. 유효한 값 범위는 0byte 에서 8byte 이다.

 

 

 

Step .6 MDL, MDH : 메일박스 데이터 레지스트 이다.

 

 

 

Step .7 CANMD[31:-] : 32개의 메일박스의 송/수신 모드를 결정하는 비트이다. 1을 넣으면 수신, 0을 넣으면 송신으로 설정 된다.

 

 

 

Step .8 CANME[31:0] : 32개의 메일박스 활성/비활성 제어 비트이다. 사용하지 않는 메일박스는 추가 메모리로 사용할 수 있다. 1을 쓰면 메일박스가 활성화 된다. 0을 쓰면 메일박스가 비활성화 되며 추가 메모리로 사용 가능하다.

 

 

 

Step .9 CANMC - STM : 자체 테스트 모드이다. 이 비트는 EALLOW로 보호 받고 있다. 1을 넣으면 자체 테스트 모드이고, 0을 넣으면 비활성화 된다.

 

 

 

Step .10 CANMIM - MIM0~31 : 메일박스 인터럽트 마스크 비트이다. 1을 넣으면 메일박스 인터럽트가 활성화 되고, 0을 넣으면 비활성화 된다.

 

 

 

Step .11 CANMIL - MIL0~31 : 메일박스 인터럽트 라인을 설정한다. 1을 넣으면 1번 인터럽트 라인, 0을 넣으면 0번 인터럽트 라인이 설정된다. 

 

 

 

Step .12 CANGIM - I0EN : 0번 인터럽트 라인 활성/비활성을 설정한다. 1을 넣으면 0번 인터럽트 라인이 활성화 되고, 0을 넣으면 0번 인터럽트 라인이 비활성화 된다.

 

 

 

Step .13 CANRMP - RMP31~0 : 데이터가 수신되면 pendig 시키는 비트이다. 1을 쓰면 클리어 된다.

 

 

 

Step .14 CANTRS - TRS31~0 : 전송 요청 설정 비트이다. 해당 메일박스에 1을 쓰면 메시지가 전송된다.

 

 

 

Step .15 CANTA = TA31~0 : 해당 메일박스에 전송요청이 완료되었는지 알려주는 비트이다. 성공적으로 전송이 완료되면 1이 읽힌다. 1을 쓰면 이 비트는 초기화 된다.

 

 

 

결과 

 

 

 

 

728x90
반응형