add: 03_LCD/14,15,18 for stm32mp157

This commit is contained in:
weidongshan
2021-02-03 18:15:01 +08:00
parent a5fc1d05af
commit 7a4d88f8be
29 changed files with 2397 additions and 13 deletions

View File

@@ -222,8 +222,8 @@ CFBADD设置LAYER1图层1的显存地址。
![](pic/02_LCD驱动/030_LTDC_L1CFBLR.png)
CFBPFramebuffer中行像素所占据的字节数
CFBLLFramebuffer中行像素所占据的字节数+7
CFBPFramebuffer中行像素所占据的字节数
CFBLLFramebuffer中行像素所占据的字节数+7

View File

@@ -108,7 +108,8 @@ LCD驱动程序的核心就是
参考内核文件:
* `drivers\video\of_videomode.c`
* `drivers\video\fbdev\mxsfb.c`
* GIT仓库里IMX6ULL的驱动程序
* `STM32MP157\source\A7\03_LCD\12_lcd_drv_imx6ull_from_kernel_4.9.88\mxsfb.c`
#### 3.2 使用参数配置LCD控制器

View File

@@ -0,0 +1,125 @@
## 编程\_配置LCD控制器之寄存器操作\_基于STM32MP157
参考资料GIT仓库里
* 芯片资料
* `STM32MP157\开发板配套资料\datasheeet\02_Core_board(核心板)\CPU\CPU开发参考手册\DM00327659.pdf`
* `《35 LCD-TFT display controller (LTDC)》`
* STM32MP157的LCD裸机程序
* `STM32MP157\source\A7\03_LCD\05_参考的裸机源码\03_font_test`
* 内核自带的STM32MP157 LCD驱动程序
* 驱动源码:
* LCD相关`Linux-5.4\drivers\gpu\drm\panel\panel-myir070tft.c`
* LCD控制器相关`Linux-5.4\drivers\gpu\drm\stm\ltdc.c`
* GPU相关`Linux-5.4\drivers\gpu\drm\stm\drv.c`
* 设备树:
* `Linux-5.4/arch/arm/boot/dts/stm32mp157c-100ask-512d-lcd-v1.dts`
* `Linux-5.4/arch/arm/boot/dts/stm32mp151.dtsi`
* `Linux-5.4/arch/arm/boot/dts/stm32mp15-pinctrl.dtsi`
* 本节视频编写好的代码
* `STM32MP157\source\A7\03_LCD\10_lcd_drv_lcdcontroller_reg_config_use_devicetre`
* 引脚配置工具/设备树生成工具
* 打开http://download.100ask.net/
* 找到开发板:"100ASK_STM32MP157_PRO开发板"
* 下载开发板配套资料
* 下载完后,工具在如下目录里:
![image-20210122094724188](pic/02_LCD驱动/041_pins_tools.png)
### 1. 硬件相关的操作
LCD驱动程序的核心就是
* 分配fb_info
* 设置fb_info
* 注册fb_info
* 硬件相关的设置
硬件相关的设置又可以分为3部分
* 引脚设置
* 时钟设置
* LCD控制器设置
### 2. 在设备树里指定LCD参数
```shell
framebuffer-mylcd {
compatible = "100ask,lcd_drv";
pinctrl-names = "default";
pinctrl-0 = <&mylcd_pinctrl>;
backlight-gpios = <&gpio1 8 GPIO_ACTIVE_HIGH>;
clocks = <&clks IMX6UL_CLK_LCDIF_PIX>,
<&clks IMX6UL_CLK_LCDIF_APB>;
clock-names = "pix", "axi";
display = <&display0>;
display0: display {
bits-per-pixel = <24>;
bus-width = <24>;
display-timings {
native-mode = <&timing0>;
timing0: timing0_1024x768 {
clock-frequency = <50000000>;
hactive = <1024>;
vactive = <600>;
hfront-porch = <160>;
hback-porch = <140>;
hsync-len = <20>;
vback-porch = <20>;
vfront-porch = <12>;
vsync-len = <3>;
hsync-active = <0>;
vsync-active = <0>;
de-active = <1>;
pixelclk-active = <0>;
};
};
};
};
```
### 3. 编程
#### 3.1 从设备树获得参数
时序参数、引脚极性等信息都被保存在一个display_timing结构体里
![image-20210125185436508](pic/02_LCD驱动/042_display_timing.png)
参考内核文件:
* `drivers\video\of_display_timing.c`
* `drivers\video\fbdev\mxsfb.c`
#### 3.2 使用参数配置LCD控制器
根据芯片手册,一个一个设置寄存器:
* Framebuffer地址设置
* Framebuffer中数据格式设置
* LCD时序参数设置
* LCD引脚极性设置

