cuyebiren 发表于 2023-11-8 22:27

【AT-START-F423测评】+ ADC 过采样+DMA

AT32F423 的 ADC 支持过采样,可以对1个通道连续采样多次,直接输出连续采样的平均值。这样可以省去软件做平均。
配合 DMA,周期触发采样,就可以得到对应通道的周期采样的平均值。

本测评采集3个通道,ADC_IN0、内部温度传感器、内部参考电压。
步骤:
1、配置过程


2、代码编写
main.c
int main(void)
{
/* add user code begin 1 */
    uint32_t start_tick;
/* add user code end 1 */

/* add a necessary delay to ensure that Vdd is higher than the operating
   voltage of battery powered domain (2.57V) when the battery powered
   domain is powered on for the first time and being operated. */
wk_wait_for_power_stable();

/* system clock config. */
wk_system_clock_config();

/* config periph clock. */
wk_periph_clock_config();

/* nvic config. */
wk_nvic_config();

/* init dma1 channel1 */
wk_dma1_channel1_init();
/* config dma channel transfer parameter */
/* user need to modify parameters memory_base_addr and buffer_size */
wk_dma_channel_config(DMA1_CHANNEL1, (uint32_t)&ADC1->odt, (uint32_t)adc_val, 3);
dma_channel_enable(DMA1_CHANNEL1, TRUE);

/* init usart1 function. */
wk_usart1_init();

/* init adc1 function. */
wk_adc1_init();

/* add user code begin 2 */
    sys_init();

    printf("The demo is started!\n");
    start_tick = sys_get_tick();

    dma_interrupt_enable(DMA1_CHANNEL1, DMA_FDT_INT, TRUE);
    adc_interrupt_enable(ADC1, ADC_OCCO_INT, TRUE);
    adc_interrupt_enable(ADC1, ADC_OCCE_INT, TRUE);
    adc_ordinary_software_trigger_enable(ADC1, TRUE);
/* add user code end 2 */

while(1)
{
    /* add user code begin 3 */
    if (adc_val_update) {
      adc_val_update = 0;

      #define calculate_volt(val)   (val * 3.3 / 4095)
      #define calculate_temperature(val) \
                  ((calculate_volt(val) - 1.29f) * 1000 / 4.26f + 25)
      
      printf("temperature sensor value = %f ℃\n",
               calculate_temperature(adc_val));
      printf("vintrv value = %f V\n", calculate_volt(adc_val));
      printf("ADC_IN0 value = %f V\n\n", calculate_volt(adc_val));
    }
   
    if (sys_get_tick() - start_tick >= 1000) {
      start_tick = sys_get_tick();
      
      dma_flag_clear(DMA1_FDT1_FLAG);
      dma_interrupt_enable(DMA1_CHANNEL1, DMA_FDT_INT, TRUE);
      wk_dma_channel_config(DMA1_CHANNEL1, (uint32_t)&ADC1->odt, (uint32_t)adc_val, 3);
      dma_channel_enable(DMA1_CHANNEL1, TRUE);
      adc_dma_mode_enable(ADC1, TRUE);

      adc_ordinary_software_trigger_enable(ADC1, TRUE);
      
      printf("ADC overflow count = %d\n\n", adc_overflow_cnt);
    }
    /* add user code end 3 */
}
}中断函数
void DMA1_Channel1_IRQHandler(void)
{
/* add user code begin DMA1_Channel1_IRQ 0 */
    if(dma_flag_get(DMA1_FDT1_FLAG)) {
      adc_val_update = 1;
      
      adc_dma_mode_enable(ADC1, FALSE);
      dma_channel_enable(DMA1_CHANNEL1, FALSE);
      dma_interrupt_enable(DMA1_CHANNEL1, DMA_FDT_INT, FALSE);
    }
/* add user code end DMA1_Channel1_IRQ 0 */
/* add user code begin DMA1_Channel1_IRQ 1 */

/* add user code end DMA1_Channel1_IRQ 1 */
}

