视频演示:
骚气双副屏,单片机实现win10 USB副屏演示esp32 s2_哔哩哔哩_bilibili-https://www.bilibili.com/video/BV1tU4y1F7B6?spm_id_from=333.999.0.0
开源计划
2021年最后一天,庆祝新年。
github开源地址如下,欢迎复刻魔改。发b站的可以@我,给三连打call。
https://github.com/chuanjinpang/win10_idd_xfz1986_usb_graphic_driver_display
概要
单片机esp32s2+SPI屏实现一个win10 USB接口显示器。
本项目借鉴了众多开源项目,主要借鉴:
1.github.com/microsoft/Windows-driver-samples/tree/master/video/IndirectDisplay
2.git://github.com/roshkins/IddSampleDriver.git
3.Bodmer/TFT_eSPI.git
4.nopnop2002/esp-idf-ili9340,
5.serge-rgb/TinyJPEG.git
6.TJpgDec。
目前FPS在~13FPS,纯黑屏幕时能摸到20FPS。
主机使用IDD显示驱动方案,将屏幕进行JPEG压缩,然后通过URB(USB请求包)发送到下位机。下位机解压并发DMA传输写屏达到高性能。下位机esp32s2只支持全速度12Mhz,所以必须高压缩的JPEG才能有高FPS.
为了获得较稳定的FPS,采用了动态码率策略,会依据图像情况,进行压缩率调整。
- 器件清单
以下链接与卖家只是我买的地方,仅作参考,只是型号是一样的,东西是同一种,有门道能找到更便宜的卖家最好。
像ESP-12H-Kit单独买模块小板就只要10块,适合自己做PCB板。
最近也支持了st7789这种屏。
名称 | 数量 | 参考图 | 参考链接 | 说明 | |
1 | ESP-12H-Kit/开发板 | 1个 | 3.0哈RJViXrMySIx! https://m.tb.cn/h.fW0rvEj?sm=7e7b4b NodeMCU系列WiFi模块ESP32-S2F芯片 ESP-12H-Kit/开发板 | ||
2 | 2.4寸4线SPI串口TFT液晶显示屏模块 ILI9341驱动LCD触摸屏240*320 | 1个 | 7.0!vC8RXro0LDp嘻 https://m.tb.cn/h.fW0F9GF?sm=557ab4 2.4寸4线SPI串口TFT液晶显示屏模块 ILI9341驱动LCD触摸屏240*320 | 1.不用买触摸,软件目前不支持触摸功能。 用mouse更方便。 2. 其它类型的320*240屏也可以,比如st7789。不过软件目前只有9341驱动,将来会加上更多的屏。主要是合别人的代码。 | |
3 | MICRO USB转Dip 母座 | 1个 | 2信8fXpXroYDr0, https://m.tb.cn/h.fW0wxi2?sm=c95448 MICRO USB转Dip 母座B型 麦克5p 贴片转直插 转接板 已焊接 母头 | ||
4 | 2.54mm杜邦线 | 12根 | 自备 | ||
5 | Micro USB线 | 1根 | 自备 |
- 整机组装图
这个是组双屏的效果,通常一个屏就好了。
3.硬件连接图
4 .安装说明
4.1 ESP32-S2固件更新
使用下载工具更新固件。第一次应该要更新所有的文件,包括bootloader.bin,partion-table.bin
4.2 windows驱动安装
因为目前没有给驱动签名,所以要关掉windows对驱动的检查,使用测试模式。
如果相对比较稳定后,看要不要弄个签名,淘宝上卖家签名一次要300!
4.2.1 启用测试模式
使用管理员身份打开命令行cmd
bcdedit /set testsigning on
重启系统,桌面右下角会有一个测试模式的水印。如下图。
如果要关掉,使用bcdedit /set testsigning off 然后重启即可。
4.2.2 安装驱动
1. 插入已经更新好esp32s2设备,这一步应该的固件。会被windows识别为未知设备,如下图。我们的USB设备号为:USB\VID_303A&PID_1986
2. 复制驱动文件到桌面,或者其它地方。
- 右键设备,选择浏览查找
- 找到驱动文件夹
- 选择始终安装此驱动,因为没有正式签名。系统给出警告。
- 安装完毕,会在显示适配器下面出现xfz1986_usb_graphic(demo). 正常就能看到windows桌面了。
- 本驱动目前只支持2种分辨率320*240,640*480.对于640会进行2:1缩放。
有兴趣的可以自己魔改,增加更多的设置,和更大的屏幕。
- 固件与驱动编译
4.1 esp32s2 设备固件编译
Esp-idf版本:v4.3-beta3
4.1.1. esp32s2_usbdisp 复制到esp-idf目录下
本身就是一个esp-idf工程
4.1.2 更新tinyusb
Tinyusb.tgz 解压合并放入esp-idf/components/tinyusb。图省事没有生成patch.大家可以用比较工具比较差异,改动并不大,主要是增加 vendor模式。需要注意的是,目前USB的改法是个临时方案,可能会对其它tinyusb有影响。
4.1.3 配置工程
进入esp32s2_usbdisp
idf.py set-target esp32s2 #设置目标芯片
idf.py menuconfig #修改配置,
相关4个配置如下:主要是配置LCD管脚,提高CPU频率到 240M,编译为O2性能模式,使能 tinyUSB
4.1.4 编译
idf.py build
生成固件
4.1.5 可选的杂项
串口连接S2查看工作状态
默认打印FPS
开机logo
实现了一个开机图片,一个重要的功能是表明屏驱动在工作。是内嵌jpeg 文件的数组。具体是 logo.c 实现。
只要替换这个logo_jpg数组的内容即可。大小不要超过320*240.
我是用 git://github.com/Jamesits/bin2array.git 实现转换的,python小工具。
4.2 windows驱动编译
本人使用是vs2015+wdk10,也可以使用vs2019+wdk10等。大家可以自己看情况,网上也有相关教程。如果不想魔改,这个驱动也应该够用了。能魔改更好。
打开工程,右键工程,选择生成。
然后会在类似下面的路径生成驱动包。这个是x64的,应该没人用32位的系统吧?
- 软件架构
从设计实现上,本软件是支持2种数据模式,一种rgb565直传,一种是jpeg压缩数据。
USB传输也实现了两种:一种是同步,一种是异步模式。异步从理论上讲性能要好一些。
rgb565直传,同步模式主要是为了调试而存在了。
6.1 ESP32固件架构
Usb实现了一个vendor自己定义的USB设备,有一个in 管道。
注册一个回调处理函数tud_vendor_rx_cb,收到一个数据包64字节。
先进行头解析,如果是起始包byte[0] bit7 置位,表明一个操作开始,解析相应参数(total_size,top,bottom,...)。
然后将数据推入缓存disp_rx_ring_buf中。
显示线程,从disp_rx_ring_buf抽取数据进程处理,目前都是jpeg的显示数据,所以都会走jpeg显示处理,边接收数据边解码,积累到足够多时(一次多传输点,能降低额外开销,提高速度),启动SPI dma进行送显。同时会交换ping-pong buffer. 并行进行,提高FPS.
主机与设备通讯协议是沿用rpusbdisp的协议。就是消息头改了下:
该协议的要点:
USB是包消息,并且是固定长度64byte(大体如此),最后一个包例外。所以每个包第一个字节是协议占用,表明类型。好处是方便定位消息头部:如果第一个字节的bit7置位,就是一个新的操作,否则是数据。这样利于出错恢复。
解码与屏幕刷新:
1.这种是dma模式的spi,跑的是40Mhz,理论带宽可以跑到30 fps,如果spi是80Mhz的.屏幕也支持的话,就加倍了60fps。
2.另外一个关键点是边解码边刷数据,并行做。比如数据一帧要50ms.传输也要50ms.那串行就要100.并行就只要50ms.
3.一次刷dma数据不要太少,建议一次传5kb,降低非必要开销。具体大小要和数据配合调优。
6.2 windows驱动架构
大体框架是基于MS的idd驱动sampledriver,所以我只讲增加的部分。
1.在void SwapChainProcessor::RunCore()采集屏幕数据,当前没有找dirty区域,因为懒。
直接复制整个屏幕.
- 在这里,存在一个将GPU 数据转换为CPU能访问的数据区域,具体是创建了一个ID3D11Texture2D对象,其有D3D11_CPU_ACCESS_READ能力。然后复制出GPU 数据.
- 自动适应屏幕大小缩放。如果是640*480就2:1缩放。
- 然后调用usb_send_jpeg_image()发送
- 具体是先生成包头,内容jpeg编码压缩,这里有一个自动压缩率算法,目的是保证FPS能稳定在13-15fps。下位机能力比较弱,使用固定压缩质量,复杂画面容易把fps拉到10fps.
- 编码成usb协议包,也就是为每64byte增加一个特别的头。
- 调用usb_send_msg_async()进行真正的USB传输。
- 开发者
不才,欢迎相互交流下经验。
7.1 windows调试:
主要有2种,一种是用tracevew来查看驱动日志,另一种是windbg。
目前没有明显的bug,应该都用不上。只是开发过程中用得比较多。
7.2 esp32调试:
主要是log,当然也有一些高级点的调试,比如通过panic dump信息来正面刚来调试。
7.进一步的工作:
提高FPS,当前的瓶颈在于JPEG解码开销。 可能的方法:
- 采用 S3 双核并发提高JPEG 解码速度。
320*240对于桌面来说,分辨率小了些。因此可以考虑用安卓手机来当下位机显示器。