본문 바로가기
개발/TI_TMS320

TMS320 F28069 CCS SCI(UART) printf source : TI 입문

by 즐기며 2025. 3. 21.

 

TI TMS320 입문 연재 입니다.

 

1.  CCS, C2000Ware, sprc191 (sprc097) 설치, compile

2.  XDS100, XDS200 로 CCS Debug 하기 

3.  UniFlash 로 (CCS 없이) FW Download 하기(Driver 설치)  

4.  C2Prog 로 (CCS 없이) FW Download 하기 

5.  C2000Ware Sample code 를 다른곳으로 가져 가기  

6.  CCS v20 Project 만들기  

7.  CCS,  다른 ( 옛날 ) Compiler (CGT) 버전 설치  

8.  TMS320 F28069 CCS SCI(UART) source              == 본글

9.  TMS320 F28069 CCS PWM source     

10.  TMS320 F28069 CCS ADC source   


ㄱ. 
 TMS320 error: program will not fit into available memory  

==========================================

본글 목차    250321

 

1. 들머리

2. main.c ( Example_2806xSci_FFDLB_int.c ) 풀이

    1) main 함수 부분

    2) SCI (UART) 초기화 하는 데

    3) 문자 보내는 데

    4) 문자 받아 저장 하는 데

    5) 받아 저장한 문자 처리 하는데

3. sprintf, printf

 

4. 소스 

 

================================

 

1. 들머리

> Tx 는 일반(Normal) 방식, 즉 interrupt 안쓰고,

   Rx 는 Interrupt 쓰는 방식으로 하였읍니다.

 

> 이런 방식을 인터넷에 뒤졌는데, 잘 안나오네요.. 

   이거 저거 (C2000Ware 등) 에서 가위질 하고, 쬐끔 고쳤읍니다. 

 

> rx 로 1바이트 받을때 마다 받은거 대소 문자 바꾸어 tx 하는 것입니다.

   본래 제공 되는 예제는 2, 4 바이트 받는거로 되어 있는데, 불편 하여 1바이트 받는거로 바꾸었읍니다.

   본 예제는 간단히 영문 대소문자만 잘 룹백 합니다... 숫자 등은 이상하게 됩니다. 

   뭐 개념 정리 용으로 그리 만든 것입니다.  

 

2. main.c ( Example_2806xSci_FFDLB_int.c ) 풀이

1) main 함수 부분

//
// Main
//
void main(void)
{
    char *msg;

    //
    // Step 1. Initialize System Control:
    // PLL, WatchDog, enable Peripheral Clocks
    // This example function is found in the F2806x_SysCtrl.c file.
    //
    InitSysCtrl();

    //
    // Step 2. Initalize GPIO:
    // This example function is found in the F2806x_Gpio.c file and
    // illustrates how to set the GPIO to it's default state.
    //
    //InitGpio();    // 이 보기에서는 쓰는 GPIO 가 따로 없어, 안씀
    
    //
    // Setup only the GP I/O only for SCI-A and SCI-B functionality
    // This function is found in F2806x_Sci.c
    //
//    InitSciGpio();  // scia_fifo_init()  로 옮김,

    //
    // Step 3. Clear all interrupts and initialize PIE vector table:
    // Disable CPU interrupts
    //
    DINT;

    //
    // Initialize PIE control registers to their default state.
    // The default state is all PIE interrupts disabled and flags
    // are cleared.
    // This function is found in the F2806x_PieCtrl.c file.
    //
    InitPieCtrl();

    //
    // Disable CPU interrupts and clear all CPU interrupt flags
    //
    IER = 0x0000;
    IFR = 0x0000;

    //
    // Initialize the PIE vector table with pointers to the shell Interrupt
    // Service Routines (ISR).
    // This will populate the entire table, even if the interrupt
    // is not used in this example.  This is useful for debug purposes.
    // The shell ISR routines are found in F2806x_DefaultIsr.c.
    // This function is found in F2806x_PieVect.c.
    //
    InitPieVectTable();

    //
    // Interrupts that are used in this example are re-mapped to
    // ISR functions found within this file.
    //
    EALLOW;  // This is needed to write to EALLOW protected registers
    PieVectTable.SCIRXINTA = &sciaRxFifoIsr;        // PIE Group 9, INT1   SCI RX INT A
//    PieVectTable.SCITXINTA = &sciaTxFifoIsr;      // PIE Group 9, INT2   SCI TX INT A 
    EDIS;   // This is needed to disable write to EALLOW protected registers

    //
    // Step 4. Initialize all the Device Peripherals
    // This function is found in F2806x_InitPeripherals.c
    //
    //InitPeripherals(); // Not required for this example
    scia_fifo_init();  // Init SCI-A 초기화

    //
    // Step 5. User specific code, enable interrupts
    // 초기 데이타 송신
    //
    msg = "\nHello SCI World!\n";
    scia_msg(msg);

    //
    // Enable interrupts required for this example
    //
    PieCtrlRegs.PIECTRL.bit.ENPIE = 1;   // Enable the PIE block
    PieCtrlRegs.PIEIER9.bit.INTx1=1;     // PIE Group 9, 인터럽트 1 (SCI-A RX) 활성화
//    PieCtrlRegs.PIEIER9.bit.INTx2=0;     // PIE Group 9, INT2   SCI TX INT A

    IER |= M_INT9;                      // Enable CPU INT, M_INT9 == 0x100(SCIA_RX)
    EINT;
    scia_msg("333");
    
    //
    // Step 6. IDLE loop. Just sit and loop forever (optional)
    //
    for(;;){
  //   scia_msg("444");
        parseByte();
    }
}

 

 

