0%

墨水屏入门功能开发(一)——驱动编写

开发工具: Keil 5
开发芯片: STM32F1x
墨水屏型号:GooDisplay 2.7寸四阶灰度墨水屏(GDEW027W3)
文档编写工具: Markdown

墨水屏入门功能开发,理解局刷、全刷和墨水屏LUT.

墨水屏简介

墨水屏特性

原理
墨水屏下包含这很多黑白粒子,黑白例子都是带不同电荷的色素颗粒,初始状态下色素颗粒会在一个单位中漂浮(floating);当施加过一定方向的电场后,相应的色素颗粒会被推到顶端,使得一个单位呈现相应的颜色,大量的显示单位通过这种显色方式同时工作组成了不同的图案和文字。

以GooDisplay的产品为例,根据它的数据手册将墨水屏原理总结如下:

  • 物理原理:黑色粒子带负电荷,白色粒子带正电荷,通过基板的电压正负控制粒子运动(面板显示的颜色);
  • 双稳态特性: 由于电子墨水具有双稳态效应(磁滞效应),黑白粒子不会回复原状或者变成随机的混沌状态;
  • 低功耗: 屏幕不变化,屏幕部分耗电量为0,主要耗电来自于电路板待机消耗以及电源内阻消耗;
  • 刷新缺陷: 同样由于磁滞效应,墨水屏在刷新一次如果不施加反向电压(显示为黑白切换)就有可能导致色素粒子运动混乱,在屏幕中出现“残影”

墨水屏光源解决方案

传统的LCD液晶屏有背光,受外界光源影响较小,只有日光环境下需要调节背光亮度来抵御环境光对屏幕显示的遮盖效果。墨水屏因为其物理特性比较依赖环境光,在实际应用中通常使用导光板+内置LED光源进行补光。
这在现实应用中已有先例可循,如生活中最常见的 [安全出口] 的指示牌就是利用了导光板实现低功耗光源的扩散效果。

安全出口

​ 底部为荧光LED,表面使用导光板

墨水屏功耗实测

仍以GooDisplay的GDEW027W3型号的墨水屏为例,手册中给出的功耗如下表所示:

image-20210118143657105

实际应用时需要将墨水屏的驱动板功耗也考虑进去。使用万用表测量墨水屏转接板DESPI-C02上GNDPREVGH之间的电流,如下图所示:

待机功耗
image-20200831214637793

静态画面功耗
image-20200831214513063

刷新峰值功耗
image-20200831214427132

可以看到墨水屏在实际应用时功耗也相当低,能够满足低功耗的大部分应用场景。

墨水屏的应用问题

在墨水屏实际应用进行全局刷新时,遇到的最大问题为全局刷新的速度慢,且刷新时面板会出现夸张的黑白影像互换 **(即闪屏现象)**。 如果忽略这一问题进行开发,容易使客户形成产品有问题的印象。

针对这一问题的解决需要从墨水屏的物理原理入手。通过上述墨水屏的简介中可以知道,墨水屏能够在断电后保持原图像是因为墨水屏本身的磁滞效应。
磁滞效应
上图中,横轴为电压大小,纵轴为灰度(设正轴为白负轴为黑)。电压加大的过程和减小的过程,给予同样的电压,电子墨水黑白程度是不同的,这就是双稳态效应(磁滞效应)。利用这样的效应,我们就可以给一个正电压,电压从0升至B(在图中体现为从原点对应的A点到B点的过程,走下面上升的路线),吸引负电荷,显示正电荷白色给读者,然后断电(电压从B减少到0,走上方那条回来的路线),白色得以保持。墨水屏省电就在于如果不需要显示有所变化,屏幕部分消耗电量为0。

利用上图解释我们在全局刷新时遇到的问题:假设电压从0加大然后又降为0,墨水屏对应的灰度从A点经B最终达到了C点。如果下一次变化,减少电压,使得灰度沿着上图中的路径继续行走则墨水屏工作正常,墨水屏从黑–>白–>黑,这就是全局刷新时“闪屏”现象出现的原因,本质上为短时间内黑白两色粒子在反向电压下相互交替,全局刷新的实现手段即施加一个电压之后再施加一个反向电压,在形式上体现为“全部清场”;如果下一次变化不施加反向电压,即这个时刻得到白色之后在下一时刻仍需要这个像素点表现为白色,那么墨水屏在C点的灰度就不再是这个图形,电路驱动的电压对应的灰度将会不准确,白色粒子会堆积在上层,下一次施加反向电压(需要黑色)时,白色粒子在顶层仍有残留,墨水屏的黑白颜色程度就会不相同,出现了残影。

