[TOC]

RT-Thread Studio配置WAV音频

1.前言说明

1.1本章内容

本次测评AB32VG1音频输出,从内部Flash读取Wav音频进行播放,按键控制音频的切换

1.2模块介绍

开发板板载一个3.5mm的音频接口,接口是直连芯片的DAC输出和一个麦克风输入采样和收音机天线

20210531183935

原理图如下

微信图片_20210316215932.png

芯片音频特性:

  • 具有16位立体声DAC和两个通道16位ADC的音频编解码器。
  • 支持灵活的音频EQ调节,支持8、11.025、12、16、22.05、32、44.1和48khz的采样率。
  • 4通道立体声模拟MUX。
  • 双通道MIC放大器输入。
  • 具有90dB信噪比的高性能立体声ADC。
  • 高性能立体声音频DAC,带95dBSNR,带耳机放大器输出。

1.3开发软件

20210318172331.png

编译平台:RT-Thread Studio: 安装链接

下载平台:Downloader: 安装链接

2.步骤说明

2.1 新建工程

点击 文件-> 新建-> RT-Thread项目控件

20210209213346.png

选择基于开发板的项目,填写工程名字,选择我们使用到的开发板(AB32VG1),调试器我们随便选,下载方式不是通过此处下载

20210531181847

注意:如果第一次使用RISC-V芯片需要安装工具链,在SDK管理器中下载工具链

20210318193859.png

然右击项目名称,进入属性

20210531182155

找到MCU->RISC-V ToolchainsPat ,配置Tool的环境,在软件安装位置下面的路径中

1
软件安装位置\RT-ThreadStudio\repo\Extract\ToolChain_Support_Packages\RISC-V\RISC-V-GCC\10.1.0\bin

20210531182445

工程新建后左边的项目资源管理器会显示我们的工程,我们把他展开,点击小锤子图标编译一下,编译结果如下

20210531182515

编译无报错,新建工程完成了!

2.2 RT-Thread Studio配置Audio

点击RT Thread Setting -> 添加软件包

20210531184148

依次添加multibutton、wavplayer、optoarse三个软件包

20210531184318

点击更多配置 -> 进入软件包 -> 配置使用的软件包

optparse是WavPlay软件包依赖,因此optparse软件包在 wavplayer 勾选后,自动选择。optparse模块主要用来为脚本传递命令参数,采用预先定义好的选项来解析命令行参数,所以我吗只要配置WavPlay软件包就行

  1. wavplayer wav播放软件包安装

20210531184824

点击硬件->Enable Audio Device使能硬件

20210601100817

  1. multibutton 多按键软件包安装

20210531185021

使能虚拟文件系统DFS,开启Ulog调试日志

20210601094441

点击组件->设备虚拟文件系统->使能Flash上只读文件系统(ROMFS)

20210601105908

点击保存,使RT Thread的配置生效,下一步进入代码修改

2.2 代码编写

首先需要下载 romfs.c(本文件包含了两个音频文件用于demo播放)放到applications 下:下载地址

然后需要注意的一点是,需要修改mnt.c的内容,对ROMFS进行挂载,在mnt文件中添加下面代码即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <dfs_fs.h>
#include "dfs_romfs.h"

int mnt_init(void)
{
if (dfs_mount(RT_NULL, "/", "rom", 0, &(romfs_root)) == 0)
{
rt_kprintf("ROM file system initializated!\n");
}
else
{
rt_kprintf("ROM file system initializate failed!\n");
}

return 0;
}
INIT_ENV_EXPORT(mnt_init);

然后在 applications 下新建 event_async.c 文件,编写以下代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
//头文件包含
#include <rtthread.h>
#include <rtdevice.h>
#include "board.h"
#include <multi_button.h>
#include "wavplayer.h"
//按键获取
#define BUTTON_PIN_0 rt_pin_get("PF.0")
#define BUTTON_PIN_1 rt_pin_get("PF.1")
//按键编号
#define NUM_OF_SONGS (2u)
//按键结构体
static struct button btn_0;
static struct button btn_1;

static uint32_t cnt_0 = 0;
static uint32_t cnt_1 = 0;
//音乐名称
static char *table[2] =
{
"wav_1.wav",
"wav_2.wav",
};

void saia_channels_set(uint8_t channels);
void saia_volume_set(rt_uint8_t volume);
uint8_t saia_volume_get(void);

按键驱动编写

