CMSIS-DSP
介绍
CMSIS-DSP 是为嵌入式系统优化的计算库(由于历史原因,DSP 在名称中保留)。
它为 Cortex-M 和 Cortex-A 提供了优化的计算内核。
根据核心的不同,有不同的变体可用,而且大多数函数在有 Helium 或 Neon 扩展时都会使用向量化版本。
这个仓库包含了 CMSIS-DSP 库和其他几个项目:
- 针对裸金属 Cortex-M 或 Cortex-A 的测试框架
- 针对裸金属 Cortex-M 的示例
- ComputeGraph
- PythonWrapper
你不需要其他任何项目就可以构建和使用 CMSIS-DSP 库。构建其他项目可能需要安装其他库(CMSIS)、其他工具(Arm Virtual Hardware)或 CMSIS 构建工具。
许可条款
CMSIS-DSP 采用 Apache License 2.0 许可。
CMSIS-DSP 内核
CMSIS-DSP 提供的内核(列表不完整):
- 基本数学(实数、复数、四元数、线性代数、快速数学函数)
- DSP(滤波)
- 变换(FFT、MFCC、DCT)
- 统计
- 经典机器学习(支持向量机、用于聚类的距离函数等)
内核提供多种数据类型:f64、f32、f16、q31、q15、q7。
Python wrapper
一个 PythonWrapper 也可用,可以通过以下方式安装:
pip install cmsisdsp
通过这个 wrapper,你可以在 Python 中使用尽可能接近 C API 的 API 设计你的算法。该 wrapper 兼容 NumPy,并支持定点算术。这个 wrapper 也可以在 google colab 中工作。
其目标是使从设计到最终 C 实现的过渡更加容易。
支持 / 联系
如有任何问题或需要联系 CMSIS-DSP 团队,请在 https://github.com/ARM-software/CMSIS-DSP/issues 中创建一个新问题。
内容目录
为速度构建
CMSIS-DSP 用于需要性能的场合。因此,CMSIS-DSP 应该使用能够提供最佳性能的选项进行编译:
推荐使用的选项
- 为了获得最佳性能,必须使用
-Ofast
。 - 使用 Helium 时,强烈建议使用
-Ofast
- 当前使用 GCC 针对 Helium 时性能不佳。你应使用 Arm 编译器
当使用浮点数时,应选择 fpu 以确保编译器没有使用软件浮点模拟。
使用 Helium 支持进行构建时,CMSIS-DSP 会自动检测到。对于 Neon 不是这种情况,你必须为 C 编译启用 -DARM_MATH_NEON
选项。在使用 cmake
时,此选项由 -DNEON=ON
控制。
-DLOOPUNROLL=ON
也可以在使用 cmake 编译时使用- 它对应于 C 选项
-DARM_MATH_LOOPUNROLL
编译器会进行循环展开。因此,可能不需要这个选项,但高度依赖于编译器。对某些编译器,需要这个选项才能获得更好的性能。
内存速度很重要。如果你能将数据和 CMSIS-DSP 使用的常量表映射到 DTCM
内存中,那就更好。如果有缓存,请启用它。
应避免的选项
-fno-builtin
-ffreestanding
因为它启用了前面的选项
库正在做一些类型 punning 以将内存中的 32 位字作为 q15
对或 q7
四元组进行处理。这些类型操作通过 memcpy
函数完成。当要复制的长度较小时(4 字节),大多数编译器应能够优化掉这些函数调用。
当使用 -fno-builtin
时,这种优化将 不 会发生,并且会对性能产生 非常不好的 影响。
某些编译器也可能需要使用选项 -munaligned-access
来指定使用未对齐的访问。
半浮点支持
f16
数据类型(半浮点)已添加到库中。仅当你的 Cortex 有一些半浮点硬件加速(例如 Helium 扩展)时,它才有用。如果你不需要 f16
,应禁用它,因为它可能导致编译问题。构建时只需定义 -DDISABLEFLOAT16
。
如何构建
你可以使用 open CMSIS-Pack、cmake 或 Makefile 来构建 CMSIS-DSP,并且如果使用其他任何构建工具,也很容易构建。
如何使用 MDK 或 Open CMSIS-Pack 进行构建
标准的构建方式是使用 CMSIS 打包技术。CMSIS-DSP 作为一个包提供。
这种包技术由一些 IDE 支持,例如 Keil MDK 或 Keil studio。
你也可以使用 Open CMSIS-Pack 技术和命令行在任何平台上使用这些包。
你应该首先从 https://github.com/Open-CMSIS-Pack/devtools/tree/main/tools 安装工具
你可以获得包含包安装程序、cmsis build 和 cmsis project manager 的 CMSIS-Toolbox。以下是一些文档:
- 关于 CMSIS Build 的文档
- 关于 CMSIS Pack 的文档
- 关于 CMSIS Project manager 的文档
安装工具后,你需要使用 cpackget
工具下载包索引。
然后,你需要将解决方案文件转换为 .cprj
。例如,对于 CMSIS-DSP 示例,你可以前往:
Examples/cmsis_build
然后输入
csolution convert -s examples.csolution_ac6.yml
此命令处理描述如何为多个平台构建示例的 examples.csolution_ac6.yml
。它会生成很多可以用 cbuild
构建的 .cprj
文件。
如果你想为 Corstone-300
虚拟硬件平台构建 FFT
示例,只需执行:
cbuild "fftbin.Release+VHT-Corstone-300.cprj"
如何使用 Make 进行构建
Source
中有一个 Makefile
示例。
在每个源文件夹(如 BasicMathFunctions
)中,你会看到没有 _datatype
后缀的文件(如 BasicMathFunctions.c
和 BasicMathFunctionsF16.c
)。
这些文件是你在 makefile 中所需的全部文件。它们包括了源文件夹中的所有其他 C 文件。
然后,对于包含文件,你需要添加路径:Include
、PrivateInclude
,并且由于依赖 CMSIS Core,还需要 CMSIS_5/CMSIS
中的 Core/Include
。
如果你为 Cortex-A
构建并且想使用 Neon,还需要包含 ComputeLibrary/Include
和 ComputeLibrary/Source
中的源文件。
如何使用 cmake 进行构建
创建一个 CMakeLists.txt
并在其中添加一个项目。
将 CMSIS-DSP 作为子目录添加。下面示例中的变量 CMSISDSP
是 CMSIS-DSP 存储库的路径。
cmake_minimum_required (VERSION 3.14)
# 定义项目
project (testcmsisdsp VERSION 0.1)
add_subdirectory(${CMSISDSP}/Source bin_dsp)
CMSIS-DSP 依赖于 CMSIS Core includes。因此,你应在 cmake 命令行中定义 CMSISCORE
。CMSIS-DSP 使用的路径将是 ${CMSISCORE}/Include
。
你还应设置用于构建库的编译选项。
如果是为 Helium 构建,你应使用任意一个选项 MVEF
、MVEI
或 HELIUM
。
如果是为 Neon 构建,使用 NEON
和/或 NEONEXPERIMENTAL
。
启动构建
一旦 cmake 已生成 makefiles,你可以使用 GNU Make 进行构建。
make VERBOSE=1
如何使用任何其他构建系统进行构建
你需要以下文件夹:
- Source
- Include
- PrivateInclude
- ComputeLibrary(仅在使用 Neon 时)
在 Source
子文件夹中,你可以构建所有带有数据类型后缀(如 _f32.c
)的源文件,或者只编译没有数据类型后缀的文件。例如,对于 BasicMathFunctions
,你可以构建所有 C 文件,除了 BasicMathFunctions.c
和 BasicMathFunctionsF16.c
,或者你可以只构建这两个文件(它们包括了文件夹中的所有其他 C 文件)。
f16
文件不是必需的。你可以使用 -DDISABLEFLOAT16
进行构建。
如何为 aarch64 构建
Core_A/Include
中定义的内在函数在最近的 Cortex-A 处理器上不可用。
但你仍然可以为这些 Cortex-A 内核构建并受益于 Neon 内在函数。
你需要在编译器命令行中使用 -D__GNUC_PYTHON__
构建。该标志是为构建 Python wrapper 引入的,并禁用了 CMSIS Core includes 的使用。
启用该标志时,CMSIS-DSP 在库中定义了一些用于编译器可移植性的宏:
#define __ALIGNED(x) __attribute__((aligned(x)))
#define __STATIC_FORCEINLINE static inline __attribute__((always_inline))
#define __STATIC_INLINE static inline
如果你使用的编译器需要不同的定义,你可以将它们添加到库的 Include
文件夹中的 arm_math_types.h
。MSVC 和 XCode 已经支持,在这些情况下,不需要定义 -D__GNUC_PYTHON__
然后,你需要定义 -DARM_MATH_NEON
对于 cmake,等效选项是:
-DHOST=ON
-DNEON=ON
cmake 会自动包括 ComputeLibrary
文件夹。如果你使用不同的构建工具,也需要包括该文件夹以支持 Neon。
代码大小
之前版本的库使用编译指令来控制代码大小。这太复杂了,并且当 CMSIS-DSP 仅作为静态库提供时不可用。
现在,库再次依赖于链接器来进行代码大小优化。但这对你编写的代码有一些限制,并且新函数需要引入。
如果你提前知道 FFT 的大小,使用诸如 arm_cfft_init_64_f32
的初始化函数代替使用通用的初始化函数 arm_cfft_init_f32
。使用通用函数将阻止链接器能够推断出哪些函数和表必须保留,因此一切都会被包含。
RFFT、MFCC 也有类似的函数。
如果标志 ARM_DSP_CONFIG_TABLES
仍然设置,你现在会得到一个编译错误,提醒你该标志不再对代码大小有任何影响,并且你可能需要重新调整初始化。
文件夹和文件
构建和使用 CMSIS-DSP 库所需的文件夹是:
- Source
- Include
- PrivateInclude
- ComputeLibrary(仅在使用 Neon 时)
其他文件夹是不同项目、测试或示例的一部分。
文件夹
- cmsisdsp
- 构建用于 Python 存储库的 CMSIS-DSP PythonWrapper 所需
- 它包含所有 Python 包
- ComputeLibrary:
- 构建具有 Neon 加速的 CMSIS-DSP 时所需的一些内核
- Examples:
- 在裸金属 Cortex-M 上使用 CMSIS-DSP 的示例
- 需要使用 CMSIS 构建工具
- Include:
- CMSIS-DSP 的包含文件
- PrivateInclude:
- 构建 CMSIS-DSP 所需的一些包括
- PythonWrapper:
- CMSIS-DSP PythonWrapper 的 C 代码
- PythonWrapper 的示例
- Scripts:
- 调试脚本
- 生成 CMSIS-DSP 使用的某些系数表的脚本
- Source:
- CMSIS-DSP 源码
- Testing:
- 裸金属 Cortex-M 和 Cortex-A 的 CMSIS-DSP 测试框架
- 需要使用 CMSIS 构建工具
文件
生成 PythonWrapper 所需的某些文件:
- PythonWrapper_README.md
- LICENSE
- MANIFEST.in
- pyproject.toml
- setup.py