☰
5G小基站PHY SPI接口:MAC与PHY对话规则与实战避坑
2026/10/20 18:10:13 网站建设 项目流程

简介:SCF222_5G-FAPI_PHY_SPI_Specification.pdf 是Small Cell Forum正式发布的5G小基站物理层接口规范,主要面向小基站基带算法开发、协议栈集成、射频前传联调及通信标准研究的工程师,旨在统一FAPI(前传应用编程接口)PHY层在SPI规范下的接口定义、消息交互与参数配置流程,解决不同厂商基带与射频单元之间集成适配难、互联互通成本高的问题。这份规范为单文件PDF文档,压缩包整体约2.36MB,对应Small Cell Forum Release 10.0(2020年3月)版本,内容覆盖FAPI接口的功能模型、消息交互流程、参数配置结构以及5G NR物理通道相关定义,既可作为软件架构设计时的接口参考,也可作为驱动开发、联调测试和问题定位的权威依据。已有1438人学习下载。文档源自SCF正式发布程序,适合5G小基站产品研发、FAPI接口开发、PHY层协议测试等岗位的工程师系统研读;对理解小基站开放接口体系、降低多厂商设备集成门槛、提升产品互操作能力具有直接的工程参考价值。

1. 拿到 SCF222 PDF 之后:5G 小基站 PHY SPI 到底在解决什么

某开发者第一次接触 5G 小基站协议栈时,被 PHY 厂商的对接文档折腾了整整一周:MAC 层明明按时把下行调度发下去了,PHY 侧却总是说“时隙对不上”,最后才发现双方对“提前几个时隙下发”的约定完全不一样。SCF222_5G-FAPI_PHY_SPI_Specification.pdf 这份规范,解决的就是这类问题——它定义了 5G 小基站里 MAC 层与 PHY 层之间的接口消息集合,把小区配置、时隙调度、上行反馈、测量上报这些交互方式固化成一套标准“对话协议”。理解它之后,无论你的 PHY 是自研代码、第三方 IP 还是黑盒加速器,上层逻辑都能按同一套思路对接,不用再猜对方怎么想。适合读这篇文章的人,是做协议栈、基带/DSP、仿真验证的工程师,以及刚进入小基站方向想搞清楚 L2 与 PHY 边界的新人。

2. PHY SPI 的角色定位:不写物理层算法,只写 MAC 和 PHY 的“对话规则”

2.1 在 FAPI 接口族里,PHY SPI 站在哪一层

小基站标准化组织定义的 FAPI 并不是一个单一接口,而是一族接口的统称。按层次拆分大致有:P1 负责核心网与高层之间,P2 是 PHY 往上层方向的上报通道,P3 是上层往 PHY 方向的下发通道,P4 是 PHY 内部多个处理节点之间的连接,P5 则是 PHY 与射频前端之间的采样接口。SCF222 对应的 PHY SPI,是 5G NR 时代把 P2/P3 职责整合后的完整定义,它关心的粒度是时隙和符号,而不是 IQ 采样点。

很多人容易把 PHY SPI 和 P5 搞混。P5 上跑的是采样率和 IQ 数据,解决的是“射频怎么把信号交给基带”;而 PHY SPI 上跑的是调度指令和结果上报,解决的是“MAC 怎么指挥 PHY 在哪个时隙做什么”。一个在数字前端,一个在协议栈内部,层次完全不同。做集成时如果拿 P5 的思路去理解 PHY SPI,很容易在消息时序上翻车。

为什么需要这样一层标准化接口?因为小基站产品里 MAC 和 PHY 往往不是同一个团队交付的,甚至 PHY 是外购的黑盒。如果没有统一接口,交接边界就模糊:MAC 侧不知道 PHY 需要多长的处理时间,PHY 侧不知道 MAC 什么时候给调度最合理。PHY SPI 存在的意义,就是把所有交互都收敛成显式的消息,双方只需要保证“消息格式一致、时序符合规范”,就能完成集成。

2.2 三类消息:配置、控制、数据

