6.1.5. 设计指南¶
6.1.5.1. 源码说明¶
源代码位于:
bsp/artinchip/drv/audio/drv_audio.c: Playback的driver层驱动
bsp/artinchip/drv/audio/drv_dmic.c: DMIC的driver层驱动
bsp/artinchip/drv/audio/drv_amic.c: AMIC的driver层驱动
bsp/artinchip/hal/audio/hal_audio.c: audio模块的hal层驱动
bsp/artinchip/include/hal/hal_audio.h: audio模块的hal层头文件
bsp/artinchip/include/hal/hal_audio_reg.h: audio模块的hal层头文件,用于寄存器定义
6.1.5.2. 模块架构设计¶
6.1.5.2.1. RT-Thread audio框架¶
RT-Thread定义了一套音频框架,driver层的驱动就是为了对接该音频框架。该框架在录音端和播放端采用了两种不同的机制,现对录音端和播放端的框架进行简单说明。
6.1.5.2.1.1. 播放端框架¶

如上图所示,应用层读取的音频数据写入到内存池的block中,并用数据队列对内存池的block数据进行管理。从数据队列中依次取出音频数据,写入到audio buffer中,audio buffer在原理上是一个环形缓冲区,最后通过DMA将音频数据写入到硬件的TXFIFO中。所以,playback端的driver层驱动主要是负责audio buffer环形缓冲区的管理,及时写入音频数据,并用DMA搬运到audio硬件。
6.1.5.2.1.2. 录音端框架¶

