轻AI越影视觉开发板出厂固件开箱:显示/触摸/AI检测全链路体验

一、与Hi3519DV500、RK3588怎么选——定位对比

开箱前先回答一个常被问的问题:同为国产视觉AI开发板,这块板子和Hi3519DV500、RK3588(LubanCat5-V2)是什么关系?一句话——不是同档位竞品,是三条不同的产品定位。

  • 维度轻AI越影视觉开发板Hi3519DV500RK3588(LubanCat5-V2)
    定位轻智能消费终端(低成本视觉+语音+触控)超高清智慧视觉SoC(专业IPC/安防)高性能边缘计算/ARM PC级SBC
    CPUARMv7 双核@950MHzARMv8 双核A55ARMv8 4×A76+4×A55 八核(NEON)
    AI算力1TOPS NPU~2.5TOPS NPU6TOPS NPU(INT4~FP16)
    内存/存储128MB DDR3L + 256MB NANDDDR4/LPDDR4/4X接口(GB级)+eMMCLPDDR4X 4~16GB + eMMC 32~128GB
    视频能力4K@20解码 / 6M@30编码4K@30编解码8K@60解码 / 8K@30编码
    显示输出SPI小屏DRM(标配2.8寸触控屏,可换)单路MIPI TX(无HDMI)HDMI2.1×2+MIPI DSI×2,多屏异显
    摄像头2×MIPI CSI 2-Lane(送OS04D10 4MP)MIPI CSI(专业ISP管线)6×MIPI CSI
    无线WS73星闪扩展板:WiFi+BLE+SLE 三协议可外接星闪模组或内置(如虹鸥派就内置了)WiFi/BT需mini-PCIe或4G模块
    有线百兆网口千兆GMAC千兆自适应
    系统/SDKhi_aiot_solution组件化SDK(musl+Linux5.10),出厂六合一demo即跑海思MPP/SVP专业SDK,ISP工具链重,门槛高瑞芯微SDK+rknn-toolkit2,生态最成熟
    适合场景AIoT轻终端:视觉门铃/猫眼/陪伴机器人/触控小屏设备专业安防摄像机、多路高清视频分析边缘AI盒子、桌面小主机、机器人主控

上手体感差异

  • RK3588 是"小电脑":八核+Mali-G610 GPU+6T算力+全接口(HDMI×3/USB3/mini-PCIe),跑桌面系统都够,代价是12V供电+风扇和复杂度;当算力中枢合适,跑轻终端属于杀鸡用牛刀。
  • Hi3519DV500 是"专业摄像机芯":ISP画质管线与安防生态是强项,但单VO无HDMI、SDK门槛高,更适合有ISP调优能力的团队做产品。
  • 轻AI越影 是"开箱即用的轻智能终端":算力/内存只有前两者的零头,但出厂固件就把"摄像头采集+H.265编码+RTSP+触控UI+BLE配网+AI Agent"六合一跑起来了,还附送了别家没有的星闪WS73三协议——本文接下来的全部内容,都是这盘出厂固件的实测记录。

二、概述

4块板:主板 + WS73扩展板 + OS04D10摄像头 + 2.8寸SPI屏(+线材/亚克力)。

  • 部件规格
    主板A7双核950MHz、128MB DDR3L、256MB NAND、1T NPU、4K@20、6M@30编码
    接口:三个Type-C(POWER供电/Debug串口/USB2.0通信兼供电)、两路MIPI CSI 2-Lane(Sensor0背面/Sensor1正面)、40PIN排针、百兆网口、TF卡槽、RTC电池接口、SPI、2×SDIO、2×I2C、1×UART、2路模拟硅麦+喇叭接口+音频回采、复位/升级按键、电源灯、2位DIP拨码(丝印SW1)
    WS73扩展板插40PIN排母(不是SDIO专用座!)、板载ES7210 ADC+两路模拟麦+Type-C/UART/按键/LCD FPC座
    摄像头OS04D10 4MP、MIPI 2-Lane、定焦+IRCUT、默认接背面Sensor0,正面Sensor1留给双摄;
    上双摄时另一颗接Sensor1,拨码1保持OFF、拨码2拨到ON。
    ON屏×2.8寸方屏SPI;同一接口板兼容2.1寸圆屏/1.28寸双圆屏
    • 拨码机制

      • 拨码1拨码2得到屏
        OFFOFF场景一:双屏+单摄+WiFi+UART双屏
        OFFON场景二:单屏+双摄+WiFi+UART单屏
        ONOFF(官方没列):TF卡+单摄+WiFi+UART无屏
        ONON场景三:TF卡+双摄+WiFi+UART无屏
    • 硬件连接

      • 1.WS73排母对准排针垂直压入
        2.屏FPC插扩展板LCD座
        3.网线插入网口
        4.摄像头FPC插背面Sensor0
        5.背面喇叭接线、插tf卡
        6.TypeC-DEBUG接调试串口
        7.TypeC-POWER接电源
        8.拨动拨码开关至ON上电
        

三、连接与烧录部署

VMware的安装与环境搭建(略)

1.串口/SSH连接

  • 串口连接调试

    • 连接:Debug线连接PC(CH343P驱动,设备管理器出COM口)
    • 串口配置:波特率115200 8N1无流控 镜像root空密码
  • SSH连接调试:连上串口调整

    • 网口直连或者通过交换机连接时

      此例使用局域网电脑+交换机的网口

      # 1.临时生效(重启会丢)
      ifconfig eth0 192.168.1.221 netmask 255.255.255.0 up
      route add default gw 192.168.1.1
      # 验证:ifconfig eth0 看 inet addr
      
      # 2.持久化(改开机脚本,本镜像就是这么做的)
      vi /etc/init.d/S80network
      ipaddr=192.168.1.221   # 这三行改成你的值
      gateway=192.168.1.1
      netmask=255.255.255.0
      autoconf=no        ← 关键,关掉DHCP
      bootp=no
      # 改完 chmod +x /etc/init.d/S80network保险
      
      # 3.防DHCP兜底抢占(S90ws73_lcd的逻辑:eth0有IP就跳过udhcpc)
      vi /etc/init.d/S90ws73_lcd
      /root/set_eth_mac.sh          # 固化MAC(否则每次开机随机→DHCP租约漂移)
      ifconfig eth0 up
      if ! ifconfig eth0 | grep -q "inet addr"; then   # ← 关键判断
          /root/eth_dhcp_monitor.sh eth0 &             # 只有eth0没IP才起DHCP监控
      fi
      
      # 4.DNS(S90里已写114.114.114.114+8.8.8.8,确认在)
      cat /etc/resolv.conf
      
      # 5.重启验证
      reboot   # 起来后 ifconfig eth0 应仍是 192.168.1.221,不再漂移
      
      # ---------- VM侧(可选,仅当VM是NAT模式时需要)----------
      # 此场景下板子/PC/VM同处192.168.1.x局域网,VM默认即可直连板子。
      # 若VM用NAT模式(VMnet8,IP在别的网段)→ 改桥接模式:
      #   虚拟机设置 → 网络适配器 → 桥接到物理网卡
      #   或VM内加:ip route add 192.168.1.0/24 via <宿主机IP>
      
    • USB拓展坞网口连接时

      此例使用自己的电脑+USB拓展坞上的网口

      # 拓扑:
        板子(192.168.110.221) ─拓展坞网口─ PC(192.168.110.208)
                                            └ WLAN(192.168.124.119) ─路由器─ 外网
        VM:  ens33=192.168.124.220 (VMnet0→WLAN,外网用)
             ens37=192.168.110.220 (VMnet2→拓展坞网卡,板子用)
      
      # 1.VMware(GUI操作,只做一次)
      # 虚拟网络编辑器(管理员):
          - VMnet0: 桥接 → Intel Wi-Fi(已有,不动)
          - 新建 VMnet2: 桥接 → Realtek USB FE Family Controller(拓展坞网卡)
      # 虚拟机设置 → 添加 → 网络适配器 → 自定义选VMnet2 → VM内出现ens37
      # (若用过Windows网桥,ncpa.cpl里删掉,会顶掉VMware桥接)
      
      # 2.VM侧(Ubuntu22.04, netplan永久配置)
      # 文件: /etc/netplan/01-network-manager-all.yaml
      cat << 'EOF' | sudo tee /etc/netplan/01-network-manager-all.yaml
      network:
        version: 2
        renderer: networkd
        ethernets:
          ens33:
            dhcp4: false
            addresses: [192.168.124.220/24]
            routes:
              - to: default
                via: 192.168.124.1
            nameservers:
              addresses: [8.8.8.8, 114.114.114.114]
          ens37:
            dhcp4: false
            addresses: [192.168.110.220/24]
      EOF
      sudo netplan apply
      ip addr                       # 确认 ens33=.124.220, ens37=.110.220
      
      # 3.板子侧(串口,改S80network持久化)
      # 先 cat /etc/init.d/S80network 看原脚本写法,本板是变量+ifconfig风格:
      ipaddr=192.168.110.221
      gateway=192.168.110.208     # ← 网关指PC(板子要能回程到VM/PC)
      netmask=255.255.255.0
      autoconf=no
      bootp=no
      # 注意: .110网段无DHCP服务器,必须静态;udhcpc拿不到地址。
      #       改完reboot生效。
      
      # 4.临时调试用法(板子串口,不写文件)
      ip link set eth0 up
      ip addr add 192.168.110.221/24 dev eth0
      ip route add default via 192.168.110.208
      
      # 5.验证
      # 板子:
      ping 192.168.110.208          # → PC
      ping 192.168.110.220          # → VM
      # VM:
      ping 192.168.110.221          # → 板子
      ssh nancy@192.168.124.220     # PC→VM (走124网段)
      # 板子上外网: 默认不通(.110无NAT),需要时再在PC上加转发/NAT
      

2.编译烧录

