Init: 导入开发日志和项目文档

This commit is contained in:
Kevin Wong
2025-12-31 16:18:28 +08:00
commit bcebc7e316
32 changed files with 9208 additions and 0 deletions

718
DevLogs/Day4.md Normal file
View File

@@ -0,0 +1,718 @@
# 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 传感器配置完成!** 🎉