176|1

90

帖子

0

资源

一粒金砂(中级)

【GD32450I-EVAL】定时器 测试ADC速度

本帖最后由 tinnu 于 2020-10-8 13:57 编辑

测试ADC速度需要定时器的加持,所以必须先将定时器功能摸清楚。

 

(一)定时器时钟

定时器的时钟是经过:AHB——APB——定时器

我们使用的是TIMER1

有意思的是CK_APB1总线最高只能到50M,而从CK_APB1出来的时钟却可以到达200M,这是中间有一个倍频的功能。

 

1-CK_APB1的时钟

关于这个时钟可以看:UART

USART使用的是PCLK1时钟,目前CK_APB1的时钟是最高的50M

 

2-TIMER时钟

TIMER1使用的是CK_APB1倍频后的时钟。关于倍频系数可以参考 RCU_CFG1寄存器:

CFG1.png 在复位状态下为0,即2倍频。这里2倍频是100M。

 

(二)设置

例程的配合代码:


    timer_parameter_struct timer_initpara;    
/* TIMER1 configuration */
    timer_initpara.prescaler         = 9999;
    timer_initpara.alignedmode       = TIMER_COUNTER_EDGE;
    timer_initpara.counterdirection  = TIMER_COUNTER_UP;
    timer_initpara.period            = 9999;
    timer_initpara.clockdivision     = TIMER_CKDIV_DIV1;
    timer_initpara.repetitioncounter = 0;
    timer_init(TIMER1,&timer_initpara);
") rgba(220, 220, 220, 0.5); top: -15px; left: 0px; display: block;">

有一个预分频器和比较器。在100M的时钟下,一次更新的时间为(9999+1)*(9999+1)=100M,刚好1S。

 

使能中断:

    timer_interrupt_enable(TIMER1, TIMER_INT_UP);
    nvic_irq_enable(TIMER1_IRQn, 2U, 0U);
") rgba(220, 220, 220, 0.5); top: -15px; left: 0px; display: block;">

 

使能定时器:

    /* enable TIMER1 */
    timer_enable(TIMER1);
") rgba(220, 220, 220, 0.5); top: -15px; left: 0px; display: block;">

 

实际上运行之后会发现无法触发外部中断,这是因为TIMER1的时钟要额外使能:

    rcu_periph_clock_enable(RCU_TIMER1);
") rgba(220, 220, 220, 0.5); top: -15px; left: 0px; display: block;">

 

(三)中断服务函数与测试ADC速度的代码

ADC这里需要失能中断,在主循环里面操作,因为在使能了ADC的连续读写功能后,ADC的转换速度是惊人的,中断的速度根本跟不上读写的速度,甚至主循环里面多一句代码都会严重影响测试的准确度。这也是为何ADC建议采用DMA方式读写的原因,但是DMA不方便测试速度,因此还是采用轮询的方式。

1-使能ADC连续转换功能

    // ADC contineous function enable 
    adc_special_function_config(ADC0, ADC_CONTINUOUS_MODE, ENABLE);
") rgba(220, 220, 220, 0.5); top: -15px; left: 0px; display: block;">

2-在初始化的时候使能一次

    adc_software_trigger_enable(ADC0, ADC_REGULAR_CHANNEL);
") rgba(220, 220, 220, 0.5); top: -15px; left: 0px; display: block;">

3-主循环里面不能进行多余的操作

        if (adc_interrupt_flag_get(ADC0, ADC_INT_FLAG_EOC) == SET)
        {
            adc_regular_data_read(ADC0);
            adc_counter++;
            adc_interrupt_flag_clear(ADC0, ADC_INT_FLAG_EOC);
        }

4-定时器的中断服务函数

void TIMER1_IRQHandler(void)
{
    char t_char[30] = "";
    gd_eval_led_toggle(LED1);
    sprintf(t_char, "ADC for one second:%d\r\n", adc_counter);
    PRINTF_UART0(t_char);
    adc_counter = 0;
    timer_interrupt_flag_clear(TIMER1, TIMER_INT_FLAG_UP);
}

 

 

(四)效果

当采样速度为ADC_SAMPLETIME_112

ADC for one second:403225
ADC for one second:402292
ADC for one second:402292
ADC for one second:402291
ADC for one second:402291
ADC for one second:402291
ADC for one second:402292
ADC for one second:402292

一秒400K的速度。

当采样速度为ADC_SAMPLETIME_15

ADC for one second:1010101
ADC for one second:1007662
ADC for one second:1007662
ADC for one second:1007661
ADC for one second:1007661

已经有1M了。

但必须注意到,采用速度的增加并没有跟上转换速度增加的比例,这可能还是存在轮询耗时的问题。毕竟1M的转换速度下,实际上每次只有200个机器时钟。

 

(五)ADC执行也放进中断

之后尝试了把ADC的执行操作也放入ADC中断,这里设置定时器中断的抢断优先级更高一点:

    nvic_irq_enable(TIMER1_IRQn, 1U, 0U);

当采样速度为ADC_SAMPLETIME_112:

ADC for one second:403225
ADC for one second:402292
ADC for one second:402292

竟然和轮询的时候一模一样,看来在400k低速情况下中断是不会成为转换的瓶颈

当采样速度为ADC_SAMPLETIME_15

ADC for one second:925925
ADC for one second:923779
ADC for one second:923778

这时候就明显小于轮询了


回复

1万

帖子

133

资源

管理员

个人签名

玩板看这里:

http://bbs.eeworld.com.cn/elecplay.html

EEWorld测评频道众多好板等你来玩,还可以来频道许愿树许愿说说你想要玩的板子,我们都在努力为大家实现!


回复
您需要登录后才可以回帖 登录 | 注册

关闭
站长推荐上一条 1/5 下一条

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区知春路23号集成电路设计园量子银座1305 电话:(010)82350740 邮编:100191

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号 电信业务审批[2006]字第258号函 京公海网安备110108001534 Copyright © 2005-2020 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表