
66元5.5寸1080P触摸HDMI蓝牙WIFI的多功能电脑副屏
简介
上个项目中,我们使用树莓派成功驱动了一款手机屏幕,这次围绕着使用这片全新的面板TM055VDXP35,尝试以最低成本打造一款5.5寸1080p带触摸蓝牙wifi兼显示器功能的智能硬件设备。
简介:上个项目中,我们使用树莓派成功驱动了一款手机屏幕,这次围绕着使用这片全新的面板TM055VDXP35,尝试以最低成本打造一款5.5寸1080p带触摸蓝牙wifi兼显示器功能的智能硬件设备。开源协议
:CC BY-NC-SA 4.0
描述
项目简介
在上个项目中,我们使用树莓派成功驱动了一款手机屏幕,机缘巧合我们又搞到了一些型号为TM055VDXP35 5.5寸 1080p的面板,使用这款面板的手机挺多的(具体详情可以网上搜索该型号),这次我们就尝试主要围绕这块屏幕,打造一款带触摸蓝牙wifi兼显示器功能的智能硬件设备。
关于如何在没有规格书的情况下逆向点亮一块手机mipi屏幕,上期有较详细说明,具体可以查看之前的项目链接:https://oshwhub.com/5473675a/28-yuan-make-5inch-touch-display
,这里就不详细赘述了,有了上次的经验驱动点亮应该不是很难的事情(主要就是按顺序供电,拉复位,发初始化代码),这次就详细介绍一下其他部分开发的心路过程吧,这个项目目零零碎碎消耗了三个多月的时间,PCB也推倒重来好多次,其中踩过的坑数不胜数,好几次都想放弃但是都坚持下来了,目前硬件主要功能已完成,你也可以打板测试,软件附加功能仍在继续开发中。。。
项目成本
1. 5.5寸 1080p 屏幕 无货
2. 5.5寸 触摸 9元
3. SOC主控 杰理 AC7916N 8元
4. LCD电源&背光 KTZ8850EUC 3元
5. 视频桥接芯片 RK628d 12元
6. SPI存储8MB 1元
7. 屏幕&触摸连接器 3元
8. HDMI、typec、耳机接口/阻容/晶振/电感等其他杂项应该可以压到15元以内
上述材料去某宝搜索型号都可以买到,未包含运费。如果只考虑物料成本,免费打板,手动焊接🤭,项目总成本应该可以压到66元以内,当然我这是有点标题党了,如果算上开发,组装和外壳,应该成本至少要翻个倍吧。
成品渲染图


半成品实物图

功能特性
- 外接HDMI显示 (完成)
- 触摸/虚拟触摸板 (完成)
- 虚拟声卡/蓝牙音频A2DP/EQ调节 (部分完成)
- 快捷控制(音量,亮度,AI唤醒,快捷键) (部分完成)
- 主机性能监控 (部分完成)
- 密码管理器 / USB硬件安全密钥(评估阶段)
- 更多功能待挖掘
芯片选型
主控
主控MCU方面,考察需要的功能(触摸转USB,音频处理播放,蓝牙音频A2DP,HDMI音频,网络通信,IIC通信)
则MCU至少需要有usb otg控制器,i2s音频接口,音频dac,IIC接口,WIFI/蓝牙这些配置
在考察过STM32,GD32,ESP32,WCH等多款芯片后,发现不是这里没有USB控制器,就是没有音频编解码,或者没有蓝牙wifi,都有的话价格又不合适,如果改用外挂芯片来实现一些功能又太麻烦,外围也会更复杂,思索再三,发现有且只能从国产冷门MCU中寻找出路,经过查阅多家智能硬件的廉价MCU方案,排除掉一些根本买不到的方案,最终锁定了杰理方案的AC791N系列,这款MCU的接口相当丰富,功能也十分齐全,看到这个规格的第一眼,我就知道这个芯片完美解决了我的需求。