void ADC1_IRQHandler(void)
{
/* add user code begin ADC1_IRQ 0 */
    if(adc_flag_get(ADC1, ADC_OCCO_FLAG) != RESET)
    {
      adc_flag_clear(ADC1, ADC_OCCO_FLAG);
      adc_overflow_cnt++;
    }
    if(adc_flag_get(ADC1, ADC_OCCE_FLAG) != RESET)
    {
      adc_flag_clear(ADC1, ADC_OCCE_FLAG);
    }
/* add user code end ADC1_IRQ 0 */
/* add user code begin ADC1_IRQ 1 */

/* add user code end ADC1_IRQ 1 */
}

3、测试


测试中遇到的问题:
1、DMA 使用过程中有开关通道和中断操作,当关必 DMA 通道后,再打开 DMA 通道时,必须要重新使能 ADC 的 DMA,
adc_dma_mode_enable(ADC1, TRUE);否则,不会触发 DMA 传输。2、内部温度传感器采到的温度值,和 ADC_IN0 的电压相关,ADC_IN0 电压越高,采到的温度越高,猜测可能和通道切换过程有关。不过,内部参考电压不受这些影响。

muyichuan2012 发表于 2023-11-9 09:19

AT32F423 adc传输完毕dma 设定counter 后就会停止传输,不再产生dma 请求。

chenjun89 发表于 2023-11-9 10:00

雅特力也出配置工具了吗?

cuyebiren 发表于 2023-11-9 13:16

muyichuan2012 发表于 2023-11-9 09:19
AT32F423 adc传输完毕dma 设定counter 后就会停止传输,不再产生dma 请求。

void DMA1_Channel1_IRQHandler(void)

{

/* add user code begin DMA1_Channel1_IRQ 0 */

    if(dma_flag_get(DMA1_FDT1_FLAG)) {

      adc_val_update = 1;

      

      // adc_dma_mode_enable(ADC1, FALSE);

      dma_channel_enable(DMA1_CHANNEL1, FALSE);

      dma_interrupt_enable(DMA1_CHANNEL1, DMA_FDT_INT, FALSE);

    }

/* add user code end DMA1_Channel1_IRQ 0 */

/* add user code begin DMA1_Channel1_IRQ 1 */



/* add user code end DMA1_Channel1_IRQ 1 */

}

我在 DMA 中断中有关闭 DMA 的通道和中断,把 adc_dma_mode_enable(ADC1, FALSE); 屏蔽,当再次配置启动 ADC DMA 传输时,
dma_flag_clear(DMA1_FDT1_FLAG);

      dma_interrupt_enable(DMA1_CHANNEL1, DMA_FDT_INT, TRUE);

      wk_dma_channel_config(DMA1_CHANNEL1, (uint32_t)&ADC1->odt, (uint32_t)adc_val, 3);

      dma_channel_enable(DMA1_CHANNEL1, TRUE);

      adc_dma_mode_enable(ADC1, TRUE);



      adc_ordinary_software_trigger_enable(ADC1, TRUE);

adc_dma_mode_enable(ADC1, TRUE); 这句如果不加,不会触发 DMA 传输,但可以触发 ADC 的相关中断。
初始化配置时,有调用这句 adc_dma_mode_enable(ADC1, TRUE); ,理论上,只要不关闭,就应该一直有效,但是实测的结果时,只有上电初始化后,触发一次 DMA 中断,如果不加 adc_dma_mode_enable(ADC1, TRUE);,此后不会触发 DMA

xu@xupt 发表于 2023-11-9 17:36

不错的学习资源~~

单片小菜 发表于 2023-11-13 17:26

过采样会有问题吗?

cuyebiren 发表于 2023-11-15 08:25

单片小菜 发表于 2023-11-13 17:26
过采样会有问题吗?

没有问题吧。过采样会自动采样多次算平均,我1s 采一次,测试的结果值基本不跳动。如果有问题,结果值会跳动得厉害

wangwu1976@ 发表于 2024-1-20 10:06

in0的值变化有点大哦。是输入信号不稳定还是采样偏差,理论上12位的ADC误差不应该这么大,最少还要小一个量级才对。
页: [1]
查看完整版本: 【AT-START-F423测评】+ ADC 过采样+DMA