1.环境构建

  • # ============================================================
    # 环境:Windows/WSL2 或 VMware VM 编译机 + 轻AI越影视觉开发板
    # 覆盖:依赖安装 → 拉源码 → 工具链 → 编译 → 产物校验 → 烧录/热部署
    # ============================================================
    
    # 1.系统依赖(Ubuntu 22.04,约1-2GB)
    export DEBIAN_FRONTEND=noninteractive
    sudo apt-get update
    sudo apt-get install -y \
        apt-utils make libc6-i386 lib32z1 lib32stdc++6 \
        zlib1g-dev liblzo2-dev rename pigz \
        libncurses5-dev libncursesw5-dev ncurses-term \
        ffmpeg autopoint g++ u-boot-tools texinfo gawk \
        libssl-dev openssl bc p7zip-full gperf \
        bison flex diffutils git git-lfs openssh-client unzip \
        libffi-dev libtool libfreetype6 dos2unix \
        uuid-dev pkg-config automake texlive unrar \
        vim sudo curl wget po4a fakeroot \
        python3-pip cmake ninja-build meson \
        libmpc-dev picocom net-tools iputils-ping \
        device-tree-compiler mtd-utils \
        python3-gi python3-dbus gir1.2-glib-2.0
    sudo apt-get clean
    git lfs install --system
    # texlive 可去掉;缺包的错往往延迟几十行才爆(openpyxl→mv报错、meson→libdrm失败),
    # 看日志找第一处 Traceback,别被最后表象带偏
    
    # 2.repo + 拉源码
    mkdir -p ~/bin
    curl -L https://raw.gitcode.com/gitcode-dev/repo/raw/main/repo-py3 -o ~/bin/repo
    chmod a+x ~/bin/repo
    pip3 install -i https://repo.huaweicloud.com/repository/pypi/simple requests
    echo 'export PATH=$HOME/bin:$PATH' >> ~/.bashrc && source ~/.bashrc
    # repo init 卡住时换镜像:
    #   export REPO_URL='https://mirrors.tuna.tsinghua.edu.cn/git/git-repo'
    
    mkdir -p ~/demb && cd ~/demb
    repo init -u https://gitcode.com/HiSpark/hi_aiot_solution_manifest.git \
      -b main -m chipsets/demb/boards/ev_board.xml -g linux
    repo sync -c -j8
    repo manifest -r -o manifest-pinned.xml   # 锁版本留档,复现以这份为准
    # 工作树约4.3GB + .repo约2.8GB,预留30GB磁盘
    
    pip3 install -q -i https://repo.huaweicloud.com/repository/pypi/simple \
        wheel pycryptodome pyelftools cryptography kconfiglib requests \
        openpyxl pdfplumber
    
    # 3.交叉工具链(最大坑:.tgz是LFS指针)
    cd ~/demb/hi_aiot_solution/sdk/demb
    ls -l prebuilts/gcc-10.3-arm-musl-x86-linux-26.06.1-codesize.tgz
    file prebuilts/*.tgz        # 133字节=ASCII指针;真包≈88MiB(gzip)
    git lfs install --local
    git lfs pull --include="prebuilts/*.tgz"
    ls -lh prebuilts/*.tgz      # 应≈88M,file 变 gzip compressed data
    mkdir -p ~/toolchains
    tar -xzf prebuilts/gcc-10.3-arm-musl-x86-linux-26.06.1-codesize.tgz -C ~/toolchains
    
    # 关键路径:
    #   ~/toolchains/gcc-10.3-arm-musl-x86-linux-26.06.1/arm-v01c02-linux-musleabi-gcc/bin/
    #   └── arm-v01c02-linux-musleabi-gcc  (GCC 10.3.0, musl-1.2.3)
    # ⚠️ SDK预编译库按musl构建,别用arm-linux-gnueabihf那套glibc工具链,链接必炸
    

2.编译

  • # PATH三件套缺一不可(非交互ssh尤其):工具链bin + cmake + repo
    export PATH=$HOME/toolchains/gcc-10.3-arm-musl-x86-linux-26.06.1/arm-v01c02-linux-musleabi-gcc/bin:$HOME/miniconda3/bin:$HOME/bin:$PATH
    cd ~/demb/hi_aiot_solution
    
    # 完整镜像(framework_media,含BSP/内核/rootfs打包):
    set -o pipefail    # 必加!否则 | tee 会把失败退出码吞成0
    bash scripts/build.sh build --target demb_ev_board samples framework_media \
      2>&1 | tee ~/demb/build-framework_media.log
    
    # 应用级迭代(只编目标二进制,跳过全量)——日常开发用这个:
    bash scripts/build.sh build --target demb_ev_board references factory_demo/ws73_lcd
    cd _build && make factory_demo_main
    # 产物:_build/bin/factory_demo_main
    
    # 产物校验
    # 完整镜像:_build/install/image/framework_media/(约124MB,ubifs+jffs2+env+uImage)
    du -sh _build/install/image/framework_media/
    sha256sum _build/install/image/framework_media/* > artifacts.sha256  # 留档
    

3.烧录镜像/部署程序

  • 文档路径内容
    burn.sh使用文档hi_aiot_solution\sdk\demb\tools\burn\burn.sh使用文档.md(若不在此路径,tools\burn\下找.md)脚本烧录参数、TFTP配置、前置依赖
    BurnTool文档hi_aiot_solution\sdk\demb\docs\zh-CN\tools\BurnTool.mdToolPlatform操作:选芯片→加载*_burn_table.xml→按分区烧
    工具包tools\ToolPlatform\ToolPlatform-CAM-5.7.14-win32-x86_64.zipWindows端烧录工具本体
  • 首次烧录整机镜像 → BurnTool(ToolPlatform)

  • 日常重复烧录/批量 → tools/burn/burn.sh

  • 只改应用代码 → 热部署(不用烧录)

    ## 1.烧录镜像(换镜像/分区布局时)
    # 官方三通道:
    #   tools/burn/burn.sh    —— 正常态,串口进U-Boot+TFTP拉镜像+按烧录表写NAND
    #   BurnTool(ToolPlatform) —— 砖机/空片救援,串口直打ROM Boot不依赖U-Boot
    #   U-Boot手烧单分区      —— 开发期 tftp xxx.bin → nand write
    # ⚠️ nand_env.txt是分区唯一事实源(mkenvimage+env2burn.py同源生成);
    #    分区尺寸按案例变(base=251M rootfs vs ble_wifi=64M),换案例先核对烧录表
    # ⚠️ 本板SPI NAND是2K page/128K block,选 *_2k_128k_* 那套,别选4k_256k
    
    ## 2.热部署程序
    # 传二进制:编译机跑 scp _build/bin/factory_demo_main root@192.168.1.221:/root/factory_demo_main.new
    #          (或 Xftp/拖拽传好后),板端(Xshell)执行:
    killall factory_demo_main; sleep 3              # SIGTERM停旧进程
    chmod +x /root/factory_demo_main.new
    nohup sh -c "/root/factory_demo_main.new > /root/fd.log 2>&1; echo EXITED rc=\$? >> /root/fd.log" > /dev/null 2>&1 &
    
    # ⚠️ 板端注意:
    #   - 停进程用SIGTERM(killall默认),kill -9会弄脏MPP/sensor状态→下次起不来只能reboot
    #   - wrapper写EXITED rc=到日志:rc=139=SIGSEGV,rc=251=初始化失败退出
    #   - 双镜像切换:/usr/bin/bootsel lcd|tf(刷mtd2+sha校验+reboot约40s)
    #   - mtd2单分区备份/回滚:/root/img/mtdflash /dev/mtd2 /tmp/mtd2.bak
    

四、出厂功能测试

显示·触摸·影像三链路初步测试

场景:ws73_lcd(sensor+LCD+RTSP合并案例)| 板端Xshell直跑

  • ws73_lcd是sensor+LCD+RTSP合并案例——不插Sensor0,应用VI初始化失败退出→屏亮几秒后灭。触摸独立(i2c-1)不受影响。
  • 连接示意图image-20261102163653820

连接完成后,查看状态

  1. LCD(屏亮+DRM节点)

    • ls -l /dev/dri/
      #   crw------- 1 root root 226,0 card0       ← DRM注册成功
      cat /sys/class/drm/*/status
      #   connected                                ← 面板在线(应用接管后)
      dmesg | grep -iE "jd9853|panel|drm"
      #   [drm] Initialized jd9853 1.0.0 for spi0.0
      #   jd9853 spi0.0: JD9853 panel probe done, 240x320 rotation=0
      lsmod | grep jd9853                    # jd9853 16384 1 驱动在
      ps | grep factory                      # factory_demo_main 驻留=UI在渲染
      cat /sys/class/drm/card0-*/modes       # 240x320
      
      #2.触摸(event0坐标输出)
      cat /proc/bus/input/devices   # 应见 "hyn_ts" → Handlers=event0
      /root/tsread                  # 无evtest,hexdump不可用,编写程序监测触摸事件
      
      
      #3.Sensor(摄像头→VI通路)
      dmesg | grep -iE "sensor_cfg|os04d10"
      #   sensor_cfg,439: ==========sensor0: os04d10==========
      ps | grep -E "factory|sdk_server" | grep -v grep
      #   1041 root  /root/sdk_server        ← MPP UDS守护
      #   1063 root  /root/factory_demo_main ← 演示应用驻留=VI初始化已过
      cat /proc/umap/vi | grep -A3 "pipe status"
      #   pipe_id  enable  width  height  int_cnt  send_cnt  frame_rate
      #        0       Y    2560    1440    52089     46022          25
      #   ↑ 真在采数:int_cnt/send_cnt持续增长,25fps
      netstat -tln | grep 554
      #   tcp  0  0.0.0.0:554  LISTEN   ← RTSP推流端就绪
      #   PC端VLC拉 rtsp://192.168.1.221:554/livestream/0 出画面=全链最强证据
      
  2. 触摸(event0坐标输出)

    • cat /proc/bus/input/devices
      #   N: Name="hyn_ts"  H: Handlers=event0    ← 触摸注册成功
      #   B: ABS=6658000 3                        ← 带ABS_MT_POSITION_X/Y
      /root/tsread                                # evdev监测器(无evtest时自写,源码附后)
      #   划屏输出:[DOWN] X=120 Y=160 ... [UP]
      
      #include <stdio.h>
      #include <fcntl.h>
      #include <unistd.h>
      #include <linux/input.h>
      int main(int argc, char**argv){
          const char *dev = argc>1?argv[1]:"/dev/input/event0";
          int fd=open(dev,O_RDONLY); if(fd<0){perror(dev);return 1;}
          struct input_event ev; int x=-1,y=-1;
          printf("reading %s ... touch the screen (Ctrl-C quit)\n",dev);
          while(read(fd,&ev,sizeof(ev))==sizeof(ev)){
              if(ev.type==EV_ABS){
                  if(ev.code==ABS_MT_POSITION_X){x=ev.value;printf("X=%d ",x);}
                  else if(ev.code==ABS_MT_POSITION_Y){y=ev.value;printf("Y=%d ",y);}
                  else if(ev.code==ABS_MT_TRACKING_ID&&ev.value<0)printf("[UP]\n");
              } else if(ev.type==EV_KEY&&ev.code==BTN_TOUCH)
                  printf("%s ",ev.value?"[DOWN]":"[UP]");
              else if(ev.type==EV_SYN)fflush(stdout);
          }
          perror("read"); return 2;
      }
      

      板端hexdump/od读/dev/input/eventN会报Invalid argument——busybox对evdev字符设备不适用。

  3. Sensor(摄像头→VI通路)

    •  dmesg | grep -iE "sensor_cfg|os04d10"
       #   sensor_cfg,439: ==========sensor0: os04d10==========
       ps | grep -E "factory|sdk_server" | grep -v grep
       #   1027 /root/sdk_server      ← MPP UDS守护
       #   1050 /root/factory_demo_main ← 驻留=VI初始化通过
       cat /proc/umap/vi | grep -A3 "pipe status"
       #   pipe_id enable width height int_cnt send_cnt frame_rate
       #        0      Y   2560   1440   33318    33317          30   ← 30fps实采
       netstat -tln | grep 554
       #   tcp 0.0.0.0:554 LISTEN
       #   PC端VLC拉 rtsp://192.168.1.221:554/livestream/0 = 端到端最强证据
       
       ls -l /tmp/osal_uds_server.sock    # sdk_server的UDS桥——sock在=应用可调MPP
      
      •  # -sensor0 是"选sensor0口"(背面FPC座),不是型号选择;
         # 型号由mpp配置写死os04d10。双摄要插Sensor1座+拨码2-ON。
        

五、Sample实战

1.factory_demo_main

默认就是这个

factory_demo_main(ws73_lcd出厂演示):单进程六合一整机演示——摄像头采集+H.265编码+RTSP点播、SPI屏 LVGL 9页触控UI、BLE手机配网、ZeroClaw AI Agent(NPU检测+拍照技能)、网络自愈(DHCP+NTP)。

image-20261102164536371

2.square_lcd_sample

square_lcd_sample:一个四页 LVGL 演示程序——主屏显示摄像头实时预览,支持触控切换 亮度调节/摄像头控制/倒计时 三个功能页。

1.编译部署

  • #环境准备
    (1)开发板(检查即可,不用敲命令)
    1.Sensor0摄像头已插(背面FPC触点朝下)——没插=屏亮几秒灭+应用起不来
    2.WS73扩展板插在40PIN上、屏FPC插在扩展板LCD座
    3.板已刷ws73_lcd镜像、能ssh/串口登录(root@192.168.1.221)
    4.factory_demo_main在跑:ps|grep factory;不在先 sh /root/start_ws73_lcd.sh
    (2) 编译机(一次性)
    ~/miniconda3/bin/pip install cmake==3.31.10 meson ninja jsonschema jinja2 pyyaml \
      -i https://pypi.tuna.tsinghua.edu.cn/simple
    
    #1.编译(编译机)
    cd ~/tmp/hi_aiot_solution
    export PATH=/home/nancy/miniconda3/bin:$PATH   # python3.12+cmake3.31+meson/ninja
    export PATH=/home/nancy/tools/mtd/sbin:$PATH
    export PATH=/home/nancy/toolchains/gcc-10.3-arm-musl-x86-linux-26.06.1/arm-v01c02-linux-musleabi-gcc/bin:$PATH
    bash scripts/build.sh build --target demb_ev_board samples gui/square_lcd_video_ui
    # 产物:_build/bin/square_lcd_sample
    
    #2.部署(编译机→板)
    cd _build/rootfs/gui_rootfs_tmp/root
    tar czf /tmp/gui_app.tgz gui
    scp /tmp/gui_app.tgz root@192.168.1.221:/tmp/    #没密码就设置个密码
    # 板端(Xshell):
    cd /root && tar xzf /tmp/gui_app.tgz   # 出/root/gui/square_lcd_sample + param/
    

2.板端运行(Xshell)

  • # 前置(ws73_lcd镜像启动后都已在位):
    lsmod | grep -E "jd9853|hynitron"      # 驱动在
    ps | grep sdk_server                   # MPP桥在
    
    killall factory_demo_main              # 释放DRM master(不杀会冲突)
    sleep 3                                # 等MPP释放完(看ps确认更稳)
    ps | grep factory | grep -v grep               # 无输出=释放完
    cd /root/gui && ./square_lcd_sample
    # 成功标志:日志出现"Press Ctrl+C to quit"且屏显示LVGL界面可触控;
    # 失败排查:无屏显→查killall是否执行;segmentation fault→查sdk_server。
    
    • 若要回到出厂演示

      killall square_lcd_sample; /root/factory_demo_main &   # 或直接重启
      

3.示意

3.sample_aidetect

sample_aidetect:给一张 YUV 图 + 检测模型,用 NPU 推理出人形/车辆/人脸/宠物/包裹的检测框。

1.编译部署

  • #前提
    编译机:同 square_lcd_sample(三行export,已配好不用重弄)
    开发板:sdk_server 在跑(ps|grep sdk_server)
    
    #1.编译(编译机)
    cd ~/tmp/hi_aiot_solution
    export PATH=/home/nancy/miniconda3/bin:$PATH
    export PATH=/home/nancy/tools/mtd/sbin:$PATH
    export PATH=/home/nancy/toolchains/gcc-10.3-arm-musl-x86-linux-26.06.1/arm-v01c02-linux-musleabi-gcc/bin:$PATH
    bash scripts/build.sh build --target demb_ev_board samples ai_component
    # 产物:_build/bin/sample_aidetect、sample_aivsr
    #   注意:模型/测试图/musl库不在 _build 里,要从 SDK 源码树拿(见下)
    
    #2.部署(编译机→板)
    # 编译机上组装最小测试集:
    SDK=~/tmp/hi_aiot_solution/sdk/demb
    mkdir -p /tmp/ai_test/{soc/libs,out/model/aidetect,samples/mpp/svp/ai_component/aidetect/data}
    cp _build/bin/sample_aidetect   /tmp/ai_test/samples/mpp/svp/ai_component/aidetect/
    cp $SDK/samples/mpp/svp/ai_component/aidetect/data/hvf_image_hor_1920x1080.yuv \
       /tmp/ai_test/samples/mpp/svp/ai_component/aidetect/data/
    cp $SDK/output/mpp/model/aidetect/det_hvf_hor.bin /tmp/ai_test/out/model/aidetect/
    cp -rf $SDK/soc/libs/musl /tmp/ai_test/soc/libs/
    cd /tmp/ai_test && tar czf /tmp/ai_test.tgz .
    scp /tmp/ai_test.tgz root@192.168.1.221:/tmp/
    
    # 板端(Xshell):
    mkdir -p /mnt/test_dir && cd /mnt/test_dir && tar xzf /tmp/ai_test.tgz
    mkdir -p /run/sdk_server
    ln -sf /tmp/osal_uds_server.sock /run/sdk_server/osal_uds_server.sock 
    

