我们的题目核心是使用 SensorTile 实现音频处理。
在音频处理、电机控制等很多应用中经常会用到一些常见的正余弦,矩阵计算,FFT等一些DSP函数。提到DSP库,通常会想到使用ARM 公司提供的 CMSIS 库。CMSIS 库是ARM和一些半导体厂家针对Cortex-M系列制定的一套接口标准,包括针对内核操作的CMSIS-CORE API,针对DSP应用的CMSIS-DSP Library,针对RTOS的CMSIS-RTOS API,与外设接口的CMSIS-SVD以及提供Debug访问接口的CMSIS-DAP。 其中,又以DSP应用的CMSIS-DSP 库的应用最为广泛。针对Cortex-M4中的DSP功能,CMSIS-DSP部分提供了超过60多种功能的DSP算法库,尤其是随着Cortex-M4中集成了FPU硬件单元,CMSIS-DSP 库的应用也越来越广泛。
在KEIL 中集成了对CMSIS的支持,以下将阐述如何在 Keil uv5 项目中引入 DSP 库,以及开始使用。
1. 引入 CMSIS-DSP .lib 文件
Keil uv5 已经简化了许多步骤,只需要从运行时环境管理界面里,勾选 CMSIS DSP 就可以。
如果使用的是老版本 Keil,则手动找到并引入
arm_cortexM4lf_math.lib 即可。
2. 设置宏定义。
在项目选项窗口→C/C++→Define 中添加:
ARM_MATH_CM4,__FPU_PRESENT=1
这段的意思是使用 Cortex-M4 的 指令集加速计算。此外,由于 SensorTile 采用的 STM32L4 含有 FPU(浮点数硬件加速单元),可以用此大大提升浮点数的计算速度。
注意分隔符(逗号)!
3. 开发程序
编写算法代码时,需要引入两个头文件(第二个主要是为 FFT 准备的,若不需要,可以省略):
- #include <arm_math.h>
- #include <arm_const_structs.h>
如果是使用第一步中的方法引入的 DSP 库,则能够自动解决头文件路径问题,否则……自己把头文件路径添加到工程选项里吧。
接下来就可以愉快地使用 CMSIS DSP 库快速地完成一些科学运算了。
在 Keil 安装文件夹下有一个 CMSIS\DSP_Lib\Examples,可以找到一些使用例子。
在
https://www.keil.com/pack/doc/CMSIS/DSP/html/modules.html 可以找到API使用手册。
以下是一个简单的矩阵运算例子,涉及到了矩阵的 转置、求逆、类似MATLAB的“点乘” 以及 DSP矩阵的初始化:
- /** \example arm_matrix_example_f32.c
- */
- #include "arm_math.h"
- #include "math_helper.h"
- #define SNR_THRESHOLD 90
- /* --------------------------------------------------------------------------------
- * Test input data(Cycles) taken from FIR Q15 module for differant cases of blockSize
- * and tapSize
- * --------------------------------------------------------------------------------- */
- const float32_t B_f32[4] =
- {
- 782.0, 7577.0, 470.0, 4505.0
- };
- /* --------------------------------------------------------------------------------
- * Formula to fit is C1 + C2 * numTaps + C3 * blockSize + C4 * numTaps * blockSize
- * -------------------------------------------------------------------------------- */
- const float32_t A_f32[16] =
- {
- /* Const, numTaps, blockSize, numTaps*blockSize */
- 1.0, 32.0, 4.0, 128.0,
- 1.0, 32.0, 64.0, 2048.0,
- 1.0, 16.0, 4.0, 64.0,
- 1.0, 16.0, 64.0, 1024.0,
- };
- /* ----------------------------------------------------------------------
- * Temporary buffers for storing intermediate values
- * ------------------------------------------------------------------- */
- /* Transpose of A Buffer */
- float32_t AT_f32[16];
- /* (Transpose of A * A) Buffer */
- float32_t ATMA_f32[16];
- /* Inverse(Transpose of A * A) Buffer */
- float32_t ATMAI_f32[16];
- /* Test Output Buffer */
- float32_t X_f32[4];
- /* ----------------------------------------------------------------------
- * Reference ouput buffer C1, C2, C3 and C4 taken from MATLAB
- * ------------------------------------------------------------------- */
- const float32_t xRef_f32[4] = {73.0, 8.0, 21.25, 2.875};
- float32_t snr;
- /* ----------------------------------------------------------------------
- * Max magnitude FFT Bin test
- * ------------------------------------------------------------------- */
- int32_t main(void)
- {
- arm_matrix_instance_f32 A; /* Matrix A Instance */
- arm_matrix_instance_f32 AT; /* Matrix AT(A transpose) instance */
- arm_matrix_instance_f32 ATMA; /* Matrix ATMA( AT multiply with A) instance */
- arm_matrix_instance_f32 ATMAI; /* Matrix ATMAI(Inverse of ATMA) instance */
- arm_matrix_instance_f32 B; /* Matrix B instance */
- arm_matrix_instance_f32 X; /* Matrix X(Unknown Matrix) instance */
- uint32_t srcRows, srcColumns; /* Temporary variables */
- arm_status status;
- /* Initialise A Matrix Instance with numRows, numCols and data array(A_f32) */
- srcRows = 4;
- srcColumns = 4;
- arm_mat_init_f32(&A, srcRows, srcColumns, (float32_t *)A_f32);
- /* Initialise Matrix Instance AT with numRows, numCols and data array(AT_f32) */
- srcRows = 4;
- srcColumns = 4;
- arm_mat_init_f32(&AT, srcRows, srcColumns, AT_f32);
- /* calculation of A transpose */
- status = arm_mat_trans_f32(&A, &AT);
- /* Initialise ATMA Matrix Instance with numRows, numCols and data array(ATMA_f32) */
- srcRows = 4;
- srcColumns = 4;
- arm_mat_init_f32(&ATMA, srcRows, srcColumns, ATMA_f32);
- /* calculation of AT Multiply with A */
- status = arm_mat_mult_f32(&AT, &A, &ATMA);
- /* Initialise ATMAI Matrix Instance with numRows, numCols and data array(ATMAI_f32) */
- srcRows = 4;
- srcColumns = 4;
- arm_mat_init_f32(&ATMAI, srcRows, srcColumns, ATMAI_f32);
- /* calculation of Inverse((Transpose(A) * A) */
- status = arm_mat_inverse_f32(&ATMA, &ATMAI);
- /* calculation of (Inverse((Transpose(A) * A)) * Transpose(A)) */
- status = arm_mat_mult_f32(&ATMAI, &AT, &ATMA);
- /* Initialise B Matrix Instance with numRows, numCols and data array(B_f32) */
- srcRows = 4;
- srcColumns = 1;
- arm_mat_init_f32(&B, srcRows, srcColumns, (float32_t *)B_f32);
- /* Initialise X Matrix Instance with numRows, numCols and data array(X_f32) */
- srcRows = 4;
- srcColumns = 1;
- arm_mat_init_f32(&X, srcRows, srcColumns, X_f32);
- /* calculation ((Inverse((Transpose(A) * A)) * Transpose(A)) * B) */
- status = arm_mat_mult_f32(&ATMA, &B, &X);
- /* Comparison of reference with test output */
- snr = arm_snr_f32((float32_t *)xRef_f32, X_f32, 4);
- /*------------------------------------------------------------------------------
- * Initialise status depending on SNR calculations
- *------------------------------------------------------------------------------*/
- if( snr > SNR_THRESHOLD)
- {
- status = ARM_MATH_SUCCESS;
- }
- else
- {
- status = ARM_MATH_TEST_FAILURE;
- }
- /* ----------------------------------------------------------------------
- ** Loop here if the signals fail the PASS check.
- ** This denotes a test failure
- ** ------------------------------------------------------------------- */
- if( status != ARM_MATH_SUCCESS)
- {
- while(1);
- }
- while(1); /* main function does not return */
- }