详见代码
https://gitee.com/qinyunti/fr3068-e-c-micropython.git
为了实现dac播放音乐,先来实现dac的任意输出测试
原理图
原理图如下使用PB12控制PA,PC7和PC6为DAC的R通道输出
路径如下,使能mono模式时,始终使用L的FIFO
PA控制
void app_dac_pa_init(void){
GPIO_InitTypeDef gpio_config;
__SYSTEM_GPIOB_CLK_ENABLE();
gpio_config.Pin = GPIO_PIN_12;
gpio_config.Mode = GPIO_MODE_OUTPUT_PP;
gpio_config.Pull = GPIO_PULLUP;
gpio_config.Alternate = GPIO_FUNCTION_0;
gpio_init(GPIOB, &gpio_config);
}
void app_dac_pa_ctrl(int en){
if(en != 0){
gpio_write_pin(GPIOB,GPIO_PIN_12,GPIO_PIN_CLEAR);
}else{
gpio_write_pin(GPIOB,GPIO_PIN_12,GPIO_PIN_SET);
}
}
增加shell命令控制,测试控制
DAC初始化
引脚配置
__SYSTEM_GPIOC_CLK_ENABLE();
GPIO_InitTypeDef CodecIO;
CodecIO.Pin = GPIO_PIN_6 | GPIO_PIN_7;
CodecIO.Mode = GPIO_MODE_AF_PP;
CodecIO.Pull = GPIO_PULLUP;
CodecIO.Alternate = GPIO_FUNCTION_D;
gpio_init(GPIOC, &CodecIO);
这里demo功能配置为D,但是数据手册中对应的是C不知道为何??
DAC配置
__SYSTEM_PSD_DAC_CLK_ENABLE();
hpsd.Init.DataSrc = PSD_DAC_DATA_SOURCE_DACFIFO;
hpsd.Init.Right_mix = PSD_DAC_FUNC_DISABLE;
hpsd.Init.Left_mix = PSD_DAC_FUNC_DISABLE;
hpsd.Init.MonoEn = PSD_DAC_FUNC_ENABLE;
hpsd.Init.ClockSource = PSD_DAC_CLOCK_SOURCE_24M_MODE;
hpsd.Init.Swap = 0;
hpsd.Init.SampleRate = PSD_DAC_SAMPLE_RATE_16000;
hpsd.Init.Oversampling_Level = PSD_DAC_OVERSAMPLING_LOW;
hpsd.Init.DAC_DataFormat = PSD_DAC_FIFO_FORMAT_24BIT;
hpsd.Init.DAC_FIFOCombine = PSD_DAC_FUNC_DISABLE;
hpsd.Init.DAC_FIFOThreshold = sizeof(dac_data)/sizeof(dac_data[0]);
hpsd.DAC_FIFO_LeftEmpty_Callback = dac_leftempty_cb;
hpsd.DAC_FIFO_RightEmpty_Callback = dac_rightempty_cb;
hpsd.DAC_FIFO_LeftAlmostEmpty_Callback = dac_leftalmostempty_cb;
hpsd.DAC_FIFO_RightAlmostEmpty_Callback = dac_rightalmostempty_cb;
NVIC_SetPriority(PSD_DAC_IRQn, 4);
NVIC_EnableIRQ(PSD_DAC_IRQn);
psd_dac_int_clr(PSD_DAC_INT_DACFF_L_AEMPTY);
psd_dac_int_clr(PSD_DAC_INT_DACFF_R_AEMPTY);
psd_dac_int_disable(PSD_DAC_INT_DACFF_L_AEMPTY);
psd_dac_int_disable(PSD_DAC_INT_DACFF_R_AEMPTY);
psd_dac_init(&hpsd);
psd_dac_mute_contrl(0);
psd_dac_set_volume(PSD_DAC_CH_LR, 0x1000);
DAC中断入口配置
默认中断入口是psd_dac_irq
需要在
components\drivers\peripheral\Inc\driver_psd_dac.h中添加驱动的中断函数申明
void psd_dac_IRQHandler(PSD_DAC_HandleTypeDef *hpsd);
examples\evb_demo\lvgl_demo\Src\app_dac.c中
实现中断入口调用驱动的中断函数
void psd_dac_irq(void)
{
psd_dac_IRQHandler(&hpsd);
}
其实作为SDK来说建议这一部分驱动应该对应好,无需用户再回调一次,
用户只需要init时指定回调即可。
增加清除中断入口
#define __PSD_DAC_INT_STATUS_CLR(__STATUS__) (PSD_DAC->DACIntRawStatus &= ~(__STATUS__));(PSD_DAC->DACIntStatus &= ~(__STATUS__))
void psd_dac_int_clr(enum_PSD_DAC_INT_Status_t fe_Int_Status)
{
__PSD_DAC_INT_STATUS_ENABLE(fe_Int_Status);
}
中断测试
FIFO是64个点,对于16k,发送16个点对应1ms,先写32个点,设置阈值16个点,半满中断,继续写下一个16个点,形成ping-pong
static uint32_t dac_data[16];
psd_dac_write_dac_fifo_left(dac_data, sizeof(dac_data)/sizeof(dac_data[0]));
psd_dac_write_dac_fifo_left(dac_data, sizeof(dac_data)/sizeof(dac_data[0]));
psd_dac_int_enable(PSD_DAC_INT_DACFF_L_AEMPTY);
void dac_leftalmostempty_cb(struct __PSD_DAC_HandleTypeDef *hpsd){
psd_dac_write_dac_fifo_left(dac_data, sizeof(dac_data)/sizeof(dac_data[0]));
psd_dac_int_clr(PSD_DAC_INT_DACFF_L_AEMPTY);
printf("lae\r\n");
}
测试中断产生
测试输出
产生正弦波测试
线性测试
for(int i=0; i<sizeof(dac_data)/sizeof(dac_data[0]);i++){
int tmp = sin((2*3.141592653*i)/(sizeof(dac_data)/sizeof(dac_data[0])))*32767;
//int tmp = -32768 + i*65536/(sizeof(dac_data)/sizeof(dac_data[0]));
printf("%d\r\n",tmp);
dac_data = ((uint32_t)(tmp&0xFFFF))<<8;
}
对应如下值
示波器测量,看到采样率和波形都正确