2011년9월2일_ARM_AT91SAM7S256 DBGU(디버그유닛)으로 ARM↔PC간 시리얼통신하기 위해 DBGU초기화와 1Byte송신/수신 함수들을 만들자.



AT91SAM7S256에는 총 3개의 USART(직렬통신)가 있고,

image

그 중 하나는 DBGU이다.
이번에 할 것이 바로 이 디버그 유닛이고 아래의 USART는 아니다.

image

USART는 DBGU에 비해 잘 사용되지 않는다는데 DBGU보다 기능이 많아 보인다. (더 좋아 보인다.)
그러나 우리가 지급 받은 실습보드는 아래와 같이 DBGU만 쓰기 쉽도록 하드웨어적인 구성이 되어 있어 USART는 하지 않는다.

image

PC와 통신을 하기 위해선 PC의 시리얼통신방식 RS232인터페이스에 맞춰줘야 한다. (참조URL: http://ko.wikipedia.org/wiki/RS-232)
MAX3232라는 IC는 PC(컴퓨터)와 ARM보드사이에 서로 다른 전압을 맞춰주는 역활을 한다.
RS232는 일반 IC의 High/Low 로직의 신호레벨(0~3.3V)와 달리 High레벨은 -10V정도이고 Low레벨은 +10V이다.
이렇게 전압레벨이 다르니 레벨변환IC가 필요한데 다른 핀들에는 이런 IC를 따로 연결해 줘야 한다.
그래서 실습에는 적합하지 않느니 DBGU를 사용한다.
상기의 회로도를 보면 PA9와 PA10이 MAX3232에 연결되어 있으니 시리얼통신을 할 때에는 PA9와 PA10을 다른 용도로 사용할 수 없다.
이를 하드웨어적인 제약이라고 한다.



DSCN4086 image

상기의 사진에서 3핀 몰렉스와 ARM보드가 연결된 부분의 실크스크린을 보면,
G는 검은색, GND이고,
R은 흰색, 수신이고,
T는 빨간색, 송신이다.

회로도상에 몰렉스 3핀의 위치는 오른쪽 그림과 같이 B2에 위치해 있다.



● DBGU초기화절차

① 송/수신부를 리셋시키고 동작을 중지. 비활성.
② DBGU관련 인터럽트를 비활성시킴.
③ 9번 RXD, 10번 TXD핀을 Peripheral A모드로 바꾸고,
   Peripheral B모드 비활성. (이유: A와 B를 동시에 사용하는 것은 불가)  <- 이 부분은 생략해도 됨.
   9번, 10번 핀을 통신용으로 사용하기 위해 병렬포트 Disable
④ 통신속도(보레이트)설정
⑤ 통신모드와 패리티설정
⑥ 송/수신 모드 활성화



   1: void DBGU_INIT()
   2: {
   3:     // 1.송/수신부를 리셋.
   4:     DBGU_CR = (1 << RSTRX) | (1 << RSTTX);    //송/수신부를 리셋시키고 동작을 중지 시킴.
   5:     // 2. 인터럽트 비활성
   6:     DBGU_IDR = 0xFFFFFFFF;        //관련 인터럽트 비활성화
   7:     // 3. 외부 연결용 pin설정.
   8:     PIOA_ASR = (1 << DRXD) | (1 << DTXD);        //Peripheral A 사용.      PIOA_BSR = 0;    //B모드 비활성.
   9:     PIOA_PDR = (1 << DRXD) | (1 << DTXD);        //I/O포트로 사용하지 않음.
  10:     // 4. 포트 속도 설정.
  11:     DBGU_BRGR = CD;            //115200bps
  12:     // 5. 포트 모드 설정.
  13:     DBGU_MR = (0 << CHMODE) | (4 << PAR);    //로컬 루프백, 패리티x
  14:     // 6. 송/수신 모드 활성화
  15:     DBGU_CR = (1 << TXEN) | (1 << RXEN);        //송/수신 허용
  16:     
  17:     return ;
  18: }


<소스설명>

//도식과 설명과 소스코드 일부분을 추가할 것.




● 1Byte 송수신 함수

   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: }
  12:  
  13:  
  14: // 8. Data 수신용 함수의 제작
  15: unsigned char Recv_Char()
  16: {
  17:     unsigned char ucRData = 0;
  18:     
  19:     // 8-2 DBGU_SR레지스터 폴링. (수신가능하지 check)
  20:     while(0 == (DBGU_SR & (1 << RXRDY)));        //RXRDY비트 검사하여 1이면 탈출.
  21:                                             // 1이면 수신준비완료.
  22:     // 8-3 DBGU로부터 1Byte수신
  23:     ucRData = DBGU_RHR;
  24:                                             
  25:     return ucRData;
  26: }