为了避免残影的出现,就必须在刷新时给墨水屏施加最大或者最小电压,使墨水屏的黑白粒子完成磁滞效应图中一个完整的运动周期(A–>B–>C–>D–>A)。

刷新速率慢则是各个厂家不同产品之间的差异,微观上体现为黑白粒子在正反向电压下运动速率。


SPI寄存器工作

SDA以D7、D6、…D0的顺序移位到8位移位寄存器中。移位寄存器中的数据字节在同一时钟内写入图形显示数据RAM(RAM)或命令寄存器。在串行模式下,仅允许写入操作。
SDA写入移位寄存器,先Command(发送寄存器指令)再parameter(write Data),实现大多数的命令+数据写入。

在刷新和初始设置中有一部分指令比较重要,对以下指令作着重介绍。

面板设置指令(R00H):

面板设置是执行所有操作之前必须设置的一项,通过面板设置我们可以改变墨水屏的分辨率、灰度初始设置、显示模式切换、调整扫描方向(包括左右扫描方向和上下扫描方向)等,理解这一指令对墨水屏的开发有着关键的意义。

W/R C/D D7 D6 D5 D4 D3 D2 D1 D0
0 0 0 0 0 0 0 0 0 0
0 1 RES1 RES0 LUT BWR UD SHL SH RST

RES[1:0]: 显示分辨率设置 (source×gate)
00b: 320×300 (default) , 01b: 300×200
10b: 296×160 , 11b: 296×128

LUT: LUT选择设定.
0: Using LUT from OTP. (default)
1: Using LUT from register.

BWR: 颜色选择设定.
0: 使用黑/白/红像素点. Run both LU1 and LU2. (default)
1: 使用黑/白像素点. Run LU1 only.

UD: Gate 扫描方向
0: Scan down First line to last: Gn→…→ G1 (default)
1: Scan up. (default) First line to last: G1→…→ Gn

SHL: Source偏移方向
0: shift left. First data to last data: Sn→…→ S1
1: shift right First data to last data: S1→… →Sn (default)

SHD: 升压开关
0: Booster OFF,寄存器数据保持不变,SEG / BG / VCOM保持浮动。
1: Booster ON(默认)SHD_N变低时,DC-DC将关闭。 寄存器和SRAM数据将一直保持到VDD OFF。 SD输出和VCOM将基于先前的条件并保持浮动。

RST: 软复位
0: No effect.
1: 升压器关闭,寄存器数据设置为其默认值,并且SEG / BG / VCOM:0V。 (默认)当RST_N变为低电平时,驱动器将复位。 所有寄存器将重置为默认值。 驱动程序所有功能将被禁用。 SD输出和VCOM将基于先前的条件并保持浮动。

应用举例:

EPD_W21_WriteCMD(0x90);

1
2
3
4
5
6
7
0x901001 0000(RES1|RES0|LUT_EN|BWR|UD|SHL|SHD_N|RST_N)
RSE[1:0]设为10即设置分辨率为296x160,
LUT_EN为0表示Using LUT from OTP(默认设置)
BWR为1表示仅使用黑白像素点
UD为0设置扫描横方向从左到右,SHL为0设置扫描纵方向从上往下
SHD_N设置为0即设置升压开关状态为OFF
RST_N为0表示所有设置重置为默认值,输出将默认为之前的设定

显示刷新命令(R12H)

W/R C/D D7 D6 D5 D4 D3 D2 D1 D0
0 0 0 0 0 1 0 0 1 0

-该命令定义为:当用户发送该命令时,驱动程序将根据SRAM数据和LUT刷新显示(DATA/VCOM)。显示刷新命令后,BUSY_N信号将变为“0”。

部分数据传输至寄存器1(R14H)

Inst W/R C/D D7 D6 D5 D4 D3 D2 D1 D0
PDT w 0 0 0 0 1 0 1 0 0
1st w 1 x8
2nd w 1 x7 x6 x5 x4 x3 0 0 0
3rd w Y8
4th w 1 Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0
5th w 1 w8
6th w 1 w7 w6 w5 w4 w3 0 0 0
7th w L8
8th w 1 L7 L6 L5 L4 L3 L2 L1 L0

