使用C++开发STM32 FreeRTOS工程与添加DSP库

  续上一篇文章的内容。由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);
    }
}

修改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 $@

  这里的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

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

  • 4
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小裘HUST

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值