<소스설명>

//도식과 설명과 소스코드 일부분을 추가할 것.



● 전체소스코드

소스코드는 참고만 하고 궁금한 점이 있으면 댓글 달아주세요.
설명을 추가해야 하는데 시간이...

○ main.c

   1: /*********************************************************
   2: 
   3:     제    목: DBGU테스트
   4:     
   5: *********************************************************/
   6: #include "PIOA.h"
   7: #include "DBGU.h"
   8: #include "LCD.h"
   9:  
  10: #define    MCK        48000000
  11: #define    BRATE    115200
  12: #define    CD        (MCK / (16 * BRATE))        
  13:  
  14: void DBGU_INIT();
  15: void Send_Char(unsigned char ucSData);
  16: unsigned char Recv_Char();
  17:  
  18: int main(void)
  19: {
  20:     unsigned char ucBuff;
  21:     int iCol = 0;
  22:  
  23:     PORT_INIT();
  24:     LCD_INIT();
  25:     LCD_Print("Test DBGU");
  26:     DBGU_INIT();    
  27:  
  28:     while(1)
  29:     {        
  30:         ucBuff = Recv_Char();
  31:         Send_Char(ucBuff);
  32:         LCD_Cursor(1, iCol);
  33:         LCD_Data(ucBuff);
  34:         ++iCol;
  35:         if(16 == iCol)
  36:         {
  37:             iCol = 0;            
  38:         }
  39:     }
  40:     
  41:     while(1);            //return되면 안됨. 돌아갈 곳이 없어. 집이 없어. 
  42:  
  43:     return 0;
  44: }
  45:  
  46: void DBGU_INIT()
  47: {
  48:     // 1.송/수신부를 리셋.
  49:     DBGU_CR = (1 << RSTRX) | (1 << RSTTX);    //송/수신부를 리셋시키고 동작을 중지 시킴.
  50:     // 2. 인터럽트 비활성
  51:     DBGU_IDR = 0xFFFFFFFF;        //관련 인터럽트 비활성화
  52:     // 3. 외부 연결용 pin설정.
  53:     PIOA_ASR = (1 << DRXD) | (1 << DTXD);        //Peripheral A 사용.      PIOA_BSR = 0;    //B모드 비활성.
  54:     PIOA_PDR = (1 << DRXD) | (1 << DTXD);        //I/O포트로 사용하지 않음.
  55:     // 4. 포트 속도 설정.
  56:     DBGU_BRGR = CD;            //115200bps
  57:     // 5. 포트 모드 설정.
  58:     DBGU_MR = (0 << CHMODE) | (4 << PAR);    //로컬 루프백, 패리티x
  59:     // 6. 송/수신 모드 활성화
  60:     DBGU_CR = (1 << TXEN) | (1 << RXEN);        //송/수신 허용
  61:     
  62:     return ;
  63: }
  64:  
  65:  
  66: // 7. Data송신용 함수의 제작
  67: void Send_Char(unsigned char ucSData)
  68: {
  69:     // 7-2  DBGU_SR레지스터 폴링 (송신이 가능한지 check)
  70:     while(0 == (DBGU_SR & (1 << TXRDY)));        //TXRDY비트 검사하여 1이면 탈출.
  71:                                             // 1이면 송신준비완료
  72:     // 7-3 DBGU 유닛에 문자 전송.
  73:     DBGU_THR = ucSData;
  74:  
  75:     return ;
  76: }
  77:  
  78:  
  79: // 8. Data 수신용 함수의 제작
  80: unsigned char Recv_Char()
  81: {
  82:     unsigned char ucRData = 0;
  83:     
  84:     // 8-2 DBGU_SR레지스터 폴링. (수신가능하지 check)
  85:     while(0 == (DBGU_SR & (1 << RXRDY)));        //RXRDY비트 검사하여 1이면 탈출.
  86:                                             // 1이면 수신준비완료.
  87:     // 8-3 DBGU로부터 1Byte수신
  88:     ucRData = DBGU_RHR;
  89:                                             
  90:     return ucRData;
  91: }

