RK3568笔记八: Display子系统

modetest 是由 libdrm 提供的测试程序,可以查询显示设备的特性,进行基本的显示测试,以及设置显示的模式。

我们可以借助该工具来学习 Linux DRM 应用编程,另外为了深入分析 Rockchip DRM driver,有必要先了解一下这个工具的使用方法和内部实现。

一、准本工作

1、开发板:ATK-DLRK3568 开发板

2、环境:ubuntu20.0 正点原子网盘提供的版本

二、modetest编译

本人没自己编译过,编译过程只供参考,正点的板子自带了

编写一个libdrm的测试程序较为复杂,这里我们使用libdrm官方的测试工具来进行测试,我们可以在这里下载源码并进行交叉编译出测试工具,以供在开发板上使用: libdrm .

新版的libdrm使用meson+ninja的构建方式,而不是老版的autotools,没有基础的同学构建新版libdrm会比较痛苦。 建议直接使用我们给大家编译好的测试程序,测试程序位于配套例程 linux_driver/framework_drm/modetest

如果要自己编译libdrm,可以参考下面命令:

git clone https://gitlab.freedesktop.org/mesa/drm

sudo apt -y install python3-pip cmake git ninja-build

python3 -m pip install meson  /*安装之后,重启板卡*/

meson . build && ninja -C build

编译之后在build/tests/modetest/下会有modetest程序, 对libdrm测试程序感兴趣的同学,可以下载libdrm源码解压,在其目录/drm/tests/modetest/下,查看modetest.c文件,此为测试程序源码。

三、modetest 使用示例

modetest在bin目录下,板子上电后打开终端进入bin目录
 

cd /bin

1、 查看帮助信息

modetest -h

RK3568笔记八: Display子系统_第1张图片2、查看组件的信息

modetest -M rockchip

RK3568笔记八: Display子系统_第2张图片

参数说明:

  • -M:用于指定访问 rockchip DRM driver

关键内容:

  • Encoders / Connectors / CRTCs / Planes 的 id,modetest 通过 id 来用于引用这些组件。
  • Connectors 的 modes/props:
    • prop: 任何你想设置的参数,都可以做成 property,是 DRM 驱动中最灵活、最方便的 Mode setting 机制;
    • modes: 显示模式,mode 里包含分辨率/刷新率等显示相关的信息;
  • CRTCs 的 props;
  • Planes 的 formats/props;

3、查看各组件的 id

modetest -M rockchip | cut -f1 | grep -E ^[0-9A-Z]\|id

RK3568笔记八: Display子系统_第3张图片

正点原子的RK3568提供了一路的MIPI DSI 接口,所以测试MIPI

modetest -M rockchip -s 163@115:720x1280

RK3568笔记八: Display子系统_第4张图片

四、最简单DRM(drm-single)

直接上代码,目录根据yolov5的那个程序修改的,替换mian.cc文件后需要添加drm库和头文件。

// Copyright (c) 2021 by Rockchip Electronics Co., Ltd. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/*-------------------------------------------
                Includes
-------------------------------------------*/
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#include "drm_func.h"
#include "rga_func.h"
#include "rknn_api.h"
#include "yolo.h"

#include "RgaUtils.h"
#include "im2d.h"
#include "opencv2/core/core.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/imgproc.hpp"
#include 
#include "rga.h"
#include 
#include 


#define RED         0XFF0000
#define GREEN       0X00FF00
#define BLUE        0X0000FF
#define BLACK       0X000000
#define WHITE       0XFFFFFF
#define BLACK_BLUE  0X123456

struct drm_device {
	uint32_t width;			//显示器的宽的像素点数量
	uint32_t height;		//显示器的高的像素点数量
	uint32_t pitch;			//每行占据的字节数
	uint32_t handle;		//drm_mode_create_dumb的返回句柄
	uint32_t size;			//显示器占据的总字节数
	uint32_t *vaddr;		//mmap的首地址
	uint32_t fb_id;			//创建的framebuffer的id号
	struct drm_mode_create_dumb create ;	//创建的dumb
    struct drm_mode_map_dumb map;			//内存映射结构体
};

drmModeConnector *conn;	    //connetor相关的结构体
drmModeRes *res;		    //资源
uint32_t conn_id;           //connetor的id号
uint32_t crtc_id;           //crtc的id号
int fd;					    //文件描述符

#define RED 0XFF0000
#define GREEN 0X00FF00
#define BLUE 0X0000FF

uint32_t color_table[6] = {RED,GREEN,BLUE,BLACK,WHITE,BLACK_BLUE};

uint32_t plane_id[3];	//图层id数组

struct drm_device buf;

static int drm_create_fb(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);
	
	//每行占用字节数,共占用字节数,MAP_DUMB的句柄
	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 = (uint32_t*)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_fb(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()
{
	//打开drm设备,设备会随设备树的更改而改变,多个设备时,请留一下每个屏幕设备对应的drm设备
	fd = open("/dev/dri/card0", O_RDWR | O_CLOEXEC);
    if(fd < 0){
        printf("wrong\n");
        return 0;
    }

	//获取drm的信息
	res = drmModeGetResources(fd);
	crtc_id = res->crtcs[1];
	conn_id = res->connectors[1];
	//打印CRTCS,以及conneter的id
	printf("crtc = %d , conneter = %d\n",crtc_id,conn_id);

	conn = drmModeGetConnector(fd, conn_id);
	buf.width = conn->modes[0].hdisplay;
	buf.height = conn->modes[0].vdisplay;

	//打印屏幕分辨率
	printf("width = %d , height = %d\n",buf.width,buf.height);

	//创建framebuffer层
	drm_create_fb(&buf);

	//设置CRTCS
	drmModeSetCrtc(fd, crtc_id, buf.fb_id,
			0, 0, &conn_id, 1, &conn->modes[0]);

	return 0;
}

void drm_exit()
{
	drm_destroy_fb(&buf);
	drmModeFreeConnector(conn);
	drmModeFreeResources(res);
	close(fd);
}

int main(int argc, char **argv)
{
	int i,j;
	drm_init();
	sleep(2);
	printf("display colour\n");
	//显示三色
	for(j=0;j<3;j++){
		for(i =j*buf.width*buf.height/3;i< (j+1)*buf.width*buf.height/3;i++)
			buf.vaddr[i] = color_table[j];
	}

	getchar();
	printf("getchar\n");
	
	
	drm_exit();

	exit(0);
}

运行结果

程序需要注意一点。

  //获取drm的信息
    res = drmModeGetResources(fd);
    crtc_id = res->crtcs[1];
    conn_id = res->connectors[1];

RK3568笔记八: Display子系统_第5张图片

接下来,实现采集视频显示。

你可能感兴趣的:(RK3568学习笔记,笔记)