View File

@@ -0,0 +1,229 @@
## 上机实验\_基于STM32MP157
参考资料GIT仓库里
* 芯片资料
* `STM32MP157\开发板配套资料\datasheeet\02_Core_board(核心板)\CPU\CPU开发参考手册\DM00327659.pdf`
* `《35 LCD-TFT display controller (LTDC)》`
* STM32MP157的LCD裸机程序
* `STM32MP157\source\A7\03_LCD\05_参考的裸机源码\03_font_test`
* 内核自带的STM32MP157 LCD驱动程序
* 驱动源码:
* LCD相关`Linux-5.4\drivers\gpu\drm\panel\panel-myir070tft.c`
* LCD控制器相关`Linux-5.4\drivers\gpu\drm\stm\ltdc.c`
* GPU相关`Linux-5.4\drivers\gpu\drm\stm\drv.c`
* 设备树:
* `Linux-5.4/arch/arm/boot/dts/stm32mp157c-100ask-512d-lcd-v1.dts`
* `Linux-5.4/arch/arm/boot/dts/stm32mp151.dtsi`
* `Linux-5.4/arch/arm/boot/dts/stm32mp15-pinctrl.dtsi`
* 本节视频测试通过的代码
* `STM32MP157\source\A7\03_LCD\11_lcd_drv_stm32mp157_ok`
* 搭建开发环境
* 视频https://www.100ask.net/
* 《Linux系列教程之快速入门》之《【第2篇】环境搭建、Linux基本操作、工具使用》
* 文档:` git clone https://e.coding.net/weidongshan/01_all_series_quickstart.git`
* 《嵌入式Linux应用开发完全手册\_韦东山全系列视频文档全集V2.8.pdf》
### 1. 要做的事情
* 去除内核自带的驱动程序
* 加入我们编写的驱动程序、设备树文件
* 重新编译内核、设备树
* 上机测试:使用编译出来的内核、设备树启动板子
### 2. 去除内核自带的驱动程序
* 设置工具链
```shell
source /home/book/100ask_stm32mp157_pro-sdk/ToolChain/openstlinux_eglfs-linux-gnueabi/environment-setup-cortexa7t2hf-neon-vfpv4-ostl-linux-gnueabi
export ARCH=arm
export CROSS_COMPILE=arm-ostl-linux-gnueabi-
```
* 配置内核使用STM32MP157默认配置
```shell
~/100ask_stm32mp157_pro-sdk/$ cd Linux-5.4
~/100ask_stm32mp157_pro-sdk/Linux-5.4$ make 100ask_stm32mp157_pro_defconfig
```
* 去掉自带的驱动程序:执行`make menuconfig`,如下配置内核
```shell
Device Drivers --->
Graphics support --->
< > DRM Support for STMicroelectronics SoC Series // 输入N
```
* 解决可能出现的问题
* 如果执行`make menuconfnig`出现如下问题:
![image-20210203095417662](pic/02_LCD驱动/043_make_menuconfig_ncurse.png)
* 就先执行以下命令:
```shell
sudo apt install lib32ncursesw5 lib32ncursesw5-dev
```
### 3. 加入新驱动程序、设备树
* 复制驱动程序:
* 把`11_lcd_drv_stm32mp157_ok\lcd_drv.c`放到内核源码目录`drivers/video/fbdev`
* 备份内核自带设备树文件:`arch/arm/boot/dts/stm32mp157c-100ask-512d-lcd-v1.dts`
* 把`11_lcd_drv_stm32mp157_ok\stm32mp157c-100ask-512d-lcd-v1.dts`放到内核源码目录`arch/arm/boot/dts/`
* 修改内核文件:
* 修改:`drivers/video/fbdev/Makefile`使用我们提供的lcd_drv.c如下
```shell
obj-y += lcd_drv.o
```
### 4. 重新编译内核、设备树
**以下命令在Ubuntu中执行。**
* 设置工具链
```shell
source /home/book/100ask_stm32mp157_pro-sdk/ToolChain/openstlinux_eglfs-linux-gnueabi/environment-setup-cortexa7t2hf-neon-vfpv4-ostl-linux-gnueabi
export ARCH=arm
export CROSS_COMPILE=arm-ostl-linux-gnueabi-
```
* 配置、编译
```shell
~/100ask_stm32mp157_pro-sdk/$ cd Linux-5.4
~/100ask_stm32mp157_pro-sdk/Linux-5.4$
~/100ask_stm32mp157_pro-sdk/Linux-5.4$ make uImage LOADADDR=0xC2000040
~/100ask_stm32mp157_pro-sdk/Linux-5.4$ make dtbs
```
* 得到
* 内核:`arch/arm/boot/uImage`
* 设备树文件:`arch/arm/boot/dts/stm32mp157c-100ask-512d-lcd-v1.dtb`
* 复制到NFS目录
```shell
$ cp arch/arm/boot/uImage ~/nfs_rootfs/
$ cp arch/arm/boot/dts/stm32mp157c-100ask-512d-lcd-v1.dtb ~/nfs_rootfs/
```
### 5. 上机测试
**以下命令在开发板中执行。**
#### 5.1 更换内核、设备树
* 挂载NFS
* vmware使用NAT(假设windowsIP为192.168.1.100)
```shell
[root@100ask:~]# mount -t nfs -o nolock,vers=3,port=2049,mountport=9999
192.168.1.100:/home/book/nfs_rootfs /mnt
```
* vmware使用桥接或者不使用vmware而是直接使用服务器假设Ubuntu IP为192.168.1.137
```shell
[root@100ask:~]# mount -t nfs -o nolock,vers=3 192.168.1.137:/home/book/nfs_rootfs /mnt
```
* 确定单板上内核、设备树保存在哪里
由于版本变化STM32MP157单板上烧录的系统可能有细微差别在开发板上执行`cat /proc/mounts`后,
可以得到两种结果(见下图)
* 保存内核、设备树的分区,挂载在/boot目录下无需特殊操作
* 保存内核、设备树的分区,挂载在/mnt目录下
* 在视频里、后面文档里,都是更新/boot目录下的文件所以要先执行以下命令重新挂载
* `mount /dev/mmcblk2p2 /boot`
![image-20210203132435507](pic/02_LCD驱动/047_boot_mount.png)
* 更新单板文件
```shell
[root@100ask:~]# cp /mnt/uImage /boot
[root@100ask:~]# cp /mnt/stm32mp157c-100ask-512d-lcd-v1.dtb /boot
[root@100ask:~]# sync
```
* 重启开发板观察现象
* 如果可以看到企鹅LOGO就表示正常
* 如果在终端中可以查看到存在`/dev/fb0`节点,也表示正常
#### 5.2 板子无法启动使用uboot下载内核、设备树
使用新内核、设备树启动单板时,打印`Starting kernel`后就再无输出,串口信息如下:
![image-20210203094102367](pic/02_LCD驱动/044_cannot_boot.png)
这表示内核或设备树有问题只能使用uboot来下载其他内核、设备树来调试。
重启开发板按住空格进入uboot在uboot使用nfs命令下载uImage、设备树来启动开发板。
* 以下命令适用于vmware使用桥接
```shell
=> setenv ipaddr 192.168.1.112 //设置开发板的IP地址。
=> nfs c4000000 192.168.1.137:/home/book/nfs_rootfs/stm32mp157c-100ask-512d-lcd-v1.dtb
=> nfs c4100000 192.168.1.137:/home/book/nfs_rootfs/uImage
=> setenv bootargs root=/dev/mmcblk2p3 rw
=> bootm c4100000 - 0xc4000000
```
* 以下命令使用于vmware使用NAT并且先启动tftpd64在tftpd64所设置目录下放入uImage和设备树文件
```shell
=> setenv serverip 192.168.1.100 //设置服务器的IP地址这里指的是Ubuntu主机IP
=> setenv ipaddr 192.168.1.112 //设置开发板的IP地址。
=> tftpboot 0xc4000000 stm32mp157c-100ask-512d-lcd-v1.dtb
=> tftpboot c4100000 uImage
=> setenv bootargs root=/dev/mmcblk2p3 rw
=> bootm c4100000 - 0xc4000000
```
#### 5. 问题所在
* 设备树中引脚冲突,如下修改
![image-20210203094835973](pic/02_LCD驱动/045_pins_conflict.png)
* 驱动程序函数使用方法有变化
![image-20210203095040925](pic/02_LCD驱动/046_dma_alloc_wc.png)