从用途上区分,PHY SPI 消息大体分成三类。配置类消息负责一次性或低频的参数设置,比如小区级参数、载波参数、波束配置,通常在小区建立阶段下发,之后很少变动。控制类消息负责每个时隙的调度与反馈,下行有调度请求、上行有调度请求、时隙指示、CRC 结果等,这类消息频率最高,是整个接口的主体。数据类消息负责承载传输块、HARQ 相关的数据内容,往往与控制消息成对出现。

工程实现上,常见做法是定义统一的消息结构体,用消息 ID 区分类型,用环形缓冲或信号量做传输。下面是一个简化到可写工程代码的结构:

typedef struct { uint32_t msg_id; /* 消息类型,如 DL_TTI_REQ / UL_TTI_REQ */ uint16_t sfn; /* 系统帧号,0~1023 */ uint16_t slot; /* 时隙号,由子载波间隔决定范围 */ uint32_t flags; /* 保留位或错误标志 */ union { config_req_t config; /* 配置类消息体 */ dl_tti_req_t dl_tti; /* 下行调度消息体 */ ul_tti_req_t ul_tti; /* 上行调度消息体 */ } body; } fapi_msg_t;

这段代码的逻辑是:MAC 侧填充sfn/slot和对应消息体,通过接口发给 PHY;PHY 侧拿到消息后先看msg_id,再决定走哪条处理分支。这里sfn/slot是最关键的两个字段,PHY 必须依据它们做时分对齐,否则整个调度节奏都会乱掉。参数说明:sfn取值范围与 LTE/NR 一样是 0~1023;slot的范围取决于子载波间隔,30 kHz 下每帧 20 个时隙,取值范围就是 0~19。msg_id的枚举值必须与规范中的编号保持一致,不同版本之间可能会有差异,建议做成独立的头文件统一管理,不要散落在代码里。

实际对接中,最常见的低级错误就是msg_id枚举值两边各写了一份,结果消息到了 PHY 侧全被当成未知类型丢弃。这类问题排错时很难一眼看出来,因为链路本身是通的,只是消息全被“吞”了。

2.3 PHY SPI 标准化带来的三个实际收益

第一个收益是可替换性。MAC 侧按标准消息驱动 PHY,那么换一家 PHY 供应商时,改动被限制在适配层,调度器逻辑基本不用动。第二个收益是可仿真性。在没有真实基带硬件时,可以把 PHY 替换成一个软件模型,模型只负责按规范回消息,MAC 侧代码就能在 x86 环境跑起来做功能验证。第三个收益是可测试性。因为消息格式统一,接口上的日志可以规格化打印,对照规范就能判断实现是否符合预期,联调效率比私有接口高很多。

当然,标准化也有代价。接口本身有封装损耗,每条消息都要带头部和校验信息,对实时性要求极高的场景需要仔细设计传输机制。但从产品集成角度看,这点损耗换来的边界清晰非常值得。如果你正在做的是私有 PHY 和自己写的 MAC,或许会觉得这套接口是多余的;一旦加入第三方组件或需要外场联调,就会理解为什么要提前按规范约束好。

3. 跑通 PHY SPI 的最小流程:从小区配置到逐时隙调度

3.1 开机三步:能力查询、小区配置、时隙指示

一个小区从启动到正常调度,PHY SPI 上至少要经历三步。第一步是能力查询,MAC 发参数请求,PHY 回能力参数,告诉上层自己支持哪些 numerology、最大带宽、处理延迟等。第二步是小区配置,MAC 下发完整的小区级配置,PHY 配置成功后回复确认,双方进入“已配置”状态。第三步才是时隙级的调度交互,PHY 在每个时隙产生指示,MAC 根据指示下发对应的调度请求。

常见做法是:能力查询只在启动时做一次,结果缓存在 MAC 侧;小区配置在建立小区时做;而时隙指示和调度请求则是持续运行的核心循环。小区配置这一步特别值得注意,PHY 返回的确认里往往带有处理延迟参数,这个值要保存下来并传给调度器,后面所有时隙的提前量都靠它计算。如果这里漏了,后续调度时序大概率对不齐。

