1. 问题现象描述
最近在调试杰理平台的音频设备时,发现一个比较恼人的现象:当设备执行关机操作时,音频输出会出现明显的卡顿现象,音乐先断续卡几下,然后才完全关机。这种体验对于用户来说非常不友好,特别是在播放音乐时突然关机的情况。
这个现象在多个设备上都能复现,具体表现为:
- 按下关机键后,音频输出不会立即停止
- 先出现1-3次明显的卡顿(每次约0.5秒)
- 卡顿后系统才完全关机
- 整个过程持续约1.5-2秒
2. 问题根源分析
2.1 音频系统关机流程
要解决这个问题,首先需要理解杰理平台音频系统的关机流程。通过分析源代码和调试日志,发现关机流程大致如下:
- 用户触发关机信号
- 系统发送关机广播通知
- 音频子系统接收关机通知
- 音频驱动开始释放资源
- 停止DMA传输
- 关闭音频时钟
- 释放缓冲区
- 系统电源管理模块执行断电
2.2 卡顿产生的原因
通过逻辑分析和示波器测量,发现卡顿主要发生在第4步(音频驱动释放资源阶段)。具体原因包括:
- 资源释放顺序不当:音频DMA在时钟关闭前就被停止,导致残留数据无法完整传输
- 中断处理延迟:关机中断优先级设置不合理,导致音频中断被延迟处理
- 缓冲区清空不彻底:音频缓冲区还有数据未处理完就被强制清空
- 电源管理响应过快:音频子系统还未完全关闭,主电源就开始下降
3. 解决方案设计与实现
3.1 优化关机流程
重新设计了关机流程,关键修改点包括:
c复制// 修改后的音频关机流程
void audio_power_off_sequence(void) {
// 1. 先停止应用层音频播放
audio_app_stop_playback();
// 2. 等待当前音频帧完成(最多20ms)
audio_wait_frame_complete(20);
// 3. 停止DMA但保持时钟运行
audio_dma_stop();
// 4. 清空FIFO缓冲区
audio_flush_fifo();
// 5. 关闭音频时钟
audio_clock_disable();
// 6. 通知电源管理可以断电
power_mgmt_notify_audio_off();
}
3.2 关键参数调整
-
DMA缓冲区设置:
- 原配置:双缓冲,每缓冲512字节
- 新配置:三缓冲,每缓冲256字节
- 优点:更细粒度的控制,减少关机时的残留数据量
-
中断优先级调整:
c复制// 修改前 #define AUDIO_IRQ_PRIORITY 12 #define POWER_IRQ_PRIORITY 8 // 修改后 #define AUDIO_IRQ_PRIORITY 6 #define POWER_IRQ_PRIORITY 10 -
电源下降时序:
- 增加50ms延迟,确保音频系统完全关闭
- 修改电源管理配置寄存器:
c复制PMU->CTRL |= (1 << 5); // 增加音频电源保持位
4. 实际测试与验证
4.1 测试方法
- 使用示波器监测音频输出波形
- 通过逻辑分析仪捕捉关机信号时序
- 人工耳听感测试
- 自动化压力测试(连续开关机100次)
4.2 测试结果对比
| 测试项 | 修改前 | 修改后 |
|---|---|---|
| 关机卡顿次数 | 2-3次 | 0次 |
| 关机总耗时 | 1500-2000ms | 300-500ms |
| 电源下降毛刺 | 明显 | 基本消除 |
| 残留音频数据 | 约1KB | <100字节 |
5. 经验总结与注意事项
5.1 关键经验
- 关机时序的重要性:音频系统关机不是简单的断电,需要严格的时序控制
- DMA缓冲区的设计:多小缓冲区比少大缓冲区更适合快速关机场景
- 中断优先级的艺术:电源管理中断不应高于音频处理中断
5.2 常见问题排查
如果按照上述修改后仍出现卡顿,可以检查:
-
硬件方面:
- 电源滤波电容是否老化
- 音频晶振启动时间是否过长
-
软件方面:
- 是否有其他高优先级任务阻塞关机流程
- 音频驱动版本是否匹配
-
配置方面:
- 检查时钟树配置是否正确
- 确认DMA通道优先级设置
5.3 优化建议
-
可以增加关机前淡出效果,提升用户体验
c复制void audio_fade_out(void) { for(int vol=100; vol>=0; vol-=5) { audio_set_volume(vol); delay_ms(10); } } -
考虑增加关机超时保护机制,避免某些异常情况下无法关机
-
对于电池供电设备,可以动态调整关机速度(电量充足时慢关,低电量时快关)