尝试结合STM32F401的ADC, PWM, SPI(NRF24L01)和TIM, 对音频的无线传输(对讲机原型)进行了测试
工作机制
音频采样
由于硬件的限制, 包括STM32F401片内存储, 内存大小, PWM频率, 以及之前的实际测试NRF24L01获得的经验数据, 采样采用最基本的8bit分辨率, 采样频率为16KHz附近
- SYSCLK使用25MHz, APB2CLK使用半频率, 即12.5MHz
- ADC在APB2CLK基于8分频, 所以ADC时钟为12.5MHz/8
- ADC使用8bit分辨率, 对应11个ADC时钟, 采样周期为84, 所以每次采样95个ADC周期, 实际采样频率为 12500000 / 8 / 95 = 16,447 Hz, 接近16KHz
- 使用ADC2DMA, DMA使用一个32byte大小的uint8_t数组
无线传输
- 使用fastwrite机制, 也就是说,一直保持在头发状态, 只要FIFO TX队列未满就一直写, 满了就检查MAX_RT标志位, 如果位置被拉,再拉高CE重置发送状态
- 采样端使用DMA中断传输, 对应32个byte的DMA内存, 每次收集32个byte会触发中断, 此时调用NRF24L01进行发送
- 接收端使用IRQ中断接收, 创建一个128Byte接收数组, 循环写入. 每次收到中断,在里面写32个byte, 往后增长, 到右边界后,从0开始
音频输出
- 接收端也使用25MHz的SYSCLK
- 接收端启用PWM输出, 输出分辨率为8bit
- 接收端启用Prescaler=0, Period=1561的定时器TIM3, 该配置对应的频率是 25000000 / (0 1)(1561 1) = 16,005 Hz, 接近16KHz. (注: 这里的频率选择有一些问题, 比发送端频率略高, 这样才能保证持续发送, 播放不被接收打断)
- 每次定时器触发中断, 都会在128byte检查接收数组中是否有新数据, 有前进一格,此值修改PWM占空比, 无则跳过. 若已达到数组右边界,则返回数组0下标.
电路
输入端电路
输入端使用驻极体二极管S9014组成简单的放大电路.
输出端电路
先通过输出端RC低通滤波(R=20, C=10uF), 再使用PAM8403进行放大
项目代码
项目代码在Github: https://github.com/IOsetting/stm32f4-hal-projects/tree/main/Projects/WalkieTalkieDemo 可以使用Keil5 MDK打开和编译
测试记录
- 采样: 采样工作正常, 观察输出可以看到采样值的变化
- 传输: 距离测试仅10米, 出现MAX_RT标志的比例很小, 至少从16KHz采样, 32byte一个package从发送速率来看, 发送和接收都不是瓶颈. 当墙壁堵塞时,错误率显著上升
- 播放: 背景噪音大, 近距离时容易相互干扰. 播放效果差, 沙沙声明显. 加入低通滤波器后,可以听到人声, 但还是达不到"能听"的水平.
电路部分原型
电路部分原型
发送端
下一步
因为传输不是瓶颈, 因此,改进的主要方向是音质. 可能需要从几个方面进行调查:
- 播放方面. 这一块比较容易排查, 例如,使用单频音源输出, 使用预录音源输出, 评估使用量有多高PWM频率以及RC滤波参数可以达到可接受的播放效果
- 采样方面. 有示波器会很方便, 没有示波器, 只能通过ADC判断采样输出, 编写代码将数组输出到存储中, 需要添加一些片外存储