2011년9월5일_ARM_AT91SAM7S256 DBGU모드와 1Bytes송수신함수, 문자열을 전송하는 함수, 컴퓨터(PC)와 ARM보드간 RS232인터페이스로 연결하여 하이퍼터미널에서 입력한 문자로 ARM보드제어(LED, LCD등등)



● AT91SAM7S256 DBGU모드

image  

AT91SAM7S256 MCU는 시리얼통신에서 통신속도(보레이트), 데이터비트, 정지비트, 핸드쉐이킹 뿐만 아니라 통신모드가 존재한다.
USART장치에는 적외선 통신(IrDA)을 위한 모드도 있으나 DBGU에는 없다.
DBGU은 USART 기능의 일부를 상속받은 것 처럼 상기의 네 가지 모드를 가진다.
※ USART의 기능이 더 많다.

일반적으로 PC와 통신을 하려면 정상 모드를 사용해야 하고,
만약 ARM Board밖에 없는데 테스트를 해야 하는 상황이라면 로컬 루프백 모드를 사용하면 되겠다.
그리고 PC와 ARM Board사이에 전송선과 PC에 작성된 어플리케이션을 테스트하고 싶다면 자동에코나 리모트 루프백 모드를..
사용하면 ARM Board의 F/W와는 무관하니 마음껏 전송라인과 어플리케이션을 테스트할 수 있을 것이다.
★ 루프백은 TCP/IP소켓통신에서의 로컬루프백주소 127.0.0.1과 같은 것이라 보면 된다.

그럼 이를 코드로 표현해 보기 위해 레지스터를 살펴보자.

image

Datasheet p.224 (2011년 5월판)을 보면 모드설정을 위한 레지스터의 이름이 DBGU_MR이라는 것을 알 수 있다.


image

DBGU모드 관련 레지스터인 DBGU_MR을 살펴보니 9~11번 비트와 14~15번 비트만 사용하고,
패리티을 없애는 설정을 하려고 보니 1 x x이다. x는 Don’t care로 0 또는 1 어떤 값이 들어가도 상관없다는 뜻이나..
우리는 0을 넣자. 그래서 1 0 0 을 넣어야 하니 이를 십진수로 바꾸면 4이다.
4를 9번 좌측으로 시프트하면 패리티설정은 끝난다.

이제 중요한 모드설정을 해야한다.
노멀모드가 윤교수님 책의 정상모드로 PC와 통신시에 해야 되는 모드이다.
0 0을 넣어야 하니 아무일도 하지 않아도 되나 0을 14번 시프트하자.
이를 코드로 바꾸면 아래와 같다.

// 5. 포트 모드 설정.
DBGU_MR = (0 << CHMODE) | (4 << PAR);    //노멀모드, 패리티x




● 1Byte 전송함수 Send_Char()

순서
① DBGU_SR 레지스터의 1번 비트 TXRDY가 1이 될 때까지 대기. 0이면 전송불가. (블로킹) 
② DBGU_THR에 전송할 데이터를 쓰기.

   1: / 7. Data송신용 함수의 제작
   2: void Send_Char(unsigned char ucSData)
   3: {
   4:     // 7-2  DBGU_SR레지스터 폴링 (송신이 가능한지 check)
   5:     while(0 == (DBGU_SR & (1 << TXRDY)));        //TXRDY비트 검사하여 1이면 탈출.
   6:                                             // 1이면 송신준비완료
   7:     // 7-3 DBGU 유닛에 문자 전송.
   8:     DBGU_THR = ucSData;        //송신버퍼에 데이터 넣음.
   9:  
  10:     return ;
  11: }

설명은 노트참조



● 문자열 전송함수 Send_String()

변수를 쓰지 말고 아래와 같은 원형의 함수를 작성하라.

void Send_String(void *vpData)


   1: //문자열을 보내는 함수
   2: void Send_String(void *vpData)
   3: {
   4:     //while문과 Send_Char() 만 사용. 변수 추가하지 말 것.
   5:     while('\0' !=  (/*(unsigned char)*/ *((unsigned char *)vpData)))
   6:     {
   7:         Send_Char(/*(unsigned char)*/ *((unsigned char *)vpData));
   8:         (unsigned char *)vpData++;
   9:     }    
  10:  
  11:     return ;
  12: }

