<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by RT-Thread IoT OS on Medium]]></title>
        <description><![CDATA[Stories by RT-Thread IoT OS on Medium]]></description>
        <link>https://medium.com/@rt-thread?source=rss-6ea18de1fff4------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*qtsDwdqDFZcp-3X2bMmWIw.jpeg</url>
            <title>Stories by RT-Thread IoT OS on Medium</title>
            <link>https://medium.com/@rt-thread?source=rss-6ea18de1fff4------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Wed, 20 May 2026 23:16:57 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@rt-thread/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com" rel="hub"/>
        <item>
            <title><![CDATA[RT-Thread-based Smart Helmet Sensor Data Acquisition System on FRDM-MCXA156 | Technical Collection]]></title>
            <link>https://rt-thread.medium.com/rt-thread-based-smart-helmet-sensor-data-acquisition-system-on-frdm-mcxa156-technical-collection-33bb25a72b6a?source=rss-6ea18de1fff4------2</link>
            <guid isPermaLink="false">https://medium.com/p/33bb25a72b6a</guid>
            <dc:creator><![CDATA[RT-Thread IoT OS]]></dc:creator>
            <pubDate>Wed, 22 Apr 2026 05:40:08 GMT</pubDate>
            <atom:updated>2026-04-22T05:40:08.970Z</atom:updated>
            <content:encoded><![CDATA[<p>This article is contributed by Peipeipei.</p><h3>1 Project Overview</h3><p>This project is based on the NXP FRDM-MCXA156 development board, running the RT-Thread real-time operating system. It implements multi-sensor data acquisition and uploads the data to the Huawei Cloud IoT platform via the ESP01S WiFi module.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*vpwz7E2sI3julhBZubyv7A.png" /></figure><h4>1.1 Main Functions</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*du9-F0LRQOcY0ffdQvgGAQ.png" /></figure><h4>1.2 System Architecture</h4><pre>+------------------+     +------------------+     +------------------+<br>|   Sensor Layer   |     |   Application    |     |   Communication   |<br>|                  |     |   Layer          |     |   Layer           |<br>+------------------+     +------------------+     +------------------+<br>| drv_mq2.c        | --&gt; | MQ2_app.c        |     |                  |<br>| drv_dht11.c      | --&gt; | dht11_app.c      | --&gt; | esp_app.c        | --&gt; Huawei Cloud IoT<br>| drv_max30102.c   | --&gt; | max30102_app.c   |     | (MQTT reporting) |<br>| (UART receive)   | --&gt; | ATGM336H_app.c   |     |                  |<br>+------------------+     +------------------+     +------------------+</pre><h3>2 Hardware Platform</h3><h4>2.1 Main Controller Chip</h4><p>Model: NXP MCXA156</p><p>Core: ARM Cortex-M33</p><p>Main Frequency: 96 MHz</p><p>Flash: 1 MB</p><p>RAM: 128 KB</p><h4>2.2 Pin Assignment</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*j4dzMsMJGTMK0zIpE7tipg.png" /></figure><p><strong>3 Directory Structure</strong></p><pre>frdm-mcxa156/<br>├── applications/           # Application layer code<br>│   ├── main.c             # Main function entry<br>│   ├── mydefine.h         # Common header definitions<br>│   │<br>│   ├── drv_dht11.c/h      # DHT11 driver layer<br>│   ├── dht11_app.c/h      # DHT11 application layer<br>│   │<br>│   ├── drv_mq2.c/h        # MQ2 driver layer<br>│   ├── MQ2_app.c/h        # MQ2 application layer<br>│   │<br>│   ├── drv_max30102.c/h   # MAX30102 driver layer<br>│   ├── max30102_app.c/h   # MAX30102 application layer<br>│   │<br>│   ├── ATGM336H_app.c/h   # GPS module application layer<br>│   │<br>│   ├── esp_app.c/h        # ESP01S WiFi/MQTT communication<br>│   │<br>│   ├── adc_app.c/h        # ADC acquisition wrapper<br>│   └── uart_app.c/h       # UART utility functions<br>│<br>├── board/                  # Board support package<br>│   ├── board.c/h          # Board initialization<br>│   ├── Kconfig            # Hardware configuration menu<br>│   ├── MCUX_Config/       # NXP MCUXpresso configuration<br>│   │   └── board/<br>│   │       ├── clock_config.c/h   # Clock configuration<br>│   │       └── pin_mux.c/h        # Pin multiplexing configuration<br>│   └── linker_scripts/    # Linker scripts<br>│<br>├── packages/               # RT-Thread packages<br>│   ├── nxp-mcx-cmsis-latest/     # NXP CMSIS support<br>│   └── nxp-mcx-series-latest/    # NXP MCX series drivers<br>│<br>├── .config                # RT-Thread configuration file<br>├── rtconfig.h             # RT-Thread configuration header<br>├── Kconfig                # Top-level configuration menu<br>├── SConstruct             # SCons build file<br>├── project.uvprojx        # Keil MDK project file<br>└── rtthread.elf/bin       # Build output files</pre><h3>4 Sensor Module Details</h3><h3>4.1 MQ2 Gas Sensor</h3><p><strong>Files:</strong> drv_mq2.c/h, MQ2_app.c/h</p><p><strong>Function:</strong> Detects methane (CH4) and other combustible gases</p><p><strong>Data Structure:</strong></p><pre>typedef struct {<br>    rt_base_t dopin;    // Digital output pin<br>    float adc_val;      // ADC raw value<br>    float ch4ppm;       // Methane concentration (ppm)<br>} mq2_device_t;</pre><p><strong>API Interfaces:</strong></p><pre>// Initialize MQ2 device<br>rt_err_t mq2_init(mq2_device_t *dev, rt_base_t dopin);</pre><pre>// Read gas concentration<br>mq2_result_t MQ2_GetPmm(mq2_device_t *dev);</pre><pre>// Get current methane concentration (application layer)<br>float mq2_get_ch4ppm(void);</pre><p><strong>Global Variable:</strong><br>g_mq2_dev — MQ2 device object</p><h3>4.2 DHT11 Temperature and Humidity Sensor</h3><p><strong>Files:</strong> drv_dht11.c/h, dht11_app.c/h</p><p><strong>Function:</strong> Measures ambient temperature and humidity</p><p><strong>Data Structure:</strong></p><pre>typedef struct {<br>    rt_base_t pin;          // Data pin<br>    rt_uint8_t humidity;    // Integer part of humidity<br>    rt_uint8_t temperature; // Integer part of temperature<br>} dht11_device_t;</pre><p><strong>API Interfaces:</strong></p><pre>// Initialize DHT11 device<br>rt_err_t dht11_init(dht11_device_t *dev, rt_base_t pin);</pre><pre>// Read temperature and humidity<br>dht11_result_t dht11_read(dht11_device_t *dev, rt_uint8_t *temp, rt_uint8_t *humi);</pre><pre>// Get current temperature (application layer)<br>rt_uint8_t dht11_get_temperature(void);</pre><pre>// Get current humidity (application layer)<br>rt_uint8_t dht11_get_humidity(void);</pre><p><strong>Global Variables:</strong></p><ul><li>g_dht11_dev — DHT11 device object</li><li>g_dht11_temperature — Latest temperature value</li><li>g_dht11_humidity — Latest humidity value</li></ul><h3>4.3 MAX30102 Heart Rate and Blood Oxygen Sensor</h3><p><strong>Files:</strong> drv_max30102.c/h, max30102_app.c/h</p><p><strong>Function:</strong> Detects heart rate and blood oxygen using red and infrared light</p><p><strong>Communication Interface:</strong> I2C (address: 0x57)</p><p><strong>Data Structure:</strong></p><pre>typedef struct {<br>    struct rt_i2c_bus_device *i2c_bus;  // I2C bus handle<br>    rt_mutex_t lock;                   // Mutex<br>    rt_uint8_t addr;                   // I2C address<br>    rt_bool_t initialized;             // Initialization flag<br>} max30102_device_t;</pre><p><strong>API Interfaces:</strong></p><pre>// Initialize MAX30102 device<br>max30102_device_t *max30102_init(const char *i2c_bus_name);</pre><pre>// Read LED data from FIFO<br>rt_err_t max30102_read_fifo(max30102_device_t *dev,<br>                            rt_uint32_t *red_led,<br>                            rt_uint32_t *ir_led);</pre><pre>// Get heart rate (application layer)<br>rt_uint32_t max30102_get_heart_rate(void);</pre><p><strong>Global Variables:</strong></p><ul><li>g_max30102_red_led — Red LED raw value</li><li>g_max30102_ir_led — Infrared LED raw value</li><li>g_max30102_heart_rate — Estimated heart rate</li></ul><p><strong>Operating Modes:</strong><br>Supports interrupt mode and polling mode (switch via USE_INTERRUPT_MODE macro)</p><h3>4.4 ATGM336H GPS Module</h3><p><strong>Files:</strong> ATGM336H_app.c/h</p><p><strong>Function:</strong> Obtains GPS positioning information (longitude, latitude)</p><p><strong>Communication Interface:</strong> UART2 (baud rate: 9600)</p><p><strong>Data Structures:</strong></p><pre>typedef struct {<br>    char GPS_Buffer[80];    // Raw GPS data buffer<br>    char isGetData;         // Data received flag<br>    char isParseData;       // Data parsed flag<br>    char UTCTime[11];       // UTC time<br>    char latitude[11];      // Latitude string<br>    char N_S[2];            // North/South<br>    char longitude[12];     // Longitude string<br>    char E_W[2];            // East/West<br>    char isUsefull;         // Valid positioning flag<br>} _SaveData;</pre><pre>typedef struct {<br>    float latitude;         // Latitude (decimal degrees)<br>    float longitude;        // Longitude (decimal degrees)<br>    char N_S;               // North/South indicator<br>    char E_W;               // East/West indicator<br>} LatitudeAndLongitude_s;</pre><p><strong>Global Variables:</strong></p><ul><li>Save_Data — Raw GPS data structure</li><li>g_LatAndLongData — Parsed latitude and longitude</li><li>latitude, longitude — Global coordinate variables</li></ul><h3>4.5 ESP01S WiFi Module</h3><p><strong>Files:</strong> esp_app.c/h</p><p><strong>Function:</strong> Uploads sensor data to Huawei Cloud IoT platform via MQTT protocol</p><p><strong>Communication Interface:</strong> UART1</p><p><strong>Cloud Configuration (defined in esp_app.h):</strong></p><pre>#define WIFI_NAME               &quot;LP11&quot;<br>#define WIFI_PWD                &quot;123456aa&quot;<br>#define HUAWEI_MQTT_ADDRESS     &quot;e8b7ac5772.st1.iotda-device.cn-east-3.myhuaweicloud.com&quot;<br>#define HUAWEI_MQTT_PORT        1883</pre><p><strong>API Interfaces:</strong></p><pre>// Send AT command<br>void esp_send(const char *data);</pre><pre>// Report sensor data to cloud<br>int esp_report(float density, int hr, int temp, int humi);</pre><p><strong>Data Reporting Format (MQTT JSON):</strong></p><pre>{<br>  &quot;services&quot;: [{<br>    &quot;service_id&quot;: &quot;BasedData&quot;,<br>    &quot;properties&quot;: {<br>      &quot;density&quot;: 100.5,<br>      &quot;heart_rate&quot;: 75,<br>      &quot;temperature&quot;: 25,<br>      &quot;humidity&quot;: 60<br>    }<br>  }]<br>}</pre><h3>5 Thread Architecture</h3><p>The system adopts a multi-threaded architecture, where each sensor is collected independently:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*BRWhv2LQI7SU1DXsUkuWFQ.png" /></figure><h3><strong>6 Build and Flash</strong></h3><h4>6.1 Using Keil MDK</h4><p>Open the project.uvprojx project file</p><p>Build: Project -&gt; Build Target or F7</p><p>Flash: Flash -&gt; Download or F8</p><h4>6.2 Using SCons (Command Line)</h4><pre># Configure<br>scons --menuconfig</pre><pre># Build<br>scons</pre><pre># Clean<br>scons -c</pre><h3>7 Configuration</h3><h4>7.1 RT-Thread Configuration</h4><p>Configure via menuconfig or by directly editing the .config file:</p><pre># UART configuration<br>CONFIG_BSP_USING_UART0=y    # Debug UART<br>CONFIG_BSP_USING_UART1=y    # ESP01S<br>CONFIG_BSP_USING_UART2=y    # GPS module</pre><pre># I2C configuration<br>CONFIG_BSP_USING_I2C0=y     # MAX30102</pre><pre># ADC configuration<br>CONFIG_BSP_USING_ADC0_CH0=y # MQ2 analog output</pre><h4>7.2 Sensor Pin Configuration</h4><p>Modify pin definitions in each application file:</p><pre>// MQ2_app.c<br>#define MQ2_DATA_PIN     ((3*32)+7)    // P3_7</pre><pre>// dht11_app.c<br>#define DHT11_DATA_PIN   ((3*32)+6)    // P3_6</pre><pre>// max30102_app.c<br>#define MAX30102_INT_PIN ((1*32)+13)   // P1_13</pre><h3>8 Data Flow Description</h3><pre>[Sensor Acquisition] --&gt; [Global Variable Update] --&gt; [esp_thread_entry Read] --&gt; [esp_report Upload] --&gt; [Huawei Cloud]</pre><p><strong>Sequence:</strong></p><ol><li>Each sensor thread periodically collects data and updates global variables</li><li>The ESP thread reads global variables in the main loop</li><li>Calls esp_report() to construct and send MQTT messages</li><li>Huawei Cloud IoT platform receives and stores the data</li></ol><h3>9 Notes</h3><ul><li><strong>DHT11:</strong> At least 2 seconds interval between reads</li><li><strong>MQ2:</strong> Requires a warm-up stabilization period after power-on</li><li><strong>MAX30102:</strong> I2C communication requires larger stack space</li><li><strong>GPS:</strong> Initial positioning may take a long time; may not work indoors</li><li><strong>ESP01S:</strong> WiFi connection requires ~5 seconds; MQTT connection requires ~3 seconds</li></ul><h3>10 File Dependency Relationships</h3><pre>mydefine.h (basic definitions)<br>    ├── drv_dht11.h<br>    ├── drv_mq2.h<br>    ├── drv_max30102.h<br>    │<br>    ├── dht11_app.h      --&gt; dht11_app.c<br>    ├── MQ2_app.h        --&gt; MQ2_app.c<br>    ├── max30102_app.h   --&gt; max30102_app.c<br>    ├── ATGM336H_app.h   --&gt; ATGM336H_app.c<br>    │<br>    └── esp_app.h        --&gt; esp_app.c (references all sensor data)</pre><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=33bb25a72b6a" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[RT-Thread Device Tree Adaptation Method | Technical Collection]]></title>
            <link>https://rt-thread.medium.com/rt-thread-device-tree-adaptation-method-technical-collection-d7bfcffc9d16?source=rss-6ea18de1fff4------2</link>
            <guid isPermaLink="false">https://medium.com/p/d7bfcffc9d16</guid>
            <dc:creator><![CDATA[RT-Thread IoT OS]]></dc:creator>
            <pubDate>Thu, 09 Apr 2026 09:37:32 GMT</pubDate>
            <atom:updated>2026-04-09T09:37:32.878Z</atom:updated>
            <content:encoded><![CDATA[<p>This article is contributed by GuEe_GUI.</p><p>This article is based on the existing DM (Device Model) framework of RT-Thread. Taking the Rock2F development board as an example, it systematically outlines the rapid porting process for the RK3528 SoC, covering the adaptation methods of key drivers such as CLK, Pinctrl, ADC, NVMEM, Thermal, and RNG.</p><h3>1. Prerequisites</h3><p>In bsp/rockchip, it can be seen that support has already been implemented using the DM framework for SoCs such as RK3566, RK3568, RK3576, and RK3588. Next, we will take the Rockchip RK3528-based Rock2F as an example to briefly explain the porting process for a new Rockchip BSP.</p><h3>2. Product Introduction</h3><p>Official website: <a href="https://docs.radxa.com/rock2/rock2f">https://docs.radxa.com/rock2/rock2f</a></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*vXQmMVDL-VEZm9OQHnJeVg.png" /></figure><h3>3. Preparation</h3><p>In addition, I prepared an FPC Connector with PCIe 2.0 for the Raspberry Pi 5 to verify PCIe functionality.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*t_a3qC9fiCsxBRHtTjlPsg.png" /></figure><p>First, follow the official Radxa guide to flash RadxaOS onto the board:<br> <a href="https://docs.radxa.com/rock2/rock2f/getting-started/install-os">https://docs.radxa.com/rock2/rock2f/getting-started/install-os</a></p><p>Connect the serial port and boot up the board:<br> <a href="https://docs.radxa.com/rock2/rock2f/radxa-os/serial">https://docs.radxa.com/rock2/rock2f/radxa-os/serial</a></p><pre>Debian GNU/Linux 12 rock-2f ttyFIQ0</pre><pre>rock-2f login: radxa<br>Password:<br>Linux rock-2f 6.1.43-26-rk2312 #26 SMP Tue Dec 30 13:28:44 UTC 2025 aarch64<br>The programs included with the Debian GNU/Linux system are free software;<br>the exact distribution terms for each program are described in the<br>individual files in /usr/share/doc/*/copyright.<br>Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent<br>permitted by applicable law.<br>Last login: Thu Jun 26 14:59:52 UTC 2025 on ttyFIQ0<br>radxa@rock-2f:~$</pre><p>Swipe up/down or left/right to view more.</p><p>Then, use the dtc tool to extract the device tree from the SBC:</p><pre>radxa@rock-2f:~$ sudo dtc -I dtb -O dts /sys/firmware/fdt -o Rock2F.dts</pre><h3>4. Start Porting</h3><p>In bsp/rockchip/dm, a set of DM drivers has already been implemented. This means you only need to port the drivers that are not yet supported for RK3528 but are required for your use case.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*MgdWAJKxU3alI9VrKC-Ncw.png" /></figure><p>In the device tree, we can see a large number of device nodes with compatible strings starting with rockchip,rk3528-. Since the device tree supports driver backward compatibility, we need to identify which nodes correspond to new IP blocks or device configurations introduced by Rockchip for the RK3528.</p><p>Therefore, the next step is to clone the Rockchip Linux kernel source code:<br> <a href="https://github.com/rockchip-linux/kernel/tree/develop-6.6">https://github.com/rockchip-linux/kernel/tree/develop-6.6</a></p><p>Under the drivers directory, search for drivers related to RK3528:</p><pre>[gui@gui-pc drivers]$ grep -riE rk3528<br>clk/rockchip/Makefile<br>clk/rockchip/clk-rk3528.c<br>cpufreq/cpufreq-dt-platdev.c<br>devfreq/event/rockchip-dfi.c<br>devfreq/rockchip_bus.c<br>devfreq/rockchip_dmc.c<br>gpu/arm/mali400/mali/platform/rk/rk.c<br>gpu/drm/rockchip/dw_hdmi-rockchip.c<br>gpu/drm/rockchip/rockchip_drm_tve.c<br>gpu/drm/rockchip/rockchip_drm_vkms.c<br>gpu/drm/rockchip/rockchip_drm_vop2.c<br>gpu/drm/rockchip/rockchip_vop2_reg.c<br>iio/adc/rockchip_saradc.c<br>mmc/host/sdhci-of-dwcmshc.c<br>net/ethernet/stmicro/stmmac/dwmac-rk.c<br>nvmem/rockchip-otp.c<br>pci/controller/dwc/pcie-dw-rockchip.c<br>phy/rockchip/phy-rockchip-inno-hdmi-phy.c<br>phy/rockchip/phy-rockchip-inno-usb2.c<br>phy/rockchip/phy-rockchip-naneng-combphy.c<br>pinctrl/pinctrl-rockchip.c<br>pmdomain/rockchip/pm-domains.c<br>soc/rockchip/rockchip-cpuinfo.c<br>soc/rockchip/rockchip_pm_config.c<br>thermal/rockchip_thermal.c<br>video/rockchip/mpp/mpp_rkvdec2.c<br>video/rockchip/mpp/mpp_rkvenc2.c</pre><p>Next, we focus on several key modules:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*FGEgTc5xW4F2O-RTuqd0pA.png" /></figure><p>Here is a precise and faithful English translation of your content:</p><p>In addition, some drivers may not be named with “RK3528”, so we still need to rely primarily on the device tree. For example, this RNG device:</p><pre>rng: rng@ffc50000 {<br>    compatible = &quot;rockchip,rkrng&quot;;<br>    reg = &lt;0x00 0xffc50000 0x0 0x200&gt;;<br>    interrupts = &lt;GIC_SPI 23 IRQ_TYPE_LEVEL_HIGH&gt;;<br>    clocks = &lt;&amp;scmi_clk SCMI_HCLK_TRNG&gt;;<br>    clock-names = &quot;hclk_trng&quot;;<br>    resets = &lt;&amp;cru SRST_HRESETN_TRNG_NS&gt;;<br>    reset-names = &quot;reset&quot;;<br>};</pre><p>Swipe up/down or left/right to view more.</p><p>We also need to complete support in dm/hwcrypto/hw-rng-rockchip.c.</p><h3>7. Start Porting Drivers</h3><p>In other words, once clk and pinctrl are supported, the Rock2F should be able to boot. Then, adding support for ADC, NVMEM, Thermal, and RNG will complete the porting process.</p><p><strong>Note:</strong> RK3528 uses GICv2:</p><pre>gic: interrupt-controller@fed01000 {<br>    compatible = &quot;arm,gic-400&quot;;<br>    #interrupt-cells = &lt;3&gt;;<br>    #address-cells = &lt;0&gt;;<br>    interrupt-controller;<br>    reg = &lt;0x00 0xfed01000 0x0 0x1000&gt;,<br>          &lt;0x00 0xfed02000 0x0 0x2000&gt;,<br>          &lt;0x00 0xfed04000 0x0 0x2000&gt;,<br>          &lt;0x00 0xfed06000 0x0 0x2000&gt;;<br>    interrupts = &lt;GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)&gt;;<br>};</pre><p>This has already been ported in DM. Simply enable RT_PIC_ARM_GIC to use it directly.</p><h3>CLK Porting</h3><p>Refer to RK3568.</p><p>Taking RK3568 as an example, we can see that DM already integrates many CLK modules (newer Rockchip SoCs may require additional modules):</p><pre>#include &quot;clk-rk-composite.h&quot;<br>#include &quot;clk-rk-cpu.h&quot;<br>#include &quot;clk-rk-divider.h&quot;<br>#include &quot;clk-rk-factor.h&quot;<br>#include &quot;clk-rk-fraction-divider.h&quot;<br>#include &quot;clk-rk-gate.h&quot;<br>#include &quot;clk-rk.h&quot;<br>#include &quot;clk-rk-half-divider.h&quot;<br>#include &quot;clk-rk-mmc-phase.h&quot;<br>#include &quot;clk-rk-muxgrf.h&quot;<br>#include &quot;clk-rk-mux.h&quot;<br>#include &quot;clk-rk-pll.h&quot;<br>#define DBG_TAG &quot;clk.rk3568&quot;<br>#define DBG_LVL DBG_INFO<br>#include &lt;rtdbg.h&gt;<br>#include &lt;dt-bindings/clock/rk3568-cru.h&gt;</pre><p>Each new driver requires filling in the CLK Cells table. Every device has its own CLK description, which can be referenced from the TRM and Linux implementation.</p><p>Then, during the platform bus probe phase, register the CLK into the system and also register the reset controller.</p><h3>RK3528 Implementation</h3><p>From the device tree, RK3528 has a syscon-based CRU and a main CRU:</p><pre>grf: syscon@ff300000 {<br>    compatible = &quot;rockchip,rk3528-grf&quot;, &quot;syscon&quot;, &quot;simple-mfd&quot;;<br>    reg = &lt;0x00 0xff300000 0x0 0x90000&gt;;<br>    grf_cru: grf-clock-controller {<br>        compatible = &quot;rockchip,rk3528-grf-cru&quot;;<br>        #clock-cells = &lt;1&gt;;<br>    };<br>};</pre><pre>cru: clock-controller@ff4a0000 {<br>    compatible = &quot;rockchip,rk3528-cru&quot;;<br>    reg = &lt;0x00 0xff4a0000 0x0 0x30000&gt;;<br>    rockchip,grf = &lt;&amp;grf&gt;;<br>    #clock-cells = &lt;1&gt;;<br>    #reset-cells = &lt;1&gt;;<br>    ...<br>};</pre><p>Follow the same approach as RK3568. Key parts to port include:</p><ul><li>Import clock IDs</li><li>Define PLL rate tables</li><li>Define CPU clock tables</li><li>Define parent clock sources</li><li>Define PLL and mux cells</li><li>Populate RT-Thread CLK cell tables</li><li>Register CRU and GRF clock cells</li></ul><p>RK3528 CLK is a new driver file and must be registered in:</p><ul><li>bsp/rockchip/dm/clk/Kconfig</li><li>bsp/rockchip/dm/clk/SConscript</li></ul><h3>Pinctrl Porting</h3><p>Similar to other SoCs. Rockchip pinctrl mainly includes four aspects:</p><ul><li>MUX (function multiplexing)</li><li>Pull-up/down</li><li>Drive strength</li><li>Schmitt trigger</li></ul><p>Add implementations in pinctrl-rockchip.c, including:</p><ul><li>set_mux</li><li>set_pull</li><li>set_drive</li><li>set_schmitt</li></ul><p>Then:</p><ul><li>Define GPIO banks</li><li>Define SoC pinctrl descriptor</li><li>Add device tree matching IDs</li></ul><h3>ADC Porting</h3><p>ADC porting is straightforward. Only channel descriptions need to be added:</p><pre>static const struct saradc_channel rockchip_rk3528_channels[] =<br>{<br>    SARADC_CHANNEL(0, &quot;adc0&quot;, 10),<br>    SARADC_CHANNEL(1, &quot;adc1&quot;, 10),<br>    SARADC_CHANNEL(2, &quot;adc2&quot;, 10),<br>    SARADC_CHANNEL(3, &quot;adc3&quot;, 10),<br>};</pre><p>Also define SoC-specific access methods and register device tree matching.</p><h3>NVMEM Porting</h3><p>Even simpler. Just define:</p><ul><li>OTP memory size</li><li>Read interface version</li></ul><h3>Thermal Porting</h3><p>Thermal requires:</p><ul><li>Temperature lookup tables</li><li>Sensor configuration</li><li>Implementation of new interface functions (based on hardware manual)</li></ul><h3>RNG Porting</h3><p>For RNG:</p><ul><li>Implement initialization and random read interfaces</li><li>Add device tree matching (rockchip,rkrng)</li></ul><h3>8. Boot Address</h3><p>Since we are replacing Linux directly, we need to know where U-Boot loads the kernel:</p><pre>radxa@rock-2f:~$ sudo cat /proc/iomem | grep -iE Kernel<br>  00410000-019affff : Kernel code<br>  02050000-024cffff : Kernel data</pre><p>So the load address is approximately 0x410000.</p><p>For RT-Smart:</p><ul><li>ARCH_TEXT_OFFSET = 0x410000</li><li>ARCH_RAM_OFFSET = 0x0</li></ul><h3>9. Toolchain Configuration</h3><p>The Rock2F uses Cortex-A53, while RK3500 defaults to Cortex-A55 (ARMv8.2+), which may cause instruction incompatibility.</p><p>Use minimal compatibility settings:</p><pre># For Cortex-A53/A72<br>DEVICE = &#39; -g -mcpu=cortex-a53 -fdiagnostics-color=always&#39;</pre><h3>10. Earlycon</h3><p>If the system crashes before showing any boot logo, enable early serial debugging:</p><pre>chosen {<br>    bootargs = &quot;console=ttyFIQ0,1500000n8&quot;;<br>};</pre><pre>aliases {<br>    serial0 = &quot;/serial@ff9f0000&quot;;<br>};</pre><pre>serial@ff9f0000 {<br>    compatible = &quot;rockchip,rk3528-uart&quot;,&quot;snps,dw-apb-uart&quot;;<br>    reg = &lt;0x000 0xff9f0000 0x000 0x100&gt;;<br>};</pre><pre>fiq-debugger {<br>    compatible = &quot;rockchip,fiq-debugger&quot;;<br>    rockchip,serial-id = &lt;0&gt;;<br>};</pre><p>The early UART address is 0xff9f0000, using a DWC 8250 UART.</p><h3>11. Boot Configuration</h3><p>Check the SBC boot method via /boot:</p><pre>ls /boot<br>lsblk</pre><p>It uses the familiar <strong>extlinux</strong> boot script:</p><pre>cat /boot/extlinux/extlinux.conf</pre><p>Add a new entry before label l0 to boot RT-Thread:</p><pre>label rt-thread<br>        menu RT-Thread<br>        linux /boot/rtthread.bin<br>        fdtdir /usr/lib/linux-image-6.1.43-26-rk2312/<br>        append earlycon=uart8250,mmio32,0xff9f0000 console=ttyFIQ0,1500000n8 root=sd1p0 rootfstype=elm rootwait rw</pre><h3>12. Start Booting</h3><p>Copy rtthread.bin into /boot (on the third MMC partition), reboot the board, and enter 1 in the boot menu to launch RT-Thread.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*XsbPPM1PbuluDx9W1363HQ.png" /></figure><p>Then we can see that we have entered the MSH:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/854/1*D6tDP_fXwAjLFiOXmCQD6g.png" /></figure><p>We directly reused a large number of device drivers from DM, so we can check how many devices are currently supported by the system:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*fmKz_TSNpIlzYVFBqHBMcw.png" /></figure><p>Except for SDMMC and NVMe, which we can mount and test directly, testing for other interfaces can refer to the official documentation:<br><a href="https://docs.radxa.com/rock2/rock2f/getting-started/interface-usage/pin-40-test">https://docs.radxa.com/rock2/rock2f/getting-started/interface-usage/pin-40-test</a></p><p>Next, we can check the status of other system subsystems:</p><h3>Interrupt Domain</h3><p>In the interrupt domain, we can observe the number of interrupts triggered by devices, as well as their cascading relationships and affinity. For example, NVMe uses the DWC PCI INTx interrupt, which is cascaded to the GICv2 of rk-pcie.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*XIj3h00THjAJaRTw426xqQ.png" /></figure><h3>Thermal Domain</h3><p>In the thermal domain, we can view the temperature of devices equipped with thermal sensors, along with their cooling methods, mechanisms, and trigger thresholds. Currently, only the CPU is present in this domain, using CPU DVFS for thermal management. Since DVFS has not yet been merged into the mainline, it is shown as unsupported here.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*d15Nfx6cZUQffWRdJ8aEcA.png" /></figure><h3>Clock Domain (Partial)</h3><p>In the clock domain, we can see the names and frequencies of system clocks, their enable counts, associated devices, and parent-child relationships.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*mRh_tgH2mfSVf3rHarX6EA.png" /></figure><h3>LED</h3><p>We can observe that the LED operates in a heartbeat pattern, which matches the configuration specified in the device tree:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/936/1*YXHYcySUxVcTf31cHus7pw.png" /></figure><pre>gpio-leds {<br>    compatible = &quot;gpio-leds&quot;;<br>    state-led {<br>        gpios = &lt;&amp;gpio3 RK_PC1 GPIO_ACTIVE_LOW&gt;;<br>        linux,default-trigger = &quot;heartbeat&quot;;<br>    };<br>};</pre><h3>Code Repository</h3><p>We can also review all the modifications:</p><pre>[gui@gui-pc rockchip]$ git status .<br>On branch rockchip_rk3528<br>Changes not staged for commit:<br>  (use &quot;git add &lt;file&gt;...&quot; to update what will be committed)<br>  (use &quot;git restore &lt;file&gt;...&quot; to discard changes in working directory)<br>        modified:     dm/adc/adc-rockchip_saradc.c<br>        modified:     dm/clk/Kconfig<br>        modified:     dm/clk/SConscript<br>        modified:     dm/hwcrypto/hw-rng-rockchip.c<br>        modified:     dm/include/pinctrl-rockchip.h<br>        modified:     dm/nvmem/nvmem-rockchip-otp.c<br>        modified:     dm/pinctrl/pinctrl-rockchip.c<br>        modified:     dm/thermal/thermal-rockchip_tsadc.c<br>        modified:     rk3500/README.md<br>        modified:     rk3500/README_ZH.md<br>        modified:     rk3500/rtconfig.h<br>        modified:     rk3500/rtconfig.py</pre><pre>Untracked files:<br>  (use &quot;git add &lt;file&gt;...&quot; to include in what will be committed)<br>        dm/clk/clk-rk3528.c<br>        dm/include/dt-bindings/clock/rk3528-cru.h</pre><p>Changes not staged for commit (use git add and/or git commit -a).</p><p>Pull Request:<br><a href="https://github.com/RT-Thread/rt-thread/pull/11300">https://github.com/RT-Thread/rt-thread/pull/11300</a></p><p>Slack: <a href="https://rtthreadhq.slack.com/archives/C0AHNBQLW5P">https://rtthreadhq.slack.com/archives/C0AHNBQLW5P</a><br>Discord: <a href="https://discord.com/channels/1444976234378428520/1444976235435524180">https://discord.com/channels/1444976234378428520/1444976235435524180</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=d7bfcffc9d16" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Wake Word Model Training with Edge Impulse]]></title>
            <link>https://rt-thread.medium.com/wake-word-model-training-with-edge-impulse-dbf4215d3092?source=rss-6ea18de1fff4------2</link>
            <guid isPermaLink="false">https://medium.com/p/dbf4215d3092</guid>
            <dc:creator><![CDATA[RT-Thread IoT OS]]></dc:creator>
            <pubDate>Wed, 18 Mar 2026 09:48:43 GMT</pubDate>
            <atom:updated>2026-03-18T09:48:43.860Z</atom:updated>
            <content:encoded><![CDATA[<p><strong>Introduction to Edge Impulse</strong></p><p>Edge Impulse is a leading edge AI development platform designed to help developers, engineers, and enterprises rapidly deploy intelligent AI to any edge device, such as microcontrollers, sensors, and IoT hardware.</p><p>With Edge Impulse, you can easily collect sensor data, build datasets, train and optimize machine learning models, and deploy them to thousands of hardware platforms worldwide with just one click — enabling fast prototyping and real-world deployment without requiring deep AI expertise.</p><p>Today, we’ll walk you step by step through how to train a wake word model and deploy it to embedded hardware using the Edgi-Talk platform integrated with Edge Impulse. The same principles also apply to other ARM-based embedded platforms. Let’s explore how to get started with edge machine learning on Edgi-Talk!</p><p><strong>Create an Account</strong></p><p><strong>Steps:</strong></p><ol><li>Go to Edge Impulse: <a href="https://edgeimpulse.com/">https://edgeimpulse.com/</a></li><li>Sign up for an account;</li><li>Create a project by clicking <strong>“Create New Project”</strong>.</li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ji-S-Uuqg15T8Xmyepe8Gg.png" /></figure><p><strong>Record Dataset</strong></p><ol><li>Flash the UAC firmware onto the Edgi-Talk development board to collect audio data: uac-firmware.hex;</li><li>Download the audio recording tool: Audio-recording.exe;</li><li>Connect the development board to your computer via USB — an audio input device will appear;</li><li>Select the audio input device: <strong>Audio Control (MME)</strong>;</li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/972/1*YXkMX-wHK9dhpYhfM5tndg.png" /></figure><p>5. Click <strong>Start Recording</strong> to record for 10 seconds. During recording, ensure clear speech, and leave a 1–2 second pause between wake words;</p><p>6. After each recording, click <strong>“Save Recording”</strong> on the right to save the file;</p><p>7. The file index will increment automatically — repeat the above steps to record 20–50 keyword audio samples;</p><p>8. Finally, prepare two types of audio data: one for the wake word and one for background noise.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/526/1*rbj4wVr0_X0BfHcrF6Oi4A.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*p-wMWWjMRjIQIaEpEiacOQ.png" /></figure><p><strong>Upload Data</strong></p><p><strong>Steps:</strong></p><ol><li>Click <strong>Add Existing Data</strong>;</li><li>Select <strong>Upload Data</strong>;</li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/916/1*Ep-ZVQi0tkJNZNyDQA46DA.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/924/1*bCEi7KEBzo0XJZe7qvBTxA.png" /></figure><p>3. Choose the folder on your computer containing the audio files and upload them. The platform will automatically categorize the files based on their names (e.g., <strong>noise</strong>, wake word).</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*OwTsavJbeMJUfyMbWpMR6w.png" /></figure><p><strong>Data Segmentation</strong></p><p><strong>Steps:</strong></p><ol><li>First, select the data in the <strong>Training</strong> list. Click <strong>Filter</strong> and enter the file prefix of your wake word recordings to filter the files you want to work on.</li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*2VVw3DpTqDFXk9bufCdjwg.png" /></figure><p>2. On the right, click an audio file and select <strong>Split Sample</strong>. The platform will split the audio into roughly 1-second segments.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*nLGIKre-3WmZmdf80MlZeg.png" /></figure><p>3. In the split audio interface, you can adjust each segment to fully cover the wake word. Play back the segments to check and fine-tune them.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*rr7ebXlH9DLpTi0_-yX4aA.png" /></figure><p>Each rectangle represents a segment extracted from the audio. You can move the rectangles to fully cover the wake word, or add/delete segments as needed.</p><p>4. The split segments will become independent audio files, and the platform will automatically append a suffix to each file (e.g., xxxx_Sn).</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*re9C26C87ggbgIpUJPOKXg.png" /></figure><p>5. Repeat the above steps to segment all wake word training files.</p><p>6. Select the data in the <strong>Test</strong> list and similarly split the wake word files. Noise-labeled files do not need to be split.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1010/1*TqsD2EgKR1EXzr7idOrV5A.png" /></figure><p>7. Classify the data: as shown in the diagram, divide the dataset into two main categories: <strong>Wake Word</strong> + <strong>Others</strong>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1016/1*UcDAn7h9ZBbBZGkPQCsmVw.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*KyolLiL-4yEpXQw4ENpGcQ.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*chmDFE4ibylr6dhZtRxRJw.png" /></figure><p><strong>Model Training</strong><br><strong>Create an Impulse (Preprocessing / Model Definition)</strong><br>An impulse here is Edge Impulse’s term for a data processing and training pipeline.</p><p>Create an impulse and set the window size to 1000 ms, window increase to 500 ms (overlapping windows to augment data), and frequency to 16 kHz.<br>These settings mean that each inference collects sensor data over 1000 ms, with the number of samples determined by the sampling frequency.<br>In short, your device collects N data samples within a 1000 ms window, then preprocesses them and feeds them into the neural network for inference.</p><p><strong>Steps:</strong></p><ol><li>Click <strong>Create Impulse</strong> on the left;</li><li>Click <strong>Add a Processing Block</strong> and add <strong>Audio (MFCC)</strong>;</li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/886/1*IphD99FStRrDDEVH90AXCA.png" /></figure><p>3. A dialog will pop up — use the default settings;</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*AjEDC6xOWtFpuwBz7opMfA.png" /></figure><p>4. MFCC extracts features from audio signals using Mel-Frequency Cepstral Coefficients, which is very useful for human voice;</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*pmmn9DXEnTgmjLPkgysUFg.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Lb9JR1jwqBwgRkLfMdo1aw.png" /></figure><p>5. Click <strong>Add a Learning Block</strong> and add a <strong>Classification</strong> module, which builds our model from scratch using a convolutional neural network;</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ELHC4-MVVVe0Xm7gHyJzxg.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*siP2PR-_XhpedF79b2duTQ.png" /></figure><p>6. Finally, click <strong>Save Impulse</strong> to save the configuration.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*PYW_Ggoq0jq4aunh5W71cg.png" /></figure><p><strong>Preprocessing (MFCC)</strong><br>MFCC is a widely used method to convert audio signals into 2D features representing speech frequency patterns, which are ideal for speech-based recognition models.<br>We create spectrogram images from the recorded audio.</p><p><strong>Steps:</strong></p><ol><li>Click <strong>MFCC</strong> and keep the default parameter values;</li><li>Click <strong>Save Parameters</strong>;</li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/1020/1*-g-qZts6hM2CmTQRGHQKnw.png" /></figure><p>3. Click <strong>Generate Features</strong> to generate features for the three labeled datasets.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*zlZ2L-OwUEmiQ8175oT3wQ.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*lb7p36bjv3PwiJkzOhWlAw.png" /></figure><p><strong>Model Design and Training (Classifier)</strong><br>Next, we design the model structure and start training.</p><p><strong>Steps:</strong></p><ol><li>Click <strong>Classifier</strong> on the left — the model structure is already configured;</li><li>Click <strong>Save &amp; Train</strong> to start training the model.</li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*13cjwdxtamuJPj7kgDwaAg.png" /></figure><p>Through multiple iterations, the model’s generalization can be improved. Methods include optimizing the test dataset and adjusting the model structure (e.g., adding more convolutional layers).<br>The platform has a limit on training time: free users can train for up to 20 minutes per session. Unlimited training requires a paid plan.</p><p><strong>Model Evaluation</strong></p><p><strong>Steps:</strong></p><ol><li>Click <strong>Model Testing</strong> on the left;</li><li>Click <strong>Classify All</strong>;</li><li>Classify all test dataset data;</li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*_unTGSu-0-fitNORNQWMrQ.png" /></figure><p>4. After testing, view the results on the right under <strong>Result</strong>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*DRDwe_wuJtGpMjoTxSJ1rw.png" /></figure><p><strong>Model Integration</strong><br><strong>Generate Library File</strong><br>After training, generate a library file that can run on the Edgi-Talk platform.</p><p><strong>Steps:</strong></p><ol><li>Click <strong>Deployment</strong> on the left;</li><li>Search for <strong>Arduino Library</strong> and <strong>TensorFlow Lite</strong>;</li><li>Click <strong>Build</strong>. After building, save and download the library files.</li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*yVVPAywfkHkf_VY2PM4kJA.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*76FR50JIEORijnLdBfSluA.png" /></figure><p><strong>Deploy to Embedded Hardware</strong></p><ol><li>Unzip the downloaded package to get the file directory;</li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*0lxSimsIi2sI_YI8TBRiIg.png" /></figure><p>2. Obtain the latest Edgi-Talk SDK and enter Edgi_Talk_M55_XiaoZhi/edge-impulse directory. Delete the two folders shown, then replace them with the two folders from the previous step to update the model files;</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*jIcY5o6isq2q4F4xV_bAVQ.png" /></figure><p>3. Compile the Edgi_Talk_M55_XiaoZhi project and flash it to the development board;</p><p>4. On the Edgi-Talk serial terminal, enter the following commands to start the wake word test:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*h5vre6oqZ9Iy6xgFgsIFdg.png" /></figure><p>5. Say the wake word to the board. In this demo, the wake word is <strong>“xiaorui, xiaorui”</strong>. When spoken, the serial terminal will print logs.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*VQp2KnEokNyII5n7pPajiQ.png" /></figure><p>Join our global community on Slack or Discord to connect directly with official experts and developers.</p><p>Slack: <a href="https://rtthreadhq.slack.com/archives/C0AHNBQLW5P">https://rtthreadhq.slack.com/archives/C0AHNBQLW5P</a><br>Discord: <a href="https://discord.com/channels/1444976234378428520/1444976235435524180">https://discord.com/channels/1444976234378428520/1444976235435524180</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=dbf4215d3092" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[XiaoZhi AI Experiment]]></title>
            <link>https://rt-thread.medium.com/xiaozhi-ai-experiment-373a2b028a24?source=rss-6ea18de1fff4------2</link>
            <guid isPermaLink="false">https://medium.com/p/373a2b028a24</guid>
            <dc:creator><![CDATA[RT-Thread IoT OS]]></dc:creator>
            <pubDate>Mon, 16 Mar 2026 09:47:58 GMT</pubDate>
            <atom:updated>2026-03-16T09:47:58.692Z</atom:updated>
            <content:encoded><![CDATA[<h3>1. Enter the XiaoZhi AI Project</h3><p>Open the XiaoZhi AI project: <strong>Edgi_Talk_M55_XiaoZhi</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*KQCz7Se6nQctJ76cpkBX0w.png" /></figure><h3>Firmware Compilation</h3><p>Open <strong>Env</strong> and run the following command to compile the project:</p><pre>scons</pre><p>After compilation, the firmware file <strong>rtthread.hex</strong> will be generated in the current directory.</p><h3>Firmware Flashing</h3><p>The flashing method is the same as described in the <strong>environment setup</strong> section.</p><p>Use the <strong>OpenOCD</strong> tool to flash the firmware through the command line.</p><pre>./openocd.exe -s ../scripts -s ../flm/cypress/cat1d -f interface/kitprog3.cfg -f target/infineon/pse84xgxs2.cfg -c &quot;set QSPI_FLASHLOADER ../flm/cypress/cat1d/PSE84_SMIF.FLM&quot; -c &quot;transport select swd&quot; -c &quot;set ENABLE_ACQUIRE 0&quot; -c &quot;init; reset init; flash write_image erase ./rtthread.hex; reset run; exit&quot;</pre><h3>How to Configure the XiaoZhi App Network Connection</h3><p><strong>Note:</strong></p><p>If you have an <strong>SD card</strong>, insert it into the development board’s SD card slot.</p><p>The device will <strong>automatically reconnect to the network on the next boot</strong>.</p><h3>First-Time Network Setup</h3><p>When the development board is powered on for the first time, it will <strong>enter AP mode by default</strong>.</p><p>1. Find and connect to the corresponding <strong>Wi-Fi AP</strong> broadcast by the board.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/550/1*q2gJeV7UHTQ0Q-kXGIYX_w.png" /></figure><p>2. The <strong>Wi-Fi password is displayed on the screen</strong>.</p><p>After successfully connecting to the AP, open a browser on your device and enter:</p><p>192.168.169.1</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/556/1*AmVyJMBTJX2ignV7ecknQw.png" /></figure><p>This will open the <strong>configuration interface</strong> for network setup.</p><h3>Steps to Connect to Wi-Fi</h3><ol><li>Click <strong>Scan</strong> to search for nearby Wi-Fi networks.</li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/554/1*e-Me05wPIsWZMd2_Y4X6lQ.png" /></figure><p>2. Select the Wi-Fi you want to connect to and enter the password.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/548/1*fzbpYagLN5-3wqh_fGuR2A.png" /></figure><p>3. After a successful connection, the interface will display the connection status.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/530/1*jSDK4c2H_zy1u_2_QKPXfQ.png" /></figure><h3>XiaoZhi AI — Meaning of the Status Emojis</h3><p><strong>Connecting to the network</strong></p><p>The device is connecting to the network. Please wait until the process is completed.<strong>Listening for conversation</strong></p><p>The device is waiting for interaction.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/558/1*hiq7ciin1ES3PFUgm7UuBA.png" /></figure><p>At this moment, press the <strong>user button</strong> or say the wake word <strong>“Xiao Rui, Xiao Rui”</strong>, then start speaking.</p><p><strong>Listening state</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/430/1*OcJ7mwcv73ewoXf5TvFICQ.png" /></figure><p>XiaoZhi enters the listening mode and begins capturing the conversation.</p><p>After you finish speaking and pause, the system will process the input.<strong>In conversation</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/554/1*4H88J5pbms5kw1pDCZMmhg.png" /></figure><p>XiaoZhi is generating and replying to your request.<strong>Sleep mode</strong></p><p>The device enters <strong>low-power mode</strong>.</p><p>Press the <strong>user button</strong> once to wake it up, wait until the screen shows <strong>Standby</strong>, and then you can continue the conversation.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/530/1*iIC7Le5-iAv6q4iq-rLnmw.png" /></figure><h3>MCP Control of Development Board Peripherals</h3><p><strong>MCP (Model Context Protocol)</strong> is a <strong>lightweight implementation adapted for resource-constrained embedded devices</strong>, created by simplifying the Model Context Protocol to its essential components.</p><h3>Core Objective</h3><p>Enable <strong>edge microcontrollers or small SoCs</strong> to act directly as an <strong>MCP Server</strong>, exposing hardware capabilities such as:</p><p>● GPIO control</p><p>● Sensor reading</p><p>● Motor driving</p><p>● LED control</p><p>● IoT data reporting</p><p>These capabilities can then be <strong>remotely invoked by an LLM through a standardized protocol</strong>, enabling <strong>natural language control of the physical world</strong>.</p><h3>Currently Supported Peripheral Controls</h3><p>● LED indicator</p><p>● Screen brightness</p><p>● Volume level</p><h3>How to Use</h3><p>1. Press the <strong>first user button</strong> on the development board to start a conversation.</p><p>2. XiaoZhi enters <strong>listening mode</strong>.</p><p>3. Speak commands such as:</p><p>● “Turn on the light”</p><p>● “Turn off the light”</p><p>● “Increase the screen brightness”</p><p>● “Increase the volume”</p><p>These commands will trigger <strong>MCP-based control of the board’s peripherals</strong>.</p><h3>XiaoZhi MCP LED Control Principle</h3><p><strong>1. MCP Initialization</strong></p><p>Send the <strong>IoT descriptor</strong> during MCP initialization.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*jcGsWMJ9CA8YHif1vuUlpw.png" /></figure><p><strong>2. Register IoT device</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*GXPe1BYUtj2Zv1OBNYBXEQ.png" /></figure><p><strong>3. LED control tool</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*rEP6Iup1d05dudcNY7ACUw.png" /></figure><p>Expose the LED control function as a tool that can be called through MCP.<strong>4. Driver mapping</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*yCVN0aIMgytYWRe0TaS8fw.png" /></figure><p>Each control method corresponds to a <strong>specific hardware driver implementation</strong>.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=373a2b028a24" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Development of a Multifunctional Motor Driver Based on RT-Thread and Renesas VisionBoard |…]]></title>
            <link>https://rt-thread.medium.com/development-of-a-multifunctional-motor-driver-based-on-rt-thread-and-renesas-visionboard-809a1acd5af9?source=rss-6ea18de1fff4------2</link>
            <guid isPermaLink="false">https://medium.com/p/809a1acd5af9</guid>
            <dc:creator><![CDATA[RT-Thread IoT OS]]></dc:creator>
            <pubDate>Wed, 11 Mar 2026 09:43:22 GMT</pubDate>
            <atom:updated>2026-03-11T09:43:22.983Z</atom:updated>
            <content:encoded><![CDATA[<h3>Development of a Multifunctional Motor Driver Based on RT-Thread and Renesas VisionBoard | Technical Collection</h3><h3>1. Introduction</h3><p>This project focuses on developing a multifunctional motor driver based on the Renesas VisionBoard MCU. The core functionality enables communication between external devices and the driver through the RS-485 serial protocol, allowing control commands such as motor start and stop.</p><p>During the development process, several additional hardware circuits were temporarily added to enrich the functionality, including general-purpose isolated input/output circuits and stepper motor drivers. At present, the power module, brushless motor driver module, and RS-485 communication module have completed functional verification.</p><p>This project was mainly a hands-on learning process. During development, I explored a new PCB design tool to complete circuit layout and routing (although the layout still needs further optimization). I also learned the basics of the RT-Thread operating system and gained initial experience working with the Renesas VisionBoard chip and its development tools.</p><p>Since this is my first time participating in such a project and the whole process was mainly for personal learning and experimentation, the current design may appear somewhat messy. I appreciate your understanding.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*AlfgYbFnlLQBdDqzj7N8CQ.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*SenRMawT5KpT6Hb_PfyYmw.png" /></figure><p>Additionally, some modules were added simply to try out different ideas. In the future, I plan to redesign the PCB and reorganize the hardware modules. In this version, the functions were implemented module by module without full system integration.</p><p>Later in the project, I also designed an additional BTB expansion board. Initially, I expected that the Raspberry Pi PWM interface could provide three PWM outputs to achieve complementary PWM signals for six-step commutation of the BLDC motor. However, due to limited familiarity with the tools and insufficient available IO resources, I created a temporary expansion board that includes LED digital displays and an OLED module while exposing the BTB IO pins via headers.</p><h3>2. Design Architecture</h3><h3>2.1 Motor Module</h3><h3>2.1.1 Motor Selection</h3><p>Two types of motors were selected to cover different application scenarios:</p><p>● <strong>Brushless DC motor (BLDC):</strong> suitable for continuous rotation applications</p><p>● <strong>Stepper motor:</strong> suitable for high-precision position control</p><h3>2.1.2 Brushless Motor Control</h3><p>The BLDC motor drive is implemented using dedicated hardware circuits.</p><p><strong>Core driver</strong></p><p>The EG2123A BLDC driver IC (U29) is used to generate phase drive signals for the motor.</p><p><strong>Current monitoring</strong></p><p>INA240 bidirectional current sensing amplifiers (U25, U26) are used to monitor the phase current of the brushless motor in real time.</p><p><strong>Power stage</strong></p><p>A power MOSFET stage (Q4, Q5, etc.) amplifies the drive signals before they are connected to the motor through connector J8.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*eaYWbz_rATP9u0hbodbO8Q.png" /></figure><p>The waveform of the driver signal was measured during testing. The motor can rotate, but there may still be some issues requiring further debugging and testing.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*il6zKbGk4Q2hKpUdbWLxbQ.png" /></figure><h3>2.1.3 Stepper Motor Control</h3><p>Stepper motor control is implemented using the A4988 microstepping driver.</p><p><strong>Driver IC</strong></p><p>Two A4988 stepper motor driver chips (U1, U2) are used, supporting DIR (direction) and STEP (pulse) control signals.</p><p><strong>Current monitoring</strong></p><p>INA219 current sensors (U3, U4) are used to monitor the working current of the stepper motors.</p><p><strong>Interface</strong></p><p>The motors are connected through connectors J10 and J13 to transmit control signals.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*q4q7uIEanYDw0xKhoHF6mg.png" /></figure><h3>2.2 Main Control Board and Button Module</h3><h3>2.2.1 Main Controller Selection</h3><p>The Renesas VisionBoard MCU is used as the main controller, responsible for:</p><p>● Parsing RS-485 communication commands</p><p>● Generating motor control signals</p><p>● Managing the logical scheduling of different functional modules</p><h3>2.2.2 Communication Module (RS-485 Serial Communication)</h3><p>The design adopts an <strong>isolated and independently powered RS-485 communication architecture</strong>.</p><p><strong>Signal isolation</strong></p><p>The TJA121M31 chip (U13) is used to isolate the control signals between the MCU and the RS-485 bus.</p><p><strong>Bus transceiver</strong></p><p>The GM485E transceiver (U16) converts MCU UART signals to differential RS-485 signals.</p><p><strong>Power isolation</strong></p><p>A B0505S-1WR3 isolated power module (U14) provides an independent power supply for the RS-485 circuit to prevent ground interference.</p><p><strong>External interface</strong></p><p>External RS-485 devices are connected via connector J15.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*8mJ_uRtDY-xD8iCMCXAO_g.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*huKdedDOqZTRdY5G5541oQ.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*9JLFA67EdBnBj8Kuz8SmrQ.png" /></figure><p>During testing, the communication waveform was captured successfully, indicating functional operation. However, the waveform amplitude did not reach the expected 3.3V peak and may require further adjustment.</p><h3>2.2.3 General-Purpose Isolated Input/Output Module</h3><p>Signal isolation is implemented using EL357N optocouplers.</p><p><strong>Isolated input</strong></p><p>External signals pass through a 2.2k current-limiting resistor and a 1N4148W protection diode before entering optocouplers (U18, U19). The signals are then transmitted to the MCU input pins (MCU_IN1–IN4 via interface U40).</p><p><strong>Isolated output</strong></p><p>MCU output signals (MCU_OUT1–OUT2) are transmitted through optocouplers (U20, U21) before reaching external interfaces (U42, U7). Pull-up resistors (4.7kΩ) are used to enhance driving capability.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*z5OTH8mSguzhqVv6CieEyQ.png" /></figure><h3>2.3 Power Module</h3><p>A multi-stage voltage regulation architecture was designed to power different modules.</p><p><strong>+12V input</strong></p><p>The +12V input is regulated through chip U54 to supply high-power circuits such as the BLDC motor driver.</p><p><strong>12V to 5V conversion</strong></p><p>The U35 converter steps down 12V to 5V, which powers the RS-485 communication module and BLDC driver circuits.</p><p><strong>5V to 3.3V conversion</strong></p><p>An RT90L3–33GB LDO (U36) converts 5V to 3.3V to power the MCU, optocouplers, and current sensing chips.</p><p><strong>Filtering</strong></p><p>Each power branch uses 10 µF and 0.1 µF capacitors to provide voltage stabilization and filtering.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*z1zPIrmQjmJH6u-2b6zIXQ.png" /></figure><p>Power ripple measurements indicate relatively stable performance, although further optimization of resistor and capacitor values may improve the design.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*YmRMaL8o3Yi1gzrl4GFovQ.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*hqXWNUqB9XCC9PaPSzzHkA.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*MJlEsicPrsCGt8O9C8DbqQ.png" /></figure><p>Additional oscilloscope captures show the voltage waveforms after step-down conversion.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*8DKnQ2b_tnumwqZn9kfvwQ.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*vodyguA1fybWbTSXkLR2uA.png" /></figure><h3>3. Code Implementation</h3><h3>3.1 Source Code</h3><p>The project shares the RT-Thread adaptation code for the Renesas VisionBoard.</p><p>The code includes modules such as:</p><p>● RS-485 driver</p><p>● BLDC motor driver</p><p>● Power monitoring</p><p>● System initialization and command parsing logic</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*DvC5sCGVVoW_oJmQ5zByDA.png" /></figure><p>Configuration is implemented using <strong>Renesas FSP (rasc) configuration tools</strong>, along with application code.</p><p>PWM parameters such as <strong>dead time, waveform mode, and switching frequency</strong> should be adjusted according to actual hardware requirements.</p><p>For reference, developers can consult the RT-Thread guide:</p><p>● <em>RA8D1 Vision Board Development Practice Guide</em></p><p>● <em>IIC Practice on RA8D1 Vision Board</em></p><p>● <em>ADC Practice on Vision Board</em></p><p>● <em>PWM Module Practice on Vision Board</em></p><p>RT-Thread community resources are available at:</p><p><a href="https://club.rt-thread.org">https://club.rt-thread.org</a></p><p><strong>motor_ctrl.c</strong></p><pre>#include &quot;FOC.h&quot; #include &quot;rtdevice.h&quot;<br><br>#define MOTOR_THREAD_STACK_SIZE    2048<br><br>#define MOTOR_THREAD_PRIORITY      8<br><br>#define MOTOR_THREAD_TIMESLICE     10<br><br>#define MAX_TARGET_SPEED_RPM       2400.0f<br><br>#define SPEED_RAMP_RATE            100.0f<br><br>static float current_target_speed = 0.0f;<br><br>static rt_bool_t motor_enabled = RT_FALSE;<br><br>static rt_uint16_t motor_pole_pairs = 7;<br><br>static float rpm_to_radps(float rpm) {<br><br>      return rpm  2.0f  PI / 60.0f;<br><br>}<br><br>static float radps_to_rpm(float radps) {<br><br>     return radps  60.0f / (2.0f  PI); <br><br>}<br><br>static float speed_ramp(float target_speed, float current_speed, float dt) {<br><br>      float max_delta = SPEED_RAMP_RATE * dt;<br><br>       if (target_speed &gt; current_speed) {<br><br>                 current_speed += max_delta; <br><br>                    if (current_speed &gt; target_speed) current_speed = target_speed; <br><br>        } else {  <br><br>                  current_speed -= max_delta; <br><br>                  if (current_speed &lt; target_speed) current_speed = target_speed; <br><br>        } return current_speed; <br><br>}<br><br>static void motor_thread_entry(void *parameter) {<br><br>   static rt_tick_t last_time = 0; <br><br>   static float current_speed_rpm = 0.0f;<br><br>foc_init(); foc_start(); motor_enabled = RT_TRUE;<br><br>while (1) { rt_tick_t current_time = rt_tick_get(); float dt = (current_time - last_time) * 0.001f; if (dt &lt;= 0) dt = 0.001f;<br><br>if (motor_enabled) {<br>    float target_velocity = get_target_velocity();<br>    float target_speed_rpm = radps_to_rpm(target_velocity);<br>    <br>    target_speed_rpm = target_speed_rpm &gt; MAX_TARGET_SPEED_RPM ? MAX_TARGET_SPEED_RPM : target_speed_rpm;<br>    target_speed_rpm = target_speed_rpm &lt; -MAX_TARGET_SPEED_RPM ? -MAX_TARGET_SPEED_RPM : target_speed_rpm;<br>    <br>    current_speed_rpm = speed_ramp(target_speed_rpm, current_speed_rpm, dt);<br>    <br>    float target_mech_radps = rpm_to_radps(current_speed_rpm);<br>    FOC_M0_SET_VEL(target_mech_radps);<br>    <br>    foc_loop();<br>    <br>    if (current_time - last_time &gt; RT_TICK_PER_SECOND) {<br>        float actual_vel = getVelocity();<br>        float actual_rpm = radps_to_rpm(actual_vel);<br>        rt_kprintf(&quot;Motor: Target=%.1fRPM, Actual=%.1fRPM\n&quot;, current_speed_rpm, actual_rpm);<br>        last_time = current_time;<br>    }<br>} else {<br>    current_speed_rpm = 0;<br>    FOC_M0_SET_VEL(0);<br>}<br><br>rt_thread_mdelay(1);<br>last_time = current_time;<br><br>}<br><br>}<br><br>void motor_start(void) {<br><br>     rt_thread_t tid = rt_thread_create(&quot;motor&quot;, motor_thread_entry, RT_NULL,                                                                                                          MOTOR_THREAD_STACK_SIZE, MOTOR_THREAD_PRIORITY,                                                                          MOTOR_THREAD_TIMESLICE); <br><br>     if (tid) { rt_thread_startup(tid); <br><br>    }<br><br>}<br><br>void motor_enable(rt_bool_t enable) {<br><br>    motor_enabled = enable; <br><br>    if (!enable) {<br><br>          set_target_velocity(0); <br><br>     } <br><br>}</pre><p><strong>rs485.c</strong></p><pre>#include &quot;bsp_rs485.h&quot;<br>#include &quot;hal_data.h&quot;<br><br>#define RS485_RX_BUF_SIZE 100<br>#define RS485_SWITCH_DELAY 10<br><br>static uint8_t rs485_rx_data[RS485_RX_BUF_SIZE];<br>static volatile uint16_t rs485_rx_datalen;<br>static volatile bool rs485_rx_complete;<br>static volatile bool rs485_tx_complete;<br><br>fsp_err_t RS485_Init(void)<br>{<br>    fsp_err_t err = FSP_SUCCESS;<br>    err = R_SCI_B_UART_Open(&amp;g_uart2_rs485_ctrl, &amp;g_uart2_rs485_cfg);<br>    if(FSP_SUCCESS != err) return err;<br>    err = R_SCI_B_UART_Read(&amp;g_uart2_rs485_ctrl, rs485_rx_data, RS485_RX_BUF_SIZE);<br>    return err;<br>}<br><br>void RS485_Print(uint8_t *str, uint32_t strlen)<br>{<br>    RS485_TX_EN;<br>    R_BSP_SoftwareDelay(RS485_SWITCH_DELAY, BSP_DELAY_UNITS_MILLISECONDS);<br>    rs485_tx_complete = false;<br>    R_SCI_B_UART_Write(&amp;g_uart2_rs485_ctrl, str, strlen);<br>    while(false == rs485_tx_complete);<br>    R_BSP_SoftwareDelay(RS485_SWITCH_DELAY, BSP_DELAY_UNITS_MILLISECONDS);<br>    RS485_RX_EN;<br>}<br><br>uint16_t RS485_GetRxData(uint8_t *buf, uint16_t len)<br>{<br>    uint16_t copy_len = (rs485_rx_datalen &lt; len) ? rs485_rx_datalen : len;<br>    R_BSP_InterruptsDisable();<br>    memcpy(buf, rs485_rx_data, copy_len);<br>    rs485_rx_datalen = 0;<br>    rs485_rx_complete = false;<br>    R_BSP_InterruptsEnable();<br>    R_SCI_B_UART_Read(&amp;g_uart2_rs485_ctrl, rs485_rx_data, RS485_RX_BUF_SIZE);<br>    return copy_len;<br>}<br><br>bool RS485_GetRxComplete(void)<br>{<br>    return rs485_rx_complete;<br>}<br><br>void rs485_uart2_callback(uart_callback_args_t *p_args)<br>{<br>    switch(p_args-&gt;event)<br>    {<br>        case UART_EVENT_RX_COMPLETE:<br>            rs485_rx_complete = true;<br>            break;<br>        case UART_EVENT_RX_CHAR:<br>            R_BSP_InterruptsDisable();<br>            if(rs485_rx_datalen &lt; RS485_RX_BUF_SIZE)<br>            {<br>                rs485_rx_data[rs485_rx_datalen] = (uint8_t)p_args-&gt;data;<br>                rs485_rx_datalen++;<br>            }<br>            R_BSP_InterruptsEnable();<br>            break;<br>        case UART_EVENT_TX_COMPLETE:<br>            rs485_tx_complete = true;<br>            break;<br>        default:<br>            break;<br>    }<br>}</pre><p>Have questions while using the RT-Thread RTOS? Join our global community on Slack or Discord to connect directly with official experts and developers.</p><p>Slack: <a href="https://rtthreadhq.slack.com/archives/C0AHNBQLW5P">https://rtthreadhq.slack.com/archives/C0AHNBQLW5P</a></p><p>Discord: <a href="https://discord.com/channels/1444976234378428520/1444976235435524180">https://discord.com/channels/1444976234378428520/1444976235435524180</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=809a1acd5af9" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Smart Door Lock: Multi-Peripheral Embedded Practice Based on RT-Thread and FRDM-MCXA156 | Technical…]]></title>
            <link>https://rt-thread.medium.com/smart-door-lock-multi-peripheral-embedded-practice-based-on-rt-thread-and-frdm-mcxa156-technical-9bfab8836212?source=rss-6ea18de1fff4------2</link>
            <guid isPermaLink="false">https://medium.com/p/9bfab8836212</guid>
            <dc:creator><![CDATA[RT-Thread IoT OS]]></dc:creator>
            <pubDate>Wed, 25 Feb 2026 09:45:30 GMT</pubDate>
            <atom:updated>2026-02-25T09:45:30.780Z</atom:updated>
            <content:encoded><![CDATA[<h3>Smart Door Lock: Multi-Peripheral Embedded Practice Based on RT-Thread and FRDM-MCXA156 | Technical Collection</h3><p>This project is an award-winning work from the RT-Thread Embedded Competition. It builds a multifunctional smart door lock control system based on NXP’s MCXA156 series microcontroller.</p><p>Currently, multiple products from NXP Semiconductors have completed adaptation with RT-Thread. Recently, an important member of the MCX A series, FRDM-MCXA346, has also completed adaptation. With the collaboration of community developers, the eBook <em>FRDM-MCX A346 Development Practice Guide</em> has been published (see the contributor list and development board details at the end of this article ↓).</p><h3>1. Project Overview</h3><p>This project builds a multifunctional smart door lock control system based on the MCXA156 series microcontroller. It integrates three unlocking methods: password, fingerprint, and RFID card. The system features a local OLED display and audio-visual feedback mechanisms. EEPROM is used to achieve persistent key storage, forming an embedded solution that balances security and convenience.</p><p>The system supports local key modification, real-time unlocking status feedback, and error alarms. It can be widely applied to access control scenarios in homes, offices, and other environments.</p><h3>Design Concept Proposal</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*15AHmPBbh0uKp7mPN6c5pg.png" /></figure><h3>System operation flowchart</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*dK4oKFtUxicRwx1AZA6VwQ.png" /></figure><h3>Core Features</h3><p><strong>Multi-mode unlocking:</strong></p><p>● Supports three unlocking methods: 6-digit numeric password, FPM383C fingerprint recognition, and RC522 RFID card, meeting the needs of different usage scenarios.</p><p><strong>Key management:</strong></p><p>● Uses 24CXX series EEPROM for persistent storage of unlocking keys. Supports local key modification via buttons, with automatic synchronization to storage after changes.</p><p><strong>Status visualization:</strong></p><p>● With the SSD1306 OLED display, the system shows the current interface status, number of entered password digits, unlocking results, and other real-time information.</p><p><strong>Audio-visual feedback:</strong></p><p>● When unlocking succeeds, the LED lights up with an icon prompt. When the password is incorrect, the buzzer alarms and the icon flashes, enhancing user interaction experience.</p><p><strong>Concurrent task handling:</strong></p><p>● Based on bare-metal programming, the system enables concurrent execution of sensor scanning, button processing, display updates, and alarm control, ensuring real-time responsiveness.This article will further break down the system’s hardware selection, software architecture, core logic implementation, and key development details, providing practical reference for embedded access control system development.</p><h3>2. Hardware Selection and Connections</h3><p><strong>Core Controller: FRDM-MCXA156</strong></p><p>The FRDM-MCXA156 microcontroller is selected as the core control unit. Its advantages are as follows:</p><p><strong>Performance:</strong></p><p>Equipped with an ARM Cortex-M series core, it provides efficient instruction execution capability to meet the requirements of multi-peripheral concurrent control and algorithm processing. It also features rich interfaces such as I2C, SPI, UART, PWM, and GPIO, allowing direct connection of all functional modules without the need for additional expansion boards.</p><h3>Module Functions</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*sxIIvPcZt2qVFl52ROZCTQ.png" /></figure><h3>Communication Protocol Flowchart</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*L5cdQ9aPmwS3RRxB-dvHZA.png" /></figure><h3>Hardware Connection Details</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*LPAHMDtOfsbB8xvK5YIHIg.png" /></figure><h3>3. Software Architecture Design</h3><p>The software of this project is developed based on the official demo of RT-Thread 5.2.1. The system functions are divided into multiple independent modules, and global variables are used to enable data interaction between modules, ensuring code maintainability and scalability.</p><h3>Overall Architecture</h3><p>The system software consists of five core modules. Each module works independently while collaborating with others:</p><p><strong>Peripheral Driver Module:</strong></p><p>Responsible for initialization and low-level operations of hardware peripherals (such as UART, I2C, SPI, PWM, GPIO, etc.).<strong>Core Control Module:</strong></p><p>Implements unlocking logic, key verification, and status management.<strong>Input Processing Module:</strong></p><p>Handles button input, fingerprint recognition results, and RFID card data reading.<strong>Display Control Module:</strong></p><p>Manages OLED screen interface refresh and information display.<strong>Feedback Module:</strong></p><p>Controls LED and buzzer to provide status feedback for successful unlocking or error alarms.</p><h3>Workflow Details</h3><h4>System Initialization Phase</h4><p>After startup, the system sequentially completes:</p><p>● Interrupt priority configuration</p><p>● Serial port initialization</p><p>● Initialization of all peripherals (fingerprint module, RC522, OLED, buttons, EEPROM, PWM)</p><p>It then checks whether the EEPROM is functioning properly. If an abnormal condition is detected, the LED flashes as an indication. The pre-stored 6-digit unlocking key is read from EEPROM and stored in the global variable open_lock_key.</p><h4>Main Loop Tasks (Executed Infinitely)</h4><p><strong>Sensor scanning:</strong></p><p>Continuously calls fpm383c_Scan() (fingerprint scanning) and RC522_Scan() (RFID scanning) to wait for recognition results.</p><p>Uses key_Scan() to detect button input and process number input, password confirmation, deletion, interface switching, and other operations.</p><p>After entering a 6-digit password, it is compared with the stored unlocking key:</p><p>● If matched, unlocking is triggered.</p><p>● If not matched, the alarm is activated.</p><p>Based on the unlocking result or error status, the system controls the LED and buzzer accordingly and updates the OLED display simultaneously.</p><p><strong>Inter-thread communication:</strong></p><p>Global variables such as open_door_type (unlock status), open_door_alert (alarm status), and interface_num (interface identifier) are used to enable data interaction between modules. This simplifies communication logic while ensuring real-time system responsiveness.</p><h3>4. Core Module Implementation</h3><h3>EEPROM Key Storage and Reading</h3><p>A 24CXX EEPROM is used to achieve persistent key storage, ensuring that the key is not lost after power-off.</p><p><strong>Initialization:</strong></p><p>Call AT24CXX_Init() to initialize the I2C bus and EEPROM device.</p><p>Use AT24CXX_Check() to verify whether the device is functioning properly.</p><p><strong>Key Reading:</strong></p><p>When the system starts, it reads EEPROM addresses 0–5 in a loop and stores the data into the open_lock_key array.</p><p><strong>Key Modification:</strong></p><p>In the modification interface (interface_num = 2), after confirmation, the temporary key open_lock_key_temp is written to the corresponding EEPROM addresses and then re-read to synchronize with open_lock_key.</p><pre>// 初始化EEPROM并读取密钥<br>AT24CXX_Init();<br>while(AT24CXX_Check()){<br>    // EEPROM异常，LED闪烁提示<br>    LED_ON = !LED_ON;<br>    Delay1_ms(100);<br>}<br>for(i=0;i&lt;6;i++){<br>    open_lock_key[i] = AT24CXX_ReadOneByte(i); // 读取密钥<br>}<br>// 修改密钥并写入EEPROM<br>for(i=0;i&lt;6;i++){<br>    AT24CXX_WriteOneByte(i, open_lock_key_temp[i]); // 写入新密钥<br>}</pre><h3>Unlocking and Alarm Feedback</h3><p><strong>Unlock Logic:</strong></p><p>When key verification succeeds (or fingerprint/RFID recognition is successful), open_door_type is set to 1. The LED lights up, and the OLED displays the unlock success icon (BMP4). After 2 seconds, the system automatically locks again (LED turns off and the icon returns to default).</p><p><strong>Alarm Logic:</strong></p><p>When the key does not match or an operation error occurs, open_door_alert is set to 1. The buzzer emits an alarm sound (time2_Pwm_Alert), and the OLED error icon (BMP2) flashes four times before returning to the default state.</p><pre>// 开锁反馈<br>if(open_door_type){<br>    LED_ON;<br>    OLED_DrawBMP(12,5,28,7,BMP4); // 显示开锁成功图标<br>    Delay1_ms(2000);<br>    LED_OFF;<br>    OLED_DrawBMP(12,5,28,7,BMP3); // 恢复默认图标<br>    open_door_type = 0;<br>}<br>// 错误报警反馈<br>if(open_door_alert){<br>    for(i=0;i&lt;4;i++){<br>        OLED_DrawBMP(12,5,28,7,BMP2); // 显示错误图标<br>        time2_Pwm_Alert(150,1000); // 蜂鸣器报警<br>        OLED_DrawBMP(12,5,28,7,BMP3); // 恢复默认图标<br>        rt_thread_mdelay(100);<br>    }<br>    open_door_alert = 0;<br>}</pre><h3>OLED Interface Display</h3><p>The OLED screen is used to display the system status in real time, including the following:</p><p><strong>Interface indicator:</strong></p><p>Displays the current interface (default interface / modification interface), refreshed via interface_Oled_Flushed().</p><p><strong>Password input length:</strong></p><p>Indicates the number of entered password digits using the BMP2 bitmap.<strong>Status icons:</strong></p><p>Default state (BMP3), error state (BMP2), and unlock success state (BMP4).<strong>Key value display:</strong></p><p>Shows the numeric value of the currently pressed button in real time.</p><pre>// 刷新界面标识<br>voidinterface_Oled_Flushed(){<br>    OLED_DrawBMP(72,5,86,7,BMP6);<br>    OLED_ShowNum(72,5,interface_num,1,16); // 显示当前界面编号<br>}<br>// 显示按键值<br>OLED_ShowNum(100,5,key_vel,a,16);</pre><h3>5. Multi-Mode Unlocking Extension</h3><p>The system reserves expansion interfaces for fingerprint recognition (FPM383C) and RFID card recognition (RC522). The core implementation approach is as follows:</p><p><strong>Fingerprint recognition:</strong></p><p>Continuously scans fingerprints via fpm383c_Scan(). Once recognition succeeds and a match result is returned, open_door_type is set directly to trigger unlocking.</p><p><strong>RFID recognition:</strong></p><p>Reads the RFID card ID through RC522_Scan(), compares it with the pre-stored valid ID, and triggers unlocking if matched.</p><p>At present, module initialization and scanning function calls have been completed in the code. Only the storage and comparison logic for valid fingerprint/RFID data needs to be expanded to fully enable multi-mode unlocking.</p><p>A small 3D-printed casing was also made to dress it up.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/520/1*P8abZuBltChW7wYRL-lkVQ.png" /></figure><h3>6. Project Optimization and Improvement Directions</h3><p><strong>Sensor stability:</strong></p><p>The RC522 RFID module may experience read failures in strong interference environments. Adding data validation and multiple scanning mechanisms can improve stability.<strong>Password security:</strong></p><p>Currently, the key is stored in plaintext in the EEPROM. An AES encryption algorithm can be added to encrypt the key before storage to enhance security.<strong>Feature expansion:</strong></p><p>Add remote unlocking (via a SIM900A GSM module), unlock log storage, and low-power mode functionality.<strong>User interaction:</strong></p><p>Optimize the OLED interface by adding hidden password input (e.g., displaying asterisks) and Chinese prompts to improve user experience.<strong>Exception handling:</strong></p><p>Add dedicated feedback mechanisms for fingerprint recognition failures and RFID reading failures to distinguish different error types.</p><h3>7. Project Source Code</h3><p>Baidu Netdisk address: Shared file — frdm-mcxa156.zip</p><p>Link: <a href="https://pan.baidu.com/s/1SDYqULii2I0b2lkJM9ecrg?pwd=8888">https://pan.baidu.com/s/1SDYqULii2I0b2lkJM9ecrg?pwd=8888</a></p><p>Extraction code: 8888Code repository: <a href="https://gitee.com/yang-xianyi/exclusive">https://gitee.com/yang-xianyi/exclusive</a></p><p>Developers are welcome to provide valuable feedback and optimization suggestions to jointly improve the system.</p><h3>Contributor List of FRDM-MCX A346 Development Practice Guide</h3><p>The RT-Thread community, together with NXP Semiconductors, jointly launched the FRDM-MCXA346 development board evaluation activity. The <em>FRDM-MCX A346 Development Practice Guide</em> provides detailed listings of each content section and its contributors. Sincere thanks to all contributors for their support and contributions!</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*lbxqOQILRcEZHskxE3Ojmw.png" /></figure><h3>Introduction to the FRDM-MCXA346 Development Board</h3><p>The FRDM-MCXA346 is a compact and scalable development board that enables rapid prototyping based on the FRDM-MCXA346 microcontroller unit (MCU).</p><p>It provides industry-standard interfaces for easy access to the MCU’s I/O, and is equipped with an integrated open-standard serial interface, external flash memory, and an onboard MCU-Link debugger.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*kw9yHSkkTLhL9R2u_FeeWw.png" /></figure><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=9bfab8836212" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Design and Implementation of a USB HID Gamepad Based on RT-Thread and MCXA156 | Tech Collection]]></title>
            <link>https://rt-thread.medium.com/design-and-implementation-of-a-usb-hid-gamepad-based-on-rt-thread-and-mcxa156-tech-collection-7a156500a038?source=rss-6ea18de1fff4------2</link>
            <guid isPermaLink="false">https://medium.com/p/7a156500a038</guid>
            <dc:creator><![CDATA[RT-Thread IoT OS]]></dc:creator>
            <pubDate>Fri, 06 Feb 2026 09:23:55 GMT</pubDate>
            <atom:updated>2026-02-06T09:23:55.036Z</atom:updated>
            <content:encoded><![CDATA[<h3>1 Project Overview</h3><h3>1.1 Implemented Functions</h3><p>This project is based on the NXP FRDM-MCXA156 development board and implements a standard USB HID gamepad device. The main functions include:</p><p>● <strong>16 digital buttons</strong>: Implemented using a 4×4 matrix keypad, consisting of 14 buttons plus 2 joystick buttons</p><p>● <strong>Dual joystick input</strong>: Left and right analog joysticks, each providing X/Y axis data</p><p>● <strong>USB HID protocol</strong>: Standard HID Gamepad device, plug-and-play without driver installation</p><p>● <strong>Real-time response</strong>: 10 ms scanning interval with low-latency input</p><h3>1.2 Technical Features</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*xP7Sv4tboklGm8xPVm31qg.png" /></figure><h3>2 RT-Thread Usage Overview</h3><h3>2.1 Kernel Configuration</h3><pre>#define RT_THREAD_PRIORITY_MAX  32      // 32 priority levels<br>#define RT_TICK_PER_SECOND      1000    // 1 ms system tick<br>#define RT_USING_TIMER_SOFT             // Software timer<br>#define RT_USING_SEMAPHORE              // Semaphore<br>#define RT_USING_MUTEX                  // Mutex<br>#define RT_USING_MAILBOX                // Mailbox</pre><h3>2.2 Used Components</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*0h_VE363rFCAw-tN5_PCag.png" /></figure><h3>2.3 Thread Design</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*nIceitIeZI5iITqIaGwCnA.png" /></figure><h3>2.4 Automatic Initialization</h3><p>The project uses the RT-Thread automatic initialization mechanism:</p><pre>INIT_BOARD_EXPORT(rt_hw_adc_init);      // ADC driver initialization<br>INIT_DEVICE_EXPORT(key_init);           // Matrix keypad initialization<br>INIT_DEVICE_EXPORT(joystick_init);      // Joystick initialization<br>INIT_COMPONENT_EXPORT(cherryusb_init);  // USB initialization<br>INIT_APP_EXPORT(gamepad_app_start);     // Application startup</pre><h3>3 Hardware Architecture</h3><h3>3.1 System Block Diagram</h3><pre>┌─────────────────────────────────────────────────────────────┐<br>│                      FRDM-MCXA156                           │<br>│  ┌─────────────┐  ┌─────────────┐  ┌─────────────────────┐ │<br>│  │  4x4 Matrix │  │ Dual Joystick│  │     USB Device      │ │<br>│  │   Keypad    │  │  (with BTN)  │  │    (Full Speed)     │ │<br>│  └──────┬──────┘  └──────┬──────┘  └──────────┬──────────┘ │<br>│         │                │                     │            │<br>│    GPIO P2/P3       ADC0 CH0/1/8/13           USB0         │<br>│         │                │                     │            │<br>│  ┌──────┴────────────────┴─────────────────────┴──────────┐│<br>│  │                    MCXA156 MCU                          ││<br>│  │              (Cortex-M33 @ 96MHz)                       ││<br>│  └─────────────────────────────────────────────────────────┘│<br>└─────────────────────────────────────────────────────────────┘</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*PQmtGnINWgQ9a6lcu5EiBw.png" /></figure><h3>3.2 Pin Assignment</h3><h4>3.2.1 Matrix Keypad (4×4)</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*KpE_k-Bb5LDBk6rUK_Mq3A.png" /></figure><h4>3.2.2 Joystick ADC</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/948/1*MSpC3vB8JQbnawiou5AfCg.png" /></figure><h4>3.2.3 Joystick Buttons</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ioQfcGs4iPfa4Jcdlledcg.png" /></figure><h3>4 Software Architecture Description</h3><h3>4.1 Software Architecture</h3><pre>┌─────────────────────────────────────────────────────────────┐<br>│                  Application Layer                          │<br>│  ┌─────────────────────────────────────────────────────────┐│<br>│  │                   gamepad_app.c                         ││<br>│  │   (Integrates input devices and maps to USB HID reports) ││<br>│  └─────────────────────────────────────────────────────────┘│<br>├─────────────────────────────────────────────────────────────┤<br>│                  Function Layer                             │<br>│  ┌───────────────┐  ┌───────────────┐  ┌─────────────────┐ │<br>│  │  key_app.c    │  │ joystick_app.c│  │   usb_app.c     │ │<br>│  │ (Keypad)      │  │ (Dual Joystick)│ │  (USB HID)      │ │<br>│  └───────────────┘  └───────────────┘  └─────────────────┘ │<br>├─────────────────────────────────────────────────────────────┤<br>│                  Driver Layer                               │<br>│  ┌───────────────┐  ┌───────────────┐  ┌─────────────────┐ │<br>│  │   drv_pin.c   │  │   drv_adc.c   │  │   CherryUSB     │ │<br>│  │   (GPIO)      │  │   (ADC)       │  │   (USB Stack)   │ │<br>│  └───────────────┘  └───────────────┘  └─────────────────┘ │<br>├─────────────────────────────────────────────────────────────┤<br>│                  RT-Thread Kernel                           │<br>│     (Thread scheduling, IPC, device framework, auto init)   │<br>├─────────────────────────────────────────────────────────────┤<br>│                  Hardware Abstraction Layer                 │<br>│                NXP MCX SDK / CMSIS                           │<br>└─────────────────────────────────────────────────────────────┘</pre><h3>4.2 Data Flow</h3><pre>Matrix Keypad ──► key_read() ───────────────────────────────┐<br>                                                            │<br>Left Joystick ADC ──► joystick_left_read() ─► apply_deadzone() ─┤<br>                                                            ├──► gamepad_thread<br>Right Joystick ADC ─► joystick_right_read() ─► apply_deadzone() ─┤     │<br>                                                            │     ▼<br>Joystick Buttons ──► rt_pin_read() ─────────────────────────┘  scale_axis()<br>                                                                   │<br>                                                                   ▼<br>                                                           USB HID Report<br>                                                                   │<br>                                                                   ▼<br>                                                     hid_gamepad_send_report()<br>                                                                   │<br>                                                                   ▼<br>                                                               USB Host (PC)</pre><p>This strictly follows the <strong>Perception → Cognition → Control</strong> system design pattern.</p><h3>5 Software Module Description</h3><h3>5.1 key_app Module (Matrix Keypad)</h3><p>Files: applications/key_app.c, applications/key_app.h</p><p>Function: 4×4 matrix keypad scanning</p><p>Core function:</p><pre>rt_uint8_t key_read(void);  // Returns 0–15 for key index, 0xFF if no key is pressed</pre><p>Scanning principle:</p><p>● Drive one column low at a time</p><p>● Read all row pin states</p><p>● A detected low level indicates the key at that intersection is pressed</p><h3>5.2 joystick_app Module (Joystick)</h3><p>Files: applications/joystick_app.c, applications/joystick_app.h</p><p>Function: Dual joystick ADC reading and button detection</p><p>Data structure:</p><pre>typedef struct {<br>    int16_t x;      // X axis: -32768 ~ 32767<br>    int16_t y;      // Y axis: -32768 ~ 32767<br>    bool btn;       // Button: true = pressed<br>} joystick_data_t;</pre><p>Core functions:</p><pre>rt_err_t joystick_left_read(joystick_data_t *data);<br>rt_err_t joystick_right_read(joystick_data_t *data);</pre><h3>5.3 usb_app Module (USB HID)</h3><p>Files: applications/usb_app.c, applications/usb_app.h</p><p>Function: USB HID gamepad device implementation</p><p>HID report structure (9 bytes):</p><pre>typedef struct __attribute__((packed)) {<br>    uint16_t buttons;      // 16 buttons<br>    int8_t left_x;         // Left joystick X (-127 ~ 127)<br>    int8_t left_y;         // Left joystick Y<br>    int8_t right_x;        // Right joystick X<br>    int8_t right_y;        // Right joystick Y<br>    uint8_t left_trigger;  // Left trigger (0–255)<br>    uint8_t right_trigger; // Right trigger (0–255)<br>    uint8_t hat;           // D-pad (0–8)<br>} usb_gamepad_report_t;</pre><p>USB descriptor configuration:</p><p>● VID: 0x045E (Microsoft)</p><p>● PID: 0x02FF (Generic Gamepad)</p><p>● Endpoint: 0x81 (IN), interrupt transfer</p><p>● Polling interval: 1 ms</p><h3>5.4 gamepad_app Module (Application Layer)</h3><p>Files: applications/gamepad_app.c, applications/gamepad_app.h</p><p>Function: Integrates all input devices and maps them to USB HID reports</p><p>Core features:</p><p>● Dead zone processing: Eliminates joystick center jitter</p><p>● Change detection: Reports are sent only when state changes</p><p>● Retry mechanism: Reports are cached and resent when USB is busy</p><p>● Button mapping</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/902/1*PORVD0SErXSk3aP6RsC7fQ.png" /></figure><h3>5.5 drv_adc Module (ADC Driver)</h3><p>File: Libraries/drivers/drv_adc.c</p><p>Function: LPADC driver supporting multi-channel ADC reading</p><p>Key modifications:</p><p>● Fixed multi-channel initialization overwrite issue</p><p>● Added timeout protection to prevent system deadlock</p><p>● Optimized command slot allocation (4 channels use 4 independent command slots)</p><h3>6 Demonstration Results</h3><h3>6.1 Startup Log</h3><pre>KEY OK<br>joystick: init OK<br>[USB] Initializing HID Gamepad...<br>[USB] HID Gamepad initialized successfully<br>[USB] VID:0x045E PID:0x02FF<br>[GAMEPAD] Started (interval: 10ms)<br>System Start<br>[GAMEPAD] Thread started<br>[USB] Device Configured - Gamepad Ready!</pre><h3>6.2 Windows Testing</h3><p>1. After connecting the device, it appears as <strong>“USB Gamepad HID”</strong> in Device Manager</p><p>2. Use joy.cpl (Game Controllers) to test all buttons and joysticks</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/300/1*FW5srg68DmGtTZ_UVvW2SA.jpeg" /></figure><p>3. Use the online platform <a href="https://gamepad-tester.com/">https://gamepad-tester.com/</a> to test all buttons and joysticks</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/400/1*6oZ3RiafkPBPKV_4fNvb5w.jpeg" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/400/1*oZRbhnUa6j8cPSkIE03EnA.jpeg" /></figure><h3>6.3 Function Demonstration</h3><p>● All 16 buttons respond correctly</p><p>● Left and right joystick X/Y axes function correctly</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/400/1*800vlwQvffkNLunv8iPp9A.jpeg" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/400/1*7lfpgfZFct4Q5ddAgQFUMQ.jpeg" /></figure><p>● Joystick buttons function correctly</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/300/1*IqtlHzHJQsSgce7IaxbDig.jpeg" /></figure><p>● Low-latency response</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/300/1*IWcXxqlSlRIKSbuQPWn_YA.jpeg" /></figure><h3>7 Code Repository</h3><p>Git repository:</p><p><a href="https://github.com/Rolmoland/Project_GamepadMi">https://github.com/Rolmoland/Project_GamepadMi</a></p><p>Main files:</p><pre>applications/<br>├── main.c              # Entry point<br>├── gamepad_app.c/h     # Gamepad application layer<br>├── key_app.c/h         # Matrix keypad module<br>├── joystick_app.c/h    # Joystick module<br>└── usb_app.c/h         # USB HID module<br> <br>board/<br>├── MCUX_Config/board/pin_mux.c  # Pin configuration<br>└── ports/cherryusb/             # CherryUSB adaptation<br> <br>Libraries/drivers/<br>└── drv_adc.c           # ADC driver (modified)</pre><h3>8 Summary</h3><p>This project successfully implements a USB HID gamepad based on RT-Thread, with the following characteristics:</p><p>● <strong>Modular design</strong>: Clear separation of hardware, function, and application layers for easy maintenance</p><p>● <strong>Good real-time performance</strong>: Based on the RT-Thread real-time kernel with a 10 ms scan cycle</p><p>● <strong>Strong compatibility</strong>: Standard HID protocol, driver-free on Windows, Linux, and macOS</p><p>● <strong>Extensible</strong>: Easy to add features such as vibration feedback and LED indicators</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=7a156500a038" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[RT-Thread Vector Package: A Dynamic Array Container for Embedded Development | Tech Collection]]></title>
            <link>https://rt-thread.medium.com/rt-thread-vector-package-a-dynamic-array-container-for-embedded-development-tech-collection-efedd9de07ed?source=rss-6ea18de1fff4------2</link>
            <guid isPermaLink="false">https://medium.com/p/efedd9de07ed</guid>
            <dc:creator><![CDATA[RT-Thread IoT OS]]></dc:creator>
            <pubDate>Tue, 27 Jan 2026 08:32:45 GMT</pubDate>
            <atom:updated>2026-01-27T08:32:45.537Z</atom:updated>
            <content:encoded><![CDATA[<p><strong>RT-Thread Vector Package: A Dynamic Array Container for Embedded Development</strong></p><p>Package URL:</p><p><a href="https://packages.rt-thread.org/detail.html?package=vector">https://packages.rt-thread.org/detail.html?package=vector</a></p><p>Original Article:</p><p><a href="https://club.rt-thread.org/ask/article/165b038347c75637.html">https://club.rt-thread.org/ask/article/165b038347c75637.html</a></p><h3>1. A New Tool for Embedded Development: RT-Thread Vector Package</h3><p>In embedded system development, the choice of data structures directly affects application performance, memory utilization, and code maintainability.</p><p>Traditional static arrays are simple and intuitive, but they reveal many limitations when dealing with dynamically changing data sizes:Fixed-size limitation</p><p>Static arrays require their size to be defined at compile time, making them inflexible when data volume changes.</p><h3>If the data exceeds expectations, buffer overflow may occur; if the actual data is far less than the allocated size, precious memory is wasted.Inefficient resizing</h3><p>If developers implement dynamic arrays manually, they must handle memory allocation, data copying, and deallocation themselves, which increases code complexity and introduces risks such as memory leaks.</p><h3>Poor reusability</h3><p>Implementing separate dynamic arrays for different data types leads to code duplication and reduced maintainability.</p><p>To solve these problems, we designed the <strong>Vector package for RT-Thread</strong> — a general-purpose dynamic array container tailored for embedded systems.</p><p>It combines the fast access of static arrays with the flexibility of dynamic arrays, providing a complete API for storing and managing any data type.As a third-party module designed for RT-Thread, Vector features efficient memory management (automatic expansion and shrinkage), rich operations (insert, delete, update, search, sort, iterate), and a lightweight design suitable for resource-constrained embedded environments.</p><h3>2. What Is the Vector Package?</h3><h3>2.1 Definition</h3><p>The RT-Thread Vector package is a general-purpose dynamic array container designed specifically for embedded systems.</p><p>It provides a flexible and efficient way to store and manage different types of data elements.By using a <strong>void*</strong> pointer combined with an element-size parameter, Vector achieves <strong>type-independent container functionality</strong>, allowing a single container to store integers, floats, structures, or custom data types seamlessly.</p><p>Essentially, Vector is a <strong>contiguous memory block that automatically resizes</strong>, combining:</p><p>● O(1) random access of arrays</p><p>● Dynamic sizing of linked lists</p><p>When the number of elements approaches the capacity limit, the container automatically expands.</p><p>When elements are removed significantly, it shrinks to free unused memory — avoiding both waste and overflow risks.2.2 Design Goals</p><p>The Vector package follows four core design principles:</p><h4>2.2.1 Generality</h4><p>● Type-agnostic design using void* and item size</p><p>● Unified API</p><p>● Customizable initial capacity</p><h4>2.2.2 Efficiency</h4><p>● O(1) random access</p><p>● Smart memory resizing (double/half)</p><p>● O(n log n) merge sort implementation</p><p>● Batch operations for reduced overhead</p><h4>2.2.3 Lightweight</h4><p>● Minimal code size and runtime footprint</p><p>● Zero external dependencies</p><p>● Easy portability to other embedded systems</p><h4>2.2.4 Ease of Use</h4><p>● Intuitive API naming</p><p>● Clear return values for error handling</p><p>● Complete documentation and examples</p><h3>2.3 Comparison with Traditional Arrays</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ddMXCnNVDkQ3x4y0MDmzjA.png" /></figure><p>Compared to static arrays, Vector offers significant advantages in flexibility, memory efficiency, and maintainability (omitted table in original text).</p><h3>2.4 Position in the RT-Thread Ecosystem</h3><p>As a third-party module for RT-Thread, Vector plays an important role:</p><p>● <strong>Memory integration</strong>: Built on rt_malloc/rt_free for full kernel compatibility</p><p>● <strong>Design philosophy alignment</strong>: Lightweight, efficient, embedded-friendly</p><p>● <strong>Seamless integration</strong>: No kernel modification required</p><p>● <strong>Ecosystem enhancement</strong>: Fills the gap of general-purpose dynamic containers</p><p>● <strong>Extensible architecture</strong>: Handle-based design hides implementation details</p><h3>2.5 API Design and Naming Convention</h3><p>● All APIs use the vector_ prefix</p><p>● Handle-based design: vector_handle_t (void*)</p><p>● Consistent parameter ordering</p><p>● Clear return values</p><p>Example:</p><pre>vector_handle_t vector_create(const vector_config_t *config);<br>int vector_push_back(vector_handle_t handle, const void *data);<br>void *vector_get(vector_handle_t handle, size_t index);<br>int vector_destroy(vector_handle_t handle);</pre><p>This design makes Vector easy to use even for beginners.</p><h3>2.6 Typical Use Cases</h3><h4>2.6.1 Dynamic Data Management</h4><p>Sensor data, packet processing, task queues, etc.</p><p>Nested Vectors can be used to build dynamic 2D data structures without wasting memory.</p><h4>2.6.2 Generic Data Storage</h4><p>Configuration systems, device management, logging systems.</p><h4>2.6.3 High-performance Access</h4><p>Real-time monitoring, caches, indexes.</p><h4>2.6.4 Resource-constrained Systems</h4><p>Cortex-M and low-power MCU applications.</p><h4>2.6.5 Rapid Development</h4><p>Reduce manual memory management and data movement code.</p><h3>3. Core Features</h3><h3>3.1 Smart Memory Management</h3><p>● Automatic expansion (double capacity)</p><p>● Automatic shrink (half capacity, min = 4)</p><p>● Manual shrink function</p><h3>3.2 Flexible Element Operations</h3><p>● Insert: push_back, push_front, insert</p><p>● Remove: pop_back, pop_front, remove</p><p>● Access: get, front, back, modify</p><p>● Management: clear, destroy, size, capacity</p><h3>3.3 Batch Operations</h3><p>Efficient bulk insert/remove using memcpy to reduce overhead.</p><h3>3.4 Stable Sorting</h3><p>O(n log n) merge sort with user-defined comparator.</p><h3>3.5 Easy Iteration</h3><p>Callback-based iteration with context support.</p><h3>3.6 Thread Safety</h3><p>● Safe in single-threaded environments</p><p>● Multi-threaded use requires mutex protection</p><h3>3.7 Lightweight Design</h3><p>● Small code size</p><p>● No external dependencies</p><p>● Ideal for embedded systems</p><h3>4. Implementation Details</h3><h3>4.1 Core Data Structure</h3><pre>typedef struct {<br>    size_t capacity;<br>    size_t size;<br>    size_t item_size;<br>    void *data;<br>} vector_ctrl_block_t;</pre><h3>4.2 Handle-based Design</h3><p>● Improves encapsulation</p><p>● Prevents direct manipulation</p><p>● Allows future extension</p><h3>4.3 Memory Management</h3><h4>Expansion</h4><p>● Double capacity</p><p>● Allocate new memory</p><p>● Copy old data</p><p>● Free old memory</p><h4>Shrinking</h4><p>● Halve capacity (min 4)</p><p>● Copy and free old buffer</p><h3>4.4 Algorithms</h3><p>● Merge sort (stable, O(n log n))</p><p>● O(1) random access</p><p>● Efficient memory movement</p><h3>4.5 Callback Mechanism</h3><p>vector_for_each supports context-aware iteration.</p><h3>5. Usage and Examples</h3><h3>5.1 Basic Workflow</h3><h4>5.1.1 Create and Initialize</h4><pre>vector_config_t config = {<br>    .item_size = sizeof(int),<br>    .capacity = 10<br>};<br>vector_handle_t v = vector_create(&amp;config);</pre><h4>5.1.2 Core Operations</h4><pre>vector_push_back(v, &amp;num);<br>vector_pop_back(v);<br>vector_sort(v, int_cmp);<br>vector_for_each(v, print_int, RT_NULL);</pre><h4>5.1.3 Batch Operations</h4><pre>vector_push_back_block(v, nums, count);<br>vector_remove_block(v, start, length);</pre><h4>5.1.4 Management</h4><pre>vector_shrink(v);<br>vector_clear(v);<br>vector_destroy(v);</pre><h3>5.2 Complete Example</h3><p>(Example code unchanged, omitted here for brevity — same as original)</p><h3>5.3 Common Issues</h3><h4>Memory allocation failure</h4><p>● Reduce initial capacity</p><p>● Check system memory</p><h4>Type casting errors</h4><p>Always cast returned pointers correctly.</p><h4>Index out of bounds</h4><p>Always check index before access.</p><h3>6. Performance and Advantages</h3><h3>6.1 Memory Efficiency</h3><p>● Automatic resizing reduces waste</p><p>● Amortized O(1) insert/delete</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*0moZsMBQwSCf9PMfLzuvgA.png" /></figure><h3>6.2 Execution Performance</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*rXbFYUj76H2D7_x7eYBj3g.png" /></figure><p>● O(1) access</p><p>● O(n log n) sort</p><p>● Optimized bulk operations</p><h3>6.3 Resource Usage</h3><p>● Control block: ~24 bytes (32-bit)</p><p>● Default capacity: 4</p><p>● No extra dependencies</p><h3>6.4 Thread Safety</h3><p>● Safe in single-thread</p><p>● Use mutex in multi-thread</p><h3>6.5 Best Practices</h3><p>● Estimate capacity in advance</p><p>● Use batch APIs for large data</p><p>● Avoid frequent front insert/remove</p><h3>7. Summary</h3><p>The <strong>RT-Thread Vector package</strong> is a general-purpose dynamic array container designed for embedded systems, featuring:</p><p>● Smart memory management</p><p>● Rich and efficient APIs</p><p>● High-performance algorithms</p><p>● Type-independent design</p><p>● Lightweight implementation</p><p>● Easy-to-use interface</p><p>It fills an important gap in the RT-Thread ecosystem, providing a reliable and efficient solution for sensor data processing, packet handling, task management, and more.</p><p>The Vector package has already been validated in <strong>industrial-grade, 24/7 long-running systems</strong>, proving its stability and reliability.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=efedd9de07ed" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[A Simple IoT Temperature-Controlled Chamber Based on RT-Thread | Tech Collection]]></title>
            <link>https://rt-thread.medium.com/a-simple-iot-temperature-controlled-chamber-based-on-rt-thread-tech-collection-85d1128e7990?source=rss-6ea18de1fff4------2</link>
            <guid isPermaLink="false">https://medium.com/p/85d1128e7990</guid>
            <dc:creator><![CDATA[RT-Thread IoT OS]]></dc:creator>
            <pubDate>Wed, 14 Jan 2026 09:05:00 GMT</pubDate>
            <atom:updated>2026-01-14T09:05:00.485Z</atom:updated>
            <content:encoded><![CDATA[<h3>1. Project Overview</h3><p>This project is a simple, high-precision, and easily extensible desktop-level temperature control system. It achieves accurate temperature control inside an enclosed chamber and connects to the network via Wi-Fi. A fully featured web-based visualization and parameter-tuning dashboard is provided, forming a complete IoT closed loop.</p><p>The entire project makes full use of RT-Thread’s multithreading capabilities, device driver framework, and networking components to deliver a complete hardware–software integrated solution.</p><p><strong>Hardware Platform:</strong> NXP FRDM-MCXA156</p><p><strong>RT-Thread Version:</strong> 5.2.1</p><p><strong>Core Features:</strong></p><p>● Maximum system power consumption: 24 W</p><p>● Temperature control range: ambient to 70 °C (the range can be extended by adding a thermoelectric cooler or higher-temperature PTC heaters)</p><p>● High-precision temperature regulation</p><p>○ Maximum fluctuation: 3 °C</p><p>○ Steady-state fluctuation: 1 °C</p><p>● Multi-sensor data fusion</p><p>● Local OLED display</p><p>● Web-based remote monitoring and online parameter tuning</p><p><strong>Project Highlights:</strong></p><p>Cascade PID with feedforward composite control algorithm, a three-state control state machine, and a TCP–WebSocket–bridged web visualization solution.</p><h3>2. RT-Thread Usage Overview</h3><p>RT-Thread serves as the core operating system of the project and provides a solid foundation for all functionalities. Its stable and reliable kernel, rich component ecosystem, and concise APIs significantly improve development efficiency.</p><p><strong>Kernel and Scheduler:</strong></p><p>Multiple threads are created to handle different tasks, including the main control thread, PID control thread, OLED refresh thread, network service thread, and LED indicator thread. RT-Thread’s preemptive scheduler ensures real-time performance for high-priority tasks such as temperature control.<strong>Device Driver Framework:</strong></p><p>● Using RT-Thread’s unified device model, multiple hardware peripherals are easily managed:<strong>Pin device:</strong> Controls LED indicators and relays for heating/cooling mode switching</p><p>● <strong>ADC device:</strong> Reads voltage values from the NTC thermistor to calculate the real-time temperature of the PTC heater</p><p>● <strong>PWM device:</strong> Precisely controls the power output of the PTC heater and cooling fan</p><p>● <strong>I2C device:</strong> Drives the OLED display (based on the u8g2 package) and reads data from the onboard P3T1755 ambient temperature sensor</p><p>● <strong>Sensor framework:</strong> Reads data from the DHT11 and P3T1755 sensors</p><p><strong>Network Stack:</strong></p><p>The built-in lwIP protocol stack and SAL socket abstraction layer are used to quickly implement a stable TCP server for remote monitoring.<strong>WLAN Framework:</strong></p><p>Wi-Fi connectivity is implemented conveniently via the rt_wlan_connect interface.</p><p><strong>FinSH/MSH Command Line:</strong></p><p>Custom get_status and tune commands allow all key parameters to be adjusted dynamically at runtime through the serial console.</p><p><strong>Software Packages Used:</strong></p><p>● <strong>u8g2:</strong> Local UI graphics library</p><p>● <strong>dhtxx:</strong> DHT11 temperature and humidity sensor package</p><p>● <strong>p3t1755:</strong> Onboard I2C temperature sensor package</p><h3>3. Hardware Architecture</h3><p>The system hardware consists of four main parts: core control, sensors, actuators, and human–machine interface.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/898/1*0jkR2lwn7o9GFazVpoqx7Q.png" /></figure><p><strong>Core Controller:</strong></p><p>● NXP FRDM-MCXA156 development board</p><p><strong>Sensor Modules:</strong></p><p>● <strong>Internal temperature and humidity:</strong> DHT11 sensor, read via the RT-Thread Sensor framework</p><p>● <strong>PTC surface temperature:</strong> NTC thermistor sampled via ADC and calculated using the Steinhart–Hart model, used for inner-loop control and over-temperature protection</p><p>● <strong>Ambient temperature:</strong> Onboard P3T1755 I2C temperature sensor on the development board</p><p><strong>Actuator Modules:</strong></p><p>● <strong>Heating:</strong> PTC ceramic heater driven by an LR7843 MOSFET, with power regulated via PWM</p><p>● <strong>Cooling:</strong> 12 V DC fan, also driven by PWM</p><p>● <strong>Mode switching:</strong> A relay switches the PWM output between the MOSFET and the fan, enabling automatic heating/cooling mode selection</p><p><strong>Human–Machine Interface:</strong></p><p>● <strong>Local:</strong> SSD1306 OLED display showing system status, current temperature, target temperature, and other key information in real time</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/910/1*ahc2L9Iq0vqYE0GdC94Tyg.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/908/1*ex6En4l1OCqX-vANfS0wxQ.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/904/1*zbqbwoXEaVy5pOUypAwwmw.png" /></figure><p>● <strong>Remote:</strong> A visual dashboard accessed via a web browser on a PC or mobile device through Wi-Fi</p><p><strong>Hardware Wiring Diagram</strong></p><h3>4. Software Architecture Description</h3><p>The core software is built around a three-state state machine in main.c and a cascade PID control algorithm implemented in the pid_entry thread.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/926/1*MesoQsF73Wf20zt2tLnWBg.png" /></figure><h4>Software Module Description</h4><p><strong>Main Control and State Machine (main.c)</strong></p><p>The main function initializes all devices (sensors, PWM, ADC, Wi-Fi) and creates the application threads.</p><p>The while (1) loop in main acts as the system’s primary state machine. It periodically reads the internal temperature and compares it with the target temperature and hysteresis band, automatically switching among three states: <strong>HEATING</strong>, <strong>WARMING</strong>, and <strong>COOLING</strong>.</p><p>During state transitions, the relay is controlled via STATE_PIN to route the PWM signal to the appropriate actuator (PTC heater or fan), and the PID integral term is reset to prevent abrupt changes.</p><p><strong>Core Control Algorithm (pid_entry thread)</strong></p><p>This independent thread runs at a higher frequency (CONTROL_PERIOD_MS) and is responsible for the core temperature control algorithm.</p><p><strong>Cascade PID + Feedforward Control (Heating/Warming Modes):</strong></p><p>● <strong>Outer-loop PID (pid_box):</strong></p><p>Calculates the desired PTC target temperature (ptc_target_temp) based on the difference between the internal temperature and the target temperature. This allows the heating rate to adapt dynamically according to how far the system is from the target.</p><p>● <strong>Inner-loop PID (pid_ptc):</strong></p><p>Computes the PWM adjustment based on the difference between the actual PTC temperature and the ptc_target_temp from the outer loop, enabling fast response to PTC temperature fluctuations and more stable heat output.</p><p>● <strong>Feedforward Control:</strong></p><p>A mapping table (ff_table) is established between ptc_target_temp and a base PWM value. The PID output is applied as a fine adjustment on top of this base value, significantly accelerating convergence and reducing the risk of PID integral windup.</p><p><strong>PI Control (Cooling Mode):</strong></p><p>When switched to cooling mode, the algorithm uses a simple PI controller (pid_cool) to directly control the fan speed based on the difference between the internal temperature and the target temperature.</p><p><strong>Over-Temperature Protection:</strong></p><p>The algorithm continuously monitors the PTC temperature. Once it exceeds the safety threshold (PTC_MAX_SAFE_TEMP), the PWM output is immediately set to zero to ensure system safety.</p><p><strong>Remote Control Service (remote.c)</strong></p><p>The remote_server_thread_entry thread creates a TCP server listening on port 5000.</p><p>The server supports two types of text commands:</p><p>● <strong>get_status:</strong></p><p>● Packages all key real-time system variables (temperatures, humidity, PID parameters, control state, PWM duty cycle, etc.) into a JSON string and returns it.<strong>tune …:</strong></p><p>Passes the received parameters directly to the tune() function in main.c, enabling runtime modification of all key parameters, including target temperature, PID gains, and feedforward tables.</p><p><strong>OLED Display (screen.c)</strong></p><p>The screen_on thread drives the OLED display.</p><p>The UI clearly shows the current operating mode (HEATING / COOLING / WARMING), four temperature values (current, target, ambient, and PTC temperature), and an intuitive temperature difference indicator bar.</p><h3>5. Demonstration</h3><p><strong>Local OLED Display</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/906/1*XLk_TI7etx0OJxvQLSbIPQ.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ap82D2aZLWGv4MaFdQ7Xuw.gif" /></figure><p>The OLED displays key system data in real time.</p><p><strong>Remote Web Dashboard</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/904/1*7WYMN4z0FhBATEe1F3GZNQ.png" /></figure><p>A real-time monitoring dashboard accessed via a browser, including gauges, status indicators, and an online parameter tuning section.</p><p><strong>Temperature History Curve</strong></p><p>Historical temperature plots allow intuitive analysis of system response speed, overshoot, and steady-state error (candlestick charts can provide even more information and are visually interesting).</p><p><strong>MSH Command-Line Debugging</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/906/1*mlEDhqz80vzuLAxbr2kfww.png" /></figure><p>By connecting via the serial port, system status can be queried using get_status, and parameters can be modified using the tune command.</p><h3>6. Future Improvements</h3><p><strong>Hardware</strong></p><p>Replace the DHT11 with a better sensor (such as the DHT22). The DHT11 has limited accuracy and response speed. Due to the lack of alternative sensors on hand, it is used temporarily.</p><p><strong>Functionality</strong></p><p>Allow users to configure a time-based temperature profile via the web interface (e.g., maintain 60 °C for 30 minutes, then increase to 70 °C for 1 hour), enabling the temperature chamber to support more complex use cases.</p><p><strong>Parameter Optimization</strong></p><p>The current parameters still have significant room for improvement. Since temperature changes slowly, experimentally determining optimal parameters is time-consuming. Model-based simulation is currently being explored to find optimal parameters more efficiently.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/898/1*kP1SWxdbaNehm1B-dPvHgw.png" /></figure><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=85d1128e7990" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Humanoid Detection Mobile Tracking Pan-Tilt Camera | Tech Collection]]></title>
            <link>https://rt-thread.medium.com/humanoid-detection-mobile-tracking-pan-tilt-camera-tech-collection-8be7a5b96c09?source=rss-6ea18de1fff4------2</link>
            <guid isPermaLink="false">https://medium.com/p/8be7a5b96c09</guid>
            <dc:creator><![CDATA[RT-Thread IoT OS]]></dc:creator>
            <pubDate>Tue, 06 Jan 2026 09:38:58 GMT</pubDate>
            <atom:updated>2026-01-06T09:38:58.302Z</atom:updated>
            <content:encoded><![CDATA[<h3>1. Project Background and Features</h3><p>With the rapid development of high-performance embedded chips, artificial intelligence, and visual neural networks, intelligent detection technologies have been widely applied in fields such as smart security, intelligent healthcare, autonomous driving, and industrial inspection.</p><p>This project mainly relies on the <strong>FH8626V300L NNA module</strong>, using the humanoid detection model provided by the SDK to implement human detection. Combined with a <strong>2-axis pan-tilt gimbal</strong>, the system further realizes <strong>humanoid tracking</strong> functionality.</p><h3>2. Hardware Usage</h3><p>● Dual-camera <strong>CV2005</strong> used as binocular visual input</p><p>● <strong>PWM6</strong> and <strong>PWM7</strong> used to drive the pan-tilt servo motors</p><p>● Ethernet connection used for network access and <strong>RTSP video streaming</strong></p><h3>3. Hardware Design</h3><p>The <strong>FH8626V300L demo board</strong> exposes PWM interfaces, which are selected via jumper caps. The schematic is shown below.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*w9VPpXNGX5DXDpkZ2VHvYg.png" /></figure><p>In this design, the jumper caps are removed, and the servo PWM control pins are directly connected to <strong>pin 2 of JP18 and JP20</strong>, which are connected to the chip.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*61STK4M-8xAl1_QKoYKMLA.png" /></figure><p>The 2-axis pan-tilt gimbal used in this project adopts <strong>LD-1501MG PWM servos</strong>.</p><p>Since the servos require <strong>6–7.4V power supply</strong>, an additional independent power module is added to power the servos separately.</p><h3>4. Development Environment</h3><p>The <strong>FH8626V300 SDK</strong> must be developed under a Linux environment.</p><p>For convenience, a <strong>virtual machine</strong> is installed on Windows, combined with <strong>Samba</strong> and <strong>SSH</strong>, enabling development operations directly from Windows.</p><p>Installation of the cross-compilation toolchain, SDK compilation, and usage can be completed quickly by following the official <strong>Fullhan SDK documentation</strong>.</p><p>This project is developed based on the <strong>media_demo</strong> example provided in the SDK. Configuration follows the manual, with one difference: firmware is loaded via <strong>SD card</strong>. The commands are as follows:</p><pre>fatload mmc 0 10000000 media_demo.bin<br>go 10000000</pre><p>Apart from the loading method, all other steps are consistent with the official documentation.</p><h3>5. Software Design</h3><h3>1) PWM Multiplexing</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*lwRKkXSnwcu1dhwwQkKSWw.png" /></figure><p>Ensure that the kernel PWM device driver is enabled.</p><p>In the sdk/rt-thread directory, run make menuconfig and enable the corresponding PWM configuration, as shown below.</p><h3>2) IO Multiplexing Configuration</h3><p>Modify the following file:</p><pre>sdk/rt-thread/platform/fh8626v300/app_board/appboard_iopad.h</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*p-GTdBkHJ-2qrFx3cqaMGw.png" /></figure><p>When configuring pin multiplexing, ensure that <strong>there are no conflicts</strong>, otherwise the multiplexing configuration will not take effect.</p><p>Pin functions can be checked via the <strong>pin_mux table</strong>, or directly referenced from:</p><pre>fh8626v300_iopad.h</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*7MYAVAaXcUpRnl3qstgBjw.png" /></figure><h3>3) Device Verification</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*-Ek-17P1_sBiiaSw1SCD0A.png" /></figure><p>After the configuration takes effect, corresponding device files will appear under /dev on the board.</p><p>You can use the following command to view pin multiplexing information:</p><pre>pinctrl -l</pre><h3>4) CV2005 Dual-Camera Output</h3><p>The dual-camera output of CV2005 can be configured by following the <strong>CV2005 always-on mode test firmware documentation</strong> provided in the SDK.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*M2ARePYSzVZEyNohyTalyw.png" /></figure><p>The FH video stream channel data format is shown below.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*cFAmAvuj_PaOG4M8DfD_Ew.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Nt5E8tAwLOi8NG1fNHZLTg.png" /></figure><p>The <strong>NNA module requires RGB888 input format</strong>, so when enabling humanoid detection, <strong>Channel 2</strong> must be enabled.</p><p>In this design:</p><p>● <strong>Sensor 0</strong> is used for humanoid detection</p><p>● The resolution of <strong>Channel 2</strong> maintains the same aspect ratio as <strong>Channel 0</strong></p><p>● Channel 2 data is scaled from Channel 0</p><p>● Detection results can be directly mapped back to Channel 0 for <strong>OSD bounding box rendering</strong></p><p>The resolution configuration is shown below.</p><p>The mapping relationship between <strong>NNA detection results</strong> and <strong>Channel 0</strong> is illustrated below.</p><h3>6. Humanoid Tracking Logic</h3><p><strong>Objective:</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*MmZgglupiYrhdyC0SsODKQ.png" /></figure><p>Ensure that the detected humanoid target’s center point falls near the center of the frame (1920/2, 1080/2).</p><p>To prevent camera jitter, the center area is expanded into a <strong>tolerance zone</strong>.</p><p>As long as the target’s center remains within this zone, the gimbal will not rotate.The relationship between <strong>pixel displacement and rotation angle</strong> is illustrated below.</p><p>Using a simple mapping relationship, the angular difference corresponding to pixel offsets can be calculated.</p><p>The gimbal rotation angle is then derived from the pixel distance between the target center and the image center.</p><h3>7. Video Demonstration</h3><p>Humanoid detection bounding boxes can be viewed by pulling the <strong>RTSP stream using VLC</strong>.</p><p>Due to the lack of a proper mounting bracket and concerns about short circuits when mounting the gimbal directly onto the development board, the current demo only shows the <strong>directional response of the gimbal</strong> when a humanoid appears in different regions of the frame.</p><p>A full demo with the gimbal mounted on the board will be provided in future updates.</p><h3>8. Issues Encountered During Debugging</h3><h3>Yellowish Image Color</h3><p><strong>IR-CUT issue</strong>:</p><p>● Connect the camera IR-CUT interface to <strong>J20</strong></p><p>● Short <strong>JP27 pins 1 and 2</strong></p><p>● After multiplexing to <strong>GPIO4</strong>, power on the board to switch IR-CUT</p><p>● GPIO4 default level is <strong>high</strong></p><p>Hardware inspection revealed that <strong>R69</strong>, located between the IR-CUT chip and another control pin <strong>GPIO29</strong>, is not populated.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*kp6CAS-IL8RVN6X6xPHGrQ.png" /></figure><p>Therefore, the IR-CUT module can be removed directly, restoring normal image color.For indoor testing, the IR-CUT state must still be evaluated based on actual lighting conditions.</p><p>If IR-CUT needs to be enabled:</p><p>● Short <strong>R69</strong></p><p>● Pull <strong>GPIO29 high</strong></p><p>● Pull <strong>GPIO4 low</strong></p><h3>9. Future Outlook</h3><p>This project currently adopts a <strong>dual-camera solution</strong>:</p><p>● The <strong>primary camera</strong> performs tripwire detection</p><p>● The <strong>secondary camera</strong> performs humanoid tracking</p><p>This enables a linkage mechanism where:</p><p>● The primary camera monitors a fixed region</p><p>● When a person enters a predefined area, an alarm is triggered</p><p>● The secondary camera automatically tracks the target</p><p>This approach achieves functionality similar to <strong>gun-ball linkage systems</strong> used in modern surveillance cameras.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=8be7a5b96c09" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>