1. 雷达硬件加速器:FFT处理的幕后功臣
在雷达信号处理,尤其是像毫米波雷达这样的高分辨率应用中,实时性就是生命线。一帧雷达数据,从天线接收的模拟信号,到最终我们能在屏幕上看到的点云或目标列表,中间要经过模数转换、数字下变频、脉冲压缩(通常通过FFT实现)、恒虚警检测等一系列复杂运算。如果这些运算全靠主处理器(比如ARM Cortex-R4F)来承担,其负载会非常沉重,难以满足系统对低延迟和低功耗的要求。
这时,专用的雷达硬件加速器(Radar Hardware Accelerator)就成了解决问题的关键。它就像一个高度专业化的“数学协处理器”,专门负责处理雷达信号处理流水线中最耗时的核心算法,尤其是快速傅里叶变换。它的设计目标非常明确:以最高的能效比,实现确定性的、高吞吐量的数据处理。今天,我们就深入拆解这个加速器中两个至关重要的“数据管家”——输入格式化器(Input Formatter)和输出格式化器(Output Formatter),看看它们是如何与FFT引擎协同工作,将杂乱的原始数据流,变成规整、可用的频域结果的。理解这两个模块,是高效配置和发挥硬件加速器性能的基础。
2. 核心架构与数据流全景
在深入细节之前,我们需要先建立起对整个加速器数据通路的宏观认识。硬件加速器并非一个孤立的黑盒,它被精心集成在SoC的存储子系统之中,与DMA和处理器核心紧密协作。
2.1 系统级视图:内存、数据流与控制
想象一下加速器的工作场景:大量的ADC采样数据通过DMA被源源不断地搬运到一片专属于加速器的“工作区”——即加速器本地内存(Accelerator Local Memories)。这片工作区通常由多个(例如4个)独立的16KB内存块(Bank)组成,它们在地址空间上是连续的,共同构成一个64KB的寻址空间。加速器的核心任务,就是从这片内存的某个区域(源内存)读取数据,经过内部计算单元处理,再将结果写回到这片内存的另一个区域(目的内存)。
整个数据旅程由三个核心模块接力完成:
- 输入格式化器:它扮演“数据准备员”的角色。根据配置,它从源内存中以特定的模式(比如间隔读取、跳读)抓取数据,并进行必要的预处理,如零填充、复数/实数转换、缩放等,然后将格式统一的24位复数流(24位实部 + 24位虚部)喂给核心计算单元。
- 核心计算单元:这是“数学运算引擎”。它接收格式化后的数据流,执行我们配置的算法,比如加窗、FFT、求对数幅度等。它以流水线方式工作,在稳态下能够每个时钟周期吞入一个复数样本,并吐出一个结果样本。
- 输出格式化器:它扮演“数据归档员”的角色。接收来自核心计算单元的24位复数结果流,根据配置进行后处理(如缩放、共轭、取实部等),然后以灵活的存储模式(如转置写入、间隔写入)将结果存回目的内存。
这三个模块被一个状态机统一调度。状态机管理着一系列参数集。每个参数集完整定义了输入、计算、输出三个阶段的所有配置寄存器值。通过编排多个参数集的执行顺序,我们可以实现复杂的多级处理流水线,例如先对每个脉冲的采样做距离维FFT(第一维),再对多个脉冲相同距离单元的数据做多普勒维FFT(第二维)。
2.2 关键设计哲学:吞吐量与灵活性
这个架构体现了两个核心设计思想:高吞吐量和配置灵活性。
- 高吞吐量:通过输入、计算、输出三个模块的深度流水线化,实现了每个时钟周期处理一个复数样本的稳态吞吐率。对于200MHz的系统时钟,这意味着每秒2亿个复数样本的处理能力,足以应对多通道雷达的实时数据流。
- 配置灵活性:通过参数集机制,几乎所有的数据路径和行为都可以在运行时动态配置。这使得同一套硬件能够适应不同的雷达模式(如短距、长距)、不同的算法步骤(如仅FFT、或FFT+对数幅度),而无需硬件改动。
理解了这套整体流程,我们就能明白,输入输出格式化器并非简单的数据搬运工,而是确保数据以正确“形状”和“节奏”流经计算引擎的关键智能接口。配置不当,轻则导致数据错位、结果错误,重则可能因内存访问冲突导致系统挂起。
3. 输入格式化器:数据搬运与预处理的艺术
输入格式化器是数据进入计算引擎的“海关”,它的职责是确保送进去的数据格式完全符合FFT引擎等计算单元的要求。它的配置直接决定了“读什么数据”以及“怎么读”。
3.1 核心寄存器组与寻址模式
输入格式化器的行为由一组参数集寄存器控制。要理解它,必须掌握几个核心寄存器的协同工作方式,它们共同定义了一种强大的二维索引寻址模式。
SRCADDR:源起始地址。指向加速器本地内存中原始数据的起始位置(字节地址)。SRCACNT:源样本计数。定义每次迭代需要从源内存中读取的样本数量(实际值=寄存器值+1)。注意,这是样本数,不是字节数。SRCAINDX:源样本索引增量。定义同一次迭代内,连续两个样本在内存中的字节间隔。例如,如果复数样本以实部、虚部交错存储,每个部分16位(2字节),那么间隔就是4字节。REG_BCNT:迭代次数。定义整个处理过程需要重复多少次(实际迭代次数=寄存器值+1)。这常用于连续处理多个接收通道的数据。SRCBINDX:源偏移量/迭代。定义连续两次迭代之间,源起始地址的字节偏移量。这用于在内存中跳过一段数据,读取下一个通道的数据块。
一个生动的例子:假设我们有4个接收通道(RX0, RX1, RX2, RX3),每个通道采集了256个复数样本,每个样本的实部和虚部各用16位存储,交错排列。所有通道的数据在内存中连续存放。
- 要处理RX0的256个样本:
SRCADDR指向RX0数据起始处,SRCACNT=255,SRCAINDX=4(样本间隔),REG_BCNT=0(单次迭代)。 - 要依次处理所有4个通道:
SRCADDR指向RX0起始处,SRCACNT=255,SRCAINDX=4,REG_BCNT=3(4次迭代),SRCBINDX=1024(256样本/通道 * 4字节/样本 = 1024字节,即下一个通道的起始偏移)。
这种SRCAINDX和SRCBINDX的组合,赋予了格式化器强大的数据重组能力。它不仅能处理连续数据,还能实现“跳跃式”读取,例如从多个交织存放的数据流中,抽取出属于同一通道的所有数据。
3.2 零填充:应对非2的幂次点数
FFT算法在硬件上实现时,为了达到最高效率,通常要求点数N是2的幂次(如256,512,1024)。但实际采样点数可能并非如此。例如,由于雷达波形设计或抗混叠滤波器的限制,我们可能只采集了200个有效样本。
这时,零填充功能就至关重要了。输入格式化器可以自动完成这个操作。我们通过FFTSIZE寄存器设定FFT引擎的大小(例如,设定为8,代表256点FFT)。当SRCACNT设定的实际样本数(如199,代表200个样本)小于FFT点数(256)时,输入格式化器会在读取完所有有效样本后,自动向计算单元补足相应数量的零值样本(此例中为56个零),然后再开始下一次迭代或结束。
关键限制:SRCACNT(代表的样本数)必须永远小于或等于2^FFTSIZE - 1。你不能要求做一个128点(FFTSIZE=7)的FFT,却试图送入129个样本。硬件会通过自动零填充来适配较小的样本数,但无法处理超出的情况。
实操心得:零填充虽然方便,但它会改变频谱。增加的零样本实际上是在时域上对原信号加了一个矩形窗,这会导致频域频谱泄露特性发生变化,主瓣会变窄(因为看起来信号长度变长了),但旁瓣特性由原数据的窗函数决定。在雷达测距中,零填充可以提高FFT输出的频率分辨率(更多频点),但不会提高真实的物理分辨率(这由信号带宽决定)。它常用于需要做谱峰插值或与后续固定点数模块对接的场景。
3.3 数据格式转换与预处理
在将数据送入24位宽的核心计算单元前,输入格式化器还能进行一系列格式转换:
SRCREAL:输入为实数或复数。如果输入是实数(如单通道的ADC数据),设置此位为1,格式化器会自动为每个样本生成一个为0的虚部,构成24位复数。SRC16b32b:输入数据位宽。指示从内存中读取的样本是16位宽还是32位宽。这决定了格式化器如何将内存中的数据拼接成24位。SRCSIGNED:输入符号扩展模式。如果输入数据是有符号数(雷达的ADC数据通常都是有符号的),必须将此位置1,这样在将16/32位数据扩展到24位时,会进行正确的符号扩展。SRCCONJ:输入共轭。将输入复数样本取共轭(实部不变,虚部取反)。这个功能,结合输出格式化器的共轭功能,可以实现逆FFT。REG_SRCSCAL:输入缩放。通过算术右移(保留符号位),对从内存读取的数据进行缩放,再送入24位数据路径。这用于调整输入信号的幅度,防止后续FFT计算溢出。
配置流程示例:假设我们从内存读取的是16位有符号、交错的实数采样数据(I0, I1, I2...),需要做256点复数FFT。
- 设置
SRCREAL=1,SRC16b32b=0,SRCSIGNED=1。 - 设置
SRCADDR指向数据起始。 - 设置
SRCACNT=255(256个实数样本,但注意,对于FFT引擎,它会被视为256个复数样本,虚部为0)。 - 设置
SRCAINDX=2(因为每个实数样本占2字节)。 - 设置
FFTSIZE=8(256点)。 - 根据输入信号幅度,可能还需要设置
REG_SRCSCAL进行适当的衰减。
4. 输出格式化器:结果存储与后处理的智慧
FFT引擎产出的结果是24位的复数流,并且初始顺序是位反转的。输出格式化器的任务就是接管这个流,进行必要的后处理,然后以我们期望的、规整的格式写回到内存中。
4.1 二维索引写入与数据重组
输出格式化器拥有与输入格式化器对称但独立的寄存器组(DSTADDR,DSTACNT,DSTAINDX,DSTBINDX),同样支持强大的二维索引寻址模式,这使得数据存储模式极其灵活。
一个经典应用场景是数据转置。在雷达处理中,我们经常需要做“距离-多普勒”二维FFT。首先对快时间维(距离)做FFT,结果按距离单元顺序存储。但接下来对慢时间维(多普勒)做FFT时,需要将相同距离单元、不同脉冲的数据排列在一起。如果第一次FFT的输出是连续存放的,那么第二次FFT的输入就需要进行“矩阵转置”。
输出格式化器可以巧妙地完成这个转置写入。假设有128个距离单元和256个脉冲( chirp)。
- 第一次FFT(距离维)的输出配置:
DSTAINDX设置为一个较大的值(如512),使得同一脉冲内、不同距离单元的结果在内存中间隔很远;DSTBINDX设置为一个较小的值(如4),使得下一个脉冲的第一个距离单元结果紧挨着上一个脉冲的第一个距离单元结果存放。这样,在内存中实际形成的就是一个“按脉冲优先”的存储布局,为第二次FFT准备好了数据。 DSTACNT与REG_DST_SKIP_INIT:DSTACNT定义了每次迭代写入的样本数,它可以小于FFT点数。结合REG_DST_SKIP_INIT(跳过起始的若干个样本),我们可以选择只存储FFT结果中我们关心的部分频点(例如,只保留基带附近的频点,丢弃高频部分),这能有效节省存储空间和后续处理的带宽。
4.2 位反转顺序校正
这是一个非常重要的隐藏功能。FFT硬件引擎为了优化蝶形运算的数据访问模式,其自然输出顺序是位反转的。也就是说,第n个输出频点并不存放在第n个内存位置。如果直接使用,会给后续处理带来巨大麻烦。
输出格式化器内部自动处理了这个问题。当FFT_EN使能时,它会将来自核心计算单元的、位反转顺序的数据流,在写入内存时自动校正为自然顺序。开发者完全无需关心内部的位反转寻址逻辑,只需要像访问普通数组一样访问FFT结果即可。这大大简化了软件层的处理。
4.3 数据缩放、格式转换与共轭
输出格式化器提供了强大的数据后处理能力:
REG_DSTSCAL:输出缩放。这是最常用的功能之一。FFT输出的24位数据动态范围很大,但我们最终可能只需要16位整数送给后续的检测算法或通过特定接口输出。REG_DSTSCAL允许我们对24位数据进行移位缩放,然后饱和处理或补零,生成16位或32位的结果。- 输出为16位:将24位数转换为16位数。
REG_DSTSCAL的值k决定了操作:丢弃低k位(含舍入),并对高8-k位进行饱和处理(防止溢出)。k越大,保留的高位数据越少,相当于对信号进行了更大的衰减。 - 输出为32位:将24位数转换为32位数。在24位数据的最高位之前符号扩展
k位,在最低位之后补零8-k位。这实际上是将定点数放置在一个更大位宽的容器中,保留了全部精度。
- 输出为16位:将24位数转换为16位数。
DSTSIGNED:输出符号模式。必须根据数据特性正确设置。对于普通的复数FFT输出,应设为1(有符号)。如果使能了核心计算单元的对数幅度(Log-Magnitude)功能,输出为无符号数,则应设为0。DSTREAL:输出实数/复数。如果只需要幅度信息(如进行CFAR检测),可以设置DSTREAL=1,这样输出格式化器将只写入结果的实部(即I路),丢弃虚部(Q路),节省一半的存储空间和带宽。DSTCONJ:输出共轭。与输入的SRCCONJ结合,可以实现IFFT。因为FFT和IFFT在数学上只差一个共轭操作和缩放因子。通过配置输入输出均进行共轭,再利用缩放寄存器调整幅度,即可用同一个FFT硬件引擎完成IFFT运算。
5. 核心计算单元:FFT引擎的深度配置
输入输出格式化器为FFT准备好了数据和存放地,而FFT运算本身的质量和性能则由核心计算单元内部的配置决定。
5.1 加窗处理
加窗是FFT前减少频谱泄漏的标准操作。加速器内部提供了一个1024x18位的可编程窗函数RAM。
- 灵活性:用户可以预存任何窗函数(汉宁窗、汉明窗、凯泽窗等),甚至为不同维度的FFT预存不同的窗。
- 配置:通过
WINDOW_START寄存器指定每次FFT运算起始使用的窗系数索引。WINSYMM寄存器位非常有用,如果窗函数是对称的,只需在RAM中存储前半部分窗系数,设置WINSYMM=1,硬件会自动在读取一半样本后反向索引,复用窗系数,节省了一半的RAM空间。 - 操作:窗系数(18位有符号实数)与输入的24位复数(I和Q)分别相乘,结果舍入回24位。通过
WINDOW_EN寄存器使能或旁路此功能。
5.2 FFT点数与性能
FFT大小通过FFTSIZE寄存器配置(例如,FFTSIZE=6代表64点FFT)。硬件支持2点到1024点(2的幂次)的FFT。更小的点数(如4,8,16,32)常用于角度估计(第三维FFT)。
- 吞吐量与延迟:架构采用流水线设计,在稳态下可以达到每个时钟周期输出一个频点。但存在一个初始延迟,大约等于FFT的点数。例如,做一个256点FFT,前255个时钟周期没有输出,从第256个时钟周期开始,才连续输出结果。这个延迟对于流式处理来说是可以接受的。
- FFT拼接:手册提到了支持2048和4096点FFT的“拼接”功能。这通常是通过将大点数FFT分解为两个小点数FFT,并结合额外的处理步骤来实现的,这需要更复杂的配置,通常在第二部分用户指南中描述。
5.3 量化、缩放与无杂散动态范围
这是影响FFT输出质量的关键环节。FFT蝶形运算中的加法和乘法会导致数据位宽增长。
- 蝶形缩放:
BFLY_SCALING是一个10位的寄存器,每一位独立控制一个蝶形运算级后的缩放策略。如果某一位为0,则该级加法器输出的25位结果将通过饱和处理(丢弃最高位)变回24位;如果为1,则通过舍入(丢弃最低位)变回24位。- 策略选择:饱和处理会引入非线性失真,但能最大限度保留信号强度;舍入会引入噪声,但更线性。通常的策略是:在信号强度可能较大的前几级使用舍入,在信号已经衰减的后几级使用饱和,以在动态范围和精度间取得平衡。
- 旋转因子抖动:旋转因子(Twiddle Factors)存储在ROM中,为24位。在乘法前,会先被截断到21位。
TWID_DITHER_EN寄存器使能一个伪随机数发生器(LFSR)对截断过程进行抖动。这能将量化误差白噪声化,避免产生相关的谐波杂散。强烈建议始终使能此功能,如图表所示,它可以将FFT的无杂散动态范围提升到优于-140dBc的水平。 - 溢出监测:
FFTCLIP是一个只读的状态寄存器,它的每一位指示对应的蝶形运算级是否发生过饱和溢出。这是一个“粘性”位,一旦置位,除非手动清除,否则会一直保持。在调试阶段,监控这个寄存器有助于判断BFLY_SCALING设置是否合理。
6. 实战配置与常见问题排查
理解了原理,最终要落到配置上。下面以一个典型的毫米波雷达处理链为例,展示如何配置参数集。
6.1 典型用例:距离维FFT处理链
场景:4接收通道,每个通道采集256个复数采样(16位I/Q交错存储),需进行256点加窗(汉宁窗)FFT,结果取对数幅度,并以16位有符号整数存储。
步骤分解:
数据准备:DMA将4个通道的原始采样数据搬运到加速器本地内存(例如
ACCEL_MEM0),布局为:Ch0_S0, Ch0_S1, ... Ch0_S255, Ch1_S0, Ch1_S1, ... Ch3_S255。窗系数加载:CPU将256点的汉宁窗系数(18位有符号定点数)预先写入窗函数RAM。由于汉宁窗对称,可只存储前128点,并设置
WINSYMM=1。配置参数集:
- 输入格式化:
SRCADDR:ACCEL_MEM0起始地址。SRCACNT: 255 (256个样本)。SRCAINDX: 4 (16位I+16位Q=4字节)。SRCBINDX: 1024 (256样本 * 4字节 = 1024,通道间隔)。REG_BCNT: 3 (处理4个通道)。SRCREAL: 0 (复数输入)。SRC16b32b: 0 (16位输入)。SRCSIGNED: 1 (有符号数)。SRCCONJ: 0。REG_SRCSCAL: 根据ADC数据幅度设定,防止溢出。
- 核心计算单元:
WINDOW_EN: 1。WINDOW_START: 窗系数起始索引(例如0)。WINSYMM: 1。FFT_EN: 1。FFTSIZE: 8 (256点)。BFLY_SCALING: 根据仿真或经验设置,例如0b0011111111(前两级饱和,后八级舍入)。TWID_DITHER_EN: 1。ABSEN: 1 (使能求模)。LOG2EN: 1 (使能以2为底的对数)。ACCEL_MODE: 0 (FFT引擎路径)。
- 输出格式化:
DSTADDR: 指向ACCEL_MEM1或ACCEL_MEM2(不能与源内存相同)。DSTACNT: 255 (存储全部256个距离门结果)。DSTAINDX: 2 (对数幅度结果为16位实数,每个占2字节)。DSTBINDX: 512 (256个结果 * 2字节 = 512,通道间隔)。REG_BCNT: 3 (与输入迭代次数一致)。DSTREAL: 1 (实数输出,对数幅度)。DST16b32b: 0 (输出16位)。DSTSIGNED: 0 (对数幅度结果为无符号数)。REG_DSTSCAL: 根据对数幅度输出的动态范围调整,将其缩放到16位整数的有效范围内。
- 输入格式化:
触发与执行:状态机加载该参数集,等待DMA传输完成的触发信号,然后开始自动处理。处理完成后,可以产生中断通知CPU。
6.2 常见问题与排查技巧
即使理解了所有寄存器,实际调试中仍会踩坑。以下是一些常见问题及排查思路:
| 问题现象 | 可能原因 | 排查步骤 |
|---|---|---|
| FFT结果完全错误(如全零、全最大值) | 1. 源/目的内存冲突。 2. SRCACNT大于2^FFTSIZE - 1。3. 数据格式配置错误(如 SRCSIGNED)。 | 1. 检查SRCADDR和DSTADDR是否指向了同一个16KB内存Bank。这是硬性限制。2. 确认 SRCACNT+1 <= 2^FFTSIZE。3. 核对 SRCREAL/SRC16b32b/SRCSIGNED是否与原始数据格式匹配。 |
| FFT输出幅度异常(过小或饱和) | 1.REG_SRCSCAL缩放过度或不足。2. BFLY_SCALING设置不当,导致中间级溢出或过度衰减。3. REG_DSTSCAL输出缩放配置错误。 | 1. 检查FFTCLIP寄存器,看是否有蝶形运算级发生饱和。2. 用已知幅度的单频信号测试,逐步调整 REG_SRCSCAL和BFLY_SCALING。3. 验证输出缩放逻辑,对于16位输出,确保 REG_DSTSCAL值合理(通常为2-6),避免有效信号被截断。 |
| 频谱中出现固定频率的杂散谱线 | 旋转因子量化噪声相关。 | 确保TWID_DITHER_EN已使能,并且LFSRSEED寄存器已初始化为一个非零值。 |
| 多通道处理时,通道间数据错乱 | SRCBINDX或DSTBINDX计算错误。 | 仔细计算通道间隔:样本数/通道 * 字节/样本 = 字节间隔/通道。确保输入和输出的REG_BCNT一致。 |
| 执行时间远超预期 | 状态机配置或触发逻辑问题。 | 1. 检查NLOOPS(状态机循环次数)和REG_BCNT(格式化器迭代次数)的区别。NLOOPS是参数集执行次数,REG_BCNT是单个参数集内数据块的处理次数。2. 确认触发信号是否正确连接和产生。 |
| 对数幅度结果不准确 | 核心计算单元中的对数近似算法(JPL Approx.)引入误差。 | 这是由硬件近似算法决定的固有误差。对于精度要求极高的场合,可能需要考虑在软件中做更精确的对数运算,或者接受此误差并在检测算法中加以补偿。 |
调试建议:
- 从小处着手:先用单通道、少点数(如64点)的简单正弦波信号进行测试,验证基础功能。
- 内存查看:充分利用调试工具,在加速器处理前后,分别导出源内存和目的内存的数据,与MATLAB或Python的计算结果进行逐点比对。
- 寄存器快照:在关键节点(如触发前、中断后)读取并记录所有相关配置寄存器和状态寄存器(如
STATERRCODE)的值。 - 利用可视化:将硬件输出的FFT结果绘制成频谱图,与理论频谱对比,可以快速发现增益、偏移、杂散等问题。
配置雷达硬件加速器是一个对细节要求极高的工作,每一个寄存器的值都影响着数据流的精确走向和最终结果的保真度。它就像指挥一个交响乐团,输入输出格式化器是管弦乐部,负责音符(数据)的进出和初步修饰;核心计算单元是打击乐和关键声部,负责核心旋律(算法)的演绎;而参数集就是乐谱,开发者就是指挥家。只有深刻理解每个“声部”的特性,才能编写出精准的“乐谱”,让硬件加速器奏出高性能雷达信号处理的完美乐章。