Skip to content

由 爱笑 贡献,Ai-Thinker 进行整理

【Ai-WB2中级篇】DAC数模转换

数模转换器(diaital-to-anal0g converter,通常称为DAC)是一种数字与模拟转换器,FIFO深度为1,支持2路DAC调制输出。可用于音频播放,常规的模拟信号调制。 本文将详细介绍如何使用Ai-WB2的DAC模块播放音频

📜 点击展开完整代码
c
**一:DAC介绍**
BL602芯片内置一个10bits的数字模拟转换Q器(DAC),FIFO深度为1,支持2路DAC调制输出。 可用于音频播放,变送器电压调制。其特性如下:
**·** DAC调制精度为10-bits
**·** DAC的输入时钟可选为32k、16k8k或512k
**·** 支持DMA将内存搬运至DAC调制寄存器
**·** 支持双声道播放DMA搬运模式
**·** DAC的输出引脚固定为ChannelA为GPI013,Channel为GPI014

DAC的基本功能框图如下:

📜 点击展开完整代码
c
**·** DAC模块支持最多两路调制输出
**·** DAC模块支持双声道DMA数据搬运模式
**·** DAC模块支持长度为32-bit的DMA数据接口,其中高16位将会调制在ChannelA的引脚上,低16位调制在ChannelB引脚
**二:DAC驱动API介绍**

DAC的HOSAL层驱动API在文件 components/platform/hosal/include/hosal_dac.h 中定义,常用的AP!如下: · int hosal_dac_init(hosal_dac_dev_t *dac):初始化DAC。参数说明如下: · dac:DAC设备实例。其定义如下:

📜 点击展开完整代码
c
typedef struct {
uint8_t  port;                    /**< @brief dac id */
hosal_dac_config_t config;        /**< @brief dac config */
hosal_dac_cb_t cb;                /**< @brief dma callback */
hosal_dma_chan_t dma_chan;        /**< @brief dac dma channel */
void    *arg;                     /**< @brief arg data */
void    *priv;                    /**< @brief priv data */
} hosal_dac_dev_t;

其中,hosal_dac_config_t为DAC配置,其定义如下:

📜 点击展开完整代码
c
typedef struct {
uint8_t  dma_enable;        /**< @brief 1: use dma, 0: no dma */
uint32_t  pin;              /**< @brief dac pin */
uint32_t  freq;             /**< @brief dac freq */
} hosal_dac_config_t;

hosal _dac_cb_t为DAC回调函数,定义如下:

  1. typedef void (*hosal_dac_cb_t)(void *arg)
📜 点击展开完整代码
c
**·** 返回值:成功时,返回0;否则返回非零值
**·** int hosal_dac_finalize(hosal_dac_dev_t *dac):销毁DAC实例并释放相关资源。参数说明如下:
**·** dac:DAC设备实例。
**·** 返回值:成功时,返回0;否则返回非零值
**·** int hosal_dac_start(hosal_dac_dev_t *dac):启动DAC。参数说明如下:
**·** dac:DAC设备实例。
**·** 返回值:成功时,返回0;否则返回非零值
**·** int hosal_dac_stop(hosal_dac_dev_t *dac):停止DAC。参数说明如下:
**·** dac:DAC设备实例。
**·** 返回值:成功时,返回0;否则返回非零值
**·** int hosal_dac_set_value(hosal_dac_dev_t *dac,uint32_t data):设置DAC输出电压,单位为UV。参数说明如下:
**·** dac:DAC设备实例。
**·** data:输出电压大小。单位为V。比如输出1V,则参数的值为1000000。返回值:成功时,返回0;否则返回非零值
**·** int hosal_dac_get_value(hosal_dac_dev_t *dac):査询最新的DAC端口输出电压值。单位为V。参数说明如下:
**·** dac:DAC设备实例。
**·** 返回值:返回最新电压值
**·** int hosal_dac_dma_cb_reg(hosal_dac_dev_t *dac, hosal_dac_cb_t callback, void *arg):注册DMA模式下的回调函数。参数说明如下:
**·** dac:DAC设备实例。
**·** callback:回调函数
**·** arg:回调函数参数
**·** 返回值:成功时,返回0;否则返回非零值
**·** int hosal_dac_dma_start(hosal_dac_dev_t *dac, uint32_t *data, uint32_t size):启动DMA方式输出。参数说明如下:
**·** dac:DAC设备实例。
**·** data:需要传输的数据
**·** size:数据长度
**·** 返回值:成功时,返回0;否则返回非零值
**·** int hosal_dac_dma_stop(hosal_dac_dev_t *dac):停止DMA传输。参数说明如下:
**·** dac:DAC设备实例。
**·** 返回值:成功时,返回0;否则返回非零值

另外,HAL层的驱动API位于components/platform/hosal/b1602_hal/bl_dac.h 。 三:音频数据转换1. 音频格式转换 由于DAC不支持WAV、MP3等音频数据解码,因此需要将这些格式的音频数据转换成RAW格式数据或PCM数据。下面以WAV格式音频为例,详细介绍如何将WAV格式音频数据转换成C语言数组。

