FMAC (滤波器数学加速器)

简介

FMAC 对向量执行算术运算。它包括一个乘法/累加 (MAC) 单元,以及地址生成逻辑,这使得它可以索引保存在本地内存中的向量元素。

FMAC 可以从 CPU 中释放与滤波器有关的运算,让 CPU 去执行其他任务。在许多情况下,与软件实现相比,它可以加速此类计算,从而加快时间关键任务的速度。

功能概述

  • 支持16位的输入输出数据

  • 拥有256 x 16 位本地内存

  • 可以在内存中定义三个区域用于数据缓存 (两个输入,一个输出),由可编程的基地址指针和相关的大小寄存器定义

  • 输入和输出采样缓冲区为环形 buffer

  • 可编程输入输出 buffer“水线”以减少中断开销

  • 支持FIR滤波器和IIR滤波器

  • 支持 DMA 读写

功能解析配置

有限脉冲响应 (FIR) 滤波器操作 (也称为卷积) 包括重复计算系数向量和输入样本向量的点积,一次点积计算完之后将输入样本向量移动一个样本延迟,丢弃掉最先被计算的样本,并在每次重复计算中添加一个新样本。

无限脉冲响应 (IIR) 滤波器运算是将反馈系数与之前的输出样本进行卷积,再加上 FIR卷积的结果。

FMAC 的核心功能包括三种数据加载操作(加载 X1 输入缓冲区、加载 X2 系数缓冲区、加载 Y 输出缓冲区)和两种卷积计算操作(FIR 滤波、IIR 滤波)。其中以 FIR/IIR 滤波器计算为主,前面三种加载操作主要是把数据准备到本地内存中,辅助后面两个计算功能。不同芯片的驱动接口有所差异:

驱动为每种操作提供独立的接口函数:加载操作对应 FMAC_loadX1Buff()FMAC_loadX2Buff()FMAC_loadYBuff() ;卷积计算对应 FMAC_FIR_convolutionStart()FMAC_IIR_convolutionStart()

输入输出数据格式

FMAC的数据输入输出格式固定为16bit定点数,统一为s(16,15)格式数据;数值范围是-1(0x8000)到1-2^-15(0x7FFF)。

FMAC中的累加器有26位,数据格式为s(26,22),支持数据范围为-8(0x800000)到8-2^-22(0x7FFFFF)。由于累加器的数值范围限制,在超出数值范围后,针对数据的截取有两种方式。

从输入到累加器到输出的整个过程中有两个部分需要对数据进行部分处理:

数据处理的地方

中间两种关于数据处理的方式为:

  1. wrap模式:截取模式,超出数据范围的数据丢掉,仅保留有效位内的数据。

  2. saturate模式:饱和模式,超出范围后,数据直接饱和为最大或最小,不进行数据截取。

FIR滤波功能

FIR滤波器部分主要分两个部分进行说明,一个是FIR滤波器的原理,一个是FIR滤波计算功能的配置。

FIR 受内存大小限制,滤波阶数最大为127阶。

FIR滤波器计算

  • FIR计算公式:

    \[Y = B * X\]

    执行长度为N+1的向量B与不定长向量X的卷积。其中向量B包含滤波器系数,向量X包含输入数据。

    \[\begin{split}y_n &= 2^R \times \sum_{k=0}^{N} b_k x_{n-k} \\ &= 2^R \cdot (b_0 x_n + b_1 x_{n-1} + \cdots + b_N x_{n-N})\end{split}\]

    Y中每次增加的元素yn都是用点积来计算的: yn = B * Xn

  • FIR滤波器结构

FIR滤波器结构
输入:
  • X1缓冲区包含向量X的元素,它是一个长度为N+1+d1的循环缓冲区。

  • X2缓冲区包含向量B的元素,它是一个长度为N+1的固定缓冲区。

输出:
  • Y缓冲区包含输出值yn,它是一个长度为d的循环缓冲区。

参数对应:
  • cfg_p(P) 包含长度为 N+1 的系数向量 B,范围为[2~127]。

  • cfg_r(R)包含应用于累加器输出的增益值,输出到 Y 缓冲区的值乘以 2^R,其中 R的范围为[0~7]。

  • cfg_q(Q)未被使用,因为没有反馈系数,所以Q参数不进行初始化配置;