提示:能力查询和小区配置阶段的消息都是低频的,排错相对容易;真正难查的时序问题几乎都出在第三步,也就是时隙级调度阶段。

3.2 下行调度闭环:DL_TTI.request 与 CRC.indication

下行调度是一个典型的请求-反馈闭环。MAC 提前若干时隙把下行调度请求发给 PHY,PHY 在指定时隙把 PDSCH/PDCCH 发下去,完成空口发送后再做 CRC 校验,最后通过 CRC 指示消息把结果上报给 MAC。MAC 根据这个结果决定是新传还是重传。

过程中的关键节点可以用表格概括:

阶段消息方向关键内容
调度准备下行调度请求MAC → PHY时隙号、PDSCH 资源、调制编码方式
空口发送下行链路PHY → UE传输块、HARQ 进程号、冗余版本
结果上报CRC 指示PHY → MAC时隙号、HARQ 进程号、CRC 结果

MAC 侧需要一个状态机来跟踪每个 HARQ 进程。下发调度请求时记录发送状态,收到 CRC 指示后更新进程状态,如果是 NACK 则安排重传。这里很容易忽略的一点是:CRC 指示消息里的时隙号必须与调度请求里的一致,不能拿当前时隙去判断,否则重传逻辑会出错。代码上可以用这样的结构管理:

typedef struct { uint16_t sfn; uint16_t slot; uint8_t harq_id; uint8_t status; /* 0=空闲, 1=已调度, 2=已反馈 */ } harq_proc_t; harq_proc_t proc[16]; void on_crc_ind(uint16_t sfn, uint16_t slot, uint8_t harq_id, uint8_t crc_ok) { proc[harq_id].status = 2; if (!crc_ok) { /* 安排重传,重传时仍使用原 sfn/slot 对应的资源 */ } }

这个片段展示的是 HARQ 进程收到反馈后的处理逻辑:先标记进程状态为已反馈,再根据 CRC 结果决定是否重传。关键点在注释里:重传时要回溯到原始调度的时隙号,而不是用当前时隙,因为 PHY 上报时携带的时隙信息才是那次空口传输的真实位置。参数说明:harq_id是上下行各自独立的进程号,下行 HARQ 进程数一般 8 到 16 个,取决于 UE 能力和基站配置;status这个状态位是避免重复反馈覆盖前一次结果的简单手段,实际工程里还要加超时保护。

3.3 上行调度闭环:UL_TTI.request、UCI.indication 与数据接收

上行调度与下行不同,它先由 MAC 发送上行调度请求,配置 PHY 在指定时隙做接收,然后 UE 在空口发送,PHY 解调后把数据以及测量结果一起上报。这里的反馈通道主要是 UCI 指示消息,里面携带 HARQ-ACK、CSI、SR 等信息,MAC 拿到后更新链路自适应参数。

上行调度的时序更敏感,因为 UE 的发送受 TA(时间提前)控制,MAC 必须把 TA 值透传给 PHY。如果 TA 换算错误,PHY 接收窗和实际到达信号对不齐,解调性能会明显下降。这个现象在室内小基站场景特别明显:小区覆盖小、信号强,CRC 却频繁出错,查来查去最后发现是 TA 参数量纲没对齐。

上行数据接收还有一个细节:PHY 解调出传输块后,可能需要通过数据消息把完整的数据内容交给 MAC,而不是像下行那样只上报 CRC。因此在实现上,上行链路除了处理 UCI 指示,还要维护数据缓冲区的生命周期,防止 PHY 写入的数据在 MAC 还没来得及读取时被覆盖。

3.4 SLOT 指示为什么不能省:时隙对齐是调度器命门

PHY 在每个时隙开始时会产生 SLOT 指示消息,本质上是告诉 MAC“新的时隙开始了”。很多 MAC 实现会用这条消息作为调度器的时间基准,在指示到达后触发下一轮调度计算。也有实现不用它,完全靠内部定时器驱动,但这要求两个模块的时钟严格同步,工程上容易出偏差。

