开发板移植RTOS操作系统,RTOS操作系统适配开发板整理大全_use_rtos

先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7

深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Golang全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Go语言开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以添加V获取:vip1024b (备注go)
img

正文

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

img

1.3 gd32407v-start构建

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

img

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

2 BSP移植

2.1 Keil环境准备

目前市面通用的MDK for ARM版本有Keil 4和Keil 5:使用Keil 4建议安装4.74及以上;使用Keil 5建议安装5.20以上版本。笔者的MDK是5.30。

从MDK的官网可以下载得到MDK的安装包,然后安装即可,关于的MDK安装请看笔者的教程。

MDK安装教程:https://blog.csdn.net/bruceoxl/article/details/108548573

MDK下载地址:https://www.keil.com/download/product/

img

安装完成后会自动打开,我们将其关闭。

接下来我们下载GD32F30x的软件支持包。

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

img

下载好后双击GigaDevice.GD32F4xx_DFP.2.1.0.pack运行即可:

img

点击[Next]即可安装完成。

img

安装成功后,重新打开Keil,则可以在File->Device Database中出现Gigadevice的下拉选项,点击可以查看到相应的型号。

img

2.2 BSP工程制作

1.构建基础工程

首先看看RT-Thread代码仓库中已有很多BSP,而我要移植的是Cortex-M4内核。这里我找了一个相似的内核,把它复制一份,并修改文件名为:gd32407v-start。这样就有一个基础的工程。然后就开始增删改查,完成最终的BSP,几乎所有的BSP的制作都是如此。

2.修改BSP构建脚本

bsp/gd32/gd32407v-start/Kconfig修改后的内容如下:

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 “ R T T D I R / K c o n f i g " s o u r c e " RTT_DIR/Kconfig" source " RTTDIR/Kconfig"source"PKGS_DIR/Kconfig”
source “…/libraries/Kconfig”
source “board/Kconfig”

该文件是获取所有路径下的Kconfig。

bsp/gd32/gd32407v-start/SConscript修改后的内容如下:

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’)

该文件是用于遍历当前目录的所有文件夹。

bsp/gd32/gd32407v-start/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)

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_Firmware_Library’
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, ‘Drivers’, ‘SConscript’)))

make a building

DoBuilding(TARGET, objs)

该文件用于链接所有的依赖文件,并调用make进行编译。

3.修改开发环境信息

bsp/gd32/gd32407v-start/cconfig.h修改后的内容如下:

#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

该文件是是编译BSP的环境信息,需根据实时修改。

4.修改KEIL的模板工程

双击:template.uvprojx即可修改模板工程。

修改为对应芯片设备:

img

修改FLASH和RAM的配置:

img

修改可执行文件名字:

img

修改默认调试工具:CMSIS-DAP Debugger。

img

修改编程算法:GD32F4xx FMC。

img

5.修改board文件夹

(1) 修改bsp/gd32/gd32407v-start/board/linker_scripts/link.icf

修改后的内容如下:

/###ICF### Section handled by ICF editor, don’t touch! /
/
-Editor annotation file-
/
/
IcfEditorFile=“ T O O L K I T D I R TOOLKIT_DIR TOOLKITDIR\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 };

该文件是IAR编译的链接脚本,根据《GD32F407xx_Datasheet_Rev2.1》可知,GD32F407VKT6的flash大小为3072KB,SRAM大小为192KB,因此需要设置ROM和RAM的起始地址和堆栈大小等。

(2) 修改bsp/gd32/gd32407v-start/board/linker_scripts/link.ld

修改后的内容如下:

/* 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) }
    }

该文件是GCC编译的链接脚本,根据《GD32F407xx_Datasheet_Rev2.1》可知,GD32F407VKT6的flash大小为3072KB,SRAM大小为192KB,因此CODE和DATA 的LENGTH分别设置为3072KB和192KB,其他芯片类似,但其实地址都是一样的。

(3) 修改bsp/gd32/gd32407v-start/board/linker_scripts/link.sct

该文件是MDK的连接脚本,根据《GD32F407xx_Datasheet_Rev2.1》手册,因此需要将 LR_IROM1 和 ER_IROM1 的参数设置为 0x00300000;RAM 的大小为192k,因此需要将 RW_IRAM1 的参数设置为 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) 修改bsp/gd32/gd32407v-start/board/board.h文件

修改后内容如下:

#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 */

// Internal SRAM memory size[Kbytes] <8-64>
// 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 R W I R A M 1 RW_IRAM1 RWIRAM1ZIKaTeX parse error: Expected 'EOF', got '#' at position 8: Limit; #̲define HEAP_BEG…RW_IRAM1 Z I ZI ZILimit)
#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

值得注意的是,不同的编译器规定的堆栈内存的起始地址 HEAP_BEGIN 和结束地址 HEAP_END。这里 HEAP_BEGIN 和 HEAP_END 的值需要和前面的链接脚本是一致的,需要结合实际去修改。

(5) 修改bsp/gd32/gd32407v-start/board/board.c文件

修改后的文件如下:

#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
}

该文件重点关注的就是SystemClock_Config配置,SystemCoreClock的定义在system_gd32f4xx.c中定义的。

(6) 修改bsp/gd32/gd32407v-start/board/Kconfig文件

修改后内容如下:

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/gd32_drivers/Kconfig”

endmenu

menu “Board extended module Drivers”

endmenu

endmenu

这个文件就是配置板子驱动的,这里可根据实际需求添加。

(7) 修改bsp/gd32/gd32407v-start/board/SConscript文件

修改后内容如下:

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_Firmware_Library/CMSIS/GD/GD32F4xx/Source/GCC/startup_gd32f4xx.s’]
elif rtconfig.CROSS_TOOL == ‘keil’:
src += [startup_path_prefix + ‘/GD32F4xx_Firmware_Library/CMSIS/GD/GD32F4xx/Source/ARM/startup_gd32f4xx.s’]
elif rtconfig.CROSS_TOOL == ‘iar’:
src += [startup_path_prefix + ‘/GD32F4xx_Firmware_Library/CMSIS/GD/GD32F4xx/Source/IAR/startup_gd32f4xx.s’]

CPPDEFINES = [‘GD32F407’]
group = DefineGroup(‘Drivers’, src, depend = [‘’], CPPPATH = path, CPPDEFINES = CPPDEFINES)

Return(‘group’)

该文件主要添加board文件夹的.c文件和头文件路径。另外根据开发环境选择相应的汇编文件,和前面的libraries的SConscript语法是一样,文件的结构都是类似的,这里就没有注释了。

到这里,基本所有的依赖脚本都配置完成了,接下来将通过menuconfig配置工程。

6**.menuconfig配置**

关闭套接字抽象层。

img

关闭网络设备接口。

img

关闭LWIP协议栈。

img

GD32407V-START板载没有以太网,因此这里主要是关闭网络相关的内容,当然GD32407V-START的资源丰富,不关这些其实也不影响,如果是其他MCU,根据实际需求自行修改吧。

7.驱动修改

一个基本的BSP中,串口是必不可少的,所以还需要编写串口驱动,这里使用的串口2作为调试串口。

板子上还有LED灯,主要要编写GPIO驱动即可。

关于串口和LED的驱动可以查看源码,这里就不贴出来了。

8.应用开发

笔者在applications的main.c中添加LED的应用代码,

#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;
}

当然,这需要GPIO驱动的支持。

9.使用ENV编译工程

在env中执行:scons

img

编译成功打印信息如下:

img

10.使用env生成MDK工程

在env中执行:scons --target=mdk5

img

生成MDK工程后,打开MDK工程进行编译

img

成功编译打印信息如下:

img

【注】笔者没有IAR环境,有兴趣的朋友自行去开发吧。

2.3使用GD-Link 下载调试GD32

前面使用ENV和MDK成功编译可BSP,那么接下来就是下载调试环节,下载需要下载器,而GD32部分开发板自带GD-link,可以用开发板上自带的GD-link调试仿真代码,不带的可外接GD-link模块,还是很方便的。具体操作方法如下。

1.第一次使用GD-link插入电脑后,会自动安装驱动。

在Options for Target -> Debug 中选择“CMSIS-DAP Debugger”,部分客户反馈找不到这一驱动器选项,那是因为MDK版本过低,只有Keil4.74以上的版本和Keil5才支持CMSIS-DAP Debugger选项。

img

2.在Options for Target -> Debug ->Settings勾选SWJ、 Port选择 SW。右框IDcode会出现”0xXBAXXXXX”。

img

