打印

GD32 定时器+DMA+ADC 实现16K 音频ADC采样及PCM编码

[复制链接]
7078|24
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
kingpower2019|  楼主 | 2020-3-7 13:10 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
GD32 定时器+DMA+ADC 实现16K 音频ADC采样及PCM编码

参考代码:
uint16_t ad_value[1920*2];   //音频原始AD采样值
uint8_t audio_EncodeValue[1008]; //音频PCM编码值
uint8_t StartSend=0;  //编码后发送标志

void adc_rcu_config(void);
void adc_gpio_config(void);
void adc_dma_config(void);
void adc_timer_config(void);
void adc_config(void);


/*!
    \brief      RCU configuration function for ADC
    \param[in]  none
    \param[out] none
    \retval     none
*/
void adc_rcu_config(void)
{
    /* enable the GPIO clock */
    rcu_periph_clock_enable(RCU_GPIOA);


    /* ADCCLK = PCLK2/4 */
    rcu_adc_clock_config(RCU_ADCCK_APB2_DIV4);

    /* enable DMA clock */
    rcu_periph_clock_enable(RCU_DMA);

    /* enable ADC clock */
    rcu_periph_clock_enable(RCU_ADC);

    /* enable TIMER0 clock */
    rcu_periph_clock_enable(RCU_TIMER0);
}
/*!
    \brief      GPIO configuration function for ADC
    \param[in]  none
    \param[out] none
    \retval     none
*/
void adc_gpio_config(void)
{
    /* configure PA1(ADC channel1) as analog input */
    gpio_mode_set(GPIOA, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO_PIN_1);
}
/*!
    \brief      DMA configuration function for ADC
    \param[in]  none
    \param[out] none
    \retval     none
*/
void adc_dma_config(void)
{
    dma_parameter_struct dma_init_struct;

    /* initialize DMA channel0 */
    dma_deinit(DMA_CH0);
    dma_init_struct.direction    = DMA_PERIPHERAL_TO_MEMORY;
    dma_init_struct.memory_addr  = (uint32_t)ad_value;
    dma_init_struct.memory_inc   = DMA_MEMORY_INCREASE_ENABLE;
    dma_init_struct.memory_width = DMA_MEMORY_WIDTH_16BIT;
    dma_init_struct.number       = 1920*2;        //双BUFFER 循环缓冲
    dma_init_struct.periph_addr  = (uint32_t)&(ADC_RDATA);
    dma_init_struct.periph_inc   = DMA_PERIPH_INCREASE_DISABLE;
    dma_init_struct.periph_width = DMA_PERIPHERAL_WIDTH_16BIT;
    dma_init_struct.priority     = DMA_PRIORITY_ULTRA_HIGH;
    dma_init(DMA_CH0, &dma_init_struct);
   
    /* configure DMA mode */
    dma_circulation_enable(DMA_CH0);
    dma_memory_to_memory_disable(DMA_CH0);

    dma_interrupt_enable(DMA_CH0,DMA_INT_FTF);   //DMA完成中断使能
   dma_interrupt_enable(DMA_CH0,DMA_INT_HTF); // DMA半完成中断使能 实现双缓冲

    /* enable DMA channel0 */
    dma_channel_enable(DMA_CH0);
}

/*!
    \brief      TIMER configuration function for ADC
    \param[in]  none
    \param[out] none
    \retval     none
*/
void adc_timer_config(void)
{
    timer_oc_parameter_struct timer_ocintpara;
    timer_parameter_struct timer_initpara;

    timer_deinit(TIMER0);

    /* TIMER0 configuration */
    timer_initpara.prescaler         = 53;        //108MHZ--54分频到2MHZ
    timer_initpara.alignedmode       = TIMER_COUNTER_EDGE;
    timer_initpara.counterdirection  = TIMER_COUNTER_UP;
    timer_initpara.period            = 1250;        //16KHz的音频采样频率
    timer_initpara.clockdivision     = TIMER_CKDIV_DIV1;
    timer_initpara.repetitioncounter = 0;
    timer_init(TIMER0, &timer_initpara);

    /* CH0 configuration in PWM mode1 */
    timer_ocintpara.ocpolarity  = TIMER_OC_POLARITY_LOW;
    timer_ocintpara.outputstate = TIMER_CCX_ENABLE;
    timer_channel_output_config(TIMER0, TIMER_CH_0, &timer_ocintpara);

    timer_channel_output_pulse_value_config(TIMER0, TIMER_CH_0, 625); //50%占空比
    timer_channel_output_mode_config(TIMER0, TIMER_CH_0, TIMER_OC_MODE_PWM1);
    timer_channel_output_shadow_config(TIMER0, TIMER_CH_0, TIMER_OC_SHADOW_DISABLE);

    /* auto-reload preload enable */
    timer_auto_reload_shadow_enable(TIMER0);
    timer_primary_output_config(TIMER0, ENABLE);
}