可能有些人对杰理这个名字很陌生,但是一提到华强北的山寨TWS,你肯定不会陌生,很多山寨TWS用的就是这家公司的芯片,并且真是便宜大碗,仅需8元即可买到带wifi和蓝牙5.3的320MHz的高性能双核浮点DSP处理器,但是缺点也很明显,相关开发资料极少,很多都是闭源,烧录器都加密,不过谁叫它便宜呢,至少网上还有点资料。同时好在最近杰理上线了开源页面: https://doc.zh-jieli.com/AC79/zh-cn/release_v1.0.3/index.html
最新的AC79系列也提供了相对完整的开发文档和流程,可以绕过烧录器进行烧录程序了,我相信能跑起来应该问题不大,主要是小问题比较难以解决。
最后别忘了这家公司之前专攻TWS的,在音频部分有很深的积累,所以在处理HDMI音频的同时,应该也可以作为一个虚拟USB声卡来使用,如果有较好的调教并且设计得当,成品的音质应该会不错。此外,杰理还提供了很高级的音频调教工具,如下图:


显示转接
显示部分,需要一个hdmi转mipi的ic,主流有东芝和龙讯的可选,但是价格太贵,且资料相当封闭,可定制度不高,就算你买到芯片,没原理图说明文档你也跑不起来,只能转向非专业hdmi转mipi的ic,经过不断查找,一个偶然的机会,我发现了这篇文章: https://oshwhub.com/bitszh3271/RK628-HDMIzhuai-MIPI-ping-mu-shi
看过之后我立马锁定了RK628d,这是一款24合1视频桥接芯片,性价比极高,无论是性能和功能都非常强,特定场景下甚至最高支持到4k 60hz,且某宝售价才12元,算是很超值了,并且网上泄露的资料也较多,重点是有人尝试过能跑起来,那就一定不会有大问题,相比起来一片TC358870都50多元了,有这钱我都可以做两个了。
供电
供电部分主要包供电,显示屏供电以及背光供电,5v从typec引出,后续通过SM8103ADC(手头正好有)转成3.3v主供电,RK628d还需要一路1.1v供电,使用的是TLV74311PDBVR,还有一路3.3v转1.8v供电(显示面板的IOVCC)继续使用上次没用完的XC6206P182MR。
接下来是显示屏供电,由于主板空间相当紧张,屏幕又需要使用到Bias Power ±5V供电,为了尽量减少外围,选择了背光供电二合一芯片KTZ8850EUC,这个型号不是很常见,用的也少,我是从查看原手机的电路图才知道有这款芯片(使用的相同公司的不同型号)。这款芯片集成度相当高,真的丧心病狂的在接近0402的封装里塞下了18个焊点,焊接相当困难,这个焊盘需要的工艺已经在挑战嘉立创免费打板的极限了,免费打板的工艺是不可能进行全引脚引出的,甚至打一个最小的过孔都要占用两个焊点,为了用上这个ic,首先砍掉了中间的两个i2c引脚,其次+5v和-5v的使能都改用成一个io控制,这才艰难地满足了要求。

中间的方块就是KTZ8850EUC,可以看到它与周围的电容几乎差不多大
可选外设
Touch Bar的一个重要的缺陷就是缺乏物理反馈,为了提高效率,在盲触时有反馈,可选增加线性马达和H桥控制芯片TM6604,马达部分可选挺多的,但是正好手头有iPhone 6s拆机的Taptic Engine,先在pcb上预留了固定位置,暂时还没时间测试。
PCB设计
尺寸
PCB尺寸上,首先确定PCB需要置放在屏幕下的,这样首先需要满足的是,长宽任意一条边不得超过屏幕尺寸,其次考虑到免费打板是10x10cm,以及后续的SMT需求,最终PCB尺寸定为7.8x9.0cm