3.运行测试(板端)

  • ps | grep sdk_server                          # 确认MPP桥在
    killall factory_demo_main; sleep 3            # 释放VB/MMZ
    ps | grep factory | grep -v grep              # 无输出=凉透
    
    #重建运行环境(重启后/tmp保留但/run是tmpfs会丢、env会丢)
    mkdir -p /run/sdk_server
    ln -sf /tmp/osal_uds_server.sock /run/sdk_server/osal_uds_server.sock
    export TEST_PATH=/mnt/test_dir
    export LD_LIBRARY_PATH=$TEST_PATH/soc/libs/musl:$LD_LIBRARY_PATH
    
    # 运行测试
    cd $TEST_PATH/samples/mpp/svp/ai_component/aidetect
    ./sample_aidetect -m /mnt/test_dir/out/model/aidetect/det_hvf_hor.bin \
      -i ./data/hvf_image_hor_1920x1080.yuv -s 1920x1080 -v
      
      
    #   成功标志:尾部打印 ==== Frame ==== + type:x conf:0.xx [x,y,w,h] 检测框
    #   实测输出:type:1 conf:0.85(人形检测框)
    
  • image-20261103113302503

4.sample_single_sensor

sample_single_sensor:单摄像头整机通路——OS04D10采集→VPSS→H.265编码→RTSP推流 + 屏上240×320实时预览,可选录像到/mnt。

1.编译部署

  • # 编译(编译机)——注意带 -DSENSOR=os04d10
    cd ~/tmp/hi_aiot_solution
    export PATH=/home/nancy/miniconda3/bin:$PATH
    export PATH=/home/nancy/tools/mtd/sbin:$PATH
    export PATH=/home/nancy/toolchains/gcc-10.3-arm-musl-x86-linux-26.06.1/arm-v01c02-linux-musleabi-gcc/bin:$PATH
    bash scripts/build.sh build --target demb_ev_board samples sensor/single -DSENSOR=os04d10
    # 产物:_build/bin/sample_single_sensor
    
    # 部署(编译机→板)
    cd _build/rootfs/rootfs_tmp_single/root
    tar czf /tmp/single_app.tgz single
    scp /tmp/single_app.tgz root@192.168.1.221:/tmp/
    # 板端(Xshell):
    cd /root && tar xzf /tmp/single_app.tgz    # 出 /root/single/sample_single_sensor + param/
    

2.板端运行

  • killall factory_demo_main; sleep 3        # 同一套:释放VB/MMZ+DRM
    ps | grep factory | grep -v grep          # 无输出=凉透
    
    cd /root/single
    ./sample_single_sensor -t 0 -n            # -t0持续运行 -n不录像(只预览+推流)
    # 成功标志:
    #   os04d10 24Mclk 4M30fps Init OK
    #   [lcd] 240x320 via DRM
    #   [rtsp] RTSP server ready on port 554, stream=livestream/0
    #   屏上显示实时预览画面
    # Ctrl+C 退出 → "os04d10 Sensor + LCD success!"
    
  • 也可调参

    • 命令效果
      ./sample_single_sensor -t 30录30秒H.265到/mnt/os04d10_*.h265
      ./sample_single_sensor -b 6000 -t 30自定义码率6Mbps
      ./sample_single_sensor默认录10秒

3.RTSP验证(PC端)

  • VLC → 打开网络串流 → rtsp://192.168.1.221:554/livestream/0
    出画面 = 采集→编码→推流全链通
    

与square_lcd_sample的区别

  • square_lcd:VI→VPSS→RGB565→DRM(屏显UI,无RTSP编码路)
    single_sensor:VI→VPSS双通道→VENC(H.265)→RTSP + 屏预览(录像可选)
    
  • image-20261103142350882

六、语音AI助手

目标:在官方factory_demo/ws73_lcd出厂六合一演示(相机/NPU/RTSP/BLE/WiFi配网/LVGL UI)基础上添加"本地唤醒+云端语音识别+LLM对话+板端技能"的一个助手

  • # 语音AI助手能力(均已实测验证)
    
    【语音输入】
    - "你好芯宝"离线唤醒(KWS),唤醒后自动进入15秒命令窗口
    - 唤醒后自由说话:自动断句→云端ASR转文字→进输入框
    - "语音"按钮按住说话:VAD静音1.2s自动结束(15秒上限)
    - "直发"开关:识别完直接发给agent,无需审稿
    
    【对话与执行】
    - 自由对话:DeepSeek多轮上下文(agent -m + session文件)
    - 拍照:语音/文字触发,相机实时拍照回显在聊天气泡
    - 人员检测:NPU目标检测,语音"打开空调"(KWS命令词)或文字"有没有人"均可触发
    - 拼音输入:26键全拼输入法,屏幕键盘+候选条
    - 新对话:一键清上下文重来
    

0.前置条件

  • 项要求
    编译环境SDKhi_aiot_solution可正常编译,PATH含miniconda3/bin+arm-v01c02-linux-musleabi-gcc工具链
    板子能跑factory_demo(相机/显示屏初始化正常),WiFi已配网可上外网
    火山引擎控制台开通**“流式语音识别模型2.0”**(有免费额度),API密钥管理里新建一条API Key(不要用"默认体验中心使用"那条)
    LLMzeroclaw已配好(本例DeepSeek),agent -m能对话
    • 火山引擎豆包语音开通流式语音识别2.0步骤

      • image-20261106144029861
    • depseek获取API Key:进入deepseek官网———>充值——->获取API Key

1.总体架构

  • ┌────────────────────────── LVGL 主线程(UI)──────────────────────────┐
    │  AI助手页:聊天气泡/26键拼音IME/"语音"按钮/"直发"开关/照片气泡 │
    └──────────────▲──────────────────────────────┬───────────────────────┘
                   │ refresh_ui                   │ publish
    ┌──────────────┴──────────── EventHub(SS_EVTHUB)─────────────────────┐
    │  EVENT_CMD_ZC_CHAT_SEND   EVENT_VOICE_TRIGGER                        │
    │  EVENT_VOICE_ASR_STATE    EVENT_VOICE_ASR_TEXT   EVENT_ZC_CHAT_DONE  │
    └──▲───────────────▲───────────────────▲───────────────────▲──────────┘
       │               │                   │                   │
    ┌──┴───────┐ ┌─────┴──────┐ ┌──────────┴────────┐ ┌────────┴─────────┐
    │ zeroclaw │ │ KWS线程     │ │ 录音+VAD(ACAP回调)│ │ ASR worker线程    │
    │ worker   │ │(offline_    │ │                   │ │ libcurl WS        │
    │          │ │ voice)      │ │                   │ │ →火山SAU          │
    └──┬───────┘ └─────▲──────┘ └──────────▲────────┘ └────────┬─────────┘
       │ posix_spawn   │ ov_feed_pcm       │ 同一批PCM帧         │ HTTPS/WS
       ▼               │                   │                    ▼
    zeroclaw agent -m  └────────── AI dev0(inner ADC 48k)─→AENC hdl0─→ACAP tap
      --session-state-file              (媒体管线已有音频通路,直接旁路取帧)
            │
            ▼
       DeepSeek LLM → 文本回复/skill触发(拍照·检测人·系统状态)
    
  • 关键设计

    新app还是改factory_demo改factory_demo相机/NPU/网络/UI全现成,重复造轮子没意义
    LLM接入posix_spawn("zeroclaw agent -m ...")每轮一发不引入长驻LLM进程;--session-state-file保上下文
    音频源复用ACAP tap(acap_reg_cb+aenc_start)媒体管线已占AI dev0,硬开第二路会冲突;tap白捡16kHz单声道PCM
    KWS模式offline_voice EXTERNAL-PCM模式组件内部AFE旁路,ov_feed_pcm直接喂帧,零硬件依赖
    ASR方案按住说话→批量WS识别(火山SAU)比流式简单可靠;16k/16bit/mono正好是tap输出格式
    线程模型每环节独立线程+EventHub总线KWS回调/录音/ASR网络互不阻塞,LVGL只消费事件
    UI安全语音线程绝不直接碰LVGL一律publish→主线程route_event→UI更新
  • 事件清单

    事件生产者→消费者用途
    EVENT_CMD_ZC_CHAT_SENDUI→main发送聊天(按钮/预设/语音统一入口)
    EVENT_ZC_CHAT_DONEzeroclaw worker→mainLLM回复就绪
    EVENT_VOICE_TRIGGERKWS回调→main唤醒/命令词→映射prompt走发送链
    EVENT_VOICE_ASR_STATE录音状态机→mainrec/asr/idle同步按钮配色
    EVENT_VOICE_ASR_TEXTASR worker→main识别文本回填输入框(或直发)

    注意:事件必须SS_EVTHUB_Register+Subscribe双侧都加,只定义ID会被静默丢弃。

2.构建流程

  • #1.构建链路
    app.defconfig  ──Kconfig──▶  .config  ──config.cmake生成──▶  .config.cmake
          │
          ▼               ┌── ExternalProject(openssl/curl/lvgl/cjson…)
    build.sh build   ────▶├── components静态库(media/hiai/hichannel…)
          │               └── apps可执行 → _build/bin/factory_demo_main
          ▼
     工具链arm-v01c02-linux-musleabi-gcc(C11)必须在PATH
     
     #2.配置开关
     # app.defconfig增量
    CONFIG_HIAI_OFFLINE_VOICE=y    # KWS组件(unisound适配器+libkws.a随编译)
    CONFIG_OS_CURL=y               # libcurl 8.9.1(≥7.86才有WS API)
    CONFIG_OS_OPENSSL=y            # curl的TLS依赖(自动select 1.1.1w)
    
    #3.常用命令
    # 编译机(~/tmp/hi_aiot_solution,PATH需含miniconda3/bin+工具链bin)
    bash scripts/build.sh build --target demb_ev_board references factory_demo/ws73_lcd
    # 只编目标(跳过ExternalProject全量,micropython链接失败是既有噪声可无视)
    cd _build && make factory_demo_main
    

3.功能适配流程

  • 功能适配流程
    ├─ 3.1 AI对话页(第一阶段)
    │  ├─ 页面:page_t加PAGE_AI_CHAT,`navigate_to_page()`管生命周期
    │  ├─ UI:ui_module.c气泡列表+输入行+LVGL `lv_ime_pinyin`(换自建全简体词库防豆腐块)
    │  ├─ LLM:zeroclaw_module.c的`chat_send`→pthread→`posix_spawn agent -m`→截stdout→`EVENT_ZC_CHAT_DONE`
    │  ├─ 接线:main.c事件Register/Subscribe/route三点
    │  └─ 照片:agent回复带`[PHOTO:/path]`标记→UI用`tjpgd`解码成图片气泡
    │
    ├─ 3.2 KWS离线唤醒(第二阶段)
    │  ├─ 开关:defconfig开CONFIG_HIAI_OFFLINE_VOICE→liboffline_voice.a+unisound厂商库
    │  ├─ 引擎:voice_module.c里`ov_create(ext_audio_fmt={16000,1,16})`(外部喂帧)+`ov_start(callback)`
    │  ├─ PCM:`acap_reg_cb(0)`+`aenc_start(0)`起feed线程→回调拿virt_addr[0]单声道→`ov_feed_pcm()`
    │  ├─ 事件:`OV_EVENT_WAKEUP`→`EVENT_VOICE_TRIGGER`→`chat_do_send("你好")`;`OV_EVENT_COMMAND`→`g_voice_cmd_map[]`映射intent→prompt
    │  └─ 可逆:CMake用`if(TARGET offline_voice)`包住源文件和链接,组件没开应用照常编译
    │
    └─ 3.3 云端ASR语音输入(第三阶段)
       ├─ 开关:defconfig开CONFIG_OS_CURL/CONFIG_OS_OPENSSL(首编多编openssl+curl几分钟)
       ├─ 录音:输入行"语音"按钮→`voice_rec_start()`→ACAP回调里同一批PCM顺带写进480KB bss缓冲
       ├─ VAD:帧均值振幅>55记voiced;voiced后连续1.2s静音→自动`voice_rec_end`(15s上限兜底)
       ├─ 识别:ASR worker线程起一条WS连接→config帧→分块audio帧→end帧→收cJSON结果
       ├─ 回填:`EVENT_VOICE_ASR_TEXT`→主线程:"直发"开→`chat_do_send`;关→填输入框+弹键盘审稿
       └─ 凭证:板端/root/voice_asr.conf(token/url/res_id),不进代码仓
    

4.部署与验证

  • 1.部署

    • # 传二进制:编译机跑 scp _build/bin/factory_demo_main root@192.168.1.221:/root/factory_demo_main.new
      #          (或Xftp/拖拽),板端(Xshell)执行:
      killall factory_demo_main.new; sleep 3        # 运行中的文件会text busy,先停(SIGTERM)
      chmod +x /root/factory_demo_main.new
      
      # 起进程:wrapper把退出码写进日志(rc=139=SIGSEGV)
      nohup sh -c \
        "/root/factory_demo_main.new > /root/fd.log 2>&1; echo EXITED rc=\$? >> /root/fd.log" \
        > /dev/null 2>&1 &
      
      • 注意:停进程一律SIGTERM——kill -9会把MPP/sensor状态弄脏,下次起不来只能reboot。
  • 2.日志验证

    • 验什么怎么验
      ASR凭证/连通性本机curl模拟WS握手看101 vs 403,不用等板子测:
      curl -N -H "Upgrade: websocket" -H "Sec-WebSocket-Version:13" -H "Sec-WebSocket-Key:x3JJHMbDL1EzLkh9GBhXDw==" -H "X-Api-Key: <key>" -H "X-Api-Resource-Id: volc.seedasr.sauc.duration" -H "X-Api-Sequence: -1" https://openspeech.bytedance.com/api/v3/sauc/bigmodel_async
      录音能量rec dbg: mean=N voiced=Xms sil=Yms每0.5s一条
      KWS状态日志看Domain: wakeup/ivm切换、[voice] wakeup/cmd/sleep
      进程死法EXITED rc=+dmesg的MMB LEAK(异常死必留痕)
    • 成功标志:日志出现

      • [voice] rec start → rec dbg: mean=172 ... → rec end: NNN samples, ASR started
        < HTTP/1.1 101 Switching Protocols
        [asr] sent 77824 bytes, waiting result
        [asr] text='今天周几?'
        
        • 屏幕侧:识别文本进输入框(直发模式直接成用户气泡)→ agent回复。
  • 3.上机验证

    • image-20261106150228632

