<!-- 本文件由脚本自动转换生成，请勿手动编辑 -->

> **《LKS32MC45x User Manual》FMAC **滤波加速器**** . 完整目录见 [README.md](README.md)
>
> **声明**：本文档由芯片用户手册自动转换生成，仅供检索与查阅参考。Markdown 格式可被自由编译、修改，本文档不构成正式技术文件，相关内容以凌鸥创芯官方网站正式发布的手册为准。
>
> 南京凌鸥创芯电子有限公司 . (C) 2020, 版权归凌鸥创芯所有 . 机密文件，未经许可不得扩散

# FMAC **滤波加速器**

## 概述

滤波加速器可进行向量算术操作，包含乘法器、累加器，以及本地存储器地址产生逻辑，用于在滤波加速器本地存储中索引向量数据。

滤波加速模块支持输入、输出循环滚动缓存，以便于实现有限/无限冲击响应数字滤波器。

滤波加速模块将CPU从冗长而频繁的滤波操作中解放出来，节省CPU算力用于其他任务。同时与CPU的软件滤波相比，硬件滤波加速模块可以较大程度提升滤波计算速度。

## 特性

- 16位×16位 乘法器
- 24+2位累加器，支持饱和处理
- 16位数据输入、输出
- 256×16位本地数据存储
- 本地存储最多可以定义3个数据缓存区域（两个输入缓存，一个输出缓存）缓存基地址和缓存大小可以通过寄存器配置
- 输入、输出缓存可以作为循环buffer使用
- 滤波函数：FIR，直接1型IIR
- 向量操作：点积，卷积，相关
- AHB总线接口
- 支持DMA读写数据

## 功能描述

滤波加速模块如图12-1所示。

【图片已删除】为控制知识库体积，本文档不携带图片，相关图示请查阅凌鸥创芯官网发布的正式手册。

图12-1滤波加速模块框图

该模块的核心是定点乘累加器（MAC）。乘累加器从本地存储中读取两个16位有符号数作为输入，相乘以后与之前的和进行累加。本地存储中的数据地址由一系列的地址指针来决定。地址指针可以加载初始值，递增，递减，也可以被内部硬件复位回初值。所有的指针和MAC模块都是由内部的硬件逻辑控制来完成指定的操作序列。

如果要计算点积，两个输入向量被CPU或DMA存入FMAC本地存储中。当相应的操作被配置并开始执行时，每次硬件逻辑从本地存储读取来自两个向量的一对数据作为MAC输入，乘累加后暂存至内部中间结果寄存器，当所有向量元素均计算完成后，累加器的输出作为最终结果被写回本地存储，等待CPU或DMA读出。

如果要作为FIR滤波器（卷积）使用，FMAC需要反复计算滤波器系数和输入向量的点积。每个采样周期，输入向量位移一个采样数据，最早的一个采样数据被丢弃，加入一个新的采样数据，然后使用相同的滤波器系数向量重新计算一次点积。如此往复。

如果要作为IIR滤波器使用，需要在FIR的基础上再进行计算输出结果与反馈系数向量的点积并与FIR的滤波结果相加。

更多的滤波器操作实现细节见后续章节介绍。

### 本地存储与缓存

FMAC包含有一个256×16位的可读写存储器作为FMAC的本地存储

输入数据（输入向量元素）存储在两个输入buffer X1和X2中。

输出数据（操作结果）存储在buffer Y中。

缓存基地址和缓存大小由以下变量指定：

x1_base为X1 buffer在本地存储中的基地址，

x2_base为X2 buffer在本地存储中的基地址，

y_base为Y buffer在本地存储中的基地址，

x1_buf_size为X1 buffer的缓存大小，即其内包含多少个16bit有符号数

x2_buf_size为X2 buffer的缓存大小，即其内包含多少个16bit有符号数

y_buf_size为Y buffer的缓存大小，即其内包含多少个16bit有符号数

以上参数均可通过模块的寄存器进行配置。

CPU或DMA可以通过FMAC模块的初始化功能，也可以通过直接写入，来初始化各个缓存的数据。写入的数据根据硬件写指针存入目标buffer，每次数据写入，硬件写指针自动加1，当写指针到达buffer尾时，再次回到buffer基地址。初始化功能用于滤波操作前的数据预装载，或者初始化滤波器系数。

**缓存配置**

缓存基地址和缓存大小通过X1,X2,Y
buffer的配置寄存器进行配置。基地址可以是本地存储的任意位置，只要基地址+缓存大小不超过本地存储地址范围(0x00~0xFF)即可。即基地址+缓存大小≤256.

缓存的大小和位置没有限制，缓存甚至可以重叠，但是要解决好数据读写先后的问题。对于滤波操作来说，一般不建议缓存重叠，容易出现不易调试的错误。

当缓存作为循环buffer使用时，可以留有一定的动态余量（headroom，d）。同时可以设置FIFO的水线深度（watermark
level）来调整CPU和DMA的访问频次。动态余量和水线深度应该根据应用需求来进行适当选择。为了最大化FMAC的吞吐率，输入buffer应该永不为空，因此d应该大于水线深度，以防止因为中断和DMA操作的延迟导致FMAC等待数据输入而暂时停滞。另一方面，如果输入数据的填装速度小于被FMAC处理的速度，输入缓存可能会被FMAC读空，并等待CPU或DMA写入下一个数据。d可以等于水线深度，确保输入读取不会溢出。

