[domestic MCU transplantation] teach you how to use RT thread to make gd32 series BSP

Time:2021-12-29

This article was originally published by RT thread forum user @ Bruce ou:https://club.rt-thread.org/ask/article/3043.html

Friends familiar with RT thread know that RT thread provides many BSPs, but not all boards can find corresponding BSPs. At this time, it is necessary to transplant new BSPs. Among all the BSPs of RT thread, the most perfect BSP is the STM32 series. However, since the second half of 2020, there has been an unprecedented shortage of chips in China, and the delivery date and price of chips have been rising. The price of STM32 is also rising. Many friends are also considering using domestic alternatives. The author uses Zhaoyi innovative gd32 series. I have seen the GD series BSPs in RT thread, Players do their own things. Everyone submits the BSP of their own board, which is filled with a lot of redundant code. I am very unhappy with obsessive-compulsive disorder. According to the board at hand, refer to the BSP architecture of STM32 to build the BSP architecture of gd32.

The development board used by the author is the gd32407v-start development board designed by Zhaoyi innovation. The main control chip is gd32f407vkt6, the main frequency is 168mhz, the internal 3072k flash and 192kb SRAM are very rich in resources.
[domestic MCU transplantation] teach you how to use RT thread to make gd32 series BSP

1 BSP frame fabrication

Before transplanting the BSP of gd32407v-start, first complete the BSP architecture of gd32. The BSP frame structure is shown in the figure below:
[domestic MCU transplantation] teach you how to use RT thread to make gd32 series BSP

The BSP architecture of gd32 is mainly divided into three parts: libraries, tools and specific boards. Libraries contains the general library of gd32, including Hal of each series and drivers adapted to RT thread; Tools is a python script tool for generating projects; The other is the boards file. Of course, there are many boards here. I listed gd32407v-start.

Let’s talk about the construction of libraries and tools first, and then discuss the production of specific board level BSP separately later.

1.1 construction of Libraries

The libraries folder contains the Hal library provided by Zhaoyi innovation, which can be downloaded directly on the official website of Zhaoyi innovation.

Download address

Then copy the Hal library to the libraries directory and rename it gd32f4xx_ Hal, other series are similar.

[domestic MCU transplantation] teach you how to use RT thread to make gd32 series BSP

GD32F4xx_ Hal is an official file. It basically doesn’t need to be moved, but the script file sconscript of the construction project needs to be added in the folder, which is actually a python script.

[domestic MCU transplantation] teach you how to use RT thread to make gd32 series BSP

The contents of the sconscript file are as follows:

Import rtconfig # import package
from building import *

# get current directory
CWD = getcurrentdir() # get path

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

