前一阵在学校那会,偶然的机会晚上饭后出去遛弯,在路边看到个被抛弃的 U盾,这么一想应该是附近拆迁搬东西时丢出去的,随即捕捉它。作为一个啥都折腾的捡垃圾技术宅肯定要去研究一波(笑
是个建行的 U盾,按键部分还有点老灰,屏幕的尺寸盲猜 128x64,不可能再大了
背面除了序列号没有别的东西,顶部有个盖子,像极了上古时期的 U盘
插上充电宝可以正常点亮,至少屏没坏
拆解&分析电路
直接开拆,用刀片沿着四周缝隙插入并挑开卡扣
内部结构挺简单,只有两颗较大的芯片,屏幕的 FPC 排线直接焊接在 PCB 上
中间的这颗是主控,为国民技术的 8051 内核 MCU,型号是 Z8D256U,但是网上没有任何技术资料,所以不去研究它
另一侧的 SOP8 芯片是 1MB 的 SPI FLASH,用来存放驱动软件的虚拟光盘和固件信息,型号是 MD25D80SIG
PCB 的正面有屏幕和按键,屏幕下带有框架和匀光板
接着就是把所有的芯片都淦下来,准备无情地抄板
花了一点点时间,把板子抄下来了,这次用的是纯手工古法制作(doge
顺手分析一下这个电路的原理吧,USB 公头CN1
输入 5V 后分成两路,一路给MCU U1
供电,另一路输入 LDOU2
,转换 3.3V 后为U3
和液晶屏供电,之间都并联了滤波和退耦电容K1
K2
K3
K4
P1
是外部控制的开关,都输入给主控的 GPIO,C3
C4
Y1
R1
组成了震荡电路,给 MCU 提供主频D1
Q1
R2
组成了屏幕的背光控制电路,使用 NPN 三极管的共射极接法作为开关U3
和液晶屏公用同一SPI总线和主控通讯
液晶屏研究
分离屏幕面板和下方的框架,可见这种屏幕排线上没有任何的芯片,这种工艺叫做“COG(ChipOnGlass)”封装,不同于常见的 LCD1602 和 LCD12864 模组,也就是液晶点阵的行列控制线不引出,而引到屏幕下方的一片区域,驱动芯片粘附之上并连接,面板只引出电源和数据引脚,扫描和偏压电路全部集成在这个芯片内部
那么,想驱动这个屏幕,就需要知道它的主控型号和引脚定义,才能用正确的硬件接口和软件协议使它正确显示
而且这屏幕背面和 FPC 上没有任何的丝印型号,用电子放大镜对它做一波逆向分析~
我这个放大倍数是 X1600倍,小一些也没关系,但必须带照明,因为要利用玻璃上 ITO 涂层特定角度下的反光才能看清走线
先观察芯片的引脚排布,如果经验稍微丰富一些,看到这基本已经知道型号了,不再需要用卡尺测量芯片尺寸和估算屏幕分辨率了
像这样屏幕输出驱动引脚是双排交错的芯片,有且只有一个,这就是应用非常广泛的ST7567
芯片,它和ST7565
UC1701
等等芯片软件协议兼容
对照数据手册,可以知道它是STN液晶控制器,分辨率最大支持到65x132,硬件接口兼容8-bit 8080和6800并口总线和SPI总线,内建显存和偏压电路,使用3.3V供电
这个屏幕只用到了 128x64 的区域
对照数据手册的引脚定义部分,根据引脚的顺序推断定义
这是最后分析出的引脚定义(拙劣拼图技术
直接在 PS 里标出来
ITO 走线引出了19个引脚,而FPC端只有12个引脚,需要继续观察FPC的走线
最终得出引脚定义(屏幕正面从左到右
PIN | 定义 |
---|---|
1 | N/C(不接) |
2 | N/C(不接) |
3 | VG(偏压输出) |
4 | XV0(XV0电压输出) |
5 | V0(V0电压输出) |
6 | GND(接地) |
7 | VCC(+3.3V电源) |
8 | D7(复用为SDA,串行数据) |
9 | D6(复用为SCL,串行时钟) |
10 | A0(指令/数据切换) |
11 | RST(复位) |
12 | CS(片选) |
其中 1 2 脚悬空不用
6 7 脚连接3.3V电源和地
12 11 10 分别对应控制信号CS(片选)
RST(复位)
A0(数据/指令选择)
而 8 9 脚对应并口总线的D7
和D6
,根据数据手册中的说明,在SPI模式下它们分别复用为SDA
和SCL
根据数据手册,第 3 4 5 脚为液晶驱动电压端,虽然内部已集成了电源电路,但还需要在外部连接 0.1μF-1.0μF 的无极电容,才能正常显示V0
和XV0
是内部两路驱动电压发生器的端路,之间需要相互连接电容VG
是内部偏压电路的端路,需要对地连接电容
原电路取值都是 1μF
焊上 FPC 专用测试板转出插针,引脚间距是 0.8mm
调试单片机程序
使用stm32单片机最小系统板作为测试平台,用杜邦线连接测试板和单片机
GPIO口的连接如下:
PA2->CS
PA3->RST
PA4->A0
PA5(SPI1_SCK)->SCL
PA7(SPI1_MOSI)->SDA
本着不重复造轮子的原则,软件部分直接调开源库u8g2
构建函数部分随便选了一个 ST7567 主控的屏幕配置,实际上可以自己二次开发,自定义屏幕的显示属性和初始化参数
#include <Arduino.h>
#include "U8g2lib.h"
U8G2_ST7567_ENH_DG128064_F_4W_HW_SPI u8g2(U8G2_R0, PA2, PA4, PA3);
void setup() {
u8g2.begin();
u8g2.setFont(u8g2_font_wqy13_t_chinese3);
u8g2.enableUTF8Print();
u8g2.setCursor(30,20);
u8g2.print("hello world!");
u8g2.setCursor(35,40);
u8g2.print("你好世界!");
u8g2.drawFrame(0,0,128,64);
u8g2.sendBuffer();
}
成功点亮,但是发现显示方向是反的,而且左边还有重影
欸欸欸!可别慌了,前面说随便选了个屏幕的配置,当然会有参数微调的问题
再参考数据手册,这里有SEG Direction
和COM Direction
两个指令,对应水平镜像和垂直镜像,也就是操作MX
和MY
的两个bit的使能就可以从硬件层面上控制扫描方向(这里还有个反向坐标偏移的问题,如SEG从132端还是0端连接屏幕X轴的128个像素,涉及不到就不做处理了
在u8g2框架下,直接向屏幕发送指令需要调用底层的函数u8x8_cad_SendCmd()
等,但在这之前先要取得u8x8_t
结构体指针
因为 u8g2 是对 u8x8 的高级图形封装,而 u8x8 是对屏幕控制器接口的 HAL 层封装
代码加入这几行即可发送
#include <Arduino.h>
#include "U8g2lib.h"
U8G2_ST7567_ENH_DG128064_F_4W_HW_SPI u8g2(U8G2_R0, PA2, PA4, PA3);
void setup() {
u8g2.begin();
// 操作底层指令以修正镜像设置
u8x8_t *u8x8 = u8g2.getU8x8(); // 获取u8x8结构体指针
u8x8_cad_StartTransfer(u8x8);
u8x8_cad_SendCmd(u8x8, 0xa0); // 水平镜像
u8x8_cad_SendCmd(u8x8, 0xc8); // 垂直镜像
u8x8_cad_EndTransfer(u8x8);
u8g2.setFont(u8g2_font_wqy13_t_chinese3);
u8g2.enableUTF8Print();
u8g2.setCursor(30,20);
u8g2.print("hello world!");
u8g2.setCursor(35,40);
u8g2.print("你好世界!");
u8g2.drawFrame(0,0,128,64);
u8g2.sendBuffer();
}
这就可以正常显示了 OHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
最后老规矩,有屏幕的地方就有坏苹果,虽然只有1帧(灵梦のU盾,确信
传送门:B站专栏转载