Any oscilloscope that uses the RP2040 ADC will be limited by its modest maximum sample rate of 500kS/s - and so when I saw on the Raspberry Pi forums a thread titled RP2040 ADC Overclock - 4Msps! - I decided to investigate to see if higher sample rates could be achieved without an unacceptable effect on oscilloscope performance.
My oscilloscope uses the Scoppy firmware and Android app but the information here applies to any oscilloscope that acquires its samples using the internal ADC of the RP2040.
The RP2040 datasheet states that the clock source for the built-in ADC must be 48MHz and that each ADC conversion takes 96 clock cycles. This gives a maximum sample rate of 500kS/s (ie. 48000000 / 96 = 500000). This in turn limits the maximum bandwidth achievable by an oscilloscope that uses the RP2040's internal ADC.
However, if we ignore the datasheet and clock the ADC at a higher rate then we can achieve sample rates of 2.0MS/s or higher.
How to increase the maximum sample rate (i.e. reduce the sampling time)The maximum sample rate can be increased by reducing the time required to acquire each sample. Each sample acquisition takes a fixed number of ADC clock cycles and so the obvious thing to do is reduce the ADC clock period....so how can we do that?
The Pico C-SDK configures the ADC to use the fixed frequency USB PLL as its clock source. This runs at 48MHz and in turn limits our sampling rate to 500kS/s. We can however configure the ADC to use the variable frequency system PLL as its clock source. The default frequency of the system PLL is 125MHz and so this alone will increase our maximum sample rate to approximately 1.3MS/s (125M / 96 = 1.3M)
In the forum post mentioned above, the author configures the ADC clock source by directly accessing the CLK_ADC_CTRL register. I prefer to use the clock_configure SDK function as it not only updates the CLK_ADC_CTRL register but also allows the ADC clock frequency to be accurately queried with the clock_get_hz function.
uint32_t adc_clk_freq_hz = clock_get_hz(clk_sys);
clock_configure(clk_adc, 0, CLOCKS_CLK_ADC_CTRL_AUXSRC_VALUE_CLKSRC_PLL_SYS, adc_clk_freq_hz, adc_clk_freq_hz);
The code above sets the system PLL as the ADC clock source.
How to increase the maximum sample rate even moreOK. Now that we have the ADC clock generator tied to the variable frequency system clock we can increase the system clock frequency to get even higher sample rates. Here's the code to do just that:
// Set the sys_clk to 192MHz (192000kHz)
set_sys_clock_khz(192000, true);
In the code above I've set the system clock to 192MHz which gives us a maximum ADC sample rate of 2MS/s (192M/96=2M).
PerformanceThe next thing I did was run some simple (some might say simplistic!) tests to check what affect overclocking the ADC has on the performance of our oscilloscope - specifically with regards to amplitude measurement accuracy, distortion and the appearance of the displayed waveform.
No attempt has been made (by me) to characterize the ADC in terms of ENOB, INL and DNL at these higher clock frequencies. I'll leave that to others.
Some of the findings are outlined below and more details can be found here.
Waveforms
The appearance of the waveforms (traces) was very similar when comparing the clocked vs overclocked ADC except that I occasionally did see some small glitches at around 0 volts as shown in the image below.
DC Voltage Measurement
In one of the tests, I simply fed a 2.07V DC signal into the oscilloscope and compared the voltage reported by the oscilloscope at different ADC clock frequencies.
At the default clock frequency of 48MHz the voltage measurement was 2.08V. At 125MHz and 192MHz ADC clock frequencies the oscilloscope reported a voltage of 2.13V.
So yes, overclocking the ADC can affect the measurement accuracy of the oscilloscope. In the example above this was a 2% discrepancy.
Distortion
The FFT of a 1kHz sine wave shows slighly higher peaks at the fifth and seventh harmonics with the ADC clocked at 192MHz compared with 48MHz.
In the first attempt to implement the higher ADC clock frequency in the Scoppy app and firmware, I simply had the firmware set the clock frequency at boot time according to the 'Max. Sample Rate' setting in the app (the user can select one of three maximum sample rates - 500kS/s, 1.3MS/s and 2MS/s which correspond to the ADC clock frequencies of 48MHz, 125MHz and 192MHz respectively).
However, I didn't like the fact that the performance would be degraded - even if only slightly - when the firmware was sampling at 500kS/s or less (in which case the higher ADC clock frequency wouldn't be required anyway).
Note. The RP2040 samples at lower than maximum sample rates by inserting a gap between acquisitions and not by lowering the ADC clock frequency. This means that changing the ADC clock frequency affects the ADC at all sample rates.
The fix for this was quite simple. Like many (all?) oscilloscopes, Scoppy will change the sample rate according to the Time/Div setting set by the user. All that was needed was to configure the firmware so that the higher ADC clock frequencies are only used when the sample rate needs to go above 500kS/s. This implementation preserves the current performance at the existing sample rates supported by the app/firmware/RP2040 but still allows the higher samples rates when required.
GotchasChanging the system clock frequency on-the-fly does affect peripherals that use the System PLL as the clock source. For example, I use the UART for debugging purposes and my serial terminal would stop working when the clock frequency changed. The solution for this was to configure the USB PLL as the peripheral clock source (rather than the default system PLL) on boot as follows:
// The default is to use PLL_SYS as the clock source for the peripherals (UART, SPI etc)
// Change this to PLL_USB so that overclocking SYS doesn't affect the peripherals
clock_configure(clk_peri, 0, CLOCKS_CLK_PERI_CTRL_AUXSRC_VALUE_CLKSRC_PLL_USB, 48 * MHZ, 48 * MHZ);
Other peripherals such as the PIO and PWM are clocked at the system clock frequency (and as far as I know can't use a different clock source). The Scoppy firmware uses the PIO for its logic analyzer and PWM for the signal generator and so these are reconfigured each time the system clock frequency changes.
How to use the RP2040/Pico as an oscilloscopeFirmware
Of course you can write your own firmware but I suggest you start by installing the (free to download) Scoppy firmware and Android app.
Hardware
Any usable oscilloscope also needs some signal conditioning circuitry (analog front-end), examples of which can be found on the Scoppy github page and documentation. Alternatively you could try the open-source FSCOPE-500K hardware.
Inexpensive oscilloscopes that use the Scoppy firmware and app can also be purchased from Elecrow and Tindie. These include the DSO-500K, FSCOPE-500K Kit and FSCOPE-500K.
How to quadruple the maximum sample rate when using the Scoppy firmware and app- Ensure you have the the latest Scoppy firmware installed on your Raspberry Pi Pico (or Pico W).
- Install the latest version of the Scoppy app on your Android device.
- In the Scoppy app go to Menu > Settings > RP2040 Settings > Max. Sample Rate
- Tap 2.0MS/s and then OK.
Done!
Comments