当前位置:   article > 正文

使用C++开发STM32 FreeRTOS工程与添加DSP库_stm32 freertos和c++

stm32 freertos和c++

  续上一篇文章的内容。由CubeMX构建的Makefile工程只支持C和汇编的编译,而且FreeRTOS的代码也需要作为C代码编译。
  当我们想使用C++时,需要做一些准备并且修改Makefile;另外本文补充了一下DSP库的调用方式。参考了另外两位博主的文章:

FreeRTOS与C++

  FreeRTOS的代码是必须作为C语言编译的。C++可以调用C函数,而且也可以在C++的源文件里写C函数。但是C的源文件里不能调用C++相关的东西,比如在C源文件里创建一个类的对象是不行的。
  所以我觉得最好的做法是把任务的定义放到自己的C++源文件中,而在FreeRTOS的C文件中用“extern”声明任务函数。
在这里插入图片描述
  具体做法就是在用CubeMX创建Task的时候,把任务的函数都设置成external。这里的默认选项是既有声明又有实现;exteral选项就是只有一个带extern的任务函数声明;还有一个weak选项表示这个任务函数有一个默认的实现,但可以被外部的定义覆盖,类似于C++中的虚函数的重新定义。
  我一般会把CubeMX工程中的下面的设置勾上。这样不同的外设就会有一个单独的.c和.h文件。
在这里插入图片描述
  然后就可以自己创建一个C++源文件来定义这几个任务函数。
在这里插入图片描述
  任务函数的声明需要放在 extern “C” {} 中,然后就可以在任务函数中创建类的对象,调用成员函数等。
  就像下面这个形式,可以把一堆任务函数的声明都放在一个 extern “C” {} 中,后面逐个对这些任务函数进行定义。

extern "C"
{
void BlinkTskFxn(void *argument);
...
}

...

void BlinkTskFxn(void *argument)
{
    for(;;){
        HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
        osDelay(500);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

修改Makefile

  Makefile的修改可以参考前面提到的另一篇博文。总得来说就是新增了一套编译C++源文件的规则。

CXX_SOURCES = \
...

ifdef GCC_PATH
CXX = $(GCC_PATH)/$(PREFIX)g++
...
else
CXX = $(PREFIX)g++
...
endif

CXXFLAGS = $(MCU) $(C_DEFS) $(C_INCLUDES) $(OPT) -Wall -fdata-sections -ffunction-sections -std=c++11

CXXFLAGS += -g -gdwarf-2

CXXFLAGS += -MMD -MP -MF"$(@:%.o=%.d)"

LDFLAGS = $(MCU) -specs=nano.specs -specs=nosys.specs -T$(LDSCRIPT) $(LIBDIR) $(LIBS) -Wl,-Map=$(BUILD_DIR)/$(TARGET).map,--cref -Wl,--gc-sections 

OBJECTS += $(addprefix $(BUILD_DIR)/,$(notdir $(CXX_SOURCES:.cpp=.o)))
vpath %.cpp $(sort $(dir $(CXX_SOURCES)))

$(BUILD_DIR)/%.o: %.cpp Makefile | $(BUILD_DIR)
    $(CXX) -c $(CXXFLAGS) -Wa,-a,-ad,-alms=$(BUILD_DIR)/$(notdir $(<:.cpp=.lst)) $< -o $@

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

  这里的CXX_SOURCES用于列出需要编译的C++源文件;CXX表示编译器,CXXFLAGS中包含编译选项,其中沿用的C_DEFS和C_INCLUDES,这表示即使把编译器改成g++,之前gcc用的define和include路径还是相同的。
  LDFLAGS是link的选项,其中相比于之前的LDFLAGS新增了-specs=nosys.specs,这是必不可少的,如果没有的话编译就会报错,具体做了什么我没太搞明白。-specs=nano.specs表示采用精简后的C库,这个有无不会对编译是否能通过不会有影响。
在这里插入图片描述
  为了便于调试,也需要在工程的属性中为C++添加include和symbol(如果之前没有添加的话),这样就不会有那种报错的波浪线。
  在这里添加include路径和symbol的时候,有“Add to all languages”和“Add to all configurations”的选项可以勾选,这样对于一个条目就只需要添加一次就行了。不管是C还是C++,不管是Debug的配置还是Release的配置,就都能设置好,不需要再去逐个反复添加。(虽然对于Makefile工程来说没有直接的Debug和Release的区分,是否支持Debug,优化的等级都是直接改Makefile的)。

添加DSP库

  通过CubeMX添加DSP库真的非常快。参考前面提到的另一篇博文,在“Pinout & Configuration”界面点“Software Packs”选择组件。
在这里插入图片描述
  然后就可以安装DSP库并勾选它。
在这里插入图片描述
  这时候再回到CubeMX的工程就可以看到左边多了一栏Software Packs,选择它之后再把DSP Library勾选上,令当前的CubeMX工程支持DSP Library。
在这里插入图片描述
  通过这些配置生成的Makefile工程将另外生成DSP库的头文件和预编译好的lib文件,并放在Middlewares目录下。
在这里插入图片描述
  预编译好的lib文件有三种,开头的arm,iar,libarm应该是区分它们是在不同的环境下编译的。l后缀表示小端模式,f后缀表示使用FPU。
  我一开始尝试用arm_cortexM4lf_math.lib,编译会有warning,说这个库用的wchar_t类型是2字节的,而我们的工程中用的是4字节的,这不兼容。后来用iar_cortexM4lf_math.a就没有这个问题。
  关于DSP库的API,可以在官方文档里找到。如果是从源文件开始编译DSP库,还有一些宏定义可以设置,比如ARM_MATH_BIG_ENDIAN设置大端模式;ARM_MATH_MATRIX_CHECK设置输入输出矩阵的维度检查……但是像现在这样用已经编译好的库,这些宏定义是没用的。就像之前要从源码编译时,需要定义__FPU_PRESENT一样,现在即使不定义也没有关系,因为源码都已经编译完成了。
  用预先编译好的DSP库,就只需要include <arm_math.h>和定义ARM_MATH_CM7, ARM_MATH_CM4, ARM_MATH_CM3, ARM_MATH_CM0PLUS, ARM_MATH_CM0, ARM_MATH_ARMV8MBL, ARM_MATH_ARMV8MML中的一种就好了。
在这里插入图片描述
  我再回过头来发现,即使不在CubeMX中添加DSP库,这些DSP库相关的文件随着CMSIS的device驱动一起就提供了。就在Drivers/CMSIS/Lib目录下。

# defines
-DARM_MATH_CM4

# includes
C_INCLUDES =  \
-IDrivers/CMSIS/DSP/Include

# libraries
LIBS = -lc -lm -lnosys  \
-l:iar_cortexM4lf_math.a
LIBDIR =  \
-LDrivers/CMSIS/Lib/IAR
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

  所以只需要在Makefile中增加器件相关的define和include相应的lib就行了,而不需要通过CubeMX额外导入DSP库。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家自动化/article/detail/684117
推荐阅读
相关标签
  

闽ICP备14008679号