本文作者:我爱下载

1、概述

远程音频采集系统利用RVB2601的ES7210麦克风数字化采样,W800的WiFi通讯和OLED液晶显示相关信息,进行音频收集和存储。开发专用的上位软件,通过以太网通讯启动下位机完成一定数据量的音频收集后,传输到上位机,并存储为RAW文件。

系统中使用了麦克风音频采集ADC,W800无线以太网通讯,OLED液晶显示,指示灯等几个外设设备。

2、测试程序

通过概述的描述,利用之前的外设测试和学习经验,本次开发包括下位机软件,和上位机软件。

2.1 下位机软件

下位机软件主要包含wifi接口处理,音频采集、缓存管理和OLED三个主要部分。

1) 初始化

根据以太网通讯的研究,《以太网通讯测试》连接 RVB2601评估板试用3: 以太网通讯测试 - 国产芯片交流 - 电子工程世界-论坛  建立wifi连接,获取ip地址,这里为了后面的处理方便,路由器中设置了固定的ip地址和mac的绑定关系,保证ip地址的获取唯一。

根据音频测试的研究,《麦克风录音测试》 连接 RVB2601评估板试用4: 麦克风录音测试 - 国产芯片交流 - 电子工程世界-论坛  完成音频采样音频初始化,并进入等待状态。

为了更好的管理采样数据,建立一个RingBuffer缓冲队列。开辟一个48K的缓冲区,用来存储音频采样数据。

ringbuffer_t mic_ring_buffer;
#define MIC_RECORDER_BUF_SIZE 49152
uint8_t repeater_data_addr[MIC_RECORDER_BUF_SIZE];
//设置录音缓冲区环形队列
mic_ring_buffer.buffer = repeater_data_addr;
mic_ring_buffer.size = MIC_RECORDER_BUF_SIZE;
ringbuffer_reset(&mic_ring_buffer);

创建一个画面,画面中包换本次试用程序的标题“THEAD RVB2601 RECORDER”和2个显示标签。显示标签中实时显示当前的运行状态。

static void gui_label_create(void)
{lv_obj_t* scr = lv_scr_act();//获取当前活跃的屏幕对象lv_obj_t *p = lv_label_create(scr, NULL);lv_label_set_long_mode(p, LV_LABEL_LONG_BREAK);lv_label_set_align(p, LV_LABEL_ALIGN_CENTER);lv_obj_set_pos(p, 0, 4);lv_obj_set_size(p, 128, 60);lv_label_set_text(p, "THEAD RVB2601\nRECORDER");p = lv_label_create(scr, NULL);lv_label_set_align(p, LV_LABEL_ALIGN_LEFT);lv_obj_set_pos(p, 0, 40);lv_obj_set_size(p, 60, 20);lv_label_set_text(p, "STATUS:");pLabel = lv_label_create(scr, NULL);lv_label_set_align(pLabel, LV_LABEL_ALIGN_CENTER);lv_obj_set_pos(pLabel, 65, 40);lv_obj_set_size(pLabel, 50, 20);lv_label_set_text(pLabel, "idel");
}

建立了以太网接收函数,音频采集任务,音频数据发送任务,图形显示这4个主要任务,并利用信号量完成任务间的协调工作。

  • 音频采集任务
aos_task_new("mic_recorder", main_mic_task, NULL, 2 * 1024);
  • 音频数据发送任务
aos_task_new("mic_recorder_send", wifi_send_task, NULL, 4 * 1024);
  • 图形显示任务
aos_task_new("gui", gui_lvgl_task, NULL, 10 * 1024);
  • 以太网接收函数通过串口终端启动。
int mic_tcpclient(void);

2) 以太网数据接收

根据前面的研究,RVB2601只能作为以太网的Client端,所以,这里必须以以太网的客户端方式建立连接,完成数据收发。

