应用实战精解系列(八):RVB2601麦克风录音测试

简介: 芯片开放社区(OCC)面向广大开发者推出应用实战系列内容,通过分享开发者实战开发案例,总结应用开发经验,梳理开发中的常见问题及解决方案,为后续参与的开发者提供更多参考与借鉴。

上期内容,我们学习了如何通过集成于RVB2601的W800实现Wi-Fi联网,并进行了以太网通讯测试,带大家直观了解了RVB2601 Wi-Fi功能的使用方法。本期我们将为大家带来RVB2601另一基础功能的教程,即通过ES7210进行麦克风数字化采样。


01 概述

RVB2601采用ES7210进行麦克风的数字化采样。本次测试,学习使用I2S接口从ES7210中进行一定时间的麦克风音频数据采集和暂存。


02 驱动描述

2.1 硬件接口原理

image.png


CH2601采用I2C接口完成ES7210的配置,采用I2S接口读取ES7210的转换数据,其接口如图所示。

序号

ES7210

GPIO

1

I2C SCL

PA8(I2C0_SCL)

2

I2C SDA

PA9(I2C0_SDA)

3

ADC MCLK

PA10(I2S0_MCLK)

4

ADC BCLK

I2S4_SCLK

5

ADC LRLK

I2S4_LSCLK

6

ADC DAT1

I2S4_DATA

7

ADC DAT2

I2S5_DATA


2.2 软件驱动设计 CODEC

CODEC在这里指的是同时具有D/A(数字讯号转换成模拟讯号)和A/D(模拟讯号转换成数字讯号)转换功能的编解码器,播放音乐的时候用到的是D/A转换功能。在录音的时候用到的是A/D转换功能。


在接口中,D/A指的是输出通道,A/D指的是输入通道。我们这里主要使用AD的输入通道


本次使用CODEC的CSI接口如下所示:

函数

说明

csi_codec_init

CODEC设备初始化

csi_codec_uninit

CODEC设备去初始化

csi_codec_input_open

CODEC输入通道打开

csi_codec_input_config

CODEC输入通道配置

csi_codec_input_analog_gain

CODEC输入通道设置模拟增益

csi_codec_input_start

CODEC接收输入音频流

csi_codec_input_stop

CODEC结束接收输入音频流

csi_codec_input_read_async

CODEC输入通道异步模式读取数据

csi_codec_input_read

CODEC输入通道同步模式读取数据

csi_codec_input_attach_callback

CODEC输入通道注册回调函数

csi_codec_input_detach_callback

CODEC输入通道注销回调函数

csi_codec_input_close

CODEC输入通道关闭

csi_codec_input_link_dma

CODEC输入通道配置DMA


CODEC设备初始化CODEC用于输入接口详细说明

  • CODEC设备初始化


csi_error_t csi_codec_init(csi_codec_t *codec, uint32_t idx)


功能描述:

   通过设备ID初始化对应的CODEC实例。


参数:

   codec: 设备句柄(需要用户申请句柄空间)。

   idx: 设备ID。


返回值:

   CSI_OK: 初始化成功。

   CSI_ERROR: 初始化失败。


csi_codec_t

成员

类型

说明

dev

csi_dev_t

csi设备统一句柄

output_chs

csi_codec_output_t

输出通道句柄

input_chs

csi_codec_input_t

输入通道句柄

*priv

void

设备私有变量


ringbuffer_t

成员

类型

描述

buffer

uint8_t *

环形缓冲区地址

size

uint32_t

环形缓冲区大小

write

uint32_t

环形缓冲区当前写指针位置

read

uint32_t

环形缓冲区当前读指针位置

data_len

uint32_t

环形缓冲区当前可读数据长度


csi_codec_output_t

成员

类型

描述

codec

csi_codec_t *

CODEC设备句柄

ch_idx

uint32_t

当前通道的序号

callback

void (callback)(csi_codec_output_t output, csi_codec_event_t event, void *arg)

当前通道的回调

arg

void *

当前通道的用户参数

ring_buf

ringbuffer_t *

当前通道的缓冲器句柄

period

uint32_t

设置完成多少数据发送上报周期

sound_channel_num

uint32_t

声道数

state

csi_state_t

当前通道的状态

dma

csi_dma_ch_t *

当前通道的DMA句柄

next

struct csi_codec_output *

下一个输出通道的地址指针

priv

void *

设备私有变量


csi_codec_input_t

成员

描述

codec

csi_codec_t *

CODEC设备句柄

ch_idx

uint32_t

当前通道的序号

callback

void (callback)(csi_codec_input_t input, csi_codec_event_t event, void *arg)

当前通道的回调

arg

void *

当前通道的用户参数

ring_buf

ringbuffer_t *

当前通道的缓冲器句柄

period

uint32_t