【图片已删除】为控制知识库体积，本文档不携带图片，相关图示请查阅凌鸥创芯官网发布的正式手册。

图12-2FMAC 硬件乘加运算单元整体架构框图

### 输入缓存

X1和X2
buffer为FMAC的输入缓存，用于存储输入数据。FMAC的每次乘法操作从X1读取一个数据，从X2读取一个数据，然后相乘。FMAC内部硬件指针，控制读取数据相对于缓存基地址的偏移。指针由硬件根据操作配置自动管理。

【图片已删除】为控制知识库体积，本文档不携带图片，相关图示请查阅凌鸥创芯官网发布的正式手册。

图12-3输入缓存区域

X1
buffer可以作为循环buffer使用，只要buffer有空闲空间即可写入输入数据。buffer在操作前可以进行初始化，也可以不进行初始化。如果操作开始时buffer内部没有数据，则buffer空的标志会触发CPU或DMA进行新数据装填直到有足够的数据进行滤波计算。

【图片已删除】为控制知识库体积，本文档不携带图片，相关图示请查阅凌鸥创芯官网发布的正式手册。

图12-4循环输入buffer

X2 buffer无法作为循环buffer使用，而且通常需要预装载。在滤波操作中，X2
buffer用于存储滤波器系数。

当X1
buffer作为循环buffer使用时，x1_buf_size应略大于当前操作所需数据个数（滤波器阶数），这样buffer可以一直存在未经FMAC使用的新数据。图12-3展示了FMAC在进行滤波操作时的缓存分布情况。当计算输出y\[n\]时，FMAC需要使用N+1个输入数据，x\[n-N\]至x\[n\]。当计算完毕y\[n\]，FMAC开始使用x\[n+1-N\]至x\[n+1\]计算y\[n+1\]，而最早输入的数据x\[n-N\]不再被FMAC所需要，可以被新数据替换。

CPU或DMA需要在FMAC需要数据时进行及时填装，否则FMAC会将buffer空标志置位，并暂停FMAC内部的滤波计算操作，直到新的数据填入buffer。X1
buffer硬件上保证了不会出现因为读取而造成的下溢出。

举例来说，如果采样滤波流程是受控于定时器或是ADC外设，则buffer会定期地进入空状态，因为FMAC处理数据的速度快于采样数据产生的速度。这是正常特性。

如果buffer内的空闲空间小于水线阈值(FMAC_X1BUFCFG.FULL_WM)，则buffer的满标志会置位。如果满标志未置位，则FMAC会产生中断请求，请求更多的数据填入buffer。水线的存在使得一次中断填入多个数据成为可能，且不会发生buffer上溢出。

如果发生了上溢出，则FMAC_SR.OVFL会置位，且写入数据会被丢弃，写指针维持不变。X1
buffer没有下溢出标志。

X1
buffer在滤波操作器件的读写动作如图12-4所示。本例为一个8阶FIR滤波器，水线阈值设置为4。

【图片已删除】为控制知识库体积，本文档不携带图片，相关图示请查阅凌鸥创芯官网发布的正式手册。

图12-5循环输入buffer的读写操作

### 输出缓存

Y buffer用于存储累加器的输出，并等待CPU或DMA读取。每读取一次，Y
buffer的读指针加1，当指针遇到buffer尾时，自动回到buffer基地址。

【图片已删除】为控制知识库体积，本文档不携带图片，相关图示请查阅凌鸥创芯官网发布的正式手册。

图12-6循环输出buffer

Y
buffer也可以作为循环buffer使用。如果待写入的输出数据地址与读指针重合，即与未读取的结果数据重叠，则buffer满标志置位，FMAC会中断计算操作直到Y
buffer中的结果数据被读走。

当进行IIR滤波操作时，Y
buffer需要预装载M个历史输出数据y\[n-M\]至y\[n-1\]，用于计算下一个输出数据y\[n\]。每次Y
buffer填入一个新的数据，最旧的数据y\[n-M\]会被替换掉。

如果Y buffer内的未读取数据个数少于水线阈值（FMAC_YBUFCFG.EMPTY_WM），则Y
buffer空标志置位。如果Y
buffer不为空，则会通过中断请求CPU或DMA读取其中的输出数据。水线阈值的存在使得CPU可以运行一次中断服务函数读取多个输出数据，而无下溢出风险。但如果发生了下溢出，FMAC_CR.UNFL的标志会置位。这种情况下Y
buffer读指针维持不变，读取的数据为读指针指向的数据。

Y
buffer作为循环buffer使用时的读写操作如图12-6所示。本例为一个7阶IIR滤波器，水线阈值设置为4。

【图片已删除】为控制知识库体积，本文档不携带图片，相关图示请查阅凌鸥创芯官网发布的正式手册。

图12-7循环输出buffer读写操作

### 初始化函数

FMAC除了常规的滤波操作外，还有初始化操作用于初始化输入buffer数据。初始化操作通过向FMAC_PARAM.FUNC写入适当的值，并将FMAC_PARAM.START写入为1来触发。同时FMAC_PARAM.P/Q字段也需要进行适当配置。当初始化操作完成后，START由硬件自动复位为0。

#### 填装X1 buffer

