키0가 눌리면 인터럽트가 발생하고 발생하면
내용이 바뀌어서 LEDR0가 깜빡 깜빡하게 되는 형태
c코드 파일이 3개로 구성되어있다.
심플C 메인 함수가 들어있는 c파일이 있고
실제로 우리가 푸쉬버튼을 눌렀을 때 사용되는 함수가 들어있는
C파일 하나가 있고
exception 핸들러
인터럽트가 발생했을 때 중간에서 처리해주는 파일이 있다.
어셈블리어로 인터럽트 구현할 때는
정확하게 세개로 나눠서 구현을 했는데 이번에도 똑같다.
nios2_ctrl_reg
컨트롤 레지스터랑 관련된 메크로를 집어넣는다
c언어에서 메크로를 배웠었다.
간단한 한줄 짜리 문구를 함수 비슷하게 구현하는것이 메크로
그것을 먼저 보고 넘어가죠
프로세싱하기 전 단계에서
코드를 원래 짜면 컴파일러가 읽어서 해석을 해서 바이너리로 만들기 전에
오브젝트 파일로 만드는데
그게 컴파일러가 해주는 기능인데 컴파일러가 자체적으로 해석을 해서
오브젝트 파일로 바꾸는게 컴파일러가 해주는일인데
컴파일러가 컴파일 하기 전에 쭉 읽어봐서 바꿔치기(?) 해줄 수 있는게
전처리기 입니다.
메크로 함수들은 NIOS2_READ_STATUS
이런 메크로를 만나면 do~ while 문구로 대체해버린다.
즉, 텍스트 치환기능'이다 라고 생각하면 된다.
ifndef==> else if 와 같은것
약간의 문법을 넣어주는것 인데
if 만약에 ndef 뒤에것이 없으면 #define해라
endif까지가 한 괄호라고 생각하면 된다.
이것을 해주는 이유는 nios2.macro.h 헤더파일이
여러군데에서 포함될 수 있다.
파일 하나 하나를 컴파일 할 때는 상관이 없는데
컴파일러가 오브젝트 파일을 하나 하나 모을 텐데
linking 작업을 할 때
똑같은 이름을 가진놈이 여러번 define나오면 안되니까
겹치지 말라는 의미에서 ifndef을 사용한다.
선언을 8개 해놓으면 STATUS의 리드 라이트 BSTATUS의 리드 INEABLE을 READ WRITE
리드면 인풋 알큐먼트가 데스티네이션.. 어디서 쓸것인가 어디서 읽을것이냐
앞에꺼가 B로 대체되는것인데
백 슬래쉬\ 이것이 의미하는것은 원래는 메크로가 한줄로 쭉 적혀 있는데
이 줄이 너무 길면 사람이 보기 너무 힘들기 때문에
줄을 바꾸고 싶은것 문법에서는 줄을 그을 수 없으니 \을 사용하면 한줄인것 처럼
해석을 하게 된다.
컨트롤 레지스터 0를 읽어서 그값을 dest에 집어 넣어라
while(0) => 조건을 항상 만족하지 않는다는것
사실상 반복문이 아닙니다 ^~^
왜 이런짓을 하느냐?=> 원래 의도한바는
우선순위가 헷갈리는 경우가 생긴다.
이것은 c 프로그래밍 할 때 우선 순위 때문에 문제를 낸적이 있을 텐데
항상 괄호를 많이 사용을 해라' 라고 하는데
이것을 붙여줌으로써 이 안에 있는 구문을 하나의 통으로 해석될 수 있도록
괄호를 쳐주는 것이다.
메크로 함수를 쓸 때 굉장히 자주 쓰는 트릭 중에 하나이다.
라이트 컨트롤을 한다. 소스 값으로 적는다
이렇게 설명을 합니다.
KET0 눌리면 인터럽트 발생하고 깨지고 하기로 했죠
심플C 인터럽트는 메인이 들어있는것
메인에서 하는것은 인터럽트가 발생할 수 있도록 초기화 시켜준다.
volatile 포인터 소스 코드를 보면 인터럽트를 인클루드하고
외부 변수로 LEDR_on=0;
첫번 째는 순서대로 얘기하면 작은 스코프부터 몇번째 푸쉬버튼을 enable할것이냐
이것은 인터럽트 마스크 레지스터랑 관련 있다.
키 0를 사용할거니까 1번을 인에이블해준다.
포인터에서 더하기 1은
주소값이 4가 증가하는것이다.
포인터에 +2를 하면 주소가 마스크 비트가 될것이고 여기에 1을 집어 넣겠다.
푸쉬버튼 인터럽트를 인에이블하겠다.
푸쉬버튼 IRQ를 살려준다.
이것을 ctl3에서 한다. 푸쉬버튼에서 관련되있는것을 1로 세팅해주면 된다.
1,0이니까 얘를 2진수나 10진수도 마찬가지고 10이니까 2가 된다.
여기에 2를 집어넣는다.
마지막에 두번째 인터럽트를 인에이블한다.
status 레지스터에서 PIE를 1로 세팅해주면 된다.
이 때부터 nios II 인터럽트가 작동된다.
요까지가 세팅 부분이고
while (1)
이 안에서 무한 루프 LEDR_on 변수값을 계속 읽어서 LEDR_ptr에 집어넣는다.
변화를 시켜주면 변화하게 된다.
무한루프를 돌면서 상태 변수를 LED에 표시해준다.
인터럽트가 발생했을 때 인터럽트 서비스 루틴을 가서 솰라 솰라해서
인터럽트를 발생하면 아래 구문들을 실행한다.
KEY_ptr +3 ==> 엣지 캡쳐 레지스터로 가서 읽는데 이것을 press에 집어넣는다.
다시 엣지 캡쳐 레지스터에 프레스에 집어넣는다.
엣지 캡쳐 레지스터에 어떤값이든 쓰기만하면 여기가 0이되니까
즉, 클리어, 리셋하기 위해서 아무값이나 집어 넣는거에요.
다음 인터럽트를 위해서 비워둔다고 생각하면 됩니다.
지금 값은 press에 저장이 되어있고
LEDR_on 이랑 1을 xor해서
0 1이면 1이되고 1일 때 0이 되고 ==>not해주는거
뒤집어 주는 역할을 하는거에요.
눌릴 때 마다 LEDR_on 값이 토굴이 된다.
디파인에서 한가지 설명안한 부분이 있는데
extern부분을 설명 안했다.
이밑에서 쓰기 때문이죠
extern이라는 키워드는 왜 적었느냐
우리가 원하는것은 키포인터가 외부에 글로벌하게 선언되어있고
서로 다른 파일에서도 참조를 하고 결국에는 같은 변수이고
컴파일러를 통해서 c파일이 오브젝트 파일로 바뀌는데
선언이 아예 안되있다면 헤더 파일을 수행할 때 에레거 날것입니다.
extern이라는 파일을 안쓰면 오브젝트 파일을 만드는데는 상관 없는데
실제 실행 파일을 만들 때 같은 선언이 있어서 커플링이 납니다.
이러면 안돼요!! 변수 이름을 바꾸면 에러는 안날 텐데
우리는 서로 공유되기를 원하니까 인스턴스가 하나만 있어야 합니다.
그래서 extern이라는 키워드를 사용하면 됩니다.
실질적으로는 진짜 선언은 바깥 어딘가에 있다.
일단은 임시로 선언하는데 진짜 선언은 바깥에 있으니 참조해라'
그래서 외부에 이미 선언이 되있고
extern이라는 키워드를 붙여서 커플링이 안생기게 한다.
exception_handler.c
asm이라는 함수를 사용하는데
이것은 스트링을 받아서 스트링이 적힌게
어셈블러 한줄과 똑같은 일을 한다.
어셈블러를 사용하고 싶으면 asm을 사용하면 된다.
인터럽트 관련한것은 어셈블러에서 선언이 되어있으니 c에서는 맵핑만 하는것이다.
쌈싸먹는것 처럼 싸주는것
c의 탈을 쓴 어셈블러 ^~^
리셋을 했을 때는 메인으로 가라~~
익셉션이 발생했을 때는
스택을 하나 잡아서 128만큼 빼고
ctl4레지스터에서 값을 읽어서 비교를 한다.
그 값이 0이면 스킵하고 아니면 하나 더 빼주고 ~
하드웨어 인터럽트인가 소프트웨어 트랩인가 체크하는 부분이고
그래서 128만큼 빼서 스택에 r1~r31 까지 다 스택에 피신을 시킨다.
어떤것을 코드안에서 쓸지를 컴파일러가 결정하니까
현재 레지스터를 스택 포인터로 피신을 시키고
그 다음에 인터럽트 헨들러를 부른다.
인터럽트 헨들러 서브루틴을 불러서
다시 원복을 시키고 addi sp,sp,128해서 끝내고
eret 해서 끝낸다.
어셈블러로 서브루틴을 불렀는데
c로 보이드 형태로 받을 수 있도록 컴파일러가 알아서 해줍니다.
암튼 function이 call 된다.
하드웨어 인터럽트가 발생했을 때
어떤 IRQ에서 불렸는지 판단
그것에 해당하는 적절한 함수를 불런주는것
ipending이라는 변수를 만들고
그변수에 ipending 레지스터 현재값을 읽어온다.
비트마스킹을 해주고
그럼 푸쉬버튼 인터럽트가 불렸구나
판단 하고
푸쉬버튼 ISR을 불러주기 위해서
선언도 해두었다.
불러주고 끝납니다.
만약에 푸쉬버튼 인터럽트도 쓰고
타이머 인터럽트도 쓴다고 하면 어떻게 하는가?
앞에서 else if ~~ 0x1 하면
timer ISR 이런식으로 부르고 하면 되겠죠?
어딘가에 선언해주고
새로운 인터럽트를 추가한다면!!!
Exception handler 고쳐주고
이부분에 함수 추가해주고
이런 파일 하나 만들어줘서 함수구현해 주고 이런것만 하면되고
메인 함수에서 세팅만 해주면 된다.
이런식으로 간단한 코드지만 c로 인터럽트를 짜는 부분에 대해서
한번 리뷰를 해봤습니다.
파트 1에서는 C 프로그램 짜는건데
키 프레싱 하는 이벤트는 인터럽트를 사용한다.
인터벌 타이머를 사용한다
내부적으로 카운터 벨류가 있어서
0.25초마다 타이머 인터럽트를 사용해서
타임아웃이 되면 1을 증가시킨다.
얘는 언제 하느냐 run이 1일 때
돌다가 안돌다가
KEY3를 맵핑해서 누르면 run되고 또 누르면 스톱되고
인터럽트 두개를 사용하는 방법을 여러분들이 한번 해봐라~~~~~~
키1, 2 누르면 1씩 증가하는게 아니라
레이트가 더블되는것 2를 누르면 rate가 느려지는것.