일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
- 백준
- BST
- 자료구조
- Transport layer
- boot sequence
- 응용 계층
- Embedded
- 관계형 모델
- ps
- 릿코드
- 문제풀이
- DB
- baekjoon
- 네트워크
- 프로그래머스
- swea
- leetcode
- Application Layer
- STL
- 다익스트라
- 임베디드
- 부트시퀀스
- 데이터베이스
- C++
- 전송 계층
- Database
- Network
- dp
- Djikstra
- BHS
- Today
- Total
BOBO's Note
GPIO 본문
임베디드 시스템에서 외부 디바이스와 통신할 때 high bandwidth가 필요하지 않은 경우, 주로 사용하는 인터페이스는 다음과 같다.
- I2C
- SPI
- UART
- GPIO
GPIO
GPIO는 General Puprpose Input Output의 약자로, pin의 용도를 정해놓지 않고 사용자가 자유롭게 input 또는 output 핀으로 사용할 수 있다.
한편, 보드에서 하나의 pin이 GPIO 외에 I2C와 같이 미리 정의된 기능에 연결되어 있을 수도 있는데, 이를 alternative functionality라고 한다. 핀의 모드를 설정해줌으로써 GPIO 또는 alternative functionality로 사용할 수 있다.
프로세스에서는 Memory Mapped I/O를 통해 GPIO 핀에 접근한다.
Memory Mapped I/O
메모리 영역에 I/O를 위한 레지스터를 할당해놓아서 메모리 영역에 접근하면 I/O 디바이스에 접근할 수 있게 해준다. 특정 메모리 영역에 데이터를 쓰면 외부 I/O 디바이스에 신호가 전달된다. 반대로 I/O 디바이스의 데이터를 메모리 영역에 접근함으로써 읽어올 수 있다.
이 방법은 주소 공간 내에 메모리와 I/O가 연속적인 공간을 차지하므로, I/O가 차지하는 만큼 메모리의 주소 공간 크기가 줄어든다. 대신 CPU 및 프로세스 입장에서는 메모리와 I/O가 동일하게 취급되기 때문에 I/O 디바이스에도 load/store 명령어를 통해 접근할 수 있어 로직이 간단하다.
ARM, MIPS 아키텍처에서 사용하는 방식이다.
cf) I/O Mapped I/O: 메모리와 I/O가 별개의 주소 공간에 할당된다. 따라서 I/O 디바이스에 접근하기 위해서는 별도의 명령어(예. input/output)를 사용해야 한다. Intel 아키텍처에서 사용하는 방식이다.
GPIO 제어
보드마다 GPIO를 제어하기 위한 레지스터들이 존재한다. 각 레지스터들은 앞서 말했듯이 Memory Mapped I/O 방식으로 메모리 주소를 갖는다. 따라서 특정 주소에 접근하여 레지스터를 set해주어 GPIO를 제어할 수 있다.
위 문서를 살펴보면 GPSET0, GPSET1이라는 레지스터가 존재한다. GPSETn 레지스터는 각 비트마다 GPIO 핀을 담당하고, 이 비트를 set해주면 GPIO 핀 값이 1이 된다.
반대로 GPCLRn 레지스터의 임의의 비트를 set해주면 해당하는 GPIO 핀 값이 0이 된다.
GPIO 핀 값을 0 또는 1로 설정하기 위해 하나의 레지스터가 아닌 두개의 레지스터로 나누어 설계한 이유는 access 횟수를 줄이기 위해서이다. 만약 하나의 레지스터의 각 비트 값이 그대로 GPIO 핀 값에 반영된다고 한다면, 원하는 비트만 값을 바꿔주기 위해 load → modify → store 과정을 거쳐야 한다. 반면 두 개의 레지스터로 나누어주면 원하는 값에 따라 레지스터에 write, 즉 store만 해주면 된다.
위 문서에서 GPFSELn 레지스터는 GPIO 핀의 모드를 설정하는 레지스터이다. 32비트 레지스터에서 3비트씩 하나의 GPIO 핀을 담당한다.
이처럼 각 레지스터마다, 레지스터 내의 비트마다 담당하는 제어 기능 및 GPIO 핀 번호가 다르다. 그렇지만 word 단위로 접근할 수 있기 때문에 각 비트에 직접적으로 read/write할 수 없다. 따라서 원하는 위치의 비트만 값을 바꿔주기 위해 비트 마스크 연산을 사용한다.
void set_gpio_output_value void gpio_ctr int gpio_nr int value
int
reg_id gpio_nr 32
int
pos gpio_nr 32
if
value
#define GPIO_SET_OFFSET 0x1c
uint32_t
output_set uint32_t gpio_ctr GPIO_SET_OFFSET 0x4 reg_id
*
output_set 0x1 pos
}
else
#define GPIO_CLR_OFFSET 0x28
uint32_t
output_clr uint32_t gpio_ctr GPIO_CLR_OFFSET 0x4 reg_id
*
output_clr 0x1 pos
}
}
'Embedded System' 카테고리의 다른 글
Linux에서의 전력 관리 (0) | 2020.06.17 |
---|---|
Bare Metal (0) | 2020.06.16 |
Interrupt Handler (0) | 2020.06.03 |
Kernel Module과 Device Driver (0) | 2020.05.29 |
Android Boot Sequence (0) | 2020.05.26 |