在 imx93 平臺調試 rgb lcd 屏幕
一、環境介紹
linux 版本:6.6.52
soc:imx9331
使用 rgb lcd 屏,565 的數據格式
使用的內核文件為 Image,dtb 文件為:imx93-11x11-evk.dtb
二、硬件檢查
-
背光供電要符合規格
-
rgb 的線序需要對上:The Data[23:0] from i.MX93 is R-G-B:高位是 R,低位是 B
三、調試技巧
nxp 提供了云開發板,只需要注冊賬號就能申請在線調試使用
https://aiotcloud.nxp.com.cn/product/overview
四、驅動修改
使用的源碼路徑如下,分支為 lf-6.6.y
git clone https://github.com/nxp-imx/linux-imx.git -b lf-6.6.y
使用的 config 文件為:imx_v8_defconfig
參考配置文件為:arch/arm64/boot/dts/freescale/imx93-9x9-qsb-ontat-wvga-panel.dts
直接修改 arch/arm64/boot/dts/freescale/imx93-11x11-evk.dts 文件,添加 rgb lcd 的配置,修改如下:
// 在根節點中添加 panel 配置,暫時不用 pwd 和供電控制,所以將這些給注釋掉了
panel: panel {
compatible = "liangtao,xxx-lcd";
//backlight = <&backlight>;
//power-supply = <®_rpi_3v3>;
//enable-gpios = <&pcal6524 22 GPIO_ACTIVE_HIGH>;
port {
panel_in: endpoint {
remote-endpoint = <&display_out>;
};
};
};
¶llel_disp_fmt {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_lcdif>;
fsl,interface-pix-fmt = "rgb565";
status = "okay";
ports {
port@1 {
reg = <1>;
display_out: endpoint {
remote-endpoint = <&panel_in>;
};
};
};
};
// pinctrl 配置如下
pinctrl_lcdif: lcdifgrp {
fsl,pins = <
MX93_PAD_GPIO_IO00__MEDIAMIX_DISP_CLK 0x31e // lcd 顯示屏調試
MX93_PAD_GPIO_IO01__MEDIAMIX_DISP_DE 0x31e
MX93_PAD_GPIO_IO02__MEDIAMIX_DISP_VSYNC 0x31e
MX93_PAD_GPIO_IO03__MEDIAMIX_DISP_HSYNC 0x31e
MX93_PAD_GPIO_IO04__MEDIAMIX_DISP_DATA00 0x31e // B0
MX93_PAD_GPIO_IO05__MEDIAMIX_DISP_DATA01 0x31e // B1
MX93_PAD_GPIO_IO06__MEDIAMIX_DISP_DATA02 0x31e // B2
MX93_PAD_GPIO_IO07__MEDIAMIX_DISP_DATA03 0x31e // B3
MX93_PAD_GPIO_IO08__MEDIAMIX_DISP_DATA04 0x31e // B4
MX93_PAD_GPIO_IO09__MEDIAMIX_DISP_DATA05 0x31e // G0
MX93_PAD_GPIO_IO10__MEDIAMIX_DISP_DATA06 0x31e // G1
MX93_PAD_GPIO_IO11__MEDIAMIX_DISP_DATA07 0x31e // G2
MX93_PAD_GPIO_IO12__MEDIAMIX_DISP_DATA08 0x31e // G3
MX93_PAD_GPIO_IO13__MEDIAMIX_DISP_DATA09 0x31e // G4
MX93_PAD_GPIO_IO14__MEDIAMIX_DISP_DATA10 0x31e // G5
MX93_PAD_GPIO_IO15__MEDIAMIX_DISP_DATA11 0x31e // R0
MX93_PAD_GPIO_IO16__MEDIAMIX_DISP_DATA12 0x31e // R1
MX93_PAD_GPIO_IO17__MEDIAMIX_DISP_DATA13 0x31e // R2
MX93_PAD_GPIO_IO18__MEDIAMIX_DISP_DATA14 0x31e // R3
MX93_PAD_GPIO_IO19__MEDIAMIX_DISP_DATA15 0x31e // R4
>;
};
在驅動文件 drivers/gpu/drm/panel/panel-simple.c 中添加自己屏的配置
在 static const struct of_device_id platform_of_match[] 結構體數組中添加自己的屏幕
static const struct of_device_id platform_of_match[] = {
{ .compatible = "liangtao,xxx-lcd",
.data = &liangtao_xxx_lcd,
}, {
.compatible = "ampire,am-1280800n3tzqw-t00h",
.data = &ire_am_1280800n3tzqw_t00h,
},
添加屏幕配置如下:
static const struct drm_display_mode liangtao_xxx_lcd_mode = {
.clock = 28000, // 時鐘,單位為 khz
.hdisplay = 480, // 水平分辨率
.hsync_start = 480 + 20, // 水平同步信號開始(換行信號)
.hsync_end = 480 + 20 + 10, // 水平同步信號結束
.htotal = 480 + 20 + 10 + 40, // 整體的水平同步信號
.vdisplay = 800, // 垂直分辨率
.vsync_start = 800 + 20, // 垂直分辨率同步信號開始(換頁信號)
.vsync_end = 800 + 20 + 8, // 垂直分辨率同步信號結束
.vtotal = 800 + 20 + 8 + 20, // 整體的垂直同步信號
.flags = DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC, // 正極性同步水平和垂直信號(高電平有效)
};
static const struct panel_desc liangtao_xxx_lcd = {
.modes = &liangtao_xxx_lcd_mode,
.num_modes = 1,
.bpc = 6, // 565 和 666 都配置為 6
.size = {
.width = 57, // 面板物理寬度
.height = 94, // 面板物理高度
},
.bus_format = MEDIA_BUS_FMT_RGB565_1X16, // 565 的格式
.bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_SAMPLE_NEGEDGE, // DE 信號高電平有效,數據低電平采樣
.connector_type = DRM_MODE_CONNECTOR_DPI, // DPI 顯示接口
};
修改完畢后,編譯燒錄;發現沒有生成 /dev/dri/card0 節點
使用 dmesg | grep drm 查看顯示驅動報錯信息;
更具報錯信息,在 dts 中,將不想關的 dsi 節點注釋掉(主要是 mipi 的顯示)后,出現了 /dev/dri/card0 和 /dev/fb0 節點
五、編寫 fb 測試應用
通過以下 shell 命令可知,雖然配置的是 565 的屏;但對于 fb0 還是需要填寫 888 的數據;
/tmp # cat /sys/class/graphics/fb0/virtual_size
480,800
/tmp # cat /sys/class/graphics/fb0/bits_per_pixel
32
編寫應用如下:
并使用 -static 參數靜態編譯,這樣可以上傳 nxp 云開發板實驗;
實驗前需要使用 fuser 來查看 /dev/dri/card0、/dev/fb0 是否有應用占用,如果有;需要 kill 掉;
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/fb.h>
#include <sys/mman.h>
#include <string.h>
#define FB_DEV "/dev/fb0"
#define SCREEN_WIDTH 480
#define SCREEN_HEIGHT 800
static void print_compile_date(void)
{
const char *date = __DATE__;
char month_str[4];
int day, year;
int month = 0;
// 從 __DATE__ 提取信息
sscanf(date, "%s %d %d", month_str, &day, &year);
// 將月份轉換為數字
if (strcmp(month_str, "Jan") == 0)
month = 1;
else if (strcmp(month_str, "Feb") == 0)
month = 2;
else if (strcmp(month_str, "Mar") == 0)
month = 3;
else if (strcmp(month_str, "Apr") == 0)
month = 4;
else if (strcmp(month_str, "May") == 0)
month = 5;
else if (strcmp(month_str, "Jun") == 0)
month = 6;
else if (strcmp(month_str, "Jul") == 0)
month = 7;
else if (strcmp(month_str, "Aug") == 0)
month = 8;
else if (strcmp(month_str, "Sep") == 0)
month = 9;
else if (strcmp(month_str, "Oct") == 0)
month = 10;
else if (strcmp(month_str, "Nov") == 0)
month = 11;
else if (strcmp(month_str, "Dec") == 0)
month = 12;
// 輸出格式化日期
printf("Compile Date: %04d-%02d-%02d\n", year, month, day);
printf("Compile Time: %s\n\n", __TIME__);
}
int main()
{
print_compile_date();
int fb_fd = open(FB_DEV, O_RDWR);
if (fb_fd == -1) {
perror("Error opening framebuffer device");
return 1;
}
struct fb_var_screeninfo vinfo;
if (ioctl(fb_fd, FBIOGET_VSCREENINFO, &vinfo)) {
perror("Error reading variable information");
close(fb_fd);
return 1;
}
if (vinfo.bits_per_pixel != 32 || vinfo.xres != SCREEN_WIDTH || vinfo.yres != SCREEN_HEIGHT) {
fprintf(stderr, "Framebuffer format or resolution is not supported\n");
close(fb_fd);
return 1;
}
size_t screensize = SCREEN_WIDTH * SCREEN_HEIGHT * 4 * 3; // 32 bits per pixel
u_int32_t *fb_ptr = mmap(NULL, screensize, PROT_READ | PROT_WRITE, MAP_SHARED, fb_fd, 0);
if (fb_ptr == MAP_FAILED) {
perror("Error mapping framebuffer device to memory");
close(fb_fd);
return 1;
}
// Fill the entire framebuffer with red color (RGBA8888)
u_int32_t pixel = 0xFFFF0000; // R: 8 bits (bits 16-23)
int x, y, idex;
for (y = 0; y < SCREEN_HEIGHT; y++) {
for (x = 0; x < SCREEN_WIDTH; x++) {
fb_ptr[y * SCREEN_WIDTH + x] = pixel;
}
}
// 白色
pixel = 0xFFFFFFFF;
idex = 3;
for (y = 0; y < SCREEN_HEIGHT / 4 * idex; y++) {
for (x = 0; x < SCREEN_WIDTH / 4 * idex; x++) {
fb_ptr[y * SCREEN_WIDTH + x] = pixel;
}
}
// 綠色
pixel = 0xFF00FF00;
idex = 2;
for (y = 0; y < SCREEN_HEIGHT / 4 * idex; y++) {
for (x = 0; x < SCREEN_WIDTH / 4 * idex; x++) {
fb_ptr[y * SCREEN_WIDTH + x] = pixel;
}
}
// 藍色
pixel = 0xFF0000FF;
idex = 1;
for (y = 0; y < SCREEN_HEIGHT / 4 * idex; y++) {
for (x = 0; x < SCREEN_WIDTH / 4 * idex; x++) {
fb_ptr[y * SCREEN_WIDTH + x] = pixel;
}
}
vinfo.yoffset = 0;
if (ioctl(fb_fd, FBIOPAN_DISPLAY, &vinfo) == -1) {
printf("liangtao vinfo.yoffset error \n");
}
// Clean up
munmap(fb_ptr, screensize);
close(fb_fd);
return 0;
}
測試后,發現屏幕有光標閃爍,通過以下命令來關閉光標
echo 0 > /sys/class/graphics/fbcon/cursor_blink

浙公網安備 33010602011771號