This is an automated email from the ASF dual-hosted git repository.

xiaoxiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git

commit bd6a46631771f8864d85aa0c9963661de270107c
Author: Felipe Moura <[email protected]>
AuthorDate: Wed Mar 25 08:19:45 2026 -0300

    ht32f491x3/esk32: add docs and flash helpers
    
    Document the HT32F491x3 ESK32 board, build steps,
    flashing flow, and validation commands. Add WSL and
    PowerShell flash backends plus a Python wrapper.
    
    Signed-off-by: Felipe Moura <[email protected]>
---
 .../boards/esk32/ht32f491x3-starter-kit.jpg        | Bin 0 -> 211344 bytes
 .../arm/ht32f491x3/boards/esk32/index.rst          | 177 +++++++++++++++
 Documentation/platforms/arm/ht32f491x3/index.rst   |  14 ++
 arch/arm/include/ht32f491x3/chip.h                 |   6 +-
 boards/arm/ht32f491x3/esk32/tools/flash.ps1        | 239 +++++++++++++++++++++
 boards/arm/ht32f491x3/esk32/tools/flash.py         |  91 ++++++++
 boards/arm/ht32f491x3/esk32/tools/flash.sh         |  32 ++-
 7 files changed, 554 insertions(+), 5 deletions(-)

diff --git 
a/Documentation/platforms/arm/ht32f491x3/boards/esk32/ht32f491x3-starter-kit.jpg
 
b/Documentation/platforms/arm/ht32f491x3/boards/esk32/ht32f491x3-starter-kit.jpg
new file mode 100644
index 00000000000..9422d707cc5
Binary files /dev/null and 
b/Documentation/platforms/arm/ht32f491x3/boards/esk32/ht32f491x3-starter-kit.jpg
 differ
