You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by xi...@apache.org on 2026/03/30 01:48:24 UTC

(nuttx) 01/03: arch/arm/ht32f491x3: add initial support

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 ba6ee9d559f227518ab80cbd5076e007864b36cc
Author: Felipe Moura <mo...@gmail.com>
AuthorDate: Tue Mar 24 21:51:04 2026 -0300

    arch/arm/ht32f491x3: add initial support
    
    Add initial HT32F491x3 support with startup, IRQ handling,
    serial console, GPIO helpers, custom vectors, and CMake build files.
    
    Signed-off-by: Felipe Moura <mo...@gmail.com>
---
 arch/arm/Kconfig                                   |  12 +
 arch/arm/include/ht32f491x3/chip.h                 |  69 +++
 arch/arm/include/ht32f491x3/ht32f491x3_irq.h       | 130 ++++
 arch/arm/include/ht32f491x3/irq.h                  |  61 ++
 arch/arm/src/Makefile                              |   9 +
 arch/arm/src/ht32f491x3/CMakeLists.txt             |  37 ++
 arch/arm/src/ht32f491x3/Kconfig                    |  67 +++
 arch/arm/src/ht32f491x3/Make.defs                  |  34 ++
 arch/arm/src/ht32f491x3/arm_vectors.c              | 108 ++++
 arch/arm/src/ht32f491x3/chip.h                     |  43 ++
 arch/arm/src/ht32f491x3/hardware/ht32f491x3_crm.h  | 249 ++++++++
 .../arm/src/ht32f491x3/hardware/ht32f491x3_flash.h |  50 ++
 arch/arm/src/ht32f491x3/hardware/ht32f491x3_gpio.h |  83 +++
 .../src/ht32f491x3/hardware/ht32f491x3_memorymap.h | 127 ++++
 arch/arm/src/ht32f491x3/hardware/ht32f491x3_pwc.h  |  48 ++
 arch/arm/src/ht32f491x3/hardware/ht32f491x3_uart.h | 147 +++++
 arch/arm/src/ht32f491x3/ht32f491x3_config.h        |  53 ++
 arch/arm/src/ht32f491x3/ht32f491x3_gpio.c          |  78 +++
 arch/arm/src/ht32f491x3/ht32f491x3_gpio.h          |  63 ++
 arch/arm/src/ht32f491x3/ht32f491x3_irq.c           | 310 ++++++++++
 arch/arm/src/ht32f491x3/ht32f491x3_lowputc.c       | 287 +++++++++
 arch/arm/src/ht32f491x3/ht32f491x3_lowputc.h       |  43 ++
 arch/arm/src/ht32f491x3/ht32f491x3_serial.c        | 658 +++++++++++++++++++++
 arch/arm/src/ht32f491x3/ht32f491x3_serial.h        |  46 ++
 arch/arm/src/ht32f491x3/ht32f491x3_start.c         | 114 ++++
 arch/arm/src/ht32f491x3/ht32f491x3_start.h         |  39 ++
 arch/arm/src/ht32f491x3/ht32f491x3_timerisr.c      |  95 +++
 27 files changed, 3060 insertions(+)

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 52b1e3e88da..de81c0fb81c 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -779,6 +779,14 @@ config ARCH_CHIP_CXD32XX
 	---help---
 		Sony CXD32XX (ARM Cortex-M4) architectures
 
+config ARCH_CHIP_HT32F491X3
+	bool "Holtek HT32F491x3"
+	select ARCH_CORTEXM4
+	select ARCH_HAVE_FPU
+	select LIBC_ARCH_ATOMIC
+	---help---
+		Holtek HT32F491x3 (ARM Cortex-M4) architectures
+
 config ARCH_CHIP_ARM_CUSTOM
 	bool "Custom ARM chip"
 	select ARCH_CHIP_CUSTOM
@@ -1207,6 +1215,7 @@ config ARCH_CHIP
 	default "goldfish"	if ARCH_CHIP_GOLDFISH_ARM
 	default "at32"		if ARCH_CHIP_AT32
 	default "cxd32xx"	if ARCH_CHIP_CXD32XX
+	default "ht32f491x3"	if ARCH_CHIP_HT32F491X3
 	default "csk6"		if ARCH_CHIP_CSK6
 	default "mcx-nxxx"	if ARCH_CHIP_MCX_NXXX
 
@@ -1748,6 +1757,9 @@ endif
 if ARCH_CHIP_CXD32XX
 source "arch/arm/src/cxd32xx/Kconfig"
 endif
+if ARCH_CHIP_HT32F491X3
+source "arch/arm/src/ht32f491x3/Kconfig"
+endif
 if ARCH_CHIP_MCX_NXXX
 source "arch/arm/src/mcx-nxxx/Kconfig"
 endif
diff --git a/arch/arm/include/ht32f491x3/chip.h b/arch/arm/include/ht32f491x3/chip.h
new file mode 100644
index 00000000000..bc843a01c33
--- /dev/null
+++ b/arch/arm/include/ht32f491x3/chip.h
@@ -0,0 +1,69 @@
+/****************************************************************************
+ * arch/arm/include/ht32f491x3/chip.h
+ *
+ * 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.
+ *
+ ****************************************************************************/
+
+#ifndef __ARCH_ARM_INCLUDE_HT32F491X3_CHIP_H
+#define __ARCH_ARM_INCLUDE_HT32F491X3_CHIP_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define HT32M4_SYSH_PRIORITY_MIN     0xe0
+#define HT32M4_SYSH_PRIORITY_DEFAULT 0x80
+#define HT32M4_SYSH_PRIORITY_MAX     0x00
+#define HT32M4_SYSH_PRIORITY_STEP    0x20
+
+#define NVIC_SYSH_PRIORITY_MIN        HT32M4_SYSH_PRIORITY_MIN
+#define NVIC_SYSH_PRIORITY_DEFAULT    HT32M4_SYSH_PRIORITY_DEFAULT
+#define NVIC_SYSH_PRIORITY_MAX        HT32M4_SYSH_PRIORITY_MAX
+#define NVIC_SYSH_PRIORITY_STEP       HT32M4_SYSH_PRIORITY_STEP
+
+#if defined(CONFIG_ARCH_CHIP_HT32F49153)
+#  define HT32_FLASH_KB 128
+#elif defined(CONFIG_ARCH_CHIP_HT32F49163)
+#  define HT32_FLASH_KB 256
+#else
+#  error "Unsupported HT32F491x3 device"
+#endif
+
+#define HT32_SRAM_KB             48
+#define HT32_NUSART              8
+#define HT32_NGPIO               6
+
+#define HT32_HICK_FREQUENCY       8000000
+#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_SYSCLK_FREQUENCY CONFIG_HT32F491X3_SYSCLK_FREQUENCY
+#define HT32_HCLK_FREQUENCY   HT32_SYSCLK_FREQUENCY
+#define HT32_PCLK1_FREQUENCY  CONFIG_HT32F491X3_PCLK1_FREQUENCY
+#define HT32_PCLK2_FREQUENCY  CONFIG_HT32F491X3_PCLK2_FREQUENCY
+
+#endif /* __ARCH_ARM_INCLUDE_HT32F491X3_CHIP_H */
diff --git a/arch/arm/include/ht32f491x3/ht32f491x3_irq.h b/arch/arm/include/ht32f491x3/ht32f491x3_irq.h
new file mode 100644
index 00000000000..201431f885c
--- /dev/null
+++ b/arch/arm/include/ht32f491x3/ht32f491x3_irq.h
@@ -0,0 +1,130 @@
+/****************************************************************************
+ * arch/arm/include/ht32f491x3/ht32f491x3_irq.h
+ *
+ * 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.
+ *
+ ****************************************************************************/
+
+/* This file should never be included directly but, rather,
+ * only indirectly through nuttx/irq.h
+ */
+
+#ifndef __ARCH_ARM_INCLUDE_HT32F491X3_HT32F491X3_IRQ_H
+#define __ARCH_ARM_INCLUDE_HT32F491X3_HT32F491X3_IRQ_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include <nuttx/irq.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* External interrupts.  These values follow the Holtek CMSIS device header
+ * and startup vector table for the HT32F491x3 family.
+ */
+
+#define HT32_IRQ_WWDT          (HT32_IRQ_FIRST + 0)
+#define HT32_IRQ_PVM           (HT32_IRQ_FIRST + 1)
+#define HT32_IRQ_PVD           HT32_IRQ_PVM
+#define HT32_IRQ_TAMP_STAMP    (HT32_IRQ_FIRST + 2)
+#define HT32_IRQ_TAMPER        HT32_IRQ_TAMP_STAMP
+#define HT32_IRQ_TIMESTAMP     HT32_IRQ_TAMP_STAMP
+#define HT32_IRQ_ERTCWAKEUP    (HT32_IRQ_FIRST + 3)
+#define HT32_IRQ_FLASH         (HT32_IRQ_FIRST + 4)
+#define HT32_IRQ_CRM           (HT32_IRQ_FIRST + 5)
+#define HT32_IRQ_EXINT0        (HT32_IRQ_FIRST + 6)
+#define HT32_IRQ_EXINT1        (HT32_IRQ_FIRST + 7)
+#define HT32_IRQ_EXINT2        (HT32_IRQ_FIRST + 8)
+#define HT32_IRQ_EXINT3        (HT32_IRQ_FIRST + 9)
+#define HT32_IRQ_EXINT4        (HT32_IRQ_FIRST + 10)
+#define HT32_IRQ_DMA1CH1       (HT32_IRQ_FIRST + 11)
+#define HT32_IRQ_DMA1CH2       (HT32_IRQ_FIRST + 12)
+#define HT32_IRQ_DMA1CH3       (HT32_IRQ_FIRST + 13)
+#define HT32_IRQ_DMA1CH4       (HT32_IRQ_FIRST + 14)
+#define HT32_IRQ_DMA1CH5       (HT32_IRQ_FIRST + 15)
+#define HT32_IRQ_DMA1CH6       (HT32_IRQ_FIRST + 16)
+#define HT32_IRQ_DMA1CH7       (HT32_IRQ_FIRST + 17)
+#define HT32_IRQ_ADC1          (HT32_IRQ_FIRST + 18)
+#define HT32_IRQ_ADC           HT32_IRQ_ADC1
+#define HT32_IRQ_CAN1TX        (HT32_IRQ_FIRST + 19)
+#define HT32_IRQ_CAN1RX0       (HT32_IRQ_FIRST + 20)
+#define HT32_IRQ_CAN1RX1       (HT32_IRQ_FIRST + 21)
+#define HT32_IRQ_CAN1SE        (HT32_IRQ_FIRST + 22)
+#define HT32_IRQ_CANSE         HT32_IRQ_CAN1SE
+#define HT32_IRQ_EXINT95       (HT32_IRQ_FIRST + 23)
+#define HT32_IRQ_TMR1BRK       (HT32_IRQ_FIRST + 24)
+#define HT32_IRQ_TMR9          HT32_IRQ_TMR1BRK
+#define HT32_IRQ_TMR1UP        (HT32_IRQ_FIRST + 25)
+#define HT32_IRQ_TMR10         HT32_IRQ_TMR1UP
+#define HT32_IRQ_TMR1TRGCOM    (HT32_IRQ_FIRST + 26)
+#define HT32_IRQ_TMR11         HT32_IRQ_TMR1TRGCOM
+#define HT32_IRQ_TMR1CC        (HT32_IRQ_FIRST + 27)
+#define HT32_IRQ_TMR2          (HT32_IRQ_FIRST + 28)
+#define HT32_IRQ_TMR3          (HT32_IRQ_FIRST + 29)
+#define HT32_IRQ_TMR4          (HT32_IRQ_FIRST + 30)
+#define HT32_IRQ_I2C1EV        (HT32_IRQ_FIRST + 31)
+#define HT32_IRQ_I2C1ERR       (HT32_IRQ_FIRST + 32)
+#define HT32_IRQ_I2C2EV        (HT32_IRQ_FIRST + 33)
+#define HT32_IRQ_I2C2ERR       (HT32_IRQ_FIRST + 34)
+#define HT32_IRQ_SPI1          (HT32_IRQ_FIRST + 35)
+#define HT32_IRQ_SPI2          (HT32_IRQ_FIRST + 36)
+#define HT32_IRQ_USART1        (HT32_IRQ_FIRST + 37)
+#define HT32_IRQ_USART2        (HT32_IRQ_FIRST + 38)
+#define HT32_IRQ_USART3        (HT32_IRQ_FIRST + 39)
+#define HT32_IRQ_EXINT1510     (HT32_IRQ_FIRST + 40)
+#define HT32_IRQ_ERTCALARM     (HT32_IRQ_FIRST + 41)
+#define HT32_IRQ_OTGFSWKUP     (HT32_IRQ_FIRST + 42)
+#define HT32_IRQ_TMR12         (HT32_IRQ_FIRST + 43)
+#define HT32_IRQ_TMR13         (HT32_IRQ_FIRST + 44)
+#define HT32_IRQ_TMR14         (HT32_IRQ_FIRST + 45)
+#define HT32_IRQ_SPI3          (HT32_IRQ_FIRST + 51)
+#define HT32_IRQ_USART4        (HT32_IRQ_FIRST + 52)
+#define HT32_IRQ_USART5        (HT32_IRQ_FIRST + 53)
+#define HT32_IRQ_TMR6          (HT32_IRQ_FIRST + 54)
+#define HT32_IRQ_DAC           HT32_IRQ_TMR6
+#define HT32_IRQ_TMR7          (HT32_IRQ_FIRST + 55)
+#define HT32_IRQ_DMA2CH1       (HT32_IRQ_FIRST + 56)
+#define HT32_IRQ_DMA2CH2       (HT32_IRQ_FIRST + 57)
+#define HT32_IRQ_DMA2CH3       (HT32_IRQ_FIRST + 58)
+#define HT32_IRQ_DMA2CH4       (HT32_IRQ_FIRST + 59)
+#define HT32_IRQ_DMA2CH5       (HT32_IRQ_FIRST + 60)
+#define HT32_IRQ_CAN2TX        (HT32_IRQ_FIRST + 63)
+#define HT32_IRQ_CAN2RX0       (HT32_IRQ_FIRST + 64)
+#define HT32_IRQ_CAN2RX1       (HT32_IRQ_FIRST + 65)
+#define HT32_IRQ_CAN2SE        (HT32_IRQ_FIRST + 66)
+#define HT32_IRQ_OTGFS1        (HT32_IRQ_FIRST + 67)
+#define HT32_IRQ_OTGFS         HT32_IRQ_OTGFS1
+#define HT32_IRQ_DMA2CH6       (HT32_IRQ_FIRST + 68)
+#define HT32_IRQ_DMA2CH7       (HT32_IRQ_FIRST + 69)
+#define HT32_IRQ_USART6        (HT32_IRQ_FIRST + 71)
+#define HT32_IRQ_I2C3EV        (HT32_IRQ_FIRST + 72)
+#define HT32_IRQ_I2C3ERR       (HT32_IRQ_FIRST + 73)
+#define HT32_IRQ_FPU           (HT32_IRQ_FIRST + 81)
+#define HT32_IRQ_USART7        (HT32_IRQ_FIRST + 82)
+#define HT32_IRQ_USART8        (HT32_IRQ_FIRST + 83)
+#define HT32_IRQ_DMAMUX        (HT32_IRQ_FIRST + 94)
+#define HT32_IRQ_ACC           (HT32_IRQ_FIRST + 103)
+
+#define HT32_IRQ_NEXTINT       (104)
+#define NR_IRQS                (HT32_IRQ_FIRST + HT32_IRQ_NEXTINT)
+
+#endif /* __ARCH_ARM_INCLUDE_HT32F491X3_HT32F491X3_IRQ_H */
diff --git a/arch/arm/include/ht32f491x3/irq.h b/arch/arm/include/ht32f491x3/irq.h
new file mode 100644
index 00000000000..16d1f314af8
--- /dev/null
+++ b/arch/arm/include/ht32f491x3/irq.h
@@ -0,0 +1,61 @@
+/****************************************************************************
+ * arch/arm/include/ht32f491x3/irq.h
+ *
+ * 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.
+ *
+ ****************************************************************************/
+
+/* This file should never be included directly but, rather,
+ * only indirectly through nuttx/irq.h
+ */
+
+#ifndef __ARCH_ARM_INCLUDE_HT32F491X3_IRQ_H
+#define __ARCH_ARM_INCLUDE_HT32F491X3_IRQ_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include <nuttx/irq.h>
+#include <arch/ht32f491x3/chip.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define HT32_IRQ_RESERVED       (0)
+#define HT32_IRQ_NMI            (2)
+#define HT32_IRQ_HARDFAULT      (3)
+#define HT32_IRQ_MEMFAULT       (4)
+#define HT32_IRQ_BUSFAULT       (5)
+#define HT32_IRQ_USAGEFAULT     (6)
+#define HT32_IRQ_SVCALL        (11)
+#define HT32_IRQ_DBGMONITOR    (12)
+#define HT32_IRQ_PENDSV        (14)
+#define HT32_IRQ_SYSTICK       (15)
+
+#define HT32_IRQ_FIRST         (16)
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <arch/ht32f491x3/ht32f491x3_irq.h>
+
+#endif /* __ARCH_ARM_INCLUDE_HT32F491X3_IRQ_H */
diff --git a/arch/arm/src/Makefile b/arch/arm/src/Makefile
index 00581e6a1c1..7c6da2a3eaa 100644
--- a/arch/arm/src/Makefile
+++ b/arch/arm/src/Makefile
@@ -21,7 +21,16 @@
 ############################################################################
 
 include $(TOPDIR)/tools/Make.defs
