I want to do AC RMS measurement. The input signal is derived from the utility power line, so it's frequency not so stable. So i want to use PLL to synchronize the ADC sample pulses to the input signal. Use PLL to generate N pulse per cycle, then route these pulses to ADC. Is this possible?
PLL synchronized ADC sampling
adcpll
Related Solutions
These methods are used. The TI MSP430, for example, uses something they call a "modulator" which is essentially what you're talking about.
The main advantage is that that they are super simple and they can change their output frequency quickly (without any lock-time or whatever that PLL's require), and without any "glitches".
I'll also mention another method that you didn't mention (directly). It is, essentially, a super simple version of making your approaches 3 and 4. It's called a numerically controlled oscillator. Here's a code snippet in VHDL (but it's generic enough that most should be able to follow):
signal phase :std_logic_vector (n_bits-1 downto 0) := (others=>'0');
process (clk_in)
begin
if rising_edge(clk_in) then
phase <= phase + inc;
end if;
end process;
clk_out <= phase(phase'high);
Basically, we have an n_bit long accumulator (a.k.a. counter). On each clock, we add 'inc' to the accumulator. The most-significant-bit of the accumulator is output as the new clock signal. The output frequency is calculated like this:
Fout = Fclk_in * inc/(2^n_bits)
Where Fclk_in is the input clock frequency, inc is the value added to the accumulator, etc. Fout can be anything less than Fclk/2. For more accuracy, or a lower output frequency, you need more n_bits.
The output of this logic is essentially a jittery clock, where the jitter is about 1 clk_in period. The frequency and duty cycle will be dead-on (given n_bits and the clk_in period).
I have frequently used this logic to generate baud rates and other slow but accurate clocks. Since I work with FPGA's and not too many ASIC's I normally keep the logic synchronous with respect to clk_in and output a clock enable signal or something-- but the same concepts apply.
While more elaborate interrupt- or DMA-based code would be necessary to achieve the best performance, relatively minor improvements to your code would improve the situation already. I'd start by transmitting samples in binary instead of in text. This requires slightly more work at the receiving end, but will cut the required UART bandwidth by at least 2-3x (2 bytes per sample vs. up to 6 in text with separator). You can also readily increase the baud rate to, e.g., 921.6kbps, which is standard and should be well supported on the receiving end. Assuming a standard STM32F2 architecture, you could go up to 7.5Mbps but you'd need to check support for that at the receiving end.
With 2 bytes per sample and 921.6kbps, you would get a throughput of about 46'000 samples/s. At 7.5Mbps, you'd get 370'000 samples/s. If your application allows it, you could reduce the resolution to 8 bits and thus use a single byte per sample, effectively doubling the throughput in samples/s.
While 370ksamples/s is not bad, it's still pretty far from the theoretical 6Msamples/s (assuming STM32F2, 12bit conversion and using the 3 ADC in triple interleaved mode). This translates to 12MB/s of data to transfer from the MCU to the computer, which is no trivial amount. UART will not do. SPI, at a max of 30Mbps (2-3MB/s) wont do it either. Writing to a microSD card via SDIO would come close. USB 2.0 would do it but is much more complicated software-wise and requires external components for the PHY. ETH would do fine as well but would require additional components and a network stack to be implemented on the MCU. This complexity explains why, in most applications, the samples are buffered in memory and transferred asynchronously.
Best Answer
Yes this is quite feasible and I remember doin this back in the 80s on one job because the processing power we had was not enough to create too many samples per cycle and, with an exact integer number of samples per cycle, you can avoid certain errors thus the calulation is quite precise. Here's a little picture showing what I mean: -
The pink trace is a pure sinewave and there are exactly 8 samples taken in one cycle of the sinusoid. If you take all the sample values and calculate RMS you get exactly 0.7071.
It's also worth pointing out that the samples don't need to be aligned with the sinewave's zero crossing. Should the samples have began a little late at 22.5 degrees, the accumulation of squared samples would be: -
0.1464 + 0.8536 + 0.8536 + + 0.1464 + 0.1464 + 0.8536 + 0.8536 + 0.1464 = 4
Dividing by # of samples gets 0.5 and taking the square root yields 0.7071 i.e. exactly the same.
Should your sampling have been asynchronous to the sinewave, there would have been an error on the first cycle of calculations that would eventually even-out over enough cycles but if you want to do this quickly, with minimal CPU overhead then using a PLL to "sync" sampling to the AC waveform works.
Of course, if you take more samples per cycle the error reduces and, if you average over several cycles the error also reduces.
One extra word of warning about sampling - the harmonic distortion in your waveform can affect this calculation due to aliasing - as ever, you need to sample greater than twice the highest frequency in the waveform you are analysing.