uboot移植(十七)实现 LCD 显示

arch/arm/lib/board.c 中的 board_init_f 函数
uboot移植(十七)实现 LCD 显示

如果定义了 CONFIG_LCD,就会调用了 lcd_setmem 函数,这个函数用来分配帧缓存地址, 其定义在common/lcd.c
uboot移植(十七)实现 LCD 显示

        这个函数调用了 panel_info 变量,这个变量在每个具体的 lcd 驱动中定义,定义了具体 LCD 的相关信息,比如这里通过 debug 打印了它的成员变量: vl_col(列)、 vl_row(行)和 vl_bpixBPP)。 然后调用lcd_get_size 函数来获得帧缓存大小。 lcd_get_size common/lcd.c 中定义为一个弱符号,我们可以在自己的 LCD 驱动中重定义这个函数,也可以使用默认的。
uboot移植(十七)实现 LCD 显示

arch/arm/lib/board.c 中的 board_init_r 函数
uboot移植(十七)实现 LCD 显示

这里调用了 stdio_init,初始化标准输入、标准输出、标准错误输出等 IO。 它在 common/stdio.c 中定义common/stdio.c 中的 stdio_init 函数
uboot移植(十七)实现 LCD 显示
如果定义了 CONFIG_LCD,就调用 drv_lcd_init,其定义在 common/lcd.c
uboot移植(十七)实现 LCD 显示

这个函数又调用了当前文件中的 lcd_init,初始化 LCD
uboot移植(十七)实现 LCD 显示

        这个函数调用了 lcd_ctrl_init,这个函数在具体的 LCD 驱动中实现,我们需要自己实现这个函数,它进行具体的硬件初始化,下面调用 lcd_clear 清屏, lcd_enable 使能 LCD 控制器,这个函数也需要我们自己实现。 分析到这里,我们就可以开始移植 LCD 驱动了。
        首先在
drivers/video 目录下创建文件 s5pv210_fb.c,同时修改 drivers/video/Makefile,把 s5pv210_fb.c
编译进 u-boot.bin
uboot移植(十七)实现 LCD 显示

然后在 smdkv210.h 中定义相关宏
uboot移植(十七)实现 LCD 显示

按照惯例,我们需要在 s5pv210_fb.c 中操作 LCD 控制器的寄存器,因此需要在arch/arm/include/asm/arch-s5pc1xx/下创建 lcd_reg.h,定义 LCD 控制器的寄存器结构体
uboot移植(十七)实现 LCD 显示

同样需要修改 arch/arm/include/asm/arch-s5pc1xx/cpu.h
uboot移植(十七)实现 LCD 显示

定义 LCD 控制器的基地址
uboot移植(十七)实现 LCD 显示

定义获得 LCD 控制器基地址的宏
然后仿照裸机编程中
LCD 一节的代码,在 s5pv210_fb.c 中实现 lcd_ctrl_init 函数和 lcd_enable 函数。
还要定义一个用来描述
LCD 相关信息的结构体
uboot移植(十七)实现 LCD 显示

这个结构体中使用了一个宏 LCD_COLOR24,表示使用 24BPP,在 include/lcd.h 中只定义了下面几个表示颜色位深的宏
uboot移植(十七)实现 LCD 显示

我们的 LCD 使用的是 24BPP,因此需要在其后面添加一个 LCD_COLOR24
uboot移植(十七)实现 LCD 显示

另外,在下面定义了默认的 LCD_BPP LCD_COLOR8
uboot移植(十七)实现 LCD 显示

我们使用的是 24BPP,因此需要在 smdkv210.h 中定义 LCD_BPP 24BPP
uboot移植(十七)实现 LCD 显示

下面开始编译,出错
uboot移植(十七)实现 LCD 显示

找到 common/lcd.c 106
uboot移植(十七)实现 LCD 显示

        如果 LCD_BPP == LCD_COLOR8 或者 LCD_BPP == LCD_COLOR16 ,就定义 COLOR_MASK,否则就输出
错误信息
Unsupported LCD BPP,我们的 BPP 24,因此需要修改这段代码
uboot移植(十七)实现 LCD 显示

我们还需要修改 lcd_drawchars 函数,也是与 BPP 相关的,否则屏幕没输出
uboot移植(十七)实现 LCD 显示

我们使用 24BPP,一个像素在内存中占 32 位,有一个字节被浪费掉了
uboot移植(十七)实现 LCD 显示

再次编译,成功将文字输出到 LCD 上了
uboot移植(十七)实现 LCD 显示

        stdio 为串口, stdou stderr 已经定向到 lcd 了,我们可以在串口终端输入东西,但是我们只能在 LCD
上看到我们输入了什么。
uboot移植(十七)实现 LCD 显示

我们可以设置环境变量 stdout=serial,将标准输出重新定向到串口,我们在串口终端输入
set stdout serial
注意:我们的输入没法在串口终端显示出来,但可以在 LCD 上看到我们的输入,然后按回车执行后,
就将标准输出切换到串口终端了。
u-boot 中,将标准输出(stdou)定向到 LCD 是没什么意义的, 我希望的是在 u-boot 中显示开机
画面,这样避免了在
u-boot 启动到内核启动期间屏幕一直黑屏。
common/lcd.c 中的 lcd_clear 函数中调用了当前文件中的 lcd_logo
uboot移植(十七)实现 LCD 显示

