Files
Docs/DevLogs/Day4.md
2025-12-31 16:18:28 +08:00

719 lines
20 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Avaota F1 开发日志 - Day 4模拟麦克风配置
**版本**v1.0
**日期**2025-11-26
**主机环境**Windows + Ubuntu 24.04 LTS
**目标平台**Avaota F1 (全志 V821 / 32-bit RISC-V)
---
## 项目背景
根据 Day 3 的计划,原定配置 PDM 数字麦克风DMIC以实现音频采集功能。但在实际开发中发现开发板使用的是**板载模拟麦克风**,通过芯片内部 Audio Codec 进行音频采集,而非独立的 PDM/DMIC 设备。
---
## 第一部分:硬件类型确认
### 1. 文档确认
查阅 [`MIC.md`](file:///d:/CodingProjects/Antigravity/AvaotaF1/MIC.md) 文档后确认:
**硬件配置**
- **麦克风类型**:模拟麦克风(板载)
- **接口**:通过芯片内部 Audio Codec
- **ALSA 设备名称**`hw:audiocodec``hw:0,0`
- **驱动**`audiocodec` (已内置于内核)
**关键区别**
| 项目 | 原计划 (PDM/DMIC) | 实际硬件 (模拟麦克风) |
|------|-------------------|----------------------|
| **接口** | PDM 数字信号 | 模拟信号 → ADC |
| **Device Tree** | 需配置 `&dmic` 节点 | 使用 `&codec` 节点 |
| **引脚配置** | 需 pinctrl 设置 | 无需额外引脚配置 |
| **ALSA 设备** | `hw:snddmic` | `hw:audiocodec` |
| **运行时配置** | 即插即用 | 需打开 MIC Switch |
**结论**:配置难度大幅降低,无需修改 Device Tree。
---
## 第二部分Device Tree 验证
### 1. 检查现有配置
查看 [`board.dts`](file:///d:/CodingProjects/Antigravity/AvaotaF1/board.dts) 第 759-797 行:
```dts
&codec {
tx-hub-en;
rx-sync-en;
dac-vol = <63>; /* DAC 音量 */
dacl-vol = <160>; /* DAC L 音量 */
adc-vol = <160>; /* ✅ ADC 音量(麦克风采集)*/
lineout-gain = <31>; /* LINEOUT 增益 */
mic-gain = <31>; /* ✅ 麦克风增益(最大值)*/
adcdelaytime = <0>; /* ADC 延迟时间 */
pa-pin-max = <1>;
pa-pin-0 = <&pio PC 15 GPIO_ACTIVE_HIGH>;
pa-pin-level-0 = <1>;
pa-pin-msleep-0 = <0>;
status = "okay"; /* ✅ 已启用 */
};
&codec_plat {
status = "okay";
};
&codec_mach {
status = "okay";
soundcard-mach,cpu {
sound-dai = <&codec_plat>;
};
soundcard-mach,codec {
sound-dai = <&codec>;
};
};
```
**验证结果**
-`&codec` 节点已启用(`status = "okay"`
-`mic-gain` 已设置为 31最大值
-`adc-vol` 已配置为 160
-**无需修改 Device Tree**
---
## 第三部分:测试脚本开发
### 1. 创建自动化测试脚本
为了简化测试流程,创建了 [`test_mic.sh`](file:///d:/CodingProjects/Antigravity/AvaotaF1/src/test_mic.sh) 脚本:
**功能**
1. 检查 ALSA 设备
2. 配置麦克风(打开 MIC Switch设置 Gain
3. 执行 5 秒录音测试
4. 播放录音验证
**关键命令**
```bash
# 打开 MIC 开关(必须)
amixer -Dhw:audiocodec cset name="MIC Switch" 1
# 设置 MIC 增益
amixer -Dhw:audiocodec cset name="MIC Gain" 15
# 录音测试
arecord -D hw:audiocodec -f S16_LE -t wav -r 16000 -c 1 -d 5 /tmp/test_mic.wav
# 播放验证(使用 I2S 扬声器)
aplay -D hw:1,0 /tmp/test_mic.wav
```
---
## 第四部分:开发板测试
### 1. ALSA 设备验证
在开发板上检查音频设备:
```bash
root@(none):/# cat /proc/asound/cards
0 [audiocodec ]: audiocodec - audiocodec
audiocodec
1 [sndi2s0 ]: sndi2s0 - sndi2s0
sndi2s0
```
**结果**audiocodec (card 0) 和 sndi2s0 (card 1) 都已正常识别。
```bash
root@(none):/# arecord -l
**** List of CAPTURE Hardware Devices ****
card 0: audiocodec [audiocodec], device 0: ...
```
**结果**audiocodec 录音设备已注册。
---
### 2. 麦克风配置测试
执行配置命令:
```bash
# 打开 MIC 开关
root@(none):/# amixer -Dhw:audiocodec cset name="MIC Switch" 1
numid=16,iface=MIXER,name='MIC Switch'
; type=BOOLEAN,access=rw------,values=1
: values=on
# 设置初始增益为 15
root@(none):/# amixer -Dhw:audiocodec cset name="MIC Gain" 15
numid=15,iface=MIXER,name='MIC Gain'
; type=INTEGER,access=rw---R--,values=1,min=0,max=31,step=0
: values=15
```
**结果**MIC Switch 已打开,增益设置成功。
---
### 3. 录音测试(第一次)
```bash
root@(none):/# arecord -D hw:audiocodec -f S16_LE -t wav -r 16000 -c 1 -d 5 /tmp/test.wav
Recording WAVE 'stdin' : Signed 16 bit Little Endian, Rate 16000 Hz, Mono
root@(none):/# ls -lh /tmp/test.wav
-rw-r--r-- 1 root root 160.0K Nov 26 15:32 test.wav
root@(none):/# aplay -D hw:1,0 /tmp/test.wav
Playing WAVE '/tmp/test.wav' : Signed 16 bit Little Endian, Rate 16000 Hz, Mono
```
**结果**
- 录音成功文件大小正常160KB ≈ 5 秒 @ 16kHz
- 播放时**有声音,听得清**
- **但声音很小**
---
### 4. 增益调优
**问题**MIC Gain 15 时音量较小
**方案**:逐步增加增益值
#### 测试 1MIC Gain = 25
```bash
root@(none):/# amixer -Dhw:audiocodec cset name="MIC Gain" 25
root@(none):/# arecord -D hw:audiocodec -f S16_LE -t wav -r 16000 -c 1 -d 5 /tmp/test2.wav
root@(none):/# aplay -D hw:1,0 /tmp/test2.wav
```
**结果**:音量适中,清晰度良好
#### 测试 2MIC Gain = 31 (最大值)
```bash
root@(none):/# amixer -Dhw:audiocodec cset name="MIC Gain" 31
root@(none):/# arecord -D hw:audiocodec -f S16_LE -t wav -r 16000 -c 1 -d 5 /tmp/test3.wav
root@(none):/# aplay -D hw:1,0 /tmp/test3.wav
```
**结果**:音量最大,但有轻微底噪
**最佳配置****MIC Gain = 25**
- 音量适中
- 音质清晰
- 无明显杂音
---
## 第五部分AudioCapture 集成
### 1. 验证设备名称
检查 [`test_audio.cpp`](file:///d:/CodingProjects/Antigravity/AvaotaF1/src/test_audio.cpp) 第 23 行:
```cpp
const char* DEVICE_NAME = "hw:0,0"; // audiocodec 是 card 0
```
**兼容性**
- `hw:0,0` 正确指向 audiocodec
- 也可以使用 `hw:audiocodec`(更明确)
---
### 2. 集成方案
在主程序 [`main.cpp`](file:///d:/CodingProjects/Antigravity/AvaotaF1/src/main.cpp) 的 `audio_capture_thread()` 中:
```cpp
void audio_capture_thread() {
LOG_INFO("Starting audio capture thread...");
// 1. 配置麦克风(打开 MIC 开关和增益)
system("amixer -Dhw:audiocodec cset name='MIC Switch' 1");
system("amixer -Dhw:audiocodec cset name='MIC Gain' 25");
// 2. 初始化音频采集
AudioCapture mic("hw:audiocodec", 16000, 1);
if (!mic.init()) {
LOG_ERROR("Failed to initialize microphone");
return;
}
// 3. 连接 WebSocket 服务器
WSClient ws_aud(SERVER_HOST, SERVER_PORT, "/ws_audio");
if (!ws_aud.connect()) {
LOG_ERROR("Failed to connect to audio WebSocket");
return;
}
// 4. 音频采集循环
int16_t buffer[320]; // 20ms @ 16kHz
while (g_running) {
snd_pcm_sframes_t frames = mic.read(buffer, 320);
if (frames > 0) {
// 发送音频数据到服务器
ws_aud.send_binary((uint8_t*)buffer, frames * 2);
}
}
LOG_INFO("Audio capture thread stopped");
}
```
**关键点**
- 使用 `system()` 调用 `amixer` 配置(简单直接)
- 或者可以使用 ALSA Mixer API更优雅
---
## 第六部分:技术总结
### 1. 关键发现
**硬件差异**
- 原计划PDM 数字麦克风DMIC
- 实际硬件模拟麦克风Audio Codec ADC
**配置方式**
- Device Tree✅ 已完整配置,无需修改
- 运行时:需通过 `amixer` 打开 MIC Switch
### 2. 配置要点
| 配置项 | 说明 | 推荐值 |
|--------|------|--------|
| **MIC Switch** | 麦克风开关 (必须打开) | `1` (on) |
| **MIC Gain** | 麦克风增益 (0-31) | `25` |
| **ADC Volume** | ADC 音量 (0-255) | `160` (默认) |
### 3. 音频参数
- **采样率**16000 Hz (16kHz)
- **位深度**16-bit signed PCM (S16_LE)
- **声道数**1 (Mono)
- **ALSA 设备**`hw:audiocodec``hw:0,0`
---
## 第七部分:问题与解决
### 问题 1音量太小
**现象**MIC Gain 15 时录音音量偏小
**原因**:初始增益设置过低
**解决**:增加 MIC Gain 到 25
### 问题 2增益过高有杂音
**现象**MIC Gain 31 时有轻微底噪
**原因**:增益过高放大了底噪
**解决**:降低到 25平衡音量和音质
---
## 🏆 Day 4 成果
### 核心成就
1.**确认硬件类型**:模拟麦克风(非 PDM/DMIC
2.**验证 Device Tree**audiocodec 已完整配置
3.**创建测试脚本**[`test_mic.sh`](file:///d:/CodingProjects/Antigravity/AvaotaF1/src/test_mic.sh)
4.**完成硬件测试**:录音功能正常
5.**调优增益参数**MIC Gain = 25 (最佳)
6.**集成方案设计**AudioCapture 集成代码
### 技术文档
- [MIC.md](file:///d:/CodingProjects/Antigravity/NaviGlass/NaviGlassClient/MIC.md) - 官方麦克风使用文档
- [board.dts](file:///d:/CodingProjects/Antigravity/NaviGlass/NaviGlassClient/board.dts) - Device Tree 配置
- [test_mic.sh](file:///d:/CodingProjects/Antigravity/NaviGlass/NaviGlassClient/src/test_mic.sh) - 自动化测试脚本
- [Microphone_Configuration_Complete.md](file:///d:/CodingProjects/Antigravity/NaviGlass/Docs/Microphone_Configuration_Complete.md) - 完整配置报告
### 测试结果
| 测试项 | 状态 | 备注 |
|--------|------|------|
| ALSA 设备识别 | ✅ 通过 | audiocodec (card 0) |
| MIC Switch 配置 | ✅ 通过 | amixer 控制正常 |
| 录音功能 | ✅ 通过 | 5 秒录音成功 |
| 音质测试 | ✅ 通过 | 清晰、无明显杂音 |
| 增益调优 | ✅ 完成 | MIC Gain = 25 最佳 |
### 配置完成度
**音频系统**
- ✅ 音频播放I2S + MAX98357A- Day 3 完成
- ✅ 音频采集(模拟麦克风 + audiocodec- Day 4 完成
- ⏳ 端到端集成WebSocket + HTTP- 待完成
**整体进度**:约 **60%** (+10%)
---
## 下一步计划
### 短期目标Day 5
1. **音频系统集成**
- 集成 MIC 配置到主程序
- WebSocket 音频上传测试
- HTTP TTS 下载播放测试
- 完整语音对话闭环验证
2. **或进入摄像头开发**(取决于优先级)
- GC2083 摄像头配置
- MPP 库集成
- JPEG 硬件编码
### 中期目标Day 6-7
3. **摄像头系统**
- ISP 参数加载
- 视频流采集
- WebSocket 图像上传
4. **IMU 系统**
- MPU6050 I2C 配置
- 数据读取和校准
- UDP 上报
5. **系统完整集成**
- 多线程协同
- 性能优化
- 稳定性测试
---
## 经验总结
### 收获
1. **硬件确认的重要性**
- 开发前必须确认实际硬件类型
- 文档MIC.md比猜测更可靠
2. **Device Tree 的灵活性**
- 如果驱动已配置,无需重复造轮子
- 运行时配置amixer比编译时更灵活
3. **逐步调优的必要性**
- 增益参数需要实测调优
- 音量和音质需要平衡
### 启示
- **模拟麦克风 vs PDM**:模拟方案配置更简单,但抗干扰能力较弱
- **运行时配置**MIC Switch 默认关闭,需要程序主动打开
- **增益设置**:过高会放大噪声,过低影响音量,需要找到平衡点
---
## 第八部分IMU 传感器配置
### 1. 硬件选型
**传感器型号**ICM-42688-P
- 6 轴 IMU3 轴加速度计 + 3 轴陀螺仪)
- 支持 I2C 和 SPI 双接口
- 高精度、低功耗
- TDK InvenSense 出品
### 2. 接口选择I2C vs SPI
#### I2C 尝试(失败)
**初始方案**
- 使用 GPIO 模拟 I2CPD3/PD2
- 原因:硬件 I2C 引脚配置复杂
**遇到的问题**
1. Device Tree 配置困难
- PD1/PD2 支持 TWI0但 PD1 被其他功能占用
- PL2/PL3 不支持 TWI0 功能
2. 设备响应地址但拒绝寄存器访问
- `Write addr (0xD0): ACK` - 地址响应正常
- `Write reg (0x75): NACK` - 寄存器访问失败
3. 可能原因:
- 需要特殊的初始化序列
- 寄存器 Bank 切换问题
- I2C 时序要求严格
#### SPI 方案(成功)✅
**优势**
- 协议简单,无 ACK/NACK 握手
- 时序可靠,主设备完全控制
- 高速传输(可达 MHz 级)
- ICM-42688 官方推荐接口
**实现方式**GPIO 模拟 SPI
### 3. 硬件连接SPI 模式)
```
ICM-42688 模块 → Avaota F1
-------------- ---------
VCC → 3.3V
GND → GND
SCL/SCLK → PD3 (GPIO 99)
SDA/MOSI → PD2 (GPIO 98)
AD0/MISO → PD4 (GPIO 100)
CS → PD5 (GPIO 101)
INT1/INT2 → 悬空(未使用)
```
### 4. 软件实现
**驱动文件**[`icm42688_spi.cpp`](file:///d:/CodingProjects/Antigravity/AvaotaF1/src/imu/icm42688_spi.cpp)
**关键特性**
- GPIO 模拟 SPIMode 0: CPOL=0, CPHA=0
- 速度约 500kHz可调
- 完整的寄存器读写功能
- 6 轴数据读取(加速度、陀螺仪、温度)
**SPI 时序实现**
```cpp
static uint8_t spi_transfer_byte(uint8_t tx_byte) {
uint8_t rx_byte = 0;
for (int i = 7; i >= 0; i--) {
// 设置 MOSI
if (tx_byte & (1 << i)) mosi_high();
else mosi_low();
sclk_high(); // 上升沿:从设备采样
if (miso_read()) rx_byte |= (1 << i);
sclk_low(); // 下降沿:从设备准备下一位
}
return rx_byte;
}
```
**读取寄存器**
```cpp
uint8_t ICM42688::read_register(uint8_t reg) {
cs_select();
spi_transfer_byte(reg | 0x80); // 读操作:地址最高位为 1
uint8_t value = spi_transfer_byte(0x00); // Dummy 字节
cs_deselect();
return value;
}
```
### 5. 测试结果
**成功识别**
```
[INFO] ICM42688 detected, WHO_AM_I = 0x47
[INFO] ICM42688 initialized successfully
```
**数据采集**(静止状态):
```
[Sample 1]
Accel: X= -2.52 Y= -9.40 Z= 1.37 m/s²
Gyro: X= -0.06 Y= 0.00 Z= -0.18 °/s
Temp: 19.33 °C
```
**数据分析**
-**加速度计**:总加速度 ≈ 9.8 m/s²重力加速度
-**陀螺仪**:接近 0°/s静止状态
-**温度**19.3°C室温
-**数据稳定**10 次采样波动极小
### 6. 配置参数
| 参数 | 配置值 | 说明 |
|------|--------|------|
| 加速度计量程 | ±16g | `AFS_16G` |
| 陀螺仪量程 | ±2000°/s | `GFS_2000DPS` |
| 输出数据率 | 1kHz | `ODR_1KHZ` |
| SPI 时钟 | ~500kHz | GPIO 模拟 |
### 7. 技术要点
**为什么加速度计静止也有数值?**
传感器测量的是**加速度**,包括:
- 运动加速度(移动时产生)
- 重力加速度(始终存在,约 9.8 m/s²
静止状态下:
- 运动加速度 = 0
- 重力加速度 ≠ 0分解在 X/Y/Z 三轴)
- 总加速度 = √(X² + Y² + Z²) ≈ 9.8 m/s²
**陀螺仪数据理解**
- ✅ 静止时0°/s±噪声
- ✅ 旋转时:几十到几百°/s
### 8. 集成方案
**在主程序中**
```cpp
void imu_thread() {
LOG_INFO("Starting IMU thread...");
ICM42688 imu("/dev/spidev0.0", 0); // SPI 模式
if (!imu.init()) {
LOG_ERROR("Failed to initialize IMU");
return;
}
// UDP 发送器
UDPSender udp(SERVER_HOST, UDP_PORT);
while (g_running) {
if (imu.read_sensor()) {
// 构造 IMU 数据包
ImuData data = {
.ax = imu.get_accel_x(),
.ay = imu.get_accel_y(),
.az = imu.get_accel_z(),
.gx = imu.get_gyro_x(),
.gy = imu.get_gyro_y(),
.gz = imu.get_gyro_z(),
.temp = imu.get_temperature()
};
// UDP 发送
udp.send((uint8_t*)&data, sizeof(data));
}
usleep(10000); // 100Hz
}
}
```
---
## 🏆 Day 4 成果(更新)
### 核心成就
1.**确认硬件类型**:模拟麦克风(非 PDM/DMIC
2.**验证 Device Tree**audiocodec 已完整配置
3.**创建测试脚本**[`test_mic.sh`](file:///d:/CodingProjects/Antigravity/AvaotaF1/src/test_mic.sh)
4.**完成硬件测试**:录音功能正常
5.**调优增益参数**MIC Gain = 25 (最佳)
6.**集成方案设计**AudioCapture 集成代码
7.**IMU 配置完成**ICM-42688 SPI 模式成功
8.**6 轴数据采集**:加速度、陀螺仪、温度
### 技术文档
- [MIC.md](file:///d:/CodingProjects/Antigravity/AvaotaF1/MIC.md) - 官方麦克风使用文档
- [board.dts](file:///d:/CodingProjects/Antigravity/AvaotaF1/board.dts) - Device Tree 配置
- [test_mic.sh](file:///d:/CodingProjects/Antigravity/AvaotaF1/src/test_mic.sh) - 麦克风测试脚本
- [icm42688_spi.cpp](file:///d:/CodingProjects/Antigravity/AvaotaF1/src/imu/icm42688_spi.cpp) - IMU SPI 驱动
- [test_imu.cpp](file:///d:/CodingProjects/Antigravity/AvaotaF1/src/test_imu.cpp) - IMU 测试程序
### 测试结果
| 测试项 | 状态 | 备注 |
|--------|------|------|
| ALSA 设备识别 | ✅ 通过 | audiocodec (card 0) |
| MIC Switch 配置 | ✅ 通过 | amixer 控制正常 |
| 录音功能 | ✅ 通过 | 5 秒录音成功 |
| 音质测试 | ✅ 通过 | 清晰、无明显杂音 |
| 增益调优 | ✅ 完成 | MIC Gain = 25 最佳 |
| **IMU 识别** | ✅ 通过 | WHO_AM_I = 0x47 |
| **IMU 数据读取** | ✅ 通过 | 6 轴数据正常 |
| **SPI 通信** | ✅ 通过 | GPIO 模拟稳定 |
### 配置完成度
**传感器系统**
- ✅ 音频播放I2S + MAX98357A- Day 3 完成
- ✅ 音频采集(模拟麦克风 + audiocodec- Day 4 完成
- ✅ IMU 传感器ICM-42688 SPI- Day 4 完成
- ⏳ 摄像头GC2083 MIPI- 待完成
- ⏳ 端到端集成WebSocket + HTTP + UDP- 待完成
**整体进度**:约 **70%** (+10%)
---
## 下一步计划
### 短期目标Day 5
1. **音频系统集成**
- 集成 MIC 配置到主程序
- WebSocket 音频上传测试
- HTTP TTS 下载播放测试
- 完整语音对话闭环验证
2. **IMU 系统集成**
- 集成到主程序多线程
- UDP 数据上报
- 姿态解算(可选)
### 中期目标Day 6-7
3. **摄像头系统**
- GC2083 配置
- MPP 库集成
- JPEG 硬件编码
- WebSocket 图像上传
4. **系统完整集成**
- 多线程协同
- 性能优化
- 稳定性测试
---
## 经验总结
### 收获
1. **硬件确认的重要性**
- 开发前必须确认实际硬件类型
- 文档MIC.md比猜测更可靠
2. **Device Tree 的灵活性**
- 如果驱动已配置,无需重复造轮子
- 运行时配置amixer比编译时更灵活
3. **逐步调优的必要性**
- 增益参数需要实测调优
- 音量和音质需要平衡
4. **接口选型的技巧**
- I2C简单但对时序要求高易受干扰
- SPI引脚多但可靠性高速度快
- 遇到 I2C 问题时,尝试 SPI 是明智选择
5. **GPIO 模拟的实用性**
- 绕过复杂的 Device Tree 配置
- 完全用户空间实现,调试方便
- 性能对 IMU 等低速设备完全够用
### 启示
- **模拟麦克风 vs PDM**:模拟方案配置更简单,但抗干扰能力较弱
- **运行时配置**MIC Switch 默认关闭,需要程序主动打开
- **增益设置**:过高会放大噪声,过低影响音量,需要找到平衡点
- **SPI vs I2C**:高性能场景优先选择 SPI
- **传感器数据理解**:加速度计测量重力+运动,静止时仍有读数
---
**模拟麦克风 + IMU 传感器配置完成!** 🎉