设置完成多少数据接收上报周期

sound_channel_num

uint32_t

声道数

state

csi_state_t

当前通道的状态

dma

csi_dma_ch_t *

当前通道的DMA句柄

next

struct csi_codec_input *

下一个输入通道的地址指针

priv

void *

设备私有变量


  • CODEC设备去初始化


void csi_codec_uninit(csi_codec_t *codec)


功能描述:

   codec实例反初始化。该接口会清理并释放相关的软硬件资源。


参数:

   codec: 实例句柄。


返回值:

   无。


  • CODEC输入通道打开


csi_error_t csi_codec_input_open(csi_codec_t *codec, csi_codec_input_t *ch, uint32_t ch_idx)


功能描述:

   将输入通道的ch句柄注册到codec句柄中。初始化输入通道有关的硬件资源。


参数:

   codec: codec实例句柄。

   ch: 输入通道的实例句柄。

   ch_idx:通道的ID。


返回值:

   错误码csi_error_t。


  • CODEC输入通道配置


csi_error_t csi_codec_input_config(csi_codec_input_t *ch, csi_codec_input_config_t *config)


功能描述:

   根据传入的配置配置输入通道。配置输入通道采样宽度、采样比率、设置缓冲区地址、设置输入通道的输出模式(差分输入还是单端输入)。


参数:

   ch:通道实例句柄。

   config:配置参数。


返回值:

   错误码csi_error_t。


  • CODEC输入通道注册回调函数


csi_error_t csi_codec_input_attach_callback(csi_codec_input_t *ch, void *callback, void *arg)


功能描述:

   设置输入通道回调函数。


参数:

   csi_codec_input_t:输入通道实例句柄。

   callback:codec:输入通道的事件回调函数(一般在上下文执行)。

   arg:回调函数参数(可选,由用户定义)。


返回值:

   错误码csi_error_t。


callback


void (*callback)(csi_codec_input_t *input, csi_codec_event_t event, void *arg)


其中 input为输入通道句柄,event 为传给回调函数的事件类型,arg 为用户自定义的回调函数对应的参数。


codec 回调事件枚举类型csi_codec_event_t定义如下:

类型

说明

CODEC_EVENT_PERIOD_READ_COMPLETE

接收period完成

CODEC_EVENT_PERIOD_WRITE_COMPLETE

发送period完成

CODEC_EVENT_WRITE_BUFFER_EMPTY

发送缓冲区已经空

CODEC_EVENT_READ_BUFFER_FULL

接收缓冲区已经满

CODEC_EVENT_TRANSFER_ERROR

传输错误


  • CODEC输入通道注销回调函数


void csi_codec_input_detach_callback(csi_codec_input_t *ch)


功能描述:

   注销CODEC 输入通道的回调函数。


参数:

   ch:通道实例句柄。


返回值:

   无。


  • CODEC输入通道关闭


void csi_codec_input_close(csi_codec_input_t *ch)


功能描述:

   关闭输入通道。调用该接口会马上停止接收数据。


参数:

   ch:通道实例句柄。


  • CODEC输入通道配置DMA


csi_error_t csi_codec_input_link_dma(csi_codec_input_t *ch, csi_dma_ch_t *dma)


功能描述:

   输入通道连接DMA。


参数:

   ch:输入通道的实例句柄。

   dma:dma实例句柄。


返回:

   错误码csi_error_t。


  • CODEC接收输入音频流


csi_error_t csi_codec_input_start(csi_codec_input_t *ch)


功能描述:

   输入通道开始数据流。


参数:

   ch:输入通道的实例句柄。


返回值:

   错误码csi_error_t。


  • CODEC结束接收输入音频流


csi_error_t csi_codec_input_stop(csi_codec_input_t *ch)


功能描述:

   输入通道结束数据流。


参数:

   ch:输入通道的实例句柄。


返回值:

   错误码csi_error_t。


  • CODEC输入通道设置模拟增益


csi_error_t csi_codec_input_analog_gain(csi_codec_input_t *ch, uint32_t val)


功能描述:

   设置输入通道模拟增益。


参数:

   ch:输入通道的实例句柄。

   val: 增益的DB值。


返回值:

   错误码csi_error_t。


03 测试程序

本测试程序通过RVB2601建立一个通过I2S接口读取ES7210录音测试程序,数据录取结束后将数据打印到串口终端。


3.1 初始化

初始化代码参考wiki上的基本配置信息完成。