X1 buffer初始化函数可以用于X1
buffer的预填装，从X1_BASE开始，连续写入N+1个数据到FMAC_WDATA寄存器，输入数据写入到本地存储，同时写指针跟随递增。初始化完成后，写指针指向X1_BASE+N+1。

X1 buffer初始化函数可以用于向X1
buffer填入向量元素，或是滤波器的输入数据。其相关参数如下：

P表示待填入X1 buffer的数据个数N+1；

Q和R未使用

CPU或DMA向FMAC_WDATA写入N+1个数据后，初始化操作完成。

#### 填装X2 buffer

X2 buffer初始化函数可以用于X2
buffer的预填装，从X2_BASE开始，连续写入N+1+M个数据到FMAC_WDATA寄存器，输入数据写入到本地存储，同时写指针跟随递增。初始化完成后，写指针指向X2_BASE+N+1+M。

X2 buffer初始化函数可以用于向X2
buffer填入向量元素，或是滤波器的系数。其相关参数如下：

P表示待填入X2 buffer的数据个数N+1，从X2_BASE开始填装；

Q表示待填入X2 buffer的数据个数M，从X2_BASE+N+1开始填装；

R未使用

CPU或DMA向FMAC_WDATA写入N+1+M个数据后，初始化操作完成。

对于FIR，x2 buffer初始化系数数据从h(0)开始，然后是h(1),h(2),…,直到h(N)。

对于IIR，x2
buffer的初始化系数数据从b(0)开始，然后是b(1),b(2),…,直到b(N)，为x的系数；之后是a(1),a(2),…,a(M)，为y的系数。y
buffer初始化样本数不超过M个。

【图片已删除】为控制知识库体积，本文档不携带图片，相关图示请查阅凌鸥创芯官网发布的正式手册。

图12-8 FIR和IIR滤波器x2 buffer系数排列

#### 填装Y buffer

Y buffer初始化函数可以用于Y
buffer的预填装，从Y_BASE开始，连续写入N+1个数据到FMAC_WDATA寄存器，数据写入到本地存储，同时写指针跟随递增。初始化完成后，写指针指向Y_BASE+N+1。

Y buffer初始化函数可以用于向Y
buffer填入IIR滤波中的反馈数据。其相关参数如下：

P表示待填入Y buffer的数据个数N+1，从Y_BASE开始填装；

Q和R未使用

CPU或DMA向FMAC_WDATA写入N+1个数据后，初始化操作完成。

### 滤波器函数

FMAC可用于执行FIR、IIR等滤波操作。通过向FMAC_PARAM.FUNC写入适当的值，并将FMAC_PARAM.START写入为1可以触发滤波操作开始执行。同时，P/Q/R等字段也需要设置适当的值。滤波操作会持续进行直到START位被软件复位。

#### FIR滤波器（卷积）

*Y*=*B*\**X*

此操作对长度为N+1的向量B和无限长的向量X进行卷积。，其中，包含有X的N+1个元素，下标为n-N到n。这个操作与FIR滤波相对应，向量*B*即为滤波器系数，向量*X*为待滤波的采样数据。

滤波器结构如图12-8所示。

【图片已删除】为控制知识库体积，本文档不携带图片，相关图示请查阅凌鸥创芯官网发布的正式手册。

图12-9
FIR滤波器结构

FIR滤波操作也可以用于计算向量的相关，这时需要将向量B首尾元素互换。

输入：

X1 buffer存储有向量*X*，是长度为N+1+d的循环buffer，

X2 buffer存储有向量*B*，是长度为N+1的固定buffer

输出：

Y buffer存储有输出数据*y<sub>n</sub>*，是长度为d的循环buffer。

参数：

P为向量B的长度，N+1，取值范围是2~127

R是累加器输出增益，存入Y buffer的数据需要乘以2<sup>R</sup>，R的范围是0~7

Q未使用。

FIR滤波操作从START被置位为1开始持续进行，直到START被软件复位为0停止。

#### IIR滤波器

*Y*=*B*\**X+A\*Y’*

滤波器输出*Y*是长度为N+1的向量*B*与无限长度向量X的卷积，加上*Y*的历史数据与长度为M的反馈向量*A*的卷积。，其中，包含有X的N+1个元素，下标为n-N到n，，包含有Y的M个元素，下标为n-M到n-1。

直接1型IIR滤波器结构如图12-9所示。

【图片已删除】为控制知识库体积，本文档不携带图片，相关图示请查阅凌鸥创芯官网发布的正式手册。

图12-10
直接1型IIR滤波器结构

输入：

X1 buffer存储有向量*X*，是长度为N+1+d的循环buffer，

X2 buffer存储有向量*B*和向量*A*，格式为 (b<sub>0</sub>, b<sub>1</sub>,
b<sub>2</sub>..., b<sub>N</sub>, a<sub>1</sub>, a<sub>2</sub>, ...,
a<sub>M</sub>)，是长度为M+N+1的固定buffer

输出：

Y buffer存储有输出数据*y<sub>n</sub>*，是长度为M+d的循环buffer。

参数：

P为向量B的长度，N+1，取值范围是2~127

Q为向量A的长度，M，取值范围是1~63

R是累加器输出增益，存入Y buffer的数据需要乘以2<sup>R</sup>，R的范围是0~7

IIR滤波操作从START被置位为1开始持续进行，直到START被软件复位为0停止。

### 定点数表示

FMAC以定点数的数据格式进行计算操作。输入和输出数据都是Q1.15的定点数。