2) SCI (UART) 초기화 부분

//
// scia_fifo_init - 
//
void
scia_fifo_init()
{
    Uint16 sci16baud;
    
     InitSciaGpio();     //   InitSciGpio();
   
    SciaRegs.SCICCR.all =0x0007;    // 1 stop bit,  No loopback, No parity,8 char bits, async mode, idle-line protocol
    
    SciaRegs.SCICTL1.all =0x0003;   // TX, RX 활성화, 내부 SCICLK, RX ERR, SLEEP, TXWAKE 비활성화
//    SciaRegs.SCICTL2.all =0x0003;
    SciaRegs.SCICTL2.bit.TXINTENA =0;   // TX 인터럽트 비활성화
    SciaRegs.SCICTL2.bit.RXBKINTENA =0; // RX 브레이크 인터럽트 비활성화 (필요 없음)
//    sci16baud = CalculateBaudRateAt90Mhz(9600); SciaRegs.SCIHBAUD = (sci16baud >> 8) & 0xFF ;    SciaRegs.SCILBAUD = sci16baud & 0xFF;
    SciaRegs.SCIHBAUD = 1;    SciaRegs.SCILBAUD = 0x24; // baud rate 설정 (LSPCLK 22.5MHz에서 9600 baud)
 //   SciaRegs.SCICCR.bit.LOOPBKENA =1;   // Enable loop back, 이거 하면 난리남...뭔데 이거 ?

    SciaRegs.SCIFFTX.all=0xE040;        // Tx FIFO 사용 설정  

    // 수신 FIFO 1바이트로 설정 하고, 그거 차면 인터럽트 발생 하도록
    SciaRegs.SCIFFRX.all=0x2041;        // RX FIFO RESET enable, RX FF I EN A, Receive FIFO interrupt level bits==1 ( 1 byte 받으면 발생)
    SciaRegs.SCIFFRX.bit.RXFFIENA = 1; // RX FIFO 인터럽트 활성화, 이줄 없으면 인터럽트 안됨 !!!!! 
    SciaRegs.SCIFFCT.all=0x00;

    SciaRegs.SCICTL1.all =0x0023;       // Relinquish SCI from Reset
    SciaRegs.SCIFFTX.bit.TXFIFOXRESET=1;
    SciaRegs.SCIFFRX.bit.RXFIFORESET=1;

    // 보류 중인 인터럽트 클리어
    SciaRegs.SCIFFTX.bit.TXFFINTCLR = 1;
    SciaRegs.SCIFFRX.bit.RXFFINTCLR = 1;    
}

 

3)  문자 보내는 데

//
// scia_xmit - Transmit a character from the SCI
//
void
scia_xmit(int a)
{
    while (SciaRegs.SCIFFTX.bit.TXFFST != 0)   {    }
    SciaRegs.SCITXBUF=a;
}

//
// scia_msg - 
//
void
scia_msg(char * msg)
{
    int i;
    i = 0;
    while(msg[i] != '\0')
    {
        scia_xmit(msg[i]);
        i++;
    }
}

 

 

4) 문자 받아 저장 하는 데

//
// sciaRxFifoIsr - 
//
__interrupt void
sciaRxFifoIsr(void)
{
    rdBytes();
//    scia_msg("555");

    SciaRegs.SCIFFRX.bit.RXFFOVRCLR=1;   // Clear Overflow flag
    SciaRegs.SCIFFRX.bit.RXFFINTCLR=1;   // Clear Interrupt flag

    PieCtrlRegs.PIEACK.all |= 0x100;       // Issue PIE ack
}

void rdBytes()
{
    Uint16 ReceivedChar;

//    while(SciaRegs.SCIFFRX.bit.RXFFST == 1)
    {
        ReceivedChar = SciaRegs.SCIRXBUF.all;

        if(g_u32comRbytes < RXBUFSIZE)  {  					// Check if buffer full
            rRawDataA[g_u32comRhead] = ReceivedChar;
            g_u32comRhead = (g_u32comRhead == (RXBUFSIZE - 1)) ? 0 : (g_u32comRhead + 1);
            g_u32comRbytes++;				
        }
    }    
}

 

5) 받아 저장한 문자 처리 하는데

void Minus1Byte(){ g_u32comRtail = (g_u32comRtail == (RXBUFSIZE - 1)) ? 0 : (g_u32comRtail + 1); g_u32comRbytes--;}
void parseByte()
{
    Uint16 ReceivedChar;

    while(g_u32comRbytes) {   
        ReceivedChar = rRawDataA[ g_u32comRtail ];
        ReceivedChar ^= 0x0020;   // 대소문자 반전 시키기
        scia_xmit( ReceivedChar );
        Minus1Byte();
    }
}

