فهرست منبع

Merge pull request #3694 from nuclei-community/dev_nuclei_rvstar_pr_new

bsp/nuclei: Add more drivers support for gd32vf103_rvstar board
Bernard Xiong 4 سال پیش
والد
کامیت
fa19533a3d
32فایلهای تغییر یافته به همراه2287 افزوده شده و 87 حذف شده
  1. 16 0
      bsp/nuclei/README.md
  2. 24 20
      bsp/nuclei/gd32vf103_rvstar/.config
  3. 129 41
      bsp/nuclei/gd32vf103_rvstar/README.md
  4. 7 2
      bsp/nuclei/gd32vf103_rvstar/SConstruct
  5. 102 0
      bsp/nuclei/gd32vf103_rvstar/board/Kconfig
  6. 94 0
      bsp/nuclei/gd32vf103_rvstar/board/board.c
  7. BIN
      bsp/nuclei/gd32vf103_rvstar/doc/images/config_openocd_cfg.png
  8. BIN
      bsp/nuclei/gd32vf103_rvstar/doc/images/create_c_project.png
  9. BIN
      bsp/nuclei/gd32vf103_rvstar/doc/images/create_gdb_cfg.png
  10. BIN
      bsp/nuclei/gd32vf103_rvstar/doc/images/link_rtthread_code.png
  11. BIN
      bsp/nuclei/gd32vf103_rvstar/doc/images/start_debug_in_ide.png
  12. 8 10
      bsp/nuclei/gd32vf103_rvstar/rtconfig.h
  13. 5 5
      bsp/nuclei/gd32vf103_rvstar/rtconfig.py
  14. 22 0
      bsp/nuclei/libraries/gd32vf103/HAL_Drivers/SConscript
  15. 137 0
      bsp/nuclei/libraries/gd32vf103/HAL_Drivers/drv_adc.c
  16. 32 0
      bsp/nuclei/libraries/gd32vf103/HAL_Drivers/drv_adc.h
  17. 12 2
      bsp/nuclei/libraries/gd32vf103/HAL_Drivers/drv_gpio.c
  18. 315 0
      bsp/nuclei/libraries/gd32vf103/HAL_Drivers/drv_hwtimer.c
  19. 33 0
      bsp/nuclei/libraries/gd32vf103/HAL_Drivers/drv_hwtimer.h
  20. 228 0
      bsp/nuclei/libraries/gd32vf103/HAL_Drivers/drv_i2c.c
  21. 33 0
      bsp/nuclei/libraries/gd32vf103/HAL_Drivers/drv_i2c.h
  22. 352 0
      bsp/nuclei/libraries/gd32vf103/HAL_Drivers/drv_pwm.c
  23. 34 0
      bsp/nuclei/libraries/gd32vf103/HAL_Drivers/drv_pwm.h
  24. 160 0
      bsp/nuclei/libraries/gd32vf103/HAL_Drivers/drv_rtc.c
  25. 19 0
      bsp/nuclei/libraries/gd32vf103/HAL_Drivers/drv_rtc.h
  26. 287 0
      bsp/nuclei/libraries/gd32vf103/HAL_Drivers/drv_spi.c
  27. 40 0
      bsp/nuclei/libraries/gd32vf103/HAL_Drivers/drv_spi.h
  28. 20 4
      bsp/nuclei/libraries/gd32vf103/HAL_Drivers/drv_usart.c
  29. 1 1
      bsp/nuclei/libraries/gd32vf103/HAL_Drivers/drv_usart.h
  30. 156 0
      bsp/nuclei/libraries/gd32vf103/HAL_Drivers/drv_wdt.c
  31. 20 0
      bsp/nuclei/libraries/gd32vf103/HAL_Drivers/drv_wdt.h
  32. 1 2
      bsp/nuclei/tools/sdk_dist.py

+ 16 - 0
bsp/nuclei/README.md

