提交 7761923e 编写于 作者: 嵌入式AIoT's avatar 嵌入式AIoT

bsp/nuclei: Add more drivers support for gd32vf103_rvstar board

Squashed commit of the following:

commit 32dd349ccff85cdcad81021b5185f8f7347786db
Author: Huaqi Fang <578567190@qq.com>
Date:   Thu Jun 11 16:08:08 2020 +0800

    bsp/nuclei: Add more documentation about how to use RT-Thread in RV-STAR
Signed-off-by: 嵌入式AIoT's avatarHuaqi Fang <578567190@qq.com>

commit c9474c20a558e9d7934a3d72cc9bb17a98c20871
Author: Huaqi Fang <578567190@qq.com>
Date:   Thu Jun 11 14:06:42 2020 +0800

    bsp/nuclei: remove comments in rt_hw_*_drvinit
Signed-off-by: 嵌入式AIoT's avatarHuaqi Fang <578567190@qq.com>

commit 89b5caa2c3e55dc352b13f8e33229f03351b7049
Author: Huaqi Fang <578567190@qq.com>
Date:   Thu Jun 11 13:52:12 2020 +0800

    bsp/nuclei: Add a entry README.md for nuclei bsp
Signed-off-by: 嵌入式AIoT's avatarHuaqi Fang <578567190@qq.com>

commit ae50d6e9bdc92ca4767c5ac7d0ded7252314a42e
Author: Huaqi Fang <578567190@qq.com>
Date:   Thu Jun 11 11:52:52 2020 +0800

    bsp/nuclei: update README.md cover more pinmux section
Signed-off-by: 嵌入式AIoT's avatarHuaqi Fang <578567190@qq.com>

commit 1a42d85dfe5bc7b009f057784249d54d0c82de0f
Author: Huaqi Fang <578567190@qq.com>
Date:   Thu Jun 11 08:52:06 2020 +0800

    bsp/nuclei: clean up unused code in drv_spi.c
Signed-off-by: 嵌入式AIoT's avatarHuaqi Fang <578567190@qq.com>

commit b40edcdf59c96ef261f65a0c023a24ac78cabb39
Author: Huaqi Fang <578567190@qq.com>
Date:   Wed Jun 10 14:09:15 2020 +0800

    bsp/nuclei: Format the code comments for hw pinmux init
Signed-off-by: 嵌入式AIoT's avatarHuaqi Fang <578567190@qq.com>

commit c8ae9fdfdb989bbff85d911fee3124abd9d145db
Author: Huaqi Fang <578567190@qq.com>
Date:   Mon Jun 8 17:12:43 2020 +0800

    bsp/nuclei: Add more drivers support for gd32vf103

    * More drivers are supported for rvstar board, see README.md
    * If user want to use these supported drivers, menuconfig is required
    * User also need to setup pinmux for its coresponding driver in
    board/board.c
Signed-off-by: 嵌入式AIoT's avatarHuaqi Fang <578567190@qq.com>
Signed-off-by: 嵌入式AIoT's avatarHuaqi Fang <578567190@qq.com>
上级 0a7e38c5
# 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)
\ No newline at end of file
......@@ -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
......
......@@ -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模块进行功能实现,所以在使用驱动时,请务必注意不要重叠使用相同模块。
## 联系人信息
......
......@@ -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')
......
......@@ -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"
......
......@@ -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 *******************/
......
......@@ -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 */
......
......@@ -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)
......@@ -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)
......
/*
* 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 */
/*
* 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
......@@ -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 */
/*
* 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 */
/*
* 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
/*
* 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 */
/*
* 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
/*
* 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 */
/*
* 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
/*
* 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 */
/*
* 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
/*
* 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 */
/*
* 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
......@@ -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;
......
......@@ -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);
......
/*
* 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 */
/*
* 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
......@@ -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")
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册