一、SAI 为什么放在 Multimedia 栏目?

SAI 的全称是 Serial Audio Interface(串行音频接口),是 ST 官方专为音频场景设计的高性能串行外设,它的原生定位就是连接数字麦克风、音频 Codec、DAC/ADC 等多媒体音频设备,原生支持 I2S、PCM、TDM 等主流音频传输协议STMicroelectronics。

TDM 本身就是多声道音频的标准传输方式(比如 8 声道、16 声道环绕声、麦克风阵列),所以 SAI 的 TDM 模式最初是为多声道音频采集设计的。只是因为它时序精准、同步性极强,才被拓展到加速度计、IMU 等需要多芯片同步采样的传感器场景。

CubeMX 是按外设的设计定位分类,因此 SAI 被归在 Multimedia(多媒体)分组下,而非普通通信外设(SPI/I2C)。

二、SAI1 和 SAI2 的区别

STM32L476 集成了两个完全独立的 SAI 外设,二者功能、性能、支持的最大时隙数完全一致,没有规格差异:

  • 每个 SAI 都包含 Block A 和 Block B 两个独立子块,每个子块可单独配置为主机 / 从机、发送 / 接收,互不干扰;
  • 每个子块最多支持 16 个时隙(Slot),单条 TDM 总线最多可接 16 颗芯片;
  • 二者唯一区别是IO 引脚位置不同、时钟源可独立配置,适合需要两路独立 TDM 总线的场景(比如两排独立的传感器阵列)。

采集加速度计一般只用一个 SAI 的一个 Block 就足够了。


三、STM32CubeMX TDM 模式完整配置步骤(加速度计采集场景)

我们以最常用的场景为例:SAI1 Block A 作为主机接收,4 颗加速度计共享一条 TDM 总线,单时隙 32 位,一步步完成配置。

1. 时钟树配置(同步稳定的核心)

SAI 的时钟精度直接决定 TDM 数据是否错位,L476 的 SAI 推荐使用独立的 PLLSAI1 作为时钟源,不受系统时钟波动影响:

  1. 进入 Clock Configuration 页面;
  2. 勾选启用 PLLSAI1,时钟源建议选外部高速晶振 HSE,配置分频系数,使输出频率能分频得到你需要的位时钟(BCLK)。
    • 计算公式:BCLK频率 = 采样率 × 每帧总位数
    • 举例:4 颗芯片,每颗 32 位,采样率 10kHz → 每帧 128 位 → BCLK = 10kHz × 128 = 1.28MHz
  3. 在下方时钟映射中,将 SAI1 Clock Source 选择为 PLLSAI1
2. 启用 SAI 外设,设置基础模式
  1. 回到 Pinout & Configuration 页面,在左侧 Multimedia 分类下点开 SAI1
  2. 勾选 SAI1 Block A,模式选择 Master Receive(主机接收:MCU 生成 BCLK 和帧同步信号,接收传感器数据);
  3. Audio Protocol 选择 Free Protocol(自由协议)。

    说明:CubeMX 里没有单独的 “TDM” 选项,TDM 是通过自定义帧结构 + 时隙参数实现的,Free Protocol 就是用来配置自定义 TDM/PCM 协议的模式STMicroelectronics。

3. 配置 TDM 核心参数(必须和加速度计时序完全匹配)

Parameter Settings 面板,分三部分配置:

(1)基础传输参数
  • Data Size:单路有效数据位宽,根据加速度计规格选择,常用 16Bit32Bit
  • First Bit:默认 MSB First(高位先行,绝大多数传感器都是此标准);
  • Clock Strobing:时钟采样边沿,需和加速度计输出边沿匹配。通常传感器在下降沿输出数据,MCU 选 Rising Edge 上升沿采样。
(2)帧结构配置(Frame)
  • Frame Length:一帧的总位数 = 时隙数量 × 单个时隙位宽。 例:4 个时隙,每个时隙 32 位 → 填 128
  • Sync Definition:选 Start Of Frame(帧同步脉冲表示新一帧开始);
  • Sync Polarity:帧同步极性,高有效或低有效,和传感器一致即可;
  • Sync Width:同步脉冲宽度,标准 TDM 常用 1 Bit(1 个 BCLK 周期的脉冲)。