diff --git a/Documentation/platforms/arm/ht32f491x3/boards/esk32/index.rst 
b/Documentation/platforms/arm/ht32f491x3/boards/esk32/index.rst
new file mode 100644
index 00000000000..fbf7f2fa1f6
--- /dev/null
+++ b/Documentation/platforms/arm/ht32f491x3/boards/esk32/index.rst
@@ -0,0 +1,177 @@
+==================
+ESK32 (HT32F49163)
+==================
+
+.. tags:: arch:arm, chip:ht32f491x3, chip:ht32f49163, vendor:holtek
+
+The ESK32 is a development board based on the Holtek HT32F49163 MCU.
+The current NuttX port targets the HT32F49163 device used on the
+HT32F49163 development kit and focuses on a working serial-console NSH
+configuration with basic board bring-up.
+
+For additional hardware details, refer to Holtek's
+`HT32F491x3 Starter Kit User Guide 
<https://www.holtek.com/webapi/106680/HT32F491x3_StarterKitUserManualv100.pdf>`_.
+
+.. figure:: ht32f491x3-starter-kit.jpg
+   :align: center
+   :alt: HT32F491x3 Starter Kit
+
+   HT32F491x3 Starter Kit board photo
+
+Features
+========
+
+The current port provides:
+
+* Holtek HT32F49163 MCU from the HT32F491x3 family
+* ARM Cortex-M4 core with FPU support
+* Boot and clock initialization for the ESK32 8 MHz external crystal
+* System clock configured to 150 MHz
+* USART1 serial console at 115200 8N1
+* ``/bin`` mounted through ``binfs``
+* ``/proc`` mounted through ``procfs``
+* User LED registration through ``/dev/userleds``
+* Basic internal GPIO helpers used by the console and LED support
+
+The default ``esk32:nsh`` configuration also enables these built-in
+applications:
+
+* ``hello``
+* ``ostest``
+* ``dumpstack``
+* ``leds``
+
+Buttons and LEDs
+================
+
+Board LEDs
+----------
+
+Three user LEDs from the development kit are currently mapped by the board
+port. They are active-low and are exposed through the standard NuttX
+``USERLED`` interface and the ``/dev/userleds`` device.
+
+===== =========== ==========
+LED   Port/Pin    Notes
+===== =========== ==========
+LED2  PD13        Active-low
+LED3  PD14        Active-low
+LED4  PD15        Active-low
+===== =========== ==========
+
+The generic ``leds`` example from ``nuttx-apps`` can be used to validate the
+LED interface.
+
+Board Buttons
+-------------
+
+No button is currently exposed by the board port.
+
+Pin Mapping
+===========
+
+The current port uses the following MCU pins:
+
+===== ========== ==========
+Pin   Signal     Notes
+===== ========== ==========
+PA9   USART1_TX  Default serial console TX
+PA10  USART1_RX  Default serial console RX
+PD13  LED2       User LED, active-low
+PD14  LED3       User LED, active-low
+PD15  LED4       User LED, active-low
+===== ========== ==========
+
+Flashing
+========
+
+The board directory includes a helper script for flashing through Holtek's
+Windows OpenOCD package from a WSL-based development environment:
+
+.. code-block:: console
+
+   $ ./boards/arm/ht32f491x3/esk32/tools/flash.sh
+
+The script expects:
+
+* ``nuttx.bin`` already generated in the ``nuttx`` directory
+* Holtek xPack OpenOCD installed under
+  ``C:\Program Files (x86)\Holtek HT32 
Series\HT32-IDE\xPack\xpack-openocd-0.11.0-4``
+* an HT32-Link compatible debug connection
+* Holtek xPack OpenOCD can be installed together with the HT32 IDE, available
+  from Holtek's website: `Holtek Downloads 
<https://www.holtek.com/page/index>`_
+
+Useful options:
+
+.. code-block:: console
+
+   $ ./boards/arm/ht32f491x3/esk32/tools/flash.sh --dry-run
+   $ ./boards/arm/ht32f491x3/esk32/tools/flash.sh --device HT32F49163_100LQFP
+   $ ./boards/arm/ht32f491x3/esk32/tools/flash.sh --openocd-root 
/mnt/c/path/to/openocd
+
+Testing Notes
+=============
+
+The following commands are useful for validating the current port:
+
+.. code-block:: console
+
+   nsh> hello
+   nsh> ostest
+   nsh> dumpstack
+   nsh> leds
+
+When ``leds`` is executed, the example opens ``/dev/userleds`` and cycles
+through the LED bitmasks supported by the board.
+
+Current Limitations
+===================
+
+The current port is still intentionally small. In particular:
+
+* only the ``nsh`` board configuration is maintained
+* only USART1 routing is described by the board port
+* LEDs are supported, but board buttons are not yet implemented
+* internal GPIO helpers exist, but there is not yet a board-level ``/dev/gpio``
+  test interface in this port
+
+Configurations
+==============
+
+nsh
+---
+
+This is the currently maintained configuration for the board. It provides a
+serial console with the NuttShell and mounts ``/bin`` and ``/proc`` during
+board bring-up.
+
+Configure and build it from the ``nuttx`` directory:
+
+.. code-block:: console
+
+   $ ./tools/configure.sh -l esk32:nsh
+   $ make -j
+
+After boot, a typical prompt looks like:
+
+.. code-block:: console
+
+   NuttShell (NSH) NuttX-12.x.x
+   nsh> ls /
+   /:
+    bin/
+    dev/
+    proc/
+
+And the built-in applications can be listed with:
+
+.. code-block:: console
+
+   nsh> ls /bin
+   dd
+   dumpstack
+   hello
+   leds
+   nsh
+   ostest
+   sh
diff --git a/Documentation/platforms/arm/ht32f491x3/index.rst 
b/Documentation/platforms/arm/ht32f491x3/index.rst
new file mode 100644
index 00000000000..c468b5d7e68
--- /dev/null
+++ b/Documentation/platforms/arm/ht32f491x3/index.rst
@@ -0,0 +1,14 @@
+===============
+Holtek HT32F491
+===============
+
+The HT32F491x3 family is based on the ARM Cortex-M4 core.
+
+Supported Boards
+================
+
+.. toctree::
+   :glob:
+   :maxdepth: 1
+
+   boards/*/*
diff --git a/arch/arm/include/ht32f491x3/chip.h 
b/arch/arm/include/ht32f491x3/chip.h
index bc843a01c33..8b3393a1cf7 100644
--- a/arch/arm/include/ht32f491x3/chip.h
+++ b/arch/arm/include/ht32f491x3/chip.h
@@ -56,10 +56,10 @@
 #define HT32_NGPIO               6
 
 #define HT32_HICK_FREQUENCY       8000000
-#define HT32_HICK48_FREQUENCY    48000000
+#define HT32_HICK48_FREQUENCY     48000000
 #define HT32_HEXT_MIN_FREQUENCY   4000000
-#define HT32_HEXT_MAX_FREQUENCY  25000000
-#define HT32_PLL_MAX_FREQUENCY  150000000
+#define HT32_HEXT_MAX_FREQUENCY   25000000
+#define HT32_PLL_MAX_FREQUENCY    150000000
 
 #define HT32_SYSCLK_FREQUENCY CONFIG_HT32F491X3_SYSCLK_FREQUENCY
 #define HT32_HCLK_FREQUENCY   HT32_SYSCLK_FREQUENCY
diff --git a/boards/arm/ht32f491x3/esk32/tools/flash.ps1 
b/boards/arm/ht32f491x3/esk32/tools/flash.ps1
new file mode 100644
index 00000000000..39f15246bfe
--- /dev/null
+++ b/boards/arm/ht32f491x3/esk32/tools/flash.ps1
@@ -0,0 +1,239 @@
+############################################################################
+# boards/arm/ht32f491x3/esk32/tools/flash.ps1
+#
+# SPDX-License-Identifier: Apache-2.0
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+#
+############################################################################
+
+param(
+  [Parameter(ValueFromRemainingArguments = $true)]
+  [string[]]$RemainingArgs
+)
+
+$ErrorActionPreference = "Stop"
+Set-StrictMode -Version 2
+
+$ScriptDir = $PSScriptRoot
+$TopDir = [System.IO.Path]::GetFullPath((Join-Path $ScriptDir 
"..\..\..\..\.."))
+
+$DefaultBin = Join-Path $TopDir "nuttx.bin"
+$WindowsSetup = "Windows 10 Pro"
+$PowerShellSetup = "Windows PowerShell 5.1 or newer"
+$HT32IDEVersion = "HT32-IDE 1.0.6 (Build Date: 2025/12/04)"
+$HT32IDERoot = "C:\Program Files (x86)\Holtek HT32 Series\HT32-IDE"
+$OpenOCDPackage = "xPack OpenOCD 0.11.0-4"
+$OpenOCDRoot = Join-Path $HT32IDERoot "xPack\xpack-openocd-0.11.0-4"
+$OpenOCDExe = Join-Path $OpenOCDRoot "bin\openocd.exe"
+$ScriptsDir = Join-Path $OpenOCDRoot "scripts"
+$FlashLoader = Join-Path $OpenOCDRoot "FlashLoader\HT32F491x3_256.HLM"
+$DeviceName = "HT32F49163_100LQFP"
+$FlashBase = "0x08000000"
+$FlashEnd = "0x0803FFFF"
+$SRAMBase = "0x20000000"
+$WorkAreaSize = "0xC000"
+$BinPath = $DefaultBin
+$DryRun = $false
+$ProgName = $MyInvocation.MyCommand.Name
+
+function Get-AbsolutePath {
+  param(
+    [string]$Path
+  )
+
+  if ([System.IO.Path]::IsPathRooted($Path)) {
+    return [System.IO.Path]::GetFullPath($Path)
+  }
+
+  return [System.IO.Path]::GetFullPath((Join-Path (Get-Location) $Path))
+}
+
+function Format-CommandArgument {
+  param(
+    [string]$Argument
+  )
+
+  if ($Argument -match '[\s"]') {
+    return '"' + ($Argument -replace '"', '\"') + '"'
+  }
+
+  return $Argument
+}
+
+function Show-Assumptions {
+  Write-Host 
"############################################################################"
+  Write-Host "# Assumptions:"
+  Write-Host "#"
+  Write-Host "#   - $WindowsSetup"
+  Write-Host "#   - $PowerShellSetup"
+  Write-Host "#   - This is the native Windows backend; use flash.py from the 
same"
+  Write-Host "#     directory for automatic backend selection, or run this 
script directly"
+  Write-Host "#   - $HT32IDEVersion installed at:"
+  Write-Host "#       $HT32IDERoot"
+  Write-Host "#   - $OpenOCDPackage available at:"
+  Write-Host "#       $OpenOCDRoot"
+  Write-Host "#   - Holtek HT-Link probe using interface/htlink.cfg"
+  Write-Host "#   - ESK32 board with $DeviceName and 
FlashLoader\HT32F491x3_256.HLM"
+  Write-Host "#"
+  Write-Host "# Update this script if any of the above are not true."
+  Write-Host "#"
+  Write-Host 
"############################################################################"
+  Write-Host ""
+}
+
+function Show-Usage {
+  Write-Host "Usage: $ProgName [options]"
+  Write-Host ""
+  Write-Host "Options:"
+  Write-Host "  --bin PATH         Binary to flash. Default: $DefaultBin"
+  Write-Host "  --device NAME      Holtek expected device name. Default: 
$DeviceName"
+  Write-Host "  --openocd-root DIR Holtek xPack OpenOCD root."
+  Write-Host "  --dry-run          Print the OpenOCD command without executing 
it."
+  Write-Host "  --help             Show this help."
+  Write-Host ""
+  Write-Host "Examples:"
+  Write-Host "  .\$ProgName"
+  Write-Host "  .\$ProgName --dry-run"
+  Write-Host "  .\$ProgName --device HT32F49163_100LQFP"
+}
+
+function Fail {
+  param(
+    [string]$Message,
+    [switch]$ShowUsage
+  )
+
+  [Console]::Error.WriteLine($Message)
+
+  if ($ShowUsage) {
+    Show-Usage
+  }
+
+  exit 1
+}
+
+Show-Assumptions
+
+for ($i = 0; $i -lt $RemainingArgs.Count; $i++) {
+  switch ($RemainingArgs[$i]) {
+    "--bin" {
+      if ($i + 1 -ge $RemainingArgs.Count) {
+        Fail "Missing value for --bin" -ShowUsage
+      }
+
+      $i++
+      $BinPath = Get-AbsolutePath $RemainingArgs[$i]
+    }
+    "--device" {
+      if ($i + 1 -ge $RemainingArgs.Count) {
+        Fail "Missing value for --device" -ShowUsage
+      }
+
+      $i++
+      $DeviceName = $RemainingArgs[$i]
+    }
+    "--openocd-root" {
+      if ($i + 1 -ge $RemainingArgs.Count) {
+        Fail "Missing value for --openocd-root" -ShowUsage
+      }
+
+      $i++
+      $OpenOCDRoot = Get-AbsolutePath $RemainingArgs[$i]
+      $OpenOCDExe = Join-Path $OpenOCDRoot "bin\openocd.exe"
+      $ScriptsDir = Join-Path $OpenOCDRoot "scripts"
+      $FlashLoader = Join-Path $OpenOCDRoot "FlashLoader\HT32F491x3_256.HLM"
+    }
+    "--dry-run" {
+      $DryRun = $true
+    }
+    "--help" {
+      Show-Usage
+      exit 0
+    }
+    "-h" {
+      Show-Usage
+      exit 0
+    }
+    default {
+      Fail "Unknown argument: $($RemainingArgs[$i])" -ShowUsage
+    }
+  }
+}
+
+if (-not $DryRun) {
+  if (-not (Test-Path -Path $BinPath -PathType Leaf)) {
+    Fail "Binary not found: $BinPath"
+  }
+
+  if (-not (Test-Path -Path $OpenOCDExe -PathType Leaf)) {
+    Fail "OpenOCD executable not found: $OpenOCDExe"
+  }
+
+  if (-not (Test-Path -Path $FlashLoader -PathType Leaf)) {
+    Fail "Flash loader not found: $FlashLoader"
+  }
+}
+
+$OpenOCDArgs = @(
+  "-s"
+  $ScriptsDir
+  "-c"
+  "hlm_SRAM $SRAMBase $WorkAreaSize"
+  "-c"
+  "hlm_loader {$FlashLoader} $FlashBase $FlashEnd"
+  "-c"
+  "ht_flags erase_sector"
+  "-c"
+  "set WORKAREASIZE $WorkAreaSize"
+  "-f"
+  "interface/htlink.cfg"
+  "-f"
+  "target/HLM491x3.cfg"
+  "-c"
+  "set_expected_name $DeviceName"
+  "-c"
+  "program $BinPath verify reset exit $FlashBase"
+)
+
+$CommandParts = @($OpenOCDExe) + $OpenOCDArgs
+$CommandText = ($CommandParts | ForEach-Object { Format-CommandArgument $_ }) 
-join " "
+
+Write-Host ("TOPDIR      : {0}" -f $TopDir)
+Write-Host ("Binary      : {0}" -f $BinPath)
+Write-Host ("Device      : {0}" -f $DeviceName)
+Write-Host ("OpenOCD     : {0}" -f $OpenOCDExe)
+Write-Host ("Flash loader: {0}" -f $FlashLoader)
+
+if ($DryRun) {
+  if (-not (Test-Path -Path $BinPath -PathType Leaf)) {
+    Write-Host "Warning     : binary not found yet"
+  }
+
+  if (-not (Test-Path -Path $OpenOCDExe -PathType Leaf)) {
+    Write-Host "Warning     : OpenOCD executable not found"
+  }
+
+  if (-not (Test-Path -Path $FlashLoader -PathType Leaf)) {
+    Write-Host "Warning     : flash loader not found"
+  }
+
+  Write-Host ("Command     : {0}" -f $CommandText)
+  exit 0
+}
+
+& $OpenOCDExe @OpenOCDArgs
+exit $LASTEXITCODE
diff --git a/boards/arm/ht32f491x3/esk32/tools/flash.py 
b/boards/arm/ht32f491x3/esk32/tools/flash.py
new file mode 100755
index 00000000000..74ae8a6a462
--- /dev/null
+++ b/boards/arm/ht32f491x3/esk32/tools/flash.py
@@ -0,0 +1,91 @@
+#!/usr/bin/env python3
+############################################################################
+# boards/arm/ht32f491x3/esk32/tools/flash.py
+#
+# SPDX-License-Identifier: Apache-2.0
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+#
+############################################################################
+
+# Wrapper that dispatches to flash.sh in WSL and flash.ps1 on Windows.
+
+import os
+import platform
+import shutil
+import subprocess
+import sys
+from pathlib import Path
+
+SCRIPT_DIR = Path(__file__).resolve().parent
+
+
+def is_windows_host():
+    system = platform.system().lower()
+    return os.name == "nt" or system.startswith("msys") or 
system.startswith("cygwin")
+
+
+def is_wsl():
+    if "WSL_INTEROP" in os.environ or "WSL_DISTRO_NAME" in os.environ:
+        return True
+
+    release = platform.release().lower()
+    version = platform.version().lower()
+    return "microsoft" in release or "microsoft" in version
+
+
+def build_command(argv):
+    if is_windows_host():
+        powershell = shutil.which("powershell.exe") or shutil.which("pwsh.exe")
+        if powershell is None:
+            raise RuntimeError("Unable to find powershell.exe or pwsh.exe in 
PATH.")
+
+        backend = SCRIPT_DIR / "flash.ps1"
+        return [powershell, "-ExecutionPolicy", "Bypass", "-File", 
str(backend), *argv]
+
+    if sys.platform.startswith("linux"):
+        if not is_wsl():
+            raise RuntimeError(
+                "Unsupported host: this wrapper supports Windows native and 
WSL."
+            )
+
+        bash = shutil.which("bash")
+        if bash is None:
+            raise RuntimeError("Unable to find bash in PATH.")
+
+        backend = SCRIPT_DIR / "flash.sh"
+        return [bash, str(backend), *argv]
+
+    raise RuntimeError(
+        "Unsupported host: this wrapper supports Windows native and WSL."
+    )
+
+
+def main(argv):
+    try:
+        cmd = build_command(argv)
+        completed = subprocess.run(cmd, check=False)
+        return completed.returncode
+    except RuntimeError as err:
+        print(err, file=sys.stderr)
+        return 1
+    except OSError as err:
+        print(f"Failed to start backend script: {err}", file=sys.stderr)
+        return 1
+
+
+if __name__ == "__main__":
+    sys.exit(main(sys.argv[1:]))
diff --git a/boards/arm/ht32f491x3/esk32/tools/flash.sh 
b/boards/arm/ht32f491x3/esk32/tools/flash.sh
index 25d3635deb1..eeff2de93d8 100755
--- a/boards/arm/ht32f491x3/esk32/tools/flash.sh
+++ b/boards/arm/ht32f491x3/esk32/tools/flash.sh
@@ -27,7 +27,11 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
 TOPDIR="$(cd "${SCRIPT_DIR}/../../../../.." && pwd)"
 
 DEFAULT_BIN="${TOPDIR}/nuttx.bin"
-OPENOCD_ROOT="/mnt/c/Program Files (x86)/Holtek HT32 
Series/HT32-IDE/xPack/xpack-openocd-0.11.0-4"
+WINDOWS_SETUP="Windows 10 Pro with WSL2"
+HT32_IDE_VERSION="HT32-IDE 1.0.6 (Build Date: 2025/12/04)"
+HT32_IDE_ROOT="/mnt/c/Program Files (x86)/Holtek HT32 Series/HT32-IDE"
+OPENOCD_PACKAGE="xPack OpenOCD 0.11.0-4"
+OPENOCD_ROOT="${HT32_IDE_ROOT}/xPack/xpack-openocd-0.11.0-4"
 OPENOCD_EXE="${OPENOCD_ROOT}/bin/openocd.exe"
 SCRIPTS_DIR="${OPENOCD_ROOT}/scripts"
 FLASH_LOADER="${OPENOCD_ROOT}/FlashLoader/HT32F491x3_256.HLM"
@@ -39,6 +43,28 @@ WORKAREA_SIZE="0xC000"
 BIN_PATH="${DEFAULT_BIN}"
 DRY_RUN=0
 
+print_assumptions() {
+  cat <<EOF
+############################################################################
+# Assumptions:
+#
+#   - ${WINDOWS_SETUP}; the Windows C: drive is available in WSL at /mnt/c
+#   - This is the WSL backend; use flash.py from the same directory for
+#     automatic backend selection, or run this script directly from WSL2
+#   - ${HT32_IDE_VERSION} installed at:
+#       ${HT32_IDE_ROOT}
+#   - ${OPENOCD_PACKAGE} available at:
+#       ${OPENOCD_ROOT}
+#   - Holtek HT-Link probe using interface/htlink.cfg
+#   - ESK32 board with ${DEVICE_NAME} and FlashLoader/HT32F491x3_256.HLM
+#
+# Update this script if any of the above are not true.
+#
+############################################################################
+
+EOF
+}
+
 usage() {
   cat <<EOF
 Usage: $0 [options]
@@ -53,10 +79,12 @@ Options:
 Examples:
   $0
   $0 --dry-run
-  $0 --device HT32F49163_64LQFP
+  $0 --device HT32F49163_100LQFP
 EOF
 }
 
+print_assumptions
+
 while (($# > 0)); do
   case "$1" in
     --bin)

Reply via email to