이 글은 라즈베리파이의 HDMI에 연결된 화면에 텍스트와 그래픽을 표시하기위해 저수준에서 수행해야하는 작업을 정리한 것이다. 라즈베리파이 리눅스 커널에는 이미 구현되어 있으므로 일반적인 경우 이것을 할 필요가없다.
프레임버퍼는 기본적으로 소프트웨어가 구성하는 일부 파라미터에 기초하여 화면 좌표에 매핑되는 메모리 블럭이다. 이것을 어떻게 구성하는지에대한 설명을하기 전에 Raspberry Pi가 어떻게 작동하는지 이해해야한다.
Raspberry Pi에 사용되는 SoC는 ARM CPU 와 브로드컴 GPU를 탑재한 고성능 프로세서이다. 최초 GPU가 먼저 부팅되고 기본적으로 SD 카드에서 펌웨어 파일을 읽어서 실행한다음 커널 이미지를 메모리에 로드하고 실행한다. 이 과정에서 ARM CPU는 초기화 메시지를 작성하고 메시지의 메모리 주소를 GPU에 전달해야한다. 프로세서 간의 통신은 mailbox 메커니즘을 사용한다.
mailbox는 두 프로세서가 모두 접근할 수 있도록 설정된 Peripheral, 하드웨어 레지스터에 불과하다. mailbox의 하드웨어 레지스터 주소는 다음과 같다.
REGISTER |
OFFSET |
Base |
0xB880 |
Poll |
0xB890 |
Sender |
0xB894 |
Status |
0xB898 |
Configuration |
0xB89C |
Write |
0xB8A0 |
이 레지스터들 중 일부만 사용한다.
우선 mailbox에 쓰기는 다음과 같이 수행할 수 있다.
1. 상태 레지스터 (0xB898)를 읽는다.
2. 31번 비트(0x80000000)가 설정되어 있는지 확인한다. (mailbox가 Full인 경우 설정됨)
3. 설정된 경우 1단계로 돌아가고 아니면 다음 단계로 진행한다.
4. 기록 할 데이터는 4비트씩 왼쪽으로 이동해야 한다. 이것은 주소를 28비트로 변환한다.
5. 하위 4비트에는 mailbox 채널 번호가 포함되며, 4 단계의 28비트 주소와 논리 OR연산을 수행하여 이를 28비트 주소와 결합한다.
6. 쓰기 레지스터 (0xB8A0)에 데이터를 쓴다.
mailbox에서 읽기는 다음과 같이 한다.
1. 상태 (0xB898) 레지스터를 읽는다.
2. 30번 비트 (0x40000000)가 설정되어 있는지 확인한다.(mailbox가 Empty인 경우 설정됨)
3. 설정된 경우 1 단계로 돌아간다.
4. 메일박스 base 레지스터 (0xB880)를 읽는다.
5. 하위 4비트에는 응답 한 mailbox의 채널 번호가 포함된다. 원하는 mailbox와 일치하는지 확인하고 그렇지 않으면 1단계로 돌아간다.
6. 상위 28비트에는 처음 전달한 주소와 동일한 주소가 포함되어야 한다.
mailbox로 주고받는 주소는 4비트씩 왼쪽으로 이동한다. 처음 4비트에는 mailbox 채널 번호가 포함되어 있기 때문이다.
메일박스 채널은 10개이다.
0. Power management
1. Framebuffer
2. Virtual UART
3. VCHIQ
4. LEDs
5. Buttons
6. Touch screen
7. NA
8. Mailbox-property-interface – ARM to GPU
9. Mailbox-property-interface – GPU to ARM
채널 1이 프레임 버퍼 채널로 표시되어 있지만 PRI2부터 채널 8을 사용한다.
Configuration
프레임 버퍼를 구성하려면 다양한 태그를 쿼리하고 적절한 값으로 설정하면 된다. 아래는 프레임 버퍼와 관련된 태그 목록이다.
REGISTER |
ADDRESS |
Allocate buffer |
0x00040001 |
Release buffer |
0x00048001 |
Blank screen |
0x00040002 |
Get physical (display) width/height |
0x00040003 |
Test physical (display) width/height |
0x00044003 |
Set physical (display) width/height |
0x00048003 |
Get virtual (buffer) width/height |
0x00040004 |
Test virtual (buffer) width/height |
0x00044004 |
Set virtual (buffer) width/height |
0x00048004 |
Get depth |
0x00040005 |
Test depth |
0x00044005 |
Set depth |
0x00048005 |
Get pixel order |
0x00040006 |
Test pixel order |
0x00044006 |
Set pixel order |
0x00048006 |
Get alpha mode |
0x00040007 |
Test alpha mode |
0x00044007 |
Set alpha mode |
0x00048007 |
Get pitch |
0x00040008 |
Get virtual offset |
0x00040009 |
Test virtual offset |
0x00044009 |
Set virtual offset |
0x00048009 |
Get overscan |
0x0004000a |
Test overscan |
0x0004400a |
Set overscan |
0x0004800a |
Get palette |
0x0004000b |
Test palette |
0x0004400b |
Set palette |
0x0004800b |
이 태그들을 사용하여 메세지 버퍼를 설정한다. 이 버퍼의 주소를 위에서 설명한 mailbox 메커니즘을 통해 그래픽 프로세서로 전송해야 한다.
중요한 것은, 메시지를 보내고 응답을 받는 것이 아니라 전달한 버퍼가 GPU에의해 직접 수정된다는 것이다.
메시지를 주고받는 것처럼 보이게 하여 mailbox 비유가 혼란스러울 수 있다. 실제로는 버퍼를 제공하고 원래 요청 값 중 일부가 그래픽 프로세서에 의해 적절한 응답 값으로 수정된다.
프레임 버퍼를 구성하는 데 사용할 버퍼는 16바이트에 맞춰야 함을 기억하자. 부호 없는 32비트 정수의 배열로 선언해야 한다. 이 버퍼의 레이아웃은 다음과 같다.
OFFSET |
DESCRIPTION |
0 |
Total Buffer size (number of bytes) |
1 |
Request/Response indicator 0x00000000 – Request 0x80000000 – Success Response 0x80000001 – Error Response |
2 |
Tag ID |
3 |
Tag value length (number of bytes) |
4 |
Tag Request/Response indicator 0x00000000 – Request 0x80000000 – Success Response 0x80000001 – Error Response |
5 |
Value data |
… |
Value data |
n |
0 – End tag |
주의 할 점은 이 버퍼의 주소에 0x40000000 더하여 GPU에 전달해야한다. 주소에 0x400,000 을 더하는 이유는 GPU에서 RAM을 매핑하여 물리적 주소 0x400,000 에서 시작하기 때문이다(L2 캐싱이 활성화된 경우). 비활성화된 경우 실제로는 0xC0000000 에서 시작한다.
GPU가 물리적 메모리에서 0x400,000 + our_address 에 액세스할 때, 실제로는 RAM의 our_address 에 액세스하는 것이다.
기본 프레임 버퍼 기능을 구성하는 단계는 다음과 같다.
1. 태그 0x00040003을 사용하여 프레임 버퍼의 실제 너비와 높이를 쿼리한다. 응답은 HDMI 포트에 부착된 모니터의 지원되는 크기와 일치해야 한다.
2. 1단계의 정보를 사용하여 모든 관련 태그를 한 번에 설정하여 일치하는 프레임버퍼 할당을 요청한다. 요청을 하나씩 전송하는 것은 그래픽 프로세서가 모든 파라미터를 무시하게 되므로, 하나의 요청에 통합 태그를 사용하는 것이 중요하다. 설정할 태그는 다음과 같다.
0x00048003 – 물리적 폭과 높이를 설정한다. 이것은 1단계에서 알 수 있다.
0x00048004 – 가상 너비 및 높이를 설정. 일단은 물리적 설정과 동일한 값으로 설정.
0x00048005 – 깊이를 설정한다. 이것은 색상을 나타내기 위해 픽셀 당 몇 비트를 사용해야 하는가를 의미한다. (16과 24 만 시도했다.)
0x00040001 – 실제 버퍼를 메모리에 할당을 요청한다.
3. 오류를 확인하여 응답을 구문 분석한다.
4. 프레임 버퍼의 한 행에 몇 바이트가 있는지 알려주는 태그 0x00040008을 사용하여 피치를 얻는다.
마무리
모든 것이 제대로 진행됐다면 응답으로 실제 프레임버퍼 메모리 주소(포인터)를 받을 것이다.
소스코드 및 문서:
linux/drivers/video/fbdev/bcm2708_fb.c
번호 | 제목 | 글쓴이 | 날짜 | 조회 수 |
---|---|---|---|---|
13 | POSIX를 지원하는 오픈소스 RTOS, RTEMS | makersweb | 2020.04.15 | 2633 |
12 | 라즈베리파이2에서 RTOS기반 GPIO제어(LED) | makersweb | 2020.04.21 | 2498 |
» | Raspberry Pi 의 프레임버퍼(Framebuffer)구성 | makersweb | 2020.05.15 | 2752 |
10 | Android 기기를 사용하여 Raspberry Pi SD 카드 작성 방법 | makersweb | 2020.08.01 | 1802 |
9 | 플랫폼 디바이스 및 디바이스 트리 | makersweb | 2021.03.20 | 4925 |
8 | ATtiny85 개발보드(HW-260) | makersweb | 2023.01.02 | 1346 |
7 | 임베디드 개발자를 위한 Hex,Bin,Dec 변환기 유틸 | makersweb | 2023.02.27 | 1849 |
6 | 로직분석기와 함께 PulseView 를 사용해서 CAN 신호 캡쳐 | makersweb | 2023.03.16 | 1481 |
5 | Raspberry Pi 와 ATtiny85 간 I²C 통신 | makersweb | 2023.03.18 | 1310 |
4 | Yocto 프로젝트 3.4 릴리스(honister) 이상 버전으로 마이그레이션 시 참고 사항 | makersweb | 2023.03.21 | 1913 |
3 | Raspberry Pi에서 I²C 그리고 Bit-bang (비트뱅) | makersweb | 2023.08.27 | 1576 |
2 | Rockchip VOP | makersweb | 2024.04.22 | 968 |
1 | OpenAMP 간단한 소개 | makersweb | 2024.09.21 | 598 |