命令定义如下:寄存器IS表示用户开始传输数据,然后写入SRAM。
当数据传输完成时,用户必须发送命令11H。
然后芯片将开始向面板发送数据/VCOM。
在B/W模式下,此命令将“旧”数据写入SRAM。
在B/W/Red模式下,此命令将“B/W”数据写入SRAM。

局部刷新位置和区域见数据手册


墨水屏主要功能实现

局部刷新

在分析完墨水屏的物理特性之后了解了全局刷新的缺陷,这种缺陷由墨水屏的先天物理特性决定无法更改。但墨水屏厂家为了应对这一情况,给墨水屏添加了局部刷新的功能,局部刷新模式下能够减少磁滞效应的闪屏和刷新缓慢的影响,但局部刷新多次后需要执行一次全局刷新将残影抹除。

局刷程序的流程为:

面板设置–>色度设置(LUT)–>扫描方向设置–>旧数据写入–>新数据写入–>刷新并将BUSY_N信号置0

其中,新旧数据写入在不同的场景下可以通过模式进行区分

1
2
3
4
5
6
旧数据写入:
模式0:写入刷新区域全白数据,使用场景为第一张图片(无旧图片替代)
0模式:写入前一张图像点阵
新数据写入:
模式2:写入刷新区域全白数据,使用场景为没有新图像以空白刷新
2模式:写入新图像的点阵

完整局刷程序如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
//局部刷新程序
void EPD_partial_display(u16 x,u16 y,const unsigned char *old_data,const unsigned char *new_data,unsigned int w,unsigned int l,unsigned char mode)
{
unsigned int i,count;
EPD_W21_WriteCMD(0x82); //vcom_DC setting
EPD_W21_WriteDATA (0x08); //VCOM_DC VALUE=-0.5v
EPD_W21_WriteCMD(0X50); //vcom和数据间隔设置(CDI)
EPD_W21_WriteDATA(0x47); //0x47=0100 0111:01-LUTBW(0→1),00-B/W两色模式,
//0111-vcom和数据间隔设置为10(默认)
lut1(); //设置Look-up Table
EPD_W21_WriteCMD(0x91); //This command makes the display enter partial mode
EPD_W21_WriteCMD(0x90); //resolution setting
EPD_W21_WriteCMD(0x14); //old data 发送到寄存器1(x和w应该是8的整除)
EPD_W21_WriteDATA(0); //x-start
EPD_W21_WriteDATA(x); //x-end
EPD_W21_WriteDATA(0); //y-start
EPD_W21_WriteDATA(y); //y-end
EPD_W21_WriteDATA(0); //w-start
EPD_W21_WriteDATA(w); //w-end
EPD_W21_WriteDATA(0); //l-start
EPD_W21_WriteDATA(l); //l-end

count=w*l/8; //计算Byte个数
if(mode==0)
{
for(i=0;i<count;i++)
{
EPD_W21_WriteDATA(0x00); //全白
}
}
else
{
for(i=0;i<count;i++)
{
EPD_W21_WriteDATA(~old_data[i]); //写入旧数据
}
}

EPD_W21_WriteCMD(0x15); //write new data(发送到寄存器2)
EPD_W21_WriteDATA(0); //x-start
EPD_W21_WriteDATA(x); //x-end
EPD_W21_WriteDATA(0); //y-start
EPD_W21_WriteDATA(y); //y-end
EPD_W21_WriteDATA(0); //w-start
EPD_W21_WriteDATA(w); //w-end
EPD_W21_WriteDATA(0); //l-start
EPD_W21_WriteDATA(l); //l-end

if(mode!=2) //new datas
{
for(i=0;i<count;i++)
{
EPD_W21_WriteDATA(~new_data[i]);
//old_data[i]=new_data[i];
}
}
else //white
{
for(i=0;i<count;i++)
{
EPD_W21_WriteDATA(0x00);
}
}

EPD_W21_WriteCMD(0x16); //write display position
EPD_W21_WriteDATA(0); //x-start
EPD_W21_WriteDATA(x); //x-end
EPD_W21_WriteDATA(0); //y-start
EPD_W21_WriteDATA(y); //y-end
EPD_W21_WriteDATA(0); //w-start
EPD_W21_WriteDATA(w); //w-end
EPD_W21_WriteDATA(0); //l-start
EPD_W21_WriteDATA(l); //l-end
lcd_chkstatus();

EPD_W21_WriteCMD(0x12); //DISPLAY REFRESH
//发出此命令后,驱动程序将根据SRAM数据和LUT刷新显示(数据/ VCOM)。
//显示刷新命令后,BUSY_N信号将变为“ 0”。
//该命令仅在BUSY_N =“ 1”时有效。
driver_delay_xms(1); //!!!The delay here is necessary, 200uS at least!!!
lcd_chkstatus(); //Check BUSY_N
//当BUSY_N为低电平时,芯片的操作不中断,并且不向模块发出任何命令。

}