在Q1.15个时钟，数值表示为1bit符号位，和15bit的小数部分。数值范围为-1（0x8000）至1-2<sup>-15</sup>（0x7FFF）。

累加器位宽26bit，其中22bit为小数部分，4bit为整数和符号位，即Q4.22格式。因此累加器和的数值范围为-8（0x2000000）至7.99999976（0x1FFFFFF）。可编程增益步长为6dB（即一档变化为原来的2倍），增益范围为0db~42db，对应R的设置为0~7，即增益范围为2<sup>0</sup>~2<sup>7</sup>，增益施加于累加器输出，数据写入Y
buffer之前。

注意，累加器的中间结果并没有饱和处理，因此如果数值超出定点数表示范围则会溢出。部分和可能会在中间计算过程中超出-8（0x2000000）至7.99999976（0x1FFFFFF）的表示范围，但暂时的溢出并不会导致最终结果出错，因为滤波器输出的有效数据实际上位于数值的低位部分，只要最终结果再次回到定点数表示范围内则最终结果仍是正确的。但FMAC_SR.SAT会在溢出发生时置位。如果使能了FMAC_CR.SATIEN，则会发生中断请求。这一特性有助于调试滤波器。

累加器的最终输出（经过增益处理之后）可以选择是否进行饱和处理。如果设置了FMAC_CR.CLIPEN，则最终输出数据会被钳位在Q1.15的表示范围内，即-1（0x8000）至1-2<sup>-15</sup>（0x7FFF）。如果CLIPEN未使能，则会将累加器的高位截断丢弃，将低位存入Y
buffer。

### 使用FMAC实现FIR滤波器

FMAC支持长度为N+1的FIR滤波操作，其中N+1为滤波器系数个数或抽头数。

长度为N的FIR滤波器，最小本地存储需求为2N+3：

- N+1个系数
- N+1个输入数据
- 1个输出数据

本地存储空间为256，因此FMAC支持的最大FIR滤波器尺寸为127抽头。

为了最大化吞吐率，可以分别给输入输出缓存，留有一定额外空闲空间，大小分别为d1和d2，以确保输入缓存永不为空，输出缓存永不为满。在这种设置下，本地存储需求为2N+2+d1+d2。

buffer配置如下：

X1_BUF_SIZE=N+1+d1；

X2_BUF_SIZE=N+1；

Y_BUF_SIZE=d2（或1，如果不需要额外空闲空间）

buffer基地址可以是本地存储的任意位置，但X2不应与其他buffer重叠，否则滤波器系数可能会被写覆盖，下面给出一个可能的基地址配置：

X2_BASE=0；

X1_BASE=N+1;

Y_BASE=2N+2+d1

FMAC_X1BUFCFG.FULL_WM位域必须≤log2(d1)，否则N当输入数据写入还未完成X1
buffer就会被标记为满状态，导致输入数据无法继续写入。
同样，FMAC_YBUFCFG.EMPTY_WM位域必须≤log2(d2)。

滤波器系数必须通过X2初始化操作进行预装载。X1
buffer可以进行预装载，填充数据可以为任意个，最多为N+1个，也可以不做预装载。Y
buffer在进行FIR操作时无需预装载，因为FIR不存在反馈路径。

完成buffer的配置和初始化之后，可以对FMAC_CR进行配置来指定FMAC_WDATA写入的方式和FMAC_RDATA读取的方式。有三种方式可选：

轮询：无DMA请求或中断请求产生。软件查询X1_FULL标志是否为低，为低则通过FMAC_WDATA向X1
buffer写入数据，查询Y_EMPTY标志是否为低，为低则通过FMAC_RDATA从Y
buffer读取数据。

中断：当X1_FULL标志为低时，产生中断请求CPU通过FMAC_WDATA向X1
buffer写入数据，当Y_EMPTY为低时，产生中断请求CPU通过FMAC_RDATA从Y
buffer读取数据。

DMA：当X1_FULL标志为低时，产生DMA传输请求，通过FMAC_WDATA向X1
buffer写入数据，当Y_EMPTY为低时，产生DMA传输请求，通过FMAC_RDATA从Y
buffer读取数据。

读写操作方式可以不同。但一般不建议同一个操作同时使用中断和DMA请求，如果同时使能中断和DMA，通常是DMA进行传输，中断不再进行传输。可选的读写操作方式组合如下

表12-1
可选的读写操作方式组合

|||||||
|---|---|---|---|---|---|
|WIEN|RIEN|DMAWEN|DMAREN|X1 Write|Y Read|
|0|0|0|0|轮询|轮询|
|0|1|0|0|轮询|中断|
|1|0|0|0|中断|轮询|
|1|1|0|0|中断|中断|
|0|0|0|1|轮询|DMA|
|0|0|1|0|DMA|轮询|
|0|0|1|1|DMA|DMA|
|0|1|1|0|DMA|中断|
|1|0|0|1|中断|DMA|

FIR滤波操作启动前，需要对FMAC_PARAM进行如下配置：

FUNC=8（FIR滤波功能）

P=N+1（滤波器系数个数）

Q=任意值（Don’t Care）

R=Gain

START=1（启动滤波操作）

