最近在玩电子墨水屏,记录一下电子墨水屏的驱动过程
硬件
- 4.2寸的电子墨水屏,驱动ic是SSD1619
- 驱动板淘宝买的,也可以自己画板集成到自己的主控板上也行,原理图可参考:https://oshwhub.com/ludas/mo-shui-ping-qu-dong
- ESP32-S3开发板
接线
#define EPD_SCK 36
#define EPD_MOSI 35
#define EPD_CS 10
#define EPD_RST 11
#define EPD_DC 12
#define EPD_BUSY 13
软件
在Github上找到一个开源的Arduino驱动库:https://github.com/HalfSweetStudio/EPaperDrive
踩坑
LittleFS字体的文件系统
驱动程序最开始我是参考的上面那个开源项目里的examples,用的硬件SPI的那个例程,改为我的接线方式后,烧录进去后发现文字乱码,图标可以正常显示出来,所以猜到应该是字符编码问题,仔细看代码这几行:
EPD.SetHardSPI(&SPI);
LittleFS.begin();
EPD.SetFS(&LittleFS); //设置存放字体的文件系统,传入的为该文件系统的操作指针,可自行修改
EPD.EPD_Set_Model(HINKE0266A15A0); //设置屏幕类型,具体型号可以参考文档
EPD.EPD_init_Full(); //全刷初始化,使用全刷波形
EPD.clearbuffer(); //清空缓存(全白)
EPD.fontscale = 2; //字体缩放系数(支持1和2,对图片也有效,用完记得重新改成1)
EPD.SetFont(FONT12); //选择字体,具体支持的字体见文档
EPaperDrive 的字体文件存储在 LittleFS 中,而 Arduino 工程只烧录了程序,没有把 data 目录中的字体文件烧录到 ESP32 的文件系统分区。
里面包含多个字体和图标文件,例如:
data/
├── font10
├── font12
├── font32
├── font60
├── font70
├── weathericon
├── weathericon32
├── weathericon50
└── weathericon80
所以EPD.DrawUTF()函数实际上不仅仅是在显存里画几个字符。
它还需要:
-
从 LittleFS 找到对应字体文件
-
读取字体数据
-
根据字符编码查找字模
-
将字模绘制到
EPDbuffer -
最后通过 SSD1619 刷新到电子纸
给 LittleFS 分配分区
可以在 Arduino 工程目录中创建分区文件partitions.csv:
# Name, Type, SubType, Offset, Size, Flags
nvs, data, nvs, 0x9000, 0x5000,
app0, app, factory, 0x10000, 0x400000,
spiffs, data, spiffs, 0x410000, 0xBE0000,
这里:
app0 0x10000
开始存放程序。
而:
spiffs 0x410000
开始作为文件系统分区。
分区大小:
0xBE0000
约为:
11.875 MiB
足够存放 EPaperDrive 示例中的字体和图标文件。
制作 LittleFS 镜像
有了data目录以后,需要使用 ESP32 Arduino 工具链中的mklittlefs工具制作文件系统镜像。
macOS 下,我使用 Arduino-ESP32 自带的:
~/Library/Arduino15/packages/esp32/tools/mklittlefs/4.0.2-db0513a/mklittlefs \
-c data \
-b 4096 \
-p 256 \
-s 0xBE0000 \
littlefs.bin
成功后会生成littlefs.bin,文件大小大约12 MB
烧录 LittleFS
接下来需要把littlefs.bin烧录到0x410000这个地址
例如 ESP32-S3:
~/Library/Arduino15/packages/esp32/tools/esptool_py/5.3.1/esptool \
--chip esp32s3 \
--port /dev/cu.usbmodem5C830274731 \
--baud 921600 \
write-flash 0x410000 littlefs.bin
验证字体文件
重新运行 ESP32 程序:
if (!LittleFS.begin()) {
Serial.println("LittleFS mount failed");
return;
}
Serial.println("LittleFS mounted");
if (LittleFS.exists("/font12")) {
Serial.println("/font12 exists");
} else {
Serial.println("/font12 NOT FOUND");
}
正常情况下应该看到:
LittleFS mounted
/font12 exists
此时再调用:
EPD.fontscale = 1;
EPD.SetFont(FONT12);
EPD.DrawUTF(0, 0, "这个是局刷的测试");
EPD.DrawUTF(30, 0, "一二三四五六七八九十");
EPD.DrawUTF(60, 0, "Hello World!!!");
中文和英文就可以正常显示。
显示大量中文太慢
能正常显示中文后又发现刷新大量文字时特别慢,需要十几秒,后来发现是EPD.DrawUTF()函数会对每个字符都打开字体文件查找,耗费大量时间,后来又找到这个驱动:https://oshwhub.com/shilihualang/han-jia-qian-gai-zhuang-ji-jian-kai-fa-ban
我跟他用的同款屏幕,而且他这个版本和前面那个 EPD.DrawUTF() 最大的区别是:这里用的是 GUI_Paint 的 Paint_DrawString_CN() + Font12CN,字模直接编译进程序,不需要每个汉字去 LittleFS 查字库,所以明显快很多,实测刷新一整屏的汉字大概3秒多
旋转竖屏
Paint_NewImage(
BlackImage,
EPD_4IN2_WIDTH,
EPD_4IN2_HEIGHT,
ROTATE_270,
WHITE
);
这个函数的第四个参数就是旋转270度竖屏,但是发现不管用,看了下源码:
void Paint_NewImage(UBYTE *image, UWORD Width, UWORD Height, UWORD Rotate, UWORD Color)
{
Paint.Image = NULL;
Paint.Image = image;
Paint.WidthMemory = Width;
Paint.HeightMemory = Height;
Paint.Color = Color;
Paint.Scale = 2;
Paint.WidthByte = (Width % 8 == 0)? (Width / 8 ): (Width / 8 + 1);
Paint.HeightByte = Height;
// printf("WidthByte = %d, HeightByte = %d\r\n", Paint.WidthByte, Paint.HeightByte);
// printf(" EPD_WIDTH / 8 = %d\r\n", 122 / 8);
Paint.Rotate = Rotate;
Paint.Mirror = MIRROR_NONE;
if(Rotate == ROTATE_0 || Rotate == ROTATE_180) {
Paint.Width = Width;
Paint.Height = Height;
} else {
Paint.Width = Height;
Paint.Height = Width;
}
Paint_SetMirroring(1);
Paint_SetRotate(Rotate);
}
最后那行改改就好了

评论区