嵌入式中 gui 显示单缓冲、双缓冲、三缓冲的原理

gui 中的显示功能

嵌入式中,gui 中图像的显示最终通过调用底层 lcd 驱动提供的接口来将 【framebuffer】 刷新到屏幕上。framebuffer 的大小与屏幕大小、屏幕分辨率、图片显示方式有关。对于 gui 而言,所有调用 lcd 驱动刷新 framebuffer 到屏幕上显示之前的绘制操作都是通过对 framebuffer 的操作完成的。这里提及的操作主要是 memcpy、memset ,它们的速度将直接限制操作 framebuffer 的速度,因此一般都会编写多个版本的 memset、memcpy 来优化设置、拷贝的速度。

上面的叙述表明 gui 中完全可以实现一套底层 lcd 驱动的接口,用以适配不同的 lcd 控制器。这样就能够屏蔽 lcd 控制器的差别,便于在不同的平台上进行移植。

lcd 控制器的基本工作过程

lcd 控制器的正常工作需要配置一些显示参数。如前肩后肩的延时等等。这里提及的前后肩延时其实只是为了兼容老的 lcd 控制器。这些控制器必须在刷新 framebuffer 到屏幕上的前后进行延时,这个延时实际是为了消抖,以得到更好的显示效果。

当配置完成 lcd 控制器后,你还要设置 lcd 刷新时使用的 framebuffer 地址,与 framebuffer 大小。这一般在 gui 调用 lcd 提供的绘制接口中进行设定,设定后 lcd 控制器便会持续的从该地址按照指定的大小刷新数据到屏幕上。

对于需要持续刷新的 lcd 控制器而言,其对设定的 framebuffer 的读取是一直在进行的,除非关闭 lcd 控制器。这就使得软件的代码逻辑中必须对缓冲区交换的时机进行判断。这个判断可以通过帧同步信号来完成。一般来说,常见的 lcd 控制器会在刷完一帧之后发出一个帧同步信号,这个帧同步信号就相当于通知用户时机已到,可以设置下一帧的地址了。

单缓冲

顾名思义,单缓冲就是仅仅使用一个 framebuffer 来完成绘制。此 framebuffer 的地址在设定给 lcd 控制器中的对应寄存器之前由 gui 填充。

由于我们只是用了一个 framebuffer,这就可能导致 gui 在操作这个 framebuffer 的同时,lcd 控制器也在同时操作相同的内存。这样如果 framebuffer 的内容有所变化,那么我们可能会看到一个重叠的显示效果。这常见于用单缓冲去实现动态切换的内容及复杂的页面的场景中。这也就说明单缓冲并不适合用来设计复杂的页面,这是它的一大缺点。不过相较多缓冲机制,它的实现相对简单,使用的内存也相对较少,这是单缓冲的优势。

双缓冲

诚如其名,双缓冲使用了两个 framebuffer。常见的实现中这两个 framebuffer 一个称为 online fb、一个称为 offline fb。这两个 framebuffer 也可称为一个前置缓冲与一个后置缓冲。前置缓冲是 lcd 控制器绘制正使用的缓冲区,后置缓冲是 gui 能够继续填充的缓冲区。

在实际的实现中,我们需要对这两个缓冲区进行交换。缓冲区的交换并不会再次进行 memcpy,而是通过交换指针来实现。也就是说,lcd 当前正在使用的 online fb 指针将会与 offline fb 指针进行切换,这样会极大的提高效率。

该在什么时候进行缓冲区交换呢?

这个时机的确定要以 lcd 控制器提供的功能为准。常见的方式是使用帧同步信号来完成,其它的方式请参考 lcd 控制器的用户手册。使用帧同步信号来实现的情况中,获取到一个帧同步信号就表明 lcd 已经刷完了上一帧,可以交换指针来刷新的一帧。

**在这里我们需要注意交换指针一定要在新的一帧刷新开始之前完成。**一般在 lcd 控制器中设置的前后肩时间为交换指针操作提供了缓冲,不太容易出现问题。对于那些有两个 framebuffer 地址寄存器的 lcd 控制器而言,交换可以通过写入地址到当前未被用于显示的地址寄存器中,由 lcd 控制器来完成具体的指针切换工作。

交换指针的安全保证让双缓冲的方式避免了单缓冲方式在动态内容显示中的问题,增加的一个缓冲区也在一定程度上提高了 gui 绘制的效率,这种方式的使用十分广泛。

三缓冲

三缓冲的工作原理与双缓冲类似,只是缓冲区的数目增加了一个。这个增加的缓冲区让缓冲区交换的实现更为复杂,却也提供了一个提高 gui 绘制效率的机会。在这种实现中我们将三个缓冲区分为一个前置缓冲区与两个后置缓冲区。当 cpu 填充 framebuffer 的速度非常快的时候,双缓冲方式可能会出现两个缓冲区都被占用的情况。这种情况下,由于缓冲区已经被用完,gui 无法绘制新的数据到framebuffer 中,这意味着它必须等待一次缓冲区交换的完成才能继续填充新的缓冲区。

