对于 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
}
并且可以在相应的 ISR 中捕获 ADC 输出:
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:“ADC 时钟范围在 MCK/2 之间,如果 PRESCAL 为 0,并且 MCK/512,如果 PRESCAL 设置为 255 (0xFF)。"。这与我在第 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 上限冲突。
知道我在哪里误解了一些东西吗?(还有关于程序一般工作的更多评论吗?)。