본문 바로가기
코스웨어/11년 내장형하드웨어

[내장형]이성재 2011년 9월1일 일일보고서

by 알 수 없는 사용자 2011. 9. 1.
728x90
반응형

일일보고서 2011년 9월 1

내장형하드웨어 이성재

ARM

 

AT91SAM7S256 의 인터럽트를 하기 위해서는 병렬 입출력 제어기(PIOA)를 사용한다.

PIOA는 각 핀에서의 입력 레벨 변화(에지)가 인터럽트를 발생하도록 할수 있다.

 

PIOA를 사용하기 위해서는 전력관리 제어기에서 클럭을 공급해야만 동작한다.

클럭을 공급하면 PIOA의 PA0~PA31까지 사용할수 있다.

클럭을 공급하기위해서는 PMC_PCER 레지스터(0xFFFF_FC10)를 설정해야 한다.

#define PIOA 2; 

#define PMC_PCER          (*(volatile unsigned int *)0xFFFFFC10)

PMC_PCER = 1 << PIOA;      /*  밑의 표를 참고하면 ID 2번이 PIOA이다.

                                  그래서 PIOA는  define 한다. */

 

위와같이 PIOA 자리에 1 SHIFT 하여 PIOA에 전원을 공급하여 사용할수 있게끔 한다.

 


PIOA를 입력용으로 쓰기 위해서 출력을 disable 하여야 하기 때문에 출력을 disable

하는 PIOA_ODR레지스터 (0xFFFF_F414) 를 설정한다.

 

#define PIOA_ODR                                (*(volatile unsigned int *)0xFFFFF414)

 PIOA_ODR = 1 << INT_PIN7;       /* INT_PIN7  7번 핀을 입력용으로 쓰기 위해 7로 define한다.*/

 

입력용으로 사용한다고 설정했다면 이제 PIN을 사용하기 위해서 PIOA_PER (0xFFFF_F400)를 설정한다.

 

#define PIOA_PER                                (*(volatile unsigned int *)0xFFFFF400)

 PIOA_PER  =  1 << INT_PIN7;   /* 7번에 1을 넣어 주므로서 7번핀을 사용함 */

 

그럼 우리는 밑의 그림과 같이 PIOA 0~31개의 핀중에  7번핀을 사용한다는 것을 알수있다.


  

인터럽트가 발생했을 때 생기는 서비스루틴(핸들러)의 어드레스를 저장하기 위해서 AIC_SVR을 사용한다.

여기서 AIC는 인터럽트 제어기(Advanced Interrupt Controller :AIC) 이다.

 

#define AIC_SVR                                       ((volatile unsigned int *)0xFFFFF080)

 AIC_SVR[PIOA] = (unsigned int)Handler;

 

AIC_SVR 은 배열로 사용하기 위해 주소형식으로 define한다.

그리고 Handler는 함수의 시작주소 이나 왼쪽에는 배열 형식이므로 타입이 같지 않기 때문에

(unsigned int)로 캐스팅하여 함수의 시작 주소 값 자체를 배열에 넣도록 한다.

 

AIC_SMR 레지스트를 사용하여 외부,내부인터럽트레벨감지방식,에지트리거,하이레벨,로우레벨,상승에지,하강에지

모드를 설정할수 있다.

 

#define AIC_SMR                                      ((volatile unsigned int *)0xFFFFF000)

 AIC_SMR[PIOA] = ( 2 << SRCTYPE | 0 << PRIOR);      /* 2진수 10 16진수로 2이기 때문에 2을 시프트한다.

10은 외부인터럽트의 high레벨를 사용한다.
                    밑의 표를 참고하시면 됩니다 */

 




 

그리고 PIO_IFER 레지스트를 사용하여 해당 비트 핀의 입력에 글리치 필터를 사용하도록 허용한다.

한마디로 스위치에 있는 핀사이 간격의 잡음을 막기위해 사용된다.

 

#define PIOA_IFER                                (*(volatile unsigned int *)0xFFFFF420)

 PIOA_IFER = 1 << INT_PIN7;                     //글리지 필터 사용 허가

 