阻抗
阻抗部分主要需要考虑的是mipi/usb/天线部分的走线,上次的转接板使用了4层板工艺,主要是为了考虑阻抗(嘉立创两层板没有做阻抗的选项),这次无意中发现嘉立创虽然不做2层板阻抗,但阻抗计算神器中仍然可以计算两层板阻抗,我猜这大概是说阻抗不做额外调教保证,能不能工作全看人品,所以试试呗。测试打板时试用了2层板工艺,可能是运气比较好,目前实测没有发现问题,所以直接保留使用二层板,如果批量制作还能进一步降低成本。
天线部分,我没有太多经验,经过上网查询以及翻阅杰理给出的硬件设计指南,得知主要有两点1.不同的板厚对应不同的天线外形,2.要做50欧姆的阻抗匹配,剩下的仿真有亿点难搞,没经验的话可能还不如不搞,还是直接完全照搬参考设计吧。
我们采用的是默认板厚1.6mm,可以直接套用ESP32的天线外形,为了保证最大的布线空间,优先将天线放到角落,另外由于天线附近需要净空,于是将多余的角进行切除。由于没有专业设备,无法确定这样是否会对信号质量是否有影响,阻抗也只能根据阻抗计算神器的计算结果进行匹配,能做的都做了,最后注意一下预留出π型的匹配电路,以待后续有条件了的情况下可以再对阻抗进行优化。