有了 SLOT 指示,至少可以在 MAC 侧做一层保护:收到指示时校验当前期望的时隙号,发现不连续就打印告警。这种校验成本很低,但对定位时隙错位极有帮助。比如下面的判断逻辑:

static int slot_expect(uint16_t cur_sfn, uint16_t cur_slot, uint16_t *next_slot) { if (cur_slot + 1 >= slots_per_frame) { *next_slot = 0; return (cur_sfn + 1) & 0x3FF; /* sfn 回绕处理 */ } *next_slot = cur_slot + 1; return cur_sfn; }

这段代码解决的是 sfn/slot 递推中的边界问题:时隙号到帧尾时需要进位,系统帧号到 1023 后要回绕到 0。很多对接问题恰恰发生在 sfn 回绕的那一刻——MAC 侧还在用 1023 的帧号,PHY 侧已经切到 0,两边差了一整帧。参数说明:slots_per_frame由子载波间隔决定,30 kHz 时为 20;& 0x3FF是因为 NR 系统帧号就是 10 bit。这个函数建议放在通用工具模块里,MAC 和 PHY 复用同一份实现,避免各写一遍导致规则不一致。

4. 关键参数从哪里来:把规范字段映射到调度器的四个重点

4.1 numerology、带宽与 pointA:配置错一步,接入就卡住

PHY SPI 配置消息里第一组关键参数是载波相关的:子载波间隔、带宽、pointA。pointA 是公共资源块的参考点,所有资源分配都围绕它计算。配置错误时症状往往很隐蔽——基站自己觉得自己配置正常,但 UE 侧无法完成初始接入,或者接入后频域资源完全错位。

常见做法是在 MAC 侧维护一个载波配置结构,字段直接对应规范里的定义。以 30 kHz 子载波间隔、100 MHz 带宽为例:

carrier_cfg_t cfg = { .scs = 30, /* kHz,对应 numerology 1 */ .bw = 100, /* MHz,决定 RB 总数 */ .pointA = arfcn_from_ssb(ssb_freq), /* 由 SSB 频点查 ARFCN 表得到 */ .offset = 0, /* pointA 与资源块的偏移 */ };

逻辑说明:arfcn_from_ssb是一个换算函数,把 SSB 的绝对频点换算成规范的 ARFCN 数值,不能直接把 MHz 频率填进去。这也是最常见的错误:把 3.5 GHz 频点直接写成 3500000000 填进 pointA,PHY 侧按照规范单位解析后完全混乱。参数说明:scs决定时隙长度和每帧时隙数;bw决定可用 RB 数,100 MHz 在 30 kHz 子载波间隔下约 273 个 RB;pointA的单位是 ARFCN,和频点不是一个量纲。这部分务必在接口适配层做一次统一换算,并加单元测试覆盖。

4.2 时隙格式与 TDD 上下行比例:调度方向必须和 PHY 一致

5G 小基站绝大多数跑 TDD,每个时隙是下行、上行还是保护间隔,由时隙格式决定。PHY SPI 的下行调度请求和上行调度请求里都会带方向信息,MAC 必须保证发出去的方向和 PHY 侧配置的时隙格式一致,否则 PHY 可能直接丢弃消息。

工程上常见做法是配置一张时隙格式表,按每帧 20 个时隙循环使用。代码里可以这样组织:

/* 0=DL, 1=UL, 2=GP,按 DDDSU 比例配置一帧 */ static const uint8_t slot_fmt[20] = { 0,0,0,0,1, 0,0,0,0,1, 0,0,0,0,1, 0,0,0,0,1 }; uint8_t get_slot_direction(uint16_t sfn, uint16_t slot) { return slot_fmt[slot % 20]; }

逻辑说明:MAC 调度器在每个时隙计算方向时,直接查表拿到 DL/UL 指示,然后决定发哪种调度请求。这张表必须和小区配置阶段下发给 PHY 的时隙配置完全一致,否则会出现 MAC 发下行调度、PHY 认为该时隙是上行的情况。参数说明:示例里用的是 4 下行 1 上行的常见室内配置,实际比例根据业务模型调整;关键是把表做成唯一的配置源,MAC 和 PHY 适配层都从这个表取方向,不要各维护一份。