위에서 AIC_SMR로 외부인터럽트의 상승에지를 설정했다이를 위하여 인터럽트 소스의 입력단에는 에지검출기를 가지고 있는데AIC_ISCR  AIC_ICCR레지스터를 사용하여 이것의 상태를 세트 또는 클리어할수 있다.

 

#define AIC_ISCR       (*(volatile unsigned int *)0xFFFFF12C)

AIC_ISCR = 1 << PIOA;                   // 대응하는 인터럽트의 에지 검출기를 세트한다.

 
 이제 인터럽트가 들어오면 인터럽트를 허용한다라는 것을 설정해주는데

PIOA_IER 레지스터가 해준다.

 

#define PIOA_IER                                      (*(volatile unsigned int *)0xFFFFF440)

 

PIOA_IER = 1 << INT_PIN7;         // 인터럽트가 들어오면 인터럽트를 허용.

 

AIC에서도 대응하는 인터럽트를 허용해야되는데 이것은 AIC_IECR레지스터가 설정해준다

 

#define AIC_IECR       (*(volatile unsigned int *)0xFFFFF120)

 

AIC_IECR = 1 << PIOA;         // AIC 에서도 인터럽트를 허용.

 

위 내용을 종합해보면   InterruptInit함수를 만들수 있다.

void InterruptInit(void)

 {

   PMC_PCER =   1 << PIOA;        //PIOA 전원공급

   PIOA_ODR =  1 << INT_PIN7;   //출력 비활성화

   PIOA_PER  =  1 << INT_PIN7;   //pin enalbe

   AIC_IDCR   = 1 << PIOA;

   AIC_SVR[PIOA] = (unsigned int)Handler;

   AIC_SMR[PIOA] = ( 2 << SRCTYPE | 0 << PRIOR);   //  high level sensitive.

   PIOA_IFER = 1 << INT_PIN7;           //글리지 필터 사용 허가

   AIC_ISCR = 1 << PIOA;                // 대응하는 인터럽트의 에지 검출기를 세트한다.

   PIOA_IER = 1 << INT_PIN7;         // 인터럽트가 들어오면 인터럽트를 허용.

   AIC_IECR = 1 << PIOA;         // AIC 에서도 인터럽트를 허용.

 }

  

빠져먹은것도 많고 틀린거도 많습니다그중에 IRQ핸들러 벡터 넘기는부분 
보충설명 댓글부탁드립니다
.

   

Araxis Merge 프로그램 설명

 




파일 두개를 불러와서 서로 비교해주는 참 유용한 프로그램이다.

  

그림파일 또한 서로 비교가 가능하다.  마우스우클릭으로 Compare with Araxis Merge를 선택.



두번째 그림파일에서는 Compare with Araxis Merge(+1 in queue) 을 선택한다.

 

그림파일 두개가 서로 비교하고 있는 것을 볼수 있다.

 

 

 WINAPI

 

윈도우와 관련된 메시지 중 가장 간단한 메시지는 윈도우가 생성될 때 보내지는 WM_CREATE와 윈도우가 파괴될 때 보내지는WM_DESTROY 두가지가 있다. WM_CREATE 메시지는 윈도우가 생성될 때 보내지므로 각종 초기화를 하기에 적합한 장소이며 반대로WM_DESTROY 메시지는 종료처리를 하기에 적합하다이 두 메시지는 앞에서 몇번 사용해 보았으며 직감적으로 이해될만큼 상당히 쉬운 편이다.

 

이 메시지 대신 사용할 수 있는 방법으로는 WinMain에서 직접 초기화와 종료 처리를 해 주는 방법이 있다. WM_CREATE 메시지는CreateWindow 함수에 의해 메인 윈도우가 생성된 직후에 보내지므로 CreateWindow 함수 호출문 다음에 초기화 코드를 작성해도 효과는 같다. WM_DESTROY 메시지는 메인 윈도우가 파괴되기 직전에 보내지는데 메인 윈도우 파괴후에는 메시지 루프가 끝나게 되므로 메시지 루프 다음에 종료 처리 코드를 작성할 수도 있다앞에서 만들었던 MyTimer 예제를 이런 식으로 변경해 보면 다음과 같아진다.

 

