IO를 하려고 임베디드 시스템을 한다.
lab4에서는 인터럽트를 사용하지 않고 사용하는 IO
lab5에서는 인터럽트를 사용해서 IO를 사용한다.
Memory-Mapped IO
메모리의 일정 부분인냥 IO를 다루게 된다.
다른 프로세서들은 IO를 위한 포트가 따로 있고
명령어가 따로 있고 사용하는 방식도 다른 방식으로 동작하는데
Memory -mapped IO는 메모리 명령어와 동일하게 사용한다.
peripheral device와
load/store 명령어를 사용해서 peripherals도 사용할 수 있다.
io 명령어를 뒤에 붙여주면 된다.
안붙여줘도 되지만 cache를 bypass 해주기 위해서 io를 뒤에 붙여 준다.
cache 캐시는 cpu에 있는것 (서럽장 같은 존재. 사용하면 빠른데 캐시에 있는 데이터와 메모리에 있는 데이터가 카피가 되기 때문에 달라질 수 있다?)
IO같은 경우 포트에 가서 쓰는데 센서값을 읽을 수도 있는데
센서의 지금값을 타와야하는데 캐시에 있는 옛날 값을 읽어올 수 있다.
맵핑을 적어준것이 위의 헤더 파일이다.
HEX3_HEX0_BASE의 번지가 0xFF200020 이다.
IO 종류가 두가지가 있다.
인터럽트를 사용하는지 안하는지
Polled IO
폴이 선거하고 투표하고 이런것이 폴드 IO 인데
'계속 IO입장에서는 물어봄을 당한다'
CPU가 디바이스 상태를 체크하는겁니다.
주도적으로 주기적으로 지켜본다.
busy-wait IO
in_status 가 0이 아니면 빠져 나와서
데이터를 로드해서 저장한다.
스토어를 한다.
다시 out_status를 계속 체크한다.
인풋이 되었건 아웃풋이 되었건
cpu가 다른 일을 할 수 없고 체크를 해야한다.
효율적이지 못하다.
두개의 일을 동시에 처리하기 어렵다.
실질적으로 사용하지는 않고 interrupt IO를 많이 사용한다.
푸시버튼, 스위치, LED, 7-segments
네개가 메이저한 페럴들이다.
그밖에 다양한 것들이 존재하는데
파란색으로 된것이 niosII 인데
외부센서를 꼽는다거나 ~ 확장할 수 있도록
제너럴 포트들이 오픈이 되어있다.
어떤 포트들은 readable 어떤 포트들은 writable
쓸 수 있는 포트들을 다르게 세팅할 수 있다.
메모리 맵트라고 하니까 메모리 영역이라고 생각하면 된다
offset이 0,4,8,12가 있다.
4
디렉션 비트는 비어있는 패널 포트들에
센서를 붙일지 모터를 붙일지 모르니까
방향이 R/W를 정해줄 필요가 있는데
방향을 정해주는것이 R/W 비트이다.
포트에 핀이 있는데 인풋으로 쓸지 아웃풋으로 쓸지 정해놓고 가는데
리드인지 라이트 인지 결정을 해줘야하는데
이것을 선언해주는것이 디렉션
8
인터럽트 마스크
1에 세팅해두면 해당하는 비트를 인터럽트로 발생시키는데 써먹겠다.
0으로 세팅해두면 사용하지 않겠다는 말이다.
12
엣지캡쳐 레지스트
인터럽트가 발생했으면 가서 읽어보면
어느놈이 눌렸는지 판단을 해야하니까 가서 읽어본다.
그것이 엣지 캡쳐 레지스터이다.
IO포트들은 어드레스가 결정되어있고
베이스 레지스터 기준으로 +4 +8 +12 해서
4개의 워드 크기로 특정 IO port와 맵핑이 되어있다.
+16하면 어떤 것이 나올까?
16진수니까 베이스 주소가 첫자리가 항상 0이다.
두번째 자리가 하나씩 혹은 둘씩 올라가게 된다.
그렇게 해서 매모리 mapped 레지스터가 각각 무엇을 하는지 알 수 있었다.
푸쉬 버튼도 베이스 어드레스가 존재한다.
안쓰는 비트가 있겠지만 프로그램 편이를 위해서
32비트 즉, 워드 단위로 ldw와 stw를 사용할것 이다.
푸쉬버튼 같은 경우 각각이 한비트이다. 0번비트 1번비트 3번 비트가 있다.
KEY3-0까지 맵핑이 되어있고
훨씬 많은 비트들은 사용하지 않는다.
버튼 누르면 1로 표시, 버튼 안눌렀으면 0으로 표시
슬라이더 스위치도 10개의 비트가 필요하다.
푸쉬버튼도 마찬가지로
4개의 하위 비트를 사용한다.
디렉션 비트는 사용안하고
인터럽트를 사용가능하다.
이것이 데이터 레지스터이다.
읽어오면 됩니다. (LDW를 사용해야 한다.)
unused bit는 direction
세그먼트는 BASE 레지스터가 있는데 (이름에 베이스가 붙어 있다.)
베이스 어드레스가 존재한다.
LED나 세그먼트는 STW를 사용해줘야 한다. (아웃풋이 므로)
LED가 10개의 비트가 할당이 되어있다.
아웃풋인것이 결정이 되어있으니까
디렉션 워드는 필요하지 않다.
7-segment는 8비트 마다 하나씩 세그먼트가 맵핑이 되어있다.
두개의 베이스 어드레스가 필요하다.
주석에 써있듯이 슬라이더 스위치가
스위치 value가 있는데 그대로 읽어서 (10개가 있는데 )
LED도 10개가 있는데
LDER에 표시를 한다.
HEX display에 로테이팅 패턴을 디스플레이 한다.
키버튼이 눌러져 있을 때
소프트웨어 스위치 벨류를 보여준다.
r6에 값을 집어 넣는다.
r16이 LED
값을 읽어서 LED값을 읽는다.
r17값을 불러와서
r0이면 NO_BUTTON
0이 아니면 눌렸으니까 r4의 값을 r6에 저장한다.
r4의 값이 슬라이더 스위치의 벨류입니다.
WAIT로 가면
r17의 값을 다시 읽어서 r5에 넣는다.
0이 아니면 계속 WAIT에 있는다
푸쉬버튼을 땔 때까지 기다리는것 입니다.
(아무리 짧게 눌렀다 때도 WAIT를 여러번 돈다.)
눌렀다가 땔 때를 디텍트하는것이다.
NO_BUTTON
버튼이 눌러져 있지 않은 상태
r20에 r6을 집어 넣는다.
그전에 있던
슬라이더 스위치 값을 집어 넣는다.
한비트씩 쉬프트 시키고
r7값에 50,000을 집어 넣어서 딜레이로 간다.
r7에서 1을 넣고
0인지 아닌지 체크하고
딜레이를 한다.
50만번 정도하면 의미있는 시간이 흐른다?
일부로 딜레이를 넣어줘서 IO속도에 맞춰주는것 입니다.
(조절해줄 수 있는값)
딜레이가 끝나면 다시 DO_DISPLAY로 간다.
많이 쓰는 기능 중에 하나가
굉장히 자주 쓰는 것이 타이머이다. 인터벌 타이머
주기적으로 일을 해야하는데 신호를 처리할 때
샘플링 주기가 있는데 아날로그 신호가 있고하는데
40k의 1초마다 타이머를 걸어줘야 겠죠? (예를 들어서)
마찬가지로 모터도 rpm을 어떻게 해줄지는 타이머에 따라서 달려있습니다.
모터가 얼마나 돌것인가~
임베디드 시스템은 타이머 기능을 필수적으로 사용한다.
리얼타임 클락을 구현하는데 사용된다.
타이머는 보드에 보면 클락이 존재한다.
오실레이터가 존재하는데 100MHZ로 돌고 있다.
cpu는 보통 디지털 보드에 오실레이터가 있어서
클락을 넣어주는데 이것을 기준으로해서
한클락에 하나씩 작업이 이루어지는데
아무리 바빠도 클락을 쪼개서 쓰지는 않습니다.
최소 100M분의 1초로 걸수있다?
조금더 복잡한데
어드레스는 6개의 워드 영역을 사용하고 있는데
실제로는 모든 워드가 하위 16비트만 사용하고 있다. (nios II가 그렇다. 다른것은 다를지도 모름)
첫번째 워드에서는 하위 두개의 비트만 사용
RUN 비트와 TO(타임아웃 비트)
두번째 워드에서는 4개의 비트를 사용한다.
STOP START CONT ITO
나머지는 16비트를 사용한다.
시험에 필요하면 위의 그림은 시험지에 붙어있을것입니다.
하지만 각각 비트가 어떻게 사용되는지는 머리속에 넣어두셔야 합니다.
위의 두 워드는 다음장에서 설명하고
밑의 얘기를 해볼게요
Counter start value
비트는 32비트 타이머를 사용하는데
2^32 -1 까지 클락을 카운트 할 수 있다.
숫자를 세팅해두면 숫자안에서 줄어드는것이다.
타임아웃하는것 있잖아요?
D-100같은 느낌
이클락에 1000이렇게 나왔다면
1000클락 이후에 종료되는것 입니다.(타임아웃)
32비트에 한방에 넣지않고
위에는 high
아래는 low
이렇게 해서 두개의 워드를 사용한다.
갑자기 STOP을 누르면 스탑되어있는것
snaph, snapl
내려가는 숫자라고 생각하면 됩니다.
실제로 타임을 스타트해서 run하면 시간 지난다음에 읽어보면
그때 숫자가 지금 시간이 얼만큼 지났는지 보여줄 수 있는
예를 들어서 10만 중에서 3만이 지났으면 7만이 저장되어있을것이다.
TO
타임아웃이 발생했을 때 원래0이었다가 1로 바뀐느것이다.
1이 세팅이 된다음에 계속 1이 되어있을것 아닙니까?
새롭게 발생하면 알수없으니까
TO를 클리어 해줘야 하는데
아무값이나 세팅해주면 0으로 간다.
RUN
Read only이다
카운터가 running할 떄 제대로 러닝하고 있는지 읽어올 수있다.
러닝 중에는 1 아닐 때는 0이다.
세팅해줄수있는것이 아니라 듣는것이다.
기본적으로 스테이터스 레지스터는 리드 온리이다.
STOP
스탑 비트에 1로 적어주면 멈춘다.
라이트 온리입니다.
ITO
인터럽트 타임아웃
인터럽트를 타이머에서 사용할지 안할지를 결정해준다.
1로 세팅이 되어있으면 타임아웃 했을 때
그 순간에 인터럽트가 발생하는것
사용안한다면 0으로 세팅해둔다.
CONT
1로 세팅해두면 타임아웃이 주기적으로 발생한다.
1000클락마다 주기적으로 발생한다.
이값이 0이면 한번 타이머 발생하고 끝난다.
START
말그대로 스타트이다.
1로 라이트 해주면 타이머가 그때 부터 돌기 시작한다
끄려면 0으로 적어주느냐"? 아닙니다.
스탑 비트를 1로해두고
다시 시작하려면 스타트를 1로 해준다.
라이트 온리입니다.
첫번 째는 키가 4개가 있는데
푸쉬버튼가 7세그먼트를 사용해서 넘버를 왔다 갔다 하는것을 할것이다
내부적인 숫자가 있는데
그숫자를 HEX0에 넣어둘것이고
키1은 숫자 상승
키2는 숫자 하강
키3은 리셋 넘버( HEX0를 턴 오프해서 리셋 넘버)
폴드 IO를 사용하라
키 버튼이 눌러졌는지 안눌렸는지
릴리스가 됬는지 안됬는지를 정확하게 디텍트해라
r7값을 읽어와서 0랑 비교해서
눌러져 있는지 안눌러져 있는지 확인한다.
눌려질 때 까지는 뻉뻉이 를 돈다
눌리면 wait로 넘어가서 뺑뻉이 돌고
때지면 빠져나온다.
옛날값은 r6에 저장되어있는데
r6이랑 1이랑 and를 해서 비트마스킹을 하는것입니다.
r6의 최하위비트만 살아나고 나머지는 0인것이 r4에 들어가서
r4가 0이랑 다르면 key 0가 눌린것이니 reset call로 간다.
어떤 키가 눌러져있는지 읽어오는것
서브루틴은 여러분이 작성하세요 ^^
스켈레톤 코드는 주어졌구요
파트 2는 타이머를 사용하는것이고
1초에 한번씩 카운터가 증가하도록 어떻게 하는가
인터럽트 카운터를 폴링 방식으로 사용해라
100M를 넣어줘서 정확하게는 -1한 값을
어디에 넣어주냐
위에 끊어서 넣어주고
폴드IO를 사용해서 타임아웃 될 떄까지 사용하는것이다.
폴드 IO에 대해서 알아봤는데 프로젝트하면서
부족한 부분이 있으면 알테라 PDF를 참고하세요.
'제어 > 전자HW설계' 카테고리의 다른 글
Lab6 (0) | 2020.10.26 |
---|---|
Lab5 (0) | 2020.10.14 |
[전자HW설계] LAB3 (0) | 2020.09.30 |
[전자HW설계] LAB2 (0) | 2020.09.22 |
[전자HW설계] 3-1 [Nios II 이론 마무리] (0) | 2020.09.14 |