原理图
MCU的原理图部分主要参考: https://oshwhub.com/aknice/jie-li-ac7916a-he-xin-ban (写得非常详细)以及官方SDK中的原理图PDF根据需要进行删改,主要修改了供电部分,以及USB部分,USB主要是对typec的正反插进行复用,杰理AC7916N的USB是具有两个USB controller的,一个usb 1.1主要用于升级,一个全功能usb 2.0,为了减少开发难度,将两组usb都引到了同一个typec接口,通过正反插可以切换不同的功能。
RK628d的资料可以参考上面提到的文章,以及RK628D_DEMO_BGA144_REF_V11_20210602.pdf 不用想太多,直接抄就是了,抄完之后1. 本来连接到外部gpio的引脚分配到自己MCU的引脚,2.重新分配供电,3.修改时钟来源,可以使用独立晶振,也可以使用MCU扇出的时钟来源。
布线
由于是两层板,并且考虑到焊接以及显示屏贴放的位置,只能单面放元件,所以芯片周围空间还是非常紧张的,主要的阻容原件都被逼用上了0402的小型封装,虽然板子四周还有较多空间,但是主要io和走线都集中在中间很难利用上,就拿rk628d来说,芯片的hdmi接口在上,mipi接口在下,再加上hdmi和mipi有等长和最多两次过孔的限制,一旦你定下hdmi接口的方向,显示座的位置也被锁死了,RK628d的原厂参考设计中,电容是可以放在背面的,现在要移动到正面,再加上很多电容都要靠近管脚处放置,一些IO还需要特定的走向,布线时错过一个扇出位置就要绕很远的路,所以走了再改,改了再走是很常见的事情,不过好在软硬件是同步开发的,io口走向不合适我还能根据参考设计手册查看有没有备用io,进行软件上的改动,即使是这样,还是有很多要取舍的地方,有些地方是实在走不通的,只能用飞线或者外部元件进行替代了,本来还想将soc的RGB显示接口连接到rk628d进行输出(这样的话板子可以脱离外部主机独立运行),但是空间实在紧张,要绕的路太多,rk628d的扇出也已经没有空间了,只能作罢。
焊接
焊接是这里面最难的部分了,没打板之前我就知道这块板相当难焊接,结果也如我所料,焊接热风枪是不行的,不是吹飞了就是吹变形了,必须上恒温铁板烧,为了简化焊接,很多esd组件都可以省略。
我是没有使用钢网的,为了避免大面积返工,我都是焊一点测一点,这样反复加热,几次下去pcb背面就开始起皮了,然后就只能重新搬板重新测,焊黑了三块板子之后才勉强得到了一块能工作的板子。焊完一次真的不想再想再来第二次
其中最难焊接的是显示屏排座和屏幕背光供电ic,显示屏排座的针脚特别密集,先上锡膏再放上去非常容易连锡,相对来说rk628d的bga反倒没有那么难焊接,焊接显示器排座的时,候焊油放多了,焊油渗透到排座上,加热后非常难清理,不清理焊油固化后排座就死活扣不上了。最坑的是有一次显示排座虚焊,万用表测试的时候,可能是有力压上去就通,松开就虚焊,测都测不出来。
由于焊接的不确定问题,调试变得更加困难,有过相似经验的可能深有体会,代码不工作->怀疑电路有问题->检查电路->检查是不是贴错元件->检查虚焊->发现没问题继续检查代码,如此循环往复。
软件部分
开发环境搭建
主要参考:
https://doc.zh-jieli.com/AC79/zh-cn/master/getting_started/environmental_install/index.html
非常顺利,没什么可说的,需要注意的是,在将程序下载到板子之前需要更新一下配置文件app_config.h你的spi flash的容量,这里使用的是64Mb,8M的spi flash
#define __FLASH_SIZE__ (8 * 1024 * 1024) #define __SDRAM_SIZE__ (8 * 1024 * 1024)
首次使用codeblock编译示例项目的时候会有找不到文件的报错,删掉该文件的引用就好。
杰里SDK
杰理有一套自己的系统开发框架,还有自己的app生命周期和状态机,但是由于其开发资料不是很全,也没有对自己系统的运行机制做一个很详细的说明,所以大部分代码走的还是纯c/c++路线,开发遇到瓶颈的时候,我一般都去仔细阅读sdk中的示例代码,比文档更有用,示例代码中没有的,那就只能去.h文件中找接口一个个去试了。其中最让人和谐头大的应该就是一层套一层的宏定义了。杰理的系统中,几乎全部的功能都是靠宏定义开关的,想开一个功能,例如usb的otg,需要打开很多项的宏定义,这时候只能是一个个去翻找这个宏是做什么的,需要依赖哪些相关的宏,非常费时间。另外则是一些库的引入,这是杰理关于他们类库的说明 https://doc.zh-jieli.com/AC79/zh-cn/release_v1.0.3/module_example/system/lib_info.html
这些库大部分都是不开源的,编译的时候,还分为报错和不报错,报错的还算好解决,无非就是提示找不到xxx定义,那就全局搜索这个定义,找到最可能的那个.h文件进行引入,如果有依赖,那么就将依赖一并引入,如果依赖还有依赖,那就继续套娃引入,到最后总能成功编译的。其次也不能瞎引入,有些.c/.h文件,不知道是没开发好还是上个项目留下来的史山代码,功能/定义残缺,这时候千万不要引入,不修改代码是永远不可能编译过的。区分上述两种情况的方法就是:最好一个文件一个文件的引入,不要一次性批量引入,全引入必定特别多莫名其妙的报错。
不报错的部分,大部分都是静态库,你少引入一些库是不会报错的,而且你根本不知道当前功能需要引入哪些库,功能不正常?一个个查去吧,要么就全部引入,但是这样的缺点是编译的时间会变得很长,且生成的固件变大,如果存储不够,下载就会报错,而且报错内容也不会告诉你是存储不足,如果你去网上搜索解决方案会将你带入更深的坑。
触摸屏
这次我们使用的是某大厂的触屏遥控器的全新触摸库存货,触摸ic是GT1151Q,支持手套模式,支持15点触控,手套模式,以及自定义手势唤醒,资料手册也很全,接口也是通用的i2c不怕驱不动。另外杰理sdk中的示例代码是GT911的,照葫芦画瓢,初始化后按照下面的寄存器地址进行读取就能够轻松读出来触摸数据。