5.踩坑表

  • 坑一句话教训
    printf日志"丢失"nohup重定向后stdout全缓冲——main()开头setvbuf(stdout,NULL,_IOLBF,0)
    VAD不自动停实测电平定阈值:这麦底噪15、说话100,拍脑袋写500永远判无声
    中文豆腐块字体是裁剪子集,新文案/符号(连"…")都可能缺字形——F12直接上全GB2312
    curl请求没发出就失败curl_slist_append判空守卫会把首个append也挡住,hdrs永远NULL
    ASR 403"默认体验中心"key≠业务key要自建;res_id必须匹配开通的模型版本(seedasr=2.0/bigasr=1.0)
    token进日志CURLOPT_VERBOSE打全量请求头,调通就关
    KWS词表改不动语法编译进libkws.a的FST,定制词要找云知声重训;intent→action映射在自己代码里随便改
    UniKws免费版~1小时后out of call limit刷屏停识别,重启进程恢复;商用要授权
    屏幕黑多半不是显示bug,是进程死了——先查ps和EXITED rc=

七、星闪WS73互连测试

开发板板:ws73_lcd案例镜像

Hi3519DV500板:ws73四ko已加载、test_ws73_sle就位

目标:验证两板WS73能否互连,顺带测SLE/BLE/WiFi三协议吞吐

1.环境

  • 项开发板板Hi3519板DV500
    WS73ExtBoard插SDIO1槽USB接ws73e模组
    工具链arm-v01c02-linux-musleabiaarch64-v01c01-linux-gnu
  • image-20261102141006315
  • 查看开发板侧WS73上电状态

    • cat /proc/mci/mci_info          # 看MCI1状态——扩展板插好应显示:
      #   MCI1: pluged_connected / Type: SDIO card / 50MHz
      sh /root/start_wifi.sh          # 加载plat_soc/wifi_soc/sle_soc/ble_soc+wpa_supplicant
      lsmod | grep soc                # 四ko应该都在
      ip -o link show wlan0           # 应出现wlan0
      
      • 若MCI1: pluged_init_failed→扩展板没插到位,插好后重跑脚本

2.编译测试:

  • 移植测试程序到开发板,编译

    • 软件环境参考了鸿鸥派hi3519DV500的构建,测试例程在默认基础上调优
  • 测试

    1. WiFi互测

      • # Hi3519板做AP
        LD_LIBRARY_PATH=/usr/lib hostapd -B /etc/wireless/hostapd.conf
        ifconfig wlan0 192.168.49.1
        udhcpd -S /etc/wireless/udhcpd.conf &
        
        # 开发板连AP(wpa_cli在/ws73/不在PATH!)
        # —— 另开一个Xshell窗口登开发板板,执行:
        /ws73/wpa_cli -i wlan0 add_network
        /ws73/wpa_cli -i wlan0 set_network 1 ssid "HongOU_PI_AP"
        /ws73/wpa_cli -i wlan0 set_network 1 psk "12345678"
        /ws73/wpa_cli -i wlan0 select_network 1
        sleep 4; ip -o -4 addr show wlan0      # 应拿到192.168.49.x
        
        # Hi3519板端窗口1(接收端):
        /root/tcpperf server -p 5201 -t 12
        # 开发板板端窗口2(发送端,先确认server已listen再敲):
        /root/tcpperf client -a 192.168.49.1 -p 5201 -t 10
        # 实测:tx 47.88 Mbps / rx 47.70 Mbps(2.4G HT20@2437MHz)
        
        • ps:也可使用iperf3互测
    2. SLE互测

      • # Hi3519板端窗口1(接收端):
        /root/test_ws73_sle server -t 45
        
        # 开发板板端窗口2(发送端):
        /root/test_ws73_sle client -t 15 -n test_ws73_sle
        
      • 调参

        • 参数组实测
          默认(200B/2ms/conn16slot)avg 16.80/peak 19.73 KB/s
          调参(-l 1000 -i 1 -c 8 -M 12)avg 58.88/peak 97.66 KB/s,server稳态68-71KB/s
    3. BLE互测

      • # Hi3519板端窗口1(接收端):
        /root/test_ws73_ble_hwbt server -t 45
        # 开发板板端窗口2(发送端):
        /root/test_ws73_ble_hwbt client -t 15
        
        • 协商MTU 517/PHY 2M/interval 15ms;client TX~98KB/s(队列写入速率),server RX~29-31KB/s(空口实际送达),fail=0。TX/RX不对称是统计口径差异,RX才是空口真实吞吐。
  • 数据汇总表

    • 协议方向吞吐说明
      WiFi开发板→Hi351947.88 Mbpstcpperf双端互证
      WiFiHi3519→开发板39.46 Mbps反向
      SLE开发板→Hi351916.80→58.88/97.66 KB/s默认→调参(conn8slot/1KB包/MCS12)
      BLE开发板→Hi3519~29-31 KB/s(空口)MTU517/2M PHY

八、外设驱动解析

1.hynitron触摸驱动(CST3530,I2C接口)

给开发板2.8寸屏配的海栎创CST3530电容触摸,走"改DTS → 编ko → insmod → probe → input节点 → 用户态坐标"完整链路。

0.硬件链路

  • CST3530触摸IC → 排线 → WS73扩展板 → 40PIN → 主板 i2c-1(0x5A) + 中断GPIO0_0 + 复位GPIO4_2
    

1.驱动

  • 源码:components/adapter/drivers/touch/hynitron/(SDK自带,hyn_core.c+各芯片适配)
    产物:/drv/hynitron_touch.ko(约430KB)
    匹配:compatible="hyn,66xx"  —— readme.txt写明 66xx 兼容 cst35xx 系列
    

2.DTS节点  apps/demb_ev_board/bsp/dts/panel_config.dtsi(由ws73_lcd_dts.patch在编译期写入),挂在i2c_bus1 下

  • hynitron: hynitron@5a {
        compatible = "hyn,66xx";              // CST3530 走 66xx 适配
        reg = <0x5a>;                          // I2C 地址 0x5A
        interrupt-parent = <&gpio_chip0>;
        interrupts = <0 IRQ_TYPE_EDGE_FALLING>;// 中断脚 GPIO0_0 下降沿
        irq-gpios = <&gpio_chip0 0 0>;
        reset-gpios = <&gpio_chip4 2 0>;       // 复位脚 GPIO4_2
        max-touch-number = <5>;                // 五点触控
        display-coords = <0 0 240 320>;        // 屏分辨率
        pos-swap = <0>;
        posx-reverse = <1>;                    // 面板贴装方向→坐标翻转
        posy-reverse = <1>;
    };
    

3.编译 + 加载

  • # 编译机(ws73_lcd案例内随系统一起编,ko落在镜像/drv/)
    bash scripts/build.sh build --target demb_ev_board references factory_demo/ws73_lcd
    
    # 板端手动加载(开机脚本 start_ws73_lcd.sh 已自动做这一步):
    insmod /drv/hynitron_touch.ko
    

4.验证

  • # 1.probe日志——驱动认到芯片没
    dmesg | grep -iE "hyn|cst"
    #   [HYN]i2c addr:0x5a  read_part_no:0xcaca220e
    #   chip cst3530 match fw success
    #   input: hyn_ts as /devices/.../input0        ← 出现=驱动跑通
    
    # 2.I2C从设备被绑定
    i2cdetect -y 1      # 0x5a 位置显示 "UU"(被驱动占用,不是裸地址)
    cd /sys/devices/platform/soc/soc:amba/11061000.i2c/i2c-1/1-005a/
    cat hyntpfwver      # 读固件版本——证明I2C双向通信正常
    
    # 3.input节点注册
    cat /proc/bus/input/devices
    #   N: Name="hyn_ts"  H: Handlers=event0
    ls -l /dev/input/event0        # 13:64
    
    # 4.用户态坐标——最终判据
    /root/tsread                   # 自写evdev读取器(hexdump/od读evdev会Invalid argument)
    #   划屏输出:[DOWN] X=120 Y=160 ... [UP]  ← 出坐标=全链通
    

2.JD9853 SPI屏驱动

0.硬件链路

  • JD9853 驱动IC → 屏FPC → WS73扩展板LCD座 → 40PIN → 主板SPI0
      数据线:SPI0_SDO/SDI/CLK/CSN(50MHz,DMA加速)
      控制脚:DC=GPIO0_1 / TE=GPIO3_5 / RST=GPIO7_5 / 背光PWM=GPIO7_0
    

1.驱动

  • 源码:components/adapter/drivers/lcd/jd9853/jd9853.c
    产物:/drv/jd9853.ko(约16KB)
    modalias:spi:jd9853-240x320(SPI总线自动匹配)
    

2.DTS节点 bsp/dts/panel_config.dtsi

  • backlight: backlight {
        compatible = "pwm-backlight";
        pwms = <&pwm1 7 100000>;            // PWM1通道7=GPIO7_0,周期100us
    };
    
    &spi_bus0 {
        dmas = <&edmacv310_0 7 7>, <&edmacv310_0 6 6>;   // SPI-DMA加速
        dma-names = "tx","rx";
    
        jd9853:ips@0 {
            compatible = "fitipower,jd9853-240x320";  // 型号+分辨率写进modalias
            reg = <0>;                               // CS0
            spi-max-frequency = <50000000>;          // 50MHz
            pl022,com-mode = <2>;                    // pl022控制器参数
            pl022,tx-level-trig = <3>;
            pl022,rx-level-trig = <3>;
            rotation = <0>;                          // 0°(竖屏240×320)
            dc-gpios    = <&gpio_chip0 1 0>;         // 命令/数据脚 GPIO0_1
            te-gpios    = <&gpio_chip3 5 0>;         // TE撕屏同步 GPIO3_5
            reset-gpios = <&gpio_chip7 5 0>;         // 复位 GPIO7_5
            backlight = <&backlight>;                // 挂上PWM背光
            status = "okay";
        };
    };
    

    关于移植:换屏只改compatible(驱动里对应不同初始化序列)、rotation、dc/te/reset三根 GPIO;spi-max-frequency按屏手册降速。

3.编译 + 加载

  • # 编译机(ws73_lcd案例随系统编出):
    bash scripts/build.sh build --target demb_ev_board references factory_demo/ws73_lcd
    
    # 板端手动加载(开机脚本 start_ws73_lcd.sh 已自动):
    insmod /drv/lcd_panel.ko  
    

4.验证

  • # 1.查看驱动模块是否加载   
    lsmod | grep jd9853    # 能出 "jd9853 16384 0"——虽然文件叫 lcd_panel.ko
                           # 模块名≠文件名:ko内部注册的模块名是 jd9853           
    # 2.probe日志——SPI认到屏+初始化序列发完
    dmesg | grep -iE "jd9853|drm"    
    #   [drm] Initialized jd9853 1.0.0 for spi0.0
    #   jd9853 spi0.0: JD9853 panel probe done, 240x320 rotation=0   ← 关键行
    
    # 3.DRM设备注册(Linux显示子系统接管)
    ls -l /dev/dri/                # card0(主显示设备)
    cat /sys/class/drm/card0-*/status     # connected
    cat /sys/class/drm/card0-*/modes      # 240x320
    
    # 4.modalias匹配(SPI自动绑定证明)
    cat /sys/bus/spi/devices/spi0.0/modalias   # spi:jd9853-240x320
    ls -l /sys/bus/spi/devices/spi0.0/driver   # → drivers/jd9853
    
    # 实显+背光——最终判据
    #   屏显示LVGL界面 = 显示链路全通
    #   square_lcd_sample的Light页划亮度 → 背光PWM链路通
    
  • 关于背光

    • #demo运行时
      ls /sys/class/backlight/backlight/
      #   brightness  actual_brightness  max_brightness(=100)  bl_power  ...
      
      echo 100 > /sys/class/backlight/backlight/brightness   # 最亮
      echo 50  > /sys/class/backlight/backlight/brightness   # 半亮
      echo 0   > /sys/class/backlight/backlight/brightness   # 灭背光(屏还显示,只是没光)
      cat /sys/class/backlight/backlight/actual_brightness    # 回读确认生效
      

对于触摸驱动

  • hynitron:I2C-1(0x5A) + GPIO0_0中断 + GPIO4_2复位 → /dev/input/event0
    jd9853:  SPI0(CS0,50MHz) + GPIO0_1 DC + GPIO7_5复位 + PWM背光 → /dev/dri/card0
    

九、外设扩展实战

1.HC-05

1.接线

  • HC-05 引脚J3 pinSoC GPIOfunction方向/说明
    VCC2或4——5V0供电
    GND6或其他(略)——共地必须
    TXD10GPIO0_6UART1_RXD(func5)模组发→板收
    RXD8GPIO0_7UART1_TXD(func5)板发→模组收
    EN/STATE/KEY不接——保留脚,悬空即可
    • 上电红灯快闪=正常(等待配对)

