mirror of
https://github.com/fsender/readguy.git
synced 2026-03-27 14:40:00 +08:00
279 lines
9.4 KiB
C++
279 lines
9.4 KiB
C++
/******************** F r i e n d s h i p E n d e r ********************
|
|
* 本程序隶属于 Readguy 开源项目, 请尊重开源开发者, 也就是我FriendshipEnder.
|
|
* 如果有条件请到 extra/artset/reward 中扫描打赏,否则请在 Bilibili 上支持我.
|
|
* 项目交流QQ群: 926824162 (萌新可以进来问问题的哟)
|
|
* 郑重声明: 未经授权还请不要商用本开源项目编译出的程序.
|
|
* @file guy_420a.cpp
|
|
* @author FriendshipEnder (f_ender@163.com), Bilibili: FriendshipEnder
|
|
* @brief 4.2英寸Hink墨水屏 驱动库函数
|
|
* @version 1.0
|
|
* @date 2023-09-21
|
|
|
|
* @attention
|
|
* Copyright (c) 2022-2023 FriendshipEnder
|
|
*
|
|
* Apache License, Version 2.0
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include "guy_420a.h"
|
|
#ifdef READGUY_DEV_420A
|
|
namespace guydev_420A{
|
|
//////////// @brief 以下的部分代码来自半糖(HalfSweet)的程序
|
|
//////////// github.com/HalfSweetStudio/EPaperDrive
|
|
//////////// @copyright HalfSweet
|
|
|
|
const PROGMEM unsigned char drv::epd42_lut_full[]={
|
|
0x08,0x00,0x48,0x40,0x00,0x00,0x00,//L0 B low-high-low-high
|
|
0x20,0x00,0x12,0x20,0x00,0x00,0x00,//L1 W low-high-low
|
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,//L4 VCOM
|
|
0x05,0x20,0x20,0x05,0x00,
|
|
0x0f,0x00,0x00,0x00,0x00,
|
|
0x20,0x40,0x20,0x20,0x00,
|
|
0x20,0x00,0x00,0x00,0x00,
|
|
0x05,0x00,0x00,0x00,0x01,
|
|
0x00,0x00,0x00,0x00,0x00,
|
|
0x00,0x00,0x00,0x00,0x00,
|
|
};
|
|
const PROGMEM unsigned char drv::lut_213_B72_Full[]={
|
|
0x80, 0x60, 0x40, 0x00, 0x00, 0x00, 0x00, //LUT0: BB: VS 0 ~7
|
|
0x10, 0x60, 0x20, 0x00, 0x00, 0x00, 0x00, //LUT1: BW: VS 0 ~7
|
|
0x80, 0x60, 0x40, 0x00, 0x00, 0x00, 0x00, //LUT2: WB: VS 0 ~7
|
|
0x10, 0x60, 0x20, 0x00, 0x00, 0x00, 0x00, //LUT3: WW: VS 0 ~7
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //LUT4: VCOM: VS 0 ~7
|
|
0x03, 0x03, 0x00, 0x00, 0x02, // TP0 A~D RP0
|
|
0x09, 0x09, 0x00, 0x00, 0x02, // TP1 A~D RP1
|
|
0x03, 0x03, 0x00, 0x00, 0x02, // TP2 A~D RP2
|
|
0x00, 0x00, 0x00, 0x00, 0x00, // TP3 A~D RP3
|
|
0x00, 0x00, 0x00, 0x00, 0x00, // TP4 A~D RP4
|
|
0x00, 0x00, 0x00, 0x00, 0x00, // TP5 A~D RP5
|
|
0x00, 0x00, 0x00, 0x00, 0x00, // TP6 A~D RP6
|
|
};
|
|
const PROGMEM unsigned char drv::lut_213_B72[]={
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //LUT0: BB: VS 0 ~7
|
|
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //LUT1: BW: VS 0 ~7
|
|
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //LUT2: WB: VS 0 ~7
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //LUT3: WW: VS 0 ~7
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //LUT4: VCOM: VS 0 ~7
|
|
0x0f, 0x00, 0x00, 0x00, 0x00, // TP0 A~D RP0
|
|
0x00, 0x00, 0x00, 0x00, 0x00, // TP1 A~D RP1
|
|
0x00, 0x00, 0x00, 0x00, 0x00, // TP2 A~D RP2
|
|
0x00, 0x00, 0x00, 0x00, 0x00, // TP3 A~D RP3
|
|
0x00, 0x00, 0x00, 0x00, 0x00, // TP4 A~D RP4
|
|
0x00, 0x00, 0x00, 0x00, 0x00, // TP5 A~D RP5
|
|
0x00, 0x00, 0x00, 0x00, 0x00, // TP6 A~D RP6
|
|
};
|
|
const PROGMEM unsigned char drv::lut_213_B72_16grey[]={
|
|
//0x05,0x00,0x10,0x10,0x10,0x00,0x01,//L0 BB R0 B/W 0
|
|
//0x00,0x00,0x00,0x00,0x00,0x00,0x00, //L1 BW R0 B/W 1
|
|
//0x05,0x00,0x05,0x10,0x10,0x00,0x01, //L2 WB R1 B/W 0
|
|
//0x00,0x00,0x00,0x00,0x00,0x00,0x00, //L3 WW R0 W/W 0
|
|
//0x00,0x00,0x00,0x00,0x00,0x00,0x00, //L4 VCOM
|
|
0x01,0x00,0x00,0x00,0x00,0x00,0x00, //L4 bb
|
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00, //L4 bw
|
|
0x01,0x00,0x00,0x00,0x00,0x00,0x00, //L4 wb
|
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00, //L4 ww
|
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00, //L4 VCOM
|
|
|
|
0x00,0x00,0x00,0x01,0x01,
|
|
0x00,0x00,0x00,0x00,0x00,
|
|
0x00,0x00,0x00,0x00,0x00,
|
|
0x00,0x00,0x00,0x00,0x00,
|
|
0x00,0x00,0x00,0x00,0x00,
|
|
0x00,0x00,0x00,0x00,0x00,
|
|
0x00,0x00,0x00,0x00,0x00,
|
|
};
|
|
|
|
void drv::epd_Init(void){
|
|
const uint16_t GreyDrvFrameFreq[]={
|
|
0x1108, /* 75Hz */
|
|
0x1108, /* 75Hz */
|
|
0x180c, /* 35Hz */
|
|
0x2c0a, /* 50Hz */
|
|
0x0709, /* 65Hz */
|
|
0x2f07, /* 80Hz */
|
|
0x0807, /* 90Hz */
|
|
0x2106, /* 100Hz */
|
|
0x0306, /* 110Hz */
|
|
0x1405, /* 120Hz */
|
|
0x0705, /* 125Hz */
|
|
0x3104, /* ~130Hz */
|
|
0x2404, /* 135Hz */
|
|
0x1804, /* 140Hz */
|
|
0x0d04, /* 145Hz */
|
|
0x0304, /* 150Hz */
|
|
};
|
|
//_InitDisplay fx
|
|
if(epdFull==2) {
|
|
Reset();
|
|
epdFull--;
|
|
}
|
|
//guy_epdCmd(0x12); //wake from deepsleep?
|
|
guy_epdCmd(0x74);
|
|
guy_epdParam(0x54);
|
|
guy_epdCmd(0x7e);
|
|
guy_epdParam(0x3b);
|
|
guy_epdCmd(0x01);
|
|
guy_epdParam(0x2b); //300 columns, will send 299.
|
|
guy_epdParam(0x01);
|
|
guy_epdParam(0x00);
|
|
|
|
/*guy_epdCmd(0x0c); //Booster Enable with Phase 1, Phase 2
|
|
//and Phase 3 for soft start current and duration setting.
|
|
guy_epdParam(0x8b);
|
|
guy_epdParam(0x9c);
|
|
guy_epdParam(0xd6);
|
|
guy_epdParam(0x0f);
|
|
guy_epdCmd(0x3a); //set to 100 Hz(0x3a--0x21, 0x3b--0x06)
|
|
guy_epdParam(0x21);
|
|
guy_epdCmd(0x3b);
|
|
guy_epdParam(0x06);*/
|
|
guy_epdCmd(0x3c);
|
|
guy_epdParam(0x03);
|
|
guy_epdCmd(0x2c); //vcom
|
|
guy_epdParam(0x70); //-1.6v
|
|
guy_epdCmd(0x03);
|
|
guy_epdParam(0x15);
|
|
guy_epdCmd(0x04); //set src volt (SEE DOC)
|
|
guy_epdParam(0x41);
|
|
guy_epdParam(0xa8);
|
|
guy_epdParam(0x32);
|
|
guy_epdCmd(0x3a); //Now trying 100Hz
|
|
guy_epdParam((GreyDrvFrameFreq[GreyScalingHighQuality]>>8)&0xff); //raw 30
|
|
guy_epdCmd(0x3b);
|
|
guy_epdParam(GreyDrvFrameFreq[GreyScalingHighQuality]&0xff); //raw 0a
|
|
guy_epdCmd(0x11); //Data Entry mode
|
|
guy_epdParam(0x03); //0x03 or 0x01
|
|
}
|
|
void drv::power_down(){
|
|
Power_is_on=0;
|
|
BeginTransfer();
|
|
guy_epdCmd(0x22);
|
|
guy_epdParam(0xc3);
|
|
guy_epdCmd(0x20);
|
|
EndTransfer();
|
|
guy_epdBusy(210);
|
|
}
|
|
|
|
void drv::SetLut(const unsigned char* lut){
|
|
guy_epdCmd(0x32);
|
|
for(int i=0;i<70;i++){
|
|
if(!epdFull && GreyScaling && !GreyScalingHighQuality && i==35) guy_epdParam(GreyScaling);
|
|
else guy_epdParam(pgm_read_byte(lut+i));
|
|
}
|
|
}
|
|
void drv::drv_init(){ //初始化屏幕
|
|
Power_is_on = 0; //初始为未上电
|
|
epdFull = 2; //初始设为正在休眠
|
|
//drv_color(0xff);
|
|
}
|
|
void drv::drv_fullpart(bool part){ //初始化慢刷功能
|
|
if(epdFull<=1) epdFull = !part; //epdFull==2代表睡眠中, 不能快刷
|
|
if(epdFull) GreyScaling=0;
|
|
}
|
|
void drv::drv_dispWriter(std::function<uint8_t(int)> f,uint8_t m){ //单色刷新
|
|
if(m&1){//stage 1
|
|
if(lastRefresh) drv_dispWriter(f,2);
|
|
BeginTransfer();
|
|
epd_Init();
|
|
SetMemory();
|
|
if(!Power_is_on){ //Power is not On, Power up.
|
|
guy_epdCmd(0x22);
|
|
guy_epdParam(0xc0);
|
|
guy_epdCmd(0x20);
|
|
guy_epdBusy(120);
|
|
Power_is_on=1;
|
|
}
|
|
SetMemory();
|
|
if(epdFull){ //慢刷
|
|
guy_epdCmd(0x26);
|
|
for (int i = 0; i < GUY_D_HEIGHT*GUY_D_WIDTH/8; i++)
|
|
SpiTransfer(f(i)); //按照给定的RAM写入数据
|
|
}
|
|
guy_epdCmd(0x24);
|
|
for (int i = 0; i < GUY_D_HEIGHT*GUY_D_WIDTH/8; i++)
|
|
SpiTransfer(f(i)); //按照给定的RAM写入数据
|
|
if(epdFull){ //慢刷
|
|
epd_Init();
|
|
SetMemory();
|
|
SetLut(lut_213_B72_Full);
|
|
guy_epdCmd(0x22);
|
|
guy_epdParam(0xc4);
|
|
//guy_epdBusy(1600); //等待刷完
|
|
}
|
|
else{ //快刷
|
|
guy_epdCmd(0x2c); //may a mistake? 此处不需要设置vcom
|
|
guy_epdParam(0x20);
|
|
SetLut(GreyScalingHighQuality?lut_213_B72_16grey:lut_213_B72);
|
|
guy_epdCmd(0x22);
|
|
guy_epdParam(0x04);
|
|
}
|
|
guy_epdCmd(0x20);
|
|
EndTransfer();
|
|
lastRefresh=millis();
|
|
}
|
|
if(m&2){//stage 2
|
|
uint32_t ms=millis()-lastRefresh;
|
|
uint32_t u=epdFull?1600:260;
|
|
if(ms<u) guy_epdBusy(u-ms); //等待屏幕刷新完成
|
|
lastRefresh=0;
|
|
BeginTransfer(); //write again
|
|
SetMemory();
|
|
guy_epdCmd(0x26);
|
|
for (int i = 0; i < GUY_D_HEIGHT*GUY_D_WIDTH/8; i++)
|
|
SpiTransfer(f(i)); //按照给定的RAM写入数据
|
|
EndTransfer();
|
|
if(epdFull) power_down();
|
|
}
|
|
}
|
|
void drv::drv_draw16grey_step(std::function<uint8_t(int)> f, int step){
|
|
if(_quality&1) return readguyEpdBase::drv_draw16grey_step(f,step);
|
|
if(step==1) drv_fullpart(1);//初始阶段,完成准备工作 //设置为快刷模式
|
|
GreyScalingHighQuality=step; //开启高品质灰度模式
|
|
drv_dispWriter(f);
|
|
//DelayMs(10); //未知原因()
|
|
if(step==15) GreyScalingHighQuality=0;//初始阶段,完成准备工作 //设置为快刷模式
|
|
}
|
|
/*void drv::drv_draw16grey(uint8_t *d16bit){ //绘制16阶段灰度示例图片, 注意这需要4倍的内存
|
|
(void) d16bit;
|
|
//drv_color(0xffu); 建议在开始前调用
|
|
drv_fullpart(1); //设置为快刷模式
|
|
for(int i=0;i<16;i++){
|
|
GreyScalingHighQuality=i; //开启高品质灰度模式
|
|
for(int j=0;j<15000;j++){ //从最深色开始发送, 逐步淡化, 重复15次(白色就不用刷了)
|
|
//if(j%50<5) guy_epdParam(0xff);
|
|
//guy_p[j] = (j%50-5<i*3?0:0xff); //For test only
|
|
}
|
|
//drv_display(guy_p);
|
|
}
|
|
GreyScalingHighQuality=0; //关闭灰度模式
|
|
}*/
|
|
void drv::drv_sleep() { //开始屏幕睡眠
|
|
if(RST_PIN>=0) { //未定义RST_PIN时无法唤醒
|
|
power_down();
|
|
BeginTransfer();
|
|
guy_epdCmd(0x10); // deep sleep mode
|
|
guy_epdParam(0x01); // enter deep sleep
|
|
EndTransfer();
|
|
}
|
|
epdFull=2; //睡眠
|
|
Power_is_on=0;
|
|
}
|
|
}
|
|
#endif /* END OF FILE. ReadGuy project.
|
|
Copyright (C) 2023 FriendshipEnder. */
|