编写一个rt-smart上的应用程序体验一下!

2020-11-25 11:51:37 浏览数 (1)

编写一个rt-smart上的应用程序体验一下!

  • 1.本文目的
  • 2.设计思路
    • 2.1 驱动设计
    • 2.2 树莓派4 上的framebuffer与touch
    • 2.3 上层应用程序的设计
  • 3.开发流程
    • 3.1 环境搭建
    • 3.2 编写lvgl_smart应用程序
    • 3.3 编写驱动程序
  • 4.效果体验
  • 5.rt-smart使用心得

1.本文目的

在漫长的等待过程中,rt-smart开源版本发布出来了。拿到rt-smart第一手资料的,就在思考如何用rt-smart做些好玩的东西,可以充分发挥出用户态与内核态的特性。正好目前正在研究树莓派4的显示屏和触摸屏,所以就想着把lvgl最新版本移植上去跑跑,看看上手难度以及最后的运行体验效果究竟怎么样。心动不如行动,立即评估自己的时间。花了两三个小时就把思路理清楚了,然后花了三四个小时去用代码实现功能,最后效果确实还很好,不管是流畅性还是代码的设计都非常简单明了,下面来分享一下其中的过程。

2.设计思路

2.1 驱动设计

由于应用态与内核态的分离和单独编译,使得应用程序的开发更加关注上层业务逻辑,不太关注系统层面的东西。但是目前rt-smart的驱动框架编程上还是要有一些理解才能访问framebuffer以及触摸坐标点,目前由于lcd与touch驱动都在内核层。访问时可以通过rt-thread设备驱动框架进行。如果对rt-thread编程比较熟悉的,都会使用rt_device_findrt_device_openrt_device_control去进行驱动接口的访问,而在rt-smart上,这一套编程模型还是依然如此。也就是userapps访问外设依然通过rt_device_xx来进行设备的访问。

需要注意的frambuffer是内核态的地址,此时用户态不能直接访问的,如果要访问该怎么办?此时应用了一个共享内存页面的特性,将一块内核态的内存与用户态的内存进行共享,此时访问就可以正常进行了。

代码语言:javascript复制
https://github.com/RT-Thread/rt-thread/blob/rt-smart/bsp/qemu-vexpress-a9/drivers/drv_clcd.c

具体可以看到下面的实现:

代码语言:javascript复制
info->smem_len    = lcd->width * lcd->height * 2;
info->smem_start  = (uint32_t)lwp_map_user_phy(lwp_self(), RT_NULL, lcd->fb,info->smem_len, 1);

而对于触摸设备,向用户态传输不是地址,而是坐标,这样就不会出现这样的问题。应用程序只用关注坐标x,坐标y,以及是否被按下的状态。有了lcd与触摸屏这两个驱动,移植lvgl就没有什么问题了。

2.2 树莓派4 上的framebuffer与touch

目前接的是dsi的屏幕,也就是右边的图示所对应的屏。

该驱动和HDMI是一样的,也就是树莓派GPU的程序已经完成实现,接上HDMI或接上DSI,两者都是一样的显示效果。而不同的是DSI是带有触摸接口的。访问的方式采用mailbox进行CPU与GPU的通信。

对于LCD,首先写程序让CPU告诉GPU需要的分辨率和bpp,然后通过mailbox获取framebuffer的地址,向该地址写图形数据,GPU会自动刷新到LCD上。

对于触摸,只需从GPU获取一个地址,该地址记录这触摸的buffer,支持多点触摸的坐标信息。

这就是异构设计共享内存的特点,传递消息机制都是如此的有特色。

2.3 上层应用程序的设计

本来想按照rt-thread的rtt-lvgl的软件包来进行设计,我看了一下,对工程结构的改动较大。不适合作为我的设计初衷。而且随着lvgl版本的迭代升级,维护成本太大。我的设计是,不改变lvgl的整个仓库的目录结构,中间加个rt-smart与lvgl的兼容层。每次rt-smart更新或者lvgl更新,只要是关键移植api不变,那对于整个工程都没有影响。

这种设计才是我想要达到的目的。所以我设计了一个兼容层目录结构。

3.开发流程

3.1 环境搭建

做rt-smart的开发首先需要集成开发环境。

代码语言:javascript复制
https://realthread.cowtransfer.com/s/5d7f490c09ef42

下载完成后解压可以看到如下的目录:

目录名

说明

kernel

RT-Thread内核 (打开RT_USING_SMART将开启smart特性)

tools

编译rt-smart时用到的python脚本

userapps

用户态开发环境和示例

userapps/apps

用户态应用示例

userapps/linker_scripts

不同CPU体系结构下的默认链接脚本

userapps/sdk

用户态环境中需要用到的头文件,库等

集成开发环境中只有针对Linux环境下的交叉编译工具链,若要进行windows环境的开发工作,可以下载

代码语言:javascript复制
http://117.143.63.254:9012/www/rt-smart/install_arm-linux-musleabi_for_i686-w64-mingw32.zip

下载后解压放到rt-smarttoolsgnu_gcc目录。

检查并确认gcc路径为:rt-smarttoolsgnu_gccinstall_arm-linux-musleabi_for_i686-w64-mingw32bin