+
+# Allow cleanup targets to run even if the configured chip dirlink is gone.
+CLEAN_GOALS = clean distclean
+ifeq ($(strip $(MAKECMDGOALS)),)
+include chip/Make.defs
+else ifeq ($(strip $(filter-out $(CLEAN_GOALS),$(MAKECMDGOALS))),)
+-include chip/Make.defs
+else
 include chip/Make.defs
+endif
 
 ifeq ($(CONFIG_ARCH_ARMV7A),y)          # ARMv7-A
 ARCH_SUBDIR = armv7-a
diff --git a/arch/arm/src/ht32f491x3/CMakeLists.txt b/arch/arm/src/ht32f491x3/CMakeLists.txt
new file mode 100644
index 00000000000..1231e5546bd
--- /dev/null
+++ b/arch/arm/src/ht32f491x3/CMakeLists.txt
@@ -0,0 +1,37 @@
+# ##############################################################################
+# arch/arm/src/ht32f491x3/CMakeLists.txt
+#
+# 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.
+#
+# ##############################################################################
+
+list(
+  APPEND
+  SRCS
+  ht32f491x3_start.c
+  ht32f491x3_irq.c
+  ht32f491x3_timerisr.c
+  ht32f491x3_gpio.c
+  ht32f491x3_lowputc.c
+  ht32f491x3_serial.c)
+
+if(CONFIG_ARCH_HAVE_CUSTOM_VECTORS)
+  list(APPEND SRCS arm_vectors.c)
+endif()
+
+target_sources(arch PRIVATE ${SRCS})
diff --git a/arch/arm/src/ht32f491x3/Kconfig b/arch/arm/src/ht32f491x3/Kconfig
new file mode 100644
index 00000000000..3a32d32146a
--- /dev/null
+++ b/arch/arm/src/ht32f491x3/Kconfig
@@ -0,0 +1,67 @@
+#
+# For a description of the syntax of this configuration file,
+# see the file kconfig-language.txt in the NuttX tools repository.
+#
+
+comment "HT32F491x3 Configuration Options"
+
+choice
+	prompt "HT32F491x3 Chip Selection"
+	default ARCH_CHIP_HT32F49163
+	depends on ARCH_CHIP_HT32F491X3
+
+config ARCH_CHIP_HT32F49153
+	bool "HT32F49153"
+	select ARCH_HAVE_CUSTOM_VECTORS
+	---help---
+		128 KiB FLASH, 48 KiB SRAM.
+
+config ARCH_CHIP_HT32F49163
+	bool "HT32F49163"
+	select ARCH_HAVE_CUSTOM_VECTORS
+	---help---
+		256 KiB FLASH, 48 KiB SRAM.
+
+endchoice
+
+config HT32F491X3_SYSCLK_FREQUENCY
+	int "System clock frequency"
+	default 8000000
+	range 1 150000000
+	depends on ARCH_CHIP_HT32F491X3
+	---help---
+		The reset clock tree runs from the 8 MHz HICK oscillator. Adjust
+		this if board-specific CRM/PLL setup changes SYSCLK before the
+		generic timer or serial logic runs.
+
+config HT32F491X3_PCLK1_FREQUENCY
+	int "APB1 clock frequency"
+	default HT32F491X3_SYSCLK_FREQUENCY
+	range 1 150000000
+	depends on ARCH_CHIP_HT32F491X3
+	---help---
+		APB1 clock used by USART2 and USART3. The default matches the reset
+		configuration where APB1DIV does not divide HCLK.
+
+config HT32F491X3_PCLK2_FREQUENCY
+	int "APB2 clock frequency"
+	default HT32F491X3_SYSCLK_FREQUENCY
+	range 1 150000000
+	depends on ARCH_CHIP_HT32F491X3
+	---help---
+		APB2 clock used by USART1. The default matches the reset
+		configuration where APB2DIV does not divide HCLK.
+
+menu "Peripheral Support"
+
+config HT32F491X3_USART1_SERIALDRIVER
+	bool "USART1"
+	default y
+	select USART1_SERIALDRIVER
+	select ARCH_HAVE_SERIAL_TERMIOS
+	---help---
+		Enable the standard lower-half driver for USART1.
+
+comment "In this current version, only USART1 is exposed by the esk32 board support."
+
+endmenu # "Peripheral Support"
diff --git a/arch/arm/src/ht32f491x3/Make.defs b/arch/arm/src/ht32f491x3/Make.defs
new file mode 100644
index 00000000000..e8fee89b83f
--- /dev/null
+++ b/arch/arm/src/ht32f491x3/Make.defs
@@ -0,0 +1,34 @@
+############################################################################
+# arch/arm/src/ht32f491x3/Make.defs
+#
+# 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.
+#
+############################################################################
+
+include armv7-m/Make.defs
+
+CHIP_ASRCS +=
+
+CHIP_CSRCS += ht32f491x3_start.c ht32f491x3_irq.c
+CHIP_CSRCS += ht32f491x3_timerisr.c ht32f491x3_gpio.c
+CHIP_CSRCS += ht32f491x3_lowputc.c
+CHIP_CSRCS += ht32f491x3_serial.c
+
+ifeq ($(CONFIG_ARCH_HAVE_CUSTOM_VECTORS),y)
+CHIP_CSRCS += arm_vectors.c
+endif
diff --git a/arch/arm/src/ht32f491x3/arm_vectors.c b/arch/arm/src/ht32f491x3/arm_vectors.c
new file mode 100644
index 00000000000..bfd2bcd5511
--- /dev/null
+++ b/arch/arm/src/ht32f491x3/arm_vectors.c
@@ -0,0 +1,108 @@
+/****************************************************************************
+ * arch/arm/src/ht32f491x3/arm_vectors.c
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ * SPDX-FileCopyrightText: 2012 Michael Smith. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ *    used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdint.h>
+
+#include "chip.h"
+#include "arm_internal.h"
+#include "ram_vectors.h"
+#include "nvic.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define IDLE_STACK (_ebss + CONFIG_IDLETHREAD_STACKSIZE)
+
+#define HT32_VECTOR_RESERVED ((const void *)(uintptr_t)UINT32_MAX)
+
+#if defined(CONFIG_ARCH_CHIP_HT32F49153)
+#  define HT32_VECTOR_FWID ((const void *)(uintptr_t)0x00049153u)
+#elif defined(CONFIG_ARCH_CHIP_HT32F49163)
+#  define HT32_VECTOR_FWID ((const void *)(uintptr_t)0x00049163u)
+#else
+#  error "Unsupported HT32F491x3 device"
+#endif
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+extern void __start(void);
+
+static void start(void)
+{
+  /* Zero lr to mark the end of backtrace */
+
+  asm volatile ("mov lr, #0\n\t"
+                "b  __start\n\t");
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+extern void exception_common(void);
+extern void exception_direct(void);
+
+/****************************************************************************
+ * Public data
+ ****************************************************************************/
+
+/* Holtek reserves vector slots 7/9/10/13 and uses slot 8 for a device FWID.
+ * Keep the NuttX exception routing semantics for all real exceptions/IRQs.
+ */
+
+const void * const _vectors[] locate_data(".vectors")
+                              aligned_data(VECTAB_ALIGN) =
+{
+  IDLE_STACK,
+  start,
+  [NVIC_IRQ_NMI ... NVIC_IRQ_USAGEFAULT] = &exception_common,
+  [7]                                    = HT32_VECTOR_RESERVED,
+  [8]                                    = HT32_VECTOR_FWID,
+  [9 ... 10]                             = HT32_VECTOR_RESERVED,
+  [NVIC_IRQ_SVCALL ... NVIC_IRQ_DBGMONITOR] = &exception_common,
+  [13]                                   = HT32_VECTOR_RESERVED,
+  [NVIC_IRQ_PENDSV]                      = &exception_common,
+  [NVIC_IRQ_SYSTICK ... (15 + ARMV7M_PERIPHERAL_INTERRUPTS)]
+                                         = &exception_direct
+};
diff --git a/arch/arm/src/ht32f491x3/chip.h b/arch/arm/src/ht32f491x3/chip.h
new file mode 100644
index 00000000000..6e9ff9162a5
--- /dev/null
+++ b/arch/arm/src/ht32f491x3/chip.h
@@ -0,0 +1,43 @@
+/****************************************************************************
+ * arch/arm/src/ht32f491x3/chip.h
+ *
+ * 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.
+ *
+ ****************************************************************************/
+
+#ifndef __ARCH_ARM_SRC_HT32F491X3_CHIP_H
+#define __ARCH_ARM_SRC_HT32F491X3_CHIP_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <arch/ht32f491x3/chip.h>
+#include <arch/ht32f491x3/irq.h>
+
+#include "hardware/ht32f491x3_memorymap.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define ARMV7M_PERIPHERAL_INTERRUPTS HT32_IRQ_NEXTINT
+
+#endif /* __ARCH_ARM_SRC_HT32F491X3_CHIP_H */
diff --git a/arch/arm/src/ht32f491x3/hardware/ht32f491x3_crm.h b/arch/arm/src/ht32f491x3/hardware/ht32f491x3_crm.h
new file mode 100644
index 00000000000..2d0387e2778
--- /dev/null
+++ b/arch/arm/src/ht32f491x3/hardware/ht32f491x3_crm.h
@@ -0,0 +1,249 @@
+/****************************************************************************
+ * arch/arm/src/ht32f491x3/hardware/ht32f491x3_crm.h
+ *
+ * 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.
+ *
+ ****************************************************************************/
+
+#ifndef __ARCH_ARM_SRC_HT32F491X3_HARDWARE_HT32F491X3_CRM_H
+#define __ARCH_ARM_SRC_HT32F491X3_HARDWARE_HT32F491X3_CRM_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include "chip.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Register Offsets *********************************************************/
+
+#define HT32_CRM_CTRL_OFFSET            0x000
+#define HT32_CRM_PLLCFG_OFFSET          0x004
+#define HT32_CRM_CFG_OFFSET             0x008
+#define HT32_CRM_CLKINT_OFFSET          0x00c
+#define HT32_CRM_AHBRST1_OFFSET         0x010
+#define HT32_CRM_AHBRST2_OFFSET         0x014
+#define HT32_CRM_AHBRST3_OFFSET         0x018
+#define HT32_CRM_APB1RST_OFFSET         0x020
+#define HT32_CRM_APB2RST_OFFSET         0x024
+#define HT32_CRM_AHBEN1_OFFSET          0x030
+#define HT32_CRM_AHBEN2_OFFSET          0x034
+#define HT32_CRM_AHBEN3_OFFSET          0x038
+#define HT32_CRM_APB1EN_OFFSET          0x040
+#define HT32_CRM_APB2EN_OFFSET          0x044
+#define HT32_CRM_APB1LPEN_OFFSET        0x060
+#define HT32_CRM_APB2LPEN_OFFSET        0x064
+#define HT32_CRM_PICLKS_OFFSET          0x068
+#define HT32_CRM_MISC1_OFFSET           0x0a0
+#define HT32_CRM_MISC2_OFFSET           0x0a4
+
+/* Register Addresses *******************************************************/
+
+#define HT32_CRM_CTRL                   (HT32_CRM_BASE + HT32_CRM_CTRL_OFFSET)
+#define HT32_CRM_PLLCFG                 (HT32_CRM_BASE + HT32_CRM_PLLCFG_OFFSET)
+#define HT32_CRM_CFG                    (HT32_CRM_BASE + HT32_CRM_CFG_OFFSET)
+#define HT32_CRM_CLKINT                 (HT32_CRM_BASE + HT32_CRM_CLKINT_OFFSET)
+#define HT32_CRM_AHBRST1                (HT32_CRM_BASE + HT32_CRM_AHBRST1_OFFSET)
+#define HT32_CRM_AHBRST2                (HT32_CRM_BASE + HT32_CRM_AHBRST2_OFFSET)
+#define HT32_CRM_AHBRST3                (HT32_CRM_BASE + HT32_CRM_AHBRST3_OFFSET)
+#define HT32_CRM_APB1RST                (HT32_CRM_BASE + HT32_CRM_APB1RST_OFFSET)
+#define HT32_CRM_APB2RST                (HT32_CRM_BASE + HT32_CRM_APB2RST_OFFSET)
+#define HT32_CRM_AHBEN1                 (HT32_CRM_BASE + HT32_CRM_AHBEN1_OFFSET)
+#define HT32_CRM_AHBEN2                 (HT32_CRM_BASE + HT32_CRM_AHBEN2_OFFSET)
+#define HT32_CRM_AHBEN3                 (HT32_CRM_BASE + HT32_CRM_AHBEN3_OFFSET)
+#define HT32_CRM_APB1EN                 (HT32_CRM_BASE + HT32_CRM_APB1EN_OFFSET)
+#define HT32_CRM_APB2EN                 (HT32_CRM_BASE + HT32_CRM_APB2EN_OFFSET)
+#define HT32_CRM_APB1LPEN               (HT32_CRM_BASE + HT32_CRM_APB1LPEN_OFFSET)
+#define HT32_CRM_APB2LPEN               (HT32_CRM_BASE + HT32_CRM_APB2LPEN_OFFSET)
+#define HT32_CRM_PICLKS                 (HT32_CRM_BASE + HT32_CRM_PICLKS_OFFSET)
+#define HT32_CRM_MISC1                  (HT32_CRM_BASE + HT32_CRM_MISC1_OFFSET)
+#define HT32_CRM_MISC2                  (HT32_CRM_BASE + HT32_CRM_MISC2_OFFSET)
+
+/* Clock control register ***************************************************/
+
+#define HT32_CRM_CTRL_HICKEN            (1 << 0)
+#define HT32_CRM_CTRL_HICKSTBL          (1 << 1)
+#define HT32_CRM_CTRL_HEXTEN            (1 << 16)
+#define HT32_CRM_CTRL_HEXTSTBL          (1 << 17)
+#define HT32_CRM_CTRL_HEXTBYPS          (1 << 18)
+#define HT32_CRM_CTRL_PLLEN             (1 << 24)
+#define HT32_CRM_CTRL_PLLSTBL           (1 << 25)
+
+/* PLL configuration register ***********************************************/
+
+#define HT32_CRM_PLLCFG_PLLMS_SHIFT     (0)
+#define HT32_CRM_PLLCFG_PLLMS_MASK      (0x0f << HT32_CRM_PLLCFG_PLLMS_SHIFT)
+#define HT32_CRM_PLLCFG_PLLNS_SHIFT     (6)
+#define HT32_CRM_PLLCFG_PLLNS_MASK      (0x1ff << HT32_CRM_PLLCFG_PLLNS_SHIFT)
+#define HT32_CRM_PLLCFG_PLLFR_SHIFT     (16)
+#define HT32_CRM_PLLCFG_PLLFR_MASK      (7 << HT32_CRM_PLLCFG_PLLFR_SHIFT)
+#define HT32_CRM_PLLCFG_PLLRCS          (1 << 22)
+
+#define HT32_CRM_PLLCFG_SOURCE_HICK     0
+#define HT32_CRM_PLLCFG_SOURCE_HEXT     HT32_CRM_PLLCFG_PLLRCS
+
+#define HT32_CRM_PLLCFG_FR_1            (0 << HT32_CRM_PLLCFG_PLLFR_SHIFT)
+#define HT32_CRM_PLLCFG_FR_2            (1 << HT32_CRM_PLLCFG_PLLFR_SHIFT)
+#define HT32_CRM_PLLCFG_FR_4            (2 << HT32_CRM_PLLCFG_PLLFR_SHIFT)
+#define HT32_CRM_PLLCFG_FR_8            (3 << HT32_CRM_PLLCFG_PLLFR_SHIFT)
+#define HT32_CRM_PLLCFG_FR_16           (4 << HT32_CRM_PLLCFG_PLLFR_SHIFT)
+#define HT32_CRM_PLLCFG_FR_32           (5 << HT32_CRM_PLLCFG_PLLFR_SHIFT)
+
+/* Clock configuration register *********************************************/
+
+#define HT32_CRM_CFG_SCLKSEL_SHIFT      (0)
+#define HT32_CRM_CFG_SCLKSEL_MASK       (3 << HT32_CRM_CFG_SCLKSEL_SHIFT)
+#  define HT32_CRM_CFG_SEL_HICK         (0 << HT32_CRM_CFG_SCLKSEL_SHIFT)
+#  define HT32_CRM_CFG_SEL_HEXT         (1 << HT32_CRM_CFG_SCLKSEL_SHIFT)
+#  define HT32_CRM_CFG_SEL_PLL          (2 << HT32_CRM_CFG_SCLKSEL_SHIFT)
+
+#define HT32_CRM_CFG_SCLKSTS_SHIFT      (2)
+#define HT32_CRM_CFG_SCLKSTS_MASK       (3 << HT32_CRM_CFG_SCLKSTS_SHIFT)
+#  define HT32_CRM_CFG_STS_HICK         (0 << HT32_CRM_CFG_SCLKSTS_SHIFT)
+#  define HT32_CRM_CFG_STS_HEXT         (1 << HT32_CRM_CFG_SCLKSTS_SHIFT)
+#  define HT32_CRM_CFG_STS_PLL          (2 << HT32_CRM_CFG_SCLKSTS_SHIFT)
+
+#define HT32_CRM_CFG_AHBDIV_SHIFT       (4)
+#define HT32_CRM_CFG_AHBDIV_MASK        (0x0f << HT32_CRM_CFG_AHBDIV_SHIFT)
+#  define HT32_CRM_CFG_AHBDIV_NONE      (0 << HT32_CRM_CFG_AHBDIV_SHIFT)
+#  define HT32_CRM_CFG_AHBDIV_2         (8 << HT32_CRM_CFG_AHBDIV_SHIFT)
+#  define HT32_CRM_CFG_AHBDIV_4         (9 << HT32_CRM_CFG_AHBDIV_SHIFT)
+#  define HT32_CRM_CFG_AHBDIV_8         (10 << HT32_CRM_CFG_AHBDIV_SHIFT)
+#  define HT32_CRM_CFG_AHBDIV_16        (11 << HT32_CRM_CFG_AHBDIV_SHIFT)
+#  define HT32_CRM_CFG_AHBDIV_64        (12 << HT32_CRM_CFG_AHBDIV_SHIFT)
+#  define HT32_CRM_CFG_AHBDIV_128       (13 << HT32_CRM_CFG_AHBDIV_SHIFT)
+#  define HT32_CRM_CFG_AHBDIV_256       (14 << HT32_CRM_CFG_AHBDIV_SHIFT)
+#  define HT32_CRM_CFG_AHBDIV_512       (15 << HT32_CRM_CFG_AHBDIV_SHIFT)
+
+#define HT32_CRM_CFG_APB1DIV_SHIFT      (10)
+#define HT32_CRM_CFG_APB1DIV_MASK       (7 << HT32_CRM_CFG_APB1DIV_SHIFT)
+#  define HT32_CRM_CFG_APB1DIV_1        (0 << HT32_CRM_CFG_APB1DIV_SHIFT)
+#  define HT32_CRM_CFG_APB1DIV_2        (4 << HT32_CRM_CFG_APB1DIV_SHIFT)
+#  define HT32_CRM_CFG_APB1DIV_4        (5 << HT32_CRM_CFG_APB1DIV_SHIFT)
+#  define HT32_CRM_CFG_APB1DIV_8        (6 << HT32_CRM_CFG_APB1DIV_SHIFT)
+#  define HT32_CRM_CFG_APB1DIV_16       (7 << HT32_CRM_CFG_APB1DIV_SHIFT)
+#  define HT32_CRM_CFG_APB1DIV_NONE     HT32_CRM_CFG_APB1DIV_1
+
+#define HT32_CRM_CFG_APB2DIV_SHIFT      (13)
+#define HT32_CRM_CFG_APB2DIV_MASK       (7 << HT32_CRM_CFG_APB2DIV_SHIFT)
+#  define HT32_CRM_CFG_APB2DIV_1        (0 << HT32_CRM_CFG_APB2DIV_SHIFT)
+#  define HT32_CRM_CFG_APB2DIV_2        (4 << HT32_CRM_CFG_APB2DIV_SHIFT)
+#  define HT32_CRM_CFG_APB2DIV_4        (5 << HT32_CRM_CFG_APB2DIV_SHIFT)
+#  define HT32_CRM_CFG_APB2DIV_8        (6 << HT32_CRM_CFG_APB2DIV_SHIFT)
+#  define HT32_CRM_CFG_APB2DIV_16       (7 << HT32_CRM_CFG_APB2DIV_SHIFT)
+#  define HT32_CRM_CFG_APB2DIV_NONE     HT32_CRM_CFG_APB2DIV_1
+
+/* Clock misc1 register *****************************************************/
+
+#define HT32_CRM_MISC1_HICKDIV          (1 << 12)
+#define HT32_CRM_MISC1_HICKTOUSB        (1 << 13)
+#define HT32_CRM_MISC1_HICKTOSCLK       (1 << 14)
+#define HT32_CRM_MISC1_PLLCLKTOADC      (1 << 15)
+
+/* Clock misc2 register *****************************************************/
+
+#define HT32_CRM_MISC2_AUTOSTEP_SHIFT   (4)
+#define HT32_CRM_MISC2_AUTOSTEP_MASK    (3 << HT32_CRM_MISC2_AUTOSTEP_SHIFT)
+#define HT32_CRM_MISC2_AUTOSTEP_ENABLE  (3 << HT32_CRM_MISC2_AUTOSTEP_SHIFT)
+#define HT32_CRM_MISC2_HICKDIV_SHIFT    (16)
+#define HT32_CRM_MISC2_HICKDIV_MASK     (7 << HT32_CRM_MISC2_HICKDIV_SHIFT)
+#  define HT32_CRM_MISC2_HICKDIV_1      (0 << HT32_CRM_MISC2_HICKDIV_SHIFT)
+#  define HT32_CRM_MISC2_HICKDIV_2      (1 << HT32_CRM_MISC2_HICKDIV_SHIFT)
+#  define HT32_CRM_MISC2_HICKDIV_4      (2 << HT32_CRM_MISC2_HICKDIV_SHIFT)
+#  define HT32_CRM_MISC2_HICKDIV_8      (3 << HT32_CRM_MISC2_HICKDIV_SHIFT)
+#  define HT32_CRM_MISC2_HICKDIV_16     (4 << HT32_CRM_MISC2_HICKDIV_SHIFT)
+
+/* Peripheral independent clocks register ***********************************/
+
+#define HT32_CRM_PICLKS_USART1SEL_SHIFT (0)
+#define HT32_CRM_PICLKS_USART1SEL_MASK  (3 << HT32_CRM_PICLKS_USART1SEL_SHIFT)
+#define HT32_CRM_PICLKS_USART2SEL_SHIFT (2)
+#define HT32_CRM_PICLKS_USART2SEL_MASK  (3 << HT32_CRM_PICLKS_USART2SEL_SHIFT)
+#define HT32_CRM_PICLKS_USART3SEL_SHIFT (4)
+#define HT32_CRM_PICLKS_USART3SEL_MASK  (3 << HT32_CRM_PICLKS_USART3SEL_SHIFT)
+
+#define HT32_CRM_PICLKS_USARTSEL_PCLK   0
+#define HT32_CRM_PICLKS_USARTSEL_SCLK   1
+#define HT32_CRM_PICLKS_USARTSEL_HICK   2
+#define HT32_CRM_PICLKS_USARTSEL_LEXT   3
+
+/* Peripheral reset registers ***********************************************/
+
+#define HT32_CRM_APB1RST_USART2RST      (1 << 17)
+#define HT32_CRM_APB1RST_USART3RST      (1 << 18)
+
+#define HT32_CRM_APB2RST_USART1RST      (1 << 4)
+
+/* Clock enable registers ***************************************************/
+
+#define HT32_CRM_AHBEN1_GPIOAEN         (1 << 0)
+#define HT32_CRM_AHBEN1_GPIOBEN         (1 << 1)
+#define HT32_CRM_AHBEN1_GPIOCEN         (1 << 2)
+#define HT32_CRM_AHBEN1_GPIODEN         (1 << 3)
+#define HT32_CRM_AHBEN1_GPIOEEN         (1 << 4)
+#define HT32_CRM_AHBEN1_GPIOFEN         (1 << 5)
+#define HT32_CRM_AHBEN1_CRCEN           (1 << 12)
+#define HT32_CRM_AHBEN1_DMA1EN          (1 << 22)
+#define HT32_CRM_AHBEN1_DMA2EN          (1 << 24)
+
+#define HT32_CRM_AHBEN2_OTGFS1EN        (1 << 7)
+
+#define HT32_CRM_AHBEN3_XMCEN           (1 << 0)
+
+#define HT32_CRM_APB1EN_TMR2EN          (1 << 0)
+#define HT32_CRM_APB1EN_TMR3EN          (1 << 1)
+#define HT32_CRM_APB1EN_TMR4EN          (1 << 2)
+#define HT32_CRM_APB1EN_TMR6EN          (1 << 4)
+#define HT32_CRM_APB1EN_TMR7EN          (1 << 5)
+#define HT32_CRM_APB1EN_TMR12EN         (1 << 6)
+#define HT32_CRM_APB1EN_TMR13EN         (1 << 7)
+#define HT32_CRM_APB1EN_TMR14EN         (1 << 8)
+#define HT32_CRM_APB1EN_WWDTEN          (1 << 11)
+#define HT32_CRM_APB1EN_SPI2EN          (1 << 14)
+#define HT32_CRM_APB1EN_SPI3EN          (1 << 15)
+#define HT32_CRM_APB1EN_USART2EN        (1 << 17)
+#define HT32_CRM_APB1EN_USART3EN        (1 << 18)
+#define HT32_CRM_APB1EN_USART4EN        (1 << 19)
+#define HT32_CRM_APB1EN_USART5EN        (1 << 20)
+#define HT32_CRM_APB1EN_I2C1EN          (1 << 21)
+#define HT32_CRM_APB1EN_I2C2EN          (1 << 22)
+#define HT32_CRM_APB1EN_I2C3EN          (1 << 23)
+#define HT32_CRM_APB1EN_CAN1EN          (1 << 25)
+#define HT32_CRM_APB1EN_CAN2EN          (1 << 26)
+#define HT32_CRM_APB1EN_PWCEN           (1 << 28)
+#define HT32_CRM_APB1EN_DACEN           (1 << 29)
+#define HT32_CRM_APB1EN_USART7EN        (1u << 30)
+#define HT32_CRM_APB1EN_USART8EN        (1u << 31)
+
+#define HT32_CRM_APB2EN_TMR1EN          (1 << 0)
+#define HT32_CRM_APB2EN_USART1EN        (1 << 4)
+#define HT32_CRM_APB2EN_USART6EN        (1 << 5)
+#define HT32_CRM_APB2EN_ADC1EN          (1 << 8)
+#define HT32_CRM_APB2EN_SPI1EN          (1 << 12)
+#define HT32_CRM_APB2EN_SCFGEN          (1 << 14)
+#define HT32_CRM_APB2EN_TMR9EN          (1 << 16)
+#define HT32_CRM_APB2EN_TMR10EN         (1 << 17)
+#define HT32_CRM_APB2EN_TMR11EN         (1 << 18)
+#define HT32_CRM_APB2EN_ACCEN           (1 << 29)
+
+#endif /* __ARCH_ARM_SRC_HT32F491X3_HARDWARE_HT32F491X3_CRM_H */
diff --git a/arch/arm/src/ht32f491x3/hardware/ht32f491x3_flash.h b/arch/arm/src/ht32f491x3/hardware/ht32f491x3_flash.h
new file mode 100644
index 00000000000..6cea92716b7
--- /dev/null
+++ b/arch/arm/src/ht32f491x3/hardware/ht32f491x3_flash.h
@@ -0,0 +1,50 @@
+/****************************************************************************
+ * arch/arm/src/ht32f491x3/hardware/ht32f491x3_flash.h
+ *
+ * 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.
+ *
+ ****************************************************************************/
+
+#ifndef __ARCH_ARM_SRC_HT32F491X3_HARDWARE_HT32F491X3_FLASH_H
+#define __ARCH_ARM_SRC_HT32F491X3_HARDWARE_HT32F491X3_FLASH_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include "ht32f491x3_memorymap.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define HT32_FLASH_PSR_OFFSET           0x000
+
+#define HT32_FLASH_PSR                  (HT32_FLASHREG_BASE + HT32_FLASH_PSR_OFFSET)
+
+#define HT32_FLASH_PSR_PROGRAM(wtcyc)   (0x150u | (wtcyc))
+
+#define HT32_FLASH_WAIT_CYCLE_0         0x00
+#define HT32_FLASH_WAIT_CYCLE_1         0x01
+#define HT32_FLASH_WAIT_CYCLE_2         0x02
+#define HT32_FLASH_WAIT_CYCLE_3         0x03
+#define HT32_FLASH_WAIT_CYCLE_4         0x04
+
+#endif /* __ARCH_ARM_SRC_HT32F491X3_HARDWARE_HT32F491X3_FLASH_H */
diff --git a/arch/arm/src/ht32f491x3/hardware/ht32f491x3_gpio.h b/arch/arm/src/ht32f491x3/hardware/ht32f491x3_gpio.h
new file mode 100644
index 00000000000..451c4667269
--- /dev/null
+++ b/arch/arm/src/ht32f491x3/hardware/ht32f491x3_gpio.h
@@ -0,0 +1,83 @@
+/****************************************************************************
+ * arch/arm/src/ht32f491x3/hardware/ht32f491x3_gpio.h
+ *
+ * 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.
+ *
+ ****************************************************************************/
+
+#ifndef __ARCH_ARM_SRC_HT32F491X3_HARDWARE_HT32F491X3_GPIO_H
+#define __ARCH_ARM_SRC_HT32F491X3_HARDWARE_HT32F491X3_GPIO_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <stdint.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* GPIO register offsets ****************************************************/
+
+#define HT32_GPIO_CFGR_OFFSET          0x0000
+#define HT32_GPIO_OMODE_OFFSET         0x0004
+#define HT32_GPIO_ODRVR_OFFSET         0x0008
+#define HT32_GPIO_PULL_OFFSET          0x000c
+#define HT32_GPIO_IDT_OFFSET           0x0010
+#define HT32_GPIO_ODT_OFFSET           0x0014
+#define HT32_GPIO_SCR_OFFSET           0x0018
+#define HT32_GPIO_WPR_OFFSET           0x001c
+#define HT32_GPIO_MUXL_OFFSET          0x0020
+#define HT32_GPIO_MUXH_OFFSET          0x0024
+#define HT32_GPIO_CLR_OFFSET           0x0028
+
+/* GPIO helpers *************************************************************/
+
+#define HT32_GPIO_PIN(n)               (1u << (n))
+
+#define HT32_GPIO_MODE_SHIFT(n)        ((n) << 1)
+#define HT32_GPIO_MODE_MASK(n)         (3u << HT32_GPIO_MODE_SHIFT(n))
+#define HT32_GPIO_MODE_VALUE(n, v)     ((uint32_t)(v) << HT32_GPIO_MODE_SHIFT(n))
+
+#define HT32_GPIO_ODRVR_SHIFT(n)       ((n) << 1)
+#define HT32_GPIO_ODRVR_MASK(n)        (3u << HT32_GPIO_ODRVR_SHIFT(n))
+#define HT32_GPIO_ODRVR_VALUE(n, v)    ((uint32_t)(v) << HT32_GPIO_ODRVR_SHIFT(n))
+
+#define HT32_GPIO_PULL_SHIFT(n)        ((n) << 1)
+#define HT32_GPIO_PULL_MASK(n)         (3u << HT32_GPIO_PULL_SHIFT(n))
+#define HT32_GPIO_PULL_VALUE(n, v)     ((uint32_t)(v) << HT32_GPIO_PULL_SHIFT(n))
+
+#define HT32_GPIO_MUX_SHIFT(n)         (((n) & 7u) << 2)
+#define HT32_GPIO_MUX_MASK(n)          (0x0fu << HT32_GPIO_MUX_SHIFT(n))
+#define HT32_GPIO_MUX_VALUE(n, af)     ((uint32_t)(af) << HT32_GPIO_MUX_SHIFT(n))
+#define HT32_GPIO_MUX_OFFSET(n)        (((n) < 8u) ? HT32_GPIO_MUXL_OFFSET : \
+                                        HT32_GPIO_MUXH_OFFSET)
+
+/* Compatibility aliases for board pinmux code that still uses the older
+ * CFGLR/CFGHR naming for alternate-function selection.
+ */
+
+#define HT32_GPIO_CFGLR_OFFSET         HT32_GPIO_MUXL_OFFSET
+#define HT32_GPIO_CFGHR_OFFSET         HT32_GPIO_MUXH_OFFSET
+#define HT32_GPIO_CFG_SHIFT(n)         HT32_GPIO_MUX_SHIFT(n)
+#define HT32_GPIO_CFG_MASK(n)          HT32_GPIO_MUX_MASK(n)
+#define HT32_GPIO_CFG_VALUE(n, af)     HT32_GPIO_MUX_VALUE(n, af)
+#define HT32_GPIO_CFG_OFFSET(n)        HT32_GPIO_MUX_OFFSET(n)
+
+#endif /* __ARCH_ARM_SRC_HT32F491X3_HARDWARE_HT32F491X3_GPIO_H */
diff --git a/arch/arm/src/ht32f491x3/hardware/ht32f491x3_memorymap.h b/arch/arm/src/ht32f491x3/hardware/ht32f491x3_memorymap.h
new file mode 100644
index 00000000000..fbe0c1228f3
--- /dev/null
+++ b/arch/arm/src/ht32f491x3/hardware/ht32f491x3_memorymap.h
@@ -0,0 +1,127 @@
+/****************************************************************************
+ * arch/arm/src/ht32f491x3/hardware/ht32f491x3_memorymap.h
+ *
+ * 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.
+ *
+ ****************************************************************************/
+
+#ifndef __ARCH_ARM_SRC_HT32F491X3_HARDWARE_HT32F491X3_MEMORYMAP_H
+#define __ARCH_ARM_SRC_HT32F491X3_HARDWARE_HT32F491X3_MEMORYMAP_H
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Address blocks ***********************************************************/
+
+#define HT32_CODE_BASE        0x00000000
+#define HT32_SRAM_BASE        0x20000000
+#define HT32_PERIPH_BASE      0x40000000
+#define HT32_XMC_MEM_BASE     0x60000000
+#define HT32_XMC_BANK1        HT32_XMC_MEM_BASE
+#define HT32_XMC_REG_BASE     0xa0000000
+#define HT32_CORTEX_BASE      0xe0000000
+
+/* Code region **************************************************************/
+
+#define HT32_BOOT_BASE        0x00000000
+#define HT32_FLASH_BASE       0x08000000
+#define HT32_FLASHREG_BASE    0x40023c00
+#define HT32_SYSMEM_BASE      0x1fffa400
+#define HT32_USERDATA_BASE    0x1ffff800
+
+/* SRAM region **************************************************************/
+
+#define HT32_SRAMBB_BASE      0x22000000
+
+/* Peripheral region ********************************************************/
+
+#define HT32_APB1_BASE        0x40000000
+#define HT32_APB2_BASE        0x40010000
+#define HT32_AHB1_BASE        0x40020000
+#define HT32_AHB2_BASE        0x50000000
+
+/* APB1 */
+
+#define HT32_TMR2_BASE        0x40000000
+#define HT32_TMR3_BASE        0x40000400
+#define HT32_TMR4_BASE        0x40000800
+#define HT32_TMR6_BASE        0x40001000
+#define HT32_TMR7_BASE        0x40001400
+#define HT32_TMR12_BASE       0x40001800
+#define HT32_TMR13_BASE       0x40001c00
+#define HT32_TMR14_BASE       0x40002000
+#define HT32_ERTC_BASE        0x40002800
+#define HT32_WWDT_BASE        0x40002c00
+#define HT32_WDT_BASE         0x40003000
+#define HT32_SPI2_BASE        0x40003800
+#define HT32_SPI3_BASE        0x40003c00
+#define HT32_USART2_BASE      0x40004400
+#define HT32_USART3_BASE      0x40004800
+#define HT32_USART4_BASE      0x40004c00
+#define HT32_USART5_BASE      0x40005000
+#define HT32_I2C1_BASE        0x40005400
+#define HT32_I2C2_BASE        0x40005800
+#define HT32_I2C3_BASE        0x40005c00
+#define HT32_CAN1_BASE        0x40006400
+#define HT32_CAN2_BASE        0x40006800
+#define HT32_PWC_BASE         0x40007000
+#define HT32_DAC_BASE         0x40007400
+#define HT32_USART7_BASE      0x40007800
+#define HT32_USART8_BASE      0x40007c00
+
+/* APB2 */
+
+#define HT32_TMR1_BASE        0x40010000
+#define HT32_USART1_BASE      0x40011000
+#define HT32_USART6_BASE      0x40011400
+#define HT32_ADC1_BASE        0x40012000
+#define HT32_ADC_BASE         HT32_ADC1_BASE
+#define HT32_ADCCOM_BASE      0x40012300
+#define HT32_SPI1_BASE        0x40013000
+#define HT32_SCFG_BASE        0x40013800
+#define HT32_EXINT_BASE       0x40013c00
+#define HT32_TMR9_BASE        0x40014000
+#define HT32_TMR10_BASE       0x40014400
+#define HT32_TMR11_BASE       0x40014800
+#define HT32_ACC_BASE         0x40017400
+
+/* AHB1 */
+
+#define HT32_GPIOA_BASE       0x40020000
+#define HT32_GPIOB_BASE       0x40020400
+#define HT32_GPIOC_BASE       0x40020800
+#define HT32_GPIOD_BASE       0x40020c00
+#define HT32_GPIOE_BASE       0x40021000
+#define HT32_GPIOF_BASE       0x40021400
+#define HT32_CRC_BASE         0x40023000
+#define HT32_CRM_BASE         0x40023800
+#define HT32_FLASHIF_BASE     0x40023c00
+#define HT32_DMA1_BASE        0x40026000
+#define HT32_DMA2_BASE        0x40026400
+
+/* AHB2 */
+
+#define HT32_OTGFS1_BASE      0x50000000
+#define HT32_OTGFS_BASE       HT32_OTGFS1_BASE
+
+/* Cortex-M4 system control space *******************************************/
+
+#define HT32_SCS_BASE         0xe000e000
+
+#endif /* __ARCH_ARM_SRC_HT32F491X3_HARDWARE_HT32F491X3_MEMORYMAP_H */
diff --git a/arch/arm/src/ht32f491x3/hardware/ht32f491x3_pwc.h b/arch/arm/src/ht32f491x3/hardware/ht32f491x3_pwc.h
new file mode 100644
index 00000000000..94f80da4945
--- /dev/null
+++ b/arch/arm/src/ht32f491x3/hardware/ht32f491x3_pwc.h
@@ -0,0 +1,48 @@
+/****************************************************************************
+ * arch/arm/src/ht32f491x3/hardware/ht32f491x3_pwc.h
+ *
+ * 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.
+ *
+ ****************************************************************************/
+
+#ifndef __ARCH_ARM_SRC_HT32F491X3_HARDWARE_HT32F491X3_PWC_H
+#define __ARCH_ARM_SRC_HT32F491X3_HARDWARE_HT32F491X3_PWC_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include "ht32f491x3_memorymap.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define HT32_PWC_LDOOV_OFFSET           0x010
+
+#define HT32_PWC_LDOOV                  (HT32_PWC_BASE + HT32_PWC_LDOOV_OFFSET)
+
+#define HT32_PWC_LDOOVSEL_SHIFT         0
+#define HT32_PWC_LDOOVSEL_MASK          (3 << HT32_PWC_LDOOVSEL_SHIFT)
+#define HT32_PWC_LDO_OUTPUT_1V1         (1 << HT32_PWC_LDOOVSEL_SHIFT)
+#define HT32_PWC_LDO_OUTPUT_1V2         (2 << HT32_PWC_LDOOVSEL_SHIFT)
+#define HT32_PWC_LDO_OUTPUT_1V3         (3 << HT32_PWC_LDOOVSEL_SHIFT)
+
+#endif /* __ARCH_ARM_SRC_HT32F491X3_HARDWARE_HT32F491X3_PWC_H */
diff --git a/arch/arm/src/ht32f491x3/hardware/ht32f491x3_uart.h b/arch/arm/src/ht32f491x3/hardware/ht32f491x3_uart.h
new file mode 100644
index 00000000000..3d059206c2a
--- /dev/null
+++ b/arch/arm/src/ht32f491x3/hardware/ht32f491x3_uart.h
@@ -0,0 +1,147 @@
+/****************************************************************************
+ * arch/arm/src/ht32f491x3/hardware/ht32f491x3_uart.h
+ *
+ * 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.
+ *
+ ****************************************************************************/
+
+#ifndef __ARCH_ARM_SRC_HT32F491X3_HARDWARE_HT32F491X3_UART_H
+#define __ARCH_ARM_SRC_HT32F491X3_HARDWARE_HT32F491X3_UART_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include "chip.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Register Offsets *********************************************************/
+
+#define HT32_USART_STS_OFFSET            0x00
+#define HT32_USART_DT_OFFSET             0x04
+#define HT32_USART_BAUDR_OFFSET          0x08
+#define HT32_USART_CTRL1_OFFSET          0x0c
+#define HT32_USART_CTRL2_OFFSET          0x10
+#define HT32_USART_CTRL3_OFFSET          0x14
+#define HT32_USART_GDIV_OFFSET           0x18
+#define HT32_USART_RTOR_OFFSET           0x1c
+#define HT32_USART_IFC_OFFSET            0x20
+
+/* Register Addresses *******************************************************/
+
+#define HT32_USART1_STS                  (HT32_USART1_BASE + HT32_USART_STS_OFFSET)
+#define HT32_USART1_DT                   (HT32_USART1_BASE + HT32_USART_DT_OFFSET)
+#define HT32_USART1_BAUDR                (HT32_USART1_BASE + HT32_USART_BAUDR_OFFSET)
+#define HT32_USART1_CTRL1                (HT32_USART1_BASE + HT32_USART_CTRL1_OFFSET)
+#define HT32_USART1_CTRL2                (HT32_USART1_BASE + HT32_USART_CTRL2_OFFSET)
+#define HT32_USART1_CTRL3                (HT32_USART1_BASE + HT32_USART_CTRL3_OFFSET)
+
+#define HT32_USART2_STS                  (HT32_USART2_BASE + HT32_USART_STS_OFFSET)
+#define HT32_USART2_DT                   (HT32_USART2_BASE + HT32_USART_DT_OFFSET)
+#define HT32_USART2_BAUDR                (HT32_USART2_BASE + HT32_USART_BAUDR_OFFSET)
+#define HT32_USART2_CTRL1                (HT32_USART2_BASE + HT32_USART_CTRL1_OFFSET)
+#define HT32_USART2_CTRL2                (HT32_USART2_BASE + HT32_USART_CTRL2_OFFSET)
+#define HT32_USART2_CTRL3                (HT32_USART2_BASE + HT32_USART_CTRL3_OFFSET)
+
+#define HT32_USART3_STS                  (HT32_USART3_BASE + HT32_USART_STS_OFFSET)
+#define HT32_USART3_DT                   (HT32_USART3_BASE + HT32_USART_DT_OFFSET)
+#define HT32_USART3_BAUDR                (HT32_USART3_BASE + HT32_USART_BAUDR_OFFSET)
+#define HT32_USART3_CTRL1                (HT32_USART3_BASE + HT32_USART_CTRL1_OFFSET)
+#define HT32_USART3_CTRL2                (HT32_USART3_BASE + HT32_USART_CTRL2_OFFSET)
+#define HT32_USART3_CTRL3                (HT32_USART3_BASE + HT32_USART_CTRL3_OFFSET)
+
+/* Status register **********************************************************/
+
+#define HT32_USART_STS_PERR              (1 << 0)
+#define HT32_USART_STS_FERR              (1 << 1)
+#define HT32_USART_STS_NERR              (1 << 2)
+#define HT32_USART_STS_ROERR             (1 << 3)
+#define HT32_USART_STS_IDLEF             (1 << 4)
+#define HT32_USART_STS_RDBF              (1 << 5)
+#define HT32_USART_STS_TDC               (1 << 6)
+#define HT32_USART_STS_TDBE              (1 << 7)
+#define HT32_USART_STS_BFF               (1 << 8)
+#define HT32_USART_STS_CTSCF             (1 << 9)
+#define HT32_USART_STS_LPWUF             (1 << 20)
+#define HT32_USART_STS_TXON              (1 << 21)
+#define HT32_USART_STS_RXON              (1 << 22)
+
+/* Data register ************************************************************/
+
+#define HT32_USART_DT_SHIFT              (0)
+#define HT32_USART_DT_MASK               (0x1ff << HT32_USART_DT_SHIFT)
+
+/* Baud rate register *******************************************************/
+
+#define HT32_USART_BAUDR_DIV_SHIFT       (0)
+#define HT32_USART_BAUDR_DIV_MASK        (0xffff << HT32_USART_BAUDR_DIV_SHIFT)
+
+/* Control register 1 *******************************************************/
+
+#define HT32_USART_CTRL1_SBF             (1 << 0)
+#define HT32_USART_CTRL1_RM              (1 << 1)
+#define HT32_USART_CTRL1_REN             (1 << 2)
+#define HT32_USART_CTRL1_TEN             (1 << 3)
+#define HT32_USART_CTRL1_IDLEIEN         (1 << 4)
+#define HT32_USART_CTRL1_RDBFIEN         (1 << 5)
+#define HT32_USART_CTRL1_TDCIEN          (1 << 6)
+#define HT32_USART_CTRL1_TDBEIEN         (1 << 7)
+#define HT32_USART_CTRL1_PERRIEN         (1 << 8)
+#define HT32_USART_CTRL1_PSEL            (1 << 9)
+#define HT32_USART_CTRL1_PEN             (1 << 10)
+#define HT32_USART_CTRL1_WUM             (1 << 11)
+#define HT32_USART_CTRL1_DBN0            (1 << 12)
+#define HT32_USART_CTRL1_UEN             (1 << 13)
+#define HT32_USART_CTRL1_DBN1            (1 << 28)
+
+/* Control register 2 *******************************************************/
+
+#define HT32_USART_CTRL2_BFIEN           (1 << 6)
+#define HT32_USART_CTRL2_LBCP            (1 << 8)
+#define HT32_USART_CTRL2_CLKPHA          (1 << 9)
+#define HT32_USART_CTRL2_CLKPOL          (1 << 10)
+#define HT32_USART_CTRL2_CLKEN           (1 << 11)
+#define HT32_USART_CTRL2_STOPBN_SHIFT    (12)
+#define HT32_USART_CTRL2_STOPBN_MASK     (3 << HT32_USART_CTRL2_STOPBN_SHIFT)
+#define HT32_USART_CTRL2_STOPBN_10       (0 << HT32_USART_CTRL2_STOPBN_SHIFT)
+#define HT32_USART_CTRL2_STOPBN_05       (1 << HT32_USART_CTRL2_STOPBN_SHIFT)
+#define HT32_USART_CTRL2_STOPBN_20       (2 << HT32_USART_CTRL2_STOPBN_SHIFT)
+#define HT32_USART_CTRL2_STOPBN_15       (3 << HT32_USART_CTRL2_STOPBN_SHIFT)
+
+/* Control register 3 *******************************************************/
+
+#define HT32_USART_CTRL3_ERRIEN          (1 << 0)
+#define HT32_USART_CTRL3_DMAREN          (1 << 6)
+#define HT32_USART_CTRL3_DMATEN          (1 << 7)
+#define HT32_USART_CTRL3_RTSEN           (1 << 8)
+#define HT32_USART_CTRL3_CTSEN           (1 << 9)
+#define HT32_USART_CTRL3_CTSCFIEN        (1 << 10)
+#define HT32_USART_CTRL3_RS485EN         (1 << 14)
+#define HT32_USART_CTRL3_DEP             (1 << 15)
+
+/* Convenience aliases ******************************************************/
+
+#define HT32_USART_RDR_OFFSET            HT32_USART_DT_OFFSET
+#define HT32_USART_TDR_OFFSET            HT32_USART_DT_OFFSET
+
+#endif /* __ARCH_ARM_SRC_HT32F491X3_HARDWARE_HT32F491X3_UART_H */
diff --git a/arch/arm/src/ht32f491x3/ht32f491x3_config.h b/arch/arm/src/ht32f491x3/ht32f491x3_config.h
new file mode 100644
index 00000000000..459d4d29bc8
--- /dev/null
+++ b/arch/arm/src/ht32f491x3/ht32f491x3_config.h
@@ -0,0 +1,53 @@
+/****************************************************************************
+ * arch/arm/src/ht32f491x3/ht32f491x3_config.h
+ *
+ * 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.
+ *
+ ****************************************************************************/
+
+#ifndef __ARCH_ARM_SRC_HT32F491X3_HT32F491X3_CONFIG_H
+#define __ARCH_ARM_SRC_HT32F491X3_HT32F491X3_CONFIG_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#undef HAVE_UART
+#if defined(CONFIG_HT32F491X3_USART1_SERIALDRIVER) || \
+    defined(CONFIG_HT32F491X3_USART2_SERIALDRIVER) || \
+    defined(CONFIG_HT32F491X3_USART3_SERIALDRIVER)
+#  define HAVE_UART 1
+#endif
+
+#undef HAVE_CONSOLE
+#if (defined(CONFIG_USART1_SERIAL_CONSOLE) && \
+     defined(CONFIG_HT32F491X3_USART1_SERIALDRIVER)) || \
+    (defined(CONFIG_USART2_SERIAL_CONSOLE) && \
+     defined(CONFIG_HT32F491X3_USART2_SERIALDRIVER)) || \
+    (defined(CONFIG_USART3_SERIAL_CONSOLE) && \
+     defined(CONFIG_HT32F491X3_USART3_SERIALDRIVER))
+#  define HAVE_CONSOLE 1
+#endif
+
+#endif /* __ARCH_ARM_SRC_HT32F491X3_HT32F491X3_CONFIG_H */
diff --git a/arch/arm/src/ht32f491x3/ht32f491x3_gpio.c b/arch/arm/src/ht32f491x3/ht32f491x3_gpio.c
new file mode 100644
index 00000000000..92d3def504d
--- /dev/null
+++ b/arch/arm/src/ht32f491x3/ht32f491x3_gpio.c
@@ -0,0 +1,78 @@
+/****************************************************************************
+ * arch/arm/src/ht32f491x3/ht32f491x3_gpio.c
+ *
+ * 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.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "arm_internal.h"
+
+#include "ht32f491x3_gpio.h"
+
+#include "hardware/ht32f491x3_gpio.h"
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+void ht32f491x3_gpioconfig(uintptr_t base, unsigned int pin,
+                           unsigned int mode, bool opendrain,
+                           unsigned int drive, unsigned int pull,
+                           unsigned int af)
+{
+  modifyreg32(base + HT32_GPIO_CFGR_OFFSET,
+              HT32_GPIO_MODE_MASK(pin),
+              HT32_GPIO_MODE_VALUE(pin, mode));
+
+  modifyreg32(base + HT32_GPIO_OMODE_OFFSET,
+              HT32_GPIO_PIN(pin),
+              opendrain ? HT32_GPIO_PIN(pin) : 0);
+
+  modifyreg32(base + HT32_GPIO_ODRVR_OFFSET,
+              HT32_GPIO_ODRVR_MASK(pin),
+              HT32_GPIO_ODRVR_VALUE(pin, drive));
+
+  modifyreg32(base + HT32_GPIO_PULL_OFFSET,
+              HT32_GPIO_PULL_MASK(pin),
+              HT32_GPIO_PULL_VALUE(pin, pull));
+
+  modifyreg32(base + HT32_GPIO_MUX_OFFSET(pin),
+              HT32_GPIO_MUX_MASK(pin),
+              mode == HT32_GPIO_MODE_ALTFN ?
+              HT32_GPIO_MUX_VALUE(pin, af) : 0);
+}
+
+void ht32f491x3_gpiowrite(uintptr_t base, unsigned int pin, bool value)
+{
+  putreg32(HT32_GPIO_PIN(pin),
+           base + (value ? HT32_GPIO_SCR_OFFSET : HT32_GPIO_CLR_OFFSET));
+}
+
+bool ht32f491x3_gpioread(uintptr_t base, unsigned int pin)
+{
+  return (getreg32(base + HT32_GPIO_IDT_OFFSET) & HT32_GPIO_PIN(pin)) != 0;
+}
diff --git a/arch/arm/src/ht32f491x3/ht32f491x3_gpio.h b/arch/arm/src/ht32f491x3/ht32f491x3_gpio.h
new file mode 100644
index 00000000000..aae7b3ecf72
--- /dev/null
+++ b/arch/arm/src/ht32f491x3/ht32f491x3_gpio.h
@@ -0,0 +1,63 @@
+/****************************************************************************
+ * arch/arm/src/ht32f491x3/ht32f491x3_gpio.h
+ *
+ * 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.
+ *
+ ****************************************************************************/
+
+#ifndef __ARCH_ARM_SRC_HT32F491X3_HT32F491X3_GPIO_H
+#define __ARCH_ARM_SRC_HT32F491X3_HT32F491X3_GPIO_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdbool.h>
+#include <stdint.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define HT32_GPIO_MODE_INPUT           0u
+#define HT32_GPIO_MODE_OUTPUT          1u
+#define HT32_GPIO_MODE_ALTFN           2u
+#define HT32_GPIO_MODE_ANALOG          3u
+
+#define HT32_GPIO_DRIVE_LOW            0u
+#define HT32_GPIO_DRIVE_MEDIUM         1u
+#define HT32_GPIO_DRIVE_HIGH           2u
+
+#define HT32_GPIO_PULL_NONE            0u
+#define HT32_GPIO_PULL_UP              1u
+#define HT32_GPIO_PULL_DOWN            2u
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+void ht32f491x3_gpioconfig(uintptr_t base, unsigned int pin,
+                           unsigned int mode, bool opendrain,
+                           unsigned int drive, unsigned int pull,
+                           unsigned int af);
+void ht32f491x3_gpiowrite(uintptr_t base, unsigned int pin, bool value);
+bool ht32f491x3_gpioread(uintptr_t base, unsigned int pin);
+
+#endif /* __ARCH_ARM_SRC_HT32F491X3_HT32F491X3_GPIO_H */
diff --git a/arch/arm/src/ht32f491x3/ht32f491x3_irq.c b/arch/arm/src/ht32f491x3/ht32f491x3_irq.c
new file mode 100644
index 00000000000..49f45c0f104
--- /dev/null
+++ b/arch/arm/src/ht32f491x3/ht32f491x3_irq.c
@@ -0,0 +1,310 @@
+/****************************************************************************
+ * arch/arm/src/ht32f491x3/ht32f491x3_irq.c
+ *
+ * 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.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <assert.h>
+#include <debug.h>
+#include <errno.h>
+#include <stdint.h>
+
+#include <nuttx/arch.h>
+#include <nuttx/irq.h>
+#include <arch/irq.h>
+#include <arch/armv7-m/nvicpri.h>
+
+#include "nvic.h"
+#ifdef CONFIG_ARCH_RAMVECTORS
+#  include "ram_vectors.h"
+#endif
+#include "arm_internal.h"
+#include "chip.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define DEFPRIORITY32 \
+  (NVIC_SYSH_PRIORITY_DEFAULT << 24 | \
+   NVIC_SYSH_PRIORITY_DEFAULT << 16 | \
+   NVIC_SYSH_PRIORITY_DEFAULT << 8  | \
+   NVIC_SYSH_PRIORITY_DEFAULT)
+
+#define NVIC_ENA_OFFSET    (0)
+#define NVIC_CLRENA_OFFSET (NVIC_IRQ0_31_CLEAR - NVIC_IRQ0_31_ENABLE)
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+#ifdef CONFIG_DEBUG_FEATURES
+static int ht32_nmi(int irq, FAR void *context, FAR void *arg)
+{
+  UNUSED(irq);
+  UNUSED(context);
+  UNUSED(arg);
+
+  up_irq_save();
+  _err("PANIC!!! NMI received\n");
+  PANIC();
+  return 0;
+}
+
+static int ht32_pendsv(int irq, FAR void *context, FAR void *arg)
+{
+  UNUSED(irq);
+  UNUSED(context);
+  UNUSED(arg);
+
+  up_irq_save();
+  _err("PANIC!!! PendSV received\n");
+  PANIC();
+  return 0;
+}
+
+static int ht32_dbgmonitor(int irq, FAR void *context, FAR void *arg)
+{
+  UNUSED(irq);
+  UNUSED(context);
+  UNUSED(arg);
+
+  up_irq_save();
+  _err("PANIC!!! Debug Monitor received\n");
+  PANIC();
+  return 0;
+}
+
+static int ht32_reserved(int irq, FAR void *context, FAR void *arg)
+{
+  UNUSED(irq);
+  UNUSED(context);
+  UNUSED(arg);
+
+  up_irq_save();
+  _err("PANIC!!! Reserved interrupt\n");
+  PANIC();
+  return 0;
+}
+#endif
+
+static inline void ht32_prioritize_syscall(int priority)
+{
+  uint32_t regval;
+
+  regval  = getreg32(NVIC_SYSH8_11_PRIORITY);
+  regval &= ~NVIC_SYSH_PRIORITY_PR11_MASK;
+  regval |= (priority << NVIC_SYSH_PRIORITY_PR11_SHIFT);
+  putreg32(regval, NVIC_SYSH8_11_PRIORITY);
+}
+
+static int ht32_irqinfo(int irq, uintptr_t *regaddr, uint32_t *bit,
+                        uintptr_t offset)
+{
+  int n;
+
+  DEBUGASSERT(irq >= HT32_IRQ_NMI && irq < NR_IRQS);
+
+  if (irq >= HT32_IRQ_FIRST)
+    {
+      n        = irq - HT32_IRQ_FIRST;
+      *regaddr = NVIC_IRQ_ENABLE(n) + offset;
+      *bit     = (uint32_t)1 << (n & 0x1f);
+    }
+  else
+    {
+      *regaddr = NVIC_SYSHCON;
+      if (irq == HT32_IRQ_MEMFAULT)
+        {
+          *bit = NVIC_SYSHCON_MEMFAULTENA;
+        }
+      else if (irq == HT32_IRQ_BUSFAULT)
+        {
+          *bit = NVIC_SYSHCON_BUSFAULTENA;
+        }
+      else if (irq == HT32_IRQ_USAGEFAULT)
+        {
+          *bit = NVIC_SYSHCON_USGFAULTENA;
+        }
+      else if (irq == HT32_IRQ_SYSTICK)
+        {
+          *regaddr = NVIC_SYSTICK_CTRL;
+          *bit = NVIC_SYSTICK_CTRL_ENABLE;
+        }
+      else
+        {
+          return -EINVAL;
+        }
+    }
+
+  return 0;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+void up_irqinitialize(void)
+{
+  uint32_t regaddr;
+  int num_priority_registers;
+  int i;
+
+  for (i = 0; i < NR_IRQS - HT32_IRQ_FIRST; i += 32)
+    {
+      putreg32(0xffffffff, NVIC_IRQ_CLEAR(i));
+    }
+
+#if defined(__ICCARM__)
+  putreg32((uint32_t)__vector_table, NVIC_VECTAB);
+#else
+  putreg32((uint32_t)_vectors, NVIC_VECTAB);
+#endif
+
+#ifdef CONFIG_ARCH_RAMVECTORS
+  arm_ramvec_initialize();
+#endif
+
+  putreg32(DEFPRIORITY32, NVIC_SYSH4_7_PRIORITY);
+  putreg32(DEFPRIORITY32, NVIC_SYSH8_11_PRIORITY);
+  putreg32(DEFPRIORITY32, NVIC_SYSH12_15_PRIORITY);
+
+  num_priority_registers = (getreg32(NVIC_ICTR) + 1) * 8;
+  regaddr = NVIC_IRQ0_3_PRIORITY;
+
+  while (num_priority_registers-- > 0)
+    {
+      putreg32(DEFPRIORITY32, regaddr);
+      regaddr += 4;
+    }
+
+  irq_attach(HT32_IRQ_SVCALL, arm_svcall, NULL);
+  irq_attach(HT32_IRQ_HARDFAULT, arm_hardfault, NULL);
+  ht32_prioritize_syscall(NVIC_SYSH_SVCALL_PRIORITY);
+
+#ifdef CONFIG_ARM_MPU
+  irq_attach(HT32_IRQ_MEMFAULT, arm_memfault, NULL);
+  up_enable_irq(HT32_IRQ_MEMFAULT);
+#endif
+
+#ifdef CONFIG_DEBUG_FEATURES
+  irq_attach(HT32_IRQ_NMI, ht32_nmi, NULL);
+#ifndef CONFIG_ARM_MPU
+  irq_attach(HT32_IRQ_MEMFAULT, arm_memfault, NULL);
+#endif
+  irq_attach(HT32_IRQ_BUSFAULT, arm_busfault, NULL);
+  irq_attach(HT32_IRQ_USAGEFAULT, arm_usagefault, NULL);
+  irq_attach(HT32_IRQ_PENDSV, ht32_pendsv, NULL);
+  irq_attach(HT32_IRQ_DBGMONITOR, ht32_dbgmonitor, NULL);
+  irq_attach(HT32_IRQ_RESERVED, ht32_reserved, NULL);
+#endif
+
+#ifndef CONFIG_SUPPRESS_INTERRUPTS
+  arm_color_intstack();
+  up_irq_enable();
+#endif
+}
+
+void up_disable_irq(int irq)
+{
+  uintptr_t regaddr;
+  uint32_t regval;
+  uint32_t bit;
+
+  if (ht32_irqinfo(irq, &regaddr, &bit, NVIC_CLRENA_OFFSET) < 0)
+    {
+      return;
+    }
+
+  if (irq >= HT32_IRQ_FIRST)
+    {
+      putreg32(bit, regaddr);
+    }
+  else
+    {
+      regval  = getreg32(regaddr);
+      regval &= ~bit;
+      putreg32(regval, regaddr);
+    }
+}
+
+void up_enable_irq(int irq)
+{
+  uintptr_t regaddr;
+  uint32_t regval;
+  uint32_t bit;
+
+  if (ht32_irqinfo(irq, &regaddr, &bit, NVIC_ENA_OFFSET) < 0)
+    {
+      return;
+    }
+
+  if (irq >= HT32_IRQ_FIRST)
+    {
+      putreg32(bit, regaddr);
+    }
+  else
+    {
+      regval  = getreg32(regaddr);
+      regval |= bit;
+      putreg32(regval, regaddr);
+    }
+}
+
+void arm_ack_irq(int irq)
+{
+  UNUSED(irq);
+}
+
+#ifdef CONFIG_ARCH_IRQPRIO
+int up_prioritize_irq(int irq, int priority)
+{
+  uint32_t regaddr;
+  uint32_t regval;
+  int shift;
+
+  DEBUGASSERT(irq >= HT32_IRQ_MEMFAULT && irq < NR_IRQS &&
+              (unsigned)priority <= NVIC_SYSH_PRIORITY_MIN);
+
+  if (irq < HT32_IRQ_FIRST)
+    {
+      regaddr = NVIC_SYSH_PRIORITY(irq);
+      irq    -= 4;
+    }
+  else
+    {
+      irq    -= HT32_IRQ_FIRST;
+      regaddr = NVIC_IRQ_PRIORITY(irq);
+    }
+
+  regval      = getreg32(regaddr);
+  shift       = ((irq & 3) << 3);
+  regval     &= ~(0xff << shift);
+  regval     |= ((uint32_t)priority << shift);
+  putreg32(regval, regaddr);
+
+  return 0;
+}
+#endif
diff --git a/arch/arm/src/ht32f491x3/ht32f491x3_lowputc.c b/arch/arm/src/ht32f491x3/ht32f491x3_lowputc.c
new file mode 100644
index 00000000000..c22c40ae9d2
--- /dev/null
+++ b/arch/arm/src/ht32f491x3/ht32f491x3_lowputc.c
@@ -0,0 +1,287 @@
+/****************************************************************************
+ * arch/arm/src/ht32f491x3/ht32f491x3_lowputc.c
+ *
+ * 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.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <nuttx/compiler.h>
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include <arch/board/board.h>
+
+#include "arm_internal.h"
+#include "chip.h"
+
+#include "ht32f491x3_config.h"
+#include "ht32f491x3_gpio.h"
+#include "ht32f491x3_lowputc.h"
+#include "ht32f491x3_serial.h"
+
+#include "hardware/ht32f491x3_crm.h"
+#include "hardware/ht32f491x3_gpio.h"
+#include "hardware/ht32f491x3_uart.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#ifdef HAVE_CONSOLE
+#  if defined(CONFIG_USART1_SERIAL_CONSOLE) && \
+      defined(CONFIG_HT32F491X3_USART1_SERIALDRIVER)
+#    define HT32_CONSOLE_BASE      HT32_USART1_BASE
+#    define HT32_CONSOLE_APBREG    HT32_CRM_APB2EN
+#    define HT32_CONSOLE_APBEN     HT32_CRM_APB2EN_USART1EN
+#    define HT32_CONSOLE_CLOCK     HT32_PCLK2_FREQUENCY
+#    define HT32_CONSOLE_BAUD      CONFIG_USART1_BAUD
+#    define HT32_CONSOLE_BITS      CONFIG_USART1_BITS
+#    define HT32_CONSOLE_PARITY    CONFIG_USART1_PARITY
+#    define HT32_CONSOLE_2STOP     CONFIG_USART1_2STOP
+#  elif defined(CONFIG_USART2_SERIAL_CONSOLE) && \
+        defined(CONFIG_HT32F491X3_USART2_SERIALDRIVER)
+#    define HT32_CONSOLE_BASE      HT32_USART2_BASE
+#    define HT32_CONSOLE_APBREG    HT32_CRM_APB1EN
+#    define HT32_CONSOLE_APBEN     HT32_CRM_APB1EN_USART2EN
+#    define HT32_CONSOLE_CLOCK     HT32_PCLK1_FREQUENCY
+#    define HT32_CONSOLE_BAUD      CONFIG_USART2_BAUD
+#    define HT32_CONSOLE_BITS      CONFIG_USART2_BITS
+#    define HT32_CONSOLE_PARITY    CONFIG_USART2_PARITY
+#    define HT32_CONSOLE_2STOP     CONFIG_USART2_2STOP
+#  elif defined(CONFIG_USART3_SERIAL_CONSOLE) && \
+        defined(CONFIG_HT32F491X3_USART3_SERIALDRIVER)
+#    define HT32_CONSOLE_BASE      HT32_USART3_BASE
+#    define HT32_CONSOLE_APBREG    HT32_CRM_APB1EN
+#    define HT32_CONSOLE_APBEN     HT32_CRM_APB1EN_USART3EN
+#    define HT32_CONSOLE_CLOCK     HT32_PCLK1_FREQUENCY
+#    define HT32_CONSOLE_BAUD      CONFIG_USART3_BAUD
+#    define HT32_CONSOLE_BITS      CONFIG_USART3_BITS
+#    define HT32_CONSOLE_PARITY    CONFIG_USART3_PARITY
+#    define HT32_CONSOLE_2STOP     CONFIG_USART3_2STOP
+#  endif
+
+#  define HT32_USART_CTRL1_CLRBITS \
+     (HT32_USART_CTRL1_SBF | HT32_USART_CTRL1_RM | HT32_USART_CTRL1_REN | \
+      HT32_USART_CTRL1_TEN | HT32_USART_CTRL1_IDLEIEN | \
+      HT32_USART_CTRL1_RDBFIEN | HT32_USART_CTRL1_TDCIEN | \
+      HT32_USART_CTRL1_TDBEIEN | HT32_USART_CTRL1_PERRIEN | \
+      HT32_USART_CTRL1_PSEL | HT32_USART_CTRL1_PEN | \
+      HT32_USART_CTRL1_WUM | HT32_USART_CTRL1_DBN0 | \
+      HT32_USART_CTRL1_UEN | HT32_USART_CTRL1_DBN1)
+
+#  define HT32_USART_CTRL2_CLRBITS \
+     (HT32_USART_CTRL2_BFIEN | HT32_USART_CTRL2_LBCP | \
+      HT32_USART_CTRL2_CLKPHA | HT32_USART_CTRL2_CLKPOL | \
+      HT32_USART_CTRL2_CLKEN | HT32_USART_CTRL2_STOPBN_MASK)
+
+#  define HT32_USART_CTRL3_CLRBITS \
+     (HT32_USART_CTRL3_ERRIEN | HT32_USART_CTRL3_DMAREN | \
+      HT32_USART_CTRL3_DMATEN | HT32_USART_CTRL3_RTSEN | \
+      HT32_USART_CTRL3_CTSEN | HT32_USART_CTRL3_CTSCFIEN | \
+      HT32_USART_CTRL3_RS485EN | HT32_USART_CTRL3_DEP)
+#endif
+
+static uint32_t ht32f491x3_bauddiv(uint32_t clock, uint32_t baud)
+{
+  uint32_t div;
+
+  div = (clock * 10u) / baud;
+  return ((div % 10u) < 5u) ? (div / 10u) : (div / 10u + 1u);
+}
+
+void ht32f491x3_usart_config(uintptr_t uartbase)
+{
+  if (uartbase == HT32_USART1_BASE)
+    {
+      modifyreg32(HT32_CRM_PICLKS,
+                  HT32_CRM_PICLKS_USART1SEL_MASK,
+                  HT32_CRM_PICLKS_USARTSEL_PCLK <<
+                  HT32_CRM_PICLKS_USART1SEL_SHIFT);
+      modifyreg32(HT32_CRM_APB2RST, 0, HT32_CRM_APB2RST_USART1RST);
+      modifyreg32(HT32_CRM_APB2RST, HT32_CRM_APB2RST_USART1RST, 0);
+    }
+  else if (uartbase == HT32_USART2_BASE)
+    {
+      modifyreg32(HT32_CRM_PICLKS,
+                  HT32_CRM_PICLKS_USART2SEL_MASK,
+                  HT32_CRM_PICLKS_USARTSEL_PCLK <<
+                  HT32_CRM_PICLKS_USART2SEL_SHIFT);
+      modifyreg32(HT32_CRM_APB1RST, 0, HT32_CRM_APB1RST_USART2RST);
+      modifyreg32(HT32_CRM_APB1RST, HT32_CRM_APB1RST_USART2RST, 0);
+    }
+  else if (uartbase == HT32_USART3_BASE)
+    {
+      modifyreg32(HT32_CRM_PICLKS,
+                  HT32_CRM_PICLKS_USART3SEL_MASK,
+                  HT32_CRM_PICLKS_USARTSEL_PCLK <<
+                  HT32_CRM_PICLKS_USART3SEL_SHIFT);
+      modifyreg32(HT32_CRM_APB1RST, 0, HT32_CRM_APB1RST_USART3RST);
+      modifyreg32(HT32_CRM_APB1RST, HT32_CRM_APB1RST_USART3RST, 0);
+    }
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/* Configure the board-specific pinmux for the selected USART. The physical
+ * mapping comes from BOARD_USARTx_* macros in <arch/board/board.h>.
+ */
+
+void ht32f491x3_usart_pins(uintptr_t uartbase)
+{
+#ifdef BOARD_USART1_GPIO_CLKEN
+  if (uartbase == HT32_USART1_BASE)
+    {
+      modifyreg32(HT32_CRM_AHBEN1, 0, BOARD_USART1_GPIO_CLKEN);
+      ht32f491x3_gpioconfig(BOARD_USART1_TX_GPIO_BASE,
+                            BOARD_USART1_TX_PIN, HT32_GPIO_MODE_ALTFN,
+                            false, HT32_GPIO_DRIVE_MEDIUM,
+                            HT32_GPIO_PULL_NONE,
+                            BOARD_USART1_TX_AF);
+      ht32f491x3_gpioconfig(BOARD_USART1_RX_GPIO_BASE,
+                            BOARD_USART1_RX_PIN, HT32_GPIO_MODE_ALTFN,
+                            false, HT32_GPIO_DRIVE_MEDIUM,
+                            HT32_GPIO_PULL_UP,
+                            BOARD_USART1_RX_AF);
+      return;
+    }
+#endif
+
+#ifdef BOARD_USART2_GPIO_CLKEN
+  if (uartbase == HT32_USART2_BASE)
+    {
+      modifyreg32(HT32_CRM_AHBEN1, 0, BOARD_USART2_GPIO_CLKEN);
+      ht32f491x3_gpioconfig(BOARD_USART2_TX_GPIO_BASE,
+                            BOARD_USART2_TX_PIN, HT32_GPIO_MODE_ALTFN,
+                            false, HT32_GPIO_DRIVE_MEDIUM,
+                            HT32_GPIO_PULL_NONE,
+                            BOARD_USART2_TX_AF);
+      ht32f491x3_gpioconfig(BOARD_USART2_RX_GPIO_BASE,
+                            BOARD_USART2_RX_PIN, HT32_GPIO_MODE_ALTFN,
+                            false, HT32_GPIO_DRIVE_MEDIUM,
+                            HT32_GPIO_PULL_UP,
+                            BOARD_USART2_RX_AF);
+      return;
+    }
+#endif
+
+#ifdef BOARD_USART3_GPIO_CLKEN
+  if (uartbase == HT32_USART3_BASE)
+    {
+      modifyreg32(HT32_CRM_AHBEN1, 0, BOARD_USART3_GPIO_CLKEN);
+      ht32f491x3_gpioconfig(BOARD_USART3_TX_GPIO_BASE,
+                            BOARD_USART3_TX_PIN, HT32_GPIO_MODE_ALTFN,
+                            false, HT32_GPIO_DRIVE_MEDIUM,
+                            HT32_GPIO_PULL_NONE,
+                            BOARD_USART3_TX_AF);
+      ht32f491x3_gpioconfig(BOARD_USART3_RX_GPIO_BASE,
+                            BOARD_USART3_RX_PIN, HT32_GPIO_MODE_ALTFN,
+                            false, HT32_GPIO_DRIVE_MEDIUM,
+                            HT32_GPIO_PULL_UP,
+                            BOARD_USART3_RX_AF);
+    }
+#endif
+}
+
+void arm_lowputc(char ch)
+{
+#ifdef HAVE_CONSOLE
+  while ((getreg32(HT32_CONSOLE_BASE + HT32_USART_STS_OFFSET) &
+          HT32_USART_STS_TDBE) == 0)
+    {
+    }
+
+  putreg32((uint32_t)ch & HT32_USART_DT_MASK,
+           HT32_CONSOLE_BASE + HT32_USART_DT_OFFSET);
+#endif
+}
+
+void ht32f491x3_lowsetup(void)
+{
+#if defined(HAVE_CONSOLE)
+  uint32_t regval;
+
+  modifyreg32(HT32_CONSOLE_APBREG, 0, HT32_CONSOLE_APBEN);
+  ht32f491x3_usart_config(HT32_CONSOLE_BASE);
+  ht32f491x3_usart_pins(HT32_CONSOLE_BASE);
+
+#ifndef CONFIG_SUPPRESS_UART_CONFIG
+  regval  = getreg32(HT32_CONSOLE_BASE + HT32_USART_CTRL1_OFFSET);
+  regval &= ~HT32_USART_CTRL1_UEN;
+  putreg32(regval, HT32_CONSOLE_BASE + HT32_USART_CTRL1_OFFSET);
+
+  regval  = getreg32(HT32_CONSOLE_BASE + HT32_USART_CTRL2_OFFSET);
+  regval &= ~HT32_USART_CTRL2_CLRBITS;
+  if (HT32_CONSOLE_2STOP != 0)
+    {
+      regval |= HT32_USART_CTRL2_STOPBN_20;
+    }
+  else
+    {
+      regval |= HT32_USART_CTRL2_STOPBN_10;
+    }
+
+  putreg32(regval, HT32_CONSOLE_BASE + HT32_USART_CTRL2_OFFSET);
+
+  regval  = getreg32(HT32_CONSOLE_BASE + HT32_USART_CTRL1_OFFSET);
+  regval &= ~HT32_USART_CTRL1_CLRBITS;
+
+  if (HT32_CONSOLE_PARITY == 1)
+    {
+      regval |= HT32_USART_CTRL1_PEN;
+    }
+  else if (HT32_CONSOLE_PARITY == 2)
+    {
+      regval |= HT32_USART_CTRL1_PEN | HT32_USART_CTRL1_PSEL;
+    }
+
+  if (HT32_CONSOLE_BITS == 9 ||
+      (HT32_CONSOLE_BITS == 8 && HT32_CONSOLE_PARITY != 0))
+    {
+      regval |= HT32_USART_CTRL1_DBN0;
+    }
+  else if (HT32_CONSOLE_BITS == 7)
+    {
+      regval |= HT32_USART_CTRL1_DBN1;
+    }
+
+  putreg32(regval, HT32_CONSOLE_BASE + HT32_USART_CTRL1_OFFSET);
+
+  regval  = getreg32(HT32_CONSOLE_BASE + HT32_USART_CTRL3_OFFSET);
+  regval &= ~HT32_USART_CTRL3_CLRBITS;
+  putreg32(regval, HT32_CONSOLE_BASE + HT32_USART_CTRL3_OFFSET);
+
+  putreg32(ht32f491x3_bauddiv(HT32_CONSOLE_CLOCK, HT32_CONSOLE_BAUD),
+           HT32_CONSOLE_BASE + HT32_USART_BAUDR_OFFSET);
+#endif
+
+  regval  = getreg32(HT32_CONSOLE_BASE + HT32_USART_CTRL1_OFFSET);
+  regval |= HT32_USART_CTRL1_UEN |
+            HT32_USART_CTRL1_TEN |
+            HT32_USART_CTRL1_REN;
+  putreg32(regval, HT32_CONSOLE_BASE + HT32_USART_CTRL1_OFFSET);
+#endif
+}
diff --git a/arch/arm/src/ht32f491x3/ht32f491x3_lowputc.h b/arch/arm/src/ht32f491x3/ht32f491x3_lowputc.h
new file mode 100644
index 00000000000..c900b58dd41
--- /dev/null
+++ b/arch/arm/src/ht32f491x3/ht32f491x3_lowputc.h
@@ -0,0 +1,43 @@
+/****************************************************************************
+ * arch/arm/src/ht32f491x3/ht32f491x3_lowputc.h
+ *
+ * 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.
+ *
+ ****************************************************************************/
+
+#ifndef __ARCH_ARM_SRC_HT32F491X3_HT32F491X3_LOWPUTC_H
+#define __ARCH_ARM_SRC_HT32F491X3_HT32F491X3_LOWPUTC_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdint.h>
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+#ifndef __ASSEMBLY__
+void ht32f491x3_lowsetup(void);
+void ht32f491x3_usart_config(uintptr_t uartbase);
+#endif
+
+#endif /* __ARCH_ARM_SRC_HT32F491X3_HT32F491X3_LOWPUTC_H */
diff --git a/arch/arm/src/ht32f491x3/ht32f491x3_serial.c b/arch/arm/src/ht32f491x3/ht32f491x3_serial.c
new file mode 100644
index 00000000000..06ff5013159
--- /dev/null
+++ b/arch/arm/src/ht32f491x3/ht32f491x3_serial.c
@@ -0,0 +1,658 @@
+/****************************************************************************
+ * arch/arm/src/ht32f491x3/ht32f491x3_serial.c
+ *
+ * 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.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <sys/types.h>
+
+#include <stdbool.h>
+#include <errno.h>
+#include <stdint.h>
+
+#include <nuttx/arch.h>
+#include <nuttx/irq.h>
+#include <nuttx/serial/serial.h>
+#include <nuttx/spinlock.h>
+
+#include "chip.h"
+#include "arm_internal.h"
+
+#include "ht32f491x3_config.h"
+#include "ht32f491x3_lowputc.h"
+#include "ht32f491x3_serial.h"
+
+#include "hardware/ht32f491x3_crm.h"
+#include "hardware/ht32f491x3_uart.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#if defined(CONFIG_USART1_SERIAL_CONSOLE) && \
+    defined(CONFIG_HT32F491X3_USART1_SERIALDRIVER)
+#  define CONSOLE_USART 1
+#elif defined(CONFIG_USART2_SERIAL_CONSOLE) && \
+      defined(CONFIG_HT32F491X3_USART2_SERIALDRIVER)
+#  define CONSOLE_USART 2
+#elif defined(CONFIG_USART3_SERIAL_CONSOLE) && \
+      defined(CONFIG_HT32F491X3_USART3_SERIALDRIVER)
+#  define CONSOLE_USART 3
+#else
+#  define CONSOLE_USART 0
+#endif
+
+#define HT32_USART_CTRL1_USED_INTS \
+  (HT32_USART_CTRL1_IDLEIEN | HT32_USART_CTRL1_RDBFIEN | \
+   HT32_USART_CTRL1_TDCIEN | HT32_USART_CTRL1_TDBEIEN | \
+   HT32_USART_CTRL1_PERRIEN)
+
+#define HT32_USART_CTRL3_USED_INTS HT32_USART_CTRL3_ERRIEN
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+struct up_dev_s
+{
+  uintptr_t uartbase;
+  uintptr_t apbreg;
+  uint32_t apbmask;
+  uint32_t apbclock;
+  uint32_t baud;
+  uint32_t ie;
+  int irq;
+  uint8_t parity;
+  uint8_t bits;
+  bool stopbits2;
+  spinlock_t lock;
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static int up_setup(FAR struct uart_dev_s *dev);
+static void up_shutdown(FAR struct uart_dev_s *dev);
+static int up_attach(FAR struct uart_dev_s *dev);
+static void up_detach(FAR struct uart_dev_s *dev);
+static int ht32_interrupt(int irq, FAR void *context, FAR void *arg);
+static int up_ioctl(FAR struct file *filep, int cmd, unsigned long arg);
+static int up_receive(FAR struct uart_dev_s *dev,
+                      FAR unsigned int *status);
+static void up_rxint(FAR struct uart_dev_s *dev, bool enable);
+static bool up_rxavailable(FAR struct uart_dev_s *dev);
+static void up_send(FAR struct uart_dev_s *dev, int ch);
+static void up_txint(FAR struct uart_dev_s *dev, bool enable);
+static bool up_txready(FAR struct uart_dev_s *dev);
+static bool up_txempty(FAR struct uart_dev_s *dev);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const struct uart_ops_s g_uart_ops =
+{
+  .setup       = up_setup,
+  .shutdown    = up_shutdown,
+  .attach      = up_attach,
+  .detach      = up_detach,
+  .ioctl       = up_ioctl,
+  .receive     = up_receive,
+  .rxint       = up_rxint,
+  .rxavailable = up_rxavailable,
+  .send        = up_send,
+  .txint       = up_txint,
+  .txready     = up_txready,
+  .txempty     = up_txempty,
+};
+
+#if defined(USE_SERIALDRIVER) && defined(HAVE_UART)
+
+#ifdef CONFIG_HT32F491X3_USART1_SERIALDRIVER
+static char g_usart1rxbuffer[CONFIG_USART1_RXBUFSIZE];
+static char g_usart1txbuffer[CONFIG_USART1_TXBUFSIZE];
+
+static struct up_dev_s g_usart1priv =
+{
+  .uartbase  = HT32_USART1_BASE,
+  .apbreg    = HT32_CRM_APB2EN,
+  .apbmask   = HT32_CRM_APB2EN_USART1EN,
+  .apbclock  = HT32_PCLK2_FREQUENCY,
+  .baud      = CONFIG_USART1_BAUD,
+  .irq       = HT32_IRQ_USART1,
+  .parity    = CONFIG_USART1_PARITY,
+  .bits      = CONFIG_USART1_BITS,
+  .stopbits2 = CONFIG_USART1_2STOP,
+  .lock      = SP_UNLOCKED,
+};
+
+static uart_dev_t g_usart1port =
+{
+#if CONSOLE_USART == 1
+  .isconsole = true,
+#endif
+  .recv      =
+    {
+      .size   = CONFIG_USART1_RXBUFSIZE,
+      .buffer = g_usart1rxbuffer,
+    },
+  .xmit      =
+    {
+      .size   = CONFIG_USART1_TXBUFSIZE,
+      .buffer = g_usart1txbuffer,
+    },
+  .ops       = &g_uart_ops,
+  .priv      = &g_usart1priv,
+};
+#endif
+
+#ifdef CONFIG_HT32F491X3_USART2_SERIALDRIVER
+static char g_usart2rxbuffer[CONFIG_USART2_RXBUFSIZE];
+static char g_usart2txbuffer[CONFIG_USART2_TXBUFSIZE];
+
+static struct up_dev_s g_usart2priv =
+{
+  .uartbase  = HT32_USART2_BASE,
+  .apbreg    = HT32_CRM_APB1EN,
+  .apbmask   = HT32_CRM_APB1EN_USART2EN,
+  .apbclock  = HT32_PCLK1_FREQUENCY,
+  .baud      = CONFIG_USART2_BAUD,
+  .irq       = HT32_IRQ_USART2,
+  .parity    = CONFIG_USART2_PARITY,
+  .bits      = CONFIG_USART2_BITS,
+  .stopbits2 = CONFIG_USART2_2STOP,
+  .lock      = SP_UNLOCKED,
+};
+
+static uart_dev_t g_usart2port =
+{
+#if CONSOLE_USART == 2
+  .isconsole = true,
+#endif
+  .recv      =
+    {
+      .size   = CONFIG_USART2_RXBUFSIZE,
+      .buffer = g_usart2rxbuffer,
+    },
+  .xmit      =
+    {
+      .size   = CONFIG_USART2_TXBUFSIZE,
+      .buffer = g_usart2txbuffer,
+    },
+  .ops       = &g_uart_ops,
+  .priv      = &g_usart2priv,
+};
+#endif
+
+#ifdef CONFIG_HT32F491X3_USART3_SERIALDRIVER
+static char g_usart3rxbuffer[CONFIG_USART3_RXBUFSIZE];
+static char g_usart3txbuffer[CONFIG_USART3_TXBUFSIZE];
+
+static struct up_dev_s g_usart3priv =
+{
+  .uartbase  = HT32_USART3_BASE,
+  .apbreg    = HT32_CRM_APB1EN,
+  .apbmask   = HT32_CRM_APB1EN_USART3EN,
+  .apbclock  = HT32_PCLK1_FREQUENCY,
+  .baud      = CONFIG_USART3_BAUD,
+  .irq       = HT32_IRQ_USART3,
+  .parity    = CONFIG_USART3_PARITY,
+  .bits      = CONFIG_USART3_BITS,
+  .stopbits2 = CONFIG_USART3_2STOP,
+  .lock      = SP_UNLOCKED,
+};
+
+static uart_dev_t g_usart3port =
+{
+#if CONSOLE_USART == 3
+  .isconsole = true,
+#endif
+  .recv      =
+    {
+      .size   = CONFIG_USART3_RXBUFSIZE,
+      .buffer = g_usart3rxbuffer,
+    },
+  .xmit      =
+    {
+      .size   = CONFIG_USART3_TXBUFSIZE,
+      .buffer = g_usart3txbuffer,
+    },
+  .ops       = &g_uart_ops,
+  .priv      = &g_usart3priv,
+};
+#endif
+
+static uart_dev_t *const g_uart_devs[] =
+{
+#ifdef CONFIG_HT32F491X3_USART1_SERIALDRIVER
+  &g_usart1port,
+#else
+  NULL,
+#endif
+#ifdef CONFIG_HT32F491X3_USART2_SERIALDRIVER
+  &g_usart2port,
+#else
+  NULL,
+#endif
+#ifdef CONFIG_HT32F491X3_USART3_SERIALDRIVER
+  &g_usart3port,
+#else
+  NULL,
+#endif
+};
+
+#define HT32_NUART_PORTS (sizeof(g_uart_devs) / sizeof(g_uart_devs[0]))
+
+#if CONSOLE_USART == 1
+#  define CONSOLE_DEVPTR (&g_usart1port)
+#elif CONSOLE_USART == 2
+#  define CONSOLE_DEVPTR (&g_usart2port)
+#elif CONSOLE_USART == 3
+#  define CONSOLE_DEVPTR (&g_usart3port)
+#else
+#  define CONSOLE_DEVPTR ((FAR uart_dev_t *)0)
+#endif
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+static inline uint32_t up_serialin(FAR struct up_dev_s *priv, int offset)
+{
+  return getreg32(priv->uartbase + offset);
+}
+
+static inline void up_serialout(FAR struct up_dev_s *priv, int offset,
+                                uint32_t value)
+{
+  putreg32(value, priv->uartbase + offset);
+}
+
+static uint32_t ht32f491x3_bauddiv(uint32_t clock, uint32_t baud)
+{
+  uint32_t div;
+
+  div = (clock * 10u) / baud;
+  return ((div % 10u) < 5u) ? (div / 10u) : (div / 10u + 1u);
+}
+
+static void up_setusartint_nolock(FAR struct up_dev_s *priv, uint32_t ie)
+{
+  uint32_t regval;
+
+  priv->ie = ie;
+
+  regval  = up_serialin(priv, HT32_USART_CTRL1_OFFSET);
+  regval &= ~HT32_USART_CTRL1_USED_INTS;
+  regval |= ie & HT32_USART_CTRL1_USED_INTS;
+  up_serialout(priv, HT32_USART_CTRL1_OFFSET, regval);
+
+  regval  = up_serialin(priv, HT32_USART_CTRL3_OFFSET);
+  regval &= ~HT32_USART_CTRL3_USED_INTS;
+  regval |= ie & HT32_USART_CTRL3_USED_INTS;
+  up_serialout(priv, HT32_USART_CTRL3_OFFSET, regval);
+}
+
+static void up_restoreusartint(FAR struct up_dev_s *priv, uint32_t ie)
+{
+  irqstate_t flags;
+
+  flags = spin_lock_irqsave(&priv->lock);
+  up_setusartint_nolock(priv, ie);
+  spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+static void up_disableusartint(FAR struct up_dev_s *priv, FAR uint32_t *ie)
+{
+  irqstate_t flags;
+
+  flags = spin_lock_irqsave(&priv->lock);
+
+  if (ie != NULL)
+    {
+      uint32_t regval;
+
+      regval  = up_serialin(priv, HT32_USART_CTRL1_OFFSET);
+      *ie     = regval & HT32_USART_CTRL1_USED_INTS;
+      regval  = up_serialin(priv, HT32_USART_CTRL3_OFFSET);
+      *ie    |= regval & HT32_USART_CTRL3_USED_INTS;
+    }
+
+  up_setusartint_nolock(priv, 0);
+  spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+#ifndef CONFIG_SUPPRESS_UART_CONFIG
+static void up_set_format(FAR struct uart_dev_s *dev)
+{
+  FAR struct up_dev_s *priv = (FAR struct up_dev_s *)dev->priv;
+  uint32_t regval;
+
+  regval  = up_serialin(priv, HT32_USART_CTRL1_OFFSET);
+  regval &= ~(HT32_USART_CTRL1_PEN | HT32_USART_CTRL1_PSEL |
+              HT32_USART_CTRL1_DBN0 | HT32_USART_CTRL1_DBN1);
+
+  if (priv->parity == 1)
+    {
+      regval |= HT32_USART_CTRL1_PEN;
+    }
+  else if (priv->parity == 2)
+    {
+      regval |= HT32_USART_CTRL1_PEN | HT32_USART_CTRL1_PSEL;
+    }
+
+  if (priv->bits == 9 || (priv->bits == 8 && priv->parity != 0))
+    {
+      regval |= HT32_USART_CTRL1_DBN0;
+    }
+  else if (priv->bits == 7)
+    {
+      regval |= HT32_USART_CTRL1_DBN1;
+    }
+
+  up_serialout(priv, HT32_USART_CTRL1_OFFSET, regval);
+
+  regval  = up_serialin(priv, HT32_USART_CTRL2_OFFSET);
+  regval &= ~HT32_USART_CTRL2_STOPBN_MASK;
+  regval |= priv->stopbits2 ? HT32_USART_CTRL2_STOPBN_20
+                            : HT32_USART_CTRL2_STOPBN_10;
+  up_serialout(priv, HT32_USART_CTRL2_OFFSET, regval);
+
+  regval  = up_serialin(priv, HT32_USART_CTRL3_OFFSET);
+  regval &= ~(HT32_USART_CTRL3_RTSEN | HT32_USART_CTRL3_CTSEN |
+              HT32_USART_CTRL3_RS485EN | HT32_USART_CTRL3_DEP);
+  up_serialout(priv, HT32_USART_CTRL3_OFFSET, regval);
+
+  up_serialout(priv, HT32_USART_BAUDR_OFFSET,
+               ht32f491x3_bauddiv(priv->apbclock, priv->baud));
+}
+#endif
+
+static int up_setup(FAR struct uart_dev_s *dev)
+{
+  FAR struct up_dev_s *priv = (FAR struct up_dev_s *)dev->priv;
+  uint32_t regval;
+
+  modifyreg32(priv->apbreg, 0, priv->apbmask);
+  ht32f491x3_usart_config(priv->uartbase);
+  ht32f491x3_usart_pins(priv->uartbase);
+
+  regval  = up_serialin(priv, HT32_USART_CTRL1_OFFSET);
+  regval &= ~HT32_USART_CTRL1_UEN;
+  up_serialout(priv, HT32_USART_CTRL1_OFFSET, regval);
+
+#ifndef CONFIG_SUPPRESS_UART_CONFIG
+  up_set_format(dev);
+#endif
+
+  regval  = up_serialin(priv, HT32_USART_CTRL1_OFFSET);
+  regval |= HT32_USART_CTRL1_UEN |
+            HT32_USART_CTRL1_TEN |
+            HT32_USART_CTRL1_REN;
+  up_serialout(priv, HT32_USART_CTRL1_OFFSET, regval);
+
+  return 0;
+}
+
+static void up_shutdown(FAR struct uart_dev_s *dev)
+{
+  FAR struct up_dev_s *priv = (FAR struct up_dev_s *)dev->priv;
+  uint32_t regval;
+
+  up_disableusartint(priv, NULL);
+
+  regval  = up_serialin(priv, HT32_USART_CTRL1_OFFSET);
+  regval &= ~(HT32_USART_CTRL1_UEN |
+              HT32_USART_CTRL1_TEN |
+              HT32_USART_CTRL1_REN);
+  up_serialout(priv, HT32_USART_CTRL1_OFFSET, regval);
+}
+
+static int up_attach(FAR struct uart_dev_s *dev)
+{
+  FAR struct up_dev_s *priv = (FAR struct up_dev_s *)dev->priv;
+  int ret;
+
+  ret = irq_attach(priv->irq, ht32_interrupt, dev);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  up_enable_irq(priv->irq);
+  return 0;
+}
+
+static void up_detach(FAR struct uart_dev_s *dev)
+{
+  FAR struct up_dev_s *priv = (FAR struct up_dev_s *)dev->priv;
+
+  up_disable_irq(priv->irq);
+  irq_detach(priv->irq);
+}
+
+static int ht32_interrupt(int irq, FAR void *context, FAR void *arg)
+{
+  FAR struct uart_dev_s *dev = (FAR struct uart_dev_s *)arg;
+  FAR struct up_dev_s *priv = (FAR struct up_dev_s *)dev->priv;
+  uint32_t status;
+
+  UNUSED(irq);
+  UNUSED(context);
+
+  status = up_serialin(priv, HT32_USART_STS_OFFSET);
+
+  if ((status & HT32_USART_STS_RDBF) != 0)
+    {
+      uart_recvchars(dev);
+    }
+
+  if ((status & HT32_USART_STS_TDBE) != 0 &&
+      (priv->ie & HT32_USART_CTRL1_TDBEIEN) != 0)
+    {
+      uart_xmitchars(dev);
+    }
+
+  return 0;
+}
+
+static int up_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
+{
+  UNUSED(filep);
+  UNUSED(cmd);
+  UNUSED(arg);
+  return -ENOTTY;
+}
+
+static int up_receive(FAR struct uart_dev_s *dev, FAR unsigned int *status)
+{
+  FAR struct up_dev_s *priv = (FAR struct up_dev_s *)dev->priv;
+  uint32_t regval;
+
+  regval = up_serialin(priv, HT32_USART_STS_OFFSET);
+  if (status != NULL)
+    {
+      *status = regval;
+    }
+
+  regval = up_serialin(priv, HT32_USART_RDR_OFFSET);
+  return (int)(regval & (HT32_USART_DT_MASK >> HT32_USART_DT_SHIFT));
+}
+
+static void up_rxint(FAR struct uart_dev_s *dev, bool enable)
+{
+  FAR struct up_dev_s *priv = (FAR struct up_dev_s *)dev->priv;
+  irqstate_t flags;
+  uint32_t ie;
+
+  flags = spin_lock_irqsave(&priv->lock);
+  ie    = priv->ie;
+
+  if (enable)
+    {
+      ie |= HT32_USART_CTRL1_RDBFIEN | HT32_USART_CTRL3_ERRIEN;
+    }
+  else
+    {
+      ie &= ~(HT32_USART_CTRL1_RDBFIEN | HT32_USART_CTRL3_ERRIEN);
+    }
+
+  up_setusartint_nolock(priv, ie);
+  spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+static bool up_rxavailable(FAR struct uart_dev_s *dev)
+{
+  FAR struct up_dev_s *priv = (FAR struct up_dev_s *)dev->priv;
+
+  return (up_serialin(priv, HT32_USART_STS_OFFSET) &
+          HT32_USART_STS_RDBF) != 0;
+}
+
+static void up_send(FAR struct uart_dev_s *dev, int ch)
+{
+  FAR struct up_dev_s *priv = (FAR struct up_dev_s *)dev->priv;
+
+  up_serialout(priv, HT32_USART_TDR_OFFSET,
+               (uint32_t)ch & (HT32_USART_DT_MASK >> HT32_USART_DT_SHIFT));
+}
+
+static void up_txint(FAR struct uart_dev_s *dev, bool enable)
+{
+  FAR struct up_dev_s *priv = (FAR struct up_dev_s *)dev->priv;
+  irqstate_t flags;
+  uint32_t ie;
+
+  flags = spin_lock_irqsave(&priv->lock);
+  ie    = priv->ie;
+
+  if (enable)
+    {
+      ie |= HT32_USART_CTRL1_TDBEIEN;
+    }
+  else
+    {
+      ie &= ~HT32_USART_CTRL1_TDBEIEN;
+    }
+
+  up_setusartint_nolock(priv, ie);
+  spin_unlock_irqrestore(&priv->lock, flags);
+
+  if (enable)
+    {
+      uart_xmitchars(dev);
+    }
+}
+
+static bool up_txready(FAR struct uart_dev_s *dev)
+{
+  FAR struct up_dev_s *priv = (FAR struct up_dev_s *)dev->priv;
+
+  return (up_serialin(priv, HT32_USART_STS_OFFSET) &
+          HT32_USART_STS_TDBE) != 0;
+}
+
+static bool up_txempty(FAR struct uart_dev_s *dev)
+{
+  FAR struct up_dev_s *priv = (FAR struct up_dev_s *)dev->priv;
+
+  return (up_serialin(priv, HT32_USART_STS_OFFSET) &
+          HT32_USART_STS_TDC) != 0;
+}
+
+void arm_earlyserialinit(void)
+{
+  unsigned int i;
+
+  for (i = 0; i < HT32_NUART_PORTS; i++)
+    {
+      if (g_uart_devs[i] != NULL)
+        {
+          up_disableusartint((FAR struct up_dev_s *)g_uart_devs[i]->priv,
+                             NULL);
+        }
+    }
+
+#if CONSOLE_USART > 0
+  up_setup(CONSOLE_DEVPTR);
+#endif
+}
+
+void arm_serialinit(void)
+{
+  char devname[] = "/dev/ttySx";
+  unsigned int i;
+  unsigned int minor = 0;
+
+#if CONSOLE_USART > 0
+  uart_register("/dev/console", CONSOLE_DEVPTR);
+  uart_register("/dev/ttyS0", CONSOLE_DEVPTR);
+  minor = 1;
+#endif
+
+  for (i = 0; i < HT32_NUART_PORTS; i++)
+    {
+      if (g_uart_devs[i] == NULL || g_uart_devs[i]->isconsole)
+        {
+          continue;
+        }
+
+      devname[9] = '0' + minor++;
+      uart_register(devname, g_uart_devs[i]);
+    }
+}
+
+#else
+
+void arm_earlyserialinit(void)
+{
+}
+
+void arm_serialinit(void)
+{
+}
+
+#endif /* USE_SERIALDRIVER && HAVE_UART */
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+void up_putc(int ch)
+{
+#ifdef HAVE_CONSOLE
+#  if defined(USE_SERIALDRIVER) && defined(HAVE_UART) && CONSOLE_USART > 0
+  FAR struct up_dev_s *priv = (FAR struct up_dev_s *)CONSOLE_DEVPTR->priv;
+  uint32_t ie;
+
+  up_disableusartint(priv, &ie);
+  arm_lowputc(ch);
+  up_restoreusartint(priv, ie);
+#  else
+  arm_lowputc(ch);
+#  endif
+#endif
+}
diff --git a/arch/arm/src/ht32f491x3/ht32f491x3_serial.h b/arch/arm/src/ht32f491x3/ht32f491x3_serial.h
new file mode 100644
index 00000000000..0f242735249
--- /dev/null
+++ b/arch/arm/src/ht32f491x3/ht32f491x3_serial.h
@@ -0,0 +1,46 @@
+/****************************************************************************
+ * arch/arm/src/ht32f491x3/ht32f491x3_serial.h
+ *
+ * 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.
+ *
+ ****************************************************************************/
+
+#ifndef __ARCH_ARM_SRC_HT32F491X3_HT32F491X3_SERIAL_H
+#define __ARCH_ARM_SRC_HT32F491X3_HT32F491X3_SERIAL_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdint.h>
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+#ifndef __ASSEMBLY__
+
+void arm_earlyserialinit(void);
+void arm_serialinit(void);
+void ht32f491x3_usart_pins(uintptr_t uartbase);
+
+#endif
+
+#endif /* __ARCH_ARM_SRC_HT32F491X3_HT32F491X3_SERIAL_H */
diff --git a/arch/arm/src/ht32f491x3/ht32f491x3_start.c b/arch/arm/src/ht32f491x3/ht32f491x3_start.c
new file mode 100644
index 00000000000..c688976e243
--- /dev/null
+++ b/arch/arm/src/ht32f491x3/ht32f491x3_start.c
@@ -0,0 +1,114 @@
+/****************************************************************************
+ * arch/arm/src/ht32f491x3/ht32f491x3_start.c
+ *
+ * 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.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdint.h>
+
+#include <nuttx/init.h>
+#include <arch/irq.h>
+
+#include "arm_internal.h"
+
+#include "ht32f491x3_lowputc.h"
+#include "ht32f491x3_serial.h"
+#include "ht32f491x3_start.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#ifdef CONFIG_DEBUG_FEATURES
+#  define showprogress(c) arm_lowputc(c)
+#else
+#  define showprogress(c)
+#endif
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+const uintptr_t g_idle_topstack = (uintptr_t)_END_BSS +
+  CONFIG_IDLETHREAD_STACKSIZE;
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+void weak_function ht32f491x3_clockconfig(void)
+{
+}
+
+void __start(void) __attribute__((section(".entry")));
+void __start(void)
+{
+  const uint32_t *src;
+  uint32_t *dest;
+
+  up_irq_disable();
+
+  /* Let the board tune CRM before the early console computes its divisors.
+   */
+
+  ht32f491x3_clockconfig();
+  ht32f491x3_lowsetup();
+  showprogress('A');
+
+  for (dest = (uint32_t *)_START_BSS; dest < (uint32_t *)_END_BSS; )
+    {
+      *dest++ = 0;
+    }
+
+  showprogress('B');
+
+  src  = (const uint32_t *)_DATA_INIT;
+  dest = (uint32_t *)_START_DATA;
+
+  while (dest < (uint32_t *)_END_DATA)
+    {
+      *dest++ = *src++;
+    }
+
+  showprogress('C');
+
+  arm_fpuconfig();
+  showprogress('D');
+
+#ifdef USE_EARLYSERIALINIT
+  arm_earlyserialinit();
+#endif
+  showprogress('E');
+
+  ht32f491x3_boardinitialize();
+  showprogress('F');
+
+  showprogress('\r');
+  showprogress('\n');
+
+  nx_start();
+
+  for (; ; );
+}
diff --git a/arch/arm/src/ht32f491x3/ht32f491x3_start.h b/arch/arm/src/ht32f491x3/ht32f491x3_start.h
new file mode 100644
index 00000000000..68b12352454
--- /dev/null
+++ b/arch/arm/src/ht32f491x3/ht32f491x3_start.h
@@ -0,0 +1,39 @@
+/****************************************************************************
+ * arch/arm/src/ht32f491x3/ht32f491x3_start.h
+ *
+ * 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.
+ *
+ ****************************************************************************/
+
+#ifndef __ARCH_ARM_SRC_HT32F491X3_HT32F491X3_START_H
+#define __ARCH_ARM_SRC_HT32F491X3_HT32F491X3_START_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+void ht32f491x3_clockconfig(void);
+void ht32f491x3_boardinitialize(void);
+
+#endif /* __ARCH_ARM_SRC_HT32F491X3_HT32F491X3_START_H */
diff --git a/arch/arm/src/ht32f491x3/ht32f491x3_timerisr.c b/arch/arm/src/ht32f491x3/ht32f491x3_timerisr.c
new file mode 100644
index 00000000000..17b05d2eedf
--- /dev/null
+++ b/arch/arm/src/ht32f491x3/ht32f491x3_timerisr.c
@@ -0,0 +1,95 @@
+/****************************************************************************
+ * arch/arm/src/ht32f491x3/ht32f491x3_timerisr.c
+ *
+ * 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.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdint.h>
+#include <time.h>
+
+#include <nuttx/arch.h>
+#include <nuttx/timers/arch_timer.h>
+
+#include "nvic.h"
+#include "clock/clock.h"
+#include "arm_internal.h"
+#include "systick.h"
+
+#include "chip.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define HT32_SYSTICK_RELOAD ((HT32_HCLK_FREQUENCY / CLK_TCK) - 1)
+
+#if HT32_SYSTICK_RELOAD > 0x00ffffff
+#  error HT32_SYSTICK_RELOAD exceeds the SysTick reload field
+#endif
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+#if !defined(CONFIG_ARMV7M_SYSTICK) && !defined(CONFIG_TIMER_ARCH)
+static int ht32f491x3_timerisr(int irq, FAR void *context, FAR void *arg)
+{
+  UNUSED(irq);
+  UNUSED(context);
+  UNUSED(arg);
+
+  nxsched_process_timer();
+  return 0;
+}
+#endif
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+void up_timer_initialize(void)
+{
+  uint32_t regval;
+
+  regval  = getreg32(NVIC_SYSH12_15_PRIORITY);
+  regval &= ~NVIC_SYSH_PRIORITY_PR15_MASK;
+  regval |= (NVIC_SYSH_PRIORITY_DEFAULT << NVIC_SYSH_PRIORITY_PR15_SHIFT);
+  putreg32(regval, NVIC_SYSH12_15_PRIORITY);
+
+#if defined(CONFIG_ARMV7M_SYSTICK) && defined(CONFIG_TIMER_ARCH)
+  up_timer_set_lowerhalf(systick_initialize(true, HT32_HCLK_FREQUENCY, -1));
+#else
+  putreg32(HT32_SYSTICK_RELOAD, NVIC_SYSTICK_RELOAD);
+
+  irq_attach(HT32_IRQ_SYSTICK, ht32f491x3_timerisr, NULL);
+
+  putreg32(NVIC_SYSTICK_CTRL_CLKSOURCE |
+           NVIC_SYSTICK_CTRL_TICKINT |
+           NVIC_SYSTICK_CTRL_ENABLE,
+           NVIC_SYSTICK_CTRL);
+
+  up_enable_irq(HT32_IRQ_SYSTICK);
+#endif
+}