> 여기서 는 간단하게, 저장한 문자 꺼내고,

> 대소 문자 반전 하고,

> 다시 송신 하였는데,

 

> 이부분을 원하시는 데로 바꾸어 사용 하시면 됩니다.

 

 

 

3. sprintf, printf

1) TI 는 printf 에 대하여 많이 인색 합니다. 느끼기에 쓰지 말라는거 같군요.

   어째든 printf 까지는 안되고, sprintf 만 조금 되도록 하였읍니다.

   자세한것은 소스 참고 하시고,

#include <stdio.h>      // for use sprintf()

    char *pMsg;
    int n = 0;
    unsigned int m=33; 
    
    pMsg = "\r\nHello World !\r\n\0";
    scia_msg(pMsg);
    // printf("Hello World %d\n", 2);  // printf 안됨

    sprintf( prBuf, "Ha00  \r\n");  scia_msg(prBuf);         // 문자

    sprintf( prBuf, "Ha11~ %d  \r\n", -5);  scia_msg(prBuf);  // 정수(+,-)     
    sprintf( prBuf, "Ha11~ %u  \r\n", 10);  scia_msg(prBuf);  // 양수(+)     
    
    sprintf( prBuf, "Ho22~ %Ld  \r\n", n);  scia_msg(prBuf);  // 큰정수  
    sprintf( prBuf, "Ho33~ %Lu  \r\n", m);  scia_msg(prBuf);  // 큰양수

//    sprintf( prBuf, "Ho44~ %f  \r\n", 3.3);  //   float 안됨
//    scia_msg(prBuf);

 

2)  써 본거는 다음 입니다.

d: 숫자( + , - )

u: 양수 ( + )

Ld : 큰 수자

Lu : unsigned int

 

3) 해봐서 안된거는 

- float 

- printf

입니다.

 

> 250530 일자 부터,  소스에 들어 있읍니다.

 

4) sprintf 를 쓰기 위해서는 stdio.h 를 include 해야 합니다.

#include <stdio.h>      // for use sprintf()

 

 

5) sprintf 에서 상수를 프린트 하기 위해서 즉 sprintf( buf, "aaa %d", 30 ); 과 같은거

compile 옵션에서 --printf_support=minimal 을 해 주면 되는데,

> Project > Properties ( ALt+Enter )

 

> Tools > C2000 Compiler > Advanced Options > Language Options

     > Level of printf/scanf ~( --printf_support ) > minimal 또는 full

 

6) 변수를 쓰기 위해서는  

compile 옵션에서  --printf_support=full  을 해줘야 합니다,

  뭐 상수만 프린트 하는거는 거의 없을테니 "full" 을 해줘야 겠읍니다.

 

7)  위에서도 말씀 드렸드시 printf 를 쓰기 위해 메모리가 많이 먹으니 

> 가능하면 쓰지 마시고,

> 쓰더라도 %d 만 쓰시고, 

 

8) 뭐 다 아시겠지만, float 를 %d 로 하기 위해서는

float f = -1203.05
char a,b,c;
char prBuf[100];

    a = (int) ( f ) / 100 ;
    b = abs( (int) ( f ) ) % 100;
    c = abs( (int) ( (f - (int) f)  * 100 ) )  % 100 ;

    sprintf( prBuf, " f = %d%02d.%02d \n", a, b, c );
    scia_msg(prBuf);

  

와 같이 하는것도 하나의 방법이라 하겠읍니다.

함수로 만들어 보았읍니다.

// Fraction part of float 0.AABBCCDD  , 1:AA, 2:BB, 3:CC 
// floatFrac(f,1) :소수 첫 두자리
char floatFrac(float f, unsigned char n){
    f = f - (int)f;		// 소수 부분 구하기
    switch(n){
        case 1: default: return abs( (int) (f * 100) ); break;		// AA 첫 2자리
        case 2: return abs ( (int) (f * 10000) % 100); break;		// BB 3,4 자리
        case 3: return abs ( (int) (f * 1000000) % 100); break;		// CC 5,6 자리
    }
}

// 부를때
    sprintf(prBuf, "%5d.%02d%02d", (int) f1, floatFrac(f1, 1), floatFrac(f1, 2));
    scia_msg(prBuf);

/////////////  본 내용은 아래 첨부 source 에는 들어 있지 않읍니다.

 

 

4. 소스

처음만들고 조금씩 고친거 계속 올리고 있읍니다, 맨 아래꺼가 가장 최신 입니다.

   

ti-tms320f28069-scia-uart_loopback_Rx_interrupts-250321.zip
0.29MB

 

ti-tms320f28069-scia-uart_loopback_Rx_interrupts-250401.zip
0.29MB

 

250530

ti-tms320f28069-sci-uart_sprint-250530.zip
0.78MB

 

ti-tms320f28069-sci-uart_sprint-250602.zip
0.29MB

 

 

ti-tms320f28069-sci-uart_sprintf-250604.zip
0.29MB