在相同的情况下,三缓冲增加的一个缓冲区能够在有限范围内避免不必要的等待。当两个缓冲区都被占用,gui 仍旧能够获取到一个后置缓冲区,不用等待就能继续在此缓冲区上进行绘制,这样就能提高绘制的效率。

不过可以想象,在这种方式下缓冲区的交换比双缓冲更难实现。如果我们再增加缓冲区数目,不仅内存占用会成倍增加,且缓冲区交换功能实现的难度会不断上升,而绘制效率的提升空间却可能微乎其微,因此我们很难看到诸如四缓冲、五缓冲之类的实现。

framebuffer 的内存属性对显示的影响

gui 在实际绘制中可能存在许多问题。这里我想重点讲讲 framebuffer 内存属性配置对显示的一些影响,以 armv7-m 架构为例。

armv7-m 的内存模型

armv7-m 参考手册的第三章讲解了 arm 架构的内存模型。其中提到了内存的类型和属性及内存的序列模型。

内存类型主要有三种——Normal、Device、Strongly-ordered。framebuffer 的内存分配主要与 Normal 类型的内存有关。

Normal 内存可以分为非共享与共享两个类别。这种分类是以内存是否能被多个处理器访问划分的。非共享 Normal 内存只能被单个处理器访问。共享 Normal 内存能够被多个处理器或其它系统主控访问。

对于非共享 Normal 内存,有四个具体的属性可以配置。

  1. Write-through cacheable
  2. Write-back,write-allocate
  3. Write-back,no write-allocate
  4. Non-cacheable
潜在的问题

这里的可能存在的问题主要与 cache 有关。对于可 cache 的内存属性,第一种属性会在数据写入到 cache 之后立刻将改动更新到内存中,第二、三种属性不会立刻将 cache 缓存的内存数据改动立刻写回到内存中,最后一种属性标志内存区域不可 cache。

当你使用第二、三中属性配置 framebuffer 所属的内存区域时,显示时可能会出现部分数据残缺,且很有规律。在这种情况中,由于内存属性配置为写回型, cache 中缓存的一些界面数据没有立刻更新到内存中,导致显示出现部分残缺。将内存属性修改为第一种写通型就能显示正常的界面效果。第四种不可 cache 的配置也可以解决这个问题,只是它的效率不及第一种,因此不推荐使用。

按照我的理解。写回型的配置其实是将数据变动更新到内存的时间延后了,一般会在当前的 cache 行被置换出去之前进行。这样的方式在大多数时间内都有助于提高性能,却并不适用于所有的情况,这里就是一个具体的例子。

总结

本文描述了嵌入式中 lcd 控制器的基本工作原理及在 gui 显示中经常使用的不同缓冲技术。通过对这几种不同缓冲技术的描述,我们对 gui 调用 lcd 控制器完成绘制的过程有了更好的了解。在文章最后我讲了一个与 framebuffer 内存属性配置有关的问题,这是一个相对基础的问题。实际开发中 gui 显示不正常可能有多种原因。其中既可能有内存属性配置不正确的问题,也可能有其它的问题,需要根据实际情况进行判定!

  • 4
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
嵌入式系统,设置接收缓冲(Receive Buffer)的大小是一个关键步骤,因为这直接影响到系统的通信效率和数据处理能力。接收缓冲用于暂存从网络、串口或其他输入源接收到的数据,直到应用程序有足够的时间或资源来处理这些数据。 以下是在嵌入式环境设置接收缓冲大小的一般步骤: 1. **了解需求**: 首先,你需要明确你的应用对数据传输速度的要求、以及预期的最大数据包大小。这将决定缓冲的最小和理想尺寸。 2. **硬件限制**: 考虑硬件资源,如内存大小。缓冲过大可能会消耗过多内存,导致其他功能受限。相反,如果太小,可能会丢失数据或者频繁地产生数据包重传。 3. **操作系统支持**: 查看使用的操作系统文档,了解其提供的API来设置接收缓冲。比如,在Linux,你可以使用`sockopt`函数在套接字上设置`SO_RCVBUF`选项。 4. **设置方法**: - 如果是使用标准库或API,通常会有一个参数允许你指定缓冲大小,例如`recv()`或`socket recvmsg()`函数。 - 使用`ioctl()`系统调用或配置文件(如Linux的`/proc/sys/net/core/rmem_default`)来动态调整内核缓冲。 5. **测试与调整**: 设置后,进行实际通信测试,观察系统的性能和稳定性。根据测试结果,可能需要调整缓冲大小以达到最佳效果。 6. **考虑超时和重试机制**: 如果缓冲满但接收操作未完成,可能需要设置适当的超时时间或者重试策略。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值