int mic_tcpclient(void)
{struct sockaddr_in  sAddr;int                 iAddrSize;int                 iStatus;char            *cBsdBuf = NULL;
//    int time_ms = aos_now_ms();
//    int time_ms_step = aos_now_ms();running = 1;cBsdBuf = lan_buf;//filling the TCP server socket addressFD_ZERO(&sAddr);sAddr.sin_family = AF_INET;sAddr.sin_port = htons(26666);sAddr.sin_addr.s_addr = inet_addr("192.168.1.3");iAddrSize = sizeof(struct sockaddr_in);// creating a TCP socketiSockFD = socket(AF_INET, SOCK_STREAM, 0);if (iSockFD < 0) {LOGE(TAG, "TCP ERROR: create tcp client socket fd error!");goto Exit1;}LOGD(TAG, "ServerIP=%s port=%d.", "192.168.1.3", 26666);LOGD(TAG, "Create socket %d.", iSockFD);// connecting to TCP serveriStatus = connect(iSockFD, (struct sockaddr *)&sAddr, iAddrSize);if (iStatus < 0) {LOGE(TAG, "TCP ERROR: tcp client connect server error! ");goto Exit;}LOGD(TAG, "TCP: Connect server successfully.");record_sta = NET_CONNECT;// sending multiple packets to the TCP serverwhile (running) {if ( (iStatus = read(iSockFD, cBsdBuf, 1024)) < 0) {break;}//解析数据if(cBsdBuf[0] == 1) //起动录音{LOGD(TAG, "get record start command!");mic_recorder_start();wifi_send_run_flag = 1;}
//      else if(cBsdBuf[0] == 2)    //起动传输
//      {
//          LOGD(TAG, "get stop command!");
//          mic_recorder_stop();
//          wifi_send_task_run_status = 0;
//      }else if(cBsdBuf[0] == 3)    {wifi_send_run_flag = 0;LOGD(TAG, "quit command!");break;}}LOGD(TAG, "RECORDER: Quit!");record_sta = NET_DISCON;
Exit://closing the socket after sending 1000 packetsclose(iSockFD);
Exit1:return 0;
}

3)以太网数据发送

每帧发送1024字节数据,连续发送,直到所有数据发送完成为止。

void wifi_send_task(void *arg)
{int                 iStatus;int len;LOGD(TAG, "MIC Recorder send thread begin!");aos_sem_new(&mic_data_send_sem, 0); while (1){aos_sem_wait(&mic_data_send_sem, AOS_WAIT_FOREVER);while(wifi_send_run_flag){len = mic_recorder_getdata_len();if(len > 0){len = mic_recorder_getdata((uint8_t *)lan_buf,1024);if(len > 0){record_sta = REC_SEND;// sending packetiStatus = send(iSockFD, lan_buf, len, 0);if (iStatus <= 0) {printf("TCP ERROR: tcp client send data error!  iStatus:%d", iStatus);record_sta = NET_ERROR;}aos_msleep(100);}}else{wifi_send_run_flag = 0;}}record_sta = IDEL;}
}

4)音频采样

音频启动中负责复位缓冲队列,然后启动音频采样。

void mic_recorder_start(void)
{ringbuffer_reset(&mic_ring_buffer);csi_codec_input_start(&codec_input_ch);
}

录取到一定数量音频后,产生触发事件,事件中利用信号量环形音频采样任务,将数据读出并存入缓冲队列。

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) {aos_sem_signal(&mic_input_sem);}
}

通过音频采集任务,接收事件信号触发,完成数据读取

static void main_mic_task(void *arg)
{LOGD(TAG, "MIC Recorder thread begin!");aos_sem_new(&mic_input_sem, 0); //创建音频采样信号mic_recorder_init(); //初始化音频采样while (1){aos_sem_wait(&mic_input_sem, AOS_WAIT_FOREVER); //等待一组音频数据采集完成mic_recorder_to_buff(); //将采集到的音频数据压入缓冲队列中}
}

读取音频数据压入缓冲队列,判断采样结束,并触发音频数据发送

void mic_recorder_to_buff(void)
{csi_codec_input_read_async(&codec_input_ch, mic_input_buf, 1024);ringbuffer_in(&mic_ring_buffer, mic_input_buf, 1024);uint32_t len = ringbuffer_len(&mic_ring_buffer);if(len >= MIC_RECORDER_BUF_SIZE){csi_codec_input_stop(&codec_input_ch);aos_sem_signal(&mic_data_send_sem);}
}

5)运行状态显示

首先创建了一个枚举类型,包换所有待显示的状态定义。

typedef enum _RECORDER_STA
{IDEL = 0, //空闲状态NET_CONNECT, //网络连接NET_DISCON, //网络断开NET_ERROR, //网络数据发送错误REC_INIT, //录音初始化REC_START, //录音启动REC_RUNNING, //录音采样中REC_SEND, //发送录音数据
}RECORDER_STA;

