I think it's finally time for an update.
I've spent the last three weeks working on this project again, and I'm happy to report that I have solved all software issues so far. It's amazing how after a year of working with the RP2040, I was able to come back to this project and get it up and running in no time! I also have to thank iMo for the suggestion of using set pins for both reference switches and the input switch, it saved a few instructions. While I was at it, I also optimized the runup code to use fewer instructions.
First, I was able to move the residue ADC reading code to PIO, and I have synchronized it with the runup PIO code via interrupts. I replaced the MCP3202 with the MCP3201, since the second channel was unused, and the two-channel version needed configuration. Switching to the single channel version simplifies the code.
The second big change was to reduce the modulation frequency from 300kHz to 75kHz. I took a closer look at the scope waveforms, and the integrator summing junction didn't settle to a reasonable level in the short constant phase of each runup cycle. I also tweaked the voltage divider between the two OPA140s while looking at the output of the first stage op-amp to obtain an optimum response. That happened with a divider of approximately 4kΩ/1kΩ. I have attached a scope screenshot that shows the first stage op-amp output on Ch2 (cyan) with 10kΩ/1kΩ, you can see how the rising edge is rather slow and has an RC-like curve. After tuning the divider, the spike is still present but the curve goes away. I wonder if I could implement more advanced compensation, but I am not sure how I would do that.
With just runup and residue, the resolution is rather limited, with around 50μVpp noise in the readings, plot attached.
I also implemented Kleinstein's idea for fast rundown (I learned that this originated in the 3456A meter) to reduce the range of voltages that the residue ADC has to digitize. One advantage here is that the scaling buffer amplifier in front of the ADC has to amplify the integrator voltage instead of attenuate it, which should reduce the residue ADC's referred-to-input noise. A waveform with 5 runup cycles is attached, you can also see the fast rundown at the end after a short dwell time. Ch1: integrator, Ch2: input switch control, Ch3: -ref switch, Ch4: +ref switch.
With that change, the noise has gone down quite a bit. The second plot attached has units of LSBs, I will change the code in a bit so the readings are in volts. But based on some rough calculations, looks like the noise is around 2μVrms or around 13μVpp.
Here are the formulas used to calculate the counts:
Step 1:
N1 = n_neg*(7*RUU + 1*RUD) - n_pos*(1*RUU + 7*RUD)
where:
n_neg - number of times the negative reference was turned on
n_pos - number of times the positive reference was turned on
RUU - residue counts corresponding to 1/8 runup 'up'
RUD - residue counts corresponding to 1/8 runup 'down'
(fast rundown has a 1/8 runup cycle resolution)
Step 2:
N2 = n_rundown_neg*RUU - n_rundown_pos*RUD
where:
n_rundown_neg - number of 1/8 runup units the negative reference was turned on
n_rundown_pos - number of 1/8 runup units the positive reference was turned on
Step 3:
N3 = residue_before - residue_after
where:
residue_before - residue ADC reading before runup
residue_after - residue ADC reading after runup
Step 4:
FINAL = N1 + N2 + N3
where:
FINAL - final result, in units of residue ADC counts
N1 - runup counts (in terms of residue ADC counts)
N2 - fast rundown counts (in terms of residue ADC counts)
N3 - residue difference (in terms of residue ADC counts)
Final result is in terms of residue ADC counts, equivalent to an LSB
The residue ADC is calibrated by switching +ref and -ref to the integrator for 1/8 runup period and measuring the difference in integrator voltage before and after. This is because the fast rundown resolution is 1/8 of a runup cycle (runup has a 1/8 or 7/8 duty cycle).
There's a few more modifications and improvements I'd like to make to the circuit, I will post an update regarding that later.
The latest C code for the RP2040 can be found in the project repository:
https://github.com/NNNILabs/Multislope-3I/tree/main/SWThere is also a file called project.log in the SW folder. It's just a text file with a little more details on what modifications I made on what date.