1Byte 데이터를 PC로 수신받아 바로 돌려주고 LCD의 두 번째 줄에 표시.
LCD 커서는 계속 시프트하다 화면을 벗어나면 처음으로..

○ PIOA.h

   1: #ifndef __PIOA_H__
   2: #define __PIOA_H__
   3:  
   4: /*********************************************************
   5:                     PIO (AT91SAM7S256)
   6: *********************************************************/
   7: #define PIOA_PER    (*(volatile unsigned int *)0xFFFFF400)    //포트 활성
   8: #define PIOA_PDR    (*(volatile unsigned int *)0xFFFFF404)    //포트 활성
   9: #define PIOA_OER    (*(volatile unsigned int *)0xFFFFF410)    //포트 출력사용
  10: #define PIOA_ODR    (*(volatile unsigned int *)0xFFFFF414)    //포트 출력x
  11: #define PIOA_PPUDR    (*(volatile unsigned int *)0xFFFFF460)    //포트 풀업x
  12: #define PIOA_CODR    (*(volatile unsigned int *)0xFFFFF434)    //포트 클리어
  13: #define PIOA_SODR    (*(volatile unsigned int *)0xFFFFF430)    //포트 세트
  14: #define PIOA_IFER    (*(volatile unsigned int *)0xFFFFF420)    //글리치 필터
  15: #define PIOA_IER        (*(volatile unsigned int *)0xFFFFF440)    //인터럽트 허용 PIOA를 먼저 거친다.
  16: #define PIOA_IDR        (*(volatile unsigned int *)0xFFFFF444)    //인터럽트 금지 PIOA를 먼저 거친다.
  17: #define PIOA_ISR        (*(volatile unsigned int *)0xFFFFF44C)    //인터럽트 상태
  18: #define PIOA_ODSR    (*(volatile unsigned int *)0xFFFFF438)    //출력 데이터 상태
  19: #define PIOA_PDSR    (*(volatile unsigned int *)0xFFFFF43C)    //핀 데이터 상태
  20: #define PIOA_ASR    (*(volatile unsigned int *)0xFFFFF470)    //Peripheral A선택
  21: #define PIOA_BSR    (*(volatile unsigned int *)0xFFFFF474)    //Peripheral B선택
  22:  
  23: #define DRXD        9
  24: #define DTXD        10
  25:  
  26: #endif    //__PIOA_H__

PIO장치 관련해 레지스터들을 정의한 것.

○ DBGU.h

   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: #endif    //__DBGU_H__
  23:  

DBGU관련 레지스터와 각 비트를 정의한 것.
DBGU.h에도 LCD.h와 마찬가지로 DBGU관련함수들의 원형을 넣고,
DBGU.c파일을 만들어 분할 컴파일 할 것.

○ LCD.h

   1: #ifndef __LCD_H__        //8월31일추가 분할컴파일.
   2: #define __LCD_H__
   3:  
   4: //volatile unsigned int iCount = 0;        //딜레이용 카운트 변수, unsigned가 더 fast
   5:  
   6:  
   7: /*********************************************************
   8:                     16 * 2line CLCD
   9: *********************************************************/
  10: //7월 13일 추가
  11: #define    CLCD_RS    (1 << 11)            //LCD레지스터 선택 (1 = DATA, 0 = INST)
  12: #define    CLCD_RW    (1 << 12)            //LCd읽기/쓰기 선택( 1 = READ, 0 = WRITE)
  13: #define    CLCD_EN    (1 << 13)            //LCD활성.
  14: #define    CLCD_BS    (0xFF << 16)        //데이터버스 I/O
  15: //7월 14일 추가
  16: #define    CLCD_INST_CD    0x01        //Clear Display명령
  17: #define    CLCD_INST_RH    0x02        //Return Home명령
  18: #define    CLCD_INST_FS    0x38        //Function Set명령
  19: #define    CLCD_INST_EM    0x06        //Entry Mode Set명령
  20: #define    CLCD_INST_DO    0x0C        //Display ON/OFF Control명령    커서OFF
  21: #define    CLCD_INST_CS    0x14        //Cursor Shift명령 - 커서를 right
  22: #define    CLCD_INST_DD    0x80        //DDRAM 0번지선택.
  23: #define    CLCD_INST_CG    0x40        //CGRAM 0번지선택.
  24: #define    CLCD_DELAY(Z)    for(iCount = 0 ; (Z) > iCount ;++iCount)        //시간지연
  25:  
  26: void PORT_INIT(void);            //PORT초기화
  27: void LCD_INIT(void);            //LCD초기화
  28: void LCD_Inst(unsigned char);    //LCD에 명령을 내리는 함수.
  29: void LCD_Data(unsigned char);    //LCD에 데이터를 보내는 함수.
  30: void Set_FONT(void);            //사용자정의 문자를 CLCD의 CGRAM에 저장.
  31: void LCD_Print(const char *);    //LCD에 문자열을 출력하는 함수.
  32: void LCD_Cursor(char, char);        //LCD커서를 이동시키는 함수.
  33:  
  34: #endif    //__LCD_H__