使用rt-thread的env工具,在``rt-smart的目录中输入.smart-env.bat`则环境搭建完成。

3.2 编写lvgl_smart应用程序

只需要在userapps/apps目录下新建一个名为lvgl_smart的文件夹。

代码语言:javascript复制
lvgl_smart
----[lv_rtt_port]
----[lvgl]
----lv_conf.h
----SConscript

上述目录结构中lv_rtt_port是移植的关键部分对接程序,主要由自己编写。

lvgl完全从https://github.com/lvgl/lvgl上获取最新代码,完全不用修改。

lv_conf.h文件为lvgl目录中的lvgl_conf_template.h修改而来,只需修改四个个宏定义即可。

代码语言:javascript复制
#if 1 /*Set it to "1" to enable content*/  //需要打开

#define LV_HOR_RES_MAX          (800)  //根据自己的lcd进行配置
#define LV_VER_RES_MAX          (480)  //根据自己的lcd进行配置

/* Color depth:
 * - 1:  1 byte per pixel
 * - 8:  RGB332
 * - 16: RGB565
 * - 32: ARGB8888
 */
#define LV_COLOR_DEPTH     32    //根据自己的lcd进行配置

核心还是在lv_rtt_port中,而具体需要关注的文件就是lv_port_rtt.c文件。

代码语言:javascript复制
#ifndef FBDEV_NAME
#define FBDEV_NAME "hdmi"
#endif

#define TOUCH_NAME "touch"

通过rt_device_xxx来操作设备。

代码语言:javascript复制
    lv_lcd = rt_device_find(FBDEV_NAME);
    if (lv_lcd == RT_NULL)
    {
        rt_kprintf("can't find the lcd:%sn", FBDEV_NAME);
        return;
    }
    rt_kprintf("nThe framebuffer device was opened successfully.n");
    rt_device_open(lv_lcd, RT_DEVICE_OFLAG_RDWR);
    // Get fixed screen information
    rt_device_control(lv_lcd, FBIOGET_FSCREENINFO, &lcd_info);
    rt_device_control(lv_lcd, FBIOGET_VSCREENINFO, &lcd_var_info);

主要获取framebuffer则可以进行操作了。

获取触摸点也是类似操作。然后对接lvgl相关的显示和触摸接口即可。

另外需要关注的文件是rtt_lvgl_test.c文件,该文件是显示demo的接口。也就是该应用程序的入口地址。关于lvgl的examples我主要参考移植https://github.com/lvgl/lv_examples

整个app的工程项目代码在下面找到:

代码语言:javascript复制
https://gitee.com/bigmagic/lvgl_smart

3.3 编写驱动程序

由于目前公开版本的代码还在稳定期,我未向其pr,目前工程代码还在整理之中。如果想体验,我已经将一份放置于百度网盘中。

代码语言:javascript复制
链接:https://pan.baidu.com/s/1w2x0iKQpBhGsNjZEWM4VHw 
提取码:si2r

本次改动主要在时钟tick、hdmi驱动、增加触摸功能,以及增加mbox的一个接口。rt-smart驱动的设计目前和之前的rt-thread通用版本改动不大。另外需要注意的是内核地址的映射问题。

4.效果体验

在env控制台输入

代码语言:javascript复制
 .smart-env.bat

然后进入userapps目录,输入scons开始编译应用程序。生成的文件位于rootbin*.elf。

然后进入kernelbspraspberry-piraspi4-32输入scons开始编译kernel。

放入boot文件

首先需要准备一张空白的32GB或者32GB以下的sd卡。

下载树莓派4b的boot文件,解压后提取文件夹里面的内容放在sd卡根目录。

代码语言:javascript复制
链接:https://pan.baidu.com/s/1gvJInzKzPB8PNeoYrIvYCw 
提取码:bnd7

该boot里面的kernel7.imgbin*.elf是rt-smart旧版本,自己编译生成后可进行替换。

连接串口线

按照树莓派的串口序号进行连接

连接时,可以将树莓派的GND与串口模块的GND相连,树莓派上的RX、TX与串口模块交叉相连。

注意串口波特率115200,停止位1,无奇偶校验位。

下面看一下具体的运行效果:

5.rt-smart使用心得

在进行rtos编程时,若进行带有mmu的中高端芯片编程,使用rt-smart是比较理想的,实现了应用程序与内核程序的分离,使得上层的代码的容错性更大一些,比如对于GUI编程之类偏向业务逻辑设计,真是非常的简单。但是对于做驱动和做中间层的人来说,难度可能稍微有点大,而对于未曾接触过rt-thread编程的人来说,确实需要一点时间熟悉rt-thread的编程思想。

该移植过程中,整个设计还是比较清晰的,就是在实现的细节上确实也遇到一些问题,比如帧率很低,移植后很卡,触摸屏坐标对不上等等问题,这些都是驱动设计上的问题,最后都得到了比较好的解决。我更加倾向于在rt-smart上做一些业务层面的东西,最好设备驱动尽量的简单一些,这样做出来的东西架构清晰,出错的机率很低,就算应用程序异常了也不会对内核的执行造成影响。

0 人点赞