视频转接
网上能找到的RK628d的资料挺多的,但是比较乱,并且这个ic的原始驱动是linux内核的,给的文档也是linux的,不通用,很多东西都需要自行研究,还有就是这款ic找不到寄存器手册,给开发带来了很大的麻烦,抛开这方面不谈,这款芯片还是比较易于上手的,底层逻辑就是该芯片作为主控与屏幕的桥梁,主控通过i2c控制其与屏幕进行通信,所以任意一款支持i2c的主控,理论上都能调用RK628d进行视频转换。
主要的移植过程可以参考这篇文章,这是我翻了挺多文档,对比出来的,单纯移植代码看这篇足够:
https://github.com/mfkiwl/rk-open-docs/blob/master/DISPLAY/Rockchip_MCU_RK628D_Porting_Guide_CN.md
RK628d已经提供了一套完整的驱动代码,我们只需要实现其中的i2c读写接口/延时函数/以及屏幕的初始化流程控制即可完成适配。
首先需要解决的是i2c的读写问题,由于RK628d的寄存器地址和数据都是32位的,跟常见的i2c设备不一样,查看文档也没有说到寄存器读写应该怎么测试,这个能理解,毕竟本来就不是为了非RK SOC准备的,另外杰里那边i2c的示例代码也都是16位地址和数据,并且是封装好的IOCTL,不知道底层实现是什么样的,实际测试用杰里的i2c示例代码一读就卡死,只能继续翻资料,翻了挺多资料,走了很多弯路,直到找到了这张时序图:

对照着图中的时序,调整收发代码,这时候发现原先收发的代码能跑通了,但是发现读出来的数据全是0,也不知道哪里出问题了,先确定硬件以及连接是否有问题吧,还是上逻辑分析仪吧,由于焊点很小焊接困难,连接全靠漆包线和夹子,又要一边连电脑一边连测试板,导致连接相当不稳定,用一次也特别麻烦,所以我一直很抗拒使用它,一切都折腾好后,调出逻辑图形:

首先发现写入有ack,确定了硬件连接是正常的,再次仔细检查设备地址和寄存器地址大小端序,也没发现什么问题,怀疑是停止位的问题(后面证实不是),又折腾了一段时间,发现可能是杰理的printf函数实现可能有问题,似乎不支持0x%x这种写法,修改后,另外将代码中读取所有寄存器数据的宏打开后,发现能读取到一些数据了,但是大部分还是0x00000000,我也不知道这样的值是不是正确的,也不确定读出来的字节序对不对,只有硬着头皮,假装是正确的,先把后面的写完,回头再来反推这部分写得对不对,以下是后面得出的正确读取时序:
/**
* I2C读取32位数据函数
*/
static s32 i2c_read_32bit(u8 device_addr, u32 reg_addr, u32 *data)
{
u8 i;
u32 temp = 0;
u8 dev_addr_write = (device_addr << 1) | 0x00;
u8 dev_addr_read = (device_addr << 1) | 0x01;
*data = 0;
log_info("i2c_read_32bit : %d, device_addr: 0x%02X\n", __LINE__, device_addr);
// 启动I2C通信
dev_ioctl(g_iic_handle, IIC_IOCTL_START, 0);
// 发送设备写地址
if (dev_ioctl(g_iic_handle, IIC_IOCTL_TX_WITH_START_BIT, dev_addr_write))
{
log_info("iic write addr err!!! line : %d, device_addr: 0x%02X\n", __LINE__, device_addr);
goto exit;
}
delay(100);
// 发送32位寄存器地址 (小端序:低字节先发)
for (i = 0; i < 4; i++)
{
temp = (reg_addr >> (8 * i)) & 0xFF;
if (dev_ioctl(g_iic_handle, IIC_IOCTL_TX, temp))
{
log_info("iic write reg addr err!!! line : %d \n", __LINE__);
goto exit;
}
delay(100);
}
// 发送重复起始条件和读地址
if (dev_ioctl(g_iic_handle, IIC_IOCTL_TX_WITH_START_BIT, dev_addr_read))
{
log_info("iic restart err!!! line : %d \n", __LINE__);
goto exit;
}
delay(100);
// 读取4字节数据 (按小端序接收:低字节先收)
for (i = 0; i < 4; i++)
{
temp = 0;
if (i == 3)
{
// 最后一个字节:接收需要生成STOP条件
if (dev_ioctl(g_iic_handle, IIC_IOCTL_RX_WITH_STOP_BIT, &temp))
{
log_info("iic read data[%d] err!!! line : %d \n", i, __LINE__);
goto exit;
}
}
else
{
// 非最后字节:发送ACK继续接收
if (dev_ioctl(g_iic_handle, IIC_IOCTL_RX, &temp))
{
log_info("iic read data[%d] err!!! line : %d \n", i, __LINE__);
goto exit;
}
}
// 按小端方式拼接 data(低字节在低位)
*data |= (temp << (8 * i));
delay(100);
}
return 0;
exit:
dev_ioctl(g_iic_handle, IIC_IOCTL_STOP, 0);
return -1;
}
默认i2c的问题解决后,接下来内容就是按照文档中的说明依次配置就ok了,文档没有提到的,但是需要注意的,还有EDID配置,EDID 全称是 Extended Display Identification Data(扩展显示识别数据),是显示设备(如显示器、电视、投影仪)用于向视频输出设备(如电脑显卡、主板、机顶盒等)报告自身能力的一种数据结构标准,你可以把显示相关的配置(如分辨率)写入到EDID,RK628d的EDID是硬编码在代码的edid_init_data数组中的,如果需要修改,先将这串数组使用winhex转存成二进制文件,再用AW EDID Editor打开编辑即可,这地方涉及到显示的时序调整,不同分辨率,不同刷新率需要的时序都是有区别的,也是要根据面板慢慢测的,调整不对,花屏黑屏都是家常便饭,以下是我测得的一组可用的时序数据,EDID涉及到的内容太多了,这部分的内容下次有机会再详细说明吧。