src = Split('''
CMSIS/GD/GD32F4xx/Source/system_gd32f4xx.c
GD32F4xx_standard_peripheral/Source/gd32f4xx_gpio.c
GD32F4xx_standard_peripheral/Source/gd32f4xx_rcu.c
GD32F4xx_standard_peripheral/Source/gd32f4xx_exti.c
GD32F4xx_standard_peripheral/Source/gd32f4xx_misc.c
GD32F4xx_standard_peripheral/Source/gd32f4xx_syscfg.c
'' '# splits the string in parentheses into a list for inclusion in the project
    
If getappend (['rt_using_serial ']): # if RT is turned on_ USING_ Macro of serial, the following source files will be included
    src += ['GD32F4xx_standard_peripheral/Source/gd32f4xx_usart.c']
    
if GetDepend(['RT_USING_I2C']):
    src += ['GD32F4xx_standard_peripheral/Source/gd32f4xx_i2c.c']

if GetDepend(['RT_USING_SPI']):
    src += ['GD32F4xx_standard_peripheral/Source/gd32f4xx_spi.c']

if GetDepend(['RT_USING_CAN']):
    src += ['GD32F4xx_standard_peripheral/Source/gd32f4xx_can.c']

if GetDepend(['BSP_USING_ETH']):
    src += ['GD32F4xx_standard_peripheral/Source/gd32f4xx_enet.c']

if GetDepend(['RT_USING_ADC']):
    src += ['GD32F4xx_standard_peripheral/Source/gd32f4xx_adc.c']

if GetDepend(['RT_USING_DAC']):
    src += ['GD32F4xx_standard_peripheral/Source/gd32f4xx_dac.c']

if GetDepend(['RT_USING_RTC']):
    src += ['GD32F4xx_standard_peripheral/Source/gd32f4xx_rtc.c']

if GetDepend(['RT_USING_WDT']):
    src += ['GD32F4xx_standard_peripheral/Source/gd32f4xx_wwdgt.c']
    src += ['GD32F4xx_standard_peripheral/Source/gd32f4xx_fwdgt.c']

if GetDepend(['RT_USING_SDIO']):
    src += ['GD32F4xx_standard_peripheral/Source/gd32f4xx_sdio.c']

#Header file path
path = [
    cwd + '/CMSIS/GD/GD32F4xx/Include',
    cwd + '/CMSIS',
    cwd + '/GD32F4xx_standard_peripheral/Include',]

CPPDEFINES = ['USE_STDPERIPH_DRIVER']
#Define a group. The group name is' Libraries'. If the dependent is empty, it means that it depends on any other macro. In addition, the current header file path is added to the project
group = DefineGroup('Libraries', src, depend = [''], CPPPATH = path, CPPDEFINES = CPPDEFINES)

Return('group')

The main function of this file is to add library files and header file paths. Some files belong to basic files, so you can directly call the split inclusion of Python library, and some files are added according to the actual application requirements.

Here is an example of gdf4. Other series are similar.

Next, let’s talk about the kconfig file, which configures the functions of the kernel and components, and freely cuts the components of RT thread.
If RT thread studio is used, the role of kconfig file can be reflected through RT thread setting.

[domestic MCU transplantation] teach you how to use RT thread to make gd32 series BSP

If env environment is used, it is reflected when configuring and clipping RT thread using menuconfig.

[domestic MCU transplantation] teach you how to use RT thread to make gd32 series BSP

All subsequent kconfig files have the same logic. The following table lists some common kconfig syntax rules.

[domestic MCU transplantation] teach you how to use RT thread to make gd32 series BSP

Kconfig has a lot of grammar rules on the Internet. Learn them by yourself.

The contents of BSP / gd32 / kconfig are as follows:

config SOC_FAMILY_GD32
    bool

config SOC_SERIES_GD32F4
    bool
    select ARCH_ARM_CORTEX_M4
    select SOC_FAMILY_GD32

At present, the author only transplants gdf4, so there is little content here. If there are some series, just refer to the configuration example of F4 directly and add it here.

Finally, talk about Hal_ Drivers, this folder is the peripheral driver folder of gd32, which provides a call interface for upper layer applications.

[domestic MCU transplantation] teach you how to use RT thread to make gd32 series BSP

At present, there are only serial port and GPIO drivers. This folder is shared by the whole gd32, so you should be careful in writing and modifying. About DRV_ XXX file will be explained when transplanting BSP in the following sentence. Here, the overall architecture, the functions of sconscript and kconfig are the same as those in the previous sentence, but the specific contents are different.

OK, first look at BSP / gd32 / Hal_ Drivers / sconscript file.

Import('RTT_ROOT')
Import('rtconfig')
from building import *

CWD = getcurrentdir() # get current path

# add the general drivers.
src = Split("""
"" ") # add a common driver file, no

# add pin drivers.
if GetDepend('RT_USING_PIN'):
    src += ['drv_gpio.c']
    
if GetDepend(['RT_USING_SERIAL']):
    src += ['drv_usart.c']

path =  [cwd]

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

Return('group')

And gd32f4xx_ The sconscript in the Hal folder is similar.

bsp/gd32/HAL_ The drivers / kconfig file structure is as follows:

if BSP_USING_USBD
    config BSP_USBD_TYPE_FS
        bool
        # "USB Full Speed (FS) Core"
    config BSP_USBD_TYPE_HS
        bool
        # "USB High Speed (HS) Core"

    config BSP_USBD_SPEED_HS
        bool 
        # "USB High Speed (HS) Mode"
    config BSP_USBD_SPEED_HSINFS
        bool 
        # "USB High Speed (HS) Core in FS mode"

    config BSP_USBD_PHY_EMBEDDED
        bool 
        # "Using Embedded phy interface"
    config BSP_USBD_PHY_UTMI
        bool 
        # "UTMI: USB 2.0 Transceiver Macrocell Interace"
    config BSP_USBD_PHY_ULPI
        bool 
        # "ULPI: UTMI+ Low Pin Interface"
endif

1.2 tools build

This folder is the script of project construction,

import os
import sys
import shutil

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, 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, 'HAL_Drivers'), os.path.join(library_dir, 'HAL_Drivers'))
    shutil.copyfile(os.path.join(library_path, 'Kconfig'), os.path.join(library_dir, 'Kconfig'))

The above code is very simple. It mainly uses the join function of Python OS module, which is used to connect two or more pathnames. Finally, copy the BSP dependent files to the specified directory.

When using the scons — dist command to package, it depends on the script. The project in the generated dist folder can be used in any directory, that is, the BSP related library and kernel files can be extracted, and the project can be copied arbitrarily.
[domestic MCU transplantation] teach you how to use RT thread to make gd32 series BSP

1.3 gd32407v start build

This folder contains the specific BSP files of gd32407v start. The file structure is as follows:
[domestic MCU transplantation] teach you how to use RT thread to make gd32 series BSP

How to build this part will be explained in detail later.

2 BSP transplantation

2.1 keil environmental preparation

At present, the MDK for arm versions commonly used in the market include keil 4 and keil 5: it is recommended to install 4.74 or above when using keil 4; Using keil 5, it is recommended to install version 5.20 or above. The author’s MDK is 5.30.

You can download the MDK installation package from MDK’s official website, and then install it. For MDK installation, please see the author’s tutorial.
MDK installation tutorial:https://blog.csdn.net/bruceox…
MDK download address:https://www.keil.com/download…

[domestic MCU transplantation] teach you how to use RT thread to make gd32 series BSP

It will open automatically after installation, and we will close it.

Next, we download the software support package for gd32f30x.

Download address:http://www.gd32mcu.com/cn/dow…

[domestic MCU transplantation] teach you how to use RT thread to make gd32 series BSP

After downloading, double-click gigadevice GD32F4xx_ DFP. 2.1. 0.pack can be run:

[domestic MCU transplantation] teach you how to use RT thread to make gd32 series BSP

Click [next] to complete the installation.

[domestic MCU transplantation] teach you how to use RT thread to make gd32 series BSP

After successful installation, re open KEIL, and the drop-down option of gigadevice appears in file – > device database. Click to view the corresponding model.

[domestic MCU transplantation] teach you how to use RT thread to make gd32 series BSP

2.2 BSP engineering production

1. Construction of foundation works
First of all, there are many BSPs in the RT thread code warehouse, and I want to migrate the cortex-m4 kernel. Here I found a similar kernel, copied it, and changed the file name to gd32407v start. In this way, there is a basic project. Then start adding, deleting, modifying and checking to complete the final BSP, which is the case for almost all BSP production.

2. Modify BSP build script
The modified contents of BSP / gd32 / gd32407v start / kconfig are as follows:

mainmenu "RT-Thread Configuration"

config BSP_DIR
    string
    option env="BSP_ROOT"
    default "."

config RTT_DIR
    string
    option env="RTT_ROOT"
    default "../../.."

config PKGS_DIR
    string
    option env="PKGS_ROOT"
    default "packages"
 
source "$RTT_DIR/Kconfig"
source "$PKGS_DIR/Kconfig"
source "../libraries/Kconfig"
source "board/Kconfig"

This file is to get kconfig under all paths.

The modified content of BSP / gd32 / gd32407v start / sconscript is as follows:

# for module compiling
import os
Import('RTT_ROOT')
from building import *

cwd = GetCurrentDir()
objs = []
list = os.listdir(cwd)

for d in list:
    path = os.path.join(cwd, d)
    if os.path.isfile(os.path.join(path, 'SConscript')):
        objs = objs + SConscript(os.path.join(d, 'SConscript'))

Return('objs')

This file is used to traverse all folders in the current directory.

The modified contents of BSP / gd32 / gd32407v start / sconstruct are as follows:

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)

if rtconfig.PLATFORM == 'iar':
    env.Replace(CCCOM = ['$CC $CCFLAGS $CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS -o $TARGET $SOURCES'])
    env.Replace(ARFLAGS = [''])
    env.Replace(LINKCOM = env["LINKCOM"] + ' --map rtthread.map')

Export('RTT_ROOT')
Export('rtconfig')

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

if os.path.exists(SDK_ROOT + '/libraries'):
    libraries_path_prefix = SDK_ROOT + '/libraries'
else:
    libraries_path_prefix = os.path.dirname(SDK_ROOT) + '/libraries'

SDK_LIB = libraries_path_prefix
Export('SDK_LIB')

# prepare building environment
objs = PrepareBuilding(env, RTT_ROOT, has_libcpu=False)

gd32_library = 'GD32F4xx_HAL'
rtconfig.BSP_LIBRARY_TYPE = gd32_library

# include libraries
objs.extend(SConscript(os.path.join(libraries_path_prefix, gd32_library, 'SConscript')))

# include drivers
objs.extend(SConscript(os.path.join(libraries_path_prefix, 'HAL_Drivers', 'SConscript')))

# make a building
DoBuilding(TARGET, objs)

This file is used to link all dependent files and call make to compile.

3. Modify development environment information
bsp/gd32/gd32407v-start/cconfig. H the revised content is as follows:

#ifndef CCONFIG_H__
#define CCONFIG_H__
/* Automatically generated file; DO NOT EDIT. */
/* compiler configure file for RT-Thread in GCC*/

#define HAVE_NEWLIB_H 1
#define LIBC_VERSION "newlib 2.4.0"

#define HAVE_SYS_SIGNAL_H 1
#define HAVE_SYS_SELECT_H 1
#define HAVE_PTHREAD_H 1

#define HAVE_FDSET 1
#define HAVE_SIGACTION 1
#define GCC_VERSION_STR "5.4.1 20160919 (release) [ARM/embedded-5-branch revision 240496]"
#define STDC "2011"

#endif

This file is the environment information for compiling BSP and needs to be modified in real time.

4. Modify keil’s formwork works

Double click: template Uvprojx can modify the template project.

Modify to corresponding chip device:

[domestic MCU transplantation] teach you how to use RT thread to make gd32 series BSP

Modify the configuration of flash and ram:

[domestic MCU transplantation] teach you how to use RT thread to make gd32 series BSP

Modify executable name:

[domestic MCU transplantation] teach you how to use RT thread to make gd32 series BSP

Modify the default debugging tool: cmsis-dap debugger.

[domestic MCU transplantation] teach you how to use RT thread to make gd32 series BSP

Modify the programming algorithm: gd32f4xx FMC.

[domestic MCU transplantation] teach you how to use RT thread to make gd32 series BSP

5. Modify board folder
(1) Modify BSP / gd32 / gd32407v start / board / linker_ scripts/link. icf

The revised content is as follows:

/*###ICF### Section handled by ICF editor, don't touch! ****/
/*-Editor annotation file-*/
/* IcfEditorFile="$TOOLKIT_DIR$\config\ide\IcfEditor\cortex_v1_0.xml" */
/*-Specials-*/
define symbol __ICFEDIT_intvec_start__ = 0x08000000;
/*-Memory Regions-*/
define symbol __ICFEDIT_region_ROM_start__ = 0x08000000;
define symbol __ICFEDIT_region_ROM_end__   = 0x082FFFFF;
define symbol __ICFEDIT_region_RAM_start__ = 0x20000000;
define symbol __ICFEDIT_region_RAM_end__   = 0x2002FFFF;
/*-Sizes-*/
define symbol __ICFEDIT_size_cstack__ = 0x2000;
define symbol __ICFEDIT_size_heap__   = 0x2000;
/**** End of ICF editor section. ###ICF###*/

export symbol __ICFEDIT_region_RAM_end__;

define symbol __region_RAM1_start__ = 0x10000000;
define symbol __region_RAM1_end__   = 0x1000FFFF;

define memory mem with size = 4G;
define region ROM_region   = mem:[from __ICFEDIT_region_ROM_start__   to __ICFEDIT_region_ROM_end__];
define region RAM_region   = mem:[from __ICFEDIT_region_RAM_start__   to __ICFEDIT_region_RAM_end__];
define region RAM1_region  = mem:[from __region_RAM1_start__   to __region_RAM1_end__];

define block CSTACK    with alignment = 8, size = __ICFEDIT_size_cstack__   { };
define block HEAP      with alignment = 8, size = __ICFEDIT_size_heap__     { };

initialize by copy { readwrite };
do not initialize  { section .noinit };

keep { section FSymTab };
keep { section VSymTab };
keep { section .rti_fn* };
place at address mem:__ICFEDIT_intvec_start__ { readonly section .intvec };

place in ROM_region   { readonly };
place in RAM_region   { readwrite,
                        block CSTACK, block HEAP };                        
place in RAM1_region  { section .sram };

This file is a link script compiled by IAR. According to gd32f407xx_datasheet_rev2.1, the flash size of gd32f407vkt6 is 3072kb and the SRAM size is 192kb. Therefore, it is necessary to set the starting address and stack size of ROM and ram.

(2) Modify BSP / gd32 / gd32407v start / board / linker_ scripts/link. ld

The revised content is as follows:

/* Program Entry, set to mark it as "used" and avoid gc */
MEMORY
{
    CODE (rx) : ORIGIN = 0x08000000, LENGTH = 3072k /* 3072KB flash */
    DATA (rw) : ORIGIN = 0x20000000, LENGTH =  192k /* 192KB sram */
}
ENTRY(Reset_Handler)
_system_stack_size = 0x200;

SECTIONS
{
    .text :
    {
        . = ALIGN(4);
        _stext = .;
        KEEP(*(.isr_vector))            /* Startup code */
        . = ALIGN(4);
        *(.text)                        /* remaining code */
        *(.text.*)                      /* remaining code */
        *(.rodata)                      /* read-only data (constants) */
        *(.rodata*)
        *(.glue_7)
        *(.glue_7t)
        *(.gnu.linkonce.t*)

        /* section information for finsh shell */
        . = ALIGN(4);
        __fsymtab_start = .;
        KEEP(*(FSymTab))
        __fsymtab_end = .;
        . = ALIGN(4);
        __vsymtab_start = .;
        KEEP(*(VSymTab))
        __vsymtab_end = .;
        . = ALIGN(4);

        /* section information for initial. */
        . = ALIGN(4);
        __rt_init_start = .;
        KEEP(*(SORT(.rti_fn*)))
        __rt_init_end = .;
        . = ALIGN(4);

        . = ALIGN(4);
        _etext = .;
    } > CODE = 0

    /* .ARM.exidx is sorted, so has to go in its own output section.  */
    __exidx_start = .;
    .ARM.exidx :
    {
        *(.ARM.exidx* .gnu.linkonce.armexidx.*)

        /* This is used by the startup in order to initialize the .data secion */
        _sidata = .;
    } > CODE
    __exidx_end = .;

    /* .data section which is used for initialized data */

    .data : AT (_sidata)
    {
        . = ALIGN(4);
        /* This is used by the startup in order to initialize the .data secion */
        _sdata = . ;

        *(.data)
        *(.data.*)
        *(.gnu.linkonce.d*)

        . = ALIGN(4);
        /* This is used by the startup in order to initialize the .data secion */
        _edata = . ;
    } >DATA

    .stack : 
    {
        . = . + _system_stack_size;
        . = ALIGN(4);
        _estack = .;
    } >DATA

    __bss_start = .;
    .bss :
    {
        . = ALIGN(4);
        /* This is used by the startup in order to initialize the .bss secion */
        _sbss = .;

        *(.bss)
        *(.bss.*)
        *(COMMON)

        . = ALIGN(4);
        /* This is used by the startup in order to initialize the .bss secion */
        _ebss = . ;
        
        *(.bss.init)
    } > DATA
    __bss_end = .;

    _end = .;

    /* Stabs debugging sections.  */
    .stab          0 : { *(.stab) }
    .stabstr       0 : { *(.stabstr) }
    .stab.excl     0 : { *(.stab.excl) }
    .stab.exclstr  0 : { *(.stab.exclstr) }
    .stab.index    0 : { *(.stab.index) }
    .stab.indexstr 0 : { *(.stab.indexstr) }
    .comment       0 : { *(.comment) }
    /* DWARF debug sections.
     * Symbols in the DWARF debugging sections are relative to the beginning
     * of the section so we begin them at 0.  */
    /* DWARF 1 */
    .debug          0 : { *(.debug) }
    .line           0 : { *(.line) }
    /* GNU DWARF 1 extensions */
    .debug_srcinfo  0 : { *(.debug_srcinfo) }
    .debug_sfnames  0 : { *(.debug_sfnames) }
    /* DWARF 1.1 and DWARF 2 */
    .debug_aranges  0 : { *(.debug_aranges) }
    .debug_pubnames 0 : { *(.debug_pubnames) }
    /* DWARF 2 */
    .debug_info     0 : { *(.debug_info .gnu.linkonce.wi.*) }
    .debug_abbrev   0 : { *(.debug_abbrev) }
    .debug_line     0 : { *(.debug_line) }
    .debug_frame    0 : { *(.debug_frame) }
    .debug_str      0 : { *(.debug_str) }
    .debug_loc      0 : { *(.debug_loc) }
    .debug_macinfo  0 : { *(.debug_macinfo) }
    /* SGI/MIPS DWARF 2 extensions */
    .debug_weaknames 0 : { *(.debug_weaknames) }
    .debug_funcnames 0 : { *(.debug_funcnames) }
    .debug_typenames 0 : { *(.debug_typenames) }
    .debug_varnames  0 : { *(.debug_varnames) }
}

This file is a link script compiled by GCC. According to gd32f407xx_datasheet_rev2.1, the flash size of gd32f407vkt6 is 3072kb and the SRAM size is 192kb. Therefore, the length of code and data are set to 3072kb and 192kb respectively. Other chips are similar, but the addresses are the same.

(3) Modify BSP / gd32 / gd32407v start / board / linker_ scripts/link. sct

This file is the connection script of MDK. According to the manual gd32f407xx_datasheet_rev2.1, LR needs to be_ Irom1 and ER_ The parameter of irom1 is set to 0x00300000; The size of ram is 192K, so RW needs to be_ The parameter of iram1 is set to 0x00030000.

; *************************************************************
; *** Scatter-Loading Description File generated by uVision ***
; *************************************************************

LR_IROM1 0x08000000 0x00300000  {    ; load region size_region
  ER_IROM1 0x08000000 0x00300000  {  ; load address = execution address
   *.o (RESET, +First)
   *(InRoot$$Sections)
   .ANY (+RO)
  }
  RW_IRAM1 0x20000000 0x00030000  {  ; RW data
   .ANY (+RW +ZI)
  }
}

(4) Modify BSP / gd32 / gd32407v start / board / board H file

The revised content is as follows:

#ifndef __BOARD_H__
#define __BOARD_H__

#include "gd32f4xx.h"
#include "drv_usart.h"
#include "drv_gpio.h"

#include "gd32f4xx_exti.h"

#define EXT_SDRAM_BEGIN    (0xC0000000U) /* the begining address of external SDRAM */
#define EXT_SDRAM_END      (EXT_SDRAM_BEGIN + (32U * 1024 * 1024)) /* the end address of external SDRAM */

// <o> Internal SRAM memory size[Kbytes] <8-64>
//  <i>Default: 64
#ifdef __ICCARM__
// Use *.icf ram symbal, to avoid hardcode.
extern char __ICFEDIT_region_RAM_end__;
#define GD32_SRAM_END          &__ICFEDIT_region_RAM_end__
#else
#define GD32_SRAM_SIZE         192
#define GD32_SRAM_END          (0x20000000 + GD32_SRAM_SIZE * 1024)
#endif

#ifdef __CC_ARM
extern int Image$$RW_IRAM1$$ZI$$Limit;
#define HEAP_BEGIN    (&Image$$RW_IRAM1$$ZI$$Limit)
#elif __ICCARM__
#pragma section="HEAP"
#define HEAP_BEGIN    (__segment_end("HEAP"))
#else
extern int __bss_end;
#define HEAP_BEGIN    (&__bss_end)
#endif

#define HEAP_END          GD32_SRAM_END

#endif

It is worth noting that different compilers specify the starting address heap of stack memory_ Begin and end address heap_ END。 Here’s heap_ Begin and heap_ The end value needs to be consistent with the previous link script and needs to be modified in combination with the actual situation.

(5) Modify BSP / gd32 / gd32407v start / board / board C Documents

The revised document is as follows:

#include <stdint.h>
#include <rthw.h>
#include <rtthread.h>
#include <board.h>

/**
  * @brief  This function is executed in case of error occurrence.
  * @param  None
  * @retval None
  */
void Error_Handler(void)
{
    /* USER CODE BEGIN Error_Handler */
    /* User can add his own implementation to report the HAL error return state */
    while (1)
    {
    }
    /* USER CODE END Error_Handler */
}

/** System Clock Configuration
*/
void SystemClock_Config(void)
{
    SysTick_Config(SystemCoreClock / RT_TICK_PER_SECOND);
    NVIC_SetPriority(SysTick_IRQn, 0);
}

/**
 * This is the timer interrupt service routine.
 *
 */
void SysTick_Handler(void)
{
    /* enter interrupt */
    rt_interrupt_enter();

    rt_tick_increase();

    /* leave interrupt */
    rt_interrupt_leave();
}

/**
 * This function will initial GD32 board.
 */
void rt_hw_board_init()
{
    /* NVIC Configuration */
#define NVIC_VTOR_MASK              0x3FFFFF80
#ifdef  VECT_TAB_RAM
    /* Set the Vector Table base location at 0x10000000 */
    SCB->VTOR  = (0x10000000 & NVIC_VTOR_MASK);
#else  /* VECT_TAB_FLASH  */
    /* Set the Vector Table base location at 0x08000000 */
    SCB->VTOR  = (0x08000000 & NVIC_VTOR_MASK);
#endif

    SystemClock_Config();

#ifdef RT_USING_COMPONENTS_INIT
    rt_components_board_init();
#endif

#ifdef RT_USING_CONSOLE
    rt_console_set_device(RT_CONSOLE_DEVICE_NAME);
#endif

#ifdef BSP_USING_SDRAM
    rt_system_heap_init((void *)EXT_SDRAM_BEGIN, (void *)EXT_SDRAM_END);
#else
    rt_system_heap_init((void *)HEAP_BEGIN, (void *)HEAP_END);
#endif
}

This file focuses on systemclock_ Config configuration. Systemcorelock is defined in system_ gd32f4xx. As defined in C.

(6) Modify BSP / gd32 / gd32407v start / board / kconfig file

The revised content is as follows:

menu "Hardware Drivers Config"

config SOC_GD32407V
    bool 
    select SOC_SERIES_GD32F4
    select RT_USING_COMPONENTS_INIT
    select RT_USING_USER_MAIN
    default y
    
menu "Onboard Peripheral Drivers"

endmenu

menu "On-chip Peripheral Drivers"

    config BSP_USING_GPIO
        bool "Enable GPIO"
        select RT_USING_PIN
        default y

    menuconfig BSP_USING_UART
        bool "Enable UART"
        default y
        select RT_USING_SERIAL
        if BSP_USING_UART
            config BSP_USING_UART1
                bool "Enable UART1"
                default y

            config BSP_UART1_RX_USING_DMA
                bool "Enable UART1 RX DMA"
                depends on BSP_USING_UART1 && RT_SERIAL_USING_DMA
                default n
        endif

    menuconfig BSP_USING_SPI
        bool "Enable SPI BUS"
        default n
        select RT_USING_SPI
        if BSP_USING_SPI
            config BSP_USING_SPI1
                bool "Enable SPI1 BUS"
                default n

            config BSP_SPI1_TX_USING_DMA
                bool "Enable SPI1 TX DMA"
                depends on BSP_USING_SPI1
                default n
                
            config BSP_SPI1_RX_USING_DMA
                bool "Enable SPI1 RX DMA"
                depends on BSP_USING_SPI1
                select BSP_SPI1_TX_USING_DMA
                default n
        endif

    menuconfig BSP_USING_I2C1
        bool "Enable I2C1 BUS (software simulation)"
        default n
        select RT_USING_I2C
        select RT_USING_I2C_BITOPS
        select RT_USING_PIN
        if BSP_USING_I2C1
            config BSP_I2C1_SCL_PIN
                int "i2c1 scl pin number"
                range 1 216
                default 24
            config BSP_I2C1_SDA_PIN
                int "I2C1 sda pin number"
                range 1 216
                default 25
        endif
    source "../libraries/HAL_Drivers/Kconfig"
    
endmenu

menu "Board extended module Drivers"

endmenu
 
endmenu

This file is driven by the configuration board, which can be added according to actual needs.

(7) Modify BSP / gd32 / gd32407v start / board / sconscript file

The revised content is as follows:

import os
import rtconfig
from building import *

Import('SDK_LIB')

cwd = GetCurrentDir()

# add general drivers
src = Split('''
board.c
''')

path =  [cwd]

startup_path_prefix = SDK_LIB

if rtconfig.CROSS_TOOL == 'gcc':
    src += [startup_path_prefix + '/GD32F4xx_HAL/CMSIS/GD/GD32F4xx/Source/GCC/startup_gd32f4xx.S']
elif rtconfig.CROSS_TOOL == 'keil':
    src += [startup_path_prefix + '/GD32F4xx_HAL/CMSIS/GD/GD32F4xx/Source/ARM/startup_gd32f4xx.s']
elif rtconfig.CROSS_TOOL == 'iar':
    src += [startup_path_prefix + '/GD32F4xx_HAL/CMSIS/GD/GD32F4xx/Source/IAR/startup_gd32f4xx.s']
    
CPPDEFINES = ['GD32F407xx']
group = DefineGroup('Drivers', src, depend = [''], CPPPATH = path, CPPDEFINES = CPPDEFINES)

Return('group')

This file is mainly added to the board folder C file and header file path. In addition, select the corresponding assembly file according to the development environment. It is the same as the sconscript syntax of the previous libraries. The file structure is similar. There are no comments here.

Here, basically all the dependent scripts have been configured. Next, we will configure the project through menuconfig.

6. Menuconfig configuration

Close the socket abstraction layer.

[domestic MCU transplantation] teach you how to use RT thread to make gd32 series BSP

Turn off the network device interface.

[domestic MCU transplantation] teach you how to use RT thread to make gd32 series BSP

Close the LwIP protocol stack.

[domestic MCU transplantation] teach you how to use RT thread to make gd32 series BSP

There is no Ethernet on board gd32407v-start, so the main thing here is to turn off the network related content. Of course, gd32407v-start is rich in resources, which will not affect it. If it is other MCU, modify it according to the actual needs.

7. Drive modification

In a basic BSP, serial port is essential, so you also need to write serial port driver. Serial port 2 is used here as the debugging serial port.
There are also led lights on the board, which mainly need to write GPIO driver.

About the serial port and LED driver, you can view the source code, which will not be posted here.

8. Application development

The author is in the main C add LED application code,

#include <stdio.h>
#include <rtthread.h>
#include <rtdevice.h>
#include <board.h>

/* defined the LED2 pin: PC6 */
#define LED2_PIN GET_PIN(C, 6)

int main(void)
{
    int count = 1;

    /* set LED2 pin mode to output */
    rt_pin_mode(LED2_PIN, PIN_MODE_OUTPUT);

    while (count++)
    {
        rt_pin_write(LED2_PIN, PIN_HIGH);
        rt_thread_mdelay(500);
        rt_pin_write(LED2_PIN, PIN_LOW);
        rt_thread_mdelay(500);
    }

    return RT_EOK;
}

Of course, this requires GPIO driver support.

9. Use env to compile the project
Execute: scons in Env
[domestic MCU transplantation] teach you how to use RT thread to make gd32 series BSP

The compilation is successful, and the printing information is as follows:
[domestic MCU transplantation] teach you how to use RT thread to make gd32 series BSP

10. Generate MDK project using env
Execute in Env: scons — target = mdk5
[domestic MCU transplantation] teach you how to use RT thread to make gd32 series BSP

After generating the MDK project, open the MDK project for compilation
[domestic MCU transplantation] teach you how to use RT thread to make gd32 series BSP

The printing information is compiled successfully as follows:

[domestic MCU transplantation] teach you how to use RT thread to make gd32 series BSP

[note] I don’t have IAR environment. Interested friends can develop it by themselves.

[note] the gd32407v-start development board also has two USB interfaces. If you have time later, you can consider BSP. At present, it has its own GPIO and serial port. Of course, drivers such as SPI will also be integrated step by step. Please look forward to it.

2.3 download and debug gd32 using GD link

Previously, the BSP was successfully compiled using Env and MDK. The next step is to download and debug. Downloading requires a downloader. Some gd32 development boards come with Gd link. You can use the GD link on the development board to debug the simulation code. If not, you can connect the GD link module externally, which is very convenient. The specific operation methods are as follows.

1. The driver will be installed automatically after GD link is inserted into the computer for the first time.

Select “cmsis-dap debugger” in options for target – > debug. Some customers reported that this drive option could not be found because the MDK version is too low and only keil4 The cmsis-dap debugger option is only supported for versions above 74 and keil5.

[domestic MCU transplantation] teach you how to use RT thread to make gd32 series BSP

2. Check swj and port in options for target – > debug – > settings and select SW. “0xxbxxxxx” will appear in the idcode in the right box.
[domestic MCU transplantation] teach you how to use RT thread to make gd32 series BSP

3. Add the flash algorithm of gd32 in options for target – > debug – > Settings – > flash download.
[domestic MCU transplantation] teach you how to use RT thread to make gd32 series BSP

4. Click the shortcut “debug” in the figure below to use GD link for simulation.

[domestic MCU transplantation] teach you how to use RT thread to make gd32 series BSP

Of course, you can also use GD link to download the program.
[domestic MCU transplantation] teach you how to use RT thread to make gd32 series BSP

After downloading the program successfully, the printing information is as follows:
[domestic MCU transplantation] teach you how to use RT thread to make gd32 series BSP

Connect the serial port and print the information as follows:
[domestic MCU transplantation] teach you how to use RT thread to make gd32 series BSP

At the same time, the LED will flash continuously.

2.4 RT thread Studio development

Of course, the project can also be exported and developed using RT thread studio.

First export the project using scons — dist.

[domestic MCU transplantation] teach you how to use RT thread to make gd32 series BSP

Then import the project into RT thread studio

[domestic MCU transplantation] teach you how to use RT thread to make gd32 series BSP

Finally, you can develop in RT thread studio.
[domestic MCU transplantation] teach you how to use RT thread to make gd32 series BSP

Of course, you can also select the BSP of gd32407v-start submitted by the author when creating a new project in RT thread studio.

That’s all for the transplantation of BSP. Of course, there are still a lot of content. It’s just a brick to attract jade. Finally, I hope more friends will join in and contribute to the domestic RTOS.

The above code has been submitted to RT thread.

BSP address