본문 바로가기
DSP, MCU/TMS320F2838x (C28x)

TMS320F28388D ] SCI (UART) 통신하기 - 수신 인터럽트를 통한 에코백

by eteo 2022. 9. 8.

설정은 이전 글에서 이어진다.

 

2022.09.07 - [DSP, MCU/TMS320F2838x (C28x)] - TMS320F28388D ] SCI (UART) 통신하기 - 송신

 

TMS320F28388D ] SCI (UART) 통신하기 - 송신

SCI : Serial Commnucation Interface 직렬 통신 인터페이스로 UART보다 광범위한 개념으로 쓰이지만 주로 UART 용도로 쓴다. 새 프로젝트를 만드는 것보다 .syscfg 가 있는 예제파일을 불러와 시작하는 것이

eteo.tistory.com

 

 

interrupt를 수행하는 함수를 Interrupt Handler 또는 ISR (Interrupt Service Routine) 이라고 표현한다.

그리고 핸들러 함수를 만들때는 앞에 __interrupt 키워드를 붙여 complier 가 이게 interrupt handler 라는 것을 알게 한다.

 

예시)

__interrupt void int_handler()
{
 unsigned int flags;
 ...
}

 

Handling Interrupt에 대한 설명은 Technical Reference Manual 145페이지 부터 매우 자세히 설명되어있다. 그리고 __interrupt Keyword 에 대해 더 알고 싶다면 Optimizing C/C++ Complier 109페이지에 설명이 나와있다.

 

 

 

 

 

아무튼 아래의 코드는 Technical Reference Manual 148페이지에 나와있는 절차를 따른 코드이다.

 

 

//
// Interrupt Handler
//

// 핸들러 함수 원형 선언
__interrupt void sciaRXFIFOISR(void);

uint16_t receivedChar;
uint16_t rxStatus = 0U;


//
// Main
//
void main(void)
{


    //
    // Initializes system control, device clock, and peripherals
    //
    Device_init();

    //
    // Initializes PIE and clear PIE registers. Disables CPU interrupts.
    // and clear all CPU interrupt flags.
    //
    Interrupt_initModule();

    //
    // Initialize the PIE vector table with pointers to the shell interrupt
    // Service Routines (ISR).
    //
    Interrupt_initVectorTable();


    // PIE vector init 과 Board init 사이에 아래 문구 추가
    
    // register handler and enable interrupt
    Interrupt_register(INT_SCIA_RX, sciaRXFIFOISR);
    Interrupt_enable(INT_SCIA_RX);
    
    // Issue PIE Ack 굳이 할필요는 없는거 같은데 안전빵코드
    Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP9);

    //
    // Board Initialization
    //
    Board_init();

    //
    // Enables CPU interrupts
    //
    Interrupt_enableMaster();


    //
    // Loop.
    //
    for(;;);
    
}

//
// sciaRXFIFOISR - SCIA Receive FIFO ISR
//
__interrupt void sciaRXFIFOISR(void)
{
    //
    // Read a character from the FIFO.
    //
    receivedChar = SCI_readCharBlockingFIFO(SCIA_BASE);

    rxStatus = SCI_getRxStatus(SCIA_BASE);
    if((rxStatus & SCI_RXSTATUS_ERROR) != 0)
    {
        //
        //If Execution stops here there is some error
        //Analyze SCI_getRxStatus() API return value
        //
        ESTOP0;
    }

    //
    // Echo back the character.
    //
    SCI_writeCharBlockingFIFO(SCIA_BASE, receivedChar);

    
    SCI_clearOverflowStatus(SCIA_BASE);
    //
    SCI_clearInterruptStatus(SCIA_BASE, SCI_INT_RXFF);

    //
    // Issue PIE ack
    //
    Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP9);
}

 

핸들러 함수를 정의하고 해야할 일은 PIE Interrupt Vectors 에 ISR의 위치(함수의 주소값)를 알려주는 일이다.

 

CPU가 평상시 하던일을 하다가 인터럽트가 걸리면 ISR로 점프하여 함수를 실행하는 데 그 점프해야하는 주소가 PIE Vector table의 address에 저장이 된다.

 

주소를 지정하는 일은 위 코드처럼 Interrupt_register(INT_SCIA_RX, sciaRXFIFOISR); 함수를 사용하면 되고 첫번째 매개변수가 hw_ints.h 에 정의된 PIE Interrupt Numbers 두번째 매개변수가 내가 만든 핸들러 함수명이다.

 

 

 

그리고 매뉴얼 설명에 나와있듯이 ISR 끝부분에서 Interrupt_clearACKGroup(INTERRUPT_ACK_GROUPx); 함수를 호출해서 PIEACK bit 를 clear 해주어야 한다.

 

 

에코백 테스트

 

 

 

참고.

SCI_readChar 함수는 4종류가 있고 다음과 같은 특징을 가지고 있다.

SCI_readCharBlockingFIFO(uint32_t base);
//! Gets a character from the receive FIFO for the specified port.  If there
//! are no characters available, this function waits until a character is
//! received before returning. Returns immediately in case of Error.

 

SCI_readCharBlockingNonFIFO(uint32_t base);
//! Gets a character from the receive buffer for the specified port.  If there
//! is no characters available, this function waits until a character is
//! received before returning.

 

 

SCI_readCharNonBlocking(uint32_t base);
//! Gets a character from the receive buffer for the specified port. This
//! function does not block and only reads the receive buffer.  The user should
//! use SCI_isDataAvailableNonFIFO() or SCI_getRxFIFOStatus() to determine if
//! the receive buffer or FIFO have data available.

 

 

SCI_readCharArray(uint32_t base, uint16_t * const array, uint16_t length);
//! Receives an array of characters from the receive buffer for the specified
//! port, and stores them as an array of characters starting at address
//! \e array.  This function waits until the \e length number of characters are
//! received before returning.