如果填入X1
buffer的数据个数少于N+1+d-2<sup>FULL_WM</sup>，则X1_FULL标志维持为低。如果FMAC_CR.WIEN为1，则立即产生中断，请求CPU向FMAC_WDATA寄存器写入2<sup>FULL_WM</sup>个新的采样数据。中断请求会一直存在，直到FMAC_SR.X1_FULL置位为1。中断服务函数通常应该在写入2<sup>FULL_WM</sup>个数据后查询X1_FULL标志，反复写入2<sup>FULL_WM</sup>个新数据直到X1_FULL置位。

在X1
buffer写入了至少N+1个输入数据之后（包含预装载的数据个数），FMAC开始计算第一个输出数据。

当2<sup>EMPTY_WM</sup>个输出数据写入Y
buffer之后，FMAC_SR.Y_EMPTY标志置低。如果FMAC_CR.RIEN为1，则立即产生中断，请求CPU从FMAC_RDATA读取2<sup>EMPTY_WM</sup>个数据。中断请求会一直存在，直到FMAC_SR.Y_EMPTY置位为1。中断服务函数通常应该在读取2<sup>EMPTY_WM</sup>个数据后查询Y_EMPTY标志，反复读取2<sup>EMPTY_WM</sup>个新数据直到Y_EMPTY置位。

滤波操作按照这种方式持续进行，直到软件向START写入0。

【图片已删除】为控制知识库体积，本文档不携带图片，相关图示请查阅凌鸥创芯官网发布的正式手册。

图12-12 FMAC工作模式下IIR滤波器数据交互架构

### 滤波器初始化示例

【图片已删除】为控制知识库体积，本文档不携带图片，相关图示请查阅凌鸥创芯官网发布的正式手册。

图12-13
X1 buffer初始化

图12-10展示了X1 buffer配置为P=4的预填装过程。X1
buffer大小X1_BUF_SIZE=6。向FMAC_PARAM.START写入1，初始化操作启动。4个数据写入FMAC_WDATA寄存器，并存入FMAC本地存储，对应地址从X1_BASE开始递增。4个数据写入完成后，START被硬件复位为0。此时X1
buffer存储有4个有效的输入数据，同时写指针指向下一次写入数据的位置X1_BASE+0x4。

### 滤波器操作示例

【图片已删除】为控制知识库体积，本文档不携带图片，相关图示请查阅凌鸥创芯官网发布的正式手册。

图12-14滤波器操作示例1

图12-11展示了滤波器操作启动的情形。滤波器抽头数为4（P=4）。X1
buffer大小为6，Y buffer大小为2。FULL_WM和EMPTY_WM均为0。滤波器启动前，X1
buffer已经预填装了4个有效输入数据x\[0:3\]。因此一旦START被写入为1，滤波器即开始计算第一个输出数据y\[0\]。因为X1
buffer还存在两个空闲位置，X1_FULL标志维持为0。FMAC产生中断，请求新的输入数据。CPU通过FMAC_WDATA再次写入两个输入数据x\[4\]和x\[5\]，两个数据被存入FMAC本地存储中的X1
buffer中。

与此同时，FMAC计算完成第一个输出数据y\[0\]，将其写入Y buffer，使得Y
buffer
不再为空，Y_EMPTY变低。计算完成y\[0\]后，x\[0\]可以被丢弃，释放一个X1
buffer空间（位于X1_BASE）。FMAC立即启动计算第二个输出数据y\[1\]，此时y\[1\]所需的所有输入数据x\[1:5\]均已就绪。

由于Y_EMPTY为低，FMAC提起中断，请求CPU通过FMAC_RDATA读取Y
buffer中的y\[0\]，释放Y buffer的空间。此时y\[1\]尚未计算完完成，Y
buffer中不存在有效输出数据，Y_EMPTY变高。由于X1
buffer仍有空闲空间，FMAC继续提起中断请求，请求CPU通过FMAC_WDATA向X1
buffer写入新的输入数据x\[6\]等。

本例中，CPU可以以更快的速度填入输入数据，填入的速度比FMAC处理速度更快，因此X1_FULL标志会偶尔变高为1。但CPU读取Y
buffer的速度不够快，导致FMAC偶尔需要等待Y
buffer被读取以释放空间。这导致滤波操作没有全速进行，原因是滤波器长度比较小，而CPU处理速度比较慢。在这种情况下，增加buffer大小对于提高滤波器吞吐率**没有**改善效果。

【图片已删除】为控制知识库体积，本文档不携带图片，相关图示请查阅凌鸥创芯官网发布的正式手册。

图12-15滤波器操作示例2

图12-12的例子中是滤波器抽头数为6的FIR。X1 buffer大小为6，Y
buffer大小为2。FULL_WM和EMPTY_WM均为0。START写入1之前，X1
buffer中已经预填装了4个有效的输入数据x\[0:3\]。但此时X1
buffer中的输入数据仍然不足，X1_FULL标志没有置位。FMAC继续提起中断，请求CPU填入更多的输入数据。且FMAC的滤波计算因等待足够的输入数据而处于暂停状态。

CPU通过FMAC_WDATA写入两个新的输入数据x\[4\]和x\[5\]，存入X1
buffer中的空闲位置。此时X1
buffer中有6个有效输入数据，X1_FULL变高为1，FMAC不再提起中断请求。FMAC开始计算得到输出数据y\[0\]，并将其存入Y
buffer。此时x\[0\]被丢弃，释放掉X1
buffer的一个空间位置，X1_FULL变低。与此同时Y_EMPTY变低。buffer标志变化导致中断再次被提起，请求CPU写入新的输入数据，并读取输出数据。FMAC处于停止状态，直到新的输入数据写入。