如上图所示,RT-Thread audio框架在录音端的设计与播放端不同。在录音端框架虚拟了一个pipe设备,其实就是一个ringbuffer,读写pipe设备就是对ringbuffer的读写。driver层驱动负责管理一个RX buffer,RX buffer在逻辑上也是一个环形缓冲区。DMA负责将MIC端接收到的数据搬运到RX buffer,再通过写pipe设备将音频数据写入到pipe的ringbuffer中。应用层代码则通过 rt_device_read
每次从pipe设备中读取音频数据,再将音频数据写入到wav文件。
6.1.5.3. 关键流程设计¶
6.1.5.3.1. 初始化流程¶
初始化audio模块时钟频率
释放reset和clock信号
注册音频设备,playback端注册为
sound0
设备,DMIC注册为dmic0
设备,AMIC注册为amic0
设备
6.1.5.3.2. playback流程¶
6.1.5.3.2.1. init流程¶
初始化DMA传输的起始地址,buf_len以及period_len
注册hal层的回调函数
audio模块使用DMA传输音频数据,DMA采用环形链表形式,依次将音频数据传送到硬件。所以需要配置DMA传输时的起始地址(即TX buffer地址)以及buf_len,period_len。在driver层驱动,将buf_len配置为period_len的4倍,DMA每传输period_len长度的数据,触发一次DMA中断,通知CPU向TX buffer中写入数据。
6.1.5.3.2.2. start流程¶
根据menuconfig配置音频通路
填充TX buffer
设置DMA传输的参数,调用
hal_audio_playback_start
开始音频数据传输使能PA
为保证DMA传输音频数据的连续性,需要在DMA开始传输前,先向TX buffer中填充数据。在playback的driver层驱动,是将TX buffer填充满后,才开始DMA的传输。
6.1.5.3.2.3. DMA中断流程¶
DMA每传输完period_len长度的数据后,触发一次DMA中断,然后通过DMA回调函数的逐级调用,最终调用 rt_audio_tx_complete
对TX buffer进行填充,每次填充period_len长度的音频数据。
6.1.5.3.3. record流程¶
6.1.5.3.3.1. init流程¶
初始化DMA传输的起始地址,buf_len以及period_len
注册hal层的回调函数
audio模块使用DMA传输音频数据,DMA采用环形链表形式,依次将音频数据传送到硬件。所以需要配置DMA传输时的起始地址(即RX buffer地址)以及buf_len,period_len。在driver层驱动,将buf_len配置为period_len的2倍,DMA每传输period_len长度的数据,触发一次DMA中断,通知CPU向pipe设备写入数据。
6.1.5.3.3.2. start流程¶
按照RT-Thread audio的框架,在执行 rt_device_open
时,就会调用start流程,开始音频的录制,然后再通过 rt_device_control
设置音频的格式(采样率,通道数等)。按照这个流程,最开始可能会录制一段不符合设置的音频格式的数据,这显然是不合理的。所以,在driver层的驱动实现中,start流程并未做任何处理,而是在设置完音频格式后才开始音频的录制。
6.1.5.3.3.3. DMA中断流程¶
DMA每传输完period_len长度的数据后,触发一次DMA中断,然后通过DMA回调函数的逐级调用,最终调用 rt_audio_rx_done
,将RX buffer的数据写入到pipe设备,每次写入period_len长度的音频数据。
6.1.5.4. 数据结构设计¶
6.1.5.4.1. hal层数据结构¶
struct aic_audio_buf_info
{
void *buf;
uint32_t buf_len;
uint32_t period_len;
};
struct aic_audio_transfer_info
{
struct aic_dma_chan *dma_chan;
struct aic_audio_buf_info buf_info;
int transfer_type;
};
struct aic_audio_ctrl
{
unsigned long reg_base;
uint32_t irq_num;
uint32_t clk_id;
struct aic_audio_transfer_info tx_info; //TX buffer的参数
struct aic_audio_transfer_info dmic_info; //DMIC RX buffer的参数
struct aic_audio_transfer_info amic_info; //AMIC RX buffer的参数
audio_callback callback;
void *arg;
struct aic_audio_config config;
};
6.1.5.4.2. driver层数据结构¶
struct aic_audio
{
struct rt_audio_device audio;
aic_audio_ctrl codec;
rt_uint8_t volume; //playback音量
char *pa_name; //PA引脚的名字
unsigned int gpio_pa; //PA引脚的IO口号
};
struct aic_dmic
{
struct rt_audio_device audio;
aic_audio_ctrl codec;
rt_uint8_t volume;
uint8_t index;
};
6.1.5.5. 接口设计¶
6.1.5.5.1. driver层接口设计¶
driver层将audio定义为 sound0
, dmic0
, amic0
三个设备,三个设备在driver层的接口基本相同,下面以playback端的接口进行说明。
6.1.5.5.1.1. drv_audio_init¶
函数原型 |
rt_err_t drv_audio_init(struct rt_audio_device *audio) |
---|---|
功能说明 |
playback端的初始化函数 |
参数定义 |
audio:指向playback设备的指针 |
返回值 |
RT_EOK:执行成功 |
注意事项 |
6.1.5.5.1.2. drv_audio_buffer_info¶
函数原型 |
void drv_audio_buffer_info(struct rt_audio_device *audio, struct rt_audio_buf_info *info) |
---|---|
功能说明 |
获取playback端的TX buffer参数 |
参数定义 |
audio:指向playback设备的指针
info:用于获取TX buffer参数的指针
|
返回值 |
无 |
注意事项 |
6.1.5.5.1.3. drv_audio_start¶
函数原型 |
rt_err_t drv_audio_start(struct rt_audio_device *audio, int stream) |
---|---|
功能说明 |
开始playback端播放 |
参数定义 |
audio:指向playback设备的指针
stream:音频数据流方向
|
返回值 |
RT_EOK:执行成功
-RT_EINVAL:参数非法
|
注意事项 |
6.1.5.5.1.4. drv_audio_stop¶
函数原型 |
rt_err_t drv_audio_stop(struct rt_audio_device *audio, int stream) |
---|---|
功能说明 |
结束playback端播放 |
参数定义 |
audio:指向playback设备的指针
stream:音频数据流方向
|
返回值 |
RT_EOK:执行成功
-RT_EINVAL:参数非法
|
注意事项 |
6.1.5.5.1.5. drv_audio_pause¶
函数原型 |
rt_err_t drv_audio_pause(struct rt_audio_device *audio, int enable) |
---|---|
功能说明 |
暂停/恢复playback端播放 |
参数定义 |
audio:指向playback设备的指针
enable:playback端暂停和恢复播放使能位(0为恢复,非0为暂停)
|
返回值 |
RT_EOK:执行成功
|
注意事项 |
6.1.5.5.1.6. drv_audio_configure¶
函数原型 |
rt_err_t drv_audio_configure(struct rt_audio_device *audio, struct rt_audio_caps *caps) |
---|---|
功能原型 |
音频设备配置接口,用于配置采样格式,采样率,通道数等接口 |
参数定义 |
audio:指向playback设备的指针
caps:指向配置参数的指针
|
返回值 |
RT_EOK:执行成功
-RT_ERROR:参数不支持
|
注意事项 |
6.1.5.5.1.7. drv_audio_getcaps¶
函数原型 |
rt_err_t drv_audio_getcaps(struct rt_audio_device *audio, struct rt_audio_caps *caps) |
---|---|
功能说明 |
获取音频设备的参数 |
参数定义 |
audio:指向playback设备的指针
caps:指向配置参数的指针
|
返回值 |
RT_EOK:执行成功
-RT_ERROR:参数不支持
|
注意事项 |
6.1.5.5.1.8. drv_audio_get_playback_avail¶
函数原型 |
rt_size_t drv_audio_get_playback_avail(struct rt_audio_device *audio) |
---|---|
功能说明 |
获取playback端缓存的数据大小 |
参数定义 |
audio:指向playback设备的指针
|
返回值 |
缓存数据的大小
|
注意事项 |
6.1.5.5.1.9. hal层接口设计¶
hal层接口也是分playback、DMIC、AMIC三部分进行设计,下面以playback端的接口进行说明。
6.1.5.5.1.10. hal_audio_set_samplerate¶
函数原型 |
void hal_audio_set_samplerate(aic_audio_ctrl *codec, uint32_t samplerate) |
---|---|
功能说明 |
设置采样率 |
参数定义 |
codec:指向aic_audio_ctrl的指针
samplerate:采样率
|
返回值 |
无 |
注意事项 |
6.1.5.5.1.11. hal_audio_set_playback_channel¶
函数原型 |
void hal_audio_set_playback_channel(aic_audio_ctrl *codec, uint32_t ch) |
---|---|
功能说明 |
设置playback端的通道数 |
参数定义 |
codec:指向aic_audio_ctrl的指针
ch:通道数
|
返回值 |
无 |
注意事项 |
6.1.5.5.1.12. hal_audio_set_playback_by_spk0¶
函数原型 |
void hal_audio_set_playback_by_spk0(aic_audio_ctrl *codec) |
---|---|
功能说明 |
配置SPK0音频通路 |
参数定义 |
codec:指向aic_audio_ctrl的指针
|
返回值 |
无 |
注意事项 |
6.1.5.5.1.13. hal_audio_set_playback_by_spk1¶
函数原型 |
void hal_audio_set_playback_by_spk1(aic_audio_ctrl *codec) |
---|---|
功能说明 |
配置SPK1音频通路 |
参数定义 |
codec:指向aic_audio_ctrl的指针
|
返回值 |
无 |
注意事项 |
6.1.5.5.1.14. hal_audio_playback_start¶
函数原型 |
void hal_audio_playback_start(aic_audio_ctrl *codec) |
---|---|
功能说明 |
开始播放 |
参数定义 |
codec:指向aic_audio_ctrl的指针
|
返回值 |
无 |
注意事项 |
6.1.5.5.1.15. hal_audio_playback_stop¶
函数原型 |
void hal_audio_playback_stop(aic_audio_ctrl *codec) |
---|---|
功能说明 |
结束播放 |
参数定义 |
codec:指向aic_audio_ctrl的指针
|
返回值 |
无 |
注意事项 |