LCD관련 PORT설정 및 명령어셋

LCD.c
   1: #include "PIOA.h"
   2: #include "LCD.h"
   3:  
   4:  
   5: void PORT_INIT(void)
   6: {
   7:     // Configure the pin in output
   8:     PIOA_OER    = CLCD_BS | CLCD_RS | CLCD_RW | CLCD_EN;
   9:     // Set the PIO controller in PIO mode instead of peripheral mode
  10:     PIOA_PER    = CLCD_BS | CLCD_RS | CLCD_RW | CLCD_EN;
  11:     // Disable pull-up
  12:     PIOA_PPUDR    = CLCD_BS | CLCD_RS | CLCD_RW | CLCD_EN;
  13:     PIOA_CODR = CLCD_BS;        //데이터 버스 클리어.
  14:  
  15:     return ;
  16: }
  17:  
  18: void LCD_INIT(void)
  19: {
  20:     static volatile unsigned int iCount = 0;        //딜레이용 카운트 변수, unsigned가 더 fast
  21:  
  22:     CLCD_DELAY(60000);            //30ms이상 대기.
  23:     LCD_Inst(CLCD_INST_FS);        
  24:     CLCD_DELAY(8200);            //4.1ms이상 대기.
  25:     LCD_Inst(CLCD_INST_FS);        
  26:     CLCD_DELAY(200);            //100us이상 대기.
  27:         
  28:     LCD_Inst(CLCD_INST_FS);
  29:     LCD_Inst(CLCD_INST_FS);        
  30:     LCD_Inst(CLCD_INST_EM);
  31:     LCD_Inst(CLCD_INST_CS);
  32:     LCD_Inst(CLCD_INST_DO);
  33:     LCD_Inst(CLCD_INST_CD);
  34:     CLCD_DELAY(3040);            //1.52ms이상 대기.
  35:     LCD_Inst(CLCD_INST_DD);        //첫행으로.
  36:     LCD_Inst(CLCD_INST_RH);        //리턴홈.
  37:     CLCD_DELAY(3040);            //1.52ms이상 대기.
  38:     
  39:     return ;
  40: }
  41:  
  42:  
  43:  
  44: // LCD에 명령을 내리는 함수
  45: void LCD_Inst(unsigned char uiInst)    //LCD에 명령을 내리는 함수.
  46: {
  47:     static volatile unsigned int iCount = 0;        //딜레이용 카운트 변수, unsigned가 더 fast
  48:     
  49:     PIOA_CODR = CLCD_RS;    //CLCD instruction resgister 선택
  50:     PIOA_CODR = CLCD_RW;    //write모드
  51:     CLCD_DELAY(1);            //40ns정도딜레이필요.
  52:     PIOA_SODR = CLCD_EN;    //CLCD 활성    
  53:     PIOA_CODR = CLCD_BS;    //databus 초기화 0x00
  54:     PIOA_SODR = (uiInst << 16);        //데이터 버스에 명령 올림.
  55:     CLCD_DELAY(1);            //100ns정도딜레이필요.
  56:     PIOA_CODR = CLCD_EN;    //CLCD 비활성
  57:     CLCD_DELAY(80);        //Data write to CG RAM or DD RAM에 필요한 시간. 41us
  58:  
  59:     return ;
  60: }
  61:  
  62: // LCD에 데이터를 보내는 함수.
  63: void LCD_Data(unsigned char uiData)    //LCD에 데이터를 보내는 함수.
  64: {    
  65:     static volatile unsigned int iCount = 0;        //딜레이용 카운트 변수, unsigned가 더 fast
  66:  
  67:     PIOA_SODR = CLCD_RS;    //CLCD data resgister 선택
  68:     PIOA_CODR = CLCD_RW;    //write모드
  69:     CLCD_DELAY(1);            //40ns정도딜레이필요.
  70:     PIOA_SODR = CLCD_EN;    //CLCD 활성    
  71:     PIOA_CODR = CLCD_BS;    //databus 초기화 0x00
  72:     PIOA_SODR = (uiData << 16);        //데이터 버스에 데이터 올림.
  73:     CLCD_DELAY(1);            //100ns정도딜레이필요.
  74:     PIOA_CODR = CLCD_EN;    //CLCD 비활성
  75:     CLCD_DELAY(80);        //Data write to CG RAM or DD RAM에 필요한 시간. 41us
  76:  
  77:     return ;
  78: }
  79:  
  80: // 사용자정의 폰트를 CLCD CGRAM에 저장하는 함수.
  81: void Set_FONT()
  82: {
  83:     unsigned int iLoop;
  84:     unsigned char font[] = 
  85:     {
  86:         0x1F, 0x01, 0x01, 0x02, 0x02, 0x04, 0x08, 0x00,        // ㄱ
  87:         0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x00,        // ㅣ
  88:         0x00, 0x1E, 0x12, 0x12, 0x12, 0x1E, 0x00, 0x00,         // ㅁ
  89:         0x00, 0x04, 0x0A, 0x0A, 0x11, 0x11, 0x00, 0x00,        // ㅅ
  90:         0x1F, 0x04, 0x04, 0x04, 0x04, 0x04, 0x00, 0x00,        // ㅜ
  91:         0x04, 0x04, 0x04, 0x07, 0x04, 0x04, 0x04, 0x00,        // ㅏ
  92:         0x00, 0x10, 0x10, 0x10, 0x10, 0x1F, 0x00, 0x00,        // ㄴ
  93:         0x00, 0x0A, 0x15, 0x11, 0x11, 0x0A, 0x04, 0x00            // ♡
  94:     };
  95:  
  96:     //CGRAM에 폰트 넣기.
  97:     LCD_Inst(0x40);    //set CG RAM address
  98:     for(iLoop = 0 ; iLoop < sizeof(font) ; ++iLoop)
  99:     {
 100:         LCD_Data(font[iLoop]);
 101:     }
 102:  
 103:     return ;
 104: }
 105:  
 106: //CLCD 문자열 출력함수 LCD_Data가 필요. 
 107: void LCD_Print(const char *str)
 108: {
 109:     int iLoop = 0;
 110:     
 111:     while('\0' != str[iLoop])    //NULL문자를 만나면 그만.
 112:     {
 113:         LCD_Data(str[iLoop]);    //1Byte씩 출력.
 114:         ++iLoop;
 115:     }
 116:     
 117:     return ;
 118: }
 119:  
 120: //CLCD 커서이동함수, LCD_Inst필요.
 121: void LCD_Cursor(char iRow, char iCol)
 122: {              //    행(0~1), 열(0~15)
 123:     char cPos;
 124:     
 125:     cPos = iRow * 0x40 + iCol;    //어드레스 계산
 126:     cPos = cPos | 0x80;            //DDRAM
 127:     LCD_Inst(cPos);                //커서이동.
 128:     
 129:     return ;
 130: }
 131:  