(3)时隙配置(Slot)—— 区分不同芯片的核心
  • Slot Size:单个时隙的位宽,必须≥Data Size,常用 32Bit
  • Number of Slot:一帧内的时隙总数,等于你接的加速度计数量,比如 4 颗就填 4
  • Slot Active:激活时隙掩码(16 进制),标记哪些时隙有效。 例:4 颗芯片用前 4 个时隙 → 填 0x000F;8 颗就是 0x00FF
4. GPIO 与 DMA 配置
  1. 引脚确认:CubeMX 会自动分配 SAI 功能引脚,确认 3 根关键信号线:

    • SAI1_SCK_A:位时钟 BCLK
    • SAI1_FS_A:帧同步 FS
    • SAI1_SD_A:串行数据输入 SD 如有引脚冲突,手动切换到其他复用引脚即可(L476 的 SAI 一般复用为 AF13)。
  2. DMA 配置(必配):TDM 是连续流式传输,必须用 DMA 搬运,否则会丢数据:

    • 左侧 System CoreDMA → 点击 Add
    • 选择 SAI1_A 通道,方向 Peripheral To Memory
    • 模式选 Circular(循环模式,实现连续采集);
    • 数据宽度:外设和内存都选 Word(32 位时隙),16 位则选 Half Word;
    • 优先级设为 High,保证数据及时搬运。
5. 生成工程

所有参数确认无误后,直接生成 Keil/IAR 工程,CubeMX 会自动生成 SAI 和 DMA 的初始化代码。


四、加速度计对接与代码实现要点

1. 传感器端预配置(对应 I2C 的 SA0 地址功能)

TDM 总线本身没有寻址机制,所有加速度计的时隙号必须提前单独配置

  • 绝大多数支持 TDM 的加速度计,都需要先通过 SPI/I2C 接口写入寄存器,设置自身的 TDM 时隙编号、输出位宽、时钟边沿等参数;
  • 必须保证总线上所有芯片的时隙号不重复,且和 MCU 端的 Slot 顺序一一对应,否则会出现总线冲突或数据串路。
2. 启动 TDM 采集

初始化完成后,调用 HAL 库函数启动 DMA 循环接收:

// 接收缓冲区:4个时隙,每个32位,双缓冲结构
uint32_t tdm_rx_buf[4 * 2];  

// 启动SAI DMA循环接收
HAL_SAI_Receive_DMA(&hsai_BlockA1, (uint8_t*)tdm_rx_buf, 4);
3. 按时隙拆分数据(区分不同芯片)

在 DMA 接收完成回调中,按数组位置直接对应到每颗芯片:

void HAL_SAI_RxCpltCallback(SAI_HandleTypeDef *hsai)
{
    // tdm_rx_buf[0] → 第1颗加速度计(时隙0)
    // tdm_rx_buf[1] → 第2颗加速度计(时隙1)
    // tdm_rx_buf[2] → 第3颗加速度计(时隙2)
    // tdm_rx_buf[3] → 第4颗加速度计(时隙3)
    
    // 在此处解析每一路的加速度原始数据
}

五、常见踩坑提醒

  1. 时序对齐是生命线:帧同步极性、位时钟采样边沿、帧长度三个参数,只要有一个和传感器不匹配,数据就会全部错位,所有通道串数;
  2. 时隙大小≥数据大小:如果传感器输出 24 位数据,时隙建议设为 32 位,注意数据左对齐 / 右对齐的匹配;
  3. 先配置传感器,再启动 SAI:必须等所有传感器的 TDM 参数配置完成后,再启动 MCU 的 SAI 接收,避免第一帧就错位;
  4. 空闲时隙必须高阻:确保加速度计在非自身时隙时输出高阻,否则会出现总线冲突,后果和 I2C 地址重复一致。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