라즈베리파이 4 (BCM2711)에서 메모리 맵 I/O로 GPIO를 직접 제어해보는 예시 일부를 요약해서 필기해보았다.
메모리 맵 I/O (Memory-Mapped I/O)
개념:
CPU의 주소 공간에 메모리뿐 아니라 I/O 장치 레지스터(GPIO, UART, SPI 등)를 같은 주소 공간에 배치하는 방식.
→ CPU는 메모리에 접근하는 것과 동일한 방식으로 장치를 제어할 수 있음.
전체 메모리 공간을 메모리와 I/O 장치로 나눠서 사용
버스 요약
Address bus: CPU는 값을 가져오기 위해 접근할 메모리/장치 주소를 어드레스 버스를 통해 설정
Data bus: 데이터버스를 통해 값을 읽어옴.
Control bus: 읽기/쓰기 동작 제어 (입출력 방향 설정)

어드레스 버스를 통해 GPIO와 같은 H/W에 접근, 메모리 특정 주소를 사용해 GPIO에 값을 보내거나, 들어오는 값을 읽는다.

mmap()으로 라즈베리파이 led 제어해보기
bcm2711의 메모리 주소 맵핑


- BCM2711의 GPIO주소

GPIO base 주소: 0x7E200000 (I/O base + 0x200000)
- GPIO 주요 레지스터



GPFSELn (GPIO Function Select) : 각 GPIO 핀의 입출력 모드 설정 (핀당 3비트)
GPSETn : GPIO 출력 High (1로 설정)
GPCLRn : GPIO 출력 Low (0으로 클리어)
GPLEVn : 현재 입력 레벨 확인
- GPIO 방향 설정 (GPFSEL)

핀 하나당 3비트씩 할당하여 I/O 방향을 설정.
입력 : 000, 출력 : 001
특정 핀 번호를 GPFSEL 레지스터에서 찾는 방법:
총 0~5번으로 6개의 GPFSEL레지스터. gpio핀은 58개,
핀번호 / 10 → 사용할 GPFSEL 레지스터 선택
핀번호 % 10 → 그 레지스터 내에서의 비트 위치
mmap()
Memory-mapped I/O: I/O 장치를 메모리 주소 공간에 포함시켜 접근
Raspberry Pi 4 (BCM2711): GPIO base는 0xFE200000
직접 제어: /dev/mem → mmap()으로 매핑 → GPIO 레지스터 접근 → 토글
이제 mmap()을 알아보고 직접 제어를 해볼 것이다.
#include <sys/mman.h>
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
int munmap(void *addr, size_t length);
(사물인터넷을 위한 리눅스 프로그래밍 with 라즈베리파이)
mmap() : fd가 가리키는 객체를 offset의 값을 기준으로 length 만큼 메모리에 매핑하도록 커널에 요청하면 매핑된 시작 주소가 반환된다.
munmap() : mmap()함수와 연결된 메모리 해제.
주요 코드 흐름
/dev/mem → mmap()으로 매핑 → GPIO 레지스터 접근 → 토글
- /dev/mem 열기커널이 관리하는 물리 메모리 공간에 접근하기 위해 /dev/mem 사용
mem_fd = open("/dev/mem", O_RDWR | O_SYNC);- mmap()으로 물리 주소를 가상 주소에 매핑GPIO 레지스터 주소 영역을 프로세스의 가상주소에 매핑
gpio_map = mmap(NULL, GPIO_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, mem_fd, GPIO_BASE);- GPIO 포인터 설정이제 gpio[]배열처럼 접근하면 실제 레지스터에 읽기, 쓰기 가능하다.
gpio= (volatile unsigned *)gpio_map;
- GPIO를 출력으로 설정 하는예
GPIO\_OUT(gno);
매크로로 해당 핀을 출력 모드(001)로 설정.
LED 토글
GPIO_SET(gno) //high sleep(1); GPIO_CLR(gno) //Low sleep(1);1초 간격으로 GPIO핀을 on/off하는 예.
리소스 해제!
munmap(gpio_map, GPIO_SIZE); close(mem_fd);
'Linux' 카테고리의 다른 글
| 문자 디바이스 파일 (주 번호와 부번호 할당, 번호 등록과 사용) (2) | 2025.08.17 |
|---|---|
| [리눅스 커널과 디바이스 드라이버]애플리케이션->syscall->vfs->디바이스파일open 까지 (2) | 2025.08.17 |
| 리눅스 디바이스 드라이버 - module_init() 모듈 등록부터 사용자 호출까지 (1) | 2025.08.17 |
| syscall번호를 테이블에 넣어 커널에 빌트인하여 사용 (2) | 2025.08.17 |
| U-Boot 부팅 흐름 과정 요약 2 -Linux kernel 로드 (3) | 2025.08.16 |