3.在Options for Target -> Debug ->Settings -> Flash Download中添加GD32的flash算法。

img

4.单击下图的快捷方式“debug”, 即可使用GD-Link进行仿真。

img

当然啦,也可使用GD-Link下载程序。

img

下载程序成功后,打印信息如下:

img

接上串口,打印信息如下:

img

同时LED会不断闪烁。

2.4 RT-Thread studio开发

当然,该工程也可导出使用rt-thread studio开发。

先使用scons --dist导出工程。

img

再将工程导入rt-thread studio中

img

最后,就可在rt-thread studio就可进行开发工作了。

img

当然啦,后面也可在rt-thread studio中新建工程时选择笔者提交的GD32407V-START的BSP。

关于BSP的移植就到这里了,当然还有很多内容,这里只是抛砖引玉。最后希望更多的朋友加入进来,为国产RTOS贡献自己的力量吧。

GD32 BSP: https://gitee.com/ouxiaolong/GD32_RT-Thread

RT-Thread :https://github.com/Ouxiaolong/rt-thread/tree/master/bsp/gd32

六、RT-Thread官方的移植方法

STM32系列驱动介绍

在 RT-Thread 实时操作系统中,各种各样的设备驱动是通过一套 I/O 设备管理框架来管理的。设备管理框架给上层应用提供了一套标准的设备操作 API,开发者通过调用这些标准设备操作 API,可以高效地完成和底层硬件外设的交互。设备管理框架的结构如下图所示:

rt_device

使用 I/O 设备管理框架开发应用程序,有如下优点:

  • 使用同一套标准的 API 开发应用程序,使应用程序具有更好的移植性
  • 底层驱动的升级和修改不会影响到上层代码
  • 驱动和应用程序相互独立,方便多个开发者协同开发

1. 驱动分类介绍

本小节介绍 BSP 提供的不同类别驱动的概念,对一个 BSP 而言,有如下三类驱动:

  • 板载外设驱动:指 MCU 之外,开发板上外设,例如 TF 卡、以太网和 LCD 等
  • 片上外设驱动:指 MCU 芯片上的外设,例如硬件定时器、ADC 和看门狗等
  • 扩展模块驱动:指可以通过扩展接口或者杜邦线连接的开发板的模块,例如 ESP8266 模块

这三种外设的示意图如下所示:

Peripheral

2. 外设驱动的使用方法

当前 RT-Thread 提供的驱动库已经支持 STM32 多个系列的 BSP。点击下表中的驱动名称,即可跳转到对应驱动框架的介绍文档。开发者可以通过阅读相关资料,了解如何在应用开发中通过设备驱动框架来使用这些外设驱动。

2.1 片上外设
序号驱动简介
1GPIO操作 GPIO 管脚
2UART通过串口收发数据
3soft I2C通过软件 I2C 收发数据
4SPI通过 SPI 收发数据
5ADC测量管脚上的模拟量
6SDIO通过 SDIO 读写数据
7TIMER使用硬件定时器实现测量时间和定时执行回调函数功能
8PWM在特定的管脚输出 PWM 波形
9RTC设置和读取时间
10WDT看门狗驱动
11QSPI通过 SPI(1、2、4线) 收发数据
2.2 板载外设
序号驱动简介
1SD适用于 SPI 接口或 SDIO 接口的 SD(TF) 卡
2ETH PHY以太网
3USB PHYUSB
4LCD显示屏
2.3 扩展模块
序号驱动简介
1ESP8266串口转 WIFI 模块
2ENC28J60SPI 接口的以太网控制器
2.4 驱动示例代码

在 RT-Thread 的 examples\test 目录下,有 RT-Thread 提供的基于不同外设驱动的示例代码。在 env 工具中开启 BSP 中要测试的驱动,并将 examples\test 中对应的驱动框架测试文件加入工程,即可快速测试 BSP 中提供的驱动。

STM32 系列 BSP 制作教程

已剪辑自: https://www.rt-thread.org/document/site/#/rt-thread-version/rt-thread-standard/tutorial/make-bsp/stm32-bsp/STM32系列BSP制作教程

为了让广大开发者更好、更方便地使用 BSP 进行开发,RT-Thread 开发团队重新整理了现有的 STM32 系列的 BSP,推出了新的 BSP 框架。新的 BSP 框架在易用性、移植便利性、驱动完整性、代码规范性等方面都有较大提升,在新的 BSP 框架下进行开发,可以大大提高应用的开发效率。

和 RT-Thread 以往提供的 BSP 不同,在新的 BSP 文件夹中将不会包含固件库、外设驱动等可以被多个 BSP 引用的代码文件。而是将这些通用的文件统一存放在 Library 文件夹中,通过在特定 BSP 中引用这些文件的方式,来包含 BSP 中所需的库文件或者驱动文件。这种方式不仅大大提高了代码复用率,降低了 BSP 的维护成本,而且可以更方便地给开发者提供更丰富的驱动文件,让开发者可以更容易地找到自己需要的资源。

新的 BSP 框架还引入了 CubeMX 工具,可以使用该工具来对 BSP 中使用的外设引脚进行配置。CubeMX 工具提供了图形化的配置界面,这种图形化的配置方式对开发者来说更加直观,不仅可以让开发者灵活地配置 BSP 中使用的资源,并且可以让开发者对资源的使用情况一目了然。

新 BSP 框架的主要特性如下:

  • 提供多系列 BSP 模板,大大降低新 BSP 的添加难度;
  • 每个 BSP 都配有齐全的驱动文件,开发者可以方便地使用所有驱动;
  • 开发者可以使用 CubeMX 工具对 BSP 进行图形化配置;

1. BSP 框架介绍

BSP 框架结构如下图所示:

BSP 框架图

每一个 STM32 系列的 BSP 由三部分组成,分别是通用库、BSP 模板和特定开发板 BSP,下面的表格以 F1 系列 BSP 为例介绍这三个部分:

项目 文件夹 说明

通用库stm32/libraries用于存放 HAL 库以及基于 HAL 库的多系列通用外设驱动文件
F1 系列 BSP 工程模板stm32/libraries/templates/stm32f10xF1系列 BSP 模板,可以通过修改该模板制作更多 F1系列 BSP
特定开发板 BSPstm32/stm32f103-atk-nano在 BSP 模板的基础上修改而成

2. 知识准备

制作一个 BSP 的过程就是构建一个新系统的过程,因此想要制作出好用的 BSP,要对 RT-Thread 系统的构建过程有一定了解,需要的知识准备如下所示:

  • 掌握 STM32 系列 BSP 的使用方法

了解 BSP 的使用方法,可以阅读 BSP 说明文档 中使用教程表格内的文档。了解外设驱动的添加方法可以参考《外设驱动添加指南》。

  • 了解 Scons 工程构建方法

RT-Thread 使用 Scons 作为系统的构建工具,因此了解 Scons 的常用命令对制作新 BSP 是基本要求。

  • 了解设备驱动框架

在 RT-Thread 系统中,应用程序通过设备驱动框架来操作硬件,因此了解设备驱动框架,对添加 BSP 驱动是很重要的。

  • 了解 Kconfig 语法

RT-Thread 系统通过 menuconfig 的方式进行配置,而 menuconfig 中的选项是由 Kconfig 文件决定的,因此想要对 RT-Thread 系统进行配置,需要对 kconfig 语法有一定了解。

  • 熟悉 CubeMX 工具的使用

在新的 STM32 系列 BSP 中利用了 CubeMX 工具对底层硬件进行配置,因此需要了解 CubeMX 工具的使用方法。

3. BSP 制作方法

本节以制作正点原子 stm32f103-atk-nano 开发板的 BSP 为例,讲解如何为一个新的开发板添加 BSP。

BSP 的制作过程分为如下五个步骤:

  1. 复制通用模板
  2. 使用 CubeMX 工具配置工程
  3. 修改 BSP 中的 Kconfig 文件
  4. 修改构建工程相关文件
  5. 重新生成工程

在接下来的章节中将会详细介绍这五个步骤,帮助开发者快速创建所需要的 BSP。

3.1 复制通用模板

制作新 BSP 的第一步是复制一份同系列的 BSP 模板作为基础,通过对 BSP 模板的修改来获得新 BSP。目前提供的 BSP 模板系列如下表所示:

工程模板 说明

libraries/templates/stm32f0xxF0 系列 BSP 模板
libraries/templates/stm32f10xF1 系列 BSP 模板
libraries/templates/stm32f4xxF4 系列 BSP 模板
libraries/templates/stm32f7xxF7 系列 BSP 模板
libraries/templates/stm32l4xxL4 系列 BSP 模板

