VID_20250630_165629
灵眸开发板没有加载FrameBuffer驱动和设备,但是有挂在DRM设备:
因此想要操作HDMI接口输出文字或者动图,那就需要用到DRM的应用层代码,我这里移植的是ATOMIC接口的DRM应用代码,DRM-ATOMIC接口应用层代码所使用的基本元素是property(属性),这个在Linux驱动层开发中有提到,property可以对ATOMIC接口下挂的各种模块比如CRTC、Connector等进行操作,实现调整对比度,分辨率,拉伸,缩放,伽马值,连接接口类型等操作,而本帖对property的操作并不多,主要是使用ATOMIC接口抽象出来的Framebuffer,Framebuffer又下挂有一个缓存(Buffer),操作方式就跟直接操作/dev/fb0设备一模一样,应用层代码也是这么写的:
- #include
- #include
- struct drm_device
- {
- uint32_t width;
- uint32_t height;
- uint32_t pitch;
- uint32_t handle;
- uint32_t size;
- uint32_t *vaddr;
- uint32_t fb_id;
- struct drm_mode_create_dumb create ;
- struct drm_mode_map_dumb map;
- };
- static int DRM_Create_FrameBuffer(struct drm_device *bo)
- {
- /* create a dumb-buffer, the pixel format is XRGB888 */
- bo->create.width = bo->width;
- bo->create.height = bo->height;
- bo->create.bpp = 32;
- /* handle, pitch, size will be returned */
- drmIoctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &bo->create);
- /* bind the dumb-buffer to an FB object */
- bo->pitch = bo->create.pitch;
- bo->size = bo->create.size;
- bo->handle = bo->create.handle;
- drmModeAddFB(fd, bo->width, bo->height, 24, 32, bo->pitch,
- bo->handle, &bo->fb_id);
-
- printf("pitch = %d ,size = %d, handle = %d \n",bo->pitch,bo->size,bo->handle);
- /* map the dumb-buffer to userspace */
- bo->map.handle = bo->create.handle;
- drmIoctl(fd, DRM_IOCTL_MODE_MAP_DUMB, &bo->map);
- bo->vaddr = mmap(0, bo->create.size, PROT_READ | PROT_WRITE,
- MAP_SHARED, fd, bo->map.offset);
- /* initialize the dumb-buffer with white-color */
- memset(bo->vaddr, 0xff,bo->size);
- return 0;
- }
- static void DRM_Destroy_FrameBuffer(struct drm_device *bo)
- {
- struct drm_mode_destroy_dumb destroy = {};
- drmModeRmFB(fd, bo->fb_id);
- munmap(bo->vaddr, bo->size);
- destroy.handle = bo->handle;
- drmIoctl(fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy);
- }
- int DRM_Init()
- {
- int i;
- drmModeObjectProperties *props;
- drmModeAtomicReq *req;
- fd = open("/dev/dri/card0", O_RDWR | O_CLOEXEC);
- res = drmModeGetResources(fd);
- crtc_id = res->crtcs[0];
- conn_id = res->connectors[0];
- drmSetClientCap(fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
- plane_res = drmModeGetPlaneResources(fd);
- for(i=0;i<3;i++){
- plane_id[i] = plane_res->planes[i];
- printf("planes[%d]= %d\n",i,plane_id[i]);
- }
- conn = drmModeGetConnector(fd, conn_id);
- buf.width = conn->modes[0].hdisplay;
- buf.height = conn->modes[0].vdisplay;
- DRM_Create_FrameBuffer(&buf);
- drmSetClientCap(fd, DRM_CLIENT_CAP_ATOMIC, 1);
- /* get connector properties */
- props = drmModeObjectGetProperties(fd, conn_id, DRM_MODE_OBJECT_CONNECTOR);
- printf("/-----conn_Property-----/\n");
- get_property(fd, props);
- printf("\n");
- pc.property_crtc_id = get_property_id(fd, props, "CRTC_ID");
- drmModeFreeObjectProperties(props);
- /* get crtc properties */
- props = drmModeObjectGetProperties(fd, crtc_id, DRM_MODE_OBJECT_CRTC);
- printf("/-----CRTC_Property-----/\n");
- get_property(fd, props);
- printf("\n");
- pc.property_active = get_property_id(fd, props, "ACTIVE");
- pc.property_mode_id = get_property_id(fd, props, "MODE_ID");
- drmModeFreeObjectProperties(props);
- /* create blob to store current mode, and retun the blob id */
- drmModeCreatePropertyBlob(fd, &conn->modes[0],
- sizeof(conn->modes[0]), &pc.blob_id);
- /* start modeseting */
- req = drmModeAtomicAlloc();
- drmModeAtomicAddProperty(req, crtc_id, pc.property_active, 1);
- drmModeAtomicAddProperty(req, crtc_id, pc.property_mode_id, pc.blob_id);
- drmModeAtomicAddProperty(req, conn_id, pc.property_crtc_id, crtc_id);
- drmModeAtomicCommit(fd, req, DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
- drmModeAtomicFree(req);
- }
复制代码
可以看出,对/dev/dri/card0设备的操作是ioctl方式,只不过名字换成drmIoctl而已。能成功对Framebuffer进行缓存刷新之后,像清屏、显示文字、显示图片等等操作都可以直接照抄FrameBuffer应用层代码的,这里就不过多赘述了,看看显示文字和静态图的效果:
同理,对SPITFTLCD液晶屏的操作也是类似的,需要对/dev/spidevx.x设备进行操作:
|