根据当前系统运行的状态,显示在OLED的画面上。

static void gui_lvgl_task(void *arg)
{lv_init();/*Initialize for LittlevGL*/oled_init();/*Select display 1*/// demo_create();gui_label_create();while (1) {switch(record_sta){case    IDEL:   //空闲状态lv_label_set_text(pLabel, "idel");break;case NET_CONNECT:   //网络连接lv_label_set_text(pLabel, "connect");break;case NET_DISCON:        //网络断开lv_label_set_text(pLabel, "discon");break;case NET_ERROR:     //网络数据发送错误lv_label_set_text(pLabel, "neterr");break;case REC_INIT:      //录音初始化lv_label_set_text(pLabel, "init");break;case REC_START:     //录音启动lv_label_set_text(pLabel, "start");break;case REC_RUNNING:   //录音采样中lv_label_set_text(pLabel, "rec...");break;case REC_SEND:      //发送录音数据lv_label_set_text(pLabel, "send");break;default:break;};/* Periodically call the lv_task handler.* It could be done in a timer interrupt or an OS task too.*/lv_task_handler();aos_msleep(5);lv_tick_inc(1);}
}

2.2 上位机软件

软件是本次测试工程的上位机软件,软件功能包括网络通讯,声音采样控制,波形展示,录音数据存储,状态显示等几个部分。利用TCPServer在端口为26666建立一个监听,接收来自下位机的连接申请。通过上位机的采样启动按钮发送启动命令,下位机接收到启动命令后启动录音采样并存储,采样结束后,触发数据发送,上位机接收到数据后存入缓存中,同时刷新波形显示。点击文件保存按钮,在弹出的对话框中输入名称和选择存储路径,完成接收到的数据保存到文件的工作。

1)界面布局

如图所示,界面中包括标题栏“RVB2601声音采集系统”,按钮控制区,包括录音启动控制和录音文件保存。状态显示区,在录音过程中,显示包括网络通讯在内的信息显示。波形展示区,将接收到的波形实时显示出来,支持波形的局部放大查看等基本功能。

2)波形数据分析

利用软件Audition,打开保存的录音数据,可以播放和对数据进行分析。

3、实测效果演示

3.1 连接建立

上位机在和下位机完成以太网连接后,小灯由绿色变为红色,如果连接断开,小灯由红色变为绿色。

通过串口中断,如果连接成功建立,屏幕打印连接服务器成功提示。

液晶显示屏上显示“connect"字样。

3.2 启动录音和数据传输

接到上位机启动录音采样命令后,终端打印录音开始。当录音采样结束后,自动进入发送程序,完成录音数据发送。液晶显示屏上也有相应的显示,由于切换速度较快,具体细节参见后面的视频部分。

3.3 波形展示

通过软件打开形成的录音文件和上位软件采集的数据比对,是相同的。

上位软件实时显示的录音数据波形。

3.4 视频

1) RVB2601录音过程中,液晶显示屏上状态变化显示

2)下位机和上位机联调全过程视频

4、写在最后总结的话

通过本次的测试,体验到了国产RSIC-V的发展,尤其是平头哥的这款处理器,和CDK开发环境的组合,给我的感觉是丝般顺滑的开发过程。而且在遇到问题的时候,钉钉上的技术支持和网站上的工单问题解决方式,都非常有效率,非常不错的一次测试。

注:联调视频拍的不太好,主要是手机拍摄,画面范围小,而且一个人拍不太好操作。

本文源自:平头哥芯片开放社区