FIR滤波器配置

  • 根据上述中的几个参数对输入缓冲区和输出缓冲区进行初始化配置,缓冲区的地址可以随意配置,但是为了方便理解,并且避免内存缓冲区重叠,下面给出缓冲区的推荐配置:

  1. X1_Buffer 用于存放 X 向量,为用于FIR计算的输入数据;需要配置 x1_basex1_buf_size 两个参数,分别为X1缓冲区的基地址和缓冲区大小。

  • X1缓冲区存放的是输入数据,输入数据是循环进行输入的,整个空间是需要进行循环输入使用,这里为了提高吞吐量,输入数据可以额外增加空d1大小,以确保滤波器不会因为等待新的数据被写入而暂停。

  • X1缓冲区的基地址为 N ,x1_buf_size配置为 N+d1

  1. X2_Buffer 用于存放 B 向量,为用于FIR计算的滤波器系数;需要配置 x2_basex2_buf_size 两个参数,分别为X2缓冲区的基地址和缓冲区大小。

  • X2缓冲区由于存放的是滤波器系数,系数个数是固定的,所以一般把 x2_base 的基地址配置为 0x2_buf_size 配置为 N

  1. Y_Buffer 用于存放输出数据,为FIR计算的结果;需要配置 y_basey_buf_size 两个参数,分别为Y缓冲区的基地址和缓冲区大小。

  • Y缓冲区由于存放的是输出结果,在FIR中没有反馈系数,所以结果缓冲区没有强制的大小要求,但是为了保证计算不会因为等待数据数据被读取而暂停。

  • Y缓冲区的基地址为 N+N+d1 ,y_buf_size配置为 d2 = 256-N-N-d1

缓存区分配图
  • 配置流程图:

    FIR计算流程

IIR滤波功能

IIR滤波器部分主要分两个部分进行说明,一个是IIR滤波器的原理,一个是IIR滤波计算功能的配置。