@@ -0,0 +1,16 @@
+# Nuclei RISC-V Processor Support Package
+
+This directory provided support for [Nuclei RISC-V Processor](https://nucleisys.com/) based board, currently
+we mainly provided the following support package.
+
+| **BSP**                              | **Development Board Name**                                                                                                  |
+| :----------------------------------- | :-------------------------------------------------------------------------------------------------------------------------- |
+| [gd32vf103_rvstar](gd32vf103_rvstar) | [Nuclei RV-STAR Arduino Compatible Development Board](https://www.riscv-mcu.com/quickstart-quickstart-index-u-RV_STAR.html) |
+
+**If you want to learn more about Nuclei Processors, please click the following links:**
+
+* [Professional RISC-V IPs](https://nucleisys.com/product.php)
+* [Professional Nuclei Processor Development Boards](https://nucleisys.com/developboard.php)
+* [Comprehensive Documents and Development Tools](https://nucleisys.com/download.php)
+* [Active RISC-V IP and MCU Community](https://www.rvmcu.com/)
+* [Professional University Program](https://nucleisys.com/campus.php)

+ 24 - 20
bsp/nuclei/gd32vf103_rvstar/.config

@@ -78,7 +78,7 @@ CONFIG_ARCH_RISCV32=y
 #
 CONFIG_RT_USING_COMPONENTS_INIT=y
 CONFIG_RT_USING_USER_MAIN=y
-CONFIG_RT_MAIN_THREAD_STACK_SIZE=2048
+CONFIG_RT_MAIN_THREAD_STACK_SIZE=1024
 CONFIG_RT_MAIN_THREAD_PRIORITY=10
 
 #
@@ -97,7 +97,7 @@ CONFIG_FINSH_USING_SYMTAB=y
 CONFIG_FINSH_USING_DESCRIPTION=y
 # CONFIG_FINSH_ECHO_DISABLE_DEFAULT is not set
 CONFIG_FINSH_THREAD_PRIORITY=20
-CONFIG_FINSH_THREAD_STACK_SIZE=4096
+CONFIG_FINSH_THREAD_STACK_SIZE=2048
 CONFIG_FINSH_CMD_SIZE=80
 # CONFIG_FINSH_USING_AUTH is not set
 CONFIG_FINSH_USING_MSH=y
@@ -108,27 +108,18 @@ CONFIG_FINSH_ARG_MAX=10
 #
 # Device virtual file system
 #
-CONFIG_RT_USING_DFS=y
-CONFIG_DFS_USING_WORKDIR=y
-CONFIG_DFS_FILESYSTEMS_MAX=2
-CONFIG_DFS_FILESYSTEM_TYPES_MAX=2
-CONFIG_DFS_FD_MAX=16
-# CONFIG_RT_USING_DFS_MNTTABLE is not set
-# CONFIG_RT_USING_DFS_ELMFAT is not set
-CONFIG_RT_USING_DFS_DEVFS=y
-# CONFIG_RT_USING_DFS_ROMFS is not set
-# CONFIG_RT_USING_DFS_RAMFS is not set
-# CONFIG_RT_USING_DFS_UFFS is not set
-# CONFIG_RT_USING_DFS_JFFS2 is not set
+# CONFIG_RT_USING_DFS is not set
 
 #
 # Device Drivers
 #
 CONFIG_RT_USING_DEVICE_IPC=y
 CONFIG_RT_PIPE_BUFSZ=512
-# CONFIG_RT_USING_SYSTEM_WORKQUEUE is not set
+CONFIG_RT_USING_SYSTEM_WORKQUEUE=y
+CONFIG_RT_SYSTEM_WORKQUEUE_STACKSIZE=2048
+CONFIG_RT_SYSTEM_WORKQUEUE_PRIORITY=23
 CONFIG_RT_USING_SERIAL=y
-CONFIG_RT_SERIAL_USING_DMA=y
+# CONFIG_RT_SERIAL_USING_DMA is not set
 CONFIG_RT_SERIAL_RB_BUFSZ=64
 # CONFIG_RT_USING_CAN is not set
 # CONFIG_RT_USING_HWTIMER is not set
@@ -163,10 +154,6 @@ CONFIG_RT_USING_PIN=y
 #
 CONFIG_RT_USING_LIBC=y
 # CONFIG_RT_USING_PTHREADS is not set
-CONFIG_RT_USING_POSIX=y
-# CONFIG_RT_USING_POSIX_MMAP is not set
-# CONFIG_RT_USING_POSIX_TERMIOS is not set
-# CONFIG_RT_USING_POSIX_AIO is not set
 # CONFIG_RT_USING_MODULE is not set
 
 #
@@ -218,6 +205,7 @@ CONFIG_RT_USING_POSIX=y
 # CONFIG_PKG_USING_MONGOOSE is not set
 # CONFIG_PKG_USING_MYMQTT is not set
 # CONFIG_PKG_USING_KAWAII_MQTT is not set
+# CONFIG_PKG_USING_BC28_MQTT is not set
 # CONFIG_PKG_USING_WEBTERMINAL is not set
 # CONFIG_PKG_USING_CJSON is not set
 # CONFIG_PKG_USING_JSMN is not set
@@ -244,6 +232,7 @@ CONFIG_RT_USING_POSIX=y
 # CONFIG_PKG_USING_COAP is not set
 # CONFIG_PKG_USING_NOPOLL is not set
 # CONFIG_PKG_USING_NETUTILS is not set
+# CONFIG_PKG_USING_CMUX is not set
 # CONFIG_PKG_USING_PPP_DEVICE is not set
 # CONFIG_PKG_USING_AT_DEVICE is not set
 # CONFIG_PKG_USING_ATSRV_SOCKET is not set
@@ -320,6 +309,7 @@ CONFIG_RT_USING_POSIX=y
 # CONFIG_PKG_USING_CHINESE_FONT_LIBRARY is not set
 # CONFIG_PKG_USING_LUNAR_CALENDAR is not set
 # CONFIG_PKG_USING_BS8116A is not set
+# CONFIG_PKG_USING_URLENCODE is not set
 
 #
 # system packages
@@ -330,6 +320,7 @@ CONFIG_RT_USING_POSIX=y
 # CONFIG_PKG_USING_LWEXT4 is not set
 # CONFIG_PKG_USING_PARTITION is not set
 # CONFIG_PKG_USING_FAL is not set
+# CONFIG_PKG_USING_FLASHDB is not set
 # CONFIG_PKG_USING_SQLITE is not set
 # CONFIG_PKG_USING_RTI is not set
 # CONFIG_PKG_USING_LITTLEVGL2RTT is not set
@@ -361,6 +352,7 @@ CONFIG_RT_USING_POSIX=y
 # CONFIG_PKG_USING_LITTLED is not set
 # CONFIG_PKG_USING_LKDGUI is not set
 # CONFIG_PKG_USING_NRF5X_SDK is not set
+# CONFIG_PKG_USING_NRFX is not set
 # CONFIG_PKG_USING_WM_LIBRARIES is not set
 # CONFIG_PKG_USING_KENDRYTE_SDK is not set
 # CONFIG_PKG_USING_INFRARED is not set
@@ -386,10 +378,15 @@ CONFIG_RT_USING_POSIX=y
 # CONFIG_PKG_USING_EASYBLINK is not set
 # CONFIG_PKG_USING_PMS_SERIES is not set
 CONFIG_PKG_USING_NUCLEI_SDK=y
+
+#
+# !!!Nuclei SDK only works with Nuclei RISC-V Processor IP!!!
+#
 CONFIG_PKG_NUCLEI_SDK_PATH="/packages/peripherals/nuclei_sdk"
 # CONFIG_PKG_USING_NUCLEI_SDK_V023 is not set
 CONFIG_PKG_USING_NUCLEI_SDK_LATEST_VERSION=y
 CONFIG_PKG_NUCLEI_SDK_VER="latest"
+# CONFIG_PKG_USING_CAN_YMODEM is not set
 
 #
 # miscellaneous packages
@@ -446,6 +443,13 @@ CONFIG_BSP_USING_UART=y
 # CONFIG_BSP_USING_UART2 is not set
 # CONFIG_BSP_USING_UART3 is not set
 CONFIG_BSP_USING_UART4=y
+# CONFIG_BSP_USING_I2C is not set
+# CONFIG_BSP_USING_SPI is not set
+# CONFIG_BSP_USING_HWTIMER is not set
+# CONFIG_BSP_USING_ADC is not set
+# CONFIG_BSP_USING_WDT is not set
+# CONFIG_BSP_USING_RTC is not set
+# CONFIG_BSP_USING_PWM is not set
 
 #
 # Board extended module Drivers

+ 129 - 41
bsp/nuclei/gd32vf103_rvstar/README.md

@@ -2,17 +2,17 @@
 
 ## 简介
 
-**RVSTAR开发板** 是由芯来科技公司推出的基于采用芯来科技RISC-V架构处理器芯片的GD32VF103的开发板。
+**RVSTAR开发板** 是由[芯来科技Nuclei](https://nucleisys.com/)公司推出的基于采用芯来科技RISC-V架构处理器芯片的GD32VF103的开发板。
 
 更多关于 **RVSTAR开发板** 开发板的详细资料请参见 [RVSTAR开发板快速入门](https://www.rvmcu.com/quickstart-quickstart-index-u-RV_STAR.html)
 
 ### 板载资源
 
-| 硬件 | 描述 |
-| ---  | --- |
-| 内核 | Nuclei N205 |
+| 硬件 | 描述            |
+| ---- | --------------- |
+| 内核 | Nuclei N205     |
 | 架构 | 32-bit RV32IMAC |
-| 主频 | 108 MHz |
+| 主频 | 108 MHz         |
 
 ## 工具安装
 
@@ -75,27 +75,28 @@ export PATH=~/Software/Nuclei/gcc/bin:~/Software/Nuclei/openocd/bin:$PATH
 
 正常下载的输出如下:
 
-~~~
+~~~bat
+57856@DESKTOP-4LATIEU D:\workspace\Sourcecode\rt-thread\bsp\nuclei\gd32vf103_rvstar
+> scons --run upload
 scons: Reading SConscript files ...
 Supported downloaded modes for board gd32vf103v_rvstar are flashxip, chosen downloaded mode is flashxip
 Upload application rtthread.elf using openocd and gdb
 riscv-nuclei-elf-gdb rtthread.elf -ex "set remotetimeout 240"                     -ex "target remote | openocd --pipe -f D:/workspace/Sourcecode/rt-thread/bsp/nuclei/gd32vf103_rvstar/packages/nuclei_sdk-latest/SoC/gd32vf103/Board/gd32vf103v_rvstar/openocd_gd32vf103.cfg"                     --batch -ex "monitor halt" -ex "monitor flash protect 0 0 last off" -ex "load"                     -ex "monitor resume" -ex "monitor shutdown" -ex "quit"
 D:\Software\Nuclei\gcc\bin\riscv-nuclei-elf-gdb.exe: warning: Couldn't determine a path for the index cache directory.
-
 Nuclei OpenOCD, 64-bit Open On-Chip Debugger 0.10.0+dev-00014-g0eae03214 (2019-12-12-07:43)
 Licensed under GNU GPL v2
 For bug reports, read
         http://openocd.org/doc/doxygen/bugs.html
-rt_thread_idle_entry (parameter=0x0) at D:\workspace\Sourcecode\rt-thread\src\idle.c:251
-251                 if (idle_hook_list[i] != RT_NULL)
+rt_assert_handler (ex_string=ex_string@entry=0x800ab10 "0", func=func@entry=0x800ac14 <__FUNCTION__.3090> "rt_sem_take", line=line@entry=363) at D:\workspace\Sourcecode\rt-thread\src\kservice.c:1371
+1371                while (dummy == 0);
 cleared protection for sectors 0 through 127 on flash bank 0
 
 Loading section .init, size 0x264 lma 0x8000000
-Loading section .text, size 0x140de lma 0x8000280
-Loading section .rodata, size 0x37c0 lma 0x8014360
-Loading section .data, size 0x404 lma 0x8017b20
-Start address 0x800015c, load size 98054
-Transfer rate: 8 KB/sec, 10894 bytes/write.
+Loading section .text, size 0xa646 lma 0x8000280
+Loading section .rodata, size 0x2a80 lma 0x800a8c8
+Loading section .data, size 0x350 lma 0x800d348
+Start address 0x800015c, load size 54906
+Transfer rate: 6 KB/sec, 9151 bytes/write.
 shutdown command invoked
 A debugging session is active.
 
@@ -112,38 +113,55 @@ initialize rti_board_start:0 done
 
  \ | /
 - RT -     Thread Operating System
- / | \     4.0.3 build Apr  9 2020
+ / | \     4.0.3 build Jun  9 2020
  2006 - 2020 Copyright by rt-thread team
 do components initialization.
 initialize rti_board_end:0 done
-initialize dfs_init:0 done
+initialize rt_work_sys_workqueue_init:0 done
+initialize rt_hw_pin_init:0 done
 initialize libc_system_init:0 done
 initialize finsh_system_init:0 done
-msh />
+msh >
 ```
 
 在串口终端(我这里使用的是TeraTerm)输入``ps``即可查看当前线程工作情况:
 
 ~~~
-msh />ps
+msh >ps
 thread   pri  status      sp     stack size max used left tick  error
 -------- ---  ------- ---------- ----------  ------  ---------- ---
-thread01  19  suspend 0x00000158 0x0000018c    87%   0x00000005 000
-thread00  19  suspend 0x00000158 0x0000018c    87%   0x00000005 000
-tshell    20  running 0x00000258 0x00001000    18%   0x00000004 000
-tidle0    31  ready   0x000000a8 0x0000018c    59%   0x0000000e 000
-timer      4  suspend 0x000000f8 0x00000200    49%   0x00000009 000
-main      10  suspend 0x00000168 0x00000800    36%   0x00000006 000
-msh />
+tshell    20  running 0x000000f8 0x00000800    21%   0x00000008 000
+sys_work  23  suspend 0x00000098 0x00000800    07%   0x0000000a 000
+tidle0    31  ready   0x000000b8 0x0000018c    46%   0x00000013 000
+timer      4  suspend 0x00000098 0x00000200    29%   0x00000009 000
+msh >list_device
+device           type         ref count
+-------- -------------------- ----------
+pin      Miscellaneous Device 0
+uart4    Character Device     2
+msh >version
+
+ \ | /
+- RT -     Thread Operating System
+ / | \     4.0.3 build Jun 11 2020
+ 2006 - 2020 Copyright by rt-thread team
+msh >free
+total memory: 14208
+used memory : 5248
+maximum allocated memory: 6424
 ~~~
 
 ### 调试程序
 
+#### 命令行GDB调试
+
 在保证程序编译成功后, 在相同ENV终端执行``scons --run debug``进行代码在命令行下进行GDB调试。
 
 正常的调试输出如下:
 
-~~~
+~~~bat
+57856@DESKTOP-4LATIEU D:\workspace\Sourcecode\rt-thread\bsp\nuclei\gd32vf103_rvstar
+> scons --run debug
 scons: Reading SConscript files ...
 Supported downloaded modes for board gd32vf103v_rvstar are flashxip, chosen downloaded mode is flashxip
 Debug application rtthread.elf using openocd and gdb
@@ -165,42 +183,112 @@ Find the GDB manual and other documentation resources online at:
 For help, type "help".
 Type "apropos word" to search for commands related to "word"...
 Reading symbols from rtthread.elf...
-Remote debugging using | openocd --pipe -f D:/workspace/Sourcecode/rt-thread/bsp/nuclei/gd32vf103_rvstar/packages/nuclei_sdk-latest/SoC/gd32vf103/Board/gd32vf103v_rvstar/openocd_gd32vf103.cfg Nuclei OpenOCD, 64-bit Open On-Chip Debugger 0.10.0+dev-00014-g0eae03214 (2019-12-12-07:43)
+Remote debugging using | openocd --pipe -f D:/workspace/Sourcecode/rt-thread/bsp/nuclei/gd32vf103_rvstar/packages/nuclei_sdk-latest/SoC/gd32vf103/Board/gd32vf103v_rvstar/openocd_gd32vf103.cfg
+Nuclei OpenOCD, 64-bit Open On-Chip Debugger 0.10.0+dev-00014-g0eae03214 (2019-12-12-07:43)
 Licensed under GNU GPL v2
 For bug reports, read
         http://openocd.org/doc/doxygen/bugs.html
-rt_thread_idle_entry (parameter=0x0) at D:\workspace\Sourcecode\rt-thread\src\idle.c:249
-249             for (i = 0; i < RT_IDLE_HOOK_LIST_SIZE; i++)
-(gdb)
-(gdb) b main.c:35
-Breakpoint 1 at 0x8000290: file applications\main.c, line 35.
+0x080011ca in rt_thread_idle_excute () at D:\workspace\Sourcecode\rt-thread\src\idle.c:153
+153         while (_has_defunct_thread())
+(gdb) b irq_entry
+Breakpoint 1 at 0x8003840: file D:\workspace\Sourcecode\rt-thread\libcpu\risc-v\nuclei\interrupt_gcc.S, line 190.
 (gdb) c
 Continuing.
 Note: automatically using hardware breakpoints for read-only addresses.
 
-Breakpoint 1, thread_entry (parameter=0x0) at applications\main.c:35
-35              rt_thread_mdelay(500);
-(gdb)
+Breakpoint 1, irq_entry () at D:\workspace\Sourcecode\rt-thread\libcpu\risc-v\nuclei\interrupt_gcc.S:190
+190         SAVE_CONTEXT
+(gdb) c
 ~~~
 
 调试例子参见如下文档:
 
 * https://doc.nucleisys.com/nuclei_sdk/quickstart.html#debug-application
 
-为了更方便的进行调试, 也可以下载**Nuclei Studio**集成开发环境, 创建一个Debug Configuration, 选择编译好的
-ELF文件, 然后配置OPENOCD和GDB即可, OPENOCD配置文件路径为**bsp\nuclei\gd32vf103_rvstar\packages\nuclei_sdk-latest\SoC\gd32vf103\Board\gd32vf103v_rvstar\openocd_gd32vf103.cfg**
+#### Nuclei Studio IDE调试
+
+为了更方便的进行图形化调试, 也可以下载并使用[**Nuclei Studio IDE**](https://nucleisys.com/download.php)集成开发环境.
+
+1. 打开Nuclei Studio IDE, 创建一个名为**Nuclei_RT-Thread**的**C Project**,Project Type选择**Empty Project**,
+   Toolchain选择**RISC-V Cross GCC**, 然后点击**Finish**.
+
+   ![Create A RISC-V C Project](doc/images/create_c_project.png)
+
+2. 选中**rt-thread**的代码目录,然后鼠标左键拖到Nuclei Studio中创建好的**Nuclei_RT-Thread**工程中,选择
+   **Link to files and folders**, 点击**OK**, 就将**rt-thread**的代码拖到了工程中并创建软链接,注意这里建立的工程
+   仅用于调试,不可以用于编译,编译请使用上文中提到的`scons`命令。
+
+   ![Drop and link RT-Thread source code](doc/images/link_rtthread_code.png)
+
+3. 创建一个OpenOCD Debugging Configuration, 选择编译好的ELF文件, 并选定**Disable auto build**, 如下图所示:
+
+   ![Create OpenOCD Debugging Configuration](doc/images/create_gdb_cfg.png)
 
+4. 然后打开**Debugger**Tab, 配置好OPENOCD的配置文件路径, 其中OPENOCD配置文件路径为
+*bsp\nuclei\gd32vf103_rvstar\packages\nuclei_sdk-latest\SoC\gd32vf103\Board\gd32vf103v_rvstar\openocd_gd32vf103.cfg*,
+   请在配置时使用完整绝对路径,根据自己文件所在目录来提供。配置完毕后,点击 **Debug**,开始下载调试。
+
+   ![Configure OpenOCD configuration file](doc/images/config_openocd_cfg.png)
+
+5. 最终调试界面如下所示
+
+   ![Debug in Nuclei Studio IDE](doc/images/start_debug_in_ide.png)
+
+6. 上面步骤中的路径请根据自己的环境进行调整,调试时请确保开发板正常连接到电脑,并且调试器驱动安装正确。
 
 ## 驱动支持情况
 
-| 驱动 | 支持情况  |  备注  |
-| ------ | ----  | :------:  |
-| UART | 支持 | RV-STAR板载串口是UART4 |
+| 驱动    | 支持情况 |               备注               |
+| ------- | -------- | :------------------------------: |
+| UART    | 支持     | RV-STAR板载串口是UART4, 默认使能 |
+| GPIO    | 支持     |      默认使能,支持中断控制      |
+| SPI     | 支持     |             默认关闭             |
+| I2C     | 支持     |             默认关闭             |
+| HWTIMER | 支持     |             默认关闭             |
+| PWM     | 支持     |             默认关闭             |
+| WDT     | 支持     |             默认关闭             |
+| RTC     | 支持     |             默认关闭             |
+| ADC     | 支持     |             默认关闭             |
+
+### 适配开发板Pinmux
+
+如果需要使用到其他的外设驱动,则首先需要运行`menuconfig`命令,在
+`Hardware Drivers Config -> On-chip Peripheral Drivers`中使能对应的外设接口,
+但是由于针对不同的外设接口GPIO的pinux配置不一样,开发者仍需要根据自己的需求
+在 `board/board.c` 中的 `rt_hw_drivers_init`入口函数中找到需要使用到的子函数,
+并在对应的子函数中进行功能适配。
+
+**使用举例**
+
+* I2C外设Pinmux
+
+如果需要将I2C1的SCL和SDA配置在PB10和PB11,首先需要在menuconfig中将I2C1使能,然后
+更改board.c中`rt_hw_i2c_drvinit`函数,并进行如下设定。
+
+~~~c
+/* Configure PB10 PB11 (I2C1 SCL SDA) as alternate function  */
+gpio_init(GPIOB, GPIO_MODE_AF_OD, GPIO_OSPEED_50MHZ, GPIO_PIN_10 | GPIO_PIN_11);
+~~~
+
+* SPI外设Pinmux
+
+如果需要将SPI0的SCK MISO和MOSI配置在PA5, PA6和PA7,首先需要在menuconfig中将SPI0使能,
+然后更改board.c中的`rt_hw_spi_drvinit`函数,并进行如下设定。
+
+~~~c
+/* Configure PA5 PA6 PA7 (SPI0 SCK MISO MOSI) as alternate function */
+gpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_5 | GPIO_PIN_7);
+gpio_init(GPIOA, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_6);
+~~~
+
+* 其余类似的外设也是如上做适配处理
 
-**注:**
+### 注意
 
 - 适配RT-Thread的驱动框架的代码在 [../libraries/gd32vf103/HAL_Drivers](../libraries/gd32vf103/HAL_Drivers)目录下。
 - 如果有开发者想适配更多的驱动, 请在对应目录下增加驱动适配支持。
+- GD32VF103的驱动适配开关在 `menuconfig -> Hardware Drivers Config -> On-chip Peripheral Drivers` 可以找到。
+- HWTIMER和PWM都是采用的TIMER模块进行功能实现,所以在使用驱动时,请务必注意不要重叠使用相同模块。
 
 ## 联系人信息
 

+ 7 - 2
bsp/nuclei/gd32vf103_rvstar/SConstruct

@@ -24,7 +24,8 @@ DefaultEnvironment(tools=[])
 env = Environment(tools = ['mingw'],
     AS = rtconfig.AS, ASFLAGS = rtconfig.AFLAGS,
     CC = rtconfig.CC, CCFLAGS = rtconfig.CFLAGS,
-    AR = rtconfig.AR, ARFLAGS = '-rc',
+    CXX = rtconfig.CXX, CXXFLAGS = rtconfig.CXXFLAGS,
+    AR = rtconfig.AR, ARFLAGS = '-rc', LIBS = rtconfig.LIBS,
     LINK = rtconfig.LINK, LINKFLAGS = rtconfig.LFLAGS)
 env.PrependENVPath('PATH', rtconfig.EXEC_PATH)
 env['ASCOM'] = env['ASPPCOM']
@@ -50,7 +51,11 @@ objs = PrepareBuilding(env, RTT_ROOT)
 bsp_library_type = rtconfig.NUCLEI_SDK_SOC
 rtconfig.BSP_LIBRARY_TYPE = bsp_library_type
 
-openocd_cfg = rtconfig.NUCLEI_SDK_OPENOCD_CFG.replace('\\', '/')
+if hasattr(rtconfig, 'NUCLEI_SDK_OPENOCD_CFG'):
+    openocd_cfg = rtconfig.NUCLEI_SDK_OPENOCD_CFG.replace('\\', '/')
+else:
+    print("ERROR: Nuclei SDK package is not yet downloaded, please execute <pkgs --update> in command line first!")
+    exit(0)
 
 # include hal drivers
 hal_sconscript = os.path.join(libraries_path_prefix, bsp_library_type, 'HAL_Drivers', 'SConscript')

+ 102 - 0
bsp/nuclei/gd32vf103_rvstar/board/Kconfig

@@ -38,6 +38,108 @@ menu "On-chip Peripheral Drivers"
                 default n
         endif
 
+    menuconfig BSP_USING_I2C
+        bool "Enable I2C"
+        default n
+        select RT_USING_I2C
+        if BSP_USING_I2C
+            config BSP_USING_I2C0
+                bool "Enable I2C0"
+                default n
+            config BSP_USING_I2C1
+                bool "Enable I2C1"
+                default n
+        endif
+
+    menuconfig BSP_USING_SPI
+        bool "Enable SPI"
+        default n
+        select RT_USING_SPI
+        if BSP_USING_SPI
+            config BSP_USING_SPI0
+                bool "Enable SPI0"
+                default n
+            config BSP_USING_SPI1
+                bool "Enable SPI1"
+                default n
+            config BSP_USING_SPI2
+                bool "Enable SPI2"
+                default n
+        endif
+
+    menuconfig BSP_USING_HWTIMER
+        bool "Enable TIMER"
+        default n
+        select RT_USING_HWTIMER
+        if BSP_USING_HWTIMER
+            config BSP_USING_HWTIMER0
+                bool "Enable TIMER0"
+                default n
+            config BSP_USING_HWTIMER1
+                bool "Enable TIMER1"
+                default n
+            config BSP_USING_HWTIMER2
+                bool "Enable TIMER2"
+                default n
+            config BSP_USING_HWTIMER3
+                bool "Enable TIMER3"
+                default n
+            config BSP_USING_HWTIMER4
+                bool "Enable TIMER4"
+                default n
+            config BSP_USING_HWTIMER5
+                bool "Enable TIMER5"
+                default n
+            config BSP_USING_HWTIMER6
+                bool "Enable TIMER6"
+                default n
+        endif
+
+    menuconfig BSP_USING_ADC
+        bool "Enable ADC"
+        default n
+        select RT_USING_ADC
+        if BSP_USING_ADC
+            config BSP_USING_ADC0
+                bool "Enable ADC0"
+                default n
+            config BSP_USING_ADC1
+                bool "Enable ADC1"
+                default n
+        endif
+
+    menuconfig BSP_USING_WDT
+        bool "Enable WDT"
+        default n
+        select RT_USING_WDT
+
+    menuconfig BSP_USING_RTC
+        bool "Enable RTC"
+        default n
+        select RT_USING_RTC
+
+    menuconfig BSP_USING_PWM
+        bool "Enable PWM"
+        default n
+        select RT_USING_PWM
+        if BSP_USING_PWM
+            config BSP_USING_PWM0
+                bool "Enable PWM0"
+                default n
+            config BSP_USING_PWM1
+                bool "Enable PWM1"
+                default n
+            config BSP_USING_PWM2
+                bool "Enable PWM2"
+                default n
+            config BSP_USING_PWM3
+                bool "Enable PWM3"
+                default n
+            config BSP_USING_PWM4
+                bool "Enable PWM4"
+                default n
+        endif
+
 endmenu
 
 menu "Board extended module Drivers"

+ 94 - 0
bsp/nuclei/gd32vf103_rvstar/board/board.c

@@ -32,6 +32,96 @@ extern void *_heap_end;
  */
 extern void _init(void);
 
+/* 
+ * - Check MCU pin assignment here https://doc.nucleisys.com/nuclei_board_labs/hw/hw.html
+ * - If you changed menuconfig to use different peripherals such as SPI, ADC, GPIO,
+ *   HWTIMER, I2C, PWM, UART, WDT, RTC, please add or change related pinmux configuration
+ *   code in functions(rt_hw_*_drvinit) below
+ */
+
+void rt_hw_spi_drvinit(void)
+{
+
+}
+
+void rt_hw_adc_drvinit(void)
+{
+
+}
+
+void rt_hw_gpio_drvinit(void)
+{
+    // Clock on all the GPIOs and AF
+    rcu_periph_clock_enable(RCU_GPIOA);
+    rcu_periph_clock_enable(RCU_GPIOB);
+    rcu_periph_clock_enable(RCU_GPIOC);
+    rcu_periph_clock_enable(RCU_GPIOD);
+    rcu_periph_clock_enable(RCU_GPIOE);
+    rcu_periph_clock_enable(RCU_AF);
+}
+
+void rt_hw_hwtimer_drvinit(void)
+{
+
+}
+
+void rt_hw_i2c_drvinit(void)
+{
+
+}
+
+void rt_hw_pwm_drvinit(void)
+{
+
+}
+
+void rt_hw_rtc_drvinit(void)
+{
+
+}
+
+void rt_hw_uart_drvinit(void)
+{
+    /* Notice: Debug UART4 GPIO pins are already initialized in nuclei_sdk */
+
+}
+
+void rt_hw_wdt_drvinit(void)
+{
+
+}
+
+void rt_hw_drivers_init(void)
+{
+#ifdef RT_USING_PIN
+    rt_hw_gpio_drvinit();
+#endif
+#ifdef BSP_USING_UART
+    rt_hw_uart_drvinit();
+#endif
+#ifdef BSP_USING_SPI
+    rt_hw_spi_drvinit();
+#endif
+#ifdef BSP_USING_I2C
+    rt_hw_i2c_drvinit();
+#endif
+#ifdef BSP_USING_ADC
+    rt_hw_adc_drvinit();
+#endif
+#ifdef BSP_USING_WDT
+    rt_hw_wdt_drvinit();
+#endif
+#ifdef BSP_USING_RTC
+    rt_hw_rtc_drvinit();
+#endif
+#ifdef BSP_USING_HWTIMER
+    rt_hw_hwtimer_drvinit();
+#endif
+#ifdef BSP_USING_PWM
+    rt_hw_pwm_drvinit();
+#endif
+}
+
 /**
  * @brief Setup hardware board for rt-thread
  *
@@ -47,6 +137,9 @@ void rt_hw_board_init(void)
 
     _init(); // __libc_init_array is not used in RT-Thread
 
+    /* Board hardware drivers initialization */
+    rt_hw_drivers_init();
+
     /* USART driver initialization is open by default */
 #ifdef RT_USING_SERIAL
     rt_hw_usart_init();
@@ -61,6 +154,7 @@ void rt_hw_board_init(void)
 #ifdef RT_USING_COMPONENTS_INIT
     rt_components_board_init();
 #endif
+
 }
 
 /******************** end of file *******************/

BIN
bsp/nuclei/gd32vf103_rvstar/doc/images/config_openocd_cfg.png


BIN
bsp/nuclei/gd32vf103_rvstar/doc/images/create_c_project.png


BIN
bsp/nuclei/gd32vf103_rvstar/doc/images/create_gdb_cfg.png


BIN
bsp/nuclei/gd32vf103_rvstar/doc/images/link_rtthread_code.png


BIN
bsp/nuclei/gd32vf103_rvstar/doc/images/start_debug_in_ide.png


+ 8 - 10
bsp/nuclei/gd32vf103_rvstar/rtconfig.h

@@ -52,7 +52,7 @@
 
 #define RT_USING_COMPONENTS_INIT
 #define RT_USING_USER_MAIN
-#define RT_MAIN_THREAD_STACK_SIZE 2048
+#define RT_MAIN_THREAD_STACK_SIZE 1024
 #define RT_MAIN_THREAD_PRIORITY 10
 
 /* C++ features */
@@ -67,7 +67,7 @@
 #define FINSH_USING_SYMTAB
 #define FINSH_USING_DESCRIPTION
 #define FINSH_THREAD_PRIORITY 20
-#define FINSH_THREAD_STACK_SIZE 4096
+#define FINSH_THREAD_STACK_SIZE 2048
 #define FINSH_CMD_SIZE 80
 #define FINSH_USING_MSH
 #define FINSH_USING_MSH_DEFAULT
@@ -75,19 +75,15 @@
 
 /* Device virtual file system */
 
-#define RT_USING_DFS
-#define DFS_USING_WORKDIR
-#define DFS_FILESYSTEMS_MAX 2
-#define DFS_FILESYSTEM_TYPES_MAX 2
-#define DFS_FD_MAX 16
-#define RT_USING_DFS_DEVFS
 
 /* Device Drivers */
 
 #define RT_USING_DEVICE_IPC
 #define RT_PIPE_BUFSZ 512
+#define RT_USING_SYSTEM_WORKQUEUE
+#define RT_SYSTEM_WORKQUEUE_STACKSIZE 2048
+#define RT_SYSTEM_WORKQUEUE_PRIORITY 23
 #define RT_USING_SERIAL
-#define RT_SERIAL_USING_DMA
 #define RT_SERIAL_RB_BUFSZ 64
 #define RT_USING_PIN
 
@@ -97,7 +93,6 @@
 /* POSIX layer and C standard library */
 
 #define RT_USING_LIBC
-#define RT_USING_POSIX
 
 /* Network */
 
@@ -153,6 +148,9 @@
 /* peripheral libraries and drivers */
 
 #define PKG_USING_NUCLEI_SDK
+
+/* !!!Nuclei SDK only works with Nuclei RISC-V Processor IP!!! */
+
 #define PKG_USING_NUCLEI_SDK_LATEST_VERSION
 
 /* miscellaneous packages */

+ 5 - 5
bsp/nuclei/gd32vf103_rvstar/rtconfig.py

@@ -23,7 +23,6 @@ else:
 BUILD = 'debug'
 
 # Fixed configurations below
-NUCLEI_SDK_OPENOCD_CFG = "type in your config"
 NUCLEI_SDK_SOC = "gd32vf103"
 NUCLEI_SDK_BOARD = "gd32vf103v_rvstar"
 NUCLEI_SDK_DOWNLOAD = "flashxip"
@@ -46,13 +45,14 @@ if PLATFORM == 'gcc':
     CFLAGS  = ' -ffunction-sections -fdata-sections -fno-common '
     AFLAGS  = CFLAGS
     LFLAGS  = ' --specs=nano.specs --specs=nosys.specs -nostartfiles -Wl,--gc-sections '
-    LFLAGS += ' -Wl,-cref,-Map=rtthread.map'
+    LFLAGS  += ' -Wl,-cref,-Map=rtthread.map '
     LFLAGS  += ' -u _isatty -u _write -u _sbrk -u _read -u _close -u _fstat -u _lseek '
     CPATH   = ''
     LPATH   = ''
+    LIBS = ['stdc++']
 
     if BUILD == 'debug':
-        CFLAGS += ' -O0 -ggdb'
+        CFLAGS += ' -O2 -Os -ggdb'
         AFLAGS += ' -ggdb'
     else:
         CFLAGS += ' -O2 -Os'
@@ -62,9 +62,9 @@ if PLATFORM == 'gcc':
 DUMP_ACTION = OBJDUMP + ' -D -S $TARGET > rtt.asm\n'
 POST_ACTION = OBJCPY + ' -O binary $TARGET rtthread.bin\n' + SIZE + ' $TARGET \n'
 
-def dist_handle(BSP_ROOT):
+def dist_handle(BSP_ROOT, dist_dir):
     import sys
     cwd_path = os.getcwd()
     sys.path.append(os.path.join(os.path.dirname(BSP_ROOT), 'tools'))
     from sdk_dist import dist_do_building
-    dist_do_building(BSP_ROOT)
+    dist_do_building(BSP_ROOT, dist_dir)

+ 22 - 0
bsp/nuclei/libraries/gd32vf103/HAL_Drivers/SConscript

@@ -14,6 +14,28 @@ if GetDepend(['RT_USING_PIN']):
 if GetDepend(['RT_USING_SERIAL']):
     src += ['drv_usart.c']
 
+if GetDepend(['RT_USING_I2C']):
+    src += ['drv_i2c.c']
+
+if GetDepend(['RT_USING_SPI']):
+    src += ['drv_spi.c']
+
+if GetDepend(['RT_USING_HWTIMER']):
+    src += ['drv_hwtimer.c']
+
+if GetDepend(['RT_USING_ADC']):
+    src += ['drv_adc.c']
+
+if GetDepend(['RT_USING_WDT']):
+    src += ['drv_wdt.c']
+
+if GetDepend(['RT_USING_RTC']):
+    src += ['drv_rtc.c']
+
+if GetDepend(['RT_USING_PWM']):
+    src += ['drv_pwm.c']
+
+
 path =  [cwd]
 
 group = DefineGroup('Drivers', src, depend = [''], CPPPATH = path)

+ 137 - 0
bsp/nuclei/libraries/gd32vf103/HAL_Drivers/drv_adc.c

@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 2006-2020, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2020-06-03     hqfang       the first version.
+ *
+ */
+#include "drv_adc.h"
+
+#ifdef BSP_USING_ADC
+
+#if !defined(BSP_USING_ADC0) && !defined(BSP_USING_ADC1)
+    #error "Please define at least one BSP_USING_ADCx"
+    /* this driver can be disabled at menuconfig -> Hardware Drivers Config -> On-chip Peripheral Drivers -> Enable ADC */
+#endif
+
+
+static struct gd32_adc_config adc_config[] =
+{
+#ifdef BSP_USING_ADC0
+    {
+        "adc0",
+        ADC0,
+    },
+#endif
+#ifdef BSP_USING_ADC1
+    {
+        "adc1",
+        ADC1,
+    },
+#endif
+};
+
+static struct gd32_adc adc_obj[sizeof(adc_config) / sizeof(adc_config[0])] = {0};
+
+static void gd32_adc_init(struct gd32_adc_config *config)
+{
+    RT_ASSERT(config != RT_NULL);
+    adc_deinit(config->adc_periph);
+
+    ADC_CTL0(config->adc_periph) &= ~(ADC_CTL0_SYNCM);
+    ADC_CTL0(config->adc_periph) |= ADC_MODE_FREE;
+
+    ADC_CTL1(config->adc_periph) |= ADC_CTL1_TSVREN;
+
+    adc_resolution_config(config->adc_periph, ADC_RESOLUTION_12B);
+    /* ADC contineous function enable */
+    adc_special_function_config(config->adc_periph, ADC_SCAN_MODE, ENABLE);
+    /* ADC data alignment config */
+    adc_data_alignment_config(config->adc_periph, ADC_DATAALIGN_RIGHT);
+    /* ADC channel length config */
+    adc_channel_length_config(config->adc_periph, ADC_REGULAR_CHANNEL, 1);
+    adc_external_trigger_source_config(config->adc_periph, ADC_REGULAR_CHANNEL, ADC0_1_EXTTRIG_REGULAR_NONE);
+
+    /* ADC enable */
+    adc_external_trigger_config(config->adc_periph, ADC_REGULAR_CHANNEL, ENABLE);
+    adc_enable(config->adc_periph);
+
+    adc_calibration_enable(config->adc_periph);
+}
+
+static rt_err_t gd32_adc_enabled(struct rt_adc_device *device, rt_uint32_t channel, rt_bool_t enabled)
+{
+    if (channel > ADC_CHANNEL_17)
+    {
+        return RT_EINVAL;
+    }
+    return RT_EOK;
+}
+
+static rt_err_t gd32_adc_convert(struct rt_adc_device *device, rt_uint32_t channel, rt_uint32_t *value)
+{
+    struct gd32_adc_config *config;
+    RT_ASSERT(device != RT_NULL);
+
+    if (channel > ADC_CHANNEL_17)
+    {
+        return RT_EINVAL;
+    }
+    config = (struct gd32_adc_config *)(device->parent.user_data);
+
+    if (channel > ADC_CHANNEL_15)
+    {
+        adc_regular_channel_config(config->adc_periph, 0, channel, ADC_SAMPLETIME_239POINT5);
+    }
+    else
+    {
+        adc_regular_channel_config(config->adc_periph, 0, channel, ADC_SAMPLETIME_55POINT5);
+    }
+    adc_software_trigger_enable(config->adc_periph, ADC_REGULAR_CHANNEL);
+
+    while (SET != adc_flag_get(config->adc_periph, ADC_FLAG_EOC));
+    adc_flag_clear(config->adc_periph, ADC_FLAG_EOC);
+
+    *value = ADC_RDATA(config->adc_periph);
+
+    return RT_EOK;
+}
+
+static struct rt_adc_ops gd32_adc_ops =
+{
+    .enabled = gd32_adc_enabled,
+    .convert = gd32_adc_convert,
+};
+
+int rt_hw_adc_init(void)
+{
+    int i = 0;
+    int result = RT_EOK;
+
+#if defined(BSP_USING_ADC0)
+    rcu_periph_clock_enable(RCU_ADC0);
+#endif
+#if defined(BSP_USING_ADC1)
+    rcu_periph_clock_enable(RCU_ADC1);
+#endif
+
+    rcu_adc_clock_config(RCU_CKADC_CKAPB2_DIV8);
+
+    for (i = 0; i < sizeof(adc_obj) / sizeof(adc_obj[0]); i++)
+    {
+        adc_obj[i].config = &adc_config[i];
+        gd32_adc_init(&adc_config[i]);
+        rt_hw_adc_register(&adc_obj[i].adc_device, \
+                           adc_obj[i].config->name, &gd32_adc_ops, adc_obj[i].config);
+    }
+
+    return result;
+}
+
+INIT_DEVICE_EXPORT(rt_hw_adc_init);
+
+#endif /* BSP_USING_ADC */
+

+ 32 - 0
bsp/nuclei/libraries/gd32vf103/HAL_Drivers/drv_adc.h

@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2006-2020, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2020-06-03     hqfang       first implementation.
+ */
+
+#ifndef __DRV_ADC__
+#define __DRV_ADC__
+
+#include <rtthread.h>
+#include <rtdevice.h>
+#include <rthw.h>
+#include <drv_config.h>
+
+/* gd32 config class */
+struct gd32_adc_config
+{
+    const char *name;
+    rt_uint32_t adc_periph;
+};
+
+struct gd32_adc
+{
+    struct rt_adc_device adc_device;
+    struct gd32_adc_config *config;
+};
+
+#endif

+ 12 - 2
bsp/nuclei/libraries/gd32vf103/HAL_Drivers/drv_gpio.c

@@ -337,8 +337,11 @@ static rt_err_t gd32_pin_irq_enable(struct rt_device *device, rt_base_t pin,
     const struct pin_irq_map *irqmap;
     rt_base_t level;
     rt_int32_t irqindex = -1;
+    rt_uint8_t portsrc = 0, pinsrc = 0;
     exti_trig_type_enum trigger_mode;
 
+    portsrc = pin >> 4;
+    pinsrc = pin % 16;
     index = get_pin(pin);
     if (index == RT_NULL)
     {
@@ -378,8 +381,9 @@ static rt_err_t gd32_pin_irq_enable(struct rt_device *device, rt_base_t pin,
             rt_hw_interrupt_enable(level);
             return RT_EINVAL;
         }
+
         /* connect EXTI line to  GPIO pin */
-        gpio_exti_source_select(index->gpio, index->pin);
+        gpio_exti_source_select(portsrc, pinsrc);
 
         /* configure EXTI line */
         exti_init((exti_line_enum)(index->pin), EXTI_INTERRUPT, trigger_mode);
@@ -391,6 +395,8 @@ static rt_err_t gd32_pin_irq_enable(struct rt_device *device, rt_base_t pin,
         ECLIC_EnableIRQ(irqmap->irqno);
         pin_irq_enable_mask |= irqmap->pinbit;
 
+        exti_interrupt_enable((exti_line_enum)(index->pin));
+
         rt_hw_interrupt_enable(level);
     }
     else if (enabled == PIN_IRQ_DISABLE)
@@ -405,6 +411,7 @@ static rt_err_t gd32_pin_irq_enable(struct rt_device *device, rt_base_t pin,
             if (!(pin_irq_enable_mask & (GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7 | GPIO_PIN_8 | GPIO_PIN_9)))
             {
                 ECLIC_DisableIRQ(irqmap->irqno);
+                exti_interrupt_disable((exti_line_enum)(index->pin));
             }
         }
         else if ((irqmap->pinbit >= GPIO_PIN_10) && (irqmap->pinbit <= GPIO_PIN_15))
@@ -412,11 +419,13 @@ static rt_err_t gd32_pin_irq_enable(struct rt_device *device, rt_base_t pin,
             if (!(pin_irq_enable_mask & (GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15)))
             {
                 ECLIC_DisableIRQ(irqmap->irqno);
+                exti_interrupt_disable((exti_line_enum)(index->pin));
             }
         }
         else
         {
             ECLIC_DisableIRQ(irqmap->irqno);
+            exti_interrupt_disable((exti_line_enum)(index->pin));
         }
     }
     else
@@ -515,6 +524,7 @@ int rt_hw_pin_init(void)
     rcu_periph_clock_enable(RCU_AF);
     return rt_device_pin_register("pin", &_gd32_pin_ops, RT_NULL);
 }
-INIT_BOARD_EXPORT(rt_hw_pin_init);
+
+INIT_DEVICE_EXPORT(rt_hw_pin_init);
 
 #endif /* RT_USING_PIN */

+ 315 - 0
bsp/nuclei/libraries/gd32vf103/HAL_Drivers/drv_hwtimer.c

@@ -0,0 +1,315 @@
+/*
+ * Copyright (c) 2006-2018, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2020-05-12     hqfang       first version
+ */
+
+#include "drv_hwtimer.h"
+
+#ifdef BSP_USING_HWTIMER
+
+#if !defined(BSP_USING_HWTIMER0) && !defined(BSP_USING_HWTIMER1) && !defined(BSP_USING_HWTIMER2) \
+    && !defined(BSP_USING_HWTIMER3) && !defined(BSP_USING_HWTIMER4)
+    #error "Please define at least one BSP_USING_HWTIMERx"
+    /* this driver can be disabled at menuconfig -> Hardware Drivers Config -> On-chip Peripheral Drivers -> Enable HWTIMER */
+#endif
+
+static struct gd32_hwtimer_config hwtimer_config[] =
+{
+#ifdef BSP_USING_HWTIMER0
+    {
+        "timer0",
+        TIMER0,
+        TIMER0_UP_IRQn,
+    },
+#endif
+#ifdef BSP_USING_HWTIMER1
+    {
+        "timer1",
+        TIMER1,
+        TIMER1_IRQn,
+    },
+#endif
+#ifdef BSP_USING_HWTIMER2
+    {
+        "timer2",
+        TIMER2,
+        TIMER2_IRQn,
+    },
+#endif
+#ifdef BSP_USING_HWTIMER3
+    {
+        "timer3",
+        TIMER3,
+        TIMER3_IRQn,
+    },
+#endif
+#ifdef BSP_USING_HWTIMER4
+    {
+        "timer4",
+        TIMER4,
+        TIMER4_IRQn,
+    },
+#endif
+#ifdef BSP_USING_HWTIMER5
+    {
+        "timer5",
+        TIMER5,
+        TIMER5_IRQn,
+    },
+#endif
+#ifdef BSP_USING_HWTIMER6
+    {
+        "timer6",
+        TIMER6,
+        TIMER6_IRQn,
+    },
+#endif
+};
+
+static struct gd32_hwtimer hwtimer_obj[sizeof(hwtimer_config) / sizeof(hwtimer_config[0])] = {0};
+
+static rt_err_t gd32_hwtimer_control(rt_hwtimer_t *timer, rt_uint32_t cmd, void *args)
+{
+    rt_err_t err = RT_EOK;
+    struct gd32_hwtimer_config *config;
+    RT_ASSERT(timer != RT_NULL);
+
+    config = (struct gd32_hwtimer_config *)timer->parent.user_data;
+
+    switch (cmd)
+    {
+    case HWTIMER_CTRL_FREQ_SET:
+    {
+        uint32_t clk;
+        uint8_t clkpre;
+        uint32_t pre;
+        if (config->timer_periph != TIMER0)
+        {
+            clk = rcu_clock_freq_get(CK_APB1);
+            clkpre = GET_BITS(RCU_CFG0, 8, 10);
+        }
+        else
+        {
+            clk = rcu_clock_freq_get(CK_APB2);
+            clkpre = GET_BITS(RCU_CFG0, 11, 13);
+        }
+        if (clkpre >= 4)
+        {
+            clk = clk * 2;
+        }
+        pre = (clk / * ((uint32_t *)args)) - 1;
+        TIMER_PSC(config->timer_periph) = (uint32_t)pre;
+    }
+    break;
+    case HWTIMER_CTRL_STOP:
+        timer_disable(config->timer_periph);
+        break;
+    default:
+        err = -RT_ENOSYS;
+        break;
+    }
+    return err;
+}
+
+static rt_uint32_t gd32_hwtimer_count_get(rt_hwtimer_t *timer)
+{
+    rt_uint32_t CurrentTimer_Count;
+    struct gd32_hwtimer_config *config;
+    RT_ASSERT(timer != RT_NULL);
+
+    config = (struct gd32_hwtimer_config *)timer->parent.user_data;
+
+    CurrentTimer_Count = timer_counter_read(config->timer_periph);
+
+    return CurrentTimer_Count;
+}
+
+static void gd32_hwtimer_init(rt_hwtimer_t *timer, rt_uint32_t state)
+{
+    struct gd32_hwtimer_config *config;
+    timer_parameter_struct initpara;
+    RT_ASSERT(timer != RT_NULL);
+    config = (struct gd32_hwtimer_config *)timer->parent.user_data;
+
+    if (state == 1)
+    {
+        timer_deinit(config->timer_periph);
+        timer_struct_para_init(&initpara);
+        timer_init(config->timer_periph, &initpara);
+    }
+    else
+    {
+        timer_disable(config->timer_periph);
+        timer_interrupt_enable(config->timer_periph, TIMER_INT_FLAG_UP);
+        ECLIC_DisableIRQ(config->irqn);
+    }
+}
+
+static rt_err_t gd32_hwtimer_start(rt_hwtimer_t *timer, rt_uint32_t cnt, rt_hwtimer_mode_t mode)
+{
+    struct gd32_hwtimer_config *config;
+    RT_ASSERT(timer != RT_NULL);
+    config = (struct gd32_hwtimer_config *)timer->parent.user_data;
+
+    if (mode == HWTIMER_MODE_ONESHOT)
+    {
+        timer_single_pulse_mode_config(config->timer_periph, TIMER_SP_MODE_SINGLE);
+    }
+    else
+    {
+        timer_single_pulse_mode_config(config->timer_periph, TIMER_SP_MODE_REPETITIVE);
+    }
+    timer_counter_value_config(config->timer_periph, 0);
+    timer_autoreload_value_config(config->timer_periph, cnt);
+    timer_interrupt_enable(config->timer_periph, TIMER_INT_FLAG_UP);
+    timer_enable(config->timer_periph);
+    ECLIC_EnableIRQ(config->irqn);
+
+    return RT_EOK;
+}
+
+static void gd32_hwtimer_stop(rt_hwtimer_t *timer)
+{
+    struct gd32_hwtimer_config *config;
+    RT_ASSERT(timer != RT_NULL);
+    config = (struct gd32_hwtimer_config *)timer->parent.user_data;
+
+    timer_disable(config->timer_periph);
+
+    ECLIC_DisableIRQ(config->irqn);
+}
+
+static const struct rt_hwtimer_ops gd32_hwtimer_ops =
+{
+    .init = gd32_hwtimer_init,
+    .start = gd32_hwtimer_start,
+    .stop = gd32_hwtimer_stop,
+    .count_get = gd32_hwtimer_count_get,
+    .control = gd32_hwtimer_control,
+};
+
+static const struct rt_hwtimer_info gd32_hwtimer_info =
+{
+    54000000,           /* the maximum count frequency can be set */
+    1000,               /* the minimum count frequency can be set */
+    0xFFFF,
+    HWTIMER_CNTMODE_UP,
+};
+
+#ifdef BSP_USING_HWTIMER0
+
+void TIMER0_UP_IRQHandler(void)
+{
+    timer_interrupt_flag_clear(hwtimer_obj[0].config->timer_periph, TIMER_INT_FLAG_UP);
+    rt_device_hwtimer_isr(&hwtimer_obj[0].time_device);
+}
+
+#endif
+
+#ifdef BSP_USING_HWTIMER1
+
+void TIMER1_IRQHandler(void)
+{
+    timer_interrupt_flag_clear(hwtimer_obj[1].config->timer_periph, TIMER_INT_FLAG_UP);
+    rt_device_hwtimer_isr(&hwtimer_obj[1].time_device);
+}
+
+#endif
+
+#ifdef BSP_USING_HWTIMER2
+
+void TIMER2_IRQHandler(void)
+{
+    timer_interrupt_flag_clear(hwtimer_obj[2].config->timer_periph, TIMER_INT_FLAG_UP);
+    rt_device_hwtimer_isr(&hwtimer_obj[2].time_device);
+}
+
+#endif
+
+#ifdef BSP_USING_HWTIMER3
+
+void TIMER3_IRQHandler(void)
+{
+    timer_interrupt_flag_clear(hwtimer_obj[3].config->timer_periph, TIMER_INT_FLAG_UP);
+    rt_device_hwtimer_isr(&hwtimer_obj[3].time_device);
+}
+
+#endif
+
+#ifdef BSP_USING_HWTIMER4
+
+void TIMER4_IRQHandler(void)
+{
+    timer_interrupt_flag_clear(hwtimer_obj[4].config->timer_periph, TIMER_INT_FLAG_UP);
+    rt_device_hwtimer_isr(&hwtimer_obj[4].time_device);
+}
+
+#endif
+
+#ifdef BSP_USING_HWTIMER5
+
+void TIMER5_IRQHandler(void)
+{
+    timer_interrupt_flag_clear(hwtimer_obj[5].config->timer_periph, TIMER_INT_FLAG_UP);
+    rt_device_hwtimer_isr(&hwtimer_obj[5].time_device);
+}
+
+#endif
+
+#ifdef BSP_USING_HWTIMER6
+
+void TIMER6_IRQHandler(void)
+{
+    timer_interrupt_flag_clear(hwtimer_obj[6].config->timer_periph, TIMER_INT_FLAG_UP);
+    rt_device_hwtimer_isr(&hwtimer_obj[6].time_device);
+}
+
+#endif
+
+static int rt_hwtimer_init(void)
+{
+    int i = 0;
+    int result = RT_EOK;
+
+#ifdef BSP_USING_HWTIMER0
+    rcu_periph_clock_enable(RCU_TIMER0);
+#endif
+#ifdef BSP_USING_HWTIMER1
+    rcu_periph_clock_enable(RCU_TIMER1);
+#endif
+#ifdef BSP_USING_HWTIMER2
+    rcu_periph_clock_enable(RCU_TIMER2);
+#endif
+#ifdef BSP_USING_HWTIMER3
+    rcu_periph_clock_enable(RCU_TIMER3);
+#endif
+#ifdef BSP_USING_HWTIMER4
+    rcu_periph_clock_enable(RCU_TIMER4);
+#endif
+#ifdef BSP_USING_HWTIMER5
+    rcu_periph_clock_enable(RCU_TIMER5);
+#endif
+#ifdef BSP_USING_HWTIMER6
+    rcu_periph_clock_enable(RCU_TIMER6);
+#endif
+
+    for (i = 0; i < sizeof(hwtimer_obj) / sizeof(hwtimer_obj[0]); i++)
+    {
+        hwtimer_obj[i].time_device.info = &gd32_hwtimer_info;
+        hwtimer_obj[i].time_device.ops  = &gd32_hwtimer_ops;
+        hwtimer_obj[i].config = &hwtimer_config[i];
+        rt_device_hwtimer_register(&hwtimer_obj[i].time_device, \
+                                   hwtimer_obj[i].config->name, hwtimer_obj[i].config);
+    }
+
+    return result;
+}
+
+INIT_DEVICE_EXPORT(rt_hwtimer_init);
+
+#endif /* RT_USING_HWTIMER */

+ 33 - 0
bsp/nuclei/libraries/gd32vf103/HAL_Drivers/drv_hwtimer.h

@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2006-2020, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2029-05-06     hqfang       first implementation.
+ */
+
+#ifndef __DRV_HWTIMER__
+#define __DRV_HWTIMER__
+
+#include <rtthread.h>
+#include <rtdevice.h>
+#include <rthw.h>
+#include <drv_config.h>
+
+/* gd32 config class */
+struct gd32_hwtimer_config
+{
+    const char *name;
+    rt_uint32_t timer_periph;
+    IRQn_Type irqn;
+};
+
+struct gd32_hwtimer
+{
+    rt_hwtimer_t time_device;
+    struct gd32_hwtimer_config *config;
+};
+
+#endif

+ 228 - 0
bsp/nuclei/libraries/gd32vf103/HAL_Drivers/drv_i2c.c

@@ -0,0 +1,228 @@
+/*
+ * Copyright (c) 2006-2020, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2020-04-27     hqfang       first implementation.
+ */
+
+#include "drv_i2c.h"
+
+#ifdef RT_USING_I2C
+
+#if !defined(BSP_USING_I2C0) && !defined(BSP_USING_I2C1)
+    #error "Please define at least one BSP_USING_I2Cx"
+    /* this driver can be disabled at menuconfig -> Hardware Drivers Config -> On-chip Peripheral Drivers -> Enable I2C */
+#endif
+
+static struct gd32_i2c_config i2c_config[] =
+{
+#ifdef BSP_USING_I2C0
+    {
+        "i2c0",
+        I2C0,
+        100000,
+    },
+#endif
+#ifdef BSP_USING_I2C1
+    {
+        "i2c1",
+        I2C1,
+        100000,
+    },
+#endif
+};
+
+static struct gd32_i2c i2c_obj[sizeof(i2c_config) / sizeof(i2c_config[0])] = {0};
+
+#define GD32_I2C_TIMEOUT    10
+
+static int gd32_i2c_read(rt_uint32_t i2c_periph, rt_uint16_t slave_address, rt_uint8_t *p_buffer, rt_uint16_t cnt)
+{
+    /* send slave address to I2C bus */
+    i2c_master_addressing(i2c_periph, slave_address << 1, I2C_RECEIVER);
+
+    /* wait until ADDSEND bit is set */
+    while (!i2c_flag_get(i2c_periph, I2C_FLAG_ADDSEND));
+
+    /* clear the ADDSEND bit */
+    i2c_flag_clear(i2c_periph, I2C_FLAG_ADDSEND);
+
+    /* while there is data to be read */
+    while (cnt)
+    {
+        if (cnt == 1)
+        {
+            // Send NACK for last 1 byte receive
+            i2c_ack_config(i2c_periph, I2C_ACK_DISABLE);
+        }
+        /* wait until the RBNE bit is set */
+        while (i2c_flag_get(i2c_periph, I2C_FLAG_RBNE) == RESET);
+
+        /* read a byte from i2c */
+        *p_buffer = i2c_data_receive(i2c_periph);
+
+        /* point to the next location where the byte read will be saved */
+        p_buffer++;
+
+        /* decrement the read bytes counter */
+        cnt--;
+    }
+
+    return 0;
+}
+
+static int gd32_i2c_write(rt_uint32_t i2c_periph, uint16_t slave_address, uint8_t *p_buffer, uint16_t cnt)
+{
+    /* send slave address to I2C bus */
+    i2c_master_addressing(i2c_periph, slave_address << 1, I2C_TRANSMITTER);
+
+    /* wait until ADDSEND bit is set */
+    while (!i2c_flag_get(i2c_periph, I2C_FLAG_ADDSEND));
+
+    /* clear the ADDSEND bit */
+    i2c_flag_clear(i2c_periph, I2C_FLAG_ADDSEND);
+
+    /* wait until the transmit data buffer is empty */
+    while (SET != i2c_flag_get(i2c_periph, I2C_FLAG_TBE));
+
+    /* while there is data to be read */
+    while (cnt)
+    {
+        i2c_data_transmit(i2c_periph, *p_buffer);
+
+        /* point to the next byte to be written */
+        p_buffer++;
+
+        /* decrement the write bytes counter */
+        cnt--;
+
+        /* wait until BTC bit is set */
+        while (!i2c_flag_get(i2c_periph, I2C_FLAG_BTC));
+    }
+
+    return 0;
+}
+
+static void gd32_i2c_configure(struct gd32_i2c_config *i2c_cfg)
+{
+    RT_ASSERT(i2c_cfg != RT_NULL);
+
+    /* configure i2c speed to 100Khz */
+    i2c_clock_config(i2c_cfg->i2c_periph, i2c_cfg->speed, I2C_DTCY_2);
+    /* enable I2C */
+    i2c_enable(i2c_cfg->i2c_periph);
+    /* enable acknowledge */
+    i2c_ack_config(i2c_cfg->i2c_periph, I2C_ACK_ENABLE);
+}
+
+
+static rt_size_t gd32_i2c_xfer(struct rt_i2c_bus_device *device, struct rt_i2c_msg msgs[], rt_uint32_t num)
+{
+    struct rt_i2c_msg *msg;
+    rt_uint32_t i;
+    rt_err_t ret = RT_ERROR;
+    rt_uint16_t last_flags;
+
+    RT_ASSERT(device != RT_NULL);
+
+    struct gd32_i2c *i2c_obj = (struct gd32_i2c *)(device);
+    struct gd32_i2c_config *i2c_cfg = (struct gd32_i2c_config *)(i2c_obj->config);
+    RT_ASSERT(i2c_cfg != RT_NULL);
+
+    /* wait until I2C bus is idle */
+    while (i2c_flag_get(i2c_cfg->i2c_periph, I2C_FLAG_I2CBSY));
+
+    if (num)
+    {
+        if (msg[0].flags & RT_I2C_ADDR_10BIT)
+        {
+            i2c_mode_addr_config(i2c_cfg->i2c_periph, I2C_I2CMODE_ENABLE, I2C_ADDFORMAT_10BITS, 0x82);
+        }
+        else
+        {
+            i2c_mode_addr_config(i2c_cfg->i2c_periph, I2C_I2CMODE_ENABLE, I2C_ADDFORMAT_7BITS, 0x82);
+        }
+    }
+    for (i = 0; i < num; i++)
+    {
+        msg = &msgs[i];
+
+        if (!(msg->flags & RT_I2C_NO_START))
+        {
+            /* send a start condition to I2C bus */
+            i2c_start_on_bus(i2c_cfg->i2c_periph);
+            /* wait until SBSEND bit is set */
+            while (!i2c_flag_get(i2c_cfg->i2c_periph, I2C_FLAG_SBSEND));
+        }
+
+        if (msg->flags & RT_I2C_RD)
+        {
+            gd32_i2c_read(i2c_cfg->i2c_periph, msg->addr, msg->buf, msg->len);
+        }
+        else
+        {
+            gd32_i2c_write(i2c_cfg->i2c_periph, msg->addr, msg->buf, msg->len);
+        }
+    }
+
+    if (num)
+    {
+        /* send a stop condition to I2C bus */
+        i2c_stop_on_bus(i2c_cfg->i2c_periph);
+
+        /* wait until the stop condition is finished */
+        while (I2C_CTL0(i2c_cfg->i2c_periph) & I2C_CTL0_STOP);
+    }
+    i2c_ack_config(i2c_cfg->i2c_periph, I2C_ACK_ENABLE);
+
+    ret = i;
+
+    return ret;
+}
+
+static const struct rt_i2c_bus_device_ops i2c_ops =
+{
+    gd32_i2c_xfer,
+    RT_NULL,
+    RT_NULL
+};
+
+int rt_hw_i2c_init(void)
+{
+    rt_size_t obj_num;
+    int index;
+    rt_err_t result = 0;
+
+#ifdef BSP_USING_I2C0
+    rcu_periph_clock_enable(RCU_I2C0);
+#endif
+#ifdef BSP_USING_I2C1
+    rcu_periph_clock_enable(RCU_I2C1);
+#endif
+
+    obj_num = sizeof(i2c_obj) / sizeof(struct gd32_i2c);
+    for (index = 0; index < obj_num; index++)
+    {
+        /* init i2c object */
+        i2c_obj[index].config = &i2c_config[index];
+        i2c_obj[index].bus.ops = &i2c_ops;
+
+        /* init i2c device */
+        gd32_i2c_configure(&i2c_config[index]);
+
+        /* register i2c device */
+        result = rt_i2c_bus_device_register(&i2c_obj[index].bus,
+                                            i2c_obj[index].config->name
+                                           );
+        RT_ASSERT(result == RT_EOK);
+    }
+
+    return 0;
+}
+INIT_DEVICE_EXPORT(rt_hw_i2c_init);
+
+#endif
+/* end of i2c driver */

+ 33 - 0
bsp/nuclei/libraries/gd32vf103/HAL_Drivers/drv_i2c.h

@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2006-2020, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2020-04-27     hqfang       first implementation.
+ */
+
+#ifndef __DRV_I2C__
+#define __DRV_I2C__
+
+#include <rtthread.h>
+#include <rtdevice.h>
+#include <rthw.h>
+#include <drv_config.h>
+
+/* gd32 config class */
+struct gd32_i2c_config
+{
+    const char *name;
+    rt_uint32_t i2c_periph;
+    rt_uint32_t speed;
+};
+
+struct gd32_i2c
+{
+    struct rt_i2c_bus_device bus;
+    struct gd32_i2c_config *config;
+};
+
+#endif

+ 352 - 0
bsp/nuclei/libraries/gd32vf103/HAL_Drivers/drv_pwm.c

@@ -0,0 +1,352 @@
+/*
+ * Copyright (c) 2006-2018, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2020-06-02     hqfang       first version
+ */
+
+#include "drv_pwm.h"
+// #define DBG_LVL               DBG_INFO
+
+#include <rtdbg.h>
+
+#ifdef BSP_USING_PWM
+
+#if !defined(BSP_USING_PWM0) && !defined(BSP_USING_PWM1) && !defined(BSP_USING_PWM2) \
+    && !defined(BSP_USING_PWM3) && !defined(BSP_USING_PWM4)
+    #error "Please define at least one BSP_USING_PWMx"
+    /* this driver can be disabled at menuconfig -> Hardware Drivers Config -> On-chip Peripheral Drivers -> Enable PWM */
+#endif
+
+static struct gd32_pwm_config pwm_config[] =
+{
+#ifdef BSP_USING_PWM0
+    {
+        "pwm0",
+        TIMER0,
+        1000000,
+    },
+#endif
+#ifdef BSP_USING_PWM1
+    {
+        "pwm1",
+        TIMER1,
+        1000000,
+    },
+#endif
+#ifdef BSP_USING_PWM2
+    {
+        "pwm2",
+        TIMER2,
+        1000000,
+    },
+#endif
+#ifdef BSP_USING_PWM3
+    {
+        "pwm3",
+        TIMER3,
+        1000000,
+    },
+#endif
+#ifdef BSP_USING_PWM4
+    {
+        "pwm4",
+        TIMER4,
+        1000000,
+    },
+#endif
+};
+
+#define GD32_MAX_PWM_CHANNELS   TIMER_CH_3
+static struct gd32_pwm pwm_obj[sizeof(pwm_config) / sizeof(pwm_config[0])] = {0};
+
+static rt_err_t gd32_pwm_enable(struct rt_device_pwm *device, struct rt_pwm_configuration *configuration, rt_bool_t enable)
+{
+    struct gd32_pwm_config *config;
+    config = (struct gd32_pwm_config *)device->parent.user_data;
+    RT_ASSERT(config);
+
+    if (configuration->channel > GD32_MAX_PWM_CHANNELS)
+    {
+        return RT_EINVAL;
+    }
+    if (!enable)
+    {
+        timer_channel_output_state_config(config->periph, configuration->channel, TIMER_CCX_DISABLE);
+    }
+    else
+    {
+        timer_channel_output_state_config(config->periph, configuration->channel, TIMER_CCX_ENABLE);
+    }
+
+    return RT_EOK;
+}
+
+static uint32_t gd32_get_pwm_clk(rt_uint32_t periph)
+{
+    uint32_t clk;
+    uint8_t clkpre;
+    if (periph != TIMER0)
+    {
+        clk = rcu_clock_freq_get(CK_APB1);
+        clkpre = GET_BITS(RCU_CFG0, 8, 10);
+    }
+    else
+    {
+        clk = rcu_clock_freq_get(CK_APB2);
+        clkpre = GET_BITS(RCU_CFG0, 11, 13);
+    }
+    if (clkpre >= 4)
+    {
+        clk = clk * 2;
+    }
+    return clk;
+}
+
+static rt_err_t gd32_pwm_get(struct rt_device_pwm *device, struct rt_pwm_configuration *configuration)
+{
+    uint32_t pwmclk;
+    uint16_t prescale, period, clkdiv, pulse;
+    struct gd32_pwm_config *config;
+    config = (struct gd32_pwm_config *)device->parent.user_data;
+    RT_ASSERT(config);
+
+    pwmclk = gd32_get_pwm_clk(config->periph);
+    prescale = (uint16_t)TIMER_PSC(config->periph) + 1;
+    clkdiv = ((uint16_t)(TIMER_CTL0(config->periph) & TIMER_CTL0_CKDIV) >> 8);
+    clkdiv = 1 << clkdiv;
+    period = (uint16_t)TIMER_CAR(config->periph) + 1;
+    pulse = (uint16_t)REG32((config->periph) + 0x34U + configuration->channel << 2) + 1;
+
+    pwmclk = pwmclk / prescale / clkdiv;
+    LOG_I("current pwmclk is %d\n", pwmclk);
+
+    configuration->period = (uint64_t)period * 1000000000 / pwmclk;
+    configuration->pulse = (uint64_t)pulse * 1000000000 / pwmclk;
+    return RT_EOK;
+}
+
+static rt_err_t gd32_pwm_set(struct rt_device_pwm *device, struct rt_pwm_configuration *configuration)
+{
+    timer_oc_parameter_struct timer_ocinitpara;
+    timer_parameter_struct timer_initpara;
+    uint32_t pwmclk, pwmclkv2;
+    uint64_t period_cmp;
+    uint16_t prescale, period, clkdiv, pulse;
+    struct gd32_pwm_config *config;
+    config = (struct gd32_pwm_config *)device->parent.user_data;
+    RT_ASSERT(config);
+
+    if (configuration->channel > GD32_MAX_PWM_CHANNELS)
+    {
+        LOG_I("max channel supported is %d\n", GD32_MAX_PWM_CHANNELS);
+        return RT_EINVAL;
+    }
+    if (configuration->period < configuration->pulse)
+    {
+        LOG_I("period should > pulse \n");
+        return RT_EINVAL;
+    }
+
+    pwmclk = gd32_get_pwm_clk(config->periph);
+
+    // min period value >= 100
+    period_cmp = (uint64_t)(1000000000 / pwmclk) * 10;
+    if (configuration->period < period_cmp)
+    {
+        return RT_EINVAL;
+    }
+    period_cmp = (uint64_t)(1000000000 / (pwmclk / 65536 / 4)) * 65536;
+    if (configuration->period > period_cmp)
+    {
+        return RT_EINVAL;
+    }
+
+    period_cmp = (uint64_t) pwmclk * configuration->period / 1000000000;
+
+    if (period_cmp < 65536)
+    {
+        prescale = 0;
+        clkdiv = TIMER_CKDIV_DIV1;
+        period = period_cmp;
+    }
+    else if (period_cmp < 4294967296)
+    {
+        prescale = period_cmp / 65536;
+        period = period_cmp / (prescale + 1);
+        clkdiv = TIMER_CKDIV_DIV1;
+    }
+    else if (period_cmp < 8589934592)
+    {
+        prescale = period_cmp / 65536;
+        period = period_cmp / (prescale + 1) / 2;
+        clkdiv = TIMER_CKDIV_DIV2;
+    }
+    else
+    {
+        prescale = period_cmp / 65536;
+        period = period_cmp / (prescale + 1) / 4;
+        clkdiv = TIMER_CKDIV_DIV4;
+    }
+
+    pwmclkv2 = pwmclk / (prescale + 1) / (1 << clkdiv);
+    LOG_I("current pwmclk is %d\n", pwmclkv2);
+
+    LOG_I("Set channel %d, period %dns, pulse %dns\n", configuration->channel, \
+          configuration->period, configuration->pulse);
+    pulse = (uint64_t)period * configuration->pulse / configuration->period;
+    LOG_I("pwmclk %d, pwmcmp %d, prescale %d, period %d, pulse %d, clkdiv %d\n", \
+          pwmclk, (uint32_t)period_cmp, prescale, period, pulse, clkdiv);
+
+    /* initialize TIMER init parameter struct */
+    timer_struct_para_init(&timer_initpara);
+    /* TIMER configuration */
+    timer_initpara.prescaler         = prescale;
+    timer_initpara.alignedmode       = TIMER_COUNTER_EDGE;
+    timer_initpara.counterdirection  = TIMER_COUNTER_UP;
+    timer_initpara.period            = period;
+    timer_initpara.clockdivision     = clkdiv;
+    timer_initpara.repetitioncounter = 0;
+    timer_init(config->periph, &timer_initpara);
+
+    /* initialize TIMER channel output parameter struct */
+    timer_channel_output_struct_para_init(&timer_ocinitpara);
+    /* CH0, CH1 and CH2 configuration in PWM mode */
+    timer_ocinitpara.outputstate  = TIMER_CCX_DISABLE;
+    timer_ocinitpara.outputnstate = TIMER_CCXN_DISABLE;
+    timer_ocinitpara.ocpolarity   = TIMER_OC_POLARITY_HIGH;
+    timer_ocinitpara.ocnpolarity  = TIMER_OCN_POLARITY_HIGH;
+    timer_ocinitpara.ocidlestate  = TIMER_OC_IDLE_STATE_LOW;
+    timer_ocinitpara.ocnidlestate = TIMER_OCN_IDLE_STATE_LOW;
+
+    timer_channel_output_config(config->periph, configuration->channel, &timer_ocinitpara);
+
+    /* Channel configuration in PWM mode */
+    timer_channel_output_pulse_value_config(config->periph, configuration->channel, pulse);
+    timer_channel_output_mode_config(config->periph, configuration->channel, TIMER_OC_MODE_PWM0);
+    timer_channel_output_shadow_config(config->periph, configuration->channel, TIMER_OC_SHADOW_DISABLE);
+
+    timer_primary_output_config(config->periph, ENABLE);
+    /* auto-reload preload enable */
+    timer_auto_reload_shadow_enable(config->periph);
+    timer_enable(config->periph);
+
+    return RT_EOK;
+}
+
+static rt_err_t gd32_pwm_control(struct rt_device_pwm *device, int cmd, void *arg)
+{
+    struct rt_pwm_configuration *configuration = (struct rt_pwm_configuration *)arg;
+
+    switch (cmd)
+    {
+    case PWM_CMD_ENABLE:
+        return gd32_pwm_enable(device, configuration, RT_TRUE);
+    case PWM_CMD_DISABLE:
+        return gd32_pwm_enable(device, configuration, RT_FALSE);
+    case PWM_CMD_SET:
+        return gd32_pwm_set(device, configuration);
+    case PWM_CMD_GET:
+        return gd32_pwm_get(device, configuration);
+    default:
+        return RT_EINVAL;
+    }
+}
+
+static rt_err_t gd32_pwm_init(struct gd32_pwm_config *config)
+{
+    timer_oc_parameter_struct timer_ocinitpara;
+    timer_parameter_struct timer_initpara;
+    uint32_t pwmclk;
+    uint16_t prescale;
+
+    pwmclk = gd32_get_pwm_clk(config->periph);
+
+    /* period 1ms, duty 50% */
+    prescale = pwmclk / 1000 / 1000 - 1;
+
+    config->period = 1000000;
+
+    LOG_I("pwmclk %d, prescale %d, period %d, clkdiv %d\n", pwmclk, prescale, 999, 0);
+
+    /* initialize TIMER init parameter struct */
+    timer_struct_para_init(&timer_initpara);
+    /* TIMER configuration */
+    timer_initpara.prescaler         = prescale;
+    timer_initpara.alignedmode       = TIMER_COUNTER_EDGE;
+    timer_initpara.counterdirection  = TIMER_COUNTER_UP;
+    timer_initpara.period            = 999;
+    timer_initpara.clockdivision     = TIMER_CKDIV_DIV1;
+    timer_initpara.repetitioncounter = 0;
+    timer_init(config->periph, &timer_initpara);
+
+    /* initialize TIMER channel output parameter struct */
+    timer_channel_output_struct_para_init(&timer_ocinitpara);
+    /* CH0, CH1 and CH2 configuration in PWM mode */
+    timer_ocinitpara.outputstate  = TIMER_CCX_DISABLE;
+    timer_ocinitpara.outputnstate = TIMER_CCXN_DISABLE;
+    timer_ocinitpara.ocpolarity   = TIMER_OC_POLARITY_HIGH;
+    timer_ocinitpara.ocnpolarity  = TIMER_OCN_POLARITY_HIGH;
+    timer_ocinitpara.ocidlestate  = TIMER_OC_IDLE_STATE_LOW;
+    timer_ocinitpara.ocnidlestate = TIMER_OCN_IDLE_STATE_LOW;
+
+    /* Channel configuration in PWM mode */
+    for (int i = 0; i <= GD32_MAX_PWM_CHANNELS; i ++)
+    {
+        timer_channel_output_config(config->periph, i, &timer_ocinitpara);
+        timer_channel_output_pulse_value_config(config->periph, i, 499);
+        timer_channel_output_mode_config(config->periph, i, TIMER_OC_MODE_PWM0);
+        timer_channel_output_shadow_config(config->periph, i, TIMER_OC_SHADOW_DISABLE);
+    }
+
+    timer_primary_output_config(config->periph, ENABLE);
+    /* auto-reload preload enable */
+    timer_auto_reload_shadow_enable(config->periph);
+    timer_enable(config->periph);
+
+    return RT_EOK;
+}
+
+static struct rt_pwm_ops gd32_drv_ops =
+{
+    .control = gd32_pwm_control
+};
+
+static int rt_pwm_init(void)
+{
+    int i = 0;
+    int result = RT_EOK;
+
+#ifdef BSP_USING_PWM0
+    rcu_periph_clock_enable(RCU_TIMER0);
+#endif
+#ifdef BSP_USING_PWM1
+    rcu_periph_clock_enable(RCU_TIMER1);
+#endif
+#ifdef BSP_USING_PWM2
+    rcu_periph_clock_enable(RCU_TIMER2);
+#endif
+#ifdef BSP_USING_PWM3
+    rcu_periph_clock_enable(RCU_TIMER3);
+#endif
+#ifdef BSP_USING_PWM4
+    rcu_periph_clock_enable(RCU_TIMER4);
+#endif
+    rcu_periph_clock_enable(RCU_AF);
+
+    for (i = 0; i < sizeof(pwm_obj) / sizeof(pwm_obj[0]); i++)
+    {
+        pwm_obj[i].config = &pwm_config[i];
+        rt_device_pwm_register(&pwm_obj[i].pwm_device, pwm_config[i].name, &gd32_drv_ops, pwm_obj[i].config);
+        gd32_pwm_init(&pwm_config[i]);
+    }
+
+    return result;
+}
+
+INIT_DEVICE_EXPORT(rt_pwm_init);
+
+#endif /* RT_USING_PWM */

+ 34 - 0
bsp/nuclei/libraries/gd32vf103/HAL_Drivers/drv_pwm.h

@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2006-2020, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2029-06-02     hqfang       first implementation.
+ */
+
+#ifndef __DRV_PWM__
+#define __DRV_PWM__
+
+#include <rtthread.h>
+#include <rtdevice.h>
+#include <rthw.h>
+#include <drv_config.h>
+
+/* gd32 config class */
+struct gd32_pwm_config
+{
+    const char *name;
+    rt_uint32_t periph;
+    rt_uint32_t period;
+    rt_uint32_t pulse;
+};
+
+struct gd32_pwm
+{
+    struct rt_device_pwm pwm_device;
+    struct gd32_pwm_config *config;
+};
+
+#endif

+ 160 - 0
bsp/nuclei/libraries/gd32vf103/HAL_Drivers/drv_rtc.c

@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 2006-2020, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2020-06-08     hqfang       first implementation.
+ */
+
+#include "drv_rtc.h"
+
+#ifdef BSP_USING_RTC
+
+static time_t get_timestamp(void)
+{
+    return (time_t)rtc_counter_get();
+}
+
+static int set_timestamp(time_t timestamp)
+{
+    /* wait until last write operation on RTC registers has finished */
+    rtc_lwoff_wait();
+    /* change the current time */
+    rtc_counter_set((uint32_t)timestamp);
+    /* wait until last write operation on RTC registers has finished */
+    rtc_lwoff_wait();
+    return RT_EOK;
+}
+
+static void rtc_configuration(void)
+{
+    /* enable PMU and BKPI clocks */
+    rcu_periph_clock_enable(RCU_BKPI);
+    rcu_periph_clock_enable(RCU_PMU);
+    /* allow access to BKP domain */
+    pmu_backup_write_enable();
+
+    /* reset backup domain */
+    bkp_deinit();
+
+    /* enable LXTAL */
+    rcu_osci_on(RCU_LXTAL);
+    /* wait till LXTAL is ready */
+    rcu_osci_stab_wait(RCU_LXTAL);
+
+    /* select RCU_LXTAL as RTC clock source */
+    rcu_rtc_clock_config(RCU_RTCSRC_LXTAL);
+
+    /* enable RTC Clock */
+    rcu_periph_clock_enable(RCU_RTC);
+
+    /* wait for RTC registers synchronization */
+    rtc_register_sync_wait();
+
+    /* wait until last write operation on RTC registers has finished */
+    rtc_lwoff_wait();
+
+    /* wait until last write operation on RTC registers has finished */
+    rtc_lwoff_wait();
+
+    /* set RTC prescaler: set RTC period to 1s */
+    rtc_prescaler_set(32767);
+
+    /* wait until last write operation on RTC registers has finished */
+    rtc_lwoff_wait();
+}
+
+static rt_err_t gd32_rtc_init(rt_device_t dev)
+{
+    if (bkp_data_read(BKP_DATA_0) != 0xA5A5)
+    {
+        rtc_configuration();
+        bkp_data_write(BKP_DATA_0, 0xA5A5);
+    }
+    else
+    {
+        /* allow access to BKP domain */
+        rcu_periph_clock_enable(RCU_PMU);
+        pmu_backup_write_enable();
+
+        /* wait for RTC registers synchronization */
+        rtc_register_sync_wait();
+        /* wait until last write operation on RTC registers has finished */
+        rtc_lwoff_wait();
+    }
+
+    return RT_EOK;
+}
+
+static rt_err_t gd32_rtc_open(rt_device_t dev, rt_uint16_t oflag)
+{
+    return RT_EOK;
+}
+
+static rt_err_t gd32_rtc_close(rt_device_t dev)
+{
+    return RT_EOK;
+}
+
+static rt_size_t gd32_rtc_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
+{
+    return RT_EOK;
+}
+
+static rt_size_t gd32_rtc_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
+{
+    return RT_EOK;
+}
+
+static rt_err_t gd32_rtc_control(rt_device_t dev, int cmd, void *args)
+{
+    RT_ASSERT(dev != RT_NULL);
+
+    switch (cmd)
+    {
+    case RT_DEVICE_CTRL_RTC_GET_TIME:
+    {
+        *(uint32_t *)args = get_timestamp();
+    }
+    break;
+
+    case RT_DEVICE_CTRL_RTC_SET_TIME:
+    {
+        set_timestamp(*(time_t *)args);
+    }
+    break;
+
+    default:
+        return RT_EINVAL;
+    }
+
+    return RT_EOK;
+}
+
+static struct rt_device rtc_device =
+{
+    .type    = RT_Device_Class_RTC,
+    .init    = gd32_rtc_init,
+    .open    = gd32_rtc_open,
+    .close   = gd32_rtc_close,
+    .read    = gd32_rtc_read,
+    .write   = gd32_rtc_write,
+    .control = gd32_rtc_control,
+};
+
+int rt_hw_rtc_init(void)
+{
+    rt_err_t ret = RT_EOK;
+
+    ret = rt_device_register(&rtc_device, "rtc", RT_DEVICE_FLAG_RDWR);
+
+    rt_device_open(&rtc_device, RT_DEVICE_OFLAG_RDWR);
+
+    return RT_EOK;
+}
+
+INIT_DEVICE_EXPORT(rt_hw_rtc_init);
+
+#endif /* BSP_USING_RTC */

+ 19 - 0
bsp/nuclei/libraries/gd32vf103/HAL_Drivers/drv_rtc.h

@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2006-2020, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2020-06-08     hqfang       first implementation.
+ */
+
+#ifndef DRV_RTC_H__
+#define DRV_RTC_H__
+
+#include <rtthread.h>
+#include <rtdevice.h>
+#include <rthw.h>
+#include <drv_config.h>
+
+#endif

+ 287 - 0
bsp/nuclei/libraries/gd32vf103/HAL_Drivers/drv_spi.c

@@ -0,0 +1,287 @@
+/*
+ * Copyright (c) 2006-2020, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2020-05-28     hqfang       first implementation.
+ */
+
+#include "drv_spi.h"
+
+#ifdef RT_USING_SPI
+
+#if !defined(BSP_USING_SPI0) && !defined(BSP_USING_SPI1) && !defined(BSP_USING_SPI2)
+    #error "Please define at least one BSP_USING_SPIx"
+    /* this driver can be disabled at menuconfig -> Hardware Drivers Config -> On-chip Peripheral Drivers -> Enable SPI */
+#endif
+
+static struct gd32_spi_config spi_config[] =
+{
+#ifdef BSP_USING_SPI0
+    {
+        "spi0",
+        SPI0,
+    },
+#endif
+#ifdef BSP_USING_SPI1
+    {
+        "spi1",
+        SPI1,
+    },
+#endif
+#ifdef BSP_USING_SPI2
+    {
+        "spi2",
+        SPI2,
+    },
+#endif
+};
+
+static struct gd32_spi spi_obj[sizeof(spi_config) / sizeof(spi_config[0])] = {0};
+
+static rt_err_t gd32_spi_init(rt_uint32_t spi_periph, struct rt_spi_configuration *cfg)
+{
+    spi_parameter_struct spicfg;
+    uint32_t apbfreq;
+    uint32_t scale;
+
+    RT_ASSERT(cfg != RT_NULL);
+
+    spi_struct_para_init(&spicfg);
+
+    if (cfg->data_width != 8 && cfg->data_width != 16)
+    {
+        return (-RT_EINVAL);
+    }
+
+    switch (spi_periph)
+    {
+    case SPI0:
+        apbfreq = rcu_clock_freq_get(CK_APB2);
+        break;
+    default:
+        apbfreq = rcu_clock_freq_get(CK_APB1);
+        break;
+    }
+
+    scale = apbfreq / cfg->max_hz;
+    if (scale <= 2)
+    {
+        spicfg.prescale = SPI_PSC_2;
+    }
+    else if (scale <= 4)
+    {
+        spicfg.prescale = SPI_PSC_4;
+    }
+    else if (scale <= 8)
+    {
+        spicfg.prescale = SPI_PSC_8;
+    }
+    else if (scale <= 16)
+    {
+        spicfg.prescale = SPI_PSC_16;
+    }
+    else if (scale <= 32)
+    {
+        spicfg.prescale = SPI_PSC_32;
+    }
+    else if (scale <= 64)
+    {
+        spicfg.prescale = SPI_PSC_64;
+    }
+    else if (scale <= 128)
+    {
+        spicfg.prescale = SPI_PSC_128;
+    }
+    else if (scale <= 256)
+    {
+        spicfg.prescale = SPI_PSC_256;
+    }
+    else
+    {
+        spicfg.prescale = SPI_PSC_256;
+    }
+
+    if (cfg->data_width == 8)
+    {
+        spicfg.frame_size = SPI_FRAMESIZE_8BIT;
+    }
+    else
+    {
+        spicfg.frame_size = SPI_FRAMESIZE_16BIT;
+    }
+
+    if (cfg->mode & RT_SPI_MSB)
+    {
+        spicfg.endian = SPI_ENDIAN_MSB;
+    }
+    else
+    {
+        spicfg.endian = SPI_ENDIAN_LSB;
+    }
+
+    spicfg.clock_polarity_phase = 0;
+    if (cfg->mode & RT_SPI_CPHA)
+    {
+        spicfg.clock_polarity_phase |= SPI_CTL0_CKPH;
+    }
+    if (cfg->mode & RT_SPI_CPOL)
+    {
+        spicfg.clock_polarity_phase |= SPI_CTL0_CKPL;
+    }
+
+    if (cfg->mode & RT_SPI_SLAVE)
+    {
+        spicfg.device_mode = SPI_SLAVE;
+    }
+    else
+    {
+        spicfg.device_mode = SPI_MASTER;
+    }
+    spicfg.nss = SPI_NSS_SOFT;
+    spicfg.trans_mode = SPI_TRANSMODE_FULLDUPLEX;
+
+    spi_init(spi_periph, &spicfg);
+    /* set crc polynomial */
+    spi_crc_polynomial_set(spi_periph, 7);
+
+    return RT_EOK;
+}
+
+static rt_err_t gd32_spi_configure(struct rt_spi_device *device, struct rt_spi_configuration *cfg)
+{
+    rt_err_t ret = RT_EOK;
+    RT_ASSERT(device != RT_NULL);
+
+    struct gd32_spi *spi_obj = (struct gd32_spi *)(device->bus->parent.user_data);
+    struct gd32_spi_config *spi_cfg = (struct gd32_spi_config *)(spi_obj->config);
+
+    ret = gd32_spi_init(spi_cfg->spi_periph, cfg);
+    /* enable SPI */
+    spi_enable(spi_cfg->spi_periph);
+
+    return ret;
+}
+
+/**
+  * Attach the spi device to SPI bus, this function must be used after initialization.
+  */
+rt_err_t rt_hw_spi_device_attach(const char *bus_name, const char *device_name, rt_uint32_t pin)
+{
+    rt_err_t ret = RT_EOK;
+
+    struct rt_spi_device *spi_device = (struct rt_spi_device *)rt_malloc(sizeof(struct rt_spi_device));
+    RT_ASSERT(spi_device != RT_NULL);
+
+    struct gd32_spi_cs *cs_pin = (struct gd32_spi_cs *)rt_malloc(sizeof(struct gd32_spi_cs));
+    RT_ASSERT(cs_pin != RT_NULL);
+
+    cs_pin->pin = pin;
+    rt_pin_mode(pin, PIN_MODE_OUTPUT);
+    rt_pin_write(pin, PIN_HIGH);
+
+    ret = rt_spi_bus_attach_device(spi_device, device_name, bus_name, (void *)cs_pin);
+
+    return ret;
+}
+
+rt_size_t gd32_spi_transmit(rt_uint32_t spi_periph, const void *send_buf, void *recv_buf, rt_size_t length)
+{
+    uint8_t *send_buf_8b = (uint8_t *)send_buf;
+    uint8_t *recv_buf_8b = (uint8_t *)recv_buf;
+    uint8_t sndbyte = 0xFF, rcvbyte;
+    rt_size_t idx = 0;
+
+    while (idx < length)
+    {
+        while (RESET == spi_i2s_flag_get(spi_periph, SPI_FLAG_TBE));
+        if (send_buf_8b)
+        {
+            sndbyte = send_buf_8b[idx];
+        }
+        spi_i2s_data_transmit(spi_periph, sndbyte);
+        while (RESET == spi_i2s_flag_get(spi_periph, SPI_FLAG_RBNE));
+        rcvbyte = spi_i2s_data_receive(spi_periph);
+        if (recv_buf_8b)
+        {
+            recv_buf_8b[idx] = rcvbyte;
+        }
+        idx ++;
+    }
+
+    return length;
+}
+
+static rt_uint32_t gd32_spi_xfer(struct rt_spi_device *device, struct rt_spi_message *message)
+{
+    rt_uint32_t total_length = 0;
+    rt_err_t ret = RT_EOK;
+
+    RT_ASSERT(device != RT_NULL);
+
+    struct gd32_spi *spi_obj = (struct gd32_spi *)(device->bus->parent.user_data);
+    struct gd32_spi_config *spi_cfg = (struct gd32_spi_config *)(spi_obj->config);
+    RT_ASSERT(spi_cfg != RT_NULL);
+    struct gd32_spi_cs *cs = (struct gd32_spi_cs *)(device->parent.user_data);
+
+    if (message && message->cs_take)
+    {
+        rt_pin_write(cs->pin, PIN_LOW);
+    }
+    if (message && message->length)
+    {
+
+        total_length += gd32_spi_transmit(spi_cfg->spi_periph, message->send_buf, \
+                                          message->recv_buf, message->length);
+    }
+    if (message && message->cs_release)
+    {
+        rt_pin_write(cs->pin, PIN_HIGH);
+    }
+    return total_length;
+}
+
+static const struct rt_spi_ops spi_ops =
+{
+    gd32_spi_configure,
+    gd32_spi_xfer
+};
+
+int rt_hw_spi_init(void)
+{
+    rt_size_t obj_num;
+    int index;
+    rt_err_t result = 0;
+
+#ifdef BSP_USING_SPI0
+    rcu_periph_clock_enable(RCU_SPI0);
+#endif
+#ifdef BSP_USING_SPI1
+    rcu_periph_clock_enable(RCU_SPI1);
+#endif
+#ifdef BSP_USING_SPI2
+    rcu_periph_clock_enable(RCU_SPI2);
+#endif
+
+    obj_num = sizeof(spi_obj) / sizeof(struct gd32_spi);
+    for (index = 0; index < obj_num; index++)
+    {
+        /* init spi object */
+        spi_obj[index].config = &spi_config[index];
+        spi_obj[index].bus.parent.user_data = &spi_obj[index];
+
+        /* register spi device */
+        result = rt_spi_bus_register(&spi_obj[index].bus,
+                                     spi_obj[index].config->name,
+                                     &spi_ops);
+        RT_ASSERT(result == RT_EOK);
+    }
+
+    return 0;
+}
+INIT_DEVICE_EXPORT(rt_hw_spi_init);
+
+#endif
+/* end of spi driver */

+ 40 - 0
bsp/nuclei/libraries/gd32vf103/HAL_Drivers/drv_spi.h

@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2006-2020, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2029-04-29     hqfang       first implementation.
+ */
+
+#ifndef __DRV_SPI__
+#define __DRV_SPI__
+
+#include <rtthread.h>
+#include <rtdevice.h>
+#include <rthw.h>
+#include <drv_config.h>
+
+/* gd32 config class */
+struct gd32_spi_config
+{
+    const char *name;
+    rt_uint32_t spi_periph;
+};
+
+struct gd32_spi_cs
+{
+    rt_uint32_t pin;
+};
+
+struct gd32_spi
+{
+    struct rt_spi_bus bus;
+    struct gd32_spi_config *config;
+};
+
+int rt_hw_spi_init(void);
+rt_err_t rt_hw_spi_device_attach(const char *bus_name, const char *device_name, rt_uint32_t pin);
+
+#endif

+ 20 - 4
bsp/nuclei/libraries/gd32vf103/HAL_Drivers/drv_usart.c

@@ -16,7 +16,7 @@
 #if !defined(BSP_USING_UART0) && !defined(BSP_USING_UART1) && !defined(BSP_USING_UART2) \
     && !defined(BSP_USING_UART3) && !defined(BSP_USING_UART4)
     #error "Please define at least one BSP_USING_UARTx"
-    /* this driver can be disabled at menuconfig -> RT-Thread Components -> Device Drivers */
+    /* this driver can be disabled at menuconfig -> Hardware Drivers Config -> On-chip Peripheral Drivers -> Enable UART */
 #endif
 
 enum
@@ -64,8 +64,8 @@ static struct gd32_uart_config uart_config[] =
 #ifdef BSP_USING_UART3
     {
         "uart3",
-        USART3,
-        USART3_IRQn,
+        UART3,
+        UART3_IRQn,
     },
 #endif
 #ifdef BSP_USING_UART4
@@ -137,7 +137,7 @@ static rt_err_t gd32_configure(struct rt_serial_device *serial,
         break;
     }
     usart_hardware_flow_rts_config(usart->uart_base, USART_RTS_DISABLE);
-    usart_hardware_flow_cts_config(usart->uart_base, USART_RTS_DISABLE);
+    usart_hardware_flow_cts_config(usart->uart_base, USART_CTS_DISABLE);
     usart_receive_config(usart->uart_base, USART_RECEIVE_ENABLE);
     usart_transmit_config(usart->uart_base, USART_TRANSMIT_ENABLE);
     usart_enable(usart->uart_base);
@@ -320,6 +320,22 @@ int rt_hw_usart_init(void)
     rt_size_t obj_num;
     int index;
 
+#ifdef BSP_USING_UART0
+    rcu_periph_clock_enable(RCU_USART0);
+#endif
+#ifdef BSP_USING_UART1
+    rcu_periph_clock_enable(RCU_USART1);
+#endif
+#ifdef BSP_USING_UART2
+    rcu_periph_clock_enable(RCU_USART2);
+#endif
+#ifdef BSP_USING_UART3
+    rcu_periph_clock_enable(RCU_UART3);
+#endif
+#ifdef BSP_USING_UART4
+    rcu_periph_clock_enable(RCU_UART4);
+#endif
+
     obj_num = sizeof(uart_obj) / sizeof(struct gd32_uart);
     struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT;
     rt_err_t result = 0;

+ 1 - 1
bsp/nuclei/libraries/gd32vf103/HAL_Drivers/drv_usart.h

@@ -25,8 +25,8 @@ struct gd32_uart_config
 /* gd32 uart dirver class */
 struct gd32_uart
 {
-    struct gd32_uart_config *config;
     struct rt_serial_device serial;
+    struct gd32_uart_config *config;
 };
 
 int rt_hw_usart_init(void);

+ 156 - 0
bsp/nuclei/libraries/gd32vf103/HAL_Drivers/drv_wdt.c

@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2006-2020, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2020-06-08     hqfang       the first version.
+ *
+ */
+#include "drv_wdt.h"
+
+#ifdef BSP_USING_WDT
+
+
+static rt_err_t gd32_wdog_close(rt_watchdog_t *wdt)
+{
+    rt_uint32_t level;
+
+    level = rt_hw_interrupt_disable();
+    rcu_osci_off(RCU_IRC40K);
+    rt_hw_interrupt_enable(level);
+
+    return RT_EOK;
+}
+
+static rt_err_t gd32_wdog_open(rt_watchdog_t *wdt, rt_uint16_t oflag)
+{
+    rt_uint32_t level;
+
+    level = rt_hw_interrupt_disable();
+    /* enable IRC40K */
+    rcu_osci_on(RCU_IRC40K);
+    /* wait till IRC40K is ready */
+    while (SUCCESS != rcu_osci_stab_wait(RCU_IRC40K));
+    fwdgt_counter_reload();
+    fwdgt_enable();
+    rt_hw_interrupt_enable(level);
+
+    return RT_EOK;
+}
+
+static rt_err_t gd32_wdog_init(rt_watchdog_t *wdt)
+{
+    /* confiure FWDGT counter clock: 40KHz(IRC40K) / 256 = 0.15625 KHz */
+    fwdgt_config(FWDGT_RLD_RLD, FWDGT_PSC_DIV256);
+    fwdgt_enable();
+    return RT_EOK;
+}
+
+static rt_err_t gd32_wdog_refresh(rt_watchdog_t *wdt)
+{
+    rt_uint32_t level;
+
+    level = rt_hw_interrupt_disable();
+    fwdgt_counter_reload();
+    rt_hw_interrupt_enable(level);
+
+    return RT_EOK;
+}
+
+/**
+ * @function control wdog
+ *
+ * @param
+ *    wdt  whick wdog used
+ *    cmd  control wdog options
+ *    args argument of conrtol
+ * @retval rt_err_t the status of control result
+ *
+ *
+ */
+#define WDT_RELOAD_SECOND       ((FWDGT_RLD & FWDGT_RLD_RLD) / 156)
+static rt_err_t gd32_wdog_control(rt_watchdog_t *wdt, int cmd, void *args)
+{
+    RT_ASSERT(wdt != NULL);
+
+    uint16_t reload_value;
+    static uint16_t wdt_started = 0;
+    static rt_tick_t last_tick = 0;
+
+    switch (cmd)
+    {
+    case RT_DEVICE_CTRL_WDT_GET_TIMEOUT:
+    {
+        *(uint16_t *)args = WDT_RELOAD_SECOND;
+    }
+    break;
+    case RT_DEVICE_CTRL_WDT_SET_TIMEOUT:
+    {
+        RT_ASSERT(*(uint16_t *)args != 0);
+        reload_value = *(uint16_t *)args;
+        // 6.4ms 1 tick, 1s -> 1000 / 6.4 = 625 / 4 ticks
+        reload_value = ((uint32_t)reload_value * 625) / 4;
+        fwdgt_write_enable();
+        while (FWDGT_STAT & FWDGT_STAT_RUD);
+        FWDGT_RLD = FWDGT_RLD_RLD & reload_value;
+        fwdgt_write_disable();
+    }
+    break;
+    case RT_DEVICE_CTRL_WDT_GET_TIMELEFT:
+        *(uint16_t *)args = WDT_RELOAD_SECOND - \
+                            (rt_tick_get() - last_tick) / RT_TICK_PER_SECOND;
+
+        break;
+    case RT_DEVICE_CTRL_WDT_KEEPALIVE:
+    {
+        last_tick = rt_tick_get();
+        gd32_wdog_refresh(wdt);
+    }
+    break;
+    case RT_DEVICE_CTRL_WDT_START:
+    {
+        gd32_wdog_open(wdt, *(rt_uint32_t *)args);
+        last_tick = rt_tick_get();
+        wdt_started = 1;
+        while (FWDGT_STAT & FWDGT_STAT_RUD);
+    }
+    break;
+    case RT_DEVICE_CTRL_WDT_STOP:
+    {
+        gd32_wdog_close(wdt);
+        wdt_started = 0;
+    }
+    break;
+    default:
+        return RT_EINVAL;
+    }
+
+    return RT_EOK;
+}
+
+static struct rt_watchdog_ops gd32_wdog_ops =
+{
+    .init = gd32_wdog_init,
+    .control = gd32_wdog_control,
+};
+
+static struct rt_watchdog_device gd32_wdt_device;
+
+int rt_hw_wdt_init(void)
+{
+    int result = RT_EOK;
+
+    rcu_osci_off(RCU_IRC40K);
+    gd32_wdt_device.ops = &gd32_wdog_ops;
+    result = rt_hw_watchdog_register(&gd32_wdt_device, "wdt", \
+                                     RT_DEVICE_FLAG_RDWR, (void *)FWDGT);
+
+    return result;
+}
+
+INIT_DEVICE_EXPORT(rt_hw_wdt_init);
+
+#endif /* BSP_USING_WDT */
+

+ 20 - 0
bsp/nuclei/libraries/gd32vf103/HAL_Drivers/drv_wdt.h

@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2006-2020, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2029-06-08     hqfang       first implementation.
+ */
+
+#ifndef __DRV_WDT__
+#define __DRV_WDT__
+
+#include <rtthread.h>
+#include <rtdevice.h>
+#include <rthw.h>
+#include <drv_config.h>
+
+
+#endif

+ 1 - 2
bsp/nuclei/tools/sdk_dist.py

@@ -5,11 +5,10 @@ cwd_path = os.getcwd()
 sys.path.append(os.path.join(os.path.dirname(cwd_path), 'rt-thread', 'tools'))
 
 # BSP dist function
-def dist_do_building(BSP_ROOT):
+def dist_do_building(BSP_ROOT, dist_dir):
     from mkdist import bsp_copy_files
     import rtconfig
 
-    dist_dir  = os.path.join(BSP_ROOT, 'dist', os.path.basename(BSP_ROOT))
     library_dir  = os.path.join(dist_dir, 'libraries')
 
     print("=> copy nuclei bsp library")