void포인터라 크기를 알 수 없으니 바로 읽어 올 수는 없다.
그러므로 1Byte씩 Send_Char()의 인자의 데이터type과 맞추기 위해 (unsigned char *)로 캐스팅한다.
캐스팅만 하면 그 자체는 아직 주소값이 들어 있으므로 *를 써서 주소값을 참조하여 1Byte씩 읽어 올 수 있도록 한다.
while문의 종료 조건은 문자열의 끝인 NULL문자가 될 때까지이고,
최초부터 검사하여 계속 vpData의 주소값을 1Byte씩 증가시켜 1Byte를 읽어와 Send_Char()로 전송한다.
8행의 캐스팅은 필요없다고 하나 있으면 더 안전해 보인다.
증가연산자 ++을 캐스팅 왼쪽에 두면 경고메시지가 뜬다.



● DBGU관련 함수와 레지스터 모음 DBGU.h와 DBGU.c

   1: #ifndef __DBGU_H__
   2: #define __DBGU_H__
   3:  
   4: /*********************************************************
   5:                     DBGU (AT91SAM7S256)
   6: *********************************************************/
   7: #define    DBGU_CR    (*(volatile unsigned int *)0xFFFFF200)        //컨트롤 #define    DBGU_MR    (*(volatile unsigned int *)0xFFFFF204)        //모드
   8: #define    DBGU_IDR    (*(volatile unsigned int *)0xFFFFF20C)        //인터럽트 비활성.
   9: #define    DBGU_SR    (*(volatile unsigned int *)0xFFFFF214)        //상태 #define    DBGU_BRGR    (*(volatile unsigned int *)0xFFFFF220)        //보레이트
  10: #define    DBGU_THR    (*(volatile unsigned int *)0xFFFFF21C)        //송신 홀딩 
  11: #define    DBGU_RHR    (*(volatile unsigned int *)0xFFFFF218)        //송신 홀딩 
  12: //레지스터 각 비트
  13: #define    RSTRX        2
  14: #define    RSTTX        3
  15: #define    CHMODE        14
  16: #define    PAR            9
  17: #define    TXEN        6
  18: #define    RXEN        4
  19: #define    TXRDY        1
  20: #define    RXRDY        0
  21:  
  22: //보레이트
  23: #define    MCK        48000000
  24: #define    BRATE    115200
  25: #define    CD        (MCK / (16 * BRATE))    
  26:  
  27: void DBGU_INIT();
  28: void Send_Char(unsigned char ucSData);
  29: unsigned char Recv_Char();
  30: void Send_String(void *vpData);
  31:  
  32: #endif    //__DBGU_H__
  33:  
   1: #include "PIOA.h"
   2: #include "DBGU.h"
   3:  
   4: //DBGU초기화
   5: void DBGU_INIT()
   6: {
   7:     // 1.송/수신부를 리셋.
   8:     DBGU_CR = (1 << RSTRX) | (1 << RSTTX);    //송/수신부를 리셋시키고 동작을 중지 시킴.
   9:     // 2. 인터럽트 비활성
  10:     DBGU_IDR = 0xFFFFFFFF;        //관련 인터럽트 비활성화
  11:     // 3. 외부 연결용 pin설정.
  12:     PIOA_ASR = (1 << DRXD) | (1 << DTXD);        //Peripheral A 사용.      PIOA_BSR = 0;    //B모드 비활성.
  13:     PIOA_PDR = (1 << DRXD) | (1 << DTXD);        //I/O포트로 사용하지 않음.
  14:     // 4. 포트 속도 설정.
  15:     DBGU_BRGR = CD;            //115200bps
  16:     // 5. 포트 모드 설정.
  17:     DBGU_MR = (0 << CHMODE) | (4 << PAR);    //노멀모드, 패리티x
  18:     // 6. 송/수신 모드 활성화
  19:     DBGU_CR = (1 << TXEN) | (1 << RXEN);        //송/수신 허용
  20:     
  21:     return ;
  22: }
  23:  
  24: // 7. Data송신용 함수의 제작
  25: void Send_Char(unsigned char ucSData)
  26: {
  27:     // 7-2  DBGU_SR레지스터 폴링 (송신이 가능한지 check)
  28:     while(0 == (DBGU_SR & (1 << TXRDY)));        //TXRDY비트 검사하여 1이면 탈출.
  29:                                             // 1이면 송신준비완료
  30:     // 7-3 DBGU 유닛에 문자 전송.
  31:     DBGU_THR = ucSData;        //송신버퍼에 데이터 넣음.
  32:  
  33:     return ;
  34: }
  35:  
  36:  
  37: // 8. Data 수신용 함수의 제작
  38: unsigned char Recv_Char()
  39: {
  40:     // 8-2 DBGU_SR레지스터 폴링. (수신가능하지 check)
  41:     while(0 == (DBGU_SR & (1 << RXRDY)));        //RXRDY비트 검사하여 1이면 탈출.
  42:                                             // 1이면 수신준비완료.
  43:     return DBGU_RHR;        //수신버퍼의 값을 리턴.
  44: }
  45:  
  46:  
  47: //문자열을 보내는 함수
  48: void Send_String(void *vpData)
  49: {
  50:     //while문과 Send_Char() 만 사용. 변수 추가하지 말 것.
  51:     while('\0' !=  (/*(unsigned char)*/ *((unsigned char *)vpData)))
  52:     {
  53:         Send_Char(/*(unsigned char)*/ *((unsigned char *)vpData));
  54:         (unsigned char *)vpData++;
  55:     }    
  56:  
  57:     return ;
  58: }
  59:  