/*!
    \brief      ADC configuration function
    \param[in]  none
    \param[out] none
    \retval     none
*/
void adc_config(void)
{
    /* ADC channel length config */
    adc_channel_length_config(ADC_REGULAR_CHANNEL, 1);

    /* ADC regular channel config */
    adc_regular_channel_config(0, ADC_CHANNEL_1, ADC_SAMPLETIME_55POINT5);

    /* ADC external trigger enable */
    adc_external_trigger_config(ADC_REGULAR_CHANNEL, ENABLE);
    /* ADC external trigger source config */
    adc_external_trigger_source_config(ADC_REGULAR_CHANNEL, ADC_EXTTRIG_REGULAR_T0_CH0);
    /* ADC data alignment config */
    adc_data_alignment_config(ADC_DATAALIGN_RIGHT);
    /* enable ADC interface */
    adc_enable();
    /* ADC calibration and reset calibration */
    adc_calibration_enable();
    /* ADC DMA function enable */
    adc_dma_mode_enable();
}


void DMA_Channel0_IRQHandler(void)
{
   if(dma_interrupt_flag_get(DMA_CH0,DMA_INT_FLAG_FTF)
  {
    dma_interrupt_flag_clear(DMA_CH0,DMA_INT_FLAG_FTF);
    // ADPCM 编码
    audio_EncodeValue = ADPCM_Encode(adc_value);

    //发送音频数据
    StartSend = 1;
}
   if(dma_interrupt_flag_get(DMA_CH0,DMA_INT_FLAG_HTF)
  {
    dma_interrupt_flag_clear(DMA_CH0,DMA_INT_FLAG_HTF);
    // ADPCM 编码
    audio_EncodeValue = ADPCM_Encode(adc_value);

    //发送音频数据
    StartSend = 1;
}
}

使用特权

评论回复
沙发
kingpower2019|  楼主 | 2020-3-7 13:12 | 只看该作者
有什么不清楚的可以来提问?有时间我会及时给您们回复

使用特权

评论回复
板凳
xdqfc| | 2020-3-7 15:31 | 只看该作者
DMA配合ADC使用,假如规则组使用6个通道采样,DMA也开辟6个空间,理论上最后得到的转换数据是可以一一对应的,但是有时候会发生数据错开的现象,请问楼主是如何解决的。

使用特权

评论回复
地板
lanmanck| | 2020-3-11 17:15 | 只看该作者
kingpower2019 发表于 2020-3-7 13:12
有什么不清楚的可以来提问?有时间我会及时给您们回复

大概说一下思路,不要一来就代码,有做pcm压缩和解码吗?做算法放到主循环还是中断中?

使用特权

评论回复
5
sonicll| | 2020-3-11 17:40 | 只看该作者
xdqfc 发表于 2020-3-7 15:31
DMA配合ADC使用,假如规则组使用6个通道采样,DMA也开辟6个空间,理论上最后得到的转换数据是可以一一对应 ...

一般情况都不会错位,你有没有做反复开关ADC的操作?CTL1寄存器的ADCON那一位,是会触发采样的,你如果反复开关ADC,可能会导致额外触发一次采样,导致数据错位

使用特权

评论回复
6
laserpic| | 2020-3-13 11:57 | 只看该作者
DMA半完成中断使能 实现双缓冲: 整个代码看起来半没有双缓冲功能。半中断,与完全中断,你都在中断函数里处理。用不用半中断都一样。

使用特权

评论回复
7
lvben5d| | 2020-3-13 12:44 | 只看该作者
本帖最后由 lvben5d 于 2020-3-13 12:47 编辑

楼主的代码  设置了2个buffer长度,很好,缓冲区接收一半中断和全满也很巧妙啊。 学习

使用特权

评论回复
8
heimaojingzhang| | 2020-4-7 14:03 | 只看该作者
非常感谢楼主分享

使用特权

评论回复
9
keaibukelian| | 2020-4-7 14:03 | 只看该作者
非常感谢楼主分享

使用特权

评论回复
10
labasi| | 2020-4-7 14:03 | 只看该作者
非常感谢楼主分享

使用特权

评论回复
11
paotangsan| | 2020-4-7 14:03 | 只看该作者
非常感谢楼主分享

使用特权

评论回复
12
renzheshengui| | 2020-4-7 14:04 | 只看该作者
非常感谢楼主分享

使用特权

评论回复
13
EDAStarer| | 2020-7-7 18:10 | 只看该作者
请问DMA_Channel0_IRQHandler在哪里调用的

使用特权

评论回复
14
雨花开在下雨天| | 2021-8-13 15:13 | 只看该作者
EDAStarer 发表于 2020-7-7 18:10
请问DMA_Channel0_IRQHandler在哪里调用的

中断向量表__vector_table,具体内容可以看xxx.s启动文件

使用特权

评论回复
15
Lindaic| | 2021-9-14 16:43 | 只看该作者
请问楼主,ADC采样输入为0时,采样值为多少?比如模拟输入为0,ADC采样值会不会在10左右跳(最大采样值是4095)?

使用特权

评论回复
16
jkl21| | 2021-10-5 17:58 | 只看该作者
这个采集数据吗  

使用特权

评论回复
17
iyoum| | 2021-10-5 17:58 | 只看该作者
能够转为pwm输出吗  

使用特权

评论回复
18
uytyu| | 2021-10-5 17:58 | 只看该作者
使用的是多大的采样率呢   

使用特权

评论回复
19
myiclife| | 2021-10-5 17:59 | 只看该作者
驱动定时器波形信号吧   

使用特权

评论回复
20
touser| | 2021-10-5 17:59 | 只看该作者
PCM编码难吗?

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

1

主题

3

帖子

0

粉丝