1.14. DAC

DAC接口包括该模块的初始化,关闭,模拟部分的开关,音量的控制等,相关接口可通过结构体dac_driver进行调用。该系列DAC支持16bit精度,单声道(单端)。

1.14.1. DAC接口

static const struct dac_driver dac_drv_ins = {
    .open       = __dac_open,               //初始化DAC
    .close      = __dac_close,              //关闭DAC
    .analog_open = __dac_analog_open,       //打开DAC的模拟部分
    .analog_close = __dac_analog_close,     //关闭DAC的模拟部分
    .ioctrl     = __dac_ioctl,              //音量、采样率、中断配置接口
    .vol_ctrl   = __digital_vol_ctrl,       //音量控制接口
};
const struct dac_driver *dac_drv = &dac_drv_ins;

1.14.2. DAC初始化

1.14.2.1. 传入参数

typedef struct _DAC_INF {
    u32 def_sr;             //DAC 普通模式采样率(8K,11.025K,12K,16K,22.05K,24K,32K,44.1K,48K,64K,88.2K,96K)
    dac_func dac_input;     //DAC中断回调
    void *priv;             //传入中断回调的私有参数
    u8 dac_mode;            //DAC模式(0:普通,1:2M, 2M模式下输入的音频不能超过-6dB)
    u8 fs_2M_sr;            //DAC 2M模式采样率参数(fs_2M_sr = 12M / dac_sr - 1,96k < dac_sr < 2 M)
    u8 dcc_en;              //直流滤波器使能
} DAC_INF;

1.14.2.2. 使用方法

#include "dac_api.h"

dac_input(void *priv, void *dac_buf, u32 len){
    //*dac_buf:可写入的首地址
    //len:可写入数据长度(字节数);
    printf("dac_sr:%d\n", *priv);
}

int dac_sr = 48000;
DAC_INF info = {
    .priv = (void *)&dac_sr,
    .def_sr = dac_sr,
    .dac_input = (dac_func)dac_input,
    .dac_mode = (dac_sr > 96000L) ? 1 : 0,
    .fs_2M_sr = 12000000L / dac_sr - 1,
    .dcc_en = 1,
};

dac_drv->open(&info);

1.14.3. DAC关闭

关闭dac的数字部分和模拟部分

1.14.3.1. 使用方法

dac_drv->close(void);

1.14.4. dac打开模拟部分

该接口只会打开dac的模拟部分,不会对dac的数字部分进行操作。可配合dac_drv->analog_close()使用

1.14.4.1. 使用方法

dac_drv->analog_open(void);

1.14.5. dac关闭模拟部分

该接口只会关闭dac的模拟部分,不会对dac的数字部分进行操作。可配合dac_drv->analog_open()使用,减少不需要播放信号时的功耗。

1.14.5.1. 使用方法

dac_drv->analog_close(void);

1.14.6. dac音量、采样率、中断配置接口

该接口通过传入的命令和参数判断需要执行的功能(音量的初始化、采样率设置/获取、中断的开关)

1.14.6.1. 传入参数

enum {              //传入参数      功能解释
    DAC_REG_VOL_TAB,//u16 *        注册音量表
    DAC_GET_MAX_VOL,//u8 *         获取最大音量
    DAC_SET_MAX_VOL,//u8 *         设置最大音量
    DAC_GET_CUR_VOL,//u8 *         获取当前音量
    DAC_SET_CUR_VOL,//u8 *         设置当前音量
    DAC_CLR_DMA_BUF,//NULL         清除DMABUF数据
    DAC_SET_SR,     //u16 *        设置采样率
    DAC_GET_SR,     //u16 *        获取采样率
    DAC_IE_CTL,     //u8 *         控制IE
};

1.14.6.2. 使用方法

#define MAX_SYS_VOL                 (31)                       //最大音量等级
#define DEFUAL_SYS_VOL              (MAX_SYS_VOL)      //系统默认音量
#define DAC_DEFAULT_SR              (32000)            //dac初始化的采样率