● PC와 연결하여 ARM Board에 연결된 LED를 제어하는 소스코드 (전체)

   1: /*********************************************************
   2: 
   3:     제    목: PC에서 ARM Board제어.
   4:     
   5: *********************************************************/
   6: #include "PIOA.h"
   7: #include "DBGU.h"
   8: #include "LCD.h"
   9: #include "PMC.h"
  10:  
  11: #define    PIOA        2    //PIOA PID
  12: #define    LED1        0        // ARM보드 확인을 위해 임시로 추가.
  13: #define    LED2        1        // ARM보드 확인을 위해 임시로 추가.
  14:  
  15: void one(void);
  16: void two(void);
  17:  
  18: int main(void)
  19: {
  20:     unsigned char ucRData;
  21:     
  22:     PORT_INIT();
  23:     LCD_INIT();
  24:     LCD_String("Test DBGU");
  25:     DBGU_INIT();    
  26: /*
  27:     Send_Char('1');
  28:     Send_Char('2');
  29:     Send_Char('3');
  30:     Send_Char('\n');
  31:     Send_Char('\r');
  32: */
  33:     Send_String("\n\r터미널창에 '1'을 입력하면 AT91SAM7S256 Board에 연결된 LED(PA0)가 toggle되고,");
  34:     Send_String("\n\r'2'를 입력하면 CLCD와 터미널에 문자열 \"Hello\"출력.\n\r");
  35:         
  36:     // LED가 달린 port초기화
  37:     PIOA_PER = (1 << LED1) | (1 << LED2);
  38:     PIOA_OER = (1 << LED1) | (1 << LED2);
  39:     PIOA_PPUDR = (1 << LED1) | (1 << LED2);
  40:     PIOA_SODR = (1 << LED1) | (1 << LED2);
  41:     //PIOA_IFER = (1 << LED1) | (1 << LED2); //그림 1.5.20에는 글리치 필터가 연관되어 보이나 비활성이라도 되네.
  42:     // 전력공급, PIOA에 클록이 공급되야 입력을 받을 수 있다.
  43:     PMC_PCER = (1 << PIOA);
  44:  
  45:     while(1)
  46:     {    
  47:         ucRData = Recv_Char();
  48:  
  49:         switch(ucRData)
  50:         {
  51:             case '1':
  52:                 one();
  53:                 break;
  54:  
  55:             case '2':
  56:                 two();
  57:                 break;
  58:                 
  59:             default:
  60:                 break;
  61:         }
  62:  
  63:     }
  64:     
  65:     while(1);            //return되면 안됨. 돌아갈 곳이 없어. 집이 없어. 
  66:  
  67:     return 0;
  68: }
  69:  
  70: void one()
  71: {
  72:     if(0 != (PIOA_PDSR & (1 << LED1)))
  73:     {
  74:         PIOA_CODR = (1 << LED1);
  75:         LCD_Cursor(1, 0);
  76:         LCD_String("LED ON ");
  77:     }
  78:     else
  79:     {
  80:         PIOA_SODR = (1 << LED1);
  81:         LCD_Cursor(1, 0);
  82:         LCD_String("LED OFF");
  83:     }
  84:  
  85:  
  86:     return ;
  87: }
  88:  
  89: void two()
  90: {
  91:     Send_String("Hello\n\r");
  92:     LCD_Cursor(1, 0);
  93:     LCD_String("Hello  ");
  94:     
  95:     return ;
  96: }    
  97:  

one()는 PA0에 연결된 LED의 상태를 토글시키는 함수로 하이퍼터미널에서 ‘1’을 보내면 수행된다.
two()는 LCD와 터미널로 문자열을 출력하는 함수로 하이퍼터미널에서 ‘2’를 보내면 수행된다.

분할컴파일하니 파일이 많아 올리기 번거러움. 그러니 압축하여 파일을 첨부함.

AT91SAM7S25620110905_DBGU.zip

링크를 클릭하여 다운 받으세요.



DSCN4098