HANDLE hTimer, hTimer2;

char *str;

 

int APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance

                             ,LPSTR lpszCmdParam,int nCmdShow)

{

 

             ================  중간 생략 ===================

             hWnd=CreateWindow(lpszClass,lpszClass,WS_OVERLAPPEDWINDOW,

                             CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,

                             NULL,(HMENU)NULL,hInstance,NULL);

             ShowWindow(hWnd,nCmdShow);

            

             hTimer=(HANDLE)SetTimer(hWnd,1,1000,NULL);

             hTimer2=(HANDLE)SetTimer(hWnd,2,5000,NULL);

             str="";

             SendMessage(hWnd, WM_TIMER, 1, 0);

 

             while(GetMessage(&Message,0,0,0)) {

                           TranslateMessage(&Message);

                           DispatchMessage(&Message);

             }

 

             KillTimer(hWnd,1);

             KillTimer(hWnd,2);

 

             return Message.wParam;

}

 

CreateWindow 호출문 다음에 타이머를 설정하는 초기화 처리를 하였고 메시지 루프 다음에 타이머를 파괴하는 종료 처리를 하였으며 관련된 전역 변수들을 WinMain 이전에 선언하였다. WM_CREATE WM_DESTROY에 있던 코드를 그대로 WinMain으로 옮겼는데 실행시켜 보면 완전히 동일하게 동작할 것이다.

 

그런데 어쨋든 결과가 같기는 하지만 WinMain에서 하는 초기화와 종료 처리는 WM_CREATE, WM_DESTROY 메시지가 발생했을 때 하는 것과는 엄밀하게 따지면 다르다두 메시지는 특정한 윈도우에 관련된 초기/종료 처리를 하는데 사용하는 것이 좋고 WinMain에서는 프로그램 전역적인 초기/종료 처리를 하는 것이 좋다여기서는 메인 윈도우 하나만 사용되므로 어디에서 하나 결과가 같지만 여러개의 윈도우가 사용된다면 그 의미가 조금 달라진다

 

 

윈도우는 작업 영역(Client Area)과 비작업 영역(Non Client Area) 두 부분으로 구성되어 있다작업 영역이란 쉽게 말해서 윈도우 중앙의 흰 부분을 말하며 비작업 영역이란 그 외의 영역을 말한다비작업 영역에 속하는 부분은 일단 타이틀 바와 경계선이 있고 메뉴가 있을 경우 메뉴도 비작업 영역에 속한다.

 

작업/비작업 영역의 구분은 윈도우를 이해하는데 중요한 비중을 차지하는데 왜냐하면 프로그래머에게 프로그래밍 대상이 되는 것은 작업 영역에 한정되기 때문이다일반적으로 비작업 영역은 프로그래밍 대상이 아니며 운영체제가 알아서 관리해 주도록 되어 있다타이틀 바나 경계선을 프로그래머가 직접 그려 주어야 할 필요가 없다는 얘기다또한 모든 출력을 기준은 작업 영역인데 좌표 (10,10)을 지정하면 이는 작업 영역의 좌상단을 기준으로 (10,10)을 의미하는 것이지 윈도우를 기준으로 (10,10)을 의미하는 것이 아니다.

 

그래서 원하는 위치에 정확하게 출력하려면 윈도우가 차지하고 있는 영역의 좌표를 조사해야 하는 것이 아니라 작업 영역의 좌표를 조사해야 한다이때는 다음 함수를 사용한다.

 

BOOL GetClientRect( HWND hWnd, LPRECT lpRect);

 

이름 그대로 Client가 차지하고 있는 Rect Get하는 함수이다첫번재 인수로 대상 윈도우 핸들을 주고 두번째 인수로 리턴값을 돌려받기 위한 RECT 구조체의 포인터를 넘겨주면 된다이 함수 호출 후에 RECT 구조체에는 작업 영역의 좌표가 들어가는데 left, top은 항상 0이며right, bottom에 우하단의 좌표가 대입된다.

 