IIR滤波器计算

  • IIR计算公式:

    \[Y = B * X + A * Y'\]
    \begin{aligned} y_n &= 2^R \times \left(\sum_{k = 0}^{N} b_k x_{n - k} + \sum_{k = 1}^{M} a_k y_{n - k}\right) \\ &= 2^R \cdot (b_0 x_n + b_1 x_{n-1} + \cdots + b_N x_{n-N} + a_1 y_{n-1} + \cdots + a_M y_{n-M}) \end{aligned}

    滤波器输出向量Y是长度为N+1的系数向量B和不定长的向量X的卷积,加上延迟输出向量 Y’ 与长度为 M 的第二个系数向量 A 的卷积。

  • IIR滤波器结构

IIR滤波器结构(直接I型)
输入:
  • X1缓冲区包含向量X的元素,它是一个长度为N+1+d1的循环缓冲区。

  • X2缓冲区包含系数向量B和A的元素,它是一个长度为N+M+1的固定缓冲区。

输出:
  • Y缓冲区包含输出值yn,它是一个长度为M+d的循环缓冲区。

参数对应:
  • cfg_p(P) 包含长度为 N+1 的系数向量 B,范围为[2~64]。

  • cfg_q(Q)包含长度为 M 的系数向量 A,范围为[1~63]。

  • cfg_r(R)包含应用于累加器输出的增益值,输出到 Y 缓冲区的值乘以 2^R,其中 R的范围为[0~7]。

IIR滤波器配置

  • 根据上述中的几个参数对输入缓冲区和输出缓冲区进行初始化配置,缓冲区的地址可以随意配置,但是为了方便理解,并且避免内存缓冲区重叠,下面给出缓冲区的推荐配置:

  1. X1_Buffer 用于存放 X 向量,为用于IIR计算的输入数据;需要配置 x1_basex1_buf_size 两个参数,分别为X1缓冲区的基地址和缓冲区大小。

  • X1缓冲区存放的是输入数据,输入数据是循环进行输入的,整个空间是需要进行循环输入使用,这里为了提高吞吐量,输入数据可以额外增加d1大小,以确保滤波器在循环中计算中不会因为等待新的数据被写入而暂停。

  • X1缓冲区的基地址为 N + M ,x1_buf_size配置为 N + d1

  1. X2_Buffer 用于存放 B 向量,为用于IIR计算的滤波器系数向量 B 和向量 A ;需要配置 x2_basex2_buf_size 两个参数,分别为X2缓冲区的基地址和缓冲区大小。

  • X2缓冲区由于存放的是滤波器系数,系数个数是固定的,所以一般把 x2_base 的基地址配置为 0x2_buf_size 配置为 N(向量B的长度) + M(向量A的长度)

  1. Y_Buffer 用于存放输出数据,为FIR计算的结果;需要配置 y_basey_buf_size 两个参数,分别为Y缓冲区的基地址和缓冲区大小。

  • Y缓冲区由于存放的是输出结果,在IIR中需要进行反馈计算,所以结果缓冲区的大小至少要等与A向量的长度M,但是为了保证计算不会因为等待数据数据被读取而暂停,所以需要留出一部分区域周转。

  • Y缓冲区的基地址为 N+N+M+d1 ,y_buf_size配置为 d2 = 256-N-N-M-d1

缓存区分配图

备注

X1缓存区多分配了额外空间大小为d1,要求X1的缓存区阈值应该小于或等于 \(\log_2(d_1)\) ,否则在写入N个数据样本之前,缓存区就会被标记为满【因为满标志位在缓存区中的空闲空间数量小于 2^full_wm时置位】。 同理Y缓存区多分配了额外空间大小为d2,要求Y的缓存区阈值也必须应该小于或等于 \(\log_2(d_2)\)

  • 配置流程图:

    IIR计算流程

数据写入和读取方式

在配置和初始化缓冲区完成后,在计算中动态向FMAC内存写入数据和读取数据的方式共有三种:软件轮询、中断读写、DMA通路。

  • 轮询模式:不产生 DMA 请求或中断请求。软件必须在向 X1 缓冲区写入数据之前检查X1 缓冲区的满标志值是否为低,在从 Y 缓冲区读取数据之前检查 Y 缓冲区空标志值是否低。 因为输入和读取使用的是同一个FIFO寄存器接口,所以要注意读取和写入的顺序,常规使用一般先判断X1_Buffer满标志,如果不满则先通过FIFO先向X1_Buffer写入数据,直到写满为止。 然后判断Y_Buffer空标志,如果非空,则开始从FIFO中读取数据,直到读完为止,重复进行写入和读取操作。

  • 中断模式:当 X1 缓冲区的满标志值为低时,产生写数据中断请求,在对应中断函数中向FIFO写入数据;当 Y 缓冲区空标志值为低时,产生读数据中断请求,在对应中断函数中读取FIFO寄存器;

  • DMA模式:当 X1 缓冲区的满标志值为低时,产生 DMA 写数据请求;当 Y 缓冲区空标志值为低时,产生 DMA 读数据请求,这里的请求只要使能FMAC模块中的DMA使能位即可,读写DMA使能需要分开配置。

读写数据可以使用不同的方法。但是对于同一个操作 (写入或者读取),不建议同时使用中断和 DMA 请求,这样不能控制数据写入的顺序。读写数据的有效组合方式如下表所示:

写数据中断使能

读数据中断使能

DMA写数据使能

DMA读数据使能

写数据

读数据

0

0

0

0

轮询

轮询

0

1

0

0

轮询

中断

1

0

0

0

中断

轮询

1

1

0

0

中断

中断

0

0

1

0

DMA

轮询

0

1

1

0

DMA

中断

0

0

1

1

DMA

DMA

1

0

0

1

中断

DMA

软件配置流程

FIR滤波器配置流程如下:

  1. 配置FMAC

    调用 FMAC_config() 传入参数结构体指针

  2. 将过滤系数加载到X2缓冲区

    调用 FMAC_loadX2Buff() 传入相关参数

  3. 将输入数据加载到X1缓冲区

    调用 FMAC_loadX1Buff() 传入相关参数

  4. 启动FIR卷积并将结果存储到输出缓冲区中

    调用 FMAC_FIR_convolutionStart() 传入相关参数。

IIR滤波器配置流程如下:

  1. 配置FMAC

    调用 FMAC_config() 传入参数结构体指针

  2. 将过滤系数加载到X2缓冲区

    调用 FMAC_loadX2Buff() 传入相关参数

  3. 将输入数据加载到X1缓冲区

    调用 FMAC_loadX1Buff() 传入相关参数

  4. 将初始的输出数据(这里可以默认加载数据0)加载到Y缓冲区,这个动作主要是需要确认有初始数据用于计算

    调用 FMAC_loadYBuff() 传入相关参数

  5. 启动IIR卷积并将结果存储到输出缓冲区中

    调用 FMAC_IIR_convolutionStart() 传入相关参数。

应用示例

API Reference

Header File

Functions

void FMAC_config(FMAC_ConfigParams *config)

Initial FMAC and configure parameters.

参数:

config

DRV_Status FMAC_loadX1Buff(int16_t *pInputData, uint32_t *pOutoutDataNum, uint8_t maxDataNum, uint32_t timeout)

load X1 buff

参数:
  • pInputData

  • pInputDataNum

  • maxDataNum

  • timeout

返回:

DRV_Status

DRV_Status FMAC_loadX2Buff(int16_t *pInputData, uint8_t dataNum, uint32_t timeout)

load X2 buff

参数:
  • pInputData

  • dataNum

  • timeout

返回:

DRV_Status

DRV_Status FMAC_IIR_loadX2Buff(int16_t *pInputCoeffA, uint8_t coeffANum, int16_t *pInputCoeffB, uint8_t coeffBNum, uint32_t timeout)

load X2 buff for IIR

参数:
  • pInputCoeffA

  • coeffANum

  • pInputCoeffB

  • coeffBNum

  • timeout

返回:

DRV_Status

DRV_Status FMAC_loadYBuff(int16_t *pInputData, uint8_t dataNum, uint32_t timeout)

load Y buff

参数:
  • pInputData

  • dataNum

  • timeout

返回:

DRV_Status

DRV_Status FMAC_FIR_convolutionStart(int16_t *pInputData, int16_t *pOutoutData, uint32_t dataNum, uint8_t gain, uint32_t timeout)

start FIR convolution

参数:
  • pInputData

  • pOutoutData

  • dataNum

  • timeout

返回:

DRV_Status

DRV_Status FMAC_FIR_convolutionInterruptDMA(uint8_t gain)

FIR convolution DMA and interrupt configuration.

参数:

gain[in]

返回:

DRV_Status

DRV_Status FMAC_IIR_convolutionStart(int16_t *pInputData, int16_t *pOutoutData, uint8_t numStages, uint32_t dataNum, uint8_t gain, uint32_t timeout)

start IIR convolution

参数:
  • pInputData

  • pOutoutData

  • dataNum

  • gain

  • timeout

返回:

DRV_Status

DRV_Status FMAC_IIR_convolutionInterruptDMA(uint8_t numStages, uint8_t gain)

IIR convolution DMA and interrupt configuration.

参数:
  • numStages[in] number of stages

  • gain[in] gain

返回:

DRV_Status

DRV_Status FMAC_convolutionAppend(int16_t *pInputData, int16_t *pOutoutData, uint32_t dataNum, uint32_t timeout)

FIR and IIR convolution data append.

参数:
  • pInputData

  • pInputDataNum

  • maxInputDataNum

  • pOutoutData

  • pOutoutDataNum

  • maxOutoutDataNum

  • timeout

返回:

DRV_Status

void FMAC_writeFIFO(int16_t data)

set FIFO data

返回:

int16_t

int16_t FMAC_readFIFO(void)

get FIFO data

返回:

int16_t

void FMAC_resetFilter(void)

reset FMAC buffer and parameters

bool FMAC_isFuncBusy(void)

get function busy status

返回:

true

返回:

false

uint8_t FMAC_getX1BuffSpareSpaceNum(void)

get X1 buff spare space number

返回:

uint8_t

uint8_t FMAC_getYBuffUnreadDataNum(void)

get Y buff unread data number

返回:

uint8_t

uint32_t FMAC_getStatus(void)

get FMAC status

返回:

uint32_t

void FMAC_enableInterrupt(uint32_t interruptMasks)

enable interrupt

参数:

interruptMasks

void FMAC_disableInterrupt(uint32_t interruptMasks)

disable interrupt

参数:

interruptMasks

void FMAC_forceInterrupt(uint32_t interruptMasks)

force interrupt

参数:

interruptMasks

void FMAC_clearInterruptStatus(uint32_t interruptMasks)

clear interrupt status

参数:

interruptMasks

uint32_t FMAC_getInterruptStatusRaw(void)

get interrupt raw status

返回:

uint32_t

uint32_t FMAC_getInterruptStatus(void)

get interrupt status

返回:

uint32_t

void FMAC_setInterruptMask(uint32_t interruptMasks)

set interrupt masks

参数:

interruptMasks

void FMAC_clearInterruptMask(uint32_t interruptMasks)

clear interrupt masks

参数:

interruptMasks

Structures

struct FMAC_ConfigParams

Public Members

uint8_t X1_BuffBase

< Base address of the input buffer (X1) within the internal memory Number of 16-bit words allocated to the input buffer

uint8_t X1_BuffSize

Input threshold: the buffer full flag will be set if the number of free spaces in the buffer is lower than this threshold.This parameter can be a value of FMAC_BuffFIFOLevel.

FMAC_BuffFIFOLevel X1_BuffFIFOTrhd

Base address of the coefficient buffer (X2) within the internal memory

uint8_t X2_BuffBase

Number of 16-bit words allocated to the coefficient buffer.

uint8_t X2_BuffSize

Base address of the output buffer (Y) within the internal memory (0x00 to 0xFF)

uint8_t Y_BuffBase

Number of 16-bit words allocated to the output buffer

uint8_t Y_BuffSize

Output threshold: the buffer empty flag will be set if the number of unread values in the buffer is lower than this threshold.This parameter can be a value of FMAC_BuffFIFOLevel.

FMAC_BuffFIFOLevel Y_BuffFIFOTrhd

whether warp the accumulator output

ControlStatus accumulatorWrapEn

output data format

FMAC_OutputDataFormat outputDataFormat

input Buffer accessed through DMA

ControlStatus DMADataReadEn

output Buffer accessed through DMA

ControlStatus DMADataWriteEn

Enable or disable the clipping feature

ControlStatus clipEn

output data offset value

uint16_t outputDataOffset

output data shift value

Macros

FMAC_STS_Y_BUFF_IS_EMPTY_FLAG_MASK
FMAC_STS_X1_BUFF_IS_FULL_FLAG_MASK
FMAC_STS_X1_BUFF_IS_OVERFLOW_FLAG_MASK
FMAC_STS_Y_BUFF_IS_UNDERFLOW_FLAG_MASK
FMAC_STS_ACCUMULATOR_DATA_IS_SAT_FLAG_MASK
FMAC_STS_OUTPUT_IS_NEGATIVE_WITH_OFFSET_FLAG_MASK
FMAC_IT_X1_BUFF_REQ_IT_MASK
FMAC_IT_Y_BUFF_REQ_IT_MASK
FMAC_IT_FIR_IIR_SAT_IT_MASK
FMAC_IT_X1_BUFF_OVERFLOW_IT_MASK
FMAC_IT_Y_BUFF_UNDERFLOW_IT_MASK
FMAC_IT_P_PARAM_ERR_IT_MASK
FMAC_IT_Q_PARAM_ERR_IT_MASK
FMAC_IT_R_PARAM_ERR_IT_MASK

Enumerations

enum FMAC_BuffFIFOLevel

fifo watermark level for input and output buffers

Values:

enumerator FMAC_FIFO_TRHD_1
enumerator FMAC_FIFO_TRHD_2
enumerator FMAC_FIFO_TRHD_4
enumerator FMAC_FIFO_TRHD_8
enum FMAC_OutputDataFormat

FMAC output data format.

Values:

enumerator FMAC_NO_OFFSET_AND_SAT

direct output

enumerator FMAC_ADD_SHIFT_AND_SAT_TO_12BIT

output data with shift and saturation to 12bit

enumerator FMAC_ADD_SHIFT_AND_SAT_TO_16BIT

output data with shift and saturation to 16bit

enum FMAC_OutputDataShift

FMAC output data shift.

Values:

enumerator FMAC_LEFT_SHIFT_8
enumerator FMAC_LEFT_SHIFT_7
enumerator FMAC_LEFT_SHIFT_6
enumerator FMAC_LEFT_SHIFT_5
enumerator FMAC_LEFT_SHIFT_4
enumerator FMAC_LEFT_SHIFT_3
enumerator FMAC_LEFT_SHIFT_2
enumerator FMAC_LEFT_SHIFT_1
enumerator FMAC_NO_SHIFT
enumerator FMAC_RIGHT_SHIFT_1
enumerator FMAC_RIGHT_SHIFT_2
enumerator FMAC_RIGHT_SHIFT_3
enumerator FMAC_RIGHT_SHIFT_4
enumerator FMAC_RIGHT_SHIFT_5
enumerator FMAC_RIGHT_SHIFT_6
enumerator FMAC_RIGHT_SHIFT_7