打印
[活动专区]

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

[复制链接]
2372|9
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
AD, ADC, DM, 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[0]));
        printf("vintrv value = %f V\n", calculate_volt(adc_val[1]));
        printf("ADC_IN0 value = %f V\n\n", calculate_volt(adc_val[2]));
    }
   
    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 电压越高,采到的温度越高,猜测可能和通道切换过程有关。不过,内部参考电压不受这些影响。

adc.zip

5.52 MB

使用特权

评论回复
沙发
muyichuan2012| | 2023-11-9 09:19 | 只看该作者
AT32F423 adc传输完毕dma 设定counter 后就会停止传输,不再产生dma 请求。

使用特权

评论回复
板凳
chenjun89| | 2023-11-9 10:00 | 只看该作者
雅特力也出配置工具了吗?

使用特权

评论回复
评论
muyichuan2012 2023-11-9 11:34 回复TA
是的 AT32 workbench发布一段时间了。 目前仅支持型号421,423,最近会支持403A,407,413,415等 
地板
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

使用特权

评论回复
5
xu@xupt| | 2023-11-9 17:36 | 只看该作者
不错的学习资源~~

使用特权

评论回复
6
单片小菜| | 2023-11-13 17:26 | 只看该作者
过采样会有问题吗?

使用特权

评论回复
7
cuyebiren|  楼主 | 2023-11-15 08:25 | 只看该作者
单片小菜 发表于 2023-11-13 17:26
过采样会有问题吗?

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

使用特权

评论回复
8
wangwu1976@| | 2024-1-20 10:06 | 只看该作者
in0的值变化有点大哦。是输入信号不稳定还是采样偏差,理论上12位的ADC误差不应该这么大,最少还要小一个量级才对。

使用特权

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

本版积分规则

8

主题

39

帖子

0

粉丝