csi_codec_input_config_t input_config;
/* init函数的idx参数,请根据soc的实际情况进行选择 */
ret = csi_codec_init(&codec, 0);;
if (ret != CSI_OK) {
return -1;
}
/* input ch config */
csi_codec_input_attach_callback(&codec_input_ch, codec_input_event_cb_fun, NULL);
codec_input_ch.period = INPUT_BUF_SIZE/2;
codec_input_ch.ring_buf = &input_ring_buffer;
csi_codec_input_open(&codec, &codec_input_ch, 0);
input_config.bit_width = 16;
input_config.sample_rate = 8000;
input_config.buffer = input_buf;
input_config.buffer_size = INPUT_BUF_SIZE;
input_config.period = INPUT_BUF_SIZE/2;
input_config.mode = CODEC_INPUT_DIFFERENCE;
csi_codec_input_config(&codec_input_ch,&input_config);
csi_codec_input_link_dma(&codec_input_ch,&dma_ch_input_handle);
csi_codec_input_start(&codec_input_ch);


3.2 事件处理


static void codec_input_event_cb_fun(csi_codec_input_t *i2s, csi_codec_event_t event, void *arg)
{
    if (event == CODEC_EVENT_PERIOD_READ_COMPLETE) {
        cb_input_transfer_flag = 1;
    }
}


3.3 数据的显示


int i;
uint16_t *p = (uint16_t *)(repeater_data_addr + 24*1024);
for(i=0;i<48*512;i++)
{
  if(i%16 == 0)
    printf("\n");
  printf("%04x ",p);
}


3.4 通过console调用


static void mic_handler(char *wbuf, int wbuf_len, int argc, char **argv)
{
    csi_error_t ret;
    csi_codec_input_config_t input_config;
    ret = csi_codec_init(&codec, 0);
    if (ret != CSI_OK) {
        printf("csi_codec_init error\n");
        return ;
    }
    codec_input_ch.ring_buf = &input_ring_buffer;
    csi_codec_input_open(&codec, &codec_input_ch, 0);
  /* input ch config */
    csi_codec_input_attach_callback(&codec_input_ch, codec_input_event_cb_fun, NULL);
    input_config.bit_width = 16;
    input_config.sample_rate = 8000;
    input_config.buffer = input_buf;
    input_config.buffer_size = INPUT_BUF_SIZE;
    input_config.period = 1024;
    input_config.mode = CODEC_INPUT_DIFFERENCE;
    csi_codec_input_config(&codec_input_ch, &input_config);
    csi_codec_input_analog_gain(&codec_input_ch, 0xbf);
    csi_codec_input_link_dma(&codec_input_ch, &dma_ch_input_handle);
    printf("start recorder\n");
    csi_codec_input_start(&codec_input_ch);
  while (new_data_flag < 48) {
            if (cb_input_transfer_flag) {
                csi_codec_input_read_async(&codec_input_ch, repeater_data_addr + (new_data_flag * 1024), 1024);
                cb_input_transfer_flag = 0U;
                new_data_flag ++;
         }
     }
aos_msleep(100);
  printf("record sound data: \n");
  int i;
  uint16_t *p = (uint16_t *)(repeater_data_addr + 24*1024);
  for(i=0;i<512;i++)
  {
    if(i%16 == 0)
      printf("\n");
    printf("%04x ",p);
  }
    printf("stop reorder\n");
    csi_codec_input_stop(&codec_input_ch);
    csi_codec_input_link_dma(&codec_input_ch, NULL);
    csi_codec_input_detach_callback(&codec_input_ch);
    csi_codec_uninit(&codec);
    return;
}
int cli_reg_cmd_ft(void)
{
static const struct cli_command mic_cmd_info = {
        "mic",
        "mic",
        mic_handler,
    };
    aos_cli_register_command(&mic_cmd_info);
    return 0;
}


04 实测效果演示

4.1 录取数据开始

image.gifimage.png


4.2 展示数据结束

image.png


4.3 波形数据展示

image.png


05 下期预告

有关RVB2601的麦克风测试,就先介绍到这里,下期将为大家带来的是基于RVB2601的远程音频采集系统开发介绍。欢迎大家持续关注应用实战精解系列内容。