灰度调节

随着对墨水屏了解的深入,发现手册中介绍了墨水屏的另一个功能——灰度调节

灰度功能简介

这个功能由LUT(Look-Up-Table)实现,针对LUT搜集到的资料如下:

定义:LUT指显示查找表(Look-Up-Table),本质上就是一个RAM。可以应用到一张像素灰度值的映射表,它将实际采样到的像素灰度值经过一定的变换如阈值、反转、二值化、对比度调整、线性变换等,变成了另外一个与之对应的灰度值,这样可以起到突出图像的有用信息,增强图像的光对比度的作用。

参考链接

LUT(Look-Up-Table)-百度百科

TW8836字体OSD~第一节LUT-CSDN

LUT的3種不同用途解析

LUT函数的实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
void lut(void)//改变画面的曝光与色彩,增强图像的光对比度的作用      
{
unsigned int count;
EPD_W21_WriteCMD(0x20); //使用该指令为VCOM建立一个显示查找表(Look-Up-Table)
for(count=0;count<44;count++)
{EPD_W21_WriteDATA(lut_vcomDC[count]);}

EPD_W21_WriteCMD(0x21); //使用该指令建立一个白色-白色的显示查找表
for(count=0;count<42;count++)
{EPD_W21_WriteDATA(lut_ww[count]);}

EPD_W21_WriteCMD(0x22); //使用该指令建立一个黑色-白色的显示查找表
for(count=0;count<42;count++)
{EPD_W21_WriteDATA(lut_bw[count]);}

EPD_W21_WriteCMD(0x23); //使用该指令建立一个白色-黑色的显示查找表
for(count=0;count<42;count++)
{EPD_W21_WriteDATA(lut_wb[count]);}

EPD_W21_WriteCMD(0x24); //使用该指令建立一个黑色-黑色的显示查找表
for(count=0;count<42;count++)
{EPD_W21_WriteDATA(lut_bb[count]);}
}

手册中并没有告诉我lut_ww,lut_bw,lut_wb,lut_bb这些数组的作用,也并不清楚IC(驱动芯片)是如何工作的,因此我翻了国内外一些关于墨水屏开发的视频,E-paper hacking: fastest possible refresh rate-YouTube中详细讲解了各个数组和波形的用途。

查询GooDisplay墨水屏手册我了解到该型号墨水屏的驱动芯片(IC)为IL91874。在搜集了国外微雪的资料再结合视频中的知识之后,发现IL91874的波形与微雪的IC的波形在数据格式上是基本一致的,主要的区别在于GooDisplay中设置时钟频率和门电路的Byte放在前两位,而微雪则是放在最后两位 (这一点在做不同厂家墨水屏开发程序之间的迁移时需要格外注意)

微雪墨水屏数据手册:
img

GooDisplay的数据手册:
![LUT for Vcom](/upload_image/LUT for Vcom.jpg)

分析上表:

  • 1st Parameter:

    • 这个byte可以设置四个波形,第一个波形使用D7-D6指定,第二个波形使用D5-D4指定,第三个波形D3-D2,第四个波形D1-D0.

    • 其中,Level selection的定义在数据手册中定义如下:

      00: -VCM_DC

      01: VSH-VCM_DC,为VCOMH,给VCOM正电

      10: VSL-VCM_DC,为VCOML,给VCOM负电

      11: Floating.

    • 00和11在电压正常情况下,黑白粒子的位置会保持不变,灰度不变;

    • 如果VCOM使用01b(正电),结合前边的内容理解,屏幕会更黑;

    • 如果VCOM使用10b(负电),屏幕会更白。

  • 2nd Parameter: Frame number[7:0],指定帧数[0~255]

  • 3rd Parameter: Frame number[7:0],指定帧数[0~255]

  • 4th Parameter: Frame number[7:0],指定帧数[0~255]

  • 5th Parameter: Frame number[7:0],指定帧数[0~255]

  • 6th Parameter: Repeat number[7:0],bytes2到bytes6做出的波形,要重复的次数[0~255]