本次示例所用的 F1 系列 BSP 模板文件夹结构如下所示:

F1 系列 BSP 模板文件夹内容

本次制作的 BSP 为 F1 系列,因此拷贝模板文件夹下的 stm32f10x 文件夹,并将该文件夹的名称改为 stm32f103-atk-nano ,如下图所示:

复制通用模板

在接下来的 BSP 的制作过程中,将会修改 board 文件夹内的配置文件,将 F1 系列的 BSP 模板变成一个适用于正点原子 stm32f103-atk-nano 开发板的 BSP ,下表总结了 board 文件夹中需要修改的内容:

项目 需要修改的内容说明

CubeMX_Config (文件夹)CubeMX 工程
linker_scripts (文件夹)BSP 特定的链接脚本
board.c/h系统时钟、GPIO 初始化函数、芯片存储器大小
Kconfig芯片型号、系列、外设资源
SConscript芯片启动文件、目标芯片型号
3.2 使用 CubeMX 配置工程

在制作 BSP 的第二步,需要创建一个基于目标芯片的 CubeMX 工程。默认的 CubeMX 工程在 CubeMX_Config 文件夹中,双击打开 CubeMX_Config.ioc 工程,如下图所示:

open_cubemx

在 CubeMX 工程中将芯片型号为修改芯片型号为 STM32F103RBTx 。

3.2.1 生成 CubeMX 工程

配置系统时钟、外设引脚等,步骤如下图所示:

  1. 打开外部时钟、设置下载方式、打开串口外设(注意只需要选择串口外设引脚即可,无需配置其他参数):

配置芯片引脚

  1. 配置系统时钟:

配置系统时钟

  1. 设置项目名称,并在指定地址重新生成 CubeMX 工程:

生成对应的配置代码

注意:在生成代码时,不要勾选以下选项(即:不让其生成单独的 .c/.h 驱动文件,直接全部更新到 rt-thread 要使用的 stm32xxx_hal_msp.c 文件中)

generate-code

最终 CubeMX 生成的工程目录结构如下图所示:

CubeMX 图7

3.2.2 拷贝初始化函数

board.c 文件中存放了函数 SystemClock_Config() ,该函数负责初始化系统时钟。当使用 CubeMX 工具对系统时钟重新配置的时候,需要更新这个函数。

该函数由 CubeMX 工具生成,默认存放在board/CubeMX_Config/Src/main.c 文件中。但是该文件并没有被包含到我们的工程中,因此需要将这个函数从 main.c 中拷贝到 board.c 文件中。在整个 BSP 的制作过程中,这个函数是唯一要拷贝的函数,该函数内容如下所示:

board_1

board.h 文件中配置了 FLASH 和 RAM 的相关参数,这个文件中需要修改的是 STM32_FLASH_SIZESTM32_SRAM_SIZE 这两个宏控制的参数。本次制作的 BSP 所用的 STM32F103RBTx 芯片的 flash 大小为 128k,ram 的大小为 20k,因此对该文件作出如下的修改:

修改 board.h

3.2.3 堆内存配置讲解

通常情况下,系统 RAM 中的一部分内存空间会被用作堆内存。下面代码的作用是,在不同编译器下规定堆内存的起始地址 HEAP_BEGIN 和结束地址 HEAP_END。这里 HEAP_BEGINHEAP_END 的值需要和后面 [3.4.1 修改链接脚本](# 3.4.1 修改链接脚本) 章节所修改的配置相一致。

在某些系列的芯片中,芯片 RAM 可能分布在不连续的多块内存区域上。此时堆内存的位置可以和系统内存在同一片连续的内存区域,也可以存放在一片独立的内存区域中。例如在 L4 系列的芯片上,就可以将堆内存配置在起始地址为 0x20000000 的大小为 96k 的内存空间,而将 0x10000000 开始的 32k 内存空间用作系统运行内存。

heap_config

3.3 修改 Kconfig 选项

在本小节中修改 board/Kconfig 文件的内容有如下两点:

  • 芯片型号和系列
  • BSP 上的外设支持选项

芯片型号和系列的修改如下表所示:

宏定义 意义 格式

SOC_STM32F103RB芯片型号SOC_STM32xxx
SOC_SERIES_STM32F1芯片系列SOC_SERIES_STM32xx

关于 BSP 上的外设支持选项,一个初次提交的 BSP 仅仅需要支持 GPIO 驱动和串口驱动即可,因此在配置选项中只需保留这两个驱动配置项,如下图所示:

修改 Kconfig

3.4 修改工程构建相关文件

接下来需要修改用于构建工程相关的文件。

3.4.1 修改链接脚本

linker_scripts 链接文件如下图所示:

需要修改的链接脚本

下面以 MDK 使用的链接脚本 link.sct 为例,演示如何修改链接脚本:

linkscripts_change

本次制作 BSP 使用的芯片为 STM32F103RB,FLASH 为 128k,因此修改 LR_IROM1 和 ER_IROM1 的参数为 0x00020000。RAM 的大小为20k, 因此修改 RW_IRAM1 的参数为 0x00005000。这样的修改方式在一般的应用下就够用了,后续如果有特殊要求,则需要按照链接脚本的语法来根据需求修改。修改链接脚本时,可以参考 [3.2.3 堆内存配置讲解](# 3.2.3 堆内存配置讲解) 章节来确定 BSP 的内存分配。

其他两个链接脚本的文件分别为 IAR 使用的 link.icf 和 gcc 编译器使用的 link.lds,修改的方式也是类似的,如下图所示:

  • link.icf 修改内容

link_icf

  • link.lds 修改内容

link_lds

3.4.2 修改构建脚本

SConscript 脚本决定 MDK/IAR 工程的生成以及编译过程中要添加文件。

在这一步中需要修改芯片型号以及芯片启动文件的地址,修改内容如下图所示:

修改启动文件和芯片型号

注意:如果在文件夹中找不到相应系列的 .s 文件,可能是多个系列的芯片重用了相同的启动文件,此时可以在 CubeMX 中生成目标芯片的工程,查看使用了哪个启动文件,然后再修改启动文件名。

3.4.3 修改工程模板

template 文件是生成 MDK/IAR 工程的模板文件,通过修改该文件可以设置工程中使用的芯片型号以及下载方式。MDK4/MDK5/IAR 的工程模板文件,如下图所示:

MDK/IAR 工程模板

下面以 MDK5 模板的修改为例,介绍如何修改模板配置:

选择芯片型号

修改程序下载方式:

配置下载方式

3.5 重新生成工程

重新生成工程需要使用 Env 工具。

在 Env 界面输入命令 menuconfig 对工程进行配置,并生成新的 rtconfig.h 文件。如下图所示:

输入menuconfig进入配置界面

选择要打开的外设

下面以重新生成 MDK 工程为例,介绍如何重新生成 BSP 工程。

使用 env 工具输入命令 scons --target=mdk5 重新生成工程,如下图所示:

重新生成 BSP 工程

重新生成工程成功:

重新生成 BSP 工程

到这一步为止,新的 BSP 就可以使用了。

接下来我们可以分别使用命令 scons --target=mdk4scons --target=iar,来更新 MDK4 和 IAR 的工程,使得该 BSP 变成一个完整的,可以提交到 GitHub 的 BSP (MDK4工程的制作为可选)。

感谢每一位贡献代码的开发者,RT-Thread 将与你一同成长。

4. 规范

本章节介绍 RT-Thread STM32 系列 BSP 制作与提交时应当遵守的规范 。开发人员在 BSP 制作完成后,可以根据本规范提出的检查点对制作的 BSP 进行检查,确保 BSP 在提交前有较高的质量 。

4.1 BSP 制作规范

STM32 BSP 的制作规范主要分为 3 个方面:工程配置,ENV 配置和 IDE 配置。在已有的 STM32 系列 BSP 的模板中,已经根据下列规范对模板进行配置。在制作新 BSP 的过程中,拷贝模板进行修改时,需要注意的是不要修改这些默认的配置。BSP 制作完成后,需要对新制作的 BSP 进行功能测试,功能正常后再进行代码提交。

下面将详细介绍 BSP 的制作规范。

4.1.1 工程配置
  • 遵从RT-Thread 编码规范,代码注释风格统一
  • main 函数功能保持一致
  • 如果有 LED 的话,main 函数里只放一个 LED 1HZ 闪烁的程序
  • rt_hw_board_init 中需要完成堆的初始化:调用 rt_system_heap_init
  • 默认只初始化 GPIO 驱动和 FinSH 对应的串口驱动,不使用 DMA
  • 当使能板载外设驱动时,应做到不需要修改代码就能编译下载使用
  • 提交前应检查 GCC/MDK/IAR 三种编译器直接编译或者重新生成后编译是否成功
  • 使用 dist 命令对 BSP 进行发布,检查使用 dist 命令生成的工程是否可以正常使用
4.1.2 ENV 配置
  • 系统心跳统一设置为 1000(宏:RT_TICK_PER_SECOND)
  • BSP 中需要打开调试选项中的断言(宏:RT_DEBUG)
  • 系统空闲线程栈大小统一设置为 256(宏:IDLE_THREAD_STACK_SIZE)
  • 开启组件自动初始化(宏:RT_USING_COMPONENTS_INIT)
  • 需要开启 user main 选项(宏:RT_USING_USER_MAIN)
  • FinSH 默认只使用 MSH 模式(宏:FINSH_USING_MSH_ONLY)
4.1.3 IDE 配置
  • 使能下载代码后自动运行
  • 使能 C99 支持
  • 使能 One ELF Section per Function(MDK)
  • MDK/IAR 生成的临时文件分别放到build下的 MDK/IAR 文件夹下
  • MDK/GCC/IAR 生成 bin 文件名字统一成 rtthread.bin
4.2 BSP 提交规范
  • 提交前请认真修改 BSP 的 README.md 文件,README.md 文件的外设支持表单只填写 BSP 支持的外设,可参考其他 BSP 填写。查看文档《STM32系列驱动介绍》了解驱动分类。
  • 提交 BSP 分为 2 个阶段提交:
  • 第一阶段:基础 BSP 包括串口驱动和 GPIO 驱动,能运行 FinSH 控制台。完成 MDK4、MDK5 、IAR 和 GCC 编译器支持,如果芯片不支持某款编译器(比如MDK4)可以不用做。 BSP 的 README.md 文件需要填写第二阶段要完成的驱动。
  • 第二阶段:完成板载外设驱动支持,所有板载外设使用 menuconfig 配置后就能直接使用。若开发板没有板载外设,则此阶段可以不用完成。不同的驱动要分开提交,方便 review 和合并。
  • 只提交 BSP 必要的文件,删除无关的中间文件,能够提交的文件请对照其他 BSP。
  • 提交 STM32 不同系列的 Library 库时,请参考 f1/f4 系列的 HAL 库,删除多余库文件
  • 提交前要对 BSP 进行编译测试,确保在不同编译器下编译正常
  • 提交前要对 BSP 进行功能测试,确保 BSP 的在提交前符合工程配置章节中的要求

我有疑问: RT-Thread 官方论坛

STM32 系列外设驱动添加指南

已剪辑自: https://www.rt-thread.org/document/site/#/rt-thread-version/rt-thread-standard/tutorial/make-bsp/stm32-bsp/STM32系列外设驱动添加指南

本文档是为需要给现有的 STM32 BSP 添加更多外设驱动的开发者准备的。通过阅读本文,开发者可以按照自己的实际情况给现有 BSP 添加自己需要的驱动。

  • 熟练使用 ENV 工具,参考:RT-Thread env 工具用户手册
  • 熟悉 Kconfig 语法
  • 熟悉 STM32CubeMX 工具
  • 对 RT-Thread 设备驱动框架有一定了解

本章节以添加片上外设驱动为例,讲解如何为 BSP 添加更多可用驱动。如果想使用的片上外设是 片上外设配置菜单 里没有的,就需要开发者自己添加了。下面我们将演示如何为 stm32f429-atk-apollo BSP 添加 SPI3 驱动。

没有安装 stm32cubemx 软件的可以访问 STM32cube中文网:http://www.stm32cube.com/ ,在 资源下载 里下载 stm32cubemx 软件。

阿波罗 BSP 默认只支持 SPI1、SPI2 和 SPI5,是不支持 SPI3 的。开发者如果需要使用 SPI3,则需要自己添加。

spi_config

添加 SPI3 的外设支持需要以下几步:

1)打开 STM32CubeMX 工程

打开 BSP 的 STM32CubeMX 配置文件。

1543486779576

按图示顺序配置 SPI3,并生成代码。

1543487684698

为 BSP 添加驱动时,STM32CubeMX 工具可以快速的完成使能外设配置管脚的工作。而外设初始化,中断配置,DMA配置等等则由 RT-Thread 提供的驱动文件来完成。也就是说,虽然 STM32CubeMX 生成了多个文件用来初始化外设,但 RT-Thread 只使用了 STM32CubeMX 生成的 stm32fxx_hal_msp.c 文件和 stm32fxx_hal_conf.h 文件。

对于不同的外设驱动,通过 STM32CubeMX 工具配置的内容也不一样。开发者可以参考本文档的附录 CubeMX 配置说明章节来了解不同外设的配置方法。

3)修改 Kconfig 文件