最后,在发送mipi指令的过程中,我察觉到串口始终输出下面的字符:
[00:03:02.843]rk628_dsi: generic write payload fifo is full
[00:03:02.848]failed to write dcs cmd: -60
[00:03:02.883]rk628_dsi: generic write payload fifo is full
[00:03:02.888]failed to write dcs cmd: -60
[00:03:02.923]rk628_dsi: generic write payload fifo is full
[00:03:02.928]failed to write dcs cmd: -60
[00:03:02.963]rk628_dsi: generic write payload fifo is full
[00:03:02.968]failed to write dcs cmd: -60
[00:03:03.003]rk628_dsi: generic write payload fifo is full
[00:03:03.008]failed to write dcs cmd: -60
[00:03:03.053]rk628_dsi: generic write fifo is full. sts: 0x15
[00:03:03.058]failed to write dcs cmd: -60
这个东西坑了我很久的时间,让我总觉得是i2c部分的代码有问题,实际上mipi初始化指令已经成功发送到屏上了,这也是在一次无意的尝试中突然将屏点亮之后,我才确定了i2c部分是没有问题的,至于为什么一直提示这个报错还有待研究。
其实回头再看,关于i2c寄存器部分,文档中还是能找到部分寄存器的读出参考值的,只是在几十个文档,上百页内容中直接找到这部分不起眼的内容还是有点困难的,如果当时我能直接看到这里,能少走很多弯路的。