2.板上配置

  1. 方式一:快速配置验证

    bspmm 0x11130030 0x1205   # GPIO0_6 → UART1_RXD (pin10)
    bspmm 0x11130034 0x1205   # GPIO0_7 → UART1_TXD (pin8)
    stty -F /dev/ttyAMA1 9600 raw -echo
    
  2. 方式二:改设备树配置验证

    #1. 改dtsi
    pin-cfg@26 {
        pin = <26>;              /* 引脚号: GPIO0_7 -> J3 pin8  UART1_TXD */
        gpio-num = "GPIO0_7";    /* GPIO 号 */
        function = "UART1_TXD";  /* 功能名 (func5) */
        pull = "pull-down";      /* 上下拉: pull-up / pull-down / none */
        drive = "I02_level4";    /* 驱动档位 */
        slew = "fast";           /* 边沿: fast / slow */
        input-enable;            /* 输入使能 */
    };
    
    pin-cfg@27 {
        pin = <27>;              /* 引脚号: GPIO0_6 -> J3 pin10 UART1_RXD */
        gpio-num = "GPIO0_6";    /* GPIO 号 */
        function = "UART1_RXD";  /* 功能名 (func5) */
        pull = "pull-down";      /* 上下拉: pull-up / pull-down / none */
        drive = "I02_level4";    /* 驱动档位 */
        slew = "fast";           /* 边沿: fast / slow */
        input-enable;            /* 输入使能 */
    };
    
    #2.编译(以下在编译机 nancy@192.168.1.220 上执行)
    S=~/tmp/hi_aiot_solution; B=$S/apps/demb_ev_board/bsp/dts
    A=$S/apps/demb_ev_board/references/factory_demo/ws73_lcd/dts
    STAGE=/tmp/dts_stage; rm -rf $STAGE && mkdir -p $STAGE
    for f in demb-flash.dts demb-open.dtsi \
             demb_family_usb.dtsi demb.dts panel_config.dtsi; do
        cp $B/$f $STAGE/
    done
    cp $A/board_io_config.dtsi $STAGE/            # 案例覆盖赢bsp同名
    INC=$S/sdk/demb/third_party/linux/linux-5.10.y/include
    gcc -E -nostdinc -I$STAGE -I$INC -undef -D__DTS__ \
        -x assembler-with-cpp -o /tmp/x.tmp $STAGE/demb-flash.dts
    dtc -I dts -i $STAGE -i $INC -O dtb \
        -o /tmp/demb-flash.dtb /tmp/x.tmp   # warning刷屏正常;必须带-I dts
    mkdir -p /tmp/fit
    cp $S/sdk/demb/third_party/linux/linux-5.10.y/arch/arm/boot/zImage /tmp/fit/
    cp /tmp/demb-flash.dtb /tmp/fit/devicetree.dtb
    cp $S/sdk/demb/boards/dmeb/tools/pc/image_tree_source/linux_image.its /tmp/fit/
    cd /tmp/fit && mkimage -f linux_image.its uImage
    sha256sum uImage                               # 本次: 5efc91fd...
    
    #3.传板+烧录+校验(先把编译机的 /tmp/fit/uImage 传到板端 /tmp/uImage_uart1:
    #   编译机跑 scp /tmp/fit/uImage root@192.168.1.221:/tmp/uImage_uart1,或Xftp拖拽)
    # —— 以下在板端(Xshell)执行:
    sha256sum /tmp/uImage_uart1                             # 必须=编译机sha
    cd /root/img && ./mtdflash /dev/mtd2 /tmp/uImage_uart1  # 烧mtd2(命令不能以 / 开头!)
    dd if=/dev/mtdblock2 bs=1M count=4 2>/dev/null | head -c $(stat -c%s /tmp/uImage_uart1) | sha256sum
    # 必须=5efc91fd...,不一致别重启
    cp /tmp/uImage_uart1 /root/img/uImage_uart1 && sync     # 留档(/tmp 重启会丢)
    
    #4.重启验证(同板端)
    reboot                                                  # 等~40s
    bspmd.l 0x11130030 0x18                                 # 两个寄存器应=0x1205,固化成功的判据
    lsmod | grep board_io                                   # ko 在
    

3.AT验证

  • cat /dev/ttyAMA1 > /tmp/rx.log &          # 后台接收
    echo -ne "AT\r\n" > /dev/ttyAMA1; sleep 1
    cat /tmp/rx.log                           # 应见 OK
    echo -ne "AT+NAME?\r\n" > /dev/ttyAMA1; sleep 1; cat /tmp/rx.log   # +NAME:HC-05
    echo -ne "AT+ADDR?\r\n" > /dev/ttyAMA1; sleep 1; cat /tmp/rx.log   # 蓝牙MAC
    kill %1
    
    
    #改蓝牙名/波特率
    echo -ne "AT+NAME=YueYing_BT\r\n" > /dev/ttyAMA1   # 改名
    echo -ne "AT+UART=115200,0,0\r\n" > /dev/ttyAMA1 # 改波特率(改完stty要跟着换)
    # AT+PSWD=1234 改配对码;AT+ROLE=1 改主机
    

4.手机透传测试

  1. 手机设置→蓝牙→搜 HC-05→配对,PIN 输 1234

  2. 装「蓝牙串口助手/Serial Bluetooth Terminal」类 app,连 HC-05

  3. 板上

    1. cat /dev/ttyAMA1 &        # 收手机发的
      # 手机端发 "hello" → 串口终端应打印 hello
      echo -ne "board hi\r\n" > /dev/ttyAMA1   # 手机端应收 "board hi"
      

5.切换/回滚:与tf卡的配置一致,再加一个

  • bootsel lcd      # 出厂屏版
    bootsel tf       # TF卡版
    bootsel uart1    # LCD+UART1 版(当前)
    

2.ST7789V屏适配轻AI越影视觉开发板全流程

目标:在hi_aiot_solutionSDK的轻AI越影视觉开发板上接入一块通用8pin 1.14"ST7789V SPI TFT模组(135×240,无触摸、无TE引脚),复用已有st7789vDRM驱动与panelsample框架点亮。

  • 成果:板端实测通过——st7789vprobe成功,/dev/dri/card0注册135x240模式,自写DRM测试程序输出彩条+边框画面,SPI传输统计与帧数据量吻合。

已知参数

  • 项值
    ICST7789V(复用components/adapter/drivers/lcd/st7789v/)
    分辨率135×240
    尺寸/形状1.14"方屏
    案例名st7789_135_240_114_50M(命名规则<ic>_<w>_<h>_<尺寸×10>_50M)
    案例基底st7789_240_320_28_50M
    SPISPI0 @50MHz
    触摸无(模组无触摸,pin_mux/DTS不埋触摸节点)
    TE不接(模组没引出TE脚,dts里删te-gpios)

1.软硬件环境

  • 项值备注
    主控轻AI越影视觉开发板NAND 512MB版,mtdparts=512K(boot),512K(env),4M(kernel),198M(rootfs)
    内核Linux 5.10.221FIT打包kernel+dtb,刷mtd2
    SDKhi_aiot_solution(WS73场景app框架)编译入口scripts/build.sh
    交叉编译链arm-linux-musleabi-gcc(gcc 10.3,~/toolchains/gcc-10.3-arm-musl-x86-linux-26.06.1)环境初始化source ~/demb_env.sh
    显示模组1.14"ST7789V SPI TFT,8pin排针小板135×240可视,GRAM 240×320,无触摸无TE
    屏驱动components/adapter/drivers/lcd/st7789v/st7789.c现成DRM驱动,变体用patches/差分
    应用框架LVGL 9.4.0+lv_linux_drm后端sample源码source/main.c
    调试工具串口COM21@115200、SSH、in.tftpd(192.168.1.220)、U-Boot TFTP救砖流程见《开发板U-Boot_TFTP_NAND救砖刷机》

2.原理与前期分析

  • ST7789V控制器与135×240的偏置问题

    • ST7789V:Sitronix单芯片TFT控制器,内部 **GRAM(显存)*固定为*240×320×16bit,通过4线SPI(SCLK/SDA/CS/DC)接收命令与像素流。
    • 显示窗口:SPI刷屏向GRAM写像素前须先发CASET/RASET限定地址窗(st7789.c内st7789v_set_window,st7789.c),窗口=可见区映射进GRAM的起止坐标。
    • 本模组的偏置:1.14"屏物理像素135×240,但其GRAM可视区不从(0,0)起,居中于240×320 GRAM内——left_offset=52、top_offset=40(240-135=105,(105-1)/2=52;320-240=80/2=40),即CASET区间[52,186]、RASET区间[40,279]。
    • TE(Tearing Effect):刷屏同步信号引脚,本模组未引出;驱动对te-gpios做gpiod_get_optional,缺失时打印probed (TE not wired)并跳过TEAR_ON路径(st7789.c)。
  • 硬件连接

    • SPI0控制器:spi_bus0: spi@11070000(apps/demb_ev_board/bsp/dts/demb_hisupport.dtsi:),arm,pl022IP,num-cs=<2>,SPI屏挂在spi0.0。

      • 模组pin信号排针pinSoC功能
        GND地6/9/14/20/25/30/34/39任一GND
        VCC电源1或173.3V
        SCLSPI时钟23GPIO3_7 → SPI0_SCLK
        SDAMOSI19GPIO4_0 → SPI0_SDO
        RES复位27GPIO7_5 → GPIO
        DC数据/命令11GPIO0_1 → GPIO
        CS片选26GPIO7_0 → SPI0_CSN0
        BLK背光28GPIO7_4 → PWM1_OUT7
  • 驱动框架

    • samples_panel (LVGL, /dev/dri/card0)
            │  DRM_IOCTL dumb-buffer + modeset
            ▼
      st7789.ko ── mipi_dbi_dev_init ── drm_simple_display_pipe
            │  fb刷新 → st7789v_enable_flush → CASET/RASET(+offset) → RAMWR像素流
            ▼
      spi0.0 (pl022) → SPI0_SCLK/SDO/CSN0 + DC/RST GPIO → ST7789V GRAM → 屏
      
    • 驱动是变体补丁制:patches/下1/2.4/3.2/3.5寸各一个patch,CMakeLists.txt按ENABLE_*宏选择性打补丁到st7789.c.tmp再编ko(st7789v/CMakeLists.txt:26-58)——不新写驱动,只加一个新patch。

    • sample_panel应用的disp_init直接用lv_linux_drm_create()建LVGL显示,分辨率从DRM connector读,无需改代码(source/main.c)。

