PUYA I2S — 主机轮询收发(双板)

PUYA PY32F403_Firmware V1.4.5 I2S 主机轮询收发(I2S_TwoBoard_CommunicationMaster_Polling)示例教学

I2S — 主机轮询收发(双板)

固件库: PY32F403_Firmware V1.4.5
芯片: PY32F403
源文件: PUYA/PY32F403_Firmware_V1.4.5/Projects/PY32F403-STK/Example/I2S/I2S_TwoBoard_CommunicationMaster_Polling/Src/main.c


功能简介

I2S(Inter-IC Sound)是专为数字音频设计的同步串行总线,三线(SCK 位时钟、WS 声道选择、SD 数据)+ 可选 MCLK 主时钟,常用于连接音频 DAC/ADC、CODEC、MEMS 麦克风。

PY32F403 的 SPI2 外设可复用为 I2S。本示例演示主机(Master)轮询收发:

  • 先配置为 I2S_MODE_MASTER_TX,发送 16 个 16 位样本;
  • 再切换为 I2S_MODE_MASTER_RX,接收 16 个样本;
  • 轮询等待每步完成,最后比较收发数据;
  • 一致则点亮绿灯,不一致则闪烁报警。

I2S 与 SPI 分时复用同一组引脚,区别在 HAL_I2S_Init 时选 I2S_* 模式而非 SPI_*

硬件准备

  • 两块 PY32F403 开发板(一主一发/收,或一块自连回环)
  • 交叉连接 I2S 信号:主 SCK↔从 SCK,主 WS↔从 WS,主 SD↔从 SD(MOSI/MISO),共地
  • 板载 LED / 按键用于交互(示例需按键触发一次传输)

完整代码(主机部分)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include "main.h"

I2S_HandleTypeDef I2sHandle;
uint16_t TxBuff[16] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16};
uint16_t RxBuff[16] = {0};
#define DATA_LENGTH 16

int main(void)
{
  HAL_Init();
  APP_SystemClockConfig();         /* 系统时钟:HSI */
  BSP_LED_Init(LED_GREEN);
  BSP_PB_Init(BUTTON_KEY, BUTTON_MODE_GPIO);

  while (BSP_PB_GetState(BUTTON_KEY) == 1) {}  /* 等按键触发 */

  /* === 主机发送 === */
  I2sHandle.Instance        = SPI2;            /* I2S 复用 SPI2 */
  I2sHandle.Init.Mode       = I2S_MODE_MASTER_TX; /* 主机发送 */
  I2sHandle.Init.Standard   = I2S_STANDARD_PHILIPS; /* 飞利浦标准 */
  I2sHandle.Init.DataFormat = I2S_DATAFORMAT_16B;  /* 16 位数据 */
  I2sHandle.Init.MCLKOutput = I2S_MCLKOUTPUT_DISABLE;
  I2sHandle.Init.AudioFreq  = I2S_AUDIOFREQ_8K;    /* 8kHz 采样率 */
  I2sHandle.Init.CPOL       = I2S_CPOL_HIGH;       /* 时钟极性 */
  if (HAL_I2S_Init(&I2sHandle) != HAL_OK) APP_ErrorHandler();

  if (HAL_I2S_Transmit(&I2sHandle, (uint16_t*)TxBuff, DATA_LENGTH, 5000) != HAL_OK)
    APP_ErrorHandler();
  while (HAL_I2S_GetState(&I2sHandle) != HAL_I2S_STATE_READY) {}

  HAL_Delay(1);  /* 给从机一点准备时间 */

  /* === 主机接收 === */
  I2sHandle.Init.Mode = I2S_MODE_MASTER_RX;     /* 切换为主机接收 */
  if (HAL_I2S_Init(&I2sHandle) != HAL_OK) APP_ErrorHandler();

  if (HAL_I2S_Receive(&I2sHandle, (uint16_t*)RxBuff, DATA_LENGTH, 5000) != HAL_OK)
    APP_ErrorHandler();
  while (HAL_I2S_GetState(&I2sHandle) != HAL_I2S_STATE_READY) {}

  APP_CheckEndOfTransfer();   /* 比较收发,亮灯/闪烁 */
  while (1) {}
}

代码分段讲解

1. 标准与极性

  • I2S_STANDARD_PHILIPS:标准飞利浦格式(WS 在第二个时钟沿变化,SD 在 WS 变化后一位有效)。另有 MSB/LSB 对齐、PCM 等格式,按 CODEC 手册选。
  • CPOL:串行时钟空闲极性,必须与对端一致。

2. 采样率 AudioFreq

I2S_AUDIOFREQ_8K 决定 SCK/WS 频率。HAL 会根据系统时钟自动计算分频;常见值 8k/16k/44.1k/48k。实际可用频率受主时钟约束,复杂场景需打开 MCLK 并精确配置。

3. 主机切换发/收

同一 I2sHandle 重新 HAL_I2S_InitMode 即可在 TX/RX 间切换(本例用两块板对传,先发后收)。真实音频链路通常是固定方向:MCU 做发送端驱动 DAC,或做接收端读 ADC。

4. 轮询

HAL_I2S_Transmit/Receive(..., Timeout) 阻塞直到完成或超时,代码简单但占 CPU。大数据量/连续音频建议用 ITDMA 版(同目录有 _DMA / _IT)。

实验现象

  • 按键后主机发送 {1..16},再接收一帧;
  • 收发一致(回环或正确对接),绿灯常亮;不一致则绿灯 500ms 闪烁。

常见问题

  1. 没声音 / 收不到数据?

    • 确认 I2S 引脚(SCK/WS/SD)与 SPI2 复用引脚一致,且主从 Standard/CPOL/DataFormat/AudioFreq 完全相同。
    • 主从共地,接线交叉正确。
  2. 想连续播放音频?

    • HAL_I2S_Transmit_DMA + 双缓冲,从 Flash/SD 卡取 PCM 数据不断送 DAC(如 WM8978、MAX98357A)。
  3. 采样率不准/有杂音?

    • 检查系统时钟与 MCLK 配置;音频对时钟精度敏感,必要时开 MCLK 输出给 CODEC 作基准。

小结

  • I2S 配置要点:标准格式、数据位宽、声道极性 CPOL、采样率、主/从模式
  • SPI2 可复用为 I2S,引脚与 SPI 相同。
  • 轮询版适合教学;音频流用 DMA/中断。

拓展应用

  • 驱动 I2S DAC(MAX98357A)播放 WAV/提示音。
  • 读取 I2S MEMS 麦克风做录音/声控。
  • 接 CODEC(WM8978)做双向音频(通话/采集)。
  • DMA + 双缓冲实现不间断音频流。
世界是你们
使用 Hugo 构建
主题 StackJimmy 设计