在Arduino Due上设置正确的ADC预分频器,以定时器和中断驱动的多通道ADC采集

问题描述

我正在尝试针对Arduino Due:https://forum.arduino.cc/index.php?topic=589213.0遵循,适应,理解(并清理一点)围绕那里可用代码的变体。我不喜欢论坛格式,因为事情最终埋没得很深,所以请在这里询问。不幸的是,这意味着在问题之前有很多解释。如果您认为将其张贴在此处是错误的,请告诉我,我可以搬家。

基本上,该想法是使用基于计时器的触发将多个ADC通道记录在缓冲区中。有一些设置:

// sample rate in Hz
constexpr int sample_rate = 1000;

constexpr uint8_t channels[] = {7,6,5,4,3};
constexpr int nbr_channels = sizeof(channels);

然后将计时器0的通道2设置为正确的频率以触发ADC转换:

// use time counter 0 channel 2 to generate the ADC start of conversion signal
// i.e. this sets a rising edge with the right frequency for triggering ADC conversions corresponding to sample_rate
// for more information about the timers: https://github.com/ivanseidel/DueTimer/blob/master/TimerCounter.md
// NOTE: TIOA2 should not be available on any due pin https://github.com/ivanseidel/DueTimer/issues/11
void tc_setup() {
  PMC->PMC_PCER0 |= PMC_PCER0_PID29;                       // TC2 power ON : Timer Counter 0 channel 2 IS TC2
  TC0->TC_CHANNEL[2].TC_CMR = TC_CMR_TCCLKS_TIMER_CLOCK2   // clock 2 has frequency MCK/8,clk on rising edge
                              | TC_CMR_WAVE                // Waveform mode
                              | TC_CMR_WAVSEL_UP_RC        // UP mode with automatic trigger on RC Compare
                              | TC_CMR_ACPA_CLEAR          // Clear TIOA2 on RA compare match
                              | TC_CMR_ACPC_SET;           // Set TIOA2 on RC compare match

  constexpr int ticks_per_sample = F_CPU / 8 / sample_rate; // F_CPU / 8 is the timer clock frequency,see MCK/8 setup
  constexpr int ticks_duty_cycle = ticks_per_sample / 2; // duty rate up vs down ticks over timer cycle; use 50%
  TC0->TC_CHANNEL[2].TC_RC = ticks_per_sample;
  TC0->TC_CHANNEL[2].TC_RA = ticks_duty_cycle;

  TC0->TC_CHANNEL[2].TC_CCR = TC_CCR_SWTRG | TC_CCR_CLKEN; // Software trigger TC2 counter and enable
}

最后可以用来触发ADC:

// start ADC conversion on rising edge on time counter 0 channel 2
// perform ADC conversion on several channels in a row one after the other
// report finished conversion using ADC interrupt
void adc_setup() {
  PMC->PMC_PCER1 |= PMC_PCER1_PID37;                     // ADC power on
  ADC->ADC_CR = ADC_CR_SWRST;                            // Reset ADC
  ADC->ADC_MR |=  ADC_MR_TRGEN_EN |                      // Hardware trigger select
                  ADC_MR_PRESCAL(1) |                    // the pre-scaler: as high as possible for better accuracy,while still fast enough to measure everything
                                                         // see: https://arduino.stackexchange.com/questions/12723/how-to-slow-adc-clock-speed-to-1mhz-on-arduino-due
                  ADC_MR_TRGSEL_ADC_TRIG3;               // Trigger by TIOA2 Rising edge

  ADC->ADC_IDR = ~(0ul);
  ADC->ADC_CHDR = ~(0ul);
  for (int i = 0; i < nbr_channels; i++)
  {
    ADC->ADC_CHER |= ADC_CHER_CH0 << channels[i];
  }
  ADC->ADC_IER |= ADC_IER_EOC0 << channels[nbr_channels - 1];
  ADC->ADC_PTCR |= ADC_PTCR_RXTDIS | ADC_PTCR_TXTDIS;    // Disable PDC DMA
  NVIC_EnableIRQ(ADC_IRQn);                              // Enable ADC interrupt
}

并且ADC输出可以在相应的ISR中捕获:

void ADC_Handler() {
for (size_t i = 0; i < nbr_channels; i++)
  {
      SOME_BUFFER[i] = static_cast<volatile uint16_t>( * (ADC->ADC_CDR + channels[i]) & 0x0FFFF ); // get the output
  }
}

我认为这是可以理解的,但是我有一个问题:预分频器的设置。

  • 如果我在线上理解的很好,应该将预分频器设置为frq_ADC >= sample_rate * nbr_channels,主要是因为该芯片只是通过多个通道对ADC进行多路复用

  • 如果我理解得很好,我们希望在给定先前约束的情况下将此类预分频器值设置得尽可能高,从而使ADC频率尽可能低,因为这会提高ADC的转换质量

是吗?

问题在于,我对如何设置预分频器以及与该值对应的值感到困惑,因为我在数据表中找到的内容与我阅读的其他一些在线回复不一致。

从数据表https://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-11057-32-bit-Cortex-M3-Microcontroller-SAM3X-SAM3A_Datasheet.pdf:“如果PRESCAL为0,则ADC时钟范围在MCK / 2之间;如果PRESCAL设置为255(0xFF),则ADC时钟范围在MCK / 512之间。这与我在1334页上找到的内容一致:“ ADCClock = MCK /((PRESCAL + 1)* 2)”。但是在第1318页中,记录了转换速率为1MHz。那如何与Due上具有84MHz的MCK频率兼容呢? 84/2 = 48MHz,84/512 = 0.164MHz,高频率值太高。

然后让我感到困惑的是,我发现了这个问题:https://arduino.stackexchange.com/questions/12723/how-to-slow-adc-clock-speed-to-1mhz-on-arduino-due/21054#21054也似乎与1MHz的上限冲突。

有人知道我误会了什么吗? (以及有关该程序正常工作的更多评论吗?)。

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)