splash screen 即启动画面的意思。
如果定义了
CONFIG_SPLASH_SCREEN,就会执行下面这段代码。首先获得环境变量 splashimage 的值保存到 s 中,然后调用 simple_strtoul 将它转换为 16 进制的整数保存到 addr 中。
环境变量
splashimage 保存了要显示的图片的地址,然后调用 splash_screen_prepare 做一些准备工作,比如:我们的图片实际保存在 SD 卡或者 FLASH 中, splash_screen_prepare 这个函数就可以从 SD 卡或者 FLASH 中将图片读取到环境变量 splashimage 指定的地址,接着调用 bmp_display 函数显示图片,给它传了一个参数 addraddr 保存了要显示的图片在内存中的地址。 因此,我们需要准备一张 BMP 格式的图片。
首先在
smdkv210.h 中定义宏 CONFIG_SPLASH_SCREEN
uboot移植(十七)实现 LCD 显示

        我们还需要修改分区信息,增加一个分区用来存储 BMP 图片,我制作了一张 800x480 BMP 格式
的图片,大约
1M 多点。我们就给它分配 2M 的空间。
uboot移植(十七)实现 LCD 显示

我们可以在CONFIG_EXTRA_ENV_SETTINGS 中定义一下额外的环境变量,将默认的删除掉,然后定义splashimage 0x23000000,我们将 BMP 图片从 FLASH 中加载到这个地址。
uboot移植(十七)实现 LCD 显示
另外,我们还需要实现 splash_screen_prepare 函数,用来从 FLASH 中拷贝 BMP 图片到环境变量splashimage 指定的地址。 我们在 s5pv210_fb.c 中定义 splash_screen_prepare
uboot移植(十七)实现 LCD 显示

这里我们使用了 run_command_list 来执行命令,这样比较方便。
编译出错

uboot移植(十七)实现 LCD 显示

没有定义 bmp_display,通过 SourceInght 跟踪代码发现 bmp_display common/cmd_bmp.c 中定义,
我们看下
common 下的 Makefile
uboot移植(十七)实现 LCD 显示

发现需要定义 CONFIG_CMD_BMP 这个宏,我们在 smdkv210.h 中来定义它
uboot移植(十七)实现 LCD 显示

再次编译,成功生成 u-boot-a.bin,如果还是出错,需要执行 make distclean,重新配置、编译。
前面移植了
u-boot LCD 驱动,把输出定向到了 LCD,我们通过设置环境变量 stdout 重新将标准输出定向到串口(前面讲过),然后烧写 u-boot-a.bin NAND FLASH
uboot移植(十七)实现 LCD 显示

然后重启
我们发现,添加启动画面后,
u-boot 已经不再把标准输出定向到 LCD 了,看 common/console.c 中的console_init_r 就明白了
uboot移植(十七)实现 LCD 显示

如果定义了环境变量 splashimage,就把标准输出定向到了 serial
由于现在还没有烧写图片到
NAND FLASH,所以 LCD 没有显示,下面烧写图片到 NAND log 分区
首先需要加载默认的分区,然后查看一下分区,看是否有
log 分区
uboot移植(十七)实现 LCD 显示

执行 saveenv 将新的分区信息保存到 NAND
uboot移植(十七)实现 LCD 显示

将制作好的 bmp 图片写入 NAND
uboot移植(十七)实现 LCD 显示

然后重启, LCD 没有显示图片,串口输出一条错误信息
uboot移植(十七)实现 LCD 显示

提示需要 32 位的图片,我之前制作了 2 bmp 图片,一张 24 位,一张 32 位,现在我烧写 32 位的图片。
首先我们添加几个菜单,方便以后操作

uboot移植(十七)实现 LCD 显示
我们添加了
3 个菜单, 菜单 0 通常用来执行 bootcmd 指定的命令,用来启动内核,默认执行菜单 0,由于现在我们还没移植内核,所以用 echo 命令打印空,什么也不做。 另外添加了更新 u-boot log的菜单。
uboot移植(十七)实现 LCD 显示

现在我们可以使用上下键选择菜单 download log 来下载图片了,将 32 位图片下载到 NAND 后重启
uboot移植(十七)实现 LCD 显示

没有提示错误了,但 LCD 还是没有显示,跟踪代码发现,在 bmp_display 中调用的lcd_display_bitmap 函数是根据 CONFIG_BMP_xx 来决定如何显示图片的,我们没有定义这个宏,导致 lcd_display_bitmap 没有显示任何东西。我们需要定义的是 CONFIG_BMP_32BPP,在 smdkv210.h 中定义
uboot移植(十七)实现 LCD 显示

重新编译,把u-boot-a.bin烧写到NAND,重启开发板,选择update u-boot(u-boot-a.bin)菜单更新u-boot
uboot移植(十七)实现 LCD 显示

更新完成后重启
uboot移植(十七)实现 LCD 显示

我们需要进行如下操作再次加载默认分区表
uboot移植(十七)实现 LCD 显示

烧写 32 位图片到 NAND log 分区
uboot移植(十七)实现 LCD 显示

重启开发板,已经显示图片了
uboot移植(十七)实现 LCD 显示

下面教大家如何使用 Photoshop 制作 32 位的 BMP 图片
打开
Photoshop,文件->新建

uboot移植(十七)实现 LCD 显示

输入宽度和高度,背景色透明,确定
选择 文件
->置入,找到你要制作的图片后,单击置入
uboot移植(十七)实现 LCD 显示

uboot移植(十七)实现 LCD 显示

然后拖动图片到背景框的大小
uboot移植(十七)实现 LCD 显示

然后双击图片
uboot移植(十七)实现 LCD 显示

然后选择 文件->存储为 ,选择格式为 BMP ,然后单击保存
uboot移植(十七)实现 LCD 显示

uboot移植(十七)实现 LCD 显示

选择深度为 32 位,确定,制作完成。