RVB2601开发板试用5——远程音频采集系统相关推荐

  1. 【平头哥RVB2601开发板试用体验】AT解析器和通过w800 AT命令接入阿里云生活物联网平台

    作者:niu 在RVB2601开发板上,CH2601主芯片通过SPI接口和W800 WIFi/BLE模块通信,W800芯片在此接口上提供AT命令的方式供主芯片使用W800的功能. 根据<W800 ...

  2. RVB2601开发板试用3——以太网通讯测试

    本文作者:我爱下载 1.概述 RVB2601中集成的CH2601通过W800提供了AT透传的wifi 功能,可以完成和外界进行数据交换的需要. 2.驱动描述 2.1 硬件接口原理 CH2601采用SP ...

  3. 【平头哥RVB2601开发板试用体验】I/O扩展

    一.概述 RVB2601是基于平头哥生态芯片CH2601的开发板,板载JTAG调试器,WiFi&BLE芯片W800,音频ADCES7210,音频DACES8156,128x64 OLED屏幕, ...

  4. RVB2601开发板试用2——PWM的使用,既三色小灯驱动

    本文作者:我爱下载 1.概述 RVB2601评估板包含RGB三基色LED一个,为了学习PWM信号的驱动,我们可以通过驱动三基色LED来完成. 2.硬件接口描述 通过如上两个原理图对照可知. 序号 LE ...

  5. 【平头哥RVB2601开发板试用体验】基于 HTTPClient 的云语音识别 1

    作者:哈猪猪 前言 本系列共有三篇文章,目的是在 RVB2601 上实现基于 HTTPClient 组件的云语音识别.文章连接与主要内容如下: 文章1:设计思路:HTTPClient 组件测试 文章2 ...

  6. 【平头哥RVB2601开发板试用体验】基于NTP的网络校时及WIFI驱动Bug调试

    作者:czxin NTP全称Network time Protocol,即网络时间协议,顾名思义就是通过与网络服务器之间通信来达到时间校准的协议,它是基于UDP的协议,记住这里的UDP,和后面遇到的W ...

  7. 【MM32F5270开发板试用】播放TF卡WAV格式音乐,I2S驱动CS4344

    [MM32F5270开发板试用]播放TF卡WAV格式音乐,I2S驱动CS4344 上四篇文章: [MM32F5270开发板试用]一.依靠SPI_SD,移植FatFs文件系统 [MM32F5270开发板 ...

  8. qt工程在linux系统里颜色显示错误_【飞凌嵌入式RK3399开发板试用体验】+QT开发环境搭建测试(二)...

    作者:飞扬的青春 在拿到开发板之后,已经体验了Android操作系统,接下来就是体验Linux下的开发,本次以QT的一个小案例来测试下. 首先是自己先搭建了一个Ubuntu18.04的虚拟机,使用真机 ...

  9. 鸿蒙开发板能干什么,【鸿蒙开发板试用报告】用OLED板实现FlappyBird小游戏(中)...

    小伙伴们久等了,在上一篇<[开发板试用报告]用OLED板实现FlappyBird小游戏(上)>中,我们本着拿来主义的原则,成功的让小鸟在OLED屏幕上自由飞翔起来,下面我们将加入按钮交互功 ...

最新文章

  1. 读自动驾驶激光雷达物体检测技术(Lidar Obstacle Detection)(2):点云滤波FilterCloud()函数
  2. 26个类型的常见面试精选总结(建议收藏)
  3. Linux驱动程序中的file,inode,file_operations三大结构体
  4. 终于看到了希望——基于美女的VGA系统构架
  5. QT实现太阳系系统八大行星
  6. RAC Failover三种方式
  7. Python中jmespath解析提取json数据
  8. 深度学习(五十八)caffe移植至mxnet
  9. 2.5 指数加权平均的偏差修正
  10. linux ping策略打开_Linux Iptables允许或阻止ICMP ping请求
  11. subsample downsample
  12. SharePoint 2007 在Windows Server 2008上列表Open with Windows Explorer失效 解决
  13. 华为微博抽奖头目两次中奖:大哥咱玩不起,不玩行不行?
  14. KitKat带来短信应用的改变
  15. Lua开发工具(IntelliJ IDE +EmmyLua 插件 )
  16. Mac苹果电脑怎么创建加密文件夹
  17. springMVC+mybatis
  18. Excel:计数相关的函数
  19. 【题目回顾】广工大2020年10月ACM第一次月赛B题--Dio的面包工坊
  20. 网易2018实习生招聘笔试题的收获

热门文章

  1. JS调用万维易源、聚合数据提供的接口获取7天天气预报
  2. 跟着官网学k8s-05运行应用程序的多个实例
  3. 基于Matlab模拟天气观测极化雷达回波(附源码)
  4. 奇葩!!!同为‘CST时区‘,java与mysql相差13个小时
  5. 【QlikView】No.1 QlikView概述
  6. TeX.Knuth有关的故事
  7. 通达信神奇牛熊主图指标公式
  8. Unity2D_鼠标拖动物体移动
  9. 3DMax怎么导出材质到unity?
  10. APP 图标生成工具