4.3 处理延迟与提前量:PHY 不是即时执行的

很多第一次对接的人默认 PHY 收到调度请求后能在同一时隙执行,这是最大的误解。PHY 从收到消息到完成基带处理、形成发射信号,需要固定的处理时间,这个时间在 PHY SPI 里通过参数告诉 MAC。MAC 调度器必须“往前看 N 个时隙”:计算第 K 个时隙的资源时,提前 N 个时隙把调度请求发出去。

N 的取值会直接影响空口性能。N 太小,PHY 来不及准备,时隙直接空发;N 太大,调度周期拉长,链路自适应响应变慢。我一般会把这个值做成可配置项,先按 PHY 供应商提供的典型值起步,然后通过压力测试观察空口吞吐和误码率做微调。如果你拿到的 PHY 是黑盒,可以做一个简单的试验:把提前量从 2 逐步加到 8,观察 CRC 错误率的变化曲线,稳定且最低的点就是当前负载下的合理值。

这里还要注意一个细节:提前量不是所有消息都相同。小区配置等低频消息没有严格提前量要求,但调度请求必须严格遵守。代码实现时,建议把提前量作为调度器构造参数传入,而不是到处硬编码。

4.4 参数单位与换算:symbol、RB、ARFCN 别再自己拍脑袋

PHY SPI 对接中一半以上的参数错误都和单位有关。规范里的字段单位往往不是直觉上的 Hz、秒,而是约定好的抽象单位,比如频率用 ARFCN、时间用符号或时隙、资源用 RB。这一节值得单独梳理一张常用换算表:

参数规范字段常见单位易错点
频点ARFCN直接用 Hz 填入会差几个数量级
时隙提前量时隙或符号数混用这两者会导致提前量错一截
资源分配RB 编号和 OFDM 子载波编号混用
TA 时间提前符号或采样点直接从 RRC 层拿数值不换算就透传

每遇到一个新字段,先确认单位再写代码。实在不确定时,可以查一下规范里的定义说明,或者在适配层打日志对比 PHY 侧的解析结果。宁可多花十分钟确认单位,也不要等上了外场再排查这种低级错误。

5. 对接避坑:PHY SPI 落地最容易踩的五个雷

5.1 现象:定时调度偶发丢失,PHY 侧找不到目标时隙

**现象:**系统跑起来大部分时间正常,但不定什么时候 PHY 侧日志会报“未找到对应时隙”,该时隙的下行数据直接丢失;重跑同样的调度序列,又不一定能复现。

**原因:**MAC 侧提前量计算用的是本地时钟,PHY 侧按自己的时隙计数对齐,两边的 sfn/slot 不一致。最常见的是 sfn 回绕时 MAC 没有处理进位,导致整帧错位。

**解决:**把 sfn/slot 递推逻辑收敛到同一个工具函数,MAC 和 PHY 共用;在接口日志里对每个调度请求打点,记录 sfn、slot、消息时间戳,对齐后就能看到错位发生在哪个边界。我接手过的项目里,这一条占时隙类问题的一半以上。

5.2 现象:上行 CRC 频繁报错,但下行链路正常

**现象:**下行吞吐正常,上行吞吐上不去,PHY 上报的 CRC 错误率异常高;射频指标检查过是正常的,UE 信号也够强。

**原因:**上行调度请求里的 TA 或时域资源位置配置错误,PHY 的接收窗和实际信号到达时间对不齐。另一个常见原因是上行调度请求提前量没有单独配置,直接沿用了下行的提前量。

**解决:**确认 TA 的单位和换算关系,在适配层统一换算;给上行调度单独配置提前量参数。排查时让 UE 静止在近点位置,排除频偏和多径干扰,集中验证 TA 字段。

5.3 现象:RACH 一直检测不到 preamble

**现象:**UE 在小区搜索阶段能读到 SSB,但发随机接入前导后基站侧一直没有响应,PHY 日志里看不到 RACH 检测结果。