i2c共享
由于soc只有一个硬件i2c接口,rk628d和gt1151q挂载在同一个总线上(当然也可以使用软件i2c拓展,不过MCU一侧的io口已经不够用了,强行从另一侧引线绕路太远了),要保证两个设备的数据交互不出现冲突,则必须进行临界区加锁,但本来以为是很好解决的问题,但是实际情况是分出两个线程,一个负责触摸,一个负责显示,只要任意一个线程在访问i2c的时加锁,那么整个线程都会进入死锁,一开始我觉得可能是自己的代码编写的有问题,直到我不懈的调试,发现只开一个线程也会死锁,进一步观察到,只要加锁后,再调用ioctl,必然卡死,我就知道,这应该是系统底层的一些问题了,由于系统这部分是闭源的,我也没办法进一步查到在调用dev_ioctl发生了什么事(我怀疑是dev_ioctl这个操作又进行了一次加锁),只能换用第二种方法,通过任务队列消息进行线程间通信,但是这一条路也不是那么好走的,杰里线程间通信的api是os_taskq_pend相关函数,但是这个函数只能在os_api.h文件中有少量说明:
/* ----------------------------------------------------------------------------*/
/**
* @brief 发送任务队列消息
* @param[in] name: 消息队列所属任务名
* @param[in] type: 消息类型
* @param[in] argc: 消息个数
* @param[in] argv: 消息数组
* @return 0: 成功
* @return OS_TASK_NOT_EXIST: 任务不存在
* @return OS_ERR_POST_NULL_PTR: 任务消息队列不存在
* @return OS_Q_FULL: 任务消息队列已满
*/
/* ----------------------------------------------------------------------------*/
int __os_taskq_post(const char *name, int type, int argc, int *argv);
/* ----------------------------------------------------------------------------*/
/**
* @brief 接收任务队列消息
* @param[in] tick: 等待超时,时钟节拍为单位,取0不等待马上返回
* @param[in] argv: 可用消息数组
* @param[in] argc: 可用消息个数
* @return OS_TASKQ: 成功
* @return OS_Q_EMPTY: 任务消息队列为空
*/
/* ----------------------------------------------------------------------------*/
int __os_taskq_pend(int *argv, int argc, int tick);
/* ----------------------------------------------------------------------------*/
/**
* @brief 删除任务队列的指定某个消息
* @param[in] name: 消息队列所属任务名
* @param[in] type: 消息类型
* @param[in] argv: 之前发送的消息个数
* @param[in] msg: 之前发送的消息
* @return 0: 成功
* @return OS_TASK_NOT_EXIST: 任务不存在
* @return OS_ERR_POST_NULL_PTR: 任务消息队列不存在
*/
/* ----------------------------------------------------------------------------*/
int __os_taskq_del(const char *name, int type, int argc, int *msg);
/* ----------------------------------------------------------------------------*/
/**
* @brief 接收任务队列消息,无限等待
* @param[in] fmt: "taskq"
* @param[in] argv: 可用消息数组
* @param[in] argc: 可用消息个数
* @return OS_TASKQ: 成功
* @return OS_Q_EMPTY: 任务消息队列为空
*/
/* ----------------------------------------------------------------------------*/
int os_taskq_pend(const char *fmt, int *argv, int argc);
实测只能一个线程发,一个线程接收,如果需要双向通信则会变得非常麻烦,最终还是切换成了简单粗暴的共享内存方案,虽然说可能牺牲了点安全性和稳定性,但是应该影响不大,先跑起来再说了。
热插拔
上述都解决之后,最后需要完成的就是根据平台实现tx_5v_power_present函数了,这个函数是检查hdmi是否插入的,这个地方有很大的坑,原先我以为使用GPIO去读一下VCC5V_HDMIRX_PORT引脚,看是否有高电平即可,如果有高电平返回1,没有返回0,但事实上这里有两个坑
其一为漏电,原版的设计似乎有问题,官方似乎也意识到了这一点,可以在官方修改日志中找到修改的部分:

这个解决方案解决了一部分问题,但是并没有完全解决,如果从检测物理插入状态的角度来看,这样设计是没有问题的,理论上HDMI设备插入有5V进来,经过电阻分压后,Q5006导通,HDMI_DET电平会被拉低,实际情况因为各种HDMI接口设备的设计问题,某些HDMI设备在休眠的时候存在漏电,串电或者感应电,导致HDMIRX_5V始终会存在一个3.3v-5v的电压,这样会导致平时这些HDMI设备都没有问题,但是在休眠后重新点亮的过程中,由于检测不到HDMI_DET的状态改变,不能重新进入到HDMI握手过程导致点不亮,市面上挺多DIY便携屏休眠后不能唤醒的BUG可能问题就是出现在这里,我后续决定将这部分电路替换成光耦,应该能极大程度缓解这个问题。
其二为延迟,RK628d有个问题,RK628d检测HDMI频点,时钟以及握手的时间较长,且由于没有寄存器文档,导致不知道在错过HDMI插入信号后如何主动重新进行握手,所以只能是把握好时间,在HDMIRX_5V变化的特定窗口期进行握手,太快了不行,信号没稳定,没有进入主机的握手窗口,导致clock detected failed,太慢了同样会错过握手时间,实测需要像这样去读两次,每次延迟1ms,如果有一次成功,则进入后续握手流程,这样就更容易握手成功。
static int tx_5v_power_present(void)
{
bool ret;
int val, i, cnt;
cnt = 0;
for (i = 0; i 0)
cnt++;
mdelay(1);
}
ret = (cnt >= 1) ? 1 : 0;
//printf("%s: %d\n", __func__, ret);
return ret;
}
当然,如果能在握手失败的情况下主动重新握手是最好的,实测有些HDMI设备无论什么时候握手都可以,某些设备就只能上电的一瞬间进行握手,如果错过了,那就只能一直死循环了。
如果有哪位大神知道如何彻底解决这个问题,或者有这款芯片寄存器手册的能不能私下透露一下呢?
结语
由于这个项目涉及到的内容较多,一篇文章肯定说不完了,暂时先写到这里吧,本也同时因为内容较多,不可避免会有一些错误和遗漏,请各位大佬们批评指正。
下一篇文章继续分享USB协议栈部分,以及如何将读取到的触摸点数据传输到主机实现触摸驱动,以及多功能USB设备的配置。
后续补充
第二篇已发:
https://oshwhub.com/article/hdmimultifunctionslavedisplay-2
主要功能已完成,但是具有较多的bug,想要抢先体验,获取beta固件,参与mipi开发测试交流的可以来DC交流:
https://discord.gg/rUfe89Ycys
下面是部分界面截图展示:




