第2章:基带处理器架构:ARM与DSP异构计算、硬件加速器(FFT/信道编解码)、内存层次结构

好,咱们直接进入正题。基带处理器,说白了就是手机或基站里那个专门处理通信信号的芯片。它不像CPU那样啥都干,而是专精于信号处理。我做了这么多年固件,最深的体会就是:搞懂基带架构,你写驱动时才知道哪些活该CPU干,哪些该甩给DSP,哪些直接交给硬件加速器。

2.1 ARM与DSP:一对黄金搭档

为什么基带里要用两种处理器?你想想看,通信协议栈分两层:上层是控制面,比如信令交互、资源调度,这些活儿逻辑复杂,但数据量不大。下层是数据面,比如信道估计、均衡、解调,这些活儿计算量大,但算法相对固定。

ARM擅长跑操作系统和复杂逻辑。我习惯把ARM比作项目经理,负责统筹协调。DSP则是个数学天才,专门做乘加运算。两者通过共享内存或硬件邮箱通信。

关键点:ARM跑Linux或RTOS,DSP跑裸机或轻量级实时内核。驱动开发时,你需要在ARM侧写一个DSP控制驱动,负责加载DSP固件、启动/停止DSP核、传递消息。

我在项目中遇到过一个问题:DSP跑飞了,ARM侧完全不知道。后来我加了个硬件看门狗,DSP每隔10ms给ARM发个心跳包。如果ARM连续3次没收到,就强制复位DSP。嗯,这个机制后来成了我们团队的标配。

2.2 硬件加速器:把算法烧进硅片

有些算法,比如FFT、维特比译码、Turbo译码,用DSP跑虽然能行,但功耗和延迟都扛不住。这时候就需要硬件加速器——说白了,就是把算法用逻辑电路固定下来。

2.4.1 FFT加速器

FFT是OFDM系统的核心。一个20MHz带宽的LTE信号,每秒要做上万次FFT。用DSP软算?延迟至少几十微秒。硬件加速器呢?几个时钟周期搞定。

驱动开发时,你只需要做三件事:

  1. 把时域数据写入加速器的输入FIFO
  2. 配置FFT点数(128/256/512/1024/2048)
  3. 启动加速器,然后从输出FIFO读频域数据

我的经验:配置寄存器时一定要检查忙标志位。我曾经在加速器还在处理上一帧数据时,就写了新配置,结果数据全乱了。后来我加了个轮询等待,虽然损失了一点性能,但稳定性大幅提升。

2.4.2 信道编解码加速器

Turbo码和LDPC码的译码,迭代次数多,计算量大。硬件加速器通常包含多个译码核,可以并行处理多个码块。

驱动接口一般长这样:

// 配置译码参数
turbodec_cfg_t cfg = {
    .block_len = 6144,    // 码块长度
    .iter_max  = 8,       // 最大迭代次数
    .mod_type  = QPSK,    // 调制方式
    .rate      = 1_3      // 码率 1/3
};

// 启动译码
turbodec_start(&cfg, input_buf, output_buf);

// 等待完成(中断或轮询)
while(!turbodec_is_done());

注意:硬件加速器通常有输入输出对齐要求。比如输入数据必须128字节对齐,否则DMA传输会出错。我踩过这个坑,调试了两天才发现是地址没对齐。

2.3 内存层次结构:谁快谁贵

基带芯片的内存,跟PC一样,也是金字塔结构。但区别在于,基带对实时性要求极高,延迟必须可预测。

层级 容量 延迟 用途
L1 Cache (ARM/DSP) 32KB - 64KB 1-2 cycles 指令/数据缓存
L2 Cache (共享) 256KB - 1MB 10-20 cycles 共享数据
内部SRAM 2MB - 8MB 30-50 cycles 基带帧缓冲
外部DDR 128MB - 1GB 100+ cycles 协议栈、日志

你可能会问:为什么不用大Cache?因为Cache的延迟不可预测——缓存命中时很快,未命中时很慢。基带处理要求确定性延迟,所以关键数据(比如接收到的IQ样本)必须放在SRAM里。

我建议在驱动初始化时,就把SRAM分区规划好:

  • 区域A:接收帧缓冲(DMA直接写入)
  • 区域B:发送帧缓冲(DMA直接读取)
  • 区域C:硬件加速器描述符环
  • 区域D:DSP固件代码段

避坑指南:我曾经把DSP的代码段放在DDR里,结果DSP启动时频繁取指失败。后来发现是DDR初始化时序没配好,DSP在DDR稳定前就开始跑了。解决方案:把DSP启动代码放在内部ROM里,等DDR稳定后再加载主程序。

2.4 异构计算的数据流

一个典型的接收链路是这样的:

  1. 天线收到射频信号,ADC转为数字IQ
  2. DMA直接把IQ数据写入SRAM区域A
  3. ARM配置FFT加速器,从区域A读数据,结果写入区域B
  4. DSP从区域B读频域数据,做信道估计和均衡
  5. ARM配置译码加速器,从区域C读软比特,结果写入区域D
  6. ARM从区域D读MAC PDU,交给协议栈

你看,整个流程里,ARM、DSP、硬件加速器各司其职,通过共享内存传递数据。驱动开发的核心,就是管理好这些数据通路和同步机制。

我个人习惯用环形缓冲区(ring buffer)来管理描述符。每个描述符指向一个数据块,包含状态位(空闲/忙/完成)。生产者(比如DMA)把数据写完后,把状态置为完成;消费者(比如DSP)轮询到完成状态后,开始处理。

小技巧:用内存屏障(memory barrier)保证顺序。ARM和DSP看到的缓存可能不一致,你需要在写状态位之前加一个写屏障,在读状态位之前加一个读屏障。否则,你可能会读到过时的数据。

2.5 总结与展望

基带处理器架构,说白了就是ARM管控制、DSP管算法、硬件加速器管重复劳动。内存层次结构决定了数据该放哪里。写驱动时,你心里要时刻想着:这个数据是给谁用的?延迟要求多高?能不能用Cache?

下一章,我们会深入DMA子系统,看看如何高效地在这些处理器和加速器之间搬运数据。嗯,那才是真正考验驱动工程师功底的地方。