임베디드 | 라즈베리파이 | ARM | 리눅스 | Qt | 딥러닝

로봇만들기 +6

config.txt 에 vc4-kms-v3d 체크 확인

sudo nano /boot/firmware/config.txt

 

sudo apt install libdrm-dev

sudo apt install libinput-dev

 

 

// drm_example.c

#include <drm/drm.h>
#include <drm/drm_mode.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <xf86drm.h>
#include <xf86drmMode.h>
#include <sys/mman.h>
#include <errno.h>

#define DEVICE "/dev/dri/card0"

int main() {
    int fd = open(DEVICE, O_RDWR | O_CLOEXEC);
    if (fd < 0) {
        perror("Failed to open DRM device");
        return 1;
    }

    drmModeRes *resources = drmModeGetResources(fd);
    if (!resources) {
        perror("drmModeGetResources failed");
        close(fd);
        return 1;
    }

    // Pick the first connected connector
    drmModeConnector *connector = NULL;
    for (int i = 0; i < resources->count_connectors; ++i) {
        connector = drmModeGetConnector(fd, resources->connectors[i]);
        if (connector->connection == DRM_MODE_CONNECTED) {
            break;
        }
        drmModeFreeConnector(connector);
        connector = NULL;
    }

    if (!connector) {
        fprintf(stderr, "No connected connector found\n");
        drmModeFreeResources(resources);
        close(fd);
        return 1;
    }

    drmModeModeInfo mode = connector->modes[0]; // Use the first mode
    int width = mode.hdisplay;
    int height = mode.vdisplay;

    drmModeEncoder *encoder = drmModeGetEncoder(fd, connector->encoder_id);
    uint32_t crtc_id = encoder->crtc_id;

    // Create dumb buffer
    struct drm_mode_create_dumb creq = {0};
    creq.width = width;
    creq.height = height;
    creq.bpp = 32;
    if (drmIoctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &creq) < 0) {
        perror("DRM_IOCTL_MODE_CREATE_DUMB failed");
        return 1;
    }

    uint32_t handle = creq.handle;
    uint32_t pitch = creq.pitch;
    uint64_t size = creq.size;

    // Create framebuffer
    uint32_t fb;
    if (drmModeAddFB(fd, width, height, 24, 32, pitch, handle, &fb)) {
        perror("drmModeAddFB failed");
        return 1;
    }

    // Map buffer
    struct drm_mode_map_dumb mreq = {0};
    mreq.handle = handle;
    if (drmIoctl(fd, DRM_IOCTL_MODE_MAP_DUMB, &mreq)) {
        perror("DRM_IOCTL_MODE_MAP_DUMB failed");
        return 1;
    }

    uint8_t *map = mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, mreq.offset);
    if (map == MAP_FAILED) {
        perror("mmap failed");
        return 1;
    }

    // Fill with a solid color (e.g., blue)
    memset(map, 0, size);
    for (int y = 0; y < height; ++y) {
        uint32_t *row = (uint32_t *)(map + y * pitch);
        for (int x = 0; x < width; ++x) {
            row[x] = 0xFF0000FF; // ARGB: Blue
        }
    }

    // Set CRTC (display the framebuffer)
    if (drmModeSetCrtc(fd, crtc_id, fb, 0, 0, &connector->connector_id, 1, &mode)) {
        perror("drmModeSetCrtc failed");
        return 1;
    }

    printf("Frame displayed. Press Enter to exit...\n");
    getchar();

    // Clean up
    munmap(map, size);
    drmModeRmFB(fd, fb);

    struct drm_mode_destroy_dumb dreq = {0};
    dreq.handle = handle;
    drmIoctl(fd, DRM_IOCTL_MODE_DESTROY_DUMB, &dreq);

    drmModeFreeEncoder(encoder);
    drmModeFreeConnector(connector);
    drmModeFreeResources(resources);
    close(fd);

    return 0;
}

 

 

 

 

에러발생

/usr/include/xf86drm.h:40:10: fatal error: drm.h: No such file or directory
   40 | #include <drm.h>
      |          ^~~~~~~

 

1. 

 pkg-config --cflags libdrm

dpkg -L libdrm-dev | grep drm.h

find /usr/include -name drm.h

drm.h가 있나보라

1-1) 컴파일 할때 -I옵션을 주던가

1-2) Makefile에 추가하기

 

# 컴파일러
CC := gcc

# 컴파일 옵션
CFLAGS := -Wall -O2 -I/usr/include/libdrm
#CFLAGS := -Wall -O2 -I/usr/include/libdrm 
# ㄴ 이게 핵심이다. 

# 링커 옵션
LDFLAGS := -ldrm
LDFLAGS_prepend = "-linput "
# 타겟 실행 파일 이름
TARGET := drm_example

# 소스 파일
SRC := drm_example.c

# 기본 빌드 타겟
all: $(TARGET)

$(TARGET): $(SRC)
        $(CC) $(CFLAGS) -o $(TARGET) $(SRC) $(LDFLAGS)

# 정리
clean:
        rm -f $(TARGET)

1-3) 환경 변수 사용

export C_INCLUDE_PATH=/usr/include/libdrm:$C_INCLUDE_PATH
gcc -o drm_example drm_example.c -ldrm

 

*에러 참고링크

https://github.com/agherzan/meta-raspberrypi/issues/987

https://forum.lvgl.io/t/what-drm-and-libinput-library-versions-is-lvgl-expecting/18426/2

https://bugs.gentoo.org/689768

$ pkg-config --cflags libdrm
-I/usr/include/libdrm

 

 

메이크 잘 되어졌다. 

 

 

 ./drm_example
drmModeSetCrtc failed: Permission denied

실행시 에러 발생

 

2. 사용자를 video 그룹에 추가하기
DRM 디바이스 파일들은 일반적으로 video 그룹 소유입니다:

ls -l /dev/dri/

crw-rw----+ 1 root video 226, 0 Jun 10 10:00 card0

sudo usermod -aG video $USER

 

3. 권한 임시 변경 (테스트용)

sudo chmod a+rw /dev/dri/*

 보안상 권장되지 않으며, 부팅 시 초기화됩니다.

 

4. udev rules로 영구 권한 변경 (선택사항)

/etc/udev/rules.d/99-drm.rules에 아래 내용 추가:

KERNEL=="card*", GROUP="video", MODE="0660"

sudo udevadm control --reload-rules
sudo udevadm trigger

 

 

 

X서버 또는 Wayland에서 실행하면 안된다.

✔️ 해당 프로그램은 CRTC 설정을 직접 하므로, Xorg/Wayland가 실행 중이면 실패합니다.

 

echo $XDG_SESSION_TYPE

결과가 x11, wayland, 또는 wayland+x11이면 GUI가 실행 중이라는 뜻입니다.

콘솔로 전환 

sudo systemctl stop lightdm      # Ubuntu 계열

sudo systemctl stop display-manager  # 일반적으로 이걸로도 가능

라즈베리파이*

sudo systemctl disable lightdm

sudo reboot

 

✅ 장치가 실제로 CRTC를 지원하는지 확인

sudo apt install libdrm-tests

modetest -c

이 명령으로 CRTC/Connector 정보가 출력되지 않으면, 해당 드라이버가 KMS 모드를 제대로 지원하지 않는 겁니다.

 

 

 

 

lightdm 을 끄고 ./drm_example 실행하면

HDMI 화면에 파란색화면이 나타난다.

이로써 라즈베리파이에서도 DRM출력이 가능한 것을 알게되었다.