如此,1-6定义一个子波形,7-13定义第二个子波形,等等等等以此类推。一共42/6=7个子波形,他们共同拼接成一整个波形。

1
2
3
4
5
6
7
8
const unsigned char lut_ww[] ={	
0x40 ,0x08 ,0x00 ,0x00 ,0x00 ,0x02,
0x90 ,0x28 ,0x28 ,0x00 ,0x00 ,0x01,
0x40 ,0x14 ,0x00 ,0x00 ,0x00 ,0x01,
0xA0 ,0x12 ,0x12 ,0x00 ,0x00 ,0x01,
0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00,
0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00,
0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00, };

以上述截图中的lut_ww(white-white)数组为例,一行6个Parameter共7行,第一个波形执行了两次(0x02),第二个波形执行了一次(0x01)……实现的功能是通过控制VCOM的上电时间控制墨水屏例子显示的颜色,如在清屏之后的屏幕上(0.5单位的黑色+0.5单位的白色)的情况下,给墨水屏上1.5秒的负电,此时墨水屏中粒子的黑色浓度变成了(0.5单位的黑色+1.5单位的白色=1单位的白色),墨水屏的颜色就从黑白平衡变成了纯白,lut_ww的”white-white”的功能就实现了。

分析lut函数的意义
  1. 根据以上3个场景,可以推理出其他色阶的展示。灰阶,就是波形的产物;

  2. 只要波形设置到位,可以显示任意灰阶;

  3. 在波形叠加的情况下,也可以从任意灰阶,直接跳到另一灰阶;

  4. 墨水屏上的灰度,可以对这个Vcom施加不同时长的正负电,以实现灰度;

  5. (猜想)对于宋体字在墨水屏中显示单薄/不好看的问题,可以通过调整灰度来使”黑的更黑白的更白”,而不再需要更换字库中的字体。

    7.23更新:暂时放弃,改善会议中提出的清晰度问题,通过改字库的方法更方便。这条可备用后续功能 [调整面板对比度]

BUSY状态检查

使用SPI指令时需要用到自锁lcd_chkstatus程序(检查Busy状态),引入这一信号量来保证指令之间不互相干涉。

检查Busy状态的操作流程为:

  1. 开机指令后,驱动器将根据开机顺序开机。接通电源命令后,BUSY_N信号将从高降至低;
  2. 当完成断电序列时,BUSY_N信号将从低上升到高;
  3. BUSY_N=“0”:驱动程序繁忙,数据/VCOM正在转换。BUSY_N=“1”:非忙,主机端可以向驱动程序发送命令/数据。

代码实现:

1
2
3
4
5
6
7
8
9
10
11
12
void lcd_chkstatus(void)    //Check BUSY_N 
{
unsigned char busy;
do
{
EPD_W21_WriteCMD(0x71); //读取IC状态
busy = isEPD_W21_BUSY;
busy =!(busy & 0x01); // xxxx xxxx&0000 0001
}
while(busy); //若BUSN_N为低电平,则循环查询
driver_delay_xms(200);
}

墨水屏开发小结

读懂墨水屏的英文开发文档之后再结合相关知识,我发现墨水屏的低功耗、局部快速刷新功能具有相当的实用价值。如果在实际应用中能够接受偶尔全局刷新的闪屏(约5-10次局部刷新之后)和墨水屏的成本较高等缺陷,那么墨水屏就可以作为工业显示仪表中传统LED屏幕的有力替代方案。

第一阶段的开发过程有很多不足,需要在下一阶段继续调试和研究:

  1. 项目开发的最终目标为在更低功耗的MSP430上运行,目前开发环境为STM32F1X芯片,需要重新比对两者区别,后续完成程序的移植;
  2. 同一厂家的墨水屏硬件也不相同,同时字库的设置会因为字体要求不同而反复调整,为了方便维护,准备引入宏定义增加程序可移植性;
  3. 墨水屏的汉字索引目前的方法为预先建立字库调用,效率较低,下一阶段准备使用2312汉字字库匹配的方式在程序中实现“所现即所求”。
两种颜色的功德箱(逃