View File

@@ -19,16 +19,118 @@
### 1. 单Buffer的缺点
* 如果APP速度很慢可以看到它在LCD上缓慢绘制图案
* 即使APP速度很高LCD控制器不断从Framebuffer中读取数据来显示而APP不断把数据写入Framebuffer
* 假设APP想把LCD显示为整屏幕的蓝色、红色
* 很大几率出现这种情况:
* LCD控制器读取Framebuffer数据读到一半时在LCD上显示了半屏幕的蓝色
* 这是APP非常高效地把整个Framebuffer的数据都改为了红色
* LCD控制器继续读取数据于是LCD上就会显示半屏幕蓝色、半屏幕红色
* 人眼就会感觉到屏幕闪烁、撕裂
![image-20210203172823180](pic/02_LCD驱动/048_singble_buffer.png)
### 2. 使用多Buffer来改进
上述两个缺点的根源是一致的Framebuffer中的数据还没准备好整帧数据就被LCD控制器使用了。
使用双buffer甚至多buffer可以解决这个问题
### 3. 内核驱动程序分析
### 4. APP编写方法
* 假设有2个FramebufferFB0、FB1
* LCD控制器正在读取FB0
* APP写FB1
* 写好FB1后让LCD控制器切换到FB1
* APP写FB0
* 写好FB0后让LCD控制器切换到FB0
### 3. 内核驱动程序、APP互相配合使用多buffer
流程如下:
![image-20210203180534206](pic/02_LCD驱动/049_drv_app_use_double_buff.png)
* 驱动分配多个buffer
```c
fb_info->fix.smem_len = SZ_32M;
fbi->screen_base = dma_alloc_writecombine(fbi->device,
fbi->fix.smem_len,
(dma_addr_t *)&fbi->fix.smem_start,
GFP_DMA | GFP_KERNEL);
```
* 驱动保存buffer信息
```c
fb_info->fix.smem_len // 含有总buffer大小
fb_info->var // 含有单个buffer信息
```
* APP读取buffer信息
```c
ioctl(fd_fb, FBIOGET_FSCREENINFO, &fix);
ioctl(fd_fb, FBIOGET_VSCREENINFO, &var);
// 计算是否支持多buffer有多少个buffer
screen_size = var.xres * var.yres * var.bits_per_pixel / 8;
nBuffers = fix.smem_len / screen_size;
```
* APP使能多buffer
```c
var.yres_virtual = nBuffers * var.yres;
ioctl(fd_fb, FBIOPUT_VSCREENINFO, &var);
```
* APP写buffer
```c
fb_base = (unsigned char *)mmap(NULL , fix.smem_len, PROT_READ | PROT_WRITE, MAP_SHARED, fd_fb, 0);
/* get buffer */
pNextBuffer = fb_base + nNextBuffer * screen_size;
/* set buffer */
lcd_draw_screen(pNextBuffer, colors[i]);
```
* APP开始切换buffer
```c
/* switch buffer */
var.yoffset = nNextBuffer * var.yres;
ioctl(fd_fb, FBIOPAN_DISPLAY, &var);
```
* 驱动切换buffer
```c
// fbmem.c
fb_ioctl
do_fb_ioctl
fb_pan_display(info, &var);
err = info->fbops->fb_pan_display(var, info) // 调用硬件相关的函数
```
示例:
![image-20210203180357860](pic/02_LCD驱动/050_mxsfb_pan_display.png)
* APP等待切换完成(在驱动程序中已经等待切换完成了,所以这个调用并无必要)
```c
ret = 0;
ioctl(fd_fb, FBIO_WAITFORVSYNC, &ret);
```

