The results from various opamps varied wildly, and results from positive and inverting buffering configs also varied a lot.
My best hit was with a UA741, in inverting mode the amplitude was perfect across the entire frequency range! Unfortunately, it was only a lucky strike, I retried several other UA741s and the result varied from around 7 to around 13V amplitude (when the real amplitude should be 10V).
The conclusion then is that at voltages very close to zero will experience a lot of variation even between specimens of the same family.
|Tested op amps|
I am not sure how the effects are over time and temperature, this must be tested.
If the effects are mostly production variations, it would be possible to calibrate each DCO.
This can be done in code even if DAC lookup tables must reside in program memory due to RAM limitations (1kB of memory is required for DAC keystep and rise-per-substep tables and the MCU only has 1kB of RAM in total). The PIC16F allows programmatical/runtime writes to flash program memory, and though there is a limit to the number of times this can be done (>10 000), even a write on every system startup would probably be possible.
Hopefully though, calibration will seldom be necessary. As a nice side effect, calibration will correct variances in both charging caps and resistors as well as opamps.
Here is how I imagine it to be done:
A reference voltage is applied to one of the MCU pins. This is used as the reference voltage of one of the internal comparators.
First, apply the lowest frequency. By increasing and lowering the DAC output voltage until the comparator changes polarity, we figure out
- if the voltage is too high or too low
- if the amplitude error is within acceptable limits
A slightly too low amplitude is acceptable but a too high amplitude is not as this will trigger the comparator during normal operations, if we choose to use it as a reset-on-frequency-change trigger. The amplitude must also be adjusted to always be slightly lower than the comparator trigger point to prevent false triggers.
We also have to consider measuring the highest frequency amplitude error to see if errors are always either high or low. For now, I'll assume that they are always one or the other.
After finding the initial error, one loops through the remaining 255 samples, starting from the bottom.
For every frequency, the DAC voltage is increased or lowered (based on what we found for the lowest frequency) until the comparator changes polarity - this gives us the "correct" value for that step. To save time, we may stop checking once we reach a frequency where the error is small enough (and lower than the comparator voltage).
We should now have a correct lookup table for key samples. All that is needed now is to calculate the interpolation lookup table, and write everything to non-volatile flash memory.
To minimise the number of recalibrations, we could let the DCO check the keysamples on startup. If they are still within limits, no recalibration is necessary.
A different approach to finding the current amplitude would be letting the DCO control a PWM-based DAC to generate the reference voltage. It could then change the reference voltage instead of DAC output value to find the amplitude. Not sure that it's a better approach though.
PS: If the signal amplitude is 10V, using a resistor divider with R1 = 100k and R2 = 68k will get the amplitude down to 4.048V. This lets us use the internal 4.096V voltage reference with the comparator.