Skip to content

Contributed by 爱笑, organized by Ai-Thinker

[Ai-WB2 Intermediate] DAC Digital-to-Analog Conversion

A digital-to-analog converter (DAC) is a device that converts digital signals to analog signals. It has a FIFO depth of 1 and supports 2 channels of DAC modulation output. It can be used for audio playback and general analog signal modulation. This article will detail how to use the Ai-WB2 DAC module to play audio.

Click to expand full code
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

The basic functional block diagram of the DAC is as follows:

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

The HOSAL-layer driver API of the DAC is defined in components/platform/hosal/include/hosal_dac.h. The commonly used APIs are as follows: · int hosal_dac_init(hosal_dac_dev_t *dac): Initialize the DAC. Parameter description: · dac: DAC device instance. It is defined as follows:

Click to expand full code
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;

Among them, hosal_dac_config_t is the DAC configuration, defined as follows:

Click to expand full code
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 is the DAC callback function, defined as follows:

  1. typedef void (*hosal_dac_cb_t)(void *arg)
Click to expand full code
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;否则返回非零值

In addition, the HAL-layer driver API is located at components/platform/hosal/bl602_hal/bl_dac.h. 3. Audio Data Conversion1. Audio Format Conversion Since the DAC does not support decoding audio data in formats such as WAV and MP3, audio data in these formats needs to be converted into RAW format data or PCM data. Taking WAV format audio as an example, the following details how to convert WAV format audio data into a C array.

Click to expand full code
c
**第一步,准备软件工具:**
**·** 下载并安装音频处理工具软件:[Audacity](https://www.audacityteam.org/)
**·** 下载并安装:[bin2c工具软件](https://sourceforge.net/projects/bin2c/)
**第二步,将音频数据转换成raw格式音频数据。**
  1. Launch Audacity and load a WAV audio file

  1. Resample. Since the BL602 DAC supports a maximum sample rate of 32 kHz and a minimum of 8 kHz, the audio needs to be resampled within this range.

Note: if the audio has multiple channels, merge them into a single channel or delete the extra channels. 3) Export the audio file in RAW format

2. Generating a C Array from Audio Data Before generating the C array, the RAW format data needs further conversion. Below is a Python script provided for the BL602:

Click to expand full code
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()

Run the Python script from the command line: python test.raw test.bin Finally, use the bin2c tool to convert it into a C array:

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

The generated content is as follows:

Click to expand full code
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

The generated data has 16 entries per line, so the data length can be calculated from the number of lines. Alternatively, the array length can be calculated in the code with sizeof. The generated array name can be changed as needed. 4. DAC Usage Example

Click to expand full code
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();
}

Note: connect the speaker to an external amplifier or directly to the DAC pin.

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