[RVB2601 Creative Application Development] Environmental Monitoring Terminal 04- Sound Collection and Dynamic Light Bar Display
[Copy link]
This article introduces how to use the microphone on the RVB2601 development board to collect surrounding sounds and record the maximum value per unit time to indicate the ambient noise level. For a more intuitive display, a dynamic light bar is designed on the OLED display that can dance with the rhythm of the sound .
1. Preparation
Before starting the project, the first thing to do is to consult the information and do the preparatory work. As a single-chip microcomputer system that has been launched for some time, there have been many experts on the Internet who have done experiments on sound. For my experiment, I first studied the article "Microphone Recording Test" written by "I Love Download " and started to work after understanding the principle of sound collection. The original post link is as follows.
https://occ.t-head.cn/community/post/detail?spm=a2cl5.26076654.0.0.56981f9cfBQl94&id=3945884479054815232
2. Hardware Principle
First, let me introduce the hardware principle. RVB2601 connects to ES7210 ADC chip through I2S and I2C bus to realize audio signal sampling of silicon microphone. The principle diagram is as follows.
Figure 1. Audio sampling principle
CH2601 uses I2C interface to complete the configuration of ES7210 and I2S interface to read the conversion data of ES7210. Its interface is shown in the figure.
Figure 2. Hardware interface
3. Software Design
The software driver design uses the CODEC codec library. CODEC here refers to a codec that has both D/A (digital signal converted to analog signal) and A/D (analog signal converted to digital signal) conversion functions. The D/A conversion function is used when playing music. The A/D conversion function is used when recording. For detailed introduction and usage methods, please see the official link below.
https://yoc.docs.t-head.cn/yocbook/Chapter3-AliOS/CSI%E8%AE%BE%E5%A4%87%E9%A9%B1%E5%8A%A8%E6%8E% A5%E5%8F%A3/CSI2/CODEC.html
In the interface, D/A refers to the output channel, and A/D refers to the input channel. This experiment mainly uses the input channel of AD . The CSI interface of the CODEC used is as follows:
Figure 3. Software interface
4. Code writing
Download the official example ch2601_ft_demo and intercept the recording code. Because this application only needs the sound amplitude, the code is greatly reduced and modified, the cache is reduced, and only one sampling cycle is retained. After each sampling, the maximum value of the audio data in this cycle is calculated, and this result is used as the real-time volume data to be output. It can be printed out through the serial port or passed to other tasks for display. The audio sampling code is as follows.
#include <stdlib.h>
#include <aos/aos.h>
#include "board_config.h"
#include "drv/codec.h"
#include "drv/dma.h"
#include <drv/ringbuffer.h>
#include "snd_get.h"
csi_codec_t codec;
csi_codec_input_t codec_input_ch;
csi_dma_ch_t dma_ch_input_handle;
#define INPUT_BUF_SIZE 2048
uint8_t input_buf[INPUT_BUF_SIZE];
ringbuffer_t input_ring_buffer;
volatile uint32_t cb_input_transfer_flag = 0;
int16_t sound_buff[512];
volatile int16_t sound_max=0;
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;
}
}
void cmd_ft_mic_handler(uint32_t channel_status)
{
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 sound get\n");
csi_codec_input_start(&codec_input_ch);
while (1)
{
if (cb_input_transfer_flag)
{
csi_codec_input_read_async(&codec_input_ch, sound_buff, 1024);
cb_input_transfer_flag = 0U;
sound_max=0;
int ii=0;
while(ii < 512)
{
if(sound_max < sound_buff[ii])
{
sound_max = sound_buff[ii];
}
ii++;
}
// printf("max sound:%d\n",sound_max);
}
aos_msleep(10);
}
return;
}
The figure below shows the real-time volume data printed out by the serial port. I spoke into the microphone at different volumes and found that the actual data is around 30 at the minimum and 32767 at the maximum. The average noise floor is around 50.
Figure 4: Serial port output volume
5. Dynamic light strip realization
The serial port data is not very intuitive, so I modified the display program to display the volume changes in real time on the OLED screen.
Since I tested this board at night most of the time, it was quite dazzling to see the OLED screen when it was fully lit. In order to make it look more comfortable, increase the screen life and reduce power consumption, I made some changes to the underlying display program and inverted the colors, which made it look more comfortable. Specifically, I modified the dot drawing function in the oled.c file. The code is as follows.
void oled_draw_point(uint8_t r, uint8_t c, uint8_t t)
{
if (t) {
CLR_BIT(g_oled_ram[r / 8][c], ((r % 8)));
} else {
SET_BIT(g_oled_ram[r / 8][c], (r % 8));
}
// if (t) {
// SET_BIT(g_oled_ram[r / 8][c], ((r % 8)));
// } else {
// CLR_BIT(g_oled_ram[r / 8][c], (r % 8));
// }
}
Then we designed the dynamic light bar code. The idea is to follow the nesting doll method. First, draw a larger positive color rectangle to display the border; then draw a smaller negative color rectangle as the background; finally, use the quantized volume value as a parameter and pass it in as the length to draw the third positive color rectangle, thus realizing the light bar design. When calling continuously, the length of the light bar changes with the value passed in, thus realizing the dynamic light bar design. The specific code is as follows.
//num_p = 1...100
void oled_draw_bar(uint8_t num_p)
{
unsigned char i, j, k;
for (i = 54; i < 64; i++) {
for (j = 0; j < 128; j++) {
oled_draw_point(i, j, 0);
}
}
for (i = 55; i < 63; i++) {
for (j = 1; j < 127; j++) {
oled_draw_point(i, j, 1);
}
}
k = num_p * 124 / 100;
for (i = 56; i < 62; i++) {
for (j = 2; j < k; j++) {
oled_draw_point(i, j, 0);
}
}
oled_reflesh();
}
When different values are passed in, the dynamic effect of the light bar is as follows.
Figure 5. Dynamic light bar effect
Then create a task in the main function, associate the dynamic light bar with the sound sampling, and you can achieve the effect of a dynamic light bar that dances with the music. The code is as follows.
/*
* Copyright (C) 2019-2020 Alibaba Group Holding Limited
*/
#include <stdlib.h>
#include <string.h>
#include <aos/aos.h>
#include "aos/cli.h"
#include "main.h"
#include "app_init.h"
#include "oled.h"
#include "snd_get.h"
#define TAG "app"
static void snd_get_task(void *arg);
extern int16_t sound_max;
int main(void)
{
int i=0;
board_yoc_init();
aos_task_new("snd", snd_get_task, NULL, 10 * 1024);
LOGD(TAG, "%s\n", aos_get_app_version());
oled_init();
while (1)
{
aos_msleep(100);
i = sound_max /20;
i++;
if(i>100) i=100;
printf("%d\n",i);
oled_draw_bar( i);
}
return 0;
}
static void snd_get_task(void *arg)
{
cmd_ft_mic_handler(0);
}
The final music light bar effect is shown in the following video. The audio data collected is relatively large, so in order to make the effect more obvious at normal volume, I did some simple processing, but the light bar will appear saturated when the sound is very loud. For better results, you can perform a first-order high-pass digital filter on the original data, and only intercept the high-frequency fluctuation part for display, so that it can adapt to a wider volume range.
Figure 6: Music light bar
Finally, I transplanted the sound acquisition code to the display interface introduced in my previous article. From the video below, you can see that the real-time response effect is a little delayed, which is caused by insufficient refresh of LVGL. However, in my expected application, the impact is not significant, because I expect to upload the average value once more than one second, and the real-time requirement is not high.
Figure 7. Displaying volume in LVGL
This experiment mainly collects and displays sound from a qualitative perspective, without quantitative calibration. If a decibel meter can be obtained later, you can try to calibrate the sound collection part, and the decibel value of the volume can be displayed more accurately.
|