本例中CPU必须等待FMAC完成第一个输出数据的计算才能写入新的输入数据，因此第一个输出数据需要用到x\[0\]，只有完成计算x\[0\]位置才会成为X1
buffer中的空闲位置。因此X1
buffer会偶尔进入数据不足的状态，导致FMAC停止计算。通过增加buffer空间大小可以改善这个问题。

### 滤波器设计提示

FMAC的设计架构对数字滤波器实现有某些限制

1\. 直接2型和转置型需要转换为直接1型，才能在FMAC中实现

2\.
IIR滤波器级联需要合并成单级滤波器，或者分开实现。如果选择分开实现，FMAC的X2
buffer中可能存储有多组滤波器系数，在进行不同的滤波操作时需要更改X2_BASE。实现多级滤波器的比较有效的方式是，先对X1
buffer进行预装载，然后使用第一级滤波器系数进行计算，将结果存入芯片的主存储器（从FMAC的本地存储中读出存入SRAM）。修改X2_BASE指向第二级滤波器系数，然后使用第一级滤波器的输出数据再次初始化X1
buffer。如此往复。最后一级滤波的输出数据被读入芯片主存之后，X1
buffer可以填入新一轮的输入数据，FMAC即可开启新一轮的计算。需要注意的是，每一级的N+1个输入数据都需要使用前一级的N的数据和一个新输入数据，保证各级间的处理连续。同样，IIR滤波需要使用M个本级历史输出数据对输出buffer进行初始化。

3\.
直接1型的IIR滤波器可能在累加器阶段产生绝对值很大的部分和，比如输入信号是一个很大的阶跃信号，或者滤波器系数绝对值大于1。累加器位宽为26bit，在不进行高位截断（wrapping）的情况下可处理的最大数值范围是0x1FFFFFF~0x2000000，在Q3.23定点数格式下对应3.99999988~-4。高位截断并不会导致最终结果错误，因为滤波输出的信息保存在数据的低位，高位部分大部分时间是维持不变的，可以视为DC分量，只要最终结果在表示范围内，则最终结果仍是正确的，可以看做高位截断被撤销了。当然，IIR初值问题仍需要谨慎考虑，否则存在出错可能。

4\. IIR滤波器有前馈（分子）系数\[b<sub>0</sub>, b<sub>1</sub>, ...,
b<sub>N</sub>\]和反馈（分母）系数\[1, a<sub>1</sub>, ...,
a<sub>M</sub>\]。某些IIR滤波器需要反馈系数绝对值大于1以得到一个陡峭的滚降频响曲线。但由于滤波器系数是Q1.15编码的，是无法直接表示大于1的系数的。可以利用增益2<sup>-R</sup>，使得2<sup>-R</sup>\[1,
a<sub>1</sub>, ...,
a<sub>M</sub>\]是小于1的，即可以用Q1.15定点数编码表示。在累加器的输出位置再将增益2<sup>R</sup>乘回。但这个操作会影响信噪比。

## 寄存器

### 地址分配

FMAC的基地址是0x4001_7000，寄存器列表如下：

表12-2 FMAC寄存器列表

||||
|---|---|---|
|名称|偏移地址|说明|
|FMAC_X1BUFCFG|0x00|FMAC X1 buffer配置寄存器|
|FMAC_X2BUFCFG|0x04|FMAC X2 buffer配置寄存器|
|FMAC_YBUFCFG|0x08|FMAC Y buffer配置寄存器|
|FMAC_PARAM|0x0C|FMAC参数寄存器|
|FMAC_CR|0x10|FMAC控制寄存器|
|FMAC_SR|0x14|FMAC状态寄存器|
|FMAC_WDATA|0x18|FMAC写数据寄存器|
|FMAC_RDATA|0x1C|FMAC读数据寄存器|

### 寄存器描述

#### FMAC_X1BUFCFG FMAC X1 buffer 配置寄存器

地址：0x4001_7000

复位值：0x0

表12-3 FMAC_X1BUFCFG FMAC X1
buffer配置寄存器

|||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|31|30|29|28|27|26|25|24|23|22|21|20|19|18|17|16|
|||||||FULL_WM||||||||||
|||||||RW||||||||||
|||||||0||||||||||
|15|14|13|12|11|10|9|8|7|6|5|4|3|2|1|0|
|X1_BUF_SIZE||||||||X1_BASE||||||||
|RW||||||||RW||||||||
|0||||||||0||||||||

||||
|---|---|---|
|位置|位名称|说明|
|\[31:26\]|未使用|NA|
|\[25:24\]|FULL_WM|X1 buffer满水线阈值，当X1 buffer中的空闲位置少于2FULL_WM时，X1 buffer满标志置位。0：水线阈值为11：水线阈值为22：水线阈值为43：水线阈值为8设置水线阈值大于1可以在一次中断处理中传输多个数据到X1 buffer中，当使用DMA写X1 buffer时水线阈值应该设置为1。|
|\[23:16\]|未使用|NA|
|\[15:8\]|X1_BUF_SIZE|X1 buffer 大小，X1 buffer中包含的16bit有符号数个数，buffer尺寸最小值为滤波器前馈阶数（+水线阈值-1）|
|\[7:0\]|X1_BASE|X1 buffer 基地址|