2026.3.8 重要更新
新版上位机增加Vibe Coding,内部配置好了Opencode AI编程工具,能自动分析项目代码并实现自我编码,自我测试,自我升级和自我迭代,完全不懂代码的小白也能自己修bug,自行添加新功能,定制属于自己的上位机界面。目前该功能还处于初级阶段,根据不同电脑环境和不同AI大模型生成的质量可能有较大差异,但此功能应该是后续主力的开发方向。


2026.6.6 重要更新
- 补充HX8399屏幕驱动ic手册
- 由于TM055VDXP35屏幕缺货,当前项目迁移至:https://oshwhub.com/5473675a/project_rnkdtbtx
并兼容新版 H546DAN07 屏幕,旧版硬件软件上将继续兼容新版上位机,但是部分新版硬件的特性不被支持,目前已经将新版固件反向移植回旧版,固件我已经上传至附件。 - 上传了3d外壳文件,仅供参考,需要根据打印材料自行调整公差和优化结构强度
固件下载步骤
理论上打好板子,硬件焊接无问题的情况下,进入设备管理器的磁盘驱动器分支下应该会出现

这样的一个设备,这样基本说明你的板子焊接的没问题,可以开始下载固件。
当前上位机程序已经集成固件写入功能,无需杰理官方烧录工具,首先下载好sdk.elf固件,然后进入上位机的设置->更新->手动固件更新,按住SPI_FLASH上方的进入升级模式的按钮不放(如果你是空片,不按也会直接进入烧录模式),插入USB,选择之前下载的固件刷入即可。
需要注意的是,当前Type-C USB接口在烧录模式下是区分正反插的,如果出现识别错误导致烧录失败就换一面插,刷入的耗时较久,请耐心等待刷入成功的提示出现,不要提前关闭窗口。
当前项目已开源到GitHub,获取实时更新请访问:
https://github.com/git8129/PanelManager
设计图
未生成预览图,请在编辑器重新保存一次BOM
暂无BOM
克隆工程工程成员
知识产权声明&复刻说明
本项目为开源硬件项目,其相关的知识产权归创作者所有。创作者在本平台上传该硬件项目仅供平台用户用于学习交流及研究,不包括任何商业性使用,请勿用于商业售卖或其他盈利性的用途;如您认为本项目涉嫌侵犯了您的相关权益,请点击上方“侵权投诉”按钮,我们将按照嘉立创《侵权投诉与申诉规则》进行处理。
请在进行项目复刻时自行验证电路的可行性,并自行辨别该项目是否对您适用。您对复刻项目的任何后果负责,无论何种情况,本平台将不对您在复刻项目时,遇到的任何因开源项目电路设计问题所导致的直接、间接等损害负责。


评论