相关文章
|
4天前
|
人工智能 数据可视化 API
10 分钟构建 AI 客服并应用到网站、钉钉或微信中测试评
10 分钟构建 AI 客服并应用到网站、钉钉或微信中测试评
21 2
|
21天前
|
运维 Ubuntu 测试技术
自动化运维的利剑:Ansible在配置管理中的应用软件测试的艺术:探索性测试的深度与广度
【8月更文挑战第27天】 在数字化浪潮中,高效的运维工作是支撑企业IT系统稳定运行的关键。Ansible,作为一款简易而强大的自动化运维工具,正逐渐成为IT专业人士的新宠。本文将通过浅显易懂的语言和生动的案例,带你了解Ansible的核心概念、安装步骤、基础命令以及它在配置管理中的实际应用。我们的目标是让初学者能够轻松上手Ansible,同时为有经验的运维工程师提供一些实用的技巧和思路。
|
21天前
|
机器学习/深度学习 人工智能 自然语言处理
探索AI在文本生成中的应用与挑战自动化测试框架的搭建与实践
【8月更文挑战第27天】本文将深入探讨人工智能(AI)在文本生成领域的应用,包括其技术原理、实际应用案例以及面临的主要挑战。通过分析AI文本生成的工作原理和实际效果,我们将揭示这项技术如何改变内容创作、新闻撰写、对话系统等多个领域。同时,我们也将讨论AI文本生成带来的伦理和质量问题,以及如何平衡创新与风险,确保技术的健康发展。
|
12天前
|
缓存 测试技术 Apache
告别卡顿!Python性能测试实战教程,JMeter&Locust带你秒懂性能优化💡
【9月更文挑战第5天】性能测试是确保应用在高负载下稳定运行的关键。本文介绍Apache JMeter和Locust两款常用性能测试工具,帮助识别并解决性能瓶颈。JMeter适用于测试静态和动态资源,而Locust则通过Python脚本模拟HTTP请求。文章详细讲解了安装、配置及使用方法,并提供了实战案例,帮助你掌握性能测试技巧,提升应用性能。通过分析测试结果、模拟并发、检查资源使用情况及代码优化,确保应用在高并发环境下表现优异。
37 5
|
11天前
|
测试技术 Apache 数据库
从慢如蜗牛到飞一般的感觉!Python性能测试实战,JMeter&Locust助你加速🏃‍♂️
【9月更文挑战第6天】你的Python应用是否曾因响应缓慢而让用户望而却步?借助JMeter与Locust,这一切将迎刃而解。JMeter作为Apache基金会的明星项目,以其强大的跨平台和多协议支持能力,成为性能测试领域的魔法师;而Locust则以Python的简洁与高效,让性能测试更加灵活。通过实战演练,你可以利用这两款工具轻松识别并解决性能瓶颈,优化数据库查询、网络配置等,最终使应用变得敏捷高效,轻松应对高并发挑战。
11 1
|
14天前
|
Kubernetes Linux API
CentOS 7.6使用kubeadm部署k8s 1.17.2测试集群实战篇
该博客文章详细介绍了在CentOS 7.6操作系统上使用kubeadm工具部署kubernetes 1.17.2版本的测试集群的过程,包括主机环境准备、安装Docker、配置kubelet、初始化集群、添加节点、部署网络插件以及配置k8s node节点管理api server服务器。
45 0
CentOS 7.6使用kubeadm部署k8s 1.17.2测试集群实战篇
|
20天前
|
测试技术 API 开发者
.NET单元测试框架大比拼:MSTest、xUnit与NUnit的实战较量与选择指南
【8月更文挑战第28天】单元测试是软件开发中不可或缺的一环,它能够确保代码的质量和稳定性。在.NET生态系统中,MSTest、xUnit和NUnit是最为流行的单元测试框架。本文将对这三种测试框架进行全面解析,并通过示例代码展示它们的基本用法和特点。
36 7
|
18天前
|
IDE Java 测试技术
揭秘Java高效编程:测试与调试实战策略,让你代码质量飞跃,职场竞争力飙升!
【8月更文挑战第30天】在软件开发中,测试与调试对确保代码质量至关重要。本文通过对比单元测试、集成测试、调试技巧及静态代码分析,探讨了多种实用的Java测试与调试策略。JUnit和Mockito分别用于单元测试与集成测试,有助于提前发现错误并提高代码可维护性;Eclipse和IntelliJ IDEA内置调试器则能快速定位问题;Checkstyle和PMD等工具则通过静态代码分析发现潜在问题。综合运用这些策略,可显著提升代码质量,为项目成功打下坚实基础。
35 2
|
18天前
|
监控 数据管理 jenkins
深入理解与应用软件自动化测试框架
【8月更文挑战第30天】在现代软件开发周期中,自动化测试已成为提高测试效率、保证软件质量的关键步骤。本文将探讨自动化测试框架的设计与实现,重点放在如何根据不同项目需求选择合适的测试框架,以及如何有效地集成到现有的开发和测试流程中。通过分析几个流行的自动化测试工具,如Selenium、Appium和JUnit,我们将讨论它们的特点、优势以及可能面临的挑战。此外,文章还将介绍一些最佳实践,帮助读者构建稳定且易于维护的自动化测试环境。
|
20天前
|
测试技术 芯片
飞针测试机在贴装线路板应用
【8月更文挑战第26天】飞针测试机在PCBA中的应用涵盖检测开路与短路、测试元件电气性能、检查元件安装正确性、识别缺失或损坏的元件,并适用于小批量和多品种生产,有助于提高产品质量和可靠性。它能提供详细故障信息,便于问题定位与反馈,但测试速度较慢,需根据生产规模和质量要求选择合适的测试设备。