除了显示驱动,其余全部测试通过

This commit is contained in:
guo
2026-08-30 14:13:24 +08:00
commit c0ace98dff
146 changed files with 9476 additions and 0 deletions
+362
View File
@@ -0,0 +1,362 @@
#include "app_config.h"
#include "app_log.h"
#include "system/includes.h"
#include "os/os_api.h"
#include "asm/includes.h"
#include "server/audio_server.h"
#include "generic/printf.h"
#include "audio_test.h"
#define AUDIO_TEST_BYTES_PER_SEC \
(AUDIO_TEST_SAMPLE_RATE * AUDIO_TEST_RECORD_CHANNEL * 2)
#define AUDIO_TEST_RECORD_BUF_SIZE \
(AUDIO_TEST_BYTES_PER_SEC * AUDIO_TEST_RECORD_MS / 1000)
#define AUDIO_TEST_FRAME_SIZE \
(AUDIO_TEST_SAMPLE_RATE / 100 * 2 * AUDIO_TEST_RECORD_CHANNEL)
#define AUDIO_TEST_TASK_NAME "audio_test"
#define AUDIO_TEST_TASK_PRIO 6
#define AUDIO_TEST_TASK_STK 1024
#define AUDIO_TEST_MS_TO_TICKS(ms) ((ms) / (1000 / OS_TICKS_PER_SEC))
struct audio_test_hdl {
struct server *enc_server;
struct server *dec_server;
u8 *record_buf;
volatile u32 record_len; /* 已录音字节数(单声道) */
volatile u32 play_pos; /* 已回放字节数(单声道计) */
volatile u8 running;
volatile u8 recording;
volatile u8 playing;
u32 peak;
u32 sum_abs;
u32 samples;
int task_pid;
};
static struct audio_test_hdl audio_test_hdl;
/* MIC录音数据回调: 拷贝进内存缓冲并统计峰值/均值 */
static int audio_test_rec_fwrite(void *file, void *data, u32 len)
{
struct audio_test_hdl *p = (struct audio_test_hdl *)file;
u32 remain, copy_len, i, n;
s16 *s;
u32 a;
if (!p->recording || !p->record_buf) {
return len;
}
remain = AUDIO_TEST_RECORD_BUF_SIZE - p->record_len;
if (!remain) {
return len;
}
copy_len = (len > remain) ? remain : len;
memcpy(p->record_buf + p->record_len, data, copy_len);
p->record_len += copy_len;
s = (s16 *)data;
n = copy_len / 2;
for (i = 0; i < n; i++) {
a = (s[i] < 0) ? (u32)(-s[i]) : (u32)s[i];
p->sum_abs += a;
if (a > p->peak) {
p->peak = a;
}
}
p->samples += n;
return len;
}
/* DAC回放数据回调: 单声道->双声道 */
static int audio_test_play_fread(void *file, void *data, u32 len)
{
struct audio_test_hdl *p = (struct audio_test_hdl *)file;
u32 mono_remain, stereo_remain, frames, i;
s16 *src, *dst;
if (!p->playing || !p->record_buf || p->play_pos >= p->record_len) {
return 0;
}
mono_remain = p->record_len - p->play_pos;
stereo_remain = mono_remain * 2;
if (len > stereo_remain) {
len = stereo_remain;
}
frames = len / (2 * 2);
if (!frames) {
return 0;
}
src = (s16 *)(p->record_buf + p->play_pos);
dst = (s16 *)data;
for (i = 0; i < frames; i++) {
s16 v = src[i] * AUDIO_TEST_PLAYBACK_GAIN;
dst[i * 2] = v;
dst[i * 2 + 1] = v;
}
p->play_pos += frames * 2;
return frames * 2 * 2;
}
static int audio_test_play_flen(void *file)
{
struct audio_test_hdl *p = (struct audio_test_hdl *)file;
return p->record_len * 2;
}
static int audio_test_vfs_fclose(void *file)
{
return 0;
}
static const struct audio_vfs_ops audio_test_rec_vfs = {
.fwrite = audio_test_rec_fwrite,
.fclose = audio_test_vfs_fclose,
};
static const struct audio_vfs_ops audio_test_play_vfs = {
.fread = audio_test_play_fread,
.fclose = audio_test_vfs_fclose,
.flen = audio_test_play_flen,
};
static int audio_test_record_start(void)
{
struct audio_test_hdl *p = &audio_test_hdl;
union audio_req req = {0};
if (!p->record_buf) {
p->record_buf = malloc(AUDIO_TEST_RECORD_BUF_SIZE);
if (!p->record_buf) {
APP_LOG("[AUDIO_TEST] malloc record buf fail: %d\n",
AUDIO_TEST_RECORD_BUF_SIZE);
return -1;
}
}
p->record_len = 0;
p->peak = 0;
p->sum_abs = 0;
p->samples = 0;
p->enc_server = server_open("audio_server", "enc");
if (!p->enc_server) {
APP_LOG("[AUDIO_TEST] enc server open fail\n");
return -1;
}
p->recording = 1;
req.enc.cmd = AUDIO_ENC_OPEN;
req.enc.channel = AUDIO_TEST_RECORD_CHANNEL;
req.enc.volume = AUDIO_TEST_ADC_GAIN;
req.enc.output_buf = NULL;
req.enc.output_buf_len = AUDIO_TEST_DMA_BUF_SIZE;
req.enc.sample_rate = AUDIO_TEST_SAMPLE_RATE;
req.enc.format = "pcm";
req.enc.frame_size = AUDIO_TEST_FRAME_SIZE;
req.enc.sample_source = "mic";
req.enc.channel_bit_map = BIT(AUDIO_TEST_ADC_CHANNEL_L);
req.enc.vfs_ops = &audio_test_rec_vfs;
req.enc.file = (FILE *)p;
req.enc.msec = 0;
if (server_request(p->enc_server, AUDIO_REQ_ENC, &req)) {
APP_LOG("[AUDIO_TEST] enc open fail\n");
goto __err;
}
req.enc.cmd = AUDIO_ENC_START;
if (server_request(p->enc_server, AUDIO_REQ_ENC, &req)) {
APP_LOG("[AUDIO_TEST] enc start fail\n");
goto __err;
}
return 0;
__err:
p->recording = 0;
server_close(p->enc_server);
p->enc_server = NULL;
return -1;
}
static void audio_test_record_stop(void)
{
struct audio_test_hdl *p = &audio_test_hdl;
union audio_req req = {0};
if (p->enc_server) {
req.enc.cmd = AUDIO_ENC_STOP;
server_request(p->enc_server, AUDIO_REQ_ENC, &req);
server_close(p->enc_server);
p->enc_server = NULL;
}
p->recording = 0;
}
static int audio_test_play_start(void)
{
struct audio_test_hdl *p = &audio_test_hdl;
union audio_req req = {0};
p->play_pos = 0;
p->dec_server = server_open("audio_server", "dec");
if (!p->dec_server) {
APP_LOG("[AUDIO_TEST] dec server open fail\n");
return -1;
}
p->playing = 1;
req.dec.cmd = AUDIO_DEC_OPEN;
req.dec.channel = AUDIO_TEST_PLAYBACK_CHANNEL;
req.dec.volume = AUDIO_TEST_DAC_VOLUME;
req.dec.output_buf = NULL;
req.dec.output_buf_len = AUDIO_TEST_DMA_BUF_SIZE;
req.dec.sample_rate = AUDIO_TEST_SAMPLE_RATE;
req.dec.dec_type = "pcm";
req.dec.sample_source = "dac";
req.dec.vfs_ops = &audio_test_play_vfs;
req.dec.file = (FILE *)p;
req.dec.priority = 1;
if (server_request(p->dec_server, AUDIO_REQ_DEC, &req)) {
APP_LOG("[AUDIO_TEST] dec open fail\n");
goto __err;
}
req.dec.cmd = AUDIO_DEC_START;
if (server_request(p->dec_server, AUDIO_REQ_DEC, &req)) {
APP_LOG("[AUDIO_TEST] dec start fail\n");
goto __err;
}
return 0;
__err:
p->playing = 0;
server_close(p->dec_server);
p->dec_server = NULL;
return -1;
}
static void audio_test_play_stop(void)
{
struct audio_test_hdl *p = &audio_test_hdl;
union audio_req req = {0};
if (p->dec_server) {
req.dec.cmd = AUDIO_DEC_STOP;
server_request(p->dec_server, AUDIO_REQ_DEC, &req);
server_close(p->dec_server);
p->dec_server = NULL;
}
p->playing = 0;
}
/* 显式驱动功放SD脚 */
static void audio_test_amp_set(u8 enable)
{
u8 level = enable ? AUDIO_TEST_AMP_ENABLE_LEVEL : !AUDIO_TEST_AMP_ENABLE_LEVEL;
gpio_direction_output(AUDIO_TEST_AMP_PORT, level);
APP_LOG("[AUDIO_TEST] amp SD=PA0 -> %s\n", level ? "HIGH" : "LOW");
}
static void audio_test_task(void *priv)
{
struct audio_test_hdl *p = (struct audio_test_hdl *)priv;
u32 timeout;
APP_LOG("[AUDIO_TEST] ===== audio test start =====\n");
APP_LOG("[AUDIO_TEST] sample=%dHz record=%dms adc_gain=%d dac_vol=%d ch=%d\n",
AUDIO_TEST_SAMPLE_RATE, AUDIO_TEST_RECORD_MS,
AUDIO_TEST_ADC_GAIN, AUDIO_TEST_DAC_VOLUME,
AUDIO_TEST_ADC_CHANNEL_L);
audio_test_amp_set(0); /* 测试开始先静音功放, 防止上电杂音 */
/* 1. MIC 录音 */
if (audio_test_record_start()) {
goto __exit;
}
APP_LOG("[AUDIO_TEST] recording, please speak to MIC...\n");
timeout = AUDIO_TEST_MS_TO_TICKS(AUDIO_TEST_RECORD_MS);
while (timeout--) {
os_time_dly(1);
if (p->record_len >= AUDIO_TEST_RECORD_BUF_SIZE) {
break;
}
}
audio_test_record_stop();
APP_LOG("[AUDIO_TEST] record done: %d bytes, peak=%d, avg=%d\n",
p->record_len, p->peak,
p->samples ? (u32)(p->sum_abs / p->samples) : 0);
if (p->peak >= AUDIO_TEST_PEAK_PASS_THRESHOLD) {
APP_LOG("[AUDIO_TEST] MIC result: PASS (peak=%d)\n", p->peak);
} else {
APP_LOG("[AUDIO_TEST] MIC result: WEAK/FAIL (peak=%d < %d), check mic circuit\n",
p->peak, AUDIO_TEST_PEAK_PASS_THRESHOLD);
}
/* 2. 回放录音到功放 */
if (p->record_len < AUDIO_TEST_FRAME_SIZE * 2) {
APP_LOG("[AUDIO_TEST] record too short, skip playback\n");
goto __exit;
}
if (audio_test_play_start()) {
goto __exit;
}
audio_test_amp_set(1); /* 使能功放 */
APP_LOG("[AUDIO_TEST] playing, listen speaker...\n");
timeout = AUDIO_TEST_MS_TO_TICKS(AUDIO_TEST_RECORD_MS) + AUDIO_TEST_MS_TO_TICKS(2000);
while (timeout--) {
os_time_dly(1);
if (p->play_pos >= p->record_len) {
break;
}
}
audio_test_play_stop();
audio_test_amp_set(0); /* 回放结束静音功放 */
APP_LOG("[AUDIO_TEST] playback done: %d bytes\n", p->play_pos);
APP_LOG("[AUDIO_TEST] ===== audio test finish =====\n");
__exit:
p->running = 0;
p->task_pid = 0;
}
int audio_test_start(void)
{
struct audio_test_hdl *p = &audio_test_hdl;
if (p->running || p->task_pid) {
APP_LOG("[AUDIO_TEST] already running\n");
return -1;
}
p->running = 1;
if (thread_fork(AUDIO_TEST_TASK_NAME, AUDIO_TEST_TASK_PRIO,
AUDIO_TEST_TASK_STK, 0, &p->task_pid,
audio_test_task, p) != OS_NO_ERR) {
p->running = 0;
p->task_pid = 0;
APP_LOG("[AUDIO_TEST] task fork fail\n");
return -1;
}
return 0;
}
int audio_test_stop(void)
{
struct audio_test_hdl *p = &audio_test_hdl;
audio_test_play_stop();
audio_test_record_stop();
if (p->task_pid) {
thread_kill(&p->task_pid, KILL_WAIT);
p->task_pid = 0;
}
p->running = 0;
return 0;
}
+34
View File
@@ -0,0 +1,34 @@
#ifndef AUDIO_TEST_H
#define AUDIO_TEST_H
/* ==================== 功放控制(NS4150B) ==================== */
/* 测试时由本模块直接驱动功放SD脚, 以便验证功放通路 */
#define AUDIO_TEST_AMP_PORT IO_PORTA_00 /* NS4150B SD脚 -> PA0 */
#define AUDIO_TEST_AMP_ENABLE_LEVEL 1 /* 实测确认: NS4150B SD 高电平使能功放(低电平静音) */
/* ==================== 测试参数 ==================== */
#define AUDIO_TEST_SAMPLE_RATE 16000 /* 采样率 */
#define AUDIO_TEST_RECORD_CHANNEL 1 /* MIC 录音单声道 */
#define AUDIO_TEST_PLAYBACK_CHANNEL 2 /* DAC 播放双声道(单声道复制成左右) */
#define AUDIO_TEST_RECORD_MS 5000 /* 录音时长 ms */
#define AUDIO_TEST_ADC_GAIN 75 /* MIC 模拟增益 0-100 */
#define AUDIO_TEST_DAC_VOLUME 85 /* 播放音量 0-100 */
#define AUDIO_TEST_PLAYBACK_GAIN 1 /* 回放数字增益倍数 */
#define AUDIO_TEST_DMA_BUF_SIZE (4 * 1024) /* 编解码DMA缓冲 */
#define AUDIO_TEST_PEAK_PASS_THRESHOLD 2000 /* 峰值>=此值判 MIC PASS(可调) */
/*
* 逻辑ADC通道号:
* MIC1 -> 1, MIC2 -> 2, MIC3 -> 3 (参考官方 CONFIG_AUDIO_ADC_CHANNEL_L/R)
* 需与 board.c 中 adc_platform_data.mic_channel 对应的物理通道一致
*/
#define AUDIO_TEST_ADC_CHANNEL_L 1
/* ==================== 接口 ==================== */
/* 异步启动完整测试(MIC录音->回放), 成功返回0 */
int audio_test_start(void);
/* 停止/复位测试 */
int audio_test_stop(void);
#endif