打开 board 文件夹下的 Konfig 文件,拷贝 SPI2 的配置项,并重命名 SPI2 为 SPI3。

1543542657074

经过上一步的修改,此时重新打开 ENV 工具,在 menuconfig 中就会出现添加的 SPI3 的配置项。

1543543081284

使用 ENV 重新生成工程并打开,检查原有驱动文件是否支持新添加的驱动(查看是否有新驱动的配置文件,中断函数,DMA配置和中断函数等等),如不支持,需参考现有驱动添加相关的代码。

spi_code

检查完工程后,编译下载到开发板,程序会自动开始运行。输入 list_device 命令,可以看到 spi3 总线已经注册到内核,说明驱动已经添加成功。

1543543446786

  • 部分驱动如果没有适配 BSP 所属的 STM32 系列,请等待 RT-Thread 团队更新。
  • 对于驱动文件或文档说明,有任何建议或者意见,欢迎反馈到 RT_Thread GitHub 网站或 RT-Thread 官方论坛
  • 在生成代码时,不要勾选以下选项(即:不让其生成单独的 .c/.h 驱动文件,直接全部更新到 RT-Thread 要使用的 stm32xxx_hal_msp.c 文件中)

generate-code

5.1 CubeMX配置说明

本小节介绍 STM32 系列的 BSP 是如何利用 CubeMX 工具对 BSP 进行配置的。

就像文档中提到的那样,STM32 系列的 BSP 只利用了 CubeMX 工具生成的 stm32XXxx_hal_conf.hstm32XXxx_hal_msp.c 文件。在 HAL 库中, stm32XXxx_hal_conf.h 文件里提供的宏开关会决定 HAL 库将哪些外设驱动添加到工程中。 而 stm32XXxx_hal_msp.c 文件中则存放了在 CubeMX 工具中开启的外设驱动的配置代码。

5.2 外设配置总结

当开发者想要在 BSP 中添加更多驱动时,需要使用 CubeMX 工具来配置这些外设。对于绝大多数驱动的配置,只需要在工具中使能相应的外设即可。但是对于一些复杂的外设,则需要更多的配置内容。下表展示了不同驱动在 CubeMX 工具配置步骤的总结:

序号 驱动 CubeMx 工程中的配置情况(加粗部分为必做步骤

1GPIO无需任何操作
2UART开启该外设 ,然后配置所需要的引脚(或者使用默认引脚)
3SPI开启该外设 ,然后配置所需要的引脚(或者使用默认引脚)
4I2C依赖于PIN 驱动,无需任何操作
5TIMER使能 internal Clock 时钟 ,详细内容可参考5.3章节
7PWM首先使能 internal Clock 时钟,然后为 channelx 选项选择PWM Generation CHx, 最后配置所需要的引脚(或者使用默认引脚) ,详细内容可参考5.3章节
8ADC开启该外设,然后选择使用的通道 ,详细内容可参考5.3章节
9RTC开启该外设,然后在时钟树状图里将 RTC 选择为 LSE 时钟
10Watchdog开启该外设
11EMAC配置 ETH 外设的工作模式(一般为 RMII 模式)
12SDRAM需要根据板载的 SDRAM 型号配置片选脚,地址线,数据线等
13SDIO开启该外设,配置引脚(或者使用默认引脚),SDIO会改变时钟结构,故需重新配置时钟并修改board.c
5.3 复杂外设配置说明

本章节着重介绍配置步骤较为复杂的驱动。

5.3.1 TIMER 外设驱动添加说明
  1. 打开 STM32CubeMX 工程,设置 timer 在 Cube 里的选项,如下图所示:

timer CubeMX 配置
2. 打开 stm32/stm32f429-atk-apollo/board/Kconfig ,添加 Kconfig 选项。选中自己添加的选项后,生成一遍工程,如下图所示:

timer Kconfig 配置

  1. 打开工程进行编译,工程会提示 TIM11_CONFIG 未定义。 可以在 stm32/libraries/HAL_Drivers/config/f4/tim_config.h 中进行定义,如下图所示:timer 编译timer 编译
5.3.2 PWM 外设驱动添加说明
  1. 打开 STM32CubeMX 工程,设置 PWM 在 Cube 里的选项,如下图所示:

pwm CubeMX 配置
2. 打开 stm32/stm32f429-atk-apollo/board/Kconfig ,添加 Kconfig 选项。选中自己添加的选项后,生成一遍工程,如下图所示:

pwm Kconfig 配置
3. 打开工程进行编译,工程会提示 PWM2_CONFIG 未定义。 可以在 stm32/libraries/HAL_Drivers/config/f4/pwm_config.h 中进行定义,如下图所示:

pwm 编译pwm 编译

5.3.3 ADC 外设驱动添加说明
  1. 打开 STM32CubeMX 工程,设置 ADC 在 Cube 里的选项,如下图所示:

adc CubeMX 配置
2. 打开 stm32/stm32f429-atk-apollo/board/Kconfig ,添加 Kconfig 选项。选中自己添加的选项后,生成一遍工程,如下图所示:

adc Kconfig 配置
3. 打开工程进行编译,工程会提示 ADC1_CONFIG 未定义。 可以在 stm32/libraries/HAL_Drivers/config/f4/adc_config.h 中进行定义,如下图所示:

adc 编译adc 编译

5.3.4 编码器外设驱动添加说明
  1. 打开 STM32CubeMX 工程,设置 TIMER 在 Cube 里的选项,如下图所示:

pulse_encoder CubeMX 配置
2. 打开 stm32/stm32f407-atk-explorer/board/Kconfig ,添加 Kconfig 选项。选中自己添加的选项后,生成一遍工程,如下图所示:

pulse_encoder Kconfig 配置
3. 打开工程进行编译,工程会提示 PULSE_ENCODER4_CONFIG 未定义。 可以在 stm32/libraries/HAL_Drivers/config/f4/pulse_encoder_config.h 中进行定义,如下图所示:

pulse_encoder 编译pulse_encoder 编译

我有疑问: RT-Thread 官方论坛

七、LiteOS移植指南

概述

什么是移植,为什么要移植

对于嵌入式设备,由于芯片型号和外设差异较大,且资源有限,所以物联网操作系统无法像 Windows/Linux 那样适配集成所有驱动,因此通常会先适配部分芯片/开发板。为了让操作系统运行在其他芯片/开发板上,此时就需要移植。

开发板的移植包括 CPU架构移植、板级/外设驱动移植和操作系统的移植。

指南适用范围

本指南基于STM32芯片平台,以正点原子STM32F407开发板为例介绍如何快速移植LiteOS,其中并不涉及CPU架构移植。

移植目录结构

表格列出了LiteOS源码的目录,其中加粗字体的目录/文件在移植过程中需要修改。

表 1 LiteOS源码目录

一级目录二级目录/文件说明
arch芯片架构支持
buildLiteOS编译系统需要的配置及脚本
compatLiteOS提供的CMSIS-RTOS 1.0和2.0接口
components组件代码
demos组件和内核的demo
docLiteOS使用文档
includecomponents中各模块的头文件
kernel内核代码
liblibc/zlib/posix接口
osdependsLiteOS提供的部分OS适配接口
targetsbsp通用板级支持包
Cloud_STM32F429IGTx_FIRE野火STM32F429(ARM Cortex M4)开发板的开发工程源码包
qemu-virt-a53Coretex A53的qemu开发工程源码包
realview-pbx-a9Coretex A9的qemu开发工程源码包
STM32F072_NucleoSTM32F072_Nucleo(ARM Cortex M0)开发板的开发工程源码包
STM32F103_FIRE_Arbitrary野火STM32F103(ARM Cortex M3)霸道开发板的开发工程源码包
STM32F769IDISCOVERYSTM32F769IDISCOVERY(ARM Cortex M7)开发板的开发工程源码包
其他开发板的开发工程源码包
Kconfig
Makefile
targets.mk
toolsbuild/configLiteOS支持的各开发板的编译配置文件,移植新的开发板时,需要在这个目录下增加这个新开发板的编译配置文件
menuconfigLiteOS编译所需的menuconfig脚本
Makefile整个LiteOS的Makefile
.config开发板的编译配置文件,默认为Cloud_STM32F429IGTx_FIRE开发板的配置文件,移植时需要替换成新开发板的编译配置文件

target目录下保存了当前已经支持的开发板工程源码。当移植新开发板时,应该在target目录下增加该开发板的目录,目录结构和代码可以参考当前已支持的开发板的目录。例如:

  • STM32F4系列的移植可以参考Cloud_STM32F429IGTx_FIRE工程。
  • STM32F7系列的移植可以参考STM32F769IDISCOVERY工程。
  • STM32L4系列的移植可以参考STM32L431_BearPi工程。

环境准备

获取LiteOS源代码

LiteOS源码仓在码云上,使用master分支。

硬件环境
开发板

本指南以国内主流STM32学习板-正点原子STM32F407开发板为例进行移植。该开发板的介绍可参考官方网站:探索者STM32F407开发板

烧录仿真器

JLink。

软件环境
简介

本指南主要基于LiteOS Studio集成开发环境进行移植,烧录工具为JLink,同时使用STM32CubeMX软件生成裸机工程。

安装STM32CubeMX

STM32CubeMX下载,本指南使用的是6.0.1版本。

安装LiteOS Studio

除了LiteOS Studio,同时还需要安装git工具、arm-none-eabi软件、make构建软件、C/C++扩展、JLink烧录软件,这些软件的安装均可参考LiteOS Studio安装指南

所有软件安装完毕后,需要重启计算机。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qw8KdraL-1665821485116)(https://github.com/LiteOS/LiteOS/raw/master/doc/public_sys-resources/icon-notice.gif)] 须知: 对于板载STLink仿真器的STM32开发板,需要先把STLink仿真器刷成JLink仿真器,再按照JLink的方式烧写。可以参考LiteOS Studio官方文档的“STM32工程示例”中的“ST-Link仿真器单步调测”

验证LiteOS Studio集成开发环境

在正式开始移植前,可以先验证当前开发环境是否能成功编译LiteOS代码并完成烧录。目前开源LiteOS支持了若干开发板,如:Cloud_STM32F429IGTx_FIRE、STM32F769IDISCOVERY、STM32L431_BearPi等。可以视情况验证环境:

  • 没有官方已适配的开发板,可以先使用LiteOS已支持的开发板工程验证编译功能。暂时不验证烧录功能,在下一章节“测试裸机工程”中再验证。
  • 有官方已适配的开发板,使用开发板对应的工程验证编译和烧录功能。即:
  • 对于Cloud_STM32F429IGTx_FIRE开发板,在LiteOS Studio中配置目标板信息时,选择STM32F429IG。
  • 对于STM32F769IDISCOVERY开发板,在LiteOS Studio中配置目标板信息时,选择STM32F769NI。
  • 对于STM32L431_BearPi 开发板,在LiteOS Studio中配置目标板信息时,选择STM32L431RC。

验证方法可以参考LiteOS Studio官方文档的“STM32工程示例”中的“使用入门”(只需关注其中的“打开工程”、“目标板配置”、“编译配置-编译代码”和“烧录配置-烧录”)。

创建裸机工程

简介

STM32CubeMX 是意法半导体(ST) 推出的一款图形化开发工具,支持 STM32 全系列产品,能够让用户轻松配置芯片外设引脚和功能,并一键生成C语言的裸机工程。

裸机工程可以为移植提供硬件配置文件和外设驱动文件,同时可以测试开发板的基本功能。以下介绍正点原子STM32F407的裸机工程创建过程。

新建工程
  1. 打开STM32CubeMX软件,点击菜单栏“File”在下拉菜单中选择“New Project”,如下图所示:

图 1 新建工程 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OAfEOlv3-1665821485117)(https://github.com/LiteOS/LiteOS/raw/master/doc/figures/%E6%96%B0%E5%BB%BA%E5%B7%A5%E7%A8%8B.png)]
2. 选择开发板芯片。

选择对应的开发板MCU(对于正点原子STM32F407开发板,选择STM32F407ZG),如下图所示:

图 2 设置开发板芯片 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nGRsCMo9-1665821485117)(https://github.com/LiteOS/LiteOS/raw/master/doc/figures/%E8%AE%BE%E7%BD%AE%E5%BC%80%E5%8F%91%E6%9D%BF%E8%8A%AF%E7%89%87.png)]

配置芯片外设
简介

可以根据需要,自定义配置外设。这里仅配置了最基本的时钟、串口和LED灯、以及烧录调试方式,已经能满足LiteOS运行所需的基本硬件需求。

配置时钟
  1. 配置时钟引脚。

选择“Pinout & Configuration”标签页,在左边的“System Core”中选择RCC,设置HSE(High Speed Clock,外部高速时钟)为Crystal/ Ceramic Resonator(晶振/陶瓷谐振器),即采用外部晶振作为 HSE 的时钟源,如下图所示:

图 1 配置时钟引脚 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KQUs4vzF-1665821485117)(https://github.com/LiteOS/LiteOS/raw/master/doc/figures/%E9%85%8D%E7%BD%AE%E6%97%B6%E9%92%9F%E5%BC%95%E8%84%9A.png)]
2. 配置时钟频率。

将标签页切换为“Clock Configuration”。STM32F407芯片的最高时钟为168MHz,在HCLK处输入168并且回车即可完成配置,如下图所示。其他开发板的配置方式也类似。

图 2 配置时钟频率 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JLY8nCCq-1665821485117)(https://github.com/LiteOS/LiteOS/raw/master/doc/figures/%E9%85%8D%E7%BD%AE%E6%97%B6%E9%92%9F%E9%A2%91%E7%8E%87.png)]

配置串口和LED灯

将标签页切换回“Pinout & Configuration”。下图是正点原子STM32F407开发板的配置方法。对于其他开发板,可以参考开发板的原理图进行相应配置。

图 1 配置串口和LED引脚 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9IH1qAGw-1665821485118)(https://github.com/LiteOS/LiteOS/raw/master/doc/figures/%E9%85%8D%E7%BD%AE%E4%B8%B2%E5%8F%A3%E5%92%8CLED%E5%BC%95%E8%84%9A.png)]

配置烧录调试方式

仍然在“Pinout & Configuration”标签页中,在左边的“System Core”中选择“SYS”,将“Debug”设置为“Serial Wire”,即SWD接口。该接口适用于STLink和JLink。

图 1 设置烧录调试方式 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tNVqZXZE-1665821485118)(https://github.com/LiteOS/LiteOS/raw/master/doc/figures/%E8%AE%BE%E7%BD%AE%E7%83%A7%E5%BD%95%E8%B0%83%E8%AF%95%E6%96%B9%E5%BC%8F.png)]

配置工程

工程配置中,需要设置工程名、代码保存路径、编译工具链/IDE、代码使用的堆栈大小以及HAL库版本。CubeMX 可以生成 Makefile、MDK-ARM、IAR 等 IDE 工程。本指南基于GCC编译工具链,所以Toolchain/IDE需要选择Makefile。将标签页切换到“Project Manager”,选择左边的“Project”标签,如下图所示:

图 1 工程配置 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dQLX4acz-1665821485118)(https://github.com/LiteOS/LiteOS/raw/master/doc/figures/%E5%B7%A5%E7%A8%8B%E9%85%8D%E7%BD%AE.png)]

为便于外设相关代码维护,建议勾选生成外设驱动的.c/.h文件。选择左边的“Code Generator”标签,如下图所示:

图 2 生成代码配置 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FLpn2TqI-1665821485119)(https://github.com/LiteOS/LiteOS/raw/master/doc/figures/%E7%94%9F%E6%88%90%E4%BB%A3%E7%A0%81%E9%85%8D%E7%BD%AE.png)]

生成裸机工程代码

按以上步骤设置完外设和工程配置后,就可以生成裸机工程代码了,如下图所示:

图 1 生成工程 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OhmF7Ulc-1665821485119)(https://github.com/LiteOS/LiteOS/raw/master/doc/figures/%E7%94%9F%E6%88%90%E5%B7%A5%E7%A8%8B.png)]

生成的裸机工程目录结构如下表所示:

表 1 裸机工程目录结构

目录/文件说明
build该目录用于存放编译生成的文件
Core用户代码和开发板的基本配置文件
DriversSTM32 官方HAL 库
Makefile裸机工程的Makefile
startup_stm32f407xx.s芯片启动文件,主要包含堆栈定义等
STM32F407ZGTx_FLASH.ld裸机工程的链接脚本
测试裸机工程
编写测试程序

下面在裸机工程Core\Src\main.c文件中编写测试代码,实现串口循环输出并且LED灯闪烁:

  1. 添加头文件:

#include <stdio.h>

  1. 在main()函数的while(1)循环中添加如下代码:

printf(“hello\n”);
HAL_Delay(1000);
HAL_GPIO_TogglePin(GPIOF, GPIO_PIN_9);

  1. /* USER CODE BEGIN 4 */中添加函数:

attribute((used)) int _write(int fd, char *ptr, int len)
{
(void)HAL_UART_Transmit(&huart1, (uint8_t *)ptr, len, 0xFFFF);
return len;
}

使用LiteOS Studio测试裸机工程
  1. 配置目标板。

在“工程配置”界面中点击“目标板”,在“操作”列中点击“+”后,在出现的空行中填入STM32F407开发板信息,选中新增的开发板后,点击确认按钮保存,如下图所示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XO5thnH7-1665821485119)(https://github.com/LiteOS/LiteOS/raw/master/doc/figures/%E7%9B%AE%E6%A0%87%E6%9D%BF%E9%85%8D%E7%BD%AE.png)]
2. 编译。

在裸机工程根目录下的Makefile文件上点击右键->设置为Makefile文件,然后编译工程,编译生成的二进制镜像文件在工程根目录的build目录下,如下图所示:

图 1 编译裸机工程 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ffrZjrzJ-1665821485119)(https://github.com/LiteOS/LiteOS/raw/master/doc/figures/%E7%BC%96%E8%AF%91%E8%A3%B8%E6%9C%BA%E5%B7%A5%E7%A8%8B.png)]
3. 烧录。

  1. 配置烧录器。

在“工程配置”界面中点击“烧录器”,参照下图进行配置,要烧录的二进制镜像文件就是上一步编译生成的bin文件,配置项中的“连接速率”、“加载地址”保持默认即可。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pSSG8ppV-1665821485120)(https://github.com/LiteOS/LiteOS/raw/master/doc/figures/%E7%83%A7%E5%BD%95%E5%99%A8%E9%85%8D%E7%BD%AE.png)]
2. 点击“工具栏”上的“烧录”按钮,进行烧录。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tMJSmLt0-1665821485120)(https://github.com/LiteOS/LiteOS/raw/master/doc/figures/%E7%83%A7%E5%BD%95%E6%8C%89%E9%92%AE.png)]

烧录成功后,可以在终端界面看到如下输出:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OdeY0rfx-1665821485120)(https://github.com/LiteOS/LiteOS/raw/master/doc/figures/%E7%83%A7%E5%BD%95%E6%88%90%E5%8A%9F%E7%9A%84%E8%BE%93%E5%87%BA.png)]
3. 查看串口输出。

点击“工具栏”上“串口终端”图标[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4xyeMfk3-1665821485120)(https://github.com/LiteOS/LiteOS/raw/master/doc/figures/%E4%B8%B2%E5%8F%A3%E7%BB%88%E7%AB%AF%E6%8C%89%E9%92%AE.png)],打开串口终端界面。如下图,只需设置与开发板连接的实际端口号,并打开串口开关。开发板按下复位RESET按钮后,即可在“串口终端”界面中看到不断输出hello,同时也可以观察到开发板的LED灯闪烁。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kro6Ah7g-1665821485120)(https://github.com/LiteOS/LiteOS/raw/master/doc/figures/%E8%A3%B8%E6%9C%BA%E5%B7%A5%E7%A8%8B%E4%B8%B2%E5%8F%A3%E8%BE%93%E5%87%BA.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Xb9rnk0c-1665821485121)(https://github.com/LiteOS/LiteOS/raw/master/doc/public_sys-resources/icon-note.gif)] 说明: 如果想更详细的了解LiteOS Studio的使用,可以参考LiteOS Studio官方文档的“STM32工程示例”

移植适配

移植步骤

下面的移植工作会基于现有的裸机工程进行,大致步骤如下:

  1. 增加新移植开发板的目录。
  2. 适配新开发板的外设驱动和HAL库配置文件。
  3. 配置系统时钟。
  4. 适配串口初始化文件。
  5. 修改链接脚本。
  6. 适配编译配置。
增加新开发板的目录

正点原子STM32F407开发板使用的是STM32F4芯片,可以参考Cloud_STM32F429IGTx_FIRE工程代码。

在LiteOS源码target目录下拷贝Cloud_STM32F429IGTx_FIRE目录,并将目录重命名为新开发板名,比如STM32F407_OpenEdv。下表是STM32F407_OpenEdv目录中的子目录和文件,只列出了和本次移植相关的内容,不相关的文件和目录可以删除。

表 1 新增开发板目录结构

目录/文件说明
Inc芯片外设配置的头文件
includeLiteOS系统相关配置头文件
os_adaptLiteOS适配的接口文件
Src芯片外设配置的源文件
config.mk当前开发板工程的编译配置文件
liteos.ld当前开发板工程的链接文件
los_startup_gcc.S芯片启动文件,主要包含堆栈定义等
Makefile当前开发板工程的Makefile
适配外设驱动和HAL库配置文件
  1. 将芯片外设驱动文件替换为对应芯片的文件。
  • 修改芯片外设驱动源文件system_xxx.c。

LiteOS对STM32F407_OpenEdv\Src\system_stm32f4xx.c做了修改,所以该文件无法使用在新开发板上,移植时可以直接替换为裸机工程中对应的文件。对于正点原子STM32F407开发板,在裸机工程中的对应文件为:Core\Src\system_stm32f4xx.c。

  • 修改芯片外设驱动头文件。

删除原stm32f429芯片外设驱动的头文件STM32F407_OpenEdv\Inc\stm32f429xx.h,替换为新开发版对应的文件,可以直接使用裸机工程中的Drivers\CMSIS\Device\ST\STM32F4xx\Include\stm32f407xx.h文件。

同时注意在某些文件中可能引用了原芯片外设的头文件stm32f429xx.h,需要在文件中改为stm32f407xx.h。目前在新增开发板STM32F407_OpenEdv目录下,只有include\asm\hal_platform_ints.h中的引用了stm32f429xx.h,修改 #include “stm32f429xx.h”#include “stm32f407xx.h”
2. 移植HAL库配置文件。

直接用裸机工程中的Core\Inc\stm32f4xx_hal_conf.h文件替换STM32F407_OpenEdv\Inc\stm32f4xx_hal_conf.h即可。
3. 注释随机数代码。

目前不需要使用随机数,为减少不必要的移植工作,先注释随机数相关代码。搜索关键字“rng”,在STM32F407_OpenEdv目录下找到以下几处使用,将其注释掉:

  • Src\sys_init.c中:

/*
int atiny_random(void *output, size_t len)
{
return hal_rng_generate_buffer(output, len);
}
*/

  • Src\main.c中:

VOID HardwareInit(VOID)
{
SystemClock_Config();
MX_USART1_UART_Init();
// hal_rng_config();
dwt_delay_init(SystemCoreClock);
}

  1. 在STM32F407_OpenEdv\Src\main.c硬件初始化函数的第一行,添加初始化HAL库的函数HAL_Init():

VOID HardwareInit(VOID)
{
HAL_Init();
SystemClock_Config();
MX_USART1_UART_Init();
// hal_rng_config();
dwt_delay_init(SystemCoreClock);
}

配置系统时钟
  1. 设置系统主频。

可在STM32F407_OpenEdv\include\hisoc\clock.h文件中设置,一般将时间频率设置为SystemCoreClock,实现代码为:

#define get_bus_clk() SystemCoreClock

  1. 修改系统时钟配置函数SystemClock_Config()。

函数定义在STM32F407_OpenEdv\Src\sys_init.c文件中,可以直接使用裸机工程Core\Src\main.c中的函数实现。同时在函数结束前加上 SystemCoreClockUpdate(); 调用。

适配串口初始化文件
  1. 使用裸机工程的串口初始化文件Core\Src\usart.cCore\Inc\usart.h替换LiteOS源码中的targets\STM32F407_OpenEdv\Src\usart.ctargets\STM32F407_OpenEdv\Inc\usart.h
  2. 在targets\STM32F407_OpenEdv\Inc\usart.h中增加对STM32F4系列芯片的HAL驱动头文件的引用:

#include “stm32f4xx_hal.h”

  1. 在targets\STM32F407_OpenEdv\Src\usart.c文件尾部添加如下两个函数定义:

attribute((used)) int _write(int fd, char *ptr, int len)
{
(void)HAL_UART_Transmit(&huart1, (uint8_t *)ptr, len, 0xFFFF);
return len;
}
int uart_write(const char *buf, int len, int timeout)
{
(void)HAL_UART_Transmit(&huart1, (uint8_t *)buf, len, 0xFFFF);
return len;
}

修改链接脚本

STM32F407_OpenEdv\liteos.ld是新开发板的链接脚本,需要根据开发板实际情况修改stack,flash,ram的值,可以参考裸机工程链接脚本STM32F407ZGTx_FLASH.ld中的设定值进行设置。

  • stack在链接脚本中对应的是“_estack”变量。
  • flash 对应的是“FLASH”变量。
  • ram对应的是“RAM ”变量。

同时为适配LiteOS操作系统,链接脚本中增加了如下代码:

  1. 增加了一个vector,用于初始化LiteOS:

/* used by the startup to initialize liteos vector */
_si_liteos_vector_data = LOADADDR(.vector_ram);

/* Initialized liteos vector sections goes into RAM, load LMA copy after code */
.vector_ram :
{
. = ORIGIN(RAM);
_s_liteos_vector = .;
(.data.vector) / liteos vector in ram */
_e_liteos_vector = .;
} > RAM AT> FLASH

  1. 在.bss段中增加“__bss_end”变量的定义,因为在LiteOS中使用的是这个变量而非“bss_end”变量:

__bss_end = _ebss;

  1. 设置LiteOS使用的内存池的地址,包括起始地址和结束地址:

. = ALIGN(8);
los_heap_addr_start = .;
los_heap_addr_end = ORIGIN(RAM) + LENGTH(RAM) - _Min_Stack_Size - 1;

适配编译配置
修改开发板Makefile文件
  1. 将所有“Cloud_STM32F429IGTx_FIRE”替换成“STM32F407_OpenEdv”。
  2. STM32F407_OpenEdv目录结构相对于Cloud_STM32F429IGTx_FIRE工程的目录少了一些文件和子目录,需要在Makefile中删除对这些目录文件的引用,即删除如下内容:

HARDWARE_SRC =
${wildcard $(LITEOSTOPDIR)/targets/Cloud_STM32F429IGTx_FIRE/Hardware/Src/*.c}
C_SOURCES += $(HARDWARE_SRC)

HARDWARE_INC =
-I $(LITEOSTOPDIR)/targets/Cloud_STM32F429IGTx_FIRE/Hardware/Inc
BOARD_INCLUDES += $(HARDWARE_INC)

  1. 搜索关键字“STM32F429”,替换为“STM32F407”。
  2. 如果需要添加自己的源文件,可以将该源文件添加到“USER_SRC”变量中。
添加新开发板到系统配置中
  1. 修改targets\targets.mk。

可以参考其他开发板的编译配置,新增正点原子开发板的配置,如下所示:

######################### STM32F407ZGTX Options###############################
else ifeq ($(LOSCFG_PLATFORM_STM32F407ZGTX), y)
TIMER_TYPE := arm/timer/arm_cortex_m
LITEOS_CMACRO_TEST += -DSTM32F407xx
HAL_DRIVER_TYPE := STM32F4xx_HAL_Driver

  1. 新增STM32F407_OpenEdv.config。

在tools\build\config文件夹下复制Cloud_STM32F429IGTx_FIRE.config文件,并重命名为STM32F407_OpenEdv.config,同时将文件内容中的“Cloud_STM32F429IGTx_FIRE”改为“STM32F407_OpenEdv”,将“LOSCFG_PLATFORM_STM32F429IGTX”改为“LOSCFG_PLATFORM_STM32F407ZGTX”。
3. 修改.config。

复制tools\build\config\STM32F407_OpenEdv.config文件到LiteOS根目录下,并重命名为.config以替换根目录下原有的.config文件。

在LiteOS Studio上验证

通过编译和烧录,验证移植后的LiteOS源码,验证方法可以参考“使用LiteOS Studio测试裸机工程”。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FF3vE5G0-1665821485121)(https://github.com/LiteOS/LiteOS/raw/master/doc/public_sys-resources/icon-note.gif)] 说明: 对于移植后的LiteOS源码,其Makefile文件在源码根目录下,编译生成的镜像文件Huawei_LiteOS.bin在根目录的out目录下。

将Huawei_LiteOS.bin烧录到开发板后,复位开发板,可以在串口看到类似下图的输出:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8ooBNT1S-1665821485121)(https://github.com/LiteOS/LiteOS/raw/master/doc/figures/LiteOS%E7%89%88%E6%9C%AC%E8%BE%93%E5%87%BA.png)]

任务创建示例

任务处理函数简介

LiteOS的main函数定义在开发板工程的main.c文件中,主要负责硬件和内核的初始化工作,并在初始化完成后开始任务调度。在main() 调用的OsMain函数中,会调用OsAppInit() 创建一个名为“app_Task”的任务,该任务的处理函数为app_init()。用户可以直接在app_init()中添加自己的代码,可以为一段功能代码或者是一个任务。

创建任务
任务简介

LiteOS支持多任务。在LiteOS 中,一个任务表示一个线程。任务可以使用或等待CPU、使用内存空间等系统资源,并独立于其它任务运行。LiteOS实现了任务之间的切换和通信,帮助开发者管理业务程序流程。开发者可以将更多的精力投入到业务功能的实现中。

在LiteOS中,通过函数LOS_TaskCreate()创建任务,LOS_TaskCreate()函数原型在kernel\base\los_task.c文件中定义。调用LOS_TaskCreate()创建一个任务后,任务就会进入就绪状态。

任务创建流程

下面以一个循环亮灯任务为例,介绍LiteOS任务创建流程。

在移植好的开发板工程“targets\开发板名称\Src\main.c”文件中按照如下流程创建任务:

  1. 编写任务函数,创建两个不同闪烁频率的LED指示灯任务:

UINT32 LED1_init(VOID)
{
while(1) {
HAL_GPIO_TogglePin(GPIOF, GPIO_PIN_9); // 需要和“创建裸机工程”中配置的LED灯引脚对应
LOS_TaskDelay(500000);
}
return 0;
}

UINT32 LED2_init(VOID)
{
while(1) {
HAL_GPIO_TogglePin(GPIOF, GPIO_PIN_10); // 需要和“创建裸机工程”中配置的LED灯引脚对应
LOS_TaskDelay(1000000);
}
return 0;
}

  1. 配置两个任务的参数并创建任务:

STATIC UINT32 LED1TaskCreate(VOID)
{
UINT32 taskId;
TSK_INIT_PARAM_S LEDTask;

(VOID)memset_s(&LEDTask, sizeof(TSK_INIT_PARAM_S), 0, sizeof(TSK_INIT_PARAM_S));
LEDTask.pfnTaskEntry = (TSK_ENTRY_FUNC)LED1_init;
LEDTask.uwStackSize = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE;
LEDTask.pcName = “LED1_Task”;
LEDTask.usTaskPrio = LOSCFG_BASE_CORE_TSK_DEFAULT_PRIO;
LEDTask.uwResved = LOS_TASK_STATUS_DETACHED;
return LOS_TaskCreate(&taskId, &LEDTask);
}

STATIC UINT32 LED2TaskCreate(VOID)
{
UINT32 taskId;
TSK_INIT_PARAM_S LEDTask;

(VOID)memset_s(&LEDTask, sizeof(TSK_INIT_PARAM_S), 0, sizeof(TSK_INIT_PARAM_S));
LEDTask.pfnTaskEntry = (TSK_ENTRY_FUNC)LED2_init;
LEDTask.uwStackSize = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE;
LEDTask.pcName = “LED2_Task”;
LEDTask.usTaskPrio = LOSCFG_BASE_CORE_TSK_DEFAULT_PRIO;
LEDTask.uwResved = LOS_TASK_STATUS_DETACHED;
return LOS_TaskCreate(&taskId, &LEDTask);
}

  1. 在硬件初始化函数HardwareInit()中增加对LED灯的初始化:

MX_GPIO_Init();

  1. 对于移植好的STM32F407_OpenEdv工程,任务处理函数app_init定义在targets\STM32F407_OpenEdv\Src\user_task.c文件中,其中包含了网络、文件系统等相关的任务,目前并不需要执行这些任务,可在targets\STM32F407_OpenEdv\Makefile的“USER_SRC”变量中删除这个文件,后续有相关任务需求时,可以参考这个文件的实现。
  2. 在main.c文件的main()函数前实现任务处理函数app_init(),添加对LED任务创建函数的调用:

UINT32 app_init(VOID)
{
LED1TaskCreate();
LED2TaskCreate();

return 0;
}

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip1024b (备注Go)
img

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
sk”的任务,该任务的处理函数为app_init()。用户可以直接在app_init()中添加自己的代码,可以为一段功能代码或者是一个任务。

创建任务
任务简介

LiteOS支持多任务。在LiteOS 中,一个任务表示一个线程。任务可以使用或等待CPU、使用内存空间等系统资源,并独立于其它任务运行。LiteOS实现了任务之间的切换和通信,帮助开发者管理业务程序流程。开发者可以将更多的精力投入到业务功能的实现中。

在LiteOS中,通过函数LOS_TaskCreate()创建任务,LOS_TaskCreate()函数原型在kernel\base\los_task.c文件中定义。调用LOS_TaskCreate()创建一个任务后,任务就会进入就绪状态。

任务创建流程

下面以一个循环亮灯任务为例,介绍LiteOS任务创建流程。

在移植好的开发板工程“targets\开发板名称\Src\main.c”文件中按照如下流程创建任务:

  1. 编写任务函数,创建两个不同闪烁频率的LED指示灯任务:

UINT32 LED1_init(VOID)
{
while(1) {
HAL_GPIO_TogglePin(GPIOF, GPIO_PIN_9); // 需要和“创建裸机工程”中配置的LED灯引脚对应
LOS_TaskDelay(500000);
}
return 0;
}

UINT32 LED2_init(VOID)
{
while(1) {
HAL_GPIO_TogglePin(GPIOF, GPIO_PIN_10); // 需要和“创建裸机工程”中配置的LED灯引脚对应
LOS_TaskDelay(1000000);
}
return 0;
}

  1. 配置两个任务的参数并创建任务:

STATIC UINT32 LED1TaskCreate(VOID)
{
UINT32 taskId;
TSK_INIT_PARAM_S LEDTask;

(VOID)memset_s(&LEDTask, sizeof(TSK_INIT_PARAM_S), 0, sizeof(TSK_INIT_PARAM_S));
LEDTask.pfnTaskEntry = (TSK_ENTRY_FUNC)LED1_init;
LEDTask.uwStackSize = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE;
LEDTask.pcName = “LED1_Task”;
LEDTask.usTaskPrio = LOSCFG_BASE_CORE_TSK_DEFAULT_PRIO;
LEDTask.uwResved = LOS_TASK_STATUS_DETACHED;
return LOS_TaskCreate(&taskId, &LEDTask);
}

STATIC UINT32 LED2TaskCreate(VOID)
{
UINT32 taskId;
TSK_INIT_PARAM_S LEDTask;

(VOID)memset_s(&LEDTask, sizeof(TSK_INIT_PARAM_S), 0, sizeof(TSK_INIT_PARAM_S));
LEDTask.pfnTaskEntry = (TSK_ENTRY_FUNC)LED2_init;
LEDTask.uwStackSize = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE;
LEDTask.pcName = “LED2_Task”;
LEDTask.usTaskPrio = LOSCFG_BASE_CORE_TSK_DEFAULT_PRIO;
LEDTask.uwResved = LOS_TASK_STATUS_DETACHED;
return LOS_TaskCreate(&taskId, &LEDTask);
}

  1. 在硬件初始化函数HardwareInit()中增加对LED灯的初始化:

MX_GPIO_Init();

  1. 对于移植好的STM32F407_OpenEdv工程,任务处理函数app_init定义在targets\STM32F407_OpenEdv\Src\user_task.c文件中,其中包含了网络、文件系统等相关的任务,目前并不需要执行这些任务,可在targets\STM32F407_OpenEdv\Makefile的“USER_SRC”变量中删除这个文件,后续有相关任务需求时,可以参考这个文件的实现。
  2. 在main.c文件的main()函数前实现任务处理函数app_init(),添加对LED任务创建函数的调用:

UINT32 app_init(VOID)
{
LED1TaskCreate();
LED2TaskCreate();

return 0;
}

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip1024b (备注Go)
[外链图片转存中…(img-2jsa6ihz-1713216587069)]

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 28
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值