**原因:**RACH 配置消息里的频域起始位置没有正确映射到 pointA,或者 preamble 格式与小区配置不一致,PHY 在错误的资源位置做检测。

**解决:**先在配置层做一致性检查,确认 RACH 频域位置、preamble 格式、接收窗口三者匹配;再抓 PHY 侧的检测日志,确认检测窗是否落在预期时隙内。这种问题通常不会是射频原因,别把时间浪费在天线和馈线上。

5.4 现象:改大带宽后速率不升反降

**现象:**从 20 MHz 带宽切到 100 MHz,峰值吞吐反而下降,PHY 侧频繁报资源分配出错。

**原因:**调度器还在按旧带宽的 RB 数做资源分配,而 PDSCH 资源指示按新带宽的 RB 编号下发,两边位图长度不匹配,PHY 解析越界。

**解决:**带宽参数只影响载波配置,调度器还必须同步更新自己的资源池信息,包括 RB 总数、资源位图长度、PDCCH 可用资源。改配置后加断言:调度的 RB 范围和带宽配置必须一致,不一致直接报错而不是静默处理。

5.5 现象:消息内容偶发损坏,解析结果前后不一致

**现象:**PHY SPI 消息在传输过程中极少出现乱码,一旦出现,PHY 侧解析出的参数明显不合理,但传输层本身没有报错。

**原因:**消息结构体没有按紧凑方式定义,发送方和接收方编译器对结构体做了不同对齐,导致字段偏移不一致。这个坑在自己 GCC 版本不一致、或者一端是 DSP 编译器一端是 ARM 编译器时特别容易踩。

**解决:**结构体定义加紧凑对齐指令,并在头文件里用静态断言检查结构体大小,两端编译时一旦大小不一致立即报错。别只靠代码审查,编译器差异造成的偏移问题是肉眼很难看出来的。

6. 验证技巧:用双端日志对齐 PHY SPI 时隙错位

做 PHY SPI 联调时,我最依赖的验证手段是“双端日志对齐”。原理不复杂:MAC 侧和 PHY 侧各自在消息入口打印日志,记录(sfn, slot, 消息名, 时间戳),跑完一段场景后把两份日志按(sfn, slot)做关联对比,任何时隙层面的错位都会立刻现形。关键是日志里要有绝对参考点:每个系统帧的第一个时隙打一条特殊标记(比如FRAME_START),这样两边日志对齐时有锚点,不会因为只比较相对序号而错开一帧都发现不了。

写一个简单的解析脚本就能做这件事:

import re mac_events = {} for line in open("mac.log"): m = re.search(r"\[(\d+),(\d+)\] (\w+)", line) if m: key = (int(m.group(1)), int(m.group(2))) mac_events.setdefault(key, []).append(m.group(3)) for line in open("phy.log"): m = re.search(r"\[(\d+),(\d+)\] (\w+)", line) if m: key = (int(m.group(1)), int(m.group(2))) if key not in mac_events: print(f"PHY-only event at {key}: {m.group(3)}")

逻辑说明:这个脚本只做最基础的一步——把 PHY 侧出现的(sfn, slot)拿去向 MAC 侧查有没有对应记录,如果查不到,说明该时隙两边没有对上。实际使用时可以扩展成对同一时隙的所有消息做列表对比,看顺序是否一致、有没有漏消息。参数说明:日志正则里的(\w+)抓消息名,(\d+),(\d+)抓 sfn 和 slot;如果日志时间戳包含毫秒,还可以在对比时增加时间差统计,超过阈值自动告警。

把这个技巧和其他办法配合会更好用:跑固定场景前,先清空两边日志缓冲;结束时先看FRAME_START的数量是否一致,再逐帧对齐;发现偏差后,回到调度器检查提前量配置。我最早做 PHY SPI 对接时,花了两天查一个偶发丢调度的问题,最后确认是 sfn 回绕那一帧两边差了一位,当时要是早点打FRAME_START标记,半小时就能定位。后来每做一轮联调,我都会先把这个日志链路铺好,再开始跑场景,这个习惯帮我少加了不少班,希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询