const u16 digital_vol_tab[MAX_SYS_VOL + 1] = {
    0,     93,   111,  132,  158,  189,  226,  270,   323,  386,   //9
    462,   552,  660,  789,  943,  1127, 1347, 1610,  1925, 2301,  //19
    2751,  3288, 3930, 4698, 5616, 6713, 8025, 9592, 11466, 15200, //29
    16000, 16384                                                                                               //31
};
u8  vol = DEFUAL_SYS_VOL;

dac_drv->ioctrl((void *)&vol, DAC_SET_MAX_VOL);     //设置最大音量
dac_drv->ioctrl((void *)&vol, DAC_SET_CUR_VOL);     //设置当前音量
dac_drv->ioctrl((void *)digital_vol_tab, DAC_REG_VOL_TAB);      //注册音量表

u16 def_sr = DAC_DEFAULT_SR;
u16 cur_sr = 0;
dac_drv->ioctrl((void *)&def_sr, DAC_SET_SR);       //设置采样率(只适用于DAC普通模式)
dac_drv->ioctrl((void *)&cur_sr, DAC_GET_SR);       //获取当前音量到cur_sr中(只适用于DAC普通模式)

dac_drv->ioctrl((void *)NULL, DAC_CLR_DMA_BUF);     //清除DMABUF数据

u8 ie_en = 0;
dac_drv->ioctrl((void *)&ie_en, DAC_IE_CTL);        //通过ie_en控制中断

1.14.7. dac音量控制接口

通过ioctrl完成音量表、最大音量和当前音量的设置后,将需要播放的数据传入该接口,便能实现音量控制。

1.14.7.1. 使用方法

dac_drv->vol_ctrl(dac_buf, buf_len);

1.14.8. dac使用案例

#define DAC_MAX_SYS_VOL                                     (31)                       //最大音量等级
#define DAC_DEFUAL_SYS_VOL                          (DAC_MAX_SYS_VOL)      //系统默认音量

const u16 dac_demo_digital_vol_tab[DAC_MAX_SYS_VOL + 1] = {
    0,     93,   111,  132,  158,  189,  226,  270,   323,  386,   //9
    462,   552,  660,  789,  943,  1127, 1347, 1610,  1925, 2301,  //19
    2751,  3288, 3930, 4698, 5616, 6713, 8025, 9592, 11466, 15200, //29
    16000, 16384                                                                                               //31
};

u16 dac_cnt = 0;
extern int get_sine_data(u16 *s_cnt, s16 *data, u16 points, u8 ch);//数据替换
static void dac_input(void *priv, void *data, u32 len)
{
    get_sine_data(&dac_cnt, data, len / 2, 1);//将数据替换为44.1K采样率的1k正弦波用于测试。
    dac_drv->vol_ctrl(data, len);
}

void dac_test_demo()
{
    u8  vol = DAC_DEFUAL_SYS_VOL;
    dac_drv->ioctrl((void *)&vol, DAC_SET_MAX_VOL);     //设置最大音量
    dac_drv->ioctrl((void *)&vol, DAC_SET_CUR_VOL);     //设置当前音量
    dac_drv->ioctrl((void *)dac_demo_digital_vol_tab, DAC_REG_VOL_TAB);      //注册音量表

    int dac_sr = 44100;
    DAC_INF dac_inf = {
        .priv = (void *) &dac_sr,
        .def_sr = dac_sr,
        .dac_input = (dac_func)dac_input,
        .dac_mode = (dac_sr > 96000L) ? 1 : 0,
        .fs_2M_sr = 12000000L / dac_sr - 1,
        .dcc_en = 1,
    };

    //电源配置
    hadc_avddcp_config(1, AVDDCP_MODE_SEL_NORMAL, AVDDCP_VOL_SEL_3P60);
    hadc_avddr_config(1, AVDDR_VOL_SEL_3P0);
    hadc_avbg_config(1, 0, 1);
    hadc_avcm_config(1, 1);
    hadc_pa_config(1, 1, HADC_PA_MUXP_SEL_AVBG, HADC_PA_MUXN_DACO_BIAS, HADC_PA_GAIN_SEL_M0db);

    dac_drv->open(&dac_inf);
    u8 ie_en = 1;
    dac_drv->ioctrl((void *)&ie_en, DAC_IE_CTL); //使能DAC中断

    while (1) {
        wdt_clear();
        mdelay(5);
    }
}