3.案例克隆与重命名

  • cp -r apps/demb_ev_board/samples/panel/st7789_240_320_28_50M \
          apps/demb_ev_board/samples/panel/st7789_135_240_114_50M
          
    vi hi_aiot_solution/apps/demb_ev_board/samples/panel/st7789_135_240_114_50M/BUILD.gn
    -executable("samples_panel_st7789_240_320_28_50M") {
    +executable("samples_panel_st7789_135_240_114_50M") {
    
    vi hi_aiot_solution/apps/demb_ev_board/samples/panel/st7789_135_240_114_50M/oh_product/BUILD.gn
    -  case_dts_dir = "//../apps/demb_ev_board/samples/panel/st7789_240_320_28_50M/dts"
    +  case_dts_dir = "//../apps/demb_ev_board/samples/panel/st7789_135_240_114_50M/dts"
    -    "//../apps/demb_ev_board/samples/panel/st7789_240_320_28_50M:samples_panel_st7789_240_320_28_50M",
    -    "//../apps/demb_ev_board/samples/panel/st7789_240_320_28_50M:sys_config_module",
    +    "//../apps/demb_ev_board/samples/panel/st7789_135_240_114_50M:samples_panel_st7789_135_240_114_50M",
    +    "//../apps/demb_ev_board/samples/panel/st7789_135_240_114_50M:sys_config_module",
    
    vi hi_aiot_solution/apps/demb_ev_board/samples/panel/st7789_135_240_114_50M/dts/BUILD.gn
    # panel/st7789_135_240_114_50M案例dts目录——hispark外部编译dtb时的同名覆盖源
    # (覆盖bsp/dts同名文件,如board_io_config.dtsi)。
    # 消费点:oh_product/BUILD.gn的board_dtb_uimage实例(case_dts_dir参数指向本目录)。
    group("dts") {
    }
    
    vi hi_aiot_solution/apps/demb_ev_board/samples/panel/st7789_135_240_114_50M/app.defconfig
    -# 功能:ST7789V SPI LCD + Goodix GT911 触摸屏 LVGL UI demo SPI速率50M 尺寸为2.8寸
    +# 功能:ST7789V SPI LCD LVGL UI demo SPI速率50M 尺寸为1.14寸(135x240,无触摸无TE)
    -#   - ST7789V LCD 驱动 / Goodix 触摸驱动
    +#   - ST7789V LCD 驱动(1.14" 135x240 变体,无触摸)
     CONFIG_DRV_LCD_ST7789V=y
     CONFIG_DRV_LCD_ST7789V_30FPS=y
    +CONFIG_DRV_LCD_ST7789V_1_14INCH=y
    -CONFIG_DRV_TOUCH_GOODIX=y
    +# CONFIG_DRV_TOUCH_GOODIX is not set
    
    vi hi_aiot_solution/apps/demb_ev_board/samples/panel/st7789_135_240_114_50M/oh_product/init_configs/etc/init.d/S82ohos
    #! /bin/sh
    
    insmod /ko/sys_config.ko
    
    cd /vendor/adapter/ko
    insmod ot_board_io_cfg.ko
    insmod st7789.ko
    
    cd /bin/samples/bin
    ./samples_panel_st7789_135_240_114_50M &
    

4.驱动补丁

  • vi hi_aiot_solution/components/adapter/drivers/lcd/st7789v/patches/1_14inch.patch
    From: hi_aiot_solution
    Subject: [PATCH] st7789v: 1.14" 135x240 module support (geometry + GRAM offsets)
    
    --- a/components/adapter/drivers/lcd/st7789v/st7789.c
    +++ b/components/adapter/drivers/lcd/st7789v/st7789.c
    @@ -108,7 +108,7 @@
     #define ST7789_MADCTL_MY	BIT(7)
     
    -#define PANEL_WIDTH   240
    -#define PANEL_HEIGHT  320
    +#define PANEL_WIDTH   135
    +#define PANEL_HEIGHT  240
     
     /* pl022 DMA 要求 TX/RX 缓冲区页对齐,用 alloc_pages 保证对齐 */
     #define DMA_BUF_BYTES  (PANEL_WIDTH * PANEL_HEIGHT * 2)
    @@ -379,7 +379,7 @@
     
     	mipi_dbi_command(dbi, ST7789_INVON);
    -	mipi_dbi_command(dbi, ST7789_CASET, 0x00, 0x00, 0x00, 0xef);
    -	mipi_dbi_command(dbi, ST7789_RASET, 0x00, 0x00, 0x00, 0xc5);
    +	mipi_dbi_command(dbi, ST7789_CASET, 0x00, 0x34, 0x00, 0xba);
    +	mipi_dbi_command(dbi, ST7789_RASET, 0x00, 0x28, 0x01, 0x17);
     	msleep(120);
     
     	if (priv->te_gpio) {
    @@ -465,7 +465,7 @@
     };
     
     static const struct drm_display_mode st7789v_mode = {
    -	DRM_SIMPLE_MODE(240, 320, 26, 30),
    +	DRM_SIMPLE_MODE(135, 240, 15, 26),
     };
     
     DEFINE_DRM_GEM_CMA_FOPS(st7789v_fops);
    @@ -577,6 +577,10 @@
     
     	dbi->command = st7789v_command;
     
    +	/* 1.14" 135x240: visible window inside the 240x320 GRAM */
    +	dbidev->left_offset = 52;
    +	dbidev->top_offset = 40;
    +
     	ret = mipi_dbi_dev_init(dbidev, &st7789v_pipe_funcs,
     		&st7789v_mode, rotation);
     	if (ret) {
    
    vi hi_aiot_solution/components/adapter/drivers/lcd/Kconfig(DRV_LCD_ST7789V_3_2INCH 之后插入)
    config DRV_LCD_ST7789V_1_14INCH
        bool "ST7789V 1.14 寸 135x240 模组(8pin SPI 小板)"
        default n
        depends on DRV_LCD_ST7789V
        help
          1.14 寸 ST7789V 模组的显示窗口在 240x320 GRAM 内偏置
          left_offset=52 / top_offset=40;分辨率 135x240。
     	
    vi hi_aiot_solution/components/adapter/drivers/lcd/st7789v/CMakeLists.txt(3_2inch 的 endif 之后插入)
    if(ENABLE_DRV_LCD_ST7789V_1_14INCH)
        list(APPEND _drv_patches "${_ST7789V_SRC_DIR}/patches/1_14inch.patch")
    endif()
    

5.设备树

  • vi hi_aiot_solution/apps/demb_ev_board/samples/panel/st7789_135_240_114_50M/dts/panel_config.dtsi
    /*
     * ST7789V(1.14" 135x240,50M,无触摸,无 TE)屏幕设备树片段。
     *
     * 通过"同名覆盖"机制覆盖 bsp/dts/panel_config.dtsi(默认 JD9853),
     * 使 bsp/dts 外部编译 dtb 时切到本屏。
     * 模组无触摸 → 不启用 i2c_bus1 触摸节点;模组无 TE 脚 → 不带 te-gpios。
     */
    
    / {
    	backlight: backlight {
    		compatible = "pwm-backlight";
    		pwms = <&pwm1 7 100000>;
    		brightness-levels = <0 27 28 29 31 32 34 35 37 39 40 42 44 46 48 50 51 53 55 57 59 61 63 65 67 69 71 74 76 78 80 82 84 87 89 91 93 95 98 100 102 105 107 109 112 114 116 119 121 123 126 128 130 133 135 138 140 143 145 148 150 153 155 158 160 163 165 168 170 173 175 178 180 183 186 188 191 193 196 199 201 204 206 209 212 214 217 220 222 225 228 230 233 236 239 241 244 247 250 252 255>;
    		default-brightness-level = <100>;
    		status = "okay";
    	};
    };
    
    &pwm1 {
    	#pwm-cells = <2>;
    };
    
    &i2c_bus1 {
    	/* 总线使能保留(基线行为);本模组无触摸,不挂子节点 */
    	status = "okay";
    };
    
    &spi_bus0 {
    	status = "okay";
    	dmas = <&edmacv310_0 7 7>, <&edmacv310_0 6 6>;
    	dma-names = "tx","rx";
    
    	st7789v_114:ips@0 {
    		compatible = "sitronix,st7789v_240x320";
    		reg = <0>;
    		pl022,interface = <0>;
    		pl022,com-mode = <2>;
    		spi-max-frequency = <50000000>;
    		pl022,tx-level-trig = <3>;
    		pl022,rx-level-trig = <3>;
    		rotation = <0>;
    		dc-gpios = <&gpio_chip0 1 0>;
    		reset-gpios = <&gpio_chip7 5 0>;
    		debug = <0>;
    		backlight = <&backlight>;
    		status = "okay";
    	};
    };
    

6.引脚配置:6根屏引脚条目

  • vi apps/demb_ev_board/samples/panel/st7789_135_240_114_50M/dts/board_io_config.dtsi
    pin-cfg@7{pin=<7>;gpio-num="GPIO0_1";function="GPIO0_1";pull="pull-down"; drive = "I06_level8";      slew = "fast"; };  /* DC   → 排针11 */
    pin-cfg@18 { pin = <18>; gpio-num = "GPIO7_4"; function = "PWM1_OUT7"; pull = "pull-up";   drive = "I02_level4";      slew = "fast"; };  /* BLK  → 排针28 */
    pin-cfg@19 { pin = <19>; gpio-num = "GPIO7_5"; function = "GPIO7_5";   pull = "pull-up";   drive = "I02_level4";      slew = "fast"; };  /* RES  → 排针27 */
    pin-cfg@46 { pin = <46>; gpio-num = "GPIO7_0"; function = "SPI0_CSN0"; pull = "pull-down"; drive = "I06_level8";      slew = "fast"; };  /* CS   → 排针26 */
    pin-cfg@84 { pin = <84>; gpio-num = "GPIO4_0"; function = "SPI0_SDO";  pull = "pull-down"; drive = "EMMC I0_level16"; slew = "fast"; };  /* SDA  → 排针19 */
    pin-cfg@85 { pin = <85>; gpio-num = "GPIO3_7"; function = "SPI0_SCLK"; pull = "pull-up";   drive = "EMMC I0_level16"; slew = "fast"; };  /* SCL  → 排针23 */
    

7.集成裁剪

  • vi apps/demb_ev_board/samples/panel/st7789_135_240_114_50M/rootfs/CMakeLists.txt(去掉 _GOODIX_KO 变量与拷贝行)
    set(_ST7789_KO  "${CMAKE_BINARY_DIR}/drivers/lcd/st7789v/st7789.ko")
    set(_PANEL_BIN  "${CMAKE_BINARY_DIR}/bin/samples_panel")
    
    add_custom_target(rootfs_panel_prepare
        COMMAND bash -c "if [ -f '${CMAKE_BINARY_DIR}/.clean_pending' ]; then rm -rf '${_IMAGE_DIR}'; fi"
        COMMAND ${CMAKE_COMMAND} -E rm -rf "${_ROOTFS_TMP}"
        COMMAND ${CMAKE_COMMAND} -E make_directory "${_ROOTFS_TMP}"
    
        COMMAND bash -c "cp -raf ${_BSP_PUB_ROOT}/rootfs_debug_musl_arm/. ${_ROOTFS_TMP}/"
    
        COMMAND ${CMAKE_COMMAND} -E make_directory "${_ROOTFS_TMP}/root/panel"
        COMMAND ${CMAKE_COMMAND} -E copy_if_different
            "${_PANEL_BIN}" "${_ROOTFS_TMP}/root/panel/samples_panel"
    
        # 驱动目录:MPP ko + st7789.ko(无触摸变体:不安装触摸 ko)
        COMMAND ${CMAKE_COMMAND} -E make_directory "${_ROOTFS_TMP}/drv"
        COMMAND ${CMAKE_COMMAND} -E copy_directory
            "${_MPP_OUT}/ko" "${_ROOTFS_TMP}/drv/ko"
        COMMAND ${CMAKE_COMMAND} -E copy_if_different
            "${_ST7789_KO}" "${_ROOTFS_TMP}/drv/st7789.ko"
        COMMAND ${CMAKE_COMMAND} -E copy_if_different
            "${CMAKE_BINARY_DIR}/drivers/board_io_cfg/ot_board_io_cfg.ko"
            "${_ROOTFS_TMP}/drv/ko/ot_board_io_cfg.ko"
        DEPENDS samples_panel drv_all board_io_cfg
        COMMENT "[panel/rootfs] 组装根文件系统..."
        VERBATIM
    )
    

8.编译烧录

  • source ~/demb_env.sh
    bash scripts/build.sh build --target demb_ev_board samples panel/st7789_135_240_114_50M
    # 传板(编译机):scp /tmp/mtdflash install/image/panel/uImage root@192.168.1.221:/tmp/
    # 板端(Xshell):
    chmod +x /tmp/mtdflash && mv /tmp/mtdflash /root/
    /root/mtdflash /dev/mtd2 /tmp/uImage && reboot
    
    • patch打补丁环节在st7789v/CMakeLists.txt内自动完成;bsp_make_opts的KERNEL_CFG沿用demb_drm_touch_defconfig

9.板端验证

  1. 模块加载与设备注册

    • insmod /drv/ko/sys_config.ko       # 已由启动脚本加载可跳
      insmod /drv/ko/ot_board_io_cfg.ko  # 应用引脚复用(同上)
      insmod /tmp/st7789.ko
      
      • dmesg预期:st7789v probed (TE not wired)、Initialized st7789v 1.0.0 ... for spi0.0、注册fb0;/dev/dri/card0出现。
  2. 显示验证(自写drmtest)

    • 板端无/dev/fb0节点(fbdev仿真没开),用libdrm写最小测试:dumb buffer填6条横向彩条+2px白框+中央黑十字,drmModeSetCrtc上屏常驻。

      • // drmtest.c - minimal DRM dumb-buffer modeset test for the board's SPI panels
        // Draws color bars + white border so panel offset/orientation can be checked.
        // 用法: drmtest [秒数(0=常驻)] [/dev/dri/cardN]
        #include <stdio.h>
        #include <stdlib.h>
        #include <string.h>
        #include <fcntl.h>
        #include <unistd.h>
        #include <stdint.h>
        #include <sys/mman.h>
        #include <xf86drm.h>
        #include <xf86drmMode.h>
        
        static uint16_t rgb565(uint8_t r, uint8_t g, uint8_t b) {
            return ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3);
        }
        
        int main(int argc, char **argv)
        {
            int secs = argc > 1 ? atoi(argv[1]) : 30;
            const char *card = argc > 2 ? argv[2] : "/dev/dri/card0";
            int fd = open(card, O_RDWR);
            if (fd < 0) { perror("open"); return 1; }
        
            drmModeRes *res = drmModeGetResources(fd);
            if (!res) { perror("resources"); return 1; }
            if (!res->count_connectors) { fprintf(stderr, "no connector\n"); return 1; }
            drmModeConnector *conn = drmModeGetConnector(fd, res->connectors[0]);
            if (!conn || conn->connection != DRM_MODE_CONNECTED || !conn->count_modes) {
                fprintf(stderr, "no connected/mode\n"); return 1; }
            drmModeModeInfo *mode = &conn->modes[0];
            uint32_t w = mode->hdisplay, h = mode->vdisplay;
            printf("mode: %dx%d @%dHz name=%s\n", w, h, mode->vrefresh, mode->name);
        
            uint32_t crtc_id = res->crtcs[0];
        
            struct drm_mode_create_dumb creq = {0};
            creq.width = w; creq.height = h; creq.bpp = 16;
            if (drmIoctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &creq)) {
                perror("create_dumb"); return 1; }
        
            struct drm_mode_map_dumb mreq = {0};
            mreq.handle = creq.handle;
            if (drmIoctl(fd, DRM_IOCTL_MODE_MAP_DUMB, &mreq)) {
                perror("map_dumb"); return 1; }
            uint16_t *fb = mmap(0, creq.size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, mreq.offset);
            if (fb == MAP_FAILED) { perror("mmap"); return 1; }
        
            // pattern: 6 horizontal color bars + 2px white border + center black cross
            static const uint8_t cols[6][3] = {
                {255,0,0}, {0,255,0}, {0,0,255}, {255,255,0}, {0,255,255}, {255,0,255} };
            for (uint32_t y = 0; y < h; y++)
                for (uint32_t x = 0; x < w; x++) {
                    int bar = y * 6 / h;
                    uint16_t px = rgb565(cols[bar][0], cols[bar][1], cols[bar][2]);
                    if (x < 2 || y < 2 || x >= w-2 || y >= h-2) px = 0xFFFF;
                    if (x == w/2 || y == h/2) px = 0x0000;
                    fb[y * w + x] = px;
                }
        
            uint32_t fb_id;
            if (drmModeAddFB(fd, w, h, 16, 16, creq.pitch, creq.handle, &fb_id)) {
                perror("addfb"); return 1; }
            if (drmModeSetCrtc(fd, crtc_id, fb_id, 0, 0, &conn->connector_id, 1, mode)) {
                perror("setcrtc"); return 1; }
        
            if (secs <= 0) {
                printf("displaying forever (Ctrl+C to stop)...\n");
                for (;;) sleep(60);
            }
            printf("displaying for %ds...\n", secs);
            sleep(secs);
        
            drmModeRmFB(fd, fb_id);
            struct drm_mode_destroy_dumb dreq = { .handle = creq.handle };
            drmIoctl(fd, DRM_IOCTL_MODE_DESTROY_DUMB, &dreq);
            close(fd);
            return 0;
        }
        
    • 编译运行

      • #编译
        TC=~/toolchains/gcc-10.3-arm-musl-x86-linux-26.06.1/arm-v01c02-linux-musleabi-gcc/bin
        DR=~/tmp/hi_aiot_solution/_build/open_source/drm/release
        $TC/arm-linux-musleabi-gcc -static -O2 -o /tmp/drmtest /tmp/drmtest.c \
            -I$DR/include -I$DR/include/libdrm $DR/lib/libdrm.a
        # 产物: /tmp/drmtest(~300KB 静态 musl ELF,板端零依赖)
        
        #运行测试
        # 传板(编译机):scp /tmp/drmtest root@192.168.1.221:/tmp/(或Xftp拖拽)
        # —— 以下在板端(Xshell)执行:
        insmod /tmp/st7789.ko          # 已加载可跳;成功后/dev/dri/card0出现
        killall samples_panel          # 若有app占着card0先杀
        /tmp/drmtest 0                 # 0=常驻显示;给秒数则到时自动退出
        
      • 结果:mode: 135x240模式设置成功,画面实机可见。

        • image-20261110102751358

3.TF卡与USB大容量存储

3.1 启用tf卡

环境:ws73_lcd出厂镜像 + 拨码SW1301-1拨到ON(TF模式)+ 插卡重启

现象:能枚举出型号容量(说明CMD通),但一个扇区都读不出(说明数据路断)

  • 根因:拨码只管物理路由,SW1301-1不管引脚功能,把SDIO0的8根引脚从"40PIN排针"扳到"TF卡槽"。但SoC在这几根脚上跑什么协议,由pin_mux(iocfg寄存器)决定。board_io_cfg.ko开机按bsp/dts/board_io_config.dtsi配iocfg寄存器(基址0x10260000`)。实测默认引脚归属:

    • 偏移引脚SDIO0角色被配成谁在用
      0x34GPIO4_0CLKSPI0_SDO屏
      0x30GPIO3_7DAT0SPI0_SCLK屏
      0x28GPIO3_5CDGPIO(屏TE)屏
      0x3CGPIO4_2DAT3GPIO(触摸RST)触摸
      0x38GPIO4_1CMDI2S_BCLK音频ko(insmod时写)
      0x40GPIO4_3DAT2I2S_WS音频
      0x44GPIO3_4卡电源I2S_SD_RX音频
      0x2CGPIO3_6DAT1SDIO0 ✓唯一幸存
  • 调整 & 测试

    1. 方式一:bspmm运行期改寄存器——免刷机、重启还原、随改随验

      # ============================================================
      # 开发板 TF卡 运行期启用 + 完整测试(免刷机,重启还原)
      # 前提:拨码 SW1301-1 = ON(物理切到TF卡槽)、TF卡已插
      # ============================================================
      
      # 1.修引脚复用(6刀:抢回被屏/触摸/I2S占走的SDIO0脚)
      bspmm 0x10260030 0x11e1    # GPIO3_7  DAT0   原SPI0_SCLK → SDIO0
      bspmm 0x10260034 0x12c1    # GPIO4_0  CLK    原SPI0_SDO  → SDIO0
      bspmm 0x10260038 0x11e1    # GPIO4_1  CMD    原I2S_BCLK  → SDIO0
      bspmm 0x1026003C 0x1101    # GPIO4_2  DAT3   原触摸RST   → SDIO0
      bspmm 0x10260040 0x1101    # GPIO4_3  DAT2   原I2S_WS    → SDIO0
      bspmm 0x10260044 0x1101    # GPIO3_4  卡电源  原I2S_SD_RX → SDIO0
      # 注意:0x10260028 (GPIO3_5,CD) 保持0x1100不改——驱动按GPIO读插拔检测
      
      # 2.验证寄存器(可选,应看到低4位全是1,仅0x28是0)
      bspmd.l 0x10260028 0x20
      
      # 3.重新枚举卡
      echo 10030000.SDIO > /sys/bus/platform/drivers/sdhci_nebula/unbind
      sleep 1
      echo 10030000.SDIO > /sys/bus/platform/drivers/sdhci_nebula/bind
      sleep 3
      
      # 4.确认卡设备
      ls -l /dev/mmcblk*              # 应见 mmcblk0 + mmcblk0pN
      dmesg | tail -6                 # 应见 "new high speed SDXC/SDHC card" + pN 分区
      # ⚠️ 不要 cat /proc/mci/mci_info ——插拔瞬间读它会kernel panic
      
      # 5.读测试
      dd if=/dev/mmcblk0 of=/dev/null bs=1M count=4
      # 通过标志:4.0MB copied(之前是 dd: I/O error)
      
      # 6.看分区/文件系统
      fdisk -l /dev/mmcblk0
      mkdir -p /mnt/tf
      mount /dev/mmcblk0p1 /mnt/tf    # 已有FAT32直接挂;挂载失败=需格式化
      ls -l /mnt/tf && df -h /mnt/tf
      
      # 7.写+校验测试
      dd if=/dev/urandom of=/mnt/tf/test.bin bs=1M count=10
      sync
      md5sum /mnt/tf/test.bin          # 记下哈希
      umount /mnt/tf && mount /dev/mmcblk0p1 /mnt/tf
      md5sum /mnt/tf/test.bin          # 两次哈希一致 = 写落盘真实
      rm /mnt/tf/test.bin && sync
      
      # 8.(可选)格式化
      umount /mnt/tf
      mkfs.vfat /dev/mmcblk0p1         # 整卡单分区FAT32,PC可读
      mount /dev/mmcblk0p1 /mnt/tf
      
      # 9.还原(不用跑,重启即自动还原)
      # 本方案是运行期寄存器修改:reboot后全部恢复为屏/触摸/I2S原配置
      # 副作用提醒:TF启用期间 喇叭/I2S音频 不可用(脚被夺)
      
    2. 方式二:dtsi改源码 → 编译 → 刷mtd2——开机原生支持、不可逆(除非回刷)

      #1.改源码 demb_ev_board\references\factory_demo\ws73_lcd\dts\board_io_config.dtsi
      (1)3处function修改
       pin-cfg@82 {  pin=<82>;  gpio-num="GPIO4_2";
      -    function = "GPIO4_2";        /* 触摸复位 */
      +    function = "SDIO0_CDATA3";   /* DAT3 */
      
       pin-cfg@84 {  pin=<84>;  gpio-num="GPIO4_0";
      -    function = "SPI0_SDO";       /* 屏SPI数据 */
      +    function = "SDIO0_CCLK_OUT"; /* CLK */
      
       pin-cfg@85 {  pin=<85>;  gpio-num="GPIO3_7";
      -    function = "SPI0_SCLK";      /* 屏SPI时钟 */
      +    function = "SDIO0_CDATA0";   /* DAT0 */
      (2)3个pin-cfg整块新增
      pin-cfg@79 {  pin=<79>;  gpio-num="GPIO3_4";  function="SDIO0_CARD_POWER_EN_N"; ... }  // 卡电源(原I2S_SD_RX)
      pin-cfg@81 {  pin=<81>;  gpio-num="GPIO4_3";  function="SDIO0_CDATA2";          ... }  // DAT2(原I2S_WS)
      pin-cfg@83 {  pin=<83>;  gpio-num="GPIO4_1";  function="SDIO0_CCMD";            ... }  // CMD(原I2S_BCLK)
      
      #2.编译
      touch sdk/demb/third_party/linux/linux-5.10.y/.scmversion
      cd sdk/demb/third_party/linux/linux-5.10.y
      git checkout drivers/vendor/Makefile
      export PATH=/home/nancy/miniconda3/bin:/home/nancy/toolchains/gcc-10.3-arm-musl-x86-linux-26.06.1/arm-v01c02-linux-musleabi-gcc/bin:$PATH
      cd ~/tmp/hi_aiot_solution
      bash scripts/build.sh build --target demb_ev_board references factory_demo/ws73_lcd 2>&1 | tee /tmp/build_tf.log
      sha256sum sdk/demb/boards/dmeb/pub/demb_image_debug_musl/uImage
      
      #3.传板 + 烧录(只刷mtd2)
      # 传板(编译机):
      #   scp /tmp/mtdflash sdk/demb/boards/dmeb/pub/uImage root@192.168.1.221:/tmp/
      #   (或Xftp拖拽;uImage到板端改名 /tmp/uImage_new)
      # —— 以下在板端(Xshell)执行:
      chmod +x /tmp/mtdflash && mv /tmp/uImage /tmp/uImage_new
      /tmp/mtdflash /dev/mtd2 /tmp/uImage_new
      # 回读校验,必须等于编译机哈希:
      dd if=/dev/mtdblock2 bs=1M count=4 | head -c $(stat -c%s /tmp/uImage_new) | sha256sum
       
      #4.重启验证(不打bspmm)
      ls /dev/mmcblk*                                   # mmcblk0 + p1
      dd if=/dev/mmcblk0 of=/dev/null bs=1M count=4     # ~19.7MB/s
      mount /dev/mmcblk0p1 /mnt/tf                      # 读写+md5 重挂校验
      lsmod | grep ot_                                  # 修好后MPP ko全栈加载
      
      #5.若提前备份,可快速回滚
      # 若备份在 demb_board_backup_20261103\mtd2_lcd.bin,先传到板端 /tmp/mtd2.bak
      # (编译机:scp mtd2_lcd.bin root@192.168.1.221:/tmp/mtd2.bak,或Xftp),板端执行:
      /root/img/mtdflash /dev/mtd2 /tmp/mtd2.bak && \
        dd if=/dev/mtdblock2 bs=1M count=4 | head -c 4194304 | sha256sum && reboot
      

      坑1 vermagic:ko按5.10.221编 / 内核是5.10.221+——厂 Makefile无条件调setlocalversion,git树无tag就补"+"。

      • 修复:touch third_party/linux/linux-5.10.y/.scmversion(空文件,官方旁路)

      坑2 dup symbol:vermagic修好后insmod还挂,真错是exports duplicate symbol sys_ctl (owned by kernel)——drivers/vendor/Makefile 被 fastboot/ws53_lp 的 kmod_builtin 残留补丁加了MPPKO_BUILTIN := y,整套MPP驱动编进了vmlinux,ko自然撞车(也解释了新zImage比旧的胖~300KB)。

      修复:git checkout drivers/vendor/Makefile → 重编zImage → 复刻dts→dtb→FIT(暂存6文件+gcc -E+dtc+mkimage)→ 刷入

    3. 方式三:结合方式一构建脚本自行切换

      • bootsel lcd    # 回屏版(刷+sha256校验+reboot)
        bootsel tf     # 回TF版
        

      或可调整start_ws73_lcd.sh

      1. dtsi默认SDIO0(就用刚刚的TF镜像);
      2. start_ws73_lcd.sh在Step1后试读卡:成功→跳过lcd/touch加载;失败→bspmm 把 6 个寄存器写回屏/I2S配置再正常加载

      再或者就是优化调整uboot或者硬件(略)

3.2 Type-C连PC映射U盘(configfs gadget)

目标:Type-C连PC → TF卡映射为U盘

# ============================================================
# 开发板 Type-C连PC → TF卡映射为U盘(纯手工命令)
# 前提:TF镜像 + DIP1=ON + 卡已插(本流程重启后需重跑)
# ============================================================

#1.确认device模式(开机默认就是,保险确认)
cat /proc/wing-usb/10300000.usb20drd/mode    # 应回显 device
echo device > /proc/wing-usb/10300000.usb20drd/mode   # 不是就写一次
sleep 2

#2.确认卡活着
ls /dev/mmcblk0                                    # 应有节点
dd if=/dev/mmcblk0 of=/dev/null bs=1M count=1      # 应正常读出
# 若没节点或读失败:执行 unbind/bind 重枚举(见文末B)

#3.板端卸载卡(PC独占,防双写毁文件系统)
umount /dev/mmcblk0p1 2>/dev/null
umount /mnt/tf 2>/dev/null

#4.搭configfs gadget
mount -t configfs none /sys/kernel/config
G=/sys/kernel/config/usb_gadget/g1
mkdir -p $G
echo 0x1d6b > $G/idVendor
echo 0x0104 > $G/idProduct
echo high-speed > $G/max_speed
mkdir -p $G/strings/0x409
echo YueYing > $G/strings/0x409/manufacturer
echo "YueYing TF Card" > $G/strings/0x409/product
echo yytf001 > $G/strings/0x409/serialnumber      # Windows必需
mkdir -p $G/configs/c.1/strings/0x409
echo "Config 1" > $G/configs/c.1/strings/0x409/configuration
echo 250 > $G/configs/c.1/MaxPower
mkdir -p $G/functions/mass_storage.0
echo /dev/mmcblk0 > $G/functions/mass_storage.0/lun.0/file
ln -s $G/functions/mass_storage.0 $G/configs/c.1/
 
#5.绑定UDC(激活)
echo 10300000.dwc3 > $G/UDC

#6.验证
cat /sys/class/udc/10300000.dwc3/state           # 插线前 not attached
bspmd.l 0x1030c704 4                             # DCTL第1个值应0x8xxxxxxx(上拉已开)
 
#7.插Type-C到PC
cat /sys/class/udc/10300000.dwc3/state           # → configured = PC枚举成功
cat /sys/class/udc/10300000.dwc3/current_speed   # → high-speed
# PC资源管理器出现"U盘"

#8.退出/收尾:PC端先"安全弹出"盘符,然后板端
echo "" > /sys/kernel/config/usb_gadget/g1/UDC    # 解绑
mount /dev/mmcblk0p1 /mnt/tf                      # 板子重新用卡
  • image-20261104134954909

十、体验总结

1.对开发板的体验总结

折腾下来,这块板子给我的感受可以概括为:麻雀虽小,出厂即飞。

让人惊喜的点

  • 开箱完成度罕见的高:上电不进命令行,屏直接亮LVGL九页UI——亮度滑条、摄像头控制、倒计时、AI检测、AI助手、设置页全是能点的真功能,不是摆设demo。摄像头+编码+RTSP+触控+BLE配网+ZeroClaw Agent六合一一次点亮,同价位里我没见过第二家。
  • AI助手是真能用的:出厂就接了ZeroClaw Agent——屏上打字(拼音IME)、持续会话、“帮我拍张照”"画面里有什么"都能调板子能力,不是只能聊天的玩具。
  • 星闪WS73是独家卖点:一块扩展板同时给WiFi/BLE/SLE三协议,SLE调参后avg 58KB/s/peak 97KB/s,BLE空口~30KB/s,和低延迟近场场景很配。
  • 硬件留的余量实在:2×MIPI CSI双摄、2路模拟麦+喇叭+回采、40pin排针(SPI/I2C/UART/SDIO/PWM/LSADC全引)、TF卡槽、RTC、DIP拨码——HC-05、TF卡、新屏、USB Gadget都是我自己接出来跑通的。
  • SDK是产品级组件化:hi_aiot_solution按components/samples/references分层,案例即产品(factory_demo直接可当门铃固件雏形),比"一堆松散demo"的SDK强一截。

需要提醒的点

  • 内存是硬约束:128MB DDR3L——LVGL+MPP+ZeroClaw同时跑已经很挤,别指望再塞大应用。
  • 性能是轻量级:双核950MHz/1TOPS——人脸识别、多路视频、大模型本地推理别想了,它干的是"看得懂有人经过"这类轻活。
  • 开发要Linux编译机:SDK全量编译对新手有门槛(本文环境搭建一节就是踩坑记录),不过单文件热部署循环很快。
  • 细节糙点:fbdev仿真没开(要用libdrm)、/tmp重启即清、busybox缺flashcp类工具——都能绕,但会踩一下。

一句话:如果目标是低成本、低功耗、快速落地的视觉+语音+轻交互终端(门铃/猫眼/宠物陪伴/养老看护/智能家居中控屏),这块板子是我玩过"出厂即能用"程度最高的选择;要算力/大屏/桌面生态→看RK3588,要专业安防ISP→看Hi3519DV500。

2.开发板购买链接

  • 淘宝购买页:轻AI越影视觉开发板

    • 本文这套对应套餐4:主板 + WS73扩展板 + 2.8寸屏 + Sensor模组 + 喇叭;同页另有单板、WS53扩展板、Hi2131 4G扩展板、1.28寸双圆屏/2.1寸圆屏等套餐SKU可选
  • 官方资料页(原理图/装配图/Datasheet/SDK文档):开发板产品介绍

十一、附录

1.mtdflash—极简MTD烧录工具

  • 用途:板端busybox无flashcp/nandwrite/mtd_debug时的替代品——把镜像文件写进/dev/mtdN字符设备分区。

  • 用法:mtdflash /dev/mtd2 uImage

    • /* mtdflash <mtd> <img> — erase + writesize-aligned write to NAND partition */
      #include <stdio.h>
      #include <stdlib.h>
      #include <string.h>
      #include <fcntl.h>
      #include <unistd.h>
      #include <sys/ioctl.h>
      #include <sys/stat.h>
      #include <mtd/mtd-abi.h>
      
      int main(int argc, char **argv)
      {
          if (argc < 3) { fprintf(stderr, "usage: %s /dev/mtdN image\n", argv[0]); return 1; }
          int mtd = open(argv[1], O_RDWR | O_SYNC);
          if (mtd < 0) { perror("open mtd"); return 1; }
          int img = open(argv[2], O_RDONLY);
          if (img < 0) { perror("open img"); return 1; }
          struct stat st; fstat(img, &st);
          size_t imgsz = st.st_size;
      
          struct mtd_info_user mi;
          if (ioctl(mtd, MEMGETINFO, &mi) < 0) { perror("MEMGETINFO"); return 1; }
          printf("mtd: size=%u erase=%u write=%u img=%zu\n", mi.size, mi.erasesize, mi.writesize, imgsz);
          if (imgsz > mi.size) { fprintf(stderr, "image too big\n"); return 1; }
      
          struct erase_info_user ei = { .start = 0, .length = mi.size };
          if (ioctl(mtd, MEMERASE, &ei) < 0) { perror("MEMERASE"); return 1; }
          printf("erased\n");
      
          size_t chunk = mi.writesize;
          unsigned char *buf = malloc(chunk);
          size_t off = 0; int bad = 0;
          while (off < imgsz) {
              size_t n = imgsz - off < chunk ? imgsz - off : chunk;
              memset(buf, 0xFF, chunk);
              if (read(img, buf, n) != (ssize_t)n) { perror("read"); return 1; }
              ssize_t w = pwrite(mtd, buf, chunk, off);
              if (w != (ssize_t)chunk) { perror("pwrite"); bad = 1; break; }
              off += n;
          }
          printf("%s wrote %zu bytes\n", bad ? "FAIL" : "OK", off);
          return bad;
      }
      
      

2.40pin排针引脚功能表

Pin信号/网络IOCFG 寄存器可用功能(f#)
13.3V—电源 3.3V
25V—电源 5V
3GPIO1_50x11130000f0:GPIO / f1:I2C1_SDA / f2:PWM0_OUT2 / f3:UART2_RXD / f4:LSADC_CH1
45V—电源 5V
5GPIO1_40x11130004f0:GPIO / f1:I2C1_SCL / f2:PWM0_OUT3 / f3:UART2_TXD / f4:LSADC_CH0
6GND—地
7GPIO0_00x10260000f0:GPIO(UPDATE_MODE 网络,无其他复用)
8GPIO0_70x11130034f0:JTAG_TDI / f1:ETH_LINK_ACT_LED / f2:ETH_STA_ACT_LED / f3:I2C0_SDA / f4:USB2_PWREN / f5:UART1_TXD / f6:GPIO / f7:PWM0_OUT2
9GND—地
10GPIO0_60x11130030f0:JTAG_TRSTN / f1:ETH_LINK_STA_LED / f2:GPIO / f3:I2C0_SCL / f5:UART1_RXD / f6:SPI0_CSN1 / f7:PWM0_OUT1
11GPIO0_10x10260004f0:GPIO / f1:PWM0_OUT3 / f2:BOOT_SEL1
12GPIO4_1 ※D0x10260038f0:GPIO / f1:SDIO0_CCMD / f4:SPI0_SDI / f5:PWM1_OUT4 / f6:I2S_BCLK / f7:UART1_RXD
13GPIO1_00x1113003Cf0:GPIO / f1:SDIO1_CDATA3 / f3:I2S_SD_TX / f5:UART1_CTSN / f6:SPI1_SDI / f7:PWM1_OUT1
14GND—地
15GPIO1_30x11130044f0:JTAG_TCK / f1:SDIO1_CCLK_OUT / f2:GPIO / f3:I2S_WS / f6:SPI1_SCLK / f7:PWM1_OUT3
16GPIO1_20x11130040f0:GPIO / f1:SDIO1_CCMD / f3:I2S_BCLK / f5:SENSOR1_RSTN / f6:SPI1_CSN / f7:PWM1_OUT2
173.3V—电源 3.3V
18GPIO1_10x11130048f0:GPIO / f1:SDIO1_CDATA0 / f3:I2S_SD_RX / f5:UART2_RXD / f6:SPI0_SDO / f7:PWM1_OUT4
19GPIO4_0 ※D0x10260034f0:GPIO / f1:SDIO0_CCLK_OUT / f2:TEST_MODE / f4:SPI0_SDO / f5:PWM1_OUT3 / f6:I2S_MCLK
20GND—地
21GPIO7_10x17940094f0:GPIO / f1:VI_BT1120_CLK¹ / f3:SPI0_SDI / f4:SENSOR0_RSTN / f5:I2C1_SCL / f7:SENSOR0_VS
22GPIO7_60x1113004Cf0:GPIO / f1:SDIO1_CDATA1 / f5:UART2_TXD / f6:SPI0_SDI / f7:PWM1_OUT5
23GPIO3_7 ※D0x10260030f0:GPIO / f1:SDIO0_CDATA0 / f4:SPI0_SCLK / f5:PWM1_OUT2 / f7:SENSOR1_RSTN
24GPIO3_6 ※D0x1026002Cf0:GPIO / f1:SDIO0_CDATA1 / f4:SPI0_CSN1 / f5:PWM1_OUT1 / f6:I2C2_SCL / f7:UART2_TXD
25GND—地
26GPIO7_00x17940090f0:GPIO / f1:VI_BT1120_CLK¹ / f3:SPI0_CSN0 / f5:I2C1_SDA / f6:VI_HS / f7:SENSOR0_HS
27GPIO7_50x11130050f0:JTAG_TMS / f1:SDIO1_CARD_DETECT / f2:SENSOR1_RSTN / f3:I2C2_SDA / f5:GPIO / f6:SPI0_SCLK / f7:PWM1_OUT6
28GPIO7_40x11130054f0:JTAG_TDO / f1:SDIO1_CARD_POWER_EN_N / f3:I2C2_SCL / f5:GPIO / f6:SPI0_CSN0 / f7:PWM1_OUT7
29GPIO6_3 ※M0x1794000Cf0:MIPI_RX_D3P / f1:GPIO / f2:VI_BT1120_DATA11 / f3:VI_DATA8 / f7:PWM0_OUT1
30GND—地
31GPIO6_2 ※M0x17940008f0:MIPI_RX_D3N / f1:GPIO / f2:VI_BT1120_DATA10 / f3:VI_DATA9 / f7:SENSOR0_RSTN
32GPIO3_5 ※D0x10260028f0:GPIO / f1:SDIO0_CARD_DETECT / f2:EMMC_RST_N / f3:SFC_CSN1 / f5:PWM1_OUT0 / f6:I2C2_SDA / f7:UART2_RXD
33GPIO6_1 ※M0x17940014f0:MIPI_RX_D1P / f1:GPIO / f2:VI_BT1120_DATA13 / f3:VI_DATA7 / f7:PWM0_OUT3
34GND—地
35GPIO4_3 ※D0x10260040f0:GPIO / f1:SDIO0_CDATA2 / f4:UART2_RXD / f5:PWM1_OUT6 / f6:I2S_WS / f7:UART1_RTSN
36GPIO6_0 ※M0x17940010f0:MIPI_RX_D1N / f1:GPIO / f2:VI_BT1120_DATA12 / f3:VI_CLK / f7:PWM0_OUT2
37GPIO7_70x11130038f0:GPIO / f1:SDIO1_CDATA2 / f3:I2S_MCLK / f5:UART1_RTSN / f6:SPI1_SDO / f7:PWM1_OUT0
38GPIO3_4 ※D0x10260044f0:GPIO / f1:SDIO0_CARD_POWER_EN_N / f4:UART2_TXD / f5:PWM1_OUT7 / f6:I2S_SD_RX / f7:UART1_CTSN
39GND—地
40GPIO4_2 ※D0x1026003Cf0:GPIO / f1:SDIO0_CDATA3 / f4:SPI0_CSN0 / f5:PWM1_OUT5 / f6:I2S_SD_TX / f7:UART1_TXD

3.电容触摸skill

这是我在适配过程中沉淀的一个skill(放在仓库 .agents/skills/ 下),已单独开源:gitlab.com/moonnancy881-dotcom/touch-bringup-skill,把它作为经验打包形式一并记录在此。

功能:factory_demo/ws73_lcd这类合并应用换一块带电容触摸的新屏模组时的全流程及问题排查

  1. 拿到一块新屏模组后,skill引导完成全流程

    • 参数收集:触摸IC型号、I2C总线/地址、INT/RST接哪个GPIO、触点分辨率——缺项必问不猜
    • 驱动匹配:自动探测 components/adapter/drivers/touch/(hynitron/goodix/edt_ft5x06)和内核树,IC不在其中就停止报告,不做从零移植
    • 代码落地:改5个点——panel_config.dtsi(触摸节点)、board_io_config.dtsi(引脚复用,仅接线变时)、app.defconfig(驱动开关)、rootfs/CMakeLists.txt(ko安装,顺带修 _HYNITRON_KO 硬编码坑)、启动脚本insmod行
    • 增量编译 + 构建后四项产物验证
  2. 板端六层故障定位

    • L0 I2C物理层 → L1 probe → L2 input设备 → L3 事件上报 → L4 LVGL消费 → L5 坐标 → L6 稳定性
      
      • 每层给具体命令(i2cdetect/dmesg//proc/bus/input/devices)和故障对照表,“每层不过就停在该层修,不要跳层”
  3. evdump工具(自研,已实测):板子没有evtest,skill自带scripts/evdump.c——50行evdev事件打印器,交叉编译静态传板就能看触摸原始事件流。已在真板验证(还顺手修了EVIOCGNAME的bug)。

    • # 编译机交叉编译 → 传到板端(scp/Xftp) → 板端跑
      arm-v01c02-linux-musleabi-gcc -O2 -static -o evdump evdump.c   # 编译机
      # scp evdump root@192.168.1.221:/tmp/   (或Xftp拖拽)
      # —— 以下在板端(Xshell)执行:
      chmod +x /tmp/evdump
      /tmp/evdump /dev/input/event0    # 触摸屏幕看 ABS_MT_POSITION_X/Y 事件流
      
  4. ko热替换调试:改触摸驱动/dts属性后不用重启不重烧:rmmod touch_panel.ko → insmod新ko → dmesg看probe,一轮几十秒。

架构

  • hi_aiot_solution/.agents/skills/hi-aiot-demb-touch-bringup/
    ├── SKILL.md                        ← 主入口(Agent 运行指令)
    ├── README.md                       ← 说明文档
    ├── references/
    │   ├── info-collection.md          ← 参数收集+EVB接线基线
    │   ├── driver-availability.md      ← 三驱动匹配
    │   ├── integration.md              ← 落地集成五步+§9验证
    │   └── board-debug.md              ← 板端六层故障树
    └── scripts/
        └── evdump.c                    ← 板端 evdev 事件打印工具
    
Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