فهرست منبع

Add support for GD32F3x0 series microcontrollers

This commit adds standard peripheral library support for the GD32F3x0 series MCUs, including:
- GD32F3x0 standard peripheral library (drivers for GPIO, USART, SPI, I2C, etc.)
- GD32F3x0 USB FS library (device, host, and driver support)
- SConscript build configuration
liuyucai 2 ماه پیش
والد
کامیت
99ff0a3eb4
100فایلهای تغییر یافته به همراه36406 افزوده شده و 0 حذف شده
  1. 364 0
      GD32F3x0/GD32F3x0_standard_peripheral/Include/gd32f3x0_adc.h
  2. 249 0
      GD32F3x0/GD32F3x0_standard_peripheral/Include/gd32f3x0_cec.h
  3. 147 0
      GD32F3x0/GD32F3x0_standard_peripheral/Include/gd32f3x0_cmp.h
  4. 123 0
      GD32F3x0/GD32F3x0_standard_peripheral/Include/gd32f3x0_crc.h
  5. 186 0
      GD32F3x0/GD32F3x0_standard_peripheral/Include/gd32f3x0_ctc.h
  6. 218 0
      GD32F3x0/GD32F3x0_standard_peripheral/Include/gd32f3x0_dac.h
  7. 129 0
      GD32F3x0/GD32F3x0_standard_peripheral/Include/gd32f3x0_dbg.h
  8. 270 0
      GD32F3x0/GD32F3x0_standard_peripheral/Include/gd32f3x0_dma.h
  9. 283 0
      GD32F3x0/GD32F3x0_standard_peripheral/Include/gd32f3x0_exti.h
  10. 255 0
      GD32F3x0/GD32F3x0_standard_peripheral/Include/gd32f3x0_fmc.h
  11. 126 0
      GD32F3x0/GD32F3x0_standard_peripheral/Include/gd32f3x0_fwdgt.h
  12. 407 0
      GD32F3x0/GD32F3x0_standard_peripheral/Include/gd32f3x0_gpio.h
  13. 344 0
      GD32F3x0/GD32F3x0_standard_peripheral/Include/gd32f3x0_i2c.h
  14. 91 0
      GD32F3x0/GD32F3x0_standard_peripheral/Include/gd32f3x0_misc.h
  15. 196 0
      GD32F3x0/GD32F3x0_standard_peripheral/Include/gd32f3x0_pmu.h
  16. 799 0
      GD32F3x0/GD32F3x0_standard_peripheral/Include/gd32f3x0_rcu.h
  17. 556 0
      GD32F3x0/GD32F3x0_standard_peripheral/Include/gd32f3x0_rtc.h
  18. 371 0
      GD32F3x0/GD32F3x0_standard_peripheral/Include/gd32f3x0_spi.h
  19. 189 0
      GD32F3x0/GD32F3x0_standard_peripheral/Include/gd32f3x0_syscfg.h
  20. 764 0
      GD32F3x0/GD32F3x0_standard_peripheral/Include/gd32f3x0_timer.h
  21. 390 0
      GD32F3x0/GD32F3x0_standard_peripheral/Include/gd32f3x0_tsi.h
  22. 572 0
      GD32F3x0/GD32F3x0_standard_peripheral/Include/gd32f3x0_usart.h
  23. 92 0
      GD32F3x0/GD32F3x0_standard_peripheral/Include/gd32f3x0_wwdgt.h
  24. 868 0
      GD32F3x0/GD32F3x0_standard_peripheral/Source/gd32f3x0_adc.c
  25. 497 0
      GD32F3x0/GD32F3x0_standard_peripheral/Source/gd32f3x0_cec.c
  26. 278 0
      GD32F3x0/GD32F3x0_standard_peripheral/Source/gd32f3x0_cmp.c
  27. 241 0
      GD32F3x0/GD32F3x0_standard_peripheral/Source/gd32f3x0_crc.c
  28. 380 0
      GD32F3x0/GD32F3x0_standard_peripheral/Source/gd32f3x0_ctc.c
  29. 509 0
      GD32F3x0/GD32F3x0_standard_peripheral/Source/gd32f3x0_dac.c
  30. 126 0
      GD32F3x0/GD32F3x0_standard_peripheral/Source/gd32f3x0_dbg.c
  31. 560 0
      GD32F3x0/GD32F3x0_standard_peripheral/Source/gd32f3x0_dma.c
  32. 252 0
      GD32F3x0/GD32F3x0_standard_peripheral/Source/gd32f3x0_exti.c
  33. 889 0
      GD32F3x0/GD32F3x0_standard_peripheral/Source/gd32f3x0_fmc.c
  34. 243 0
      GD32F3x0/GD32F3x0_standard_peripheral/Source/gd32f3x0_fwdgt.c
  35. 423 0
      GD32F3x0/GD32F3x0_standard_peripheral/Source/gd32f3x0_gpio.c
  36. 730 0
      GD32F3x0/GD32F3x0_standard_peripheral/Source/gd32f3x0_i2c.c
  37. 189 0
      GD32F3x0/GD32F3x0_standard_peripheral/Source/gd32f3x0_misc.c
  38. 417 0
      GD32F3x0/GD32F3x0_standard_peripheral/Source/gd32f3x0_pmu.c
  39. 1210 0
      GD32F3x0/GD32F3x0_standard_peripheral/Source/gd32f3x0_rcu.c
  40. 962 0
      GD32F3x0/GD32F3x0_standard_peripheral/Source/gd32f3x0_rtc.c
  41. 778 0
      GD32F3x0/GD32F3x0_standard_peripheral/Source/gd32f3x0_spi.c
  42. 226 0
      GD32F3x0/GD32F3x0_standard_peripheral/Source/gd32f3x0_syscfg.c
  43. 2082 0
      GD32F3x0/GD32F3x0_standard_peripheral/Source/gd32f3x0_timer.c
  44. 696 0
      GD32F3x0/GD32F3x0_standard_peripheral/Source/gd32f3x0_tsi.c
  45. 1259 0
      GD32F3x0/GD32F3x0_standard_peripheral/Source/gd32f3x0_usart.c
  46. 125 0
      GD32F3x0/GD32F3x0_standard_peripheral/Source/gd32f3x0_wwdgt.c
  47. 316 0
      GD32F3x0/GD32F3x0_usbfs_library/device/class/audio/Include/audio_core.h
  48. 48 0
      GD32F3x0/GD32F3x0_usbfs_library/device/class/audio/Include/audio_out_itf.h
  49. 951 0
      GD32F3x0/GD32F3x0_usbfs_library/device/class/audio/Source/audio_core.c
  50. 167 0
      GD32F3x0/GD32F3x0_usbfs_library/device/class/audio/Source/audio_out_itf.c
  51. 65 0
      GD32F3x0/GD32F3x0_usbfs_library/device/class/cdc/Include/cdc_acm_core.h
  52. 520 0
      GD32F3x0/GD32F3x0_usbfs_library/device/class/cdc/Source/cdc_acm_core.c
  53. 171 0
      GD32F3x0/GD32F3x0_usbfs_library/device/class/dfu/Include/dfu_core.h
  54. 80 0
      GD32F3x0/GD32F3x0_usbfs_library/device/class/dfu/Include/dfu_mem.h
  55. 668 0
      GD32F3x0/GD32F3x0_usbfs_library/device/class/dfu/Source/dfu_core.c
  56. 238 0
      GD32F3x0/GD32F3x0_usbfs_library/device/class/dfu/Source/dfu_mem.c
  57. 66 0
      GD32F3x0/GD32F3x0_usbfs_library/device/class/hid/Include/custom_hid_core.h
  58. 67 0
      GD32F3x0/GD32F3x0_usbfs_library/device/class/hid/Include/standard_hid_core.h
  59. 478 0
      GD32F3x0/GD32F3x0_usbfs_library/device/class/hid/Source/custom_hid_core.c
  60. 383 0
      GD32F3x0/GD32F3x0_usbfs_library/device/class/hid/Source/standard_hid_core.c
  61. 91 0
      GD32F3x0/GD32F3x0_usbfs_library/device/class/iap/Include/usb_iap_core.h
  62. 645 0
      GD32F3x0/GD32F3x0_usbfs_library/device/class/iap/Source/usb_iap_core.c
  63. 100 0
      GD32F3x0/GD32F3x0_usbfs_library/device/class/msc/Include/usbd_msc_bbb.h
  64. 57 0
      GD32F3x0/GD32F3x0_usbfs_library/device/class/msc/Include/usbd_msc_core.h
  65. 58 0
      GD32F3x0/GD32F3x0_usbfs_library/device/class/msc/Include/usbd_msc_mem.h
  66. 53 0
      GD32F3x0/GD32F3x0_usbfs_library/device/class/msc/Include/usbd_msc_scsi.h
  67. 287 0
      GD32F3x0/GD32F3x0_usbfs_library/device/class/msc/Source/usbd_msc_bbb.c
  68. 316 0
      GD32F3x0/GD32F3x0_usbfs_library/device/class/msc/Source/usbd_msc_core.c
  69. 758 0
      GD32F3x0/GD32F3x0_usbfs_library/device/class/msc/Source/usbd_msc_scsi.c
  70. 78 0
      GD32F3x0/GD32F3x0_usbfs_library/device/class/printer/Include/printer_core.h
  71. 302 0
      GD32F3x0/GD32F3x0_usbfs_library/device/class/printer/Source/printer_core.c
  72. 102 0
      GD32F3x0/GD32F3x0_usbfs_library/device/core/Include/usbd_core.h
  73. 98 0
      GD32F3x0/GD32F3x0_usbfs_library/device/core/Include/usbd_enum.h
  74. 56 0
      GD32F3x0/GD32F3x0_usbfs_library/device/core/Include/usbd_transc.h
  75. 311 0
      GD32F3x0/GD32F3x0_usbfs_library/device/core/Source/usbd_core.c
  76. 762 0
      GD32F3x0/GD32F3x0_usbfs_library/device/core/Source/usbd_enum.c
  77. 256 0
      GD32F3x0/GD32F3x0_usbfs_library/device/core/Source/usbd_transc.c
  78. 336 0
      GD32F3x0/GD32F3x0_usbfs_library/driver/Include/drv_usb_core.h
  79. 197 0
      GD32F3x0/GD32F3x0_usbfs_library/driver/Include/drv_usb_dev.h
  80. 113 0
      GD32F3x0/GD32F3x0_usbfs_library/driver/Include/drv_usb_host.h
  81. 60 0
      GD32F3x0/GD32F3x0_usbfs_library/driver/Include/drv_usb_hw.h
  82. 615 0
      GD32F3x0/GD32F3x0_usbfs_library/driver/Include/drv_usb_regs.h
  83. 45 0
      GD32F3x0/GD32F3x0_usbfs_library/driver/Include/drv_usbd_int.h
  84. 53 0
      GD32F3x0/GD32F3x0_usbfs_library/driver/Include/drv_usbh_int.h
  85. 319 0
      GD32F3x0/GD32F3x0_usbfs_library/driver/Source/drv_usb_core.c
  86. 585 0
      GD32F3x0/GD32F3x0_usbfs_library/driver/Source/drv_usb_dev.c
  87. 410 0
      GD32F3x0/GD32F3x0_usbfs_library/driver/Source/drv_usb_host.c
  88. 493 0
      GD32F3x0/GD32F3x0_usbfs_library/driver/Source/drv_usbd_int.c
  89. 601 0
      GD32F3x0/GD32F3x0_usbfs_library/driver/Source/drv_usbh_int.c
  90. 116 0
      GD32F3x0/GD32F3x0_usbfs_library/host/class/hid/Include/usbh_hid_core.h
  91. 96 0
      GD32F3x0/GD32F3x0_usbfs_library/host/class/hid/Include/usbh_standard_hid.h
  92. 582 0
      GD32F3x0/GD32F3x0_usbfs_library/host/class/hid/Source/usbh_hid_core.c
  93. 271 0
      GD32F3x0/GD32F3x0_usbfs_library/host/class/hid/Source/usbh_standard_hid.c
  94. 148 0
      GD32F3x0/GD32F3x0_usbfs_library/host/class/msc/Include/usbh_msc_bbb.h
  95. 122 0
      GD32F3x0/GD32F3x0_usbfs_library/host/class/msc/Include/usbh_msc_core.h
  96. 96 0
      GD32F3x0/GD32F3x0_usbfs_library/host/class/msc/Include/usbh_msc_scsi.h
  97. 360 0
      GD32F3x0/GD32F3x0_usbfs_library/host/class/msc/Source/usbh_msc_bbb.c
  98. 551 0
      GD32F3x0/GD32F3x0_usbfs_library/host/class/msc/Source/usbh_msc_core.c
  99. 231 0
      GD32F3x0/GD32F3x0_usbfs_library/host/class/msc/Source/usbh_msc_fatfs.c
  100. 397 0
      GD32F3x0/GD32F3x0_usbfs_library/host/class/msc/Source/usbh_msc_scsi.c

+ 364 - 0
GD32F3x0/GD32F3x0_standard_peripheral/Include/gd32f3x0_adc.h

@@ -0,0 +1,364 @@
+/*!
+    \file    gd32f3x0_adc.h
+    \brief   definitions for the ADC
+
+    \version 2025-01-01, V2.5.0, firmware for GD32F3x0
+*/
+
+/*
+    Copyright (c) 2025, GigaDevice Semiconductor Inc.
+
+    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 of the copyright holder 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 HOLDER 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.
+*/
+
+#ifndef GD32F3X0_ADC_H
+#define GD32F3X0_ADC_H
+
+#include "gd32f3x0.h"
+
+/* ADC definitions */
+#define ADC                              ADC_BASE                                    /*!< ADC base address */
+
+/* registers definitions */
+#define ADC_STAT                         REG32(ADC + 0x00000000U)                    /*!< ADC status register */
+#define ADC_CTL0                         REG32(ADC + 0x00000004U)                    /*!< ADC control register 0 */
+#define ADC_CTL1                         REG32(ADC + 0x00000008U)                    /*!< ADC control register 1 */
+#define ADC_SAMPT0                       REG32(ADC + 0x0000000CU)                    /*!< ADC sample time register 0 */
+#define ADC_SAMPT1                       REG32(ADC + 0x00000010U)                    /*!< ADC sample time register 1 */
+#define ADC_IOFF0                        REG32(ADC + 0x00000014U)                    /*!< ADC inserted channel data offset register 0 */
+#define ADC_IOFF1                        REG32(ADC + 0x00000018U)                    /*!< ADC inserted channel data offset register 1 */
+#define ADC_IOFF2                        REG32(ADC + 0x0000001CU)                    /*!< ADC inserted channel data offset register 2 */
+#define ADC_IOFF3                        REG32(ADC + 0x00000020U)                    /*!< ADC inserted channel data offset register 3 */
+#define ADC_WDHT                         REG32(ADC + 0x00000024U)                    /*!< ADC watchdog high threshold register */
+#define ADC_WDLT                         REG32(ADC + 0x00000028U)                    /*!< ADC watchdog low threshold register */
+#define ADC_RSQ0                         REG32(ADC + 0x0000002CU)                    /*!< ADC regular sequence register 0 */
+#define ADC_RSQ1                         REG32(ADC + 0x00000030U)                    /*!< ADC regular sequence register 1 */
+#define ADC_RSQ2                         REG32(ADC + 0x00000034U)                    /*!< ADC regular sequence register 2 */
+#define ADC_ISQ                          REG32(ADC + 0x00000038U)                    /*!< ADC inserted sequence register */
+#define ADC_IDATA0                       REG32(ADC + 0x0000003CU)                    /*!< ADC inserted data register 0 */
+#define ADC_IDATA1                       REG32(ADC + 0x00000040U)                    /*!< ADC inserted data register 1 */
+#define ADC_IDATA2                       REG32(ADC + 0x00000044U)                    /*!< ADC inserted data register 2 */
+#define ADC_IDATA3                       REG32(ADC + 0x00000048U)                    /*!< ADC inserted data register 3 */
+#define ADC_RDATA                        REG32(ADC + 0x0000004CU)                    /*!< ADC regular data register */
+#define ADC_OVSAMPCTL                    REG32(ADC + 0x00000080U)                    /*!< ADC oversampling control register */
+
+/* bits definitions */
+/* ADC_STAT */
+#define ADC_STAT_WDE                     BIT(0)                                      /*!< analog watchdog event flag */
+#define ADC_STAT_EOC                     BIT(1)                                      /*!< end of conversion flag */
+#define ADC_STAT_EOIC                    BIT(2)                                      /*!< inserted channel end of conversion flag */
+#define ADC_STAT_STIC                    BIT(3)                                      /*!< inserted channel start flag */
+#define ADC_STAT_STRC                    BIT(4)                                      /*!< regular channel start flag */
+
+/* ADC_CTL0 */
+#define ADC_CTL0_WDCHSEL                 BITS(0,4)                                   /*!< analog watchdog channel select bits */
+#define ADC_CTL0_EOCIE                   BIT(5)                                      /*!< interrupt enable for EOC */
+#define ADC_CTL0_WDEIE                   BIT(6)                                      /*!< analog watchdog interrupt enable */
+#define ADC_CTL0_EOICIE                  BIT(7)                                      /*!< interrupt enable for inserted channels */
+#define ADC_CTL0_SM                      BIT(8)                                      /*!< scan mode */
+#define ADC_CTL0_WDSC                    BIT(9)                                      /*!< when in scan mode, analog watchdog is effective on a single channel */
+#define ADC_CTL0_ICA                     BIT(10)                                     /*!< automatic inserted group conversion */
+#define ADC_CTL0_DISRC                   BIT(11)                                     /*!< discontinuous mode on regular channels */
+#define ADC_CTL0_DISIC                   BIT(12)                                     /*!< discontinuous mode on inserted channels */
+#define ADC_CTL0_DISNUM                  BITS(13,15)                                 /*!< discontinuous mode channel count */
+#define ADC_CTL0_IWDEN                   BIT(22)                                     /*!< analog watchdog enable on inserted channels */
+#define ADC_CTL0_RWDEN                   BIT(23)                                     /*!< analog watchdog enable on regular channels */
+#define ADC_CTL0_DRES                    BITS(24,25)                                 /*!< ADC data resolution */
+
+/* ADC_CTL1 */
+#define ADC_CTL1_ADCON                   BIT(0)                                      /*!< ADC converter on */
+#define ADC_CTL1_CTN                     BIT(1)                                      /*!< continuous conversion */
+#define ADC_CTL1_CLB                     BIT(2)                                      /*!< ADC calibration */
+#define ADC_CTL1_RSTCLB                  BIT(3)                                      /*!< reset calibration */
+#define ADC_CTL1_DMA                     BIT(8)                                      /*!< direct memory access mode */
+#define ADC_CTL1_DAL                     BIT(11)                                     /*!< data alignment */
+#define ADC_CTL1_ETSIC                   BITS(12,14)                                 /*!< external trigger select for inserted channel */
+#define ADC_CTL1_ETEIC                   BIT(15)                                     /*!< external trigger enable for inserted channel */
+#define ADC_CTL1_ETSRC                   BITS(17,19)                                 /*!< external trigger select for regular channel */
+#define ADC_CTL1_ETERC                   BIT(20)                                     /*!< external trigger enable for regular channel */
+#define ADC_CTL1_SWICST                  BIT(21)                                     /*!< start on inserted channel */
+#define ADC_CTL1_SWRCST                  BIT(22)                                     /*!< start on regular channel */
+#define ADC_CTL1_TSVREN                  BIT(23)                                     /*!< enable channel 16 and 17 */
+#define ADC_CTL1_VBETEN                  BIT(24)                                     /*!< VBAT enable */
+
+/* ADC_SAMPTx x=0,1 */
+#define ADC_SAMPTX_SPTN                  BITS(0,2)                                   /*!< channel n(n=0..18) sample time selection */
+
+/* ADC_IOFFx x=0..3 */
+#define ADC_IOFFX_IOFF                   BITS(0,11)                                  /*!< data offset for inserted channel x */
+
+/* ADC_WDHT */
+#define ADC_WDHT_WDHT                    BITS(0,11)                                  /*!< analog watchdog high threshold */
+
+/* ADC_WDLT */
+#define ADC_WDLT_WDLT                    BITS(0,11)                                  /*!< analog watchdog low threshold */
+
+/* ADC_RSQx x=0..2 */
+#define ADC_RSQX_RSQN                    BITS(0,4)                                   /*!< n conversion in regular sequence */
+#define ADC_RSQ0_RL                      BITS(20,23)                                 /*!< regular channel sequence length */
+
+/* ADC_ISQ */
+#define ADC_ISQ_ISQN                     BITS(0,4)                                   /*!< n conversion in regular sequence */
+#define ADC_ISQ_IL                       BITS(20,21)                                 /*!< inserted sequence length */
+
+/* ADC_IDATAx x=0..3 */
+#define ADC_IDATAX_IDATAN                BITS(0,15)                                  /*!< inserted channel x conversion data  */
+
+/* ADC_RDATA */
+#define ADC_RDATA_RDATA                  BITS(0,15)                                  /*!< regular channel data */
+
+/* ADC_OVSAMPCTL */
+#define ADC_OVSAMPCTL_OVSEN              BIT(0)                                      /*!< oversampling enable */
+#define ADC_OVSAMPCTL_OVSR               BITS(2,4)                                   /*!< oversampling ratio */
+#define ADC_OVSAMPCTL_OVSS               BITS(5,8)                                   /*!< oversampling shift */
+#define ADC_OVSAMPCTL_TOVS               BIT(9)                                      /*!< triggered oversampling */
+
+/* constants definitions */
+/* ADC flag definitions */
+#define ADC_FLAG_WDE                     ADC_STAT_WDE                                /*!< analog watchdog event flag */
+#define ADC_FLAG_EOC                     ADC_STAT_EOC                                /*!< end of group conversion flag */
+#define ADC_FLAG_EOIC                    ADC_STAT_EOIC                               /*!< end of inserted channel group conversion flag */
+#define ADC_FLAG_STIC                    ADC_STAT_STIC                               /*!< start flag of inserted channel group */
+#define ADC_FLAG_STRC                    ADC_STAT_STRC                               /*!< start flag of regular channel group */
+
+/* adc_ctl0 register value */
+#define CTL0_DISNUM(regval)              (BITS(13,15) & ((uint32_t)(regval) << 13))  /*!< number of conversions in discontinuous mode */
+
+/* ADC special function */
+#define ADC_SCAN_MODE                    ADC_CTL0_SM                                 /*!< scan mode */
+#define ADC_INSERTED_CHANNEL_AUTO        ADC_CTL0_ICA                                /*!< inserted channel group convert automatically */
+#define ADC_CONTINUOUS_MODE              ADC_CTL1_CTN                                /*!< continuous mode */
+
+/* ADC data alignment */
+#define ADC_DATAALIGN_RIGHT              ((uint32_t)0x00000000U)                     /*!< right alignment */
+#define ADC_DATAALIGN_LEFT               ADC_CTL1_DAL                                /*!< left alignment */
+
+/* external trigger select for regular channel */
+#define CTL1_ETSRC(regval)               (BITS(17,19) & ((uint32_t)(regval) << 17))
+#define ADC_EXTTRIG_REGULAR_T0_CH0       CTL1_ETSRC(0)                               /*!< TIMER0 CH0 event select */
+#define ADC_EXTTRIG_REGULAR_T0_CH1       CTL1_ETSRC(1)                               /*!< TIMER0 CH1 event select */
+#define ADC_EXTTRIG_REGULAR_T0_CH2       CTL1_ETSRC(2)                               /*!< TIMER0 CH2 event select */
+#define ADC_EXTTRIG_REGULAR_T1_CH1       CTL1_ETSRC(3)                               /*!< TIMER1 CH1 event select */
+#define ADC_EXTTRIG_REGULAR_T2_TRGO      CTL1_ETSRC(4)                               /*!< TIMER2 TRGO event select */
+#define ADC_EXTTRIG_REGULAR_T14_CH0      CTL1_ETSRC(5)                               /*!< TIMER14 CH0 event select */
+#define ADC_EXTTRIG_REGULAR_EXTI_11      CTL1_ETSRC(6)                               /*!< external interrupt line 11 */
+#define ADC_EXTTRIG_REGULAR_NONE         CTL1_ETSRC(7)                               /*!< software trigger */
+
+/* external trigger select for inserted channel */
+#define CTL1_ETSIC(regval)               (BITS(12,14) & ((uint32_t)(regval) << 12))
+#define ADC_EXTTRIG_INSERTED_T0_TRGO     CTL1_ETSIC(0)                               /*!< TIMER0 TRGO event select */
+#define ADC_EXTTRIG_INSERTED_T0_CH3      CTL1_ETSIC(1)                               /*!< TIMER0 CH3 event select */
+#define ADC_EXTTRIG_INSERTED_T1_TRGO     CTL1_ETSIC(2)                               /*!< TIMER1 TRGO event select */
+#define ADC_EXTTRIG_INSERTED_T1_CH0      CTL1_ETSIC(3)                               /*!< TIMER1 CH0 event select */
+#define ADC_EXTTRIG_INSERTED_T2_CH3      CTL1_ETSIC(4)                               /*!< TIMER2 CH3 event select */
+#define ADC_EXTTRIG_INSERTED_T14_TRGO    CTL1_ETSIC(5)                               /*!< TIMER14 TRGO event select */
+#define ADC_EXTTRIG_INSERTED_EXTI_15     CTL1_ETSIC(6)                               /*!< external interrupt line 15 */
+#define ADC_EXTTRIG_INSERTED_NONE        CTL1_ETSIC(7)                               /*!< software trigger */
+
+/* adc_samptx register value */
+#define SAMPTX_SPT(regval)               (BITS(0,2) & ((uint32_t)(regval) << 0))
+#define ADC_SAMPLETIME_1POINT5           SAMPTX_SPT(0)                               /*!< 1.5 sampling cycles */
+#define ADC_SAMPLETIME_7POINT5           SAMPTX_SPT(1)                               /*!< 7.5 sampling cycles */
+#define ADC_SAMPLETIME_13POINT5          SAMPTX_SPT(2)                               /*!< 13.5 sampling cycles */
+#define ADC_SAMPLETIME_28POINT5          SAMPTX_SPT(3)                               /*!< 28.5 sampling cycles */
+#define ADC_SAMPLETIME_41POINT5          SAMPTX_SPT(4)                               /*!< 41.5 sampling cycles */
+#define ADC_SAMPLETIME_55POINT5          SAMPTX_SPT(5)                               /*!< 55.5 sampling cycles */
+#define ADC_SAMPLETIME_71POINT5          SAMPTX_SPT(6)                               /*!< 71.5 sampling cycles */
+#define ADC_SAMPLETIME_239POINT5         SAMPTX_SPT(7)                               /*!< 239.5 sampling cycles */
+
+/* ADC data offset for inserted channel x */
+#define IOFFX_IOFF(regval)               (BITS(0,11) & ((uint32_t)(regval) << 0))
+
+/* ADC analog watchdog high threshold */
+#define WDHT_WDHT(regval)                (BITS(0,11) & ((uint32_t)(regval) << 0))
+
+/* ADC analog watchdog low  threshold */
+#define WDLT_WDLT(regval)                (BITS(0,11) & ((uint32_t)(regval) << 0))
+
+/* ADC regular channel group length */
+#define RSQ0_RL(regval)                  (BITS(20,23) & ((uint32_t)(regval) << 20))
+
+/* ADC inserted channel group length */
+#define ISQ_IL(regval)                   (BITS(20,21) & ((uint32_t)(regval) << 20))
+
+/* ADC resolution definitions */
+#define CTL0_DRES(regval)                (BITS(24,25) & ((uint32_t)(regval) << 24))  /*!< ADC resolution */
+#define ADC_RESOLUTION_12B               CTL0_DRES(0)                                /*!< 12-bit ADC resolution */
+#define ADC_RESOLUTION_10B               CTL0_DRES(1)                                /*!< 10-bit ADC resolution */
+#define ADC_RESOLUTION_8B                CTL0_DRES(2)                                /*!< 8-bit ADC resolution */
+#define ADC_RESOLUTION_6B                CTL0_DRES(3)                                /*!< 6-bit ADC resolution */
+
+/* ADC oversampling shift */
+#define OVSAMPCTL_OVSS(regval)           (BITS(5,8) & ((uint32_t)(regval) << 5))
+#define ADC_OVERSAMPLING_SHIFT_NONE      OVSAMPCTL_OVSS(0)                           /*!< no oversampling shift */
+#define ADC_OVERSAMPLING_SHIFT_1B        OVSAMPCTL_OVSS(1)                           /*!< 1-bit oversampling shift */
+#define ADC_OVERSAMPLING_SHIFT_2B        OVSAMPCTL_OVSS(2)                           /*!< 2-bit oversampling shift */
+#define ADC_OVERSAMPLING_SHIFT_3B        OVSAMPCTL_OVSS(3)                           /*!< 3-bit oversampling shift */
+#define ADC_OVERSAMPLING_SHIFT_4B        OVSAMPCTL_OVSS(4)                           /*!< 4-bit oversampling shift */
+#define ADC_OVERSAMPLING_SHIFT_5B        OVSAMPCTL_OVSS(5)                           /*!< 5-bit oversampling shift */
+#define ADC_OVERSAMPLING_SHIFT_6B        OVSAMPCTL_OVSS(6)                           /*!< 6-bit oversampling shift */
+#define ADC_OVERSAMPLING_SHIFT_7B        OVSAMPCTL_OVSS(7)                           /*!< 7-bit oversampling shift */
+#define ADC_OVERSAMPLING_SHIFT_8B        OVSAMPCTL_OVSS(8)                           /*!< 8-bit oversampling shift */
+
+/* ADC oversampling ratio */
+#define OVSAMPCTL_OVSR(regval)           (BITS(2,4) & ((uint32_t)(regval) << 2))
+#define ADC_OVERSAMPLING_RATIO_MUL2      OVSAMPCTL_OVSR(0)                           /*!< oversampling ratio multiple 2 */
+#define ADC_OVERSAMPLING_RATIO_MUL4      OVSAMPCTL_OVSR(1)                           /*!< oversampling ratio multiple 4 */
+#define ADC_OVERSAMPLING_RATIO_MUL8      OVSAMPCTL_OVSR(2)                           /*!< oversampling ratio multiple 8 */
+#define ADC_OVERSAMPLING_RATIO_MUL16     OVSAMPCTL_OVSR(3)                           /*!< oversampling ratio multiple 16 */
+#define ADC_OVERSAMPLING_RATIO_MUL32     OVSAMPCTL_OVSR(4)                           /*!< oversampling ratio multiple 32 */
+#define ADC_OVERSAMPLING_RATIO_MUL64     OVSAMPCTL_OVSR(5)                           /*!< oversampling ratio multiple 64 */
+#define ADC_OVERSAMPLING_RATIO_MUL128    OVSAMPCTL_OVSR(6)                           /*!< oversampling ratio multiple 128 */
+#define ADC_OVERSAMPLING_RATIO_MUL256    OVSAMPCTL_OVSR(7)                           /*!< oversampling ratio multiple 256 */
+
+/* ADC triggered oversampling */
+#define ADC_OVERSAMPLING_ALL_CONVERT     0U                                          /*!< all oversampled conversions for a channel are done consecutively after a trigger */
+#define ADC_OVERSAMPLING_ONE_CONVERT     1U                                          /*!< each oversampled conversion for a channel needs a trigger */
+
+/* ADC channel group definitions */
+#define ADC_REGULAR_CHANNEL              ((uint8_t)0x01U)                            /*!< ADC regular channel group */
+#define ADC_INSERTED_CHANNEL             ((uint8_t)0x02U)                            /*!< ADC inserted channel group */
+#define ADC_REGULAR_INSERTED_CHANNEL     ((uint8_t)0x03U)                            /*!< both regular and inserted channel group */
+#define ADC_CHANNEL_DISCON_DISABLE       ((uint8_t)0x04U)                            /*!< disable discontinuous mode of regular & inserted channel */
+
+/* ADC inserted channel definitions */
+#define ADC_INSERTED_CHANNEL_0           ((uint8_t)0x00U)                            /*!< ADC inserted channel 0 */
+#define ADC_INSERTED_CHANNEL_1           ((uint8_t)0x01U)                            /*!< ADC inserted channel 1 */
+#define ADC_INSERTED_CHANNEL_2           ((uint8_t)0x02U)                            /*!< ADC inserted channel 2 */
+#define ADC_INSERTED_CHANNEL_3           ((uint8_t)0x03U)                            /*!< ADC inserted channel 3 */
+
+/* ADC channel definitions */
+#define ADC_CHANNEL_0                    ((uint8_t)0x00U)                            /*!< ADC channel 0 */
+#define ADC_CHANNEL_1                    ((uint8_t)0x01U)                            /*!< ADC channel 1 */
+#define ADC_CHANNEL_2                    ((uint8_t)0x02U)                            /*!< ADC channel 2 */
+#define ADC_CHANNEL_3                    ((uint8_t)0x03U)                            /*!< ADC channel 3 */
+#define ADC_CHANNEL_4                    ((uint8_t)0x04U)                            /*!< ADC channel 4 */
+#define ADC_CHANNEL_5                    ((uint8_t)0x05U)                            /*!< ADC channel 5 */
+#define ADC_CHANNEL_6                    ((uint8_t)0x06U)                            /*!< ADC channel 6 */
+#define ADC_CHANNEL_7                    ((uint8_t)0x07U)                            /*!< ADC channel 7 */
+#define ADC_CHANNEL_8                    ((uint8_t)0x08U)                            /*!< ADC channel 8 */
+#define ADC_CHANNEL_9                    ((uint8_t)0x09U)                            /*!< ADC channel 9 */
+#define ADC_CHANNEL_10                   ((uint8_t)0x0AU)                            /*!< ADC channel 10 */
+#define ADC_CHANNEL_11                   ((uint8_t)0x0BU)                            /*!< ADC channel 11 */
+#define ADC_CHANNEL_12                   ((uint8_t)0x0CU)                            /*!< ADC channel 12 */
+#define ADC_CHANNEL_13                   ((uint8_t)0x0DU)                            /*!< ADC channel 13 */
+#define ADC_CHANNEL_14                   ((uint8_t)0x0EU)                            /*!< ADC channel 14 */
+#define ADC_CHANNEL_15                   ((uint8_t)0x0FU)                            /*!< ADC channel 15 */
+#define ADC_CHANNEL_16                   ((uint8_t)0x10U)                            /*!< ADC channel 16 */
+#define ADC_CHANNEL_17                   ((uint8_t)0x11U)                            /*!< ADC channel 17 */
+#define ADC_CHANNEL_18                   ((uint8_t)0x12U)                            /*!< ADC channel 18 */
+
+/* ADC interrupt definitions */
+#define ADC_INT_WDE                      ADC_STAT_WDE                                /*!< analog watchdog event interrupt */
+#define ADC_INT_EOC                      ADC_STAT_EOC                                /*!< end of group conversion interrupt */
+#define ADC_INT_EOIC                     ADC_STAT_EOIC                               /*!< end of inserted group conversion interrupt */
+
+/* ADC interrupt flag */
+#define ADC_INT_FLAG_WDE                 ADC_STAT_WDE                                /*!< analog watchdog event interrupt flag */
+#define ADC_INT_FLAG_EOC                 ADC_STAT_EOC                                /*!< end of group conversion interrupt flag */
+#define ADC_INT_FLAG_EOIC                ADC_STAT_EOIC                               /*!< end of inserted group conversion interrupt flag */
+
+/* function declarations */
+/* reset ADC */
+void adc_deinit(void);
+/* enable ADC interface */
+void adc_enable(void);
+/* disable ADC interface */
+void adc_disable(void);
+
+/* ADC calibration and reset calibration */
+void adc_calibration_enable(void);
+/* enable DMA request */
+void adc_dma_mode_enable(void);
+/* disable DMA request */
+void adc_dma_mode_disable(void);
+
+/* enable the temperature sensor and Vrefint channel */
+void adc_tempsensor_vrefint_enable(void);
+/* disable the temperature sensor and Vrefint channel */
+void adc_tempsensor_vrefint_disable(void);
+/* enable the Vbat channel */
+void adc_vbat_enable(void);
+/* disable the Vbat channel */
+void adc_vbat_disable(void);
+
+/* configure ADC discontinuous mode */
+void adc_discontinuous_mode_config(uint8_t channel_group, uint8_t length);
+/* enable or disable ADC special function */
+void adc_special_function_config(uint32_t function, ControlStatus newvalue);
+
+/* configure ADC data alignment */
+void adc_data_alignment_config(uint32_t data_alignment);
+/* configure the length of regular channel group or inserted channel group */
+void adc_channel_length_config(uint8_t channel_group, uint32_t length);
+/* configure ADC regular channel */
+void adc_regular_channel_config(uint8_t rank, uint8_t channel, uint32_t sample_time);
+/* configure ADC inserted channel */
+void adc_inserted_channel_config(uint8_t rank, uint8_t channel, uint32_t sample_time);
+/* configure ADC inserted channel offset */
+void adc_inserted_channel_offset_config(uint8_t inserted_channel, uint16_t offset);
+/* enable ADC external trigger */
+void adc_external_trigger_config(uint8_t channel_group, ControlStatus newvalue);
+/* configure ADC external trigger source */
+void adc_external_trigger_source_config(uint8_t channel_group, uint32_t external_trigger_source);
+/* enable ADC software trigger */
+void adc_software_trigger_enable(uint8_t channel_group);
+
+/* read ADC regular group data register */
+uint16_t adc_regular_data_read(void);
+/* read ADC inserted group data register */
+uint16_t adc_inserted_data_read(uint8_t inserted_channel);
+
+/* configure ADC analog watchdog single channel */
+void adc_watchdog_single_channel_enable(uint8_t channel);
+/* configure ADC analog watchdog group channel */
+void adc_watchdog_group_channel_enable(uint8_t channel_group);
+/* disable ADC analog watchdog */
+void adc_watchdog_disable(void);
+/* configure ADC analog watchdog threshold */
+void adc_watchdog_threshold_config(uint16_t low_threshold, uint16_t high_threshold);
+
+/* configure ADC resolution */
+void adc_resolution_config(uint32_t resolution);
+/* configure ADC oversample mode */
+void adc_oversample_mode_config(uint8_t mode, uint16_t shift, uint8_t ratio);
+/* enable ADC oversample mode */
+void adc_oversample_mode_enable(void);
+/* disable ADC oversample mode */
+void adc_oversample_mode_disable(void);
+
+/* get the ADC flag bits */
+FlagStatus adc_flag_get(uint32_t flag);
+/* clear the ADC flag bits */
+void adc_flag_clear(uint32_t flag);
+/* enable ADC interrupt */
+void adc_interrupt_enable(uint32_t interrupt);
+/* disable ADC interrupt */
+void adc_interrupt_disable(uint32_t interrupt);
+/* get the ADC interrupt bits */
+FlagStatus adc_interrupt_flag_get(uint32_t flag);
+/* clear the ADC interrupt flag */
+void adc_interrupt_flag_clear(uint32_t flag);
+
+#endif /* GD32F3X0_ADC_H */

+ 249 - 0
GD32F3x0/GD32F3x0_standard_peripheral/Include/gd32f3x0_cec.h

@@ -0,0 +1,249 @@
+/*!
+    \file    gd32f3x0_cec.h
+    \brief   definitions for the CEC
+
+    \version 2025-01-01, V2.5.0, firmware for GD32F3x0
+*/
+
+/*
+    Copyright (c) 2025, GigaDevice Semiconductor Inc.
+
+    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 of the copyright holder 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 HOLDER 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.
+*/
+
+#if defined(GD32F350)||defined(GD32F355)||defined(GD32F370)
+
+#ifndef GD32F3X0_CEC_H
+#define GD32F3X0_CEC_H
+
+#include "gd32f3x0.h"
+
+/* CEC definitions */
+#define CEC                                CEC_BASE                   /*!< CEC base address */
+
+/* registers definitions */
+#define CEC_CTL                            REG32(CEC + 0x00000000U)   /*!< CEC control register */
+#define CEC_CFG                            REG32(CEC + 0x00000004U)   /*!< CEC configuration register */
+#define CEC_TDATA                          REG32(CEC + 0x00000008U)   /*!< CEC transmit data register */
+#define CEC_RDATA                          REG32(CEC + 0x0000000CU)   /*!< CEC receive data register */
+#define CEC_INTF                           REG32(CEC + 0x00000010U)   /*!< CEC interrupt flag Register */
+#define CEC_INTEN                          REG32(CEC + 0x00000014U)   /*!< CEC interrupt enable register */
+
+/* bits definitions */
+/* CEC_CTL */
+#define CEC_CTL_CECEN                      BIT(0)                     /*!< enable or disable HDMI-CEC controller bit */
+#define CEC_CTL_STAOM                      BIT(1)                     /*!< start of sending a message. */
+#define CEC_CTL_ENDOM                      BIT(2)                     /*!< ENDOM bit value in the next frame in Tx mode */
+
+/* CEC_CFG */
+#define CEC_CFG_SFT                        BITS(0,2)                  /*!< signal free time */
+#define CEC_CFG_RTOL                       BIT(3)                     /*!< reception bit timing tolerance */
+#define CEC_CFG_BRES                       BIT(4)                     /*!< whether stop receive message when detected BRE */
+#define CEC_CFG_BREG                       BIT(5)                     /*!< generate Error-bit when detected BRE in singlecast */
+#define CEC_CFG_BPLEG                      BIT(6)                     /*!< generate Error-bit when detected BPLE in singlecast */
+#define CEC_CFG_BCNG                       BIT(7)                     /*!< do not generate Error-bit in broadcast message */
+#define CEC_CFG_SFTOPT                     BIT(8)                     /*!< the SFT start option bit */
+#define CEC_CFG_OAD                        BITS(16,30)                /*!< own address */
+#define CEC_CFG_LMEN                       BIT(31)                    /*!< listen mode enable bit */
+
+/* CEC_TDATA */
+#define CEC_TDATA_TDATA                    BITS(0,7)                  /*!< Tx data register */
+
+/* CEC_RDATA */
+#define CEC_RDATA_RDATA                    BITS(0,7)                  /*!< Rx data register */
+
+/* CEC_INTF */
+#define CEC_INTF_BR                        BIT(0)                     /*!< Rx-byte data received */
+#define CEC_INTF_REND                      BIT(1)                     /*!< end of reception */
+#define CEC_INTF_RO                        BIT(2)                     /*!< Rx overrun */
+#define CEC_INTF_BRE                       BIT(3)                     /*!< bit rising error */
+#define CEC_INTF_BPSE                      BIT(4)                     /*!< short bit period error */
+#define CEC_INTF_BPLE                      BIT(5)                     /*!< long bit period error */
+#define CEC_INTF_RAE                       BIT(6)                     /*!< Rx ACK error */
+#define CEC_INTF_ARBF                      BIT(7)                     /*!< arbitration fail */
+#define CEC_INTF_TBR                       BIT(8)                     /*!< Tx-byte data request */
+#define CEC_INTF_TEND                      BIT(9)                     /*!< transmission successfully end */
+#define CEC_INTF_TU                        BIT(10)                    /*!< Tx data buffer underrun */
+#define CEC_INTF_TERR                      BIT(11)                    /*!< Tx-error */
+#define CEC_INTF_TAERR                     BIT(12)                    /*!< Tx ACK error flag */
+
+/* CEC_INTEN */
+#define CEC_INTEN_BRIE                     BIT(0)                     /*!< BR interrupt enable */
+#define CEC_INTEN_RENDIE                   BIT(1)                     /*!< REND interrupt enable */
+#define CEC_INTEN_ROIE                     BIT(2)                     /*!< RO interrupt enable */
+#define CEC_INTEN_BREIE                    BIT(3)                     /*!< BRE interrupt enable. */
+#define CEC_INTEN_BPSEIE                   BIT(4)                     /*!< BPSE interrupt enable */
+#define CEC_INTEN_BPLEIE                   BIT(5)                     /*!< BPLE interrupt enable. */
+#define CEC_INTEN_RAEIE                    BIT(6)                     /*!< RAE interrupt enable */
+#define CEC_INTEN_ARBFIE                   BIT(7)                     /*!< ARBF interrupt enable */
+#define CEC_INTEN_TBRIE                    BIT(8)                     /*!< TBR interrupt enable */
+#define CEC_INTEN_TENDIE                   BIT(9)                     /*!< TEND interrupt enable */
+#define CEC_INTEN_TUIE                     BIT(10)                    /*!< TU interrupt enable */
+#define CEC_INTEN_TERRIE                   BIT(11)                    /*!< TE interrupt enable */
+#define CEC_INTEN_TAERRIE                  BIT(12)                    /*!< TAE interrupt enable */
+
+/* constants definitions */
+/* signal free time */
+#define CFG_SFT(regval)                    (BITS(0, 2) & ((regval) << 0U))
+#define CEC_SFT_PROTOCOL_PERIOD            CFG_SFT(0)                 /*!< the signal free time will perform as HDMI-CEC protocol description */
+#define CEC_SFT_1POINT5_PERIOD             CFG_SFT(1)                 /*!< 1.5 nominal data bit periods */
+#define CEC_SFT_2POINT5_PERIOD             CFG_SFT(2)                 /*!< 2.5 nominal data bit periods */
+#define CEC_SFT_3POINT5_PERIOD             CFG_SFT(3)                 /*!< 3.5 nominal data bit periods */
+#define CEC_SFT_4POINT5_PERIOD             CFG_SFT(4)                 /*!< 4.5 nominal data bit periods */
+#define CEC_SFT_5POINT5_PERIOD             CFG_SFT(5)                 /*!< 5.5 nominal data bit periods */
+#define CEC_SFT_6POINT5_PERIOD             CFG_SFT(6)                 /*!< 6.5 nominal data bit periods */
+#define CEC_SFT_7POINT5_PERIOD             CFG_SFT(7)                 /*!< 7.5 nominal data bit periods */
+
+/* signal free time start option */
+#define CEC_SFT_START_STAOM                ((uint32_t)0x00000000U)    /*!< signal free time counter starts counting when STAOM is asserted */
+#define CEC_SFT_START_LAST                 CEC_CFG_SFTOPT             /*!< signal free time counter starts automatically after transmission/reception end */
+
+/* own address */
+#define CEC_OWN_ADDRESS_CLEAR              ((uint32_t)0x00000000U)    /*!< own address is cleared */
+#define CEC_OWN_ADDRESS0                   BIT(16)                    /*!< own address is 0 */
+#define CEC_OWN_ADDRESS1                   BIT(17)                    /*!< own address is 1 */
+#define CEC_OWN_ADDRESS2                   BIT(18)                    /*!< own address is 2 */
+#define CEC_OWN_ADDRESS3                   BIT(19)                    /*!< own address is 3 */
+#define CEC_OWN_ADDRESS4                   BIT(20)                    /*!< own address is 4 */
+#define CEC_OWN_ADDRESS5                   BIT(21)                    /*!< own address is 5 */
+#define CEC_OWN_ADDRESS6                   BIT(22)                    /*!< own address is 6 */
+#define CEC_OWN_ADDRESS7                   BIT(23)                    /*!< own address is 7 */
+#define CEC_OWN_ADDRESS8                   BIT(24)                    /*!< own address is 8 */
+#define CEC_OWN_ADDRESS9                   BIT(25)                    /*!< own address is 9 */
+#define CEC_OWN_ADDRESS10                  BIT(26)                    /*!< own address is 10 */
+#define CEC_OWN_ADDRESS11                  BIT(27)                    /*!< own address is 11 */
+#define CEC_OWN_ADDRESS12                  BIT(28)                    /*!< own address is 12 */
+#define CEC_OWN_ADDRESS13                  BIT(29)                    /*!< own address is 13 */
+#define CEC_OWN_ADDRESS14                  BIT(30)                    /*!< own address is 14 */
+
+/* error-bit generate */
+#define CEC_BROADCAST_ERROR_BIT_ON         ((uint32_t)0x00000000U)    /*!< generate Error-bit in broadcast */
+#define CEC_BROADCAST_ERROR_BIT_OFF        CEC_CFG_BCNG               /*!< do not generate Error-bit in broadcast */
+#define CEC_LONG_PERIOD_ERROR_BIT_OFF      ((uint32_t)0x00000000U)    /*!< generate Error-bit on long bit period error */
+#define CEC_LONG_PERIOD_ERROR_BIT_ON       CEC_CFG_BPLEG              /*!< do not generate Error-bit on long bit period error */
+#define CEC_RISING_PERIOD_ERROR_BIT_OFF    ((uint32_t)0x00000000U)    /*!< generate Error-bit on bit rising error */
+#define CEC_RISING_PERIOD_ERROR_BIT_ON     CEC_CFG_BREG               /*!< do not generate Error-bit on bit rising error */
+
+/* whether stop receive message when detected bit rising error */
+#define CEC_STOP_RISING_ERROR_BIT_ON       ((uint32_t)0x00000000U)    /*!< stop reception when detected bit rising error */
+#define CEC_STOP_RISING_ERROR_BIT_OFF      ((uint32_t)0x00000001U)    /*!< do not stop reception when detected bit rising error */
+
+/* flag bits */
+#define CEC_FLAG_BR                        CEC_INTF_BR                /*!< RX-byte data received */
+#define CEC_FLAG_REND                      CEC_INTF_REND              /*!< end of reception */
+#define CEC_FLAG_RO                        CEC_INTF_RO                /*!< RX overrun */
+#define CEC_FLAG_BRE                       CEC_INTF_BRE               /*!< bit rising error */
+#define CEC_FLAG_BPSE                      CEC_INTF_BPSE              /*!< short bit period error */
+#define CEC_FLAG_BPLE                      CEC_INTF_BPLE              /*!< long bit period error */
+#define CEC_FLAG_RAE                       CEC_INTF_RAE               /*!< RX ACK error */
+#define CEC_FLAG_ARBF                      CEC_INTF_ARBF              /*!< arbitration lost */
+#define CEC_FLAG_TBR                       CEC_INTF_TBR               /*!< TX-byte data request */
+#define CEC_FLAG_TEND                      CEC_INTF_TEND              /*!< transmission successfully end */
+#define CEC_FLAG_TU                        CEC_INTF_TU                /*!< TX data buffer underrun */
+#define CEC_FLAG_TERR                      CEC_INTF_TERR              /*!< TX-error */
+#define CEC_FLAG_TAERR                     CEC_INTF_TAERR             /*!< TX ACK error flag */
+
+/* interrupt flag bits */
+#define CEC_INT_FLAG_BR                    CEC_INTF_BR                /*!< RX-byte data received */
+#define CEC_INT_FLAG_REND                  CEC_INTF_REND              /*!< end of reception */
+#define CEC_INT_FLAG_RO                    CEC_INTF_RO                /*!< RX overrun */
+#define CEC_INT_FLAG_BRE                   CEC_INTF_BRE               /*!< bit rising error */
+#define CEC_INT_FLAG_BPSE                  CEC_INTF_BPSE              /*!< short bit period error */
+#define CEC_INT_FLAG_BPLE                  CEC_INTF_BPLE              /*!< long bit period error */
+#define CEC_INT_FLAG_RAE                   CEC_INTF_RAE               /*!< RX ACK error */
+#define CEC_INT_FLAG_ARBF                  CEC_INTF_ARBF              /*!< arbitration lost */
+#define CEC_INT_FLAG_TBR                   CEC_INTF_TBR               /*!< TX-byte data request */
+#define CEC_INT_FLAG_TEND                  CEC_INTF_TEND              /*!< transmission successfully end */
+#define CEC_INT_FLAG_TU                    CEC_INTF_TU                /*!< TX data buffer underrun */
+#define CEC_INT_FLAG_TERR                  CEC_INTF_TERR              /*!< TX-error */
+#define CEC_INT_FLAG_TAERR                 CEC_INTF_TAERR             /*!< TX ACK error flag */
+
+/* interrupt enable bits */
+#define CEC_INT_BR                         CEC_INTEN_BRIE             /*!< RBR interrupt enable */
+#define CEC_INT_REND                       CEC_INTEN_RENDIE           /*!< REND interrupt enable */
+#define CEC_INT_RO                         CEC_INTEN_ROIE             /*!< RO interrupt enable */
+#define CEC_INT_BRE                        CEC_INTEN_BREIE            /*!< RBRE interrupt enable. */
+#define CEC_INT_BPSE                       CEC_INTEN_BPSEIE           /*!< RSBPE interrupt enable */
+#define CEC_INT_BPLE                       CEC_INTEN_BPLEIE           /*!< RLBPE interrupt enable. */
+#define CEC_INT_RAE                        CEC_INTEN_RAEIE            /*!< RAE interrupt enable */
+#define CEC_INT_ARBF                       CEC_INTEN_ARBFIE           /*!< ALRLST interrupt enable */
+#define CEC_INT_TBR                        CEC_INTEN_TBRIE            /*!< TBR interrupt enable */
+#define CEC_INT_TEND                       CEC_INTEN_TENDIE           /*!< TEND interrupt enable */
+#define CEC_INT_TU                         CEC_INTEN_TUIE             /*!< TU interrupt enable */
+#define CEC_INT_TERR                       CEC_INTEN_TERRIE           /*!< TE interrupt enable */
+#define CEC_INT_TAERR                      CEC_INTEN_TAERRIE          /*!< TAE interrupt enable */
+
+/* function declarations */
+/* reset HDMI-CEC controller */
+void cec_deinit(void);
+/* configure signal free time,the signal free time counter start option,own address */
+void cec_init(uint32_t sftmopt, uint32_t sft, uint32_t address);
+/* configure generate Error-bit, whether stop receive message when detected bit rising error */
+void cec_error_config(uint32_t broadcast, uint32_t singlecast_lbpe, uint32_t singlecast_bre, uint32_t rxbrestp);
+/* enable HDMI-CEC controller */
+void cec_enable(void);
+/* disable HDMI-CEC controller */
+void cec_disable(void);
+
+/* start CEC message transmission */
+void cec_transmission_start(void);
+/* end CEC message transmission */
+void cec_transmission_end(void);
+/* enable CEC listen mode */
+void cec_listen_mode_enable(void);
+/* disable CEC listen mode */
+void cec_listen_mode_disable(void);
+/* configure and clear own address */
+void cec_own_address_config(uint32_t address);
+/* configure signal free time and the signal free time counter start option */
+void cec_sft_config(uint32_t sftmopt, uint32_t sft);
+/* configure generate Error-bit when detected some abnormal situation or not */
+void cec_generate_errorbit_config(uint32_t broadcast, uint32_t singlecast_lbpe, uint32_t singlecast_bre);
+/* whether stop receive message when detected bit rising error */
+void cec_stop_receive_bre_config(uint32_t rxbrestp);
+/* enable reception bit timing tolerance */
+void cec_reception_tolerance_enable(void);
+/* disable reception bit timing tolerance */
+void cec_reception_tolerance_disable(void);
+/* send a data by the CEC peripheral */
+void cec_data_send(uint8_t data);
+/* receive a data by the CEC peripheral */
+uint8_t cec_data_receive(void);
+
+/* enable interrupt */
+void cec_interrupt_enable(uint32_t flag);
+/* disable interrupt */
+void cec_interrupt_disable(uint32_t flag);
+/* get CEC status */
+FlagStatus cec_flag_get(uint32_t flag);
+/* clear CEC status */
+void cec_flag_clear(uint32_t flag);
+/* get CEC int flag and status */
+FlagStatus cec_interrupt_flag_get(uint32_t flag);
+/* clear CEC int flag and status */
+void cec_interrupt_flag_clear(uint32_t flag);
+
+#endif /* GD32F3X0_CEC_H */
+
+#endif /* defined(GD32F350)||defined(GD32F355)||defined(GD32F370) */

+ 147 - 0
GD32F3x0/GD32F3x0_standard_peripheral/Include/gd32f3x0_cmp.h

@@ -0,0 +1,147 @@
+/*!
+    \file    gd32f3x0_cmp.h
+    \brief   definitions for the CMP
+
+    \version 2025-01-01, V2.5.0, firmware for GD32F3x0
+*/
+
+/*
+    Copyright (c) 2025, GigaDevice Semiconductor Inc.
+
+    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 of the copyright holder 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 HOLDER 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.
+*/
+
+#ifndef GD32F3X0_CMP_H
+#define GD32F3X0_CMP_H
+
+#include "gd32f3x0.h"
+
+/* CMP definitions */
+#define CMP                                      CMP_BASE                       /*!< CMP base address */
+
+/* registers definitions */
+#define CMP_CS                                   REG32((CMP) + 0x00000000U)     /*!< CMP control and status register */
+
+/* bits definitions */
+/* CMP_CS */
+#define CMP_CS_CMP0EN                            BIT(0)                         /*!< CMP0 enable */
+#define CMP_CS_CMP0SW                            BIT(1)                         /*!< CMP switch mode enable */
+#define CMP_CS_CMP0M                             BITS(2,3)                      /*!< CMP0 mode */
+#define CMP_CS_CMP0MSEL                          BITS(4,6)                      /*!< CMP_IM input selection */
+#define CMP_CS_CMP0OSEL                          BITS(8,10)                     /*!< CMP0 output selection */
+#define CMP_CS_CMP0PL                            BIT(11)                        /*!< CMP0 output polarity */
+#define CMP_CS_CMP0HST                           BITS(12,13)                    /*!< CMP0 hysteresis */
+#define CMP_CS_CMP0O                             BIT(14)                        /*!< CMP0 output state bit */
+#define CMP_CS_CMP0LK                            BIT(15)                        /*!< CMP0 lock */
+#define CMP_CS_CMP1EN                            BIT(16)                        /*!< CMP1 enable */
+#define CMP_CS_CMP1M                             BITS(18,19)                    /*!< CMP1 mode */
+#define CMP_CS_CMP1MSEL                          BITS(20,22)                    /*!< CMP_IM input selection */
+#define CMP_CS_WNDEN                             BIT(23)                        /*!< CMP window mode enable */
+#define CMP_CS_CMP1OSEL                          BITS(24,26)                    /*!< CMP1 output selection */
+#define CMP_CS_CMP1PL                            BIT(27)                        /*!< CMP1 output polarity */
+#define CMP_CS_CMP1HST                           BITS(28,29)                    /*!< CMP1 hysteresis */
+#define CMP_CS_CMP1O                             BIT(30)                        /*!< CMP1 output state bit */
+#define CMP_CS_CMP1LK                            BIT(31)                        /*!< CMP1 lock */
+
+/* constants definitions */
+/* CMP units */
+typedef enum{
+    CMP0,                                                                       /*!< comparator 0 */
+    CMP1                                                                        /*!< comparator 1 */
+}cmp_enum;
+
+/* CMP operating mode */
+#define CS_CMPXM(regval)                         (BITS(2,3) & ((uint32_t)(regval) << 2U))
+#define CMP_MODE_HIGHSPEED                       CS_CMPXM(0)                    /*!< CMP mode high speed */
+#define CMP_MODE_MIDDLESPEED                     CS_CMPXM(1)                    /*!< CMP mode middle speed */
+#define CMP_MODE_LOWSPEED                        CS_CMPXM(2)                    /*!< CMP mode low speed */
+#define CMP_MODE_VERYLOWSPEED                    CS_CMPXM(3)                    /*!< CMP mode very low speed */
+
+/* CMP hysteresis */
+#define CS_CMPXHST(regval)                       (BITS(12,13) & ((uint32_t)(regval) << 12U))
+#define CMP_HYSTERESIS_NO                        CS_CMPXHST(0)                  /*!< CMP output no hysteresis */
+#define CMP_HYSTERESIS_LOW                       CS_CMPXHST(1)                  /*!< CMP output low hysteresis */
+#define CMP_HYSTERESIS_MIDDLE                    CS_CMPXHST(2)                  /*!< CMP output middle hysteresis */
+#define CMP_HYSTERESIS_HIGH                      CS_CMPXHST(3)                  /*!< CMP output high hysteresis */
+
+/* CMP inverting input */
+#define CS_CMPXMSEL(regval)                      (BITS(4,6) & ((uint32_t)(regval) << 4U))
+#define CMP_INVERTING_INPUT_1_4VREFINT           CS_CMPXMSEL(0)                 /*!< CMP inverting input 1/4 Vrefint */
+#define CMP_INVERTING_INPUT_1_2VREFINT           CS_CMPXMSEL(1)                 /*!< CMP inverting input 1/2 Vrefint */
+#define CMP_INVERTING_INPUT_3_4VREFINT           CS_CMPXMSEL(2)                 /*!< CMP inverting input 3/4 Vrefint */
+#define CMP_INVERTING_INPUT_VREFINT              CS_CMPXMSEL(3)                 /*!< CMP inverting input Vrefint */
+#define CMP_INVERTING_INPUT_PA4                  CS_CMPXMSEL(4)                 /*!< CMP inverting input PA4(DAC0_OUT0) */
+#define CMP_INVERTING_INPUT_PA5                  CS_CMPXMSEL(5)                 /*!< CMP inverting input PA5 */
+#define CMP_INVERTING_INPUT_PA0_PA2              CS_CMPXMSEL(6)                 /*!< CMP inverting input PA0 for CMP0 or PA2 for CMP1 */
+
+/* CMP output */
+#define CS_CMPXOSEL(regval)                      (BITS(8,10) & ((uint32_t)(regval) << 8U))
+#define CMP_OUTPUT_NONE                          CS_CMPXOSEL(0)                 /*!< CMP output none */
+#define CMP_OUTPUT_TIMER0_BRKIN                  CS_CMPXOSEL(1)                 /*!< CMP output TIMER0 break input */
+#define CMP_OUTPUT_TIMER0_IC0                    CS_CMPXOSEL(2)                 /*!< CMP output TIMER0_CH0 input capture */
+#define CMP_OUTPUT_TIMER0_OCPRECLR               CS_CMPXOSEL(3)                 /*!< CMP output TIMER0 OCPRE_CLR input */
+#define CMP_OUTPUT_TIMER1_IC3                    CS_CMPXOSEL(4)                 /*!< CMP output TIMER1_CH3 input capture */
+#define CMP_OUTPUT_TIMER1_OCPRECLR               CS_CMPXOSEL(5)                 /*!< CMP output TIMER1 OCPRE_CLR input */
+#define CMP_OUTPUT_TIMER2_IC0                    CS_CMPXOSEL(6)                 /*!< CMP output TIMER2_CH0 input capture */
+#define CMP_OUTPUT_TIMER2_OCPRECLR               CS_CMPXOSEL(7)                 /*!< CMP output TIMER2 OCPRE_CLR input */
+
+/* CMP output polarity*/
+#define CS_CMPXPL(regval)                        (BIT(11) & ((uint32_t)(regval) << 11U))
+#define CMP_OUTPUT_POLARITY_NONINVERTED          CS_CMPXPL(0)                   /*!< CMP output not inverted */
+#define CMP_OUTPUT_POLARITY_INVERTED             CS_CMPXPL(1)                   /*!< CMP output inverted */
+
+/* CMP output level */
+#define CMP_OUTPUTLEVEL_HIGH                     ((uint32_t)0x00000001U)        /*!< CMP output high */
+#define CMP_OUTPUTLEVEL_LOW                      ((uint32_t)0x00000000U)        /*!< CMP output low */
+
+/* function declarations */
+/* initialization functions */
+/* CMP deinit */
+void cmp_deinit(cmp_enum cmp_periph);
+/* CMP mode init */
+void cmp_mode_init(cmp_enum cmp_periph, uint32_t operating_mode, uint32_t inverting_input, uint32_t output_hysteresis);
+/* CMP output init */
+void cmp_output_init(cmp_enum cmp_periph, uint32_t output_selection, uint32_t output_polarity);
+
+/* enable functions */
+/* enable CMP */
+void cmp_enable(cmp_enum cmp_periph);
+/* disable CMP */
+void cmp_disable(cmp_enum cmp_periph);
+/* enable CMP switch */
+void cmp_switch_enable(void);
+/* disable CMP switch */
+void cmp_switch_disable(void);
+/* enable the window mode */
+void cmp_window_enable(void);
+/* disable the window mode */
+void cmp_window_disable(void);
+/* lock the CMP */
+void cmp_lock_enable(cmp_enum cmp_periph);
+
+/* get state related functions */
+/* get output level */
+uint32_t cmp_output_level_get(cmp_enum cmp_periph);
+
+#endif /* GD32F3X0_CMP_H */

+ 123 - 0
GD32F3x0/GD32F3x0_standard_peripheral/Include/gd32f3x0_crc.h

@@ -0,0 +1,123 @@
+/*!
+    \file    gd32f3x0_crc.h
+    \brief   definitions for the CRC
+
+    \version 2025-01-01, V2.5.0, firmware for GD32F3x0
+*/
+
+/*
+    Copyright (c) 2025, GigaDevice Semiconductor Inc.
+
+    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 of the copyright holder 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 HOLDER 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.
+*/
+
+#ifndef GD32F3X0_CRC_H
+#define GD32F3X0_CRC_H
+
+#include "gd32f3x0.h"
+
+/* CRC definitions */
+#define CRC                            CRC_BASE
+
+/* registers definitions */
+#define CRC_DATA                       REG32(CRC + 0x00000000U)            /*!< CRC data register */
+#define CRC_FDATA                      REG32(CRC + 0x00000004U)            /*!< CRC free data register */
+#define CRC_CTL                        REG32(CRC + 0x00000008U)            /*!< CRC control register */
+#define CRC_IDATA                      REG32(CRC + 0x00000010U)            /*!< CRC initialization data register */
+#define CRC_POLY                       REG32(CRC + 0x00000014U)            /*!< CRC polynomial register */
+
+/* bits definitions */
+/* CRC_DATA */
+#define CRC_DATA_DATA                  BITS(0,31)                      /*!< CRC data bits */
+
+/* CRC_FDATA */
+#define CRC_FDATA_FDATA                BITS(0,7)                       /*!< CRC free data bits */
+
+/* CRC_CTL */
+#define CRC_CTL_RST                    BIT(0)                          /*!< CRC reset bit */
+#define CRC_CTL_PS                     BITS(3,4)                       /*!< size of polynomial function bits */
+#define CRC_CTL_REV_I                  BITS(5,6)                       /*!< input data reverse function bits */
+#define CRC_CTL_REV_O                  BIT(7)                          /*!< output data reverse function bit */
+
+/* CRC_INIT */
+#define CRC_IDATA_IDATA                BITS(0,31)                      /*!< CRC initialization data bits */
+
+/* CRC_POLY */
+#define CRC_POLY_POLY                  BITS(0,31)                      /*!< CRC polynomial value bits */
+
+/* constants definitions */
+/* size of polynomial function */
+#define CTL_PS(regval)                 (BITS(3, 4) & ((regval) << 3))
+#define CRC_CTL_PS_32                  CTL_PS(0)                       /*!< 32-bit polynomial for CRC calculation */
+#define CRC_CTL_PS_16                  CTL_PS(1)                       /*!< 16-bit polynomial for CRC calculation */
+#define CRC_CTL_PS_8                   CTL_PS(2)                       /*!< 8-bit polynomial for CRC calculation */
+#define CRC_CTL_PS_7                   CTL_PS(3)                       /*!< 7-bit polynomial for CRC calculation */
+
+/* input data reverse function */
+#define CTL_REV_I(regval)              (BITS(5, 6) & ((regval) << 5))
+#define CRC_INPUT_DATA_NOT             CTL_REV_I(0)                    /*!< input data not reverse */
+#define CRC_INPUT_DATA_BYTE            CTL_REV_I(1)                    /*!< input data reversed by byte type */
+#define CRC_INPUT_DATA_HALFWORD        CTL_REV_I(2)                    /*!< input data reversed by half-word type */
+#define CRC_INPUT_DATA_WORD            CTL_REV_I(3)                    /*!< input data reversed by word type */
+
+/* input data format */
+#define INPUT_FORMAT_WORD              0U                              /*!< input data in word format */
+#define INPUT_FORMAT_HALFWORD          1U                              /*!< input data in half-word format */
+#define INPUT_FORMAT_BYTE              2U                              /*!< input data in byte format */
+
+/* function declarations */
+/* deinit CRC calculation unit */
+void crc_deinit(void);
+
+/* enable the reverse operation of output data */
+void crc_reverse_output_data_enable(void);
+/* disable the reverse operation of output data */
+void crc_reverse_output_data_disable(void);
+
+/* reset data register to the value of initializaiton data register */
+void crc_data_register_reset(void);
+/* read the data register  */
+uint32_t crc_data_register_read(void);
+
+/* read the free data register */
+uint8_t crc_free_data_register_read(void);
+/* write the free data register */
+void crc_free_data_register_write(uint8_t free_data);
+
+/* write the initial value register */
+void crc_init_data_register_write(uint32_t init_data);
+/* configure the CRC input data function */
+void crc_input_data_reverse_config(uint32_t data_reverse);
+
+/* configure the CRC size of polynomial function */
+void crc_polynomial_size_set(uint32_t poly_size);
+/* configure the CRC polynomial value function */
+void crc_polynomial_set(uint32_t poly);
+
+/* CRC calculate single data */
+uint32_t crc_single_data_calculate(uint32_t sdata, uint8_t data_format);
+/* CRC calculate a data array */
+uint32_t crc_block_data_calculate(void *array, uint32_t size, uint8_t data_format);
+
+#endif /* GD32F3X0_CRC_H */

+ 186 - 0
GD32F3x0/GD32F3x0_standard_peripheral/Include/gd32f3x0_ctc.h

@@ -0,0 +1,186 @@
+/*!
+    \file    gd32f3x0_ctc.h
+    \brief   definitions for the CTC
+
+    \version 2025-01-01, V2.5.0, firmware for GD32F3x0
+*/
+
+/*
+    Copyright (c) 2025, GigaDevice Semiconductor Inc.
+
+    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 of the copyright holder 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 HOLDER 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.
+*/
+
+#ifndef GD32F3X0_CTC_H
+#define GD32F3X0_CTC_H
+
+#include "gd32f3x0.h"
+
+/* CTC definitions */
+#define CTC                          CTC_BASE                  /*!< base address */
+
+/* registers definitions */
+#define CTC_CTL0                     REG32((CTC) + 0x00000000U)  /*!< CTC control register 0 */
+#define CTC_CTL1                     REG32((CTC) + 0x00000004U)  /*!< CTC control register 1 */
+#define CTC_STAT                     REG32((CTC) + 0x00000008U)  /*!< CTC status register */
+#define CTC_INTC                     REG32((CTC) + 0x0000000CU)  /*!< CTC interrupt clear register */
+
+/* bits definitions */
+/* CTC_CTL0 */
+#define CTC_CTL0_CKOKIE              BIT(0)                    /*!< clock trim OK(CKOKIF) interrupt enable */
+#define CTC_CTL0_CKWARNIE            BIT(1)                    /*!< clock trim warning(CKWARNIF) interrupt enable */
+#define CTC_CTL0_ERRIE               BIT(2)                    /*!< error(ERRIF) interrupt enable */
+#define CTC_CTL0_EREFIE              BIT(3)                    /*!< EREFIF interrupt enable */
+#define CTC_CTL0_CNTEN               BIT(5)                    /*!< CTC counter enable */
+#define CTC_CTL0_AUTOTRIM            BIT(6)                    /*!< hardware automatically trim mode */
+#define CTC_CTL0_SWREFPUL            BIT(7)                    /*!< software reference source sync pulse */
+#define CTC_CTL0_TRIMVALUE           BITS(8,13)                /*!< IRC48M trim value */
+
+/* CTC_CTL1 */
+#define CTC_CTL1_RLVALUE             BITS(0,15)                /*!< CTC counter reload value */
+#define CTC_CTL1_CKLIM               BITS(16,23)               /*!< clock trim base limit value */
+#define CTC_CTL1_REFPSC              BITS(24,26)               /*!< reference signal source prescaler */
+#define CTC_CTL1_REFSEL              BITS(28,29)               /*!< reference signal source selection */
+#define CTC_CTL1_REFPOL              BIT(31)                   /*!< reference signal source polarity */
+
+/* CTC_STAT */
+#define CTC_STAT_CKOKIF              BIT(0)                    /*!< clock trim OK interrupt flag */
+#define CTC_STAT_CKWARNIF            BIT(1)                    /*!< clock trim warning interrupt flag */
+#define CTC_STAT_ERRIF               BIT(2)                    /*!< error interrupt flag */
+#define CTC_STAT_EREFIF              BIT(3)                    /*!< expect reference interrupt flag */
+#define CTC_STAT_CKERR               BIT(8)                    /*!< clock trim error bit */
+#define CTC_STAT_REFMISS             BIT(9)                    /*!< reference sync pulse miss */
+#define CTC_STAT_TRIMERR             BIT(10)                   /*!< trim value error bit */
+#define CTC_STAT_REFDIR              BIT(15)                   /*!< CTC trim counter direction when reference sync pulse occurred */
+#define CTC_STAT_REFCAP              BITS(16,31)               /*!< CTC counter capture when reference sync pulse occurred */
+
+/* CTC_INTC */
+#define CTC_INTC_CKOKIC              BIT(0)                    /*!< CKOKIF interrupt clear bit */
+#define CTC_INTC_CKWARNIC            BIT(1)                    /*!< CKWARNIF interrupt clear bit */
+#define CTC_INTC_ERRIC               BIT(2)                    /*!< ERRIF interrupt clear bit */
+#define CTC_INTC_EREFIC              BIT(3)                    /*!< EREFIF interrupt clear bit */
+
+/* constants definitions */
+#define CTL0_TRIMVALUE(regval)                           (BITS(8,13) & ((uint32_t)(regval) << 8))
+#define CTL1_CKLIM(regval)                               (BITS(16,23) & ((uint32_t)(regval) << 16))
+#define GET_STAT_REFCAP(regval)                          GET_BITS((regval),16,31)
+#define GET_CTL0_TRIMVALUE(regval)                       GET_BITS((regval),8,13)
+
+/* hardware automatically trim mode definitions */
+#define CTC_HARDWARE_TRIM_MODE_ENABLE                    CTC_CTL0_AUTOTRIM            /*!< hardware automatically trim mode enable*/
+#define CTC_HARDWARE_TRIM_MODE_DISABLE                   ((uint32_t)0x00000000U)      /*!< hardware automatically trim mode disable*/
+
+/* reference signal source polarity definitions */
+#define CTC_REFSOURCE_POLARITY_FALLING                   CTC_CTL1_REFPOL              /*!< reference signal source polarity is falling edge*/
+#define CTC_REFSOURCE_POLARITY_RISING                    ((uint32_t)0x00000000U)      /*!< reference signal source polarity is rising edge*/
+
+/* reference signal source selection definitions */
+#define CTL1_REFSEL(regval)                              (BITS(28,29) & ((uint32_t)(regval) << 28))
+#define CTC_REFSOURCE_GPIO                               CTL1_REFSEL(0)               /*!< GPIO is selected */
+#define CTC_REFSOURCE_LXTAL                              CTL1_REFSEL(1)               /*!< LXTAL is clock selected */
+
+/* reference signal source prescaler definitions */
+#define CTL1_REFPSC(regval)                              (BITS(24,26) & ((uint32_t)(regval) << 24))
+#define CTC_REFSOURCE_PSC_OFF                            CTL1_REFPSC(0)               /*!< reference signal not divided */
+#define CTC_REFSOURCE_PSC_DIV2                           CTL1_REFPSC(1)               /*!< reference signal divided by 2 */
+#define CTC_REFSOURCE_PSC_DIV4                           CTL1_REFPSC(2)               /*!< reference signal divided by 4 */
+#define CTC_REFSOURCE_PSC_DIV8                           CTL1_REFPSC(3)               /*!< reference signal divided by 8 */
+#define CTC_REFSOURCE_PSC_DIV16                          CTL1_REFPSC(4)               /*!< reference signal divided by 16 */
+#define CTC_REFSOURCE_PSC_DIV32                          CTL1_REFPSC(5)               /*!< reference signal divided by 32 */
+#define CTC_REFSOURCE_PSC_DIV64                          CTL1_REFPSC(6)               /*!< reference signal divided by 64 */
+#define CTC_REFSOURCE_PSC_DIV128                         CTL1_REFPSC(7)               /*!< reference signal divided by 128 */
+
+/* CTC interrupt enable definitions */
+#define CTC_INT_CKOK                                     CTC_CTL0_CKOKIE              /*!< clock trim OK interrupt enable */
+#define CTC_INT_CKWARN                                   CTC_CTL0_CKWARNIE            /*!< clock trim warning interrupt enable */
+#define CTC_INT_ERR                                      CTC_CTL0_ERRIE               /*!< error interrupt enable */
+#define CTC_INT_EREF                                     CTC_CTL0_EREFIE              /*!< expect reference interrupt enable */
+
+/* CTC interrupt source definitions */
+#define CTC_INT_FLAG_CKOK                                CTC_STAT_CKOKIF              /*!< clock trim OK interrupt flag */
+#define CTC_INT_FLAG_CKWARN                              CTC_STAT_CKWARNIF            /*!< clock trim warning interrupt flag */
+#define CTC_INT_FLAG_ERR                                 CTC_STAT_ERRIF               /*!< error interrupt flag */
+#define CTC_INT_FLAG_EREF                                CTC_STAT_EREFIF              /*!< expect reference interrupt flag */
+#define CTC_INT_FLAG_CKERR                               CTC_STAT_CKERR               /*!< clock trim error bit */
+#define CTC_INT_FLAG_REFMISS                             CTC_STAT_REFMISS             /*!< reference sync pulse miss */
+#define CTC_INT_FLAG_TRIMERR                             CTC_STAT_TRIMERR             /*!< trim value error */
+
+/* CTC flag definitions */
+#define CTC_FLAG_CKOK                                    CTC_STAT_CKOKIF              /*!< clock trim OK flag */
+#define CTC_FLAG_CKWARN                                  CTC_STAT_CKWARNIF            /*!< clock trim warning flag */
+#define CTC_FLAG_ERR                                     CTC_STAT_ERRIF               /*!< error flag */
+#define CTC_FLAG_EREF                                    CTC_STAT_EREFIF              /*!< expect reference flag */
+#define CTC_FLAG_CKERR                                   CTC_STAT_CKERR               /*!< clock trim error bit */
+#define CTC_FLAG_REFMISS                                 CTC_STAT_REFMISS             /*!< reference sync pulse miss */
+#define CTC_FLAG_TRIMERR                                 CTC_STAT_TRIMERR             /*!< trim value error bit */
+
+/* function declarations */
+/* initialization functions */
+/* reset ctc clock trim controller */
+void ctc_deinit(void);
+/* enable CTC trim counter */
+void ctc_counter_enable(void);
+/* disable CTC trim counter */
+void ctc_counter_disable(void);
+/* configure the IRC48M trim value */
+void ctc_irc48m_trim_value_config(uint8_t trim_value);
+/* generate software reference source sync pulse */
+void ctc_software_refsource_pulse_generate(void);
+/* configure hardware automatically trim mode */
+void ctc_hardware_trim_mode_config(uint32_t hardmode);
+/* configure reference signal source polarity */
+void ctc_refsource_polarity_config(uint32_t polarity);
+/* select reference signal source */
+void ctc_refsource_signal_select(uint32_t refs);
+/* configure reference signal source prescaler */
+void ctc_refsource_prescaler_config(uint32_t prescaler);
+/* configure clock trim base limit value */
+void ctc_clock_limit_value_config(uint8_t limit_value);
+/* configure CTC counter reload value */
+void ctc_counter_reload_value_config(uint16_t reload_value);
+
+/* read CTC counter capture value when reference sync pulse occurred */
+uint16_t ctc_counter_capture_value_read(void);
+/* read CTC trim counter direction when reference sync pulse occurred */
+FlagStatus ctc_counter_direction_read(void);
+/* read CTC counter reload value */
+uint16_t ctc_counter_reload_value_read(void);
+/* read the IRC48M trim value */
+uint8_t ctc_irc48m_trim_value_read(void);
+
+/* interrupt & flag functions */
+/* get CTC flag */
+FlagStatus ctc_flag_get(uint32_t flag);
+/* clear CTC flag */
+void ctc_flag_clear(uint32_t flag);
+/* enable the CTC interrupt */
+void ctc_interrupt_enable(uint32_t interrupt);
+/* disable the CTC interrupt */
+void ctc_interrupt_disable(uint32_t interrupt);
+/* get CTC interrupt flag */
+FlagStatus ctc_interrupt_flag_get(uint32_t int_flag);
+/* clear CTC interrupt flag */
+void ctc_interrupt_flag_clear(uint32_t int_flag);
+
+#endif /* GD32F3X0_CTC_H */

+ 218 - 0
GD32F3x0/GD32F3x0_standard_peripheral/Include/gd32f3x0_dac.h

@@ -0,0 +1,218 @@
+/*!
+    \file    gd32f3x0_dac.h
+    \brief   definitions for the DAC
+
+    \version 2025-01-01, V2.5.0, firmware for GD32F3x0
+*/
+
+/*
+    Copyright (c) 2025, GigaDevice Semiconductor Inc.
+
+    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 of the copyright holder 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 HOLDER 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.
+*/
+
+#if (defined(GD32F350) || defined(GD32F355) || defined(GD32F370))
+#ifndef GD32F3X0_DAC_H
+#define GD32F3X0_DAC_H
+
+#include "gd32f3x0.h"
+
+/* DACx(x=0) definitions */
+#define DAC0                             (DAC_BASE)
+
+/* registers definitions */
+#define DAC_CTL0(dacx)                    REG32((dacx) + 0x00000000U)          /*!< DACx control register 0 */
+#define DAC_SWT(dacx)                     REG32((dacx) + 0x00000004U)          /*!< DACx software trigger register */
+#define DAC_OUT0_R12DH(dacx)              REG32((dacx) + 0x00000008U)          /*!< DACx_OUT0 12-bit right-aligned data holding register */
+#define DAC_OUT0_L12DH(dacx)              REG32((dacx) + 0x0000000CU)          /*!< DACx_OUT0 12-bit left-aligned data holding register */
+#define DAC_OUT0_R8DH(dacx)               REG32((dacx) + 0x00000010U)          /*!< DACx_OUT0 8-bit right-aligned data holding register */
+#define DAC_OUT0_DO(dacx)                 REG32((dacx) + 0x0000002CU)          /*!< DACx_OUT0 data output register */
+#define DAC_STAT0(dacx)                   REG32((dacx) + 0x00000034U)          /*!< DACx status register 0 */
+
+/* bits definitions */
+/* DAC_CTL0 */
+#define DAC_CTL0_DEN0                     BIT(0)                               /*!< DACx_OUT0 enable */
+#define DAC_CTL0_DBOFF0                   BIT(1)                               /*!< DACx_OUT0 output buffer turn off */
+#define DAC_CTL0_DTEN0                    BIT(2)                               /*!< DACx_OUT0 trigger enable */
+#define DAC_CTL0_DTSEL0                   BITS(3,5)                            /*!< DACx_OUT0 trigger selection */
+#define DAC_CTL0_DWM0                     BITS(6,7)                            /*!< DACx_OUT0 noise wave mode */
+#define DAC_CTL0_DWBW0                    BITS(8,11)                           /*!< DACx_OUT0 noise wave bit width */
+#define DAC_CTL0_DDMAEN0                  BIT(12)                              /*!< DACx_OUT0 DMA enable */
+#define DAC_CTL0_DDUDRIE0                 BIT(13)                              /*!< DACx_OUT0 DMA underrun interrupt enable */
+
+/* DAC_SWT */
+#define DAC_SWT_SWTR0                     BIT(0)                               /*!< DACx_OUT0 software trigger */
+
+/* DAC0_R12DH */
+#define DAC_OUT0_DH_R12                   BITS(0,11)                           /*!< DACx_OUT0 12-bit right-aligned data */
+
+/* DAC0_L12DH */
+#define DAC_OUT0_DH_L12                   BITS(4,15)                           /*!< DACx_OUT0 12-bit left-aligned data */
+
+/* DAC0_R8DH */
+#define DAC_OUT0_DH_R8                    BITS(0,7)                            /*!< DACx_OUT0 8-bit right-aligned data */
+
+/* DAC0_DO */
+#define DAC_OUT0_DO_BITS                  BITS(0,11)                           /*!< DACx_OUT0 12-bit output data */
+
+/* DAC_STAT0 */
+#define DAC_STAT0_DDUDR0                  BIT(13)                              /*!< DACx_OUT0 DMA underrun flag */
+
+/* constants definitions */
+/* DAC trigger source */
+#define CTL_DTSEL(regval)                 (BITS(3,5) & ((uint32_t)(regval) << 3))
+#define DAC_TRIGGER_T5_TRGO               CTL_DTSEL(0)                         /*!< TIMER5 TRGO */
+#define DAC_TRIGGER_T2_TRGO               CTL_DTSEL(1)                         /*!< TIMER2 TRGO */
+#define DAC_TRIGGER_T14_TRGO              CTL_DTSEL(3)                         /*!< TIMER14 TRGO */
+#define DAC_TRIGGER_T1_TRGO               CTL_DTSEL(4)                         /*!< TIMER1 TRGO */
+#define DAC_TRIGGER_EXTI_9                CTL_DTSEL(6)                         /*!< EXTI interrupt line9 event */
+#define DAC_TRIGGER_SOFTWARE              CTL_DTSEL(7)                         /*!< software trigger */
+
+/* DAC noise wave mode */
+#define CTL_DWM(regval)                   (BITS(6,7) & ((uint32_t)(regval) << 6))
+#define DAC_WAVE_DISABLE                  CTL_DWM(0)                           /*!< wave disabled */
+#define DAC_WAVE_MODE_LFSR                CTL_DWM(1)                           /*!< LFSR noise mode */
+#define DAC_WAVE_MODE_TRIANGLE            CTL_DWM(2)                           /*!< triangle noise mode */
+
+/* DAC noise wave bit width */
+#define DWBW(regval)                      (BITS(8, 11) & ((uint32_t)(regval) << 8))
+#define DAC_WAVE_BIT_WIDTH_1              DWBW(0)                              /*!< bit width of the wave signal is 1 */
+#define DAC_WAVE_BIT_WIDTH_2              DWBW(1)                              /*!< bit width of the wave signal is 2 */
+#define DAC_WAVE_BIT_WIDTH_3              DWBW(2)                              /*!< bit width of the wave signal is 3 */
+#define DAC_WAVE_BIT_WIDTH_4              DWBW(3)                              /*!< bit width of the wave signal is 4 */
+#define DAC_WAVE_BIT_WIDTH_5              DWBW(4)                              /*!< bit width of the wave signal is 5 */
+#define DAC_WAVE_BIT_WIDTH_6              DWBW(5)                              /*!< bit width of the wave signal is 6 */
+#define DAC_WAVE_BIT_WIDTH_7              DWBW(6)                              /*!< bit width of the wave signal is 7 */
+#define DAC_WAVE_BIT_WIDTH_8              DWBW(7)                              /*!< bit width of the wave signal is 8 */
+#define DAC_WAVE_BIT_WIDTH_9              DWBW(8)                              /*!< bit width of the wave signal is 9 */
+#define DAC_WAVE_BIT_WIDTH_10             DWBW(9)                              /*!< bit width of the wave signal is 10 */
+#define DAC_WAVE_BIT_WIDTH_11             DWBW(10)                             /*!< bit width of the wave signal is 11 */
+#define DAC_WAVE_BIT_WIDTH_12             DWBW(11)                             /*!< bit width of the wave signal is 12 */
+
+/* unmask LFSR bits in DAC LFSR noise mode */
+#define DAC_LFSR_BIT0                     DAC_WAVE_BIT_WIDTH_1                 /*!< unmask the LFSR bit0 */
+#define DAC_LFSR_BITS1_0                  DAC_WAVE_BIT_WIDTH_2                 /*!< unmask the LFSR bits[1:0] */
+#define DAC_LFSR_BITS2_0                  DAC_WAVE_BIT_WIDTH_3                 /*!< unmask the LFSR bits[2:0] */
+#define DAC_LFSR_BITS3_0                  DAC_WAVE_BIT_WIDTH_4                 /*!< unmask the LFSR bits[3:0] */
+#define DAC_LFSR_BITS4_0                  DAC_WAVE_BIT_WIDTH_5                 /*!< unmask the LFSR bits[4:0] */
+#define DAC_LFSR_BITS5_0                  DAC_WAVE_BIT_WIDTH_6                 /*!< unmask the LFSR bits[5:0] */
+#define DAC_LFSR_BITS6_0                  DAC_WAVE_BIT_WIDTH_7                 /*!< unmask the LFSR bits[6:0] */
+#define DAC_LFSR_BITS7_0                  DAC_WAVE_BIT_WIDTH_8                 /*!< unmask the LFSR bits[7:0] */
+#define DAC_LFSR_BITS8_0                  DAC_WAVE_BIT_WIDTH_9                 /*!< unmask the LFSR bits[8:0] */
+#define DAC_LFSR_BITS9_0                  DAC_WAVE_BIT_WIDTH_10                /*!< unmask the LFSR bits[9:0] */
+#define DAC_LFSR_BITS10_0                 DAC_WAVE_BIT_WIDTH_11                /*!< unmask the LFSR bits[10:0] */
+#define DAC_LFSR_BITS11_0                 DAC_WAVE_BIT_WIDTH_12                /*!< unmask the LFSR bits[11:0] */
+
+/* triangle amplitude in DAC triangle noise mode */
+#define DAC_TRIANGLE_AMPLITUDE_1          DAC_WAVE_BIT_WIDTH_1                 /*!< triangle amplitude is 1 */
+#define DAC_TRIANGLE_AMPLITUDE_3          DAC_WAVE_BIT_WIDTH_2                 /*!< triangle amplitude is 3 */
+#define DAC_TRIANGLE_AMPLITUDE_7          DAC_WAVE_BIT_WIDTH_3                 /*!< triangle amplitude is 7 */
+#define DAC_TRIANGLE_AMPLITUDE_15         DAC_WAVE_BIT_WIDTH_4                 /*!< triangle amplitude is 15 */
+#define DAC_TRIANGLE_AMPLITUDE_31         DAC_WAVE_BIT_WIDTH_5                 /*!< triangle amplitude is 31 */
+#define DAC_TRIANGLE_AMPLITUDE_63         DAC_WAVE_BIT_WIDTH_6                 /*!< triangle amplitude is 63 */
+#define DAC_TRIANGLE_AMPLITUDE_127        DAC_WAVE_BIT_WIDTH_7                 /*!< triangle amplitude is 127 */
+#define DAC_TRIANGLE_AMPLITUDE_255        DAC_WAVE_BIT_WIDTH_8                 /*!< triangle amplitude is 255 */
+#define DAC_TRIANGLE_AMPLITUDE_511        DAC_WAVE_BIT_WIDTH_9                 /*!< triangle amplitude is 511 */
+#define DAC_TRIANGLE_AMPLITUDE_1023       DAC_WAVE_BIT_WIDTH_10                /*!< triangle amplitude is 1023 */
+#define DAC_TRIANGLE_AMPLITUDE_2047       DAC_WAVE_BIT_WIDTH_11                /*!< triangle amplitude is 2047 */
+#define DAC_TRIANGLE_AMPLITUDE_4095       DAC_WAVE_BIT_WIDTH_12                /*!< triangle amplitude is 4095 */
+
+/* DAC data alignment */
+#define DATA_ALIGN(regval)                (BITS(0,1) & ((uint32_t)(regval) << 0))
+#define DAC_ALIGN_12B_R                   DATA_ALIGN(0)                        /*!< 12-bit right-aligned data */
+#define DAC_ALIGN_12B_L                   DATA_ALIGN(1)                        /*!< 12-bit left-aligned data */
+#define DAC_ALIGN_8B_R                    DATA_ALIGN(2)                        /*!< 8-bit right-aligned data */
+
+/* DAC output channel definitions */
+#define DAC_OUT0                          ((uint8_t)0x00U)                     /*!< DACx_OUT0 channel */
+
+/* DAC interrupt */
+#define DAC_INT_DDUDR0                    DAC_CTL0_DDUDRIE0                    /*!< DACx_OUT0 DMA underrun interrupt enable */
+
+/* DAC interrupt flag */
+#define DAC_INT_FLAG_DDUDR0               DAC_STAT0_DDUDR0                     /*!< DACx_OUT0 DMA underrun interrupt flag */
+
+/* DAC flags */
+#define DAC_FLAG_DDUDR0                   DAC_STAT0_DDUDR0                     /*!< DACx_OUT0 DMA underrun flag */
+
+/* function declarations */
+/* DAC initialization functions */
+/* deinitialize DAC */
+void dac_deinit(uint32_t dac_periph);
+/* enable DAC */
+void dac_enable(uint32_t dac_periph, uint8_t dac_out);
+/* disable DAC */
+void dac_disable(uint32_t dac_periph, uint8_t dac_out);
+/* enable DAC DMA function */
+void dac_dma_enable(uint32_t dac_periph, uint8_t dac_out);
+/* disable DAC DMA function */
+void dac_dma_disable(uint32_t dac_periph, uint8_t dac_out);
+
+/* DAC buffer functions */
+/* enable DAC output buffer */
+void dac_output_buffer_enable(uint32_t dac_periph, uint8_t dac_out);
+/* disable DAC output buffer */
+void dac_output_buffer_disable(uint32_t dac_periph, uint8_t dac_out);
+
+/* read and write operation functions */
+/* get DAC output value */
+uint16_t dac_output_value_get(uint32_t dac_periph, uint8_t dac_out);
+/* set DAC data holding register value */
+void dac_data_set(uint32_t dac_periph, uint8_t dac_out, uint32_t dac_align, uint16_t data);
+
+/* DAC trigger configuration */
+/* enable DAC trigger */
+void dac_trigger_enable(uint32_t dac_periph, uint8_t dac_out);
+/* disable DAC trigger */
+void dac_trigger_disable(uint32_t dac_periph, uint8_t dac_out);
+/* configure DAC trigger source */
+void dac_trigger_source_config(uint32_t dac_periph, uint8_t dac_out, uint32_t triggersource);
+/* enable DAC software trigger */
+void dac_software_trigger_enable(uint32_t dac_periph, uint8_t dac_out);
+
+/* DAC wave mode configuration */
+/* configure DAC wave mode */
+void dac_wave_mode_config(uint32_t dac_periph, uint8_t dac_out, uint32_t wave_mode);
+/* configure DAC LFSR noise mode */
+void dac_lfsr_noise_config(uint32_t dac_periph, uint8_t dac_out, uint32_t unmask_bits);
+/* configure DAC triangle noise mode */
+void dac_triangle_noise_config(uint32_t dac_periph, uint8_t dac_out, uint32_t amplitude);
+
+/* DAC interrupt and flag functions */
+/* get DAC flag */
+FlagStatus dac_flag_get(uint32_t dac_periph, uint32_t flag);
+/* clear DAC flag */
+void dac_flag_clear(uint32_t dac_periph, uint32_t flag);
+/* enable DAC interrupt */
+void dac_interrupt_enable(uint32_t dac_periph, uint32_t interrupt);
+/* disable DAC interrupt */
+void dac_interrupt_disable(uint32_t dac_periph, uint32_t interrupt);
+/* get DAC interrupt flag */
+FlagStatus dac_interrupt_flag_get(uint32_t dac_periph, uint32_t int_flag);
+/* clear DAC interrupt flag */
+void dac_interrupt_flag_clear(uint32_t dac_periph, uint32_t int_flag);
+
+#endif /* GD32F3X0_DAC_H */
+
+#endif /* GD32F350 GD32F355 GD32F370 */

+ 129 - 0
GD32F3x0/GD32F3x0_standard_peripheral/Include/gd32f3x0_dbg.h

@@ -0,0 +1,129 @@
+/*!
+    \file    gd32f3x0_dbg.h
+    \brief   definitions for the DBG
+
+    \version 2025-01-01, V2.5.0, firmware for GD32F3x0
+*/
+
+/*
+    Copyright (c) 2025, GigaDevice Semiconductor Inc.
+
+    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 of the copyright holder 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 HOLDER 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.
+*/
+
+#ifndef GD32F3X0_DBG_H
+#define GD32F3X0_DBG_H
+
+#include "gd32f3x0.h"
+
+/* DBG definitions */
+#define DBG                      DBG_BASE
+
+/* registers definitions */
+#define DBG_ID                   REG32(DBG + 0x00000000U)      /*!< DBG_ID code register */
+#define DBG_CTL0                 REG32(DBG + 0x00000004U)      /*!< DBG control register 0 */
+#define DBG_CTL1                 REG32(DBG + 0x00000008U)      /*!< DBG control register 1 */
+
+/* bits definitions */
+/* DBG_ID */
+#define DBG_ID_ID_CODE           BITS(0,31)                    /*!< DBG ID code values */
+
+/* DBG_CTL0 */
+#define DBG_CTL0_SLP_HOLD        BIT(0)                        /*!< keep debugger connection during sleep mode */
+#define DBG_CTL0_DSLP_HOLD       BIT(1)                        /*!< keep debugger connection during deepsleep mode */
+#define DBG_CTL0_STB_HOLD        BIT(2)                        /*!< keep debugger connection during standby mode */
+#define DBG_CTL0_FWDGT_HOLD      BIT(8)                        /*!< debug FWDGT kept when core is halted */
+#define DBG_CTL0_WWDGT_HOLD      BIT(9)                        /*!< debug WWDGT kept when core is halted */
+#define DBG_CTL0_TIMER0_HOLD     BIT(10)                       /*!< hold TIMER0 counter when core is halted */
+#if (defined(GD32F350) || defined(GD32F330))
+#define DBG_CTL0_TIMER1_HOLD     BIT(11)                       /*!< hold TIMER1 counter when core is halted */
+#endif /* GD32F350 and GD32F330 */
+#define DBG_CTL0_TIMER2_HOLD     BIT(12)                       /*!< hold TIMER2 counter when core is halted */
+#define DBG_CTL0_I2C0_HOLD       BIT(15)                       /*!< hold I2C0 smbus when core is halted */
+#define DBG_CTL0_I2C1_HOLD       BIT(16)                       /*!< hold I2C1 smbus when core is halted */
+#ifdef GD32F350
+#define DBG_CTL0_TIMER5_HOLD     BIT(19)                       /*!< hold TIMER5 counter when core is halted */
+#endif /* GD32F350 */
+#define DBG_CTL0_TIMER13_HOLD    BIT(27)                       /*!< hold TIMER13 counter when core is halted */
+
+/* DBG_CTL1 */
+#define DBG_CTL1_RTC_HOLD        BIT(10)                       /*!< hold RTC calendar and wakeup counter when core is halted */
+#define DBG_CTL1_TIMER14_HOLD    BIT(16)                       /*!< hold TIMER14 counter when core is halted */
+#define DBG_CTL1_TIMER15_HOLD    BIT(17)                       /*!< hold TIMER15 counter when core is halted */
+#define DBG_CTL1_TIMER16_HOLD    BIT(18)                       /*!< hold TIMER16 counter when core is halted */
+
+/* constants definitions */
+#define DBG_LOW_POWER_SLEEP      DBG_CTL0_SLP_HOLD             /*!< keep debugger connection during sleep mode */
+#define DBG_LOW_POWER_DEEPSLEEP  DBG_CTL0_DSLP_HOLD            /*!< keep debugger connection during deepsleep mode */
+#define DBG_LOW_POWER_STANDBY    DBG_CTL0_STB_HOLD             /*!< keep debugger connection during standby mode */
+
+/* define the peripheral debug hold bit position and its register index offset */
+#define DBG_REGIDX_BIT(regidx, bitpos)      (((regidx) << 6) | (bitpos))
+#define DBG_REG_VAL(periph)                 (REG32(DBG + ((uint32_t)(periph) >> 6)))
+#define DBG_BIT_POS(val)                    ((uint32_t)(val) & 0x0000001FU)
+
+/* register index */
+typedef enum {
+    DBG_IDX_CTL0            = 0x04U,                                         /*!< DBG control register 0 offset */
+    DBG_IDX_CTL1            = 0x08U,                                         /*!< DBG control register 1 offset */
+} dbg_reg_idx;
+
+/* peripherals hold bit */
+typedef enum {
+    DBG_FWDGT_HOLD          = DBG_REGIDX_BIT(DBG_IDX_CTL0, 8U),              /*!< debug FWDGT kept when core is halted */
+    DBG_WWDGT_HOLD          = DBG_REGIDX_BIT(DBG_IDX_CTL0, 9U),              /*!< debug WWDGT kept when core is halted */
+    DBG_TIMER0_HOLD         = DBG_REGIDX_BIT(DBG_IDX_CTL0, 10U),             /*!< hold TIMER0 counter when core is halted */
+#if (defined(GD32F350) || defined(GD32F330)|| defined (GD32F355) || defined (GD32F370))
+    DBG_TIMER1_HOLD         = DBG_REGIDX_BIT(DBG_IDX_CTL0, 11U),             /*!< hold TIMER1 counter when core is halted */
+#endif /* GD32F350 || GD32F330 || GD32F355 || GD32F370 */
+    DBG_TIMER2_HOLD         = DBG_REGIDX_BIT(DBG_IDX_CTL0, 12U),             /*!< hold TIMER2 counter when core is halted */
+#if (defined(GD32F350) || defined (GD32F355) || defined (GD32F370))
+    DBG_TIMER5_HOLD         = DBG_REGIDX_BIT(DBG_IDX_CTL0, 19U),             /*!< hold TIMER5 counter when core is halted */
+#endif /* GD32F350 || GD32F355 || GD32F370 */
+    DBG_TIMER13_HOLD        = DBG_REGIDX_BIT(DBG_IDX_CTL0, 27U),             /*!< hold TIMER13 counter when core is halted */
+    DBG_TIMER14_HOLD        = DBG_REGIDX_BIT(DBG_IDX_CTL1, 16U),             /*!< hold TIMER14 counter when core is halted */
+    DBG_TIMER15_HOLD        = DBG_REGIDX_BIT(DBG_IDX_CTL1, 17U),             /*!< hold TIMER15 counter when core is halted */
+    DBG_TIMER16_HOLD        = DBG_REGIDX_BIT(DBG_IDX_CTL1, 18U),             /*!< hold TIMER16 counter when core is halted  */
+    DBG_I2C0_HOLD           = DBG_REGIDX_BIT(DBG_IDX_CTL0, 15U),             /*!< hold I2C0 smbus when core is halted */
+    DBG_I2C1_HOLD           = DBG_REGIDX_BIT(DBG_IDX_CTL0, 16U),             /*!< hold I2C1 smbus when core is halted */
+    DBG_RTC_HOLD            = DBG_REGIDX_BIT(DBG_IDX_CTL1, 10U),             /*!< hold RTC calendar and wakeup counter when core is halted */
+} dbg_periph_enum;
+
+/* function declarations */
+/* deinitialize the DBG */
+void dbg_deinit(void);
+/* read DBG_ID code register */
+uint32_t dbg_id_get(void);
+
+/* enable low power behavior when the MCU is in debug mode */
+void dbg_low_power_enable(uint32_t dbg_low_power);
+/* disable low power behavior when the MCU is in debug mode */
+void dbg_low_power_disable(uint32_t dbg_low_power);
+
+/* enable peripheral behavior when the MCU is in debug mode */
+void dbg_periph_enable(dbg_periph_enum dbg_periph);
+/* disable peripheral behavior when the MCU is in debug mode */
+void dbg_periph_disable(dbg_periph_enum dbg_periph);
+
+#endif /* GD32F3X0_DBG_H */

+ 270 - 0
GD32F3x0/GD32F3x0_standard_peripheral/Include/gd32f3x0_dma.h

@@ -0,0 +1,270 @@
+/*!
+    \file    gd32f3x0_dma.h
+    \brief   definitions for the DMA
+
+    \version 2025-01-01, V2.5.0, firmware for GD32F3x0
+*/
+
+/*
+    Copyright (c) 2025, GigaDevice Semiconductor Inc.
+
+    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 of the copyright holder 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 HOLDER 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.
+*/
+
+#ifndef GD32F3X0_DMA_H
+#define GD32F3X0_DMA_H
+
+#include "gd32f3x0.h"
+
+/* DMA definitions */
+#define DMA                               DMA_BASE                    /*!< DMA base address */
+
+/* registers definitions */
+#define DMA_INTF                          REG32(DMA + 0x00000000U)    /*!< DMA interrupt flag register */
+#define DMA_INTC                          REG32(DMA + 0x00000004U)    /*!< DMA interrupt flag clear register */
+#define DMA_CH0CTL                        REG32(DMA + 0x00000008U)    /*!< DMA channel 0 control register */
+#define DMA_CH0CNT                        REG32(DMA + 0x0000000CU)    /*!< DMA channel 0 counter register */
+#define DMA_CH0PADDR                      REG32(DMA + 0x00000010U)    /*!< DMA channel 0 peripheral base address register */
+#define DMA_CH0MADDR                      REG32(DMA + 0x00000014U)    /*!< DMA channel 0 memory base address register */
+#define DMA_CH1CTL                        REG32(DMA + 0x0000001CU)    /*!< DMA channel 1 control register */
+#define DMA_CH1CNT                        REG32(DMA + 0x00000020U)    /*!< DMA channel 1 counter register */
+#define DMA_CH1PADDR                      REG32(DMA + 0x00000024U)    /*!< DMA channel 1 peripheral base address register */
+#define DMA_CH1MADDR                      REG32(DMA + 0x00000028U)    /*!< DMA channel 1 memory base address register */
+#define DMA_CH2CTL                        REG32(DMA + 0x00000030U)    /*!< DMA channel 2 control register */
+#define DMA_CH2CNT                        REG32(DMA + 0x00000034U)    /*!< DMA channel 2 counter register */
+#define DMA_CH2PADDR                      REG32(DMA + 0x00000038U)    /*!< DMA channel 2 peripheral base address register */
+#define DMA_CH2MADDR                      REG32(DMA + 0x0000003CU)    /*!< DMA channel 2 memory base address register */
+#define DMA_CH3CTL                        REG32(DMA + 0x00000044U)    /*!< DMA channel 3 control register */
+#define DMA_CH3CNT                        REG32(DMA + 0x00000048U)    /*!< DMA channel 3 counter register */
+#define DMA_CH3PADDR                      REG32(DMA + 0x0000004CU)    /*!< DMA channel 3 peripheral base address register */
+#define DMA_CH3MADDR                      REG32(DMA + 0x00000050U)    /*!< DMA channel 3 memory base address register */
+#define DMA_CH4CTL                        REG32(DMA + 0x00000058U)    /*!< DMA channel 4 control register */
+#define DMA_CH4CNT                        REG32(DMA + 0x0000005CU)    /*!< DMA channel 4 counter register */
+#define DMA_CH4PADDR                      REG32(DMA + 0x00000060U)    /*!< DMA channel 4 peripheral base address register */
+#define DMA_CH4MADDR                      REG32(DMA + 0x00000064U)    /*!< DMA channel 4 memory base address register */
+#define DMA_CH5CTL                        REG32(DMA + 0x0000006CU)    /*!< DMA channel 5 control register */
+#define DMA_CH5CNT                        REG32(DMA + 0x00000070U)    /*!< DMA channel 5 counter register */
+#define DMA_CH5PADDR                      REG32(DMA + 0x00000074U)    /*!< DMA channel 5 peripheral base address register */
+#define DMA_CH5MADDR                      REG32(DMA + 0x00000078U)    /*!< DMA channel 5 memory base address register */
+#define DMA_CH6CTL                        REG32(DMA + 0x00000080U)    /*!< DMA channel 6 control register */
+#define DMA_CH6CNT                        REG32(DMA + 0x00000084U)    /*!< DMA channel 6 counter register */
+#define DMA_CH6PADDR                      REG32(DMA + 0x00000088U)    /*!< DMA channel 6 peripheral base address register */
+#define DMA_CH6MADDR                      REG32(DMA + 0x0000008CU)    /*!< DMA channel 6 memory base address register */
+
+/* bits definitions */
+/* DMA_INTF */
+#define DMA_INTF_GIF                      BIT(0)                /*!< global interrupt flag of channel */
+#define DMA_INTF_FTFIF                    BIT(1)                /*!< full transfer finish flag of channel */
+#define DMA_INTF_HTFIF                    BIT(2)                /*!< half transfer finish flag of channel */
+#define DMA_INTF_ERRIF                    BIT(3)                /*!< error flag of channel */
+
+/* DMA_INTC */
+#define DMA_INTC_GIFC                     BIT(0)                /*!< clear global interrupt flag of channel */
+#define DMA_INTC_FTFIFC                   BIT(1)                /*!< clear transfer finish flag of channel */
+#define DMA_INTC_HTFIFC                   BIT(2)                /*!< clear half transfer finish flag of channel */
+#define DMA_INTC_ERRIFC                   BIT(3)                /*!< clear error flag of channel */
+
+/* DMA_CHxCTL,x=0..6 */
+#define DMA_CHXCTL_CHEN                   BIT(0)                /*!< channel x enable */
+#define DMA_CHXCTL_FTFIE                  BIT(1)                /*!< enable bit for channel x transfer complete interrupt */
+#define DMA_CHXCTL_HTFIE                  BIT(2)                /*!< enable bit for channel x transfer half complete interrupt */
+#define DMA_CHXCTL_ERRIE                  BIT(3)                /*!< enable bit for channel x error interrupt */
+#define DMA_CHXCTL_DIR                    BIT(4)                /*!< direction of the data transfer on the channel */
+#define DMA_CHXCTL_CMEN                   BIT(5)                /*!< circulation mode */
+#define DMA_CHXCTL_PNAGA                  BIT(6)                /*!< next address generation algorithm of peripheral */
+#define DMA_CHXCTL_MNAGA                  BIT(7)                /*!< next address generation algorithm of memory */
+#define DMA_CHXCTL_PWIDTH                 BITS(8,9)             /*!< transfer data size of peripheral */
+#define DMA_CHXCTL_MWIDTH                 BITS(10,11)           /*!< transfer data size of memory */
+#define DMA_CHXCTL_PRIO                   BITS(12,13)           /*!< priority level of channelx */
+#define DMA_CHXCTL_M2M                    BIT(14)               /*!< memory to memory mode */
+
+/* DMA_CHxCNT,x=0..6 */
+#define DMA_CHXCNT_CNT                    BITS(0,15)            /*!< transfer counter */
+
+/* DMA_CHxPADDR,x=0..6 */
+#define DMA_CHXPADDR_PADDR                BITS(0,31)            /*!< peripheral base address */
+
+/* DMA_CHxMADDR,x=0..6 */
+#define DMA_CHXMADDR_MADDR                BITS(0,31)            /*!< memory base address */
+
+/* constants definitions */
+/* DMA channel select */
+typedef enum {
+    DMA_CH0 = 0,                          /*!< DMA Channel0 */
+    DMA_CH1,                              /*!< DMA Channel1 */
+    DMA_CH2,                              /*!< DMA Channel2 */
+    DMA_CH3,                              /*!< DMA Channel3 */
+    DMA_CH4,                              /*!< DMA Channel4 */
+    DMA_CH5,                              /*!< DMA Channel5 */
+    DMA_CH6                               /*!< DMA Channel6 */
+} dma_channel_enum;
+
+/* DMA initialize struct */
+typedef struct {
+    uint32_t periph_addr;                 /*!< peripheral base address */
+    uint32_t periph_width;                /*!< transfer data size of peripheral */
+    uint8_t periph_inc;                   /*!< peripheral increasing mode */
+    uint32_t memory_addr;                 /*!< memory base address */
+    uint32_t memory_width;                /*!< transfer data size of memory */
+    uint8_t memory_inc;                   /*!< memory increasing mode */
+    uint8_t direction;                    /*!< channel data transfer direction */
+    uint32_t number;                      /*!< channel transfer number */
+    uint32_t priority;                    /*!< channel priority level */
+} dma_parameter_struct;
+
+/* DMA reset value */
+#define DMA_CHCTL_RESET_VALUE             ((uint32_t)0x00000000U)                         /*!< the reset value of DMA channel CHXCTL register */
+#define DMA_CHCNT_RESET_VALUE             ((uint32_t)0x00000000U)                         /*!< the reset value of DMA channel CHXCNT register */
+#define DMA_CHPADDR_RESET_VALUE           ((uint32_t)0x00000000U)                         /*!< the reset value of DMA channel CHXPADDR register */
+#define DMA_CHMADDR_RESET_VALUE           ((uint32_t)0x00000000U)                         /*!< the reset value of DMA channel CHXMADDR register */
+#define DMA_CHINTF_RESET_VALUE            (DMA_INTF_GIF | DMA_INTF_FTFIF | \
+                                           DMA_INTF_HTFIF | DMA_INTF_ERRIF)
+
+#define DMA_FLAG_ADD(flag,shift)          ((flag) << ((uint32_t)(shift) * 4U))            /*!< DMA channel flag shift */
+
+/* DMA_CHCTL base address */
+#define DMA_CHXCTL_BASE                   (DMA + (uint32_t)0x00000008U)                   /*!< the base address of DMA channel CHXCTL register */
+#define DMA_CHXCNT_BASE                   (DMA + (uint32_t)0x0000000CU)                   /*!< the base address of DMA channel CHXCNT register */
+#define DMA_CHXPADDR_BASE                 (DMA + (uint32_t)0x00000010U)                   /*!< the base address of DMA channel CHXPADDR register */
+#define DMA_CHXMADDR_BASE                 (DMA + (uint32_t)0x00000014U)                   /*!< the base address of DMA channel CHXMADDR register */
+
+/* DMA channel shift bit */
+#define DMA_CHCTL(channel)                REG32(DMA_CHXCTL_BASE + (uint32_t)0x0000014U * (uint32_t)(channel))         /*!< the address of DMA channel CHXCTL register */
+#define DMA_CHCNT(channel)                REG32(DMA_CHXCNT_BASE + (uint32_t)0x0000014U * (uint32_t)(channel))         /*!< the address of DMA channel CHXCNT register */
+#define DMA_CHPADDR(channel)              REG32(DMA_CHXPADDR_BASE + (uint32_t)0x0000014U * (uint32_t)(channel))       /*!< the address of DMA channel CHXPADDR register */
+#define DMA_CHMADDR(channel)              REG32(DMA_CHXMADDR_BASE + (uint32_t)0x0000014U * (uint32_t)(channel))       /*!< the address of DMA channel CHXMADDR register */
+
+/* DMA_INTF register */
+/* interrupt flag bits */
+#define DMA_INT_FLAG_G                    DMA_INTF_GIF                                    /*!< global interrupt flag of channel */
+#define DMA_INT_FLAG_FTF                  DMA_INTF_FTFIF                                  /*!< full transfer finish interrupt flag of channel */
+#define DMA_INT_FLAG_HTF                  DMA_INTF_HTFIF                                  /*!< half transfer finish interrupt flag of channel */
+#define DMA_INT_FLAG_ERR                  DMA_INTF_ERRIF                                  /*!< error interrupt flag of channel */
+
+/* flag bits */
+#define DMA_FLAG_G                        DMA_INTF_GIF                                    /*!< global interrupt flag of channel */
+#define DMA_FLAG_FTF                      DMA_INTF_FTFIF                                  /*!< full transfer finish flag of channel */
+#define DMA_FLAG_HTF                      DMA_INTF_HTFIF                                  /*!< half transfer finish flag of channel */
+#define DMA_FLAG_ERR                      DMA_INTF_ERRIF                                  /*!< error flag of channel */
+
+/* DMA_CHxCTL register */
+/* interrupt enable bits */
+#define DMA_INT_FTF                       DMA_CHXCTL_FTFIE                                /*!< enable bit for channel full transfer finish interrupt */
+#define DMA_INT_HTF                       DMA_CHXCTL_HTFIE                                /*!< enable bit for channel half transfer finish interrupt */
+#define DMA_INT_ERR                       DMA_CHXCTL_ERRIE                                /*!< enable bit for channel error interrupt */
+
+/* transfer direction */
+#define DMA_PERIPHERAL_TO_MEMORY          ((uint32_t)0x00000000U)                         /*!< read from peripheral and write to memory */
+#define DMA_MEMORY_TO_PERIPHERAL          ((uint32_t)0x00000001U)                         /*!< read from memory and write to peripheral */
+
+/* peripheral increasing mode */
+#define DMA_PERIPH_INCREASE_DISABLE       ((uint32_t)0x00000000U)                         /*!< next address of peripheral is fixed address mode */
+#define DMA_PERIPH_INCREASE_ENABLE        ((uint32_t)0x00000001U)                         /*!< next address of peripheral is increasing address mode */
+
+/* memory increasing mode */
+#define DMA_MEMORY_INCREASE_DISABLE       ((uint32_t)0x00000000U)                         /*!< next address of memory is fixed address mode */
+#define DMA_MEMORY_INCREASE_ENABLE        ((uint32_t)0x00000001U)                         /*!< next address of memory is increasing address mode */
+
+/* transfer data size of peripheral */
+#define CHCTL_PWIDTH(regval)              (BITS(8,9) & ((regval) << 8))                   /*!< transfer data size of peripheral */
+#define DMA_PERIPHERAL_WIDTH_8BIT         CHCTL_PWIDTH(0)                                 /*!< transfer data size of peripheral is 8-bit */
+#define DMA_PERIPHERAL_WIDTH_16BIT        CHCTL_PWIDTH(1)                                 /*!< transfer data size of peripheral is 16-bit */
+#define DMA_PERIPHERAL_WIDTH_32BIT        CHCTL_PWIDTH(2)                                 /*!< transfer data size of peripheral is 32-bit */
+
+/* transfer data size of memory */
+#define CHCTL_MWIDTH(regval)              (BITS(10,11) & ((regval) << 10))                /*!< transfer data size of memory */
+#define DMA_MEMORY_WIDTH_8BIT             CHCTL_MWIDTH(0)                                 /*!< transfer data size of memory is 8-bit */
+#define DMA_MEMORY_WIDTH_16BIT            CHCTL_MWIDTH(1)                                 /*!< transfer data size of memory is 16-bit */
+#define DMA_MEMORY_WIDTH_32BIT            CHCTL_MWIDTH(2)                                 /*!< transfer data size of memory is 32-bit */
+
+/* channel priority level */
+#define CHCTL_PRIO(regval)                (BITS(12,13) & ((uint32_t)(regval) << 12))      /*!< DMA channel priority level */
+#define DMA_PRIORITY_LOW                  CHCTL_PRIO(0)                                   /*!< low priority */
+#define DMA_PRIORITY_MEDIUM               CHCTL_PRIO(1)                                   /*!< medium priority */
+#define DMA_PRIORITY_HIGH                 CHCTL_PRIO(2)                                   /*!< high priority */
+#define DMA_PRIORITY_ULTRA_HIGH           CHCTL_PRIO(3)                                   /*!< ultra high priority */
+
+/* DMA_CHxCNT register */
+/* transfer counter */
+#define DMA_CHANNEL_CNT_MASK              DMA_CHXCNT_CNT
+
+/* function declarations */
+/* deinitialize DMA a channel registers */
+void dma_deinit(dma_channel_enum channelx);
+/* initialize the parameters of DMA struct with the default values */
+void dma_struct_para_init(dma_parameter_struct *init_struct);
+/* initialize DMA channel */
+void dma_init(dma_channel_enum channelx, dma_parameter_struct *init_struct);
+/* enable DMA circulation mode */
+void dma_circulation_enable(dma_channel_enum channelx);
+/* disable DMA circulation mode */
+void dma_circulation_disable(dma_channel_enum channelx);
+/* enable memory to memory mode */
+void dma_memory_to_memory_enable(dma_channel_enum channelx);
+/* disable memory to memory mode */
+void dma_memory_to_memory_disable(dma_channel_enum channelx);
+/* enable DMA channel */
+void dma_channel_enable(dma_channel_enum channelx);
+/* disable DMA channel */
+void dma_channel_disable(dma_channel_enum channelx);
+
+/* set DMA peripheral base address */
+void dma_periph_address_config(dma_channel_enum channelx, uint32_t address);
+/* set DMA memory base address */
+void dma_memory_address_config(dma_channel_enum channelx, uint32_t address);
+/* set the number of remaining data to be transferred by the DMA */
+void dma_transfer_number_config(dma_channel_enum channelx, uint32_t number);
+/* get the number of remaining data to be transferred by the DMA */
+uint32_t dma_transfer_number_get(dma_channel_enum channelx);
+/* configure priority level of DMA channel */
+void dma_priority_config(dma_channel_enum channelx, uint32_t priority);
+/* configure transfer data size of memory */
+void dma_memory_width_config(dma_channel_enum channelx, uint32_t mwidth);
+/* configure transfer data size of peripheral */
+void dma_periph_width_config(dma_channel_enum channelx, uint32_t pwidth);
+/* enable next address increasement algorithm of memory */
+void dma_memory_increase_enable(dma_channel_enum channelx);
+/* disable next address increasement algorithm of memory */
+void dma_memory_increase_disable(dma_channel_enum channelx);
+/* enable next address increasement algorithm of peripheral */
+void dma_periph_increase_enable(dma_channel_enum channelx);
+/* disable next address increasement algorithm of peripheral */
+void dma_periph_increase_disable(dma_channel_enum channelx);
+/* configure the direction of data transfer on the channel */
+void dma_transfer_direction_config(dma_channel_enum channelx, uint32_t direction);
+
+/* check DMA flag is set or not */
+FlagStatus dma_flag_get(dma_channel_enum channelx, uint32_t flag);
+/* clear DMA a channel flag */
+void dma_flag_clear(dma_channel_enum channelx, uint32_t flag);
+/* enable DMA interrupt */
+void dma_interrupt_enable(dma_channel_enum channelx, uint32_t source);
+/* disable DMA interrupt */
+void dma_interrupt_disable(dma_channel_enum channelx, uint32_t source);
+/* check DMA flag and interrupt enable bit is set or not */
+FlagStatus dma_interrupt_flag_get(dma_channel_enum channelx, uint32_t flag);
+/* clear DMA a channel flag */
+void dma_interrupt_flag_clear(dma_channel_enum channelx, uint32_t flag);
+
+#endif /* GD32F3X0_DMA_H */

+ 283 - 0
GD32F3x0/GD32F3x0_standard_peripheral/Include/gd32f3x0_exti.h

@@ -0,0 +1,283 @@
+/*!
+    \file    gd32f3x0_exti.h
+    \brief   definitions for the EXTI
+
+    \version 2025-01-01, V2.5.0, firmware for GD32F3x0
+*/
+
+/*
+    Copyright (c) 2025, GigaDevice Semiconductor Inc.
+
+    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 of the copyright holder 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 HOLDER 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.
+*/
+
+#ifndef GD32F3X0_EXTI_H
+#define GD32F3X0_EXTI_H
+
+#include "gd32f3x0.h"
+
+/* EXTI definitions */
+#define EXTI                         EXTI_BASE                 /*!< EXTI base address */
+
+/* registers definitions */
+#define EXTI_INTEN                   REG32(EXTI + 0x00000000U) /*!< interrupt enable register */
+#define EXTI_EVEN                    REG32(EXTI + 0x00000004U) /*!< event enable register */
+#define EXTI_RTEN                    REG32(EXTI + 0x00000008U) /*!< rising edge trigger enable register */
+#define EXTI_FTEN                    REG32(EXTI + 0x0000000CU) /*!< falling trigger enable register */
+#define EXTI_SWIEV                   REG32(EXTI + 0x00000010U) /*!< software interrupt event register */
+#define EXTI_PD                      REG32(EXTI + 0x00000014U) /*!< pending register */
+
+/* bits definitions */
+/* EXTI_INTEN */
+#define EXTI_INTEN_INTEN0            BIT(0)                   /*!< interrupt from line 0 */
+#define EXTI_INTEN_INTEN1            BIT(1)                   /*!< interrupt from line 1 */
+#define EXTI_INTEN_INTEN2            BIT(2)                   /*!< interrupt from line 2 */
+#define EXTI_INTEN_INTEN3            BIT(3)                   /*!< interrupt from line 3 */
+#define EXTI_INTEN_INTEN4            BIT(4)                   /*!< interrupt from line 4 */
+#define EXTI_INTEN_INTEN5            BIT(5)                   /*!< interrupt from line 5 */
+#define EXTI_INTEN_INTEN6            BIT(6)                   /*!< interrupt from line 6 */
+#define EXTI_INTEN_INTEN7            BIT(7)                   /*!< interrupt from line 7 */
+#define EXTI_INTEN_INTEN8            BIT(8)                   /*!< interrupt from line 8 */
+#define EXTI_INTEN_INTEN9            BIT(9)                   /*!< interrupt from line 9 */
+#define EXTI_INTEN_INTEN10           BIT(10)                  /*!< interrupt from line 10 */
+#define EXTI_INTEN_INTEN11           BIT(11)                  /*!< interrupt from line 11 */
+#define EXTI_INTEN_INTEN12           BIT(12)                  /*!< interrupt from line 12 */
+#define EXTI_INTEN_INTEN13           BIT(13)                  /*!< interrupt from line 13 */
+#define EXTI_INTEN_INTEN14           BIT(14)                  /*!< interrupt from line 14 */
+#define EXTI_INTEN_INTEN15           BIT(15)                  /*!< interrupt from line 15 */
+#define EXTI_INTEN_INTEN16           BIT(16)                  /*!< interrupt from line 16 */
+#define EXTI_INTEN_INTEN17           BIT(17)                  /*!< interrupt from line 17 */
+#define EXTI_INTEN_INTEN18           BIT(18)                  /*!< interrupt from line 18 */
+#define EXTI_INTEN_INTEN19           BIT(19)                  /*!< interrupt from line 19 */
+#define EXTI_INTEN_INTEN20           BIT(20)                  /*!< interrupt from line 20 */
+#define EXTI_INTEN_INTEN21           BIT(21)                  /*!< interrupt from line 21 */
+#define EXTI_INTEN_INTEN22           BIT(22)                  /*!< interrupt from line 22 */
+#define EXTI_INTEN_INTEN23           BIT(23)                  /*!< interrupt from line 23 */
+#define EXTI_INTEN_INTEN24           BIT(24)                  /*!< interrupt from line 24 */
+#define EXTI_INTEN_INTEN25           BIT(25)                  /*!< interrupt from line 25 */
+#define EXTI_INTEN_INTEN26           BIT(26)                  /*!< interrupt from line 26 */
+#define EXTI_INTEN_INTEN27           BIT(27)                  /*!< interrupt from line 27 */
+
+/* EXTI_EVEN */
+#define EXTI_EVEN_EVEN0              BIT(0)                   /*!< event from line 0 */
+#define EXTI_EVEN_EVEN1              BIT(1)                   /*!< event from line 1 */
+#define EXTI_EVEN_EVEN2              BIT(2)                   /*!< event from line 2 */
+#define EXTI_EVEN_EVEN3              BIT(3)                   /*!< event from line 3 */
+#define EXTI_EVEN_EVEN4              BIT(4)                   /*!< event from line 4 */
+#define EXTI_EVEN_EVEN5              BIT(5)                   /*!< event from line 5 */
+#define EXTI_EVEN_EVEN6              BIT(6)                   /*!< event from line 6 */
+#define EXTI_EVEN_EVEN7              BIT(7)                   /*!< event from line 7 */
+#define EXTI_EVEN_EVEN8              BIT(8)                   /*!< event from line 8 */
+#define EXTI_EVEN_EVEN9              BIT(9)                   /*!< event from line 9 */
+#define EXTI_EVEN_EVEN10             BIT(10)                  /*!< event from line 10 */
+#define EXTI_EVEN_EVEN11             BIT(11)                  /*!< event from line 11 */
+#define EXTI_EVEN_EVEN12             BIT(12)                  /*!< event from line 12 */
+#define EXTI_EVEN_EVEN13             BIT(13)                  /*!< event from line 13 */
+#define EXTI_EVEN_EVEN14             BIT(14)                  /*!< event from line 14 */
+#define EXTI_EVEN_EVEN15             BIT(15)                  /*!< event from line 15 */
+#define EXTI_EVEN_EVEN16             BIT(16)                  /*!< event from line 16 */
+#define EXTI_EVEN_EVEN17             BIT(17)                  /*!< event from line 17 */
+#define EXTI_EVEN_EVEN18             BIT(18)                  /*!< event from line 18 */
+#define EXTI_EVEN_EVEN19             BIT(19)                  /*!< event from line 19 */
+#define EXTI_EVEN_EVEN20             BIT(20)                  /*!< event from line 20 */
+#define EXTI_EVEN_EVEN21             BIT(21)                  /*!< event from line 21 */
+#define EXTI_EVEN_EVEN22             BIT(22)                  /*!< event from line 22 */
+#define EXTI_EVEN_EVEN23             BIT(23)                  /*!< event from line 23 */
+#define EXTI_EVEN_EVEN24             BIT(24)                  /*!< event from line 24 */
+#define EXTI_EVEN_EVEN25             BIT(25)                  /*!< event from line 25 */
+#define EXTI_EVEN_EVEN26             BIT(26)                  /*!< event from line 26 */
+#define EXTI_EVEN_EVEN27             BIT(27)                  /*!< event from line 27 */
+
+/* EXTI_RTEN */
+#define EXTI_RTEN_RTEN0              BIT(0)                   /*!< rising edge from line 0 */
+#define EXTI_RTEN_RTEN1              BIT(1)                   /*!< rising edge from line 1 */
+#define EXTI_RTEN_RTEN2              BIT(2)                   /*!< rising edge from line 2 */
+#define EXTI_RTEN_RTEN3              BIT(3)                   /*!< rising edge from line 3 */
+#define EXTI_RTEN_RTEN4              BIT(4)                   /*!< rising edge from line 4 */
+#define EXTI_RTEN_RTEN5              BIT(5)                   /*!< rising edge from line 5 */
+#define EXTI_RTEN_RTEN6              BIT(6)                   /*!< rising edge from line 6 */
+#define EXTI_RTEN_RTEN7              BIT(7)                   /*!< rising edge from line 7 */
+#define EXTI_RTEN_RTEN8              BIT(8)                   /*!< rising edge from line 8 */
+#define EXTI_RTEN_RTEN9              BIT(9)                   /*!< rising edge from line 9 */
+#define EXTI_RTEN_RTEN10             BIT(10)                  /*!< rising edge from line 10 */
+#define EXTI_RTEN_RTEN11             BIT(11)                  /*!< rising edge from line 11 */
+#define EXTI_RTEN_RTEN12             BIT(12)                  /*!< rising edge from line 12 */
+#define EXTI_RTEN_RTEN13             BIT(13)                  /*!< rising edge from line 13 */
+#define EXTI_RTEN_RTEN14             BIT(14)                  /*!< rising edge from line 14 */
+#define EXTI_RTEN_RTEN15             BIT(15)                  /*!< rising edge from line 15 */
+#define EXTI_RTEN_RTEN16             BIT(16)                  /*!< rising edge from line 16 */
+#define EXTI_RTEN_RTEN17             BIT(17)                  /*!< rising edge from line 17 */
+#define EXTI_RTEN_RTEN18             BIT(18)                  /*!< rising edge from line 18 */
+#define EXTI_RTEN_RTEN19             BIT(19)                  /*!< rising edge from line 19 */
+#define EXTI_RTEN_RTEN21             BIT(21)                  /*!< rising edge from line 21 */
+#define EXTI_RTEN_RTEN22             BIT(22)                  /*!< rising edge from line 22 */
+
+/* EXTI_FTEN */
+#define EXTI_FTEN_FTEN0              BIT(0)                   /*!< falling edge from line 0 */
+#define EXTI_FTEN_FTEN1              BIT(1)                   /*!< falling edge from line 1 */
+#define EXTI_FTEN_FTEN2              BIT(2)                   /*!< falling edge from line 2 */
+#define EXTI_FTEN_FTEN3              BIT(3)                   /*!< falling edge from line 3 */
+#define EXTI_FTEN_FTEN4              BIT(4)                   /*!< falling edge from line 4 */
+#define EXTI_FTEN_FTEN5              BIT(5)                   /*!< falling edge from line 5 */
+#define EXTI_FTEN_FTEN6              BIT(6)                   /*!< falling edge from line 6 */
+#define EXTI_FTEN_FTEN7              BIT(7)                   /*!< falling edge from line 7 */
+#define EXTI_FTEN_FTEN8              BIT(8)                   /*!< falling edge from line 8 */
+#define EXTI_FTEN_FTEN9              BIT(9)                   /*!< falling edge from line 9 */
+#define EXTI_FTEN_FTEN10             BIT(10)                  /*!< falling edge from line 10 */
+#define EXTI_FTEN_FTEN11             BIT(11)                  /*!< falling edge from line 11 */
+#define EXTI_FTEN_FTEN12             BIT(12)                  /*!< falling edge from line 12 */
+#define EXTI_FTEN_FTEN13             BIT(13)                  /*!< falling edge from line 13 */
+#define EXTI_FTEN_FTEN14             BIT(14)                  /*!< falling edge from line 14 */
+#define EXTI_FTEN_FTEN15             BIT(15)                  /*!< falling edge from line 15 */
+#define EXTI_FTEN_FTEN16             BIT(16)                  /*!< falling edge from line 16 */
+#define EXTI_FTEN_FTEN17             BIT(17)                  /*!< falling edge from line 17 */
+#define EXTI_FTEN_FTEN18             BIT(18)                  /*!< falling edge from line 18 */
+#define EXTI_FTEN_FTEN19             BIT(19)                  /*!< falling edge from line 19 */
+#define EXTI_FTEN_FTEN21             BIT(21)                  /*!< falling edge from line 21 */
+#define EXTI_FTEN_FTEN22             BIT(22)                  /*!< falling edge from line 22 */
+
+/* EXTI_SWIEV */
+#define EXTI_SWIEV_SWIEV0            BIT(0)                   /*!< software interrupt/event request from line 0 */
+#define EXTI_SWIEV_SWIEV1            BIT(1)                   /*!< software interrupt/event request from line 1 */
+#define EXTI_SWIEV_SWIEV2            BIT(2)                   /*!< software interrupt/event request from line 2 */
+#define EXTI_SWIEV_SWIEV3            BIT(3)                   /*!< software interrupt/event request from line 3 */
+#define EXTI_SWIEV_SWIEV4            BIT(4)                   /*!< software interrupt/event request from line 4 */
+#define EXTI_SWIEV_SWIEV5            BIT(5)                   /*!< software interrupt/event request from line 5 */
+#define EXTI_SWIEV_SWIEV6            BIT(6)                   /*!< software interrupt/event request from line 6 */
+#define EXTI_SWIEV_SWIEV7            BIT(7)                   /*!< software interrupt/event request from line 7 */
+#define EXTI_SWIEV_SWIEV8            BIT(8)                   /*!< software interrupt/event request from line 8 */
+#define EXTI_SWIEV_SWIEV9            BIT(9)                   /*!< software interrupt/event request from line 9 */
+#define EXTI_SWIEV_SWIEV10           BIT(10)                  /*!< software interrupt/event request from line 10 */
+#define EXTI_SWIEV_SWIEV11           BIT(11)                  /*!< software interrupt/event request from line 11 */
+#define EXTI_SWIEV_SWIEV12           BIT(12)                  /*!< software interrupt/event request from line 12 */
+#define EXTI_SWIEV_SWIEV13           BIT(13)                  /*!< software interrupt/event request from line 13 */
+#define EXTI_SWIEV_SWIEV14           BIT(14)                  /*!< software interrupt/event request from line 14 */
+#define EXTI_SWIEV_SWIEV15           BIT(15)                  /*!< software interrupt/event request from line 15 */
+#define EXTI_SWIEV_SWIEV16           BIT(16)                  /*!< software interrupt/event request from line 16 */
+#define EXTI_SWIEV_SWIEV17           BIT(17)                  /*!< software interrupt/event request from line 17 */
+#define EXTI_SWIEV_SWIEV18           BIT(18)                  /*!< software interrupt/event request from line 18 */
+#define EXTI_SWIEV_SWIEV19           BIT(19)                  /*!< software interrupt/event request from line 19 */
+#define EXTI_SWIEV_SWIEV21           BIT(21)                  /*!< software interrupt/event request from line 21 */
+#define EXTI_SWIEV_SWIEV22           BIT(22)                  /*!< software interrupt/event request from line 22 */
+
+/* EXTI_PD */
+#define EXTI_PD_PD0                  BIT(0)                   /*!< interrupt pending status from line 0 */
+#define EXTI_PD_PD1                  BIT(1)                   /*!< interrupt pending status from line 1 */
+#define EXTI_PD_PD2                  BIT(2)                   /*!< interrupt pending status from line 2 */
+#define EXTI_PD_PD3                  BIT(3)                   /*!< interrupt pending status from line 3 */
+#define EXTI_PD_PD4                  BIT(4)                   /*!< interrupt pending status from line 4 */
+#define EXTI_PD_PD5                  BIT(5)                   /*!< interrupt pending status from line 5 */
+#define EXTI_PD_PD6                  BIT(6)                   /*!< interrupt pending status from line 6 */
+#define EXTI_PD_PD7                  BIT(7)                   /*!< interrupt pending status from line 7 */
+#define EXTI_PD_PD8                  BIT(8)                   /*!< interrupt pending status from line 8 */
+#define EXTI_PD_PD9                  BIT(9)                   /*!< interrupt pending status from line 9 */
+#define EXTI_PD_PD10                 BIT(10)                  /*!< interrupt pending status from line 10 */
+#define EXTI_PD_PD11                 BIT(11)                  /*!< interrupt pending status from line 11 */
+#define EXTI_PD_PD12                 BIT(12)                  /*!< interrupt pending status from line 12 */
+#define EXTI_PD_PD13                 BIT(13)                  /*!< interrupt pending status from line 13 */
+#define EXTI_PD_PD14                 BIT(14)                  /*!< interrupt pending status from line 14 */
+#define EXTI_PD_PD15                 BIT(15)                  /*!< interrupt pending status from line 15 */
+#define EXTI_PD_PD16                 BIT(16)                  /*!< interrupt pending status from line 16 */
+#define EXTI_PD_PD17                 BIT(17)                  /*!< interrupt pending status from line 17 */
+#define EXTI_PD_PD18                 BIT(18)                  /*!< interrupt pending status from line 18 */
+#define EXTI_PD_PD19                 BIT(19)                  /*!< interrupt pending status from line 19 */
+#define EXTI_PD_PD21                 BIT(21)                  /*!< interrupt pending status from line 21 */
+#define EXTI_PD_PD22                 BIT(22)                  /*!< interrupt pending status from line 22 */
+
+/* constants definitions */
+/* EXTI line number */
+typedef enum {
+    EXTI_0      = BIT(0),                                     /*!< EXTI line 0 */
+    EXTI_1      = BIT(1),                                     /*!< EXTI line 1 */
+    EXTI_2      = BIT(2),                                     /*!< EXTI line 2 */
+    EXTI_3      = BIT(3),                                     /*!< EXTI line 3 */
+    EXTI_4      = BIT(4),                                     /*!< EXTI line 4 */
+    EXTI_5      = BIT(5),                                     /*!< EXTI line 5 */
+    EXTI_6      = BIT(6),                                     /*!< EXTI line 6 */
+    EXTI_7      = BIT(7),                                     /*!< EXTI line 7 */
+    EXTI_8      = BIT(8),                                     /*!< EXTI line 8 */
+    EXTI_9      = BIT(9),                                     /*!< EXTI line 9 */
+    EXTI_10     = BIT(10),                                    /*!< EXTI line 10 */
+    EXTI_11     = BIT(11),                                    /*!< EXTI line 11 */
+    EXTI_12     = BIT(12),                                    /*!< EXTI line 12 */
+    EXTI_13     = BIT(13),                                    /*!< EXTI line 13 */
+    EXTI_14     = BIT(14),                                    /*!< EXTI line 14 */
+    EXTI_15     = BIT(15),                                    /*!< EXTI line 15 */
+    EXTI_16     = BIT(16),                                    /*!< EXTI line 16 */
+    EXTI_17     = BIT(17),                                    /*!< EXTI line 17 */
+    EXTI_18     = BIT(18),                                    /*!< EXTI line 18 */
+    EXTI_19     = BIT(19),                                    /*!< EXTI line 19 */
+    EXTI_20     = BIT(20),                                    /*!< EXTI line 20 */
+    EXTI_21     = BIT(21),                                    /*!< EXTI line 21 */
+    EXTI_22     = BIT(22),                                    /*!< EXTI line 22 */
+    EXTI_23     = BIT(23),                                    /*!< EXTI line 23 */
+    EXTI_24     = BIT(24),                                    /*!< EXTI line 24 */
+    EXTI_25     = BIT(25),                                    /*!< EXTI line 25 */
+    EXTI_26     = BIT(26),                                    /*!< EXTI line 26 */
+    EXTI_27     = BIT(27)                                     /*!< EXTI line 27 */
+} exti_line_enum;
+
+/* external interrupt and event */
+typedef enum {
+    EXTI_INTERRUPT   = 0,                                     /*!< EXTI interrupt mode */
+    EXTI_EVENT                                                /*!< EXTI event mode */
+} exti_mode_enum;
+
+/* interrupt and event trigger mode */
+typedef enum {
+    EXTI_TRIG_RISING = 0,                                     /*!< EXTI rising edge trigger */
+    EXTI_TRIG_FALLING,                                        /*!< EXTI falling edge trigger */
+    EXTI_TRIG_BOTH,                                           /*!< EXTI rising and falling edge trigger */
+    EXTI_TRIG_NONE                                            /*!< without rising edge or falling edge trigger */
+} exti_trig_type_enum;
+
+/* function declarations */
+/* reset EXTI, reset the value of all EXTI registers into initial values */
+void exti_deinit(void);
+/* initialize the EXTI, enable the configuration of EXTI initialize */
+void exti_init(exti_line_enum linex, exti_mode_enum mode, exti_trig_type_enum trig_type);
+/* enable the interrupts from EXTI line x */
+void exti_interrupt_enable(exti_line_enum linex);
+/* disable the interrupts from EXTI line x */
+void exti_interrupt_disable(exti_line_enum linex);
+/* enable the events from EXTI line x */
+void exti_event_enable(exti_line_enum linex);
+/* disable the events from EXTI line x */
+void exti_event_disable(exti_line_enum linex);
+/* enable EXTI software interrupt event */
+void exti_software_interrupt_enable(exti_line_enum linex);
+/* disable EXTI software interrupt event */
+void exti_software_interrupt_disable(exti_line_enum linex);
+
+/* interrupt & flag functions */
+/* get EXTI line x interrupt pending flag */
+FlagStatus exti_flag_get(exti_line_enum linex);
+/* clear EXTI line x interrupt pending flag */
+void exti_flag_clear(exti_line_enum linex);
+/* get EXTI line x interrupt pending flag */
+FlagStatus exti_interrupt_flag_get(exti_line_enum linex);
+/* clear EXTI line x interrupt pending flag */
+void exti_interrupt_flag_clear(exti_line_enum linex);
+
+#endif /* GD32F3X0_EXTI_H */

+ 255 - 0
GD32F3x0/GD32F3x0_standard_peripheral/Include/gd32f3x0_fmc.h

@@ -0,0 +1,255 @@
+/*!
+    \file    gd32f3x0_fmc.h
+    \brief   definitions for the FMC
+
+    \version 2025-01-01, V2.5.0, firmware for GD32F3x0
+*/
+
+/*
+    Copyright (c) 2025, GigaDevice Semiconductor Inc.
+
+    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 of the copyright holder 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 HOLDER 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.
+*/
+
+
+#ifndef GD32F3X0_FMC_H
+#define GD32F3X0_FMC_H
+
+#include "gd32f3x0.h"
+
+/* FMC and option byte definition */
+#define FMC                     FMC_BASE                    /*!< FMC register base address */
+#define OB                      OB_BASE                     /*!< option byte base address */
+
+/* registers definitions */
+#define FMC_WS                  REG32(FMC + 0x00000000U)    /*!< FMC wait state register */
+#define FMC_KEY                 REG32(FMC + 0x00000004U)    /*!< FMC unlock key register */
+#define FMC_OBKEY               REG32(FMC + 0x00000008U)    /*!< FMC option bytes unlock key register */
+#define FMC_STAT                REG32(FMC + 0x0000000CU)    /*!< FMC status register */
+#define FMC_CTL                 REG32(FMC + 0x00000010U)    /*!< FMC control register */
+#define FMC_ADDR                REG32(FMC + 0x00000014U)    /*!< FMC address register */
+#define FMC_OBSTAT              REG32(FMC + 0x0000001CU)    /*!< FMC option bytes status register */
+#define FMC_WP                  REG32(FMC + 0x00000020U)    /*!< FMC write protection register */
+#define FMC_WSEN                REG32(FMC + 0x000000FCU)    /*!< FMC wait state enable register */
+#define FMC_PID                 REG32(FMC + 0x00000100U)    /*!< FMC product ID register */
+
+#define OB_SPC                  REG16(OB + 0x00000000U)     /*!< option byte security protection value */
+#define OB_USER                 REG16(OB + 0x00000002U)     /*!< option byte user value */
+#define OB_DATA0                REG16(OB + 0x00000004U)     /*!< option byte data bit[7:0] value */
+#define OB_DATA1                REG16(OB + 0x00000006U)     /*!< option byte data bit[15:8] value */
+#define OB_WP0                  REG16(OB + 0x00000008U)     /*!< option byte write protection 0 */
+#define OB_WP1                  REG16(OB + 0x0000000AU)     /*!< option byte write protection 1 */
+
+/* bits definitions */
+/* FMC_WS */
+#define FMC_WS_WSCNT            BITS(0,2)                   /*!< wait state counter */
+
+/* FMC_KEY */
+#define FMC_KEY_KEY             BITS(0,31)                  /*!< FMC main flash unlock key bits */
+
+/* FMC_OBKEY */
+#define FMC_OBKEY_OBKEY         BITS(0,31)                  /*!< option bytes unlock key bits */
+
+/* FMC_STAT */
+#define FMC_STAT_BUSY           BIT(0)                      /*!< flash busy flag bit */
+#define FMC_STAT_PGERR          BIT(2)                      /*!< flash program error flag bit */
+#define FMC_STAT_WPERR          BIT(4)                      /*!< flash write protection error flag bit */
+#define FMC_STAT_ENDF           BIT(5)                      /*!< end of operation flag bit */
+
+/* FMC_CTL */
+#define FMC_CTL_PG              BIT(0)                      /*!< main flash program command bit */
+#define FMC_CTL_PER             BIT(1)                      /*!< main flash page erase bit */
+#define FMC_CTL_MER             BIT(2)                      /*!< main flash mass erase bit */
+#define FMC_CTL_OBPG            BIT(4)                      /*!< option bytes program command bit */
+#define FMC_CTL_OBER            BIT(5)                      /*!< option bytes erase command bit */
+#define FMC_CTL_START           BIT(6)                      /*!< send erase command to FMC bit */
+#define FMC_CTL_LK              BIT(7)                      /*!< flash lock bit */
+#define FMC_CTL_OBWEN           BIT(9)                      /*!< option bytes erase/program enable bit */
+#define FMC_CTL_ERRIE           BIT(10)                     /*!< error interrupt enable bit */
+#define FMC_CTL_ENDIE           BIT(12)                     /*!< end of operation interrupt enable bit */
+#define FMC_CTL_OBRLD           BIT(13)                     /*!< option bytes reload bit */
+
+/* FMC_ADDR */
+#define FMC_ADDR_ADDR           BITS(0,31)                  /*!< flash command address bits */
+
+/* FMC_OBSTAT */
+#define FMC_OBSTAT_OBERR        BIT(0)                      /*!< option bytes read error bit */
+#define FMC_OBSTAT_PLEVEL_BIT0  BIT(1)                      /*!< protection level bit 0 */
+#define FMC_OBSTAT_PLEVEL_BIT1  BIT(2)                      /*!< protection level bit 1 */
+#define FMC_OBSTAT_USER         BITS(8,15)                  /*!< option bytes user bits */
+#define FMC_OBSTAT_DATA         BITS(16,31)                 /*!< option byte data bits */
+
+/* FMC_WSEN */
+#define FMC_WSEN_WSEN           BIT(0)                      /*!< FMC wait state enable bit */
+#define FMC_WSEN_BPEN           BIT(1)                      /*!< FMC bit program enable bit */
+
+/* FMC_PID */
+#define FMC_PID_PID             BITS(0,31)                  /*!< product ID bits */
+
+/* constants definitions */
+/* fmc state */
+typedef enum {
+    FMC_READY,                                              /*!< the operation has been completed */
+    FMC_BUSY,                                               /*!< the operation is in progress */
+    FMC_PGERR,                                              /*!< program error */
+    FMC_WPERR,                                              /*!< erase/program protection error */
+    FMC_TOERR,                                              /*!< timeout error */
+    FMC_OB_HSPC                                             /*!< option byte security protection code high */
+} fmc_state_enum;
+
+/* option byte parameter */
+typedef struct {
+    uint8_t spc;                                            /*!< option byte parameter spc */
+    uint8_t user;                                           /*!< option byte parameter user */
+    uint8_t data0;                                          /*!< option byte parameter data0 */
+    uint8_t data1;                                          /*!< option byte parameter data1 */
+    uint8_t wp0;                                            /*!< option byte parameter wp0 */
+    uint8_t wp1;                                            /*!< option byte parameter wp1 */
+} ob_parm_struct;
+
+/* unlock key */
+#define UNLOCK_KEY0             ((uint32_t)0x45670123U)     /*!< unlock key 0 */
+#define UNLOCK_KEY1             ((uint32_t)0xCDEF89ABU)     /*!< unlock key 1 */
+
+/* wait state counter value */
+#define WS_WSCNT_0              ((uint8_t)0x00U)            /*!< 0 wait state added */
+#define WS_WSCNT_1              ((uint8_t)0x01U)            /*!< 1 wait state added */
+#define WS_WSCNT_2              ((uint8_t)0x02U)            /*!< 2 wait state added */
+
+/* read protect configure */
+#define FMC_NSPC                ((uint8_t)0xA5U)            /*!< no security protection */
+#define FMC_LSPC                ((uint8_t)0xBBU)            /*!< low security protection, any value except 0xA5 or 0xCC */
+#define FMC_HSPC                ((uint8_t)0xCCU)            /*!< high security protection */
+
+/* option byte write protection */
+#define OB_LWP                  ((uint32_t)0x000000FFU)     /*!< write protection low bits */
+#define OB_HWP                  ((uint32_t)0x0000FF00U)     /*!< write protection high bits */
+
+#define OB_FWDGT_HW             ((uint8_t)(~BIT(0)))        /*!< hardware free watchdog timer */
+#define OB_DEEPSLEEP_RST        ((uint8_t)(~BIT(1)))        /*!< generate a reset instead of entering deepsleep mode */
+#define OB_STDBY_RST            ((uint8_t)(~BIT(2)))        /*!< generate a reset instead of entering standby mode */
+#define OB_BOOT1_SET_1          ((uint8_t)(~BIT(4)))        /*!< BOOT1 bit is 1 */
+#define OB_VDDA_DISABLE         ((uint8_t)(~BIT(5)))        /*!< disable VDDA monitor */
+#define OB_SRAM_PARITY_ENABLE   ((uint8_t)(~BIT(6)))        /*!< enable SRAM parity check */
+
+/* option byte security protection level in FMC_OBSTAT register */
+#define OB_OBSTAT_PLEVEL_NO     ((uint32_t)0x00000000U)     /*!< no security protection */
+#define OB_OBSTAT_PLEVEL_LOW    ((uint32_t)0x00000002U)     /*!< low security protection */
+#define OB_OBSTAT_PLEVEL_HIGH   ((uint32_t)0x00000006U)     /*!< high security protection */
+
+#define OB_USER_DEFAULT         ((uint8_t)0xDFU)            /*!< OB_USER default value */
+
+/* option byte parameter address */
+#define OB_SPC_ADDR             (uint32_t)(OB + 0x00000000U)/*!< option byte spc address */
+#define OB_USER_ADDR            (uint32_t)(OB + 0x00000002U)/*!< option byte user address */
+#define OB_DATA_ADDR0           (uint32_t)(OB + 0x00000004U)/*!< option byte data address 0 */
+#define OB_DATA_ADDR1           (uint32_t)(OB + 0x00000006U)/*!< option byte data address 1 */
+#define OB_WP_ADDR0             (uint32_t)(OB + 0x00000008U)/*!< option byte wp address 0 */
+#define OB_WP_ADDR1             (uint32_t)(OB + 0x0000000AU)/*!< option byte wp address 1 */
+
+/* FMC flags */
+#define FMC_FLAG_BUSY           FMC_STAT_BUSY               /*!< FMC busy flag */
+#define FMC_FLAG_PGERR          FMC_STAT_PGERR              /*!< FMC programming error flag */
+#define FMC_FLAG_WPERR          FMC_STAT_WPERR              /*!< FMC write protection error flag */
+#define FMC_FLAG_END            FMC_STAT_ENDF               /*!< FMC end of programming flag */
+
+/* FMC interrupt enable */
+#define FMC_INTEN_END           FMC_CTL_ENDIE               /*!< enable FMC end of operation interrupt */
+#define FMC_INTEN_ERR           FMC_CTL_ERRIE               /*!< enable FMC error interrupt */
+
+/* FMC time out */
+#define FMC_TIMEOUT_COUNT       ((uint32_t)0x000F0000U)     /*!< count to judge of FMC timeout */
+
+/* function declarations */
+/* FMC main memory programming functions */
+/* unlock the main FMC operation */
+void fmc_unlock(void);
+/* lock the main FMC operation */
+void fmc_lock(void);
+/* set the wait state counter value */
+void fmc_wscnt_set(uint8_t wscnt);
+/* fmc wait state enable */
+void fmc_wait_state_enable(void);
+/* fmc wait state disable */
+void fmc_wait_state_disable(void);
+/* FMC erase page */
+fmc_state_enum fmc_page_erase(uint32_t page_address);
+/* FMC erase whole chip */
+fmc_state_enum fmc_mass_erase(void);
+/* FMC program a word at the corresponding address */
+fmc_state_enum fmc_word_program(uint32_t address, uint32_t data);
+/* FMC program a half word at the corresponding address */
+fmc_state_enum fmc_halfword_program(uint32_t address, uint16_t data);
+/* FMC program a word at the corresponding address without erasing */
+fmc_state_enum fmc_word_reprogram(uint32_t address, uint32_t data);
+
+/* FMC option bytes programming functions */
+/* unlock the option byte operation */
+void ob_unlock(void);
+/* lock the option byte operation */
+void ob_lock(void);
+/* reload the option byte and generate a system reset */
+void ob_reset(void);
+/* erase option byte */
+fmc_state_enum ob_erase(void);
+/* enable option byte write protection (OB_WP) */
+fmc_state_enum ob_write_protection_enable(uint16_t ob_wp);
+/* configure read out protect */
+fmc_state_enum ob_security_protection_config(uint8_t ob_spc);
+/* write the FMC option byte user */
+fmc_state_enum ob_user_write(uint8_t ob_user);
+/* write the FMC option byte data */
+fmc_state_enum ob_data_program(uint32_t address, uint8_t data);
+/* get the FMC option byte OB_USER */
+uint8_t ob_user_get(void);
+/* get the FMC option byte OB_DATA */
+uint16_t ob_data_get(void);
+/* get the FMC option byte write protection */
+uint16_t ob_write_protection_get(void);
+/* get the value of FMC option byte security protection level (PLEVEL) in FMC_OBSTAT register */
+uint32_t ob_obstat_plevel_get(void);
+
+/* FMC interrupts and flags management functions */
+/* enable FMC interrupt */
+void fmc_interrupt_enable(uint32_t interrupt);
+/* disable FMC interrupt */
+void fmc_interrupt_disable(uint32_t interrupt);
+/* get flag set or reset */
+FlagStatus fmc_flag_get(uint32_t flag);
+/* clear the FMC pending flag */
+void fmc_flag_clear(uint32_t flag);
+/* get interrupt flag set or reset */
+FlagStatus fmc_interrupt_flag_get(uint32_t flag);
+/* clear the FMC interrupt pending flag */
+void fmc_interrupt_flag_clear(uint32_t flag);
+/* return the FMC state */
+fmc_state_enum fmc_state_get(void);
+/* check FMC ready or not */
+fmc_state_enum fmc_ready_wait(uint32_t timeout);
+/* get current option byte value */
+void ob_parm_get(ob_parm_struct *ob_parm);
+/* modify the target option byte depending on the original value */
+void ob_value_modify(uint32_t address, uint16_t value, ob_parm_struct *ob_parm);
+
+#endif /* GD32F3X0_FMC_H */

+ 126 - 0
GD32F3x0/GD32F3x0_standard_peripheral/Include/gd32f3x0_fwdgt.h

@@ -0,0 +1,126 @@
+/*!
+    \file    gd32f3x0_fwdgt.h
+    \brief   definitions for the FWDGT
+
+    \version 2025-01-01, V2.5.0, firmware for GD32F3x0
+*/
+
+/*
+    Copyright (c) 2025, GigaDevice Semiconductor Inc.
+
+    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 of the copyright holder 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 HOLDER 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.
+*/
+
+
+#ifndef GD32F3X0_FWDGT_H
+#define GD32F3X0_FWDGT_H
+
+#include "gd32f3x0.h"
+
+/* FWDGT definitions */
+#define FWDGT                       FWDGT_BASE                                 /*!< FWDGT base address */
+
+/* registers definitions */
+#define FWDGT_CTL                   REG32(FWDGT + 0x00000000U)                 /*!< FWDGT control register */
+#define FWDGT_PSC                   REG32(FWDGT + 0x00000004U)                 /*!< FWDGT prescaler register */
+#define FWDGT_RLD                   REG32(FWDGT + 0x00000008U)                 /*!< FWDGT reload register */
+#define FWDGT_STAT                  REG32(FWDGT + 0x0000000CU)                 /*!< FWDGT status register */
+#define FWDGT_WND                   REG32(FWDGT + 0x00000010U)                 /*!< FWDGT window register */
+
+/* bits definitions */
+/* FWDGT_CTL */
+#define FWDGT_CTL_CMD               BITS(0,15)                                 /*!< FWDGT command value */
+
+/* FWDGT_PSC */
+#define FWDGT_PSC_PSC               BITS(0,2)                                  /*!< FWDGT prescaler divider value */
+
+/* FWDGT_RLD */
+#define FWDGT_RLD_RLD               BITS(0,11)                                 /*!< FWDGT counter reload value */
+
+/* FWDGT_STAT */
+#define FWDGT_STAT_PUD              BIT(0)                                     /*!< FWDGT prescaler divider value update */
+#define FWDGT_STAT_RUD              BIT(1)                                     /*!< FWDGT counter reload value update */
+#define FWDGT_STAT_WUD              BIT(2)                                     /*!< FWDGT counter window value update */
+
+/* FWDGT_WND */
+#define FWDGT_WND_WND               BITS(0,11)                                 /*!< FWDGT counter window value */
+
+/* constants definitions */
+/* FWDGT_CTL register value */
+#define CTL_CMD(regval)             (BITS(0,15) & ((uint32_t)(regval) << 0U))   /*!< write value to FWDGT_CTL_CMD bit field */
+
+/* FWDGT_PSC register value */
+#define PSC_PSC(regval)             (BITS(0,2) & ((uint32_t)(regval) << 0U))
+#define FWDGT_PSC_DIV4              ((uint8_t)PSC_PSC(0))                      /*!< FWDGT prescaler set to 4 */
+#define FWDGT_PSC_DIV8              ((uint8_t)PSC_PSC(1))                      /*!< FWDGT prescaler set to 8 */
+#define FWDGT_PSC_DIV16             ((uint8_t)PSC_PSC(2))                      /*!< FWDGT prescaler set to 16 */
+#define FWDGT_PSC_DIV32             ((uint8_t)PSC_PSC(3))                      /*!< FWDGT prescaler set to 32 */
+#define FWDGT_PSC_DIV64             ((uint8_t)PSC_PSC(4))                      /*!< FWDGT prescaler set to 64 */
+#define FWDGT_PSC_DIV128            ((uint8_t)PSC_PSC(5))                      /*!< FWDGT prescaler set to 128 */
+#define FWDGT_PSC_DIV256            ((uint8_t)PSC_PSC(6))                      /*!< FWDGT prescaler set to 256 */
+
+/* control value */
+#define FWDGT_WRITEACCESS_ENABLE    ((uint16_t)0x5555U)                        /*!< FWDGT_CTL bits write access enable value */
+#define FWDGT_WRITEACCESS_DISABLE   ((uint16_t)0x0000U)                        /*!< FWDGT_CTL bits write access disable value */
+#define FWDGT_KEY_RELOAD            ((uint16_t)0xAAAAU)                        /*!< FWDGT_CTL bits fwdgt counter reload value */
+#define FWDGT_KEY_ENABLE            ((uint16_t)0xCCCCU)                        /*!< FWDGT_CTL bits fwdgt counter enable value */
+
+/* FWDGT timeout value */
+#define FWDGT_WND_TIMEOUT           ((uint32_t)0x000FFFFFU)                    /*!< FWDGT_WND register write operation state flag timeout */
+#define FWDGT_PSC_TIMEOUT           ((uint32_t)0x000FFFFFU)                    /*!< FWDGT_PSC register write operation state flag timeout */
+#define FWDGT_RLD_TIMEOUT           ((uint32_t)0x000FFFFFU)                    /*!< FWDGT_RLD register write operation state flag timeout */
+
+/* FWDGT flag definitions */
+#define FWDGT_FLAG_PUD              FWDGT_STAT_PUD                             /*!< a write operation to FWDGT_PSC register is on going */
+#define FWDGT_FLAG_RUD              FWDGT_STAT_RUD                             /*!< a write operation to FWDGT_RLD register is on going */
+#define FWDGT_FLAG_WUD              FWDGT_STAT_WUD                             /*!< a write operation to FWDGT_WND register is on going */
+
+/*!< write value to FWDGT_RLD_RLD bit field */
+#define RLD_RLD(regval)             (BITS(0,11) & ((uint32_t)(regval) << 0U))
+/*!< write value to FWDGT_WND_WND bit field */
+#define WND_WND(regval)             (BITS(0,11) & ((uint32_t)(regval) << 0U))
+
+/* function declarations */
+/* enable write access to FWDGT_PSC,FWDGT_RLD and FWDGT_WND */
+void fwdgt_write_enable(void);
+/* disable write access to FWDGT_PSC,FWDGT_RLD and FWDGT_WND */
+void fwdgt_write_disable(void);
+/* start the free watchdog timer counter */
+void fwdgt_enable(void);
+
+/* configure the free watchdog timer counter prescaler value */
+ErrStatus fwdgt_prescaler_value_config(uint16_t prescaler_value);
+/* configure the free watchdog timer counter reload value */
+ErrStatus fwdgt_reload_value_config(uint16_t reload_value);
+/* configure the free watchdog timer counter window value */
+ErrStatus fwdgt_window_value_config(uint16_t window_value);
+/* reload the counter of FWDGT */
+void fwdgt_counter_reload(void);
+/* configure counter reload value, and prescaler divider value */
+ErrStatus fwdgt_config(uint16_t reload_value, uint8_t prescaler_div);
+
+/* get flag state of FWDGT */
+FlagStatus fwdgt_flag_get(uint16_t flag);
+
+#endif /* GD32F3X0_FWDGT_H */

+ 407 - 0
GD32F3x0/GD32F3x0_standard_peripheral/Include/gd32f3x0_gpio.h

@@ -0,0 +1,407 @@
+/*!
+    \file    gd32f3x0_gpio.h
+    \brief   definitions for the GPIO
+
+    \version 2025-01-01, V2.5.0, firmware for GD32F3x0
+*/
+
+/*
+    Copyright (c) 2025, GigaDevice Semiconductor Inc.
+
+    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 of the copyright holder 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 HOLDER 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.
+*/
+
+#ifndef GD32F3X0_GPIO_H
+#define GD32F3X0_GPIO_H
+
+#include "gd32f3x0.h"
+
+/* GPIOx(x=A,B,C,D,F) definitions */
+#define GPIOA                      (GPIO_BASE + 0x00000000U)
+#define GPIOB                      (GPIO_BASE + 0x00000400U)
+#define GPIOC                      (GPIO_BASE + 0x00000800U)
+#define GPIOD                      (GPIO_BASE + 0x00000C00U)
+#define GPIOF                      (GPIO_BASE + 0x00001400U)
+
+/* registers definitions */
+#define GPIO_CTL(gpiox)            REG32((gpiox) + 0x00000000U)    /*!< GPIO port control register */
+#define GPIO_OMODE(gpiox)          REG32((gpiox) + 0x00000004U)    /*!< GPIO port output mode register */
+#define GPIO_OSPD0(gpiox)          REG32((gpiox) + 0x00000008U)    /*!< GPIO port output speed register 0 */
+#define GPIO_PUD(gpiox)            REG32((gpiox) + 0x0000000CU)    /*!< GPIO port pull-up/pull-down register */
+#define GPIO_ISTAT(gpiox)          REG32((gpiox) + 0x00000010U)    /*!< GPIO port input status register */
+#define GPIO_OCTL(gpiox)           REG32((gpiox) + 0x00000014U)    /*!< GPIO port output control register */
+#define GPIO_BOP(gpiox)            REG32((gpiox) + 0x00000018U)    /*!< GPIO port bit operation register */
+#define GPIO_LOCK(gpiox)           REG32((gpiox) + 0x0000001CU)    /*!< GPIO port configuration lock register */
+#define GPIO_AFSEL0(gpiox)         REG32((gpiox) + 0x00000020U)    /*!< GPIO alternate function selected register 0 */
+#define GPIO_AFSEL1(gpiox)         REG32((gpiox) + 0x00000024U)    /*!< GPIO alternate function selected register 1 */
+#define GPIO_BC(gpiox)             REG32((gpiox) + 0x00000028U)    /*!< GPIO bit clear register */
+#define GPIO_TG(gpiox)             REG32((gpiox) + 0x0000002CU)    /*!< GPIO port bit toggle register */
+#define GPIO_OSPD1(gpiox)          REG32((gpiox) + 0x0000003CU)    /*!< GPIO port output speed register 1 */
+
+/* bits definitions */
+/* GPIO_CTL */
+#define GPIO_CTL_CTL0              BITS(0,1)             /*!< pin 0 configuration bits */
+#define GPIO_CTL_CTL1              BITS(2,3)             /*!< pin 1 configuration bits */
+#define GPIO_CTL_CTL2              BITS(4,5)             /*!< pin 2 configuration bits */
+#define GPIO_CTL_CTL3              BITS(6,7)             /*!< pin 3 configuration bits */
+#define GPIO_CTL_CTL4              BITS(8,9)             /*!< pin 4 configuration bits */
+#define GPIO_CTL_CTL5              BITS(10,11)           /*!< pin 5 configuration bits */
+#define GPIO_CTL_CTL6              BITS(12,13)           /*!< pin 6 configuration bits */
+#define GPIO_CTL_CTL7              BITS(14,15)           /*!< pin 7 configuration bits */
+#define GPIO_CTL_CTL8              BITS(16,17)           /*!< pin 8 configuration bits */
+#define GPIO_CTL_CTL9              BITS(18,19)           /*!< pin 9 configuration bits */
+#define GPIO_CTL_CTL10             BITS(20,21)           /*!< pin 10 configuration bits */
+#define GPIO_CTL_CTL11             BITS(22,23)           /*!< pin 11 configuration bits */
+#define GPIO_CTL_CTL12             BITS(24,25)           /*!< pin 12 configuration bits */
+#define GPIO_CTL_CTL13             BITS(26,27)           /*!< pin 13 configuration bits */
+#define GPIO_CTL_CTL14             BITS(28,29)           /*!< pin 14 configuration bits */
+#define GPIO_CTL_CTL15             BITS(30,31)           /*!< pin 15 configuration bits */
+
+/* GPIO_OMODE */
+#define GPIO_OMODE_OM0             BIT(0)                /*!< pin 0 output mode bit */
+#define GPIO_OMODE_OM1             BIT(1)                /*!< pin 1 output mode bit */
+#define GPIO_OMODE_OM2             BIT(2)                /*!< pin 2 output mode bit */
+#define GPIO_OMODE_OM3             BIT(3)                /*!< pin 3 output mode bit */
+#define GPIO_OMODE_OM4             BIT(4)                /*!< pin 4 output mode bit */
+#define GPIO_OMODE_OM5             BIT(5)                /*!< pin 5 output mode bit */
+#define GPIO_OMODE_OM6             BIT(6)                /*!< pin 6 output mode bit */
+#define GPIO_OMODE_OM7             BIT(7)                /*!< pin 7 output mode bit */
+#define GPIO_OMODE_OM8             BIT(8)                /*!< pin 8 output mode bit */
+#define GPIO_OMODE_OM9             BIT(9)                /*!< pin 9 output mode bit */
+#define GPIO_OMODE_OM10            BIT(10)               /*!< pin 10 output mode bit */
+#define GPIO_OMODE_OM11            BIT(11)               /*!< pin 11 output mode bit */
+#define GPIO_OMODE_OM12            BIT(12)               /*!< pin 12 output mode bit */
+#define GPIO_OMODE_OM13            BIT(13)               /*!< pin 13 output mode bit */
+#define GPIO_OMODE_OM14            BIT(14)               /*!< pin 14 output mode bit */
+#define GPIO_OMODE_OM15            BIT(15)               /*!< pin 15 output mode bit */
+
+/* GPIO_OSPD0 */
+#define GPIO_OSPD0_OSPD0           BITS(0,1)             /*!< pin 0 output max speed bits */
+#define GPIO_OSPD0_OSPD1           BITS(2,3)             /*!< pin 1 output max speed bits */
+#define GPIO_OSPD0_OSPD2           BITS(4,5)             /*!< pin 2 output max speed bits */
+#define GPIO_OSPD0_OSPD3           BITS(6,7)             /*!< pin 3 output max speed bits */
+#define GPIO_OSPD0_OSPD4           BITS(8,9)             /*!< pin 4 output max speed bits */
+#define GPIO_OSPD0_OSPD5           BITS(10,11)           /*!< pin 5 output max speed bits */
+#define GPIO_OSPD0_OSPD6           BITS(12,13)           /*!< pin 6 output max speed bits */
+#define GPIO_OSPD0_OSPD7           BITS(14,15)           /*!< pin 7 output max speed bits */
+#define GPIO_OSPD0_OSPD8           BITS(16,17)           /*!< pin 8 output max speed bits */
+#define GPIO_OSPD0_OSPD9           BITS(18,19)           /*!< pin 9 output max speed bits */
+#define GPIO_OSPD0_OSPD10          BITS(20,21)           /*!< pin 10 output max speed bits */
+#define GPIO_OSPD0_OSPD11          BITS(22,23)           /*!< pin 11 output max speed bits */
+#define GPIO_OSPD0_OSPD12          BITS(24,25)           /*!< pin 12 output max speed bits */
+#define GPIO_OSPD0_OSPD13          BITS(26,27)           /*!< pin 13 output max speed bits */
+#define GPIO_OSPD0_OSPD14          BITS(28,29)           /*!< pin 14 output max speed bits */
+#define GPIO_OSPD0_OSPD15          BITS(30,31)           /*!< pin 15 output max speed bits */
+
+/* GPIO_PUD */
+#define GPIO_PUD_PUD0              BITS(0,1)             /*!< pin 0 pull-up or pull-down bits */
+#define GPIO_PUD_PUD1              BITS(2,3)             /*!< pin 1 pull-up or pull-down bits */
+#define GPIO_PUD_PUD2              BITS(4,5)             /*!< pin 2 pull-up or pull-down bits */
+#define GPIO_PUD_PUD3              BITS(6,7)             /*!< pin 3 pull-up or pull-down bits */
+#define GPIO_PUD_PUD4              BITS(8,9)             /*!< pin 4 pull-up or pull-down bits */
+#define GPIO_PUD_PUD5              BITS(10,11)           /*!< pin 5 pull-up or pull-down bits */
+#define GPIO_PUD_PUD6              BITS(12,13)           /*!< pin 6 pull-up or pull-down bits */
+#define GPIO_PUD_PUD7              BITS(14,15)           /*!< pin 7 pull-up or pull-down bits */
+#define GPIO_PUD_PUD8              BITS(16,17)           /*!< pin 8 pull-up or pull-down bits */
+#define GPIO_PUD_PUD9              BITS(18,19)           /*!< pin 9 pull-up or pull-down bits */
+#define GPIO_PUD_PUD10             BITS(20,21)           /*!< pin 10 pull-up or pull-down bits */
+#define GPIO_PUD_PUD11             BITS(22,23)           /*!< pin 11 pull-up or pull-down bits */
+#define GPIO_PUD_PUD12             BITS(24,25)           /*!< pin 12 pull-up or pull-down bits */
+#define GPIO_PUD_PUD13             BITS(26,27)           /*!< pin 13 pull-up or pull-down bits */
+#define GPIO_PUD_PUD14             BITS(28,29)           /*!< pin 14 pull-up or pull-down bits */
+#define GPIO_PUD_PUD15             BITS(30,31)           /*!< pin 15 pull-up or pull-down bits */
+
+/* GPIO_ISTAT */
+#define GPIO_ISTAT_ISTAT0          BIT(0)                /*!< pin 0 input status */
+#define GPIO_ISTAT_ISTAT1          BIT(1)                /*!< pin 1 input status */
+#define GPIO_ISTAT_ISTAT2          BIT(2)                /*!< pin 2 input status */
+#define GPIO_ISTAT_ISTAT3          BIT(3)                /*!< pin 3 input status */
+#define GPIO_ISTAT_ISTAT4          BIT(4)                /*!< pin 4 input status */
+#define GPIO_ISTAT_ISTAT5          BIT(5)                /*!< pin 5 input status */
+#define GPIO_ISTAT_ISTAT6          BIT(6)                /*!< pin 6 input status */
+#define GPIO_ISTAT_ISTAT7          BIT(7)                /*!< pin 7 input status */
+#define GPIO_ISTAT_ISTAT8          BIT(8)                /*!< pin 8 input status */
+#define GPIO_ISTAT_ISTAT9          BIT(9)                /*!< pin 9 input status */
+#define GPIO_ISTAT_ISTAT10         BIT(10)               /*!< pin 10 input status */
+#define GPIO_ISTAT_ISTAT11         BIT(11)               /*!< pin 11 input status */
+#define GPIO_ISTAT_ISTAT12         BIT(12)               /*!< pin 12 input status */
+#define GPIO_ISTAT_ISTAT13         BIT(13)               /*!< pin 13 input status */
+#define GPIO_ISTAT_ISTAT14         BIT(14)               /*!< pin 14 input status */
+#define GPIO_ISTAT_ISTAT15         BIT(15)               /*!< pin 15 input status */
+
+/* GPIO_OCTL */
+#define GPIO_OCTL_OCTL0            BIT(0)                /*!< pin 0 output bit */
+#define GPIO_OCTL_OCTL1            BIT(1)                /*!< pin 1 output bit */
+#define GPIO_OCTL_OCTL2            BIT(2)                /*!< pin 2 output bit */
+#define GPIO_OCTL_OCTL3            BIT(3)                /*!< pin 3 output bit */
+#define GPIO_OCTL_OCTL4            BIT(4)                /*!< pin 4 output bit */
+#define GPIO_OCTL_OCTL5            BIT(5)                /*!< pin 5 output bit */
+#define GPIO_OCTL_OCTL6            BIT(6)                /*!< pin 6 output bit */
+#define GPIO_OCTL_OCTL7            BIT(7)                /*!< pin 7 output bit */
+#define GPIO_OCTL_OCTL8            BIT(8)                /*!< pin 8 output bit */
+#define GPIO_OCTL_OCTL9            BIT(9)                /*!< pin 9 output bit */
+#define GPIO_OCTL_OCTL10           BIT(10)               /*!< pin 10 output bit */
+#define GPIO_OCTL_OCTL11           BIT(11)               /*!< pin 11 output bit */
+#define GPIO_OCTL_OCTL12           BIT(12)               /*!< pin 12 output bit */
+#define GPIO_OCTL_OCTL13           BIT(13)               /*!< pin 13 output bit */
+#define GPIO_OCTL_OCTL14           BIT(14)               /*!< pin 14 output bit */
+#define GPIO_OCTL_OCTL15           BIT(15)               /*!< pin 15 output bit */
+
+/* GPIO_BOP */
+#define GPIO_BOP_BOP0              BIT(0)                /*!< pin 0 set bit */
+#define GPIO_BOP_BOP1              BIT(1)                /*!< pin 1 set bit */
+#define GPIO_BOP_BOP2              BIT(2)                /*!< pin 2 set bit */
+#define GPIO_BOP_BOP3              BIT(3)                /*!< pin 3 set bit */
+#define GPIO_BOP_BOP4              BIT(4)                /*!< pin 4 set bit */
+#define GPIO_BOP_BOP5              BIT(5)                /*!< pin 5 set bit */
+#define GPIO_BOP_BOP6              BIT(6)                /*!< pin 6 set bit */
+#define GPIO_BOP_BOP7              BIT(7)                /*!< pin 7 set bit */
+#define GPIO_BOP_BOP8              BIT(8)                /*!< pin 8 set bit */
+#define GPIO_BOP_BOP9              BIT(9)                /*!< pin 9 set bit */
+#define GPIO_BOP_BOP10             BIT(10)               /*!< pin 10 set bit */
+#define GPIO_BOP_BOP11             BIT(11)               /*!< pin 11 set bit */
+#define GPIO_BOP_BOP12             BIT(12)               /*!< pin 12 set bit */
+#define GPIO_BOP_BOP13             BIT(13)               /*!< pin 13 set bit */
+#define GPIO_BOP_BOP14             BIT(14)               /*!< pin 14 set bit */
+#define GPIO_BOP_BOP15             BIT(15)               /*!< pin 15 set bit */
+#define GPIO_BOP_CR0               BIT(16)               /*!< pin 0 clear bit */
+#define GPIO_BOP_CR1               BIT(17)               /*!< pin 1 clear bit */
+#define GPIO_BOP_CR2               BIT(18)               /*!< pin 2 clear bit */
+#define GPIO_BOP_CR3               BIT(19)               /*!< pin 3 clear bit */
+#define GPIO_BOP_CR4               BIT(20)               /*!< pin 4 clear bit */
+#define GPIO_BOP_CR5               BIT(21)               /*!< pin 5 clear bit */
+#define GPIO_BOP_CR6               BIT(22)               /*!< pin 6 clear bit */
+#define GPIO_BOP_CR7               BIT(23)               /*!< pin 7 clear bit */
+#define GPIO_BOP_CR8               BIT(24)               /*!< pin 8 clear bit */
+#define GPIO_BOP_CR9               BIT(25)               /*!< pin 9 clear bit */
+#define GPIO_BOP_CR10              BIT(26)               /*!< pin 10 clear bit */
+#define GPIO_BOP_CR11              BIT(27)               /*!< pin 11 clear bit */
+#define GPIO_BOP_CR12              BIT(28)               /*!< pin 12 clear bit */
+#define GPIO_BOP_CR13              BIT(29)               /*!< pin 13 clear bit */
+#define GPIO_BOP_CR14              BIT(30)               /*!< pin 14 clear bit */
+#define GPIO_BOP_CR15              BIT(31)               /*!< pin 15 clear bit */
+
+/* GPIO_LOCK */
+#define GPIO_LOCK_LK0              BIT(0)                /*!< pin 0 lock bit */
+#define GPIO_LOCK_LK1              BIT(1)                /*!< pin 1 lock bit */
+#define GPIO_LOCK_LK2              BIT(2)                /*!< pin 2 lock bit */
+#define GPIO_LOCK_LK3              BIT(3)                /*!< pin 3 lock bit */
+#define GPIO_LOCK_LK4              BIT(4)                /*!< pin 4 lock bit */
+#define GPIO_LOCK_LK5              BIT(5)                /*!< pin 5 lock bit */
+#define GPIO_LOCK_LK6              BIT(6)                /*!< pin 6 lock bit */
+#define GPIO_LOCK_LK7              BIT(7)                /*!< pin 7 lock bit */
+#define GPIO_LOCK_LK8              BIT(8)                /*!< pin 8 lock bit */
+#define GPIO_LOCK_LK9              BIT(9)                /*!< pin 9 lock bit */
+#define GPIO_LOCK_LK10             BIT(10)               /*!< pin 10 lock bit */
+#define GPIO_LOCK_LK11             BIT(11)               /*!< pin 11 lock bit */
+#define GPIO_LOCK_LK12             BIT(12)               /*!< pin 12 lock bit */
+#define GPIO_LOCK_LK13             BIT(13)               /*!< pin 13 lock bit */
+#define GPIO_LOCK_LK14             BIT(14)               /*!< pin 14 lock bit */
+#define GPIO_LOCK_LK15             BIT(15)               /*!< pin 15 lock bit */
+#define GPIO_LOCK_LKK              BIT(16)               /*!< pin sequence lock key */
+
+/* GPIO_AFSEL0 */
+#define GPIO_AFSEL0_SEL0           BITS(0,3)             /*!< pin 0 alternate function selected */
+#define GPIO_AFSEL0_SEL1           BITS(4,7)             /*!< pin 1 alternate function selected */
+#define GPIO_AFSEL0_SEL2           BITS(8,11)            /*!< pin 2 alternate function selected */
+#define GPIO_AFSEL0_SEL3           BITS(12,15)           /*!< pin 3 alternate function selected */
+#define GPIO_AFSEL0_SEL4           BITS(16,19)           /*!< pin 4 alternate function selected */
+#define GPIO_AFSEL0_SEL5           BITS(20,23)           /*!< pin 5 alternate function selected */
+#define GPIO_AFSEL0_SEL6           BITS(24,27)           /*!< pin 6 alternate function selected */
+#define GPIO_AFSEL0_SEL7           BITS(28,31)           /*!< pin 7 alternate function selected */
+
+/* GPIO_AFSEL1 */
+#define GPIO_AFSEL1_SEL8           BITS(0,3)             /*!< pin 8 alternate function selected */
+#define GPIO_AFSEL1_SEL9           BITS(4,7)             /*!< pin 9 alternate function selected */
+#define GPIO_AFSEL1_SEL10          BITS(8,11)            /*!< pin 10 alternate function selected */
+#define GPIO_AFSEL1_SEL11          BITS(12,15)           /*!< pin 11 alternate function selected */
+#define GPIO_AFSEL1_SEL12          BITS(16,19)           /*!< pin 12 alternate function selected */
+#define GPIO_AFSEL1_SEL13          BITS(20,23)           /*!< pin 13 alternate function selected */
+#define GPIO_AFSEL1_SEL14          BITS(24,27)           /*!< pin 14 alternate function selected */
+#define GPIO_AFSEL1_SEL15          BITS(28,31)           /*!< pin 15 alternate function selected */
+
+/* GPIO_BC */
+#define GPIO_BC_CR0                BIT(0)                /*!< pin 0 clear bit */
+#define GPIO_BC_CR1                BIT(1)                /*!< pin 1 clear bit */
+#define GPIO_BC_CR2                BIT(2)                /*!< pin 2 clear bit */
+#define GPIO_BC_CR3                BIT(3)                /*!< pin 3 clear bit */
+#define GPIO_BC_CR4                BIT(4)                /*!< pin 4 clear bit */
+#define GPIO_BC_CR5                BIT(5)                /*!< pin 5 clear bit */
+#define GPIO_BC_CR6                BIT(6)                /*!< pin 6 clear bit */
+#define GPIO_BC_CR7                BIT(7)                /*!< pin 7 clear bit */
+#define GPIO_BC_CR8                BIT(8)                /*!< pin 8 clear bit */
+#define GPIO_BC_CR9                BIT(9)                /*!< pin 9 clear bit */
+#define GPIO_BC_CR10               BIT(10)               /*!< pin 10 clear bit */
+#define GPIO_BC_CR11               BIT(11)               /*!< pin 11 clear bit */
+#define GPIO_BC_CR12               BIT(12)               /*!< pin 12 clear bit */
+#define GPIO_BC_CR13               BIT(13)               /*!< pin 13 clear bit */
+#define GPIO_BC_CR14               BIT(14)               /*!< pin 14 clear bit */
+#define GPIO_BC_CR15               BIT(15)               /*!< pin 15 clear bit */
+
+/* GPIO_TG */
+#define GPIO_TG_TG0                BIT(0)                /*!< pin 0 toggle bit */
+#define GPIO_TG_TG1                BIT(1)                /*!< pin 1 toggle bit */
+#define GPIO_TG_TG2                BIT(2)                /*!< pin 2 toggle bit */
+#define GPIO_TG_TG3                BIT(3)                /*!< pin 3 toggle bit */
+#define GPIO_TG_TG4                BIT(4)                /*!< pin 4 toggle bit */
+#define GPIO_TG_TG5                BIT(5)                /*!< pin 5 toggle bit */
+#define GPIO_TG_TG6                BIT(6)                /*!< pin 6 toggle bit */
+#define GPIO_TG_TG7                BIT(7)                /*!< pin 7 toggle bit */
+#define GPIO_TG_TG8                BIT(8)                /*!< pin 8 toggle bit */
+#define GPIO_TG_TG9                BIT(9)                /*!< pin 9 toggle bit */
+#define GPIO_TG_TG10               BIT(10)               /*!< pin 10 toggle bit */
+#define GPIO_TG_TG11               BIT(11)               /*!< pin 11 toggle bit */
+#define GPIO_TG_TG12               BIT(12)               /*!< pin 12 toggle bit */
+#define GPIO_TG_TG13               BIT(13)               /*!< pin 13 toggle bit */
+#define GPIO_TG_TG14               BIT(14)               /*!< pin 14 toggle bit */
+#define GPIO_TG_TG15               BIT(15)               /*!< pin 15 toggle bit */
+
+/* GPIO_OSPD1 */
+#define GPIO_OSPD1_SPD0            BIT(0)                /*!< set pin 0 very high output speed when OSPD0 is "11" */
+#define GPIO_OSPD1_SPD1            BIT(1)                /*!< set pin 1 very high output speed when OSPD1 is "11" */
+#define GPIO_OSPD1_SPD2            BIT(2)                /*!< set pin 2 very high output speed when OSPD2 is "11" */
+#define GPIO_OSPD1_SPD3            BIT(3)                /*!< set pin 3 very high output speed when OSPD3 is "11" */
+#define GPIO_OSPD1_SPD4            BIT(4)                /*!< set pin 4 very high output speed when OSPD4 is "11" */
+#define GPIO_OSPD1_SPD5            BIT(5)                /*!< set pin 5 very high output speed when OSPD5 is "11" */
+#define GPIO_OSPD1_SPD6            BIT(6)                /*!< set pin 6 very high output speed when OSPD6 is "11" */
+#define GPIO_OSPD1_SPD7            BIT(7)                /*!< set pin 7 very high output speed when OSPD7 is "11" */
+#define GPIO_OSPD1_SPD8            BIT(8)                /*!< set pin 8 very high output speed when OSPD8 is "11" */
+#define GPIO_OSPD1_SPD9            BIT(9)                /*!< set pin 9 very high output speed when OSPD9 is "11" */
+#define GPIO_OSPD1_SPD10           BIT(10)               /*!< set pin 10 very high output speed when OSPD10 is "11" */
+#define GPIO_OSPD1_SPD11           BIT(11)               /*!< set pin 11 very high output speed when OSPD11 is "11" */
+#define GPIO_OSPD1_SPD12           BIT(12)               /*!< set pin 12 very high output speed when OSPD12 is "11" */
+#define GPIO_OSPD1_SPD13           BIT(13)               /*!< set pin 13 very high output speed when OSPD13 is "11" */
+#define GPIO_OSPD1_SPD14           BIT(14)               /*!< set pin 14 very high output speed when OSPD14 is "11" */
+#define GPIO_OSPD1_SPD15           BIT(15)               /*!< set pin 15 very high output speed when OSPD15 is "11" */
+
+/* constants definitions */
+typedef FlagStatus bit_status;
+
+/* output mode definitions */
+#define CTL_CLTR(regval)           (BITS(0,1) & ((uint32_t)(regval) << 0))
+#define GPIO_MODE_INPUT            CTL_CLTR(0)           /*!< input mode */
+#define GPIO_MODE_OUTPUT           CTL_CLTR(1)           /*!< output mode */
+#define GPIO_MODE_AF               CTL_CLTR(2)           /*!< alternate function mode */
+#define GPIO_MODE_ANALOG           CTL_CLTR(3)           /*!< analog mode */
+
+/* pull-up/pull-down definitions */
+#define PUD_PUPD(regval)           (BITS(0,1) & ((uint32_t)(regval) << 0))
+#define GPIO_PUPD_NONE             PUD_PUPD(0)           /*!< floating mode, no pull-up and pull-down resistors */
+#define GPIO_PUPD_PULLUP           PUD_PUPD(1)           /*!< with pull-up resistor */
+#define GPIO_PUPD_PULLDOWN         PUD_PUPD(2)           /*!< with pull-down resistor */
+
+/* GPIO pin definitions */
+#define GPIO_PIN_0                 BIT(0)                /*!< GPIO pin 0 */
+#define GPIO_PIN_1                 BIT(1)                /*!< GPIO pin 1 */
+#define GPIO_PIN_2                 BIT(2)                /*!< GPIO pin 2 */
+#define GPIO_PIN_3                 BIT(3)                /*!< GPIO pin 3 */
+#define GPIO_PIN_4                 BIT(4)                /*!< GPIO pin 4 */
+#define GPIO_PIN_5                 BIT(5)                /*!< GPIO pin 5 */
+#define GPIO_PIN_6                 BIT(6)                /*!< GPIO pin 6 */
+#define GPIO_PIN_7                 BIT(7)                /*!< GPIO pin 7 */
+#define GPIO_PIN_8                 BIT(8)                /*!< GPIO pin 8 */
+#define GPIO_PIN_9                 BIT(9)                /*!< GPIO pin 9 */
+#define GPIO_PIN_10                BIT(10)               /*!< GPIO pin 10 */
+#define GPIO_PIN_11                BIT(11)               /*!< GPIO pin 11 */
+#define GPIO_PIN_12                BIT(12)               /*!< GPIO pin 12 */
+#define GPIO_PIN_13                BIT(13)               /*!< GPIO pin 13 */
+#define GPIO_PIN_14                BIT(14)               /*!< GPIO pin 14 */
+#define GPIO_PIN_15                BIT(15)               /*!< GPIO pin 15 */
+#define GPIO_PIN_ALL               BITS(0,15)            /*!< GPIO pin all */
+
+/* GPIO mode configuration values */
+#define GPIO_MODE_SET(n, mode)     ((uint32_t)((uint32_t)(mode) << (2U * (n))))
+#define GPIO_MODE_MASK(n)          ((uint32_t)((uint32_t)0x00000003U << (2U * (n))))
+
+/* GPIO pull-up/pull-down values */
+#define GPIO_PUPD_SET(n, pupd)     ((uint32_t)((uint32_t)(pupd) << (2U * (n))))
+#define GPIO_PUPD_MASK(n)          ((uint32_t)((uint32_t)0x00000003U << (2U * (n))))
+
+/* GPIO output speed values */
+#define GPIO_OSPEED_SET(n, speed)  ((uint32_t)((uint32_t)(speed) << (2U * (n))))
+#define GPIO_OSPEED_MASK(n)        ((uint32_t)((uint32_t)0x00000003U << (2U * (n))))
+
+/* GPIO output type */
+#define GPIO_OTYPE_PP              ((uint8_t)(0x00U))    /*!< push pull mode */
+#define GPIO_OTYPE_OD              ((uint8_t)(0x01U))    /*!< open drain mode */
+
+/* GPIO output max speed value */
+#define OSPD_OSPD0(regval)         (BITS(0,1) & ((uint32_t)(regval) << 0))
+#define GPIO_OSPEED_2MHZ           OSPD_OSPD0(0)                     /*!< output max speed 2MHz */
+#define GPIO_OSPEED_10MHZ          OSPD_OSPD0(1)                     /*!< output max speed 10MHz */
+#define GPIO_OSPEED_50MHZ          OSPD_OSPD0(3)                     /*!< output max speed 50MHz */
+#define GPIO_OSPEED_MAX            ((uint32_t)0x0000FFFFU)           /*!< GPIO very high output speed, max speed more than 50MHz */
+
+/* GPIO alternate function values */
+#define GPIO_AFR_SET(n, af)        ((uint32_t)((uint32_t)(af) << (4U * (n))))
+#define GPIO_AFR_MASK(n)           ((uint32_t)((uint32_t)0x0000000FU << (4U * (n))))
+
+/* GPIO alternate function */
+#define AF(regval)                 (BITS(0,3) & ((uint32_t)(regval) << 0))
+#define GPIO_AF_0                   AF(0)                /*!< alternate function 0 selected */
+#define GPIO_AF_1                   AF(1)                /*!< alternate function 1 selected */
+#define GPIO_AF_2                   AF(2)                /*!< alternate function 2 selected */
+#define GPIO_AF_3                   AF(3)                /*!< alternate function 3 selected */
+#define GPIO_AF_4                   AF(4)                /*!< alternate function 4 selected (port A,B only) */
+#define GPIO_AF_5                   AF(5)                /*!< alternate function 5 selected (port A,B only) */
+#define GPIO_AF_6                   AF(6)                /*!< alternate function 6 selected (port A,B only) */
+#define GPIO_AF_7                   AF(7)                /*!< alternate function 7 selected (port A,B only) */
+
+/* function declarations */
+/* reset GPIO port */
+void gpio_deinit(uint32_t gpio_periph);
+/* set GPIO mode */
+void gpio_mode_set(uint32_t gpio_periph, uint32_t mode, uint32_t pull_up_down, uint32_t pin);
+/* set GPIO output type and speed */
+void gpio_output_options_set(uint32_t gpio_periph, uint8_t otype, uint32_t speed, uint32_t pin);
+
+/* set GPIO pin bit */
+void gpio_bit_set(uint32_t gpio_periph, uint32_t pin);
+/* reset GPIO pin bit */
+void gpio_bit_reset(uint32_t gpio_periph, uint32_t pin);
+/* write data to the specified GPIO pin */
+void gpio_bit_write(uint32_t gpio_periph, uint32_t pin, bit_status bit_value);
+/* write data to the specified GPIO port */
+void gpio_port_write(uint32_t gpio_periph, uint16_t data);
+
+/* get GPIO pin input status */
+FlagStatus gpio_input_bit_get(uint32_t gpio_periph, uint32_t pin);
+/* get GPIO port input status */
+uint16_t gpio_input_port_get(uint32_t gpio_periph);
+/* get GPIO pin output status */
+FlagStatus gpio_output_bit_get(uint32_t gpio_periph, uint32_t pin);
+/* get GPIO port output status */
+uint16_t gpio_output_port_get(uint32_t gpio_periph);
+
+/* set GPIO alternate function */
+void gpio_af_set(uint32_t gpio_periph, uint32_t alt_func_num, uint32_t pin);
+/* lock GPIO pin bit */
+void gpio_pin_lock(uint32_t gpio_periph, uint32_t pin);
+
+/* toggle GPIO pin status */
+void gpio_bit_toggle(uint32_t gpio_periph, uint32_t pin);
+/* toggle GPIO port status */
+void gpio_port_toggle(uint32_t gpio_periph);
+
+#endif /* GD32F3X0_GPIO_H */

+ 344 - 0
GD32F3x0/GD32F3x0_standard_peripheral/Include/gd32f3x0_i2c.h

@@ -0,0 +1,344 @@
+/*!
+    \file    gd32f3x0_i2c.h
+    \brief   definitions for the I2C
+
+    \version 2025-01-01, V2.5.0, firmware for GD32F3x0
+*/
+
+/*
+    Copyright (c) 2025, GigaDevice Semiconductor Inc.
+
+    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 of the copyright holder 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 HOLDER 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.
+*/
+
+#ifndef GD32F3X0_I2C_H
+#define GD32F3X0_I2C_H
+
+#include "gd32f3x0.h"
+
+/* I2Cx(x=0,1) definitions */
+#define I2C0                          I2C_BASE                         /*!< I2C0 base address */
+#define I2C1                          (I2C_BASE+0x00000400U)           /*!< I2C1 base address */
+
+/* registers definitions */
+#define I2C_CTL0(i2cx)                REG32((i2cx) + 0x00000000U)      /*!< I2C control register 0 */
+#define I2C_CTL1(i2cx)                REG32((i2cx) + 0x00000004U)      /*!< I2C control register 1 */
+#define I2C_SADDR0(i2cx)              REG32((i2cx) + 0x00000008U)      /*!< I2C slave address register 0*/
+#define I2C_SADDR1(i2cx)              REG32((i2cx) + 0x0000000CU)      /*!< I2C slave address register 1 */
+#define I2C_DATA(i2cx)                REG32((i2cx) + 0x00000010U)      /*!< I2C transfer buffer register */
+#define I2C_STAT0(i2cx)               REG32((i2cx) + 0x00000014U)      /*!< I2C transfer status register 0 */
+#define I2C_STAT1(i2cx)               REG32((i2cx) + 0x00000018U)      /*!< I2C transfer status register */
+#define I2C_CKCFG(i2cx)               REG32((i2cx) + 0x0000001CU)      /*!< I2C clock configure register */
+#define I2C_RT(i2cx)                  REG32((i2cx) + 0x00000020U)      /*!< I2C rise time register */
+#define I2C_FMPCFG(i2cx)              REG32((i2cx) + 0x00000090U)      /*!< I2C fast-mode-plus configure register */
+
+/* bits definitions */
+/* I2Cx_CTL0 */
+#define I2C_CTL0_I2CEN                BIT(0)        /*!< peripheral enable */
+#define I2C_CTL0_SMBEN                BIT(1)        /*!< SMBus mode */
+#define I2C_CTL0_SMBSEL               BIT(3)        /*!< SMBus type */
+#define I2C_CTL0_ARPEN                BIT(4)        /*!< ARP enable */
+#define I2C_CTL0_PECEN                BIT(5)        /*!< PEC enable */
+#define I2C_CTL0_GCEN                 BIT(6)        /*!< general call enable */
+#define I2C_CTL0_SS                   BIT(7)        /*!< clock stretching disable (slave mode) */
+#define I2C_CTL0_START                BIT(8)        /*!< start generation */
+#define I2C_CTL0_STOP                 BIT(9)        /*!< stop generation */
+#define I2C_CTL0_ACKEN                BIT(10)       /*!< acknowledge enable */
+#define I2C_CTL0_POAP                 BIT(11)       /*!< acknowledge/PEC position (for data reception) */
+#define I2C_CTL0_PECTRANS             BIT(12)       /*!< packet error checking */
+#define I2C_CTL0_SALT                 BIT(13)       /*!< SMBus alert */
+#define I2C_CTL0_SRESET               BIT(15)       /*!< software reset */
+
+/* I2Cx_CTL1 */
+#define I2C_CTL1_I2CCLK               BITS(0,5)     /*!< I2CCLK[5:0] bits (peripheral clock frequency) */
+#define I2C_CTL1_ERRIE                BIT(8)        /*!< error interrupt enable */
+#define I2C_CTL1_EVIE                 BIT(9)        /*!< event interrupt enable */
+#define I2C_CTL1_BUFIE                BIT(10)       /*!< buffer interrupt enable */
+#define I2C_CTL1_DMAON                BIT(11)       /*!< DMA requests enable */
+#define I2C_CTL1_DMALST               BIT(12)       /*!< DMA last transfer */
+
+/* I2Cx_SADDR0 */
+#define I2C_SADDR0_ADDRESS0           BIT(0)        /*!< bit 0 of a 10-bit address */
+#define I2C_SADDR0_ADDRESS            BITS(1,7)     /*!< 7-bit address or bits 7:1 of a 10-bit address */
+#define I2C_SADDR0_ADDRESS_H          BITS(8,9)     /*!< highest two bits of a 10-bit address */
+#define I2C_SADDR0_ADDFORMAT          BIT(15)       /*!< address mode for the I2C slave */
+
+/* I2Cx_SADDR1 */
+#define I2C_SADDR1_DUADEN             BIT(0)        /*!< aual-address mode switch */
+#define I2C_SADDR1_ADDRESS2           BITS(1,7)     /*!< second I2C address for the slave in dual-address mode */
+
+/* I2Cx_DATA */
+#define I2C_DATA_TRB                  BITS(0,7)     /*!< 8-bit data register */
+
+/* I2Cx_STAT0 */
+#define I2C_STAT0_SBSEND              BIT(0)        /*!< start bit (master mode) */
+#define I2C_STAT0_ADDSEND             BIT(1)        /*!< address sent (master mode)/matched (slave mode) */
+#define I2C_STAT0_BTC                 BIT(2)        /*!< byte transfer finished */
+#define I2C_STAT0_ADD10SEND           BIT(3)        /*!< 10-bit header sent (master mode) */
+#define I2C_STAT0_STPDET              BIT(4)        /*!< stop detection (slave mode) */
+#define I2C_STAT0_RBNE                BIT(6)        /*!< data register not empty (receivers) */
+#define I2C_STAT0_TBE                 BIT(7)        /*!< data register empty (transmitters) */
+#define I2C_STAT0_BERR                BIT(8)        /*!< bus error */
+#define I2C_STAT0_LOSTARB             BIT(9)        /*!< arbitration lost (master mode) */
+#define I2C_STAT0_AERR                BIT(10)       /*!< acknowledge failure */
+#define I2C_STAT0_OUERR               BIT(11)       /*!< overrun/underrun */
+#define I2C_STAT0_PECERR              BIT(12)       /*!< PEC error in reception */
+#define I2C_STAT0_SMBTO               BIT(14)       /*!< timeout signal in SMBus mode */
+#define I2C_STAT0_SMBALT              BIT(15)       /*!< SMBus alert status */
+
+/* I2Cx_STAT1 */
+#define I2C_STAT1_MASTER              BIT(0)        /*!< master/slave */
+#define I2C_STAT1_I2CBSY              BIT(1)        /*!< bus busy */
+#define I2C_STAT1_TR                  BIT(2)        /*!< transmitter/receiver */
+#define I2C_STAT1_RXGC                BIT(4)        /*!< general call address (slave mode) */
+#define I2C_STAT1_DEFSMB              BIT(5)        /*!< SMBus device default address (slave mode) */
+#define I2C_STAT1_HSTSMB              BIT(6)        /*!< SMBus host header (slave mode) */
+#define I2C_STAT1_DUMODF              BIT(7)        /*!< dual flag (slave mode) */
+#define I2C_STAT1_PECV                BITS(8,15)    /*!< packet error checking value */
+
+/* I2Cx_CKCFG */
+#define I2C_CKCFG_CLKC                BITS(0,11)    /*!< clock control register in fast/standard mode or fast mode plus(master mode) */
+#define I2C_CKCFG_DTCY                BIT(14)       /*!< duty cycle of fast mode or fast mode plus */
+#define I2C_CKCFG_FAST                BIT(15)       /*!< I2C speed selection in master mode */
+
+/* I2Cx_RT */
+#define I2C_RT_RISETIME               BITS(0,6)     /*!< maximum rise time in fast/standard mode or fast mode plus(master mode) */
+
+/* I2Cx_FMPCFG */
+#define I2C_FMPCFG_FMPEN              BIT(0)        /*!< fast mode plus enable */
+
+/* constants definitions */
+/* define the I2C bit position and its register index offset */
+#define I2C_REGIDX_BIT(regidx, bitpos)  (((uint32_t)(regidx) << 6) | (uint32_t)(bitpos))
+#define I2C_REG_VAL(i2cx, offset)       (REG32((i2cx) + (((uint32_t)(offset) & 0x0000FFFFU) >> 6)))
+#define I2C_BIT_POS(val)                ((uint32_t)(val) & 0x0000001FU)
+#define I2C_REGIDX_BIT2(regidx, bitpos, regidx2, bitpos2)   (((uint32_t)(regidx2) << 22) | (uint32_t)((bitpos2) << 16)\
+                                                              | (((uint32_t)(regidx) << 6) | (uint32_t)(bitpos)))
+#define I2C_REG_VAL2(i2cx, offset)      (REG32((i2cx) + ((uint32_t)(offset) >> 22)))
+#define I2C_BIT_POS2(val)               (((uint32_t)(val) & 0x001F0000U) >> 16)
+
+/* register offset */
+#define I2C_CTL1_REG_OFFSET           (0x00000004U)         /*!< CTL1 register offset */
+#define I2C_STAT0_REG_OFFSET          (0x00000014U)         /*!< STAT0 register offset */
+#define I2C_STAT1_REG_OFFSET          (0x00000018U)         /*!< STAT1 register offset */
+
+/* I2C flags */
+typedef enum {
+    /* flags in STAT0 register */
+    I2C_FLAG_SBSEND = I2C_REGIDX_BIT(I2C_STAT0_REG_OFFSET, 0U),                /*!< start condition sent out in master mode */
+    I2C_FLAG_ADDSEND = I2C_REGIDX_BIT(I2C_STAT0_REG_OFFSET, 1U),               /*!< address is sent in master mode or received and matches in slave mode */
+    I2C_FLAG_BTC = I2C_REGIDX_BIT(I2C_STAT0_REG_OFFSET, 2U),                   /*!< byte transmission finishes */
+    I2C_FLAG_ADD10SEND = I2C_REGIDX_BIT(I2C_STAT0_REG_OFFSET, 3U),             /*!< header of 10-bit address is sent in master mode */
+    I2C_FLAG_STPDET = I2C_REGIDX_BIT(I2C_STAT0_REG_OFFSET, 4U),                /*!< stop condition detected in slave mode */
+    I2C_FLAG_RBNE = I2C_REGIDX_BIT(I2C_STAT0_REG_OFFSET, 6U),                  /*!< I2C_DATA is not empty during receiving */
+    I2C_FLAG_TBE = I2C_REGIDX_BIT(I2C_STAT0_REG_OFFSET, 7U),                   /*!< I2C_DATA is empty during transmitting */
+    I2C_FLAG_BERR = I2C_REGIDX_BIT(I2C_STAT0_REG_OFFSET, 8U),                  /*!< a bus error occurs indication a unexpected start or stop condition on I2C bus */
+    I2C_FLAG_LOSTARB = I2C_REGIDX_BIT(I2C_STAT0_REG_OFFSET, 9U),               /*!< arbitration lost in master mode */
+    I2C_FLAG_AERR = I2C_REGIDX_BIT(I2C_STAT0_REG_OFFSET, 10U),                 /*!< acknowledge error */
+    I2C_FLAG_OUERR = I2C_REGIDX_BIT(I2C_STAT0_REG_OFFSET, 11U),                /*!< over-run or under-run situation occurs in slave mode */
+    I2C_FLAG_PECERR = I2C_REGIDX_BIT(I2C_STAT0_REG_OFFSET, 12U),               /*!< PEC error when receiving data */
+    I2C_FLAG_SMBTO = I2C_REGIDX_BIT(I2C_STAT0_REG_OFFSET, 14U),                /*!< timeout signal in SMBus mode */
+    I2C_FLAG_SMBALT = I2C_REGIDX_BIT(I2C_STAT0_REG_OFFSET, 15U),               /*!< SMBus alert status */
+    /* flags in STAT1 register */
+    I2C_FLAG_MASTER = I2C_REGIDX_BIT(I2C_STAT1_REG_OFFSET, 0U),                /*!< a flag indicating whether I2C block is in master or slave mode */
+    I2C_FLAG_I2CBSY = I2C_REGIDX_BIT(I2C_STAT1_REG_OFFSET, 1U),                /*!< busy flag */
+    I2C_FLAG_TR = I2C_REGIDX_BIT(I2C_STAT1_REG_OFFSET, 2U),                    /*!< whether the I2C is a transmitter or a receiver */
+    I2C_FLAG_RXGC = I2C_REGIDX_BIT(I2C_STAT1_REG_OFFSET, 4U),                  /*!< general call address (00h) received */
+    I2C_FLAG_DEFSMB = I2C_REGIDX_BIT(I2C_STAT1_REG_OFFSET, 5U),                /*!< default address of SMBus device */
+    I2C_FLAG_HSTSMB = I2C_REGIDX_BIT(I2C_STAT1_REG_OFFSET, 6U),                /*!< SMBus host header detected in slave mode */
+    I2C_FLAG_DUMOD = I2C_REGIDX_BIT(I2C_STAT1_REG_OFFSET, 7U)                  /*!< dual flag in slave mode indicating which address is matched in dual-address mode */
+} i2c_flag_enum;
+
+/* I2C interrupt flags */
+typedef enum {
+    /* interrupt flags in CTL1 register */
+    I2C_INT_FLAG_SBSEND = I2C_REGIDX_BIT2(I2C_CTL1_REG_OFFSET, 9U, I2C_STAT0_REG_OFFSET, 0U),        /*!< start condition sent out in master mode interrupt flag */
+    I2C_INT_FLAG_ADDSEND = I2C_REGIDX_BIT2(I2C_CTL1_REG_OFFSET, 9U, I2C_STAT0_REG_OFFSET, 1U),       /*!< address is sent in master mode or received and matches in slave mode interrupt flag */
+    I2C_INT_FLAG_BTC =  I2C_REGIDX_BIT2(I2C_CTL1_REG_OFFSET, 9U, I2C_STAT0_REG_OFFSET, 2U),          /*!< byte transmission finishes interrupt flag */
+    I2C_INT_FLAG_ADD10SEND =  I2C_REGIDX_BIT2(I2C_CTL1_REG_OFFSET, 9U, I2C_STAT0_REG_OFFSET, 3U),    /*!< header of 10-bit address is sent in master mode interrupt flag */
+    I2C_INT_FLAG_STPDET = I2C_REGIDX_BIT2(I2C_CTL1_REG_OFFSET, 9U, I2C_STAT0_REG_OFFSET, 4U),        /*!< stop condition detected in slave mode interrupt flag */
+    I2C_INT_FLAG_RBNE = I2C_REGIDX_BIT2(I2C_CTL1_REG_OFFSET, 9U, I2C_STAT0_REG_OFFSET, 6U),          /*!< I2C_DATA is not empty during receiving interrupt flag */
+    I2C_INT_FLAG_TBE = I2C_REGIDX_BIT2(I2C_CTL1_REG_OFFSET, 9U, I2C_STAT0_REG_OFFSET, 7U),           /*!< I2C_DATA is empty during transmitting interrupt flag */
+    I2C_INT_FLAG_BERR = I2C_REGIDX_BIT2(I2C_CTL1_REG_OFFSET, 8U, I2C_STAT0_REG_OFFSET, 8U),          /*!< a bus error occurs indication a unexpected start or stop condition on I2C bus interrupt flag */
+    I2C_INT_FLAG_LOSTARB = I2C_REGIDX_BIT2(I2C_CTL1_REG_OFFSET, 8U, I2C_STAT0_REG_OFFSET, 9U),       /*!< arbitration lost in master mode interrupt flag */
+    I2C_INT_FLAG_AERR = I2C_REGIDX_BIT2(I2C_CTL1_REG_OFFSET, 8U, I2C_STAT0_REG_OFFSET, 10U),         /*!< acknowledge error interrupt flag */
+    I2C_INT_FLAG_OUERR = I2C_REGIDX_BIT2(I2C_CTL1_REG_OFFSET, 8U, I2C_STAT0_REG_OFFSET, 11U),        /*!< over-run or under-run situation occurs in slave mode interrupt flag */
+    I2C_INT_FLAG_PECERR = I2C_REGIDX_BIT2(I2C_CTL1_REG_OFFSET, 8U, I2C_STAT0_REG_OFFSET, 12U),       /*!< PEC error when receiving data interrupt flag */
+    I2C_INT_FLAG_SMBTO = I2C_REGIDX_BIT2(I2C_CTL1_REG_OFFSET, 8U, I2C_STAT0_REG_OFFSET, 14U),        /*!< timeout signal in SMBus mode interrupt flag */
+    I2C_INT_FLAG_SMBALT = I2C_REGIDX_BIT2(I2C_CTL1_REG_OFFSET, 8U, I2C_STAT0_REG_OFFSET, 15U),       /*!< SMBus alert status interrupt flag */
+} i2c_interrupt_flag_enum;
+
+/* I2C interrupt */
+typedef enum {
+    /* interrupt in CTL1 register */
+    I2C_INT_ERR = I2C_REGIDX_BIT(I2C_CTL1_REG_OFFSET, 8U),                     /*!< error interrupt enable */
+    I2C_INT_EV = I2C_REGIDX_BIT(I2C_CTL1_REG_OFFSET, 9U),                      /*!< event interrupt enable */
+    I2C_INT_BUF = I2C_REGIDX_BIT(I2C_CTL1_REG_OFFSET, 10U),                    /*!< buffer interrupt enable */
+} i2c_interrupt_enum;
+
+/* SMBus/I2C mode switch and SMBus type selection */
+#define I2C_I2CMODE_ENABLE            ((uint32_t)0x00000000U)                  /*!< I2C mode */
+#define I2C_SMBUSMODE_ENABLE          I2C_CTL0_SMBEN                           /*!< SMBus mode */
+
+/* SMBus/I2C mode switch and SMBus type selection */
+#define I2C_SMBUS_DEVICE              ((uint32_t)0x00000000U)                  /*!< SMBus mode device type */
+#define I2C_SMBUS_HOST                I2C_CTL0_SMBSEL                          /*!< SMBus mode host type */
+
+/* I2C transfer direction */
+#define I2C_RECEIVER                  ((uint32_t)0x00000001U)                  /*!< receiver */
+#define I2C_TRANSMITTER               ((uint32_t)0xFFFFFFFEU)                  /*!< transmitter */
+
+/* whether or not to send an ACK */
+#define I2C_ACK_DISABLE               ((uint32_t)0x00000000U)                  /*!< ACK will be not sent */
+#define I2C_ACK_ENABLE                I2C_CTL0_ACKEN                           /*!< ACK will be sent */
+
+/* I2C POAP position*/
+#define I2C_ACKPOS_CURRENT            ((uint32_t)0x00000000U)                  /*!< ACKEN bit decides whether or not to send ACK or not for the current byte */
+#define I2C_ACKPOS_NEXT               I2C_CTL0_POAP                            /*!< ACKEN bit decides whether or not to send ACK for the next byte */
+
+/* whether or not to stretch SCL low */
+#define I2C_SCLSTRETCH_ENABLE         ((uint32_t)0x00000000U)                  /*!< SCL stretching is enabled */
+#define I2C_SCLSTRETCH_DISABLE        I2C_CTL0_SS                              /*!< SCL stretching is disabled */
+
+/* whether or not to response to a general call */
+#define I2C_GCEN_ENABLE               I2C_CTL0_GCEN                            /*!< slave will response to a general call */
+#define I2C_GCEN_DISABLE              ((uint32_t)0x00000000U)                  /*!< slave will not response to a general call */
+
+/* software reset I2C */
+#define I2C_SRESET_RESET              ((uint32_t)0x00000000U)                  /*!< I2C is not under reset */
+#define I2C_SRESET_SET                I2C_CTL0_SRESET                          /*!< I2C is under reset */
+
+/* I2C DMA mode configure */
+/* DMA mode switch */
+#define I2C_DMA_OFF                   ((uint32_t)0x00000000U)                  /*!< disable DMA mode */
+#define I2C_DMA_ON                    I2C_CTL1_DMAON                           /*!< enable DMA mode */
+
+/* flag indicating DMA last transfer */
+#define I2C_DMALST_OFF                ((uint32_t)0x00000000U)                  /*!< next DMA EOT is not the last transfer */
+#define I2C_DMALST_ON                 I2C_CTL1_DMALST                          /*!< next DMA EOT is the last transfer */
+
+/* I2C PEC configure */
+/* PEC enable */
+#define I2C_PEC_DISABLE               ((uint32_t)0x00000000U)                  /*!< PEC calculation off */
+#define I2C_PEC_ENABLE                I2C_CTL0_PECEN                           /*!< PEC calculation on */
+
+/* PEC transfer */
+#define I2C_PECTRANS_DISABLE          ((uint32_t)0x00000000U)                  /*!< not transfer PEC value */
+#define I2C_PECTRANS_ENABLE           I2C_CTL0_PECTRANS                        /*!< transfer PEC value */
+
+/* I2C SMBus configure */
+/* issue or not alert through SMBA pin */
+#define I2C_SALTSEND_DISABLE          ((uint32_t)0x00000000U)                  /*!< not issue alert through SMBA */
+#define I2C_SALTSEND_ENABLE           I2C_CTL0_SALT                            /*!< issue alert through SMBA pin */
+
+/* ARP protocol in SMBus switch */
+#define I2C_ARP_DISABLE               ((uint32_t)0x00000000U)                  /*!< disable ARP */
+#define I2C_ARP_ENABLE                I2C_CTL0_ARPEN                           /*!< enable ARP */
+
+/* fast mode plus enable */
+#define I2C_FAST_MODE_PLUS_DISABLE    ((uint32_t)0x00000000U)                  /*!< fast mode plus disable */
+#define I2C_FAST_MODE_PLUS_ENABLE     I2C_FMPCFG_FMPEN                         /*!< fast mode plus enable */
+
+/* transmit I2C data */
+#define DATA_TRANS(regval)            (BITS(0,7) & ((uint32_t)(regval) << 0))
+
+/* receive I2C data */
+#define DATA_RECV(regval)             GET_BITS((uint32_t)(regval), 0, 7)
+
+/* I2C duty cycle in fast mode or fast mode plus */
+#define I2C_DTCY_2                    ((uint32_t)0x00000000U)                  /*!< Tlow/Thigh = 2 in I2C fast mode or fast mode plus */
+#define I2C_DTCY_16_9                 I2C_CKCFG_DTCY                           /*!< Tlow/Thigh = 16/9 in I2C fast mode or fast mode plus */
+
+/* address mode for the I2C slave */
+#define I2C_ADDFORMAT_7BITS           ((uint32_t)0x00000000U)                  /*!< address format is 7 bits */
+#define I2C_ADDFORMAT_10BITS          I2C_SADDR0_ADDFORMAT                     /*!< address format is 10 bits */
+
+/* function declarations */
+/* reset I2C */
+void i2c_deinit(uint32_t i2c_periph);
+/* configure I2C clock */
+void i2c_clock_config(uint32_t i2c_periph, uint32_t clkspeed, uint32_t dutycyc);
+/* configure I2C address */
+void i2c_mode_addr_config(uint32_t i2c_periph, uint32_t mode, uint32_t addformat, uint32_t addr);
+/* select SMBus type */
+void i2c_smbus_type_config(uint32_t i2c_periph, uint32_t type);
+/* whether or not to send an ACK */
+void i2c_ack_config(uint32_t i2c_periph, uint32_t ack);
+/* configure I2C POAP position */
+void i2c_ackpos_config(uint32_t i2c_periph, uint32_t pos);
+/* master sends slave address */
+void i2c_master_addressing(uint32_t i2c_periph, uint32_t addr, uint32_t trandirection);
+/* enable dual-address mode */
+void i2c_dualaddr_enable(uint32_t i2c_periph, uint32_t addr);
+/* disable dual-address mode */
+void i2c_dualaddr_disable(uint32_t i2c_periph);
+/* enable I2C */
+void i2c_enable(uint32_t i2c_periph);
+/* disable I2C */
+void i2c_disable(uint32_t i2c_periph);
+
+/* generate a START condition on I2C bus */
+void i2c_start_on_bus(uint32_t i2c_periph);
+/* generate a STOP condition on I2C bus */
+void i2c_stop_on_bus(uint32_t i2c_periph);
+/* I2C transmit data function */
+void i2c_data_transmit(uint32_t i2c_periph, uint8_t data);
+/* I2C receive data function */
+uint8_t i2c_data_receive(uint32_t i2c_periph);
+/* configure I2C DMA mode */
+void i2c_dma_config(uint32_t i2c_periph, uint32_t dmastate);
+/* configure whether next DMA EOT is DMA last transfer or not */
+void i2c_dma_last_transfer_config(uint32_t i2c_periph, uint32_t dmalast);
+/* whether to stretch SCL low when data is not ready in slave mode */
+void i2c_stretch_scl_low_config(uint32_t i2c_periph, uint32_t stretchpara);
+/* whether or not to response to a general call */
+void i2c_slave_response_to_gcall_config(uint32_t i2c_periph, uint32_t gcallpara);
+/* configure software reset of I2C */
+void i2c_software_reset_config(uint32_t i2c_periph, uint32_t sreset);
+
+/* configure I2C PEC calculation */
+void i2c_pec_config(uint32_t i2c_periph, uint32_t pecstate);
+/* configure whether to transfer PEC value */
+void i2c_pec_transfer_config(uint32_t i2c_periph, uint32_t pecpara);
+/* get packet error checking value */
+uint8_t i2c_pec_value_get(uint32_t i2c_periph);
+/* configure I2C alert through SMBA pin */
+void i2c_smbus_alert_config(uint32_t i2c_periph, uint32_t smbuspara);
+/* configure I2C ARP protocol in SMBus */
+void i2c_smbus_arp_config(uint32_t i2c_periph, uint32_t arpstate);
+
+/* check I2C flag is set or not */
+FlagStatus i2c_flag_get(uint32_t i2c_periph, i2c_flag_enum flag);
+/* clear I2C flag status */
+void i2c_flag_clear(uint32_t i2c_periph, i2c_flag_enum flag);
+/* enable I2C interrupt */
+void i2c_interrupt_enable(uint32_t i2c_periph, i2c_interrupt_enum interrupt);
+/* disable I2C interrupt */
+void i2c_interrupt_disable(uint32_t i2c_periph, i2c_interrupt_enum interrupt);
+/* get I2C interrupt flag status */
+FlagStatus i2c_interrupt_flag_get(uint32_t i2c_periph, i2c_interrupt_flag_enum int_flag);
+/* clear I2C interrupt flag status */
+void i2c_interrupt_flag_clear(uint32_t i2c_periph, i2c_interrupt_flag_enum int_flag);
+
+#endif /* GD32F3X0_I2C_H */

+ 91 - 0
GD32F3x0/GD32F3x0_standard_peripheral/Include/gd32f3x0_misc.h

@@ -0,0 +1,91 @@
+/*!
+    \file    gd32f3x0_misc.h
+    \brief   definitions for the MISC
+
+    \version 2025-01-01, V2.5.0, firmware for GD32F3x0
+*/
+
+/*
+    Copyright (c) 2025, GigaDevice Semiconductor Inc.
+
+    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 of the copyright holder 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 HOLDER 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.
+*/
+
+#ifndef GD32F3X0_MISC_H
+#define GD32F3X0_MISC_H
+
+#include "gd32f3x0.h"
+
+/* constants definitions */
+/* set the RAM and FLASH base address */
+#define NVIC_VECTTAB_RAM            ((uint32_t)0x20000000)                      /*!< RAM base address */
+#define NVIC_VECTTAB_FLASH          ((uint32_t)0x08000000)                      /*!< Flash base address */
+
+/* set the NVIC vector table offset mask */
+#define NVIC_VECTTAB_OFFSET_MASK    ((uint32_t)0x1FFFFF80)                      /*!< NVIC vector table offset mask */
+
+/* the register key mask, if you want to do the write operation, you should write 0x5FA to VECTKEY bits */
+#define NVIC_AIRCR_VECTKEY_MASK     ((uint32_t)0x05FA0000)                      /*!< NVIC VECTKEY mask */
+
+/* priority group - define the pre-emption priority and the subpriority */
+#define NVIC_PRIGROUP_PRE0_SUB4     ((uint32_t)0x00000700)                      /*!< 0 bits for pre-emption priority 4 bits for subpriority */
+#define NVIC_PRIGROUP_PRE1_SUB3     ((uint32_t)0x00000600)                      /*!< 1 bits for pre-emption priority 3 bits for subpriority */
+#define NVIC_PRIGROUP_PRE2_SUB2     ((uint32_t)0x00000500)                      /*!< 2 bits for pre-emption priority 2 bits for subpriority */
+#define NVIC_PRIGROUP_PRE3_SUB1     ((uint32_t)0x00000400)                      /*!< 3 bits for pre-emption priority 1 bits for subpriority */
+#define NVIC_PRIGROUP_PRE4_SUB0     ((uint32_t)0x00000300)                      /*!< 4 bits for pre-emption priority 0 bits for subpriority */
+
+/* choose the method to enter or exit the lowpower mode */
+#define SCB_SCR_SLEEPONEXIT         ((uint8_t)0x02)                             /*!< choose the the system whether enter low power mode by exiting from ISR */
+#define SCB_SCR_SLEEPDEEP           ((uint8_t)0x04)                             /*!< choose the the system enter the DEEPSLEEP mode or SLEEP mode */
+#define SCB_SCR_SEVONPEND           ((uint8_t)0x10)                             /*!< choose the interrupt source that can wake up the lowpower mode */
+
+#define SCB_LPM_SLEEP_EXIT_ISR      SCB_SCR_SLEEPONEXIT                         /*!< low power mode by exiting from ISR */
+#define SCB_LPM_DEEPSLEEP           SCB_SCR_SLEEPDEEP                           /*!< DEEPSLEEP mode or SLEEP mode */
+#define SCB_LPM_WAKE_BY_ALL_INT     SCB_SCR_SEVONPEND                           /*!< wakeup by all interrupt */
+
+/* choose the systick clock source */
+#define SYSTICK_CLKSOURCE_HCLK_DIV8 ((uint32_t)0xFFFFFFFBU)                     /*!< systick clock source is from HCLK/8 */
+#define SYSTICK_CLKSOURCE_HCLK      ((uint32_t)0x00000004U)                     /*!< systick clock source is from HCLK */
+
+/* function declarations */
+/* set the priority group */
+void nvic_priority_group_set(uint32_t nvic_prigroup);
+
+/* enable NVIC request */
+void nvic_irq_enable(IRQn_Type nvic_irq, uint8_t nvic_irq_pre_priority, uint8_t nvic_irq_sub_priority);
+/* disable NVIC request */
+void nvic_irq_disable(IRQn_Type nvic_irq);
+
+/* set the NVIC vector table base address */
+void nvic_vector_table_set(uint32_t nvic_vict_tab, uint32_t offset);
+
+/* set the state of the low power mode */
+void system_lowpower_set(uint8_t lowpower_mode);
+/* reset the state of the low power mode */
+void system_lowpower_reset(uint8_t lowpower_mode);
+
+/* set the systick clock source */
+void systick_clksource_set(uint32_t systick_clksource);
+
+#endif /* GD32F3X0_MISC_H */

+ 196 - 0
GD32F3x0/GD32F3x0_standard_peripheral/Include/gd32f3x0_pmu.h

@@ -0,0 +1,196 @@
+/*!
+    \file    gd32f3x0_pmu.h
+    \brief   definitions for the PMU
+
+    \version 2025-01-01, V2.5.0, firmware for GD32F3x0
+*/
+
+/*
+    Copyright (c) 2025, GigaDevice Semiconductor Inc.
+
+    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 of the copyright holder 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 HOLDER 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.
+*/
+
+#ifndef GD32F3X0_PMU_H
+#define GD32F3X0_PMU_H
+
+#include "gd32f3x0.h"
+
+/* PMU definitions */
+#define PMU                           PMU_BASE                 /*!< PMU base address */
+
+/* registers definitions */
+#define PMU_CTL                       REG32(PMU + 0x00000000U) /*!< PMU control register */
+#define PMU_CS                        REG32(PMU + 0x00000004U) /*!< PMU control and status register */
+
+/* bits definitions */
+/* PMU_CTL */
+#define PMU_CTL_LDOLP                 BIT(0)                   /*!< LDO low power mode */
+#define PMU_CTL_STBMOD                BIT(1)                   /*!< standby mode */
+#define PMU_CTL_WURST                 BIT(2)                   /*!< wakeup flag reset */
+#define PMU_CTL_STBRST                BIT(3)                   /*!< standby flag reset */
+#define PMU_CTL_LVDEN                 BIT(4)                   /*!< low voltage detector enable */
+#define PMU_CTL_LVDT                  BITS(5,7)                /*!< low voltage detector threshold */
+#define PMU_CTL_BKPWEN                BIT(8)                   /*!< backup domain write enable */
+#define PMU_CTL_LDLP                  BIT(10)                  /*!< low-driver mode when use low power LDO */
+#define PMU_CTL_LDNP                  BIT(11)                  /*!< low-driver mode when use normal power LDO */
+#define PMU_CTL_LDOVS                 BITS(14,15)              /*!< LDO output voltage select */
+#define PMU_CTL_HDEN                  BIT(16)                  /*!< high-driver mode enable */
+#define PMU_CTL_HDS                   BIT(17)                  /*!< high-driver mode switch */
+#define PMU_CTL_LDEN                  BITS(18,19)              /*!< low-driver mode enable in deep-sleep mode */
+
+/* PMU_CS */
+#define PMU_CS_WUF                    BIT(0)                   /*!< wakeup flag */
+#define PMU_CS_STBF                   BIT(1)                   /*!< standby flag */
+#define PMU_CS_LVDF                   BIT(2)                   /*!< low voltage detector status flag */
+#define PMU_CS_WUPEN0                 BIT(8)                   /*!< wakeup pin enable */
+#define PMU_CS_WUPEN1                 BIT(9)                   /*!< wakeup pin enable */
+#define PMU_CS_WUPEN4                 BIT(12)                  /*!< wakeup pin enable */
+#define PMU_CS_WUPEN5                 BIT(13)                  /*!< wakeup pin enable */
+#define PMU_CS_WUPEN6                 BIT(14)                  /*!< wakeup pin enable */
+#define PMU_CS_LDOVSRF                BIT(15)                  /*!< LDO voltage select ready flag */
+#define PMU_CS_HDRF                   BIT(16)                  /*!< high-driver ready flag */
+#define PMU_CS_HDSRF                  BIT(17)                  /*!< high-driver switch ready flag */
+#define PMU_CS_LDRF                   BITS(18,19)              /*!< low-driver mode ready flag */
+
+/* constants definitions */
+/* PMU low voltage detector threshold definitions */
+#define CTL_LVDT(regval)              (BITS(5,7)&((uint32_t)(regval)<<5))
+#define PMU_LVDT_0                    CTL_LVDT(0)              /*!< voltage threshold is 2.1V */
+#define PMU_LVDT_1                    CTL_LVDT(1)              /*!< voltage threshold is 2.3V */
+#define PMU_LVDT_2                    CTL_LVDT(2)              /*!< voltage threshold is 2.4V */
+#define PMU_LVDT_3                    CTL_LVDT(3)              /*!< voltage threshold is 2.6V */
+#define PMU_LVDT_4                    CTL_LVDT(4)              /*!< voltage threshold is 2.7V */
+#define PMU_LVDT_5                    CTL_LVDT(5)              /*!< voltage threshold is 2.9V */
+#define PMU_LVDT_6                    CTL_LVDT(6)              /*!< voltage threshold is 3.0V */
+#define PMU_LVDT_7                    CTL_LVDT(7)              /*!< voltage threshold is 3.1V */
+
+/* PMU LDO output voltage select definitions */
+#define CTL_LDOVS(regval)             (BITS(14,15)&((uint32_t)(regval)<<14))
+#define PMU_LDOVS_LOW                 CTL_LDOVS(1)             /*!< LDO output voltage low mode */
+#define PMU_LDOVS_MID                 CTL_LDOVS(2)             /*!< LDO output voltage mid mode */
+#define PMU_LDOVS_HIGH                CTL_LDOVS(3)             /*!< LDO output voltage high mode */
+
+/* PMU low-driver mode enable in deep-sleep mode */
+#define CTL_LDEN(regval)              (BITS(18,19)&((uint32_t)(regval)<<18))
+#define PMU_LOWDRIVER_DISABLE         CTL_LDEN(0)              /*!< low-driver mode disable in deep-sleep mode */
+#define PMU_LOWDRIVER_ENABLE          CTL_LDEN(3)              /*!< low-driver mode enable in deep-sleep mode */
+
+/* PMU low power mode ready flag definitions */
+#define CS_LDRF(regval)               (BITS(18,19)&((uint32_t)(regval)<<18))
+#define PMU_LDRF_NORMAL               CS_LDRF(0)               /*!< normal-driver in deep-sleep mode */
+#define PMU_LDRF_LOWDRIVER            CS_LDRF(3)               /*!< low-driver mode in deep-sleep mode */
+
+/* PMU high-driver mode switch */
+#define PMU_HIGHDR_SWITCH_NONE        ((uint32_t)0x00000000U)  /*!< no high-driver mode switch */
+#define PMU_HIGHDR_SWITCH_EN          PMU_CTL_HDS              /*!< high-driver mode switch */
+
+/* PMU low-driver mode when use normal power LDO */
+#define PMU_NORMALDR_NORMALPWR        ((uint32_t)0x00000000U)  /*!< normal-driver when use normal power LDO */
+#define PMU_LOWDR_NORMALPWR           PMU_CTL_LDNP             /*!< low-driver mode enabled when LDEN is 11 and use normal power LDO */
+
+/* PMU low-driver mode when use low power LDO */
+#define PMU_NORMALDR_LOWPWR           ((uint32_t)0x00000000U)  /*!< normal-driver when use low power LDO */
+#define PMU_LOWDR_LOWPWR              PMU_CTL_LDLP             /*!< low-driver mode enabled when LDEN is 11 and use low power LDO */
+
+/* PMU ldo definitions */
+#define PMU_LDO_NORMAL                ((uint32_t)0x00000000U)  /*!< LDO operates normally when PMU enter deepsleep mode */
+#define PMU_LDO_LOWPOWER              PMU_CTL_LDOLP            /*!< LDO work at low power status when PMU enter deepsleep mode */
+
+/* PMU flag definitions */
+#define PMU_FLAG_WAKEUP               PMU_CS_WUF               /*!< wakeup flag status */
+#define PMU_FLAG_STANDBY              PMU_CS_STBF              /*!< standby flag status */
+#define PMU_FLAG_LVD                  PMU_CS_LVDF              /*!< LVD flag status */
+#define PMU_FLAG_LDOVSR               PMU_CS_LDOVSRF           /*!< LDO voltage select ready flag */
+#define PMU_FLAG_HDR                  PMU_CS_HDRF              /*!< high-driver ready flag */
+#define PMU_FLAG_HDSR                 PMU_CS_HDSRF             /*!< high-driver switch ready flag */
+#define PMU_FLAG_LDR                  PMU_CS_LDRF              /*!< low-driver mode ready flag */
+
+/* PMU WKUP pin definitions */
+#define PMU_WAKEUP_PIN0               PMU_CS_WUPEN0            /*!< WKUP Pin 0 (PA0) enable */
+#define PMU_WAKEUP_PIN1               PMU_CS_WUPEN1            /*!< WKUP Pin 1 (PC13) enable */
+#define PMU_WAKEUP_PIN4               PMU_CS_WUPEN4            /*!< WKUP Pin 4 (PC5) enable */
+#define PMU_WAKEUP_PIN5               PMU_CS_WUPEN5            /*!< WKUP Pin 5 (PB5) enable */
+#define PMU_WAKEUP_PIN6               PMU_CS_WUPEN6            /*!< WKUP Pin 6 (PB15) enable */
+
+/* PMU flag reset definitions */
+#define PMU_FLAG_RESET_WAKEUP         PMU_CTL_WURST            /*!< wakeup flag reset */
+#define PMU_FLAG_RESET_STANDBY        PMU_CTL_STBRST           /*!< standby flag reset */
+
+/* PMU command constants definitions */
+#define WFI_CMD                       ((uint8_t)0x00U)         /*!< use WFI command */
+#define WFE_CMD                       ((uint8_t)0x01U)         /*!< use WFE command */
+
+/* function declarations */
+/* function configuration */
+/* reset PMU registers */
+void pmu_deinit(void);
+/* select low voltage detector threshold */
+void pmu_lvd_select(uint32_t lvdt_n);
+/* select LDO output voltage */
+void pmu_ldo_output_select(uint32_t ldo_output);
+/* disable PMU lvd */
+void pmu_lvd_disable(void);
+
+/* functions of low-driver mode and high-driver mode in deep-sleep mode */
+/* enable low-driver mode in deep-sleep mode */
+void pmu_lowdriver_mode_enable(void);
+/* disable low-driver mode in deep-sleep mode */
+void pmu_lowdriver_mode_disable(void);
+/* enable high-driver mode */
+void pmu_highdriver_mode_enable(void);
+/* disable high-driver mode */
+void pmu_highdriver_mode_disable(void);
+/* switch high-driver mode */
+void pmu_highdriver_switch_select(uint32_t highdr_switch);
+/* in deep-sleep mode, low-driver mode when use low power LDO */
+void pmu_lowpower_driver_config(uint32_t mode);
+/* in deep-sleep mode, low-driver mode when use normal power LDO */
+void pmu_normalpower_driver_config(uint32_t mode);
+
+/* set PMU mode */
+/* PMU work in sleep mode */
+void pmu_to_sleepmode(uint8_t sleepmodecmd);
+/* PMU work in deepsleep mode */
+void pmu_to_deepsleepmode(uint32_t ldo, uint32_t lowdrive, uint8_t deepsleepmodecmd);
+/* PMU work in standby mode */
+void pmu_to_standbymode(void);
+/* enable PMU wakeup pin */
+void pmu_wakeup_pin_enable(uint32_t wakeup_pin);
+/* disable PMU wakeup pin */
+void pmu_wakeup_pin_disable(uint32_t wakeup_pin);
+
+/* backup related functions */
+/* enable backup domain write */
+void pmu_backup_write_enable(void);
+/* disable backup domain write */
+void pmu_backup_write_disable(void);
+
+/* flag functions */
+/* get flag state */
+FlagStatus pmu_flag_get(uint32_t flag);
+/* clear flag bit */
+void pmu_flag_clear(uint32_t flag);
+
+#endif /* GD32F3X0_PMU_H */

+ 799 - 0
GD32F3x0/GD32F3x0_standard_peripheral/Include/gd32f3x0_rcu.h

@@ -0,0 +1,799 @@
+/*!
+    \file    gd32f3x0_rcu.h
+    \brief   definitions for the RCU
+
+    \version 2025-01-01, V2.5.0, firmware for GD32F3x0
+*/
+
+/*
+    Copyright (c) 2025, GigaDevice Semiconductor Inc.
+
+    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 of the copyright holder 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 HOLDER 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.
+*/
+
+#ifndef GD32F3X0_RCU_H
+#define GD32F3X0_RCU_H
+
+#include "gd32f3x0.h"
+
+/* RCU definitions */
+#define RCU                         RCU_BASE
+
+/* registers definitions */
+#define RCU_CTL0                    REG32(RCU + 0x00000000U)        /*!< control register 0 */
+#define RCU_CFG0                    REG32(RCU + 0x00000004U)        /*!< configuration register 0 */
+#define RCU_INT                     REG32(RCU + 0x00000008U)        /*!< interrupt register */
+#define RCU_APB2RST                 REG32(RCU + 0x0000000CU)        /*!< APB2 reset register */
+#define RCU_APB1RST                 REG32(RCU + 0x00000010U)        /*!< APB1 reset register */
+#define RCU_AHBEN                   REG32(RCU + 0x00000014U)        /*!< AHB enable register */
+#define RCU_APB2EN                  REG32(RCU + 0x00000018U)        /*!< APB2 enable register */
+#define RCU_APB1EN                  REG32(RCU + 0x0000001CU)        /*!< APB1 enable register  */
+#define RCU_BDCTL                   REG32(RCU + 0x00000020U)        /*!< backup domain control register */
+#define RCU_RSTSCK                  REG32(RCU + 0x00000024U)        /*!< reset source /clock register */
+#define RCU_AHBRST                  REG32(RCU + 0x00000028U)        /*!< AHB reset register */
+#define RCU_CFG1                    REG32(RCU + 0x0000002CU)        /*!< configuration register 1 */
+#define RCU_CFG2                    REG32(RCU + 0x00000030U)        /*!< configuration register 2 */
+#define RCU_CTL1                    REG32(RCU + 0x00000034U)        /*!< control register 1 */
+#define RCU_ADDCTL                  REG32(RCU + 0x000000C0U)        /*!< additional clock control register */
+#define RCU_ADDINT                  REG32(RCU + 0x000000CCU)        /*!< additional clock interrupt register */
+#define RCU_ADDAPB1EN               REG32(RCU + 0x000000F8U)        /*!< APB1 additional enable register */
+#define RCU_ADDAPB1RST              REG32(RCU + 0x000000FCU)        /*!< APB1 additional reset register */
+#define RCU_VKEY                    REG32(RCU + 0x00000100U)        /*!< voltage key register */
+#define RCU_DSV                     REG32(RCU + 0x00000134U)        /*!< deep-sleep mode voltage register */
+
+/* bits definitions */
+/* RCU_CTL0 */
+#define RCU_CTL0_IRC8MEN            BIT(0)                    /*!< internal high speed oscillator enable */
+#define RCU_CTL0_IRC8MSTB           BIT(1)                    /*!< IRC8M high speed internal oscillator stabilization flag */
+#define RCU_CTL0_IRC8MADJ           BITS(3,7)                 /*!< high speed internal oscillator clock trim adjust value */
+#define RCU_CTL0_IRC8MCALIB         BITS(8,15)                /*!< high speed internal oscillator calibration value register */
+#define RCU_CTL0_HXTALEN            BIT(16)                   /*!< external high speed oscillator enable */
+#define RCU_CTL0_HXTALSTB           BIT(17)                   /*!< external crystal oscillator clock stabilization flag */
+#define RCU_CTL0_HXTALBPS           BIT(18)                   /*!< external crystal oscillator clock bypass mode enable */
+#define RCU_CTL0_CKMEN              BIT(19)                   /*!< HXTAL clock monitor enable */
+#define RCU_CTL0_PLLEN              BIT(24)                   /*!< PLL enable */
+#define RCU_CTL0_PLLSTB             BIT(25)                   /*!< PLL clock stabilization flag */
+
+/* RCU_CFG0 */
+#define RCU_CFG0_SCS                BITS(0,1)                 /*!< system clock switch */
+#define RCU_CFG0_SCSS               BITS(2,3)                 /*!< system clock switch status */
+#define RCU_CFG0_AHBPSC             BITS(4,7)                 /*!< AHB prescaler selection */
+#define RCU_CFG0_APB1PSC            BITS(8,10)                /*!< APB1 prescaler selection */
+#define RCU_CFG0_APB2PSC            BITS(11,13)               /*!< APB2 prescaler selection */
+#define RCU_CFG0_ADCPSC             BITS(14,15)               /*!< ADC clock prescaler selection */
+#define RCU_CFG0_PLLSEL             BIT(16)                   /*!< PLL clock source selection */
+#define RCU_CFG0_PLLPREDV           BIT(17)                   /*!< divider for PLL source clock selection */
+#define RCU_CFG0_PLLMF              (BIT(27) | BITS(18,21))   /*!< PLL multiply factor */
+#define RCU_CFG0_USBFSPSC           BITS(22,23)               /*!< USBFS clock prescaler selection */
+#define RCU_CFG0_CKOUTSEL           BITS(24,26)               /*!< CK_OUT clock source selection */
+#define RCU_CFG0_PLLMF4             BIT(27)                   /*!< bit 4 of PLLMF */
+#define RCU_CFG0_CKOUTDIV           BITS(28,30)               /*!< CK_OUT divider which the CK_OUT frequency can be reduced */
+#define RCU_CFG0_PLLDV              BIT(31)                   /*!< CK_PLL divide by 1 or 2 */
+
+/* RCU_INT */
+#define RCU_INT_IRC40KSTBIF         BIT(0)                    /*!< IRC40K stabilization interrupt flag */
+#define RCU_INT_LXTALSTBIF          BIT(1)                    /*!< LXTAL stabilization interrupt flag */
+#define RCU_INT_IRC8MSTBIF          BIT(2)                    /*!< IRC8M stabilization interrupt flag */
+#define RCU_INT_HXTALSTBIF          BIT(3)                    /*!< HXTAL stabilization interrupt flag */
+#define RCU_INT_PLLSTBIF            BIT(4)                    /*!< PLL stabilization interrupt flag */
+#define RCU_INT_IRC28MSTBIF         BIT(5)                    /*!< IRC28M stabilization interrupt flag */
+#define RCU_INT_CKMIF               BIT(7)                    /*!< HXTAL clock stuck interrupt flag */
+#define RCU_INT_IRC40KSTBIE         BIT(8)                    /*!< IRC40K stabilization interrupt enable */
+#define RCU_INT_LXTALSTBIE          BIT(9)                    /*!< LXTAL stabilization interrupt enable */
+#define RCU_INT_IRC8MSTBIE          BIT(10)                   /*!< IRC8M stabilization interrupt enable */
+#define RCU_INT_HXTALSTBIE          BIT(11)                   /*!< HXTAL stabilization interrupt enable */
+#define RCU_INT_PLLSTBIE            BIT(12)                   /*!< PLL stabilization interrupt enable */
+#define RCU_INT_IRC28MSTBIE         BIT(13)                   /*!< IRC28M stabilization interrupt enable */
+#define RCU_INT_IRC40KSTBIC         BIT(16)                   /*!< IRC40K stabilization interrupt clear */
+#define RCU_INT_LXTALSTBIC          BIT(17)                   /*!< LXTAL stabilization interrupt clear */
+#define RCU_INT_IRC8MSTBIC          BIT(18)                   /*!< IRC8M stabilization interrupt clear */
+#define RCU_INT_HXTALSTBIC          BIT(19)                   /*!< HXTAL stabilization interrupt clear */
+#define RCU_INT_PLLSTBIC            BIT(20)                   /*!< PLL stabilization interrupt clear */
+#define RCU_INT_IRC28MSTBIC         BIT(21)                   /*!< IRC28M stabilization interrupt clear */
+#define RCU_INT_CKMIC               BIT(23)                   /*!< HXTAL clock stuck interrupt clear */
+
+/* RCU_APB2RST */
+#define RCU_APB2RST_CFGRST          BIT(0)                    /*!< system configuration reset */
+#define RCU_APB2RST_ADCRST          BIT(9)                    /*!< ADC reset */
+#define RCU_APB2RST_TIMER0RST       BIT(11)                   /*!< TIMER0 reset */
+#define RCU_APB2RST_SPI0RST         BIT(12)                   /*!< SPI0 reset */
+#define RCU_APB2RST_USART0RST       BIT(14)                   /*!< USART0 reset */
+#define RCU_APB2RST_TIMER14RST      BIT(16)                   /*!< TIMER14 reset */
+#define RCU_APB2RST_TIMER15RST      BIT(17)                   /*!< TIMER15 reset */
+#define RCU_APB2RST_TIMER16RST      BIT(18)                   /*!< TIMER16 reset */
+
+/* RCU_APB1RST */
+#define RCU_APB1RST_TIMER1RST       BIT(0)                    /*!< TIMER1 timer reset */
+#define RCU_APB1RST_TIMER2RST       BIT(1)                    /*!< TIMER2 timer reset */
+#define RCU_APB1RST_TIMER5RST       BIT(4)                    /*!< TIMER5 timer reset */
+#define RCU_APB1RST_TIMER13RST      BIT(8)                    /*!< TIMER13 timer reset */
+#define RCU_APB1RST_WWDGTRST        BIT(11)                   /*!< window watchdog timer reset */
+#define RCU_APB1RST_SPI1RST         BIT(14)                   /*!< SPI1 reset */
+#define RCU_APB1RST_USART1RST       BIT(17)                   /*!< USART1 reset */
+#define RCU_APB1RST_I2C0RST         BIT(21)                   /*!< I2C0 reset */
+#define RCU_APB1RST_I2C1RST         BIT(22)                   /*!< I2C1 reset */
+#define RCU_APB1RST_PMURST          BIT(28)                   /*!< power control reset */
+#define RCU_APB1RST_DACRST          BIT(29)                   /*!< DAC reset */
+#define RCU_APB1RST_CECRST          BIT(30)                   /*!< HDMI CEC reset */
+
+/* RCU_AHBEN */
+#define RCU_AHBEN_DMAEN             BIT(0)                    /*!< DMA clock enable */
+#define RCU_AHBEN_SRAMSPEN          BIT(2)                    /*!< SRAM interface clock enable */
+#define RCU_AHBEN_FMCSPEN           BIT(4)                    /*!< FMC clock enable */
+#define RCU_AHBEN_CRCEN             BIT(6)                    /*!< CRC clock enable */
+#define RCU_AHBEN_USBFS             BIT(12)                   /*!< USBFS clock enable */
+#define RCU_AHBEN_PAEN              BIT(17)                   /*!< GPIO port A clock enable */
+#define RCU_AHBEN_PBEN              BIT(18)                   /*!< GPIO port B clock enable */
+#define RCU_AHBEN_PCEN              BIT(19)                   /*!< GPIO port C clock enable */
+#define RCU_AHBEN_PDEN              BIT(20)                   /*!< GPIO port D clock enable */
+#define RCU_AHBEN_PFEN              BIT(22)                   /*!< GPIO port F clock enable */
+#define RCU_AHBEN_TSIEN             BIT(24)                   /*!< TSI clock enable */
+
+/* RCU_APB2EN */
+#define RCU_APB2EN_CFGCMPEN         BIT(0)                    /*!< system configuration and comparator clock enable */
+#define RCU_APB2EN_ADCEN            BIT(9)                    /*!< ADC interface clock enable */
+#define RCU_APB2EN_TIMER0EN         BIT(11)                   /*!< TIMER0 timer clock enable */
+#define RCU_APB2EN_SPI0EN           BIT(12)                   /*!< SPI0 clock enable */
+#define RCU_APB2EN_USART0EN         BIT(14)                   /*!< USART0 clock enable */
+#define RCU_APB2EN_TIMER14EN        BIT(16)                   /*!< TIMER14 timer clock enable */
+#define RCU_APB2EN_TIMER15EN        BIT(17)                   /*!< TIMER15 timer clock enable */
+#define RCU_APB2EN_TIMER16EN        BIT(18)                   /*!< TIMER16 timer clock enable */
+
+/* RCU_APB1EN */
+#define RCU_APB1EN_TIMER1EN         BIT(0)                    /*!< TIMER1 timer clock enable */
+#define RCU_APB1EN_TIMER2EN         BIT(1)                    /*!< TIMER2 timer clock enable */
+#define RCU_APB1EN_TIMER5EN         BIT(4)                    /*!< TIMER5 timer clock enable */
+#define RCU_APB1EN_TIMER13EN        BIT(8)                    /*!< TIMER13 timer clock enable */
+#define RCU_APB1EN_WWDGTEN          BIT(11)                   /*!< window watchdog timer clock enable */
+#define RCU_APB1EN_SPI1EN           BIT(14)                   /*!< SPI1 clock enable */
+#define RCU_APB1EN_USART1EN         BIT(17)                   /*!< USART1 clock enable */
+#define RCU_APB1EN_I2C0EN           BIT(21)                   /*!< I2C0 clock enable */
+#define RCU_APB1EN_I2C1EN           BIT(22)                   /*!< I2C1 clock enable */
+#define RCU_APB1EN_PMUEN            BIT(28)                   /*!< power interface clock enable */
+#define RCU_APB1EN_DACEN            BIT(29)                   /*!< DAC interface clock enable */
+#define RCU_APB1EN_CECEN            BIT(30)                   /*!< HDMI CEC interface clock enable */
+
+/* RCU_BDCTL */
+#define RCU_BDCTL_LXTALEN           BIT(0)                    /*!< LXTAL enable */
+#define RCU_BDCTL_LXTALSTB          BIT(1)                    /*!< external low-speed oscillator stabilization */
+#define RCU_BDCTL_LXTALBPS          BIT(2)                    /*!< LXTAL bypass mode enable */
+#define RCU_BDCTL_LXTALDRI          BITS(3,4)                 /*!< LXTAL drive capability */
+#define RCU_BDCTL_RTCSRC            BITS(8,9)                 /*!< RTC clock entry selection */
+#define RCU_BDCTL_RTCEN             BIT(15)                   /*!< RTC clock enable */
+#define RCU_BDCTL_BKPRST            BIT(16)                   /*!< backup domain reset */
+
+/* RCU_RSTSCK */
+#define RCU_RSTSCK_IRC40KEN         BIT(0)                    /*!< IRC40K enable */
+#define RCU_RSTSCK_IRC40KSTB        BIT(1)                    /*!< IRC40K stabilization */
+#define RCU_RSTSCK_V12RSTF          BIT(23)                   /*!< V12 domain power reset flag */
+#define RCU_RSTSCK_RSTFC            BIT(24)                   /*!< reset flag clear */
+#define RCU_RSTSCK_OBLRSTF          BIT(25)                   /*!< option byte loader reset flag */
+#define RCU_RSTSCK_EPRSTF           BIT(26)                   /*!< external pin reset flag */
+#define RCU_RSTSCK_PORRSTF          BIT(27)                   /*!< power reset flag */
+#define RCU_RSTSCK_SWRSTF           BIT(28)                   /*!< software reset flag */
+#define RCU_RSTSCK_FWDGTRSTF        BIT(29)                   /*!< free watchdog timer reset flag */
+#define RCU_RSTSCK_WWDGTRSTF        BIT(30)                   /*!< window watchdog timer reset flag */
+#define RCU_RSTSCK_LPRSTF           BIT(31)                   /*!< low-power reset flag */
+
+/* RCU_AHBRST */
+#define RCU_AHBRST_USBFSRST         BIT(12)                   /*!< USBFS reset */
+#define RCU_AHBRST_PARST            BIT(17)                   /*!< GPIO port A reset */
+#define RCU_AHBRST_PBRST            BIT(18)                   /*!< GPIO port B reset */
+#define RCU_AHBRST_PCRST            BIT(19)                   /*!< GPIO port C reset */
+#define RCU_AHBRST_PDRST            BIT(20)                   /*!< GPIO port D reset */
+#define RCU_AHBRST_PFRST            BIT(22)                   /*!< GPIO port F reset */
+#define RCU_AHBRST_TSIRST           BIT(24)                   /*!< TSI unit reset */
+
+/* RCU_CFG1 */
+#define RCU_CFG1_PREDV              BITS(0,3)                 /*!< CK_HXTAL divider previous PLL */
+#define RCU_CFG1_PLLPRESEL          BIT(30)                   /*!< PLL clock source preselection */
+#define RCU_CFG1_PLLMF5             BIT(31)                   /*!< bit 5 of PLLMF */
+
+/* RCU_CFG2 */
+#define RCU_CFG2_USART0SEL          BITS(0,1)                 /*!< CK_USART0 clock source selection */
+#define RCU_CFG2_CECSEL             BIT(6)                    /*!< CK_CEC clock source selection */
+#define RCU_CFG2_ADCSEL             BIT(8)                    /*!< CK_ADC clock source selection */
+#define RCU_CFG2_IRC28MDIV          BIT(16)                   /*!< CK_IRC28M divider 2 or not */
+#define RCU_CFG2_USBFSPSC2          BIT(30)                   /*!< bit 2 of USBFSPSC */
+#define RCU_CFG2_ADCPSC2            BIT(31)                   /*!< bit 2 of ADCPSC */
+
+/* RCU_CTL1 */
+#define RCU_CTL1_IRC28MEN           BIT(0)                    /*!< IRC28M internal 28M RC oscillator enable */
+#define RCU_CTL1_IRC28MSTB          BIT(1)                    /*!< IRC28M internal 28M RC oscillator stabilization flag */
+#define RCU_CTL1_IRC28MADJ          BITS(3,7)                 /*!< internal 28M RC oscillator clock trim adjust value */
+#define RCU_CTL1_IRC28MCALIB        BITS(8,15)                /*!< internal 28M RC oscillator calibration value register */
+
+/* RCU_ADDCTL */
+#define RCU_ADDCTL_CK48MSEL         BIT(0)                    /*!< 48M clock selection */
+#define RCU_ADDCTL_IRC48MEN         BIT(16)                   /*!< IRC48M internal 48M RC oscillator enable */
+#define RCU_ADDCTL_IRC48MSTB        BIT(17)                   /*!< internal 48M RC oscillator stabilization flag */
+#define RCU_ADDCTL_IRC48MCALIB      BITS(24,31)               /*!< internal 48M RC oscillator calibration value register */
+
+/* RCU_ADDINT */
+#define RCU_ADDINT_IRC48MSTBIF      BIT(6)                    /*!< IRC48M stabilization interrupt flag */
+#define RCU_ADDINT_IRC48MSTBIE      BIT(14)                   /*!< IRC48M stabilization interrupt enable */
+#define RCU_ADDINT_IRC48MSTBIC      BIT(22)                   /*!< IRC48M stabilization interrupt clear */
+
+/* RCU_ADDAPB1EN */
+#define RCU_ADDAPB1EN_CTCEN         BIT(27)                   /*!< CTC unit clock enable */
+
+/* RCU_ADDAPB1RST */
+#define RCU_ADDAPB1RST_CTCRST       BIT(27)                   /*!< CTC unit reset */
+
+/* RCU_VKEY */
+#define RCU_VKEY_KEY                BITS(0,31)                /*!< key of RCU_DSV register */
+
+/* RCU_DSV */
+#define RCU_DSV_DSLPVS              BITS(0,1)                 /*!< deep-sleep mode voltage select */
+
+/* constants definitions */
+/* define the peripheral clock enable bit position and its register index offset */
+#define RCU_REGIDX_BIT(regidx, bitpos)      (((uint32_t)(regidx)<<6) | (uint32_t)(bitpos))
+#define RCU_REG_VAL(periph)                 (REG32(RCU + ((uint32_t)(periph)>>6)))
+#define RCU_BIT_POS(val)                    ((uint32_t)(val) & (uint32_t)0x0000001FU)
+/* define the voltage key unlock value */
+#define RCU_VKEY_UNLOCK                     ((uint32_t)0x1A2B3C4DU)
+
+/* register index */
+typedef enum {
+    /* peripherals enable */
+    IDX_AHBEN      = ((uint32_t)0x00000014U),
+    IDX_APB2EN     = ((uint32_t)0x00000018U),
+    IDX_APB1EN     = ((uint32_t)0x0000001CU),
+    IDX_ADDAPB1EN  = ((uint32_t)0x000000F8U),
+    /* peripherals reset */
+    IDX_AHBRST     = ((uint32_t)0x00000028U),
+    IDX_APB2RST    = ((uint32_t)0x0000000CU),
+    IDX_APB1RST    = ((uint32_t)0x00000010U),
+    IDX_ADDAPB1RST = ((uint32_t)0x000000FCU),
+    /* clock stabilization */
+    IDX_CTL0       = ((uint32_t)0x00000000U),
+    IDX_BDCTL      = ((uint32_t)0x00000020U),
+    IDX_CTL1       = ((uint32_t)0x00000034U),
+    IDX_ADDCTL     = ((uint32_t)0x000000C0U),
+    /* peripheral reset */
+    IDX_RSTSCK     = ((uint32_t)0x00000024U),
+    /* clock stabilization and stuck interrupt */
+    IDX_INT        = ((uint32_t)0x00000008U),
+    IDX_ADDINT     = ((uint32_t)0x000000CCU),
+    /* configuration register */
+    IDX_CFG0       = ((uint32_t)0x00000004U),
+    IDX_CFG2       = ((uint32_t)0x00000030U)
+} reg_idx;
+
+/* peripheral clock enable */
+typedef enum {
+    /* AHB peripherals */
+    RCU_DMA     = RCU_REGIDX_BIT(IDX_AHBEN, 0U),                  /*!< DMA clock */
+    RCU_CRC     = RCU_REGIDX_BIT(IDX_AHBEN, 6U),                  /*!< CRC clock */
+    RCU_GPIOA   = RCU_REGIDX_BIT(IDX_AHBEN, 17U),                 /*!< GPIOA clock */
+    RCU_GPIOB   = RCU_REGIDX_BIT(IDX_AHBEN, 18U),                 /*!< GPIOB clock */
+    RCU_GPIOC   = RCU_REGIDX_BIT(IDX_AHBEN, 19U),                 /*!< GPIOC clock */
+    RCU_GPIOD   = RCU_REGIDX_BIT(IDX_AHBEN, 20U),                 /*!< GPIOD clock */
+    RCU_GPIOF   = RCU_REGIDX_BIT(IDX_AHBEN, 22U),                 /*!< GPIOF clock */
+#if (defined(GD32F350) || defined(GD32F355) || defined(GD32F370))
+    RCU_TSI     = RCU_REGIDX_BIT(IDX_AHBEN, 24U),                 /*!< TSI clock */
+#endif /* GD32F350, GD32F355 and GD32F370 */
+
+    /* APB2 peripherals */
+    RCU_CFGCMP  = RCU_REGIDX_BIT(IDX_APB2EN, 0U),                 /*!< CFGCMP clock */
+    RCU_ADC     = RCU_REGIDX_BIT(IDX_APB2EN, 9U),                 /*!< ADC clock */
+    RCU_TIMER0  = RCU_REGIDX_BIT(IDX_APB2EN, 11U),                /*!< TIMER0 clock */
+    RCU_SPI0    = RCU_REGIDX_BIT(IDX_APB2EN, 12U),                /*!< SPI0 clock */
+    RCU_USART0  = RCU_REGIDX_BIT(IDX_APB2EN, 14U),                /*!< USART0 clock */
+    RCU_TIMER14 = RCU_REGIDX_BIT(IDX_APB2EN, 16U),                /*!< TIMER14 clock */
+    RCU_TIMER15 = RCU_REGIDX_BIT(IDX_APB2EN, 17U),                /*!< TIMER15 clock */
+    RCU_TIMER16 = RCU_REGIDX_BIT(IDX_APB2EN, 18U),                /*!< TIMER16 clock */
+
+    /* APB1 peripherals */
+#if (defined(GD32F330) || defined(GD32F350) || defined(GD32F355) || defined(GD32F370))
+    RCU_TIMER1  = RCU_REGIDX_BIT(IDX_APB1EN, 0U),                 /*!< TIMER1 clock */
+#endif /* GD32F330, GD32F350, GD32F355 and GD32F370*/
+    RCU_TIMER2  = RCU_REGIDX_BIT(IDX_APB1EN, 1U),                 /*!< TIMER2 clock */
+    RCU_TIMER13 = RCU_REGIDX_BIT(IDX_APB1EN, 8U),                 /*!< TIMER13 clock */
+    RCU_WWDGT   = RCU_REGIDX_BIT(IDX_APB1EN, 11U),                /*!< WWDGT clock */
+    RCU_SPI1    = RCU_REGIDX_BIT(IDX_APB1EN, 14U),                /*!< SPI1 clock */
+    RCU_USART1  = RCU_REGIDX_BIT(IDX_APB1EN, 17U),                /*!< USART1 clock */
+    RCU_I2C0    = RCU_REGIDX_BIT(IDX_APB1EN, 21U),                /*!< I2C0 clock */
+    RCU_I2C1    = RCU_REGIDX_BIT(IDX_APB1EN, 22U),                /*!< I2C1 clock */
+    RCU_PMU     = RCU_REGIDX_BIT(IDX_APB1EN, 28U),                /*!< PMU clock */
+#if (defined(GD32F350) || defined(GD32F355) || defined(GD32F370))
+    RCU_DAC     = RCU_REGIDX_BIT(IDX_APB1EN, 29U),                /*!< DAC clock */
+    RCU_CEC     = RCU_REGIDX_BIT(IDX_APB1EN, 30U),                /*!< CEC clock */
+    RCU_TIMER5  = RCU_REGIDX_BIT(IDX_APB1EN, 4U),                 /*!< TIMER5 clock */
+    RCU_USBFS   = RCU_REGIDX_BIT(IDX_AHBEN, 12U),                 /*!< USBFS clock */
+#endif /* GD32F350, GD32F355 and GD32F370 */
+    RCU_RTC     = RCU_REGIDX_BIT(IDX_BDCTL, 15U),                 /*!< RTC clock */
+
+    /* RCU_ADDAPB1EN */
+    RCU_CTC     = RCU_REGIDX_BIT(IDX_ADDAPB1EN, 27U)              /*!< CTC clock */
+} rcu_periph_enum;
+
+/* peripheral clock enable when sleep mode*/
+typedef enum {
+    /* AHB peripherals */
+    RCU_SRAM_SLP     = RCU_REGIDX_BIT(IDX_AHBEN, 2U),             /*!< SRAM clock */
+    RCU_FMC_SLP      = RCU_REGIDX_BIT(IDX_AHBEN, 4U),             /*!< FMC clock */
+} rcu_periph_sleep_enum;
+
+/* peripherals reset */
+typedef enum {
+    /* AHB peripherals reset */
+    RCU_GPIOARST   = RCU_REGIDX_BIT(IDX_AHBRST, 17U),             /*!< GPIOA reset */
+    RCU_GPIOBRST   = RCU_REGIDX_BIT(IDX_AHBRST, 18U),             /*!< GPIOB reset */
+    RCU_GPIOCRST   = RCU_REGIDX_BIT(IDX_AHBRST, 19U),             /*!< GPIOC reset */
+    RCU_GPIODRST   = RCU_REGIDX_BIT(IDX_AHBRST, 20U),             /*!< GPIOD reset */
+    RCU_GPIOFRST   = RCU_REGIDX_BIT(IDX_AHBRST, 22U),             /*!< GPIOF reset */
+#if (defined(GD32F350) || defined(GD32F355) || defined(GD32F370))
+    RCU_TSIRST     = RCU_REGIDX_BIT(IDX_AHBRST, 24U),             /*!< TSI reset */
+#endif /* GD32F350, GD32F355 and GD32F370 */
+
+    /* APB2 peripherals reset */
+    RCU_CFGCMPRST  = RCU_REGIDX_BIT(IDX_APB2RST, 0U),             /*!< CFGCMP reset */
+    RCU_ADCRST     = RCU_REGIDX_BIT(IDX_APB2RST, 9U),             /*!< ADC reset */
+    RCU_TIMER0RST  = RCU_REGIDX_BIT(IDX_APB2RST, 11U),            /*!< TIMER0 reset */
+    RCU_SPI0RST    = RCU_REGIDX_BIT(IDX_APB2RST, 12U),            /*!< SPI0 reset */
+    RCU_USART0RST  = RCU_REGIDX_BIT(IDX_APB2RST, 14U),            /*!< USART0 reset */
+    RCU_TIMER14RST = RCU_REGIDX_BIT(IDX_APB2RST, 16U),            /*!< TIMER14 reset */
+    RCU_TIMER15RST = RCU_REGIDX_BIT(IDX_APB2RST, 17U),            /*!< TIMER15 reset */
+    RCU_TIMER16RST = RCU_REGIDX_BIT(IDX_APB2RST, 18U),            /*!< TIMER16 reset */
+
+    /* APB1 peripherals reset */
+#if (defined(GD32F330) || defined(GD32F350) || defined(GD32F355) || defined(GD32F370))
+    RCU_TIMER1RST  = RCU_REGIDX_BIT(IDX_APB1RST, 0U),             /*!< TIMER1 reset */
+#endif /* GD32F330, GD32F350, GD32F355 and GD32F370*/
+    RCU_TIMER2RST  = RCU_REGIDX_BIT(IDX_APB1RST, 1U),             /*!< TIMER2 reset */
+    RCU_TIMER13RST = RCU_REGIDX_BIT(IDX_APB1RST, 8U),             /*!< TIMER13 reset */
+    RCU_WWDGTRST   = RCU_REGIDX_BIT(IDX_APB1RST, 11U),            /*!< WWDGT reset */
+    RCU_SPI1RST    = RCU_REGIDX_BIT(IDX_APB1RST, 14U),            /*!< SPI1 reset */
+    RCU_USART1RST  = RCU_REGIDX_BIT(IDX_APB1RST, 17U),            /*!< USART1 reset */
+    RCU_I2C0RST    = RCU_REGIDX_BIT(IDX_APB1RST, 21U),            /*!< I2C0 reset */
+    RCU_I2C1RST    = RCU_REGIDX_BIT(IDX_APB1RST, 22U),            /*!< I2C1 reset */
+    RCU_PMURST     = RCU_REGIDX_BIT(IDX_APB1RST, 28U),            /*!< PMU reset */
+#if (defined(GD32F350) || defined(GD32F355) || defined(GD32F370))
+    RCU_DACRST     = RCU_REGIDX_BIT(IDX_APB1RST, 29U),            /*!< DAC reset */
+    RCU_CECRST     = RCU_REGIDX_BIT(IDX_APB1RST, 30U),            /*!< CEC reset */
+    RCU_TIMER5RST  = RCU_REGIDX_BIT(IDX_APB1RST, 4U),             /*!< TIMER5 reset */
+    RCU_USBFSRST   = RCU_REGIDX_BIT(IDX_AHBRST, 12U),             /*!< USBFS reset */
+#endif /* GD32F350, GD32F355 and GD32F370 */
+    /* RCU_ADDAPB1RST */
+    RCU_CTCRST     = RCU_REGIDX_BIT(IDX_ADDAPB1RST, 27U),         /*!< CTC reset */
+} rcu_periph_reset_enum;
+
+/* clock stabilization and peripheral reset flags */
+typedef enum {
+    RCU_FLAG_IRC40KSTB    = RCU_REGIDX_BIT(IDX_RSTSCK, 1U),       /*!< IRC40K stabilization flags */
+    RCU_FLAG_LXTALSTB     = RCU_REGIDX_BIT(IDX_BDCTL, 1U),        /*!< LXTAL stabilization flags */
+    RCU_FLAG_IRC8MSTB     = RCU_REGIDX_BIT(IDX_CTL0, 1U),         /*!< IRC8M stabilization flags */
+    RCU_FLAG_HXTALSTB     = RCU_REGIDX_BIT(IDX_CTL0, 17U),        /*!< HXTAL stabilization flags */
+    RCU_FLAG_PLLSTB       = RCU_REGIDX_BIT(IDX_CTL0, 25U),        /*!< PLL stabilization flags */
+    RCU_FLAG_IRC28MSTB    = RCU_REGIDX_BIT(IDX_CTL1, 1U),         /*!< IRC28M stabilization flags */
+    RCU_FLAG_IRC48MSTB    = RCU_REGIDX_BIT(IDX_ADDCTL, 17U),      /*!< IRC48M stabilization flags */
+
+    RCU_FLAG_V12RST       = RCU_REGIDX_BIT(IDX_RSTSCK, 23U),      /*!< V12 reset flags */
+    RCU_FLAG_OBLRST       = RCU_REGIDX_BIT(IDX_RSTSCK, 25U),      /*!< OBL reset flags */
+    RCU_FLAG_EPRST        = RCU_REGIDX_BIT(IDX_RSTSCK, 26U),      /*!< EPR reset flags */
+    RCU_FLAG_PORRST       = RCU_REGIDX_BIT(IDX_RSTSCK, 27U),      /*!< power reset flags */
+    RCU_FLAG_SWRST        = RCU_REGIDX_BIT(IDX_RSTSCK, 28U),      /*!< SW reset flags */
+    RCU_FLAG_FWDGTRST     = RCU_REGIDX_BIT(IDX_RSTSCK, 29U),      /*!< FWDGT reset flags */
+    RCU_FLAG_WWDGTRST     = RCU_REGIDX_BIT(IDX_RSTSCK, 30U),      /*!< WWDGT reset flags */
+    RCU_FLAG_LPRST        = RCU_REGIDX_BIT(IDX_RSTSCK, 31U)       /*!< LP reset flags */
+} rcu_flag_enum;
+
+/* clock stabilization and ckm interrupt flags */
+typedef enum {
+    RCU_INT_FLAG_IRC40KSTB = RCU_REGIDX_BIT(IDX_INT, 0U),         /*!< IRC40K stabilization interrupt flag */
+    RCU_INT_FLAG_LXTALSTB  = RCU_REGIDX_BIT(IDX_INT, 1U),         /*!< LXTAL stabilization interrupt flag */
+    RCU_INT_FLAG_IRC8MSTB  = RCU_REGIDX_BIT(IDX_INT, 2U),         /*!< IRC8M stabilization interrupt flag */
+    RCU_INT_FLAG_HXTALSTB  = RCU_REGIDX_BIT(IDX_INT, 3U),         /*!< HXTAL stabilization interrupt flag */
+    RCU_INT_FLAG_PLLSTB    = RCU_REGIDX_BIT(IDX_INT, 4U),         /*!< PLL stabilization interrupt flag */
+    RCU_INT_FLAG_IRC28MSTB = RCU_REGIDX_BIT(IDX_INT, 5U),         /*!< IRC28M stabilization interrupt flag */
+    RCU_INT_FLAG_CKM       = RCU_REGIDX_BIT(IDX_INT, 7U),         /*!< CKM interrupt flag */
+    RCU_INT_FLAG_IRC48MSTB = RCU_REGIDX_BIT(IDX_ADDINT, 6U)       /*!< IRC48M stabilization interrupt flag */
+} rcu_int_flag_enum;
+
+/* clock stabilization and stuck interrupt flags clear */
+typedef enum {
+    RCU_INT_FLAG_IRC40KSTB_CLR = RCU_REGIDX_BIT(IDX_INT, 16U),    /*!< IRC40K stabilization interrupt flags clear */
+    RCU_INT_FLAG_LXTALSTB_CLR  = RCU_REGIDX_BIT(IDX_INT, 17U),    /*!< LXTAL stabilization interrupt flags clear */
+    RCU_INT_FLAG_IRC8MSTB_CLR  = RCU_REGIDX_BIT(IDX_INT, 18U),    /*!< IRC8M stabilization interrupt flags clear */
+    RCU_INT_FLAG_HXTALSTB_CLR  = RCU_REGIDX_BIT(IDX_INT, 19U),    /*!< HXTAL stabilization interrupt flags clear */
+    RCU_INT_FLAG_PLLSTB_CLR    = RCU_REGIDX_BIT(IDX_INT, 20U),    /*!< PLL stabilization interrupt flags clear */
+    RCU_INT_FLAG_IRC28MSTB_CLR = RCU_REGIDX_BIT(IDX_INT, 21U),    /*!< IRC28M stabilization interrupt flags clear */
+    RCU_INT_FLAG_CKM_CLR       = RCU_REGIDX_BIT(IDX_INT, 23U),    /*!< CKM interrupt flags clear */
+    RCU_INT_FLAG_IRC48MSTB_CLR = RCU_REGIDX_BIT(IDX_ADDINT, 22U)  /*!< IRC48M stabilization interrupt flag clear */
+} rcu_int_flag_clear_enum;
+
+/* clock stabilization interrupt enable or disable */
+typedef enum {
+    RCU_INT_IRC40KSTB       = RCU_REGIDX_BIT(IDX_INT, 8U),        /*!< IRC40K stabilization interrupt */
+    RCU_INT_LXTALSTB        = RCU_REGIDX_BIT(IDX_INT, 9U),        /*!< LXTAL stabilization interrupt */
+    RCU_INT_IRC8MSTB        = RCU_REGIDX_BIT(IDX_INT, 10U),       /*!< IRC8M stabilization interrupt */
+    RCU_INT_HXTALSTB        = RCU_REGIDX_BIT(IDX_INT, 11U),       /*!< HXTAL stabilization interrupt */
+    RCU_INT_PLLSTB          = RCU_REGIDX_BIT(IDX_INT, 12U),       /*!< PLL stabilization interrupt */
+    RCU_INT_IRC28MSTB       = RCU_REGIDX_BIT(IDX_INT, 13U),       /*!< IRC28M stabilization interrupt */
+    RCU_INT_IRC48MSTB       = RCU_REGIDX_BIT(IDX_ADDINT, 14U)     /*!< IRC48M stabilization interrupt */
+} rcu_int_enum;
+
+/* ADC clock source */
+typedef enum {
+    RCU_ADCCK_IRC28M_DIV2   = 0U,                                 /*!< ADC clock source select IRC28M/2 */
+    RCU_ADCCK_IRC28M,                                             /*!< ADC clock source select IRC28M */
+    RCU_ADCCK_APB2_DIV2,                                          /*!< ADC clock source select APB2/2 */
+    RCU_ADCCK_AHB_DIV3,                                           /*!< ADC clock source select AHB/3 */
+    RCU_ADCCK_APB2_DIV4,                                          /*!< ADC clock source select APB2/4 */
+    RCU_ADCCK_AHB_DIV5,                                           /*!< ADC clock source select AHB/5 */
+    RCU_ADCCK_APB2_DIV6,                                          /*!< ADC clock source select APB2/6 */
+    RCU_ADCCK_AHB_DIV7,                                           /*!< ADC clock source select AHB/7 */
+    RCU_ADCCK_APB2_DIV8,                                          /*!< ADC clock source select APB2/8 */
+    RCU_ADCCK_AHB_DIV9                                            /*!< ADC clock source select AHB/9 */
+} rcu_adc_clock_enum;
+
+/* oscillator types */
+typedef enum {
+    RCU_HXTAL   = RCU_REGIDX_BIT(IDX_CTL0, 16U),                  /*!< HXTAL */
+    RCU_LXTAL   = RCU_REGIDX_BIT(IDX_BDCTL, 0U),                  /*!< LXTAL */
+    RCU_IRC8M   = RCU_REGIDX_BIT(IDX_CTL0, 0U),                   /*!< IRC8M */
+    RCU_IRC28M  = RCU_REGIDX_BIT(IDX_CTL1, 0U),                   /*!< IRC28M */
+    RCU_IRC48M  = RCU_REGIDX_BIT(IDX_ADDCTL, 16U),                /*!< IRC48M */
+    RCU_IRC40K  = RCU_REGIDX_BIT(IDX_RSTSCK, 0U),                 /*!< IRC40K */
+    RCU_PLL_CK  = RCU_REGIDX_BIT(IDX_CTL0, 24U)                   /*!< PLL */
+} rcu_osci_type_enum;
+
+/* rcu clock frequency */
+typedef enum {
+    CK_SYS      = 0U,                                             /*!< system clock */
+    CK_AHB,                                                       /*!< AHB clock */
+    CK_APB1,                                                      /*!< APB1 clock */
+    CK_APB2,                                                      /*!< APB2 clock */
+    CK_ADC,                                                       /*!< ADC clock */
+    CK_CEC,                                                       /*!< CEC clock */
+    CK_USART                                                      /*!< USART clock */
+} rcu_clock_freq_enum;
+
+/* system clock source select */
+#define CFG0_SCS(regval)            (BITS(0,1) & ((uint32_t)(regval) << 0))
+#define RCU_CKSYSSRC_IRC8M          CFG0_SCS(0)                   /*!< system clock source select IRC8M */
+#define RCU_CKSYSSRC_HXTAL          CFG0_SCS(1)                   /*!< system clock source select HXTAL */
+#define RCU_CKSYSSRC_PLL            CFG0_SCS(2)                   /*!< system clock source select PLL */
+
+/* system clock source select status */
+#define CFG0_SCSS(regval)           (BITS(2,3) & ((uint32_t)(regval) << 2))
+#define RCU_SCSS_IRC8M              CFG0_SCSS(0)                  /*!< system clock source select IRC8M */
+#define RCU_SCSS_HXTAL              CFG0_SCSS(1)                  /*!< system clock source select HXTAL */
+#define RCU_SCSS_PLL                CFG0_SCSS(2)                  /*!< system clock source select PLL */
+
+/* AHB prescaler selection */
+#define CFG0_AHBPSC(regval)         (BITS(4,7) & ((uint32_t)(regval) << 4))
+#define RCU_AHB_CKSYS_DIV1          CFG0_AHBPSC(0)                /*!< AHB prescaler select CK_SYS */
+#define RCU_AHB_CKSYS_DIV2          CFG0_AHBPSC(8)                /*!< AHB prescaler select CK_SYS/2 */
+#define RCU_AHB_CKSYS_DIV4          CFG0_AHBPSC(9)                /*!< AHB prescaler select CK_SYS/4 */
+#define RCU_AHB_CKSYS_DIV8          CFG0_AHBPSC(10)               /*!< AHB prescaler select CK_SYS/8 */
+#define RCU_AHB_CKSYS_DIV16         CFG0_AHBPSC(11)               /*!< AHB prescaler select CK_SYS/16 */
+#define RCU_AHB_CKSYS_DIV64         CFG0_AHBPSC(12)               /*!< AHB prescaler select CK_SYS/64 */
+#define RCU_AHB_CKSYS_DIV128        CFG0_AHBPSC(13)               /*!< AHB prescaler select CK_SYS/128 */
+#define RCU_AHB_CKSYS_DIV256        CFG0_AHBPSC(14)               /*!< AHB prescaler select CK_SYS/256 */
+#define RCU_AHB_CKSYS_DIV512        CFG0_AHBPSC(15)               /*!< AHB prescaler select CK_SYS/512 */
+
+/* APB1 prescaler selection */
+#define CFG0_APB1PSC(regval)        (BITS(8,10) & ((uint32_t)(regval) << 8))
+#define RCU_APB1_CKAHB_DIV1         CFG0_APB1PSC(0)               /*!< APB1 prescaler select CK_AHB */
+#define RCU_APB1_CKAHB_DIV2         CFG0_APB1PSC(4)               /*!< APB1 prescaler select CK_AHB/2 */
+#define RCU_APB1_CKAHB_DIV4         CFG0_APB1PSC(5)               /*!< APB1 prescaler select CK_AHB/4 */
+#define RCU_APB1_CKAHB_DIV8         CFG0_APB1PSC(6)               /*!< APB1 prescaler select CK_AHB/8 */
+#define RCU_APB1_CKAHB_DIV16        CFG0_APB1PSC(7)               /*!< APB1 prescaler select CK_AHB/16 */
+
+/* APB2 prescaler selection */
+#define CFG0_APB2PSC(regval)        (BITS(11,13) & ((uint32_t)(regval) << 11))
+#define RCU_APB2_CKAHB_DIV1         CFG0_APB2PSC(0)               /*!< APB2 prescaler select CK_AHB */
+#define RCU_APB2_CKAHB_DIV2         CFG0_APB2PSC(4)               /*!< APB2 prescaler select CK_AHB/2 */
+#define RCU_APB2_CKAHB_DIV4         CFG0_APB2PSC(5)               /*!< APB2 prescaler select CK_AHB/4 */
+#define RCU_APB2_CKAHB_DIV8         CFG0_APB2PSC(6)               /*!< APB2 prescaler select CK_AHB/8 */
+#define RCU_APB2_CKAHB_DIV16        CFG0_APB2PSC(7)               /*!< APB2 prescaler select CK_AHB/16 */
+
+/* ADC clock prescaler selection */
+#define CFG0_ADCPSC(regval)         (BITS(14,15) & ((uint32_t)(regval) << 14))
+#define RCU_ADC_CKAPB2_DIV2         CFG0_ADCPSC(0)                /*!< ADC clock prescaler select CK_APB2/2 */
+#define RCU_ADC_CKAPB2_DIV4         CFG0_ADCPSC(1)                /*!< ADC clock prescaler select CK_APB2/4 */
+#define RCU_ADC_CKAPB2_DIV6         CFG0_ADCPSC(2)                /*!< ADC clock prescaler select CK_APB2/6 */
+#define RCU_ADC_CKAPB2_DIV8         CFG0_ADCPSC(3)                /*!< ADC clock prescaler select CK_APB2/8 */
+
+/* PLL clock source selection */
+#define RCU_PLLSRC_IRC8M_DIV2       ((uint32_t)0x00000000U)       /*!< PLL clock source select IRC8M/2 */
+#define RCU_PLLSRC_HXTAL_IRC48M     RCU_CFG0_PLLSEL               /*!< PLL clock source select HXTAL or IRC48M*/
+
+/* PLL clock source preselection */
+#define RCU_PLLPRESEL_HXTAL         ((uint32_t)0x00000000U)       /*!< PLL clock source preselection HXTAL */
+#define RCU_PLLPRESEL_IRC48M        RCU_CFG1_PLLPRESEL            /*!< PLL clock source preselection IRC48M */
+
+/* HXTAL or IRC48M divider for PLL source clock selection */
+#define RCU_PLLPREDV                ((uint32_t)0x00000000U)       /*!< HXTAL or IRC48M clock selected */
+#define RCU_PLLPREDV_DIV2           RCU_CFG0_PLLPREDV             /*!< (HXTAL or IRC48M) /2 clock selected */
+
+/* PLL multiply factor */
+#define CFG0_PLLMF(regval)          (BITS(18,21) & ((uint32_t)(regval) << 18))
+#define RCU_PLL_MUL2                CFG0_PLLMF(0)                       /*!< PLL source clock multiply by 2 */
+#define RCU_PLL_MUL3                CFG0_PLLMF(1)                       /*!< PLL source clock multiply by 3 */
+#define RCU_PLL_MUL4                CFG0_PLLMF(2)                       /*!< PLL source clock multiply by 4 */
+#define RCU_PLL_MUL5                CFG0_PLLMF(3)                       /*!< PLL source clock multiply by 5 */
+#define RCU_PLL_MUL6                CFG0_PLLMF(4)                       /*!< PLL source clock multiply by 6 */
+#define RCU_PLL_MUL7                CFG0_PLLMF(5)                       /*!< PLL source clock multiply by 7 */
+#define RCU_PLL_MUL8                CFG0_PLLMF(6)                       /*!< PLL source clock multiply by 8 */
+#define RCU_PLL_MUL9                CFG0_PLLMF(7)                       /*!< PLL source clock multiply by 9 */
+#define RCU_PLL_MUL10               CFG0_PLLMF(8)                       /*!< PLL source clock multiply by 10 */
+#define RCU_PLL_MUL11               CFG0_PLLMF(9)                       /*!< PLL source clock multiply by 11 */
+#define RCU_PLL_MUL12               CFG0_PLLMF(10)                      /*!< PLL source clock multiply by 12 */
+#define RCU_PLL_MUL13               CFG0_PLLMF(11)                      /*!< PLL source clock multiply by 13 */
+#define RCU_PLL_MUL14               CFG0_PLLMF(12)                      /*!< PLL source clock multiply by 14 */
+#define RCU_PLL_MUL15               CFG0_PLLMF(13)                      /*!< PLL source clock multiply by 15 */
+#define RCU_PLL_MUL16               CFG0_PLLMF(14)                      /*!< PLL source clock multiply by 16 */
+#define RCU_PLL_MUL17               (RCU_CFG0_PLLMF4 | CFG0_PLLMF(0))   /*!< PLL source clock multiply by 17 */
+#define RCU_PLL_MUL18               (RCU_CFG0_PLLMF4 | CFG0_PLLMF(1))   /*!< PLL source clock multiply by 18 */
+#define RCU_PLL_MUL19               (RCU_CFG0_PLLMF4 | CFG0_PLLMF(2))   /*!< PLL source clock multiply by 19 */
+#define RCU_PLL_MUL20               (RCU_CFG0_PLLMF4 | CFG0_PLLMF(3))   /*!< PLL source clock multiply by 20 */
+#define RCU_PLL_MUL21               (RCU_CFG0_PLLMF4 | CFG0_PLLMF(4))   /*!< PLL source clock multiply by 21 */
+#define RCU_PLL_MUL22               (RCU_CFG0_PLLMF4 | CFG0_PLLMF(5))   /*!< PLL source clock multiply by 22 */
+#define RCU_PLL_MUL23               (RCU_CFG0_PLLMF4 | CFG0_PLLMF(6))   /*!< PLL source clock multiply by 23 */
+#define RCU_PLL_MUL24               (RCU_CFG0_PLLMF4 | CFG0_PLLMF(7))   /*!< PLL source clock multiply by 24 */
+#define RCU_PLL_MUL25               (RCU_CFG0_PLLMF4 | CFG0_PLLMF(8))   /*!< PLL source clock multiply by 25 */
+#define RCU_PLL_MUL26               (RCU_CFG0_PLLMF4 | CFG0_PLLMF(9))   /*!< PLL source clock multiply by 26 */
+#define RCU_PLL_MUL27               (RCU_CFG0_PLLMF4 | CFG0_PLLMF(10))  /*!< PLL source clock multiply by 27 */
+#define RCU_PLL_MUL28               (RCU_CFG0_PLLMF4 | CFG0_PLLMF(11))  /*!< PLL source clock multiply by 28 */
+#define RCU_PLL_MUL29               (RCU_CFG0_PLLMF4 | CFG0_PLLMF(12))  /*!< PLL source clock multiply by 29 */
+#define RCU_PLL_MUL30               (RCU_CFG0_PLLMF4 | CFG0_PLLMF(13))  /*!< PLL source clock multiply by 30 */
+#define RCU_PLL_MUL31               (RCU_CFG0_PLLMF4 | CFG0_PLLMF(14))  /*!< PLL source clock multiply by 31 */
+#define RCU_PLL_MUL32               (RCU_CFG0_PLLMF4 | CFG0_PLLMF(15))  /*!< PLL source clock multiply by 32 */
+#define RCU_PLL_MUL33               (CFG0_PLLMF(0) | RCU_CFG1_PLLMF5)   /*!< PLL source clock multiply by 33 */
+#define RCU_PLL_MUL34               (CFG0_PLLMF(1) | RCU_CFG1_PLLMF5)   /*!< PLL source clock multiply by 34 */
+#define RCU_PLL_MUL35               (CFG0_PLLMF(2) | RCU_CFG1_PLLMF5)   /*!< PLL source clock multiply by 35 */
+#define RCU_PLL_MUL36               (CFG0_PLLMF(3) | RCU_CFG1_PLLMF5)   /*!< PLL source clock multiply by 36 */
+#define RCU_PLL_MUL37               (CFG0_PLLMF(4) | RCU_CFG1_PLLMF5)   /*!< PLL source clock multiply by 37 */
+#define RCU_PLL_MUL38               (CFG0_PLLMF(5) | RCU_CFG1_PLLMF5)   /*!< PLL source clock multiply by 38 */
+#define RCU_PLL_MUL39               (CFG0_PLLMF(6) | RCU_CFG1_PLLMF5)   /*!< PLL source clock multiply by 39 */
+#define RCU_PLL_MUL40               (CFG0_PLLMF(7) | RCU_CFG1_PLLMF5)   /*!< PLL source clock multiply by 40 */
+#define RCU_PLL_MUL41               (CFG0_PLLMF(8) | RCU_CFG1_PLLMF5)   /*!< PLL source clock multiply by 41 */
+#define RCU_PLL_MUL42               (CFG0_PLLMF(9) | RCU_CFG1_PLLMF5)   /*!< PLL source clock multiply by 42 */
+#define RCU_PLL_MUL43               (CFG0_PLLMF(10) | RCU_CFG1_PLLMF5)  /*!< PLL source clock multiply by 43 */
+#define RCU_PLL_MUL44               (CFG0_PLLMF(11) | RCU_CFG1_PLLMF5)  /*!< PLL source clock multiply by 44 */
+#define RCU_PLL_MUL45               (CFG0_PLLMF(12) | RCU_CFG1_PLLMF5)  /*!< PLL source clock multiply by 45 */
+#define RCU_PLL_MUL46               (CFG0_PLLMF(13) | RCU_CFG1_PLLMF5)  /*!< PLL source clock multiply by 46 */
+#define RCU_PLL_MUL47               (CFG0_PLLMF(14) | RCU_CFG1_PLLMF5)  /*!< PLL source clock multiply by 47 */
+#define RCU_PLL_MUL48               (CFG0_PLLMF(15) | RCU_CFG1_PLLMF5)  /*!< PLL source clock multiply by 48 */
+#define RCU_PLL_MUL49               (RCU_CFG0_PLLMF4 | RCU_CFG1_PLLMF5) /*!< PLL source clock multiply by 49 */
+#define RCU_PLL_MUL50               (RCU_PLL_MUL18 | RCU_CFG1_PLLMF5)   /*!< PLL source clock multiply by 50 */
+#define RCU_PLL_MUL51               (RCU_PLL_MUL19 | RCU_CFG1_PLLMF5)   /*!< PLL source clock multiply by 51 */
+#define RCU_PLL_MUL52               (RCU_PLL_MUL20 | RCU_CFG1_PLLMF5)   /*!< PLL source clock multiply by 52 */
+#define RCU_PLL_MUL53               (RCU_PLL_MUL21 | RCU_CFG1_PLLMF5)   /*!< PLL source clock multiply by 53 */
+#define RCU_PLL_MUL54               (RCU_PLL_MUL22 | RCU_CFG1_PLLMF5)   /*!< PLL source clock multiply by 54 */
+#define RCU_PLL_MUL55               (RCU_PLL_MUL23 | RCU_CFG1_PLLMF5)   /*!< PLL source clock multiply by 55 */
+#define RCU_PLL_MUL56               (RCU_PLL_MUL24 | RCU_CFG1_PLLMF5)   /*!< PLL source clock multiply by 56 */
+#define RCU_PLL_MUL57               (RCU_PLL_MUL25 | RCU_CFG1_PLLMF5)   /*!< PLL source clock multiply by 57 */
+#define RCU_PLL_MUL58               (RCU_PLL_MUL26 | RCU_CFG1_PLLMF5)   /*!< PLL source clock multiply by 58 */
+#define RCU_PLL_MUL59               (RCU_PLL_MUL27 | RCU_CFG1_PLLMF5)   /*!< PLL source clock multiply by 59 */
+#define RCU_PLL_MUL60               (RCU_PLL_MUL28 | RCU_CFG1_PLLMF5)   /*!< PLL source clock multiply by 60 */
+#define RCU_PLL_MUL61               (RCU_PLL_MUL29 | RCU_CFG1_PLLMF5)   /*!< PLL source clock multiply by 61 */
+#define RCU_PLL_MUL62               (RCU_PLL_MUL30 | RCU_CFG1_PLLMF5)   /*!< PLL source clock multiply by 62 */
+#define RCU_PLL_MUL63               (RCU_PLL_MUL31 | RCU_CFG1_PLLMF5)   /*!< PLL source clock multiply by 63 */
+#define RCU_PLL_MUL64               (RCU_PLL_MUL32 | RCU_CFG1_PLLMF5)   /*!< PLL source clock multiply by 64 */
+
+/* USBFS clock prescaler selection */
+#define CFG0_USBFSPSC(regval)       (BITS(22,23) & ((uint32_t)(regval) << 22))
+#define RCU_USBFS_CKPLL_DIV1_5      CFG0_USBFSPSC(0)                      /*!< USBFS clock prescaler select CK_PLL/1.5 */
+#define RCU_USBFS_CKPLL_DIV1        CFG0_USBFSPSC(1)                      /*!< USBFS clock prescaler select CK_PLL */
+#define RCU_USBFS_CKPLL_DIV2_5      CFG0_USBFSPSC(2)                      /*!< USBFS clock prescaler select CK_PLL/2.5 */
+#define RCU_USBFS_CKPLL_DIV2        CFG0_USBFSPSC(3)                      /*!< USBFS clock prescaler select CK_PLL/2 */
+#define RCU_USBFS_CKPLL_DIV3        RCU_CFG2_USBFSPSC2                    /*!< USBFS clock prescaler select CK_PLL/3 */
+#define RCU_USBFS_CKPLL_DIV3_5      (CFG0_USBFSPSC(1)|RCU_CFG2_USBFSPSC2) /*!< USBFS clock prescaler select CK_PLL/3.5 */
+
+/* CK_OUT clock source selection */
+#define CFG0_CKOUTSEL(regval)       (BITS(24,26) & ((uint32_t)(regval) << 24))
+#define RCU_CKOUTSRC_NONE           CFG0_CKOUTSEL(0)                      /*!< no clock selected */
+#define RCU_CKOUTSRC_IRC28M         CFG0_CKOUTSEL(1)                      /*!< CK_OUT clock source select IRC28M */
+#define RCU_CKOUTSRC_IRC40K         CFG0_CKOUTSEL(2)                      /*!< CK_OUT clock source select IRC40K */
+#define RCU_CKOUTSRC_LXTAL          CFG0_CKOUTSEL(3)                      /*!< CK_OUT clock source select LXTAL */
+#define RCU_CKOUTSRC_CKSYS          CFG0_CKOUTSEL(4)                      /*!< CK_OUT clock source select CKSYS */
+#define RCU_CKOUTSRC_IRC8M          CFG0_CKOUTSEL(5)                      /*!< CK_OUT clock source select IRC8M */
+#define RCU_CKOUTSRC_HXTAL          CFG0_CKOUTSEL(6)                      /*!< CK_OUT clock source select HXTAL */
+#define RCU_CKOUTSRC_CKPLL_DIV1     (RCU_CFG0_PLLDV | CFG0_CKOUTSEL(7))   /*!< CK_OUT clock source select CK_PLL */
+#define RCU_CKOUTSRC_CKPLL_DIV2     CFG0_CKOUTSEL(7)                      /*!< CK_OUT clock source select CK_PLL/2 */
+
+/* CK_OUT divider */
+#define CFG0_CKOUTDIV(regval)       (BITS(28,30) & ((uint32_t)(regval) << 28))
+#define RCU_CKOUT_DIV1              CFG0_CKOUTDIV(0)                      /*!< CK_OUT is divided by 1 */
+#define RCU_CKOUT_DIV2              CFG0_CKOUTDIV(1)                      /*!< CK_OUT is divided by 2 */
+#define RCU_CKOUT_DIV4              CFG0_CKOUTDIV(2)                      /*!< CK_OUT is divided by 4 */
+#define RCU_CKOUT_DIV8              CFG0_CKOUTDIV(3)                      /*!< CK_OUT is divided by 8 */
+#define RCU_CKOUT_DIV16             CFG0_CKOUTDIV(4)                      /*!< CK_OUT is divided by 16 */
+#define RCU_CKOUT_DIV32             CFG0_CKOUTDIV(5)                      /*!< CK_OUT is divided by 32 */
+#define RCU_CKOUT_DIV64             CFG0_CKOUTDIV(6)                      /*!< CK_OUT is divided by 64 */
+#define RCU_CKOUT_DIV128            CFG0_CKOUTDIV(7)                      /*!< CK_OUT is divided by 128 */
+
+/* CK_PLL divide by 1 or 2 for CK_OUT */
+#define RCU_PLLDV_CKPLL_DIV2        ((uint32_t)0x00000000U)               /*!< CK_PLL divide by 2 for CK_OUT */
+#define RCU_PLLDV_CKPLL             RCU_CFG0_PLLDV                        /*!< CK_PLL divide by 1 for CK_OUT */
+
+/* LXTAL drive capability */
+#define BDCTL_LXTALDRI(regval)      (BITS(3,4) & ((uint32_t)(regval) << 3))
+#define RCU_LXTAL_LOWDRI            BDCTL_LXTALDRI(0)                     /*!< lower driving capability */
+#define RCU_LXTAL_MED_LOWDRI        BDCTL_LXTALDRI(1)                     /*!< medium low driving capability */
+#define RCU_LXTAL_MED_HIGHDRI       BDCTL_LXTALDRI(2)                     /*!< medium high driving capability */
+#define RCU_LXTAL_HIGHDRI           BDCTL_LXTALDRI(3)                     /*!< higher driving capability */
+
+/* RTC clock entry selection */
+#define BDCTL_RTCSRC(regval)        (BITS(8,9) & ((uint32_t)(regval) << 8))
+#define RCU_RTCSRC_NONE             BDCTL_RTCSRC(0)                       /*!< no clock selected */
+#define RCU_RTCSRC_LXTAL            BDCTL_RTCSRC(1)                       /*!< LXTAL selected as RTC source clock */
+#define RCU_RTCSRC_IRC40K           BDCTL_RTCSRC(2)                       /*!< IRC40K selected as RTC source clock */
+#define RCU_RTCSRC_HXTAL_DIV32      BDCTL_RTCSRC(3)                       /*!< HXTAL/32 selected as RTC source clock */
+
+/* CK_HXTAL divider previous PLL */
+#define CFG1_PREDV(regval)         (BITS(0,3) & ((uint32_t)(regval) << 0))
+#define RCU_PLL_PREDV1              CFG1_PREDV(0)                         /*!< PLL not divided */
+#define RCU_PLL_PREDV2              CFG1_PREDV(1)                         /*!< PLL divided by 2 */
+#define RCU_PLL_PREDV3              CFG1_PREDV(2)                         /*!< PLL divided by 3 */
+#define RCU_PLL_PREDV4              CFG1_PREDV(3)                         /*!< PLL divided by 4 */
+#define RCU_PLL_PREDV5              CFG1_PREDV(4)                         /*!< PLL divided by 5 */
+#define RCU_PLL_PREDV6              CFG1_PREDV(5)                         /*!< PLL divided by 6 */
+#define RCU_PLL_PREDV7              CFG1_PREDV(6)                         /*!< PLL divided by 7 */
+#define RCU_PLL_PREDV8              CFG1_PREDV(7)                         /*!< PLL divided by 8 */
+#define RCU_PLL_PREDV9              CFG1_PREDV(8)                         /*!< PLL divided by 9 */
+#define RCU_PLL_PREDV10             CFG1_PREDV(9)                         /*!< PLL divided by 10 */
+#define RCU_PLL_PREDV11             CFG1_PREDV(10)                        /*!< PLL divided by 11 */
+#define RCU_PLL_PREDV12             CFG1_PREDV(11)                        /*!< PLL divided by 12 */
+#define RCU_PLL_PREDV13             CFG1_PREDV(12)                        /*!< PLL divided by 13 */
+#define RCU_PLL_PREDV14             CFG1_PREDV(13)                        /*!< PLL divided by 14 */
+#define RCU_PLL_PREDV15             CFG1_PREDV(14)                        /*!< PLL divided by 15 */
+#define RCU_PLL_PREDV16             CFG1_PREDV(15)                        /*!< PLL divided by 16 */
+
+/* USART0 clock source selection */
+#define CFG2_USART0SEL(regval)      (BITS(0,1) & ((uint32_t)(regval) << 0))
+#define RCU_USART0SRC_CKAPB2        CFG2_USART0SEL(0)                     /*!< CK_USART0 select CK_APB2 */
+#define RCU_USART0SRC_CKSYS         CFG2_USART0SEL(1)                     /*!< CK_USART0 select CK_SYS */
+#define RCU_USART0SRC_LXTAL         CFG2_USART0SEL(2)                     /*!< CK_USART0 select LXTAL */
+#define RCU_USART0SRC_IRC8M         CFG2_USART0SEL(3)                     /*!< CK_USART0 select IRC8M */
+
+/* CEC clock source selection */
+#define RCU_CECSRC_IRC8M_DIV244     ((uint32_t)0x00000000U)               /*!< CK_CEC clock source select IRC8M/244 */
+#define RCU_CECSRC_LXTAL            RCU_CFG2_CECSEL                       /*!< CK_CEC clock source select LXTAL */
+
+/* ADC clock source selection */
+#define RCU_ADCSRC_IRC28M           ((uint32_t)0x00000000U)               /*!< ADC clock source select */
+#define RCU_ADCSRC_AHB_APB2DIV      RCU_CFG2_ADCSEL                       /*!< ADC clock source select */
+
+/* IRC28M clock divider for ADC */
+#define RCU_ADC_IRC28M_DIV2         ((uint32_t)0x00000000U)               /*!< IRC28M/2 select to ADC clock */
+#define RCU_ADC_IRC28M_DIV1         RCU_CFG2_IRC28MDIV                    /*!< IRC28M select to ADC clock */
+
+/* CK48M clock source selection */
+#define RCU_CK48MSRC_PLL48M         ((uint32_t)0x00000000U)               /*!< CK48M source clock select PLL48M */
+#define RCU_CK48MSRC_IRC48M         RCU_ADDCTL_CK48MSEL                   /*!< CK48M source clock select IRC48M */
+
+/* Deep-sleep mode voltage */
+#define DSV_DSLPVS(regval)          (BITS(0,1) & ((uint32_t)(regval) << 0))
+#define RCU_DEEPSLEEP_V_0           DSV_DSLPVS(0)                         /*!< core voltage is default value in deep-sleep mode */
+#define RCU_DEEPSLEEP_V_1           DSV_DSLPVS(1)                         /*!< core voltage is (default value-0.1)V in deep-sleep mode */
+#define RCU_DEEPSLEEP_V_2           DSV_DSLPVS(2)                         /*!< core voltage is (default value-0.2)V in deep-sleep mode */
+#define RCU_DEEPSLEEP_V_3           DSV_DSLPVS(3)                         /*!< core voltage is (default value-0.3)V in deep-sleep mode */
+
+/* function declarations */
+/* peripherals clock configure functions */
+/* deinitialize the RCU */
+void rcu_deinit(void);
+/* enable the peripherals clock */
+void rcu_periph_clock_enable(rcu_periph_enum periph);
+/* disable the peripherals clock */
+void rcu_periph_clock_disable(rcu_periph_enum periph);
+/* enable the peripherals clock when sleep mode */
+void rcu_periph_clock_sleep_enable(rcu_periph_sleep_enum periph);
+/* disable the peripherals clock when sleep mode */
+void rcu_periph_clock_sleep_disable(rcu_periph_sleep_enum periph);
+/* reset the peripherals */
+void rcu_periph_reset_enable(rcu_periph_reset_enum periph_reset);
+/* disable reset the peripheral */
+void rcu_periph_reset_disable(rcu_periph_reset_enum periph_reset);
+/* reset the BKP */
+void rcu_bkp_reset_enable(void);
+/* disable the BKP reset */
+void rcu_bkp_reset_disable(void);
+
+/* system and peripherals clock source, system reset configure functions */
+/* configure the system clock source */
+void rcu_system_clock_source_config(uint32_t ck_sys);
+/* get the system clock source */
+uint32_t rcu_system_clock_source_get(void);
+/* configure the AHB prescaler selection */
+void rcu_ahb_clock_config(uint32_t ck_ahb);
+/* configure the APB1 prescaler selection */
+void rcu_apb1_clock_config(uint32_t ck_apb1);
+/* configure the APB2 prescaler selection */
+void rcu_apb2_clock_config(uint32_t ck_apb2);
+/* configure the ADC clock source and prescaler selection */
+void rcu_adc_clock_config(rcu_adc_clock_enum ck_adc);
+/* configure the USBFS prescaler selection */
+void rcu_usbfs_clock_config(uint32_t ck_usbfs);
+/* configure the CK_OUT clock source and divider */
+void rcu_ckout_config(uint32_t ckout_src, uint32_t ckout_div);
+
+/* configure the PLL clock source preselection */
+void rcu_pll_preselection_config(uint32_t pll_presel);
+/* configure the PLL clock source selection and PLL multiply factor */
+void rcu_pll_config(uint32_t pll_src, uint32_t pll_mul);
+/* configure the USART clock source selection */
+void rcu_usart_clock_config(uint32_t ck_usart);
+/* configure the CEC clock source selection */
+void rcu_cec_clock_config(uint32_t ck_cec);
+/* configure the RTC clock source selection */
+void rcu_rtc_clock_config(uint32_t rtc_clock_source);
+/* configure the CK48M clock selection */
+void rcu_ck48m_clock_config(uint32_t ck48m_clock_source);
+/* configure the HXTAL divider used as input of PLL */
+void rcu_hxtal_prediv_config(uint32_t hxtal_prediv);
+/* configure the LXTAL drive capability */
+void rcu_lxtal_drive_capability_config(uint32_t lxtal_dricap);
+
+/* LXTAL, IRC8M, PLL and other oscillator configure functions */
+/* wait until oscillator stabilization flags is SET */
+ErrStatus rcu_osci_stab_wait(rcu_osci_type_enum osci);
+/* turn on the oscillator */
+void rcu_osci_on(rcu_osci_type_enum osci);
+/* turn off the oscillator */
+void rcu_osci_off(rcu_osci_type_enum osci);
+/* enable the oscillator bypass mode */
+void rcu_osci_bypass_mode_enable(rcu_osci_type_enum osci);
+/* disable the oscillator bypass mode */
+void rcu_osci_bypass_mode_disable(rcu_osci_type_enum osci);
+/* set the IRC8M adjust value */
+void rcu_irc8m_adjust_value_set(uint8_t irc8m_adjval);
+/* set the IRC28M adjust value */
+void rcu_irc28m_adjust_value_set(uint8_t irc28m_adjval);
+
+/* clock monitor configure functions */
+/* enable the HXTAL clock monitor */
+void rcu_hxtal_clock_monitor_enable(void);
+/* disable the HXTAL clock monitor */
+void rcu_hxtal_clock_monitor_disable(void);
+
+/* voltage configure and clock frequency get functions */
+/* unlock the voltage key */
+void rcu_voltage_key_unlock(void);
+/* set the deep sleep mode voltage */
+void rcu_deepsleep_voltage_set(uint32_t dsvol);
+/* get the system clock, bus and peripheral clock frequency */
+uint32_t rcu_clock_freq_get(rcu_clock_freq_enum clock);
+
+/* flag & interrupt functions */
+/* get the clock stabilization and periphral reset flags */
+FlagStatus rcu_flag_get(rcu_flag_enum flag);
+/* clear the reset flag */
+void rcu_all_reset_flag_clear(void);
+/* get the clock stabilization interrupt and ckm flags */
+FlagStatus rcu_interrupt_flag_get(rcu_int_flag_enum int_flag);
+/* clear the interrupt flags */
+void rcu_interrupt_flag_clear(rcu_int_flag_clear_enum int_flag_clear);
+/* enable the stabilization interrupt */
+void rcu_interrupt_enable(rcu_int_enum stab_int);
+/* disable the stabilization interrupt */
+void rcu_interrupt_disable(rcu_int_enum stab_int);
+
+#endif /* GD32F3X0_RCU_H */

+ 556 - 0
GD32F3x0/GD32F3x0_standard_peripheral/Include/gd32f3x0_rtc.h

@@ -0,0 +1,556 @@
+/*!
+    \file    gd32f3x0_rtc.h
+    \brief   definitions for the RTC
+
+    \version 2025-01-01, V2.5.0, firmware for GD32F3x0
+*/
+
+/*
+    Copyright (c) 2025, GigaDevice Semiconductor Inc.
+
+    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 of the copyright holder 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 HOLDER 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.
+*/
+
+#ifndef GD32F3X0_RTC_H
+#define GD32F3X0_RTC_H
+
+#include "gd32f3x0.h"
+
+/* RTC definitions */
+#define RTC                                RTC_BASE
+
+/* registers definitions */
+#define RTC_TIME                           REG32(RTC + 0x00000000U)                    /*!< RTC time of day register */
+#define RTC_DATE                           REG32(RTC + 0x00000004U)                    /*!< RTC date register */
+#define RTC_CTL                            REG32(RTC + 0x00000008U)                    /*!< RTC control register */
+#define RTC_STAT                           REG32(RTC + 0x0000000CU)                    /*!< RTC status register */
+#define RTC_PSC                            REG32(RTC + 0x00000010U)                    /*!< RTC time prescaler register */
+#define RTC_ALRM0TD                        REG32(RTC + 0x0000001CU)                    /*!< RTC alarm 0 time and date register */
+#define RTC_WPK                            REG32(RTC + 0x00000024U)                    /*!< RTC write protection key register */
+#define RTC_SS                             REG32(RTC + 0x00000028U)                    /*!< RTC sub second register */
+#define RTC_SHIFTCTL                       REG32(RTC + 0x0000002CU)                    /*!< RTC shift function control register */
+#define RTC_TTS                            REG32(RTC + 0x00000030U)                    /*!< RTC time of timestamp register */
+#define RTC_DTS                            REG32(RTC + 0x00000034U)                    /*!< RTC date of timestamp register */
+#define RTC_SSTS                           REG32(RTC + 0x00000038U)                    /*!< RTC sub second of timestamp register */
+#define RTC_HRFC                           REG32(RTC + 0x0000003CU)                    /*!< RTC high resolution frequency compensation registor */
+#define RTC_TAMP                           REG32(RTC + 0x00000040U)                    /*!< RTC tamper register */
+#define RTC_ALRM0SS                        REG32(RTC + 0x00000044U)                    /*!< RTC alarm 0 sub second register */
+#define RTC_BKP0                           REG32(RTC + 0x00000050U)                    /*!< RTC backup 0 register */
+#define RTC_BKP1                           REG32(RTC + 0x00000054U)                    /*!< RTC backup 1 register */
+#define RTC_BKP2                           REG32(RTC + 0x00000058U)                    /*!< RTC backup 2 register */
+#define RTC_BKP3                           REG32(RTC + 0x0000005CU)                    /*!< RTC backup 3 register */
+#define RTC_BKP4                           REG32(RTC + 0x00000060U)                    /*!< RTC backup 4 register */
+
+/* bits definitions */
+/* RTC_TIME */
+#define RTC_TIME_SCU                       BITS(0,3)                                   /*!< second units in BCD code */
+#define RTC_TIME_SCT                       BITS(4,6)                                   /*!< second tens in BCD code */
+#define RTC_TIME_MNU                       BITS(8,11)                                  /*!< minute units in BCD code */
+#define RTC_TIME_MNT                       BITS(12,14)                                 /*!< minute tens in BCD code */
+#define RTC_TIME_HRU                       BITS(16,19)                                 /*!< hour units in BCD code */
+#define RTC_TIME_HRT                       BITS(20,21)                                 /*!< hour tens in BCD code */
+#define RTC_TIME_PM                        BIT(22)                                     /*!< AM/PM notation */
+
+/* RTC_DATE */
+#define RTC_DATE_DAYU                      BITS(0,3)                                   /*!< date units in BCD code */
+#define RTC_DATE_DAYT                      BITS(4,5)                                   /*!< date tens in BCD code */
+#define RTC_DATE_MONU                      BITS(8,11)                                  /*!< month units in BCD code */
+#define RTC_DATE_MONT                      BIT(12)                                     /*!< month tens in BCD code */
+#define RTC_DATE_DOW                       BITS(13,15)                                 /*!< day of week units */
+#define RTC_DATE_YRU                       BITS(16,19)                                 /*!< year units in BCD code */
+#define RTC_DATE_YRT                       BITS(20,23)                                 /*!< year tens in BCD code */
+
+/* RTC_CTL */
+#define RTC_CTL_TSEG                       BIT(3)                                      /*!< valid event edge of time-stamp */
+#define RTC_CTL_REFEN                      BIT(4)                                      /*!< reference clock detection function enable */
+#define RTC_CTL_BPSHAD                     BIT(5)                                      /*!< shadow registers bypass control */
+#define RTC_CTL_CS                         BIT(6)                                      /*!< display format of clock system */
+#define RTC_CTL_ALRM0EN                    BIT(8)                                      /*!< alarm function enable */
+#define RTC_CTL_TSEN                       BIT(11)                                     /*!< time-stamp function enable */
+#define RTC_CTL_ALRM0IE                    BIT(12)                                     /*!< RTC alarm interrupt enable */
+#define RTC_CTL_TSIE                       BIT(15)                                     /*!< time-stamp interrupt enable */
+#define RTC_CTL_A1H                        BIT(16)                                     /*!< add 1 hour(summer time change) */
+#define RTC_CTL_S1H                        BIT(17)                                     /*!< subtract 1 hour(winter time change) */
+#define RTC_CTL_DSM                        BIT(18)                                     /*!< daylight saving mark */
+#define RTC_CTL_COS                        BIT(19)                                     /*!< calibration output selection */
+#define RTC_CTL_OPOL                       BIT(20)                                     /*!< output polarity */
+#define RTC_CTL_OS                         BITS(21,22)                                 /*!< output selection */
+#define RTC_CTL_COEN                       BIT(23)                                     /*!< calibration output enable */
+
+/* RTC_STAT */
+#define RTC_STAT_ALRM0WF                   BIT(0)                                      /*!< alarm configuration can be write flag */
+#define RTC_STAT_SOPF                      BIT(3)                                      /*!< shift function operation pending flag */
+#define RTC_STAT_YCM                       BIT(4)                                      /*!< year configuration mark status flag */
+#define RTC_STAT_RSYNF                     BIT(5)                                      /*!< register synchronization flag */
+#define RTC_STAT_INITF                     BIT(6)                                      /*!< initialization state flag */
+#define RTC_STAT_INITM                     BIT(7)                                      /*!< enter initialization mode */
+#define RTC_STAT_ALRM0F                    BIT(8)                                      /*!< alarm occurs flag */
+#define RTC_STAT_TSF                       BIT(11)                                     /*!< time-stamp flag */
+#define RTC_STAT_TSOVRF                    BIT(12)                                     /*!< time-stamp overflow flag */
+#define RTC_STAT_TP0F                      BIT(13)                                     /*!< RTC tamp 0 detected flag */
+#define RTC_STAT_TP1F                      BIT(14)                                     /*!< RTC tamp 1 detected flag */
+#define RTC_STAT_SCPF                      BIT(16)                                     /*!< recalibration pending flag */
+
+/* RTC_PSC */
+#define RTC_PSC_FACTOR_S                   BITS(0,14)                                  /*!< synchronous prescaler factor */
+#define RTC_PSC_FACTOR_A                   BITS(16,22)                                 /*!< asynchronous prescaler factor */
+
+/* RTC_ALRM0TD */
+#define RTC_ALRM0TD_SCU                    BITS(0,3)                                   /*!< second units in BCD code */
+#define RTC_ALRM0TD_SCT                    BITS(4,6)                                   /*!< second tens in BCD code */
+#define RTC_ALRM0TD_MSKS                   BIT(7)                                      /*!< alarm second mask bit */
+#define RTC_ALRM0TD_MNU                    BITS(8,11)                                  /*!< minutes units in BCD code */
+#define RTC_ALRM0TD_MNT                    BITS(12,14)                                 /*!< minutes tens in BCD code */
+#define RTC_ALRM0TD_MSKM                   BIT(15)                                     /*!< alarm minutes mask bit */
+#define RTC_ALRM0TD_HRU                    BITS(16,19)                                 /*!< hour units in BCD code */
+#define RTC_ALRM0TD_HRT                    BITS(20,21)                                 /*!< hour units in BCD code */
+#define RTC_ALRM0TD_PM                     BIT(22)                                     /*!< AM/PM flag */
+#define RTC_ALRM0TD_MSKH                   BIT(23)                                     /*!< alarm hour mask bit */
+#define RTC_ALRM0TD_DAYU                   BITS(24,27)                                 /*!< date units or week day in BCD code */
+#define RTC_ALRM0TD_DAYT                   BITS(28,29)                                 /*!< date tens in BCD code */
+#define RTC_ALRM0TD_DOWS                   BIT(30)                                     /*!< day of week  selection */
+#define RTC_ALRM0TD_MSKD                   BIT(31)                                     /*!< alarm date mask bit */
+
+/* RTC_WPK */
+#define RTC_WPK_WPK                        BITS(0,7)                                   /*!< key for write protection */
+
+/* RTC_SS */
+#define RTC_SS_SSC                         BITS(0,15)                                  /*!< sub second value */
+
+/* RTC_SHIFTCTL */
+#define RTC_SHIFTCTL_SFS                   BITS(0,14)                                  /*!< subtract a fraction of a second */
+#define RTC_SHIFTCTL_A1S                   BIT(31)                                     /*!< one second add */
+
+/* RTC_TTS */
+#define RTC_TTS_SCU                        BITS(0,3)                                   /*!< second units in BCD code */
+#define RTC_TTS_SCT                        BITS(4,6)                                   /*!< second units in BCD code */
+#define RTC_TTS_MNU                        BITS(8,11)                                  /*!< minute units in BCD code */
+#define RTC_TTS_MNT                        BITS(12,14)                                 /*!< minute tens in BCD code */
+#define RTC_TTS_HRU                        BITS(16,19)                                 /*!< hour units in BCD code */
+#define RTC_TTS_HRT                        BITS(20,21)                                 /*!< hour tens in BCD code */
+#define RTC_TTS_PM                         BIT(22)                                     /*!< AM/PM notation */
+
+/* RTC_DTS */
+#define RTC_DTS_DAYU                       BITS(0,3)                                   /*!< date units in BCD code */
+#define RTC_DTS_DAYT                       BITS(4,5)                                   /*!< date tens in BCD code */
+#define RTC_DTS_MONU                       BITS(8,11)                                  /*!< month units in BCD code */
+#define RTC_DTS_MONT                       BIT(12)                                     /*!< month tens in BCD code */
+#define RTC_DTS_DOW                        BITS(13,15)                                 /*!< day of week units */
+
+/* RTC_SSTS */
+#define RTC_SSTS_SSC                       BITS(0,15)                                  /*!< timestamp sub second units */
+
+/* RTC_HRFC */
+#define RTC_HRFC_CMSK                      BITS(0,8)                                   /*!< calibration mask number */
+#define RTC_HRFC_CWND16                    BIT(13)                                     /*!< calibration window select 16 seconds */
+#define RTC_HRFC_CWND8                     BIT(14)                                     /*!< calibration window select 16 seconds */
+#define RTC_HRFC_FREQI                     BIT(15)                                     /*!< increase RTC frequency by 488.5ppm */
+
+/* RTC_TAMP */
+#define RTC_TAMP_TP0EN                     BIT(0)                                      /*!< tamper 0 detection enable */
+#define RTC_TAMP_TP0EG                     BIT(1)                                      /*!< tamper 0 event trigger edge for RTC tamp 0 input */
+#define RTC_TAMP_TPIE                      BIT(2)                                      /*!< tamper detection interrupt enable */
+#define RTC_TAMP_TP1EN                     BIT(3)                                      /*!< tamper 1 detection enable */
+#define RTC_TAMP_TP1EG                     BIT(4)                                      /*!< tamper 1 event trigger edge for RTC tamp 1 input */
+#define RTC_TAMP_TPTS                      BIT(7)                                      /*!< make tamper function used for timestamp function */
+#define RTC_TAMP_FREQ                      BITS(8,10)                                  /*!< sample frequency of tamper event detection */
+#define RTC_TAMP_FLT                       BITS(11,12)                                 /*!< RTC tamp x filter count setting */
+#define RTC_TAMP_PRCH                      BITS(13,14)                                 /*!< precharge duration time of RTC tamp x */
+#define RTC_TAMP_DISPU                     BIT(15)                                     /*!< RTC tamp x pull up disable bit */
+#define RTC_TAMP_PC13VAL                   BIT(18)                                     /*!< alarm output type control/PC13 output value */
+#define RTC_TAMP_PC13MDE                   BIT(19)                                     /*!< PC13 mode */
+#define RTC_TAMP_PC14VAL                   BIT(20)                                     /*!< PC14 output value */
+#define RTC_TAMP_PC14MDE                   BIT(21)                                     /*!< PC14 mode */
+#define RTC_TAMP_PC15VAL                   BIT(22)                                     /*!< PC15 output value */
+#define RTC_TAMP_PC15MDE                   BIT(23)                                     /*!< PC15 mode */
+
+/* RTC_ALRM0SS */
+#define RTC_ALRM0SS_SSC                    BITS(0,14)                                  /*!< alarm sub second value */
+#define RTC_ALRM0SS_MASKSSC                BITS(24,27)                                 /*!< mask control bit of SS */
+
+/* RTC_BKP0 */
+#define RTC_BKP0_DATA                      BITS(0,31)                                  /*!< backup domain registers */
+
+/* RTC_BKP1 */
+#define RTC_BKP1_DATA                      BITS(0,31)                                  /*!< backup domain registers */
+
+/* RTC_BKP2 */
+#define RTC_BKP2_DATA                      BITS(0,31)                                  /*!< backup domain registers */
+
+/* RTC_BKP3 */
+#define RTC_BKP3_DATA                      BITS(0,31)                                  /*!< backup domain registers */
+
+/* RTC_BKP4 */
+#define RTC_BKP4_DATA                      BITS(0,31)                                  /*!< backup domain registers */
+
+/* constants definitions */
+/* structure for initialization of the RTC */
+typedef struct {
+    uint8_t rtc_year;                                                                  /*!< RTC year value: 0x0 - 0x99(BCD format) */
+    uint8_t rtc_month;                                                                 /*!< RTC month value */
+    uint8_t rtc_date;                                                                  /*!< RTC date value: 0x1 - 0x31(BCD format) */
+    uint8_t rtc_day_of_week;                                                           /*!< RTC weekday value */
+    uint8_t rtc_hour;                                                                  /*!< RTC hour value */
+    uint8_t rtc_minute;                                                                /*!< RTC minute value: 0x0 - 0x59(BCD format) */
+    uint8_t rtc_second;                                                                /*!< RTC second value: 0x0 - 0x59(BCD format) */
+    uint16_t rtc_factor_asyn;                                                          /*!< RTC asynchronous prescaler value: 0x0 - 0x7F */
+    uint16_t rtc_factor_syn;                                                           /*!< RTC synchronous prescaler value: 0x0 - 0x7FFF */
+    uint32_t rtc_am_pm;                                                                /*!< RTC AM/PM value */
+    uint32_t rtc_display_format;                                                       /*!< RTC time notation */
+} rtc_parameter_struct;
+
+/* structure for RTC alarm configuration */
+typedef struct {
+    uint32_t rtc_alarm_mask;                                                           /*!< RTC alarm mask */
+    uint32_t rtc_weekday_or_date;                                                      /*!< specify RTC alarm is on date or weekday */
+    uint8_t rtc_alarm_day;                                                             /*!< RTC alarm date or weekday value*/
+    uint8_t rtc_alarm_hour;                                                            /*!< RTC alarm hour value */
+    uint8_t rtc_alarm_minute;                                                          /*!< RTC alarm minute value: 0x0 - 0x59(BCD format) */
+    uint8_t rtc_alarm_second;                                                          /*!< RTC alarm second value: 0x0 - 0x59(BCD format) */
+    uint32_t rtc_am_pm;                                                                /*!< RTC alarm AM/PM value */
+} rtc_alarm_struct;
+
+/* structure for RTC time-stamp configuration */
+typedef struct {
+    uint8_t rtc_timestamp_month;                                                       /*!< RTC time-stamp month value */
+    uint8_t rtc_timestamp_date;                                                        /*!< RTC time-stamp date value: 0x1 - 0x31(BCD format) */
+    uint8_t rtc_timestamp_day;                                                         /*!< RTC time-stamp weekday value */
+    uint8_t rtc_timestamp_hour;                                                        /*!< RTC time-stamp hour value */
+    uint8_t rtc_timestamp_minute;                                                      /*!< RTC time-stamp minute value: 0x0 - 0x59(BCD format) */
+    uint8_t rtc_timestamp_second;                                                      /*!< RTC time-stamp second value: 0x0 - 0x59(BCD format) */
+    uint32_t rtc_am_pm;                                                                /*!< RTC time-stamp AM/PM value */
+} rtc_timestamp_struct;
+
+/* structure for RTC tamper configuration */
+typedef struct {
+    uint32_t rtc_tamper_source;                                                        /*!< RTC tamper source */
+    uint32_t rtc_tamper_trigger;                                                       /*!< RTC tamper trigger */
+    uint32_t rtc_tamper_filter;                                                        /*!< RTC tamper consecutive samples needed during a voltage level detection */
+    uint32_t rtc_tamper_sample_frequency;                                              /*!< RTC tamper sampling frequency during a voltage level detection */
+    ControlStatus
+    rtc_tamper_precharge_enable;                                         /*!< RTC tamper precharge feature during a voltage level detection */
+    uint32_t rtc_tamper_precharge_time;                                                /*!< RTC tamper precharge duration if precharge feature is enabled */
+    ControlStatus rtc_tamper_with_timestamp;                                           /*!< RTC tamper time-stamp feature */
+} rtc_tamper_struct;
+
+/* time register value */
+#define TIME_SC(regval)                    (BITS(0,6) & ((uint32_t)(regval) << 0U))    /*!< write value to RTC_TIME_SC bit field */
+#define GET_TIME_SC(regval)                GET_BITS((regval),0,6)                      /*!< get value of RTC_TIME_SC bit field */
+
+#define TIME_MN(regval)                    (BITS(8,14) & ((uint32_t)(regval) << 8U))   /*!< write value to RTC_TIME_MN bit field */
+#define GET_TIME_MN(regval)                GET_BITS((regval),8,14)                     /*!< get value of RTC_TIME_MN bit field */
+
+#define TIME_HR(regval)                    (BITS(16,21) & ((uint32_t)(regval) << 16U)) /*!< write value to RTC_TIME_HR bit field */
+#define GET_TIME_HR(regval)                GET_BITS((regval),16,21)                    /*!< get value of RTC_TIME_HR bit field */
+
+#define RTC_AM                             ((uint32_t)0x00000000U)                     /*!< AM format */
+#define RTC_PM                             RTC_TIME_PM                                 /*!< PM format */
+
+/* date register value */
+#define DATE_DAY(regval)                   (BITS(0,5) & ((uint32_t)(regval) << 0U))    /*!< write value to RTC_DATE_DAY bit field */
+#define GET_DATE_DAY(regval)               GET_BITS((regval),0,5)                      /*!< get value of RTC_DATE_DAY bit field */
+
+#define DATE_MON(regval)                   (BITS(8,12) & ((uint32_t)(regval) << 8U))   /*!< write value to RTC_DATE_MON bit field */
+#define GET_DATE_MON(regval)               GET_BITS((regval),8,12)                     /*!< get value of RTC_DATE_MON bit field */
+#define RTC_JAN                            ((uint8_t)0x01U)                            /*!< Janurary */
+#define RTC_FEB                            ((uint8_t)0x02U)                            /*!< February */
+#define RTC_MAR                            ((uint8_t)0x03U)                            /*!< March */
+#define RTC_APR                            ((uint8_t)0x04U)                            /*!< April */
+#define RTC_MAY                            ((uint8_t)0x05U)                            /*!< May */
+#define RTC_JUN                            ((uint8_t)0x06U)                            /*!< June */
+#define RTC_JUL                            ((uint8_t)0x07U)                            /*!< July */
+#define RTC_AUG                            ((uint8_t)0x08U)                            /*!< August */
+#define RTC_SEP                            ((uint8_t)0x09U)                            /*!< September */
+#define RTC_OCT                            ((uint8_t)0x10U)                            /*!< October */
+#define RTC_NOV                            ((uint8_t)0x11U)                            /*!< November */
+#define RTC_DEC                            ((uint8_t)0x12U)                            /*!< December */
+
+#define DATE_DOW(regval)                   (BITS(13,15) & ((uint32_t)(regval) << 13U)) /*!< write value to RTC_DATE_DOW bit field */
+#define GET_DATE_DOW(regval)               GET_BITS((regval),13,15)                    /*!< get value of RTC_DATE_DOW bit field */
+#define RTC_MONDAY                         ((uint8_t)0x01U)                            /*!< Monday */
+#define RTC_TUESDAY                        ((uint8_t)0x02U)                            /*!< Tuesday */
+#define RTC_WEDSDAY                        ((uint8_t)0x03U)                            /*!< Wednesday */
+#define RTC_THURSDAY                       ((uint8_t)0x04U)                            /*!< Thursday */
+#define RTC_FRIDAY                         ((uint8_t)0x05U)                            /*!< Friday */
+#define RTC_SATURDAY                       ((uint8_t)0x06U)                            /*!< Saturday */
+#define RTC_SUNDAY                         ((uint8_t)0x07U)                            /*!< Sunday */
+
+#define DATE_YR(regval)                    (BITS(16,23) & ((uint32_t)(regval) << 16U)) /*!< write value to RTC_DATE_YR bit field */
+#define GET_DATE_YR(regval)                GET_BITS((regval),16,23)                    /*!< get value of RTC_DATE_YR bit field */
+
+/* ctl register value */
+#define CTL_OS(regval)                     (BITS(21,22) & ((uint32_t)(regval) << 21U)) /*!< write value to RTC_CTL_OS bit field */
+#define RTC_OS_DISABLE                     CTL_OS(0)                                   /*!< disable output RTC_ALARM */
+#define RTC_OS_ENABLE                      CTL_OS(1)                                   /*!< enable alarm flag output */
+
+#define RTC_CALIBRATION_512HZ              RTC_CTL_COEN                                /*!< calibration output of 512Hz is enable */
+#define RTC_CALIBRATION_1HZ                RTC_CTL_COEN | RTC_CTL_COS                  /*!< calibration output of 1Hz is enable */
+#define RTC_ALARM_HIGH                     RTC_OS_ENABLE                               /*!< enable alarm flag output with high level */
+#define RTC_ALARM_LOW                      RTC_OS_ENABLE | RTC_CTL_OPOL                /*!< enable alarm flag output with low level*/
+
+#define RTC_24HOUR                         ((uint32_t)0x00000000U)                     /*!< 24-hour format */
+#define RTC_12HOUR                         RTC_CTL_CS                                  /*!< 12-hour format */
+
+#define RTC_TIMESTAMP_RISING_EDGE          ((uint32_t)0x00000000U)                     /*!< rising edge is valid event edge for time-stamp event */
+#define RTC_TIMESTAMP_FALLING_EDGE         RTC_CTL_TSEG                                /*!< falling edge is valid event edge for time-stamp event */
+
+/* psc register value */
+#define PSC_FACTOR_S(regval)               (BITS(0,14) & ((uint32_t)(regval) << 0U))   /*!< write value to RTC_PSC_FACTOR_S bit field */
+#define GET_PSC_FACTOR_S(regval)           GET_BITS((regval),0,14)                     /*!< get value of RTC_PSC_FACTOR_S bit field */
+
+#define PSC_FACTOR_A(regval)               (BITS(16,22) & ((uint32_t)(regval) << 16U)) /*!< write value to RTC_PSC_FACTOR_A bit field */
+#define GET_PSC_FACTOR_A(regval)           GET_BITS((regval),16,22)                    /*!< get value of RTC_PSC_FACTOR_A bit field */
+
+/* alrm0td register value */
+#define ALRM0TD_SC(regval)                 (BITS(0,6) & ((uint32_t)(regval)<< 0U))     /*!< write value to RTC_ALRM0TD_SC bit field */
+#define GET_ALRM0TD_SC(regval)             GET_BITS((regval),0,6)                      /*!< get value of RTC_ALRM0TD_SC bit field */
+
+#define ALRM0TD_MN(regval)                 (BITS(8,14) & ((uint32_t)(regval) << 8U))   /*!< write value to RTC_ALRM0TD_MN bit field */
+#define GET_ALRM0TD_MN(regval)             GET_BITS((regval),8,14)                     /*!< get value of RTC_ALRM0TD_MN bit field */
+
+#define ALRM0TD_HR(regval)                 (BITS(16,21) & ((uint32_t)(regval) << 16U)) /*!< write value to RTC_ALRM0TD_HR bit field */
+#define GET_ALRM0TD_HR(regval)             GET_BITS((regval),16,21)                    /*!< get value of RTC_ALRM0TD_HR bit field */
+
+#define ALRM0TD_DAY(regval)                (BITS(24,29) & ((uint32_t)(regval) << 24U)) /*!< write value to RTC_ALRM0TD_DAY bit field */
+#define GET_ALRM0TD_DAY(regval)            GET_BITS((regval),24,29)                    /*!< get value of RTC_ALRM0TD_DAY bit field */
+
+#define RTC_ALARM_NONE_MASK                ((uint32_t)0x00000000U)                     /*!< alarm none mask */
+#define RTC_ALARM_DATE_MASK                RTC_ALRM0TD_MSKD                            /*!< alarm date mask */
+#define RTC_ALARM_HOUR_MASK                RTC_ALRM0TD_MSKH                            /*!< alarm hour mask */
+#define RTC_ALARM_MINUTE_MASK              RTC_ALRM0TD_MSKM                            /*!< alarm minute mask */
+#define RTC_ALARM_SECOND_MASK              RTC_ALRM0TD_MSKS                            /*!< alarm second mask */
+#define RTC_ALARM_ALL_MASK                 (RTC_ALRM0TD_MSKD|RTC_ALRM0TD_MSKH|RTC_ALRM0TD_MSKM|RTC_ALRM0TD_MSKS)    /*!< alarm all mask */
+
+#define RTC_ALARM_DATE_SELECTED            ((uint32_t)0x00000000U)                     /*!< alarm date format selected */
+#define RTC_ALARM_WEEKDAY_SELECTED         RTC_ALRM0TD_DOWS                            /*!< alarm weekday format selected */
+
+/* wpk register value */
+#define WPK_WPK(regval)                    (BITS(0,7) & ((uint32_t)(regval) << 0U))     /*!< write value to RTC_WPK_WPK bit field */
+
+/* ss register value */
+#define SS_SSC(regval)                     (BITS(0,15) & ((uint32_t)(regval) << 0U))    /*!< write value to RTC_SS_SSC bit field */
+
+/* shiftctl register value */
+#define SHIFTCTL_SFS(regval)               (BITS(0,14) & ((uint32_t)(regval) << 0U))   /*!< write value to RTC_SHIFTCTL_SFS bit field */
+
+#define RTC_SHIFT_ADD1S_RESET              ((uint32_t)0x00000000U)                     /*!< not add 1 second */
+#define RTC_SHIFT_ADD1S_SET                RTC_SHIFTCTL_A1S                            /*!< add one second to the clock */
+
+/* tts register value */
+#define TTS_SC(regval)                     (BITS(0,6) & ((uint32_t)(regval) << 0U))    /*!< write value to RTC_TTS_SC bit field */
+#define GET_TTS_SC(regval)                 GET_BITS((regval),0,6)                      /*!< get value of RTC_TTS_SC bit field */
+
+#define TTS_MN(regval)                     (BITS(8,14) & ((uint32_t)(regval) << 8U))   /*!< write value to RTC_TTS_MN bit field */
+#define GET_TTS_MN(regval)                 GET_BITS((regval),8,14)                     /*!< get value of RTC_TTS_MN bit field */
+
+#define TTS_HR(regval)                     (BITS(16,21) & ((uint32_t)(regval) << 16U)) /*!< write value to RTC_TTS_HR bit field */
+#define GET_TTS_HR(regval)                 GET_BITS((regval),16,21)                    /*!< get value of RTC_TTS_HR bit field */
+
+/* dts register value */
+#define DTS_DAY(regval)                    (BITS(0,5) & ((uint32_t)(regval) << 0U))    /*!< write value to RTC_DTS_DAY bit field */
+#define GET_DTS_DAY(regval)                GET_BITS((regval),0,5)                      /*!< get value of RTC_DTS_DAY bit field */
+
+#define DTS_MON(regval)                    (BITS(8,12) & ((uint32_t)(regval) << 8U))   /*!< write value to RTC_DTS_MON bit field */
+#define GET_DTS_MON(regval)                GET_BITS((regval),8,12)                     /*!< get value of RTC_DTS_MON bit field */
+
+#define DTS_DOW(regval)                    (BITS(13,15) & ((uint32_t)(regval) << 13U)) /*!< write value to RTC_DTS_DOW bit field */
+#define GET_DTS_DOW(regval)                GET_BITS((regval),13,15)                    /*!< get value of RTC_DTS_DOW bit field */
+
+/* ssts register value */
+#define SSTS_SSC(regval)                   (BITS(0,15) & ((uint32_t)(regval) << 0U))   /*!< write value to RTC_SSTS_SSC bit field */
+
+/* hrfc register value */
+#define HRFC_CMSK(regval)                  (BITS(0,8) & ((uint32_t)(regval) << 0U))    /*!< write value to RTC_HRFC_CMSK bit field */
+
+#define RTC_CALIBRATION_WINDOW_32S         ((uint32_t)0x00000000U)                     /*!< 2exp20 RTCCLK cycles, 32s if RTCCLK = 32768 Hz */
+#define RTC_CALIBRATION_WINDOW_16S         RTC_HRFC_CWND16                             /*!< 2exp19 RTCCLK cycles, 16s if RTCCLK = 32768 Hz */
+#define RTC_CALIBRATION_WINDOW_8S          RTC_HRFC_CWND8                              /*!< 2exp18 RTCCLK cycles, 8s if RTCCLK = 32768 Hz */
+
+#define RTC_CALIBRATION_PLUS_SET           RTC_HRFC_FREQI                              /*!< increase RTC frequency by 488.5ppm */
+#define RTC_CALIBRATION_PLUS_RESET         ((uint32_t)0x00000000U)                     /*!< no effect */
+
+/* tamp register value */
+#define TAMP_FREQ(regval)                  (BITS(8,10) & ((uint32_t)(regval) << 8U))   /*!< write value to RTC_TAMP_FREQ bit field */
+#define RTC_FREQ_DIV32768                  TAMP_FREQ(0)                                /*!< sample once every 32768 RTCCLK(1Hz if RTCCLK=32.768KHz) */
+#define RTC_FREQ_DIV16384                  TAMP_FREQ(1)                                /*!< sample once every 16384 RTCCLK(2Hz if RTCCLK=32.768KHz) */
+#define RTC_FREQ_DIV8192                   TAMP_FREQ(2)                                /*!< sample once every 8192 RTCCLK(4Hz if RTCCLK=32.768KHz) */
+#define RTC_FREQ_DIV4096                   TAMP_FREQ(3)                                /*!< sample once every 4096 RTCCLK(8Hz if RTCCLK=32.768KHz) */
+#define RTC_FREQ_DIV2048                   TAMP_FREQ(4)                                /*!< sample once every 2048 RTCCLK(16Hz if RTCCLK=32.768KHz) */
+#define RTC_FREQ_DIV1024                   TAMP_FREQ(5)                                /*!< sample once every 1024 RTCCLK(32Hz if RTCCLK=32.768KHz) */
+#define RTC_FREQ_DIV512                    TAMP_FREQ(6)                                /*!< sample once every 512 RTCCLK(64Hz if RTCCLK=32.768KHz) */
+#define RTC_FREQ_DIV256                    TAMP_FREQ(7)                                /*!< sample once every 256 RTCCLK(128Hz if RTCCLK=32.768KHz) */
+
+#define TAMP_FLT(regval)                   (BITS(11,12) & ((uint32_t)(regval) << 11U))  /*!< write value to RTC_TAMP_FLT bit field */
+#define RTC_FLT_EDGE                       TAMP_FLT(0)                                 /*!< detecting tamper event using edge mode. precharge duration is disabled automatically */
+#define RTC_FLT_2S                         TAMP_FLT(1)                                 /*!< detecting tamper event using level mode.2 consecutive valid level samples will make a effective tamper event  */
+#define RTC_FLT_4S                         TAMP_FLT(2)                                 /*!< detecting tamper event using level mode.4 consecutive valid level samples will make an effective tamper event */
+#define RTC_FLT_8S                         TAMP_FLT(3)                                 /*!< detecting tamper event using level mode.8 consecutive valid level samples will make a effective tamper event  */
+
+#define TAMP_PRCH(regval)                  (BITS(13,14) & ((uint32_t)(regval) << 13U)) /*!< write value to RTC_TAMP_PRCH bit field */
+#define RTC_PRCH_1C                        TAMP_PRCH(0)                                /*!< 1 RTC clock prechagre time before each sampling */
+#define RTC_PRCH_2C                        TAMP_PRCH(1)                                /*!< 2 RTC clock prechagre time before each sampling  */
+#define RTC_PRCH_4C                        TAMP_PRCH(2)                                /*!< 4 RTC clock prechagre time before each sampling */
+#define RTC_PRCH_8C                        TAMP_PRCH(3)                                /*!< 8 RTC clock prechagre time before each sampling */
+
+#define RTC_TAMPER0                        RTC_TAMP_TP0EN                              /*!< tamper 0 detection enable */
+#define RTC_TAMPER1                        RTC_TAMP_TP1EN                              /*!< tamper 1 detection enable */
+
+#define RTC_TAMPER_TRIGGER_EDGE_RISING     ((uint32_t)0x00000000U)                     /*!< tamper detection is in rising edge mode */
+#define RTC_TAMPER_TRIGGER_EDGE_FALLING    RTC_TAMP_TP0EG                              /*!< tamper detection is in falling edge mode */
+#define RTC_TAMPER_TRIGGER_LEVEL_LOW       ((uint32_t)0x00000000U)                     /*!< tamper detection is in low level mode */
+#define RTC_TAMPER_TRIGGER_LEVEL_HIGH      RTC_TAMP_TP0EG                              /*!< tamper detection is in high level mode */
+
+#define RTC_TAMPER_TRIGGER_POS             ((uint32_t)0x00000001U)                     /* shift position of trigger relative to source */
+
+#define RTC_ALARM_OUTPUT_OD                ((uint32_t)0x00000000U)                     /*!< RTC alarm output open-drain mode */
+#define RTC_ALARM_OUTPUT_PP                RTC_TAMP_PC13VAL                            /*!< RTC alarm output push-pull mode */
+
+/* alrm0ss register value */
+#define ALRM0SS_SSC(regval)                (BITS(0,14) & ((uint32_t)(regval)<< 0U))    /*!< write value to RTC_ALRM0SS_SSC bit field */
+
+#define ALRM0SS_MASKSSC(regval)            (BITS(24,27) & ((uint32_t)(regval) << 24U)) /*!< write value to RTC_ALRM0SS_MASKSSC bit field */
+#define RTC_MASKSSC_0_14                   ALRM0SS_MASKSSC(0)                          /*!< mask alarm subsecond configuration */
+#define RTC_MASKSSC_1_14                   ALRM0SS_MASKSSC(1)                          /*!< mask RTC_ALRM0SS_SSC[14:1], and RTC_ALRM0SS_SSC[0] is to be compared */
+#define RTC_MASKSSC_2_14                   ALRM0SS_MASKSSC(2)                          /*!< mask RTC_ALRM0SS_SSC[14:2], and RTC_ALRM0SS_SSC[1:0] is to be compared */
+#define RTC_MASKSSC_3_14                   ALRM0SS_MASKSSC(3)                          /*!< mask RTC_ALRM0SS_SSC[14:3], and RTC_ALRM0SS_SSC[2:0] is to be compared */
+#define RTC_MASKSSC_4_14                   ALRM0SS_MASKSSC(4)                          /*!< mask RTC_ALRM0SS_SSC[14:4], and RTC_ALRM0SS_SSC[3:0] is to be compared */
+#define RTC_MASKSSC_5_14                   ALRM0SS_MASKSSC(5)                          /*!< mask RTC_ALRM0SS_SSC[14:5], and RTC_ALRM0SS_SSC[4:0] is to be compared */
+#define RTC_MASKSSC_6_14                   ALRM0SS_MASKSSC(6)                          /*!< mask RTC_ALRM0SS_SSC[14:6], and RTC_ALRM0SS_SSC[5:0] is to be compared */
+#define RTC_MASKSSC_7_14                   ALRM0SS_MASKSSC(7)                          /*!< mask RTC_ALRM0SS_SSC[14:7], and RTC_ALRM0SS_SSC[6:0] is to be compared */
+#define RTC_MASKSSC_8_14                   ALRM0SS_MASKSSC(8)                          /*!< mask RTC_ALRM0SS_SSC[14:8], and RTC_ALRM0SS_SSC[7:0] is to be compared */
+#define RTC_MASKSSC_9_14                   ALRM0SS_MASKSSC(9)                          /*!< mask RTC_ALRM0SS_SSC[14:9], and RTC_ALRM0SS_SSC[8:0] is to be compared */
+#define RTC_MASKSSC_10_14                  ALRM0SS_MASKSSC(10)                         /*!< mask RTC_ALRM0SS_SSC[14:10], and RTC_ALRM0SS_SSC[9:0] is to be compared */
+#define RTC_MASKSSC_11_14                  ALRM0SS_MASKSSC(11)                         /*!< mask RTC_ALRM0SS_SSC[14:11], and RTC_ALRM0SS_SSC[10:0] is to be compared */
+#define RTC_MASKSSC_12_14                  ALRM0SS_MASKSSC(12)                         /*!< mask RTC_ALRM0SS_SSC[14:12], and RTC_ALRM0SS_SSC[11:0] is to be compared */
+#define RTC_MASKSSC_13_14                  ALRM0SS_MASKSSC(13)                         /*!< mask RTC_ALRM0SS_SSC[14:13], and RTC_ALRM0SS_SSC[12:0] is to be compared */
+#define RTC_MASKSSC_14                     ALRM0SS_MASKSSC(14)                         /*!< mask RTC_ALRM0SS_SSC[14], and RTC_ALRM0SS_SSC[13:0] is to be compared */
+#define RTC_MASKSSC_NONE                   ALRM0SS_MASKSSC(15)                         /*!< mask none, and RTC_ALRM0SS_SSC[14:0] is to be compared */
+
+/* RTC interrupt source */
+#define RTC_INT_TIMESTAMP                  RTC_CTL_TSIE                                /*!< time-stamp interrupt enable */
+#define RTC_INT_ALARM                      RTC_CTL_ALRM0IE                             /*!< RTC alarm interrupt enable */
+#define RTC_INT_TAMP                       RTC_TAMP_TPIE                               /*!< tamper detection interrupt enable */
+
+/* write protect key */
+#define RTC_UNLOCK_KEY1                    ((uint8_t)0xCAU)                            /*!< RTC unlock key1 */
+#define RTC_UNLOCK_KEY2                    ((uint8_t)0x53U)                            /*!< RTC unlock key2 */
+#define RTC_LOCK_KEY                       ((uint8_t)0xFFU)                            /*!< RTC lock key */
+
+/* registers reset value */
+#define RTC_REGISTER_RESET                 ((uint32_t)0x00000000U)                     /*!< RTC common register reset value */
+#define RTC_DATE_RESET                     ((uint32_t)0x00002101U)                     /*!< RTC_DATE register reset value */
+#define RTC_STAT_RESET                     ((uint32_t)0x00000007U)                     /*!< RTC_STAT register reset value */
+#define RTC_PSC_RESET                      ((uint32_t)0x007F00FFU)                     /*!< RTC_PSC register reset value */
+
+/* RTC timeout value */
+#define RTC_INITM_TIMEOUT                  ((uint32_t)0x00004000U)                     /*!< initialization state flag timeout */
+#define RTC_RSYNF_TIMEOUT                  ((uint32_t)0x00008000U)                     /*!< register synchronization flag timeout */
+#define RTC_HRFC_TIMEOUT                   ((uint32_t)0x00001000U)                     /*!< recalibration pending flag timeout */
+#define RTC_SHIFTCTL_TIMEOUT               ((uint32_t)0x00001000U)                     /*!< shift function operation pending flag timeout */
+#define RTC_ALRM0WF_TIMEOUT                ((uint32_t)0x00008000U)                     /*!< alarm configuration can be write flag timeout */
+
+/* RTC flag */
+#define RTC_FLAG_RECALIBRATION             RTC_STAT_SCPF                               /*!< recalibration pending flag */
+#define RTC_FLAG_TAMP1                     RTC_STAT_TP1F                               /*!< tamper 1 event flag */
+#define RTC_FLAG_TAMP0                     RTC_STAT_TP0F                               /*!< tamper 0 event flag */
+#define RTC_FLAG_TIMESTAMP_OVERFLOW        RTC_STAT_TSOVRF                             /*!< time-stamp overflow event flag */
+#define RTC_FLAG_TIMESTAMP                 RTC_STAT_TSF                                /*!< time-stamp event flag */
+#define RTC_FLAG_ALARM0                    RTC_STAT_ALRM0F                             /*!< alarm event flag */
+#define RTC_FLAG_INIT                      RTC_STAT_INITF                              /*!< init mode event flag */
+#define RTC_FLAG_RSYN                      RTC_STAT_RSYNF                              /*!< registers synchronized flag */
+#define RTC_FLAG_YCM                       RTC_STAT_YCM                                /*!< year parameter configured event flag */
+#define RTC_FLAG_SHIFT                     RTC_STAT_SOPF                               /*!< shift operation pending flag */
+#define RTC_FLAG_ALARM0_WRITTEN            RTC_STAT_ALRM0WF                            /*!< alarm written available flag */
+
+/* function declarations */
+/* reset most of the RTC registers */
+ErrStatus rtc_deinit(void);
+/* initialize RTC registers */
+ErrStatus rtc_init(rtc_parameter_struct *rtc_initpara_struct);
+/* enter RTC init mode */
+ErrStatus rtc_init_mode_enter(void);
+/* exit RTC init mode */
+void rtc_init_mode_exit(void);
+/* wait until RTC_TIME and RTC_DATE registers are synchronized with APB clock, and the shadow registers are updated */
+ErrStatus rtc_register_sync_wait(void);
+
+/* get current time and date */
+void rtc_current_time_get(rtc_parameter_struct *rtc_initpara_struct);
+/* get current subsecond value */
+uint32_t rtc_subsecond_get(void);
+
+/* configure RTC alarm */
+void rtc_alarm_config(rtc_alarm_struct *rtc_alarm_time);
+/* configure subsecond of RTC alarm */
+void rtc_alarm_subsecond_config(uint32_t mask_subsecond, uint32_t subsecond);
+/* get RTC alarm */
+void rtc_alarm_get(rtc_alarm_struct *rtc_alarm_time);
+/* get RTC alarm subsecond */
+uint32_t rtc_alarm_subsecond_get(void);
+/* enable RTC alarm */
+void rtc_alarm_enable(void);
+/* disable RTC alarm */
+ErrStatus rtc_alarm_disable(void);
+
+/* enable RTC time-stamp */
+void rtc_timestamp_enable(uint32_t edge);
+/* disable RTC time-stamp */
+void rtc_timestamp_disable(void);
+/* get RTC timestamp time and date */
+void rtc_timestamp_get(rtc_timestamp_struct *rtc_timestamp);
+/* get RTC time-stamp subsecond */
+uint32_t rtc_timestamp_subsecond_get(void);
+
+/* enable RTC tamper */
+void rtc_tamper_enable(rtc_tamper_struct *rtc_tamper);
+/* disable RTC tamper */
+void rtc_tamper_disable(uint32_t source);
+
+/* enable specified RTC interrupt */
+void rtc_interrupt_enable(uint32_t interrupt);
+/* disble specified RTC interrupt */
+void rtc_interrupt_disable(uint32_t interrupt);
+/* check specified flag */
+FlagStatus rtc_flag_get(uint32_t flag);
+/* clear specified flag */
+void rtc_flag_clear(uint32_t flag);
+
+/* configure RTC alternate output source */
+void rtc_alter_output_config(uint32_t source, uint32_t mode);
+/* configure RTC calibration register */
+ErrStatus rtc_calibration_config(uint32_t window, uint32_t plus, uint32_t minus);
+/* ajust the daylight saving time by adding or substracting one hour from the current time */
+void rtc_hour_adjust(uint32_t operation);
+/* ajust RTC second or subsecond value of current time */
+ErrStatus rtc_second_adjust(uint32_t add, uint32_t minus);
+/* enable RTC bypass shadow registers function */
+void rtc_bypass_shadow_enable(void);
+/* disable RTC bypass shadow registers function */
+void rtc_bypass_shadow_disable(void);
+/* enable RTC reference clock detection function */
+ErrStatus rtc_refclock_detection_enable(void);
+/* disable RTC reference clock detection function */
+ErrStatus rtc_refclock_detection_disable(void);
+
+#endif /* GD32F3X0_RTC_H */

+ 371 - 0
GD32F3x0/GD32F3x0_standard_peripheral/Include/gd32f3x0_spi.h

@@ -0,0 +1,371 @@
+/*!
+    \file    gd32f3x0_spi.h
+    \brief   definitions for the SPI
+
+    \version 2025-01-01, V2.5.0, firmware for GD32F3x0
+*/
+
+/*
+    Copyright (c) 2025, GigaDevice Semiconductor Inc.
+
+    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 of the copyright holder 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 HOLDER 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.
+*/
+
+#ifndef GD32F3X0_SPI_H
+#define GD32F3X0_SPI_H
+
+#include "gd32f3x0.h"
+
+/* SPIx(x=0,1) definitions */
+#define SPI0                            (SPI_BASE + 0x0000F800U)
+#define SPI1                            SPI_BASE
+
+/* registers definitions */
+#define SPI_CTL0(spix)                  REG32((spix) + 0x00000000U)             /*!< SPI control register 0 */
+#define SPI_CTL1(spix)                  REG32((spix) + 0x00000004U)             /*!< SPI control register 1*/
+#define SPI_STAT(spix)                  REG32((spix) + 0x00000008U)             /*!< SPI status register */
+#define SPI_DATA(spix)                  REG32((spix) + 0x0000000CU)             /*!< SPI data register */
+#define SPI_CRCPOLY(spix)               REG32((spix) + 0x00000010U)             /*!< SPI CRC polynomial register */
+#define SPI_RCRC(spix)                  REG32((spix) + 0x00000014U)             /*!< SPI receive CRC register */
+#define SPI_TCRC(spix)                  REG32((spix) + 0x00000018U)             /*!< SPI transmit CRC register */
+#define SPI_I2SCTL(spix)                REG32((spix) + 0x0000001CU)             /*!< SPI I2S control register */
+#define SPI_I2SPSC(spix)                REG32((spix) + 0x00000020U)             /*!< SPI I2S clock prescaler register */
+#define SPI_QCTL(spix)                  REG32((spix) + 0x00000080U)             /*!< SPI quad mode control register(only available in SPI1) */
+
+/* bits definitions */
+/* SPI_CTL0 */
+#define SPI_CTL0_CKPH                   BIT(0)                                  /*!< clock phase selection */
+#define SPI_CTL0_CKPL                   BIT(1)                                  /*!< clock polarity selection */
+#define SPI_CTL0_MSTMOD                 BIT(2)                                  /*!< master mode enable */
+#define SPI_CTL0_PSC                    BITS(3,5)                               /*!< master clock prescaler selection */
+#define SPI_CTL0_SPIEN                  BIT(6)                                  /*!< SPI enable*/
+#define SPI_CTL0_LF                     BIT(7)                                  /*!< LSB first mode */
+#define SPI_CTL0_SWNSS                  BIT(8)                                  /*!< NSS pin selection in NSS software mode */
+#define SPI_CTL0_SWNSSEN                BIT(9)                                  /*!< NSS software mode selection */
+#define SPI_CTL0_RO                     BIT(10)                                 /*!< receive only */
+#define SPI_CTL0_FF16                   BIT(11)                                 /*!< data frame size */
+#define SPI_CTL0_CRCNT                  BIT(12)                                 /*!< CRC next transfer */
+#define SPI_CTL0_CRCEN                  BIT(13)                                 /*!< CRC calculation enable */
+#define SPI_CTL0_BDOEN                  BIT(14)                                 /*!< bidirectional transmit output enable*/
+#define SPI_CTL0_BDEN                   BIT(15)                                 /*!< bidirectional enable */
+
+/* SPI_CTL1 */
+#define SPI_CTL1_DMAREN                 BIT(0)                                  /*!< receive buffer DMA enable */
+#define SPI_CTL1_DMATEN                 BIT(1)                                  /*!< transmit buffer DMA enable */
+#define SPI_CTL1_NSSDRV                 BIT(2)                                  /*!< drive NSS output */
+#define SPI_CTL1_NSSP                   BIT(3)                                  /*!< SPI NSS pulse mode enable */
+#define SPI_CTL1_TMOD                   BIT(4)                                  /*!< SPI TI mode enable */
+#define SPI_CTL1_ERRIE                  BIT(5)                                  /*!< errors interrupt enable */
+#define SPI_CTL1_RBNEIE                 BIT(6)                                  /*!< receive buffer not empty interrupt enable */
+#define SPI_CTL1_TBEIE                  BIT(7)                                  /*!< transmit buffer empty interrupt enable */
+
+/* SPI_STAT */
+#define SPI_STAT_RBNE                   BIT(0)                                  /*!< receive buffer not empty */
+#define SPI_STAT_TBE                    BIT(1)                                  /*!< transmit buffer empty */
+#define SPI_STAT_I2SCH                  BIT(2)                                  /*!< I2S channel side */
+#define SPI_STAT_TXURERR                BIT(3)                                  /*!< I2S transmission underrun error bit */
+#define SPI_STAT_CRCERR                 BIT(4)                                  /*!< SPI CRC error bit */
+#define SPI_STAT_CONFERR                BIT(5)                                  /*!< SPI configuration error bit */
+#define SPI_STAT_RXORERR                BIT(6)                                  /*!< SPI reception overrun error bit */
+#define SPI_STAT_TRANS                  BIT(7)                                  /*!< transmitting on-going bit */
+#define SPI_STAT_FERR                   BIT(8)                                  /*!< format error bit */
+
+/* SPI_DATA */
+#define SPI_DATA_DATA                   BITS(0,15)                              /*!< data transfer register */
+
+/* SPI_CRCPOLY */
+#define SPI_CRCPOLY_CRCPOLY             BITS(0,15)                              /*!< CRC polynomial value */
+
+/* SPI_RCRC */
+#define SPI_RCRC_RCRC                   BITS(0,15)                              /*!< RX CRC value */
+
+/* SPI_TCRC */
+#define SPI_TCRC_TCRC                   BITS(0,15)                              /*!< TX CRC value */
+
+/* SPI_I2SCTL */
+#define SPI_I2SCTL_CHLEN                BIT(0)                                  /*!< channel length */
+#define SPI_I2SCTL_DTLEN                BITS(1,2)                               /*!< data length */
+#define SPI_I2SCTL_CKPL                 BIT(3)                                  /*!< idle state clock polarity */
+#define SPI_I2SCTL_I2SSTD               BITS(4,5)                               /*!< I2S standard selection */
+#define SPI_I2SCTL_PCMSMOD              BIT(7)                                  /*!< PCM frame synchronization mode */
+#define SPI_I2SCTL_I2SOPMOD             BITS(8,9)                               /*!< I2S operation mode */
+#define SPI_I2SCTL_I2SEN                BIT(10)                                 /*!< I2S enable */
+#define SPI_I2SCTL_I2SSEL               BIT(11)                                 /*!< I2S mode selection */
+
+/* SPI_I2SPSC */
+#define SPI_I2SPSC_DIV                  BITS(0,7)                               /*!< dividing factor for the prescaler */
+#define SPI_I2SPSC_OF                   BIT(8)                                  /*!< odd factor for the prescaler */
+#define SPI_I2SPSC_MCKOEN               BIT(9)                                  /*!< I2S MCK output enable */
+
+/* SPI_QCTL(only available in SPI1) */
+#define SPI_QCTL_QMOD                   BIT(0)                                  /*!< quad-SPI mode enable */
+#define SPI_QCTL_QRD                    BIT(1)                                  /*!< quad-SPI mode read select */
+#define SPI_QCTL_IO23_DRV               BIT(2)                                  /*!< drive SPI_IO2 and SPI_IO3 enable */
+
+/* constants definitions */
+/* SPI and I2S parameter struct definitions */
+typedef struct {
+    uint32_t device_mode;                                                       /*!< SPI master or slave */
+    uint32_t trans_mode;                                                        /*!< SPI transfer type */
+    uint32_t frame_size;                                                        /*!< SPI frame size */
+    uint32_t nss;                                                               /*!< SPI NSS control by handware or software */
+    uint32_t endian;                                                            /*!< SPI big endian or little endian */
+    uint32_t clock_polarity_phase;                                              /*!< SPI clock phase and polarity */
+    uint32_t prescale;                                                          /*!< SPI prescaler factor */
+} spi_parameter_struct;
+
+/* SPI mode definitions */
+#define SPI_MASTER                      (SPI_CTL0_MSTMOD | SPI_CTL0_SWNSS)      /*!< SPI as master */
+#define SPI_SLAVE                       ((uint32_t)0x00000000U)                 /*!< SPI as slave */
+
+/* SPI bidirectional transfer direction */
+#define SPI_BIDIRECTIONAL_TRANSMIT      SPI_CTL0_BDOEN                          /*!< SPI work in transmit-only mode */
+#define SPI_BIDIRECTIONAL_RECEIVE       (~SPI_CTL0_BDOEN)                       /*!< SPI work in receive-only mode */
+
+/* SPI transmit type */
+#define SPI_TRANSMODE_FULLDUPLEX        ((uint32_t)0x00000000U)                 /*!< SPI receive and send data at fullduplex communication */
+#define SPI_TRANSMODE_RECEIVEONLY       SPI_CTL0_RO                             /*!< SPI only receive data */
+#define SPI_TRANSMODE_BDRECEIVE         SPI_CTL0_BDEN                           /*!< bidirectional receive data */
+#define SPI_TRANSMODE_BDTRANSMIT        (SPI_CTL0_BDEN | SPI_CTL0_BDOEN)        /*!< bidirectional transmit data*/
+
+/* SPI frame size */
+#define SPI_FRAMESIZE_16BIT             SPI_CTL0_FF16                           /*!< SPI frame size is 16 bits */
+#define SPI_FRAMESIZE_8BIT              ((uint32_t)0x00000000U)                 /*!< SPI frame size is 8 bits */
+
+/* SPI NSS control mode */
+#define SPI_NSS_SOFT                    SPI_CTL0_SWNSSEN                        /*!< SPI NSS control by sofrware */
+#define SPI_NSS_HARD                    ((uint32_t)0x00000000U)                 /*!< SPI NSS control by hardware */
+
+/* SPI transmit way */
+#define SPI_ENDIAN_MSB                  ((uint32_t)0x00000000U)                 /*!< SPI transmit way is big endian: transmit MSB first */
+#define SPI_ENDIAN_LSB                  SPI_CTL0_LF                             /*!< SPI transmit way is little endian: transmit LSB first */
+
+/* SPI clock phase and polarity */
+#define SPI_CK_PL_LOW_PH_1EDGE          ((uint32_t)0x00000000U)                 /*!< SPI clock polarity is low level and phase is first edge */
+#define SPI_CK_PL_HIGH_PH_1EDGE         SPI_CTL0_CKPL                           /*!< SPI clock polarity is high level and phase is first edge */
+#define SPI_CK_PL_LOW_PH_2EDGE          SPI_CTL0_CKPH                           /*!< SPI clock polarity is low level and phase is second edge */
+#define SPI_CK_PL_HIGH_PH_2EDGE         (SPI_CTL0_CKPL | SPI_CTL0_CKPH)         /*!< SPI clock polarity is high level and phase is second edge */
+
+/* SPI clock prescaler factor */
+#define CTL0_PSC(regval)                (BITS(3,5) & ((uint32_t)(regval) << 3))
+#define SPI_PSC_2                       CTL0_PSC(0)                             /*!< SPI clock prescaler factor is 2 */
+#define SPI_PSC_4                       CTL0_PSC(1)                             /*!< SPI clock prescaler factor is 4 */
+#define SPI_PSC_8                       CTL0_PSC(2)                             /*!< SPI clock prescaler factor is 8 */
+#define SPI_PSC_16                      CTL0_PSC(3)                             /*!< SPI clock prescaler factor is 16 */
+#define SPI_PSC_32                      CTL0_PSC(4)                             /*!< SPI clock prescaler factor is 32 */
+#define SPI_PSC_64                      CTL0_PSC(5)                             /*!< SPI clock prescaler factor is 64 */
+#define SPI_PSC_128                     CTL0_PSC(6)                             /*!< SPI clock prescaler factor is 128 */
+#define SPI_PSC_256                     CTL0_PSC(7)                             /*!< SPI clock prescaler factor is 256 */
+
+#if (defined(GD32F370) || defined(GD32F355) || defined(GD32F350) || defined(GD32F310))
+/* I2S audio sample rate */
+#define I2S_AUDIOSAMPLE_8K              ((uint32_t)8000U)                       /*!< I2S audio sample rate is 8KHz */
+#define I2S_AUDIOSAMPLE_11K             ((uint32_t)11025U)                      /*!< I2S audio sample rate is 11KHz */
+#define I2S_AUDIOSAMPLE_16K             ((uint32_t)16000U)                      /*!< I2S audio sample rate is 16KHz */
+#define I2S_AUDIOSAMPLE_22K             ((uint32_t)22050U)                      /*!< I2S audio sample rate is 22KHz */
+#define I2S_AUDIOSAMPLE_32K             ((uint32_t)32000U)                      /*!< I2S audio sample rate is 32KHz */
+#define I2S_AUDIOSAMPLE_44K             ((uint32_t)44100U)                      /*!< I2S audio sample rate is 44KHz */
+#define I2S_AUDIOSAMPLE_48K             ((uint32_t)48000U)                      /*!< I2S audio sample rate is 48KHz */
+#define I2S_AUDIOSAMPLE_96K             ((uint32_t)96000U)                      /*!< I2S audio sample rate is 96KHz */
+#define I2S_AUDIOSAMPLE_192K            ((uint32_t)192000U)                     /*!< I2S audio sample rate is 192KHz */
+
+/* I2S frame format */
+#define I2SCTL_DTLEN(regval)            (BITS(1,2) & ((uint32_t)(regval) << 1))
+#define I2S_FRAMEFORMAT_DT16B_CH16B     I2SCTL_DTLEN(0)                         /*!< I2S data length is 16 bit and channel length is 16 bit */
+#define I2S_FRAMEFORMAT_DT16B_CH32B     (I2SCTL_DTLEN(0) | SPI_I2SCTL_CHLEN)    /*!< I2S data length is 16 bit and channel length is 32 bit */
+#define I2S_FRAMEFORMAT_DT24B_CH32B     (I2SCTL_DTLEN(1) | SPI_I2SCTL_CHLEN)    /*!< I2S data length is 24 bit and channel length is 32 bit */
+#define I2S_FRAMEFORMAT_DT32B_CH32B     (I2SCTL_DTLEN(2) | SPI_I2SCTL_CHLEN)    /*!< I2S data length is 32 bit and channel length is 32 bit */
+
+/* I2S master clock output */
+#define I2S_MCKOUT_DISABLE              ((uint32_t)0x00000000U)                 /*!< I2S master clock output disable */
+#define I2S_MCKOUT_ENABLE               SPI_I2SPSC_MCKOEN                       /*!< I2S master clock output enable */
+
+/* I2S operation mode */
+#define I2SCTL_I2SOPMOD(regval)         (BITS(8,9) & ((uint32_t)(regval) << 8))
+#define I2S_MODE_SLAVETX                I2SCTL_I2SOPMOD(0)                      /*!< I2S slave transmit mode */
+#define I2S_MODE_SLAVERX                I2SCTL_I2SOPMOD(1)                      /*!< I2S slave receive mode */
+#define I2S_MODE_MASTERTX               I2SCTL_I2SOPMOD(2)                      /*!< I2S master transmit mode */
+#define I2S_MODE_MASTERRX               I2SCTL_I2SOPMOD(3)                      /*!< I2S master receive mode */
+
+/* I2S standard */
+#define I2SCTL_I2SSTD(regval)           (BITS(4,5) & ((uint32_t)(regval) << 4))
+#define I2S_STD_PHILLIPS                I2SCTL_I2SSTD(0)                        /*!< I2S phillips standard */
+#define I2S_STD_MSB                     I2SCTL_I2SSTD(1)                        /*!< I2S MSB standard */
+#define I2S_STD_LSB                     I2SCTL_I2SSTD(2)                        /*!< I2S LSB standard */
+#define I2S_STD_PCMSHORT                I2SCTL_I2SSTD(3)                        /*!< I2S PCM short standard */
+#define I2S_STD_PCMLONG                 (I2SCTL_I2SSTD(3) | SPI_I2SCTL_PCMSMOD) /*!< I2S PCM long standard */
+
+/* I2S clock polarity */
+#define I2S_CKPL_LOW                    ((uint32_t)0x00000000U)                 /*!< I2S clock polarity low level */
+#define I2S_CKPL_HIGH                   SPI_I2SCTL_CKPL                         /*!< I2S clock polarity high level */
+#endif /* GD32F370, GD32F355, GD32F350 and GD32F310 */
+
+/* SPI DMA constants definitions */
+#define SPI_DMA_TRANSMIT                ((uint8_t)0x00U)                        /*!< SPI transmit data use DMA */
+#define SPI_DMA_RECEIVE                 ((uint8_t)0x01U)                        /*!< SPI receive data use DMA */
+
+/* SPI CRC constants definitions */
+#define SPI_CRC_TX                      ((uint8_t)0x00U)                        /*!< SPI transmit CRC value */
+#define SPI_CRC_RX                      ((uint8_t)0x01U)                        /*!< SPI receive CRC value */
+
+/* SPI/I2S interrupt enable/disable constants definitions */
+#define SPI_I2S_INT_TBE                 SPI_CTL1_TBEIE                          /*!< transmit buffer empty interrupt */
+#define SPI_I2S_INT_RBNE                SPI_CTL1_RBNEIE                         /*!< receive buffer not empty interrupt */
+#define SPI_I2S_INT_ERR                 SPI_CTL1_ERRIE                          /*!< error interrupt */
+
+/* SPI/I2S interrupt flag constants definitions */
+#define SPI_I2S_INT_FLAG_TBE            ((uint8_t)0x00U)                        /*!< transmit buffer empty interrupt flag */
+#define SPI_I2S_INT_FLAG_RBNE           ((uint8_t)0x01U)                        /*!< receive buffer not empty interrupt flag */
+#define SPI_I2S_INT_FLAG_RXORERR        ((uint8_t)0x02U)                        /*!< overrun interrupt flag */
+#define SPI_INT_FLAG_CONFERR            ((uint8_t)0x03U)                        /*!< config error interrupt flag */
+#define SPI_INT_FLAG_CRCERR             ((uint8_t)0x04U)                        /*!< CRC error interrupt flag */
+#define I2S_INT_FLAG_TXURERR            ((uint8_t)0x05U)                        /*!< underrun error interrupt flag */
+#define SPI_I2S_INT_FLAG_FERR           ((uint8_t)0x06U)                        /*!< format error interrupt flag */
+
+/* SPI flag definitions */
+#define SPI_FLAG_RBNE                   SPI_STAT_RBNE                           /*!< receive buffer not empty flag */
+#define SPI_FLAG_TBE                    SPI_STAT_TBE                            /*!< transmit buffer empty flag */
+#define SPI_FLAG_CRCERR                 SPI_STAT_CRCERR                         /*!< CRC error flag */
+#define SPI_FLAG_CONFERR                SPI_STAT_CONFERR                        /*!< mode config error flag */
+#define SPI_FLAG_RXORERR                SPI_STAT_RXORERR                        /*!< receive overrun error flag */
+#define SPI_FLAG_TRANS                  SPI_STAT_TRANS                          /*!< transmit on-going flag */
+#define SPI_FLAG_FERR                   SPI_STAT_FERR                           /*!< format error flag */
+
+#if (defined(GD32F370) || defined(GD32F355) || defined(GD32F350) || defined(GD32F310))
+/* I2S flag definitions */
+#define I2S_FLAG_RBNE                   SPI_STAT_RBNE                           /*!< receive buffer not empty flag */
+#define I2S_FLAG_TBE                    SPI_STAT_TBE                            /*!< transmit buffer empty flag */
+#define I2S_FLAG_CH                     SPI_STAT_I2SCH                          /*!< channel side flag */
+#define I2S_FLAG_TXURERR                SPI_STAT_TXURERR                        /*!< underrun error flag */
+#define I2S_FLAG_RXORERR                SPI_STAT_RXORERR                        /*!< overrun error flag */
+#define I2S_FLAG_TRANS                  SPI_STAT_TRANS                          /*!< transmit on-going flag */
+#define I2S_FLAG_FERR                   SPI_STAT_FERR                           /*!< format error interrupt flag */
+#endif /* GD32F370, GD32F355, GD32F350 and GD32F310 */
+
+/* function declarations */
+/* SPI deinitialization and initialization functions */
+/* reset SPI and I2S */
+void spi_i2s_deinit(uint32_t spi_periph);
+/* initialize the parameters of SPI structure with the default values */
+void spi_struct_para_init(spi_parameter_struct *spi_struct);
+/* initialize SPI parameters */
+void spi_init(uint32_t spi_periph, spi_parameter_struct *spi_struct);
+/* enable SPI */
+void spi_enable(uint32_t spi_periph);
+/* disable SPI */
+void spi_disable(uint32_t spi_periph);
+
+#if (defined(GD32F370) || defined(GD32F355) || defined(GD32F350) || defined(GD32F310))
+/* I2S initialization functions */
+/* initialize I2S parameters */
+void i2s_init(uint32_t spi_periph, uint32_t mode, uint32_t standard, uint32_t ckpl);
+/* configure I2S prescaler */
+void i2s_psc_config(uint32_t spi_periph, uint32_t audiosample, uint32_t frameformat, uint32_t mckout);
+/* enable I2S */
+void i2s_enable(uint32_t spi_periph);
+/* disable I2S */
+void i2s_disable(uint32_t spi_periph);
+#endif /* GD32F370, GD32F355, GD32F350 and GD32F310 */
+
+/* NSS functions */
+/* enable SPI NSS output */
+void spi_nss_output_enable(uint32_t spi_periph);
+/* disable SPI NSS output */
+void spi_nss_output_disable(uint32_t spi_periph);
+/* pull NSS pin high in software mode */
+void spi_nss_internal_high(uint32_t spi_periph);
+/* pull NSS pin low in software mode */
+void spi_nss_internal_low(uint32_t spi_periph);
+
+/* DMA functions */
+/* enable SPI DMA */
+void spi_dma_enable(uint32_t spi_periph, uint8_t dma);
+/* disable SPI DMA */
+void spi_dma_disable(uint32_t spi_periph, uint8_t dma);
+
+/* communication functions */
+/* configure SPI data frame format */
+void spi_i2s_data_frame_format_config(uint32_t spi_periph, uint16_t frame_format);
+/* configure SPI bidirectional transfer direction */
+void spi_bidirectional_transfer_config(uint32_t spi_periph, uint32_t transfer_direction);
+/* SPI transmit data */
+void spi_i2s_data_transmit(uint32_t spi_periph, uint16_t data);
+/* SPI receive data */
+uint16_t spi_i2s_data_receive(uint32_t spi_periph);
+/* clear SPI/I2S format error flag status */
+void spi_i2s_format_error_clear(uint32_t spi_periph, uint32_t flag);
+
+/* SPI CRC functions */
+/* set SPI CRC polynomial */
+void spi_crc_polynomial_set(uint32_t spi_periph, uint16_t crc_poly);
+/* get SPI CRC polynomial */
+uint16_t spi_crc_polynomial_get(uint32_t spi_periph);
+/* turn on SPI CRC function */
+void spi_crc_on(uint32_t spi_periph);
+/* turn off SPI CRC function */
+void spi_crc_off(uint32_t spi_periph);
+/* SPI next data is CRC value */
+void spi_crc_next(uint32_t spi_periph);
+/* get SPI CRC send value or receive value */
+uint16_t spi_crc_get(uint32_t spi_periph, uint8_t crc);
+/* clear SPI CRC error flag status */
+void spi_crc_error_clear(uint32_t spi_periph);
+
+/* SPI TI mode functions */
+/* enable SPI TI mode */
+void spi_ti_mode_enable(uint32_t spi_periph);
+/* disable SPI TI mode */
+void spi_ti_mode_disable(uint32_t spi_periph);
+
+/* SPI NSS pulse mode functions */
+/* enable SPI NSS pulse mode */
+void spi_nssp_mode_enable(uint32_t spi_periph);
+/* disable SPI NSS pulse mode */
+void spi_nssp_mode_disable(uint32_t spi_periph);
+
+/* SPI quad mode functions */
+/* enable SPI quad wire mode */
+void spi_quad_enable(uint32_t spi_periph);
+/* disable SPI quad wire mode */
+void spi_quad_disable(uint32_t spi_periph);
+/* enable SPI quad wire mode write */
+void spi_quad_write_enable(uint32_t spi_periph);
+/* enable SPI quad wire mode read */
+void spi_quad_read_enable(uint32_t spi_periph);
+/* enable SPI quad wire mode SPI_IO2 and SPI_IO3 pin output */
+void spi_quad_io23_output_enable(uint32_t spi_periph);
+/* disable SPI quad wire mode SPI_IO2 and SPI_IO3 pin output */
+void spi_quad_io23_output_disable(uint32_t spi_periph);
+
+/* flag and interrupt functions */
+/* get SPI and I2S flag status */
+FlagStatus spi_i2s_flag_get(uint32_t spi_periph, uint32_t flag);
+/* enable SPI and I2S interrupt */
+void spi_i2s_interrupt_enable(uint32_t spi_periph, uint8_t interrupt);
+/* disable SPI and I2S interrupt */
+void spi_i2s_interrupt_disable(uint32_t spi_periph, uint8_t interrupt);
+/* get SPI and I2S interrupt status */
+FlagStatus spi_i2s_interrupt_flag_get(uint32_t spi_periph, uint8_t interrupt);
+
+#endif /* GD32F3X0_SPI_H */

+ 189 - 0
GD32F3x0/GD32F3x0_standard_peripheral/Include/gd32f3x0_syscfg.h

@@ -0,0 +1,189 @@
+/*!
+    \file    gd32f3x0_syscfg.h
+    \brief   definitions for the SYSCFG
+
+    \version 2025-01-01, V2.5.0, firmware for GD32F3x0
+*/
+
+/*
+    Copyright (c) 2025, GigaDevice Semiconductor Inc.
+
+    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 of the copyright holder 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 HOLDER 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.
+*/
+
+#ifndef GD32F3X0_SYSCFG_H
+#define GD32F3X0_SYSCFG_H
+
+#include "gd32f3x0.h"
+
+/* SYSCFG definitions */
+#define SYSCFG                              SYSCFG_BASE
+
+/* registers definitions */
+#define SYSCFG_CFG0                         REG32(SYSCFG + 0x00000000U)         /*!< system configuration register 0 */
+#define SYSCFG_EXTISS0                      REG32(SYSCFG + 0x00000008U)         /*!< EXTI sources selection register 0 */
+#define SYSCFG_EXTISS1                      REG32(SYSCFG + 0x0000000CU)         /*!< EXTI sources selection register 1 */
+#define SYSCFG_EXTISS2                      REG32(SYSCFG + 0x00000010U)         /*!< EXTI sources selection register 2 */
+#define SYSCFG_EXTISS3                      REG32(SYSCFG + 0x00000014U)         /*!< EXTI sources selection register 3 */
+#define SYSCFG_CFG2                         REG32(SYSCFG + 0x00000018U)         /*!< system configuration register 2 */
+#define SYSCFG_CPSCTL                       REG32(SYSCFG + 0x00000020U)         /*!< system I/O compensation control register */
+
+/* SYSCFG_CFG0 bits definitions */
+#define SYSCFG_CFG0_BOOT_MODE               BITS(0,1)                           /*!< SYSCFG memory remap config */
+#define SYSCFG_CFG0_ADC_DMA_RMP             BIT(8)                              /*!< ADC DMA remap config */
+#define SYSCFG_CFG0_USART0_TX_DMA_RMP       BIT(9)                              /*!< USART0 Tx DMA remap config */
+#define SYSCFG_CFG0_USART0_RX_DMA_RMP       BIT(10)                             /*!< USART0 Rx DMA remap config */
+#define SYSCFG_CFG0_TIMER15_DMA_RMP         BIT(11)                             /*!< TIMER 15 DMA remap config */
+#define SYSCFG_CFG0_TIMER16_DMA_RMP         BIT(12)                             /*!< TIMER 16 DMA remap config */
+#define SYSCFG_CFG0_PB9_HCCE                BIT(19)                             /*!< PB9 pin high current capability enable */
+
+/* SYSCFG_EXTISS0 bits definitions */
+#define SYSCFG_EXTISS0_EXTI0_SS             BITS(0,3)                           /*!< EXTI 0 configuration */
+#define SYSCFG_EXTISS0_EXTI1_SS             BITS(4,7)                           /*!< EXTI 1 configuration */
+#define SYSCFG_EXTISS0_EXTI2_SS             BITS(8,11)                          /*!< EXTI 2 configuration */
+#define SYSCFG_EXTISS0_EXTI3_SS             BITS(12,15)                         /*!< EXTI 3 configuration */
+
+/* SYSCFG_EXTISS1 bits definitions */
+#define SYSCFG_EXTISS1_EXTI4_SS             BITS(0,3)                           /*!< EXTI 4 configuration */
+#define SYSCFG_EXTISS1_EXTI5_SS             BITS(4,7)                           /*!< EXTI 5 configuration */
+#define SYSCFG_EXTISS1_EXTI6_SS             BITS(8,11)                          /*!< EXTI 6 configuration */
+#define SYSCFG_EXTISS1_EXTI7_SS             BITS(12,15)                         /*!< EXTI 7 configuration */
+
+/* SYSCFG_EXTISS2 bits definitions */
+#define SYSCFG_EXTISS2_EXTI8_SS             BITS(0,3)                           /*!< EXTI 8 configuration */
+#define SYSCFG_EXTISS2_EXTI9_SS             BITS(4,7)                           /*!< EXTI 9 configuration */
+#define SYSCFG_EXTISS2_EXTI10_SS            BITS(8,11)                          /*!< EXTI 10 configuration */
+#define SYSCFG_EXTISS2_EXTI11_SS            BITS(12,15)                         /*!< EXTI 11 configuration */
+
+/* SYSCFG_EXTISS3 bits definitions */
+#define SYSCFG_EXTISS3_EXTI12_SS            BITS(0,3)                           /*!< EXTI 12 configuration */
+#define SYSCFG_EXTISS3_EXTI13_SS            BITS(4,7)                           /*!< EXTI 13 configuration */
+#define SYSCFG_EXTISS3_EXTI14_SS            BITS(8,11)                          /*!< EXTI 14 configuration */
+#define SYSCFG_EXTISS3_EXTI15_SS            BITS(12,15)                         /*!< EXTI 15 configuration */
+
+/* SYSCFG_CFG2 bits definitions */
+#define SYSCFG_CFG2_LOCKUP_LOCK             BIT(0)                              /*!< enable and lock the LOCKUP (Hardfault) output of Cortex-M4 with break input of TIMER0/14/15/16 */
+#define SYSCFG_CFG2_SRAM_PARITY_ERROR_LOCK  BIT(1)                              /*!< enable and lock the SRAM_PARITY error signal with break input of TIMER0/14/15/16 */
+#define SYSCFG_CFG2_LVD_LOCK                BIT(2)                              /*!< enable and lock the LVD connection with TIMER0 break input and also the LVD_EN and LVDSEL[2:0] bits of the power control interface */
+#define SYSCFG_CFG2_SRAM_PCEF               BIT(8)                              /*!< SRAM parity check error flag */
+
+/* SYSCFG_CPSCTL bits definitions */
+#define SYSCFG_CPSCTL_CPS_EN                BIT(0)                              /*!< I/O compensation cell enable */
+#define SYSCFG_CPSCTL_CPS_RDY               BIT(8)                              /*!< I/O compensation cell is ready or not */
+
+/* constants definitions */
+/* DMA remap definitions */
+#define SYSCFG_DMA_REMAP_ADC                SYSCFG_CFG0_ADC_DMA_RMP             /*!< ADC DMA remap */
+#define SYSCFG_DMA_REMAP_USART0TX           SYSCFG_CFG0_USART0_TX_DMA_RMP       /*!< USART0_TX DMA remap */
+#define SYSCFG_DMA_REMAP_USART0RX           SYSCFG_CFG0_USART0_RX_DMA_RMP       /*!< USART0_RX DMA remap */
+#define SYSCFG_DMA_REMAP_TIMER15            SYSCFG_CFG0_TIMER15_DMA_RMP         /*!< TIMER15 DMA remap */
+#define SYSCFG_DMA_REMAP_TIMER16            SYSCFG_CFG0_TIMER16_DMA_RMP         /*!< TIMER16 DMA remap */
+
+/* high current definitions */
+#define SYSCFG_HIGH_CURRENT_ENABLE          SYSCFG_CFG0_PB9_HCCE                /*!< high current enable */
+#define SYSCFG_HIGH_CURRENT_DISABLE         (~SYSCFG_CFG0_PB9_HCCE)             /*!< high current disable */
+
+/* EXTI source select definition */
+#define EXTISS0                             ((uint8_t)0x00U)                    /*!< EXTI source select register 0 */
+#define EXTISS1                             ((uint8_t)0x01U)                    /*!< EXTI source select register 1 */
+#define EXTISS2                             ((uint8_t)0x02U)                    /*!< EXTI source select register 2 */
+#define EXTISS3                             ((uint8_t)0x03U)                    /*!< EXTI source select register 3 */
+
+/* EXTI source select mask bits definition */
+#define EXTI_SS_MASK                        BITS(0,3)                           /*!< EXTI source select mask */
+
+/* EXTI source select jumping step definition */
+#define EXTI_SS_JSTEP                       ((uint8_t)0x04U)                    /*!< EXTI source select jumping step */
+
+/* EXTI source select moving step definition */
+#define EXTI_SS_MSTEP(pin)                  (EXTI_SS_JSTEP * ((pin) % EXTI_SS_JSTEP))   /*!< EXTI source select moving step */
+
+/* EXTI source port definitions */
+#define EXTI_SOURCE_GPIOA                   ((uint8_t)0x00U)                    /*!< EXTI GPIOA configuration */
+#define EXTI_SOURCE_GPIOB                   ((uint8_t)0x01U)                    /*!< EXTI GPIOB configuration */
+#define EXTI_SOURCE_GPIOC                   ((uint8_t)0x02U)                    /*!< EXTI GPIOC configuration */
+#define EXTI_SOURCE_GPIOD                   ((uint8_t)0x03U)                    /*!< EXTI GPIOD configuration */
+#define EXTI_SOURCE_GPIOF                   ((uint8_t)0x05U)                    /*!< EXTI GPIOF configuration */
+
+/* EXTI source pin definitions */
+#define EXTI_SOURCE_PIN0                    ((uint8_t)0x00U)                    /*!< EXTI GPIO pin0 configuration */
+#define EXTI_SOURCE_PIN1                    ((uint8_t)0x01U)                    /*!< EXTI GPIO pin1 configuration */
+#define EXTI_SOURCE_PIN2                    ((uint8_t)0x02U)                    /*!< EXTI GPIO pin2 configuration */
+#define EXTI_SOURCE_PIN3                    ((uint8_t)0x03U)                    /*!< EXTI GPIO pin3 configuration */
+#define EXTI_SOURCE_PIN4                    ((uint8_t)0x04U)                    /*!< EXTI GPIO pin4 configuration */
+#define EXTI_SOURCE_PIN5                    ((uint8_t)0x05U)                    /*!< EXTI GPIO pin5 configuration */
+#define EXTI_SOURCE_PIN6                    ((uint8_t)0x06U)                    /*!< EXTI GPIO pin6 configuration */
+#define EXTI_SOURCE_PIN7                    ((uint8_t)0x07U)                    /*!< EXTI GPIO pin7 configuration */
+#define EXTI_SOURCE_PIN8                    ((uint8_t)0x08U)                    /*!< EXTI GPIO pin8 configuration */
+#define EXTI_SOURCE_PIN9                    ((uint8_t)0x09U)                    /*!< EXTI GPIO pin9 configuration */
+#define EXTI_SOURCE_PIN10                   ((uint8_t)0x0AU)                    /*!< EXTI GPIO pin10 configuration */
+#define EXTI_SOURCE_PIN11                   ((uint8_t)0x0BU)                    /*!< EXTI GPIO pin11 configuration */
+#define EXTI_SOURCE_PIN12                   ((uint8_t)0x0CU)                    /*!< EXTI GPIO pin12 configuration */
+#define EXTI_SOURCE_PIN13                   ((uint8_t)0x0DU)                    /*!< EXTI GPIO pin13 configuration */
+#define EXTI_SOURCE_PIN14                   ((uint8_t)0x0EU)                    /*!< EXTI GPIO pin14 configuration */
+#define EXTI_SOURCE_PIN15                   ((uint8_t)0x0FU)                    /*!< EXTI GPIO pin15 configuration */
+
+/* lock definitions */
+#define SYSCFG_LOCK_LOCKUP                  SYSCFG_CFG2_LOCKUP_LOCK             /*!< LOCKUP output lock */
+#define SYSCFG_LOCK_SRAM_PARITY_ERROR       SYSCFG_CFG2_SRAM_PARITY_ERROR_LOCK  /*!< SRAM parity error lock */
+#define SYSCFG_LOCK_LVD                     SYSCFG_CFG2_LVD_LOCK                /*!< LVD lock */
+
+/* SRAM parity check error flag definitions */
+#define SYSCFG_SRAM_PCEF                    SYSCFG_CFG2_SRAM_PCEF               /*!< SRAM parity check error flag */
+
+/* I/O compensation cell enable/disable */
+#define SYSCFG_COMPENSATION(regval)         (BIT(0) & ((uint32_t)(regval) << 0))
+#define SYSCFG_COMPENSATION_DISABLE         SYSCFG_COMPENSATION(0)              /*!< I/O compensation cell is power-down */
+#define SYSCFG_COMPENSATION_ENABLE          SYSCFG_COMPENSATION(1)              /*!< I/O compensation cell is enabled */
+
+/* function declarations */
+/* deinit syscfg module */
+void syscfg_deinit(void);
+
+/* enable the DMA channels remapping */
+void syscfg_dma_remap_enable(uint32_t syscfg_dma_remap);
+/* disable the DMA channels remapping */
+void syscfg_dma_remap_disable(uint32_t syscfg_dma_remap);
+
+/* enable PB9 high current capability */
+void syscfg_high_current_enable(void);
+/* disable PB9 high current capability */
+void syscfg_high_current_disable(void);
+
+/* configure the GPIO pin as EXTI Line */
+void syscfg_exti_line_config(uint8_t exti_port, uint8_t exti_pin);
+/* connect TIMER0/14/15/16 break input to the selected parameter */
+void syscfg_lock_config(uint32_t syscfg_lock);
+
+/* check if the specified flag in SYSCFG_CFG2 is set or not */
+FlagStatus syscfg_flag_get(uint32_t syscfg_flag);
+/* clear the flag in SYSCFG_CFG2 by writing 1 */
+void syscfg_flag_clear(uint32_t syscfg_flag);
+
+/* configure the I/O compensation cell */
+void syscfg_compensation_config(uint32_t syscfg_compensation);
+/* check if the I/O compensation cell ready flag is set or not */
+FlagStatus syscfg_cps_rdy_flag_get(void);
+
+#endif /* GD32F3X0_SYSCFG_H */

+ 764 - 0
GD32F3x0/GD32F3x0_standard_peripheral/Include/gd32f3x0_timer.h

@@ -0,0 +1,764 @@
+/*!
+    \file    gd32f3x0_timer.h
+    \brief   definitions for the TIMER
+
+    \version 2025-01-01, V2.5.0, firmware for GD32F3x0
+*/
+
+/*
+    Copyright (c) 2025, GigaDevice Semiconductor Inc.
+
+    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 of the copyright holder 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 HOLDER 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.
+*/
+
+#ifndef GD32F3X0_TIMER_H
+#define GD32F3X0_TIMER_H
+
+#include "gd32f3x0.h"
+
+/* TIMERx(x=0,1,2,5,13..16) definitions */
+#define TIMER0                           (TIMER_BASE + 0x00012C00U)                 /*!< TIMER0 base address */
+#if (!defined (GD32F310))
+#define TIMER1                           (TIMER_BASE + 0x00000000U)                 /*!< TIMER1 base address */
+#endif /* GD32F310 */
+#define TIMER2                           (TIMER_BASE + 0x00000400U)                 /*!< TIMER2 base address */
+#if (defined(GD32F350) || defined(GD32F355) || defined(GD32F370))
+#define TIMER5                           (TIMER_BASE + 0x00001000U)                 /*!< TIMER5 base address */
+#endif /* GD32F350, GD32F355 and GD32F370 */
+#define TIMER13                          (TIMER_BASE + 0x00002000U)                 /*!< TIMER13 base address */
+#define TIMER14                          (TIMER_BASE + 0x00014000U)                 /*!< TIMER14 base address */
+#define TIMER15                          (TIMER_BASE + 0x00014400U)                 /*!< TIMER15 base address */
+#define TIMER16                          (TIMER_BASE + 0x00014800U)                 /*!< TIMER16 base address */
+
+/* registers definitions */
+#define TIMER_CTL0(timerx)               REG32((timerx) + 0x00000000U)              /*!< TIMER control register 0 */
+#define TIMER_CTL1(timerx)               REG32((timerx) + 0x00000004U)              /*!< TIMER control register 1 */
+#define TIMER_SMCFG(timerx)              REG32((timerx) + 0x00000008U)              /*!< TIMER slave mode configuration register */
+#define TIMER_DMAINTEN(timerx)           REG32((timerx) + 0x0000000CU)              /*!< TIMER DMA and interrupt enable register */
+#define TIMER_INTF(timerx)               REG32((timerx) + 0x00000010U)              /*!< TIMER interrupt flag register */
+#define TIMER_SWEVG(timerx)              REG32((timerx) + 0x00000014U)              /*!< TIMER software event generation register */
+#define TIMER_CHCTL0(timerx)             REG32((timerx) + 0x00000018U)              /*!< TIMER channel control register 0 */
+#define TIMER_CHCTL1(timerx)             REG32((timerx) + 0x0000001CU)              /*!< TIMER channel control register 1 */
+#define TIMER_CHCTL2(timerx)             REG32((timerx) + 0x00000020U)              /*!< TIMER channel control register 2 */
+#define TIMER_CNT(timerx)                REG32((timerx) + 0x00000024U)              /*!< TIMER counter register */
+#define TIMER_PSC(timerx)                REG32((timerx) + 0x00000028U)              /*!< TIMER prescaler register */
+#define TIMER_CAR(timerx)                REG32((timerx) + 0x0000002CU)              /*!< TIMER counter auto reload register */
+#define TIMER_CREP(timerx)               REG32((timerx) + 0x00000030U)              /*!< TIMER counter repetition register */
+#define TIMER_CH0CV(timerx)              REG32((timerx) + 0x00000034U)              /*!< TIMER channel 0 capture/compare value register */
+#define TIMER_CH1CV(timerx)              REG32((timerx) + 0x00000038U)              /*!< TIMER channel 1 capture/compare value register */
+#define TIMER_CH2CV(timerx)              REG32((timerx) + 0x0000003CU)              /*!< TIMER channel 2 capture/compare value register */
+#define TIMER_CH3CV(timerx)              REG32((timerx) + 0x00000040U)              /*!< TIMER channel 3 capture/compare value register */
+#define TIMER_CCHP(timerx)               REG32((timerx) + 0x00000044U)              /*!< TIMER complementary channel protection register */
+#define TIMER_DMACFG(timerx)             REG32((timerx) + 0x00000048U)              /*!< TIMER DMA configuration register */
+#define TIMER_DMATB(timerx)              REG32((timerx) + 0x0000004CU)              /*!< TIMER DMA transfer buffer register */
+#define TIMER_IRMP(timerx)               REG32((timerx) + 0x00000050U)              /*!< TIMER channel input remap register */
+#define TIMER_CFG(timerx)                REG32((timerx) + 0x000000FCU)              /*!< TIMER configuration register */
+
+/* bits definitions */
+/* TIMER_CTL0 */
+#define TIMER_CTL0_CEN                   BIT(0)                                     /*!< TIMER counter enable */
+#define TIMER_CTL0_UPDIS                 BIT(1)                                     /*!< update disable */
+#define TIMER_CTL0_UPS                   BIT(2)                                     /*!< update source */
+#define TIMER_CTL0_SPM                   BIT(3)                                     /*!< single pulse mode */
+#define TIMER_CTL0_DIR                   BIT(4)                                     /*!< timer counter direction */
+#define TIMER_CTL0_CAM                   BITS(5,6)                                  /*!< center-aligned mode selection */
+#define TIMER_CTL0_ARSE                  BIT(7)                                     /*!< auto-reload shadow enable */
+#define TIMER_CTL0_CKDIV                 BITS(8,9)                                  /*!< clock division */
+
+/* TIMER_CTL1 */
+#define TIMER_CTL1_CCSE                  BIT(0)                                     /*!< commutation control shadow enable */
+#define TIMER_CTL1_CCUC                  BIT(2)                                     /*!< commutation control shadow register update control */
+#define TIMER_CTL1_DMAS                  BIT(3)                                     /*!< DMA request source selection */
+#define TIMER_CTL1_MMC                   BITS(4,6)                                  /*!< master mode control */
+#define TIMER_CTL1_TI0S                  BIT(7)                                     /*!< channel 0 trigger input selection(hall mode selection) */
+#define TIMER_CTL1_ISO0                  BIT(8)                                     /*!< idle state of channel 0 output */
+#define TIMER_CTL1_ISO0N                 BIT(9)                                     /*!< idle state of channel 0 complementary output */
+#define TIMER_CTL1_ISO1                  BIT(10)                                    /*!< idle state of channel 1 output */
+#define TIMER_CTL1_ISO1N                 BIT(11)                                    /*!< idle state of channel 1 complementary output */
+#define TIMER_CTL1_ISO2                  BIT(12)                                    /*!< idle state of channel 2 output */
+#define TIMER_CTL1_ISO2N                 BIT(13)                                    /*!< idle state of channel 2 complementary output */
+#define TIMER_CTL1_ISO3                  BIT(14)                                    /*!< idle state of channel 3 output */
+
+/* TIMER_SMCFG */
+#define TIMER_SMCFG_SMC                  BITS(0,2)                                  /*!< slave mode control */
+#define TIMER_SMCFG_OCRC                 BIT(3)                                     /*!< OCPRE clear source selection */
+#define TIMER_SMCFG_TRGS                 BITS(4,6)                                  /*!< trigger selection */
+#define TIMER_SMCFG_MSM                  BIT(7)                                     /*!< master-slave mode */
+#define TIMER_SMCFG_ETFC                 BITS(8,11)                                 /*!< external trigger filter control */
+#define TIMER_SMCFG_ETPSC                BITS(12,13)                                /*!< external trigger prescaler */
+#define TIMER_SMCFG_SMC1                 BIT(14)                                    /*!< part of SMC for enable external clock mode 1 */
+#define TIMER_SMCFG_ETP                  BIT(15)                                    /*!< external trigger polarity */
+
+/* TIMER_DMAINTEN */
+#define TIMER_DMAINTEN_UPIE              BIT(0)                                     /*!< update interrupt enable */
+#define TIMER_DMAINTEN_CH0IE             BIT(1)                                     /*!< channel 0 capture/compare interrupt enable */
+#define TIMER_DMAINTEN_CH1IE             BIT(2)                                     /*!< channel 1 capture/compare interrupt enable */
+#define TIMER_DMAINTEN_CH2IE             BIT(3)                                     /*!< channel 2 capture/compare interrupt enable */
+#define TIMER_DMAINTEN_CH3IE             BIT(4)                                     /*!< channel 3 capture/compare interrupt enable */
+#define TIMER_DMAINTEN_CMTIE             BIT(5)                                     /*!< commutation interrupt request enable */
+#define TIMER_DMAINTEN_TRGIE             BIT(6)                                     /*!< trigger interrupt enable */
+#define TIMER_DMAINTEN_BRKIE             BIT(7)                                     /*!< break interrupt enable */
+#define TIMER_DMAINTEN_UPDEN             BIT(8)                                     /*!< update DMA request enable */
+#define TIMER_DMAINTEN_CH0DEN            BIT(9)                                     /*!< channel 0 DMA request enable */
+#define TIMER_DMAINTEN_CH1DEN            BIT(10)                                    /*!< channel 1 DMA request enable */
+#define TIMER_DMAINTEN_CH2DEN            BIT(11)                                    /*!< channel 2 DMA request enable */
+#define TIMER_DMAINTEN_CH3DEN            BIT(12)                                    /*!< channel 3 DMA request enable */
+#define TIMER_DMAINTEN_CMTDEN            BIT(13)                                    /*!< commutation DMA request enable */
+#define TIMER_DMAINTEN_TRGDEN            BIT(14)                                    /*!< trigger DMA request enable */
+
+/* TIMER_INTF */
+#define TIMER_INTF_UPIF                  BIT(0)                                     /*!< update interrupt flag */
+#define TIMER_INTF_CH0IF                 BIT(1)                                     /*!< channel 0 capture/compare interrupt flag */
+#define TIMER_INTF_CH1IF                 BIT(2)                                     /*!< channel 1 capture/compare interrupt flag */
+#define TIMER_INTF_CH2IF                 BIT(3)                                     /*!< channel 2 capture/compare interrupt flag */
+#define TIMER_INTF_CH3IF                 BIT(4)                                     /*!< channel 3 capture/compare interrupt flag */
+#define TIMER_INTF_CMTIF                 BIT(5)                                     /*!< channel commutation interrupt flag */
+#define TIMER_INTF_TRGIF                 BIT(6)                                     /*!< trigger interrupt flag */
+#define TIMER_INTF_BRKIF                 BIT(7)                                     /*!< break interrupt flag */
+#define TIMER_INTF_CH0OF                 BIT(9)                                     /*!< channel 0 overcapture flag */
+#define TIMER_INTF_CH1OF                 BIT(10)                                    /*!< channel 1 overcapture flag */
+#define TIMER_INTF_CH2OF                 BIT(11)                                    /*!< channel 2 overcapture flag */
+#define TIMER_INTF_CH3OF                 BIT(12)                                    /*!< channel 3 overcapture flag */
+
+/* TIMER_SWEVG */
+#define TIMER_SWEVG_UPG                  BIT(0)                                     /*!< update event generate */
+#define TIMER_SWEVG_CH0G                 BIT(1)                                     /*!< channel 0 capture or compare event generation */
+#define TIMER_SWEVG_CH1G                 BIT(2)                                     /*!< channel 1 capture or compare event generation */
+#define TIMER_SWEVG_CH2G                 BIT(3)                                     /*!< channel 2 capture or compare event generation */
+#define TIMER_SWEVG_CH3G                 BIT(4)                                     /*!< channel 3 capture or compare event generation */
+#define TIMER_SWEVG_CMTG                 BIT(5)                                     /*!< channel commutation event generation */
+#define TIMER_SWEVG_TRGG                 BIT(6)                                     /*!< trigger event generation */
+#define TIMER_SWEVG_BRKG                 BIT(7)                                     /*!< break event generation */
+
+/* TIMER_CHCTL0 */
+/* output compare mode */
+#define TIMER_CHCTL0_CH0MS               BITS(0,1)                                  /*!< channel 0 mode selection */
+#define TIMER_CHCTL0_CH0COMFEN           BIT(2)                                     /*!< channel 0 output compare fast enable */
+#define TIMER_CHCTL0_CH0COMSEN           BIT(3)                                     /*!< channel 0 output compare shadow enable */
+#define TIMER_CHCTL0_CH0COMCTL           BITS(4,6)                                  /*!< channel 0 output compare mode */
+#define TIMER_CHCTL0_CH0COMCEN           BIT(7)                                     /*!< channel 0 output compare clear enable */
+#define TIMER_CHCTL0_CH1MS               BITS(8,9)                                  /*!< channel 1 mode selection */
+#define TIMER_CHCTL0_CH1COMFEN           BIT(10)                                    /*!< channel 1 output compare fast enable */
+#define TIMER_CHCTL0_CH1COMSEN           BIT(11)                                    /*!< channel 1 output compare shadow enable */
+#define TIMER_CHCTL0_CH1COMCTL           BITS(12,14)                                /*!< channel 1 output compare mode */
+#define TIMER_CHCTL0_CH1COMCEN           BIT(15)                                    /*!< channel 1 output compare clear enable */
+/* input capture mode */                                                            
+#define TIMER_CHCTL0_CH0CAPPSC           BITS(2,3)                                  /*!< channel 0 input capture prescaler */
+#define TIMER_CHCTL0_CH0CAPFLT           BITS(4,7)                                  /*!< channel 0 input capture filter control */
+#define TIMER_CHCTL0_CH1CAPPSC           BITS(10,11)                                /*!< channel 1 input capture prescaler */
+#define TIMER_CHCTL0_CH1CAPFLT           BITS(12,15)                                /*!< channel 1 input capture filter control */
+
+/* TIMER_CHCTL1 */
+/* output compare mode */
+#define TIMER_CHCTL1_CH2MS               BITS(0,1)                                  /*!< channel 2 mode selection */
+#define TIMER_CHCTL1_CH2COMFEN           BIT(2)                                     /*!< channel 2 output compare fast enable */
+#define TIMER_CHCTL1_CH2COMSEN           BIT(3)                                     /*!< channel 2 output compare shadow enable */
+#define TIMER_CHCTL1_CH2COMCTL           BITS(4,6)                                  /*!< channel 2 output compare mode */
+#define TIMER_CHCTL1_CH2COMCEN           BIT(7)                                     /*!< channel 2 output compare clear enable */
+#define TIMER_CHCTL1_CH3MS               BITS(8,9)                                  /*!< channel 3 mode selection */
+#define TIMER_CHCTL1_CH3COMFEN           BIT(10)                                    /*!< channel 3 output compare fast enable */
+#define TIMER_CHCTL1_CH3COMSEN           BIT(11)                                    /*!< channel 3 output compare shadow enable */
+#define TIMER_CHCTL1_CH3COMCTL           BITS(12,14)                                /*!< channel 3 output compare mode */
+#define TIMER_CHCTL1_CH3COMCEN           BIT(15)                                    /*!< channel 3 output compare clear enable */
+/* input capture mode */
+#define TIMER_CHCTL1_CH2CAPPSC           BITS(2,3)                                  /*!< channel 2 input capture prescaler */
+#define TIMER_CHCTL1_CH2CAPFLT           BITS(4,7)                                  /*!< channel 2 input capture filter control */
+#define TIMER_CHCTL1_CH3CAPPSC           BITS(10,11)                                /*!< channel 3 input capture prescaler */
+#define TIMER_CHCTL1_CH3CAPFLT           BITS(12,15)                                /*!< channel 3 input capture filter control */
+
+/* TIMER_CHCTL2 */
+#define TIMER_CHCTL2_CH0EN               BIT(0)                                     /*!< channel 0 capture/compare function enable */
+#define TIMER_CHCTL2_CH0P                BIT(1)                                     /*!< channel 0 capture/compare function polarity */
+#define TIMER_CHCTL2_CH0NEN              BIT(2)                                     /*!< channel 0 complementary output enable */
+#define TIMER_CHCTL2_CH0NP               BIT(3)                                     /*!< channel 0 complementary output polarity */
+#define TIMER_CHCTL2_CH1EN               BIT(4)                                     /*!< channel 1 capture/compare function enable  */
+#define TIMER_CHCTL2_CH1P                BIT(5)                                     /*!< channel 1 capture/compare function polarity */
+#define TIMER_CHCTL2_CH1NEN              BIT(6)                                     /*!< channel 1 complementary output enable */
+#define TIMER_CHCTL2_CH1NP               BIT(7)                                     /*!< channel 1 complementary output polarity */
+#define TIMER_CHCTL2_CH2EN               BIT(8)                                     /*!< channel 2 capture/compare function enable  */
+#define TIMER_CHCTL2_CH2P                BIT(9)                                     /*!< channel 2 capture/compare function polarity */
+#define TIMER_CHCTL2_CH2NEN              BIT(10)                                    /*!< channel 2 complementary output enable */
+#define TIMER_CHCTL2_CH2NP               BIT(11)                                    /*!< channel 2 complementary output polarity */
+#define TIMER_CHCTL2_CH3EN               BIT(12)                                    /*!< channel 3 capture/compare function enable  */
+#define TIMER_CHCTL2_CH3P                BIT(13)                                    /*!< channel 3 capture/compare function polarity */
+#define TIMER_CHCTL2_CH3NP               BIT(15)                                    /*!< channel 3 complementary output polarity */
+
+/* TIMER_CNT */
+#define TIMER_CNT_CNT16                  BITS(0,15)                                 /*!< 16 bit timer counter */
+#define TIMER_CNT_CNT32                  BITS(0,31)                                 /*!< 32 bit(TIMER1) timer counter */
+
+/* TIMER_PSC */
+#define TIMER_PSC_PSC                    BITS(0,15)                                 /*!< prescaler value of the counter clock */
+
+/* TIMER_CAR */
+#define TIMER_CAR_CARL16                 BITS(0,15)                                 /*!< 16 bit counter auto reload value */
+#define TIMER_CAR_CARL32                 BITS(0,31)                                 /*!< 32 bit(TIMER1) counter auto reload value */
+
+/* TIMER_CREP */
+#define TIMER_CREP_CREP                  BITS(0,7)                                  /*!< counter repetition value */
+
+/* TIMER_CH0CV */
+#define TIMER_CH0CV_CH0VAL16             BITS(0,15)                                 /*!< 16 bit capture/compare value of channel 0 */
+#define TIMER_CH0CV_CH0VAL32             BITS(0,31)                                 /*!< 32 bit(TIMER1) capture/compare value of channel 0 */
+
+/* TIMER_CH1CV */
+#define TIMER_CH1CV_CH1VAL16             BITS(0,15)                                 /*!< 16 bit capture/compare value of channel 1 */
+#define TIMER_CH1CV_CH1VAL32             BITS(0,31)                                 /*!< 32 bit(TIMER1) capture/compare value of channel 1 */
+
+/* TIMER_CH2CV */
+#define TIMER_CH2CV_CH2VAL16             BITS(0,15)                                 /*!< 16 bit capture/compare value of channel 2 */
+#define TIMER_CH2CV_CH2VAL32             BITS(0,31)                                 /*!< 32 bit(TIMER1) capture/compare value of channel 2 */
+
+/* TIMER_CH3CV */
+#define TIMER_CH3CV_CH3VAL16             BITS(0,15)                                 /*!< 16 bit capture/compare value of channel 3 */
+#define TIMER_CH3CV_CH3VAL32             BITS(0,31)                                 /*!< 32 bit(TIMER1) capture/compare value of channel 3 */
+
+/* TIMER_CCHP */
+#define TIMER_CCHP_DTCFG                 BITS(0,7)                                  /*!< dead time configure */
+#define TIMER_CCHP_PROT                  BITS(8,9)                                  /*!< complementary register protect control */
+#define TIMER_CCHP_IOS                   BIT(10)                                    /*!< idle mode off-state configure */
+#define TIMER_CCHP_ROS                   BIT(11)                                    /*!< run mode off-state configure */
+#define TIMER_CCHP_BRKEN                 BIT(12)                                    /*!< break enable */
+#define TIMER_CCHP_BRKP                  BIT(13)                                    /*!< break polarity */
+#define TIMER_CCHP_OAEN                  BIT(14)                                    /*!< output automatic enable */
+#define TIMER_CCHP_POEN                  BIT(15)                                    /*!< primary output enable */
+
+/* TIMER_DMACFG */
+#define TIMER_DMACFG_DMATA               BITS(0,4)                                  /*!< DMA transfer access start address */
+#define TIMER_DMACFG_DMATC               BITS(8,12)                                 /*!< DMA transfer count */
+
+/* TIMER_DMATB */
+#define TIMER_DMATB_DMATB                BITS(0,15)                                 /*!< DMA transfer buffer address */
+
+/* TIMER_IRMP */                                                                    
+#define TIMER13_IRMP_CI0_RMP             BITS(0,1)                                  /*!< TIMER13 channel 0 input remap */
+
+/* TIMER_CFG */
+#define TIMER_CFG_OUTSEL                 BIT(0)                                     /*!< the output value selection */
+#define TIMER_CFG_CHVSEL                 BIT(1)                                     /*!< write CHxVAL register selection */
+
+/* constants definitions */
+/* TIMER init parameter struct definitions*/
+typedef struct {
+    uint16_t prescaler;                                                             /*!< prescaler value */
+    uint16_t alignedmode;                                                           /*!< aligned mode */
+    uint16_t counterdirection;                                                      /*!< counter direction */
+    uint16_t clockdivision;                                                         /*!< clock division value */
+    uint32_t period;                                                                /*!< period value */
+    uint8_t  repetitioncounter;                                                     /*!< the counter repetition value */
+} timer_parameter_struct;
+
+/* break parameter struct definitions*/
+typedef struct {
+    uint32_t runoffstate;                                                           /*!< run mode off-state */
+    uint32_t ideloffstate;                                                          /*!< idle mode off-state */
+    uint16_t deadtime;                                                              /*!< dead time */
+    uint16_t breakpolarity;                                                         /*!< break polarity */
+    uint32_t outputautostate;                                                       /*!< output automatic enable */
+    uint32_t protectmode;                                                           /*!< complementary register protect control */
+    uint32_t breakstate;                                                            /*!< break enable */
+} timer_break_parameter_struct;
+
+/* channel output parameter struct definitions */
+typedef struct {
+    uint32_t outputstate;                                                           /*!< channel output state */
+    uint16_t outputnstate;                                                          /*!< channel complementary output state */
+    uint16_t ocpolarity;                                                            /*!< channel output polarity */
+    uint16_t ocnpolarity;                                                           /*!< channel complementary output polarity */
+    uint16_t ocidlestate;                                                           /*!< idle state of channel output */
+    uint16_t ocnidlestate;                                                          /*!< idle state of channel complementary output */
+} timer_oc_parameter_struct;
+
+/* channel input parameter struct definitions */
+typedef struct {
+    uint16_t icpolarity;                                                            /*!< channel input polarity */
+    uint16_t icselection;                                                           /*!< channel input mode selection */
+    uint16_t icprescaler;                                                           /*!< channel input capture prescaler */
+    uint16_t icfilter;                                                              /*!< channel input capture filter control */
+} timer_ic_parameter_struct;
+
+/* TIMER interrupt enable or disable */
+#define TIMER_INT_UP                        TIMER_DMAINTEN_UPIE                     /*!< update interrupt */
+#define TIMER_INT_CH0                       TIMER_DMAINTEN_CH0IE                    /*!< channel 0 interrupt */
+#define TIMER_INT_CH1                       TIMER_DMAINTEN_CH1IE                    /*!< channel 1 interrupt */
+#define TIMER_INT_CH2                       TIMER_DMAINTEN_CH2IE                    /*!< channel 2 interrupt */
+#define TIMER_INT_CH3                       TIMER_DMAINTEN_CH3IE                    /*!< channel 3 interrupt */
+#define TIMER_INT_CMT                       TIMER_DMAINTEN_CMTIE                    /*!< channel commutation interrupt flag */
+#define TIMER_INT_TRG                       TIMER_DMAINTEN_TRGIE                    /*!< trigger interrupt */
+#define TIMER_INT_BRK                       TIMER_DMAINTEN_BRKIE                    /*!< break interrupt */
+
+/* TIMER flag */
+#define TIMER_FLAG_UP                       TIMER_INTF_UPIF                         /*!< update flag */
+#define TIMER_FLAG_CH0                      TIMER_INTF_CH0IF                        /*!< channel 0 flag */
+#define TIMER_FLAG_CH1                      TIMER_INTF_CH1IF                        /*!< channel 1 flag */
+#define TIMER_FLAG_CH2                      TIMER_INTF_CH2IF                        /*!< channel 2 flag */
+#define TIMER_FLAG_CH3                      TIMER_INTF_CH3IF                        /*!< channel 3 flag */
+#define TIMER_FLAG_CMT                      TIMER_INTF_CMTIF                        /*!< channel commutation flag */
+#define TIMER_FLAG_TRG                      TIMER_INTF_TRGIF                        /*!< trigger flag */
+#define TIMER_FLAG_BRK                      TIMER_INTF_BRKIF                        /*!< break flag */
+#define TIMER_FLAG_CH0O                     TIMER_INTF_CH0OF                        /*!< channel 0 overcapture flag */
+#define TIMER_FLAG_CH1O                     TIMER_INTF_CH1OF                        /*!< channel 1 overcapture flag */
+#define TIMER_FLAG_CH2O                     TIMER_INTF_CH2OF                        /*!< channel 2 overcapture flag */
+#define TIMER_FLAG_CH3O                     TIMER_INTF_CH3OF                        /*!< channel 3 overcapture flag */
+
+/* TIMER interrupt flag */
+#define TIMER_INT_FLAG_UP                   TIMER_INTF_UPIF                         /*!< update interrupt flag */
+#define TIMER_INT_FLAG_CH0                  TIMER_INTF_CH0IF                        /*!< channel 0 interrupt flag */
+#define TIMER_INT_FLAG_CH1                  TIMER_INTF_CH1IF                        /*!< channel 1 interrupt flag */
+#define TIMER_INT_FLAG_CH2                  TIMER_INTF_CH2IF                        /*!< channel 2 interrupt flag */
+#define TIMER_INT_FLAG_CH3                  TIMER_INTF_CH3IF                        /*!< channel 3 interrupt flag */
+#define TIMER_INT_FLAG_CMT                  TIMER_INTF_CMTIF                        /*!< channel commutation interrupt flag */
+#define TIMER_INT_FLAG_TRG                  TIMER_INTF_TRGIF                        /*!< trigger interrupt flag */
+#define TIMER_INT_FLAG_BRK                  TIMER_INTF_BRKIF
+
+/* TIMER DMA source enable */
+#define TIMER_DMA_UPD                       ((uint16_t)TIMER_DMAINTEN_UPDEN)        /*!< update DMA enable */
+#define TIMER_DMA_CH0D                      ((uint16_t)TIMER_DMAINTEN_CH0DEN)       /*!< channel 0 DMA enable */
+#define TIMER_DMA_CH1D                      ((uint16_t)TIMER_DMAINTEN_CH1DEN)       /*!< channel 1 DMA enable */
+#define TIMER_DMA_CH2D                      ((uint16_t)TIMER_DMAINTEN_CH2DEN)       /*!< channel 2 DMA enable */
+#define TIMER_DMA_CH3D                      ((uint16_t)TIMER_DMAINTEN_CH3DEN)       /*!< channel 3 DMA enable */
+#define TIMER_DMA_CMTD                      ((uint16_t)TIMER_DMAINTEN_CMTDEN)       /*!< commutation DMA request enable */
+#define TIMER_DMA_TRGD                      ((uint16_t)TIMER_DMAINTEN_TRGDEN)       /*!< trigger DMA enable */
+
+/* channel DMA request source selection */
+#define TIMER_DMAREQUEST_UPDATEEVENT        ((uint8_t)0x00U)                        /*!< DMA request of channel y is sent when update event occurs */
+#define TIMER_DMAREQUEST_CHANNELEVENT       ((uint8_t)0x01U)                        /*!< DMA request of channel y is sent when channel y event occurs */
+
+/* DMA access base address */
+#define DMACFG_DMATA(regval)                (BITS(0, 4) & ((uint32_t)(regval) << 0U))
+#define TIMER_DMACFG_DMATA_CTL0             DMACFG_DMATA(0)                         /*!< DMA transfer address is TIMER_CTL0 */
+#define TIMER_DMACFG_DMATA_CTL1             DMACFG_DMATA(1)                         /*!< DMA transfer address is TIMER_CTL1 */
+#define TIMER_DMACFG_DMATA_SMCFG            DMACFG_DMATA(2)                         /*!< DMA transfer address is TIMER_SMCFG */
+#define TIMER_DMACFG_DMATA_DMAINTEN         DMACFG_DMATA(3)                         /*!< DMA transfer address is TIMER_DMAINTEN */
+#define TIMER_DMACFG_DMATA_INTF             DMACFG_DMATA(4)                         /*!< DMA transfer address is TIMER_INTF */
+#define TIMER_DMACFG_DMATA_SWEVG            DMACFG_DMATA(5)                         /*!< DMA transfer address is TIMER_SWEVG */
+#define TIMER_DMACFG_DMATA_CHCTL0           DMACFG_DMATA(6)                         /*!< DMA transfer address is TIMER_CHCTL0 */
+#define TIMER_DMACFG_DMATA_CHCTL1           DMACFG_DMATA(7)                         /*!< DMA transfer address is TIMER_CHCTL1 */
+#define TIMER_DMACFG_DMATA_CHCTL2           DMACFG_DMATA(8)                         /*!< DMA transfer address is TIMER_CHCTL2 */
+#define TIMER_DMACFG_DMATA_CNT              DMACFG_DMATA(9)                         /*!< DMA transfer address is TIMER_CNT */
+#define TIMER_DMACFG_DMATA_PSC              DMACFG_DMATA(10)                        /*!< DMA transfer address is TIMER_PSC */
+#define TIMER_DMACFG_DMATA_CAR              DMACFG_DMATA(11)                        /*!< DMA transfer address is TIMER_CAR */
+#define TIMER_DMACFG_DMATA_CREP             DMACFG_DMATA(12)                        /*!< DMA transfer address is TIMER_CREP */
+#define TIMER_DMACFG_DMATA_CH0CV            DMACFG_DMATA(13)                        /*!< DMA transfer address is TIMER_CH0CV */
+#define TIMER_DMACFG_DMATA_CH1CV            DMACFG_DMATA(14)                        /*!< DMA transfer address is TIMER_CH1CV */
+#define TIMER_DMACFG_DMATA_CH2CV            DMACFG_DMATA(15)                        /*!< DMA transfer address is TIMER_CH2CV */
+#define TIMER_DMACFG_DMATA_CH3CV            DMACFG_DMATA(16)                        /*!< DMA transfer address is TIMER_CH3CV */
+#define TIMER_DMACFG_DMATA_CCHP             DMACFG_DMATA(17)                        /*!< DMA transfer address is TIMER_CCHP */
+#define TIMER_DMACFG_DMATA_DMACFG           DMACFG_DMATA(18)                        /*!< DMA transfer address is TIMER_DMACFG */
+#define TIMER_DMACFG_DMATA_DMATB            DMACFG_DMATA(19)                        /*!< DMA transfer address is TIMER_DMATB */
+
+/* DMA access burst length */
+#define DMACFG_DMATC(regval)                (BITS(8, 12) & ((uint32_t)(regval) << 8U))
+#define TIMER_DMACFG_DMATC_1TRANSFER        DMACFG_DMATC(0)                         /*!< DMA transfer 1 time */
+#define TIMER_DMACFG_DMATC_2TRANSFER        DMACFG_DMATC(1)                         /*!< DMA transfer 2 times */
+#define TIMER_DMACFG_DMATC_3TRANSFER        DMACFG_DMATC(2)                         /*!< DMA transfer 3 times */
+#define TIMER_DMACFG_DMATC_4TRANSFER        DMACFG_DMATC(3)                         /*!< DMA transfer 4 times */
+#define TIMER_DMACFG_DMATC_5TRANSFER        DMACFG_DMATC(4)                         /*!< DMA transfer 5 times */
+#define TIMER_DMACFG_DMATC_6TRANSFER        DMACFG_DMATC(5)                         /*!< DMA transfer 6 times */
+#define TIMER_DMACFG_DMATC_7TRANSFER        DMACFG_DMATC(6)                         /*!< DMA transfer 7 times */
+#define TIMER_DMACFG_DMATC_8TRANSFER        DMACFG_DMATC(7)                         /*!< DMA transfer 8 times */
+#define TIMER_DMACFG_DMATC_9TRANSFER        DMACFG_DMATC(8)                         /*!< DMA transfer 9 times */
+#define TIMER_DMACFG_DMATC_10TRANSFER       DMACFG_DMATC(9)                         /*!< DMA transfer 10 times */
+#define TIMER_DMACFG_DMATC_11TRANSFER       DMACFG_DMATC(10)                        /*!< DMA transfer 11 times */
+#define TIMER_DMACFG_DMATC_12TRANSFER       DMACFG_DMATC(11)                        /*!< DMA transfer 12 times */
+#define TIMER_DMACFG_DMATC_13TRANSFER       DMACFG_DMATC(12)                        /*!< DMA transfer 13 times */
+#define TIMER_DMACFG_DMATC_14TRANSFER       DMACFG_DMATC(13)                        /*!< DMA transfer 14 times */
+#define TIMER_DMACFG_DMATC_15TRANSFER       DMACFG_DMATC(14)                        /*!< DMA transfer 15 times */
+#define TIMER_DMACFG_DMATC_16TRANSFER       DMACFG_DMATC(15)                        /*!< DMA transfer 16 times */
+#define TIMER_DMACFG_DMATC_17TRANSFER       DMACFG_DMATC(16)                        /*!< DMA transfer 17 times */
+#define TIMER_DMACFG_DMATC_18TRANSFER       DMACFG_DMATC(17)                        /*!< DMA transfer 18 times */
+
+/* TIMER software event generation source */
+#define TIMER_EVENT_SRC_UPG                 ((uint16_t)0x0001U)                     /*!< update event generation */
+#define TIMER_EVENT_SRC_CH0G                ((uint16_t)0x0002U)                     /*!< channel 0 capture or compare event generation */
+#define TIMER_EVENT_SRC_CH1G                ((uint16_t)0x0004U)                     /*!< channel 1 capture or compare event generation */
+#define TIMER_EVENT_SRC_CH2G                ((uint16_t)0x0008U)                     /*!< channel 2 capture or compare event generation */
+#define TIMER_EVENT_SRC_CH3G                ((uint16_t)0x0010U)                     /*!< channel 3 capture or compare event generation */
+#define TIMER_EVENT_SRC_CMTG                ((uint16_t)0x0020U)                     /*!< channel commutation event generation */
+#define TIMER_EVENT_SRC_TRGG                ((uint16_t)0x0040U)                     /*!< trigger event generation */
+#define TIMER_EVENT_SRC_BRKG                ((uint16_t)0x0080U)                     /*!< break event generation */
+
+/* center-aligned mode selection */
+#define CTL0_CAM(regval)                    ((uint16_t)(BITS(5, 6) & ((uint32_t)(regval) << 5U)))
+#define TIMER_COUNTER_EDGE                  CTL0_CAM(0)                             /*!< edge-aligned mode */
+#define TIMER_COUNTER_CENTER_DOWN           CTL0_CAM(1)                             /*!< center-aligned and counting down assert mode */
+#define TIMER_COUNTER_CENTER_UP             CTL0_CAM(2)                             /*!< center-aligned and counting up assert mode */
+#define TIMER_COUNTER_CENTER_BOTH           CTL0_CAM(3)                             /*!< center-aligned and counting up/down assert mode */
+
+/* TIMER prescaler reload mode */
+#define TIMER_PSC_RELOAD_NOW                ((uint8_t)0x00U)                        /*!< the prescaler is loaded right now */
+#define TIMER_PSC_RELOAD_UPDATE             ((uint8_t)0x01U)                        /*!< the prescaler is loaded at the next update event */
+
+/* count direction */
+#define TIMER_COUNTER_UP                    ((uint16_t)0x0000U)                     /*!< counter up direction */
+#define TIMER_COUNTER_DOWN                  ((uint16_t)0x0010U)                     /*!< counter down direction */
+
+/* specify division ratio between TIMER clock and dead-time and sampling clock */
+#define CTL0_CKDIV(regval)                  ((uint16_t)(BITS(8, 9) & ((uint32_t)(regval) << 8U)))
+#define TIMER_CKDIV_DIV1                    CTL0_CKDIV(0)                           /*!< clock division value is 1, fDTS=fTIMER_CK */
+#define TIMER_CKDIV_DIV2                    CTL0_CKDIV(1)                           /*!< clock division value is 2, fDTS= fTIMER_CK/2 */
+#define TIMER_CKDIV_DIV4                    CTL0_CKDIV(2)                           /*!< clock division value is 4, fDTS= fTIMER_CK/4 */
+
+/* single pulse mode */
+#define TIMER_SP_MODE_SINGLE                ((uint8_t)0x00U)                        /*!< single pulse mode */
+#define TIMER_SP_MODE_REPETITIVE            ((uint8_t)0x01U)                        /*!< repetitive pulse mode */
+
+/* update source */
+#define TIMER_UPDATE_SRC_REGULAR            ((uint8_t)0x00U)                        /*!< update generate only by counter overflow/underflow */
+#define TIMER_UPDATE_SRC_GLOBAL             ((uint8_t)0x01U)                        /*!< update generate by setting of UPG bit or the counter overflow/underflow,or the slave mode controller trigger */
+
+/* run mode off-state configure */
+#define TIMER_ROS_STATE_ENABLE              ((uint32_t)0x00000800U)                 /*!< when POEN bit is set, the channel output signals (CHx_O/CHx_ON) are enabled, with relationship to CHxEN/CHxNEN bits */
+#define TIMER_ROS_STATE_DISABLE             ((uint32_t)0x00000000U)                 /*!< when POEN bit is set, the channel output signals (CHx_O/CHx_ON) are disabled */
+
+/* idle mode off-state configure */
+#define TIMER_IOS_STATE_ENABLE              ((uint16_t)0x0400U)                     /*!< when POEN bit is reset, he channel output signals (CHx_O/CHx_ON) are enabled, with relationship to CHxEN/CHxNEN bits */
+#define TIMER_IOS_STATE_DISABLE             ((uint16_t)0x0000U)                     /*!< when POEN bit is reset, the channel output signals (CHx_O/CHx_ON) are disabled */
+
+/* break input polarity */
+#define TIMER_BREAK_POLARITY_LOW            ((uint16_t)0x0000U)                     /*!< break input polarity is low */
+#define TIMER_BREAK_POLARITY_HIGH           ((uint16_t)0x2000U)                     /*!< break input polarity is high */
+
+/* output automatic enable */
+#define TIMER_OUTAUTO_ENABLE                ((uint16_t)0x4000U)                     /*!< output automatic enable */
+#define TIMER_OUTAUTO_DISABLE               ((uint16_t)0x0000U)                     /*!< output automatic disable */
+
+/* complementary register protect control */
+#define CCHP_PROT(regval)                   ((uint16_t)(BITS(8, 9) & ((uint32_t)(regval) << 8U)))
+#define TIMER_CCHP_PROT_OFF                 CCHP_PROT(0)                            /*!< protect disable */
+#define TIMER_CCHP_PROT_0                   CCHP_PROT(1)                            /*!< PROT mode 0 */
+#define TIMER_CCHP_PROT_1                   CCHP_PROT(2)                            /*!< PROT mode 1 */
+#define TIMER_CCHP_PROT_2                   CCHP_PROT(3)                            /*!< PROT mode 2 */
+
+/* break input enable */
+#define TIMER_BREAK_ENABLE                  ((uint16_t)0x1000U)                     /*!< break input enable */
+#define TIMER_BREAK_DISABLE                 ((uint16_t)0x0000U)                     /*!< break input disable */
+
+/* TIMER channel n(n=0,1,2,3) */
+#define TIMER_CH_0                          ((uint16_t)0x0000U)                     /*!< TIMER channel 0(TIMERx(x=0..2,13..16)) */
+#define TIMER_CH_1                          ((uint16_t)0x0001U)                     /*!< TIMER channel 1(TIMERx(x=0..2,14)) */
+#define TIMER_CH_2                          ((uint16_t)0x0002U)                     /*!< TIMER channel 2(TIMERx(x=0..2)) */
+#define TIMER_CH_3                          ((uint16_t)0x0003U)                     /*!< TIMER channel 3(TIMERx(x=0..2)) */
+
+/* channel enable state*/
+#define TIMER_CCX_ENABLE                    ((uint32_t)0x00000001U)                 /*!< channel enable */
+#define TIMER_CCX_DISABLE                   ((uint32_t)0x00000000U)                 /*!< channel disable */
+
+/* channel complementary output enable state*/
+#define TIMER_CCXN_ENABLE                   ((uint16_t)0x0004U)                     /*!< channel complementary enable */
+#define TIMER_CCXN_DISABLE                  ((uint16_t)0x0000U)                     /*!< channel complementary disable */
+
+/* channel output polarity */
+#define TIMER_OC_POLARITY_HIGH              ((uint16_t)0x0000U)                     /*!< channel output polarity is high */
+#define TIMER_OC_POLARITY_LOW               ((uint16_t)0x0002U)                     /*!< channel output polarity is low */
+
+/* channel complementary output polarity */
+#define TIMER_OCN_POLARITY_HIGH             ((uint16_t)0x0000U)                     /*!< channel complementary output polarity is high */
+#define TIMER_OCN_POLARITY_LOW              ((uint16_t)0x0008U)                     /*!< channel complementary output polarity is low */
+
+/* idle state of channel output */
+#define TIMER_OC_IDLE_STATE_HIGH            ((uint16_t)0x0100)                      /*!< idle state of channel output is high */
+#define TIMER_OC_IDLE_STATE_LOW             ((uint16_t)0x0000)                      /*!< idle state of channel output is low */
+
+/* idle state of channel complementary output */
+#define TIMER_OCN_IDLE_STATE_HIGH           ((uint16_t)0x0200U)                     /*!< idle state of channel complementary output is high */
+#define TIMER_OCN_IDLE_STATE_LOW            ((uint16_t)0x0000U)                     /*!< idle state of channel complementary output is low */
+
+/* channel output compare mode */
+#define TIMER_OC_MODE_TIMING                ((uint16_t)0x0000U)                     /*!< timing mode */
+#define TIMER_OC_MODE_ACTIVE                ((uint16_t)0x0010U)                     /*!< active mode */
+#define TIMER_OC_MODE_INACTIVE              ((uint16_t)0x0020U)                     /*!< inactive mode */
+#define TIMER_OC_MODE_TOGGLE                ((uint16_t)0x0030U)                     /*!< toggle mode */
+#define TIMER_OC_MODE_LOW                   ((uint16_t)0x0040U)                     /*!< force low mode */
+#define TIMER_OC_MODE_HIGH                  ((uint16_t)0x0050U)                     /*!< force high mode */
+#define TIMER_OC_MODE_PWM0                  ((uint16_t)0x0060U)                     /*!< PWM0 mode */
+#define TIMER_OC_MODE_PWM1                  ((uint16_t)0x0070U)                     /*!< PWM1 mode*/
+
+/* channel output compare shadow enable */
+#define TIMER_OC_SHADOW_ENABLE              ((uint16_t)0x0008U)                     /*!< channel output shadow state enable */
+#define TIMER_OC_SHADOW_DISABLE             ((uint16_t)0x0000U)                     /*!< channel output shadow state disable */
+
+/* channel output compare fast enable */
+#define TIMER_OC_FAST_ENABLE                ((uint16_t)0x0004)                      /*!< channel output fast function enable */
+#define TIMER_OC_FAST_DISABLE               ((uint16_t)0x0000)                      /*!< channel output fast function disable */
+
+/* channel output compare clear enable */
+#define TIMER_OC_CLEAR_ENABLE               ((uint16_t)0x0080U)                     /*!< channel output clear function enable */
+#define TIMER_OC_CLEAR_DISABLE              ((uint16_t)0x0000U)                     /*!< channel output clear function disable */
+
+/* channel control shadow register update control */
+#define TIMER_UPDATECTL_CCU                 ((uint8_t)0x00U)                        /*!< the shadow registers update by when CMTG bit is set */
+#define TIMER_UPDATECTL_CCUTRI              ((uint8_t)0x01U)                        /*!< the shadow registers update by when CMTG bit is set or an rising edge of TRGI occurs */
+
+/* channel input capture polarity */
+#define TIMER_IC_POLARITY_RISING            ((uint16_t)0x0000U)                     /*!< input capture rising edge */
+#define TIMER_IC_POLARITY_FALLING           ((uint16_t)0x0002U)                     /*!< input capture falling edge */
+#define TIMER_IC_POLARITY_BOTH_EDGE         ((uint16_t)0x000AU)                     /*!< input capture both edge */
+
+/* timer input capture selection */
+#define TIMER_IC_SELECTION_DIRECTTI         ((uint16_t)0x0001U)                     /*!< channel y is configured as input and icy is mapped on CIy */
+#define TIMER_IC_SELECTION_INDIRECTTI       ((uint16_t)0x0002U)                     /*!< channel y is configured as input and icy is mapped on opposite input */
+#define TIMER_IC_SELECTION_ITS              ((uint16_t)0x0003U)                     /*!< channel y is configured as input and icy is mapped on ITS */
+
+/* channel input capture prescaler */
+#define TIMER_IC_PSC_DIV1                   ((uint16_t)0x0000U)                     /*!< no prescaler */
+#define TIMER_IC_PSC_DIV2                   ((uint16_t)0x0004U)                     /*!< divided by 2 */
+#define TIMER_IC_PSC_DIV4                   ((uint16_t)0x0008U)                     /*!< divided by 4*/
+#define TIMER_IC_PSC_DIV8                   ((uint16_t)0x000CU)                     /*!< divided by 8 */
+
+/* trigger selection */
+#define SMCFG_TRGSEL(regval)                (BITS(4, 6) & ((uint32_t)(regval) << 4U))
+#define TIMER_SMCFG_TRGSEL_ITI0              SMCFG_TRGSEL(0)                        /*!< internal trigger 0 */
+#define TIMER_SMCFG_TRGSEL_ITI1              SMCFG_TRGSEL(1)                        /*!< internal trigger 1 */
+#define TIMER_SMCFG_TRGSEL_ITI2              SMCFG_TRGSEL(2)                        /*!< internal trigger 2 */
+#define TIMER_SMCFG_TRGSEL_ITI3              SMCFG_TRGSEL(3)                        /*!< internal trigger 3 */
+#define TIMER_SMCFG_TRGSEL_CI0F_ED           SMCFG_TRGSEL(4)                        /*!< TI0 Edge Detector */
+#define TIMER_SMCFG_TRGSEL_CI0FE0            SMCFG_TRGSEL(5)                        /*!< filtered TIMER input 0 */
+#define TIMER_SMCFG_TRGSEL_CI1FE1            SMCFG_TRGSEL(6)                        /*!< filtered TIMER input 1 */
+#define TIMER_SMCFG_TRGSEL_ETIFP             SMCFG_TRGSEL(7)                        /*!< external trigger */
+
+/* master mode control */
+#define CTL1_MMC(regval)                    (BITS(4, 6) & ((uint32_t)(regval) << 4U))
+#define TIMER_TRI_OUT_SRC_RESET             CTL1_MMC(0)                             /*!< the UPG bit as trigger output */
+#define TIMER_TRI_OUT_SRC_ENABLE            CTL1_MMC(1)                             /*!< the counter enable signal TIMER_CTL0_CEN as trigger output */
+#define TIMER_TRI_OUT_SRC_UPDATE            CTL1_MMC(2)                             /*!< update event as trigger output */
+#define TIMER_TRI_OUT_SRC_CH0               CTL1_MMC(3)                             /*!< a capture or a compare match occurred in channal0 as trigger output TRGO */
+#define TIMER_TRI_OUT_SRC_O0CPRE            CTL1_MMC(4)                             /*!< O0CPRE as trigger output */
+#define TIMER_TRI_OUT_SRC_O1CPRE            CTL1_MMC(5)                             /*!< O1CPRE as trigger output */
+#define TIMER_TRI_OUT_SRC_O2CPRE            CTL1_MMC(6)                             /*!< O2CPRE as trigger output */
+#define TIMER_TRI_OUT_SRC_O3CPRE            CTL1_MMC(7)                             /*!< O3CPRE as trigger output */
+
+/* slave mode control */
+#define SMCFG_SMC(regval)                   (BITS(0, 2) & ((uint32_t)(regval) << 0U))
+#define TIMER_SLAVE_MODE_DISABLE            SMCFG_SMC(0)                            /*!< slave mode disable */
+#define TIMER_QUAD_DECODER_MODE0            SMCFG_SMC(1)                            /*!< quadrature decoder mode 0 */
+#define TIMER_QUAD_DECODER_MODE1            SMCFG_SMC(2)                            /*!< quadrature decoder mode 1 */
+#define TIMER_QUAD_DECODER_MODE2            SMCFG_SMC(3)                            /*!< quadrature decoder mode 2 */
+#define TIMER_SLAVE_MODE_RESTART            SMCFG_SMC(4)                            /*!< restart mode */
+#define TIMER_SLAVE_MODE_PAUSE              SMCFG_SMC(5)                            /*!< pause mode */
+#define TIMER_SLAVE_MODE_EVENT              SMCFG_SMC(6)                            /*!< event mode */
+#define TIMER_SLAVE_MODE_EXTERNAL0          SMCFG_SMC(7)                            /*!< external clock mode 0 */
+
+/* OCPRE clear source selection */
+#define TIMER_OCPRE_CLEAR_SOURCE_CLR        ((uint8_t)0x00U)                        /*!< OCPRE_CLR_INT is connected to the OCPRE_CLR input */
+#define TIMER_OCPRE_CLEAR_SOURCE_ETIF       ((uint8_t)0x01U)                        /*!< OCPRE_CLR_INT is connected to ETIF */
+
+/* master slave mode selection */
+#define TIMER_MASTER_SLAVE_MODE_ENABLE      ((uint8_t)0x00U)                        /*!< master slave mode enable */
+#define TIMER_MASTER_SLAVE_MODE_DISABLE     ((uint8_t)0x01U)                        /*!< master slave mode disable */
+
+/* external trigger prescaler */
+#define SMCFG_ETPSC(regval)                 (BITS(12, 13) & ((uint32_t)(regval) << 12U))
+#define TIMER_EXT_TRI_PSC_OFF               SMCFG_ETPSC(0)                          /*!< no divided */
+#define TIMER_EXT_TRI_PSC_DIV2              SMCFG_ETPSC(1)                          /*!< divided by 2 */
+#define TIMER_EXT_TRI_PSC_DIV4              SMCFG_ETPSC(2)                          /*!< divided by 4 */
+#define TIMER_EXT_TRI_PSC_DIV8              SMCFG_ETPSC(3)                          /*!< divided by 8 */
+
+/* external trigger polarity */
+#define TIMER_ETP_FALLING                   TIMER_SMCFG_ETP                         /*!< active low or falling edge active */
+#define TIMER_ETP_RISING                    ((uint32_t)0x00000000U)                 /*!< active high or rising edge active */
+
+/* channel 0 trigger input selection */
+#define TIMER_HALLINTERFACE_ENABLE          ((uint8_t)0x00U)                        /*!< TIMER hall sensor mode enable */
+#define TIMER_HALLINTERFACE_DISABLE         ((uint8_t)0x01U)                        /*!< TIMER hall sensor mode disable */
+
+/* timerx(x=0,1,2,13,14,15,16) write CHxVAL register selection */
+#define TIMER_CHVSEL_ENABLE                 ((uint16_t)0x0002U)                     /*!< write CHxVAL register selection enable */
+#define TIMER_CHVSEL_DISABLE                ((uint16_t)0x0000U)                     /*!< write CHxVAL register selection disable */
+
+/* the output value selection */
+#define TIMER_OUTSEL_DISABLE                ((uint16_t)0x0000U)                     /*!< output value selection disable */
+#define TIMER_OUTSEL_ENABLE                 ((uint16_t)0x0001U)                     /*!< output value selection enable */
+
+/* timer13 channel 0 input remap */
+#define TIMER13_IRMP(regval)                (BITS(0, 1) & ((uint32_t)(regval) << 0U))
+#define TIMER13_CI0_RMP_GPIO                TIMER13_IRMP(0)                         /*!< timer13 channel 0 input is connected to GPIO(TIMER13_CH0) */
+#define TIMER13_CI0_RMP_RTCCLK              TIMER13_IRMP(1)                         /*!< timer13 channel 0 input is connected to the RTCCLK */
+#define TIMER13_CI0_RMP_HXTAL_DIV32         TIMER13_IRMP(2)                         /*!< timer13 channel 0 input is connected to HXTAL/32 clock */
+#define TIMER13_CI0_RMP_CKOUTSEL            TIMER13_IRMP(3)                         /*!< timer13 channel 0 input is connected to CKOUTSEL */
+
+/* function declarations */
+/* TIMER timebase*/
+/* deinit a TIMER */
+void timer_deinit(uint32_t timer_periph);
+/* initialize TIMER init parameter struct */
+void timer_struct_para_init(timer_parameter_struct *initpara);
+/* initialize TIMER counter */
+void timer_init(uint32_t timer_periph, timer_parameter_struct *initpara);
+/* enable a TIMER */
+void timer_enable(uint32_t timer_periph);
+/* disable a TIMER */
+void timer_disable(uint32_t timer_periph);
+/* enable the auto reload shadow function */
+void timer_auto_reload_shadow_enable(uint32_t timer_periph);
+/* disable the auto reload shadow function */
+void timer_auto_reload_shadow_disable(uint32_t timer_periph);
+/* enable the update event */
+void timer_update_event_enable(uint32_t timer_periph);
+/* disable the update event */
+void timer_update_event_disable(uint32_t timer_periph);
+/* set TIMER counter alignment mode */
+void timer_counter_alignment(uint32_t timer_periph, uint16_t aligned);
+/* set TIMER counter up direction */
+void timer_counter_up_direction(uint32_t timer_periph);
+/* set TIMER counter down direction */
+void timer_counter_down_direction(uint32_t timer_periph);
+/* configure TIMER prescaler */
+void timer_prescaler_config(uint32_t timer_periph, uint16_t prescaler, uint8_t pscreload);
+/* configure TIMER repetition register value */
+void timer_repetition_value_config(uint32_t timer_periph, uint16_t repetition);
+/* configure TIMER autoreload register value */
+void timer_autoreload_value_config(uint32_t timer_periph, uint32_t autoreload);
+/* configure TIMER counter register value */
+void timer_counter_value_config(uint32_t timer_periph, uint32_t counter);
+/* read TIMER counter value */
+uint32_t timer_counter_read(uint32_t timer_periph);
+/* read TIMER prescaler value */
+uint16_t timer_prescaler_read(uint32_t timer_periph);
+/* configure TIMER single pulse mode */
+void timer_single_pulse_mode_config(uint32_t timer_periph, uint8_t spmode);
+/* configure TIMER update source */
+void timer_update_source_config(uint32_t timer_periph, uint8_t update);
+/* OCPRE clear source selection */
+void timer_ocpre_clear_source_config(uint32_t timer_periph, uint8_t ocpreclear);
+
+/* TIMER interrupt and flag*/
+/* get TIMER flags */
+FlagStatus timer_flag_get(uint32_t timer_periph, uint32_t flag);
+/* clear TIMER flags */
+void timer_flag_clear(uint32_t timer_periph, uint32_t flag);
+/* enable the TIMER interrupt */
+void timer_interrupt_enable(uint32_t timer_periph, uint32_t interrupt);
+/* disable the TIMER interrupt */
+void timer_interrupt_disable(uint32_t timer_periph, uint32_t interrupt);
+/* get TIMER interrupt flag */
+FlagStatus timer_interrupt_flag_get(uint32_t timer_periph, uint32_t interrupt);
+/* clear TIMER interrupt flag */
+void timer_interrupt_flag_clear(uint32_t timer_periph, uint32_t interrupt);
+
+/* TIMER DMA and event*/
+/* enable the TIMER DMA */
+void timer_dma_enable(uint32_t timer_periph, uint16_t dma);
+/* disable the TIMER DMA */
+void timer_dma_disable(uint32_t timer_periph, uint16_t dma);
+/* channel DMA request source selection */
+void timer_channel_dma_request_source_select(uint32_t timer_periph, uint8_t dma_request);
+/* configure the TIMER DMA transfer */
+void timer_dma_transfer_config(uint32_t timer_periph, uint32_t dma_baseaddr, uint32_t dma_lenth);
+/* software generate events */
+void timer_event_software_generate(uint32_t timer_periph, uint16_t event);
+
+/* TIMER channel complementary protection */
+/* initialize TIMER break parameter struct */
+void timer_break_struct_para_init(timer_break_parameter_struct *breakpara);
+/* configure TIMER break function */
+void timer_break_config(uint32_t timer_periph, timer_break_parameter_struct *breakpara);
+/* enable TIMER break function */
+void timer_break_enable(uint32_t timer_periph);
+/* disable TIMER break function */
+void timer_break_disable(uint32_t timer_periph);
+/* enable TIMER output automatic function */
+void timer_automatic_output_enable(uint32_t timer_periph);
+/* disable TIMER output automatic function */
+void timer_automatic_output_disable(uint32_t timer_periph);
+/* enable or disable TIMER primary output function */
+void timer_primary_output_config(uint32_t timer_periph, ControlStatus newvalue);
+/* enable or disable channel capture/compare control shadow register */
+void timer_channel_control_shadow_config(uint32_t timer_periph, ControlStatus newvalue);
+/* configure TIMER channel control shadow register update control */
+void timer_channel_control_shadow_update_config(uint32_t timer_periph, uint8_t ccuctl);
+
+/* TIMER channel output */
+/* initialize TIMER channel output parameter struct */
+void timer_channel_output_struct_para_init(timer_oc_parameter_struct *ocpara);
+/* configure TIMER channel output function */
+void timer_channel_output_config(uint32_t timer_periph, uint16_t channel, timer_oc_parameter_struct *ocpara);
+/* configure TIMER channel output compare mode */
+void timer_channel_output_mode_config(uint32_t timer_periph, uint16_t channel, uint16_t ocmode);
+/* configure TIMER channel output pulse value */
+void timer_channel_output_pulse_value_config(uint32_t timer_periph, uint16_t channel, uint32_t pulse);
+/* configure TIMER channel output shadow function */
+void timer_channel_output_shadow_config(uint32_t timer_periph, uint16_t channel, uint16_t ocshadow);
+/* configure TIMER channel output fast function */
+void timer_channel_output_fast_config(uint32_t timer_periph, uint16_t channel, uint16_t ocfast);
+/* configure TIMER channel output clear function */
+void timer_channel_output_clear_config(uint32_t timer_periph, uint16_t channel, uint16_t occlear);
+/* configure TIMER channel output polarity */
+void timer_channel_output_polarity_config(uint32_t timer_periph, uint16_t channel, uint16_t ocpolarity);
+/* configure TIMER channel complementary output polarity */
+void timer_channel_complementary_output_polarity_config(uint32_t timer_periph, uint16_t channel, uint16_t ocnpolarity);
+/* configure TIMER channel enable state */
+void timer_channel_output_state_config(uint32_t timer_periph, uint16_t channel, uint32_t state);
+/* configure TIMER channel complementary output enable state */
+void timer_channel_complementary_output_state_config(uint32_t timer_periph, uint16_t channel, uint16_t ocnstate);
+
+/* TIMER channel input */
+/* initialize TIMER channel input parameter struct */
+void timer_channel_input_struct_para_init(timer_ic_parameter_struct *icpara);
+/* configure TIMER input capture parameter */
+void timer_input_capture_config(uint32_t timer_periph, uint16_t channel, timer_ic_parameter_struct *icpara);
+/* configure TIMER channel input capture prescaler value */
+void timer_channel_input_capture_prescaler_config(uint32_t timer_periph, uint16_t channel, uint16_t prescaler);
+/* read TIMER channel capture compare register value */
+uint32_t timer_channel_capture_value_register_read(uint32_t timer_periph, uint16_t channel);
+/* configure TIMER input pwm capture function */
+void timer_input_pwm_capture_config(uint32_t timer_periph, uint16_t channel, timer_ic_parameter_struct *icpwm);
+/* configure TIMER hall sensor mode */
+void timer_hall_mode_config(uint32_t timer_periph, uint8_t hallmode);
+
+/* TIMER master and slave */
+/* select TIMER input trigger source */
+void timer_input_trigger_source_select(uint32_t timer_periph, uint32_t intrigger);
+/* select TIMER master mode output trigger source */
+void timer_master_output_trigger_source_select(uint32_t timer_periph, uint32_t outrigger);
+/* select TIMER slave mode */
+void timer_slave_mode_select(uint32_t timer_periph, uint32_t slavemode);
+/* configure TIMER master slave mode */
+void timer_master_slave_mode_config(uint32_t timer_periph, uint8_t masterslave);
+/* configure TIMER external trigger input */
+void timer_external_trigger_config(uint32_t timer_periph, uint32_t extprescaler, uint32_t extpolarity, uint32_t extfilter);
+/* configure TIMER quadrature decoder mode */
+void timer_quadrature_decoder_mode_config(uint32_t timer_periph, uint32_t decomode, uint16_t ic0polarity, uint16_t ic1polarity);
+/* configure TIMER internal clock mode */
+void timer_internal_clock_config(uint32_t timer_periph);
+/* configure TIMER the internal trigger as external clock input */
+void timer_internal_trigger_as_external_clock_config(uint32_t timer_periph, uint32_t intrigger);
+/* configure TIMER the external trigger as external clock input */
+void timer_external_trigger_as_external_clock_config(uint32_t timer_periph, uint32_t extrigger, uint16_t extpolarity, uint32_t extfilter);
+/* configure TIMER the external clock mode 0 */
+void timer_external_clock_mode0_config(uint32_t timer_periph, uint32_t extprescaler, uint32_t extpolarity, uint32_t extfilter);
+/* configure TIMER the external clock mode 1 */
+void timer_external_clock_mode1_config(uint32_t timer_periph, uint32_t extprescaler, uint32_t extpolarity, uint32_t extfilter);
+/* disable TIMER the external clock mode 1 */
+void timer_external_clock_mode1_disable(uint32_t timer_periph);
+/* configure TIMER channel remap function */
+void timer_channel_remap_config(uint32_t timer_periph, uint32_t remap);
+
+/* TIMER configure */
+/* configure TIMER write CHxVAL register selection */
+void timer_write_chxval_register_config(uint32_t timer_periph, uint16_t ccsel);
+/* configure TIMER output value selection */
+void timer_output_value_selection_config(uint32_t timer_periph, uint16_t outsel);
+
+#endif /* GD32F3X0_TIMER_H */

+ 390 - 0
GD32F3x0/GD32F3x0_standard_peripheral/Include/gd32f3x0_tsi.h

@@ -0,0 +1,390 @@
+/*!
+    \file    gd32f3x0_tsi.h
+    \brief   definitions for the TSI
+
+    \version 2025-01-01, V2.5.0, firmware for GD32F3x0
+*/
+
+/*
+    Copyright (c) 2025, GigaDevice Semiconductor Inc.
+
+    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 of the copyright holder 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 HOLDER 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.
+*/
+
+#if defined (GD32F350) || defined (GD32F355) || defined (GD32F370)
+
+#ifndef GD32F3X0_TSI_H
+#define GD32F3X0_TSI_H
+
+#include "gd32f3x0.h"
+
+/* TSI definitions */
+#define TSI                     TSI_BASE                    /*!< TSI base address */
+
+/* registers definitions */
+#define TSI_CTL0                REG32(TSI + 0x00000000U)    /*!< TSI control register 0 */
+#define TSI_INTEN               REG32(TSI + 0x00000004U)    /*!< TSI interrupt enable register */
+#define TSI_INTC                REG32(TSI + 0x00000008U)    /*!< TSI interrupt flag clear register */
+#define TSI_INTF                REG32(TSI + 0x0000000CU)    /*!< TSI interrupt flag register */
+#define TSI_PHM                 REG32(TSI + 0x00000010U)    /*!< TSI pin hysteresis mode register */
+#define TSI_ASW                 REG32(TSI + 0x00000018U)    /*!< TSI analog switch register */
+#define TSI_SAMPCFG             REG32(TSI + 0x00000020U)    /*!< TSI sample configuration register */
+#define TSI_CHCFG               REG32(TSI + 0x00000028U)    /*!< TSI channel configuration register */
+#define TSI_GCTL                REG32(TSI + 0x00000030U)    /*!< TSI group control register */
+#define TSI_G0CYCN              REG32(TSI + 0x00000034U)    /*!< TSI group 0 cycle number register */
+#define TSI_G1CYCN              REG32(TSI + 0x00000038U)    /*!< TSI group 1 cycle number register */
+#define TSI_G2CYCN              REG32(TSI + 0x0000003CU)    /*!< TSI group 2 cycle number register */
+#define TSI_G3CYCN              REG32(TSI + 0x00000040U)    /*!< TSI group 3 cycle number register */
+#define TSI_G4CYCN              REG32(TSI + 0x00000044U)    /*!< TSI group 4 cycle number register */
+#define TSI_G5CYCN              REG32(TSI + 0x00000048U)    /*!< TSI group 5 cycle number register */
+#define TSI_CTL1                REG32(TSI + 0x00000300U)    /*!< TSI control registers1 */
+
+/* bits definitions */
+/* TSI_CTL0 */
+#define TSI_CTL0_TSIEN          BIT(0)                      /*!< TSI enable */
+#define TSI_CTL0_TSIS           BIT(1)                      /*!< TSI start */
+#define TSI_CTL0_TRGMOD         BIT(2)                      /*!< trigger mode selection */
+#define TSI_CTL0_EGSEL          BIT(3)                      /*!< edge selection */
+#define TSI_CTL0_PINMOD         BIT(4)                      /*!< pin mode */
+#define TSI_CTL0_MCN            BITS(5,7)                   /*!< max cycle number of a sequence */
+#define TSI_CTL0_CTCDIV         BITS(12,14)                 /*!< CTCLK clock division factor */
+#define TSI_CTL0_ECDIV          BIT(15)                     /*!< ECCLK clock division factor */
+#define TSI_CTL0_ECEN           BIT(16)                     /*!< extend charge state enable */
+#define TSI_CTL0_ECDT           BITS(17,23)                 /*!< extend charge state maximum duration time */
+#define TSI_CTL0_CTDT           BITS(24,27)                 /*!< charge transfer state duration time */
+#define TSI_CTL0_CDT            BITS(28,31)                 /*!< charge state duration time */
+
+/* TSI_INTEN */
+#define TSI_INTEN_CTCFIE        BIT(0)                      /*!< charge transfer complete flag interrupt enable */
+#define TSI_INTEN_MNERRIE       BIT(1)                      /*!< max cycle number error interrupt enable */
+
+/* TSI_INTC */
+#define TSI_INTC_CCTCF          BIT(0)                      /*!< clear charge transfer complete flag */
+#define TSI_INTC_CMNERR         BIT(1)                      /*!< clear max cycle number error */
+
+/* TSI_INTF */
+#define TSI_INTF_CTCF           BIT(0)                      /*!< charge transfer complete flag */
+#define TSI_INTF_MNERR          BIT(1)                      /*!< max cycle number error */
+
+/* TSI_PHM */
+#define TSI_PHM_G0P0            BIT(0)                      /*!< pin G0P0 Schmitt trigger hysteresis state */
+#define TSI_PHM_G0P1            BIT(1)                      /*!< pin G0P1 Schmitt trigger hysteresis state */
+#define TSI_PHM_G0P2            BIT(2)                      /*!< pin G0P2 Schmitt trigger hysteresis state */
+#define TSI_PHM_G0P3            BIT(3)                      /*!< pin G0P3 Schmitt trigger hysteresis state */
+#define TSI_PHM_G1P0            BIT(4)                      /*!< pin G1P0 Schmitt trigger hysteresis state */
+#define TSI_PHM_G1P1            BIT(5)                      /*!< pin G1P1 Schmitt trigger hysteresis state */
+#define TSI_PHM_G1P2            BIT(6)                      /*!< pin G1P2 Schmitt trigger hysteresis state */
+#define TSI_PHM_G1P3            BIT(7)                      /*!< pin G1P3 Schmitt trigger hysteresis state */
+#define TSI_PHM_G2P0            BIT(8)                      /*!< pin G2P0 Schmitt trigger hysteresis state */
+#define TSI_PHM_G2P1            BIT(9)                      /*!< pin G2P1 Schmitt trigger hysteresis state */
+#define TSI_PHM_G2P2            BIT(10)                     /*!< pin G2P2 Schmitt trigger hysteresis state */
+#define TSI_PHM_G2P3            BIT(11)                     /*!< pin G2P3 Schmitt trigger hysteresis state */
+#define TSI_PHM_G3P0            BIT(12)                     /*!< pin G3P0 Schmitt trigger hysteresis state */
+#define TSI_PHM_G3P1            BIT(13)                     /*!< pin G3P1 Schmitt trigger hysteresis state */
+#define TSI_PHM_G3P2            BIT(14)                     /*!< pin G3P2 Schmitt trigger hysteresis state */
+#define TSI_PHM_G3P3            BIT(15)                     /*!< pin G3P3 Schmitt trigger hysteresis state */
+#define TSI_PHM_G4P0            BIT(16)                     /*!< pin G4P0 Schmitt trigger hysteresis state */
+#define TSI_PHM_G4P1            BIT(17)                     /*!< pin G4P1 Schmitt trigger hysteresis state */
+#define TSI_PHM_G4P2            BIT(18)                     /*!< pin G4P2 Schmitt trigger hysteresis state */
+#define TSI_PHM_G4P3            BIT(19)                     /*!< pin G4P3 Schmitt trigger hysteresis state */
+#define TSI_PHM_G5P0            BIT(20)                     /*!< pin G5P0 Schmitt trigger hysteresis state */
+#define TSI_PHM_G5P1            BIT(21)                     /*!< pin G5P1 Schmitt trigger hysteresis state */
+#define TSI_PHM_G5P2            BIT(22)                     /*!< pin G5P2 Schmitt trigger hysteresis state */
+#define TSI_PHM_G5P3            BIT(23)                     /*!< pin G5P3 Schmitt trigger hysteresis state */
+
+/* TSI_ASW */
+#define TSI_ASW_G0P0            BIT(0)                      /*!< pin G0P0 analog switch state */
+#define TSI_ASW_G0P1            BIT(1)                      /*!< pin G0P1 analog switch state */
+#define TSI_ASW_G0P2            BIT(2)                      /*!< pin G0P2 analog switch state */
+#define TSI_ASW_G0P3            BIT(3)                      /*!< pin G0P3 analog switch state */
+#define TSI_ASW_G1P0            BIT(4)                      /*!< pin G1P0 analog switch state */
+#define TSI_ASW_G1P1            BIT(5)                      /*!< pin G1P1 analog switch state */
+#define TSI_ASW_G1P2            BIT(6)                      /*!< pin G1P2 analog switch state */
+#define TSI_ASW_G1P3            BIT(7)                      /*!< pin G1P3 analog switch state */
+#define TSI_ASW_G2P0            BIT(8)                      /*!< pin G2P0 analog switch state */
+#define TSI_ASW_G2P1            BIT(9)                      /*!< pin G2P1 analog switch state */
+#define TSI_ASW_G2P2            BIT(10)                     /*!< pin G2P2 analog switch state */
+#define TSI_ASW_G2P3            BIT(11)                     /*!< pin G2P3 analog switch state */
+#define TSI_ASW_G3P0            BIT(12)                     /*!< pin G3P0 analog switch state */
+#define TSI_ASW_G3P1            BIT(13)                     /*!< pin G3P1 analog switch state */
+#define TSI_ASW_G3P2            BIT(14)                     /*!< pin G3P2 analog switch state */
+#define TSI_ASW_G3P3            BIT(15)                     /*!< pin G3P3 analog switch state */
+#define TSI_ASW_G4P0            BIT(16)                     /*!< pin G4P0 analog switch state */
+#define TSI_ASW_G4P1            BIT(17)                     /*!< pin G4P1 analog switch state */
+#define TSI_ASW_G4P2            BIT(18)                     /*!< pin G4P2 analog switch state */
+#define TSI_ASW_G4P3            BIT(19)                     /*!< pin G4P3 analog switch state */
+#define TSI_ASW_G5P0            BIT(20)                     /*!< pin G5P0 analog switch state */
+#define TSI_ASW_G5P1            BIT(21)                     /*!< pin G5P1 analog switch state */
+#define TSI_ASW_G5P2            BIT(22)                     /*!< pin G5P2 analog switch state */
+#define TSI_ASW_G5P3            BIT(23)                     /*!< pin G5P3 analog switch state */
+
+/* TSI_SAMPCFG */
+#define TSI_SAMPCFG_G0P0        BIT(0)                      /*!< pin G0P0 sample pin mode */
+#define TSI_SAMPCFG_G0P1        BIT(1)                      /*!< pin G0P1 sample pin mode */
+#define TSI_SAMPCFG_G0P2        BIT(2)                      /*!< pin G0P2 sample pin mode */
+#define TSI_SAMPCFG_G0P3        BIT(3)                      /*!< pin G0P3 sample pin mode */
+#define TSI_SAMPCFG_G1P0        BIT(4)                      /*!< pin G1P0 sample pin mode */
+#define TSI_SAMPCFG_G1P1        BIT(5)                      /*!< pin G1P1 sample pin mode */
+#define TSI_SAMPCFG_G1P2        BIT(6)                      /*!< pin G1P2 sample pin mode */
+#define TSI_SAMPCFG_G1P3        BIT(7)                      /*!< pin G1P3 sample pin mode */
+#define TSI_SAMPCFG_G2P0        BIT(8)                      /*!< pin G2P0 sample pin mode */
+#define TSI_SAMPCFG_G2P1        BIT(9)                      /*!< pin G2P1 sample pin mode */
+#define TSI_SAMPCFG_G2P2        BIT(10)                     /*!< pin G2P2 sample pin mode */
+#define TSI_SAMPCFG_G2P3        BIT(11)                     /*!< pin G2P3 sample pin mode */
+#define TSI_SAMPCFG_G3P0        BIT(12)                     /*!< pin G3P0 sample pin mode */
+#define TSI_SAMPCFG_G3P1        BIT(13)                     /*!< pin G3P1 sample pin mode */
+#define TSI_SAMPCFG_G3P2        BIT(14)                     /*!< pin G3P2 sample pin mode */
+#define TSI_SAMPCFG_G3P3        BIT(15)                     /*!< pin G3P3 sample pin mode */
+#define TSI_SAMPCFG_G4P0        BIT(16)                     /*!< pin G4P0 sample pin mode */
+#define TSI_SAMPCFG_G4P1        BIT(17)                     /*!< pin G4P1 sample pin mode */
+#define TSI_SAMPCFG_G4P2        BIT(18)                     /*!< pin G4P2 sample pin mode */
+#define TSI_SAMPCFG_G4P3        BIT(19)                     /*!< pin G4P3 sample pin mode */
+#define TSI_SAMPCFG_G5P0        BIT(20)                     /*!< pin G5P0 sample pin mode */
+#define TSI_SAMPCFG_G5P1        BIT(21)                     /*!< pin G5P1 sample pin mode */
+#define TSI_SAMPCFG_G5P2        BIT(22)                     /*!< pin G5P2 sample pin mode */
+#define TSI_SAMPCFG_G5P3        BIT(23)                     /*!< pin G5P3 sample pin mode */
+
+/* TSI_CHCFG */
+#define TSI_CHCFG_G0P0          BIT(0)                      /*!< pin G0P0 channel pin mode */
+#define TSI_CHCFG_G0P1          BIT(1)                      /*!< pin G0P1 channel pin mode */
+#define TSI_CHCFG_G0P2          BIT(2)                      /*!< pin G0P2 channel pin mode */
+#define TSI_CHCFG_G0P3          BIT(3)                      /*!< pin G0P3 channel pin mode */
+#define TSI_CHCFG_G1P0          BIT(4)                      /*!< pin G1P0 channel pin mode */
+#define TSI_CHCFG_G1P1          BIT(5)                      /*!< pin G1P1 channel pin mode */
+#define TSI_CHCFG_G1P2          BIT(6)                      /*!< pin G1P2 channel pin mode */
+#define TSI_CHCFG_G1P3          BIT(7)                      /*!< pin G1P3 channel pin mode */
+#define TSI_CHCFG_G2P0          BIT(8)                      /*!< pin G2P0 channel pin mode */
+#define TSI_CHCFG_G2P1          BIT(9)                      /*!< pin G2P1 channel pin mode */
+#define TSI_CHCFG_G2P2          BIT(10)                     /*!< pin G2P2 channel pin mode */
+#define TSI_CHCFG_G2P3          BIT(11)                     /*!< pin G2P3 channel pin mode */
+#define TSI_CHCFG_G3P0          BIT(12)                     /*!< pin G3P0 channel pin mode */
+#define TSI_CHCFG_G3P1          BIT(13)                     /*!< pin G3P1 channel pin mode */
+#define TSI_CHCFG_G3P2          BIT(14)                     /*!< pin G3P2 channel pin mode */
+#define TSI_CHCFG_G3P3          BIT(15)                     /*!< pin G3P3 channel pin mode */
+#define TSI_CHCFG_G4P0          BIT(16)                     /*!< pin G4P0 channel pin mode */
+#define TSI_CHCFG_G4P1          BIT(17)                     /*!< pin G4P1 channel pin mode */
+#define TSI_CHCFG_G4P2          BIT(18)                     /*!< pin G4P2 channel pin mode */
+#define TSI_CHCFG_G4P3          BIT(19)                     /*!< pin G4P3 channel pin mode */
+#define TSI_CHCFG_G5P0          BIT(20)                     /*!< pin G5P0 channel pin mode */
+#define TSI_CHCFG_G5P1          BIT(21)                     /*!< pin G5P1 channel pin mode */
+#define TSI_CHCFG_G5P2          BIT(22)                     /*!< pin G5P2 channel pin mode */
+#define TSI_CHCFG_G5P3          BIT(23)                     /*!< pin G5P3 channel pin mode */
+
+/* TSI_GCTL */
+#define TSI_GCTL_GE0            BIT(0)                      /*!< group0 enable */
+#define TSI_GCTL_GE1            BIT(1)                      /*!< group1 enable */
+#define TSI_GCTL_GE2            BIT(2)                      /*!< group2 enable */
+#define TSI_GCTL_GE3            BIT(3)                      /*!< group3 enable */
+#define TSI_GCTL_GE4            BIT(4)                      /*!< group4 enable */
+#define TSI_GCTL_GE5            BIT(5)                      /*!< group5 enable */
+#define TSI_GCTL_GC0            BIT(16)                     /*!< group0 complete */
+#define TSI_GCTL_GC1            BIT(17)                     /*!< group1 complete */
+#define TSI_GCTL_GC2            BIT(18)                     /*!< group2 complete */
+#define TSI_GCTL_GC3            BIT(19)                     /*!< group3 complete */
+#define TSI_GCTL_GC4            BIT(20)                     /*!< group4 complete */
+#define TSI_GCTL_GC5            BIT(21)                     /*!< group5 complete */
+
+/* TSI_CTL1 */
+#define TSI_CTL1_CTCDIV         BIT(24)                     /*!< CTCLK clock division factor */
+#define TSI_CTL1_ECDIV          BITS(28,29)                 /*!< ECCLK clock division factor */
+
+/* constants definitions */
+/* TSI interrupt enable bit */
+#define TSI_INT_CCTCF           TSI_INTEN_CTCFIE            /*!< charge transfer complete flag interrupt enable */
+#define TSI_INT_MNERR           TSI_INTEN_MNERRIE           /*!< max cycle number error interrupt enable */
+
+/* TSI interrupt flags */
+#define TSI_INT_FLAG_CTCF       TSI_INTF_CTCF               /*!< charge transfer complete flag */
+#define TSI_INT_FLAG_MNERR      TSI_INTF_MNERR              /*!< max cycle number error */
+
+/* TSI flags */
+#define TSI_FLAG_CTCF           TSI_INTF_CTCF               /*!< charge transfer complete flag */
+#define TSI_FLAG_MNERR          TSI_INTF_MNERR              /*!< max cycle number error */
+
+/* CTCLK clock division factor */
+#define TSI_CTCDIV_DIV1         ((uint32_t)0x00000000U)     /*!< fCTCLK = fHCLK */
+#define TSI_CTCDIV_DIV2         ((uint32_t)0x00000001U)     /*!< fCTCLK = fHCLK/2 */
+#define TSI_CTCDIV_DIV4         ((uint32_t)0x00000002U)     /*!< fCTCLK = fHCLK/4 */
+#define TSI_CTCDIV_DIV8         ((uint32_t)0x00000003U)     /*!< fCTCLK = fHCLK/8 */
+#define TSI_CTCDIV_DIV16        ((uint32_t)0x00000004U)     /*!< fCTCLK = fHCLK/16 */
+#define TSI_CTCDIV_DIV32        ((uint32_t)0x00000005U)     /*!< fCTCLK = fHCLK/32 */
+#define TSI_CTCDIV_DIV64        ((uint32_t)0x00000006U)     /*!< fCTCLK = fHCLK/64 */
+#define TSI_CTCDIV_DIV128       ((uint32_t)0x00000007U)     /*!< fCTCLK = fHCLK/128 */
+#define TSI_CTCDIV_DIV256       ((uint32_t)0x00000008U)     /*!< fCTCLK = fHCLK/256 */
+#define TSI_CTCDIV_DIV512       ((uint32_t)0x00000009U)     /*!< fCTCLK = fHCLK/512 */
+#define TSI_CTCDIV_DIV1024      ((uint32_t)0x0000000AU)     /*!< fCTCLK = fHCLK/1024 */
+#define TSI_CTCDIV_DIV2048      ((uint32_t)0x0000000BU)     /*!< fCTCLK = fHCLK/2048 */
+#define TSI_CTCDIV_DIV4096      ((uint32_t)0x0000000CU)     /*!< fCTCLK = fHCLK/4096 */
+#define TSI_CTCDIV_DIV8192      ((uint32_t)0x0000000DU)     /*!< fCTCLK = fHCLK/8192 */
+#define TSI_CTCDIV_DIV16384     ((uint32_t)0x0000000EU)     /*!< fCTCLK = fHCLK/16384 */
+#define TSI_CTCDIV_DIV32768     ((uint32_t)0x0000000FU)     /*!< fCTCLK = fHCLK/32768 */
+
+/* charge transfer state duration Time */
+#define CTL_CTDT(regval)        (BITS(24,27) & ((uint32_t)(regval) << 24U))
+#define TSI_TRANSFER_1CTCLK     CTL_CTDT(0)                 /*!< the duration time of transfer state is 1 CTCLK */
+#define TSI_TRANSFER_2CTCLK     CTL_CTDT(1)                 /*!< the duration time of transfer state is 2 CTCLK */
+#define TSI_TRANSFER_3CTCLK     CTL_CTDT(2)                 /*!< the duration time of transfer state is 3 CTCLK */
+#define TSI_TRANSFER_4CTCLK     CTL_CTDT(3)                 /*!< the duration time of transfer state is 4 CTCLK */
+#define TSI_TRANSFER_5CTCLK     CTL_CTDT(4)                 /*!< the duration time of transfer state is 5 CTCLK */
+#define TSI_TRANSFER_6CTCLK     CTL_CTDT(5)                 /*!< the duration time of transfer state is 6 CTCLK */
+#define TSI_TRANSFER_7CTCLK     CTL_CTDT(6)                 /*!< the duration time of transfer state is 7 CTCLK */
+#define TSI_TRANSFER_8CTCLK     CTL_CTDT(7)                 /*!< the duration time of transfer state is 8 CTCLK */
+#define TSI_TRANSFER_9CTCLK     CTL_CTDT(8)                 /*!< the duration time of transfer state is 9 CTCLK */
+#define TSI_TRANSFER_10CTCLK    CTL_CTDT(9)                 /*!< the duration time of transfer state is 10 CTCLK */
+#define TSI_TRANSFER_11CTCLK    CTL_CTDT(10)                /*!< the duration time of transfer state is 11 CTCLK */
+#define TSI_TRANSFER_12CTCLK    CTL_CTDT(11)                /*!< the duration time of transfer state is 12 CTCLK */
+#define TSI_TRANSFER_13CTCLK    CTL_CTDT(12)                /*!< the duration time of transfer state is 13 CTCLK */
+#define TSI_TRANSFER_14CTCLK    CTL_CTDT(13)                /*!< the duration time of transfer state is 14 CTCLK */
+#define TSI_TRANSFER_15CTCLK    CTL_CTDT(14)                /*!< the duration time of transfer state is 15 CTCLK */
+#define TSI_TRANSFER_16CTCLK    CTL_CTDT(15)                /*!< the duration time of transfer state is 16 CTCLK */
+
+/* charge state duration time */
+#define CTL_CDT(regval)         (BITS(28,31) & ((uint32_t)(regval) << 28U))
+#define TSI_CHARGE_1CTCLK       CTL_CDT(0)                  /*!< the duration time of charge state is 1 CTCLK */
+#define TSI_CHARGE_2CTCLK       CTL_CDT(1)                  /*!< the duration time of charge state is 2 CTCLK */
+#define TSI_CHARGE_3CTCLK       CTL_CDT(2)                  /*!< the duration time of charge state is 3 CTCLK */
+#define TSI_CHARGE_4CTCLK       CTL_CDT(3)                  /*!< the duration time of charge state is 4 CTCLK */
+#define TSI_CHARGE_5CTCLK       CTL_CDT(4)                  /*!< the duration time of charge state is 5 CTCLK */
+#define TSI_CHARGE_6CTCLK       CTL_CDT(5)                  /*!< the duration time of charge state is 6 CTCLK */
+#define TSI_CHARGE_7CTCLK       CTL_CDT(6)                  /*!< the duration time of charge state is 7 CTCLK */
+#define TSI_CHARGE_8CTCLK       CTL_CDT(7)                  /*!< the duration time of charge state is 8 CTCLK */
+#define TSI_CHARGE_9CTCLK       CTL_CDT(8)                  /*!< the duration time of charge state is 9 CTCLK */
+#define TSI_CHARGE_10CTCLK      CTL_CDT(9)                  /*!< the duration time of charge state is 10 CTCLK */
+#define TSI_CHARGE_11CTCLK      CTL_CDT(10)                 /*!< the duration time of charge state is 11 CTCLK */
+#define TSI_CHARGE_12CTCLK      CTL_CDT(11)                 /*!< the duration time of charge state is 12 CTCLK */
+#define TSI_CHARGE_13CTCLK      CTL_CDT(12)                 /*!< the duration time of charge state is 13 CTCLK */
+#define TSI_CHARGE_14CTCLK      CTL_CDT(13)                 /*!< the duration time of charge state is 14 CTCLK */
+#define TSI_CHARGE_15CTCLK      CTL_CDT(14)                 /*!< the duration time of charge state is 15 CTCLK */
+#define TSI_CHARGE_16CTCLK      CTL_CDT(15)                 /*!< the duration time of charge state is 16 CTCLK */
+
+/* max cycle number of a sequence */
+#define CTL_MCN(regval)         (BITS(5,7) & ((uint32_t)(regval) << 5U))
+#define TSI_MAXNUM255           CTL_MCN(0)                  /*!< the max cycle number of a sequence is 255 */
+#define TSI_MAXNUM511           CTL_MCN(1)                  /*!< the max cycle number of a sequence is 511 */
+#define TSI_MAXNUM1023          CTL_MCN(2)                  /*!< the max cycle number of a sequence is 1023 */
+#define TSI_MAXNUM2047          CTL_MCN(3)                  /*!< the max cycle number of a sequence is 2047 */
+#define TSI_MAXNUM4095          CTL_MCN(4)                  /*!< the max cycle number of a sequence is 4095 */
+#define TSI_MAXNUM8191          CTL_MCN(5)                  /*!< the max cycle number of a sequence is 8191 */
+#define TSI_MAXNUM16383         CTL_MCN(6)                  /*!< the max cycle number of a sequence is 16383 */
+
+/* ECCLK clock division factor */
+#define TSI_EXTEND_DIV1         ((uint32_t)0x00000000U)     /*!< fECCLK = fHCLK */
+#define TSI_EXTEND_DIV2         ((uint32_t)0x00000001U)     /*!< fECCLK = fHCLK/2 */
+#define TSI_EXTEND_DIV3         ((uint32_t)0x00000002U)     /*!< fECCLK = fHCLK/3 */
+#define TSI_EXTEND_DIV4         ((uint32_t)0x00000003U)     /*!< fECCLK = fHCLK/4 */
+#define TSI_EXTEND_DIV5         ((uint32_t)0x00000004U)     /*!< fECCLK = fHCLK/5 */
+#define TSI_EXTEND_DIV6         ((uint32_t)0x00000005U)     /*!< fECCLK = fHCLK/6 */
+#define TSI_EXTEND_DIV7         ((uint32_t)0x00000006U)     /*!< fECCLK = fHCLK/7 */
+#define TSI_EXTEND_DIV8         ((uint32_t)0x00000007U)     /*!< fECCLK = fHCLK/8 */
+
+/* extend charge state maximum duration time */
+#define TSI_EXTENDMAX(regval)   (BITS(17,23) & ((uint32_t)(regval) << 17U)) /* value range 1..128, extend charge state maximum duration time */
+
+/* hardware trigger mode */
+#define TSI_FALLING_TRIGGER     ((uint32_t)0x00000000U)     /*!< falling edge trigger TSI charge transfer sequence */
+#define TSI_RISING_TRIGGER      ((uint32_t)0x00000001U)     /*!< rising edge trigger TSI charge transfer sequence */
+
+/* pin mode */
+#define TSI_OUTPUT_LOW          ((uint32_t)0x00000000U)     /*!< TSI pin will output low when IDLE */
+#define TSI_INPUT_FLOATING      ((uint32_t)0x00000001U)     /*!< TSI pin will keep input_floating when IDLE */
+
+/* function declarations */
+/* reset TSI peripheral */
+void tsi_deinit(void);
+/* initialize TSI pulse prescaler,charge pulse,transfer pulse,max cycle number */
+void tsi_init(uint32_t prescaler, uint32_t charge_duration, uint32_t transfer_duration, uint32_t max_number);
+/* enable TSI module */
+void tsi_enable(void);
+/* disable TSI module */
+void tsi_disable(void);
+/* enable sample pin */
+void tsi_sample_pin_enable(uint32_t sample);
+/* disable sample pin */
+void tsi_sample_pin_disable(uint32_t sample);
+/* enable channel pin */
+void tsi_channel_pin_enable(uint32_t channel);
+/* disable channel pin */
+void tsi_channel_pin_disable(uint32_t channel);
+
+/* configure TSI triggering by software */
+void tsi_software_mode_config(void);
+/* start a charge-transfer sequence when TSI is in software trigger mode */
+void tsi_software_start(void);
+/* stop a charge-transfer sequence when TSI is in software trigger mode */
+void tsi_software_stop(void);
+/* configure TSI triggering by hardware */
+void tsi_hardware_mode_config(uint8_t trigger_edge);
+/* configure TSI pin mode when charge-transfer sequence is IDLE */
+void tsi_pin_mode_config(uint8_t pin_mode);
+/* configure extend charge state */
+void tsi_extend_charge_config(ControlStatus extend, uint8_t prescaler, uint32_t max_duration);
+
+/* configure charge pulse and transfer pulse */
+void tsi_pulse_config(uint32_t prescaler, uint32_t charge_duration, uint32_t transfer_duration);
+/* configure the max cycle number of a charge-transfer sequence */
+void tsi_max_number_config(uint32_t max_number);
+/* switch on hysteresis pin */
+void tsi_hysteresis_on(uint32_t group_pin);
+/* switch off hysteresis pin */
+void tsi_hysteresis_off(uint32_t group_pin);
+/* switch on analog pin */
+void tsi_analog_on(uint32_t group_pin);
+/* switch off analog pin */
+void tsi_analog_off(uint32_t group_pin);
+
+/* enable group */
+void tsi_group_enable(uint32_t group);
+/* disable group */
+void tsi_group_disable(uint32_t group);
+/* get group complete status */
+FlagStatus tsi_group_status_get(uint32_t group);
+/* get the cycle number for group0 as soon as a charge-transfer sequence completes */
+uint16_t tsi_group0_cycle_get(void);
+/* get the cycle number for group1 as soon as a charge-transfer sequence completes */
+uint16_t tsi_group1_cycle_get(void);
+/* get the cycle number for group2 as soon as a charge-transfer sequence completes */
+uint16_t tsi_group2_cycle_get(void);
+/* get the cycle number for group3 as soon as a charge-transfer sequence completes */
+uint16_t tsi_group3_cycle_get(void);
+/* get the cycle number for group4 as soon as a charge-transfer sequence completes */
+uint16_t tsi_group4_cycle_get(void);
+/* get the cycle number for group5 as soon as a charge-transfer sequence completes */
+uint16_t tsi_group5_cycle_get(void);
+
+/* get TSI flag */
+FlagStatus tsi_flag_get(uint32_t flag);
+/* clear TSI flag */
+void tsi_flag_clear(uint32_t flag);
+/* enable TSI interrupt */
+void tsi_interrupt_enable(uint32_t source);
+/* disable TSI interrupt */
+void tsi_interrupt_disable(uint32_t source);
+/* get TSI interrupt flag */
+FlagStatus tsi_interrupt_flag_get(uint32_t flag);
+/* clear interrupt flag */
+void tsi_interrupt_flag_clear(uint32_t flag);
+
+#endif /* GD32F3X0_TSI_H */
+
+#endif /* GD32F350 || GD32F355 || GD32F370 */

+ 572 - 0
GD32F3x0/GD32F3x0_standard_peripheral/Include/gd32f3x0_usart.h

@@ -0,0 +1,572 @@
+/*!
+    \file    gd32f3x0_usart.h
+    \brief   definitions for the USART
+
+    \version 2025-01-01, V2.5.0, firmware for GD32F3x0
+*/
+
+/*
+    Copyright (c) 2025, GigaDevice Semiconductor Inc.
+
+    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 of the copyright holder 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 HOLDER 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.
+*/
+
+#ifndef GD32F3X0_USART_H
+#define GD32F3X0_USART_H
+
+#include "gd32f3x0.h"
+
+/* USARTx(x=0,1) definitions */
+#define USART0                        (USART_BASE + 0x0000F400U)
+#define USART1                        USART_BASE
+
+/* registers definitions */
+#define USART_CTL0(usartx)            REG32((usartx) + 0x00000000U)         /*!< USART control register 0 */
+#define USART_CTL1(usartx)            REG32((usartx) + 0x00000004U)         /*!< USART control register 1 */
+#define USART_CTL2(usartx)            REG32((usartx) + 0x00000008U)         /*!< USART control register 2 */
+#define USART_BAUD(usartx)            REG32((usartx) + 0x0000000CU)         /*!< USART baud rate register */
+#define USART_GP(usartx)              REG32((usartx) + 0x00000010U)         /*!< USART guard time and prescaler register */
+#define USART_RT(usartx)              REG32((usartx) + 0x00000014U)         /*!< USART receiver timeout register */
+#define USART_CMD(usartx)             REG32((usartx) + 0x00000018U)         /*!< USART command register */
+#define USART_STAT(usartx)            REG32((usartx) + 0x0000001CU)         /*!< USART status register */
+#define USART_INTC(usartx)            REG32((usartx) + 0x00000020U)         /*!< USART status clear register */
+#define USART_RDATA(usartx)           REG32((usartx) + 0x00000024U)         /*!< USART receive data register */
+#define USART_TDATA(usartx)           REG32((usartx) + 0x00000028U)         /*!< USART transmit data register */
+#define USART_RFCS(usartx)            REG32((usartx) + 0x000000D0U)         /*!< USART receive FIFO control and status register */
+
+/* bits definitions */
+/* USARTx_CTL0 */
+#define USART_CTL0_UEN                BIT(0)                                /*!< enable USART */
+#define USART_CTL0_UESM               BIT(1)                                /*!< enable USART in deep-sleep mode */
+#define USART_CTL0_REN                BIT(2)                                /*!< enable receiver */
+#define USART_CTL0_TEN                BIT(3)                                /*!< enable transmitter */
+#define USART_CTL0_IDLEIE             BIT(4)                                /*!< enable idle line detected interrupt */
+#define USART_CTL0_RBNEIE             BIT(5)                                /*!< enable ead data buffer not empty interrupt and overrun error interrupt */
+#define USART_CTL0_TCIE               BIT(6)                                /*!< enable transmission complete interrupt */
+#define USART_CTL0_TBEIE              BIT(7)                                /*!< enable transmitter register empty interrupt */
+#define USART_CTL0_PERRIE             BIT(8)                                /*!< enable parity error interrupt */
+#define USART_CTL0_PM                 BIT(9)                                /*!< parity mode */
+#define USART_CTL0_PCEN               BIT(10)                               /*!< enable parity control */
+#define USART_CTL0_WM                 BIT(11)                               /*!< wakeup method in mute mode */
+#define USART_CTL0_WL                 BIT(12)                               /*!< word length */
+#define USART_CTL0_MEN                BIT(13)                               /*!< enable mute mode */
+#define USART_CTL0_AMIE               BIT(14)                               /*!< enable address match interrupt */
+#define USART_CTL0_OVSMOD             BIT(15)                               /*!< oversample mode */
+#define USART_CTL0_DED                BITS(16,20)                           /*!< enable driver deassertion time */
+#define USART_CTL0_DEA                BITS(21,25)                           /*!< enable driver assertion time */
+#define USART_CTL0_RTIE               BIT(26)                               /*!< enable receiver timeout interrupt */
+#define USART_CTL0_EBIE               BIT(27)                               /*!< enable end of block interrupt */
+
+/* USARTx_CTL1 */
+#define USART_CTL1_ADDM               BIT(4)                                /*!< address detection mode */
+#define USART_CTL1_LBLEN              BIT(5)                                /*!< LIN break frame length */
+#define USART_CTL1_LBDIE              BIT(6)                                /*!< enable LIN break detection interrupt */
+#define USART_CTL1_CLEN               BIT(8)                                /*!< last bit clock pulse */
+#define USART_CTL1_CPH                BIT(9)                                /*!< clock phase */
+#define USART_CTL1_CPL                BIT(10)                               /*!< clock polarity */
+#define USART_CTL1_CKEN               BIT(11)                               /*!< enable ck pin */
+#define USART_CTL1_STB                BITS(12,13)                           /*!< stop bits length */
+#define USART_CTL1_LMEN               BIT(14)                               /*!< enable LIN mode */
+#define USART_CTL1_STRP               BIT(15)                               /*!< swap TX/RX pins */
+#define USART_CTL1_RINV               BIT(16)                               /*!< RX pin level inversion */
+#define USART_CTL1_TINV               BIT(17)                               /*!< TX pin level inversion */
+#define USART_CTL1_DINV               BIT(18)                               /*!< data bit level inversion */
+#define USART_CTL1_MSBF               BIT(19)                               /*!< most significant bit first */
+#define USART_CTL1_RTEN               BIT(23)                               /*!< enable receiver timeout */
+#define USART_CTL1_ADDR               BITS(24,31)                           /*!< address of the USART terminal */
+
+/* USARTx_CTL2 */
+#define USART_CTL2_ERRIE              BIT(0)                                /*!< enable error interrupt in multibuffer communication */
+#define USART_CTL2_IREN               BIT(1)                                /*!< enable IrDA mode */
+#define USART_CTL2_IRLP               BIT(2)                                /*!< IrDA low-power */
+#define USART_CTL2_HDEN               BIT(3)                                /*!< enable half-duplex */
+#define USART_CTL2_NKEN               BIT(4)                                /*!< enable NACK in smartcard mode */
+#define USART_CTL2_SCEN               BIT(5)                                /*!< enable smartcard mode */
+#define USART_CTL2_DENR               BIT(6)                                /*!< enable DMA for reception */
+#define USART_CTL2_DENT               BIT(7)                                /*!< enable DMA for transmission */
+#define USART_CTL2_RTSEN              BIT(8)                                /*!< enable RTS */
+#define USART_CTL2_CTSEN              BIT(9)                                /*!< enable CTS */
+#define USART_CTL2_CTSIE              BIT(10)                               /*!< enable CTS interrupt */
+#define USART_CTL2_OSB                BIT(11)                               /*!< one sample bit mode */
+#define USART_CTL2_OVRD               BIT(12)                               /*!< disable overrun */
+#define USART_CTL2_DDRE               BIT(13)                               /*!< disable DMA on reception error */
+#define USART_CTL2_DEM                BIT(14)                               /*!< enable driver mode */
+#define USART_CTL2_DEP                BIT(15)                               /*!< enable driver polarity mode */
+#define USART_CTL2_SCRTNUM            BITS(17,19)                           /*!< smartcard auto-retry number */
+#define USART_CTL2_WUM                BITS(20,21)                           /*!< wakeup mode from deep-sleep mode */
+#define USART_CTL2_WUIE               BIT(22)                               /*!< enable wakeup from deep-sleep mode interrupt */
+
+/* USARTx_BAUD */
+#define USART_BAUD_FRADIV             BITS(0,3)                             /*!< fraction of baud-rate divider */
+#define USART_BAUD_INTDIV             BITS(4,15)                            /*!< integer of baud-rate divider */
+
+/* USARTx_GP */
+#define USART_GP_PSC                  BITS(0,7)                             /*!< prescaler value for dividing the system clock */
+#define USART_GP_GUAT                 BITS(8,15)                            /*!< guard time value in smartcard mode */
+
+/* USARTx_RT */
+#define USART_RT_RT                   BITS(0,23)                            /*!< receiver timeout threshold */
+#define USART_RT_BL                   BITS(24,31)                           /*!< block length */
+
+/* USARTx_CMD */
+#define USART_CMD_SBKCMD              BIT(1)                                /*!< send break command */
+#define USART_CMD_MMCMD               BIT(2)                                /*!< mute mode command */
+#define USART_CMD_RXFCMD              BIT(3)                                /*!< receive data flush command */
+#define USART_CMD_TXFCMD              BIT(4)                                /*!< transmit data flush request */
+
+/* USARTx_STAT */
+#define USART_STAT_PERR               BIT(0)                                /*!< parity error flag */
+#define USART_STAT_FERR               BIT(1)                                /*!< frame error flag */
+#define USART_STAT_NERR               BIT(2)                                /*!< noise error flag */
+#define USART_STAT_ORERR              BIT(3)                                /*!< overrun error */
+#define USART_STAT_IDLEF              BIT(4)                                /*!< idle line detected flag */
+#define USART_STAT_RBNE               BIT(5)                                /*!< read data buffer not empty */
+#define USART_STAT_TC                 BIT(6)                                /*!< transmission completed */
+#define USART_STAT_TBE                BIT(7)                                /*!< transmit data register empty */
+#define USART_STAT_LBDF               BIT(8)                                /*!< LIN break detected flag */
+#define USART_STAT_CTSF               BIT(9)                                /*!< CTS change flag */
+#define USART_STAT_CTS                BIT(10)                               /*!< CTS level */
+#define USART_STAT_RTF                BIT(11)                               /*!< receiver timeout flag */
+#define USART_STAT_EBF                BIT(12)                               /*!< end of block flag */
+#define USART_STAT_BSY                BIT(16)                               /*!< busy flag */
+#define USART_STAT_AMF                BIT(17)                               /*!< address match flag */
+#define USART_STAT_SBF                BIT(18)                               /*!< send break flag */
+#define USART_STAT_RWU                BIT(19)                               /*!< receiver wakeup from mute mode */
+#define USART_STAT_WUF                BIT(20)                               /*!< wakeup from deep-sleep mode flag */
+#define USART_STAT_TEA                BIT(21)                               /*!< transmit enable acknowledge flag */
+#define USART_STAT_REA                BIT(22)                               /*!< receive enable acknowledge flag */
+
+/* USARTx_INTC */
+#define USART_INTC_PEC                BIT(0)                                /*!< clear parity error */
+#define USART_INTC_FEC                BIT(1)                                /*!< clear frame error flag */
+#define USART_INTC_NEC                BIT(2)                                /*!< clear noise detected */
+#define USART_INTC_OREC               BIT(3)                                /*!< clear overrun error */
+#define USART_INTC_IDLEC              BIT(4)                                /*!< clear idle line detected */
+#define USART_INTC_TCC                BIT(6)                                /*!< clear transmission complete */
+#define USART_INTC_LBDC               BIT(8)                                /*!< clear LIN break detected */
+#define USART_INTC_CTSC               BIT(9)                                /*!< clear CTS change */
+#define USART_INTC_RTC                BIT(11)                               /*!< clear receiver timeout */
+#define USART_INTC_EBC                BIT(12)                               /*!< clear end of timeout */
+#define USART_INTC_AMC                BIT(17)                               /*!< clear address match */
+#define USART_INTC_WUC                BIT(20)                               /*!< clear wakeup from deep-sleep mode */
+
+/* USARTx_RDATA */
+#define USART_RDATA_RDATA             BITS(0,8)                             /*!< receive data value */
+
+/* USARTx_TDATA */
+#define USART_TDATA_TDATA             BITS(0,8)                             /*!< transmit data value */
+
+/* USARTx_RFCS */
+#define USART_RFCS_ELNACK             BIT(0)                                /*!< early NACK */
+#define USART_RFCS_RFEN               BIT(8)                                /*!< enable receive FIFO */
+#define USART_RFCS_RFFIE              BIT(9)                                /*!< enable receive FIFO full interrupt */
+#define USART_RFCS_RFE                BIT(10)                               /*!< receive FIFO empty flag */
+#define USART_RFCS_RFF                BIT(11)                               /*!< receive FIFO full flag */
+#define USART_RFCS_RFCNT              BITS(12,14)                           /*!< receive FIFO counter number */
+#define USART_RFCS_RFFINT             BIT(15)                               /*!< receive FIFO full interrupt flag */
+
+/* constants definitions */
+/* define the USART bit position and its register index offset */
+#define USART_REGIDX_BIT(regidx, bitpos)    (((uint32_t)(regidx) << 6) | (uint32_t)(bitpos))
+#define USART_REG_VAL(usartx, offset)       (REG32((usartx) + (((uint32_t)(offset) & 0x0000FFFFU) >> 6)))
+#define USART_BIT_POS(val)                  ((uint32_t)(val) & 0x0000001FU)
+#define USART_REGIDX_BIT2(regidx, bitpos, regidx2, bitpos2)   (((uint32_t)(regidx2) << 22) | (uint32_t)((bitpos2) << 16)\
+                                                              | (((uint32_t)(regidx) << 6) | (uint32_t)(bitpos)))
+#define USART_REG_VAL2(usartx, offset)       (REG32((usartx) + ((uint32_t)(offset) >> 22)))
+#define USART_BIT_POS2(val)                  (((uint32_t)(val) & 0x001F0000U) >> 16)
+
+/* register offset */
+#define USART_CTL0_REG_OFFSET              ((uint32_t)0x00000000U)          /*!< CTL0 register offset */
+#define USART_CTL1_REG_OFFSET              ((uint32_t)0x00000004U)          /*!< CTL1 register offset */
+#define USART_CTL2_REG_OFFSET              ((uint32_t)0x00000008U)          /*!< CTL2 register offset */
+#define USART_STAT_REG_OFFSET              ((uint32_t)0x0000001CU)          /*!< STAT register offset */
+#define USART_RFCS_REG_OFFSET              ((uint32_t)0x000000D0U)          /*!< RFCS register offset */
+
+/* USART flags */
+typedef enum {
+    /* flags in STAT register */
+    USART_FLAG_REA = USART_REGIDX_BIT(USART_STAT_REG_OFFSET, 22U),          /*!< receive enable acknowledge flag */
+    USART_FLAG_TEA = USART_REGIDX_BIT(USART_STAT_REG_OFFSET, 21U),          /*!< transmit enable acknowledge flag */
+    USART_FLAG_WU = USART_REGIDX_BIT(USART_STAT_REG_OFFSET, 20U),           /*!< wakeup from deep-sleep mode flag */
+    USART_FLAG_RWU = USART_REGIDX_BIT(USART_STAT_REG_OFFSET, 19U),          /*!< receiver wakeup from mute mode */
+    USART_FLAG_SB = USART_REGIDX_BIT(USART_STAT_REG_OFFSET, 18U),           /*!< send break flag */
+    USART_FLAG_AM = USART_REGIDX_BIT(USART_STAT_REG_OFFSET, 17U),           /*!< ADDR match flag */
+    USART_FLAG_BSY = USART_REGIDX_BIT(USART_STAT_REG_OFFSET, 16U),          /*!< busy flag */
+    USART_FLAG_EB = USART_REGIDX_BIT(USART_STAT_REG_OFFSET, 12U),           /*!< end of block flag */
+    USART_FLAG_RT = USART_REGIDX_BIT(USART_STAT_REG_OFFSET, 11U),           /*!< receiver timeout flag */
+    USART_FLAG_CTS = USART_REGIDX_BIT(USART_STAT_REG_OFFSET, 10U),          /*!< CTS level */
+    USART_FLAG_CTSF = USART_REGIDX_BIT(USART_STAT_REG_OFFSET, 9U),          /*!< CTS change flag */
+    USART_FLAG_LBD = USART_REGIDX_BIT(USART_STAT_REG_OFFSET, 8U),           /*!< LIN break detected flag */
+    USART_FLAG_TBE = USART_REGIDX_BIT(USART_STAT_REG_OFFSET, 7U),           /*!< transmit data buffer empty */
+    USART_FLAG_TC = USART_REGIDX_BIT(USART_STAT_REG_OFFSET, 6U),            /*!< transmission complete flag */
+    USART_FLAG_RBNE = USART_REGIDX_BIT(USART_STAT_REG_OFFSET, 5U),          /*!< read data buffer not empty */
+    USART_FLAG_IDLE = USART_REGIDX_BIT(USART_STAT_REG_OFFSET, 4U),          /*!< idle line detected flag */
+    USART_FLAG_ORERR = USART_REGIDX_BIT(USART_STAT_REG_OFFSET, 3U),         /*!< overrun error flag */
+    USART_FLAG_NERR = USART_REGIDX_BIT(USART_STAT_REG_OFFSET, 2U),          /*!< noise error flag */
+    USART_FLAG_FERR = USART_REGIDX_BIT(USART_STAT_REG_OFFSET, 1U),          /*!< frame error flag */
+    USART_FLAG_PERR = USART_REGIDX_BIT(USART_STAT_REG_OFFSET, 0U),          /*!< parity error flag */
+    /* flags in RFCS register */
+    USART_FLAG_RFF = USART_REGIDX_BIT(USART_RFCS_REG_OFFSET, 11U),          /*!< receive FIFO full flag */
+    USART_FLAG_RFE = USART_REGIDX_BIT(USART_RFCS_REG_OFFSET, 10U),          /*!< receive FIFO empty flag */
+} usart_flag_enum;
+
+/* USART interrupt flags */
+typedef enum {
+    /* interrupt flags in CTL0 register */
+    USART_INT_FLAG_EB = USART_REGIDX_BIT2(USART_CTL0_REG_OFFSET, 27U, USART_STAT_REG_OFFSET, 12U),       /*!< end of block interrupt flag */
+    USART_INT_FLAG_RT = USART_REGIDX_BIT2(USART_CTL0_REG_OFFSET, 26U, USART_STAT_REG_OFFSET, 11U),       /*!< receiver timeout interrupt flag */
+    USART_INT_FLAG_AM = USART_REGIDX_BIT2(USART_CTL0_REG_OFFSET, 14U, USART_STAT_REG_OFFSET, 17U),       /*!< address match interrupt flag */
+    USART_INT_FLAG_PERR = USART_REGIDX_BIT2(USART_CTL0_REG_OFFSET, 8U, USART_STAT_REG_OFFSET, 0U),       /*!< parity error interrupt flag */
+    USART_INT_FLAG_TBE = USART_REGIDX_BIT2(USART_CTL0_REG_OFFSET, 7U, USART_STAT_REG_OFFSET, 7U),        /*!< transmitter buffer empty interrupt flag */
+    USART_INT_FLAG_TC = USART_REGIDX_BIT2(USART_CTL0_REG_OFFSET, 6U, USART_STAT_REG_OFFSET, 6U),         /*!< transmission complete interrupt flag */
+    USART_INT_FLAG_RBNE = USART_REGIDX_BIT2(USART_CTL0_REG_OFFSET, 5U, USART_STAT_REG_OFFSET, 5U),       /*!< read data buffer not empty interrupt flag */
+    USART_INT_FLAG_RBNE_ORERR = USART_REGIDX_BIT2(USART_CTL0_REG_OFFSET, 5U, USART_STAT_REG_OFFSET, 3U), /*!< overrun error interrupt flag */
+    USART_INT_FLAG_IDLE = USART_REGIDX_BIT2(USART_CTL0_REG_OFFSET, 4U, USART_STAT_REG_OFFSET, 4U),       /*!< idle line detected interrupt flag */
+    /* interrupt flags in CTL1 register */
+    USART_INT_FLAG_LBD = USART_REGIDX_BIT2(USART_CTL1_REG_OFFSET, 6U, USART_STAT_REG_OFFSET, 8U),        /*!< LIN break detected interrupt flag */
+    /* interrupt flags in CTL2 register */
+    USART_INT_FLAG_WU = USART_REGIDX_BIT2(USART_CTL2_REG_OFFSET, 22U, USART_STAT_REG_OFFSET, 20U),       /*!< wakeup from deep-sleep mode interrupt flag */
+    USART_INT_FLAG_CTS = USART_REGIDX_BIT2(USART_CTL2_REG_OFFSET, 10U, USART_STAT_REG_OFFSET, 9U),       /*!< CTS interrupt flag */
+    USART_INT_FLAG_ERR_NERR = USART_REGIDX_BIT2(USART_CTL2_REG_OFFSET, 0U, USART_STAT_REG_OFFSET, 2U),   /*!< noise error interrupt flag */
+    USART_INT_FLAG_ERR_ORERR = USART_REGIDX_BIT2(USART_CTL2_REG_OFFSET, 0U, USART_STAT_REG_OFFSET, 3U),  /*!< overrun error interrupt flag */
+    USART_INT_FLAG_ERR_FERR = USART_REGIDX_BIT2(USART_CTL2_REG_OFFSET, 0U, USART_STAT_REG_OFFSET, 1U),   /*!< frame error interrupt flag */
+    /* interrupt flags in RFCS register */
+    USART_INT_FLAG_RFF = USART_REGIDX_BIT2(USART_RFCS_REG_OFFSET, 9U, USART_RFCS_REG_OFFSET, 15U),       /*!< receive FIFO full interrupt flag */
+} usart_interrupt_flag_enum;
+
+/* enable or disable USART interrupt */
+typedef enum {
+    /* interrupt in CTL0 register */
+    USART_INT_EB = USART_REGIDX_BIT(USART_CTL0_REG_OFFSET, 27U),            /*!< end of block interrupt */
+    USART_INT_RT = USART_REGIDX_BIT(USART_CTL0_REG_OFFSET, 26U),            /*!< receiver timeout interrupt */
+    USART_INT_AM = USART_REGIDX_BIT(USART_CTL0_REG_OFFSET, 14U),            /*!< address match interrupt */
+    USART_INT_PERR = USART_REGIDX_BIT(USART_CTL0_REG_OFFSET, 8U),           /*!< parity error interrupt */
+    USART_INT_TBE = USART_REGIDX_BIT(USART_CTL0_REG_OFFSET, 7U),            /*!< transmitter buffer empty interrupt */
+    USART_INT_TC = USART_REGIDX_BIT(USART_CTL0_REG_OFFSET, 6U),             /*!< transmission complete interrupt */
+    USART_INT_RBNE = USART_REGIDX_BIT(USART_CTL0_REG_OFFSET, 5U),           /*!< read data buffer not empty interrupt and overrun error interrupt */
+    USART_INT_IDLE = USART_REGIDX_BIT(USART_CTL0_REG_OFFSET, 4U),           /*!< idle line detected interrupt */
+    /* interrupt in CTL1 register */
+    USART_INT_LBD = USART_REGIDX_BIT(USART_CTL1_REG_OFFSET, 6U),            /*!< LIN break detected interrupt */
+    /* interrupt in CTL2 register */
+    USART_INT_WU = USART_REGIDX_BIT(USART_CTL2_REG_OFFSET, 22U),            /*!< wakeup from deep-sleep mode interrupt */
+    USART_INT_CTS = USART_REGIDX_BIT(USART_CTL2_REG_OFFSET, 10U),           /*!< CTS interrupt */
+    USART_INT_ERR = USART_REGIDX_BIT(USART_CTL2_REG_OFFSET, 0U),            /*!< error interrupt */
+    /* interrupt in RFCS register */
+    USART_INT_RFF = USART_REGIDX_BIT(USART_RFCS_REG_OFFSET, 9U),            /*!< receive FIFO full interrupt */
+} usart_interrupt_enum;
+
+/* configure USART invert */
+typedef enum {
+    /* data bit level inversion */
+    USART_DINV_ENABLE,                                                      /*!< data bit level inversion */
+    USART_DINV_DISABLE,                                                     /*!< data bit level not inversion */
+    /* TX pin level inversion */
+    USART_TXPIN_ENABLE,                                                     /*!< TX pin level inversion */
+    USART_TXPIN_DISABLE,                                                    /*!< TX pin level not inversion */
+    /* RX pin level inversion */
+    USART_RXPIN_ENABLE,                                                     /*!< RX pin level inversion */
+    USART_RXPIN_DISABLE,                                                    /*!< RX pin level not inversion */
+    /* swap TX/RX pins */
+    USART_SWAP_ENABLE,                                                      /*!< swap TX/RX pins */
+    USART_SWAP_DISABLE,                                                     /*!< not swap TX/RX pins */
+} usart_invert_enum;
+
+/* configure USART receiver */
+#define CTL0_REN(regval)              (BIT(2) & ((uint32_t)(regval) << 2))
+#define USART_RECEIVE_ENABLE          CTL0_REN(1)                           /*!< enable receiver */
+#define USART_RECEIVE_DISABLE         CTL0_REN(0)                           /*!< disable receiver */
+
+/* configure USART transmitter */
+#define CTL0_TEN(regval)              (BIT(3) & ((uint32_t)(regval) << 3))
+#define USART_TRANSMIT_ENABLE         CTL0_TEN(1)                           /*!< enable transmitter */
+#define USART_TRANSMIT_DISABLE        CTL0_TEN(0)                           /*!< disable transmitter */
+
+/* USART parity bits definitions */
+#define CTL0_PM(regval)               (BITS(9,10) & ((uint32_t)(regval) << 9))
+#define USART_PM_NONE                 CTL0_PM(0)                            /*!< no parity */
+#define USART_PM_EVEN                 CTL0_PM(2)                            /*!< even parity */
+#define USART_PM_ODD                  CTL0_PM(3)                            /*!< odd parity */
+
+/* USART wakeup method in mute mode */
+#define CTL0_WM(regval)               (BIT(11) & ((uint32_t)(regval) << 11))
+#define USART_WM_IDLE                 CTL0_WM(0)                            /*!< idle line */
+#define USART_WM_ADDR                 CTL0_WM(1)                            /*!< address match */
+
+/* USART word length definitions */
+#define CTL0_WL(regval)               (BIT(12) & ((uint32_t)(regval) << 12))
+#define USART_WL_8BIT                 CTL0_WL(0)                            /*!< 8 bits */
+#define USART_WL_9BIT                 CTL0_WL(1)                            /*!< 9 bits */
+
+/* USART oversample mode */
+#define CTL0_OVSMOD(regval)           (BIT(15) & ((uint32_t)(regval) << 15))
+#define USART_OVSMOD_8                CTL0_OVSMOD(1)                        /*!< oversampling by 8 */
+#define USART_OVSMOD_16               CTL0_OVSMOD(0)                        /*!< oversampling by 16 */
+
+/* USART address detection mode */
+#define CTL1_ADDM(regval)             (BIT(4) & ((uint32_t)(regval) << 4))
+#define USART_ADDM_4BIT               CTL1_ADDM(0)                          /*!< 4-bit address detection */
+#define USART_ADDM_FULLBIT            CTL1_ADDM(1)                          /*!< full-bit address detection */
+
+/* USART LIN break frame length */
+#define CTL1_LBLEN(regval)            (BIT(5) & ((uint32_t)(regval) << 5))
+#define USART_LBLEN_10B               CTL1_LBLEN(0)                         /*!< 10 bits break detection */
+#define USART_LBLEN_11B               CTL1_LBLEN(1)                         /*!< 11 bits break detection */
+
+/* USART last bit clock pulse */
+#define CTL1_CLEN(regval)             (BIT(8) & ((uint32_t)(regval) << 8))
+#define USART_CLEN_NONE               CTL1_CLEN(0)                          /*!< clock pulse of the last data bit (MSB) is not output to the CK pin */
+#define USART_CLEN_EN                 CTL1_CLEN(1)                          /*!< clock pulse of the last data bit (MSB) is output to the CK pin */
+
+/* USART clock phase */
+#define CTL1_CPH(regval)              (BIT(9) & ((uint32_t)(regval) << 9))
+#define USART_CPH_1CK                 CTL1_CPH(0)                           /*!< first clock transition is the first data capture edge */
+#define USART_CPH_2CK                 CTL1_CPH(1)                           /*!< second clock transition is the first data capture edge */
+
+/* USART clock polarity */
+#define CTL1_CPL(regval)              (BIT(10) & ((uint32_t)(regval) << 10))
+#define USART_CPL_LOW                 CTL1_CPL(0)                           /*!< steady low value on CK pin */
+#define USART_CPL_HIGH                CTL1_CPL(1)                           /*!< steady high value on CK pin */
+
+/* USART stop bits definitions */
+#define CTL1_STB(regval)              (BITS(12,13) & ((uint32_t)(regval) << 12))
+#define USART_STB_1BIT                CTL1_STB(0)                           /*!< 1 bit */
+#define USART_STB_0_5BIT              CTL1_STB(1)                           /*!< 0.5 bit */
+#define USART_STB_2BIT                CTL1_STB(2)                           /*!< 2 bits */
+#define USART_STB_1_5BIT              CTL1_STB(3)                           /*!< 1.5 bits */
+
+/* USART data is transmitted/received with the LSB/MSB first */
+#define CTL1_MSBF(regval)             (BIT(19) & ((uint32_t)(regval) << 19))
+#define USART_MSBF_LSB                CTL1_MSBF(0)                          /*!< LSB first */
+#define USART_MSBF_MSB                CTL1_MSBF(1)                          /*!< MSB first */
+
+/* enable USART IrDA low-power */
+#define CTL2_IRLP(regval)             (BIT(2) & ((uint32_t)(regval) << 2))
+#define USART_IRLP_LOW                CTL2_IRLP(1)                          /*!< low-power */
+#define USART_IRLP_NORMAL             CTL2_IRLP(0)                          /*!< normal */
+
+/* configure USART DMA request for receive */
+#define CTL2_DENR(regval)             (BIT(6) & ((uint32_t)(regval) << 6))
+#define USART_RECEIVE_DMA_ENABLE      CTL2_DENR(1)                          /*!< DMA request enable for reception */
+#define USART_RECEIVE_DMA_DISABLE     CTL2_DENR(0)                          /*!< DMA request disable for reception */
+
+/* configure USART DMA request for transmission */
+#define CTL2_DENT(regval)             (BIT(7) & ((uint32_t)(regval) << 7))
+#define USART_TRANSMIT_DMA_ENABLE     CTL2_DENT(1)                          /*!< DMA request enable for transmission */
+#define USART_TRANSMIT_DMA_DISABLE    CTL2_DENT(0)                          /*!< DMA request disable for transmission */
+
+/* configure USART RTS hardware flow control */
+#define CTL2_RTSEN(regval)            (BIT(8) & ((uint32_t)(regval) << 8))
+#define USART_RTS_ENABLE              CTL2_RTSEN(1)                         /*!< enable RTS hardware flow control */
+#define USART_RTS_DISABLE             CTL2_RTSEN(0)                         /*!< disable RTS hardware flow control */
+
+/* configure USART CTS hardware flow control */
+#define CTL2_CTSEN(regval)            (BIT(9) & ((uint32_t)(regval) << 9))
+#define USART_CTS_ENABLE              CTL2_CTSEN(1)                         /*!< enable CTS hardware flow control */
+#define USART_CTS_DISABLE             CTL2_CTSEN(0)                         /*!< disable CTS hardware flow control */
+
+/* configure USART one sample bit method */
+#define CTL2_OSB(regval)              (BIT(11) & ((uint32_t)(regval) << 11))
+#define USART_OSB_1BIT                CTL2_OSB(1)                           /*!< 1 sample bit */
+#define USART_OSB_3BIT                CTL2_OSB(0)                           /*!< 3 sample bits */
+
+/* USART driver enable polarity mode */
+#define CTL2_DEP(regval)              (BIT(15) & ((uint32_t)(regval) << 15))
+#define USART_DEP_HIGH                CTL2_DEP(0)                           /*!< DE signal is active high */
+#define USART_DEP_LOW                 CTL2_DEP(1)                           /*!< DE signal is active low */
+
+/* USART wakeup mode from deep-sleep mode */
+#define CTL2_WUM(regval)              (BITS(20,21) & ((uint32_t)(regval) << 20))
+#define USART_WUM_ADDR                CTL2_WUM(0)                           /*!< WUF active on address match */
+#define USART_WUM_STARTB              CTL2_WUM(2)                           /*!< WUF active on start bit */
+#define USART_WUM_RBNE                CTL2_WUM(3)                           /*!< WUF active on RBNE */
+
+/* function declarations */
+/* initialization functions */
+/* reset USART */
+void usart_deinit(uint32_t usart_periph);
+/* configure USART baud rate value */
+void usart_baudrate_set(uint32_t usart_periph, uint32_t baudval);
+/* configure USART parity */
+void usart_parity_config(uint32_t usart_periph, uint32_t paritycfg);
+/* configure USART word length */
+void usart_word_length_set(uint32_t usart_periph, uint32_t wlen);
+/* configure USART stop bit length */
+void usart_stop_bit_set(uint32_t usart_periph, uint32_t stblen);
+/* enable USART */
+void usart_enable(uint32_t usart_periph);
+/* disable USART */
+void usart_disable(uint32_t usart_periph);
+/* configure USART transmitter */
+void usart_transmit_config(uint32_t usart_periph, uint32_t txconfig);
+/* configure USART receiver */
+void usart_receive_config(uint32_t usart_periph, uint32_t rxconfig);
+
+/* USART normal mode communication */
+/* data is transmitted/received with the LSB/MSB first */
+void usart_data_first_config(uint32_t usart_periph, uint32_t msbf);
+/* configure USART inversion */
+void usart_invert_config(uint32_t usart_periph, usart_invert_enum invertpara);
+/* enable the USART overrun function */
+void usart_overrun_enable(uint32_t usart_periph);
+/* disable the USART overrun function */
+void usart_overrun_disable(uint32_t usart_periph);
+/* configure the USART oversample mode */
+void usart_oversample_config(uint32_t usart_periph, uint32_t oversamp);
+/* configure the sample bit method */
+void usart_sample_bit_config(uint32_t usart_periph, uint32_t osb);
+/* enable receiver timeout */
+void usart_receiver_timeout_enable(uint32_t usart_periph);
+/* disable receiver timeout */
+void usart_receiver_timeout_disable(uint32_t usart_periph);
+/* configure receiver timeout threshold */
+void usart_receiver_timeout_threshold_config(uint32_t usart_periph, uint32_t rtimeout);
+/* USART transmit data function */
+void usart_data_transmit(uint32_t usart_periph, uint16_t data);
+/* USART receive data function */
+uint16_t usart_data_receive(uint32_t usart_periph);
+/* enable USART command */
+void usart_command_enable(uint32_t usart_periph, uint32_t cmdtype);
+
+/* multi-processor communication */
+/* configure the address of the USART in wake up by address match mode */
+void usart_address_config(uint32_t usart_periph, uint8_t addr);
+/* configure address detection mode */
+void usart_address_detection_mode_config(uint32_t usart_periph, uint32_t addmod);
+/* enable mute mode */
+void usart_mute_mode_enable(uint32_t usart_periph);
+/* disable mute mode */
+void usart_mute_mode_disable(uint32_t usart_periph);
+/* configure wakeup method in mute mode */
+void usart_mute_mode_wakeup_config(uint32_t usart_periph, uint32_t wmethod);
+
+/* LIN mode communication */
+/* enable LIN mode */
+void usart_lin_mode_enable(uint32_t usart_periph);
+/* disable LIN mode */
+void usart_lin_mode_disable(uint32_t usart_periph);
+/* configure LIN break frame length */
+void usart_lin_break_detection_length_config(uint32_t usart_periph, uint32_t lblen);
+
+/* half-duplex communication */
+/* enable half-duplex mode */
+void usart_halfduplex_enable(uint32_t usart_periph);
+/* disable half-duplex mode */
+void usart_halfduplex_disable(uint32_t usart_periph);
+
+/* synchronous communication */
+/* enable USART clock */
+void usart_clock_enable(uint32_t usart_periph);
+/* disable USART clock */
+void usart_clock_disable(uint32_t usart_periph);
+/* configure USART synchronous mode parameters */
+void usart_synchronous_clock_config(uint32_t usart_periph, uint32_t clen, uint32_t cph, uint32_t cpl);
+
+/* smartcard communication */
+/* configure guard time value in smartcard mode */
+void usart_guard_time_config(uint32_t usart_periph, uint32_t guat);
+/* enable smartcard mode */
+void usart_smartcard_mode_enable(uint32_t usart_periph);
+/* disable smartcard mode */
+void usart_smartcard_mode_disable(uint32_t usart_periph);
+/* enable NACK in smartcard mode */
+void usart_smartcard_mode_nack_enable(uint32_t usart_periph);
+/* disable NACK in smartcard mode */
+void usart_smartcard_mode_nack_disable(uint32_t usart_periph);
+/* enable early NACK in smartcard mode */
+void usart_smartcard_mode_early_nack_enable(uint32_t usart_periph);
+/* disable early NACK in smartcard mode */
+void usart_smartcard_mode_early_nack_disable(uint32_t usart_periph);
+/* configure smartcard auto-retry number */
+void usart_smartcard_autoretry_config(uint32_t usart_periph, uint32_t scrtnum);
+/* configure block length */
+void usart_block_length_config(uint32_t usart_periph, uint32_t bl);
+
+/* IrDA communication */
+/* enable IrDA mode */
+void usart_irda_mode_enable(uint32_t usart_periph);
+/* disable IrDA mode */
+void usart_irda_mode_disable(uint32_t usart_periph);
+/* configure the peripheral clock prescaler in USART IrDA low-power or smartcard mode */
+void usart_prescaler_config(uint32_t usart_periph, uint32_t psc);
+/* configure IrDA low-power */
+void usart_irda_lowpower_config(uint32_t usart_periph, uint32_t irlp);
+
+/* hardware flow communication */
+/* configure hardware flow control RTS */
+void usart_hardware_flow_rts_config(uint32_t usart_periph, uint32_t rtsconfig);
+/* configure hardware flow control CTS */
+void usart_hardware_flow_cts_config(uint32_t usart_periph, uint32_t ctsconfig);
+
+/* enable RS485 driver */
+void usart_rs485_driver_enable(uint32_t usart_periph);
+/* disable RS485 driver */
+void usart_rs485_driver_disable(uint32_t usart_periph);
+/* configure driver enable assertion time */
+void usart_driver_assertime_config(uint32_t usart_periph, uint32_t deatime);
+/* configure driver enable de-assertion time */
+void usart_driver_deassertime_config(uint32_t usart_periph, uint32_t dedtime);
+/* configure driver enable polarity mode */
+void usart_depolarity_config(uint32_t usart_periph, uint32_t dep);
+
+/* USART DMA */
+/* configure USART DMA reception */
+void usart_dma_receive_config(uint32_t usart_periph, uint8_t dmacmd);
+/* configure USART DMA transmission */
+void usart_dma_transmit_config(uint32_t usart_periph, uint8_t dmacmd);
+/* enable DMA on reception error */
+void usart_reception_error_dma_enable(uint32_t usart_periph);
+/* disable DMA on reception error */
+void usart_reception_error_dma_disable(uint32_t usart_periph);
+
+/* USART wakeup function */
+/* enable USART to wakeup the MCU from deep-sleep mode */
+void usart_wakeup_enable(uint32_t usart_periph);
+/* disable USART to wakeup the MCU from deep-sleep mode */
+void usart_wakeup_disable(uint32_t usart_periph);
+/* configure the USART wakeup mode from deep-sleep mode */
+void usart_wakeup_mode_config(uint32_t usart_periph, uint32_t wum);
+
+/* USART receive FIFO */
+/* enable receive FIFO */
+void usart_receive_fifo_enable(uint32_t usart_periph);
+/* disable receive FIFO */
+void usart_receive_fifo_disable(uint32_t usart_periph);
+/* read receive FIFO counter number */
+uint8_t usart_receive_fifo_counter_number(uint32_t usart_periph);
+
+/* flag & interrupt functions */
+/* get USART status */
+FlagStatus usart_flag_get(uint32_t usart_periph, usart_flag_enum flag);
+/* clear USART status */
+void usart_flag_clear(uint32_t usart_periph, usart_flag_enum flag);
+/* enable USART interrupt */
+void usart_interrupt_enable(uint32_t usart_periph, usart_interrupt_enum interrupt);
+/* disable USART interrupt */
+void usart_interrupt_disable(uint32_t usart_periph, usart_interrupt_enum interrupt);
+/* get USART interrupt flag status */
+FlagStatus usart_interrupt_flag_get(uint32_t usart_periph, usart_interrupt_flag_enum int_flag);
+/* clear USART interrupt flag */
+void usart_interrupt_flag_clear(uint32_t usart_periph, usart_interrupt_flag_enum int_flag);
+
+#endif /* GD32F3X0_USART_H */

+ 92 - 0
GD32F3x0/GD32F3x0_standard_peripheral/Include/gd32f3x0_wwdgt.h

@@ -0,0 +1,92 @@
+/*!
+    \file    gd32f3x0_wwdgt.h
+    \brief   definitions for the WWDGT
+
+    \version 2025-01-01, V2.5.0, firmware for GD32F3x0
+*/
+
+/*
+    Copyright (c) 2025, GigaDevice Semiconductor Inc.
+
+    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 of the copyright holder 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 HOLDER 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.
+*/
+
+#ifndef GD32F3X0_WWDGT_H
+#define GD32F3X0_WWDGT_H
+
+#include "gd32f3x0.h"
+
+/* WWDGT definitions */
+#define WWDGT                       WWDGT_BASE                                     /*!< WWDGT base address */
+
+/* registers definitions */
+#define WWDGT_CTL                   REG32(WWDGT + 0x00000000U)                     /*!< WWDGT control register */
+#define WWDGT_CFG                   REG32(WWDGT + 0x00000004U)                     /*!< WWDGT configuration register */
+#define WWDGT_STAT                  REG32(WWDGT + 0x00000008U)                     /*!< WWDGT status register */
+
+/* bits definitions */
+/* WWDGT_CTL */
+#define WWDGT_CTL_CNT               BITS(0,6)                                      /*!< WWDGT counter value */
+#define WWDGT_CTL_WDGTEN            BIT(7)                                         /*!< WWDGT counter enable */
+
+/* WWDGT_CFG */
+#define WWDGT_CFG_WIN               BITS(0,6)                                      /*!< WWDGT counter window value */
+#define WWDGT_CFG_PSC               BITS(7,8)                                      /*!< WWDGT prescaler divider value */
+#define WWDGT_CFG_EWIE              BIT(9)                                         /*!< WWDGT early wakeup interrupt enable */
+
+/* WWDGT_STAT */
+#define WWDGT_STAT_EWIF             BIT(0)                                         /*!< WWDGT early wakeup interrupt flag */
+
+/* constants definitions */
+#define CFG_PSC(regval)             (BITS(7,8) & ((uint32_t)(regval) << 7U))       /*!< write value to WWDGT_CFG_PSC bit field */
+#define WWDGT_CFG_PSC_DIV1          ((uint32_t)CFG_PSC(0))                         /*!< the time base of WWDGT = (PCLK1/4096)/1 */
+#define WWDGT_CFG_PSC_DIV2          ((uint32_t)CFG_PSC(1))                         /*!< the time base of WWDGT = (PCLK1/4096)/2 */
+#define WWDGT_CFG_PSC_DIV4          ((uint32_t)CFG_PSC(2))                         /*!< the time base of WWDGT = (PCLK1/4096)/4 */
+#define WWDGT_CFG_PSC_DIV8          ((uint32_t)CFG_PSC(3))                         /*!< the time base of WWDGT = (PCLK1/4096)/8 */
+
+/* WWDGT_CTL register value */
+#define CTL_CNT(regval)             (BITS(0,6) & ((uint32_t)(regval) << 0U))       /*!< write value to WWDGT_CTL_CNT bit field */
+/* WWDGT_CFG register value */
+#define CFG_WIN(regval)             (BITS(0,6) & ((uint32_t)(regval) << 0U))       /*!< write value to WWDGT_CFG_WIN bit field */
+
+/* function declarations */
+/* reset the window watchdog timer configuration */
+void wwdgt_deinit(void);
+/* start the window watchdog timer counter */
+void wwdgt_enable(void);
+
+/* configure the window watchdog timer counter value */
+void wwdgt_counter_update(uint16_t counter_value);
+/* configure counter value, window value, and prescaler divider value */
+void wwdgt_config(uint16_t counter, uint16_t window, uint32_t prescaler);
+
+/* check early wakeup interrupt state of WWDGT */
+FlagStatus wwdgt_flag_get(void);
+/* clear early wakeup interrupt state of WWDGT */
+void wwdgt_flag_clear(void);
+
+/* enable early wakeup interrupt of WWDGT */
+void wwdgt_interrupt_enable(void);
+
+#endif /* GD32F3X0_WWDGT_H */

+ 868 - 0
GD32F3x0/GD32F3x0_standard_peripheral/Source/gd32f3x0_adc.c

@@ -0,0 +1,868 @@
+/*!
+    \file    gd32f3x0_adc.c
+    \brief   ADC driver
+
+    \version 2025-01-01, V2.5.0, firmware for GD32F3x0
+*/
+
+/*
+    Copyright (c) 2025, GigaDevice Semiconductor Inc.
+
+    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 of the copyright holder 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 HOLDER 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.
+*/
+
+#include "gd32f3x0_adc.h"
+
+/*!
+    \brief      reset ADC
+    \param[in]  none
+    \param[out] none
+    \retval     none
+*/
+void adc_deinit(void)
+{
+    rcu_periph_reset_enable(RCU_ADCRST);
+    rcu_periph_reset_disable(RCU_ADCRST);
+}
+
+/*!
+    \brief      enable ADC interface
+    \param[in]  none
+    \param[out] none
+    \retval     none
+*/
+void adc_enable(void)
+{
+    if(RESET == (ADC_CTL1 & ADC_CTL1_ADCON)) {
+        ADC_CTL1 |= (uint32_t)ADC_CTL1_ADCON;
+    }
+}
+
+/*!
+    \brief      disable ADC interface
+    \param[in]  none
+    \param[out] none
+    \retval     none
+*/
+void adc_disable(void)
+{
+    ADC_CTL1 &= ~((uint32_t)ADC_CTL1_ADCON);
+}
+
+/*!
+    \brief      ADC calibration and reset calibration
+    \param[in]  none
+    \param[out] none
+    \retval     none
+*/
+void adc_calibration_enable(void)
+{
+    /* reset the selected ADC calibration register */
+    ADC_CTL1 |= (uint32_t) ADC_CTL1_RSTCLB;
+    /* check the RSTCLB bit state */
+    while((ADC_CTL1 & ADC_CTL1_RSTCLB)) {
+    }
+
+    /* enable ADC calibration process */
+    ADC_CTL1 |= ADC_CTL1_CLB;
+    /* check the CLB bit state */
+    while((ADC_CTL1 & ADC_CTL1_CLB)) {
+    }
+}
+
+/*!
+    \brief      enable DMA request
+    \param[in]  none
+    \param[out] none
+    \retval     none
+*/
+void adc_dma_mode_enable(void)
+{
+    ADC_CTL1 |= (uint32_t)(ADC_CTL1_DMA);
+}
+
+/*!
+    \brief      disable DMA request
+    \param[in]  none
+    \param[out] none
+    \retval     none
+*/
+void adc_dma_mode_disable(void)
+{
+    ADC_CTL1 &= ~((uint32_t)ADC_CTL1_DMA);
+}
+
+/*!
+    \brief      enable the temperature sensor and Vrefint channel
+    \param[in]  none
+    \param[out] none
+    \retval     none
+*/
+void adc_tempsensor_vrefint_enable(void)
+{
+    /* enable the temperature sensor and Vrefint channel */
+    ADC_CTL1 |= ADC_CTL1_TSVREN;
+}
+
+/*!
+    \brief      disable the temperature sensor and Vrefint channel
+    \param[in]  none
+    \param[out] none
+    \retval     none
+*/
+void adc_tempsensor_vrefint_disable(void)
+{
+    /* disable the temperature sensor and Vrefint channel */
+    ADC_CTL1 &= ~ADC_CTL1_TSVREN;
+}
+
+/*!
+    \brief      enable the Vbat channel
+    \param[in]  none
+    \param[out] none
+    \retval     none
+*/
+void adc_vbat_enable(void)
+{
+    /* enable the vbat channel */
+    ADC_CTL1 |= ADC_CTL1_VBETEN;
+}
+
+/*!
+    \brief      disable the Vbat channel
+    \param[in]  none
+    \param[out] none
+    \retval     none
+*/
+void adc_vbat_disable(void)
+{
+    /* disable the vbat channel */
+    ADC_CTL1 &= ~ADC_CTL1_VBETEN;
+}
+
+/*!
+    \brief      configure ADC discontinuous mode
+    \param[in]  channel_group: select the channel group
+                only one parameter can be selected which is shown as below:
+      \arg        ADC_REGULAR_CHANNEL: regular channel group
+      \arg        ADC_INSERTED_CHANNEL: inserted channel group
+      \arg        ADC_CHANNEL_DISCON_DISABLE: disable discontinuous mode of regular and inserted channel
+    \param[in]  length: number of conversions in discontinuous mode,the number can be 1..8
+                        for regular channel, the number has no effect for inserted channel
+    \param[out] none
+    \retval     none
+*/
+void adc_discontinuous_mode_config(uint8_t channel_group, uint8_t length)
+{
+    ADC_CTL0 &= ~((uint32_t)(ADC_CTL0_DISRC | ADC_CTL0_DISIC));
+
+    switch(channel_group) {
+    case ADC_REGULAR_CHANNEL:
+        /* configure the number of conversions in discontinuous mode */
+        ADC_CTL0 &= ~((uint32_t)ADC_CTL0_DISNUM);
+        ADC_CTL0 |= CTL0_DISNUM(((uint32_t)length - 1U));
+        ADC_CTL0 |= (uint32_t)ADC_CTL0_DISRC;
+        break;
+    case ADC_INSERTED_CHANNEL:
+        ADC_CTL0 |= (uint32_t)ADC_CTL0_DISIC;
+        break;
+    case ADC_CHANNEL_DISCON_DISABLE:
+    default:
+        break;
+    }
+}
+
+/*!
+    \brief      enable or disable ADC special function
+    \param[in]  function: the function to configure
+                one or more parameters can be selected which is shown as below:
+      \arg        ADC_SCAN_MODE: scan mode select
+      \arg        ADC_INSERTED_CHANNEL_AUTO: inserted channel group convert automatically
+      \arg        ADC_CONTINUOUS_MODE: continuous mode select
+    \param[in]  newvalue: ENABLE or DISABLE
+    \param[out] none
+    \retval     none
+*/
+void adc_special_function_config(uint32_t function, ControlStatus newvalue)
+{
+    if(newvalue) {
+        /* enable ADC scan mode */
+        if(RESET != (function & ADC_SCAN_MODE)) {
+            ADC_CTL0 |= ADC_SCAN_MODE;
+        }
+        /* enable ADC inserted channel group convert automatically */
+        if(RESET != (function & ADC_INSERTED_CHANNEL_AUTO)) {
+            ADC_CTL0 |= ADC_INSERTED_CHANNEL_AUTO;
+        }
+        /* enable ADC continuous mode */
+        if(RESET != (function & ADC_CONTINUOUS_MODE)) {
+            ADC_CTL1 |= ADC_CONTINUOUS_MODE;
+        }
+    } else {
+        /* disable ADC scan mode */
+        if(RESET != (function & ADC_SCAN_MODE)) {
+            ADC_CTL0 &= ~ADC_SCAN_MODE;
+        }
+        /* disable ADC inserted channel group convert automatically */
+        if(RESET != (function & ADC_INSERTED_CHANNEL_AUTO)) {
+            ADC_CTL0 &= ~ADC_INSERTED_CHANNEL_AUTO;
+        }
+        /* disable ADC continuous mode */
+        if(RESET != (function & ADC_CONTINUOUS_MODE)) {
+            ADC_CTL1 &= ~ADC_CONTINUOUS_MODE;
+        }
+    }
+}
+
+/*!
+    \brief      configure ADC data alignment
+    \param[in]  data_alignment: data alignment select
+                only one parameter can be selected which is shown as below:
+      \arg        ADC_DATAALIGN_RIGHT: right alignment
+      \arg        ADC_DATAALIGN_LEFT: left alignment
+    \param[out] none
+    \retval     none
+*/
+void adc_data_alignment_config(uint32_t data_alignment)
+{
+    if(ADC_DATAALIGN_RIGHT != data_alignment) {
+        ADC_CTL1 |= ADC_CTL1_DAL;
+    } else {
+        ADC_CTL1 &= ~((uint32_t)ADC_CTL1_DAL);
+    }
+}
+
+/*!
+    \brief      configure the length of regular channel group or inserted channel group
+    \param[in]  channel_group: select the channel group
+                only one parameter can be selected which is shown as below:
+      \arg        ADC_REGULAR_CHANNEL: regular channel group
+      \arg        ADC_INSERTED_CHANNEL: inserted channel group
+    \param[in]  length: the length of the channel
+                        regular channel 1-16
+                        inserted channel 1-4
+    \param[out] none
+    \retval     none
+*/
+void adc_channel_length_config(uint8_t channel_group, uint32_t length)
+{
+    switch(channel_group) {
+    case ADC_REGULAR_CHANNEL:
+        /* configure the length of regular channel group */
+        ADC_RSQ0 &= ~((uint32_t)ADC_RSQ0_RL);
+        ADC_RSQ0 |= RSQ0_RL((uint32_t)(length - 1U));
+        break;
+    case ADC_INSERTED_CHANNEL:
+        /* configure the length of inserted channel group */
+        ADC_ISQ &= ~((uint32_t)ADC_ISQ_IL);
+        ADC_ISQ |= ISQ_IL((uint32_t)(length - 1U));
+        break;
+    default:
+        break;
+    }
+}
+
+/*!
+    \brief      configure ADC regular channel
+    \param[in]  rank: the regular group sequence rank, this parameter must be between 0 to 15
+    \param[in]  channel: the selected ADC channel
+                only one parameter can be selected which is shown as below:
+      \arg        ADC_CHANNEL_x(x=0..18): ADC Channelx
+    \param[in]  sample_time: the sample time value
+                only one parameter can be selected which is shown as below:
+      \arg        ADC_SAMPLETIME_1POINT5: 1.5 cycles
+      \arg        ADC_SAMPLETIME_7POINT5: 7.5 cycles
+      \arg        ADC_SAMPLETIME_13POINT5: 13.5 cycles
+      \arg        ADC_SAMPLETIME_28POINT5: 28.5 cycles
+      \arg        ADC_SAMPLETIME_41POINT5: 41.5 cycles
+      \arg        ADC_SAMPLETIME_55POINT5: 55.5 cycles
+      \arg        ADC_SAMPLETIME_71POINT5: 71.5 cycles
+      \arg        ADC_SAMPLETIME_239POINT5: 239.5 cycles
+    \param[out] none
+    \retval     none
+*/
+void adc_regular_channel_config(uint8_t rank, uint8_t channel, uint32_t sample_time)
+{
+    uint32_t rsq, sampt;
+
+    /* configure ADC regular sequence */
+    if(rank < 6U) {
+        rsq = ADC_RSQ2;
+        rsq &=  ~((uint32_t)(ADC_RSQX_RSQN << (5U * rank)));
+        rsq |= ((uint32_t)channel << (5U * rank));
+        ADC_RSQ2 = rsq;
+    } else if(rank < 12U) {
+        rsq = ADC_RSQ1;
+        rsq &= ~((uint32_t)(ADC_RSQX_RSQN << (5U * (rank - 6U))));
+        rsq |= ((uint32_t)channel << (5U * (rank - 6U)));
+        ADC_RSQ1 = rsq;
+    } else if(rank < 16U) {
+        rsq = ADC_RSQ0;
+        rsq &= ~((uint32_t)(ADC_RSQX_RSQN << (5U * (rank - 12U))));
+        rsq |= ((uint32_t)channel << (5U * (rank - 12U)));
+        ADC_RSQ0 = rsq;
+    } else {
+    }
+
+    /* configure ADC sampling time */
+    if(channel < 10U) {
+        sampt = ADC_SAMPT1;
+        sampt &= ~((uint32_t)(ADC_SAMPTX_SPTN << (3U * channel)));
+        sampt |= (uint32_t)(sample_time << (3U * channel));
+        ADC_SAMPT1 = sampt;
+    } else if(channel < 19U) {
+        sampt = ADC_SAMPT0;
+        sampt &= ~((uint32_t)(ADC_SAMPTX_SPTN << (3U * (channel - 10U))));
+        sampt |= (uint32_t)(sample_time << (3U * (channel - 10U)));
+        ADC_SAMPT0 = sampt;
+    } else {
+        /* illegal parameters */
+    }
+}
+
+/*!
+    \brief      configure ADC inserted channel
+    \param[in]  rank: the inserted group sequencer rank,this parameter must be between 0 to 3
+    \param[in]  channel: the selected ADC channel
+                only one parameter can be selected which is shown as below:
+      \arg        ADC_CHANNEL_x(x=0..18): ADC Channelx
+    \param[in]  sample_time: The sample time value
+                only one parameter can be selected which is shown as below:
+      \arg        ADC_SAMPLETIME_1POINT5: 1.5 cycles
+      \arg        ADC_SAMPLETIME_7POINT5: 7.5 cycles
+      \arg        ADC_SAMPLETIME_13POINT5: 13.5 cycles
+      \arg        ADC_SAMPLETIME_28POINT5: 28.5 cycles
+      \arg        ADC_SAMPLETIME_41POINT5: 41.5 cycles
+      \arg        ADC_SAMPLETIME_55POINT5: 55.5 cycles
+      \arg        ADC_SAMPLETIME_71POINT5: 71.5 cycles
+      \arg        ADC_SAMPLETIME_239POINT5: 239.5 cycles
+    \param[out] none
+    \retval     none
+*/
+void adc_inserted_channel_config(uint8_t rank, uint8_t channel, uint32_t sample_time)
+{
+    uint8_t inserted_length;
+    uint32_t isq, sampt;
+
+    inserted_length = (uint8_t)GET_BITS(ADC_ISQ, 20U, 21U);
+
+    isq = ADC_ISQ;
+    isq &= ~((uint32_t)(ADC_ISQ_ISQN << (15U - (inserted_length - rank) * 5U)));
+    isq |= ((uint32_t)channel << (15U - (inserted_length - rank) * 5U));
+    ADC_ISQ = isq;
+
+    /* configure ADC sampling time */
+    if(channel < 10U) {
+        sampt = ADC_SAMPT1;
+        sampt &= ~((uint32_t)(ADC_SAMPTX_SPTN << (3U * channel)));
+        sampt |= (uint32_t) sample_time << (3U * channel);
+        ADC_SAMPT1 = sampt;
+    } else if(channel < 19U) {
+        sampt = ADC_SAMPT0;
+        sampt &= ~((uint32_t)(ADC_SAMPTX_SPTN << (3U * (channel - 10U))));
+        sampt |= ((uint32_t)sample_time << (3U * (channel - 10U)));
+        ADC_SAMPT0 = sampt;
+    } else {
+        /* illegal parameters */
+    }
+}
+
+/*!
+    \brief      configure ADC inserted channel offset
+    \param[in]  inserted_channel: insert channel select
+                only one parameter can be selected which is shown as below:
+      \arg        ADC_INSERTED_CHANNEL_0: ADC inserted channel 0
+      \arg        ADC_INSERTED_CHANNEL_1: ADC inserted channel 1
+      \arg        ADC_INSERTED_CHANNEL_2: ADC inserted channel 2
+      \arg        ADC_INSERTED_CHANNEL_3: ADC inserted channel 3
+    \param[in]  offset: the offset data
+    \param[out] none
+    \retval     none
+*/
+void adc_inserted_channel_offset_config(uint8_t inserted_channel, uint16_t offset)
+{
+    uint8_t inserted_length;
+    uint32_t num = 0U;
+
+    inserted_length = (uint8_t)GET_BITS(ADC_ISQ, 20U, 21U);
+    num = 3U - (inserted_length - inserted_channel);
+
+    if(num <= 3U) {
+        /* calculate the offset of the register */
+        num = num * 4U;
+        /* configure the offset of the selected channels */
+        REG32((ADC) + 0x14U + num) = IOFFX_IOFF((uint32_t)offset);
+    }
+}
+
+/*!
+    \brief      enable or disable ADC external trigger
+    \param[in]  channel_group: select the channel group
+                one or more parameters can be selected which is shown as below:
+      \arg        ADC_REGULAR_CHANNEL: regular channel group
+      \arg        ADC_INSERTED_CHANNEL: inserted channel group
+    \param[in]  newvalue: ENABLE or DISABLE
+    \param[out] none
+    \retval     none
+*/
+void adc_external_trigger_config(uint8_t channel_group, ControlStatus newvalue)
+{
+    if(newvalue) {
+        /* external trigger enable for regular channel */
+        if(RESET != (channel_group & ADC_REGULAR_CHANNEL)) {
+            ADC_CTL1 |= ADC_CTL1_ETERC;
+        }
+        /* external trigger enable for inserted channel */
+        if(RESET != (channel_group & ADC_INSERTED_CHANNEL)) {
+            ADC_CTL1 |= ADC_CTL1_ETEIC;
+        }
+    } else {
+        /* external trigger disable for regular channel */
+        if(RESET != (channel_group & ADC_REGULAR_CHANNEL)) {
+            ADC_CTL1 &= ~ADC_CTL1_ETERC;
+        }
+        /* external trigger disable for inserted channel */
+        if(RESET != (channel_group & ADC_INSERTED_CHANNEL)) {
+            ADC_CTL1 &= ~ADC_CTL1_ETEIC;
+        }
+    }
+}
+
+/*!
+    \brief      configure ADC external trigger source
+    \param[in]  channel_group: select the channel group
+                only one parameter can be selected which is shown as below:
+      \arg        ADC_REGULAR_CHANNEL: regular channel group
+      \arg        ADC_INSERTED_CHANNEL: inserted channel group
+    \param[in]  external_trigger_source: regular or inserted group trigger source
+                only one parameter can be selected which is shown as below:
+                for regular channel:
+      \arg        ADC_EXTTRIG_REGULAR_T0_CH0: TIMER0 CH0 event select
+      \arg        ADC_EXTTRIG_REGULAR_T0_CH1: TIMER0 CH1 event select
+      \arg        ADC_EXTTRIG_REGULAR_T0_CH2: TIMER0 CH2 event select
+      \arg        ADC_EXTTRIG_REGULAR_T1_CH1: TIMER1 CH1 event select
+      \arg        ADC_EXTTRIG_REGULAR_T2_TRGO: TIMER2 TRGO event select
+      \arg        ADC_EXTTRIG_REGULAR_T14_CH0:  TIMER14 CH0 event select
+      \arg        ADC_EXTTRIG_REGULAR_EXTI_11: external interrupt line 11
+      \arg        ADC_EXTTRIG_REGULAR_NONE: software trigger
+                for inserted channel:
+      \arg        ADC_EXTTRIG_INSERTED_T0_TRGO: TIMER0 TRGO event select
+      \arg        ADC_EXTTRIG_INSERTED_T0_CH3: TIMER0 CH3 event select
+      \arg        ADC_EXTTRIG_INSERTED_T1_TRGO: TIMER1 TRGO event select
+      \arg        ADC_EXTTRIG_INSERTED_T1_CH0: TIMER1 CH0 event select
+      \arg        ADC_EXTTRIG_INSERTED_T2_CH3: TIMER2 CH3 event select
+      \arg        ADC_EXTTRIG_INSERTED_T14_TRGO: TIMER14 TRGO event select
+      \arg        ADC_EXTTRIG_INSERTED_EXTI_15: external interrupt line 15
+      \arg        ADC_EXTTRIG_INSERTED_NONE: software trigger
+    \param[out] none
+    \retval     none
+*/
+void adc_external_trigger_source_config(uint8_t channel_group, uint32_t external_trigger_source)
+{
+    switch(channel_group) {
+    case ADC_REGULAR_CHANNEL:
+        /* external trigger select for regular channel */
+        ADC_CTL1 &= ~((uint32_t)ADC_CTL1_ETSRC);
+        ADC_CTL1 |= (uint32_t)external_trigger_source;
+        break;
+    case ADC_INSERTED_CHANNEL:
+        /* external trigger select for inserted channel */
+        ADC_CTL1 &= ~((uint32_t)ADC_CTL1_ETSIC);
+        ADC_CTL1 |= (uint32_t)external_trigger_source;
+        break;
+    default:
+        break;
+    }
+}
+
+/*!
+    \brief      enable ADC software trigger
+    \param[in]  channel_group: select the channel group
+                one or more parameters can be selected which is shown as below:
+      \arg        ADC_REGULAR_CHANNEL: regular channel group
+      \arg        ADC_INSERTED_CHANNEL: inserted channel group
+    \param[out] none
+    \retval     none
+*/
+void adc_software_trigger_enable(uint8_t channel_group)
+{
+    /* enable regular group channel software trigger */
+    if(RESET != (channel_group & ADC_REGULAR_CHANNEL)) {
+        ADC_CTL1 |= ADC_CTL1_SWRCST;
+    }
+    /* enable inserted channel group software trigger */
+    if(RESET != (channel_group & ADC_INSERTED_CHANNEL)) {
+        ADC_CTL1 |= ADC_CTL1_SWICST;
+    }
+}
+
+/*!
+    \brief      read ADC regular group data register
+    \param[in]  none
+    \param[out] none
+    \retval     the conversion value
+*/
+uint16_t adc_regular_data_read(void)
+{
+    return ((uint16_t)ADC_RDATA);
+}
+
+/*!
+    \brief      read ADC inserted group data register
+    \param[in]  inserted_channel: inserted channel select
+                only one parameter can be selected which is shown as below:
+      \arg        ADC_INSERTED_CHANNEL_0: ADC inserted channel 0
+      \arg        ADC_INSERTED_CHANNEL_1: ADC inserted channel 1
+      \arg        ADC_INSERTED_CHANNEL_2: ADC inserted channel 2
+      \arg        ADC_INSERTED_CHANNEL_3: ADC inserted channel 3
+    \param[out] none
+    \retval     the conversion value
+*/
+uint16_t adc_inserted_data_read(uint8_t inserted_channel)
+{
+    uint32_t idata;
+    /* read the data of the selected channel */
+    switch(inserted_channel) {
+    case ADC_INSERTED_CHANNEL_0:
+        idata = ADC_IDATA0;
+        break;
+    case ADC_INSERTED_CHANNEL_1:
+        idata = ADC_IDATA1;
+        break;
+    case ADC_INSERTED_CHANNEL_2:
+        idata = ADC_IDATA2;
+        break;
+    case ADC_INSERTED_CHANNEL_3:
+        idata = ADC_IDATA3;
+        break;
+    default:
+        idata = 0U;
+        break;
+    }
+    return (uint16_t)idata;
+}
+
+/*!
+    \brief      configure ADC analog watchdog single channel
+    \param[in]  channel: the selected ADC channel
+                only one parameter can be selected which is shown as below:
+      \arg        ADC_CHANNEL_x(x=0..18): ADC Channelx
+    \param[out] none
+    \retval     none
+*/
+void adc_watchdog_single_channel_enable(uint8_t channel)
+{
+    ADC_CTL0 &= (uint32_t)~(ADC_CTL0_RWDEN | ADC_CTL0_IWDEN | ADC_CTL0_WDSC | ADC_CTL0_WDCHSEL);
+
+    ADC_CTL0 |= (uint32_t)channel;
+    ADC_CTL0 |= (uint32_t)(ADC_CTL0_RWDEN | ADC_CTL0_IWDEN | ADC_CTL0_WDSC);
+}
+
+/*!
+    \brief      configure ADC analog watchdog group channel
+    \param[in]  channel_group: the channel group use analog watchdog
+                only one parameter can be selected which is shown as below:
+      \arg        ADC_REGULAR_CHANNEL: regular channel group
+      \arg        ADC_INSERTED_CHANNEL: inserted channel group
+      \arg        ADC_REGULAR_INSERTED_CHANNEL: both regular and inserted group
+    \param[out] none
+    \retval     none
+*/
+void adc_watchdog_group_channel_enable(uint8_t channel_group)
+{
+    ADC_CTL0 &= (uint32_t)~(ADC_CTL0_RWDEN | ADC_CTL0_IWDEN | ADC_CTL0_WDSC);
+
+    /* select the group */
+    switch(channel_group) {
+    case ADC_REGULAR_CHANNEL:
+        ADC_CTL0 |= (uint32_t)ADC_CTL0_RWDEN;
+        break;
+    case ADC_INSERTED_CHANNEL:
+        ADC_CTL0 |= (uint32_t)ADC_CTL0_IWDEN;
+        break;
+    case ADC_REGULAR_INSERTED_CHANNEL:
+        ADC_CTL0 |= (uint32_t)(ADC_CTL0_RWDEN | ADC_CTL0_IWDEN);
+        break;
+    default:
+        break;
+    }
+}
+
+/*!
+    \brief      disable ADC analog watchdog
+    \param[in]  none
+    \param[out] none
+    \retval     none
+*/
+void adc_watchdog_disable(void)
+{
+    ADC_CTL0 &= (uint32_t)~(ADC_CTL0_RWDEN | ADC_CTL0_IWDEN | ADC_CTL0_WDSC | ADC_CTL0_WDCHSEL);
+}
+
+/*!
+    \brief      configure ADC analog watchdog threshold
+    \param[in]  low_threshold: analog watchdog low threshold,0..4095
+    \param[in]  high_threshold: analog watchdog high threshold,0..4095
+    \param[out] none
+    \retval     none
+*/
+void adc_watchdog_threshold_config(uint16_t low_threshold, uint16_t high_threshold)
+{
+    ADC_WDLT = (uint32_t)WDLT_WDLT(low_threshold);
+    ADC_WDHT = (uint32_t)WDHT_WDHT(high_threshold);
+}
+
+/*!
+    \brief      configure ADC resolution
+    \param[in]  resolution: ADC resolution
+                only one parameter can be selected which is shown as below:
+      \arg        ADC_RESOLUTION_12B: 12-bit ADC resolution
+      \arg        ADC_RESOLUTION_10B: 10-bit ADC resolution
+      \arg        ADC_RESOLUTION_8B: 8-bit ADC resolution
+      \arg        ADC_RESOLUTION_6B: 6-bit ADC resolution
+    \param[out] none
+    \retval     none
+*/
+void adc_resolution_config(uint32_t resolution)
+{
+    ADC_CTL0 &= ~((uint32_t)ADC_CTL0_DRES);
+    ADC_CTL0 |= (uint32_t)resolution;
+}
+
+/*!
+    \brief      configure ADC oversample mode
+    \param[in]  mode: ADC oversampling mode
+                only one parameter can be selected which is shown as below:
+      \arg        ADC_OVERSAMPLING_ALL_CONVERT: all oversampled conversions for a channel are done consecutively after a trigger
+      \arg        ADC_OVERSAMPLING_ONE_CONVERT: each oversampled conversion for a channel needs a trigger
+    \param[in]  shift: ADC oversampling shift
+                only one parameter can be selected which is shown as below:
+      \arg        ADC_OVERSAMPLING_SHIFT_NONE: no oversampling shift
+      \arg        ADC_OVERSAMPLING_SHIFT_1B: 1-bit oversampling shift
+      \arg        ADC_OVERSAMPLING_SHIFT_2B: 2-bit oversampling shift
+      \arg        ADC_OVERSAMPLING_SHIFT_3B: 3-bit oversampling shift
+      \arg        ADC_OVERSAMPLING_SHIFT_4B: 3-bit oversampling shift
+      \arg        ADC_OVERSAMPLING_SHIFT_5B: 5-bit oversampling shift
+      \arg        ADC_OVERSAMPLING_SHIFT_6B: 6-bit oversampling shift
+      \arg        ADC_OVERSAMPLING_SHIFT_7B: 7-bit oversampling shift
+      \arg        ADC_OVERSAMPLING_SHIFT_8B: 8-bit oversampling shift
+    \param[in]  ratio: ADC oversampling ratio
+                only one parameter can be selected which is shown as below:
+      \arg        ADC_OVERSAMPLING_RATIO_MUL2: oversampling ratio multiple 2
+      \arg        ADC_OVERSAMPLING_RATIO_MUL4: oversampling ratio multiple 4
+      \arg        ADC_OVERSAMPLING_RATIO_MUL8: oversampling ratio multiple 8
+      \arg        ADC_OVERSAMPLING_RATIO_MUL16: oversampling ratio multiple 16
+      \arg        ADC_OVERSAMPLING_RATIO_MUL32: oversampling ratio multiple 32
+      \arg        ADC_OVERSAMPLING_RATIO_MUL64: oversampling ratio multiple 64
+      \arg        ADC_OVERSAMPLING_RATIO_MUL128: oversampling ratio multiple 128
+      \arg        ADC_OVERSAMPLING_RATIO_MUL256: oversampling ratio multiple 256
+    \param[out] none
+    \retval     none
+*/
+void adc_oversample_mode_config(uint8_t mode, uint16_t shift, uint8_t ratio)
+{
+    /* configure ADC oversampling mode */
+    if(ADC_OVERSAMPLING_ONE_CONVERT == mode) {
+        ADC_OVSAMPCTL |= (uint32_t)ADC_OVSAMPCTL_TOVS;
+    } else {
+        ADC_OVSAMPCTL &= ~((uint32_t)ADC_OVSAMPCTL_TOVS);
+    }
+
+    /* configure the shift and ratio */
+    ADC_OVSAMPCTL &= ~((uint32_t)(ADC_OVSAMPCTL_OVSR | ADC_OVSAMPCTL_OVSS));
+    ADC_OVSAMPCTL |= ((uint32_t)shift | (uint32_t)ratio);
+}
+
+/*!
+    \brief      enable ADC oversample mode
+    \param[in]  none
+    \param[out] none
+    \retval     none
+*/
+void adc_oversample_mode_enable(void)
+{
+    ADC_OVSAMPCTL |= ADC_OVSAMPCTL_OVSEN;
+}
+
+/*!
+    \brief      disable ADC oversample mode
+    \param[in]  none
+    \param[out] none
+    \retval     none
+*/
+void adc_oversample_mode_disable(void)
+{
+    ADC_OVSAMPCTL &= ~((uint32_t)ADC_OVSAMPCTL_OVSEN);
+}
+
+/*!
+    \brief      get the ADC flag bits
+    \param[in]  flag: the adc flag bits
+                only one parameter can be selected which is shown as below:
+      \arg        ADC_FLAG_WDE: analog watchdog event flag
+      \arg        ADC_FLAG_EOC: end of group conversion flag
+      \arg        ADC_FLAG_EOIC: end of inserted group conversion flag
+      \arg        ADC_FLAG_STIC: start flag of inserted channel group
+      \arg        ADC_FLAG_STRC: start flag of regular channel group
+    \param[out] none
+    \retval     FlagStatus: SET or RESET
+*/
+FlagStatus adc_flag_get(uint32_t flag)
+{
+    FlagStatus reval = RESET;
+
+    if(ADC_STAT & flag) {
+        reval = SET;
+    }
+    return reval;
+}
+
+/*!
+    \brief      clear the ADC flag
+    \param[in]  flag: the adc flag
+                one or more parameters can be selected which is shown as below:
+      \arg        ADC_FLAG_WDE: analog watchdog event flag
+      \arg        ADC_FLAG_EOC: end of group conversion flag
+      \arg        ADC_FLAG_EOIC: end of inserted group conversion flag
+      \arg        ADC_FLAG_STIC: start flag of inserted channel group
+      \arg        ADC_FLAG_STRC: start flag of regular channel group
+    \param[out] none
+    \retval     none
+*/
+void adc_flag_clear(uint32_t flag)
+{
+    ADC_STAT &= ~((uint32_t)flag);
+}
+
+/*!
+    \brief      enable ADC interrupt
+    \param[in]  interrupt: the adc interrupt
+                one or more parameters can be selected which is shown as below:
+      \arg        ADC_INT_WDE: analog watchdog interrupt
+      \arg        ADC_INT_EOC: end of group conversion interrupt
+      \arg        ADC_INT_EOIC: end of inserted group conversion interrupt
+    \param[out] none
+    \retval     none
+*/
+void adc_interrupt_enable(uint32_t interrupt)
+{
+    /* enable analog watchdog interrupt */
+    if(RESET != (interrupt & ADC_INT_WDE)) {
+        ADC_CTL0 |= (uint32_t)ADC_CTL0_WDEIE;
+    }
+
+    /* enable end of group conversion interrupt */
+    if(RESET != (interrupt & ADC_INT_EOC)) {
+        ADC_CTL0 |= (uint32_t)ADC_CTL0_EOCIE;
+    }
+
+    /* enable end of inserted group conversion interrupt */
+    if(RESET != (interrupt & ADC_INT_EOIC)) {
+        ADC_CTL0 |= (uint32_t)ADC_CTL0_EOICIE;
+    }
+}
+
+/*!
+    \brief      disable ADC interrupt
+    \param[in]  interrupt: the adc interrupt flag
+                one or more parameters can be selected which is shown as below:
+      \arg        ADC_INT_WDE: analog watchdog interrupt
+      \arg        ADC_INT_EOC: end of group conversion interrupt
+      \arg        ADC_INT_EOIC: end of inserted group conversion interrupt
+    \param[out] none
+    \retval     none
+*/
+void adc_interrupt_disable(uint32_t interrupt)
+{
+    /* disable analog watchdog interrupt */
+    if(RESET != (interrupt & ADC_INT_WDE)) {
+        ADC_CTL0 &= ~(uint32_t)ADC_CTL0_WDEIE;
+    }
+
+    /* disable end of group conversion interrupt */
+    if(RESET != (interrupt & ADC_INT_EOC)) {
+        ADC_CTL0 &= ~(uint32_t)ADC_CTL0_EOCIE;
+    }
+
+    /* disable end of inserted group conversion interrupt */
+    if(RESET != (interrupt & ADC_INT_EOIC)) {
+        ADC_CTL0 &= ~(uint32_t)ADC_CTL0_EOICIE;
+    }
+}
+
+/*!
+    \brief      get the ADC interrupt flag
+    \param[in]  flag: the adc interrupt flag
+                only one parameter can be selected which is shown as below:
+      \arg        ADC_INT_FLAG_WDE: analog watchdog interrupt flag
+      \arg        ADC_INT_FLAG_EOC: end of group conversion interrupt flag
+      \arg        ADC_INT_FLAG_EOIC: end of inserted group conversion interrupt flag
+    \param[out] none
+    \retval     FlagStatus: SET or RESET
+*/
+FlagStatus adc_interrupt_flag_get(uint32_t flag)
+{
+    FlagStatus interrupt_flag = RESET;
+    uint32_t state;
+
+    /* check the interrupt bits */
+    switch(flag) {
+    case ADC_INT_FLAG_WDE:
+        state = ADC_STAT & ADC_STAT_WDE;
+        if((ADC_CTL0 & ADC_CTL0_WDEIE) && state) {
+            interrupt_flag = SET;
+        }
+        break;
+    case ADC_INT_FLAG_EOC:
+        state = ADC_STAT & ADC_STAT_EOC;
+        if((ADC_CTL0 & ADC_CTL0_EOCIE) && state) {
+            interrupt_flag = SET;
+        }
+        break;
+    case ADC_INT_FLAG_EOIC:
+        state = ADC_STAT & ADC_STAT_EOIC;
+        if((ADC_CTL0 & ADC_CTL0_EOICIE) && state) {
+            interrupt_flag = SET;
+        }
+        break;
+    default:
+        break;
+    }
+    return interrupt_flag;
+}
+
+/*!
+    \brief      clear ADC interrupt flag
+    \param[in]  flag: the adc interrupt flag
+                only one parameter can be selected which is shown as below:
+      \arg        ADC_INT_FLAG_WDE: analog watchdog interrupt flag
+      \arg        ADC_INT_FLAG_EOC: end of group conversion interrupt flag
+      \arg        ADC_INT_FLAG_EOIC: end of inserted group conversion interrupt flag
+    \param[out] none
+    \retval     none
+*/
+void adc_interrupt_flag_clear(uint32_t flag)
+{
+    ADC_STAT &= ~((uint32_t)flag);
+}

+ 497 - 0
GD32F3x0/GD32F3x0_standard_peripheral/Source/gd32f3x0_cec.c

@@ -0,0 +1,497 @@
+/*!
+    \file    gd32f3x0_cec.c
+    \brief   CEC driver
+
+    \version 2025-01-01, V2.5.0, firmware for GD32F3x0
+*/
+
+/*
+    Copyright (c) 2025, GigaDevice Semiconductor Inc.
+
+    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 of the copyright holder 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 HOLDER 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.
+*/
+
+#if defined(GD32F350)||defined(GD32F355)||defined(GD32F370)
+
+#include "gd32f3x0_cec.h"
+
+/*!
+    \brief      reset HDMI-CEC controller
+    \param[in]  none
+    \param[out] none
+    \retval     none
+*/
+void cec_deinit(void)
+{
+    rcu_periph_reset_enable(RCU_CECRST);
+    rcu_periph_reset_disable(RCU_CECRST);
+}
+
+/*!
+    \brief      configure signal free time,the signal free time counter start option,own address
+    \param[in]  sftmopt: signal free time counter start option
+                only one parameter can be selected which is shown as below:
+      \arg        CEC_SFT_START_STAOM: signal free time counter starts counting when STAOM is asserted
+      \arg        CEC_SFT_START_LAST: signal free time counter starts automatically after transmission/reception end
+    \param[in]  sft: signal free time
+                only one parameter can be selected which is shown as below:
+      \arg        CEC_SFT_PROTOCOL_PERIOD: the signal free time will perform as HDMI-CEC protocol description
+      \arg        CEC_SFT_1POINT5_PERIOD: 1.5 nominal data bit periods
+      \arg        CEC_SFT_2POINT5_PERIOD: 2.5 nominal data bit periods
+      \arg        CEC_SFT_3POINT5_PERIOD: 3.5 nominal data bit periods
+      \arg        CEC_SFT_4POINT5_PERIOD: 4.5 nominal data bit periods
+      \arg        CEC_SFT_5POINT5_PERIOD: 5.5 nominal data bit periods
+      \arg        CEC_SFT_6POINT5_PERIOD: 6.5 nominal data bit periods
+      \arg        CEC_SFT_7POINT5_PERIOD: 7.5 nominal data bit periods
+    \param[in]  address: own address
+                only one parameter can be selected which is shown as below:
+      \arg        CEC_OWN_ADDRESS_CLEAR: own address is cleared
+      \arg        CEC_OWN_ADDRESSx(x=0..14): own address is x
+    \param[out] none
+    \retval     none
+*/
+void cec_init(uint32_t sftmopt, uint32_t sft, uint32_t address)
+{
+    uint32_t cfg;
+    cfg = CEC_CFG;
+    /* clear SFTMOPT bit,SFT[2:0] */
+    cfg &= ~(CEC_CFG_SFTOPT | CEC_CFG_SFT);
+    /* assign SFTMOPT bit,SFT[2:0] */
+    cfg |= (sftmopt | sft);
+    CEC_CFG = cfg;
+    if(CEC_OWN_ADDRESS_CLEAR == address){
+        CEC_CFG &= ~CEC_CFG_OAD;
+    }else{
+        CEC_CFG |= address;
+    }
+}
+
+/*!
+    \brief      configure generate Error-bit when detected some abnormal situation or not,
+                whether stop receive message when detected bit rising error
+    \param[in]  broadcast:
+                only one parameter can be selected which is shown as below:
+      \arg        CEC_BROADCAST_ERROR_BIT_ON:generate Error-bit in broadcast
+      \arg        CEC_BROADCAST_ERROR_BIT_OFF:do not generate Error-bit in broadcast
+    \param[in]  singlecast_lbpe:
+                only one parameter can be selected which is shown as below:
+      \arg        CEC_LONG_PERIOD_ERROR_BIT_ON:generate Error-bit on long bit period error
+      \arg        CEC_LONG_PERIOD_ERROR_BIT_OFF:do not generate Error-bit on long bit period error
+    \param[in]  singlecast_bre:
+                only one parameter can be selected which is shown as below:
+      \arg        CEC_RISING_PERIOD_ERROR_BIT_ON:generate Error-bit on bit rising error
+      \arg        CEC_RISING_PERIOD_ERROR_BIT_OFF:do not generate Error-bit on bit rising error
+    \param[in]  rxbrestp:
+                only one parameter can be selected which is shown as below:
+      \arg        CEC_STOP_RISING_ERROR_BIT_ON: stop reception when detected bit rising error
+      \arg        CEC_STOP_RISING_ERROR_BIT_OFF: do not stop reception when detected bit rising error
+    \param[out] none
+    \retval     none
+*/
+void cec_error_config(uint32_t broadcast, uint32_t singlecast_lbpe, uint32_t singlecast_bre, uint32_t rxbrestp)
+{
+    uint32_t cfg;
+    cfg = CEC_CFG;
+    /* clear BCNG bit, BPLEG bit, BREG bit */
+    cfg &= ~(CEC_CFG_BCNG | CEC_CFG_BPLEG | CEC_CFG_BREG);
+    /* assign BCNG bit, BPLEG bit, BREG bit */
+    cfg |= (broadcast | singlecast_lbpe | singlecast_bre);
+    CEC_CFG = cfg;
+    if(CEC_STOP_RISING_ERROR_BIT_ON == rxbrestp){
+        CEC_CFG |= CEC_CFG_BRES;
+    }else{
+        CEC_CFG &= ~CEC_CFG_BRES;
+    }
+}
+
+/*!
+    \brief      enable HDMI-CEC controller
+    \param[in]  none
+    \param[out] none
+    \retval     none
+*/
+void cec_enable(void)
+{
+    CEC_CTL |= CEC_CTL_CECEN;
+}
+
+/*!
+    \brief      disable HDMI-CEC controller
+    \param[in]  none
+    \param[out] none
+    \retval     none
+*/
+void cec_disable(void)
+{
+    CEC_CTL &= ~CEC_CTL_CECEN;
+}
+
+/*!
+    \brief      start CEC message transmission
+    \param[in]  none
+    \param[out] none
+    \retval     none
+*/
+void cec_transmission_start(void)
+{
+    CEC_CTL |= CEC_CTL_STAOM;
+}
+
+/*!
+    \brief      end CEC message transmission
+    \param[in]  none
+    \param[out] none
+    \retval     none
+*/
+void cec_transmission_end(void)
+{
+    CEC_CTL |= CEC_CTL_ENDOM;
+}
+
+/*!
+    \brief      enable CEC listen mode.
+    \param[in]  none
+    \param[out] none
+    \retval     none
+*/
+void cec_listen_mode_enable(void)
+{
+    CEC_CFG |= CEC_CFG_LMEN;
+}
+
+/*!
+    \brief      disable CEC listen mode.
+    \param[in]  none
+    \param[out] none
+    \retval     none
+*/
+void cec_listen_mode_disable(void)
+{
+    CEC_CFG &= ~CEC_CFG_LMEN;
+}
+
+/*!
+    \brief      configure and clear own address.the controller can be configured to multiple own address
+    \param[in]  address: own address
+                one or more parameters can be selected which are shown as below:
+      \arg        CEC_OWN_ADDRESS_CLEAR: own address is cleared
+      \arg        CEC_OWN_ADDRESSx(x=0..14): own address is x
+    \param[out] none
+    \retval     none
+*/
+void cec_own_address_config(uint32_t address)
+{
+    if(CEC_OWN_ADDRESS_CLEAR == address){
+        CEC_CFG &= ~CEC_CFG_OAD;
+    }else{
+        CEC_CFG |= address;
+    }
+}
+
+/*!
+    \brief      configure signal free time and the signal free time counter start option
+    \param[in]  sftmopt: signal free time counter start option
+                only one parameter can be selected which is shown as below:
+      \arg        CEC_SFT_START_STAOM: signal free time counter starts counting when STAOM is asserted
+      \arg        CEC_SFT_START_LAST: signal free time counter starts automatically after transmission/reception end
+    \param[in]  sft: signal free time
+                only one parameter can be selected which is shown as below:
+      \arg        CEC_SFT_PROTOCOL_PERIOD: the signal free time will perform as HDMI-CEC protocol description
+      \arg        CEC_SFT_1POINT5_PERIOD: 1.5 nominal data bit periods
+      \arg        CEC_SFT_2POINT5_PERIOD: 2.5 nominal data bit periods
+      \arg        CEC_SFT_3POINT5_PERIOD: 3.5 nominal data bit periods
+      \arg        CEC_SFT_4POINT5_PERIOD: 4.5 nominal data bit periods
+      \arg        CEC_SFT_5POINT5_PERIOD: 5.5 nominal data bit periods
+      \arg        CEC_SFT_6POINT5_PERIOD: 6.5 nominal data bit periods
+      \arg        CEC_SFT_7POINT5_PERIOD: 7.5 nominal data bit periods
+    \param[out] none
+    \retval     none
+*/
+void cec_sft_config(uint32_t sftmopt, uint32_t sft)
+{
+    uint32_t cfg;
+    cfg = CEC_CFG;
+    /* clear SFTMOPT bit,SFT[2:0] */
+    cfg &= ~(CEC_CFG_SFTOPT | CEC_CFG_SFT);
+    /* assign SFTMOPT bit,SFT[2:0] */
+    cfg |= (sftmopt | sft);
+    CEC_CFG = cfg;
+}
+
+/*!
+    \brief      configure generate Error-bit when detected some abnormal situation or not
+    \param[in]  broadcast:
+                only one parameter can be selected which is shown as below:
+      \arg        CEC_BROADCAST_ERROR_BIT_ON:generate Error-bit in broadcast
+      \arg        CEC_BROADCAST_ERROR_BIT_OFF:do not generate Error-bit in broadcast
+    \param[in]  singlecast_lbpe:
+                only one parameter can be selected which is shown as below:
+      \arg        CEC_LONG_PERIOD_ERROR_BIT_ON:generate Error-bit on long bit period error
+      \arg        CEC_LONG_PERIOD_ERROR_BIT_OFF:do not generate Error-bit on long bit period error
+    \param[in]  singlecast_bre:
+                only one parameter can be selected which is shown as below:
+      \arg        CEC_RISING_PERIOD_ERROR_BIT_ON:generate Error-bit on bit rising error
+      \arg        CEC_RISING_PERIOD_ERROR_BIT_OFF:do not generate Error-bit on bit rising error
+    \param[out] none
+    \retval     none
+*/
+void cec_generate_errorbit_config(uint32_t broadcast, uint32_t singlecast_lbpe, uint32_t singlecast_bre)
+{
+    uint32_t cfg;
+    cfg = CEC_CFG;
+    /* clear BCNG bit, RLBPEGEN bit, RBREGEN bit */
+    cfg &= ~(CEC_CFG_BCNG | CEC_CFG_BPLEG | CEC_CFG_BREG);
+    /* assign BCNG bit, RLBPEGEN bit, RBREGEN bit */
+    cfg |= (broadcast | singlecast_lbpe | singlecast_bre);
+    CEC_CFG = cfg;
+}
+
+/*!
+    \brief      whether stop receive message when detected bit rising error
+    \param[in]  rxbrestp:
+                only one parameter can be selected which is shown as below:
+      \arg        CEC_STOP_RISING_ERROR_BIT_ON: stop reception when detected bit rising error
+      \arg        CEC_STOP_RISING_ERROR_BIT_OFF: do not stop reception when detected bit rising error
+    \param[out] none
+    \retval     none
+*/
+void cec_stop_receive_bre_config(uint32_t rxbrestp)
+{
+    if(CEC_STOP_RISING_ERROR_BIT_ON == rxbrestp){
+        CEC_CFG |= CEC_CFG_BRES;
+    }else{
+        CEC_CFG &= ~CEC_CFG_BRES;
+    }
+}
+
+/*!
+    \brief      enable reception bit timing tolerance
+    \param[in]  none
+    \param[out] none
+    \retval     none
+*/
+void cec_reception_tolerance_enable(void)
+{
+    CEC_CFG |= CEC_CFG_RTOL;
+}
+
+/*!
+    \brief      disable reception bit timing tolerance
+    \param[in]  none
+    \param[out] none
+    \retval     none
+*/
+void cec_reception_tolerance_disable(void)
+{
+    CEC_CFG &= ~CEC_CFG_RTOL;
+}
+
+/*!
+    \brief      send a data by the CEC peripheral
+    \param[in]  data: the data to transmit
+    \param[out] none
+    \retval     none
+*/
+void cec_data_send(uint8_t data)
+{
+    CEC_TDATA = (uint32_t)data;
+}
+
+/*!
+    \brief      receive a data by the CEC peripheral
+    \param[in]  data: the data to receive
+    \param[out] none
+    \retval     none
+*/
+uint8_t cec_data_receive(void)
+{
+    return (uint8_t)CEC_RDATA;
+}
+
+
+/*!
+    \brief      enable interrupt
+    \param[in]  flag: specify which flag
+                one or more parameters can be selected which are shown as below:
+      \arg        CEC_INT_BR: enable Rx-byte data received interrupt
+      \arg        CEC_INT_REND: enable end of reception interrupt
+      \arg        CEC_INT_RO: enable RX overrun interrupt
+      \arg        CEC_INT_BRE: enable bit rising error interrupt
+      \arg        CEC_INT_BPSE: enable short bit period error interrupt
+      \arg        CEC_INT_BPLE: enable long bit period error interrupt
+      \arg        CEC_INT_RAE: enable Rx ACK error interrupt
+      \arg        CEC_INT_ARBF: enable arbitration lost interrupt
+      \arg        CEC_INT_TBR: enable Tx-byte data request interrupt
+      \arg        CEC_INT_TEND: enable transmission successfully end interrupt
+      \arg        CEC_INT_TU: enable Tx data buffer underrun interrupt
+      \arg        CEC_INT_TERR: enable Tx-error interrupt
+      \arg        CEC_INT_TAERR: enable Tx ACK error interrupt
+    \param[out] none
+    \retval     none
+*/
+void cec_interrupt_enable(uint32_t flag)
+{
+    CEC_INTEN |= flag;
+}
+
+/*!
+    \brief      disable interrupt
+    \param[in]  flag: specify which flag
+                one or more parameters can be selected which are shown as below:
+      \arg        CEC_INT_BR: disable Rx-byte data received interrupt
+      \arg        CEC_INT_REND: disable end of reception interrupt
+      \arg        CEC_INT_RO: disable RX overrun interrupt
+      \arg        CEC_INT_BRE: disable bit rising error interrupt
+      \arg        CEC_INT_BPSE: disable short bit period error interrupt
+      \arg        CEC_INT_BPLE: disable long bit period error interrupt
+      \arg        CEC_INT_RAE: disable Rx ACK error interrupt
+      \arg        CEC_INT_ARBF: disable arbitration lost interrupt
+      \arg        CEC_INT_TBR: disable Tx-byte data request interrupt
+      \arg        CEC_INT_TEND: disable transmission successfully end interrupt
+      \arg        CEC_INT_TU: disable Tx data buffer underrun interrupt
+      \arg        CEC_INT_TERR: disable Tx-error interrupt
+      \arg        CEC_INT_TAERR: disable Tx ACK error  interrupt
+
+    \param[out] none
+    \retval     none
+*/
+void cec_interrupt_disable(uint32_t flag)
+{
+    CEC_INTEN &= ~flag;
+}
+
+
+/*!
+    \brief      get CEC status
+    \param[in]  flag:  specify which flag
+                one or more parameters can be selected which are shown as below:
+      \arg        CEC_FLAG_BR: Rx-byte data received
+      \arg        CEC_FLAG_REND: end of reception
+      \arg        CEC_FLAG_RO: RX overrun
+      \arg        CEC_FLAG_BRE: bit rising error
+      \arg        CEC_FLAG_BPSE: short bit period error
+      \arg        CEC_FLAG_BPLE: long bit period error
+      \arg        CEC_FLAG_RAE: Rx ACK error
+      \arg        CEC_FLAG_ARBF: arbitration lost
+      \arg        CEC_FLAG_TBR: Tx-byte data request
+      \arg        CEC_FLAG_TEND: transmission successfully end
+      \arg        CEC_FLAG_TU: Tx data buffer underrun
+      \arg        CEC_FLAG_TERR: Tx-error
+      \arg        CEC_FLAG_TAERR Tx ACK error flag
+    \param[out] none
+    \retval     FlagStatus: SET or RESET
+*/
+FlagStatus cec_flag_get(uint32_t flag)
+{
+    if(CEC_INTF & flag){
+        return SET;
+    }else{
+        return RESET;
+    }
+}
+
+/*!
+    \brief      clear CEC status
+    \param[in]  flag:  specify which flag
+                one or more parameters can be selected which are shown as below:
+      \arg        CEC_FLAG_BR: Rx-byte data received
+      \arg        CEC_FLAG_REND: end of reception
+      \arg        CEC_FLAG_RO: RX overrun
+      \arg        CEC_FLAG_BRE: bit rising error
+      \arg        CEC_FLAG_BPSE: short bit period error
+      \arg        CEC_FLAG_BPLE: long bit period error
+      \arg        CEC_FLAG_RAE: Rx ACK error
+      \arg        CEC_FLAG_ARBF: arbitration lost
+      \arg        CEC_FLAG_TBR: Tx-byte data request
+      \arg        CEC_FLAG_TEND: transmission successfully end
+      \arg        CEC_FLAG_TU: Tx data buffer underrun
+      \arg        CEC_FLAG_TERR: Tx-error
+      \arg        CEC_FLAG_TAERR: Tx ACK error flag
+
+    \param[out] none
+    \retval     FlagStatus: SET or RESET
+*/
+void cec_flag_clear(uint32_t flag)
+{
+    CEC_INTF |= flag;
+}
+
+/*!
+    \brief      get CEC int flag and status
+    \param[in]  flag:  specify which flag
+                one or more parameters can be selected which are shown as below:
+      \arg        CEC_INT_FLAG_BR: Rx-byte data received
+      \arg        CEC_INT_FLAG_REND: end of reception
+      \arg        CEC_INT_FLAG_RO: RX overrun
+      \arg        CEC_INT_FLAG_BRE: bit rising error
+      \arg        CEC_INT_FLAG_BPSE: short bit period error
+      \arg        CEC_INT_FLAG_BPLE: long bit period error
+      \arg        CEC_INT_FLAG_RAE: Rx ACK error
+      \arg        CEC_INT_FLAG_ARBF: arbitration lost
+      \arg        CEC_INT_FLAG_TBR: Tx-byte data request
+      \arg        CEC_INT_FLAG_TEND: transmission successfully end
+      \arg        CEC_INT_FLAG_TU: Tx data buffer underrun
+      \arg        CEC_INT_FLAG_TERR: Tx-error
+      \arg        CEC_INT_FLAG_TAERR: Tx ACK error flag
+    \param[out] none
+    \retval     FlagStatus: SET or RESET
+*/
+FlagStatus cec_interrupt_flag_get(uint32_t flag)
+{
+    uint32_t interrupt_enable = 0U, interrupt_flag = 0U;
+    interrupt_flag = (CEC_INTF & flag);
+    interrupt_enable = (CEC_INTEN & flag);
+    if(interrupt_flag && interrupt_enable){
+        return SET;
+    }else{
+        return RESET;
+    }
+}
+
+/*!
+    \brief      clear CEC int flag and status
+    \param[in]  flag:  specify which flag
+                one or more parameters can be selected which are shown as below:
+      \arg        CEC_INT_FLAG_BR: Rx-byte data received
+      \arg        CEC_INT_FLAG_REND: end of reception
+      \arg        CEC_INT_FLAG_RO: RX overrun
+      \arg        CEC_INT_FLAG_BRE: bit rising error
+      \arg        CEC_INT_FLAG_BPSE: short bit period error
+      \arg        CEC_INT_FLAG_BPLE: long bit period error
+      \arg        CEC_INT_FLAG_RAE: Rx ACK error
+      \arg        CEC_INT_FLAG_ARBF: arbitration lost
+      \arg        CEC_INT_FLAG_TBR: Tx-byte data request
+      \arg        CEC_INT_FLAG_TEND: transmission successfully end
+      \arg        CEC_INT_FLAG_TU: Tx data buffer underrun
+      \arg        CEC_INT_FLAG_TERR: Tx-error
+      \arg        CEC_INT_FLAG_TAERR: Tx ACK error flag
+    \param[out] none
+    \retval     none
+*/
+void cec_interrupt_flag_clear(uint32_t flag)
+{
+    CEC_INTF = flag;
+}
+
+#endif

+ 278 - 0
GD32F3x0/GD32F3x0_standard_peripheral/Source/gd32f3x0_cmp.c

@@ -0,0 +1,278 @@
+/*!
+    \file    gd32f3x0_cmp.c
+    \brief   CMP driver
+
+    \version 2025-01-01, V2.5.0, firmware for GD32F3x0
+*/
+
+/*
+    Copyright (c) 2025, GigaDevice Semiconductor Inc.
+
+    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 of the copyright holder 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 HOLDER 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.
+*/
+
+#include "gd32f3x0_cmp.h"
+
+/*!
+    \brief      CMP deinit
+    \param[in]  cmp_periph
+      \arg        CMP0: comparator 0
+      \arg        CMP1: comparator 1
+    \param[out] none
+    \retval     none
+*/
+void cmp_deinit(cmp_enum cmp_periph)
+{
+    if(CMP0 == cmp_periph){
+        CMP_CS &= ((uint32_t)0xFFFF0000U);
+    }else if(CMP1 == cmp_periph){
+        CMP_CS &= ((uint32_t)0x0000FFFFU);
+    }else{
+    }
+}
+
+/*!
+    \brief      CMP mode init
+    \param[in]  cmp_periph
+      \arg        CMP0: comparator 0
+      \arg        CMP1: comparator 1
+    \param[in]  operating_mode
+      \arg        CMP_MODE_HIGHSPEED: high speed mode
+      \arg        CMP_MODE_MIDDLESPEED: medium speed mode
+      \arg        CMP_MODE_LOWSPEED: low speed mode
+      \arg        CMP_MODE_VERYLOWSPEED: very-low speed mode
+    \param[in]  inverting_input
+      \arg        CMP_INVERTING_INPUT_1_4VREFINT: VREFINT *1/4 input
+      \arg        CMP_INVERTING_INPUT_1_2VREFINT: VREFINT *1/2 input
+      \arg        CMP_INVERTING_INPUT_3_4VREFINT: VREFINT *3/4 input
+      \arg        CMP_INVERTING_INPUT_VREFINT: VREFINT input
+      \arg        CMP_INVERTING_INPUT_PA4: PA4(DAC0_OUT0) input
+      \arg        CMP_INVERTING_INPUT_PA5: PA5 input
+      \arg        CMP_INVERTING_INPUT_PA0_PA2: PA0 for CMP0 or PA2 for CMP1 as inverting input
+    \param[in]  output_hysteresis
+      \arg        CMP_HYSTERESIS_NO: output no hysteresis
+      \arg        CMP_HYSTERESIS_LOW: output low hysteresis
+      \arg        CMP_HYSTERESIS_MIDDLE: output middle hysteresis
+      \arg        CMP_HYSTERESIS_HIGH: output high hysteresis
+    \param[out] none
+    \retval     none
+*/
+void cmp_mode_init(cmp_enum cmp_periph, uint32_t operating_mode, uint32_t inverting_input, uint32_t output_hysteresis)
+{
+    uint32_t temp = 0U;
+
+    if(CMP0 == cmp_periph){
+        /* initialize comparator 0 mode */
+        temp = CMP_CS;
+        temp &= ~(uint32_t)(CMP_CS_CMP0M | CMP_CS_CMP0MSEL | CMP_CS_CMP0HST);
+        temp |= (uint32_t)(operating_mode | inverting_input | output_hysteresis);
+        CMP_CS = temp;
+    }else if(CMP1 == cmp_periph){
+        /* initialize comparator 1 mode */
+        temp = CMP_CS;
+        temp &= ~(uint32_t)(CMP_CS_CMP1M | CMP_CS_CMP1MSEL | CMP_CS_CMP1HST);
+        temp |= (uint32_t)((operating_mode | inverting_input | output_hysteresis) << 16U);
+        CMP_CS = temp;
+    }else{
+    }
+}
+
+/*!
+    \brief      CMP output init
+    \param[in]  cmp_periph
+      \arg        CMP0: comparator 0
+      \arg        CMP1: comparator 1
+    \param[in]  output_selection
+      \arg        CMP_OUTPUT_NONE: CMP output none
+      \arg        CMP_OUTPUT_TIMER0_BRKIN: CMP output TIMER0 break input
+      \arg        CMP_OUTPUT_TIMER0_IC0: CMP output TIMER0_CH0 input capture
+      \arg        CMP_OUTPUT_TIMER0_OCPRECLR: CMP output TIMER0 OCPRE_CLR input
+      \arg        CMP_OUTPUT_TIMER1_IC3: CMP output TIMER1_CH3 input capture
+      \arg        CMP_OUTPUT_TIMER1_OCPRECLR: CMP output TIMER1 OCPRE_CLR input
+      \arg        CMP_OUTPUT_TIMER2_IC0: CMP output TIMER2_CH0 input capture
+      \arg        CMP_OUTPUT_TIMER2_OCPRECLR: CMP output TIMER2 OCPRE_CLR input
+    \param[in]  output_polarity
+      \arg        CMP_OUTPUT_POLARITY_INVERTED: output is inverted
+      \arg        CMP_OUTPUT_POLARITY_NONINVERTED: output is not inverted
+    \param[out] none
+    \retval     none
+*/
+void cmp_output_init(cmp_enum cmp_periph, uint32_t output_selection, uint32_t output_polarity)
+{
+    uint32_t temp = 0U;
+
+    if(CMP0 == cmp_periph){
+        /* initialize comparator 0 output */
+        temp = CMP_CS;
+        temp &= ~(uint32_t)CMP_CS_CMP0OSEL;
+        temp |= (uint32_t)output_selection;
+        /* output polarity */
+        if(CMP_OUTPUT_POLARITY_INVERTED == output_polarity){
+            temp |= (uint32_t)CMP_CS_CMP0PL;
+        }else{
+            temp &= ~(uint32_t)CMP_CS_CMP0PL;
+        }
+        CMP_CS = temp;
+    }else if(CMP1 == cmp_periph){
+        /* initialize comparator 1 output */
+        temp = CMP_CS;
+        temp &= ~(uint32_t)CMP_CS_CMP1OSEL;
+        temp |= (uint32_t)(output_selection << 16U);
+        /* output polarity */
+        if(CMP_OUTPUT_POLARITY_INVERTED == output_polarity){
+            temp |= (uint32_t)CMP_CS_CMP1PL;
+        }else{
+            temp &= ~(uint32_t)CMP_CS_CMP1PL;
+        }
+        CMP_CS = temp;
+    }else{
+    }
+}
+
+/*!
+    \brief      enable CMP
+    \param[in]  cmp_periph
+      \arg        CMP0: comparator 0
+      \arg        CMP1: comparator 1
+    \param[out] none
+    \retval     none
+*/
+void cmp_enable(cmp_enum cmp_periph)
+{
+    if(CMP0 == cmp_periph){
+        CMP_CS |= (uint32_t)CMP_CS_CMP0EN;
+    }else if(CMP1 == cmp_periph){
+        CMP_CS |= (uint32_t)CMP_CS_CMP1EN;
+    }else{
+    }
+}
+
+/*!
+    \brief      disable CMP
+    \param[in]  cmp_periph
+      \arg        CMP0: comparator 0
+      \arg        CMP1: comparator 1
+    \param[out] none
+    \retval     none
+*/
+void cmp_disable(cmp_enum cmp_periph)
+{
+    if(CMP0 == cmp_periph){
+        CMP_CS &= ~(uint32_t)CMP_CS_CMP0EN;
+    }else if(CMP1 == cmp_periph){
+        CMP_CS &= ~(uint32_t)CMP_CS_CMP1EN;
+    }else{
+    }
+}
+
+/*!
+    \brief      enable CMP switch
+    \param[in]  none
+    \param[out] none
+    \retval     none
+*/
+void cmp_switch_enable(void)
+{
+    CMP_CS |= (uint32_t)CMP_CS_CMP0SW;
+}
+
+/*!
+    \brief      disable CMP switch
+    \param[in]  none
+    \param[out] none
+    \retval     none
+*/
+void cmp_switch_disable(void)
+{
+    CMP_CS &= ~(uint32_t)CMP_CS_CMP0SW;
+}
+
+/*!
+    \brief      enable the window mode
+    \param[in]  none
+    \param[out] none
+    \retval     none
+*/
+void cmp_window_enable(void)
+{
+    CMP_CS |= (uint32_t)CMP_CS_WNDEN;
+}
+
+/*!
+    \brief      disable the window mode
+    \param[in]  none
+    \param[out] none
+    \retval     none
+*/
+void cmp_window_disable(void)
+{
+    CMP_CS &= ~(uint32_t)CMP_CS_WNDEN;
+}
+
+/*!
+    \brief      lock the CMP
+    \param[in]  cmp_periph
+      \arg        CMP0: comparator 0
+      \arg        CMP1: comparator 1
+    \param[out] none
+    \retval     none
+*/
+void cmp_lock_enable(cmp_enum cmp_periph)
+{
+    if(CMP0 == cmp_periph){
+        /* lock CMP0 */
+        CMP_CS |= (uint32_t)CMP_CS_CMP0LK;
+    }else if(CMP1 == cmp_periph){
+        /* lock CMP1 */
+        CMP_CS |= (uint32_t)CMP_CS_CMP1LK;
+    }else{
+    }
+}
+
+/*!
+    \brief      get output level
+    \param[in]  cmp_periph
+      \arg        CMP0: comparator 0
+      \arg        CMP1: comparator 1
+    \param[out] none
+    \retval     the output level
+*/
+uint32_t cmp_output_level_get(cmp_enum cmp_periph)
+{
+    if(CMP0 == cmp_periph){
+        /* get output level of CMP0 */
+        if((uint32_t)RESET != (CMP_CS & CMP_CS_CMP0O)) {
+            return CMP_OUTPUTLEVEL_HIGH;
+        }else{
+            return CMP_OUTPUTLEVEL_LOW;
+        }
+    }else{
+        /* get output level of CMP1 */
+        if((uint32_t)RESET != (CMP_CS & CMP_CS_CMP1O)) {
+            return CMP_OUTPUTLEVEL_HIGH;
+        }else{
+            return CMP_OUTPUTLEVEL_LOW;
+        }
+    }
+}

+ 241 - 0
GD32F3x0/GD32F3x0_standard_peripheral/Source/gd32f3x0_crc.c

@@ -0,0 +1,241 @@
+/*!
+    \file    gd32f3x0_crc.c
+    \brief   CRC driver
+
+    \version 2025-01-01, V2.5.0, firmware for GD32F3x0
+*/
+
+/*
+    Copyright (c) 2025, GigaDevice Semiconductor Inc.
+
+    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 of the copyright holder 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 HOLDER 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.
+*/
+
+#include "gd32f3x0_crc.h"
+
+/*!
+    \brief      deinit CRC calculation unit
+    \param[in]  none
+    \param[out] none
+    \retval     none
+*/
+void crc_deinit(void)
+{
+    CRC_IDATA = (uint32_t)0xFFFFFFFFU;
+    CRC_DATA  = (uint32_t)0xFFFFFFFFU;
+    CRC_FDATA = (uint32_t)0x00000000U;
+    CRC_POLY  = (uint32_t)0x04C11DB7U;
+    CRC_CTL   = CRC_CTL_RST;
+}
+
+/*!
+    \brief      enable the reverse operation of output data
+    \param[in]  none
+    \param[out] none
+    \retval     none
+*/
+void crc_reverse_output_data_enable(void)
+{
+    CRC_CTL &= (uint32_t)(~ CRC_CTL_REV_O);
+    CRC_CTL |= (uint32_t)CRC_CTL_REV_O;
+}
+
+/*!
+    \brief      disable the reverse operation of output data
+    \param[in]  none
+    \param[out] none
+    \retval     none
+*/
+void crc_reverse_output_data_disable(void)
+{
+    CRC_CTL &= (uint32_t)(~ CRC_CTL_REV_O);
+}
+
+/*!
+    \brief      reset data register to the value of initializaiton data register
+    \param[in]  none
+    \param[out] none
+    \retval     none
+*/
+void crc_data_register_reset(void)
+{
+    CRC_CTL |= (uint32_t)CRC_CTL_RST;
+}
+
+/*!
+    \brief      read the data register
+    \param[in]  none
+    \param[out] none
+    \retval     32-bit value of the data register
+*/
+uint32_t crc_data_register_read(void)
+{
+    uint32_t data;
+    data = CRC_DATA;
+    return (data);
+}
+
+/*!
+    \brief      read the free data register
+    \param[in]  none
+    \param[out] none
+    \retval     8-bit value of the free data register
+*/
+uint8_t crc_free_data_register_read(void)
+{
+    uint8_t fdata;
+    fdata = (uint8_t)CRC_FDATA;
+    return (fdata);
+}
+
+/*!
+    \brief      write the free data register
+    \param[in]  free_data: specify 8-bit data
+    \param[out] none
+    \retval     none
+*/
+void crc_free_data_register_write(uint8_t free_data)
+{
+    CRC_FDATA = (uint32_t)free_data;
+}
+
+/*!
+    \brief      write the initializaiton data register
+    \param[in]  init_data:specify 32-bit data
+    \param[out] none
+    \retval     none
+*/
+void crc_init_data_register_write(uint32_t init_data)
+{
+    CRC_IDATA = (uint32_t)init_data;
+}
+
+/*!
+    \brief      configure the CRC input data function
+    \param[in]  data_reverse: specify input data reverse function
+                only one parameter can be selected which is shown as below:
+      \arg        CRC_INPUT_DATA_NOT: input data is not reversed
+      \arg        CRC_INPUT_DATA_BYTE: input data is reversed on 8 bits
+      \arg        CRC_INPUT_DATA_HALFWORD: input data is reversed on 16 bits
+      \arg        CRC_INPUT_DATA_WORD: input data is reversed on 32 bits
+    \param[out] none
+    \retval     none
+*/
+void crc_input_data_reverse_config(uint32_t data_reverse)
+{
+    CRC_CTL &= (uint32_t)(~CRC_CTL_REV_I);
+    CRC_CTL |= (uint32_t)data_reverse;
+}
+
+/*!
+    \brief      configure the CRC size of polynomial function
+    \param[in]  poly_size: size of polynomial
+                only one parameter can be selected which is shown as below:
+      \arg        CRC_CTL_PS_32: 32-bit polynomial for CRC calculation
+      \arg        CRC_CTL_PS_16: 16-bit polynomial for CRC calculation
+      \arg        CRC_CTL_PS_8: 8-bit polynomial for CRC calculation
+      \arg        CRC_CTL_PS_7: 7-bit polynomial for CRC calculation
+    \param[out] none
+    \retval     none
+*/
+void crc_polynomial_size_set(uint32_t poly_size)
+{
+    CRC_CTL &= (uint32_t)(~(CRC_CTL_PS));
+    CRC_CTL |= (uint32_t)poly_size;
+}
+
+/*!
+    \brief      configure the CRC polynomial value function
+    \param[in]  poly: configurable polynomial value
+    \param[out] none
+    \retval     none
+*/
+void crc_polynomial_set(uint32_t poly)
+{
+    CRC_POLY &= (uint32_t)(~CRC_POLY_POLY);
+    CRC_POLY = poly;
+}
+
+/*!
+    \brief      CRC calculate single data
+    \param[in]  sdata: specify input data data
+    \param[in]  data_format: input data format
+                only one parameter can be selected which is shown as below:
+      \arg        INPUT_FORMAT_WORD: input data in word format
+      \arg        INPUT_FORMAT_HALFWORD: input data in half-word format
+      \arg        INPUT_FORMAT_BYTE: input data in byte format
+    \param[out] none
+    \retval     CRC calculate value
+*/
+uint32_t crc_single_data_calculate(uint32_t sdata, uint8_t data_format)
+{
+    if(INPUT_FORMAT_WORD == data_format) {
+        REG32(CRC) = sdata;
+    } else if(INPUT_FORMAT_HALFWORD == data_format) {
+        REG16(CRC) = (uint16_t)sdata;
+    } else {
+        REG8(CRC) = (uint8_t)sdata;
+    }
+
+    return(CRC_DATA);
+}
+
+/*!
+    \brief      CRC calculate a data array
+    \param[in]  array: pointer to the input data array
+    \param[in]  size: size of the array
+    \param[in]  data_format: input data format
+                only one parameter can be selected which is shown as below:
+      \arg        INPUT_FORMAT_WORD: input data in word format
+      \arg        INPUT_FORMAT_HALFWORD: input data in half-word format
+      \arg        INPUT_FORMAT_BYTE: input data in byte format
+    \param[out] none
+    \retval     CRC calculate value
+*/
+uint32_t crc_block_data_calculate(void *array, uint32_t size, uint8_t data_format)
+{
+    uint8_t *data8;
+    uint16_t *data16;
+    uint32_t *data32;
+    uint32_t index;
+
+    if(INPUT_FORMAT_WORD == data_format) {
+        data32 = (uint32_t *)array;
+        for(index = 0U; index < size; index++) {
+            REG32(CRC) = data32[index];
+        }
+    } else if(INPUT_FORMAT_HALFWORD == data_format) {
+        data16 = (uint16_t *)array;
+        for(index = 0U; index < size; index++) {
+            REG16(CRC) = data16[index];
+        }
+    } else {
+        data8 = (uint8_t *)array;
+        for(index = 0U; index < size; index++) {
+            REG8(CRC) =  data8[index];
+        }
+    }
+
+    return (CRC_DATA);
+}

+ 380 - 0
GD32F3x0/GD32F3x0_standard_peripheral/Source/gd32f3x0_ctc.c

@@ -0,0 +1,380 @@
+/*!
+    \file    gd32f3x0_ctc.c
+    \brief   CTC driver
+
+    \version 2025-01-01, V2.5.0, firmware for GD32F3x0
+*/
+
+/*
+    Copyright (c) 2025, GigaDevice Semiconductor Inc.
+
+    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 of the copyright holder 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 HOLDER 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.
+*/
+
+#include "gd32f3x0_ctc.h"
+
+#define CTC_FLAG_MASK            ((uint32_t)0x00000700U)
+
+/*!
+    \brief      reset CTC clock trim controller
+    \param[in]  none
+    \param[out] none
+    \retval     none
+*/
+void ctc_deinit(void)
+{
+    /* reset CTC */
+    rcu_periph_reset_enable(RCU_CTCRST);
+    rcu_periph_reset_disable(RCU_CTCRST);
+}
+
+/*!
+    \brief      enable CTC trim counter
+    \param[in]  none
+    \param[out] none
+    \retval     none
+*/
+void ctc_counter_enable(void)
+{
+    CTC_CTL0 |= (uint32_t)CTC_CTL0_CNTEN;
+}
+
+/*!
+    \brief      disable CTC trim counter
+    \param[in]  none
+    \param[out] none
+    \retval     none
+*/
+void ctc_counter_disable(void)
+{
+    CTC_CTL0 &= (uint32_t)(~CTC_CTL0_CNTEN);
+}
+
+/*!
+    \brief      configure the IRC48M trim value
+    \param[in]  trim_value: 6-bit IRC48M trim value
+      \arg        0x00-0x3F
+    \param[out] none
+    \retval     none
+*/
+void ctc_irc48m_trim_value_config(uint8_t trim_value)
+{
+    /* clear TRIMVALUE bits */
+    CTC_CTL0 &= (~(uint32_t)CTC_CTL0_TRIMVALUE);
+    /* set TRIMVALUE bits */
+    CTC_CTL0 |= CTL0_TRIMVALUE(trim_value);
+}
+
+/*!
+    \brief      generate software reference source sync pulse
+    \param[in]  none
+    \param[out] none
+    \retval     none
+*/
+void ctc_software_refsource_pulse_generate(void)
+{
+    CTC_CTL0 |= (uint32_t)CTC_CTL0_SWREFPUL;
+}
+
+/*!
+    \brief      configure hardware automatically trim mode
+    \param[in]  hardmode:
+                only one parameter can be selected which is shown as below:
+      \arg        CTC_HARDWARE_TRIM_MODE_ENABLE: hardware automatically trim mode enable
+      \arg        CTC_HARDWARE_TRIM_MODE_DISABLE: hardware automatically trim mode disable
+    \param[out] none
+    \retval     none
+*/
+void ctc_hardware_trim_mode_config(uint32_t hardmode)
+{
+    CTC_CTL0 &= (uint32_t)(~CTC_CTL0_AUTOTRIM);
+    CTC_CTL0 |= (uint32_t)hardmode;
+}
+
+/*!
+    \brief      configure reference signal source polarity
+    \param[in]  polarity:
+                only one parameter can be selected which is shown as below:
+      \arg        CTC_REFSOURCE_POLARITY_FALLING: reference signal source polarity is falling edge
+      \arg        CTC_REFSOURCE_POLARITY_RISING: reference signal source polarity is rising edge
+    \param[out] none
+    \retval     none
+*/
+void ctc_refsource_polarity_config(uint32_t polarity)
+{
+    CTC_CTL1 &= (uint32_t)(~CTC_CTL1_REFPOL);
+    CTC_CTL1 |= (uint32_t)polarity;
+}
+
+/*!
+    \brief      select reference signal source
+    \param[in]  refs:
+                only one parameter can be selected which is shown as below:
+      \arg        CTC_REFSOURCE_GPIO: GPIO is selected
+      \arg        CTC_REFSOURCE_LXTAL: LXTAL is selected
+    \param[out] none
+    \retval     none
+*/
+void ctc_refsource_signal_select(uint32_t refs)
+{
+    CTC_CTL1 &= (uint32_t)(~CTC_CTL1_REFSEL);
+    CTC_CTL1 |= (uint32_t)refs;
+}
+
+/*!
+    \brief      configure reference signal source prescaler
+    \param[in]  prescaler:
+                only one parameter can be selected which is shown as below:
+      \arg        CTC_REFSOURCE_PSC_OFF: reference signal not divided
+      \arg        CTC_REFSOURCE_PSC_DIV2: reference signal divided by 2
+      \arg        CTC_REFSOURCE_PSC_DIV4: reference signal divided by 4
+      \arg        CTC_REFSOURCE_PSC_DIV8: reference signal divided by 8
+      \arg        CTC_REFSOURCE_PSC_DIV16: reference signal divided by 16
+      \arg        CTC_REFSOURCE_PSC_DIV32: reference signal divided by 32
+      \arg        CTC_REFSOURCE_PSC_DIV64: reference signal divided by 64
+      \arg        CTC_REFSOURCE_PSC_DIV128: reference signal divided by 128
+    \param[out] none
+    \retval     none
+*/
+void ctc_refsource_prescaler_config(uint32_t prescaler)
+{
+    CTC_CTL1 &= (uint32_t)(~CTC_CTL1_REFPSC);
+    CTC_CTL1 |= (uint32_t)prescaler;
+}
+
+/*!
+    \brief      configure clock trim base limit value
+    \param[in]  limit_value: 8-bit clock trim base limit value
+      \arg        0x00 - 0xFF
+    \param[out] none
+    \retval     none
+*/
+void ctc_clock_limit_value_config(uint8_t limit_value)
+{
+    CTC_CTL1 &= (uint32_t)(~CTC_CTL1_CKLIM);
+    CTC_CTL1 |= CTL1_CKLIM(limit_value);
+}
+
+/*!
+    \brief      configure CTC counter reload value
+    \param[in]  reload_value: 16-bit CTC counter reload value
+      \arg        0x0000-0xFFFF
+    \param[out] none
+    \retval     none
+*/
+void ctc_counter_reload_value_config(uint16_t reload_value)
+{
+    CTC_CTL1 &= (uint32_t)(~CTC_CTL1_RLVALUE);
+    CTC_CTL1 |= (uint32_t)reload_value;
+}
+
+/*!
+    \brief      read CTC counter capture value when reference sync pulse occurred
+    \param[in]  none
+    \param[out] none
+    \retval     the 16-bit CTC counter capture value
+*/
+uint16_t ctc_counter_capture_value_read(void)
+{
+    uint16_t capture_value = 0U;
+    capture_value = (uint16_t)GET_STAT_REFCAP(CTC_STAT);
+    return (capture_value);
+}
+
+/*!
+    \brief      read CTC trim counter direction when reference sync pulse occurred
+    \param[in]  none
+    \param[out] none
+    \retval     FlagStatus: SET or RESET
+      \arg        SET: CTC trim counter direction is down-counting
+      \arg        RESET: CTC trim counter direction is up-counting
+*/
+FlagStatus ctc_counter_direction_read(void)
+{
+    FlagStatus ret_status = RESET;
+    if(RESET != (CTC_STAT & CTC_STAT_REFDIR)) {
+        ret_status = SET;
+    }
+    return ret_status;
+}
+
+/*!
+    \brief      read CTC counter reload value
+    \param[in]  none
+    \param[out] none
+    \retval     the 16-bit CTC counter reload value
+*/
+uint16_t ctc_counter_reload_value_read(void)
+{
+    uint16_t reload_value = 0U;
+    reload_value = (uint16_t)(CTC_CTL1 & CTC_CTL1_RLVALUE);
+    return (reload_value);
+}
+
+/*!
+    \brief      read the IRC48M trim value
+    \param[in]  none
+    \param[out] none
+    \retval     the 6-bit IRC48M trim value
+*/
+uint8_t ctc_irc48m_trim_value_read(void)
+{
+    uint8_t trim_value = 0U;
+    trim_value = (uint8_t)GET_CTL0_TRIMVALUE(CTC_CTL0);
+    return (trim_value);
+}
+
+/*!
+    \brief      get CTC flag
+    \param[in]  flag: the CTC flag
+                only one parameter can be selected which is shown as below:
+      \arg        CTC_FLAG_CKOK: clock trim OK flag
+      \arg        CTC_FLAG_CKWARN: clock trim warning flag
+      \arg        CTC_FLAG_ERR: error flag
+      \arg        CTC_FLAG_EREF: expect reference flag
+      \arg        CTC_FLAG_CKERR: clock trim error bit
+      \arg        CTC_FLAG_REFMISS: reference sync pulse miss
+      \arg        CTC_FLAG_TRIMERR: trim value error bit
+    \param[out] none
+    \retval     FlagStatus: SET or RESET
+*/
+FlagStatus ctc_flag_get(uint32_t flag)
+{
+    FlagStatus ret_status = RESET;
+
+    if(RESET != (CTC_STAT & flag)) {
+        ret_status = SET;
+    }
+    return ret_status;
+}
+
+/*!
+    \brief      clear CTC flag
+    \param[in]  flag: the CTC flag
+                only one parameter can be selected which is shown as below:
+      \arg        CTC_FLAG_CKOK: clock trim OK flag
+      \arg        CTC_FLAG_CKWARN: clock trim warning flag
+      \arg        CTC_FLAG_ERR: error flag
+      \arg        CTC_FLAG_EREF: expect reference flag
+      \arg        CTC_FLAG_CKERR: clock trim error bit
+      \arg        CTC_FLAG_REFMISS: reference sync pulse miss
+      \arg        CTC_FLAG_TRIMERR: trim value error bit
+    \param[out] none
+    \retval     none
+*/
+void ctc_flag_clear(uint32_t flag)
+{
+    if(RESET != (flag & CTC_FLAG_MASK)){
+        CTC_INTC |= CTC_INTC_ERRIC;
+    } else {
+        CTC_INTC |= flag;
+    }
+}
+/*!
+    \brief      enable the CTC interrupt
+    \param[in]  interrupt: CTC interrupt enable
+                one or more parameters can be selected which are shown as below:
+      \arg        CTC_INT_CKOK: clock trim OK interrupt enable
+      \arg        CTC_INT_CKWARN: clock trim warning interrupt enable
+      \arg        CTC_INT_ERR: error interrupt enable
+      \arg        CTC_INT_EREF: expect reference interrupt enable
+    \param[out] none
+    \retval     none
+*/
+void ctc_interrupt_enable(uint32_t interrupt)
+{
+    CTC_CTL0 |= (uint32_t)interrupt;
+}
+
+/*!
+    \brief      disable the CTC interrupt
+    \param[in]  interrupt: CTC interrupt enable source
+                one or more parameters can be selected which are shown as below:
+      \arg        CTC_INT_CKOK: clock trim OK interrupt enable
+      \arg        CTC_INT_CKWARN: clock trim warning interrupt enable
+      \arg        CTC_INT_ERR: error interrupt enable
+      \arg        CTC_INT_EREF: expect reference interrupt enable
+    \param[out] none
+    \retval     none
+*/
+void ctc_interrupt_disable(uint32_t interrupt)
+{
+    CTC_CTL0 &= (uint32_t)(~interrupt); 
+}
+
+/*!
+    \brief      get CTC interrupt flag
+    \param[in]  int_flag: the CTC interrupt flag
+                only one parameter can be selected which is shown as below:
+      \arg        CTC_INT_FLAG_CKOK: clock trim OK interrupt
+      \arg        CTC_INT_FLAG_CKWARN: clock trim warning interrupt
+      \arg        CTC_INT_FLAG_ERR: error interrupt
+      \arg        CTC_INT_FLAG_EREF: expect reference interrupt
+      \arg        CTC_INT_FLAG_CKERR: clock trim error bit interrupt
+      \arg        CTC_INT_FLAG_REFMISS: reference sync pulse miss interrupt
+      \arg        CTC_INT_FLAG_TRIMERR: trim value error interrupt
+    \param[out] none
+    \retval     FlagStatus: SET or RESET
+*/
+FlagStatus ctc_interrupt_flag_get(uint32_t int_flag)
+{
+    uint32_t interrupt_flag = 0U, intenable = 0U;
+    FlagStatus ret_status = RESET;
+
+    /* check whether the interrupt is enabled */
+    if(RESET != (int_flag & CTC_FLAG_MASK)){
+        intenable = CTC_CTL0 & CTC_INT_ERR;
+    } else {
+        intenable = CTC_CTL0 & int_flag;
+    }
+    interrupt_flag = CTC_STAT & int_flag;
+
+    if(interrupt_flag && intenable) {
+        ret_status = SET;
+    }
+    return ret_status;
+}
+
+/*!
+    \brief      clear CTC interrupt flag
+    \param[in]  int_flag: the CTC interrupt flag
+                only one parameter can be selected which is shown as below:
+      \arg        CTC_INT_FLAG_CKOK: clock trim OK interrupt
+      \arg        CTC_INT_FLAG_CKWARN: clock trim warning interrupt
+      \arg        CTC_INT_FLAG_ERR: error interrupt
+      \arg        CTC_INT_FLAG_EREF: expect reference interrupt
+      \arg        CTC_INT_FLAG_CKERR: clock trim error bit interrupt
+      \arg        CTC_INT_FLAG_REFMISS: reference sync pulse miss interrupt
+      \arg        CTC_INT_FLAG_TRIMERR: trim value error interrupt
+    \param[out] none
+    \retval     none
+*/
+void ctc_interrupt_flag_clear(uint32_t int_flag)
+{
+    if(RESET != (int_flag & CTC_FLAG_MASK)){
+        CTC_INTC |= CTC_INTC_ERRIC;
+    } else {
+        CTC_INTC |= int_flag;
+    }
+}

+ 509 - 0
GD32F3x0/GD32F3x0_standard_peripheral/Source/gd32f3x0_dac.c

@@ -0,0 +1,509 @@
+/*!
+    \file    gd32f3x0_dac.c
+    \brief   DAC driver
+
+    \version 2025-01-01, V2.5.0, firmware for GD32F3x0
+*/
+
+/*
+    Copyright (c) 2025, GigaDevice Semiconductor Inc.
+
+    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 of the copyright holder 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 HOLDER 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.
+*/
+
+#if (defined(GD32F350) || defined(GD32F355) || defined(GD32F370))
+#include "gd32f3x0_dac.h"
+
+/* DAC register bit offset */
+#define OUT1_REG_OFFSET           ((uint32_t)0x00000010U)
+#define DH_12BIT_OFFSET           ((uint32_t)0x00000010U)
+#define DH_8BIT_OFFSET            ((uint32_t)0x00000008U)
+
+#define DAC_STAT_FLAG_MASK0       (DAC_INT_FLAG_DDUDR0)
+#define DAC_INT_EN_MASK0          (DAC_INT_DDUDR0)
+#define DAC_INT_FLAG_MASK0        (DAC_INT_FLAG_DDUDR0)
+
+/*!
+    \brief      deinitialize DAC
+    \param[in]  dac_periph: DACx(x=0)
+    \param[out] none
+    \retval     none
+*/
+void dac_deinit(uint32_t dac_periph)
+{
+    switch(dac_periph){
+        case DAC0:
+            /* reset DAC0 */
+            rcu_periph_reset_enable(RCU_DACRST);
+            rcu_periph_reset_disable(RCU_DACRST);
+            break;
+        default:
+            break;
+    }
+}
+
+/*!
+    \brief      enable DAC
+    \param[in]  dac_periph: DACx(x=0)
+    \param[in]  dac_out: DAC_OUTx(x=0)
+    \param[out] none
+    \retval     none
+*/
+void dac_enable(uint32_t dac_periph, uint8_t dac_out)
+{
+    if(DAC_OUT0 == dac_out){
+        DAC_CTL0(dac_periph) |= (uint32_t)DAC_CTL0_DEN0;
+    }else{
+        /* illegal parameters */
+    }
+}
+
+/*!
+    \brief      disable DAC
+    \param[in]  dac_periph: DACx(x=0)
+    \param[in]  dac_out: DAC_OUTx(x=0)
+    \param[out] none
+    \retval     none
+*/
+void dac_disable(uint32_t dac_periph, uint8_t dac_out)
+{
+    if(DAC_OUT0 == dac_out){
+        DAC_CTL0(dac_periph) &= (uint32_t)(~DAC_CTL0_DEN0);
+    }else{
+        /* illegal parameters */
+    }
+}
+
+/*!
+    \brief      enable DAC DMA function
+    \param[in]  dac_periph: DACx(x=0)
+    \param[in]  dac_out: DAC_OUTx(x=0)
+    \param[out] none
+    \retval     none
+*/
+void dac_dma_enable(uint32_t dac_periph, uint8_t dac_out)
+{
+    if(DAC_OUT0 == dac_out){
+        DAC_CTL0(dac_periph) |= (uint32_t)DAC_CTL0_DDMAEN0;
+    }else{
+        /* illegal parameters */
+    }
+}
+
+/*!
+    \brief      disable DAC DMA function
+    \param[in]  dac_periph: DACx(x=0)
+    \param[in]  dac_out: DAC_OUTx(x=0)
+    \param[out] none
+    \retval     none
+*/
+void dac_dma_disable(uint32_t dac_periph, uint8_t dac_out)
+{
+    if(DAC_OUT0 == dac_out){
+        DAC_CTL0(dac_periph) &= (uint32_t)(~DAC_CTL0_DDMAEN0);
+    }else{
+        /* illegal parameters */
+    }
+}
+
+/*!
+    \brief      enable DAC output buffer
+    \param[in]  dac_periph: DACx(x=0)
+    \param[in]  dac_out: DAC_OUTx(x=0)
+    \param[out] none
+    \retval     none
+*/
+void dac_output_buffer_enable(uint32_t dac_periph, uint8_t dac_out)
+{
+    if(DAC_OUT0 == dac_out){
+        DAC_CTL0(dac_periph) &= (uint32_t)(~DAC_CTL0_DBOFF0);
+    }else{
+        /* illegal parameters */
+    }
+}
+
+/*!
+    \brief      disable DAC output buffer
+    \param[in]  dac_periph: DACx(x=0)
+    \param[in]  dac_out: DAC_OUTx(x=0)
+    \param[out] none
+    \retval     none
+*/
+void dac_output_buffer_disable(uint32_t dac_periph, uint8_t dac_out)
+{
+    if(DAC_OUT0 == dac_out){
+        DAC_CTL0(dac_periph) |= (uint32_t)DAC_CTL0_DBOFF0;
+    }else{
+        /* illegal parameters */
+    }
+}
+
+/*!
+    \brief      get DAC output value
+    \param[in]  dac_periph: DACx(x=0)
+    \param[in]  dac_out: DAC_OUTx(x=0)
+    \param[out] none
+    \retval     DAC output data: 0~4095
+*/
+uint16_t dac_output_value_get(uint32_t dac_periph, uint8_t dac_out)
+{
+    uint16_t data = 0U;
+
+    if(DAC_OUT0 == dac_out){
+        /* store the DACx_OUT0 output value */
+        data = (uint16_t)DAC_OUT0_DO(dac_periph);
+    }else{
+        /* illegal parameters */
+    }
+
+    return data;
+}
+
+/*!
+    \brief      set DAC data holding register value
+    \param[in]  dac_periph: DACx(x=0)
+    \param[in]  dac_out: DAC_OUTx(x=0)
+    \param[in]  dac_align: DAC data alignment mode
+                only one parameter can be selected which is shown as below:
+      \arg        DAC_ALIGN_12B_R: 12-bit right-aligned data
+      \arg        DAC_ALIGN_12B_L: 12-bit left-aligned data
+      \arg        DAC_ALIGN_8B_R: 8-bit right-aligned data
+    \param[in]  data: data to be loaded(0~4095)
+    \param[out] none
+    \retval     none
+*/
+void dac_data_set(uint32_t dac_periph, uint8_t dac_out, uint32_t dac_align, uint16_t data)
+{
+    /* DAC_OUT0 data alignment */
+    if(DAC_OUT0 == dac_out){
+        switch(dac_align){
+        /* 12-bit right-aligned data */
+        case DAC_ALIGN_12B_R:
+            DAC_OUT0_R12DH(dac_periph) = data;
+            break;
+        /* 12-bit left-aligned data */
+        case DAC_ALIGN_12B_L:
+            DAC_OUT0_L12DH(dac_periph) = data;
+            break;
+        /* 8-bit right-aligned data */
+        case DAC_ALIGN_8B_R:
+            DAC_OUT0_R8DH(dac_periph) = data;
+            break;
+        default:
+            break;
+        }
+    }else{
+        /* illegal parameters */
+    }
+}
+
+/*!
+    \brief      enable DAC trigger
+    \param[in]  dac_periph: DACx(x=0)
+    \param[in]  dac_out: DAC_OUTx(x=0)
+    \param[out] none
+    \retval     none
+*/
+void dac_trigger_enable(uint32_t dac_periph, uint8_t dac_out)
+{
+    if(DAC_OUT0 == dac_out){
+        DAC_CTL0(dac_periph) |= (uint32_t)DAC_CTL0_DTEN0;
+    }else{
+        /* illegal parameters */
+    }
+}
+
+/*!
+    \brief      disable DAC trigger
+    \param[in]  dac_periph: DACx(x=0)
+    \param[in]  dac_out: DAC_OUTx(x=0)
+    \param[out] none
+    \retval     none
+*/
+void dac_trigger_disable(uint32_t dac_periph, uint8_t dac_out)
+{
+    if(DAC_OUT0 == dac_out){
+        DAC_CTL0(dac_periph) &= (uint32_t)(~DAC_CTL0_DTEN0);
+    }else{
+        /* illegal parameters */
+    }
+}
+
+/*!
+    \brief      configure DAC trigger source
+    \param[in]  dac_periph: DACx(x=0)
+    \param[in]  dac_out: DAC_OUTx(x=0)
+    \param[in]  triggersource: external trigger of DAC
+                only one parameter can be selected which is shown as below:
+      \arg        DAC_TRIGGER_T5_TRGO: TIMER5 TRGO
+      \arg        DAC_TRIGGER_T14_TRGO: TIMER14 TRGO
+      \arg        DAC_TRIGGER_T2_TRGO: TIMER2 TRGO
+      \arg        DAC_TRIGGER_T1_TRGO: TIMER1 TRGO
+      \arg        DAC_TRIGGER_EXTI_9: EXTI interrupt line9 event
+      \arg        DAC_TRIGGER_SOFTWARE: software trigger
+    \param[out] none
+    \retval     none
+*/
+void dac_trigger_source_config(uint32_t dac_periph, uint8_t dac_out, uint32_t triggersource)
+{
+    if(DAC_OUT0 == dac_out){
+        /* configure DACx_OUT0 trigger source */
+        DAC_CTL0(dac_periph) &= (uint32_t)(~(DAC_CTL0_DTSEL0));
+        DAC_CTL0(dac_periph) |= triggersource;
+    }else{
+        /* illegal parameters */
+    }
+}
+
+/*!
+    \brief      enable DAC software trigger
+    \param[in]  dac_periph: DACx(x=0)
+    \param[in]  dac_out: DAC_OUTx(x=0)
+    \retval     none
+*/
+void dac_software_trigger_enable(uint32_t dac_periph, uint8_t dac_out)
+{
+    if(DAC_OUT0 == dac_out){
+        DAC_SWT(dac_periph) |= (uint32_t)DAC_SWT_SWTR0;
+    }else{
+        /* illegal parameters */
+    }
+}
+
+/*!
+    \brief      configure DAC wave mode
+    \param[in]  dac_periph: DACx(x=0)
+    \param[in]  dac_out: DAC_OUTx(x=0)
+    \param[in]  wave_mode: DAC wave mode
+                only one parameter can be selected which is shown as below:
+      \arg        DAC_WAVE_DISABLE: wave mode disable
+      \arg        DAC_WAVE_MODE_LFSR: LFSR noise mode
+      \arg        DAC_WAVE_MODE_TRIANGLE: triangle noise mode
+    \param[out] none
+    \retval     none
+*/
+void dac_wave_mode_config(uint32_t dac_periph, uint8_t dac_out, uint32_t wave_mode)
+{
+    if(DAC_OUT0 == dac_out){
+        /* configure DACx_OUT0 wave mode */
+        DAC_CTL0(dac_periph) &= (uint32_t)(~DAC_CTL0_DWM0);
+        DAC_CTL0(dac_periph) |= wave_mode;
+    }else{
+        /* illegal parameters */
+    }
+}
+
+/*!
+    \brief      configure DAC LFSR noise mode
+    \param[in]  dac_periph: DACx(x=0)
+    \param[in]  dac_out: DAC_OUTx(x=0)
+    \param[in]  unmask_bits: LFSR noise unmask bits
+                only one parameter can be selected which is shown as below:
+      \arg        DAC_LFSR_BIT0: unmask the LFSR bit0
+      \arg        DAC_LFSR_BITS1_0: unmask the LFSR bits[1:0]
+      \arg        DAC_LFSR_BITS2_0: unmask the LFSR bits[2:0]
+      \arg        DAC_LFSR_BITS3_0: unmask the LFSR bits[3:0]
+      \arg        DAC_LFSR_BITS4_0: unmask the LFSR bits[4:0]
+      \arg        DAC_LFSR_BITS5_0: unmask the LFSR bits[5:0]
+      \arg        DAC_LFSR_BITS6_0: unmask the LFSR bits[6:0]
+      \arg        DAC_LFSR_BITS7_0: unmask the LFSR bits[7:0]
+      \arg        DAC_LFSR_BITS8_0: unmask the LFSR bits[8:0]
+      \arg        DAC_LFSR_BITS9_0: unmask the LFSR bits[9:0]
+      \arg        DAC_LFSR_BITS10_0: unmask the LFSR bits[10:0]
+      \arg        DAC_LFSR_BITS11_0: unmask the LFSR bits[11:0]
+    \param[out] none
+    \retval     none
+*/
+void dac_lfsr_noise_config(uint32_t dac_periph, uint8_t dac_out, uint32_t unmask_bits)
+{
+    if(DAC_OUT0 == dac_out){
+        /* configure DACx_OUT0 LFSR noise mode */
+        DAC_CTL0(dac_periph) &= (uint32_t)(~DAC_CTL0_DWBW0);
+        DAC_CTL0(dac_periph) |= unmask_bits;
+    }else{
+        /* illegal parameters */
+    }
+}
+
+/*!
+    \brief      configure DAC triangle noise mode
+    \param[in]  dac_periph: DACx(x=0)
+    \param[in]  dac_out: DAC_OUTx(x=0)
+    \param[in]  amplitude: the amplitude of the triangle
+                only one parameter can be selected which is shown as below:
+      \arg        DAC_TRIANGLE_AMPLITUDE_1: triangle amplitude is 1
+      \arg        DAC_TRIANGLE_AMPLITUDE_3: triangle amplitude is 3
+      \arg        DAC_TRIANGLE_AMPLITUDE_7: triangle amplitude is 7
+      \arg        DAC_TRIANGLE_AMPLITUDE_15: triangle amplitude is 15
+      \arg        DAC_TRIANGLE_AMPLITUDE_31: triangle amplitude is 31
+      \arg        DAC_TRIANGLE_AMPLITUDE_63: triangle amplitude is 63
+      \arg        DAC_TRIANGLE_AMPLITUDE_127: triangle amplitude is 127
+      \arg        DAC_TRIANGLE_AMPLITUDE_255: triangle amplitude is 255
+      \arg        DAC_TRIANGLE_AMPLITUDE_511: triangle amplitude is 511
+      \arg        DAC_TRIANGLE_AMPLITUDE_1023: triangle amplitude is 1023
+      \arg        DAC_TRIANGLE_AMPLITUDE_2047: triangle amplitude is 2047
+      \arg        DAC_TRIANGLE_AMPLITUDE_4095: triangle amplitude is 4095
+    \param[out] none
+    \retval     none
+*/
+void dac_triangle_noise_config(uint32_t dac_periph, uint8_t dac_out, uint32_t amplitude)
+{
+    if(DAC_OUT0 == dac_out){
+        /* configure DACx_OUT0 triangle noise mode */
+        DAC_CTL0(dac_periph) &= (uint32_t)(~DAC_CTL0_DWBW0);
+        DAC_CTL0(dac_periph) |= amplitude;
+    }else{
+        /* illegal parameters */
+    }
+}
+
+/*!
+    \brief      get DAC flag
+    \param[in]  dac_periph: DACx(x=0)
+    \param[in]  flag: the DAC status flags, only one parameter can be selected which is shown
+                as below:
+      \arg        DAC_FLAG_DDUDR0: DACx_OUT0 DMA underrun flag
+    \param[out] none
+    \retval     the state of DAC bit(SET or RESET)
+*/
+FlagStatus dac_flag_get(uint32_t dac_periph, uint32_t flag)
+{
+    if(flag & DAC_STAT_FLAG_MASK0){
+        /* check DAC_STAT0 flag */
+        if(RESET != (DAC_STAT0(dac_periph) & flag)){
+            return SET;
+        }else{
+            return RESET;
+        }
+    }else{
+        /* illegal parameters */
+        return RESET;
+    }
+}
+
+/*!
+    \brief      clear DAC flag
+    \param[in]  dac_periph: DACx(x=0)
+    \param[in]  flag: DAC flag
+                only one parameter can be selected which is shown as below:
+      \arg        DAC_FLAG_DDUDR0: DACx_OUT0 DMA underrun flag
+    \param[out] none
+    \retval     none
+*/
+void dac_flag_clear(uint32_t dac_periph, uint32_t flag)
+{
+    if(flag & DAC_STAT_FLAG_MASK0){
+        /* check DAC_STAT0 flag */
+        DAC_STAT0(dac_periph) = (uint32_t)(flag & DAC_STAT_FLAG_MASK0);
+    }else{
+        /* illegal parameters */
+    }
+}
+
+/*!
+    \brief      enable DAC interrupt
+    \param[in]  dac_periph: DACx(x=0)
+    \param[in]  interrupt: the DAC interrupt
+                only one parameter can be selected which is shown as below:
+      \arg        DAC_INT_DDUDR0: DACx_OUT0 DMA underrun interrupt
+    \param[out] none
+    \retval     none
+*/
+void dac_interrupt_enable(uint32_t dac_periph, uint32_t interrupt)
+{
+    if(interrupt & DAC_INT_EN_MASK0){
+        /* enable underrun interrupt */
+        DAC_CTL0(dac_periph) |= (uint32_t)(interrupt & DAC_INT_EN_MASK0);
+    }else{
+        /* illegal parameters */
+    }
+}
+
+/*!
+    \brief      disable DAC interrupt
+    \param[in]  dac_periph: DACx(x=0)
+    \param[in]  interrupt: the DAC interrupt
+                only one parameter can be selected which is shown as below:
+      \arg        DAC_INT_DDUDR0: DACx_OUT0 DMA underrun interrupt
+    \param[out] none
+    \retval     none
+*/
+void dac_interrupt_disable(uint32_t dac_periph, uint32_t interrupt)
+{
+    if(interrupt & DAC_INT_EN_MASK0){
+        /* disable underrun interrupt */
+        DAC_CTL0(dac_periph) &= (uint32_t)(~(interrupt & DAC_INT_EN_MASK0));
+    }else{
+        /* illegal parameters */
+    }
+}
+
+/*!
+    \brief      get DAC interrupt flag
+    \param[in]  dac_periph: DACx(x=0)
+    \param[in]  int_flag: DAC interrupt flag
+                only one parameter can be selected which is shown as below:
+      \arg        DAC_INT_FLAG_DDUDR0: DACx_OUT0 DMA underrun interrupt flag
+    \param[out] none
+    \retval     the state of DAC interrupt flag(SET or RESET)
+*/
+FlagStatus dac_interrupt_flag_get(uint32_t dac_periph, uint32_t int_flag)
+{
+    uint32_t reg1 = 0U, reg2 = 0U;
+
+    if(int_flag & DAC_INT_FLAG_MASK0){
+        /* check underrun interrupt int_flag */
+        reg1 = DAC_STAT0(dac_periph) & int_flag;
+        reg2 = DAC_CTL0(dac_periph) & int_flag;
+    }else{
+        /* illegal parameters */
+    }
+
+    /*get DAC interrupt flag status */
+    if((RESET != reg1) && (RESET != reg2)){
+        return SET;
+    }else{
+        return RESET;
+    }
+}
+
+/*!
+    \brief      clear DAC interrupt flag
+    \param[in]  dac_periph: DACx(x=0)
+    \param[in]  int_flag: DAC interrupt flag
+                only one parameter can be selected which is shown as below:
+      \arg        DAC_INT_FLAG_DDUDR0: DACx_OUT0 DMA underrun interrupt flag
+    \param[out] none
+    \retval     none
+*/
+void dac_interrupt_flag_clear(uint32_t dac_periph, uint32_t int_flag)
+{
+    /* clear underrun interrupt int_flag */
+    if(int_flag & DAC_INT_FLAG_MASK0)
+    {
+        DAC_STAT0(dac_periph) = (uint32_t)int_flag;
+    }
+}
+
+#endif /* GD32F350 */

+ 126 - 0
GD32F3x0/GD32F3x0_standard_peripheral/Source/gd32f3x0_dbg.c

@@ -0,0 +1,126 @@
+/*!
+    \file    gd32f3x0_dbg.c
+    \brief   DBG driver
+
+    \version 2025-01-01, V2.5.0, firmware for GD32F3x0
+*/
+
+/*
+    Copyright (c) 2025, GigaDevice Semiconductor Inc.
+
+    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 of the copyright holder 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 HOLDER 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.
+*/
+
+#include "gd32f3x0_dbg.h"
+
+#define DBG_RESET_VAL       ((uint32_t)0x00000000U)   /*!< DBG reset value */
+
+/*!
+    \brief      deinitialize the DBG
+    \param[in]  none
+    \param[out] none
+    \retval     none
+*/
+void dbg_deinit(void)
+{
+    DBG_CTL0 = DBG_RESET_VAL;
+    DBG_CTL1 = DBG_RESET_VAL;
+}
+
+/*!
+    \brief      read DBG_ID code register
+    \param[in]  none
+    \param[out] none
+    \retval     DBG_ID code
+*/
+uint32_t dbg_id_get(void)
+{
+    return DBG_ID;
+}
+
+/*!
+    \brief      enable low power behavior when the mcu is in debug mode
+    \param[in]  dbg_low_power:
+                one or more parameters can be selected which are shown as below:
+      \arg        DBG_LOW_POWER_SLEEP: keep debugger connection during sleep mode
+      \arg        DBG_LOW_POWER_DEEPSLEEP: keep debugger connection during deepsleep mode
+      \arg        DBG_LOW_POWER_STANDBY: keep debugger connection during standby mode
+    \param[out] none
+    \retval     none
+*/
+void dbg_low_power_enable(uint32_t dbg_low_power)
+{
+    DBG_CTL0 |= dbg_low_power;
+}
+
+/*!
+    \brief      disable low power behavior when the mcu is in debug mode
+    \param[in]  dbg_low_power:
+                one or more parameters can be selected which are shown as below:
+      \arg        DBG_LOW_POWER_SLEEP: donot keep debugger connection during sleep mode
+      \arg        DBG_LOW_POWER_DEEPSLEEP: donot keep debugger connection during deepsleep mode
+      \arg        DBG_LOW_POWER_STANDBY: donot keep debugger connection during standby mode
+    \param[out] none
+    \retval     none
+*/
+void dbg_low_power_disable(uint32_t dbg_low_power)
+{
+    DBG_CTL0 &= ~dbg_low_power;
+}
+
+/*!
+    \brief      enable peripheral behavior when the mcu is in debug mode
+    \param[in]  dbg_periph: refer to dbg_periph_enum
+                only one parameter can be selected which are shown as below:
+      \arg        DBG_FWDGT_HOLD: debug FWDGT kept when core is halted
+      \arg        DBG_WWDGT_HOLD: debug WWDGT kept when core is halted
+      \arg        DBG_TIMERx_HOLD (x=0,1,2,5,13,14,15,16,TIMER5 is only available in GD32F350, 
+                  TIMER1 is only available in GD32F350 and GD32F330): hold TIMERx counter when core is halted
+      \arg        DBG_I2Cx_HOLD (x=0,1): hold I2Cx smbus when core is halted
+      \arg        DBG_RTC_HOLD: hold RTC calendar and wakeup counter when core is halted
+    \param[out] none
+    \retval     none
+*/
+void dbg_periph_enable(dbg_periph_enum dbg_periph)
+{
+    DBG_REG_VAL(dbg_periph) |= BIT(DBG_BIT_POS(dbg_periph));
+}
+
+/*!
+    \brief      disable peripheral behavior when the mcu is in debug mode
+    \param[in]  dbg_periph: refer to dbg_periph_enum
+                only one parameter can be selected which are shown as below:
+      \arg        DBG_FWDGT_HOLD: debug FWDGT kept when core is halted
+      \arg        DBG_WWDGT_HOLD: debug WWDGT kept when core is halted
+      \arg        DBG_TIMERx_HOLD (x=0,1,2,5,13,14,15,16,TIMER5 is only available in GD32F350, 
+                  TIMER1 is only available in GD32F350 and GD32F330): hold TIMERx counter when core is halted
+      \arg        DBG_I2Cx_HOLD (x=0,1): hold I2Cx smbus when core is halted
+      \arg        DBG_RTC_HOLD: hold RTC calendar and wakeup counter when core is halted
+    \param[out] none
+    \retval     none
+*/
+void dbg_periph_disable(dbg_periph_enum dbg_periph)
+{
+    DBG_REG_VAL(dbg_periph) &= ~BIT(DBG_BIT_POS(dbg_periph));
+}

+ 560 - 0
GD32F3x0/GD32F3x0_standard_peripheral/Source/gd32f3x0_dma.c

@@ -0,0 +1,560 @@
+/*!
+    \file    gd32f3x0_dma.c
+    \brief   DMA driver
+
+    \version 2025-01-01, V2.5.0, firmware for GD32F3x0
+*/
+
+/*
+    Copyright (c) 2025, GigaDevice Semiconductor Inc.
+
+    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 of the copyright holder 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 HOLDER 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.
+*/
+
+#include "gd32f3x0_dma.h"
+
+/*!
+    \brief      deinitialize DMA a channel registers
+    \param[in]  channelx: specify which DMA channel is deinitialized
+                only one parameter can be selected which is shown as below:
+      \arg        DMA_CHx(x=0..6)
+    \param[out] none
+    \retval     none
+*/
+void dma_deinit(dma_channel_enum channelx)
+{
+    /* disable DMA a channel */
+    DMA_CHCTL(channelx) &= ~DMA_CHXCTL_CHEN;
+    /* reset DMA channel registers */
+    DMA_CHCTL(channelx) = DMA_CHCTL_RESET_VALUE;
+    DMA_CHCNT(channelx) = DMA_CHCNT_RESET_VALUE;
+    DMA_CHPADDR(channelx) = DMA_CHPADDR_RESET_VALUE;
+    DMA_CHMADDR(channelx) = DMA_CHMADDR_RESET_VALUE;
+    DMA_INTC |= DMA_FLAG_ADD(DMA_CHINTF_RESET_VALUE, channelx);
+}
+
+/*!
+    \brief      initialize the parameters of DMA struct with the default values
+    \param[in]  init_struct: the initialization data needed to initialize DMA channel
+    \param[out] none
+    \retval     none
+*/
+void dma_struct_para_init(dma_parameter_struct *init_struct)
+{
+    /* set the DMA struct with the default values */
+    init_struct->periph_addr  = 0U;
+    init_struct->periph_width = 0U;
+    init_struct->periph_inc   = (uint8_t)DMA_PERIPH_INCREASE_DISABLE;
+    init_struct->memory_addr  = 0U;
+    init_struct->memory_width = 0U;
+    init_struct->memory_inc   = (uint8_t)DMA_MEMORY_INCREASE_DISABLE;
+    init_struct->number       = 0U;
+    init_struct->direction    = (uint8_t)DMA_PERIPHERAL_TO_MEMORY;
+    init_struct->priority     = (uint32_t)DMA_PRIORITY_LOW;
+}
+
+/*!
+    \brief      initialize DMA channel
+    \param[in]  channelx: specify which DMA channel is initialized
+                only one parameter can be selected which is shown as below:
+      \arg        DMA_CHx(x=0..6)
+    \param[in]  init_struct: the data needed to initialize DMA channel
+                  periph_addr: peripheral base address
+                  periph_width: DMA_PERIPHERAL_WIDTH_8BIT,DMA_PERIPHERAL_WIDTH_16BIT,DMA_PERIPHERAL_WIDTH_32BIT
+                  periph_inc: DMA_PERIPH_INCREASE_ENABLE,DMA_PERIPH_INCREASE_DISABLE
+                  memory_addr: memory base address
+                  memory_width: DMA_MEMORY_WIDTH_8BIT,DMA_MEMORY_WIDTH_16BIT,DMA_MEMORY_WIDTH_32BIT
+                  memory_inc: DMA_MEMORY_INCREASE_ENABLE,DMA_MEMORY_INCREASE_DISABLE
+                  direction: DMA_PERIPHERAL_TO_MEMORY,DMA_MEMORY_TO_PERIPHERAL
+                  number: the number of remaining data to be transferred by the DMA
+                  priority: DMA_PRIORITY_LOW,DMA_PRIORITY_MEDIUM,DMA_PRIORITY_HIGH,DMA_PRIORITY_ULTRA_HIGH
+    \param[out] none
+    \retval     none
+*/
+void dma_init(dma_channel_enum channelx, dma_parameter_struct *init_struct)
+{
+    uint32_t ctl;
+
+    dma_channel_disable(channelx);
+
+    /* configure peripheral base address */
+    DMA_CHPADDR(channelx) = init_struct->periph_addr;
+
+    /* configure memory base address */
+    DMA_CHMADDR(channelx) = init_struct->memory_addr;
+
+    /* configure the number of remaining data to be transferred */
+    DMA_CHCNT(channelx) = (init_struct->number & DMA_CHANNEL_CNT_MASK);
+
+    /* configure peripheral transfer width,memory transfer width,channel priotity */
+    ctl = DMA_CHCTL(channelx);
+    ctl &= ~(DMA_CHXCTL_PWIDTH | DMA_CHXCTL_MWIDTH | DMA_CHXCTL_PRIO);
+    ctl |= (init_struct->periph_width | init_struct->memory_width | init_struct->priority);
+    DMA_CHCTL(channelx) = ctl;
+
+    /* configure peripheral increasing mode */
+    if(DMA_PERIPH_INCREASE_ENABLE == init_struct->periph_inc) {
+        DMA_CHCTL(channelx) |= DMA_CHXCTL_PNAGA;
+    } else {
+        DMA_CHCTL(channelx) &= ~DMA_CHXCTL_PNAGA;
+    }
+
+    /* configure memory increasing mode */
+    if(DMA_MEMORY_INCREASE_ENABLE == init_struct->memory_inc) {
+        DMA_CHCTL(channelx) |= DMA_CHXCTL_MNAGA;
+    } else {
+        DMA_CHCTL(channelx) &= ~DMA_CHXCTL_MNAGA;
+    }
+
+    /* configure the direction of  data transfer */
+    if(DMA_PERIPHERAL_TO_MEMORY == init_struct->direction) {
+        DMA_CHCTL(channelx) &= ~DMA_CHXCTL_DIR;
+    } else {
+        DMA_CHCTL(channelx) |= DMA_CHXCTL_DIR;
+    }
+}
+
+/*!
+    \brief      enable DMA circulation mode
+    \param[in]  channelx: specify which DMA channel to set
+                only one parameter can be selected which is shown as below:
+      \arg        DMA_CHx(x=0..6)
+    \param[out] none
+    \retval     none
+*/
+void dma_circulation_enable(dma_channel_enum channelx)
+{
+    DMA_CHCTL(channelx) |= DMA_CHXCTL_CMEN;
+}
+
+/*!
+    \brief      disable DMA circulation mode
+    \param[in]  channelx: specify which DMA channel to set
+                only one parameter can be selected which is shown as below:
+      \arg        DMA_CHx(x=0..6)
+    \param[out] none
+    \retval     none
+*/
+void dma_circulation_disable(dma_channel_enum channelx)
+{
+    DMA_CHCTL(channelx) &= ~DMA_CHXCTL_CMEN;
+}
+
+/*!
+    \brief      enable memory to memory mode
+    \param[in]  channelx: specify which DMA channel to set
+                only one parameter can be selected which is shown as below:
+      \arg        DMA_CHx(x=0..6)
+    \param[out] none
+    \retval     none
+*/
+void dma_memory_to_memory_enable(dma_channel_enum channelx)
+{
+    DMA_CHCTL(channelx) |= DMA_CHXCTL_M2M;
+}
+
+/*!
+    \brief      disable memory to memory mode
+    \param[in]  channelx: specify which DMA channel to set
+                only one parameter can be selected which is shown as below:
+      \arg        DMA_CHx(x=0..6)
+    \param[out] none
+    \retval     none
+*/
+void dma_memory_to_memory_disable(dma_channel_enum channelx)
+{
+    DMA_CHCTL(channelx) &= ~DMA_CHXCTL_M2M;
+}
+
+/*!
+    \brief      enable DMA channel
+    \param[in]  channelx: specify which DMA channel to set
+                only one parameter can be selected which is shown as below:
+      \arg        DMA_CHx(x=0..6)
+    \param[out] none
+    \retval     none
+*/
+void dma_channel_enable(dma_channel_enum channelx)
+{
+    DMA_CHCTL(channelx) |= DMA_CHXCTL_CHEN;
+}
+
+/*!
+    \brief      disable DMA channel
+    \param[in]  channelx: specify which DMA channel to set
+                only one parameter can be selected which is shown as below:
+      \arg        DMA_CHx(x=0..6)
+    \param[out] none
+    \retval     none
+*/
+void dma_channel_disable(dma_channel_enum channelx)
+{
+    DMA_CHCTL(channelx) &= ~DMA_CHXCTL_CHEN;
+}
+
+/*!
+    \brief      set DMA peripheral base address
+    \param[in]  channelx: specify which DMA channel to set peripheral base address
+                only one parameter can be selected which is shown as below:
+      \arg        DMA_CHx(x=0..6)
+    \param[in]  address: peripheral base address
+    \param[out] none
+    \retval     none
+*/
+void dma_periph_address_config(dma_channel_enum channelx, uint32_t address)
+{
+    DMA_CHPADDR(channelx) = address;
+}
+
+/*!
+    \brief      set DMA memory base address
+    \param[in]  channelx: specify which DMA channel to set memory base address
+                only one parameter can be selected which is shown as below:
+      \arg        DMA_CHx(x=0..6)
+    \param[in]  address: memory base address
+    \param[out] none
+    \retval     none
+*/
+void dma_memory_address_config(dma_channel_enum channelx, uint32_t address)
+{
+    DMA_CHMADDR(channelx) = address;
+}
+
+/*!
+    \brief      set the number of remaining data to be transferred by the DMA
+    \param[in]  channelx: specify which DMA channel to set number
+                only one parameter can be selected which is shown as below:
+      \arg        DMA_CHx(x=0..6)
+    \param[in]  number: the number of remaining data to be transferred by the DMA
+    \param[out] none
+    \retval     none
+*/
+void dma_transfer_number_config(dma_channel_enum channelx, uint32_t number)
+{
+    DMA_CHCNT(channelx) = (number & DMA_CHANNEL_CNT_MASK);
+}
+
+/*!
+    \brief      get the number of remaining data to be transferred by the DMA
+    \param[in]  channelx: specify which DMA channel to set number
+                only one parameter can be selected which is shown as below:
+      \arg        DMA_CHx(x=0..6)
+    \param[out] none
+    \retval     the number of remaining data to be transferred by the DMA
+*/
+uint32_t dma_transfer_number_get(dma_channel_enum channelx)
+{
+    return (uint32_t)DMA_CHCNT(channelx);
+}
+
+/*!
+    \brief      configure priority level of DMA channel
+    \param[in]  channelx: specify which DMA channel to set
+                only one parameter can be selected which is shown as below:
+      \arg        DMA_CHx(x=0..6)
+    \param[in]  priority: priority level of this channel
+                only one parameter can be selected which is shown as below:
+      \arg        DMA_PRIORITY_LOW: low priority
+      \arg        DMA_PRIORITY_MEDIUM: medium priority
+      \arg        DMA_PRIORITY_HIGH: high priority
+      \arg        DMA_PRIORITY_ULTRA_HIGH: ultra high priority
+    \param[out] none
+    \retval     none
+*/
+void dma_priority_config(dma_channel_enum channelx, uint32_t priority)
+{
+    uint32_t ctl;
+
+    /* acquire DMA_CHxCTL register */
+    ctl = DMA_CHCTL(channelx);
+    /* assign regiser */
+    ctl &= ~DMA_CHXCTL_PRIO;
+    ctl |= priority;
+    DMA_CHCTL(channelx) = ctl;
+}
+
+/*!
+    \brief      configure transfer data width of memory
+    \param[in]  channelx: specify which DMA channel to set
+                only one parameter can be selected which is shown as below:
+      \arg        DMA_CHx(x=0..6)
+    \param[in]  mwidth: transfer data width of memory
+                only one parameter can be selected which is shown as below:
+      \arg        DMA_MEMORY_WIDTH_8BIT: transfer data width of memory is 8-bit
+      \arg        DMA_MEMORY_WIDTH_16BIT: transfer data width of memory is 16-bit
+      \arg        DMA_MEMORY_WIDTH_32BIT: transfer data width of memory is 32-bit
+    \param[out] none
+    \retval     none
+*/
+void dma_memory_width_config(dma_channel_enum channelx, uint32_t mwidth)
+{
+    uint32_t ctl;
+
+    /* acquire DMA_CHxCTL register */
+    ctl = DMA_CHCTL(channelx);
+    /* assign regiser */
+    ctl &= ~DMA_CHXCTL_MWIDTH;
+    ctl |= mwidth;
+    DMA_CHCTL(channelx) = ctl;
+}
+
+/*!
+    \brief      configure transfer data width of peripheral
+    \param[in]  channelx: specify which DMA channel
+                only one parameter can be selected which is shown as below:
+      \arg        DMA_CHx(x=0..6)
+    \param[in]  pwidth: transfer data width of peripheral
+                only one parameter can be selected which is shown as below:
+      \arg        DMA_PERIPHERAL_WIDTH_8BIT: transfer data width of peripheral is 8-bit
+      \arg        DMA_PERIPHERAL_WIDTH_16BIT: transfer data width of peripheral is 16-bit
+      \arg        DMA_PERIPHERAL_WIDTH_32BIT: transfer data width of peripheral is 32-bit
+    \param[out] none
+    \retval     none
+*/
+void dma_periph_width_config(dma_channel_enum channelx, uint32_t pwidth)
+{
+    uint32_t ctl;
+
+    /* acquire DMA_CHxCTL register */
+    ctl = DMA_CHCTL(channelx);
+    /* assign regiser */
+    ctl &= ~DMA_CHXCTL_PWIDTH;
+    ctl |= pwidth;
+    DMA_CHCTL(channelx) = ctl;
+}
+
+/*!
+    \brief      enable next address increasement algorithm of memory
+    \param[in]  channelx: specify which DMA channel to set
+                only one parameter can be selected which is shown as below:
+      \arg        DMA_CHx(x=0..6)
+    \param[out] none
+    \retval     none
+*/
+void dma_memory_increase_enable(dma_channel_enum channelx)
+{
+    DMA_CHCTL(channelx) |= DMA_CHXCTL_MNAGA;
+}
+
+/*!
+    \brief      disable next address increasement algorithm of memory
+    \param[in]  channelx: specify which DMA channel to set
+                only one parameter can be selected which is shown as below:
+      \arg        DMA_CHx(x=0..6)
+    \param[out] none
+    \retval     none
+*/
+void dma_memory_increase_disable(dma_channel_enum channelx)
+{
+    DMA_CHCTL(channelx) &= ~DMA_CHXCTL_MNAGA;
+}
+
+/*!
+    \brief      enable next address increasement algorithm of peripheral
+    \param[in]  channelx: specify which DMA channel to set
+                only one parameter can be selected which is shown as below:
+      \arg        DMA_CHx(x=0..6)
+    \param[out] none
+    \retval     none
+*/
+void dma_periph_increase_enable(dma_channel_enum channelx)
+{
+    DMA_CHCTL(channelx) |= DMA_CHXCTL_PNAGA;
+}
+
+/*!
+    \brief      disable next address increasement algorithm of peripheral
+    \param[in]  channelx: specify which DMA channel to set
+                only one parameter can be selected which is shown as below:
+      \arg        DMA_CHx(x=0..6)
+    \param[out] none
+    \retval     none
+*/
+void dma_periph_increase_disable(dma_channel_enum channelx)
+{
+    DMA_CHCTL(channelx) &= ~DMA_CHXCTL_PNAGA;
+}
+
+/*!
+    \brief      configure the direction of data transfer on the channel
+    \param[in]  channelx: specify which DMA channel to set
+                only one parameter can be selected which is shown as below:
+      \arg        DMA_CHx(x=0..6)
+    \param[in]  direction: specify the direction of  data transfer
+                only one parameter can be selected which is shown as below:
+      \arg        DMA_PERIPHERAL_TO_MEMORY: read from peripheral and write to memory
+      \arg        DMA_MEMORY_TO_PERIPHERAL: read from memory and write to peripheral
+    \param[out] none
+    \retval     none
+*/
+void dma_transfer_direction_config(dma_channel_enum channelx, uint32_t direction)
+{
+    if(DMA_PERIPHERAL_TO_MEMORY == direction) {
+        DMA_CHCTL(channelx) &= ~DMA_CHXCTL_DIR;
+    } else {
+        DMA_CHCTL(channelx) |= DMA_CHXCTL_DIR;
+    }
+}
+
+/*!
+    \brief      check DMA flag is set or not
+    \param[in]  channelx: specify which DMA channel to get flag
+                only one parameter can be selected which is shown as below:
+      \arg        DMA_CHx(x=0..6)
+    \param[in]  flag: specify get which flag
+                only one parameter can be selected which is shown as below:
+      \arg        DMA_FLAG_G: global interrupt flag of channel
+      \arg        DMA_FLAG_FTF: full transfer finish flag of channel
+      \arg        DMA_FLAG_HTF: half transfer finish flag of channel
+      \arg        DMA_FLAG_ERR: error flag of channel
+    \param[out] none
+    \retval     FlagStatus: SET or RESET
+*/
+FlagStatus dma_flag_get(dma_channel_enum channelx, uint32_t flag)
+{
+    FlagStatus reval;
+
+    if(RESET != (DMA_INTF & DMA_FLAG_ADD(flag, channelx))) {
+        reval = SET;
+    } else {
+        reval = RESET;
+    }
+
+    return reval;
+}
+
+/*!
+    \brief      clear DMA a channel flag
+    \param[in]  channelx: specify which DMA channel to clear flag
+                only one parameter can be selected which is shown as below:
+      \arg        DMA_CHx(x=0..6)
+    \param[in]  flag: specify get which flag
+                only one parameter can be selected which is shown as below:
+      \arg        DMA_FLAG_G: global interrupt flag of channel
+      \arg        DMA_FLAG_FTF: full transfer finish flag of channel
+      \arg        DMA_FLAG_HTF: half transfer finish flag of channel
+      \arg        DMA_FLAG_ERR: error flag of channel
+    \param[out] none
+    \retval     none
+*/
+void dma_flag_clear(dma_channel_enum channelx, uint32_t flag)
+{
+    DMA_INTC |= DMA_FLAG_ADD(flag, channelx);
+}
+
+/*!
+    \brief      enable DMA interrupt
+    \param[in]  channelx: specify which DMA channel to set
+                only one parameter can be selected which is shown as below:
+      \arg        DMA_CHx(x=0..6)
+    \param[in]  source: specify which interrupt to enable
+                only one parameter can be selected which is shown as below:
+      \arg        DMA_INT_ERR: channel error interrupt
+      \arg        DMA_INT_HTF: channel half transfer finish interrupt
+      \arg        DMA_INT_FTF: channel full transfer finish interrupt
+    \param[out] none
+    \retval     none
+*/
+void dma_interrupt_enable(dma_channel_enum channelx, uint32_t source)
+{
+    DMA_CHCTL(channelx) |= source;
+}
+
+/*!
+    \brief      disable DMA interrupt
+    \param[in]  channelx: specify which DMA channel to set
+                only one parameter can be selected which is shown as below:
+      \arg        DMA_CHx(x=0..6)
+    \param[in]  source: specify which interrupt to disable
+                only one parameter can be selected which is shown as below:
+      \arg        DMA_INT_ERR: channel error interrupt
+      \arg        DMA_INT_HTF: channel half transfer finish interrupt
+      \arg        DMA_INT_FTF: channel full transfer finish interrupt
+    \param[out] none
+    \retval     none
+*/
+void dma_interrupt_disable(dma_channel_enum channelx, uint32_t source)
+{
+    DMA_CHCTL(channelx) &= ~source;
+}
+
+/*!
+    \brief      check DMA flag and interrupt enable bit is set or not
+    \param[in]  channelx: specify which DMA channel to get flag
+                only one parameter can be selected which is shown as below:
+      \arg        DMA_CHx(x=0..6)
+    \param[in]  flag: specify get which flag
+                only one parameter can be selected which is shown as below:
+      \arg        DMA_INT_FLAG_FTF: transfer finish flag of channel
+      \arg        DMA_INT_FLAG_HTF: half transfer finish flag of channel
+      \arg        DMA_INT_FLAG_ERR: error flag of channel
+    \param[out] none
+    \retval     FlagStatus: SET or RESET
+*/
+FlagStatus dma_interrupt_flag_get(dma_channel_enum channelx, uint32_t flag)
+{
+    uint32_t interrupt_enable = 0U, interrupt_flag = 0U;
+
+    switch(flag) {
+    case DMA_INT_FLAG_FTF:
+        interrupt_flag = DMA_INTF & DMA_FLAG_ADD(flag, channelx);
+        interrupt_enable = DMA_CHCTL(channelx) & DMA_CHXCTL_FTFIE;
+        break;
+    case DMA_INT_FLAG_HTF:
+        interrupt_flag = DMA_INTF & DMA_FLAG_ADD(flag, channelx);
+        interrupt_enable = DMA_CHCTL(channelx) & DMA_CHXCTL_HTFIE;
+        break;
+    case DMA_INT_FLAG_ERR:
+        interrupt_flag = DMA_INTF & DMA_FLAG_ADD(flag, channelx);
+        interrupt_enable = DMA_CHCTL(channelx) & DMA_CHXCTL_ERRIE;
+        break;
+    default:
+        break;
+    }
+
+    if(interrupt_flag && interrupt_enable) {
+        return SET;
+    } else {
+        return RESET;
+    }
+}
+
+/*!
+    \brief      clear DMA a channel interrupt flag
+    \param[in]  channelx: specify which DMA channel to clear flag
+                only one parameter can be selected which is shown as below:
+      \arg        DMA_CHx(x=0..6)
+    \param[in]  flag: specify get which flag
+                only one parameter can be selected which is shown as below:
+      \arg        DMA_INT_FLAG_G: global interrupt flag of channel
+      \arg        DMA_INT_FLAG_FTF: transfer finish flag of channel
+      \arg        DMA_INT_FLAG_HTF: half transfer finish flag of channel
+      \arg        DMA_INT_FLAG_ERR: error flag of channel
+    \param[out] none
+    \retval     none
+*/
+void dma_interrupt_flag_clear(dma_channel_enum channelx, uint32_t flag)
+{
+    DMA_INTC |= DMA_FLAG_ADD(flag, channelx);
+}

+ 252 - 0
GD32F3x0/GD32F3x0_standard_peripheral/Source/gd32f3x0_exti.c

@@ -0,0 +1,252 @@
+/*!
+    \file    gd32f3x0_exti.c
+    \brief   EXTI driver
+
+    \version 2025-01-01, V2.5.0, firmware for GD32F3x0
+*/
+
+/*
+    Copyright (c) 2025, GigaDevice Semiconductor Inc.
+
+    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 of the copyright holder 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 HOLDER 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.
+*/
+
+#include "gd32f3x0_exti.h"
+
+#define EXTI_INTEN_RESET_VAL    ((uint32_t)0x0F900000U)
+#define EXTI_REG_RESET_VAL      ((uint32_t)0x00000000U)
+
+/*!
+    \brief      reset EXTI, reset the value of all EXTI registers into initial values
+    \param[in]  none
+    \param[out] none
+    \retval     none
+*/
+void exti_deinit(void)
+{
+    /* reset the value of all the EXTI registers */
+    EXTI_INTEN = EXTI_INTEN_RESET_VAL;
+    EXTI_EVEN  = EXTI_REG_RESET_VAL;
+    EXTI_RTEN  = EXTI_REG_RESET_VAL;
+    EXTI_FTEN  = EXTI_REG_RESET_VAL;
+    EXTI_SWIEV = EXTI_REG_RESET_VAL;
+}
+
+/*!
+    \brief      initialize the EXTI, enable the configuration of EXTI initialize
+    \param[in]  linex: EXTI line number, refer to exti_line_enum
+                only one parameter can be selected which is shown as below:
+      \arg        EXTI_x (x=0..19,21,22): EXTI line x
+    \param[in]  mode: interrupt or event mode, refer to exti_mode_enum
+                only one parameter can be selected which is shown as below:
+      \arg        EXTI_INTERRUPT: interrupt mode
+      \arg        EXTI_EVENT: event mode
+    \param[in]  trig_type: interrupt trigger type, refer to exti_trig_type_enum
+                only one parameter can be selected which is shown as below:
+      \arg        EXTI_TRIG_RISING: rising edge trigger
+      \arg        EXTI_TRIG_FALLING: falling trigger
+      \arg        EXTI_TRIG_BOTH: rising and falling trigger
+      \arg        EXTI_TRIG_NONE: without rising edge or falling edge trigger
+    \param[out] none
+    \retval     none
+*/
+void exti_init(exti_line_enum linex, \
+               exti_mode_enum mode, \
+               exti_trig_type_enum trig_type)
+{
+    /* reset the EXTI line x */
+    EXTI_INTEN &= ~(uint32_t)linex;
+    EXTI_EVEN &= ~(uint32_t)linex;
+    EXTI_RTEN &= ~(uint32_t)linex;
+    EXTI_FTEN &= ~(uint32_t)linex;
+
+    /* set the EXTI mode and enable the interrupts or events from EXTI line x */
+    switch(mode) {
+    case EXTI_INTERRUPT:
+        EXTI_INTEN |= (uint32_t)linex;
+        break;
+    case EXTI_EVENT:
+        EXTI_EVEN |= (uint32_t)linex;
+        break;
+    default:
+        break;
+    }
+
+    /* set the EXTI trigger type */
+    switch(trig_type) {
+    case EXTI_TRIG_RISING:
+        EXTI_RTEN |= (uint32_t)linex;
+        EXTI_FTEN &= ~(uint32_t)linex;
+        break;
+    case EXTI_TRIG_FALLING:
+        EXTI_RTEN &= ~(uint32_t)linex;
+        EXTI_FTEN |= (uint32_t)linex;
+        break;
+    case EXTI_TRIG_BOTH:
+        EXTI_RTEN |= (uint32_t)linex;
+        EXTI_FTEN |= (uint32_t)linex;
+        break;
+    case EXTI_TRIG_NONE:
+    default:
+        break;
+    }
+}
+
+/*!
+    \brief      enable the interrupts from EXTI line x
+    \param[in]  linex: EXTI line number, refer to exti_line_enum
+                only one parameter can be selected which is shown as below:
+      \arg        EXTI_x (x=0..27): EXTI line x
+    \param[out] none
+    \retval     none
+*/
+void exti_interrupt_enable(exti_line_enum linex)
+{
+    EXTI_INTEN |= (uint32_t)linex;
+}
+
+/*!
+    \brief      disable the interrupt from EXTI line x
+    \param[in]  linex: EXTI line number, refer to exti_line_enum
+                only one parameter can be selected which is shown as below:
+      \arg        EXTI_x (x=0..27): EXTI line x
+    \param[out] none
+    \retval     none
+*/
+void exti_interrupt_disable(exti_line_enum linex)
+{
+    EXTI_INTEN &= ~(uint32_t)linex;
+}
+
+/*!
+    \brief      enable the events from EXTI line x
+    \param[in]  linex: EXTI line number, refer to exti_line_enum
+                only one parameter can be selected which is shown as below:
+      \arg        EXTI_x (x=0..27): EXTI line x
+    \param[out] none
+    \retval     none
+*/
+void exti_event_enable(exti_line_enum linex)
+{
+    EXTI_EVEN |= (uint32_t)linex;
+}
+
+/*!
+    \brief      disable the events from EXTI line x
+    \param[in]  linex: EXTI line number, refer to exti_line_enum
+                only one parameter can be selected which is shown as below:
+      \arg        EXTI_x (x=0..27): EXTI line x
+    \param[out] none
+    \retval     none
+*/
+void exti_event_disable(exti_line_enum linex)
+{
+    EXTI_EVEN &= ~(uint32_t)linex;
+}
+
+/*!
+    \brief      enable EXTI software interrupt event
+    \param[in]  linex: EXTI line number, refer to exti_line_enum
+                only one parameter can be selected which is shown as below:
+      \arg        EXTI_x (x=0..19,21,22): EXTI line x
+    \param[out] none
+    \retval     none
+*/
+void exti_software_interrupt_enable(exti_line_enum linex)
+{
+    EXTI_SWIEV |= (uint32_t)linex;
+}
+
+/*!
+    \brief      disable EXTI software interrupt event
+    \param[in]  linex: EXTI line number, refer to exti_line_enum
+                only one parameter can be selected which is shown as below:
+      \arg        EXTI_x (x=0..19,21,22): EXTI line x
+    \param[out] none
+    \retval     none
+*/
+void exti_software_interrupt_disable(exti_line_enum linex)
+{
+    EXTI_SWIEV &= ~(uint32_t)linex;
+}
+
+/*!
+    \brief      get EXTI line x interrupt pending flag
+    \param[in]  linex: EXTI line number, refer to exti_line_enum
+                only one parameter can be selected which is shown as below:
+      \arg        EXTI_x (x=0..19,21,22): EXTI line x
+    \param[out] none
+    \retval     FlagStatus: status of flag (RESET or SET)
+*/
+FlagStatus exti_flag_get(exti_line_enum linex)
+{
+    if(RESET != (EXTI_PD & (uint32_t)linex)) {
+        return SET;
+    } else {
+        return RESET;
+    }
+}
+
+/*!
+    \brief      clear EXTI line x interrupt pending flag
+    \param[in]  linex: EXTI line number, refer to exti_line_enum
+                only one parameter can be selected which is shown as below:
+      \arg        EXTI_x (x=0..19,21,22): EXTI line x
+    \param[out] none
+    \retval     none
+*/
+void exti_flag_clear(exti_line_enum linex)
+{
+    EXTI_PD = (uint32_t)linex;
+}
+
+/*!
+    \brief      get EXTI line x interrupt pending flag
+    \param[in]  linex: EXTI line number, refer to exti_line_enum
+                only one parameter can be selected which is shown as below:
+      \arg        EXTI_x (x=0..19,21,22): EXTI line x
+    \param[out] none
+    \retval     FlagStatus: status of flag (RESET or SET)
+*/
+FlagStatus exti_interrupt_flag_get(exti_line_enum linex)
+{
+    if(RESET != (EXTI_PD & (uint32_t)linex)) {
+        return SET;
+    } else {
+        return RESET;
+    }
+}
+
+/*!
+    \brief      clear EXTI line x interrupt pending flag
+    \param[in]  linex: EXTI line number, refer to exti_line_enum
+                only one parameter can be selected which is shown as below:
+      \arg        EXTI_x (x=0..19,21,22): EXTI line x
+    \param[out] none
+    \retval     none
+*/
+void exti_interrupt_flag_clear(exti_line_enum linex)
+{
+    EXTI_PD = (uint32_t)linex;
+}

+ 889 - 0
GD32F3x0/GD32F3x0_standard_peripheral/Source/gd32f3x0_fmc.c

@@ -0,0 +1,889 @@
+/*!
+    \file    gd32f3x0_fmc.c
+    \brief   FMC driver
+
+    \version 2025-01-01, V2.5.0, firmware for GD32F3x0
+*/
+
+/*
+    Copyright (c) 2025, GigaDevice Semiconductor Inc.
+
+    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 of the copyright holder 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 HOLDER 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.
+*/
+
+#include "gd32f3x0_fmc.h"
+
+/* FMC main memory programming functions */
+
+/*!
+    \brief      unlock the main FMC operation
+                it is better to used in pairs with fmc_lock
+    \param[in]  none
+    \param[out] none
+    \retval     none
+*/
+void fmc_unlock(void)
+{
+    if((RESET != (FMC_CTL & FMC_CTL_LK))) {
+        /* write the FMC key */
+        FMC_KEY = UNLOCK_KEY0;
+        FMC_KEY = UNLOCK_KEY1;
+    }
+}
+
+/*!
+    \brief      lock the main FMC operation
+                it is better to used in pairs with fmc_unlock after an operation
+    \param[in]  none
+    \param[out] none
+    \retval     none
+*/
+void fmc_lock(void)
+{
+    /* set the LK bit*/
+    FMC_CTL |= FMC_CTL_LK;
+}
+
+/*!
+    \brief      set the wait state counter value
+    \param[in]  wscnt: wait state counter value
+                only one parameter can be selected which is shown as below:
+      \arg        WS_WSCNT_0: 0 wait state added
+      \arg        WS_WSCNT_1: 1 wait state added
+      \arg        WS_WSCNT_2: 2 wait state added
+    \param[out] none
+    \retval     none
+*/
+void fmc_wscnt_set(uint8_t wscnt)
+{
+    uint32_t reg;
+
+    reg = FMC_WS;
+    /* set the wait state counter value */
+    reg &= ~FMC_WS_WSCNT;
+    FMC_WS = (reg | wscnt);
+}
+
+/*!
+    \brief      fmc wait state enable
+    \param[in]  none
+    \param[out] none
+    \retval     none
+*/
+void fmc_wait_state_enable(void)
+{
+    /* unlock the main flash */
+    fmc_unlock();
+
+    /* set the WSEN bit in register FMC_WSEN */
+    FMC_WSEN |= FMC_WSEN_WSEN;
+
+    /* lock the main flash after operation */
+    fmc_lock();
+}
+
+/*!
+    \brief      fmc wait state disable
+    \param[in]  none
+    \param[out] none
+    \retval     none
+*/
+void fmc_wait_state_disable(void)
+{
+    /* unlock the main flash */
+    fmc_unlock();
+
+    /* reset the WSEN bit in register FMC_WSEN */
+    FMC_WSEN &= ~FMC_WSEN_WSEN;
+
+    /* lock the main flash after operation */
+    fmc_lock();
+}
+
+/*!
+    \brief      erase page
+    \param[in]  page_address: target page start address
+    \param[out] none
+    \retval     fmc_state
+*/
+fmc_state_enum fmc_page_erase(uint32_t page_address)
+{
+    fmc_state_enum fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
+
+    if(FMC_READY == fmc_state) {
+        /* start page erase */
+        FMC_CTL |= FMC_CTL_PER;
+        FMC_ADDR = page_address;
+        FMC_CTL |= FMC_CTL_START;
+        __NOP();
+        __NOP();
+        /* wait for the FMC ready */
+        fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
+
+        /* reset the PER bit */
+        FMC_CTL &= ~FMC_CTL_PER;
+    }
+
+    /* return the FMC state  */
+    return fmc_state;
+}
+
+/*!
+    \brief      erase whole chip
+    \param[in]  none
+    \param[out] none
+    \retval     fmc_state
+*/
+fmc_state_enum fmc_mass_erase(void)
+{
+    fmc_state_enum fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
+
+    if(FMC_READY == fmc_state) {
+        /* start chip erase */
+        FMC_CTL |= FMC_CTL_MER;
+        FMC_CTL |= FMC_CTL_START;
+
+        /* wait for the FMC ready */
+        fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
+
+        /* reset the MER bit */
+        FMC_CTL &= ~FMC_CTL_MER;
+    }
+
+    /* return the fmc state  */
+    return fmc_state;
+}
+
+/*!
+    \brief      program a word at the corresponding address
+    \param[in]  address: address to program
+    \param[in]  data: word to program
+    \param[out] none
+    \retval     fmc_state
+*/
+fmc_state_enum fmc_word_program(uint32_t address, uint32_t data)
+{
+    fmc_state_enum fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
+
+    if(FMC_READY == fmc_state) {
+        /* set the PG bit to start program */
+        FMC_CTL |= FMC_CTL_PG;
+
+        REG32(address) = data;
+
+        /* wait for the FMC ready */
+        fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
+
+        /* reset the PG bit */
+        FMC_CTL &= ~FMC_CTL_PG;
+    }
+
+    /* return the FMC state */
+    return fmc_state;
+}
+
+/*!
+    \brief      program a half word at the corresponding address
+    \param[in]  address: address to program
+    \param[in]  data: word to program
+    \param[out] none
+    \retval     fmc_state
+*/
+fmc_state_enum fmc_halfword_program(uint32_t address, uint16_t data)
+{
+    fmc_state_enum fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
+
+    if(FMC_READY == fmc_state) {
+        /* set the PG bit to start program */
+        FMC_CTL |= FMC_CTL_PG;
+
+        REG16(address) = data;
+
+        /* wait for the FMC ready */
+        fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
+
+        /* reset the PG bit */
+        FMC_CTL &= ~FMC_CTL_PG;
+    }
+
+    /* return the FMC state */
+    return fmc_state;
+}
+
+/*!
+    \brief      program a word at the corresponding address without erasing
+    \param[in]  address: address to program
+    \param[in]  data: word to program
+    \param[out] none
+    \retval     fmc_state
+*/
+fmc_state_enum fmc_word_reprogram(uint32_t address, uint32_t data)
+{
+    fmc_state_enum fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
+    FMC_WSEN |= FMC_WSEN_BPEN;
+
+    if(FMC_READY == fmc_state) {
+        /* set the PG bit to start program */
+        FMC_CTL |= FMC_CTL_PG;
+
+        REG32(address) = data;
+
+        /* wait for the FMC ready */
+        fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
+
+        /* reset the PG bit */
+        FMC_CTL &= ~FMC_CTL_PG;
+    }
+    
+    FMC_WSEN &= ~FMC_WSEN_BPEN;
+
+    /* return the FMC state */
+    return fmc_state;
+}
+
+/* FMC option bytes programming functions */
+
+/*!
+    \brief      unlock the option byte operation
+                it is better to used in pairs with ob_lock
+    \param[in]  none
+    \param[out] none
+    \retval     none
+*/
+void ob_unlock(void)
+{
+    if(RESET == (FMC_CTL & FMC_CTL_OBWEN)) {
+        /* write the FMC key */
+        FMC_OBKEY = UNLOCK_KEY0;
+        FMC_OBKEY = UNLOCK_KEY1;
+    }
+}
+
+/*!
+    \brief      lock the option byte operation
+                it is better to used in pairs with ob_unlock after an operation
+    \param[in]  none
+    \param[out] none
+    \retval     none
+*/
+void ob_lock(void)
+{
+    /* reset the OBWE bit */
+    FMC_CTL &= ~FMC_CTL_OBWEN;
+}
+
+/*!
+    \brief      reload the option byte and generate a system reset
+    \param[in]  none
+    \param[out] none
+    \retval     none
+*/
+void ob_reset(void)
+{
+    /* set the OBRLD bit */
+    FMC_CTL |= FMC_CTL_OBRLD;
+}
+
+/*!
+    \brief      erase the option byte
+                programmer must ensure FMC & option byte are both unlocked before calling this function
+    \param[in]  none
+    \param[out] none
+    \retval     fmc_state
+*/
+fmc_state_enum ob_erase(void)
+{
+    uint16_t fmc_spc;
+
+    uint32_t fmc_plevel = ob_obstat_plevel_get();
+    fmc_state_enum fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
+
+    /* get the original option byte security protection code */
+    if(OB_OBSTAT_PLEVEL_NO == fmc_plevel) {
+        fmc_spc = FMC_NSPC;
+    } else if(OB_OBSTAT_PLEVEL_LOW == fmc_plevel) {
+        fmc_spc = FMC_LSPC;
+    } else {
+        fmc_spc = FMC_HSPC;
+        fmc_state = FMC_OB_HSPC;
+    }
+
+    if(FMC_READY == fmc_state) {
+        /* start erase the option byte */
+        FMC_CTL |= FMC_CTL_OBER;
+        FMC_CTL |= FMC_CTL_START;
+
+        /* wait for the FMC ready */
+        fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
+
+        if(FMC_READY == fmc_state) {
+            /* reset the OBER bit */
+            FMC_CTL &= ~FMC_CTL_OBER;
+
+            /* set the OBPG bit */
+            FMC_CTL |= FMC_CTL_OBPG;
+
+            /* restore the last get option byte security protection code */
+            OB_SPC = fmc_spc;
+            OB_USER = OB_USER_DEFAULT;
+
+            /* wait for the FMC ready */
+            fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
+
+            if(FMC_TOERR != fmc_state) {
+                /* reset the OBPG bit */
+                FMC_CTL &= ~FMC_CTL_OBPG;
+            }
+        } else {
+            if(FMC_TOERR != fmc_state) {
+                /* reset the OBPG bit */
+                FMC_CTL &= ~FMC_CTL_OBPG;
+            }
+        }
+    }
+    /* return the FMC state */
+    return fmc_state;
+}
+
+/*!
+    \brief      enable option byte write protection(OB_WP) depending on current option byte
+    \param[in]  ob_wp: write protection configuration data
+                       setting the bit of ob_wp means enabling the corresponding sector write protection
+    \param[out] none
+    \retval     fmc_state
+*/
+fmc_state_enum ob_write_protection_enable(uint16_t ob_wp)
+{
+    uint8_t ob_wrp0, ob_wrp1;
+    ob_parm_struct ob_parm;
+    fmc_state_enum fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
+    ob_parm_get(&ob_parm);
+    ob_wp   = (uint16_t)(~ob_wp);
+    ob_wrp0 = (uint8_t)(ob_wp & OB_LWP);
+    ob_wrp1 = (uint8_t)((ob_wp & OB_HWP) >> 8U);
+
+    if(0xFFFFU == OB_WP0) {
+        if(0xFFFFU == OB_WP1) {
+            if(FMC_READY == fmc_state) {
+                /* set the OBPG bit*/
+                FMC_CTL |= FMC_CTL_OBPG;
+
+                if(0xFFU != ob_wrp0) {
+                    OB_WP0 = ob_wrp0 ;
+                    /* wait for the FMC ready */
+                    fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
+                }
+
+                if((FMC_READY == fmc_state) && (0xFFU != ob_wrp1)) {
+                    OB_WP1 = ob_wrp1 ;
+                    /* wait for the FMC ready */
+                    fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
+                }
+
+                if(FMC_TOERR != fmc_state) {
+                    /* reset the OBPG bit */
+                    FMC_CTL &= ~FMC_CTL_OBPG;
+                }
+            }
+        }
+    } else {
+        if(FMC_READY == fmc_state) {
+            /* start erase the option byte */
+            FMC_CTL |= FMC_CTL_OBER;
+            FMC_CTL |= FMC_CTL_START;
+
+            /* wait for the FMC ready */
+            fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
+
+            if(FMC_READY == fmc_state) {
+
+                /* reset the OBER bit */
+                FMC_CTL &= ~FMC_CTL_OBER;
+
+                /* enable the option bytes programming */
+                FMC_CTL |= FMC_CTL_OBPG;
+
+                ob_value_modify(OB_WP_ADDR0, ob_wp, &ob_parm);
+                /* wait for the FMC ready */
+                fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
+
+                if(FMC_TOERR != fmc_state) {
+                    /* reset the OBPG bit */
+                    FMC_CTL &= ~FMC_CTL_OBPG;
+                }
+            } else {
+                if(FMC_TOERR != fmc_state) {
+                    /* reset the OBER bit */
+                    FMC_CTL &= ~FMC_CTL_OBER;
+                }
+            }
+        }
+    }
+    /* return the FMC state */
+    return fmc_state;
+}
+
+/*!
+    \brief      configure security protection
+    \param[in]  ob_spc: specify security protection code
+                only one parameter can be selected which is shown as below:
+      \arg        FMC_NSPC: no security protection
+      \arg        FMC_LSPC: low security protection
+      \arg        FMC_HSPC: high security protection
+    \param[out] none
+    \retval     fmc_state
+*/
+fmc_state_enum ob_security_protection_config(uint8_t ob_spc)
+{
+    fmc_state_enum fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
+
+    ob_parm_struct ob_parm;
+    ob_parm_get(&ob_parm);
+
+    /* the OB_SPC byte cannot be reprogrammed if protection level is high */
+    if(OB_OBSTAT_PLEVEL_HIGH == ob_obstat_plevel_get()) {
+        fmc_state = FMC_OB_HSPC;
+    }
+
+    if(FMC_READY == fmc_state) {
+        /* start erase the option byte */
+        FMC_CTL |= FMC_CTL_OBER;
+        FMC_CTL |= FMC_CTL_START;
+
+        /* wait for the FMC ready */
+        fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
+
+        if(FMC_READY == fmc_state) {
+
+            /* reset the OBER bit */
+            FMC_CTL &= ~FMC_CTL_OBER;
+
+            /* enable the option bytes programming */
+            FMC_CTL |= FMC_CTL_OBPG;
+
+            ob_value_modify(OB_SPC_ADDR, (uint16_t)ob_spc, &ob_parm);
+            /* wait for the FMC ready */
+            fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
+
+            if(FMC_TOERR != fmc_state) {
+                /* reset the OBPG bit */
+                FMC_CTL &= ~FMC_CTL_OBPG;
+            }
+        } else {
+            if(FMC_TOERR != fmc_state) {
+                /* reset the OBER bit */
+                FMC_CTL &= ~FMC_CTL_OBER;
+            }
+        }
+    }
+    /* return the FMC state */
+    return fmc_state;
+}
+
+/*!
+    \brief      program the FMC user option byte depending on current option byte
+    \param[in]  ob_user: user option byte
+                one or more parameters (bitwise AND) can be selected which are shown as below:
+      \arg        OB_FWDGT_HW: hardware free watchdog timer
+      \arg        OB_DEEPSLEEP_RST: generate a reset instead of entering deepsleep mode
+      \arg        OB_STDBY_RST: generate a reset instead of entering standby mode
+      \arg        OB_BOOT1_SET_1: BOOT1 bit is 1
+      \arg        OB_VDDA_DISABLE: disable VDDA monitor
+      \arg        OB_SRAM_PARITY_ENABLE: enable sram parity check
+    \param[out] none
+    \retval     fmc_state
+*/
+fmc_state_enum ob_user_write(uint8_t ob_user)
+{
+    /* check whether FMC is ready or not */
+    fmc_state_enum fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
+    ob_parm_struct ob_parm;
+    ob_parm_get(&ob_parm);
+
+    if(FMC_READY == fmc_state) {
+        /* start erase the option byte */
+        FMC_CTL |= FMC_CTL_OBER;
+        FMC_CTL |= FMC_CTL_START;
+
+        /* wait for the FMC ready */
+        fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
+
+        if(FMC_READY == fmc_state) {
+            /* reset the OBER bit */
+            FMC_CTL &= ~FMC_CTL_OBER;
+
+            /* set the OBPG bit */
+            FMC_CTL |= FMC_CTL_OBPG;
+
+            /* restore the last get option byte security protection code */
+            ob_value_modify(OB_USER_ADDR, (uint16_t)ob_user, &ob_parm);
+
+            /* wait for the FMC ready */
+            fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
+
+            if(FMC_TOERR != fmc_state) {
+                /* reset the OBPG bit */
+                FMC_CTL &= ~FMC_CTL_OBPG;
+            }
+        } else {
+            if(FMC_TOERR != fmc_state) {
+                /* reset the OBPG bit */
+                FMC_CTL &= ~FMC_CTL_OBPG;
+            }
+        }
+    }
+    /* return the FMC state */
+    return fmc_state;
+}
+
+/*!
+    \brief      program the FMC data option byte
+    \param[in]  address: OB_DATA_ADDR0 or OB_DATA_ADDR1
+                only one parameter can be selected which is shown as below:
+      \arg        OB_DATA_ADDR0: option byte data address 0
+      \arg        OB_DATA_ADDR1: option byte data address 1
+    \param[in]  data: the byte to be programmed
+    \param[out] none
+    \retval     fmc_state
+*/
+fmc_state_enum ob_data_program(uint32_t address, uint8_t data)
+{
+    fmc_state_enum fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
+    ob_parm_struct ob_parm;
+    ob_parm_get(&ob_parm);
+    if(0xFFFFU == REG16(address)) {
+        if(FMC_READY == fmc_state) {
+            /* set the OBPG bit */
+            FMC_CTL |= FMC_CTL_OBPG;
+
+            REG16(address) = data ;
+
+            /* wait for the FMC ready */
+            fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
+
+            if(FMC_TOERR != fmc_state) {
+                /* reset the OBPG bit */
+                FMC_CTL &= ~FMC_CTL_OBPG;
+            }
+        }
+    } else {
+        if(FMC_READY == fmc_state) {
+            /* start erase the option byte */
+            FMC_CTL |= FMC_CTL_OBER;
+            FMC_CTL |= FMC_CTL_START;
+
+            /* wait for the FMC ready */
+            fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
+
+            if(FMC_READY == fmc_state) {
+
+                /* reset the OBER bit */
+                FMC_CTL &= ~FMC_CTL_OBER;
+
+                /* enable the option bytes programming */
+                FMC_CTL |= FMC_CTL_OBPG;
+
+                ob_value_modify(address, (uint16_t)data, &ob_parm);
+                /* wait for the FMC ready */
+                fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
+
+                if(FMC_TOERR != fmc_state) {
+                    /* reset the OBPG bit */
+                    FMC_CTL &= ~FMC_CTL_OBPG;
+                }
+            } else {
+                if(FMC_TOERR != fmc_state) {
+                    /* reset the OBER bit */
+                    FMC_CTL &= ~FMC_CTL_OBER;
+                }
+            }
+        }
+    }
+
+    /* return the FMC state */
+    return fmc_state;
+}
+
+/*!
+    \brief      get OB_USER in register FMC_OBSTAT
+    \param[in]  none
+    \param[out] none
+    \retval     ob_user
+*/
+uint8_t ob_user_get(void)
+{
+    return (uint8_t)(FMC_OBSTAT >> 8U);
+}
+
+/*!
+    \brief      get OB_DATA in register FMC_OBSTAT
+    \param[in]  none
+    \param[out] none
+    \retval     ob_data
+*/
+uint16_t ob_data_get(void)
+{
+    return (uint16_t)(FMC_OBSTAT >> 16U);
+}
+
+/*!
+    \brief      get the FMC option byte write protection (OB_WP) in register FMC_WP
+    \param[in]  none
+    \param[out] none
+    \retval     OB_WP
+*/
+uint16_t ob_write_protection_get(void)
+{
+    return (uint16_t)(FMC_WP);
+}
+
+/*!
+    \brief      get the value of FMC option byte security protection level (PLEVEL) in FMC_OBSTAT register
+    \param[in]  none
+    \param[out] none
+    \retval     the value of PLEVEL
+*/
+uint32_t ob_obstat_plevel_get(void)
+{
+    return (FMC_OBSTAT & (FMC_OBSTAT_PLEVEL_BIT0 | FMC_OBSTAT_PLEVEL_BIT1));
+}
+
+/* FMC interrupts and flags management functions */
+/*!
+    \brief      enable FMC interrupt
+    \param[in]  interrupt: the FMC interrupt source
+                one or more parameters can be selected which are shown as below:
+      \arg        FMC_INTEN_END: FMC end of operation interrupt
+      \arg        FMC_INTEN_ERR: FMC error interrupt
+    \param[out] none
+    \retval     none
+*/
+void fmc_interrupt_enable(uint32_t interrupt)
+{
+    FMC_CTL |= interrupt;
+}
+
+/*!
+    \brief      disable FMC interrupt
+    \param[in]  interrupt: the FMC interrupt source
+                one or more parameters can be selected which are shown as below:
+      \arg        FMC_INTEN_END: FMC end of operation interrupt
+      \arg        FMC_INTEN_ERR: FMC error interrupt
+    \param[out] none
+    \retval     none
+*/
+void fmc_interrupt_disable(uint32_t interrupt)
+{
+    FMC_CTL &= ~(uint32_t)interrupt;
+}
+
+/*!
+    \brief      get flag set or reset
+    \param[in]  flag: check FMC flag
+                only one parameter can be selected which is shown as below:
+      \arg        FMC_FLAG_BUSY: FMC busy flag
+      \arg        FMC_FLAG_PGERR: FMC programming error flag
+      \arg        FMC_FLAG_WPERR: FMC write protection error flag
+      \arg        FMC_FLAG_END: FMC end of programming flag
+    \param[out] none
+    \retval     FlagStatus: SET or RESET
+*/
+FlagStatus fmc_flag_get(uint32_t flag)
+{
+    FlagStatus status = RESET;
+
+    if(FMC_STAT & flag) {
+        status = SET;
+    }
+    /* return the state of corresponding FMC flag */
+    return status;
+}
+
+/*!
+    \brief      clear the FMC pending flag by writing 1
+    \param[in]  flag: clear FMC flag
+                only one parameter can be selected which is shown as below:
+      \arg        FMC_FLAG_PGERR: FMC programming error flag
+      \arg        FMC_FLAG_WPERR: FMC write protection error flag
+      \arg        FMC_FLAG_END: fmc end of programming flag
+    \param[out] none
+    \retval     none
+*/
+void fmc_flag_clear(uint32_t flag)
+{
+    /* clear the flags */
+    FMC_STAT = flag;
+}
+
+/*!
+    \brief      get flag set or reset
+    \param[in]  flag: check FMC flag
+                only one parameter can be selected which is shown as below:
+      \arg        FMC_FLAG_PGERR: FMC programming error flag
+      \arg        FMC_FLAG_WPERR: FMC write protection error flag
+      \arg        FMC_FLAG_END: FMC end of programming flag
+    \param[out] none
+    \retval     FlagStatus: SET or RESET
+*/
+FlagStatus fmc_interrupt_flag_get(uint32_t flag)
+{
+    FlagStatus status = RESET;
+
+    if(FMC_STAT & flag) {
+        status = SET;
+    }
+    /* return the state of corresponding FMC flag */
+    return status;
+}
+
+/*!
+    \brief      clear the FMC pending flag by writing 1
+    \param[in]  flag: clear FMC flag
+                only one parameter can be selected which is shown as below:
+      \arg        FMC_FLAG_PGERR: FMC programming error flag
+      \arg        FMC_FLAG_WPERR: FMC write protection error flag
+      \arg        FMC_FLAG_END: fmc end of programming flag
+    \param[out] none
+    \retval     none
+*/
+void fmc_interrupt_flag_clear(uint32_t flag)
+{
+    /* clear the flags */
+    FMC_STAT = flag;
+}
+
+/*!
+    \brief      get the FMC state
+    \param[in]  none
+    \param[out] none
+    \retval     fmc_state
+*/
+fmc_state_enum fmc_state_get(void)
+{
+    fmc_state_enum fmc_state = FMC_READY;
+
+    if((uint32_t)0x00U != (FMC_STAT & FMC_STAT_BUSY)) {
+        fmc_state = FMC_BUSY;
+    } else {
+        if((uint32_t)0x00U != (FMC_STAT & FMC_STAT_WPERR)) {
+            fmc_state = FMC_WPERR;
+        } else {
+            if((uint32_t)0x00U != (FMC_STAT & FMC_STAT_PGERR)) {
+                fmc_state = FMC_PGERR;
+            }
+        }
+    }
+    /* return the FMC state */
+    return fmc_state;
+}
+
+/*!
+    \brief      check whether FMC is ready or not
+    \param[in]  timeout: timeout count
+    \param[out] none
+    \retval     fmc_state
+*/
+fmc_state_enum fmc_ready_wait(uint32_t timeout)
+{
+    fmc_state_enum fmc_state = FMC_BUSY;
+
+    /* wait for FMC ready */
+    do {
+        /* get FMC state */
+        fmc_state = fmc_state_get();
+        timeout--;
+    } while((FMC_BUSY == fmc_state) && (0U != timeout));
+
+    if(FMC_BUSY == fmc_state) {
+        fmc_state = FMC_TOERR;
+    }
+    /* return the FMC state */
+    return fmc_state;
+}
+
+/*!
+    \brief      get current option byte value
+    \param[in]  ob_parm: pointer to option byte parameter struct
+    \param[out] ob_parm: pointer to option byte parameter struct
+    \retval     none
+*/
+void ob_parm_get(ob_parm_struct *ob_parm)
+{
+    /* get current option byte value */
+    ob_parm->spc = (uint8_t)OB_SPC;
+    ob_parm->user = (uint8_t)OB_USER;
+    ob_parm->data0 = (uint8_t)OB_DATA0;
+    ob_parm->data1 = (uint8_t)OB_DATA1;
+    ob_parm->wp0 = (uint8_t)OB_WP0;
+    ob_parm->wp1 = (uint8_t)OB_WP1;
+}
+
+/*!
+    \brief      modify the target option byte depending on the original value
+    \param[in]  address: target option byte address
+    \param[in]  value: target option byte value
+    \param[in]  ob_parm: pointer to option byte parameter struct
+    \param[out] none
+    \retval     none
+*/
+void ob_value_modify(uint32_t address, uint16_t value, ob_parm_struct *ob_parm)
+{
+    uint8_t spc, user, data0, data1, wp0, wp1;
+    /* store the original option bytes */
+    spc = ob_parm->spc;
+    user = ob_parm->user;
+    data0 = ob_parm->data0;
+    data1 = ob_parm->data1;
+    wp0 = ob_parm->wp0;
+    wp1 = ob_parm->wp1;
+
+    /* bring in the target option byte */
+    if(OB_SPC_ADDR == address) {
+        spc = (uint8_t)value;
+    } else if(OB_DATA_ADDR0 == address) {
+        data0 = (uint8_t)value;
+    } else if(OB_DATA_ADDR1 == address) {
+        data1 = (uint8_t)value;
+    } else if(OB_USER_ADDR == address) {
+        user =  user & (uint8_t)value;
+    } else {
+        wp0 = wp0 & ((uint8_t)(value));
+        wp1 = wp1 & ((uint8_t)(value >> 8U));
+    }
+    /* basing on original value, modify the target option byte */
+    OB_SPC = spc;
+    OB_USER = user;
+    if(0xFFU != data0) {
+        OB_DATA0 = data0;
+    }
+    if(0xFFU != data1) {
+        OB_DATA1 = data1;
+    }
+    if(0xFFU != wp0) {
+        OB_WP0 = wp0;
+    }
+    if(0xFFU != wp1) {
+        OB_WP1 = wp1;
+    }
+}

+ 243 - 0
GD32F3x0/GD32F3x0_standard_peripheral/Source/gd32f3x0_fwdgt.c

@@ -0,0 +1,243 @@
+/*!
+    \file    gd32f3x0_fwdgt.c
+    \brief   FWDGT driver
+
+    \version 2025-01-01, V2.5.0, firmware for GD32F3x0
+*/
+
+/*
+    Copyright (c) 2025, GigaDevice Semiconductor Inc.
+
+    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 of the copyright holder 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 HOLDER 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.
+*/
+
+#include "gd32f3x0_fwdgt.h"
+
+/*!
+    \brief      enable write access to FWDGT_PSC,FWDGT_RLD and FWDGT_WND
+    \param[in]  none
+    \param[out] none
+    \retval     none
+*/
+void fwdgt_write_enable(void)
+{
+    FWDGT_CTL = FWDGT_WRITEACCESS_ENABLE;
+}
+
+/*!
+    \brief      disable write access to FWDGT_PSC,FWDGT_RLD and FWDGT_WND
+    \param[in]  none
+    \param[out] none
+    \retval     none
+*/
+void fwdgt_write_disable(void)
+{
+    FWDGT_CTL = FWDGT_WRITEACCESS_DISABLE;
+}
+
+/*!
+    \brief      start the free watchdog timer counter
+    \param[in]  none
+    \param[out] none
+    \retval     none
+*/
+void fwdgt_enable(void)
+{
+    FWDGT_CTL = FWDGT_KEY_ENABLE;
+}
+
+/*!
+    \brief      configure the free watchdog timer counter prescaler value
+    \param[in]  prescaler_value: specify prescaler value
+                only one parameter can be selected which is shown as below:
+      \arg        FWDGT_PSC_DIV4: FWDGT prescaler set to 4
+      \arg        FWDGT_PSC_DIV8: FWDGT prescaler set to 8
+      \arg        FWDGT_PSC_DIV16: FWDGT prescaler set to 16
+      \arg        FWDGT_PSC_DIV32: FWDGT prescaler set to 32
+      \arg        FWDGT_PSC_DIV64: FWDGT prescaler set to 64
+      \arg        FWDGT_PSC_DIV128: FWDGT prescaler set to 128
+      \arg        FWDGT_PSC_DIV256: FWDGT prescaler set to 256
+    \param[out] none
+    \retval     ErrStatus: ERROR or SUCCESS
+*/
+ErrStatus fwdgt_prescaler_value_config(uint16_t prescaler_value)
+{
+    uint32_t timeout = FWDGT_PSC_TIMEOUT;
+    uint32_t flag_status = RESET;
+
+    /* enable write access to FWDGT_PSC */
+    FWDGT_CTL = FWDGT_WRITEACCESS_ENABLE;
+
+    /* wait until the PUD flag to be reset */
+    do {
+        flag_status = FWDGT_STAT & FWDGT_STAT_PUD;
+    } while((--timeout > 0U) && ((uint32_t)RESET != flag_status));
+
+    if((uint32_t)RESET != flag_status) {
+        return ERROR;
+    }
+
+    /* configure FWDGT */
+    FWDGT_PSC = (uint32_t)prescaler_value;
+
+    return SUCCESS;
+}
+
+/*!
+    \brief      configure the free watchdog timer counter reload value
+    \param[in]  reload_value: specify reload value(0x0000 - 0x0FFF)
+    \param[out] none
+    \retval     ErrStatus: ERROR or SUCCESS
+*/
+ErrStatus fwdgt_reload_value_config(uint16_t reload_value)
+{
+    uint32_t timeout = FWDGT_RLD_TIMEOUT;
+    uint32_t flag_status = RESET;
+
+    /* enable write access to FWDGT_RLD */
+    FWDGT_CTL = FWDGT_WRITEACCESS_ENABLE;
+
+    /* wait until the RUD flag to be reset */
+    do {
+        flag_status = FWDGT_STAT & FWDGT_STAT_RUD;
+    } while((--timeout > 0U) && ((uint32_t)RESET != flag_status));
+
+    if((uint32_t)RESET != flag_status) {
+        return ERROR;
+    }
+
+    FWDGT_RLD = RLD_RLD(reload_value);
+
+    return SUCCESS;
+}
+
+/*!
+    \brief      configure the free watchdog timer counter window value
+    \param[in]  window_value: specify window value(0x0000 - 0x0FFF)
+    \param[out] none
+    \retval     ErrStatus: ERROR or SUCCESS
+*/
+ErrStatus fwdgt_window_value_config(uint16_t window_value)
+{
+    uint32_t time_index = FWDGT_WND_TIMEOUT;
+    uint32_t flag_status = RESET;
+
+    /* enable write access to FWDGT_WND */
+    FWDGT_CTL = FWDGT_WRITEACCESS_ENABLE;
+
+    /* wait until the WUD flag to be reset */
+    do {
+        flag_status = FWDGT_STAT & FWDGT_STAT_WUD;
+    } while((--time_index > 0U) && (RESET != flag_status));
+
+    if(RESET != flag_status) {
+        return ERROR;
+    }
+
+    FWDGT_WND = WND_WND(window_value);
+
+    return SUCCESS;
+}
+
+/*!
+    \brief      reload the counter of FWDGT
+    \param[in]  none
+    \param[out] none
+    \retval     none
+*/
+void fwdgt_counter_reload(void)
+{
+    FWDGT_CTL = FWDGT_KEY_RELOAD;
+}
+
+/*!
+    \brief      configure counter reload value, and prescaler divider value
+    \param[in]  reload_value: specify reload value(0x0000 - 0x0FFF)
+    \param[in]  prescaler_div: FWDGT prescaler value
+                only one parameter can be selected which is shown as below:
+      \arg        FWDGT_PSC_DIV4: FWDGT prescaler set to 4
+      \arg        FWDGT_PSC_DIV8: FWDGT prescaler set to 8
+      \arg        FWDGT_PSC_DIV16: FWDGT prescaler set to 16
+      \arg        FWDGT_PSC_DIV32: FWDGT prescaler set to 32
+      \arg        FWDGT_PSC_DIV64: FWDGT prescaler set to 64
+      \arg        FWDGT_PSC_DIV128: FWDGT prescaler set to 128
+      \arg        FWDGT_PSC_DIV256: FWDGT prescaler set to 256
+    \param[out] none
+    \retval     ErrStatus: ERROR or SUCCESS
+*/
+ErrStatus fwdgt_config(uint16_t reload_value, uint8_t prescaler_div)
+{
+    uint32_t timeout = FWDGT_PSC_TIMEOUT;
+    uint32_t flag_status = RESET;
+
+    /* enable write access to FWDGT_PSC,and FWDGT_RLD */
+    FWDGT_CTL = FWDGT_WRITEACCESS_ENABLE;
+
+    /* wait until the PUD flag to be reset */
+    do {
+        flag_status = FWDGT_STAT & FWDGT_STAT_PUD;
+    } while((--timeout > 0U) && (RESET != flag_status));
+
+    if(RESET != flag_status) {
+        return ERROR;
+    }
+
+    /* configure FWDGT */
+    FWDGT_PSC = (uint32_t)prescaler_div;
+
+    timeout = FWDGT_RLD_TIMEOUT;
+    /* wait until the RUD flag to be reset */
+    do {
+        flag_status = FWDGT_STAT & FWDGT_STAT_RUD;
+    } while((--timeout > 0U) && (RESET != flag_status));
+
+    if(RESET != flag_status) {
+        return ERROR;
+    }
+
+    FWDGT_RLD = RLD_RLD(reload_value);
+
+    /* reload the counter */
+    FWDGT_CTL = FWDGT_KEY_RELOAD;
+
+    return SUCCESS;
+}
+
+/*!
+    \brief      get flag state of FWDGT
+    \param[in]  flag: flag to get
+                only one parameter can be selected which is shown as below:
+      \arg        FWDGT_FLAG_PUD: a write operation to FWDGT_PSC register is on going
+      \arg        FWDGT_FLAG_RUD: a write operation to FWDGT_RLD register is on going
+      \arg        FWDGT_FLAG_WUD: a write operation to FWDGT_WND register is on going
+    \param[out] none
+    \retval     FlagStatus: SET or RESET
+*/
+FlagStatus fwdgt_flag_get(uint16_t flag)
+{
+    if(FWDGT_STAT & flag) {
+        return SET;
+    }
+    return RESET;
+}

+ 423 - 0
GD32F3x0/GD32F3x0_standard_peripheral/Source/gd32f3x0_gpio.c

@@ -0,0 +1,423 @@
+/*!
+    \file    gd32f3x0_gpio.c
+    \brief   GPIO driver
+
+    \version 2025-01-01, V2.5.0, firmware for GD32F3x0
+*/
+
+/*
+    Copyright (c) 2025, GigaDevice Semiconductor Inc.
+
+    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 of the copyright holder 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 HOLDER 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.
+*/
+
+#include "gd32f3x0_gpio.h"
+
+/*!
+    \brief      reset GPIO port
+    \param[in]  gpio_periph: GPIOx(x = A,B,C,D,F)
+                only one parameter can be selected which is shown as below:
+      \arg        GPIOx(x = A,B,C,D,F)
+    \param[out] none
+    \retval     none
+*/
+void gpio_deinit(uint32_t gpio_periph)
+{
+    switch(gpio_periph) {
+    case GPIOA:
+        /* reset GPIOA */
+        rcu_periph_reset_enable(RCU_GPIOARST);
+        rcu_periph_reset_disable(RCU_GPIOARST);
+        break;
+    case GPIOB:
+        /* reset GPIOB */
+        rcu_periph_reset_enable(RCU_GPIOBRST);
+        rcu_periph_reset_disable(RCU_GPIOBRST);
+        break;
+    case GPIOC:
+        /* reset GPIOC */
+        rcu_periph_reset_enable(RCU_GPIOCRST);
+        rcu_periph_reset_disable(RCU_GPIOCRST);
+        break;
+    case GPIOD:
+        /* reset GPIOD */
+        rcu_periph_reset_enable(RCU_GPIODRST);
+        rcu_periph_reset_disable(RCU_GPIODRST);
+        break;
+    case GPIOF:
+        /* reset GPIOF */
+        rcu_periph_reset_enable(RCU_GPIOFRST);
+        rcu_periph_reset_disable(RCU_GPIOFRST);
+        break;
+    default:
+        break;
+    }
+}
+
+/*!
+    \brief      set GPIO mode
+    \param[in]  gpio_periph: GPIOx(x = A,B,C,D,F)
+                only one parameter can be selected which is shown as below:
+      \arg        GPIOx(x = A,B,C,D,F)
+    \param[in]  mode: gpio pin mode
+                only one parameter can be selected which is shown as below:
+      \arg        GPIO_MODE_INPUT: input mode
+      \arg        GPIO_MODE_OUTPUT: output mode
+      \arg        GPIO_MODE_AF: alternate function mode
+      \arg        GPIO_MODE_ANALOG: analog mode
+    \param[in]  pull_up_down: gpio pin with pull-up or pull-down resistor
+                only one parameter can be selected which is shown as below:
+      \arg        GPIO_PUPD_NONE: floating mode, no pull-up and pull-down resistors
+      \arg        GPIO_PUPD_PULLUP: with pull-up resistor
+      \arg        GPIO_PUPD_PULLDOWN:with pull-down resistor
+    \param[in]  pin: GPIO pin
+                one or more parameters can be selected which are shown as below:
+      \arg        GPIO_PIN_x(x=0..15), GPIO_PIN_ALL
+    \param[out] none
+    \retval     none
+*/
+void gpio_mode_set(uint32_t gpio_periph, uint32_t mode, uint32_t pull_up_down, uint32_t pin)
+{
+    uint16_t i;
+    uint32_t ctl, pupd;
+
+    ctl = GPIO_CTL(gpio_periph);
+    pupd = GPIO_PUD(gpio_periph);
+
+    for(i = 0U; i < 16U; i++) {
+        if((1U << i) & pin) {
+            /* clear the specified pin mode bits */
+            ctl &= ~GPIO_MODE_MASK(i);
+            /* set the specified pin mode bits */
+            ctl |= GPIO_MODE_SET(i, mode);
+
+            /* clear the specified pin pupd bits */
+            pupd &= ~GPIO_PUPD_MASK(i);
+            /* set the specified pin pupd bits */
+            pupd |= GPIO_PUPD_SET(i, pull_up_down);
+        }
+    }
+
+    GPIO_CTL(gpio_periph) = ctl;
+    GPIO_PUD(gpio_periph) = pupd;
+}
+
+/*!
+    \brief      set GPIO output type and speed
+    \param[in]  gpio_periph: GPIOx(x = A,B,C,D,F)
+                only one parameter can be selected which is shown as below:
+      \arg        GPIOx(x = A,B,C,D,F)
+    \param[in]  otype: gpio pin output mode
+                only one parameter can be selected which is shown as below:
+      \arg        GPIO_OTYPE_PP: push pull mode
+      \arg        GPIO_OTYPE_OD: open drain mode
+    \param[in]  speed: gpio pin output max speed
+                only one parameter can be selected which is shown as below:
+      \arg        GPIO_OSPEED_2MHZ: output max speed 2MHz
+      \arg        GPIO_OSPEED_10MHZ: output max speed 10MHz
+      \arg        GPIO_OSPEED_50MHZ: output max speed 50MHz
+      \arg        GPIO_OSPEED_MAX: GPIO very high output speed, max speed more than 50MHz
+    \param[in]  pin: GPIO pin
+                one or more parameters can be selected which are shown as below:
+      \arg        GPIO_PIN_x(x=0..15), GPIO_PIN_ALL
+    \param[out] none
+    \retval     none
+*/
+void gpio_output_options_set(uint32_t gpio_periph, uint8_t otype, uint32_t speed, uint32_t pin)
+{
+    uint16_t i;
+    uint32_t ospeed0, ospeed1;
+
+    if(GPIO_OTYPE_OD == otype) {
+        GPIO_OMODE(gpio_periph) |= (uint32_t)pin;
+    } else {
+        GPIO_OMODE(gpio_periph) &= (uint32_t)(~pin);
+    }
+
+    /* get the specified pin output speed bits value */
+    ospeed0 = GPIO_OSPD0(gpio_periph);
+
+    if(GPIO_OSPEED_MAX == speed) {
+        ospeed1 = GPIO_OSPD1(gpio_periph);
+
+        for(i = 0U; i < 16U; i++) {
+            if((1U << i) & pin) {
+                /* enable very high output speed function of the pin when the corresponding OSPDy(y=0..15)
+                   is "11" (output max speed 50MHz) */
+                ospeed0 |= GPIO_OSPEED_SET(i, 0x03);
+                ospeed1 |= (1U << i);
+            }
+        }
+        GPIO_OSPD0(gpio_periph) = ospeed0;
+        GPIO_OSPD1(gpio_periph) = ospeed1;
+    } else {
+        for(i = 0U; i < 16U; i++) {
+            if((1U << i) & pin) {
+                /* clear the specified pin output speed bits */
+                ospeed0 &= ~GPIO_OSPEED_MASK(i);
+                /* set the specified pin output speed bits */
+                ospeed0 |= GPIO_OSPEED_SET(i, speed);
+            }
+        }
+        GPIO_OSPD0(gpio_periph) = ospeed0;
+    }
+}
+
+/*!
+    \brief      set GPIO pin bit
+    \param[in]  gpio_periph: GPIOx(x = A,B,C,D,F)
+                only one parameter can be selected which is shown as below:
+      \arg        GPIOx(x = A,B,C,D,F)
+    \param[in]  pin: GPIO pin
+                one or more parameters can be selected which are shown as below:
+      \arg        GPIO_PIN_x(x=0..15), GPIO_PIN_ALL
+    \param[out] none
+    \retval     none
+*/
+void gpio_bit_set(uint32_t gpio_periph, uint32_t pin)
+{
+    GPIO_BOP(gpio_periph) = (uint32_t)pin;
+}
+
+/*!
+    \brief      reset GPIO pin bit
+    \param[in]  gpio_periph: GPIOx(x = A,B,C,D,F)
+                only one parameter can be selected which is shown as below:
+      \arg        GPIOx(x = A,B,C,D,F)
+    \param[in]  pin: GPIO pin
+                one or more parameters can be selected which are shown as below:
+      \arg        GPIO_PIN_x(x=0..15), GPIO_PIN_ALL
+    \param[out] none
+    \retval     none
+*/
+void gpio_bit_reset(uint32_t gpio_periph, uint32_t pin)
+{
+    GPIO_BC(gpio_periph) = (uint32_t)pin;
+}
+
+/*!
+    \brief      write data to the specified GPIO pin
+    \param[in]  gpio_periph: GPIOx(x = A,B,C,D,F)
+                only one parameter can be selected which is shown as below:
+      \arg        GPIOx(x = A,B,C,D,F)
+    \param[in]  pin: GPIO pin
+                one or more parameters can be selected which are shown as below:
+      \arg        GPIO_PIN_x(x=0..15), GPIO_PIN_ALL
+    \param[in]  bit_value: SET or RESET
+                only one parameter can be selected which is shown as below:
+      \arg        RESET: clear the port pin
+      \arg        SET: set the port pin
+    \param[out] none
+    \retval     none
+*/
+void gpio_bit_write(uint32_t gpio_periph, uint32_t pin, bit_status bit_value)
+{
+    if(RESET != bit_value) {
+        GPIO_BOP(gpio_periph) = (uint32_t)pin;
+    } else {
+        GPIO_BC(gpio_periph) = (uint32_t)pin;
+    }
+}
+
+/*!
+    \brief      write data to the specified GPIO port
+    \param[in]  gpio_periph: GPIOx(x = A,B,C,D,F)
+                only one parameter can be selected which is shown as below:
+      \arg        GPIOx(x = A,B,C,D,F)
+    \param[in]  data: specify the value to be written to the port output control register
+    \param[out] none
+    \retval     none
+*/
+void gpio_port_write(uint32_t gpio_periph, uint16_t data)
+{
+    GPIO_OCTL(gpio_periph) = (uint32_t)data;
+}
+
+/*!
+    \brief      get GPIO pin input status
+    \param[in]  gpio_periph: GPIOx(x = A,B,C,D,F)
+                only one parameter can be selected which is shown as below:
+      \arg        GPIOx(x = A,B,C,D,F)
+    \param[in]  pin: GPIO pin
+                one or more parameters can be selected which are shown as below:
+      \arg        GPIO_PIN_x(x=0..15), GPIO_PIN_ALL
+    \param[out] none
+    \retval     SET or RESET
+*/
+FlagStatus gpio_input_bit_get(uint32_t gpio_periph, uint32_t pin)
+{
+    if((uint32_t)RESET != (GPIO_ISTAT(gpio_periph) & (pin))) {
+        return SET;
+    } else {
+        return RESET;
+    }
+}
+
+/*!
+    \brief      get GPIO all pins input status
+    \param[in]  gpio_periph: GPIOx(x = A,B,C,D,F)
+                only one parameter can be selected which is shown as below:
+      \arg        GPIOx(x = A,B,C,D,F)
+    \param[out] none
+    \retval     state of GPIO all pins
+*/
+uint16_t gpio_input_port_get(uint32_t gpio_periph)
+{
+    return (uint16_t)GPIO_ISTAT(gpio_periph);
+}
+
+/*!
+    \brief      get GPIO pin output status
+    \param[in]  gpio_periph: GPIOx(x = A,B,C,D,F)
+                only one parameter can be selected which is shown as below:
+      \arg        GPIOx(x = A,B,C,D,F)
+    \param[in]  pin: GPIO pin
+                one or more parameters can be selected which are shown as below:
+      \arg        GPIO_PIN_x(x=0..15), GPIO_PIN_ALL
+    \param[out] none
+    \retval     SET or RESET
+*/
+FlagStatus gpio_output_bit_get(uint32_t gpio_periph, uint32_t pin)
+{
+    if((uint32_t)RESET != (GPIO_OCTL(gpio_periph) & (pin))) {
+        return SET;
+    } else {
+        return RESET;
+    }
+}
+
+/*!
+    \brief      get GPIO all pins output status
+    \param[in]  gpio_periph: GPIOx(x = A,B,C,D,F)
+                only one parameter can be selected which is shown as below:
+      \arg        GPIOx(x = A,B,C,D,F)
+    \param[out] none
+    \retval     state of GPIO all pins
+*/
+uint16_t gpio_output_port_get(uint32_t gpio_periph)
+{
+    return (uint16_t)GPIO_OCTL(gpio_periph);
+}
+
+/*!
+    \brief      set GPIO alternate function
+    \param[in]  gpio_periph: GPIOx(x = A,B,C)
+                only one parameter can be selected which is shown as below:
+      \arg        GPIOx(x = A,B,C)
+    \param[in]  alt_func_num: GPIO pin af function, please refer to specific device datasheet
+                only one parameter can be selected which is shown as below:
+      \arg        GPIO_AF_0: TIMER2, TIMER13, TIMER14, TIMER16, SPI0, SPI1, I2S0, CK_OUT, USART0, CEC,
+                              IFRP, TSI, CTC, I2C0, I2C1, SWDIO, SWCLK
+      \arg        GPIO_AF_1: USART0, USART1, TIMER2, TIMER14, I2C0, I2C1, IFRP, CEC
+      \arg        GPIO_AF_2: TIMER0, TIMER1, TIMER15, TIMER16, I2S0
+      \arg        GPIO_AF_3: TSI, I2C0, TIMER14
+      \arg        GPIO_AF_4(port A,B only): USART1, I2C0, I2C1, TIMER13
+      \arg        GPIO_AF_5(port A,B only): TIMER15, TIMER16, USBFS, I2S0
+      \arg        GPIO_AF_6(port A,B only): CTC, SPI1
+      \arg        GPIO_AF_7(port A,B only): CMP0, CMP1
+    \param[in]  pin: GPIO pin
+                one or more parameters can be selected which are shown as below:
+      \arg        GPIO_PIN_x(x=0..15), GPIO_PIN_ALL
+    \param[out] none
+    \retval     none
+*/
+void gpio_af_set(uint32_t gpio_periph, uint32_t alt_func_num, uint32_t pin)
+{
+    uint16_t i;
+    uint32_t afrl, afrh;
+
+    afrl = GPIO_AFSEL0(gpio_periph);
+    afrh = GPIO_AFSEL1(gpio_periph);
+
+    for(i = 0U; i < 8U; i++) {
+        if((1U << i) & pin) {
+            /* clear the specified pin alternate function bits */
+            afrl &= ~GPIO_AFR_MASK(i);
+            afrl |= GPIO_AFR_SET(i, alt_func_num);
+        }
+    }
+
+    for(i = 8U; i < 16U; i++) {
+        if((1U << i) & pin) {
+            /* clear the specified pin alternate function bits */
+            afrh &= ~GPIO_AFR_MASK(i - 8U);
+            afrh |= GPIO_AFR_SET(i - 8U, alt_func_num);
+        }
+    }
+
+    GPIO_AFSEL0(gpio_periph) = afrl;
+    GPIO_AFSEL1(gpio_periph) = afrh;
+}
+
+/*!
+    \brief      lock GPIO pin bit
+    \param[in]  gpio_periph: GPIOx(x = A,B)
+                only one parameter can be selected which is shown as below:
+      \arg        GPIOx(x = A,B)
+    \param[in]  pin: GPIO pin
+                one or more parameters can be selected which are shown as below:
+      \arg        GPIO_PIN_x(x=0..15), GPIO_PIN_ALL
+    \param[out] none
+    \retval     none
+*/
+void gpio_pin_lock(uint32_t gpio_periph, uint32_t pin)
+{
+    uint32_t lock = 0x00010000U;
+    lock |= pin;
+
+    /* lock key writing sequence: write 1->write 0->write 1->read 0->read 1 */
+    GPIO_LOCK(gpio_periph) = (uint32_t)lock;
+    GPIO_LOCK(gpio_periph) = (uint32_t)pin;
+    GPIO_LOCK(gpio_periph) = (uint32_t)lock;
+    lock = GPIO_LOCK(gpio_periph);
+    lock = GPIO_LOCK(gpio_periph);
+}
+
+/*!
+    \brief      toggle GPIO pin status
+    \param[in]  gpio_periph: GPIOx(x = A,B,C,D,F)
+                only one parameter can be selected which is shown as below:
+      \arg        GPIOx(x = A,B,C,D,F)
+    \param[in]  pin: GPIO pin
+                one or more parameters can be selected which are shown as below:
+      \arg        GPIO_PIN_x(x=0..15), GPIO_PIN_ALL
+    \param[out] none
+    \retval     none
+*/
+void gpio_bit_toggle(uint32_t gpio_periph, uint32_t pin)
+{
+    GPIO_TG(gpio_periph) = (uint32_t)pin;
+}
+
+/*!
+    \brief      toggle GPIO port status
+                only one parameter can be selected which is shown as below:
+      \arg        GPIOx(x = A,B,C,D,F)
+    \param[out] none
+    \retval     none
+*/
+void gpio_port_toggle(uint32_t gpio_periph)
+{
+    GPIO_TG(gpio_periph) = 0x0000FFFFU;
+}

+ 730 - 0
GD32F3x0/GD32F3x0_standard_peripheral/Source/gd32f3x0_i2c.c

@@ -0,0 +1,730 @@
+/*!
+    \file    gd32f3x0_i2c.c
+    \brief   I2C driver
+
+    \version 2025-01-01, V2.5.0, firmware for GD32F3x0
+*/
+
+/*
+    Copyright (c) 2025, GigaDevice Semiconductor Inc.
+
+    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 of the copyright holder 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 HOLDER 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.
+*/
+
+#include "gd32f3x0_i2c.h"
+
+/* I2C register bit mask */
+#define I2CCLK_MAX                    ((uint32_t)0x0000003FU)             /*!< i2cclk maximum value */
+#define I2CCLK_MIN                    ((uint32_t)0x00000002U)             /*!< i2cclk minimum value */
+#define I2C_FLAG_MASK                 ((uint32_t)0x0000FFFFU)             /*!< i2c flag mask */
+#define I2C_ADDRESS_MASK              ((uint32_t)0x000003FFU)             /*!< i2c address mask */
+#define I2C_ADDRESS2_MASK             ((uint32_t)0x000000FEU)             /*!< the second i2c address mask */
+
+/* I2C register bit offset */
+#define STAT1_PECV_OFFSET             ((uint32_t)0x00000008U)             /*!< bit offset of PECV in I2C_STAT1 */
+
+/*!
+    \brief      reset I2C
+    \param[in]  i2c_periph: I2Cx(x=0,1)
+    \param[out] none
+    \retval     none
+*/
+void i2c_deinit(uint32_t i2c_periph)
+{
+    switch(i2c_periph) {
+    case I2C0:
+        /* reset I2C0 */
+        rcu_periph_reset_enable(RCU_I2C0RST);
+        rcu_periph_reset_disable(RCU_I2C0RST);
+        break;
+    case I2C1:
+        /* reset I2C1 */
+        rcu_periph_reset_enable(RCU_I2C1RST);
+        rcu_periph_reset_disable(RCU_I2C1RST);
+        break;
+    default:
+        break;
+    }
+}
+
+/*!
+    \brief      configure I2C clock
+    \param[in]  i2c_periph: I2Cx(x=0,1)
+    \param[in]  clkspeed: I2C clock speed, supports standard mode (up to 100 kHz), fast mode (up to 400 kHz)
+                          and fast mode plus (up to 1MHz)
+    \param[in]  dutycyc: duty cycle in fast mode or fast mode plus, and only I2C_DTCY_2 can be selected in standard mode
+                only one parameter can be selected which is shown as below:
+      \arg        I2C_DTCY_2: T_low/T_high=2
+      \arg        I2C_DTCY_16_9: T_low/T_high=16/9
+    \param[out] none
+    \retval     none
+*/
+void i2c_clock_config(uint32_t i2c_periph, uint32_t clkspeed, uint32_t dutycyc)
+{
+    uint32_t pclk1, clkc, freq, risetime;
+    uint32_t temp;
+
+    pclk1 = rcu_clock_freq_get(CK_APB1);
+    /* I2C peripheral clock frequency */
+    freq = (uint32_t)(pclk1 / 1000000U);
+    if(freq >= I2CCLK_MAX) {
+        freq = I2CCLK_MAX;
+    }
+    temp = I2C_CTL1(i2c_periph);
+    temp &= ~I2C_CTL1_I2CCLK;
+    temp |= freq;
+
+    I2C_CTL1(i2c_periph) = temp;
+
+    if(100000U >= clkspeed) {
+        /* the maximum SCL rise time is 1000ns in standard mode */
+        risetime = (uint32_t)((pclk1 / 1000000U) + 1U);
+        if(risetime >= I2CCLK_MAX) {
+            I2C_RT(i2c_periph) = I2CCLK_MAX;
+        } else if(risetime <= I2CCLK_MIN) {
+            I2C_RT(i2c_periph) = I2CCLK_MIN;
+        } else {
+            I2C_RT(i2c_periph) = risetime;
+        }
+        clkc = (uint32_t)(pclk1 / (clkspeed * 2U));
+        if(clkc < 0x04U) {
+            /* the CLKC in standard mode minmum value is 4 */
+            clkc = 0x04U;
+        }
+        I2C_CKCFG(i2c_periph) |= (I2C_CKCFG_CLKC & clkc);
+
+    } else if(400000U >= clkspeed) {
+        /* the maximum SCL rise time is 300ns in fast mode */
+        I2C_RT(i2c_periph) = (uint32_t)(((freq * (uint32_t)300U) / (uint32_t)1000U) + (uint32_t)1U);
+        if(I2C_DTCY_2 == dutycyc) {
+            /* I2C duty cycle is 2 */
+            clkc = (uint32_t)(pclk1 / (clkspeed * 3U));
+            I2C_CKCFG(i2c_periph) &= ~I2C_CKCFG_DTCY;
+        } else {
+            /* I2C duty cycle is 16/9 */
+            clkc = (uint32_t)(pclk1 / (clkspeed * 25U));
+            I2C_CKCFG(i2c_periph) |= I2C_CKCFG_DTCY;
+        }
+        if(0U == (clkc & I2C_CKCFG_CLKC)) {
+            /* the CLKC in fast mode minimum value is 1 */
+            clkc |= 0x0001U;
+        }
+        I2C_CKCFG(i2c_periph) |= I2C_CKCFG_FAST;
+        I2C_CKCFG(i2c_periph) |= clkc;
+    } else {
+        /* fast mode plus, the maximum SCL rise time is 120ns */
+        I2C_RT(i2c_periph) = (uint32_t)(((freq * (uint32_t)120U) / (uint32_t)1000U) + (uint32_t)1U);
+        if(I2C_DTCY_2 == dutycyc) {
+            /* I2C duty cycle is 2 */
+            clkc = (uint32_t)(pclk1/(clkspeed*3U));
+            I2C_CKCFG(i2c_periph) &= ~I2C_CKCFG_DTCY;
+        } else {
+            /* I2C duty cycle is 16/9 */
+            clkc = (uint32_t)(pclk1 / (clkspeed * 25U));
+            I2C_CKCFG(i2c_periph) |= I2C_CKCFG_DTCY;
+        }
+        /* enable fast mode */
+        I2C_CKCFG(i2c_periph) |= I2C_CKCFG_FAST;
+        I2C_CKCFG(i2c_periph) |= clkc;
+        /* enable I2C fast mode plus */
+        I2C_FMPCFG(i2c_periph) = I2C_FMPCFG_FMPEN;
+    }
+}
+
+/*!
+    \brief      configure I2C address
+    \param[in]  i2c_periph: I2Cx(x=0,1)
+    \param[in]  mode:
+                only one parameter can be selected which is shown as below:
+      \arg        I2C_I2CMODE_ENABLE: I2C mode
+      \arg        I2C_SMBUSMODE_ENABLE: SMBus mode
+    \param[in]  addformat: 7bits or 10bits
+                only one parameter can be selected which is shown as below:
+      \arg        I2C_ADDFORMAT_7BITS: address format is 7 bits
+      \arg        I2C_ADDFORMAT_10BITS: address format is 10 bits
+    \param[in]  addr: I2C address
+    \param[out] none
+    \retval     none
+*/
+void i2c_mode_addr_config(uint32_t i2c_periph, uint32_t mode, uint32_t addformat, uint32_t addr)
+{
+    /* SMBus/I2C mode selected */
+    uint32_t ctl = 0U;
+
+    ctl = I2C_CTL0(i2c_periph);
+    ctl &= ~(I2C_CTL0_SMBEN);
+    ctl |= mode;
+    I2C_CTL0(i2c_periph) = ctl;
+
+    /* configure address */
+    addr = addr & I2C_ADDRESS_MASK;
+    I2C_SADDR0(i2c_periph) = (addformat | addr);
+}
+
+/*!
+    \brief      select SMBus type
+    \param[in]  i2c_periph: I2Cx(x=0,1)
+    \param[in]  type:
+                only one parameter can be selected which is shown as below:
+      \arg        I2C_SMBUS_DEVICE: SMBus mode device type
+      \arg        I2C_SMBUS_HOST: SMBus mode host type
+    \param[out] none
+    \retval     none
+*/
+void i2c_smbus_type_config(uint32_t i2c_periph, uint32_t type)
+{
+    if(I2C_SMBUS_HOST == type) {
+        I2C_CTL0(i2c_periph) |= I2C_CTL0_SMBSEL;
+    } else {
+        I2C_CTL0(i2c_periph) &= ~(I2C_CTL0_SMBSEL);
+    }
+}
+
+/*!
+    \brief      whether or not to send an ACK
+    \param[in]  i2c_periph: I2Cx(x=0,1)
+    \param[in]  ack:
+                only one parameter can be selected which is shown as below:
+      \arg        I2C_ACK_ENABLE: ACK will be sent
+      \arg        I2C_ACK_DISABLE: ACK will not be sent
+    \param[out] none
+    \retval     none
+*/
+void i2c_ack_config(uint32_t i2c_periph, uint32_t ack)
+{
+    uint32_t ctl = 0U;
+
+    ctl = I2C_CTL0(i2c_periph);
+    ctl &= ~(I2C_CTL0_ACKEN);
+    ctl |= ack;
+    I2C_CTL0(i2c_periph) = ctl;
+}
+
+/*!
+    \brief      configure I2C POAP position
+    \param[in]  i2c_periph: I2Cx(x=0,1)
+    \param[in]  pos:
+                only one parameter can be selected which is shown as below:
+      \arg        I2C_ACKPOS_CURRENT: ACKEN bit decides whether or not to send ACK or not for the current byte
+      \arg        I2C_ACKPOS_NEXT: ACKEN bit decides whether or not to send ACK for the next byte
+    \param[out] none
+    \retval     none
+*/
+void i2c_ackpos_config(uint32_t i2c_periph, uint32_t pos)
+{
+    uint32_t ctl = 0U;
+
+    /* configure I2C POAP position */
+    ctl = I2C_CTL0(i2c_periph);
+    ctl &= ~(I2C_CTL0_POAP);
+    ctl |= pos;
+    I2C_CTL0(i2c_periph) = ctl;
+}
+
+/*!
+    \brief      master sends slave address
+    \param[in]  i2c_periph: I2Cx(x=0,1)
+    \param[in]  addr: slave address
+    \param[in]  trandirection: transmitter or receiver
+                only one parameter can be selected which is shown as below:
+      \arg        I2C_TRANSMITTER: transmitter
+      \arg        I2C_RECEIVER: receiver
+    \param[out] none
+    \retval     none
+*/
+void i2c_master_addressing(uint32_t i2c_periph, uint32_t addr, uint32_t trandirection)
+{
+    /* master is a transmitter or a receiver */
+    if(I2C_TRANSMITTER == trandirection) {
+        addr = addr & I2C_TRANSMITTER;
+    } else {
+        addr = addr | I2C_RECEIVER;
+    }
+    /* send slave address */
+    I2C_DATA(i2c_periph) = addr;
+}
+
+/*!
+    \brief      enable dual-address mode
+    \param[in]  i2c_periph: I2Cx(x=0,1)
+    \param[in]  addr: the second address in dual-address mode
+    \param[out] none
+    \retval     none
+*/
+void i2c_dualaddr_enable(uint32_t i2c_periph, uint32_t addr)
+{
+    /* configure address */
+    addr = addr & I2C_ADDRESS2_MASK;
+    I2C_SADDR1(i2c_periph) = (I2C_SADDR1_DUADEN | addr);
+}
+
+/*!
+    \brief      disable dual-address mode
+    \param[in]  i2c_periph: I2Cx(x=0,1)
+    \param[out] none
+    \retval     none
+*/
+void i2c_dualaddr_disable(uint32_t i2c_periph)
+{
+    I2C_SADDR1(i2c_periph) &= ~(I2C_SADDR1_DUADEN);
+}
+
+/*!
+    \brief      enable I2C
+    \param[in]  i2c_periph: I2Cx(x=0,1)
+    \param[out] none
+    \retval     none
+*/
+void i2c_enable(uint32_t i2c_periph)
+{
+    I2C_CTL0(i2c_periph) |= I2C_CTL0_I2CEN;
+}
+
+/*!
+    \brief      disable I2C
+    \param[in]  i2c_periph: I2Cx(x=0,1)
+    \param[out] none
+    \retval     none
+*/
+void i2c_disable(uint32_t i2c_periph)
+{
+    I2C_CTL0(i2c_periph) &= ~(I2C_CTL0_I2CEN);
+}
+
+/*!
+    \brief      generate a START condition on I2C bus
+    \param[in]  i2c_periph: I2Cx(x=0,1)
+    \param[out] none
+    \retval     none
+*/
+void i2c_start_on_bus(uint32_t i2c_periph)
+{
+    I2C_CTL0(i2c_periph) |= I2C_CTL0_START;
+}
+
+/*!
+    \brief      generate a STOP condition on I2C bus
+    \param[in]  i2c_periph: I2Cx(x=0,1)
+    \param[out] none
+    \retval     none
+*/
+void i2c_stop_on_bus(uint32_t i2c_periph)
+{
+    I2C_CTL0(i2c_periph) |= I2C_CTL0_STOP;
+}
+
+/*!
+    \brief      I2C transmit data function
+    \param[in]  i2c_periph: I2Cx(x=0,1)
+    \param[in]  data: data of transmission
+    \param[out] none
+    \retval     none
+*/
+void i2c_data_transmit(uint32_t i2c_periph, uint8_t data)
+{
+    I2C_DATA(i2c_periph) = DATA_TRANS(data);
+}
+
+/*!
+    \brief      I2C receive data function
+    \param[in]  i2c_periph: I2Cx(x=0,1)
+    \param[out] none
+    \retval     data of received
+*/
+uint8_t i2c_data_receive(uint32_t i2c_periph)
+{
+    return (uint8_t)DATA_RECV(I2C_DATA(i2c_periph));
+}
+
+/*!
+    \brief      configure I2C DMA mode
+    \param[in]  i2c_periph: I2Cx(x=0,1)
+    \param[in]  dmastate:
+                only one parameter can be selected which is shown as below:
+      \arg        I2C_DMA_ON: enable DMA mode
+      \arg        I2C_DMA_OFF: disable DMA mode
+    \param[out] none
+    \retval     none
+*/
+void i2c_dma_config(uint32_t i2c_periph, uint32_t dmastate)
+{
+    /* configure I2C DMA function */
+    uint32_t ctl = 0U;
+
+    ctl = I2C_CTL1(i2c_periph);
+    ctl &= ~(I2C_CTL1_DMAON);
+    ctl |= dmastate;
+    I2C_CTL1(i2c_periph) = ctl;
+}
+
+/*!
+    \brief      configure whether next DMA EOT is DMA last transfer or not
+    \param[in]  i2c_periph: I2Cx(x=0,1)
+    \param[in]  dmalast:
+                only one parameter can be selected which is shown as below:
+      \arg        I2C_DMALST_ON: next DMA EOT is the last transfer
+      \arg        I2C_DMALST_OFF: next DMA EOT is not the last transfer
+    \param[out] none
+    \retval     none
+*/
+void i2c_dma_last_transfer_config(uint32_t i2c_periph, uint32_t dmalast)
+{
+    /* configure DMA last transfer */
+    uint32_t ctl = 0U;
+
+    ctl = I2C_CTL1(i2c_periph);
+    ctl &= ~(I2C_CTL1_DMALST);
+    ctl |= dmalast;
+    I2C_CTL1(i2c_periph) = ctl;
+}
+
+/*!
+    \brief      whether to stretch SCL low when data is not ready in slave mode
+    \param[in]  i2c_periph: I2Cx(x=0,1)
+    \param[in]  stretchpara:
+                only one parameter can be selected which is shown as below:
+      \arg        I2C_SCLSTRETCH_ENABLE: enable SCL stretching
+      \arg        I2C_SCLSTRETCH_DISABLE: disable SCL stretching
+    \param[out] none
+    \retval     none
+*/
+void i2c_stretch_scl_low_config(uint32_t i2c_periph, uint32_t stretchpara)
+{
+    /* configure I2C SCL stretching */
+    uint32_t ctl = 0U;
+
+    ctl = I2C_CTL0(i2c_periph);
+    ctl &= ~(I2C_CTL0_SS);
+    ctl |= stretchpara;
+    I2C_CTL0(i2c_periph) = ctl;
+}
+
+/*!
+    \brief      whether or not to response to a general call
+    \param[in]  i2c_periph: I2Cx(x=0,1)
+    \param[in]  gcallpara:
+                only one parameter can be selected which is shown as below:
+      \arg        I2C_GCEN_ENABLE: slave will response to a general call
+      \arg        I2C_GCEN_DISABLE: slave will not response to a general call
+    \param[out] none
+    \retval     none
+*/
+void i2c_slave_response_to_gcall_config(uint32_t i2c_periph, uint32_t gcallpara)
+{
+    /* configure slave response to a general call enable or disable */
+    uint32_t ctl = 0U;
+
+    ctl = I2C_CTL0(i2c_periph);
+    ctl &= ~(I2C_CTL0_GCEN);
+    ctl |= gcallpara;
+    I2C_CTL0(i2c_periph) = ctl;
+}
+
+/*!
+    \brief      configure software reset of I2C
+    \param[in]  i2c_periph: I2Cx(x=0,1)
+    \param[in]  sreset:
+                only one parameter can be selected which is shown as below:
+      \arg        I2C_SRESET_SET: I2C is under reset
+      \arg        I2C_SRESET_RESET: I2C is not under reset
+    \param[out] none
+    \retval     none
+*/
+void i2c_software_reset_config(uint32_t i2c_periph, uint32_t sreset)
+{
+    /* modify CTL0 and configure software reset I2C state */
+    uint32_t ctl = 0U;
+
+    ctl = I2C_CTL0(i2c_periph);
+    ctl &= ~(I2C_CTL0_SRESET);
+    ctl |= sreset;
+    I2C_CTL0(i2c_periph) = ctl;
+}
+
+/*!
+    \brief      configure I2C PEC calculation
+    \param[in]  i2c_periph: I2Cx(x=0,1)
+    \param[in]  pecstate:
+                only one parameter can be selected which is shown as below:
+      \arg        I2C_PEC_ENABLE: PEC calculation on
+      \arg        I2C_PEC_DISABLE: PEC calculation off
+    \param[out] none
+    \retval     none
+*/
+void i2c_pec_config(uint32_t i2c_periph, uint32_t pecstate)
+{
+    /* on/off PEC calculation */
+    uint32_t ctl = 0U;
+
+    ctl = I2C_CTL0(i2c_periph);
+    ctl &= ~(I2C_CTL0_PECEN);
+    ctl |= pecstate;
+    I2C_CTL0(i2c_periph) = ctl;
+}
+
+/*!
+    \brief      configure whether to transfer PEC value
+    \param[in]  i2c_periph: I2Cx(x=0,1)
+    \param[in]  pecpara:
+                only one parameter can be selected which is shown as below:
+      \arg        I2C_PECTRANS_ENABLE: transfer PEC value
+      \arg        I2C_PECTRANS_DISABLE: not transfer PEC value
+    \param[out] none
+    \retval     none
+*/
+void i2c_pec_transfer_config(uint32_t i2c_periph, uint32_t pecpara)
+{
+    /* whether to transfer PEC */
+    uint32_t ctl = 0U;
+
+    ctl = I2C_CTL0(i2c_periph);
+    ctl &= ~(I2C_CTL0_PECTRANS);
+    ctl |= pecpara;
+    I2C_CTL0(i2c_periph) = ctl;
+}
+
+/*!
+    \brief      get packet error checking value
+    \param[in]  i2c_periph: I2Cx(x=0,1)
+    \param[out] none
+    \retval     PEC value
+*/
+uint8_t i2c_pec_value_get(uint32_t i2c_periph)
+{
+    return (uint8_t)((I2C_STAT1(i2c_periph) & I2C_STAT1_PECV) >> STAT1_PECV_OFFSET);
+}
+
+/*!
+    \brief      configure I2C alert through SMBA pin
+    \param[in]  i2c_periph: I2Cx(x=0,1)
+    \param[in]  smbuspara:
+                only one parameter can be selected which is shown as below:
+      \arg        I2C_SALTSEND_ENABLE: issue alert through SMBA pin
+      \arg        I2C_SALTSEND_DISABLE: not issue alert through SMBA pin
+    \param[out] none
+    \retval     none
+*/
+void i2c_smbus_alert_config(uint32_t i2c_periph, uint32_t smbuspara)
+{
+    /* configure smbus alert through SMBA pin */
+    uint32_t ctl = 0U;
+
+    ctl = I2C_CTL0(i2c_periph);
+    ctl &= ~(I2C_CTL0_SALT);
+    ctl |= smbuspara;
+    I2C_CTL0(i2c_periph) = ctl;
+}
+
+/*!
+    \brief      configure I2C ARP protocol in SMBus
+    \param[in]  i2c_periph: I2Cx(x=0,1)
+    \param[in]  arpstate:
+                only one parameter can be selected which is shown as below:
+      \arg        I2C_ARP_ENABLE: enable ARP
+      \arg        I2C_ARP_DISABLE: disable ARP
+    \param[out] none
+    \retval     none
+*/
+void i2c_smbus_arp_config(uint32_t i2c_periph, uint32_t arpstate)
+{
+    /* enable or disable I2C ARP protocol*/
+    uint32_t ctl = 0U;
+
+    ctl = I2C_CTL0(i2c_periph);
+    ctl &= ~(I2C_CTL0_ARPEN);
+    ctl |= arpstate;
+    I2C_CTL0(i2c_periph) = ctl;
+}
+
+/*!
+    \brief      check I2C flag is set or not
+    \param[in]  i2c_periph: I2Cx(x=0,1)
+    \param[in]  flag: I2C flags, refer to i2c_flag_enum
+                only one parameter can be selected which is shown as below:
+      \arg        I2C_FLAG_SBSEND: start condition sent out in master mode
+      \arg        I2C_FLAG_ADDSEND: address is sent in master mode or received and matches in slave mode
+      \arg        I2C_FLAG_BTC: byte transmission finishes
+      \arg        I2C_FLAG_ADD10SEND: header of 10-bit address is sent in master mode
+      \arg        I2C_FLAG_STPDET: stop condition detected in slave mode
+      \arg        I2C_FLAG_RBNE: I2C_DATA is not empty during receiving
+      \arg        I2C_FLAG_TBE: I2C_DATA is empty during transmitting
+      \arg        I2C_FLAG_BERR: a bus error occurs indication a unexpected start or stop condition on I2C bus
+      \arg        I2C_FLAG_LOSTARB: arbitration lost in master mode
+      \arg        I2C_FLAG_AERR: acknowledge error
+      \arg        I2C_FLAG_OUERR: over-run or under-run situation occurs in slave mode
+      \arg        I2C_FLAG_PECERR: PEC error when receiving data
+      \arg        I2C_FLAG_SMBTO: timeout signal in SMBus mode
+      \arg        I2C_FLAG_SMBALT: SMBus alert status
+      \arg        I2C_FLAG_MASTER: a flag indicating whether I2C block is in master or slave mode
+      \arg        I2C_FLAG_I2CBSY: busy flag
+      \arg        I2C_FLAG_TR: whether the I2C is a transmitter or a receiver
+      \arg        I2C_FLAG_RXGC: general call address (00h) received
+      \arg        I2C_FLAG_DEFSMB: default address of SMBus device
+      \arg        I2C_FLAG_HSTSMB: SMBus host header detected in slave mode
+      \arg        I2C_FLAG_DUMOD: dual flag in slave mode indicating which address is matched in dual-address mode
+    \param[out] none
+    \retval     FlagStatus: SET or RESET
+*/
+FlagStatus i2c_flag_get(uint32_t i2c_periph, i2c_flag_enum flag)
+{
+    if(RESET != (I2C_REG_VAL(i2c_periph, flag) & BIT(I2C_BIT_POS(flag)))) {
+        return SET;
+    } else {
+        return RESET;
+    }
+}
+
+/*!
+    \brief      clear I2C flag status
+    \param[in]  i2c_periph: I2Cx(x=0,1)
+    \param[in]  flag: I2C flags, refer to i2c_flag_enum
+                only one parameter can be selected which is shown as below:
+      \arg       I2C_FLAG_SMBALT: SMBus alert status
+      \arg       I2C_FLAG_SMBTO: timeout signal in SMBus mode
+      \arg       I2C_FLAG_PECERR: PEC error when receiving data
+      \arg       I2C_FLAG_OUERR: over-run or under-run situation occurs in slave mode
+      \arg       I2C_FLAG_AERR: acknowledge error
+      \arg       I2C_FLAG_LOSTARB: arbitration lost in master mode
+      \arg       I2C_FLAG_BERR: a bus error occurs indication a unexpected start or stop condition on I2C bus
+      \arg       I2C_FLAG_ADDSEND: address is sent in master mode or received and matches in slave mode
+    \param[out] none
+    \retval     none
+*/
+void i2c_flag_clear(uint32_t i2c_periph, i2c_flag_enum flag)
+{
+    if(I2C_FLAG_ADDSEND == flag) {
+        /* read I2C_STAT0 and then read I2C_STAT1 to clear ADDSEND */
+        I2C_STAT0(i2c_periph);
+        I2C_STAT1(i2c_periph);
+    } else {
+        I2C_REG_VAL(i2c_periph, flag) &= ~BIT(I2C_BIT_POS(flag));
+    }
+}
+
+/*!
+    \brief      enable I2C interrupt
+    \param[in]  i2c_periph: I2Cx(x=0,1)
+    \param[in]  interrupt: I2C interrupts, refer to i2c_interrupt_enum
+                only one parameter can be selected which is shown as below:
+      \arg        I2C_INT_ERR: error interrupt
+      \arg        I2C_INT_EV: event interrupt
+      \arg        I2C_INT_BUF: buffer interrupt
+    \param[out] none
+    \retval     none
+*/
+void i2c_interrupt_enable(uint32_t i2c_periph, i2c_interrupt_enum interrupt)
+{
+    I2C_REG_VAL(i2c_periph, interrupt) |= BIT(I2C_BIT_POS(interrupt));
+}
+
+/*!
+    \brief      disable I2C interrupt
+    \param[in]  i2c_periph: I2Cx(x=0,1)
+    \param[in]  interrupt: I2C interrupts, refer to i2c_interrupt_enum
+                only one parameter can be selected which is shown as below:
+      \arg        I2C_INT_ERR: error interrupt
+      \arg        I2C_INT_EV: event interrupt
+      \arg        I2C_INT_BUF: buffer interrupt
+    \param[out] none
+    \retval     none
+*/
+void i2c_interrupt_disable(uint32_t i2c_periph, i2c_interrupt_enum interrupt)
+{
+    I2C_REG_VAL(i2c_periph, interrupt) &= ~BIT(I2C_BIT_POS(interrupt));
+}
+
+/*!
+    \brief      get I2C interrupt flag status
+    \param[in]  i2c_periph: I2Cx(x=0,1)
+    \param[in]  int_flag: I2C interrupt flags, refer to i2c_interrupt_flag_enum
+                only one parameter can be selected which is shown as below:
+      \arg        I2C_INT_FLAG_SBSEND: start condition sent out in master mode interrupt flag
+      \arg        I2C_INT_FLAG_ADDSEND: address is sent in master mode or received and matches in slave mode interrupt flag
+      \arg        I2C_INT_FLAG_BTC: byte transmission finishes interrupt flag
+      \arg        I2C_INT_FLAG_ADD10SEND: header of 10-bit address is sent in master mode interrupt flag
+      \arg        I2C_INT_FLAG_STPDET: stop condition detected in slave mode interrupt flag
+      \arg        I2C_INT_FLAG_RBNE: I2C_DATA is not Empty during receiving interrupt flag
+      \arg        I2C_INT_FLAG_TBE: I2C_DATA is empty during transmitting interrupt flag
+      \arg        I2C_INT_FLAG_BERR: a bus error occurs indication a unexpected start or stop condition on I2C bus interrupt flag
+      \arg        I2C_INT_FLAG_LOSTARB: arbitration lost in master mode interrupt flag
+      \arg        I2C_INT_FLAG_AERR: acknowledge error interrupt flag
+      \arg        I2C_INT_FLAG_OUERR: over-run or under-run situation occurs in slave mode interrupt flag
+      \arg        I2C_INT_FLAG_PECERR: PEC error when receiving data interrupt flag
+      \arg        I2C_INT_FLAG_SMBTO: timeout signal in SMBus mode interrupt flag
+      \arg        I2C_INT_FLAG_SMBALT: SMBus alert status interrupt flag
+    \param[out] none
+    \retval     FlagStatus: SET or RESET
+*/
+FlagStatus i2c_interrupt_flag_get(uint32_t i2c_periph, i2c_interrupt_flag_enum int_flag)
+{
+    uint32_t intenable = 0U, flagstatus = 0U, bufie;
+
+    /* check BUFIE */
+    bufie = I2C_CTL1(i2c_periph)&I2C_CTL1_BUFIE;
+
+    /* get the interrupt enable bit status */
+    intenable = (I2C_REG_VAL(i2c_periph, int_flag) & BIT(I2C_BIT_POS(int_flag)));
+    /* get the corresponding flag bit status */
+    flagstatus = (I2C_REG_VAL2(i2c_periph, int_flag) & BIT(I2C_BIT_POS2(int_flag)));
+
+    if((I2C_INT_FLAG_RBNE == int_flag) || (I2C_INT_FLAG_TBE == int_flag)) {
+        if(intenable && bufie) {
+            intenable = 1U;
+        } else {
+            intenable = 0U;
+        }
+    }
+    if((0U != flagstatus) && (0U != intenable)) {
+        return SET;
+    } else {
+        return RESET;
+    }
+}
+
+/*!
+    \brief      clear I2C interrupt flag status
+    \param[in]  i2c_periph: I2Cx(x=0,1)
+    \param[in]  int_flag: I2C interrupt flags, refer to i2c_interrupt_flag_enum
+                only one parameter can be selected which is shown as below:
+      \arg        I2C_INT_FLAG_ADDSEND: address is sent in master mode or received and matches in slave mode interrupt flag
+      \arg        I2C_INT_FLAG_BERR: a bus error occurs indication a unexpected start or stop condition on I2C bus interrupt flag
+      \arg        I2C_INT_FLAG_LOSTARB: arbitration lost in master mode interrupt flag
+      \arg        I2C_INT_FLAG_AERR: acknowledge error interrupt flag
+      \arg        I2C_INT_FLAG_OUERR: over-run or under-run situation occurs in slave mode interrupt flag
+      \arg        I2C_INT_FLAG_PECERR: PEC error when receiving data interrupt flag
+      \arg        I2C_INT_FLAG_SMBTO: timeout signal in SMBus mode interrupt flag
+      \arg        I2C_INT_FLAG_SMBALT: SMBus alert status interrupt flag
+    \param[out] none
+    \retval     none
+*/
+void i2c_interrupt_flag_clear(uint32_t i2c_periph, i2c_interrupt_flag_enum int_flag)
+{
+    if(I2C_INT_FLAG_ADDSEND == int_flag) {
+        /* read I2C_STAT0 and then read I2C_STAT1 to clear ADDSEND */
+        I2C_STAT0(i2c_periph);
+        I2C_STAT1(i2c_periph);
+    } else {
+        I2C_REG_VAL2(i2c_periph, int_flag) &= ~BIT(I2C_BIT_POS2(int_flag));
+    }
+}

+ 189 - 0
GD32F3x0/GD32F3x0_standard_peripheral/Source/gd32f3x0_misc.c

@@ -0,0 +1,189 @@
+/*!
+    \file    gd32f3x0_misc.c
+    \brief   MISC driver
+
+    \version 2025-01-01, V2.5.0, firmware for GD32F3x0
+*/
+
+/*
+    Copyright (c) 2025, GigaDevice Semiconductor Inc.
+
+    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 of the copyright holder 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 HOLDER 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.
+*/
+
+#include "gd32f3x0_misc.h"
+
+/*!
+    \brief      set the priority group
+    \param[in]  nvic_prigroup: the NVIC priority group
+                only one parameter can be selected which is shown as below:
+      \arg        NVIC_PRIGROUP_PRE0_SUB4:0 bits for pre-emption priority 4 bits for subpriority
+      \arg        NVIC_PRIGROUP_PRE1_SUB3:1 bits for pre-emption priority 3 bits for subpriority
+      \arg        NVIC_PRIGROUP_PRE2_SUB2:2 bits for pre-emption priority 2 bits for subpriority
+      \arg        NVIC_PRIGROUP_PRE3_SUB1:3 bits for pre-emption priority 1 bits for subpriority
+      \arg        NVIC_PRIGROUP_PRE4_SUB0:4 bits for pre-emption priority 0 bits for subpriority
+    \param[out] none
+    \retval     none
+*/
+void nvic_priority_group_set(uint32_t nvic_prigroup)
+{
+    /* set the priority group value */
+    SCB->AIRCR = NVIC_AIRCR_VECTKEY_MASK | nvic_prigroup;
+}
+
+/*!
+    \brief      enable NVIC request
+    \param[in]  nvic_irq: the NVIC interrupt request, detailed in IRQn_Type
+    \param[in]  nvic_irq_pre_priority: the pre-emption priority needed to set
+    \param[in]  nvic_irq_sub_priority: the subpriority needed to set
+    \param[out] none
+    \retval     none
+*/
+void nvic_irq_enable(IRQn_Type nvic_irq,
+                     uint8_t nvic_irq_pre_priority,
+                     uint8_t nvic_irq_sub_priority)
+{
+    uint32_t temp_priority = 0x00U, temp_pre = 0x00U, temp_sub = 0x00U;
+
+    /* use the priority group value to get the temp_pre and the temp_sub */
+    switch((SCB->AIRCR) & (uint32_t)0x700U) {
+    case NVIC_PRIGROUP_PRE0_SUB4:
+        temp_pre = 0U;
+        temp_sub = 0x4U;
+        break;
+    case NVIC_PRIGROUP_PRE1_SUB3:
+        temp_pre = 1U;
+        temp_sub = 0x3U;
+        break;
+    case NVIC_PRIGROUP_PRE2_SUB2:
+        temp_pre = 2U;
+        temp_sub = 0x2U;
+        break;
+    case NVIC_PRIGROUP_PRE3_SUB1:
+        temp_pre = 3U;
+        temp_sub = 0x1U;
+        break;
+    case NVIC_PRIGROUP_PRE4_SUB0:
+        temp_pre = 4U;
+        temp_sub = 0x0U;
+        break;
+    default:
+        nvic_priority_group_set(NVIC_PRIGROUP_PRE2_SUB2);
+        temp_pre = 2U;
+        temp_sub = 0x2U;
+        break;
+    }
+
+    /* get the temp_priority to fill the NVIC->IP register */
+    temp_priority = (uint32_t)nvic_irq_pre_priority << (0x4U - temp_pre);
+    temp_priority |= nvic_irq_sub_priority & (0x0FU >> (0x4U - temp_sub));
+    temp_priority = temp_priority << 0x04U;
+    NVIC->IP[nvic_irq] = (uint8_t)temp_priority;
+
+    /* enable the selected IRQ */
+    NVIC->ISER[nvic_irq >> 0x05U] = (uint32_t)0x01U << (nvic_irq & (uint8_t)0x1FU);
+}
+
+/*!
+    \brief      disable NVIC request
+    \param[in]  nvic_irq: the NVIC interrupt request, detailed in IRQn_Type
+    \param[out] none
+    \retval     none
+*/
+void nvic_irq_disable(IRQn_Type nvic_irq)
+{
+    /* disable the selected IRQ.*/
+    NVIC->ICER[nvic_irq >> 0x05U] = (uint32_t)0x01U << (nvic_irq & (uint8_t)0x1FU);
+}
+
+/*!
+    \brief      set the NVIC vector table base address
+    \param[in]  nvic_vict_tab: the RAM or FLASH base address
+                only one parameter can be selected which is shown as below:
+      \arg        NVIC_VECTTAB_RAM: RAM base address
+      \are        NVIC_VECTTAB_FLASH: Flash base address
+    \param[in]  offset: Vector Table offset
+    \param[out] none
+    \retval     none
+*/
+void nvic_vector_table_set(uint32_t nvic_vict_tab, uint32_t offset)
+{
+    SCB->VTOR = nvic_vict_tab | (offset & NVIC_VECTTAB_OFFSET_MASK);
+    __DSB();
+}
+
+/*!
+    \brief      set the state of the low power mode
+    \param[in]  lowpower_mode: the low power mode state
+                only one parameter can be selected which is shown as below:
+      \arg        SCB_LPM_SLEEP_EXIT_ISR: if chose this para, the system always enter low power
+                    mode by exiting from ISR
+      \arg        SCB_LPM_DEEPSLEEP: if chose this para, the system will enter the DEEPSLEEP mode
+      \arg        SCB_LPM_WAKE_BY_ALL_INT: if chose this para, the lowpower mode can be woke up
+                    by all the enable and disable interrupts
+    \param[out] none
+    \retval     none
+*/
+void system_lowpower_set(uint8_t lowpower_mode)
+{
+    SCB->SCR |= (uint32_t)lowpower_mode;
+}
+
+/*!
+    \brief      reset the state of the low power mode
+    \param[in]  lowpower_mode: the low power mode state
+                only one parameter can be selected which is shown as below:
+      \arg        SCB_LPM_SLEEP_EXIT_ISR: if chose this para, the system will exit low power
+                    mode by exiting from ISR
+      \arg        SCB_LPM_DEEPSLEEP: if chose this para, the system will enter the SLEEP mode
+      \arg        SCB_LPM_WAKE_BY_ALL_INT: if chose this para, the lowpower mode only can be
+                    woke up by the enable interrupts
+    \param[out] none
+    \retval     none
+*/
+void system_lowpower_reset(uint8_t lowpower_mode)
+{
+    SCB->SCR &= (~(uint32_t)lowpower_mode);
+}
+
+/*!
+    \brief      set the systick clock source
+    \param[in]  systick_clksource: the systick clock source needed to choose
+                only one parameter can be selected which is shown as below:
+      \arg        SYSTICK_CLKSOURCE_HCLK: systick clock source is from HCLK
+      \arg        SYSTICK_CLKSOURCE_HCLK_DIV8: systick clock source is from HCLK/8
+    \param[out] none
+    \retval     none
+*/
+
+void systick_clksource_set(uint32_t systick_clksource)
+{
+    if(SYSTICK_CLKSOURCE_HCLK == systick_clksource) {
+        /* set the systick clock source from HCLK */
+        SysTick->CTRL |= SYSTICK_CLKSOURCE_HCLK;
+    } else {
+        /* set the systick clock source from HCLK/8 */
+        SysTick->CTRL &= SYSTICK_CLKSOURCE_HCLK_DIV8;
+    }
+}

+ 417 - 0
GD32F3x0/GD32F3x0_standard_peripheral/Source/gd32f3x0_pmu.c

@@ -0,0 +1,417 @@
+/*!
+    \file    gd32f3x0_pmu.c
+    \brief   PMU driver
+
+    \version 2025-01-01, V2.5.0, firmware for GD32F3x0
+*/
+
+/*
+    Copyright (c) 2025, GigaDevice Semiconductor Inc.
+
+    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 of the copyright holder 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 HOLDER 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.
+*/
+
+#include "gd32f3x0_pmu.h"
+
+
+/*!
+    \brief      reset PMU register
+    \param[in]  none
+    \param[out] none
+    \retval     none
+*/
+void pmu_deinit(void)
+{
+    /* reset PMU */
+    rcu_periph_reset_enable(RCU_PMURST);
+    rcu_periph_reset_disable(RCU_PMURST);
+}
+
+/*!
+    \brief      select low voltage detector threshold
+    \param[in]  lvdt_n:
+                only one parameter can be selected which is shown as below:
+      \arg        PMU_LVDT_0: voltage threshold is 2.1V
+      \arg        PMU_LVDT_1: voltage threshold is 2.3V
+      \arg        PMU_LVDT_2: voltage threshold is 2.4V
+      \arg        PMU_LVDT_3: voltage threshold is 2.6V
+      \arg        PMU_LVDT_4: voltage threshold is 2.7V
+      \arg        PMU_LVDT_5: voltage threshold is 2.9V
+      \arg        PMU_LVDT_6: voltage threshold is 3.0V
+      \arg        PMU_LVDT_7: voltage threshold is 3.1V
+    \param[out] none
+    \retval     none
+*/
+void pmu_lvd_select(uint32_t lvdt_n)
+{
+    /* disable LVD */
+    PMU_CTL &= ~PMU_CTL_LVDEN;
+    /* clear LVDT bits */
+    PMU_CTL &= ~PMU_CTL_LVDT;
+    /* set LVDT bits according to lvdt_n */
+    PMU_CTL |= lvdt_n;
+    /* enable LVD */
+    PMU_CTL |= PMU_CTL_LVDEN;
+}
+
+/*!
+    \brief      select LDO output voltage
+                these bits set by software when the main PLL closed
+    \param[in]  ldo_output:
+                only one parameter can be selected which is shown as below:
+      \arg        PMU_LDOVS_LOW: LDO output voltage low mode
+      \arg        PMU_LDOVS_MID: LDO output voltage mid mode
+      \arg        PMU_LDOVS_HIGH: LDO output voltage high mode
+    \param[out] none
+    \retval     none
+*/
+void pmu_ldo_output_select(uint32_t ldo_output)
+{
+    PMU_CTL &= ~PMU_CTL_LDOVS;
+    PMU_CTL |= ldo_output;
+}
+
+/*!
+    \brief      disable PMU lvd
+    \param[in]  none
+    \param[out] none
+    \retval     none
+*/
+void pmu_lvd_disable(void)
+{
+    /* disable LVD */
+    PMU_CTL &= ~PMU_CTL_LVDEN;
+}
+
+/*!
+    \brief      enable low-driver mode in deep-sleep mode
+    \param[in]  none
+    \param[out] none
+    \retval     none
+*/
+void pmu_lowdriver_mode_enable(void)
+{
+    PMU_CTL &= ~PMU_CTL_LDEN;
+    PMU_CTL |= PMU_LOWDRIVER_ENABLE;
+}
+
+/*!
+    \brief      disable low-driver mode in deep-sleep mode
+    \param[in]  none
+    \param[out] none
+    \retval     none
+*/
+void pmu_lowdriver_mode_disable(void)
+{
+    PMU_CTL &= ~PMU_CTL_LDEN;
+    PMU_CTL |= PMU_LOWDRIVER_DISABLE;
+}
+
+/*!
+    \brief      enable high-driver mode
+                this bit set by software only when IRC8M or HXTAL used as system clock
+    \param[in]  none
+    \param[out] none
+    \retval     none
+*/
+void pmu_highdriver_mode_enable(void)
+{
+    PMU_CTL |= PMU_CTL_HDEN;
+}
+
+/*!
+    \brief      disable high-driver mode
+    \param[in]  none
+    \param[out] none
+    \retval     none
+*/
+void pmu_highdriver_mode_disable(void)
+{
+    PMU_CTL &= ~PMU_CTL_HDEN;
+}
+
+/*!
+    \brief      switch high-driver mode
+                this bit set by software only when IRC8M or HXTAL used as system clock
+    \param[in]  highdr_switch:
+                only one parameter can be selected which is shown as below:
+      \arg        PMU_HIGHDR_SWITCH_NONE: disable high-driver mode switch
+      \arg        PMU_HIGHDR_SWITCH_EN: enable high-driver mode switch
+    \param[out] none
+    \retval     none
+*/
+void pmu_highdriver_switch_select(uint32_t highdr_switch)
+{
+    /* wait for HDRF flag to be set */
+    while(SET != pmu_flag_get(PMU_FLAG_HDR)) {
+    }
+    PMU_CTL &= ~PMU_CTL_HDS;
+    PMU_CTL |= highdr_switch;
+}
+
+/*!
+    \brief      low-driver mode when use low power LDO
+    \param[in]  mode:
+                only one parameter can be selected which is shown as below:
+      \arg        PMU_NORMALDR_LOWPWR: normal-driver when use low power LDO
+      \arg        PMU_LOWDR_LOWPWR: low-driver mode enabled when LDEN is 11 and use low power LDO
+    \param[out] none
+    \retval     none
+*/
+void pmu_lowpower_driver_config(uint32_t mode)
+{
+    PMU_CTL &= ~PMU_CTL_LDLP;
+    PMU_CTL |= mode;
+}
+
+/*!
+    \brief      low-driver mode when use normal power LDO
+    \param[in]  mode:
+                only one parameter can be selected which is shown as below:
+      \arg        PMU_NORMALDR_NORMALPWR: normal-driver when use low power LDO
+      \arg        PMU_LOWDR_NORMALPWR: low-driver mode enabled when LDEN is 11 and use low power LDO
+    \param[out] none
+    \retval     none
+*/
+void pmu_normalpower_driver_config(uint32_t mode)
+{
+    PMU_CTL &= ~PMU_CTL_LDNP;
+    PMU_CTL |= mode;
+}
+
+/*!
+    \brief      PMU work at sleep mode
+    \param[in]  sleepmodecmd:
+                only one parameter can be selected which is shown as below:
+      \arg        WFI_CMD: use WFI command
+      \arg        WFE_CMD: use WFE command
+    \param[out] none
+    \retval     none
+*/
+void pmu_to_sleepmode(uint8_t sleepmodecmd)
+{
+    /* clear sleepdeep bit of Cortex-M4 system control register */
+    SCB->SCR &= ~((uint32_t)SCB_SCR_SLEEPDEEP_Msk);
+
+    /* select WFI or WFE command to enter sleep mode */
+    if(WFI_CMD == sleepmodecmd) {
+        __WFI();
+    } else {
+        __WFE();
+    }
+}
+
+/*!
+    \brief      PMU work at deepsleep mode
+    \param[in]  ldo:
+                only one parameter can be selected which is shown as below:
+      \arg        PMU_LDO_NORMAL: LDO operates normally when pmu enter deepsleep mode
+      \arg        PMU_LDO_LOWPOWER: LDO work at low power mode when pmu enter deepsleep mode
+    \param[in]  lowdrive:
+                only one parameter can be selected which is shown as below:
+      \arg        PMU_LOWDRIVER_ENABLE: low-driver mode enable in deep-sleep mode
+      \arg        PMU_LOWDRIVER_DISABLE: low-driver mode disable in deep-sleep mode
+    \param[in]  deepsleepmodecmd:
+                only one parameter can be selected which is shown as below:
+      \arg        WFI_CMD: use WFI command
+      \arg        WFE_CMD: use WFE command
+    \param[out] none
+    \retval     none
+*/
+void pmu_to_deepsleepmode(uint32_t ldo, uint32_t lowdrive, uint8_t deepsleepmodecmd)
+{
+    static uint32_t reg_snap[ 4 ];
+    /* clear stbmod and ldolp bits */
+    PMU_CTL &= ~((uint32_t)(PMU_CTL_STBMOD | PMU_CTL_LDOLP | PMU_CTL_LDEN | PMU_CTL_LDNP | PMU_CTL_LDLP));
+
+    /* set ldolp bit according to pmu_ldo */
+    PMU_CTL |= ldo;
+
+    /* low drive mode config in deep-sleep mode */
+    if(PMU_LOWDRIVER_ENABLE == lowdrive) {
+        if(PMU_LDO_NORMAL == ldo) {
+            PMU_CTL |= (uint32_t)(PMU_CTL_LDEN | PMU_CTL_LDNP);
+        } else {
+            PMU_CTL |= (uint32_t)(PMU_CTL_LDEN | PMU_CTL_LDLP);
+        }
+    }
+
+    /* set sleepdeep bit of Cortex-M4 system control register */
+    SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
+
+    reg_snap[0] = REG32(0xE000E010U);
+    reg_snap[1] = REG32(0xE000E100U);
+    reg_snap[2] = REG32(0xE000E104U);
+    reg_snap[3] = REG32(0xE000E108U);
+
+    REG32(0xE000E010U) &= 0x00010004U;
+    REG32(0xE000E180U)  = 0XB7FFEF19U;
+    REG32(0xE000E184U)  = 0XFFFFFBFFU;
+    REG32(0xE000E188U)  = 0xFFFFFFFFU;
+
+    /* select WFI or WFE command to enter deepsleep mode */
+    if(WFI_CMD == deepsleepmodecmd) {
+        __WFI();
+    } else {
+        __SEV();
+        __WFE();
+        __WFE();
+    }
+
+    REG32(0xE000E010U) = reg_snap[0];
+    REG32(0xE000E100U) = reg_snap[1];
+    REG32(0xE000E104U) = reg_snap[2];
+    REG32(0xE000E108U) = reg_snap[3];
+
+    /* reset sleepdeep bit of Cortex-M4 system control register */
+    SCB->SCR &= ~((uint32_t)SCB_SCR_SLEEPDEEP_Msk);
+}
+
+/*!
+    \brief      pmu work at standby mode
+    \param[in]  none
+    \param[out] none
+    \retval     none
+*/
+void pmu_to_standbymode(void)
+{
+    /* set stbmod bit */
+    PMU_CTL |= PMU_CTL_STBMOD;
+
+    /* reset wakeup flag */
+    PMU_CTL |= PMU_CTL_WURST;
+
+    /* set sleepdeep bit of Cortex-M4 system control register */
+    SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
+
+    REG32( 0xE000E010U ) &= 0x00010004U;
+    REG32( 0xE000E180U ) = 0XFFFFFFFBU;
+    REG32( 0xE000E184U ) = 0XFFFFFFFFU;
+    REG32( 0xE000E188U ) = 0xFFFFFFFFU;
+
+    /* select WFI command to enter standby mode */
+    __WFI();
+}
+
+/*!
+    \brief      enable wakeup pin
+    \param[in]  wakeup_pin:
+                one or more parameters can be selected which are shown as below:
+      \arg        PMU_WAKEUP_PIN0: WKUP Pin 0 (PA0)
+      \arg        PMU_WAKEUP_PIN1: WKUP Pin 1 (PC13)
+      \arg        PMU_WAKEUP_PIN4: WKUP Pin 4 (PC5)
+      \arg        PMU_WAKEUP_PIN5: WKUP Pin 5 (PB5)
+      \arg        PMU_WAKEUP_PIN6: WKUP Pin 6 (PB15)
+    \param[out] none
+    \retval     none
+*/
+void pmu_wakeup_pin_enable(uint32_t wakeup_pin)
+{
+    PMU_CS |= wakeup_pin;
+}
+
+/*!
+    \brief      disable wakeup pin
+    \param[in]  wakeup_pin:
+                one or more parameters can be selected which are shown as below:
+      \arg        PMU_WAKEUP_PIN0: WKUP Pin 0 (PA0)
+      \arg        PMU_WAKEUP_PIN1: WKUP Pin 1 (PC13)
+      \arg        PMU_WAKEUP_PIN4: WKUP Pin 4 (PC5)
+      \arg        PMU_WAKEUP_PIN5: WKUP Pin 5 (PB5)
+      \arg        PMU_WAKEUP_PIN6: WKUP Pin 6 (PB15)
+    \param[out] none
+    \retval     none
+*/
+void pmu_wakeup_pin_disable(uint32_t wakeup_pin)
+{
+    PMU_CS &= ~(wakeup_pin);
+}
+
+/*!
+    \brief      enable backup domain write
+    \param[in]  none
+    \param[out] none
+    \retval     none
+*/
+void pmu_backup_write_enable(void)
+{
+    PMU_CTL |= PMU_CTL_BKPWEN;
+}
+
+/*!
+    \brief      disable backup domain write
+    \param[in]  none
+    \param[out] none
+    \retval     none
+*/
+void pmu_backup_write_disable(void)
+{
+    PMU_CTL &= ~PMU_CTL_BKPWEN;
+}
+
+/*!
+    \brief      get flag state
+    \param[in]  flag:
+                only one parameter can be selected which is shown as below:
+      \arg        PMU_FLAG_WAKEUP: wakeup flag
+      \arg        PMU_FLAG_STANDBY: standby flag
+      \arg        PMU_FLAG_LVD: lvd flag
+      \arg        PMU_FLAG_LDOVSR: LDO voltage select ready flag
+      \arg        PMU_FLAG_HDR: high-driver ready flag
+      \arg        PMU_FLAG_HDSR: high-driver switch ready flag
+      \arg        PMU_FLAG_LDR: low-driver mode ready flag
+    \param[out] none
+    \retval     FlagStatus SET or RESET
+*/
+FlagStatus pmu_flag_get(uint32_t flag)
+{
+    FlagStatus ret_status = RESET;
+
+    if(PMU_CS & flag) {
+        ret_status = SET;
+    }
+
+    return ret_status;
+}
+
+/*!
+    \brief      clear flag bit
+    \param[in]  flag:
+                one or more parameters can be selected which are shown as below:
+      \arg        PMU_FLAG_RESET_WAKEUP: reset wakeup flag
+      \arg        PMU_FLAG_RESET_STANDBY: reset standby flag
+    \param[out] none
+    \retval     none
+*/
+void pmu_flag_clear(uint32_t flag)
+{
+    if(RESET != (flag & PMU_FLAG_RESET_WAKEUP)) {
+        /* reset wakeup flag */
+        PMU_CTL |= PMU_CTL_WURST;
+    }
+    if(RESET != (flag & PMU_FLAG_RESET_STANDBY)) {
+        /* reset standby flag */
+        PMU_CTL |= PMU_CTL_STBRST;
+    }
+}

+ 1210 - 0
GD32F3x0/GD32F3x0_standard_peripheral/Source/gd32f3x0_rcu.c

@@ -0,0 +1,1210 @@
+/*!
+    \file    gd32f3x0_rcu.c
+    \brief   RCU driver
+
+    \version 2025-01-01, V2.5.0, firmware for GD32F3x0
+*/
+
+/*
+    Copyright (c) 2025, GigaDevice Semiconductor Inc.
+
+    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 of the copyright holder 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 HOLDER 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.
+*/
+
+#include "gd32f3x0_rcu.h"
+
+/* define clock source */
+#define SEL_IRC8M                    ((uint32_t)0x00000000U)
+#define SEL_HXTAL                    ((uint32_t)0x00000001U)
+#define SEL_PLL                      ((uint32_t)0x00000002U)
+
+/* define startup timeout count */
+#define OSC_STARTUP_TIMEOUT          ((uint32_t)0x000FFFFFU)
+#define LXTAL_STARTUP_TIMEOUT        ((uint32_t)0x03FFFFFFU)
+
+/*!
+    \brief      deinitialize the RCU
+    \param[in]  none
+    \param[out] none
+    \retval     none
+*/
+void rcu_deinit(void)
+{
+    /* enable IRC8M */
+    RCU_CTL0 |= RCU_CTL0_IRC8MEN;
+    while(0U == (RCU_CTL0 & RCU_CTL0_IRC8MSTB)) {
+    }
+
+    RCU_CFG0 &= ~RCU_CFG0_SCS;
+
+    /* reset CTL register */
+    RCU_CTL0 &= ~(RCU_CTL0_HXTALEN | RCU_CTL0_CKMEN | RCU_CTL0_PLLEN | RCU_CTL0_HXTALBPS);
+    RCU_CTL1 &= ~RCU_CTL1_IRC28MEN;
+
+    /* reset RCU */
+    RCU_CFG0 &= ~(RCU_CFG0_SCS | RCU_CFG0_AHBPSC | RCU_CFG0_APB1PSC | RCU_CFG0_APB2PSC | \
+                  RCU_CFG0_ADCPSC | RCU_CFG0_CKOUTSEL | RCU_CFG0_CKOUTDIV | RCU_CFG0_PLLDV);
+    RCU_CFG0 &= ~(RCU_CFG0_PLLSEL | RCU_CFG0_PLLMF | RCU_CFG0_PLLMF4 | RCU_CFG0_PLLDV);
+#if (defined(GD32F350) || defined(GD32F355) || defined(GD32F370))
+    RCU_CFG0 &= ~(RCU_CFG0_USBFSPSC);
+    RCU_CFG2 &= ~(RCU_CFG2_CECSEL | RCU_CFG2_USBFSPSC2);
+#endif /* GD32F350, GD32F355 and GD32F370 */
+
+    RCU_CFG1 &= ~(RCU_CFG1_PREDV | RCU_CFG1_PLLMF5 | RCU_CFG1_PLLPRESEL);
+    RCU_CFG2 &= ~(RCU_CFG2_USART0SEL | RCU_CFG2_ADCSEL);
+    RCU_CFG2 &= ~RCU_CFG2_IRC28MDIV;
+    RCU_CFG2 &= ~RCU_CFG2_ADCPSC2;
+    RCU_ADDCTL &= ~RCU_ADDCTL_IRC48MEN;
+    RCU_INT = 0x00000000U;
+    RCU_ADDINT = 0x00000000U;
+}
+
+/*!
+    \brief      enable the peripherals clock
+    \param[in]  periph: RCU peripherals, refer to rcu_periph_enum
+                only one parameter can be selected which is shown as below:
+      \arg        RCU_GPIOx (x=A,B,C,D,F): GPIO ports clock
+      \arg        RCU_DMA: DMA clock
+      \arg        RCU_CRC: CRC clock
+      \arg        RCU_TSI: TSI clock
+      \arg        RCU_CFGCMP: CFGCMP clock
+      \arg        RCU_ADC: ADC clock
+      \arg        RCU_TIMERx (x=0,1,2,5,13,14,15,16): TIMER clock (RCU_TIMER5 only for GD32F350)
+      \arg        RCU_SPIx (x=0,1): SPI clock
+      \arg        RCU_USARTx (x=0,1): USART clock
+      \arg        RCU_WWDGT: WWDGT clock
+      \arg        RCU_I2Cx (x=0,1): I2C clock
+      \arg        RCU_USBFS: USBFS clock (only for GD32F350)
+      \arg        RCU_PMU: PMU clock
+      \arg        RCU_DAC: DAC clock (only for GD32F350)
+      \arg        RCU_CEC: CEC clock (only for GD32F350)
+      \arg        RCU_CTC: CTC clock
+      \arg        RCU_RTC: RTC clock
+    \param[out] none
+    \retval     none
+*/
+void rcu_periph_clock_enable(rcu_periph_enum periph)
+{
+    RCU_REG_VAL(periph) |= BIT(RCU_BIT_POS(periph));
+}
+
+/*!
+    \brief      disable the peripherals clock
+    \param[in]  periph: RCU peripherals, refer to rcu_periph_enum
+                only one parameter can be selected which is shown as below:
+      \arg        RCU_GPIOx (x=A,B,C,D,F): GPIO ports clock
+      \arg        RCU_DMA: DMA clock
+      \arg        RCU_CRC: CRC clock
+      \arg        RCU_TSI: TSI clock
+      \arg        RCU_CFGCMP: CFGCMP clock
+      \arg        RCU_ADC: ADC clock
+      \arg        RCU_TIMERx (x=0,1,2,5,13,14,15,16): TIMER clock (RCU_TIMER5 only for GD32F350)
+      \arg        RCU_SPIx (x=0,1): SPI clock
+      \arg        RCU_USARTx (x=0,1): USART clock
+      \arg        RCU_WWDGT: WWDGT clock
+      \arg        RCU_I2Cx (x=0,1): I2C clock
+      \arg        RCU_USBFS: USBFS clock (only for GD32F350)
+      \arg        RCU_PMU: PMU clock
+      \arg        RCU_DAC: DAC clock (only for GD32F350)
+      \arg        RCU_CEC: CEC clock (only for GD32F350)
+      \arg        RCU_CTC: CTC clock
+      \arg        RCU_RTC: RTC clock
+    \param[out] none
+    \retval     none
+*/
+void rcu_periph_clock_disable(rcu_periph_enum periph)
+{
+    RCU_REG_VAL(periph) &= ~BIT(RCU_BIT_POS(periph));
+}
+
+/*!
+    \brief      enable the peripherals clock when sleep mode
+    \param[in]  periph: RCU peripherals, refer to rcu_periph_sleep_enum
+                only one parameter can be selected which is shown as below:
+      \arg        RCU_FMC_SLP: FMC clock
+      \arg        RCU_SRAM_SLP: SRAM clock
+    \param[out] none
+    \retval     none
+*/
+void rcu_periph_clock_sleep_enable(rcu_periph_sleep_enum periph)
+{
+    RCU_REG_VAL(periph) |= BIT(RCU_BIT_POS(periph));
+}
+
+/*!
+    \brief      disable the peripherals clock when sleep mode
+    \param[in]  periph: RCU peripherals, refer to rcu_periph_sleep_enum
+                only one parameter can be selected which is shown as below:
+      \arg        RCU_FMC_SLP: FMC clock
+      \arg        RCU_SRAM_SLP: SRAM clock
+    \param[out] none
+    \retval     none
+*/
+void rcu_periph_clock_sleep_disable(rcu_periph_sleep_enum periph)
+{
+    RCU_REG_VAL(periph) &= ~BIT(RCU_BIT_POS(periph));
+}
+/*!
+    \brief      reset the peripherals
+    \param[in]  periph_reset: RCU peripherals reset, refer to rcu_periph_reset_enum
+                only one parameter can be selected which is shown as below:
+      \arg        RCU_GPIOxRST (x=A,B,C,D,F): reset GPIO ports
+      \arg        RCU_TSIRST: reset TSI
+      \arg        RCU_CFGCMPRST: reset CFGCMP
+      \arg        RCU_ADCRST: reset ADC
+      \arg        RCU_TIMERxRST (x=0,1,2,5,13,14,15,16): reset TIMER (RCU_TIMER5 only for GD32F350)
+      \arg        RCU_SPIxRST (x=0,1): reset SPI
+      \arg        RCU_USARTxRST (x=0,1): reset USART
+      \arg        RCU_WWDGTRST: reset WWDGT
+      \arg        RCU_I2CxRST (x=0,1): reset I2C
+      \arg        RCU_USBFSRST: reset USBFS (only for GD32F350)
+      \arg        RCU_PMURST: reset PMU
+      \arg        RCU_DACRST: reset DAC (only for GD32F350)
+      \arg        RCU_CECRST: reset CEC (only for GD32F350)
+      \arg        RCU_CTCRST: reset CTC
+    \param[out] none
+    \retval     none
+*/
+void rcu_periph_reset_enable(rcu_periph_reset_enum periph_reset)
+{
+    RCU_REG_VAL(periph_reset) |= BIT(RCU_BIT_POS(periph_reset));
+}
+
+/*!
+    \brief      disable reset the peripheral
+    \param[in]  periph_reset: RCU peripherals reset, refer to rcu_periph_reset_enum
+                only one parameter can be selected which is shown as below:
+      \arg        RCU_GPIOxRST (x=A,B,C,D,F): reset GPIO ports
+      \arg        RCU_TSIRST: reset TSI
+      \arg        RCU_CFGCMPRST: reset CFGCMP
+      \arg        RCU_ADCRST: reset ADC
+      \arg        RCU_TIMERxRST (x=0,1,2,5,13,14,15,16): reset TIMER (RCU_TIMER5 only for GD32F350)
+      \arg        RCU_SPIxRST (x=0,1,2): reset SPI
+      \arg        RCU_USARTxRST (x=0,1): reset USART
+      \arg        RCU_WWDGTRST: reset WWDGT
+      \arg        RCU_I2CxRST (x=0,1,2): reset I2C
+      \arg        RCU_USBFSRST: reset USBFS (only for GD32F350)
+      \arg        RCU_PMURST: reset PMU
+      \arg        RCU_DACRST: reset DAC (only for GD32F350)
+      \arg        RCU_CECRST: reset CEC (only for GD32F350)
+      \arg        RCU_CTCRST: reset CTC
+    \param[out] none
+    \retval     none
+*/
+void rcu_periph_reset_disable(rcu_periph_reset_enum periph_reset)
+{
+    RCU_REG_VAL(periph_reset) &= ~BIT(RCU_BIT_POS(periph_reset));
+}
+
+/*!
+    \brief      reset the BKP
+    \param[in]  none
+    \param[out] none
+    \retval     none
+*/
+void rcu_bkp_reset_enable(void)
+{
+    RCU_BDCTL |= RCU_BDCTL_BKPRST;
+}
+
+/*!
+    \brief      disable the BKP reset
+    \param[in]  none
+    \param[out] none
+    \retval     none
+*/
+void rcu_bkp_reset_disable(void)
+{
+    RCU_BDCTL &= ~RCU_BDCTL_BKPRST;
+}
+
+/*!
+    \brief      configure the system clock source
+    \param[in]  ck_sys: system clock source select
+                only one parameter can be selected which is shown as below:
+      \arg        RCU_CKSYSSRC_IRC8M: select CK_IRC8M as the CK_SYS source
+      \arg        RCU_CKSYSSRC_HXTAL: select CK_HXTAL as the CK_SYS source
+      \arg        RCU_CKSYSSRC_PLL: select CK_PLL as the CK_SYS source
+    \param[out] none
+    \retval     none
+*/
+void rcu_system_clock_source_config(uint32_t ck_sys)
+{
+    uint32_t cksys_source = 0U;
+    cksys_source = RCU_CFG0;
+    /* reset the SCS bits and set according to ck_sys */
+    cksys_source &= ~RCU_CFG0_SCS;
+    RCU_CFG0 = (ck_sys | cksys_source);
+}
+
+/*!
+    \brief      get the system clock source
+    \param[in]  none
+    \param[out] none
+    \retval     which clock is selected as CK_SYS source
+                only one parameter can be selected which is shown as below:
+      \arg        RCU_SCSS_IRC8M: select CK_IRC8M as the CK_SYS source
+      \arg        RCU_SCSS_HXTAL: select CK_HXTAL as the CK_SYS source
+      \arg        RCU_SCSS_PLL: select CK_PLL as the CK_SYS source
+*/
+uint32_t rcu_system_clock_source_get(void)
+{
+    return (RCU_CFG0 & RCU_CFG0_SCSS);
+}
+
+/*!
+    \brief      configure the AHB clock prescaler selection
+    \param[in]  ck_ahb: AHB clock prescaler selection
+                only one parameter can be selected which is shown as below:
+      \arg        RCU_AHB_CKSYS_DIVx, x=1, 2, 4, 8, 16, 64, 128, 256, 512
+    \param[out] none
+    \retval     none
+*/
+void rcu_ahb_clock_config(uint32_t ck_ahb)
+{
+    uint32_t ahbpsc = 0U;
+    ahbpsc = RCU_CFG0;
+    /* reset the AHBPSC bits and set according to ck_ahb */
+    ahbpsc &= ~RCU_CFG0_AHBPSC;
+    RCU_CFG0 = (ck_ahb | ahbpsc);
+}
+
+/*!
+    \brief      configure the APB1 clock prescaler selection
+    \param[in]  ck_apb1: APB1 clock prescaler selection
+                only one parameter can be selected which is shown as below:
+      \arg        RCU_APB1_CKAHB_DIV1: select CK_AHB as CK_APB1
+      \arg        RCU_APB1_CKAHB_DIV2: select CK_AHB/2 as CK_APB1
+      \arg        RCU_APB1_CKAHB_DIV4: select CK_AHB/4 as CK_APB1
+      \arg        RCU_APB1_CKAHB_DIV8: select CK_AHB/8 as CK_APB1
+      \arg        RCU_APB1_CKAHB_DIV16: select CK_AHB/16 as CK_APB1
+    \param[out] none
+    \retval     none
+*/
+void rcu_apb1_clock_config(uint32_t ck_apb1)
+{
+    uint32_t apb1psc = 0U;
+    apb1psc = RCU_CFG0;
+    /* reset the APB1PSC and set according to ck_apb1 */
+    apb1psc &= ~RCU_CFG0_APB1PSC;
+    RCU_CFG0 = (ck_apb1 | apb1psc);
+}
+
+/*!
+    \brief      configure the APB2 clock prescaler selection
+    \param[in]  ck_apb2: APB2 clock prescaler selection
+                only one parameter can be selected which is shown as below:
+      \arg        RCU_APB2_CKAHB_DIV1: select CK_AHB as CK_APB2
+      \arg        RCU_APB2_CKAHB_DIV2: select CK_AHB/2 as CK_APB2
+      \arg        RCU_APB2_CKAHB_DIV4: select CK_AHB/4 as CK_APB2
+      \arg        RCU_APB2_CKAHB_DIV8: select CK_AHB/8 as CK_APB2
+      \arg        RCU_APB2_CKAHB_DIV16: select CK_AHB/16 as CK_APB2
+    \param[out] none
+    \retval     none
+*/
+void rcu_apb2_clock_config(uint32_t ck_apb2)
+{
+    uint32_t apb2psc = 0U;
+    apb2psc = RCU_CFG0;
+    /* reset the APB2PSC and set according to ck_apb2 */
+    apb2psc &= ~RCU_CFG0_APB2PSC;
+    RCU_CFG0 = (ck_apb2 | apb2psc);
+}
+
+/*!
+    \brief      configure the ADC clock prescaler selection
+    \param[in]  ck_adc: ADC clock prescaler selection, refer to rcu_adc_clock_enum
+                only one parameter can be selected which is shown as below:
+      \arg        RCU_ADCCK_IRC28M_DIV2: select CK_IRC28M/2 as CK_ADC
+      \arg        RCU_ADCCK_IRC28M: select CK_IRC28M as CK_ADC
+      \arg        RCU_ADCCK_APB2_DIV2: select CK_APB2/2 as CK_ADC
+      \arg        RCU_ADCCK_AHB_DIV3: select CK_AHB/3 as CK_ADC
+      \arg        RCU_ADCCK_APB2_DIV4: select CK_APB2/4 as CK_ADC
+      \arg        RCU_ADCCK_AHB_DIV5: select CK_AHB/5 as CK_ADC
+      \arg        RCU_ADCCK_APB2_DIV6: select CK_APB2/6 as CK_ADC
+      \arg        RCU_ADCCK_AHB_DIV7: select CK_AHB/7 as CK_ADC
+      \arg        RCU_ADCCK_APB2_DIV8: select CK_APB2/8 as CK_ADC
+      \arg        RCU_ADCCK_AHB_DIV9: select CK_AHB/9 as CK_ADC
+    \param[out] none
+    \retval     none
+*/
+void rcu_adc_clock_config(rcu_adc_clock_enum ck_adc)
+{
+    /* reset the ADCPSC, ADCSEL, IRC28MDIV bits */
+    RCU_CFG0 &= ~RCU_CFG0_ADCPSC;
+    RCU_CFG2 &= ~(RCU_CFG2_ADCSEL | RCU_CFG2_IRC28MDIV | RCU_CFG2_ADCPSC2);
+
+    /* set the ADC clock according to ck_adc */
+    switch(ck_adc) {
+    case RCU_ADCCK_IRC28M_DIV2:
+        RCU_CFG2 &= ~RCU_CFG2_IRC28MDIV;
+        RCU_CFG2 &= ~RCU_CFG2_ADCSEL;
+        break;
+    case RCU_ADCCK_IRC28M:
+        RCU_CFG2 |= RCU_CFG2_IRC28MDIV;
+        RCU_CFG2 &= ~RCU_CFG2_ADCSEL;
+        break;
+    case RCU_ADCCK_APB2_DIV2:
+        RCU_CFG0 |= RCU_ADC_CKAPB2_DIV2;
+        RCU_CFG2 |= RCU_CFG2_ADCSEL;
+        break;
+    case RCU_ADCCK_AHB_DIV3:
+        RCU_CFG0 |= RCU_ADC_CKAPB2_DIV2;
+        RCU_CFG2 |= RCU_CFG2_ADCPSC2;
+        RCU_CFG2 |= RCU_CFG2_ADCSEL;
+        break;
+    case RCU_ADCCK_APB2_DIV4:
+        RCU_CFG0 |= RCU_ADC_CKAPB2_DIV4;
+        RCU_CFG2 |= RCU_CFG2_ADCSEL;
+        break;
+    case RCU_ADCCK_AHB_DIV5:
+        RCU_CFG0 |= RCU_ADC_CKAPB2_DIV4;
+        RCU_CFG2 |= RCU_CFG2_ADCPSC2;
+        RCU_CFG2 |= RCU_CFG2_ADCSEL;
+        break;
+    case RCU_ADCCK_APB2_DIV6:
+        RCU_CFG0 |= RCU_ADC_CKAPB2_DIV6;
+        RCU_CFG2 |= RCU_CFG2_ADCSEL;
+        break;
+    case RCU_ADCCK_AHB_DIV7:
+        RCU_CFG0 |= RCU_ADC_CKAPB2_DIV6;
+        RCU_CFG2 |= RCU_CFG2_ADCPSC2;
+        RCU_CFG2 |= RCU_CFG2_ADCSEL;
+        break;
+    case RCU_ADCCK_APB2_DIV8:
+        RCU_CFG0 |= RCU_ADC_CKAPB2_DIV8;
+        RCU_CFG2 |= RCU_CFG2_ADCSEL;
+        break;
+    case RCU_ADCCK_AHB_DIV9:
+        RCU_CFG0 |= RCU_ADC_CKAPB2_DIV8;
+        RCU_CFG2 |= RCU_CFG2_ADCPSC2;
+        RCU_CFG2 |= RCU_CFG2_ADCSEL;
+        break;
+    default:
+        break;
+    }
+}
+
+/*!
+    \brief      configure the USBFS clock prescaler selection
+    \param[in]  ck_usbfs: USBFS clock prescaler selection
+                only one parameter can be selected which is shown as below:
+      \arg        RCU_USBFS_CKPLL_DIV1_5: select CK_PLL/1.5 as CK_USBFS
+      \arg        RCU_USBFS_CKPLL_DIV1: select CK_PLL as CK_USBFS
+      \arg        RCU_USBFS_CKPLL_DIV2_5: select CK_PLL/2.5 as CK_USBFS
+      \arg        RCU_USBFS_CKPLL_DIV2: select CK_PLL/2 as CK_USBFS
+      \arg        RCU_USBFS_CKPLL_DIV3: select CK_PLL/3 as CK_USBFS
+      \arg        RCU_USBFS_CKPLL_DIV3_5: select CK_PLL/3.5 as CK_USBFS
+    \param[out] none
+    \retval     none
+*/
+void rcu_usbfs_clock_config(uint32_t ck_usbfs)
+{
+    /* reset the USBFSPSC bits and set according to ck_usbfs */
+    RCU_CFG0 &= ~RCU_CFG0_USBFSPSC;
+    RCU_CFG2 &= ~RCU_CFG2_USBFSPSC2;
+
+    RCU_CFG0 |= (ck_usbfs & (~RCU_CFG2_USBFSPSC2));
+    RCU_CFG2 |= (ck_usbfs & RCU_CFG2_USBFSPSC2);
+}
+
+/*!
+    \brief      configure the CK_OUT clock source and divider
+    \param[in]  ckout_src: CK_OUT clock source selection
+                only one parameter can be selected which is shown as below:
+      \arg        RCU_CKOUTSRC_NONE: no clock selected
+      \arg        RCU_CKOUTSRC_IRC28M: IRC28M selected
+      \arg        RCU_CKOUTSRC_IRC40K: IRC40K selected
+      \arg        RCU_CKOUTSRC_LXTAL: LXTAL selected
+      \arg        RCU_CKOUTSRC_CKSYS: CKSYS selected
+      \arg        RCU_CKOUTSRC_IRC8M: IRC8M selected
+      \arg        RCU_CKOUTSRC_HXTAL: HXTAL selected
+      \arg        RCU_CKOUTSRC_CKPLL_DIV1: CK_PLL selected
+      \arg        RCU_CKOUTSRC_CKPLL_DIV2: CK_PLL/2 selected
+    \param[in]  ckout_div: CK_OUT divider
+      \arg        RCU_CKOUT_DIVx(x=1,2,4,8,16,32,64,128): CK_OUT is divided by x
+    \param[out] none
+    \retval     none
+*/
+void rcu_ckout_config(uint32_t ckout_src, uint32_t ckout_div)
+{
+    uint32_t ckout = 0U;
+    ckout = RCU_CFG0;
+    /* reset the CKOUTSEL, CKOUTDIV and PLLDV bits and set according to ckout_src and ckout_div */
+    ckout &= ~(RCU_CFG0_CKOUTSEL | RCU_CFG0_CKOUTDIV | RCU_CFG0_PLLDV);
+    RCU_CFG0 = (ckout | ckout_src | ckout_div);
+}
+
+/*!
+    \brief      configure the PLL clock source preselection
+    \param[in]  pll_presel: PLL clock source preselection
+                only one parameter can be selected which is shown as below:
+      \arg        RCU_PLLPRESEL_IRC48M: select IRC48M as PLL preselection clock
+      \arg        RCU_PLLPRESEL_HXTAL: select HXTAL as PLL preselection clock
+    \param[out] none
+    \retval     none
+*/
+void rcu_pll_preselection_config(uint32_t pll_presel)
+{
+    RCU_CFG1 &= ~(RCU_CFG1_PLLPRESEL);
+    RCU_CFG1 |= pll_presel;
+}
+
+/*!
+    \brief      configure the PLL clock source selection and PLL multiply factor
+    \param[in]  pll_src: PLL clock source selection
+                only one parameter can be selected which is shown as below:
+      \arg        RCU_PLLSRC_IRC8M_DIV2: select CK_IRC8M/2 as PLL source clock
+      \arg        RCU_PLLSRC_HXTAL_IRC48M: select HXTAL or IRC48M as PLL source clock
+    \param[in]  pll_mul: PLL multiply factor
+                only one parameter can be selected which is shown as below:
+      \arg        RCU_PLL_MULx(x=2..64): PLL source clock * x
+    \param[out] none
+    \retval     none
+*/
+void rcu_pll_config(uint32_t pll_src, uint32_t pll_mul)
+{
+    RCU_CFG0 &= ~(RCU_CFG0_PLLSEL | RCU_CFG0_PLLMF | RCU_CFG0_PLLMF4);
+    RCU_CFG1 &= ~(RCU_CFG1_PLLMF5);
+    RCU_CFG0 |= (pll_src | (pll_mul & (~RCU_CFG1_PLLMF5)));
+    RCU_CFG1 |= (pll_mul & RCU_CFG1_PLLMF5);
+}
+
+/*!
+    \brief      configure the USART clock source selection
+    \param[in]  ck_usart: USART clock source selection
+                only one parameter can be selected which is shown as below:
+      \arg        RCU_USART0SRC_CKAPB2: CK_USART0 select CK_APB2
+      \arg        RCU_USART0SRC_CKSYS: CK_USART0 select CK_SYS
+      \arg        RCU_USART0SRC_LXTAL: CK_USART0 select CK_LXTAL
+      \arg        RCU_USART0SRC_IRC8M: CK_USART0 select CK_IRC8M
+    \param[out] none
+    \retval     none
+*/
+void rcu_usart_clock_config(uint32_t ck_usart)
+{
+    /* reset the USART0SEL bits and set according to ck_usart */
+    RCU_CFG2 &= ~RCU_CFG2_USART0SEL;
+    RCU_CFG2 |= ck_usart;
+}
+
+/*!
+    \brief      configure the CEC clock source selection
+    \param[in]  ck_cec: CEC clock source selection
+                only one parameter can be selected which is shown as below:
+      \arg        RCU_CECSRC_IRC8M_DIV244: CK_CEC select CK_IRC8M/244
+      \arg        RCU_CECSRC_LXTAL: CK_CEC select CK_LXTAL
+    \param[out] none
+    \retval     none
+*/
+void rcu_cec_clock_config(uint32_t ck_cec)
+{
+    /* reset the CECSEL bit and set according to ck_cec */
+    RCU_CFG2 &= ~RCU_CFG2_CECSEL;
+    RCU_CFG2 |= ck_cec;
+}
+
+/*!
+    \brief      configure the RTC clock source selection
+    \param[in]  rtc_clock_source: RTC clock source selection
+                only one parameter can be selected which is shown as below:
+      \arg        RCU_RTCSRC_NONE: no clock selected
+      \arg        RCU_RTCSRC_LXTAL: CK_LXTAL selected as RTC source clock
+      \arg        RCU_RTCSRC_IRC40K: CK_IRC40K selected as RTC source clock
+      \arg        RCU_RTCSRC_HXTAL_DIV32: CK_HXTAL/32 selected as RTC source clock
+    \param[out] none
+    \retval     none
+*/
+void rcu_rtc_clock_config(uint32_t rtc_clock_source)
+{
+    /* reset the RTCSRC bits and set according to rtc_clock_source */
+    RCU_BDCTL &= ~RCU_BDCTL_RTCSRC;
+    RCU_BDCTL |= rtc_clock_source;
+}
+
+/*!
+    \brief      configure the CK48M clock source selection
+    \param[in]  ck48m_clock_source: CK48M clock source selection
+                only one parameter can be selected which is shown as below:
+      \arg        RCU_CK48MSRC_PLL48M: CK_PLL48M selected as CK48M source clock
+      \arg        RCU_CK48MSRC_IRC48M: CK_IRC48M selected as CK48M source clock
+    \param[out] none
+    \retval     none
+*/
+void rcu_ck48m_clock_config(uint32_t ck48m_clock_source)
+{
+    uint32_t reg;
+
+    reg = RCU_ADDCTL;
+    /* reset the CK48MSEL bit and set according to ck48m_clock_source */
+    reg &= ~RCU_ADDCTL_CK48MSEL;
+    RCU_ADDCTL = (reg | ck48m_clock_source);
+}
+
+/*!
+    \brief      configure the HXTAL divider used as input of PLL
+    \param[in]  hxtal_prediv: HXTAL divider used as input of PLL
+                only one parameter can be selected which is shown as below:
+      \arg        RCU_PLL_PREDVx(x=1..16): HXTAL or IRC48M divided x used as input of PLL
+    \param[out] none
+    \retval     none
+*/
+void rcu_hxtal_prediv_config(uint32_t hxtal_prediv)
+{
+    uint32_t prediv = 0U;
+    prediv = RCU_CFG1;
+    /* reset the HXTALPREDV bits and set according to hxtal_prediv */
+    prediv &= ~RCU_CFG1_PREDV;
+    RCU_CFG1 = (prediv | hxtal_prediv);
+}
+
+/*!
+    \brief      configure the LXTAL drive capability
+    \param[in]  lxtal_dricap: drive capability of LXTAL
+                only one parameter can be selected which is shown as below:
+      \arg        RCU_LXTAL_LOWDRI: lower driving capability
+      \arg        RCU_LXTAL_MED_LOWDRI: medium low driving capability
+      \arg        RCU_LXTAL_MED_HIGHDRI: medium high driving capability
+      \arg        RCU_LXTAL_HIGHDRI: higher driving capability
+    \param[out] none
+    \retval     none
+*/
+void rcu_lxtal_drive_capability_config(uint32_t lxtal_dricap)
+{
+    /* reset the LXTALDRI bits and set according to lxtal_dricap */
+    RCU_BDCTL &= ~RCU_BDCTL_LXTALDRI;
+    RCU_BDCTL |= lxtal_dricap;
+}
+
+/*!
+    \brief      get the clock stabilization and periphral reset flags
+    \param[in]  flag: the clock stabilization and periphral reset flags, refer to rcu_flag_enum
+                only one parameter can be selected which is shown as below:
+      \arg        RCU_FLAG_IRC40KSTB: IRC40K stabilization flag
+      \arg        RCU_FLAG_LXTALSTB: LXTAL stabilization flag
+      \arg        RCU_FLAG_IRC8MSTB: IRC8M stabilization flag
+      \arg        RCU_FLAG_HXTALSTB: HXTAL stabilization flag
+      \arg        RCU_FLAG_PLLSTB: PLL stabilization flag
+      \arg        RCU_FLAG_IRC28MSTB: IRC28M stabilization flag
+      \arg        RCU_FLAG_IRC48MSTB: IRC48M stabilization flag
+      \arg        RCU_FLAG_V12RST: V12 domain power reset flag
+      \arg        RCU_FLAG_OBLRST: option byte loader reset flag
+      \arg        RCU_FLAG_EPRST: external pin reset flag
+      \arg        RCU_FLAG_PORRST: power reset flag
+      \arg        RCU_FLAG_SWRST: software reset flag
+      \arg        RCU_FLAG_FWDGTRST: free watchdog timer reset flag
+      \arg        RCU_FLAG_WWDGTRST: window watchdog timer reset flag
+      \arg        RCU_FLAG_LPRST: low-power reset flag
+    \param[out] none
+    \retval     FlagStatus: SET or RESET
+*/
+FlagStatus rcu_flag_get(rcu_flag_enum flag)
+{
+    if(RESET != (RCU_REG_VAL(flag) & BIT(RCU_BIT_POS(flag)))) {
+        return SET;
+    } else {
+        return RESET;
+    }
+}
+
+/*!
+    \brief      clear the reset flag
+    \param[in]  none
+    \param[out] none
+    \retval     none
+*/
+void rcu_all_reset_flag_clear(void)
+{
+    RCU_RSTSCK |= RCU_RSTSCK_RSTFC;
+}
+
+/*!
+    \brief      get the clock stabilization interrupt and ckm flags
+    \param[in]  int_flag: interrupt and ckm flags, refer to rcu_int_flag_enum
+                only one parameter can be selected which is shown as below:
+      \arg        RCU_INT_FLAG_IRC40KSTB: IRC40K stabilization interrupt flag
+      \arg        RCU_INT_FLAG_LXTALSTB: LXTAL stabilization interrupt flag
+      \arg        RCU_INT_FLAG_IRC8MSTB: IRC8M stabilization interrupt flag
+      \arg        RCU_INT_FLAG_HXTALSTB: HXTAL stabilization interrupt flag
+      \arg        RCU_INT_FLAG_PLLSTB: PLL stabilization interrupt flag
+      \arg        RCU_INT_FLAG_IRC28MSTB: IRC28M stabilization interrupt flag
+      \arg        RCU_INT_FLAG_IRC48MSTB: IRC48M stabilization interrupt flag
+      \arg        RCU_INT_FLAG_CKM: HXTAL clock stuck interrupt flag
+    \param[out] none
+    \retval     FlagStatus: SET or RESET
+*/
+FlagStatus rcu_interrupt_flag_get(rcu_int_flag_enum int_flag)
+{
+    if(RESET != (RCU_REG_VAL(int_flag) & BIT(RCU_BIT_POS(int_flag)))) {
+        return SET;
+    } else {
+        return RESET;
+    }
+}
+
+/*!
+    \brief      clear the interrupt flags
+    \param[in]  int_flag_clear: clock stabilization and stuck interrupt flags clear, refer to rcu_int_flag_clear_enum
+                only one parameter can be selected which is shown as below:
+      \arg        RCU_INT_FLAG_IRC40KSTB_CLR: IRC40K stabilization interrupt flag clear
+      \arg        RCU_INT_FLAG_LXTALSTB_CLR: LXTAL stabilization interrupt flag clear
+      \arg        RCU_INT_FLAG_IRC8MSTB_CLR: IRC8M stabilization interrupt flag clear
+      \arg        RCU_INT_FLAG_HXTALSTB_CLR: HXTAL stabilization interrupt flag clear
+      \arg        RCU_INT_FLAG_PLLSTB_CLR: PLL stabilization interrupt flag clear
+      \arg        RCU_INT_FLAG_IRC28MSTB_CLR: IRC28M stabilization interrupt flag clear
+      \arg        RCU_INT_FLAG_IRC48MSTB_CLR: IRC48M stabilization interrupt flag clear
+      \arg        RCU_INT_FLAG_CKM_CLR: clock stuck interrupt flag clear
+    \param[out] none
+    \retval     none
+*/
+void rcu_interrupt_flag_clear(rcu_int_flag_clear_enum int_flag_clear)
+{
+    RCU_REG_VAL(int_flag_clear) |= BIT(RCU_BIT_POS(int_flag_clear));
+}
+
+/*!
+    \brief      enable the stabilization interrupt
+    \param[in]  stab_int: clock stabilization interrupt, refer to rcu_int_enum
+                only one parameter can be selected which is shown as below:
+      \arg        RCU_INT_IRC40KSTB: IRC40K stabilization interrupt enable
+      \arg        RCU_INT_LXTALSTB: LXTAL stabilization interrupt enable
+      \arg        RCU_INT_IRC8MSTB: IRC8M stabilization interrupt enable
+      \arg        RCU_INT_HXTALSTB: HXTAL stabilization interrupt enable
+      \arg        RCU_INT_PLLSTB: PLL stabilization interrupt enable
+      \arg        RCU_INT_IRC28MSTB: IRC28M stabilization interrupt enable
+      \arg        RCU_INT_IRC48MSTB: IRC48M stabilization interrupt enable
+    \param[out] none
+    \retval     none
+*/
+void rcu_interrupt_enable(rcu_int_enum stab_int)
+{
+    RCU_REG_VAL(stab_int) |= BIT(RCU_BIT_POS(stab_int));
+}
+
+
+/*!
+    \brief      disable the stabilization interrupt
+    \param[in]  stab_int: clock stabilization interrupt, refer to rcu_int_enum
+                only one parameter can be selected which is shown as below:
+      \arg        RCU_INT_IRC40KSTB: IRC40K stabilization interrupt disable
+      \arg        RCU_INT_LXTALSTB: LXTAL stabilization interrupt disable
+      \arg        RCU_INT_IRC8MSTB: IRC8M stabilization interrupt disable
+      \arg        RCU_INT_HXTALSTB: HXTAL stabilization interrupt disable
+      \arg        RCU_INT_PLLSTB: PLL stabilization interrupt disable
+      \arg        RCU_INT_IRC28MSTB: IRC28M stabilization interrupt disable
+      \arg        RCU_INT_IRC48MSTB: IRC48M stabilization interrupt disable
+    \param[out] none
+    \retval     none
+*/
+void rcu_interrupt_disable(rcu_int_enum stab_int)
+{
+    RCU_REG_VAL(stab_int) &= ~BIT(RCU_BIT_POS(stab_int));
+}
+
+/*!
+    \brief      wait until oscillator stabilization flags is SET
+    \param[in]  osci: oscillator types, refer to rcu_osci_type_enum
+                only one parameter can be selected which is shown as below:
+      \arg        RCU_HXTAL: HXTAL
+      \arg        RCU_LXTAL: LXTAL
+      \arg        RCU_IRC8M: IRC8M
+      \arg        RCU_IRC28M: IRC28M
+      \arg        RCU_IRC48M: IRC48M
+      \arg        RCU_IRC40K: IRC40K
+      \arg        RCU_PLL_CK: PLL
+    \param[out] none
+    \retval     ErrStatus: SUCCESS or ERROR
+*/
+ErrStatus rcu_osci_stab_wait(rcu_osci_type_enum osci)
+{
+    uint32_t stb_cnt = 0U;
+    ErrStatus reval = ERROR;
+    FlagStatus osci_stat = RESET;
+    switch(osci) {
+    case RCU_HXTAL:
+        /* wait until HXTAL is stabilization and osci_stat is not more than timeout */
+        while((RESET == osci_stat) && (HXTAL_STARTUP_TIMEOUT != stb_cnt)) {
+            osci_stat = rcu_flag_get(RCU_FLAG_HXTALSTB);
+            stb_cnt++;
+        }
+        if(RESET != rcu_flag_get(RCU_FLAG_HXTALSTB)) {
+            reval = SUCCESS;
+        }
+        break;
+    /* wait LXTAL stable */
+    case RCU_LXTAL:
+        while((RESET == osci_stat) && (LXTAL_STARTUP_TIMEOUT != stb_cnt)) {
+            osci_stat = rcu_flag_get(RCU_FLAG_LXTALSTB);
+            stb_cnt++;
+        }
+
+        /* check whether flag is set or not */
+        if(RESET != rcu_flag_get(RCU_FLAG_LXTALSTB)) {
+            reval = SUCCESS;
+        }
+        break;
+
+    /* wait IRC8M stable */
+    case RCU_IRC8M:
+        while((RESET == osci_stat) && (IRC8M_STARTUP_TIMEOUT != stb_cnt)) {
+            osci_stat = rcu_flag_get(RCU_FLAG_IRC8MSTB);
+            stb_cnt++;
+        }
+
+        /* check whether flag is set or not */
+        if(RESET != rcu_flag_get(RCU_FLAG_IRC8MSTB)) {
+            reval = SUCCESS;
+        }
+        break;
+
+    /* wait IRC28M stable */
+    case RCU_IRC28M:
+        while((RESET == osci_stat) && (OSC_STARTUP_TIMEOUT != stb_cnt)) {
+            osci_stat = rcu_flag_get(RCU_FLAG_IRC28MSTB);
+            stb_cnt++;
+        }
+
+        /* check whether flag is set or not */
+        if(RESET != rcu_flag_get(RCU_FLAG_IRC28MSTB)) {
+            reval = SUCCESS;
+        }
+        break;
+    /* wait IRC48M stable */
+    case RCU_IRC48M:
+        while((RESET == osci_stat) && (OSC_STARTUP_TIMEOUT != stb_cnt)) {
+            osci_stat = rcu_flag_get(RCU_FLAG_IRC48MSTB);
+            stb_cnt++;
+        }
+
+        /* check whether flag is set or not */
+        if(RESET != rcu_flag_get(RCU_FLAG_IRC48MSTB)) {
+            reval = SUCCESS;
+        }
+        break;
+
+    /* wait IRC40K stable */
+    case RCU_IRC40K:
+        while((RESET == osci_stat) && (OSC_STARTUP_TIMEOUT != stb_cnt)) {
+            osci_stat = rcu_flag_get(RCU_FLAG_IRC40KSTB);
+            stb_cnt++;
+        }
+
+        /* check whether flag is set or not */
+        if(RESET != rcu_flag_get(RCU_FLAG_IRC40KSTB)) {
+            reval = SUCCESS;
+        }
+        break;
+
+    /* wait PLL stable */
+    case RCU_PLL_CK:
+        while((RESET == osci_stat) && (OSC_STARTUP_TIMEOUT != stb_cnt)) {
+            osci_stat = rcu_flag_get(RCU_FLAG_PLLSTB);
+            stb_cnt++;
+        }
+
+        /* check whether flag is set or not */
+        if(RESET != rcu_flag_get(RCU_FLAG_PLLSTB)) {
+            reval = SUCCESS;
+        }
+        break;
+
+    default:
+        break;
+    }
+    /* return value */
+    return reval;
+}
+
+/*!
+    \brief      turn on the oscillator
+    \param[in]  osci: oscillator types, refer to rcu_osci_type_enum
+                only one parameter can be selected which is shown as below:
+      \arg        RCU_HXTAL: HXTAL
+      \arg        RCU_LXTAL: LXTAL
+      \arg        RCU_IRC8M: IRC8M
+      \arg        RCU_IRC28M: IRC28M
+      \arg        RCU_IRC48M: IRC48M
+      \arg        RCU_IRC40K: IRC40K
+      \arg        RCU_PLL_CK: PLL
+    \param[out] none
+    \retval     none
+*/
+void rcu_osci_on(rcu_osci_type_enum osci)
+{
+    RCU_REG_VAL(osci) |= BIT(RCU_BIT_POS(osci));
+}
+
+/*!
+    \brief      turn off the oscillator
+    \param[in]  osci: oscillator types, refer to rcu_osci_type_enum
+                only one parameter can be selected which is shown as below:
+      \arg        RCU_HXTAL: HXTAL
+      \arg        RCU_LXTAL: LXTAL
+      \arg        RCU_IRC8M: IRC8M
+      \arg        RCU_IRC28M: IRC28M
+      \arg        RCU_IRC48M: IRC48M
+      \arg        RCU_IRC40K: IRC40K
+      \arg        RCU_PLL_CK: PLL
+    \param[out] none
+    \retval     none
+*/
+void rcu_osci_off(rcu_osci_type_enum osci)
+{
+    RCU_REG_VAL(osci) &= ~BIT(RCU_BIT_POS(osci));
+}
+
+/*!
+    \brief      enable the oscillator bypass mode, HXTALEN or LXTALEN must be reset before it
+    \param[in]  osci: oscillator types, refer to rcu_osci_type_enum
+                only one parameter can be selected which is shown as below:
+      \arg        RCU_HXTAL: HXTAL
+      \arg        RCU_LXTAL: LXTAL
+    \param[out] none
+    \retval     none
+*/
+void rcu_osci_bypass_mode_enable(rcu_osci_type_enum osci)
+{
+    uint32_t reg;
+    switch(osci) {
+    case RCU_HXTAL:
+        /* HXTALEN must be reset before enable the oscillator bypass mode */
+        reg = RCU_CTL0;
+        RCU_CTL0 &= ~RCU_CTL0_HXTALEN;
+        RCU_CTL0 = (reg | RCU_CTL0_HXTALBPS);
+        break;
+    case RCU_LXTAL:
+        /* LXTALEN must be reset before enable the oscillator bypass mode */
+        reg = RCU_BDCTL;
+        RCU_BDCTL &= ~RCU_BDCTL_LXTALEN;
+        RCU_BDCTL = (reg | RCU_BDCTL_LXTALBPS);
+        break;
+    case RCU_IRC8M:
+    case RCU_IRC28M:
+    case RCU_IRC48M:
+    case RCU_IRC40K:
+    case RCU_PLL_CK:
+        break;
+    default:
+        break;
+    }
+}
+
+/*!
+    \brief      disable the oscillator bypass mode, HXTALEN or LXTALEN must be reset before it
+    \param[in]  osci: oscillator types, refer to rcu_osci_type_enum
+                only one parameter can be selected which is shown as below:
+      \arg        RCU_HXTAL: HXTAL
+      \arg        RCU_LXTAL: LXTAL
+    \param[out] none
+    \retval     none
+*/
+void rcu_osci_bypass_mode_disable(rcu_osci_type_enum osci)
+{
+    uint32_t reg;
+    switch(osci) {
+    case RCU_HXTAL:
+        /* HXTALEN must be reset before disable the oscillator bypass mode */
+        reg = RCU_CTL0;
+        RCU_CTL0 &= ~RCU_CTL0_HXTALEN;
+        RCU_CTL0 = (reg & (~RCU_CTL0_HXTALBPS));
+        break;
+    case RCU_LXTAL:
+        /* LXTALEN must be reset before disable the oscillator bypass mode */
+        reg = RCU_BDCTL;
+        RCU_BDCTL &= ~RCU_BDCTL_LXTALEN;
+        RCU_BDCTL = (reg & (~RCU_BDCTL_LXTALBPS));
+        break;
+    case RCU_IRC8M:
+    case RCU_IRC28M:
+    case RCU_IRC48M:
+    case RCU_IRC40K:
+    case RCU_PLL_CK:
+        break;
+    default:
+        break;
+    }
+}
+
+/*!
+    \brief      enable the HXTAL clock monitor
+    \param[in]  none
+    \param[out] none
+    \retval     none
+*/
+void rcu_hxtal_clock_monitor_enable(void)
+{
+    RCU_CTL0 |= RCU_CTL0_CKMEN;
+}
+
+/*!
+    \brief      disable the HXTAL clock monitor
+    \param[in]  none
+    \param[out] none
+    \retval     none
+*/
+void rcu_hxtal_clock_monitor_disable(void)
+{
+    RCU_CTL0 &= ~RCU_CTL0_CKMEN;
+}
+
+/*!
+    \brief      set the IRC8M adjust value
+    \param[in]  irc8m_adjval: IRC8M adjust value, must be between 0 and 0x1F
+    \param[out] none
+    \retval     none
+*/
+void rcu_irc8m_adjust_value_set(uint8_t irc8m_adjval)
+{
+    uint32_t adjust = 0U;
+    adjust = RCU_CTL0;
+    /* reset the IRC8MADJ bits and set according to irc8m_adjval */
+    adjust &= ~RCU_CTL0_IRC8MADJ;
+    RCU_CTL0 = (adjust | (((uint32_t)irc8m_adjval) << 3));
+}
+
+/*!
+    \brief      set the IRC28M adjust value
+    \param[in]  irc28m_adjval: IRC28M adjust value, must be between 0 and 0x1F
+    \param[out] none
+    \retval     none
+*/
+void rcu_irc28m_adjust_value_set(uint8_t irc28m_adjval)
+{
+    uint32_t adjust = 0U;
+    adjust = RCU_CTL1;
+    /* reset the IRC28MADJ bits and set according to irc28m_adjval */
+    adjust &= ~RCU_CTL1_IRC28MADJ;
+    RCU_CTL1 = (adjust | (((uint32_t)irc28m_adjval) << 3));
+}
+
+/*!
+    \brief      unlock the voltage key
+    \param[in]  none
+    \param[out] none
+    \retval     none
+*/
+void rcu_voltage_key_unlock(void)
+{
+    /* reset the KEY bits and set 0x1A2B3C4D */
+    RCU_VKEY &= ~RCU_VKEY_KEY;
+    RCU_VKEY |= RCU_VKEY_UNLOCK;
+}
+
+/*!
+    \brief      set voltage in deep sleep mode
+    \param[in]  dsvol: deep sleep mode voltage
+                only one parameter can be selected which is shown as below:
+      \arg        RCU_DEEPSLEEP_V_0: the core voltage is default value
+      \arg        RCU_DEEPSLEEP_V_1: the core voltage is (default value-0.1)V (customers are not recommended to use it)
+      \arg        RCU_DEEPSLEEP_V_2: the core voltage is (default value-0.2)V (customers are not recommended to use it)
+      \arg        RCU_DEEPSLEEP_V_3: the core voltage is (default value-0.3)V (customers are not recommended to use it)
+    \param[out] none
+    \retval     none
+*/
+void rcu_deepsleep_voltage_set(uint32_t dsvol)
+{
+    /* reset the DSLPVS bits and set according to dsvol */
+    RCU_DSV &= ~RCU_DSV_DSLPVS;
+    RCU_DSV |= dsvol;
+}
+
+/*!
+    \brief      get the system clock, bus and peripheral clock frequency
+    \param[in]  clock: the clock frequency which to get
+                only one parameter can be selected which is shown as below:
+      \arg        CK_SYS: system clock frequency
+      \arg        CK_AHB: AHB clock frequency
+      \arg        CK_APB1: APB1 clock frequency
+      \arg        CK_APB2: APB2 clock frequency
+      \arg        CK_ADC: ADC clock frequency
+      \arg        CK_CEC: CEC clock frequency
+      \arg        CK_USART: USART clock frequency
+    \param[out] none
+    \retval     clock frequency of system, AHB, APB1, APB2, ADC, CEC or USRAT
+*/
+uint32_t rcu_clock_freq_get(rcu_clock_freq_enum clock)
+{
+    uint32_t sws = 0U, adcps = 0U, adcps2 = 0U, ck_freq = 0U;
+    uint32_t cksys_freq = 0U, ahb_freq = 0U, apb1_freq = 0U, apb2_freq = 0U;
+    uint32_t adc_freq = 0U, cec_freq = 0U, usart_freq = 0U;
+    uint32_t pllmf = 0U, pllmf4 = 0U, pllmf5 = 0U, pllsel = 0U, pllpresel = 0U, prediv = 0U, idx = 0U, clk_exp = 0U;
+    /* exponent of AHB, APB1 and APB2 clock divider */
+    const uint8_t ahb_exp[16] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9};
+    const uint8_t apb1_exp[8] = {0, 0, 0, 0, 1, 2, 3, 4};
+    const uint8_t apb2_exp[8] = {0, 0, 0, 0, 1, 2, 3, 4};
+
+    sws = GET_BITS(RCU_CFG0, 2, 3);
+    switch(sws) {
+    /* IRC8M is selected as CK_SYS */
+    case SEL_IRC8M:
+        cksys_freq = IRC8M_VALUE;
+        break;
+    /* HXTAL is selected as CK_SYS */
+    case SEL_HXTAL:
+        cksys_freq = HXTAL_VALUE;
+        break;
+    /* PLL is selected as CK_SYS */
+    case SEL_PLL:
+        /* get the value of PLLMF[3:0] */
+        pllmf = GET_BITS(RCU_CFG0, 18, 21);
+        pllmf4 = GET_BITS(RCU_CFG0, 27, 27);
+        pllmf5 = GET_BITS(RCU_CFG1, 31, 31);
+        /* high 16 bits */
+        /* high 16 bits */
+        if((0U == pllmf4) && (0U == pllmf5)) {
+            pllmf += 2U;
+        }
+        if((1U == pllmf4) && (0U == pllmf5)) {
+            pllmf += 17U;
+        }
+        if((0U == pllmf4) && (1U == pllmf5)) {
+            pllmf += 33U;
+        }
+        if((1U == pllmf4) && (1U == pllmf5)) {
+            pllmf += 49U;
+        }
+
+        /* PLL clock source selection, HXTAL or IRC48M or IRC8M/2 */
+        pllsel = GET_BITS(RCU_CFG0, 16, 16);
+        pllpresel = GET_BITS(RCU_CFG1, 30, 30);
+        if(0U != pllsel) {
+            prediv = (GET_BITS(RCU_CFG1, 0, 3) + 1U);
+            if(0U == pllpresel) {
+                cksys_freq = (HXTAL_VALUE / prediv) * pllmf;
+            } else {
+                cksys_freq = (IRC48M_VALUE / prediv) * pllmf;
+            }
+        } else {
+            cksys_freq = (IRC8M_VALUE >> 1) * pllmf;
+        }
+        break;
+    /* IRC8M is selected as CK_SYS */
+    default:
+        cksys_freq = IRC8M_VALUE;
+        break;
+    }
+    /* calculate AHB clock frequency */
+    idx = GET_BITS(RCU_CFG0, 4, 7);
+    clk_exp = ahb_exp[idx];
+    ahb_freq = cksys_freq >> clk_exp;
+
+    /* calculate APB1 clock frequency */
+    idx = GET_BITS(RCU_CFG0, 8, 10);
+    clk_exp = apb1_exp[idx];
+    apb1_freq = ahb_freq >> clk_exp;
+
+    /* calculate APB2 clock frequency */
+    idx = GET_BITS(RCU_CFG0, 11, 13);
+    clk_exp = apb2_exp[idx];
+    apb2_freq = ahb_freq >> clk_exp;
+
+    /* return the clocks frequency */
+    switch(clock) {
+    case CK_SYS:
+        ck_freq = cksys_freq;
+        break;
+    case CK_AHB:
+        ck_freq = ahb_freq;
+        break;
+    case CK_APB1:
+        ck_freq = apb1_freq;
+        break;
+    case CK_APB2:
+        ck_freq = apb2_freq;
+        break;
+    case CK_ADC:
+        /* calculate ADC clock frequency */
+        if(RCU_ADCSRC_AHB_APB2DIV != (RCU_CFG2 & RCU_CFG2_ADCSEL)) {
+            if(RCU_ADC_IRC28M_DIV1 != (RCU_CFG2 & RCU_CFG2_IRC28MDIV)) {
+                adc_freq = IRC28M_VALUE >> 1;
+            } else {
+                adc_freq = IRC28M_VALUE;
+            }
+        } else {
+            /* ADC clock select CK_APB2 divided by 2/4/6/8 or CK_AHB divided by 3/5/7/9 */
+            adcps = GET_BITS(RCU_CFG0, 14, 15);
+            adcps2 = GET_BITS(RCU_CFG2, 31, 31);
+            switch(adcps) {
+            case 0:
+                if(0U == adcps2) {
+                    adc_freq = apb2_freq / 2U;
+                } else {
+                    adc_freq = ahb_freq / 3U;
+                }
+                break;
+            case 1:
+                if(0U == adcps2) {
+                    adc_freq = apb2_freq / 4U;
+                } else {
+                    adc_freq = ahb_freq / 5U;
+                }
+                break;
+            case 2:
+                if(0U == adcps2) {
+                    adc_freq = apb2_freq / 6U;
+                } else {
+                    adc_freq = ahb_freq / 7U;
+                }
+                break;
+            case 3:
+                if(0U == adcps2) {
+                    adc_freq = apb2_freq / 8U;
+                } else {
+                    adc_freq = ahb_freq / 9U;
+                }
+                break;
+            default:
+                break;
+            }
+        }
+        ck_freq = adc_freq;
+        break;
+    case CK_CEC:
+        /* calculate CEC clock frequency */
+        if(RCU_CECSRC_LXTAL != (RCU_CFG2 & RCU_CFG2_CECSEL)) {
+            cec_freq = IRC8M_VALUE / 244U;
+        } else {
+            cec_freq = LXTAL_VALUE;
+        }
+        ck_freq = cec_freq;
+        break;
+    case CK_USART:
+        /* calculate USART clock frequency */
+        if(RCU_USART0SRC_CKAPB2 == (RCU_CFG2 & RCU_CFG2_USART0SEL)) {
+            usart_freq = apb2_freq;
+        } else if(RCU_USART0SRC_CKSYS == (RCU_CFG2 & RCU_CFG2_USART0SEL)) {
+            usart_freq = cksys_freq;
+        } else if(RCU_USART0SRC_LXTAL == (RCU_CFG2 & RCU_CFG2_USART0SEL)) {
+            usart_freq = LXTAL_VALUE;
+        } else if(RCU_USART0SRC_IRC8M == (RCU_CFG2 & RCU_CFG2_USART0SEL)) {
+            usart_freq = IRC8M_VALUE;
+        } else {
+        }
+        ck_freq = usart_freq;
+        break;
+    default:
+        break;
+    }
+    return ck_freq;
+}

+ 962 - 0
GD32F3x0/GD32F3x0_standard_peripheral/Source/gd32f3x0_rtc.c

@@ -0,0 +1,962 @@
+/*!
+    \file    gd32f3x0_rtc.c
+    \brief   RTC driver
+
+    \version 2025-01-01, V2.5.0, firmware for GD32F3x0
+*/
+
+/*
+    Copyright (c) 2025, GigaDevice Semiconductor Inc.
+
+    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 of the copyright holder 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 HOLDER 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.
+*/
+
+#include "gd32f3x0_rtc.h"
+
+/*!
+    \brief      reset most of the RTC registers
+    \param[in]  none
+    \param[out] none
+    \retval     ErrStatus: ERROR or SUCCESS
+*/
+ErrStatus rtc_deinit(void)
+{
+    ErrStatus error_status = ERROR;
+
+    /* RTC_TAMP register is not under write protection */
+    RTC_TAMP = RTC_REGISTER_RESET;
+
+    /* disable the write protection */
+    RTC_WPK = RTC_UNLOCK_KEY1;
+    RTC_WPK = RTC_UNLOCK_KEY2;
+
+    /* reset RTC_CTL register, this can be done without the init mode */
+    RTC_CTL &= RTC_REGISTER_RESET;
+
+    /* enter init mode */
+    error_status = rtc_init_mode_enter();
+
+    if(ERROR != error_status) {
+        /* before reset RTC_TIME and RTC_DATE, BPSHAD bit in RTC_CTL should be reset as the condition.
+           in order to read calendar from shadow register, not the real registers being reset */
+        RTC_TIME = RTC_REGISTER_RESET;
+        RTC_DATE = RTC_DATE_RESET;
+
+        RTC_PSC = RTC_PSC_RESET;
+
+        /* reset RTC_STAT register, also exit init mode.
+           at the same time, RTC_STAT_SOPF bit is reset, as the condition to reset RTC_SHIFTCTL register later */
+        RTC_STAT = RTC_STAT_RESET;
+
+        /* to write RTC_ALRM0SS register, ALRM0EN bit in RTC_CTL register should be reset as the condition */
+        RTC_ALRM0TD = RTC_REGISTER_RESET;
+        RTC_ALRM0SS = RTC_REGISTER_RESET;
+
+        /* reset RTC_SHIFTCTL and RTC_HRFC register, this can be done without the init mode */
+        RTC_SHIFTCTL = RTC_REGISTER_RESET;
+        RTC_HRFC = RTC_REGISTER_RESET;
+
+        error_status = rtc_register_sync_wait();
+    }
+
+    /* enable the write protection */
+    RTC_WPK = RTC_LOCK_KEY;
+
+    return error_status;
+}
+
+/*!
+    \brief      initialize RTC registers
+    \param[in]  rtc_initpara_struct: pointer to a rtc_parameter_struct structure which contains
+                parameters for initialization of the rtc peripheral
+                members of the structure and the member values are shown as below:
+                  rtc_year: 0x0 - 0x99(BCD format)
+                  rtc_month: RTC_JAN, RTC_FEB, RTC_MAR, RTC_APR, RTC_MAY, RTC_JUN,
+                             RTC_JUL, RTC_AUG, RTC_SEP, RTC_OCT, RTC_NOV, RTC_DEC
+                  rtc_date: 0x1 - 0x31(BCD format)
+                  rtc_day_of_week: RTC_MONDAY, RTC_TUESDAY, RTC_WEDSDAY, RTC_THURSDAY
+                                   RTC_FRIDAY, RTC_SATURDAY, RTC_SUNDAY
+                  rtc_hour: 0x0 - 0x12(BCD format) or 0x0 - 0x23(BCD format) depending on the rtc_display_format chose
+                  rtc_minute: 0x0 - 0x59(BCD format)
+                  rtc_second: 0x0 - 0x59(BCD format)
+                  rtc_factor_asyn: 0x0 - 0x7F
+                  rtc_factor_syn: 0x0 - 0x7FFF
+                  rtc_am_pm: RTC_AM, RTC_PM
+                  rtc_display_format: RTC_24HOUR, RTC_12HOUR
+    \param[out] none
+    \retval     ErrStatus: ERROR or SUCCESS
+*/
+ErrStatus rtc_init(rtc_parameter_struct *rtc_initpara_struct)
+{
+    ErrStatus error_status = ERROR;
+    uint32_t reg_time = 0x00U, reg_date = 0x00U;
+
+    reg_date = (DATE_YR(rtc_initpara_struct->rtc_year) | \
+                DATE_DOW(rtc_initpara_struct->rtc_day_of_week) | \
+                DATE_MON(rtc_initpara_struct->rtc_month) | \
+                DATE_DAY(rtc_initpara_struct->rtc_date));
+
+    reg_time = (rtc_initpara_struct->rtc_am_pm | \
+                TIME_HR(rtc_initpara_struct->rtc_hour) | \
+                TIME_MN(rtc_initpara_struct->rtc_minute) | \
+                TIME_SC(rtc_initpara_struct->rtc_second));
+
+    /* 1st: disable the write protection */
+    RTC_WPK = RTC_UNLOCK_KEY1;
+    RTC_WPK = RTC_UNLOCK_KEY2;
+
+    /* 2nd: enter init mode */
+    error_status = rtc_init_mode_enter();
+
+    if(ERROR != error_status) {
+        RTC_PSC = (uint32_t)(PSC_FACTOR_A(rtc_initpara_struct->rtc_factor_asyn) | \
+                             PSC_FACTOR_S(rtc_initpara_struct->rtc_factor_syn));
+
+        RTC_TIME = (uint32_t)reg_time;
+        RTC_DATE = (uint32_t)reg_date;
+
+        RTC_CTL &= (uint32_t)(~RTC_CTL_CS);
+        RTC_CTL |=  rtc_initpara_struct->rtc_display_format;
+
+        /* 3rd: exit init mode */
+        rtc_init_mode_exit();
+
+        /* 4th: wait the RSYNF flag to set */
+        error_status = rtc_register_sync_wait();
+    }
+
+    /* 5th: enable the write protection */
+    RTC_WPK = RTC_LOCK_KEY;
+
+    return error_status;
+}
+
+/*!
+    \brief      enter RTC init mode
+    \param[in]  none
+    \param[out] none
+    \retval     ErrStatus: ERROR or SUCCESS
+*/
+ErrStatus rtc_init_mode_enter(void)
+{
+    uint32_t time_index = RTC_INITM_TIMEOUT;
+    uint32_t flag_status = RESET;
+    ErrStatus error_status = ERROR;
+
+    /* check whether it has been in init mode */
+    if(RESET == (RTC_STAT & RTC_STAT_INITF)) {
+        RTC_STAT |= RTC_STAT_INITM;
+
+        /* wait until the INITF flag to be set */
+        do {
+            flag_status = RTC_STAT & RTC_STAT_INITF;
+        } while((--time_index > 0x00U) && (RESET == flag_status));
+
+        if(RESET != flag_status) {
+            error_status = SUCCESS;
+        }
+    } else {
+        error_status = SUCCESS;
+    }
+    return error_status;
+}
+
+/*!
+    \brief      exit RTC init mode
+    \param[in]  none
+    \param[out] none
+    \retval     none
+*/
+void rtc_init_mode_exit(void)
+{
+    RTC_STAT &= (uint32_t)(~RTC_STAT_INITM);
+}
+
+/*!
+    \brief      wait until RTC_TIME and RTC_DATE registers are synchronized with APB clock, and the shadow
+                registers are updated
+    \param[in]  none
+    \param[out] none
+    \retval     ErrStatus: ERROR or SUCCESS
+*/
+ErrStatus rtc_register_sync_wait(void)
+{
+    volatile uint32_t time_index = RTC_RSYNF_TIMEOUT;
+    uint32_t flag_status = RESET;
+    ErrStatus error_status = ERROR;
+
+    if(RESET == (RTC_CTL & RTC_CTL_BPSHAD)) {
+        /* disable the write protection */
+        RTC_WPK = RTC_UNLOCK_KEY1;
+        RTC_WPK = RTC_UNLOCK_KEY2;
+
+        /* firstly clear RSYNF flag */
+        RTC_STAT &= (uint32_t)(~RTC_STAT_RSYNF);
+
+        /* wait until RSYNF flag to be set */
+        do {
+            flag_status = RTC_STAT & RTC_STAT_RSYNF;
+        } while((--time_index > 0x00U) && (RESET == flag_status));
+
+        if(RESET != flag_status) {
+            error_status = SUCCESS;
+        }
+
+        /* enable the write protection */
+        RTC_WPK = RTC_LOCK_KEY;
+    } else {
+        error_status = SUCCESS;
+    }
+
+    return error_status;
+}
+
+/*!
+    \brief      get current time and date
+    \param[in]  none
+    \param[out] rtc_initpara_struct: pointer to a rtc_parameter_struct structure which contains
+                parameters for initialization of the rtc peripheral
+                members of the structure and the member values are shown as below:
+                  rtc_year: 0x0 - 0x99(BCD format)
+                  rtc_month: RTC_JAN, RTC_FEB, RTC_MAR, RTC_APR, RTC_MAY, RTC_JUN,
+                             RTC_JUL, RTC_AUG, RTC_SEP, RTC_OCT, RTC_NOV, RTC_DEC
+                  rtc_date: 0x1 - 0x31(BCD format)
+                  rtc_day_of_week: RTC_MONDAY, RTC_TUESDAY, RTC_WEDSDAY, RTC_THURSDAY
+                                   RTC_FRIDAY, RTC_SATURDAY, RTC_SUNDAY
+                  rtc_hour: 0x0 - 0x12(BCD format) or 0x0 - 0x23(BCD format) depending on the rtc_display_format chose
+                  rtc_minute: 0x0 - 0x59(BCD format)
+                  rtc_second: 0x0 - 0x59(BCD format)
+                  rtc_factor_asyn: 0x0 - 0x7F
+                  rtc_factor_syn: 0x0 - 0x7FFF
+                  rtc_am_pm: RTC_AM, RTC_PM
+                  rtc_display_format: RTC_24HOUR, RTC_12HOUR
+    \retval     none
+*/
+void rtc_current_time_get(rtc_parameter_struct *rtc_initpara_struct)
+{
+    uint32_t temp_tr = 0x00U, temp_dr = 0x00U, temp_pscr = 0x00U, temp_ctlr = 0x00U;
+
+    temp_tr = (uint32_t)RTC_TIME;
+    temp_dr = (uint32_t)RTC_DATE;
+    temp_pscr = (uint32_t)RTC_PSC;
+    temp_ctlr = (uint32_t)RTC_CTL;
+
+    /* get current time and construct rtc_parameter_struct structure */
+    rtc_initpara_struct->rtc_year = (uint8_t)GET_DATE_YR(temp_dr);
+    rtc_initpara_struct->rtc_month = (uint8_t)GET_DATE_MON(temp_dr);
+    rtc_initpara_struct->rtc_date = (uint8_t)GET_DATE_DAY(temp_dr);
+    rtc_initpara_struct->rtc_day_of_week = (uint8_t)GET_DATE_DOW(temp_dr);
+    rtc_initpara_struct->rtc_hour = (uint8_t)GET_TIME_HR(temp_tr);
+    rtc_initpara_struct->rtc_minute = (uint8_t)GET_TIME_MN(temp_tr);
+    rtc_initpara_struct->rtc_second = (uint8_t)GET_TIME_SC(temp_tr);
+    rtc_initpara_struct->rtc_factor_asyn = (uint16_t)GET_PSC_FACTOR_A(temp_pscr);
+    rtc_initpara_struct->rtc_factor_syn = (uint16_t)GET_PSC_FACTOR_S(temp_pscr);
+    rtc_initpara_struct->rtc_am_pm = (uint32_t)(temp_tr & RTC_TIME_PM);
+    rtc_initpara_struct->rtc_display_format = (uint32_t)(temp_ctlr & RTC_CTL_CS);
+}
+
+/*!
+    \brief      get current subsecond value
+    \param[in]  none
+    \param[out] none
+    \retval     current subsecond value
+*/
+uint32_t rtc_subsecond_get(void)
+{
+    uint32_t reg = 0x00U;
+    /* if BPSHAD bit is reset, reading RTC_SS will lock RTC_TIME and RTC_DATE automatically */
+    reg = (uint32_t)RTC_SS;
+    /* read RTC_DATE to unlock the 3 shadow registers */
+    (void)(RTC_DATE);
+
+    return reg;
+}
+
+/*!
+    \brief      configure RTC alarm
+    \param[in]  rtc_alarm_time: pointer to a rtc_alarm_struct structure which contains
+                parameters for RTC alarm configuration
+                members of the structure and the member values are shown as below:
+                  rtc_alarm_mask: RTC_ALARM_NONE_MASK, RTC_ALARM_DATE_MASK, RTC_ALARM_HOUR_MASK
+                                  RTC_ALARM_MINUTE_MASK, RTC_ALARM_SECOND_MASK, RTC_ALARM_ALL_MASK
+                  rtc_weekday_or_date: RTC_ALARM_DATE_SELECTED, RTC_ALARM_WEEKDAY_SELECTED
+                  rtc_alarm_day: 1) 0x1 - 0x31(BCD format) if RTC_ALARM_DATE_SELECTED is set
+                                 2) RTC_MONDAY, RTC_TUESDAY, RTC_WEDSDAY, RTC_THURSDAY, RTC_FRIDAY,
+                                    RTC_SATURDAY, RTC_SUNDAY if RTC_ALARM_WEEKDAY_SELECTED is set
+                  rtc_alarm_hour: 0x0 - 0x12(BCD format) or 0x0 - 0x23(BCD format) depending on the rtc_display_format
+                  rtc_alarm_minute: 0x0 - 0x59(BCD format)
+                  rtc_alarm_second: 0x0 - 0x59(BCD format)
+                  rtc_am_pm: RTC_AM, RTC_PM
+    \param[out] none
+    \retval     none
+*/
+void rtc_alarm_config(rtc_alarm_struct *rtc_alarm_time)
+{
+    uint32_t reg_alrm0td = 0x00U;
+
+    reg_alrm0td = (rtc_alarm_time->rtc_alarm_mask | \
+                   rtc_alarm_time->rtc_weekday_or_date | \
+                   rtc_alarm_time->rtc_am_pm | \
+                   ALRM0TD_DAY(rtc_alarm_time->rtc_alarm_day) | \
+                   ALRM0TD_HR(rtc_alarm_time->rtc_alarm_hour) | \
+                   ALRM0TD_MN(rtc_alarm_time->rtc_alarm_minute) | \
+                   ALRM0TD_SC(rtc_alarm_time->rtc_alarm_second));
+
+    /* disable the write protection */
+    RTC_WPK = RTC_UNLOCK_KEY1;
+    RTC_WPK = RTC_UNLOCK_KEY2;
+
+    RTC_ALRM0TD = (uint32_t)reg_alrm0td;
+
+    /* enable the write protection */
+    RTC_WPK = RTC_LOCK_KEY;
+}
+
+/*!
+    \brief      configure subsecond of RTC alarm
+    \param[in]  mask_subsecond: alarm subsecond mask
+                only one parameter can be selected which is shown as below:
+      \arg        RTC_MASKSSC_0_14: mask alarm subsecond configuration
+      \arg        RTC_MASKSSC_1_14: mask RTC_ALRM0SS_SSC[14:1], and RTC_ALRM0SS_SSC[0] is to be compared
+      \arg        RTC_MASKSSC_2_14: mask RTC_ALRM0SS_SSC[14:2], and RTC_ALRM0SS_SSC[1:0] is to be compared
+      \arg        RTC_MASKSSC_3_14: mask RTC_ALRM0SS_SSC[14:3], and RTC_ALRM0SS_SSC[2:0] is to be compared
+      \arg        RTC_MASKSSC_4_14: mask RTC_ALRM0SS_SSC[14:4], and RTC_ALRM0SS_SSC[3:0] is to be compared
+      \arg        RTC_MASKSSC_5_14: mask RTC_ALRM0SS_SSC[14:5], and RTC_ALRM0SS_SSC[4:0] is to be compared
+      \arg        RTC_MASKSSC_6_14: mask RTC_ALRM0SS_SSC[14:6], and RTC_ALRM0SS_SSC[5:0] is to be compared
+      \arg        RTC_MASKSSC_7_14: mask RTC_ALRM0SS_SSC[14:7], and RTC_ALRM0SS_SSC[6:0] is to be compared
+      \arg        RTC_MASKSSC_8_14: mask RTC_ALRM0SS_SSC[14:8], and RTC_ALRM0SS_SSC[7:0] is to be compared
+      \arg        RTC_MASKSSC_9_14: mask RTC_ALRM0SS_SSC[14:9], and RTC_ALRM0SS_SSC[8:0] is to be compared
+      \arg        RTC_MASKSSC_10_14: mask RTC_ALRM0SS_SSC[14:10], and RTC_ALRM0SS_SSC[9:0] is to be compared
+      \arg        RTC_MASKSSC_11_14: mask RTC_ALRM0SS_SSC[14:11], and RTC_ALRM0SS_SSC[10:0] is to be compared
+      \arg        RTC_MASKSSC_12_14: mask RTC_ALRM0SS_SSC[14:12], and RTC_ALRM0SS_SSC[11:0] is to be compared
+      \arg        RTC_MASKSSC_13_14: mask RTC_ALRM0SS_SSC[14:13], and RTC_ALRM0SS_SSC[12:0] is to be compared
+      \arg        RTC_MASKSSC_14: mask RTC_ALRM0SS_SSC[14], and RTC_ALRM0SS_SSC[13:0] is to be compared
+      \arg        RTC_MASKSSC_NONE: mask none, and RTC_ALRM0SS_SSC[14:0] is to be compared
+    \param[in]  subsecond: alarm subsecond value(0x000 - 0x7FFF)
+    \param[out] none
+    \retval     none
+*/
+void rtc_alarm_subsecond_config(uint32_t mask_subsecond, uint32_t subsecond)
+{
+    /* disable the write protection */
+    RTC_WPK = RTC_UNLOCK_KEY1;
+    RTC_WPK = RTC_UNLOCK_KEY2;
+
+    RTC_ALRM0SS = mask_subsecond | subsecond;
+
+    /* enable the write protection */
+    RTC_WPK = RTC_LOCK_KEY;
+}
+
+/*!
+    \brief      get RTC alarm
+    \param[in]  none
+    \param[out] rtc_alarm_time: pointer to a rtc_alarm_struct structure which contains
+                parameters for RTC alarm configuration
+                members of the structure and the member values are shown as below:
+                  rtc_alarm_mask: RTC_ALARM_NONE_MASK, RTC_ALARM_DATE_MASK, RTC_ALARM_HOUR_MASK
+                                  RTC_ALARM_MINUTE_MASK, RTC_ALARM_SECOND_MASK, RTC_ALARM_ALL_MASK
+                  rtc_weekday_or_date: RTC_ALARM_DATE_SELECTED, RTC_ALARM_WEEKDAY_SELECTED
+                  rtc_alarm_day: 1) 0x1 - 0x31(BCD format) if RTC_ALARM_DATE_SELECTED is set
+                                 2) RTC_MONDAY, RTC_TUESDAY, RTC_WEDSDAY, RTC_THURSDAY, RTC_FRIDAY,
+                                    RTC_SATURDAY, RTC_SUNDAY if RTC_ALARM_WEEKDAY_SELECTED is set
+                  rtc_alarm_hour: 0x0 - 0x12(BCD format) or 0x0 - 0x23(BCD format) depending on the rtc_display_format
+                  rtc_alarm_minute: 0x0 - 0x59(BCD format)
+                  rtc_alarm_second: 0x0 - 0x59(BCD format)
+                  rtc_am_pm: RTC_AM, RTC_PM
+    \retval     none
+*/
+void rtc_alarm_get(rtc_alarm_struct *rtc_alarm_time)
+{
+    uint32_t reg_alrm0td = 0x00U;
+
+    /* get the value of RTC_ALRM0TD register */
+    reg_alrm0td = RTC_ALRM0TD;
+
+    /* get alarm parameters and construct the rtc_alarm_struct structure */
+    rtc_alarm_time->rtc_alarm_mask = reg_alrm0td & RTC_ALARM_ALL_MASK;
+    rtc_alarm_time->rtc_am_pm = (uint32_t)(reg_alrm0td & RTC_ALRM0TD_PM);
+    rtc_alarm_time->rtc_weekday_or_date = (uint32_t)(reg_alrm0td & RTC_ALRM0TD_DOWS);
+    rtc_alarm_time->rtc_alarm_day = (uint8_t)GET_ALRM0TD_DAY(reg_alrm0td);
+    rtc_alarm_time->rtc_alarm_hour = (uint8_t)GET_ALRM0TD_HR(reg_alrm0td);
+    rtc_alarm_time->rtc_alarm_minute = (uint8_t)GET_ALRM0TD_MN(reg_alrm0td);
+    rtc_alarm_time->rtc_alarm_second = (uint8_t)GET_ALRM0TD_SC(reg_alrm0td);
+}
+
+/*!
+    \brief      get RTC alarm subsecond
+    \param[in]  none
+    \param[out] none
+    \retval     RTC alarm subsecond value
+*/
+uint32_t rtc_alarm_subsecond_get(void)
+{
+    return ((uint32_t)(RTC_ALRM0SS & RTC_ALRM0SS_SSC));
+}
+
+/*!
+    \brief      enable RTC alarm
+    \param[in]  none
+    \param[out] none
+    \retval     none
+*/
+void rtc_alarm_enable(void)
+{
+    /* disable the write protection */
+    RTC_WPK = RTC_UNLOCK_KEY1;
+    RTC_WPK = RTC_UNLOCK_KEY2;
+
+    RTC_CTL |= RTC_CTL_ALRM0EN;
+
+    /* enable the write protection */
+    RTC_WPK = RTC_LOCK_KEY;
+}
+
+/*!
+    \brief      disable RTC alarm
+    \param[in]  none
+    \param[out] none
+    \retval     ErrStatus: ERROR or SUCCESS
+*/
+ErrStatus rtc_alarm_disable(void)
+{
+    volatile uint32_t time_index = RTC_ALRM0WF_TIMEOUT;
+    ErrStatus error_status = ERROR;
+    uint32_t flag_status = RESET;
+
+    /* disable the write protection */
+    RTC_WPK = RTC_UNLOCK_KEY1;
+    RTC_WPK = RTC_UNLOCK_KEY2;
+
+    /* clear the state of alarm */
+    RTC_CTL &= (uint32_t)(~RTC_CTL_ALRM0EN);
+
+    /* wait until ALRM0WF flag to be set after the alarm is disabled */
+    do {
+        flag_status = RTC_STAT & RTC_STAT_ALRM0WF;
+    } while((--time_index > 0x00U) && (RESET == flag_status));
+
+    if(RESET != flag_status) {
+        error_status = SUCCESS;
+    }
+
+    /* enable the write protection */
+    RTC_WPK = RTC_LOCK_KEY;
+
+    return error_status;
+}
+
+/*!
+    \brief      enable RTC time-stamp
+    \param[in]  edge: specify which edge to detect of time-stamp
+                only one parameter can be selected which is shown as below:
+      \arg        RTC_TIMESTAMP_RISING_EDGE: rising edge is valid event edge for timestamp event
+      \arg        RTC_TIMESTAMP_FALLING_EDGE: falling edge is valid event edge for timestamp event
+    \param[out] none
+    \retval     none
+*/
+void rtc_timestamp_enable(uint32_t edge)
+{
+    uint32_t reg_ctl = 0x00U;
+
+    /* clear the bits to be configured in RTC_CTL */
+    reg_ctl = (uint32_t)(RTC_CTL & (uint32_t)(~(RTC_CTL_TSEG | RTC_CTL_TSEN)));
+
+    /* new configuration */
+    reg_ctl |= (uint32_t)(edge | RTC_CTL_TSEN);
+
+    /* disable the write protection */
+    RTC_WPK = RTC_UNLOCK_KEY1;
+    RTC_WPK = RTC_UNLOCK_KEY2;
+
+    RTC_CTL = (uint32_t)reg_ctl;
+
+    /* enable the write protection */
+    RTC_WPK = RTC_LOCK_KEY;
+}
+
+/*!
+    \brief      disable RTC time-stamp
+    \param[in]  none
+    \param[out] none
+    \retval     none
+*/
+void rtc_timestamp_disable(void)
+{
+    /* disable the write protection */
+    RTC_WPK = RTC_UNLOCK_KEY1;
+    RTC_WPK = RTC_UNLOCK_KEY2;
+
+    /* clear the TSEN bit */
+    RTC_CTL &= (uint32_t)(~ RTC_CTL_TSEN);
+
+    /* enable the write protection */
+    RTC_WPK = RTC_LOCK_KEY;
+}
+
+/*!
+    \brief      get RTC timestamp time and date
+    \param[in]  none
+    \param[out] rtc_timestamp: pointer to a rtc_timestamp_struct structure which contains
+                parameters for RTC time-stamp configuration
+                members of the structure and the member values are shown as below:
+                  rtc_timestamp_month: RTC_JAN, RTC_FEB, RTC_MAR, RTC_APR, RTC_MAY, RTC_JUN,
+                                       RTC_JUL, RTC_AUG, RTC_SEP, RTC_OCT, RTC_NOV, RTC_DEC
+                  rtc_timestamp_date: 0x1 - 0x31(BCD format)
+                  rtc_timestamp_day: RTC_MONDAY, RTC_TUESDAY, RTC_WEDSDAY, RTC_THURSDAY, RTC_FRIDAY,
+                                     RTC_SATURDAY, RTC_SUNDAY if RTC_ALARM_WEEKDAY_SELECTED is set
+                  rtc_timestamp_hour: 0x0 - 0x12(BCD format) or 0x0 - 0x23(BCD format) depending on the rtc_display_format
+                  rtc_timestamp_minute: 0x0 - 0x59(BCD format)
+                  rtc_timestamp_second: 0x0 - 0x59(BCD format)
+                  rtc_am_pm: RTC_AM, RTC_PM
+    \retval     none
+*/
+void rtc_timestamp_get(rtc_timestamp_struct *rtc_timestamp)
+{
+    uint32_t temp_tts = 0x00U, temp_dts = 0x00U;
+
+    /* get the value of time_stamp registers */
+    temp_tts = (uint32_t)RTC_TTS;
+    temp_dts = (uint32_t)RTC_DTS;
+
+    /* get timestamp time and construct the rtc_timestamp_struct structure */
+    rtc_timestamp->rtc_am_pm = (uint32_t)(temp_tts & RTC_TTS_PM);
+    rtc_timestamp->rtc_timestamp_month = (uint8_t)GET_DTS_MON(temp_dts);
+    rtc_timestamp->rtc_timestamp_date = (uint8_t)GET_DTS_DAY(temp_dts);
+    rtc_timestamp->rtc_timestamp_day = (uint8_t)GET_DTS_DOW(temp_dts);
+    rtc_timestamp->rtc_timestamp_hour = (uint8_t)GET_TTS_HR(temp_tts);
+    rtc_timestamp->rtc_timestamp_minute = (uint8_t)GET_TTS_MN(temp_tts);
+    rtc_timestamp->rtc_timestamp_second = (uint8_t)GET_TTS_SC(temp_tts);
+}
+
+/*!
+    \brief      get RTC time-stamp subsecond
+    \param[in]  none
+    \param[out] none
+    \retval     RTC time-stamp subsecond value
+*/
+uint32_t rtc_timestamp_subsecond_get(void)
+{
+    return ((uint32_t)RTC_SSTS);
+}
+
+/*!
+    \brief      enable RTC tamper
+    \param[in]  rtc_tamper: pointer to a rtc_tamper_struct structure which contains
+                parameters for RTC tamper configuration
+                members of the structure and the member values are shown as below:
+                  rtc_tamper_source: RTC_TAMPER0, RTC_TAMPER1
+                  rtc_tamper_trigger: RTC_TAMPER_TRIGGER_EDGE_RISING, RTC_TAMPER_TRIGGER_EDGE_FALLING
+                                      RTC_TAMPER_TRIGGER_LEVEL_LOW, RTC_TAMPER_TRIGGER_LEVEL_HIGH
+                  rtc_tamper_filter: RTC_FLT_EDGE, RTC_FLT_2S, RTC_FLT_4S, RTC_FLT_8S
+                  rtc_tamper_sample_frequency: RTC_FREQ_DIV32768, RTC_FREQ_DIV16384, RTC_FREQ_DIV8192,
+                                               RTC_FREQ_DIV4096, RTC_FREQ_DIV2048, RTC_FREQ_DIV1024,
+                                               RTC_FREQ_DIV512, RTC_FREQ_DIV256
+                  rtc_tamper_precharge_enable: DISABLE, ENABLE
+                  rtc_tamper_precharge_time: RTC_PRCH_1C, RTC_PRCH_2C, RTC_PRCH_4C, RTC_PRCH_8C
+                  rtc_tamper_with_timestamp: DISABLE, ENABLE
+    \param[out] none
+    \retval     none
+*/
+void rtc_tamper_enable(rtc_tamper_struct *rtc_tamper)
+{
+    /* disable tamper */
+    RTC_TAMP &= (uint32_t)~(rtc_tamper->rtc_tamper_source);
+
+    /* tamper filter must be used when the tamper source is voltage level detection */
+    RTC_TAMP &= (uint32_t)~RTC_TAMP_FLT;
+
+    /* the tamper source is voltage level detection */
+    if(rtc_tamper->rtc_tamper_filter != RTC_FLT_EDGE) {
+        RTC_TAMP &= (uint32_t)~(RTC_TAMP_DISPU | RTC_TAMP_PRCH | RTC_TAMP_FREQ | RTC_TAMP_FLT);
+
+        /* check if the tamper pin need precharge, if need, then configure the precharge time */
+        if(DISABLE == rtc_tamper->rtc_tamper_precharge_enable) {
+            RTC_TAMP |= (uint32_t)RTC_TAMP_DISPU;
+        } else {
+            RTC_TAMP |= (uint32_t)(rtc_tamper->rtc_tamper_precharge_time);
+        }
+
+        RTC_TAMP |= (uint32_t)(rtc_tamper->rtc_tamper_sample_frequency);
+        RTC_TAMP |= (uint32_t)(rtc_tamper->rtc_tamper_filter);
+    }
+
+    RTC_TAMP &= (uint32_t)~RTC_TAMP_TPTS;
+
+    if(DISABLE != rtc_tamper->rtc_tamper_with_timestamp) {
+        /* the tamper event also cause a time-stamp event */
+        RTC_TAMP |= (uint32_t)RTC_TAMP_TPTS;
+    }
+
+    /* configure the tamper trigger */
+    RTC_TAMP &= ((uint32_t)~((rtc_tamper->rtc_tamper_source) << RTC_TAMPER_TRIGGER_POS));
+    if(RTC_TAMPER_TRIGGER_EDGE_RISING != rtc_tamper->rtc_tamper_trigger) {
+        RTC_TAMP |= (uint32_t)((rtc_tamper->rtc_tamper_source) << RTC_TAMPER_TRIGGER_POS);
+    }
+    /* enable tamper */
+    RTC_TAMP |= (uint32_t)(rtc_tamper->rtc_tamper_source);
+}
+
+/*!
+    \brief      disable RTC tamper
+    \param[in]  source: specify which tamper source to be disabled
+                only one parameter can be selected which is shown as below:
+      \arg        RTC_TAMPER0
+      \arg        RTC_TAMPER1
+    \param[out] none
+    \retval     none
+*/
+void rtc_tamper_disable(uint32_t source)
+{
+    /* disable tamper */
+    RTC_TAMP &= (uint32_t)~source;
+}
+
+/*!
+    \brief      enable specified RTC interrupt
+    \param[in]  interrupt: specify which interrupt source to be enabled
+                only one parameter can be selected which is shown as below:
+      \arg        RTC_INT_TIMESTAMP: timestamp interrupt
+      \arg        RTC_INT_ALARM: alarm interrupt
+      \arg        RTC_INT_TAMP: tamp interrupt
+    \param[out] none
+    \retval     none
+*/
+void rtc_interrupt_enable(uint32_t interrupt)
+{
+    /* disable the write protection */
+    RTC_WPK = RTC_UNLOCK_KEY1;
+    RTC_WPK = RTC_UNLOCK_KEY2;
+
+    /* enable the interrupts in RTC_CTL register */
+    RTC_CTL |= (uint32_t)(interrupt & (uint32_t)~RTC_TAMP_TPIE);
+    /* enable the interrupts in RTC_TAMP register */
+    RTC_TAMP |= (uint32_t)(interrupt & RTC_TAMP_TPIE);
+
+    /* enable the write protection */
+    RTC_WPK = RTC_LOCK_KEY;
+}
+
+/*!
+    \brief      disble specified RTC interrupt
+    \param[in]  interrupt: specify which interrupt source to be disabled
+                only one parameter can be selected which is shown as below:
+      \arg        RTC_INT_TIMESTAMP: timestamp interrupt
+      \arg        RTC_INT_ALARM: alarm interrupt
+      \arg        RTC_INT_TAMP: tamp interrupt
+    \param[out] none
+    \retval     none
+*/
+void rtc_interrupt_disable(uint32_t interrupt)
+{
+    /* disable the write protection */
+    RTC_WPK = RTC_UNLOCK_KEY1;
+    RTC_WPK = RTC_UNLOCK_KEY2;
+
+    /* disable the interrupts in RTC_CTL register */
+    RTC_CTL &= (uint32_t)~(interrupt & (uint32_t)~RTC_TAMP_TPIE);
+    /* disable the interrupts in RTC_TAMP register */
+    RTC_TAMP &= (uint32_t)~(interrupt & RTC_TAMP_TPIE);
+
+    /* enable the write protection */
+    RTC_WPK = RTC_LOCK_KEY;
+}
+
+/*!
+    \brief      check specified flag
+    \param[in]  flag: specify which flag to check
+                only one parameter can be selected which is shown as below:
+      \arg        RTC_FLAG_RECALIBRATION: recalibration pending flag
+      \arg        RTC_FLAG_TAMP1: tamper 1 event flag
+      \arg        RTC_FLAG_TAMP0: tamper 0 event flag
+      \arg        RTC_FLAG_TIMESTAMP_OVERFLOW: time-stamp overflow event flag
+      \arg        RTC_FLAG_TIMESTAMP: time-stamp event flag
+      \arg        RTC_FLAG_ALARM0: alarm event flag
+      \arg        RTC_FLAG_INIT: init mode event flag
+      \arg        RTC_FLAG_RSYN: time and date registers synchronized event flag
+      \arg        RTC_FLAG_YCM: year parameter configured event flag
+      \arg        RTC_FLAG_SHIFT: shift operation pending flag
+      \arg        RTC_FLAG_ALARM0_WRITTEN: alarm writen available flag
+    \param[out] none
+    \retval     FlagStatus: SET or RESET
+*/
+FlagStatus rtc_flag_get(uint32_t flag)
+{
+    FlagStatus flag_state = RESET;
+
+    if(RESET != (RTC_STAT & flag)) {
+        flag_state = SET;
+    }
+    return flag_state;
+}
+
+/*!
+    \brief      clear specified flag
+    \param[in]  flag: specify which flag to clear
+      \arg        RTC_FLAG_TAMP1: tamper 1 event flag
+      \arg        RTC_FLAG_TAMP0: tamper 0 event flag
+      \arg        RTC_FLAG_TIMESTAMP_OVERFLOW: time-stamp overflow event flag
+      \arg        RTC_FLAG_TIMESTAMP: time-stamp event flag
+      \arg        RTC_FLAG_ALARM0: alarm event flag
+      \arg        RTC_FLAG_RSYN: time and date registers synchronized event flag
+    \param[out] none
+    \retval     none
+*/
+void rtc_flag_clear(uint32_t flag)
+{
+    RTC_STAT &= (uint32_t)(~flag);
+}
+
+/*!
+    \brief      configure rtc alternate output source
+    \param[in]  source: specify signal to output
+                only one parameter can be selected which is shown as below:
+      \arg        RTC_CALIBRATION_512HZ: when the LSE freqency is 32768Hz and the RTC_PSC
+                                         is the default value, output 512Hz signal
+      \arg        RTC_CALIBRATION_1HZ: when the LSE freqency is 32768Hz and the RTC_PSC
+                                       is the default value, output 1Hz signal
+      \arg        RTC_ALARM_HIGH: when the  alarm flag is set, the output pin is high
+      \arg        RTC_ALARM_LOW: when the  Alarm flag is set, the output pin is low
+    \param[in]  mode: specify the output pin (PC13) mode when output alarm signal
+                only one parameter can be selected which is shown as below:
+      \arg        RTC_ALARM_OUTPUT_OD: open drain mode
+      \arg        RTC_ALARM_OUTPUT_PP: push pull mode
+    \param[out] none
+    \retval     none
+*/
+void rtc_alter_output_config(uint32_t source, uint32_t mode)
+{
+    /* disable the write protection */
+    RTC_WPK = RTC_UNLOCK_KEY1;
+    RTC_WPK = RTC_UNLOCK_KEY2;
+
+    RTC_CTL &= (uint32_t)~(RTC_CTL_COEN | RTC_CTL_OS | RTC_CTL_OPOL | RTC_CTL_COS);
+
+    RTC_CTL |= (uint32_t)(source);
+
+    /* alarm output */
+    if(RESET != (source & RTC_OS_ENABLE)) {
+        RTC_TAMP &= (uint32_t)~(RTC_TAMP_PC13VAL);
+        RTC_TAMP |= (uint32_t)(mode);
+    }
+
+    /* enable the write protection */
+    RTC_WPK = RTC_LOCK_KEY;
+}
+
+
+/*!
+    \brief      configure RTC calibration register
+    \param[in]  window: select calibration window
+                only one parameter can be selected which is shown as below:
+      \arg        RTC_CALIBRATION_WINDOW_32S: 2exp20 RTCCLK cycles, 32s if RTCCLK = 32768 Hz
+      \arg        RTC_CALIBRATION_WINDOW_16S: 2exp19 RTCCLK cycles, 16s if RTCCLK = 32768 Hz
+      \arg        RTC_CALIBRATION_WINDOW_8S: 2exp18 RTCCLK cycles, 8s if RTCCLK = 32768 Hz
+    \param[in]  plus: add RTC clock or not
+                only one parameter can be selected which is shown as below:
+      \arg        RTC_CALIBRATION_PLUS_SET: add one RTC clock every 2048 rtc clock
+      \arg        RTC_CALIBRATION_PLUS_RESET: no effect
+    \param[in]  minus: the RTC clock to minus during the calibration window(0x0 - 0x1FF)
+    \param[out] none
+    \retval     ErrStatus: ERROR or SUCCESS
+*/
+ErrStatus rtc_calibration_config(uint32_t window, uint32_t plus, uint32_t minus)
+{
+    uint32_t time_index = RTC_HRFC_TIMEOUT;
+    ErrStatus error_status = ERROR;
+    uint32_t flag_status = RESET;
+
+    /* disable the write protection */
+    RTC_WPK = RTC_UNLOCK_KEY1;
+    RTC_WPK = RTC_UNLOCK_KEY2;
+
+    /* check if a calibration operation is ongoing */
+    do {
+        flag_status = RTC_STAT & RTC_STAT_SCPF;
+    } while((--time_index > 0x00U) && (RESET != flag_status));
+
+    if(RESET == flag_status) {
+        RTC_HRFC = (uint32_t)(window | plus | HRFC_CMSK(minus));
+        error_status = SUCCESS;
+    }
+
+    /* enable the write protection */
+    RTC_WPK = RTC_LOCK_KEY;
+
+    return error_status;
+}
+
+/*!
+    \brief      ajust the daylight saving time by adding or substracting one hour from the current time
+    \param[in]  operation: hour ajustment operation
+                only one parameter can be selected which is shown as below:
+      \arg        RTC_CTL_A1H: add one hour
+      \arg        RTC_CTL_S1H: substract one hour
+    \param[out] none
+    \retval     none
+*/
+void rtc_hour_adjust(uint32_t operation)
+{
+    /* disable the write protection */
+    RTC_WPK = RTC_UNLOCK_KEY1;
+    RTC_WPK = RTC_UNLOCK_KEY2;
+
+    RTC_CTL |= (uint32_t)(operation);
+
+    /* enable the write protection */
+    RTC_WPK = RTC_LOCK_KEY;
+}
+
+/*!
+    \brief      ajust RTC second or subsecond value of current time
+    \param[in]  add: add 1s to current time or not
+                only one parameter can be selected which is shown as below:
+      \arg        RTC_SHIFT_ADD1S_RESET: no effect
+      \arg        RTC_SHIFT_ADD1S_SET: add 1s to current time
+    \param[in]  minus: number of subsecond to minus from current time(0x0 - 0x7FFF)
+    \param[out] none
+    \retval     ErrStatus: ERROR or SUCCESS
+*/
+ErrStatus rtc_second_adjust(uint32_t add, uint32_t minus)
+{
+    uint32_t time_index = RTC_SHIFTCTL_TIMEOUT;
+    ErrStatus error_status = ERROR;
+    uint32_t flag_status = RESET;
+    uint32_t temp = 0U;
+
+    /* disable the write protection */
+    RTC_WPK = RTC_UNLOCK_KEY1;
+    RTC_WPK = RTC_UNLOCK_KEY2;
+
+    /* check if a shift operation is ongoing */
+    do {
+        flag_status = RTC_STAT & RTC_STAT_SOPF;
+    } while((--time_index > 0x00U) && (RESET != flag_status));
+
+    temp = RTC_CTL & RTC_CTL_REFEN;
+    /* check if the function of reference clock detection is disabled */
+    if((RESET == flag_status) && (RESET == temp)) {
+        RTC_SHIFTCTL = (uint32_t)(add | SHIFTCTL_SFS(minus));
+        error_status = rtc_register_sync_wait();
+    }
+
+    /* enable the write protection */
+    RTC_WPK = RTC_LOCK_KEY;
+
+    return error_status;
+}
+
+/*!
+    \brief      enable RTC bypass shadow registers function
+    \param[in]  none
+    \param[out] none
+    \retval     none
+*/
+void rtc_bypass_shadow_enable(void)
+{
+    /* disable the write protection */
+    RTC_WPK = RTC_UNLOCK_KEY1;
+    RTC_WPK = RTC_UNLOCK_KEY2;
+
+    RTC_CTL |= (uint8_t)RTC_CTL_BPSHAD;
+
+    /* enable the write protection */
+    RTC_WPK = RTC_LOCK_KEY;
+}
+
+/*!
+    \brief      disable RTC bypass shadow registers function
+    \param[in]  none
+    \param[out] none
+    \retval     none
+*/
+void rtc_bypass_shadow_disable(void)
+{
+    /* disable the write protection */
+    RTC_WPK = RTC_UNLOCK_KEY1;
+    RTC_WPK = RTC_UNLOCK_KEY2;
+
+    RTC_CTL &= (uint8_t)~RTC_CTL_BPSHAD;
+
+    /* enable the write protection */
+    RTC_WPK = RTC_LOCK_KEY;
+}
+
+/*!
+    \brief      enable RTC reference clock detection function
+    \param[in]  none
+    \param[out] none
+    \retval     ErrStatus: ERROR or SUCCESS
+*/
+ErrStatus rtc_refclock_detection_enable(void)
+{
+    ErrStatus error_status = ERROR;
+
+    /* disable the write protection */
+    RTC_WPK = RTC_UNLOCK_KEY1;
+    RTC_WPK = RTC_UNLOCK_KEY2;
+
+    /* enter init mode */
+    error_status = rtc_init_mode_enter();
+
+    if(ERROR != error_status) {
+        RTC_CTL |= (uint32_t)RTC_CTL_REFEN;
+        /* exit init mode */
+        rtc_init_mode_exit();
+    }
+
+    /* enable the write protection */
+    RTC_WPK = RTC_LOCK_KEY;
+
+    return error_status;
+}
+
+/*!
+    \brief      disable RTC reference clock detection function
+    \param[in]  none
+    \param[out] none
+    \retval     ErrStatus: ERROR or SUCCESS
+*/
+ErrStatus rtc_refclock_detection_disable(void)
+{
+    ErrStatus error_status = ERROR;
+
+    /* disable the write protection */
+    RTC_WPK = RTC_UNLOCK_KEY1;
+    RTC_WPK = RTC_UNLOCK_KEY2;
+
+    /* enter init mode */
+    error_status = rtc_init_mode_enter();
+
+    if(ERROR != error_status) {
+        RTC_CTL &= (uint32_t)~RTC_CTL_REFEN;
+        /* exit init mode */
+        rtc_init_mode_exit();
+    }
+
+    /* enable the write protection */
+    RTC_WPK = RTC_LOCK_KEY;
+
+    return error_status;
+}

+ 778 - 0
GD32F3x0/GD32F3x0_standard_peripheral/Source/gd32f3x0_spi.c

@@ -0,0 +1,778 @@
+/*!
+    \file    gd32f3x0_spi.c
+    \brief   SPI driver
+
+    \version 2025-01-01, V2.5.0, firmware for GD32F3x0
+*/
+
+/*
+    Copyright (c) 2025, GigaDevice Semiconductor Inc.
+
+    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 of the copyright holder 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 HOLDER 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.
+*/
+
+#include "gd32f3x0_spi.h"
+
+/* SPI/I2S parameter initialization mask */
+#define SPI_INIT_MASK                   ((uint32_t)0x00003040U)  /*!< SPI parameter initialization mask */
+#define I2S_INIT_MASK                   ((uint32_t)0x0000F047U)  /*!< I2S parameter initialization mask */
+
+#define SPI_I2SPSC_RESET                ((uint32_t)0x00000002U)  /*!< default value of SPI_I2SPSC register */
+
+/*!
+    \brief      reset SPI and I2S
+    \param[in]  spi_periph: SPIx(x=0,1)
+    \param[out] none
+    \retval     none
+*/
+void spi_i2s_deinit(uint32_t spi_periph)
+{
+    switch(spi_periph) {
+    case SPI0:
+        /* reset SPI0 and I2S0 */
+        rcu_periph_reset_enable(RCU_SPI0RST);
+        rcu_periph_reset_disable(RCU_SPI0RST);
+        break;
+    case SPI1:
+        /* reset SPI1 */
+        rcu_periph_reset_enable(RCU_SPI1RST);
+        rcu_periph_reset_disable(RCU_SPI1RST);
+        break;
+    default :
+        break;
+    }
+}
+
+/*!
+    \brief      initialize the parameters of SPI struct with the default values
+    \param[in]  none
+    \param[out] spi_parameter_struct: the initialized structure spi_parameter_struct pointer
+    \retval     none
+*/
+void spi_struct_para_init(spi_parameter_struct *spi_struct)
+{
+    /* configure the SPI structure with the default values */
+    spi_struct->device_mode          = SPI_SLAVE;
+    spi_struct->trans_mode           = SPI_TRANSMODE_FULLDUPLEX;
+    spi_struct->frame_size           = SPI_FRAMESIZE_8BIT;
+    spi_struct->nss                  = SPI_NSS_HARD;
+    spi_struct->endian               = SPI_ENDIAN_MSB;
+    spi_struct->clock_polarity_phase = SPI_CK_PL_LOW_PH_1EDGE;
+    spi_struct->prescale             = SPI_PSC_2;
+}
+
+/*!
+    \brief      initialize SPI parameter
+    \param[in]  spi_periph: SPIx(x=0,1)
+    \param[in]  spi_struct: SPI parameter initialization stuct members of the structure
+                            and the member values are shown as below:
+                  device_mode: SPI_MASTER, SPI_SLAVE
+                  trans_mode: SPI_TRANSMODE_FULLDUPLEX, SPI_TRANSMODE_RECEIVEONLY,
+                              SPI_TRANSMODE_BDRECEIVE, SPI_TRANSMODE_BDTRANSMIT
+                  frame_size: SPI_FRAMESIZE_16BIT, SPI_FRAMESIZE_8BIT
+                  nss: SPI_NSS_SOFT, SPI_NSS_HARD
+                  endian: SPI_ENDIAN_MSB, SPI_ENDIAN_LSB
+                  clock_polarity_phase: SPI_CK_PL_LOW_PH_1EDGE, SPI_CK_PL_HIGH_PH_1EDGE
+                                        SPI_CK_PL_LOW_PH_2EDGE, SPI_CK_PL_HIGH_PH_2EDGE
+                  prescale: SPI_PSC_n (n=2,4,8,16,32,64,128,256)
+    \param[out] none
+    \retval     none
+*/
+void spi_init(uint32_t spi_periph, spi_parameter_struct *spi_struct)
+{
+    uint32_t reg = 0U;
+    reg = SPI_CTL0(spi_periph);
+    reg &= SPI_INIT_MASK;
+
+    /* select SPI as master or slave */
+    reg |= spi_struct->device_mode;
+    /* select SPI transfer mode */
+    reg |= spi_struct->trans_mode;
+    /* select SPI frame size */
+    reg |= spi_struct->frame_size;
+    /* select SPI NSS use hardware or software */
+    reg |= spi_struct->nss;
+    /* select SPI LSB or MSB */
+    reg |= spi_struct->endian;
+    /* select SPI polarity and phase */
+    reg |= spi_struct->clock_polarity_phase;
+    /* select SPI prescale to adjust transmit speed */
+    reg |= spi_struct->prescale;
+
+    /* write to SPI_CTL0 register */
+    SPI_CTL0(spi_periph) = (uint32_t)reg;
+
+    /* select SPI mode */
+    SPI_I2SCTL(spi_periph) &= (uint32_t)(~SPI_I2SCTL_I2SSEL);
+}
+
+/*!
+    \brief      enable SPI
+    \param[in]  spi_periph: SPIx(x=0,1)
+    \param[out] none
+    \retval     none
+*/
+void spi_enable(uint32_t spi_periph)
+{
+    SPI_CTL0(spi_periph) |= (uint32_t)SPI_CTL0_SPIEN;
+}
+
+/*!
+    \brief      disable SPI
+    \param[in]  spi_periph: SPIx(x=0,1)
+    \param[out] none
+    \retval     none
+*/
+void spi_disable(uint32_t spi_periph)
+{
+    SPI_CTL0(spi_periph) &= (uint32_t)(~SPI_CTL0_SPIEN);
+}
+
+
+#if (defined(GD32F370) || defined(GD32F355) || defined(GD32F350) || defined(GD32F310))
+/*!
+    \brief      initialize I2S parameter
+    \param[in]  spi_periph: SPI0
+    \param[in]  mode: I2S operation mode
+                only one parameter can be selected which is shown as below:
+      \arg        I2S_MODE_SLAVETX: I2S slave transmit mode
+      \arg        I2S_MODE_SLAVERX: I2S slave receive mode
+      \arg        I2S_MODE_MASTERTX: I2S master transmit mode
+      \arg        I2S_MODE_MASTERRX: I2S master receive mode
+    \param[in]  standard: I2S standard
+                only one parameter can be selected which is shown as below:
+      \arg        I2S_STD_PHILLIPS: I2S phillips standard
+      \arg        I2S_STD_MSB: I2S MSB standard
+      \arg        I2S_STD_LSB: I2S LSB standard
+      \arg        I2S_STD_PCMSHORT: I2S PCM short standard
+      \arg        I2S_STD_PCMLONG: I2S PCM long standard
+    \param[in]  ckpl: I2S idle state clock polarity
+                only one parameter can be selected which is shown as below:
+      \arg        I2S_CKPL_LOW: I2S clock polarity low level
+      \arg        I2S_CKPL_HIGH: I2S clock polarity high level
+    \param[out] none
+    \retval     none
+*/
+void i2s_init(uint32_t spi_periph, uint32_t mode, uint32_t standard, uint32_t ckpl)
+{
+    uint32_t reg = 0U;
+    reg = SPI_I2SCTL(spi_periph);
+    reg &= I2S_INIT_MASK;
+
+    /* enable I2S mode */
+    reg |= (uint32_t)SPI_I2SCTL_I2SSEL;
+    /* select I2S mode */
+    reg |= (uint32_t)mode;
+    /* select I2S standard */
+    reg |= (uint32_t)standard;
+    /* select I2S polarity */
+    reg |= (uint32_t)ckpl;
+
+    /* write to SPI_I2SCTL register */
+    SPI_I2SCTL(spi_periph) = (uint32_t)reg;
+}
+
+/*!
+    \brief      configure I2S prescaler
+    \param[in]  spi_periph: SPI0
+    \param[in]  audiosample: I2S audio sample rate
+                only one parameter can be selected which is shown as below:
+      \arg        I2S_AUDIOSAMPLE_8K: audio sample rate is 8KHz
+      \arg        I2S_AUDIOSAMPLE_11K: audio sample rate is 11KHz
+      \arg        I2S_AUDIOSAMPLE_16K: audio sample rate is 16KHz
+      \arg        I2S_AUDIOSAMPLE_22K: audio sample rate is 22KHz
+      \arg        I2S_AUDIOSAMPLE_32K: audio sample rate is 32KHz
+      \arg        I2S_AUDIOSAMPLE_44K: audio sample rate is 44KHz
+      \arg        I2S_AUDIOSAMPLE_48K: audio sample rate is 48KHz
+      \arg        I2S_AUDIOSAMPLE_96K: audio sample rate is 96KHz
+      \arg        I2S_AUDIOSAMPLE_192K: audio sample rate is 192KHz
+    \param[in]  frameformat: I2S data length and channel length
+                only one parameter can be selected which is shown as below:
+      \arg        I2S_FRAMEFORMAT_DT16B_CH16B: I2S data length is 16 bit and channel length is 16 bit
+      \arg        I2S_FRAMEFORMAT_DT16B_CH32B: I2S data length is 16 bit and channel length is 32 bit
+      \arg        I2S_FRAMEFORMAT_DT24B_CH32B: I2S data length is 24 bit and channel length is 32 bit
+      \arg        I2S_FRAMEFORMAT_DT32B_CH32B: I2S data length is 32 bit and channel length is 32 bit
+    \param[in]  mckout: I2S master clock output
+                only one parameter can be selected which is shown as below:
+      \arg        I2S_MCKOUT_ENABLE: I2S master clock output enable
+      \arg        I2S_MCKOUT_DISABLE: I2S master clock output disable
+    \param[out] none
+    \retval     none
+*/
+void i2s_psc_config(uint32_t spi_periph, uint32_t audiosample, uint32_t frameformat, uint32_t mckout)
+{
+    uint32_t i2sdiv = 2U, i2sof = 0U;
+    uint32_t clks = 0U;
+    uint32_t i2sclock = 0U;
+
+    /* deinitialize SPI_I2SPSC register */
+    SPI_I2SPSC(spi_periph) = SPI_I2SPSC_RESET;
+
+    /* get system clock */
+    i2sclock = rcu_clock_freq_get(CK_SYS);
+
+    /* configure the prescaler depending on the mclk output state, the frame format and audio sample rate */
+    if(I2S_MCKOUT_ENABLE == mckout) {
+        clks = (uint32_t)(((i2sclock / 256U) * 10U) / audiosample);
+    } else {
+        if(I2S_FRAMEFORMAT_DT16B_CH16B == frameformat) {
+            clks = (uint32_t)(((i2sclock / 32U) * 10U) / audiosample);
+        } else {
+            clks = (uint32_t)(((i2sclock / 64U) * 10U) / audiosample);
+        }
+    }
+
+    /* remove the floating point */
+    clks = (clks + 5U) / 10U;
+    i2sof = (clks & 0x00000001U);
+    i2sdiv = ((clks - i2sof) / 2U);
+    i2sof  = (i2sof << 8U);
+
+    /* set the default values */
+    if((i2sdiv < 2U) || (i2sdiv > 255U)) {
+        i2sdiv = 2U;
+        i2sof = 0U;
+    }
+
+    /* configure SPI_I2SPSC */
+    SPI_I2SPSC(spi_periph) = (uint32_t)(i2sdiv | i2sof | mckout);
+
+    /* clear SPI_I2SCTL_DTLEN and SPI_I2SCTL_CHLEN bits */
+    SPI_I2SCTL(spi_periph) &= (uint32_t)(~(SPI_I2SCTL_DTLEN | SPI_I2SCTL_CHLEN));
+    /* configure data frame format */
+    SPI_I2SCTL(spi_periph) |= (uint32_t)frameformat;
+}
+
+/*!
+    \brief      enable I2S
+    \param[in]  spi_periph: SPI0
+    \param[out] none
+    \retval     none
+*/
+void i2s_enable(uint32_t spi_periph)
+{
+    SPI_I2SCTL(spi_periph) |= (uint32_t)SPI_I2SCTL_I2SEN;
+}
+
+/*!
+    \brief      disable I2S
+    \param[in]  spi_periph: SPI0
+    \param[out] none
+    \retval     none
+*/
+void i2s_disable(uint32_t spi_periph)
+{
+    SPI_I2SCTL(spi_periph) &= (uint32_t)(~SPI_I2SCTL_I2SEN);
+}
+
+#endif /* GD32F370, GD32F355, GD32F350 and GD32F310 */
+
+/*!
+    \brief      enable SPI NSS output
+    \param[in]  spi_periph: SPIx(x=0,1)
+    \param[out] none
+    \retval     none
+*/
+void spi_nss_output_enable(uint32_t spi_periph)
+{
+    SPI_CTL1(spi_periph) |= (uint32_t)SPI_CTL1_NSSDRV;
+}
+
+/*!
+    \brief      disable SPI NSS output
+    \param[in]  spi_periph: SPIx(x=0,1)
+    \param[out] none
+    \retval     none
+*/
+void spi_nss_output_disable(uint32_t spi_periph)
+{
+    SPI_CTL1(spi_periph) &= (uint32_t)(~SPI_CTL1_NSSDRV);
+}
+
+/*!
+    \brief      pull NSS pin high in software mode
+    \param[in]  spi_periph: SPIx(x=0,1)
+    \param[out] none
+    \retval     none
+*/
+void spi_nss_internal_high(uint32_t spi_periph)
+{
+    SPI_CTL0(spi_periph) |= (uint32_t)SPI_CTL0_SWNSS;
+}
+
+/*!
+    \brief      pull NSS pin low in software mode
+    \param[in]  spi_periph: SPIx(x=0,1)
+    \param[out] none
+    \retval     none
+*/
+void spi_nss_internal_low(uint32_t spi_periph)
+{
+    SPI_CTL0(spi_periph) &= (uint32_t)(~SPI_CTL0_SWNSS);
+}
+
+/*!
+    \brief      enable SPI DMA send or receive
+    \param[in]  spi_periph: SPIx(x=0,1)
+    \param[in]  dma: SPI DMA mode
+                only one parameter can be selected which is shown as below:
+      \arg        SPI_DMA_TRANSMIT: SPI transmit data using DMA
+      \arg        SPI_DMA_RECEIVE: SPI receive data using DMA
+    \param[out] none
+    \retval     none
+*/
+void spi_dma_enable(uint32_t spi_periph, uint8_t dma)
+{
+    if(SPI_DMA_TRANSMIT == dma) {
+        SPI_CTL1(spi_periph) |= (uint32_t)SPI_CTL1_DMATEN;
+    } else {
+        SPI_CTL1(spi_periph) |= (uint32_t)SPI_CTL1_DMAREN;
+    }
+}
+
+/*!
+    \brief      disable SPI DMA send or receive
+    \param[in]  spi_periph: SPIx(x=0,1)
+    \param[in]  dma: SPI DMA mode
+                only one parameter can be selected which is shown as below:
+      \arg        SPI_DMA_TRANSMIT: SPI transmit data using DMA
+      \arg        SPI_DMA_RECEIVE: SPI receive data using DMA
+    \param[out] none
+    \retval     none
+*/
+void spi_dma_disable(uint32_t spi_periph, uint8_t dma)
+{
+    if(SPI_DMA_TRANSMIT == dma) {
+        SPI_CTL1(spi_periph) &= (uint32_t)(~SPI_CTL1_DMATEN);
+    } else {
+        SPI_CTL1(spi_periph) &= (uint32_t)(~SPI_CTL1_DMAREN);
+    }
+}
+
+/*!
+    \brief      configure SPI data frame format
+    \param[in]  spi_periph: SPIx(x=0,1)
+    \param[in]  frame_format: SPI frame size
+                only one parameter can be selected which is shown as below:
+      \arg        SPI_FRAMESIZE_16BIT: SPI frame size is 16 bits
+      \arg        SPI_FRAMESIZE_8BIT: SPI frame size is 8 bits
+    \param[out] none
+    \retval     none
+*/
+void spi_i2s_data_frame_format_config(uint32_t spi_periph, uint16_t frame_format)
+{
+    /* clear SPI_CTL0_FF16 bit */
+    SPI_CTL0(spi_periph) &= (uint32_t)(~SPI_CTL0_FF16);
+    /* configure SPI_CTL0_FF16 bit */
+    SPI_CTL0(spi_periph) |= (uint32_t)frame_format;
+}
+
+/*!
+    \brief      configure SPI bidirectional transfer direction
+    \param[in]  spi_periph: SPIx(x=0,1)
+    \param[in]  transfer_direction: SPI transfer direction
+                only one parameter can be selected which is shown as below:
+      \arg        SPI_BIDIRECTIONAL_TRANSMIT: SPI work in transmit-only mode
+      \arg        SPI_BIDIRECTIONAL_RECEIVE: SPI work in receive-only mode
+    \param[out] none
+    \retval     none
+*/
+void spi_bidirectional_transfer_config(uint32_t spi_periph, uint32_t transfer_direction)
+{
+    if(SPI_BIDIRECTIONAL_TRANSMIT == transfer_direction) {
+        /* set the transmit only mode */
+        SPI_CTL0(spi_periph) |= (uint32_t)SPI_BIDIRECTIONAL_TRANSMIT;
+    } else {
+        /* set the receive only mode */
+        SPI_CTL0(spi_periph) &= SPI_BIDIRECTIONAL_RECEIVE;
+    }
+}
+
+/*!
+    \brief      SPI transmit data
+    \param[in]  spi_periph: SPIx(x=0,1)
+    \param[in]  data: 16-bit data
+    \param[out] none
+    \retval     none
+*/
+void spi_i2s_data_transmit(uint32_t spi_periph, uint16_t data)
+{
+    SPI_DATA(spi_periph) = (uint32_t)data;
+}
+
+/*!
+    \brief      SPI receive data
+    \param[in]  spi_periph: SPIx(x=0,1)
+    \param[out] none
+    \retval     16-bit data
+*/
+uint16_t spi_i2s_data_receive(uint32_t spi_periph)
+{
+    return ((uint16_t)SPI_DATA(spi_periph));
+}
+
+/*!
+    \brief      clear SPI/I2S format error flag status
+    \param[in]  spi_periph: SPIx(x=0,1)
+    \param[in]  flag: SPI/I2S frame format error flag 
+      \arg        SPI_FLAG_FERR: only for SPI work in TI mode
+      \arg        I2S_FLAG_FERR: for I2S
+    \param[out] none
+    \retval     none
+*/
+void spi_i2s_format_error_clear(uint32_t spi_periph, uint32_t flag)
+{
+    SPI_STAT(spi_periph) = (uint32_t)(~flag);
+}
+
+/*!
+    \brief      set CRC polynomial
+    \param[in]  spi_periph: SPIx(x=0,1)
+    \param[in]  crc_poly: CRC polynomial value
+    \param[out] none
+    \retval     none
+*/
+void spi_crc_polynomial_set(uint32_t spi_periph, uint16_t crc_poly)
+{
+    /* enable SPI CRC */
+    SPI_CTL0(spi_periph) |= (uint32_t)SPI_CTL0_CRCEN;
+    /* set SPI CRC polynomial */
+    SPI_CRCPOLY(spi_periph) = (uint32_t)crc_poly;
+}
+
+/*!
+    \brief      get SPI CRC polynomial
+    \param[in]  spi_periph: SPIx(x=0,1)
+    \param[out] none
+    \retval     16-bit CRC polynomial
+*/
+uint16_t spi_crc_polynomial_get(uint32_t spi_periph)
+{
+    return ((uint16_t)SPI_CRCPOLY(spi_periph));
+}
+
+/*!
+    \brief      turn on CRC function
+    \param[in]  spi_periph: SPIx(x=0,1)
+    \param[out] none
+    \retval     none
+*/
+void spi_crc_on(uint32_t spi_periph)
+{
+    SPI_CTL0(spi_periph) |= (uint32_t)SPI_CTL0_CRCEN;
+}
+
+/*!
+    \brief      turn off CRC function
+    \param[in]  spi_periph: SPIx(x=0,1)
+    \param[out] none
+    \retval     none
+*/
+void spi_crc_off(uint32_t spi_periph)
+{
+    SPI_CTL0(spi_periph) &= (uint32_t)(~SPI_CTL0_CRCEN);
+}
+
+/*!
+    \brief      SPI next data is CRC value
+    \param[in]  spi_periph: SPIx(x=0,1)
+    \param[out] none
+    \retval     none
+*/
+void spi_crc_next(uint32_t spi_periph)
+{
+    SPI_CTL0(spi_periph) |= (uint32_t)SPI_CTL0_CRCNT;
+}
+
+/*!
+    \brief      get SPI CRC send value or receive value
+    \param[in]  spi_periph: SPIx(x=0,1)
+    \param[in]  crc: SPI crc value
+                only one parameter can be selected which is shown as below:
+      \arg        SPI_CRC_TX: get transmit crc value
+      \arg        SPI_CRC_RX: get receive crc value
+    \param[out] none
+    \retval     16-bit CRC value
+*/
+uint16_t spi_crc_get(uint32_t spi_periph, uint8_t crc)
+{
+    if(SPI_CRC_TX == crc) {
+        return ((uint16_t)(SPI_TCRC(spi_periph)));
+    } else {
+        return ((uint16_t)(SPI_RCRC(spi_periph)));
+    }
+}
+
+/*!
+    \brief      clear SPI CRC error flag status
+    \param[in]  spi_periph: SPIx(x=0,1)
+    \param[out] none
+    \retval     none
+*/
+void spi_crc_error_clear(uint32_t spi_periph)
+{
+    SPI_STAT(spi_periph) = (uint32_t)(~SPI_FLAG_CRCERR);
+}
+
+/*!
+    \brief      enable SPI TI mode
+    \param[in]  spi_periph: SPIx(x=0,1)
+    \param[out] none
+    \retval     none
+*/
+void spi_ti_mode_enable(uint32_t spi_periph)
+{
+    SPI_CTL1(spi_periph) |= (uint32_t)SPI_CTL1_TMOD;
+}
+
+/*!
+    \brief      disable SPI TI mode
+    \param[in]  spi_periph: SPIx(x=0,1)
+    \param[out] none
+    \retval     none
+*/
+void spi_ti_mode_disable(uint32_t spi_periph)
+{
+    SPI_CTL1(spi_periph) &= (uint32_t)(~SPI_CTL1_TMOD);
+}
+
+/*!
+    \brief      enable SPI NSS pulse mode
+    \param[in]  spi_periph: SPIx(x=0,1)
+    \param[out] none
+    \retval     none
+*/
+void spi_nssp_mode_enable(uint32_t spi_periph)
+{
+    SPI_CTL1(spi_periph) |= (uint32_t)SPI_CTL1_NSSP;
+}
+
+/*!
+    \brief      disable SPI NSS pulse mode
+    \param[in]  spi_periph: SPIx(x=0,1)
+    \param[out] none
+    \retval     none
+*/
+void spi_nssp_mode_disable(uint32_t spi_periph)
+{
+    SPI_CTL1(spi_periph) &= (uint32_t)(~SPI_CTL1_NSSP);
+}
+
+/*!
+    \brief      enable SPI quad wire mode
+    \param[in]  spi_periph: SPI1
+    \param[out] none
+    \retval     none
+*/
+void spi_quad_enable(uint32_t spi_periph)
+{
+    SPI_QCTL(spi_periph) |= (uint32_t)SPI_QCTL_QMOD;
+}
+
+/*!
+    \brief      disable SPI quad wire mode
+    \param[in]  spi_periph: SPI1
+    \param[out] none
+    \retval     none
+*/
+void spi_quad_disable(uint32_t spi_periph)
+{
+    SPI_QCTL(spi_periph) &= (uint32_t)(~SPI_QCTL_QMOD);
+}
+
+/*!
+    \brief      enable SPI quad wire mode write
+    \param[in]  spi_periph: SPI1
+    \param[out] none
+    \retval     none
+*/
+void spi_quad_write_enable(uint32_t spi_periph)
+{
+    SPI_QCTL(spi_periph) &= (uint32_t)(~SPI_QCTL_QRD);
+}
+
+/*!
+    \brief      enable SPI quad wire mode read
+    \param[in]  spi_periph: SPI1
+    \param[out] none
+    \retval     none
+*/
+void spi_quad_read_enable(uint32_t spi_periph)
+{
+    SPI_QCTL(spi_periph) |= (uint32_t)SPI_QCTL_QRD;
+}
+
+/*!
+    \brief      enable SPI quad wire mode SPI_IO2 and SPI_IO3 pin output
+    \param[in]  spi_periph: SPI1
+    \param[out] none
+    \retval     none
+*/
+void spi_quad_io23_output_enable(uint32_t spi_periph)
+{
+    SPI_QCTL(spi_periph) |= (uint32_t)SPI_QCTL_IO23_DRV;
+}
+
+/*!
+   \brief      disable SPI quad wire mode SPI_IO2 and SPI_IO3 pin output
+   \param[in]  spi_periph: SPI1
+   \param[out] none
+   \retval     none
+*/
+void spi_quad_io23_output_disable(uint32_t spi_periph)
+{
+    SPI_QCTL(spi_periph) &= (uint32_t)(~SPI_QCTL_IO23_DRV);
+}
+
+/*!
+    \brief      get SPI and I2S flag status
+    \param[in]  spi_periph: SPIx(x=0,1)
+    \param[in]  flag: SPI/I2S flag status
+                only one parameter can be selected which are shown as below:
+      \arg        SPI_FLAG_TBE: transmit buffer empty flag
+      \arg        SPI_FLAG_RBNE: receive buffer not empty flag
+      \arg        SPI_FLAG_TRANS: transmit on-going flag
+      \arg        SPI_FLAG_RXORERR: receive overrun error flag
+      \arg        SPI_FLAG_CONFERR: mode config error flag
+      \arg        SPI_FLAG_CRCERR: CRC error flag
+      \arg        SPI_FLAG_FERR: SPI format error interrupt flag
+      \arg        I2S_FLAG_TBE: transmit buffer empty flag
+      \arg        I2S_FLAG_RBNE: receive buffer not empty flag
+      \arg        I2S_FLAG_TRANS: transmit on-going flag
+      \arg        I2S_FLAG_RXORERR: overrun error flag
+      \arg        I2S_FLAG_TXURERR: underrun error flag
+      \arg        I2S_FLAG_CH: channel side flag
+      \arg        I2S_FLAG_FERR: I2S format error interrupt flag
+    \param[out] none
+    \retval     FlagStatus: SET or RESET
+*/
+FlagStatus spi_i2s_flag_get(uint32_t spi_periph, uint32_t flag)
+{
+    if(RESET != (SPI_STAT(spi_periph) & flag)) {
+        return SET;
+    } else {
+        return RESET;
+    }
+}
+
+/*!
+    \brief      enable SPI and I2S interrupt
+    \param[in]  spi_periph: SPIx(x=0,1)
+    \param[in]  interrupt: SPI/I2S interrupt
+                only one parameter can be selected which is shown as below:
+      \arg        SPI_I2S_INT_TBE: transmit buffer empty interrupt
+      \arg        SPI_I2S_INT_RBNE: receive buffer not empty interrupt
+      \arg        SPI_I2S_INT_ERR: CRC error,configuration error,reception overrun error,
+                                   transmission underrun error and format error interrupt
+    \param[out] none
+    \retval     none
+*/
+void spi_i2s_interrupt_enable(uint32_t spi_periph, uint8_t interrupt)
+{
+    SPI_CTL1(spi_periph) |= (uint32_t)interrupt;
+}
+
+/*!
+    \brief      disable SPI and I2S interrupt
+    \param[in]  spi_periph: SPIx(x=0,1)
+    \param[in]  interrupt: SPI/I2S interrupt
+                only one parameter can be selected which is shown as below:
+      \arg        SPI_I2S_INT_TBE: transmit buffer empty interrupt
+      \arg        SPI_I2S_INT_RBNE: receive buffer not empty interrupt
+      \arg        SPI_I2S_INT_ERR: CRC error,configuration error,reception overrun error,
+                                   transmission underrun error and format error interrupt
+    \param[out] none
+    \retval     none
+*/
+void spi_i2s_interrupt_disable(uint32_t spi_periph, uint8_t interrupt)
+{
+    SPI_CTL1(spi_periph) &= ~(uint32_t)interrupt;
+}
+
+/*!
+    \brief      get SPI and I2S interrupt flag status
+    \param[in]  spi_periph: SPIx(x=0,1)
+    \param[in]  interrupt: SPI/I2S interrupt flag status
+                only one parameter can be selected which is shown as below:
+      \arg        SPI_I2S_INT_FLAG_TBE: transmit buffer empty interrupt flag
+      \arg        SPI_I2S_INT_FLAG_RBNE: receive buffer not empty interrupt flag
+      \arg        SPI_I2S_INT_FLAG_RXORERR: overrun interrupt flag
+      \arg        SPI_INT_FLAG_CONFERR: config error interrupt flag
+      \arg        SPI_INT_FLAG_CRCERR: CRC error interrupt flag
+      \arg        I2S_INT_FLAG_TXURERR: underrun error interrupt flag
+      \arg        SPI_I2S_INT_FLAG_FERR: format error interrupt flag
+    \param[out] none
+    \retval     FlagStatus: SET or RESET
+*/
+FlagStatus spi_i2s_interrupt_flag_get(uint32_t spi_periph, uint8_t interrupt)
+{
+    uint32_t reg1 = SPI_STAT(spi_periph);
+    uint32_t reg2 = SPI_CTL1(spi_periph);
+
+    switch(interrupt) {
+    /* SPI/I2S transmit buffer empty interrupt */
+    case SPI_I2S_INT_FLAG_TBE:
+        reg1 = reg1 & SPI_STAT_TBE;
+        reg2 = reg2 & SPI_CTL1_TBEIE;
+        break;
+    /* SPI/I2S receive buffer not empty interrupt */
+    case SPI_I2S_INT_FLAG_RBNE:
+        reg1 = reg1 & SPI_STAT_RBNE;
+        reg2 = reg2 & SPI_CTL1_RBNEIE;
+        break;
+    /* SPI/I2S overrun interrupt */
+    case SPI_I2S_INT_FLAG_RXORERR:
+        reg1 = reg1 & SPI_STAT_RXORERR;
+        reg2 = reg2 & SPI_CTL1_ERRIE;
+        break;
+    /* SPI config error interrupt */
+    case SPI_INT_FLAG_CONFERR:
+        reg1 = reg1 & SPI_STAT_CONFERR;
+        reg2 = reg2 & SPI_CTL1_ERRIE;
+        break;
+    /* SPI CRC error interrupt */
+    case SPI_INT_FLAG_CRCERR:
+        reg1 = reg1 & SPI_STAT_CRCERR;
+        reg2 = reg2 & SPI_CTL1_ERRIE;
+        break;
+    /* I2S underrun error interrupt */
+    case I2S_INT_FLAG_TXURERR:
+        reg1 = reg1 & SPI_STAT_TXURERR;
+        reg2 = reg2 & SPI_CTL1_ERRIE;
+        break;
+    /* SPI/I2S format error interrupt */
+    case SPI_I2S_INT_FLAG_FERR:
+        reg1 = reg1 & SPI_STAT_FERR;
+        reg2 = reg2 & SPI_CTL1_ERRIE;
+        break;
+    default :
+        break;
+    }
+    /*get SPI/I2S interrupt flag status */
+    if((0U != reg1) && (0U != reg2)) {
+        return SET;
+    } else {
+        return RESET;
+    }
+}

+ 226 - 0
GD32F3x0/GD32F3x0_standard_peripheral/Source/gd32f3x0_syscfg.c

@@ -0,0 +1,226 @@
+/*!
+    \file    gd32f3x0_syscfg.c
+    \brief   SYSCFG driver
+
+    \version 2025-01-01, V2.5.0, firmware for GD32F3x0
+*/
+
+/*
+    Copyright (c) 2025, GigaDevice Semiconductor Inc.
+
+    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 of the copyright holder 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 HOLDER 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.
+*/
+
+#include "gd32f3x0_syscfg.h"
+
+/*!
+    \brief      reset the SYSCFG registers
+    \param[in]  none
+    \param[out] none
+    \retval     none
+*/
+void syscfg_deinit(void)
+{
+    rcu_periph_reset_enable(RCU_CFGCMPRST);
+    rcu_periph_reset_disable(RCU_CFGCMPRST);
+}
+
+/*!
+    \brief      enable the DMA channels remapping
+    \param[in]  syscfg_dma_remap: specify the DMA channels to remap
+                one or more parameters can be selected which is shown as below:
+      \arg        SYSCFG_DMA_REMAP_TIMER16: remap TIMER16 channel0 and UP DMA requests to channel1(defaut channel0)
+      \arg        SYSCFG_DMA_REMAP_TIMER15: remap TIMER15 channel2 and UP DMA requests to channel3(defaut channel2)
+      \arg        SYSCFG_DMA_REMAP_USART0RX: remap USART0 Rx DMA request to channel4(default channel2)
+      \arg        SYSCFG_DMA_REMAP_USART0TX: remap USART0 Tx DMA request to channel3(default channel1)
+      \arg        SYSCFG_DMA_REMAP_ADC: remap ADC DMA requests from channel0 to channel1
+    \param[out] none
+    \retval     none
+*/
+void syscfg_dma_remap_enable(uint32_t syscfg_dma_remap)
+{
+    SYSCFG_CFG0 |= syscfg_dma_remap;
+}
+
+/*!
+    \brief      disable the DMA channels remapping
+    \param[in]  syscfg_dma_remap: specify the DMA channels to remap
+                one or more parameters can be selected which is shown as below:
+      \arg        SYSCFG_DMA_REMAP_TIMER16: remap TIMER16 channel0 and UP DMA requests to channel1(defaut channel0)
+      \arg        SYSCFG_DMA_REMAP_TIMER15: remap TIMER15 channel2 and UP DMA requests to channel3(defaut channel2)
+      \arg        SYSCFG_DMA_REMAP_USART0RX: remap USART0 Rx DMA request to channel4(default channel2)
+      \arg        SYSCFG_DMA_REMAP_USART0TX: remap USART0 Tx DMA request to channel3(default channel1)
+      \arg        SYSCFG_DMA_REMAP_ADC: remap ADC DMA requests from channel0 to channel1
+    \param[out] none
+    \retval     none
+*/
+void syscfg_dma_remap_disable(uint32_t syscfg_dma_remap)
+{
+    SYSCFG_CFG0 &= ~syscfg_dma_remap;
+}
+
+/*!
+    \brief      enable PB9 high current capability
+    \param[in]  none
+    \param[out] none
+    \retval     none
+*/
+void syscfg_high_current_enable(void)
+{
+    SYSCFG_CFG0 |= SYSCFG_HIGH_CURRENT_ENABLE;
+}
+
+/*!
+    \brief      disable PB9 high current capability
+    \param[in]  none
+    \param[out] none
+    \retval     none
+*/
+void syscfg_high_current_disable(void)
+{
+    SYSCFG_CFG0 &= SYSCFG_HIGH_CURRENT_DISABLE;
+}
+
+/*!
+    \brief      configure the GPIO pin as EXTI Line
+    \param[in]  exti_port: specify the GPIO port used in EXTI
+                only one parameter can be selected which is shown as below:
+      \arg        EXTI_SOURCE_GPIOx(x = A,B,C,D,F): EXTI GPIO port
+    \param[in]  exti_pin: specify the EXTI line
+                only one parameter can be selected which is shown as below:
+      \arg        EXTI_SOURCE_PINx(x = 0..15): EXTI GPIO pin
+    \param[out] none
+    \retval     none
+*/
+void syscfg_exti_line_config(uint8_t exti_port, uint8_t exti_pin)
+{
+    uint32_t clear_exti_mask = ~((uint32_t)EXTI_SS_MASK << (EXTI_SS_MSTEP(exti_pin)));
+    uint32_t config_exti_mask = ((uint32_t)exti_port) << (EXTI_SS_MSTEP(exti_pin));
+
+    switch(exti_pin / EXTI_SS_JSTEP) {
+    case EXTISS0:
+        /* clear EXTI source line(0..3) */
+        SYSCFG_EXTISS0 &= clear_exti_mask;
+        /* configure EXTI soure line(0..3) */
+        SYSCFG_EXTISS0 |= config_exti_mask;
+        break;
+    case EXTISS1:
+        /* clear EXTI soure line(4..7) */
+        SYSCFG_EXTISS1 &= clear_exti_mask;
+        /* configure EXTI soure line(4..7) */
+        SYSCFG_EXTISS1 |= config_exti_mask;
+        break;
+    case EXTISS2:
+        /* clear EXTI soure line(8..11) */
+        SYSCFG_EXTISS2 &= clear_exti_mask;
+        /* configure EXTI soure line(8..11) */
+        SYSCFG_EXTISS2 |= config_exti_mask;
+        break;
+    case EXTISS3:
+        /* clear EXTI soure line(12..15) */
+        SYSCFG_EXTISS3 &= clear_exti_mask;
+        /* configure EXTI soure line(12..15) */
+        SYSCFG_EXTISS3 |= config_exti_mask;
+        break;
+    default:
+        break;
+    }
+}
+
+/*!
+    \brief      connect TIMER0/14/15/16 break input to the selected parameter
+    \param[in]  syscfg_lock: Specify the parameter to be connected
+                one or more parameters can be selected which is shown as below:
+      \arg        SYSCFG_LOCK_LOCKUP: Cortex-M4 lockup output connected to the break input
+      \arg        SYSCFG_LOCK_SRAM_PARITY_ERROR: SRAM_PARITY check error connected to the break input
+      \arg        SYSCFG_LOCK_LVD: LVD interrupt connected to the break input
+    \param[out] none
+    \retval     none
+*/
+void syscfg_lock_config(uint32_t syscfg_lock)
+{
+    SYSCFG_CFG2 |= syscfg_lock;
+}
+
+/*!
+    \brief      check if the specified flag in SYSCFG_CFG2 is set or not.
+    \param[in]  syscfg_flag: specify the flag in SYSCFG_CFG2 to check.
+      \arg        SYSCFG_SRAM_PCEF: SRAM parity check error flag.
+    \param[out] none
+    \retval     the syscfg_flag state returned (SET or RESET).
+  */
+FlagStatus syscfg_flag_get(uint32_t syscfg_flag)
+{
+    if((SYSCFG_CFG2 & syscfg_flag) != (uint32_t)RESET) {
+        return SET;
+    } else {
+        return RESET;
+    }
+}
+
+/*!
+    \brief      clear the flag in SYSCFG_CFG2 by writing 1.
+    \param[in]  syscfg_flag: Specify the flag in SYSCFG_CFG2 to clear.
+      \arg        SYSCFG_SRAM_PCEF: SRAM parity check error flag.
+    \param[out] none
+    \retval     none
+*/
+void syscfg_flag_clear(uint32_t syscfg_flag)
+{
+    SYSCFG_CFG2 |= (uint32_t) syscfg_flag;
+}
+
+/*!
+    \brief      configure the I/O compensation cell
+    \param[in]  syscfg_compensation: specifies the I/O compensation cell mode
+                only one parameter can be selected which is shown as below:
+      \arg        SYSCFG_COMPENSATION_ENABLE: I/O compensation cell is enabled
+      \arg        SYSCFG_COMPENSATION_DISABLE: I/O compensation cell is disabled
+    \param[out] none
+    \retval     none
+*/
+void syscfg_compensation_config(uint32_t syscfg_compensation)
+{
+    uint32_t reg;
+
+    reg = SYSCFG_CPSCTL;
+    /* reset the SYSCFG_CPSCTL_CPS_EN bit and set according to syscfg_compensation */
+    reg &= ~SYSCFG_CPSCTL_CPS_EN;
+    SYSCFG_CPSCTL = (reg | syscfg_compensation);
+}
+
+/*!
+    \brief      check if the I/O compensation cell ready flag is set or not
+    \param[in]  none
+    \param[out] none
+    \retval     FlagStatus: SET or RESET
+  */
+FlagStatus syscfg_cps_rdy_flag_get(void)
+{
+    if(((uint32_t)RESET) != (SYSCFG_CPSCTL & SYSCFG_CPSCTL_CPS_RDY)) {
+        return SET;
+    } else {
+        return RESET;
+    }
+}

+ 2082 - 0
GD32F3x0/GD32F3x0_standard_peripheral/Source/gd32f3x0_timer.c

@@ -0,0 +1,2082 @@
+/*!
+    \file    gd32f3x0_timer.c
+    \brief   TIMER driver
+
+    \version 2025-01-01, V2.5.0, firmware for GD32F3x0
+*/
+
+/*
+    Copyright (c) 2025, GigaDevice Semiconductor Inc.
+
+    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 of the copyright holder 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 HOLDER 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.
+*/
+
+
+#include "gd32f3x0_timer.h"
+
+/*!
+    \brief      deinit a TIMER
+    \param[in]  timer_periph: TIMERx(x=0,2,13..16), TIMER1(not available in GD32F310), TIMER5(not available in GD32F310 and GD32F330)
+    \param[out] none
+    \retval     none
+*/
+void timer_deinit(uint32_t timer_periph)
+{
+    switch(timer_periph) {
+    case TIMER0:
+        /* reset TIMER0 */
+        rcu_periph_reset_enable(RCU_TIMER0RST);
+        rcu_periph_reset_disable(RCU_TIMER0RST);
+        break;
+#if (!defined (GD32F310))
+    case TIMER1:
+        /* reset TIMER1 */
+        rcu_periph_reset_enable(RCU_TIMER1RST);
+        rcu_periph_reset_disable(RCU_TIMER1RST);
+        break;
+#endif
+    case TIMER2:
+        /* reset TIMER2 */
+        rcu_periph_reset_enable(RCU_TIMER2RST);
+        rcu_periph_reset_disable(RCU_TIMER2RST);
+        break;
+#if (defined(GD32F350) || defined(GD32F355) || defined(GD32F370))
+    case TIMER5:
+        /* reset TIMER5 */
+        rcu_periph_reset_enable(RCU_TIMER5RST);
+        rcu_periph_reset_disable(RCU_TIMER5RST);
+        break;
+#endif
+    case TIMER13:
+        /* reset TIMER13 */
+        rcu_periph_reset_enable(RCU_TIMER13RST);
+        rcu_periph_reset_disable(RCU_TIMER13RST);
+        break;
+    case TIMER14:
+        /* reset TIMER14 */
+        rcu_periph_reset_enable(RCU_TIMER14RST);
+        rcu_periph_reset_disable(RCU_TIMER14RST);
+        break;
+    case TIMER15:
+        /* reset TIMER15 */
+        rcu_periph_reset_enable(RCU_TIMER15RST);
+        rcu_periph_reset_disable(RCU_TIMER15RST);
+        break;
+    case TIMER16:
+        /* reset TIMER16 */
+        rcu_periph_reset_enable(RCU_TIMER16RST);
+        rcu_periph_reset_disable(RCU_TIMER16RST);
+        break;
+    default:
+        break;
+    }
+}
+
+/*!
+    \brief      initialize TIMER init parameter struct with a default value
+    \param[in]  initpara: init parameter struct
+    \param[out] none
+    \retval     none
+*/
+void timer_struct_para_init(timer_parameter_struct *initpara)
+{
+    /* initialize the init parameter struct member with the default value */
+    initpara->prescaler         = 0U;
+    initpara->alignedmode       = TIMER_COUNTER_EDGE;
+    initpara->counterdirection  = TIMER_COUNTER_UP;
+    initpara->period            = 65535U;
+    initpara->clockdivision     = TIMER_CKDIV_DIV1;
+    initpara->repetitioncounter = 0U;
+}
+
+/*!
+    \brief      initialize TIMER counter
+    \param[in]  timer_periph: TIMERx(x=0,2,13..16), TIMER1(not available in GD32F310), TIMER5(not available in GD32F310 and GD32F330)
+    \param[in]  timer_initpara: init parameter struct
+                prescaler: prescaler value of the counter clock,0~65535
+                alignedmode: TIMER_COUNTER_EDGE,TIMER_COUNTER_CENTER_DOWN,TIMER_COUNTER_CENTER_UP,TIMER_COUNTER_CENTER_BOTH
+                counterdirection: TIMER_COUNTER_UP,TIMER_COUNTER_DOWN
+                period: counter auto reload value,(TIMER1 32 bit)
+                clockdivision: TIMER_CKDIV_DIV1,TIMER_CKDIV_DIV2,TIMER_CKDIV_DIV4
+                repetitioncounter: counter repetition value,0~255
+    \param[out] none
+    \retval     none
+*/
+void timer_init(uint32_t timer_periph, timer_parameter_struct *initpara)
+{
+    /* configure the counter prescaler value */
+    TIMER_PSC(timer_periph) = (uint16_t)initpara->prescaler;
+
+#if (!defined (GD32F310))
+    /* configure the counter direction and aligned mode */
+    if((TIMER0 == timer_periph) || (TIMER1 == timer_periph) || (TIMER2 == timer_periph)) {
+        TIMER_CTL0(timer_periph) &= ~(uint32_t)(TIMER_CTL0_DIR | TIMER_CTL0_CAM);
+        TIMER_CTL0(timer_periph) |= (uint32_t)initpara->alignedmode;
+        TIMER_CTL0(timer_periph) |= (uint32_t)initpara->counterdirection;
+    }
+
+    /* configure the autoreload value */
+    TIMER_CAR(timer_periph) = (uint32_t)initpara->period;
+
+    if((TIMER0 == timer_periph) || (TIMER1 == timer_periph) || (TIMER2 == timer_periph) || (TIMER13 == timer_periph)
+            || (TIMER14 == timer_periph) || (TIMER15 == timer_periph) || (TIMER16 == timer_periph)) {
+        /* reset the CKDIV bit */
+        TIMER_CTL0(timer_periph) &= ~(uint32_t)TIMER_CTL0_CKDIV;
+        TIMER_CTL0(timer_periph) |= (uint32_t)initpara->clockdivision;
+    }
+#else
+    /* configure the counter direction and aligned mode */
+    if((TIMER0 == timer_periph)  || (TIMER2 == timer_periph)) {
+        TIMER_CTL0(timer_periph) &= ~(uint32_t)(TIMER_CTL0_DIR | TIMER_CTL0_CAM);
+        TIMER_CTL0(timer_periph) |= (uint32_t)initpara->alignedmode;
+        TIMER_CTL0(timer_periph) |= (uint32_t)initpara->counterdirection;
+    }
+
+    /* configure the autoreload value */
+    TIMER_CAR(timer_periph) = (uint32_t)initpara->period;
+
+    if((TIMER0 == timer_periph) || (TIMER2 == timer_periph) || (TIMER13 == timer_periph)
+            || (TIMER14 == timer_periph) || (TIMER15 == timer_periph) || (TIMER16 == timer_periph)) {
+        /* reset the CKDIV bit */
+        TIMER_CTL0(timer_periph) &= ~(uint32_t)TIMER_CTL0_CKDIV;
+        TIMER_CTL0(timer_periph) |= (uint32_t)initpara->clockdivision;
+    }
+#endif
+
+    if((TIMER0 == timer_periph) || (TIMER14 == timer_periph) || (TIMER15 == timer_periph) || (TIMER16 == timer_periph)) {
+        /* configure the repetition counter value */
+        TIMER_CREP(timer_periph) = (uint32_t)initpara->repetitioncounter;
+    }
+
+    /* generate an update event */
+    TIMER_SWEVG(timer_periph) |= (uint32_t)TIMER_SWEVG_UPG;
+}
+
+/*!
+    \brief      enable a TIMER
+    \param[in]  timer_periph: TIMERx(x=0,2,13..16), TIMER1(not available in GD32F310), TIMER5(not available in GD32F310 and GD32F330)
+    \param[out] none
+    \retval     none
+*/
+void timer_enable(uint32_t timer_periph)
+{
+    TIMER_CTL0(timer_periph) |= (uint32_t)TIMER_CTL0_CEN;
+}
+
+/*!
+    \brief      disable a TIMER
+    \param[in]  timer_periph: TIMERx(x=0,2,13..16), TIMER1(not available in GD32F310), TIMER5(not available in GD32F310 and GD32F330)
+    \param[out] none
+    \retval     none
+*/
+void timer_disable(uint32_t timer_periph)
+{
+    TIMER_CTL0(timer_periph) &= ~(uint32_t)TIMER_CTL0_CEN;
+}
+
+/*!
+    \brief      enable the auto reload shadow function
+    \param[in]  timer_periph: TIMERx(x=0,2,13..16), TIMER1(not available in GD32F310), TIMER5(not available in GD32F310 and GD32F330)
+    \param[out] none
+    \retval     none
+*/
+void timer_auto_reload_shadow_enable(uint32_t timer_periph)
+{
+    TIMER_CTL0(timer_periph) |= (uint32_t)TIMER_CTL0_ARSE;
+}
+
+/*!
+    \brief      disable the auto reload shadow function
+    \param[in]  timer_periph: TIMERx(x=0,2,13..16), TIMER1(not available in GD32F310), TIMER5(not available in GD32F310 and GD32F330)
+    \param[out] none
+    \retval     none
+*/
+void timer_auto_reload_shadow_disable(uint32_t timer_periph)
+{
+    TIMER_CTL0(timer_periph) &= ~(uint32_t)TIMER_CTL0_ARSE;
+}
+
+/*!
+    \brief      enable the update event
+    \param[in]  timer_periph: TIMERx(x=0,2,13..16), TIMER1(not available in GD32F310), TIMER5(not available in GD32F310 and GD32F330)
+    \param[out] none
+    \retval     none
+*/
+void timer_update_event_enable(uint32_t timer_periph)
+{
+    TIMER_CTL0(timer_periph) &= ~(uint32_t)TIMER_CTL0_UPDIS;
+}
+
+/*!
+    \brief      disable the update event
+    \param[in]  timer_periph: TIMERx(x=0,2,13..16), TIMER1(not available in GD32F310), TIMER5(not available in GD32F310 and GD32F330)
+    \param[out] none
+    \retval     none
+*/
+void timer_update_event_disable(uint32_t timer_periph)
+{
+    TIMER_CTL0(timer_periph) |= (uint32_t) TIMER_CTL0_UPDIS;
+}
+
+/*!
+    \brief      set TIMER counter alignment mode
+    \param[in]  timer_periph: TIMERx(x=0,2), TIMER1(not available in GD32F310)
+    \param[in]  aligned:
+                only one parameter can be selected which is shown as below:
+      \arg        TIMER_COUNTER_EDGE: edge-aligned mode
+      \arg        TIMER_COUNTER_CENTER_DOWN: center-aligned and counting down assert mode
+      \arg        TIMER_COUNTER_CENTER_UP: center-aligned and counting up assert mode
+      \arg        TIMER_COUNTER_CENTER_BOTH: center-aligned and counting up/down assert mode
+    \param[out] none
+    \retval     none
+*/
+void timer_counter_alignment(uint32_t timer_periph, uint16_t aligned)
+{
+    TIMER_CTL0(timer_periph) &= ~(uint32_t)TIMER_CTL0_CAM;
+    TIMER_CTL0(timer_periph) |= (uint32_t)aligned;
+}
+
+/*!
+    \brief      set TIMER counter up direction
+    \param[in]  timer_periph: TIMERx(x=0,2), TIMER1(not available in GD32F310)
+    \param[out] none
+    \retval     none
+*/
+void timer_counter_up_direction(uint32_t timer_periph)
+{
+    TIMER_CTL0(timer_periph) &= ~(uint32_t)TIMER_CTL0_DIR;
+}
+
+/*!
+    \brief      set TIMER counter down direction
+    \param[in]  timer_periph: TIMERx(x=0,2), TIMER1(not available in GD32F310)
+    \param[out] none
+    \retval     none
+*/
+void timer_counter_down_direction(uint32_t timer_periph)
+{
+    TIMER_CTL0(timer_periph) |= (uint32_t)TIMER_CTL0_DIR;
+}
+
+/*!
+    \brief      configure TIMER prescaler
+    \param[in]  timer_periph: TIMERx(x=0,2,13..16), TIMER1(not available in GD32F310), TIMER5(not available in GD32F310 and GD32F330)
+    \param[in]  prescaler: prescaler value
+    \param[in]  pscreload: prescaler reload mode
+                only one parameter can be selected which is shown as below:
+      \arg        TIMER_PSC_RELOAD_NOW: the prescaler is loaded right now
+      \arg        TIMER_PSC_RELOAD_UPDATE: the prescaler is loaded at the next update event
+    \param[out] none
+    \retval     none
+*/
+void timer_prescaler_config(uint32_t timer_periph, uint16_t prescaler, uint8_t pscreload)
+{
+    TIMER_PSC(timer_periph) = (uint32_t)prescaler;
+
+    if(TIMER_PSC_RELOAD_NOW == pscreload) {
+        TIMER_SWEVG(timer_periph) |= (uint32_t)TIMER_SWEVG_UPG;
+    }
+}
+
+/*!
+    \brief      configure TIMER repetition register value
+    \param[in]  timer_periph: TIMERx(x=0,15,16)
+    \param[in]  repetition: the counter repetition value,0~255
+    \param[out] none
+    \retval     none
+*/
+void timer_repetition_value_config(uint32_t timer_periph, uint16_t repetition)
+{
+    TIMER_CREP(timer_periph) = (uint32_t)repetition;
+}
+
+/*!
+    \brief      configure TIMER autoreload register value
+    \param[in]  timer_periph: TIMERx(x=0,2,13..16), TIMER1(not available in GD32F310), TIMER5(not available in GD32F310 and GD32F330)
+    \param[in]  autoreload: the counter auto-reload value
+    \param[out] none
+    \retval     none
+*/
+void timer_autoreload_value_config(uint32_t timer_periph, uint32_t autoreload)
+{
+    TIMER_CAR(timer_periph) = (uint32_t)autoreload;
+}
+
+/*!
+    \brief      configure TIMER counter register value
+    \param[in]  timer_periph: TIMERx(x=0,2,13..16), TIMER1(not available in GD32F310), TIMER5(not available in GD32F310 and GD32F330)
+    \param[in]  counter: the counter value
+    \param[out] none
+    \retval     none
+*/
+void timer_counter_value_config(uint32_t timer_periph, uint32_t counter)
+{
+    TIMER_CNT(timer_periph) = (uint32_t)counter;
+}
+
+/*!
+    \brief      read TIMER counter value
+    \param[in]  timer_periph: TIMERx(x=0,2,13..16), TIMER1(not available in GD32F310), TIMER5(not available in GD32F310 and GD32F330)
+    \param[out] none
+    \retval     counter value
+*/
+uint32_t timer_counter_read(uint32_t timer_periph)
+{
+    uint32_t count_value = 0U;
+    count_value = TIMER_CNT(timer_periph);
+    return (count_value);
+}
+
+/*!
+    \brief      read TIMER prescaler value
+    \param[in]  timer_periph: TIMERx(x=0,2,13..16), TIMER1(not available in GD32F310), TIMER5(not available in GD32F310 and GD32F330)
+    \param[out] none
+    \retval     prescaler register value
+*/
+uint16_t timer_prescaler_read(uint32_t timer_periph)
+{
+    uint16_t prescaler_value = 0U;
+    prescaler_value = (uint16_t)(TIMER_PSC(timer_periph));
+    return (prescaler_value);
+}
+
+/*!
+    \brief      configure TIMER single pulse mode
+    \param[in]  timer_periph: TIMERx(x=0,2,14..16), TIMER1(not available in GD32F310), TIMER5(not available in GD32F310 and GD32F330)
+    \param[in]  spmode:
+                only one parameter can be selected which is shown as below:
+      \arg        TIMER_SP_MODE_SINGLE: single pulse mode
+      \arg        TIMER_SP_MODE_REPETITIVE: repetitive pulse mode
+    \param[out] none
+    \retval     none
+*/
+void timer_single_pulse_mode_config(uint32_t timer_periph, uint8_t spmode)
+{
+    if(TIMER_SP_MODE_SINGLE == spmode) {
+        TIMER_CTL0(timer_periph) |= (uint32_t)TIMER_CTL0_SPM;
+    } else if(TIMER_SP_MODE_REPETITIVE == spmode) {
+        TIMER_CTL0(timer_periph) &= ~((uint32_t)TIMER_CTL0_SPM);
+    } else {
+        /* illegal parameters */
+    }
+}
+
+/*!
+    \brief      configure TIMER update source
+    \param[in]  timer_periph: TIMERx(x=0,2,13..16), TIMER1(not available in GD32F310), TIMER5(not available in GD32F310 and GD32F330)
+    \param[in]  update:
+                only one parameter can be selected which is shown as below:
+      \arg        TIMER_UPDATE_SRC_GLOBAL: update generate by setting of UPG bit or the counter overflow/underflow,or the slave mode controller trigger
+      \arg        TIMER_UPDATE_SRC_REGULAR: update generate only by counter overflow/underflow
+    \param[out] none
+    \retval     none
+*/
+void timer_update_source_config(uint32_t timer_periph, uint8_t update)
+{
+    if(TIMER_UPDATE_SRC_REGULAR == update) {
+        TIMER_CTL0(timer_periph) |= (uint32_t)TIMER_CTL0_UPS;
+    } else if(TIMER_UPDATE_SRC_GLOBAL == update) {
+        TIMER_CTL0(timer_periph) &= ~(uint32_t)TIMER_CTL0_UPS;
+    } else {
+        /* illegal parameters */
+    }
+}
+
+/*!
+    \brief      configure TIMER OCPRE clear source selection
+    \param[in]  timer_periph: TIMERx(x=0,2), TIMER1(not available in GD32F310)
+    \param[in]  ocpreclear:
+                only one parameter can be selected which is shown as below:
+      \arg        TIMER_OCPRE_CLEAR_SOURCE_CLR: OCPRE_CLR_INT is connected to the OCPRE_CLR input
+      \arg        TIMER_OCPRE_CLEAR_SOURCE_ETIF: OCPRE_CLR_INT is connected to ETIF
+    \param[out] none
+    \retval     none
+*/
+void timer_ocpre_clear_source_config(uint32_t timer_periph, uint8_t ocpreclear)
+{
+    if(TIMER_OCPRE_CLEAR_SOURCE_ETIF == ocpreclear) {
+        TIMER_SMCFG(timer_periph) |= (uint32_t)TIMER_SMCFG_OCRC;
+    } else if(TIMER_OCPRE_CLEAR_SOURCE_CLR == ocpreclear) {
+        TIMER_SMCFG(timer_periph) &= ~(uint32_t)TIMER_SMCFG_OCRC;
+    } else {
+        /* illegal parameters */
+    }
+}
+
+/*!
+    \brief      get TIMER flags
+    \param[in]  timer_periph: please refer to the following parameters
+    \param[in]  flag: the timer interrupt flags
+                only one parameter can be selected which is shown as below:
+      \arg        TIMER_FLAG_UP: update flag, TIMERx(x=0,2,5,13..16), TIMER1(not available in GD32F310), TIMER5(not available in GD32F310 and GD32F330)
+      \arg        TIMER_FLAG_CH0: channel 0 flag, TIMERx(x=0,2,13..16), TIMER1(not available in GD32F310)
+      \arg        TIMER_FLAG_CH1: channel 1 flag, TIMERx(x=0,2,14), TIMER1(not available in GD32F310)
+      \arg        TIMER_FLAG_CH2: channel 2 flag, TIMERx(x=0,2), TIMER1(not available in GD32F310)
+      \arg        TIMER_FLAG_CH3: channel 3 flag, TIMERx(x=0,2), TIMER1(not available in GD32F310)
+      \arg        TIMER_FLAG_CMT: channel control update flag, TIMERx(x=0,14..16)
+      \arg        TIMER_FLAG_TRG: trigger flag, TIMERx(x=0,2,14), TIMER1(not available in GD32F310)
+      \arg        TIMER_FLAG_BRK: break flag,TIMERx(x=0,14..16)
+      \arg        TIMER_FLAG_CH0O: channel 0 overcapture flag, TIMERx(x=0,2,13..16), TIMER1(not available in GD32F310)
+      \arg        TIMER_FLAG_CH1O: channel 1 overcapture flag, TIMERx(x=0,2,14), TIMER1(not available in GD32F310)
+      \arg        TIMER_FLAG_CH2O: channel 2 overcapture flag, TIMERx(x=0,2), TIMER1(not available in GD32F310)
+      \arg        TIMER_FLAG_CH3O: channel 3 overcapture flag, TIMERx(x=0,2), TIMER1(not available in GD32F310)
+    \param[out] none
+    \retval     FlagStatus: SET or RESET
+*/
+FlagStatus timer_flag_get(uint32_t timer_periph, uint32_t flag)
+{
+    if(RESET != (TIMER_INTF(timer_periph) & flag)) {
+        return SET;
+    } else {
+        return RESET;
+    }
+}
+
+/*!
+    \brief      clear TIMER flags
+    \param[in]  timer_periph: please refer to the following parameters
+    \param[in]  flag: the timer interrupt flags
+                only one parameter can be selected which is shown as below:
+      \arg        TIMER_FLAG_UP: update flag, TIMERx(x=0,2,13..16), TIMER1(not available in GD32F310), TIMER5(not available in GD32F310 and GD32F330)
+      \arg        TIMER_FLAG_CH0: channel 0 flag, TIMERx(x=0,2,13..16), TIMER1(not available in GD32F310)
+      \arg        TIMER_FLAG_CH1: channel 1 flag, TIMERx(x=0,2,14), TIMER1(not available in GD32F310)
+      \arg        TIMER_FLAG_CH2: channel 2 flag, TIMERx(x=0,2), TIMER1(not available in GD32F310)
+      \arg        TIMER_FLAG_CH3: channel 3 flag, TIMERx(x=0,2), TIMER1(not available in GD32F310)
+      \arg        TIMER_FLAG_CMT: channel control update flag, TIMERx(x=0,14..16)
+      \arg        TIMER_FLAG_TRG: trigger flag, TIMERx(x=0,2,14), TIMER1(not available in GD32F310)
+      \arg        TIMER_FLAG_BRK: break flag,TIMERx(x=0,14..16)
+      \arg        TIMER_FLAG_CH0O: channel 0 overcapture flag, TIMERx(x=0,2,13..16), TIMER1(not available in GD32F310)
+      \arg        TIMER_FLAG_CH1O: channel 1 overcapture flag, TIMERx(x=0,2,14), TIMER1(not available in GD32F310)
+      \arg        TIMER_FLAG_CH2O: channel 2 overcapture flag, TIMERx(x=0,2), TIMER1(not available in GD32F310)
+      \arg        TIMER_FLAG_CH3O: channel 3 overcapture flag, TIMERx(x=0,2), TIMER1(not available in GD32F310)
+    \param[out] none
+    \retval     none
+*/
+void timer_flag_clear(uint32_t timer_periph, uint32_t flag)
+{
+    TIMER_INTF(timer_periph) = (~(uint32_t)flag);
+}
+
+/*!
+    \brief      enable the TIMER interrupt
+    \param[in]  timer_periph: please refer to the following parameters
+    \param[in]  interrupt: timer interrupt enable source
+                only one parameter can be selected which is shown as below:
+      \arg        TIMER_INT_UP: update interrupt enable, TIMERx(x=0,2,13..16), TIMER1(not available in GD32F310), TIMER5(not available in GD32F310 and GD32F330)
+      \arg        TIMER_INT_CH0: channel 0 interrupt enable, TIMERx(x=0,2,13..16), TIMER1(not available in GD32F310)
+      \arg        TIMER_INT_CH1: channel 1 interrupt enable, TIMERx(x=0,2,14), TIMER1(not available in GD32F310)
+      \arg        TIMER_INT_CH2: channel 2 interrupt enable, TIMERx(x=0,2), TIMER1(not available in GD32F310)
+      \arg        TIMER_INT_CH3: channel 3 interrupt enable , TIMERx(x=0,2), TIMER1(not available in GD32F310)
+      \arg        TIMER_INT_CMT: commutation interrupt enable, TIMERx(x=0,14..16)
+      \arg        TIMER_INT_TRG: trigger interrupt enable, TIMERx(x=0,2,14), TIMER1(not available in GD32F310)
+      \arg        TIMER_INT_BRK: break interrupt enable, TIMERx(x=0,14..16)
+    \param[out] none
+    \retval     none
+*/
+void timer_interrupt_enable(uint32_t timer_periph, uint32_t interrupt)
+{
+    TIMER_DMAINTEN(timer_periph) |= (uint32_t) interrupt;
+}
+
+/*!
+    \brief      disable the TIMER interrupt
+    \param[in]  timer_periph: please refer to the following parameters
+    \param[in]  interrupt: timer interrupt source disable
+                only one parameter can be selected which is shown as below:
+      \arg        TIMER_INT_UP: update interrupt disable, TIMERx(x=0,2,13..16), TIMER1(not available in GD32F310), TIMER5(not available in GD32F310 and GD32F330)
+      \arg        TIMER_INT_CH0: channel 0 interrupt disable, TIMERx(x=0,2,13..16), TIMER1(not available in GD32F310)
+      \arg        TIMER_INT_CH1: channel 1 interrupt disable, TIMERx(x=0,2,14), TIMER1(not available in GD32F310)
+      \arg        TIMER_INT_CH2: channel 2 interrupt disable, TIMERx(x=0,2), TIMER1(not available in GD32F310)
+      \arg        TIMER_INT_CH3: channel 3 interrupt disable , TIMERx(x=0,2), TIMER1(not available in GD32F310)
+      \arg        TIMER_INT_CMT: commutation interrupt disable, TIMERx(x=0,14..16)
+      \arg        TIMER_INT_TRG: trigger interrupt disable, TIMERx(x=0,2,14), TIMER1(not available in GD32F310)
+      \arg        TIMER_INT_BRK: break interrupt disable, TIMERx(x=0,14..16)
+    \param[out] none
+    \retval     none
+*/
+void timer_interrupt_disable(uint32_t timer_periph, uint32_t interrupt)
+{
+    TIMER_DMAINTEN(timer_periph) &= (~(uint32_t)interrupt);
+}
+
+/*!
+    \brief      get timer interrupt flag
+    \param[in]  timer_periph: please refer to the following parameters
+    \param[in]  interrupt: the timer interrupt bits
+                only one parameter can be selected which is shown as below:
+      \arg        TIMER_INT_FLAG_UP: update interrupt flag,TIMERx(x=0,2,13..16), TIMER1(not available in GD32F310), TIMER5(not available in GD32F310 and GD32F330)
+      \arg        TIMER_INT_FLAG_CH0: channel 0 interrupt flag,TIMERx(x=0,2,13..16), TIMER1(not available in GD32F310)
+      \arg        TIMER_INT_FLAG_CH1: channel 1 interrupt flag,TIMERx(x=0,2,14), TIMER1(not available in GD32F310)
+      \arg        TIMER_INT_FLAG_CH2: channel 2 interrupt flag,TIMERx(x=0,2), TIMER1(not available in GD32F310)
+      \arg        TIMER_INT_FLAG_CH3: channel 3 interrupt flag,TIMERx(x=0,2), TIMER1(not available in GD32F310)
+      \arg        TIMER_INT_FLAG_CMT: channel commutation interrupt flag,TIMERx(x=0,14..16)
+      \arg        TIMER_INT_FLAG_TRG: trigger interrupt flag,TIMERx(x=0,2,14), TIMER1(not available in GD32F310)
+      \arg        TIMER_INT_FLAG_BRK:  break interrupt flag,TIMERx(x=0,14..16)
+    \param[out] none
+    \retval     FlagStatus: SET or RESET
+*/
+FlagStatus timer_interrupt_flag_get(uint32_t timer_periph, uint32_t interrupt)
+{
+    uint32_t val;
+    val = (TIMER_DMAINTEN(timer_periph) & interrupt);
+    if((RESET != (TIMER_INTF(timer_periph) & interrupt)) && (RESET != val)) {
+        return SET;
+    } else {
+        return RESET;
+    }
+}
+
+/*!
+    \brief      clear TIMER interrupt flag
+    \param[in]  timer_periph: please refer to the following parameters
+    \param[in]  interrupt: the timer interrupt bits
+                only one parameter can be selected which is shown as below:
+      \arg        TIMER_INT_FLAG_UP: update interrupt flag, TIMERx(x=0,2,13..16), TIMER1(not available in GD32F310), TIMER5(not available in GD32F310 and GD32F330)
+      \arg        TIMER_INT_FLAG_CH0: channel 0 interrupt flag, TIMERx(x=0,2,13..16), TIMER1(not available in GD32F310)
+      \arg        TIMER_INT_FLAG_CH1: channel 1 interrupt flag, TIMERx(x=0,2,14), TIMER1(not available in GD32F310)
+      \arg        TIMER_INT_FLAG_CH2: channel 2 interrupt flag, TIMERx(x=0,2), TIMER1(not available in GD32F310)
+      \arg        TIMER_INT_FLAG_CH3: channel 3 interrupt flag, TIMERx(x=0,2), TIMER1(not available in GD32F310)
+      \arg        TIMER_INT_FLAG_CMT: channel commutation interrupt flag, TIMERx(x=0,14..16)
+      \arg        TIMER_INT_FLAG_TRG: trigger interrupt flag, TIMERx(x=0,2,14), TIMER1(not available in GD32F310)
+      \arg        TIMER_INT_FLAG_BRK:  break interrupt flag, TIMERx(x=0,14..16)
+    \param[out] none
+    \retval     none
+*/
+void timer_interrupt_flag_clear(uint32_t timer_periph, uint32_t interrupt)
+{
+    TIMER_INTF(timer_periph) = (~(uint32_t)interrupt);
+}
+
+/*!
+    \brief      enable the TIMER DMA
+    \param[in]  timer_periph: please refer to the following parameters
+    \param[in]  dma: specify which DMA to enable
+                one or more parameters can be selected which is shown as below:
+      \arg        TIMER_DMA_UPD: update DMA, TIMERx(x=0,2,14..16), TIMER1(not available in GD32F310), TIMER5(not available in GD32F310 and GD32F330)
+      \arg        TIMER_DMA_CH0D: channel 0 DMA request, TIMERx(x=0,2,14..16), TIMER1(not available in GD32F310)
+      \arg        TIMER_DMA_CH1D: channel 1 DMA request, TIMERx(x=0,2,14), TIMER1(not available in GD32F310)
+      \arg        TIMER_DMA_CH2D: channel 2 DMA request, TIMERx(x=0,2), TIMER1(not available in GD32F310)
+      \arg        TIMER_DMA_CH3D: channel 3 DMA request, TIMERx(x=0,2), TIMER1(not available in GD32F310)
+      \arg        TIMER_DMA_CMTD: commutation DMA request, TIMERx(x=0,14)
+      \arg        TIMER_DMA_TRGD: trigger DMA request, TIMERx(x=0,2,14), TIMER1(not available in GD32F310)
+    \param[out] none
+    \retval     none
+*/
+void timer_dma_enable(uint32_t timer_periph, uint16_t dma)
+{
+    TIMER_DMAINTEN(timer_periph) |= (uint32_t) dma;
+}
+
+/*!
+    \brief      disable the TIMER DMA
+    \param[in]  timer_periph: please refer to the following parameters
+    \param[in]  dma: specify which DMA to disable
+                one or more parameters can be selected which are shown as below:
+      \arg        TIMER_DMA_UPD: update DMA, TIMERx(x=0,2,14..16), TIMER1(not available in GD32F310), TIMER5(not available in GD32F310 and GD32F330)
+      \arg        TIMER_DMA_CH0D: channel 0 DMA request, TIMERx(x=0,2,14..16), TIMER1(not available in GD32F310)
+      \arg        TIMER_DMA_CH1D: channel 1 DMA request, TIMERx(x=0,2,14), TIMER1(not available in GD32F310)
+      \arg        TIMER_DMA_CH2D: channel 2 DMA request, TIMERx(x=0,2), TIMER1(not available in GD32F310)
+      \arg        TIMER_DMA_CH3D: channel 3 DMA request, TIMERx(x=0,2), TIMER1(not available in GD32F310)
+      \arg        TIMER_DMA_CMTD: commutation DMA request , TIMERx(x=0,14)
+      \arg        TIMER_DMA_TRGD: trigger DMA request, TIMERx(x=0,2,14), TIMER1(not available in GD32F310)
+    \param[out] none
+    \retval     none
+*/
+void timer_dma_disable(uint32_t timer_periph, uint16_t dma)
+{
+    TIMER_DMAINTEN(timer_periph) &= (~(uint32_t)(dma));
+}
+
+/*!
+    \brief      channel DMA request source selection
+    \param[in]  timer_periph: TIMERx(x=0,2,14..16), TIMER1(not available in GD32F310)
+    \param[in]  dma_request: channel DMA request source selection
+                only one parameter can be selected which is shown as below:
+       \arg        TIMER_DMAREQUEST_CHANNELEVENT: DMA request of channel y is sent when channel y event occurs
+       \arg        TIMER_DMAREQUEST_UPDATEEVENT: DMA request of channel y is sent when update event occurs
+    \param[out] none
+    \retval     none
+*/
+void timer_channel_dma_request_source_select(uint32_t timer_periph, uint8_t dma_request)
+{
+    if(TIMER_DMAREQUEST_UPDATEEVENT == dma_request) {
+        TIMER_CTL1(timer_periph) |= (uint32_t)TIMER_CTL1_DMAS;
+    } else if(TIMER_DMAREQUEST_CHANNELEVENT == dma_request) {
+        TIMER_CTL1(timer_periph) &= ~(uint32_t)TIMER_CTL1_DMAS;
+    } else {
+        /* illegal parameters */
+    }
+}
+
+/*!
+    \brief      configure the TIMER DMA transfer
+    \param[in]  timer_periph: TIMERx(x=0,2,14..16), TIMER1(not available in GD32F310)
+    \param[in]  dma_baseaddr:
+                only one parameter can be selected which is shown as below:
+       \arg        TIMER_DMACFG_DMATA_CTL0: DMA transfer address is TIMER_CTL0, TIMERx(x=0,2,14..16), TIMER1(not available in GD32F310)
+       \arg        TIMER_DMACFG_DMATA_CTL1: DMA transfer address is TIMER_CTL1, TIMERx(x=0,2,14..16), TIMER1(not available in GD32F310)
+       \arg        TIMER_DMACFG_DMATA_SMCFG: DMA transfer address is TIMER_SMCFG, TIMERx(x=0,2,14), TIMER1(not available in GD32F310)
+       \arg        TIMER_DMACFG_DMATA_DMAINTEN: DMA transfer address is TIMER_DMAINTEN, TIMERx(x=0,2,14..16), TIMER1(not available in GD32F310)
+       \arg        TIMER_DMACFG_DMATA_INTF: DMA transfer address is TIMER_INTF, TIMERx(x=0,2,14..16), TIMER1(not available in GD32F310)
+       \arg        TIMER_DMACFG_DMATA_SWEVG: DMA transfer address is TIMER_SWEVG, TIMERx(x=0,2,14..16), TIMER1(not available in GD32F310)
+       \arg        TIMER_DMACFG_DMATA_CHCTL0: DMA transfer address is TIMER_CHCTL0, TIMERx(x=0,2,14..16), TIMER1(not available in GD32F310)
+       \arg        TIMER_DMACFG_DMATA_CHCTL1: DMA transfer address is TIMER_CHCTL1, TIMERx(x=0,2), TIMER1(not available in GD32F310)
+       \arg        TIMER_DMACFG_DMATA_CHCTL2: DMA transfer address is TIMER_CHCTL2, TIMERx(x=0,2,14..16), TIMER1(not available in GD32F310)
+       \arg        TIMER_DMACFG_DMATA_CNT: DMA transfer address is TIMER_CNT, TIMERx(x=0,2,14..16), TIMER1(not available in GD32F310)
+       \arg        TIMER_DMACFG_DMATA_PSC: DMA transfer address is TIMER_PSC, TIMERx(x=0,2,14..16), TIMER1(not available in GD32F310)
+       \arg        TIMER_DMACFG_DMATA_CAR: DMA transfer address is TIMER_CAR, TIMERx(x=0,2,14..16), TIMER1(not available in GD32F310)
+       \arg        TIMER_DMACFG_DMATA_CREP: DMA transfer address is TIMER_CREP, TIMERx(x=0,14..16)
+       \arg        TIMER_DMACFG_DMATA_CH0CV: DMA transfer address is TIMER_CH0CV, TIMERx(x=0,2,14..16), TIMER1(not available in GD32F310)
+       \arg        TIMER_DMACFG_DMATA_CH1CV: DMA transfer address is TIMER_CH1CV, TIMERx(x=0,2,14), TIMER1(not available in GD32F310)
+       \arg        TIMER_DMACFG_DMATA_CH2CV: DMA transfer address is TIMER_CH2CV, TIMERx(x=0,2), TIMER1(not available in GD32F310)
+       \arg        TIMER_DMACFG_DMATA_CH3CV: DMA transfer address is TIMER_CH3CV, TIMERx(x=0,2), TIMER1(not available in GD32F310)
+       \arg        TIMER_DMACFG_DMATA_CCHP: DMA transfer address is TIMER_CCHP, TIMERx(x=0,14..16)
+       \arg        TIMER_DMACFG_DMATA_DMACFG: DMA transfer address is TIMER_DMACFG, TIMERx(x=0,2,14..16), TIMER1(not available in GD32F310)
+       \arg        TIMER_DMACFG_DMATA_DMATB: DMA transfer address is TIMER_DMATB, TIMERx(x=0,2,14..16), TIMER1(not available in GD32F310)
+    \param[in]  dma_lenth:
+                only one parameter can be selected which is shown as below:
+       \arg        TIMER_DMACFG_DMATC_xTRANSFER(x=1..18): DMA transfer x time
+    \param[out] none
+    \retval     none
+*/
+void timer_dma_transfer_config(uint32_t timer_periph, uint32_t dma_baseaddr, uint32_t dma_lenth)
+{
+    TIMER_DMACFG(timer_periph) &= (~(uint32_t)(TIMER_DMACFG_DMATA | TIMER_DMACFG_DMATC));
+    TIMER_DMACFG(timer_periph) |= (uint32_t)(dma_baseaddr | dma_lenth);
+}
+
+/*!
+    \brief      software generate events
+    \param[in]  timer_periph: please refer to the following parameters
+    \param[in]  event: the timer software event generation sources
+                one or more parameters can be selected which are shown as below:
+      \arg        TIMER_EVENT_SRC_UPG: update event,TIMERx(x=0,2,13..16), TIMER1(not available in GD32F310), TIMER5(not available in GD32F310 and GD32F330)
+      \arg        TIMER_EVENT_SRC_CH0G: channel 0 capture or compare event generation, TIMERx(x=0,2,13..16), TIMER1(not available in GD32F310)
+      \arg        TIMER_EVENT_SRC_CH1G: channel 1 capture or compare event generation, TIMERx(x=0,2,14), TIMER1(not available in GD32F310)
+      \arg        TIMER_EVENT_SRC_CH2G: channel 2 capture or compare event generation, TIMERx(x=0,2), TIMER1(not available in GD32F310)
+      \arg        TIMER_EVENT_SRC_CH3G: channel 3 capture or compare event generation, TIMERx(x=0,2), TIMER1(not available in GD32F310)
+      \arg        TIMER_EVENT_SRC_CMTG: channel commutation event generation, TIMERx(x=0,14..16)
+      \arg        TIMER_EVENT_SRC_TRGG: trigger event generation, TIMERx(x=0,2,14), TIMER1(not available in GD32F310)
+      \arg        TIMER_EVENT_SRC_BRKG:  break event generation, TIMERx(x=0,14..16)
+    \param[out] none
+    \retval     none
+*/
+void timer_event_software_generate(uint32_t timer_periph, uint16_t event)
+{
+    TIMER_SWEVG(timer_periph) |= (uint32_t)event;
+}
+
+/*!
+    \brief      initialize TIMER break parameter struct with a default value
+    \param[in]  breakpara: TIMER break parameter struct
+    \param[out] none
+    \retval     none
+*/
+void timer_break_struct_para_init(timer_break_parameter_struct *breakpara)
+{
+    /* initialize the break parameter struct member with the default value */
+    breakpara->runoffstate     = TIMER_ROS_STATE_DISABLE;
+    breakpara->ideloffstate    = TIMER_IOS_STATE_DISABLE;
+    breakpara->deadtime        = 0U;
+    breakpara->breakpolarity   = TIMER_BREAK_POLARITY_LOW;
+    breakpara->outputautostate = TIMER_OUTAUTO_DISABLE;
+    breakpara->protectmode     = TIMER_CCHP_PROT_OFF;
+    breakpara->breakstate      = TIMER_BREAK_DISABLE;
+}
+
+/*!
+    \brief      configure TIMER break function
+    \param[in]  timer_periph: TIMERx(x=0,14..16)
+    \param[in]  breakpara: TIMER break parameter struct
+                runoffstate: TIMER_ROS_STATE_ENABLE,TIMER_ROS_STATE_DISABLE
+                ideloffstate: TIMER_IOS_STATE_ENABLE,TIMER_IOS_STATE_DISABLE
+                deadtime: 0~255
+                breakpolarity: TIMER_BREAK_POLARITY_LOW,TIMER_BREAK_POLARITY_HIGH
+                outputautostate: TIMER_OUTAUTO_ENABLE,TIMER_OUTAUTO_DISABLE
+                protectmode: TIMER_CCHP_PROT_OFF,TIMER_CCHP_PROT_0,TIMER_CCHP_PROT_1,TIMER_CCHP_PROT_2
+                breakstate: TIMER_BREAK_ENABLE,TIMER_BREAK_DISABLE
+    \param[out] none
+    \retval     none
+*/
+void timer_break_config(uint32_t timer_periph, timer_break_parameter_struct *breakpara)
+{
+    TIMER_CCHP(timer_periph) = (uint32_t)(((uint32_t)(breakpara->runoffstate)) |
+                                          ((uint32_t)(breakpara->ideloffstate)) |
+                                          ((uint32_t)(breakpara->deadtime)) |
+                                          ((uint32_t)(breakpara->breakpolarity)) |
+                                          ((uint32_t)(breakpara->outputautostate)) |
+                                          ((uint32_t)(breakpara->protectmode)) |
+                                          ((uint32_t)(breakpara->breakstate))) ;
+}
+
+/*!
+    \brief      enable TIMER break function
+    \param[in]  timer_periph: TIMERx(x=0,14..16)
+    \param[out] none
+    \retval     none
+*/
+void timer_break_enable(uint32_t timer_periph)
+{
+    TIMER_CCHP(timer_periph) |= (uint32_t)TIMER_CCHP_BRKEN;
+}
+
+/*!
+    \brief      disable TIMER break function
+    \param[in]  timer_periph: TIMERx(x=0,14..16)
+    \param[out] none
+    \retval     none
+*/
+void timer_break_disable(uint32_t timer_periph)
+{
+    TIMER_CCHP(timer_periph) &= ~(uint32_t)TIMER_CCHP_BRKEN;
+}
+
+/*!
+    \brief      enable TIMER output automatic function
+    \param[in]  timer_periph: TIMERx(x=0,14..16)
+    \param[out] none
+    \retval     none
+*/
+void timer_automatic_output_enable(uint32_t timer_periph)
+{
+    TIMER_CCHP(timer_periph) |= (uint32_t)TIMER_CCHP_OAEN;
+}
+
+/*!
+    \brief      disable TIMER output automatic function
+    \param[in]  timer_periph: TIMERx(x=0,14..16)
+    \param[out] none
+    \retval     none
+*/
+void timer_automatic_output_disable(uint32_t timer_periph)
+{
+    TIMER_CCHP(timer_periph) &= ~(uint32_t)TIMER_CCHP_OAEN;
+}
+
+/*!
+    \brief      configure TIMER primary output function
+    \param[in]  timer_periph: TIMERx(x=0,14..16)
+    \param[in]  newvalue: ENABLE or DISABLE
+    \param[out] none
+    \retval     none
+*/
+void timer_primary_output_config(uint32_t timer_periph, ControlStatus newvalue)
+{
+    if(ENABLE == newvalue) {
+        TIMER_CCHP(timer_periph) |= (uint32_t)TIMER_CCHP_POEN;
+    } else {
+        TIMER_CCHP(timer_periph) &= (~(uint32_t)TIMER_CCHP_POEN);
+    }
+}
+
+/*!
+    \brief      enable or disable channel capture/compare control shadow register
+    \param[in]  timer_periph: TIMERx(x=0,14..16)
+    \param[in]  newvalue: ENABLE or DISABLE
+    \param[out] none
+    \retval     none
+*/
+void timer_channel_control_shadow_config(uint32_t timer_periph, ControlStatus newvalue)
+{
+    if(ENABLE == newvalue) {
+        TIMER_CTL1(timer_periph) |= (uint32_t)TIMER_CTL1_CCSE;
+    } else {
+        TIMER_CTL1(timer_periph) &= (~(uint32_t)TIMER_CTL1_CCSE);
+    }
+}
+
+/*!
+    \brief      configure TIMER channel control shadow register update control
+    \param[in]  timer_periph: TIMERx(x=0,14..16)
+    \param[in]  ccuctl: channel control shadow register update control
+                only one parameter can be selected which is shown as below:
+      \arg        TIMER_UPDATECTL_CCU: the shadow registers update by when CMTG bit is set
+      \arg        TIMER_UPDATECTL_CCUTRI: the shadow registers update by when CMTG bit is set or an rising edge of TRGI occurs
+    \param[out] none
+    \retval     none
+*/
+void timer_channel_control_shadow_update_config(uint32_t timer_periph, uint8_t ccuctl)
+{
+    if(TIMER_UPDATECTL_CCU == ccuctl) {
+        TIMER_CTL1(timer_periph) &= (~(uint32_t)TIMER_CTL1_CCUC);
+    } else if(TIMER_UPDATECTL_CCUTRI == ccuctl) {
+        TIMER_CTL1(timer_periph) |= (uint32_t)TIMER_CTL1_CCUC;
+    } else {
+        /* illegal parameters */
+    }
+}
+
+/*!
+    \brief      initialize TIMER channel output parameter struct with a default value
+    \param[in]  ocpara: TIMER channel n output parameter struct
+    \param[out] none
+    \retval     none
+*/
+void timer_channel_output_struct_para_init(timer_oc_parameter_struct *ocpara)
+{
+    /* initialize the channel output parameter struct member with the default value */
+    ocpara->outputstate  = (uint16_t)TIMER_CCX_DISABLE;
+    ocpara->outputnstate = TIMER_CCXN_DISABLE;
+    ocpara->ocpolarity   = TIMER_OC_POLARITY_HIGH;
+    ocpara->ocnpolarity  = TIMER_OCN_POLARITY_HIGH;
+    ocpara->ocidlestate  = TIMER_OC_IDLE_STATE_LOW;
+    ocpara->ocnidlestate = TIMER_OCN_IDLE_STATE_LOW;
+}
+
+/*!
+    \brief      configure TIMER channel output function
+    \param[in]  timer_periph: please refer to the following parameters
+    \param[in]  channel:
+                only one parameter can be selected which is shown as below:
+      \arg        TIMER_CH_0: TIMER channel 0(TIMERx(x=0,2,13..16)), TIMER1(not available in GD32F310)
+      \arg        TIMER_CH_1: TIMER channel 1(TIMERx(x=0,2,14)), TIMER1(not available in GD32F310)
+      \arg        TIMER_CH_2: TIMER channel 2(TIMERx(x=0,2)), TIMER1(not available in GD32F310)
+      \arg        TIMER_CH_3: TIMER channel 3(TIMERx(x=0,2)), TIMER1(not available in GD32F310)
+    \param[in]  ocpara: TIMER channeln output parameter struct
+                outputstate: TIMER_CCX_ENABLE,TIMER_CCX_DISABLE
+                outputnstate: TIMER_CCXN_ENABLE,TIMER_CCXN_DISABLE
+                ocpolarity: TIMER_OC_POLARITY_HIGH,TIMER_OC_POLARITY_LOW
+                ocnpolarity: TIMER_OCN_POLARITY_HIGH,TIMER_OCN_POLARITY_LOW
+                ocidlestate: TIMER_OC_IDLE_STATE_LOW,TIMER_OC_IDLE_STATE_HIGH
+                ocnidlestate: TIMER_OCN_IDLE_STATE_LOW,TIMER_OCN_IDLE_STATE_HIGH
+    \param[out] none
+    \retval     none
+*/
+void timer_channel_output_config(uint32_t timer_periph, uint16_t channel, timer_oc_parameter_struct *ocpara)
+{
+    switch(channel) {
+    /* configure TIMER_CH_0 */
+    case TIMER_CH_0:
+        /* reset the CH0EN bit */
+        TIMER_CHCTL2(timer_periph) &= (~(uint32_t)TIMER_CHCTL2_CH0EN);
+        TIMER_CHCTL0(timer_periph) &= ~(uint32_t)TIMER_CHCTL0_CH0MS;
+        /* set the CH0EN bit */
+        TIMER_CHCTL2(timer_periph) |= (uint32_t)ocpara->outputstate;
+        /* reset the CH0P bit */
+        TIMER_CHCTL2(timer_periph) &= (~(uint32_t)TIMER_CHCTL2_CH0P);
+        /* set the CH0P bit */
+        TIMER_CHCTL2(timer_periph) |= (uint32_t)ocpara->ocpolarity;
+
+        if((TIMER0 == timer_periph) || (TIMER14 == timer_periph) || (TIMER15 == timer_periph) || (TIMER16 == timer_periph)) {
+            /* reset the CH0NEN bit */
+            TIMER_CHCTL2(timer_periph) &= (~(uint32_t)TIMER_CHCTL2_CH0NEN);
+            /* set the CH0NEN bit */
+            TIMER_CHCTL2(timer_periph) |= (uint32_t)ocpara->outputnstate;
+            /* reset the CH0NP bit */
+            TIMER_CHCTL2(timer_periph) &= (~(uint32_t)TIMER_CHCTL2_CH0NP);
+            /* set the CH0NP bit */
+            TIMER_CHCTL2(timer_periph) |= (uint32_t)ocpara->ocnpolarity;
+            /* reset the ISO0 bit */
+            TIMER_CTL1(timer_periph) &= (~(uint32_t)TIMER_CTL1_ISO0);
+            /* set the ISO0 bit */
+            TIMER_CTL1(timer_periph) |= (uint32_t)ocpara->ocidlestate;
+            /* reset the ISO0N bit */
+            TIMER_CTL1(timer_periph) &= (~(uint32_t)TIMER_CTL1_ISO0N);
+            /* set the ISO0N bit */
+            TIMER_CTL1(timer_periph) |= (uint32_t)ocpara->ocnidlestate;
+        }
+        break;
+    /* configure TIMER_CH_1 */
+    case TIMER_CH_1:
+        /* reset the CH1EN bit */
+        TIMER_CHCTL2(timer_periph) &= (~(uint32_t)TIMER_CHCTL2_CH1EN);
+        TIMER_CHCTL0(timer_periph) &= ~(uint32_t)TIMER_CHCTL0_CH1MS;
+        /* set the CH1EN bit */
+        TIMER_CHCTL2(timer_periph) |= (uint32_t)(ocpara->outputstate << 4U);
+        /* reset the CH1P bit */
+        TIMER_CHCTL2(timer_periph) &= (~(uint32_t)TIMER_CHCTL2_CH1P);
+        /* set the CH1P bit */
+        TIMER_CHCTL2(timer_periph) |= (uint32_t)((uint32_t)(ocpara->ocpolarity) << 4U);
+
+        if(TIMER0 == timer_periph) {
+            /* reset the CH1NEN bit */
+            TIMER_CHCTL2(timer_periph) &= (~(uint32_t)TIMER_CHCTL2_CH1NEN);
+            /* set the CH1NEN bit */
+            TIMER_CHCTL2(timer_periph) |= (uint32_t)((uint32_t)(ocpara->outputnstate) << 4U);
+            /* reset the CH1NP bit */
+            TIMER_CHCTL2(timer_periph) &= (~(uint32_t)TIMER_CHCTL2_CH1NP);
+            /* set the CH1NP bit */
+            TIMER_CHCTL2(timer_periph) |= (uint32_t)((uint32_t)(ocpara->ocnpolarity) << 4U);
+            /* reset the ISO1 bit */
+            TIMER_CTL1(timer_periph) &= (~(uint32_t)TIMER_CTL1_ISO1);
+            /* set the ISO1 bit */
+            TIMER_CTL1(timer_periph) |= (uint32_t)((uint32_t)(ocpara->ocidlestate) << 2U);
+            /* reset the ISO1N bit */
+            TIMER_CTL1(timer_periph) &= (~(uint32_t)TIMER_CTL1_ISO1N);
+            /* set the ISO1N bit */
+            TIMER_CTL1(timer_periph) |= (uint32_t)((uint32_t)(ocpara->ocnidlestate) << 2U);
+        }
+
+        if(TIMER14 == timer_periph) {
+            /* reset the ISO1 bit */
+            TIMER_CTL1(timer_periph) &= (~(uint32_t)TIMER_CTL1_ISO1);
+            /* set the ISO1 bit */
+            TIMER_CTL1(timer_periph) |= (uint32_t)((uint32_t)(ocpara->ocidlestate) << 2U);
+        }
+
+        break;
+    /* configure TIMER_CH_2 */
+    case TIMER_CH_2:
+        /* reset the CH2EN bit */
+        TIMER_CHCTL2(timer_periph) &= (~(uint32_t)TIMER_CHCTL2_CH2EN);
+        TIMER_CHCTL1(timer_periph) &= ~(uint32_t)TIMER_CHCTL1_CH2MS;
+        /* set the CH2EN bit */
+        TIMER_CHCTL2(timer_periph) |= (uint32_t)(ocpara->outputstate << 8U);
+        /* reset the CH2P bit */
+        TIMER_CHCTL2(timer_periph) &= (~(uint32_t)TIMER_CHCTL2_CH2P);
+        /* set the CH2P bit */
+        TIMER_CHCTL2(timer_periph) |= (uint32_t)((uint32_t)(ocpara->ocpolarity) << 8U);
+
+        if(TIMER0 == timer_periph) {
+            /* reset the CH2NEN bit */
+            TIMER_CHCTL2(timer_periph) &= (~(uint32_t)TIMER_CHCTL2_CH2NEN);
+            /* set the CH2NEN bit */
+            TIMER_CHCTL2(timer_periph) |= (uint32_t)((uint32_t)(ocpara->outputnstate) << 8U);
+            /* reset the CH2NP bit */
+            TIMER_CHCTL2(timer_periph) &= (~(uint32_t)TIMER_CHCTL2_CH2NP);
+            /* set the CH2NP bit */
+            TIMER_CHCTL2(timer_periph) |= (uint32_t)((uint32_t)(ocpara->ocnpolarity) << 8U);
+            /* reset the ISO2 bit */
+            TIMER_CTL1(timer_periph) &= (~(uint32_t)TIMER_CTL1_ISO2);
+            /* set the ISO2 bit */
+            TIMER_CTL1(timer_periph) |= (uint32_t)((uint32_t)(ocpara->ocidlestate) << 4U);
+            /* reset the ISO2N bit */
+            TIMER_CTL1(timer_periph) &= (~(uint32_t)TIMER_CTL1_ISO2N);
+            /* set the ISO2N bit */
+            TIMER_CTL1(timer_periph) |= (uint32_t)((uint32_t)(ocpara->ocnidlestate) << 4U);
+        }
+        break;
+    /* configure TIMER_CH_3 */
+    case TIMER_CH_3:
+        /* reset the CH3EN bit */
+        TIMER_CHCTL2(timer_periph) &= (~(uint32_t)TIMER_CHCTL2_CH3EN);
+        TIMER_CHCTL1(timer_periph) &= ~(uint32_t)TIMER_CHCTL1_CH3MS;
+        /* set the CH3EN bit */
+        TIMER_CHCTL2(timer_periph) |= (uint32_t)(ocpara->outputstate << 12U);
+        /* reset the CH3P bit */
+        TIMER_CHCTL2(timer_periph) &= (~(uint32_t)TIMER_CHCTL2_CH3P);
+        /* set the CH3P bit */
+        TIMER_CHCTL2(timer_periph) |= (uint32_t)((uint32_t)(ocpara->ocpolarity) << 12U);
+
+        if(TIMER0 == timer_periph) {
+            /* reset the ISO3 bit */
+            TIMER_CTL1(timer_periph) &= (~(uint32_t)TIMER_CTL1_ISO3);
+            /* set the ISO3 bit */
+            TIMER_CTL1(timer_periph) |= (uint32_t)((uint32_t)(ocpara->ocidlestate) << 6U);
+        }
+        break;
+    default:
+        break;
+    }
+}
+
+/*!
+    \brief      configure TIMER channel output compare mode
+    \param[in]  timer_periph: please refer to the following parameters
+    \param[in]  channel:
+                only one parameter can be selected which is shown as below:
+      \arg        TIMER_CH_0: TIMER channel0(TIMERx(x=0,2,13..16)), TIMER1(not available in GD32F310)
+      \arg        TIMER_CH_1: TIMER channel1(TIMERx(x=0,2,14)), TIMER1(not available in GD32F310)
+      \arg        TIMER_CH_2: TIMER channel2(TIMERx(x=0,2)), TIMER1(not available in GD32F310)
+      \arg        TIMER_CH_3: TIMER channel3(TIMERx(x=0,2)), TIMER1(not available in GD32F310)
+    \param[in]  ocmode: channel output compare mode
+                only one parameter can be selected which is shown as below:
+      \arg        TIMER_OC_MODE_TIMING: timing mode
+      \arg        TIMER_OC_MODE_ACTIVE: active mode
+      \arg        TIMER_OC_MODE_INACTIVE: inactive mode
+      \arg        TIMER_OC_MODE_TOGGLE: toggle mode
+      \arg        TIMER_OC_MODE_LOW: force low mode
+      \arg        TIMER_OC_MODE_HIGH: force high mode
+      \arg        TIMER_OC_MODE_PWM0: PWM0 mode
+      \arg        TIMER_OC_MODE_PWM1: PWM1 mode
+    \param[out] none
+    \retval     none
+*/
+void timer_channel_output_mode_config(uint32_t timer_periph, uint16_t channel, uint16_t ocmode)
+{
+    switch(channel) {
+    /* configure TIMER_CH_0 */
+    case TIMER_CH_0:
+        TIMER_CHCTL0(timer_periph) &= (~(uint32_t)TIMER_CHCTL0_CH0COMCTL);
+        TIMER_CHCTL0(timer_periph) |= (uint32_t)ocmode;
+        break;
+    /* configure TIMER_CH_1 */
+    case TIMER_CH_1:
+        TIMER_CHCTL0(timer_periph) &= (~(uint32_t)TIMER_CHCTL0_CH1COMCTL);
+        TIMER_CHCTL0(timer_periph) |= (uint32_t)((uint32_t)(ocmode) << 8U);
+        break;
+    /* configure TIMER_CH_2 */
+    case TIMER_CH_2:
+        TIMER_CHCTL1(timer_periph) &= (~(uint32_t)TIMER_CHCTL1_CH2COMCTL);
+        TIMER_CHCTL1(timer_periph) |= (uint32_t)ocmode;
+        break;
+    /* configure TIMER_CH_3 */
+    case TIMER_CH_3:
+        TIMER_CHCTL1(timer_periph) &= (~(uint32_t)TIMER_CHCTL1_CH3COMCTL);
+        TIMER_CHCTL1(timer_periph) |= (uint32_t)((uint32_t)(ocmode) << 8U);
+        break;
+    default:
+        break;
+    }
+}
+
+/*!
+    \brief      configure TIMER channel output pulse value
+    \param[in]  timer_periph: please refer to the following parameters
+    \param[in]  channel:
+                only one parameter can be selected which is shown as below:
+      \arg        TIMER_CH_0: TIMER channel0(TIMERx(x=0,2,13..16)), TIMER1(not available in GD32F310)
+      \arg        TIMER_CH_1: TIMER channel1(TIMERx(x=0,2,14)), TIMER1(not available in GD32F310)
+      \arg        TIMER_CH_2: TIMER channel2(TIMERx(x=0,2)), TIMER1(not available in GD32F310)
+      \arg        TIMER_CH_3: TIMER channel3(TIMERx(x=0,2)), TIMER1(not available in GD32F310)
+    \param[in]  pulse: channel output pulse value,0~65535
+    \param[out] none
+    \retval     none
+*/
+void timer_channel_output_pulse_value_config(uint32_t timer_periph, uint16_t channel, uint32_t pulse)
+{
+    switch(channel) {
+    /* configure TIMER_CH_0 */
+    case TIMER_CH_0:
+        TIMER_CH0CV(timer_periph) = (uint32_t)pulse;
+        break;
+    /* configure TIMER_CH_1 */
+    case TIMER_CH_1:
+        TIMER_CH1CV(timer_periph) = (uint32_t)pulse;
+        break;
+    /* configure TIMER_CH_2 */
+    case TIMER_CH_2:
+        TIMER_CH2CV(timer_periph) = (uint32_t)pulse;
+        break;
+    /* configure TIMER_CH_3 */
+    case TIMER_CH_3:
+        TIMER_CH3CV(timer_periph) = (uint32_t)pulse;
+        break;
+    default:
+        break;
+    }
+}
+
+/*!
+    \brief      configure TIMER channel output shadow function
+    \param[in]  timer_periph: please refer to the following parameters
+    \param[in]  channel:
+                only one parameter can be selected which is shown as below:
+      \arg        TIMER_CH_0: TIMER channel0(TIMERx(x=0,2,13..16)), TIMER1(not available in GD32F310)
+      \arg        TIMER_CH_1: TIMER channel1(TIMERx(x=0,2,14)), TIMER1(not available in GD32F310)
+      \arg        TIMER_CH_2: TIMER channel2(TIMERx(x=0,2)), TIMER1(not available in GD32F310)
+      \arg        TIMER_CH_3: TIMER channel3(TIMERx(x=0,2)), TIMER1(not available in GD32F310)
+    \param[in]  ocshadow: channel output shadow state
+                only one parameter can be selected which is shown as below:
+      \arg        TIMER_OC_SHADOW_ENABLE: channel output shadow state enable
+      \arg        TIMER_OC_SHADOW_DISABLE: channel output shadow state disable
+    \param[out] none
+    \retval     none
+*/
+void timer_channel_output_shadow_config(uint32_t timer_periph, uint16_t channel, uint16_t ocshadow)
+{
+    switch(channel) {
+    /* configure TIMER_CH_0 */
+    case TIMER_CH_0:
+        TIMER_CHCTL0(timer_periph) &= (~(uint32_t)TIMER_CHCTL0_CH0COMSEN);
+        TIMER_CHCTL0(timer_periph) |= (uint32_t)ocshadow;
+        break;
+    /* configure TIMER_CH_1 */
+    case TIMER_CH_1:
+        TIMER_CHCTL0(timer_periph) &= (~(uint32_t)TIMER_CHCTL0_CH1COMSEN);
+        TIMER_CHCTL0(timer_periph) |= (uint32_t)((uint32_t)(ocshadow) << 8U);
+        break;
+    /* configure TIMER_CH_2 */
+    case TIMER_CH_2:
+        TIMER_CHCTL1(timer_periph) &= (~(uint32_t)TIMER_CHCTL1_CH2COMSEN);
+        TIMER_CHCTL1(timer_periph) |= (uint32_t)ocshadow;
+        break;
+    /* configure TIMER_CH_3 */
+    case TIMER_CH_3:
+        TIMER_CHCTL1(timer_periph) &= (~(uint32_t)TIMER_CHCTL1_CH3COMSEN);
+        TIMER_CHCTL1(timer_periph) |= (uint32_t)((uint32_t)(ocshadow) << 8U);
+        break;
+    default:
+        break;
+    }
+}
+
+/*!
+    \brief      configure TIMER channel output fast function
+    \param[in]  timer_periph: please refer to the following parameters
+    \param[in]  channel:
+                only one parameter can be selected which is shown as below:
+      \arg        TIMER_CH_0: TIMER channel0(TIMERx(x=0,2,13..16)), TIMER1(not available in GD32F310)
+      \arg        TIMER_CH_1: TIMER channel1(TIMERx(x=0,2,14)), TIMER1(not available in GD32F310)
+      \arg        TIMER_CH_2: TIMER channel2(TIMERx(x=0,2)), TIMER1(not available in GD32F310)
+      \arg        TIMER_CH_3: TIMER channel3(TIMERx(x=0,2)), TIMER1(not available in GD32F310)
+    \param[in]  ocfast: channel output fast function
+                only one parameter can be selected which is shown as below:
+      \arg        TIMER_OC_FAST_ENABLE: channel output fast function enable
+      \arg        TIMER_OC_FAST_DISABLE: channel output fast function disable
+    \param[out] none
+    \retval     none
+*/
+void timer_channel_output_fast_config(uint32_t timer_periph, uint16_t channel, uint16_t ocfast)
+{
+    switch(channel) {
+    /* configure TIMER_CH_0 */
+    case TIMER_CH_0:
+        TIMER_CHCTL0(timer_periph) &= (~(uint32_t)TIMER_CHCTL0_CH0COMFEN);
+        TIMER_CHCTL0(timer_periph) |= (uint32_t)ocfast;
+        break;
+    /* configure TIMER_CH_1 */
+    case TIMER_CH_1:
+        TIMER_CHCTL0(timer_periph) &= (~(uint32_t)TIMER_CHCTL0_CH1COMFEN);
+        TIMER_CHCTL0(timer_periph) |= (uint32_t)((uint32_t)ocfast << 8U);
+        break;
+    /* configure TIMER_CH_2 */
+    case TIMER_CH_2:
+        TIMER_CHCTL1(timer_periph) &= (~(uint32_t)TIMER_CHCTL1_CH2COMFEN);
+        TIMER_CHCTL1(timer_periph) |= (uint32_t)ocfast;
+        break;
+    /* configure TIMER_CH_3 */
+    case TIMER_CH_3:
+        TIMER_CHCTL1(timer_periph) &= (~(uint32_t)TIMER_CHCTL1_CH3COMFEN);
+        TIMER_CHCTL1(timer_periph) |= (uint32_t)((uint32_t)ocfast << 8U);
+        break;
+    default:
+        break;
+    }
+}
+
+/*!
+    \brief      configure TIMER channel output clear function
+    \param[in]  timer_periph: please refer to the following parameters
+    \param[in]  channel:
+                only one parameter can be selected which is shown as below:
+      \arg        TIMER_CH_0: TIMER channel0(TIMERx(x=0,2)), TIMER1(not available in GD32F310)
+      \arg        TIMER_CH_1: TIMER channel1(TIMERx(x=0,2)), TIMER1(not available in GD32F310)
+      \arg        TIMER_CH_2: TIMER channel2(TIMERx(x=0,2)), TIMER1(not available in GD32F310)
+      \arg        TIMER_CH_3: TIMER channel3(TIMERx(x=0,2)), TIMER1(not available in GD32F310)
+    \param[in]  occlear: channel output clear function
+                only one parameter can be selected which is shown as below:
+      \arg        TIMER_OC_CLEAR_ENABLE: channel output clear function enable
+      \arg        TIMER_OC_CLEAR_DISABLE: channel output clear function disable
+    \param[out] none
+    \retval     none
+*/
+void timer_channel_output_clear_config(uint32_t timer_periph, uint16_t channel, uint16_t occlear)
+{
+    switch(channel) {
+    /* configure TIMER_CH_0 */
+    case TIMER_CH_0:
+        TIMER_CHCTL0(timer_periph) &= (~(uint32_t)TIMER_CHCTL0_CH0COMCEN);
+        TIMER_CHCTL0(timer_periph) |= (uint32_t)occlear;
+        break;
+    /* configure TIMER_CH_1 */
+    case TIMER_CH_1:
+        TIMER_CHCTL0(timer_periph) &= (~(uint32_t)TIMER_CHCTL0_CH1COMCEN);
+        TIMER_CHCTL0(timer_periph) |= (uint32_t)((uint32_t)occlear << 8U);
+        break;
+    /* configure TIMER_CH_2 */
+    case TIMER_CH_2:
+        TIMER_CHCTL1(timer_periph) &= (~(uint32_t)TIMER_CHCTL1_CH2COMCEN);
+        TIMER_CHCTL1(timer_periph) |= (uint32_t)occlear;
+        break;
+    /* configure TIMER_CH_3 */
+    case TIMER_CH_3:
+        TIMER_CHCTL1(timer_periph) &= (~(uint32_t)TIMER_CHCTL1_CH3COMCEN);
+        TIMER_CHCTL1(timer_periph) |= (uint32_t)((uint32_t)occlear << 8U);
+        break;
+    default:
+        break;
+    }
+}
+
+/*!
+    \brief      configure TIMER channel output polarity
+    \param[in]  timer_periph: please refer to the following parameters
+    \param[in]  channel:
+                only one parameter can be selected which is shown as below:
+      \arg        TIMER_CH_0: TIMER channel0(TIMERx(x=0,2,13..16)), TIMER1(not available in GD32F310)
+      \arg        TIMER_CH_1: TIMER channel1(TIMERx(x=0,2,14)), TIMER1(not available in GD32F310)
+      \arg        TIMER_CH_2: TIMER channel2(TIMERx(x=0,2)), TIMER1(not available in GD32F310)
+      \arg        TIMER_CH_3: TIMER channel3(TIMERx(x=0,2)), TIMER1(not available in GD32F310)
+    \param[in]  ocpolarity: channel output polarity
+                only one parameter can be selected which is shown as below:
+      \arg        TIMER_OC_POLARITY_HIGH: channel output polarity is high
+      \arg        TIMER_OC_POLARITY_LOW: channel output polarity is low
+    \param[out] none
+    \retval     none
+*/
+void timer_channel_output_polarity_config(uint32_t timer_periph, uint16_t channel, uint16_t ocpolarity)
+{
+    switch(channel) {
+    /* configure TIMER_CH_0 */
+    case TIMER_CH_0:
+        TIMER_CHCTL2(timer_periph) &= (~(uint32_t)TIMER_CHCTL2_CH0P);
+        TIMER_CHCTL2(timer_periph) |= (uint32_t)ocpolarity;
+        break;
+    /* configure TIMER_CH_1 */
+    case TIMER_CH_1:
+        TIMER_CHCTL2(timer_periph) &= (~(uint32_t)TIMER_CHCTL2_CH1P);
+        TIMER_CHCTL2(timer_periph) |= (uint32_t)((uint32_t)ocpolarity << 4U);
+        break;
+    /* configure TIMER_CH_2 */
+    case TIMER_CH_2:
+        TIMER_CHCTL2(timer_periph) &= (~(uint32_t)TIMER_CHCTL2_CH2P);
+        TIMER_CHCTL2(timer_periph) |= (uint32_t)((uint32_t)ocpolarity << 8U);
+        break;
+    /* configure TIMER_CH_3 */
+    case TIMER_CH_3:
+        TIMER_CHCTL2(timer_periph) &= (~(uint32_t)TIMER_CHCTL2_CH3P);
+        TIMER_CHCTL2(timer_periph) |= (uint32_t)((uint32_t)ocpolarity << 12U);
+        break;
+    default:
+        break;
+    }
+}
+
+/*!
+    \brief      configure TIMER channel complementary output polarity
+    \param[in]  timer_periph: TIMERx(x=0,2,14), TIMER1(not available in GD32F310)
+    \param[in]  channel:
+                only one parameter can be selected which is shown as below:
+      \arg        TIMER_CH_0: TIMER channel0(TIMERx(x=0,2,13..16)), TIMER1(not available in GD32F310)
+      \arg        TIMER_CH_1: TIMER channel1(TIMERx(x=0,2,14)), TIMER1(not available in GD32F310)
+      \arg        TIMER_CH_2: TIMER channel2(TIMERx(x=0,2)), TIMER1(not available in GD32F310)
+      \arg        TIMER_CH_3: TIMER channel3(TIMERx(x=0,2)), TIMER1(not available in GD32F310)
+    \param[in]  ocnpolarity: channel complementary output polarity
+                only one parameter can be selected which is shown as below:
+      \arg        TIMER_OCN_POLARITY_HIGH: channel complementary output polarity is high
+      \arg        TIMER_OCN_POLARITY_LOW: channel complementary output polarity is low
+    \param[out] none
+    \retval     none
+*/
+void timer_channel_complementary_output_polarity_config(uint32_t timer_periph, uint16_t channel, uint16_t ocnpolarity)
+{
+    switch(channel) {
+    /* configure TIMER_CH_0 */
+    case TIMER_CH_0:
+        TIMER_CHCTL2(timer_periph) &= (~(uint32_t)TIMER_CHCTL2_CH0NP);
+        TIMER_CHCTL2(timer_periph) |= (uint32_t)ocnpolarity;
+        break;
+    /* configure TIMER_CH_1 */
+    case TIMER_CH_1:
+        TIMER_CHCTL2(timer_periph) &= (~(uint32_t)TIMER_CHCTL2_CH1NP);
+        TIMER_CHCTL2(timer_periph) |= (uint32_t)((uint32_t)ocnpolarity << 4U);
+        break;
+    /* configure TIMER_CH_2 */
+    case TIMER_CH_2:
+        TIMER_CHCTL2(timer_periph) &= (~(uint32_t)TIMER_CHCTL2_CH2NP);
+        TIMER_CHCTL2(timer_periph) |= (uint32_t)((uint32_t)ocnpolarity << 8U);
+        break;
+    /* configure TIMER_CH_3 */
+    case TIMER_CH_3:
+        TIMER_CHCTL2(timer_periph) &= (~(uint32_t)TIMER_CHCTL2_CH3NP);
+        TIMER_CHCTL2(timer_periph) |= (uint32_t)((uint32_t)ocnpolarity << 12U);
+        break;
+    default:
+        break;
+    }
+}
+
+/*!
+    \brief      configure TIMER channel enable state
+    \param[in]  timer_periph: please refer to the following parameters
+    \param[in]  channel:
+                only one parameter can be selected which is shown as below:
+      \arg        TIMER_CH_0: TIMER channel0(TIMERx(x=0,2,13..16)), TIMER1(not available in GD32F310)
+      \arg        TIMER_CH_1: TIMER channel1(TIMERx(x=0,2,14)), TIMER1(not available in GD32F310)
+      \arg        TIMER_CH_2: TIMER channel2(TIMERx(x=0,2)), TIMER1(not available in GD32F310)
+      \arg        TIMER_CH_3: TIMER channel3(TIMERx(x=0,2)), TIMER1(not available in GD32F310)
+    \param[in]  state: TIMER channel enable state
+                only one parameter can be selected which is shown as below:
+      \arg        TIMER_CCX_ENABLE: channel enable
+      \arg        TIMER_CCX_DISABLE: channel disable
+    \param[out] none
+    \retval     none
+*/
+void timer_channel_output_state_config(uint32_t timer_periph, uint16_t channel, uint32_t state)
+{
+    switch(channel) {
+    /* configure TIMER_CH_0 */
+    case TIMER_CH_0:
+        TIMER_CHCTL2(timer_periph) &= (~(uint32_t)TIMER_CHCTL2_CH0EN);
+        TIMER_CHCTL2(timer_periph) |= (uint32_t)state;
+        break;
+    /* configure TIMER_CH_1 */
+    case TIMER_CH_1:
+        TIMER_CHCTL2(timer_periph) &= (~(uint32_t)TIMER_CHCTL2_CH1EN);
+        TIMER_CHCTL2(timer_periph) |= (uint32_t)((uint32_t)state << 4U);
+        break;
+    /* configure TIMER_CH_2 */
+    case TIMER_CH_2:
+        TIMER_CHCTL2(timer_periph) &= (~(uint32_t)TIMER_CHCTL2_CH2EN);
+        TIMER_CHCTL2(timer_periph) |= (uint32_t)((uint32_t)state << 8U);
+        break;
+    /* configure TIMER_CH_3 */
+    case TIMER_CH_3:
+        TIMER_CHCTL2(timer_periph) &= (~(uint32_t)TIMER_CHCTL2_CH3EN);
+        TIMER_CHCTL2(timer_periph) |= (uint32_t)((uint32_t)state << 12U);
+        break;
+    default:
+        break;
+    }
+}
+
+/*!
+    \brief      configure TIMER channel complementary output enable state
+    \param[in]  timer_periph: TIMERx(x=0,14..16)
+    \param[in]  channel:
+                only one parameter can be selected which is shown as below:
+      \arg        TIMER_CH_0: TIMER channel0(TIMERx(x=0,14..16))
+      \arg        TIMER_CH_1: TIMER channel1(TIMERx(x=0))
+      \arg        TIMER_CH_2: TIMER channel2(TIMERx(x=0))
+    \param[in]  ocnstate: TIMER channel complementary output enable state
+                only one parameter can be selected which is shown as below:
+      \arg        TIMER_CCXN_ENABLE: channel complementary enable
+      \arg        TIMER_CCXN_DISABLE: channel complementary disable
+    \param[out] none
+    \retval     none
+*/
+void timer_channel_complementary_output_state_config(uint32_t timer_periph, uint16_t channel, uint16_t ocnstate)
+{
+    switch(channel) {
+    /* configure TIMER_CH_0 */
+    case TIMER_CH_0:
+        TIMER_CHCTL2(timer_periph) &= (~(uint32_t)TIMER_CHCTL2_CH0NEN);
+        TIMER_CHCTL2(timer_periph) |= (uint32_t)ocnstate;
+        break;
+    /* configure TIMER_CH_1 */
+    case TIMER_CH_1:
+        TIMER_CHCTL2(timer_periph) &= (~(uint32_t)TIMER_CHCTL2_CH1NEN);
+        TIMER_CHCTL2(timer_periph) |= (uint32_t)((uint32_t)ocnstate << 4U);
+        break;
+    /* configure TIMER_CH_2 */
+    case TIMER_CH_2:
+        TIMER_CHCTL2(timer_periph) &= (~(uint32_t)TIMER_CHCTL2_CH2NEN);
+        TIMER_CHCTL2(timer_periph) |= (uint32_t)((uint32_t)ocnstate << 8U);
+        break;
+    default:
+        break;
+    }
+}
+
+/*!
+    \brief      initialize TIMER channel input parameter struct with a default value
+    \param[in]  icpara: TIMER channel intput parameter struct
+    \param[out] none
+    \retval     none
+*/
+void timer_channel_input_struct_para_init(timer_ic_parameter_struct *icpara)
+{
+    /* initialize the channel input parameter struct member with the default value */
+    icpara->icpolarity  = TIMER_IC_POLARITY_RISING;
+    icpara->icselection = TIMER_IC_SELECTION_DIRECTTI;
+    icpara->icprescaler = TIMER_IC_PSC_DIV1;
+    icpara->icfilter    = 0U;
+}
+
+/*!
+    \brief      configure TIMER input capture parameter
+    \param[in]  timer_periph: please refer to the following parameters
+    \param[in]  channel:
+                only one parameter can be selected which is shown as below:
+      \arg        TIMER_CH_0: TIMER channel0(TIMERx(x=0,2,13..16)), TIMER1(not available in GD32F310)
+      \arg        TIMER_CH_1: TIMER channel1(TIMERx(x=0,2,14)), TIMER1(not available in GD32F310)
+      \arg        TIMER_CH_2: TIMER channel2(TIMERx(x=0,2)), TIMER1(not available in GD32F310)
+      \arg        TIMER_CH_3: TIMER channel3(TIMERx(x=0,2)), TIMER1(not available in GD32F310)
+     \param[in]  icpara: TIMER channel intput parameter struct
+                 icpolarity: TIMER_IC_POLARITY_RISING,TIMER_IC_POLARITY_FALLING,TIMER_IC_POLARITY_BOTH_EDGE
+                 icselection: TIMER_IC_SELECTION_DIRECTTI,TIMER_IC_SELECTION_INDIRECTTI,TIMER_IC_SELECTION_ITS
+                 icprescaler: TIMER_IC_PSC_DIV1,TIMER_IC_PSC_DIV2,TIMER_IC_PSC_DIV4,TIMER_IC_PSC_DIV8
+                 icfilter: 0~15
+    \param[out]  none
+    \retval      none
+*/
+void timer_input_capture_config(uint32_t timer_periph, uint16_t channel, timer_ic_parameter_struct *icpara)
+{
+    switch(channel) {
+    /* configure TIMER_CH_0 */
+    case TIMER_CH_0:
+        /* reset the CH0EN bit */
+        TIMER_CHCTL2(timer_periph) &= (~(uint32_t)TIMER_CHCTL2_CH0EN);
+
+        /* reset the CH0P and CH0NP bits */
+        TIMER_CHCTL2(timer_periph) &= (~(uint32_t)(TIMER_CHCTL2_CH0P | TIMER_CHCTL2_CH0NP));
+        TIMER_CHCTL2(timer_periph) |= (uint32_t)(icpara->icpolarity);
+        /* reset the CH0MS bit */
+        TIMER_CHCTL0(timer_periph) &= (~(uint32_t)TIMER_CHCTL0_CH0MS);
+        TIMER_CHCTL0(timer_periph) |= (uint32_t)(icpara->icselection);
+        /* reset the CH0CAPFLT bit */
+        TIMER_CHCTL0(timer_periph) &= (~(uint32_t)TIMER_CHCTL0_CH0CAPFLT);
+        TIMER_CHCTL0(timer_periph) |= (uint32_t)((uint32_t)(icpara->icfilter) << 4U);
+
+        /* set the CH0EN bit */
+        TIMER_CHCTL2(timer_periph) |= (uint32_t)TIMER_CHCTL2_CH0EN;
+        break;
+
+    /* configure TIMER_CH_1 */
+    case TIMER_CH_1:
+        /* reset the CH1EN bit */
+        TIMER_CHCTL2(timer_periph) &= (~(uint32_t)TIMER_CHCTL2_CH1EN);
+
+        /* reset the CH1P and CH1NP bits */
+        TIMER_CHCTL2(timer_periph) &= (~(uint32_t)(TIMER_CHCTL2_CH1P | TIMER_CHCTL2_CH1NP));
+        TIMER_CHCTL2(timer_periph) |= (uint32_t)((uint32_t)(icpara->icpolarity) << 4U);
+        /* reset the CH1MS bit */
+        TIMER_CHCTL0(timer_periph) &= (~(uint32_t)TIMER_CHCTL0_CH1MS);
+        TIMER_CHCTL0(timer_periph) |= (uint32_t)((uint32_t)(icpara->icselection) << 8U);
+        /* reset the CH1CAPFLT bit */
+        TIMER_CHCTL0(timer_periph) &= (~(uint32_t)TIMER_CHCTL0_CH1CAPFLT);
+        TIMER_CHCTL0(timer_periph) |= (uint32_t)((uint32_t)(icpara->icfilter) << 12U);
+
+        /* set the CH1EN bit */
+        TIMER_CHCTL2(timer_periph) |= (uint32_t)TIMER_CHCTL2_CH1EN;
+        break;
+    /* configure TIMER_CH_2 */
+    case TIMER_CH_2:
+        /* reset the CH2EN bit */
+        TIMER_CHCTL2(timer_periph) &= (~(uint32_t)TIMER_CHCTL2_CH2EN);
+
+        /* reset the CH2P and CH2NP bits */
+        TIMER_CHCTL2(timer_periph) &= (~(uint32_t)(TIMER_CHCTL2_CH2P | TIMER_CHCTL2_CH2NP));
+        TIMER_CHCTL2(timer_periph) |= (uint32_t)((uint32_t)(icpara->icpolarity) << 8U);
+
+        /* reset the CH2MS bit */
+        TIMER_CHCTL1(timer_periph) &= (~(uint32_t)TIMER_CHCTL1_CH2MS);
+        TIMER_CHCTL1(timer_periph) |= (uint32_t)((uint32_t)(icpara->icselection));
+
+        /* reset the CH2CAPFLT bit */
+        TIMER_CHCTL1(timer_periph) &= (~(uint32_t)TIMER_CHCTL1_CH2CAPFLT);
+        TIMER_CHCTL1(timer_periph) |= (uint32_t)((uint32_t)(icpara->icfilter) << 4U);
+
+        /* set the CH2EN bit */
+        TIMER_CHCTL2(timer_periph) |= (uint32_t)TIMER_CHCTL2_CH2EN;
+        break;
+    /* configure TIMER_CH_3 */
+    case TIMER_CH_3:
+        /* reset the CH3EN bit */
+        TIMER_CHCTL2(timer_periph) &= (~(uint32_t)TIMER_CHCTL2_CH3EN);
+
+        /* reset the CH3P and CH3NP bits */
+        TIMER_CHCTL2(timer_periph) &= (~(uint32_t)(TIMER_CHCTL2_CH3P | TIMER_CHCTL2_CH3NP));
+        TIMER_CHCTL2(timer_periph) |= (uint32_t)((uint32_t)(icpara->icpolarity) << 12U);
+
+        /* reset the CH3MS bit */
+        TIMER_CHCTL1(timer_periph) &= (~(uint32_t)TIMER_CHCTL1_CH3MS);
+        TIMER_CHCTL1(timer_periph) |= (uint32_t)((uint32_t)(icpara->icselection) << 8U);
+
+        /* reset the CH3CAPFLT bit */
+        TIMER_CHCTL1(timer_periph) &= (~(uint32_t)TIMER_CHCTL1_CH3CAPFLT);
+        TIMER_CHCTL1(timer_periph) |= (uint32_t)((uint32_t)(icpara->icfilter) << 12U);
+
+        /* set the CH3EN bit */
+        TIMER_CHCTL2(timer_periph) |= (uint32_t)TIMER_CHCTL2_CH3EN;
+        break;
+    default:
+        break;
+    }
+    /* configure TIMER channel input capture prescaler value */
+    timer_channel_input_capture_prescaler_config(timer_periph, channel, (uint16_t)(icpara->icprescaler));
+}
+
+/*!
+    \brief      configure TIMER channel input capture prescaler value
+    \param[in]  timer_periph: please refer to the following parameters
+    \param[in]  channel:
+                only one parameter can be selected which is shown as below:
+      \arg        TIMER_CH_0: TIMER channel0(TIMERx(x=0,2,13..16)), TIMER1(not available in GD32F310)
+      \arg        TIMER_CH_1: TIMER channel1(TIMERx(x=0,2,14)), TIMER1(not available in GD32F310)
+      \arg        TIMER_CH_2: TIMER channel2(TIMERx(x=0,2)), TIMER1(not available in GD32F310)
+      \arg        TIMER_CH_3: TIMER channel3(TIMERx(x=0,2)), TIMER1(not available in GD32F310)
+    \param[in]  prescaler: channel input capture prescaler value
+                only one parameter can be selected which is shown as below:
+      \arg        TIMER_IC_PSC_DIV1: no prescaler
+      \arg        TIMER_IC_PSC_DIV2: divided by 2
+      \arg        TIMER_IC_PSC_DIV4: divided by 4
+      \arg        TIMER_IC_PSC_DIV8: divided by 8
+    \param[out] none
+    \retval     none
+*/
+void timer_channel_input_capture_prescaler_config(uint32_t timer_periph, uint16_t channel, uint16_t prescaler)
+{
+    switch(channel) {
+    /* configure TIMER_CH_0 */
+    case TIMER_CH_0:
+        TIMER_CHCTL0(timer_periph) &= (~(uint32_t)TIMER_CHCTL0_CH0CAPPSC);
+        TIMER_CHCTL0(timer_periph) |= (uint32_t)prescaler;
+        break;
+    /* configure TIMER_CH_1 */
+    case TIMER_CH_1:
+        TIMER_CHCTL0(timer_periph) &= (~(uint32_t)TIMER_CHCTL0_CH1CAPPSC);
+        TIMER_CHCTL0(timer_periph) |= ((uint32_t)prescaler << 8U);
+        break;
+    /* configure TIMER_CH_2 */
+    case TIMER_CH_2:
+        TIMER_CHCTL1(timer_periph) &= (~(uint32_t)TIMER_CHCTL1_CH2CAPPSC);
+        TIMER_CHCTL1(timer_periph) |= (uint32_t)prescaler;
+        break;
+    /* configure TIMER_CH_3 */
+    case TIMER_CH_3:
+        TIMER_CHCTL1(timer_periph) &= (~(uint32_t)TIMER_CHCTL1_CH3CAPPSC);
+        TIMER_CHCTL1(timer_periph) |= ((uint32_t)prescaler << 8U);
+        break;
+    default:
+        break;
+    }
+}
+
+/*!
+    \brief      read TIMER channel capture compare register value
+    \param[in]  timer_periph: please refer to the following parameters
+    \param[in]  channel:
+                only one parameter can be selected which is shown as below:
+      \arg        TIMER_CH_0: TIMER channel0(TIMERx(x=0,2,13..16)), TIMER1(not available in GD32F310)
+      \arg        TIMER_CH_1: TIMER channel1(TIMERx(x=0,2,14)), TIMER1(not available in GD32F310)
+      \arg        TIMER_CH_2: TIMER channel2(TIMERx(x=0,2)), TIMER1(not available in GD32F310)
+      \arg        TIMER_CH_3: TIMER channel3(TIMERx(x=0,2)), TIMER1(not available in GD32F310)
+    \param[out] none
+    \retval     channel capture compare register value
+*/
+uint32_t timer_channel_capture_value_register_read(uint32_t timer_periph, uint16_t channel)
+{
+    uint32_t count_value = 0U;
+
+    switch(channel) {
+    /* read TIMER channel 0 capture compare register value */
+    case TIMER_CH_0:
+        count_value = TIMER_CH0CV(timer_periph);
+        break;
+    /* read TIMER channel 1 capture compare register value */
+    case TIMER_CH_1:
+        count_value = TIMER_CH1CV(timer_periph);
+        break;
+    /* read TIMER channel 2 capture compare register value */
+    case TIMER_CH_2:
+        count_value = TIMER_CH2CV(timer_periph);
+        break;
+    /* read TIMER channel 3 capture compare register value */
+    case TIMER_CH_3:
+        count_value = TIMER_CH3CV(timer_periph);
+        break;
+    default:
+        break;
+    }
+    return (count_value);
+}
+
+/*!
+    \brief      configure TIMER input pwm capture function
+    \param[in]  timer_periph: TIMERx(x=0,2,14), TIMER1(not available in GD32F310)
+    \param[in]  channel:
+                only one parameter can be selected which is shown as below:
+      \arg        TIMER_CH_0: TIMER channel0
+      \arg        TIMER_CH_1: TIMER channel1
+     \param[in]  icpwm:TIMER channel intput pwm parameter struct
+                 icpolarity: TIMER_IC_POLARITY_RISING,TIMER_IC_POLARITY_FALLING
+                 icselection: TIMER_IC_SELECTION_DIRECTTI,TIMER_IC_SELECTION_INDIRECTTI
+                 icprescaler: TIMER_IC_PSC_DIV1,TIMER_IC_PSC_DIV2,TIMER_IC_PSC_DIV4,TIMER_IC_PSC_DIV8
+                 icfilter: 0~15
+    \param[out] none
+    \retval     none
+*/
+void timer_input_pwm_capture_config(uint32_t timer_periph, uint16_t channel, timer_ic_parameter_struct *icpwm)
+{
+    uint16_t icpolarity  = 0x0U;
+    uint16_t icselection = 0x0U;
+
+    /* Set channel input polarity */
+    if(TIMER_IC_POLARITY_RISING == icpwm->icpolarity) {
+        icpolarity = TIMER_IC_POLARITY_FALLING;
+    } else {
+        icpolarity = TIMER_IC_POLARITY_RISING;
+    }
+
+    /* Set channel input mode selection */
+    if(TIMER_IC_SELECTION_DIRECTTI == icpwm->icselection) {
+        icselection = TIMER_IC_SELECTION_INDIRECTTI;
+    } else {
+        icselection = TIMER_IC_SELECTION_DIRECTTI;
+    }
+
+    if(TIMER_CH_0 == channel) {
+        /* reset the CH0EN bit */
+        TIMER_CHCTL2(timer_periph) &= (~(uint32_t)TIMER_CHCTL2_CH0EN);
+        /* reset the CH0P and CH0NP bits */
+        TIMER_CHCTL2(timer_periph) &= (~(uint32_t)(TIMER_CHCTL2_CH0P | TIMER_CHCTL2_CH0NP));
+        /* set the CH0P and CH0NP bits */
+        TIMER_CHCTL2(timer_periph) |= (uint32_t)(icpwm->icpolarity);
+        /* reset the CH0MS bit */
+        TIMER_CHCTL0(timer_periph) &= (~(uint32_t)TIMER_CHCTL0_CH0MS);
+        /* set the CH0MS bit */
+        TIMER_CHCTL0(timer_periph) |= (uint32_t)(icpwm->icselection);
+        /* reset the CH0CAPFLT bit */
+        TIMER_CHCTL0(timer_periph) &= (~(uint32_t)TIMER_CHCTL0_CH0CAPFLT);
+        /* set the CH0CAPFLT bit */
+        TIMER_CHCTL0(timer_periph) |= ((uint32_t)(icpwm->icfilter) << 4U);
+        /* set the CH0EN bit */
+        TIMER_CHCTL2(timer_periph) |= (uint32_t)TIMER_CHCTL2_CH0EN;
+        /* configure TIMER channel input capture prescaler value */
+        timer_channel_input_capture_prescaler_config(timer_periph, TIMER_CH_0, (uint16_t)(icpwm->icprescaler));
+
+        /* reset the CH1EN bit */
+        TIMER_CHCTL2(timer_periph) &= (~(uint32_t)TIMER_CHCTL2_CH1EN);
+        /* reset the CH1P and CH1NP bits */
+        TIMER_CHCTL2(timer_periph) &= (~(uint32_t)(TIMER_CHCTL2_CH1P | TIMER_CHCTL2_CH1NP));
+        /* set the CH1P and CH1NP bits */
+        TIMER_CHCTL2(timer_periph) |= (uint32_t)((uint32_t)icpolarity << 4U);
+        /* reset the CH1MS bit */
+        TIMER_CHCTL0(timer_periph) &= (~(uint32_t)TIMER_CHCTL0_CH1MS);
+        /* set the CH1MS bit */
+        TIMER_CHCTL0(timer_periph) |= (uint32_t)((uint32_t)icselection << 8U);
+        /* reset the CH1CAPFLT bit */
+        TIMER_CHCTL0(timer_periph) &= (~(uint32_t)TIMER_CHCTL0_CH1CAPFLT);
+        /* set the CH1CAPFLT bit */
+        TIMER_CHCTL0(timer_periph) |= (uint32_t)((uint32_t)(icpwm->icfilter) << 12U);
+        /* set the CH1EN bit */
+        TIMER_CHCTL2(timer_periph) |= (uint32_t)TIMER_CHCTL2_CH1EN;
+        /* configure TIMER channel input capture prescaler value */
+        timer_channel_input_capture_prescaler_config(timer_periph, TIMER_CH_1, (uint16_t)(icpwm->icprescaler));
+    } else {
+        /* reset the CH1EN bit */
+        TIMER_CHCTL2(timer_periph) &= (~(uint32_t)TIMER_CHCTL2_CH1EN);
+        /* reset the CH1P and CH1NP bits */
+        TIMER_CHCTL2(timer_periph) &= (~(uint32_t)(TIMER_CHCTL2_CH1P | TIMER_CHCTL2_CH1NP));
+        /* set the CH1P and CH1NP bits */
+        TIMER_CHCTL2(timer_periph) |= (uint32_t)((uint32_t)(icpwm->icpolarity) << 4U);
+        /* reset the CH1MS bit */
+        TIMER_CHCTL0(timer_periph) &= (~(uint32_t)TIMER_CHCTL0_CH1MS);
+        /* set the CH1MS bit */
+        TIMER_CHCTL0(timer_periph) |= (uint32_t)((uint32_t)(icpwm->icselection) << 8U);
+        /* reset the CH1CAPFLT bit */
+        TIMER_CHCTL0(timer_periph) &= (~(uint32_t)TIMER_CHCTL0_CH1CAPFLT);
+        /* set the CH1CAPFLT bit */
+        TIMER_CHCTL0(timer_periph) |= (uint32_t)((uint32_t)(icpwm->icfilter) << 12U);
+        /* set the CH1EN bit */
+        TIMER_CHCTL2(timer_periph) |= (uint32_t)TIMER_CHCTL2_CH1EN;
+        /* configure TIMER channel input capture prescaler value */
+        timer_channel_input_capture_prescaler_config(timer_periph, TIMER_CH_1, (uint16_t)(icpwm->icprescaler));
+
+        /* reset the CH0EN bit */
+        TIMER_CHCTL2(timer_periph) &= (~(uint32_t)TIMER_CHCTL2_CH0EN);
+        /* reset the CH0P and CH0NP bits */
+        TIMER_CHCTL2(timer_periph) &= (~(uint32_t)(TIMER_CHCTL2_CH0P | TIMER_CHCTL2_CH0NP));
+        /* set the CH0P and CH0NP bits */
+        TIMER_CHCTL2(timer_periph) |= (uint32_t)icpolarity;
+        /* reset the CH0MS bit */
+        TIMER_CHCTL0(timer_periph) &= (~(uint32_t)TIMER_CHCTL0_CH0MS);
+        /* set the CH0MS bit */
+        TIMER_CHCTL0(timer_periph) |= (uint32_t)icselection;
+        /* reset the CH0CAPFLT bit */
+        TIMER_CHCTL0(timer_periph) &= (~(uint32_t)TIMER_CHCTL0_CH0CAPFLT);
+        /* set the CH0CAPFLT bit */
+        TIMER_CHCTL0(timer_periph) |= ((uint32_t)(icpwm->icfilter) << 4U);
+        /* set the CH0EN bit */
+        TIMER_CHCTL2(timer_periph) |= (uint32_t)TIMER_CHCTL2_CH0EN;
+        /* configure TIMER channel input capture prescaler value */
+        timer_channel_input_capture_prescaler_config(timer_periph, TIMER_CH_0, (uint16_t)(icpwm->icprescaler));
+    }
+}
+
+/*!
+    \brief      configure TIMER hall sensor mode
+    \param[in]  timer_periph: TIMERx(x=0,2), TIMER1(not available in GD32F310)
+    \param[in]  hallmode:
+                only one parameter can be selected which is shown as below:
+      \arg        TIMER_HALLINTERFACE_ENABLE: TIMER hall sensor mode enable
+      \arg        TIMER_HALLINTERFACE_DISABLE: TIMER hall sensor mode disable
+    \param[out] none
+    \retval     none
+*/
+void timer_hall_mode_config(uint32_t timer_periph, uint8_t hallmode)
+{
+    if(TIMER_HALLINTERFACE_ENABLE == hallmode) {
+        TIMER_CTL1(timer_periph) |= (uint32_t)TIMER_CTL1_TI0S;
+    } else if(TIMER_HALLINTERFACE_DISABLE == hallmode) {
+        TIMER_CTL1(timer_periph) &= ~(uint32_t)TIMER_CTL1_TI0S;
+    } else {
+        /* illegal parameters */
+    }
+}
+
+/*!
+    \brief      select TIMER input trigger source
+    \param[in]  timer_periph: TIMERx(x=0,2,14), TIMER1(not available in GD32F310)
+    \param[in]  intrigger:
+                only one parameter can be selected which is shown as below:
+      \arg        TIMER_SMCFG_TRGSEL_ITI0: internal trigger 0(TIMERx(x=0,2,14)), TIMER1(not available in GD32F310)
+      \arg        TIMER_SMCFG_TRGSEL_ITI1: internal trigger 1(TIMERx(x=0,2,14)), TIMER1(not available in GD32F310)
+      \arg        TIMER_SMCFG_TRGSEL_ITI2: internal trigger 2(TIMERx(x=0,2)), TIMER1(not available in GD32F310)
+      \arg        TIMER_SMCFG_TRGSEL_CI0F_ED: TI0 edge detector(TIMERx(x=0,2,14)), TIMER1(not available in GD32F310)
+      \arg        TIMER_SMCFG_TRGSEL_CI0FE0: filtered TIMER input 0(TIMERx(x=0,2,14)), TIMER1(not available in GD32F310)
+      \arg        TIMER_SMCFG_TRGSEL_CI1FE1: filtered TIMER input 1(TIMERx(x=0,2,14)), TIMER1(not available in GD32F310)
+      \arg        TIMER_SMCFG_TRGSEL_ETIFP: external trigger(TIMERx(x=0,2)), TIMER1(not available in GD32F310)
+    \param[out] none
+    \retval     none
+*/
+void timer_input_trigger_source_select(uint32_t timer_periph, uint32_t intrigger)
+{
+    TIMER_SMCFG(timer_periph) &= (~(uint32_t)TIMER_SMCFG_TRGS);
+    TIMER_SMCFG(timer_periph) |= (uint32_t)intrigger;
+}
+
+/*!
+    \brief      select TIMER master mode output trigger source
+    \param[in]  timer_periph: TIMERx(x=0,2,14), TIMER1(not available in GD32F310), TIMER5(not available in GD32F310 and GD32F330)
+    \param[in]  outrigger:
+                only one parameter can be selected which is shown as below:
+      \arg        TIMER_TRI_OUT_SRC_RESET: the UPG bit as trigger output(TIMERx(x=0,2,14), TIMER1(not available in GD32F310), TIMER5(not available in GD32F310 and GD32F330)
+      \arg        TIMER_TRI_OUT_SRC_ENABLE: the counter enable signal TIMER_CTL0_CEN as trigger output(TIMERx(x=0,2,14), TIMER1(not available in GD32F310), TIMER5(not available in GD32F310 and GD32F330)
+      \arg        TIMER_TRI_OUT_SRC_UPDATE: update event as trigger output(TIMERx(x=0,2,14), TIMER1(not available in GD32F310), TIMER5(not available in GD32F310 and GD32F330)
+      \arg        TIMER_TRI_OUT_SRC_CH0: a capture or a compare match occurred in channal0 as trigger output TRGO
+      \arg        TIMER_TRI_OUT_SRC_O0CPRE: O0CPRE as trigger output(TIMERx(x=0,2,14)), TIMER1(not available in GD32F310)
+      \arg        TIMER_TRI_OUT_SRC_O1CPRE: O1CPRE as trigger output(TIMERx(x=0,2,14)), TIMER1(not available in GD32F310)
+      \arg        TIMER_TRI_OUT_SRC_O2CPRE: O2CPRE as trigger output(TIMERx(x=0,2,14)), TIMER1(not available in GD32F310)
+      \arg        TIMER_TRI_OUT_SRC_O3CPRE: O3CPRE as trigger output(TIMERx(x=0,2,14)), TIMER1(not available in GD32F310)
+    \param[out] none
+    \retval     none
+*/
+void timer_master_output_trigger_source_select(uint32_t timer_periph, uint32_t outrigger)
+{
+    TIMER_CTL1(timer_periph) &= (~(uint32_t)TIMER_CTL1_MMC);
+    TIMER_CTL1(timer_periph) |= (uint32_t)outrigger;
+}
+
+/*!
+    \brief      select TIMER slave mode
+    \param[in]  timer_periph: TIMERx(x=0,2,14), TIMER1(not available in GD32F310)
+    \param[in]  slavemode:
+                only one parameter can be selected which is shown as below:
+      \arg        TIMER_SLAVE_MODE_DISABLE: slave mode disable(TIMERx(x=0,2,14)), TIMER1(not available in GD32F310)
+      \arg        TIMER_QUAD_DECODER_MODE0: encoder mode 0(TIMERx(x=0,2)), TIMER1(not available in GD32F310)
+      \arg        TIMER_QUAD_DECODER_MODE1: encoder mode 1(TIMERx(x=0,2)), TIMER1(not available in GD32F310)
+      \arg        TIMER_QUAD_DECODER_MODE2: encoder mode 2(TIMERx(x=0,2)), TIMER1(not available in GD32F310)
+      \arg        TIMER_SLAVE_MODE_RESTART: restart mode(TIMERx(x=0,2,14)), TIMER1(not available in GD32F310)
+      \arg        TIMER_SLAVE_MODE_PAUSE: pause mode(TIMERx(x=0,2,14)), TIMER1(not available in GD32F310)
+      \arg        TIMER_SLAVE_MODE_EVENT: event mode(TIMERx(x=0,2,14)), TIMER1(not available in GD32F310)
+      \arg        TIMER_SLAVE_MODE_EXTERNAL0: external clock mode 0(TIMERx(x=0,2,14)), TIMER1(not available in GD32F310)
+    \param[out] none
+    \retval     none
+*/
+
+void timer_slave_mode_select(uint32_t timer_periph, uint32_t slavemode)
+{
+    TIMER_SMCFG(timer_periph) &= (~(uint32_t)TIMER_SMCFG_SMC);
+
+    TIMER_SMCFG(timer_periph) |= (uint32_t)slavemode;
+}
+
+/*!
+    \brief      configure TIMER master slave mode
+    \param[in]  timer_periph: TIMERx(x=0,2,14), TIMER1(not available in GD32F310)
+    \param[in]  masterslave:
+                only one parameter can be selected which is shown as below:
+      \arg        TIMER_MASTER_SLAVE_MODE_ENABLE: master slave mode enable
+      \arg        TIMER_MASTER_SLAVE_MODE_DISABLE: master slave mode disable
+    \param[out] none
+    \retval     none
+*/
+void timer_master_slave_mode_config(uint32_t timer_periph, uint8_t masterslave)
+{
+    if(TIMER_MASTER_SLAVE_MODE_ENABLE == masterslave) {
+        TIMER_SMCFG(timer_periph) |= (uint32_t)TIMER_SMCFG_MSM;
+    } else if(TIMER_MASTER_SLAVE_MODE_DISABLE == masterslave) {
+        TIMER_SMCFG(timer_periph) &= ~(uint32_t)TIMER_SMCFG_MSM;
+    } else {
+        /* illegal parameters */
+    }
+}
+
+/*!
+    \brief      configure TIMER external trigger input
+    \param[in]  timer_periph: TIMERx(x=0,2), TIMER1(not available in GD32F310)
+    \param[in]  extprescaler:
+                only one parameter can be selected which is shown as below:
+      \arg        TIMER_EXT_TRI_PSC_OFF: no divided
+      \arg        TIMER_EXT_TRI_PSC_DIV2: divided by 2
+      \arg        TIMER_EXT_TRI_PSC_DIV4: divided by 4
+      \arg        TIMER_EXT_TRI_PSC_DIV8: divided by 8
+    \param[in]  extpolarity:
+                only one parameter can be selected which is shown as below:
+      \arg        TIMER_ETP_FALLING: active low or falling edge active
+      \arg        TIMER_ETP_RISING: active high or rising edge active
+    \param[in]  extfilter: a value between 0 and 15
+    \param[out] none
+    \retval     none
+*/
+void timer_external_trigger_config(uint32_t timer_periph, uint32_t extprescaler,
+                                   uint32_t extpolarity, uint32_t extfilter)
+{
+    TIMER_SMCFG(timer_periph) &= (~(uint32_t)(TIMER_SMCFG_ETP | TIMER_SMCFG_ETPSC | TIMER_SMCFG_ETFC));
+    TIMER_SMCFG(timer_periph) |= (uint32_t)(extprescaler | extpolarity);
+    TIMER_SMCFG(timer_periph) |= (uint32_t)(extfilter << 8U);
+}
+
+/*!
+    \brief      configure TIMER quadrature decoder mode
+    \param[in]  timer_periph: TIMERx(x=0,2), TIMER1(not available in GD32F310)
+    \param[in]  decomode:
+                only one parameter can be selected which is shown as below:
+      \arg        TIMER_QUAD_DECODER_MODE0: counter counts on CI0FE0 edge depending on CI1FE1 level
+      \arg        TIMER_QUAD_DECODER_MODE1: counter counts on CI1FE1 edge depending on CI0FE0 level
+      \arg        TIMER_QUAD_DECODER_MODE1: counter counts on both CI0FE0 and CI1FE1 edges depending on the level of the other input
+    \param[in]  ic0polarity:
+                only one parameter can be selected which is shown as below:
+      \arg        TIMER_IC_POLARITY_RISING: capture rising edge
+      \arg        TIMER_IC_POLARITY_FALLING: capture falling edge
+    \param[in]  ic1polarity:
+                only one parameter can be selected which is shown as below:
+      \arg        TIMER_IC_POLARITY_RISING: capture rising edge
+      \arg        TIMER_IC_POLARITY_FALLING: capture falling edge
+    \param[out] none
+    \retval     none
+*/
+void timer_quadrature_decoder_mode_config(uint32_t timer_periph, uint32_t decomode,
+        uint16_t ic0polarity, uint16_t ic1polarity)
+{
+    TIMER_SMCFG(timer_periph) &= (~(uint32_t)TIMER_SMCFG_SMC);
+    TIMER_SMCFG(timer_periph) |= (uint32_t)decomode;
+
+    TIMER_CHCTL0(timer_periph) &= (uint32_t)(((~(uint32_t)TIMER_CHCTL0_CH0MS)) & ((~(uint32_t)TIMER_CHCTL0_CH1MS)));
+    TIMER_CHCTL0(timer_periph) |= (uint32_t)(TIMER_IC_SELECTION_DIRECTTI | ((uint32_t)TIMER_IC_SELECTION_DIRECTTI << 8U));
+
+    TIMER_CHCTL2(timer_periph) &= (~(uint32_t)(TIMER_CHCTL2_CH0P | TIMER_CHCTL2_CH0NP));
+    TIMER_CHCTL2(timer_periph) &= (~(uint32_t)(TIMER_CHCTL2_CH1P | TIMER_CHCTL2_CH1NP));
+    TIMER_CHCTL2(timer_periph) |= ((uint32_t)ic0polarity | ((uint32_t)ic1polarity << 4U));
+}
+
+/*!
+    \brief      configure TIMER internal clock mode
+    \param[in]  timer_periph: TIMERx(x=0,2,14), TIMER1(not available in GD32F310)
+    \param[out] none
+    \retval     none
+*/
+void timer_internal_clock_config(uint32_t timer_periph)
+{
+    TIMER_SMCFG(timer_periph) &= ~(uint32_t)TIMER_SMCFG_SMC;
+}
+
+/*!
+    \brief      configure TIMER the internal trigger as external clock input
+    \param[in]  timer_periph: TIMERx(x=0,2,14), TIMER1(not available in GD32F310)
+    \param[in]  intrigger:
+                only one parameter can be selected which is shown as below:
+      \arg        TIMER_SMCFG_TRGSEL_ITI0: internal trigger 0(TIMERx(x=0,2,14)), TIMER1(not available in GD32F310)
+      \arg        TIMER_SMCFG_TRGSEL_ITI1: internal trigger 1(TIMERx(x=0,2,14)), TIMER1(not available in GD32F310)
+      \arg        TIMER_SMCFG_TRGSEL_ITI2: internal trigger 2(TIMERx(x=0,2)), TIMER1(not available in GD32F310)
+    \param[out] none
+    \retval     none
+*/
+void timer_internal_trigger_as_external_clock_config(uint32_t timer_periph, uint32_t intrigger)
+{
+    timer_input_trigger_source_select(timer_periph, intrigger);
+    TIMER_SMCFG(timer_periph) &= ~(uint32_t)TIMER_SMCFG_SMC;
+    TIMER_SMCFG(timer_periph) |= (uint32_t)TIMER_SLAVE_MODE_EXTERNAL0;
+}
+
+/*!
+    \brief      configure TIMER the external trigger as external clock input
+    \param[in]  timer_periph: TIMERx(x=0,2,14), TIMER1(not available in GD32F310)
+    \param[in]  extrigger:
+                only one parameter can be selected which is shown as below:
+      \arg        TIMER_SMCFG_TRGSEL_CI0F_ED: TI0 edge detector
+      \arg        TIMER_SMCFG_TRGSEL_CI0FE0: filtered TIMER input 0
+      \arg        TIMER_SMCFG_TRGSEL_CI1FE1: filtered TIMER input 1
+    \param[in]  extpolarity:
+                only one parameter can be selected which is shown as below:
+      \arg        TIMER_IC_POLARITY_RISING: active high or rising edge active
+      \arg        TIMER_IC_POLARITY_FALLING: active low or falling edge active
+      \arg        TIMER_IC_POLARITY_BOTH_EDGE: active both edge
+    \param[in]  extfilter: a value between 0 and 15
+    \param[out] none
+    \retval     none
+*/
+void timer_external_trigger_as_external_clock_config(uint32_t timer_periph, uint32_t extrigger,
+        uint16_t extpolarity, uint32_t extfilter)
+{
+    if(TIMER_SMCFG_TRGSEL_CI1FE1 == extrigger) {
+        /* reset the CH1EN bit */
+        TIMER_CHCTL2(timer_periph) &= (~(uint32_t)TIMER_CHCTL2_CH1EN);
+        /* reset the CH1NP bit */
+        TIMER_CHCTL2(timer_periph) &= (~(uint32_t)(TIMER_CHCTL2_CH1P | TIMER_CHCTL2_CH1NP));
+        /* set the CH1NP bit */
+        TIMER_CHCTL2(timer_periph) |= (uint32_t)((uint32_t)extpolarity << 4U);
+        /* reset the CH1MS bit */
+        TIMER_CHCTL0(timer_periph) &= (~(uint32_t)TIMER_CHCTL0_CH1MS);
+        /* set the CH1MS bit */
+        TIMER_CHCTL0(timer_periph) |= (uint32_t)((uint32_t)TIMER_IC_SELECTION_DIRECTTI << 8U);
+        /* reset the CH1CAPFLT bit */
+        TIMER_CHCTL0(timer_periph) &= (~(uint32_t)TIMER_CHCTL0_CH1CAPFLT);
+        /* set the CH1CAPFLT bit */
+        TIMER_CHCTL0(timer_periph) |= (uint32_t)(extfilter << 12U);
+        /* set the CH1EN bit */
+        TIMER_CHCTL2(timer_periph) |= (uint32_t)TIMER_CHCTL2_CH1EN;
+    } else {
+        /* reset the CH0EN bit */
+        TIMER_CHCTL2(timer_periph) &= (~(uint32_t)TIMER_CHCTL2_CH0EN);
+        /* reset the CH0P and CH0NP bits */
+        TIMER_CHCTL2(timer_periph) &= (~(uint32_t)(TIMER_CHCTL2_CH0P | TIMER_CHCTL2_CH0NP));
+        /* set the CH0P and CH0NP bits */
+        TIMER_CHCTL2(timer_periph) |= (uint32_t)extpolarity;
+        /* reset the CH0MS bit */
+        TIMER_CHCTL0(timer_periph) &= (~(uint32_t)TIMER_CHCTL0_CH0MS);
+        /* set the CH0MS bit */
+        TIMER_CHCTL0(timer_periph) |= (uint32_t)TIMER_IC_SELECTION_DIRECTTI;
+        /* reset the CH0CAPFLT bit */
+        TIMER_CHCTL0(timer_periph) &= (~(uint32_t)TIMER_CHCTL0_CH0CAPFLT);
+        /* reset the CH0CAPFLT bit */
+        TIMER_CHCTL0(timer_periph) |= (uint32_t)(extfilter << 4U);
+        /* set the CH0EN bit */
+        TIMER_CHCTL2(timer_periph) |= (uint32_t)TIMER_CHCTL2_CH0EN;
+    }
+    /* select TIMER input trigger source */
+    timer_input_trigger_source_select(timer_periph, extrigger);
+    /* reset the SMC bit */
+    TIMER_SMCFG(timer_periph) &= (~(uint32_t)TIMER_SMCFG_SMC);
+    /* set the SMC bit */
+    TIMER_SMCFG(timer_periph) |= (uint32_t)TIMER_SLAVE_MODE_EXTERNAL0;
+}
+
+/*!
+    \brief      configure TIMER the external clock mode0
+    \param[in]  timer_periph: TIMERx(x=0,2), TIMER1(not available in GD32F310)
+    \param[in]  extprescaler:
+                only one parameter can be selected which is shown as below:
+      \arg        TIMER_EXT_TRI_PSC_OFF: no divided
+      \arg        TIMER_EXT_TRI_PSC_DIV2: divided by 2
+      \arg        TIMER_EXT_TRI_PSC_DIV4: divided by 4
+      \arg        TIMER_EXT_TRI_PSC_DIV8: divided by 8
+    \param[in]  extpolarity:
+                only one parameter can be selected which is shown as below:
+      \arg        TIMER_ETP_FALLING: active low or falling edge active
+      \arg        TIMER_ETP_RISING: active high or rising edge active
+    \param[in]  extfilter: a value between 0 and 15
+    \param[out] none
+    \retval     none
+*/
+void timer_external_clock_mode0_config(uint32_t timer_periph, uint32_t extprescaler,
+                                       uint32_t extpolarity, uint32_t extfilter)
+{
+    /* configure TIMER external trigger input */
+    timer_external_trigger_config(timer_periph, extprescaler, extpolarity, extfilter);
+
+    /* reset the SMC bit,TRGS bit */
+    TIMER_SMCFG(timer_periph) &= (~(uint32_t)(TIMER_SMCFG_SMC | TIMER_SMCFG_TRGS));
+    /* set the SMC bit,TRGS bit */
+    TIMER_SMCFG(timer_periph) |= (uint32_t)(TIMER_SLAVE_MODE_EXTERNAL0 | TIMER_SMCFG_TRGSEL_ETIFP);
+}
+
+/*!
+    \brief      configure TIMER the external clock mode1
+    \param[in]  timer_periph: TIMERx(x=0,2), TIMER1(not available in GD32F310)
+    \param[in]  extprescaler:
+                only one parameter can be selected which is shown as below:
+      \arg        TIMER_EXT_TRI_PSC_OFF: no divided
+      \arg        TIMER_EXT_TRI_PSC_DIV2: divided by 2
+      \arg        TIMER_EXT_TRI_PSC_DIV4: divided by 4
+      \arg        TIMER_EXT_TRI_PSC_DIV8: divided by 8
+    \param[in]  extpolarity:
+                only one parameter can be selected which is shown as below:
+      \arg        TIMER_ETP_FALLING: active low or falling edge active
+      \arg        TIMER_ETP_RISING: active high or rising edge active
+    \param[in]  extfilter: a value between 0 and 15
+    \param[out] none
+    \retval     none
+*/
+void timer_external_clock_mode1_config(uint32_t timer_periph, uint32_t extprescaler,
+                                       uint32_t extpolarity, uint32_t extfilter)
+{
+    /* configure TIMER external trigger input */
+    timer_external_trigger_config(timer_periph, extprescaler, extpolarity, extfilter);
+
+    TIMER_SMCFG(timer_periph) |= (uint32_t)TIMER_SMCFG_SMC1;
+}
+
+/*!
+    \brief      disable TIMER the external clock mode1
+    \param[in]  timer_periph: TIMERx(x=0,2), TIMER1(not available in GD32F310)
+    \param[out] none
+    \retval     none
+*/
+void timer_external_clock_mode1_disable(uint32_t timer_periph)
+{
+    TIMER_SMCFG(timer_periph) &= ~(uint32_t)TIMER_SMCFG_SMC1;
+}
+
+/*!
+    \brief      configure TIMER channel remap function
+    \param[in]  timer_periph: TIMERx(x=13)
+    \param[in]  remap:
+                only one parameter can be selected which is shown as below:
+      \arg        TIMER13_CI0_RMP_GPIO: timer13 channel 0 input is connected to GPIO(TIMER13_CH0)
+      \arg        TIMER13_CI0_RMP_RTCCLK: timer13 channel 0 input is connected to the RTCCLK
+      \arg        TIMER13_CI0_RMP_HXTAL_DIV32: timer13 channel 0 input is connected to HXTAL/32 clock
+      \arg        TIMER13_CI0_RMP_CKOUTSEL: timer13 channel 0 input is connected to CKOUTSEL
+    \param[out] none
+    \retval     none
+*/
+void timer_channel_remap_config(uint32_t timer_periph, uint32_t remap)
+{
+    TIMER_IRMP(timer_periph) = (uint32_t)remap;
+}
+
+/*!
+    \brief      configure TIMER write CHxVAL register selection
+    \param[in]  timer_periph: TIMERx(x=0,2,13..16), TIMER1(not available in GD32F310)
+    \param[in]  ccsel:
+                only one parameter can be selected which is shown as below:
+      \arg        TIMER_CHVSEL_DISABLE: no effect
+      \arg        TIMER_CHVSEL_ENABLE:  when write the CHxVAL register, if the write value is same as the CHxVAL value, the write access is ignored
+    \param[out] none
+    \retval     none
+*/
+void timer_write_chxval_register_config(uint32_t timer_periph, uint16_t ccsel)
+{
+    if(TIMER_CHVSEL_ENABLE == ccsel) {
+        TIMER_CFG(timer_periph) |= (uint32_t)TIMER_CFG_CHVSEL;
+    } else if(TIMER_CHVSEL_DISABLE == ccsel) {
+        TIMER_CFG(timer_periph) &= ~(uint32_t)TIMER_CFG_CHVSEL;
+    } else {
+        /* illegal parameters */
+    }
+}
+
+/*!
+    \brief      configure TIMER output value selection
+    \param[in]  timer_periph: TIMERx(x=0,14..16)
+    \param[in]  outsel:
+                only one parameter can be selected which is shown as below:
+      \arg        TIMER_OUTSEL_DISABLE: no effect
+      \arg        TIMER_OUTSEL_ENABLE: if POEN and IOS is 0, the output disabled
+    \param[out] none
+    \retval     none
+*/
+void timer_output_value_selection_config(uint32_t timer_periph, uint16_t outsel)
+{
+    if(TIMER_OUTSEL_ENABLE == outsel) {
+        TIMER_CFG(timer_periph) |= (uint32_t)TIMER_CFG_OUTSEL;
+    } else if(TIMER_OUTSEL_DISABLE == outsel) {
+        TIMER_CFG(timer_periph) &= ~(uint32_t)TIMER_CFG_OUTSEL;
+    } else {
+        /* illegal parameters */
+    }
+}

+ 696 - 0
GD32F3x0/GD32F3x0_standard_peripheral/Source/gd32f3x0_tsi.c

@@ -0,0 +1,696 @@
+/*!
+    \file    gd32f3x0_tsi.c
+    \brief   TSI driver
+
+    \version 2025-01-01, V2.5.0, firmware for GD32F3x0
+*/
+
+/*
+    Copyright (c) 2025, GigaDevice Semiconductor Inc.
+
+    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 of the copyright holder 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 HOLDER 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.
+*/
+
+#if defined (GD32F350) || defined (GD32F355) || defined (GD32F370)
+
+#include "gd32f3x0_tsi.h"
+
+/*!
+    \brief      reset TSI peripheral
+    \param[in]  none
+    \param[out] none
+    \retval     none
+*/
+void tsi_deinit(void)
+{
+    rcu_periph_reset_enable(RCU_TSIRST);
+    rcu_periph_reset_disable(RCU_TSIRST);
+}
+
+/*!
+    \brief      initialize TSI pulse prescaler,charge pulse,transfer pulse,max cycle number
+    \param[in]  prescaler: CTCLK clock division factor
+                only one parameter can be selected which is shown as below:
+      \arg        TSI_CTCDIV_DIV1: fCTCLK = fHCLK
+      \arg        TSI_CTCDIV_DIV2: fCTCLK = fHCLK/2
+      \arg        TSI_CTCDIV_DIV4: fCTCLK = fHCLK/4
+      \arg        TSI_CTCDIV_DIV8: fCTCLK = fHCLK/8
+      \arg        TSI_CTCDIV_DIV16: fCTCLK = fHCLK/16
+      \arg        TSI_CTCDIV_DIV32: fCTCLK = fHCLK/32
+      \arg        TSI_CTCDIV_DIV64: fCTCLK = fHCLK/64
+      \arg        TSI_CTCDIV_DIV128: fCTCLK = fHCLK/128
+      \arg        TSI_CTCDIV_DIV256: fCTCLK = fHCLK/256
+      \arg        TSI_CTCDIV_DIV512: fCTCLK = fHCLK/512
+      \arg        TSI_CTCDIV_DIV1024: fCTCLK = fHCLK/1024
+      \arg        TSI_CTCDIV_DIV2048: fCTCLK = fHCLK/2048
+      \arg        TSI_CTCDIV_DIV4096: fCTCLK = fHCLK/4096
+      \arg        TSI_CTCDIV_DIV8192: fCTCLK = fHCLK/8192
+      \arg        TSI_CTCDIV_DIV16384: fCTCLK = fHCLK/16384
+      \arg        TSI_CTCDIV_DIV32768: fCTCLK = fHCLK/32768
+    \param[in]  charge_duration: charge state duration time
+                only one parameter can be selected which is shown as below:
+      \arg        TSI_CHARGE_xCTCLK(x=1..16): the duration time of charge state is x CTCLK
+    \param[in]  transfer_duration: charge transfer state duration time
+                only one parameter can be selected which is shown as below:
+      \arg        TSI_TRANSFER_xCTCLK(x=1..16): the duration time of transfer state is x CTCLK
+    \param[in]  max_number: max cycle number
+                only one parameter can be selected which is shown as below:
+      \arg        TSI_MAXNUM255:  the max cycle number of a sequence is 255
+      \arg        TSI_MAXNUM511:  the max cycle number of a sequence is 511
+      \arg        TSI_MAXNUM1023: the max cycle number of a sequence is 1023
+      \arg        TSI_MAXNUM2047: the max cycle number of a sequence is 2047
+      \arg        TSI_MAXNUM4095: the max cycle number of a sequence is 4095
+      \arg        TSI_MAXNUM8191: the max cycle number of a sequence is 8191
+      \arg        TSI_MAXNUM16383: the max cycle number of a sequence is 16383
+    \param[out] none
+    \retval     none
+*/
+void tsi_init(uint32_t prescaler, uint32_t charge_duration, uint32_t transfer_duration, uint32_t max_number)
+{
+    uint32_t ctl0, ctl1;
+
+    if(RESET == (TSI_CTL0 & TSI_CTL0_TSIS)) {
+        if(TSI_CTCDIV_DIV256 > prescaler) {
+            /* configure TSI_CTL0 */
+            ctl0 = TSI_CTL0;
+            /*configure TSI clock division factor,charge state duration time,charge transfer state duration time */
+            ctl0 &= ~(TSI_CTL0_CTCDIV | TSI_CTL0_CTDT | TSI_CTL0_CDT | TSI_CTL0_MCN);
+            ctl0 |= ((prescaler << 12U) | charge_duration | transfer_duration | max_number);
+            TSI_CTL0 = ctl0;
+
+            /* configure TSI_CTL1 */
+            ctl1 = TSI_CTL1;
+            ctl1 &= ~TSI_CTL1_CTCDIV;
+            TSI_CTL1 = ctl1;
+        } else {
+            /* configure TSI_CTL0 */
+            ctl0 = TSI_CTL0;
+            prescaler &= ~0x08U;
+            /*configure TSI clock division factor,charge state duration time,charge transfer state duration time */
+            ctl0 &= ~(TSI_CTL0_CTCDIV | TSI_CTL0_CTDT | TSI_CTL0_CDT | TSI_CTL0_MCN);
+            ctl0 |= ((prescaler << 12U) | charge_duration | transfer_duration | max_number);
+            TSI_CTL0 = ctl0;
+
+            /* configure TSI_CTL1 */
+            ctl1 = TSI_CTL1;
+            ctl1 |= TSI_CTL1_CTCDIV;
+            TSI_CTL1 = ctl1;
+        }
+    }
+}
+
+/*!
+    \brief      enable TSI module
+    \param[in]  none
+    \param[out] none
+    \retval     none
+*/
+void tsi_enable(void)
+{
+    TSI_CTL0 |= TSI_CTL0_TSIEN;
+}
+
+/*!
+    \brief      disable TSI module
+    \param[in]  none
+    \param[out] none
+    \retval     none
+*/
+void tsi_disable(void)
+{
+    TSI_CTL0 &= ~TSI_CTL0_TSIEN;
+}
+
+/*!
+    \brief      enable sample pin
+    \param[in]  sample: sample pin
+                one or more parameters can be selected which are shown as below:
+      \arg        TSI_SAMPCFG_GxPy(x=0..5,y=0..3):pin y of group x is sample pin
+    \param[out] none
+    \retval     none
+*/
+void tsi_sample_pin_enable(uint32_t sample)
+{
+    if(RESET == (TSI_CTL0 & TSI_CTL0_TSIS)) {
+        TSI_SAMPCFG |= sample;
+    }
+}
+
+/*!
+    \brief      disable sample pin
+    \param[in]  sample: sample pin
+                one or more parameters can be selected which are shown as below:
+      \arg        TSI_SAMPCFG_GxPy(x=0..5,y =0..3): pin y of group x is sample pin
+    \param[out] none
+    \retval     none
+*/
+void tsi_sample_pin_disable(uint32_t sample)
+{
+    if(RESET == (TSI_CTL0 & TSI_CTL0_TSIS)) {
+        TSI_SAMPCFG &= ~sample;
+    }
+}
+
+/*!
+    \brief      enable channel pin
+    \param[in]  channel: channel pin
+                one or more parameters can be selected which are shown as below:
+      \arg        TSI_CHCFG_GxPy(x=0..5,y=0..3): pin y of group x
+    \param[out] none
+    \retval     none
+*/
+void tsi_channel_pin_enable(uint32_t channel)
+{
+    TSI_CHCFG |= channel;
+}
+
+/*!
+    \brief      disable channel pin
+    \param[in]  channel: channel pin
+                one or more parameters can be selected which are shown as below:
+      \arg        TSI_CHCFG_GxPy(x=0..5,y=0..3): pin y of group x
+    \param[out] none
+    \retval     none
+*/
+void tsi_channel_pin_disable(uint32_t channel)
+{
+    TSI_CHCFG &= ~channel;
+}
+
+/*!
+    \brief      configure TSI triggering by software
+    \param[in]  none
+    \param[out] none
+    \retval     none
+*/
+void tsi_software_mode_config(void)
+{
+    if(RESET == (TSI_CTL0 & TSI_CTL0_TSIS)) {
+        TSI_CTL0 &= ~TSI_CTL0_TRGMOD;
+    }
+}
+
+/*!
+    \brief      start a charge-transfer sequence when TSI is in software trigger mode
+    \param[in]  none
+    \param[out] none
+    \retval     none
+*/
+void tsi_software_start(void)
+{
+    TSI_CTL0 |= TSI_CTL0_TSIS;
+}
+
+/*!
+    \brief      stop a charge-transfer sequence when TSI is in software trigger mode
+    \param[in]  none
+    \param[out] none
+    \retval     none
+*/
+void tsi_software_stop(void)
+{
+    TSI_CTL0 &= ~TSI_CTL0_TSIS;
+}
+
+/*!
+    \brief      configure TSI triggering by hardware
+    \param[in]  trigger_edge: the edge type in hardware trigger mode
+                only one parameter can be selected which is shown as below:
+      \arg        TSI_FALLING_TRIGGER: falling edge trigger TSI charge transfer sequence
+      \arg        TSI_RISING_TRIGGER:  rising edge trigger TSI charge transfer sequence
+    \param[out] none
+    \retval     none
+*/
+void tsi_hardware_mode_config(uint8_t trigger_edge)
+{
+    if(RESET == (TSI_CTL0 & TSI_CTL0_TSIS)) {
+        /*enable hardware mode*/
+        TSI_CTL0 |= TSI_CTL0_TRGMOD;
+        /*configure the edge type in hardware trigger mode*/
+        if(TSI_FALLING_TRIGGER == trigger_edge) {
+            TSI_CTL0 &= ~TSI_CTL0_EGSEL;
+        } else {
+            TSI_CTL0 |= TSI_CTL0_EGSEL;
+        }
+    }
+}
+
+/*!
+    \brief      configure TSI pin mode when charge-transfer sequence is IDLE
+    \param[in]  pin_mode: pin mode when charge-transfer sequence is IDLE
+                only one parameter can be selected which is shown as below:
+      \arg        TSI_OUTPUT_LOW: TSI pin will output low when IDLE
+      \arg        TSI_INPUT_FLOATING: TSI pin will keep input_floating when IDLE
+    \param[out] none
+    \retval     none
+*/
+void tsi_pin_mode_config(uint8_t pin_mode)
+{
+    if(RESET == (TSI_CTL0 & TSI_CTL0_TSIS)) {
+        if(TSI_OUTPUT_LOW == pin_mode) {
+            TSI_CTL0 &= ~TSI_CTL0_PINMOD;
+        } else {
+            TSI_CTL0 |= TSI_CTL0_PINMOD;
+        }
+    }
+}
+
+/*!
+    \brief      configure extend charge state
+    \param[in]  extend: enable or disable extend charge state
+                only one parameter can be selected which is shown as below:
+      \arg        ENABLE:  enable extend charge state
+      \arg        DISABLE: disable extend charge state
+    \param[in]  prescaler: ECCLK clock division factor
+                only one parameter can be selected which is shown as below:
+      \arg        TSI_EXTEND_DIV1: fECCLK = fHCLK
+      \arg        TSI_EXTEND_DIV2: fECCLK = fHCLK/2
+      \arg        TSI_EXTEND_DIV3: fECCLK = fHCLK/3
+      \arg        TSI_EXTEND_DIV4: fECCLK = fHCLK/4
+      \arg        TSI_EXTEND_DIV5: fECCLK = fHCLK/5
+      \arg        TSI_EXTEND_DIV6: fECCLK = fHCLK/6
+      \arg        TSI_EXTEND_DIV7: fECCLK = fHCLK/7
+      \arg        TSI_EXTEND_DIV8: fECCLK = fHCLK/8
+    \param[in]  max_duration: value range 1...128,extend charge state maximum duration time is 1*tECCLK~128*tECCLK
+    \param[out] none
+    \retval     none
+*/
+void tsi_extend_charge_config(ControlStatus extend, uint8_t prescaler, uint32_t max_duration)
+{
+    uint32_t ctl0, ctl1;
+
+    if(RESET == (TSI_CTL0 & TSI_CTL0_TSIS)) {
+        if(DISABLE == extend) {
+            /*disable extend charge state*/
+            TSI_CTL0 &= ~TSI_CTL0_ECEN;
+        } else {
+            if(TSI_EXTEND_DIV3 > prescaler) {
+                /*configure extend charge state maximum duration time*/
+                ctl0 = TSI_CTL0;
+                ctl0 &= ~TSI_CTL0_ECDT;
+                ctl0 |= TSI_EXTENDMAX((max_duration - 1U));
+                TSI_CTL0 = ctl0;
+                /*configure ECCLK clock division factor*/
+                ctl0 = TSI_CTL0;
+                ctl0 &= ~TSI_CTL0_ECDIV;
+                ctl0 |= (uint32_t)prescaler << 15U;
+                TSI_CTL0 = ctl0;
+                ctl1 = TSI_CTL1;
+                ctl1 &= ~TSI_CTL1_ECDIV;
+                TSI_CTL1 = ctl1;
+                /*enable extend charge state*/
+                TSI_CTL0 |= TSI_CTL0_ECEN;
+            } else {
+                /*configure extend charge state maximum duration time*/
+                ctl0 = TSI_CTL0;
+                ctl0 &= ~TSI_CTL0_ECDT;
+                ctl0 |= TSI_EXTENDMAX((max_duration - 1U));
+                TSI_CTL0 = ctl0;
+                /*configure ECCLK clock division factor*/
+                ctl0 = TSI_CTL0;
+                ctl0 &= ~TSI_CTL0_ECDIV;
+                ctl0 |= (prescaler & 0x01U) << 15U;
+                TSI_CTL0 = ctl0;
+                ctl1 = TSI_CTL1;
+                ctl1 &= ~TSI_CTL1_ECDIV;
+                ctl1 |= (prescaler & 0x06U) << 27U;
+                TSI_CTL1 = ctl1;
+                /*enable extend charge state*/
+                TSI_CTL0 |= TSI_CTL0_ECEN;
+            }
+        }
+    }
+}
+
+/*!
+    \brief      configure charge pulse and transfer pulse
+    \param[in]  prescaler: CTCLK clock division factor
+                only one parameter can be selected which is shown as below:
+      \arg        TSI_CTCDIV_DIV1: fCTCLK = fHCLK
+      \arg        TSI_CTCDIV_DIV2: fCTCLK = fHCLK/2
+      \arg        TSI_CTCDIV_DIV4: fCTCLK = fHCLK/4
+      \arg        TSI_CTCDIV_DIV8: fCTCLK = fHCLK/8
+      \arg        TSI_CTCDIV_DIV16: fCTCLK = fHCLK/16
+      \arg        TSI_CTCDIV_DIV32: fCTCLK = fHCLK/32
+      \arg        TSI_CTCDIV_DIV64: fCTCLK = fHCLK/64
+      \arg        TSI_CTCDIV_DIV128: fCTCLK = fHCLK/128
+      \arg        TSI_CTCDIV_DIV256: fCTCLK = fHCLK/256
+      \arg        TSI_CTCDIV_DIV512: fCTCLK = fHCLK/512
+      \arg        TSI_CTCDIV_DIV1024: fCTCLK = fHCLK/1024
+      \arg        TSI_CTCDIV_DIV2048: fCTCLK = fHCLK/2048
+      \arg        TSI_CTCDIV_DIV4096: fCTCLK = fHCLK/4096
+      \arg        TSI_CTCDIV_DIV8192: fCTCLK = fHCLK/8192
+      \arg        TSI_CTCDIV_DIV16384: fCTCLK = fHCLK/16384
+      \arg        TSI_CTCDIV_DIV32768: fCTCLK = fHCLK/32768
+    \param[in]  charge_duration: charge state duration time
+                only one parameter can be selected which is shown as below:
+      \arg        TSI_CHARGE_xCTCLK(x=1..16): the duration time of charge state is x CTCLK
+    \param[in]  transfer_duration: charge transfer state duration time
+                only one parameter can be selected which is shown as below:
+      \arg        TSI_TRANSFER_xCTCLK(x=1..16): the duration time of transfer state is x CTCLK
+    \param[out] none
+    \retval     none
+*/
+void tsi_pulse_config(uint32_t prescaler, uint32_t charge_duration, uint32_t transfer_duration)
+{
+    uint32_t ctl0, ctl1;
+
+    if(RESET == (TSI_CTL0 & TSI_CTL0_TSIS)) {
+        if(TSI_CTCDIV_DIV256 > prescaler) {
+            /* configure TSI_CTL0 */
+            ctl0 = TSI_CTL0;
+            /*configure TSI clock division factor,charge state duration time,charge transfer state duration time */
+            ctl0 &= ~(TSI_CTL0_CTCDIV | TSI_CTL0_CTDT | TSI_CTL0_CDT);
+            ctl0 |= ((prescaler << 12U) | charge_duration | transfer_duration);
+            TSI_CTL0 = ctl0;
+
+            /* configure TSI_CTL1 */
+            ctl1 = TSI_CTL1;
+            ctl1 &= ~TSI_CTL1_CTCDIV;
+            TSI_CTL1 = ctl1;
+        } else {
+            /* configure TSI_CTL */
+            ctl0 = TSI_CTL0;
+            prescaler &= ~0x08U;
+            /*configure TSI clock division factor,charge state duration time,charge transfer state duration time */
+            ctl0 &= ~(TSI_CTL0_CTCDIV | TSI_CTL0_CTDT | TSI_CTL0_CDT);
+            ctl0 |= ((prescaler << 12U) | charge_duration | transfer_duration);
+            TSI_CTL0 = ctl0;
+
+            /* configure TSI_CTL1 */
+            ctl1 = TSI_CTL1;
+            ctl1 |= TSI_CTL1_CTCDIV;
+            TSI_CTL1 = ctl1;
+        }
+    }
+}
+
+/*!
+    \brief      configure the max cycle number of a charge-transfer sequence
+    \param[in]  max_number: max cycle number
+                only one parameter can be selected which is shown as below:
+      \arg        TSI_MAXNUM255: the max cycle number of a sequence is 255
+      \arg        TSI_MAXNUM511: the max cycle number of a sequence is 511
+      \arg        TSI_MAXNUM1023: the max cycle number of a sequence is 1023
+      \arg        TSI_MAXNUM2047: the max cycle number of a sequence is 2047
+      \arg        TSI_MAXNUM4095: the max cycle number of a sequence is 4095
+      \arg        TSI_MAXNUM8191: the max cycle number of a sequence is 8191
+      \arg        TSI_MAXNUM16383: the max cycle number of a sequence is 16383
+    \param[out] none
+    \retval     none
+*/
+void tsi_max_number_config(uint32_t max_number)
+{
+    if(RESET == (TSI_CTL0 & TSI_CTL0_TSIS)) {
+        uint32_t maxnum;
+        maxnum = TSI_CTL0;
+        /*configure the max cycle number of a charge-transfer sequence*/
+        maxnum &= ~TSI_CTL0_MCN;
+        maxnum |= max_number;
+        TSI_CTL0 = maxnum;
+    }
+}
+
+/*!
+    \brief      switch on hysteresis pin
+    \param[in]  group_pin: select pin which will be switched on hysteresis
+                one or more parameters can be selected which are shown as below:
+      \arg        TSI_PHM_GxPy(x=0..5,y=0..3): pin y of group x switch on hysteresis
+    \param[out] none
+    \retval     none
+*/
+void tsi_hysteresis_on(uint32_t group_pin)
+{
+    TSI_PHM |= group_pin;
+}
+
+/*!
+    \brief      switch off hysteresis pin
+    \param[in]  group_pin: select pin which will be switched off hysteresis
+                one or more parameters can be selected which are shown as below:
+      \arg        TSI_PHM_GxPy(x=0..5,y=0..3): pin y of group x switch off hysteresis
+    \param[out] none
+    \retval     none
+*/
+void tsi_hysteresis_off(uint32_t group_pin)
+{
+    TSI_PHM &= ~group_pin;
+}
+
+/*!
+    \brief      switch on analog pin
+    \param[in]  group_pin: select pin which will be switched on analog
+                one or more parameters can be selected which are shown as below:
+      \arg        TSI_ASW_GxPy(x=0..5,y=0..3):pin y of group x switch on analog
+    \param[out] none
+    \retval     none
+*/
+void tsi_analog_on(uint32_t group_pin)
+{
+    TSI_ASW |= group_pin;
+}
+
+/*!
+    \brief      switch off analog pin
+    \param[in]  group_pin: select pin which will be switched off analog
+                one or more parameters can be selected which are shown as below:
+      \arg        TSI_ASW_GxPy(x=0..5,y=0..3):pin y of group x switch off analog
+    \param[out] none
+    \retval     none
+*/
+void tsi_analog_off(uint32_t group_pin)
+{
+    TSI_ASW &= ~group_pin;
+}
+
+/*!
+    \brief      enable group
+    \param[in]  group: select group to be enabled
+                one or more parameters can be selected which are shown as below:
+      \arg        TSI_GCTL_GEx(x=0..5): the x group will be enabled
+    \param[out] none
+    \retval     none
+*/
+void tsi_group_enable(uint32_t group)
+{
+    TSI_GCTL |= group;
+}
+
+/*!
+    \brief      disable group
+    \param[in]  group: select group to be disabled
+                one or more parameters can be selected which are shown as below:
+      \arg        TSI_GCTL_GEx(x=0..5):the x group will be disabled
+    \param[out] none
+    \retval     none
+*/
+void tsi_group_disable(uint32_t group)
+{
+    TSI_GCTL &= ~group;
+}
+
+/*!
+    \brief      get group complete status
+    \param[in]  group: select group
+                only one parameter can be selected which is shown as below:
+      \arg        TSI_GCTL_GCx(x=0..5): get the complete status of group x
+    \param[out] none
+    \retval     FlagStatus: group complete status,SET or RESET
+*/
+FlagStatus tsi_group_status_get(uint32_t group)
+{
+    FlagStatus flag_status;
+
+    if(TSI_GCTL & group) {
+        flag_status = SET;
+    } else {
+        flag_status = RESET;
+    }
+    return flag_status;
+}
+
+/*!
+    \brief      get the cycle number for group0 as soon as a charge-transfer sequence completes
+    \param[in]  none
+    \param[out] none
+    \retval     group0 cycle number
+*/
+uint16_t tsi_group0_cycle_get(void)
+{
+    return (uint16_t)TSI_G0CYCN;
+}
+
+/*!
+    \brief      get the cycle number for group1 as soon as a charge-transfer sequence completes
+    \param[in]  none
+    \param[out] none
+    \retval     group1 cycle number
+*/
+uint16_t tsi_group1_cycle_get(void)
+{
+    return (uint16_t)TSI_G1CYCN;
+}
+
+/*!
+    \brief      get the cycle number for group2 as soon as a charge-transfer sequence completes
+    \param[in]  none
+    \param[out] none
+    \retval     group2 cycle number
+*/
+uint16_t tsi_group2_cycle_get(void)
+{
+    return (uint16_t)TSI_G2CYCN;
+}
+
+/*!
+    \brief      get the cycle number for group3 as soon as a charge-transfer sequence completes
+    \param[in]  none
+    \param[out] none
+    \retval     group3 cycle number
+*/
+uint16_t tsi_group3_cycle_get(void)
+{
+    return (uint16_t)TSI_G3CYCN;
+}
+
+/*!
+    \brief      get the cycle number for group4 as soon as a charge-transfer sequence completes
+    \param[in]  none
+    \param[out] none
+    \retval     group4 cycle number
+*/
+uint16_t tsi_group4_cycle_get(void)
+{
+    return (uint16_t)TSI_G4CYCN;
+}
+
+/*!
+    \brief      get the cycle number for group5 as soon as a charge-transfer sequence completes
+    \param[in]  none
+    \param[out] none
+    \retval     group5 cycle number
+*/
+uint16_t tsi_group5_cycle_get(void)
+{
+    return (uint16_t)TSI_G5CYCN;
+}
+
+/*!
+    \brief      get TSI flag
+    \param[in]  flag:
+                only one parameter can be selected which is shown as below:
+      \arg        TSI_FLAG_CTCF: charge-transfer complete flag
+      \arg        TSI_FLAG_MNERR: max cycle number error
+    \param[out] none
+    \retval     FlagStatus:SET or RESET
+*/
+FlagStatus tsi_flag_get(uint32_t flag)
+{
+    FlagStatus flag_status;
+    if(TSI_INTF & flag) {
+        flag_status = SET;
+    } else {
+        flag_status = RESET;
+    }
+    return flag_status;
+}
+
+/*!
+    \brief      clear TSI flag
+    \param[in]  flag: select flag which will be cleared
+                only one parameter can be selected which is shown as below:
+      \arg        TSI_FLAG_CTCF: clear charge-transfer complete flag
+      \arg        TSI_FLAG_MNERR: clear max cycle number error
+    \param[out] none
+    \retval     none
+*/
+void tsi_flag_clear(uint32_t flag)
+{
+    TSI_INTC |= flag;
+}
+
+/*!
+    \brief      enable TSI interrupt
+    \param[in]  source: select interrupt which will be enabled
+                only one parameter can be selected which is shown as below:
+      \arg        TSI_INT_CCTCF: charge-transfer complete flag interrupt enable
+      \arg        TSI_INT_MNERR:  max cycle number error interrupt enable
+    \param[out] none
+    \retval     none
+*/
+void tsi_interrupt_enable(uint32_t source)
+{
+    TSI_INTEN |= source;
+}
+
+/*!
+    \brief      disable TSI interrupt
+    \param[in]  source: select interrupt which will be disabled
+                only one parameter can be selected which is shown as below:
+      \arg        TSI_INT_CCTCF: charge-transfer complete flag interrupt disable
+      \arg        TSI_INT_MNERR: max cycle number error interrupt disable
+    \param[out] none
+    \retval     none
+*/
+void tsi_interrupt_disable(uint32_t source)
+{
+    TSI_INTEN &= ~source;
+}
+
+/*!
+    \brief      get TSI interrupt flag
+    \param[in]  flag:
+                only one parameter can be selected which is shown as below:
+      \arg        TSI_INT_FLAG_CTCF: charge-transfer complete flag
+      \arg        TSI_INT_FLAG_MNERR: max Cycle Number Error
+    \param[out] none
+    \retval     FlagStatus:SET or RESET
+*/
+FlagStatus tsi_interrupt_flag_get(uint32_t flag)
+{
+    uint32_t interrupt_enable = 0U, interrupt_flag = 0U;
+    interrupt_flag = (TSI_INTF & flag);
+    interrupt_enable = (TSI_INTEN & flag);
+    if(interrupt_flag && interrupt_enable) {
+        return SET;
+    } else {
+        return RESET;
+    }
+}
+
+/*!
+    \brief      clear TSI interrupt flag
+    \param[in]  flag: select flag which will be cleared
+                only one parameter can be selected which is shown as below:
+      \arg        TSI_INT_FLAG_CTCF: clear charge-transfer complete flag
+      \arg        TSI_INT_FLAG_MNERR: clear max cycle number error
+    \param[out] none
+    \retval     none
+*/
+void tsi_interrupt_flag_clear(uint32_t flag)
+{
+    TSI_INTC |= flag;
+}
+
+#endif /* GD32F350 || GD32F355 || GD32F370 */

+ 1259 - 0
GD32F3x0/GD32F3x0_standard_peripheral/Source/gd32f3x0_usart.c

@@ -0,0 +1,1259 @@
+/*!
+    \file    gd32f3x0_usart.c
+    \brief   USART driver
+
+    \version 2025-01-01, V2.5.0, firmware for GD32F3x0
+*/
+
+/*
+    Copyright (c) 2025, GigaDevice Semiconductor Inc.
+
+    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 of the copyright holder 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 HOLDER 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.
+*/
+
+#include "gd32f3x0_usart.h"
+
+/* USART register bit offset */
+#define CTL1_ADDR_OFFSET             ((uint32_t)24U)     /* bit offset of ADDR in USART_CTL1 */
+#define GP_GUAT_OFFSET               ((uint32_t)8U)      /* bit offset of GUAT in USART_GP */
+#define CTL2_SCRTNUM_OFFSET          ((uint32_t)17U)     /* bit offset of SCRTNUM in USART_CTL2 */
+#define RT_BL_OFFSET                 ((uint32_t)24U)     /* bit offset of BL in USART_RT */
+#define CTL0_DEA_OFFSET              ((uint32_t)21U)     /* bit offset of DEA in USART_CTL0 */
+#define CTL0_DED_OFFSET              ((uint32_t)16U)     /* bit offset of DED in USART_CTL0 */
+
+/*!
+    \brief      reset USART
+    \param[in]  usart_periph: USARTx(x=0,1)
+    \param[out] none
+    \retval     none
+*/
+void usart_deinit(uint32_t usart_periph)
+{
+    switch(usart_periph) {
+    case USART0:
+        /* reset USART0 */
+        rcu_periph_reset_enable(RCU_USART0RST);
+        rcu_periph_reset_disable(RCU_USART0RST);
+        break;
+    case USART1:
+        /* reset USART1 */
+        rcu_periph_reset_enable(RCU_USART1RST);
+        rcu_periph_reset_disable(RCU_USART1RST);
+        break;
+    default:
+        break;
+    }
+}
+
+/*!
+    \brief      configure USART baud rate value
+    \param[in]  usart_periph: USARTx(x=0,1)
+    \param[in]  baudval: baud rate value
+    \param[out] none
+    \retval     none
+*/
+void usart_baudrate_set(uint32_t usart_periph, uint32_t baudval)
+{
+    uint32_t uclk = 0U, intdiv = 0U, fradiv = 0U, udiv = 0U;
+    switch(usart_periph) {
+    /* get clock frequency */
+    case USART0:
+        /* get USART0 clock */
+        uclk = rcu_clock_freq_get(CK_USART);
+        break;
+    case USART1:
+        /* get USART1 clock */
+        uclk = rcu_clock_freq_get(CK_APB1);
+        break;
+    default:
+        break;
+    }
+    if(USART_CTL0(usart_periph) & USART_CTL0_OVSMOD) {
+        /* oversampling by 8, configure the value of USART_BAUD */
+        udiv = ((2U * uclk) + (baudval / 2U)) / baudval;
+        intdiv = udiv & 0x0000fff0U;
+        fradiv = (udiv >> 1U) & 0x00000007U;
+        USART_BAUD(usart_periph) = ((USART_BAUD_FRADIV | USART_BAUD_INTDIV) & (intdiv | fradiv));
+    } else {
+        /* oversampling by 16, configure the value of USART_BAUD */
+        udiv = (uclk + (baudval / 2U)) / baudval;
+        intdiv = udiv & 0x0000fff0U;
+        fradiv = udiv & 0x0000000fU;
+        USART_BAUD(usart_periph) = ((USART_BAUD_FRADIV | USART_BAUD_INTDIV) & (intdiv | fradiv));
+    }
+}
+
+/*!
+    \brief      configure USART parity
+    \param[in]  usart_periph: USARTx(x=0,1)
+    \param[in]  paritycfg: USART parity configure
+                only one parameter can be selected which is shown as below:
+      \arg        USART_PM_NONE: no parity
+      \arg        USART_PM_ODD: odd parity
+      \arg        USART_PM_EVEN: even parity
+    \param[out] none
+    \retval     none
+*/
+void usart_parity_config(uint32_t usart_periph, uint32_t paritycfg)
+{
+    /* disable USART */
+    USART_CTL0(usart_periph) &= ~(USART_CTL0_UEN);
+    /* clear USART_CTL0 PM,PCEN bits */
+    USART_CTL0(usart_periph) &= ~(USART_CTL0_PM | USART_CTL0_PCEN);
+    /* configure USART parity mode */
+    USART_CTL0(usart_periph) |= paritycfg;
+}
+
+/*!
+    \brief      configure USART word length
+    \param[in]  usart_periph: USARTx(x=0,1)
+    \param[in]  wlen: USART word length configure
+                only one parameter can be selected which is shown as below:
+      \arg        USART_WL_8BIT: 8 bits
+      \arg        USART_WL_9BIT: 9 bits
+    \param[out] none
+    \retval     none
+*/
+void usart_word_length_set(uint32_t usart_periph, uint32_t wlen)
+{
+    /* disable USART */
+    USART_CTL0(usart_periph) &= ~(USART_CTL0_UEN);
+    /* clear USART_CTL0 WL bit */
+    USART_CTL0(usart_periph) &= ~USART_CTL0_WL;
+    /* configure USART word length */
+    USART_CTL0(usart_periph) |= wlen;
+}
+
+/*!
+    \brief      configure USART stop bit length
+    \param[in]  usart_periph: USARTx(x=0,1)
+    \param[in]  stblen: USART stop bit configure
+                only one parameter can be selected which is shown as below:
+      \arg        USART_STB_1BIT: 1 bit
+      \arg        USART_STB_0_5BIT: 0.5bit
+      \arg        USART_STB_2BIT: 2 bits
+      \arg        USART_STB_1_5BIT: 1.5bit
+    \param[out] none
+    \retval     none
+*/
+void usart_stop_bit_set(uint32_t usart_periph, uint32_t stblen)
+{
+    /* disable USART */
+    USART_CTL0(usart_periph) &= ~(USART_CTL0_UEN);
+    /* clear USART_CTL1 STB bits */
+    USART_CTL1(usart_periph) &= ~USART_CTL1_STB;
+    USART_CTL1(usart_periph) |= stblen;
+}
+
+/*!
+    \brief      enable USART
+    \param[in]  usart_periph: USARTx(x=0,1)
+    \param[out] none
+    \retval     none
+*/
+void usart_enable(uint32_t usart_periph)
+{
+    USART_CTL0(usart_periph) |= USART_CTL0_UEN;
+}
+
+/*!
+    \brief      disable USART
+    \param[in]  usart_periph: USARTx(x=0,1)
+    \param[out] none
+    \retval     none
+*/
+void usart_disable(uint32_t usart_periph)
+{
+    USART_CTL0(usart_periph) &= ~(USART_CTL0_UEN);
+}
+
+/*!
+    \brief      configure USART transmitter
+    \param[in]  usart_periph: USARTx(x=0,1)
+    \param[in]  txconfig: enable or disable USART transmitter
+                only one parameter can be selected which is shown as below:
+      \arg        USART_TRANSMIT_ENABLE: enable USART transmission
+      \arg        USART_TRANSMIT_DISABLE: enable USART transmission
+    \param[out] none
+    \retval     none
+*/
+void usart_transmit_config(uint32_t usart_periph, uint32_t txconfig)
+{
+    USART_CTL0(usart_periph) &= ~USART_CTL0_TEN;
+    /* configure transfer mode */
+    USART_CTL0(usart_periph) |= txconfig;
+}
+
+/*!
+    \brief      configure USART receiver
+    \param[in]  usart_periph: USARTx(x=0,1)
+    \param[in]  rxconfig: enable or disable USART receiver
+                only one parameter can be selected which is shown as below:
+      \arg        USART_RECEIVE_ENABLE: enable USART reception
+      \arg        USART_RECEIVE_DISABLE: disable USART reception
+    \param[out] none
+    \retval     none
+*/
+void usart_receive_config(uint32_t usart_periph, uint32_t rxconfig)
+{
+    USART_CTL0(usart_periph) &= ~USART_CTL0_REN;
+    /* configure receiver mode */
+    USART_CTL0(usart_periph) |= rxconfig;
+}
+
+/*!
+    \brief      data is transmitted/received with the LSB/MSB first
+    \param[in]  usart_periph: USARTx(x=0,1)
+    \param[in]  msbf: LSB/MSB
+                only one parameter can be selected which is shown as below:
+      \arg        USART_MSBF_LSB: LSB first
+      \arg        USART_MSBF_MSB: MSB first
+    \param[out] none
+    \retval     none
+*/
+void usart_data_first_config(uint32_t usart_periph, uint32_t msbf)
+{
+    USART_CTL0(usart_periph) &= ~(USART_CTL0_UEN);
+    /* configure LSB or MSB first */
+    USART_CTL1(usart_periph) &= ~(USART_CTL1_MSBF);
+    USART_CTL1(usart_periph) |= msbf;
+}
+
+/*!
+    \brief      configure USART inversion
+    \param[in]  usart_periph: USARTx(x=0,1)
+    \param[in]  invertpara: refer to usart_invert_enum
+                only one parameter can be selected which is shown as below:
+      \arg        USART_DINV_ENABLE: data bit level inversion
+      \arg        USART_DINV_DISABLE: data bit level not inversion
+      \arg        USART_TXPIN_ENABLE: TX pin level inversion
+      \arg        USART_TXPIN_DISABLE: TX pin level not inversion
+      \arg        USART_RXPIN_ENABLE: RX pin level inversion
+      \arg        USART_RXPIN_DISABLE: RX pin level not inversion
+      \arg        USART_SWAP_ENABLE: swap TX/RX pins
+      \arg        USART_SWAP_DISABLE: not swap TX/RX pins
+    \param[out] none
+    \retval     none
+*/
+void usart_invert_config(uint32_t usart_periph, usart_invert_enum invertpara)
+{
+    USART_CTL0(usart_periph) &= ~(USART_CTL0_UEN);
+    /* inverted or not the specified signal */
+    switch(invertpara) {
+    case USART_DINV_ENABLE:
+        USART_CTL1(usart_periph) |= USART_CTL1_DINV;
+        break;
+    case USART_DINV_DISABLE:
+        USART_CTL1(usart_periph) &= ~(USART_CTL1_DINV);
+        break;
+    case USART_TXPIN_ENABLE:
+        USART_CTL1(usart_periph) |= USART_CTL1_TINV;
+        break;
+    case USART_TXPIN_DISABLE:
+        USART_CTL1(usart_periph) &= ~(USART_CTL1_TINV);
+        break;
+    case USART_RXPIN_ENABLE:
+        USART_CTL1(usart_periph) |= USART_CTL1_RINV;
+        break;
+    case USART_RXPIN_DISABLE:
+        USART_CTL1(usart_periph) &= ~(USART_CTL1_RINV);
+        break;
+    case USART_SWAP_ENABLE:
+        USART_CTL1(usart_periph) |= USART_CTL1_STRP;
+        break;
+    case USART_SWAP_DISABLE:
+        USART_CTL1(usart_periph) &= ~(USART_CTL1_STRP);
+        break;
+    default:
+        break;
+    }
+}
+
+/*!
+    \brief      enable the USART overrun function
+    \param[in]  usart_periph: USARTx(x=0,1)
+    \param[out] none
+    \retval     none
+*/
+void usart_overrun_enable(uint32_t usart_periph)
+{
+    USART_CTL0(usart_periph) &= ~(USART_CTL0_UEN);
+    /* enable overrun function */
+    USART_CTL2(usart_periph) &= ~(USART_CTL2_OVRD);
+}
+
+/*!
+    \brief      disable the USART overrun function
+    \param[in]  usart_periph: USARTx(x=0,1)
+    \param[out] none
+    \retval     none
+*/
+void usart_overrun_disable(uint32_t usart_periph)
+{
+    USART_CTL0(usart_periph) &= ~(USART_CTL0_UEN);
+    /* disable overrun function */
+    USART_CTL2(usart_periph) |= USART_CTL2_OVRD;
+}
+
+/*!
+    \brief      configure the USART oversample mode
+    \param[in]  usart_periph: USARTx(x=0,1)
+    \param[in]  oversamp: oversample value
+                only one parameter can be selected which is shown as below:
+      \arg        USART_OVSMOD_8: oversampling by 8
+      \arg        USART_OVSMOD_16: oversampling by 16
+    \param[out] none
+    \retval     none
+*/
+void usart_oversample_config(uint32_t usart_periph, uint32_t oversamp)
+{
+    /* disable USART */
+    USART_CTL0(usart_periph) &= ~(USART_CTL0_UEN);
+    /* clear OVSMOD bit */
+    USART_CTL0(usart_periph) &= ~(USART_CTL0_OVSMOD);
+    USART_CTL0(usart_periph) |= oversamp;
+}
+
+/*!
+    \brief      configure the sample bit method
+    \param[in]  usart_periph: USARTx(x=0,1)
+    \param[in]  osb: sample bit
+                only one parameter can be selected which is shown as below:
+      \arg        USART_OSB_1BIT: 1 bit
+      \arg        USART_OSB_3BIT: 3 bits
+    \param[out] none
+    \retval     none
+*/
+void usart_sample_bit_config(uint32_t usart_periph, uint32_t osb)
+{
+    /* disable USART */
+    USART_CTL0(usart_periph) &= ~(USART_CTL0_UEN);
+
+    USART_CTL2(usart_periph) &= ~(USART_CTL2_OSB);
+    USART_CTL2(usart_periph) |= osb;
+}
+
+/*!
+    \brief      enable receiver timeout
+    \param[in]  usart_periph: USARTx(x=0)
+    \param[out] none
+    \retval     none
+*/
+void usart_receiver_timeout_enable(uint32_t usart_periph)
+{
+    USART_CTL1(usart_periph) |= USART_CTL1_RTEN;
+}
+
+/*!
+    \brief      disable receiver timeout
+    \param[in]  usart_periph: USARTx(x=0)
+    \param[out] none
+    \retval     none
+*/
+void usart_receiver_timeout_disable(uint32_t usart_periph)
+{
+    USART_CTL1(usart_periph) &= ~(USART_CTL1_RTEN);
+}
+
+/*!
+    \brief      configure receiver timeout threshold
+    \param[in]  usart_periph: USARTx(x=0)
+    \param[in]  rtimeout: 0x00000000-0x00FFFFFF, receiver timeout value in terms of number of baud clocks
+    \param[out] none
+    \retval     none
+*/
+void usart_receiver_timeout_threshold_config(uint32_t usart_periph, uint32_t rtimeout)
+{
+    USART_RT(usart_periph) &= ~(USART_RT_RT);
+    USART_RT(usart_periph) |= rtimeout;
+}
+
+/*!
+    \brief      USART transmit data function
+    \param[in]  usart_periph: USARTx(x=0,1)
+    \param[in]  data: data of transmission
+    \param[out] none
+    \retval     none
+*/
+void usart_data_transmit(uint32_t usart_periph, uint16_t data)
+{
+    USART_TDATA(usart_periph) = (USART_TDATA_TDATA & (uint32_t)data);
+}
+
+/*!
+    \brief      USART receive data function
+    \param[in]  usart_periph: USARTx(x=0,1)
+    \param[out] none
+    \retval     data of received
+*/
+uint16_t usart_data_receive(uint32_t usart_periph)
+{
+    return (uint16_t)(GET_BITS(USART_RDATA(usart_periph), 0U, 8U));
+}
+
+/*!
+    \brief      enable USART command
+    \param[in]  usart_periph: USARTx(x=0,1,2)
+    \param[in]  cmdtype: command type
+                only one parameter can be selected which is shown as below:
+      \arg        USART_CMD_SBKCMD: send break command
+      \arg        USART_CMD_MMCMD: mute mode command
+      \arg        USART_CMD_RXFCMD: receive data flush command
+      \arg        USART_CMD_TXFCMD: transmit data flush request
+    \param[out] none
+    \retval     none
+*/
+void usart_command_enable(uint32_t usart_periph, uint32_t cmdtype)
+{
+    USART_CMD(usart_periph) |= (cmdtype);
+}
+
+/*!
+    \brief      configure the address of the USART in wake up by address match mode
+    \param[in]  usart_periph: USARTx(x=0,1)
+    \param[in]  addr: 0x00-0xFF, address of USART terminal
+    \param[out] none
+    \retval     none
+*/
+void usart_address_config(uint32_t usart_periph, uint8_t addr)
+{
+    /* disable USART */
+    USART_CTL0(usart_periph) &= ~(USART_CTL0_UEN);
+
+    USART_CTL1(usart_periph) &= ~(USART_CTL1_ADDR);
+    USART_CTL1(usart_periph) |= (USART_CTL1_ADDR & (((uint32_t)addr) << CTL1_ADDR_OFFSET));
+}
+
+/*!
+    \brief      configure address detection mode
+    \param[in]  usart_periph: USARTx(x=0,1)
+    \param[in]  addmod: address detection mode
+                only one parameter can be selected which is shown as below:
+      \arg        USART_ADDM_4BIT: 4 bits
+      \arg        USART_ADDM_FULLBIT: full bits
+    \param[out] none
+    \retval     none
+*/
+void usart_address_detection_mode_config(uint32_t usart_periph, uint32_t addmod)
+{
+    /* disable USART */
+    USART_CTL0(usart_periph) &= ~(USART_CTL0_UEN);
+
+    USART_CTL1(usart_periph) &= ~(USART_CTL1_ADDM);
+    USART_CTL1(usart_periph) |= USART_CTL1_ADDM & (addmod);
+}
+
+/*!
+    \brief      enable mute mode
+    \param[in]  usart_periph: USARTx(x=0,1)
+    \param[out] none
+    \retval     none
+*/
+void usart_mute_mode_enable(uint32_t usart_periph)
+{
+    USART_CTL0(usart_periph) |= USART_CTL0_MEN;
+}
+
+/*!
+    \brief      disable mute mode
+    \param[in]  usart_periph: USARTx(x=0,1)
+    \param[out] none
+    \retval     none
+*/
+void usart_mute_mode_disable(uint32_t usart_periph)
+{
+    USART_CTL0(usart_periph) &= ~(USART_CTL0_MEN);
+}
+
+/*!
+    \brief      configure wakeup method in mute mode
+    \param[in]  usart_periph: USARTx(x=0,1)
+    \param[in]  wmethod: two methods be used to enter or exit the mute mode
+                only one parameter can be selected which is shown as below:
+      \arg        USART_WM_IDLE: idle line
+      \arg        USART_WM_ADDR: address match
+    \param[out] none
+    \retval     none
+*/
+void usart_mute_mode_wakeup_config(uint32_t usart_periph, uint32_t wmethod)
+{
+    /* disable USART */
+    USART_CTL0(usart_periph) &= ~(USART_CTL0_UEN);
+
+    USART_CTL0(usart_periph) &= ~(USART_CTL0_WM);
+    USART_CTL0(usart_periph) |= wmethod;
+}
+
+/*!
+    \brief      enable LIN mode
+    \param[in]  usart_periph: USARTx(x=0)
+    \param[out] none
+    \retval     none
+*/
+void usart_lin_mode_enable(uint32_t usart_periph)
+{
+    /* disable USART */
+    USART_CTL0(usart_periph) &= ~(USART_CTL0_UEN);
+
+    USART_CTL1(usart_periph) |= USART_CTL1_LMEN;
+}
+
+/*!
+    \brief      disable LIN mode
+    \param[in]  usart_periph: USARTx(x=0)
+    \param[out] none
+    \retval     none
+*/
+void usart_lin_mode_disable(uint32_t usart_periph)
+{
+    /* disable USART */
+    USART_CTL0(usart_periph) &= ~(USART_CTL0_UEN);
+
+    USART_CTL1(usart_periph) &= ~(USART_CTL1_LMEN);
+}
+
+/*!
+    \brief      configure LIN break frame length
+    \param[in]  usart_periph: USARTx(x=0)
+    \param[in]  lblen: LIN break detection length
+                only one parameter can be selected which is shown as below:
+      \arg        USART_LBLEN_10B: 10 bits break detection
+      \arg        USART_LBLEN_11B: 11 bits break detection
+    \param[out] none
+    \retval     none
+*/
+void usart_lin_break_detection_length_config(uint32_t usart_periph, uint32_t lblen)
+{
+    /* disable USART */
+    USART_CTL0(usart_periph) &= ~(USART_CTL0_UEN);
+    USART_CTL1(usart_periph) &= ~(USART_CTL1_LBLEN);
+    USART_CTL1(usart_periph) |= USART_CTL1_LBLEN & (lblen);
+}
+
+/*!
+    \brief      enable half-duplex mode
+    \param[in]  usart_periph: USARTx(x=0,1)
+    \param[out] none
+    \retval     none
+*/
+void usart_halfduplex_enable(uint32_t usart_periph)
+{
+    /* disable USART */
+    USART_CTL0(usart_periph) &= ~(USART_CTL0_UEN);
+
+    USART_CTL2(usart_periph) |= USART_CTL2_HDEN;
+}
+
+/*!
+    \brief      disable half-duplex mode
+    \param[in]  usart_periph: USARTx(x=0,1)
+    \param[out] none
+    \retval     none
+*/
+void usart_halfduplex_disable(uint32_t usart_periph)
+{
+    /* disable USART */
+    USART_CTL0(usart_periph) &= ~(USART_CTL0_UEN);
+
+    USART_CTL2(usart_periph) &= ~(USART_CTL2_HDEN);
+}
+
+/*!
+    \brief      enable USART clock
+    \param[in]  usart_periph: USARTx(x=0)
+    \param[out] none
+    \retval     none
+*/
+void usart_clock_enable(uint32_t usart_periph)
+{
+    /* disable USART */
+    USART_CTL0(usart_periph) &= ~(USART_CTL0_UEN);
+
+    USART_CTL1(usart_periph) |= USART_CTL1_CKEN;
+}
+
+/*!
+    \brief      disable USART clock
+    \param[in]  usart_periph: USARTx(x=0)
+    \param[out] none
+    \retval     none
+*/
+void usart_clock_disable(uint32_t usart_periph)
+{
+    /* disable USART */
+    USART_CTL0(usart_periph) &= ~(USART_CTL0_UEN);
+
+    USART_CTL1(usart_periph) &= ~(USART_CTL1_CKEN);
+}
+
+/*!
+    \brief      configure USART synchronous mode parameters
+    \param[in]  usart_periph: USARTx(x=0,1)
+    \param[in]  clen: last bit clock pulse
+                only one parameter can be selected which is shown as below:
+      \arg        USART_CLEN_NONE: clock pulse of the last data bit (MSB) is not output to the CK pin
+      \arg        USART_CLEN_EN: clock pulse of the last data bit (MSB) is output to the CK pin
+    \param[in]  cph: clock phase
+                only one parameter can be selected which is shown as below:
+      \arg        USART_CPH_1CK: first clock transition is the first data capture edge
+      \arg        USART_CPH_2CK: second clock transition is the first data capture edge
+    \param[in]  cpl: clock polarity
+                only one parameter can be selected which is shown as below:
+      \arg        USART_CPL_LOW: steady low value on CK pin
+      \arg        USART_CPL_HIGH: steady high value on CK pin
+    \param[out] none
+    \retval     none
+*/
+void usart_synchronous_clock_config(uint32_t usart_periph, uint32_t clen, uint32_t cph, uint32_t cpl)
+{
+    /* disable USART */
+    USART_CTL0(usart_periph) &= ~(USART_CTL0_UEN);
+    /* reset USART_CTL1 CLEN,CPH,CPL bits */
+    USART_CTL1(usart_periph) &= ~(USART_CTL1_CLEN | USART_CTL1_CPH | USART_CTL1_CPL);
+
+    USART_CTL1(usart_periph) |= (USART_CTL1_CLEN & clen);
+    USART_CTL1(usart_periph) |= (USART_CTL1_CPH & cph);
+    USART_CTL1(usart_periph) |= (USART_CTL1_CPL & cpl);
+}
+
+/*!
+    \brief      configure guard time value in smartcard mode
+    \param[in]  usart_periph: USARTx(x=0)
+    \param[in]  guat: 0x00-0xFF
+    \param[out] none
+    \retval     none
+*/
+void usart_guard_time_config(uint32_t usart_periph, uint32_t guat)
+{
+    /* disable USART */
+    USART_CTL0(usart_periph) &= ~(USART_CTL0_UEN);
+
+    USART_GP(usart_periph) &= ~(USART_GP_GUAT);
+    USART_GP(usart_periph) |= (USART_GP_GUAT & ((guat) << GP_GUAT_OFFSET));
+}
+
+/*!
+    \brief      enable smartcard mode
+    \param[in]  usart_periph: USARTx(x=0)
+    \param[out] none
+    \retval     none
+*/
+void usart_smartcard_mode_enable(uint32_t usart_periph)
+{
+    /* disable USART */
+    USART_CTL0(usart_periph) &= ~(USART_CTL0_UEN);
+
+    USART_CTL2(usart_periph) |= USART_CTL2_SCEN;
+}
+
+/*!
+    \brief      disable smartcard mode
+    \param[in]  usart_periph: USARTx(x=0)
+    \param[out] none
+    \retval     none
+*/
+void usart_smartcard_mode_disable(uint32_t usart_periph)
+{
+    /* disable USART */
+    USART_CTL0(usart_periph) &= ~(USART_CTL0_UEN);
+
+    USART_CTL2(usart_periph) &= ~(USART_CTL2_SCEN);
+}
+
+/*!
+    \brief      enable NACK in smartcard mode
+    \param[in]  usart_periph: USARTx(x=0)
+    \param[out] none
+    \retval     none
+*/
+void usart_smartcard_mode_nack_enable(uint32_t usart_periph)
+{
+    /* disable USART */
+    USART_CTL0(usart_periph) &= ~(USART_CTL0_UEN);
+
+    USART_CTL2(usart_periph) |= USART_CTL2_NKEN;
+}
+
+/*!
+    \brief      disable NACK in smartcard mode
+    \param[in]  usart_periph: USARTx(x=0)
+    \param[out] none
+    \retval     none
+*/
+void usart_smartcard_mode_nack_disable(uint32_t usart_periph)
+{
+    /* disable USART */
+    USART_CTL0(usart_periph) &= ~(USART_CTL0_UEN);
+
+    USART_CTL2(usart_periph) &= ~(USART_CTL2_NKEN);
+}
+
+/*!
+    \brief      enable early NACK in smartcard mode
+    \param[in]  usart_periph: USARTx(x=0)
+    \param[out] none
+    \retval     none
+*/
+void usart_smartcard_mode_early_nack_enable(uint32_t usart_periph)
+{
+    USART_RFCS(usart_periph) |= USART_RFCS_ELNACK;
+}
+
+/*!
+    \brief      disable early NACK in smartcard mode
+    \param[in]  usart_periph: USARTx(x=0)
+    \param[out] none
+    \retval     none
+*/
+void usart_smartcard_mode_early_nack_disable(uint32_t usart_periph)
+{
+    USART_RFCS(usart_periph) &= ~USART_RFCS_ELNACK;
+}
+
+/*!
+    \brief      configure smartcard auto-retry number
+    \param[in]  usart_periph: USARTx(x=0)
+    \param[in]  scrtnum: 0x00000000-0x00000007, smartcard auto-retry number
+    \param[out] none
+    \retval     none
+*/
+void usart_smartcard_autoretry_config(uint32_t usart_periph, uint32_t scrtnum)
+{
+    /* disable USART */
+    USART_CTL0(usart_periph) &= ~(USART_CTL0_UEN);
+    USART_CTL2(usart_periph) &= ~(USART_CTL2_SCRTNUM);
+    USART_CTL2(usart_periph) |= (USART_CTL2_SCRTNUM & (scrtnum << CTL2_SCRTNUM_OFFSET));
+}
+
+/*!
+    \brief      configure block length
+    \param[in]  usart_periph: USARTx(x=0)
+    \param[in]  bl: 0x00000000-0x000000FF
+    \param[out] none
+    \retval     none
+*/
+void usart_block_length_config(uint32_t usart_periph, uint32_t bl)
+{
+    USART_RT(usart_periph) &= ~(USART_RT_BL);
+    USART_RT(usart_periph) |= (USART_RT_BL & ((bl) << RT_BL_OFFSET));
+}
+
+/*!
+    \brief      enable IrDA mode
+    \param[in]  usart_periph: USARTx(x=0)
+    \param[out] none
+    \retval     none
+*/
+void usart_irda_mode_enable(uint32_t usart_periph)
+{
+    /* disable USART */
+    USART_CTL0(usart_periph) &= ~(USART_CTL0_UEN);
+
+    USART_CTL2(usart_periph) |= USART_CTL2_IREN;
+}
+
+/*!
+    \brief      disable IrDA mode
+    \param[in]  usart_periph: USARTx(x=0)
+    \param[out] none
+    \retval     none
+*/
+void usart_irda_mode_disable(uint32_t usart_periph)
+{
+    /* disable USART */
+    USART_CTL0(usart_periph) &= ~(USART_CTL0_UEN);
+
+    USART_CTL2(usart_periph) &= ~(USART_CTL2_IREN);
+}
+
+/*!
+    \brief      configure the peripheral clock prescaler in USART IrDA low-power or smartcard mode
+    \param[in]  usart_periph: USARTx(x=0)
+    \param[in]  psc: 0x00000000-0x000000FF
+    \param[out] none
+    \retval     none
+*/
+void usart_prescaler_config(uint32_t usart_periph, uint32_t psc)
+{
+    /* disable USART */
+    USART_CTL0(usart_periph) &= ~(USART_CTL0_UEN);
+    USART_GP(usart_periph) &= ~(USART_GP_PSC);
+    USART_GP(usart_periph) |= psc;
+}
+
+/*!
+    \brief      configure IrDA low-power
+    \param[in]  usart_periph: USARTx(x=0)
+    \param[in]  irlp: IrDA low-power or normal
+                only one parameter can be selected which is shown as below:
+      \arg        USART_IRLP_LOW:    low-power
+      \arg        USART_IRLP_NORMAL: normal
+    \param[out] none
+    \retval     none
+*/
+void usart_irda_lowpower_config(uint32_t usart_periph, uint32_t irlp)
+{
+    /* disable USART */
+    USART_CTL0(usart_periph) &= ~(USART_CTL0_UEN);
+    USART_CTL2(usart_periph) &= ~(USART_CTL2_IRLP);
+    USART_CTL2(usart_periph) |= (USART_CTL2_IRLP & irlp);
+}
+
+/*!
+    \brief      configure hardware flow control RTS
+    \param[in]  usart_periph: USARTx(x=0,1)
+    \param[in]  rtsconfig: enable or disable RTS
+                only one parameter can be selected which is shown as below:
+      \arg        USART_RTS_ENABLE:  enable RTS
+      \arg        USART_RTS_DISABLE: disable RTS
+    \param[out] none
+    \retval     none
+*/
+void usart_hardware_flow_rts_config(uint32_t usart_periph, uint32_t rtsconfig)
+{
+    /* disable USART */
+    USART_CTL0(usart_periph) &= ~(USART_CTL0_UEN);
+
+    USART_CTL2(usart_periph) &= ~(USART_CTL2_RTSEN);
+    USART_CTL2(usart_periph) |= rtsconfig;
+}
+
+/*!
+    \brief      configure hardware flow control CTS
+    \param[in]  usart_periph: USARTx(x=0,1)
+    \param[in]  ctsconfig:  enable or disable CTS
+                only one parameter can be selected which is shown as below:
+      \arg        USART_CTS_ENABLE:  enable CTS
+      \arg        USART_CTS_DISABLE: disable CTS
+    \param[out] none
+    \retval     none
+*/
+void usart_hardware_flow_cts_config(uint32_t usart_periph, uint32_t ctsconfig)
+{
+    /* disable USART */
+    USART_CTL0(usart_periph) &= ~(USART_CTL0_UEN);
+
+    USART_CTL2(usart_periph) &= ~USART_CTL2_CTSEN;
+    USART_CTL2(usart_periph) |= ctsconfig;
+}
+
+/*!
+    \brief      enable RS485 driver
+    \param[in]  usart_periph: USARTx(x=0,1)
+    \param[out] none
+    \retval     none
+*/
+void usart_rs485_driver_enable(uint32_t usart_periph)
+{
+    /* disable USART */
+    USART_CTL0(usart_periph) &= ~(USART_CTL0_UEN);
+
+    USART_CTL2(usart_periph) |= USART_CTL2_DEM;
+}
+
+/*!
+    \brief      disable RS485 driver
+    \param[in]  usart_periph: USARTx(x=0,1)
+    \param[out] none
+    \retval     none
+*/
+void usart_rs485_driver_disable(uint32_t usart_periph)
+{
+    /* disable USART */
+    USART_CTL0(usart_periph) &= ~(USART_CTL0_UEN);
+
+    USART_CTL2(usart_periph) &= ~(USART_CTL2_DEM);
+}
+
+/*!
+    \brief      configure driver enable assertion time
+    \param[in]  usart_periph: USARTx(x=0,1)
+    \param[in]  deatime: 0x00000000-0x0000001F
+    \param[out] none
+    \retval     none
+*/
+void usart_driver_assertime_config(uint32_t usart_periph, uint32_t deatime)
+{
+    /* disable USART */
+    USART_CTL0(usart_periph) &= ~(USART_CTL0_UEN);
+
+    USART_CTL0(usart_periph) &= ~(USART_CTL0_DEA);
+    USART_CTL0(usart_periph) |= (USART_CTL0_DEA & ((deatime) << CTL0_DEA_OFFSET));
+}
+
+/*!
+    \brief      configure driver enable de-assertion time
+    \param[in]  usart_periph: USARTx(x=0,1)
+    \param[in]  dedtime: 0x00000000-0x0000001F
+    \param[out] none
+    \retval     none
+*/
+void usart_driver_deassertime_config(uint32_t usart_periph, uint32_t dedtime)
+{
+    /* disable USART */
+    USART_CTL0(usart_periph) &= ~(USART_CTL0_UEN);
+
+    USART_CTL0(usart_periph) &= ~(USART_CTL0_DED);
+    USART_CTL0(usart_periph) |= (USART_CTL0_DED & ((dedtime) << CTL0_DED_OFFSET));
+}
+
+/*!
+    \brief      configure driver enable polarity mode
+    \param[in]  usart_periph: USARTx(x=0,1)
+    \param[in]  dep: DE signal
+                only one parameter can be selected which is shown as below:
+      \arg        USART_DEP_HIGH: DE signal is active high
+      \arg        USART_DEP_LOW: DE signal is active low
+    \param[out] none
+    \retval     none
+*/
+void usart_depolarity_config(uint32_t usart_periph, uint32_t dep)
+{
+    /* disable USART */
+    USART_CTL0(usart_periph) &= ~(USART_CTL0_UEN);
+    /* reset DEP bit */
+    USART_CTL2(usart_periph) &= ~(USART_CTL2_DEP);
+    USART_CTL2(usart_periph) |= (USART_CTL2_DEP & dep);
+}
+
+/*!
+    \brief      configure USART DMA reception
+    \param[in]  usart_periph: USARTx(x=0,1)
+    \param[in]  dmacmd: USART DMA mode
+                only one parameter can be selected which is shown as below:
+      \arg        USART_RECEIVE_DMA_ENABLE: enable USART DMA for reception
+      \arg        USART_RECEIVE_DMA_DISABLE: disable USART DMA for reception
+    \param[out] none
+    \retval     none
+*/
+void usart_dma_receive_config(uint32_t usart_periph, uint8_t dmacmd)
+{
+    USART_CTL2(usart_periph) &= ~USART_CTL2_DENR;
+    USART_CTL2(usart_periph) |= (USART_CTL2_DENR & dmacmd);
+}
+
+/*!
+    \brief      configure USART DMA transmission
+    \param[in]  usart_periph: USARTx(x=0,1)
+    \param[in]  dmacmd: USART DMA mode
+                only one parameter can be selected which is shown as below:
+      \arg        USART_TRANSMIT_DMA_ENABLE: enable USART DMA for transmission
+      \arg        USART_TRANSMIT_DMA_DISABLE: disable USART DMA for transmission
+    \param[out] none
+    \retval     none
+*/
+void usart_dma_transmit_config(uint32_t usart_periph, uint8_t dmacmd)
+{
+    USART_CTL2(usart_periph) &= ~USART_CTL2_DENT;
+    USART_CTL2(usart_periph) |= (USART_CTL2_DENT & dmacmd);
+}
+
+/*!
+    \brief      enable DMA on reception error
+    \param[in]  usart_periph: USARTx(x=0,1)
+    \param[out] none
+    \retval     none
+*/
+void usart_reception_error_dma_enable(uint32_t usart_periph)
+{
+    /* disable USART */
+    USART_CTL0(usart_periph) &= ~(USART_CTL0_UEN);
+    USART_CTL2(usart_periph) &= ~(USART_CTL2_DDRE);
+}
+
+/*!
+    \brief      disable DMA on reception error
+    \param[in]  usart_periph: USARTx(x=0,1)
+    \param[out] none
+    \retval     none
+*/
+void usart_reception_error_dma_disable(uint32_t usart_periph)
+{
+    /* disable USART */
+    USART_CTL0(usart_periph) &= ~(USART_CTL0_UEN);
+    USART_CTL2(usart_periph) |= USART_CTL2_DDRE;
+}
+
+/*!
+    \brief      enable USART to wakeup the MCU from deep-sleep mode
+    \param[in]  usart_periph: USARTx(x=0)
+    \param[out] none
+    \retval     none
+*/
+void usart_wakeup_enable(uint32_t usart_periph)
+{
+    USART_CTL0(usart_periph) |= USART_CTL0_UESM;
+}
+
+/*!
+    \brief      disable USART to wakeup the MCU from deep-sleep mode
+    \param[in]  usart_periph: USARTx(x=0)
+    \param[out] none
+    \retval     none
+*/
+void usart_wakeup_disable(uint32_t usart_periph)
+{
+    USART_CTL0(usart_periph) &= ~(USART_CTL0_UESM);
+}
+
+/*!
+    \brief      configure the USART wakeup mode from deep-sleep mode
+    \param[in]  usart_periph: USARTx(x=0)
+    \param[in]  wum: wakeup mode
+                only one parameter can be selected which is shown as below:
+      \arg        USART_WUM_ADDR: WUF active on address match
+      \arg        USART_WUM_STARTB: WUF active on start bit
+      \arg        USART_WUM_RBNE: WUF active on RBNE
+    \param[out] none
+    \retval     none
+*/
+void usart_wakeup_mode_config(uint32_t usart_periph, uint32_t wum)
+{
+    /* disable USART */
+    USART_CTL0(usart_periph) &= ~(USART_CTL0_UEN);
+    /* reset WUM bit */
+    USART_CTL2(usart_periph) &= ~(USART_CTL2_WUM);
+    USART_CTL2(usart_periph) |= USART_CTL2_WUM & (wum);
+}
+
+/*!
+    \brief      enable receive FIFO
+    \param[in]  usart_periph: USARTx(x=0,1)
+    \param[out] none
+    \retval     none
+*/
+void usart_receive_fifo_enable(uint32_t usart_periph)
+{
+    USART_RFCS(usart_periph) |= USART_RFCS_RFEN;
+}
+
+/*!
+    \brief      disable receive FIFO
+    \param[in]  usart_periph: USARTx(x=0,1)
+    \param[out] none
+    \retval     none
+*/
+void usart_receive_fifo_disable(uint32_t usart_periph)
+{
+    USART_RFCS(usart_periph) &= ~(USART_RFCS_RFEN);
+}
+
+/*!
+    \brief      read receive FIFO counter number
+    \param[in]  usart_periph: USARTx(x=0,1)
+    \param[out] none
+    \retval     receive FIFO counter number
+*/
+uint8_t usart_receive_fifo_counter_number(uint32_t usart_periph)
+{
+    return (uint8_t)(GET_BITS(USART_RFCS(usart_periph), 12U, 14U));
+}
+
+/*!
+    \brief      get USART status
+    \param[in]  usart_periph: USARTx(x=0,1)
+    \param[in]  flag: flag type
+                only one parameter can be selected which is shown as below:
+      \arg        USART_FLAG_PERR: parity error flag
+      \arg        USART_FLAG_FERR: frame error flag
+      \arg        USART_FLAG_NERR: noise error flag
+      \arg        USART_FLAG_ORERR: overrun error flag
+      \arg        USART_FLAG_IDLE: idle line detected flag
+      \arg        USART_FLAG_RBNE: read data buffer not empty
+      \arg        USART_FLAG_TC: transmission complete flag
+      \arg        USART_FLAG_TBE: transmit data register empty
+      \arg        USART_FLAG_LBD: LIN break detected flag
+      \arg        USART_FLAG_CTSF: CTS change flag
+      \arg        USART_FLAG_CTS: CTS level
+      \arg        USART_FLAG_RT: receiver timeout flag
+      \arg        USART_FLAG_EB: end of block flag
+      \arg        USART_FLAG_BSY: busy flag
+      \arg        USART_FLAG_AM: address match flag
+      \arg        USART_FLAG_SB: send break flag
+      \arg        USART_FLAG_RWU: receiver wakeup from mute mode.
+      \arg        USART_FLAG_WU: wakeup from deep-sleep mode flag
+      \arg        USART_FLAG_TEA: transmit enable acknowledge flag
+      \arg        USART_FLAG_REA: receive enable acknowledge flag
+      \arg        USART_FLAG_EPERR: early parity error flag
+      \arg        USART_FLAG_RFE: receive FIFO empty flag
+      \arg        USART_FLAG_RFF: receive FIFO full flag
+    \param[out] none
+    \retval     FlagStatus: SET or RESET
+*/
+FlagStatus usart_flag_get(uint32_t usart_periph, usart_flag_enum flag)
+{
+    if(RESET != (USART_REG_VAL(usart_periph, flag) & BIT(USART_BIT_POS(flag)))) {
+        return SET;
+    } else {
+        return RESET;
+    }
+}
+
+/*!
+    \brief      clear USART status
+    \param[in]  usart_periph: USARTx(x=0,1)
+    \param[in]  flag: flag type
+                only one parameter can be selected which is shown as below:
+      \arg        USART_FLAG_PERR: parity error flag
+      \arg        USART_FLAG_FERR: frame error flag
+      \arg        USART_FLAG_NERR: noise error flag
+      \arg        USART_FLAG_ORERR: overrun error flag
+      \arg        USART_FLAG_IDLE: idle line detected flag
+      \arg        USART_FLAG_TC: transmission complete flag
+      \arg        USART_FLAG_LBD: LIN break detected flag
+      \arg        USART_FLAG_CTSF: CTS change flag
+      \arg        USART_FLAG_RT: receiver timeout flag
+      \arg        USART_FLAG_EB: end of block flag
+      \arg        USART_FLAG_AM: address match flag
+      \arg        USART_FLAG_WU: wakeup from deep-sleep mode flag
+      \arg        USART_FLAG_EPERR: early parity error flag
+    \param[out] none
+    \retval     none
+*/
+void usart_flag_clear(uint32_t usart_periph, usart_flag_enum flag)
+{
+    USART_INTC(usart_periph) |= BIT(USART_BIT_POS(flag));
+}
+
+/*!
+    \brief      enable USART interrupt
+    \param[in]  usart_periph: USARTx(x=0,1)
+    \param[in]  interrupt: interrupt
+                only one parameter can be selected which is shown as below:
+      \arg        USART_INT_IDLE: idle line detected interrupt
+      \arg        USART_INT_RBNE: read data buffer not empty interrupt and overrun error interrupt
+      \arg        USART_INT_TC: transmission complete interrupt
+      \arg        USART_INT_TBE: transmitter buffer empty interrupt
+      \arg        USART_INT_PERR: parity error interrupt
+      \arg        USART_INT_AM: address match interrupt
+      \arg        USART_INT_RT: receiver timeout interrupt
+      \arg        USART_INT_EB: end of block interrupt
+      \arg        USART_INT_LBD: LIN break detection interrupt
+      \arg        USART_INT_ERR: error interrupt
+      \arg        USART_INT_CTS: CTS interrupt
+      \arg        USART_INT_WU: wakeup from deep-sleep mode interrupt
+      \arg        USART_INT_RFF: receive FIFO full interrupt
+    \param[out] none
+    \retval     none
+*/
+void usart_interrupt_enable(uint32_t usart_periph, usart_interrupt_enum interrupt)
+{
+    USART_REG_VAL(usart_periph, interrupt) |= BIT(USART_BIT_POS(interrupt));
+}
+
+/*!
+    \brief      disable USART interrupt
+    \param[in]  usart_periph: USARTx(x=0,1)
+    \param[in]  interrupt: interrupt
+                only one parameter can be selected which is shown as below:
+      \arg        USART_INT_IDLE: idle interrupt
+      \arg        USART_INT_RBNE: read data buffer not empty interrupt and overrun error interrupt
+      \arg        USART_INT_TC: transmission complete interrupt
+      \arg        USART_INT_TBE: transmitter buffer empty interrupt
+      \arg        USART_INT_PERR: parity error interrupt
+      \arg        USART_INT_AM: address match interrupt
+      \arg        USART_INT_RT: receiver timeout interrupt
+      \arg        USART_INT_EB: end of block interrupt
+      \arg        USART_INT_LBD: LIN break detection interrupt
+      \arg        USART_INT_ERR: error interrupt
+      \arg        USART_INT_CTS: CTS interrupt
+      \arg        USART_INT_WU: wakeup from deep-sleep mode interrupt
+      \arg        USART_INT_RFF: receive FIFO full interrupt
+    \param[out] none
+    \retval     none
+*/
+void usart_interrupt_disable(uint32_t usart_periph, usart_interrupt_enum interrupt)
+{
+    USART_REG_VAL(usart_periph, interrupt) &= ~BIT(USART_BIT_POS(interrupt));
+}
+
+/*!
+    \brief      get USART interrupt flag status
+    \param[in]  usart_periph: USARTx(x=0,1)
+    \param[in]  int_flag: interrupt and flag type, refer to usart_interrupt_flag_enum
+                only one parameter can be selected which is shown as below:
+      \arg        USART_INT_FLAG_EB: end of block interrupt flag
+      \arg        USART_INT_FLAG_RT: receiver timeout interrupt flag
+      \arg        USART_INT_FLAG_AM: address match interrupt flag
+      \arg        USART_INT_FLAG_PERR: parity error interrupt flag
+      \arg        USART_INT_FLAG_TBE: transmitter buffer empty interrupt flag
+      \arg        USART_INT_FLAG_TC: transmission complete interrupt flag
+      \arg        USART_INT_FLAG_RBNE: read data buffer not empty interrupt flag
+      \arg        USART_INT_FLAG_RBNE_ORERR: overrun error interrupt flag
+      \arg        USART_INT_FLAG_IDLE: idle line detected interrupt flag
+      \arg        USART_INT_FLAG_LBD: LIN break detected interrupt flag
+      \arg        USART_INT_FLAG_WU: wakeup from deep-sleep mode interrupt flag
+      \arg        USART_INT_FLAG_CTS: CTS interrupt flag
+      \arg        USART_INT_FLAG_ERR_NERR: noise error interrupt flag
+      \arg        USART_INT_FLAG_ERR_ORERR: overrun error interrupt flag
+      \arg        USART_INT_FLAG_ERR_FERR: frame error interrupt flag
+      \arg        USART_INT_FLAG_RFF: receive FIFO full interrupt flag
+    \param[out] none
+    \retval     FlagStatus: SET or RESET
+*/
+FlagStatus usart_interrupt_flag_get(uint32_t usart_periph, usart_interrupt_flag_enum int_flag)
+{
+    uint32_t intenable = 0U, flagstatus = 0U;
+    /* get the interrupt enable bit status */
+    intenable = (USART_REG_VAL(usart_periph, int_flag) & BIT(USART_BIT_POS(int_flag)));
+    /* get the corresponding flag bit status */
+    flagstatus = (USART_REG_VAL2(usart_periph, int_flag) & BIT(USART_BIT_POS2(int_flag)));
+
+    if(flagstatus && intenable) {
+        return SET;
+    } else {
+        return RESET;
+    }
+}
+
+/*!
+    \brief      clear USART interrupt flag
+    \param[in]  usart_periph: USARTx(x=0,1)
+    \param[in]  flag: USART interrupt flag
+                only one parameter can be selected which is shown as below:
+      \arg        USART_INT_FLAG_EB: end of block interrupt flag
+      \arg        USART_INT_FLAG_RT: receiver timeout interrupt flag
+      \arg        USART_INT_FLAG_AM: address match interrupt flag
+      \arg        USART_INT_FLAG_PERR: parity error interrupt flag
+      \arg        USART_INT_FLAG_TC: transmission complete interrupt flag
+      \arg        USART_INT_FLAG_RBNE_ORERR: overrun error interrupt flag
+      \arg        USART_INT_FLAG_IDLE: idle line detected interrupt flag
+      \arg        USART_INT_FLAG_LBD: LIN break detected interrupt flag
+      \arg        USART_INT_FLAG_WU: wakeup from deep-sleep mode interrupt flag
+      \arg        USART_INT_FLAG_CTS: CTS change interrupt flag
+      \arg        USART_INT_FLAG_ERR_FERR: frame error interrupt flag
+      \arg        USART_INT_FLAG_ERR_NERR: noise detected interrupt flag
+      \arg        USART_INT_FLAG_ERR_ORERR: overrun error interrupt flag
+      \arg        USART_INT_FLAG_RFF: receive FIFO full interrupt flag
+    \param[out] none
+    \retval     none
+*/
+void usart_interrupt_flag_clear(uint32_t usart_periph, usart_interrupt_flag_enum int_flag)
+{
+    if(USART_INT_FLAG_RFF == int_flag) {
+        USART_RFCS(usart_periph) &= (uint32_t)(~USART_RFCS_RFFINT);
+    } else {
+        USART_INTC(usart_periph) |= BIT(USART_BIT_POS2(int_flag));
+    }
+}

+ 125 - 0
GD32F3x0/GD32F3x0_standard_peripheral/Source/gd32f3x0_wwdgt.c

@@ -0,0 +1,125 @@
+/*!
+    \file    gd32f3x0_wwdgt.c
+    \brief   WWDGT driver
+
+    \version 2025-01-01, V2.5.0, firmware for GD32F3x0
+*/
+
+/*
+    Copyright (c) 2025, GigaDevice Semiconductor Inc.
+
+    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 of the copyright holder 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 HOLDER 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.
+*/
+
+#include "gd32f3x0_wwdgt.h"
+#include "gd32f3x0_rcu.h"
+
+/*!
+    \brief      reset the window watchdog timer configuration
+    \param[in]  none
+    \param[out] none
+    \retval     none
+*/
+void wwdgt_deinit(void)
+{
+    rcu_periph_reset_enable(RCU_WWDGTRST);
+    rcu_periph_reset_disable(RCU_WWDGTRST);
+}
+
+/*!
+    \brief      start the window watchdog timer counter
+    \param[in]  none
+    \param[out] none
+    \retval     none
+*/
+void wwdgt_enable(void)
+{
+    WWDGT_CTL |= WWDGT_CTL_WDGTEN;
+}
+
+/*!
+    \brief      configure the window watchdog timer counter value
+    \param[in]  counter_value: 0x00 - 0x7F
+    \param[out] none
+    \retval     none
+*/
+void wwdgt_counter_update(uint16_t counter_value)
+{
+    WWDGT_CTL = (uint32_t)(CTL_CNT(counter_value));
+}
+
+/*!
+    \brief      configure counter value, window value, and prescaler divider value
+    \param[in]  counter: 0x00 - 0x7F
+    \param[in]  window: 0x00 - 0x7F
+    \param[in]  prescaler: wwdgt prescaler value
+                only one parameter can be selected which is shown as below:
+      \arg        WWDGT_CFG_PSC_DIV1: the time base of window watchdog counter = (PCLK1/4096)/1
+      \arg        WWDGT_CFG_PSC_DIV2: the time base of window watchdog counter = (PCLK1/4096)/2
+      \arg        WWDGT_CFG_PSC_DIV4: the time base of window watchdog counter = (PCLK1/4096)/4
+      \arg        WWDGT_CFG_PSC_DIV8: the time base of window watchdog counter = (PCLK1/4096)/8
+    \param[out] none
+    \retval     none
+*/
+void wwdgt_config(uint16_t counter, uint16_t window, uint32_t prescaler)
+{
+    WWDGT_CTL = (uint32_t)(CTL_CNT(counter));
+    WWDGT_CFG = (uint32_t)(CFG_WIN(window) | prescaler);
+}
+
+/*!
+    \brief      check early wakeup interrupt state of WWDGT
+    \param[in]  none
+    \param[out] none
+    \retval     FlagStatus: SET or RESET
+*/
+FlagStatus wwdgt_flag_get(void)
+{
+    if(WWDGT_STAT & WWDGT_STAT_EWIF) {
+        return SET;
+    }
+    return RESET;
+}
+
+/*!
+    \brief      clear early wakeup interrupt state of WWDGT
+    \param[in]  none
+    \param[out] none
+    \retval     none
+*/
+void wwdgt_flag_clear(void)
+{
+    WWDGT_STAT = (uint32_t)(RESET);
+}
+
+/*!
+    \brief      enable early wakeup interrupt of WWDGT
+    \param[in]  none
+    \param[out] none
+    \retval     none
+*/
+void wwdgt_interrupt_enable(void)
+{
+    WWDGT_CFG |= WWDGT_CFG_EWIE;
+}

+ 316 - 0
GD32F3x0/GD32F3x0_usbfs_library/device/class/audio/Include/audio_core.h

@@ -0,0 +1,316 @@
+/*!
+    \file    audio_core.h
+    \brief   the header file of USB audio device class core functions
+
+    \version 2025-01-01, V2.5.0, firmware for GD32F3x0
+*/
+
+/*
+    Copyright (c) 2025, GigaDevice Semiconductor Inc.
+
+    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 of the copyright holder 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 HOLDER 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.
+*/
+
+#ifndef AUDIO_CORE_H
+#define AUDIO_CORE_H
+
+#include "usbd_enum.h"
+
+#define FORMAT_24BIT(x)                           (uint8_t)(x);(uint8_t)((x) >> 8);(uint8_t)((x) >> 16)
+
+/* number of sub-packets in the audio transfer buffer. you can modify this value but always make sure
+   that it is an even number and higher than 3 */
+#define OUT_PACKET_NUM                            20U
+
+/* total size of the audio transfer buffer */
+#define OUT_BUF_MARGIN                            0U
+#define TOTAL_OUT_BUF_SIZE                        ((uint32_t)((SPEAKER_OUT_PACKET + OUT_BUF_MARGIN) * OUT_PACKET_NUM))
+
+/* audio configuration descriptor length and interface descriptor size */
+#define AD_CONFIG_DESC_SET_LEN                    (sizeof(usb_desc_config_set))
+#define AD_INTERFACE_DESC_SIZE                    9U
+
+/* audio standard endpoint and streaming endpoint descriptor size */
+#define USB_AD_DESC_SIZ                           0x09U                                    /*!< audio descriptor size */
+#define AD_STANDARD_EP_DESC_SIZE                  0x09U                                    /*!< audio standard endpoint descriptor size */
+#define AD_STREAMING_EP_DESC_SIZE                 0x07U                                    /*!< audio streaming endpoint descriptor size */
+
+/* audio interface class code */
+#define USB_CLASS_AUDIO                           0x01U
+
+/* audio interface subclass codes */
+#define AD_SUBCLASS_CONTROL                       0x01U                                    /*!< audio interface control */
+#define AD_SUBCLASS_AUDIOSTREAMING                0x02U                                    /*!< audio interface audiostreaming */
+#define AD_SUBCLASS_MIDISTREAMING                 0x03U                                    /*!< audio interface midistreaming */
+
+/* audio interface protocol codes */
+#define AD_PROTOCOL_UNDEFINED                     0x00U                                    /*!< audio interface undefined */
+#define AD_STREAMING_GENERAL                      0x01U                                    /*!< audio interface streaming general */
+#define AD_STREAMING_FORMAT_TYPE                  0x02U                                    /*!< audio interface streaming format type */
+
+/* audio class-specific descriptor types */
+#define AD_DESCTYPE_UNDEFINED                     0x20U                                    /*!< audio class-specific descriptor undefined */
+#define AD_DESCTYPE_DEVICE                        0x21U                                    /*!< audio device descriptor */
+#define AD_DESCTYPE_CONFIGURATION                 0x22U                                    /*!< audio configuration descriptor */
+#define AD_DESCTYPE_STRING                        0x23U                                    /*!< audio string descriptor */
+#define AD_DESCTYPE_INTERFACE                     0x24U                                    /*!< audio interface descriptor */
+#define AD_DESCTYPE_ENDPOINT                      0x25U                                    /*!< audio endpoint descriptor */
+
+/* audio control interface descriptor subtypes */
+#define AD_CONTROL_HEADER                         0x01U                                    /*!< audio control interface header descriptor */
+#define AD_CONTROL_INPUT_TERMINAL                 0x02U                                    /*!< audio control interface input terminal descriptor */
+#define AD_CONTROL_OUTPUT_TERMINAL                0x03U                                    /*!< audio control interface output terminal descriptor */
+#define AD_CONTROL_MIXER_UNIT                     0x04U                                    /*!< audio control interface maximum unit descriptor */
+#define AD_CONTROL_SELECTOR_UNIT                  0x05U                                    /*!< audio control interface selector unit descriptor */
+#define AD_CONTROL_FEATURE_UNIT                   0x06U                                    /*!< audio control interface feature unit descriptor */
+#define AD_CONTROL_PROCESSING_UNIT                0x07U                                    /*!< audio control interface processing unit descriptor */
+#define AD_CONTROL_EXTENSION_UNIT                 0x08U                                    /*!< audio control interface extension unit descriptor */
+
+/* audio input/output terminal and streaming interface descriptor size */
+#define AD_INPUT_TERMINAL_DESC_SIZE               0x0CU                                    /*!< audio input terminal interface descriptor size */
+#define AD_OUTPUT_TERMINAL_DESC_SIZE              0x09U                                    /*!< audio output terminal interface descriptor size */
+#define AD_STREAMING_INTERFACE_DESC_SIZE          0x07U                                    /*!< audio streaming interface descriptor size */
+
+/* audio control types */
+#define AD_CONTROL_MUTE                           0x01U                                    /*!< audio control mute type */
+#define AD_CONTROL_VOLUME                         0x02U                                    /*!< audio control volume type */
+
+/* audio format types */
+#define AD_FORMAT_TYPE_I                          0x01U                                    /*!< audio format typeI */
+#define AD_FORMAT_TYPE_III                        0x03U                                    /*!< audio format typeIII */
+
+/* endpoint types */
+#define USB_ENDPOINT_TYPE_ISOCHRONOUS             0x01U                                    /*!< audio isochronous endpoint type */
+#define AD_ENDPOINT_GENERAL                       0x01U                                    /*!< audio general endpoint type */
+
+/* audio request types */
+#define AD_REQ_UNDEFINED                          0x00U                                    /*!< audio undefined request */
+#define AD_REQ_SET_CUR                            0x01U                                    /*!< current setting attribute request */
+#define AD_REQ_GET_CUR                            0x81U                                    /*!< current getting attribute request */
+#define AD_REQ_SET_MIN                            0x02U                                    /*!< setting minimum range attribute request */
+#define AD_REQ_GET_MIN                            0x82U                                    /*!< getting minimum range attribute request */
+#define AD_REQ_SET_MAX                            0x03U                                    /*!< setting maximum range attribute request */
+#define AD_REQ_GET_MAX                            0x83U                                    /*!< getting maximum range attribute request */
+#define AD_REQ_SET_RES                            0x04U                                    /*!< setting range attribute request */
+#define AD_REQ_GET_RES                            0x84U                                    /*!< getting range attribute request */
+#define AD_REQ_SET_MEM                            0x05U                                    /*!< setting memory attribute request */
+#define AD_REQ_GET_MEM                            0x85U                                    /*!< getting memory attribute request */
+#define AD_REQ_GET_STAT                           0xFFU                                    /*!< getting state request */
+
+/* streaming control types */
+#define AD_OUT_STREAMING_CTRL                     0x05U                                    /*!< audio streaming control OUT */
+#define AD_IN_STREAMING_CTRL                      0x02U                                    /*!< audio streaming control IN */
+
+/* audio stream interface number */
+enum {
+#ifdef USE_USB_AD_MICPHONE
+    MIC_INTERFACE_COUNT,              /*!< audio microphone interface count */
+#endif /* USE_USB_AD_MICPHONE */
+
+#ifdef USE_USB_AD_SPEAKER
+    SPEAK_INTERFACE_COUNT,            /*!< audio speaker interface count */
+#endif /* USE_USB_AD_SPEAKER */
+    CONFIG_DESC_AS_ITF_COUNT          /*!< audio system interface count */
+};
+
+/* audio interface descriptor total length */
+#define AC_ITF_TOTAL_LEN                         (sizeof(usb_desc_AC_itf) + CONFIG_DESC_AS_ITF_COUNT*(sizeof(usb_desc_input_terminal) + \
+                                                  sizeof(usb_desc_mono_feature_unit) + sizeof(usb_desc_output_terminal)))
+
+#pragma pack(1)
+
+typedef struct {
+    usb_desc_header header;           /*!< descriptor header, including type and size */
+    uint8_t  bDescriptorSubtype;      /*!< header descriptor subtype */
+    uint16_t bcdADC;                  /*!< audio device class specification release number in binary-coded decimal */
+    uint16_t wTotalLength;            /*!< total number of bytes */
+    uint8_t  bInCollection;           /*!< the number of the streaming interfaces */
+#ifdef USE_USB_AD_MICPHONE
+    uint8_t  baInterfaceNr0;          /*!< interface number of the streaming interfaces */
+#endif /* USE_USB_AD_MICPHONE */
+
+#ifdef USE_USB_AD_SPEAKER
+    uint8_t  baInterfaceNr1;          /*!< interface number of the streaming interfaces */
+#endif /* USE_USB_AD_SPEAKER */
+} usb_desc_AC_itf;
+
+typedef struct {
+    usb_desc_header header;           /*!< descriptor header, including type and size */
+    uint8_t  bDescriptorSubtype;      /*!< general audio system descriptor subtype */
+    uint8_t  bTerminalLink;           /*!< the terminal ID */
+    uint8_t  bDelay;                  /*!< delay introduced by the data path */
+    uint16_t wFormatTag;              /*!< the audio data format */
+} usb_desc_AS_itf;
+
+typedef struct {
+    usb_desc_header header;           /*!< descriptor header, including type and size */
+    uint8_t  bDescriptorSubtype;      /*!< input terminal descriptor subtype. */
+    uint8_t  bTerminalID;             /*!< constant uniquely identifying the terminal within the audio function */
+    uint16_t wTerminalType;           /*!< constant characterizing the type of terminal */
+    uint8_t  bAssocTerminal;          /*!< ID of the output terminal */
+    uint8_t  bNrChannels;             /*!< number of logical output channels */
+    uint16_t wChannelConfig;          /*!< describes the spatial location of the logical channels */
+    uint8_t  iChannelNames;           /*!< index of a string descriptor */
+    uint8_t  iTerminal;               /*!< index of a string descriptor */
+} usb_desc_input_terminal;
+
+typedef struct {
+    usb_desc_header header;           /*!< descriptor header, including type and size */
+    uint8_t  bDescriptorSubtype;      /*!< output terminal descriptor subtype */
+    uint8_t  bTerminalID;             /*!< constant uniquely identifying the terminal within the audio function */
+    uint16_t wTerminalType;           /*!< constant characterizing the type of terminal */
+    uint8_t  bAssocTerminal;          /*!< constant, identifying the input terminal to which this output terminal is associated */
+    uint8_t  bSourceID;               /*!< ID of the unit or terminal */
+    uint8_t  iTerminal;               /*!< index of a string descriptor */
+} usb_desc_output_terminal;
+
+typedef struct {
+    usb_desc_header header;           /*!< descriptor header, including type and size */
+    uint8_t  bDescriptorSubtype;      /*!< feature unit descriptor subtype */
+    uint8_t  bUnitID;                 /*!< constant uniquely identifying the unit within the audio function */
+    uint8_t  bSourceID;               /*!< ID of the unit or terminal */
+    uint8_t  bControlSize;            /*!< size in bytes of an element of the bmaControls() array */
+    uint8_t  bmaControls0;            /*!< a bit set to 1 indicates that the mentioned control is supported for master channel 0 */
+    uint8_t  bmaControls1;            /*!< a bit set to 1 indicates that the mentioned control is supported for logical channel 1 */
+    uint8_t  iFeature;                /*!< index of a string descriptor */
+} usb_desc_mono_feature_unit;
+
+typedef struct {
+    usb_desc_header header;           /*!< descriptor header, including type and size */
+    uint8_t  bDescriptorSubtype;      /*!< feature unit descriptor subtype */
+    uint8_t  bUnitID;                 /*!< constant uniquely identifying the unit within the audio function */
+    uint8_t  bSourceID;               /*!< ID of the unit or terminal */
+    uint8_t  bControlSize;            /*!< size in bytes of an element of the bmaControls() array */
+    uint16_t bmaControls0;            /*!< a bit set to 1 indicates that the mentioned control is supported for master channel 0 */
+    uint16_t bmaControls1;            /*!< a bit set to 1 indicates that the mentioned control is supported for logical channel 1 */
+    uint16_t bmaControls2;            /*!< a bit set to 1 indicates that the mentioned control is supported for logical channel 2 */
+    uint8_t  iFeature;                /*!< index of a string descriptor */
+} usb_desc_stereo_feature_unit;
+
+typedef struct {
+    usb_desc_header header;           /*!< descriptor header, including type and size */
+    uint8_t  bDescriptorSubtype;      /*!< format type descriptor subtype */
+    uint8_t  bFormatType;             /*!< constant identifying the format type */
+    uint8_t  bNrChannels;             /*!< indicates the number of physical channels in the audio data stream */
+    uint8_t  bSubFrameSize;           /*!< the number of bytes occupied by one audio subframe */
+    uint8_t  bBitResolution;          /*!< the number of effectively used bits from the available bits in an audio subframe */
+    uint8_t  bSamFreqType;            /*!< indicates how the sampling frequency can be programmed */
+    uint8_t  bSamFreq[3];             /*!< sampling frequency ns in Hz for this isochronous data endpoint */
+} usb_desc_format_type;
+
+typedef struct {
+    usb_desc_header header;           /*!< descriptor header, including type and size */
+    uint8_t  bEndpointAddress;        /*!< the address of the endpoint */
+    uint8_t  bmAttributes;            /*!< transfer type and synchronization type */
+    uint16_t wMaxPacketSize;          /*!< maximum packet size this endpoint is capable of sending or receiving */
+    uint8_t  bInterval;               /*!< left to the designer's discretion */
+    uint8_t  bRefresh;                /*!< reset to 0 */
+    uint8_t  bSynchAddress;           /*!< reset to 0 */
+} usb_desc_std_ep;
+
+typedef struct {
+    usb_desc_header header;           /*!< descriptor header, including type and size */
+    uint8_t  bDescriptorSubtype;      /*!< general endpoint descriptor subtype */
+    uint8_t  bmAttributes;            /*!< transfer type and synchronization type */
+    uint8_t  bLockDelayUnits;         /*!< indicates the units used for the lock delay field */
+    uint16_t wLockDelay;              /*!< indicates the time it takes this endpoint to reliably lock its internal clock recovery circuitry */
+} usb_desc_AS_ep;
+
+typedef struct {
+    usb_desc_header header;           /*!< descriptor header, including type and size */
+    uint8_t  bEndpointAddress;        /*!< general endpoint descriptor subtype */
+    uint8_t  bmAttributes;            /*!< transfer type and synchronization type */
+    uint16_t wMaxPacketSize;          /*!< maximum packet size this endpoint is capable of sending or receiving */
+    uint8_t  bInterval;               /*!< polling interval in milliseconds for the endpoint if it is an interrupt or isochronous type */
+    uint8_t  Refresh;                 /*!< refresh 1~9, power of 2 */
+    uint8_t  bSynchAddress;           /*!< synchronous address */
+} usb_desc_FeedBack_ep;
+
+#pragma pack()
+
+/* USB configuration descriptor structure */
+typedef struct {
+    usb_desc_config              config;                        /*!< configuration descriptor */
+    usb_desc_itf                 std_itf;                       /*!< interface descriptor */
+    usb_desc_AC_itf              ac_itf;                        /*!< audio controller interface descriptor */
+
+#ifdef USE_USB_AD_MICPHONE
+    usb_desc_input_terminal      mic_in_terminal;               /*!< microphone input terminal descriptor */
+    usb_desc_mono_feature_unit   mic_feature_unit;              /*!< microphone feature unit descriptor */
+    usb_desc_output_terminal     mic_out_terminal;              /*!< microphone output terminal descriptor */
+#endif
+
+#ifdef USE_USB_AD_SPEAKER
+    usb_desc_input_terminal       speak_in_terminal;            /*!< speaker input terminal descriptor */
+    usb_desc_mono_feature_unit    speak_feature_unit;           /*!< speaker feature unit descriptor */
+    usb_desc_output_terminal      speak_out_terminal;           /*!< speaker output terminal descriptor */
+#endif /* USE_USB_AD_SPEAKER */
+
+#ifdef USE_USB_AD_MICPHONE
+    usb_desc_itf                 mic_std_as_itf_zeroband;       /*!< microphone zeroband configuration standard audio streaming interface descriptor */
+    usb_desc_itf                 mic_std_as_itf_opera;          /*!< microphone standard audio streaming interface descriptor */
+    usb_desc_AS_itf              mic_as_itf;                    /*!< microphone audio correlation descriptor */
+    usb_desc_format_type         mic_format_typeI;              /*!< microphone typeI format type descriptor */
+    usb_desc_std_ep              mic_std_endpoint;              /*!< microphone standard endpoint descriptor */
+    usb_desc_AS_ep               mic_as_endpoint;               /*!< microphone audio dependent isochronous data endpoint descriptor */
+#endif /* USE_USB_AD_MICPHONE */
+
+#ifdef USE_USB_AD_SPEAKER
+    usb_desc_itf                speak_std_as_itf_zeroband;      /*!< speaker zeroband configuration standard audio streaming interface descriptor */
+    usb_desc_itf                speak_std_as_itf_opera;         /*!< speaker standard audio streaming interface descriptor */
+    usb_desc_AS_itf             speak_as_itf;                   /*!< speaker audio correlation descriptor */
+    usb_desc_format_type        speak_format_typeI;             /*!< speaker typeI format type descriptor */
+    usb_desc_std_ep             speak_std_endpoint;             /*!< speaker standard endpoint descriptor */
+    usb_desc_AS_ep              speak_as_endpoint;              /*!< speaker audio dependent isochronous data endpoint descriptor */
+    usb_desc_FeedBack_ep        speak_feedback_endpoint;        /*!< speaker feedback endpoint descriptor */
+#endif /* USE_USB_AD_SPEAKER */
+} usb_desc_config_set;
+
+typedef struct {
+    /* main buffer for audio data OUT transfers and its relative pointers */
+    uint8_t  isoc_out_buff[TOTAL_OUT_BUF_SIZE];                 /*!< audio isochronous OUT data buff */
+    uint8_t* isoc_out_wrptr;                                    /*!< audio isochronous OUT data write pointer */
+    uint8_t* isoc_out_rdptr;                                    /*!< audio isochronous OUT data read pointer */
+    uint16_t buf_free_size;                                     /*!< audio data buff free size */
+    uint16_t dam_tx_len;                                        /*!< audio amplifier transmit length */
+
+    __IO uint32_t actual_freq;                                  /*!< audio actual frequency */
+    __IO uint8_t play_flag;                                     /*!< audio play flag */
+    uint8_t feedback_freq[3];                                   /*!< audio feedback frequency */
+    uint32_t cur_sam_freq;                                      /*!< audio current sampling frequency */
+
+    /* USB receive buffer */
+    uint8_t usb_rx_buffer[SPEAKER_OUT_MAX_PACKET];
+
+    /* main buffer for audio control requests transfers and its relative variables */
+    uint8_t  audioctl[64];                                      /*!< audio control requests transfers buff */
+    uint8_t  audioctl_unit;                                     /*!< audio control requests unit */
+    uint32_t audioctl_len;                                      /*!< audio control requests length */
+} usbd_audio_handler;
+
+extern usb_desc audio_desc;
+extern usb_class_core usbd_audio_cb;
+extern usbd_audio_handler audio_handler;
+
+#endif /* AUDIO_CORE_H */

+ 48 - 0
GD32F3x0/GD32F3x0_usbfs_library/device/class/audio/Include/audio_out_itf.h

@@ -0,0 +1,48 @@
+/*!
+    \file    audio_out_itf.h
+    \brief   audio OUT (playback) interface header file
+
+    \version 2025-01-01, V2.5.0, firmware for GD32F3x0
+*/
+
+/*
+    Copyright (c) 2025, GigaDevice Semiconductor Inc.
+
+    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 of the copyright holder 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 HOLDER 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.
+*/
+
+#ifndef AUDIO_OUT_ITF_H
+#define AUDIO_OUT_ITF_H
+
+#include "usbd_conf.h"
+
+typedef struct {
+    uint8_t (*audio_init)(uint32_t audio_freq, uint32_t volume);
+    uint8_t (*audio_deinit)(void);
+    uint8_t (*audio_cmd)(uint8_t* pbuf, uint32_t size, uint8_t cmd);
+} audio_fops_struct;
+
+extern audio_fops_struct audio_out_fops;
+
+#endif /* AUDIO_OUT_ITF_H */

+ 951 - 0
GD32F3x0/GD32F3x0_usbfs_library/device/class/audio/Source/audio_core.c

@@ -0,0 +1,951 @@
+/*!
+    \file    audio_core.c
+    \brief   USB audio device class core functions
+
+    \version 2025-01-01, V2.5.0, firmware for GD32F3x0
+*/
+
+/*
+    Copyright (c) 2025, GigaDevice Semiconductor Inc.
+
+    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 of the copyright holder 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 HOLDER 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.
+*/
+
+#include "audio_out_itf.h"
+#include "audio_core.h"
+#include <string.h>
+
+#define USBD_VID                     0x28E9U
+#define USBD_PID                     0x9574U
+
+#define VOL_MIN                      0U    /* volume minimum value */
+#define VOL_MAX                      100U  /* volume maximum value */
+#define VOL_RES                      1U    /* volume resolution */
+#define VOL_0dB                      70U   /* 0dB is in the middle of VOL_MIN and VOL_MAX */
+
+#ifdef USE_USB_AD_MICPHONE
+extern volatile uint32_t count_data;
+extern const char wavetestdata[];
+#define LENGTH_DATA                  (1747U * 32U)
+#endif /* USE_USB_AD_MICPHONE */
+
+usbd_audio_handler audio_handler;
+
+/* local function prototypes ('static') */
+static uint8_t audio_init(usb_dev *udev, uint8_t config_index);
+static uint8_t audio_deinit(usb_dev *udev, uint8_t config_index);
+static uint8_t audio_req_handler(usb_dev *udev, usb_req *req);
+static uint8_t audio_set_intf(usb_dev *udev, usb_req *req);
+static uint8_t audio_ctlx_out(usb_dev *udev);
+static uint8_t audio_data_in(usb_dev *udev, uint8_t ep_num);
+static uint8_t audio_data_out(usb_dev *udev, uint8_t ep_num);
+static uint8_t audio_sof(usb_dev *udev);
+static uint8_t audio_iso_in_incomplete(usb_dev *udev);
+static uint8_t audio_iso_out_incomplete(usb_dev *udev);
+static uint32_t usbd_audio_spk_get_feedback(usb_dev *udev);
+static void get_feedback_fs_rate(uint32_t rate, uint8_t *buf);
+
+usb_class_core usbd_audio_cb = {
+    .init      = audio_init,
+    .deinit    = audio_deinit,
+    .req_proc  = audio_req_handler,
+    .set_intf  = audio_set_intf,
+    .ctlx_out  = audio_ctlx_out,
+    .data_in   = audio_data_in,
+    .data_out  = audio_data_out,
+    .SOF       = audio_sof,
+    .incomplete_isoc_in = audio_iso_in_incomplete,
+    .incomplete_isoc_out = audio_iso_out_incomplete
+};
+
+/* note:it should use the c99 standard when compiling the below codes */
+/* USB standard device descriptor */
+const usb_desc_dev audio_dev_desc = {
+    .header = 
+     {
+         .bLength          = USB_DEV_DESC_LEN, 
+         .bDescriptorType  = USB_DESCTYPE_DEV
+     },
+    .bcdUSB                = 0x0200U,
+    .bDeviceClass          = 0x00U,
+    .bDeviceSubClass       = 0x00U,
+    .bDeviceProtocol       = 0x00U,
+    .bMaxPacketSize0       = USB_FS_EP0_MAX_LEN,
+    .idVendor              = USBD_VID,
+    .idProduct             = USBD_PID,
+    .bcdDevice             = 0x0100U,
+    .iManufacturer         = STR_IDX_MFC,
+    .iProduct              = STR_IDX_PRODUCT,
+    .iSerialNumber         = STR_IDX_SERIAL,
+    .bNumberConfigurations = USBD_CFG_MAX_NUM
+};
+
+/* USB device configuration descriptor */
+const usb_desc_config_set audio_config_set = {
+    .config =
+    {
+        .header =
+        {
+            .bLength         = sizeof(usb_desc_config),
+            .bDescriptorType = USB_DESCTYPE_CONFIG
+        },
+        .wTotalLength         = AD_CONFIG_DESC_SET_LEN,
+        .bNumInterfaces       = 0x01U + CONFIG_DESC_AS_ITF_COUNT,
+        .bConfigurationValue  = 0x01U,
+        .iConfiguration       = 0x00U,
+        .bmAttributes         = 0xC0U,
+        .bMaxPower            = 0x32U
+    },
+
+    .std_itf =
+    {
+        .header =
+        {
+            .bLength         = sizeof(usb_desc_itf),
+            .bDescriptorType = USB_DESCTYPE_ITF
+        },
+        .bInterfaceNumber    = 0x00U,
+        .bAlternateSetting   = 0x00U,
+        .bNumEndpoints       = 0x00U,
+        .bInterfaceClass     = USB_CLASS_AUDIO,
+        .bInterfaceSubClass  = AD_SUBCLASS_CONTROL,
+        .bInterfaceProtocol  = AD_PROTOCOL_UNDEFINED,
+        .iInterface          = 0x00U
+    },
+
+    .ac_itf =
+    {
+        .header =
+        {
+            .bLength         = sizeof(usb_desc_AC_itf),
+            .bDescriptorType = AD_DESCTYPE_INTERFACE
+        },
+        .bDescriptorSubtype  = 0x01U,
+        .bcdADC              = 0x0100U,
+        .wTotalLength        = AC_ITF_TOTAL_LEN,
+        .bInCollection       = CONFIG_DESC_AS_ITF_COUNT,
+#ifdef USE_USB_AD_MICPHONE
+        .baInterfaceNr0       = 0x01U,
+#endif /* USE_USB_AD_MICPHONE */
+
+#ifdef USE_USB_AD_SPEAKER
+        .baInterfaceNr1       = 0x02U
+#endif /* USE_USB_AD_SPEAKER */
+    },
+
+#ifdef USE_USB_AD_MICPHONE
+    .mic_in_terminal =
+    {
+        .header =
+        {
+            .bLength         = sizeof(usb_desc_input_terminal),
+            .bDescriptorType = AD_DESCTYPE_INTERFACE
+        },
+        .bDescriptorSubtype  = 0x02U,
+        .bTerminalID         = 0x01U,
+        .wTerminalType       = 0x0201U,
+        .bAssocTerminal      = 0x00U,
+        .bNrChannels         = 0x02U,
+        .wChannelConfig      = 0x0003U,
+        .iChannelNames       = 0x00U,
+        .iTerminal           = 0x00U
+    },
+
+    .mic_feature_unit =
+    {
+        .header =
+        {
+            .bLength         = sizeof(usb_desc_mono_feature_unit),
+            .bDescriptorType = AD_DESCTYPE_INTERFACE
+        },
+        .bDescriptorSubtype  = AD_CONTROL_FEATURE_UNIT,
+        .bUnitID             = AD_IN_STREAMING_CTRL,
+        .bSourceID           = 0x01U,
+        .bControlSize        = 0x01U,
+        .bmaControls0        = AD_CONTROL_MUTE | AD_CONTROL_VOLUME,
+        .bmaControls1        = 0x00U,
+        .iFeature            = 0x00U
+    },
+
+    .mic_out_terminal =
+    {
+        .header =
+        {
+            .bLength         = sizeof(usb_desc_output_terminal),
+            .bDescriptorType = AD_DESCTYPE_INTERFACE
+        },
+        .bDescriptorSubtype  = AD_CONTROL_OUTPUT_TERMINAL,
+        .bTerminalID         = 0x03U,
+        .wTerminalType       = 0x0101U,
+        .bAssocTerminal      = 0x00U,
+        .bSourceID           = 0x02U,
+        .iTerminal           = 0x00U
+    },
+#endif /* USE_USB_AD_MICPHONE */
+
+#ifdef USE_USB_AD_SPEAKER
+    .speak_in_terminal =
+    {
+        .header =
+        {
+            .bLength         = sizeof(usb_desc_input_terminal),
+            .bDescriptorType = AD_DESCTYPE_INTERFACE
+        },
+        .bDescriptorSubtype  = AD_CONTROL_INPUT_TERMINAL,
+        .bTerminalID         = 0x04U,
+        .wTerminalType       = 0x0101U,
+        .bAssocTerminal      = 0x00U,
+        .bNrChannels         = 0x02U,
+        .wChannelConfig      = 0x0003U,
+        .iChannelNames       = 0x00U,
+        .iTerminal           = 0x00U
+    },
+
+    .speak_feature_unit =
+    {
+        .header =
+        {
+            .bLength         = sizeof(usb_desc_mono_feature_unit),
+            .bDescriptorType = AD_DESCTYPE_INTERFACE
+        },
+        .bDescriptorSubtype  = AD_CONTROL_FEATURE_UNIT,
+        .bUnitID             = AD_OUT_STREAMING_CTRL,
+        .bSourceID           = 0x04U,
+        .bControlSize        = 0x01U,
+        .bmaControls0        = AD_CONTROL_MUTE | AD_CONTROL_VOLUME,
+        .bmaControls1        = 0x00U,
+        .iFeature            = 0x00U
+    },
+
+    .speak_out_terminal =
+    {
+        .header =
+        {
+            .bLength         = sizeof(usb_desc_output_terminal),
+            .bDescriptorType = AD_DESCTYPE_INTERFACE
+        },
+        .bDescriptorSubtype  = AD_CONTROL_OUTPUT_TERMINAL,
+        .bTerminalID         = 0x06U,
+        .wTerminalType       = 0x0301U,
+        .bAssocTerminal      = 0x00U,
+        .bSourceID           = 0x05U,
+        .iTerminal           = 0x00U
+    },
+#endif /* USE_USB_AD_SPEAKER */
+
+#ifdef USE_USB_AD_MICPHONE
+    .mic_std_as_itf_zeroband =
+    {
+        .header =
+        {
+            .bLength         = sizeof(usb_desc_itf),
+            .bDescriptorType = USB_DESCTYPE_ITF
+        },
+        .bInterfaceNumber    = 0x01U,
+        .bAlternateSetting   = 0x00U,
+        .bNumEndpoints       = 0x00U,
+        .bInterfaceClass     = USB_CLASS_AUDIO,
+        .bInterfaceSubClass  = AD_SUBCLASS_AUDIOSTREAMING,
+        .bInterfaceProtocol  = AD_PROTOCOL_UNDEFINED,
+        .iInterface          = 0x00U
+    },
+
+    .mic_std_as_itf_opera =
+    {
+        .header =
+        {
+            .bLength         = sizeof(usb_desc_itf),
+            .bDescriptorType = USB_DESCTYPE_ITF
+        },
+        .bInterfaceNumber    = 0x01U,
+        .bAlternateSetting   = 0x01U,
+        .bNumEndpoints       = 0x01U,
+        .bInterfaceClass     = USB_CLASS_AUDIO,
+        .bInterfaceSubClass  = AD_SUBCLASS_AUDIOSTREAMING,
+        .bInterfaceProtocol  = AD_PROTOCOL_UNDEFINED,
+        .iInterface          = 0x00U
+    },
+
+    .mic_as_itf =
+    {
+        .header =
+        {
+            .bLength         = sizeof(usb_desc_AS_itf),
+            .bDescriptorType = AD_DESCTYPE_INTERFACE
+        },
+        .bDescriptorSubtype  = AD_STREAMING_GENERAL,
+        .bTerminalLink       = 0x03U,
+        .bDelay              = 0x01U,
+        .wFormatTag          = 0x0001U
+    },
+
+    .mic_format_typeI =
+    {
+        .header =
+        {
+            .bLength         = sizeof(usb_desc_format_type),
+            .bDescriptorType = AD_DESCTYPE_INTERFACE
+        },
+        .bDescriptorSubtype  = AD_STREAMING_FORMAT_TYPE,
+        .bFormatType         = AD_FORMAT_TYPE_I,
+        .bNrChannels         = MIC_IN_CHANNEL_NBR,
+        .bSubFrameSize       = 0x02U,
+        .bBitResolution      = MIC_IN_BIT_RESOLUTION,
+        .bSamFreqType        = 0x01U,
+        .bSamFreq[0]         = (uint8_t)USBD_MIC_FREQ,
+        .bSamFreq[1]         = USBD_MIC_FREQ >> 8,
+        .bSamFreq[2]         = USBD_MIC_FREQ >> 16
+    },
+
+    .mic_std_endpoint =
+    {
+        .header =
+        {
+            .bLength         = sizeof(usb_desc_std_ep),
+            .bDescriptorType = USB_DESCTYPE_EP
+        },
+        .bEndpointAddress    = AD_IN_EP,
+        .bmAttributes        = USB_ENDPOINT_TYPE_ISOCHRONOUS,
+        .wMaxPacketSize      = MIC_IN_PACKET,
+        .bInterval           = 0x01U,
+        .bRefresh            = 0x00U,
+        .bSynchAddress       = 0x00U
+    },
+
+    .mic_as_endpoint =
+    {
+        .header =
+        {
+            .bLength         = sizeof(usb_desc_AS_ep),
+            .bDescriptorType = AD_DESCTYPE_ENDPOINT
+        },
+        .bDescriptorSubtype  = AD_ENDPOINT_GENERAL,
+        .bmAttributes        = 0x00U,
+        .bLockDelayUnits     = 0x00U,
+        .wLockDelay          = 0x0000U
+    },
+#endif /* USE_USB_AD_MICPHONE */
+
+#ifdef USE_USB_AD_SPEAKER
+    .speak_std_as_itf_zeroband =
+    {
+        .header =
+        {
+            .bLength         = sizeof(usb_desc_itf),
+            .bDescriptorType = USB_DESCTYPE_ITF
+        },
+        .bInterfaceNumber    = 0x02U,
+        .bAlternateSetting   = 0x00U,
+        .bNumEndpoints       = 0x00U,
+        .bInterfaceClass     = USB_CLASS_AUDIO,
+        .bInterfaceSubClass  = AD_SUBCLASS_AUDIOSTREAMING,
+        .bInterfaceProtocol  = AD_PROTOCOL_UNDEFINED,
+        .iInterface          = 0x00U
+    },
+
+    .speak_std_as_itf_opera =
+    {
+        .header =
+        {
+            .bLength         = sizeof(usb_desc_itf),
+            .bDescriptorType = USB_DESCTYPE_ITF
+        },
+        .bInterfaceNumber    = 0x02U,
+        .bAlternateSetting   = 0x01U,
+        .bNumEndpoints       = 0x02U,
+        .bInterfaceClass     = USB_CLASS_AUDIO,
+        .bInterfaceSubClass  = AD_SUBCLASS_AUDIOSTREAMING,
+        .bInterfaceProtocol  = AD_PROTOCOL_UNDEFINED,
+        .iInterface          = 0x00U
+    },
+
+    .speak_as_itf =
+    {
+        .header =
+        {
+            .bLength         = sizeof(usb_desc_AS_itf),
+            .bDescriptorType = AD_DESCTYPE_INTERFACE
+        },
+        .bDescriptorSubtype  = AD_STREAMING_GENERAL,
+        .bTerminalLink       = 0x04U,
+        .bDelay              = 0x01U,
+        .wFormatTag          = 0x0001U
+    },
+
+    .speak_format_typeI =
+    {
+        .header =
+        {
+            .bLength         = sizeof(usb_desc_format_type),
+            .bDescriptorType = AD_DESCTYPE_INTERFACE
+        },
+        .bDescriptorSubtype  = AD_STREAMING_FORMAT_TYPE,
+        .bFormatType         = AD_FORMAT_TYPE_I,
+        .bNrChannels         = SPEAKER_OUT_CHANNEL_NBR,
+        .bSubFrameSize       = 0x02U,
+        .bBitResolution      = SPEAKER_OUT_BIT_RESOLUTION,
+        .bSamFreqType        = 0x01U,
+        .bSamFreq[0]         = (uint8_t)USBD_SPEAKER_FREQ,
+        .bSamFreq[1]         = USBD_SPEAKER_FREQ >> 8,
+        .bSamFreq[2]         = USBD_SPEAKER_FREQ >> 16
+    },
+
+    .speak_std_endpoint =
+    {
+        .header =
+        {
+            .bLength         = sizeof(usb_desc_std_ep),
+            .bDescriptorType = USB_DESCTYPE_EP
+        },
+        .bEndpointAddress    = AD_OUT_EP,
+        .bmAttributes        = USB_EP_ATTR_ISO | USB_EP_ATTR_ASYNC,
+        .wMaxPacketSize      = SPEAKER_OUT_PACKET,
+        .bInterval           = 0x01U,
+        .bRefresh            = 0x00U,
+        .bSynchAddress       = AD_FEEDBACK_IN_EP
+    },
+
+    .speak_as_endpoint =
+    {
+        .header =
+        {
+            .bLength         = sizeof(usb_desc_AS_ep),
+            .bDescriptorType = AD_DESCTYPE_ENDPOINT
+        },
+        .bDescriptorSubtype  = AD_ENDPOINT_GENERAL,
+        .bmAttributes        = 0x00U,
+        .bLockDelayUnits     = 0x00U,
+        .wLockDelay          = 0x0000U,
+    },
+
+    .speak_feedback_endpoint =
+    {
+        .header =
+        {
+            .bLength         = sizeof(usb_desc_FeedBack_ep),
+            .bDescriptorType = USB_DESCTYPE_EP
+        },
+        .bEndpointAddress    = AD_FEEDBACK_IN_EP,
+        .bmAttributes        = USB_EP_ATTR_ISO | USB_EP_ATTR_ASYNC | USB_EP_ATTR_FEEDBACK,
+        .wMaxPacketSize      = FEEDBACK_IN_PACKET,
+        .bInterval           = 0x01U,
+        .Refresh             = FEEDBACK_IN_INTERVAL, /* refresh every 32(2^5) ms */
+        .bSynchAddress       = 0x00U
+    },
+#endif /* USE_USB_AD_SPEAKER */
+};
+
+/* USB language ID descriptor */
+static const usb_desc_LANGID usbd_language_id_desc = {
+    .header =
+    {
+        .bLength         = sizeof(usb_desc_LANGID),
+        .bDescriptorType = USB_DESCTYPE_STR
+    },
+
+    .wLANGID = ENG_LANGID
+};
+
+/* USB manufacture string */
+static const usb_desc_str manufacturer_string = {
+    .header =
+    {
+        .bLength         = USB_STRING_LEN(10U),
+        .bDescriptorType = USB_DESCTYPE_STR
+    },
+    .unicode_string = {'G', 'i', 'g', 'a', 'D', 'e', 'v', 'i', 'c', 'e'}
+};
+
+/* USB product string */
+static const usb_desc_str product_string = {
+    .header =
+    {
+        .bLength         = USB_STRING_LEN(14U),
+        .bDescriptorType = USB_DESCTYPE_STR
+    },
+    .unicode_string = {'G', 'D', '3', '2', '-', 'U', 'S', 'B', '_', 'A', 'u', 'd', 'i', 'o'}
+};
+
+/* USBD serial string */
+static usb_desc_str serial_string = {
+    .header =
+    {
+        .bLength         = USB_STRING_LEN(12U),
+        .bDescriptorType = USB_DESCTYPE_STR
+    }
+};
+
+/* USB string descriptor */
+void *const usbd_audio_strings[] = {
+    [STR_IDX_LANGID]  = (uint8_t *)&usbd_language_id_desc,
+    [STR_IDX_MFC]     = (uint8_t *)&manufacturer_string,
+    [STR_IDX_PRODUCT] = (uint8_t *)&product_string,
+    [STR_IDX_SERIAL]  = (uint8_t *)&serial_string
+};
+
+/* USB descriptor configure */
+usb_desc audio_desc = {
+    .dev_desc    = (uint8_t *)&audio_dev_desc,
+    .config_desc = (uint8_t *)&audio_config_set,
+    .strings     = usbd_audio_strings
+};
+
+/*!
+    \brief      initialize the AUDIO device
+    \param[in]  udev: pointer to USB device instance
+    \param[in]  config_index: configuration index
+    \param[out] none
+    \retval     USB device operation status
+*/
+static uint8_t audio_init(usb_dev *udev, uint8_t config_index)
+{
+    memset((void *)&audio_handler, 0U, sizeof(usbd_audio_handler));
+
+#ifdef USE_USB_AD_MICPHONE
+    {
+        usb_desc_std_ep std_ep = audio_config_set.mic_std_endpoint;
+
+        usb_desc_ep ep = {
+            .header           = std_ep.header,
+            .bEndpointAddress = std_ep.bEndpointAddress,
+            .bmAttributes     = std_ep.bmAttributes,
+            .wMaxPacketSize   = std_ep.wMaxPacketSize,
+            .bInterval        = std_ep.bInterval
+        };
+
+        /* initialize TX endpoint */
+        usbd_ep_setup(udev, &ep);
+    }
+#endif /* USE_USB_AD_MICPHONE */
+
+#ifdef USE_USB_AD_SPEAKER
+    {
+        audio_handler.isoc_out_rdptr = audio_handler.isoc_out_buff;
+        audio_handler.isoc_out_wrptr = audio_handler.isoc_out_buff;
+
+        usb_desc_std_ep std_ep = audio_config_set.speak_std_endpoint;
+
+        usb_desc_ep ep1 = {
+            .header           = std_ep.header,
+            .bEndpointAddress = std_ep.bEndpointAddress,
+            .bmAttributes     = std_ep.bmAttributes,
+            .wMaxPacketSize   = SPEAKER_OUT_MAX_PACKET,
+            .bInterval        = std_ep.bInterval
+        };
+
+        /* initialize RX endpoint */
+        usbd_ep_setup(udev, &ep1);
+
+        /* prepare OUT endpoint to receive next audio packet */
+        usbd_ep_recev(udev, AD_OUT_EP, audio_handler.usb_rx_buffer, SPEAKER_OUT_MAX_PACKET);
+
+        /* initialize the audio output hardware layer */
+        if(USBD_OK != audio_out_fops.audio_init(USBD_SPEAKER_FREQ, DEFAULT_VOLUME)) {
+            return USBD_FAIL;
+        }
+
+        usb_desc_FeedBack_ep feedback_ep = audio_config_set.speak_feedback_endpoint;
+
+        usb_desc_ep ep2 = {
+            .header           = feedback_ep.header,
+            .bEndpointAddress = feedback_ep.bEndpointAddress,
+            .bmAttributes     = feedback_ep.bmAttributes,
+            .wMaxPacketSize   = feedback_ep.wMaxPacketSize,
+            .bInterval        = feedback_ep.bInterval
+        };
+
+        /* initialize TX endpoint */
+        usbd_ep_setup(udev, &ep2);
+    }
+#endif /* USE_USB_AD_SPEAKER */
+
+    return USBD_OK;
+}
+
+/*!
+    \brief      de-initialize the AUDIO device
+    \param[in]  udev: pointer to USB device instance
+    \param[in]  config_index: configuration index
+    \param[out] none
+    \retval     USB device operation status
+*/
+static uint8_t audio_deinit(usb_dev *udev, uint8_t config_index)
+{
+#ifdef USE_USB_AD_MICPHONE
+    /* deinitialize AUDIO endpoints */
+    usbd_ep_clear(udev, AD_IN_EP);
+#endif /* USE_USB_AD_MICPHONE */
+
+#ifdef USE_USB_AD_SPEAKER
+    /* deinitialize AUDIO endpoints */
+    usbd_ep_clear(udev, AD_OUT_EP);
+
+    /* deinitialize the audio output hardware layer */
+    if(USBD_OK != audio_out_fops.audio_deinit()) {
+        return USBD_FAIL;
+    }
+
+    /* deinitialize AUDIO endpoints */
+    usbd_ep_clear(udev, AD_FEEDBACK_IN_EP);
+#endif /* USE_USB_AD_SPEAKER */
+
+    return USBD_OK;
+}
+
+/*!
+    \brief      handle the AUDIO class-specific requests
+    \param[in]  udev: pointer to USB device instance
+    \param[in]  req: device class-specific request
+    \param[out] none
+    \retval     USB device operation status
+*/
+static uint8_t audio_req_handler(usb_dev *udev, usb_req *req)
+{
+    uint8_t status = REQ_NOTSUPP;
+
+    usb_transc *transc_in = &udev->dev.transc_in[0];
+    usb_transc *transc_out = &udev->dev.transc_out[0];
+
+    switch(req->bRequest) {
+    case AD_REQ_GET_CUR:
+        transc_in->xfer_buf = audio_handler.audioctl;
+        transc_in->remain_len = req->wLength;
+
+        status = REQ_SUPP;
+        break;
+
+    case AD_REQ_SET_CUR:
+        if(req->wLength) {
+            transc_out->xfer_buf = audio_handler.audioctl;
+            transc_out->remain_len = req->wLength;
+
+            udev->dev.class_core->command = AD_REQ_SET_CUR;
+
+            audio_handler.audioctl_len = req->wLength;
+            audio_handler.audioctl_unit = BYTE_HIGH(req->wIndex);
+
+            status = REQ_SUPP;
+        }
+        break;
+
+    case AD_REQ_GET_MIN:
+        *((uint16_t *)audio_handler.audioctl) = VOL_MIN;
+        transc_in->xfer_buf = audio_handler.audioctl;
+        transc_in->remain_len = req->wLength;
+        status = REQ_SUPP;
+        break;
+
+    case AD_REQ_GET_MAX:
+        *((uint16_t *)audio_handler.audioctl) = VOL_MAX;
+        transc_in->xfer_buf = audio_handler.audioctl;
+        transc_in->remain_len = req->wLength;
+        status = REQ_SUPP;
+        break;
+
+    case AD_REQ_GET_RES:
+        *((uint16_t *)audio_handler.audioctl) = VOL_RES;
+        transc_in->xfer_buf = audio_handler.audioctl;
+        transc_in->remain_len = req->wLength;
+        status = REQ_SUPP;
+        break;
+
+    default:
+        break;
+    }
+
+    return status;
+}
+
+/*!
+    \brief      handle the AUDIO set interface requests
+    \param[in]  udev: pointer to USB device instance
+    \param[in]  req: device class-specific request
+    \param[out] none
+    \retval     USB device operation status
+*/
+static uint8_t audio_set_intf(usb_dev *udev, usb_req *req)
+{
+    udev->dev.class_core->alter_set = req->wValue;
+
+    if(0xFFU != req->wValue) {
+        if(0U != req->wValue) {
+            /* deinit audio handler */
+            memset((void *)&audio_handler, 0U, sizeof(usbd_audio_handler));
+
+            audio_handler.play_flag = 0U;
+            audio_handler.isoc_out_rdptr = audio_handler.isoc_out_buff;
+            audio_handler.isoc_out_wrptr = audio_handler.isoc_out_buff;
+
+            /* feedback calculate sample frequency */
+            audio_handler.actual_freq = I2S_ACTUAL_SAM_FREQ(USBD_SPEAKER_FREQ);
+            get_feedback_fs_rate(audio_handler.actual_freq, audio_handler.feedback_freq);
+
+            /* send feedback data of estimated frequency */
+            usbd_ep_send(udev, AD_FEEDBACK_IN_EP, audio_handler.feedback_freq, FEEDBACK_IN_PACKET);
+        } else {
+            /* stop audio output */
+            audio_out_fops.audio_cmd(audio_handler.isoc_out_rdptr, SPEAKER_OUT_PACKET / 2U, AD_CMD_STOP);
+
+            audio_handler.play_flag = 0U;
+            audio_handler.isoc_out_rdptr = audio_handler.isoc_out_buff;
+            audio_handler.isoc_out_wrptr = audio_handler.isoc_out_buff;
+
+            usbd_fifo_flush(udev, AD_IN_EP);
+            usbd_fifo_flush(udev, AD_FEEDBACK_IN_EP);
+            usbd_fifo_flush(udev, AD_OUT_EP);
+        }
+    }
+
+    return 0U;
+}
+
+/*!
+    \brief      handles the control transfer OUT callback
+    \param[in]  udev: pointer to USB device instance
+    \param[out] none
+    \retval     USB device operation status
+*/
+static uint8_t audio_ctlx_out(usb_dev *udev)
+{
+#ifdef USE_USB_AD_SPEAKER
+    /* handles audio control requests data */
+    /* check if an audio_control request has been issued */
+    if(AD_REQ_SET_CUR == udev->dev.class_core->command) {
+        /* in this driver, to simplify code, only SET_CUR request is managed */
+
+        /* check for which addressed unit the audio_control request has been issued */
+        if(AD_OUT_STREAMING_CTRL == audio_handler.audioctl_unit) {
+            /* in this driver, to simplify code, only one unit is manage */
+
+            /* reset the audioctl_cmd variable to prevent re-entering this function */
+            udev->dev.class_core->command = 0U;
+
+            audio_handler.audioctl_len = 0U;
+        }
+    }
+#endif /* USE_USB_AD_SPEAKER */
+
+    return USBD_OK;
+}
+
+/*!
+    \brief      handles the audio IN data stage
+    \param[in]  udev: pointer to USB device instance
+    \param[in]  ep_num: endpoint number
+    \param[out] none
+    \retval     USB device operation status
+*/
+static uint8_t audio_data_in(usb_dev *udev, uint8_t ep_num)
+{
+#ifdef USE_USB_AD_MICPHONE
+    if(EP_ID(AD_IN_EP) == ep_num) {
+        if(count_data < LENGTH_DATA) {
+            /* Prepare next buffer to be sent: dummy data */
+            usbd_ep_send(udev, AD_IN_EP, (uint8_t *)&wavetestdata[count_data], MIC_IN_PACKET);
+            count_data += MIC_IN_PACKET;
+        } else {
+            usbd_ep_send(udev, AD_IN_EP, (uint8_t *)wavetestdata, MIC_IN_PACKET);
+            count_data = MIC_IN_PACKET;
+        }
+    }
+#endif /* USE_USB_AD_MICPHONE */
+
+#ifdef USE_USB_AD_SPEAKER
+    if(EP_ID(AD_FEEDBACK_IN_EP) == ep_num) {
+        /* calculate feedback actual freq */
+        audio_handler.actual_freq = usbd_audio_spk_get_feedback(udev);
+        get_feedback_fs_rate(audio_handler.actual_freq, audio_handler.feedback_freq);
+
+        usbd_ep_send(udev, AD_FEEDBACK_IN_EP, audio_handler.feedback_freq, FEEDBACK_IN_PACKET);
+    }
+#endif /* USE_USB_AD_SPEAKER */
+
+    return USBD_OK;
+}
+
+/*!
+    \brief      handles the audio OUT data stage
+    \param[in]  udev: pointer to USB device instance
+    \param[in]  ep_num: endpoint number
+    \param[out] none
+    \retval     USB device operation status
+*/
+static uint8_t audio_data_out(usb_dev *udev, uint8_t ep_num)
+{
+    uint16_t usb_rx_length, tail_len;
+
+    /* get receive length */
+    usb_rx_length = ((usb_core_driver *)udev)->dev.transc_out[ep_num].xfer_count;
+
+    if(audio_handler.isoc_out_wrptr >= audio_handler.isoc_out_rdptr) {
+        audio_handler.buf_free_size = TOTAL_OUT_BUF_SIZE + audio_handler.isoc_out_rdptr - audio_handler.isoc_out_wrptr;
+    } else {
+        audio_handler.buf_free_size = audio_handler.isoc_out_rdptr - audio_handler.isoc_out_wrptr;
+    }
+
+    /* free buffer enough to save RX data */
+    if(audio_handler.buf_free_size > usb_rx_length) {
+        if(audio_handler.isoc_out_wrptr >= audio_handler.isoc_out_rdptr) {
+            tail_len = audio_handler.isoc_out_buff + TOTAL_OUT_BUF_SIZE - audio_handler.isoc_out_wrptr;
+
+            if(tail_len >= usb_rx_length) {
+                memcpy(audio_handler.isoc_out_wrptr, audio_handler.usb_rx_buffer, usb_rx_length);
+
+                /* increment the buffer pointer */
+                audio_handler.isoc_out_wrptr += usb_rx_length;
+
+                /* increment the Buffer pointer or roll it back when all buffers are full */
+                if(audio_handler.isoc_out_wrptr >= (audio_handler.isoc_out_buff + TOTAL_OUT_BUF_SIZE)) {
+                    /* all buffers are full: roll back */
+                    audio_handler.isoc_out_wrptr = audio_handler.isoc_out_buff;
+                }
+            } else {
+                memcpy(audio_handler.isoc_out_wrptr, audio_handler.usb_rx_buffer, tail_len);
+                /* adjust write pointer */
+                audio_handler.isoc_out_wrptr = audio_handler.isoc_out_buff;
+
+                memcpy(audio_handler.isoc_out_wrptr, &audio_handler.usb_rx_buffer[tail_len], usb_rx_length - tail_len);
+                /* adjust write pointer */
+                audio_handler.isoc_out_wrptr += usb_rx_length - tail_len;
+            }
+        } else {
+            memcpy(audio_handler.isoc_out_wrptr, audio_handler.usb_rx_buffer, usb_rx_length);
+
+            /* increment the buffer pointer */
+            audio_handler.isoc_out_wrptr += usb_rx_length;
+        }
+    }
+
+    /* toggle the frame index */
+    udev->dev.transc_out[ep_num].frame_num = (udev->dev.transc_out[ep_num].frame_num) ? 0U : 1U;
+
+    /* prepare OUT endpoint to receive next audio packet */
+    usbd_ep_recev(udev, AD_OUT_EP, audio_handler.usb_rx_buffer, SPEAKER_OUT_MAX_PACKET);
+
+    if(audio_handler.isoc_out_wrptr >= audio_handler.isoc_out_rdptr) {
+        audio_handler.buf_free_size = TOTAL_OUT_BUF_SIZE + audio_handler.isoc_out_rdptr - audio_handler.isoc_out_wrptr;
+    } else {
+        audio_handler.buf_free_size = audio_handler.isoc_out_rdptr - audio_handler.isoc_out_wrptr;
+    }
+
+    if((0U == audio_handler.play_flag) && (audio_handler.buf_free_size < TOTAL_OUT_BUF_SIZE / 2U)) {
+        /* enable start of streaming */
+        audio_handler.play_flag = 1U;
+
+        /* initialize the audio output hardware layer */
+        if(USBD_OK != audio_out_fops.audio_cmd(audio_handler.isoc_out_rdptr, SPEAKER_OUT_MAX_PACKET / 2U, AD_CMD_PLAY)) {
+            return USBD_FAIL;
+        }
+
+        audio_handler.dam_tx_len = SPEAKER_OUT_MAX_PACKET;
+    }
+
+    return USBD_OK;
+}
+
+/*!
+    \brief      handles the SOF event (data buffer update and synchronization)
+    \param[in]  udev: pointer to USB device instance
+    \param[out] none
+    \retval     USB device operation status
+*/
+static uint8_t audio_sof(usb_dev *udev)
+{
+    return USBD_OK;
+}
+
+/*!
+    \brief      handles the audio ISO IN Incomplete event
+    \param[in]  udev: pointer to USB device instance
+    \param[out] none
+    \retval     USB device operation status
+*/
+static uint8_t audio_iso_in_incomplete(usb_dev *udev)
+{
+    (void)usb_txfifo_flush(&udev->regs, EP_ID(AD_FEEDBACK_IN_EP));
+
+    audio_handler.actual_freq = usbd_audio_spk_get_feedback(udev);
+    get_feedback_fs_rate(audio_handler.actual_freq, audio_handler.feedback_freq);
+
+    /* send feedback data of estimated frequency */
+    usbd_ep_send(udev, AD_FEEDBACK_IN_EP, audio_handler.feedback_freq, FEEDBACK_IN_PACKET);
+
+    return USBD_OK;
+}
+
+/*!
+    \brief      handles the audio ISO OUT Incomplete event
+    \param[in]  udev: pointer to USB device instance
+    \param[out] none
+    \retval     USB device operation status
+*/
+static uint8_t audio_iso_out_incomplete(usb_dev *udev)
+{
+    return USBD_OK;
+}
+
+/*!
+    \brief      calculate feedback sample frequency
+    \param[in]  udev: pointer to USB device instance
+    \param[out] none
+    \retval     feedback frequency value
+*/
+static uint32_t usbd_audio_spk_get_feedback(usb_dev *udev)
+{
+    static uint32_t fb_freq;
+
+    /* calculate buffer free size */
+    if(audio_handler.isoc_out_wrptr >= audio_handler.isoc_out_rdptr) {
+        audio_handler.buf_free_size = TOTAL_OUT_BUF_SIZE + audio_handler.isoc_out_rdptr - audio_handler.isoc_out_wrptr;
+    } else {
+        audio_handler.buf_free_size = audio_handler.isoc_out_rdptr - audio_handler.isoc_out_wrptr;
+    }
+
+    /* calculate feedback frequency */
+    if(audio_handler.buf_free_size <= (TOTAL_OUT_BUF_SIZE / 4U)) {
+        fb_freq = I2S_ACTUAL_SAM_FREQ(USBD_SPEAKER_FREQ) - FEEDBACK_FREQ_OFFSET;
+    } else if(audio_handler.buf_free_size >= (TOTAL_OUT_BUF_SIZE * 3U / 4U)) {
+        fb_freq = I2S_ACTUAL_SAM_FREQ(USBD_SPEAKER_FREQ) + FEEDBACK_FREQ_OFFSET;
+    } else {
+        fb_freq = I2S_ACTUAL_SAM_FREQ(USBD_SPEAKER_FREQ);
+    }
+
+    return fb_freq;
+}
+
+/*!
+    \brief      get feedback value from rate in USB full speed
+    \param[in]  rate: sample frequency
+    \param[in]  buf: pointer to result buffer
+    \param[out] none
+    \retval     none
+*/
+static void get_feedback_fs_rate(uint32_t rate, uint8_t *buf)
+{
+    rate = ((rate / 1000U) << 14) | ((rate % 1000U) << 4);
+
+    buf[0] = rate;
+    buf[1] = rate >> 8;
+    buf[2] = rate >> 16;
+}

+ 167 - 0
GD32F3x0/GD32F3x0_usbfs_library/device/class/audio/Source/audio_out_itf.c

@@ -0,0 +1,167 @@
+/*!
+    \file    audio_out_itf.c
+    \brief   audio OUT (playback) interface functions
+
+    \version 2025-01-01, V2.5.0, firmware for GD32F3x0
+*/
+
+/*
+    Copyright (c) 2025, GigaDevice Semiconductor Inc.
+
+    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 of the copyright holder 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 HOLDER 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.
+*/
+
+#include "audio_core.h"
+#include "audio_out_itf.h"
+
+/* local function prototypes ('static') */
+static uint8_t init(uint32_t audio_freq, uint32_t volume);
+static uint8_t deinit(void);
+static uint8_t audio_cmd(uint8_t *pbuf, uint32_t size, uint8_t cmd);
+
+/* local variable defines */
+static uint8_t audio_state = AD_STATE_INACTIVE;
+
+audio_fops_struct audio_out_fops = {
+    .audio_init   = init,
+    .audio_deinit = deinit,
+    .audio_cmd    = audio_cmd
+};
+
+/*!
+    \brief      initialize and configures all required resources
+    \param[in]  audio_freq: statrt_up audio frequency
+    \param[in]  volume: start_up volume to be set
+    \param[out] none
+    \retval     AD_OK if all operations succeed, otherwise, AD_FAIL.
+*/
+static uint8_t init(uint32_t audio_freq, uint32_t volume)
+{
+    static uint32_t initialized = 0U;
+
+    /* check if the low layer has already been initialized */
+    if(0U == initialized) {
+        /* initialize GPIO */
+        codec_gpio_init();
+
+        /* initialize I2S */
+        codec_audio_interface_init(audio_freq);
+
+        /* initialize DMA */
+        codec_i2s_dma_init();
+
+        /* prevent reinitializing the interface again */
+        initialized = 1U;
+    }
+
+    /* update the audio state machine */
+    audio_state = AD_STATE_ACTIVE;
+
+    return AD_OK;
+}
+
+/*!
+    \brief      free all resources used by low layer and stops audio-play function
+    \param[in]  none
+    \param[out] none
+    \retval     AD_OK if all operations succeed, otherwise, AD_FAIL.
+*/
+static uint8_t deinit(void)
+{
+    /* update the audio state machine */
+    audio_state = AD_STATE_INACTIVE;
+
+    return AD_OK;
+}
+
+/*!
+    \brief      play, stop, pause or resume current file
+    \param[in]  pbuf: address from which file should be played
+    \param[in]  size: size of the current buffer/file
+    \param[in]  cmd: command to be executed, can be:
+      \arg        AD_CMD_PLAY
+      \arg        AD_CMD_PAUSE
+      \arg        AD_CMD_RESUME
+      \arg        AD_CMD_STOP
+    \param[out] none
+    \retval     AD_OK if all operations succeed, otherwise, AD_FAIL.
+*/
+static uint8_t audio_cmd(uint8_t *pbuf, uint32_t size, uint8_t cmd)
+{
+    /* check the current state */
+    if((AD_STATE_INACTIVE == audio_state) || (AD_STATE_ERROR == audio_state)) {
+        audio_state = AD_STATE_ERROR;
+
+        return AD_FAIL;
+    }
+
+    switch(cmd) {
+    /* process the play command */
+    case AD_CMD_PLAY:
+        /* if current state is active or stopped */
+        if((AD_STATE_ACTIVE == audio_state) || \
+                (AD_STATE_STOPPED == audio_state) || \
+                (AD_STATE_PLAYING == audio_state)) {
+            audio_play((uint32_t)pbuf, size);
+            audio_state = AD_STATE_PLAYING;
+
+            return AD_OK;
+        } else if(AD_STATE_PAUSED == audio_state) {
+            audio_pause_resume(AD_RESUME, (uint32_t)pbuf, (size / 2U));
+            audio_state = AD_STATE_PLAYING;
+
+            return AD_OK;
+        } else {
+            return AD_FAIL;
+        }
+
+    /* process the stop command */
+    case AD_CMD_STOP:
+        if(AD_STATE_PLAYING != audio_state) {
+            /* unsupported command */
+            return AD_FAIL;
+        } else {
+            audio_stop();
+            audio_state = AD_STATE_STOPPED;
+
+            return AD_OK;
+        }
+
+    /* process the pause command */
+    case AD_CMD_PAUSE:
+        if(AD_STATE_PLAYING != audio_state) {
+            /* unsupported command */
+            return AD_FAIL;
+        } else {
+            audio_pause_resume(AD_PAUSE, (uint32_t)pbuf, (size / 2U));
+            audio_state = AD_STATE_PAUSED;
+
+            return AD_OK;
+        }
+
+    /* unsupported command */
+    default:
+        return AD_FAIL;
+    }
+}

+ 65 - 0
GD32F3x0/GD32F3x0_usbfs_library/device/class/cdc/Include/cdc_acm_core.h

@@ -0,0 +1,65 @@
+/*!
+    \file    cdc_acm_core.h
+    \brief   the header file of CDC ACM driver
+
+    \version 2025-01-01, V2.5.0, firmware for GD32F3x0
+*/
+
+/*
+    Copyright (c) 2025, GigaDevice Semiconductor Inc.
+
+    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 of the copyright holder 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 HOLDER 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.
+*/
+
+#ifndef CDC_ACM_CORE_H
+#define CDC_ACM_CORE_H
+
+#include "usbd_enum.h"
+#include "usb_cdc.h"
+
+#define USB_CDC_RX_LEN      USB_CDC_DATA_PACKET_SIZE                         /*< CDC data packet size */
+
+typedef struct {
+    uint8_t data[USB_CDC_RX_LEN];                                            /*< CDC data transfer buff */
+    uint8_t cmd[USB_CDC_CMD_PACKET_SIZE];                                    /*< CDC cmd packet buff */
+
+    uint8_t packet_sent;                                                     /*< CDC data packet start send flag */
+    uint8_t packet_receive;                                                  /*< CDC data packet start receive flag */
+    uint32_t receive_length;                                                 /*< CDC data receive length */
+
+    acm_line line_coding;                                                    /*< CDC line coding structure */
+} usb_cdc_handler;
+
+extern usb_desc cdc_desc;
+extern usb_class_core cdc_class;
+
+/* function declarations */
+/* check CDC ACM is ready for data transfer */
+uint8_t cdc_acm_check_ready(usb_dev *udev);
+/* send CDC ACM data */
+void cdc_acm_data_send(usb_dev *udev);
+/* receive CDC ACM data */
+void cdc_acm_data_receive(usb_dev *udev);
+
+#endif /* CDC_ACM_CORE_H */

+ 520 - 0
GD32F3x0/GD32F3x0_usbfs_library/device/class/cdc/Source/cdc_acm_core.c

@@ -0,0 +1,520 @@
+/*!
+    \file    cdc_acm_core.c
+    \brief   CDC ACM driver
+
+    \version 2025-01-01, V2.5.0, firmware for GD32F3x0
+*/
+
+/*
+    Copyright (c) 2025, GigaDevice Semiconductor Inc.
+
+    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 of the copyright holder 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 HOLDER 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.
+*/
+
+#include "cdc_acm_core.h"
+
+#define USBD_VID                          0x28E9U
+#define USBD_PID                          0x018AU
+
+/* note:it should use the C99 standard when compiling the below codes */
+/* USB standard device descriptor */
+const usb_desc_dev cdc_dev_desc = {
+    .header =
+    {
+        .bLength          = USB_DEV_DESC_LEN,
+        .bDescriptorType  = USB_DESCTYPE_DEV
+    },
+    .bcdUSB                = 0x0200U,
+    .bDeviceClass          = USB_CLASS_CDC,
+    .bDeviceSubClass       = 0x00U,
+    .bDeviceProtocol       = 0x00U,
+    .bMaxPacketSize0       = USB_FS_EP0_MAX_LEN,
+    .idVendor              = USBD_VID,
+    .idProduct             = USBD_PID,
+    .bcdDevice             = 0x0100U,
+    .iManufacturer         = STR_IDX_MFC,
+    .iProduct              = STR_IDX_PRODUCT,
+    .iSerialNumber         = STR_IDX_SERIAL,
+    .bNumberConfigurations = USBD_CFG_MAX_NUM
+};
+
+/* USB device configuration descriptor */
+const usb_cdc_desc_config_set cdc_config_desc = {
+    .config =
+    {
+        .header =
+        {
+            .bLength         = sizeof(usb_desc_config),
+            .bDescriptorType = USB_DESCTYPE_CONFIG
+        },
+        .wTotalLength         = USB_CDC_ACM_CONFIG_DESC_SIZE,
+        .bNumInterfaces       = 0x02U,
+        .bConfigurationValue  = 0x01U,
+        .iConfiguration       = 0x00U,
+        .bmAttributes         = 0x80U,
+        .bMaxPower            = 0x32U
+    },
+
+    .cmd_itf =
+    {
+        .header =
+        {
+            .bLength         = sizeof(usb_desc_itf),
+            .bDescriptorType = USB_DESCTYPE_ITF
+        },
+        .bInterfaceNumber     = 0x00U,
+        .bAlternateSetting    = 0x00U,
+        .bNumEndpoints        = 0x01U,
+        .bInterfaceClass      = USB_CLASS_CDC,
+        .bInterfaceSubClass   = USB_CDC_SUBCLASS_ACM,
+        .bInterfaceProtocol   = USB_CDC_PROTOCOL_AT,
+        .iInterface           = 0x00U
+    },
+
+    .cdc_header =
+    {
+        .header =
+        {
+            .bLength         = sizeof(usb_desc_header_func),
+            .bDescriptorType = USB_DESCTYPE_CS_INTERFACE
+        },
+        .bDescriptorSubtype  = 0x00U,
+        .bcdCDC              = 0x0110U
+    },
+
+    .cdc_call_managment =
+    {
+        .header =
+        {
+            .bLength         = sizeof(usb_desc_call_managment_func),
+            .bDescriptorType = USB_DESCTYPE_CS_INTERFACE
+        },
+        .bDescriptorSubtype  = 0x01U,
+        .bmCapabilities      = 0x00U,
+        .bDataInterface      = 0x01U
+    },
+
+    .cdc_acm =
+    {
+        .header =
+        {
+            .bLength         = sizeof(usb_desc_acm_func),
+            .bDescriptorType = USB_DESCTYPE_CS_INTERFACE
+        },
+        .bDescriptorSubtype  = 0x02U,
+        .bmCapabilities      = 0x02U
+    },
+
+    .cdc_union =
+    {
+        .header =
+        {
+            .bLength         = sizeof(usb_desc_union_func),
+            .bDescriptorType = USB_DESCTYPE_CS_INTERFACE
+        },
+        .bDescriptorSubtype  = 0x06U,
+        .bMasterInterface    = 0x00U,
+        .bSlaveInterface0    = 0x01U
+    },
+
+    .cdc_cmd_endpoint =
+    {
+        .header =
+        {
+            .bLength         = sizeof(usb_desc_ep),
+            .bDescriptorType = USB_DESCTYPE_EP
+        },
+        .bEndpointAddress    = CDC_CMD_EP,
+        .bmAttributes        = USB_EP_ATTR_INT,
+        .wMaxPacketSize      = USB_CDC_CMD_PACKET_SIZE,
+        .bInterval           = 0x0AU
+    },
+
+    .cdc_data_interface =
+    {
+        .header =
+        {
+            .bLength         = sizeof(usb_desc_itf),
+            .bDescriptorType = USB_DESCTYPE_ITF
+        },
+        .bInterfaceNumber    = 0x01U,
+        .bAlternateSetting   = 0x00U,
+        .bNumEndpoints       = 0x02U,
+        .bInterfaceClass     = USB_CLASS_DATA,
+        .bInterfaceSubClass  = 0x00U,
+        .bInterfaceProtocol  = USB_CDC_PROTOCOL_NONE,
+        .iInterface          = 0x00U
+    },
+
+    .cdc_out_endpoint =
+    {
+        .header =
+        {
+            .bLength         = sizeof(usb_desc_ep),
+            .bDescriptorType = USB_DESCTYPE_EP
+        },
+        .bEndpointAddress     = CDC_DATA_OUT_EP,
+        .bmAttributes         = USB_EP_ATTR_BULK,
+        .wMaxPacketSize       = USB_CDC_DATA_PACKET_SIZE,
+        .bInterval            = 0x00U
+    },
+
+    .cdc_in_endpoint =
+    {
+        .header =
+        {
+            .bLength         = sizeof(usb_desc_ep),
+            .bDescriptorType = USB_DESCTYPE_EP
+        },
+        .bEndpointAddress     = CDC_DATA_IN_EP,
+        .bmAttributes         = USB_EP_ATTR_BULK,
+        .wMaxPacketSize       = USB_CDC_DATA_PACKET_SIZE,
+        .bInterval            = 0x00U
+    }
+};
+
+/* USB language ID Descriptor */
+static const usb_desc_LANGID usbd_language_id_desc = {
+    .header =
+    {
+        .bLength         = sizeof(usb_desc_LANGID),
+        .bDescriptorType = USB_DESCTYPE_STR
+    },
+    .wLANGID              = ENG_LANGID
+};
+
+/* USB manufacture string */
+static const usb_desc_str manufacturer_string = {
+    .header =
+    {
+        .bLength         = USB_STRING_LEN(10U),
+        .bDescriptorType = USB_DESCTYPE_STR
+    },
+    .unicode_string = {'G', 'i', 'g', 'a', 'D', 'e', 'v', 'i', 'c', 'e'}
+};
+
+/* USB product string */
+static const usb_desc_str product_string = {
+    .header =
+    {
+        .bLength         = USB_STRING_LEN(12U),
+        .bDescriptorType = USB_DESCTYPE_STR
+    },
+    .unicode_string = {'G', 'D', '3', '2', '-', 'C', 'D', 'C', '_', 'A', 'C', 'M'}
+};
+
+/* USBD serial string */
+static usb_desc_str serial_string = {
+    .header =
+    {
+        .bLength         = USB_STRING_LEN(12U),
+        .bDescriptorType = USB_DESCTYPE_STR
+    }
+};
+
+/* USB string descriptor set */
+void *const usbd_cdc_strings[] = {
+    [STR_IDX_LANGID]  = (uint8_t *)&usbd_language_id_desc,
+    [STR_IDX_MFC]     = (uint8_t *)&manufacturer_string,
+    [STR_IDX_PRODUCT] = (uint8_t *)&product_string,
+    [STR_IDX_SERIAL]  = (uint8_t *)&serial_string
+};
+
+usb_desc cdc_desc = {
+    .dev_desc    = (uint8_t *)&cdc_dev_desc,
+    .config_desc = (uint8_t *)&cdc_config_desc,
+    .strings     = usbd_cdc_strings
+};
+
+/* local function prototypes ('static') */
+static uint8_t cdc_acm_init(usb_dev *udev, uint8_t config_index);
+static uint8_t cdc_acm_deinit(usb_dev *udev, uint8_t config_index);
+static uint8_t cdc_acm_req(usb_dev *udev, usb_req *req);
+static uint8_t cdc_acm_ctlx_out(usb_dev *udev);
+static uint8_t cdc_acm_in(usb_dev *udev, uint8_t ep_num);
+static uint8_t cdc_acm_out(usb_dev *udev, uint8_t ep_num);
+
+/* USB CDC device class callbacks structure */
+usb_class_core cdc_class = {
+    .command   = NO_CMD,
+    .alter_set = 0U,
+
+    .init      = cdc_acm_init,
+    .deinit    = cdc_acm_deinit,
+    .req_proc  = cdc_acm_req,
+    .ctlx_out  = cdc_acm_ctlx_out,
+    .data_in   = cdc_acm_in,
+    .data_out  = cdc_acm_out
+};
+
+/*!
+    \brief      check CDC ACM is ready for data transfer
+    \param[in]  udev: pointer to USB device instance
+    \param[out] none
+    \retval     0 if CDC is ready, 1 else 
+*/
+uint8_t cdc_acm_check_ready(usb_dev *udev)
+{
+    if(NULL != udev->dev.class_data[CDC_COM_INTERFACE]) {
+        usb_cdc_handler *cdc = (usb_cdc_handler *)udev->dev.class_data[CDC_COM_INTERFACE];
+
+        if((1U == cdc->packet_receive) && (1U == cdc->packet_sent)) {
+            return 0U;
+        }
+    }
+
+    return 1U;
+}
+
+/*!
+    \brief      send CDC ACM data
+    \param[in]  udev: pointer to USB device instance
+    \param[out] none
+    \retval     none
+*/
+void cdc_acm_data_send(usb_dev *udev)
+{
+    usb_cdc_handler *cdc = (usb_cdc_handler *)udev->dev.class_data[CDC_COM_INTERFACE];
+
+    if(0U != cdc->receive_length) {
+        cdc->packet_sent = 0U;
+
+        usbd_ep_send(udev, CDC_DATA_IN_EP, (uint8_t *)(cdc->data), cdc->receive_length);
+
+        cdc->receive_length = 0U;
+    }
+}
+
+/*!
+    \brief      receive CDC ACM data
+    \param[in]  udev: pointer to USB device instance
+    \param[out] none
+    \retval     none
+*/
+void cdc_acm_data_receive(usb_dev *udev)
+{
+    usb_cdc_handler *cdc = (usb_cdc_handler *)udev->dev.class_data[CDC_COM_INTERFACE];
+
+    cdc->packet_receive = 0U;
+    cdc->packet_sent = 0U;
+
+    usbd_ep_recev(udev, CDC_DATA_OUT_EP, (uint8_t *)(cdc->data), USB_CDC_DATA_PACKET_SIZE);
+}
+
+/*!
+    \brief      initialize the CDC ACM device
+    \param[in]  udev: pointer to USB device instance
+    \param[in]  config_index: configuration index
+    \param[out] none
+    \retval     USB device operation status
+*/
+static uint8_t cdc_acm_init(usb_dev *udev, uint8_t config_index)
+{
+    static usb_cdc_handler cdc_handler;
+
+    /* initialize the data TX endpoint */
+    usbd_ep_setup(udev, &(cdc_config_desc.cdc_in_endpoint));
+
+    /* initialize the data RX endpoint */
+    usbd_ep_setup(udev, &(cdc_config_desc.cdc_out_endpoint));
+
+    /* initialize the command TX endpoint */
+    usbd_ep_setup(udev, &(cdc_config_desc.cdc_cmd_endpoint));
+
+    /* initialize CDC handler structure */
+    cdc_handler.packet_receive = 1U;
+    cdc_handler.packet_sent = 1U;
+    cdc_handler.receive_length = 0U;
+
+    cdc_handler.line_coding = (acm_line) {
+        .dwDTERate   = 115200U,
+        .bCharFormat = 0U,
+        .bParityType = 0U,
+        .bDataBits   = 0x08U
+    };
+
+    udev->dev.class_data[CDC_COM_INTERFACE] = (void *)&cdc_handler;
+
+    return USBD_OK;
+}
+
+/*!
+    \brief      deinitialize the CDC ACM device
+    \param[in]  udev: pointer to USB device instance
+    \param[in]  config_index: configuration index
+    \param[out] none
+    \retval     USB device operation status
+*/
+static uint8_t cdc_acm_deinit(usb_dev *udev, uint8_t config_index)
+{
+    /* deinitialize the data TX/RX endpoint */
+    usbd_ep_clear(udev, CDC_DATA_IN_EP);
+    usbd_ep_clear(udev, CDC_DATA_OUT_EP);
+
+    /* deinitialize the command TX endpoint */
+    usbd_ep_clear(udev, CDC_CMD_EP);
+
+    return USBD_OK;
+}
+
+/*!
+    \brief      handle the CDC ACM class-specific requests
+    \param[in]  udev: pointer to USB device instance
+    \param[in]  req: device class-specific request
+    \param[out] none
+    \retval     USB device operation status
+*/
+static uint8_t cdc_acm_req(usb_dev *udev, usb_req *req)
+{
+    usb_cdc_handler *cdc = (usb_cdc_handler *)udev->dev.class_data[CDC_COM_INTERFACE];
+
+    usb_transc *transc = NULL;
+
+    switch(req->bRequest) {
+    case SEND_ENCAPSULATED_COMMAND:
+        /* no operation for this driver */
+        break;
+
+    case GET_ENCAPSULATED_RESPONSE:
+        /* no operation for this driver */
+        break;
+
+    case SET_COMM_FEATURE:
+        /* no operation for this driver */
+        break;
+
+    case GET_COMM_FEATURE:
+        /* no operation for this driver */
+        break;
+
+    case CLEAR_COMM_FEATURE:
+        /* no operation for this driver */
+        break;
+
+    case SET_LINE_CODING:
+        transc = &udev->dev.transc_out[0];
+
+        /* set the value of the current command to be processed */
+        udev->dev.class_core->alter_set = req->bRequest;
+
+        /* enable EP0 prepare to receive command data packet */
+        transc->remain_len = req->wLength;
+        transc->xfer_buf = cdc->cmd;
+        break;
+
+    case GET_LINE_CODING:
+        transc = &udev->dev.transc_in[0];
+
+        cdc->cmd[0] = (uint8_t)(cdc->line_coding.dwDTERate);
+        cdc->cmd[1] = (uint8_t)(cdc->line_coding.dwDTERate >> 8);
+        cdc->cmd[2] = (uint8_t)(cdc->line_coding.dwDTERate >> 16);
+        cdc->cmd[3] = (uint8_t)(cdc->line_coding.dwDTERate >> 24);
+        cdc->cmd[4] = cdc->line_coding.bCharFormat;
+        cdc->cmd[5] = cdc->line_coding.bParityType;
+        cdc->cmd[6] = cdc->line_coding.bDataBits;
+
+        transc->xfer_buf = cdc->cmd;
+        transc->remain_len = 7U;
+        break;
+
+    case SET_CONTROL_LINE_STATE:
+        /* no operation for this driver */
+        break;
+
+    case SEND_BREAK:
+        /* no operation for this driver */
+        break;
+
+    default:
+        break;
+    }
+
+    return USBD_OK;
+}
+
+/*!
+    \brief      command data received on control endpoint
+    \param[in]  udev: pointer to USB device instance
+    \param[out] none
+    \retval     USB device operation status
+*/
+static uint8_t cdc_acm_ctlx_out(usb_dev *udev)
+{
+    usb_cdc_handler *cdc = (usb_cdc_handler *)udev->dev.class_data[CDC_COM_INTERFACE];
+
+    if(NO_CMD != udev->dev.class_core->alter_set) {
+        /* process the command data */
+        cdc->line_coding.dwDTERate = (uint32_t)((uint32_t)cdc->cmd[0] | \
+                                                ((uint32_t)cdc->cmd[1] << 8) | \
+                                                ((uint32_t)cdc->cmd[2] << 16) | \
+                                                ((uint32_t)cdc->cmd[3] << 24));
+
+        cdc->line_coding.bCharFormat = cdc->cmd[4];
+        cdc->line_coding.bParityType = cdc->cmd[5];
+        cdc->line_coding.bDataBits = cdc->cmd[6];
+
+        udev->dev.class_core->alter_set = NO_CMD;
+    }
+
+    return USBD_OK;
+}
+
+/*!
+    \brief      handle CDC ACM data IN stage
+    \param[in]  udev: pointer to USB device instance
+    \param[in]  ep_num: endpoint identifier
+    \param[out] none
+    \retval     USB device operation status
+*/
+static uint8_t cdc_acm_in(usb_dev *udev, uint8_t ep_num)
+{
+    usb_transc *transc = &udev->dev.transc_in[EP_ID(ep_num)];
+
+    usb_cdc_handler *cdc = (usb_cdc_handler *)udev->dev.class_data[CDC_COM_INTERFACE];
+
+    if((0U == transc->xfer_len % transc->max_len) && (0U != transc->xfer_len)) {
+        usbd_ep_send(udev, ep_num, NULL, 0U);
+    } else {
+        cdc->packet_sent = 1U;
+    }
+
+    return USBD_OK;
+}
+
+/*!
+    \brief      handle CDC ACM data OUT stage
+    \param[in]  udev: pointer to USB device instance
+    \param[in]  ep_num: endpoint identifier
+    \param[out] none
+    \retval     USB device operation status
+*/
+static uint8_t cdc_acm_out(usb_dev *udev, uint8_t ep_num)
+{
+    usb_cdc_handler *cdc = (usb_cdc_handler *)udev->dev.class_data[CDC_COM_INTERFACE];
+
+    cdc->packet_receive = 1U;
+    cdc->receive_length = ((usb_core_driver *)udev)->dev.transc_out[ep_num].xfer_count;
+
+    return USBD_OK;
+}

+ 171 - 0
GD32F3x0/GD32F3x0_usbfs_library/device/class/dfu/Include/dfu_core.h

@@ -0,0 +1,171 @@
+/*!
+    \file    dfu_core.h
+    \brief   the header file of USB DFU device class core functions
+
+    \version 2025-01-01, V2.5.0, firmware for GD32F3x0
+*/
+
+/*
+    Copyright (c) 2025, GigaDevice Semiconductor Inc.
+
+    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 of the copyright holder 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 HOLDER 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.
+*/
+
+#ifndef DFU_CORE_H
+#define DFU_CORE_H
+
+#include "usbd_enum.h"
+
+/* DFU class code */
+#define USB_DFU_CLASS                 0xFEU
+
+/* DFU subclass code */
+#define USB_DFU_SUBCLASS_UPGRADE      0x01U
+
+/* DFU protocol code */
+#define USB_DFU_PROTOCL_RUNTIME       0x01U                     /*!< runtime interface protocol */
+#define USB_DFU_PROTOCL_DFU           0x02U                     /*!< DFU interface protocol */
+
+/* manifestation state */
+#define MANIFEST_COMPLETE             0x00U                     /*!< manifest complete state */
+#define MANIFEST_IN_PROGRESS          0x01U                     /*!< manifest in progress state */
+
+/* DFU attributes code */
+#define USB_DFU_CAN_DOWNLOAD          0x01U                     /*!< download attribute */
+#define USB_DFU_CAN_UPLOAD            0x02U                     /*!< upload attribute */
+#define USB_DFU_MANIFEST_TOLERANT     0x04U                     /*!< manifest tolerant attribute */
+#define USB_DFU_WILL_DETACH           0x08U                     /*!< detach attribute */
+
+/* special commands with download request */
+#define GET_COMMANDS                  0x00U                     /*!< get command request */
+#define SET_ADDRESS_POINTER           0x21U                     /*!< set address pointer request */
+#define ERASE                         0x41U                     /*!< erase request */
+
+/* memory operation command */
+#define CMD_ERASE                     0U                        /*!< erase command */
+#define CMD_WRITE                     1U                        /*!< write command */
+
+#define _BYTE1(x)         (uint8_t)((x) & 0xFFU)                /*!< addressing cycle 1st byte */
+#define _BYTE2(x)         (uint8_t)(((x) & 0xFF00U) >> 8)       /*!< addressing cycle 2nd byte */
+#define _BYTE3(x)         (uint8_t)(((x) & 0xFF0000U) >> 16)    /*!< addressing cycle 3rd byte */
+
+#define FLASH_ERASE_TIMEOUT           60U                       /*!< erase flash timeout */
+#define FLASH_WRITE_TIMEOUT           80U                       /*!< write flash timeout */
+
+/* bit detach capable = bit 3 in bmAttributes field */
+#define DFU_DETACH_MASK               (uint8_t)(0x10U)
+
+/* DFU descriptor type code */
+#define DFU_DESC_TYPE                 0x21U
+
+/* DFU device state defines */
+typedef enum {
+    STATE_APP_IDLE = 0x00U,                                     /*!< DFU APP idle state */
+    STATE_APP_DETACH,                                           /*!< DFU APP detach state */
+    STATE_DFU_IDLE,                                             /*!< idle state */
+    STATE_DFU_DNLOAD_SYNC,                                      /*!< download synchronous state */
+    STATE_DFU_DNBUSY,                                           /*!< download busy state */
+    STATE_DFU_DNLOAD_IDLE,                                      /*!< download idle state */
+    STATE_DFU_MANIFEST_SYNC,                                    /*!< manifest synchronous state */
+    STATE_DFU_MANIFEST,                                         /*!< manifest state */
+    STATE_DFU_MANIFEST_WAIT_RESET,                              /*!< manifest wait reset state */
+    STATE_DFU_UPLOAD_IDLE,                                      /*!< upload idle state */
+    STATE_DFU_ERROR                                             /*!< DFU error state */
+} dfu_state;
+
+/* DFU device status defines */
+typedef enum {
+    STATUS_OK = 0x00U,                                          /*!< no error status */
+    STATUS_ERR_TARGET,                                          /*!< trigger error status */
+    STATUS_ERR_FILE,                                            /*!< file error status */
+    STATUS_ERR_WRITE,                                           /*!< write error status */
+    STATUS_ERR_ERASE,                                           /*!< erase error status */
+    STATUS_ERR_CHECK_ERASED,                                    /*!< check erased error status */
+    STATUS_ERR_PROG,                                            /*!< program error status */
+    STATUS_ERR_VERIFY,                                          /*!< verify error status */
+    STATUS_ERR_ADDRESS,                                         /*!< address error status */
+    STATUS_ERR_NOTDONE,                                         /*!< not done error status */
+    STATUS_ERR_FIRMWARE,                                        /*!< firmware error status */
+    STATUS_ERR_VENDOR,                                          /*!< vendor error status */
+    STATUS_ERR_USBR,                                            /*!< USB reset error status */
+    STATUS_ERR_POR,                                             /*!< power error status */
+    STATUS_ERR_UNKNOWN,                                         /*!< unknown error status */
+    STATUS_ERR_STALLEDPKT                                       /*!< stalled pocket error status */
+} dfu_status;
+
+/* DFU class-specific requests */
+typedef enum {
+    DFU_DETACH = 0U,                                            /*!< detach request */
+    DFU_DNLOAD,                                                 /*!< download request */
+    DFU_UPLOAD,                                                 /*!< upload request */
+    DFU_GETSTATUS,                                              /*!< get status request */
+    DFU_CLRSTATUS,                                              /*!< clear status request */
+    DFU_GETSTATE,                                               /*!< get state request */
+    DFU_ABORT,                                                  /*!< abort request */
+    DFU_REQ_MAX                                                 /*!< maximum request */
+} dfu_requests;
+
+#pragma pack(1)
+
+/* USB DFU function descriptor structure */
+typedef struct {
+    usb_desc_header header;               /*!< descriptor header, including type and size */
+    uint8_t bmAttributes;                 /*!< DFU attributes */
+    uint16_t wDetachTimeOut;              /*!< time, in milliseconds, that the device will wait after receipt of the DFU_DETACH request. */
+    uint16_t wTransferSize;               /*!< maximum number of bytes that the device can accept per control-write transaction */
+    uint16_t bcdDFUVersion;               /*!< numeric expression identifying the version of the DFU Specification release. */
+} usb_desc_dfu_func;
+
+#pragma pack()
+
+/* USB configuration descriptor structure */
+typedef struct {
+    usb_desc_config config;              /*!< configuration descriptor */
+    usb_desc_itf dfu_itf;                /*!< DFU interface descriptor */
+    usb_desc_dfu_func dfu_func;          /*!< DFU function descriptor */
+} usb_dfu_desc_config_set;
+
+/* USB DFU handler structure */
+typedef struct {
+    uint8_t bStatus;                     /*!< DFU device current status */
+    uint8_t bwPollTimeout0;              /*!< DFU device polling timeout 0 */
+    uint8_t bwPollTimeout1;              /*!< DFU device polling timeout 1 */
+    uint8_t bwPollTimeout2;              /*!< DFU device polling timeout 2 */
+    uint8_t bState;                      /*!< DFU device current state */
+    uint8_t iString;                     /*!< DFU device string */
+
+    uint8_t manifest_state;              /*!< DFU device current manifest state */
+    uint32_t data_len;                   /*!< DFU device data transfer length */
+    uint16_t block_num;                  /*!< memory block number */
+    uint32_t base_addr;                  /*!< memory base address */
+
+    uint8_t buf[TRANSFER_SIZE];          /*!< data transfer buff */
+} usbd_dfu_handler;
+
+typedef void (*app_func)(void);
+
+extern usb_desc dfu_desc;
+extern usb_class_core dfu_class;
+
+#endif  /* DFU_CORE_H */

+ 80 - 0
GD32F3x0/GD32F3x0_usbfs_library/device/class/dfu/Include/dfu_mem.h

@@ -0,0 +1,80 @@
+/*!
+    \file    dfu_mem.h
+    \brief   USB DFU device media access layer header file
+
+    \version 2025-01-01, V2.5.0, firmware for GD32F3x0
+*/
+
+/*
+    Copyright (c) 2025, GigaDevice Semiconductor Inc.
+
+    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 of the copyright holder 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 HOLDER 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.
+*/
+
+#ifndef DFU_MEM_H
+#define DFU_MEM_H
+
+#include "usb_conf.h"
+
+#define _1ST_BYTE(x)              (uint8_t)((x) & 0xFFU)                /*!< addressing cycle 1st byte */
+#define _2ND_BYTE(x)              (uint8_t)(((x) & 0xFF00U) >> 8)       /*!< addressing cycle 2nd byte */
+#define _3RD_BYTE(x)              (uint8_t)(((x) & 0xFF0000U) >> 16)    /*!< addressing cycle 3rd byte */
+
+#define POLLING_TIMEOUT_SET(x)    buffer[0] = _1ST_BYTE(x); \
+                                  buffer[1] = _2ND_BYTE(x); \
+                                  buffer[2] = _3RD_BYTE(x);
+typedef struct _dfu_mem_prop {
+    const uint8_t *pstr_desc;     /*!< pointer to the string descriptor */
+
+    uint8_t (*mem_init)(void);
+    uint8_t (*mem_deinit)(void);
+    uint8_t (*mem_erase)(uint32_t addr);
+    uint8_t (*mem_write)(uint8_t *buf, uint32_t addr, uint32_t len);
+    uint8_t *(*mem_read)(uint8_t *buf, uint32_t addr, uint32_t len);
+    uint8_t (*mem_checkaddr)(uint32_t addr);
+
+    const uint32_t erase_timeout; /*!< erase memory timeout */
+    const uint32_t write_timeout; /*!< write memory timeout */
+} dfu_mem_prop;
+
+typedef enum {
+    MEM_OK = 0U,  /*!< memory operation succeed */
+    MEM_FAIL      /*!< memory operation fail */
+} mem_status;
+
+/* function declarations */
+/* initialize the memory media */
+uint8_t dfu_mem_init(void);
+/* deinitialize the memory media */
+uint8_t dfu_mem_deinit(void);
+/* erase a memory sector */
+uint8_t dfu_mem_erase(uint32_t addr);
+/* write data to sectors of memory */
+uint8_t dfu_mem_write(uint8_t *buf, uint32_t addr, uint32_t len);
+/* read data from sectors of memory */
+uint8_t *dfu_mem_read(uint8_t *buf, uint32_t addr, uint32_t len);
+/* get the status of a given memory and store in buffer */
+uint8_t dfu_mem_getstatus(uint32_t addr, uint8_t cmd, uint8_t *buffer);
+
+#endif /* DFU_MEM_H */

+ 668 - 0
GD32F3x0/GD32F3x0_usbfs_library/device/class/dfu/Source/dfu_core.c

@@ -0,0 +1,668 @@
+/*!
+    \file    dfu_core.c
+    \brief   USB DFU device class core functions
+
+    \version 2025-01-01, V2.5.0, firmware for GD32F3x0
+*/
+
+/*
+    Copyright (c) 2025, GigaDevice Semiconductor Inc.
+
+    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 of the copyright holder 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 HOLDER 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.
+*/
+
+#include "dfu_core.h"
+#include "dfu_mem.h"
+#include "drv_usb_hw.h"
+#include <string.h>
+
+#define USBD_VID                     0x28E9U
+#define USBD_PID                     0x0189U
+
+/* local function prototypes ('static') */
+static uint8_t dfu_init(usb_dev *udev, uint8_t config_index);
+static uint8_t dfu_deinit(usb_dev *udev, uint8_t config_index);
+static uint8_t dfu_req_handler(usb_dev *udev, usb_req *req);
+static uint8_t dfu_ctlx_in(usb_dev *udev);
+
+static void dfu_mode_leave(usb_dev *udev);
+static uint8_t dfu_getstatus_complete(usb_dev *udev);
+
+/* DFU requests management functions */
+static void dfu_detach(usb_dev *udev, usb_req *req);
+static void dfu_dnload(usb_dev *udev, usb_req *req);
+static void dfu_upload(usb_dev *udev, usb_req *req);
+static void dfu_getstatus(usb_dev *udev, usb_req *req);
+static void dfu_clrstatus(usb_dev *udev, usb_req *req);
+static void dfu_getstate(usb_dev *udev, usb_req *req);
+static void dfu_abort(usb_dev *udev, usb_req *req);
+static void string_to_unicode(uint8_t *str, uint16_t *pbuf);
+
+extern dfu_mem_prop dfu_flash_cb;
+
+static void (*dfu_request_process[])(usb_dev *udev, usb_req *req) = {
+    [DFU_DETACH]    = dfu_detach,
+    [DFU_DNLOAD]    = dfu_dnload,
+    [DFU_UPLOAD]    = dfu_upload,
+    [DFU_GETSTATUS] = dfu_getstatus,
+    [DFU_CLRSTATUS] = dfu_clrstatus,
+    [DFU_GETSTATE]  = dfu_getstate,
+    [DFU_ABORT]     = dfu_abort
+};
+
+/* note:it should use the c99 standard when compiling the below codes */
+/* USB standard device descriptor */
+const usb_desc_dev dfu_dev_desc = {
+    .header =
+    {
+        .bLength          = USB_DEV_DESC_LEN,
+        .bDescriptorType  = USB_DESCTYPE_DEV
+    },
+    .bcdUSB                = 0x0200U,
+    .bDeviceClass          = 0x00U,
+    .bDeviceSubClass       = 0x00U,
+    .bDeviceProtocol       = 0x00U,
+    .bMaxPacketSize0       = USB_FS_EP0_MAX_LEN,
+    .idVendor              = USBD_VID,
+    .idProduct             = USBD_PID,
+    .bcdDevice             = 0x0100U,
+    .iManufacturer         = STR_IDX_MFC,
+    .iProduct              = STR_IDX_PRODUCT,
+    .iSerialNumber         = STR_IDX_SERIAL,
+    .bNumberConfigurations = USBD_CFG_MAX_NUM
+};
+
+/* USB device configuration descriptor */
+const usb_dfu_desc_config_set dfu_config_desc = {
+    .config =
+    {
+        .header =
+        {
+            .bLength         = sizeof(usb_desc_config),
+            .bDescriptorType = USB_DESCTYPE_CONFIG
+        },
+        .wTotalLength         = sizeof(usb_dfu_desc_config_set),
+        .bNumInterfaces       = 0x01U,
+        .bConfigurationValue  = 0x01U,
+        .iConfiguration       = 0x00U,
+        .bmAttributes         = 0x80U,
+        .bMaxPower            = 0x32U
+    },
+
+    .dfu_itf =
+    {
+        .header =
+        {
+            .bLength         = sizeof(usb_desc_itf),
+            .bDescriptorType = USB_DESCTYPE_ITF
+        },
+        .bInterfaceNumber     = 0x00U,
+        .bAlternateSetting    = 0x00U,
+        .bNumEndpoints        = 0x00U,
+        .bInterfaceClass      = USB_DFU_CLASS,
+        .bInterfaceSubClass   = USB_DFU_SUBCLASS_UPGRADE,
+        .bInterfaceProtocol   = USB_DFU_PROTOCL_DFU,
+        .iInterface           = 0x5
+    },
+
+    .dfu_func =
+    {
+        .header =
+        {
+            .bLength          = sizeof(usb_desc_dfu_func),
+            .bDescriptorType  = DFU_DESC_TYPE
+        },
+        .bmAttributes         = USB_DFU_CAN_DOWNLOAD | USB_DFU_CAN_UPLOAD | USB_DFU_WILL_DETACH,
+        .wDetachTimeOut       = 0x00FFU,
+        .wTransferSize        = TRANSFER_SIZE,
+        .bcdDFUVersion        = 0x0110U
+    }
+};
+
+/* USB language ID descriptor */
+static const usb_desc_LANGID usbd_language_id_desc = {
+    .header =
+    {
+        .bLength          = sizeof(usb_desc_LANGID),
+        .bDescriptorType  = USB_DESCTYPE_STR
+    },
+    .wLANGID              = ENG_LANGID
+};
+
+/* USB manufacture string */
+static const usb_desc_str manufacturer_string = {
+    .header =
+    {
+        .bLength         = USB_STRING_LEN(10U),
+        .bDescriptorType = USB_DESCTYPE_STR
+    },
+    .unicode_string = {'G', 'i', 'g', 'a', 'D', 'e', 'v', 'i', 'c', 'e'}
+};
+
+/* USB product string */
+static const usb_desc_str product_string = {
+    .header =
+    {
+        .bLength         = USB_STRING_LEN(12U),
+        .bDescriptorType = USB_DESCTYPE_STR
+    },
+    .unicode_string = {'G', 'D', '3', '2', '-', 'U', 'S', 'B', '_', 'D', 'F', 'U'}
+};
+
+/* USB serial string */
+static usb_desc_str serial_string = {
+    .header =
+    {
+        .bLength         = USB_STRING_LEN(2U),
+        .bDescriptorType = USB_DESCTYPE_STR
+    }
+};
+
+/* USB configure string */
+static const usb_desc_str config_string = {
+    .header =
+    {
+        .bLength         = USB_STRING_LEN(15U),
+        .bDescriptorType = USB_DESCTYPE_STR
+    },
+    .unicode_string = {'G', 'D', '3', '2', ' ', 'U', 'S', 'B', ' ', 'C', 'O', 'N', 'F', 'I', 'G'}
+};
+
+/* alternate interface string */
+static usb_desc_str interface_string = {
+    .header =
+    {
+        .bLength         = USB_STRING_LEN(2U),
+        .bDescriptorType = USB_DESCTYPE_STR
+    }
+};
+
+void *const usbd_dfu_strings[] = {
+    [STR_IDX_LANGID]   = (uint8_t *)&usbd_language_id_desc,
+    [STR_IDX_MFC]      = (uint8_t *)&manufacturer_string,
+    [STR_IDX_PRODUCT]  = (uint8_t *)&product_string,
+    [STR_IDX_SERIAL]   = (uint8_t *)&serial_string,
+    [STR_IDX_CONFIG]   = (uint8_t *)&config_string,
+    [STR_IDX_ITF]      = (uint8_t *)&interface_string,
+};
+
+usb_desc dfu_desc = {
+    .dev_desc    = (uint8_t *)&dfu_dev_desc,
+    .config_desc = (uint8_t *)&dfu_config_desc,
+    .strings     = usbd_dfu_strings
+};
+
+usb_class_core dfu_class = {
+    .init            = dfu_init,
+    .deinit          = dfu_deinit,
+    .req_proc        = dfu_req_handler,
+    .ctlx_in         = dfu_ctlx_in
+};
+
+/*!
+    \brief      initialize the DFU device
+    \param[in]  udev: pointer to USB device instance
+    \param[in]  config_index: configuration index
+    \param[out] none
+    \retval     USB device operation status
+*/
+static uint8_t dfu_init(usb_dev *udev, uint8_t config_index)
+{
+    static usbd_dfu_handler dfu_handler;
+
+    /* unlock the internal flash */
+    dfu_mem_init();
+
+    memset((void *)&dfu_handler, 0U, sizeof(usbd_dfu_handler));
+
+    dfu_handler.manifest_state = MANIFEST_COMPLETE;
+    dfu_handler.bState = STATE_DFU_IDLE;
+    dfu_handler.bStatus = STATUS_OK;
+
+    udev->dev.class_data[USBD_DFU_INTERFACE] = (void *)&dfu_handler;
+
+    /* create interface string */
+    string_to_unicode((uint8_t *)dfu_flash_cb.pstr_desc, udev->dev.desc->strings[STR_IDX_ITF]);
+
+    return USBD_OK;
+}
+
+/*!
+    \brief      deinitialize the DFU device
+    \param[in]  udev: pointer to USB device instance
+    \param[in]  config_index: configuration index
+    \param[out] none
+    \retval     USB device operation status
+*/
+static uint8_t dfu_deinit(usb_dev *udev, uint8_t config_index)
+{
+    usbd_dfu_handler *dfu = (usbd_dfu_handler *)udev->dev.class_data[USBD_DFU_INTERFACE];
+
+    /* restore device default state */
+    memset(udev->dev.class_data[USBD_DFU_INTERFACE], 0U, sizeof(usbd_dfu_handler));
+
+    dfu->bState = STATE_DFU_IDLE;
+    dfu->bStatus = STATUS_OK;
+
+    /* deinit the memory */
+    dfu_mem_deinit();
+
+    return USBD_OK;
+}
+
+/*!
+    \brief      handle the DFU class-specific requests
+    \param[in]  udev: pointer to USB device instance
+    \param[in]  req: device class-specific request
+    \param[out] none
+    \retval     USB device operation status
+*/
+static uint8_t dfu_req_handler(usb_dev *udev, usb_req *req)
+{
+    if(req->bRequest < DFU_REQ_MAX) {
+        dfu_request_process[req->bRequest](udev, req);
+    } else {
+        return USBD_FAIL;
+    }
+
+    return USBD_OK;
+}
+
+/*!
+    \brief      handle data stage
+    \param[in]  udev: pointer to USB device instance
+    \param[out] none
+    \retval     USB device operation status
+*/
+static uint8_t dfu_ctlx_in(usb_dev *udev)
+{
+    dfu_getstatus_complete(udev);
+
+    return USBD_OK;
+}
+
+/*!
+    \brief      leave DFU mode and reset device to jump to user loaded code
+    \param[in]  udev: pointer to USB device instance
+    \param[out] none
+    \retval     none
+*/
+static void dfu_mode_leave(usb_dev *udev)
+{
+    usbd_dfu_handler *dfu = (usbd_dfu_handler *)udev->dev.class_data[USBD_DFU_INTERFACE];
+
+    dfu->manifest_state = MANIFEST_COMPLETE;
+
+    if(dfu_config_desc.dfu_func.bmAttributes & 0x04U) {
+        dfu->bState = STATE_DFU_MANIFEST_SYNC;
+    } else {
+        dfu->bState = STATE_DFU_MANIFEST_WAIT_RESET;
+
+        /* deinit the memory */
+        dfu_mem_deinit();
+
+        /* generate system reset to allow jumping to the user code */
+        NVIC_SystemReset();
+    }
+}
+
+/*!
+    \brief      handle data IN stage in control endpoint 0
+    \param[in]  udev: pointer to USB device instance
+    \param[out] none
+    \retval     USB device operation status
+  */
+static uint8_t dfu_getstatus_complete(usb_dev *udev)
+{
+    uint32_t addr;
+
+    usbd_dfu_handler *dfu = (usbd_dfu_handler *)udev->dev.class_data[USBD_DFU_INTERFACE];
+
+    if(STATE_DFU_DNBUSY == dfu->bState) {
+        /* decode the special command */
+        if(0U == dfu->block_num) {
+            if(1U == dfu->data_len) {
+                if(GET_COMMANDS == dfu->buf[0]) {
+                    /* no operation */
+                }
+            } else if(5U == dfu->data_len) {
+                if(SET_ADDRESS_POINTER == dfu->buf[0]) {
+                    /* set flash operation address */
+                    dfu->base_addr = *(uint32_t *)(dfu->buf + 1U);
+                } else if(ERASE == dfu->buf[0]) {
+                    dfu->base_addr = *(uint32_t *)(dfu->buf + 1U);
+
+                    dfu_mem_erase(dfu->base_addr);
+                } else {
+                    /* no operation */
+                }
+            } else {
+                /* no operation */
+            }
+        } else if(dfu->block_num > 1U) { /* regular download command */
+            /* decode the required address */
+            addr = (dfu->block_num - 2U) * TRANSFER_SIZE + dfu->base_addr;
+
+            dfu_mem_write(dfu->buf, addr, dfu->data_len);
+
+            dfu->block_num = 0U;
+        } else {
+            /* no operation */
+        }
+
+        dfu->data_len = 0U;
+
+        /* update the device state and poll timeout */
+        dfu->bState = STATE_DFU_DNLOAD_SYNC;
+
+        return USBD_OK;
+    } else if(STATE_DFU_MANIFEST == dfu->bState) { /* manifestation in progress */
+        /* start leaving DFU mode */
+        dfu_mode_leave(udev);
+    } else {
+        /* no operation */
+    }
+
+    return USBD_OK;
+}
+
+/*!
+    \brief      handle the DFU_DETACH request
+    \param[in]  udev: pointer to USB device instance
+    \param[in]  req: DFU class request
+    \param[out] none
+    \retval     none.
+*/
+static void dfu_detach(usb_dev *udev, usb_req *req)
+{
+    usbd_dfu_handler *dfu = (usbd_dfu_handler *)udev->dev.class_data[USBD_DFU_INTERFACE];
+
+    switch(dfu->bState) {
+    case STATE_DFU_IDLE:
+    case STATE_DFU_DNLOAD_SYNC:
+    case STATE_DFU_DNLOAD_IDLE:
+    case STATE_DFU_MANIFEST_SYNC:
+    case STATE_DFU_UPLOAD_IDLE:
+        dfu->bStatus = STATUS_OK;
+        dfu->bState = STATE_DFU_IDLE;
+        dfu->iString = 0U; /* iString */
+
+        dfu->block_num = 0U;
+        dfu->data_len = 0U;
+        break;
+
+    default:
+        break;
+    }
+
+    /* check the detach capability in the DFU functional descriptor */
+    if(dfu_config_desc.dfu_func.wDetachTimeOut & DFU_DETACH_MASK) {
+        usbd_disconnect(udev);
+
+        usbd_connect(udev);
+    } else {
+        /* wait for the period of time specified in detach request */
+        usb_mdelay(4U);
+    }
+}
+
+/*!
+    \brief      handle the DFU_DNLOAD request
+    \param[in]  udev: pointer to USB device instance
+    \param[in]  req: DFU class request
+    \param[out] none
+    \retval     none
+*/
+static void dfu_dnload(usb_dev *udev, usb_req *req)
+{
+    usb_transc *transc = &udev->dev.transc_out[0];
+    usbd_dfu_handler *dfu = (usbd_dfu_handler *)udev->dev.class_data[USBD_DFU_INTERFACE];
+
+    switch(dfu->bState) {
+    case STATE_DFU_IDLE:
+    case STATE_DFU_DNLOAD_IDLE:
+        if(req->wLength > 0U) {
+            /* update the global length and block number */
+            dfu->block_num = req->wValue;
+            dfu->data_len = req->wLength;
+
+            dfu->bState = STATE_DFU_DNLOAD_SYNC;
+
+            transc->remain_len = dfu->data_len;
+            transc->xfer_buf = dfu->buf;
+        } else {
+            dfu->manifest_state = MANIFEST_IN_PROGRESS;
+            dfu->bState = STATE_DFU_MANIFEST_SYNC;
+        }
+        break;
+
+    default:
+        break;
+    }
+}
+
+/*!
+    \brief      handles the DFU UPLOAD request.
+    \param[in]  udev: pointer to USB device instance
+    \param[in]  req: DFU class request
+    \param[out] none
+    \retval     none
+*/
+static void dfu_upload(usb_dev *udev, usb_req *req)
+{
+    uint8_t *phy_addr = NULL;
+    uint32_t addr = 0U;
+    usbd_dfu_handler *dfu = (usbd_dfu_handler *)udev->dev.class_data[USBD_DFU_INTERFACE];
+
+    usb_transc *transc = &udev->dev.transc_in[0];
+
+    if(req->wLength <= 0U) {
+        dfu->bState = STATE_DFU_IDLE;
+        return;
+    }
+
+    switch(dfu->bState) {
+    case STATE_DFU_IDLE:
+    case STATE_DFU_UPLOAD_IDLE:
+        /* update the global length and block number */
+        dfu->block_num = req->wValue;
+        dfu->data_len = req->wLength;
+
+        /* DFU get command */
+        if(0U == dfu->block_num) {
+            /* update the state machine */
+            dfu->bState = (dfu->data_len > 3U) ? STATE_DFU_IDLE : STATE_DFU_UPLOAD_IDLE;
+
+            /* store the values of all supported commands */
+            dfu->buf[0] = GET_COMMANDS;
+            dfu->buf[1] = SET_ADDRESS_POINTER;
+            dfu->buf[2] = ERASE;
+
+            /* send the status data over EP0 */
+            transc->xfer_buf = &(dfu->buf[0]);
+            transc->remain_len = 3U;
+        } else if(dfu->block_num > 1U) {
+            dfu->bState = STATE_DFU_UPLOAD_IDLE;
+
+            /* change is accelerated */
+            addr = (dfu->block_num - 2U) * TRANSFER_SIZE + dfu->base_addr;
+
+            /* return the physical address where data are stored */
+            phy_addr = dfu_mem_read(dfu->buf, addr, dfu->data_len);
+
+            /* send the status data over EP0 */
+            transc->xfer_buf = phy_addr;
+            transc->remain_len = dfu->data_len;
+        } else {
+            dfu->bState = STATUS_ERR_STALLEDPKT;
+        }
+        break;
+
+    default:
+        dfu->data_len = 0U;
+        dfu->block_num = 0U;
+        break;
+    }
+}
+
+/*!
+    \brief      handle the DFU_GETSTATUS request
+    \param[in]  udev: pointer to USB device instance
+    \param[in]  req: DFU class request
+    \param[out] none
+    \retval     none
+*/
+static void dfu_getstatus(usb_dev *udev, usb_req *req)
+{
+    usb_transc *transc = &udev->dev.transc_in[0];
+    usbd_dfu_handler *dfu = (usbd_dfu_handler *)udev->dev.class_data[USBD_DFU_INTERFACE];
+
+    switch(dfu->bState) {
+    case STATE_DFU_DNLOAD_SYNC:
+        if(0U != dfu->data_len) {
+            dfu->bState = STATE_DFU_DNBUSY;
+
+            if(0U == dfu->block_num) {
+                if(ERASE == dfu->buf[0]) {
+                    dfu_mem_getstatus(dfu->base_addr, CMD_ERASE, (uint8_t *)&dfu->bwPollTimeout0);
+                } else {
+                    dfu_mem_getstatus(dfu->base_addr, CMD_WRITE, (uint8_t *)&dfu->bwPollTimeout0);
+                }
+            }
+        } else {
+            dfu->bState = STATE_DFU_DNLOAD_IDLE;
+        }
+        break;
+
+    case STATE_DFU_MANIFEST_SYNC:
+        if(MANIFEST_IN_PROGRESS == dfu->manifest_state) {
+            dfu->bState = STATE_DFU_MANIFEST;
+            dfu->bwPollTimeout0 = 1U;
+        } else if((MANIFEST_COMPLETE == dfu->manifest_state) && \
+                  (dfu_config_desc.dfu_func.bmAttributes & 0x04U)) {
+            dfu->bState = STATE_DFU_IDLE;
+            dfu->bwPollTimeout0 = 0U;
+        } else {
+            /* no operation */
+        }
+        break;
+
+    default:
+        break;
+    }
+
+    /* send the status data of DFU interface to host over EP0 */
+    transc->xfer_buf = (uint8_t *) & (dfu->bStatus);
+    transc->remain_len = 6U;
+}
+
+/*!
+    \brief      handle the DFU_CLRSTATUS request
+    \param[in]  udev: pointer to USB device instance
+    \param[in]  req: DFU class request
+    \param[out] none
+    \retval     none
+*/
+static void dfu_clrstatus(usb_dev *udev, usb_req *req)
+{
+    usbd_dfu_handler *dfu = (usbd_dfu_handler *)udev->dev.class_data[USBD_DFU_INTERFACE];
+
+    if(STATE_DFU_ERROR == dfu->bState) {
+        dfu->bStatus = STATUS_OK;
+        dfu->bState = STATE_DFU_IDLE;
+    } else {
+        /* state error */
+        dfu->bStatus = STATUS_ERR_UNKNOWN;
+        dfu->bState = STATE_DFU_ERROR;
+    }
+
+    dfu->iString = 0U; /* iString: index = 0 */
+}
+
+/*!
+    \brief      handle the DFU_GETSTATE request
+    \param[in]  udev: pointer to USB device instance
+    \param[in]  req: DFU class request
+    \param[out] none
+    \retval     none
+*/
+static void dfu_getstate(usb_dev *udev, usb_req *req)
+{
+    usb_transc *transc = &udev->dev.transc_in[0];
+    usbd_dfu_handler *dfu = (usbd_dfu_handler *)udev->dev.class_data[USBD_DFU_INTERFACE];
+
+    /* send the current state of the DFU interface to host */
+    transc->xfer_buf = &(dfu->bState);
+    transc->remain_len = 1U;
+}
+
+/*!
+    \brief      handle the DFU_ABORT request
+    \param[in]  udev: pointer to USB device instance
+    \param[in]  req: DFU class request
+    \param[out] none
+    \retval     none
+*/
+static void dfu_abort(usb_dev *udev, usb_req *req)
+{
+    usbd_dfu_handler *dfu = (usbd_dfu_handler *)udev->dev.class_data[USBD_DFU_INTERFACE];
+
+    switch(dfu->bState) {
+    case STATE_DFU_IDLE:
+    case STATE_DFU_DNLOAD_SYNC:
+    case STATE_DFU_DNLOAD_IDLE:
+    case STATE_DFU_MANIFEST_SYNC:
+    case STATE_DFU_UPLOAD_IDLE:
+        dfu->bStatus = STATUS_OK;
+        dfu->bState = STATE_DFU_IDLE;
+        dfu->iString = 0U; /* iString: index = 0 */
+
+        dfu->block_num = 0U;
+        dfu->data_len = 0U;
+        break;
+
+    default:
+        break;
+    }
+}
+
+/*!
+    \brief      convert string value into unicode char
+    \param[in]  str: pointer to plain string
+    \param[in]  pbuf: buffer pointer to store unicode char
+    \param[out] none
+    \retval     none
+*/
+static void string_to_unicode(uint8_t *str, uint16_t *pbuf)
+{
+    uint8_t index = 0U;
+
+    if(NULL != str) {
+        pbuf[index++] = ((strlen((const char *)str) * 2U + 2U) & 0x00FFU) | ((USB_DESCTYPE_STR << 8) & 0xFF00U);
+
+        while('\0' != *str) {
+            pbuf[index++] = *str++;
+        }
+    }
+}

+ 238 - 0
GD32F3x0/GD32F3x0_usbfs_library/device/class/dfu/Source/dfu_mem.c

@@ -0,0 +1,238 @@
+/*!
+    \file    dfu_mem.c
+    \brief   USB DFU device media access layer functions
+
+    \version 2025-01-01, V2.5.0, firmware for GD32F3x0
+*/
+
+/*
+    Copyright (c) 2025, GigaDevice Semiconductor Inc.
+
+    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 of the copyright holder 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 HOLDER 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.
+*/
+
+#include "dfu_mem.h"
+#include "usbd_transc.h"
+
+extern usb_core_driver usb_dfu_dev;
+extern dfu_mem_prop dfu_flash_cb;
+
+extern struct {
+    uint8_t buf[TRANSFER_SIZE];
+    uint16_t data_len;
+    uint16_t block_num;
+    uint32_t base_addr;
+} prog;
+
+dfu_mem_prop *mem_tab[MAX_USED_MEMORY_MEDIA] = {
+    &dfu_flash_cb
+};
+
+/* The list of memory interface string descriptor pointers. This list
+   can be updated whenever a memory has to be added or removed */
+const uint8_t *USBD_DFU_StringDesc[MAX_USED_MEMORY_MEDIA] = {
+    (const uint8_t *)INTER_FLASH_IF_STR
+};
+
+static uint8_t dfu_mem_checkaddr(uint32_t addr);
+
+/*!
+    \brief      initialize the memory media
+    \param[in]  none
+    \param[out] none
+    \retval     MEM_OK
+*/
+uint8_t dfu_mem_init(void)
+{
+    uint32_t mem_index = 0U;
+
+    /* initialize all supported memory medias */
+    for(mem_index = 0U; mem_index < MAX_USED_MEMORY_MEDIA; mem_index++) {
+        /* check if the memory media exists */
+        if(NULL != mem_tab[mem_index]->mem_init) {
+            mem_tab[mem_index]->mem_init();
+        }
+    }
+
+    return MEM_OK;
+}
+
+/*!
+    \brief      deinitialize the memory media
+    \param[in]  none
+    \param[out] none
+    \retval     MEM_OK
+*/
+uint8_t dfu_mem_deinit(void)
+{
+    uint32_t mem_index = 0U;
+
+    /* deinitialize all supported memory medias */
+    for(mem_index = 0U; mem_index < MAX_USED_MEMORY_MEDIA; mem_index++) {
+        /* check if the memory media exists */
+        if(NULL != mem_tab[mem_index]->mem_deinit) {
+            mem_tab[mem_index]->mem_deinit();
+        }
+    }
+
+    return MEM_OK;
+}
+
+/*!
+    \brief      erase a memory sector
+    \param[in]  addr: memory sector address/code
+    \param[out] none
+    \retval     MEM_OK
+*/
+uint8_t dfu_mem_erase(uint32_t addr)
+{
+    uint32_t mem_index = dfu_mem_checkaddr(addr);
+
+    /* check if the address is in protected area */
+    if(IS_PROTECTED_AREA(addr)) {
+        return MEM_FAIL;
+    }
+
+    if(mem_index < MAX_USED_MEMORY_MEDIA) {
+        /* check if the operation is supported */
+        if(NULL != mem_tab[mem_index]->mem_erase) {
+            return mem_tab[mem_index]->mem_erase(addr);
+        } else {
+            return MEM_FAIL;
+        }
+    } else {
+        return MEM_FAIL;
+    }
+}
+
+/*!
+    \brief      write data to sectors of memory
+    \param[in]  buf: the data buffer to be write
+    \param[in]  addr: memory sector address/code
+    \param[in]  len: data length
+    \param[out] none
+    \retval     MEM_OK
+*/
+uint8_t dfu_mem_write(uint8_t *buf, uint32_t addr, uint32_t len)
+{
+    uint32_t mem_index = dfu_mem_checkaddr(addr);
+
+    /* check if the address is in protected area */
+    if(IS_PROTECTED_AREA(addr)) {
+        return MEM_FAIL;
+    }
+
+    if(OB_RDPT == (addr & MAL_MASK_OB)) {
+        option_byte_write(addr, buf);
+        NVIC_SystemReset();
+
+        return MEM_OK;
+    }
+
+    if(mem_index < MAX_USED_MEMORY_MEDIA) {
+        /* check if the operation is supported */
+        if(NULL != mem_tab[mem_index]->mem_write) {
+            return mem_tab[mem_index]->mem_write(buf, addr, len);
+        } else {
+            return MEM_FAIL;
+        }
+    } else {
+        return MEM_FAIL;
+    }
+}
+
+/*!
+    \brief      read data from sectors of memory
+    \param[in]  buf: the data buffer to be write
+    \param[in]  addr: memory sector address/code
+    \param[in]  len: data length
+    \param[out] none
+    \retval     pointer to buffer
+*/
+uint8_t *dfu_mem_read(uint8_t *buf, uint32_t addr, uint32_t len)
+{
+    uint32_t mem_index = 0U;
+
+    if(OB_RDPT != addr) {
+        mem_index = dfu_mem_checkaddr(addr);
+    }
+
+    if(mem_index < MAX_USED_MEMORY_MEDIA) {
+        /* check if the operation is supported */
+        if(NULL != mem_tab[mem_index]->mem_read) {
+            return mem_tab[mem_index]->mem_read(buf, addr, len);
+        } else {
+            return buf;
+        }
+    } else {
+        return buf;
+    }
+}
+
+/*!
+    \brief      get the status of a given memory and store in buffer
+    \param[in]  addr: memory sector address/code
+    \param[in]  cmd: 0 for erase and 1 for write
+    \param[in]  buffer: pointer to the buffer where the status data will be stored
+    \param[out] none
+    \retval     MEM_OK if all operations are OK, MEM_FAIL else
+*/
+uint8_t dfu_mem_getstatus(uint32_t addr, uint8_t cmd, uint8_t *buffer)
+{
+    uint32_t mem_index = dfu_mem_checkaddr(addr);
+
+    if(mem_index < MAX_USED_MEMORY_MEDIA) {
+        if(cmd & 0x01U) {
+            POLLING_TIMEOUT_SET(mem_tab[mem_index]->write_timeout);
+        } else {
+            POLLING_TIMEOUT_SET(mem_tab[mem_index]->erase_timeout);
+        }
+
+        return MEM_OK;
+    } else {
+        return MEM_FAIL;
+    }
+}
+
+/*!
+    \brief      check the address is supported
+    \param[in]  addr: memory sector address/code
+    \param[out] none
+    \retval     index of the addressed memory
+*/
+static uint8_t dfu_mem_checkaddr(uint32_t addr)
+{
+    uint8_t mem_index = 0U;
+
+    /* check with all supported memories */
+    for(mem_index = 0U; mem_index < MAX_USED_MEMORY_MEDIA; mem_index++) {
+        /* if the check address is supported, return the memory index */
+        if(MEM_OK == mem_tab[mem_index]->mem_checkaddr(addr)) {
+            return mem_index;
+        }
+    }
+
+    /* if there is no memory found, return MAX_USED_MEMORY_MEDIA */
+    return (MAX_USED_MEMORY_MEDIA);
+}

+ 66 - 0
GD32F3x0/GD32F3x0_usbfs_library/device/class/hid/Include/custom_hid_core.h

@@ -0,0 +1,66 @@
+/*!
+    \file    custom_hid_core.h
+    \brief   definitions for HID core
+
+    \version 2025-01-01, V2.5.0, firmware for GD32F3x0
+*/
+
+/*
+    Copyright (c) 2025, GigaDevice Semiconductor Inc.
+
+    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 of the copyright holder 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 HOLDER 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.
+*/
+
+#ifndef CUSTOM_HID_CORE_H
+#define CUSTOM_HID_CORE_H
+
+#include "usbd_enum.h"
+#include "usb_hid.h"
+
+#define DESC_LEN_REPORT             96U                           /*!< report descriptor length */
+#define DESC_LEN_CONFIG             41U                           /*!< configuration descriptor length */
+#define NO_CMD                      0xFFU                         /*!< no command */
+#define MAX_PERIPH_NUM              4U                            /*!< maximum peripheral number */
+
+typedef struct {
+    uint8_t data[2];                                              /*!< custom HID data packet buff */
+    uint8_t reportID;                                             /*!< custom HID report id */
+    uint8_t idlestate;                                            /*!< idle state */
+    uint8_t protocol;                                             /*!< HID protocol */
+} custom_hid_handler;
+
+typedef struct {
+    void (*periph_config[MAX_PERIPH_NUM])(void);
+} hid_fop_handler;
+
+extern usb_desc custom_hid_desc;
+extern usb_class_core usbd_custom_hid_cb;
+
+/* function declarations */
+/* register HID interface operation functions */
+uint8_t custom_hid_itfop_register(usb_dev *udev, hid_fop_handler *hid_fop);
+/* send custom HID report */
+uint8_t custom_hid_report_send(usb_dev *udev, uint8_t *report, uint32_t len);
+
+#endif /* CUSTOM_HID_CORE_H */

+ 67 - 0
GD32F3x0/GD32F3x0_usbfs_library/device/class/hid/Include/standard_hid_core.h

@@ -0,0 +1,67 @@
+/*!
+    \file    standard_hid_core.h
+    \brief   definitions for HID core
+
+    \version 2025-01-01, V2.5.0, firmware for GD32F3x0
+*/
+
+/*
+    Copyright (c) 2025, GigaDevice Semiconductor Inc.
+
+    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 of the copyright holder 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 HOLDER 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.
+*/
+
+#ifndef STANDARD_HID_CORE_H
+#define STANDARD_HID_CORE_H
+
+#include "usbd_enum.h"
+#include "usb_hid.h"
+
+#define USB_HID_CONFIG_DESC_LEN          0x22U                     /*!< HID device configuration descriptor length */
+#define USB_HID_REPORT_DESC_LEN          0x2EU                     /*!< HID device report descriptor length */
+
+#define NO_CMD                           0xFFU                     /*!< no command */
+
+typedef struct {
+    uint32_t protocol;                                             /*!< control request protocol */
+    uint32_t idle_state;                                           /*!< HID device idle state */
+    uint8_t data[HID_IN_PACKET];                                   /*!< data transfer buff */
+    __IO uint8_t prev_transfer_complete;                           /*!< previous transfer complete flag */
+} standard_hid_handler;
+
+typedef struct {
+    void (*hid_itf_config)(void);
+    void (*hid_itf_data_process)(usb_dev *udev);
+} hid_fop_handler;
+
+extern usb_desc hid_desc;
+extern usb_class_core usbd_hid_cb;
+
+/* function declarations */
+/* register HID interface operation functions */
+uint8_t hid_itfop_register(usb_dev *udev, hid_fop_handler *hid_fop);
+/* send keyboard report */
+uint8_t hid_report_send(usb_dev *udev, uint8_t *report, uint32_t len);
+
+#endif /* STANDARD_HID_CORE_H */

+ 478 - 0
GD32F3x0/GD32F3x0_usbfs_library/device/class/hid/Source/custom_hid_core.c

@@ -0,0 +1,478 @@
+/*!
+    \file    custom_hid_core.c
+    \brief   custom HID class driver
+
+    \version 2025-01-01, V2.5.0, firmware for GD32F3x0
+*/
+
+/*
+    Copyright (c) 2025, GigaDevice Semiconductor Inc.
+
+    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 of the copyright holder 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 HOLDER 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.
+*/
+
+#include "custom_hid_core.h"
+#include <string.h>
+
+#define USBD_VID                     0x28E9U
+#define USBD_PID                     0x028AU
+
+/* Note:it should use the C99 standard when compiling the below codes */
+/* USB standard device descriptor */
+const usb_desc_dev custom_hid_dev_desc = {
+    .header =
+    {
+        .bLength          = USB_DEV_DESC_LEN,
+        .bDescriptorType  = USB_DESCTYPE_DEV
+    },
+    .bcdUSB                = 0x0200U,
+    .bDeviceClass          = 0x00U,
+    .bDeviceSubClass       = 0x00U,
+    .bDeviceProtocol       = 0x00U,
+    .bMaxPacketSize0       = USB_FS_EP0_MAX_LEN,
+    .idVendor              = USBD_VID,
+    .idProduct             = USBD_PID,
+    .bcdDevice             = 0x0100U,
+    .iManufacturer         = STR_IDX_MFC,
+    .iProduct              = STR_IDX_PRODUCT,
+    .iSerialNumber         = STR_IDX_SERIAL,
+    .bNumberConfigurations = USBD_CFG_MAX_NUM
+};
+
+/* USB device configuration descriptor */
+const usb_hid_desc_config_set custom_hid_config_desc = {
+    .config =
+    {
+        .header =
+        {
+            .bLength         = sizeof(usb_desc_config),
+            .bDescriptorType = USB_DESCTYPE_CONFIG
+        },
+        .wTotalLength         = DESC_LEN_CONFIG,
+        .bNumInterfaces       = 0x01U,
+        .bConfigurationValue  = 0x01U,
+        .iConfiguration       = 0x00U,
+        .bmAttributes         = 0x80U,
+        .bMaxPower            = 0x32U
+    },
+
+    .hid_itf =
+    {
+        .header =
+        {
+            .bLength         = sizeof(usb_desc_itf),
+            .bDescriptorType = USB_DESCTYPE_ITF
+        },
+        .bInterfaceNumber     = 0x00U,
+        .bAlternateSetting    = 0x00U,
+        .bNumEndpoints        = 0x02U,
+        .bInterfaceClass      = USB_HID_CLASS,
+        .bInterfaceSubClass   = 0x00U,
+        .bInterfaceProtocol   = 0x00U,
+        .iInterface           = 0x00U
+    },
+
+    .hid_vendor =
+    {
+        .header =
+        {
+            .bLength         = sizeof(usb_desc_hid),
+            .bDescriptorType = USB_DESCTYPE_HID
+        },
+        .bcdHID               = 0x0111U,
+        .bCountryCode         = 0x00U,
+        .bNumDescriptors      = 0x01U,
+        .bDescriptorType      = USB_DESCTYPE_REPORT,
+        .wDescriptorLength    = DESC_LEN_REPORT
+    },
+
+    .hid_epin =
+    {
+        .header =
+        {
+            .bLength         = sizeof(usb_desc_ep),
+            .bDescriptorType = USB_DESCTYPE_EP
+        },
+        .bEndpointAddress     = CUSTOMHID_IN_EP,
+        .bmAttributes         = USB_EP_ATTR_INT,
+        .wMaxPacketSize       = CUSTOMHID_IN_PACKET,
+        .bInterval            = 0x20U
+    },
+
+    .hid_epout =
+    {
+        .header =
+        {
+            .bLength         = sizeof(usb_desc_ep),
+            .bDescriptorType = USB_DESCTYPE_EP
+        },
+        .bEndpointAddress     = CUSTOMHID_OUT_EP,
+        .bmAttributes         = USB_EP_ATTR_INT,
+        .wMaxPacketSize       = CUSTOMHID_OUT_PACKET,
+        .bInterval            = 0x20U
+    }
+};
+
+/* USB language ID descriptor */
+static const usb_desc_LANGID usbd_language_id_desc = {
+    .header =
+    {
+        .bLength         = sizeof(usb_desc_LANGID),
+        .bDescriptorType = USB_DESCTYPE_STR
+    },
+    .wLANGID = ENG_LANGID
+};
+
+/* USB manufacture string */
+static const usb_desc_str manufacturer_string = {
+    .header =
+    {
+        .bLength         = USB_STRING_LEN(10U),
+        .bDescriptorType = USB_DESCTYPE_STR
+    },
+    .unicode_string = {'G', 'i', 'g', 'a', 'D', 'e', 'v', 'i', 'c', 'e'}
+};
+
+/* USB product string */
+static const usb_desc_str product_string = {
+    .header =
+    {
+        .bLength         = USB_STRING_LEN(14U),
+        .bDescriptorType = USB_DESCTYPE_STR
+    },
+    .unicode_string = {'G', 'D', '3', '2', '-', 'C', 'u', 's', 't', 'o', 'm', 'H', 'I', 'D'}
+};
+
+/* USBD serial string */
+static usb_desc_str serial_string = {
+    .header =
+    {
+        .bLength         = USB_STRING_LEN(12U),
+        .bDescriptorType = USB_DESCTYPE_STR
+    }
+};
+
+/* USB string descriptor set */
+void *const usbd_hid_strings[] = {
+    [STR_IDX_LANGID]  = (uint8_t *)&usbd_language_id_desc,
+    [STR_IDX_MFC]     = (uint8_t *)&manufacturer_string,
+    [STR_IDX_PRODUCT] = (uint8_t *)&product_string,
+    [STR_IDX_SERIAL]  = (uint8_t *)&serial_string
+};
+
+usb_desc custom_hid_desc = {
+    .dev_desc    = (uint8_t *)&custom_hid_dev_desc,
+    .config_desc = (uint8_t *)&custom_hid_config_desc,
+    .strings     = usbd_hid_strings
+};
+
+const uint8_t customhid_report_descriptor[DESC_LEN_REPORT] = {
+    0x06U, 0x00U, 0xFFU, /* USAGE_PAGE (Vendor Defined: 0xFF00) */
+    0x09U, 0x00U,        /* USAGE (Custom Device)               */
+    0xa1U, 0x01U,        /* COLLECTION (Application)            */
+
+    /* led 1 */
+    0x85U, 0x11U,     /* REPORT_ID (0x11)          */
+    0x09U, 0x01U,     /* USAGE (LED 1)             */
+    0x15U, 0x00U,     /* LOGICAL_MINIMUM (0)       */
+    0x25U, 0x01U,     /* LOGICAL_MAXIMUM (1)       */
+    0x75U, 0x08U,     /* REPORT_SIZE (8)           */
+    0x95U, 0x01U,     /* REPORT_COUNT (1)          */
+    0x91U, 0x82U,     /* OUTPUT (Data,Var,Abs,Vol) */
+
+    /* led 2 */
+    0x85U, 0x12U,     /* REPORT_ID (0x12)          */
+    0x09U, 0x02U,     /* USAGE (LED 2)             */
+    0x15U, 0x00U,     /* LOGICAL_MINIMUM (0)       */
+    0x25U, 0x01U,     /* LOGICAL_MAXIMUM (1)       */
+    0x75U, 0x08U,     /* REPORT_SIZE (8)           */
+    0x95U, 0x01U,     /* REPORT_COUNT (1)          */
+    0x91U, 0x82U,     /* OUTPUT (Data,Var,Abs,Vol) */
+
+    /* led 3 */
+    0x85U, 0x13U,     /* REPORT_ID (0x13)          */
+    0x09U, 0x03U,     /* USAGE (LED 3)             */
+    0x15U, 0x00U,     /* LOGICAL_MINIMUM (0)       */
+    0x25U, 0x01U,     /* LOGICAL_MAXIMUM (1)       */
+    0x75U, 0x08U,     /* REPORT_SIZE (8)           */
+    0x95U, 0x01U,     /* REPORT_COUNT (1)          */
+    0x91U, 0x82U,     /* OUTPUT (Data,Var,Abs,Vol) */
+
+    /* led 4 */
+    0x85U, 0x14U,     /* REPORT_ID (0x14)          */
+    0x09U, 0x04U,     /* USAGE (LED 4)             */
+    0x15U, 0x00U,     /* LOGICAL_MINIMUM (0)       */
+    0x25U, 0x01U,     /* LOGICAL_MAXIMUM (1)       */
+    0x75U, 0x08U,     /* REPORT_SIZE (8)           */
+    0x95U, 0x01U,     /* REPORT_COUNT (1)          */
+    0x91U, 0x82U,     /* OUTPUT (Data,Var,Abs,Vol) */
+
+    /* wakeup key */
+    0x85U, 0x15U,     /* REPORT_ID (0x15)          */
+    0x09U, 0x05U,     /* USAGE (Push Button)       */
+    0x15U, 0x00U,     /* LOGICAL_MINIMUM (0)       */
+    0x25U, 0x01U,     /* LOGICAL_MAXIMUM (1)       */
+    0x75U, 0x01U,     /* REPORT_SIZE (1)           */
+    0x81U, 0x02U,     /* INPUT (Data,Var,Abs,Vol)  */
+
+    0x75U, 0x07U,     /* REPORT_SIZE (7)           */
+    0x81U, 0x03U,     /* INPUT (Cnst,Var,Abs,Vol)  */
+
+    /* tamper key */
+    0x85U, 0x16U,     /* REPORT_ID (0x16)          */
+    0x09U, 0x06U,     /* USAGE (Push Button)       */
+    0x15U, 0x00U,     /* LOGICAL_MINIMUM (0)       */
+    0x25U, 0x01U,     /* LOGICAL_MAXIMUM (1)       */
+    0x75U, 0x01U,     /* REPORT_SIZE (1)           */
+    0x81U, 0x02U,     /* INPUT (Data,Var,Abs,Vol)  */
+
+    0x75U, 0x07U,     /* REPORT_SIZE (7)           */
+    0x81U, 0x03U,     /* INPUT (Cnst,Var,Abs,Vol)  */
+
+    0xc0U             /* END_COLLECTION            */
+};
+
+/* local function prototypes ('static') */
+static uint8_t custom_hid_init(usb_dev *udev, uint8_t config_index);
+static uint8_t custom_hid_deinit(usb_dev *udev, uint8_t config_index);
+static uint8_t custom_hid_req_handler(usb_dev *udev, usb_req *req);
+
+static uint8_t custom_hid_data_in(usb_dev *udev, uint8_t ep_num);
+static uint8_t custom_hid_data_out(usb_dev *udev, uint8_t ep_num);
+
+usb_class_core usbd_custom_hid_cb = {
+    .command   = NO_CMD,
+    .alter_set = 0U,
+
+    .init      = custom_hid_init,
+    .deinit    = custom_hid_deinit,
+
+    .req_proc  = custom_hid_req_handler,
+
+    .data_in   = custom_hid_data_in,
+    .data_out  = custom_hid_data_out
+};
+
+/*!
+    \brief      register HID interface operation functions
+    \param[in]  udev: pointer to USB device instance
+    \param[in]  hid_fop: HID operation functions structure
+    \param[out] none
+    \retval     USB device operation status
+*/
+uint8_t custom_hid_itfop_register(usb_dev *udev, hid_fop_handler *hid_fop)
+{
+    if(NULL != hid_fop) {
+        udev->dev.user_data = hid_fop;
+
+        return USBD_OK;
+    }
+
+    return USBD_FAIL;
+}
+
+/*!
+    \brief      send custom HID report
+    \param[in]  udev: pointer to USB device instance
+    \param[in]  report: pointer to HID report
+    \param[in]  len: data length
+    \param[out] none
+    \retval     USB device operation status
+*/
+uint8_t custom_hid_report_send(usb_dev *udev, uint8_t *report, uint32_t len)
+{
+    usbd_ep_send(udev, CUSTOMHID_IN_EP, report, len);
+
+    return USBD_OK;
+}
+
+/*!
+    \brief      initialize the HID device
+    \param[in]  udev: pointer to USB device instance
+    \param[in]  config_index: configuration index
+    \param[out] none
+    \retval     USB device operation status
+*/
+static uint8_t custom_hid_init(usb_dev *udev, uint8_t config_index)
+{
+    static custom_hid_handler hid_handler;
+
+    memset((void *)&hid_handler, 0U, sizeof(custom_hid_handler));
+
+    /* initialize the data TX endpoint */
+    usbd_ep_setup(udev, &(custom_hid_config_desc.hid_epin));
+
+    /* initialize the data RX endpoint */
+    usbd_ep_setup(udev, &(custom_hid_config_desc.hid_epout));
+
+    /* prepare receive data */
+    usbd_ep_recev(udev, CUSTOMHID_OUT_EP, hid_handler.data, 2U);
+
+    udev->dev.class_data[CUSTOM_HID_INTERFACE] = (void *)&hid_handler;
+
+    if(NULL != udev->dev.user_data) {
+        for(uint8_t i = 0U; i < MAX_PERIPH_NUM; i++) {
+            if(NULL != ((hid_fop_handler *)udev->dev.user_data)->periph_config[i]) {
+                ((hid_fop_handler *)udev->dev.user_data)->periph_config[i]();
+            }
+        }
+    }
+
+    return USBD_OK;
+}
+
+/*!
+    \brief      deinitialize the HID device
+    \param[in]  udev: pointer to USB device instance
+    \param[in]  config_index: configuration index
+    \param[out] none
+    \retval     USB device operation status
+*/
+static uint8_t custom_hid_deinit(usb_dev *udev, uint8_t config_index)
+{
+    /* deinitialize HID endpoints */
+    usbd_ep_clear(udev, CUSTOMHID_IN_EP);
+    usbd_ep_clear(udev, CUSTOMHID_OUT_EP);
+
+    return USBD_OK;
+}
+
+/*!
+    \brief      handle the HID class-specific requests
+    \param[in]  udev: pointer to USB device instance
+    \param[in]  req: device class-specific request
+    \param[out] none
+    \retval     USB device operation status
+*/
+static uint8_t custom_hid_req_handler(usb_dev *udev, usb_req *req)
+{
+    usb_transc *transc = &udev->dev.transc_in[0];
+
+    custom_hid_handler *hid = (custom_hid_handler *)udev->dev.class_data[CUSTOM_HID_INTERFACE];
+
+    switch(req->bRequest) {
+    case GET_REPORT:
+        break;
+
+    case GET_IDLE:
+        transc->xfer_buf = (uint8_t *)&hid->idlestate;
+        transc->remain_len = 1U;
+        break;
+
+    case GET_PROTOCOL:
+        transc->xfer_buf = (uint8_t *)&hid->protocol;
+        transc->remain_len = 1U;
+        break;
+
+    case SET_REPORT:
+        hid->reportID = (uint8_t)(req->wValue);
+        break;
+
+    case SET_IDLE:
+        hid->idlestate = (uint8_t)(req->wValue >> 8);
+        break;
+
+    case SET_PROTOCOL:
+        hid->protocol = (uint8_t)(req->wValue);
+        break;
+
+    case USB_GET_DESCRIPTOR:
+        if(USB_DESCTYPE_REPORT == (req->wValue >> 8)) {
+            transc->remain_len = USB_MIN(DESC_LEN_REPORT, req->wLength);
+            transc->xfer_buf = (uint8_t *)customhid_report_descriptor;
+        }
+        break;
+
+    default:
+        return USBD_FAIL;
+    }
+
+    return USBD_OK;
+}
+
+/*!
+    \brief      handle custom HID data
+    \param[in]  udev: pointer to USB device instance
+    \param[in]  ep_num: endpoint identifier
+    \param[out] none
+    \retval     USB device operation status
+*/
+static uint8_t custom_hid_data_in(usb_dev *udev, uint8_t ep_num)
+{
+    return USBD_OK;
+}
+
+/*!
+    \brief      handle custom HID data
+    \param[in]  udev: pointer to USB device instance
+    \param[in]  ep_num: endpoint identifier
+    \param[out] none
+    \retval     USB device operation status
+*/
+static uint8_t custom_hid_data_out(usb_dev *udev, uint8_t ep_num)
+{
+    custom_hid_handler *hid = (custom_hid_handler *)udev->dev.class_data[CUSTOM_HID_INTERFACE];
+
+    /* light the LED */
+    switch(hid->data[0]) {
+    case 0x11U:
+        if(RESET != hid->data[1]) {
+            gd_eval_led_on(LED1);
+        } else {
+            gd_eval_led_off(LED1);
+        }
+        break;
+
+    case 0x12U:
+        if(RESET != hid->data[1]) {
+            gd_eval_led_on(LED2);
+        } else {
+            gd_eval_led_off(LED2);
+        }
+        break;
+
+    case 0x13U:
+        if(RESET != hid->data[1]) {
+            gd_eval_led_on(LED3);
+        } else {
+            gd_eval_led_off(LED3);
+        }
+        break;
+
+    case 0x14U:
+        if(RESET != hid->data[1]) {
+            gd_eval_led_on(LED4);
+        } else {
+            gd_eval_led_off(LED4);
+        }
+        break;
+
+    default:
+        break;
+    }
+
+    usbd_ep_recev(udev, CUSTOMHID_OUT_EP, hid->data, 2U);
+
+    return USBD_OK;
+}

+ 383 - 0
GD32F3x0/GD32F3x0_usbfs_library/device/class/hid/Source/standard_hid_core.c

@@ -0,0 +1,383 @@
+/*!
+    \file    standard_hid_core.c
+    \brief   HID class driver
+
+    \version 2025-01-01, V2.5.0, firmware for GD32F3x0
+*/
+
+/*
+    Copyright (c) 2025, GigaDevice Semiconductor Inc.
+
+    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 of the copyright holder 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 HOLDER 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.
+*/
+
+#include "standard_hid_core.h"
+#include <string.h>
+
+#define USBD_VID                     0x28e9U
+#define USBD_PID                     0x0380U
+
+/* Note:it should use the C99 standard when compiling the below codes */
+/* USB standard device descriptor */
+const usb_desc_dev hid_dev_desc = {
+    .header =
+    {
+        .bLength          = USB_DEV_DESC_LEN,
+        .bDescriptorType  = USB_DESCTYPE_DEV
+    },
+    .bcdUSB                = 0x0200U,
+    .bDeviceClass          = 0x00U,
+    .bDeviceSubClass       = 0x00U,
+    .bDeviceProtocol       = 0x00U,
+    .bMaxPacketSize0       = USB_FS_EP0_MAX_LEN,
+    .idVendor              = USBD_VID,
+    .idProduct             = USBD_PID,
+    .bcdDevice             = 0x0100U,
+    .iManufacturer         = STR_IDX_MFC,
+    .iProduct              = STR_IDX_PRODUCT,
+    .iSerialNumber         = STR_IDX_SERIAL,
+    .bNumberConfigurations = USBD_CFG_MAX_NUM
+};
+
+const usb_hid_desc_config_set hid_config_desc = {
+    .config =
+    {
+        .header =
+        {
+            .bLength         = sizeof(usb_desc_config),
+            .bDescriptorType = USB_DESCTYPE_CONFIG
+        },
+        .wTotalLength         = USB_HID_CONFIG_DESC_LEN,
+        .bNumInterfaces       = 0x01U,
+        .bConfigurationValue  = 0x01U,
+        .iConfiguration       = 0x00U,
+        .bmAttributes         = 0xA0U,
+        .bMaxPower            = 0x32U
+    },
+
+    .hid_itf =
+    {
+        .header =
+        {
+            .bLength         = sizeof(usb_desc_itf),
+            .bDescriptorType = USB_DESCTYPE_ITF
+        },
+        .bInterfaceNumber     = 0x00U,
+        .bAlternateSetting    = 0x00U,
+        .bNumEndpoints        = 0x01U,
+        .bInterfaceClass      = USB_HID_CLASS,
+        .bInterfaceSubClass   = USB_HID_SUBCLASS_BOOT_ITF,
+        .bInterfaceProtocol   = USB_HID_PROTOCOL_KEYBOARD,
+        .iInterface           = 0x00U
+    },
+
+    .hid_vendor =
+    {
+        .header =
+        {
+            .bLength         = sizeof(usb_desc_hid),
+            .bDescriptorType = USB_DESCTYPE_HID
+        },
+        .bcdHID               = 0x0111U,
+        .bCountryCode         = 0x00U,
+        .bNumDescriptors      = 0x01U,
+        .bDescriptorType      = USB_DESCTYPE_REPORT,
+        .wDescriptorLength    = USB_HID_REPORT_DESC_LEN
+    },
+
+    .hid_epin =
+    {
+        .header =
+        {
+            .bLength         = sizeof(usb_desc_ep),
+            .bDescriptorType = USB_DESCTYPE_EP
+        },
+        .bEndpointAddress     = HID_IN_EP,
+        .bmAttributes         = USB_EP_ATTR_INT,
+        .wMaxPacketSize       = HID_IN_PACKET,
+        .bInterval            = 0x10U
+    }
+};
+
+/* USB language ID Descriptor */
+static const  usb_desc_LANGID usbd_language_id_desc = {
+    .header =
+    {
+        .bLength         = sizeof(usb_desc_LANGID),
+        .bDescriptorType = USB_DESCTYPE_STR
+    },
+    .wLANGID              = ENG_LANGID
+};
+
+/* USB manufacture string */
+static const usb_desc_str manufacturer_string = {
+    .header =
+    {
+        .bLength         = USB_STRING_LEN(10U),
+        .bDescriptorType = USB_DESCTYPE_STR
+    },
+    .unicode_string = {'G', 'i', 'g', 'a', 'D', 'e', 'v', 'i', 'c', 'e'}
+};
+
+/* USB product string */
+static const usb_desc_str product_string = {
+    .header =
+    {
+        .bLength         = USB_STRING_LEN(17U),
+        .bDescriptorType = USB_DESCTYPE_STR
+    },
+    .unicode_string = {'G', 'D', '3', '2', '-', 'U', 'S', 'B', '_', 'K', 'e', 'y', 'b', 'o', 'a', 'r', 'd'}
+};
+
+/* USBD serial string */
+static usb_desc_str serial_string = {
+    .header =
+    {
+        .bLength         = USB_STRING_LEN(12U),
+        .bDescriptorType = USB_DESCTYPE_STR
+    }
+};
+
+void *const usbd_hid_strings[] = {
+    [STR_IDX_LANGID]  = (uint8_t *)&usbd_language_id_desc,
+    [STR_IDX_MFC]     = (uint8_t *)&manufacturer_string,
+    [STR_IDX_PRODUCT] = (uint8_t *)&product_string,
+    [STR_IDX_SERIAL]  = (uint8_t *)&serial_string
+};
+
+usb_desc hid_desc = {
+    .dev_desc    = (uint8_t *)&hid_dev_desc,
+    .config_desc = (uint8_t *)&hid_config_desc,
+    .strings     = usbd_hid_strings
+};
+
+const uint8_t hid_report_desc[USB_HID_REPORT_DESC_LEN] = {
+    0x05U, 0x01U,  /* USAGE_PAGE (Generic Desktop) */
+    0x09U, 0x06U,  /* USAGE (Keyboard) */
+    0xa1U, 0x01U,  /* COLLECTION (Application) */
+
+    0x05U, 0x07U,  /* USAGE_PAGE (Keyboard/Keypad) */
+    0x19U, 0xe0U,  /* USAGE_MINIMUM (Keyboard LeftControl) */
+    0x29U, 0xe7U,  /* USAGE_MAXIMUM (Keyboard Right GUI) */
+    0x15U, 0x00U,  /* LOGICAL_MINIMUM (0) */
+    0x25U, 0x01U,  /* LOGICAL_MAXIMUM (1) */
+    0x95U, 0x08U,  /* REPORT_COUNT (8) */
+    0x75U, 0x01U,  /* REPORT_SIZE (1) */
+    0x81U, 0x02U,  /* INPUT (Data,Var,Abs) */
+
+    0x95U, 0x01U,  /* REPORT_COUNT (1) */
+    0x75U, 0x08U,  /* REPORT_SIZE (8) */
+    0x81U, 0x03U,  /* INPUT (Cnst,Var,Abs) */
+
+    0x95U, 0x06U,  /* REPORT_COUNT (6) */
+    0x75U, 0x08U,  /* REPORT_SIZE (8) */
+    0x15U, 0x00U,  /* LOGICAL_MINIMUM (0) */
+    0x26U, 0xFFU, 0x00U,  /* LOGICAL_MAXIMUM (255) */
+    0x05U, 0x07U,  /* USAGE_PAGE (Keyboard/Keypad) */
+    0x19U, 0x00U,  /* USAGE_MINIMUM (Reserved (no event indicated)) */
+    0x29U, 0x65U,  /* USAGE_MAXIMUM (Keyboard Application) */
+    0x81U, 0x00U,  /* INPUT (Data,Ary,Abs) */
+
+    0xc0U          /* END_COLLECTION */
+};
+
+/* local function prototypes ('static') */
+static uint8_t hid_init(usb_dev *udev, uint8_t config_index);
+static uint8_t hid_deinit(usb_dev *udev, uint8_t config_index);
+static uint8_t hid_req(usb_dev *udev, usb_req *req);
+static uint8_t hid_data_in(usb_dev *udev, uint8_t ep_num);
+
+usb_class_core usbd_hid_cb = {
+    .command         = NO_CMD,
+    .alter_set       = 0U,
+
+    .init            = hid_init,
+    .deinit          = hid_deinit,
+    .req_proc        = hid_req,
+    .data_in         = hid_data_in
+};
+
+/*!
+    \brief      register HID interface operation functions
+    \param[in]  udev: pointer to USB device instance
+    \param[in]  hid_fop: HID operation function structure
+    \param[out] none
+    \retval     USB device operation status
+*/
+uint8_t hid_itfop_register(usb_dev *udev, hid_fop_handler *hid_fop)
+{
+    if(NULL != hid_fop) {
+        udev->dev.user_data = (void *)hid_fop;
+
+        return USBD_OK;
+    }
+
+    return USBD_FAIL;
+}
+
+/*!
+    \brief      send keyboard report
+    \param[in]  udev: pointer to USB device instance
+    \param[in]  report: pointer to HID report
+    \param[in]  len: data length
+    \param[out] none
+    \retval     USB device operation status
+*/
+uint8_t hid_report_send(usb_dev *udev, uint8_t *report, uint32_t len)
+{
+    standard_hid_handler *hid = (standard_hid_handler *)udev->dev.class_data[USBD_HID_INTERFACE];
+
+    hid->prev_transfer_complete = 0U;
+
+    usbd_ep_send(udev, HID_IN_EP, report, len);
+
+    return USBD_OK;
+}
+
+/*!
+    \brief      initialize the HID device
+    \param[in]  udev: pointer to USB device instance
+    \param[in]  config_index: configuration index
+    \param[out] none
+    \retval     USB device operation status
+*/
+static uint8_t hid_init(usb_dev *udev, uint8_t config_index)
+{
+    static standard_hid_handler hid_handler;
+
+    memset((void *)&hid_handler, 0U, sizeof(standard_hid_handler));
+
+    /* initialize the data TX endpoint */
+    usbd_ep_setup(udev, &(hid_config_desc.hid_epin));
+
+    hid_handler.prev_transfer_complete = 1U;
+
+    udev->dev.class_data[USBD_HID_INTERFACE] = (void *)&hid_handler;
+
+    if(NULL != udev->dev.user_data) {
+        ((hid_fop_handler *)udev->dev.user_data)->hid_itf_config();
+    }
+
+    return USBD_OK;
+}
+
+/*!
+    \brief      deinitialize the HID device
+    \param[in]  udev: pointer to USB device instance
+    \param[in]  config_index: configuration index
+    \param[out] none
+    \retval     USB device operation status
+*/
+static uint8_t hid_deinit(usb_dev *udev, uint8_t config_index)
+{
+    /* deinitialize HID endpoints */
+    usbd_ep_clear(udev, HID_IN_EP);
+
+    return USBD_OK;
+}
+
+/*!
+    \brief      handle the HID class-specific requests
+    \param[in]  udev: pointer to USB device instance
+    \param[in]  req: device class-specific request
+    \param[out] none
+    \retval     USB device operation status
+*/
+static uint8_t hid_req(usb_dev *udev, usb_req *req)
+{
+    usb_transc *transc = &udev->dev.transc_in[0];
+
+    standard_hid_handler *hid = (standard_hid_handler *)udev->dev.class_data[USBD_HID_INTERFACE];
+
+    switch(req->bRequest) {
+    case GET_REPORT:
+        /* no use for this driver */
+        break;
+
+    case GET_IDLE:
+        transc->xfer_buf = (uint8_t *)&hid->idle_state;
+
+        transc->remain_len = 1U;
+        break;
+
+    case GET_PROTOCOL:
+        transc->xfer_buf = (uint8_t *)&hid->protocol;
+
+        transc->remain_len = 1U;
+        break;
+
+    case SET_REPORT:
+        /* no use for this driver */
+        break;
+
+    case SET_IDLE:
+        hid->idle_state = (uint8_t)(req->wValue >> 8);
+        break;
+
+    case SET_PROTOCOL:
+        hid->protocol = (uint8_t)(req->wValue);
+        break;
+
+    case USB_GET_DESCRIPTOR:
+        if(USB_DESCTYPE_REPORT == (req->wValue >> 8)) {
+            transc->remain_len = USB_MIN(USB_HID_REPORT_DESC_LEN, req->wLength);
+            transc->xfer_buf = (uint8_t *)hid_report_desc;
+
+            return REQ_SUPP;
+        } else if(USB_DESCTYPE_HID == (req->wValue >> 8)) {
+            transc->remain_len = USB_MIN(9U, req->wLength);
+            transc->xfer_buf = (uint8_t *)(&(hid_config_desc.hid_vendor));
+        } else {
+            /* no operation */
+        }
+        break;
+
+    default:
+        break;
+    }
+
+    return USBD_OK;
+}
+
+/*!
+    \brief      handle data stage
+    \param[in]  udev: pointer to USB device instance
+    \param[in]  ep_num: endpoint identifier
+    \param[out] none
+    \retval     USB device operation status
+*/
+static uint8_t hid_data_in(usb_dev *udev, uint8_t ep_num)
+{
+    standard_hid_handler *hid = (standard_hid_handler *)udev->dev.class_data[USBD_HID_INTERFACE];
+
+    if(0U != hid->data[2]) {
+        hid->data[2] = 0x00U;
+
+        usbd_ep_send(udev, HID_IN_EP, hid->data, HID_IN_PACKET);
+    } else {
+        hid->prev_transfer_complete = 1U;
+    }
+
+    return USBD_OK;
+}

+ 91 - 0
GD32F3x0/GD32F3x0_usbfs_library/device/class/iap/Include/usb_iap_core.h

@@ -0,0 +1,91 @@
+/*!
+    \file    usb_iap_core.h
+    \brief   the header file of IAP driver
+
+    \version 2025-01-01, V2.5.0, firmware for GD32F3x0
+*/
+
+/*
+    Copyright (c) 2025, GigaDevice Semiconductor Inc.
+
+    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 of the copyright holder 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 HOLDER 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.
+*/
+
+#ifndef USB_IAP_CORE_H
+#define USB_IAP_CORE_H
+
+#include "usbd_enum.h"
+#include "usb_hid.h"
+
+#define USB_SERIAL_STRING_SIZE              0x06U                                  /*!< serial string size */
+#define USB_DESC_LEN_IAP_REPORT             35U                                    /*!< report descriptor length */
+#define USB_DESC_LEN_IAP_CONFIG_SET         41U                                    /*!< configuration descriptor length */
+
+/* special commands with download request */
+#define IAP_READ_OPTION_BYTE                0x01U                                  /*!< read option byte request */
+#define IAP_ERASE                           0x02U                                  /*!< erase request */
+#define IAP_DOWNLOAD                        0x03U                                  /*!< download request */
+#define IAP_LEAVE                           0x04U                                  /*!< leave request */
+#define IAP_GETBIN_ADDRESS                  0x05U                                  /*!< get bin address request */
+#define IAP_WRITE_OPTION_BYTE               0x06U                                  /*!< write option byte request */
+#define IAP_UPLOAD                          0x07U                                  /*!< upload request */
+#define IAP_CHECK_RDP                       0x08U                                  /*!< check rdp state request */
+
+#define OPERATION_SUCCESS                   0x02U                                  /*!< operation success status */
+#define OPERATION_FAIL                      0x5FU                                  /*!< operation fail status */
+#define LEAVE_FINISH                        0x04U                                  /*!< leave finish status */
+#define OB_WRITE_SUCCESS                    0x03U                                  /*!< OB write success status */
+#define IS_RDP_MODE                         0xBBU                                  /*!< MCU RDP status */
+#define IS_NORMAL_MODE                      0xA5U                                  /*!< MCU normal status */
+
+#define IAP_HOST_ID                         0x01U                                  /*!< IAP host ID */
+#define IAP_DEVICE_ID                       0x02U                                  /*!< IAP device ID */
+
+typedef struct {
+    uint8_t report_buf[IAP_OUT_PACKET + 1U];                                       /*!< report buff */
+    uint8_t option_byte[IAP_IN_PACKET];                                            /*!< option byte buff */
+
+    /* state machine variables */
+    uint8_t dev_status[IAP_IN_PACKET];                                             /*!< device status */
+    uint8_t bin_addr[IAP_IN_PACKET];                                               /*!< load bin address */
+    uint8_t reportID;                                                              /*!< report id */
+    uint8_t flag;                                                                  /*!< flag */
+    uint32_t protocol;                                                             /*!< control request protocol */
+    uint32_t idlestate;                                                            /*!< control request idle state */
+    uint16_t transfer_times;                                                       /*!< data transfer times */
+    uint16_t page_count;                                                           /*!< memory page count */
+    uint32_t file_length;                                                          /*!< file length*/
+    uint32_t base_address;                                                         /*!< loaded base address */
+} usbd_iap_handler;
+
+typedef void (*app_func)(void);
+
+extern usb_desc iap_desc;
+extern usb_class_core iap_class;
+
+/* function declarations */
+/* send IAP report */
+uint8_t iap_report_send(usb_dev *udev, uint8_t *report, uint32_t len);
+
+#endif /* USB_IAP_CORE_H */

+ 645 - 0
GD32F3x0/GD32F3x0_usbfs_library/device/class/iap/Source/usb_iap_core.c

@@ -0,0 +1,645 @@
+/*!
+    \file    usb_iap_core.c
+    \brief   IAP driver
+
+    \version 2025-01-01, V2.5.0, firmware for GD32F3x0
+*/
+
+/*
+    Copyright (c) 2025, GigaDevice Semiconductor Inc.
+
+    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 of the copyright holder 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 HOLDER 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.
+*/
+
+#include <string.h>
+#include "usb_iap_core.h"
+#include "flash_operation.h"
+
+#define USBD_VID                     0x28E9U
+#define USBD_PID                     0x0228U
+
+/* Note:it should use the C99 standard when compiling the below codes */
+/* USB standard device descriptor */
+const usb_desc_dev iap_dev_desc = {
+    .header =
+    {
+        .bLength          = USB_DEV_DESC_LEN,
+        .bDescriptorType  = USB_DESCTYPE_DEV
+    },
+    .bcdUSB                = 0x0200U,
+    .bDeviceClass          = 0x00U,
+    .bDeviceSubClass       = 0x00U,
+    .bDeviceProtocol       = 0x00U,
+    .bMaxPacketSize0       = USB_FS_EP0_MAX_LEN,
+    .idVendor              = USBD_VID,
+    .idProduct             = USBD_PID,
+    .bcdDevice             = 0x0100U,
+    .iManufacturer         = STR_IDX_MFC,
+    .iProduct              = STR_IDX_PRODUCT,
+    .iSerialNumber         = STR_IDX_SERIAL,
+    .bNumberConfigurations = USBD_CFG_MAX_NUM
+};
+
+const usb_hid_desc_config_set iap_config_desc = {
+    .config =
+    {
+        .header =
+        {
+            .bLength         = sizeof(usb_desc_config),
+            .bDescriptorType = USB_DESCTYPE_CONFIG
+        },
+        .wTotalLength         = USB_DESC_LEN_IAP_CONFIG_SET,
+        .bNumInterfaces       = 0x01U,
+        .bConfigurationValue  = 0x01U,
+        .iConfiguration       = 0x00U,
+        .bmAttributes         = 0x80U,
+        .bMaxPower            = 0x32U
+    },
+
+    .hid_itf =
+    {
+        .header =
+        {
+            .bLength         = sizeof(usb_desc_itf),
+            .bDescriptorType = USB_DESCTYPE_ITF
+        },
+        .bInterfaceNumber     = 0x00U,
+        .bAlternateSetting    = 0x00U,
+        .bNumEndpoints        = 0x02U,
+        .bInterfaceClass      = USB_HID_CLASS,
+        .bInterfaceSubClass   = 0x00U,
+        .bInterfaceProtocol   = 0x00U,
+        .iInterface           = 0x00U
+    },
+
+    .hid_vendor =
+    {
+        .header =
+        {
+            .bLength         = sizeof(usb_desc_hid),
+            .bDescriptorType = USB_DESCTYPE_HID
+        },
+        .bcdHID               = 0x0111U,
+        .bCountryCode         = 0x00U,
+        .bNumDescriptors      = 0x01U,
+        .bDescriptorType      = USB_DESCTYPE_REPORT,
+        .wDescriptorLength    = USB_DESC_LEN_IAP_REPORT
+    },
+
+    .hid_epin =
+    {
+        .header =
+        {
+            .bLength         = sizeof(usb_desc_ep),
+            .bDescriptorType = USB_DESCTYPE_EP
+        },
+        .bEndpointAddress     = IAP_IN_EP,
+        .bmAttributes         = USB_EP_ATTR_INT,
+        .wMaxPacketSize       = IAP_IN_PACKET,
+        .bInterval            = 0x01U
+    },
+
+    .hid_epout =
+    {
+        .header =
+        {
+            .bLength         = sizeof(usb_desc_ep),
+            .bDescriptorType = USB_DESCTYPE_EP
+        },
+        .bEndpointAddress     = IAP_OUT_EP,
+        .bmAttributes         = USB_EP_ATTR_INT,
+        .wMaxPacketSize       = IAP_OUT_PACKET,
+        .bInterval            = 0x01U
+    }
+};
+
+/* USB language ID Descriptor */
+static const usb_desc_LANGID usbd_language_id_desc = {
+    .header =
+    {
+        .bLength         = sizeof(usb_desc_LANGID),
+        .bDescriptorType = USB_DESCTYPE_STR
+    },
+    .wLANGID              = ENG_LANGID
+};
+
+/* USB manufacture string */
+static const usb_desc_str manufacturer_string = {
+    .header =
+    {
+        .bLength         = USB_STRING_LEN(10U),
+        .bDescriptorType = USB_DESCTYPE_STR
+    },
+    .unicode_string = {'G', 'i', 'g', 'a', 'D', 'e', 'v', 'i', 'c', 'e'}
+};
+
+/* USB product string */
+static const usb_desc_str product_string = {
+    .header =
+    {
+        .bLength         = USB_STRING_LEN(12U),
+        .bDescriptorType = USB_DESCTYPE_STR
+    },
+    .unicode_string = {'G', 'D', '3', '2', '-', 'U', 'S', 'B', '_', 'I', 'A', 'P'}
+};
+
+/* USB serial string */
+static usb_desc_str serial_string = {
+    .header =
+    {
+        .bLength         = USB_STRING_LEN(2U),
+        .bDescriptorType = USB_DESCTYPE_STR
+    }
+};
+
+void *const usbd_iap_strings[] = {
+    [STR_IDX_LANGID]  = (uint8_t *)&usbd_language_id_desc,
+    [STR_IDX_MFC]     = (uint8_t *)&manufacturer_string,
+    [STR_IDX_PRODUCT] = (uint8_t *)&product_string,
+    [STR_IDX_SERIAL]  = (uint8_t *)&serial_string
+};
+
+usb_desc iap_desc = {
+    .dev_desc    = (uint8_t *)&iap_dev_desc,
+    .config_desc = (uint8_t *)&iap_config_desc,
+    .strings     = usbd_iap_strings
+};
+
+/* local function prototypes ('static') */
+static uint8_t iap_init(usb_dev *udev, uint8_t config_index);
+static uint8_t iap_deinit(usb_dev *udev, uint8_t config_index);
+static uint8_t iap_req_handler(usb_dev *udev, usb_req *req);
+static uint8_t iap_data_out(usb_dev *udev, uint8_t ep_num);
+
+/* IAP requests management functions */
+static void iap_req_erase(usb_dev *udev);
+static void iap_req_download(usb_dev *udev);
+static void iap_req_read_optionbyte(usb_dev *udev);
+static void iap_req_write_optionbyte(usb_dev *udev);
+static void iap_req_leave(usb_dev *udev);
+static void iap_address_send(usb_dev *udev);
+static void iap_req_upload(usb_dev *udev);
+static void iap_check_rdp(usb_dev *udev);
+
+usb_class_core iap_class = {
+    .init            = iap_init,
+    .deinit          = iap_deinit,
+    .req_proc        = iap_req_handler,
+    .data_out        = iap_data_out
+};
+
+/* USB custom HID device report descriptor */
+const uint8_t iap_report_desc[USB_DESC_LEN_IAP_REPORT] = {
+    0x05U, 0x01U,     /* USAGE_PAGE (Generic Desktop) */
+    0x09U, 0x00U,     /* USAGE (Custom Device)        */
+    0xa1U, 0x01U,     /* COLLECTION (Application)     */
+
+    /* IAP command and data */
+    0x85U, 0x01U,     /* REPORT_ID (0x01)          */
+    0x09U, 0x01U,     /* USAGE (IAP command)       */
+    0x15U, 0x00U,     /* LOGICAL_MINIMUM (0)       */
+    0x25U, 0xffU,     /* LOGICAL_MAXIMUM (255)     */
+    0x75U, 0x08U,     /* REPORT_SIZE (8)           */
+    0x95U, REPORT_OUT_COUNT,
+    0x91U, 0x82U,     /* OUTPUT (Data,Var,Abs,Vol) */
+
+    /* device status and option byte */
+    0x85U, 0x02U,     /* REPORT_ID (0x02)               */
+    0x09U, 0x02U,     /* USAGE (Status and option byte) */
+    0x15U, 0x00U,     /* LOGICAL_MINIMUM (0)            */
+    0x25U, 0xffU,     /* LOGICAL_MAXIMUM (255)          */
+    0x75U, 0x08U,     /* REPORT_SIZE (8)                */
+    0x95U, REPORT_IN_COUNT,     /* REPORT_COUNT         */
+    0x81U, 0x82U,     /* INPUT (Data,Var,Abs,Vol)       */
+
+    0xc0U             /* END_COLLECTION            */
+};
+
+/*!
+    \brief      send IAP report
+    \param[in]  udev: pointer to USB device instance
+    \param[in]  report: pointer to HID report
+    \param[in]  len: data length
+    \param[out] none
+    \retval     USB device operation status
+*/
+uint8_t iap_report_send(usb_dev *udev, uint8_t *report, uint32_t len)
+{
+    usbd_ep_send(udev, IAP_IN_EP, report, len);
+
+    return USBD_OK;
+}
+
+/*!
+    \brief      initialize the IAP device
+    \param[in]  udev: pointer to USB device instance
+    \param[in]  config_index: configuration index
+    \param[out] none
+    \retval     USB device operation status
+*/
+static uint8_t iap_init(usb_dev *udev, uint8_t config_index)
+{
+    static usbd_iap_handler iap_handler;
+
+    /* initialize TX endpoint */
+    usbd_ep_setup(udev, &(iap_config_desc.hid_epin));
+
+    /* initialize RX endpoint */
+    usbd_ep_setup(udev, &(iap_config_desc.hid_epout));
+
+    memset((void *)&iap_handler, 0U, sizeof(usbd_iap_handler));
+
+    /* prepare receive data */
+    usbd_ep_recev(udev, IAP_OUT_EP, iap_handler.report_buf, IAP_OUT_PACKET);
+
+    iap_handler.base_address = APP_LOADED_ADDR;
+
+    udev->dev.class_data[USBD_IAP_INTERFACE] = (void *)&iap_handler;
+
+    return USBD_OK;
+}
+
+/*!
+    \brief      deinitialize the IAP device
+    \param[in]  udev: pointer to USB device instance
+    \param[in]  config_index: configuration index
+    \param[out] none
+    \retval     USB device operation status
+*/
+static uint8_t iap_deinit(usb_dev *udev, uint8_t config_index)
+{
+    /* deinitialize IAP endpoints */
+    usbd_ep_clear(udev, IAP_IN_EP);
+    usbd_ep_clear(udev, IAP_OUT_EP);
+
+    return USBD_OK;
+}
+
+/*!
+    \brief      handle the IAP class-specific requests
+    \param[in]  udev: pointer to USB device instance
+    \param[in]  req: device class-specific request
+    \param[out] none
+    \retval     USB device operation status
+*/
+static uint8_t iap_req_handler(usb_dev *udev, usb_req *req)
+{
+    usb_transc *transc = &udev->dev.transc_in[0];
+    usbd_iap_handler *iap = (usbd_iap_handler *)udev->dev.class_data[USBD_IAP_INTERFACE];
+
+    switch(req->bRequest) {
+    case GET_REPORT:
+        /* no use for this driver */
+        break;
+
+    case GET_IDLE:
+        transc->xfer_buf = (uint8_t *)&iap->idlestate;
+        transc->remain_len = 1U;
+        break;
+
+    case GET_PROTOCOL:
+        transc->xfer_buf = (uint8_t *)&iap->protocol;
+        transc->remain_len = 1U;
+        break;
+
+    case SET_REPORT:
+        iap->reportID = (uint8_t)(req->wValue);
+        break;
+
+    case SET_IDLE:
+        iap->idlestate = (uint8_t)(req->wValue >> 8);
+        break;
+
+    case SET_PROTOCOL:
+        iap->protocol = (uint8_t)(req->wValue);
+        break;
+
+    case USB_GET_DESCRIPTOR:
+        if(USB_DESCTYPE_REPORT == (req->wValue >> 8)) {
+            transc->remain_len = USB_MIN(USB_DESC_LEN_IAP_REPORT, req->wLength);
+            transc->xfer_buf = (uint8_t *)iap_report_desc;
+        }
+        break;
+
+    default:
+        return USBD_FAIL;
+    }
+
+    return USBD_OK;
+}
+
+/*!
+    \brief      handle data OUT stage
+    \param[in]  udev: pointer to USB device instance
+    \param[in]  ep_num: endpoint number
+    \param[out] none
+    \retval     USB device operation status
+*/
+static uint8_t iap_data_out(usb_dev *udev, uint8_t ep_num)
+{
+    usbd_iap_handler *iap = (usbd_iap_handler *)udev->dev.class_data[USBD_IAP_INTERFACE];
+
+    if(IAP_HOST_ID == iap->report_buf[0]) {
+        switch(iap->report_buf[1]) {
+        case IAP_DOWNLOAD:
+            iap_req_download(udev);
+            break;
+
+        case IAP_ERASE:
+            iap_req_erase(udev);
+            break;
+
+        case IAP_READ_OPTION_BYTE:
+            iap_req_read_optionbyte(udev);
+            break;
+
+        case IAP_LEAVE:
+            iap_req_leave(udev);
+            break;
+
+        case IAP_GETBIN_ADDRESS:
+            iap_address_send(udev);
+            break;
+
+        case IAP_WRITE_OPTION_BYTE:
+            iap_req_write_optionbyte(udev);
+            break;
+
+        case IAP_UPLOAD:
+            iap_req_upload(udev);
+            break;
+
+        case IAP_CHECK_RDP:
+            iap_check_rdp(udev);
+            break;
+
+        default:
+            break;
+        }
+    }
+
+    usbd_ep_recev(udev, IAP_OUT_EP, iap->report_buf, IAP_OUT_PACKET);
+
+    return USBD_OK;
+}
+
+/*!
+    \brief      handle the IAP_DOWNLOAD request
+    \param[in]  udev: pointer to USB device instance
+    \param[out] none
+    \retval     none
+*/
+static void iap_req_download(usb_dev *udev)
+{
+    usbd_iap_handler *iap = (usbd_iap_handler *)udev->dev.class_data[USBD_IAP_INTERFACE];
+
+    iap->dev_status[0] = IAP_DEVICE_ID;
+
+    /* get the target address to download */
+    iap->base_address  = iap->report_buf[2];
+    iap->base_address |= (uint32_t)iap->report_buf[3] << 8;
+    iap->base_address |= (uint32_t)iap->report_buf[4] << 16;
+    iap->base_address |= (uint32_t)iap->report_buf[5] << 24;
+
+    /* program the target address */
+    if(FMC_READY == iap_data_write(&iap->report_buf[6], iap->base_address, TRANSFER_SIZE)) {
+        iap->dev_status[1] = OPERATION_SUCCESS;
+    } else {
+        iap->dev_status[1] = OPERATION_FAIL;
+    }
+
+    iap_report_send(udev, iap->dev_status, IAP_IN_PACKET);
+}
+
+/*!
+    \brief      handle the IAP_WRITE_OPTION_BYTE request
+    \param[in]  udev: pointer to USB device instance
+    \param[out] none
+    \retval     none
+*/
+static void iap_req_write_optionbyte(usb_dev *udev)
+{
+    uint32_t option_byte_addr = 0U;
+    uint16_t option_byte_size = 0U;
+    usbd_iap_handler *iap = (usbd_iap_handler *)udev->dev.class_data[USBD_IAP_INTERFACE];
+
+    /* get option byte address address */
+    option_byte_addr  = iap->report_buf[2];
+    option_byte_addr |= (uint32_t)iap->report_buf[3] << 8;
+    option_byte_addr |= (uint32_t)iap->report_buf[4] << 16;
+    option_byte_addr |= (uint32_t)iap->report_buf[5] << 24;
+
+    /* get option byte address size */
+    if(OPT_BYTE_ADDR == option_byte_addr) {
+        option_byte_size = OPT_BYTE_SIZE;
+    }
+
+    iap->dev_status[0] = IAP_DEVICE_ID;
+    /* write option byte address data */
+    if(FMC_READY == option_byte_write(option_byte_addr, &iap->report_buf[6], option_byte_size)) {
+        iap->dev_status[1] = OB_WRITE_SUCCESS;
+    } else {
+        iap->dev_status[1] = OPERATION_FAIL;
+    }
+
+    iap_report_send(udev, iap->dev_status, IAP_IN_PACKET);
+}
+
+/*!
+    \brief      handle the IAP_ERASE request
+    \param[in]  udev: pointer to USB device instance
+    \param[out] none
+    \retval     none
+*/
+static void iap_req_erase(usb_dev *udev)
+{
+    uint32_t addr = 0U;
+    usbd_iap_handler *iap = (usbd_iap_handler *)udev->dev.class_data[USBD_IAP_INTERFACE];
+
+    /* get base address to erase */
+    iap->base_address  = iap->report_buf[2];
+    iap->base_address |= (uint32_t)iap->report_buf[3] << 8;
+    iap->base_address |= (uint32_t)iap->report_buf[4] << 16;
+    iap->base_address |= (uint32_t)iap->report_buf[5] << 24;
+
+    /* get file length */
+    iap->file_length = iap->report_buf[6];
+    iap->file_length |= (uint32_t)iap->report_buf[7] << 8;
+    iap->file_length |= (uint32_t)iap->report_buf[8] << 16;
+    iap->file_length |= (uint32_t)iap->report_buf[9] << 24;
+
+    /* check if the address is in protected area */
+    if(IS_PROTECTED_AREA(iap->base_address)) {
+        return;
+    }
+
+    addr = iap->base_address;
+    iap->dev_status[0] = IAP_DEVICE_ID;
+
+    /* unlock the flash program erase controller */
+    fmc_unlock();
+    if(FMC_READY == flash_erase(addr, iap->file_length)) {
+        iap->dev_status[1] = OPERATION_SUCCESS;
+    } else {
+        iap->dev_status[1] = OPERATION_FAIL;
+    }
+    fmc_lock();
+
+    usbd_ep_send(udev, IAP_IN_EP, iap->dev_status, IAP_IN_PACKET);
+}
+
+/*!
+    \brief      handle the IAP_READ_OPTION_BYTE request
+    \param[in]  udev: pointer to USB device instance
+    \param[out] none
+    \retval     none
+*/
+static void iap_req_read_optionbyte(usb_dev *udev)
+{
+    uint8_t i = 0U;
+    uint32_t option_size = 0U, temp = 0U, option_address = 0U;
+    usbd_iap_handler *iap = (usbd_iap_handler *)udev->dev.class_data[USBD_IAP_INTERFACE];
+
+    /* read option address address */
+    option_address = iap->report_buf[2] + (iap->report_buf[3] << 8) + (iap->report_buf[4] << 16) + (iap->report_buf[5] << 24);
+
+    iap->option_byte[0] = IAP_DEVICE_ID;
+    if(OPT_BYTE_ADDR == option_address) {
+        option_size = OPT_BYTE_SIZE;
+    }
+
+    /* read option address content */
+    for(i = 0U; i < (option_size / 4U); i++) {
+        temp =  *(uint32_t *)option_address;
+        iap->option_byte[4 * i + 5] = temp >> 24;
+        iap->option_byte[4 * i + 4] = temp >> 16;
+        iap->option_byte[4 * i + 3] = temp >> 8;
+        iap->option_byte[4 * i + 2] = temp;
+        option_address = option_address + 4U;
+    }
+    iap->option_byte[1] = OPERATION_SUCCESS;
+
+    iap_report_send(udev, iap->option_byte, IAP_IN_PACKET);
+}
+
+/*!
+    \brief      handle the IAP_LEAVE request
+    \param[in]  udev: pointer to USB device instance
+    \param[out] none
+    \retval     none
+*/
+static void iap_req_leave(usb_dev *udev)
+{
+    usbd_iap_handler *iap = (usbd_iap_handler *)udev->dev.class_data[USBD_IAP_INTERFACE];
+
+    /* get base address to jump */
+    iap->base_address  = iap->report_buf[2];
+    iap->base_address |= (uint32_t)iap->report_buf[3] << 8;
+    iap->base_address |= (uint32_t)iap->report_buf[4] << 16;
+    iap->base_address |= (uint32_t)iap->report_buf[5] << 24;
+
+    iap->dev_status[0] = IAP_DEVICE_ID;
+    iap->dev_status[1] = LEAVE_FINISH;
+
+    usbd_ep_send(udev, IAP_IN_EP, iap->dev_status, IAP_IN_PACKET);
+    usbd_disconnect(udev);
+
+    /* reset register */
+    register_reset();
+    /* jump to target */
+    jump_to_execute(iap->base_address);
+}
+
+/*!
+    \brief      handle the IAP_GETBIN_ADDRESS request
+    \param[in]  udev: pointer to USB device instance
+    \param[out] none
+    \retval     none
+*/
+static void iap_address_send(usb_dev *udev)
+{
+    usbd_iap_handler *iap = (usbd_iap_handler *)udev->dev.class_data[USBD_IAP_INTERFACE];
+
+    iap->bin_addr[0] = IAP_DEVICE_ID;
+    /* get app boundary address */
+    iap->bin_addr[1] = (uint8_t)(APP_LOADED_ADDR);
+    iap->bin_addr[2] = (uint8_t)(APP_LOADED_ADDR >> 8);
+    iap->bin_addr[3] = (uint8_t)(APP_LOADED_ADDR >> 16);
+    iap->bin_addr[4] = (uint8_t)(APP_LOADED_ADDR >> 24);
+
+    iap_report_send(udev, iap->bin_addr, IAP_IN_PACKET);
+}
+
+/*!
+    \brief      handle the IAP_UPLOAD request
+    \param[in]  udev: pointer to USB device instance
+    \param[out] none
+    \retval     none
+*/
+static void iap_req_upload(usb_dev *udev)
+{
+    uint16_t packet_valid_length = 0U, i= 0U;
+    uint32_t bin_flash_addr = APP_LOADED_ADDR;
+    usbd_iap_handler *iap = (usbd_iap_handler *)udev->dev.class_data[USBD_IAP_INTERFACE];
+
+    iap->bin_addr[0] = IAP_DEVICE_ID;
+    /* get target flash address */
+    bin_flash_addr  = iap->report_buf[2];
+    bin_flash_addr |= (uint32_t)iap->report_buf[3] << 8;
+    bin_flash_addr |= (uint32_t)iap->report_buf[4] << 16;
+    bin_flash_addr |= (uint32_t)iap->report_buf[5] << 24;
+    /* get current packet valid length */
+    packet_valid_length = iap->report_buf[6];
+    packet_valid_length |= iap->report_buf[7] << 8;
+    /* get target flash address content */
+    for(i = 0U; i < packet_valid_length; i++) {
+        iap->bin_addr[i + 1] = REG8(bin_flash_addr + i);
+    }
+
+    iap_report_send(udev, iap->bin_addr, IAP_IN_PACKET);
+}
+
+/*!
+    \brief      handle the IAP_CHECK_RDP request
+    \param[in]  udev: pointer to USB device instance
+    \param[out] none
+    \retval     none
+*/
+static void iap_check_rdp(usb_dev *udev)
+{
+    uint8_t mode = 0U;
+    usbd_iap_handler *iap = (usbd_iap_handler *)udev->dev.class_data[USBD_IAP_INTERFACE];
+
+    /* check whether the SPC bit of FMC module is normal state */
+    if(0xA5U != REG8(OPT_BYTE_ADDR)) {
+        mode = IS_RDP_MODE;
+    } else {
+        mode = IS_NORMAL_MODE;
+    }
+
+    iap->bin_addr[0] = IAP_DEVICE_ID;
+    iap->bin_addr[1] = mode;
+
+    iap_report_send(udev, iap->bin_addr, IAP_IN_PACKET);
+}

+ 100 - 0
GD32F3x0/GD32F3x0_usbfs_library/device/class/msc/Include/usbd_msc_bbb.h

@@ -0,0 +1,100 @@
+/*!
+    \file    usbd_msc_bbb.h
+    \brief   the header file of the usbd_msc_bbb.c file
+
+    \version 2025-01-01, V2.5.0, firmware for GD32F3x0
+*/
+
+/*
+    Copyright (c) 2025, GigaDevice Semiconductor Inc.
+
+    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 of the copyright holder 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 HOLDER 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.
+*/
+
+#ifndef USBD_MSC_BBB_H
+#define USBD_MSC_BBB_H
+
+#include "msc_bbb.h"
+#include "msc_scsi.h"
+#include "usbd_msc_scsi.h"
+
+/* MSC BBB state */
+enum msc_bbb_state {
+    BBB_IDLE = 0U,          /*!< idle state  */
+    BBB_DATA_OUT,           /*!< data OUT state */
+    BBB_DATA_IN,            /*!< data IN state */
+    BBB_LAST_DATA_IN,       /*!< last data IN state */
+    BBB_SEND_DATA           /*!< send immediate data state */
+};
+
+/* MSC BBB status */
+enum msc_bbb_status {
+    BBB_STATUS_NORMAL = 0U, /*!< normal status */
+    BBB_STATUS_RECOVERY,    /*!< recovery status*/
+    BBB_STATUS_ERROR        /*!< error status */
+};
+
+typedef struct {
+    uint8_t bbb_data[MSC_MEDIA_PACKET_SIZE];                                    /*!< MSC BBB data buff */
+
+    uint8_t max_lun;                                                            /*!< maximum LUN */
+
+    uint8_t bbb_state;                                                          /*!< BBB state */
+    uint8_t bbb_status;                                                         /*!< BBB status */
+
+    uint32_t bbb_datalen;                                                       /*!< BBB data length */
+
+    msc_bbb_cbw bbb_cbw;                                                        /*!< MSC BBB CBW structural */
+    msc_bbb_csw bbb_csw;                                                        /*!< MSC BBB CSW structural */
+
+    uint8_t scsi_sense_head;                                                    /*!< SCSI sense header */
+    uint8_t scsi_sense_tail;                                                    /*!< SCSI sense tail */
+
+    uint32_t scsi_blk_size[MEM_LUN_NUM];                                        /*!< SCSI block size */
+    uint32_t scsi_blk_nbr[MEM_LUN_NUM];                                         /*!< SCSI block number */
+
+    uint32_t scsi_blk_addr;                                                     /*!< SCSI block address */
+    uint32_t scsi_blk_len;                                                      /*!< SCSI block length */
+    uint32_t scsi_disk_pop;                                                     /*!< SCSI disk pop */
+
+    msc_scsi_sense scsi_sense[SENSE_LIST_DEEPTH];                               /*!< MSC SCSI sense structural buff */
+} usbd_msc_handler;
+
+/* function declarations */
+/* initialize the BBB process */
+void msc_bbb_init(usb_core_driver *udev);
+/* reset the BBB machine */
+void msc_bbb_reset(usb_core_driver *udev);
+/* deinitialize the BBB machine */
+void msc_bbb_deinit(usb_core_driver *udev);
+/* handle BBB data IN stage */
+void msc_bbb_data_in(usb_core_driver *udev, uint8_t ep_num);
+/* handle BBB data OUT stage */
+void msc_bbb_data_out(usb_core_driver *udev, uint8_t ep_num);
+/* send the CSW(command status wrapper) */
+void msc_bbb_csw_send(usb_core_driver *udev, uint8_t csw_status);
+/* complete the clear feature request */
+void msc_bbb_clrfeature(usb_core_driver *udev, uint8_t ep_num);
+
+#endif /* USBD_MSC_BBB_H */

+ 57 - 0
GD32F3x0/GD32F3x0_usbfs_library/device/class/msc/Include/usbd_msc_core.h

@@ -0,0 +1,57 @@
+/*!
+    \file    usbd_msc_core.h
+    \brief   the header file of USB MSC device class core functions
+
+    \version 2025-01-01, V2.5.0, firmware for GD32F3x0
+*/
+
+/*
+    Copyright (c) 2025, GigaDevice Semiconductor Inc.
+
+    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 of the copyright holder 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 HOLDER 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.
+*/
+
+#ifndef USBD_MSC_CORE_H
+#define USBD_MSC_CORE_H
+
+#include "usbd_core.h"
+#include "usb_msc.h"
+
+#define USB_MSC_CONFIG_DESC_SIZE          32U                                   /*!< MSC configuration descriptor size */
+
+#define MSC_EPIN_SIZE                     MSC_DATA_PACKET_SIZE                  /*!< MSC endpoint IN size */
+#define MSC_EPOUT_SIZE                    MSC_DATA_PACKET_SIZE                  /*!< MSC endpoint OUT size */
+
+/* USB configuration descriptor structure */
+typedef struct {
+    usb_desc_config         config;                                             /*!< configuration descriptor */
+    usb_desc_itf            msc_itf;                                            /*!< interface descriptor */
+    usb_desc_ep             msc_epin;                                           /*!< endpoint IN descriptor */
+    usb_desc_ep             msc_epout;                                          /*!< endpoint OUT descriptor */
+} usb_desc_config_set;
+
+extern usb_desc msc_desc;
+extern usb_class_core msc_class;
+
+#endif /* USBD_MSC_CORE_H */

+ 58 - 0
GD32F3x0/GD32F3x0_usbfs_library/device/class/msc/Include/usbd_msc_mem.h

@@ -0,0 +1,58 @@
+/*!
+    \file    usbd_msc_mem.h
+    \brief   header file for storage memory
+
+    \version 2025-01-01, V2.5.0, firmware for GD32F3x0
+*/
+
+/*
+    Copyright (c) 2025, GigaDevice Semiconductor Inc.
+
+    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 of the copyright holder 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 HOLDER 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.
+*/
+
+#ifndef USBD_MSC_MEM_H
+#define USBD_MSC_MEM_H
+
+#include "usbd_conf.h"
+
+#define USBD_STD_INQUIRY_LENGTH          36U               /*!< standard inquiry length */
+
+typedef struct {
+    int8_t (*mem_init)(uint8_t lun);
+    int8_t (*mem_ready)(uint8_t lun);
+    int8_t (*mem_protected)(uint8_t lun);
+    int8_t (*mem_read)(uint8_t lun, uint8_t *buf, uint32_t block_addr, uint16_t block_len);
+    int8_t (*mem_write)(uint8_t lun, uint8_t *buf, uint32_t block_addr, uint16_t block_len);
+    int8_t (*mem_maxlun)(void);
+
+    uint8_t *mem_toc_data;                                 /*!< memory TOC command data pointer */
+    uint8_t *mem_inquiry_data[MEM_LUN_NUM];                /*!< memory inquiry data buff */
+    uint32_t mem_block_size[MEM_LUN_NUM];                  /*!< memory block size buff */
+    uint32_t mem_block_len[MEM_LUN_NUM];                   /*!< memory block length buff */
+}usbd_mem_cb;
+
+extern usbd_mem_cb *usbd_mem_fops;
+
+#endif /* USBD_MSC_MEM_H */

+ 53 - 0
GD32F3x0/GD32F3x0_usbfs_library/device/class/msc/Include/usbd_msc_scsi.h

@@ -0,0 +1,53 @@
+/*!
+    \file    usbd_msc_scsi.h
+    \brief   the header file of the usbd_msc_scsi.c file
+
+    \version 2025-01-01, V2.5.0, firmware for GD32F3x0
+*/
+
+/*
+    Copyright (c) 2025, GigaDevice Semiconductor Inc.
+
+    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 of the copyright holder 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 HOLDER 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.
+*/
+
+#ifndef USBD_MSC_SCSI_H
+#define USBD_MSC_SCSI_H
+
+#include "usbd_core.h"
+
+#define SENSE_LIST_DEEPTH                           4U                   /*!< sense list deepth */
+
+#define MODE_SENSE6_LENGTH                          8U                   /*!< sense6 mode length */
+#define MODE_SENSE10_LENGTH                         8U                   /*!< sense10 mode length */
+#define INQUIRY_PAGE00_LENGTH                       96U                  /*!< sense page 0 inquiry length */
+#define FORMAT_CAPACITIES_LENGTH                    20U                  /*!< format capacities length */
+
+/* function declarations */
+/* process SCSI commands */
+int8_t scsi_process_cmd(usb_core_driver *udev, uint8_t lun, uint8_t *cmd);
+/* load the last error code in the error list */
+void scsi_sense_code(usb_core_driver *udev, uint8_t lun, uint8_t skey, uint8_t asc);
+
+#endif /* USBD_MSC_SCSI_H */

+ 287 - 0
GD32F3x0/GD32F3x0_usbfs_library/device/class/msc/Source/usbd_msc_bbb.c

@@ -0,0 +1,287 @@
+/*!
+    \file    usbd_msc_bbb.c
+    \brief   USB BBB(Bulk/Bulk/Bulk) protocol core functions
+    \note    BBB means Bulk-only transport protocol for USB MSC
+
+    \version 2025-01-01, V2.5.0, firmware for GD32F3x0
+*/
+
+/*
+    Copyright (c) 2025, GigaDevice Semiconductor Inc.
+
+    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 of the copyright holder 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 HOLDER 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.
+*/
+
+#include "usbd_msc_bbb.h"
+#include "usbd_msc_mem.h"
+
+/* local function prototypes ('static') */
+static void msc_bbb_cbw_decode(usb_core_driver *udev);
+static void msc_bbb_data_send(usb_core_driver *udev, uint8_t *pbuf, uint32_t Len);
+static void msc_bbb_abort(usb_core_driver *udev);
+
+/*!
+    \brief      initialize the BBB process
+    \param[in]  udev: pointer to USB device instance
+    \param[out] none
+    \retval     none
+*/
+void msc_bbb_init(usb_core_driver *udev)
+{
+    uint8_t lun_num;
+
+    usbd_msc_handler *msc = (usbd_msc_handler *)udev->dev.class_data[USBD_MSC_INTERFACE];
+
+    msc->bbb_state = BBB_IDLE;
+    msc->bbb_status = BBB_STATUS_NORMAL;
+
+    /* initializes the storage logic unit */
+    for(lun_num = 0U; lun_num < MEM_LUN_NUM; lun_num++) {
+        usbd_mem_fops->mem_init(lun_num);
+    }
+
+    /* flush the RX FIFO */
+    usbd_fifo_flush(udev, MSC_OUT_EP);
+
+    /* flush the TX FIFO */
+    usbd_fifo_flush(udev, MSC_IN_EP);
+
+    /* prepare endpoint to receive the first BBB CBW */
+    usbd_ep_recev(udev, MSC_OUT_EP, (uint8_t *)&msc->bbb_cbw, BBB_CBW_LENGTH);
+}
+
+/*!
+    \brief      reset the BBB machine
+    \param[in]  udev: pointer to USB device instance
+    \param[out] none
+    \retval     none
+*/
+void msc_bbb_reset(usb_core_driver *udev)
+{
+    usbd_msc_handler *msc = (usbd_msc_handler *)udev->dev.class_data[USBD_MSC_INTERFACE];
+
+    msc->bbb_state = BBB_IDLE;
+    msc->bbb_status = BBB_STATUS_RECOVERY;
+
+    /* prepare endpoint to receive the first BBB command */
+    usbd_ep_recev(udev, MSC_OUT_EP, (uint8_t *)&msc->bbb_cbw, BBB_CBW_LENGTH);
+}
+
+/*!
+    \brief      deinitialize the BBB machine
+    \param[in]  udev: pointer to USB device instance
+    \param[out] none
+    \retval     none
+*/
+void msc_bbb_deinit(usb_core_driver *udev)
+{
+    usbd_msc_handler *msc = (usbd_msc_handler *)udev->dev.class_data[USBD_MSC_INTERFACE];
+
+    msc->bbb_state = BBB_IDLE;
+}
+
+/*!
+    \brief      handle BBB data IN stage
+    \param[in]  udev: pointer to USB device instance
+    \param[in]  ep_num: endpoint number
+    \param[out] none
+    \retval     none
+*/
+void msc_bbb_data_in(usb_core_driver *udev, uint8_t ep_num)
+{
+    usbd_msc_handler *msc = (usbd_msc_handler *)udev->dev.class_data[USBD_MSC_INTERFACE];
+
+    switch(msc->bbb_state) {
+    case BBB_DATA_IN:
+        if(scsi_process_cmd(udev, msc->bbb_cbw.bCBWLUN, &msc->bbb_cbw.CBWCB[0]) < 0) {
+            msc_bbb_csw_send(udev, CSW_CMD_FAILED);
+        }
+        break;
+
+    case BBB_SEND_DATA:
+    case BBB_LAST_DATA_IN:
+        msc_bbb_csw_send(udev, CSW_CMD_PASSED);
+        break;
+
+    default:
+        break;
+    }
+}
+
+/*!
+    \brief      handle BBB data OUT stage
+    \param[in]  udev: pointer to USB device instance
+    \param[in]  ep_num: endpoint number
+    \param[out] none
+    \retval     none
+*/
+void msc_bbb_data_out(usb_core_driver *udev, uint8_t ep_num)
+{
+    usbd_msc_handler *msc = (usbd_msc_handler *)udev->dev.class_data[USBD_MSC_INTERFACE];
+
+    switch(msc->bbb_state) {
+    case BBB_IDLE:
+        msc_bbb_cbw_decode(udev);
+        break;
+
+    case BBB_DATA_OUT:
+        if(scsi_process_cmd(udev, msc->bbb_cbw.bCBWLUN, &msc->bbb_cbw.CBWCB[0]) < 0) {
+            msc_bbb_csw_send(udev, CSW_CMD_FAILED);
+        }
+        break;
+
+    default:
+        break;
+    }
+}
+
+/*!
+    \brief      send the CSW(command status wrapper)
+    \param[in]  udev: pointer to USB device instance
+    \param[in]  csw_status: CSW status
+    \param[out] none
+    \retval     none
+*/
+void msc_bbb_csw_send(usb_core_driver *udev, uint8_t csw_status)
+{
+    usbd_msc_handler *msc = (usbd_msc_handler *)udev->dev.class_data[USBD_MSC_INTERFACE];
+
+    msc->bbb_csw.dCSWSignature = BBB_CSW_SIGNATURE;
+    msc->bbb_csw.bCSWStatus = csw_status;
+    msc->bbb_state = BBB_IDLE;
+
+    usbd_ep_send(udev, MSC_IN_EP, (uint8_t *)&msc->bbb_csw, BBB_CSW_LENGTH);
+
+    /* prepare endpoint to receive next command */
+    usbd_ep_recev(udev, MSC_OUT_EP, (uint8_t *)&msc->bbb_cbw, BBB_CBW_LENGTH);
+}
+
+/*!
+    \brief      complete the clear feature request
+    \param[in]  udev: pointer to USB device instance
+    \param[in]  ep_num: endpoint number
+    \param[out] none
+    \retval     none
+*/
+void msc_bbb_clrfeature(usb_core_driver *udev, uint8_t ep_num)
+{
+    usbd_msc_handler *msc = (usbd_msc_handler *)udev->dev.class_data[USBD_MSC_INTERFACE];
+
+    if(BBB_STATUS_ERROR == msc->bbb_status) {  /* bad CBW signature */
+        usbd_ep_stall(udev, MSC_IN_EP);
+
+        msc->bbb_status = BBB_STATUS_NORMAL;
+    } else if((0x80U == (ep_num & 0x80U)) && (BBB_STATUS_RECOVERY != msc->bbb_status)) {
+        msc_bbb_csw_send(udev, CSW_CMD_FAILED);
+    } else {
+
+    }
+}
+
+/*!
+    \brief      decode the CBW command and set the BBB state machine accordingly
+    \param[in]  udev: pointer to USB device instance
+    \param[out] none
+    \retval     none
+*/
+static void msc_bbb_cbw_decode(usb_core_driver *udev)
+{
+    usbd_msc_handler *msc = (usbd_msc_handler *)udev->dev.class_data[USBD_MSC_INTERFACE];
+
+    msc->bbb_csw.dCSWTag = msc->bbb_cbw.dCBWTag;
+    msc->bbb_csw.dCSWDataResidue = msc->bbb_cbw.dCBWDataTransferLength;
+
+    if((BBB_CBW_LENGTH != usbd_rxcount_get(udev, MSC_OUT_EP)) || \
+            (BBB_CBW_SIGNATURE != msc->bbb_cbw.dCBWSignature) || \
+            (msc->bbb_cbw.bCBWLUN > 1U) || \
+            (msc->bbb_cbw.bCBWCBLength < 1U) || \
+            (msc->bbb_cbw.bCBWCBLength > 16U)) {
+        /* illegal command handler */
+        scsi_sense_code(udev, msc->bbb_cbw.bCBWLUN, ILLEGAL_REQUEST, INVALID_CDB);
+
+        msc->bbb_status = BBB_STATUS_ERROR;
+
+        msc_bbb_abort(udev);
+    } else {
+        if(scsi_process_cmd(udev, msc->bbb_cbw.bCBWLUN, &msc->bbb_cbw.CBWCB[0]) < 0) {
+            msc_bbb_abort(udev);
+        } else if((BBB_DATA_IN != msc->bbb_state) && \
+                  (BBB_DATA_OUT != msc->bbb_state) && \
+                  (BBB_LAST_DATA_IN != msc->bbb_state)) { /* burst transfer handled internally */
+            if(msc->bbb_datalen > 0U) {
+                msc_bbb_data_send(udev, msc->bbb_data, msc->bbb_datalen);
+            } else if(0U == msc->bbb_datalen) {
+                msc_bbb_csw_send(udev, CSW_CMD_PASSED);
+            } else {
+
+            }
+        } else {
+
+        }
+    }
+}
+
+/*!
+    \brief      send the requested data
+    \param[in]  udev: pointer to USB device instance
+    \param[in]  buf: pointer to data buffer
+    \param[in]  len: data length
+    \param[out] none
+    \retval     none
+*/
+static void msc_bbb_data_send(usb_core_driver *udev, uint8_t *buf, uint32_t len)
+{
+    usbd_msc_handler *msc = (usbd_msc_handler *)udev->dev.class_data[USBD_MSC_INTERFACE];
+
+    len = USB_MIN(msc->bbb_cbw.dCBWDataTransferLength, len);
+
+    msc->bbb_csw.dCSWDataResidue -= len;
+    msc->bbb_csw.bCSWStatus = CSW_CMD_PASSED;
+    msc->bbb_state = BBB_SEND_DATA;
+
+    usbd_ep_send(udev, MSC_IN_EP, buf, len);
+}
+
+/*!
+    \brief      abort the current transfer
+    \param[in]  udev: pointer to USB device instance
+    \param[out] none
+    \retval     none
+*/
+static void msc_bbb_abort(usb_core_driver *udev)
+{
+    usbd_msc_handler *msc = (usbd_msc_handler *)udev->dev.class_data[USBD_MSC_INTERFACE];
+
+    if((0U == msc->bbb_cbw.bmCBWFlags) && \
+            (0U != msc->bbb_cbw.dCBWDataTransferLength) && \
+            (BBB_STATUS_NORMAL == msc->bbb_status)) {
+        usbd_ep_stall(udev, MSC_OUT_EP);
+    }
+
+    usbd_ep_stall(udev, MSC_IN_EP);
+
+    if(BBB_STATUS_ERROR == msc->bbb_status) {
+        usbd_ep_recev(udev, MSC_OUT_EP, (uint8_t *)&msc->bbb_cbw, BBB_CBW_LENGTH);
+    }
+}

+ 316 - 0
GD32F3x0/GD32F3x0_usbfs_library/device/class/msc/Source/usbd_msc_core.c

@@ -0,0 +1,316 @@
+/*!
+    \file    usbd_msc_core.c
+    \brief   USB MSC device class core functions
+
+    \version 2025-01-01, V2.5.0, firmware for GD32F3x0
+*/
+
+/*
+    Copyright (c) 2025, GigaDevice Semiconductor Inc.
+
+    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 of the copyright holder 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 HOLDER 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.
+*/
+
+#include "usbd_enum.h"
+#include "usbd_msc_bbb.h"
+#include "usbd_msc_core.h"
+#include "usbd_msc_mem.h"
+#include <string.h>
+
+#define USBD_VID                    0x28E9U
+#define USBD_PID                    0x028FU
+
+/* local function prototypes ('static') */
+static uint8_t msc_core_init(usb_dev *udev, uint8_t config_index);
+static uint8_t msc_core_deinit(usb_dev *udev, uint8_t config_index);
+static uint8_t msc_core_req(usb_dev *udev, usb_req *req);
+static uint8_t msc_core_in(usb_dev *udev, uint8_t ep_num);
+static uint8_t msc_core_out(usb_dev *udev, uint8_t ep_num);
+
+usb_class_core msc_class = {
+    .init     = msc_core_init,
+    .deinit   = msc_core_deinit,
+
+    .req_proc = msc_core_req,
+
+    .data_in  = msc_core_in,
+    .data_out = msc_core_out
+};
+
+/* note: it should use the C99 standard when compiling the below codes */
+/* USB standard device descriptor */
+const usb_desc_dev msc_dev_desc = {
+    .header =
+    {
+        .bLength           = USB_DEV_DESC_LEN,
+        .bDescriptorType   = USB_DESCTYPE_DEV
+    },
+    .bcdUSB                = 0x0200U,
+    .bDeviceClass          = 0x00U,
+    .bDeviceSubClass       = 0x00U,
+    .bDeviceProtocol       = 0x00U,
+    .bMaxPacketSize0       = USB_FS_EP0_MAX_LEN,
+    .idVendor              = USBD_VID,
+    .idProduct             = USBD_PID,
+    .bcdDevice             = 0x0100U,
+    .iManufacturer         = STR_IDX_MFC,
+    .iProduct              = STR_IDX_PRODUCT,
+    .iSerialNumber         = STR_IDX_SERIAL,
+    .bNumberConfigurations = USBD_CFG_MAX_NUM
+};
+
+/* USB device configuration descriptor */
+const usb_desc_config_set msc_config_desc = {
+    .config =
+    {
+        .header =
+        {
+            .bLength         = sizeof(usb_desc_config),
+            .bDescriptorType = USB_DESCTYPE_CONFIG
+        },
+        .wTotalLength        = USB_MSC_CONFIG_DESC_SIZE,
+        .bNumInterfaces      = 0x01U,
+        .bConfigurationValue = 0x01U,
+        .iConfiguration      = 0x00U,
+        .bmAttributes        = 0xC0U,
+        .bMaxPower           = 0x32U
+    },
+
+    .msc_itf =
+    {
+        .header =
+        {
+            .bLength         = sizeof(usb_desc_itf),
+            .bDescriptorType = USB_DESCTYPE_ITF
+        },
+        .bInterfaceNumber    = 0x00U,
+        .bAlternateSetting   = 0x00U,
+        .bNumEndpoints       = 0x02U,
+        .bInterfaceClass     = USB_CLASS_MSC,
+        .bInterfaceSubClass  = USB_MSC_SUBCLASS_SCSI,
+        .bInterfaceProtocol  = USB_MSC_PROTOCOL_BBB,
+        .iInterface          = 0x00U
+    },
+
+    .msc_epin =
+    {
+        .header =
+        {
+            .bLength         = sizeof(usb_desc_ep),
+            .bDescriptorType = USB_DESCTYPE_EP
+        },
+        .bEndpointAddress    = MSC_IN_EP,
+        .bmAttributes        = USB_EP_ATTR_BULK,
+        .wMaxPacketSize      = MSC_EPIN_SIZE,
+        .bInterval           = 0x00U
+    },
+
+    .msc_epout =
+    {
+        .header =
+        {
+            .bLength         = sizeof(usb_desc_ep),
+            .bDescriptorType = USB_DESCTYPE_EP
+        },
+        .bEndpointAddress    = MSC_OUT_EP,
+        .bmAttributes        = USB_EP_ATTR_BULK,
+        .wMaxPacketSize      = MSC_EPOUT_SIZE,
+        .bInterval           = 0x00U
+    }
+};
+
+/* USB language ID descriptor */
+static const usb_desc_LANGID usbd_language_id_desc = {
+    .header =
+    {
+        .bLength            = sizeof(usb_desc_LANGID),
+        .bDescriptorType    = USB_DESCTYPE_STR
+    },
+    .wLANGID                 = ENG_LANGID
+};
+
+/* USB manufacture string */
+static const usb_desc_str manufacturer_string = {
+    .header =
+    {
+        .bLength         = USB_STRING_LEN(10U),
+        .bDescriptorType = USB_DESCTYPE_STR
+    },
+    .unicode_string = {'G', 'i', 'g', 'a', 'D', 'e', 'v', 'i', 'c', 'e'}
+};
+
+/* USB product string */
+static const usb_desc_str product_string = {
+    .header =
+    {
+        .bLength         = USB_STRING_LEN(12U),
+        .bDescriptorType = USB_DESCTYPE_STR
+    },
+    .unicode_string = {'G', 'D', '3', '2', '-', 'U', 'S', 'B', '_', 'M', 'S', 'C'}
+};
+
+/* USBD serial string */
+static usb_desc_str serial_string = {
+    .header =
+    {
+        .bLength         = USB_STRING_LEN(12U),
+        .bDescriptorType = USB_DESCTYPE_STR
+    }
+};
+
+/* USB string descriptor */
+static void *const usbd_msc_strings[] = {
+    [STR_IDX_LANGID]  = (uint8_t *)&usbd_language_id_desc,
+    [STR_IDX_MFC]     = (uint8_t *)&manufacturer_string,
+    [STR_IDX_PRODUCT] = (uint8_t *)&product_string,
+    [STR_IDX_SERIAL]  = (uint8_t *)&serial_string
+};
+
+usb_desc msc_desc = {
+    .dev_desc    = (uint8_t *)&msc_dev_desc,
+    .config_desc = (uint8_t *)&msc_config_desc,
+    .strings     = usbd_msc_strings
+};
+
+static uint8_t usbd_msc_maxlun = 0U;
+
+/*!
+    \brief      initialize the MSC device
+    \param[in]  udev: pointer to USB device instance
+    \param[in]  config_index: configuration index
+    \param[out] none
+    \retval     USB device operation status
+*/
+static uint8_t msc_core_init(usb_dev *udev, uint8_t config_index)
+{
+    static usbd_msc_handler msc_handler;
+
+    memset((void *)&msc_handler, 0U, sizeof(usbd_msc_handler));
+
+    udev->dev.class_data[USBD_MSC_INTERFACE] = (void *)&msc_handler;
+
+    /* configure MSC TX endpoint */
+    usbd_ep_setup(udev, &(msc_config_desc.msc_epin));
+
+    /* configure MSC RX endpoint */
+    usbd_ep_setup(udev, &(msc_config_desc.msc_epout));
+
+    /* initialize the BBB layer */
+    msc_bbb_init(udev);
+
+    return USBD_OK;
+}
+
+/*!
+    \brief      deinitialize the MSC device
+    \param[in]  udev: pointer to USB device instance
+    \param[in]  config_index: configuration index
+    \param[out] none
+    \retval     USB device operation status
+*/
+static uint8_t msc_core_deinit(usb_dev *udev, uint8_t config_index)
+{
+    /* clear MSC endpoints */
+    usbd_ep_clear(udev, MSC_IN_EP);
+    usbd_ep_clear(udev, MSC_OUT_EP);
+
+    /* deinitialize the BBB layer */
+    msc_bbb_deinit(udev);
+
+    return USBD_OK;
+}
+
+/*!
+    \brief      handle the MSC class-specific and standard requests
+    \param[in]  udev: pointer to USB device instance
+    \param[in]  req: device class-specific request
+    \param[out] none
+    \retval     USB device operation status
+*/
+static uint8_t msc_core_req(usb_dev *udev, usb_req *req)
+{
+    usb_transc *transc = &udev->dev.transc_in[0];
+
+    switch(req->bRequest) {
+    case BBB_GET_MAX_LUN :
+        if((0U == req->wValue) && \
+                (1U == req->wLength) && \
+                (0x80U == (req->bmRequestType & 0x80U))) {
+            usbd_msc_maxlun = (uint8_t)usbd_mem_fops->mem_maxlun();
+
+            transc->xfer_buf = &usbd_msc_maxlun;
+            transc->remain_len = 1U;
+        } else {
+            return USBD_FAIL;
+        }
+        break;
+
+    case BBB_RESET :
+        if((0U == req->wValue) && \
+                (0U == req->wLength) && \
+                (0x80U != (req->bmRequestType & 0x80U))) {
+            msc_bbb_reset(udev);
+        } else {
+            return USBD_FAIL;
+        }
+        break;
+
+    case USB_CLEAR_FEATURE:
+        msc_bbb_clrfeature(udev, (uint8_t)req->wIndex);
+        break;
+
+    default:
+        return USBD_FAIL;
+    }
+
+    return USBD_OK;
+}
+
+/*!
+    \brief      handle data IN stage
+    \param[in]  udev: pointer to USB device instance
+    \param[in]  ep_num: the endpoint number
+    \param[out] none
+    \retval     none
+*/
+static uint8_t msc_core_in(usb_dev *udev, uint8_t ep_num)
+{
+    msc_bbb_data_in(udev, ep_num);
+
+    return USBD_OK;
+}
+
+/*!
+    \brief      handle data OUT stage
+    \param[in]  udev: pointer to USB device instance
+    \param[in]  ep_num: the endpoint number
+    \param[out] none
+    \retval     none
+*/
+static uint8_t msc_core_out(usb_dev *udev, uint8_t ep_num)
+{
+    msc_bbb_data_out(udev, ep_num);
+
+    return USBD_OK;
+}

+ 758 - 0
GD32F3x0/GD32F3x0_usbfs_library/device/class/msc/Source/usbd_msc_scsi.c

@@ -0,0 +1,758 @@
+/*!
+    \file    usbd_msc_scsi.c
+    \brief   USB SCSI layer functions
+
+    \version 2025-01-01, V2.5.0, firmware for GD32F3x0
+*/
+
+/*
+    Copyright (c) 2025, GigaDevice Semiconductor Inc.
+
+    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 of the copyright holder 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 HOLDER 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.
+*/
+
+#include "usbd_msc_mem.h"
+#include "usbd_msc_bbb.h"
+#include "usbd_msc_scsi.h"
+
+/* USB mass storage page 0 inquiry data */
+const uint8_t msc_page00_inquiry_data[] = {
+    0x00U,
+    0x00U,
+    0x00U,
+    0x00U,
+    (INQUIRY_PAGE00_LENGTH - 4U),
+    0x80U,
+    0x83U
+};
+
+/* USB mass storage sense 6 data */
+const uint8_t msc_mode_sense6_data[] = {
+    0x00U,
+    0x00U,
+    0x00U,
+    0x00U,
+    0x00U,
+    0x00U,
+    0x00U,
+    0x00U
+};
+
+/* USB mass storage sense 10 data */
+const uint8_t msc_mode_sense10_data[] = {
+    0x00U,
+    0x06U,
+    0x00U,
+    0x00U,
+    0x00U,
+    0x00U,
+    0x00U,
+    0x00U
+};
+
+/* local function prototypes ('static') */
+static int8_t scsi_test_unit_ready(usb_core_driver *udev, uint8_t lun, uint8_t *params);
+static int8_t scsi_mode_select6(usb_core_driver *udev, uint8_t lun, uint8_t *params);
+static int8_t scsi_mode_select10(usb_core_driver *udev, uint8_t lun, uint8_t *params);
+static int8_t scsi_inquiry(usb_core_driver *udev, uint8_t lun, uint8_t *params);
+static int8_t scsi_read_format_capacity(usb_core_driver *udev, uint8_t lun, uint8_t *params);
+static int8_t scsi_read_capacity10(usb_core_driver *udev, uint8_t lun, uint8_t *params);
+static int8_t scsi_request_sense(usb_core_driver *udev, uint8_t lun, uint8_t *params);
+static int8_t scsi_mode_sense6(usb_core_driver *udev, uint8_t lun, uint8_t *params);
+static int8_t scsi_toc_cmd_read(usb_core_driver *udev, uint8_t lun, uint8_t *params);
+static int8_t scsi_mode_sense10(usb_core_driver *udev, uint8_t lun, uint8_t *params);
+static int8_t scsi_write10(usb_core_driver *udev, uint8_t lun, uint8_t *params);
+static int8_t scsi_read10(usb_core_driver *udev, uint8_t lun, uint8_t *params);
+static int8_t scsi_verify10(usb_core_driver *udev, uint8_t lun, uint8_t *params);
+
+static int8_t scsi_process_read(usb_core_driver *udev, uint8_t lun);
+static int8_t scsi_process_write(usb_core_driver *udev, uint8_t lun);
+
+static inline int8_t scsi_check_address_range(usb_core_driver *udev, uint8_t lun, uint32_t blk_offset, uint16_t blk_nbr);
+static inline int8_t scsi_format_cmd(usb_core_driver *udev, uint8_t lun);
+static inline int8_t scsi_start_stop_unit(usb_core_driver *udev, uint8_t lun, uint8_t *params);
+static inline int8_t scsi_allow_medium_removal(usb_core_driver *udev, uint8_t lun, uint8_t *params);
+
+/*!
+    \brief      process SCSI commands
+    \param[in]  udev: pointer to USB device instance
+    \param[in]  lun: logical unit number
+    \param[in]  params: command parameters
+    \param[out] none
+    \retval     status
+*/
+int8_t scsi_process_cmd(usb_core_driver *udev, uint8_t lun, uint8_t *params)
+{
+    switch(params[0]) {
+    case SCSI_TEST_UNIT_READY:
+        return scsi_test_unit_ready(udev, lun, params);
+
+    case SCSI_REQUEST_SENSE:
+        return scsi_request_sense(udev, lun, params);
+
+    case SCSI_INQUIRY:
+        return scsi_inquiry(udev, lun, params);
+
+    case SCSI_START_STOP_UNIT:
+        return scsi_start_stop_unit(udev, lun, params);
+
+    case SCSI_ALLOW_MEDIUM_REMOVAL:
+        return scsi_allow_medium_removal(udev, lun, params);
+
+    case SCSI_MODE_SENSE6:
+        return scsi_mode_sense6(udev, lun, params);
+
+    case SCSI_MODE_SENSE10:
+        return scsi_mode_sense10(udev, lun, params);
+
+    case SCSI_READ_FORMAT_CAPACITIES:
+        return scsi_read_format_capacity(udev, lun, params);
+
+    case SCSI_READ_CAPACITY10:
+        return scsi_read_capacity10(udev, lun, params);
+
+    case SCSI_READ10:
+        return scsi_read10(udev, lun, params);
+
+    case SCSI_WRITE10:
+        return scsi_write10(udev, lun, params);
+
+    case SCSI_VERIFY10:
+        return scsi_verify10(udev, lun, params);
+
+    case SCSI_FORMAT_UNIT:
+        return scsi_format_cmd(udev, lun);
+
+    case SCSI_READ_TOC_DATA:
+        return scsi_toc_cmd_read(udev, lun, params);
+
+    case SCSI_MODE_SELECT6:
+        return scsi_mode_select6(udev, lun, params);
+
+    case SCSI_MODE_SELECT10:
+        return scsi_mode_select10(udev, lun, params);
+
+    default:
+        scsi_sense_code(udev, lun, ILLEGAL_REQUEST, INVALID_CDB);
+        return -1;
+    }
+}
+
+/*!
+    \brief      load the last error code in the error list
+    \param[in]  udev: pointer to USB device instance
+    \param[in]  lun: logical unit number
+    \param[in]  skey: sense key
+    \param[in]  asc: additional sense key
+    \param[out] none
+    \retval     none
+*/
+void scsi_sense_code(usb_core_driver *udev, uint8_t lun, uint8_t skey, uint8_t asc)
+{
+    usbd_msc_handler *msc = (usbd_msc_handler *)udev->dev.class_data[USBD_MSC_INTERFACE];
+
+    msc->scsi_sense[msc->scsi_sense_tail].SenseKey = skey;
+    msc->scsi_sense[msc->scsi_sense_tail].ASC = asc;
+    msc->scsi_sense_tail++;
+
+    if(SENSE_LIST_DEEPTH == msc->scsi_sense_tail) {
+        msc->scsi_sense_tail = 0U;
+    }
+}
+
+/*!
+    \brief      process SCSI test unit ready command
+    \param[in]  udev: pointer to USB device instance
+    \param[in]  lun: logical unit number
+    \param[in]  params: command parameters
+    \param[out] none
+    \retval     status
+*/
+static int8_t scsi_test_unit_ready(usb_core_driver *udev, uint8_t lun, uint8_t *params)
+{
+    usbd_msc_handler *msc = (usbd_msc_handler *)udev->dev.class_data[USBD_MSC_INTERFACE];
+
+    /* case 9 : Hi > D0 */
+    if(0U != msc->bbb_cbw.dCBWDataTransferLength) {
+        scsi_sense_code(udev, msc->bbb_cbw.bCBWLUN, ILLEGAL_REQUEST, INVALID_CDB);
+
+        return -1;
+    }
+
+    if(0 != usbd_mem_fops->mem_ready(lun)) {
+        scsi_sense_code(udev, lun, NOT_READY, MEDIUM_NOT_PRESENT);
+
+        return -1;
+    }
+
+    msc->bbb_datalen = 0U;
+
+    return 0;
+}
+
+/*!
+    \brief      process mode select 6 command
+    \param[in]  udev: pointer to USB device instance
+    \param[in]  lun: logical unit number
+    \param[in]  params: command parameters
+    \param[out] none
+    \retval     status
+*/
+static int8_t scsi_mode_select6(usb_core_driver *udev, uint8_t lun, uint8_t *params)
+{
+    usbd_msc_handler *msc = (usbd_msc_handler *)udev->dev.class_data[USBD_MSC_INTERFACE];
+
+    msc->bbb_datalen = 0U;
+
+    return 0;
+}
+
+/*!
+    \brief      process mode select 10 command
+    \param[in]  udev: pointer to USB device instance
+    \param[in]  lun: logical unit number
+    \param[in]  params: command parameters
+    \param[out] none
+    \retval     status
+*/
+static int8_t scsi_mode_select10(usb_core_driver *udev, uint8_t lun, uint8_t *params)
+{
+    usbd_msc_handler *msc = (usbd_msc_handler *)udev->dev.class_data[USBD_MSC_INTERFACE];
+
+    msc->bbb_datalen = 0U;
+
+    return 0;
+}
+
+/*!
+    \brief      process inquiry command
+    \param[in]  udev: pointer to USB device instance
+    \param[in]  lun: logical unit number
+    \param[in]  params: command parameters
+    \param[out] none
+    \retval     status
+*/
+static int8_t scsi_inquiry(usb_core_driver *udev, uint8_t lun, uint8_t *params)
+{
+    uint8_t *page = NULL;
+    uint16_t len = 0U;
+
+    usbd_msc_handler *msc = (usbd_msc_handler *)udev->dev.class_data[USBD_MSC_INTERFACE];
+
+    if(params[1] & 0x01U) {
+        page = (uint8_t *)msc_page00_inquiry_data;
+
+        len = INQUIRY_PAGE00_LENGTH;
+    } else {
+        page = (uint8_t *)usbd_mem_fops->mem_inquiry_data[lun];
+
+        len = (uint16_t)(page[4] + 5U);
+
+        if(params[4] <= len) {
+            len = params[4];
+        }
+    }
+
+    msc->bbb_datalen = len;
+
+    while(len) {
+        len--;
+        msc->bbb_data[len] = page[len];
+    }
+
+    return 0;
+}
+
+/*!
+    \brief      process read capacity 10 command
+    \param[in]  udev: pointer to USB device instance
+    \param[in]  lun: logical unit number
+    \param[in]  params: command parameters
+    \param[out] none
+    \retval     status
+*/
+static int8_t scsi_read_capacity10(usb_core_driver *udev, uint8_t lun, uint8_t *params)
+{
+    uint32_t blk_num = usbd_mem_fops->mem_block_len[lun] - 1U;
+    usbd_msc_handler *msc = (usbd_msc_handler *)udev->dev.class_data[USBD_MSC_INTERFACE];
+
+    msc->scsi_blk_nbr[lun] = usbd_mem_fops->mem_block_len[lun];
+    msc->scsi_blk_size[lun] = usbd_mem_fops->mem_block_size[lun];
+
+    msc->bbb_data[0] = (uint8_t)(blk_num >> 24);
+    msc->bbb_data[1] = (uint8_t)(blk_num >> 16);
+    msc->bbb_data[2] = (uint8_t)(blk_num >> 8);
+    msc->bbb_data[3] = (uint8_t)(blk_num);
+
+    msc->bbb_data[4] = (uint8_t)(msc->scsi_blk_size[lun] >> 24);
+    msc->bbb_data[5] = (uint8_t)(msc->scsi_blk_size[lun] >> 16);
+    msc->bbb_data[6] = (uint8_t)(msc->scsi_blk_size[lun] >> 8);
+    msc->bbb_data[7] = (uint8_t)(msc->scsi_blk_size[lun]);
+
+    msc->bbb_datalen = 8U;
+
+    return 0;
+}
+
+/*!
+    \brief      process read format capacity command
+    \param[in]  udev: pointer to USB device instance
+    \param[in]  lun: logical unit number
+    \param[in]  params: command parameters
+    \param[out] none
+    \retval     status
+*/
+static int8_t scsi_read_format_capacity(usb_core_driver *udev, uint8_t lun, uint8_t *params)
+{
+    uint16_t i = 0U;
+    uint32_t blk_size = usbd_mem_fops->mem_block_size[lun];
+    uint32_t blk_num = usbd_mem_fops->mem_block_len[lun];
+    uint32_t blk_nbr = blk_num - 1U;
+
+    usbd_msc_handler *msc = (usbd_msc_handler *)udev->dev.class_data[USBD_MSC_INTERFACE];
+
+    for(i = 0U; i < 12U; i++) {
+        msc->bbb_data[i] = 0U;
+    }
+
+    msc->bbb_data[3] = 0x08U;
+    msc->bbb_data[4] = (uint8_t)(blk_nbr >> 24);
+    msc->bbb_data[5] = (uint8_t)(blk_nbr >> 16);
+    msc->bbb_data[6] = (uint8_t)(blk_nbr >>  8);
+    msc->bbb_data[7] = (uint8_t)(blk_nbr);
+
+    msc->bbb_data[8] = 0x02U;
+    msc->bbb_data[9] = (uint8_t)(blk_size >> 16);
+    msc->bbb_data[10] = (uint8_t)(blk_size >> 8);
+    msc->bbb_data[11] = (uint8_t)(blk_size);
+
+    msc->bbb_datalen = 12U;
+
+    return 0;
+}
+
+/*!
+    \brief      process mode sense6 command
+    \param[in]  udev: pointer to USB device instance
+    \param[in]  lun: logical unit number
+    \param[in]  params: command parameters
+    \param[out] none
+    \retval     status
+*/
+static int8_t scsi_mode_sense6(usb_core_driver *udev, uint8_t lun, uint8_t *params)
+{
+    uint16_t len = 8U;
+    usbd_msc_handler *msc = (usbd_msc_handler *)udev->dev.class_data[USBD_MSC_INTERFACE];
+
+    msc->bbb_datalen = len;
+
+    while(len) {
+        len--;
+        msc->bbb_data[len] = msc_mode_sense6_data[len];
+    }
+
+    return 0;
+}
+
+/*!
+    \brief      process mode sense10 command
+    \param[in]  udev: pointer to USB device instance
+    \param[in]  lun: logical unit number
+    \param[in]  params: command parameters
+    \param[out] none
+    \retval     status
+*/
+static int8_t scsi_mode_sense10(usb_core_driver *udev, uint8_t lun, uint8_t *params)
+{
+    uint16_t len = 8U;
+    usbd_msc_handler *msc = (usbd_msc_handler *)udev->dev.class_data[USBD_MSC_INTERFACE];
+
+    msc->bbb_datalen = len;
+
+    while(len) {
+        len--;
+        msc->bbb_data[len] = msc_mode_sense10_data[len];
+    }
+
+    return 0;
+}
+
+/*!
+    \brief      process request sense command
+    \param[in]  udev: pointer to USB device instance
+    \param[in]  lun: logical unit number
+    \param[in]  params: command parameters
+    \param[out] none
+    \retval     status
+*/
+static int8_t scsi_request_sense(usb_core_driver *udev, uint8_t lun, uint8_t *params)
+{
+    uint8_t i = 0U;
+    usbd_msc_handler *msc = (usbd_msc_handler *)udev->dev.class_data[USBD_MSC_INTERFACE];
+
+    for(i = 0U; i < REQUEST_SENSE_DATA_LEN; i++) {
+        msc->bbb_data[i] = 0U;
+    }
+
+    msc->bbb_data[0] = 0x70U;
+    msc->bbb_data[7] = REQUEST_SENSE_DATA_LEN - 6U;
+
+    if((msc->scsi_sense_head != msc->scsi_sense_tail)) {
+        msc->bbb_data[2] = msc->scsi_sense[msc->scsi_sense_head].SenseKey;
+        msc->bbb_data[12] = msc->scsi_sense[msc->scsi_sense_head].ASC;
+        msc->bbb_data[13] = msc->scsi_sense[msc->scsi_sense_head].ASCQ;
+        msc->scsi_sense_head++;
+
+        if(SENSE_LIST_DEEPTH == msc->scsi_sense_head) {
+            msc->scsi_sense_head = 0U;
+        }
+    }
+
+    msc->bbb_datalen = USB_MIN(REQUEST_SENSE_DATA_LEN, params[4]);
+
+    return 0;
+}
+
+/*!
+    \brief      process start stop unit command
+    \param[in]  udev: pointer to USB device instance
+    \param[in]  lun: logical unit number
+    \param[in]  params: command parameters
+    \param[out] none
+    \retval     status
+*/
+static inline int8_t scsi_start_stop_unit(usb_core_driver *udev, uint8_t lun, uint8_t *params)
+{
+    usbd_msc_handler *msc = (usbd_msc_handler *)udev->dev.class_data[USBD_MSC_INTERFACE];
+
+    msc->bbb_datalen = 0U;
+    msc->scsi_disk_pop = 1U;
+
+    return 0;
+}
+
+/*!
+    \brief      process allow medium removal command
+    \param[in]  udev: pointer to USB device instance
+    \param[in]  lun: logical unit number
+    \param[in]  params: command parameters
+    \param[out] none
+    \retval     status
+*/
+static inline int8_t scsi_allow_medium_removal(usb_core_driver *udev, uint8_t lun, uint8_t *params)
+{
+    usbd_msc_handler *msc = (usbd_msc_handler *)udev->dev.class_data[USBD_MSC_INTERFACE];
+
+    msc->bbb_datalen = 0U;
+
+    return 0;
+}
+
+/*!
+    \brief      process read10 command
+    \param[in]  udev: pointer to USB device instance
+    \param[in]  lun: logical unit number
+    \param[in]  params: command parameters
+    \param[out] none
+    \retval     status
+*/
+static int8_t scsi_read10(usb_core_driver *udev, uint8_t lun, uint8_t *params)
+{
+    usbd_msc_handler *msc = (usbd_msc_handler *)udev->dev.class_data[USBD_MSC_INTERFACE];
+
+    if(BBB_IDLE == msc->bbb_state) {
+        /* direction is from device to host */
+        if(0x80U != (msc->bbb_cbw.bmCBWFlags & 0x80U)) {
+            scsi_sense_code(udev, msc->bbb_cbw.bCBWLUN, ILLEGAL_REQUEST, INVALID_CDB);
+
+            return -1;
+        }
+
+        if(0 != usbd_mem_fops->mem_ready(lun)) {
+            scsi_sense_code(udev, lun, NOT_READY, MEDIUM_NOT_PRESENT);
+
+            return -1;
+        }
+
+        msc->scsi_blk_addr = (params[2] << 24) | (params[3] << 16) | \
+                             (params[4] << 8) |  params[5];
+
+        msc->scsi_blk_len = (params[7] << 8) | params[8];
+
+        if(scsi_check_address_range(udev, lun, msc->scsi_blk_addr, (uint16_t)msc->scsi_blk_len) < 0) {
+            return -1; /* error */
+        }
+
+        msc->bbb_state = BBB_DATA_IN;
+
+        msc->scsi_blk_addr *= msc->scsi_blk_size[lun];
+        msc->scsi_blk_len  *= msc->scsi_blk_size[lun];
+
+        /* cases 4,5 : Hi <> Dn */
+        if(msc->bbb_cbw.dCBWDataTransferLength != msc->scsi_blk_len) {
+            scsi_sense_code(udev, msc->bbb_cbw.bCBWLUN, ILLEGAL_REQUEST, INVALID_CDB);
+
+            return -1;
+        }
+    }
+
+    msc->bbb_datalen = MSC_MEDIA_PACKET_SIZE;
+
+    return scsi_process_read(udev, lun);
+}
+
+/*!
+    \brief      process write10 command
+    \param[in]  udev: pointer to USB device instance
+    \param[in]  lun: logical unit number
+    \param[in]  params: command parameters
+    \param[out] none
+    \retval     status
+*/
+static int8_t scsi_write10(usb_core_driver *udev, uint8_t lun, uint8_t *params)
+{
+    usbd_msc_handler *msc = (usbd_msc_handler *)udev->dev.class_data[USBD_MSC_INTERFACE];
+
+    if(BBB_IDLE == msc->bbb_state) {
+        /* case 8 : Hi <> Do */
+        if(0x80U == (msc->bbb_cbw.bmCBWFlags & 0x80U)) {
+            scsi_sense_code(udev, msc->bbb_cbw.bCBWLUN, ILLEGAL_REQUEST, INVALID_CDB);
+
+            return -1;
+        }
+
+        /* check whether media is ready */
+        if(0 != usbd_mem_fops->mem_ready(lun)) {
+            scsi_sense_code(udev, lun, NOT_READY, MEDIUM_NOT_PRESENT);
+
+            return -1;
+        }
+
+        /* check if media is write-protected */
+        if(0 != usbd_mem_fops->mem_protected(lun)) {
+            scsi_sense_code(udev, lun, NOT_READY, WRITE_PROTECTED);
+
+            return -1;
+        }
+
+        msc->scsi_blk_addr = (params[2] << 24) | (params[3] << 16) | \
+                             (params[4] << 8) |  params[5];
+
+        msc->scsi_blk_len = (params[7] << 8) | params[8];
+
+        /* check if LBA address is in the right range */
+        if(scsi_check_address_range(udev, lun, msc->scsi_blk_addr, (uint16_t)msc->scsi_blk_len) < 0) {
+            return -1; /* error */
+        }
+
+        msc->scsi_blk_addr *= msc->scsi_blk_size[lun];
+        msc->scsi_blk_len  *= msc->scsi_blk_size[lun];
+
+        /* cases 3,11,13 : Hn,Ho <> D0 */
+        if(msc->bbb_cbw.dCBWDataTransferLength != msc->scsi_blk_len) {
+            scsi_sense_code(udev, msc->bbb_cbw.bCBWLUN, ILLEGAL_REQUEST, INVALID_CDB);
+
+            return -1;
+        }
+
+        /* prepare endpoint to receive first data packet */
+        msc->bbb_state = BBB_DATA_OUT;
+
+        usbd_ep_recev(udev, \
+                      MSC_OUT_EP, \
+                      msc->bbb_data, \
+                      USB_MIN(msc->scsi_blk_len, MSC_MEDIA_PACKET_SIZE));
+    } else { /* write process ongoing */
+        return scsi_process_write(udev, lun);
+    }
+
+    return 0;
+}
+
+/*!
+    \brief      process verify10 command
+    \param[in]  udev: pointer to USB device instance
+    \param[in]  lun: logical unit number
+    \param[in]  params: command parameters
+    \param[out] none
+    \retval     status
+*/
+static int8_t scsi_verify10(usb_core_driver *udev, uint8_t lun, uint8_t *params)
+{
+    usbd_msc_handler *msc = (usbd_msc_handler *)udev->dev.class_data[USBD_MSC_INTERFACE];
+
+    if(0x02U == (params[1] & 0x02U)) {
+        scsi_sense_code(udev, lun, ILLEGAL_REQUEST, INVALID_FIELD_IN_COMMAND);
+
+        return -1; /* error, verify mode not supported*/
+    }
+
+    if(scsi_check_address_range(udev, lun, msc->scsi_blk_addr, (uint16_t)msc->scsi_blk_len) < 0) {
+        return -1; /* error */
+    }
+
+    msc->bbb_datalen = 0U;
+
+    return 0;
+}
+
+/*!
+    \brief      check address range
+    \param[in]  udev: pointer to USB device instance
+    \param[in]  lun: logical unit number
+    \param[in]  blk_offset: block offset
+    \param[in]  blk_nbr: number of block to be processed
+    \param[out] none
+    \retval     status
+*/
+static inline int8_t scsi_check_address_range(usb_core_driver *udev, uint8_t lun, uint32_t blk_offset, uint16_t blk_nbr)
+{
+    usbd_msc_handler *msc = (usbd_msc_handler *)udev->dev.class_data[USBD_MSC_INTERFACE];
+
+    if((blk_offset + blk_nbr) > msc->scsi_blk_nbr[lun]) {
+        scsi_sense_code(udev, lun, ILLEGAL_REQUEST, ADDRESS_OUT_OF_RANGE);
+
+        return -1;
+    }
+
+    return 0;
+}
+
+/*!
+    \brief      handle read process
+    \param[in]  udev: pointer to USB device instance
+    \param[in]  lun: logical unit number
+    \param[out] none
+    \retval     status
+*/
+static int8_t scsi_process_read(usb_core_driver *udev, uint8_t lun)
+{
+    usbd_msc_handler *msc = (usbd_msc_handler *)udev->dev.class_data[USBD_MSC_INTERFACE];
+
+    uint32_t len = USB_MIN(msc->scsi_blk_len, MSC_MEDIA_PACKET_SIZE);
+
+    if(usbd_mem_fops->mem_read(lun, \
+                               msc->bbb_data, \
+                               msc->scsi_blk_addr, \
+                               (uint16_t)(len / msc->scsi_blk_size[lun])) < 0) {
+        scsi_sense_code(udev, lun, HARDWARE_ERROR, UNRECOVERED_READ_ERROR);
+
+        return -1;
+    }
+
+    usbd_ep_send(udev, MSC_IN_EP, msc->bbb_data, len);
+
+    msc->scsi_blk_addr += len;
+    msc->scsi_blk_len  -= len;
+
+    /* case 6 : Hi = Di */
+    msc->bbb_csw.dCSWDataResidue -= len;
+
+    if(0U == msc->scsi_blk_len) {
+        msc->bbb_state = BBB_LAST_DATA_IN;
+    }
+
+    return 0;
+}
+
+/*!
+    \brief      handle write process
+    \param[in]  udev: pointer to USB device instance
+    \param[in]  lun: logical unit number
+    \param[out] none
+    \retval     status
+*/
+static int8_t scsi_process_write(usb_core_driver *udev, uint8_t lun)
+{
+    usbd_msc_handler *msc = (usbd_msc_handler *)udev->dev.class_data[USBD_MSC_INTERFACE];
+
+    uint32_t len = USB_MIN(msc->scsi_blk_len, MSC_MEDIA_PACKET_SIZE);
+
+    if(usbd_mem_fops->mem_write(lun, \
+                                msc->bbb_data, \
+                                msc->scsi_blk_addr, \
+                                (uint16_t)(len / msc->scsi_blk_size[lun])) < 0) {
+        scsi_sense_code(udev, lun, HARDWARE_ERROR, WRITE_FAULT);
+
+        return -1;
+    }
+
+    msc->scsi_blk_addr += len;
+    msc->scsi_blk_len  -= len;
+
+    /* case 12 : Ho = Do */
+    msc->bbb_csw.dCSWDataResidue -= len;
+
+    if(0U == msc->scsi_blk_len) {
+        msc_bbb_csw_send(udev, CSW_CMD_PASSED);
+    } else {
+        /* prepare endpoint to receive next packet */
+        usbd_ep_recev(udev, \
+                      MSC_OUT_EP, \
+                      msc->bbb_data, \
+                      USB_MIN(msc->scsi_blk_len, MSC_MEDIA_PACKET_SIZE));
+    }
+
+    return 0;
+}
+
+/*!
+    \brief      process format unit command
+    \param[in]  udev: pointer to USB device instance
+    \param[in]  lun: logical unit number
+    \param[out] none
+    \retval     status
+*/
+static inline int8_t scsi_format_cmd(usb_core_driver *udev, uint8_t lun)
+{
+    return 0;
+}
+
+/*!
+    \brief      process read TOC command
+    \param[in]  udev: pointer to USB device instance
+    \param[in]  lun: logical unit number
+    \param[in]  params: command parameters
+    \param[out] none
+    \retval     status
+*/
+static int8_t scsi_toc_cmd_read(usb_core_driver *udev, uint8_t lun, uint8_t *params)
+{
+    uint8_t *pPage;
+    uint16_t len;
+
+    usbd_msc_handler *msc = (usbd_msc_handler *)udev->dev.class_data[USBD_MSC_INTERFACE];
+
+    pPage = (uint8_t *)&usbd_mem_fops->mem_toc_data[lun * READ_TOC_CMD_LEN];
+    len = (uint16_t)pPage[1] + 2U;
+
+    msc->bbb_datalen = len;
+
+    while(len) {
+        len--;
+        msc->bbb_data[len] = pPage[len];
+    }
+
+    return 0;
+}

+ 78 - 0
GD32F3x0/GD32F3x0_usbfs_library/device/class/printer/Include/printer_core.h

@@ -0,0 +1,78 @@
+/*!
+    \file    printer_core.h
+    \brief   the header file of USB printer device class core functions
+
+    \version 2025-01-01, V2.5.0, firmware for GD32F3x0
+*/
+
+/*
+    Copyright (c) 2025, GigaDevice Semiconductor Inc.
+
+    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 of the copyright holder 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 HOLDER 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.
+*/
+
+#ifndef PRINTER_CORE_H
+#define PRINTER_CORE_H
+
+#include "usbd_enum.h"
+
+/* USB printer device class code */
+#define USB_CLASS_PRINTER               0x07U
+
+/* printer device subclass code */
+#define USB_SUBCLASS_PRINTER            0x01U
+
+/* printer device protocol code */
+#define PROTOCOL_UNIDIRECTIONAL_ITF     0x01U            /*!< unidirectional interface */
+#define PROTOCOL_BI_DIRECTIONAL_ITF     0x02U            /*!< BI directional interface */
+#define PROTOCOL_1284_4_ITF             0x03U            /*!< 1284.4 interface */
+#define PROTOCOL_VENDOR                 0xFFU            /*!< vendor */
+
+/* device id length */
+#define DEVICE_ID_LEN                   103U
+
+/* printer configuration descriptor length */
+#define USB_PRINTER_CONFIG_DESC_LEN     32U
+
+/* printer device specific-class request */
+#define GET_DEVICE_ID                   0x00U            /*!< get device id request */
+#define GET_PORT_STATUS                 0x01U            /*!< get port status request */
+#define SOFT_RESET                      0x02U            /*!< soft reset request */
+
+#pragma pack(1)
+
+/* USB configuration descriptor structure */
+typedef struct {
+    usb_desc_config         config;                      /*!< printer configuration descriptor */
+    usb_desc_itf            printer_itf;                 /*!< printer interface descriptor */
+    usb_desc_ep             printer_epin;                /*!< endpoint IN descriptor */
+    usb_desc_ep             printer_epout;               /*!< endpoint OUT descriptor */
+} usb_printer_desc_config_set;
+
+#pragma pack()
+
+extern usb_desc printer_desc;
+extern usb_class_core usbd_printer_cb;
+
+#endif /* PRINTER_CORE_H */

+ 302 - 0
GD32F3x0/GD32F3x0_usbfs_library/device/class/printer/Source/printer_core.c

@@ -0,0 +1,302 @@
+/*!
+    \file    printer_core.c
+    \brief   USB printer device class core functions
+
+    \version 2025-01-01, V2.5.0, firmware for GD32F3x0
+*/
+
+/*
+    Copyright (c) 2025, GigaDevice Semiconductor Inc.
+
+    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 of the copyright holder 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 HOLDER 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.
+*/
+
+#include "printer_core.h"
+
+#define USBD_VID                     0x28E9U
+#define USBD_PID                     0x028DU
+
+/* printer port status: paper not empty/selected/no error */
+static uint8_t g_port_status = 0x18U;
+
+uint8_t g_printer_data_buf[PRINTER_OUT_PACKET];
+
+uint8_t PRINTER_DEVICE_ID[DEVICE_ID_LEN] = {
+    0x00U, 0x67U,
+    'M', 'A', 'N', 'U', 'F', 'A', 'C', 'T', 'U', 'R', 'E', 'R', ':',
+    'G', 'I', 'G', 'A', ' ', 'D', 'E', 'V', 'I', 'C', 'E', '-', ';',
+    'C', 'O', 'M', 'M', 'A', 'N', 'D', ' ', 'S', 'E', 'T', ':',
+    'P', 'C', 'L', ',', 'M', 'P', 'L', ';',
+    'M', 'O', 'D', 'E', 'L', ':',
+    'L', 'a', 's', 'e', 'r', 'B', 'e', 'a', 'm', '?', ';',
+    'C', 'O', 'M', 'M', 'E', 'N', 'T', ':',
+    'G', 'o', 'o', 'd', ' ', '!', ';',
+    'A', 'C', 'T', 'I', 'V', 'E', ' ', 'C', 'O', 'M', 'M', 'A', 'N', 'D', ' ', 'S', 'E', 'T', ':',
+    'P', 'C', 'L', ';'
+};
+
+/* USB standard device descriptor */
+const usb_desc_dev printer_dev_desc = {
+    .header =
+    {
+        .bLength          = USB_DEV_DESC_LEN,
+        .bDescriptorType  = USB_DESCTYPE_DEV
+    },
+    .bcdUSB                = 0x0200U,
+    .bDeviceClass          = 0x00U,
+    .bDeviceSubClass       = 0x00U,
+    .bDeviceProtocol       = 0x00U,
+    .bMaxPacketSize0       = USB_FS_EP0_MAX_LEN,
+    .idVendor              = USBD_VID,
+    .idProduct             = USBD_PID,
+    .bcdDevice             = 0x0100U,
+    .iManufacturer         = STR_IDX_MFC,
+    .iProduct              = STR_IDX_PRODUCT,
+    .iSerialNumber         = STR_IDX_SERIAL,
+    .bNumberConfigurations = USBD_CFG_MAX_NUM
+};
+
+/* USB device configuration descriptor */
+const usb_printer_desc_config_set printer_config_desc = {
+    .config = 
+    {
+        .header =
+        {
+            .bLength         = sizeof(usb_desc_config),
+            .bDescriptorType = USB_DESCTYPE_CONFIG
+        },
+        .wTotalLength         = USB_PRINTER_CONFIG_DESC_LEN,
+        .bNumInterfaces       = 0x01U,
+        .bConfigurationValue  = 0x01U,
+        .iConfiguration       = 0x00U,
+        .bmAttributes         = 0xA0U,
+        .bMaxPower            = 0x32U
+    },
+
+    .printer_itf =
+    {
+        .header =
+        {
+            .bLength         = sizeof(usb_desc_itf),
+            .bDescriptorType =  USB_DESCTYPE_ITF
+        },
+        .bInterfaceNumber     = 0x00U,
+        .bAlternateSetting    = 0x00U,
+        .bNumEndpoints        = 0x02U,
+        .bInterfaceClass      = USB_CLASS_PRINTER,
+        .bInterfaceSubClass   = USB_SUBCLASS_PRINTER,
+        .bInterfaceProtocol   = PROTOCOL_BI_DIRECTIONAL_ITF,
+        .iInterface           = 0x00U
+    },
+
+    .printer_epin =
+    {
+        .header =
+        {
+            .bLength         = sizeof(usb_desc_ep),
+            .bDescriptorType = USB_DESCTYPE_EP
+        },
+        .bEndpointAddress     = PRINTER_IN_EP,
+        .bmAttributes         = USB_EP_ATTR_BULK,
+        .wMaxPacketSize       = PRINTER_IN_PACKET,
+        .bInterval            = 0x00U
+    },
+
+    .printer_epout =
+    {
+        .header =
+        {
+            .bLength         = sizeof(usb_desc_ep),
+            .bDescriptorType = USB_DESCTYPE_EP
+        },
+        .bEndpointAddress     = PRINTER_OUT_EP,
+        .bmAttributes         = USB_EP_ATTR_BULK,
+        .wMaxPacketSize       = PRINTER_OUT_PACKET,
+        .bInterval            = 0x00U
+    },
+};
+
+/* USB language ID Descriptor */
+static const usb_desc_LANGID usbd_language_id_desc = {
+    .header = 
+    {
+        .bLength         = sizeof(usb_desc_LANGID),
+        .bDescriptorType = USB_DESCTYPE_STR
+    },
+    .wLANGID              = ENG_LANGID
+};
+
+/* USB manufacture string */
+static const usb_desc_str manufacturer_string = {
+    .header =
+    {
+        .bLength         = USB_STRING_LEN(10U),
+        .bDescriptorType = USB_DESCTYPE_STR
+    },
+    .unicode_string = {'G', 'i', 'g', 'a', 'D', 'e', 'v', 'i', 'c', 'e'}
+};
+
+/* USB product string */
+static const usb_desc_str product_string = {
+    .header =
+    {
+        .bLength         = USB_STRING_LEN(16U),
+        .bDescriptorType = USB_DESCTYPE_STR
+    },
+    .unicode_string = {'G', 'D', '3', '2', '-', 'U', 'S', 'B', '_', 'P', 'r', 'i', 'n', 't', 'e', 'r'}
+};
+
+/* USBD serial string */
+static usb_desc_str serial_string = {
+    .header =
+    {
+        .bLength         = USB_STRING_LEN(12U),
+        .bDescriptorType = USB_DESCTYPE_STR
+    }
+};
+
+/* USB string descriptor */
+static void *const usbd_printer_strings[] = {
+    [STR_IDX_LANGID]  = (uint8_t *)&usbd_language_id_desc,
+    [STR_IDX_MFC]     = (uint8_t *)&manufacturer_string,
+    [STR_IDX_PRODUCT] = (uint8_t *)&product_string,
+    [STR_IDX_SERIAL]  = (uint8_t *)&serial_string
+};
+
+usb_desc printer_desc = {
+    .dev_desc    = (uint8_t *)&printer_dev_desc,
+    .config_desc = (uint8_t *)&printer_config_desc,
+    .strings     = usbd_printer_strings
+};
+
+/* local function prototypes ('static') */
+static uint8_t printer_init(usb_dev *udev, uint8_t config_index);
+static uint8_t printer_deinit(usb_dev *udev, uint8_t config_index);
+static uint8_t printer_req(usb_dev *udev, usb_req *req);
+static uint8_t printer_in(usb_dev *udev, uint8_t ep_num);
+static uint8_t printer_out(usb_dev *udev, uint8_t ep_num);
+
+usb_class_core usbd_printer_cb = {
+    .init          = printer_init,
+    .deinit        = printer_deinit,
+
+    .req_proc      = printer_req,
+
+    .data_in       = printer_in,
+    .data_out      = printer_out
+};
+
+/*!
+    \brief      initialize the printer device
+    \param[in]  udev: pointer to USB device instance
+    \param[in]  config_index: configuration index
+    \param[out] none
+    \retval     USB device operation status
+*/
+static uint8_t printer_init(usb_dev *udev, uint8_t config_index)
+{
+    /* initialize the data TX endpoint */
+    usbd_ep_setup(udev, &(printer_config_desc.printer_epin));
+
+    /* initialize the data RX endpoint */
+    usbd_ep_setup(udev, &(printer_config_desc.printer_epout));
+
+    /* prepare to receive data */
+    usbd_ep_recev(udev, PRINTER_OUT_EP, g_printer_data_buf, PRINTER_OUT_PACKET);
+
+    return USBD_OK;
+}
+
+/*!
+    \brief      deinitialize the printer device
+    \param[in]  udev: pointer to USB device instance
+    \param[in]  config_index: configuration index
+    \param[out] none
+    \retval     USB device operation status
+*/
+static uint8_t printer_deinit(usb_dev *udev, uint8_t config_index)
+{
+    /* deinitialize the data TX/RX endpoint */
+    usbd_ep_clear(udev, PRINTER_IN_EP);
+    usbd_ep_clear(udev, PRINTER_OUT_EP);
+
+    return USBD_OK;
+}
+
+/*!
+    \brief      handle the printer class-specific requests
+    \param[in]  udev: pointer to USB device instance
+    \param[in]  req: device class-specific request
+    \param[out] none
+    \retval     USB device operation status
+*/
+static uint8_t printer_req(usb_dev *udev, usb_req *req)
+{
+    usb_transc *transc = &udev->dev.transc_in[0];
+
+    switch(req->bRequest) {
+    case GET_DEVICE_ID:
+        transc->xfer_buf = (uint8_t *)PRINTER_DEVICE_ID;
+        transc->remain_len = DEVICE_ID_LEN;
+        break;
+
+    case GET_PORT_STATUS:
+        transc->xfer_buf = (uint8_t *)&g_port_status;
+        transc->remain_len = 1U;
+        break;
+
+    case SOFT_RESET:
+        usbd_ep_recev(udev, PRINTER_OUT_EP, g_printer_data_buf, PRINTER_OUT_PACKET);
+        break;
+
+    default:
+        return USBD_FAIL;
+    }
+
+    return USBD_OK;
+}
+
+/*!
+    \brief      handle printer data
+    \param[in]  udev: pointer to USB device instance
+    \param[in]  ep_num: endpoint number
+    \param[out] none
+    \retval     USB device operation status
+*/
+static uint8_t printer_in(usb_dev *udev, uint8_t ep_num)
+{
+    return USBD_OK;
+}
+
+/*!
+    \brief      handle printer data
+    \param[in]  udev: pointer to USB device instance
+    \param[in]  ep_num: endpoint number
+    \param[out] none
+    \retval     USB device operation status
+*/
+static uint8_t printer_out(usb_dev *udev, uint8_t ep_num)
+{
+    return USBD_OK;
+}

+ 102 - 0
GD32F3x0/GD32F3x0_usbfs_library/device/core/Include/usbd_core.h

@@ -0,0 +1,102 @@
+/*!
+    \file    usbd_core.h
+    \brief   USB device mode core functions prototype
+
+    \version 2025-01-01, V2.5.0, firmware for GD32F3x0
+*/
+
+/*
+    Copyright (c) 2025, GigaDevice Semiconductor Inc.
+
+    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 of the copyright holder 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 HOLDER 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.
+*/
+
+#ifndef USBD_CORE_H
+#define USBD_CORE_H
+
+#include "drv_usb_core.h"
+#include "drv_usb_dev.h"
+
+typedef enum {
+    USBD_OK = 0U,                            /*!< status OK */
+    USBD_BUSY,                               /*!< status busy */
+    USBD_FAIL                                /*!< status fail */
+} usbd_status;
+
+enum _usbd_status {
+    USBD_DEFAULT    = 1U,                    /*!< default status */
+    USBD_ADDRESSED  = 2U,                    /*!< address send status */
+    USBD_CONFIGURED = 3U,                    /*!< configured status */
+    USBD_SUSPENDED  = 4U                     /*!< suspended status */
+};
+
+/* static inline function definitions */
+
+/*!
+    \brief      set USB device address
+    \param[in]  udev: pointer to USB core instance
+    \param[in]  addr: device address to set
+    \param[out] none
+    \retval     none
+*/
+__STATIC_INLINE void usbd_addr_set(usb_core_driver *udev, uint8_t addr)
+{
+    usb_devaddr_set(udev, addr);
+}
+
+/*!
+    \brief      get the received data length
+    \param[in]  udev: pointer to USB device instance
+    \param[in]  ep_num: endpoint number
+    \param[out] none
+    \retval     received data length
+*/
+__STATIC_INLINE uint16_t usbd_rxcount_get(usb_core_driver *udev, uint8_t ep_num)
+{
+    return (uint16_t)udev->dev.transc_out[ep_num].xfer_count;
+}
+
+/* function declarations */
+/* initializes the USB device-mode stack and load the class driver */
+void usbd_init(usb_core_driver *udev, usb_desc *desc, usb_class_core *class_core);
+/* endpoint initialization */
+uint32_t usbd_ep_setup(usb_core_driver *udev, const usb_desc_ep *ep_desc);
+/* configure the endpoint when it is disabled */
+uint32_t usbd_ep_clear(usb_core_driver *udev, uint8_t ep_addr);
+/* endpoint prepare to receive data */
+uint32_t usbd_ep_recev(usb_core_driver *udev, uint8_t ep_addr, uint8_t *pbuf, uint32_t len);
+/* endpoint prepare to transmit data */
+uint32_t usbd_ep_send(usb_core_driver *udev, uint8_t ep_addr, uint8_t *pbuf, uint32_t len);
+/* set an endpoint to STALL status */
+uint32_t usbd_ep_stall(usb_core_driver *udev, uint8_t ep_addr);
+/* clear endpoint STALLed status */
+uint32_t usbd_ep_stall_clear(usb_core_driver *udev, uint8_t ep_addr);
+/* flush the endpoint FIFOs */
+uint32_t usbd_fifo_flush(usb_core_driver *udev, uint8_t ep_addr);
+/* device connect */
+void usbd_connect(usb_core_driver *udev);
+/* device disconnect */
+void usbd_disconnect(usb_core_driver *udev);
+
+#endif /* USBD_CORE_H */

+ 98 - 0
GD32F3x0/GD32F3x0_usbfs_library/device/core/Include/usbd_enum.h

@@ -0,0 +1,98 @@
+/*!
+    \file    usbd_enum.h
+    \brief   USB enumeration definitions
+
+    \version 2025-01-01, V2.5.0, firmware for GD32F3x0
+*/
+
+/*
+    Copyright (c) 2025, GigaDevice Semiconductor Inc.
+
+    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 of the copyright holder 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 HOLDER 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.
+*/
+
+#ifndef USBD_ENUM_H
+#define USBD_ENUM_H
+
+#include "usbd_core.h"
+#include <wchar.h>
+
+typedef enum _usb_reqsta {
+    REQ_SUPP     = 0x0U,                   /*!< request support */
+    REQ_NOTSUPP  = 0x1U                    /*!< request not support */
+} usb_reqsta;
+
+/* string descriptor index */
+enum _str_index {
+    STR_IDX_LANGID                = 0x00U, /*!< language ID string index */
+    STR_IDX_MFC                   = 0x01U, /*!< manufacturer string index */
+    STR_IDX_PRODUCT               = 0x02U, /*!< product string index */
+    STR_IDX_SERIAL                = 0x03U, /*!< serial string index */
+    STR_IDX_CONFIG                = 0x04U, /*!< configuration string index */
+    STR_IDX_ITF                   = 0x05U, /*!< interface string index */
+#ifndef WINUSB_EXEMPT_DRIVER
+    STR_IDX_MAX                   = 0x0AU, /*!< string maximum index */
+#else
+    STR_IDX_MAX                   = 0xEFU  /*!< string maximum index */
+#endif /* WINUSB_EXEMPT_DRIVER */
+};
+
+typedef enum _usb_pwrsta {
+    USB_PWRSTA_SELF_POWERED       = 0x1U,  /*!< USB is in self powered status */
+    USB_PWRSTA_REMOTE_WAKEUP      = 0x2U   /*!< USB is in remote wakeup status */
+} usb_pwrsta;
+
+typedef enum _usb_feature {
+    USB_FEATURE_EP_HALT           = 0x0U,  /*!< USB has endpoint halt feature */
+    USB_FEATURE_REMOTE_WAKEUP     = 0x1U,  /*!< USB has endpoint remote wakeup feature */
+    USB_FEATURE_TEST_MODE         = 0x2U   /*!< USB has endpoint test mode feature */
+} usb_feature;
+
+#define ENG_LANGID                0x0409U  /*!< english language ID */
+#define CHN_LANGID                0x0804U  /*!< chinese language ID */
+
+/* USB device exported macros */
+#define CTL_EP(ep)                ((0x00U == (ep)) || (0x80U == (ep)))
+
+#define DEVICE_ID1                (0x1FFFF7E8U)  /*!< device ID1 */
+#define DEVICE_ID2                (0x1FFFF7ECU)  /*!< device ID2 */
+#define DEVICE_ID3                (0x1FFFF7F0U)  /*!< device ID3 */
+
+#define DEVICE_ID                 (0x40022100U)  /*!< product reserved ID */
+
+/* function declarations */
+/* handle USB standard device request */
+usb_reqsta usbd_standard_request(usb_core_driver *udev, usb_req *req);
+/* handle USB device class request */
+usb_reqsta usbd_class_request(usb_core_driver *udev, usb_req *req);
+/* handle USB vendor request */
+usb_reqsta usbd_vendor_request(usb_core_driver *udev, usb_req *req);
+/* handle USB enumeration error */
+void usbd_enum_error(usb_core_driver *udev, usb_req *req);
+/* convert hex 32bits value into unicode char */
+void int_to_unicode(uint32_t value, uint8_t *pbuf, uint8_t len);
+/* get serial string */
+void serial_string_get(uint16_t *unicode_str);
+
+#endif /* USBD_ENUM_H */

+ 56 - 0
GD32F3x0/GD32F3x0_usbfs_library/device/core/Include/usbd_transc.h

@@ -0,0 +1,56 @@
+/*!
+    \file    usbd_transc.h
+    \brief   USB transaction core functions prototype
+
+    \version 2025-01-01, V2.5.0, firmware for GD32F3x0
+*/
+
+/*
+    Copyright (c) 2025, GigaDevice Semiconductor Inc.
+
+    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 of the copyright holder 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 HOLDER 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.
+*/
+
+#ifndef USBD_TRANSC_H
+#define USBD_TRANSC_H
+
+#include "usbd_core.h"
+
+/* function declarations */
+/* USB send data in the control transaction */
+usbd_status usbd_ctl_send(usb_core_driver *udev);
+/* USB receive data in the control transaction */
+usbd_status usbd_ctl_recev(usb_core_driver *udev);
+/* USB send control transaction status */
+usbd_status usbd_ctl_status_send(usb_core_driver *udev);
+/* USB control receive status */
+usbd_status usbd_ctl_status_recev(usb_core_driver *udev);
+/* USB SETUP stage processing */
+uint8_t usbd_setup_transc(usb_core_driver *udev);
+/* data OUT stage processing */
+uint8_t usbd_out_transc(usb_core_driver *udev, uint8_t ep_num);
+/* data IN stage processing */
+uint8_t usbd_in_transc(usb_core_driver *udev, uint8_t ep_num);
+
+#endif /* USBD_TRANSC_H */

+ 311 - 0
GD32F3x0/GD32F3x0_usbfs_library/device/core/Source/usbd_core.c

@@ -0,0 +1,311 @@
+/*!
+    \file    usbd_core.c
+    \brief   USB device mode core functions
+
+    \version 2025-01-01, V2.5.0, firmware for GD32F3x0
+*/
+
+/*
+    Copyright (c) 2025, GigaDevice Semiconductor Inc.
+
+    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 of the copyright holder 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 HOLDER 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.
+*/
+
+#include "usbd_core.h"
+#include "usbd_enum.h"
+#include "drv_usb_hw.h"
+
+/* endpoint type */
+const uint32_t ep_type[] = {
+    [USB_EP_ATTR_CTL]  = (uint32_t)USB_EPTYPE_CTRL,
+    [USB_EP_ATTR_BULK] = (uint32_t)USB_EPTYPE_BULK,
+    [USB_EP_ATTR_INT]  = (uint32_t)USB_EPTYPE_INTR,
+    [USB_EP_ATTR_ISO]  = (uint32_t)USB_EPTYPE_ISOC
+};
+
+/*!
+    \brief      initializes the USB device-mode stack and load the class driver
+    \param[in]  udev: pointer to USB core instance
+    \param[in]  desc: pointer to USB descriptor
+    \param[in]  class_core: class driver
+    \param[out] none
+    \retval     none
+*/
+void usbd_init(usb_core_driver *udev, usb_desc *desc, usb_class_core *class_core)
+{
+    udev->dev.desc = desc;
+
+    /* class callbacks */
+    udev->dev.class_core = class_core;
+
+    /* create serial string */
+    serial_string_get(udev->dev.desc->strings[STR_IDX_SERIAL]);
+
+    /* configure USB capabilities */
+    (void)usb_basic_init(&udev->bp, &udev->regs);
+
+    usb_globalint_disable(&udev->regs);
+
+    /* initializes the USB core*/
+    (void)usb_core_init(udev->bp, &udev->regs);
+
+    /* set device disconnect */
+    usbd_disconnect(udev);
+
+#ifndef USE_OTG_MODE
+    usb_curmode_set(&udev->regs, DEVICE_MODE);
+#endif /* USE_OTG_MODE */
+
+    /* initializes device mode */
+    (void)usb_devcore_init(udev);
+
+    usb_globalint_enable(&udev->regs);
+
+    /* set device connect */
+    usbd_connect(udev);
+
+    udev->dev.cur_status = (uint8_t)USBD_DEFAULT;
+}
+
+/*!
+    \brief      endpoint initialization
+    \param[in]  udev: pointer to USB core instance
+    \param[in]  ep_desc: pointer to endpoint descriptor
+    \param[out] none
+    \retval     none
+*/
+uint32_t usbd_ep_setup(usb_core_driver *udev, const usb_desc_ep *ep_desc)
+{
+    usb_transc *transc;
+
+    uint8_t ep_addr = ep_desc->bEndpointAddress;
+    uint16_t max_len = ep_desc->wMaxPacketSize & EP_MAX_PACKET_SIZE_MASK;
+
+    /* set endpoint direction */
+    if(EP_DIR(ep_addr)) {
+        transc = &udev->dev.transc_in[EP_ID(ep_addr)];
+
+        transc->ep_addr.dir = 1U;
+    } else {
+        transc = &udev->dev.transc_out[ep_addr];
+
+        transc->ep_addr.dir = 0U;
+    }
+
+    transc->ep_addr.num = EP_ID(ep_addr);
+    transc->max_len = max_len;
+    transc->ep_type = (uint8_t)ep_type[ep_desc->bmAttributes & (uint8_t)USB_EPTYPE_MASK];
+
+    /* active USB endpoint function */
+    (void)usb_transc_active(udev, transc);
+
+    return 0U;
+}
+
+/*!
+    \brief      configure the endpoint when it is disabled
+    \param[in]  udev: pointer to USB core instance
+    \param[in]  ep_addr: endpoint address
+                  in this parameter:
+                    bit0..bit6: endpoint number (0..7)
+                    bit7: endpoint direction which can be IN(1) or OUT(0)
+    \param[out] none
+    \retval     none
+*/
+uint32_t usbd_ep_clear(usb_core_driver *udev, uint8_t ep_addr)
+{
+    usb_transc *transc;
+
+    if(EP_DIR(ep_addr)) {
+        transc = &udev->dev.transc_in[EP_ID(ep_addr)];
+    } else {
+        transc = &udev->dev.transc_out[ep_addr];
+    }
+
+    /* deactivate USB endpoint function */
+    (void)usb_transc_deactivate(udev, transc);
+
+    return 0U;
+}
+
+/*!
+    \brief      endpoint prepare to receive data
+    \param[in]  udev: pointer to USB core instance
+    \param[in]  ep_addr: endpoint address
+                  in this parameter:
+                    bit0..bit6: endpoint number (0..7)
+                    bit7: endpoint direction which can be IN(1) or OUT(0)
+    \param[in]  pbuf: user buffer address pointer
+    \param[in]  len: buffer length
+    \param[out] none
+    \retval     none
+*/
+uint32_t usbd_ep_recev(usb_core_driver *udev, uint8_t ep_addr, uint8_t *pbuf, uint32_t len)
+{
+    usb_transc *transc = &udev->dev.transc_out[EP_ID(ep_addr)];
+
+    /* setup the transfer */
+    transc->xfer_buf = pbuf;
+    transc->xfer_len = len;
+    transc->xfer_count = 0U;
+
+    /* start the transfer */
+    (void)usb_transc_outxfer(udev, transc);
+
+    return 0U;
+}
+
+/*!
+    \brief      endpoint prepare to transmit data
+    \param[in]  udev: pointer to USB core instance
+    \param[in]  ep_addr: endpoint address
+                  in this parameter:
+                    bit0..bit6: endpoint number (0..7)
+                    bit7: endpoint direction which can be IN(1) or OUT(0)
+    \param[in]  pbuf: transmit buffer address pointer
+    \param[in]  len: buffer length
+    \param[out] none
+    \retval     none
+*/
+uint32_t usbd_ep_send(usb_core_driver *udev, uint8_t ep_addr, uint8_t *pbuf, uint32_t len)
+{
+    usb_transc *transc = &udev->dev.transc_in[EP_ID(ep_addr)];
+
+    /* setup the transfer */
+    transc->xfer_buf = pbuf;
+    transc->xfer_len = len;
+    transc->xfer_count = 0U;
+
+    /* start the transfer */
+    (void)usb_transc_inxfer(udev, transc);
+
+    return 0U;
+}
+
+/*!
+    \brief      set an endpoint to STALL status
+    \param[in]  udev: pointer to USB core instance
+    \param[in]  ep_addr: endpoint address
+                  in this parameter:
+                    bit0..bit6: endpoint number (0..7)
+                    bit7: endpoint direction which can be IN(1) or OUT(0)
+    \param[out] none
+    \retval     none
+*/
+uint32_t usbd_ep_stall(usb_core_driver *udev, uint8_t ep_addr)
+{
+    usb_transc *transc = NULL;
+
+    if(EP_DIR(ep_addr)) {
+        transc = &udev->dev.transc_in[EP_ID(ep_addr)];
+    } else {
+        transc = &udev->dev.transc_out[ep_addr];
+    }
+
+    transc->ep_stall = 1U;
+
+    (void)usb_transc_stall(udev, transc);
+
+    return (0U);
+}
+
+/*!
+    \brief      clear endpoint STALLed status
+    \param[in]  udev: pointer to USB core instance
+    \param[in]  ep_addr: endpoint address
+                  in this parameter:
+                    bit0..bit6: endpoint number (0..7)
+                    bit7: endpoint direction which can be IN(1) or OUT(0)
+    \param[out] none
+    \retval     none
+*/
+uint32_t usbd_ep_stall_clear(usb_core_driver *udev, uint8_t ep_addr)
+{
+    usb_transc *transc = NULL;
+
+    if(EP_DIR(ep_addr)) {
+        transc = &udev->dev.transc_in[EP_ID(ep_addr)];
+    } else {
+        transc = &udev->dev.transc_out[ep_addr];
+    }
+
+    transc->ep_stall = 0U;
+
+    (void)usb_transc_clrstall(udev, transc);
+
+    return (0U);
+}
+
+/*!
+    \brief      flush the endpoint FIFOs
+    \param[in]  udev: pointer to USB core instance
+    \param[in]  ep_addr: endpoint address
+                  in this parameter:
+                    bit0..bit6: endpoint number (0..7)
+                    bit7: endpoint direction which can be IN(1) or OUT(0)
+    \param[out] none
+    \retval     none
+*/
+uint32_t usbd_fifo_flush(usb_core_driver *udev, uint8_t ep_addr)
+{
+    if(EP_DIR(ep_addr)) {
+        (void)usb_txfifo_flush(&udev->regs, EP_ID(ep_addr));
+    } else {
+        (void)usb_rxfifo_flush(&udev->regs);
+    }
+
+    return (0U);
+}
+
+/*!
+    \brief      device connect
+    \param[in]  udev: pointer to USB device instance
+    \param[out] none
+    \retval     none
+*/
+void usbd_connect(usb_core_driver *udev)
+{
+#ifndef USE_OTG_MODE
+    /* connect device */
+    usb_dev_connect(udev);
+
+    usb_mdelay(3U);
+#endif /* USE_OTG_MODE */
+}
+
+/*!
+    \brief      device disconnect
+    \param[in]  udev: pointer to USB device instance
+    \param[out] none
+    \retval     none
+*/
+void usbd_disconnect(usb_core_driver *udev)
+{
+#ifndef USE_OTG_MODE
+    /* disconnect device for 3ms */
+    usb_dev_disconnect(udev);
+
+    usb_mdelay(3U);
+#endif /* USE_OTG_MODE */
+}

+ 762 - 0
GD32F3x0/GD32F3x0_usbfs_library/device/core/Source/usbd_enum.c

@@ -0,0 +1,762 @@
+/*!
+    \file    usbd_enum.c
+    \brief   USB enumeration function
+
+    \version 2025-01-01, V2.5.0, firmware for GD32F3x0
+*/
+
+/*
+    Copyright (c) 2025, GigaDevice Semiconductor Inc.
+
+    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 of the copyright holder 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 HOLDER 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.
+*/
+
+#include "usbd_enum.h"
+
+#ifdef WINUSB_EXEMPT_DRIVER
+
+extern usbd_status usbd_OEM_req(usb_dev *udev, usb_req *req);
+
+#endif /* WINUSB_EXEMPT_DRIVER */
+
+/* local function prototypes ('static') */
+static usb_reqsta _usb_std_reserved(usb_core_driver *udev, usb_req *req);
+static uint8_t *_usb_dev_desc_get(usb_core_driver *udev, uint8_t index, uint16_t *len);
+static uint8_t *_usb_config_desc_get(usb_core_driver *udev, uint8_t index, uint16_t *len);
+static uint8_t *_usb_bos_desc_get(usb_core_driver *udev, uint8_t index, uint16_t *len);
+static uint8_t *_usb_str_desc_get(usb_core_driver *udev, uint8_t index, uint16_t *len);
+static usb_reqsta _usb_std_getstatus(usb_core_driver *udev, usb_req *req);
+static usb_reqsta _usb_std_clearfeature(usb_core_driver *udev, usb_req *req);
+static usb_reqsta _usb_std_setfeature(usb_core_driver *udev, usb_req *req);
+static usb_reqsta _usb_std_setaddress(usb_core_driver *udev, usb_req *req);
+static usb_reqsta _usb_std_getdescriptor(usb_core_driver *udev, usb_req *req);
+static usb_reqsta _usb_std_setdescriptor(usb_core_driver *udev, usb_req *req);
+static usb_reqsta _usb_std_getconfiguration(usb_core_driver *udev, usb_req *req);
+static usb_reqsta _usb_std_setconfiguration(usb_core_driver *udev, usb_req *req);
+static usb_reqsta _usb_std_getinterface(usb_core_driver *udev, usb_req *req);
+static usb_reqsta _usb_std_setinterface(usb_core_driver *udev, usb_req *req);
+static usb_reqsta _usb_std_synchframe(usb_core_driver *udev, usb_req *req);
+
+static usb_reqsta(*_std_dev_req[])(usb_core_driver *udev, usb_req *req) = {
+    [USB_GET_STATUS]        = _usb_std_getstatus,
+    [USB_CLEAR_FEATURE]     = _usb_std_clearfeature,
+    [USB_RESERVED2]         = _usb_std_reserved,
+    [USB_SET_FEATURE]       = _usb_std_setfeature,
+    [USB_RESERVED4]         = _usb_std_reserved,
+    [USB_SET_ADDRESS]       = _usb_std_setaddress,
+    [USB_GET_DESCRIPTOR]    = _usb_std_getdescriptor,
+    [USB_SET_DESCRIPTOR]    = _usb_std_setdescriptor,
+    [USB_GET_CONFIGURATION] = _usb_std_getconfiguration,
+    [USB_SET_CONFIGURATION] = _usb_std_setconfiguration,
+    [USB_GET_INTERFACE]     = _usb_std_getinterface,
+    [USB_SET_INTERFACE]     = _usb_std_setinterface,
+    [USB_SYNCH_FRAME]       = _usb_std_synchframe,
+};
+
+/* get standard descriptor handler */
+static uint8_t *(*std_desc_get[])(usb_core_driver *udev, uint8_t index, uint16_t *len) = {
+    [(uint8_t)USB_DESCTYPE_DEV - 1U]              = _usb_dev_desc_get,
+    [(uint8_t)USB_DESCTYPE_CONFIG - 1U]           = _usb_config_desc_get,
+    [(uint8_t)USB_DESCTYPE_STR - 1U]              = _usb_str_desc_get
+};
+
+/*!
+    \brief      handle USB standard device request
+    \param[in]  udev: pointer to USB device instance
+    \param[in]  req: pointer to USB device request
+    \param[out] none
+    \retval     USB device request status
+*/
+usb_reqsta usbd_standard_request(usb_core_driver *udev, usb_req *req)
+{
+    return (*_std_dev_req[req->bRequest])(udev, req);
+}
+
+/*!
+    \brief      handle USB device class request
+    \param[in]  udev: pointer to USB device instance
+    \param[in]  req: pointer to USB device class request
+    \param[out] none
+    \retval     USB device request status
+*/
+usb_reqsta usbd_class_request(usb_core_driver *udev, usb_req *req)
+{
+    if((uint8_t)USBD_CONFIGURED == udev->dev.cur_status) {
+        if(BYTE_LOW(req->wIndex) <= USBD_ITF_MAX_NUM) {
+            /* call device class handle function */
+            return (usb_reqsta)udev->dev.class_core->req_proc(udev, req);
+        }
+    }
+
+    return REQ_NOTSUPP;
+}
+
+/*!
+    \brief      handle USB vendor request
+    \param[in]  udev: pointer to USB device instance
+    \param[in]  req: pointer to USB vendor request
+    \param[out] none
+    \retval     USB device request status
+*/
+usb_reqsta usbd_vendor_request(usb_core_driver *udev, usb_req *req)
+{
+    (void)udev;
+    (void)req;
+
+    /* added by user... */
+#ifdef WINUSB_EXEMPT_DRIVER
+    usbd_OEM_req(udev, req);
+#endif
+
+    return REQ_SUPP;
+}
+
+/*!
+    \brief      handle USB enumeration error
+    \param[in]  udev: pointer to USB device instance
+    \param[in]  req: pointer to USB device request
+    \param[out] none
+    \retval     none
+*/
+void usbd_enum_error(usb_core_driver *udev, usb_req *req)
+{
+    (void)req;
+
+    (void)usbd_ep_stall(udev, 0x80U);
+    (void)usbd_ep_stall(udev, 0x00U);
+
+    usb_ctlep_startout(udev);
+}
+
+/*!
+    \brief      convert hex 32bits value into unicode char
+    \param[in]  value: hex 32bits value
+    \param[in]  pbuf: buffer pointer to store unicode char
+    \param[in]  len: value length
+    \param[out] none
+    \retval     none
+*/
+void int_to_unicode(uint32_t value, uint8_t *pbuf, uint8_t len)
+{
+    uint8_t index;
+
+    for(index = 0U; index < len; index++) {
+        if((value >> 28) < 0x0AU) {
+            pbuf[2 * index] = (uint8_t)((value >> 28) + '0');
+        } else {
+            pbuf[2 * index] = (uint8_t)((value >> 28) + 'A' - 10U);
+        }
+
+        value = value << 4;
+
+        pbuf[2U * index + 1U] = 0U;
+    }
+}
+
+/*!
+    \brief      convert hex 32bits value into unicode char
+    \param[in]  unicode_str: pointer to unicode string
+    \param[out] none
+    \retval     none
+*/
+void serial_string_get(uint16_t *unicode_str)
+{
+    if(6U != (unicode_str[0] & 0x00FFU)) {
+        uint32_t DeviceSerial0, DeviceSerial1, DeviceSerial2;
+
+        DeviceSerial0 = *(uint32_t *)DEVICE_ID1;
+        DeviceSerial1 = *(uint32_t *)DEVICE_ID2;
+        DeviceSerial2 = *(uint32_t *)DEVICE_ID3;
+
+        DeviceSerial0 += DeviceSerial2;
+
+        if(0U != DeviceSerial0) {
+            int_to_unicode(DeviceSerial0, (uint8_t *)&(unicode_str[1]), 8U);
+            int_to_unicode(DeviceSerial1, (uint8_t *)&(unicode_str[9]), 4U);
+        }
+    } else {
+        uint32_t device_serial = *(uint32_t *)DEVICE_ID;
+
+        if(0U != device_serial) {
+            unicode_str[1] = (uint16_t)(device_serial & 0x0000FFFFU);
+            unicode_str[2] = (uint16_t)((device_serial & 0xFFFF0000U) >> 16);
+
+        }
+    }
+}
+
+/*!
+    \brief      no operation, just for reserved
+    \param[in]  udev: pointer to USB device instance
+    \param[in]  req: pointer to USB vendor request
+    \param[out] none
+    \retval     USB device request status
+*/
+static usb_reqsta _usb_std_reserved(usb_core_driver *udev, usb_req *req)
+{
+    (void)udev;
+    (void)req;
+
+    /* no operation... */
+
+    return REQ_NOTSUPP;
+}
+
+/*!
+    \brief      get the device descriptor
+    \param[in]  udev: pointer to USB device instance
+    \param[in]  index: no use
+    \param[out] len: data length pointer
+    \retval     descriptor buffer pointer
+*/
+static uint8_t *_usb_dev_desc_get(usb_core_driver *udev, uint8_t index, uint16_t *len)
+{
+    (void)index;
+
+    *len = udev->dev.desc->dev_desc[0];
+
+    return udev->dev.desc->dev_desc;
+}
+
+/*!
+    \brief      get the configuration descriptor
+    \brief[in]  udev: pointer to USB device instance
+    \brief[in]  index: no use
+    \param[out] len: data length pointer
+    \retval     descriptor buffer pointer
+*/
+static uint8_t *_usb_config_desc_get(usb_core_driver *udev, uint8_t index, uint16_t *len)
+{
+    (void)index;
+
+    *len = udev->dev.desc->config_desc[2] | (udev->dev.desc->config_desc[3] << 8);
+
+    return udev->dev.desc->config_desc;
+}
+
+/*!
+    \brief      get the BOS descriptor
+    \brief[in]  udev: pointer to USB device instance
+    \brief[in]  index: no use
+    \param[out] len: data length pointer
+    \retval     descriptor buffer pointer
+*/
+static uint8_t *_usb_bos_desc_get(usb_core_driver *udev, uint8_t index, uint16_t *len)
+{
+    (void)index;
+
+    *len = udev->dev.desc->bos_desc[2];
+
+    return udev->dev.desc->bos_desc;
+}
+
+/*!
+    \brief      get string descriptor
+    \param[in]  udev: pointer to USB device instance
+    \param[in]  index: string descriptor index
+    \param[out] len: pointer to string length
+    \retval     descriptor buffer pointer
+*/
+static uint8_t *_usb_str_desc_get(usb_core_driver *udev, uint8_t index, uint16_t *len)
+{
+    uint8_t *desc = udev->dev.desc->strings[index];
+
+    *len = desc[0];
+
+    return desc;
+}
+
+/*!
+    \brief      handle Get_Status request
+    \param[in]  udev: pointer to USB device instance
+    \param[in]  req: pointer to USB device request
+    \param[out] none
+    \retval     USB device request status
+*/
+static usb_reqsta _usb_std_getstatus(usb_core_driver *udev, usb_req *req)
+{
+    uint8_t recp = BYTE_LOW(req->wIndex);
+    usb_reqsta req_status = REQ_NOTSUPP;
+    usb_transc *transc = &udev->dev.transc_in[0];
+
+    static uint8_t status[2] = {0};
+
+    switch(req->bmRequestType & (uint8_t)USB_RECPTYPE_MASK) {
+    case USB_RECPTYPE_DEV:
+        if(((uint8_t)USBD_ADDRESSED == udev->dev.cur_status) || \
+                ((uint8_t)USBD_CONFIGURED == udev->dev.cur_status)) {
+
+            if(udev->dev.pm.power_mode) {
+                status[0] = USB_STATUS_SELF_POWERED;
+            } else {
+                status[0] = 0U;
+            }
+
+            if(udev->dev.pm.dev_remote_wakeup) {
+                status[0] |= USB_STATUS_REMOTE_WAKEUP;
+            } else {
+                status[0] = 0U;
+            }
+
+            req_status = REQ_SUPP;
+        }
+        break;
+
+    case USB_RECPTYPE_ITF:
+        if(((uint8_t)USBD_CONFIGURED == udev->dev.cur_status) && (recp <= USBD_ITF_MAX_NUM)) {
+            req_status = REQ_SUPP;
+        }
+        break;
+
+    case USB_RECPTYPE_EP:
+        if((uint8_t)USBD_CONFIGURED == udev->dev.cur_status) {
+            if(0x80U == (recp & 0x80U)) {
+                status[0] = udev->dev.transc_in[EP_ID(recp)].ep_stall;
+            } else {
+                status[0] = udev->dev.transc_out[recp].ep_stall;
+            }
+
+            req_status = REQ_SUPP;
+        }
+        break;
+
+    default:
+        break;
+    }
+
+    if(REQ_SUPP == req_status) {
+        transc->xfer_buf = status;
+        transc->remain_len = 2U;
+    }
+
+    return req_status;
+}
+
+/*!
+    \brief      handle USB Clear_Feature request
+    \param[in]  udev: pointer to USB device instance
+    \param[in]  req: USB device request
+    \param[out] none
+    \retval     USB device request status
+*/
+static usb_reqsta _usb_std_clearfeature(usb_core_driver *udev, usb_req *req)
+{
+    uint8_t ep = 0U;
+
+    switch(req->bmRequestType & (uint8_t)USB_RECPTYPE_MASK) {
+    case USB_RECPTYPE_DEV:
+        if(((uint8_t)USBD_ADDRESSED == udev->dev.cur_status) || \
+                ((uint8_t)USBD_CONFIGURED == udev->dev.cur_status)) {
+
+            /* clear device remote wakeup feature */
+            if((uint16_t)USB_FEATURE_REMOTE_WAKEUP == req->wValue) {
+                udev->dev.pm.dev_remote_wakeup = 0U;
+
+                return REQ_SUPP;
+            }
+        }
+        break;
+
+    case USB_RECPTYPE_ITF:
+        break;
+
+    case USB_RECPTYPE_EP:
+        /* get endpoint address */
+        ep = BYTE_LOW(req->wIndex);
+
+        if((uint8_t)USBD_CONFIGURED == udev->dev.cur_status) {
+            /* clear endpoint halt feature */
+            if(((uint16_t)USB_FEATURE_EP_HALT == req->wValue) && (!CTL_EP(ep))) {
+                (void)usbd_ep_stall_clear(udev, ep);
+
+                (void)udev->dev.class_core->req_proc(udev, req);
+            }
+
+            return REQ_SUPP;
+        }
+        break;
+
+    default:
+        break;
+    }
+
+    return REQ_NOTSUPP;
+}
+
+/*!
+    \brief      handle USB Set_Feature request
+    \param[in]  udev: pointer to USB device instance
+    \param[in]  req: pointer to USB device request
+    \param[out] none
+    \retval     USB device request status
+*/
+static usb_reqsta _usb_std_setfeature(usb_core_driver *udev, usb_req *req)
+{
+    uint8_t ep = 0U;
+
+    switch(req->bmRequestType & (uint8_t)USB_RECPTYPE_MASK) {
+    case USB_RECPTYPE_DEV:
+        if(((uint8_t)USBD_ADDRESSED == udev->dev.cur_status) || \
+                ((uint8_t)USBD_CONFIGURED == udev->dev.cur_status)) {
+            /* set device remote wakeup feature */
+            if((uint16_t)USB_FEATURE_REMOTE_WAKEUP == req->wValue) {
+                udev->dev.pm.dev_remote_wakeup = 1U;
+            }
+
+            return REQ_SUPP;
+        }
+        break;
+
+    case USB_RECPTYPE_ITF:
+        break;
+
+    case USB_RECPTYPE_EP:
+        /* get endpoint address */
+        ep = BYTE_LOW(req->wIndex);
+
+        if((uint8_t)USBD_CONFIGURED == udev->dev.cur_status) {
+            /* set endpoint halt feature */
+            if(((uint16_t)USB_FEATURE_EP_HALT == req->wValue) && (!CTL_EP(ep))) {
+                (void)usbd_ep_stall(udev, ep);
+            }
+
+            return REQ_SUPP;
+        }
+        break;
+
+    default:
+        break;
+    }
+
+    return REQ_NOTSUPP;
+}
+
+/*!
+    \brief      handle USB Set_Address request
+    \param[in]  udev: pointer to USB device instance
+    \param[in]  req: pointer to USB device request
+    \param[out] none
+    \retval     USB device request status
+*/
+static usb_reqsta _usb_std_setaddress(usb_core_driver *udev, usb_req *req)
+{
+    if((0U == req->wIndex) && (0U == req->wLength)) {
+        udev->dev.dev_addr = (uint8_t)(req->wValue) & 0x7FU;
+
+        if((uint8_t)USBD_CONFIGURED != udev->dev.cur_status) {
+            usbd_addr_set(udev, udev->dev.dev_addr);
+
+            if(udev->dev.dev_addr) {
+                udev->dev.cur_status = (uint8_t)USBD_ADDRESSED;
+            } else {
+                udev->dev.cur_status = (uint8_t)USBD_DEFAULT;
+            }
+
+            return REQ_SUPP;
+        }
+    }
+
+    return REQ_NOTSUPP;
+}
+
+/*!
+    \brief      handle USB Get_Descriptor request
+    \param[in]  udev: pointer to USB device instance
+    \param[in]  req: pointer to USB device request
+    \param[out] none
+    \retval     USB device request status
+*/
+static usb_reqsta _usb_std_getdescriptor(usb_core_driver *udev, usb_req *req)
+{
+    uint8_t desc_type = 0U;
+    uint8_t desc_index = 0U;
+
+    usb_reqsta status = REQ_NOTSUPP;
+
+    usb_transc *transc = &udev->dev.transc_in[0];
+
+    /* get device standard descriptor */
+    switch(req->bmRequestType & USB_RECPTYPE_MASK) {
+    case USB_RECPTYPE_DEV:
+        desc_type = BYTE_HIGH(req->wValue);
+        desc_index = BYTE_LOW(req->wValue);
+
+        switch(desc_type) {
+        case USB_DESCTYPE_DEV:
+            transc->xfer_buf = std_desc_get[desc_type - 1U](udev, desc_index, (uint16_t *)&(transc->remain_len));
+
+            if(64U == req->wLength) {
+                transc->remain_len = 8U;
+            }
+            break;
+
+        case USB_DESCTYPE_CONFIG:
+            transc->xfer_buf = std_desc_get[desc_type - 1U](udev, desc_index, (uint16_t *)&(transc->remain_len));
+            break;
+
+        case USB_DESCTYPE_STR:
+            if(desc_index < (uint8_t)STR_IDX_MAX) {
+                transc->xfer_buf = std_desc_get[desc_type - 1U](udev, desc_index, (uint16_t *)&(transc->remain_len));
+            }
+            break;
+
+        case USB_DESCTYPE_ITF:
+        case USB_DESCTYPE_EP:
+        case USB_DESCTYPE_DEV_QUALIFIER:
+        case USB_DESCTYPE_OTHER_SPD_CONFIG:
+        case USB_DESCTYPE_ITF_POWER:
+            break;
+
+        case USB_DESCTYPE_BOS:
+            transc->xfer_buf = _usb_bos_desc_get(udev, desc_index, (uint16_t *)&(transc->remain_len));
+            break;
+
+        default:
+            break;
+        }
+        break;
+
+    case USB_RECPTYPE_ITF:
+        /* get device class special descriptor */
+        status = (usb_reqsta)(udev->dev.class_core->req_proc(udev, req));
+        break;
+
+    case USB_RECPTYPE_EP:
+        break;
+
+    default:
+        break;
+    }
+
+    if((0U != transc->remain_len) && (0U != req->wLength)) {
+        if(transc->remain_len < req->wLength) {
+            if((transc->remain_len >= transc->max_len) && (0U == (transc->remain_len % transc->max_len))) {
+                udev->dev.control.ctl_zlp = 1U;
+            }
+        } else {
+            transc->remain_len = req->wLength;
+        }
+
+        status = REQ_SUPP;
+    }
+
+    return status;
+}
+
+/*!
+    \brief      handle USB Set_Descriptor request
+    \param[in]  udev: pointer to USB device instance
+    \param[in]  req: pointer to USB device request
+    \param[out] none
+    \retval     USB device request status
+*/
+static usb_reqsta _usb_std_setdescriptor(usb_core_driver *udev, usb_req *req)
+{
+    (void)udev;
+    (void)req;
+
+    /* no handle... */
+    return REQ_SUPP;
+}
+
+/*!
+    \brief      handle USB Get_Configuration request
+    \param[in]  udev: pointer to USB device instance
+    \param[in]  req: pointer to USB device request
+    \param[out] none
+    \retval     USB device request status
+*/
+static usb_reqsta _usb_std_getconfiguration(usb_core_driver *udev, usb_req *req)
+{
+    (void)req;
+
+    usb_reqsta req_status = REQ_NOTSUPP;
+    usb_transc *transc = &udev->dev.transc_in[0];
+
+    switch(udev->dev.cur_status) {
+    case USBD_ADDRESSED:
+        if(USB_DEFAULT_CONFIG == udev->dev.config) {
+            req_status = REQ_SUPP;
+        }
+        break;
+
+    case USBD_CONFIGURED:
+        if(USB_DEFAULT_CONFIG != udev->dev.config) {
+            req_status = REQ_SUPP;
+        }
+        break;
+
+    default:
+        break;
+    }
+
+    if(REQ_SUPP == req_status) {
+        transc->xfer_buf = &(udev->dev.config);
+        transc->remain_len = 1U;
+    }
+
+    return req_status;
+}
+
+/*!
+    \brief      handle USB Set_Configuration request
+    \param[in]  udev: pointer to USB device instance
+    \param[in]  req: pointer to USB device request
+    \param[out] none
+    \retval     USB device request status
+*/
+static usb_reqsta _usb_std_setconfiguration(usb_core_driver *udev, usb_req *req)
+{
+    static uint8_t config;
+    usb_reqsta status = REQ_NOTSUPP;
+
+    config = (uint8_t)(req->wValue);
+
+    if(config <= USBD_CFG_MAX_NUM) {
+        switch(udev->dev.cur_status) {
+        case USBD_ADDRESSED:
+            if(config) {
+                (void)udev->dev.class_core->init(udev, config);
+
+                udev->dev.config = config;
+                udev->dev.cur_status = (uint8_t)USBD_CONFIGURED;
+            }
+
+            status = REQ_SUPP;
+            break;
+
+        case USBD_CONFIGURED:
+            if(USB_DEFAULT_CONFIG == config) {
+                (void)udev->dev.class_core->deinit(udev, config);
+
+                udev->dev.config = config;
+                udev->dev.cur_status = (uint8_t)USBD_ADDRESSED;
+            } else if(config != udev->dev.config) {
+                /* clear old configuration */
+                (void)udev->dev.class_core->deinit(udev, config);
+
+                /* set new configuration */
+                udev->dev.config = config;
+
+                (void)udev->dev.class_core->init(udev, config);
+            } else {
+                /* no operation */
+            }
+
+            status = REQ_SUPP;
+            break;
+
+        case USBD_DEFAULT:
+            break;
+
+        default:
+            break;
+        }
+    }
+
+    return status;
+}
+
+/*!
+    \brief      handle USB Get_Interface request
+    \param[in]  udev: pointer to USB device instance
+    \param[in]  req: pointer to USB device request
+    \param[out] none
+    \retval     USB device request status
+*/
+static usb_reqsta _usb_std_getinterface(usb_core_driver *udev, usb_req *req)
+{
+    switch(udev->dev.cur_status) {
+    case USBD_DEFAULT:
+        break;
+
+    case USBD_ADDRESSED:
+        break;
+
+    case USBD_CONFIGURED:
+        if(BYTE_LOW(req->wIndex) <= USBD_ITF_MAX_NUM) {
+            usb_transc *transc = &udev->dev.transc_in[0];
+
+            transc->xfer_buf = &(udev->dev.class_core->alter_set);
+            transc->remain_len = 1U;
+
+            return REQ_SUPP;
+        }
+        break;
+
+    default:
+        break;
+    }
+
+    return REQ_NOTSUPP;
+}
+
+/*!
+    \brief      handle USB Set_Interface request
+    \param[in]  udev: pointer to USB device instance
+    \param[in]  req: pointer to USB device request
+    \param[out] none
+    \retval     USB device request status
+*/
+static usb_reqsta _usb_std_setinterface(usb_core_driver *udev, usb_req *req)
+{
+    switch(udev->dev.cur_status) {
+    case USBD_DEFAULT:
+        break;
+
+    case USBD_ADDRESSED:
+        break;
+
+    case USBD_CONFIGURED:
+        if(BYTE_LOW(req->wIndex) <= USBD_ITF_MAX_NUM) {
+            if(NULL != udev->dev.class_core->set_intf) {
+                (void)udev->dev.class_core->set_intf(udev, req);
+            }
+
+            return REQ_SUPP;
+        }
+        break;
+
+    default:
+        break;
+    }
+
+    return REQ_NOTSUPP;
+}
+
+/*!
+    \brief      handle USB SynchFrame request
+    \param[in]  udev: pointer to USB device instance
+    \param[in]  req: pointer to USB device request
+    \param[out] none
+    \retval     USB device request status
+*/
+static usb_reqsta _usb_std_synchframe(usb_core_driver *udev, usb_req *req)
+{
+    (void)udev;
+    (void)req;
+
+    /* no handle */
+    return REQ_SUPP;
+}

+ 256 - 0
GD32F3x0/GD32F3x0_usbfs_library/device/core/Source/usbd_transc.c

@@ -0,0 +1,256 @@
+/*!
+    \file    usbd_transc.c
+    \brief   USB transaction core functions
+
+    \version 2025-01-01, V2.5.0, firmware for GD32F3x0
+*/
+
+/*
+    Copyright (c) 2025, GigaDevice Semiconductor Inc.
+
+    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 of the copyright holder 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 HOLDER 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.
+*/
+
+#include "usbd_enum.h"
+#include "usbd_transc.h"
+
+/*!
+    \brief      USB send data in the control transaction
+    \param[in]  udev: pointer to USB device instance
+    \param[out] none
+    \retval     USB device operation cur_status
+*/
+usbd_status usbd_ctl_send(usb_core_driver *udev)
+{
+    usb_transc *transc = &udev->dev.transc_in[0];
+
+    (void)usbd_ep_send(udev, 0U, transc->xfer_buf, transc->remain_len);
+
+    if(transc->remain_len > transc->max_len) {
+        udev->dev.control.ctl_state = (uint8_t)USB_CTL_DATA_IN;
+    } else {
+        udev->dev.control.ctl_state = (uint8_t)USB_CTL_LAST_DATA_IN;
+    }
+
+    return USBD_OK;
+}
+
+/*!
+    \brief      USB receive data in the control transaction
+    \param[in]  udev: pointer to USB device instance
+    \param[out] none
+    \retval     USB device operation cur_status
+*/
+usbd_status usbd_ctl_recev(usb_core_driver *udev)
+{
+    usb_transc *transc = &udev->dev.transc_out[0];
+
+    (void)usbd_ep_recev(udev, 0U, transc->xfer_buf, transc->remain_len);
+
+    if(transc->remain_len > transc->max_len) {
+        udev->dev.control.ctl_state = (uint8_t)USB_CTL_DATA_OUT;
+    } else {
+        udev->dev.control.ctl_state = (uint8_t)USB_CTL_LAST_DATA_OUT;
+    }
+
+    return USBD_OK;
+}
+
+/*!
+    \brief      USB send control transaction status
+    \param[in]  udev: pointer to USB device instance
+    \param[out] none
+    \retval     USB device operation cur_status
+*/
+usbd_status usbd_ctl_status_send(usb_core_driver *udev)
+{
+    udev->dev.control.ctl_state = (uint8_t)USB_CTL_STATUS_IN;
+
+    (void)usbd_ep_send(udev, 0U, NULL, 0U);
+
+    usb_ctlep_startout(udev);
+
+    return USBD_OK;
+}
+
+/*!
+    \brief      USB control receive status
+    \param[in]  udev: pointer to USB device instance
+    \param[out] none
+    \retval     USB device operation cur_status
+*/
+usbd_status usbd_ctl_status_recev(usb_core_driver *udev)
+{
+    udev->dev.control.ctl_state = (uint8_t)USB_CTL_STATUS_OUT;
+
+    (void)usbd_ep_recev(udev, 0U, NULL, 0U);
+
+    usb_ctlep_startout(udev);
+
+    return USBD_OK;
+}
+
+/*!
+    \brief      USB SETUP stage processing
+    \param[in]  udev: pointer to USB device instance
+    \param[out] none
+    \retval     USB device operation cur_status
+*/
+uint8_t usbd_setup_transc(usb_core_driver *udev)
+{
+    usb_reqsta reqstat = REQ_NOTSUPP;
+
+    usb_req req = udev->dev.control.req;
+
+    switch(req.bmRequestType & USB_REQTYPE_MASK) {
+    /* standard device request */
+    case USB_REQTYPE_STRD:
+        reqstat = usbd_standard_request(udev, &req);
+        break;
+
+    /* device class request */
+    case USB_REQTYPE_CLASS:
+        reqstat = usbd_class_request(udev, &req);
+        break;
+
+    /* vendor defined request */
+    case USB_REQTYPE_VENDOR:
+        reqstat = usbd_vendor_request(udev, &req);
+        break;
+
+    default:
+        break;
+    }
+
+    if(REQ_SUPP == reqstat) {
+        if(0U == req.wLength) {
+            (void)usbd_ctl_status_send(udev);
+        } else {
+            if(req.bmRequestType & 0x80U) {
+                (void)usbd_ctl_send(udev);
+            } else {
+                (void)usbd_ctl_recev(udev);
+            }
+        }
+    } else {
+        usbd_enum_error(udev, &req);
+    }
+
+    return (uint8_t)USBD_OK;
+}
+
+/*!
+    \brief      data OUT stage processing
+    \param[in]  udev: pointer to USB device instance
+    \param[in]  ep_num: endpoint identifier(0..7)
+    \param[out] none
+    \retval     USB device operation cur_status
+*/
+uint8_t usbd_out_transc(usb_core_driver *udev, uint8_t ep_num)
+{
+    if(0U == ep_num) {
+        usb_transc *transc = &udev->dev.transc_out[0];
+
+        switch(udev->dev.control.ctl_state) {
+        case USB_CTL_DATA_OUT:
+            /* update transfer length */
+            transc->remain_len -= transc->max_len;
+
+            (void)usbd_ctl_recev(udev);
+            break;
+
+        case USB_CTL_LAST_DATA_OUT:
+            if((uint8_t)USBD_CONFIGURED == udev->dev.cur_status) {
+                if(NULL != udev->dev.class_core->ctlx_out) {
+                    (void)udev->dev.class_core->ctlx_out(udev);
+                }
+            }
+
+            transc->remain_len = 0U;
+
+            (void)usbd_ctl_status_send(udev);
+            break;
+
+        default:
+            break;
+        }
+    } else if((NULL != udev->dev.class_core->data_out) && ((uint8_t)USBD_CONFIGURED == udev->dev.cur_status)) {
+        (void)udev->dev.class_core->data_out(udev, ep_num);
+    } else {
+        /* no operation */
+    }
+
+    return (uint8_t)USBD_OK;
+}
+
+/*!
+    \brief      data IN stage processing
+    \param[in]  udev: pointer to USB device instance
+    \param[in]  ep_num: endpoint identifier(0..7)
+    \param[out] none
+    \retval     USB device operation cur_status
+*/
+uint8_t usbd_in_transc(usb_core_driver *udev, uint8_t ep_num)
+{
+    if(0U == ep_num) {
+        usb_transc *transc = &udev->dev.transc_in[0];
+
+        switch(udev->dev.control.ctl_state) {
+        case USB_CTL_DATA_IN:
+            /* update transfer length */
+            transc->remain_len -= transc->max_len;
+
+            (void)usbd_ctl_send (udev);
+            break;
+
+        case USB_CTL_LAST_DATA_IN:
+            /* last packet is MPS multiple, so send ZLP packet */
+            if(udev->dev.control.ctl_zlp) {
+                (void)usbd_ep_send(udev, 0U, NULL, 0U);
+
+                udev->dev.control.ctl_zlp = 0U;
+            } else {
+                if((uint8_t)USBD_CONFIGURED == udev->dev.cur_status) {
+                    if(NULL != udev->dev.class_core->ctlx_in) {
+                        (void)udev->dev.class_core->ctlx_in(udev);
+                    }
+                }
+
+                transc->remain_len = 0U;
+
+                (void)usbd_ctl_status_recev(udev);
+            }
+            break;
+
+        default:
+            break;
+        }
+    } else {
+        if(((uint8_t)USBD_CONFIGURED == udev->dev.cur_status) && (NULL != udev->dev.class_core->data_in)) {
+            (void)udev->dev.class_core->data_in(udev, ep_num);
+        }
+    }
+
+    return (uint8_t)USBD_OK;
+}

+ 336 - 0
GD32F3x0/GD32F3x0_usbfs_library/driver/Include/drv_usb_core.h

@@ -0,0 +1,336 @@
+/*!
+    \file    drv_usb_core.h
+    \brief   USB core low level driver header file
+
+    \version 2025-01-01, V2.5.0, firmware for GD32F3x0
+*/
+
+/*
+    Copyright (c) 2025, GigaDevice Semiconductor Inc.
+
+    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 of the copyright holder 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 HOLDER 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.
+*/
+
+#ifndef DRV_USB_CORE_H
+#define DRV_USB_CORE_H
+
+#include "drv_usb_regs.h"
+#include "usb_ch9_std.h"
+
+#define USB_FS_EP0_MAX_LEN                  64U                                 /*!< maximum packet size of endpoint 0 */
+#define HC_MAX_PACKET_COUNT                 140U                                /*!< maximum packet count */
+
+#define EP_ID(x)                            ((uint8_t)((x) & 0x7FU))            /*!< endpoint number */
+#define EP_DIR(x)                           ((uint8_t)((x) >> 7))               /*!< endpoint direction */
+
+#define EP_MAX_PACKET_SIZE_MASK             0x07FFU                             /*!< endpoint maximum packet size mask */
+
+enum _usb_mode {
+    DEVICE_MODE = 0U,                                                           /*!< device mode */
+    HOST_MODE,                                                                  /*!< host mode */
+    OTG_MODE                                                                    /*!< OTG mode */
+};
+
+enum _usb_eptype {
+    USB_EPTYPE_CTRL = 0U,                                                       /*!< control endpoint type */
+    USB_EPTYPE_ISOC = 1U,                                                       /*!< isochronous endpoint type */
+    USB_EPTYPE_BULK = 2U,                                                       /*!< bulk endpoint type */
+    USB_EPTYPE_INTR = 3U,                                                       /*!< interrupt endpoint type */
+    USB_EPTYPE_MASK = 3U                                                        /*!< endpoint type mask */
+};
+
+typedef enum {
+    USB_OTG_OK = 0U,                                                            /*!< USB OTG status succeed */
+    USB_OTG_FAIL                                                                /*!< USB OTG status fail */
+} usb_otg_status;
+
+typedef enum {
+    USB_OK = 0U,                                                                /*!< USB status succeed */
+    USB_FAIL                                                                    /*!< USB status fail */
+} usb_status;
+
+typedef enum {
+    USB_USE_FIFO = 0U,                                                          /*!< USB use FIFO transfer mode */
+} usb_transfer_mode;
+
+typedef struct {
+    uint8_t        core_speed;                                                  /*!< USB core speed */
+    uint8_t        num_pipe;                                                    /*!< USB host channel numbers */
+    uint8_t        num_ep;                                                      /*!< USB device endpoint numbers */
+    uint8_t        transfer_mode;                                               /*!< USB transfer mode */
+    uint8_t        phy_itf;                                                     /*!< USB core PHY interface */
+    uint8_t        sof_enable;                                                  /*!< USB SOF output */
+    uint8_t        low_power;                                                   /*!< USB low power */
+    uint8_t        lpm_enable;                                                  /*!< USB link power mode(LPM) */
+    uint8_t        vbus_sensing_enable;                                         /*!< USB VBUS sensing feature */
+    uint8_t        use_dedicated_ep1;                                           /*!< USB dedicated endpoint1 interrupt */
+    uint8_t        use_external_vbus;                                           /*!< enable or disable the use of the external VBUS */
+    uint32_t       base_reg;                                                    /*!< base register address */
+} usb_core_basic;
+
+#ifdef USE_DEVICE_MODE
+
+/* USB descriptor */
+typedef struct _usb_desc {
+    uint8_t *dev_desc;                                                          /*!< device descriptor */
+    uint8_t *config_desc;                                                       /*!< configure descriptor */
+    uint8_t *bos_desc;                                                          /*!< BOS descriptor */
+    void* const *strings;                                                       /*!< string descriptor */
+} usb_desc;
+
+/* USB power management */
+typedef struct _usb_pm {
+    uint8_t  power_mode;                                                        /*!< power mode */
+    uint8_t  power_low;                                                         /*!< power low */
+    uint8_t  dev_remote_wakeup;                                                 /*!< remote wakeup */
+    uint8_t  remote_wakeup_on;                                                  /*!< remote wakeup on */
+} usb_pm;
+
+/* USB control information */
+typedef struct _usb_control {
+    usb_req    req;                                                             /*!< USB standard device request */
+
+    uint8_t    ctl_state;                                                       /*!< USB control transfer state */
+    uint8_t    ctl_zlp;                                                         /*!< zero length package */
+} usb_control;
+
+typedef struct {
+    struct {
+        uint8_t num: 4U;                                                        /*!< the endpoint number.it can be from 0 to 6 */
+        uint8_t pad: 3U;                                                        /*!< padding between number and direction */
+        uint8_t dir: 1U;                                                        /*!< the endpoint direction */
+    } ep_addr;
+
+    uint8_t        ep_type;                                                     /*!< USB endpoint type */
+    uint8_t        ep_stall;                                                    /*!< USB endpoint STALL status */
+
+    uint8_t        frame_num;                                                   /*!< number of frame */
+    uint16_t       max_len;                                                     /*!< maximum packet length */
+
+    /* transaction level variables */
+    uint8_t       *xfer_buf;                                                    /*!< transmit buffer */
+    uint32_t       xfer_len;                                                    /*!< transmit buffer length */
+    uint32_t       xfer_count;                                                  /*!< transmit buffer count */
+
+    uint32_t       remain_len;                                                  /*!< remain packet length */
+} usb_transc;
+
+typedef struct _usb_core_driver usb_dev;
+
+typedef struct _usb_class_core {
+    uint8_t  command;                                                           /*!< device class request command */
+    uint8_t  alter_set;                                                         /*!< alternative set */
+
+    uint8_t  (*init)(usb_dev *udev, uint8_t config_index);                      /*!< initialize handler */
+    uint8_t  (*deinit)(usb_dev *udev, uint8_t config_index);                    /*!< de-initialize handler */
+
+    uint8_t  (*req_proc)(usb_dev *udev, usb_req *req);                          /*!< device request handler */
+
+    uint8_t  (*set_intf)(usb_dev *udev, usb_req *req);                          /*!< device set interface callback */
+
+    uint8_t  (*ctlx_in)(usb_dev *udev);                                         /*!< device control IN callback */
+    uint8_t  (*ctlx_out)(usb_dev *udev);                                        /*!< device control OUT callback */
+
+    uint8_t  (*data_in)(usb_dev *udev, uint8_t ep_num);                         /*!< device data IN handler */
+    uint8_t  (*data_out)(usb_dev *udev, uint8_t ep_num);                        /*!< device data OUT handler */
+
+    uint8_t  (*SOF)(usb_dev *udev);                                             /*!< start of frame handler */
+
+    uint8_t  (*incomplete_isoc_in)(usb_dev *udev);                              /*!< incomplete synchronization IN transfer handler */
+    uint8_t  (*incomplete_isoc_out)(usb_dev *udev);                             /*!< incomplete synchronization OUT transfer handler */
+} usb_class_core;
+
+typedef struct _usb_perp_dev {
+    uint8_t            config;                                                  /*!< configuration */
+    uint8_t            dev_addr;                                                /*!< device address */
+
+    __IO uint8_t       cur_status;                                              /*!< current status */
+    __IO uint8_t       backup_status;                                           /*!< backup status */
+
+    usb_transc         transc_in[USBFS_MAX_TX_FIFOS];                           /*!< endpoint IN transaction */
+    usb_transc         transc_out[USBFS_MAX_TX_FIFOS];                          /*!< endpoint OUT transaction */
+
+    usb_pm             pm;                                                      /*!< power management */
+    usb_control        control;                                                 /*!< USB control information */
+    usb_desc          *desc;                                                    /*!< USB descriptors pointer */
+    usb_class_core    *class_core;                                              /*!< class driver */
+    void              *class_data[4];                                           /*!< class data pointer */
+    void              *user_data;                                               /*!< user data pointer */
+    void              *pdata;                                                   /*!< reserved data pointer */
+} usb_perp_dev;
+
+#endif /* USE_DEVICE_MODE */
+
+#ifdef USE_HOST_MODE
+
+typedef enum _usb_pipe_status {
+    PIPE_IDLE = 0U,                  /*!< host pipe IDLE status */
+    PIPE_XF,                         /*!< host pipe transfer completed status */
+    PIPE_HALTED,                     /*!< host pipe halted status */
+    PIPE_NAK,                        /*!< host pipe NAK status */
+    PIPE_NYET,                       /*!< host pipe NYET status */
+    PIPE_STALL,                      /*!< host pipe STALL status */
+    PIPE_TRACERR,                    /*!< host pipe transaction error status */
+    PIPE_BBERR,                      /*!< host pipe babble error status */
+    PIPE_REQOVR,                     /*!< host pipe frame overrun status */
+    PIPE_DTGERR                      /*!< host pipe data toggle error status */
+} usb_pipe_status;
+
+typedef enum _usb_pipe_mode {
+    PIPE_PERIOD     = 0U,            /*!< USB host pipe PERIOD mode */
+    PIPE_NON_PERIOD = 1U             /*!< USB host pipe NOT PERIOD mode */
+} usb_pipe_mode;
+typedef enum _usb_urb_state {
+    URB_IDLE = 0U,                   /*!< USB URB IDLE state */
+    URB_DONE,                        /*!< USB URB DONE state */
+    URB_NOTREADY,                    /*!< USB URB NOT READY state */
+    URB_ERROR,                       /*!< USB URB ERROR state */
+    URB_STALL,                       /*!< USB URB STALL state */
+    URB_PING                         /*!< USB URB PING state */
+} usb_urb_state;
+
+typedef struct _usb_pipe {
+    uint8_t              in_used;                                      /*!< pipe used */
+    uint8_t              dev_addr;                                     /*!< USB device address */
+    uint32_t             dev_speed;                                    /*!< USB device speed */
+
+    struct {
+        uint8_t          num;                                          /*!< endpoint numbers */
+        uint8_t          dir;                                          /*!< endpoint direction */
+        uint8_t          type;                                         /*!< endpoint transfer type */
+        uint16_t         mps;                                          /*!< endpoint max packet size */
+    } ep;
+
+    __IO uint8_t         supp_ping;                                    /*!< host pipe support PING */
+    __IO uint8_t         do_ping;                                      /*!< host pipe do PING  */
+    __IO uint32_t        DPID;                                         /*!< data PID */
+
+    uint8_t              *xfer_buf;                                    /*!< USB transfer buffer */
+    uint32_t             xfer_len;                                     /*!< USB transfer length */
+    uint32_t             xfer_count;                                   /*!< USB transfer count */
+
+    uint8_t              data_toggle_in;                               /*!< toggle DATA IN */
+    uint8_t              data_toggle_out;                              /*!< toggle DATA OUT */
+
+    __IO uint32_t        err_count;                                    /*!< error count */
+    __IO usb_pipe_status pp_status;                                    /*!< USB pipe status */
+    __IO usb_urb_state   urb_state;                                    /*!< USB urb state */
+} usb_pipe;
+
+typedef struct _usb_host_drv {
+    __IO uint32_t            connect_status;                           /*!< connect status */
+    __IO uint32_t            port_enabled;                             /*!< USB port enable */
+    __IO uint32_t            backup_xfercount[USBFS_MAX_TX_FIFOS];     /*!< USB backup transfer data count */
+
+    usb_pipe                 pipe[USBFS_MAX_TX_FIFOS];                 /*!< USB host pipe handles */
+    void                     *data;                                    /*!< user data pointer */
+} usb_host_drv;
+
+#endif /* USE_HOST_MODE */
+
+typedef struct _usb_core_driver {
+    usb_core_basic     bp;                                             /*!< USB basic parameters */
+    usb_core_regs      regs;                                           /*!< USB registers */
+
+#ifdef USE_DEVICE_MODE
+    usb_perp_dev       dev;                                            /*!< USB peripheral device */
+#endif /* USE_DEVICE_MODE */
+
+#ifdef USE_HOST_MODE
+    usb_host_drv       host;                                           /*!< USB peripheral host */
+#endif /* USE_HOST_MODE */
+} usb_core_driver;
+
+/* static inline function definitions */
+
+/*!
+    \brief      get the global interrupts
+    \param[in]  usb_regs: pointer to USB core registers
+    \param[out] none
+    \retval     interrupt status
+*/
+__STATIC_INLINE uint32_t usb_coreintr_get(usb_core_regs *usb_regs)
+{
+    uint32_t reg_data = usb_regs->gr->GINTEN;
+
+    reg_data &= usb_regs->gr->GINTF;
+
+    return reg_data;
+}
+
+/*!
+    \brief      set USB RX FIFO size
+    \param[in]  usb_regs: pointer to USB core registers
+    \param[in]  size: assigned FIFO size
+    \param[out] none
+    \retval     none
+*/
+__STATIC_INLINE void usb_set_rxfifo(usb_core_regs *usb_regs, uint16_t size)
+{
+    usb_regs->gr->GRFLEN = size;
+}
+
+/*!
+    \brief      enable the global interrupts
+    \param[in]  usb_regs: pointer to USB core registers
+    \param[out] none
+    \retval     none
+*/
+__STATIC_INLINE void usb_globalint_enable(usb_core_regs *usb_regs)
+{
+    /* enable USB global interrupt */
+    usb_regs->gr->GAHBCS |= GAHBCS_GINTEN;
+}
+
+/*!
+    \brief      disable the global interrupts
+    \param[in]  usb_regs: pointer to USB core registers
+    \param[out] none
+    \retval     none
+*/
+__STATIC_INLINE void usb_globalint_disable(usb_core_regs *usb_regs)
+{
+    /* disable USB global interrupt */
+    usb_regs->gr->GAHBCS &= ~GAHBCS_GINTEN;
+}
+
+/* function declarations */
+/* configure core capabilities */
+usb_status usb_basic_init (usb_core_basic *usb_basic, usb_core_regs *usb_regs);
+/* initializes the USB controller registers and prepares the core device mode or host mode operation */
+usb_status usb_core_init(usb_core_basic usb_basic, usb_core_regs *usb_regs);
+/* write a packet into the TX FIFO associated with the endpoint */
+usb_status usb_txfifo_write(usb_core_regs *usb_regs, uint8_t *src_buf, uint8_t  fifo_num, uint16_t byte_count);
+/* read a packet from the RX FIFO associated with the endpoint */
+void *usb_rxfifo_read(usb_core_regs *usb_regs, uint8_t *dest_buf, uint16_t byte_count);
+/* flush a TX FIFO or all TX FIFOs */
+usb_status usb_txfifo_flush(usb_core_regs *usb_regs, uint8_t fifo_num);
+/* flush the entire RX FIFO */
+usb_status usb_rxfifo_flush(usb_core_regs *usb_regs);
+/* set endpoint or channel TX FIFO size */
+void usb_set_txfifo(usb_core_regs *usb_regs, uint8_t fifo, uint16_t size);
+/* set USB current mode */
+void usb_curmode_set(usb_core_regs *usb_regs, uint8_t mode);
+
+#endif /* DRV_USB_CORE_H */

+ 197 - 0
GD32F3x0/GD32F3x0_usbfs_library/driver/Include/drv_usb_dev.h

@@ -0,0 +1,197 @@
+/*!
+    \file    drv_usb_dev.h
+    \brief   USB device low level driver header file
+
+    \version 2025-01-01, V2.5.0, firmware for GD32F3x0
+*/
+
+/*
+    Copyright (c) 2025, GigaDevice Semiconductor Inc.
+
+    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 of the copyright holder 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 HOLDER 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.
+*/
+
+#ifndef DRV_USB_DEV_H
+#define DRV_USB_DEV_H
+
+#include "usbd_conf.h"
+#include "drv_usb_core.h"
+
+#define EP_IN(x)                            ((uint8_t)(0x80U | (x)))    /*!< device IN endpoint */
+#define EP_OUT(x)                           ((uint8_t)(x))              /*!< device OUT endpoint */
+
+enum usb_ctl_status {
+    USB_CTL_IDLE = 0U,                                                  /*!< USB control transfer idle state */
+    USB_CTL_DATA_IN,                                                    /*!< USB control transfer data IN state */
+    USB_CTL_LAST_DATA_IN,                                               /*!< USB control transfer last data IN state */
+    USB_CTL_DATA_OUT,                                                   /*!< USB control transfer data OUT state */
+    USB_CTL_LAST_DATA_OUT,                                              /*!< USB control transfer last data OUT state */
+    USB_CTL_STATUS_IN,                                                  /*!< USB control transfer status IN state*/
+    USB_CTL_STATUS_OUT                                                  /*!< USB control transfer status OUT state */
+};
+
+/* static inline function definitions */
+
+/*!
+    \brief      configure the USB device to be disconnected
+    \param[in]  udev: pointer to USB device
+    \param[out] none
+    \retval     none
+*/
+__STATIC_INLINE void usb_dev_disconnect(usb_core_driver *udev)
+{
+    udev->regs.dr->DCTL |= DCTL_SD;
+}
+
+/*!
+    \brief      configure the USB device to be connected
+    \param[in]  udev: pointer to USB device
+    \param[out] none
+    \retval     none
+*/
+__STATIC_INLINE void usb_dev_connect(usb_core_driver *udev)
+{
+    udev->regs.dr->DCTL &= ~DCTL_SD;
+}
+
+/*!
+    \brief      set the USB device address
+    \param[in]  udev: pointer to USB device
+    \param[in]  dev_addr: device address for setting
+    \param[out] none
+    \retval     none
+*/
+__STATIC_INLINE void usb_devaddr_set(usb_core_driver *udev, uint8_t dev_addr)
+{
+    udev->regs.dr->DCFG &= ~DCFG_DAR;
+    udev->regs.dr->DCFG |= (uint32_t)dev_addr << 4;
+}
+
+/*!
+    \brief      read device all OUT endpoint interrupt register
+    \param[in]  udev: pointer to USB device
+    \param[out] none
+    \retval     interrupt status
+*/
+__STATIC_INLINE uint32_t usb_oepintnum_read(usb_core_driver *udev)
+{
+    uint32_t value = udev->regs.dr->DAEPINT;
+
+    value &= udev->regs.dr->DAEPINTEN;
+
+    return (value & DAEPINT_OEPITB) >> 16;
+}
+
+/*!
+    \brief      read device OUT endpoint interrupt flag register
+    \param[in]  udev: pointer to USB device
+    \param[in]  ep_num: endpoint number
+    \param[out] none
+    \retval     interrupt status
+*/
+__STATIC_INLINE uint32_t usb_oepintr_read(usb_core_driver *udev, uint8_t ep_num)
+{
+    uint32_t value = udev->regs.er_out[ep_num]->DOEPINTF;
+
+    value &= udev->regs.dr->DOEPINTEN;
+
+    return value;
+}
+
+/*!
+    \brief      read device all IN endpoint interrupt register
+    \param[in]  udev: pointer to USB device
+    \param[out] none
+    \retval     interrupt status
+*/
+__STATIC_INLINE uint32_t usb_iepintnum_read(usb_core_driver *udev)
+{
+    uint32_t value = udev->regs.dr->DAEPINT;
+
+    value &= udev->regs.dr->DAEPINTEN;
+    
+    return value & DAEPINT_IEPITB;
+}
+
+/*!
+    \brief      set remote wakeup signaling
+    \param[in]  udev: pointer to USB device
+    \param[out] none
+    \retval     none
+*/
+__STATIC_INLINE void usb_rwkup_set(usb_core_driver *udev)
+{
+    if(udev->dev.pm.dev_remote_wakeup) {
+        /* enable remote wakeup signaling */
+        udev->regs.dr->DCTL |= DCTL_RWKUP;
+    }
+}
+
+/*!
+    \brief      reset remote wakeup signaling
+    \param[in]  udev: pointer to USB device
+    \param[out] none
+    \retval     none
+*/
+__STATIC_INLINE void usb_rwkup_reset(usb_core_driver *udev)
+{
+    if(udev->dev.pm.dev_remote_wakeup) {
+        /* disable remote wakeup signaling */
+        udev->regs.dr->DCTL &= ~DCTL_RWKUP;
+    }
+}
+
+/* function declarations */
+/* initialize USB core registers for device mode */
+usb_status usb_devcore_init(usb_core_driver *udev);
+/* enable the USB device mode interrupts */
+usb_status usb_devint_enable(usb_core_driver *udev);
+/* active the USB endpoint 0 transaction */
+usb_status usb_transc0_active(usb_core_driver *udev, usb_transc *transc);
+/* active the USB transaction */
+usb_status usb_transc_active(usb_core_driver *udev, usb_transc *transc);
+/* deactivate the USB transaction */
+usb_status usb_transc_deactivate(usb_core_driver *udev, usb_transc *transc);
+/* configure USB transaction to start IN transfer */
+usb_status usb_transc_inxfer(usb_core_driver *udev, usb_transc *transc);
+/* configure USB transaction to start OUT transfer */
+usb_status usb_transc_outxfer(usb_core_driver *udev, usb_transc *transc);
+/* set the USB transaction STALL status */
+usb_status usb_transc_stall(usb_core_driver *udev, usb_transc *transc);
+/* clear the USB transaction STALL status */
+usb_status usb_transc_clrstall(usb_core_driver *udev, usb_transc *transc);
+/* read device IN endpoint interrupt flag register */
+uint32_t usb_iepintr_read(usb_core_driver *udev, uint8_t ep_num);
+/* configures OUT endpoint 0 to receive SETUP packets */
+void usb_ctlep_startout(usb_core_driver *udev);
+/* active remote wakeup signaling */
+void usb_rwkup_active(usb_core_driver *udev);
+/* active USB core clock */
+void usb_clock_active(usb_core_driver *udev);
+/* USB device suspend */
+void usb_dev_suspend(usb_core_driver *udev);
+/* stop the device and clean up FIFOs */
+void usb_dev_stop(usb_core_driver *udev);
+
+#endif /* DRV_USB_DEV_H */

+ 113 - 0
GD32F3x0/GD32F3x0_usbfs_library/driver/Include/drv_usb_host.h

@@ -0,0 +1,113 @@
+/*!
+    \file    drv_usb_host.h
+    \brief   USB host mode low level driver header file
+
+    \version 2025-01-01, V2.5.0, firmware for GD32F3x0
+*/
+
+/*
+    Copyright (c) 2025, GigaDevice Semiconductor Inc.
+
+    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 of the copyright holder 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 HOLDER 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.
+*/
+
+#ifndef DRV_USB_HOST_H
+#define DRV_USB_HOST_H
+
+#include "drv_usb_core.h"
+
+/*!
+    \brief      get USB even frame
+    \param[in]  udev: pointer to USB device
+    \param[out] none
+    \retval     USB even or odd frame
+*/
+__STATIC_INLINE uint8_t usb_frame_even(usb_core_driver *udev)
+{
+    return (uint8_t)!(udev->regs.hr->HFINFR & 0x01U);
+}
+
+/*!
+    \brief      configure USB clock of PHY
+    \param[in]  udev: pointer to USB device
+    \param[in]  clock: PHY clock
+    \param[out] none
+    \retval     none
+*/
+__STATIC_INLINE void usb_phyclock_config(usb_core_driver *udev, uint8_t clock)
+{
+    udev->regs.hr->HCTL &= ~HCTL_CLKSEL;
+    udev->regs.hr->HCTL |= clock;
+}
+
+/*!
+    \brief      read USB port
+    \param[in]  udev: pointer to USB device
+    \param[out] none
+    \retval     port status
+*/
+__STATIC_INLINE uint32_t usb_port_read(usb_core_driver *udev)
+{
+    return *udev->regs.HPCS & ~(HPCS_PE | HPCS_PCD | HPCS_PEDC);
+}
+
+/*!
+    \brief      get USB current speed
+    \param[in]  udev: pointer to USB device
+    \param[out] none
+    \retval     USB current speed
+*/
+__STATIC_INLINE uint32_t usb_curspeed_get(usb_core_driver *udev)
+{
+    return *udev->regs.HPCS & HPCS_PS;
+}
+
+/*!
+    \brief      get USB current frame
+    \param[in]  udev: pointer to USB device
+    \param[out] none
+    \retval     USB current frame
+*/
+__STATIC_INLINE uint32_t usb_curframe_get(usb_core_driver *udev)
+{
+    return (udev->regs.hr->HFINFR & 0xFFFFU);
+}
+
+/* function declarations */
+/* initializes USB core for host mode */
+usb_status usb_host_init(usb_core_driver *udev);
+/* control the VBUS to power */
+void usb_portvbus_switch(usb_core_driver *udev, uint8_t state);
+/* reset host port */
+uint32_t usb_port_reset(usb_core_driver *udev);
+/* initialize host pipe */
+usb_status usb_pipe_init(usb_core_driver *udev, uint8_t pipe_num);
+/* prepare host pipe for transferring packets */
+usb_status usb_pipe_xfer(usb_core_driver *udev, uint8_t pipe_num);
+/* halt host pipe */
+usb_status usb_pipe_halt(usb_core_driver *udev, uint8_t pipe_num);
+/* stop the USB host and clean up FIFO */
+void usb_host_stop(usb_core_driver *udev);
+
+#endif /* DRV_USB_HOST_H */

+ 60 - 0
GD32F3x0/GD32F3x0_usbfs_library/driver/Include/drv_usb_hw.h

@@ -0,0 +1,60 @@
+/*!
+    \file    drv_usb_hw.h
+    \brief   USB hardware configuration header file
+
+    \version 2025-01-01, V2.5.0, firmware for GD32F3x0
+*/
+
+/*
+    Copyright (c) 2025, GigaDevice Semiconductor Inc.
+
+    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 of the copyright holder 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 HOLDER 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.
+*/
+
+#ifndef DRV_USB_HW_H
+#define DRV_USB_HW_H
+
+#include "usb_conf.h"
+
+/* function declarations */
+/* configure USB clock */
+void usb_rcu_config(void);
+/* configure USB interrupt */
+void usb_intr_config(void);
+/* initializes delay unit using Timer2 */
+void usb_timer_init(void);
+/* delay in micro seconds */
+void usb_udelay(const uint32_t usec);
+/* delay in milliseconds */
+void usb_mdelay(const uint32_t msec);
+/* configures system clock after wakeup from STOP mode */
+void system_clk_config_stop(void);
+#ifdef USE_HOST_MODE
+/* configure USB VBus */
+void usb_vbus_config(void);
+/* drive USB VBus */
+void usb_vbus_drive(uint8_t State);
+#endif /* USE_HOST_MODE */
+
+#endif /* DRV_USB_HW_H */

+ 615 - 0
GD32F3x0/GD32F3x0_usbfs_library/driver/Include/drv_usb_regs.h

@@ -0,0 +1,615 @@
+/*!
+    \file    drv_usb_regs.h
+    \brief   USB cell registers definition and handle macros
+
+    \version 2025-01-01, V2.5.0, firmware for GD32F3x0
+*/
+
+/*
+    Copyright (c) 2025, GigaDevice Semiconductor Inc.
+
+    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 of the copyright holder 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 HOLDER 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.
+*/
+
+#ifndef DRV_USB_REGS_H
+#define DRV_USB_REGS_H
+
+#include "usb_conf.h"
+
+#define USBFS_REG_BASE                0x50000000L   /*!< base address of USBFS registers */
+
+#define USBFS_MAX_TX_FIFOS            15U           /*!< FIFO number */
+
+#define USBFS_MAX_PACKET_SIZE         64U           /*!< USBFS max packet size */
+#define USBFS_MAX_CHANNEL_COUNT       8U            /*!< USBFS host channel count */
+#define USBFS_MAX_EP_COUNT            4U            /*!< USBFS device endpoint count */
+#define USBFS_MAX_FIFO_WORDLEN        320U          /*!< USBFS max FIFO size in words */
+
+#define USB_DATA_FIFO_OFFSET          0x1000U       /*!< USB data FIFO offset */
+#define USB_DATA_FIFO_SIZE            0x1000U       /*!< USB data FIFO size */
+
+enum USB_SPEED {
+    USB_SPEED_UNKNOWN = 0U,                         /*!< USB speed unknown */
+    USB_SPEED_LOW,                                  /*!< USB speed low */
+    USB_SPEED_FULL,                                 /*!< USB speed full */
+    USB_SPEED_HIGH                                  /*!< USB speed high */
+};
+
+enum usb_reg_offset {
+    USB_REG_OFFSET_CORE      = 0x0000U,             /*!< global OTG control and status register */
+    USB_REG_OFFSET_DEV       = 0x0800U,             /*!< device mode control and status registers */
+    USB_REG_OFFSET_EP        = 0x0020U,
+    USB_REG_OFFSET_EP_IN     = 0x0900U,             /*!< device IN endpoint 0 control register */
+    USB_REG_OFFSET_EP_OUT    = 0x0B00U,             /*!< device OUT endpoint 0 control register */
+    USB_REG_OFFSET_HOST      = 0x0400U,             /*!< host control register */
+    USB_REG_OFFSET_CH        = 0x0020U,
+    USB_REG_OFFSET_PORT      = 0x0440U,             /*!< host port control and status register */
+    USB_REG_OFFSET_CH_INOUT  = 0x0500U,             /*!< Host channel-x control registers */
+    USB_REG_OFFSET_PWRCLKCTL = 0x0E00U              /*!< power and clock register */
+};
+
+typedef struct {
+    __IO uint32_t GOTGCS;                           /*!< USB global OTG control and status register       000h */
+    __IO uint32_t GOTGINTF;                         /*!< USB global OTG interrupt flag register           004h */
+    __IO uint32_t GAHBCS;                           /*!< USB global AHB control and status register       008h */
+    __IO uint32_t GUSBCS;                           /*!< USB global USB control and status register       00Ch */
+    __IO uint32_t GRSTCTL;                          /*!< USB global reset control register                010h */
+    __IO uint32_t GINTF;                            /*!< USB global interrupt flag register               014h */
+    __IO uint32_t GINTEN;                           /*!< USB global interrupt enable register             018h */
+    __IO uint32_t GRSTATR;                          /*!< USB receive status debug read register           01Ch */
+    __IO uint32_t GRSTATP;                          /*!< USB receive status and pop register              020h */
+    __IO uint32_t GRFLEN;                           /*!< USB global receive FIFO length register          024h */
+    __IO uint32_t DIEP0TFLEN_HNPTFLEN;              /*!< USB device IN endpoint 0/host non-periodic transmit FIFO length register 028h */
+    __IO uint32_t HNPTFQSTAT;                       /*!< USB host non-periodic FIFO/queue status register 02Ch */
+    uint32_t Reserved30[2];                         /*!< Reserved                                         030h */
+    __IO uint32_t GCCFG;                            /*!< USB global core configuration register           038h */
+    __IO uint32_t CID;                              /*!< USB core ID register                             03Ch */
+    uint32_t Reserved40[48];                        /*!< Reserved                                         040h-0FFh */
+    __IO uint32_t HPTFLEN;                          /*!< USB host periodic transmit FIFO length register  100h */
+    __IO uint32_t DIEPTFLEN[15];                    /*!< USB device IN endpoint transmit FIFO length register 104h */
+} usb_gr;
+
+typedef struct {
+    __IO uint32_t HCTL;                             /*!< USB host control register                             400h */
+    __IO uint32_t HFT;                              /*!< USB host frame interval register                      404h */
+    __IO uint32_t HFINFR;                           /*!< USB host frame information remaining register         408h */
+    uint32_t Reserved40C;                           /*!< Reserved                                              40Ch */
+    __IO uint32_t HPTFQSTAT;                        /*!< USB host periodic transmit FIFO/queue status register 410h */
+    __IO uint32_t HACHINT;                          /*!< USB host all channels interrupt register              414h */
+    __IO uint32_t HACHINTEN;                        /*!< USB host all channels interrupt enable register       418h */
+} usb_hr;
+
+typedef struct {
+    __IO uint32_t HCHCTL;                           /*!< USB host channel control register          500h */
+    __IO uint32_t HCHSTCTL;                         /*!< Reserved                                   504h */
+    __IO uint32_t HCHINTF;                          /*!< USB host channel interrupt flag register   508h */
+    __IO uint32_t HCHINTEN;                         /*!< USB host channel interrupt enable register 50Ch */
+    __IO uint32_t HCHLEN;                           /*!< USB host channel transfer length register  510h */
+    uint32_t Reserved514;                           /*!< Reserved                                   514h*/
+    uint32_t Reserved[2];
+} usb_pr;
+
+typedef struct {
+    __IO uint32_t DCFG;                             /*!< USB device configuration register                           800h */
+    __IO uint32_t DCTL;                             /*!< USB device control register                                 804h */
+    __IO uint32_t DSTAT;                            /*!< USB device status register                                  808h */
+    uint32_t Reserved0C;                            /*!< Reserved                                                    80Ch */
+    __IO uint32_t DIEPINTEN;                        /*!< USB device IN endpoint common interrupt enable register     810h */
+    __IO uint32_t DOEPINTEN;                        /*!< USB device OUT endpoint common interrupt enable register    814h */
+    __IO uint32_t DAEPINT;                          /*!< USB device all endpoints interrupt register                 818h */
+    __IO uint32_t DAEPINTEN;                        /*!< USB device all endpoints interrupt enable register          81Ch */
+    uint32_t Reserved20;                            /*!< Reserved                                                    820h */
+    uint32_t Reserved24;                            /*!< Reserved                                                    824h */
+    __IO uint32_t DVBUSDT;                          /*!< USB device VBUS discharge time register                     828h */
+    __IO uint32_t DVBUSPT;                          /*!< USB device VBUS pulsing time register                       82Ch */
+    __IO uint32_t DTHRCTL;                          /*!< device threshold control                                    830h */
+    __IO uint32_t DIEPFEINTEN;                      /*!< USB Device IN endpoint FIFO empty interrupt enable register 834h */
+    __IO uint32_t DEP1INT;                          /*!< USB device endpoint 1 interrupt register                    838h */
+    __IO uint32_t DEP1INTEN;                        /*!< USB device endpoint 1 interrupt enable register             83Ch */
+    uint32_t Reserved40;                            /*!< Reserved                                                    840h */
+    __IO uint32_t DIEP1INTEN;                       /*!< USB device IN endpoint-1 interrupt enable register          844h */
+    uint32_t Reserved48[15];                        /*!< Reserved                                                848-880h */
+    __IO uint32_t DOEP1INTEN;                       /*!< USB device OUT endpoint-1 interrupt enable register         884h */
+} usb_dr;
+
+typedef struct {
+    __IO uint32_t DIEPCTL;                          /*!< USB device IN endpoint control register         900h + (EpNum * 20h) + 00h */
+    uint32_t Reserved04;                            /*!< Reserved                                        900h + (EpNum * 20h) + 04h */
+    __IO uint32_t DIEPINTF;                         /*!< USB device IN endpoint interrupt flag register  900h + (EpNum * 20h) + 08h */
+    uint32_t Reserved0C;                            /*!< Reserved                                        900h + (EpNum * 20h) + 0Ch */
+    __IO uint32_t DIEPLEN;                          /*!< USB device IN endpoint transfer length register 900h + (EpNum * 20h) + 10h */
+    uint32_t Reserved14;                            /*!< Reserved                                        900h + (EpNum * 20h) + 14h */
+    __IO uint32_t DIEPTFSTAT;                       /*!< USB device IN endpoint transmit FIFO status register 900h + (EpNum * 20h) + 18h */
+} usb_erin;
+
+typedef struct {
+    __IO uint32_t DOEPCTL;                          /*!< USB device IN endpoint control register         B00h + (EpNum * 20h) + 00h */
+    uint32_t Reserved04;                            /*!< Reserved                                        B00h + (EpNum * 20h) + 04h */
+    __IO uint32_t DOEPINTF;                         /*!< USB device IN endpoint interrupt flag register  B00h + (EpNum * 20h) + 08h */
+    uint32_t Reserved0C;                            /*!< Reserved                                        B00h + (EpNum * 20h) + 0Ch */
+    __IO uint32_t DOEPLEN;                          /*!< USB device IN endpoint transfer length register B00h + (EpNum * 20h) + 10h */
+    uint32_t Reserved14;                            /*!< Reserved                                        B00h + (EpNum * 20h) + 14h */
+} usb_erout;
+
+typedef struct _usb_regs {
+    usb_gr       *gr;                               /*!< USBFS global registers */
+    usb_dr       *dr;                               /*!< Device control and status registers */
+    usb_hr       *hr;                               /*!< Host control and status registers */
+    usb_erin     *er_in[6];                         /*!< USB device IN endpoint register */
+    usb_erout    *er_out[6];                        /*!< USB device OUT endpoint register */
+    usb_pr       *pr[15];                           /*!< USB Host channel-x control register */
+
+    __IO uint32_t     *HPCS;                        /*!< USB host port control and status register */
+    __IO uint32_t     *DFIFO[USBFS_MAX_TX_FIFOS];
+    __IO uint32_t     *PWRCLKCTL;                   /*!< USB power and clock control register */
+} usb_core_regs;
+
+/* global OTG control and status register bits definitions */
+#define GOTGCS_BSV                BIT(19)             /*!< B-Session Valid */
+#define GOTGCS_ASV                BIT(18)             /*!< A-session valid */
+#define GOTGCS_DI                 BIT(17)             /*!< debounce interval */
+#define GOTGCS_CIDPS              BIT(16)             /*!< id pin status */
+#define GOTGCS_DHNPEN             BIT(11)             /*!< device HNP enable */
+#define GOTGCS_HHNPEN             BIT(10)             /*!< host HNP enable */
+#define GOTGCS_HNPREQ             BIT(9)              /*!< HNP request */
+#define GOTGCS_HNPS               BIT(8)              /*!< HNP successes */
+#define GOTGCS_SRPREQ             BIT(1)              /*!< SRP request */
+#define GOTGCS_SRPS               BIT(0)              /*!< SRP successes */
+
+/* global OTG interrupt flag register bits definitions */
+#define GOTGINTF_DF               BIT(19)             /*!< debounce finish */
+#define GOTGINTF_ADTO             BIT(18)             /*!< A-device timeout */
+#define GOTGINTF_HNPDET           BIT(17)             /*!< host negotiation request detected */
+#define GOTGINTF_HNPEND           BIT(9)              /*!< HNP end */
+#define GOTGINTF_SRPEND           BIT(8)              /*!< SRP end */
+#define GOTGINTF_SESEND           BIT(2)              /*!< session end */
+
+/* global AHB control and status register bits definitions */
+#define GAHBCS_PTXFTH             BIT(8)              /*!< periodic TX FIFO threshold */
+#define GAHBCS_TXFTH              BIT(7)              /*!< TX FIFO threshold */
+#define GAHBCS_GINTEN             BIT(0)              /*!< global interrupt enable */
+
+/* global USB control and status register bits definitions */
+#define GUSBCS_FDM                BIT(30)             /*!< force device mode */
+#define GUSBCS_FHM                BIT(29)             /*!< force host mode */
+#define GUSBCS_ULPIEOI            BIT(21)             /*!< ULPI external over-current indicator */
+#define GUSBCS_ULPIEVD            BIT(20)             /*!< ULPI external VBUS driver */
+#define GUSBCS_UTT                BITS(10, 13)        /*!< USB turnaround time */
+#define GUSBCS_HNPCEN             BIT(9)              /*!< HNP capability enable */
+#define GUSBCS_SRPCEN             BIT(8)              /*!< SRP capability enable */
+#define GUSBCS_EMBPHY             BIT(6)              /*!< embedded PHY selected */
+#define GUSBCS_TOC                BITS(0, 2)          /*!< timeout calibration */
+
+/* global reset control register bits definitions */
+#define GRSTCTL_TXFNUM            BITS(6, 10)         /*!< tx FIFO number */
+#define GRSTCTL_TXFF              BIT(5)              /*!< tx FIFO flush */
+#define GRSTCTL_RXFF              BIT(4)              /*!< rx FIFO flush */
+#define GRSTCTL_HFCRST            BIT(2)              /*!< host frame counter reset */
+#define GRSTCTL_HCSRST            BIT(1)              /*!< HCLK soft reset */
+#define GRSTCTL_CSRST             BIT(0)              /*!< core soft reset */
+
+/* global interrupt flag register bits definitions */
+#define GINTF_WKUPIF              BIT(31)             /*!< wakeup interrupt flag */
+#define GINTF_SESIF               BIT(30)             /*!< session interrupt flag */
+#define GINTF_DISCIF              BIT(29)             /*!< disconnect interrupt flag */
+#define GINTF_IDPSC               BIT(28)             /*!< id pin status change */
+#define GINTF_PTXFEIF             BIT(26)             /*!< periodic tx FIFO empty interrupt flag */
+#define GINTF_HCIF                BIT(25)             /*!< host channels interrupt flag */
+#define GINTF_HPIF                BIT(24)             /*!< host port interrupt flag */
+#define GINTF_PXNCIF              BIT(21)             /*!< periodic transfer not complete interrupt flag */
+#define GINTF_ISOONCIF            BIT(21)             /*!< isochronous OUT transfer not complete interrupt flag */
+#define GINTF_ISOINCIF            BIT(20)             /*!< isochronous IN transfer not complete interrupt flag */
+#define GINTF_OEPIF               BIT(19)             /*!< OUT endpoint interrupt flag */
+#define GINTF_IEPIF               BIT(18)             /*!< IN endpoint interrupt flag */
+#define GINTF_EOPFIF              BIT(15)             /*!< end of periodic frame interrupt flag */
+#define GINTF_ISOOPDIF            BIT(14)             /*!< isochronous OUT packet dropped interrupt flag */
+#define GINTF_ENUMFIF             BIT(13)             /*!< enumeration finished */
+#define GINTF_RST                 BIT(12)             /*!< USB reset */
+#define GINTF_SP                  BIT(11)             /*!< USB suspend */
+#define GINTF_ESP                 BIT(10)             /*!< early suspend */
+#define GINTF_GONAK               BIT(7)              /*!< global OUT NAK effective */
+#define GINTF_GNPINAK             BIT(6)              /*!< global IN non-periodic NAK effective */
+#define GINTF_NPTXFEIF            BIT(5)              /*!< non-periodic tx FIFO empty interrupt flag */
+#define GINTF_RXFNEIF             BIT(4)              /*!< rx FIFO non-empty interrupt flag */
+#define GINTF_SOF                 BIT(3)              /*!< start of frame */
+#define GINTF_OTGIF               BIT(2)              /*!< OTG interrupt flag */
+#define GINTF_MFIF                BIT(1)              /*!< mode fault interrupt flag */
+#define GINTF_COPM                BIT(0)              /*!< current operation mode */
+
+/* global interrupt enable register bits definitions */
+#define GINTEN_WKUPIE             BIT(31)             /*!< wakeup interrupt enable */
+#define GINTEN_SESIE              BIT(30)             /*!< session interrupt enable */
+#define GINTEN_DISCIE             BIT(29)             /*!< disconnect interrupt enable */
+#define GINTEN_IDPSCIE            BIT(28)             /*!< id pin status change interrupt enable */
+#define GINTEN_PTXFEIE            BIT(26)             /*!< periodic tx FIFO empty interrupt enable */
+#define GINTEN_HCIE               BIT(25)             /*!< host channels interrupt enable */
+#define GINTEN_HPIE               BIT(24)             /*!< host port interrupt enable */
+#define GINTEN_IPXIE              BIT(21)             /*!< periodic transfer not complete interrupt enable */
+#define GINTEN_ISOONCIE           BIT(21)             /*!< isochronous OUT transfer not complete interrupt enable */
+#define GINTEN_ISOINCIE           BIT(20)             /*!< isochronous IN transfer not complete interrupt enable */
+#define GINTEN_OEPIE              BIT(19)             /*!< OUT endpoints interrupt enable */
+#define GINTEN_IEPIE              BIT(18)             /*!< IN endpoints interrupt enable */
+#define GINTEN_EOPFIE             BIT(15)             /*!< end of periodic frame interrupt enable */
+#define GINTEN_ISOOPDIE           BIT(14)             /*!< isochronous OUT packet dropped interrupt enable */
+#define GINTEN_ENUMFIE            BIT(13)             /*!< enumeration finish enable */
+#define GINTEN_RSTIE              BIT(12)             /*!< USB reset interrupt enable */
+#define GINTEN_SPIE               BIT(11)             /*!< USB suspend interrupt enable */
+#define GINTEN_ESPIE              BIT(10)             /*!< early suspend interrupt enable */
+#define GINTEN_GONAKIE            BIT(7)              /*!< global OUT NAK effective interrupt enable */
+#define GINTEN_GNPINAKIE          BIT(6)              /*!< global non-periodic IN NAK effective interrupt enable */
+#define GINTEN_NPTXFEIE           BIT(5)              /*!< non-periodic TX FIFO empty interrupt enable */
+#define GINTEN_RXFNEIE            BIT(4)              /*!< receive FIFO non-empty interrupt enable */
+#define GINTEN_SOFIE              BIT(3)              /*!< start of frame interrupt enable */
+#define GINTEN_OTGIE              BIT(2)              /*!< OTG interrupt enable */
+#define GINTEN_MFIE               BIT(1)              /*!< mode fault interrupt enable */
+
+/* global receive status read and pop register bits definitions */
+#define GRSTATRP_RPCKST           BITS(17, 20)        /*!< received packet status */
+#define GRSTATRP_DPID             BITS(15, 16)        /*!< data PID */
+#define GRSTATRP_BCOUNT           BITS(4, 14)         /*!< byte count */
+#define GRSTATRP_CNUM             BITS(0, 3)          /*!< channel number */
+#define GRSTATRP_EPNUM            BITS(0, 3)          /*!< endpoint number */
+
+/* global receive FIFO length register bits definitions */
+#define GRFLEN_RXFD               BITS(0, 15)         /*!< rx FIFO depth */
+
+/* host non-periodic transmit FIFO length register bits definitions */
+#define HNPTFLEN_HNPTXFD          BITS(16, 31)        /*!< non-periodic TX FIFO depth */
+#define HNPTFLEN_HNPTXRSAR        BITS(0, 15)         /*!< non-periodic TX RAM start address */
+
+/* USB IN endpoint 0 transmit FIFO length register bits definitions */
+#define DIEP0TFLEN_IEP0TXFD       BITS(16, 31)        /*!< IN Endpoint 0 TX FIFO depth */
+#define DIEP0TFLEN_IEP0TXRSAR     BITS(0, 15)         /*!< IN Endpoint 0 TX RAM start address */
+
+/* host non-periodic transmit FIFO/queue status register bits definitions */
+#define HNPTFQSTAT_NPTXRQTOP      BITS(24, 30)        /*!< top entry of the non-periodic TX request queue */
+#define HNPTFQSTAT_NPTXRQS        BITS(16, 23)        /*!< non-periodic TX request queue space */
+#define HNPTFQSTAT_NPTXFS         BITS(0, 15)         /*!< non-periodic TX FIFO space */
+#define HNPTFQSTAT_CNUM           BITS(27, 30)        /*!< channel number*/
+#define HNPTFQSTAT_EPNUM          BITS(27, 30)        /*!< endpoint number */
+#define HNPTFQSTAT_TYPE           BITS(25, 26)        /*!< token type */
+#define HNPTFQSTAT_TMF            BIT(24)             /*!< terminate flag */
+
+/* global core configuration register bits definitions */
+#define GCCFG_VBUSIG              BIT(21)             /*!< vbus ignored */
+#define GCCFG_SOFOEN              BIT(20)             /*!< SOF output enable */
+#define GCCFG_VBUSBCEN            BIT(19)             /*!< the VBUS B-device comparer enable */
+#define GCCFG_VBUSACEN            BIT(18)             /*!< the VBUS A-device comparer enable */
+#define GCCFG_PWRON               BIT(16)             /*!< power on */
+
+/* core ID register bits definitions */
+#define CID_CID                   BITS(0, 31)         /*!< core ID */
+
+/* host periodic transmit FIFO length register bits definitions */
+#define HPTFLEN_HPTXFD            BITS(16, 31)        /*!< host periodic TX FIFO depth */
+#define HPTFLEN_HPTXFSAR          BITS(0, 15)         /*!< host periodic TX RAM start address */
+
+/* device IN endpoint transmit FIFO length register bits definitions */
+#define DIEPTFLEN_IEPTXFD         BITS(16, 31)        /*!< IN endpoint TX FIFO x depth */
+#define DIEPTFLEN_IEPTXRSAR       BITS(0, 15)         /*!< IN endpoint FIFOx TX x RAM start address */
+
+/* host control register bits definitions */
+#define HCTL_SPDFSLS              BIT(2)              /*!< speed limited to FS and LS */
+#define HCTL_CLKSEL               BITS(0, 1)          /*!< clock select for USB clock */
+
+/* host frame interval register bits definitions */
+#define HFT_FRI                   BITS(0, 15)         /*!< frame interval */
+
+/* host frame information remaining register bits definitions */
+#define HFINFR_FRT                BITS(16, 31)        /*!< frame remaining time */
+#define HFINFR_FRNUM              BITS(0, 15)         /*!< frame number */
+
+/* host periodic transmit FIFO/queue status register bits definitions */
+#define HPTFQSTAT_PTXREQT         BITS(24, 31)        /*!< top entry of the periodic TX request queue */
+#define HPTFQSTAT_PTXREQS         BITS(16, 23)        /*!< periodic TX request queue space */
+#define HPTFQSTAT_PTXFS           BITS(0, 15)         /*!< periodic TX FIFO space */
+#define HPTFQSTAT_OEFRM           BIT(31)             /*!< odd/eveb frame */
+#define HPTFQSTAT_CNUM            BITS(27, 30)        /*!< channel number */
+#define HPTFQSTAT_EPNUM           BITS(27, 30)        /*!< endpoint number */
+#define HPTFQSTAT_TYPE            BITS(25, 26)        /*!< token type */
+#define HPTFQSTAT_TMF             BIT(24)             /*!< terminate flag */
+
+#define TFQSTAT_TXFS              BITS(0, 15)
+#define TFQSTAT_CNUM              BITS(27, 30)
+
+/* host all channels interrupt register bits definitions */
+#define HACHINT_HACHINT           BITS(0, 11)         /*!< host all channel interrupts */
+
+/* host all channels interrupt enable register bits definitions */
+#define HACHINTEN_CINTEN          BITS(0, 11)         /*!< channel interrupt enable */
+
+/* host port control and status register bits definitions */
+#define HPCS_PS                   BITS(17, 18)        /*!< port speed */
+#define HPCS_PP                   BIT(12)             /*!< port power */
+#define HPCS_PLST                 BITS(10, 11)        /*!< port line status */
+#define HPCS_PRST                 BIT(8)              /*!< port reset */
+#define HPCS_PSP                  BIT(7)              /*!< port suspend */
+#define HPCS_PREM                 BIT(6)              /*!< port resume */
+#define HPCS_PEDC                 BIT(3)              /*!< port enable/disable change */
+#define HPCS_PE                   BIT(2)              /*!< port enable */
+#define HPCS_PCD                  BIT(1)              /*!< port connect detected */
+#define HPCS_PCST                 BIT(0)              /*!< port connect status */
+
+/* host channel-x control register bits definitions */
+#define HCHCTL_CEN                BIT(31)             /*!< channel enable */
+#define HCHCTL_CDIS               BIT(30)             /*!< channel disable */
+#define HCHCTL_ODDFRM             BIT(29)             /*!< odd frame */
+#define HCHCTL_DAR                BITS(22, 28)        /*!< device address */
+#define HCHCTL_MPC                BITS(20, 21)        /*!< multiple packet count */
+#define HCHCTL_EPTYPE             BITS(18, 19)        /*!< endpoint type */
+#define HCHCTL_LSD                BIT(17)             /*!< low-speed device */
+#define HCHCTL_EPDIR              BIT(15)             /*!< endpoint direction */
+#define HCHCTL_EPNUM              BITS(11, 14)        /*!< endpoint number */
+#define HCHCTL_MPL                BITS(0, 10)         /*!< maximum packet length */
+
+/* host channel-x split transaction register bits definitions */
+#define HCHSTCTL_SPLEN            BIT(31)             /*!< enable high-speed split transaction */
+#define HCHSTCTL_CSPLT            BIT(16)             /*!< complete-split enable */
+#define HCHSTCTL_ISOPCE           BITS(14, 15)        /*!< isochronous OUT payload continuation encoding */
+#define HCHSTCTL_HADDR            BITS(7, 13)         /*!< HUB address */
+#define HCHSTCTL_PADDR            BITS(0, 6)          /*!< port address */
+
+/* host channel-x interrupt flag register bits definitions */
+#define HCHINTF_DTER              BIT(10)             /*!< data toggle error */
+#define HCHINTF_REQOVR            BIT(9)              /*!< request queue overrun */
+#define HCHINTF_BBER              BIT(8)              /*!< babble error */
+#define HCHINTF_USBER             BIT(7)              /*!< USB bus Error */
+#define HCHINTF_NYET              BIT(6)              /*!< NYET */
+#define HCHINTF_ACK               BIT(5)              /*!< ACK */
+#define HCHINTF_NAK               BIT(4)              /*!< NAK */
+#define HCHINTF_STALL             BIT(3)              /*!< STALL */
+#define HCHINTF_CH                BIT(1)              /*!< channel halted */
+#define HCHINTF_TF                BIT(0)              /*!< transfer finished */
+
+/* host channel-x interrupt enable register bits definitions */
+#define HCHINTEN_DTERIE           BIT(10)             /*!< data toggle error interrupt enable */
+#define HCHINTEN_REQOVRIE         BIT(9)              /*!< request queue overrun interrupt enable */
+#define HCHINTEN_BBERIE           BIT(8)              /*!< babble error interrupt enable */
+#define HCHINTEN_USBERIE          BIT(7)              /*!< USB bus error interrupt enable */
+#define HCHINTEN_NYETIE           BIT(6)              /*!< NYET interrupt enable */
+#define HCHINTEN_ACKIE            BIT(5)              /*!< ACK interrupt enable */
+#define HCHINTEN_NAKIE            BIT(4)              /*!< NAK interrupt enable */
+#define HCHINTEN_STALLIE          BIT(3)              /*!< STALL interrupt enable */
+#define HCHINTEN_CHIE             BIT(1)              /*!< channel halted interrupt enable */
+#define HCHINTEN_TFIE             BIT(0)              /*!< transfer finished interrupt enable */
+
+/* host channel-x transfer length register bits definitions */
+#define HCHLEN_PING               BIT(31)             /*!< PING token request */
+#define HCHLEN_DPID               BITS(29, 30)        /*!< data PID */
+#define HCHLEN_PCNT               BITS(19, 28)        /*!< packet count */
+#define HCHLEN_TLEN               BITS(0, 18)         /*!< transfer length */
+
+#define PORT_SPEED(x)             (((uint32_t)(x) << 17) & HPCS_PS)         /*!< port speed */
+
+#define PORT_SPEED_HIGH           PORT_SPEED(0U)                            /*!< high speed */
+#define PORT_SPEED_FULL           PORT_SPEED(1U)                            /*!< full speed */
+#define PORT_SPEED_LOW            PORT_SPEED(2U)                            /*!< low speed */
+
+#define PIPE_CTL_DAR(x)           (((uint32_t)(x) << 22) & HCHCTL_DAR)      /*!< device address */
+#define PIPE_CTL_EPTYPE(x)        (((uint32_t)(x) << 18) & HCHCTL_EPTYPE)   /*!< endpoint type */
+#define PIPE_CTL_EPNUM(x)         (((uint32_t)(x) << 11) & HCHCTL_EPNUM)    /*!< endpoint number */
+#define PIPE_CTL_EPDIR(x)         (((uint32_t)(x) << 15) & HCHCTL_EPDIR)    /*!< endpoint direction */
+#define PIPE_CTL_EPMPL(x)         (((uint32_t)(x) <<  0) & HCHCTL_MPL)      /*!< maximum packet length */
+#define PIPE_CTL_LSD(x)           (((uint32_t)(x) << 17) & HCHCTL_LSD)      /*!< low-Speed device */
+
+#define PIPE_XFER_PCNT(x)         (((uint32_t)(x) << 19) & HCHLEN_PCNT)     /*!< packet count */
+#define PIPE_XFER_DPID(x)         (((uint32_t)(x) << 29) & HCHLEN_DPID)     /*!< data PID */
+
+#define PIPE_DPID_DATA0           PIPE_XFER_DPID(0U)                        /*!< DATA0 */
+#define PIPE_DPID_DATA1           PIPE_XFER_DPID(2U)                        /*!< DATA1 */
+#define PIPE_DPID_DATA2           PIPE_XFER_DPID(1U)                        /*!< DATA2 */
+#define PIPE_DPID_SETUP           PIPE_XFER_DPID(3U)                        /*!< MDATA (non-control)/SETUP (control) */
+
+extern const uint32_t PIPE_DPID[2];
+
+/* device configuration registers bits definitions */
+#define DCFG_EOPFT                BITS(11, 12)        /*!< end of periodic frame time */
+#define DCFG_DAR                  BITS(4, 10)         /*!< device address */
+#define DCFG_NZLSOH               BIT(2)              /*!< non-zero-length status OUT handshake */
+#define DCFG_DS                   BITS(0, 1)          /*!< device speed */
+
+/* device control registers bits definitions */
+#define DCTL_POIF                 BIT(11)             /*!< power-on initialization finished */
+#define DCTL_CGONAK               BIT(10)             /*!< clear global OUT NAK */
+#define DCTL_SGONAK               BIT(9)              /*!< set global OUT NAK */
+#define DCTL_CGINAK               BIT(8)              /*!< clear global IN NAK */
+#define DCTL_SGINAK               BIT(7)              /*!< set global IN NAK */
+#define DCTL_GONS                 BIT(3)              /*!< global OUT NAK status */
+#define DCTL_GINS                 BIT(2)              /*!< global IN NAK status */
+#define DCTL_SD                   BIT(1)              /*!< soft disconnect */
+#define DCTL_RWKUP                BIT(0)              /*!< remote wakeup */
+
+/* device status registers bits definitions */
+#define DSTAT_FNRSOF              BITS(8, 21)         /*!< the frame number of the received SOF. */
+#define DSTAT_ES                  BITS(1, 2)          /*!< enumerated speed */
+#define DSTAT_SPST                BIT(0)              /*!< suspend status */
+
+/* device IN endpoint common interrupt enable registers bits definitions */
+#define DIEPINTEN_NAKEN           BIT(13)             /*!< NAK handshake sent by USB interrupt enable bit */
+#define DIEPINTEN_TXFEEN          BIT(7)              /*!< transmit FIFO empty interrupt enable bit */
+#define DIEPINTEN_IEPNEEN         BIT(6)              /*!< IN endpoint NAK effective interrupt enable bit */
+#define DIEPINTEN_EPTXFUDEN       BIT(4)              /*!< endpoint TX FIFO underrun interrupt enable bit */
+#define DIEPINTEN_CITOEN          BIT(3)              /*!< control In Timeout interrupt enable bit */
+#define DIEPINTEN_EPDISEN         BIT(1)              /*!< endpoint disabled interrupt enable bit */
+#define DIEPINTEN_TFEN            BIT(0)              /*!< transfer finished interrupt enable bit */
+
+/* device OUT endpoint common interrupt enable registers bits definitions */
+#define DOEPINTEN_NYETEN          BIT(14)             /*!< NYET handshake is sent interrupt enable bit */
+#define DOEPINTEN_BTBSTPEN        BIT(6)              /*!< back-to-back SETUP packets interrupt enable bit */
+#define DOEPINTEN_EPRXFOVREN      BIT(4)              /*!< endpoint RX FIFO overrun interrupt enable bit */
+#define DOEPINTEN_STPFEN          BIT(3)              /*!< SETUP phase finished interrupt enable bit */
+#define DOEPINTEN_EPDISEN         BIT(1)              /*!< endpoint disabled interrupt enable bit */
+#define DOEPINTEN_TFEN            BIT(0)              /*!< transfer finished interrupt enable bit */
+
+/* device all endpoints interrupt registers bits definitions */
+#define DAEPINT_OEPITB            BITS(16, 21)        /*!< device all OUT endpoint interrupt bits */
+#define DAEPINT_IEPITB            BITS(0, 5)          /*!< device all IN endpoint interrupt bits */
+
+/* device all endpoints interrupt enable registers bits definitions */
+#define DAEPINTEN_OEPIE           BITS(16, 21)        /*!< OUT endpoint interrupt enable */
+#define DAEPINTEN_IEPIE           BITS(0, 3)          /*!< IN endpoint interrupt enable */
+
+/* device Vbus discharge time registers bits definitions */
+#define DVBUSDT_DVBUSDT           BITS(0, 15)         /*!< device VBUS discharge time */
+
+/* device Vbus pulsing time registers bits definitions */
+#define DVBUSPT_DVBUSPT           BITS(0, 11)         /*!< device VBUS pulsing time */
+
+/* device IN endpoint FIFO empty interrupt enable register bits definitions */
+#define DIEPFEINTEN_IEPTXFEIE     BITS(0, 5)          /*!< IN endpoint TX FIFO empty interrupt enable bits */
+
+/* device endpoint 0 control register bits definitions */
+#define DEP0CTL_EPEN              BIT(31)             /*!< endpoint enable */
+#define DEP0CTL_EPD               BIT(30)             /*!< endpoint disable */
+#define DEP0CTL_SNAK              BIT(27)             /*!< set NAK */
+#define DEP0CTL_CNAK              BIT(26)             /*!< clear NAK */
+#define DIEP0CTL_TXFNUM           BITS(22, 25)        /*!< tx FIFO number */
+#define DEP0CTL_STALL             BIT(21)             /*!< STALL handshake */
+#define DOEP0CTL_SNOOP            BIT(20)             /*!< snoop mode */
+#define DEP0CTL_EPTYPE            BITS(18, 19)        /*!< endpoint type */
+#define DEP0CTL_NAKS              BIT(17)             /*!< NAK status */
+#define DEP0CTL_EPACT             BIT(15)             /*!< endpoint active */
+#define DEP0CTL_MPL               BITS(0, 1)          /*!< maximum packet length */
+
+/* device endpoint x control register bits definitions */
+#define DEPCTL_EPEN               BIT(31)             /*!< endpoint enable */
+#define DEPCTL_EPD                BIT(30)             /*!< endpoint disable */
+#define DEPCTL_SODDFRM            BIT(29)             /*!< set odd frame */
+#define DEPCTL_SD1PID             BIT(29)             /*!< set DATA1 PID */
+#define DEPCTL_SEVNFRM            BIT(28)             /*!< set even frame */
+#define DEPCTL_SD0PID             BIT(28)             /*!< set DATA0 PID */
+#define DEPCTL_SNAK               BIT(27)             /*!< set NAK */
+#define DEPCTL_CNAK               BIT(26)             /*!< clear NAK */
+#define DIEPCTL_TXFNUM            BITS(22, 25)        /*!< tx FIFO number */
+#define DEPCTL_STALL              BIT(21)             /*!< STALL handshake */
+#define DOEPCTL_SNOOP             BIT(20)             /*!< snoop mode */
+#define DEPCTL_EPTYPE             BITS(18, 19)        /*!< endpoint type */
+#define DEPCTL_NAKS               BIT(17)             /*!< NAK status */
+#define DEPCTL_EOFRM              BIT(16)             /*!< even/odd frame */
+#define DEPCTL_DPID               BIT(16)             /*!< endpoint data PID */
+#define DEPCTL_EPACT              BIT(15)             /*!< endpoint active */
+#define DEPCTL_MPL                BITS(0, 10)         /*!< maximum packet length */
+
+/* device IN endpoint-x interrupt flag register bits definitions */
+#define DIEPINTF_NAK              BIT(13)             /*!< NAK handshake sent by USB */
+#define DIEPINTF_TXFE             BIT(7)              /*!< transmit FIFO empty */
+#define DIEPINTF_IEPNE            BIT(6)              /*!< IN endpoint NAK effective */
+#define DIEPINTF_EPTXFUD          BIT(4)              /*!< endpoint TX FIFO underrun */
+#define DIEPINTF_CITO             BIT(3)              /*!< control In Timeout interrupt */
+#define DIEPINTF_EPDIS            BIT(1)              /*!< endpoint disabled */
+#define DIEPINTF_TF               BIT(0)              /*!< transfer finished */
+
+/* device OUT endpoint-x interrupt flag register bits definitions */
+#define DOEPINTF_NYET             BIT(14)             /*!< NYET handshake is sent */
+#define DOEPINTF_BTBSTP           BIT(6)              /*!< back-to-back SETUP packets */
+#define DOEPINTF_EPRXFOVR         BIT(4)              /*!< endpoint RX FIFO overrun */
+#define DOEPINTF_STPF             BIT(3)              /*!< SETUP phase finished */
+#define DOEPINTF_EPDIS            BIT(1)              /*!< endpoint disabled */
+#define DOEPINTF_TF               BIT(0)              /*!< transfer finished */
+
+/* device IN endpoint 0 transfer length register bits definitions */
+#define DIEP0LEN_PCNT             BITS(19, 20)        /*!< packet count */
+#define DIEP0LEN_TLEN             BITS(0, 6)          /*!< transfer length */
+
+/* device OUT endpoint 0 transfer length register bits definitions */
+#define DOEP0LEN_STPCNT           BITS(29, 30)        /*!< SETUP packet count */
+#define DOEP0LEN_PCNT             BIT(19)             /*!< packet count */
+#define DOEP0LEN_TLEN             BITS(0, 6)          /*!< transfer length */
+
+/* device OUT endpoint-x transfer length register bits definitions */
+#define DOEPLEN_RXDPID            BITS(29, 30)        /*!< received data PID */
+#define DOEPLEN_STPCNT            BITS(29, 30)        /*!< SETUP packet count */
+#define DIEPLEN_MCNT              BITS(29, 30)        /*!< multi count */
+#define DEPLEN_PCNT               BITS(19, 28)        /*!< packet count */
+#define DEPLEN_TLEN               BITS(0, 18)         /*!< transfer length */
+
+/* device IN endpoint-x transmit FIFO status register bits definitions */
+#define DIEPTFSTAT_IEPTFS         BITS(0, 15)         /*!< IN endpoint TX FIFO space remaining */
+
+/* USB power and clock registers bits definition */
+#define PWRCLKCTL_SHCLK           BIT(1)              /*!< stop HCLK */
+#define PWRCLKCTL_SUCLK           BIT(0)              /*!< stop the USB clock */
+
+#define RSTAT_GOUT_NAK                  1U            /*!< global OUT NAK (triggers an interrupt) */
+#define RSTAT_DATA_UPDT                 2U            /*!< OUT data packet received */
+#define RSTAT_XFER_COMP                 3U            /*!< OUT transfer completed (triggers an interrupt) */
+#define RSTAT_SETUP_COMP                4U            /*!< SETUP transaction completed (triggers an interrupt) */
+#define RSTAT_SETUP_UPDT                6U            /*!< SETUP data packet received */
+
+#define DSTAT_EM_HS_PHY_30MHZ_60MHZ     0U            /*!< USB enumerate speed use high-speed PHY clock in 30MHz or 60MHz */
+#define DSTAT_EM_FS_PHY_30MHZ_60MHZ     1U            /*!< USB enumerate speed use full-speed PHY clock in 30MHz or 60MHz */
+#define DSTAT_EM_LS_PHY_6MHZ            2U            /*!< USB enumerate speed use low-speed PHY clock in 6MHz */
+#define DSTAT_EM_FS_PHY_48MHZ           3U            /*!< USB enumerate speed use full-speed PHY clock in 48MHz */
+
+#define DPID_DATA0                      0U            /*!< device endpoint data PID is DATA0 */
+#define DPID_DATA1                      2U            /*!< device endpoint data PID is DATA1 */
+#define DPID_DATA2                      1U            /*!< device endpoint data PID is DATA2 */
+#define DPID_MDATA                      3U            /*!< device endpoint data PID is MDATA */
+
+#define DCFG_PFRI(regval)         (DCFG_EOPFT & ((regval) << 11))   /*!< end of periodic frame time configuration */
+
+#define FRAME_INTERVAL_80         DCFG_PFRI(0U)                     /*!< 80% of the frame time */
+#define FRAME_INTERVAL_85         DCFG_PFRI(1U)                     /*!< 85% of the frame time */
+#define FRAME_INTERVAL_90         DCFG_PFRI(2U)                     /*!< 90% of the frame time */
+#define FRAME_INTERVAL_95         DCFG_PFRI(3U)                     /*!< 95% of the frame time */
+
+#define DCFG_DEVSPEED(regval)     (DCFG_DS & ((regval) << 0))       /*!< device speed configuration */
+
+#define USB_SPEED_EXP_HIGH        DCFG_DEVSPEED(0U)                 /*!< device external PHY high speed */
+#define USB_SPEED_EXP_FULL        DCFG_DEVSPEED(1U)                 /*!< device external PHY full speed */
+#define USB_SPEED_INP_FULL        DCFG_DEVSPEED(3U)                 /*!< device internal PHY full speed */
+
+#define DEP0_MPL(regval)          (DEP0CTL_MPL & ((regval) << 0))   /*!< maximum packet length configuration */
+
+#define EP0MPL_64                 DEP0_MPL(0U)                      /*!< maximum packet length 64 bytes */
+#define EP0MPL_32                 DEP0_MPL(1U)                      /*!< maximum packet length 32 bytes */
+#define EP0MPL_16                 DEP0_MPL(2U)                      /*!< maximum packet length 16 bytes */
+#define EP0MPL_8                  DEP0_MPL(3U)                      /*!< maximum packet length 8 bytes */
+
+#define DOEP0_TLEN(regval)        (DOEP0LEN_TLEN & ((regval) << 0))      /*!< transfer length */
+#define DOEP0_PCNT(regval)        (DOEP0LEN_PCNT & ((regval) << 19))     /*!< packet count */
+#define DOEP0_STPCNT(regval)      (DOEP0LEN_STPCNT & ((regval) << 29))   /*!< SETUP packet count */
+
+#define USB_ULPI_PHY                            1U                       /*!< ULPI interface external PHY */
+#define USB_EMBEDDED_PHY                        2U                       /*!< embedded PHY */
+
+#define GRXSTS_PKTSTS_IN                        2U
+#define GRXSTS_PKTSTS_IN_XFER_COMP              3U
+#define GRXSTS_PKTSTS_DATA_TOGGLE_ERR           5U
+#define GRXSTS_PKTSTS_CH_HALTED                 7U
+
+#define HCTL_30_60MHZ                           0U                       /*!< USB clock 30-60MHZ */
+#define HCTL_48MHZ                              1U                       /*!< USB clock 48MHZ */
+#define HCTL_6MHZ                               2U                       /*!< USB clock 6MHZ */
+
+#define EP0_OUT                   ((uint8_t)0x00U)                       /*!< endpoint OUT 0 */
+#define EP0_IN                    ((uint8_t)0x80U)                       /*!< endpoint IN 0 */
+#define EP1_OUT                   ((uint8_t)0x01U)                       /*!< endpoint OUT 1 */
+#define EP1_IN                    ((uint8_t)0x81U)                       /*!< endpoint IN 1 */
+#define EP2_OUT                   ((uint8_t)0x02U)                       /*!< endpoint OUT 2 */
+#define EP2_IN                    ((uint8_t)0x82U)                       /*!< endpoint IN 2 */
+#define EP3_OUT                   ((uint8_t)0x03U)                       /*!< endpoint OUT 3 */
+#define EP3_IN                    ((uint8_t)0x83U)                       /*!< endpoint IN 3 */
+
+#endif /* DRV_USB_REGS_H */

+ 45 - 0
GD32F3x0/GD32F3x0_usbfs_library/driver/Include/drv_usbd_int.h

@@ -0,0 +1,45 @@
+/*!
+    \file    drv_usbd_int.h
+    \brief   USB device mode interrupt header file
+
+    \version 2025-01-01, V2.5.0, firmware for GD32F3x0
+*/
+
+/*
+    Copyright (c) 2025, GigaDevice Semiconductor Inc.
+
+    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 of the copyright holder 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 HOLDER 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.
+*/
+
+#ifndef DRV_USBD_INT_H
+#define DRV_USBD_INT_H
+
+#include "drv_usb_core.h"
+#include "drv_usb_dev.h"
+
+/* function declarations */
+/* USB device-mode interrupts global service routine handler */
+void usbd_isr(usb_core_driver *udev);
+
+#endif /* DRV_USBD_INT_H */

+ 53 - 0
GD32F3x0/GD32F3x0_usbfs_library/driver/Include/drv_usbh_int.h

@@ -0,0 +1,53 @@
+/*!
+    \file    drv_usbh_int.h.h
+    \brief   USB host mode interrupt management header file
+
+    \version 2025-01-01, V2.5.0, firmware for GD32F3x0
+*/
+
+/*
+    Copyright (c) 2025, GigaDevice Semiconductor Inc.
+
+    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 of the copyright holder 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 HOLDER 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.
+*/
+
+#ifndef DRV_USBH_INT_H
+#define DRV_USBH_INT_H
+
+#include "drv_usb_host.h"
+#include "usbh_core.h"
+
+typedef struct _usbh_ev_cb {
+    uint8_t (*connect)(usbh_host *uhost);
+    uint8_t (*disconnect)(usbh_host *uhost);
+    uint8_t (*SOF)(usbh_host *uhost);
+} usbh_ev_cb;
+
+extern usbh_ev_cb *usbh_int_fop;
+
+/* function declarations */
+/* handle global host interrupt */
+uint32_t usbh_isr(usb_core_driver *udev);
+
+#endif /* DRV_USBH_INT_H */

+ 319 - 0
GD32F3x0/GD32F3x0_usbfs_library/driver/Source/drv_usb_core.c

@@ -0,0 +1,319 @@
+/*!
+    \file    drv_usb_core.c
+    \brief   USB core driver which can operate in host and device mode
+
+    \version 2025-01-01, V2.5.0, firmware for GD32F3x0
+*/
+
+/*
+    Copyright (c) 2025, GigaDevice Semiconductor Inc.
+
+    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 of the copyright holder 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 HOLDER 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.
+*/
+
+#include "drv_usb_core.h"
+#include "drv_usb_hw.h"
+
+/* local function prototypes ('static') */
+static void usb_core_reset(usb_core_regs *usb_regs);
+
+/*!
+    \brief      configure USB core basic
+    \param[in]  usb_basic: pointer to USB capabilities
+    \param[in]  usb_regs: USB core registers
+    \param[out] none
+    \retval     operation status
+*/
+usb_status usb_basic_init(usb_core_basic *usb_basic, usb_core_regs  *usb_regs)
+{
+    /* configure USB default transfer mode as FIFO mode */
+    usb_basic->transfer_mode = (uint8_t)USB_USE_FIFO;
+
+    /* USB default speed is full-speed */
+    usb_basic->core_speed = (uint8_t)USB_SPEED_FULL;
+
+    usb_basic->base_reg = (uint32_t)USBFS_REG_BASE;
+
+    /* set the host channel numbers */
+    usb_basic->num_pipe = USBFS_MAX_CHANNEL_COUNT;
+
+    /* set the device endpoint numbers */
+    usb_basic->num_ep = USBFS_MAX_EP_COUNT;
+
+    /* USBFS core use embedded physical layer */
+    usb_basic->phy_itf = USB_EMBEDDED_PHY;
+
+    /* configure the SOF output and the low power support */
+    usb_basic->sof_enable = USB_SOF_OUTPUT;
+    usb_basic->low_power = USB_LOW_POWER;
+
+    /* assign main registers address */
+    *usb_regs = (usb_core_regs) {
+        .gr          = (usb_gr *)(usb_basic->base_reg + USB_REG_OFFSET_CORE),
+        .hr          = (usb_hr *)(usb_basic->base_reg + USB_REG_OFFSET_HOST),
+        .dr          = (usb_dr *)(usb_basic->base_reg + USB_REG_OFFSET_DEV),
+
+        .HPCS        = (uint32_t *)(usb_basic->base_reg + USB_REG_OFFSET_PORT),
+        .PWRCLKCTL   = (uint32_t *)(usb_basic->base_reg + USB_REG_OFFSET_PWRCLKCTL)
+    };
+
+    /* assign device endpoint registers address */
+    for(uint8_t i = 0U; i < usb_basic->num_ep; i++) {
+        usb_regs->er_in[i] = (usb_erin *) \
+                             (usb_basic->base_reg + USB_REG_OFFSET_EP_IN + (i * USB_REG_OFFSET_EP));
+
+        usb_regs->er_out[i] = (usb_erout *)\
+                              (usb_basic->base_reg + USB_REG_OFFSET_EP_OUT + (i * USB_REG_OFFSET_EP));
+    }
+
+    /* assign host pipe registers address */
+    for(uint8_t i = 0U; i < usb_basic->num_pipe; i++) {
+        usb_regs->pr[i] = (usb_pr *) \
+                          (usb_basic->base_reg + USB_REG_OFFSET_CH_INOUT + (i * USB_REG_OFFSET_CH));
+
+        usb_regs->DFIFO[i] = (uint32_t *) \
+                             (usb_basic->base_reg + USB_DATA_FIFO_OFFSET + (i * USB_DATA_FIFO_SIZE));
+    }
+
+    return USB_OK;
+}
+
+/*!
+    \brief      initializes the USB controller registers and
+                prepares the core device mode or host mode operation
+    \param[in]  usb_basic: pointer to USB capabilities
+    \param[in]  usb_regs: pointer to USB core registers
+    \param[out] none
+    \retval     operation status
+*/
+usb_status usb_core_init(usb_core_basic usb_basic, usb_core_regs *usb_regs)
+{
+    if(USB_ULPI_PHY == usb_basic.phy_itf) {
+        usb_regs->gr->GCCFG &= ~GCCFG_PWRON;
+
+        if(usb_basic.sof_enable) {
+            usb_regs->gr->GCCFG |= GCCFG_SOFOEN;
+        }
+
+        /* initialize the ULPI interface */
+        usb_regs->gr->GUSBCS &= ~(GUSBCS_EMBPHY | GUSBCS_ULPIEOI);
+
+        /* soft reset the core */
+        usb_core_reset(usb_regs);
+    } else {
+        usb_regs->gr->GUSBCS |= GUSBCS_EMBPHY;
+
+        /* soft reset the core */
+        usb_core_reset(usb_regs);
+
+        /* active the transceiver and enable VBUS sensing */
+        usb_regs->gr->GCCFG |= GCCFG_PWRON | GCCFG_VBUSACEN | GCCFG_VBUSBCEN;
+
+#ifndef VBUS_SENSING_ENABLED
+        usb_regs->gr->GCCFG |= GCCFG_VBUSIG;
+#endif /* VBUS_SENSING_ENABLED */
+
+        /* enable SOF output */
+        if(usb_basic.sof_enable) {
+            usb_regs->gr->GCCFG |= GCCFG_SOFOEN;
+        }
+
+        usb_mdelay(20U);
+    }
+
+#ifdef USE_OTG_MODE
+
+    /* enable USB OTG features */
+    usb_regs->gr->GUSBCS |= GUSBCS_HNPCEN | GUSBCS_SRPCEN;
+
+    /* enable the USB wakeup and suspend interrupts */
+    usb_regs->gr->GINTF = 0xBFFFFFFFU;
+
+    usb_regs->gr->GINTEN = GINTEN_WKUPIE | GINTEN_SPIE | \
+                           GINTEN_OTGIE | GINTEN_SESIE | GINTEN_CIDPSCIE;
+
+#endif /* USE_OTG_MODE */
+
+    return USB_OK;
+}
+
+/*!
+    \brief      write a packet into the TX FIFO associated with the endpoint
+    \param[in]  usb_regs: pointer to USB core registers
+    \param[in]  src_buf: pointer to source buffer
+    \param[in]  fifo_num: FIFO number which is in (0..3)
+    \param[in]  byte_count: packet byte count
+    \param[out] none
+    \retval     operation status
+*/
+usb_status usb_txfifo_write(usb_core_regs *usb_regs, \
+                            uint8_t *src_buf, \
+                            uint8_t  fifo_num, \
+                            uint16_t byte_count)
+{
+    uint32_t word_count = (byte_count + 3U) / 4U;
+
+    __IO uint32_t *fifo = usb_regs->DFIFO[fifo_num];
+
+    while(word_count-- > 0U) {
+        *fifo = *((__packed uint32_t *)src_buf);
+
+        src_buf += 4U;
+    }
+
+    return USB_OK;
+}
+
+/*!
+    \brief      read a packet from the RX FIFO associated with the endpoint
+    \param[in]  usb_regs: pointer to USB core registers
+    \param[in]  dest_buf: pointer to destination buffer
+    \param[in]  byte_count: packet byte count
+    \param[out] none
+    \retval     void type pointer
+*/
+void *usb_rxfifo_read(usb_core_regs *usb_regs, uint8_t *dest_buf, uint16_t byte_count)
+{
+    uint32_t word_count = (byte_count + 3U) / 4U;
+
+    __IO uint32_t *fifo = usb_regs->DFIFO[0];
+
+    while(word_count-- > 0U) {
+        *(__packed uint32_t *)dest_buf = *fifo;
+
+        dest_buf += 4U;
+    }
+
+    return ((void *)dest_buf);
+}
+
+/*!
+    \brief      flush a TX FIFO or all TX FIFOs
+    \param[in]  usb_regs: pointer to USB core registers
+    \param[in]  fifo_num: FIFO number which is in (0..3)
+    \param[out] none
+    \retval     operation status
+*/
+usb_status usb_txfifo_flush(usb_core_regs *usb_regs, uint8_t fifo_num)
+{
+    usb_regs->gr->GRSTCTL = ((uint32_t)fifo_num << 6) | GRSTCTL_TXFF;
+
+    /* wait for TX FIFO flush bit is set */
+    while(usb_regs->gr->GRSTCTL & GRSTCTL_TXFF) {
+        /* no operation */
+    }
+
+    /* wait for 3 PHY clocks*/
+    usb_udelay(3U);
+
+    return USB_OK;
+}
+
+/*!
+    \brief      flush the entire RX FIFO
+    \param[in]  usb_regs: pointer to USB core registers
+    \param[out] none
+    \retval     operation status
+*/
+usb_status usb_rxfifo_flush(usb_core_regs *usb_regs)
+{
+    usb_regs->gr->GRSTCTL = GRSTCTL_RXFF;
+
+    /* wait for RX FIFO flush bit is set */
+    while(usb_regs->gr->GRSTCTL & GRSTCTL_RXFF) {
+        /* no operation */
+    }
+
+    /* wait for 3 PHY clocks */
+    usb_udelay(3U);
+
+    return USB_OK;
+}
+
+/*!
+    \brief      set endpoint or channel TX FIFO size
+    \param[in]  usb_regs: pointer to USB core registers
+    \param[in]  fifo: TX FIFO number
+    \param[in]  size: assigned TX FIFO size
+    \param[out] none
+    \retval     none
+*/
+void usb_set_txfifo(usb_core_regs *usb_regs, uint8_t fifo, uint16_t size)
+{
+    uint32_t tx_offset = usb_regs->gr->GRFLEN;
+
+    if(0U == fifo) {
+        usb_regs->gr->DIEP0TFLEN_HNPTFLEN = ((uint32_t)size << 16) | tx_offset;
+    } else {
+        tx_offset += (usb_regs->gr->DIEP0TFLEN_HNPTFLEN) >> 16;
+
+        for(uint8_t i = 0U; i < (fifo - 1U); i++) {
+            tx_offset += (usb_regs->gr->DIEPTFLEN[i] >> 16);
+        }
+
+        /* multiply Tx_Size by 2 to get higher performance */
+        usb_regs->gr->DIEPTFLEN[fifo - 1U] = ((uint32_t)size << 16) | tx_offset;
+    }
+}
+
+/*!
+    \brief      set USB current mode
+    \param[in]  usb_regs: pointer to USB core registers
+    \param[in]  mode: USB current mode 
+    \param[out] none
+    \retval     none
+*/
+void usb_curmode_set(usb_core_regs *usb_regs, uint8_t mode)
+{
+    usb_regs->gr->GUSBCS &= ~(GUSBCS_FDM | GUSBCS_FHM);
+
+    if(DEVICE_MODE == mode) {
+        usb_regs->gr->GUSBCS |= GUSBCS_FDM;
+    } else if(HOST_MODE == mode) {
+        usb_regs->gr->GUSBCS |= GUSBCS_FHM;
+    } else {
+        /* OTG mode and other mode can not be here! */
+    }
+}
+
+/*!
+    \brief      configure USB core to soft reset
+    \param[in]  usb_regs: pointer to USB core registers
+    \param[out] none
+    \retval     none
+*/
+static void usb_core_reset(usb_core_regs *usb_regs)
+{
+    /* enable core soft reset */
+    usb_regs->gr->GRSTCTL |= GRSTCTL_CSRST;
+
+    /* wait for the core to be soft reset */
+    while(usb_regs->gr->GRSTCTL & GRSTCTL_CSRST) {
+        /* no operation */
+    }
+
+    /* wait for additional 3 PHY clocks */
+    usb_udelay(3U);
+}
+

+ 585 - 0
GD32F3x0/GD32F3x0_usbfs_library/driver/Source/drv_usb_dev.c

@@ -0,0 +1,585 @@
+/*!
+    \file    drv_usb_dev.c
+    \brief   USB device mode low level driver
+
+    \version 2025-01-01, V2.5.0, firmware for GD32F3x0
+*/
+
+/*
+    Copyright (c) 2025, GigaDevice Semiconductor Inc.
+
+    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 of the copyright holder 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 HOLDER 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.
+*/
+
+#include "drv_usb_hw.h"
+#include "drv_usb_dev.h"
+
+/* endpoint 0 max packet length */
+static const uint8_t EP0_MAXLEN[4] = {
+    [DSTAT_EM_HS_PHY_30MHZ_60MHZ] = EP0MPL_64,
+    [DSTAT_EM_FS_PHY_30MHZ_60MHZ] = EP0MPL_64,
+    [DSTAT_EM_FS_PHY_48MHZ] = EP0MPL_64,
+    [DSTAT_EM_LS_PHY_6MHZ] = EP0MPL_8
+};
+
+/* USB endpoint TX FIFO size */
+static uint16_t USBFS_TX_FIFO_SIZE[USBFS_MAX_EP_COUNT] = {
+    (uint16_t)TX0_FIFO_FS_SIZE,
+    (uint16_t)TX1_FIFO_FS_SIZE,
+    (uint16_t)TX2_FIFO_FS_SIZE,
+    (uint16_t)TX3_FIFO_FS_SIZE
+};
+
+/*!
+    \brief      initialize USB core registers for device mode
+    \param[in]  udev: pointer to USB device
+    \param[out] none
+    \retval     operation status
+*/
+usb_status usb_devcore_init(usb_core_driver *udev)
+{
+    uint8_t i = 0U;
+
+    /* restart the PHY clock (maybe don't need to...) */
+    *udev->regs.PWRCLKCTL = 0U;
+
+    /* configure periodic frame interval to default value */
+    udev->regs.dr->DCFG &= ~DCFG_EOPFT;
+    udev->regs.dr->DCFG |= FRAME_INTERVAL_80;
+
+    udev->regs.dr->DCFG &= ~DCFG_DS;
+
+    /* set full-speed PHY */
+    udev->regs.dr->DCFG |= USB_SPEED_INP_FULL;
+
+    /* set RX FIFO size */
+    usb_set_rxfifo(&udev->regs, RX_FIFO_FS_SIZE);
+
+    /* set endpoint 0 to 3's TX FIFO length and RAM address */
+    for(i = 0U; i < USBFS_MAX_EP_COUNT; i++) {
+        usb_set_txfifo(&udev->regs, i, USBFS_TX_FIFO_SIZE[i]);
+    }
+
+    /* make sure all FIFOs are flushed */
+
+    /* flush all TX FIFOs */
+    (void)usb_txfifo_flush(&udev->regs, 0x10U);
+
+    /* flush entire RX FIFO */
+    (void)usb_rxfifo_flush(&udev->regs);
+
+    /* clear all pending device interrupts */
+    udev->regs.dr->DIEPINTEN = 0U;
+    udev->regs.dr->DOEPINTEN = 0U;
+    udev->regs.dr->DAEPINT = 0xFFFFFFFFU;
+    udev->regs.dr->DAEPINTEN = 0U;
+
+    /* configure all IN/OUT endpoints */
+    for(i = 0U; i < udev->bp.num_ep; i++) {
+        if(udev->regs.er_in[i]->DIEPCTL & DEPCTL_EPEN) {
+            udev->regs.er_in[i]->DIEPCTL |= DEPCTL_EPD | DEPCTL_SNAK;
+        } else {
+            udev->regs.er_in[i]->DIEPCTL = 0U;
+        }
+
+        /* set IN endpoint transfer length to 0 */
+        udev->regs.er_in[i]->DIEPLEN = 0U;
+
+        /* clear all pending IN endpoint interrupts */
+        udev->regs.er_in[i]->DIEPINTF = 0xFFU;
+
+        if(udev->regs.er_out[i]->DOEPCTL & DEPCTL_EPEN) {
+            udev->regs.er_out[i]->DOEPCTL |= DEPCTL_EPD | DEPCTL_SNAK;
+        } else {
+            udev->regs.er_out[i]->DOEPCTL = 0U;
+        }
+
+        /* set OUT endpoint transfer length to 0 */
+        udev->regs.er_out[i]->DOEPLEN = 0U;
+
+        /* clear all pending OUT endpoint interrupts */
+        udev->regs.er_out[i]->DOEPINTF = 0xFFU;
+    }
+
+    udev->regs.dr->DIEPINTEN |= DIEPINTEN_EPTXFUDEN;
+
+    (void)usb_devint_enable(udev);
+
+    return USB_OK;
+}
+
+/*!
+    \brief      enable the USB device mode interrupts
+    \param[in]  udev: pointer to USB device
+    \param[out] none
+    \retval     operation status
+*/
+usb_status usb_devint_enable(usb_core_driver *udev)
+{
+    /* clear any pending USB OTG interrupts */
+    udev->regs.gr->GOTGINTF = 0xFFFFFFFFU;
+
+    /* clear any pending interrupts */
+    udev->regs.gr->GINTF = 0xBFFFFFFFU;
+
+    /* enable the USB wakeup and suspend interrupts */
+    udev->regs.gr->GINTEN = GINTEN_WKUPIE | GINTEN_SPIE;
+
+    /* enable device_mode-related interrupts */
+    if((uint8_t)USB_USE_FIFO == udev->bp.transfer_mode) {
+        udev->regs.gr->GINTEN |= GINTEN_RXFNEIE;
+    }
+
+    udev->regs.gr->GINTEN |= GINTEN_RSTIE | GINTEN_ENUMFIE | GINTEN_IEPIE | \
+                             GINTEN_OEPIE | GINTEN_SOFIE | GINTEN_ISOONCIE | GINTEN_ISOINCIE;
+
+#ifdef VBUS_SENSING_ENABLED
+    udev->regs.gr->GINTEN |= GINTEN_SESIE | GINTEN_OTGIE;
+#endif /* VBUS_SENSING_ENABLED */
+
+    return USB_OK;
+}
+
+/*!
+    \brief      active the USB endpoint0 transaction
+    \param[in]  udev: pointer to USB device
+    \param[in]  transc: the USB endpoint0 transaction
+    \param[out] none
+    \retval     operation status
+*/
+usb_status usb_transc0_active(usb_core_driver *udev, usb_transc *transc)
+{
+    __IO uint32_t *reg_addr = NULL;
+
+    uint32_t enum_speed = udev->regs.dr->DSTAT & DSTAT_ES;
+
+    /* get the endpoint number */
+    uint8_t ep_num = transc->ep_addr.num;
+
+    if(ep_num) {
+        /* not endpoint 0 */
+        return USB_FAIL;
+    }
+
+    if(transc->ep_addr.dir) {
+        reg_addr = &udev->regs.er_in[0]->DIEPCTL;
+    } else {
+        reg_addr = &udev->regs.er_out[0]->DOEPCTL;
+    }
+
+    /* endpoint 0 is activated after USB clock is enabled */
+    *reg_addr &= ~(DEPCTL_MPL | DEPCTL_EPTYPE | DIEPCTL_TXFNUM);
+
+    /* set endpoint 0 maximum packet length */
+    *reg_addr |= EP0_MAXLEN[enum_speed];
+
+    /* activate endpoint */
+    *reg_addr |= ((uint32_t)transc->ep_type << 18) | ((uint32_t)ep_num << 22) | DEPCTL_SD0PID | DEPCTL_EPACT;
+
+    return USB_OK;
+}
+
+/*!
+    \brief      active the USB transaction
+    \param[in]  udev: pointer to USB device
+    \param[in]  transc: the USB transaction
+    \param[out] none
+    \retval     status
+*/
+usb_status usb_transc_active(usb_core_driver *udev, usb_transc *transc)
+{
+    __IO uint32_t *reg_addr = NULL;
+    uint32_t epinten = 0U;
+    uint32_t enum_speed = udev->regs.dr->DSTAT & DSTAT_ES;
+
+    /* get the endpoint number */
+    uint8_t ep_num = transc->ep_addr.num;
+
+    /* enable endpoint interrupt number */
+    if(transc->ep_addr.dir) {
+        reg_addr = &udev->regs.er_in[ep_num]->DIEPCTL;
+
+        epinten = 1U << ep_num;
+    } else {
+        reg_addr = &udev->regs.er_out[ep_num]->DOEPCTL;
+
+        epinten = 1U << (16U + ep_num);
+    }
+
+    /* if the endpoint is not active, need change the endpoint control register */
+    if(!(*reg_addr & DEPCTL_EPACT)) {
+        *reg_addr &= ~(DEPCTL_MPL | DEPCTL_EPTYPE | DIEPCTL_TXFNUM);
+
+        /* set endpoint maximum packet length */
+        if(0U == ep_num) {
+            *reg_addr |= EP0_MAXLEN[enum_speed];
+        } else {
+            *reg_addr |= transc->max_len;
+        }
+
+        /* activate endpoint */
+        *reg_addr |= ((uint32_t)transc->ep_type << 18) | ((uint32_t)ep_num << 22) | DEPCTL_SD0PID | DEPCTL_EPACT;
+    }
+
+    /* enable the interrupts for this endpoint */
+    udev->regs.dr->DAEPINTEN |= epinten;
+
+    return USB_OK;
+}
+
+/*!
+    \brief      deactivate the USB transaction
+    \param[in]  udev: pointer to USB device
+    \param[in]  transc: the USB transaction
+    \param[out] none
+    \retval     status
+*/
+usb_status usb_transc_deactivate(usb_core_driver *udev, usb_transc *transc)
+{
+    uint32_t epinten = 0U;
+
+    uint8_t ep_num = transc->ep_addr.num;
+
+    /* disable endpoint interrupt number */
+    if(transc->ep_addr.dir) {
+        epinten = 1U << ep_num;
+
+        udev->regs.er_in[ep_num]->DIEPCTL &= ~DEPCTL_EPACT;
+    } else {
+        epinten = 1U << (ep_num + 16U);
+
+        udev->regs.er_out[ep_num]->DOEPCTL &= ~DEPCTL_EPACT;
+    }
+
+    /* disable the interrupts for this endpoint */
+    udev->regs.dr->DAEPINTEN &= ~epinten;
+
+    return USB_OK;
+}
+
+/*!
+    \brief      configure USB transaction to start IN transfer
+    \param[in]  udev: pointer to USB device
+    \param[in]  transc: the USB IN transaction
+    \param[out] none
+    \retval     operation status
+*/
+usb_status usb_transc_inxfer(usb_core_driver *udev, usb_transc *transc)
+{
+    usb_status status = USB_OK;
+
+    uint8_t ep_num = transc->ep_addr.num;
+
+    __IO uint32_t epctl = udev->regs.er_in[ep_num]->DIEPCTL;
+    __IO uint32_t eplen = udev->regs.er_in[ep_num]->DIEPLEN;
+
+    eplen &= ~(DEPLEN_TLEN | DEPLEN_PCNT);
+
+    /* zero length packet or endpoint 0 */
+    if(0U == transc->xfer_len) {
+        /* set transfer packet count to 1 */
+        eplen |= 1U << 19;
+    } else {
+        /* set transfer packet count */
+        if(0U == ep_num) {
+            transc->xfer_len = USB_MIN(transc->xfer_len, transc->max_len);
+
+            eplen |= 1U << 19;
+        } else {
+            eplen |= (((transc->xfer_len - 1U) + transc->max_len) / transc->max_len) << 19;
+        }
+
+        /* set endpoint transfer length */
+        eplen |= transc->xfer_len;
+
+        if((uint8_t)USB_EPTYPE_ISOC == transc->ep_type) {
+            eplen |= DIEPLEN_MCNT & (1U << 29);
+        }
+    }
+
+    udev->regs.er_in[ep_num]->DIEPLEN = eplen;
+
+    if((uint8_t)USB_EPTYPE_ISOC == transc->ep_type) {
+        if(((udev->regs.dr->DSTAT & DSTAT_FNRSOF) >> 8) & 0x01U) {
+            epctl |= DEPCTL_SEVNFRM;
+        } else {
+            epctl |= DEPCTL_SODDFRM;
+        }
+    }
+
+    /* enable the endpoint and clear the NAK */
+    epctl |= DEPCTL_CNAK | DEPCTL_EPEN;
+
+    udev->regs.er_in[ep_num]->DIEPCTL = epctl;
+
+    if((uint8_t)USB_USE_FIFO == udev->bp.transfer_mode) {
+        if((uint8_t)USB_EPTYPE_ISOC != transc->ep_type) {
+            /* enable the TX FIFO empty interrupt for this endpoint */
+            if(transc->xfer_len > 0U) {
+                udev->regs.dr->DIEPFEINTEN |= 1U << ep_num;
+            }
+        } else {
+            (void)usb_txfifo_write(&udev->regs, transc->xfer_buf, ep_num, (uint16_t)transc->xfer_len);
+        }
+    }
+
+    return status;
+}
+
+/*!
+    \brief      configure USB transaction to start OUT transfer
+    \param[in]  udev: pointer to USB device
+    \param[in]  transc: the USB OUT transaction
+    \param[out] none
+    \retval     status
+*/
+usb_status usb_transc_outxfer(usb_core_driver *udev, usb_transc *transc)
+{
+    usb_status status = USB_OK;
+
+    uint8_t ep_num = transc->ep_addr.num;
+
+    uint32_t epctl = udev->regs.er_out[ep_num]->DOEPCTL;
+    uint32_t eplen = udev->regs.er_out[ep_num]->DOEPLEN;
+
+    eplen &= ~(DEPLEN_TLEN | DEPLEN_PCNT);
+
+    /* zero length packet or endpoint 0 */
+    if((0U == transc->xfer_len) || (0U == ep_num)) {
+        /* set the transfer length to max packet size */
+        eplen |= transc->max_len;
+
+        /* set the transfer packet count to 1 */
+        eplen |= 1U << 19;
+    } else {
+        /* configure the transfer size and packet count as follows:
+         * pktcnt = N
+         * xfersize = N * maxpacket
+         */
+        uint32_t packet_count = (transc->xfer_len + transc->max_len - 1U) / transc->max_len;
+
+        eplen |= packet_count << 19;
+        eplen |= packet_count * transc->max_len;
+    }
+
+    udev->regs.er_out[ep_num]->DOEPLEN = eplen;
+
+    if((uint8_t)USB_EPTYPE_ISOC == transc->ep_type) {
+        if(transc->frame_num) {
+            epctl |= DEPCTL_SD1PID;
+        } else {
+            epctl |= DEPCTL_SD0PID;
+        }
+    }
+
+    /* enable the endpoint and clear the NAK */
+    epctl |= DEPCTL_EPEN | DEPCTL_CNAK;
+
+    udev->regs.er_out[ep_num]->DOEPCTL = epctl;
+
+    return status;
+}
+
+/*!
+    \brief      set the USB transaction STALL status
+    \param[in]  udev: pointer to USB device
+    \param[in]  transc: the USB transaction
+    \param[out] none
+    \retval     status
+*/
+usb_status usb_transc_stall(usb_core_driver *udev, usb_transc *transc)
+{
+    __IO uint32_t *reg_addr = NULL;
+
+    uint8_t ep_num = transc->ep_addr.num;
+
+    if(transc->ep_addr.dir) {
+        reg_addr = &(udev->regs.er_in[ep_num]->DIEPCTL);
+
+        /* set the endpoint disable bit */
+        if(*reg_addr & DEPCTL_EPEN) {
+            *reg_addr |= DEPCTL_EPD;
+        }
+    } else {
+        /* set the endpoint STALL bit */
+        reg_addr = &(udev->regs.er_out[ep_num]->DOEPCTL);
+    }
+
+    /* set the endpoint STALL bit */
+    *reg_addr |= DEPCTL_STALL;
+
+    return USB_OK;
+}
+
+/*!
+    \brief      clear the USB transaction STALL status
+    \param[in]  udev: pointer to USB device
+    \param[in]  transc: the USB transaction
+    \param[out] none
+    \retval     operation status
+*/
+usb_status usb_transc_clrstall(usb_core_driver *udev, usb_transc *transc)
+{
+    __IO uint32_t *reg_addr = NULL;
+
+    uint8_t ep_num = transc->ep_addr.num;
+
+    if(transc->ep_addr.dir) {
+        reg_addr = &(udev->regs.er_in[ep_num]->DIEPCTL);
+    } else {
+        reg_addr = &(udev->regs.er_out[ep_num]->DOEPCTL);
+    }
+
+    /* clear the endpoint STALL bit */
+    *reg_addr &= ~DEPCTL_STALL;
+
+    /* reset data PID of the periodic endpoints */
+    if(((uint8_t)USB_EPTYPE_INTR == transc->ep_type) || ((uint8_t)USB_EPTYPE_BULK == transc->ep_type)) {
+        *reg_addr |= DEPCTL_SD0PID;
+    }
+
+    return USB_OK;
+}
+
+/*!
+    \brief      read device IN endpoint interrupt flag register
+    \param[in]  udev: pointer to USB device
+    \param[in]  ep_num: endpoint number
+    \param[out] none
+    \retval     interrupt value
+*/
+uint32_t usb_iepintr_read(usb_core_driver *udev, uint8_t ep_num)
+{
+    uint32_t value = 0U, fifoemptymask, commonintmask;
+
+    commonintmask = udev->regs.dr->DIEPINTEN;
+    fifoemptymask = udev->regs.dr->DIEPFEINTEN;
+
+    /* check FIFO empty interrupt enable bit */
+    commonintmask |= ((fifoemptymask >> ep_num) & 0x1U) << 7;
+
+    value = udev->regs.er_in[ep_num]->DIEPINTF & commonintmask;
+
+    return value;
+}
+
+/*!
+    \brief      configures OUT endpoint 0 to receive SETUP packets
+    \param[in]  udev: pointer to USB device
+    \param[out] none
+    \retval     none
+*/
+void usb_ctlep_startout(usb_core_driver *udev)
+{
+    /* set OUT endpoint 0 receive length to 24 bytes, 1 packet and 3 SETUP packets */
+    udev->regs.er_out[0]->DOEPLEN = DOEP0_TLEN(8U * 3U) | DOEP0_PCNT(1U) | DOEP0_STPCNT(3U);
+}
+
+/*!
+    \brief      active remote wakeup signaling
+    \param[in]  udev: pointer to USB device
+    \param[out] none
+    \retval     none
+*/
+void usb_rwkup_active(usb_core_driver *udev)
+{
+    if(udev->dev.pm.dev_remote_wakeup)  {
+        if(udev->regs.dr->DSTAT & DSTAT_SPST) {
+            if(udev->bp.low_power) {
+                /* ungate USB core clock */
+                *udev->regs.PWRCLKCTL &= ~(PWRCLKCTL_SHCLK | PWRCLKCTL_SUCLK);
+            }
+
+            /* active remote wakeup signaling */
+            udev->regs.dr->DCTL |= DCTL_RWKUP;
+
+            usb_mdelay(5U);
+
+            udev->regs.dr->DCTL &= ~DCTL_RWKUP;
+        }
+    }
+}
+
+/*!
+    \brief      active USB core clock
+    \param[in]  udev: pointer to USB device
+    \param[out] none
+    \retval     none
+*/
+void usb_clock_active(usb_core_driver *udev)
+{
+    if(udev->bp.low_power) {
+        if(udev->regs.dr->DSTAT & DSTAT_SPST) {
+            /* ungate USB Core clock */
+            *udev->regs.PWRCLKCTL &= ~(PWRCLKCTL_SHCLK | PWRCLKCTL_SUCLK);
+        }
+    }
+}
+
+/*!
+    \brief      USB device suspend
+    \param[in]  udev: pointer to USB device
+    \param[out] none
+    \retval     none
+*/
+void usb_dev_suspend(usb_core_driver *udev)
+{
+    __IO uint32_t devstat = udev->regs.dr->DSTAT;
+
+    if((udev->bp.low_power) && (devstat & DSTAT_SPST)) {
+        /* switch-off the USB clocks */
+        *udev->regs.PWRCLKCTL |= PWRCLKCTL_SHCLK;
+
+        /* enter DEEP_SLEEP mode with LDO in low power mode */
+        pmu_to_deepsleepmode(PMU_LDO_LOWPOWER, PMU_LOWDRIVER_DISABLE, WFI_CMD);
+    }
+}
+
+/*!
+    \brief      stop the device and clean up FIFOs
+    \param[in]  udev: pointer to USB device
+    \param[out] none
+    \retval     none
+*/
+void usb_dev_stop(usb_core_driver *udev)
+{
+    uint32_t i;
+
+    udev->dev.cur_status = 1U;
+
+    /* clear all interrupt flag and enable bits */
+    for(i = 0U; i < udev->bp.num_ep; i++) {
+        udev->regs.er_in[i]->DIEPINTF = 0xFFU;
+        udev->regs.er_out[i]->DOEPINTF = 0xFFU;
+    }
+
+    udev->regs.dr->DIEPINTEN = 0U;
+    udev->regs.dr->DOEPINTEN = 0U;
+    udev->regs.dr->DAEPINTEN = 0U;
+    udev->regs.dr->DAEPINT = 0xFFFFFFFFU;
+
+    /* flush the FIFO */
+    (void)usb_rxfifo_flush(&udev->regs);
+    (void)usb_txfifo_flush(&udev->regs, 0x10U);
+}

+ 410 - 0
GD32F3x0/GD32F3x0_usbfs_library/driver/Source/drv_usb_host.c

@@ -0,0 +1,410 @@
+/*!
+    \file    drv_usb_host.c
+    \brief   USB host mode low level driver
+
+    \version 2025-01-01, V2.5.0, firmware for GD32F3x0
+*/
+
+/*
+    Copyright (c) 2025, GigaDevice Semiconductor Inc.
+
+    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 of the copyright holder 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 HOLDER 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.
+*/
+
+#include "drv_usb_hw.h"
+#include "drv_usb_host.h"
+
+const uint32_t PIPE_DPID[2] = {
+    PIPE_DPID_DATA0,
+    PIPE_DPID_DATA1
+};
+
+/*!
+    \brief      initializes USB core for host mode
+    \param[in]  udev: pointer to selected USB host
+    \param[out] none
+    \retval     operation status
+*/
+usb_status usb_host_init(usb_core_driver *udev)
+{
+    uint32_t i = 0U, inten = 0U;
+
+    uint32_t nptxfifolen = 0U;
+    uint32_t ptxfifolen = 0U;
+
+    /* restart the PHY Clock */
+    *udev->regs.PWRCLKCTL = 0U;
+
+    /* configure USB clock of PHY */
+    usb_phyclock_config(udev, HCTL_48MHZ);
+
+    /* support FS/LS only */
+    udev->regs.hr->HCTL &= ~HCTL_SPDFSLS;
+
+    /* configure data FIFOs size */
+
+    /* set RX FIFO size */
+    udev->regs.gr->GRFLEN = USB_RX_FIFO_FS_SIZE;
+
+    /* set non-periodic TX FIFO size and address */
+    nptxfifolen |= USB_RX_FIFO_FS_SIZE;
+    nptxfifolen |= USB_HTX_NPFIFO_FS_SIZE << 16;
+    udev->regs.gr->DIEP0TFLEN_HNPTFLEN = nptxfifolen;
+
+    /* set periodic TX FIFO size and address */
+    ptxfifolen |= USB_RX_FIFO_FS_SIZE + USB_HTX_NPFIFO_FS_SIZE;
+    ptxfifolen |= USB_HTX_PFIFO_FS_SIZE << 16;
+    udev->regs.gr->HPTFLEN = ptxfifolen;
+
+#ifdef USE_OTG_MODE
+    /* clear host set HNP enable in the usb_otg control register */
+    udev->regs.gr->GOTGCS &= ~GOTGCS_HHNPEN;
+#endif /* USE_OTG_MODE */
+
+    /* make sure the FIFOs are flushed */
+
+    /* flush all TX FIFOs in device or host mode */
+    usb_txfifo_flush(&udev->regs, 0x10U);
+
+    /* flush the entire RX FIFO */
+    usb_rxfifo_flush(&udev->regs);
+
+    /* disable all interrupts */
+    udev->regs.gr->GINTEN = 0U;
+
+    /* clear any pending USB OTG interrupts */
+    udev->regs.gr->GOTGINTF = 0xFFFFFFFFU;
+
+    /* enable the USB wakeup and suspend interrupts */
+    udev->regs.gr->GINTF = 0xBFFFFFFFU;
+
+    /* clear all pending host channel interrupts */
+    for(i = 0U; i < udev->bp.num_pipe; i++) {
+        udev->regs.pr[i]->HCHINTF = 0xFFFFFFFFU;
+        udev->regs.pr[i]->HCHINTEN = 0U;
+    }
+
+#ifndef USE_OTG_MODE
+    usb_portvbus_switch(udev, 1U);
+#endif /* USE_OTG_MODE */
+
+    udev->regs.gr->GINTEN = GINTEN_WKUPIE | GINTEN_SPIE;
+
+    /* enable host_mode-related interrupts */
+    if(USB_USE_FIFO == udev->bp.transfer_mode) {
+        inten = GINTEN_RXFNEIE;
+    }
+
+    inten |= GINTEN_SESIE | GINTEN_HPIE | GINTEN_HCIE | GINTEN_ISOINCIE;
+
+    udev->regs.gr->GINTEN |= inten;
+
+    inten = GINTEN_DISCIE | GINTEN_SOFIE;
+
+    udev->regs.gr->GINTEN &= ~inten;
+
+    return USB_OK;
+}
+
+/*!
+    \brief      control the VBUS to power
+    \param[in]  udev: pointer to selected USB host
+    \param[in]  state: VBUS state
+    \param[out] none
+    \retval     none
+*/
+void usb_portvbus_switch(usb_core_driver *udev, uint8_t state)
+{
+    uint32_t port = 0U;
+
+    /* enable or disable the external charge pump */
+    usb_vbus_drive(state);
+
+    /* turn on the host port power. */
+    port = usb_port_read(udev);
+
+    if(!(port & HPCS_PP) && (1U == state)) {
+        port |= HPCS_PP;
+    }
+
+    if((port & HPCS_PP) && (0U == state)) {
+        port &= ~HPCS_PP;
+    }
+
+    *udev->regs.HPCS = port;
+
+    usb_mdelay(200U);
+}
+
+/*!
+    \brief      reset host port
+    \param[in]  udev: pointer to USB device
+    \param[out] none
+    \retval     operation status
+*/
+uint32_t usb_port_reset(usb_core_driver *udev)
+{
+    __IO uint32_t port = usb_port_read(udev);
+
+    *udev->regs.HPCS = port | HPCS_PRST;
+
+    usb_mdelay(20U); /* see note */
+
+    *udev->regs.HPCS = port & ~HPCS_PRST;
+
+    usb_mdelay(20U);
+
+    return 1U;
+}
+
+/*!
+    \brief      initialize host pipe
+    \param[in]  udev: pointer to USB device
+    \param[in]  pipe_num: host pipe number which is in (0..7)
+    \param[out] none
+    \retval     operation status
+*/
+usb_status usb_pipe_init(usb_core_driver *udev, uint8_t pipe_num)
+{
+    usb_status status = USB_OK;
+
+    __IO uint32_t pp_ctl = 0U;
+    __IO uint32_t pp_inten = HCHINTEN_TFIE;
+
+    usb_pipe *pp = &udev->host.pipe[pipe_num];
+
+    /* clear old interrupt conditions for this host channel */
+    udev->regs.pr[pipe_num]->HCHINTF = 0xFFFFFFFFU;
+
+    if(pp->ep.dir) {
+        pp_inten |= HCHINTEN_BBERIE;
+    }
+
+    /* enable channel interrupts required for this transfer */
+    switch(pp->ep.type) {
+    case USB_EPTYPE_CTRL:
+    case USB_EPTYPE_BULK:
+        pp_inten |= HCHINTEN_STALLIE | HCHINTEN_USBERIE \
+                    | HCHINTEN_DTERIE | HCHINTEN_NAKIE;
+        break;
+
+    case USB_EPTYPE_INTR:
+        pp_inten |= HCHINTEN_STALLIE | HCHINTEN_USBERIE | HCHINTEN_DTERIE \
+                    | HCHINTEN_NAKIE | HCHINTEN_REQOVRIE;
+        break;
+
+    case USB_EPTYPE_ISOC:
+        pp_inten |= HCHINTEN_REQOVRIE | HCHINTEN_ACKIE;
+
+        if(pp->ep.dir) {
+            pp_inten |= HCHINTEN_USBERIE;
+        }
+        break;
+
+    default:
+        break;
+    }
+
+    udev->regs.pr[pipe_num]->HCHINTEN = pp_inten;
+
+    /* enable the top level host channel interrupt */
+    udev->regs.hr->HACHINTEN |= 1U << pipe_num;
+
+    /* make sure host channel interrupts are enabled */
+    udev->regs.gr->GINTEN |= GINTEN_HCIE;
+
+    /* program the host channel control register */
+    pp_ctl |= PIPE_CTL_DAR(pp->dev_addr);
+    pp_ctl |= PIPE_CTL_EPNUM(pp->ep.num);
+    pp_ctl |= PIPE_CTL_EPDIR(pp->ep.dir);
+    pp_ctl |= PIPE_CTL_EPTYPE(pp->ep.type);
+    pp_ctl |= PIPE_CTL_LSD(PORT_SPEED_LOW == pp->dev_speed);
+
+    pp_ctl |= pp->ep.mps;
+    pp_ctl |= ((uint32_t)(USB_EPTYPE_INTR == pp->ep.type) << 29) & HCHCTL_ODDFRM;
+
+    udev->regs.pr[pipe_num]->HCHCTL = pp_ctl;
+
+    return status;
+}
+
+/*!
+    \brief      prepare host channel for transferring packets
+    \param[in]  udev: pointer to USB device
+    \param[in]  pipe_num: host pipe number which is in (0..7)
+    \param[out] none
+    \retval     operation status
+*/
+usb_status usb_pipe_xfer(usb_core_driver *udev, uint8_t pipe_num)
+{
+    usb_status status = USB_OK;
+
+    uint16_t dword_len = 0U;
+    uint16_t packet_count = 0U;
+
+    __IO uint32_t pp_ctl = 0U;
+
+    usb_pipe *pp = &udev->host.pipe[pipe_num];
+
+    uint16_t max_packet_len = pp->ep.mps;
+
+    /* compute the expected number of packets associated to the transfer */
+    if(pp->xfer_len > 0U) {
+        packet_count = (uint16_t)((pp->xfer_len + max_packet_len - 1U) / max_packet_len);
+
+        if(packet_count > HC_MAX_PACKET_COUNT) {
+            packet_count = HC_MAX_PACKET_COUNT;
+            pp->xfer_len = (uint16_t)(packet_count * max_packet_len);
+        }
+    } else {
+        packet_count = 1U;
+    }
+
+    if(pp->ep.dir) {
+        pp->xfer_len = (uint16_t)(packet_count * max_packet_len);
+    }
+
+    /* initialize the host channel transfer information */
+    udev->regs.pr[pipe_num]->HCHLEN = pp->xfer_len | pp->DPID | PIPE_XFER_PCNT(packet_count);
+
+    pp_ctl = udev->regs.pr[pipe_num]->HCHCTL;
+
+    if(usb_frame_even(udev)) {
+        pp_ctl |= HCHCTL_ODDFRM;
+    } else {
+        pp_ctl &= ~HCHCTL_ODDFRM;
+    }
+
+    /* set host channel enabled */
+    pp_ctl |= HCHCTL_CEN;
+    pp_ctl &= ~HCHCTL_CDIS;
+
+    udev->regs.pr[pipe_num]->HCHCTL = pp_ctl;
+
+    if(USB_USE_FIFO == udev->bp.transfer_mode) {
+        if((0U == pp->ep.dir) && (pp->xfer_len > 0U)) {
+            switch(pp->ep.type) {
+            /* non-periodic transfer */
+            case USB_EPTYPE_CTRL:
+            case USB_EPTYPE_BULK:
+                dword_len = (uint16_t)((pp->xfer_len + 3U) / 4U);
+
+                /* check if there is enough space in FIFO space */
+                if(dword_len > (udev->regs.gr->HNPTFQSTAT & HNPTFQSTAT_NPTXFS)) {
+                    /* need to process data in nptxfempty interrupt */
+                    udev->regs.gr->GINTEN |= GINTEN_NPTXFEIE;
+                }
+                break;
+
+            /* periodic transfer */
+            case USB_EPTYPE_INTR:
+            case USB_EPTYPE_ISOC:
+                dword_len = (uint16_t)((pp->xfer_len + 3U) / 4U);
+
+                /* check if there is enough space in FIFO space */
+                if(dword_len > (udev->regs.hr->HPTFQSTAT & HPTFQSTAT_PTXFS)) {
+                    /* need to process data in ptxfempty interrupt */
+                    udev->regs.gr->GINTEN |= GINTEN_PTXFEIE;
+                }
+                break;
+
+            default:
+                break;
+            }
+
+            /* write packet into the TX FIFO */
+            usb_txfifo_write(&udev->regs, pp->xfer_buf, pipe_num, (uint16_t)pp->xfer_len);
+        }
+    }
+
+    return status;
+}
+
+/*!
+    \brief      halt pipe
+    \param[in]  udev: pointer to USB device
+    \param[in]  pipe_num: host pipe number which is in (0..7)
+    \param[out] none
+    \retval     operation status
+*/
+usb_status usb_pipe_halt(usb_core_driver *udev, uint8_t pipe_num)
+{
+    __IO uint32_t pp_ctl = udev->regs.pr[pipe_num]->HCHCTL;
+
+    uint8_t ep_type = (uint8_t)((pp_ctl & HCHCTL_EPTYPE) >> 18U);
+
+    pp_ctl |= HCHCTL_CEN | HCHCTL_CDIS;
+
+    switch(ep_type) {
+    case USB_EPTYPE_CTRL:
+    case USB_EPTYPE_BULK:
+        if(0U == (udev->regs.gr->HNPTFQSTAT & HNPTFQSTAT_NPTXFS)) {
+            pp_ctl &= ~HCHCTL_CEN;
+        }
+        break;
+
+    case USB_EPTYPE_INTR:
+    case USB_EPTYPE_ISOC:
+        if(0U == (udev->regs.hr->HPTFQSTAT & HPTFQSTAT_PTXFS)) {
+            pp_ctl &= ~HCHCTL_CEN;
+        }
+        break;
+
+    default:
+        break;
+    }
+
+    udev->regs.pr[pipe_num]->HCHCTL = pp_ctl;
+
+    return USB_OK;
+}
+
+/*!
+    \brief      stop the USB host and clean up FIFO
+    \param[in]  udev: pointer to USB device
+    \param[out] none
+    \retval     none
+*/
+void usb_host_stop(usb_core_driver *udev)
+{
+    uint32_t i;
+    __IO uint32_t pp_ctl = 0U;
+
+    udev->regs.hr->HACHINTEN = 0x0U;
+    udev->regs.hr->HACHINT = 0xFFFFFFFFU;
+
+    /* flush out any leftover queued requests. */
+    for(i = 0U; i < udev->bp.num_pipe; i++) {
+        pp_ctl = udev->regs.pr[i]->HCHCTL;
+
+        pp_ctl &= ~(HCHCTL_CEN | HCHCTL_EPDIR);
+        pp_ctl |= HCHCTL_CDIS;
+
+        udev->regs.pr[i]->HCHCTL = pp_ctl;
+    }
+
+    /* flush the FIFO */
+    usb_rxfifo_flush(&udev->regs);
+    usb_txfifo_flush(&udev->regs, 0x10U);
+}

+ 493 - 0
GD32F3x0/GD32F3x0_usbfs_library/driver/Source/drv_usbd_int.c

@@ -0,0 +1,493 @@
+/*!
+    \file    drv_usbd_int.c
+    \brief   USB device mode interrupt routines
+
+    \version 2025-01-01, V2.5.0, firmware for GD32F3x0
+*/
+
+/*
+    Copyright (c) 2025, GigaDevice Semiconductor Inc.
+
+    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 of the copyright holder 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 HOLDER 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.
+*/
+
+#include "drv_usbd_int.h"
+#include "usbd_transc.h"
+
+static const uint8_t USB_SPEED[4] = {
+    [DSTAT_EM_HS_PHY_30MHZ_60MHZ] = (uint8_t)USB_SPEED_HIGH,
+    [DSTAT_EM_FS_PHY_30MHZ_60MHZ] = (uint8_t)USB_SPEED_FULL,
+    [DSTAT_EM_FS_PHY_48MHZ] = (uint8_t)USB_SPEED_FULL,
+    [DSTAT_EM_LS_PHY_6MHZ] = (uint8_t)USB_SPEED_LOW
+};
+
+__IO uint8_t setupc_flag = 0U;
+
+/* local function prototypes ('static') */
+static uint32_t usbd_int_epout(usb_core_driver *udev);
+static uint32_t usbd_int_epin(usb_core_driver *udev);
+static uint32_t usbd_int_rxfifo(usb_core_driver *udev);
+static uint32_t usbd_int_reset(usb_core_driver *udev);
+static uint32_t usbd_int_enumfinish(usb_core_driver *udev);
+static uint32_t usbd_int_suspend(usb_core_driver *udev);
+static uint32_t usbd_emptytxfifo_write(usb_core_driver *udev, uint32_t ep_num);
+
+/*!
+    \brief      USB device-mode interrupts global service routine handler
+    \param[in]  udev: pointer to USB device instance
+    \param[out] none
+    \retval     none
+*/
+void usbd_isr(usb_core_driver *udev)
+{
+    if(HOST_MODE != (udev->regs.gr->GINTF & GINTF_COPM)) {
+        uint32_t intr = udev->regs.gr->GINTF;
+        intr &= udev->regs.gr->GINTEN;
+
+        /* there are no interrupts, avoid spurious interrupt */
+        if(!intr) {
+            return;
+        }
+
+        /* OUT endpoints interrupts */
+        if(intr & GINTF_OEPIF) {
+            (void)usbd_int_epout(udev);
+        }
+
+        /* IN endpoints interrupts */
+        if(intr & GINTF_IEPIF) {
+            (void)usbd_int_epin(udev);
+        }
+
+        /* suspend interrupt */
+        if(intr & GINTF_SP) {
+            (void)usbd_int_suspend(udev);
+        }
+
+        /* wakeup interrupt */
+        if(intr & GINTF_WKUPIF) {
+            if(USBD_SUSPENDED == udev->dev.cur_status) {
+                /* inform upper layer by the resume event */
+                udev->dev.cur_status = udev->dev.backup_status;
+            }
+
+            /* clear interrupt */
+            udev->regs.gr->GINTF = GINTF_WKUPIF;
+        }
+
+        /* start of frame interrupt */
+        if(intr & GINTF_SOF) {
+            if(udev->dev.class_core->SOF) {
+                (void)udev->dev.class_core->SOF(udev);
+            }
+
+            if(0U != setupc_flag) {
+                setupc_flag++;
+
+                if(setupc_flag >= 3U) {
+                    usbd_setup_transc(udev);
+
+                    setupc_flag = 0U;
+                }
+            }
+
+            /* clear interrupt */
+            udev->regs.gr->GINTF = GINTF_SOF;
+        }
+
+        /* receive FIFO not empty interrupt */
+        if(intr & GINTF_RXFNEIF) {
+            (void)usbd_int_rxfifo(udev);
+        }
+
+        /* USB reset interrupt */
+        if(intr & GINTF_RST) {
+            (void)usbd_int_reset(udev);
+        }
+
+        /* enumeration has been done interrupt */
+        if(intr & GINTF_ENUMFIF) {
+            (void)usbd_int_enumfinish(udev);
+        }
+
+        /* incomplete synchronization IN transfer interrupt*/
+        if(intr & GINTF_ISOINCIF) {
+            if(NULL != udev->dev.class_core->incomplete_isoc_in) {
+                (void)udev->dev.class_core->incomplete_isoc_in(udev);
+            }
+
+            /* clear interrupt */
+            udev->regs.gr->GINTF = GINTF_ISOINCIF;
+        }
+
+        /* incomplete synchronization OUT transfer interrupt*/
+        if(intr & GINTF_ISOONCIF) {
+            if(NULL != udev->dev.class_core->incomplete_isoc_out) {
+                (void)udev->dev.class_core->incomplete_isoc_out(udev);
+            }
+
+            /* clear interrupt */
+            udev->regs.gr->GINTF = GINTF_ISOONCIF;
+        }
+
+#ifdef VBUS_SENSING_ENABLED
+
+        /* session request interrupt */
+        if(intr & GINTF_SESIF) {
+            udev->regs.gr->GINTF = GINTF_SESIF;
+        }
+
+        /* OTG mode interrupt */
+        if(intr & GINTF_OTGIF) {
+            if(udev->regs.gr->GOTGINTF & GOTGINTF_SESEND) {
+
+            }
+
+            /* clear OTG interrupt */
+            udev->regs.gr->GINTF = GINTF_OTGIF;
+        }
+#endif /* VBUS_SENSING_ENABLED */
+    }
+}
+
+/*!
+    \brief      indicates that an OUT endpoint has a pending interrupt
+    \param[in]  udev: pointer to USB device instance
+    \param[out] none
+    \retval     operation status
+*/
+static uint32_t usbd_int_epout(usb_core_driver *udev)
+{
+    uint32_t epintnum = 0U;
+    uint8_t ep_num = 0U;
+
+    for(epintnum = usb_oepintnum_read(udev); epintnum; epintnum >>= 1, ep_num++) {
+        if(epintnum & 0x01U) {
+            __IO uint32_t oepintr = usb_oepintr_read(udev, ep_num);
+
+            /* transfer complete interrupt */
+            if(oepintr & DOEPINTF_TF) {
+                /* clear the bit in DOEPINTF for this interrupt */
+                udev->regs.er_out[ep_num]->DOEPINTF = DOEPINTF_TF;
+
+                /* inform upper layer: data ready */
+                (void)usbd_out_transc(udev, ep_num);
+            }
+
+            /* SETUP phase finished interrupt (control endpoints) */
+            if(oepintr & DOEPINTF_STPF) {
+                if((0U == ep_num) && (0U != setupc_flag)) {
+                    /* inform the upper layer that a SETUP packet is available */
+                    (void)usbd_setup_transc(udev);
+
+                    udev->regs.er_out[ep_num]->DOEPINTF = DOEPINTF_STPF;
+
+                    setupc_flag = 0U;
+                }
+            }
+        }
+    }
+
+    return 1U;
+}
+
+/*!
+    \brief      indicates that an IN endpoint has a pending interrupt
+    \param[in]  udev: pointer to USB device instance
+    \param[out] none
+    \retval     operation status
+*/
+static uint32_t usbd_int_epin(usb_core_driver *udev)
+{
+    uint32_t epintnum = 0U;
+    uint8_t ep_num = 0U;
+
+    for(epintnum = usb_iepintnum_read(udev); epintnum; epintnum >>= 1, ep_num++) {
+        if(epintnum & 0x1U) {
+            __IO uint32_t iepintr = usb_iepintr_read(udev, ep_num);
+
+            if(iepintr & DIEPINTF_TF) {
+                udev->regs.er_in[ep_num]->DIEPINTF = DIEPINTF_TF;
+
+                /* data transmission is completed */
+                (void)usbd_in_transc(udev, ep_num);
+            }
+
+            if(iepintr & DIEPINTF_TXFE) {
+                usbd_emptytxfifo_write(udev, (uint32_t)ep_num);
+
+                udev->regs.er_in[ep_num]->DIEPINTF = DIEPINTF_TXFE;
+            }
+        }
+    }
+
+    return 1U;
+}
+
+/*!
+    \brief      handle the RX status queue level interrupt
+    \param[in]  udev: pointer to USB device instance
+    \param[out] none
+    \retval     operation status
+*/
+static uint32_t usbd_int_rxfifo(usb_core_driver *udev)
+{
+    usb_transc *transc = NULL;
+
+    uint8_t data_PID = 0U;
+    uint32_t bcount = 0U;
+
+    __IO uint32_t devrxstat = 0U;
+
+    /* disable the RX status queue non-empty interrupt */
+    udev->regs.gr->GINTEN &= ~GINTEN_RXFNEIE;
+
+    /* get the status from the top of the FIFO */
+    devrxstat = udev->regs.gr->GRSTATP;
+
+    uint8_t ep_num = (uint8_t)(devrxstat & GRSTATRP_EPNUM);
+
+    transc = &udev->dev.transc_out[ep_num];
+
+    bcount = (devrxstat & GRSTATRP_BCOUNT) >> 4;
+    data_PID = (uint8_t)((devrxstat & GRSTATRP_DPID) >> 15);
+
+    switch((devrxstat & GRSTATRP_RPCKST) >> 17) {
+    case RSTAT_GOUT_NAK:
+        break;
+
+    case RSTAT_DATA_UPDT:
+        if(bcount > 0U) {
+            (void)usb_rxfifo_read(&udev->regs, transc->xfer_buf, (uint16_t)bcount);
+
+            transc->xfer_buf += bcount;
+            transc->xfer_count += bcount;
+        }
+        break;
+
+    case RSTAT_XFER_COMP:
+        /* trigger the OUT endpoint interrupt */
+        break;
+
+    case RSTAT_SETUP_COMP:
+        /* trigger the OUT endpoint interrupt */
+        break;
+
+    case RSTAT_SETUP_UPDT:
+        if((0U == transc->ep_addr.num) && (8U == bcount) && (DPID_DATA0 == data_PID)) {
+            /* copy the SETUP packet received in FIFO into the setup buffer in RAM */
+            (void)usb_rxfifo_read(&udev->regs, (uint8_t *)&udev->dev.control.req, (uint16_t)bcount);
+
+            transc->xfer_count += bcount;
+
+            /* set the flag */
+            setupc_flag = 1;
+        }
+        break;
+
+    default:
+        break;
+    }
+
+    /* enable the RX status queue level interrupt */
+    udev->regs.gr->GINTEN |= GINTEN_RXFNEIE;
+
+    return 1U;
+}
+
+/*!
+    \brief      handle USB reset interrupt
+    \param[in]  udev: pointer to USB device instance
+    \param[out] none
+    \retval     status
+*/
+static uint32_t usbd_int_reset(usb_core_driver *udev)
+{
+    uint32_t i;
+
+    /* clear the remote wakeup signaling */
+    udev->regs.dr->DCTL &= ~DCTL_RWKUP;
+
+    /* flush the TX FIFO */
+    (void)usb_txfifo_flush(&udev->regs, 0U);
+
+    for(i = 0U; i < udev->bp.num_ep; i++) {
+        udev->regs.er_in[i]->DIEPINTF = 0xFFU;
+        udev->regs.er_out[i]->DOEPINTF = 0xFFU;
+    }
+
+    /* clear all pending device endpoint interrupts */
+    udev->regs.dr->DAEPINT = 0xFFFFFFFFU;
+
+    /* enable endpoint 0 interrupts */
+    udev->regs.dr->DAEPINTEN = 1U | (1U << 16);
+
+    /* enable OUT endpoint interrupts */
+    udev->regs.dr->DOEPINTEN = DOEPINTEN_STPFEN | DOEPINTEN_TFEN;
+
+    /* enable IN endpoint interrupts */
+    udev->regs.dr->DIEPINTEN = DIEPINTEN_TFEN;
+
+    /* reset device address */
+    udev->regs.dr->DCFG &= ~DCFG_DAR;
+
+    /* configure endpoint 0 to receive SETUP packets */
+    usb_ctlep_startout(udev);
+
+    /* clear USB reset interrupt */
+    udev->regs.gr->GINTF = GINTF_RST;
+
+    udev->dev.transc_out[0] = (usb_transc) {
+        .ep_type = USB_EPTYPE_CTRL,
+        .max_len = USB_FS_EP0_MAX_LEN
+    };
+
+    (void)usb_transc_active(udev, &udev->dev.transc_out[0]);
+
+    udev->dev.transc_in[0] = (usb_transc) {
+        .ep_addr = {
+            .dir = 1U
+        },
+
+        .ep_type = USB_EPTYPE_CTRL,
+        .max_len = USB_FS_EP0_MAX_LEN
+    };
+
+    (void)usb_transc_active(udev, &udev->dev.transc_in[0]);
+
+    /* upon reset call user call back */
+    udev->dev.cur_status = (uint8_t)USBD_DEFAULT;
+
+    return 1U;
+}
+
+/*!
+    \brief      handle USB speed enumeration finish interrupt
+    \param[in]  udev: pointer to USB device instance
+    \param[out] none
+    \retval     status
+*/
+static uint32_t usbd_int_enumfinish(usb_core_driver *udev)
+{
+    uint8_t enum_speed = (uint8_t)((udev->regs.dr->DSTAT & DSTAT_ES) >> 1);
+
+    udev->regs.dr->DCTL &= ~DCTL_CGINAK;
+    udev->regs.dr->DCTL |= DCTL_CGINAK;
+
+    udev->regs.gr->GUSBCS &= ~GUSBCS_UTT;
+
+    /* set USB turn-around time based on device speed and PHY interface */
+    if((uint8_t)USB_SPEED_HIGH == USB_SPEED[enum_speed]) {
+        udev->bp.core_speed = (uint8_t)USB_SPEED_HIGH;
+
+        udev->regs.gr->GUSBCS |= 0x09U << 10;
+    } else {
+        udev->bp.core_speed = (uint8_t)USB_SPEED_FULL;
+
+        udev->regs.gr->GUSBCS |= 0x05U << 10;
+    }
+
+    /* clear interrupt */
+    udev->regs.gr->GINTF = GINTF_ENUMFIF;
+
+    return 1U;
+}
+
+/*!
+    \brief      USB suspend interrupt handler
+    \param[in]  udev: pointer to USB device instance
+    \param[out] none
+    \retval     operation status
+*/
+static uint32_t usbd_int_suspend(usb_core_driver *udev)
+{
+    __IO uint8_t low_power = udev->bp.low_power;
+    __IO uint8_t suspend = (uint8_t)(udev->regs.dr->DSTAT & DSTAT_SPST);
+    __IO uint8_t is_configured = ((uint8_t)USBD_CONFIGURED == udev->dev.cur_status) ? 1U : 0U;
+
+    udev->dev.backup_status = udev->dev.cur_status;
+    udev->dev.cur_status = (uint8_t)USBD_SUSPENDED;
+
+    if(low_power && suspend && is_configured) {
+        /* switch-off the USB clocks */
+        *udev->regs.PWRCLKCTL |= PWRCLKCTL_SUCLK | PWRCLKCTL_SHCLK;
+
+        /* enter DEEP_SLEEP mode with LDO in low power mode */
+        pmu_to_deepsleepmode(PMU_LDO_LOWPOWER, PMU_LOWDRIVER_DISABLE, WFI_CMD);
+    }
+
+    /* clear interrupt */
+    udev->regs.gr->GINTF = GINTF_SP;
+
+    return 1U;
+}
+
+/*!
+    \brief      check FIFO for the next packet to be loaded
+    \param[in]  udev: pointer to USB device instance
+    \param[in]  ep_num: endpoint identifier which is in (0..3)
+    \param[out] none
+    \retval     status
+*/
+static uint32_t usbd_emptytxfifo_write(usb_core_driver *udev, uint32_t ep_num)
+{
+    uint32_t len;
+    uint32_t word_count;
+
+    usb_transc *transc = &udev->dev.transc_in[ep_num];
+
+    len = transc->xfer_len - transc->xfer_count;
+
+    /* get the data length to write */
+    if(len > transc->max_len) {
+        len = transc->max_len;
+    }
+
+    word_count = (len + 3U) / 4U;
+
+    while(((udev->regs.er_in[ep_num]->DIEPTFSTAT & DIEPTFSTAT_IEPTFS) >= word_count) && \
+            (transc->xfer_count < transc->xfer_len)) {
+        len = transc->xfer_len - transc->xfer_count;
+
+        if(len > transc->max_len) {
+            len = transc->max_len;
+        }
+
+        /* write FIFO in word(4bytes) */
+        word_count = (len + 3U) / 4U;
+
+        /* write the FIFO */
+        (void)usb_txfifo_write(&udev->regs, transc->xfer_buf, (uint8_t)ep_num, (uint16_t)len);
+
+        transc->xfer_buf += len;
+        transc->xfer_count += len;
+
+        if(transc->xfer_count == transc->xfer_len) {
+            /* disable the device endpoint FIFO empty interrupt */
+            udev->regs.dr->DIEPFEINTEN &= ~(0x01U << ep_num);
+        }
+    }
+
+    return 1U;
+}

+ 601 - 0
GD32F3x0/GD32F3x0_usbfs_library/driver/Source/drv_usbh_int.c

@@ -0,0 +1,601 @@
+/*!
+    \file    drv_usbh_int.c
+    \brief   USB host mode interrupt handler file
+
+    \version 2025-01-01, V2.5.0, firmware for GD32F3x0
+*/
+
+/*
+    Copyright (c) 2025, GigaDevice Semiconductor Inc.
+
+    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 of the copyright holder 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 HOLDER 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.
+*/
+
+#include "drv_usbh_int.h"
+
+#if defined   (__CC_ARM)        /*!< ARM compiler */
+    #pragma O0
+#elif defined (__GNUC__)        /*!< GNU compiler */
+    #pragma GCC optimize ("O0")
+#elif defined  (__TASKING__)    /*!< TASKING compiler */
+    #pragma optimize=0
+#endif /* __CC_ARM */
+
+/* local function prototypes ('static') */
+static uint32_t usbh_int_port(usb_core_driver *udev);
+static uint32_t usbh_int_pipe(usb_core_driver *udev);
+static uint32_t usbh_int_pipe_in(usb_core_driver *udev, uint32_t pp_num);
+static uint32_t usbh_int_pipe_out(usb_core_driver *udev, uint32_t pp_num);
+static uint32_t usbh_int_rxfifonoempty(usb_core_driver *udev);
+static uint32_t usbh_int_txfifoempty(usb_core_driver *udev, usb_pipe_mode pp_mode);
+
+/*!
+    \brief      handle global host interrupt
+    \param[in]  udev: pointer to USB core instance
+    \param[out] none
+    \retval     operation status
+*/
+uint32_t usbh_isr(usb_core_driver *udev)
+{
+    uint32_t retval = 0U;
+
+    __IO uint32_t intr = 0U;
+
+    /* check if host mode */
+    if(HOST_MODE == (udev->regs.gr->GINTF & GINTF_COPM)) {
+        intr = usb_coreintr_get(&udev->regs);
+
+        if(!intr) {
+            return 0U;
+        }
+
+        if(intr & GINTF_SOF) {
+            usbh_int_fop->SOF(udev->host.data);
+
+            /* clear interrupt */
+            udev->regs.gr->GINTF = GINTF_SOF;
+        }
+
+        if(intr & GINTF_RXFNEIF) {
+            retval |= usbh_int_rxfifonoempty(udev);
+        }
+
+        if(intr & GINTF_NPTXFEIF) {
+            retval |= usbh_int_txfifoempty(udev, PIPE_NON_PERIOD);
+        }
+
+        if(intr & GINTF_PTXFEIF) {
+            retval |= usbh_int_txfifoempty(udev, PIPE_PERIOD);
+        }
+
+        if(intr & GINTF_HCIF) {
+            retval |= usbh_int_pipe(udev);
+        }
+
+        if(intr & GINTF_HPIF) {
+            retval |= usbh_int_port(udev);
+        }
+
+        if(intr & GINTF_WKUPIF) {
+            /* clear interrupt */
+            udev->regs.gr->GINTF = GINTF_WKUPIF;
+        }
+
+        if(intr & GINTF_DISCIF) {
+            usbh_int_fop->disconnect(udev->host.data);
+
+            /* clear interrupt */
+            udev->regs.gr->GINTF = GINTF_DISCIF;
+        }
+
+        if(intr & GINTF_ISOONCIF) {
+            udev->regs.pr[0]->HCHCTL |= HCHCTL_CEN | HCHCTL_CDIS;
+
+            /* clear interrupt */
+            udev->regs.gr->GINTF = GINTF_ISOONCIF;
+        }
+
+        if(intr & GINTF_SESIF) {
+            usb_portvbus_switch(udev, 1U);
+
+            udev->regs.gr->GINTF = GINTF_SESIF;
+        }
+    }
+
+    return retval;
+}
+
+/*!
+    \brief      handle USB pipe halt
+    \param[in]  udev: pointer to USB core instance
+    \param[in]  pp_num: pp_num: host channel number which is in (0..7)
+    \param[in]  pp_int: pipe interrupt
+    \param[in]  pp_status: pipe status
+    \param[out] none
+    \retval     none
+*/
+static inline void usb_pp_halt(usb_core_driver *udev, \
+                               uint8_t pp_num, \
+                               uint32_t pp_int, \
+                               usb_pipe_status pp_status)
+{
+    udev->regs.pr[pp_num]->HCHINTEN |= HCHINTEN_CHIE;
+
+    usb_pipe_halt(udev, pp_num);
+
+    udev->regs.pr[pp_num]->HCHINTF = pp_int;
+
+    udev->host.pipe[pp_num].pp_status = pp_status;
+}
+
+/*!
+    \brief      handle the host port interrupt
+    \param[in]  udev: pointer to USB device instance
+    \param[out] none
+    \retval     operation status
+*/
+#if defined (__ICCARM__)      /*!< IAR compiler */
+    #pragma optimize = none
+#endif /* __ICCARM */
+static uint32_t usbh_int_port(usb_core_driver *udev)
+{
+    uint32_t retval = 0U;
+
+    /* note: when the USB PHY use USB HS PHY, the flag is needed */
+    uint8_t port_reset = 0U;
+
+    __IO uint32_t port_state = *udev->regs.HPCS;
+
+    /* clear the interrupt bit in GINTF */
+    port_state &= ~(HPCS_PE | HPCS_PCD | HPCS_PEDC);
+
+    /* port connect detected */
+    if(*udev->regs.HPCS & HPCS_PCD) {
+        port_state |= HPCS_PCD;
+
+        usbh_int_fop->connect(udev->host.data);
+
+        retval |= 1U;
+    }
+
+    /* port enable changed */
+    if(*udev->regs.HPCS & HPCS_PEDC) {
+        port_state |= HPCS_PEDC;
+
+        if(*udev->regs.HPCS & HPCS_PE) {
+            uint32_t port_speed = usb_curspeed_get(udev);
+            uint32_t clock_type = udev->regs.hr->HCTL & HCTL_CLKSEL;
+
+            udev->host.connect_status = 1U;
+
+            if(PORT_SPEED_LOW == port_speed) {
+                udev->regs.hr->HFT = 6000U;
+
+                if(HCTL_6MHZ != clock_type) {
+                    if(USB_EMBEDDED_PHY == udev->bp.phy_itf) {
+                        usb_phyclock_config(udev, HCTL_6MHZ);
+                    }
+
+                    port_reset = 1U;
+                }
+            } else if(PORT_SPEED_FULL == port_speed) {
+                udev->regs.hr->HFT = 48000U;
+
+                if(HCTL_48MHZ != clock_type) {
+                    usb_phyclock_config(udev, HCTL_48MHZ);
+                }
+
+                port_reset = 1U;
+            } else {
+                /* for high speed device and others */
+                port_reset = 1U;
+            }
+
+            udev->host.port_enabled = 1U;
+
+            udev->regs.gr->GINTEN |= GINTEN_DISCIE | GINTEN_SOFIE;
+        } else {
+            udev->host.port_enabled = 0U;
+        }
+    }
+
+    if(port_reset) {
+        usb_port_reset(udev);
+    }
+
+    /* clear port interrupts */
+    *udev->regs.HPCS = port_state;
+
+    return retval;
+}
+
+/*!
+    \brief      handle all host channels interrupt
+    \param[in]  udev: pointer to USB device instance
+    \param[out] none
+    \retval     operation status
+*/
+static uint32_t usbh_int_pipe(usb_core_driver *udev)
+{
+    uint32_t pp_num = 0U;
+    uint32_t retval = 0U;
+
+    for(pp_num = 0U; pp_num < udev->bp.num_pipe; pp_num++) {
+        if((udev->regs.hr->HACHINT & HACHINT_HACHINT) & (1UL << pp_num)) {
+            if(udev->regs.pr[pp_num]->HCHCTL & HCHCTL_EPDIR) {
+                retval |= usbh_int_pipe_in(udev, pp_num);
+            } else {
+                retval |= usbh_int_pipe_out(udev, pp_num);
+            }
+        }
+    }
+
+    return retval;
+}
+
+/*!
+    \brief      handle the IN channel interrupt
+    \param[in]  udev: pointer to USB device instance
+    \param[in]  pp_num: host channel number which is in (0..7)
+    \param[out] none
+    \retval     operation status
+*/
+#if defined (__ICCARM__)      /*!< IAR compiler */
+    #pragma optimize = none
+#endif /* __ICCARM */
+static uint32_t usbh_int_pipe_in(usb_core_driver *udev, uint32_t pp_num)
+{
+    usb_pr *pp_reg = udev->regs.pr[pp_num];
+
+    usb_pipe *pp = &udev->host.pipe[pp_num];
+
+    uint32_t intr_pp = pp_reg->HCHINTF;
+    intr_pp &= pp_reg->HCHINTEN;
+
+    uint8_t ep_type = (uint8_t)((pp_reg->HCHCTL & HCHCTL_EPTYPE) >> 18);
+
+    if(intr_pp & HCHINTF_ACK) {
+        pp_reg->HCHINTF = HCHINTF_ACK;
+    } else if(intr_pp & HCHINTF_STALL) {
+        usb_pp_halt(udev, (uint8_t)pp_num, HCHINTF_STALL, PIPE_STALL);
+        pp_reg->HCHINTF = HCHINTF_NAK;
+
+        /* note: When there is a 'STALL', reset also NAK,
+           else, the udev->host.pp_status = HC_STALL
+           will be overwritten by 'NAK' in code below */
+        intr_pp &= ~HCHINTF_NAK;
+    } else if(intr_pp & HCHINTF_DTER) {
+        usb_pp_halt(udev, (uint8_t)pp_num, HCHINTF_DTER, PIPE_DTGERR);
+        pp_reg->HCHINTF = HCHINTF_NAK;
+    } else {
+        /* no operation */
+    }
+
+    if(intr_pp & HCHINTF_REQOVR) {
+        usb_pp_halt(udev, (uint8_t)pp_num, HCHINTF_REQOVR, PIPE_REQOVR);
+    } else if(intr_pp & HCHINTF_TF) {
+        pp->pp_status = PIPE_XF;
+        pp->err_count = 0U;
+
+        pp_reg->HCHINTF = HCHINTF_TF;
+
+        switch(ep_type) {
+        case USB_EPTYPE_CTRL:
+        case USB_EPTYPE_BULK:
+            usb_pp_halt(udev, (uint8_t)pp_num, HCHINTF_NAK, PIPE_XF);
+
+            pp->data_toggle_in ^= 1U;
+            break;
+
+        case USB_EPTYPE_INTR:
+        case USB_EPTYPE_ISOC:
+            pp_reg->HCHCTL |= HCHCTL_ODDFRM;
+            pp->urb_state = URB_DONE;
+            break;
+
+        default:
+            break;
+        }
+    } else if(intr_pp & HCHINTF_CH) {
+        pp_reg->HCHINTEN &= ~HCHINTEN_CHIE;
+
+        switch(pp->pp_status) {
+        case PIPE_XF:
+            pp->urb_state = URB_DONE;
+            break;
+
+        case PIPE_STALL:
+            pp->urb_state = URB_STALL;
+            break;
+
+        case PIPE_TRACERR:
+        case PIPE_DTGERR:
+            pp->err_count = 0U;
+            pp->urb_state = URB_ERROR;
+
+            pp->data_toggle_in ^= 1U;
+            break;
+
+        case PIPE_IDLE:
+        case PIPE_HALTED:
+        case PIPE_NAK:
+        case PIPE_NYET:
+        case PIPE_BBERR:
+        case PIPE_REQOVR:
+        default:
+            if((uint8_t)USB_EPTYPE_INTR == ep_type) {
+                pp->data_toggle_in ^= 1U;
+            }
+            break;
+        }
+
+        pp_reg->HCHINTF = HCHINTF_CH;
+    } else if(intr_pp & HCHINTF_USBER) {
+        pp->err_count++;
+        usb_pp_halt(udev, (uint8_t)pp_num, HCHINTF_USBER, PIPE_TRACERR);
+    } else if(intr_pp & HCHINTF_NAK) {
+        switch(ep_type) {
+        case USB_EPTYPE_CTRL:
+        case USB_EPTYPE_BULK:
+            /* re-activate the channel */
+            pp_reg->HCHCTL = (pp_reg->HCHCTL | HCHCTL_CEN) & ~HCHCTL_CDIS;
+            break;
+
+        case USB_EPTYPE_INTR:
+            pp_reg->HCHINTEN |= HCHINTEN_CHIE;
+
+            (void)usb_pipe_halt(udev, (uint8_t)pp_num);
+            break;
+
+        default:
+            break;
+        }
+
+        pp->pp_status = PIPE_NAK;
+
+        pp_reg->HCHINTF = HCHINTF_NAK;
+    } else {
+        /* no operation */
+    }
+
+    return 1U;
+}
+
+/*!
+    \brief      handle the OUT channel interrupt
+    \param[in]  udev: pointer to USB device instance
+    \param[in]  pp_num: host channel number which is in (0..7)
+    \param[out] none
+    \retval     operation status
+*/
+#if defined (__ICCARM__)      /*!< IAR compiler */
+    #pragma optimize = none
+#endif /* __ICCARM */
+static uint32_t usbh_int_pipe_out(usb_core_driver *udev, uint32_t pp_num)
+{
+    usb_pr *pp_reg = udev->regs.pr[pp_num];
+
+    usb_pipe *pp = &udev->host.pipe[pp_num];
+
+    uint32_t intr_pp = pp_reg->HCHINTF;
+    intr_pp &= pp_reg->HCHINTEN;
+
+    if(intr_pp & HCHINTF_ACK) {
+
+        pp_reg->HCHINTF = HCHINTF_ACK;
+    } else if(intr_pp & HCHINTF_STALL) {
+        usb_pp_halt(udev, (uint8_t)pp_num, HCHINTF_STALL, PIPE_STALL);
+    } else if(intr_pp & HCHINTF_DTER) {
+        usb_pp_halt(udev, (uint8_t)pp_num, HCHINTF_DTER, PIPE_DTGERR);
+        pp_reg->HCHINTF = HCHINTF_NAK;
+    } else if(intr_pp & HCHINTF_REQOVR) {
+        usb_pp_halt(udev, (uint8_t)pp_num, HCHINTF_REQOVR, PIPE_REQOVR);
+    } else if(intr_pp & HCHINTF_TF) {
+        pp->err_count = 0U;
+        usb_pp_halt(udev, (uint8_t)pp_num, HCHINTF_TF, PIPE_XF);
+    } else if(intr_pp & HCHINTF_NAK) {
+        pp->err_count = 0U;
+        usb_pp_halt(udev, (uint8_t)pp_num, HCHINTF_NAK, PIPE_NAK);
+    } else if(intr_pp & HCHINTF_USBER) {
+        pp->err_count++;
+        usb_pp_halt(udev, (uint8_t)pp_num, HCHINTF_USBER, PIPE_TRACERR);
+    } else if(intr_pp & HCHINTF_NYET) {
+        pp->err_count = 0U;
+        usb_pp_halt (udev, (uint8_t)pp_num, HCHINTF_NYET, PIPE_NYET);
+    } else if(intr_pp & HCHINTF_CH) {
+        udev->regs.pr[pp_num]->HCHINTEN &= ~HCHINTEN_CHIE;
+
+        switch(pp->pp_status) {
+        case PIPE_XF:
+            pp->urb_state = URB_DONE;
+
+            if((uint8_t)USB_EPTYPE_BULK == ((pp_reg->HCHCTL & HCHCTL_EPTYPE) >> 18)) {
+                pp->data_toggle_out ^= 1U;
+            }
+            break;
+
+        case PIPE_NAK:
+        case PIPE_NYET:
+            pp->urb_state = URB_NOTREADY;
+            break;
+
+        case PIPE_STALL:
+            pp->urb_state = URB_STALL;
+            break;
+
+        case PIPE_TRACERR:
+            if(3U == pp->err_count) {
+                pp->urb_state = URB_ERROR;
+                pp->err_count = 0U;
+            }
+            break;
+
+        case PIPE_IDLE:
+        case PIPE_HALTED:
+        case PIPE_BBERR:
+        case PIPE_REQOVR:
+        case PIPE_DTGERR:
+        default:
+            break;
+        }
+
+        pp_reg->HCHINTF = HCHINTF_CH;
+    } else {
+        /* no operation */
+    }
+
+    return 1U;
+}
+
+/*!
+    \brief      handle the RX FIFO non-empty interrupt
+    \param[in]  udev: pointer to USB device instance
+    \param[out] none
+    \retval     operation status
+*/
+#if defined (__ICCARM__)      /*!< IAR compiler */
+    #pragma optimize = none
+#endif /* __ICCARM */
+static uint32_t usbh_int_rxfifonoempty(usb_core_driver *udev)
+{
+    uint32_t count = 0U, xfer_count = 0U;
+
+    __IO uint8_t pp_num = 0U;
+    __IO uint32_t rx_stat = 0U;
+
+    /* disable the RX status queue level interrupt */
+    udev->regs.gr->GINTEN &= ~GINTEN_RXFNEIE;
+
+    rx_stat = udev->regs.gr->GRSTATP;
+    pp_num = (uint8_t)(rx_stat & GRSTATRP_CNUM);
+
+    switch((rx_stat & GRSTATRP_RPCKST) >> 17) {
+    case GRXSTS_PKTSTS_IN:
+        count = (rx_stat & GRSTATRP_BCOUNT) >> 4;
+
+        /* read the data into the host buffer. */
+        if((count > 0U) && (NULL != udev->host.pipe[pp_num].xfer_buf)) {
+            (void)usb_rxfifo_read(&udev->regs, udev->host.pipe[pp_num].xfer_buf, (uint16_t)count);
+
+            /* manage multiple transfer packet */
+            udev->host.pipe[pp_num].xfer_buf += count;
+            udev->host.pipe[pp_num].xfer_count += count;
+
+            xfer_count = udev->host.pipe[pp_num].xfer_count;
+
+            udev->host.backup_xfercount[pp_num] = xfer_count;
+
+            if(udev->regs.pr[pp_num]->HCHLEN & HCHLEN_PCNT) {
+                /* re-activate the channel when more packets are expected */
+                uint32_t pp_ctl = udev->regs.pr[pp_num]->HCHCTL;
+
+                pp_ctl |= HCHCTL_CEN;
+                pp_ctl &= ~HCHCTL_CDIS;
+
+                udev->regs.pr[pp_num]->HCHCTL = pp_ctl;
+            }
+        }
+        break;
+
+    case GRXSTS_PKTSTS_IN_XFER_COMP:
+        break;
+
+    case GRXSTS_PKTSTS_DATA_TOGGLE_ERR:
+        count = (rx_stat & GRSTATRP_BCOUNT) >> 4;
+
+        while(count > 0U) {
+            rx_stat = udev->regs.gr->GRSTATP;
+            count--;
+        }
+        break;
+
+    case GRXSTS_PKTSTS_CH_HALTED:
+        break;
+
+    default:
+        break;
+    }
+
+    /* enable the RX status queue level interrupt */
+    udev->regs.gr->GINTEN |= GINTEN_RXFNEIE;
+
+    return 1U;
+}
+
+/*!
+    \brief      handle the TX FIFO empty interrupt
+    \param[in]  udev: pointer to USB device instance
+    \param[in]  pp_mode: pipe mode
+    \param[out] none
+    \retval     operation status
+*/
+#if defined (__ICCARM__)      /*!< IAR compiler */
+    #pragma optimize = none
+#endif /* __ICCARM */
+static uint32_t usbh_int_txfifoempty(usb_core_driver *udev, usb_pipe_mode pp_mode)
+{
+    uint8_t pp_num = 0U;
+    uint16_t word_count = 0U, len = 0U;
+    __IO uint32_t *txfiforeg = 0U, txfifostate = 0U;
+
+    if(PIPE_NON_PERIOD == pp_mode) {
+        txfiforeg = &udev->regs.gr->HNPTFQSTAT;
+    } else if(PIPE_PERIOD == pp_mode) {
+        txfiforeg = &udev->regs.hr->HPTFQSTAT;
+    } else {
+        return 0U;
+    }
+
+    txfifostate = *txfiforeg;
+
+    pp_num = (uint8_t)((txfifostate & TFQSTAT_CNUM) >> 27);
+
+    word_count = (uint16_t)(udev->host.pipe[pp_num].xfer_len + 3U) / 4U;
+
+    while(((txfifostate & TFQSTAT_TXFS) >= word_count) && (0U != udev->host.pipe[pp_num].xfer_len)) {
+        len = (uint16_t)(txfifostate & TFQSTAT_TXFS) * 4U;
+
+        if(len > udev->host.pipe[pp_num].xfer_len) {
+            /* last packet */
+            len = (uint16_t)udev->host.pipe[pp_num].xfer_len;
+
+            if(PIPE_NON_PERIOD == pp_mode) {
+                udev->regs.gr->GINTEN &= ~GINTEN_NPTXFEIE;
+            } else {
+                udev->regs.gr->GINTEN &= ~GINTEN_PTXFEIE;
+            }
+        }
+
+        word_count = (uint16_t)((udev->host.pipe[pp_num].xfer_len + 3U) / 4U);
+        usb_txfifo_write(&udev->regs, udev->host.pipe[pp_num].xfer_buf, pp_num, len);
+
+        udev->host.pipe[pp_num].xfer_buf += len;
+        udev->host.pipe[pp_num].xfer_len -= len;
+        udev->host.pipe[pp_num].xfer_count += len;
+
+        txfifostate = *txfiforeg;
+    }
+
+    return 1U;
+}

+ 116 - 0
GD32F3x0/GD32F3x0_usbfs_library/host/class/hid/Include/usbh_hid_core.h

@@ -0,0 +1,116 @@
+/*!
+    \file    usbh_hid_core.h
+    \brief   header file for the usbh_hid_core.c
+
+    \version 2025-01-01, V2.5.0, firmware for GD32F3x0
+*/
+
+/*
+    Copyright (c) 2025, GigaDevice Semiconductor Inc.
+
+    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 of the copyright holder 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 HOLDER 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.
+*/
+
+#ifndef USBH_HID_CORE_H
+#define USBH_HID_CORE_H
+
+#include "usb_hid.h"
+#include "usbh_enum.h"
+#include "usbh_transc.h"
+
+#define HID_MIN_POLL                                    10U              /*!< HID minimum polling */
+#define HID_REPORT_SIZE                                 16U              /*!< HID report size */
+#define HID_QUEUE_SIZE                                  10U              /*!< HID queue size */
+
+#define USB_HID_DESC_SIZE                               9U               /*!< HID descriptor size */
+
+/* states for HID state machine */
+typedef enum {
+    HID_INIT = 0U,                                                       /*!< HID init state */
+    HID_IDLE,                                                            /*!< HID idle state */
+    HID_SEND_DATA,                                                       /*!< HID send data state */
+    HID_BUSY,                                                            /*!< HID busy state */
+    HID_GET_DATA,                                                        /*!< HID get data state */
+    HID_SYNC,                                                            /*!< HID synchronous state */
+    HID_POLL,                                                            /*!< HID polling state */
+    HID_ERROR                                                            /*!< HID error state */
+} hid_state;
+
+/* state types of HID control request */
+typedef enum {
+    HID_REQ_INIT = 0U,                                                   /*!< HID init request */
+    HID_REQ_IDLE,                                                        /*!< HID idle request */
+    HID_REQ_GET_REPORT_DESC,                                             /*!< get report descriptor request */
+    HID_REQ_GET_HID_DESC,                                                /*!< get HID descriptor request */
+    HID_REQ_SET_IDLE,                                                    /*!< set idle request */
+    HID_REQ_SET_PROTOCOL,                                                /*!< set protocol request */
+    HID_REQ_SET_REPORT                                                   /*!< set report request */
+} hid_ctlstate;
+
+/* HID types */
+typedef enum {
+    HID_MOUSE    = 0x01U,                                                /*!< HID mouse type */
+    HID_KEYBOARD = 0x02U,                                                /*!< HID keyboard type */
+    HID_UNKNOWN  = 0xFFU                                                 /*!< unknown type */
+} hid_type;
+
+typedef struct {
+     uint8_t  *buf;                                                      /*!< data FIFO buff pointer */
+     uint16_t  head;                                                     /*!< data FIFO header */
+     uint16_t  tail;                                                     /*!< data FIFO tail */
+     uint16_t  size;                                                     /*!< data FIFO size */
+     uint8_t   lock;                                                     /*!< data FIFO lock */
+} data_fifo;
+
+/* structure for HID process */
+typedef struct _hid_process {
+    uint8_t              pipe_in;                                        /*!< pipe IN */
+    uint8_t              pipe_out;                                       /*!< pipe OUT */
+    uint8_t              ep_addr;                                        /*!< endpoint address */
+    uint8_t              ep_in;                                          /*!< endpoint IN */
+    uint8_t              ep_out;                                         /*!< endpoint OUT */
+    uint8_t              *pdata;                                         /*!< HID data pointer */
+    __IO uint8_t         data_ready;                                     /*!< HID data ready */
+    uint16_t             len;                                            /*!< HID data length */
+    uint16_t             poll;                                           /*!< HID polling */
+    __IO uint32_t        timer;                                          /*!< HID timer */
+    usb_desc_hid         hid_desc;                                       /*!< HID descriptor */
+    hid_state            state;                                          /*!< HID state structure */
+    hid_ctlstate         ctl_state;                                      /*!< control request state structure */
+    usbh_status          (*init)(usb_core_driver *udev, usbh_host *uhost);
+    usbh_status          (*decode)(uint8_t *data);
+} usbh_hid_handler;
+
+extern usbh_class usbh_hid;
+
+/* function declarations */
+/* set HID report */
+usbh_status usbh_set_report(usb_core_driver *udev, \
+                            usbh_host *uhost, \
+                            uint8_t report_type, \
+                            uint8_t report_ID, \
+                            uint8_t report_len, \
+                            uint8_t *report_buf);
+
+#endif /* USBH_HID_CORE_H */

+ 96 - 0
GD32F3x0/GD32F3x0_usbfs_library/host/class/hid/Include/usbh_standard_hid.h

@@ -0,0 +1,96 @@
+/*!
+    \file    usbh_standard_hid.h
+    \brief   header file for usbh_standard_hid.c
+
+    \version 2025-01-01, V2.5.0, firmware for GD32F3x0
+*/
+
+/*
+    Copyright (c) 2025, GigaDevice Semiconductor Inc.
+
+    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 of the copyright holder 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 HOLDER 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.
+*/
+
+#ifndef USBH_STANDARD_HID_H
+#define USBH_STANDARD_HID_H
+
+#include "usbh_hid_core.h"
+
+//#define AZERTY_KEYBOARD
+#define QWERTY_KEYBOARD
+
+#define MOUSE_BUTTON_1                         0x01U                          /*!< mouse button 1 */
+#define MOUSE_BUTTON_2                         0x02U                          /*!< mouse button 2 */
+#define MOUSE_BUTTON_3                         0x04U                          /*!< mouse button 3 */
+
+#define KBD_LEFT_CTRL                          0x01U                          /*!< keyboard left ctrl key */
+#define KBD_LEFT_SHIFT                         0x02U                          /*!< keyboard left shift key */
+#define KBD_LEFT_ALT                           0x04U                          /*!< keyboard left alt key */
+#define KBD_LEFT_GUI                           0x08U                          /*!< keyboard left gui key */
+#define KBD_RIGHT_CTRL                         0x10U                          /*!< keyboard right ctrl key */
+#define KBD_RIGHT_SHIFT                        0x20U                          /*!< keyboard right shift key */
+#define KBD_RIGHT_ALT                          0x40U                          /*!< keyboard right alt key */
+#define KBD_RIGHT_GUI                          0x80U                          /*!< keyboard right gui key */
+
+#define KBD_PRESSED_MAX_NUM                    6U                             /*!< keyboard pressed maximum number */
+
+typedef struct _hid_mouse_info {
+    uint8_t x;                                                                /*!< X coordinate value */
+    uint8_t y;                                                                /*!< Y coordinate value */
+    uint8_t buttons[3];                                                       /*!< button buff */
+} hid_mouse_info;
+
+typedef struct {
+    uint8_t state;                                                            /*!< keyboard state */
+    uint8_t lctrl;                                                            /*!< keyboard left ctrl */
+    uint8_t lshift;                                                           /*!< keyboard left shift */
+    uint8_t lalt;                                                             /*!< keyboard left alt */
+    uint8_t lgui;                                                             /*!< keyboard left gui */
+    uint8_t rctrl;                                                            /*!< keyboard right ctrl */
+    uint8_t rshift;                                                           /*!< keyboard right shift */
+    uint8_t ralt;                                                             /*!< keyboard right alt */
+    uint8_t rgui;                                                             /*!< keyboard right gui */
+    uint8_t keys[6];                                                          /*!< keyboard keys buff */
+} hid_keybd_info;
+
+/* function declarations */
+/* initialize mouse */
+void usr_mouse_init(void);
+/* process mouse data */
+void usr_mouse_process_data(hid_mouse_info *data);
+/* initialize mouse function */
+usbh_status usbh_hid_mouse_init(usb_core_driver *udev, usbh_host *uhost);
+/* decode mouse information */
+usbh_status usbh_hid_mouse_decode(uint8_t *data);
+
+/* initialize keyboard */
+void usr_keybrd_init(void);
+/* process keyboard data */
+void usr_keybrd_process_data(uint8_t pbuf);
+/* initialize the keyboard function */
+usbh_status usbh_hid_keybrd_init(usb_core_driver *udev, usbh_host *uhost);
+/* decode keyboard information */
+usbh_status usbh_hid_keybrd_decode(uint8_t *data);
+
+#endif /* USBH_STANDARD_HID_H */

+ 582 - 0
GD32F3x0/GD32F3x0_usbfs_library/host/class/hid/Source/usbh_hid_core.c

@@ -0,0 +1,582 @@
+/*!
+    \file    usbh_hid_core.c
+    \brief   USB host HID class driver
+
+    \version 2025-01-01, V2.5.0, firmware for GD32F3x0
+*/
+
+/*
+    Copyright (c) 2025, GigaDevice Semiconductor Inc.
+
+    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 of the copyright holder 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 HOLDER 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.
+*/
+
+#include <string.h>
+#include "usbh_pipe.h"
+#include "usbh_hid_core.h"
+#include "usbh_standard_hid.h"
+
+/* local function prototypes ('static') */
+static void usbh_hiddesc_parse(usb_desc_hid *hid_desc, uint8_t *buf);
+static void usbh_hid_itf_deinit(usbh_host *uhost);
+static usbh_status usbh_hid_itf_init(usbh_host *uhost);
+static usbh_status usbh_hid_class_req(usbh_host *uhost);
+static usbh_status usbh_hid_handle(usbh_host *uhost);
+static usbh_status usbh_hid_reportdesc_get(usbh_host *uhost, uint16_t len);
+static usbh_status usbh_hid_sof(usbh_host *uhost);
+static usbh_status usbh_hid_desc_get(usbh_host *uhost, uint16_t len);
+static usbh_status usbh_set_idle(usbh_host *uhost, uint8_t duration, uint8_t report_ID);
+static usbh_status usbh_set_protocol(usbh_host *uhost, uint8_t protocol);
+
+usbh_class usbh_hid = {
+    USB_HID_CLASS,
+    usbh_hid_itf_init,
+    usbh_hid_itf_deinit,
+    usbh_hid_class_req,
+    usbh_hid_handle,
+    usbh_hid_sof
+};
+
+/*!
+    \brief      get report
+    \param[in]  uhost: pointer to USB host
+    \param[in]  report_type: duration for HID set idle request
+    \param[in]  report_ID: targeted report ID for HID set idle request
+    \param[in]  report_len: length of data report to be send
+    \param[in]  report_buf: report buffer
+    \param[out] none
+    \retval     operation status
+*/
+usbh_status usbh_get_report(usbh_host *uhost, \
+                            uint8_t  report_type, \
+                            uint8_t  report_ID, \
+                            uint8_t  report_len, \
+                            uint8_t *report_buf)
+{
+    usbh_status status = USBH_BUSY;
+
+    if(CTL_IDLE == uhost->control.ctl_state) {
+        uhost->control.setup.req = (usb_req) {
+            .bmRequestType = USB_TRX_IN | USB_RECPTYPE_ITF | USB_REQTYPE_CLASS,
+            .bRequest      = GET_REPORT,
+            .wValue        = (report_type << 8) | report_ID,
+            .wIndex        = 0U,
+            .wLength       = report_len
+        };
+
+        usbh_ctlstate_config(uhost, report_buf, report_len);
+    }
+
+    status = usbh_ctl_handler(uhost);
+
+    return status;
+}
+
+/*!
+    \brief      set report
+    \param[in]  udev: pointer to USB core instance
+    \param[in]  uhost: pointer to USB host
+    \param[in]  report_type: duration for HID set idle request
+    \param[in]  report_ID: targeted report ID for HID set idle request
+    \param[in]  report_len: length of data report to be send
+    \param[in]  report_buf: report buffer
+    \param[out] none
+    \retval     operation status
+*/
+usbh_status usbh_set_report(usb_core_driver *udev, \
+                            usbh_host *uhost, \
+                            uint8_t  report_type, \
+                            uint8_t  report_ID, \
+                            uint8_t  report_len, \
+                            uint8_t *report_buf)
+{
+    usbh_status status = USBH_BUSY;
+
+    if(CTL_IDLE == uhost->control.ctl_state) {
+        uhost->control.setup.req = (usb_req) {
+            .bmRequestType = USB_TRX_OUT | USB_RECPTYPE_ITF | USB_REQTYPE_CLASS,
+            .bRequest      = SET_REPORT,
+            .wValue        = (report_type << 8) | report_ID,
+            .wIndex        = 0U,
+            .wLength       = report_len
+        };
+
+        usbh_ctlstate_config(uhost, report_buf, report_len);
+    }
+
+    status = usbh_ctl_handler(uhost);
+
+    return status;
+}
+
+/*!
+    \brief      deinitialize the host pipes used for the HID class
+    \param[in]  uhost: pointer to USB host
+    \param[out] none
+    \retval     operation status
+*/
+void usbh_hid_itf_deinit(usbh_host *uhost)
+{
+    usbh_hid_handler *hid = (usbh_hid_handler *)uhost->active_class->class_data;
+
+    if(0x00U != hid->pipe_in) {
+        usb_pipe_halt(uhost->data, hid->pipe_in);
+
+        usbh_pipe_free(uhost->data, hid->pipe_in);
+
+        /* reset the pipe as free */
+        hid->pipe_in = 0U;
+    }
+
+    if(0x00U != hid->pipe_out) {
+        usb_pipe_halt(uhost->data, hid->pipe_out);
+
+        usbh_pipe_free(uhost->data, hid->pipe_out);
+
+        /* reset the channel as free */
+        hid->pipe_out = 0U;
+    }
+}
+
+/*!
+    \brief      return device type
+    \param[in]  udev: pointer to USB core instance
+    \param[in]  uhost: pointer to USB host
+    \param[out] none
+    \retval     hid_type
+*/
+hid_type usbh_hid_device_type_get(usb_core_driver *udev, usbh_host *uhost)
+{
+    hid_type type = HID_UNKNOWN;
+    uint8_t interface_protocol;
+
+    if(HOST_CLASS_HANDLER == uhost->cur_state) {
+        interface_protocol = uhost->dev_prop.cfg_desc_set.itf_desc_set[uhost->dev_prop.cur_itf][0].itf_desc.bInterfaceProtocol;
+
+        if(USB_HID_PROTOCOL_KEYBOARD == interface_protocol) {
+            type = HID_KEYBOARD;
+        } else {
+            if(USB_HID_PROTOCOL_MOUSE == interface_protocol) {
+                type = HID_MOUSE;
+            }
+        }
+    }
+
+    return type;
+}
+
+/*!
+    \brief      return HID device poll time
+    \param[in]  udev: pointer to USB core instance
+    \param[in]  uhost: pointer to USB host
+    \param[out] none
+    \retval     poll time (ms)
+*/
+uint8_t usbh_hid_poll_interval_get(usb_core_driver *udev, usbh_host *uhost)
+{
+    usbh_hid_handler *hid = (usbh_hid_handler *)uhost->active_class->class_data;
+
+    if((HOST_CLASS_ENUM == uhost->cur_state) || \
+            (HOST_USER_INPUT == uhost->cur_state) || \
+            (HOST_CLASS_CHECK == uhost->cur_state) || \
+            (HOST_CLASS_HANDLER == uhost->cur_state)) {
+        return (uint8_t)(hid->poll);
+    } else {
+        return 0U;
+    }
+}
+
+/*!
+    \brief      initialize the hid class
+    \param[in]  uhost: pointer to USB host
+    \param[out] none
+    \retval     operation status
+*/
+static usbh_status usbh_hid_itf_init(usbh_host *uhost)
+{
+    uint8_t num = 0U, ep_num = 0U, interface = 0U;
+    usbh_status status = USBH_BUSY;
+
+    interface = usbh_interface_find(&uhost->dev_prop, USB_HID_CLASS, USB_HID_SUBCLASS_BOOT_ITF, 0xFFU);
+
+    if(0xFFU == interface) {
+        uhost->usr_cb->dev_not_supported();
+
+        status = USBH_FAIL;
+    } else {
+        usbh_interface_select(&uhost->dev_prop, interface);
+
+        static usbh_hid_handler hid_handler;
+
+        memset((void *)&hid_handler, 0U, sizeof(usbh_hid_handler));
+
+        hid_handler.state = HID_ERROR;
+
+        uint8_t itf_protocol = uhost->dev_prop.cfg_desc_set.itf_desc_set[uhost->dev_prop.cur_itf][0].itf_desc.bInterfaceProtocol;
+        if(USB_HID_PROTOCOL_KEYBOARD == itf_protocol) {
+            hid_handler.init = usbh_hid_keybrd_init;
+            hid_handler.decode = usbh_hid_keybrd_decode;
+        } else if(USB_HID_PROTOCOL_MOUSE == itf_protocol) {
+            hid_handler.init = usbh_hid_mouse_init;
+            hid_handler.decode = usbh_hid_mouse_decode;
+        } else {
+            status = USBH_FAIL;
+        }
+
+        hid_handler.state = HID_INIT;
+        hid_handler.ctl_state = HID_REQ_INIT;
+        hid_handler.ep_addr = uhost->dev_prop.cfg_desc_set.itf_desc_set[uhost->dev_prop.cur_itf][0].ep_desc[0].bEndpointAddress;
+        hid_handler.len = uhost->dev_prop.cfg_desc_set.itf_desc_set[uhost->dev_prop.cur_itf][0].ep_desc[0].wMaxPacketSize;
+        hid_handler.poll = uhost->dev_prop.cfg_desc_set.itf_desc_set[uhost->dev_prop.cur_itf][0].ep_desc[0].bInterval;
+
+        if(hid_handler.poll < HID_MIN_POLL) {
+            hid_handler.poll = HID_MIN_POLL;
+        }
+
+        /* check for available number of endpoints */
+        /* find the number of endpoints in the interface descriptor */
+        /* choose the lower number in order not to overrun the buffer allocated */
+        ep_num = USB_MIN(uhost->dev_prop.cfg_desc_set.itf_desc_set[uhost->dev_prop.cur_itf][0].itf_desc.bNumEndpoints, USBH_MAX_EP_NUM);
+
+        /* decode endpoint IN and OUT address from interface descriptor */
+        for(num = 0U; num < ep_num; num++) {
+            usb_desc_ep *ep_desc = &uhost->dev_prop.cfg_desc_set.itf_desc_set[uhost->dev_prop.cur_itf][0].ep_desc[num];
+
+            uint8_t ep_addr = ep_desc->bEndpointAddress;
+
+            if(ep_addr & 0x80U) {
+                hid_handler.ep_in = ep_addr;
+                hid_handler.pipe_in = usbh_pipe_allocate(uhost->data, ep_addr);
+
+                /* open channel for IN endpoint */
+                usbh_pipe_create(uhost->data, \
+                                 &uhost->dev_prop, \
+                                 hid_handler.pipe_in, \
+                                 USB_EPTYPE_INTR, \
+                                 hid_handler.len);
+
+                usbh_pipe_toggle_set(uhost->data, hid_handler.pipe_in, 0U);
+            } else {
+                hid_handler.ep_out = ep_addr;
+                hid_handler.pipe_out = usbh_pipe_allocate(uhost->data, ep_addr);
+
+                /* open channel for OUT endpoint */
+                usbh_pipe_create(uhost->data, \
+                                 &uhost->dev_prop, \
+                                 hid_handler.pipe_out, \
+                                 USB_EPTYPE_INTR, \
+                                 hid_handler.len);
+
+                usbh_pipe_toggle_set(uhost->data, hid_handler.pipe_out, 0U);
+            }
+        }
+
+        uhost->active_class->class_data = (void *)&hid_handler;
+
+        status = USBH_OK;
+    }
+
+    return status;
+}
+
+/*!
+    \brief      handle HID class requests for HID class
+    \param[in]  uhost: pointer to USB host
+    \param[out] none
+    \retval     operation status
+*/
+static usbh_status usbh_hid_class_req(usbh_host *uhost)
+{
+    usbh_status status = USBH_BUSY;
+    usbh_status class_req_status = USBH_BUSY;
+
+    usbh_hid_handler *hid = (usbh_hid_handler *)uhost->active_class->class_data;
+
+    /* handle HID control state machine */
+    switch(hid->ctl_state) {
+    case HID_REQ_INIT:
+    case HID_REQ_GET_HID_DESC:
+        /* get HID descriptor */
+        if(USBH_OK == usbh_hid_desc_get(uhost, USB_HID_DESC_SIZE)) {
+            usbh_hiddesc_parse(&hid->hid_desc, uhost->dev_prop.data);
+
+            hid->ctl_state = HID_REQ_GET_REPORT_DESC;
+        }
+        break;
+
+    case HID_REQ_GET_REPORT_DESC:
+        /* get report descriptor */
+        if(USBH_OK == usbh_hid_reportdesc_get(uhost, hid->hid_desc.wDescriptorLength)) {
+            hid->ctl_state = HID_REQ_SET_IDLE;
+        }
+        break;
+
+    case HID_REQ_SET_IDLE:
+        class_req_status = usbh_set_idle(uhost, 0U, 0U);
+
+        /* set idle */
+        if(USBH_OK == class_req_status) {
+            hid->ctl_state = HID_REQ_SET_PROTOCOL;
+        } else {
+            if(USBH_NOT_SUPPORTED == class_req_status) {
+                hid->ctl_state = HID_REQ_SET_PROTOCOL;
+            }
+        }
+        break;
+
+    case HID_REQ_SET_PROTOCOL:
+        /* set protocol */
+        if(USBH_OK == usbh_set_protocol(uhost, 0U)) {
+            hid->ctl_state = HID_REQ_IDLE;
+
+            /* all requests performed */
+            status = USBH_OK;
+        }
+        break;
+
+    case HID_REQ_IDLE:
+    default:
+        break;
+    }
+
+    return status;
+}
+
+/*!
+    \brief      manage state machine for HID data transfers
+    \param[in]  uhost: pointer to USB host
+    \param[out] none
+    \retval     operation status
+*/
+static usbh_status usbh_hid_handle(usbh_host *uhost)
+{
+    usbh_status status = USBH_OK;
+    usbh_hid_handler *hid = (usbh_hid_handler *)uhost->active_class->class_data;
+
+    switch(hid->state) {
+    case HID_INIT:
+        hid->init(uhost->data, uhost);
+        hid->state = HID_IDLE;
+        break;
+
+    case HID_IDLE:
+        hid->state = HID_SYNC;
+        status = USBH_OK;
+        break;
+
+    case HID_SYNC:
+        /* sync with start of even frame */
+        if(1U == usb_frame_even(uhost->data)) {
+            hid->state = HID_GET_DATA;
+        }
+        break;
+
+    case HID_GET_DATA:
+        usbh_data_recev(uhost->data, hid->pdata, hid->pipe_in, hid->len);
+
+        hid->state = HID_POLL;
+        hid->timer = usb_curframe_get(uhost->data);
+        hid->data_ready = 0U;
+        break;
+
+    case HID_POLL:
+        if(URB_DONE == usbh_urbstate_get(uhost->data, hid->pipe_in)) {
+            if(0U == hid->data_ready) {
+                hid->data_ready = 1U;
+
+                hid->decode(hid->pdata);
+            }
+        } else {
+            /* check IN endpoint STALL status */
+            if(URB_STALL == usbh_urbstate_get(uhost->data, hid->pipe_in)) {
+                /* issue clear feature on interrupt IN endpoint */
+                if(USBH_OK == (usbh_clrfeature(uhost, hid->ep_addr, hid->pipe_in))) {
+                    /* change state to issue next IN token */
+                    hid->state = HID_GET_DATA;
+                }
+            }
+        }
+        break;
+
+    default:
+        break;
+    }
+    return status;
+}
+
+/*!
+    \brief      send get report descriptor command to the device
+    \param[in]  uhost: pointer to USB host
+    \param[in]  len: HID report descriptor length
+    \param[out] none
+    \retval     operation status
+*/
+static usbh_status usbh_hid_reportdesc_get(usbh_host *uhost, uint16_t len)
+{
+    usbh_status status = USBH_BUSY;
+
+    if(CTL_IDLE == uhost->control.ctl_state) {
+        uhost->control.setup.req = (usb_req) {
+            .bmRequestType = USB_TRX_IN | USB_RECPTYPE_ITF | USB_REQTYPE_STRD,
+            .bRequest      = USB_GET_DESCRIPTOR,
+            .wValue        = USBH_DESC(USB_DESCTYPE_REPORT),
+            .wIndex        = 0U,
+            .wLength       = len
+        };
+
+        usbh_ctlstate_config(uhost, uhost->dev_prop.data, len);
+    }
+
+    status = usbh_ctl_handler(uhost);
+
+    return status;
+}
+
+/*!
+    \brief      managing the SOF process
+    \param[in]  uhost: pointer to USB host
+    \param[out] none
+    \retval     operation status
+*/
+static usbh_status usbh_hid_sof(usbh_host *uhost)
+{
+    usbh_hid_handler *hid = (usbh_hid_handler *)uhost->active_class->class_data;
+
+    if(HID_POLL == hid->state) {
+        uint32_t frame_count = usb_curframe_get(uhost->data);
+
+        if((frame_count > hid->timer) && ((frame_count - hid->timer) >= hid->poll)) {
+            hid->state = HID_GET_DATA;
+        } else if((frame_count < hid->timer) && ((frame_count + 0x3FFFU - hid->timer) >= hid->poll)) {
+            hid->state = HID_GET_DATA;
+        } else {
+            /* no operation */
+        }
+    }
+
+    return USBH_OK;
+}
+
+/*!
+    \brief      send the command of get HID descriptor to the device
+    \param[in]  uhost: pointer to USB host
+    \param[in]  len: HID descriptor length
+    \param[out] none
+    \retval     operation status
+*/
+static usbh_status usbh_hid_desc_get(usbh_host *uhost, uint16_t len)
+{
+    usbh_status status = USBH_BUSY;
+
+    if(CTL_IDLE == uhost->control.ctl_state) {
+        uhost->control.setup.req = (usb_req) {
+            .bmRequestType = USB_TRX_IN | USB_RECPTYPE_ITF | USB_REQTYPE_STRD,
+            .bRequest      = USB_GET_DESCRIPTOR,
+            .wValue        = USBH_DESC(USB_DESCTYPE_HID),
+            .wIndex        = 0U,
+            .wLength       = len
+        };
+
+        usbh_ctlstate_config(uhost, uhost->dev_prop.data, len);
+    }
+
+    status = usbh_ctl_handler(uhost);
+
+    return status;
+}
+
+/*!
+    \brief      set idle state
+    \param[in]  uhost: pointer to USB host
+    \param[in]  duration: duration for HID set idle request
+    \param[in]  report_ID: targeted report ID for HID set idle request
+    \param[out] none
+    \retval     operation status
+*/
+static usbh_status usbh_set_idle(usbh_host *uhost, uint8_t duration, uint8_t report_ID)
+{
+    usbh_status status = USBH_BUSY;
+
+    if(CTL_IDLE == uhost->control.ctl_state) {
+        uhost->control.setup.req = (usb_req) {
+            .bmRequestType = USB_TRX_OUT | USB_RECPTYPE_ITF | USB_REQTYPE_CLASS,
+            .bRequest      = SET_IDLE,
+            .wValue        = (duration << 8) | report_ID,
+            .wIndex        = 0U,
+            .wLength       = 0U
+        };
+
+        usbh_ctlstate_config(uhost, NULL, 0U);
+    }
+
+    status = usbh_ctl_handler(uhost);
+
+    return status;
+}
+
+/*!
+    \brief      set protocol state
+    \param[in]  uhost: pointer to USB host
+    \param[in]  protocol: boot/report protocol
+    \param[out] none
+    \retval     operation status
+*/
+static usbh_status usbh_set_protocol(usbh_host *uhost, uint8_t protocol)
+{
+    usbh_status status = USBH_BUSY;
+
+    if(CTL_IDLE == uhost->control.ctl_state) {
+        uhost->control.setup.req = (usb_req) {
+            .bmRequestType = USB_TRX_OUT | USB_RECPTYPE_ITF | USB_REQTYPE_CLASS,
+            .bRequest      = SET_PROTOCOL,
+            .wValue        = !protocol,
+            .wIndex        = 0U,
+            .wLength       = 0U
+        };
+
+        usbh_ctlstate_config(uhost, NULL, 0U);
+    }
+
+    status = usbh_ctl_handler(uhost);
+
+    return status;
+}
+
+/*!
+    \brief      parse the HID descriptor
+    \param[in]  hid_desc: pointer to HID descriptor
+    \param[in]  buf: pointer to buffer where the source descriptor is available
+    \param[out] none
+    \retval     none
+*/
+static void usbh_hiddesc_parse(usb_desc_hid *hid_desc, uint8_t *buf)
+{
+    hid_desc->header.bLength         = *(uint8_t *)(buf + 0U);
+    hid_desc->header.bDescriptorType = *(uint8_t *)(buf + 1U);
+    hid_desc->bcdHID                 = BYTE_SWAP(buf + 2U);
+    hid_desc->bCountryCode           = *(uint8_t *)(buf + 4U);
+    hid_desc->bNumDescriptors        = *(uint8_t *)(buf + 5U);
+    hid_desc->bDescriptorType        = *(uint8_t *)(buf + 6U);
+    hid_desc->wDescriptorLength      = BYTE_SWAP(buf + 7U);
+}

+ 271 - 0
GD32F3x0/GD32F3x0_usbfs_library/host/class/hid/Source/usbh_standard_hid.c

@@ -0,0 +1,271 @@
+/*!
+    \file    usbh_standard_hid.c
+    \brief   USB host HID mouse and keyboard driver
+
+    \version 2025-01-01, V2.5.0, firmware for GD32F3x0
+*/
+
+/*
+    Copyright (c) 2025, GigaDevice Semiconductor Inc.
+
+    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 of the copyright holder 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 HOLDER 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.
+*/
+
+#include "usbh_standard_hid.h"
+
+hid_mouse_info mouse_info;
+hid_keybd_info keybd_info;
+
+uint8_t mouse_report_data[8] = {0U};
+uint32_t keybd_report_data[2];
+
+/* local constants */
+static const uint8_t kbd_codes[] = {
+    0,      0,      0,      0,      31,     50,     48,     33,
+    19,     34,     35,     36,     24,     37,     38,     39,         /* 0x00 - 0x0F */
+    52,     51,     25,     26,     17,     20,     32,     21,
+    23,     49,     18,     47,     22,     46,     2,      3,          /* 0x10 - 0x1F */
+    4,      5,      6,      7,      8,      9,      10,     11,
+    43,     110,    15,     16,     61,     12,     13,     27,         /* 0x20 - 0x2F */
+    28,     29,     42,     40,     41,     1,      53,     54,
+    55,     30,     112,    113,    114,    115,    116,    117,        /* 0x30 - 0x3F */
+    118,    119,    120,    121,    122,    123,    124,    125,
+    126,    75,     80,     85,     76,     81,     86,     89,         /* 0x40 - 0x4F */
+    79,     84,     83,     90,     95,     100,    105,    106,
+    108,    93,     98,     103,    92,     97,     102,    91,         /* 0x50 - 0x5F */
+    96,     101,    99,     104,    45,     129,    0,      0,
+    0,      0,      0,      0,      0,      0,      0,      0,          /* 0x60 - 0x6F */
+    0,      0,      0,      0,      0,      0,      0,      0,
+    0,      0,      0,      0,      0,      0,      0,      0,          /* 0x70 - 0x7F */
+    0,      0,      0,      0,      0,      107,    0,      56,
+    0,      0,      0,      0,      0,      0,      0,      0,          /* 0x80 - 0x8F */
+    0,      0,      0,      0,      0,      0,      0,      0,
+    0,      0,      0,      0,      0,      0,      0,      0,          /* 0x90 - 0x9F */
+    0,      0,      0,      0,      0,      0,      0,      0,
+    0,      0,      0,      0,      0,      0,      0,      0,          /* 0xA0 - 0xAF */
+    0,      0,      0,      0,      0,      0,      0,      0,
+    0,      0,      0,      0,      0,      0,      0,      0,          /* 0xB0 - 0xBF */
+    0,      0,      0,      0,      0,      0,      0,      0,
+    0,      0,      0,      0,      0,      0,      0,      0,          /* 0xC0 - 0xCF */
+    0,      0,      0,      0,      0,      0,      0,      0,
+    0,      0,      0,      0,      0,      0,      0,      0,          /* 0xD0 - 0xDF */
+    58,     44,     60,     127,    64,     57,     62,     128         /* 0xE0 - 0xE7 */
+};
+
+#ifdef QWERTY_KEYBOARD
+
+static const int8_t kbd_key[] = {
+    '\0',   '`',    '1',    '2',    '3',    '4',    '5',    '6',
+    '7',    '8',    '9',    '0',    '-',    '=',    '\0',   '\r',
+    '\t',   'q',    'w',    'e',    'r',    't',    'y',    'u',
+    'i',    'o',    'p',    '[',    ']',    '\\',
+    '\0',   'a',    's',    'd',    'f',    'g',    'h',    'j',
+    'k',    'l',    ';',    '\'',   '\0',   '\n',
+    '\0',   '\0',   'z',    'x',    'c',    'v',    'b',    'n',
+    'm',    ',',    '.',    '/',    '\0',   '\0',
+    '\0',   '\0',   '\0',   ' ',    '\0',   '\0',   '\0',   '\0',
+    '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',
+    '\0',   '\0',   '\0',   '\0',   '\0',   '\r',   '\0',   '\0',
+    '\0',   '\0',   '\0',   '\0',   '\0',   '\0',
+    '\0',   '\0',   '7',    '4',    '1',
+    '\0',   '/',    '8',    '5',    '2',
+    '0',    '*',    '9',    '6',    '3',
+    '.',    '-',    '+',    '\0',   '\n',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',
+    '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',
+    '\0',   '\0',   '\0',   '\0'
+};
+
+static const int8_t kbd_key_shift[] = {
+    '\0',   '~',    '!',    '@',    '#',    '$',    '%',    '^',    '&',    '*',    '(',    ')',
+    '_',    '+',    '\0',   '\0',   '\0',   'Q',    'W',    'E',    'R',    'T',    'Y',    'U',
+    'I',    'O',    'P',    '{',    '}',    '|',    '\0',   'A',    'S',    'D',    'F',    'G',
+    'H',    'J',    'K',    'L',    ':',    '"',    '\0',   '\n',   '\0',   '\0',   'Z',    'X',
+    'C',    'V',    'B',    'N',    'M',    '<',    '>',    '?',    '\0',   '\0',   '\0',   '\0',
+    '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',
+    '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',
+    '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',
+    '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',
+    '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',
+    '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0'
+};
+
+#else
+
+static const int8_t kbd_key[] = {
+    '\0',   '`',    '1',    '2',    '3',    '4',    '5',    '6',    '7',    '8',    '9',    '0',
+    '-',    '=',    '\0',   '\r',   '\t',   'a',    'z',    'e',    'r',    't',    'y',    'u',
+    'i',    'o',    'p',    '[',    ']',    '\\',   '\0',   'q',    's',    'd',    'f',    'g',
+    'h',    'j',    'k',    'l',    'm',    '\0',   '\0',   '\n',   '\0',   '\0',   'w',    'x',
+    'c',    'v',    'b',    'n',    ',',    ';',    ':',    '!',    '\0',   '\0',   '\0',   '\0',
+    '\0',   ' ',    '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',
+    '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\r',   '\0',   '\0',   '\0',
+    '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '7',    '4',    '1',    '\0',   '/',
+    '8',    '5',    '2',    '0',    '*',    '9',    '6',    '3',    '.',    '-',    '+',    '\0',
+    '\n',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',
+    '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0'
+};
+
+static const int8_t kbd_key_shift[] = {
+    '\0',   '~',    '!',    '@',    '#',    '$',    '%',    '^',    '&',    '*',    '(',    ')',    '_',
+    '+',    '\0',   '\0',   '\0',   'A',    'Z',    'E',    'R',    'T',    'Y',    'U',    'I',    'O',
+    'P',    '{',    '}',    '*',    '\0',   'Q',    'S',    'D',    'F',    'G',    'H',    'J',    'K',
+    'L',    'M',    '%',    '\0',   '\n',   '\0',   '\0',   'W',    'X',    'C',    'V',    'B',    'N',
+    '?',    '.',    '/',    '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',
+    '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',
+    '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',
+    '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',
+    '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',
+    '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0',   '\0'
+};
+
+#endif /* QWERTY_KEYBOARD */
+
+/*!
+    \brief      initialize the mouse function
+    \param[in]  udev: pointer to USB core instance
+    \param[in]  uhost: pointer to USB host
+    \param[out] none
+    \retval     none
+*/
+usbh_status usbh_hid_mouse_init(usb_core_driver *udev, usbh_host *uhost)
+{
+    usbh_hid_handler *hid = (usbh_hid_handler *)uhost->active_class->class_data;
+
+    mouse_info.x = 0U;
+    mouse_info.y = 0U;
+    mouse_info.buttons[0] = 0U;
+    mouse_info.buttons[1] = 0U;
+    mouse_info.buttons[2] = 0U;
+
+    if(hid->len > sizeof(mouse_report_data)) {
+        hid->len = sizeof(mouse_report_data);
+    }
+
+    hid->pdata = (uint8_t *)(void *)mouse_report_data;
+
+    usr_mouse_init();
+
+    return USBH_OK;
+}
+
+/*!
+    \brief      decode mouse information
+    \param[in]  data: pointer to input data
+    \param[out] none
+    \retval     operation status
+*/
+usbh_status usbh_hid_mouse_decode(uint8_t *data)
+{
+    mouse_info.buttons[0] = data[0] & MOUSE_BUTTON_1;
+    mouse_info.buttons[1] = data[0] & MOUSE_BUTTON_2;
+    mouse_info.buttons[2] = data[0] & MOUSE_BUTTON_3;
+
+    mouse_info.x = data[1];
+    mouse_info.y = data[2];
+
+    /* handle mouse data position */
+    usr_mouse_process_data(&mouse_info);
+
+    return USBH_FAIL;
+}
+
+/*!
+    \brief      initialize the keyboard function
+    \param[in]  udev: pointer to USB core instance
+    \param[in]  uhost: pointer to USB host
+    \param[out] none
+    \retval     operation status
+*/
+usbh_status usbh_hid_keybrd_init(usb_core_driver *udev, usbh_host *uhost)
+{
+    usbh_hid_handler *hid = (usbh_hid_handler *)uhost->active_class->class_data;
+
+    keybd_info.lctrl = keybd_info.lshift = 0U;
+    keybd_info.lalt  = keybd_info.lgui   = 0U;
+    keybd_info.rctrl = keybd_info.rshift = 0U;
+    keybd_info.ralt  = keybd_info.rgui   = 0U;
+
+    for(uint32_t x = 0U; x < (sizeof(keybd_report_data) / sizeof(uint32_t)); x++) {
+        keybd_report_data[x] = 0U;
+    }
+
+    if(hid->len > (sizeof(keybd_report_data) / sizeof(uint32_t))) {
+        hid->len = (sizeof(keybd_report_data) / sizeof(uint32_t));
+    }
+
+    hid->pdata = (uint8_t *)(void *)keybd_report_data;
+
+    /* call user initialization*/
+    usr_keybrd_init();
+
+    return USBH_OK;
+}
+
+/*!
+    \brief      get ASCII code
+    \param[in]  info: keyboard information
+    \param[out] none
+    \retval     output
+*/
+uint8_t usbh_hid_ascii_code_get(hid_keybd_info *info)
+{
+    uint8_t output = 0U;
+
+    if((1U == info->lshift) || (info->rshift)) {
+        output = kbd_key_shift[kbd_codes[info->keys[0]]];
+    } else {
+        output = kbd_key[kbd_codes[info->keys[0]]];
+    }
+
+    return output;
+}
+
+/*!
+    \brief      decode keyboard information
+    \param[in]  udev: pointer to USB core instance
+    \param[in]  uhost: pointer to USB host
+    \param[out] none
+    \retval     operation status
+*/
+usbh_status usbh_hid_keybrd_decode(uint8_t *data)
+{
+    uint8_t output = 0U;
+
+    keybd_info.lshift = data[0] & KBD_LEFT_SHIFT;
+    keybd_info.rshift = data[0] & KBD_RIGHT_SHIFT;
+
+    keybd_info.keys[0] = data[2];
+
+    if(keybd_info.lshift || keybd_info.rshift) {
+        output = kbd_key_shift[kbd_codes[keybd_info.keys[0]]];
+    } else {
+        output = kbd_key[kbd_codes[keybd_info.keys[0]]];
+    }
+
+    if(0U != output) {
+        usr_keybrd_process_data(output);
+    }
+
+    return USBH_OK;
+}

+ 148 - 0
GD32F3x0/GD32F3x0_usbfs_library/host/class/msc/Include/usbh_msc_bbb.h

@@ -0,0 +1,148 @@
+/*!
+    \file    usbh_msc_bbb.h
+    \brief   header file for usbh_msc_bbb.c
+
+    \version 2025-01-01, V2.5.0, firmware for GD32F3x0
+*/
+
+/*
+    Copyright (c) 2025, GigaDevice Semiconductor Inc.
+
+    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 of the copyright holder 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 HOLDER 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.
+*/
+
+#ifndef USBH_MSC_BBB_H
+#define USBH_MSC_BBB_H
+
+#include "msc_bbb.h"
+#include "usbh_core.h"
+
+#define USBH_MSC_BBB_CBW_TAG                0x20304050U          /*!< MSC BBB CBW tag */
+
+#define USBH_MSC_CSW_MAX_LENGTH             63U                  /*!< MSC CSW maximum length */
+
+#define USBH_MSC_SEND_CSW_DISABLE           0U                   /*!< MSC send CSW disable */
+#define USBH_MSC_SEND_CSW_ENABLE            1U                   /*!< MSC send CSW enable */
+
+#define USBH_MSC_DIR_IN                     0U                   /*!< MSC data transfer IN */
+#define USBH_MSC_DIR_OUT                    1U                   /*!< MSC data transfer OUT */
+#define USBH_MSC_BOTH_DIR                   2U                   /*!< MSC data transfer IN/OUT */
+
+#define USBH_MSC_PAGE_LENGTH                512U                 /*!< MSC memory page length */
+
+#define CBW_CB_LENGTH                       16U                  /*!< MSC CBW CB length */
+#define CBW_LENGTH                          10U                  /*!< MSC CBW length */
+#define CBW_LENGTH_TEST_UNIT_READY          0U                   /*!< MSC CBW test unit ready length */
+
+#define MAX_BULK_STALL_COUNT_LIMIT          0x04U                /*!< if STALL is seen on bulk 
+                                                                      endpoint continously, this means 
+                                                                      that device and host has phase error
+                                                                      hence a reset is needed */
+
+typedef union {
+    msc_bbb_cbw field;                             /*!< MSC BBB CBW structure */
+
+    uint8_t CBWArray[31];                          /*!< MSC BBB CBW array buff */
+}usbh_cbw_pkt;
+
+typedef union {
+    msc_bbb_csw field;                             /*!< MSC BBB CSW structure */
+
+    uint8_t CSWArray[13];                          /*!< MSC BBB CSW array buff */
+}usbh_csw_pkt;
+
+enum usbh_msc_state {
+    USBH_MSC_BBB_INIT_STATE = 0U,                  /*!< MSC BBB init state */
+    USBH_MSC_BBB_RESET,                            /*!< MSC BBB reset state */
+    USBH_MSC_GET_MAX_LUN,                          /*!< MSC init state */
+    USBH_MSC_TEST_UNIT_READY,                      /*!< MSC test unit ready state */
+    USBH_MSC_READ_CAPACITY10,                      /*!< MSC read capacity10 state */
+    USBH_MSC_MODE_SENSE6,                          /*!< MSC sense6 mode state */
+    USBH_MSC_REQUEST_SENSE,                        /*!< MSC request sense state */
+    USBH_MSC_BBB_USB_TRANSFERS,                    /*!< MSC BBB transfers state */
+    USBH_MSC_DEFAULT_APPLI_STATE,                  /*!< MSC default application state */
+    USBH_MSC_CTRL_ERROR_STATE,                     /*!< MSC control error state */
+    USBH_MSC_UNRECOVERED_STATE                     /*!< MSC unrecovered state */
+};
+
+/* MSC BBB status types */
+typedef enum {
+    BBB_OK = 0U,                                   /*!< MSC BBB OK status */
+    BBB_FAIL,                                      /*!< MSC BBB fail status */
+    BBB_PHASE_ERROR,                               /*!< MSC BBB phase error status */
+    BBB_BUSY                                       /*!< MSC BBB busy status */
+} bbb_status;
+
+/* MSC BBB command state types */
+typedef enum {
+    BBB_CMD_IDLE = 0U,                             /*!< MSC BBB command idle state */
+    BBB_CMD_SEND,                                  /*!< MSC BBB command send state */
+    BBB_CMD_WAIT                                   /*!< MSC BBB command wait state */
+} bbb_cmd_state;
+
+/* CSW status definitions */
+typedef enum {
+    BBB_CSW_CMD_PASSED = 0U,                       /*!< MSC BBB CSW command passed status */
+    BBB_CSW_CMD_FAILED,                            /*!< MSC BBB CSW command failed status */
+    BBB_CSW_PHASE_ERROR                            /*!< MSC BBB CSW phase error status */
+} bbb_csw_status;
+
+/* MSC BBB state types */
+typedef enum {
+    BBB_SEND_CBW = 1U,                             /*!< MSC BBB send CBW state */
+    BBB_SEND_CBW_WAIT,                             /*!< MSC BBB send CBW wait state */
+    BBB_DATA_IN,                                   /*!< MSC BBB data IN state */
+    BBB_DATA_IN_WAIT,                              /*!< MSC BBB data IN wait state */
+    BBB_DATA_OUT,                                  /*!< MSC BBB data OUT state */
+    BBB_DATA_OUT_WAIT,                             /*!< MSC BBB data OUT wait state */
+    BBB_RECEIVE_CSW,                               /*!< MSC BBB receive CSW state */
+    BBB_RECEIVE_CSW_WAIT,                          /*!< MSC BBB receive CSW wait state */
+    BBB_ERROR_IN,                                  /*!< MSC BBB error IN state */
+    BBB_ERROR_OUT,                                 /*!< MSC BBB error OUT state */
+    BBB_UNRECOVERED_ERROR                          /*!< MSC BBB unrecovered error state */
+} bbb_state;
+
+typedef struct {
+    uint8_t                *pbuf;                  /*!< MSC BBB data buff pointer */
+    uint32_t                data[16];              /*!< MSC BBB data buff */
+    bbb_state               state;                 /*!< MSC BBB state */
+    bbb_state               prev_state;            /*!< MSC BBB previous state */
+    bbb_cmd_state           cmd_state;             /*!< MSC BBB command state */
+    usbh_cbw_pkt            cbw;                   /*!< MSC CBW pocket structure */
+    usbh_csw_pkt            csw;                   /*!< MSC CSW pocket structure */
+} bbb_handle;
+
+/* function declarations */
+/* initialize the mass storage parameters */
+void usbh_msc_bbb_init(usbh_host *uhost);
+/* manage the different states of BBB transfer and updates the status to upper layer */
+usbh_status usbh_msc_bbb_process(usbh_host *uhost, uint8_t lun);
+/* manages the different error handling for STALL */
+usbh_status usbh_msc_bbb_abort(usbh_host *uhost, uint8_t direction);
+/* reset MSC BBB request structure */
+usbh_status usbh_msc_bbb_reset(usbh_host *uhost);
+/* decode the CSW received by the device and updates the same to upper layer */
+bbb_csw_status usbh_msc_csw_decode(usbh_host *uhost);
+
+#endif /* USBH_MSC_BBB_H */

+ 122 - 0
GD32F3x0/GD32F3x0_usbfs_library/host/class/msc/Include/usbh_msc_core.h

@@ -0,0 +1,122 @@
+/*!
+    \file    usbh_core.h
+    \brief   header file for the usbh_core.c
+
+    \version 2025-01-01, V2.5.0, firmware for GD32F3x0
+*/
+
+/*
+    Copyright (c) 2025, GigaDevice Semiconductor Inc.
+
+    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 of the copyright holder 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 HOLDER 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.
+*/
+
+#ifndef USBH_MSC_CORE_H
+#define USBH_MSC_CORE_H
+
+#include "usb_msc.h"
+#include "usbh_msc_scsi.h"
+#include "usbh_msc_bbb.h"
+
+#define MSC_MAX_SUPPORTED_LUN                   2U
+
+/* MSC state types */
+typedef enum {
+    MSC_INIT = 0U,                                       /*!< MSC init state */
+    MSC_IDLE,                                            /*!< MSC idle state */
+    MSC_TEST_UNIT_READY,                                 /*!< MSC test unit ready state */
+    MSC_READ_CAPACITY10,                                 /*!< MSC read capacity10 state */
+    MSC_READ_INQUIRY,                                    /*!< MSC read inquiry state */
+    MSC_REQUEST_SENSE,                                   /*!< MSC request sense state */
+    MSC_READ,                                            /*!< MSC read state */
+    MSC_WRITE,                                           /*!< MSC write state */
+    MSC_UNRECOVERED_ERROR,                               /*!< MSC unrecovered state */
+    MSC_PERIODIC_CHECK                                   /*!< MSC periodic check state */
+} msc_state;
+
+/* MSC error types */
+typedef enum {
+    MSC_OK = 0U,                                         /*!< MSC no error */
+    MSC_NOT_READY,                                       /*!< MSC not ready */
+    MSC_ERROR                                            /*!< MSC error */
+} msc_error;
+
+/* MSC request types */
+typedef enum {
+    MSC_REQ_IDLE = 0U,                                   /*!< MSC idle request state */
+    MSC_REQ_RESET,                                       /*!< MSC reset request state */
+    MSC_REQ_GET_MAX_LUN,                                 /*!< MSC get maximum LUN request state */
+    MSC_REQ_ERROR                                        /*!< MSC error request state */
+} msc_req_state;
+
+/* structure for LUN */
+typedef struct {
+    msc_state               state;                       /*!< MSC LUN state */
+    msc_error               error;                       /*!< MSC LUN error */
+    msc_scsi_sense          sense;                       /*!< MSC SCSI sense */
+    scsi_capacity           capacity;                    /*!< MSC SCSI capacity */
+    scsi_std_inquiry_data   inquiry;                     /*!< MSC SCSI standard inquiry data */
+    usbh_status             prev_ready_state;            /*!< MSC previous ready state */
+    uint8_t                 state_changed;               /*!< MSC state changed */
+} msc_lun;
+
+/* structure for MSC process */
+typedef struct _msc_process {
+    uint8_t         pipe_in;                             /*!< MSC pipe IN */
+    uint8_t         pipe_out;                            /*!< MSC pipe OUT */
+    uint8_t         ep_in;                               /*!< MSC endpoint IN */
+    uint8_t         ep_out;                              /*!< MSC endpoint OUT */
+    uint16_t        ep_size_in;                          /*!< MSC endpoint IN size */
+    uint16_t        ep_size_out;                         /*!< MSC endpoint OUT size */
+    uint8_t         cur_lun;                             /*!< MSC current LUN */
+    uint16_t        rw_lun;                              /*!< MSC review LUN */
+    uint32_t        max_lun;                             /*!< MSC maximum LUN */
+    msc_state       state;                               /*!< MSC state */
+    msc_error       error;                               /*!< MSC error */
+    msc_req_state   req_state;                           /*!< MSC request state */
+    msc_req_state   prev_req_state;                      /*!< MSC previous request state */
+    bbb_handle      bbb;                                 /*!< MSC BBB correlation parameter handle */
+    msc_lun         unit[MSC_MAX_SUPPORTED_LUN];         /*!< MSC LUN unit buff */
+    uint32_t        timer;                               /*!< MSC read/write timer */
+} usbh_msc_handler;
+
+extern usbh_class usbh_msc;
+
+/* function declarations */
+/* get MSC logic unit information */
+usbh_status usbh_msc_lun_info_get(usbh_host *uhost, uint8_t lun, msc_lun *info);
+/* MSC read interface */
+usbh_status usbh_msc_read(usbh_host *uhost, \
+                          uint8_t lun, \
+                          uint32_t address, \
+                          uint8_t *pbuf, \
+                          uint32_t length);
+/* MSC write interface */
+usbh_status usbh_msc_write(usbh_host *uhost, \
+                           uint8_t lun, \
+                           uint32_t address, \
+                           uint8_t *pbuf, \
+                           uint32_t length);
+
+#endif /* USBH_MSC_CORE_H */

+ 96 - 0
GD32F3x0/GD32F3x0_usbfs_library/host/class/msc/Include/usbh_msc_scsi.h

@@ -0,0 +1,96 @@
+/*!
+    \file    usbh_msc_scsi.h
+    \brief   header file for usbh_msc_scsi.c
+
+    \version 2025-01-01, V2.5.0, firmware for GD32F3x0
+*/
+
+/*
+    Copyright (c) 2025, GigaDevice Semiconductor Inc.
+
+    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 of the copyright holder 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 HOLDER 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.
+*/
+
+#ifndef USBH_MSC_SCSI_H
+#define USBH_MSC_SCSI_H
+
+#include "msc_scsi.h"
+#include "usbh_enum.h"
+#define DESC_REQUEST_SENSE                   00U         /*!< sense request descriptor */
+#define ALLOCATION_LENGTH_REQUEST_SENSE      63U         /*!< sense request allocation length */
+#define XFER_LEN_MODE_SENSE6                 63U         /*!< MSC sense6 mode transfer length */
+
+#define MASK_MODE_SENSE_WRITE_PROTECT        0x80U       /*!< sense write protect mask mode */
+#define MODE_SENSE_PAGE_CONTROL_FIELD        0x00U       /*!< sense page control field mode */
+#define MODE_SENSE_PAGE_CODE                 0x3FU       /*!< sense page code mode */
+#define DISK_WRITE_PROTECTED                 0x01U       /*!< disk write protected */
+
+/* capacity data */
+typedef struct {
+    uint32_t block_nbr;                                  /*!< MSC SCSI block number */
+    uint16_t block_size;                                 /*!< MSC SCSI block size */
+} scsi_capacity;
+
+/* inquiry data */
+typedef struct {
+    uint8_t peripheral_qualifier;                        /*!< MSC SCSI standard peripheral qualifier */
+    uint8_t device_type;                                 /*!< MSC SCSI standard inquiry device types */
+    uint8_t removable_media;                             /*!< MSC SCSI standard inquiry removable media */
+    uint8_t vendor_id[9];                                /*!< MSC SCSI standard inquiry vendor id buff */
+    uint8_t product_id[17];                              /*!< MSC SCSI standard inquiry product id buff */
+    uint8_t revision_id[5];                              /*!< MSC SCSI standard inquiry revision id buff */
+} scsi_std_inquiry_data;
+
+typedef struct {
+    uint32_t msc_capacity;                               /*!< MSC capacity */
+    uint32_t msc_sense_key;                              /*!< MSC sense key */
+    uint16_t msc_page_len;                               /*!< MSC memory page length */
+    uint8_t msc_write_protect;                           /*!< MSC write protect */
+}usbh_msc_parameter;
+
+/* function declarations */
+/* send 'inquiry' command to the device */
+usbh_status usbh_msc_scsi_inquiry(usbh_host *uhost, uint8_t lun, scsi_std_inquiry_data *inquiry);
+/* send 'test unit ready' command to the device */
+usbh_status usbh_msc_test_unitready(usbh_host *uhost, uint8_t lun);
+/* send the read capacity command to the device */
+usbh_status usbh_msc_read_capacity10(usbh_host *uhost, uint8_t lun, scsi_capacity *capacity);
+/* send the mode sense6 command to the device */
+usbh_status usbh_msc_mode_sense6(usbh_host *uhost, uint8_t lun);
+/* send the request sense command to the device */
+usbh_status usbh_msc_request_sense(usbh_host *uhost, uint8_t lun, msc_scsi_sense *sense_data);
+/* send the write10 command to the device */
+usbh_status usbh_msc_write10(usbh_host *uhost, \
+                             uint8_t lun, \
+                             uint8_t *data_buf, \
+                             uint32_t addr, \
+                             uint32_t byte_num);
+/* send the read10 command to the device */
+usbh_status usbh_msc_read10(usbh_host *uhost, \
+                            uint8_t lun, \
+                            uint8_t *data_buf, \
+                            uint32_t addr, \
+                            uint32_t byte_num);
+
+#endif /* USBH_MSC_SCSI_H */

+ 360 - 0
GD32F3x0/GD32F3x0_usbfs_library/host/class/msc/Source/usbh_msc_bbb.c

@@ -0,0 +1,360 @@
+/*!
+    \file    usbh_msc_bbb.c
+    \brief   USB MSC BBB protocol related functions
+
+    \version 2025-01-01, V2.5.0, firmware for GD32F3x0
+*/
+
+/*
+    Copyright (c) 2025, GigaDevice Semiconductor Inc.
+
+    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 of the copyright holder 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 HOLDER 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.
+*/
+
+#include "usbh_pipe.h"
+#include "usbh_transc.h"
+#include "usbh_msc_core.h"
+#include "usbh_msc_bbb.h"
+
+/*!
+    \brief      initialize the mass storage parameters
+    \param[in]  uhost: pointer to USB host handler
+    \param[out] none
+    \retval     none
+*/
+void usbh_msc_bbb_init(usbh_host *uhost)
+{
+    usbh_msc_handler *msc = (usbh_msc_handler *)uhost->active_class->class_data;
+
+    msc->bbb.cbw.field.dCBWSignature = BBB_CBW_SIGNATURE;
+    msc->bbb.cbw.field.dCBWTag = USBH_MSC_BBB_CBW_TAG;
+    msc->bbb.state = BBB_SEND_CBW;
+    msc->bbb.cmd_state = BBB_CMD_SEND;
+}
+
+/*!
+    \brief      manage the different states of BBB transfer and updates the status to upper layer
+    \param[in]  uhost: pointer to USB host handler
+    \param[in]  lun: logic unit number
+    \param[out] none
+    \retval     operation status
+*/
+usbh_status usbh_msc_bbb_process(usbh_host *uhost, uint8_t lun)
+{
+    bbb_csw_status csw_status = BBB_CSW_CMD_FAILED;
+    usbh_status status = USBH_BUSY;
+    usbh_status error = USBH_BUSY;
+    usb_urb_state urb_status = URB_IDLE;
+    usbh_msc_handler *msc = (usbh_msc_handler *)uhost->active_class->class_data;
+
+    switch(msc->bbb.state) {
+    case BBB_SEND_CBW:
+        msc->bbb.cbw.field.bCBWLUN = lun;
+        msc->bbb.state = BBB_SEND_CBW_WAIT;
+        /* send CBW */
+        usbh_data_send(uhost->data, \
+                       msc->bbb.cbw.CBWArray, \
+                       msc->pipe_out, \
+                       BBB_CBW_LENGTH);
+        break;
+
+    case BBB_SEND_CBW_WAIT:
+        urb_status = usbh_urbstate_get(uhost->data, msc->pipe_out);
+
+        if(URB_DONE == urb_status) {
+            if(0U != msc->bbb.cbw.field.dCBWDataTransferLength) {
+                if(USB_TRX_IN == (msc->bbb.cbw.field.bmCBWFlags & USB_TRX_MASK)) {
+                    msc->bbb.state = BBB_DATA_IN;
+                } else {
+                    msc->bbb.state = BBB_DATA_OUT;
+                }
+            } else {
+                msc->bbb.state = BBB_RECEIVE_CSW;
+            }
+
+        } else if(URB_NOTREADY == urb_status) {
+            msc->bbb.state = BBB_SEND_CBW;
+        } else {
+            if(URB_STALL == urb_status) {
+                msc->bbb.state = BBB_ERROR_OUT;
+            }
+        }
+        break;
+
+    case BBB_DATA_IN:
+        usbh_data_recev(uhost->data, \
+                        msc->bbb.pbuf, \
+                        msc->pipe_in, \
+                        msc->ep_size_in);
+
+        msc->bbb.state = BBB_DATA_IN_WAIT;
+        break;
+
+    case BBB_DATA_IN_WAIT:
+        urb_status = usbh_urbstate_get(uhost->data, msc->pipe_in);
+
+        /* BBB DATA IN stage */
+        if(URB_DONE == urb_status) {
+            if(msc->bbb.cbw.field.dCBWDataTransferLength > msc->ep_size_in) {
+                msc->bbb.pbuf += msc->ep_size_in;
+                msc->bbb.cbw.field.dCBWDataTransferLength -= msc->ep_size_in;
+            } else {
+                msc->bbb.cbw.field.dCBWDataTransferLength = 0U;
+            }
+
+            if(msc->bbb.cbw.field.dCBWDataTransferLength > 0U) {
+                usbh_data_recev(uhost->data, \
+                                msc->bbb.pbuf, \
+                                msc->pipe_in, \
+                                msc->ep_size_in);
+            } else {
+                msc->bbb.state = BBB_RECEIVE_CSW;
+            }
+        } else if(URB_STALL == urb_status) {
+            /* this is data stage STALL condition */
+            msc->bbb.state = BBB_ERROR_IN;
+        } else {
+            /* no operation */
+        }
+        break;
+
+    case BBB_DATA_OUT:
+        usbh_data_send(uhost->data, \
+                       msc->bbb.pbuf, \
+                       msc->pipe_out, \
+                       msc->ep_size_out);
+
+        msc->bbb.state = BBB_DATA_OUT_WAIT;
+        break;
+
+    case BBB_DATA_OUT_WAIT:
+        /* BBB DATA OUT stage */
+        urb_status = usbh_urbstate_get(uhost->data, msc->pipe_out);
+        if(URB_DONE == urb_status) {
+            if(msc->bbb.cbw.field.dCBWDataTransferLength > msc->ep_size_out) {
+                msc->bbb.pbuf += msc->ep_size_out;
+                msc->bbb.cbw.field.dCBWDataTransferLength -= msc->ep_size_out;
+            }  else {
+                msc->bbb.cbw.field.dCBWDataTransferLength = 0U; /* reset this value and keep in same state */
+            }
+
+            if(msc->bbb.cbw.field.dCBWDataTransferLength > 0U) {
+                usbh_data_send(uhost->data, \
+                               msc->bbb.pbuf, \
+                               msc->pipe_out, \
+                               msc->ep_size_out);
+            } else {
+                msc->bbb.state = BBB_RECEIVE_CSW;
+            }
+        } else if(URB_NOTREADY == urb_status) {
+            msc->bbb.state = BBB_DATA_OUT;
+        } else if(URB_STALL == urb_status) {
+            msc->bbb.state = BBB_ERROR_OUT;
+        } else {
+            /* no operation */
+        }
+        break;
+
+    case BBB_RECEIVE_CSW:
+        /* BBB CSW stage */
+        usbh_data_recev(uhost->data, \
+                        msc->bbb.csw.CSWArray, \
+                        msc->pipe_in, \
+                        BBB_CSW_LENGTH);
+
+        msc->bbb.state = BBB_RECEIVE_CSW_WAIT;
+        break;
+
+    case BBB_RECEIVE_CSW_WAIT:
+        urb_status = usbh_urbstate_get(uhost->data, msc->pipe_in);
+
+        /* decode CSW */
+        if(URB_DONE == urb_status) {
+            msc->bbb.state = BBB_SEND_CBW;
+            msc->bbb.cmd_state = BBB_CMD_SEND;
+
+            csw_status = usbh_msc_csw_decode(uhost);
+            if(BBB_CSW_CMD_PASSED == csw_status) {
+                status = USBH_OK;
+            } else {
+                status = USBH_FAIL;
+            }
+        } else if(URB_STALL == urb_status) {
+            msc->bbb.state = BBB_ERROR_IN;
+        } else {
+            /* no operation */
+        }
+        break;
+
+    case BBB_ERROR_IN:
+        error = usbh_msc_bbb_abort(uhost, USBH_MSC_DIR_IN);
+
+        if(USBH_OK == error) {
+            msc->bbb.state = BBB_RECEIVE_CSW;
+        } else if(USBH_UNRECOVERED_ERROR == status) {
+            /* this means that there is a STALL error limit, do reset recovery */
+            msc->bbb.state = BBB_UNRECOVERED_ERROR;
+        } else {
+            /* no operation */
+        }
+        break;
+
+    case BBB_ERROR_OUT:
+        status = usbh_msc_bbb_abort(uhost, USBH_MSC_DIR_OUT);
+
+        if(USBH_OK == status) {
+            uint8_t toggle = usbh_pipe_toggle_get(uhost->data, msc->pipe_out);
+            usbh_pipe_toggle_set(uhost->data, msc->pipe_out, 1U - toggle);
+            usbh_pipe_toggle_set(uhost->data, msc->pipe_in, 0U);
+            msc->bbb.state = BBB_ERROR_IN;
+        } else {
+            if(USBH_UNRECOVERED_ERROR == status) {
+                msc->bbb.state = BBB_UNRECOVERED_ERROR;
+            }
+        }
+        break;
+
+    case BBB_UNRECOVERED_ERROR:
+        status = usbh_msc_bbb_reset(uhost);
+        if(USBH_OK == status) {
+            msc->bbb.state = BBB_SEND_CBW;
+        }
+        break;
+
+    default:
+        break;
+    }
+
+    return status;
+}
+
+/*!
+    \brief      manages the different error handling for stall
+    \param[in]  uhost: pointer to USB host handler
+    \param[in]  direction: data IN or OUT
+    \param[out] none
+    \retval     operation status
+*/
+usbh_status usbh_msc_bbb_abort(usbh_host *uhost, uint8_t direction)
+{
+    usbh_status status = USBH_BUSY;
+    usbh_msc_handler *msc = (usbh_msc_handler *)uhost->active_class->class_data;
+
+    switch(direction) {
+    case USBH_MSC_DIR_IN :
+        /* send clrfeature command on bulk IN endpoint */
+        status = usbh_clrfeature(uhost, \
+                                 msc->ep_in, \
+                                 msc->pipe_in);
+        break;
+
+    case USBH_MSC_DIR_OUT :
+        /*send clrfeature command on bulk OUT endpoint */
+        status = usbh_clrfeature(uhost, \
+                                 msc->ep_out, \
+                                 msc->pipe_out);
+        break;
+
+    default:
+        break;
+    }
+
+    return status;
+}
+
+/*!
+    \brief      reset MSC BBB transfer
+    \param[in]  uhost: pointer to USB host handler
+    \param[out] none
+    \retval     operation status
+*/
+usbh_status usbh_msc_bbb_reset(usbh_host *uhost)
+{
+    usbh_status status = USBH_BUSY;
+
+    if(CTL_IDLE == uhost->control.ctl_state) {
+        uhost->control.setup.req = (usb_req) {
+            .bmRequestType = USB_TRX_OUT | USB_REQTYPE_CLASS | USB_RECPTYPE_ITF,
+            .bRequest      = BBB_RESET,
+            .wValue        = 0U,
+            .wIndex        = 0U,
+            .wLength       = 0U
+        };
+
+        usbh_ctlstate_config(uhost, NULL, 0U);
+    }
+
+    status = usbh_ctl_handler(uhost);
+
+    return status;
+}
+
+/*!
+    \brief      decode the CSW received by the device and updates the same to upper layer
+    \param[in]  uhost: pointer to USB host
+    \param[out] none
+    \retval     on success USBH_MSC_OK, on failure USBH_MSC_FAIL
+    \notes
+          Refer to USB Mass-Storage Class: BBB (www.usb.org)
+          6.3.1 Valid CSW Conditions :
+          The host shall consider the CSW valid when:
+          1. dCSWSignature is equal to 53425355h
+          2. the CSW is 13 (Dh) bytes in length,
+          3. dCSWTag matches the dCBWTag from the corresponding CBW.
+*/
+bbb_csw_status usbh_msc_csw_decode(usbh_host *uhost)
+{
+    bbb_csw_status status = BBB_CSW_CMD_FAILED;
+    usbh_msc_handler *msc = (usbh_msc_handler *)uhost->active_class->class_data;
+
+    /* checking if the transfer length is different than 13 */
+    if(BBB_CSW_LENGTH != usbh_xfercount_get(uhost->data, msc->pipe_in)) {
+        status = BBB_CSW_PHASE_ERROR;
+    } else {
+        /* CSW length is correct */
+
+        /* check validity of the CSW Signature and CSWStatus */
+        if(BBB_CSW_SIGNATURE == msc->bbb.csw.field.dCSWSignature) {
+            /* check condition 1. dCSWSignature is equal to 53425355h */
+            if(msc->bbb.csw.field.dCSWTag == msc->bbb.cbw.field.dCBWTag) {
+                /* check condition 3. dCSWTag matches the dCBWTag from the corresponding CBW */
+                if(0U == msc->bbb.csw.field.bCSWStatus) {
+                    status = BBB_CSW_CMD_PASSED;
+                } else if(1U == msc->bbb.csw.field.bCSWStatus) {
+                    status = BBB_CSW_CMD_FAILED;
+                } else if(2U == msc->bbb.csw.field.bCSWStatus) {
+                    status = BBB_CSW_PHASE_ERROR;
+                } else {
+                    /* no operation */
+                }
+            }
+        } else {
+            /* if the CSW signature is not valid, we shall return the phase error to
+               upper layers for reset recovery */
+            status = BBB_CSW_PHASE_ERROR;
+        }
+    }
+
+    return status;
+}

+ 551 - 0
GD32F3x0/GD32F3x0_usbfs_library/host/class/msc/Source/usbh_msc_core.c

@@ -0,0 +1,551 @@
+/*!
+    \file    usbh_core.c
+    \brief   USB MSC(mass storage device) class driver
+
+    \version 2025-01-01, V2.5.0, firmware for GD32F3x0
+*/
+
+/*
+    Copyright (c) 2025, GigaDevice Semiconductor Inc.
+
+    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 of the copyright holder 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 HOLDER 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.
+*/
+
+#include "usbh_msc_core.h"
+#include "usbh_pipe.h"
+#include "usbh_transc.h"
+#include <string.h>
+
+/* local function prototypes ('static') */
+static void usbh_msc_itf_deinit(usbh_host *uhost);
+static usbh_status usbh_msc_itf_init(usbh_host *uhost);
+static usbh_status usbh_msc_req(usbh_host *uhost);
+static usbh_status usbh_msc_handle(usbh_host *uhost);
+static usbh_status usbh_msc_maxlun_get(usbh_host *uhost, uint8_t *maxlun);
+static usbh_status usbh_msc_rdwr_process(usbh_host *uhost, uint8_t lun);
+
+usbh_class usbh_msc = {
+    USB_CLASS_MSC,
+    usbh_msc_itf_init,
+    usbh_msc_itf_deinit,
+    usbh_msc_req,
+    usbh_msc_handle
+};
+
+/*!
+    \brief      get MSC logic unit information
+    \param[in]  uhost: pointer to USB host
+    \param[in]  lun: logic unit number
+    \param[in]  info: pointer to logic unit information
+    \param[out] none
+    \retval     operation status
+*/
+usbh_status usbh_msc_lun_info_get(usbh_host *uhost, uint8_t lun, msc_lun *info)
+{
+    usbh_msc_handler *msc = (usbh_msc_handler *)uhost->active_class->class_data;
+
+    if(HOST_CLASS_HANDLER == uhost->cur_state) {
+        memcpy(info, &msc->unit[lun], sizeof(msc_lun));
+
+        return USBH_OK;
+    } else {
+        return USBH_FAIL;
+    }
+}
+
+/*!
+    \brief      MSC read interface
+    \param[in]  uhost: pointer to USB host
+    \param[in]  lun: logic unit number
+    \param[in]  address: address to be read
+    \param[in]  pbuf: pointer to user buffer
+    \param[in]  length: length to be read
+    \param[out] none
+    \retval     operation status
+*/
+usbh_status usbh_msc_read(usbh_host *uhost, \
+                          uint8_t lun, \
+                          uint32_t address, \
+                          uint8_t *pbuf, \
+                          uint32_t length)
+{
+    uint32_t timeout = 0U;
+    usbh_msc_handler *msc = (usbh_msc_handler *)uhost->active_class->class_data;
+    usb_core_driver *udev = (usb_core_driver *)uhost->data;
+
+    if((0U == udev->host.connect_status) || \
+         (HOST_CLASS_HANDLER != uhost->cur_state) || \
+            (MSC_IDLE != msc->unit[lun].state)) {
+        return USBH_FAIL;
+    }
+
+    msc->state = MSC_READ;
+    msc->unit[lun].state = MSC_READ;
+    msc->rw_lun = lun;
+
+    usbh_msc_read10(uhost, lun, pbuf, address, length);
+
+    timeout = uhost->control.timer;
+
+    while(USBH_BUSY == usbh_msc_rdwr_process(uhost, lun)) {
+        if(((uhost->control.timer - timeout) > (1000U * length)) || (0U == udev->host.connect_status)) {
+            msc->state = MSC_IDLE;
+            return USBH_FAIL;
+        }
+    }
+
+    msc->state = MSC_IDLE;
+
+    return USBH_OK;
+}
+
+/*!
+    \brief      MSC write interface
+    \param[in]  uhost: pointer to USB host
+    \param[in]  lun: logic unit number
+    \param[in]  address: address to be written
+    \param[in]  pbuf: pointer to user buffer
+    \param[in]  length: length to be written
+    \param[out] none
+    \retval     operation status
+*/
+usbh_status usbh_msc_write(usbh_host *uhost, \
+                           uint8_t lun, \
+                           uint32_t address, \
+                           uint8_t *pbuf, \
+                           uint32_t length)
+{
+    uint32_t timeout = 0U;
+    usb_core_driver *udev = (usb_core_driver *)uhost->data;
+    usbh_msc_handler *msc = (usbh_msc_handler *)uhost->active_class->class_data;
+
+    if((0U == udev->host.connect_status) || \
+         (HOST_CLASS_HANDLER != uhost->cur_state) || \
+            (MSC_IDLE != msc->unit[lun].state)) {
+        return USBH_FAIL;
+    }
+
+    msc->state = MSC_WRITE;
+    msc->unit[lun].state = MSC_WRITE;
+    msc->rw_lun = lun;
+
+    usbh_msc_write10(uhost, lun, pbuf, address, length);
+
+    timeout = uhost->control.timer;
+
+    while(USBH_BUSY == usbh_msc_rdwr_process(uhost, lun)) {
+        if(((uhost->control.timer - timeout) > (1000U * length)) || (0U == udev->host.connect_status)) {
+            msc->state = MSC_IDLE;
+            return USBH_FAIL;
+        }
+    }
+
+    msc->state = MSC_IDLE;
+
+    return USBH_OK;
+}
+
+/*!
+    \brief      de-initialize interface by freeing host channels allocated to interface
+    \param[in]  uhost: pointer to USB host
+    \param[out] none
+    \retval     operation status
+*/
+static void usbh_msc_itf_deinit(usbh_host *uhost)
+{
+    usbh_msc_handler *msc = (usbh_msc_handler *)uhost->active_class->class_data;
+
+    if(msc->pipe_out) {
+        usb_pipe_halt(uhost->data, msc->pipe_out);
+        usbh_pipe_free(uhost->data, msc->pipe_out);
+
+        msc->pipe_out = 0U;
+    }
+
+    if(msc->pipe_in) {
+        usb_pipe_halt(uhost->data, msc->pipe_in);
+        usbh_pipe_free(uhost->data, msc->pipe_in);
+
+        msc->pipe_in = 0U;
+    }
+}
+
+/*!
+    \brief      interface initialization for MSC class
+    \param[in]  uhost: pointer to USB host
+    \param[out] none
+    \retval     operation status
+*/
+static usbh_status usbh_msc_itf_init(usbh_host *uhost)
+{
+    usbh_status status = USBH_OK;
+
+    uint8_t interface = usbh_interface_find(&uhost->dev_prop, MSC_CLASS, USB_MSC_SUBCLASS_SCSI, MSC_PROTOCOL);
+
+    if(0xFFU == interface) {
+        uhost->usr_cb->dev_not_supported();
+
+        status = USBH_FAIL;
+    } else {
+        static usbh_msc_handler msc_handler;
+
+        memset((void *)&msc_handler, 0U, sizeof(usbh_msc_handler));
+
+        uhost->active_class->class_data = (void *)&msc_handler;
+
+        usbh_interface_select(&uhost->dev_prop, interface);
+
+        usb_desc_ep *ep_desc = &uhost->dev_prop.cfg_desc_set.itf_desc_set[interface][0].ep_desc[0];
+
+        if(ep_desc->bEndpointAddress & 0x80U) {
+            msc_handler.ep_in = ep_desc->bEndpointAddress;
+            msc_handler.ep_size_in = ep_desc->wMaxPacketSize;
+        } else {
+            msc_handler.ep_out = ep_desc->bEndpointAddress;
+            msc_handler.ep_size_out = ep_desc->wMaxPacketSize;
+        }
+
+        ep_desc = &uhost->dev_prop.cfg_desc_set.itf_desc_set[interface][0].ep_desc[1];
+
+        if(ep_desc->bEndpointAddress & 0x80U) {
+            msc_handler.ep_in = ep_desc->bEndpointAddress;
+            msc_handler.ep_size_in = ep_desc->wMaxPacketSize;
+        } else {
+            msc_handler.ep_out = ep_desc->bEndpointAddress;
+            msc_handler.ep_size_out = ep_desc->wMaxPacketSize;
+        }
+
+        msc_handler.state = MSC_INIT;
+        msc_handler.error = MSC_OK;
+        msc_handler.req_state = MSC_REQ_IDLE;
+        msc_handler.pipe_out = usbh_pipe_allocate(uhost->data, msc_handler.ep_out);
+        msc_handler.pipe_in = usbh_pipe_allocate(uhost->data, msc_handler.ep_in);
+
+        usbh_msc_bbb_init(uhost);
+
+        /* open the new channels */
+        usbh_pipe_create(uhost->data, \
+                         &uhost->dev_prop, \
+                         msc_handler.pipe_out, \
+                         USB_EPTYPE_BULK, \
+                         msc_handler.ep_size_out);
+
+        usbh_pipe_create(uhost->data, \
+                         &uhost->dev_prop, \
+                         msc_handler.pipe_in, \
+                         USB_EPTYPE_BULK, \
+                         msc_handler.ep_size_in);
+
+        usbh_pipe_toggle_set(uhost->data, msc_handler.pipe_out, 0U);
+        usbh_pipe_toggle_set(uhost->data, msc_handler.pipe_in, 0U);
+    }
+
+    return status;
+}
+
+/*!
+    \brief      initialize the MSC state machine
+    \param[in]  uhost: pointer to USB host
+    \param[out] none
+    \retval     operation status
+*/
+static usbh_status usbh_msc_req(usbh_host *uhost)
+{
+    usbh_status status = USBH_BUSY;
+    usbh_msc_handler *msc = (usbh_msc_handler *)uhost->active_class->class_data;
+
+    switch(msc->req_state) {
+    case MSC_REQ_IDLE:
+    case MSC_REQ_GET_MAX_LUN:
+        /* issue Get_MaxLun request */
+        status = usbh_msc_maxlun_get(uhost, (uint8_t *)&msc->max_lun);
+
+        if(USBH_OK == status) {
+            msc->max_lun = ((uint8_t)msc->max_lun > MSC_MAX_SUPPORTED_LUN) ? MSC_MAX_SUPPORTED_LUN : (uint8_t)msc->max_lun + 1U;
+
+            for(uint8_t i = 0U; i < msc->max_lun; i++) {
+                msc->unit[i].prev_ready_state = USBH_FAIL;
+                msc->unit[i].state_changed = 0U;
+            }
+        } else {
+            if(USBH_NOT_SUPPORTED == status) {
+                msc->max_lun = 0U;
+                status = USBH_OK;
+            }
+        }
+        break;
+
+    case MSC_REQ_ERROR:
+        /* issue clearfeature request */
+        if(USBH_OK == usbh_clrfeature(uhost, 0x00U, uhost->control.pipe_out_num)) {
+            msc->req_state = msc->prev_req_state;
+        }
+        break;
+
+    default:
+        break;
+    }
+
+    return status;
+}
+
+/*!
+    \brief      MSC state machine handler
+    \param[in]  uhost: pointer to USB host
+    \param[out] none
+    \retval     operation status
+*/
+static usbh_status usbh_msc_handle(usbh_host *uhost)
+{
+    usbh_status status = USBH_BUSY;
+    uint8_t scsi_status = USBH_BUSY;
+    uint8_t ready_status = USBH_BUSY;
+    usbh_msc_handler *msc = (usbh_msc_handler *)uhost->active_class->class_data;
+
+    switch(msc->state) {
+    case MSC_INIT:
+        if(msc->cur_lun < msc->max_lun) {
+            msc->unit[msc->cur_lun].error = MSC_NOT_READY;
+
+            switch(msc->unit[msc->cur_lun].state) {
+            case MSC_INIT:
+                msc->unit[msc->cur_lun].state = MSC_READ_INQUIRY;
+                msc->timer = uhost->control.timer;
+                break;
+
+            case MSC_READ_INQUIRY:
+                scsi_status = usbh_msc_scsi_inquiry(uhost, msc->cur_lun, &msc->unit[msc->cur_lun].inquiry);
+
+                if(USBH_OK == scsi_status) {
+                    msc->unit[msc->cur_lun].state = MSC_TEST_UNIT_READY;
+                } else if(USBH_FAIL == scsi_status) {
+                    msc->unit[msc->cur_lun].state = MSC_REQUEST_SENSE;
+                } else {
+                    if(USBH_UNRECOVERED_ERROR == scsi_status) {
+                        msc->unit[msc->cur_lun].state = MSC_IDLE;
+                        msc->unit[msc->cur_lun].error = MSC_ERROR;
+                    }
+                }
+                break;
+
+            case MSC_TEST_UNIT_READY:
+                /* issue SCSI command TestUnitReady */
+                ready_status = usbh_msc_test_unitready(uhost, msc->cur_lun);
+
+                if(USBH_OK == ready_status) {
+                    if(USBH_OK != msc->unit[msc->cur_lun].prev_ready_state) {
+                        msc->unit[msc->cur_lun].state_changed = 1U;
+                    } else {
+                        msc->unit[msc->cur_lun].state_changed = 0U;
+                    }
+
+                    msc->unit[msc->cur_lun].state = MSC_READ_CAPACITY10;
+                    msc->unit[msc->cur_lun].error = MSC_OK;
+                    msc->unit[msc->cur_lun].prev_ready_state = USBH_OK;
+                } else if(USBH_FAIL == ready_status) {
+                    if(USBH_FAIL != msc->unit[msc->cur_lun].prev_ready_state) {
+                        msc->unit[msc->cur_lun].state_changed = 1U;
+                    } else {
+                        msc->unit[msc->cur_lun].state_changed = 0U;
+                    }
+
+                    msc->unit[msc->cur_lun].state = MSC_REQUEST_SENSE;
+                    msc->unit[msc->cur_lun].error = MSC_NOT_READY;
+                    msc->unit[msc->cur_lun].prev_ready_state = USBH_FAIL;
+                } else {
+                    if(USBH_UNRECOVERED_ERROR == ready_status) {
+                        msc->unit[msc->cur_lun].state = MSC_IDLE;
+                        msc->unit[msc->cur_lun].error = MSC_ERROR;
+                    }
+                }
+                break;
+
+            case MSC_READ_CAPACITY10:
+                /* issue READ_CAPACITY10 SCSI command */
+                scsi_status = usbh_msc_read_capacity10(uhost, msc->cur_lun, &msc->unit[msc->cur_lun].capacity);
+
+                if(USBH_OK == scsi_status) {
+                    if(1U == msc->unit[msc->cur_lun].state_changed) {
+                    }
+                    msc->unit[msc->cur_lun].state = MSC_IDLE;
+                    msc->unit[msc->cur_lun].error = MSC_OK;
+                    msc->cur_lun ++;
+                } else if(USBH_FAIL == scsi_status) {
+                    msc->unit[msc->cur_lun].state = MSC_REQUEST_SENSE;
+                } else {
+                    if(USBH_UNRECOVERED_ERROR == scsi_status) {
+                        msc->unit[msc->cur_lun].state = MSC_IDLE;
+                        msc->unit[msc->cur_lun].error = MSC_ERROR;
+                    }
+                }
+                break;
+
+            case MSC_REQUEST_SENSE:
+                /* issue RequestSense SCSI command for retrieving error code */
+                scsi_status = usbh_msc_request_sense(uhost, msc->cur_lun, &msc->unit[msc->cur_lun].sense);
+                if(USBH_OK == scsi_status) {
+                    if((UNIT_ATTENTION == msc->unit[msc->cur_lun].sense.SenseKey) || (NOT_READY == msc->unit[msc->cur_lun].sense.SenseKey)) {
+                        if((uhost->control.timer - msc->timer) < 10000U) {
+                            msc->unit[msc->cur_lun].state = MSC_TEST_UNIT_READY;
+                            break;
+                        }
+                    }
+
+                    msc->unit[msc->cur_lun].state = MSC_IDLE;
+                    msc->cur_lun++;
+                } else if(USBH_FAIL == scsi_status) {
+                    msc->unit[msc->cur_lun].state = MSC_UNRECOVERED_ERROR;
+                } else {
+                    if(MSC_UNRECOVERED_ERROR == scsi_status) {
+                        msc->unit[msc->cur_lun].state = MSC_IDLE;
+                        msc->unit[msc->cur_lun].error = MSC_ERROR;
+                    }
+                }
+                break;
+
+            case MSC_UNRECOVERED_ERROR:
+                msc->cur_lun++;
+                break;
+
+            default:
+                break;
+            }
+        } else {
+            msc->cur_lun = 0U;
+            msc->state = MSC_IDLE;
+        }
+        break;
+
+    case MSC_IDLE:
+        uhost->usr_cb->dev_user_app();
+        status = USBH_OK;
+        break;
+
+    default:
+        break;
+    }
+
+    return status;
+}
+
+/*!
+    \brief      get max lun of the mass storage device
+    \param[in]  uhost: pointer to USB host
+    \param[in]  maxlun: pointer to max lun
+    \param[out] none
+    \retval     operation status
+*/
+static usbh_status usbh_msc_maxlun_get(usbh_host *uhost, uint8_t *maxlun)
+{
+    usbh_status status = USBH_BUSY;
+
+    if(CTL_IDLE == uhost->control.ctl_state) {
+        uhost->control.setup.req = (usb_req) {
+            .bmRequestType = USB_TRX_IN | USB_REQTYPE_CLASS | USB_RECPTYPE_ITF,
+            .bRequest      = BBB_GET_MAX_LUN,
+            .wValue        = 0U,
+            .wIndex        = 0U,
+            .wLength       = 1U
+        };
+
+        usbh_ctlstate_config(uhost, maxlun, 1U);
+    }
+
+    status = usbh_ctl_handler(uhost);
+
+    return status;
+}
+
+/*!
+    \brief      get max lun of the mass storage device
+    \param[in]  uhost: pointer to USB host
+    \param[in]  lun: logic unit number
+    \param[out] none
+    \retval     operation status
+*/
+static usbh_status usbh_msc_rdwr_process(usbh_host *uhost, uint8_t lun)
+{
+    usbh_status error = USBH_BUSY;
+    usbh_status scsi_status = USBH_BUSY;
+    usbh_msc_handler *msc = (usbh_msc_handler *)uhost->active_class->class_data;
+
+    /* switch msc req state machine */
+    switch(msc->unit[lun].state) {
+    case MSC_READ:
+        scsi_status = usbh_msc_read10(uhost, lun,  NULL, 0U, 0U);
+
+        if(USBH_OK == scsi_status) {
+            msc->unit[lun].state = MSC_IDLE;
+            error = USBH_OK;
+        } else if(USBH_FAIL == scsi_status) {
+            msc->unit[lun].state = MSC_REQUEST_SENSE;
+        } else {
+            if(USBH_UNRECOVERED_ERROR == scsi_status) {
+                msc->unit[lun].state = MSC_UNRECOVERED_ERROR;
+                error = USBH_FAIL;
+            }
+        }
+        break;
+
+    case MSC_WRITE:
+        scsi_status = usbh_msc_write10(uhost, lun, NULL, 0U, 0U);
+
+        if(USBH_OK == scsi_status) {
+            msc->unit[lun].state = MSC_IDLE;
+            error = USBH_OK;
+        } else if(USBH_FAIL == scsi_status) {
+            msc->unit[lun].state = MSC_REQUEST_SENSE;
+        } else {
+            if(USBH_UNRECOVERED_ERROR == scsi_status) {
+                msc->unit[lun].state = MSC_UNRECOVERED_ERROR;
+                error = USBH_FAIL;
+            }
+        }
+        break;
+
+    case MSC_REQUEST_SENSE:
+        scsi_status = usbh_msc_request_sense(uhost, lun, &msc->unit[lun].sense);
+
+        if(USBH_OK == scsi_status) {
+            msc->unit[lun].state = MSC_IDLE;
+            msc->unit[lun].error = MSC_ERROR;
+
+            error = USBH_FAIL;
+        }
+
+        if(USBH_FAIL == scsi_status) {
+        } else {
+            if(USBH_UNRECOVERED_ERROR == scsi_status) {
+                msc->unit[lun].state = MSC_UNRECOVERED_ERROR;
+                error = USBH_FAIL;
+            }
+        }
+        break;
+
+    default:
+        break;
+    }
+
+    return error;
+}

+ 231 - 0
GD32F3x0/GD32F3x0_usbfs_library/host/class/msc/Source/usbh_msc_fatfs.c

@@ -0,0 +1,231 @@
+/*!
+    \file    usbh_msc_fatfs.c
+    \brief   USB MSC host FATFS related functions
+
+    \version 2025-01-01, V2.5.0, firmware for GD32F3x0
+*/
+
+/*
+    Copyright (c) 2025, GigaDevice Semiconductor Inc.
+
+    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 of the copyright holder 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 HOLDER 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.
+*/
+
+#include "diskio.h"
+#include "usbh_msc_core.h"
+
+static volatile DSTATUS state = STA_NOINIT; /* disk status */
+
+extern usbh_host usb_host;
+
+/*!
+    \brief      initialize the disk drive
+    \param[in]  drv: physical drive number (0)
+    \param[out] none
+    \retval     operation status
+*/
+DSTATUS disk_initialize(BYTE drv)
+{
+    usb_core_driver *udev = (usb_core_driver *)usb_host.data;
+
+    if(udev->host.connect_status) {
+        state &= ~STA_NOINIT;
+    }
+
+    return state;
+}
+
+/*!
+    \brief      get disk status
+    \param[in]  drv: physical drive number (0)
+    \param[out] none
+    \retval     operation status
+*/
+DSTATUS disk_status(BYTE drv)
+{
+    if(drv) {
+        return STA_NOINIT; /* supports only single drive */
+    }
+
+    return state;
+}
+
+/*!
+    \brief      read sectors
+    \param[in]  drv: physical drive number (0)
+    \param[in]  buff: pointer to the data buffer to store read data
+    \param[in]  sector: start sector number (LBA)
+    \param[in]  count: sector count (1..255)
+    \param[out] none
+    \retval     operation status
+*/
+DRESULT disk_read(BYTE drv, BYTE *buff, DWORD sector, UINT count)
+{
+    BYTE status = USBH_OK;
+    usb_core_driver *udev = (usb_core_driver *)usb_host.data;
+
+    if(drv || (!count)) {
+        return RES_PARERR;
+    }
+
+    if(state & STA_NOINIT) {
+        return RES_NOTRDY;
+    }
+
+    if(udev->host.connect_status) {
+        do {
+            status = usbh_msc_read(&usb_host, drv, sector, buff, count);
+
+            if(!udev->host.connect_status) {
+                return RES_ERROR;
+            }
+        } while(USBH_BUSY == status);
+    }
+
+    if(USBH_OK == status) {
+        return RES_OK;
+    }
+
+    return RES_ERROR;
+}
+
+#if _READONLY == 0U
+
+/*!
+    \brief      write sectors
+    \param[in]  drv: physical drive number (0)
+    \param[in]  buff: pointer to the data buffer to store read data
+    \param[in]  sector: start sector number (LBA)
+    \param[in]  count: sector count (1..255)
+    \param[out] none
+    \retval     operation status
+*/
+DRESULT disk_write(BYTE drv, const BYTE *buff, DWORD sector, UINT count)
+{
+    BYTE status = USBH_OK;
+    usb_core_driver *udev = (usb_core_driver *)usb_host.data;
+
+    if((!count) || drv) {
+        return RES_PARERR;
+    }
+
+    if(state & STA_NOINIT) {
+        return RES_NOTRDY;
+    }
+
+    if(state & STA_PROTECT) {
+        return RES_WRPRT;
+    }
+
+    if(udev->host.connect_status) {
+        do {
+            status = usbh_msc_write(&usb_host, drv, sector, (BYTE*)buff, count);
+
+            if(!udev->host.connect_status) {
+                return RES_ERROR;
+            }
+        } while(USBH_BUSY == status);
+    }
+
+    if(USBH_OK == status) {
+        return RES_OK;
+    }
+
+    return RES_ERROR;
+}
+
+#endif /* _READONLY == 0 */
+
+/*!
+    \brief      I/O control function
+    \param[in]  drv: physical drive number (0)
+    \param[in]  ctrl: control code
+    \param[in]  buff: pointer to the data buffer to store read data
+    \param[out] none
+    \retval     operation status
+*/
+DRESULT disk_ioctl(BYTE drv, BYTE ctrl, void *buff)
+{
+    DRESULT res = RES_OK;
+    msc_lun info;
+
+    if(drv) {
+        return RES_PARERR;
+    }
+
+    res = RES_ERROR;
+
+    if(state & STA_NOINIT) {
+        return RES_NOTRDY;
+    }
+
+    switch(ctrl) {
+    /* make sure that no pending write process */
+    case CTRL_SYNC:
+        res = RES_OK;
+        break;
+
+    /* get number of sectors on the disk (dword) */
+    case GET_SECTOR_COUNT:
+        if(USBH_OK == usbh_msc_lun_info_get(&usb_host, drv, &info)) {
+            *(DWORD*)buff = (DWORD)info.capacity.block_nbr;
+            res = RES_OK;
+        }
+        break;
+
+    /* get r/w sector size (word) */
+    case GET_SECTOR_SIZE:
+        if(USBH_OK == usbh_msc_lun_info_get(&usb_host, drv, &info)) {
+            *(WORD*)buff = (DWORD)info.capacity.block_size;
+            res = RES_OK;
+        }
+        break;
+
+    /* get erase block size in unit of sector (dword) */
+    case GET_BLOCK_SIZE:
+        *(DWORD *)buff = 512U;
+        break;
+
+    default:
+        res = RES_PARERR;
+        break;
+    }
+
+    return res;
+}
+
+/*!
+    \brief      get fat time
+    \param[in]  none
+    \param[out] none
+    \retval     time value
+*/
+DWORD get_fattime(void) {
+    return ((DWORD)(2019U - 1980U) << 25)      /* year 2019 */
+           | ((DWORD)1U << 21)                 /* month 1 */
+           | ((DWORD)1U << 16)                 /* day 1 */
+           | ((DWORD)0U << 11)                 /* hour 0 */
+           | ((DWORD)0U << 5)                  /* min 0 */
+           | ((DWORD)0U >> 1);                 /* sec 0 */
+}

+ 397 - 0
GD32F3x0/GD32F3x0_usbfs_library/host/class/msc/Source/usbh_msc_scsi.c

@@ -0,0 +1,397 @@
+/*!
+    \file    usbh_msc_scsi.c
+    \brief   USB MSC SCSI commands implementing
+
+    \version 2025-01-01, V2.5.0, firmware for GD32F3x0
+*/
+
+/*
+    Copyright (c) 2025, GigaDevice Semiconductor Inc.
+
+    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 of the copyright holder 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 HOLDER 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.
+*/
+
+#include "usbh_msc_core.h"
+#include "usbh_msc_scsi.h"
+#include <string.h>
+
+/*!
+    \brief      send 'Inquiry' command to the device
+    \param[in]  uhost: pointer to USB host handler
+    \param[in]  lun: logic unit number
+    \param[in]  inquiry: pointer to the inquiry structure
+    \param[out] none
+    \retval     operation status
+*/
+usbh_status usbh_msc_scsi_inquiry(usbh_host *uhost, uint8_t lun, scsi_std_inquiry_data *inquiry)
+{
+    usbh_status error = USBH_FAIL;
+    usbh_msc_handler *msc = (usbh_msc_handler *)uhost->active_class->class_data;
+
+    switch(msc->bbb.cmd_state) {
+    case BBB_CMD_SEND:
+        /* prepare the cbw and relevant field*/
+        msc->bbb.cbw.field.dCBWDataTransferLength = STANDARD_INQUIRY_DATA_LEN;
+        msc->bbb.cbw.field.bmCBWFlags = USB_TRX_IN;
+        msc->bbb.cbw.field.bCBWCBLength = CBW_LENGTH;
+
+        memset(msc->bbb.cbw.field.CBWCB, 0U, CBW_LENGTH);
+
+        msc->bbb.cbw.field.CBWCB[0] = SCSI_INQUIRY;
+        msc->bbb.cbw.field.CBWCB[1] = (lun << 5);
+        msc->bbb.cbw.field.CBWCB[4] = 0x24U;
+
+        msc->bbb.state = BBB_SEND_CBW;
+        msc->bbb.cmd_state = BBB_CMD_WAIT;
+        msc->bbb.pbuf = (uint8_t *)(void *)msc->bbb.data;
+        error = USBH_BUSY;
+        break;
+
+    case BBB_CMD_WAIT:
+        error = usbh_msc_bbb_process(uhost, lun);
+
+        if(USBH_OK == error) {
+            memset(inquiry, 0U, sizeof(scsi_std_inquiry_data));
+
+            /* assign inquiry data */
+            inquiry->device_type = msc->bbb.pbuf[0] & 0x1FU;
+            inquiry->peripheral_qualifier = msc->bbb.pbuf[0] >> 5;
+
+            if(0x80U == ((uint32_t)msc->bbb.pbuf[1] & 0x80U)) {
+                inquiry->removable_media = 1U;
+            } else {
+                inquiry->removable_media = 0U;
+            }
+
+            memcpy(inquiry->vendor_id, &msc->bbb.pbuf[8], 8U);
+            memcpy(inquiry->product_id, &msc->bbb.pbuf[16], 16U);
+            memcpy(inquiry->revision_id, &msc->bbb.pbuf[32], 4U);
+        }
+        break;
+
+    default:
+        break;
+    }
+
+    return error;
+}
+
+/*!
+    \brief      send 'test unit ready' command to the device
+    \param[in]  uhost: pointer to USB host handler
+    \param[in]  lun: logic unit number
+    \param[out] none
+    \retval     operation status
+*/
+usbh_status usbh_msc_test_unitready(usbh_host *uhost, uint8_t lun)
+{
+    usbh_status status = USBH_FAIL;
+    usbh_msc_handler *msc = (usbh_msc_handler *)uhost->active_class->class_data;
+
+    switch(msc->bbb.cmd_state) {
+    case BBB_CMD_SEND:
+        /* prepare the CBW and relevant field */
+        msc->bbb.cbw.field.dCBWDataTransferLength = CBW_LENGTH_TEST_UNIT_READY;
+        msc->bbb.cbw.field.bmCBWFlags = USB_TRX_OUT;
+        msc->bbb.cbw.field.bCBWCBLength = CBW_LENGTH;
+
+        memset(msc->bbb.cbw.field.CBWCB, 0U, CBW_CB_LENGTH);
+
+        msc->bbb.cbw.field.CBWCB[0] = SCSI_TEST_UNIT_READY;
+        msc->bbb.state = BBB_SEND_CBW;
+        msc->bbb.cmd_state = BBB_CMD_WAIT;
+
+        status = USBH_BUSY;
+        break;
+
+    case BBB_CMD_WAIT:
+        status = usbh_msc_bbb_process(uhost, lun);
+        break;
+
+    default:
+        break;
+    }
+
+    return status;
+}
+
+/*!
+    \brief      send the read capacity command to the device
+    \param[in]  uhost: pointer to USB host handler
+    \param[in]  lun: logic unit number
+    \param[in]  capacity: pointer to SCSI capacity
+    \param[out] none
+    \retval     operation status
+*/
+usbh_status usbh_msc_read_capacity10(usbh_host *uhost, uint8_t lun, scsi_capacity *capacity)
+{
+    usbh_status status = USBH_FAIL;
+    usbh_msc_handler *msc = (usbh_msc_handler *)uhost->active_class->class_data;
+
+    switch(msc->bbb.cmd_state) {
+    case BBB_CMD_SEND:
+        /* prepare the CBW and relevant field */
+        msc->bbb.cbw.field.dCBWDataTransferLength = READ_CAPACITY10_DATA_LEN;
+        msc->bbb.cbw.field.bmCBWFlags = USB_TRX_IN;
+        msc->bbb.cbw.field.bCBWCBLength = CBW_LENGTH;
+
+        memset(msc->bbb.cbw.field.CBWCB, 0U, CBW_CB_LENGTH);
+
+        msc->bbb.cbw.field.CBWCB[0] = SCSI_READ_CAPACITY10;
+        msc->bbb.state = BBB_SEND_CBW;
+        msc->bbb.cmd_state = BBB_CMD_WAIT;
+        msc->bbb.pbuf = (uint8_t *)(void *)msc->bbb.data;
+
+        status = USBH_BUSY;
+        break;
+
+    case BBB_CMD_WAIT:
+        status = usbh_msc_bbb_process(uhost, lun);
+
+        if(USBH_OK == status) {
+            capacity->block_nbr = msc->bbb.pbuf[3] | \
+                                  ((uint32_t)msc->bbb.pbuf[2] << 8) | \
+                                  ((uint32_t)msc->bbb.pbuf[1] << 16) | \
+                                  ((uint32_t)msc->bbb.pbuf[0] << 24);
+
+            capacity->block_size = (uint16_t)(msc->bbb.pbuf[7] | ((uint32_t)msc->bbb.pbuf[6] << 8));
+        }
+        break;
+
+    default:
+        break;
+    }
+
+    return status;
+}
+
+/*!
+    \brief      send the mode sense6 command to the device
+    \param[in]  uhost: pointer to USB host handler
+    \param[in]  lun: logic unit number
+    \param[out] none
+    \retval     operation status
+*/
+usbh_status usbh_msc_mode_sense6(usbh_host *uhost, uint8_t lun)
+{
+    usbh_status status = USBH_FAIL;
+    usbh_msc_handler *msc = (usbh_msc_handler *)uhost->active_class->class_data;
+
+
+    switch(msc->bbb.cmd_state) {
+    case BBB_CMD_SEND:
+        /* prepare the CBW and relevant field */
+        msc->bbb.cbw.field.dCBWDataTransferLength = XFER_LEN_MODE_SENSE6;
+        msc->bbb.cbw.field.bmCBWFlags = USB_TRX_IN;
+        msc->bbb.cbw.field.bCBWCBLength = CBW_LENGTH;
+
+        memset(msc->bbb.cbw.field.CBWCB, 0U, CBW_CB_LENGTH);
+
+        msc->bbb.cbw.field.CBWCB[0] = SCSI_MODE_SENSE6;
+        msc->bbb.cbw.field.CBWCB[2] = MODE_SENSE_PAGE_CONTROL_FIELD | MODE_SENSE_PAGE_CODE;
+        msc->bbb.cbw.field.CBWCB[4] = XFER_LEN_MODE_SENSE6;
+        msc->bbb.state = BBB_SEND_CBW;
+        msc->bbb.cmd_state = BBB_CMD_WAIT;
+        msc->bbb.pbuf = (uint8_t *)(void *)msc->bbb.data;
+
+        status = USBH_BUSY;
+        break;
+
+    case BBB_CMD_WAIT:
+        status = usbh_msc_bbb_process(uhost, lun);
+
+        if(USBH_OK == status) {
+            if(msc->bbb.data[2] & MASK_MODE_SENSE_WRITE_PROTECT) {
+
+            } else {
+
+            }
+        }
+        break;
+
+    default:
+        break;
+    }
+
+
+    return status;
+}
+
+/*!
+    \brief      send the request sense command to the device
+    \param[in]  uhost: pointer to USB host handler
+    \param[in]  lun: logic unit number
+    \param[in]  sense_data: pointer to sense data
+    \param[out] none
+    \retval     operation status
+*/
+usbh_status usbh_msc_request_sense(usbh_host *uhost, uint8_t lun, msc_scsi_sense *sense_data)
+{
+    usbh_status status = USBH_FAIL;
+    usbh_msc_handler *msc = (usbh_msc_handler *)uhost->active_class->class_data;
+
+    switch(msc->bbb.cmd_state) {
+    case BBB_CMD_SEND:
+        /* prepare the CBW and relevant field */
+        msc->bbb.cbw.field.dCBWDataTransferLength = ALLOCATION_LENGTH_REQUEST_SENSE;
+        msc->bbb.cbw.field.bmCBWFlags = USB_TRX_IN;
+        msc->bbb.cbw.field.bCBWCBLength = CBW_LENGTH;
+
+        memset(msc->bbb.cbw.field.CBWCB, 0U, CBW_CB_LENGTH);
+
+        msc->bbb.cbw.field.CBWCB[0] = SCSI_REQUEST_SENSE;
+        msc->bbb.cbw.field.CBWCB[1] = (lun << 5);
+        msc->bbb.cbw.field.CBWCB[4] = ALLOCATION_LENGTH_REQUEST_SENSE;
+
+        msc->bbb.state = BBB_SEND_CBW;
+        msc->bbb.cmd_state = BBB_CMD_WAIT;
+        msc->bbb.pbuf = (uint8_t *)(void *)msc->bbb.data;
+
+        status = USBH_BUSY;
+        break;
+
+    case BBB_CMD_WAIT:
+        status = usbh_msc_bbb_process(uhost, lun);
+
+        if(USBH_OK == status) {
+            /* get sense data */
+            sense_data->SenseKey = msc->bbb.pbuf[2] & 0x0FU;
+            sense_data->ASC = msc->bbb.pbuf[12];
+            sense_data->ASCQ = msc->bbb.pbuf[13];
+        }
+        break;
+
+    default:
+        break;
+    }
+
+    return status;
+}
+
+/*!
+    \brief      send the write10 command to the device
+    \param[in]  uhost: pointer to USB host handler
+    \param[in]  lun: logic unit number
+    \param[in]  data_buf: data buffer contains the data to write
+    \param[in]  addr: address to which the data will be written
+    \param[in]  sector_num: number of sector to be written
+    \param[out] none
+    \retval     operation status
+*/
+usbh_status usbh_msc_write10(usbh_host *uhost, uint8_t lun, uint8_t *data_buf, uint32_t addr, uint32_t sector_num)
+{
+    usbh_status status = USBH_FAIL;
+    usbh_msc_handler *msc = (usbh_msc_handler *)uhost->active_class->class_data;
+
+    switch(msc->bbb.cmd_state) {
+    case BBB_CMD_SEND:
+        msc->bbb.cbw.field.dCBWDataTransferLength = sector_num * msc->unit[lun].capacity.block_size;
+        msc->bbb.cbw.field.bmCBWFlags = USB_TRX_OUT;
+        msc->bbb.cbw.field.bCBWCBLength = CBW_LENGTH;
+
+        memset(msc->bbb.cbw.field.CBWCB, 0U, CBW_CB_LENGTH);
+
+        msc->bbb.cbw.field.CBWCB[0] = SCSI_WRITE10;
+
+        /* logical block address */
+        msc->bbb.cbw.field.CBWCB[2] = (((uint8_t *)&addr)[3]);
+        msc->bbb.cbw.field.CBWCB[3] = (((uint8_t *)&addr)[2]);
+        msc->bbb.cbw.field.CBWCB[4] = (((uint8_t *)&addr)[1]);
+        msc->bbb.cbw.field.CBWCB[5] = (((uint8_t *)&addr)[0]);
+
+        /* transfer length */
+        msc->bbb.cbw.field.CBWCB[7] = (((uint8_t *)&sector_num)[1]);
+        msc->bbb.cbw.field.CBWCB[8] = (((uint8_t *)&sector_num)[0]);
+
+        msc->bbb.state = BBB_SEND_CBW;
+        msc->bbb.cmd_state = BBB_CMD_WAIT;
+        msc->bbb.pbuf = data_buf;
+
+        status = USBH_BUSY;
+        break;
+
+    case BBB_CMD_WAIT:
+        status = usbh_msc_bbb_process(uhost, lun);
+        break;
+
+    default:
+        break;
+    }
+
+    return status;
+}
+
+/*!
+    \brief      send the read10 command to the device
+    \param[in]  uhost: pointer to USB host handler
+    \param[in]  lun: logic unit number
+    \param[in]  data_buf: data buffer contains the data to write
+    \param[in]  addr: address to which the data will be read
+    \param[in]  sector_num: number of sector to be read
+    \param[out] none
+    \retval     operation status
+*/
+usbh_status usbh_msc_read10(usbh_host *uhost, uint8_t lun, uint8_t *data_buf, uint32_t addr, uint32_t sector_num)
+{
+    usbh_status status = USBH_FAIL;
+    usbh_msc_handler *msc = (usbh_msc_handler *)uhost->active_class->class_data;
+
+    switch(msc->bbb.cmd_state) {
+    case BBB_CMD_SEND:
+        /* prepare the CBW and relevant field */
+        msc->bbb.cbw.field.dCBWDataTransferLength = sector_num * msc->unit[lun].capacity.block_size;
+        msc->bbb.cbw.field.bmCBWFlags = USB_TRX_IN;
+        msc->bbb.cbw.field.bCBWCBLength = CBW_LENGTH;
+
+        memset(msc->bbb.cbw.field.CBWCB, 0U, CBW_CB_LENGTH);
+
+        msc->bbb.cbw.field.CBWCB[0] = SCSI_READ10;
+
+        /* logical block address */
+        msc->bbb.cbw.field.CBWCB[2] = (((uint8_t *)&addr)[3]);
+        msc->bbb.cbw.field.CBWCB[3] = (((uint8_t *)&addr)[2]);
+        msc->bbb.cbw.field.CBWCB[4] = (((uint8_t *)&addr)[1]);
+        msc->bbb.cbw.field.CBWCB[5] = (((uint8_t *)&addr)[0]);
+
+        /* transfer length */
+        msc->bbb.cbw.field.CBWCB[7] = (((uint8_t *)&sector_num)[1]);
+        msc->bbb.cbw.field.CBWCB[8] = (((uint8_t *)&sector_num)[0]);
+
+        msc->bbb.state = BBB_SEND_CBW;
+        msc->bbb.cmd_state = BBB_CMD_WAIT;
+        msc->bbb.pbuf = data_buf;
+
+        status = USBH_BUSY;
+        break;
+
+    case BBB_CMD_WAIT:
+        status = usbh_msc_bbb_process(uhost, lun);
+        break;
+
+    default:
+        break;
+    }
+
+    return status;
+}

برخی فایل ها در این مقایسه diff نمایش داده نمی شوند زیرا تعداد فایل ها بسیار زیاد است