그럼 이 함수를 사용하여 문자열을 작업 영역의 정중앙에 출력하는 예제를 만들어 보자작업 영역의 중앙 좌표를 알려면 작업 영역의 크기를 구한후 우하단 좌표를 2로 나누어 구하면 된다

 

WM_CREATE에서 GetClientRect 함수로 작업 영역의 좌표를 구해 rt에 대입해 주었다그리고 WM_PAINT에서는 작업 영역의 중앙 좌표를 구해 문자열을 출력하되 정확하게 중앙이 되도록 하기 위해 문자열을 중앙 정렬하였다

 

 

앞에서 만든 예제는 과연 작업 영역 중앙에 문자열을 출력하기는 하였다윈도우가 만들어질 때 작업 영역 좌표를 구해 놓고 그릴 때 이 좌표를 기준으로 중앙 좌표를 계산하기 때문이다그런데 일단 출력된 윈도우의 크기를 변경하면 작업 영역의 크기가 달라져 더 이상 문자열은 작업 영역의 중앙에 있지 않게 된다.

 

문자열을 계속 작업 영역 중앙에 두고 싶으면 윈도우의 크기가 변경될 때마다 다시 출력해 주어야 하는데 이때 사용되는 메시지가WM_SIZE 메시지이다이 메시지는 윈도우의 크기가 변경되었을 때 보내진다이때 lParam의 하위 워드에는 변경된 후의 윈도우 폭이상위 워드에서는 높이가 전달되며 wParam에는 이 메시지가 발생한 이유를 나타내는 플레그가 전달된다.

 

플레그    

SIZE_MAXHIDE            다른 윈도우가 최대화되어 이 윈도우가 가려졌다.

SIZE_MAXIMIZED        최대화되었다.

SIZE_MAXSHOW                    다른 윈도우가 원래 크기로 복구되어 이 윈도우가 드러났다.

SIZE_MINIMIZED         최소화되었다.

SIZE_RESTORED         크기가 변경되었다.

 

일반적으로 이 플레그는 잘 사용되지 않는다. WM_SIZE 메시지를 사용하여 윈도우 크기가 변경될 때마다 문자열 위치를 수정하도록WndProc을 다음과 같이 수정해 보자.

 

LRESULT CALLBACK WndProc(HWND hWnd,UINT iMessage,WPARAM wParam,LPARAM lParam)

{

             HDC hdc;

             PAINTSTRUCT ps;

             static RECT rt;

             switch(iMessage) {

             case WM_PAINT:

                           hdc=BeginPaint(hWnd, &ps);

                           SetTextAlign(hdc,TA_CENTER);

                           TextOut(hdc,rt.right/2, rt.bottom/2, "Center String",13);

                           EndPaint(hWnd, &ps);

                           return 0;

             case WM_SIZE:

                           GetClientRect(hWnd, &rt);

                           InvalidateRect(hWnd, NULL, TRUE);

                           return 0;

             case WM_DESTROY:

                           PostQuitMessage(0);

                           return 0;

             }

             return(DefWindowProc(hWnd,iMessage,wParam,lParam));

}

WM_CREATE 대신 WM_SIZE에서 윈도우 크기가 변경될 때마다 작업 영역의 크기를 다시 계산하고 화면을 다시 그리므로 문자열은 윈도우의 크기에 상관없이 항상 같은 위치에 있게 된다. WM_SIZE에서 GetClientRect 함수를 호출하여 작업 영역의 크기를 다시 조사하는데lParam으로도 작업 영역 크기가 전달되므로 다음과 같이 쓸 수도 있다.

 

case WM_SIZE:

             rt.right=LOWORD(lParam);

             rt.bottom=HIWORD(lParam);

             InvalidateRect(hWnd, NULL, TRUE);

             return 0;

WM_SIZE 메시지는 윈도우 크기에 상관없이 일정한 레이아웃을 유지하기 위해 빈번하게 사용된다.

728x90