<?xml version="1.0" encoding="utf-8"?><?xml-stylesheet type="text/xsl" href="rss.xsl"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <channel>
        <title>东山Π Blog</title>
        <link>https://zephyr.100ask.org/en/blog</link>
        <description>东山Π Blog</description>
        <lastBuildDate>Wed, 10 Dec 2025 00:00:00 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <language>en</language>
        <item>
            <title><![CDATA[OPENWRT System 5: Docker Use Case Guide]]></title>
            <link>https://zephyr.100ask.org/en/blog/openwrt-docker</link>
            <guid>https://zephyr.100ask.org/en/blog/openwrt-docker</guid>
            <pubDate>Wed, 10 Dec 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[Deploy applications using Docker on OpenWrt.]]></description>
            <content:encoded><![CDATA[<p>Docker is an open-source containerization platform that encapsulates applications and their runtime environments through "containers", enabling applications to run quickly and stably across different systems. Containers are lightweight, start fast, and consume few resources, making them suitable for microservice deployment and continuous integration/delivery. Docker also provides image management, version control, and environment consistency, keeping development, testing, and production environments unified, greatly improving deployment efficiency and portability. Docker allows developers to package their applications and dependencies into a lightweight, portable container, then publish to any popular Linux machine, and can also implement virtualization.</p>
<p>Hardware environment: OpenWrt runs on a high-performance ARM SBC (such as the Dshanpi-A1 used in this article), with common home devices like an optical modem + switch/AC/AP.<br>
<!-- -->Goal: Use Docker on this SBC to run <strong>home theater + downloader + network drive + ad filtering + simple monitoring</strong>, one machine for multiple uses.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="home-network">Home Network<a href="https://zephyr.100ask.org/en/blog/openwrt-docker#home-network" class="hash-link" aria-label="Direct link to Home Network" title="Direct link to Home Network" translate="no">​</a></h2>
<ul>
<li class="">Optical modem in bridge mode, delegating PPPoE dialing to OpenWrt on the ARM SBC</li>
<li class="">ARM SBC serves both as the main router and as a "lightweight NAS + home theater server"</li>
<li class="">TV box, mobile phone, and computer are all connected to the LAN (wired or wireless), uniformly accessing services on the SBC</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="machine-configuration">Machine Configuration<a href="https://zephyr.100ask.org/en/blog/openwrt-docker#machine-configuration" class="hash-link" aria-label="Direct link to Machine Configuration" title="Direct link to Machine Configuration" translate="no">​</a></h2>
<ul>
<li class=""><strong>Device</strong>: ARM 64-bit architecture SBC, 8G memory version</li>
<li class=""><strong>System</strong>: OpenWrt (self-compiled/integrated firmware both work, the key is to have Docker)</li>
<li class=""><strong>Disk</strong>:<!-- -->
<ul>
<li class="">System disk (eMMC/TF) for OpenWrt</li>
<li class="">External SSD/HDD/large USB drive as data disk, mounted to <code>/mnt/data</code></li>
</ul>
</li>
</ul>
<h1>Docker Environment &amp; Directory Planning</h1>
<p>First confirm the environment and directory planning, which makes maintenance easier later. This step is critical.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="install-docker--docker-compose">Install Docker / Docker Compose<a href="https://zephyr.100ask.org/en/blog/openwrt-docker#install-docker--docker-compose" class="hash-link" aria-label="Direct link to Install Docker / Docker Compose" title="Direct link to Install Docker / Docker Compose" translate="no">​</a></h2>
<p>If your firmware already has Docker packaged, you can skip the installation. It is recommended to install luci-app-dockerman, which is a dedicated Docker Web management interface plugin for OpenWrt:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">opkg install luci-lib-docker dockerd luci-lib-jsonc docker ttyd --force-depends</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">opkg install luci-app-dockerman</span><br></div></code></pre></div></div>
<ul>
<li class=""><code>dockerd</code>: Docker daemon</li>
<li class=""><code>docker</code>: Command-line client</li>
<li class=""><code>luci-lib-docker</code> / <code>luci-lib-jsonc</code>: Dockerman dependencies</li>
<li class=""><code>ttyd</code>: For Web terminal and container console</li>
<li class=""><code>luci-app-dockerman</code>: Web management interface plugin</li>
</ul>
<p>Start and set to auto-start on boot:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">/etc/init.d/dockerd start</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">/etc/init.d/dockerd enable</span><br></div></code></pre></div></div>
<p>Then access the LuCI backend, and the menu will have an additional: <strong>Services / Docker</strong> or <strong>Services / Dockerman</strong>.</p>
<p>You can also confirm the environment works via command line, as shown below:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">root@LEDE:~# docker version</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Client:</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> Version:           28.0.4</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> API version:       1.48</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> Go version:        go1.25.4</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> Git commit:        b8034c0</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> Built:             Sun Sep  7 14:53:18 2025</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> OS/Arch:           linux/arm64</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> Context:           default</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Server:</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> Engine:</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  Version:          28.0.4</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  API version:      1.48 (minimum version 1.24)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  Go version:       go1.25.4</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  Git commit:       6430e49</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  Built:            Sun Sep  7 14:53:18 2025</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  OS/Arch:          linux/arm64</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  Experimental:     false</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> containerd:</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  Version:          1.7.27</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  GitCommit:        </span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> runc:</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  Version:          1.2.6</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  GitCommit:        </span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> docker-init:</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  Version:          0.19.0</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  GitCommit:        de40ad0</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">root@LEDE:~# docker ps</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">root@LEDE:~# </span><br></div></code></pre></div></div>
<p>Seeing the version information &amp; empty container list means it's OK.</p>
<p><code>docker-compose</code> is also recommended to install for managing multiple services together later (taking ARM64 as an example):</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">wget https://github.com/docker/compose/releases/download/v2.27.0/docker-compose-linux-aarch64 -O /usr/local/bin/docker-compose</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">chmod +x /usr/local/bin/docker-compose</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">docker-compose version</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="data-disk-mount--directory-planning">Data Disk Mount &amp; Directory Planning<a href="https://zephyr.100ask.org/en/blog/openwrt-docker#data-disk-mount--directory-planning" class="hash-link" aria-label="Direct link to Data Disk Mount &amp; Directory Planning" title="Direct link to Data Disk Mount &amp; Directory Planning" translate="no">​</a></h2>
<p>First, create a new partition in the remaining eMMC space, format it as ext4, then mount it on the interface as the docker data partition. Of course, you can also use other external storage devices, such as a TF card as the docker data partition, just add the corresponding mount directory configuration. An example is as follows:</p>
<p>With the data disk rooted at /opt/data, you can plan it like this:</p>
<div class="language-plain codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-plain codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">/opt/docker      # Docker root directory (images, container layers, etc.)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">/opt/data</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">   ├─ media      # Media files (movies, TV series, music)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">   │   ├─ movies</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">   │   └─ tv</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">   ├─ downloads  # BT/PT download directory</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">   └─ configs    # Configuration files for each container</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">       ├─ jellyfin</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">       ├─ qbittorrent</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">       └─ ...</span><br></div></code></pre></div></div>
<p>Then create the directories:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">mkdir -p /opt/data/{configs,downloads,media}</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">mkdir -p /opt/data/configs/{jellyfin,emby,transmission,qbittorrent,aria2,adguard,nextcloud}</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">mkdir -p /opt/data/media/{movies,tv,anime,music}</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">mkdir -p /opt/data/downloads/{bt,aria2,tmp}</span><br></div></code></pre></div></div>
<p>Later, all containers should try to be mounted under <code>/opt/data</code> to avoid filling up the system disk.</p>
<p>Benefits of doing this:</p>
<ul>
<li class="">If a container breaks, just delete and rebuild it, data is unaffected</li>
<li class="">When changing devices, just connect this disk over and modify the path to continue using it</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="configure-kernel-options-to-support-docker">Configure Kernel Options to Support Docker<a href="https://zephyr.100ask.org/en/blog/openwrt-docker#configure-kernel-options-to-support-docker" class="hash-link" aria-label="Direct link to Configure Kernel Options to Support Docker" title="Direct link to Configure Kernel Options to Support Docker" translate="no">​</a></h2>
<p>With the default compiled kernel, docker will have warning messages when running, prompting that certain feature support is missing, as shown below:</p>
<p>These WARNINGs indicate that your <strong>kernel has not enabled the cgroup v1/v2 resource limit functions</strong>, causing Docker to be unable to limit CPU, IO, memory swap, etc. for containers.  We need to enable the following configurations in our system:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain"># Open the kernel configuration page</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">make kernel_menuconfig</span><br></div></code></pre></div></div>
<p>According to the configuration below, enable CGroup and Namespace support:</p>
<p>Recompile, then upgrade. After booting, confirm there are no corresponding error messages. For more configuration support, please check the configuration in the code repository.</p>
<p>Note: Some docker versions require enabling legacy cgroup v1 related control support. Keep this disabled here.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="acceleration-source-configuration">Acceleration Source Configuration<a href="https://zephyr.100ask.org/en/blog/openwrt-docker#acceleration-source-configuration" class="hash-link" aria-label="Direct link to Acceleration Source Configuration" title="Direct link to Acceleration Source Configuration" translate="no">​</a></h2>
<ol>
<li class="">When installing the docker images below, the default repository download may fail. You can configure mainland sources to accelerate downloads;</li>
</ol>
<p>Common acceleration mirror site addresses:</p>
<div class="language-json codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-json codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"registry-mirrors"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token string" style="color:#e3116c">"https://docker.1panel.live"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token string" style="color:#e3116c">"https://registry.docker-cn.com"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token string" style="color:#e3116c">"http://hub-mirror.c.163.com"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token string" style="color:#e3116c">"https://docker.m.daocloud.io"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<ol start="2">
<li class="">If you find that the configured acceleration source is inaccessible, it may be due to the installed openwrt proxy plugin. Modify the configuration or disable the proxy and retry;</li>
<li class="">After configuration, run <code>docker pull hello-world</code> to check whether the image can be pulled normally. If it can, the network configuration is complete. Below is an example of normal operation overview:</li>
</ol>
<h1>Common Use Cases</h1>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="jellyfin-home-theater-embyplex-work-the-same-way">Jellyfin Home Theater (Emby/Plex work the same way)<a href="https://zephyr.100ask.org/en/blog/openwrt-docker#jellyfin-home-theater-embyplex-work-the-same-way" class="hash-link" aria-label="Direct link to Jellyfin Home Theater (Emby/Plex work the same way)" title="Direct link to Jellyfin Home Theater (Emby/Plex work the same way)" translate="no">​</a></h2>
<p>Note: The following uses command-line and illustrated methods for operation examples. Subsequent chapters only provide command-line examples.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="pull-image">Pull Image<a href="https://zephyr.100ask.org/en/blog/openwrt-docker#pull-image" class="hash-link" aria-label="Direct link to Pull Image" title="Direct link to Pull Image" translate="no">​</a></h3>
<p>Execute on the command line:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain"># [--platform linux/arm64] is an optional parameter, can be removed</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">docker pull --platform linux/arm64 jellyfin/jellyfin:latest</span><br></div></code></pre></div></div>
<p>LuCI interface operation:</p>
<p>After pulling successfully, you can see it in the image list on the page, as shown below:</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="start-container">Start Container<a href="https://zephyr.100ask.org/en/blog/openwrt-docker#start-container" class="hash-link" aria-label="Direct link to Start Container" title="Direct link to Start Container" translate="no">​</a></h3>
<p>Start command example:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">docker run -d \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  --name=jellyfin \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  --restart=unless-stopped \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  -p 8096:8096 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  -v /opt/data/configs/jellyfin:/config \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  -v /opt/data/media:/media \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  jellyfin/jellyfin:latest</span><br></div></code></pre></div></div>
<p>You can directly copy the above command, go to the Parse CLI on the interface, click the command line button, then paste, and finally click Apply.</p>
<p>After adding, the page shows the status as Created. At this point, select the jellyfin container, then click Start:</p>
<p>If the SBC supports hardware decoding (and GPU drivers are set up), you can try adding:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">--device /dev/dri:/dev/dri</span><br></div></code></pre></div></div>
<blockquote>
<p>Hardware decoding on ARM platforms is an advanced topic with many pitfalls. If it works, consider it a bonus; if not, just use pure software decoding, 1080p is generally fine.</p>
</blockquote>
<p>Startup parameter description:</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="web-configuration-process">Web Configuration Process<a href="https://zephyr.100ask.org/en/blog/openwrt-docker#web-configuration-process" class="hash-link" aria-label="Direct link to Web Configuration Process" title="Direct link to Web Configuration Process" translate="no">​</a></h3>
<p>Browser access: <code>http://router-IP:8096</code></p>
<ol>
<li class="">
<p>Create admin account</p>
</li>
<li class="">
<p>Add media library:</p>
<ul>
<li class="">Movies → <code>/media/movies</code></li>
<li class="">TV Series → <code>/media/tv</code></li>
<li class="">Anime → <code>/media/anime</code></li>
</ul>
</li>
<li class="">
<p>Select Simplified Chinese for the language, and the metadata source can be switched to Chinese priority (smoother scraping)</p>
</li>
</ol>
<p>After that, you can:</p>
<ul>
<li class="">Install Jellyfin client on Android TV/TV box</li>
<li class="">Access directly via web/client on phone, tablet, PC</li>
<li class="">All terminals in the home use this ARM SBC "mini server" as the server</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="usage-introduction">Usage Introduction<a href="https://zephyr.100ask.org/en/blog/openwrt-docker#usage-introduction" class="hash-link" aria-label="Direct link to Usage Introduction" title="Direct link to Usage Introduction" translate="no">​</a></h3>
<p>After the initial configuration above is completed, jellyfin is initialized. We log in with the configured admin account and can see the following interface:</p>
<p>I had previously downloaded the Minions movie source via a magnet link, and now I can click to watch it online directly.</p>
<p>The movie has no information by default. We can scrape metadata to get cover and other information. For more use cases, please refer to jellyfin's official documentation:</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="core-use-case-2-run-ubuntu">Core Use Case 2: Run Ubuntu<a href="https://zephyr.100ask.org/en/blog/openwrt-docker#core-use-case-2-run-ubuntu" class="hash-link" aria-label="Direct link to Core Use Case 2: Run Ubuntu" title="Direct link to Core Use Case 2: Run Ubuntu" translate="no">​</a></h2>
<p>Many services depend on a complete ubuntu environment rather than the OpenWrt plugin approach. In such cases, we can install a docker ubuntu container in the OpenWrt environment to have an environment similar to native ubuntu, enabling various custom features. Below is an example of a basic Python-implemented web server, demonstrating the powerful customization capability of running a containerized version of ubuntu.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="pull-image-1">Pull Image<a href="https://zephyr.100ask.org/en/blog/openwrt-docker#pull-image-1" class="hash-link" aria-label="Direct link to Pull Image" title="Direct link to Pull Image" translate="no">​</a></h3>
<p>Execute command:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">docker pull ubuntu:24.04</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="start-container-1">Start Container<a href="https://zephyr.100ask.org/en/blog/openwrt-docker#start-container-1" class="hash-link" aria-label="Direct link to Start Container" title="Direct link to Start Container" translate="no">​</a></h3>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">docker run -it ubuntu:24.04 bash</span><br></div></code></pre></div></div>
<p>Command-line start example:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">docker run -it -d \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  --name ubt-web \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  --restart=unless-stopped \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  -p 8080:8000 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  ubuntu:24.04 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  bash</span><br></div></code></pre></div></div>
<p>Enter the container and execute simple HTTP server Python code, as shown below:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">docker exec -it ubt-web bash</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">apt update</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">apt install python3 python3-pip -y</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">cat &gt; /srv/app.py &lt;&lt; 'EOF'</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">from http.server import HTTPServer, SimpleHTTPRequestHandler</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">PORT = 8000</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">httpd = HTTPServer(("", PORT), SimpleHTTPRequestHandler)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">print(f"Serving on port {PORT}...")</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">httpd.serve_forever()</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">EOF</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># The web server root implemented above is the path where python3 is currently executed</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">python3 /srv/app.py</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="web-access-test">Web Access Test<a href="https://zephyr.100ask.org/en/blog/openwrt-docker#web-access-test" class="hash-link" aria-label="Direct link to Web Access Test" title="Direct link to Web Access Test" translate="no">​</a></h3>
<p>At this point, access the http server written in python in the ubuntu container via <code>http://router-IP:8000</code>, and a file list will appear, as shown below:</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="bonus-use-case-network-wide-ad-blocking">Bonus Use Case: Network-wide Ad Blocking<a href="https://zephyr.100ask.org/en/blog/openwrt-docker#bonus-use-case-network-wide-ad-blocking" class="hash-link" aria-label="Direct link to Bonus Use Case: Network-wide Ad Blocking" title="Direct link to Bonus Use Case: Network-wide Ad Blocking" translate="no">​</a></h2>
<p>First, pull the adguardhome image:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">docker pull adguard/adguardhome:latest</span><br></div></code></pre></div></div>
<p>Then start the container, using AdGuard Home: network-wide DNS ad blocking</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">docker run -d \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  --name=adguardhome \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  --restart=unless-stopped \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  -p 3000:3000 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  -p 53:53/tcp \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  -p 53:53/udp \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  -v /opt/data/config/adguard:/opt/adguardhome/conf \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  -v /opt/data/config/adguard/work:/opt/adguardhome/work \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  adguard/adguardhome</span><br></div></code></pre></div></div>
<ul>
<li class="">
<p>Initialization address: <code>http://router-IP:3000</code></p>
</li>
<li class="">
<p>After configuration, in OpenWrt's LAN DHCP, point the DNS to the adguardhome container's port 53, thereby implementing DNS-based ad filtering.</p>
</li>
</ul>
<p>For more configuration details, please refer to the AdGuard Home official documentation.</p>
<h1>FAQ / Pitfalls Summary</h1>
<p><strong>Q1: How to set up external network access?</strong></p>
<ul>
<li class="">Recommended: Use ZeroTier/Tailscale/FRP for intranet penetration, try not to expose ports directly on the public network</li>
</ul>
<p><strong>Q3: How to do backups?</strong></p>
<ul>
<li class="">Essential: the entire <code>/opt/data/config</code> directory (configuration of all services)</li>
<li class="">Important data: <code>/opt/data/media</code> and downloads to keep</li>
<li class="">When changing machines, just connect this disk over, remount, and modify the container paths to continue using it</li>
</ul>
<p><strong>Q4: How to troubleshoot issues?</strong></p>
<ul>
<li class=""><code>docker logs container-name</code> to view logs</li>
<li class=""><code>docker exec -it container-name /bin/sh</code> to enter the container for troubleshooting</li>
<li class="">Check basic items like mount directory permissions, disk space, memory usage</li>
</ul>
<h1>Reference Links</h1>
<ul>
<li class=""><a href="https://www.runoob.com/docker/docker-tutorial.html" target="_blank" rel="noopener noreferrer" class="">Docker Tutorial</a></li>
</ul>]]></content:encoded>
            <category>OpenWrt</category>
            <category>Docker</category>
            <category>RK3576</category>
        </item>
        <item>
            <title><![CDATA[OPENWRT System 4: Lightweight NAS Use Case Guide]]></title>
            <link>https://zephyr.100ask.org/en/blog/openwrt-nas</link>
            <guid>https://zephyr.100ask.org/en/blog/openwrt-nas</guid>
            <pubDate>Mon, 08 Dec 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[Set up a lightweight NAS on OpenWrt, introducing use cases.]]></description>
            <content:encoded><![CDATA[<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="solution-introduction-and-selection">Solution Introduction and Selection<a href="https://zephyr.100ask.org/en/blog/openwrt-nas#solution-introduction-and-selection" class="hash-link" aria-label="Direct link to Solution Introduction and Selection" title="Direct link to Solution Introduction and Selection" translate="no">​</a></h2>
<p>Making the lightweight NAS (LAN file sharing) on OpenWrt accessible from the external network means being able to securely access your home storage from anywhere. This is the simplest way to set up a self-built private cloud. You only need the development board to have a USB interface, USB 3.0 is better, and then you can connect a USB portable hard drive, turning it into an OpenWrt device with lightweight NAS functionality. Below is the analysis of the implementation steps.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="file-sharing">File Sharing<a href="https://zephyr.100ask.org/en/blog/openwrt-nas#file-sharing" class="hash-link" aria-label="Direct link to File Sharing" title="Direct link to File Sharing" translate="no">​</a></h2>
<p>We first need to implement the LAN file sharing function. Below are the recommended methods for common LAN sharing scenarios. Here we choose samba4, FileBrowser, and webDAV, supporting all three common sharing methods. Below are the recommended protocols for specific scenarios, which you can flexibly choose according to your own scenario.</p>
<table><thead><tr><th>Scenario</th><th>Recommended Protocol</th></tr></thead><tbody><tr><td><strong>Windows + Linux general file sharing</strong></td><td>Samba4</td></tr><tr><td><strong>Linux server mount (e.g., Docker/K8s)</strong></td><td>NFS</td></tr><tr><td><strong>External network access to NAS (with frp/Tailscale)</strong></td><td>FileBrowser (Web)</td></tr><tr><td><strong>Most secure transfer (requires encryption)</strong></td><td>SFTP</td></tr><tr><td><strong>iPhone/macOS mount network drive</strong></td><td>WebDAV</td></tr><tr><td><strong>Media player (TV, DLNA)</strong></td><td>Samba4 or NFS</td></tr></tbody></table>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="intranet-access">Intranet Access<a href="https://zephyr.100ask.org/en/blog/openwrt-nas#intranet-access" class="hash-link" aria-label="Direct link to Intranet Access" title="Direct link to Intranet Access" translate="no">​</a></h2>
<p>After completing the LAN network sharing, to implement a lightweight NAS, there is another key feature: being able to remotely view the shared files at home at any time. Then we need to implement intranet penetration. Below are common intranet penetration methods and their corresponding pros and cons. We choose to use frp (self-built relay server) and the now-popular method DDNSTO. The former requires you to have a public network server for data forwarding, while the latter is easy to operate: you only need to install the corresponding plugin, then bind your device on the Yiyouyun platform, and the Yiyouyun service provider's server will do the data forwarding.</p>
<p>Below is a comparison of common intranet access solutions:</p>
<table><thead><tr><th>Solution</th><th>Pros</th><th>Cons</th><th>Security</th></tr></thead><tbody><tr><td>✅ <strong>Public IP + Port Mapping</strong></td><td>Simple direct connection, fast</td><td>Requires public IP (ISPs generally don't provide)</td><td>Low (requires firewall)</td></tr><tr><td>🌐 <strong>DDNS + Public IP</strong></td><td>Suitable for dynamic IP users</td><td>Also requires public network access</td><td>Medium</td></tr><tr><td>🔐 <strong>ZeroTier / Tailscale VPN</strong></td><td>No public IP needed, automatically penetrates NAT</td><td>Requires third-party VPN control plane</td><td>High</td></tr><tr><td>☁️ <strong>frp / Cloudflare Tunnel</strong></td><td>Self-built tunnel, no public IP needed</td><td>Depends on intermediate server</td><td>High</td></tr><tr><td><strong>DDNSTO Router Remote</strong></td><td>Simple operation, no public IP needed</td><td>Depends on third-party service provider</td><td>High</td></tr></tbody></table>
<p>Here we prioritize using the DDNSTO plugin + the plugin provider's cloud service to implement intranet penetration for the lightweight NAS application. You can also self-build an frp cloud service on your own VPS to implement intranet penetration for the lightweight NAS application (suitable for advanced users, requires configuring many parameters and some network knowledge, of course you can also ask AI to generate the corresponding configuration). You can choose the solution that suits you according to your actual situation.</p>
<h1>Implementing Lightweight NAS Application with DDNSTO Plugin</h1>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="mount-hard-drive">Mount Hard Drive<a href="https://zephyr.100ask.org/en/blog/openwrt-nas#mount-hard-drive" class="hash-link" aria-label="Direct link to Mount Hard Drive" title="Direct link to Mount Hard Drive" translate="no">​</a></h2>
<p>First, we need to insert the portable hard drive into the USB TYPE-A port of DshanPi A1, then configure the corresponding mount directory, and set it to automatically mount on every boot. Here we use a USB flash drive for the test example; the configuration method for a portable hard drive is exactly the same.</p>
<p>First, on the <strong>System -&gt; Mount Points</strong> page, configure the directory for automatic disk mounting, and enable it.</p>
<p>After configuration, restart the device and observe whether the configuration remains valid after power off. If it takes effect, you can see the following print:</p>
<p>Default permissions of /media:</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="enable-file-sharing-service">Enable File Sharing Service<a href="https://zephyr.100ask.org/en/blog/openwrt-nas#enable-file-sharing-service" class="hash-link" aria-label="Direct link to Enable File Sharing Service" title="Direct link to Enable File Sharing Service" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="samba-sharing">Samba Sharing<a href="https://zephyr.100ask.org/en/blog/openwrt-nas#samba-sharing" class="hash-link" aria-label="Direct link to Samba Sharing" title="Direct link to Samba Sharing" translate="no">​</a></h3>
<font style="color:rgb(64, 64, 64);background-color:rgb(252, 252, 252)">Samba is a free software that implements the SMB protocol on Linux systems. We can use terminal devices that support the SMB protocol to implement file sharing within the LAN.</font>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="install-samba"><font style="color:rgb(64, 64, 64);background-color:rgb(252, 252, 252)">Install Samba</font><a href="https://zephyr.100ask.org/en/blog/openwrt-nas#install-samba" class="hash-link" aria-label="Direct link to install-samba" title="Direct link to install-samba" translate="no">​</a></h4>
<p><font style="color:rgb(64, 64, 64);background-color:rgb(252, 252, 252)">First, we need to select luci-app-samba4 before compiling, or install the samba4 server program into the system by installing ipk online after flashing. After installation, on the page: </font><strong><font style="color:rgb(64, 64, 64);background-color:rgb(252, 252, 252)">Services -&gt; Network Shares</font></strong><font style="color:rgb(64, 64, 64);background-color:rgb(252, 252, 252)"> you can see the corresponding configuration, as shown below:</font></p>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="create-samba-user"><font style="color:rgb(64, 64, 64);background-color:rgb(252, 252, 252)">Create Samba User</font><a href="https://zephyr.100ask.org/en/blog/openwrt-nas#create-samba-user" class="hash-link" aria-label="Direct link to create-samba-user" title="Direct link to create-samba-user" translate="no">​</a></h4>
<font style="color:rgb(64, 64, 64);background-color:rgb(252, 252, 252)">When performing network sharing, we should avoid using the root user to log in to the samba server. To this end, we separately create a user for accessing the samba server and grant it access permissions to the folder.</font>
<p>Open <strong>Services -&gt; Terminal</strong>, execute the following commands to create a user, and grant the user access permissions to the shared directory.</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">#Add a user named samba</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">useradd samba</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">#Create an smb service password for user samba, this is separate from the user's login password, they can be different</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">smbpasswd -a samba</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">#Grant user samba access to the shared directory</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">#Note: Only ext4 file systems can modify permissions, make corresponding adjustments according to your disk format</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">chown -R samba:samba /media/</span><br></div></code></pre></div></div>
<p>Modify /etc/passwd to configure the samba user so it cannot log in. Below is an example:</p>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="modify-samba4-configuration">Modify samba4 Configuration<a href="https://zephyr.100ask.org/en/blog/openwrt-nas#modify-samba4-configuration" class="hash-link" aria-label="Direct link to Modify samba4 Configuration" title="Direct link to Modify samba4 Configuration" translate="no">​</a></h4>
<p><font style="color:rgb(64, 64, 64);background-color:rgb(252, 252, 252)">Open </font><strong><font style="color:rgb(64, 64, 64);background-color:rgb(252, 252, 252)">Services -&gt; Network Shares</font></strong><font style="color:rgb(64, 64, 64);background-color:rgb(252, 252, 252)"> to configure parameters.</font></p>
<p><font style="color:rgb(64, 64, 64);background-color:rgb(252, 252, 252)">Select the interface as lan, so that intranet devices can access it. Check</font><font style="color:rgb(64, 64, 64);background-color:rgb(252, 252, 252)"> </font><strong><font style="color:rgb(64, 64, 64);background-color:rgb(252, 252, 252)">Allow legacy protocols and authentication.</font></strong></p>
<p><font style="color:rgb(64, 64, 64);background-color:rgb(252, 252, 252)">Click</font><font style="color:rgb(64, 64, 64);background-color:rgb(252, 252, 252)"> </font><strong><font style="color:rgb(64, 64, 64);background-color:rgb(252, 252, 252)">Add</font></strong><font style="color:rgb(64, 64, 64);background-color:rgb(252, 252, 252)"> </font><font style="color:rgb(64, 64, 64);background-color:rgb(252, 252, 252)">an entry.</font></p>
<ul>
<li class="">
<font style="color:rgb(64, 64, 64);background-color:rgb(252, 252, 252)">Name: The folder name displayed when sharing, can be set freely, here set to media</font>
</li>
<li class=""><font style="color:rgb(64, 64, 64);background-color:rgb(252, 252, 252)">Path: The folder path to be shared, here set to the directory mounted in the previous chapter</font><code>&lt;font style={{color: 'rgb(64, 64, 64)', backgroundColor: 'rgb(252, 252, 252)'}}&gt;/media&lt;/font&gt;</code><font style="color:rgb(64, 64, 64);background-color:rgb(252, 252, 252)"></font></li>
<li class="">
<font style="color:rgb(64, 64, 64);background-color:rgb(252, 252, 252)">Allowed users: Users with access permissions, here set to the user samba just created.</font>
</li>
</ul>
<font style="color:rgb(64, 64, 64);background-color:rgb(252, 252, 252)">These are the main settings. Save and apply these configurations. For other settings, you can explore other advanced configurations on your own.</font>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="sftp-sharing">SFTP Sharing<a href="https://zephyr.100ask.org/en/blog/openwrt-nas#sftp-sharing" class="hash-link" aria-label="Direct link to SFTP Sharing" title="Direct link to SFTP Sharing" translate="no">​</a></h3>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="install-sftp-server">Install SFTP Server<a href="https://zephyr.100ask.org/en/blog/openwrt-nas#install-sftp-server" class="hash-link" aria-label="Direct link to Install SFTP Server" title="Direct link to Install SFTP Server" translate="no">​</a></h4>
<p>Dropbear does not support SFTP, but it supports calling an external sftp-server.</p>
<p>OpenWrt already provides a standalone <code>openssh-sftp-server</code> package:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">opkg update</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">opkg install openssh-sftp-server</span><br></div></code></pre></div></div>
<p>After installation, sftp-server will be placed at: <code>/usr/lib/sftp-server</code>. This solution is suitable for scenarios where you need a GUI to configure ssh keys but also need sftp server functionality. If you replace everything with the full OpenSSH suite, since OpenSSH has no official LuCI configuration interface in OpenWrt, all configurations would have to be done through the terminal.</p>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="configure-sftp">Configure SFTP<a href="https://zephyr.100ask.org/en/blog/openwrt-nas#configure-sftp" class="hash-link" aria-label="Direct link to Configure SFTP" title="Direct link to Configure SFTP" translate="no">​</a></h4>
<p>After installation, you can use it directly without other configuration. For example, connecting directly with Xftp, you can see the files in the system.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="webdav-sharing">WebDAV Sharing<a href="https://zephyr.100ask.org/en/blog/openwrt-nas#webdav-sharing" class="hash-link" aria-label="Direct link to WebDAV Sharing" title="Direct link to WebDAV Sharing" translate="no">​</a></h3>
<p>After installing the DDNSTO plugin, it comes with a lightweight webdav service built in. You don't need to install it separately, just use it directly.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="configure-intranet-penetration">Configure Intranet Penetration<a href="https://zephyr.100ask.org/en/blog/openwrt-nas#configure-intranet-penetration" class="hash-link" aria-label="Direct link to Configure Intranet Penetration" title="Direct link to Configure Intranet Penetration" translate="no">​</a></h2>
<p>First, log in to the DDNSTO console. After registering and logging in, record the user Token, then configure the DDNSTO remote control page on the board side, configuring the corresponding parameters. An example is as follows:</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="configure-samba-remote-access">Configure Samba Remote Access<a href="https://zephyr.100ask.org/en/blog/openwrt-nas#configure-samba-remote-access" class="hash-link" aria-label="Direct link to Configure Samba Remote Access" title="Direct link to Configure Samba Remote Access" translate="no">​</a></h3>
<p>Log in to the DDNSTO console. Under the File Management section, click Add File Management to add a Samba protocol file management service. Fill in the corresponding parameters. An example is as follows:</p>
<ol>
<li class="">
<p>Add configuration</p>
</li>
<li class="">
<p>Click Connect</p>
</li>
<li class="">
<p>Enter the user and password from the Samba4 configuration</p>
</li>
<li class="">
<p>Connection successful, you can see the files in the corresponding directory, as shown below:</p>
</li>
</ol>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="configure-sftp-remote-access">Configure SFTP Remote Access<a href="https://zephyr.100ask.org/en/blog/openwrt-nas#configure-sftp-remote-access" class="hash-link" aria-label="Direct link to Configure SFTP Remote Access" title="Direct link to Configure SFTP Remote Access" translate="no">​</a></h3>
<p>Log in to the DDNSTO console. Under the File Management section, click Add File Management to add an Sftp protocol file management service. Fill in the corresponding parameters. An example is as follows:</p>
<ol>
<li class="">
<p>Add configuration</p>
</li>
<li class="">
<p>Click Access</p>
</li>
<li class="">
<p>Enter the username and password that can log in via ssh, here enter the password for root</p>
</li>
<li class="">
<p>Connection successful, you can see the files in the corresponding directory, as shown below:</p>
</li>
</ol>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="configure-webdav-remote-access">Configure WebDAV Remote Access<a href="https://zephyr.100ask.org/en/blog/openwrt-nas#configure-webdav-remote-access" class="hash-link" aria-label="Direct link to Configure WebDAV Remote Access" title="Direct link to Configure WebDAV Remote Access" translate="no">​</a></h3>
<p>Log in to the DDNSTO console. Under the File Management section, click Add File Management to add a webdav protocol file management service. Fill in the corresponding parameters. An example is as follows:</p>
<ol>
<li class="">
<p>Add configuration</p>
</li>
<li class="">
<p>Click Access</p>
</li>
<li class="">
<p>Enter the authorized username and password filled in the DDSNTO plugin in the router system to the login page</p>
</li>
<li class="">
<p>Connection successful, you can see the files in the corresponding directory, as shown below:</p>
</li>
</ol>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="configure-remote-access-to-router-backend">Configure Remote Access to Router Backend<a href="https://zephyr.100ask.org/en/blog/openwrt-nas#configure-remote-access-to-router-backend" class="hash-link" aria-label="Direct link to Configure Remote Access to Router Backend" title="Direct link to Configure Remote Access to Router Backend" translate="no">​</a></h3>
<p>Log in to the DDNSTO console, select the External Domain section, then click Add Domain, and fill in the configuration according to the example below:</p>
<p>After configuration, click the External Domain section to jump directly to the external domain page. This way you can remotely configure the router in the LAN from anywhere.</p>
<p>To summarize: The DDNSTO plugin integrates many remote scenarios. For light use, the paid 4Mbps plan is sufficient, with low latency, saving you from various complex environment setup processes and the cumbersome process of self-building a VPS. Recommended!</p>
<h1>Self-build Frp Cloud Service to Implement Lightweight NAS Application</h1>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="mount-hard-drive-and-enable-file-sharing-service">Mount Hard Drive and Enable File Sharing Service<a href="https://zephyr.100ask.org/en/blog/openwrt-nas#mount-hard-drive-and-enable-file-sharing-service" class="hash-link" aria-label="Direct link to Mount Hard Drive and Enable File Sharing Service" title="Direct link to Mount Hard Drive and Enable File Sharing Service" translate="no">​</a></h2>
<p>The mounting of the hard drive and enabling of the file sharing service in the self-built solution are exactly the same as the DDNSTO plugin method. For detailed steps, please refer to the content in the previous chapter, which will not be repeated here.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="configure-intranet-penetration-service">Configure Intranet Penetration Service<a href="https://zephyr.100ask.org/en/blog/openwrt-nas#configure-intranet-penetration-service" class="hash-link" aria-label="Direct link to Configure Intranet Penetration Service" title="Direct link to Configure Intranet Penetration Service" translate="no">​</a></h2>
<p>There are many parameters to configure here, and security needs to be considered. There are many configuration items and certificate steps involved. Due to space limitations, it will not be described in detail here. For more information, please refer to frp's official documentation to set up the corresponding intranet penetration service.</p>]]></content:encoded>
            <category>OpenWrt</category>
            <category>NAS</category>
            <category>RK3576</category>
        </item>
        <item>
            <title><![CDATA[OPENWRT System 3: Existing Feature Optimization]]></title>
            <link>https://zephyr.100ask.org/en/blog/openwrt-feature-optimize</link>
            <guid>https://zephyr.100ask.org/en/blog/openwrt-feature-optimize</guid>
            <pubDate>Sat, 06 Dec 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[Optimize existing features of OpenWrt.]]></description>
            <content:encoded><![CDATA[<p>After downloading the officially adapted OpenWrt source code from 100ask, I found that many features were not fully adapted, causing some poor user experience during use. Below is a record of the problems I found during use and an analysis of the solutions, hoping to give readers some ideas for solving similar problems. Since my knowledge is limited, if there are any errors, you are welcome to discuss.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="installing-third-party-ipk-does-not-work">Installing third-party ipk does not work<a href="https://zephyr.100ask.org/en/blog/openwrt-feature-optimize#installing-third-party-ipk-does-not-work" class="hash-link" aria-label="Direct link to Installing third-party ipk does not work" title="Direct link to Installing third-party ipk does not work" translate="no">​</a></h2>
<p>The libc of the default cloud mirror repository uses musl. After flashing with glibc, I found that all installed programs could not be used. The default OpenWrt uses musl libc.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="installing-third-party-fdisk-does-not-work">Installing third-party fdisk does not work<a href="https://zephyr.100ask.org/en/blog/openwrt-feature-optimize#installing-third-party-fdisk-does-not-work" class="hash-link" aria-label="Direct link to Installing third-party fdisk does not work" title="Direct link to Installing third-party fdisk does not work" translate="no">​</a></h2>
<p>With the default busybox configuration, many tools are missing. After installing fdisk through opkg, it prompts that a certain library does not exist. You need to manually configure the Busybox options. We turn on the custom busybox options, then enable fdisk.</p>
<p>Then recompile the image and flash it. After testing, you can find that fdisk works now.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="sysupgrade-image-does-not-work">sysupgrade image does not work<a href="https://zephyr.100ask.org/en/blog/openwrt-feature-optimize#sysupgrade-image-does-not-work" class="hash-link" aria-label="Direct link to sysupgrade image does not work" title="Direct link to sysupgrade image does not work" translate="no">​</a></h2>
<p>When using the default generated sysupgrade image, in the interface [System - Backup / Upgrade - Flash new firmware image], after selecting the compiled firmware, I found it could not be used, with the following error print messages:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">Tue Dec  2 17:27:21 2025 user.info upgrade: Device 100ask,dshanpi-a1 not supported by this image</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Tue Dec  2 17:27:21 2025 user.info upgrade: Supported devices: 100ask,dshanpia1</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Tue Dec  2 17:27:21 2025 user.info upgrade: Reading partition table from bootdisk...</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Tue Dec  2 17:27:22 2025 user.info upgrade: Reading partition table from image...</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Tue Dec  2 17:27:22 2025 user.info upgrade: Device 100ask,dshanpi-a1 not supported by this image</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Tue Dec  2 17:27:22 2025 user.info upgrade: Supported devices: 100ask,dshanpia1</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Tue Dec  2 17:27:22 2025 user.info upgrade: Reading partition table from bootdisk...</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Tue Dec  2 17:27:22 2025 user.info upgrade: Reading partition table from image..</span><br></div></code></pre></div></div>
<p>After checking, I found that the device name defined in armv8.mk is inconsistent with the compatible in the dts, causing sysupgrade to refuse flashing.</p>
<p>OpenWrt sysupgrade will read:</p>
<ol>
<li class="">The identifier of the currently running device:</li>
</ol>
<p>From:</p>
<ul>
<li class=""><code>/proc/device-tree/compatible</code></li>
<li class=""><code>/etc/board.json</code></li>
</ul>
<ol start="2">
<li class="">The supported_devices list embedded in the firmware</li>
</ol>
<p>If any character of the two does not match, it reports: <code>Device XXX not supported by this image</code></p>
<p>Now that we know the problem, the fix is simple. Modify as follows:</p>
<ol>
<li class="">
<p>Modify target/linux/rockchip/image/armv8.mk to keep it consistent with the dts</p>
</li>
<li class="">
<p>Re-run make menuconfig, select the target, and the .config file will be updated automatically</p>
</li>
<li class="">
<p>Re-run make V=s -j8 to build the image.</p>
</li>
</ol>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="sftp-does-not-work">sftp does not work<a href="https://zephyr.100ask.org/en/blog/openwrt-feature-optimize#sftp-does-not-work" class="hash-link" aria-label="Direct link to sftp does not work" title="Direct link to sftp does not work" translate="no">​</a></h2>
<p>By default, dropbear is used as the ssh server, which does not have sftp functionality. Here we modify the configuration, turn off dropbear, and then enable openssh under <strong>Network -&gt; SSH</strong>, as shown below.</p>
<p>The build fails, <code>openssh-sk-helper</code> build depends on <code>libfido2</code>. We manually enable this library, select it as y, then recompile.</p>
<p>Note: openssh-server and openssh-server-pam cannot be enabled at the same time. We just enable the build without PAM support.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="rootfs-space-is-too-small">rootfs space is too small<a href="https://zephyr.100ask.org/en/blog/openwrt-feature-optimize#rootfs-space-is-too-small" class="hash-link" aria-label="Direct link to rootfs space is too small" title="Direct link to rootfs space is too small" translate="no">​</a></h2>
<p>We prefer to flash the squashfs format image, which makes it convenient to restore factory configuration, because the rom in squashfs format is based on overlayfs, and updated configurations will not directly modify the content in the rom. However, we can find that the default configured rootfs size is relatively small, while the onboard EMMC has 58G. We can expand the rootfs space to 8G, and allocate the remaining space as a separate partition.</p>
<p>The default configured rootfs partition is 512M, as shown below:</p>
<p>Modify the configuration, set the default rootfs partition size to 2G, modify the Rootfs partition size configuration under Target Images, as shown below:</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="usb-device-cannot-be-recognized">USB device cannot be recognized<a href="https://zephyr.100ask.org/en/blog/openwrt-feature-optimize#usb-device-cannot-be-recognized" class="hash-link" aria-label="Direct link to USB device cannot be recognized" title="Direct link to USB device cannot be recognized" translate="no">​</a></h2>
<p>When we simply enable usb0 and usb1 in the device tree, we find that USB drives can be recognized, but during the usb driver probe, it prints that dr_mode is forcibly set to host. Looking at the code, we find that the default configuration is otg, but there is no corresponding otg configuration, and the drd-related code is not compiled.</p>
<p>We need to modify the device tree file to enable the usb0 and usb1 controllers, with the default role as host. Enable the DRD ROLE SWITCH feature, then you can dynamically configure the controller role, and you can also specify the default role.</p>
<p>You must enable USB Gadget to enable the dual-role function, so we turn it on, then select Dual Role mode in Mode Selection. This will generate the usb_role sysfs node in the kernel, which can be dynamically configured as host or peripheral. On the DshanPi A1, usb1 is fixed as host, and usb0 can be configured as dual-role and can be switched. So we make the following dts configuration:</p>
<div class="language-diff codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-diff codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">--- a/target/linux/rockchip/files/arch/arm64/boot/dts/rockchip/rk3576-100ask-dshanpi-a1.dts</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">+++ b/target/linux/rockchip/files/arch/arm64/boot/dts/rockchip/rk3576-100ask-dshanpi-a1.dts</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">@@ -770,6 +770,20 @@</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        status = "okay";</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> };</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> </span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">+// usb0 as type-c port, can be host or peripheral.</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">+&amp;usb_drd0_dwc3 {</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">+       status = "okay";</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">+       usb-role-switch;</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">+       role-switch-default-mode ="host";</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">+};</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">+</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">+// usb1 as type-a port, fixed to host</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">+&amp;usb_drd1_dwc3 {</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">+       status = "okay";</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">+       usb-role-switch;</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">+       role-switch-default-mode ="host";</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">+};</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">+</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> &amp;uart0 {</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        pinctrl-0 = &lt;&amp;uart0m0_xfer&gt;;</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        status = "okay";</span><br></div></code></pre></div></div>
<p>After configuration, usb1 can be used, but usb0 cannot. And the onboard Hynetik HUSB311 Type-C chip can provide USB PD and USB Type-C functionality. We found that the default 6.12 kernel version driver does not support this chip. Checking the official rockchip repository, there is support for this chip, which needs to be ported over. We temporarily don't need the DP function, so we mask it out.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="pwm-fan-always-runs-at-maximum-speed">PWM fan always runs at maximum speed<a href="https://zephyr.100ask.org/en/blog/openwrt-feature-optimize#pwm-fan-always-runs-at-maximum-speed" class="hash-link" aria-label="Direct link to PWM fan always runs at maximum speed" title="Direct link to PWM fan always runs at maximum speed" translate="no">​</a></h2>
<p>After power on, the fan always runs at maximum speed, which is quite loud. We need to modify it to support automatic speed adjustment based on temperature, which is more suitable for common application scenarios. The troubleshooting record is as follows:</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="check-hardware">Check hardware<a href="https://zephyr.100ask.org/en/blog/openwrt-feature-optimize#check-hardware" class="hash-link" aria-label="Direct link to Check hardware" title="Direct link to Check hardware" translate="no">​</a></h3>
<p>The fan uses the Raspberry Pi 5 4-pin fan, which is a standard 4-pin JST connector. The physical photo and schematic are as follows:</p>
<span class="text-content">The fan connector is a 1mm pitch JST SH socket with four pins:</span>
<table><thead><tr><th><strong><span class="text-content">PIN Number</span></strong></th><th><strong><span class="text-content">Function</span></strong></th></tr></thead><tbody><tr><td><span class="text-content">1</span></td><td><span class="text-content">+5V</span></td></tr><tr><td><span class="text-content">2</span></td><td><span class="text-content">PWM</span></td></tr><tr><td><span class="text-content">3</span></td><td><span class="text-content">GND</span></td></tr><tr><td><span class="text-content">4</span></td><td><span class="text-content">Speed</span></td></tr></tbody></table>
<p>After checking the manual, pin 2 is connected to PWM1, and pin 4 is connected to the fan speed port, which means it does not support reading the speed, and can only control the speed via PWM. Looking at the schematic, it is PWM1_CH0, and there is a corresponding configuration in the dts. Searching the driver according to the compatible field "pwm-fan", I found that the file linux-6.12.43/drivers/hwmon/pwm-fan.c exists but was not compiled. That means the KCONFIG was not selected, and the pwm-fan driver was not compiled.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="enable-pwm-driver">Enable PWM driver<a href="https://zephyr.100ask.org/en/blog/openwrt-feature-optimize#enable-pwm-driver" class="hash-link" aria-label="Direct link to Enable PWM driver" title="Direct link to Enable PWM driver" translate="no">​</a></h3>
<p>So we directly run make kernel_menuconfig, search for CONFIG_SENSORS_PWM_FAN, then enter the number corresponding to the search result, and it will jump directly to the corresponding configuration location. Just enter Y to enable it.</p>
<p>After compiling and flashing, during the boot process, I found that the pwm-fan driver failed to start, with the following print:</p>
<p>It can be concluded that the upstream PWM device was not found. Searching the compatible of the referenced node, I found that the corresponding driver was not enabled, in a separate directory: drivers/soc/rockchip</p>
<p>The enabled drivers:</p>
<p>After enabling, there will be compilation issues. We modify as follows:</p>
<p>Modify as follows:</p>
<div class="language-diff codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-diff codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">--- a/include/soc/rockchip/utils.h	2025-11-23 03:35:07.695086227 +0800</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">+++ b/include/soc/rockchip/utils.h	2025-11-23 03:34:43.946599951 +0800</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">@@ -50,6 +50,7 @@</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  *</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  * Return: the value, shifted into place, with the required write-enable bits</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  */</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">+#if 0</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> #define REG_UPDATE_WE(_val, _low, _high) ( \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> 	BUILD_BUG_ON_ZERO(const_true((_low) &gt; (_high))) + \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> 	BUILD_BUG_ON_ZERO(const_true((_high) &gt; 15)) + \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">@@ -57,6 +58,11 @@</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> 	BUILD_BUG_ON_ZERO(const_true((u64) (_val) &gt; U16_MAX)) + \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> 	((_val &amp; GENMASK((_high) - (_low), 0)) &lt;&lt; (_low) | \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> 	(GENMASK((_high), (_low)) &lt;&lt; 16)))</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">+#else</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">+#define REG_UPDATE_WE(_val, _low, _high) ( \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">+	((_val &amp; GENMASK((_high) - (_low), 0)) &lt;&lt; (_low) | \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">+	(GENMASK((_high), (_low)) &lt;&lt; 16)))</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">+#endif</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> </span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> /**</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  * REG_UPDATE_BIT_WE - update a bit with a write-enable mask</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">@@ -68,9 +74,14 @@</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  *</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  * Return: a value with bit @__bit set to @__val and @__bit &lt;&lt; 16 set to ``1``</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  */</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">+#if 0</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> #define REG_UPDATE_BIT_WE(__val, __bit) ( \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> 	BUILD_BUG_ON_ZERO(const_true((__val) &gt; 1)) + \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> 	BUILD_BUG_ON_ZERO(const_true((__val) &lt; 0)) + \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> 	REG_UPDATE_WE((__val), (__bit), (__bit)))</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">+#else</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">+#define REG_UPDATE_BIT_WE(__val, __bit) ( \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">+	REG_UPDATE_WE((__val), (__bit), (__bit)))</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">+#endif</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> </span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> #endif /* __SOC_ROCKCHIP_UTILS_H__ */</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="method-to-configure-speed">Method to configure speed<a href="https://zephyr.100ask.org/en/blog/openwrt-feature-optimize#method-to-configure-speed" class="hash-link" aria-label="Direct link to Method to configure speed" title="Direct link to Method to configure speed" translate="no">​</a></h3>
<p>The method to manually configure pwm-fan: find the pwm-fan directory under sysfs, enter /sys/class/hwmon/hwmon0/, and you can see two files pwm1_enable and pwm1. First configure pwm1 to 100, and observe whether the fan noise decreases. The experiment found that it indeed became quieter, which means the PWM control took effect.</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">root@LEDE:~# ls /sys/class/hwmon/hwmon0/</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">device       of_node      pwm1         subsystem</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">name         power        pwm1_enable  uevent</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">root@LEDE:~# echo 100 &gt; /sys/class/hwmon/hwmon0/pwm1</span><br></div></code></pre></div></div>
<p>Reference documents:</p>
<ul>
<li class="">Documentation/hwmon/pwm-fan.rst</li>
<li class="">Documentation/devicetree/bindings/hwmon/pwm-fan.yaml</li>
<li class="">Documentation/driver-api/thermal/sysfs-api.rst</li>
</ul>
<p>You can also find pwm-fan through the cooling_device under the thermal framework. Under the thermal cooling device framework, there is a registered sysfs interface, corresponding to the ops provided by the pwm_fan driver binding. The state value corresponds to the index of the cooling_levels array configured in the dts, so you can configure the corresponding relative speed in the pwm driver by configuring a value from 0..max_state, directly in the shell.</p>
<div class="language-c codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-c codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">static</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">struct</span><span class="token plain"> </span><span class="token class-name">thermal_cooling_device_ops</span><span class="token plain"> pwm_fan_cooling_ops </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">	</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">get_max_state </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> pwm_fan_get_max_state</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">	</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">get_cur_state </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> pwm_fan_get_cur_state</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">	</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">set_cur_state </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> pwm_fan_set_cur_state</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">//dts</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">fan</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> pwm</span><span class="token operator" style="color:#393A34">-</span><span class="token plain">fan </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    status </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"okay"</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    compatible </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"pwm-fan"</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token macro property directive-hash" style="color:#36acaa">#</span><span class="token macro property directive keyword" style="color:#00009f">cooling</span><span class="token macro property expression operator" style="color:#393A34">-</span><span class="token macro property expression" style="color:#36acaa">cells </span><span class="token macro property expression operator" style="color:#393A34">=</span><span class="token macro property expression" style="color:#36acaa"> </span><span class="token macro property expression operator" style="color:#393A34">&lt;</span><span class="token macro property expression number" style="color:#36acaa">2</span><span class="token macro property expression operator" style="color:#393A34">&gt;</span><span class="token macro property expression punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    pwms </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain">pwm1_6ch_0 </span><span class="token number" style="color:#36acaa">0</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">50000</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// This corresponds to states from 0..5</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    cooling</span><span class="token operator" style="color:#393A34">-</span><span class="token plain">levels </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token number" style="color:#36acaa">0</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">100</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">125</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">150</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">200</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">255</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// The trips configured here did not take effect. We need to put them into the thermal framework</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    rockchip</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain">temp</span><span class="token operator" style="color:#393A34">-</span><span class="token plain">trips </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token number" style="color:#36acaa">40000</span><span class="token plain">    </span><span class="token number" style="color:#36acaa">1</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token number" style="color:#36acaa">50000</span><span class="token plain">    </span><span class="token number" style="color:#36acaa">2</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token number" style="color:#36acaa">60000</span><span class="token plain">    </span><span class="token number" style="color:#36acaa">3</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token number" style="color:#36acaa">65000</span><span class="token plain">    </span><span class="token number" style="color:#36acaa">4</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token number" style="color:#36acaa">70000</span><span class="token plain">    </span><span class="token number" style="color:#36acaa">5</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><br></div></code></pre></div></div>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">root@LEDE:~# ls /sys/class/thermal/cooling_device0/</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">cur_state  max_state  power      subsystem  type       uevent</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">root@LEDE:~# cat /sys/class/thermal/cooling_device0/max_state </span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">5</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># This is equivalent to echo 100 &gt; /sys/class/hwmon/hwmon0/pwm1</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">root@LEDE:~# echo 1 &gt; /sys/class/thermal/cooling_device0/cur_state </span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="add-automatic-speed-adjustment-feature">Add automatic speed adjustment feature<a href="https://zephyr.100ask.org/en/blog/openwrt-feature-optimize#add-automatic-speed-adjustment-feature" class="hash-link" aria-label="Direct link to Add automatic speed adjustment feature" title="Direct link to Add automatic speed adjustment feature" translate="no">​</a></h3>
<p>Automatic speed adjustment relies on the thermal system, mainly consisting of thermal_zone, cooling_device, and trip_point.</p>
<p>Reference article: <a href="https://blog.csdn.net/Linux_zhicheng/article/details/119361850" target="_blank" rel="noopener noreferrer" class="">Linux Thermal Framework Analysis - CSDN Blog</a></p>
<p>Add the corresponding trip under the thermal_zones node configured in the original dts.</p>
<p><del>Compiling dts separately failed</del></p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">make target/linux/prepare V=s</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">make target/linux/compile DTBS=1 V=s</span><br></div></code></pre></div></div>
<p>Then you can directly find the generated:</p>
<div class="language-c codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-c codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">build_dir</span><span class="token operator" style="color:#393A34">/</span><span class="token plain">target</span><span class="token operator" style="color:#393A34">-</span><span class="token operator" style="color:#393A34">*</span><span class="token operator" style="color:#393A34">/</span><span class="token plain">linux</span><span class="token operator" style="color:#393A34">-</span><span class="token operator" style="color:#393A34">*</span><span class="token operator" style="color:#393A34">/</span><span class="token plain">linux</span><span class="token operator" style="color:#393A34">-</span><span class="token operator" style="color:#393A34">*</span><span class="token operator" style="color:#393A34">/</span><span class="token plain">arch</span><span class="token operator" style="color:#393A34">/</span><span class="token plain">arm64</span><span class="token operator" style="color:#393A34">/</span><span class="token plain">boot</span><span class="token operator" style="color:#393A34">/</span><span class="token plain">dts</span><span class="token comment" style="color:#999988;font-style:italic">/*.dtb</span><br></div></code></pre></div></div>
<p>When configuring pwm1 or cur_state=0, the fan speed is maximum. According to the kernel documentation about the pwm_fan sysfs node, the specific behavior when pwm1=0 can be configured via the pwm1_enable file. The default value is 1, i.e., disable pwm, keep regulator enabled. So when set to 0, it will directly go to full speed.</p>
<p>So when we configure the cooling-levels array, we set the value of the 0th element to 10, so that it rotates at a lower speed. Then set pwm1_enable to 2, which means when pwm=0, both pwm and regulator still have output, i.e., duty cycle 0.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="onboard-led-has-no-driver">Onboard LED has no driver<a href="https://zephyr.100ask.org/en/blog/openwrt-feature-optimize#onboard-led-has-no-driver" class="hash-link" aria-label="Direct link to Onboard LED has no driver" title="Direct link to Onboard LED has no driver" translate="no">​</a></h2>
<p>This is a <strong>RGB LED strip chain controlled by single-wire serial</strong>:</p>
<ul>
<li class="">Chip: <strong>WS2812C-2020</strong></li>
<li class="">Number of LEDs: <strong>4 (RUN × 4)</strong></li>
<li class="">Each LED is both an RGB LED and integrates a driver chip</li>
<li class="">Only <strong>1 GPIO digital signal line</strong> is needed to control a string of LEDs</li>
</ul>
<p>Typical uses:</p>
<ul>
<li class="">Status light</li>
<li class="">Marquee light</li>
<li class="">Motherboard lighting</li>
<li class="">Industrial control indicator light</li>
<li class="">Router/TV box breathing light</li>
</ul>
<p>WS2812 uses <strong>single-wire 800kHz NRZ protocol, not ordinary PWM</strong>. The Linux kernel cannot bit-bang fast enough directly, and must use something that can generate precise waveforms to drive it.</p>
<p>By searching the source code, I found that the project provides two drivers: one is leds-ws2812b, and the other is ws2812-pio-rp1. After careful inspection, I found that one is based on SPI, and the other is based on the PIO expansion chip method. <del>In our schematic, we can only use the spi hacking method.</del></p>
<p>The configuration method refers to the redmi configuration, just adapt it to dshanpi.</p>
<p>The PIN in the schematic does not have MOSI function, so SPI HACKING cannot be used. After consultation, we need to use the PWM HACKING method.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="mmc-driver-frequently-prints-errors">MMC driver frequently prints errors<a href="https://zephyr.100ask.org/en/blog/openwrt-feature-optimize#mmc-driver-frequently-prints-errors" class="hash-link" aria-label="Direct link to MMC driver frequently prints errors" title="Direct link to MMC driver frequently prints errors" translate="no">​</a></h2>
<p>Driver error messages:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">[ 1344.988178] mmc0: Timeout waiting for hardware interrupt.</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[ 1344.988672] mmc0: sdhci: ============ SDHCI REGISTER DUMP ===========</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[ 1344.989235] mmc0: sdhci: Sys addr:  0x00000002 | Version:  0x00000005</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[ 1344.989800] mmc0: sdhci: Blk size:  0x00007200 | Blk cnt:  0x00000002</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[ 1344.990364] mmc0: sdhci: Argument:  0x00069e72 | Trn mode: 0x0000003f</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[ 1344.990929] mmc0: sdhci: Present:   0x03f700f1 | Host ctl: 0x00000035</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[ 1344.991493] mmc0: sdhci: Power:     0x0000000d | Blk gap:  0x00000000</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[ 1344.992057] mmc0: sdhci: Wake-up:   0x00000000 | Clock:    0x0000030f</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[ 1344.992621] mmc0: sdhci: Timeout:   0x0000000e | Int stat: 0x00000000</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[ 1344.993185] mmc0: sdhci: Int enab:  0x03ff000b | Sig enab: 0x03ff000b</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[ 1344.993749] mmc0: sdhci: ACmd stat: 0x00000000 | Slot int: 0x00000000</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[ 1344.994313] mmc0: sdhci: Caps:      0x3a6dc881 | Caps_1:   0x08000007</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[ 1344.994876] mmc0: sdhci: Cmd:       0x0000123a | Max curr: 0x00000000</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[ 1344.995439] mmc0: sdhci: Resp[0]:   0x00000900 | Resp[1]:  0xfff6dbff</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[ 1344.996003] mmc0: sdhci: Resp[2]:   0x320f5903 | Resp[3]:  0x00009001</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[ 1344.996566] mmc0: sdhci: Host ctl2: 0x0000380f</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[ 1344.996957] mmc0: sdhci: ADMA Err:  0x00000060 | ADMA Ptr: 0x00000000fc300210</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[ 1344.997581] mmc0: sdhci: ============================================</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div></code></pre></div></div>
<p>Probe information in dmesg:</p>
<div class="language-plain codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-plain codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">[ 0.438699] mmc0: SDHCI controller on 2a330000.mmc [2a330000.mmc] using ADMA 64-bit</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[ 0.499319] mmc0: new HS400 Enhanced strobe MMC card at address 0001</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[ 0.500422] mmcblk0: mmc0:0001 CJNB4R 58.2 GiB</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[ 0.502009] mmcblk0: p1 p2 p3</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[ 0.502655] mmcblk0boot0: mmc0:0001 CJNB4R 4.00 MiB</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[ 0.503828] mmcblk0boot1: mmc0:0001 CJNB4R 4.00 MiB</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[ 0.504873] mmcblk0rpmb: mmc0:0001 CJNB4R 4.00 MiB, chardev (247:0)</span><br></div></code></pre></div></div>
<p>Based on AI search and the information in the DTS, it can be seen that the eMMC works completely normally during the power-on initialization stage. The controller registers/clock/reset/pinctrl are basically fine, otherwise it would not have successfully switched to HS400 ES and recognized partitions.</p>
<p>We can try downgrading to HS200 or reducing the frequency for testing, to find a stable working version. I tested two methods locally:</p>
<ol>
<li class="">Downgrade to HS200, without changing frequency</li>
</ol>
<div class="language-c codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-c codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">mmc</span><span class="token operator" style="color:#393A34">-</span><span class="token plain">hs200</span><span class="token operator" style="color:#393A34">-</span><span class="token number" style="color:#36acaa">1</span><span class="token plain">_8v</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">//mmc-hs400-1_8v;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">//mmc-hs400-enhanced-strobe;</span><br></div></code></pre></div></div>
<p>After testing, HS200 works fine, boot print:</p>
<div class="language-plain codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-plain codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">[    0.439179] mmc0: SDHCI controller on 2a330000.mmc [2a330000.mmc] using ADMA 64-bit</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[    0.492249] mmc0: new HS200 MMC card at address 0001</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[    0.493187] mmcblk0: mmc0:0001 CJNB4R 58.2 GiB</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[    0.494771]  mmcblk0: p1 p2 p3</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[    0.495416] mmcblk0boot0: mmc0:0001 CJNB4R 4.00 MiB</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[    0.496586] mmcblk0boot1: mmc0:0001 CJNB4R 4.00 MiB</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[    0.497629] mmcblk0rpmb: mmc0:0001 CJNB4R 4.00 MiB, chardev (247:0)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div></code></pre></div></div>
<ol start="2">
<li class="">Keep HS400 unchanged, reduce frequency to 100M</li>
</ol>
<div class="language-c codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-c codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">//max-frequency = &lt;200000000&gt;;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">max</span><span class="token operator" style="color:#393A34">-</span><span class="token plain">frequency </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token number" style="color:#36acaa">100000000</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">//work perfect on 100M</span><br></div></code></pre></div></div>
<p>After testing, it also works normally, boot print:</p>
<div class="language-plain codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-plain codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">[    0.439264] mmc0: SDHCI controller on 2a330000.mmc [2a330000.mmc] using ADMA 64-bit</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[    0.492185] mmc0: new HS400 Enhanced strobe MMC card at address 0001</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[    0.493275] mmcblk0: mmc0:0001 CJNB4R 58.2 GiB</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[    0.494696]  mmcblk0: p1 p2 p3</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[    0.495331] mmcblk0boot0: mmc0:0001 CJNB4R 4.00 MiB</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[    0.496498] mmcblk0boot1: mmc0:0001 CJNB4R 4.00 MiB</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[    0.497546] mmcblk0rpmb: mmc0:0001 CJNB4R 4.00 MiB, chardev (247:0)</span><br></div></code></pre></div></div>
<p>But I found that when using docker, there are various error prints:</p>
<p>So I'll use the minimal modification method: remove the HS400 mode configuration in the device tree and set the HS200 mode. Testing shows stable operation, so I'll use this for now.</p>]]></content:encoded>
            <category>OpenWrt</category>
            <category>Optimization</category>
            <category>RK3576</category>
        </item>
        <item>
            <title><![CDATA[OPENWRT System 2: Building a Custom System]]></title>
            <link>https://zephyr.100ask.org/en/blog/openwrt-custom-build</link>
            <guid>https://zephyr.100ask.org/en/blog/openwrt-custom-build</guid>
            <pubDate>Thu, 04 Dec 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[Build a custom OpenWrt system image.]]></description>
            <content:encoded><![CDATA[<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="preface">Preface<a href="https://zephyr.100ask.org/en/blog/openwrt-custom-build#preface" class="hash-link" aria-label="Direct link to Preface" title="Direct link to Preface" translate="no">​</a></h2>
<p><font style="color:rgb(17, 17, 51)">This document aims to provide developers and enthusiasts with a clear, concise OpenWrt (LEDE) firmware build guide, dedicated to the </font><strong><font style="color:rgb(17, 17, 51)">DshanPi A1 (based on Rockchip RK3576 platform)</font></strong><font style="color:rgb(17, 17, 51)"> development board. Through this process, you will complete the complete build process from source code acquisition, dependency updates, configuration customization (including OP domain and Kernel domain), to final firmware generation. The document also covers the minimal configuration generation method, common problem tips, and image output descriptions, helping users efficiently build stable firmware adapted to the hardware, laying the foundation for subsequent development, debugging, or deployment. Whether you are new to OpenWrt compilation or want to perform deep customization for the RK3576 platform, this document can serve as a practical reference.</font></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="configure-the-build-environment">Configure the Build Environment<a href="https://zephyr.100ask.org/en/blog/openwrt-custom-build#configure-the-build-environment" class="hash-link" aria-label="Direct link to Configure the Build Environment" title="Direct link to Configure the Build Environment" translate="no">​</a></h2>
<p>If you are building based on WSL, please refer to the <a href="https://www.yuque.com/jason-0nd0f/ts7m5t/dq8nprtdhgq5lk2a#wQtqk" target="_blank" rel="noopener noreferrer" class="">《1. Board Introduction and Development Environment Setup - Development Environment》</a> section to configure the WSL basic environment.</p>
<p>Then follow the repository readme to install the build toolchain needed for building. After installing the build-related dependencies, an example is as follows:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">sudo apt install -y ack antlr3 asciidoc autoconf automake autopoint binutils bison build-essential \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">bzip2 ccache clang cmake cpio curl device-tree-compiler flex gawk gcc-multilib g++-multilib gettext \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">genisoimage git gperf haveged help2man intltool libc6-dev-i386 libelf-dev libfuse-dev libglib2.0-dev \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">libgmp3-dev libltdl-dev libmpc-dev libmpfr-dev libncurses5-dev libncursesw5-dev libpython3-dev \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">libreadline-dev libssl-dev libtool llvm lrzsz msmtp ninja-build p7zip p7zip-full patch pkgconf \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">python3 python3-pyelftools python3-setuptools qemu-utils rsync scons squashfs-tools subversion \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">swig texinfo uglifyjs upx-ucl unzip vim wget xmlto xxd zlib1g-dev</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="obtain-the-source-code">Obtain the Source Code<a href="https://zephyr.100ask.org/en/blog/openwrt-custom-build#obtain-the-source-code" class="hash-link" aria-label="Direct link to Obtain the Source Code" title="Direct link to Obtain the Source Code" translate="no">​</a></h2>
<p>Just git clone the 100ask repository. Note that in some environments GitHub access may be restricted and cloning may fail. You can refer to the content in <a href="https://www.yuque.com/jason-0nd0f/ts7m5t/dq8nprtdhgq5lk2a#SD6lh" target="_blank" rel="noopener noreferrer" class="">《1. Board Introduction and Development Environment Setup - 3.3 WSL Network Proxy Settings》</a> to configure the http/https terminal proxy.</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">git clone https://github.com/dshanpi/RK3576-DshanPiA1_LEDE.git</span><br></div></code></pre></div></div>
<p>After downloading the source code, update feeds and download the corresponding packages:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">cd RK3576-DshanPiA1_LEDE</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">./scripts/feeds update -a</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">./scripts/feeds install -a</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="custom-options">Custom Options<a href="https://zephyr.100ask.org/en/blog/openwrt-custom-build#custom-options" class="hash-link" aria-label="Direct link to Custom Options" title="Direct link to Custom Options" translate="no">​</a></h2>
<p>After updating feeds, we can first use the default minimal configuration as a base, and then make custom configurations on top of it. An example is as follows:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">cp minimal.config .config</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">make defconfig # Will automatically fill in missing configuration items to make it a complete compilable configuration</span><br></div></code></pre></div></div>
<p>Subsequent configurations can be saved as defconfig and added to version control. For the specific method, see the 《4.5 Save Configuration》 section of this document.</p>
<p>After generating the base configuration, you can proceed with custom configuration. The command for custom configuration is:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">make menuconfig</span><br></div></code></pre></div></div>
<p>The system configuration, simply divided, can be mainly split into the following parts:</p>
<ul>
<li class="">busybox</li>
</ul>
<p>This part is the feature configuration of the base system. The base system of OpenWrt uses busybox.</p>
<ul>
<li class="">app</li>
</ul>
<p>This part corresponds to some commands or luci-xxx type applications with web pages. It mainly relies on this part to extend the router's functionality and expose easy-to-use configuration interfaces.</p>
<ul>
<li class="">libs</li>
</ul>
<p>This part mainly configures the libraries integrated into the OpenWrt system, which can be added as needed. Under normal circumstances, when certain commands or luci-type apps are selected, the corresponding libraries will be automatically selected.</p>
<ul>
<li class="">kernel</li>
</ul>
<p>This part mainly configures the kernel, including some kernel features and drivers. When there is new peripheral support, it needs to be configured here.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="configure-build-options">Configure Build Options<a href="https://zephyr.100ask.org/en/blog/openwrt-custom-build#configure-build-options" class="hash-link" aria-label="Direct link to Configure Build Options" title="Direct link to Configure Build Options" translate="no">​</a></h3>
<p>This part mainly configures some optimization parameters when building target files and some options for the build toolchain. Open it according to the following method:</p>
<ol>
<li class="">
<p>First enable Advanced configuration options (for developers):</p>
</li>
<li class="">
<p>Enable Target Options, and fill in the target optimization GCC build parameters:</p>
</li>
<li class="">
<p>Enable Toolchain Options, and configure the toolchain options:</p>
</li>
</ol>
<blockquote>
<p>Warning: The C library implementation here must be musl, otherwise after flashing and entering the system, all packages downloaded via Opkg will not be usable! (Because the default packages are all musl C library)!</p>
</blockquote>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="configure-busybox-options">Configure busybox Options<a href="https://zephyr.100ask.org/en/blog/openwrt-custom-build#configure-busybox-options" class="hash-link" aria-label="Direct link to Configure busybox Options" title="Direct link to Configure busybox Options" translate="no">​</a></h3>
<p>In some scenarios, OpenWrt's non-busybox configuration cannot cover the requirements and needs to be implemented through packages inside busybox. In this case, you need to customize the busybox options. You can refer to the following configuration method:</p>
<ol>
<li class="">Select Base System -&gt; Customize busybox options</li>
</ol>
<p>Among them, Settings are some additional parameter configurations, such as build options; Applets are configurations for command-line tools. We just need to make the corresponding configurations as needed.</p>
<p>Note that when OpenWrt's packages can provide the corresponding functionality, we should not provide it again in the busybox configuration. Otherwise, in the final stage of building, an error message will be prompted indicating that it is already provided but also exists in Busybox.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="configure-applications">Configure Applications<a href="https://zephyr.100ask.org/en/blog/openwrt-custom-build#configure-applications" class="hash-link" aria-label="Direct link to Configure Applications" title="Direct link to Configure Applications" translate="no">​</a></h3>
<p>OpenWrt contains a rich set of applications that can greatly enrich the router's functionality, including various libraries, command-line tools, and GUI apps (commonly referred to as plugins). Here we only provide some configuration examples for common apps.</p>
<p>Most packages are arranged in an orderly alphabetical order under each major category by classification. For example, if we want to enable sftp-server, we can find it under: Network -&gt; SSH page, and then select it. An example is as follows:</p>
<p>There is also a quicker method. Through the menuconfig configuration item search function, you can quickly locate the page to be configured and select it. Below is an example of the search method targeting sftp-server:</p>
<ol>
<li class="">
<p>In the menuconfig main interface, type / to enter the search page, and then enter sftp-server in the search page</p>
</li>
<li class="">
<p>According to the number index corresponding to (N) in the search result page, you can quickly jump to a certain result. For example, if there is only one result here, then the index is 1. Typing 1 directly will jump to the corresponding page.</p>
</li>
<li class="">
<p>You can see that the package corresponding to the current search page is =n, not enabled; after typing the index value to jump over, it is indeed not enabled. Correspondingly, at this time we only need to type y to enable it.</p>
</li>
<li class="">
<p>For cases with multiple search results, we can use the spacebar to turn pages and view results, or use the up and down keys to view results line by line. By viewing the detailed information on the search page, we can determine whether it is the package we are looking for.</p>
</li>
</ol>
<blockquote>
<p>Note: It is recommended to use both methods flexibly, which can greatly speed up development efficiency.</p>
</blockquote>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="configure-kernel-options">Configure kernel Options<a href="https://zephyr.100ask.org/en/blog/openwrt-custom-build#configure-kernel-options" class="hash-link" aria-label="Direct link to Configure kernel Options" title="Direct link to Configure kernel Options" translate="no">​</a></h3>
<p>The kernel configuration options are different from others. They are not configured by make menuconfig, but have a separate make target. An example is as follows:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">make kernel_menuconfig</span><br></div></code></pre></div></div>
<p>When the entire project has not been built before, executing the above command will automatically build the dependent toolchain first, which may be time-consuming. It is recommended to build the entire project once first, and then customize the kernel options.</p>
<p>Because the first time the entire project is built, all dependent source packages will be downloaded and the corresponding toolchain will be built, which is quite time-consuming.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="save-configuration">Save Configuration<a href="https://zephyr.100ask.org/en/blog/openwrt-custom-build#save-configuration" class="hash-link" aria-label="Direct link to Save Configuration" title="Direct link to Save Configuration" translate="no">​</a></h3>
<p>For the OP domain configuration, use the following command to generate the minimal configuration file:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">./scripts/diffconfig.sh &gt; defconfig</span><br></div></code></pre></div></div>
<p>For the kernel domain configuration, when configuring the kernel, the configuration will be automatically updated to the config file under target, so there is no need to save it manually.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="build">Build<a href="https://zephyr.100ask.org/en/blog/openwrt-custom-build#build" class="hash-link" aria-label="Direct link to Build" title="Direct link to Build" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="process">Process<a href="https://zephyr.100ask.org/en/blog/openwrt-custom-build#process" class="hash-link" aria-label="Direct link to Process" title="Direct link to Process" translate="no">​</a></h3>
<p>First perform the download operation, resolve any problems that may be encountered during the download process, and then execute the build process.</p>
<p>Avoiding downloads during the default build process is because if a certain package fails, when building again, it will check one by one whether the previous packages have been downloaded and built. This is not conducive to debugging. Execute the command as follows:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain"># When the download fails, use -j1 to view the specific failure information</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># The downloaded source packages are all stored in the dl directory under the project root directory</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">make download -j$(nproc)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># The first build is recommended to use single thread, testing multi-thread builds may fail!</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">make V=s -j1</span><br></div></code></pre></div></div>
<p>For the second build, you can execute:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">make V=s -j$(nproc)</span><br></div></code></pre></div></div>
<p>If you need to reconfigure, follow the process below:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">rm -rf .config</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">make menuconfig</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">make V=s -j$(nproc)</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="common-build-errors">Common Build Errors<a href="https://zephyr.100ask.org/en/blog/openwrt-custom-build#common-build-errors" class="hash-link" aria-label="Direct link to Common Build Errors" title="Direct link to Common Build Errors" translate="no">​</a></h3>
<p>Some programs will fail during building. At this time, we need to re-run using make V=s -j1 to better see the errors during the build process. Common ones include undefined or library-not-found errors, or errors caused by Werror. Below is a simple example of a solution.</p>
<p>For example, when initially using glibc for building, mbedtls and vlmcsd kept failing to build. Adding the following modifications allowed them to build:</p>
<div class="language-diff codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-diff codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">diff --git a/package/libs/mbedtls/Makefile b/package/libs/mbedtls/Makefile</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">index 4e0a4a034..54a0b2d45 100644</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">--- a/package/libs/mbedtls/Makefile</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">+++ b/package/libs/mbedtls/Makefile</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">@@ -121,7 +121,7 @@ This package contains mbedtls helper programs for private key and</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> CSR generation (gen_key, cert_req)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> endef</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> </span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">-TARGET_CFLAGS += -ffunction-sections -fdata-sections</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">+TARGET_CFLAGS += -ffunction-sections -fdata-sections -Wno-error=stringop-overflow</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> TARGET_CFLAGS := $(filter-out -O%,$(TARGET_CFLAGS))</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> </span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> CMAKE_OPTIONS += </span><br></div></code></pre></div></div>
<div class="language-diff codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-diff codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">--- Makefile.orig       2025-11-14 01:58:43.376952312 +0800</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">+++ Makefile    2025-11-14 01:53:50.865983762 +0800</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">@@ -37,4 +37,6 @@</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        $(INSTALL_BIN) ./files/vlmcsd.ini $(1)/etc/vlmcsd/vlmcsd.ini</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> endef</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> </span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">+TARGET_LDFLAGS += -lresolv -lpthread</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">+</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> $(eval $(call BuildPackage,vlmcsd))</span><br></div></code></pre></div></div>
<p>For more errors during the build process, flexibly use AI tools and search engines, and you can basically solve the problems encountered in building.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="flashing">Flashing<a href="https://zephyr.100ask.org/en/blog/openwrt-custom-build#flashing" class="hash-link" aria-label="Direct link to Flashing" title="Direct link to Flashing" translate="no">​</a></h2>
<p>After the build is complete, two types of image packages will be generated in the corresponding bin/target/xxxx directory: one is ext4 and the other is squashfs. If you need to restore default configuration, you need to use the squashfs image package.</p>
<font style="color:rgb(28, 30, 33)">Note: After OpenWrt compilation is complete, the flashable image will be compressed into a zip format file. You need to perform the decompression operation first before it can be used as the flashing image for the flashing tool. An example is as follows:</font>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">jason@ubuntu24:~/LEDE/bin/targets/rockchip/armv8$ gunzip -k openwrt-rockchip-armv8-100ask_dshanpia1-squashfs-sysupgrade.img.gz -f</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">gzip: openwrt-rockchip-armv8-100ask_dshanpia1-squashfs-sysupgrade.img.gz: decompression OK, trailing garbage ignored</span><br></div></code></pre></div></div>
<p>After decompressing to get the img image, refer to 《<a href="https://www.yuque.com/jason-0nd0f/ts7m5t/dq8nprtdhgq5lk2a" target="_blank" rel="noopener noreferrer" class="">Board Introduction and Development Environment Setup - 4.3 Start Flashing</a>》 for flashing.</p>
<p>The OpenWrt system's built-in online flashing function has problems when used. Refer to the 《<a href="https://www.yuque.com/jason-0nd0f/ts7m5t/hru38u3g3erf1yuv#G6G2J" target="_blank" rel="noopener noreferrer" class="">Existing Feature Optimization - 1.3 sysupgrade image cannot be used</a>》 section for adaptation. After adaptation, you can directly flash via the web method. An example is as follows:</p>
<blockquote>
<p>Note: The image package selected for web page online upgrade is the compressed image package!</p>
</blockquote>]]></content:encoded>
            <category>OpenWrt</category>
            <category>Build</category>
            <category>RK3576</category>
        </item>
        <item>
            <title><![CDATA[OPENWRT System 1: A1 Board Introduction and Development Environment Setup]]></title>
            <link>https://zephyr.100ask.org/en/blog/openwrt-board-env-setup</link>
            <guid>https://zephyr.100ask.org/en/blog/openwrt-board-env-setup</guid>
            <pubDate>Tue, 02 Dec 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[Introduce the DshanPi-A1 board and set up the OpenWrt development environment.]]></description>
            <content:encoded><![CDATA[<font style="color:rgb(28, 30, 33)">DShanPl-A1 Education is deeply optimized for artificial intelligence education and project development. Based on Rockchip's RK3576 processor, it integrates 4 Cortex-A72 and 4 Cortex-A53 cores with NEON instruction set support, supports 8K@30fps H.265, VP9 AVS2 and AV1 decoders, 4k@60fps H.264 decoder and 4K@60fps AV1 decoder; it also supports 4K@60fps H.264 and H.265 encoders. The built-in 3D GPU is fully compatible with OpenGl ES1.1/2.0/3.2, 0penCL2.0 and Vulkan 1.1. The embedded NPU computing power reaches up to 6TopS, supporting INT4/INT8/INT16/FP16 mixed operations.</font>
<p>The board has rich peripheral interfaces, and the onboard SOC delivers strong performance, providing a <font style="color:rgb(28, 30, 33)">mid-to-high-end performance SBC (Single Board Computer) experience, smart router, etc. Below are some corresponding application scenario examples:</font></p>
<ul>
<li class="">
<font style="color:rgb(64, 64, 64);background-color:rgb(252, 252, 252)">Smart standalone mini computer, with office, education, programming development, embedded development and other functions</font>
</li>
<li class="">
<font style="color:rgb(64, 64, 64);background-color:rgb(252, 252, 252)">Personal git repository, server, NAS, soft router, private cloud</font>
</li>
<li class="">
<font style="color:rgb(64, 64, 64);background-color:rgb(252, 252, 252)">Robot, drone and other projects</font>
</li>
<li class="">
<font style="color:rgb(64, 64, 64);background-color:rgb(252, 252, 252)">TV box, smart home hub, home security monitoring, smart speaker and other smart devices</font>
</li>
</ul>
<font style="color:rgb(28, 30, 33)">OpenWrt is an open-source Linux-based embedded operating system, mainly used for network devices such as routers. Compared with traditional router firmware, OpenWrt is not a fixed-function firmware, but a freely extensible software platform. Users can install various components through the opkg package system to implement routing, firewall, VPN, NAS, intranet penetration and many other functions. It provides an SSH command line and LuCI Web interface, with flexible configuration, supporting advanced network features such as VLAN, IPv6, QoS, and multi-WAN. OpenWrt has a clear, modular structure, with the core including the UCI configuration system, netifd network management, dnsmasq, hostapd, and the firewall framework. With its high customizability and strong community support, OpenWrt is suitable for home and enterprise networks as well as secondary development, making it an ideal choice for building high-function routers and network application platforms.  </font>
<font style="color:rgb(28, 30, 33)">Lean's OpenWrt LEDE repository is an open-source project maintained by Lean, aimed at providing stable, efficient and feature-rich support for the OpenWrt system. As a combination of the OpenWrt and LEDE projects, the Lean version provides optimized firmware and enhanced features for a wide range of routers and embedded devices, and is widely used in home, enterprise and laboratory environments. The Lean repository contains numerous patches, optimizations, drivers, and various third-party applications from the global open-source community, greatly enhancing the customizability and performance of the OpenWrt system.</font>
<p>The goal of this project is to build a lightweight NAS (lightweight NAS) application based on the DShanPl-A1 Education single-board. The best implementation path is to adopt the mature and highly extensible open-source routing system OpenWrt LEDE. With OpenWrt's complete Linux environment and rich ecological plugins, we can install storage services, network services, intranet penetration, secure access and other functional modules in the system as needed. Through the collaborative configuration among these plugins, combined with OpenWrt's powerful network management capabilities, a lightweight NAS solution based on a soft router architecture can be built.</p>
<h1>Development Environment</h1>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="environment-description">Environment Description<a href="https://zephyr.100ask.org/en/blog/openwrt-board-env-setup#environment-description" class="hash-link" aria-label="Direct link to Environment Description" title="Direct link to Environment Description" translate="no">​</a></h2>
<p>The official OpenWrt build recommends using the native <font style="color:rgb(51, 51, 51)"> </font><a href="https://openwrt.org/docs/guide-developer/toolchain/install-buildsystem" target="_blank" rel="noopener noreferrer" class=""><font style="color:rgb(51, 122, 183)">GNU/Linux environment</font></a><font style="color:rgb(51, 51, 51)">, but it also supports building using Windows WSL mode. Using a WSL development environment on Windows eliminates the need to configure a virtual machine environment, and can also be used in environments where installing VMware is restricted. Therefore, the author's build and development environment mostly prioritizes using WSL.</font></p>
<p>WSL (Windows Subsystem for Linux) provides a native-level Linux environment on Windows, suitable for developers to carry out cross-platform or Linux-related project development. Its main advantages include:</p>
<ol>
<li class=""><strong>Lightweight and fast</strong><font style="color:rgb(51, 51, 51)">: No virtual machine or dual system is needed. Startup and running are almost as fast as native Linux, with low resource consumption.</font></li>
<li class=""><strong>Seamless integration with Windows</strong><font style="color:rgb(51, 51, 51)">: Can directly access the Windows file system, and use Windows tools (such as VSCode, browser) together with Linux tools.</font></li>
<li class=""><strong>Native Linux experience</strong><font style="color:rgb(51, 51, 51)">: Supports most Linux commands, package managers, and build tools. You can directly compile, debug, and run services.</font></li>
<li class=""><strong>Easy to install and maintain</strong><font style="color:rgb(51, 51, 51)">: One-click installation from the Microsoft Store. System updates and environment switching are very convenient.</font></li>
<li class=""><strong>Excellent development experience</strong><font style="color:rgb(51, 51, 51)">: Supports mainstream development environments such as Docker (WSL2), Git, Python, Node.js, C/C++, suitable for embedded, server, network, AI and other fields.</font></li>
<li class=""><strong>Good cross-platform compatibility</strong><font style="color:rgb(51, 51, 51)">: Can build Linux-runnable software on Windows, such as compiling OpenWrt, building drivers, generating cross-compiled packages, etc.</font></li>
</ol>
<font style="color:rgb(51, 51, 51)">Overall, WSL allows developers to obtain near-native Linux capabilities on Windows at minimal cost, greatly improving efficiency and flexibility. We use VSCode remote access, which makes it very convenient to complete development work.</font>
<font style="color:rgb(51, 51, 51)">Below are some WSL environment configurations that need to be set before building. Copy this part to</font>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="environment-variable-configuration"><font style="color:rgb(51, 51, 51)">Environment Variable Configuration</font><a href="https://zephyr.100ask.org/en/blog/openwrt-board-env-setup#environment-variable-configuration" class="hash-link" aria-label="Direct link to environment-variable-configuration" title="Direct link to environment-variable-configuration" translate="no">​</a></h2>
<p>Refer to the official documentation: <a href="https://openwrt.org/docs/guide-developer/toolchain/wsl" target="_blank" rel="noopener noreferrer" class="">Build system setup WSL</a></p>
<p>In the WSL environment, in the build user's .bashrc, add the corresponding configuration information according to the instructions below to solve the problem that Windows environment variables are also effective by default in WSL. After this setting, the environment is basically consistent with the native GNU/LINUX environment, and there will be no issues with WSL's import mechanism.</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain"># GO build configuration, if it cannot be built, open this</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">#export GO111MODULE=on</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">#export GOPROXY=https://goproxy.cn</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># proxy, replace this with the proxy service IP:PORT of your own Windows environment</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">export http_proxy=http://192.168.31.50:6080</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">export https_proxy=http://192.168.31.50:6080</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">export REPO_URL='https://mirrors.tuna.tsinghua.edu.cn/git/git-repo'</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># Filter Windows PATH stuff</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">export PATH=$(echo $PATH | sed -e 's|:[^:]*WindowsApps[^:]*||g')</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">export PATH=$(echo $PATH | tr ':' '\n' | grep -v NVIDIA | tr '\n' ':')</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">export PATH=$(echo $PATH | tr ':' '\n' | grep -v 'Files' | paste -sd ':' -)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">export PATH=$(echo $PATH | tr ':' '\n' | grep -v 'VS' | paste -sd ':' -)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">export PATH=$(echo $PATH | tr ':' '\n' | grep -v '/mnt/' | paste -sd ':' -)</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="wsl-network-proxy-settings">WSL Network Proxy Settings<a href="https://zephyr.100ask.org/en/blog/openwrt-board-env-setup#wsl-network-proxy-settings" class="hash-link" aria-label="Direct link to WSL Network Proxy Settings" title="Direct link to WSL Network Proxy Settings" translate="no">​</a></h2>
<p>Since some tool packages are on GitHub, default network downloads may often fail. We can choose to run the corresponding proxy software on Windows, then enable allowing other devices to connect, and then configure the corresponding http_proxy and https_proxy environment variables in WSL, which can conveniently accelerate GitHub access.</p>
<p>Below are some configuration examples:</p>
<ol>
<li class="">
<p>Proxy software enables LAN device connection</p>
</li>
<li class="">
<p>Set the network mode to Mirrored in WSL Settings</p>
</li>
</ol>
<p>For more details, please refer to Microsoft's official documentation: <a href="https://learn.microsoft.com/zh-cn/windows/wsl/networking#mirrored-mode-networking" target="_blank" rel="noopener noreferrer" class="">Access network applications with WSL - Mirrored mode networking</a></p>
<ol start="3">
<li class="">
<p>After configuration, first run wsl --shutdown, and then restart wsl ubuntu</p>
</li>
<li class="">
<p>Check whether the environment variable WSL_PAC_URL has been configured successfully. A successful example is as follows:</p>
</li>
<li class="">
<p>Configure terminal http and https proxies, with automatic PAC filtering</p>
</li>
</ol>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">export http_proxy=$WSL_PAC_URL</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">export https_proxy=$WSL_PAC_URL</span><br></div></code></pre></div></div>
<blockquote>
<p>Tips: You can directly write this into the current user's .bashrc, so you don't have to execute the proxy settings every time.</p>
</blockquote>
<h1>Flashing Test Method</h1>
<p>This section introduces the basic method of flashing the LEDE image. You need to master the method of flashing the image in advance. Below is a detailed step-by-step introduction.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="hardware-connection">Hardware Connection<a href="https://zephyr.100ask.org/en/blog/openwrt-board-env-setup#hardware-connection" class="hash-link" aria-label="Direct link to Hardware Connection" title="Direct link to Hardware Connection" translate="no">​</a></h2>
<p><font style="color:rgb(28, 30, 33)">To flash the system image, in addition to the dshanpi-a1 board, you also need to prepare </font><strong><font style="color:rgb(28, 30, 33)">TypeC USB cable, 30W PD power adapter</font></strong><font style="color:rgb(28, 30, 33)"> (recommended to purchase from Weidongshan store), as shown below:</font></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="install-driver-and-flashing-software">Install Driver and Flashing Software<a href="https://zephyr.100ask.org/en/blog/openwrt-board-env-setup#install-driver-and-flashing-software" class="hash-link" aria-label="Direct link to Install Driver and Flashing Software" title="Direct link to Install Driver and Flashing Software" translate="no">​</a></h2>
<p>The tool packages and image files that need to be downloaded are as follows:</p>
<ul>
<li class=""><strong><font style="color:rgb(28, 30, 33)">OpenWrt system image:</font></strong><font style="color:rgb(28, 30, 33)"> </font><a href="https://dl.100ask.net/Hardware/MPU/RK3576-DshanPi-A1/openwrt-rockchip-armv8-100ask_dshanpia1-squashfs-sysupgrade.7z" target="_blank" rel="noopener noreferrer" class=""><font style="color:rgb(46, 133, 85)">DshanPi-A1_OpenWrt_Image</font></a><font style="color:rgb(46, 133, 85)"> (provided by 100ask)</font></li>
<li class=""><strong><font style="color:rgb(28, 30, 33)">Flashing tool RKDevTool:</font></strong><font style="color:rgb(28, 30, 33)"> </font><a href="https://dl.100ask.net/Hardware/MPU/RK3576-DshanPi-A1/RKDevTool_Release_v3.32.zip" target="_blank" rel="noopener noreferrer" class=""><font style="color:rgb(46, 133, 85)">RKDevTool_Release_v3.32.zip</font></a></li>
<li class=""><strong><font style="color:rgb(28, 30, 33)">Driver installation tool package DriverAssitant:</font></strong><font style="color:rgb(28, 30, 33)"> </font><a href="https://dl.100ask.net/Hardware/MPU/RK3576-DshanPi-A1/DriverAssitant_v5.1.1.zip" target="_blank" rel="noopener noreferrer" class=""><font style="color:rgb(46, 133, 85)">DriverAssitant_v5.1.1.zip</font></a></li>
<li class=""><strong><font style="color:rgb(28, 30, 33)">DshanPi-A1 bootloader firmware:</font></strong><font style="color:rgb(28, 30, 33)"> </font><a href="https://dl.100ask.net/Hardware/MPU/RK3576-DshanPi-A1/rk3576_spl_loader_v1.09.107.bin" target="_blank" rel="noopener noreferrer" class=""><font style="color:rgb(46, 133, 85)">rk3576_spl_loader_v1.09.107.bin</font></a></li>
</ul>
<font style="color:rgb(28, 30, 33)">Find the driver installation tool package DriverAssitant_v5.1.1.zip in the previously downloaded materials, extract it, then open and launch the download program DriverInstall.exe, click driver installation, as follows:</font>
<p>Extract the flashing tool RKDevTool_Release_v3.32.zip downloaded from the previous link, and then directly double-click RKDevTool.exe.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="start-flashing">Start Flashing<a href="https://zephyr.100ask.org/en/blog/openwrt-board-env-setup#start-flashing" class="hash-link" aria-label="Direct link to Start Flashing" title="Direct link to Start Flashing" translate="no">​</a></h2>
<font style="color:rgb(28, 30, 33)">After the preparation is complete, follow the steps below to make the device enter the MASKROM flashing mode:</font>
<p><font style="color:rgb(28, 30, 33)">1. Connect the </font><strong><font style="color:rgb(28, 30, 33)">usb2.0/3.0 otg</font></strong><font style="color:rgb(28, 30, 33)"> cable (i.e., the type-c flashing data cable, the other end of the data cable connects to the computer's USB2.0/3.0 blue port);</font></p>
<p><font style="color:rgb(28, 30, 33)">2. Press and hold the </font><code>**&lt;font style={{color: 'rgb(28, 30, 33)', backgroundColor: 'rgb(246, 247, 248)'}}&gt;MASKROM&lt;/font&gt;**</code><font style="color:rgb(28, 30, 33)"> button, </font><strong><font style="color:rgb(28, 30, 33)">do not release it first</font></strong><font style="color:rgb(28, 30, 33)"> ;</font></p>
<p><font style="color:rgb(28, 30, 33)">3. Then connect the power supply, and the dshanpi-a1 will enter the </font><code>**&lt;font style={{color: 'rgb(28, 30, 33)', backgroundColor: 'rgb(246, 247, 248)'}}&gt;MASKROM&lt;/font&gt;**</code><font style="color:rgb(28, 30, 33)"> flashing mode;</font></p>
<font style="color:rgb(28, 30, 33)">Open the flashing tool, select the interface parameters as below, configure the flashing image and parameters, then click execute, and wait for the download to complete. After flashing is complete, the board will automatically restart, and then the LEDE pixel LOGO will appear, indicating that flashing is complete.</font>
<font style="color:rgb(28, 30, 33)">Note: After OpenWrt compilation is complete, the flashable image will be compressed into a zip format file. You need to perform the decompression operation first before it can be used as the flashing image for the flashing tool. An example is as follows:</font>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">jason@ubuntu24:~/LEDE/bin/targets/rockchip/armv8$ gunzip -k openwrt-rockchip-armv8-100ask_dshanpia1-squashfs-sysupgrade.img.gz -f</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">gzip: openwrt-rockchip-armv8-100ask_dshanpia1-squashfs-sysupgrade.img.gz: decompression OK, trailing garbage ignored</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># Wait for the img image file input</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">jason@ubuntu24:~/LEDE/bin/targets/rockchip/armv8$ ls -lh openwrt-rockchip-armv8-100ask_dshanpia1-squashfs-sysupgrade.img</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">-rw-r--r-- 1 jason jason 640M Nov 28 02:24 openwrt-rockchip-armv8-100ask_dshanpia1-squashfs-sysupgrade.img</span><br></div></code></pre></div></div>
<h1>Reference Documents</h1>
<ul>
<li class=""><a href="https://wiki.dshanpi.org/docs/DshanPi-A1/intro/" target="_blank" rel="noopener noreferrer" class="">100ask DshanPi-A1 Introduction</a></li>
<li class=""><a href="https://wiki.dshanpi.org/docs/DshanPi-A1/OtherSystem/OpenWrt-LEDE/FlasheMMC" target="_blank" rel="noopener noreferrer" class="">100ask OpenWrt System Image Flashing to EMMC</a></li>
<li class=""><a href="https://openwrt.org/docs/guide-developer/start" target="_blank" rel="noopener noreferrer" class="">https://openwrt.org/docs/guide-developer/start</a></li>
<li class=""><a href="https://www.cnblogs.com/lx2035/p/17961653" target="_blank" rel="noopener noreferrer" class="">openwrt build record - LX2020 - cnblogs</a></li>
</ul>]]></content:encoded>
            <category>OpenWrt</category>
            <category>Dev Environment</category>
            <category>RK3576</category>
        </item>
        <item>
            <title><![CDATA[DshanPI-A1 Audio Recording, Playback and Noise Analysis]]></title>
            <link>https://zephyr.100ask.org/en/blog/audio-record-noise-analysis</link>
            <guid>https://zephyr.100ask.org/en/blog/audio-record-noise-analysis</guid>
            <pubDate>Sun, 30 Nov 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[Implement audio recording and playback on RK3576, and perform spectrum analysis on noise.]]></description>
            <content:encoded><![CDATA[<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="audio-playback">Audio Playback<a href="https://zephyr.100ask.org/en/blog/audio-record-noise-analysis#audio-playback" class="hash-link" aria-label="Direct link to Audio Playback" title="Direct link to Audio Playback" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="speaker-device">Speaker Device<a href="https://zephyr.100ask.org/en/blog/audio-record-noise-analysis#speaker-device" class="hash-link" aria-label="Direct link to Speaker Device" title="Direct link to Speaker Device" translate="no">​</a></h3>
<p>Let's first look at how to use this speaker. First, list the audio playback devices.</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">aplay -l</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    **** List of PLAYBACK Hardware Devices ****</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    card 0: rockchipes8388 [rockchip-es8388], device 0: dailink-multicodecs ES8323 HiFi-0 [dailink-multicodecs ES8323 HiFi-0]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      Subdevices: 1/1</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      Subdevice #0: subdevice #0</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    card 1: rockchiphdmiin [rockchip,hdmiin], device 0: 2a640000.sai-dummy_codec dummy_codec-0 [2a640000.sai-dummy_codec dummy_codec-0]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      Subdevices: 1/1</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      Subdevice #0: subdevice #0</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    card 2: rockchipdp0 [rockchip-dp0], device 0: rockchip-dp0 spdif-hifi-0 [rockchip-dp0 spdif-hifi-0]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      Subdevices: 1/1</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      Subdevice #0: subdevice #0</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    card 3: rockchiphdmi [rockchip-hdmi], device 0: rockchip-hdmi i2s-hifi-0 [rockchip-hdmi i2s-hifi-0]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      Subdevices: 1/1</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      Subdevice #0: subdevice #0</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div></code></pre></div></div>
<p>It can be seen that a total of <strong>4 audio cards</strong> are detected (card 0 ~ card 3)</p>
<ul>
<li class=""><strong>Play audio to speaker/headphones</strong>: use <code>card 0, device 0</code></li>
<li class=""><strong>HDMI audio output</strong>: use <code>card 3, device 0</code></li>
<li class=""><strong>DisplayPort audio</strong>: use <code>card 2, device 0</code></li>
<li class=""><strong>Capture HDMI input audio</strong>: use <code>card 1, device 0</code></li>
</ul>
<p>The speaker is <strong>card0: subdevice#0</strong>, and the corresponding ALSA device is <strong>hw:0,0</strong></p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">**** List of PLAYBACK Hardware Devices ****</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">card 0: rockchipes8388 [rockchip-es8388], device 0: dailink-multicodecs ES8323 HiFi-0 [dailink-multicodecs ES8323 HiFi-0]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  Subdevices: 1/1</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  Subdevice #0: subdevice #0</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="create-and-play-a-simple-test-tone"><strong>Create and Play a Simple Test Tone</strong><a href="https://zephyr.100ask.org/en/blog/audio-record-noise-analysis#create-and-play-a-simple-test-tone" class="hash-link" aria-label="Direct link to create-and-play-a-simple-test-tone" title="Direct link to create-and-play-a-simple-test-tone" translate="no">​</a></h3>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain"># Create a 1kHz sine wave WAV file at 8kHz sample rate (5 seconds)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">ffmpeg -f lavfi -i "sine=frequency=1000:duration=5" -c:a pcm_s16le -ar 8000 test_tone.wav</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># Play the file</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">aplay test_tone.wav</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">	Playing WAVE 'test_tone.wav' : Signed 16 bit Little Endian, Rate 8000 Hz, Mono</span><br></div></code></pre></div></div>
<p>The test commands all succeeded, but no sound was heard. We need to check the properties of this speaker. It is very likely an audio routing issue. First, we need to determine the troubleshooting approach:</p>
<p>The audio chip (ES8388) is designed with:</p>
<ul>
<li class=""><strong>Software control layer</strong>: <code>Speaker Switch</code> - controls whether the audio stream is sent to the chip</li>
<li class=""><strong>Hardware control layer</strong>: <code>OUT1/OUT2 Switch</code> - controls the chip's physical pin output</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="audio-playback-debugging">Audio Playback Debugging<a href="https://zephyr.100ask.org/en/blog/audio-record-noise-analysis#audio-playback-debugging" class="hash-link" aria-label="Direct link to Audio Playback Debugging" title="Direct link to Audio Playback Debugging" translate="no">​</a></h3>
<p>First, open the audio visualization tool to take a look.</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">alsamixer -c 0</span><br></div></code></pre></div></div>
<p>It can be seen that the playback status is abnormal: <strong>MM 00</strong>. We need to further confirm which configuration is the problem. Use the <strong>PulseAudio control tool</strong>.</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">pactl list short sinks</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    0       alsa_output.0.HiFi__hw_rockchipes8388__sink     module-alsa-card.c      s16le 2ch 44100Hz       SUSPENDED</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    1       alsa_output.1.stereo-fallback   module-alsa-card.c      s16le 2ch 44100Hz       SUSPENDED</span><br></div></code></pre></div></div>
<p>Some explanations:</p>
<ul>
<li class=""><strong>Sink</strong>: the endpoint of audio output</li>
<li class=""><strong>PulseAudio architecture</strong></li>
</ul>
<div class="language-ini codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-ini codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">Application -&gt; Audio stream -&gt; PulseAudio server -&gt; Sink -&gt; Hardware</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">(player)              (mixer)          (output device)    (sound card)</span><br></div></code></pre></div></div>
<p><strong>Status description</strong></p>
<ul>
<li class=""><strong>RUNNING</strong>: audio is playing</li>
<li class=""><strong>IDLE</strong>: idle, ready</li>
<li class=""><strong>SUSPENDED</strong>: suspended, power-saving mode</li>
<li class=""><strong>UNLINKED</strong>: not connected</li>
</ul>
<p><strong>Device details</strong></p>
<ul>
<li class=""><strong>sink 0</strong>: <code>alsa_output.0.HiFi__hw_rockchipes8388__sink</code>
<ul>
<li class="">Corresponds to ALSA sound card 0 (ES8388 audio chip)</li>
<li class="">High fidelity (HiFi) output</li>
</ul>
</li>
<li class=""><strong>sink 1</strong>: <code>alsa_output.1.stereo-fallback</code>
<ul>
<li class="">Fallback/backup output device</li>
<li class="">Used when the primary device is unavailable</li>
</ul>
</li>
</ul>
<p><strong>Both audio sinks are in SUSPENDED state</strong></p>
<div class="language-ini codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-ini codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">0 ... SUSPENDED</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">1 ... SUSPENDED</span><br></div></code></pre></div></div>
<p><strong>SUSPENDED state means</strong>:</p>
<ul>
<li class="">PulseAudio thinks there is no audio stream to play</li>
<li class="">To save power, it automatically suspends audio output</li>
<li class="">The system is ready to receive audio, but there is currently no active audio stream</li>
</ul>
<p><strong>Root cause chain</strong>:</p>
<ol>
<li class="">
<p><strong>At system startup</strong> -&gt; PulseAudio loads audio devices</p>
</li>
<li class="">
<p><strong>No active audio stream</strong> -&gt; PulseAudio suspends the device (SUSPENDED)</p>
</li>
<li class="">
<p><strong>Hardware routing not activated</strong> -&gt; OUT1/OUT2 switches are off by default</p>
</li>
<li class="">
<p><strong>When starting to play audio</strong>:</p>
<ul>
<li class="">PulseAudio wakes up the device</li>
<li class=""><strong>But</strong> the hardware switches (OUT/OUT2) are still off</li>
<li class="">Need to manually <code>amixer -c 0 sset 'OUT1' on</code></li>
</ul>
<p>After my testing, after turning on</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">amixer -c 0 sset 'OUT2' on</span><br></div></code></pre></div></div>
<p>the speaker audio can be played normally. Here as a record, I list some useful commands I used during debugging.</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">#1. View more detailed sink information</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">pactl list sinks</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    Sink #0</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        ...</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    Sink #1</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">		...</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 2. View current audio streams</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">pactl list sink-inputs</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">#3. ALSA content control</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">amixer -c 0 scontents</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">	...</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">amixer -c 0 get 'Speaker'</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">amixer -c 0 get 'Master'</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">amixer -c 0 get 'Headphone'</span><br></div></code></pre></div></div>
</li>
</ol>
<p>There are multiple solutions to this problem, listed below.</p>
<p><strong>Solution 1: Prevent auto-suspend</strong></p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain"># Edit PulseAudio configuration</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">vi /etc/pulse/default.pa</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    # Prevent auto-suspend</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    load-module module-suspend-on-idle timeout=0  # 0 means never suspend</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    # Increase timeout</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    load-module module-suspend-on-idle timeout=3600  # 1 hour</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># Restart PulseAudio</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">pulseaudio -k</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">pulseaudio --start</span><br></div></code></pre></div></div>
<p><strong>Solution 2: Automatically activate hardware at startup</strong></p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain"># Create startup script /etc/pulse/audio-init.sh</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">#!/bin/bash</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># Wait for PulseAudio to start</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sleep 3</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># Activate hardware output</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">amixer -c 0 sset 'OUT2' on</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">amixer -c 0 sset 'Speaker' on</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># Set appropriate volume</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">amixer -c 0 sset 'Output 2' 90%</span><br></div></code></pre></div></div>
<p><strong>Solution 3: Use udev rules</strong></p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain"># Create /etc/udev/rules.d/90-audio.rules</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">ACTION=="add", SUBSYSTEM=="sound", KERNEL=="card0", \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    RUN+="/usr/bin/amixer -c 0 sset 'OUT2' on"</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># Takes effect after reboot</span><br></div></code></pre></div></div>
<p><strong>Solution 4: Simplest temporary test</strong></p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain"># Activate the device before playing</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">amixer -c 0 sset 'Speaker' on</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">amixer -c 0 sset 'OUT2' on</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">amixer -c 0 sset 'Output 2' 90%</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># You can also permanently save settings (did not take effect)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">alsactl store</span><br></div></code></pre></div></div>
<p><strong>Summary: The problem is actually:</strong></p>
<ul>
<li class=""><strong>Software layer</strong>: PulseAudio is normal</li>
<li class=""><strong>Driver layer</strong>: ALSA correctly identifies the device</li>
<li class=""><strong>Hardware layer</strong>: OUT2 physical switch needs to be manually activated</li>
</ul>
<p><strong>tips: Audio routing</strong></p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain"># Assume there are multiple audio devices:</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 0 - built-in speaker</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 1 - USB headset</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 2 - HDMI output</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># Send Chrome audio to the headset</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">pactl move-sink-input $(pactl list short sink-inputs | grep chrome | awk '{print $1}') 1</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># Send music player to HDMI</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">pactl move-sink-input $(pactl list short sink-inputs | grep spotify | awk '{print $1}') 2</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="audio-recording">Audio Recording<a href="https://zephyr.100ask.org/en/blog/audio-record-noise-analysis#audio-recording" class="hash-link" aria-label="Direct link to Audio Recording" title="Direct link to Audio Recording" translate="no">​</a></h2>
<p>The hardware used is the 100ask 200w USB camera + audio MEMS integrated module, as shown in the figure below.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="device-information-acquisition">Device Information Acquisition<a href="https://zephyr.100ask.org/en/blog/audio-record-noise-analysis#device-information-acquisition" class="hash-link" aria-label="Direct link to Device Information Acquisition" title="Direct link to Device Information Acquisition" translate="no">​</a></h3>
<p>First, we need to obtain the information of the entire MEMS. It communicates with RK3576 via USB. There are several ways to see its information.</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">v4l2-sysfs-path</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    Video device: video36</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            video: video37</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            sound card: hw:4</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            pcm capture: hw:4,0</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            mixer: hw:4</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    Video device: video37</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            sound card: hw:4</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            pcm capture: hw:4,0</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            mixer: hw:4</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">   .....</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">alsactl info</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    ......</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    - card: 4</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      id: Camera</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      name: USB 2.0 Camera</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      longname: lihappe8 Corp. USB 2.0 Camera at usb-xhci-hcd.8.auto-1.2.2, high speed</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      driver_name: USB-Audio</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      mixer_name: USB Mixer</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      components: USB038f:0541</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      controls_count: 4</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      pcm:</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        - stream: CAPTURE</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">          devices:</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            - device: 0</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">              id: USB Audio</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">              name: USB Audio</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">              subdevices:</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                - subdevice: 0</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                  name: subdevice #0</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    .....</span><br></div></code></pre></div></div>
<p>It can be seen that the name of this device in ALSA is <strong>hw:4,0</strong></p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="audio-recording-test">Audio Recording Test<a href="https://zephyr.100ask.org/en/blog/audio-record-noise-analysis#audio-recording-test" class="hash-link" aria-label="Direct link to Audio Recording Test" title="Direct link to Audio Recording Test" translate="no">​</a></h3>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain"># Record a segment of background noise</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">arecord -D hw:4,0 -f S16_LE -r 8000 -c 2 -d 10 noise</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">	Recording WAVE 'noise.wav' : Signed 16 bit Little Endian, Rate 8000 Hz, Stereo</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">aplay noise.wav</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">	Playing WAVE 'noise.wav' : Signed 16 bit Little Endian, Rate 8000 Hz, Stereo</span><br></div></code></pre></div></div>
<p>A clear "squeak" sound can be heard. The self-noise of this MEMS is still quite large. Noise reduction is needed later before normal voice communication can be performed.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="noise-analysis">Noise Analysis<a href="https://zephyr.100ask.org/en/blog/audio-record-noise-analysis#noise-analysis" class="hash-link" aria-label="Direct link to Noise Analysis" title="Direct link to Noise Analysis" translate="no">​</a></h3>
<p>Use sox to generate a spectrogram.</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">sox noise.wav -n spectrogram -o noise_spectrogram.pn</span><br></div></code></pre></div></div>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain"># Global spectrum</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sox noise.wav -n spectrogram -d 10 -x 1200 -z 80 -o noise_full.png</span><br></div></code></pre></div></div>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">sox noise.wav -r 2000 -c 1 noise_2k.wav</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sox noise_2k.wav -n spectrogram -d 10 -x 1200 -z 80 -o noise_low.png</span><br></div></code></pre></div></div>
<p><strong>Overall observation: the background noise is "approximately white noise + strong low-frequency peaks + slight mid-frequency texture noise"</strong></p>
<p><strong>1. There is a very obvious low-frequency energy blob around 0~200Hz (especially &lt;100Hz)</strong></p>
<p>This generally means:</p>
<ul>
<li class=""><strong>Mechanical/power-related noise</strong></li>
<li class=""><strong>Fan, vibration, chassis resonance</strong></li>
<li class=""><strong>Power ripple (50Hz / 60Hz + fundamental)</strong></li>
<li class=""><strong>Microphone directivity/enclosure coupling amplifying ultra-low frequency noise</strong></li>
</ul>
<p><strong>2. The 1kHz~4kHz range is random noise (approximately white noise) with low energy</strong></p>
<p>This indicates the microphone self-noise is typical:</p>
<ul>
<li class="">MEMS microphone inherent noise</li>
<li class="">ADC self-noise</li>
<li class="">Amplifier input noise</li>
</ul>
<p>This part is the <strong>system noise floor</strong>.</p>
<p><strong>3. High frequency (&gt;6kHz) has no strange peaks at all</strong></p>
<p>This is very good -&gt; no obvious:</p>
<ul>
<li class="">Digital EMI</li>
<li class="">Clock leakage</li>
<li class="">Sampling jitter noise</li>
</ul>
<hr>
<p><strong>4. No obvious "howling mode" appears</strong></p>
<p>None of the three figures show typical howling characteristics:</p>
<ul>
<li class="">Howling is usually a fixed-frequency bright line that remains unchanged</li>
<li class="">The figures only show <strong>a pulse at the starting moment (may be the click sound when recording starts)</strong></li>
</ul>
<p>No stable peak persists over time.</p>
<p><strong>Per-figure analysis</strong></p>
<hr>
<p><strong>(A) First figure: Full spectrum (up to 4kHz)</strong></p>
<p>The characteristics look like:</p>
<p>Overall reddish/purple, noise density is high but uniform
Obvious vertical line around 50Hz
100Hz, 150Hz also have slight energy</p>
<p>-&gt; This is almost certainly:</p>
<p><strong>Power frequency noise (50/60Hz) + harmonics (100/150Hz)</strong></p>
<p><strong>Reasons:</strong></p>
<ul>
<li class="">USB power supply brings a lot of 50/60Hz hum</li>
<li class="">Poor isolation of the sound card or microphone analog front-end</li>
<li class="">Unclean ground (such as USB common ground loop)</li>
</ul>
<hr>
<p><strong>(B) Second figure: Version with narrowed dynamic range (-80dBFS)</strong></p>
<p>This figure additionally exposes:</p>
<p>There is a very narrow horizontal line at 1.8kHz ~ 2.2kHz</p>
<p>Very faint, but stably present.</p>
<p>This indicates:</p>
<p><strong>System clock/PLL interference leakage</strong></p>
<p>Common in:</p>
<ul>
<li class="">I2S/MCLK leakage</li>
<li class="">Clock coupling of the microphone on the PCB</li>
<li class="">Digital power noise superimposed on the microphone analog part</li>
</ul>
<p>This part will not cause howling, but will reduce SNR.</p>
<hr>
<p><strong>(C) Third figure: Low frequency to 1000Hz</strong></p>
<p>Very typical:</p>
<p>The noise in the &lt;150Hz region is much higher than other frequency bands</p>
<p>Like a large "bulb" shape, very obvious.</p>
<p>This indicates:</p>
<p><strong>Low-frequency vibration + power noise are the main noise floor sources</strong></p>
<p>Including:</p>
<ul>
<li class="">Chassis vibration, fan, tabletop resonance</li>
<li class="">Power 50/60Hz + harmonics</li>
<li class="">The microphone's own LF roll-off is insufficient</li>
</ul>
<hr>
<p><strong>Comprehensive judgment: Background noise composition ratio</strong></p>
<table><thead><tr><th>Noise type</th><th>Ratio</th><th>Feature</th></tr></thead><tbody><tr><td><strong>Low-frequency mechanical/power noise (&lt;200Hz)</strong></td><td>50%</td><td>Largest source, from power, chassis, vibration</td></tr><tr><td><strong>Power frequency leakage 50/60Hz + harmonics</strong></td><td>25%</td><td>Strongest fixed peak in the figure</td></tr><tr><td><strong>Microphone inherent white noise</strong></td><td>20%</td><td>Random noise scattered in 1k~4kHz</td></tr><tr><td><strong>Digital clock leakage (around 2kHz)</strong></td><td>5%</td><td>A very weak but visible thin line</td></tr></tbody></table>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="psd-noise-model-analysis">PSD Noise Model Analysis<a href="https://zephyr.100ask.org/en/blog/audio-record-noise-analysis#psd-noise-model-analysis" class="hash-link" aria-label="Direct link to PSD Noise Model Analysis" title="Direct link to PSD Noise Model Analysis" translate="no">​</a></h3>
<p>Use Python to generate a PSD noise model.</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> numpy </span><span class="token keyword" style="color:#00009f">as</span><span class="token plain"> np</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> matplotlib</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">pyplot </span><span class="token keyword" style="color:#00009f">as</span><span class="token plain"> plt</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">from</span><span class="token plain"> scipy</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">io </span><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> wavfile</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">from</span><span class="token plain"> scipy</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">signal </span><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> welch</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> find_peaks</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> spectrogram</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> butter</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> sosfilt</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> IPython</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">display </span><span class="token keyword" style="color:#00009f">as</span><span class="token plain"> ipd</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> os</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">rate</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> data </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> wavfile</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">read</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"/mnt/data/noise.wav"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> data</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">ndim</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    data </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> data</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">mean</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">axis</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">data </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> data</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">astype</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">np</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">float32</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">N </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token builtin">len</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">data</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">duration </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> N </span><span class="token operator" style="color:#393A34">/</span><span class="token plain"> rate</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># Calculate overall RMS and dBFS</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># Assuming 16-bit PCM if dtype was int16; determine scale</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># infer max possible value from original dtype by reloading header:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> struct</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># Determine dtype max</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># but we'll normalize by max of int16 if dtype came as int16, else use max(abs(data))</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">max_possible </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">32768.0</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">rms </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> np</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">sqrt</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">np</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">mean</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">data</span><span class="token operator" style="color:#393A34">**</span><span class="token number" style="color:#36acaa">2</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">dbfs_rms </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">20</span><span class="token operator" style="color:#393A34">*</span><span class="token plain">np</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">log10</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">rms </span><span class="token operator" style="color:#393A34">/</span><span class="token plain"> max_possible</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> rms</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token number" style="color:#36acaa">0</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">else</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token plain">np</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">inf</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># Welch PSD</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">f</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> Pxx </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> welch</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">data</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> fs</span><span class="token operator" style="color:#393A34">=</span><span class="token plain">rate</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> nperseg</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">4096</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> scaling</span><span class="token operator" style="color:#393A34">=</span><span class="token string" style="color:#e3116c">'density'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># find peaks in PSD (in linear)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">peaks</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> props </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> find_peaks</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">Pxx</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> height</span><span class="token operator" style="color:#393A34">=</span><span class="token plain">np</span><span class="token punctuation" style="color:#393A34">.</span><span class="token builtin">max</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">Pxx</span><span class="token punctuation" style="color:#393A34">)</span><span class="token operator" style="color:#393A34">*</span><span class="token number" style="color:#36acaa">0.15</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> distance</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">5</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">peak_freqs </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> f</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">peaks</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">peak_heights </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> props</span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">'peak_heights'</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># Find dominant low-frequency peak under 500Hz</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">low_idx </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> np</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">where</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">f</span><span class="token operator" style="color:#393A34">&lt;=</span><span class="token number" style="color:#36acaa">500</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">low_f </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> f</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">low_idx</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">low_P </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> Pxx</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">low_idx</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">lp_peaks</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> lp_props </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> find_peaks</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">low_P</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> height</span><span class="token operator" style="color:#393A34">=</span><span class="token plain">np</span><span class="token punctuation" style="color:#393A34">.</span><span class="token builtin">max</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">low_P</span><span class="token punctuation" style="color:#393A34">)</span><span class="token operator" style="color:#393A34">*</span><span class="token number" style="color:#36acaa">0.2</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">lp_freqs </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> low_f</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">lp_peaks</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">lp_heights </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> lp_props</span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">'peak_heights'</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># Short-time energy to find transient (e.g., first second pulse)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">frame_ms </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">20</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">frame_len </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token builtin">int</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">rate </span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> frame_ms</span><span class="token operator" style="color:#393A34">/</span><span class="token number" style="color:#36acaa">1000</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">hop </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> frame_len</span><span class="token operator" style="color:#393A34">//</span><span class="token number" style="color:#36acaa">2</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">frames </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">for</span><span class="token plain"> start </span><span class="token keyword" style="color:#00009f">in</span><span class="token plain"> </span><span class="token builtin">range</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> N</span><span class="token operator" style="color:#393A34">-</span><span class="token plain">frame_len</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> hop</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    frames</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">append</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">np</span><span class="token punctuation" style="color:#393A34">.</span><span class="token builtin">sum</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">data</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">start</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain">start</span><span class="token operator" style="color:#393A34">+</span><span class="token plain">frame_len</span><span class="token punctuation" style="color:#393A34">]</span><span class="token operator" style="color:#393A34">**</span><span class="token number" style="color:#36acaa">2</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">frames </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> np</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">array</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">frames</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">frame_times </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">np</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">arange</span><span class="token punctuation" style="color:#393A34">(</span><span class="token builtin">len</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">frames</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token operator" style="color:#393A34">*</span><span class="token plain">hop</span><span class="token punctuation" style="color:#393A34">)</span><span class="token operator" style="color:#393A34">/</span><span class="token plain">rate</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># detect where energy spikes relative to median</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">median_e </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> np</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">median</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">frames</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">spikes </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> np</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">where</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">frames </span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> median_e</span><span class="token operator" style="color:#393A34">*</span><span class="token number" style="color:#36acaa">8</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic"># 8x median</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">spike_times </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> frame_times</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">spikes</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># Spectrogram</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">f_s</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> t_s</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> Sxx </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> spectrogram</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">data</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> fs</span><span class="token operator" style="color:#393A34">=</span><span class="token plain">rate</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> nperseg</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">2048</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> noverlap</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">1024</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> scaling</span><span class="token operator" style="color:#393A34">=</span><span class="token string" style="color:#e3116c">'density'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> mode</span><span class="token operator" style="color:#393A34">=</span><span class="token string" style="color:#e3116c">'magnitude'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># Plot PSD with peaks marked</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">plt</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">figure</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">figsize</span><span class="token operator" style="color:#393A34">=</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">10</span><span class="token punctuation" style="color:#393A34">,</span><span class="token number" style="color:#36acaa">5</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">plt</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">semilogy</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">f</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> Pxx</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> color</span><span class="token operator" style="color:#393A34">=</span><span class="token string" style="color:#e3116c">'tab:orange'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">plt</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">scatter</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">peak_freqs</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> peak_heights</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> color</span><span class="token operator" style="color:#393A34">=</span><span class="token string" style="color:#e3116c">'k'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> zorder</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">5</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">for</span><span class="token plain"> pf</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> ph </span><span class="token keyword" style="color:#00009f">in</span><span class="token plain"> </span><span class="token builtin">zip</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">peak_freqs</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> peak_heights</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    plt</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">text</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">pf</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> ph</span><span class="token operator" style="color:#393A34">*</span><span class="token number" style="color:#36acaa">1.1</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string-interpolation string" style="color:#e3116c">f"</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">{</span><span class="token string-interpolation interpolation">pf</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">:</span><span class="token string-interpolation interpolation format-spec">.0f</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">}</span><span class="token string-interpolation string" style="color:#e3116c"> Hz"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> fontsize</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">8</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> ha</span><span class="token operator" style="color:#393A34">=</span><span class="token string" style="color:#e3116c">'center'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">plt</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">xlim</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> rate</span><span class="token operator" style="color:#393A34">/</span><span class="token number" style="color:#36acaa">2</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">plt</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">xlabel</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"Frequency (Hz)"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">plt</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">ylabel</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"PSD"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">plt</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">title</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"Welch PSD with detected peaks"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">plt</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">grid</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">alpha</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">0.3</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">plt</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">tight_layout</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">plt</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">savefig</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"/mnt/data/psd_peaks.png"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># Plot spectrogram (dB)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Sxx_db </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">20</span><span class="token operator" style="color:#393A34">*</span><span class="token plain">np</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">log10</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">Sxx </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1e-12</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">plt</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">figure</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">figsize</span><span class="token operator" style="color:#393A34">=</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">10</span><span class="token punctuation" style="color:#393A34">,</span><span class="token number" style="color:#36acaa">5</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">plt</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">pcolormesh</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">t_s</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> f_s</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> Sxx_db</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> shading</span><span class="token operator" style="color:#393A34">=</span><span class="token string" style="color:#e3116c">'gouraud'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">plt</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">colorbar</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">label</span><span class="token operator" style="color:#393A34">=</span><span class="token string" style="color:#e3116c">'dB'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">plt</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">ylim</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">4000</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">plt</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">xlabel</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"Time (s)"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">plt</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">ylabel</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"Frequency (Hz)"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">plt</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">title</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"Spectrogram (dB)"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">plt</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">tight_layout</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">plt</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">savefig</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"/mnt/data/spectrogram_db.png"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># Prepare summary</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">summary </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token string" style="color:#e3116c">"sampling_rate"</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> rate</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token string" style="color:#e3116c">"duration_s"</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> duration</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token string" style="color:#e3116c">"rms"</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">float</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">rms</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token string" style="color:#e3116c">"dbfs_rms"</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">float</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">dbfs_rms</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token string" style="color:#e3116c">"dominant_peaks_hz"</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token builtin">float</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">p</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">for</span><span class="token plain"> p </span><span class="token keyword" style="color:#00009f">in</span><span class="token plain"> peak_freqs</span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">:</span><span class="token number" style="color:#36acaa">8</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token string" style="color:#e3116c">"dominant_peaks_vals"</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token builtin">float</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">p</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">for</span><span class="token plain"> p </span><span class="token keyword" style="color:#00009f">in</span><span class="token plain"> peak_heights</span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">:</span><span class="token number" style="color:#36acaa">8</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token string" style="color:#e3116c">"low_freq_peaks_hz"</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token builtin">float</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">p</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">for</span><span class="token plain"> p </span><span class="token keyword" style="color:#00009f">in</span><span class="token plain"> lp_freqs</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token string" style="color:#e3116c">"low_freq_peaks_vals"</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token builtin">float</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">p</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">for</span><span class="token plain"> p </span><span class="token keyword" style="color:#00009f">in</span><span class="token plain"> lp_heights</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token string" style="color:#e3116c">"spike_times_s"</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token builtin">float</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">s</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">for</span><span class="token plain"> s </span><span class="token keyword" style="color:#00009f">in</span><span class="token plain"> spike_times</span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">:</span><span class="token number" style="color:#36acaa">10</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token string" style="color:#e3116c">"spectrogram_image"</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"/mnt/data/spectrogram_db.png"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token string" style="color:#e3116c">"psd_image"</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"/mnt/data/psd_peaks.png"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> json</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">with</span><span class="token plain"> </span><span class="token builtin">open</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"/mnt/data/noise_analysis_summary.json"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token string" style="color:#e3116c">"w"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">as</span><span class="token plain"> f</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    json</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">dump</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">summary</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> f</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> indent</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">2</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># Display small tables and figures</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">from</span><span class="token plain"> caas_jupyter_tools </span><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> display_dataframe_to_user</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> pandas </span><span class="token keyword" style="color:#00009f">as</span><span class="token plain"> pd</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">df_peaks </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> pd</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">DataFrame</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token string" style="color:#e3116c">"freq_hz"</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> peak_freqs</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token string" style="color:#e3116c">"psd_val"</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> peak_heights</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">display_dataframe_to_user</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"Detected PSD Peaks"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> df_peaks</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">head</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">20</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">plt</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">figure</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">figsize</span><span class="token operator" style="color:#393A34">=</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">10</span><span class="token punctuation" style="color:#393A34">,</span><span class="token number" style="color:#36acaa">3</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">plt</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">plot</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">frame_times</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">10</span><span class="token operator" style="color:#393A34">*</span><span class="token plain">np</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">log10</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">frames</span><span class="token operator" style="color:#393A34">+</span><span class="token number" style="color:#36acaa">1e-12</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">plt</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">xlabel</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"Time (s)"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">plt</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">ylabel</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"Frame energy (dB)"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">plt</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">title</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"Short-time frame energy (20ms frames)"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">plt</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">grid</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">alpha</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">0.3</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">plt</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">tight_layout</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">plt</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">savefig</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"/mnt/data/frame_energy.png"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">plt</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">show</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># Show audio player</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">ipd</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">display</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">ipd</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Audio</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"/mnt/data/noise.wav"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">summary</span><br></div></code></pre></div></div>
<p><strong>Key quantitative results obtained:</strong></p>
<ul>
<li class="">Sample rate: <strong>8000 Hz</strong></li>
<li class="">Duration: <strong>10.0 s</strong></li>
<li class="">Overall RMS = <strong>223.11 (samples)</strong>, converted to <strong>-43.34 dBFS</strong> (normalized to 16-bit full scale 32768): <strong>indicates the noise floor is moderately high</strong>.</li>
<li class="">Detected <strong>significant frequency peaks</strong> (Welch PSD peak, in order of intensity, listing the first few):<!-- -->
<ul>
<li class="">approximately <strong>74.2 Hz</strong>, <strong>85.94 Hz</strong>, <strong>103.52 Hz</strong>, <strong>113.28 Hz</strong>, <strong>146.48 Hz</strong>, <strong>167.97 Hz</strong>, and smaller 396 Hz, etc.</li>
</ul>
</li>
<li class="">Main peaks in the low-frequency band (≤500 Hz): <strong>85.94, 95.70, 103.52, 113.28, 146.48 Hz</strong> - multiple near-frequency peaks, like a collection of power frequency/switching power supply harmonics or mechanical resonances.</li>
<li class="">Transient energy peaks (short-time energy frames, 20 ms) detected at: <strong>approximately 0.36-0.38 s</strong> there are several short pulses (may be startup click/human touch/transient events).</li>
</ul>
<p>Conclusion: <strong>The noise consists of obvious low-frequency "hum/ripple/vibration" + broadband white noise</strong> (mid-to-high frequency), with low frequency being the main energy location.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="noise-reduction-scheme">Noise Reduction Scheme<a href="https://zephyr.100ask.org/en/blog/audio-record-noise-analysis#noise-reduction-scheme" class="hash-link" aria-label="Direct link to Noise Reduction Scheme" title="Direct link to Noise Reduction Scheme" translate="no">​</a></h3>
<p><strong>1. Add a 2nd-order high-pass filter (fc = 80 Hz) to the audio chain</strong></p>
<ul>
<li class="">Directly remove most of the mechanical/power low-frequency without damaging the voice bandwidth (voice is mainly &gt;100Hz).</li>
<li class="">Implementation: use the butter/sos in the DSP library or implement biquad yourself (Direct Form I or II).</li>
</ul>
<p><strong>2 Targeted notch filter</strong></p>
<ul>
<li class="">If there are still a few extremely narrow strong peaks after HPF (such as 103Hz), add one or two notches with Q=20~40. The higher the Q, the narrower the bandwidth, and the less it damages adjacent frequency bands, but the coefficients are closer to 1.</li>
<li class="">Consider real-time requirements: need to cascade <code>hp -&gt; notch(strong peak 1) -&gt; notch(strong peak 2)</code>.</li>
</ul>
<p><strong>3 The essence is still hardware</strong></p>
<ul>
<li class="">Replace or improve the analog power supply (low-noise LDO, more bypass capacitors, star ground) or use a digital MEMS microphone with better SNR.</li>
<li class="">On embedded boards, keep switching power supply traces as far away from microphone differential/analog lines as possible.</li>
</ul>
<p><strong>Considerations for real-time audio quality</strong></p>
<ul>
<li class="">If very low latency is required (e.g., echo cancellation / real-time loopback), use IIR (biquad) one-way real-time implementation (extremely low latency), but note that the phase will change. If phase change is not allowed (e.g., for more accurate positioning), using FIR + zero-phase will have a latency cost.</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="reference-filter-coefficients">Reference Filter Coefficients<a href="https://zephyr.100ask.org/en/blog/audio-record-noise-analysis#reference-filter-coefficients" class="hash-link" aria-label="Direct link to Reference Filter Coefficients" title="Direct link to Reference Filter Coefficients" translate="no">​</a></h3>
<blockquote>
<p>Note: The coefficients given below are in the standard second-order section (biquad) format, arranged as <code>[b0, b1, b2, a0, a1, a2]</code> (a0 has been normalized to 1 or needs to be normalized when given). When implementing, usually normalize a0 to 1, and then implement according to Direct Form I/II.</p>
</blockquote>
<p><strong>High-pass: 2nd-order Butterworth (fc = 80 Hz, fs = 8000 Hz)</strong></p>
<p><code>sos_hp</code> first section coefficients (a0 normalized to 1):</p>
<div class="language-ini codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-ini codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">b0 = 0.9565432255568767</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">b1 = -1.9130864511137533</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">b2 = 0.9565432255568767</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">a0 = 1.0</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">a1 = -1.911197067426073</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">a2 = 0.9149758348014336</span><br></div></code></pre></div></div>
<p><strong>Several notch filters (notch, Q=30)</strong></p>
<blockquote>
<p>(Three examples, taken from detected peak positions) Format is the same as above (b0,b1,b2,a0,a1,a2), a0 has been normalized to 1 in the output below:</p>
</blockquote>
<ul>
<li class="">notch @ <strong>103.515625 Hz</strong></li>
</ul>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">b0 = 0.998648305437691</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">b1 = -1.99069933085876</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">b2 = 0.998648305437691</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">a0 = 1.0</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">a1 = -1.99069933085876</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">a2 = 0.9972966108753819</span><br></div></code></pre></div></div>
<ul>
<li class="">notch @ <strong>146.484375 Hz</strong></li>
</ul>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">b0 = 0.9980904047539934</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">b1 = -1.9829844796660758</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">b2 = 0.9980904047539934</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">a0 = 1.0</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">a1 = -1.9829844796660758</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">a2 = 0.9961808095079867</span><br></div></code></pre></div></div>
<ul>
<li class="">notch @ <strong>74.21875 Hz</strong></li>
</ul>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">b0 = 0.9990299707952924</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">b1 = -1.9946663265604048</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">b2 = 0.9990299707952924</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">a0 = 1.0</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">a1 = -1.9946663265604048</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">a2 = 0.9980599415905849</span><br></div></code></pre></div></div>
<p>This noise analysis is the necessary material for traditional <strong>spectral subtraction</strong> audio filtering. Using the standard rnnoise AI noise reduction does not require it, but if you improve rnnoise yourself and do model fine-tuning, you need to refer to it to achieve better noise reduction results.</p>]]></content:encoded>
            <category>Audio</category>
            <category>Recording</category>
            <category>Noise Analysis</category>
            <category>RK3576</category>
        </item>
        <item>
            <title><![CDATA[DshanPI-A1 Review Part 5: NPU in Action - YOLOv5 Real-Time Object Detection Acceleration]]></title>
            <link>https://zephyr.100ask.org/en/blog/npu-yolov5-detection</link>
            <guid>https://zephyr.100ask.org/en/blog/npu-yolov5-detection</guid>
            <pubDate>Fri, 28 Nov 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[Use the onboard NPU to accelerate YOLOv5 deep-learning inference, squeezing the full hardware potential of RK3576 for real-time object detection.]]></description>
            <content:encoded><![CDATA[<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="preface">Preface<a href="https://zephyr.100ask.org/en/blog/npu-yolov5-detection#preface" class="hash-link" aria-label="Direct link to Preface" title="Direct link to Preface" translate="no">​</a></h2>
<p>In previous articles we implemented CPU-based MediaPipe gesture recognition. Although it runs, the 15-25 FPS performance is still a bit strained, and CPU usage is high. This time I will squeeze the full hardware potential of the RK3576 - using the onboard NPU (Neural Processing Unit) to accelerate deep-learning inference. First, let's cover a few concepts.</p>
<p><strong>What is an NPU?</strong>
An NPU (Neural Processing Unit) is a hardware accelerator designed specifically for AI operations. Unlike a CPU/GPU, an NPU is deeply optimized for the matrix operations, convolutions, and other operations used in neural networks. The RK3576 chip has a built-in dual-core NPU with a theoretical compute capacity of 6 TOPS, which can dramatically boost model inference speed and lower power consumption.</p>
<p><strong>Why YOLOv5?</strong>
Actually, I originally intended to keep optimizing my previous MediaPipe TFLite model conversion, but I ran into dependency hell (a pit I stumbled into for a long time...), so this time I first used the officially provided YOLOv5 model to validate the NPU functionality. YOLOv5 is one of the most popular real-time object detection algorithms today and can simultaneously detect multiple objects and their positions in an image.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="1-environment-preparation">1. Environment Preparation<a href="https://zephyr.100ask.org/en/blog/npu-yolov5-detection#1-environment-preparation" class="hash-link" aria-label="Direct link to 1. Environment Preparation" title="Direct link to 1. Environment Preparation" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="11-hardware-connections">1.1 Hardware Connections<a href="https://zephyr.100ask.org/en/blog/npu-yolov5-detection#11-hardware-connections" class="hash-link" aria-label="Direct link to 1.1 Hardware Connections" title="Direct link to 1.1 Hardware Connections" translate="no">​</a></h3>
<ul>
<li class="">RK3576 development board (already flashed with Buildroot)</li>
<li class="">IMX415 camera (connected at /dev/video11)</li>
<li class="">HDMI monitor</li>
<li class="">Serial connection (for command-line operation)</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="12-check-the-npu-hardware">1.2 Check the NPU Hardware<a href="https://zephyr.100ask.org/en/blog/npu-yolov5-detection#12-check-the-npu-hardware" class="hash-link" aria-label="Direct link to 1.2 Check the NPU Hardware" title="Direct link to 1.2 Check the NPU Hardware" translate="no">​</a></h3>
<p>First, log in to the board and check whether the NPU is working normally:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain"># View the NPU load (should show Core0 and Core1)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">cat /sys/kernel/debug/rknpu/load</span><br></div></code></pre></div></div>
<p>This shows that both NPU cores are idle and ready to go!</p>
<p><strong>Tip:</strong> The RK3576's NPU uses a dual-core architecture and can process two models in parallel, or pipeline the different layers of one large model across the two cores.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="13-check-the-python-environment">1.3 Check the Python Environment<a href="https://zephyr.100ask.org/en/blog/npu-yolov5-detection#13-check-the-python-environment" class="hash-link" aria-label="Direct link to 1.3 Check the Python Environment" title="Direct link to 1.3 Check the Python Environment" translate="no">​</a></h3>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain"># View the Python version</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">python3 --version</span><br></div></code></pre></div></div>
<p>My output is <code>Python 3.11.8</code>; this version matters, as it must match when installing libraries later.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="2-install-the-rknn-runtime-environment">2. Install the RKNN Runtime Environment<a href="https://zephyr.100ask.org/en/blog/npu-yolov5-detection#2-install-the-rknn-runtime-environment" class="hash-link" aria-label="Direct link to 2. Install the RKNN Runtime Environment" title="Direct link to 2. Install the RKNN Runtime Environment" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="21-what-is-rknn">2.1 What is RKNN?<a href="https://zephyr.100ask.org/en/blog/npu-yolov5-detection#21-what-is-rknn" class="hash-link" aria-label="Direct link to 2.1 What is RKNN?" title="Direct link to 2.1 What is RKNN?" translate="no">​</a></h3>
<p>RKNN (Rockchip Neural Network) is the deep-learning inference framework Rockchip developed for its own NPU. The whole toolchain is split into two parts:</p>
<ul>
<li class=""><strong>rknn-toolkit2</strong> (PC side): used for model conversion, turning TensorFlow/PyTorch/ONNX models into .rknn format</li>
<li class=""><strong>rknn-toolkit-lite2</strong> (board side): a lightweight runtime library used to load and infer .rknn models on RK chips</li>
</ul>
<p>This time we only need on-board inference, so we only install the lite version.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="22-get-the-installation-package">2.2 Get the Installation Package<a href="https://zephyr.100ask.org/en/blog/npu-yolov5-detection#22-get-the-installation-package" class="hash-link" aria-label="Direct link to 2.2 Get the Installation Package" title="Direct link to 2.2 Get the Installation Package" translate="no">​</a></h3>
<p>The good news is that if you don't want to download from GitHub because it's slow or unstable, you can use the download link provided by our 100ask:
<a href="https://dl.100ask.net/Hardware/MPU/RK3576-DshanPi-A1/utils/rknn-toolkit2.zip" target="_blank" rel="noopener noreferrer" class="">https://dl.100ask.net/Hardware/MPU/RK3576-DshanPi-A1/utils/rknn-toolkit2.zip</a>
Download it and transfer it to our DshanPi-A1.</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">cd /rknn-toolkit2/rknn-toolkit-lite2/packages/</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">ls -lh</span><br></div></code></pre></div></div>
<p>You can see there are .whl installation packages for multiple Python versions; the one we need is the cp311 (Python 3.11) ARM64 version.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="23-install-rknn-toolkit-lite2">2.3 Install rknn-toolkit-lite2<a href="https://zephyr.100ask.org/en/blog/npu-yolov5-detection#23-install-rknn-toolkit-lite2" class="hash-link" aria-label="Direct link to 2.3 Install rknn-toolkit-lite2" title="Direct link to 2.3 Install rknn-toolkit-lite2" translate="no">​</a></h3>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain"># First force-install the main package (skip dependency checks, because dependencies are installed separately later)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">pip3 install --no-deps rknn_toolkit_lite2-2.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># Then use the Tsinghua mirror to install the missing dependencies</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">pip3 install -i https://pypi.tuna.tsinghua.edu.cn/simple psutil ruamel.yaml</span><br></div></code></pre></div></div>
<p>This way we don't waste time downloading unnecessary packages.</p>
<p>When you see <code>Successfully installed</code>, it's done!</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="24-verify-the-installation">2.4 Verify the Installation<a href="https://zephyr.100ask.org/en/blog/npu-yolov5-detection#24-verify-the-installation" class="hash-link" aria-label="Direct link to 2.4 Verify the Installation" title="Direct link to 2.4 Verify the Installation" translate="no">​</a></h3>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">python3 -c "from rknnlite.api import RKNNLite; print('✅ rknn-toolkit-lite2 installed successfully!')"</span><br></div></code></pre></div></div>
<p>If the check mark appears, you're good!</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="3-npu-benchmarking">3. NPU Benchmarking<a href="https://zephyr.100ask.org/en/blog/npu-yolov5-detection#3-npu-benchmarking" class="hash-link" aria-label="Direct link to 3. NPU Benchmarking" title="Direct link to 3. NPU Benchmarking" translate="no">​</a></h2>
<p>Before running real-time detection, first use a simple image-classification model to test the NPU's performance.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="31-test-with-resnet18">3.1 Test with ResNet18<a href="https://zephyr.100ask.org/en/blog/npu-yolov5-detection#31-test-with-resnet18" class="hash-link" aria-label="Direct link to 3.1 Test with ResNet18" title="Direct link to 3.1 Test with ResNet18" translate="no">​</a></h3>
<p>Enter the example directory:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">cd /rknn-toolkit2/rknn-toolkit-lite2/examples/resnet18</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">ls -lh</span><br></div></code></pre></div></div>
<p>You can see:</p>
<ul>
<li class=""><code>resnet18_for_rk3576.rknn</code> - a model specifically optimized for RK3576</li>
<li class=""><code>space_shuttle_224.jpg</code> - test image</li>
<li class=""><code>test.py</code> - inference script</li>
</ul>
<p>Run the test:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">python3 test.py</span><br></div></code></pre></div></div>
<p>My results:</p>
<ul>
<li class="">Recognition result: Space Shuttle - 99.96% confidence</li>
<li class="">Inference latency: 11.21 ms</li>
<li class="">Average FPS: 89.24</li>
</ul>
<p>This means the NPU can process 89 images per second - 3-6x faster than my previous CPU-based MediaPipe!</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="32-performance-benchmark">3.2 Performance Benchmark<a href="https://zephyr.100ask.org/en/blog/npu-yolov5-detection#32-performance-benchmark" class="hash-link" aria-label="Direct link to 3.2 Performance Benchmark" title="Direct link to 3.2 Performance Benchmark" translate="no">​</a></h3>
<p>To test the NPU performance more accurately, I wrote a script that loops 100 times (you can test it yourself):</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">cd ~</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">mkdir -p npu_test</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">cd npu_test</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># Copy the model and image</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">cp /rknn-toolkit2/rknn-toolkit-lite2/examples/resnet18/resnet18_for_rk3576.rknn ./</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">cp /rknn-toolkit2/rknn-toolkit-lite2/examples/resnet18/space_shuttle_224.jpg ./</span><br></div></code></pre></div></div>
<p>Create the test script <code>benchmark.py</code>:</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> cv2</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> numpy </span><span class="token keyword" style="color:#00009f">as</span><span class="token plain"> np</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> time</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">from</span><span class="token plain"> rknnlite</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">api </span><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> RKNNLite</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">rknn </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> RKNNLite</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">rknn</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">load_rknn</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'resnet18_for_rk3576.rknn'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">rknn</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">init_runtime</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">core_mask</span><span class="token operator" style="color:#393A34">=</span><span class="token plain">RKNNLite</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">NPU_CORE_0</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">img </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> cv2</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">imread</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'space_shuttle_224.jpg'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">img </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> cv2</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">cvtColor</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">img</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> cv2</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">COLOR_BGR2RGB</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">img </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> np</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">expand_dims</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">img</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># Warm up</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">for</span><span class="token plain"> _ </span><span class="token keyword" style="color:#00009f">in</span><span class="token plain"> </span><span class="token builtin">range</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">10</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    rknn</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">inference</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">inputs</span><span class="token operator" style="color:#393A34">=</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">img</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># Test 100 times</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">times </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">for</span><span class="token plain"> i </span><span class="token keyword" style="color:#00009f">in</span><span class="token plain"> </span><span class="token builtin">range</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">100</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    start </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> time</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">time</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    rknn</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">inference</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">inputs</span><span class="token operator" style="color:#393A34">=</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">img</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    times</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">append</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">time</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">time</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token plain"> start</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1000</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">print</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string-interpolation string" style="color:#e3116c">f'Average latency: </span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">{</span><span class="token string-interpolation interpolation">np</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">.</span><span class="token string-interpolation interpolation">mean</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">(</span><span class="token string-interpolation interpolation">times</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">)</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">:</span><span class="token string-interpolation interpolation format-spec">.2f</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">}</span><span class="token string-interpolation string" style="color:#e3116c"> ms'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">print</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string-interpolation string" style="color:#e3116c">f'Min latency: </span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">{</span><span class="token string-interpolation interpolation">np</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">.</span><span class="token string-interpolation interpolation builtin">min</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">(</span><span class="token string-interpolation interpolation">times</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">)</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">:</span><span class="token string-interpolation interpolation format-spec">.2f</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">}</span><span class="token string-interpolation string" style="color:#e3116c"> ms'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">print</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string-interpolation string" style="color:#e3116c">f'Max latency: </span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">{</span><span class="token string-interpolation interpolation">np</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">.</span><span class="token string-interpolation interpolation builtin">max</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">(</span><span class="token string-interpolation interpolation">times</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">)</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">:</span><span class="token string-interpolation interpolation format-spec">.2f</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">}</span><span class="token string-interpolation string" style="color:#e3116c"> ms'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">print</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string-interpolation string" style="color:#e3116c">f'Average FPS: </span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">{</span><span class="token string-interpolation interpolation number" style="color:#36acaa">1000</span><span class="token string-interpolation interpolation operator" style="color:#393A34">/</span><span class="token string-interpolation interpolation">np</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">.</span><span class="token string-interpolation interpolation">mean</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">(</span><span class="token string-interpolation interpolation">times</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">)</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">:</span><span class="token string-interpolation interpolation format-spec">.2f</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">}</span><span class="token string-interpolation string" style="color:#e3116c">'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">rknn</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">release</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><br></div></code></pre></div></div>
<p>Run it:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">python3 benchmark.py</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="4-yolov5-object-detection">4. YOLOv5 Object Detection<a href="https://zephyr.100ask.org/en/blog/npu-yolov5-detection#4-yolov5-object-detection" class="hash-link" aria-label="Direct link to 4. YOLOv5 Object Detection" title="Direct link to 4. YOLOv5 Object Detection" translate="no">​</a></h2>
<p>Now for the main event - using the NPU for real-time object detection!</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="41-what-is-yolov5">4.1 What is YOLOv5?<a href="https://zephyr.100ask.org/en/blog/npu-yolov5-detection#41-what-is-yolov5" class="hash-link" aria-label="Direct link to 4.1 What is YOLOv5?" title="Direct link to 4.1 What is YOLOv5?" translate="no">​</a></h3>
<p>YOLO (You Only Look Once) is a single-stage object detection algorithm that can simultaneously predict the positions and categories of multiple objects in a single forward pass. Compared with the two-stage R-CNN family, YOLO is faster and well suited for real-time scenarios.</p>
<p>YOLOv5 is the fifth generation of this family and supports detecting 80 common object categories (people, cars, animals, furniture, etc.).</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="42-prepare-the-model-and-test-image">4.2 Prepare the Model and Test Image<a href="https://zephyr.100ask.org/en/blog/npu-yolov5-detection#42-prepare-the-model-and-test-image" class="hash-link" aria-label="Direct link to 4.2 Prepare the Model and Test Image" title="Direct link to 4.2 Prepare the Model and Test Image" translate="no">​</a></h3>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">cd ~</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">mkdir -p npu_yolo_test</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">cd npu_yolo_test</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># Copy the YOLOv5 model specialized for RK3576</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">cp /rknn-toolkit2/rknpu2/examples/rknn_yolov5_demo/model/RK3576/yolov5s-640-640.rknn ./</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># Copy the test image (a bus photo)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">cp /rknn-toolkit2/rknpu2/examples/rknn_yolov5_demo/model/bus.jpg ./</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">ls -lh</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="43-single-image-detection-test">4.3 Single-Image Detection Test<a href="https://zephyr.100ask.org/en/blog/npu-yolov5-detection#43-single-image-detection-test" class="hash-link" aria-label="Direct link to 4.3 Single-Image Detection Test" title="Direct link to 4.3 Single-Image Detection Test" translate="no">​</a></h3>
<p>The complete post-processing code here is fairly long (including the NMS non-maximum suppression algorithm and so on), so I consolidated it into one script.</p>
<p>Create <code>yolo_npu_test.py</code> (see Appendix A for the full code), then run it:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">python3 yolo_npu_test.py</span><br></div></code></pre></div></div>
<p>My results:</p>
<ul>
<li class="">Detected 5 objects:<!-- -->
<ul>
<li class="">3 persons: 88.0%, 87.1%, 82.8%</li>
<li class="">1 bus: 70.1%</li>
<li class="">1 partially occluded person: 30.7%</li>
</ul>
</li>
<li class="">NPU inference latency: 87.94 ms</li>
<li class="">FPS: 11.37</li>
</ul>
<p>The detection result is saved in <code>result_npu.jpg</code>, which you can transfer to your PC to view:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain"># Run in PowerShell on the PC (replace &lt;board IP&gt; with the actual IP)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">scp root@&lt;board IP&gt;:/npu_yolo_test/result_npu.jpg .</span><br></div></code></pre></div></div>
<p><strong>[Detection Result Image]</strong></p>
<p><strong>Why is YOLOv5 slower than ResNet18?</strong></p>
<ul>
<li class="">ResNet18 only does classification, outputting the probabilities of 1000 categories (simple)</li>
<li class="">YOLOv5 detects the positions + categories of multiple objects, outputting feature maps at 3 different scales (complex)</li>
<li class="">But 11 FPS is already pretty good for object detection!</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="5-real-time-camera-detection">5. Real-Time Camera Detection<a href="https://zephyr.100ask.org/en/blog/npu-yolov5-detection#5-real-time-camera-detection" class="hash-link" aria-label="Direct link to 5. Real-Time Camera Detection" title="Direct link to 5. Real-Time Camera Detection" translate="no">​</a></h2>
<p>Single-image testing succeeded - now for a real challenge: using the IMX415 camera for real-time detection and displaying the result on the screen!</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="51-display-solution-fifo--gstreamer">5.1 Display Solution: FIFO + GStreamer<a href="https://zephyr.100ask.org/en/blog/npu-yolov5-detection#51-display-solution-fifo--gstreamer" class="hash-link" aria-label="Direct link to 5.1 Display Solution: FIFO + GStreamer" title="Direct link to 5.1 Display Solution: FIFO + GStreamer" translate="no">​</a></h3>
<p>As before, since Buildroot has no graphical interface and OpenCV's <code>imshow()</code> cannot be used, we adopt the <strong>named pipe (FIFO) + GStreamer</strong> solution:</p>
<ol>
<li class="">Python reads the camera -&gt; NPU inference -&gt; draws boxes -&gt; encodes to JPEG</li>
<li class="">Writes into the FIFO pipe</li>
<li class="">GStreamer reads from the pipe -&gt; decodes -&gt; displays on the screen</li>
</ol>
<p>This is a common inter-process communication method on Linux and was also used in the previous gesture recognition project.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="52-create-a-one-click-launch-script">5.2 Create a One-Click Launch Script<a href="https://zephyr.100ask.org/en/blog/npu-yolov5-detection#52-create-a-one-click-launch-script" class="hash-link" aria-label="Direct link to 5.2 Create a One-Click Launch Script" title="Direct link to 5.2 Create a One-Click Launch Script" translate="no">​</a></h3>
<p>For convenience, I packed the whole flow into a Shell script <code>yolo_npu_display.sh</code>:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">cd /npu_yolo_test</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">cat &gt; yolo_npu_display.sh &lt;&lt; 'EOF'</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">#!/bin/bash</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">echo "=========================================="</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">echo "YOLOv5 NPU Real-time Detection - RK3576"</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">echo "=========================================="</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">echo ""</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># Restart the 3A server (camera auto-exposure/white-balance/auto-focus)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">echo "Restarting 3A server..."</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">killall rkaiq_3A_server 2&gt;/dev/null</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sleep 2</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">rm -f /tmp/.rkaiq_3A* 2&gt;/dev/null</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">/etc/init.d/S40rkaiq_3A start &gt;/dev/null 2&gt;&amp;1</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sleep 3</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># Create the FIFO pipe</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">FIFO_PATH="/tmp/yolo_fifo"</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">rm -f $FIFO_PATH</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">mkfifo $FIFO_PATH</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">echo "Starting display pipeline..."</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">gst-launch-1.0 -q filesrc location=$FIFO_PATH ! jpegparse ! jpegdec ! videoconvert ! videoscale ! video/x-raw,width=1280,height=720 ! waylandsink fullscreen=true sync=false &amp;</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">GST_PID=$!</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sleep 2</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">echo "Starting YOLOv5 NPU detection..."</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">python3 - &lt;&lt;'PYTHON_CODE' &amp;</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">import cv2</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">import numpy as np</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">import time</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">from rknnlite.api import RKNNLite</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">from collections import deque</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">RKNN_MODEL = '/npu_yolo_test/yolov5s-640-640.rknn'</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">CAMERA_ID = 11</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">IMG_SIZE = 640</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">OBJ_THRESH = 0.25</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">NMS_THRESH = 0.45</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">FIFO_PATH = '/tmp/yolo_fifo'</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">CLASSES = ("person", "bicycle", "car", "motorbike", "aeroplane", "bus", "train", "truck", "boat", "traffic light",</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">           "fire hydrant", "stop sign", "parking meter", "bench", "bird", "cat", "dog", "horse", "sheep", "cow",</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">           "elephant", "bear", "zebra", "giraffe", "backpack", "umbrella", "handbag", "tie", "suitcase", "frisbee",</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">           "skis", "snowboard", "sports ball", "kite", "baseball bat", "baseball glove", "skateboard", "surfboard",</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">           "tennis racket", "bottle", "wine glass", "cup", "fork", "knife", "spoon", "bowl", "banana", "apple",</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">           "sandwich", "orange", "broccoli", "carrot", "hot dog", "pizza", "donut", "cake", "chair", "sofa",</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">           "pottedplant", "bed", "diningtable", "toilet", "tvmonitor", "laptop", "mouse", "remote", "keyboard",</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">           "cell phone", "microwave", "oven", "toaster", "sink", "refrigerator", "book", "clock", "vase",</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">           "scissors", "teddy bear", "hair drier", "toothbrush")</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">def xywh2xyxy(x):</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    y = np.copy(x)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    y[:, 0] = x[:, 0] - x[:, 2] / 2</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    y[:, 1] = x[:, 1] - x[:, 3] / 2</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    y[:, 2] = x[:, 0] + x[:, 2] / 2</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    y[:, 3] = x[:, 1] + x[:, 3] / 2</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    return y</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">def process(input, mask, anchors):</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    anchors = [anchors[i] for i in mask]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    grid_h, grid_w = map(int, input.shape[0:2])</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    box_confidence = np.expand_dims(input[..., 4], axis=-1)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    box_class_probs = input[..., 5:]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    box_xy = input[..., :2]*2 - 0.5</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    col = np.tile(np.arange(0, grid_w), grid_w).reshape(-1, grid_w)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    row = np.tile(np.arange(0, grid_h).reshape(-1, 1), grid_h)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    col = col.reshape(grid_h, grid_w, 1, 1).repeat(3, axis=-2)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    row = row.reshape(grid_h, grid_w, 1, 1).repeat(3, axis=-2)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    grid = np.concatenate((col, row), axis=-1)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    box_xy += grid</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    box_xy *= int(IMG_SIZE/grid_h)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    box_wh = pow(input[..., 2:4]*2, 2)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    box_wh = box_wh * anchors</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    box = np.concatenate((box_xy, box_wh), axis=-1)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    return box, box_confidence, box_class_probs</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">def filter_boxes(boxes, box_confidences, box_class_probs):</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    boxes = boxes.reshape(-1, 4)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    box_confidences = box_confidences.reshape(-1)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    box_class_probs = box_class_probs.reshape(-1, box_class_probs.shape[-1])</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    _box_pos = np.where(box_confidences &gt;= OBJ_THRESH)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    boxes = boxes[_box_pos]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    box_confidences = box_confidences[_box_pos]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    box_class_probs = box_class_probs[_box_pos]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    class_max_score = np.max(box_class_probs, axis=-1)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    classes = np.argmax(box_class_probs, axis=-1)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    _class_pos = np.where(class_max_score &gt;= OBJ_THRESH)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    boxes = boxes[_class_pos]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    classes = classes[_class_pos]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    scores = (class_max_score * box_confidences)[_class_pos]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    return boxes, classes, scores</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">def nms_boxes(boxes, scores):</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    x, y = boxes[:, 0], boxes[:, 1]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    w, h = boxes[:, 2] - boxes[:, 0], boxes[:, 3] - boxes[:, 1]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    areas = w * h</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    order = scores.argsort()[::-1]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    keep = []</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    while order.size &gt; 0:</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        i = order[0]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        keep.append(i)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        xx1 = np.maximum(x[i], x[order[1:]])</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        yy1 = np.maximum(y[i], y[order[1:]])</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        xx2 = np.minimum(x[i] + w[i], x[order[1:]] + w[order[1:]])</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        yy2 = np.minimum(y[i] + h[i], y[order[1:]] + h[order[1:]])</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        w1 = np.maximum(0.0, xx2 - xx1 + 0.00001)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        h1 = np.maximum(0.0, yy2 - yy1 + 0.00001)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        inter = w1 * h1</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        ovr = inter / (areas[i] + areas[order[1:]] - inter)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        inds = np.where(ovr &lt;= NMS_THRESH)[0]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        order = order[inds + 1]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    return np.array(keep)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">def yolov5_post_process(input_data):</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    masks = [[0, 1, 2], [3, 4, 5], [6, 7, 8]]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    anchors = [[10, 13], [16, 30], [33, 23], [30, 61], [62, 45],</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">               [59, 119], [116, 90], [156, 198], [373, 326]]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    boxes, classes, scores = [], [], []</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    for input, mask in zip(input_data, masks):</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        b, c, s = process(input, mask, anchors)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        b, c, s = filter_boxes(b, c, s)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        boxes.append(b)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        classes.append(c)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        scores.append(s)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    if len(boxes) == 0:</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        return None, None, None</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    boxes = np.concatenate(boxes)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    boxes = xywh2xyxy(boxes)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    classes = np.concatenate(classes)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    scores = np.concatenate(scores)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    nboxes, nclasses, nscores = [], [], []</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    for c in set(classes):</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        inds = np.where(classes == c)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        b, c, s = boxes[inds], classes[inds], scores[inds]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        keep = nms_boxes(b, s)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        nboxes.append(b[keep])</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        nclasses.append(c[keep])</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        nscores.append(s[keep])</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    if not nclasses:</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        return None, None, None</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    return np.concatenate(nboxes), np.concatenate(nclasses), np.concatenate(nscores)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">class YOLODetector:</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    def __init__(self):</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        self.fps_queue = deque(maxlen=30)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        self.last_time = time.time()</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        self.fps = 0.0</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    def calc_fps(self):</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        t = time.time()</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        if t - self.last_time &gt; 0:</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            self.fps_queue.append(1.0 / (t - self.last_time))</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            self.fps = sum(self.fps_queue) / len(self.fps_queue)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        self.last_time = t</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    def draw_detections(self, frame, boxes, scores, classes, scale_x, scale_y):</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        for box, score, cl in zip(boxes, scores, classes):</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            x1 = int(box[0] * scale_x)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            y1 = int(box[1] * scale_y)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            x2 = int(box[2] * scale_x)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            y2 = int(box[3] * scale_y)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            cv2.rectangle(frame, (x1, y1), (x2, y2), (0, 255, 0), 2)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            label = f'{CLASSES[cl]} {score:.2f}'</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            cv2.putText(frame, label, (x1, y1 - 10),</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                       cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    def run(self):</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        print("Initializing NPU...")</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        rknn_lite = RKNNLite()</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        rknn_lite.load_rknn(RKNN_MODEL)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        rknn_lite.init_runtime(core_mask=RKNNLite.NPU_CORE_0)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        print("NPU ready!")</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        print(f"Opening camera /dev/video{CAMERA_ID}...")</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        cap = cv2.VideoCapture(CAMERA_ID, cv2.CAP_V4L2)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        cap.set(cv2.CAP_PROP_FPS, 30)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        print(f"Camera: {width}x{height}")</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        print("Detection running...\n")</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        fifo = open(FIFO_PATH, 'wb')</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        frame_count = 0</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        scale_x = width / IMG_SIZE</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        scale_y = height / IMG_SIZE</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        try:</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            while True:</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                ret, frame = cap.read()</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                if not ret:</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                    time.sleep(0.1)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                    continue</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                img_resized = cv2.resize(frame_rgb, (IMG_SIZE, IMG_SIZE))</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                img_input = np.expand_dims(img_resized, 0)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                inf_start = time.time()</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                outputs = rknn_lite.inference(inputs=[img_input])</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                inf_time = (time.time() - inf_start) * 1000</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                input0 = outputs[0].reshape([3, -1] + list(outputs[0].shape[-2:]))</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                input1 = outputs[1].reshape([3, -1] + list(outputs[1].shape[-2:]))</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                input2 = outputs[2].reshape([3, -1] + list(outputs[2].shape[-2:]))</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                input_data = [</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                    np.transpose(input0, (2, 3, 0, 1)),</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                    np.transpose(input1, (2, 3, 0, 1)),</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                    np.transpose(input2, (2, 3, 0, 1))</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                ]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                boxes, classes, scores = yolov5_post_process(input_data)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                if boxes is not None:</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                    self.draw_detections(frame, boxes, scores, classes, scale_x, scale_y)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                    obj_count = len(boxes)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                else:</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                    obj_count = 0</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                self.calc_fps()</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                cv2.rectangle(frame, (5, 5), (400, 120), (0, 100, 0), -1)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                cv2.putText(frame, f'FPS: {self.fps:.1f}', (15, 35),</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                           cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 255, 0), 2)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                cv2.putText(frame, f'NPU: {inf_time:.1f}ms', (15, 70),</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                           cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 0), 2)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                cv2.putText(frame, f'Objects: {obj_count}', (15, 105),</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                           cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 255, 0), 2)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                _, jpeg = cv2.imencode('.jpg', frame, [cv2.IMWRITE_JPEG_QUALITY, 85])</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                fifo.write(jpeg.tobytes())</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                fifo.flush()</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                frame_count += 1</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                if frame_count % 50 == 0:</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                    print(f"Frame {frame_count}: FPS={self.fps:.1f}, NPU={inf_time:.1f}ms, Objects={obj_count}")</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        except KeyboardInterrupt:</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            print("\nStopping...")</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        finally:</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            fifo.close()</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            cap.release()</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            rknn_lite.release()</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            print("Released resources")</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">YOLODetector().run()</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">PYTHON_CODE</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">PYTHON_PID=$!</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">echo ""</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">echo "=========================================="</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">echo "System started!"</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">echo "Screen should show real-time detection"</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">echo "Press Ctrl+C to exit"</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">echo "=========================================="</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">echo ""</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">trap "echo ''; echo 'Stopping...'; kill $PYTHON_PID $GST_PID 2&gt;/dev/null; rm -f $FIFO_PATH; echo 'Cleaned up'; exit" INT</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">wait $PYTHON_PID</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">kill $GST_PID 2&gt;/dev/null</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">rm -f $FIFO_PATH</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">echo "Cleaned"</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">EOF</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">chmod +x yolo_npu_display.sh</span><br></div></code></pre></div></div>
<p><strong>[Screenshot 13: Script creation complete]</strong></p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="53-run-real-time-detection">5.3 Run Real-Time Detection<a href="https://zephyr.100ask.org/en/blog/npu-yolov5-detection#53-run-real-time-detection" class="hash-link" aria-label="Direct link to 5.3 Run Real-Time Detection" title="Direct link to 5.3 Run Real-Time Detection" translate="no">​</a></h3>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">./yolo_npu_display.sh</span><br></div></code></pre></div></div>
<p>You will see:</p>
<ol>
<li class="">The 3A server restart</li>
<li class="">The FIFO pipe being created</li>
<li class="">The GStreamer display pipeline starting</li>
<li class="">YOLOv5 detection starting</li>
</ol>
<p>The terminal will print performance statistics every 50 frames, for example:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">Frame 50: FPS=10.2, NPU=52.3ms, Objects=2</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Frame 100: FPS=10.5, NPU=48.7ms, Objects=1</span><br></div></code></pre></div></div>
<ul>
<li class="">Green detection boxes mark the objects</li>
<li class="">The top-left corner shows the FPS, NPU latency, and number of detections</li>
</ul>
<p>Press <code>Ctrl+C</code> to stop the program.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="6-performance-analysis">6. Performance Analysis<a href="https://zephyr.100ask.org/en/blog/npu-yolov5-detection#6-performance-analysis" class="hash-link" aria-label="Direct link to 6. Performance Analysis" title="Direct link to 6. Performance Analysis" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="61-measured-data">6.1 Measured Data<a href="https://zephyr.100ask.org/en/blog/npu-yolov5-detection#61-measured-data" class="hash-link" aria-label="Direct link to 6.1 Measured Data" title="Direct link to 6.1 Measured Data" translate="no">​</a></h3>
<p>My real-time detection results:</p>
<table><thead><tr><th>Metric</th><th>Value</th></tr></thead><tbody><tr><td>Average FPS</td><td>10.0-10.8</td></tr><tr><td>NPU inference latency</td><td>47-59 ms</td></tr><tr><td>Total latency (incl. capture/draw/display)</td><td>84-101 ms</td></tr><tr><td>Max number of detected objects</td><td>13 objects</td></tr></tbody></table>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="62-comparison-with-the-cpu-solution">6.2 Comparison with the CPU Solution<a href="https://zephyr.100ask.org/en/blog/npu-yolov5-detection#62-comparison-with-the-cpu-solution" class="hash-link" aria-label="Direct link to 6.2 Comparison with the CPU Solution" title="Direct link to 6.2 Comparison with the CPU Solution" translate="no">​</a></h3>
<table><thead><tr><th>Solution</th><th>FPS</th><th>CPU Usage</th><th>Power</th></tr></thead><tbody><tr><td>MediaPipe (CPU)</td><td>15-25</td><td>50-65%</td><td>High</td></tr><tr><td>YOLOv5 (NPU)</td><td>10-11</td><td>15-25%</td><td>Low</td></tr></tbody></table>
<p>Although YOLOv5's FPS is slightly lower than MediaPipe's gesture recognition, note that:</p>
<ul>
<li class="">YOLOv5 does <strong>full-scene object detection</strong> (80 classes), whereas MediaPipe only does hand detection (a much simpler task)</li>
<li class="">YOLOv5 uses the NPU, <strong>reducing CPU usage by more than 60%</strong></li>
<li class="">The NPU's power consumption is far lower than the CPU running at full speed, <strong>so heat is notably reduced</strong></li>
<li class="">If you only use YOLOv5 to detect humans (the person class), you can further optimize the post-processing and the FPS can go even higher</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="63-why-didnt-it-reach-the-theoretical-89-fps">6.3 Why Didn't It Reach the Theoretical 89 FPS?<a href="https://zephyr.100ask.org/en/blog/npu-yolov5-detection#63-why-didnt-it-reach-the-theoretical-89-fps" class="hash-link" aria-label="Direct link to 6.3 Why Didn't It Reach the Theoretical 89 FPS?" title="Direct link to 6.3 Why Didn't It Reach the Theoretical 89 FPS?" translate="no">​</a></h3>
<p>ResNet18 can hit 89 FPS on a single image - why does real-time detection only reach 10 FPS? Where is the bottleneck?</p>
<p>Based on profiling analysis:</p>
<ul>
<li class=""><strong>NPU inference</strong>: ~50ms (main bottleneck)</li>
<li class="">Camera capture: ~5ms</li>
<li class="">Post-processing (NMS, etc.): ~15ms</li>
<li class="">Drawing boxes and text: ~8ms</li>
<li class="">JPEG encoding: ~10ms</li>
<li class="">FIFO transfer + GStreamer: ~5ms</li>
</ul>
<p><strong>Summary:</strong></p>
<ol>
<li class="">The YOLOv5 model is much larger than ResNet18 (7.9MB vs 12MB) and has a larger compute load</li>
<li class="">The NMS algorithm in post-processing is pure Python and relatively slow (could be rewritten in C++ or accelerated with CUDA)</li>
<li class="">JPEG encoding also takes a fair amount of time (could be replaced with H.264 hardware encoding)</li>
</ol>
<p><strong>Optimization directions:</strong></p>
<ul>
<li class="">Use YOLOv5-nano (a smaller model)</li>
<li class="">Accelerate post-processing with Cython</li>
<li class="">Enable NPU dual-core parallelism</li>
<li class="">Use RK3576's hardware video encoder</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="7-pitfalls-encountered-and-solutions">7. Pitfalls Encountered and Solutions<a href="https://zephyr.100ask.org/en/blog/npu-yolov5-detection#7-pitfalls-encountered-and-solutions" class="hash-link" aria-label="Direct link to 7. Pitfalls Encountered and Solutions" title="Direct link to 7. Pitfalls Encountered and Solutions" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="71-pc-side-model-conversion-dependency-hell">7.1 PC-Side Model Conversion Dependency Hell<a href="https://zephyr.100ask.org/en/blog/npu-yolov5-detection#71-pc-side-model-conversion-dependency-hell" class="hash-link" aria-label="Direct link to 7.1 PC-Side Model Conversion Dependency Hell" title="Direct link to 7.1 PC-Side Model Conversion Dependency Hell" translate="no">​</a></h3>
<p><strong>Problem:</strong> I wanted to use rknn-toolkit2 on the PC to convert MediaPipe's TFLite model to .rknn format, but ran into a protobuf version conflict - TensorFlow requires <code>&lt;3.20</code>, but rknn-toolkit2 requires <code>&gt;=4.25</code>, completely incompatible.</p>
<p><strong>Attempted solutions:</strong></p>
<ul>
<li class="">Switch TensorFlow version -&gt; failed</li>
<li class="">Use a virtual environment -&gt; user refused (I was too lazy...)</li>
<li class="">Tsinghua mirror acceleration -&gt; still conflicted</li>
</ul>
<p><strong>Final solution:</strong> Gave up on PC-side conversion and directly used the officially provided .rknn model to test the NPU. I'll use Docker to run the conversion tool later if needed.</p>
<p><strong>Lesson:</strong> Python dependency management is a huge pit, especially for deep-learning frameworks. Strongly recommend using Docker or conda environments for isolation.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="72-camera-could-not-be-opened">7.2 Camera Could Not Be Opened<a href="https://zephyr.100ask.org/en/blog/npu-yolov5-detection#72-camera-could-not-be-opened" class="hash-link" aria-label="Direct link to 7.2 Camera Could Not Be Opened" title="Direct link to 7.2 Camera Could Not Be Opened" translate="no">​</a></h3>
<p><strong>Problem:</strong> Using <code>cv2.VideoCapture(11)</code> directly failed to open.</p>
<p><strong>Reason:</strong> The rkaiq_3A server (responsible for the camera's auto-exposure/white balance) was not restarted.</p>
<p><strong>Solution:</strong> Add this at the start of the script:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">killall rkaiq_3A_server 2&gt;/dev/null</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sleep 2</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">rm -f /tmp/.rkaiq_3A* 2&gt;/dev/null</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">/etc/init.d/S40rkaiq_3A start &gt;/dev/null 2&gt;&amp;1</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sleep 3</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="73-gstreamer-could-not-find-videoparse">7.3 GStreamer Could Not Find videoparse<a href="https://zephyr.100ask.org/en/blog/npu-yolov5-detection#73-gstreamer-could-not-find-videoparse" class="hash-link" aria-label="Direct link to 7.3 GStreamer Could Not Find videoparse" title="Direct link to 7.3 GStreamer Could Not Find videoparse" translate="no">​</a></h3>
<p><strong>Problem:</strong> At first I wanted to use the <code>videoparse</code> plugin, but it reported that the plugin was missing.</p>
<p><strong>Reason:</strong> Buildroot is a stripped-down system, and many GStreamer plugins are not installed.</p>
<p><strong>Solution:</strong> Switch to JPEG-stream transmission:</p>
<ul>
<li class="">Python encodes to JPEG -&gt; FIFO -&gt; GStreamer's <code>jpegparse</code> decodes</li>
<li class="">This plugin is installed by default</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="74-python-script-chinese-encoding-error">7.4 Python Script Chinese-Encoding Error<a href="https://zephyr.100ask.org/en/blog/npu-yolov5-detection#74-python-script-chinese-encoding-error" class="hash-link" aria-label="Direct link to 7.4 Python Script Chinese-Encoding Error" title="Direct link to 7.4 Python Script Chinese-Encoding Error" translate="no">​</a></h3>
<p><strong>Problem:</strong> The script had Chinese comments, and running it threw an error:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">SyntaxError: Non-UTF-8 code starting with '\xe5'</span><br></div></code></pre></div></div>
<p><strong>Solution:</strong> Change all Chinese comments to English, or add this at the top of the file:</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"># -*- coding: utf-8 -*-</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="8-summary-and-outlook">8. Summary and Outlook<a href="https://zephyr.100ask.org/en/blog/npu-yolov5-detection#8-summary-and-outlook" class="hash-link" aria-label="Direct link to 8. Summary and Outlook" title="Direct link to 8. Summary and Outlook" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="81-takeaways-from-this-practice">8.1 Takeaways from This Practice<a href="https://zephyr.100ask.org/en/blog/npu-yolov5-detection#81-takeaways-from-this-practice" class="hash-link" aria-label="Direct link to 8.1 Takeaways from This Practice" title="Direct link to 8.1 Takeaways from This Practice" translate="no">​</a></h3>
<ol>
<li class="">
<p><strong>Successfully validated the RK3576's NPU hardware-acceleration capability</strong></p>
<ul>
<li class="">ResNet18: 89 FPS (11ms latency)</li>
<li class="">YOLOv5: 10 FPS (50ms NPU latency)</li>
<li class="">CPU usage down 60%, power consumption significantly reduced</li>
</ul>
</li>
<li class="">
<p><strong>Mastered the use of the RKNN toolchain</strong></p>
<ul>
<li class="">Installation and API of rknn-toolkit-lite2</li>
<li class="">Loading and inference of .rknn models</li>
<li class="">Specifying and configuring NPU cores</li>
</ul>
</li>
<li class="">
<p><strong>Built a complete real-time detection pipeline</strong></p>
<ul>
<li class="">Camera capture -&gt; NPU inference -&gt; post-processing -&gt; display</li>
<li class="">The FIFO + GStreamer display solution</li>
<li class="">Performance monitoring and FPS calculation</li>
</ul>
</li>
<li class="">
<p><strong>Stumbled through various pitfalls</strong></p>
<ul>
<li class="">Dependency conflicts, camera initialization, display pipeline, etc.</li>
<li class="">Accumulated valuable debugging experience</li>
</ul>
</li>
</ol>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="82-reflections">8.2 Reflections<a href="https://zephyr.100ask.org/en/blog/npu-yolov5-detection#82-reflections" class="hash-link" aria-label="Direct link to 8.2 Reflections" title="Direct link to 8.2 Reflections" translate="no">​</a></h3>
<p>The RK3576's NPU is indeed powerful; 6 TOPS of compute is a top-tier configuration among edge devices. Although there are some pitfalls in using it (mainly dependency management), the overall experience is still good.</p>
<p>My biggest takeaway is: <strong>AI deployment is not easy!</strong> From model training to deployment, there is so much to consider - accuracy, speed, power, cost... every link requires trade-offs. But the moment I saw the real-time detection picture running smoothly, all the effort was worth it!</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="9-references">9. References<a href="https://zephyr.100ask.org/en/blog/npu-yolov5-detection#9-references" class="hash-link" aria-label="Direct link to 9. References" title="Direct link to 9. References" translate="no">​</a></h2>
<ol>
<li class=""><a href="https://github.com/airockchip/rknn-toolkit2" target="_blank" rel="noopener noreferrer" class="">RKNN-Toolkit2 Official Documentation</a></li>
<li class=""><a href="https://www.rock-chips.com/" target="_blank" rel="noopener noreferrer" class="">RK3576 NPU Technical White Paper</a></li>
<li class=""><a href="https://github.com/ultralytics/yolov5" target="_blank" rel="noopener noreferrer" class="">YOLOv5 Official Repository</a></li>
<li class=""><a href="https://gstreamer.freedesktop.org/documentation/" target="_blank" rel="noopener noreferrer" class="">GStreamer Pipeline Design Guide</a></li>
<li class="">My earlier articles</li>
</ol>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="appendix-a-complete-yolov5-inference-script">Appendix A: Complete YOLOv5 Inference Script<a href="https://zephyr.100ask.org/en/blog/npu-yolov5-detection#appendix-a-complete-yolov5-inference-script" class="hash-link" aria-label="Direct link to Appendix A: Complete YOLOv5 Inference Script" title="Direct link to Appendix A: Complete YOLOv5 Inference Script" translate="no">​</a></h2>
<p>Due to length, the complete Python code has been integrated into the <code>yolo_npu_display.sh</code> script.</p>
<p>Key function descriptions:</p>
<ul>
<li class=""><code>xywh2xyxy()</code>: bounding-box coordinate conversion</li>
<li class=""><code>process()</code>: YOLO output parsing</li>
<li class=""><code>filter_boxes()</code>: confidence filtering</li>
<li class=""><code>nms_boxes()</code>: non-maximum suppression (removes overlapping boxes)</li>
<li class=""><code>yolov5_post_process()</code>: complete post-processing flow</li>
</ul>]]></content:encoded>
            <category>NPU</category>
            <category>YOLOv5</category>
            <category>Object Detection</category>
            <category>RK3576</category>
        </item>
        <item>
            <title><![CDATA[DshanPI-A1 Review Part 4: Modifying an Open-Source Gesture Project]]></title>
            <link>https://zephyr.100ask.org/en/blog/open-gesture-project-modify</link>
            <guid>https://zephyr.100ask.org/en/blog/open-gesture-project-modify</guid>
            <pubDate>Wed, 26 Nov 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[Modify an open-source gesture project in terms of compatibility, smoothness, screen display, and camera invocation.]]></description>
            <content:encoded><![CDATA[<p>All of the project modifications in this article are based mainly on compatibility, smoothness, screen display method, and camera invocation.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="display-output-adaptation">Display Output Adaptation<a href="https://zephyr.100ask.org/en/blog/open-gesture-project-modify#display-output-adaptation" class="hash-link" aria-label="Direct link to Display Output Adaptation" title="Direct link to Display Output Adaptation" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="main-adaptation-issues">Main Adaptation Issues<a href="https://zephyr.100ask.org/en/blog/open-gesture-project-modify#main-adaptation-issues" class="hash-link" aria-label="Direct link to Main Adaptation Issues" title="Direct link to Main Adaptation Issues" translate="no">​</a></h3>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="1-rk3576-runs-a-pure-wayland-environment">1. RK3576 Runs a Pure Wayland Environment<a href="https://zephyr.100ask.org/en/blog/open-gesture-project-modify#1-rk3576-runs-a-pure-wayland-environment" class="hash-link" aria-label="Direct link to 1. RK3576 Runs a Pure Wayland Environment" title="Direct link to 1. RK3576 Runs a Pure Wayland Environment" translate="no">​</a></h4>
<p>RK3576 runs a pure Wayland environment with no X11 or libGL support, so the traditional <code>cv2.imshow()</code> cannot be used to display images.</p>
<p><strong>[Solution]</strong></p>
<p>Adopt the FIFO + GStreamer + Wayland display pipeline:</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"># Python side code</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">fifo </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token builtin">open</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'/tmp/gesture_fifo'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'wb'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">while</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">True</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    _</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> jpeg </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> cv2</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">imencode</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'.jpg'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> processed_frame</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">cv2</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">IMWRITE_JPEG_QUALITY</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">85</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    fifo</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">write</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">jpeg</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">tobytes</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    fifo</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">flush</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><br></div></code></pre></div></div>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain"># Shell side code</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># GStreamer reads the JPEG stream from the pipe and displays it</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">gst-launch-1.0 filesrc location=/tmp/gesture_fifo ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    jpegparse ! jpegdec ! videoconvert ! waylandsink fullscreen=true</span><br></div></code></pre></div></div>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="2-imx415-camera-color-anomaly-on-second-launch">2. IMX415 Camera Color Anomaly on Second Launch<a href="https://zephyr.100ask.org/en/blog/open-gesture-project-modify#2-imx415-camera-color-anomaly-on-second-launch" class="hash-link" aria-label="Direct link to 2. IMX415 Camera Color Anomaly on Second Launch" title="Direct link to 2. IMX415 Camera Color Anomaly on Second Launch" translate="no">​</a></h4>
<p>The IMX415 camera shows a color anomaly on its second launch, with the kernel reporting the error "no first iq setting".</p>
<p><strong>[Solution]</strong></p>
<p>Restart rkaiq_3A_server before each camera open:</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">def</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">restart_3a</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">self</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    os</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">system</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"killall rkaiq_3A_server 2&gt;/dev/null"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    time</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">sleep</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">2</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    os</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">system</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"rm -f /tmp/.rkaiq_3A* 2&gt;/dev/null"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    os</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">system</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"/etc/init.d/S40rkaiq_3A start &gt;/dev/null 2&gt;&amp;1"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    time</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">sleep</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">5</span><span class="token punctuation" style="color:#393A34">)</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="project-1-snake-game">Project 1: Snake Game<a href="https://zephyr.100ask.org/en/blog/open-gesture-project-modify#project-1-snake-game" class="hash-link" aria-label="Direct link to Project 1: Snake Game" title="Direct link to Project 1: Snake Game" translate="no">​</a></h2>
<p>Open-source project address: <a href="https://github.com/WLHSDXN/Project2/blob/main/SnakeGame/main.py" target="_blank" rel="noopener noreferrer" class="">Project2/SnakeGame/main.py at main · WLHSDXN/Project2</a></p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="modification-process">Modification Process<a href="https://zephyr.100ask.org/en/blog/open-gesture-project-modify#modification-process" class="hash-link" aria-label="Direct link to Modification Process" title="Direct link to Modification Process" translate="no">​</a></h3>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="1-multi-layer-detector-architecture">1. Multi-Layer Detector Architecture<a href="https://zephyr.100ask.org/en/blog/open-gesture-project-modify#1-multi-layer-detector-architecture" class="hash-link" aria-label="Direct link to 1. Multi-Layer Detector Architecture" title="Direct link to 1. Multi-Layer Detector Architecture" translate="no">​</a></h4>
<p>To accommodate different dependency environments, a three-layer detector fallback mechanism was designed:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">Priority 1: cvzone (MediaPipe wrapper, high accuracy)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  ↓ unavailable</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Priority 2: native MediaPipe (21 keypoints)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  ↓ unavailable</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Priority 3: HSV skin-color detection (lightweight fallback)</span><br></div></code></pre></div></div>
<p>Code implementation:</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"># Detector selection logic</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> USE_CVZONE</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    detector </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> CvzoneHandDetector</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">detectionCon</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">0.8</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> maxHands</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">elif</span><span class="token plain"> USE_MEDIAPIPE</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    detector </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> MediapipeHandDetector</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">maxHands</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                    detectionCon</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">0.5</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                    drawLandmarks</span><span class="token operator" style="color:#393A34">=</span><span class="token boolean" style="color:#36acaa">False</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">else</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    detector </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> SimpleHandDetector</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic"># HSV fallback solution</span><br></div></code></pre></div></div>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="2-mediapipe-integration-and-wrapping">2. MediaPipe Integration and Wrapping<a href="https://zephyr.100ask.org/en/blog/open-gesture-project-modify#2-mediapipe-integration-and-wrapping" class="hash-link" aria-label="Direct link to 2. MediaPipe Integration and Wrapping" title="Direct link to 2. MediaPipe Integration and Wrapping" translate="no">​</a></h4>
<p>Implemented the MediapipeHandDetector class, returning a data format compatible with cvzone:</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">MediapipeHandDetector</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">def</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">findHands</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">self</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> frame</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> flipType</span><span class="token operator" style="color:#393A34">=</span><span class="token boolean" style="color:#36acaa">False</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        img_rgb </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> cv2</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">cvtColor</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">frame</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> cv2</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">COLOR_BGR2RGB</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        results </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> self</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">hands</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">process</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">img_rgb</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        hands </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> results</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">multi_hand_landmarks</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">for</span><span class="token plain"> hand_landmarks </span><span class="token keyword" style="color:#00009f">in</span><span class="token plain"> results</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">multi_hand_landmarks</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token comment" style="color:#999988;font-style:italic"># Extract 21 keypoint coordinates</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                lmList </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token keyword" style="color:#00009f">for</span><span class="token plain"> lm </span><span class="token keyword" style="color:#00009f">in</span><span class="token plain"> hand_landmarks</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">landmark</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                    x_px </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token builtin">int</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">lm</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">x </span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> width</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                    y_px </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token builtin">int</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">lm</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">y </span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> height</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                    lmList</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">append</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">x_px</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> y_px</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> lm</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">z</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                hands</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">append</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token string" style="color:#e3116c">'lmList'</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> lmList</span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> hands</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> frame</span><br></div></code></pre></div></div>
<p><strong>[Key Point]</strong></p>
<p>The index fingertip is lmList[8], used directly as the snake-head control point.</p>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="3-hsv-skin-color-detection-fallback">3. HSV Skin-Color Detection Fallback<a href="https://zephyr.100ask.org/en/blog/open-gesture-project-modify#3-hsv-skin-color-detection-fallback" class="hash-link" aria-label="Direct link to 3. HSV Skin-Color Detection Fallback" title="Direct link to 3. HSV Skin-Color Detection Fallback" translate="no">​</a></h4>
<p>When MediaPipe is unavailable, use simple skin-color detection:</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">def</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">detect_hand_simple</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">frame</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    hsv </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> cv2</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">cvtColor</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">frame</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> cv2</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">COLOR_BGR2HSV</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    mask </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> cv2</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">inRange</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">hsv</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">30</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">60</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">255</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">255</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">255</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic"># Morphological denoising</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    kernel </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> np</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">ones</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">7</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">7</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> np</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">uint8</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    mask </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> cv2</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">morphologyEx</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">mask</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> cv2</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">MORPH_CLOSE</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> kernel</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> iterations</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">3</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    mask </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> cv2</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">morphologyEx</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">mask</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> cv2</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">MORPH_OPEN</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> kernel</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> iterations</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">2</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    contours</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> _ </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> cv2</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">findContours</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">mask</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> cv2</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">RETR_EXTERNAL</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                    cv2</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">CHAIN_APPROX_SIMPLE</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> contours</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        c </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token builtin">max</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">contours</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> key</span><span class="token operator" style="color:#393A34">=</span><span class="token plain">cv2</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">contourArea</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        hull </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> cv2</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">convexHull</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">c</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic"># Extract the topmost point as the "fingertip"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        topmost </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> hull</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">hull</span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">:</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">:</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">argmin</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> topmost</span><br></div></code></pre></div></div>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="4-mediapipe-performance-tuning">4. MediaPipe Performance Tuning<a href="https://zephyr.100ask.org/en/blog/open-gesture-project-modify#4-mediapipe-performance-tuning" class="hash-link" aria-label="Direct link to 4. MediaPipe Performance Tuning" title="Direct link to 4. MediaPipe Performance Tuning" translate="no">​</a></h4>
<h5 class="anchor anchorTargetStickyNavbar_Vzrq" id="optimization-1-use-a-lightweight-model">Optimization 1: Use a Lightweight Model<a href="https://zephyr.100ask.org/en/blog/open-gesture-project-modify#optimization-1-use-a-lightweight-model" class="hash-link" aria-label="Direct link to Optimization 1: Use a Lightweight Model" title="Direct link to Optimization 1: Use a Lightweight Model" translate="no">​</a></h5>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">self</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">hands </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> mp</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">solutions</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">hands</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Hands</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    model_complexity</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic"># 0=lite, 1=full (default)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    max_num_hands</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    min_detection_confidence</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">0.5</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic"># lower threshold for speed</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    min_tracking_confidence</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">0.5</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">)</span><br></div></code></pre></div></div>
<h5 class="anchor anchorTargetStickyNavbar_Vzrq" id="optimization-2-disable-visualization-drawing">Optimization 2: Disable Visualization Drawing<a href="https://zephyr.100ask.org/en/blog/open-gesture-project-modify#optimization-2-disable-visualization-drawing" class="hash-link" aria-label="Direct link to Optimization 2: Disable Visualization Drawing" title="Direct link to Optimization 2: Disable Visualization Drawing" translate="no">​</a></h5>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"># Remove the time-consuming keypoint drawing</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># mp_drawing.draw_landmarks(frame, landmarks, connections)  # commented out</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">drawLandmarks</span><span class="token operator" style="color:#393A34">=</span><span class="token boolean" style="color:#36acaa">False</span><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic"># new switch</span><br></div></code></pre></div></div>
<h5 class="anchor anchorTargetStickyNavbar_Vzrq" id="optimization-3-reduce-input-resolution">Optimization 3: Reduce Input Resolution<a href="https://zephyr.100ask.org/en/blog/open-gesture-project-modify#optimization-3-reduce-input-resolution" class="hash-link" aria-label="Direct link to Optimization 3: Reduce Input Resolution" title="Direct link to Optimization 3: Reduce Input Resolution" translate="no">​</a></h5>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"># 640x480 is already the optimal balance point</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># Lowering further to 320x240 can boost FPS, but hurts detection accuracy</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">cap</span><span class="token punctuation" style="color:#393A34">.</span><span class="token builtin">set</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">cv2</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">CAP_PROP_FRAME_WIDTH</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">640</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">cap</span><span class="token punctuation" style="color:#393A34">.</span><span class="token builtin">set</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">cv2</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">CAP_PROP_FRAME_HEIGHT</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">480</span><span class="token punctuation" style="color:#393A34">)</span><br></div></code></pre></div></div>
<h5 class="anchor anchorTargetStickyNavbar_Vzrq" id="optimization-4-optimize-the-camera-buffer">Optimization 4: Optimize the Camera Buffer<a href="https://zephyr.100ask.org/en/blog/open-gesture-project-modify#optimization-4-optimize-the-camera-buffer" class="hash-link" aria-label="Direct link to Optimization 4: Optimize the Camera Buffer" title="Direct link to Optimization 4: Optimize the Camera Buffer" translate="no">​</a></h5>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">cap</span><span class="token punctuation" style="color:#393A34">.</span><span class="token builtin">set</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">cv2</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">CAP_PROP_BUFFERSIZE</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic"># reduce latency</span><br></div></code></pre></div></div>
<p><strong>[Optimization Effect]</strong></p>
<p>FPS increased from 5-10 to 15-25 FPS, meeting the needs of game interaction.</p>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="5-file-based-control-interface">5. File-Based Control Interface<a href="https://zephyr.100ask.org/en/blog/open-gesture-project-modify#5-file-based-control-interface" class="hash-link" aria-label="Direct link to 5. File-Based Control Interface" title="Direct link to 5. File-Based Control Interface" translate="no">​</a></h4>
<p>Because keyboard input cannot be captured directly in FIFO mode, a control-file approach is used:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain"># Shell script section</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># Read keypresses and write control files</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">stty echo icanon</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">while read n1 t 0.1 key; do</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    if [ "$key" = "r" ]; then</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        touch /tmp/snake_restart</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    elif [ "$key" = "q" ]; then</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        touch /tmp/snake_quit</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    fi</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">done</span><br></div></code></pre></div></div>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"># Python section</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># Detect control files</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> os</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">path</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">exists</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'/tmp/snake_quit'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">print</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'Quit command detected'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">break</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> os</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">path</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">exists</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'/tmp/snake_restart'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    os</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">remove</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'/tmp/snake_restart'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic"># Reset game state</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    self</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">game</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">gameOver </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">False</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    self</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">game</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">points </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    self</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">game</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">previousHead </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">)</span><br></div></code></pre></div></div>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="effect-demonstration">Effect Demonstration<a href="https://zephyr.100ask.org/en/blog/open-gesture-project-modify#effect-demonstration" class="hash-link" aria-label="Direct link to Effect Demonstration" title="Direct link to Effect Demonstration" translate="no">​</a></h4>
<p>The code and demo video are in the attachments.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="project-2-virtual-drawing-board">Project 2: Virtual Drawing Board<a href="https://zephyr.100ask.org/en/blog/open-gesture-project-modify#project-2-virtual-drawing-board" class="hash-link" aria-label="Direct link to Project 2: Virtual Drawing Board" title="Direct link to Project 2: Virtual Drawing Board" translate="no">​</a></h2>
<p>Open-source project: [Based on hand keypoint detection, air-control the mouse / air-draw] <a href="https://www.bilibili.com/video/BV1364y1h7PS?vd_source=a16ca768198c38baa684546cf5060811" target="_blank" rel="noopener noreferrer" class="">https://www.bilibili.com/video/BV1364y1h7PS?vd_source=a16ca768198c38baa684546cf5060811</a></p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="modification-process-1">Modification Process<a href="https://zephyr.100ask.org/en/blog/open-gesture-project-modify#modification-process-1" class="hash-link" aria-label="Direct link to Modification Process" title="Direct link to Modification Process" translate="no">​</a></h3>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="1-core-logic-extraction">1. Core Logic Extraction<a href="https://zephyr.100ask.org/en/blog/open-gesture-project-modify#1-core-logic-extraction" class="hash-link" aria-label="Direct link to 1. Core Logic Extraction" title="Direct link to 1. Core Logic Extraction" translate="no">​</a></h4>
<h5 class="anchor anchorTargetStickyNavbar_Vzrq" id="gesture-recognition-logic">Gesture Recognition Logic:<a href="https://zephyr.100ask.org/en/blog/open-gesture-project-modify#gesture-recognition-logic" class="hash-link" aria-label="Direct link to Gesture Recognition Logic:" title="Direct link to Gesture Recognition Logic:" translate="no">​</a></h5>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">fingers </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> detector</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">fingersUp</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic"># returns 5 values, 1 means finger extended</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># Mode 1: select tool (index + middle finger extended)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> fingers</span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">and</span><span class="token plain"> fingers</span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">2</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> y1 </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">153</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic"># in the top toolbar area</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain"> x1 </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">320</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain">    color </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">50</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">128</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">250</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic"># blue</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">elif</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">320</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain"> x1 </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">640</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain">  color </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">255</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic"># red</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">elif</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">640</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain"> x1 </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">960</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain">  color </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">255</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic"># green</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">elif</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">960</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain"> x1 </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1280</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> color </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain">     </span><span class="token comment" style="color:#999988;font-style:italic"># eraser</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># Mode 2: draw (only index finger extended)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">elif</span><span class="token plain"> fingers</span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">and</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">not</span><span class="token plain"> fingers</span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">2</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    cv2</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">line</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">imgCanvas</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">xp</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> yp</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">x1</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> y1</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> color</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> brushThickness</span><span class="token punctuation" style="color:#393A34">)</span><br></div></code></pre></div></div>
<h5 class="anchor anchorTargetStickyNavbar_Vzrq" id="canvas-compositing-logic">Canvas Compositing Logic:<a href="https://zephyr.100ask.org/en/blog/open-gesture-project-modify#canvas-compositing-logic" class="hash-link" aria-label="Direct link to Canvas Compositing Logic:" title="Direct link to Canvas Compositing Logic:" translate="no">​</a></h5>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"># 1. Convert the canvas to grayscale and binarize it</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">imgGray </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> cv2</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">cvtColor</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">imgCanvas</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> cv2</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">COLOR_BGR2GRAY</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">_</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> imgInv </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> cv2</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">threshold</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">imgGray</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">50</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">255</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> cv2</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">THRESH_BINARY_INV</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># 2. Composite with bitwise operations</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">img </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> cv2</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">bitwise_and</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">img</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> imgInv</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic"># keep non-drawing area of camera frame</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">img </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> cv2</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">bitwise_or</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">img</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> imgCanvas</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain">   </span><span class="token comment" style="color:#999988;font-style:italic"># overlay drawing content</span><br></div></code></pre></div></div>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="2-display-system-rebuild">2. Display System Rebuild<a href="https://zephyr.100ask.org/en/blog/open-gesture-project-modify#2-display-system-rebuild" class="hash-link" aria-label="Direct link to 2. Display System Rebuild" title="Direct link to 2. Display System Rebuild" translate="no">​</a></h4>
<p>Reuse the snake game's display solution: FIFO + GStreamer.</p>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="3-toolbar-internalization">3. Toolbar Internalization<a href="https://zephyr.100ask.org/en/blog/open-gesture-project-modify#3-toolbar-internalization" class="hash-link" aria-label="Direct link to 3. Toolbar Internalization" title="Direct link to 3. Toolbar Internalization" translate="no">​</a></h4>
<p>The original project depended on 4 PNG images as the toolbar, which is inconvenient for managing external resources on an embedded system.</p>
<p><strong>[Solution]</strong></p>
<p>Generate the toolbar with OpenCV drawing APIs:</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">def</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">create_header</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">self</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token triple-quoted-string string" style="color:#e3116c">"""Dynamically generate the toolbar"""</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    header </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> np</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">zeros</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">100</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> self</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">width</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">3</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> np</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">uint8</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    header</span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">:</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">200</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">200</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">200</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic"># gray background</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    tools </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">250</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">128</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">50</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Blue"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic"># BGR format</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">255</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Red"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">255</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Green"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Eraser"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    section_width </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> self</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">width </span><span class="token operator" style="color:#393A34">//</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">4</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">for</span><span class="token plain"> i</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">color</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> label</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">in</span><span class="token plain"> </span><span class="token builtin">enumerate</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">tools</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        x1 </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> i </span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> section_width</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        x2 </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">i </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> section_width</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic"># Draw color block</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        cv2</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">rectangle</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">header</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">x1 </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">10</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">20</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">x2 </span><span class="token operator" style="color:#393A34">-</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">10</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">80</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> color</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        cv2</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">rectangle</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">header</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">x1 </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">10</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">20</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">x2 </span><span class="token operator" style="color:#393A34">-</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">10</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">80</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">               </span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">255</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">255</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">255</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">2</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic"># white border</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic"># Text label</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        cv2</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">putText</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">header</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> label</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">x1 </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">20</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">95</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">              cv2</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">FONT_HERSHEY_SIMPLEX</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0.5</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">50</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">50</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">50</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> header</span><br></div></code></pre></div></div>
<p>This way there is zero dependency on external resources, which is better for porting and project development!</p>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="4-camera-and-3a-service-adaptation">4. Camera and 3A Service Adaptation<a href="https://zephyr.100ask.org/en/blog/open-gesture-project-modify#4-camera-and-3a-service-adaptation" class="hash-link" aria-label="Direct link to 4. Camera and 3A Service Adaptation" title="Direct link to 4. Camera and 3A Service Adaptation" translate="no">​</a></h4>
<p>Reuse the snake game's fix.</p>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="5-resolution-vs-performance-trade-off">5. Resolution vs. Performance Trade-off<a href="https://zephyr.100ask.org/en/blog/open-gesture-project-modify#5-resolution-vs-performance-trade-off" class="hash-link" aria-label="Direct link to 5. Resolution vs. Performance Trade-off" title="Direct link to 5. Resolution vs. Performance Trade-off" translate="no">​</a></h4>
<p><strong>[Original Configuration]</strong>:</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">width </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1280</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> height </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">720</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">canvas</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> imgCanvas </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> np</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">zeros</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">720</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1280</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">3</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> np</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">uint8</span><span class="token punctuation" style="color:#393A34">)</span><br></div></code></pre></div></div>
<p><strong>[RK3576 Optimization]</strong></p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">width </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">640</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> height </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">480</span><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic"># reduce resolution by 50%</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">canvas</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> imgCanvas </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> np</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">zeros</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">480</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">640</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">3</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> np</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">uint8</span><span class="token punctuation" style="color:#393A34">)</span><br></div></code></pre></div></div>
<p><strong>[Reasons]</strong></p>
<ol>
<li class="">MediaPipe's FPS roughly doubles at 640x480</li>
<li class="">The drawing-board application does not demand as high a resolution as vision recognition</li>
<li class="">JPEG encoding/transmission is faster</li>
</ol>
<p><strong>[Toolbar Adaptation]</strong></p>
<p>Original: 153 pixels tall at the top, divided into 4 regions 320 pixels wide
RK3576: 100 pixels tall at the top, divided into 4 regions 160 pixels wide</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">section_width </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> self</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">width </span><span class="token operator" style="color:#393A34">//</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">4</span><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic"># adaptive width</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> y1 </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">100</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic"># toolbar height</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain"> x1 </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain"> section_width</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        self</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">color </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">250</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">128</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">50</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic"># blue</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">elif</span><span class="token plain"> section_width </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain"> x1 </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain"> section_width </span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">2</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        self</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">color </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">255</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain">   </span><span class="token comment" style="color:#999988;font-style:italic"># red</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># ...</span><br></div></code></pre></div></div>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="6-interaction-control-improvements">6. Interaction Control Improvements<a href="https://zephyr.100ask.org/en/blog/open-gesture-project-modify#6-interaction-control-improvements" class="hash-link" aria-label="Direct link to 6. Interaction Control Improvements" title="Direct link to 6. Interaction Control Improvements" translate="no">​</a></h4>
<h5 class="anchor anchorTargetStickyNavbar_Vzrq" id="1-clear-canvas-mechanism">1. Clear-Canvas Mechanism<a href="https://zephyr.100ask.org/en/blog/open-gesture-project-modify#1-clear-canvas-mechanism" class="hash-link" aria-label="Direct link to 1. Clear-Canvas Mechanism" title="Direct link to 1. Clear-Canvas Mechanism" translate="no">​</a></h5>
<p><strong>[Original]</strong></p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token builtin">all</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">x </span><span class="token operator" style="color:#393A34">&gt;=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">for</span><span class="token plain"> x </span><span class="token keyword" style="color:#00009f">in</span><span class="token plain"> fingers</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    imgCanvas </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> np</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">zeros</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">720</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1280</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">3</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> np</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">uint8</span><span class="token punctuation" style="color:#393A34">)</span><br></div></code></pre></div></div>
<p><strong>[Problem]</strong></p>
<p>High false-trigger rate; inconvenient for fine control.</p>
<p><strong>[RK3576 Improvement]</strong></p>
<p>Use keypress control:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain"># Shell side</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">while read -n1 -t 0.1 key; do</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    if [ "$key" = "c" ]; then</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        touch /tmp/painter_clear</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    fi</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">done</span><br></div></code></pre></div></div>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"># Python side</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> os</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">path</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">exists</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'/tmp/painter_clear'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    os</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">remove</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'/tmp/painter_clear'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    self</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">imgCanvas </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> np</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">zeros</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">self</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">height</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> self</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">width</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">3</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> np</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">uint8</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">print</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"Canvas cleared"</span><span class="token punctuation" style="color:#393A34">)</span><br></div></code></pre></div></div>
<h5 class="anchor anchorTargetStickyNavbar_Vzrq" id="2-exit-control">2. Exit Control<a href="https://zephyr.100ask.org/en/blog/open-gesture-project-modify#2-exit-control" class="hash-link" aria-label="Direct link to 2. Exit Control" title="Direct link to 2. Exit Control" translate="no">​</a></h5>
<p><strong>[Original]</strong></p>
<p>Can only capture the keyboard through <code>cv2.waitKey(1)</code>, dependent on window focus.</p>
<p><strong>[RK3576]</strong></p>
<p>Dual exit mechanism:</p>
<ol>
<li class="">
<p>Keypress control:
touch /tmp/painter_quit -&gt; Python detects it and exits</p>
</li>
<li class="">
<p>Ctrl+C:
Shell script traps the signal -&gt; kills all processes -&gt; cleans up the FIFO</p>
</li>
</ol>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="effect-demonstration-1">Effect Demonstration<a href="https://zephyr.100ask.org/en/blog/open-gesture-project-modify#effect-demonstration-1" class="hash-link" aria-label="Direct link to Effect Demonstration" title="Direct link to Effect Demonstration" translate="no">​</a></h4>
<p>The code and demo video are in the attachments.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="technical-summary-and-lessons">Technical Summary and Lessons<a href="https://zephyr.100ask.org/en/blog/open-gesture-project-modify#technical-summary-and-lessons" class="hash-link" aria-label="Direct link to Technical Summary and Lessons" title="Direct link to Technical Summary and Lessons" translate="no">​</a></h2>
<ol>
<li class="">
<p><strong>Cross-Platform Display Adaptation</strong>
PC GUI solutions do not apply to embedded systems; the output method must be chosen based on system characteristics (Wayland/Framebuffer).</p>
</li>
<li class="">
<p><strong>Resource Internalization</strong>
Embedded systems tend toward single-file deployment; external resources should be turned into code-generated content or packed into the program.</p>
</li>
<li class="">
<p><strong>Tiered Performance Optimization</strong></p>
<ul>
<li class="">Algorithm layer: lightweight models</li>
<li class="">Implementation layer: disable non-essential drawing</li>
<li class="">Hardware layer: buffer/resolution tuning</li>
</ul>
</li>
<li class="">
<p><strong>Interaction Adaptation</strong>
Keyboard/mouse events that GUIs depend on must be converted to file control or GPIO triggers.</p>
</li>
</ol>]]></content:encoded>
            <category>Gesture Recognition</category>
            <category>Project Modification</category>
            <category>MediaPipe</category>
            <category>RK3576</category>
        </item>
        <item>
            <title><![CDATA[DshanPI-A1 Review Part 3: OpenCV Debugging and CPU-Based Gesture Recognition Inference]]></title>
            <link>https://zephyr.100ask.org/en/blog/opencv-cpu-gesture</link>
            <guid>https://zephyr.100ask.org/en/blog/opencv-cpu-gesture</guid>
            <pubDate>Mon, 24 Nov 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[Implement real-time gesture recognition on RK3576 Buildroot using OpenCV, recognizing five gestures and displaying results on the screen.]]></description>
            <content:encoded><![CDATA[<p>Previously we finished debugging the camera and the screen, so now we can finally start working on gesture recognition!</p>
<p>This time I will implement a real-time, OpenCV-based gesture recognition system on the RK3576 Buildroot system. The system can recognize five gestures (fist/one finger, two, three, four, five fingers) and display the processing results on the screen in real time.</p>
<p>Given the particularities of embedded systems, we will focus on how to render images in a Wayland environment with no X11 and no OpenGL.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="gesture-recognition-algorithm">Gesture Recognition Algorithm<a href="https://zephyr.100ask.org/en/blog/opencv-cpu-gesture#gesture-recognition-algorithm" class="hash-link" aria-label="Direct link to Gesture Recognition Algorithm" title="Direct link to Gesture Recognition Algorithm" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="principle">Principle<a href="https://zephyr.100ask.org/en/blog/opencv-cpu-gesture#principle" class="hash-link" aria-label="Direct link to Principle" title="Direct link to Principle" translate="no">​</a></h3>
<p>Because there are concavities between our spread fingers, we can accurately identify the number of fingers by calculating the angle and depth of these concavity points.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="1-skin-color-detection">1. Skin Color Detection<a href="https://zephyr.100ask.org/en/blog/opencv-cpu-gesture#1-skin-color-detection" class="hash-link" aria-label="Direct link to 1. Skin Color Detection" title="Direct link to 1. Skin Color Detection" translate="no">​</a></h3>
<p>Use the HSV color space to extract the skin-color region:</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">def</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">detect_hand</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">self</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> frame</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    hsv </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> cv2</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">cvtColor</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">frame</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> cv2</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">COLOR_BGR2HSV</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    mask </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> cv2</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">inRange</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">hsv</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">30</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">60</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">25</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">255</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">255</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic"># skin color range</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic"># Morphological processing for denoising</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    kernel </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> np</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">ones</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">7</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">7</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> np</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">uint8</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    mask </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> cv2</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">morphologyEx</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">mask</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> cv2</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">MORPH_CLOSE</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> kernel</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> iterations</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">3</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    mask </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> cv2</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">morphologyEx</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">mask</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> cv2</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">MORPH_OPEN</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> kernel</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> iterations</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">2</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic"># Find the largest contour</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    contours</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> _ </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> cv2</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">findContours</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">mask</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> cv2</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">RETR_EXTERNAL</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> cv2</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">CHAIN_APPROX_SIMPLE</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> contours</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        c </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token builtin">max</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">contours</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> key</span><span class="token operator" style="color:#393A34">=</span><span class="token plain">cv2</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">contourArea</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> cv2</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">contourArea</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">c</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">3000</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic"># area threshold to filter noise</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> c</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> mask</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">None</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> mask</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="2-finger-counting-convex-hull-defect-method">2. Finger Counting (Convex Hull Defect Method)<a href="https://zephyr.100ask.org/en/blog/opencv-cpu-gesture#2-finger-counting-convex-hull-defect-method" class="hash-link" aria-label="Direct link to 2. Finger Counting (Convex Hull Defect Method)" title="Direct link to 2. Finger Counting (Convex Hull Defect Method)" translate="no">​</a></h3>
<p>Identify fingers by detecting the concavity points of the hand contour:</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">def</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">recognize</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">self</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> contour</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    hull </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> cv2</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">convexHull</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">contour</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> returnPoints</span><span class="token operator" style="color:#393A34">=</span><span class="token boolean" style="color:#36acaa">False</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    defects </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> cv2</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">convexityDefects</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">contour</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> hull</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    finger_count </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">for</span><span class="token plain"> i </span><span class="token keyword" style="color:#00009f">in</span><span class="token plain"> </span><span class="token builtin">range</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">defects</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">shape</span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        s</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> e</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> f</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> d </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> defects</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">i</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        start </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token builtin">tuple</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">contour</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">s</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic"># convex point 1</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        end </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token builtin">tuple</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">contour</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">e</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic"># convex point 2</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        far </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token builtin">tuple</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">contour</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">f</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic"># concavity point (between fingers)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic"># Calculate the angle to determine whether it is a valid fingertip</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        a </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> np</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">linalg</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">norm</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">np</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">array</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">start</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token plain"> np</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">array</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">end</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        b </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> np</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">linalg</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">norm</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">np</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">array</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">start</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token plain"> np</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">array</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">far</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        c </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> np</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">linalg</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">norm</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">np</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">array</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">end</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token plain"> np</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">array</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">far</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        angle </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> np</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">arccos</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">b</span><span class="token operator" style="color:#393A34">**</span><span class="token number" style="color:#36acaa">2</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> c</span><span class="token operator" style="color:#393A34">**</span><span class="token number" style="color:#36acaa">2</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token plain"> a</span><span class="token operator" style="color:#393A34">**</span><span class="token number" style="color:#36acaa">2</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">/</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">2</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> b </span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> c</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> angle </span><span class="token operator" style="color:#393A34">&lt;=</span><span class="token plain"> np</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">pi </span><span class="token operator" style="color:#393A34">/</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">2.2</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">and</span><span class="token plain"> d </span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">8000</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic"># angle and depth thresholds</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            finger_count </span><span class="token operator" style="color:#393A34">+=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    gestures </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">"Fist/One"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Two"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Three"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Four"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Five"</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> gestures</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">finger_count</span><span class="token punctuation" style="color:#393A34">]</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="how-to-display-the-opencv-processed-image">How to Display the OpenCV-Processed Image<a href="https://zephyr.100ask.org/en/blog/opencv-cpu-gesture#how-to-display-the-opencv-processed-image" class="hash-link" aria-label="Direct link to How to Display the OpenCV-Processed Image" title="Direct link to How to Display the OpenCV-Processed Image" translate="no">​</a></h2>
<p>Theory alone is not enough - we need practice! How to display the OpenCV-processed image is the focus of this tutorial. Normally we use <code>cv2.imshow()</code> to display an image, but on an embedded system without X11/OpenGL this method is unavailable. We need to use the <strong>GStreamer + Wayland</strong> solution (the same approach as in our previous article).</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="exploration-of-solutions">Exploration of Solutions<a href="https://zephyr.100ask.org/en/blog/opencv-cpu-gesture#exploration-of-solutions" class="hash-link" aria-label="Direct link to Exploration of Solutions" title="Direct link to Exploration of Solutions" translate="no">​</a></h3>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="solution-a-stdin-pipe-transmission">Solution A: stdin Pipe Transmission<a href="https://zephyr.100ask.org/en/blog/opencv-cpu-gesture#solution-a-stdin-pipe-transmission" class="hash-link" aria-label="Direct link to Solution A: stdin Pipe Transmission" title="Direct link to Solution A: stdin Pipe Transmission" translate="no">​</a></h4>
<p>The most intuitive idea is to transmit image data through the stdin pipe:</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">proc </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> subprocess</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Popen</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">'gst-launch-1.0'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'fdsrc'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'!'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">.</span><span class="token punctuation" style="color:#393A34">.</span><span class="token punctuation" style="color:#393A34">.</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> stdin</span><span class="token operator" style="color:#393A34">=</span><span class="token plain">subprocess</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">PIPE</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">proc</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">stdin</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">write</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">frame_data</span><span class="token punctuation" style="color:#393A34">)</span><br></div></code></pre></div></div>
<p><strong>Result</strong>: Broken pipe errors occurred frequently and the data transmission was unstable. I suspect the pipe was timing out and closing automatically, or my format was wrong. So I directly tried using a FIFO to transmit raw data.</p>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="solution-b-named-pipe-fifo-for-raw-data-transmission">Solution B: Named Pipe (FIFO) for Raw Data Transmission<a href="https://zephyr.100ask.org/en/blog/opencv-cpu-gesture#solution-b-named-pipe-fifo-for-raw-data-transmission" class="hash-link" aria-label="Direct link to Solution B: Named Pipe (FIFO) for Raw Data Transmission" title="Direct link to Solution B: Named Pipe (FIFO) for Raw Data Transmission" translate="no">​</a></h4>
<p>Try to transmit raw RGB data through a FIFO:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">mkfifo /tmp/video_fifo</span><br></div></code></pre></div></div>
<p>Unfortunately, this caused kernel crashes all too easily. At this point I was facing several problems: if I only used the command line to view the recognition results, I had no way of knowing whether the camera was running normally; but OpenCV and GStreamer reading the camera simultaneously was not possible (the camera can only be read by one process). Later I realized that the GStreamer display did not need to read the camera frame in real time - I only needed to display what OpenCV had processed. So I got to work, and tried to pass the OpenCV-processed image directly to the screen through GStreamer, but my skills were not up to the task and it came to nothing: the pipe either errored or closed. I stopped to think slowly, and finally came up with Solution C (getting to this step had already taken three days).</p>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="solution-c-multi-file-sequence">Solution C: Multi-File Sequence<a href="https://zephyr.100ask.org/en/blog/opencv-cpu-gesture#solution-c-multi-file-sequence" class="hash-link" aria-label="Direct link to Solution C: Multi-File Sequence" title="Direct link to Solution C: Multi-File Sequence" translate="no">​</a></h4>
<p>Change the approach: save the processed images as a sequence of JPEG files:</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"># Python side</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">cv2</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">imwrite</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string-interpolation string" style="color:#e3116c">f'/dev/shm/gesture_frames/frame_</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">{</span><span class="token string-interpolation interpolation">frame_index</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">:</span><span class="token string-interpolation interpolation format-spec">03d</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">}</span><span class="token string-interpolation string" style="color:#e3116c">.jpg'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> processed</span><span class="token punctuation" style="color:#393A34">)</span><br></div></code></pre></div></div>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain"># GStreamer side</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">gst-launch-1.0 multifilesrc location=frame_%03d.jpg loop=true ! jpegdec ! ...</span><br></div></code></pre></div></div>
<p><strong>Result</strong>: The screen finally showed some movement - I was thrilled! But the effect was poor, with severe ghosting, and because it was reading the folder's images in a loop, it kept looping the playback, which hurt both the appearance and the experience. So I decided to leverage the FIFO and, building on the previous idea, upgrade it to the current solution:</p>
<p><strong>OpenCV finishes processing a frame -&gt; immediately encodes it as JPEG -&gt; writes directly into the FIFO -&gt; GStreamer immediately decodes and displays it</strong></p>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="solution-d-fifo--jpeg-stream-final-solution">Solution D: FIFO + JPEG Stream (Final Solution!)<a href="https://zephyr.100ask.org/en/blog/opencv-cpu-gesture#solution-d-fifo--jpeg-stream-final-solution" class="hash-link" aria-label="Direct link to Solution D: FIFO + JPEG Stream (Final Solution!)" title="Direct link to Solution D: FIFO + JPEG Stream (Final Solution!)" translate="no">​</a></h4>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"># Python side: write JPEG data directly into the FIFO</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">fifo </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token builtin">open</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'/tmp/gesture_fifo'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'wb'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">_</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> jpeg </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> cv2</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">imencode</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'.jpg'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> processed</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">cv2</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">IMWRITE_JPEG_QUALITY</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">85</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">fifo</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">write</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">jpeg</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">tobytes</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">fifo</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">flush</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><br></div></code></pre></div></div>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain"># GStreamer side: use jpegparse to automatically split JPEG frames</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">gst-launch-1.0 filesrc location=/tmp/gesture_fifo ! jpegparse ! jpegdec ! ...</span><br></div></code></pre></div></div>
<p><strong>Supplement: Why does the JPEG stream work?</strong></p>
<ol>
<li class="">The JPEG format has built-in start (0xFFD8) and end (0xFFD9) markers</li>
<li class="">GStreamer's <code>jpegparse</code> plugin can automatically recognize boundaries and split independent JPEG frames</li>
<li class="">It avoids the packet-sticking problem of raw data streams</li>
</ol>
<p><strong>Result</strong>: At last I could observe the picture smoothly (the pipeline did not stutter - it was even smoother than directly opening the camera icon on the screen to view the camera feed). I will put the demo video and code in the attachments.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="bonus---the-cameras-second-launch-was-greenish-and-dark">Bonus - The Camera's Second Launch Was Greenish and Dark<a href="https://zephyr.100ask.org/en/blog/opencv-cpu-gesture#bonus---the-cameras-second-launch-was-greenish-and-dark" class="hash-link" aria-label="Direct link to Bonus - The Camera's Second Launch Was Greenish and Dark" title="Direct link to Bonus - The Camera's Second Launch Was Greenish and Dark" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="problem-description">Problem Description<a href="https://zephyr.100ask.org/en/blog/opencv-cpu-gesture#problem-description" class="hash-link" aria-label="Direct link to Problem Description" title="Direct link to Problem Description" translate="no">​</a></h3>
<p>I used the IMX415 camera on the RK3576 Buildroot system and displayed the picture through GStreamer + Wayland. I ran into a bizarre issue: <strong>the first time the camera was started the colors were normal, but after the second start the picture became dark and greenish</strong>.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="preliminary-analysis-comparing-the-boot-logs">Preliminary Analysis: Comparing the Boot Logs<a href="https://zephyr.100ask.org/en/blog/opencv-cpu-gesture#preliminary-analysis-comparing-the-boot-logs" class="hash-link" aria-label="Direct link to Preliminary Analysis: Comparing the Boot Logs" title="Direct link to Preliminary Analysis: Comparing the Boot Logs" translate="no">​</a></h3>
<p>First I compared the kernel logs of the two launches and found a key difference:</p>
<p><strong>First launch (normal colors)</strong>:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">[20.528641] rkisp_hw 27c00000.isp: set isp clk = 594000000Hz</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[20.529097] rkcif-mipi-lvds 3: stream[0] start streaming</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[20.529317] rockchip-csi2-dphy 3: dphy3, data_rate_mbps 892</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[20.529356] imx415 3-0037: s_stream: 1.3864x2192, hdr: 0, bpp: 10</span><br></div></code></pre></div></div>
<p><strong>Second launch (abnormal colors)</strong>:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">[79.209321] rkisp_hw 27c00000.isp: set isp clk = 594000000Hz</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[79.209967] rkisp rkisp-vir3: first params buf queue</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[79.210051] rkisp rkisp-vir3: id: 0 no first iq setting cfg_upd: c000dfecc7fe473b en_upd: 0 en s: 5ffcc7fe473b</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[79.210351] rkcif-mipi-lvds 3: stream[0] start streaming</span><br></div></code></pre></div></div>
<p>Key finding: <strong>the second launch had one extra warning</strong> <code>no first iq setting</code>. This indicates that the ISP's image quality parameters were not loaded correctly, causing wrong default parameters to be used, which made the colors dark and greenish.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="problem-solving-process">Problem-Solving Process<a href="https://zephyr.100ask.org/en/blog/opencv-cpu-gesture#problem-solving-process" class="hash-link" aria-label="Direct link to Problem-Solving Process" title="Direct link to Problem-Solving Process" translate="no">​</a></h3>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="phase-1-attempting-a-hardware-level-fix">Phase 1: Attempting a Hardware-level Fix<a href="https://zephyr.100ask.org/en/blog/opencv-cpu-gesture#phase-1-attempting-a-hardware-level-fix" class="hash-link" aria-label="Direct link to Phase 1: Attempting a Hardware-level Fix" title="Direct link to Phase 1: Attempting a Hardware-level Fix" translate="no">​</a></h4>
<p>At first I thought the ISP driver state had not been reset correctly, and tried several methods:</p>
<ol>
<li class="">
<p><strong>Attempt to unbind/bind the ISP driver</strong>:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">echo "27c00000.isp" &gt; /sys/bus/platform/drivers/rkisp_hw/unbind</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">echo "27c00000.isp" &gt; /sys/bus/platform/drivers/rkisp_hw/bind</span><br></div></code></pre></div></div>
<p>Result: <strong>the camera could not be opened at all</strong> - the operation was too aggressive and completely messed up the driver state.</p>
</li>
<li class="">
<p><strong>Tried v4l2-ctl reset, media-ctl reset, etc.</strong>, but none of them solved the problem.</p>
</li>
</ol>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="phase-2-in-depth-diagnosis-of-the-system-configuration">Phase 2: In-Depth Diagnosis of the System Configuration<a href="https://zephyr.100ask.org/en/blog/opencv-cpu-gesture#phase-2-in-depth-diagnosis-of-the-system-configuration" class="hash-link" aria-label="Direct link to Phase 2: In-Depth Diagnosis of the System Configuration" title="Direct link to Phase 2: In-Depth Diagnosis of the System Configuration" translate="no">​</a></h4>
<p>I began systematically diagnosing the entire camera subsystem:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain"># Find the IQ parameter file</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">find / -name "*imx415*.xml" -o -name "*imx415*.json" 2&gt;/dev/null</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># Result: found /etc/iqfiles/imx415_CMK-OT2022-PX1_IR0147-50IRC-8M-F20.json</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># Check the 3A server</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">ps aux | grep rkaiq_3A_server</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># Result: the server is running</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># View device topology</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">v4l2-ctl --list-devices</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># Confirm /dev/video-camera0 -&gt; video11</span><br></div></code></pre></div></div>
<p><strong>Key findings</strong>:</p>
<ul>
<li class="">The IQ parameter file exists</li>
<li class="">The 3A server (rkaiq_3A_server) is running</li>
<li class="">But why were the IQ parameters not loaded?</li>
</ul>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="phase-3-capturing-the-3a-server-log">Phase 3: Capturing the 3A Server Log<a href="https://zephyr.100ask.org/en/blog/opencv-cpu-gesture#phase-3-capturing-the-3a-server-log" class="hash-link" aria-label="Direct link to Phase 3: Capturing the 3A Server Log" title="Direct link to Phase 3: Capturing the 3A Server Log" translate="no">​</a></h4>
<p>I decided to run the 3A server in the foreground to view detailed output:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">killall rkaiq_3A_server</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">/usr/bin/rkaiq_3A_server 2&gt;&amp;1 &amp;</span><br></div></code></pre></div></div>
<p>The startup log showed:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">DBG: get rkisp-isp-subdev devname: /dev/v4l-subdev3</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">DBG: get rkisp-input-params devname: /dev/video18</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">DBG: get rkisp-statistics devname: /dev/video17</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">XCORE: K: cid[1] rk_aiq_uapi2_sysctl_init success. iq: /etc/iqfiles//imx415_CMK-OT2022-PX1_IR0147-50IRC-8M-F20.json</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">XCORE: K: cid[1] rk_aiq_uapi2_sysctl_prepare success. mode: 0</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">DBG: /dev/media1: wait stream start event..</span><br></div></code></pre></div></div>
<p><strong>Major finding</strong>: the 3A server was actually working fine! The IQ file had been loaded successfully!</p>
<p>At this point I ran a second camera launch test and observed:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">[625.216117] rkisp-vir3: waiting on params stream one event timeout</span><br></div></code></pre></div></div>
<p><strong>The truth came out</strong>: on the second launch, the 3A server timed out and did not respond!</p>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="phase-4-finding-the-root-cause">Phase 4: Finding the Root Cause<a href="https://zephyr.100ask.org/en/blog/opencv-cpu-gesture#phase-4-finding-the-root-cause" class="hash-link" aria-label="Direct link to Phase 4: Finding the Root Cause" title="Direct link to Phase 4: Finding the Root Cause" translate="no">​</a></h4>
<p>Through multiple tests and log analysis, I finally understood the nature of the problem:</p>
<p><strong>First launch flow (normal)</strong>:</p>
<ol>
<li class="">When the system boots, the 3A server starts automatically</li>
<li class="">The 3A server loads the IQ parameter file into memory</li>
<li class="">The 3A server pre-prepares the IQ parameter buffer</li>
<li class="">GStreamer starts the camera</li>
<li class="">The ISP requests IQ parameters</li>
<li class="">The 3A server responds immediately and pushes the IQ parameters</li>
<li class="">Colors are normal</li>
</ol>
<p><strong>Second launch flow (abnormal)</strong>:</p>
<ol>
<li class="">Stop the first GStreamer process</li>
<li class="">The 3A server is still running, but has entered some waiting state</li>
<li class="">The IQ parameter buffer has already been consumed</li>
<li class="">GStreamer is restarted immediately</li>
<li class="">The ISP requests IQ parameters</li>
<li class=""><strong>The 3A server cannot respond in time or is in an abnormal state</strong></li>
<li class="">The ISP uses default parameters to process the first frame</li>
<li class="">The <code>no first iq setting</code> warning appears</li>
<li class="">Colors are dark and greenish</li>
</ol>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="solution">Solution<a href="https://zephyr.100ask.org/en/blog/opencv-cpu-gesture#solution" class="hash-link" aria-label="Direct link to Solution" title="Direct link to Solution" translate="no">​</a></h3>
<p>The root cause of the problem is: <strong>after the camera's first run, the 3A server enters an abnormal state and cannot correctly respond to the IQ parameter request of the second launch</strong>.</p>
<p>The final fix is simple: <strong>restart the 3A server before each camera launch</strong>.</p>
<p>I wrote a wrapper script:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">#!/bin/sh</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">echo "=== Starting Camera with 3A Server Reset ==="</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 1. Stop all camera processes</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">pkill -9 gst-launch 2&gt;/dev/null</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 2. Restart the 3A server</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">killall rkaiq_3A_server 2&gt;/dev/null</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sleep 2</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">rm -f /tmp/.rkaiq_3A*</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 3. Start the 3A server</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">/etc/init.d/S40rkaiq_3A start</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">echo "Waiting for 3A server to initialize..."</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sleep 5</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 4. Confirm the 3A server is running normally</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">if ! pgrep rkaiq_3A_server &gt; /dev/null; then</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    echo "ERROR: 3A server failed to start!"</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    exit 1</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">fi</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">echo "3A server ready, starting camera..."</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 5. Start the camera</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">gst-launch-1.0 v4l2src device=/dev/video11 ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    video/x-raw,format=NV12,width=640,height=480,framerate=30/1 ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    waylandsink</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">echo "Camera stopped"</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">exit 0</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="verification-result">Verification Result<a href="https://zephyr.100ask.org/en/blog/opencv-cpu-gesture#verification-result" class="hash-link" aria-label="Direct link to Verification Result" title="Direct link to Verification Result" translate="no">​</a></h3>
<p>After using the new script, I started the camera several times in a row and the colors were always normal; the log no longer showed <code>no first iq setting</code> or timeout errors.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="lessons-learned">Lessons Learned<a href="https://zephyr.100ask.org/en/blog/opencv-cpu-gesture#lessons-learned" class="hash-link" aria-label="Direct link to Lessons Learned" title="Direct link to Lessons Learned" translate="no">​</a></h3>
<ol>
<li class="">
<p><strong>Comparing logs is key to discovering problems</strong>: by comparing the logs of the normal and abnormal cases, I quickly located the key clue <code>no first iq setting</code></p>
</li>
<li class="">
<p><strong>Diagnose systematically</strong>: do not blindly try things; first check the state of each component (IQ file, 3A server, device node)</p>
</li>
<li class="">
<p><strong>Run in the foreground to see detailed logs</strong>: many background-service problems require foreground execution to see detailed output</p>
</li>
<li class="">
<p><strong>Understand the cooperation between components</strong>: the RK platform's camera involves cooperation among the ISP driver, the 3A server, and the IQ parameter file - a problem in any link will cause an anomaly</p>
</li>
<li class="">
<p><strong>State management matters</strong>: embedded-system service-restart problems are often caused by improper state-machine management; a thorough reset is the most reliable solution.</p>
</li>
</ol>]]></content:encoded>
            <category>OpenCV</category>
            <category>Gesture Recognition</category>
            <category>CPU Inference</category>
            <category>RK3576</category>
        </item>
        <item>
            <title><![CDATA[DshanPI-A1 Review Part 2: Gesture Recognition Programming Environment Setup and Screen Debugging]]></title>
            <link>https://zephyr.100ask.org/en/blog/gesture-env-screen</link>
            <guid>https://zephyr.100ask.org/en/blog/gesture-env-screen</guid>
            <pubDate>Sat, 22 Nov 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[Install the necessary tools for a gesture recognition system and complete screen debugging, laying the groundwork for subsequent gesture recognition practice.]]></description>
            <content:encoded><![CDATA[<p>In this review, I will install the necessary tools for the gesture recognition system and debug the screen.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="hardware-and-environment-preparation">Hardware and Environment Preparation<a href="https://zephyr.100ask.org/en/blog/gesture-env-screen#hardware-and-environment-preparation" class="hash-link" aria-label="Direct link to Hardware and Environment Preparation" title="Direct link to Hardware and Environment Preparation" translate="no">​</a></h2>
<p>Before starting, let's clarify the equipment and environment on hand:</p>
<ul>
<li class="">
<p><strong>Core board</strong>: Dshanpi-A1, with the Rockchip RK3576 chip as the main SoC.</p>
</li>
<li class="">
<p><strong>Screen</strong>: A 480x800 resolution MIPI screen.</p>
</li>
<li class="">
<p><strong>System</strong>: Buildroot Linux system.</p>
</li>
<li class="">
<p><strong>Official SDK</strong></p>
</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="install-development-tools">Install Development Tools<a href="https://zephyr.100ask.org/en/blog/gesture-env-screen#install-development-tools" class="hash-link" aria-label="Direct link to Install Development Tools" title="Direct link to Install Development Tools" translate="no">​</a></h2>
<p>Here is the list for this time:</p>
<table><thead><tr><th>Package/Configuration Category</th><th>Recommended Options and Purpose</th></tr></thead><tbody><tr><td>Python Environment</td><td>python3: Core interpreter. python-pip: Used to install Python packages not included in Buildroot. python-numpy: Provides efficient numerical computation support for OpenCV and other libraries. python-setuptools: A base build dependency for some Python packages.</td></tr><tr><td>Computer Vision and Image Processing</td><td>opencv4: Be sure to enable python3 support. Provides the core computer vision library for image processing and gesture recognition algorithms. opencv4 contrib modules: Includes additional, more advanced algorithms.</td></tr><tr><td>Camera and Display Support</td><td>gstreamer1 and related plugins: Build pipelines for camera image capture and screen display. gst1-plugins-base, gst1-plugins-good, gst1-plugins-bad, gst1-plugins-ugly: Provide a rich set of codecs and functional elements. gst1-python: Allows creating and manipulating GStreamer pipelines in Python.</td></tr></tbody></table>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="sdk-configuration-process">SDK Configuration Process<a href="https://zephyr.100ask.org/en/blog/gesture-env-screen#sdk-configuration-process" class="hash-link" aria-label="Direct link to SDK Configuration Process" title="Direct link to SDK Configuration Process" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="1-select-the-chip-type">1. Select the Chip Type<a href="https://zephyr.100ask.org/en/blog/gesture-env-screen#1-select-the-chip-type" class="hash-link" aria-label="Direct link to 1. Select the Chip Type" title="Direct link to 1. Select the Chip Type" translate="no">​</a></h3>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">./build.sh chip</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="2-enter-buildroot-configuration">2. Enter buildroot Configuration<a href="https://zephyr.100ask.org/en/blog/gesture-env-screen#2-enter-buildroot-configuration" class="hash-link" aria-label="Direct link to 2. Enter buildroot Configuration" title="Direct link to 2. Enter buildroot Configuration" translate="no">​</a></h3>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">cd buildroot</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">make menuconfig</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="3-select-target-packages">3. Select Target packages<a href="https://zephyr.100ask.org/en/blog/gesture-env-screen#3-select-target-packages" class="hash-link" aria-label="Direct link to 3. Select Target packages" title="Direct link to 3. Select Target packages" translate="no">​</a></h3>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="4-install-the-python-environment">4. Install the Python Environment<a href="https://zephyr.100ask.org/en/blog/gesture-env-screen#4-install-the-python-environment" class="hash-link" aria-label="Direct link to 4. Install the Python Environment" title="Direct link to 4. Install the Python Environment" translate="no">​</a></h3>
<p>When you cannot find the installation path, press the <code>/</code> key to search:</p>
<p>Enter <code>python3</code> to search:</p>
<p>Enter the displayed Location path to configure:</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="5-save-the-configuration-and-build">5. Save the Configuration and Build<a href="https://zephyr.100ask.org/en/blog/gesture-env-screen#5-save-the-configuration-and-build" class="hash-link" aria-label="Direct link to 5. Save the Configuration and Build" title="Direct link to 5. Save the Configuration and Build" translate="no">​</a></h3>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">make</span><br></div></code></pre></div></div>
<p>Return to the SDK main directory and run:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">./build.sh rootfs</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">./build.sh updateimg</span><br></div></code></pre></div></div>
<p>Finally, flash and run it on the development board.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="development-board-debugging">Development Board Debugging<a href="https://zephyr.100ask.org/en/blog/gesture-env-screen#development-board-debugging" class="hash-link" aria-label="Direct link to Development Board Debugging" title="Direct link to Development Board Debugging" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="check-tool-installation">Check Tool Installation<a href="https://zephyr.100ask.org/en/blog/gesture-env-screen#check-tool-installation" class="hash-link" aria-label="Direct link to Check Tool Installation" title="Direct link to Check Tool Installation" translate="no">​</a></h3>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">python3 --version</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">pip3 --version</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">python3 -c "import numpy; print('NumPy version:', numpy.__version__)"</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">python3 -c "import cv2; print('OpenCV version:', cv2.__version__)"</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="screen-debugging">Screen Debugging<a href="https://zephyr.100ask.org/en/blog/gesture-env-screen#screen-debugging" class="hash-link" aria-label="Direct link to Screen Debugging" title="Direct link to Screen Debugging" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="problem-analysis">Problem Analysis<a href="https://zephyr.100ask.org/en/blog/gesture-env-screen#problem-analysis" class="hash-link" aria-label="Direct link to Problem Analysis" title="Direct link to Problem Analysis" translate="no">​</a></h3>
<p>The system is already running the Weston compositor, which means we have a graphical interface environment. Attempting to directly operate the FrameBuffer (/dev/fb0) is ineffective because Weston has already occupied the display interface.</p>
<p>Through system inspection, we found:</p>
<ul>
<li class="">The <code>/dev/fb0</code> device exists</li>
<li class="">The screen status is <code>connected</code></li>
<li class="">The resolution is 480x800</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="solution-gstreamer--wayland">Solution: GStreamer + Wayland<a href="https://zephyr.100ask.org/en/blog/gesture-env-screen#solution-gstreamer--wayland" class="hash-link" aria-label="Direct link to Solution: GStreamer + Wayland" title="Direct link to Solution: GStreamer + Wayland" translate="no">​</a></h3>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="gstreamer-basic-test">GStreamer Basic Test<a href="https://zephyr.100ask.org/en/blog/gesture-env-screen#gstreamer-basic-test" class="hash-link" aria-label="Direct link to GStreamer Basic Test" title="Direct link to GStreamer Basic Test" translate="no">​</a></h4>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">gst-launch-1.0 videotestsrc pattern=smpte ! video/x-raw,width=480,height=800 ! waylandsink sync=false</span><br></div></code></pre></div></div>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="camera-direct-to-display-test">Camera Direct-to-Display Test<a href="https://zephyr.100ask.org/en/blog/gesture-env-screen#camera-direct-to-display-test" class="hash-link" aria-label="Direct link to Camera Direct-to-Display Test" title="Direct link to Camera Direct-to-Display Test" translate="no">​</a></h4>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">gst-launch-1.0 v4l2src device=/dev/video11 ! video/x-raw,width=640,height=480 ! videoconvert ! waylandsink sync=false</span><br></div></code></pre></div></div>
<blockquote>
<p>Note: Please replace the device parameter with your camera's device node</p>
</blockquote>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="test-script">Test Script<a href="https://zephyr.100ask.org/en/blog/gesture-env-screen#test-script" class="hash-link" aria-label="Direct link to Test Script" title="Direct link to Test Script" translate="no">​</a></h3>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">#!/usr/bin/env python3</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># fixed_display_test.py</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> subprocess</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> time</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> os</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">def</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">check_camera_devices</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token triple-quoted-string string" style="color:#e3116c">"""Check available camera devices"""</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">print</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"=== Camera Device Check ==="</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">try</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic"># Use v4l2-ctl to check devices</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        result </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> subprocess</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">run</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">"v4l2-ctl"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"--list-devices"</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                        capture_output</span><span class="token operator" style="color:#393A34">=</span><span class="token boolean" style="color:#36acaa">True</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> text</span><span class="token operator" style="color:#393A34">=</span><span class="token boolean" style="color:#36acaa">True</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> result</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">returncode </span><span class="token operator" style="color:#393A34">==</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">print</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"Found video devices:"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain">n            </span><span class="token keyword" style="color:#00009f">print</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">result</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">stdout</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">else</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">print</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"v4l2-ctl command execution failed"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">except</span><span class="token plain"> Exception </span><span class="token keyword" style="color:#00009f">as</span><span class="token plain"> e</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">print</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string-interpolation string" style="color:#e3116c">f"Failed to check camera devices: </span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">{</span><span class="token string-interpolation interpolation">e</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">}</span><span class="token string-interpolation string" style="color:#e3116c">"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic"># Test common camera devices</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    camera_devices </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">"/dev/video11"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"/dev/video0"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"/dev/video1"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"/dev/video2"</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">print</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"\nTesting camera devices:"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">for</span><span class="token plain"> device </span><span class="token keyword" style="color:#00009f">in</span><span class="token plain"> camera_devices</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> os</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">path</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">exists</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">device</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">print</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string-interpolation string" style="color:#e3116c">f"Testing device: </span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">{</span><span class="token string-interpolation interpolation">device</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">}</span><span class="token string-interpolation string" style="color:#e3116c">"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">try</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token comment" style="color:#999988;font-style:italic"># Try to test the camera using GStreamer</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                cmd </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                  </span><span class="token string" style="color:#e3116c">"gst-launch-1.0"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                  </span><span class="token string" style="color:#e3116c">"-v"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                  </span><span class="token string" style="color:#e3116c">"v4l2src"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string-interpolation string" style="color:#e3116c">f"device=</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">{</span><span class="token string-interpolation interpolation">device</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">}</span><span class="token string-interpolation string" style="color:#e3116c">"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"!"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                  </span><span class="token string" style="color:#e3116c">"video/x-raw,width=640,height=480,framerate=15/1"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"!"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                  </span><span class="token string" style="color:#e3116c">"videoconvert"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"!"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                  </span><span class="token string" style="color:#e3116c">"waylandsink"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"sync=false"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                process </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> subprocess</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Popen</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">cmd</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                time</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">sleep</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">3</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic"># Display for 3 seconds</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                process</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">terminate</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                process</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">wait</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token keyword" style="color:#00009f">print</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string-interpolation string" style="color:#e3116c">f" </span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">{</span><span class="token string-interpolation interpolation">device</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">}</span><span class="token string-interpolation string" style="color:#e3116c">: Camera working normally"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> device</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">except</span><span class="token plain"> Exception </span><span class="token keyword" style="color:#00009f">as</span><span class="token plain"> e</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token keyword" style="color:#00009f">print</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string-interpolation string" style="color:#e3116c">f"</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">{</span><span class="token string-interpolation interpolation">device</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">}</span><span class="token string-interpolation string" style="color:#e3116c">: Test failed - </span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">{</span><span class="token string-interpolation interpolation">e</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">}</span><span class="token string-interpolation string" style="color:#e3116c">"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">else</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">print</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string-interpolation string" style="color:#e3116c">f"</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">{</span><span class="token string-interpolation interpolation">device</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">}</span><span class="token string-interpolation string" style="color:#e3116c">: Device does not exist"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">None</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">def</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">test_static_patterns</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token triple-quoted-string string" style="color:#e3116c">"""Test static patterns (will not change)"""</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">print</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"\n=== Static Pattern Test ==="</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic"># Set Wayland environment</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    os</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">environ</span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">'WAYLAND_DISPLAY'</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'wayland-0'</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic"># Test static patterns (will not change)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    static_patterns </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"smpte100"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"SMPTE 100% color bars"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"ball"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Clock pattern"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"blink"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Blink pattern"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"pinwheel"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Pinwheel pattern"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"spokes"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Spokes pattern"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">for</span><span class="token plain"> pattern</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> description </span><span class="token keyword" style="color:#00009f">in</span><span class="token plain"> static_patterns</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">print</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string-interpolation string" style="color:#e3116c">f"Displaying: </span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">{</span><span class="token string-interpolation interpolation">description</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">}</span><span class="token string-interpolation string" style="color:#e3116c">"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">try</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            cmd </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token string" style="color:#e3116c">"gst-launch-1.0"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token string" style="color:#e3116c">"videotestsrc"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string-interpolation string" style="color:#e3116c">f"pattern=</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">{</span><span class="token string-interpolation interpolation">pattern</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">}</span><span class="token string-interpolation string" style="color:#e3116c">"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"!"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token string" style="color:#e3116c">"video/x-raw,width=480,height=800,framerate=15/1"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"!"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token string" style="color:#e3116c">"waylandsink"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"sync=false"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            process </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> subprocess</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Popen</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">cmd</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            time</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">sleep</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">3</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            process</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">terminate</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            process</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">wait</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">print</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string-interpolation string" style="color:#e3116c">f"</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">{</span><span class="token string-interpolation interpolation">description</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">}</span><span class="token string-interpolation string" style="color:#e3116c"> displayed successfully"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">except</span><span class="token plain"> Exception </span><span class="token keyword" style="color:#00009f">as</span><span class="token plain"> e</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">print</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string-interpolation string" style="color:#e3116c">f"</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">{</span><span class="token string-interpolation interpolation">description</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">}</span><span class="token string-interpolation string" style="color:#e3116c"> display failed: </span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">{</span><span class="token string-interpolation interpolation">e</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">}</span><span class="token string-interpolation string" style="color:#e3116c">"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">def</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">test_custom_resolution</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token triple-quoted-string string" style="color:#e3116c">"""Test custom resolution display"""</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">print</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"\n=== Custom Resolution Test ==="</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    resolutions </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">480</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">800</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Portrait 480x800"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">800</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">480</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Landscape 800x480"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">640</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">480</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Standard 640x480"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">400</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">800</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Portrait 400x800"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">for</span><span class="token plain"> width</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> height</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> desc </span><span class="token keyword" style="color:#00009f">in</span><span class="token plain"> resolutions</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">print</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string-interpolation string" style="color:#e3116c">f"Testing resolution: </span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">{</span><span class="token string-interpolation interpolation">desc</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">}</span><span class="token string-interpolation string" style="color:#e3116c">"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">try</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            cmd </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token string" style="color:#e3116c">"gst-launch-1.0"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token string" style="color:#e3116c">"videotestsrc"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"pattern=smpte100"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"!"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token string-interpolation string" style="color:#e3116c">f"video/x-raw,width=</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">{</span><span class="token string-interpolation interpolation">width</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">}</span><span class="token string-interpolation string" style="color:#e3116c">,height=</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">{</span><span class="token string-interpolation interpolation">height</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">}</span><span class="token string-interpolation string" style="color:#e3116c">,framerate=15/1"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"!"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token string" style="color:#e3116c">"videoconvert"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"!"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token string" style="color:#e3116c">"waylandsink"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"sync=false"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            process </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> subprocess</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Popen</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">cmd</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            time</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">sleep</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">2</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            process</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">terminate</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            process</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">wait</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">print</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string-interpolation string" style="color:#e3116c">f" </span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">{</span><span class="token string-interpolation interpolation">desc</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">}</span><span class="token string-interpolation string" style="color:#e3116c"> displayed successfully"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">except</span><span class="token plain"> Exception </span><span class="token keyword" style="color:#00009f">as</span><span class="token plain"> e</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">print</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string-interpolation string" style="color:#e3116c">f" </span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">{</span><span class="token string-interpolation interpolation">desc</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">}</span><span class="token string-interpolation string" style="color:#e3116c"> display failed: </span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">{</span><span class="token string-interpolation interpolation">e</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">}</span><span class="token string-interpolation string" style="color:#e3116c">"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> __name__ </span><span class="token operator" style="color:#393A34">==</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"__main__"</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">print</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"="</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">50</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic"># 1. Check camera</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    camera_device </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> check_camera_devices</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic"># 2. Test static patterns</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    test_static_patterns</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic"># 3. Test different resolutions</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    test_custom_resolution</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">print</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"\n"</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"="</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">50</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> camera_device</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">print</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string-interpolation string" style="color:#e3116c">f"Available camera device: </span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">{</span><span class="token string-interpolation interpolation">camera_device</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">}</span><span class="token string-interpolation string" style="color:#e3116c">"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">else</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">print</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"No available camera device found"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">print</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"All tests completed"</span><span class="token punctuation" style="color:#393A34">)</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="run-results">Run Results<a href="https://zephyr.100ask.org/en/blog/gesture-env-screen#run-results" class="hash-link" aria-label="Direct link to Run Results" title="Direct link to Run Results" translate="no">​</a></h3>
<blockquote>
<p>I will put the demo video in the attachments</p>
</blockquote>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="bonus-chapter-filezilla-file-transfer">Bonus Chapter: FileZilla File Transfer<a href="https://zephyr.100ask.org/en/blog/gesture-env-screen#bonus-chapter-filezilla-file-transfer" class="hash-link" aria-label="Direct link to Bonus Chapter: FileZilla File Transfer" title="Direct link to Bonus Chapter: FileZilla File Transfer" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="filezilla-connection-settings">FileZilla Connection Settings<a href="https://zephyr.100ask.org/en/blog/gesture-env-screen#filezilla-connection-settings" class="hash-link" aria-label="Direct link to FileZilla Connection Settings" title="Direct link to FileZilla Connection Settings" translate="no">​</a></h3>
<p><a href="https://filezilla-project.org/" target="_blank" rel="noopener noreferrer" class="">FileZilla - The free FTP solution</a></p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="check-ssh-service">Check SSH Service<a href="https://zephyr.100ask.org/en/blog/gesture-env-screen#check-ssh-service" class="hash-link" aria-label="Direct link to Check SSH Service" title="Direct link to Check SSH Service" translate="no">​</a></h3>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">ss -tuln | grep 22</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="network-sharing-settings">Network Sharing Settings<a href="https://zephyr.100ask.org/en/blog/gesture-env-screen#network-sharing-settings" class="hash-link" aria-label="Direct link to Network Sharing Settings" title="Direct link to Network Sharing Settings" translate="no">​</a></h3>
<p>Select the network that can access the internet, and click Properties:</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="connect-to-the-development-board">Connect to the Development Board<a href="https://zephyr.100ask.org/en/blog/gesture-env-screen#connect-to-the-development-board" class="hash-link" aria-label="Direct link to Connect to the Development Board" title="Direct link to Connect to the Development Board" translate="no">​</a></h3>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">ifconfig</span><br></div></code></pre></div></div>
<p>Connect using FileZilla:</p>
<ul>
<li class="">IP: Development board IP address</li>
<li class="">Username: root</li>
<li class="">Password: rockchip</li>
<li class="">Port: 22</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="summary">Summary<a href="https://zephyr.100ask.org/en/blog/gesture-env-screen#summary" class="hash-link" aria-label="Direct link to Summary" title="Direct link to Summary" translate="no">​</a></h2>
<p>Looking back at the entire debugging process, the following key points are worth special attention:</p>
<ol>
<li class="">
<p><strong>Display Path Selection</strong>: On systems running a compositor such as Weston, prioritize the GStreamer + waylandsink solution for displaying images, rather than directly operating the FrameBuffer.</p>
</li>
<li class="">
<p><strong>Camera Device Node</strong>: Be sure to use the <code>v4l2-ctl --list-devices</code> command to confirm the device node corresponding to the camera, and specify it correctly in the code.</p>
</li>
<li class="">
<p><strong>Screen Resolution</strong>: Note that the screen resolution detected by the system (which can be queried via <code>cat /sys/class/drm/card0-DSI-1/modes</code>) may be slightly different from the physical resolution. When creating display frames, use this as the reference or make adjustments accordingly.</p>
</li>
</ol>
<p>At this point, we have successfully set up the gesture recognition programming environment on the Dshanpi A1 development board and resolved the display issues with the MIPI screen and camera. Although the process was full of twists and turns, it laid a solid foundation for the subsequent actual writing of gesture recognition algorithms. I hope my experience can be of help to everyone!</p>]]></content:encoded>
            <category>Gesture Recognition</category>
            <category>Screen</category>
            <category>RK3576</category>
        </item>
        <item>
            <title><![CDATA[DshanPI-A1 Review Part 1: Building the buildroot System and Debugging the IMX415 Camera]]></title>
            <link>https://zephyr.100ask.org/en/blog/buildroot-imx415-camera</link>
            <guid>https://zephyr.100ask.org/en/blog/buildroot-imx415-camera</guid>
            <pubDate>Thu, 20 Nov 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[Build a buildroot system on the RK3576-based DshanPi-A1, debug the IMX415 camera, and solve common issues.]]></description>
            <content:encoded><![CDATA[<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="board-introduction">Board Introduction<a href="https://zephyr.100ask.org/en/blog/buildroot-imx415-camera#board-introduction" class="hash-link" aria-label="Direct link to Board Introduction" title="Direct link to Board Introduction" translate="no">​</a></h2>
<p>DshanPi-A1 is a high-performance AI embedded development board developed by Shenzhen Baiwen Web (Weidongshan Team). It is based on the Rockchip RK3576 chip and is designed specifically for AI education, edge computing, and smart device development.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="core-specifications">Core Specifications<a href="https://zephyr.100ask.org/en/blog/buildroot-imx415-camera#core-specifications" class="hash-link" aria-label="Direct link to Core Specifications" title="Direct link to Core Specifications" translate="no">​</a></h2>
<table><thead><tr><th>Parameter</th><th>Specification</th></tr></thead><tbody><tr><td>Main SoC</td><td>Rockchip RK3576, 8nm process, octa-core 64-bit 4×Cortex-A72(2.2GHz)+4×Cortex-A53(1.8GHz) Rockchip Electronics Co., Ltd.</td></tr><tr><td>AI Compute</td><td>Built-in dedicated NPU, 6TOPS compute capability, supports INT4/INT8/INT16 mixed-precision operations</td></tr><tr><td>Memory/Storage</td><td>Onboard LPDDR4/4X memory, supports eMMC and UFS storage expansion, SD card slot</td></tr><tr><td>Display Interface</td><td>HDMI v2.1/eDP v1.3 combo interface, MIPI DSI (4-lane) Rockchip Electronics Co., Ltd.</td></tr><tr><td>Video Decoding</td><td>Supports 8K@30fps, 4K@120fps high-definition video</td></tr><tr><td>Network Connectivity</td><td>Supports WiFi6/BLE5.2 (requires external module), Gigabit Ethernet port (some versions)</td></tr><tr><td>USB Interface</td><td>Multiple USB3.0/2.0 (Type-C and Type-A) Rockchip Electronics Co., Ltd.</td></tr><tr><td>Other Interfaces</td><td>UART, I2C, SPI, GPIO, audio interface, CAN bus (some versions)</td></tr><tr><td>Power</td><td>Supports 30W PD fast charging (Type-C interface)</td></tr><tr><td>Dimensions</td><td>Compact design (specific dimensions not publicly disclosed)</td></tr></tbody></table>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="product-features">Product Features<a href="https://zephyr.100ask.org/en/blog/buildroot-imx415-camera#product-features" class="hash-link" aria-label="Direct link to Product Features" title="Direct link to Product Features" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="1️⃣-powerful-ai-processing-capability">1️⃣ Powerful AI Processing Capability<a href="https://zephyr.100ask.org/en/blog/buildroot-imx415-camera#1%EF%B8%8F%E2%83%A3-powerful-ai-processing-capability" class="hash-link" aria-label="Direct link to 1️⃣ Powerful AI Processing Capability" title="Direct link to 1️⃣ Powerful AI Processing Capability" translate="no">​</a></h3>
<p>· 6TOPS dedicated NPU can smoothly run lightweight large language models such as DeepSeek and Qwen</p>
<p>· Supports mainstream AI frameworks (TensorFlow, PyTorch, MXNet, etc.)</p>
<p>· Suitable for AI application development such as image recognition, speech processing, and smart surveillance</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="2️⃣-rich-multimedia-performance">2️⃣ Rich Multimedia Performance<a href="https://zephyr.100ask.org/en/blog/buildroot-imx415-camera#2%EF%B8%8F%E2%83%A3-rich-multimedia-performance" class="hash-link" aria-label="Direct link to 2️⃣ Rich Multimedia Performance" title="Direct link to 2️⃣ Rich Multimedia Performance" translate="no">​</a></h3>
<p>· Supports 8K video decoding, can be used as an HD media center</p>
<p>· HDMI IN function allows the development board to be used as a secondary display for a PC</p>
<p>· Built-in audio codec, supports 3.5mm audio output</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="3️⃣-comprehensive-development-support">3️⃣ Comprehensive Development Support<a href="https://zephyr.100ask.org/en/blog/buildroot-imx415-camera#3%EF%B8%8F%E2%83%A3-comprehensive-development-support" class="hash-link" aria-label="Direct link to 3️⃣ Comprehensive Development Support" title="Direct link to 3️⃣ Comprehensive Development Support" translate="no">​</a></h3>
<p>· Ships with DShanOS (Baiwen Web's self-developed Linux distribution)</p>
<p>· Comes with free teaching courses and documentation, lowering the learning barrier</p>
<p>· Supports Armbian system, with official image downloads available</p>
<p>· Provides a complete SDK and sample code for easy secondary development</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="4️⃣-flexible-expansion-capability">4️⃣ Flexible Expansion Capability<a href="https://zephyr.100ask.org/en/blog/buildroot-imx415-camera#4%EF%B8%8F%E2%83%A3-flexible-expansion-capability" class="hash-link" aria-label="Direct link to 4️⃣ Flexible Expansion Capability" title="Direct link to 4️⃣ Flexible Expansion Capability" translate="no">​</a></h3>
<p>· All GPIO interfaces are exposed, making it easy to connect various sensors and actuators</p>
<p>· Supports multiple communication protocols, suitable for IoT application development</p>
<p>· Can connect external cameras, displays, WiFi/4G modules, and more to expand functionality</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="application-scenarios">Application Scenarios<a href="https://zephyr.100ask.org/en/blog/buildroot-imx415-camera#application-scenarios" class="hash-link" aria-label="Direct link to Application Scenarios" title="Direct link to Application Scenarios" translate="no">​</a></h2>
<p><strong>·</strong> AI Education and Learning: Suitable for embedded AI course teaching and experimentation</p>
<p><strong>·</strong> Edge Computing Devices: Can deploy lightweight AI models to enable local intelligent decision-making</p>
<p><strong>·</strong> Smart Home Hub: Build a high-performance, low-power smart home control center</p>
<p><strong>·</strong> Industrial Automation: Suitable for smart device monitoring and data acquisition</p>
<p><strong>·</strong> Commercial Display: Supports 8K display, can be used for advertising machines and information publishing systems</p>
<p><strong>·</strong> AI Vision Systems: Can be used for face recognition, object detection, and other scenarios</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="companion-resources">Companion Resources<a href="https://zephyr.100ask.org/en/blog/buildroot-imx415-camera#companion-resources" class="hash-link" aria-label="Direct link to Companion Resources" title="Direct link to Companion Resources" translate="no">​</a></h2>
<p><strong>·</strong> Official documentation site: <a href="https://wiki.dshanpi.org/docs/dshanpi-a1/" target="_blank" rel="noopener noreferrer" class="">https://wiki.dshanpi.org/docs/dshanpi-a1/</a></p>
<p><strong>·</strong> Developer community: Weidongshan Embedded Developer Community (<a href="https://100ask.org/" target="_blank" rel="noopener noreferrer" class="">100ask.org</a>)</p>
<p><strong>·</strong> QQ technical exchange group: 798273638</p>
<p><strong>·</strong> Free tutorials: Provides AI development courses from basic to advanced</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="buildroot-sdk-installation">buildroot SDK Installation<a href="https://zephyr.100ask.org/en/blog/buildroot-imx415-camera#buildroot-sdk-installation" class="hash-link" aria-label="Direct link to buildroot SDK Installation" title="Direct link to buildroot SDK Installation" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="1-obtain-the-official-virtual-machine">1. Obtain the Official Virtual Machine<a href="https://zephyr.100ask.org/en/blog/buildroot-imx415-camera#1-obtain-the-official-virtual-machine" class="hash-link" aria-label="Direct link to 1. Obtain the Official Virtual Machine" title="Direct link to 1. Obtain the Official Virtual Machine" translate="no">​</a></h3>
<p><a href="https://pan.baidu.com/s/15M8zuHOwl_SITl6cSk_7Vg?pwd=eaax" target="_blank" rel="noopener noreferrer" class="">https://pan.baidu.com/s/15M8zuHOwl_SITl6cSk_7Vg?pwd=eaax</a> Extraction code: eaax</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="2-install-and-open-vmware-run-the-virtual-machine">2. Install and open vmware, run the virtual machine<a href="https://zephyr.100ask.org/en/blog/buildroot-imx415-camera#2-install-and-open-vmware-run-the-virtual-machine" class="hash-link" aria-label="Direct link to 2. Install and open vmware, run the virtual machine" title="Direct link to 2. Install and open vmware, run the virtual machine" translate="no">​</a></h3>
<p>Enter the ubuntu system, the account password is ubuntu</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="3-build-the-sdk">3. Build the SDK<a href="https://zephyr.100ask.org/en/blog/buildroot-imx415-camera#3-build-the-sdk" class="hash-link" aria-label="Direct link to 3. Build the SDK" title="Direct link to 3. Build the SDK" translate="no">​</a></h3>
<p>Open the virtual machine and execute the following command to enter the SDK root directory:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">cd ~/100ask-rk3576_SDK/</span><br></div></code></pre></div></div>
<p>Select the configuration file:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">./build.sh lunch</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="4-build">4. Build<a href="https://zephyr.100ask.org/en/blog/buildroot-imx415-camera#4-build" class="hash-link" aria-label="Direct link to 4. Build" title="Direct link to 4. Build" translate="no">​</a></h3>
<p>Run the following command</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">./build.sh</span><br></div></code></pre></div></div>
<p>Wait for the build to finish</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="device-tree-modification-to-enable-the-camera-node">Device Tree Modification to Enable the Camera Node<a href="https://zephyr.100ask.org/en/blog/buildroot-imx415-camera#device-tree-modification-to-enable-the-camera-node" class="hash-link" aria-label="Direct link to Device Tree Modification to Enable the Camera Node" title="Direct link to Device Tree Modification to Enable the Camera Node" translate="no">​</a></h2>
<p>Enter</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">/home/ubuntu/100ask-rk3576_SDK/kernel/arch/arm64/boot/dts/rockchip</span><br></div></code></pre></div></div>
<p>Modify the file shown in the picture</p>
<p>Change to if1</p>
<p>Return to the SDK directory and use</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">./build.sh kernel</span><br></div></code></pre></div></div>
<p>Finally</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">./build.sh updateimg</span><br></div></code></pre></div></div>
<p>Finally, upload and flash (remember to enter MASKROM)</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="results">Results<a href="https://zephyr.100ask.org/en/blog/buildroot-imx415-camera#results" class="hash-link" aria-label="Direct link to Results" title="Direct link to Results" translate="no">​</a></h2>
<p>But there is still a bug, the screen camera color is still not displayed correctly.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="problem-solving">Problem Solving<a href="https://zephyr.100ask.org/en/blog/buildroot-imx415-camera#problem-solving" class="hash-link" aria-label="Direct link to Problem Solving" title="Direct link to Problem Solving" translate="no">​</a></h2>
<p>At first, I suspected that the camera's .xml (.json) was not loaded. After debugging for a long time, there was still no result.</p>
<p>After extensive debugging, I finally found a solution:</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-1-discover-key-clues-from-media-ctl-output">Step 1: Discover Key Clues from media-ctl Output<a href="https://zephyr.100ask.org/en/blog/buildroot-imx415-camera#step-1-discover-key-clues-from-media-ctl-output" class="hash-link" aria-label="Direct link to Step 1: Discover Key Clues from media-ctl Output" title="Direct link to Step 1: Discover Key Clues from media-ctl Output" translate="no">​</a></h3>
<p>In the output of <code>media-ctl -p -d /dev/media0</code>, I noticed this key information:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">entity 63: m00_b_rk628-csi9-0051 (1 pad, 1 link)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">	type V4L2 subdev subtype Sensor flags 0</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">	device node name /dev/v4l-subdev2</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">	 pad 0: Source</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">	  [fmt:UYVY8_2X8/64x64@10000/600000 field:none]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">	  -&gt; "rockchip-csi2-dphy0":0 [ENABLED] ←note the [ENABLED] here</span><br></div></code></pre></div></div>
<p><strong>Analysis Points</strong>:</p>
<p>· A rk628-csi sensor entity exists in the system</p>
<p>· Its link state is [ENABLED], meaning it is occupying CSI hardware resources</p>
<p>· But the resolution is only 64x64, which is obviously not a normal camera output</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-2-discover-from-dmesg-logs-that-imx415-driver-is-normal">Step 2: Discover from dmesg Logs that IMX415 Driver Is Normal<a href="https://zephyr.100ask.org/en/blog/buildroot-imx415-camera#step-2-discover-from-dmesg-logs-that-imx415-driver-is-normal" class="hash-link" aria-label="Direct link to Step 2: Discover from dmesg Logs that IMX415 Driver Is Normal" title="Direct link to Step 2: Discover from dmesg Logs that IMX415 Driver Is Normal" translate="no">​</a></h3>
<p>From the output of <code>dmesg | grep -i imx415</code>:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">[3.459474] imx415 3-0037: Detected imx415 id 0000e0</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[3.515523] imx415 3-0037: Consider updating driver imx415 to match on endpoints</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[3.515557] rockchip-csi2-dphy csi2-dphy3: dphy3 matches m01_f_imx415 3-0037: bustype 5</span><br></div></code></pre></div></div>
<p><strong>Analysis Points</strong>:</p>
<p>· The IMX415 sensor was correctly detected (ID: 0000e0)</p>
<p>· The driver loaded successfully and even established a matching relationship with CSI-DPHY</p>
<p>· But there is no message indicating successful V4L2 sub-device creation</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-3-infer-hardware-connections-from-device-tree-structure">Step 3: Infer Hardware Connections from Device Tree Structure<a href="https://zephyr.100ask.org/en/blog/buildroot-imx415-camera#step-3-infer-hardware-connections-from-device-tree-structure" class="hash-link" aria-label="Direct link to Step 3: Infer Hardware Connections from Device Tree Structure" title="Direct link to Step 3: Infer Hardware Connections from Device Tree Structure" translate="no">​</a></h3>
<p>From the device tree snippet:</p>
<div class="language-c codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-c codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain">csi2_dphy3 </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    port@</span><span class="token number" style="color:#36acaa">0</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        mipi_in_ucam3</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> endpoint@</span><span class="token number" style="color:#36acaa">1</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            remote</span><span class="token operator" style="color:#393A34">-</span><span class="token plain">endpoint </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain">imx415_out0</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> ←IMX415 connects here</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            data</span><span class="token operator" style="color:#393A34">-</span><span class="token plain">lanes </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token number" style="color:#36acaa">1</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">2</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">3</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">4</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    port@</span><span class="token number" style="color:#36acaa">1</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        csidphy3_out</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> endpoint@</span><span class="token number" style="color:#36acaa">0</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            remote</span><span class="token operator" style="color:#393A34">-</span><span class="token plain">endpoint </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain">mipi3_csi2_input</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><br></div></code></pre></div></div>
<p><strong>Analysis Points</strong>:</p>
<p>· IMX415 is connected to the system via CSI-DPHY3</p>
<p>· But the actual media-ctl output shows that rockchip-csi2-dphy0 is occupied</p>
<p>· This indicates that there may be a resource allocation issue among multiple CSI interfaces</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-4-infer-registration-failure-from-the-missing-v4l2-sub-device">Step 4: Infer Registration Failure from the Missing V4L2 Sub-device<a href="https://zephyr.100ask.org/en/blog/buildroot-imx415-camera#step-4-infer-registration-failure-from-the-missing-v4l2-sub-device" class="hash-link" aria-label="Direct link to Step 4: Infer Registration Failure from the Missing V4L2 Sub-device" title="Direct link to Step 4: Infer Registration Failure from the Missing V4L2 Sub-device" translate="no">​</a></h3>
<p>When running the check command:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">ls /sys/bus/i2c/devices/3-0037/v4l-subdev*/media_device/</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># Output: No such file or directory</span><br></div></code></pre></div></div>
<p><strong>Analysis Points</strong>:</p>
<p>· The I2C device 3-0037 exists and the driver binding is normal</p>
<p>· But no corresponding V4L2 sub-device was created</p>
<p>· This usually means the driver probed successfully, but the subsequent V4L2 registration failed</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-5-connect-all-clues-to-form-a-complete-picture">Step 5: Connect All Clues to Form a Complete Picture<a href="https://zephyr.100ask.org/en/blog/buildroot-imx415-camera#step-5-connect-all-clues-to-form-a-complete-picture" class="hash-link" aria-label="Direct link to Step 5: Connect All Clues to Form a Complete Picture" title="Direct link to Step 5: Connect All Clues to Form a Complete Picture" translate="no">​</a></h3>
<p>Stringing the above clues together:</p>
<p><strong>1.</strong> <strong>Symptom</strong>: IMX415 driver loaded but no V4L2 device</p>
<p><strong>2.</strong> <strong>Evidence 1</strong>: rk628-csi is occupying the CSI link and its status is [ENABLED]</p>
<p><strong>3.</strong> <strong>Evidence 2</strong>: IMX415 I2C communication is normal but the media device is missing</p>
<p><strong>4.</strong> <strong>Evidence 3</strong>: The device tree shows that the two may share CSI hardware resources</p>
<p><strong>Logical Reasoning</strong>:</p>
<p>· If the IMX415 hardware is faulty -&gt; I2C probing should fail</p>
<p>· If there is an IMX415 driver issue -&gt; dmesg should have error logs</p>
<p>· If the device tree configuration is wrong -&gt; CSI matching would not succeed</p>
<p><strong>·</strong> The only reasonable explanation: the hardware resources are occupied by another device</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-6-start-practicing">Step 6: Start Practicing<a href="https://zephyr.100ask.org/en/blog/buildroot-imx415-camera#step-6-start-practicing" class="hash-link" aria-label="Direct link to Step 6: Start Practicing" title="Direct link to Step 6: Start Practicing" translate="no">​</a></h3>
<p>Recompile the device tree and flash the development board, it runs perfectly!</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="summary">Summary<a href="https://zephyr.100ask.org/en/blog/buildroot-imx415-camera#summary" class="hash-link" aria-label="Direct link to Summary" title="Direct link to Summary" translate="no">​</a></h2>
<ol>
<li class="">
<p>Hardware resource conflicts in embedded devices are common hidden issues, especially when multiple devices share links such as CSI and I2C. The device occupation status should be a key focus of investigation.</p>
</li>
<li class="">
<p>During development, make full use of tools such as media-ctl and dmesg, combined with device tree configuration analysis, to quickly locate resource allocation issues and avoid blind debugging.</p>
</li>
<li class="">
<p>For scenarios where the driver loads normally but functions abnormally, prioritize investigating key aspects such as hardware resource occupation and V4L2 sub-device registration to narrow down the scope of the problem.</p>
</li>
<li class="">
<p>The CSI interface resource allocation of the DshanPi-A1 development board must be precisely configured through the device tree. After modification, strictly follow the Buildroot build process to regenerate the image to ensure the configuration takes effect.</p>
</li>
</ol>]]></content:encoded>
            <category>Buildroot</category>
            <category>IMX415</category>
            <category>Camera</category>
            <category>RK3576</category>
        </item>
        <item>
            <title><![CDATA[Implementing sox Noise Reduction and rnnoise Noise Reduction on RK3576]]></title>
            <link>https://zephyr.100ask.org/en/blog/sox-rnnoise-denoise</link>
            <guid>https://zephyr.100ask.org/en/blog/sox-rnnoise-denoise</guid>
            <pubDate>Tue, 18 Nov 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[Two approaches to audio noise reduction using sox's noisered spectral subtraction and the rnnoise AI model, comparing their effectiveness on stationary and non-stationary noise.]]></description>
            <content:encoded><![CDATA[<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="overview">Overview<a href="https://zephyr.100ask.org/en/blog/sox-rnnoise-denoise#overview" class="hash-link" aria-label="Direct link to Overview" title="Direct link to Overview" translate="no">​</a></h2>
<p>The development of audio noise reduction technology has evolved from combating physical noise to intelligent recognition and separation.</p>
<p><strong>Analog Era (mid-20th century)</strong></p>
<ul>
<li class=""><strong>Dolby A (1965)</strong>: A pioneering dynamic noise reduction technology that used the "companding" principle to reduce tape background noise.</li>
<li class=""><strong>Dolby B (1968)</strong>: A consumer-simplified version of Dolby A, which brought cassette tapes into millions of households.</li>
<li class=""><strong>dbx (1971)</strong>: A more aggressive companding system with a larger dynamic range.</li>
<li class=""><strong>Subsequent developments</strong>: More advanced analog systems such as Dolby C and SR followed.</li>
</ul>
<p><strong>Early Digital Era (1980s-1990s)</strong></p>
<ul>
<li class="">The emergence of digital signal processing chips made real-time digital filtering and spectral subtraction possible</li>
<li class="">Algorithms began shifting from time-domain to frequency-domain processing</li>
<li class="">Adaptive filtering theory matured and was applied in communications</li>
</ul>
<p><strong>Digital Algorithm Popularization (1990s-2010s)</strong></p>
<ul>
<li class="">Improvements in personal computer performance and the popularization of professional audio software (such as Audition and iZotope RX) made digital noise reduction tools widely accessible</li>
<li class="">The application of psychoacoustic models improved the sound quality of noise reduction</li>
<li class="">Active noise canceling headphones began to be commercialized (driven by manufacturers such as Bose)</li>
</ul>
<p><strong>Artificial Intelligence Era (2010s to present)</strong></p>
<ul>
<li class="">Deep learning has completely transformed noise reduction, enabling it to handle complex non-stationary noise</li>
<li class="">The technology is widely applied in fields such as video conferencing, voice assistants, and music streaming</li>
<li class="">Research directions have expanded from simple noise reduction to refined tasks such as speech separation and vocal extraction</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="main-noise-reduction-methods">Main Noise Reduction Methods<a href="https://zephyr.100ask.org/en/blog/sox-rnnoise-denoise#main-noise-reduction-methods" class="hash-link" aria-label="Direct link to Main Noise Reduction Methods" title="Direct link to Main Noise Reduction Methods" translate="no">​</a></h3>
<p><strong>Spectrum-based Noise Reduction</strong>
The core idea is to distinguish between noise and signal in the frequency domain:</p>
<ul>
<li class="">Spectral subtraction: Subtract the noise spectrum from the audio</li>
<li class="">Wiener filtering: A better statistical noise reduction method</li>
<li class="">Masking effect method: Leverages human ear characteristics to preserve sound quality</li>
</ul>
<p><strong>Machine Learning Noise Reduction</strong></p>
<ul>
<li class="">Uses deep learning models (RNN, CNN, Transformer, etc.) to learn noise reduction from data</li>
<li class="">Can effectively handle complex scenarios and non-stationary noise</li>
<li class="">Supports end-to-end waveform or spectrum processing</li>
</ul>
<p><strong>Filtering Noise Reduction</strong></p>
<ul>
<li class="">Adaptive filtering: Requires a reference noise signal, used in telephony and active noise canceling headphones</li>
<li class="">Fixed filtering: Removes noise at specific frequencies, such as 50Hz power-line interference</li>
</ul>
<p><strong>Multi-microphone Technology</strong></p>
<ul>
<li class="">Forms a directional beam through a microphone array</li>
<li class="">Enhances sound from the target direction and suppresses ambient noise</li>
<li class="">Common in phones, conferencing equipment, and smart speakers</li>
</ul>
<p><strong>Traditional Processing Methods</strong></p>
<ul>
<li class="">Noise gate: Mutes low-level signals via a threshold</li>
<li class="">Simple and effective, commonly used in music production and live streaming</li>
</ul>
<hr>
<p>The following uses two methods for audio noise reduction: <strong>sox noise reduction</strong> and <strong>rnnoise noise reduction</strong>.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="sox-noise-reduction">sox Noise Reduction<a href="https://zephyr.100ask.org/en/blog/sox-rnnoise-denoise#sox-noise-reduction" class="hash-link" aria-label="Direct link to sox Noise Reduction" title="Direct link to sox Noise Reduction" translate="no">​</a></h2>
<p>sox's <code>noisered</code> is a classic, non-AI noise reduction tool based on noise sampling and spectral subtraction. Its principle is intuitive and relatively simple to implement, and it is remarkably effective on stationary noise (such as fan noise, air conditioner noise, and constant current noise). The <strong><code>noisered</code> effect</strong> is the core of its noise reduction. The core principle steps are as follows:</p>
<ol>
<li class=""><strong>Analysis/Training phase</strong>: The core is <strong>building a noise fingerprint</strong>. SoX needs to first "learn" what the noise looks like. You can provide a <strong>pure noise segment</strong> (such as ambient background noise recorded before the actual recording), or let it automatically detect the low-energy "silent" portions of the audio. It analyzes these segments, computes an <strong>average noise spectrum</strong>, and saves it as a <code>.prof</code> file. This file is the reference baseline for subsequent noise reduction.</li>
<li class=""><strong>Noise Reduction Processing phase</strong>: The core is <strong>spectral subtraction</strong>.<!-- -->
<ul>
<li class=""><strong>Framing and Transform</strong>: The continuous audio signal is sliced into short-time overlapping frames and converted to the <strong>frequency domain</strong> via FFT. In the frequency domain, the signal is represented as energy (amplitude) and phase at different frequencies.</li>
<li class=""><strong>Key Operation - Spectral Subtraction</strong>: This is the most critical step. The algorithm compares the spectrum of the current frame with the previously learned <strong>noise sample spectrum</strong>. The basic idea is very simple: <strong><code>clean signal spectrum ≈ noisy signal spectrum - noise spectrum</code></strong>.<!-- -->
<ul>
<li class=""><strong>Energy Subtraction</strong>: The main operation is subtraction on the <strong>energy/amplitude spectrum</strong>. If the energy of a certain frequency in the current frame is lower than or close to the energy of the noise sample at that frequency, it will be heavily suppressed; if it is much higher, it will be preserved.</li>
<li class=""><strong>Phase Preservation</strong>: Phase information is critical for reconstructing the sound waveform. Spectral subtraction usually <strong>does not change the phase of the original signal</strong>; it directly synthesizes a new signal using the denoised amplitude spectrum and the original phase spectrum.</li>
<li class=""><strong>Suppression Factor</strong>: SoX's <code>amount</code> parameter (0.0 to 1.0) controls the strength of the subtraction. <code>0.5</code> means only half of the noise energy is subtracted, which is more conservative and reduces distortion.</li>
</ul>
</li>
<li class=""><strong>Synthesis and Output</strong>: The processed frequency-domain data is converted back to a time-domain waveform via IFFT, and then the short-time frames are synthesized into a continuous audio signal through the <strong>overlap-add</strong> method, ultimately producing the denoised audio.</li>
</ul>
</li>
</ol>
<p>It looks complicated, but it is simple to operate. Now let's use the sox command to demonstrate and make it clear.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="sox-command-noise-reduction">sox Command Noise Reduction<a href="https://zephyr.100ask.org/en/blog/sox-rnnoise-denoise#sox-command-noise-reduction" class="hash-link" aria-label="Direct link to sox Command Noise Reduction" title="Direct link to sox Command Noise Reduction" translate="no">​</a></h3>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">#noise.wav is the background noise, a 10s audio clip recorded in a quiet state</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">ls</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">	noise.wav speech.wav</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">#Generate a noise profile (manually extract 5-10 seconds of pure noise)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sox noise.wav -n noiseprof noise.prof</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">#Noise reduction, 0.21 is an empirical value, the vast majority of material will not produce water sound</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sox speech.wav noisered_speech.wav noisered noise.prof 0.21</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">#Compare playback, the effect is obviously noticeable</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">aplay noise.wav</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">	Playing WAVE 'noise.wav' : Signed 16 bit Little Endian, Rate 8000 Hz, Stereo</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">aplay speech.wav</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">	Playing WAVE 'speech.wav' : Signed 16 bit Little Endian, Rate 8000 Hz, Stereo</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">aplay noisered_speech.wav</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">	Playing WAVE 'noisered_speech.wav' : Signed 16 bit Little Endian, Rate 8000 Hz, Stereo</span><br></div></code></pre></div></div>
<p>Using only the sox command for noise reduction cannot be integrated into an embedded system. Next, we will use the C language with sox's library and API to perform audio noise reduction.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="using-soxs-library-and-api-for-audio-noise-reduction">Using sox's Library and API for Audio Noise Reduction<a href="https://zephyr.100ask.org/en/blog/sox-rnnoise-denoise#using-soxs-library-and-api-for-audio-noise-reduction" class="hash-link" aria-label="Direct link to Using sox's Library and API for Audio Noise Reduction" title="Direct link to Using sox's Library and API for Audio Noise Reduction" translate="no">​</a></h3>
<p>The code structure is as follows:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">(base) ubuntu@ubuntu-2204:~/baiwen/sox_noise_reduction$ tree -L 2</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">.</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">├── CMakeLists.txt</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">├── deps</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">│   ├── include</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">│   └── lib</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">├── include</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">│   ├── custom_effects.h</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">│   └── sox_noise_reduction.h</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">├── Makefile</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">└── src</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    ├── custom_effects.c</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    ├── main.c</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    └── sox_noise_reduction.c</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">5 directories, 7 files</span><br></div></code></pre></div></div>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="build">Build<a href="https://zephyr.100ask.org/en/blog/sox-rnnoise-denoise#build" class="hash-link" aria-label="Direct link to Build" title="Direct link to Build" translate="no">​</a></h4>
<p>To build this demo, you need to set the toolchain in CMakeLists.txt</p>
<div class="language-cmake codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-cmake codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain"># Specify the cross compiler</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">set(CMAKE_C_COMPILER /home/ubuntu/rk3576_AI/buildroot/output/rockchip_rk3576/host/bin/aarch64-buildroot-linux-gnu-gcc)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">set(CMAKE_CXX_COMPILER /home/ubuntu/rk3576_AI/buildroot/output/rockchip_rk3576/host/bin/aarch64-buildroot-linux-gnu-g++)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># Set sysroot</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">set(CMAKE_SYSROOT /home/ubuntu/rk3576_AI/buildroot/output/rockchip_rk3576/staging)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT})</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># Add link libraries</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">target_link_libraries(sox_noise_reduction</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    sox</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">)</span><br></div></code></pre></div></div>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">#Build on ubuntu22.04</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">(base) ubuntu@ubuntu-2204:~/baiwen/sox_noise_reduction$ make</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Configuring CMake...</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">-- The C compiler identification is GNU 11.4.0</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">-- Detecting C compiler ABI info</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">-- Detecting C compiler ABI info - done</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">-- Check for working C compiler: /usr/bin/cc - skipped</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">-- Detecting C compile features</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">-- Detecting C compile features - done</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">-- Configuring done</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">-- Generating done</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">-- Build files have been written to: /home/ubuntu/baiwen/sox_noise_reduction/build</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Building with 16 jobs...</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">make[1]: Entering directory '/home/ubuntu/baiwen/sox_noise_reduction/build'</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">make[2]: Entering directory '/home/ubuntu/baiwen/sox_noise_reduction/build'</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">make[3]: Entering directory '/home/ubuntu/baiwen/sox_noise_reduction/build'</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">make[3]: Leaving directory '/home/ubuntu/baiwen/sox_noise_reduction/build'</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">make[3]: Entering directory '/home/ubuntu/baiwen/sox_noise_reduction/build'</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[ 75%] Building C object CMakeFiles/sox_noise_reduction.dir/src/sox_noise_reduction.c.o</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[ 75%] Building C object CMakeFiles/sox_noise_reduction.dir/src/custom_effects.c.o</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[ 75%] Building C object CMakeFiles/sox_noise_reduction.dir/src/main.c.o</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[100%] Linking C executable sox_noise_reduction</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">make[3]: Leaving directory '/home/ubuntu/baiwen/sox_noise_reduction/build'</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[100%] Built target sox_noise_reduction</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">make[2]: Leaving directory '/home/ubuntu/baiwen/sox_noise_reduction/build'</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">make[1]: Leaving directory '/home/ubuntu/baiwen/sox_noise_reduction/build'</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">#make push will push the sox_noise_reduction executable to buildroot's /develop via adb</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">(base) ubuntu@ubuntu-2204:~/baiwen/sox_noise_reduction$ make push</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Running build/sox_noise_reduction...</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">build/sox_noise_reduction: 1 file pushed. 10.6 MB/s (23840 bytes in 0.002s)</span><br></div></code></pre></div></div>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="run">Run<a href="https://zephyr.100ask.org/en/blog/sox-rnnoise-denoise#run" class="hash-link" aria-label="Direct link to Run" title="Direct link to Run" translate="no">​</a></h4>
<p>On the rk3576</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">root@rk3576-buildroot:/develop# ls</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">live_life.mp3  noise.wav  sox_noise_reduction  speech.wav</span><br></div></code></pre></div></div>
<p>First, record a background noise clip noise.wav in a quiet environment, then speak a sentence into the microphone to record speech.wav</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">root@rk3576-buildroot:/develop# ./sox_noise_reduction</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    SoX audio noise reduction processing started</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    =======================</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    Noise file:   noise.wav</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    Input file:   speech.wav</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    Output file:   noisered_output.wav</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    Noise reduction sensitivity: 0.21</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    -----------------------</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    Processing...</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    [1/2] Creating noise profile...</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    Creating noise profile from: noise.wav</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    Processing noise profile...</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    Noise profile created: /tmp/noise_profile_NFk1uN.prof</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    [2/2] Applying noise reduction...</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    Applying noise reduction to: speech.wav</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    Processing audio with noise reduction...</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    Noise reduction applied. Output: noisered_output.wav</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    Done!</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    Processing successful! Output file: noisered_output.wav</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">#Use aplay to play and compare</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">aplay noise.wav</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">aplay speech.wav</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">aplay noisered_output.wav</span><br></div></code></pre></div></div>
<p>You can hear that noisered_output.wav is noticeably improved, but there is still some faint <strong>"musical noise"</strong>. This is an inherent side effect of sox's <strong>spectral subtraction</strong> noise reduction. To completely remove it, you would need to design an additional <strong>Wiener filter</strong> effect plugin to further eliminate it.</p>
<p>The usage of sox_noise_reduction can be found in the -h help information</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">root@rk3576-buildroot:/develop# ./sox_noise_reduction -h</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">SoX audio noise reduction tool</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">====================</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Usage: ./sox_noise_reduction [options]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Options:</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  -n file   Noise sample file (default: noise.wav)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  -i file   Input speech file (default: speech.wav)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  -o file   Output file (default: noisered_output.wav)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  -s value  Noise reduction sensitivity 0.0-1.0 (default: 0.21)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  -h        Show this help information</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Parameter description:</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  Sensitivity: 0.0 means strongest noise reduction (may damage speech), 1.0 means weakest noise reduction</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  Recommended value: 0.21 (empirical value, suitable for most audio material)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Usage examples:</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  ./sox_noise_reduction                    # Use all default settings</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  ./sox_noise_reduction -n mynoise.wav    # Specify noise file</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  ./sox_noise_reduction -i myspeech.wav   # Specify input file</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  ./sox_noise_reduction -s 0.3            # Adjust noise reduction strength</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  ./sox_noise_reduction -o clean.wav      # Specify output file</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="rnnoise-noise-reduction">rnnoise Noise Reduction<a href="https://zephyr.100ask.org/en/blog/sox-rnnoise-denoise#rnnoise-noise-reduction" class="hash-link" aria-label="Direct link to rnnoise Noise Reduction" title="Direct link to rnnoise Noise Reduction" translate="no">​</a></h2>
<p><strong>RNNoise</strong> is an excellent open-source audio noise reduction tool, very suitable for scenarios that require <strong>entry-level learning, quick integration, and moderate performance</strong>.</p>
<ol>
<li class=""><strong>Technical Principle</strong>:<!-- -->
<ul>
<li class="">Combines <strong>traditional signal processing</strong> (spectral analysis) with <strong>deep learning</strong> (RNN neural network).</li>
<li class="">Input audio framing -&gt; feature extraction (such as band energy, pitch) -&gt; RNN predicts the gain mask for each band (VAD is also integrated within) -&gt; outputs the denoised spectrum -&gt; reconstructs the waveform.</li>
</ul>
</li>
<li class=""><strong>Lightweight Design</strong>:<!-- -->
<ul>
<li class="">The model is only <strong>about 86KB</strong>, suitable for embedded or real-time processing.</li>
<li class="">A single-core CPU can process in real time.</li>
</ul>
</li>
</ol>
<p><strong>Advantages</strong>:</p>
<ul>
<li class=""><strong>Open source and easy to use</strong>: Clear code, provides a C language API, easy to integrate into various projects.</li>
<li class=""><strong>Low latency</strong>: Frame processing latency is about 10ms (default frame length 20ms), suitable for real-time communication.</li>
<li class=""><strong>Strong compatibility</strong>: No third-party deep learning framework dependencies, pure C implementation.</li>
<li class=""><strong>Good speech preservation</strong>: While suppressing stationary noise (such as fan noise), it causes little damage to speech.</li>
</ul>
<p><strong>Limitations</strong>:</p>
<ul>
<li class=""><strong>Not a general-purpose noise reduction</strong>: Mainly optimized for <strong>voice communication</strong>, limited effect on music and sudden noise (such as keyboard sounds).</li>
<li class=""><strong>Fixed parameters</strong>: The model is trained for general scenarios, difficult to customize for specific noise.</li>
<li class=""><strong>Residual "musical noise"</strong>: In some scenarios, it may introduce residual noise similar to water ripples.</li>
<li class=""><strong>No support for high sampling rates</strong>: By default, only supports 48kHz/16kHz mono, music noise reduction requires adjustment.</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="build-1">Build<a href="https://zephyr.100ask.org/en/blog/sox-rnnoise-denoise#build-1" class="hash-link" aria-label="Direct link to Build" title="Direct link to Build" translate="no">​</a></h3>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">## Set the cross-compile toolchain path</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">export TOOLCHAIN_DIR="/home/ubuntu/rk3576_AI/buildroot/output/rockchip_rk3576/host/bin"</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">export CC="${TOOLCHAIN_DIR}/aarch64-buildroot-linux-gnu-gcc"</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">export CXX="${TOOLCHAIN_DIR}/aarch64-buildroot-linux-gnu-g++"</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">export AR="${TOOLCHAIN_DIR}/aarch64-buildroot-linux-gnu-ar"</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">export LD="${TOOLCHAIN_DIR}/aarch64-buildroot-linux-gnu-ld"</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">export RANLIB="${TOOLCHAIN_DIR}/aarch64-buildroot-linux-gnu-ranlib"</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">export STRIP="${TOOLCHAIN_DIR}/aarch64-buildroot-linux-gnu-strip"</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># Set target architecture</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">export ARCH="aarch64"</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">export CROSS_COMPILE="aarch64-buildroot-linux-gnu-"</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># Set sysroot (important!)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">export SYSROOT="/home/ubuntu/rk3576_AI/buildroot/output/rockchip_rk3576/staging"</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">export CFLAGS="--sysroot=${SYSROOT} -O2"</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">export LDFLAGS="--sysroot=${SYSROOT}"</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">echo "Toolchain setup complete"</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">echo "CC = $CC"</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># Clone the project and build</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">git clone https://github.com/xiph/rnnoise.git</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">cd rnnoise</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">./autogen.sh</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">./configure \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    --host=aarch64-buildroot-linux-gnu \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    --build=x86_64-pc-linux-gnu \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    --prefix=$(pwd)/tmp \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    --enable-static \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    --enable-shared \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    CFLAGS="--sysroot=${SYSROOT} -O2" \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    LDFLAGS="--sysroot=${SYSROOT}" \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    CC="${CC}" \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    CXX="${CXX}" \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    AR="${AR}" \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    LD="${LD}"</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">#Build</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">make</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">#Install to ./tmp</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">make install</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">(base) ubuntu@ubuntu-2204:~/rnnoise$ tree -L 2 tmp</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    tmp</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    ├── include</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    │   └── rnnoise.h</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    ├── lib</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    │   ├── librnnoise.a</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    │   ├── librnnoise.la</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    │   ├── librnnoise.so -&gt; librnnoise.so.0.4.1</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    │   ├── librnnoise.so.0 -&gt; librnnoise.so.0.4.1</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    │   ├── librnnoise.so.0.4.1</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    │   └── pkgconfig</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    └── share</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        └── doc</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">(base) ubuntu@ubuntu-2204:~/rnnoise$ ls examples/</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">	rnnoise_demo  rnnoise_demo.c  rnnoise_demo.o</span><br></div></code></pre></div></div>
<p>The files in the ./tmp directory are the rnnoise headers and libraries needed for integration. The rnnoise_demo under examples is a reference implementation, and there is also a .c file for reference.</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">adb push examples/.libs/rnnoise_demo /usr/bin/rnnoise_demo</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">adb push  tmp/lib/librnnoise.so* /usr/lib/</span><br></div></code></pre></div></div>
<p>Now you can do a simple test on the development board.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="test">Test<a href="https://zephyr.100ask.org/en/blog/sox-rnnoise-denoise#test" class="hash-link" aria-label="Direct link to Test" title="Direct link to Test" translate="no">​</a></h3>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain"># First check the original WAV file information</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">soxi speech.wav</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># If the sampling rate is not 48000, first convert it to 48000</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sox speech.wav -r 48000 speech_48k.wav</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># Adjust the input volume to a suitable range (-3dB to -6dB)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># RNNoise requires: 48000Hz, mono, 16-bit signed integer PCM</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sox speech_48k.wav -r 48000 -c 1 -e signed-integer -b 16 -t raw speech.pcm  gain -n -3</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># Run RNNoise noise reduction</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">rnnoise_demo speech.pcm rnnoise.pcm</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">#Convert back to WAV format</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sox -r 48000 -c 1 -e signed-integer -b 16 -t raw rnnoise.pcm rnnoise.wav</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="using-rnnoises-library-and-api-for-audio-noise-reduction">Using rnnoise's Library and API for Audio Noise Reduction<a href="https://zephyr.100ask.org/en/blog/sox-rnnoise-denoise#using-rnnoises-library-and-api-for-audio-noise-reduction" class="hash-link" aria-label="Direct link to Using rnnoise's Library and API for Audio Noise Reduction" title="Direct link to Using rnnoise's Library and API for Audio Noise Reduction" translate="no">​</a></h3>
<p>Code structure</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">(base) ubuntu@ubuntu-2204:~/baiwen/rnnoise_reduction$ tree -L 3</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">.</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">├── CMakeLists.txt</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">├── deps</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">│   ├── include</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">│   │   └── rnnoise.h</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">│   └── lib</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">│       └── librnnoise.so</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">├── include</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">├── Makefile</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">└── src</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    └── main.c</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">5 directories, 5 files</span><br></div></code></pre></div></div>
<p>Among them, rnnnoise.h and librnnoise.so come from the rnnoise build output, just copy them directly. CMakeLists.txt needs to update the toolchain path</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain"># Specify the cross compiler</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">set(CMAKE_C_COMPILER /home/ubuntu/rk3576_AI/buildroot/output/rockchip_rk3576/host/bin/aarch64-buildroot-linux-gnu-gcc)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">set(CMAKE_CXX_COMPILER /home/ubuntu/rk3576_AI/buildroot/output/rockchip_rk3576/host/bin/aarch64-buildroot-linux-gnu-g++)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># Set sysroot</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">set(CMAKE_SYSROOT /home/ubuntu/rk3576_AI/buildroot/output/rockchip_rk3576/staging)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT})</span><br></div></code></pre></div></div>
<p>Build</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">make clean</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">make</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">#push adb to the develop directory of the development board</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">make push</span><br></div></code></pre></div></div>
<p>Test on the development board</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">root@rk3576-buildroot:/develop# ./rnnoise_reduction speech.wav rnnoise.wav -3</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">=== RNNoise audio noise reduction processing ===</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">1. Read WAV file: speech.wav</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">   Sampling rate: 8000Hz, channels: 2, sample count: 40000 (5.00 seconds)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">2. Apply gain: -3.0dB</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">3. Resample to 48kHz</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">   After resampling: 240000 samples (5.00 seconds)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">4. RNNoise noise reduction processing</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    Processed frames: 500, 480 samples per frame</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    First 5 original sample values of the first frame: -34 -28 -23 -17 -11</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">   After processing: 240000 samples (5.00 seconds)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">5. Save as WAV file: rnnoise.wav</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">=== Processing complete ===</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">root@rk3576-buildroot:/develop# aplay speech.wav</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Playing WAVE 'speech.wav' : Signed 16 bit Little Endian, Rate 8000 Hz, Stereo</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">root@rk3576-buildroot:/develop# aplay rnnoise.wav</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Playing WAVE 'rnnoise.wav' : Signed 16 bit Little Endian, Rate 48000 Hz, Mono</span><br></div></code></pre></div></div>
<p>A noticeable noise reduction effect can be heard.</p>]]></content:encoded>
            <category>sox</category>
            <category>rnnoise</category>
            <category>Noise Reduction</category>
            <category>Audio</category>
        </item>
        <item>
            <title><![CDATA[DshanPI-A1 Setting Up the RKNN Environment under Buildroot]]></title>
            <link>https://zephyr.100ask.org/en/blog/buildroot-rknn-setup</link>
            <guid>https://zephyr.100ask.org/en/blog/buildroot-rknn-setup</guid>
            <pubDate>Sun, 16 Nov 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[Set up the RKNN runtime environment on a Buildroot system to prepare for NPU model inference.]]></description>
            <content:encoded><![CDATA[<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="development-environment">Development Environment<a href="https://zephyr.100ask.org/en/blog/buildroot-rknn-setup#development-environment" class="hash-link" aria-label="Direct link to Development Environment" title="Direct link to Development Environment" translate="no">​</a></h2>
<blockquote>
<p>PC side: ubuntu22.04-x86-64</p>
<p>Board side: buildroot</p>
</blockquote>
<p>The specific theoretical part won't be elaborated here; there's plenty online. This records the entire operation process, divided into two main parts: 1. PC side 2. Board side</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="1-pc-side">1. PC Side<a href="https://zephyr.100ask.org/en/blog/buildroot-rknn-setup#1-pc-side" class="hash-link" aria-label="Direct link to 1. PC Side" title="Direct link to 1. PC Side" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="setting-up-the-rknn-toolkit2-environment">Setting Up the RKNN-Toolkit2 Environment<a href="https://zephyr.100ask.org/en/blog/buildroot-rknn-setup#setting-up-the-rknn-toolkit2-environment" class="hash-link" aria-label="Direct link to Setting Up the RKNN-Toolkit2 Environment" title="Direct link to Setting Up the RKNN-Toolkit2 Environment" translate="no">​</a></h3>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain"># Download the code repository</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">mkdir rknn</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">cd rknn</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">wget https://dl.100ask.net/Hardware/MPU/RK3576-DshanPi-A1/utils/rknn-toolkit2.zip</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">unzip rknn-toolkit2.zip</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">wget https://dl.100ask.net/Hardware/MPU/RK3576-DshanPi-A1/utils/rknn_model_zoo.zip</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">unzip rknn_model_zoo.zip</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># Set up conda environment</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">wget -c https://repo.anaconda.com/archive/Anaconda3-2025.06-1-Linux-x86_64.sh</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">bash Anaconda3-2025.06-1-Linux-x86_64.sh</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">	Please, press ENTER to continue</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">	&gt;&gt;&gt; </span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">	Do you accept the license terms? [yes|no]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">	&gt;&gt;&gt; yes</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">	Anaconda3 will now be installed into this location:</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    /home/ubuntu/anaconda3</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      - Press ENTER to confirm the location</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      - Press CTRL-C to abort the installation</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      - Or specify a different location below</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    [/home/ubuntu/anaconda3] &gt;&gt;&gt; </span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> 	You can undo this by running `conda init --reverse $SHELL`? [yes|no]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">	[no] &gt;&gt;&gt; yes</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">	Thank you for installing Anaconda3!</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># Activate environment variables</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">source ~/.bashrc</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># Create RKNN environment</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">conda create -n rknn-toolkit2 python=3.8</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">conda activate rknn-toolkit2</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># Install RKNN-Toolkit2</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">cd rknn-toolkit2/rknn-toolkit2/packages/x86_64/</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">conda install compilers cmake</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">pip install -r requirements_cp38-2.3.2.txt</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">pip install rknn_toolkit2-2.3.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># Verify installation</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    (rknn-toolkit2) ubuntu@ubuntu-2204:~/rknn/rknn-toolkit2/rknn-toolkit2/packages/x86_64$ python3</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    Python 3.8.20 (default, Oct  3 2024, 15:24:27)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    [GCC 11.2.0] :: Anaconda, Inc. on linux</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    Type "help", "copyright", "credits" or "license" for more information.</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    &gt;&gt;&gt; from rknn.api import RKNN</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    &gt;&gt;&gt; exit()</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    (rknn-toolkit2) ubuntu@ubuntu-2204:~/rknn/rknn-toolkit2/rknn-toolkit2/packages/x86_64$</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="2-on-board-inference">2. On-Board Inference<a href="https://zephyr.100ask.org/en/blog/buildroot-rknn-setup#2-on-board-inference" class="hash-link" aria-label="Direct link to 2. On-Board Inference" title="Direct link to 2. On-Board Inference" translate="no">​</a></h2>
<p>First, here is my environment: I use the buildroot that comes with the SDK, adapted by the 100ASK team, with rknnruntime already enabled, and <strong>I did not update the runtime</strong>.</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">root@rk3576-buildroot:/# uname -a</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">	Linux rk3576-buildroot 6.1.75 #3 SMP Fri Nov 28 09:41:14 EST 2025 aarch64 GNU/Linux</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">root@rk3576-buildroot:/# find ./ -name *rknn*</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    ./rockchip-test/npu2/model/RK356X/mobilenet_v1.rknn</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    ./rockchip-test/npu2/model/RK3588/vgg16_max_pool_fp16.rknn</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    ./sys/kernel/debug/clk/hclk_rknn_root</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    ./sys/kernel/debug/clk/clk_rknn_dsu0</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    ./sys/kernel/debug/clk/aclk_rknn0</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    ./sys/kernel/debug/clk/aclk_rknn1</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    ./sys/kernel/debug/clk/aclk_rknn_cbuf</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    ./sys/kernel/debug/clk/hclk_rknn_cbuf</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    ./usr/share/model/RK3562/mobilenet_v1.rknn</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    ./usr/share/model/RK3566_RK3568/mobilenet_v1.rknn</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    ./usr/share/model/RK3588/mobilenet_v1.rknn</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    ./usr/share/model/RK3576/mobilenet_v1.rknn</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    ./usr/lib/librknnrt.so</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    ./usr/bin/start_rknn.sh</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    ./usr/bin/rknn_common_test</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    ./usr/bin/restart_rknn.sh</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    ./usr/bin/rknn_server</span><br></div></code></pre></div></div>
<p><strong>tip:</strong> My buildroot configuration <code>./build.sh bconfig</code></p>
<div class="language-apl codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-apl codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain"> [*] Rockchip NPU power control for linux                                                  │ │</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  │ │                   [ ] Rockchip NPU power control combine for linux                                          │ │</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  │ │                   [ ] Rockchip recovery for linux                                                           │ │</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  │ │                   [ ] rkadk                                                                                 │ │</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  │ │                   [ ] rknpu                                                                                 │ │</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  │ │                   [ ] rknpu pcie                                                                            │ │</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  │ │                   [ ] python-rknn                                                                           │ │</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  │ │                   [*] rknpu2                                                                                │ │</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  │ │                   [*] rknpu2 example                                                                        │ │</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  │ │                   [ ] rknpu firmware                                                                        │ │</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  │ │                   [ ] RKPARTYBOX demo                                                                       │ │</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  │ │                   [*] rockchip script                 </span><br></div></code></pre></div></div>
<p>As you can see, I did not change the rknpu configuration; buildroot already configures the rknpu driver and rknnruntime by default.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="problem-1-solving-adb-permission-issues-on-the-pc-side">Problem 1: Solving ADB Permission Issues on the PC Side<a href="https://zephyr.100ask.org/en/blog/buildroot-rknn-setup#problem-1-solving-adb-permission-issues-on-the-pc-side" class="hash-link" aria-label="Direct link to Problem 1: Solving ADB Permission Issues on the PC Side" title="Direct link to Problem 1: Solving ADB Permission Issues on the PC Side" translate="no">​</a></h3>
<p>When running on-board inference on the PC, the following error occurs:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">：(rknn-toolkit2) ubuntu@ubuntu-2204:~/rknn/rknn_model_zoo/examples/yolov8/python$ sudo python3 yolov8.py --target rk3576 --model_path ../model/yolov8.rknn --img_show</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Traceback (most recent call last):</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  File "/home/ubuntu/rknn/rknn_model_zoo/examples/yolov8/python/yolov8.py", line 2, in &lt;module&gt;</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    import cv2</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">ModuleNotFoundError: No module named 'cv2'</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">(rknn-toolkit2) ubuntu@ubuntu-2204:~/rknn/rknn_model_zoo/examples/yolov8/python$ python3 yolov8.py --target rk3576 --model_path ../model/yolov8.rknn --img_show</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">I rknn-toolkit2 version: 2.3.2</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">--&gt; Init runtime environment</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">adb: unable to connect for root: insufficient permissions for device: user in plugdev group; are your udev rules wrong?</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">See [http://developer.android.com/tools/device.html] for more information</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">I target set by user is: rk3576</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">E init_runtime: Get board target failed, ret code: 1. error: insufficient permissions for device: user in plugdev group; are your udev rules wrong?</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">See [http://developer.android.com/tools/device.html] for more information</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">E init_runtime: Traceback (most recent call last):</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  File "rknn/api/rknn_log.py", line 344, in rknn.api.rknn_log.error_catch_decorator.error_catch_wrapper</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  File "rknn/api/rknn_base.py", line 2566, in rknn.api.rknn_base.RKNNBase.init_runtime</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  File "rknn/api/rknn_runtime.py", line 223, in rknn.api.rknn_runtime.RKNNRuntime.__init__</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  File "rknn/api/rknn_platform.py", line 607, in rknn.api.rknn_platform.get_board_info</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">RuntimeError</span><br></div></code></pre></div></div>
<p>Note this line</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">adb: unable to connect for root: insufficient permissions for device: user in plugdev group; are your udev rules wrong?</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">See [http://developer.android.com/tools/device.html] for more information</span><br></div></code></pre></div></div>
<p>It indicates insufficient adbd permissions; fix it with:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain"># Add udev rules</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">echo 'SUBSYSTEM=="usb", ATTR{idVendor}=="2207", MODE="0666", GROUP="plugdev"' | sudo tee /etc/udev/rules.d/51-android.rules</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># Reload rules</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sudo udevadm control --reload-rules</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sudo udevadm trigger</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># Restart ADB</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">adb kill-server</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">adb start-server</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">adb devices</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    List of devices attached</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    8074683be1050187        device</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="problem-2-solving-the-board-side-adbd-port-5037-not-open-issue">Problem 2: Solving the Board-Side adbd Port 5037 Not Open Issue<a href="https://zephyr.100ask.org/en/blog/buildroot-rknn-setup#problem-2-solving-the-board-side-adbd-port-5037-not-open-issue" class="hash-link" aria-label="Direct link to Problem 2: Solving the Board-Side adbd Port 5037 Not Open Issue" title="Direct link to Problem 2: Solving the Board-Side adbd Port 5037 Not Open Issue" translate="no">​</a></h3>
<p>Symptom:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain"># Run on-board inference</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> python3 yolov8.py --target rk3576 --model_path ../model/yolov8.rknn --img_show</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    I rknn-toolkit2 version: 2.3.2</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    --&gt; Init runtime environment</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    adbd is already running as root</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    I target set by user is: rk3576</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    I Get hardware info: target_platform = rk3576, os = Linux, aarch = aarch64</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    I Check RK3576 board npu runtime version</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    W kill server failed while restarting, ret code: 1. warning: killall: rknn_server: no process killed</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      Please skip it if rknn_server not running on board.</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    I Starting ntp or adb, target is RK3576</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    I Start adb...</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    I Connect to Device success!</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    I NPUTransfer(3672747): Starting NPU Transfer Client, Transfer version 2.2.2 (12abf2a@2024-09-02T03:22:41)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    E RKNNAPI: rknn_init,  server connect fail!  ret = -9(ERROR_PIPE)!</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    E init_runtime: The rknn_server on the concected device is abnormal, please start the rknn_server on the device according to:</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                   https://github.com/airockchip/rknn-toolkit2/blob/master/doc/rknn_server_proxy.md</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    W init_runtime: ===================== WARN(1) =====================</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    E rknn-toolkit2 version: 2.3.2</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    E init_runtime: Traceback (most recent call last):</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      File "rknn/api/rknn_log.py", line 344, in rknn.api.rknn_log.error_catch_decorator.error_catch_wrapper</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div></code></pre></div></div>
<p>Note</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">    I NPUTransfer(3672747): Starting NPU Transfer Client, Transfer version 2.2.2 (12abf2a@2024-09-02T03:22:41)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    E RKNNAPI: rknn_init,  server connect fail!  ret = -9(ERROR_PIPE)!</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    E init_runtime: The rknn_server on the concected device is abnormal, please start the rknn_server on the device according to:</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                   https://github.com/airockchip/rknn-toolkit2/blob/master/doc/rknn_server_proxy.md</span><br></div></code></pre></div></div>
<p>Following the hint, go to <a href="https://github.com/airockchip/rknn-toolkit2/blob/master/doc/rknn_server_proxy.md" target="_blank" rel="noopener noreferrer" class="">https://github.com/airockchip/rknn-toolkit2/blob/master/doc/rknn_server_proxy.md</a> to find the solution</p>
<p>In this document's</p>
<blockquote>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="6-faq">6. FAQ<a href="https://zephyr.100ask.org/en/blog/buildroot-rknn-setup#6-faq" class="hash-link" aria-label="Direct link to 6. FAQ" title="Direct link to 6. FAQ" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="problem-1">Problem 1<a href="https://zephyr.100ask.org/en/blog/buildroot-rknn-setup#problem-1" class="hash-link" aria-label="Direct link to Problem 1" title="Direct link to Problem 1" translate="no">​</a></h3>
<p>On Debian systems, the rknn_server service has been started in the background, but the following error still occurs during on-board inference:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">D NPUTransfer: ERROR: socket read fd = 4, n = -1: Connection reset by peer</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">D NPUTransfer: Transfer client closed, fd = 4</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">E RKNNAPI: rknn_init,  server connect fail!  ret = -9(ERROR_PIPE)!</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">E build_graph: The rknn_server on the concected device is abnormal, please start the rknn_server on the device according to:</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">               https://github.com/airockchip/rknn-toolkit2/blob/master/doc/rknn_server_proxy.md</span><br></div></code></pre></div></div>
<p><strong>Solution:</strong> This is usually because the adbd program on the Debian firmware is not listening on port 5037. You can run the following command on the board to check:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">netstat -n -t -u -a</span><br></div></code></pre></div></div>
<p>If the output does not contain <strong>port 5037</strong>, run the following commands to download and update the adbd program, and reboot the board; otherwise, skip the following steps.</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">wget -O adbd.zip https://ftzr.zbox.filez.com/v2/delivery/data/7f0ac30dfa474892841fcb2cd29ad924/adbd.zip</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">unzip adbd.zip</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">adb push adbd/linux-aarch64/adbd /usr/bin/adbd</span><br></div></code></pre></div></div>
<p>Enter the device shell command to add executable permission to adbd</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">adb shell "chmod +x /usr/bin/adbd"</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">adb reboot</span><br></div></code></pre></div></div>
<p>After rebooting the device, follow the startup steps to start the rknn_server service and try on-board inference again.</p>
</blockquote>
<p>Although this document uses Debian firmware and I use buildroot, the symptom is the same. Follow its solution to troubleshoot:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain"># This is the board side</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">root@rk3576-buildroot:/# netstat -n -t -u -a</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Active Internet connections (servers and established)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Proto Recv-Q Send-Q Local Address           Foreign Address         State</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">tcp        0      0 0.0.0.0:53              0.0.0.0:*               LISTEN</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">tcp        0      0 :::53                   :::*                    LISTEN</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">tcp        0      0 :::22                   :::*                    LISTEN</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">tcp        0      0 :::5555                 :::*                    LISTEN</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">udp        0      0 0.0.0.0:53              0.0.0.0:*</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">udp        0      0 0.0.0.0:67              0.0.0.0:*</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">udp        0      0 0.0.0.0:68              0.0.0.0:*</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">udp        0      0 127.0.0.1:323           0.0.0.0:*</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">udp        0      0 :::53                   :::*</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">udp        0      0 ::1:323                 0.0.0.0:*</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">udp        0      0 :::546                  :::*</span><br></div></code></pre></div></div>
<p>As you can see, <strong>port 5037</strong> is indeed not open</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain"># This is the PC side</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">wget -O adbd.zip https://ftzr.zbox.filez.com/v2/delivery/data/7f0ac30dfa474892841fcb2cd29ad924/adbd.zip</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">unzip adbd.zip</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">adb push adbd/linux-aarch64/adbd /usr/bin/adbd</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">adb shell "chmod +x /usr/bin/adbd"</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">adb reboot</span><br></div></code></pre></div></div>
<p>After rebooting the development board, retest</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain"># This is the board side</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">restart_rknn.sh</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">root@rk3576-buildroot:/# netstat -n -t -u -a</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Active Internet connections (servers and established)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Proto Recv-Q Send-Q Local Address           Foreign Address         State</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">tcp        0      0 127.0.0.1:5037          0.0.0.0:*               LISTEN</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">tcp        0      0 0.0.0.0:53              0.0.0.0:*               LISTEN</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">tcp        0      0 0.0.0.0:5555            0.0.0.0:*               LISTEN</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">tcp        0      0 :::22                   :::*                    LISTEN</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">tcp        0      0 :::53                   :::*                    LISTEN</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">udp        0      0 0.0.0.0:53              0.0.0.0:*</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">udp        0      0 0.0.0.0:67              0.0.0.0:*</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">udp        0      0 0.0.0.0:68              0.0.0.0:*</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">udp        0      0 127.0.0.1:323           0.0.0.0:*</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">udp        0      0 :::546                  :::*</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">udp        0      0 :::53                   :::*</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">udp        0      0 ::1:323                 0.0.0.0:*</span><br></div></code></pre></div></div>
<p>As you can see, <strong>port 5037</strong> is now being listened on. Continue trying on-board inference</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain"># This is the PC side</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">(rknn-toolkit2) ubuntu@ubuntu-2204:~/rknn/rknn_model_zoo/examples/yolov8/python$ python3 yolov8.py --target rk3576 --model_path ../model/yolov8.rknn --img_show</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">I rknn-toolkit2 version: 2.3.2</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">--&gt; Init runtime environment</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">adb: unable to connect for root: closed</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">I target set by user is: rk3576</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">I Get hardware info: target_platform = rk3576, os = Linux, aarch = aarch64</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">I Check RK3576 board npu runtime version</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">I Starting ntp or adb, target is RK3576</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">I Start adb...</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">I Connect to Device success!</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">I NPUTransfer(3675220): Starting NPU Transfer Client, Transfer version 2.2.2 (12abf2a@2024-09-02T03:22:41)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">I NPUTransfer(3675220): TransferBuffer: min aligned size: 1024</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">D RKNNAPI: ==============================================</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">D RKNNAPI: RKNN VERSION:</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">D RKNNAPI:   API: 2.3.2 (1842325 build@2025-03-30T09:55:23)</span><br></div></code></pre></div></div>
<p>On-board inference succeeded, showing the face recognition image</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="3-on-board-inference-native">3. On-Board Inference (Native)<a href="https://zephyr.100ask.org/en/blog/buildroot-rknn-setup#3-on-board-inference-native" class="hash-link" aria-label="Direct link to 3. On-Board Inference (Native)" title="Direct link to 3. On-Board Inference (Native)" translate="no">​</a></h2>
<p>Since buildroot is used, and the RK platform after rk1808 does not support python deployment in buildroot, setting up a python inference software stack yourself is time-consuming and encounters many issues. For the python demo, refer to the 100ASK <a href="https://wiki.dshanpi.org/docs/DshanPi-A1/AppDev/part3-3/03-3-1_SetupRKNNEnvironment" target="_blank" rel="noopener noreferrer" class="">RKNN环境搭建 | 东山Π</a>; it won't be elaborated here. Using the cpp interface, we still use the aforementioned yolov8 for on-board inference:</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="prepare-the-model">Prepare the Model<a href="https://zephyr.100ask.org/en/blog/buildroot-rknn-setup#prepare-the-model" class="hash-link" aria-label="Direct link to Prepare the Model" title="Direct link to Prepare the Model" translate="no">​</a></h3>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">cd ~/rknn/rknn_model_zoo/examples/yolov8/model</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sh download_model.sh</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">ls -lah yolov8n.onnx</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">	-rw-rw-r-- 1 ubuntu ubuntu 13M Nov 29 07:36 yolov8n.onnx</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="model-conversion">Model Conversion<a href="https://zephyr.100ask.org/en/blog/buildroot-rknn-setup#model-conversion" class="hash-link" aria-label="Direct link to Model Conversion" title="Direct link to Model Conversion" translate="no">​</a></h3>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">cd ../python/</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">(rknn-toolkit2) ubuntu@ubuntu-2204:~/rknn/rknn_model_zoo/examples/yolov8/python$ python convert.py ../model/yolov8n.onnx rk3576 i8 ../model/yolov8n.rknn</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">python convert.py ../model/yolov5s_relu.onnx rk3576 i8 ../model/yolov5s_relu.rknn </span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    I rknn-toolkit2 version: 2.3.2</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    --&gt; Config model</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    done</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    --&gt; Loading model</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    I Loading : 100%|██████████████████████████████████████████████| 126/126 [00:00&lt;00:00, 43282.74it/s]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    done</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    --&gt; Building model</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    I OpFusing 0: 100%|█████████████████████████████████████████████| 100/100 [00:00&lt;00:00, 1590.15it/s]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    I OpFusing 1 : 100%|█████████████████████████████████████████████| 100/100 [00:00&lt;00:00, 860.03it/s]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    I OpFusing 0 : 100%|█████████████████████████████████████████████| 100/100 [00:00&lt;00:00, 739.11it/s]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    I OpFusing 1 : 100%|█████████████████████████████████████████████| 100/100 [00:00&lt;00:00, 652.15it/s]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    I OpFusing 2 : 100%|█████████████████████████████████████████████| 100/100 [00:00&lt;00:00, 229.74it/s]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    W build: found outlier value, this may affect quantization accuracy</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                            const name                        abs_mean    abs_std     outlier value</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                            model.0.conv.weight               2.44        2.47        -17.494</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                            model.22.cv3.2.1.conv.weight      0.09        0.14        -10.215</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                            model.22.cv3.1.1.conv.weight      0.12        0.19        13.361, 13.317</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                            model.22.cv3.0.1.conv.weight      0.18        0.20        -11.216</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    I GraphPreparing : 100%|████████████████████████████████████████| 161/161 [00:00&lt;00:00, 3291.17it/s]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    I Quantizating : 100%|████████████████████████████████████████████| 161/161 [00:04&lt;00:00, 34.87it/s]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    W build: The default input dtype of 'images' is changed from 'float32' to 'int8' in rknn model for performance!</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                           Please take care of this change when deploy rknn model with Runtime API!</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    W build: The default output dtype of '318' is changed from 'float32' to 'int8' in rknn model for performance!</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                          Please take care of this change when deploy rknn model with Runtime API!</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    W build: The default output dtype of 'onnx::ReduceSum_326' is changed from 'float32' to 'int8' in rknn model for performance!</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                          Please take care of this change when deploy rknn model with Runtime API!</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    W build: The default output dtype of '331' is changed from 'float32' to 'int8' in rknn model for performance!</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                          Please take care of this change when deploy rknn model with Runtime API!</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    W build: The default output dtype of '338' is changed from 'float32' to 'int8' in rknn model for performance!</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                          Please take care of this change when deploy rknn model with Runtime API!</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    W build: The default output dtype of 'onnx::ReduceSum_346' is changed from 'float32' to 'int8' in rknn model for performance!</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                          Please take care of this change when deploy rknn model with Runtime API!</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    W build: The default output dtype of '350' is changed from 'float32' to 'int8' in rknn model for performance!</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                          Please take care of this change when deploy rknn model with Runtime API!</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    W build: The default output dtype of '357' is changed from 'float32' to 'int8' in rknn model for performance!</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                          Please take care of this change when deploy rknn model with Runtime API!</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    W build: The default output dtype of 'onnx::ReduceSum_365' is changed from 'float32' to 'int8' in rknn model for performance!</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                          Please take care of this change when deploy rknn model with Runtime API!</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    W build: The default output dtype of '369' is changed from 'float32' to 'int8' in rknn model for performance!</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                          Please take care of this change when deploy rknn model with Runtime API!</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    I rknn building ...</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    I rknn building done.</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    done</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    --&gt; Export rknn model</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    done</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">cd ../model</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">ls -lah yolov8n.rknn</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">	-rw-rw-r-- 1 ubuntu ubuntu 6.2M Nov 29 07:39 yolov8n.rknn</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="run-the-rknn-c-example">Run the RKNN C Example<a href="https://zephyr.100ask.org/en/blog/buildroot-rknn-setup#run-the-rknn-c-example" class="hash-link" aria-label="Direct link to Run the RKNN C Example" title="Direct link to Run the RKNN C Example" translate="no">​</a></h3>
<p>First, compile the C example, then deploy the executable file, model file, and resource files to the board.</p>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="compilation">Compilation<a href="https://zephyr.100ask.org/en/blog/buildroot-rknn-setup#compilation" class="hash-link" aria-label="Direct link to Compilation" title="Direct link to Compilation" translate="no">​</a></h4>
<p>For compilation, use the <code>build-linux.sh</code> script in the <code>rknn_model_zoo</code> directory; you need to configure the toolchain first. Modify <strong>build-linux.sh</strong>:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">GCC_COMPILER=/home/ubuntu/rk3576/prebuilts/gcc/linux-x86/aarch64/gcc-arm-10.3-2021.07-x86_64-aarch64-none-linux-gnu/bin/aarch64-none-linux-gnu</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">chmod +x ./build-linux.sh</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">./build-linux.sh -t rk3576 -a aarch64 -d yolov8</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">	-- Set runtime path of "/home/ubuntu/rknn/rknn_model_zoo/install/rk3576_linux_aarch64/rknn_yolov8_demo/./rknn_yolov8_demo" to "$ORIGIN/../lib"</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">	-- Installing: /home/ubuntu/rknn/rknn_model_zoo/install/rk3576_linux_aarch64/rknn_yolov8_demo/model/bus.jpg</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">	-- Installing: /home/ubuntu/rknn/rknn_model_zoo/install/rk3576_linux_aarch64/rknn_yolov8_demo/model/coco_80_labels_list.txt</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">	-- Installing: /home/ubuntu/rknn/rknn_model_zoo/install/rk3576_linux_aarch64/rknn_yolov8_demo/model/yolov8.rknn</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">	-- Installing: /home/ubuntu/rknn/rknn_model_zoo/install/rk3576_linux_aarch64/rknn_yolov8_demo/model/yolov8n.rknn</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">	-- Installing: /home/ubuntu/rknn/rknn_model_zoo/install/rk3576_linux_aarch64/rknn_yolov8_demo/lib/librknnrt.so</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">	-- Installing: /home/ubuntu/rknn/rknn_model_zoo/install/rk3576_linux_aarch64/rknn_yolov8_demo/lib/librga.so</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># Take a look</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">ubuntu@ubuntu-2204:~/rknn/rknn_model_zoo/install$ tree -L 4</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">.</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">└── rk3576_linux_aarch64</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    └── rknn_yolov8_demo</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        ├── lib</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        │   ├── librga.so</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        │   └── librknnrt.so</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        ├── model</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        │   ├── bus.jpg</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        │   ├── coco_80_labels_list.txt</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        │   ├── yolov8n.rknn</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        │   └── yolov8.rknn</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        ├── rknn_yolov8_demo</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        └── rknn_yolov8_demo_zero_copy</span><br></div></code></pre></div></div>
<p>This rknn_yolov8_demo is the set of files to be deployed to the board</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">adb push install/rk3576_linux_aarch64/rknn_yolov8_demo /data/</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">install/rk3576_linux_aarch64/rknn_yolov8_demo/: 8 files pushed. 3.6 MB/s (23008641 bytes in 6.049s)</span><br></div></code></pre></div></div>
<p>Run on the board side</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">root@rk3576-buildroot:/data/rknn_yolov8_demo# ./rknn_yolov8_demo ./model/yolov8.rknn ./model/bus.jpg</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    load lable ./model/coco_80_labels_list.txt</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    model input num: 1, output num: 9</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    input tensors:</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      index=0, name=images, n_dims=4, dims=[1, 640, 640, 3], n_elems=1228800, size=1228800, fmt=NHWC, type=INT8, qnt_type=AFFINE, zp=-128, scale=0.003922</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    output tensors:</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      index=0, name=318, n_dims=4, dims=[1, 64, 80, 80], n_elems=409600, size=409600, fmt=NCHW, type=INT8, qnt_type=AFFINE, zp=-58, scale=0.117659</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      index=1, name=onnx::ReduceSum_326, n_dims=4, dims=[1, 80, 80, 80], n_elems=512000, size=512000, fmt=NCHW, type=INT8, qnt_type=AFFINE, zp=-128, scale=0.003104</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      index=2, name=331, n_dims=4, dims=[1, 1, 80, 80], n_elems=6400, size=6400, fmt=NCHW, type=INT8, qnt_type=AFFINE, zp=-128, scale=0.003173</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      index=3, name=338, n_dims=4, dims=[1, 64, 40, 40], n_elems=102400, size=102400, fmt=NCHW, type=INT8, qnt_type=AFFINE, zp=-45, scale=0.093747</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      index=4, name=onnx::ReduceSum_346, n_dims=4, dims=[1, 80, 40, 40], n_elems=128000, size=128000, fmt=NCHW, type=INT8, qnt_type=AFFINE, zp=-128, scale=0.003594</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      index=5, name=350, n_dims=4, dims=[1, 1, 40, 40], n_elems=1600, size=1600, fmt=NCHW, type=INT8, qnt_type=AFFINE, zp=-128, scale=0.003627</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      index=6, name=357, n_dims=4, dims=[1, 64, 20, 20], n_elems=25600, size=25600, fmt=NCHW, type=INT8, qnt_type=AFFINE, zp=-34, scale=0.083036</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      index=7, name=onnx::ReduceSum_365, n_dims=4, dims=[1, 80, 20, 20], n_elems=32000, size=32000, fmt=NCHW, type=INT8, qnt_type=AFFINE, zp=-128, scale=0.003874</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      index=8, name=369, n_dims=4, dims=[1, 1, 20, 20], n_elems=400, size=400, fmt=NCHW, type=INT8, qnt_type=AFFINE, zp=-128, scale=0.003922</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    model is NHWC input fmt</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    model input height=640, width=640, channel=3</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    origin size=640x640 crop size=640x640</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    input image: 640 x 640, subsampling: 4:2:0, colorspace: YCbCr, orientation: 1</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    scale=1.000000 dst_box=(0 0 639 639) allow_slight_change=1 _left_offset=0 _top_offset=0 padding_w=0 padding_h=0</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    rga_api version 1.10.1_[0]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    rknn_run</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    person @ (211 241 282 507) 0.864</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    person @ (109 235 225 536) 0.856</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    bus @ (99 136 552 455) 0.856</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    person @ (476 223 560 521) 0.848</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    person @ (80 326 116 513) 0.280</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    write_image path: out.png width=640 height=640 channel=3 data=0x3e2e9200</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div></code></pre></div></div>
<p>View on the PC side</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">adb pull /data/rknn_yolov8_demo/out.png ./</span><br></div></code></pre></div></div>
<p>Matches expectations</p>
<p>At this point, the RKNN environment has been set up successfully</p>]]></content:encoded>
            <category>RKNN</category>
            <category>Buildroot</category>
            <category>NPU</category>
            <category>RK3576</category>
        </item>
        <item>
            <title><![CDATA[DshanPI-A1 Weston Multi-Screen Configuration]]></title>
            <link>https://zephyr.100ask.org/en/blog/weston-multi-screen</link>
            <guid>https://zephyr.100ask.org/en/blog/weston-multi-screen</guid>
            <pubDate>Fri, 14 Nov 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[Configure multi-screen display on RK3576 with Weston, implementing mirrored and extended display.]]></description>
            <content:encoded><![CDATA[<p>In embedded system development, display configuration is the foundation for implementing user interfaces. Weston, as the reference implementation of the Wayland compositor, is widely used in embedded devices and desktop environments. Faced with different hardware configurations and application scenarios, precise control of display output is required. Below, based on the DshanPI-A1 buildroot firmware version, we provide Weston configuration methods for three typical scenarios: single-screen exclusive, dual-screen mirrored, and dual-screen extended display, along with a detailed operation guide.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="weston-architecture-and-configuration-principles">Weston Architecture and Configuration Principles<a href="https://zephyr.100ask.org/en/blog/weston-multi-screen#weston-architecture-and-configuration-principles" class="hash-link" aria-label="Direct link to Weston Architecture and Configuration Principles" title="Direct link to Weston Architecture and Configuration Principles" translate="no">​</a></h2>
<p>Before configuration, it helps to briefly understand the basic principles.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="weston-display-system-architecture">Weston Display System Architecture<a href="https://zephyr.100ask.org/en/blog/weston-multi-screen#weston-display-system-architecture" class="hash-link" aria-label="Direct link to Weston Display System Architecture" title="Direct link to Weston Display System Architecture" translate="no">​</a></h3>
<p>Weston adopts a modular design; its core components include:</p>
<ul>
<li class=""><strong>Backend</strong>: Responsible for interacting with the underlying graphics system, such as DRM, X11, Wayland, etc.</li>
<li class=""><strong>Compositor</strong>: Manages window compositing, rendering, and output</li>
<li class=""><strong>Shell</strong>: Provides the user interface framework, such as desktop, panel, etc.</li>
</ul>
<p>In embedded systems, the DRM backend drm-backend.so is typically used; it directly interacts with the Linux kernel's Direct Rendering Manager, providing efficient hardware acceleration support.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="configuration-file-structure">Configuration File Structure<a href="https://zephyr.100ask.org/en/blog/weston-multi-screen#configuration-file-structure" class="hash-link" aria-label="Direct link to Configuration File Structure" title="Direct link to Configuration File Structure" translate="no">​</a></h3>
<p>Weston's main configuration file is located at <code>/etc/xdg/weston/weston.ini</code> and is organized in INI format. The key configuration sections include:</p>
<ul>
<li class=""><code>[core]</code>: Core configuration, defines backend behavior and global parameters</li>
<li class=""><code>[output]</code>: Display output configuration, controls the properties of each physical interface</li>
<li class=""><code>[shell]</code>: Desktop environment related settings</li>
<li class=""><code>[libinput]</code>: Input device configuration</li>
<li class=""><code>[device]</code>: Advanced configuration for specific devices</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="hdmi-exclusive-display-configuration">HDMI Exclusive Display Configuration<a href="https://zephyr.100ask.org/en/blog/weston-multi-screen#hdmi-exclusive-display-configuration" class="hash-link" aria-label="Direct link to HDMI Exclusive Display Configuration" title="Direct link to HDMI Exclusive Display Configuration" translate="no">​</a></h2>
<p>In some embedded application scenarios, the device needs to force the HDMI interface as the only display output while disabling the built-in screen (such as the DSI-interface LCD). This configuration is common in:</p>
<ul>
<li class="">Industrial consoles permanently connected to external monitors</li>
<li class="">Digital signage systems using large-screen displays</li>
<li class="">Professional applications requiring high-resolution output</li>
</ul>
<p>The following is the detailed configuration:</p>
<p><strong>First, configure the environment variables</strong></p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">export WESTON_DRM_MIRROR=false</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">export WESTON_DRM_PREFER_EXTERNAL=0</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">export WESTON_DRM_SINGLE_HEAD=0</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">export WESTON_DRM_MASTER_OUTPUT="HDMI-A-1"</span><br></div></code></pre></div></div>
<p><strong>Then write to /etc/xdg/weston/weston.ini</strong></p>
<div class="language-ini codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-ini codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">[core]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">backend=drm-backend.so</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">require-input=true         # Must connect an input device to start</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">require-outputs=true       # Must detect output devices</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">idle-time=0                # Disable screen sleep</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">repaint-window=16          # Repaint window, ~60Hz refresh rate</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># Disable auto-detection</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">use-udev=false             # Turn off udev auto-detection, manually control output</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[output]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">name=HDMI-A-1             # Specify the HDMI-A-1 interface</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">mode=1920x1080@60         # 1080p resolution, 60Hz refresh rate</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">transform=normal          # No rotation transform</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">scale=1.5                 # 150% scaling, adapts to high DPI</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># Disable DSI interface</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[output]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">name=DSI-1</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">mode=off                  # Turn off this output</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[shell]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">panel-scale=2             # Panel elements 200% scaling</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">cursor-size=32            # Mouse pointer size</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">locking=false             # Disable screen locking</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">startup-animation=none    # Disable startup animation</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[keyboard]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">vt-switching=true         # Allow virtual terminal switching</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[libinput]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">touchscreen_calibrator=true  # Enable touchscreen calibration</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">enable-tap=true           	 # Enable tap gesture</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">natural-scroll=true          # Natural scroll direction</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[device]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">name=wch.cn USB2IIC_CTP_CONTROL   # Specific touch device</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">rotation=normal                   # Normal orientation</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="test">Test<a href="https://zephyr.100ask.org/en/blog/weston-multi-screen#test" class="hash-link" aria-label="Direct link to Test" title="Direct link to Test" translate="no">​</a></h3>
<p>Boot</p>
<p>Run 3D test</p>
<p>In practical applications, the DSI driver output should be turned off</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="tips-note-theres-a-pitfall-here-that-prevented-my-hdmi-screen-from-starting-at-first">Tips: Note, there's a pitfall here that prevented my HDMI screen from starting at first<a href="https://zephyr.100ask.org/en/blog/weston-multi-screen#tips-note-theres-a-pitfall-here-that-prevented-my-hdmi-screen-from-starting-at-first" class="hash-link" aria-label="Direct link to Tips: Note, there's a pitfall here that prevented my HDMI screen from starting at first" title="Direct link to Tips: Note, there's a pitfall here that prevented my HDMI screen from starting at first" translate="no">​</a></h3>
<p>Look at this Weston startup output log:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">root@rk3576-buildroot:/# weston</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Date: 2025-12-03 UTC</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">..........</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[03:20:26.528] Output HDMI-A-1 (crtc 72) video modes:</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">               1024x600@59.8, preferred, 50.2 MHz</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">               1920x1080@60.0 16:9, 148.5 MHz</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">               1920x1080@59.9 16:9, 148.4 MHz</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">               1920x1080i@60.0, 74.2 MHz</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">               1920x1080i@60.0 16:9, 74.2 MHz</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">               1920x1080i@59.9 16:9, 74.2 MHz</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">               1920x1080@50.0, current, 148.5 MHz</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">               1920x1080@50.0 16:9, 148.5 MHz</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">               1920x1080i@50.0, 74.2 MHz</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">               1920x1080i@50.0 16:9, 74.2 MHz</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">               1280x1024@75.0, 135.0 MHz</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">               1280x720@60.0 16:9, 74.2 MHz</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">               1280x720@59.9 16:9, 74.2 MHz</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">               1280x720@50.0, 74.2 MHz</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">               1280x720@50.0 16:9, 74.2 MHz</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">               1024x768@75.0, 78.8 MHz</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">               1024x768@70.1, 75.0 MHz</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">               1024x768@60.0, 65.0 MHz</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">               832x624@74.6, 57.3 MHz</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">               800x600@75.0, 49.5 MHz</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">               800x600@72.2, 50.0 MHz</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">               800x600@60.3, 40.0 MHz</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">               800x600@56.2, 36.0 MHz</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">               720x576@50.0, 27.0 MHz</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">               720x576@50.0 4:3, 27.0 MHz</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">               720x576@50.0 16:9, 27.0 MHz</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">               720x480@60.0 4:3, 27.0 MHz</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">               720x480@60.0 16:9, 27.0 MHz</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">               720x480@59.9 4:3, 27.0 MHz</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">               720x480@59.9 16:9, 27.0 MHz</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">               640x480@75.0, 31.5 MHz</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">               640x480@72.8, 31.5 MHz</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">               640x480@60.0 4:3, 25.2 MHz</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">               640x480@59.9, 25.2 MHz</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">               720x400@70.1, 28.3 MHz</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">.....</span><br></div></code></pre></div></div>
<p>Note this resolution</p>
<p>1024x600@59.8, preferred, 50.2 MHz is my screen's actual physical resolution and the default configuration. If you directly configure</p>
<div class="language-ini codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-ini codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain"># Force-specify output</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[output]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">name=HDMI-A-1</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">#mode=1920x1080@50</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">mode=1024x600@59.8</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">transform=normal</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">scale=1.5</span><br></div></code></pre></div></div>
<p>At startup:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">xkbcommon: ERROR: couldn't find a Compose file for locale "en_US.UTF-8" (mapped to "en_US.UTF-8")</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">could not create XKB compose table for locale 'en_US.UTF-8'.  Disabiling compose</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">xkbcommon: ERROR: couldn't find a Compose file for locale "en_US.UTF-8" (mapped to "en_US.UTF-8")</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">could not create XKB compose table for locale 'en_US.UTF-8'.  Disabiling compose</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[  695.260819] dwhdmi-rockchip 27da0000.hdmi: use tmds mode</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[  695.279593] rockchip-vop2 27d00000.vop: [drm:vop2_crtc_atomic_enable] Update mode to 1024x600p60, type: 11(if:HDMI0, flag:0x0) for vp0 dclk: 50250000</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[  695.279636] rockchip-hdptx-phy-hdmi 2b000000.hdmiphy: hdptx_ropll_cmn_config bus_width:7aae4 rate:1485000</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[  695.279810] rockchip-hdptx-phy-hdmi 2b000000.hdmiphy: hdptx phy pll locked!</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[  695.279872] rockchip-hdptx-phy-hdmi 2b000000.hdmiphy: hdptx_ropll_cmn_config bus_width:7aae4 rate:502500</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[  695.280061] rockchip-hdptx-phy-hdmi 2b000000.hdmiphy: hdptx phy pll locked!</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[  695.280069] rockchip-vop2 27d00000.vop: [drm:vop2_crtc_atomic_enable] set dclk_vp0 to 50250000, get 50250000</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[  695.280120] dwhdmi-rockchip 27da0000.hdmi: final tmdsclk = 50250000</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[  695.280189] dwhdmi-rockchip 27da0000.hdmi: don't use dsc mode</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[  695.280198] dwhdmi-rockchip 27da0000.hdmi: dw hdmi qp use tmds mode</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[  695.280206] rockchip-hdptx-phy-hdmi 2b000000.hdmiphy: bus_width:0x7aae4,bit_rate:502500</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[  695.285263] rockchip-hdptx-phy-hdmi 2b000000.hdmiphy: hdptx phy lane can't ready!</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[  695.285271] phy phy-2b000000.hdmiphy.4: phy poweron failed --&gt; -22</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[  695.285278] dwhdmi-rockchip 27da0000.hdmi: dw_hdmi_qp_setup hdmi set operation mode failed</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[  695.285317] dwhdmi-rockchip 27da0000.hdmi: Rate 50250000 missing; compute N dynamically</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[  695.286726] dwhdmi-rockchip 27da0000.hdmi: Rate 50250000 missing; compute N dynamically</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[  695.315462] dwhdmi-rockchip 27da0000.hdmi: use tmds mode</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div></code></pre></div></div>
<p>Note:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">[  695.285263] rockchip-hdptx-phy-hdmi 2b000000.hdmiphy: hdptx phy lane can't ready!</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[  695.285271] phy phy-2b000000.hdmiphy.4: phy poweron failed --&gt; -22</span><br></div></code></pre></div></div>
<p><strong>The screen cannot start, so here's a lesson learned:</strong></p>
<p><strong>When testing a screen, the physical resolution may be incompatible; you need to test multiple resolutions to find a compatible one.</strong></p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="key-configuration-points">Key Configuration Points<a href="https://zephyr.100ask.org/en/blog/weston-multi-screen#key-configuration-points" class="hash-link" aria-label="Direct link to Key Configuration Points" title="Direct link to Key Configuration Points" translate="no">​</a></h3>
<p><strong>Importance of use-udev=false</strong>:
By default, Weston auto-detects all connected display devices via udev. When set to <code>false</code>, Weston will only use the outputs explicitly specified in the configuration file, providing the basis for precise control.</p>
<p><strong>Output Priority Control</strong>:
When multiple <code>[output]</code> sections exist, Weston processes them in the order they appear in the configuration file. Placing the outputs to be disabled after the active output and setting <code>mode=off</code> ensures correct display control.</p>
<p><strong>Scaling Configuration Strategy</strong>:
Embedded devices often need to adjust the physical size of UI elements. The <code>scale</code> parameter allows you to independently control the scaling ratio of each output, which is especially important when connecting monitors with different DPIs.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="dsi-exclusive-mode">DSI Exclusive Mode<a href="https://zephyr.100ask.org/en/blog/weston-multi-screen#dsi-exclusive-mode" class="hash-link" aria-label="Direct link to DSI Exclusive Mode" title="Direct link to DSI Exclusive Mode" translate="no">​</a></h2>
<p>Opposite to HDMI exclusive, some applications need to use only the device's built-in screen, such as:</p>
<ul>
<li class="">Mobile devices or portable instruments</li>
<li class="">Battery-powered devices that conserve power</li>
<li class="">Application scenarios that don't need external displays</li>
</ul>
<p><strong>/etc/xdg/weston/weston.ini</strong></p>
<div class="language-ini codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-ini codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">[core]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">backend=drm-backend.so</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># Allow running without input devices</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">require-input=false</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># Allow running without output devices</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">require-outputs=none</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># Disable screen idle timeout by default</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">idle-time=0</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># Key: Disable auto-detection of all connections</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">use-udev=false</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># The repaint-window is used to calculate repaint delay(ms) after flipped.</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">#   value &lt;= 0: delay = abs(value)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">#   value &gt; 0: delay = vblank_duration - value</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">repaint-window=-1</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># Allow blending with lower drm planes</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># gbm-format=argb8888</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[shell]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># top(default)|bottom|left|right|none, none to disable panel</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># panel-position=none</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># Scale panel size</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">panel-scale=2</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># Set cursor size</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">cursor-size=32</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># none|minutes(default)|minutes-24h|seconds|seconds-24h</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># clock-format=minutes-24h</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">clock-with-date=false</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># Disable screen locking</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">locking=false</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># Disable the desktop starting up animation</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">startup-animation=none</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[libinput]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># Uncomment below to enable touch screen calibrator(weston-touch-calibrator)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># touchscreen_calibrator=true</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># calibration_helper=/bin/weston-calibration-helper.sh</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[keyboard]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># Comment this to enable vt switching</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">vt-switching=false</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># Configs for auto key repeat</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># repeat-rate=40</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># repeat-delay=400</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[output]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">name=DSI-1</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">mode=480x800</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">transform=rotate-180</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">scale=0.2</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># Explicitly disable DSI-1</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[output]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">name=HDMI-A-1</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">mode=off</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="test-1">Test<a href="https://zephyr.100ask.org/en/blog/weston-multi-screen#test-1" class="hash-link" aria-label="Direct link to Test" title="Direct link to Test" translate="no">​</a></h3>
<p>Boot</p>
<p>Run 3D test</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="key-points">Key Points<a href="https://zephyr.100ask.org/en/blog/weston-multi-screen#key-points" class="hash-link" aria-label="Direct link to Key Points" title="Direct link to Key Points" translate="no">​</a></h3>
<p><strong>Rotation Configuration</strong>:
The screen mounting orientation of embedded devices may differ. The <code>transform</code> parameter supports multiple rotation options:</p>
<ul>
<li class=""><code>normal</code>: No rotation</li>
<li class=""><code>rotate-90</code>: 90 degrees clockwise</li>
<li class=""><code>rotate-180</code>: 180 degrees</li>
<li class=""><code>rotate-270</code>: 270 degrees clockwise</li>
<li class=""><code>flipped</code>: Horizontal flip</li>
<li class=""><code>flipped-rotate-180</code>: Combined transform</li>
</ul>
<p><strong>DPI Adaptation Strategy</strong>:
Small, high-resolution screens require appropriate UI scaling. By experimenting with different <code>scale</code> values, find a UI element size with suitable physical dimensions. This configuration uses 0.2 (20%) scaling to ensure UI elements can be operated normally at 480x800 resolution.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="dual-screen-mirrored-display">Dual-Screen Mirrored Display<a href="https://zephyr.100ask.org/en/blog/weston-multi-screen#dual-screen-mirrored-display" class="hash-link" aria-label="Direct link to Dual-Screen Mirrored Display" title="Direct link to Dual-Screen Mirrored Display" translate="no">​</a></h2>
<p>Dual-screen mirrored display (mirror mode) is suitable for:</p>
<ul>
<li class="">Demonstration and teaching scenarios</li>
<li class="">Synchronized display between the main console and an observation screen</li>
<li class="">Troubleshooting and debugging</li>
</ul>
<p><strong>/etc/xdg/weston/weston.ini</strong></p>
<div class="language-ini codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-ini codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">[core]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">backend=drm-backend.so</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">require-input=true</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">require-outputs=true</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">idle-time=0</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">repaint-window=16</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">mode=mirror</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">use-udev=true  # Dual-screen requires udev enabled</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[output]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">name=HDMI-A-1</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">mode=1920x1080</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">transform=rotate-270</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">scale=0.25</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[output]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">name=DSI-1</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">mode=1920x1080</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">transform=rotate-270</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">scale=0.25</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[shell]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">panel-scale=2</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">cursor-size=32</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">locking=false</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">startup-animation=none</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[keyboard]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">vt-switching=true</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[libinput]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">touchscreen_calibrator=true</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">enable-tap=true</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">natural-scroll=true</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># Key fix: explicitly bind the touch device to HDMI output</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[device]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">name=wch.cn USB2IIC_CTP_CONTROL</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">output=HDMI-A-1  # Explicitly specify the HDMI screen</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">rotation=normal  # Adjust according to actual orientation</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="test-2">Test<a href="https://zephyr.100ask.org/en/blog/weston-multi-screen#test-2" class="hash-link" aria-label="Direct link to Test" title="Direct link to Test" translate="no">​</a></h3>
<p>Boot</p>
<p>Run 3D test</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="key-points-1">Key Points<a href="https://zephyr.100ask.org/en/blog/weston-multi-screen#key-points-1" class="hash-link" aria-label="Direct link to Key Points" title="Direct link to Key Points" translate="no">​</a></h3>
<p><strong>Resolution Alignment</strong>:
In mirror mode, the two outputs should use the same resolution; otherwise Weston will display at the lower resolution or scaled. This configuration uniformly uses 1920x1080 to ensure consistent display content.</p>
<p><strong>Touch Input Binding</strong>:
In a multi-screen environment, touch input needs to be explicitly bound to a specific screen. The <code>output=HDMI-A-1</code> configuration ensures touch operations only affect the HDMI display, avoiding confusion in mirror mode.</p>
<p><strong>Performance Optimization Considerations</strong>:
Mirror mode requires the compositor to render the same content twice, which has some impact on system performance. Properly adjusting the <code>repaint-window</code> parameter can balance smoothness and system load.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="dual-screen-extended-display">Dual-Screen Extended Display<a href="https://zephyr.100ask.org/en/blog/weston-multi-screen#dual-screen-extended-display" class="hash-link" aria-label="Direct link to Dual-Screen Extended Display" title="Direct link to Dual-Screen Extended Display" translate="no">​</a></h2>
<p>Dual-screen extended display (extend mode) is suitable for:</p>
<ul>
<li class="">Multi-tasking work environments</li>
<li class="">Separation of control panel and data display</li>
<li class="">Complex professional application interfaces</li>
</ul>
<p>The following is the configuration</p>
<p><strong>weston.ini configuration</strong></p>
<div class="language-ini codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-ini codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">[core]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">backend=drm-backend.so</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">require-input=true</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">require-outputs=true</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">idle-time=0</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">repaint-window=16</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">mode=extend  # Key: change to extend mode</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">use-udev=true</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># HDMI screen (right side)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[output]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">name=HDMI-A-1</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">mode=1920x1080</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">transform=rotate-270</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">scale=0.25</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">x=200  # DSI on the left, starting from DSI width</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">y=0</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># DSI screen (left side)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[output]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">name=DSI-1</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">mode=480x800</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">transform=rotate-270</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">scale=0.25</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">x=0</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">y=0</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[shell]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">panel-scale=2</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">cursor-size=32</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">locking=false</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">startup-animation=none</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[keyboard]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">vt-switching=true</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[libinput]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">touchscreen_calibrator=true</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">enable-tap=true</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">natural-scroll=true</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[device]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">name=wch.cn USB2IIC_CTP_CONTROL</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">output=HDMI-A-1  # Touch bound to HDMI screen</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">rotation=normal</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="test-3">Test<a href="https://zephyr.100ask.org/en/blog/weston-multi-screen#test-3" class="hash-link" aria-label="Direct link to Test" title="Direct link to Test" translate="no">​</a></h3>
<p>At startup</p>
<p>Need to set environment variables to turn off mirror mode</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain"># Environment variables</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">export WESTON_DRM_MIRROR=0         # Turn off mirror mode</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">export WESTON_DRM_PREFER_EXTERNAL=0 # Don't prefer external display</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">export WESTON_DRM_SINGLE_HEAD=0     # Enable multi-head support</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">pkill weston</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">weston &amp;</span><br></div></code></pre></div></div>
<p>After startup, the system recognizes two independent monitors, and the desktop can extend across screens. Each screen can run different applications, achieving a true multi-tasking environment.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="key-points-2">Key Points<a href="https://zephyr.100ask.org/en/blog/weston-multi-screen#key-points-2" class="hash-link" aria-label="Direct link to Key Points" title="Direct link to Key Points" translate="no">​</a></h3>
<p><strong>Screen Layout Control</strong>:
Weston's default screen layout may not match the actual physical layout. You can optimize it via the position parameters in <code>weston.ini</code> or by manually adjusting after startup.</p>
<p><strong>Cross-Screen Window Management</strong>:
In extend mode, windows can be moved between screens. You need to ensure the window manager and applications support the multi-screen environment.</p>
<p><strong>Performance Considerations</strong>:
Extend mode demands more graphics performance, especially when the two screens have very different resolutions. Rendering settings need to be adjusted based on hardware capabilities.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="summary">Summary<a href="https://zephyr.100ask.org/en/blog/weston-multi-screen#summary" class="hash-link" aria-label="Direct link to Summary" title="Direct link to Summary" translate="no">​</a></h2>
<p>Although Weston multi-screen configuration has some complexity, by deeply understanding its configuration principles and mastering the key parameters, you can achieve highly customized display solutions. Whether single-screen exclusive, dual-screen mirrored, or dual-screen extended, you need to comprehensively consider hardware characteristics, application requirements, and user experience.</p>
<p>In the actual configuration process, it is recommended to take an incremental testing approach: <strong>start from the basic configuration, verify individual functions, then gradually add complex features.</strong></p>]]></content:encoded>
            <category>Weston</category>
            <category>Multi-screen</category>
            <category>Wayland</category>
            <category>RK3576</category>
        </item>
        <item>
            <title><![CDATA[DshanPI-A1 RK3576 GStreamer Playing 16-Channel Video with Hardware Acceleration]]></title>
            <link>https://zephyr.100ask.org/en/blog/gstreamer-16ch-hw-acceleration</link>
            <guid>https://zephyr.100ask.org/en/blog/gstreamer-16ch-hw-acceleration</guid>
            <pubDate>Wed, 12 Nov 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[Playing 16-channel video with hardware decoding on RK3576 using GStreamer, fully utilizing MPP hardware acceleration.]]></description>
            <content:encoded><![CDATA[<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="demo-video">Demo Video<a href="https://zephyr.100ask.org/en/blog/gstreamer-16ch-hw-acceleration#demo-video" class="hash-link" aria-label="Direct link to Demo Video" title="Direct link to Demo Video" translate="no">​</a></h2>
<p><a href="https://www.bilibili.com/video/BV1m34VziE2s" target="_blank" rel="noopener noreferrer" class="">https://www.bilibili.com/video/BV1m34VziE2s</a></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="1-experiment-environment">1. Experiment Environment<a href="https://zephyr.100ask.org/en/blog/gstreamer-16ch-hw-acceleration#1-experiment-environment" class="hash-link" aria-label="Direct link to 1. Experiment Environment" title="Direct link to 1. Experiment Environment" translate="no">​</a></h2>
<table><thead><tr><th>Category</th><th>Configuration</th></tr></thead><tbody><tr><td>Board</td><td>DshanPI-A1</td></tr><tr><td>SoC</td><td>RK3576</td></tr><tr><td>Operating System</td><td>Armbian</td></tr><tr><td>Desktop</td><td>GNOME</td></tr><tr><td>Window System</td><td>Wayland</td></tr><tr><td>GPU Driver</td><td>Panfrost</td></tr></tbody></table>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="core-hardware-acceleration-units">Core Hardware Acceleration Units<a href="https://zephyr.100ask.org/en/blog/gstreamer-16ch-hw-acceleration#core-hardware-acceleration-units" class="hash-link" aria-label="Direct link to Core Hardware Acceleration Units" title="Direct link to Core Hardware Acceleration Units" translate="no">​</a></h3>
<p>The RK3576 chip integrates three key hardware acceleration units, each responsible for different stages of video processing:</p>
<ul>
<li class="">
<p><strong>VPU (Video Processing Unit)</strong>: Responsible for video decoding (e.g., H.264 hardware decoding); the core element <code>mppvideodec</code> invokes this unit.</p>
</li>
<li class="">
<p><strong>RGA (Image Acceleration Unit)</strong>: Responsible for image scaling and format conversion (e.g., NV12→RGBA); can be enabled via <code>mppvideodec</code> parameters.</p>
</li>
<li class="">
<p><strong>GPU (Graphics Processing Unit)</strong>: Responsible for video rendering and multi-frame compositing (e.g., <code>glvideomixer</code> compositing); managed by the Panfrost driver.</p>
</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="2-installing-gstreamer-tools-and-plugins">2. Installing GStreamer Tools and Plugins<a href="https://zephyr.100ask.org/en/blog/gstreamer-16ch-hw-acceleration#2-installing-gstreamer-tools-and-plugins" class="hash-link" aria-label="Direct link to 2. Installing GStreamer Tools and Plugins" title="Direct link to 2. Installing GStreamer Tools and Plugins" translate="no">​</a></h2>
<p>Run the following commands to install the full set of GStreamer tools and RK3576 hardware acceleration plugins:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain"># Basic tools (gst-launch-1.0, etc.)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sudo apt install -y gstreamer1.0-tools</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># Base plugin set (audio/video base functionality)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sudo apt install -y gstreamer1.0-plugins-base</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sudo apt install -y gstreamer1.0-plugins-good</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sudo apt install -y gstreamer1.0-plugins-bad</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># FFmpeg integration plugin (software decoding fallback)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sudo apt install -y gstreamer1.0-libav</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># RK3576 hardware acceleration plugin (VPU/RGA support)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sudo apt install -y gstreamer1.0-rockchip1</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># GPU rendering dependency (glvideomixer, etc.)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sudo apt install -y libgstreamer-gl1.0-0</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="3-basic-hardware-decoding-playback-practice">3. Basic Hardware Decoding Playback Practice<a href="https://zephyr.100ask.org/en/blog/gstreamer-16ch-hw-acceleration#3-basic-hardware-decoding-playback-practice" class="hash-link" aria-label="Direct link to 3. Basic Hardware Decoding Playback Practice" title="Direct link to 3. Basic Hardware Decoding Playback Practice" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="1-minimal-hardware-decoding-command">1. Minimal Hardware Decoding Command<a href="https://zephyr.100ask.org/en/blog/gstreamer-16ch-hw-acceleration#1-minimal-hardware-decoding-command" class="hash-link" aria-label="Direct link to 1. Minimal Hardware Decoding Command" title="Direct link to 1. Minimal Hardware Decoding Command" translate="no">​</a></h3>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">gst-launch-1.0 filesrc location=/root/bad_apple.mp4 ! qtdemux ! h264parse ! mppvideodec ! waylandsink</span><br></div></code></pre></div></div>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="pipeline-breakdown">Pipeline Breakdown<a href="https://zephyr.100ask.org/en/blog/gstreamer-16ch-hw-acceleration#pipeline-breakdown" class="hash-link" aria-label="Direct link to Pipeline Breakdown" title="Direct link to Pipeline Breakdown" translate="no">​</a></h4>
<table><thead><tr><th>Element</th><th>Function</th></tr></thead><tbody><tr><td><code>filesrc</code></td><td>Reads a local video file (replace with the actual path, e.g., <code>/root/bad_apple.mp4</code>)</td></tr><tr><td><code>qtdemux</code></td><td>Demuxes the MP4 file, separating video and audio streams (MP4 is a QuickTime container format)</td></tr><tr><td><code>h264parse</code></td><td>Parses the H.264 stream, converting AVCC format in MP4 to the Annex B raw stream supported by the decoder</td></tr><tr><td><code>mppvideodec</code></td><td>Invokes RK3576 VPU hardware decoding, outputting NV12 format images (the default hardware decoding format)</td></tr><tr><td><code>waylandsink</code></td><td>Invokes GPU rendering to display the video in a Wayland window (automatically converts NV12 to RGB format)</td></tr></tbody></table>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="2-additional-notes-on-key-stages">2. Additional Notes on Key Stages<a href="https://zephyr.100ask.org/en/blog/gstreamer-16ch-hw-acceleration#2-additional-notes-on-key-stages" class="hash-link" aria-label="Direct link to 2. Additional Notes on Key Stages" title="Direct link to 2. Additional Notes on Key Stages" translate="no">​</a></h3>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="1-demuxing-and-stream-parsing">(1) Demuxing and Stream Parsing<a href="https://zephyr.100ask.org/en/blog/gstreamer-16ch-hw-acceleration#1-demuxing-and-stream-parsing" class="hash-link" aria-label="Direct link to (1) Demuxing and Stream Parsing" title="Direct link to (1) Demuxing and Stream Parsing" translate="no">​</a></h4>
<ul>
<li class="">
<p>An MP4 file is a "container"; you need <code>qtdemux</code> to separate the internal video stream (H.264) and audio stream.</p>
</li>
<li class="">
<p>H.264 streams come in two formats: MP4 uses <strong>AVCC format</strong> by default, while the hardware decoder only supports <strong>Annex B raw stream</strong>, so <code>h264parse</code> must perform the conversion.</p>
</li>
</ul>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="2-decoding">(2) Decoding<a href="https://zephyr.100ask.org/en/blog/gstreamer-16ch-hw-acceleration#2-decoding" class="hash-link" aria-label="Direct link to (2) Decoding" title="Direct link to (2) Decoding" translate="no">​</a></h4>
<ul>
<li class="">H.264 decoding produces NV12 images.
In systems without hardware decoding, the <code>avdec_h264</code> element can be used instead.
<code>avdec_h264</code> invokes the FFmpeg software decoder.
It can also be used to compare the performance gap between hardware and software decoding.</li>
</ul>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="3-rendering-wayland-vs-x11">(3) Rendering (Wayland vs X11)<a href="https://zephyr.100ask.org/en/blog/gstreamer-16ch-hw-acceleration#3-rendering-wayland-vs-x11" class="hash-link" aria-label="Direct link to (3) Rendering (Wayland vs X11)" title="Direct link to (3) Rendering (Wayland vs X11)" translate="no">​</a></h4>
<ul>
<li class="">In the Wayland window system, NV12 images can be passed in directly, and the GPU is automatically invoked to convert them to RGB for rendering display.
In the X11 window system, an additional element is needed to convert NV12 images to RGB before rendering.
Since the Wayland window system is used here, the rendering element is <code>waylandsink</code>.
For X11, you would use <code>xvimagesink</code> or <code>glimagesink</code>.</li>
</ul>
<table><thead><tr><th>Window System</th><th>Rendering Element</th><th>Supported Input Formats</th><th>Additional Notes</th></tr></thead><tbody><tr><td>Wayland</td><td><code>waylandsink</code></td><td>NV12, RGBA/BGRA</td><td>Automatically uses GPU to convert NV12→RGB for rendering</td></tr><tr><td>X11</td><td><code>xvimagesink</code></td><td>RGB/RGBA (NV12 not supported)</td><td>Requires RGA/GPU to convert the format in advance</td></tr><tr><td>X11</td><td><code>glimagesink</code></td><td>RGB/RGBA (NV12 not supported)</td><td>Depends on GPU for format conversion, performance better than XV</td></tr></tbody></table>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="3-hardware-load-monitoring-commands">3. Hardware Load Monitoring Commands<a href="https://zephyr.100ask.org/en/blog/gstreamer-16ch-hw-acceleration#3-hardware-load-monitoring-commands" class="hash-link" aria-label="Direct link to 3. Hardware Load Monitoring Commands" title="Direct link to 3. Hardware Load Monitoring Commands" translate="no">​</a></h3>
<p>Use the following commands to monitor VPU/RGA/GPU usage in real time (it is recommended to use <code>tmux</code> to split panes for simultaneous viewing):</p>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="1-view-rga-usage">(1) View RGA Usage<a href="https://zephyr.100ask.org/en/blog/gstreamer-16ch-hw-acceleration#1-view-rga-usage" class="hash-link" aria-label="Direct link to (1) View RGA Usage" title="Direct link to (1) View RGA Usage" translate="no">​</a></h4>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">watch -n 1 cat /sys/kernel/debug/rkrga/load</span><br></div></code></pre></div></div>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="2-view-gpu-usage-panfrost-driver">(2) View GPU Usage (Panfrost Driver)<a href="https://zephyr.100ask.org/en/blog/gstreamer-16ch-hw-acceleration#2-view-gpu-usage-panfrost-driver" class="hash-link" aria-label="Direct link to (2) View GPU Usage (Panfrost Driver)" title="Direct link to (2) View GPU Usage (Panfrost Driver)" translate="no">​</a></h4>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">watch -n 1 cat /sys/class/devfreq/27800000.gpu/load</span><br></div></code></pre></div></div>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="3-view-gpu-usage-official-mali-driver-optional">(3) View GPU Usage (Official Mali Driver, Optional)<a href="https://zephyr.100ask.org/en/blog/gstreamer-16ch-hw-acceleration#3-view-gpu-usage-official-mali-driver-optional" class="hash-link" aria-label="Direct link to (3) View GPU Usage (Official Mali Driver, Optional)" title="Direct link to (3) View GPU Usage (Official Mali Driver, Optional)" translate="no">​</a></h4>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">watch -n 1 cat /sys/devices/platform/fb000000.gpu/utilisation</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="4-application-scenarios-for-rga-hardware-acceleration">4. Application Scenarios for RGA Hardware Acceleration<a href="https://zephyr.100ask.org/en/blog/gstreamer-16ch-hw-acceleration#4-application-scenarios-for-rga-hardware-acceleration" class="hash-link" aria-label="Direct link to 4. Application Scenarios for RGA Hardware Acceleration" title="Direct link to 4. Application Scenarios for RGA Hardware Acceleration" translate="no">​</a></h2>
<p>RGA is mainly used for <strong>image scaling</strong> and <strong>format conversion</strong>; it can reduce GPU load and is especially suited for multi-video playback scenarios.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="1-rga-for-video-scaling-full-screen-playback">1. RGA for Video Scaling (Full-Screen Playback)<a href="https://zephyr.100ask.org/en/blog/gstreamer-16ch-hw-acceleration#1-rga-for-video-scaling-full-screen-playback" class="hash-link" aria-label="Direct link to 1. RGA for Video Scaling (Full-Screen Playback)" title="Direct link to 1. RGA for Video Scaling (Full-Screen Playback)" translate="no">​</a></h3>
<p>If the video resolution is 720P and it needs to fit a 1080P screen in full screen, use the <code>width</code>/<code>height</code> parameters of <code>mppvideodec</code> to invoke RGA scaling:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">gst-launch-1.0 filesrc location=/root/bad_apple.mp4 ! qtdemux ! h264parse ! mppvideodec width=1920 height=1080 ! waylandsink</span><br></div></code></pre></div></div>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="comparison-gpu-scaling-approach">Comparison: GPU Scaling Approach<a href="https://zephyr.100ask.org/en/blog/gstreamer-16ch-hw-acceleration#comparison-gpu-scaling-approach" class="hash-link" aria-label="Direct link to Comparison: GPU Scaling Approach" title="Direct link to Comparison: GPU Scaling Approach" translate="no">​</a></h4>
<p>If RGA is not enabled and only <code>waylandsink</code>'s <code>fullscreen=true</code> is used to let the GPU scale, you can compare the load difference between the two:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">gst-launch-1.0 filesrc location=/root/bad_apple.mp4 ! qtdemux ! h264parse ! mppvideodec ! waylandsink fullscreen=true</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="2-rga-for-image-format-conversion">2. RGA for Image Format Conversion<a href="https://zephyr.100ask.org/en/blog/gstreamer-16ch-hw-acceleration#2-rga-for-image-format-conversion" class="hash-link" aria-label="Direct link to 2. RGA for Image Format Conversion" title="Direct link to 2. RGA for Image Format Conversion" translate="no">​</a></h3>
<p>In Wayland, <code>waylandsink</code> does not support RGB/BGR formats, only <strong>RGBA/BGRA</strong> (with alpha); in X11, <code>xvimagesink</code> does not support NV12 and needs RGB format. Use the <code>format</code> parameter of <code>mppvideodec</code> to invoke RGA for format conversion:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain"># Wayland scenario: NV12→RGBA (reduces GPU format conversion load)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">gst-launch-1.0 filesrc location=/root/bad_apple.mp4 ! qtdemux ! h264parse ! mppvideodec format=RGBA ! waylandsink</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># X11 scenario: NV12→RGB (adapts to xvimagesink)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">gst-launch-1.0 filesrc location=/root/bad_apple.mp4 ! qtdemux ! h264parse ! mppvideodec format=RGB ! xvimagesink</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="3-principles-for-choosing-between-rga-and-gpu">3. Principles for Choosing Between RGA and GPU<a href="https://zephyr.100ask.org/en/blog/gstreamer-16ch-hw-acceleration#3-principles-for-choosing-between-rga-and-gpu" class="hash-link" aria-label="Direct link to 3. Principles for Choosing Between RGA and GPU" title="Direct link to 3. Principles for Choosing Between RGA and GPU" translate="no">​</a></h3>
<table><thead><tr><th>Dimension</th><th>RGA</th><th>GPU</th></tr></thead><tbody><tr><td>Load</td><td>Low usage, small fluctuation, multi-core support</td><td>High usage, large fluctuation, easily exceeds 50%</td></tr><tr><td>Functional Focus</td><td>Image scaling, format conversion (dedicated)</td><td>Rendering, multi-frame compositing (general-purpose)</td></tr><tr><td>Applicable Scenarios</td><td>Single video scaling, format conversion</td><td>Multi-video compositing, 3D rendering</td></tr><tr><td>Selection Advice</td><td>Prefer RGA when possible to balance the load</td><td>Scenarios RGA does not support (e.g., compositing)</td></tr></tbody></table>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="5-multi-frame-compositing-practice">5. Multi-Frame Compositing Practice<a href="https://zephyr.100ask.org/en/blog/gstreamer-16ch-hw-acceleration#5-multi-frame-compositing-practice" class="hash-link" aria-label="Direct link to 5. Multi-Frame Compositing Practice" title="Direct link to 5. Multi-Frame Compositing Practice" translate="no">​</a></h2>
<p>Multi-frame compositing relies on <code>glvideomixer</code> (GPU implemented); pay attention to <strong>multi-stream conflict handling</strong> and <strong>queue buffer optimization</strong>.
In fact, RGA can also composite, but it is not implemented in the GStreamer element; compositing is possible by programming RGA directly.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="1-2-frame-compositing-basic-version">1. 2-Frame Compositing (Basic Version)<a href="https://zephyr.100ask.org/en/blog/gstreamer-16ch-hw-acceleration#1-2-frame-compositing-basic-version" class="hash-link" aria-label="Direct link to 1. 2-Frame Compositing (Basic Version)" title="Direct link to 1. 2-Frame Compositing (Basic Version)" translate="no">​</a></h3>
<p>For multi-stream video, you need to name the <code>qtdemux</code> (to avoid conflicts) and define frame positions via <code>xpos</code>/<code>ypos</code>:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">gst-launch-1.0 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">filesrc location=/root/bad_apple.mp4 ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">qtdemux name=demux_left ! h264parse ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">mppvideodec format=RGBA width=960 height=1080 ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">glvideomixer.sink_0 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">filesrc location=/root/bad_apple.mp4 ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">qtdemux name=demux_right ! h264parse ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">mppvideodec format=RGBA width=960 height=1080 ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">glvideomixer.sink_1 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">glvideomixer name=glvideomixer \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sink_0::xpos=0 sink_0::ypos=0 \ </span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sink_1::xpos=960 sink_1::ypos=0 ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">waylandsink</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="2-2-frame-compositing-optimized-version-with-queues">2. 2-Frame Compositing (Optimized Version, with Queues)<a href="https://zephyr.100ask.org/en/blog/gstreamer-16ch-hw-acceleration#2-2-frame-compositing-optimized-version-with-queues" class="hash-link" aria-label="Direct link to 2. 2-Frame Compositing (Optimized Version, with Queues)" title="Direct link to 2. 2-Frame Compositing (Optimized Version, with Queues)" translate="no">​</a></h3>
<p>Multi-stream video processing takes more time; add <code>queue</code> buffers to prevent stuttering (queues should be added at key nodes of each stream):</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">gst-launch-1.0 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">filesrc location=/root/bad_apple.mp4 ! queue ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">qtdemux name=demux_left ! queue ! h264parse ! queue ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">mppvideodec format=RGBA width=960 height=1080 ! queue ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">glvideomixer.sink_0 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">filesrc location=/root/bad_apple.mp4 ! queue ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">qtdemux name=demux_right ! queue ! h264parse ! queue ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">mppvideodec format=RGBA width=960 height=1080 ! queue ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">glvideomixer.sink_1 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">glvideomixer name=glvideomixer \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sink_0::xpos=0 sink_0::ypos=0 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sink_1::xpos=960 sink_1::ypos=0 ! queue ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">waylandsink</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="3-4-frame-compositing-22-grid">3. 4-Frame Compositing (2×2 Grid)<a href="https://zephyr.100ask.org/en/blog/gstreamer-16ch-hw-acceleration#3-4-frame-compositing-22-grid" class="hash-link" aria-label="Direct link to 3. 4-Frame Compositing (2×2 Grid)" title="Direct link to 3. 4-Frame Compositing (2×2 Grid)" translate="no">​</a></h3>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">gst-launch-1.0 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">filesrc location=/root/bad_apple.mp4 ! qtdemux name=demux1 ! queue ! h264parse ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">mppvideodec format=RGBA width=960 height=540 ! queue ! glvideomixer.sink_0 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">filesrc location=/root/bad_apple.mp4 ! qtdemux name=demux2 ! queue ! h264parse ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">mppvideodec format=RGBA width=960 height=540 ! queue ! glvideomixer.sink_1 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">filesrc location=/root/bad_apple.mp4 ! qtdemux name=demux3 ! queue ! h264parse ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">mppvideodec format=RGBA width=960 height=540 ! queue ! glvideomixer.sink_2 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">filesrc location=/root/bad_apple.mp4 ! qtdemux name=demux4 ! queue ! h264parse ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">mppvideodec format=RGBA width=960 height=540 ! queue ! glvideomixer.sink_3 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">glvideomixer name=glvideomixer \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sink_0::xpos=0    sink_0::ypos=0    sink_0::width=960 sink_0::height=540 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sink_1::xpos=960  sink_1::ypos=0    sink_1::width=960 sink_1::height=540 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sink_2::xpos=0    sink_2::ypos=540  sink_2::width=960 sink_2::height=540 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sink_3::xpos=960  sink_3::ypos=540  sink_3::width=960 sink_3::height=540 ! queue ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">waylandsink</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="4-16-frame-compositing-44-grid-high-load-scenario">4. 16-Frame Compositing (4×4 Grid, High-Load Scenario)<a href="https://zephyr.100ask.org/en/blog/gstreamer-16ch-hw-acceleration#4-16-frame-compositing-44-grid-high-load-scenario" class="hash-link" aria-label="Direct link to 4. 16-Frame Compositing (4×4 Grid, High-Load Scenario)" title="Direct link to 4. 16-Frame Compositing (4×4 Grid, High-Load Scenario)" translate="no">​</a></h3>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="1-solving-the-file-descriptor-limit-issue">(1) Solving the File Descriptor Limit Issue<a href="https://zephyr.100ask.org/en/blog/gstreamer-16ch-hw-acceleration#1-solving-the-file-descriptor-limit-issue" class="hash-link" aria-label="Direct link to (1) Solving the File Descriptor Limit Issue" title="Direct link to (1) Solving the File Descriptor Limit Issue" translate="no">​</a></h4>
<p>16-channel video creates a large number of DMA buffers (consuming Linux file descriptors FD); you need to raise the FD limit first:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">ulimit -n 4096  # Temporary; needs to be re-set after reboot</span><br></div></code></pre></div></div>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="2-16-frame-compositing-command">(2) 16-Frame Compositing Command<a href="https://zephyr.100ask.org/en/blog/gstreamer-16ch-hw-acceleration#2-16-frame-compositing-command" class="hash-link" aria-label="Direct link to (2) 16-Frame Compositing Command" title="Direct link to (2) 16-Frame Compositing Command" translate="no">​</a></h4>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">gst-launch-1.0 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">filesrc location=/root/bad_apple.mp4 ! qtdemux name=demux1 ! queue ! h264parse ! queue ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">mppvideodec format=RGBA width=480 height=270 ! queue ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">glvideomixer.sink_0 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">filesrc location=/root/bad_apple.mp4 ! qtdemux name=demux2 ! queue ! h264parse ! queue ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">mppvideodec format=RGBA width=480 height=270 ! queue ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">glvideomixer.sink_1 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">filesrc location=/root/bad_apple.mp4 ! qtdemux name=demux3 ! queue ! h264parse ! queue ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">mppvideodec format=RGBA width=480 height=270 ! queue ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">glvideomixer.sink_2 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">filesrc location=/root/bad_apple.mp4 ! qtdemux name=demux4 ! queue ! h264parse ! queue ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">mppvideodec format=RGBA width=480 height=270 ! queue ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">glvideomixer.sink_3 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">filesrc location=/root/bad_apple.mp4 ! qtdemux name=demux5 ! queue ! h264parse ! queue ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">mppvideodec format=RGBA width=480 height=270 ! queue ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">glvideomixer.sink_4 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">filesrc location=/root/bad_apple.mp4 ! qtdemux name=demux6 ! queue ! h264parse ! queue ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">mppvideodec format=RGBA width=480 height=270 ! queue ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">glvideomixer.sink_5 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">filesrc location=/root/bad_apple.mp4 ! qtdemux name=demux7 ! queue ! h264parse ! queue ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">mppvideodec format=RGBA width=480 height=270 ! queue ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">glvideomixer.sink_6 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">filesrc location=/root/bad_apple.mp4 ! qtdemux name=demux8 ! queue ! h264parse ! queue ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">mppvideodec format=RGBA width=480 height=270 ! queue ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">glvideomixer.sink_7 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">filesrc location=/root/bad_apple.mp4 ! qtdemux name=demux9 ! queue ! h264parse ! queue ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">mppvideodec format=RGBA width=480 height=270 ! queue ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">glvideomixer.sink_8 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">filesrc location=/root/bad_apple.mp4 ! qtdemux name=demux10 ! queue ! h264parse ! queue ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">mppvideodec format=RGBA width=480 height=270 ! queue ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">glvideomixer.sink_9 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">filesrc location=/root/bad_apple.mp4 ! qtdemux name=demux11 ! queue ! h264parse ! queue ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">mppvideodec format=RGBA width=480 height=270 ! queue ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">glvideomixer.sink_10 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">filesrc location=/root/bad_apple.mp4 ! qtdemux name=demux12 ! queue ! h264parse ! queue ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">mppvideodec format=RGBA width=480 height=270 ! queue ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">glvideomixer.sink_11 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">filesrc location=/root/bad_apple.mp4 ! qtdemux name=demux13 ! queue ! h264parse ! queue ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">mppvideodec format=RGBA width=480 height=270 ! queue ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">glvideomixer.sink_12 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">filesrc location=/root/bad_apple.mp4 ! qtdemux name=demux14 ! queue ! h264parse ! queue ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">mppvideodec format=RGBA width=480 height=270 ! queue ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">glvideomixer.sink_13 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">filesrc location=/root/bad_apple.mp4 ! qtdemux name=demux15 ! queue ! h264parse ! queue ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">mppvideodec format=RGBA width=480 height=270 ! queue ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">glvideomixer.sink_14 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">filesrc location=/root/bad_apple.mp4 ! qtdemux name=demux16 ! queue ! h264parse ! queue ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">mppvideodec format=RGBA width=480 height=270 ! queue ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">glvideomixer.sink_15 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">glvideomixer name=glvideomixer \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sink_0::xpos=0 sink_0::ypos=0 sink_0::width=480 sink_0::height=270 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sink_1::xpos=480 sink_1::ypos=0 sink_1::width=480 sink_1::height=270 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sink_2::xpos=960 sink_2::ypos=0 sink_2::width=480 sink_2::height=270 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sink_3::xpos=1440 sink_3::ypos=0 sink_3::width=480 sink_3::height=270 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sink_4::xpos=0 sink_4::ypos=270 sink_4::width=480 sink_4::height=270 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sink_5::xpos=480 sink_5::ypos=270 sink_5::width=480 sink_5::height=270 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sink_6::xpos=960 sink_6::ypos=270 sink_6::width=480 sink_6::height=270 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sink_7::xpos=1440 sink_7::ypos=270 sink_7::width=480 sink_7::height=270 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sink_8::xpos=0 sink_8::ypos=540 sink_8::width=480 sink_8::height=270 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sink_9::xpos=480 sink_9::ypos=540 sink_9::width=480 sink_9::height=270 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sink_10::xpos=960 sink_10::ypos=540 sink_10::width=480 sink_10::height=270 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sink_11::xpos=1440 sink_11::ypos=540 sink_11::width=480 sink_11::height=270 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sink_12::xpos=0 sink_12::ypos=810 sink_12::width=480 sink_12::height=270 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sink_13::xpos=480 sink_13::ypos=810 sink_13::width=480 sink_13::height=270 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sink_14::xpos=960 sink_14::ypos=810 sink_14::width=480 sink_14::height=270 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sink_15::xpos=1440 sink_15::ypos=810 sink_15::width=480 sink_15::height=270 ! queue ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">waylandsink</span><br></div></code></pre></div></div>]]></content:encoded>
            <category>RK3576</category>
            <category>GStreamer</category>
            <category>Hardware Acceleration</category>
            <category>MPP</category>
        </item>
        <item>
            <title><![CDATA[DshanPI-A1 RK3576 gmrender-resurrect Bilibili Screen Cast]]></title>
            <link>https://zephyr.100ask.org/en/blog/gmrender-bilibili-cast</link>
            <guid>https://zephyr.100ask.org/en/blog/gmrender-bilibili-cast</guid>
            <pubDate>Mon, 10 Nov 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[Using gmrender-resurrect to implement DLNA screen casting on RK3576, casting content such as Bilibili to the development board for playback.]]></description>
            <content:encoded><![CDATA[<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="demo-effect">Demo Effect<a href="https://zephyr.100ask.org/en/blog/gmrender-bilibili-cast#demo-effect" class="hash-link" aria-label="Direct link to Demo Effect" title="Direct link to Demo Effect" translate="no">​</a></h2>
<p><a href="https://www.bilibili.com/video/BV1Z646zhEBP" target="_blank" rel="noopener noreferrer" class="">https://www.bilibili.com/video/BV1Z646zhEBP</a></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="1-environment-information">1. Environment Information<a href="https://zephyr.100ask.org/en/blog/gmrender-bilibili-cast#1-environment-information" class="hash-link" aria-label="Direct link to 1. Environment Information" title="Direct link to 1. Environment Information" translate="no">​</a></h2>
<table><thead><tr><th>Category</th><th>Configuration</th></tr></thead><tbody><tr><td>Board</td><td>DshanPI-A1</td></tr><tr><td>Main SoC</td><td>RK3576</td></tr><tr><td>Operating System</td><td>Armbian</td></tr><tr><td>Desktop Environment</td><td>GNOME</td></tr><tr><td>Window System</td><td>Wayland</td></tr><tr><td>GPU Driver</td><td>Panfrost</td></tr></tbody></table>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="2-implementation-principle">2. Implementation Principle<a href="https://zephyr.100ask.org/en/blog/gmrender-bilibili-cast#2-implementation-principle" class="hash-link" aria-label="Direct link to 2. Implementation Principle" title="Direct link to 2. Implementation Principle" translate="no">​</a></h2>
<ol>
<li class="">
<p><strong>Core component</strong>: <code>gmrender-resurrect</code> is a tool that receives DLNA service content and plays it via GStreamer, and can be directly configured as a DLNA client.</p>
</li>
<li class="">
<p><strong>Hardware acceleration basis</strong>: GStreamer hardware-accelerated video playback has been implemented in advance, meeting the needs of HD stream decoding.</p>
</li>
<li class="">
<p><strong>Bilibili screen cast adaptation</strong>: When Bilibili casts via DLNA, it sends an <strong>H264 stream packaged in FLV</strong> (similar to a live stream), which can be played directly with hardware acceleration via <code>gmrender-resurrect</code>.</p>
</li>
</ol>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="3-environment-setup-install-dependencies">3. Environment Setup (Install Dependencies)<a href="https://zephyr.100ask.org/en/blog/gmrender-bilibili-cast#3-environment-setup-install-dependencies" class="hash-link" aria-label="Direct link to 3. Environment Setup (Install Dependencies)" title="Direct link to 3. Environment Setup (Install Dependencies)" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="1-install-basic-build-tools">1. Install basic build tools<a href="https://zephyr.100ask.org/en/blog/gmrender-bilibili-cast#1-install-basic-build-tools" class="hash-link" aria-label="Direct link to 1. Install basic build tools" title="Direct link to 1. Install basic build tools" translate="no">​</a></h3>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">sudo apt-get install build-essential \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            autoconf \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            automake \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            libtool \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            pkg-config</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="2-install-dlna-and-gstreamer-core-dependencies">2. Install DLNA and GStreamer core dependencies<a href="https://zephyr.100ask.org/en/blog/gmrender-bilibili-cast#2-install-dlna-and-gstreamer-core-dependencies" class="hash-link" aria-label="Direct link to 2. Install DLNA and GStreamer core dependencies" title="Direct link to 2. Install DLNA and GStreamer core dependencies" translate="no">​</a></h3>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain"># Update package sources</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sudo apt-get update</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># Install DLNA dependencies and GStreamer components (including codec and output plugins)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sudo apt-get install libupnp-dev libgstreamer1.0-dev \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            gstreamer1.0-plugins-base gstreamer1.0-plugins-good \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            gstreamer1.0-plugins-bad gstreamer1.0-plugins-ugly \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">			gstreamer1.0-rockchip1 sudo apt install -y libgstreamer-gl1.0-0 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            gstreamer1.0-libav</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># Install audio output plugins (PulseAudio + ALSA)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sudo apt install -y gstreamer1.0-pulseaudio</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sudo apt-get install gstreamer1.0-alsa</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># Install Git (for pulling source code)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sudo apt-get install git</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="4-build-gmrender-resurrect">4. Build gmrender-resurrect<a href="https://zephyr.100ask.org/en/blog/gmrender-bilibili-cast#4-build-gmrender-resurrect" class="hash-link" aria-label="Direct link to 4. Build gmrender-resurrect" title="Direct link to 4. Build gmrender-resurrect" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="1-pull-the-source-code">1. Pull the source code<a href="https://zephyr.100ask.org/en/blog/gmrender-bilibili-cast#1-pull-the-source-code" class="hash-link" aria-label="Direct link to 1. Pull the source code" title="Direct link to 1. Pull the source code" translate="no">​</a></h3>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">git clone https://github.com/hzeller/gmrender-resurrect.git</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="2-build-and-compile">2. Build and compile<a href="https://zephyr.100ask.org/en/blog/gmrender-bilibili-cast#2-build-and-compile" class="hash-link" aria-label="Direct link to 2. Build and compile" title="Direct link to 2. Build and compile" translate="no">​</a></h3>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain"># Enter the source directory</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">cd gmrender-resurrect</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># Generate configuration files</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">./autogen.sh</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># Configure build parameters</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">./configure</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">make</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="3-copy-the-logo-files-to-avoid-startup-errors">3. Copy the logo files (to avoid startup errors)<a href="https://zephyr.100ask.org/en/blog/gmrender-bilibili-cast#3-copy-the-logo-files-to-avoid-startup-errors" class="hash-link" aria-label="Direct link to 3. Copy the logo files (to avoid startup errors)" title="Direct link to 3. Copy the logo files (to avoid startup errors)" translate="no">​</a></h3>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain"># Copy icons to the system default directory</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">cp data/grender-128x128.png /usr/local/share/gmediarender/</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">cp data/grender-64x64.png /usr/local/share/gmediarender/</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="5-start-the-dlna-screen-cast-service">5. Start the DLNA Screen Cast Service<a href="https://zephyr.100ask.org/en/blog/gmrender-bilibili-cast#5-start-the-dlna-screen-cast-service" class="hash-link" aria-label="Direct link to 5. Start the DLNA Screen Cast Service" title="Direct link to 5. Start the DLNA Screen Cast Service" translate="no">​</a></h2>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain"># -f "DshanPI-A1": set the display name of the device in the DLNA list</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># --gstout-videopipe: custom video output pipeline, force Wayland fullscreen</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">./src/gmediarender  -f "DshanPI-A1" --gstout-videopipe "waylandsink fullscreen=true"</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="6-troubleshooting-and-resolution-audio-causing-video-stutter">6. Troubleshooting and Resolution (audio causing video stutter)<a href="https://zephyr.100ask.org/en/blog/gmrender-bilibili-cast#6-troubleshooting-and-resolution-audio-causing-video-stutter" class="hash-link" aria-label="Direct link to 6. Troubleshooting and Resolution (audio causing video stutter)" title="Direct link to 6. Troubleshooting and Resolution (audio causing video stutter)" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="1-problem-phenomenon">1. Problem phenomenon<a href="https://zephyr.100ask.org/en/blog/gmrender-bilibili-cast#1-problem-phenomenon" class="hash-link" aria-label="Direct link to 1. Problem phenomenon" title="Direct link to 1. Problem phenomenon" translate="no">​</a></h3>
<ul>
<li class="">When playing video only, it works normally; after adding audio, the video freezes directly.</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="2-troubleshooting-steps">2. Troubleshooting steps<a href="https://zephyr.100ask.org/en/blog/gmrender-bilibili-cast#2-troubleshooting-steps" class="hash-link" aria-label="Direct link to 2. Troubleshooting steps" title="Direct link to 2. Troubleshooting steps" translate="no">​</a></h3>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-1-check-sound-card-status-found-suspended">Step 1: Check sound card status (found suspended)<a href="https://zephyr.100ask.org/en/blog/gmrender-bilibili-cast#step-1-check-sound-card-status-found-suspended" class="hash-link" aria-label="Direct link to Step 1: Check sound card status (found suspended)" title="Direct link to Step 1: Check sound card status (found suspended)" translate="no">​</a></h4>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain"># View the status of all audio output devices</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">pactl list sinks short</span><br></div></code></pre></div></div>
<ul>
<li class="">The output shows all sound cards are in the <strong>SUSPENDED</strong> state, and they cannot be activated after running <code>suspend-sink</code>, indicating an abnormal connection between PulseAudio and the hardware.</li>
</ul>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-2-check-audio-service-usage-found-conflict">Step 2: Check audio service usage (found conflict)<a href="https://zephyr.100ask.org/en/blog/gmrender-bilibili-cast#step-2-check-audio-service-usage-found-conflict" class="hash-link" aria-label="Direct link to Step 2: Check audio service usage (found conflict)" title="Direct link to Step 2: Check audio service usage (found conflict)" translate="no">​</a></h4>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain"># View processes using audio devices</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">fuser -v /dev/snd/*</span><br></div></code></pre></div></div>
<ul>
<li class="">The output shows that <strong>PulseAudio, WirePlumber, and PipeWire</strong> three audio services occupy the device simultaneously, indicating a service conflict (PipeWire and PulseAudio have overlapping functionality, competing for sound card control).</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="3-solution-mask-the-conflicting-pulseaudio-service">3. Solution (mask the conflicting PulseAudio service)<a href="https://zephyr.100ask.org/en/blog/gmrender-bilibili-cast#3-solution-mask-the-conflicting-pulseaudio-service" class="hash-link" aria-label="Direct link to 3. Solution (mask the conflicting PulseAudio service)" title="Direct link to 3. Solution (mask the conflicting PulseAudio service)" translate="no">​</a></h3>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-1-mask-pulseaudio-autostart-user-level">Step 1: Mask PulseAudio autostart (user level)<a href="https://zephyr.100ask.org/en/blog/gmrender-bilibili-cast#step-1-mask-pulseaudio-autostart-user-level" class="hash-link" aria-label="Direct link to Step 1: Mask PulseAudio autostart (user level)" title="Direct link to Step 1: Mask PulseAudio autostart (user level)" translate="no">​</a></h4>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain"># Mask the service to prevent autostart</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">systemctl --user mask pulseaudio</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">systemctl --user mask pulseaudio.socket</span><br></div></code></pre></div></div>
<blockquote>
<p>Note: This operation will temporarily make the system unable to recognize PulseAudio devices. To restore, run the unmask command.</p>
</blockquote>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-2-force-kill-residual-pulseaudio-processes">Step 2: Force kill residual PulseAudio processes<a href="https://zephyr.100ask.org/en/blog/gmrender-bilibili-cast#step-2-force-kill-residual-pulseaudio-processes" class="hash-link" aria-label="Direct link to Step 2: Force kill residual PulseAudio processes" title="Direct link to Step 2: Force kill residual PulseAudio processes" translate="no">​</a></h4>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">pkill -9 pulseaudio</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="4-functional-verification-ensure-audiovideo-works">4. Functional verification (ensure audio/video works)<a href="https://zephyr.100ask.org/en/blog/gmrender-bilibili-cast#4-functional-verification-ensure-audiovideo-works" class="hash-link" aria-label="Direct link to 4. Functional verification (ensure audio/video works)" title="Direct link to 4. Functional verification (ensure audio/video works)" translate="no">​</a></h3>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="verification-1-audio-output-test">Verification 1: Audio output test<a href="https://zephyr.100ask.org/en/blog/gmrender-bilibili-cast#verification-1-audio-output-test" class="hash-link" aria-label="Direct link to Verification 1: Audio output test" title="Direct link to Verification 1: Audio output test" translate="no">​</a></h4>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain"># Play a 1000Hz test tone to check whether the speaker outputs sound</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">gst-launch-1.0 audiotestsrc freq=1000 ! audioconvert ! pulsesink</span><br></div></code></pre></div></div>
<ul>
<li class="">
<p>After masking PulseAudio, gst will use alsa to play audio</p>
</li>
<li class="">
<p>Volume can be controlled via alsamixer</p>
</li>
<li class="">
<p>Normal sound output indicates the audio link is restored.</p>
</li>
</ul>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="verification-2-local-video-playback-test">Verification 2: Local video playback test<a href="https://zephyr.100ask.org/en/blog/gmrender-bilibili-cast#verification-2-local-video-playback-test" class="hash-link" aria-label="Direct link to Verification 2: Local video playback test" title="Direct link to Verification 2: Local video playback test" translate="no">​</a></h4>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain"># Play a local video to check audio-video sync</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">gst-launch-1.0 playbin uri=file:///root/bad_apple.mp4</span><br></div></code></pre></div></div>
<ul>
<li class="">Normal playback with sound indicates audio-video collaboration is working normally.</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="5-restart-the-dlna-service">5. Restart the DLNA service<a href="https://zephyr.100ask.org/en/blog/gmrender-bilibili-cast#5-restart-the-dlna-service" class="hash-link" aria-label="Direct link to 5. Restart the DLNA service" title="Direct link to 5. Restart the DLNA service" translate="no">​</a></h3>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">./src/gmediarender  -f "DshanPI-A1" --gstout-videopipe "waylandsink fullscreen=true"</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="7-supplement-restore-pulseaudio-service-if-needed">7. Supplement: Restore PulseAudio service (if needed)<a href="https://zephyr.100ask.org/en/blog/gmrender-bilibili-cast#7-supplement-restore-pulseaudio-service-if-needed" class="hash-link" aria-label="Direct link to 7. Supplement: Restore PulseAudio service (if needed)" title="Direct link to 7. Supplement: Restore PulseAudio service (if needed)" translate="no">​</a></h2>
<p>If you need to use PulseAudio later, run the following commands to unmask:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">systemctl --user unmask pulseaudio</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">systemctl --user unmask pulseaudio.socket</span><br></div></code></pre></div></div>]]></content:encoded>
            <category>RK3576</category>
            <category>gmrender</category>
            <category>Screen Cast</category>
            <category>DLNA</category>
        </item>
        <item>
            <title><![CDATA[DshanPI-A1 RK3576 Armbian Remote Desktop]]></title>
            <link>https://zephyr.100ask.org/en/blog/armbian-remote-desktop</link>
            <guid>https://zephyr.100ask.org/en/blog/armbian-remote-desktop</guid>
            <pubDate>Sat, 08 Nov 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[Using Armbian's built-in remote desktop in a Wayland and open-source GPU driver environment to solve NoMachine virtual desktop and GPU acceleration failure issues.]]></description>
            <content:encoded><![CDATA[<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="background-and-problem">Background and Problem<a href="https://zephyr.100ask.org/en/blog/armbian-remote-desktop#background-and-problem" class="hash-link" aria-label="Direct link to Background and Problem" title="Direct link to Background and Problem" translate="no">​</a></h3>
<ul>
<li class="">
<p>Device used: DshanPI-A1, running the Armbian system, with Wayland as the window system and an open-source GPU driver.</p>
</li>
<li class="">
<p>Initial attempt: Using NoMachine for remote desktop, but there are two issues:</p>
</li>
</ul>
<ol>
<li class="">
<p>It creates a virtual desktop by default instead of the physical desktop;</p>
</li>
<li class="">
<p>It has poor Wayland support, launching the X11 desktop in compatibility mode, which prevents OpenGL from using GPU acceleration.</p>
</li>
</ol>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="solution-using-armbians-built-in-remote-desktop">Solution: Using Armbian's Built-in Remote Desktop<a href="https://zephyr.100ask.org/en/blog/armbian-remote-desktop#solution-using-armbians-built-in-remote-desktop" class="hash-link" aria-label="Direct link to Solution: Using Armbian's Built-in Remote Desktop" title="Direct link to Solution: Using Armbian's Built-in Remote Desktop" translate="no">​</a></h3>
<ol>
<li class="">
<p><strong>Install the necessary environment</strong></p>
<p>Since the remote desktop components are not preinstalled by default, install them first via command:</p>
</li>
</ol>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">sudo apt install gnome-remote-desktop</span><br></div></code></pre></div></div>
<ol start="2">
<li class=""><strong>Configure the remote desktop</strong></li>
</ol>
<ul>
<li class="">
<p>Restart the settings window (close and reopen it), then navigate to <code>Settings → System → Remote Desktop</code>.</p>
</li>
<li class="">
<p>Check <code>Desktop Sharing</code> and <code>Remote Control</code>.</p>
</li>
<li class="">
<p>The initial password is randomly generated and needs to be manually changed to a custom password.</p>
</li>
</ul>
<ol start="3">
<li class=""><strong>Connect and verify</strong></li>
</ol>
<ul>
<li class="">
<p>Open "Remote Desktop Connection" on Windows, and enter the device IP, username, and password.</p>
</li>
<li class="">
<p>The first login may show a black screen; after restarting the device, the connection succeeds.</p>
</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="functional-verification">Functional Verification<a href="https://zephyr.100ask.org/en/blog/armbian-remote-desktop#functional-verification" class="hash-link" aria-label="Direct link to Functional Verification" title="Direct link to Functional Verification" translate="no">​</a></h3>
<p>Test whether GPU acceleration works via commands:</p>
<ul>
<li class="">
<p>Run <code>glxinfo -B</code>; the output shows Mali GPU information (OpenGL support is normal);</p>
</li>
<li class="">
<p>Run <code>es2_info</code>; the Mali GPU is also detected (OpenGLES support is normal).</p>
</li>
</ul>
<p>Conclusion: The remote desktop can properly invoke GPU acceleration, meeting the requirements.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="references">References<a href="https://zephyr.100ask.org/en/blog/armbian-remote-desktop#references" class="hash-link" aria-label="Direct link to References" title="Direct link to References" translate="no">​</a></h3>
<ul>
<li class="">
<p>"Armbian 25.5.1 Noble Gnome Enabling Remote Desktop Feature"</p>
<p>(<a href="https://blog.csdn.net/u013833472/article/details/149032655" target="_blank" rel="noopener noreferrer" class="">https://blog.csdn.net/u013833472/article/details/149032655</a>)</p>
</li>
</ul>]]></content:encoded>
            <category>RK3576</category>
            <category>Armbian</category>
            <category>Remote Desktop</category>
            <category>Wayland</category>
        </item>
        <item>
            <title><![CDATA[DshanPi-A1 Introduction]]></title>
            <link>https://zephyr.100ask.org/en/blog/welcome</link>
            <guid>https://zephyr.100ask.org/en/blog/welcome</guid>
            <pubDate>Thu, 06 Nov 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[DshanPi-A1 focuses on AI education scenarios, providing a sustainable and evolving hardware and software ecosystem for teaching needs from beginner to advanced levels, in an integrated form of a single-board computer plus topic-based projects.]]></description>
            <content:encoded><![CDATA[<p>DshanPi-A1 focuses on AI education scenarios, providing a sustainable and evolving hardware and software ecosystem for teaching needs from beginner to advanced levels, in an integrated form of a "single-board computer + topic-based projects (paid)".
It offers a mid-to-high-end performance SBC experience, including rich interfaces such as PCIe, USB3.0, dual gigabit Ethernet, HDMI, HDMI-IN, DP, and more.</p>
<div class="theme-admonition theme-admonition-tip admonition_xJq3 alert alert--success"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>tip</div><div class="admonitionContent_BuS1"><ul>
<li class="">Source repo: <a href="https://github.com/dshanpi/" target="_blank" rel="noopener noreferrer" class="">https://github.com/dshanpi/</a></li>
<li class="">QQ community group: 798273638</li>
<li class="">Product link: <a href="https://detail.tmall.com/item.htm?id=953384132961" target="_blank" rel="noopener noreferrer" class="">https://detail.tmall.com/item.htm?id=953384132961</a></li>
<li class="">Image site: <a href="https://dl.100ask.net/Hardware/MPU/RK3576-DshanPi-A1/" target="_blank" rel="noopener noreferrer" class="">https://dl.100ask.net/Hardware/MPU/RK3576-DshanPi-A1/</a></li>
</ul></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="dshanpl-a1-education">DShanPl-A1 Education<a href="https://zephyr.100ask.org/en/blog/welcome#dshanpl-a1-education" class="hash-link" aria-label="Direct link to DShanPl-A1 Education" title="Direct link to DShanPl-A1 Education" translate="no">​</a></h2>
<p>DShanPl-A1 Education is deeply optimized for AI education and project development. Designed based on Rockchip's RK3576 processor, it integrates 4 Cortex-A72 and 4 Cortex-A53 cores with NEON instruction set support. It supports 8K@30fps H.265, VP9, AVS2 and AV1 decoders, a 4K@60fps H.264 decoder and a 4K@60fps AV1 decoder; it also supports 4K@60fps H.264 and H.265 encoders. The built-in 3D GPU is fully compatible with OpenGL ES 1.1/2.0/3.2, OpenCL 2.0 and Vulkan 1.1. The embedded NPU delivers up to 6 TOPS of computing power, supporting INT4/INT8/INT16/FP16 hybrid operations.</p>
<!-- -->
<div class="theme-tabs-container tabs-container tabList__CuJ"><ul role="tablist" aria-orientation="horizontal" class="tabs"><li role="tab" tabindex="0" aria-selected="true" class="tabs__item tabItem_LNqP tabs__item--active">Front Function Diagram</li><li role="tab" tabindex="-1" aria-selected="false" class="tabs__item tabItem_LNqP">Back Function Diagram</li><li role="tab" tabindex="-1" aria-selected="false" class="tabs__item tabItem_LNqP">Product Promo Image</li></ul><div class="margin-top--md"><div role="tabpanel" class="tabItem_Ymn6"></div><div role="tabpanel" class="tabItem_Ymn6" hidden=""></div><div role="tabpanel" class="tabItem_Ymn6" hidden=""></div></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="specifications">Specifications<a href="https://zephyr.100ask.org/en/blog/welcome#specifications" class="hash-link" aria-label="Direct link to Specifications" title="Direct link to Specifications" translate="no">​</a></h3>
<details class="details_lb9f alert alert--info details_b_Ee" data-collapsed="true"><summary>DshanPI-A1 Education RK3576 SBC detailed specifications: </summary><div><div class="collapsibleContent_i85q"><div></div></div></div></details>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="peripheral-drivers-supported-by-the-system">Peripheral Drivers Supported by the System<a href="https://zephyr.100ask.org/en/blog/welcome#peripheral-drivers-supported-by-the-system" class="hash-link" aria-label="Direct link to Peripheral Drivers Supported by the System" title="Direct link to Peripheral Drivers Supported by the System" translate="no">​</a></h3>
<p>✅: Supported —  ❌: Not yet supported —  🚫: No plan to support   —⚠: Supported but not fully tested</p>
<table><thead><tr><th>System Version</th><th>Armbian</th><th>Buildroot</th><th>OpenWrt-LEDE</th><th>ArchLinux</th><th>OpenEuler</th><th>Fedora</th></tr></thead><tbody><tr><td>SPI</td><td>✅</td><td>✅</td><td>✅</td><td>✅</td><td>✅</td><td>✅</td></tr><tr><td>I2C</td><td>✅</td><td>✅</td><td>✅</td><td>✅</td><td>✅</td><td>✅</td></tr><tr><td>PWM</td><td>✅</td><td>✅</td><td>✅</td><td>✅</td><td>✅</td><td>✅</td></tr><tr><td>UART</td><td>✅</td><td>✅</td><td>✅</td><td>✅</td><td>✅</td><td>✅</td></tr><tr><td>MMC</td><td>✅</td><td>✅</td><td>✅</td><td>✅</td><td>❌</td><td>✅</td></tr><tr><td>GPIO</td><td>✅</td><td>✅</td><td>✅</td><td>✅</td><td>✅</td><td>✅</td></tr><tr><td>NPU</td><td>✅</td><td>✅</td><td>⚠</td><td>✅</td><td>❌</td><td>❌</td></tr><tr><td>USB2.0</td><td>✅</td><td>✅</td><td>✅</td><td>✅</td><td>❌</td><td>❌</td></tr><tr><td>USB3.0</td><td>✅</td><td>✅</td><td>✅</td><td>✅</td><td>❌</td><td>❌</td></tr><tr><td>PCI-e</td><td>✅</td><td>✅</td><td>✅</td><td>✅</td><td>❌</td><td>❌</td></tr><tr><td>Video Encoding</td><td>✅</td><td>✅</td><td>✅</td><td>❌</td><td>❌</td><td>❌</td></tr><tr><td>Video Decoding</td><td>✅</td><td>✅</td><td>✅</td><td>❌</td><td>❌</td><td>❌</td></tr><tr><td>MIPI CSI</td><td>❌</td><td>✅</td><td>❌</td><td>❌</td><td>❌</td><td>❌</td></tr><tr><td>Audio</td><td>✅</td><td>✅</td><td>❌</td><td>❌</td><td>❌</td><td>❌</td></tr><tr><td>WIFI</td><td>✅</td><td>✅</td><td>✅</td><td>✅</td><td>❌</td><td>❌</td></tr></tbody></table>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="dshanpl-r1">DShanPl-R1+<a href="https://zephyr.100ask.org/en/blog/welcome#dshanpl-r1" class="hash-link" aria-label="Direct link to DShanPl-R1+" title="Direct link to DShanPl-R1+" translate="no">​</a></h2>
<div class="theme-admonition theme-admonition-tip admonition_xJq3 alert alert--success"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>tip</div><div class="admonitionContent_BuS1"><p>Status: In mass production</p></div></div>
<details class="details_lb9f alert alert--info details_b_Ee" data-collapsed="true"><summary>DshanPI-R1+ RK3568 SBC product image: </summary><div><div class="collapsibleContent_i85q"><div></div></div></div></details>]]></content:encoded>
            <category>DshanPi-A1</category>
            <category>Introduction</category>
            <category>RK3576</category>
        </item>
    </channel>
</rss>