View File

@@ -0,0 +1,179 @@
## STM32MP157内核自带的LCD驱动不支持多buffer
* 本节视频编写好的程序在GIT仓库里
* `IMX6ULL\source\03_LCD\14_use_multi_framebuffer`
* `STM32MP157\source\A7\03_LCD\14_use_multi_framebuffer`
* 参考程序应用基础课程里使用Framebuffer的精简程序
* `IMX6ULL\source\03_LCD\14_use_multi_framebuffer\reference\07_framebuffer`
* `STM32MP157\source\A7\03_LCD\14_use_multi_framebuffer\reference\07_framebuffer`
* 参考程序使用多buffer的APP在GIT仓库里
* `IMX6ULL\source\03_LCD\13_multi_framebuffer_example\testcamera`
* `STM32MP157\source\A7\03_LCD\13_multi_framebuffer_example\testcamera`
### 1. STM32MP157内核自带的LCD驱动不支持都buffer
所以无法在STM32MP157观察到多buffer的效果。
如果想学习多buffer的APP如何编写请学习IMX6ULL的视频`18_编写使用多buffer的应用程序`
### 2. 恢复自带的驱动(不想那么复杂的话,直接重烧系统)
**注意**
* 一旦使用重新编译的内核板子自带的GUI无法运行
* 原因在于内核重新编译后也需要重新编译、安装各类模块还有第3方模块。
* 编译第3方模块涉及buildroot的使用
* 这些不是LCD的内容所以建议还是直接通过USB恢复系统
#### 2.1 在Ubuntu上编译内核、设备树
* 设置工具链,执行如下命令:
```shell
source /home/book/100ask_stm32mp157_pro-sdk/ToolChain/openstlinux_eglfs-linux-gnueabi/environment-setup-cortexa7t2hf-neon-vfpv4-ostl-linux-gnueabi
export ARCH=arm
export CROSS_COMPILE=arm-ostl-linux-gnueabi-
```
* 去掉自己编写的驱动程序
* 修改内核文件:`drivers/video/fbdev/Makefile`如下注释掉lcd_drv.o那行
```shell
#obj-y += lcd_drv.o
```
* 重新配置内核选择自带驱动程序,执行`make menuconfig`如下配置2项
```shell
Device Drivers --->
Graphics support --->
<*> DRM Support for STMicroelectronics SoC Series // 输入Y选择
<*> STMicroelectronics specific extensions for Synopsys MIPI DSI // 输入Y选择
```
* 恢复设备树
* 把GIT仓库中`STM32MP157\source\A7\03_LCD\11_lcd_drv_stm32mp157_ok\origin\stm32mp157c-100ask-512d-lcd-v1.dts`
* 复制到内核目录:`arch/arm/boot/dts`目录下
* 编译内核、设备树
```shell
~/100ask_stm32mp157_pro-sdk/$ cd Linux-5.4
~/100ask_stm32mp157_pro-sdk/Linux-5.4$ make uImage LOADADDR=0xC2000040
~/100ask_stm32mp157_pro-sdk/Linux-5.4$ make dtbs
```
* 得到
* 内核:`arch/arm/boot/uImage`
* 设备树文件:`arch/arm/boot/dts/stm32mp157c-100ask-512d-lcd-v1.dtb`
* 复制到NFS目录
```shell
$ cp arch/arm/boot/uImage ~/nfs_rootfs/
$ cp arch/arm/boot/dts/stm32mp157c-100ask-512d-lcd-v1.dtb ~/nfs_rootfs/
```
#### 2.2 在开发板上通过NFS更新内核、设备树
* 挂载NFS
* vmware使用NAT(假设windowsIP为192.168.1.100)
```shell
[root@100ask:~]# mount -t nfs -o nolock,vers=3,port=2049,mountport=9999
192.168.1.100:/home/book/nfs_rootfs /mnt
```
* vmware使用桥接或者不使用vmware而是直接使用服务器假设Ubuntu IP为192.168.1.137
```shell
[root@100ask:~]# mount -t nfs -o nolock,vers=3 192.168.1.137:/home/book/nfs_rootfs /mnt
```
* 确定单板上内核、设备树保存在哪里
由于版本变化STM32MP157单板上烧录的系统可能有细微差别在开发板上执行`cat /proc/mounts`后,
可以得到两种结果(见下图)
* 保存内核、设备树的分区,挂载在/boot目录下无需特殊操作
* 保存内核、设备树的分区,挂载在/mnt目录下
* 在视频里、后面文档里,都是更新/boot目录下的文件所以要先执行以下命令重新挂载
* `mount /dev/mmcblk2p2 /boot`
![image-20210203132435507](pic/02_LCD驱动/047_boot_mount.png)
* 更新单板文件
```shell
[root@100ask:~]# cp /mnt/uImage /boot
[root@100ask:~]# cp /mnt/stm32mp157c-100ask-512d-lcd-v1.dtb /boot
```
### 3. 编译、运行APP
* 设置工具链,执行如下命令:
```shell
export ARCH=arm
export CROSS_COMPILE=arm-buildroot-linux-gnueabihf-
export PATH=$PATH:/home/book/100ask_stm32mp157_pro-sdk/ToolChain/arm-buildroot-linux-gnueabihf_sdk-buildroot/bin
```
* 上传代码、编译
* 代码位置GIT仓库`STM32MP157\source\A7\03_LCD\14_use_multi_framebuffer`
* 上传到Ubuntu
* 在`14_use_multi_framebuffer`目录下执行make可以得到`multi_framebuffer_test`
* 通过NFS放到开发板/bin目录
```shell
mount -t nfs -o nolock,vers=3 192.168.1.137:/home/book/nfs_rootfs /mnt
cp /mnt/multi_framebuffer_test /bin
```
* 在开发板执行
```shell
systemctl stop myir //关闭自带的GUI程序
multi_framebuffer_test double 或 multi_framebuffer_test single
```
* 由于STM32MP157自带的LCD驱动不支持多buffer上述命令效果一样
### 4. LCD自动黑屏
为了省电LCD在10分钟左右会自动黑屏。
我们可以禁止LCD自动黑屏执行以下命令即可
```shell
#close lcd sleep
echo -e "\033[9;0]" > /dev/tty1
echo -e "\033[?25l" > /dev/tty1
```

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 348 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 260 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB