GD32 RISC-V系列 BSP框架制作与移植

发布者:VelvetDreamer最新更新时间:2024-11-04 来源: elecfans关键字:GD32  移植 手机看文章 扫描二维码
随时随地手机看文章

熟悉RT-Thread的朋友都知道,RT-Thread提供了许多BSP,但不是所有的板子都能找到相应的BSP,这时就需要移植新的BSP。RT-Thread的所有BSP中,最完善的BSP就是STM32系列,但从2020年下半年开始,国内出现史无前例的芯片缺货潮,芯片的交期和价格不断拉升,STM32的价格也是水涨船高,很多朋友也在考虑使用国产替代,笔者使用的兆易创新的GD32系列,我看了下RT-Thread中GD系列BSP,都是玩家各自为政,每个人都是提交自己使用的板子的BSP,充斥着大量冗余的代码,对于有强迫症的我就非常不爽,就根据手头的板子,参看STM32的BSP架构,构建了GD32的BSP架构。


目前笔者已经完成了ARM架构和RISC-V架构的移植,关于ARM架构的移植可以看我以前的文章,本文将要讲解基于RISC-V架构的移植。


笔者使用的开发板是兆易创新设计的GD32VF103V-SEVAL开发板。其主控芯片为GD32VF103VB,主频 108MHz,128KB FLASH,32KB RAM,资源还算丰富。

pYYBAGKy-yaAZMK1AAHDDFLltVo796.png?imageView2/2/w/1000


1 BSP框架制作

在具体移植GD32VF103V-SEVAL的BSP之前,先做好GD32 RISC-V系列的BSP架构。BSP框架结构如下图所示:

poYBAGKy-zKAOvYGAACIroKhBts181.png?imageView2/2/w/1000

BSP架构主要分为三个部分:libraries、tools和具体的Boards,其中libraries包含了GD32的通用库,包括每个系列的Firmware Library以及适配RT-Thread的drivers;tools是生成工程的Python脚本工具;另外就是Boards文件,当然这里的Boards有很多,我这里值列举了GD32VF103V-SEVAL。

这里先谈谈libraries和tools的构建,然后在后文单独讨论具体板级BSP的制作。


1.1 Libraries构建

Libraries文件夹包含兆易创新提供的固件库,这个直接在兆易创新的官网就可以下载。

下载地址:http://www.gd32mcu.com/cn/download/

然后将GD32VF103_Firmware_Library复制到libraries目录下,其他的系列类似。

pYYBAGKy-z2AXxdDAAAvrJRX3BE603.png?imageView2/2/w/1000

GD32VF103_Firmware_Library就是官方的文件,基本是不用大改,这里先在在文件夹中需要添加构建工程的脚本文件SConscript,其实也就是Python脚本。后面具体讲解需要修改的地方。

pYYBAGKy-02AYQceAABZ4zU-8Wg632.png?imageView2/2/w/1000

SConscript文件的内容如下:

import rtconfig

from building import *


# get current directory

cwd = GetCurrentDir()


# The set of source files associated with this SConscript file.

cwd = GetCurrentDir()


src = Split('''

RISCV/env_Eclipse/handlers.c

RISCV/env_Eclipse/init.c

RISCV/env_Eclipse/your_printf.c

RISCV/drivers/n200_func.c

GD32VF103_standard_peripheral/system_gd32vf103.c

GD32VF103_standard_peripheral/Source/gd32vf103_gpio.c

GD32VF103_standard_peripheral/Source/gd32vf103_rcu.c

GD32VF103_standard_peripheral/Source/gd32vf103_exti.c

GD32VF103_standard_peripheral/Source/gd32vf103_eclic.c

''')

   

if GetDepend(['RT_USING_SERIAL']):

    src += ['GD32VF103_standard_peripheral/Source/gd32vf103_usart.c']

   

if GetDepend(['RT_USING_I2C']):

    src += ['GD32VF103_standard_peripheral/Source/gd32vf103_i2c.c']


if GetDepend(['RT_USING_SPI']):

    src += ['GD32VF103_standard_peripheral/Source/gd32vf103_spi.c']


if GetDepend(['RT_USING_CAN']):

    src += ['GD32VF103_standard_peripheral/Source/gd32vf103_can.c']


if GetDepend(['BSP_USING_ETH']):

    src += ['GD32VF103_standard_peripheral/Source/gd32vf103_enet.c']


if GetDepend(['RT_USING_ADC']):

    src += ['GD32VF103_standard_peripheral/Source/gd32vf103_adc.c']


if GetDepend(['RT_USING_DAC']):

    src += ['GD32VF103_standard_peripheral/Source/gd32vf103_dac.c']


if GetDepend(['RT_USING_HWTIMER']):

    src += ['GD32VF103_standard_peripheral/Source/gd32vf103_timer.c']


if GetDepend(['RT_USING_RTC']):

    src += ['GD32VF103_standard_peripheral/Source/gd32vf103_rtc.c']

    src += ['GD32VF103_standard_peripheral/Source/gd32vf103_pmu.c']


if GetDepend(['RT_USING_WDT']):

    src += ['GD32VF103_standard_peripheral/Source/gd32vf103_wwdgt.c']

    src += ['GD32VF103_standard_peripheral/Source/gd32vf103fwdgt.c']


path = [

    cwd + '/RISCV/drivers',

    cwd + '/GD32VF103_standard_peripheral',

    cwd + '/GD32VF103_standard_peripheral/Include',]


group = DefineGroup('Libraries', src, depend = [''], CPPPATH = path)


Return('group')

该文件主要的作用就是添加库文件和头文件路径,一部分文件是属于基础文件,因此直接调用Python库的Split包含,另外一部分文件是根据实际的应用需求添加的。


这里是以GD32VF1来举例的,其他系列的都是类似的。


接下来说说Kconfig文件,这里是对内核和组件的功能进行配置,对RT-Thread的组件进行自由裁剪。


如果使用ENV环境,则在使用 menuconfig配置和裁剪 RT-Thread时体现。

poYBAGKxy_qAAKaAAADWXQnSAxc666.png?imageView2/2/w/1000

后面所有的Kconfig文件都是一样的逻辑。下表列举一些常用的Kconfig句法规则。

关键词说明
config此关键字定义了一新的配置选项
menuconfig此关键字和前面的关键字很相似,但它在前面的基础上要求所有的子选项作为独立的行显示。
choice/endchoice该关键字定义了一组选择项。
comment这里定义了在配置过程中显示给用户的注释,该注释还将写进输出文件中。格式说明: comment 'eg: description content'
menu / endmenu这里定义了一个菜单,所有依赖于此菜单的选项都是它的子选项。
if/endif这里定义了if结构。
source读取其他具体的配置文件,其他配置文件会被解析。

Kconfig的语法规则网上资料很多,自行去学习吧。

bsp/gd32/risc-v/libraries/Kconfig内容如下:

config SOC_FAMILY_GD32

    bool


config SOC_GD32VF103V

    bool

    select SOC_SERIES_GD32VF103V

    select SOC_FAMILY_GD32


最后谈谈gd32_drivers,这个文件夹就是GD32的外设驱动文件夹,为上层应用提供调用接口。

poYBAGKy-3eAfKUMAACv920wGQY383.png?imageView2/2/w/1000

该文件夹是整个GD32共用的,因此在编写和修改都要慎重。关于drv_xxx文件在后句具体移植BSP的时候讲解,这里主要将整体架构,SConscript和Kconfig的作用和前面的一样,只是具体的内容不同罢了。

好了,先看bsp/gd32/risc-v/libraries/gd32_drivers/SConscript文件。


Import('RTT_ROOT')

Import('rtconfig')

from building import *


cwd = GetCurrentDir()


# add the general drivers.

src = Split('''

''')


# add pin drivers.

if GetDepend('RT_USING_PIN'):

    src += ['drv_gpio.c']


# add usart drivers.

if GetDepend(['RT_USING_SERIAL']):

    src += ['drv_usart.c']


# add i2c drivers.

if GetDepend(['RT_USING_I2C', 'RT_USING_I2C_BITOPS']):

    if GetDepend('BSP_USING_I2C0') or GetDepend('BSP_USING_I2C1') or GetDepend('BSP_USING_I2C2') or GetDepend('BSP_USING_I2C3'):

        src += ['drv_soft_i2c.c']


# add spi drivers.

if GetDepend('RT_USING_SPI'):

    src += ['drv_spi.c']


# add spi flash drivers.

if GetDepend('RT_USING_SFUD'):

    src += ['drv_spi_flash.c', 'drv_spi.c']


# add wdt drivers.

if GetDepend('RT_USING_WDT'):

    src += ['drv_wdt.c']


# add rtc drivers.

if GetDepend('RT_USING_RTC'):

    src += ['drv_rtc.c']


# add timer drivers.

if GetDepend('RT_USING_HWTIMER'):

    src += ['drv_hwtimer.c']


# add adc drivers.

if GetDepend('RT_USING_ADC'):

    src += ['drv_adc.c']


path = [cwd]


group = DefineGroup('Drivers', src, depend = [''], CPPPATH = path)


Return('group')

和GD32VF103_Firmware_Library文件夹中的SConscript是类似的。


bsp/gd32/risc-v/libraries/gd32_drivers/Kconfig文件结构如下:


if BSP_USING_USBD

    config BSP_USBD_TYPE_FS

        bool

        # 'USB Full Speed (FS) Core'

endif

1.2 Tools构建

该文件夹就是工程构建的脚本,


import os

import sys

import shutil


cwd_path = os.getcwd()

sys.path.append(os.path.join(os.path.dirname(cwd_path), 'rt-thread', 'tools'))


def bsp_update_board_kconfig(dist_dir):

    # change board/kconfig path

    if not os.path.isfile(os.path.join(dist_dir, 'board/Kconfig')):

        return


    with open(os.path.join(dist_dir, 'board/Kconfig'), 'r') as f:

        data = f.readlines()

    with open(os.path.join(dist_dir, 'board/Kconfig'), 'w') as f:

        for line in data:

            if line.find('../libraries/gd32_drivers/Kconfig') != -1:

                position = line.find('../libraries/gd32_drivers/Kconfig')

                line = line[0:position] + 'libraries/gd32_drivers/Kconfig'n'

            f.write(line)

           

# BSP dist function

def dist_do_building(BSP_ROOT, dist_dir):

    from mkdist import bsp_copy_files

    import rtconfig


    print('=> copy gd32 bsp library')

    library_dir = os.path.join(dist_dir, 'libraries')

    library_path = os.path.join(os.path.dirname(BSP_ROOT), 'libraries')

    bsp_copy_files(os.path.join(library_path, rtconfig.BSP_LIBRARY_TYPE),

                   os.path.join(library_dir, rtconfig.BSP_LIBRARY_TYPE))


    print('=> copy bsp drivers')

    bsp_copy_files(os.path.join(library_path, 'gd32_drivers'), os.path.join(library_dir, 'gd32_drivers'))

    shutil.copyfile(os.path.join(library_path, 'Kconfig'), os.path.join(library_dir, 'Kconfig'))

   

    bsp_update_board_kconfig(dist_dir)

以上代码很简单,主要使用了Python的OS模块的join函数,该函数的作用就是连接两个或更多的路径名。最后将BSP依赖的文件复制到指定目录下。


在使用scons --dist命令打包的时候,就是依赖的该脚本,生成的dist文件夹的工程到任何目录下使用,也就是将BSP相关的库以及内核文件提取出来,可以将该工程任意拷贝。


需要注意的是,使用scons --dist打包后需要修改board/Kconfig中的库路径,因此这里调用了bsp_update_board_kconfig方法修改。


1.3 gd32vf103v-eval构建

该文件夹就gd32vf103v-eval的具体BSP文件,文件结构如下:

poYBAGKy-6OADNpSAAF0rcbhAzE765.png?imageView2/2/w/1000

在后面将具体讲解如何构建该部分内容。


2 BSP移植

2.1GCC环境准备

RISC-V系列MCU使用的工具链是xPack GNU RISC-V Embedded GCC。

在配置交叉编译工具链之前,需要下载得到GCC工具链的安装包,然后解压即可,也可配置环境变量。

GCC工具链下载地址:https://github.com/xpack-dev-tools/riscv-none-embed-gcc-xpack/releases/

pYYBAGKy-62AaDX4AAEAYWmd8z0776.png?imageView2/2/w/1000

根据自己的主机选择相应的版本,下载完成解压即可。


2.2 BSP工程制作

1.构建基础工程

首先看看RT-Thread代码仓库中已有很多BSP,而我要移植的是RISC-V内核。这里参考GD32 ARM工程。最终目录如下:


risc-v
docs #说明文档
gd32vf103v-eval #具体BSP
libraries #库文件
  gd32_drivers
  GD32VF103_Firmware_Library # GD官方固件库
tools
  OpenOCD # OpenOCD下载调试工具
README.md

2.修改BSP构建脚本

bsp/gd32/risc-v/gd32vf103v-eval/SConstruct修改后的内容如下:

import os

import sys

import rtconfig


if os.getenv('RTT_ROOT'):

    RTT_ROOT = os.getenv('RTT_ROOT')

else:

    RTT_ROOT = os.path.normpath(os.getcwd() + '/../../../..')


sys.path = sys.path + [os.path.join(RTT_ROOT, 'tools')]

try:

    from building import *

except:

    print('Cannot found RT-Thread root directory, please check RTT_ROOT')

    print(RTT_ROOT)

    exit(-1)


TARGET = 'rtthread.' + rtconfig.TARGET_EXT


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,

    LINK = rtconfig.LINK, LINKFLAGS = rtconfig.LFLAGS)

env.PrependENVPath('PATH', rtconfig.EXEC_PATH)

env['ASCOM'] = env['ASPPCOM']


Export('RTT_ROOT')

Export('rtconfig')


SDK_ROOT = os.path.abspath('./')


if os.path.exists(SDK_ROOT + '/libraries'):

    libraries_path_prefix = SDK_ROOT + '/libraries'

[1] [2] [3]
关键字:GD32  移植 引用地址:GD32 RISC-V系列 BSP框架制作与移植

上一篇:GD32 485发送异常最常见原因
下一篇:什么是GD32 MCU读保护?

推荐阅读最新更新时间:2026-03-22 11:36

[单片机框架][bsp层][N32G4FR][bsp_flash] flash配置和使用
FLASH 规格 Flash 由主存储区、信息区组成,以下分别进行说明: (以下说明中的容量值不含 ECC)  主存储区最大为 512KB,也称作主闪存存储器,包含 256 个 Page,用于用户程序的存放和运行,以及数据存储。  信息区为 20KB,包含 10 个 Page,由系统存储区(16KB) 、系统配置区(2KB) 、选项字节区(2KB) 组成:  系统存储区为 16KB,包含 8 个 Page,也称作 System Memory,用于引导程序(BOOT)的存放和运行。  系统配置区为 2KB,包含 1 个 Page。  选项字节区为 2KB,包含 1 个 Page,也称作 OptionByte,有效空间为 1
[单片机]
[单片机<font color='red'>框架</font>][<font color='red'>bsp</font>层][N32G4FR][<font color='red'>bsp</font>_flash] flash配置和使用
[单片机框架][bsp层][N32G4FR][bsp_adc] ADC配置和使用
ADC 介绍 12 位 ADC 是一种高速逐次逼近型模拟数字转换器。它有多个通道。各通道的 A/D 转换可以单次、连续、 扫描或间断模式执行。ADC 的结果可以左对齐或右对齐方式存储在 16 位数据寄存器中。 模拟看门狗特性允许应用程序检测输入电压是否超出用户定义的高/低阀值。 ADC 的输入时钟不得超过 72MHz。 ADC 主要特征  支持最多 2 个 ADC,支持单端输入和差分输入,可测量 16 个外部和 3 个内部信号源  ADC1 支持 9 个外部通道,ADC2 支持 7 个外部通道  支持 12 位、10 位、8 位、6 位分辨率可配置  12bit 分辨率下最高采样速率 5.14MSPS  10bit 分
[单片机]
[单片机<font color='red'>框架</font>][<font color='red'>bsp</font>层][N32G4FR][<font color='red'>bsp</font>_adc] ADC配置和使用
[单片机框架][bsp层][cx32l003][bsp_exti] EXTI配置和使用
一、 主体不同 内部中断:断是一个算法指令,是由软中断指令启动的中断。 外部中断:是单片机实时地处理外部事件的一种内部机制。 二、机制不同 内部中断:执行除法指令时,出现除数为0或商超过寄存器所能表达的范围,则产生类型为0 的内部中断。是优先级最高的内部中断。 外部中断:当某种外部事件发生时,单片机的中断系统将迫使CPU暂停正在执行的程序,转而去进行中断事件的处理;中断处理完毕后.又返回被中断的程序处,继续执行下去。 /******************************************************************************** * @file bsp_exti.
[单片机]
[单片机框架][bsp层][cx32l003][bsp_flash] FLASH配置和使用
本芯片包含 1 颗 64K / 32K Byte 容量的嵌入式 Flash 存储器,包括一个 128 / 64 sector 的 Main Array区域,一个 8 sector 的 NVR 区域。每个 sector 的容量为 512 Byte。Flash 的 Main Array 区域是给用户使用的, 可以存放用户开发的程序和数据。 NVR 区域中, 一个 sector 用于存放系统配置, 一个 sector用于存放选项字节,其余的 6 个 sector 用于存放系统的 ISP 程序。本模块支持对 Flash 存储器的擦除、编程以及读取操作。此外,本模块支持对 Flash 存储器擦写的保护,以及控制寄存器的写保护。 Main
[单片机]
[单片机<font color='red'>框架</font>][<font color='red'>bsp</font>层][cx32l003][<font color='red'>bsp</font>_flash] FLASH配置和使用
[单片机框架][bsp层][cx32l003][bsp_led] LED配置和使用
LED是一种半导体器件,大家其实对LED并不陌生,各种电器的指示灯、手机键盘灯、LED液晶屏的背光、高亮LED手电筒等,都是通过LED发光的。LED有两种主要用途,一种是作为指示灯;另一种是照明。照明用的LED一般都是大功率LED,需要较大的电压电流才能正常工作。而这里我们要用到的则是用作指示灯的小功率LED。常见的小功率LED,在它的正负极加上3V左右的电压,就会发光,正常发光的时候,电流大概是2~5mA。这里要注意,LED有正负极之分,接反了不会发光。另外,电压也不可太高,那样会烧坏LED。 /*****************************************************************
[单片机]
[单片机框架][bsp层][cx32l003][bsp_crc] 硬件CRC配置和使用
循环冗余校验(CRC)计算单元是根据固定的生成多项式得到任意字节数据的 CRC 计算结果。在应用中, CRC 技术主要应用于核实数据传输或者数据存储的正确性和完整性。 本模块算法遵从 ISO/IEC13239 的定义,采用 16 位长度的 CRC,计算多项式为: 计算初始值为 0xFFFF。 本模块功能包括: ⚫ CRC 编码和 CRC 校验 ⚫ 3 种位宽访问方式:8 位、16 位、32 位 ⚫ 8 位位宽下输入数据示例为 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77 ⚫ 16 位位宽下输入数据示例为 0x1100, 0x3322, 0x5544, 0x7766 ⚫ 32
[单片机]
[单片机框架][bsp层][cx32l003][bsp_key] KEY配置和使用
按键的基本原理是设置单片机IO口(PB0-PB3)为输入状态,如DDRB = 0XF0(方向寄存器,“1”为输出,“0”为输入); 单片机一直检测按键端口(PB0-PB3)的状态,当端口为低电平时(即按键按下),实行相应的动作(比如控制LED灯)。 原理就是这么回事,但是正真实现时,按键会有抖动,要进行按键去抖,下图为按键按下时的抖动图。 按键实行一个动作过程是需要一定时间的,一般为100mS-1S左右,而一个单片机执行一个机器周期的时间很短,时钟为10MH的周期为0.1μs,这样按键每一次动作程序就会多次检测按键,出现误判(一次按下,多次动作)。 /********************************
[单片机]
[单片机框架][bsp层][cx32l003][bsp_i2c] I2C/IIC硬件配置和使用
I2C 简介 I2C 是双线双向的串行总线,它为设备之间数据交换提供了一种简单高效的方法。I2C 标准是一个具有冲突检测机制和仲裁机制的真正意义上的多主机总线。它能防止两个或者多个主机在同时请求控制总线时发生数据冲突。 I2C 总线控制器,能满足 I2C 总线的各种规格并支持所有与 I2C 总线通信的传输模式。 I2C 总线使用连接设备的 SCL (串行时钟总线)和 SDA (串行数据总线)来传送信息。数据在主机与从机之间通过 SCL 时钟线控制在 SDA 数据线上实现一个字节一个字节的同步传输, 每个字节为 8位长度,一个 SCL 时钟脉冲传输一个数据位,数据由最高位 MSB 开始传输,每个传输字节后跟随一个应答位, 每
[单片机]
[单片机<font color='red'>框架</font>][<font color='red'>bsp</font>层][cx32l003][<font color='red'>bsp</font>_i2c] I2C/IIC硬件配置和使用
小广播
最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

厂商技术中心

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

 
机器人开发圈

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2026 EEWORLD.com.cn, Inc. All rights reserved