1
2
3
4
5
6
7
8
9
10
//读取按键驱动
static uint8_t button_read_pin_0(void)
{
return rt_pin_read(BUTTON_PIN_0);
}

static uint8_t button_read_pin_1(void)
{
return rt_pin_read(BUTTON_PIN_1);
}

按键0回调函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
//按键0回调函数
static void button_0_callback(void *btn)
{
uint32_t btn_event_val;

btn_event_val = get_button_event((struct button *)btn);

switch(btn_event_val)
{
case SINGLE_CLICK:
if (cnt_0 == 1) {
saia_volume_set(30);
}else if (cnt_0 == 2) {
saia_volume_set(50);
}else {
saia_volume_set(100);
cnt_0 = 0;
}
cnt_0++;
rt_kprintf("vol=%d\n", saia_volume_get());
rt_kprintf("button 0 single click\n");
break;

case DOUBLE_CLICK:
if (cnt_0 == 1) {
saia_channels_set(1);
}else {
saia_channels_set(2);
cnt_0 = 0;
}
cnt_0++;
rt_kprintf("button 0 double click\n");
break;

case LONG_RRESS_START:
rt_kprintf("button 0 long press start\n");
break;

case LONG_PRESS_HOLD:
rt_kprintf("button 0 long press hold\n");
break;
}
}

按键1回调函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
//按键1回调函数
static void button_1_callback(void *btn)
{
uint32_t btn_event_val;

btn_event_val = get_button_event((struct button *)btn);

switch(btn_event_val)
{
case SINGLE_CLICK:
wavplayer_play(table[(cnt_1++) % NUM_OF_SONGS]);
rt_kprintf("button 1 single click\n");
break;

case DOUBLE_CLICK:
rt_kprintf("button 1 double click\n");
break;

case LONG_RRESS_START:
rt_kprintf("button 1 long press start\n");
break;

case LONG_PRESS_HOLD:
rt_kprintf("button 1 long press hold\n");
break;
}
}

任务实体

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
//按键任务实体
static void btn_thread_entry(void* p)
{
while(1)
{
/* 5ms */
rt_thread_delay(RT_TICK_PER_SECOND/200);
button_ticks();
}
}
//按键初始化
static int multi_button_test(void)
{
rt_thread_t thread = RT_NULL;

/* Create background ticks thread */
thread = rt_thread_create("btn", btn_thread_entry, RT_NULL, 1024, 10, 10);
if(thread == RT_NULL)
{
return RT_ERROR;
}
rt_thread_startup(thread);

/* low level drive */
rt_pin_mode (BUTTON_PIN_0, PIN_MODE_INPUT_PULLUP);
button_init (&btn_0, button_read_pin_0, PIN_LOW);
button_attach(&btn_0, SINGLE_CLICK, button_0_callback);
button_attach(&btn_0, DOUBLE_CLICK, button_0_callback);
button_attach(&btn_0, LONG_RRESS_START, button_0_callback);
button_attach(&btn_0, LONG_PRESS_HOLD, button_0_callback);
button_start (&btn_0);

rt_pin_mode (BUTTON_PIN_1, PIN_MODE_INPUT_PULLUP);
button_init (&btn_1, button_read_pin_1, PIN_LOW);
button_attach(&btn_1, SINGLE_CLICK, button_1_callback);
button_attach(&btn_1, DOUBLE_CLICK, button_1_callback);
button_attach(&btn_1, LONG_RRESS_START, button_1_callback);
button_attach(&btn_1, LONG_PRESS_HOLD, button_1_callback);
button_start (&btn_1);

return RT_EOK;
}
//添加到系统初始化
INIT_APP_EXPORT(multi_button_test);

编译一下,无报错

20210601115937

3.代码验证

demo编写完成后,单击编译按钮开始编译,编译成功后下载编译后生成的 .dcf 固件到芯片;

双击打开Downloader v1.9.7。

../_images/5.png

下载成功后会在串口界面打印”Hello World”, 并会有led灯闪烁

../_images/6.png

此时按下按键S2,会播放第一首音乐,再次按下,播放下一首音乐,依次循环,并且打印信息到调试终端

../_images/7.png

4.章节总结

得益于RT-Thread丰富的软件层与中间件,音频开发基本上不需要用户过多操作,在不知道芯片的底层原理的情况下仍能开发音频应用,只需要少量代码将功能整合起来即可,使用起来非常的方便快捷,大大提高了开发效率。

wechat