1.13. APA

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

1.13.1. APA接口

static const struct apa_driver apa_drv_ins = {
    .open       = __apa_open,             //初始化APA
    .close      = __apa_close,            //关闭APA
    .analog_open = __apa_analog_open,     //打开APA的模拟部分
    .analog_close = __apa_analog_close,   //关闭APA的模拟部分
    .ioctrl     = __apa_ioctl,            //音量、采样率、中断配置接口
    .vol_ctrl   = __apa_digital_vol_ctrl, //音量控制接口
};
const struct apa_driver *apa_drv = &apa_drv_ins;

1.13.2. APA初始化

1.13.2.1. 传入参数

#define APA_CLK_320M    1
#define APA_CLK_240M    2 //default
#define APA_CLK_HSB     3

#define APA_PWM_MODE    0 //APA输出音频信号
#define APA_IO_MODE     1 //APA做IO输出高低电平

#define APA_PWM_MODE1   0 //APA_PWM 调制模式1(单端/差分,推荐单端)
#define APA_PWM_MODE2   1 //APA_PWM 调制模式2(差分)

typedef struct _APA_INF {
    u8 apa_p_mode; //APA_P端的模式(APA_PWM_MODE/APA_IO_MODE)
    u8 apa_n_mode; //APA_P端的模式(APA_PWM_MODE/APA_IO_MODE)
    u8 pwm_mode;   //APA_PWM调制模式(APA_PWM_MODE1/APA_PWM_MODE2)
    u8 pwm_clk;    //APA时钟(APA_CLK_320M/APA_CLK_240M/APA_CLK_HSB)
    u16 def_sr;    //默认采样率(32K/44.1K/48K)
    apa_func apa_input; //APA中断回调处理G
    u8 dcc_en;     //直流滤波器使能
    void *priv;
} APA_INF;

1.13.2.2. 使用方法

#include "apa_api.h"

apa_input(void *priv, void *apa_buf, u32 len){
    //*apa_buf:可写入的首地址
    //len:可写入数据长度(字节数);
}

APA_INF apa_inf;
apa_inf.def_sr = 44100;
apa_inf.pwm_mode = APA_PWM_MODE2;
apa_inf.pwm_clk = APA_CLK_240M;
apa_inf.apa_input = (apa_func)apa_input;
apa_inf.apa_p_mode = APA_PWM_MODE;
apa_inf.apa_n_mode = APA_PWM_MODE;
apa_inf.dcc_en = 1;
/* apa_inf.apa_n_mode = APA_IO_MODE; */

apa_drv->open(&apa_inf);

1.13.3. APA关闭

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

1.13.3.1. 使用方法

apa_drv->close(void);

1.13.4. APA打开模拟部分

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

1.13.4.1. 使用方法

apa_drv->analog_open(void);

1.13.5. APA关闭模拟部分

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

1.13.5.1. 使用方法

apa_drv->analog_close(void);

1.13.6. APA音量、采样率、中断配置接口

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

1.13.6.1. 传入参数

enum {              //传入参数      功能解释
    APA_REG_VOL_TAB,//u16 *        注册音量表
    APA_GET_MAX_VOL,//u8 *         获取最大音量
    APA_SET_MAX_VOL,//u8 *         设置最大音量
    APA_GET_CUR_VOL,//u8 *         获取当前音量
    APA_SET_CUR_VOL,//u8 *         设置当前音量
    APA_CLR_DMA_BUF,//NULL         清除DMABUF数据
    APA_SET_SR,     //u16 *        设置采样率
    APA_GET_SR,     //u16 *        获取采样率
    APA_IE_CTL,     //u8 *         控制IE
};

1.13.6.2. 使用方法

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

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;

apa_drv->ioctrl((void *)&vol, APA_SET_MAX_VOL);     //设置最大音量
apa_drv->ioctrl((void *)&vol, APA_SET_CUR_VOL);     //设置当前音量
apa_drv->ioctrl((void *)digital_vol_tab, APA_REG_VOL_TAB);      //注册音量表

u16 def_sr = APA_DEFAULT_SR;
u16 cur_sr = 0;
apa_drv->ioctrl((void *)&def_sr, APA_SET_SR);       //设置采样率
apa_drv->ioctrl((void *)&cur_sr, APA_GET_SR);       //获取当前音量到cur_sr中

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

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

1.13.7. APA音量控制接口

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

1.13.7.1. 使用方法

apa_drv->vol_ctrl(apa_buf, buf_len);

1.13.8. APA使用案例

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

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
};

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

void apa_test_demo()
{
    u8  vol = DEFUAL_SYS_VOL;
    apa_drv->ioctrl((void *)&vol, APA_SET_MAX_VOL);     //设置最大音量
    apa_drv->ioctrl((void *)&vol, APA_SET_CUR_VOL);     //设置当前音量
    apa_drv->ioctrl((void *)digital_vol_tab, APA_REG_VOL_TAB);      //注册音量表


    APA_INF apa_inf;
    apa_inf.def_sr = 44100;
    apa_inf.pwm_mode = APA_PWM_MODE2;
    apa_inf.pwm_clk = APA_CLK_240M;
    apa_inf.apa_input = (apa_func)apa_write;
    apa_inf.apa_p_mode = APA_PWM_MODE;
    apa_inf.apa_n_mode = APA_PWM_MODE;
    apa_inf.dcc_en = 1;

    apa_drv->open(&apa_inf);
    u8 ie_en = 1;
    apa_drv->ioctrl((void*)&ie_en, APA_IE_CTL);//使能APA中断
    while(1){
        mdelay(5);
    }
}

1.13.9. APA特殊用法

APA除了用于播放音频信号,还可以作为普通IO输出高低电平

#define MAX_SYS_VOL                                 (31)
#define DEFUAL_SYS_VOL                              (MAX_SYS_VOL)

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

static void apa_write(void *priv, void *data, u32 len)
{
    apa_drv->vol_ctrl(data, len);
}

void apa_test_demo()
{
    u8  vol = DEFUAL_SYS_VOL;
    apa_drv->ioctrl((void *)&vol, APA_SET_MAX_VOL);
    apa_drv->ioctrl((void *)&vol, APA_SET_CUR_VOL);
    apa_drv->ioctrl((void *)digital_vol_tab, APA_REG_VOL_TAB);

    APA_INF apa_inf;
    apa_inf.def_sr = 44100;
    apa_inf.pwm_mode = APA_PWM_MODE2;
    apa_inf.pwm_clk = APA_CLK_240M;
    apa_inf.apa_input = (apa_func)apa_write;
    apa_inf.apa_p_mode = APA_IO_MODE;   //APA_P端IO模式
    apa_inf.apa_n_mode = APA_IO_MODE;   //APA_N端IO模式
    apa_inf.dcc_en = 0;

    apa_drv->open(&apa_inf);
    while(1){
        set_apap_output_status(1);//P端输出高电平
        set_apan_output_status(1);//N端输出高电平
        mdelay(5000);
        set_apap_output_status(1);//P端输出低电平
        set_apan_output_status(1);//N端输出低电平
    }
}