ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

STM32 FMAC硬件滤波加速器实战:从FIR到IIR与RMS详解

STM32 FMAC硬件滤波加速器实战:从FIR到IIR与RMS详解 滤波这件事做STM32的人早晚都会撞上。我之前做电机控制项目采样率提到20kHz电流环加了一阶低通又处理了一下PWM开关噪声CPU负载就从20%飙到70%。后面还想加观测器和通信协议算力却已经见底了。有人直接上SPI外挂DSP芯片成本高、布线麻烦、调试链路还很痛。其实STM32自己也带了专用的滤波加速器叫FMACFilter Math AcceleratorG4系列和H7系列的部分型号都有。它能把FIR、IIR和RMS这类运算从CPU手里整个接走让主核腾出来干真正的控制逻辑、通信和人机交互。这篇文章我会从FMAC的硬件原理讲到寄存器级配置再到用HAL库和DMA跑一个实际的FIR低通滤波器最后把二步模式、IIR系数顺序、RMS统计这些进阶用法和踩过的坑一并交代清楚。适合刚接触FMAC、想在项目里真正用起来的人参考。1. FMAC到底是个什么东西1.1 从一次电机控制的“滤波焦虑”说起我先说我那个项目的尴尬。采样率提到20kHz后每个采样周期只有50微秒电流环要完成ADC读取、坐标变换、PID计算、PWM更新留给滤波的时间窗口非常窄。CMSIS-DSP库的arm_fir_f32确实优化得不错在Cortex-M4F上一条FMA指令就能完成乘加但数据搬运、循环开销、内存访问这些加起来一个16阶FIR处理完也要不少周期。单个采样点可能只花几微秒听起来不吓人可控制环路里不止一路信号你想滤波的电流、速度、母线电压加起来有五六路每个周期都在算CPU的预算就彻底撑不住了。FMAC正是冲着这个痛点来的。它本质上是MCU内部的一个硬件协处理器内置乘加器和专用数据缓冲能够独立完成数字滤波运算。你只要把系数下进去、把数据流喂进去它自己把结果算好再交还给你。主CPU全程不需要参与乘加运算顶多搬运数据。G4系列作为STM32家族里面向数字电源和电机控制的型号把FMAC做成标配外设是有深意的。这类应用往往需要实时性极高的滤波链路用CPU软算很容易被其他中断挤占导致延迟抖动硬件滤波则固定延迟、固定吞吐这对控制环路的稳定性意义重大。1.2 FMAC的硬件架构三块缓冲加一个专用乘加器FMAC从结构上看并不复杂它主要由输入数据缓冲、系数缓冲、输出数据缓冲和控制逻辑组成。寄存器层面体现为FMAC_X1数据缓冲、FMAC_X2系数缓冲、FMAC_Y结果缓冲几个名字在参考手册里随处可见。X1负责接收待滤波的输入采样点X2用于存放滤波系数Y用来输出结果。这三个缓冲都有独立的地址映射可以像普通内存一样被CPU或DMA读写。因为缓冲深度有限常见型号的输入和输出缓冲典型深度是8个采样点具体以参考手册为准FMAC并不适合突然塞一大块数据进去更适合配合DMA做流式处理或者用二步模式做可控的分块处理。硬件内部的核心是一个支持乘加的运算单元。FIR本质上是一串乘加累加IIR还要加上反馈项FMAC把这些运算用硬件流水线实现每个采样点的处理只消耗极少的时钟周期。更关键的是乘加运算发生在FMAC模块内部不占CPU的ALU和FPU。我在实测中的体会是FMAC跑滤波的同时CPU可以并行处理通信协议栈和逻辑判断这种“并行”带来的实时性提升比单纯省几微秒更有价值。1.3 FMAC和CMSIS-DSP到底差的在哪很多人的第一反应是既然CMSIS-DSP已经有现成的滤波函数为什么还要用FMAC我列一个直观对比就清楚了。对比维度CMSIS-DSP软件滤波FMAC硬件滤波运算主体CPU的ALU/FPU独立硬件协处理器CPU占用全程占用仅初始化配置和搬运数据时占用计算延迟受中断抢占影响有波动固定流水线延迟确定性高功耗较高CPU发热明显更低适合低功耗应用配置复杂度调用函数简单寄存器配置有一定门槛灵活性任意阶数、任意格式受硬件缓冲和数据类型限制CMSIS-DSP胜在开发效率基本上一行代码就能跑一个滤波器。但项目一旦进入量产阶段尤其是电机控制、数字电源这类对时序敏感的应用CPU负载和延迟抖动就会成为大问题。FMAC的工程意义在于它把“滤波”这件高频重复劳动从CPU任务清单里彻底删掉了。我当时切换后CPU负载直接降了四成控制环路的时序余量一下就宽裕了。2. FMAC能做什么三类运算与真实应用场景2.1 FIR滤波最常见也最好用FMAC最基础的能力就是FIR有限脉冲响应滤波。FIR的数学形式是y[n] b0 * x[n] b1 * x[n-1] ... bN * x[n-N]就是当前输入和过去N个输入做加权求和。这种结构没有反馈回路天生稳定所以工程上非常常用。FMAC把系数段放在X2系数缓冲里输入采样点依次进X1数据缓冲硬件自动完成乘法累加后把结果写入Y缓冲。FIR很适合做低通、高通、带通、带阻滤波也能用于信号整形和匹配滤波。我在逆变器项目里用FMAC做了一个16阶FIR低通专门滤掉PWM开关频率附近的高频噪声效果和之前用CMSIS-DSP时一致但CPU完全不用管滤波计算了。FIR还有个优势是线性相位对波形失真敏感的信号处理场景比如电流采样、音频处理FIR几乎是首选。需要提醒的是FIR的阶数不是无上限的。FMAC的系数缓冲深度有限高阶FIR得分段或者改用IIR。实际项目中如果只是滤高频噪声16阶到32阶的FIR已经够用。盲目的高阶级只会增加系数加载和DMA调度的负担未必划算。2.2 IIR滤波一阶和二阶级联IIR无限脉冲响应滤波引入了反馈项典型的一阶IIR公式是y[n] b0 * x[n] b1 * x[n-1] - a1 * y[n-1]二阶IIR则再带上y[n-2]项。IIR的优势是用很少的阶数就能达到很高的滤波陡度比如同样实现一个低通IIR可能只需要二阶FIR却要几十阶。代价是相位非线性以及反馈结构带来的稳定性问题。FMAC对IIR的支持分为一阶和二阶两种单元。工程里最常见的是二阶IIR也就是biquad双二阶滤波器。很多高阶滤波器都可以拆成多个biquad串联所以FMAC对biquad的支持基本覆盖了绝大多数IIR需求。我之前做音频信号预处理时用FMAC级联了三个biquad实现了一个带通滤波器代码逻辑很清晰每个biquad的系数在配置阶段一次性写入数据通路用DMA自动循环整个过程CPU只负责参数管理和状态监控。2.3 RMS统计测量电流有效值的捷径FMAC还支持RMS均方根运算。这个很多人容易忽略但它实际非常实用。RMS值的公式是“平方的平均值再开方”数学上不复杂但在采样率较高的系统里要对连续几千个采样点做平方累加纯软件算同样占用不少CPU时间。FMAC内部可以直接完成累加和开方流程输出RMS结果。电机控制里检测相电流的有效值、母线电压的有效值都是高频操作。电能质量分析或者振动监测里也经常需要RMS值来评估信号强度。FMAC把RMS做成硬件运算后我从ADC拿到数据往X1一送过一段延时就能从Y里读出结果效率和确定性都远好于软件实现。2.4 哪些芯片带FMAC怎么查不是所有STM32都带FMAC。目前常见的是STM32G4系列特别是G431、G474和STM32H7系列的部分型号比如H723、H733这类偏控制应用的型号。选型时最靠谱的方法是去ST官网翻对应型号的参考手册或者直接在CubeMX里看外设列表里有没有FMAC选项。拿到芯片后打开stm32g4xx_hal_fmac.h这类外设头文件有对应的结构体和函数就说明芯片带这个外设。我遇到不少人在G0系列或者F1系列上找FMAC翻了半天没找到其实方向就错了。FMAC是较新架构的外设老型号上不存在。如果项目已经确定用旧型号那滤波只能继续走CMSIS-DSP软算路线如果还没定芯片冲着FMAC去选G4或对应的H7型号就相当值得。3. 工程准备从零搭建FMAC运行环境3.1 软件工具与参考资料的准备清单上手FMAC之前需要的工具并不复杂STM32CubeMX做引脚和时钟树配置、Keil或IAR做编译调试、STM32CubeG4或对应H7的HAL库、ST官方的参考手册例如G4系列的RM0440和FMAC应用笔记。这些资料ST官网上都能下到按自己芯片型号选对应版本即可。如果你平时习惯寄存器开发参考手册里FMAC章节的寄存器描述写得很全如果你习惯HAL库开发HAL库的fmac相关文件里已经有配置示例参考起来也很快。刚开始跑FMAC时不要追求一步到位先用最简单的CPU轮询方式跑通一个FIR确认FMAC能正常计算再引入DMA和中断。这样排查问题时变量最少。我最初就是直接上了DMA一跑数据不对根本分不清是FMAC没配置好还是DMA搬运出了问题。老老实实从轮询开始半小时就能验证。3.2 时钟使能与基本初始化FMAC属于MCU内部外设使用前要记得使能对应的时钟。HAL库里的写法是__HAL_RCC_FMAC_CLK_ENABLE()。忘了使能时钟是最常见的低级错误现象就是寄存器写不进去或者写进去了FMAC完全不动作。建议初始化代码的第一步就做时钟使能后面所有操作都有了基础。使能时钟后根据使用情况配置中断优先级。FMAC的两个主要事件是输入缓冲满XFULL和输出缓冲有数据请求RREQ。这两个事件都可以触发中断或者DMA请求。在HAL库中HAL_FMAC_Init负责完成FMAC的基础配置包括数据位宽、滤波模式、中断使能等。我习惯把FMAC放在高优先级中断组里因为滤波数据的中断延迟直接影响数据的连续性优先级低了容易导致采样点丢失。初始化完成后还需要调用HAL_FMAC_ConfigFilter等函数来配置具体的滤波器类型、参数和系数。这里需要特别注意每个函数的入参含义都要核对参考手册的寄存器位定义不要凭感觉填写。特别是滤波模式这个参数选错会导致FMAC的数据流节奏发生很大变化。3.3 数据格式Q1.15定点数的“刻度尺”逻辑FMAC最常见的数据格式是Q1.15也就是16位有符号定点数。很多刚接触的人不理解为什么非要定点数不直接用浮点。其实原理上讲用一个16位数表示-1到1之间的数就是把这个区间切成32768份每份约等于3.05乘以10的负5次方。Q1.15里的“1”表示符号位“15”表示小数部分占15位比特。用管理尺子的思路理解定点格式就是固定了刻度的尺子数值范围和精度是预先定死的。为什么FMAC用定点数硬件实现定点乘加比浮点更省资源、功耗更低、速度更快。特别是在G4系列上FMAC的定点运算流水线非常高效。那浮点怎么办部分型号的FMAC可以配置为浮点模式但我实际项目中用得最多的还是Q1.15。从ADC采样结果转换到Q1.15只需一次移位和缩放成本很低。从Q1.15结果还原成实际物理量也只需要反向缩放逻辑很清晰。你只要在配置时将输入、系数、输出都统一定义为Q1.15格式并且保证系数不超出范围得到的滤波结果就是可信的。4. 实操流程用FMAC做一个16阶FIR低通滤波器4.1 滤波系数怎么来MATLAB/Octave快速设计先准备好滤波器系数。FIR系数可以使用MATLAB的Filter Designer工具或Octave的fir1函数生成。我用Octave举个例子fs 20000; % 采样率20kHz fc 1000; % 截止频率1kHz N 16; % FIR阶数 b fir1(N, fc/(fs/2), low);这段代码会生成一个16阶低通FIR的17个系数阶数N表示N阶系数个数是N1。生成的系数默认是浮点值需要转换成Q1.15格式。公式很简单浮点系数乘以32768然后四舍五入取整得到S16格式的定点数。转换时注意系数的绝对值不能超过1否则会溢出。FIR设计工具通常会保证这一点但如果自己手写系数就要留心。系数转换完需要按顺序填入FMAC的系数缓冲X2。FMAC的FIR系数顺序是从b0到bN依次写入。写入方式可以CPU循环写也可以DMA一次搬运。我的经验是如果系数不变初始化阶段一次性写入后面就不再动了如果系数需要在线调整建议用DMA或寄存器直接写避免频繁的CPU循环影响实时任务。4.2 寄存器配置CFG、FUNC、PARAM一次讲透配置FMAC的核心是三个寄存器FMAC_CFG、FMAC_FUNC和FMAC_PARAM。FMAC_CFG负责滤波模式和使能控制。它决定FMAC是运行在标准滤波模式还是二步滤波模式。做流式FIR滤波用标准模式即可标准模式的语义就是数据连续进、结果连续出配合DMA非常好用。FMAC_FUNC负责选择具体的运算功能FIR、IIR一阶、IIR二阶还是RMS。功能不同系数缓冲的数据排布也不同。FIR模式就是正常的系数序列IIR模式需要按特定顺序填入5个系数RMS模式则不需要系数。FMAC_PARAM负责配置数据宽度、输入缓冲大小、输出缓冲大小等参数。这里的位宽要和你的数据源格式严格匹配。比如ADC以16位采样结果输入就配置成16位系数也用16位就都统一。还有输入缓冲和输出缓冲的大小配置要根据DMA的传输粒度来匹配。我将缓冲大小设置为8个采样点再用DMA触发传输实测稳定。配置顺序上建议先配置CFG和FUNC再写PARAM最后加载系数。系数加载完成后设置FMAC_CR的START位启动FMAC。启动后如果配置正确往X1写入数据经过固定流水线延迟后Y缓冲就会产出结果。4.3 标准模式下CPU轮询的简单实现我先给出一个不追求高性能、但足够验证FMAC功能的CPU轮询实现思路。初始化部分时钟使能后配置CFG为标准模式功能为FIRPARAM中把X1、X2、Y都设置为16位。然后循环写入滤波器系数到X2。接着把START位置位FMAC开始工作。处理单点数据时把16位ADC采样点左移一位转成Q1.15格式写入FMAC_X1。然后等待输出有效事件轮询FMAC_ISR的RREQ位一旦置位就从Y缓冲读取结果。结果右移一位恢复原来的数量级送进控制环或观察窗。代码逻辑非常简单但轮询等待会占用CPU因此只适合验证功能不适合高吞吐场景。这里有个细节容易踩坑写X1时如果输入缓冲已满XFULL位被置位还继续写会发生溢出或者写入无效。轮询方式下要等待XFULL标志恢复才写下一个采样点。我最早没注意这个标志连续写数据导致数据错位滤波输出完全对不上排查了很久才发现是写入时序的问题。4.4 DMA版本真正释放CPU的推荐做法工程上使用FMAC的正确姿势是配合DMA做流式搬运这样CPU完全不参与数据搬运。以电流采样滤波为例ADC可以配置为连续转换模式DMA把ADC结果循环搬运到FMAC的X1数据缓冲FMAC的输出事件触发DMA把Y缓冲里的结果搬运到内存数组。这样形成一条硬件数据通路ADC到FMAC到内存全程无CPU干预。具体配置时要注意几个关键点。第一DMA的触发源必须选FMAC的对应请求。输入侧DMA由FMAC的输入缓冲非满事件触发输出侧DMA由FMAC的输出数据请求事件触发。第二DMA模式建议使用循环模式这样数据可以连续不断。第三DMA的数据长度、位宽要和FMAC配置的位宽一致。我遇到过DMA配置成32位FMAC设置为16位结果高低位错乱输出波形像打码一样。初始化顺序也很重要。先配置FMAC再配置DMA最后同时启动。如果你的采样率高建议给DMA中断留一个足够高的优先级以便在数据满时及时处理。这个方案的CPU占用基本可以忽略主循环只管读结果数组滤波计算和搬运都在后台自动运行。4.5 滤波系数和结果的Q格式换算细节Q1.15的换算看起来简单但实际项目里很多人在这里翻车。ADC采集到的原始值通常是0到409512位或者0到6553516位直接送进FMAC是不行的因为Q1.15的范围是-1到1左右。需要先把原始数据“标定”到-1到1区间。简单做法是ADC原始值减去中点偏移再乘以一个缩放系数转化为Q1.15整数。从FMAC产出的结果也是一个Q1.15格式的定点数要还原成ADC量纲就反过来乘缩放系数并加上偏移。这个过程不要用浮点除法直接用移位和整数乘法即可效率高很多。我习惯把缩放系数预先计算好存成整数常量每次转换只需要两次乘加开销几乎可以忽略。系数换算也一样浮点系数乘32768后要注意四舍五入不是简单的取整。四舍五入可以避免小的偏移累积。FIR系数比较小的情况下定点化后的数值可能很小但只要在Q1.15范围内就不影响正确性。IIR系数通常更小但因为有反馈回路系数精度对稳定性影响更大建议二阶级联时用更高的定点精度或者直接选择支持32位FMAC的型号。5. 进阶内容IIR配置、RMS统计、二步模式与避坑5.1 二步模式到底解决什么问题FMAC的标准滤波模式适合流式处理数据一边进一边出但有一个前提数据源是持续不断的。如果数据不是连续流而是一块一块来的比如文件读取出来的音频采样或者是批量采集的传感器数据标准模式就会显得很尴尬。二步模式two-step mode就是为此设计的。二步模式把“喂数据”和“取结果”分成两个阶段FMAC在输入缓冲未填满时会进入暂停状态等待软件或DMA补充数据输出缓冲有结果时也先暂停等软件取走。通过这种方式可以精确控制数据处理的节奏。实际使用中如果你要从一个512点的数据块中滤波可以把它拆成64批每批8个点一批批喂给FMAC中间按需暂停所有数据处理完再取最终结果。二步模式比标准模式稍微复杂但好处很明显控制能力强不依赖连续数据流适合批处理场景。它的代价是需要软件更主动地管理数据流状态中断处理也更频繁。我个人建议连续采样场景用标准模式批处理场景用二步模式不要混用。5.2 IIR滤波器系数顺序和关键要点IIR滤波器的系数排布是个容易出错的点。FMAC的biquad实现涉及5个系数分别对应传递函数的分子和分母多项式。使用FMAC时X2缓冲中的系数排列顺序不是随意写的必须严格按照参考手册的寄存器描述顺序来填充。不同的芯片手册可能会对系数顺序有不同命名和排列填错一个位置滤波器行为就完全不同而且不会报错非常阴险。我建议每次写IIR系数前都打开参考手册对照一遍重点是确认系数是先分子后分母还是交替排列。STM32G4系列的FMAC通常按指定表格排布包括b0、b1、a1、b2、a2这样的顺序具体请以你所用型号的参考手册为准。如果你用HAL库官方示例代码里也会有系数表直接参考可以省不少事。IIR调试时还要关注稳定性。反馈系数如果超出理论范围滤波器可能自激振荡输出飙满。我调试时习惯先给一个已知的阶跃信号观察输出是否收敛再接入真实信号。一旦发现输出发散立刻检查系数和格式不要盲目继续。5.3 RMS运算的实际调用方式FMAC的RMS功能使用起来比FIR简单因为它连系数都不用写。配置时将FMAC_FUNC设置为RMS运算然后设置数据格式和缓冲参数启动后把采样点持续写入X1经过固定延时后从Y缓冲读出结果就是RMS值。RMS的典型用法是连续监测交流信号的幅值。我在一个电网电压监测项目里用FMAC直接计算一个工频周期的均方根结果稳定性和实时性都远远好于软件逐点平方累加的方式。需要注意的是RMS运算的结果输出粒度和窗口长度有关FMAC内部累计了一定数量的采样点后才给出结果。需要根据你实际想计算的窗口长度配置FMAC参考手册中对RMS窗口长度有明确描述。如果你不确定RMS结果和输入数据的对应关系可以先送一段已知幅值的标准正弦波做标定再对比FMAC的结果和理论RMS值偏差在可接受范围内就说明配置正确。这个方法我推荐在每次换板子或者换固件版本后都做一遍成本低、可靠。5.4 常见问题速查表现象可能原因排查方法FMAC寄存器写不进去FMAC时钟未使能检查__HAL_RCC_FMAC_CLK_ENABLE()是否调用输入数据写不进X1X1缓冲已满读取ISR的XFULL标志等待缓冲空闲再写输出一直没数据FMAC未启动或功能配置错误检查CR的START位和FUNC寄存器输出结果全是0输入数据格式或位宽不匹配核对PARAM中的数据宽度和Q格式输出值突然跳满IIR系数溢出或反馈项过大检查系数是否符合Q1.15范围尝试降阶或换FIRDMA搬运结果错位DMA位宽与FMAC不一致统一DMA和FMAC的数据位宽滤波输出延迟抖动大中断优先级设置不当给FMAC和DMA分配更高优先级二步模式数据卡住输入缓冲暂停后没有及时补充检查二步模式下使能暂停处理的中断这张表基本覆盖了常见的坑。我自己的经验是至少六成问题出在数据格式和缓冲时序上而这两类问题用示波器看波形、或者在输出端打印几个十六进制原始值就能快速定位。不要一上来就怀疑芯片坏了FMAC是成熟外设出错基本是配置和用法问题。6. 进阶一点信号链的完整工程搭建思路FMAC不是孤立外设它的价值要放在完整的信号链路中才能体现。我做一个典型的直流无刷电机控制项目时信号链是这样的三相电流采样由ADC完成采样结果通过DMA进入FMAC做FIR滤波和RMS计算滤波后的电流值再由DMA写回内存控制算法直接读取内存中的干净电流数据。这个链条里ADC、DMA、FMAC三者协同工作形成了一条硬件数据通道CPU完全不介入中间环节。搭建这类信号链时我先用CubeMX把所有外设的DMA请求关系理顺再逐个验证每个环节。第一步先让DMA把ADC数据搬运到内存数组打印出来确认数据正确第二步把DMA目的地址改到FMAC的X1同时让FMAC输出通过另一个DMA搬到内存数组第三步再合入控制算法闭环调试。分步验证有三个好处出问题时能快速定位是哪一环的问题避免了外设间互相干扰的猜测每个环节都有可确认的中间结果调试心态也稳定等全部打通后整个链路因为每步都验证过最终调试时间反而很短。另一个工程经验是始终给FMAC留一个“旁路直通”的开关方便对比有无滤波的信号差异。我在代码里用了一个全局标志如果为真ADC数据直接送控制环如果为假走FMAC滤波。这样调参时可以快速切换判断滤波器到底有没有改善系统表现。尤其在做电机控制这种强耦合系统时这种对比能力非常重要不然你很难分清楚系统性能提升是滤波带来的还是控制器参数调整带来的。7. 一点个人的经验和建议最后说点实在的。FMAC作为一个硬件外设学习曲线确实比调用CMSIS-DSP库陡但它带来的收益在实时控制类项目里非常明显。我前面提到电机控制项目切换到FMAC后CPU负载从70%降到30%上下这个余量让我后面加状态观测器、故障诊断和通信协议都从容了很多。如果再用上ADC加DMA加FMAC的信号链方式整个采样滤波通路对CPU几乎是透明的项目的实时响应能力完全不一样。给刚开始接触FMAC的人几个建议先用最小工程把FMAC跑通不要一上来就接真实信号配置寄存器时多翻参考手册特别是格式、顺序、缓冲相关字段靠猜很容易踩坑调试时多用固定信号和打印输出做验证确认滤波行为正确后再接入闭环控制。FMAC不是万能的FIR阶数、IIR稳定性、数据格式限制都在那里工程上必须理性权衡。但只要你愿意花两三天摸清楚它的脾气它就能成为你手里非常趁手的一件工具。我在项目里现在遇到滤波需求第一反应不是去优化CMSIS-DSP调用而是先想——这个滤波能不能下沉到FMAC里。
返回列表