📜 点击展开完整代码
c
**第一步,准备软件工具:**
**·** 下载并安装音频处理工具软件:[Audacity](https://www.audacityteam.org/)
**·** 下载并安装:[bin2c工具软件](https://sourceforge.net/projects/bin2c/)
**第二步,将音频数据转换成raw格式音频数据。**

1 ) 启动 Audacitya 并加载WAV格式音频文件

2 ) 重采样。由于BL602的DAC最大支持32K的采样率,最小支持8K采样率,因此需要在这范围内进行重新采样。

注意:如果音频有多个声道,则需要合并成单个声道或删除多声道 3 ) 导出RAW格式音频文件

2. 音频数据生成C数组 在生成C数组之前,需要进一步转换RAW格式数据。下面为BL602提供的一个Python脚本:

📜 点击展开完整代码
c
import os
import sys
import numpy as np
import math
if __name__ == "__main__":
data_list_deal = []
path =  sys.argv[1]
path_save = sys.argv[2]
bytes_num = os.path.getsize(path)
save_file = open(path_save, "wb")
with open(path, 'rb') as f:
for i in range(bytes_num // 2):
data = f.read(2)
data_int = int.from_bytes(data, byteorder='little', signed=True)
data_int = int((data_int +32768 ) * 0.0156099794003204)
new_data = data_int.to_bytes(2, byteorder='little', signed=False)
save_file.write(new_data)
save_file.write(new_data)
save_file.close()

在命令行中运行Python脚本:       python test.raw test.bin 最后,使用 bin2c 工具转换成C语言数组:

  1. bin2c.exe --const test.bin > test.h

生成的内容如下:

📜 点击展开完整代码
c
#ifdef __cplusplus
extern "C" {
#endif
const unsigned char imageBytes[] = {
0x80,0x44,0x30,0xec,0xa0,0xb3,0x16,0xe3,0x40,0xf0,0x78,0xe4,0x40,0x6a,0x31,0xde,
0x00,0x88,0x11,0xd7,0xc0,0xb3,0xf0,0xd9,0x00,0xfb,0xa1,0xdb,0x80,0x3b,0x00,0xdc,
0x00,0x23,0x83,0xdf,0x40,0xea,0xf6,0xdc,0x40,0x19,0x68,0xd5,0x40,0xb2,0x68,0xcf,
0x00,0x47,0x55,0xc9,0x00,0xed,0x82,0xc8,0x80,0x7e,0x57,0xcd,0x00,0xe9,0x35,0xcc,
0x80,0x28,0xee,0xc6,0x80,0x00,0x41,0xc4,0x40,0xa0,0x35,0xc1,0x40,0x16,0x79,0xc0,
....
0xf0,0xeb,0xad,0xfb,0xb0,0xff,0x92,0xf5,0x60,0xcc,0x30,0xf6,0x00,0xe5,0xf7,0xf9,
0x34,0x89,0xe2,0xfc,0x52,0x31,0xcd,0x01,0xe0,0x90,0x58,0x03,0x58,0xb0,0x5f,0xfc,
0xf0,0xde,0x64,0xf8
};
#ifdef __cplusplus
}
#endif

生成的数据每行16个数据,可以根据行数计算数据长度。或者在代码中通过( sizeof )来计算数组长度。生成的数组名称可以根据需要更改。 四:DAC使用示例

📜 点击展开完整代码
c
#include <stdio.h>
#include <string.h>
#include <FreeRTOS.h>
#include <task.h>
#include <stdio.h>
#include <stdbool.h>
#include <hosal_wdg.h>
#include <blog.h>
#include "hosal_dac.h"
#include "audio_data.h"
#define TAG "dac_demo"
#define DAC_PIN         14
static hosal_dac_dev_t dac0;
/* dac dma callback */
static void user_cb(void *arg)
{
hosal_dac_dev_t *dac = (hosal_dac_dev_t *)arg;
hosal_dac_dma_stop(dac);
hosal_dac_finalize(dac);
blog_info("success\r\n");
}
void dac_demo_init(void)
{
int ret = 0;
uint32_t *p_u32addr;
uint32_t bufsize;
dac0.port = 0;                   /* only one dac,so port must be 0 */
dac0.config.dma_enable = 1;
dac0.config.pin = DAC_PIN;              /* for 602 :only two channel:0-->channel A -->gpio13, 1-->channel B-->gpio14 */
/* for 702 :only two channel:0-->channel A -->gpio11, 1-->channel B-->gpio17*/
dac0.config.freq = 32000;               /* if you play audio ,freq must same as audio sample rate ,only support 8k,16k,32k */
p_u32addr = (uint32_t *)audio_32k;
bufsize = (uint32_t)audio_32k_len;
hosal_dma_init();
ret = hosal_dac_init(&dac0);
if (ret != 0) {
hosal_dac_finalize(&dac0);
blog_error("dac init failed \r\n");
return;
}
hosal_dac_dma_cb_reg(&dac0, user_cb, &dac0);
ret = hosal_dac_dma_start(&dac0, p_u32addr, bufsize);
if (ret != 0) {
hosal_dac_finalize(&dac0);
blog_error("dac start failed \r\n");
return;
}
}
void main(void) {
dac_demo_init();
}

注意:请将喇叭外接功放或直接连接DAC引I脚

Released under the MIT License. Build Time 2026-09-11 14:52:23