OpenHarmony HDF驱动实战:USB转串口芯片CH9344的HCS配置与内核适配详解

news2026/3/13 18:09:38
1. 从零开始理解CH9344在OpenHarmony HDF框架下的适配本质大家好我是老张一个在嵌入式圈子里摸爬滚打了十多年的老码农。最近在搞一个基于RK3568和OpenHarmony 4.0的工业网关项目板子上的原生串口根本不够用于是我们加了一颗CH9344芯片用USB扩展出几个串口来。本以为把Linux驱动往里一塞就完事了结果在OpenHarmony的HDF框架下着实踩了不少坑。今天我就把这些实战经验特别是HCS配置和内核适配的那些“魔鬼细节”掰开揉碎了跟大家聊聊。首先得搞清楚一个核心概念在OpenHarmony里HDF驱动框架到底扮演什么角色很多刚接触的朋友容易把它想得太复杂。其实对于像CH9344这样的USB转串口芯片HDF框架更像一个“中间人”或者“标准化接口层”。它本身不直接操作硬件而是对上应用层提供一套统一的、标准的API比如打开、读写、设置波特率对下则去调用已经存在于Linux内核中的原生驱动。我最初也犯过迷糊试图去重写CH9344的全部驱动逻辑后来仔细研读了uart_adapter.c的源码才发现HDF的串口驱动实现本质上就是通过标准的文件操作接口如open,read,write去访问/dev/tty*设备节点。所以我们的适配工作就可以简化为两个核心任务第一确保CH9344的驱动正确编译并加载到Linux内核中让系统能在/dev/目录下生成对应的设备节点比如ttyCH9344USB0。第二就是写好HCS配置文件告诉HDF框架“嘿这里有几个新串口它们的‘名字’和‘门牌号’是这样的你以后就按这个来管理。” 听起来很简单对吧但恰恰是第二步的HCS配置以及两者之间的衔接藏着许多让人头疼的坑。接下来我们就一步步来拆解。2. 内核基石将CH9344驱动稳稳地植入OpenHarmony内核驱动移植是基础这一步没做对后面全是白搭。我们拿到的CH9344驱动源码包通常是针对标准Linux内核的。OpenHarmony 4.0 Release版本的内核基于Linux 5.10所以兼容性一般没问题但放对地方、配对选项是关键。第一步放置源码。我个人的习惯是将驱动源码中关键的.c和.h文件复制到内核源码树的drivers/usb/serial/目录下。为什么放这里因为CH9344属于USB转串口设备归USB串口子系统管放在这里最符合内核的架构规范后续的Kconfig和Makefile修改也最方便。第二步修改Kconfig让内核“认识”它。你需要编辑drivers/usb/serial/Kconfig文件在里面添加CH9344的配置选项。这里有个小细节要注意tristate表示这个驱动可以编译成模块M也可以直接编译进内核Y。对于嵌入式系统我强烈建议直接选y编译进内核避免模块加载的麻烦。配置内容大致如下config USB_SERIAL_CH9344 tristate USB Winchiphead CH9344 Multi-Port Serial Driver help Say Y here if you want to use Winchiphead CH9344 USB to serial adapter. This driver supports multiple ports. To compile as a module, choose M.help里的描述写清楚点以后自己或同事看配置菜单时能一眼明白。第三步修改Makefile让编译系统“找到”它。编辑同目录下的Makefile添加一行将配置变量和我们的驱动文件关联起来obj-$(CONFIG_USB_SERIAL_CH9344) ch9344.o这意味着只有当CONFIG_USB_SERIAL_CH9344这个配置被设置为y或m时ch9344.o才会被加入编译列表。第四步配置内核并编译。进入你的OpenHarmony内核源码目录执行make menuconfig或你习惯的配置工具。依次找到Device Drivers-USB support-USB Serial Converter support在这里你应该能看到新添加的USB Winchiphead CH9344 Multi-Port Serial Driver选项果断按Y选中它。保存退出后再进行内核的完整编译。编译成功后烧录到板子上启动时用dmesg | grep ch9344看看有没有相关的加载成功日志再到/dev/目录下找找有没有ttyCH9344USB*这样的设备节点出现。如果看到了恭喜你最底层的一步已经稳了。3. 灵魂连接详解HCS配置文件的关键字段与匹配逻辑内核驱动好了设备节点也有了现在就需要HDF框架来接管它们。这就是HCS配置文件出场的时候了。HCS文件就像是给HDF框架的一张“设备地图”它按图索骥地去管理和操作硬件。配置错了框架就“找不到”你的设备。在OpenHarmony的标准设备配置中串口的HCS配置通常位于vendor/[你的厂商]/[你的产品名]/hdf_config/khdf/platform/目录下例如uart_config.hcs。我们需要做的不是新建一个文件而是在已有的串口配置基础上追加我们CH9344的设备信息。下面是一个针对CH9344扩展出的第一个串口的配置示例我们逐行分析每个字段的“潜规则”uart :: host { hostName uart_host; priority 56; device_uart_ch9344 :: device { device0 :: deviceNode { policy 2; // 发布服务给内核态和用户态 priority 100; // 驱动启动优先级 moduleName HDF_PLATFORM_UART; // 固定使用HDF平台UART驱动模块 serviceName HDF_PLATFORM_UART_5; // **关键服务名决定port编号** deviceMatchAttr hisilicon_hi35xx_uart_5; // **关键必须与私有属性匹配** } } } // 这是另一个独立的hcs文件通常叫 uart_private.hcs定义私有属性 platform { uart_controller_5 :: serial_controller { match_attr hisilicon_hi35xx_uart_5; // 与上面的deviceMatchAttr一致 driver_name ttyCH9344USB; // **关键内核中注册的设备名前缀** num 0; // **关键端口号与driver_name组成完整设备名** ... // 其他串口参数如波特率、数据位等可选通常应用层设置 } }几个踩坑无数的关键点serviceName与port的映射关系这是第一个大坑。在应用层调用UartOpen函数时需要传入一个port参数。这个port数字从哪里来就是从serviceName里解析出来的HDF框架的串口驱动源码里会解析serviceName字符串提取最后一个下划线后面的数字。在我的例子中serviceName HDF_PLATFORM_UART_5那么应用层需要打开的port就是5。如果你配置成UART_6port就填6。这个数字本身没有硬件含义只是一个HDF内部的逻辑编号但必须和配置对应上。deviceMatchAttr与match_attr的配对这是第二个大坑。deviceMatchAttr是设备节点声明的“我要找谁”而match_attr是私有配置块声明的“我是谁”。这两个字符串必须完全一致HDF框架才能成功将设备节点和具体的硬件配置信息绑定起来。这里就像一把钥匙开一把锁配错了配置就失效了。driver_name与num的组合这是第三个也是最容易出错的地方。driver_name不是随便写的它必须是你的内核驱动在/dev/目录下创建的设备节点的前缀。CH9344驱动默认创建的名字像ttyCH9344USB0那么前缀就是ttyCH9344USB。num就是设备的序号0表示第一个端口。HDF驱动内部会拼接这两个值形成/dev/ttyCH9344USB0这样的完整路径然后去调用open系统调用。如果拼出来的名字和/dev/下的实际节点名字对不上打开设备就会失败。4. 避坑指南典型问题排查与源码级修复实战配置写好了但事情往往没那么顺利。下面是我在实际调试中遇到的几个典型问题及其排查解决思路有些甚至需要动到HDF驱动源码。4.1 HCS配置后毫无反应驱动未加载现象修改HCS文件后重新编译系统并烧录内核启动日志里完全看不到HDF串口驱动加载CH9344设备的任何信息。排查首先怀疑HCS没生效。OpenHarmony的构建系统会将HCS文本文件编译成二进制的HCB文件。有时候如果之前已经存在HCB文件构建系统可能不会重新编译新的HCS。解决方案是在编译前手动删除out目录下对应产品的旧HCB文件如uart_config.hcb或者直接执行./build.sh --product-name rk3568 --target make_hcs命令强制重新生成HCB。清理后再次全量编译问题通常就能解决。4.2 应用层能UartOpen但返回失败或打开错误设备现象应用层调用UartOpen(5, dev)假设port是5失败或者返回成功但后续操作异常。排查检查port号确认传入的port数字是否与HCS中serviceName末尾的数字一致。深入驱动内部打日志这是最有效的调试手段。修改drivers/hdf_core/adapter/khdf/linux/platform/uart/uart_adapter.c中的UartHostOpen函数在它拼接设备路径的地方添加打印HDF_LOGI(UartHostOpen: driver_name%s, num%d, final path%s%s%d, driverName, num, /dev/, driverName, num);重新编译内核并运行查看日志。我就曾经在这里发现一个诡异的问题日志打印出来的路径是/dev/ttySH9344USB1而实际设备节点是/dev/ttyCH9344USB1。第一个字母‘C’变成了‘S’根源与修复追踪源码发现HDF串口驱动里为了兼容不同平台使用了一个全局的g_serialDevice数组来映射driver_name。但这里的设计存在一个逻辑缺陷它假设一种驱动类型只有一个driver_name。然而对于CH9344我们配置的driver_name是ttyCH9344USB但驱动内部可能从某个统一的地方获取了一个错误的默认前缀。这需要根据你的具体代码版本进行定位。修复方法是确保在解析HCS配置时将driver_name属性值正确地传递并赋值给打开设备时使用的变量而不是被全局数组覆盖。具体修改涉及uart_adapter.c中设备打开路径的生成逻辑需要仔细对照你的代码版本进行调整。4.3 设置阻塞Blocking模式无效现象调用UartSetAttribute设置阻塞模式后读数据依然立即返回无法实现阻塞等待。排查查看uart_adapter.c中的UartHostSetAttribute函数实现。在某些早期版本中你可能发现设置UART_ATTR_PARAM_BLOCK_MODE的代码只是一个空壳或者伪实现并没有真正调用fcntl去设置文件描述符的O_NONBLOCK标志。修复需要在UartHostSetAttribute函数中找到设置阻塞模式的分支添加实际的fcntl调用逻辑。例如case UART_ATTR_PARAM_BLOCK_MODE: { int flags fcntl(host-fd, F_GETFL, 0); if (attr-blockMode UART_BLOCK_MODE_NONE) { flags | O_NONBLOCK; // 非阻塞 } else { flags ~O_NONBLOCK; // 阻塞 } ret fcntl(host-fd, F_SETFL, flags); } break;确保host-fd是已经打开的设备文件描述符。4.4 串口能发送数据但无法接收现象写入数据正常但读取函数始终返回0收不到任何数据。排查这个问题通常出现在驱动底层对文件描述符的初始化配置上。检查uart_adapter.c中打开设备文件后的初始化部分特别是open函数调用时的标志位。对于串口设备除了O_RDWR有时可能需要特定的标志才能正确触发中断接收。修复在我遇到的案例中问题出在UartHostOpen函数里调用open时缺少了必要的标志。原始的open调用可能只是open(path, O_RDWR)。对于需要可靠读取的串口特别是USB转串口可能需要修改为host-fd open(path, O_RDWR | O_NOCTTY | O_NDELAY); // 或 O_NONBLOCK视情况而定然后在打开后可能需要通过tcgetattr和tcsetattr进一步配置终端属性。关键是要确保文件描述符的读写模式设置正确能够接收底层驱动上报的数据。4.5 接收逻辑的潜在死循环风险现象在阻塞模式下偶尔会出现系统卡死内核日志无响应。排查仔细审查uart_adapter.c中数据读取的函数例如UartHostRead。我发现一个危险的循环逻辑它试图在一个循环里读取指定长度的数据直到读满或出错。但循环条件判断可能有问题。风险代码示例while (remainingSize 0) { ret read(host-fd, buffer, remainingSize); if (ret 0) { // 错误处理... break; // 必须要有break } buffer ret; remainingSize - ret; }如果是在非阻塞模式下read可能立即返回0或EAGAIN循环会快速退出。但在阻塞模式下如果对端一直不发送数据read调用会一直阻塞这本身是符合预期的。但问题在于如果驱动实现有BUG在某种错误条件下read返回0表示EOF但循环条件判断不当就可能变成while(1)的死循环。修复的关键在于确保循环退出条件严密对所有read的返回值正数、0、负数错误码都有明确的处理逻辑确保在任何情况下都不会陷入无法退出的循环。通常需要检查ret 0的情况并将其视为连接已关闭或超时从而跳出循环。5. 效果验证与调试心得当所有配置和修复都完成后就是验证成果的时刻了。首先系统启动后通过cat /proc/devices或ls /dev/tty*确认ttyCH9344USB0等设备节点存在。然后查看内核启动日志dmesg | grep -i hdf.*uart\|ch9344应该能看到HDF框架成功绑定设备的信息。在应用层编写一个简单的测试程序循环打开port 5对应你的配置设置波特率如115200、数据位8、停止位1、无校验然后先发送一串数据再尝试接收。可以用一个USB转串口模块将CH9344的一个端口与电脑连接用串口调试助手进行双向收发测试。当你在开发板上发送的数据能在电脑端显示电脑端发送的数据也能被开发板正确读取时就大功告成了。回顾整个适配过程我的最大体会是在OpenHarmony HDF框架下做外设驱动适配三分在驱动本身七分在配置和框架理解。HCS文件是连接硬件和HDF服务的桥梁每一个字段都至关重要必须准确理解其含义。而调试时不要怕深入源码在关键函数添加打印信息是定位问题最快的方法。嵌入式开发就是这样很多时候没有现成的答案需要你带着逻辑思维一层层地剖析框架和代码最终解决问题的成就感也是这份工作最大的乐趣所在。希望我的这些踩坑经验能帮你少走些弯路。如果在实际操作中遇到新的问题不妨从HCS匹配和设备节点路径这两个最核心的点入手排查祝你好运

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2408409.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SpringBoot-17-MyBatis动态SQL标签之常用标签

文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…

wordpress后台更新后 前端没变化的解决方法

使用siteground主机的wordpress网站,会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后,网站没有变化的情况。 不熟悉siteground主机的新手,遇到这个问题,就很抓狂,明明是哪都没操作错误&#x…

网络编程(Modbus进阶)

思维导图 Modbus RTU(先学一点理论) 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议,由 Modicon 公司(现施耐德电气)于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…

UE5 学习系列(二)用户操作界面及介绍

这篇博客是 UE5 学习系列博客的第二篇,在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下: 【Note】:如果你已经完成安装等操作,可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作,重…

IDEA运行Tomcat出现乱码问题解决汇总

最近正值期末周,有很多同学在写期末Java web作业时,运行tomcat出现乱码问题,经过多次解决与研究,我做了如下整理: 原因: IDEA本身编码与tomcat的编码与Windows编码不同导致,Windows 系统控制台…

利用最小二乘法找圆心和半径

#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式

一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明&#xff1a;假设每台服务器已…

XML Group端口详解

在XML数据映射过程中&#xff0c;经常需要对数据进行分组聚合操作。例如&#xff0c;当处理包含多个物料明细的XML文件时&#xff0c;可能需要将相同物料号的明细归为一组&#xff0c;或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码&#xff0c;增加了开…

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造&#xff0c;完美适配AGV和无人叉车。同时&#xff0c;集成以太网与语音合成技术&#xff0c;为各类高级系统&#xff08;如MES、调度系统、库位管理、立库等&#xff09;提供高效便捷的语音交互体验。 L…

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)

题目&#xff1a;3442. 奇偶频次间的最大差值 I 思路 &#xff1a;哈希&#xff0c;时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况&#xff0c;哈希表这里用数组即可实现。 C版本&#xff1a; class Solution { public:int maxDifference(string s) {int a[26]…

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型

摘要 拍照搜题系统采用“三层管道&#xff08;多模态 OCR → 语义检索 → 答案渲染&#xff09;、两级检索&#xff08;倒排 BM25 向量 HNSW&#xff09;并以大语言模型兜底”的整体框架&#xff1a; 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后&#xff0c;分别用…

【Axure高保真原型】引导弹窗

今天和大家中分享引导弹窗的原型模板&#xff0c;载入页面后&#xff0c;会显示引导弹窗&#xff0c;适用于引导用户使用页面&#xff0c;点击完成后&#xff0c;会显示下一个引导弹窗&#xff0c;直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…

接口测试中缓存处理策略

在接口测试中&#xff0c;缓存处理策略是一个关键环节&#xff0c;直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性&#xff0c;避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明&#xff1a; 一、缓存处理的核…

龙虎榜——20250610

上证指数放量收阴线&#xff0c;个股多数下跌&#xff0c;盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型&#xff0c;指数短线有调整的需求&#xff0c;大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的&#xff1a;御银股份、雄帝科技 驱动…

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析

1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具&#xff0c;该工具基于TUN接口实现其功能&#xff0c;利用反向TCP/TLS连接建立一条隐蔽的通信信道&#xff0c;支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式&#xff0c;适应复杂网…

铭豹扩展坞 USB转网口 突然无法识别解决方法

当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…

未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?

编辑&#xff1a;陈萍萍的公主一点人工一点智能 未来机器人的大脑&#xff1a;如何用神经网络模拟器实现更智能的决策&#xff1f;RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战&#xff0c;在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…

Linux应用开发之网络套接字编程(实例篇)

服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …

华为云AI开发平台ModelArts

华为云ModelArts&#xff1a;重塑AI开发流程的“智能引擎”与“创新加速器”&#xff01; 在人工智能浪潮席卷全球的2025年&#xff0c;企业拥抱AI的意愿空前高涨&#xff0c;但技术门槛高、流程复杂、资源投入巨大的现实&#xff0c;却让许多创新构想止步于实验室。数据科学家…

深度学习在微纳光子学中的应用

深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向&#xff1a; 逆向设计 通过神经网络快速预测微纳结构的光学响应&#xff0c;替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…