#### FMAC_X2BUFCFG FMAC X2 buffer 配置寄存器

地址：0x4001_7004

复位值：0x0

表12-4 FMAC_X2BUFCFG FMAC X2
buffer配置寄存器

|||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|31|30|29|28|27|26|25|24|23|22|21|20|19|18|17|16|
|||||||||||||||||
|15|14|13|12|11|10|9|8|7|6|5|4|3|2|1|0|
|X2_BUF_SIZE||||||||X2_BASE||||||||
|RW||||||||RW||||||||
|0||||||||0||||||||

||||
|---|---|---|
|位置|位名称|说明|
|\[31:16\]|未使用|NA|
|\[15:8\]|X2_BUF_SIZE|X2 buffer 大小，X2 buffer中包含的16bit有符号数个数，这个位域在操作进行中（START=1）时无法修改|
|\[7:0\]|X2_BASE|X2 buffer 基地址，这个位域在操作进行中（START=1）时无法修改|

#### FMAC_YBUFCFG FMAC Y buffer 配置寄存器

地址：0x4001_7008

复位值：0x0

表12-5 FMAC_YBUFCFG FMAC Y
buffer配置寄存器

|||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|31|30|29|28|27|26|25|24|23|22|21|20|19|18|17|16|
|||||||EMPTY_WM||||||||||
|||||||RW||||||||||
|||||||0||||||||||
|15|14|13|12|11|10|9|8|7|6|5|4|3|2|1|0|
|Y_BUF_SIZE||||||||Y_BASE||||||||
|RW||||||||RW||||||||
|0||||||||0||||||||

||||
|---|---|---|
|位置|位名称|说明|
|\[31:26\]|未使用|NA|
|\[25:24\]|EMPTY_WM|Y buffer空水线阈值，当Y buffer中的有效数据数量少于2EMPTY_WM时，Y buffer空标志置位。0：水线阈值为11：水线阈值为22：水线阈值为43：水线阈值为8设置水线阈值大于1可以在一次中断处理中从Y buffer读取多个数据中，当使用DMA读取Y buffer时水线阈值应该设置为1。|
|\[23:16\]|未使用|NA|
|\[15:8\]|Y_BUF_SIZE|Y buffer 大小，Y buffer中包含的16bit有符号数个数。对于FIR滤波器，buffer尺寸最小值为1（+水线阈值），对于IIR滤波器，buffer尺寸最小值为滤波器反馈阶数（+水线阈值）|
|\[7:0\]|Y_BASE|Y buffer 基地址|

#### FMAC_PARAM FMAC 参数寄存器

地址：0x4001_700C

复位值：0x0

表12-6 FMAC_PARAM FMAC 参数寄存器

|||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|31|30|29|28|27|26|25|24|23|22|21|20|19|18|17|16|
|START||||FUNC||||R||||||||
|RW||||RW||||RW||||||||
|0||||0||||0||||||||
|15|14|13|12|11|10|9|8|7|6|5|4|3|2|1|0|
|Q||||||||P||||||||
|RW||||||||RW||||||||
|0||||||||0||||||||

||||
|---|---|---|
|位置|位名称|说明|
|\[31\]|START|0：停止FMAC执行1：开始FMAC执行（FMAC执行过程中）写入1触发FUNC指定操作开始执行，写入0可以停止执行中的操作，初始化操作完成后此位由硬件自动清零。|
|\[30:28\]|未使用|NA|
|\[27:24\]|FUNC|0: Reserved1: Load X1 buffer2: Load X2 buffer3: Load Y buffer4 to 7: Reserved8: Convolution (FIR filter)9: IIR filter (direct form 1)此位域在START=1时无法修改|
|\[23:16\]|R|输入参数R，Y输出前移位幅度，即Y输出前乘以2R倍此位域在START=1时无法修改|
|\[15:8\]|Q|输入参数Q，IIR中反馈系数个数此位域在START=1时无法修改|
|\[7:0\]|P|输入参数P，FIR及IIR中前馈系数个数此位域在START=1时无法修改|

#### FMAC_CR FMAC 控制寄存器

地址：0x4001_7010

复位值：0x0

表12-7 FMAC_CR FMAC控制寄存器

|||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|31|30|29|28|27|26|25|24|23|22|21|20|19|18|17|16|
||||||||||||||||RESET|
||||||||||||||||WO|
||||||||||||||||0|
|15|14|13|12|11|10|9|8|7|6|5|4|3|2|1|0|
|CLIPEN||||||DMAWEN|DMAREN||||SATIEN|UNFLIEN|OVFLIEN|WIEN|RIEN|
|RW||||||RW|RW||||RW|RW|RW|RW|RW|
|0||||||0|0||||0|0|0|0|0|