LCD에 명령을 내려 화면을 제어하는 함수들


<테스트 전에 해야 될 일>

DSCN4087DSCN4088  
PC와 연결을 위해선 RS232인터페이스 규격의 9핀 암놈 커넥터가 있어야 하고,
ARM Board는 몰렉스 3핀 커넥터로 되어 있다.


DSCN4092DSCN4094  
요즘 컴퓨터는 시리얼 RS232 9핀 커넥터가 없으나 좀 오래된 컴퓨터는 상기의 사진과 같이 커넥터가 있다.
더 옛날 컴퓨터는 프린터포트도 있어 임베디드 개발자에겐 좋으나..그렇다고 옛날 컴퓨터를 사려니 좀 그렇다.
USB to 시리얼이라는 제품이 있어 USB에 연결하여 시리얼포트 COM3부터 사용할 수 있으니 참고하자.
오른쪽 사진과 같이 RS232인터페이스 규격의 9핀 암놈 커넥터를 꼽아주자.
본체는 수놈이라 잘 맞는다.


● 실행결과

DSCN4089DSCN4091

image
 

하이퍼 터미널에 “abcdefg123 suman”을 순서대로 입력하였다.
그런데 a를 전송하니 ARM보드의 회신이 ?이다. ?는 특수문자이고 전송에러가 났다는 뜻인데..
이 부분을 해결해야 할 것이다.