||||
|---|---|---|
|位置|位名称|说明|
|\[31:17\]|未使用|NA|
|\[16\]|RESET|复位FMAC模块，向此位写1可以将FMAC内部的读写指针，内部逻辑状态机，FMAC_SR寄存器和FMAC_PARAM寄存器（包括START）进行复位，其他寄存器不受影响。此位写入自动清零。|
|\[15\]|CLIPEN|累加器输出饱和使能1：累加器增益控制后的输出被钳位在Q1.15范围内0：累加器增益控制后的输出超出Q1.15范围时丢弃高位|
|\[14:10\]|未使用|NA|
|\[9\]|DMAWEN|DMA写X1 buffer请求使能0：禁用，无DMA写请求产生1：使能，当X1不满时有DMA写请求产生此位只能在START=0时进行改写|
|\[8\]|DMAREN|DMA读请求使能0：禁用，无DMA写请求产生1：使能，当Y不空时有DMA读请求产生此位只能在START=0时进行改写|
|\[7:5\]|未使用|NA|
|\[4\]|SATIEN|累加器饱和错误中断使能0：禁用1：使能，当FMAC_SR.SAT置位时产生中断请求|
|\[3\]|UNFLIEN|Y buffer下溢出中断使能0：禁用1：使能，当FMAC_SR.UNFL置位时产生中断请求|
|\[2\]|OVFLIEN|X1 buffer上溢出中断使能0：禁用1：使能，当FMAC_SR.OVFL置位时产生中断请求|
|\[1\]|WIEN|X1 buffer写请求中断使能0：禁用1：使能，当X1 buffer不满时，向CPU发出写请求中断|
|\[0\]|RIEN|Y buffer读请求使能0：禁用1：使能，当Y buffer不空时，向CPU发出读请求中断|

#### FMAC_SR FMAC 状态寄存器

地址：0x4001_7014

复位值：0x00000001

表12-8 FMAC_SR FMAC状态寄存器

|||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|31|30|29|28|27|26|25|24|23|22|21|20|19|18|17|16|
|||||||||||||||||
|15|14|13|12|11|10|9|8|7|6|5|4|3|2|1|0|
||||||SAT|UNFL|OVFL|||||||X1_FULL|Y_EMPTY|
||||||RO|RO|RO|||||||RO|RO|
||||||0|0|0|||||||0|1|

||||
|---|---|---|
|位置|位名称|说明|
|\[31:11\]|未使用|NA|
|\[10\]|SAT|饱和错误标志当累加器输出结果超出Q1.15表示范围时，此位置位0：未发生饱和事件1：监测到饱和事件发生。如果FMAC_CR.SATIEN置位，则产生中断请求|
|\[9\]|UNFL|Y buffer下溢出错误标志当Y buffer中无有效数据且软件或DMA读取FMAC_RDATA时产生下溢出事件0：未发生下溢出事件1：监测到下溢出事件发生。如果FMAC_CR.UNFLIEN置位，则产生中断请求|
|\[8\]|OVFL|X1 buffer上溢出错误标志当X1 buffer中无空闲空间且软件或DMA通过FMAC_WDATA向X1 buffer写入数据时时产生上溢出事件0：未发生上溢出事件1：监测到上溢出事件发生。如果FMAC_CR.OVFLIEN置位，则产生中断请求|
|\[7:2\]|未使用|NA|
|\[1\]|X1_FULL|X1 buffer满标志当X1 buffer中的空闲空间大小小于水线阈值时，X1 buffer被标志位满。空闲空间大小等于写指针与最近一次读指针之差。0：X1 buffer不满。如果FMAC_CR.WIEN置位则产生中断请求向X1 buffer写入数据。如果FMAC_CR.DMAWEN置位则请求DMA向X1 buffer写入数据，直到X1_FULL置位。1：X1 buffer满此位由硬件自动置位清零，也可以通过向FMAC_CR.RESET写1清零|
|\[0\]|Y_EMPTY|Y buffer空标志当Y buffer中的有效数据数量小于水线阈值时，Y buffer被标志为空。有效数据数量等于读指针与累加器写入数据目的地址之差。0：Y buffer不空。如果FMAC_CR.RIEN置位则产生中断请求从Y buffer读取数据。如果FMAC_CR.DMAREN置位，则请求DMA从Y buffer读取数据直到Y_EMPTY置位。1：Y buffer空此位由硬件自动置位清零，也可以通过向FMAC_CR.RESET写1清零|

#### FMAC_WDATA FMAC 写入数据寄存器

地址：0x4001_7018

复位值：0x0

表12-9 FMAC_WDATA FMAC 写入数据寄存器

|||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|31|30|29|28|27|26|25|24|23|22|21|20|19|18|17|16|
|||||||||||||||||
|15|14|13|12|11|10|9|8|7|6|5|4|3|2|1|0|
|WDATA||||||||||||||||
|WO||||||||||||||||
|0||||||||||||||||

||||
|---|---|---|
|位置|位名称|说明|
|\[31:16\]|未使用|NA|
|\[15:0\]|WDATA|写入数据，向此寄存器写入数据，数据被写入写指针指向的本地存储地址，写后写指针自动加1|

#### FMAC_RDATA FMAC 读取数据寄存器

地址：0x4001_701C

复位值：0x0

表12-10 FMAC_RDATA FMAC 读取数据寄存器

|||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|31|30|29|28|27|26|25|24|23|22|21|20|19|18|17|16|
|||||||||||||||||
|15|14|13|12|11|10|9|8|7|6|5|4|3|2|1|0|
|RDATA||||||||||||||||
|RO||||||||||||||||
|0||||||||||||||||

||||
|---|---|---|
|位置|位名称|说明|
|\[31:16\]|未使用|NA|
|\[15:0\]|RDATA|读出数据，从寄存器读取数据，数据被从读指针指向的本地存储地址读出，读后读指针自动加1|

