(Yet Another) DIY Multislope ADC - Page 1
Forum section: electronics / projects

author: NNNI
author_rank: Regular Contributor
timestamp: August 27, 2021, 07:04:31 am
content: Hello!This is my very first post here, and I think I have good reasons to be nervous - I've come back to the EEVBlog forums many times, since a lot of people have posted their multislope ADC designs here, and for some reason I feel mine is a little...simple. And there is also the fact that I don't own a DMM capable of measuring more than 3.5 digits.With that being said, here is the story behind and the details of my multislope ADC.I got started on this project because I got jealous of someone getting a Keithley DMM, so I said to myself: "I'm going to make my own!" Of course, I was only this confident because I'd read the Art of Electronics 3rd edition and knew there was something about similar high resolution DMMs. At first I wanted to make a delta-sigma ADC, but after trying to understand the maths behind it, I decided to try something simpler - namely a dual slope. I got as far as a simulation (https://tinyurl.com/ygr27pba) and making a perfboard prototype, but that didn't work so well and I'd moved on to a multislope, which was described in some detail.I call the topology I came up with "free-running", because as long as a clock signal is present, the multislope keeps running. Here is a link to a simple simulation:https://tinyurl.com/yes5kj7vSurprisingly I got the thing to work on a breadboard, but of course, didn't make any measurements then because I knew it was pointless. I got a PCB made and I was able to make some first-order measurements, but was not able to get the residue measuring ADC working, and that had to be abandoned in favour of the second revision of the PCB, this time with much better parts and an LM399 voltage reference. The uC I ended up choosing was the Raspberry Pi Pico, since I got rather enamoured with it and the 500ksps 12-bit (yes, I'm aware of the quirks, I've read Mark Omo's website about it) ADC it has. Of course, there is a separate 3.3V reference for the ADC, I'm not relying on the noisy internal switcher. As for the actual software, a friend of mine is writing the code for me, and he had a brainwave - using the SPI protocol to provide a clock signal to the multislope, and reading the output of the D flip-flop on the falling edge of the clock signal to get the counts for which the negative reference was turned on, and with some maths you can figure out the time the positive reference was turned on and ultimately the input voltage. This approach worked, as seen in a video I made about it (the second half:https://www.youtube.com/watch?v=ucJOKAhCHTQ,and yep, that's my channel) and I hope with some calibration and residue measurement the readings will start to make sense. No way to test beyond 3.5 digits however...I'm well aware of the limitations of my topology, especially the fact that each switch is turned on an unknown number of times for a given number of clock cycles, for that reason the PCB has a few jumpers to change the switch inputs to PWM, so I can implement some kind of constant switch cycles algorithm.I have not been able to test the second revision of the PCB yet, since I've had some trouble finding the LT5400-1 resistor network, but I should be getting some soon and I'll post updates then!In the meanwhile, here is the schematic and a picture of the board.

author: RoGeorge
author_rank: Super Contributor
timestamp: August 27, 2021, 07:09:37 am
content: Congrats, the board looks very nice!

author: Kleinstein
author_rank: Super Contributor
timestamp: August 27, 2021, 07:34:56 am
content: If you have trouble getting LT5400: AFAIK the MORN networks have a compatible pinout, though no thermal pad at the bottom. For the not so high target, this should be well good enough. The MORN networks may also be available with more resistor values (e.g. 20 K , 50 K).The resistor R4,5,6,7 are nearly as important for the accuracy.Just in case you plan the build / polulate another board. The OPA2197 is not the very best choice. For the reference amplification part I would prefer an OPA2202 (less drift and LF noise). For the Integrator it is OK though an OPA1642 would be lower noise. There is some advantage to have 2 separate OP for the integrator, so the ouput dirver does not effect the other OP that is setting the precision.The feedback with the Flipflop makes this a very basic sigma delta ADC.I may be worth looking at the old solartron DMMs / mark space ADC (e.g. US3918050): when adding a forcing signal one could get a fixed (and lower) switching frequency. The result could still be from the comparator timing directly.

author: NNNI
author_rank: Regular Contributor
timestamp: August 27, 2021, 07:53:52 am
content: Quote from: RoGeorge on August 27, 2021, 07:09:37 amThanks, hope it works as well as it looks!

author: NNNI
author_rank: Regular Contributor
timestamp: August 27, 2021, 08:00:09 am
content: Quote from: Kleinstein on August 27, 2021, 07:34:56 amThanks for the suggestions!I just took a look at the MORN networks and they are indeed cheaper than the LT5400 series, but Vishay does not seem to have them in stock as well. I tried to get some good +/-25ppm resistors for R4 - R7, but they were out of stock, so I think in the next revision I'll end up using more of the MORN/LT5400 resistor networks.My op-amp choices were dictated by what LCSC had in stock, since I got this board JLC assembled. I'll definitely consider using separate op-amps for the integrators, I can see how having two separate ones will help.I will definitely take a look at the Solartrons and the mark space ADC.Thanks once again for the suggestions!Attached below is the table I made for selecting op-amps, there was another column for slew rate based on which I chose the OPA2197/OPA197.

author: Kleinstein
author_rank: Super Contributor
timestamp: August 27, 2021, 09:02:21 am
content: The choice at JCL is indeed a bit limited. At least they have the OP07 even as a standard part, which is a perfectly fine choice for the reference amplification. Building an MS-ADC from the parts available at JCL would be a challange - though not impossible.For the integrator the choice of OPs depends on the intendent integration time. With a relatively short integration (e.g. 20 ms) and switching between the signal and zero input even an TL072 is possible (I had this on the breadboard and still got to the 6 digit range). If a longer (e.g. > 200 ms) integration at a piece is planed / needed to get sufficient resolution (e.g. with the mark space like design) the low frequency noise would become an issue. Than a zero dift OP could be the better choice for the presicion setting OP at the integrator. This OP can use a lower (e.g. +-2 V) supply - there are than quite a few to choose from and a few even at JCL. An AZ OP may want an extra local feedback cap and input resistor. The output driving OP only needs to be fast ( e.g. > 5 MHz GBW would be nice, 10 MHz is good), but the noise hardly matters.The slew rate is not important, as the OPs are used in the small signal range. A good OP (fast and precision) as a single OP integrator may also work if the reference resistors are equal.If not limited to the footprint there are other resistor networks that could be used: e.g. NOMCT (lower noise than NOMCA) and in the low cost corner also the ACAS series. For the reference voltage there is no need to go for exactly 10 V. A gain of 1.5 or 1.33 would be OK too. For simplicity I used a gain of 2 in my design, though this needs a higher supply. Using equal resistors and 2 or 3 in parallel / series can be an option, even with discrete resistors.With reistors from the same reel, 25 ppm/K types may be good enough for the start, as the matching is often quite a bit better than absolute TC. One also usually only cares about a smaller temperature range.

author: ali_asadzadeh
author_rank: Super Contributor
timestamp: August 27, 2021, 09:28:53 am
content: Shouldn't you Connect the 4053 part to +-12V supply!? it's power is only 3.3V and GND.

author: Kleinstein
author_rank: Super Contributor
timestamp: August 27, 2021, 09:49:50 am
content: The 4053 swich does not need a higher supply. The switch directs the currents from the input or the references to either ground or the virtual ground at the integrator input. So the switch pins will see a votlage very close to ground (e.g. +-20 mV around ground). Even if things go wrong with the integrator feedback and the integrator input is no longer at ground, the current from the references and the input is limited by the resistors to a low level (e.g. 100 µA range).The LV4053 needs the low supply to work with the logic levels too. 5 V supply would help the switches a little (lower resistance), but it than is boarderline with 3.3 V logic levels.

author: NNNI
author_rank: Regular Contributor
timestamp: August 29, 2021, 06:08:42 am
content: ali_asadzadeh: What Kleinstein says is right - the switch nodes are more or less at 0V because of the integrator summing junction and the normally closed part of the switch being at ground - this is a current switched topology, and I can get away with powering the 4053 with 3.3V. I could have chosen a higher voltage, but since the 4053 does not have logic level translation for the inputs, and my microcontroller and logic runs at 3.3V.Kleinstein: True, I've seen the OP07s used in the Solartron 7081 for the same purpose in one of Marco Reps' videos. It is a good op-amp, but there are better ones available, and for the sake of convenience I wanted to use the same op-amp type across the entire board - preferably a single and dual version of the same op-amp, hence OPAx197.I did use the TL072 in the prototype, but I felt I could do better in terms of noise with a better op-amp choice. I'm not entirely sure about using auto-zero op-amps in the integrator, since I think only stability of offset/bias with temperature is more critical than having no offset. The multislope clock is 100kHz to 125kHz, so run-up should be in the order of 10s or 100s of ms. Maybe a faster clock would have benefitted, or some kind of amplifier at the integrator output, as I've seen on some designs.Luckily I was able to get my hands on some LT5400-1s, I should be getting them soon and posting the first results here.

author: Kleinstein
author_rank: Super Contributor
timestamp: August 29, 2021, 08:57:13 am
content: The refrence amplifier part is DC only. At DC / very low frequency the OP07 is supperior to the OPA197. In other places the OPA197 can be better.The right OP for the job depends on the function.The lower frequency end relavant for the integrator depends on the integration time. With 20 ms or 200 ms integration and thus a relevant frequency of 25 or 2.5 Hz the OPA197 is still good and no need for an AZ OP. If you "only" want 6 digit resolution the OPA197 would even be OK for 2 seconds integration. With longer integration I would prefer the AZ OP. This requires 2 separate OPs obviously.The needed intgration time to reach a given resolution depends on the resolution one gets in measuring the charge at the start and end.The shown hardware seems to have 2 possible methods:1) the comparator and the timing of zero crossing, like the solatron meters2) the µC internal ADC to measure the voltage at the integrator, like the HP34401For comparator method it is about timing resolution. The frequency of the modulation does not directly effect the resoluton. With some 100 ns timing resolution and 100 ms integration time one would be close to 6 digit resolution. It is still a bit less because there are 2 measurements and the references are stronger than the full scale input. So it would need more like 200-500 ms integration to get 6 digit resolution from the pure quantization limit.The modulation frequency and thus the capacitor size effects the noise for the charge measurement. A smaller cap makes the comparator less critical as the slope is steeper. The extra amplifier (slope amplifier - quite often an NE5534 with 2 additional diodes in the feedback) after the integrator is there to help the comparator. It gives a first amplification stage with a known low noise and allows the comparator to switch faster. Another, less obvious function of the slope amplifier is to get a defined and not too large bandwidth. So there is sometimes an extra cap to slow down the slope amplifier, but usually just GBW divided by the gain is enough.For the ADC way, the modulation frequency makes a difference, as with fast modulation the capacitor can be smaller and this more charge resoultion from the given voltage resolution. However a faster modulation also needs a faster ADC and more critical timing. A crude approximation for the resolution is the auxiliary ADC steps times number of modulation periods divided by about 3. For the start I would still not make the speed very high - first get it working at all (less critical timing) and than think about optimization.p.s.:I just has a look at the ciruit: ideally one of the currently unused (grounded) inputs of the MUX should also get the raw 7 V reference as an optional input. This the more stable signal than the +-10 V to check the ADC gain.

author: NNNI
author_rank: Regular Contributor
timestamp: August 29, 2021, 03:28:12 pm
content: I thought that since the OP07 is an old part I might replace it with something new, but I'll take a look at the specifications of both again and maybe change it in the next version.And yes, this is meant to resolve voltages only down to 1uV (hopefully with the same accuracy) so I don't think I need anything very fancy.I did leave a lot of options open in terms of selecting run-down/residue measurement. For now, I want to do residue measurement since it does not need exceptional timing. The comparator and the analog switches can be operated by the microcontroller directly - what I was thinking was to try PWM, where the microcontroller outputs PWM in such a way as to have the positive and negative reference switch a constant number of times, and maybe use the comparator output to trigger an interrupt to update the duty cycle in such a way as to keep the integrator from saturating.I did coincidentally take a look at the famous 1989 HP Journal with the article about the 3548A ADC, and noticed the amplifier before the comparator, but since I'm doing residue measurement I don't need it...for now.Also the reference voltageisconnected to one of the inputs of the MUX, the node is labelled 'RAW'.Edit: I took a look at the datasheets of the OP07 and the OPA197, and yes, only the OP07 (specifically the AD one) specifies long term stability, so that is definitely something to consider. Thanks for the suggestion!

author: iMo
author_rank: Super Contributor
timestamp: August 29, 2021, 04:09:14 pm
content: Double-check whether the OP07 gives you +/-10V output with +/-12V power.The TI's OP07 DS shows 0.5uV/K and 0.4uV/month.Would not be an OPA277 better one (0.1uV/K and 0.2uV/month), even we talk 399 ??

author: Kleinstein
author_rank: Super Contributor
timestamp: August 29, 2021, 08:07:54 pm
content: The are more modern alternatives to the OP07 - the big pluse with the op07 is it't relatively good availability (even a standard part at JLC).Getting 10 V out with a 12 V supply is very much boarderline - it may help at low current (e.g. add extra resistors to + or - 12 V to provide all the current and maybe a little more).For a LM399 ref the OP07 is usually good enough. The resistors for the 7 to 10 V and 10 V to -10 V step are more critical.1 µV resolution is possible, though not easy. It may need some averaging with the OPA197. In the shown circuit the OP in the integrator sees a noise gain of 3 (or 4 with an extra resistor at the input to reduce the effect of the R_on drift). This would result in about 1 µV_rms noise alone from the OPA197 in the integrator and longer integration would not help much, as there is 1/f noise.1 µV accuracy with a 10 V range is not going to happen so easy. It may be the limit to call known errors to be acceptable, so a kind of good enough limit. However chances are there are some errors that will be larger. There are plenty of small effect that may cause errors in the low ppm range. A point that can cause some error is the nonlinear resistance of the 4053 r_on. This gives a small square law contribution with a positive sign to the ADC. The small resistors are good for low noise, but can increase the INL.I would consider 100 µV Ok for the start, later maybe 10 µV if things go well. The OPA197 used as input buffer alone may give an error in the 10 µV range.Using PWM to control the feedback is an OK idea - I also use this in my new version. However I use a timer interrupt to check only the comparator state once per cyle and than a binary modulation only. Using the comparator timing to get more information for a continuous PWM feedbach is possible, but a bit tricky. It may be easier to use the µC internal ADC also for the feedback.

author: NNNI
author_rank: Regular Contributor
timestamp: November 05, 2021, 05:18:42 am
content: It's been a while, but I have an exciting update: I finally got some LT5400 resistors, thanks to a certain ExtraSolar!I'll start working on the multislope again after I finish the current project I have on hand, a fully discrete CC/CV linear supply.

author: NNNI
author_rank: Regular Contributor
timestamp: November 13, 2021, 05:08:38 pm
content: It took me way longer than it should have, thanks to some problems uploading code to the Pi Pico (turns out that it is not recognized by the computer when powered externally with 5V) and a mistake in the PCB (ironically, the same one I made on the previous iteration of the board), but I finally got it working!For now, this is the "free-running" mode where the thing just oscillates on its own with the provision of the clock signal, no measurements being made. The next step I have to take is coming up with an algorithm that implements the constant switch transitions in PIO, do the residue measurements using the in-built 12-bit ADC, maybe use timers to sync to 50Hz, and have the main processor do the maths to turn counts into volts.

author: NNNI
author_rank: Regular Contributor
timestamp: November 18, 2021, 04:29:22 am
content: After a few days of work, I was able to implement a constant switch cycles algorithm on PIO.This algorithm comes from Takovsky (familiar name around here...?) - it uses PWM to maintain a constant number of switch transitions in every cycle to make sure charge injection errors can be calibrated out. The PWM duty cycle switches between (in my case) 20% and 80% depending on the state of the integrator. This makes sure that there is always a zero crossing in every PWM cycle. Here is a link to a Falstad simulation where the PWM generator is implemented using some building blocks:https://tinyurl.com/yfhwuvolThe PIO code was implemented by my collaborator Dimin, who is working on the software.For now, we have this free-running again, the next thing to implement would be generating N PWM cycles and counting how many times each reference was turned on for 80% of the duty cycle, and then converting those counts into volts. The last step would be to add a residue measuring ADC.

author: NNNI
author_rank: Regular Contributor
timestamp: December 19, 2021, 06:38:28 pm
content: It has been a while since my last post, but I have not been idle.I did a lot of research about different multislope algorithms, and I'm going to mention two here.While I was waiting for code ( I outsource coding), I was wondering what kind of topology I could make using just some simple logic I had on hand, and what I came up with was a bounded integrator topology - the integrator waveform oscillates between a set positive and negative limit. This is accomplished using a JK flip-flop (4027) clocked at an arbitrary frequency - the higher the frequency, the less chances of over/undershoot and more resolution. The limit comparators are hooked up to the J and K inputs in a way that turns on the respective ref switch to keep the integrator within bounds. Here is a link to a Falstad simulation:https://tinyurl.com/y6g6yansSince the slopes are much longer, the number of transitions per clock cycle is considerably lesser than the other topologies I've tried - depending on the clock, the bounded integrator topology has around one transition every 10+ clock cycles, free running has between one transition every clock cycle or less, while the PWM method has exactly two transitions per clock cycle. I assumed that keeping the number of transitions as low as possible would reduce problems due to charge injection. Transitions per clock is a very loose measure of charge injection.Of course, this method is not without its problems - for one thing, the overall frequency of the integrator ramps changes with changing input up to 50%...initially this didn't seem like a problem to me until I realized that the measurement time would have to vary if I wanted a fixed number of slopes, that is, the counts per clock changes with changing input voltage. One more glaring issue is dielectric absorption, which has plenty of room to manifest itself with slow slopes, which leads to loss of linearity. I was later informed that I had partially re-invented the Solartron 7081 ADC, except that I didn't have that weird square wave injection circuit. I have attached a few images of this bounded integrator that I built on a breadboard.Since I felt like I was waiting around too much for code, I explored the possibilities of making the PWM algorithm work using discrete logic ICs, and I did end up making something using an 8:1 mux (HC151, for example), a binary counter (HC193) and a D flip-flop (4013):https://tinyurl.com/y4xps42rMaking the whole thing using logic would be finicky but not difficult - have the microcontroller generate a clock, pulse a pin to start conversion, and read back the output of the counters using PISO shift registers. Of course, just using microcontrollers would be the easiest way out, but I found this little thought experiment fun, and along the way did a lot of thinking about the way results are derived from the PWM topology.Going the logic way, each PWM cycle takes up (in my case) 8 clock cycles, so it would be possible to get 8 counts per PWM cycle, that is, one count per clock cycle. but since the first and last part of the PWM waveforms cancel each other out (duty cycle is either 12.5% or 87.5%, so the first 12.5% and the last 12.5% cause charges of the same magnitude but opposite polarity in the integrator, so they cancel out) and the main counting happens in the difference in duty cycle extremes. So ultimately it comes down to one count per PWM cycle, or one count every 8 main clock cycles.With all this boring theory out of the way, I will focus on getting the code up and running and actually post results.Found this interesting paper:https://dspace.mit.edu/bitstream/handle/1721.1/84880/868678609-MIT.pdf?sequence=2

author: Kleinstein
author_rank: Super Contributor
timestamp: December 19, 2021, 09:11:44 pm
content: The vesion with simple fixed bounds for the upper and lower limit has the problem with a variable frequency. The DA effect is actually not bad, as the slower part of the DA depends on the average voltage in the integrator. So this part would be rather small.To get closer to the Solartron working one could use time dependen bonds. So that with time the bonds get lower. The exact waveform for the bonds does not matter, so it could be some RC fitlered rectangular waveform or piecewise linear. The only point is to keep the waveform stable, or use a 3rd comparator for the actual zero crossing. With suitable modified bonds one can get a constant frequency for the PWM signal. The difference to the Solartron (mark - space type) ADC is that the forcing waveform is moved to the other side of the comparators.A week point of such a contineous integrating ADC is the somewhat limited resolution (~ 0.7 * Integration time / timing resolution ) and that the integration time can vary a bit whern the signal and thus the waveform is not stable. For a fixed time one could in theory read the residual charge with an ADC, like in the HP34401. This may also get a little more resolution than just the timing.With a constant swtiching frequency the charge injection is not the real problem. It would be only variations in the charge injection that matter. There is still more sensitivity to clock jitter when switching is more often.

author: NNNI
author_rank: Regular Contributor
timestamp: December 20, 2021, 05:56:31 am
content: Reading residual charge using an ADC is what I was initially planning, and I will experiment with that too, but the only problem with that is that it involves some math and needs to keep track of the timing between the residue measurements. It requires that both the main conversion and the residue reading be converted to volts before they can be added together, but the dual slope rundown described in that paper produces counts that can be directly combined with the main counts, and then converting counts to volts takes place in the last step. Also, the fixed number of bits of rundown is convenient.

author: NNNI
author_rank: Regular Contributor
timestamp: January 12, 2022, 08:42:30 pm
content: This might be a bit premature, but I got to finish the 3D printed case and the power supply...and the results are terrible - I could have done a much better job. The only reason I'm pushing it is because I might actually have to use this to make (crude) measurements soon.As for the software, still working on it. Since I'm using PIO, getting the timings is proving to be a challenge. However, I think I might have just the right person to help me.Hopefully I'll be able to postactualdata and statistics soon.

author: NNNI
author_rank: Regular Contributor
timestamp: January 15, 2022, 08:26:36 pm
content: Finally got the PIO PWM timings right! now the duty cycle is an exact 1/16 and 15/16, with a frequency of 200kHz which keeps the integrator swing to more or less +/-5V over the entire input range.The second picture presents something more interesting - I was running the multislope for 50 PWM cycles with input disconnected (i.e., corresponding analog switch turned off), and after every 50 cycles the integrator voltage went up by a small bit. I think this is because of charge injection from the 4053 analog switch, so I zoomed out on the scope (second image), and the integrator voltage did increase linearly. The multislope was running for around 250us every 1 second, and at 10 seconds per division you can see how the integrator voltage in yellow goes up a little bit, and the result is a nice and linear ramp. This is good news because it confirms that charge injection effects are indeed linear (at least at this temperature and supply voltage) and can be calibrated out.

author: Kleinstein
author_rank: Super Contributor
timestamp: January 15, 2022, 09:17:14 pm
content: With a constant switching frequency the charge injection part is essentially constant and thus easy to subtract. It is just part of the offset.The slight shift that happens represents the offset of the ADC input and there are multiple contributions to it. The more important are:Asymmetry in the references (from resistors and OP offset)Tolerances in the resistors for the +10 V and -10 V ref.The offset of the "slow" OP at the integratorleakage currents at the 4053mismatch in 4053 resistanceinput bias at the integratornet charge injetionpulses in the residual voltage at the integrator input voltage, that can be slightly asymmetric for the 2 directionsIt is a good sign that the drift rate seen is about constant. This gives hope to not have large nonlinear effects depending on the integrator output voltage. There may still be small INL contributions, as for the final result it is about some 100 µV or so ín the integrator voltage after some 20 ms, or some 5 mV after a second. The time with the integrator in hold mode is naturally not causing much errors.

author: NNNI
author_rank: Regular Contributor
timestamp: January 28, 2022, 07:54:28 pm
content: It is finally time for the first super-crude results!So I got the timings right and input sorted out, so just for the hell of it I set the ADC up to do one reading per second, 5000 PWM cycles so 5000 counts with no residue reading. I took 1990 readings over something like half an hour and made a histogram (inspired byhttps://pico-adc.markomo.me/INL-DNL/), and the results actually looked interesting.Next, measuring in PLCs and rundown residue.

author: NNNI
author_rank: Regular Contributor
timestamp: April 06, 2022, 04:55:48 am
content: Another rather disappointing update.The first picture (yellow - integrator, blue - positive reference switch, pink - negative reference switch, dark blue - input switch) shows a sample multislope cycle: "Desaturation", which is reading the comparator and setting one of the reference switches so that the integrator goes to zero so it does not start with a random charge. This was a problem that caused noisy results. Second, of course, is PWM - 1/16 and 15/16 duty cycle. Then comes pre-rundown, which adds a constant dummy charge to the integrator to make sure it is negative for the next step - rundown. Rundown involves ramping the integrator up till zero is reached and counting the number of cycles it takes to do so.Initially, I tried one PLC of measurement followed by one PLC of integrator zero, but added a lot of noise to the result, so I changed to 20PLC worth of continuous integration (200ms).The results, however, are rather interesting. There is still quite a bit of noise on the ADC, but there also seems to be some kind of bug that causes two "groups" of readings, as shown in the second picture. A count is worth 10uV.Of course, I do not know what the bug is yet, but given how hastily and poorly designed this ADC is, I want to start fresh with better parts and better PCB layout and better practices in general. It was an interesting experiment and I learnt a lot from it.

author: Kleinstein
author_rank: Super Contributor
timestamp: April 06, 2022, 06:18:06 am
content: The 2 groups of result look indeed like a bug (SW problem). As the noise is quite high even the "noise" could still be a SW problem.Much of the noise looks like it effects both groups and would thus be rather low frequency noise. The 1/f noise could be a problem and it may be worth considering to alternate between a conversion from the input an one from 0 V and than look at the difference only.The ADC circuit has a few weak points, but overall it does not look that bad and I would expect better performce should be possible.I looks a bit like there could be quite some overshoot at the integrator (could as well be the ground hook at the scope probes). A good testpoint for the integrator is the ouput of U6B, so the "slow" OP in the compound integrator. This should give a kind of rectangle signal with some overshoot, but not too much ringing. From my experiences and simulations it may need some resistance (e.g. 100 ohms range) in series to C19 to dampen ringing.It could be a good idea to have some kind of filtering BW limit between the integrator and comparator. The slope amplifier found in many implementations between the integrator and comparator also has the task to limit the bandwidth.A weakness in the circuit as shown is that the resistance for the input in twice the resistance for the references. This leads to incomplete compensation of the drift of the switch on resistance. So ideally there should be the same resistance,even of this means a slightly small input range (like +-8 V) only.For testing it may still help to first look at short integration and possibly even a more dual slope like mode with seperate input and reference integration. This gives less resolution and mode noise, but makes errors more visible.With only a single slope for the run-down the resolution is quite limited. There are 2 options to add a smaller slope with relatively little effort even to the existing PCB:1) add a resistor (e.g. 1 M range) from the +7 V ref. to the integrator input. So there would be no more stop mode but slow drift instead. This would be similar to the small slope in the Keithley 20002) add a resistor (e.g. 220 K) in parallel to R7 and this make the references a little asymmetric. Than the case with both reference channels actice acts as small slope. This however needs a little more math in looking at the result. This is like my ADC solution works.

author: MegaVolt
author_rank: Frequent Contributor
timestamp: April 06, 2022, 08:57:16 am
content: Two groups of readings can cause popcorn noise of the reference source.

author: NNNI
author_rank: Regular Contributor
timestamp: April 06, 2022, 10:35:35 am
content: Kleinstein, thanks for your suggestions. I'm not sure if I want to continue experimenting with this board, I already have a long list of improvements planned for a next revision including a slope amplifier and maybe the addition of some kind of slow slope. Another idea on my mind was to convert the reference voltages to currents like in the K2002.MegaVolt, do you mean the input voltage or the ADC reference? In any case, that thought never occured to me, thanks for the information.Meanwhile, I measured a 9V battery over around 6000 measurements. The histogram maybe meaningless for a drifty measurement, but the scatter plot looks interesting...now the readings have diverged into sets.

author: Kleinstein
author_rank: Super Contributor
timestamp: April 06, 2022, 10:57:44 am
content: Using current sources like in the K2002 is quite some extra effort with relatively little return. On the downside on no longer gets compensation for the drift in the on resistance of the switch for the input channel.The splitting of the signal looks to be too large to be caused by popsorn noise (either the ADC reference or the external reference for the test voltage).The line split in 4 really looks like a SW problem, like missing a count or PWM value update (and thus having one step twice). The difference between the curves may give a clue.For an initial test of the noise the usual test point is 0 input and thus no reference noise for the source and ideally no effect of reference noise for the ADC side.The slowly drifting votlage source is also a good test, as this can show DNL errors and possible weak points where the ADC does not work well.

author: NNNI
author_rank: Regular Contributor
timestamp: April 06, 2022, 09:22:19 pm
content: I tried the method Kleinstein suggested of measuring input and then zero and considering the difference between them. I also averaged 10 readings. Each input and zero reading was 1PLC. The results look slightly better.

author: NNNI
author_rank: Regular Contributor
timestamp: August 27, 2022, 08:58:01 pm
content: It's been a long while since I posted updates here, and a lot has happened!I designed a completely new set of PCBs with better layout, and got it working, complete with software. I was able to run a few INL tests (compared to Keithely 2000), and I got a reasonable inverted parabola, which is a good sign which means linearity could be better with tweaking. However, the readings are very noisy, and I narrowed it down to problems with residue readings.I'm using an MCP3202 ADC IC to do the job. Reference voltage and supply is 3.3V from a 3.3V LDO, 1uF bypass capacitor on the power pin. Since the readings were noisy, I decided to investigate the ADC alone, and on feeding a constant voltage into it I got readings that were insanely noisy (hundreds of counts), and there was also "banding". On zooming in closer, some codes are also missing. I have no idea what is causing this.

author: branadic
author_rank: Super Contributor
timestamp: August 29, 2022, 12:52:24 pm
content: Are you sure your ADC scaling is correct? If not, that could explain the "banding".Have you checked the MCP3202 ADC independently on a breadboard with shorted input? Maybe you have some weird coupling effects that affect your noise readings.-branadic-

author: julian1
author_rank: Frequent Contributor
timestamp: August 29, 2022, 07:32:17 pm
content: Also review the code used to read the adc. I used mcp3208 for a project, and found it a bit fiddly to set up the control bits for input - either differential or single-ended. As well as flipping the spi read bytes by the adc to match the endiness of the mcu. The grouping/clustering of values could be explained by a problem handling the conversion.

author: NNNI
author_rank: Regular Contributor
timestamp: August 30, 2022, 09:59:01 am
content: branadic: These are raw counts from the ADC, so I don't think it's a matter of scaling constants this time. But maybe it might have something to do with the layout, that is something I'll have to confirm later.julian1: I've attached the code used to this post.

author: MegaVolt
author_rank: Frequent Contributor
timestamp: August 30, 2022, 10:06:20 am
content: Apply a slowly varying signal to the input. I think a lot will become clearer. Perhaps there is a problem with the order of the bits.

author: Kleinstein
author_rank: Super Contributor
timestamp: August 30, 2022, 10:54:21 am
content: There are still too many codes coming up to be a problem with just the order of the bits. That much noise looks more like a problem with the supply, reference or the clock (e.g. way to fast or too slow).

author: NNNI
author_rank: Regular Contributor
timestamp: June 14, 2023, 10:29:26 pm
content: I've finally figured out why the residue ADC readings were so bad - turns out that there's something in the software that is returning the wrong pair of readings for a given charge balancing cycle.The first image shows what is going on graphically.The second image is the raw readings from the ADC. Column B and C are "before" and "after" residue ADC readings respectively, and the blue highlighted numbers are the difference between the two. If I move the values in column B one row up and then take the difference with C, the results are the ones highlighted in green, consistent expected values.I was able to figure this out by reading the voltage on the integrator during the residue readings manually while making single-shot measurements, the values in column C were consistent with what I was seeing on the scope, while column B was not.

author: iMo
author_rank: Super Contributor
timestamp: April 11, 2024, 12:49:35 pm
content: Hi, I've been playing with your SW (rp2040 with PIO state machine) and have couple of questions perhaps, if I may..My current understanding is following:1. you set rp2040's clock to 96MHz2. SM's clock is set to 52.1ns (96/5)3. the PWMcycle is set inside PIO for 32 SM clocks with 2:30 duty, thus I see the "2" (for example) aprox 105ns long on my scope, in total the PWMcycle=1.66us (=32*52.1ns) I can see here, is that correct?4. the "MScyclesPerPLC" is the number of "PWMcycles in 1PLC measurement period", thus with 50Hz it should be 12000 (you have there 6000), imho (because 20ms/1.66us is 12000), is that correct?5. in "final" this line should beCode://uint32_t counts = get_counts(pio, multislopeSM, pwmCycles); //Multisloping for 20msuint32_t counts = get_counts(pio, multislopeSM, MScyclesPerPLC); //Multisloping for 20msas the pwmCycles (12 in your source) there is for testing purposes only, is that so?.I've been running it on a waveshare's rp2040-Zero..Tnx!

author: iMo
author_rank: Super Contributor
timestamp: April 12, 2024, 09:58:51 am
content: Hi, as the rp2040 PICO with its PIO state machine engines is a pretty interesting gadget for multislope experiments, I have commented in a little bit better detail what is happening inside the PIO assembler program for the state machine providing the MS events in NNNI's design.I've done it such the algo is somehow readable for people who mess with the PIO asm first time (inclusive myself), it may contain errors, for information only.I will update or remove it when NNNI will update his MS on the github.PS: corrected my many typos..Code:;; The PIO asm program for the MUltislope 3; by NNNI in https://github.com/NNNILabs/Multislope-3I/tree/main/SW; commented in detail by iMo 04/2024;; PWMB and PWMA is a GROUP of TWO OUTPUT PINS ("pins"), manipulating switches for positive nad negative REFERENCE charges; BOTH PWMA and PWMB pins are manipulated in a single cycle, shall be adjacent pins, PWMA being the lower bit; MEAS is a so called "sidepin" (you may set/clr the sidepin within any asm instr) - here the OUTPUT PIN indicating a running MS cycle (an MS cycle consist of "N" PWM cycles); COMP is the INPUT PIN ("pin") wired to the comparator;; this program does 32 clocks long PWM cycles (PWMA and PWMB) with a duty of 2:30; the number of switchings within one MS cycle should be kept constant by this algo; the "clock" frequency and pins/pin assignments are set outside this PIO program; the residual voltage measurements are done via CPU0 (an external ADC), based on; the irq0 (at the MS start) and the irq1 (at the MS end) signals issued by this PIO SM machine; outside the MS cycle this program provides constant "dithering" of the integrator input (toggling PWMA and PWMB);; the C part of the system; 1. writes the required number "N" of PWM cycles to PIO's Y register (like 6000 for example); 2. reads the residual voltage at the beginning of the MS cycle (via SPI through the CPU0); 3. reads the number of PWMA charge buckets counted during the MS process; 4. reads the residual voltage at the end of the MS cycle (via SPI through the CPU0); the number of PWMB buckets is equal (N - PWMA).program ms.side_set ; one "side set" bit is the MEAS pin, when 0 we do not count PWMs cycles/buckets, when 1 we do count; don't forget to enable auto pushstart: ; here we start a single MS cycleset pins, 0 side 0 ; this sets GROUP of two pins [PWMB, PWMA] = [0, 0], MEAS = 0mov X, !NULL side 0 ; set X (number of PWMA charges) to initial 0xFFFFFFFF, we will count down at each bucket, MEAS = 0out Y, 32 side 0 ; read from input FIFO the desired number of MS PWM cycles (like 6000 for example) and put it into Y, MEAS = 0irq 0 side 0 ; first residue ADC reading, done via SPI via DMA by the CPU0, MEAS = 0out NULL, 32 side 0 ; stall until DMA finished reading the ADC into the CPU0, MEAS = 0beginning: ; the beginning of one MS Measurement cycle, ie 20ms long, with fixed count of ie. 6000 PWM cyclesset pins, 1 side 1 ; set [PWMB, PWMA] = [0, 1] and set MEAS = 1jmp pin pwmhigh side 1 ; pin is the COMP input pin, if 1 jump to pwmhigh, MEAS = 1set pins, 2 side 1  ; set [PWMB, PWMA] = [1, 0], and stay so for additional 15 clocks, MEAS = 1jmp Y-- beginning side 1  ; decrement Y at each PWM bucket polarity regardless, jmp if not 0 to a new PWM cycle, stay so for 13 additional clocks, MEAS = 1jmp finish side 0 ; jmp to finish of the MS cycle and set MEAS = 0 (end of MS cycle)pwmhigh: ; when pwmhigh we decrement X (PWMA)jmp X-- dummy side 1  ; decrement X and stay for additional 15 clocks, jmp if not 0 (it never be 0), MEAS = 1dummy:nop side 1  ; do NOP and stay for additional 11 clocks, MEAS = 1set pins, 2 side 1 ; set [PWMB, PWMA] = [1, 0], MEAS = 1jmp Y-- beginning side 1 ; decrement Y at each PWM bucket polarity regardless, jump to new PWMcycle if not 0, MEAS = 1jmp finish side 0 ; jmp to finish of the MS cycle and set MEAS = 0 (end of MS cycle)finish:set pins, 0 side 0 ; set [PWMB, PWMA] = [0, 0], MEAS = 0in X, 32 side 0 ; push the X value (number of PWMA charge buckets) to FIFO (will be read by CPU0 via FIFO), MEAS = 0irq 1 side 0 ; perform the second final stage ADC residue reading via SPI (done by CPU0), MEAS = 0out NULL, 32 side 0 ; stall until DMA finished reading the ADC, MEAS = 0.wrap_target ; this is an endless "desaturation loop" (between wrap_target and wrap) keeping integrator input around ZERO when not doing the MS cycledither: ; we toggle PWMA and PWMB in a loop around ZERO integrator voltagejmp !OSRE start side 0 ; jump out of this desaturation loop when the OSR has data (it means the CPO0 has sent the "N" at the beginning of the MS cycle), MEAS = 0set pins, 1 side 0 ; set [PWMB, PWMA] = [0, 1], MEAS = 0jmp pin dither side 0 ; check if the comparator output pin is still 1 and jump to dither if 1, MEAS = 0set pins, 2 side 0  ; set [PWMB, PWMA] = [1, 0], stay so for additional 1 clock, MEAS = 0.wrap

author: Kleinstein
author_rank: Super Contributor
timestamp: April 12, 2024, 11:29:16 am
content: There should be no need to have the reference modulation that fast. 96 MHz and 16 cycles would be modulation frequency of 6 MHz. For comparison the HP3458 uses some 330 kHz. With a good capacitor there is no need for more than some 50 kHz to reduce the DA effect on the INL sufficient.A very fast modulation also comes with downsides: Charge injection gets more important. The integrator settling gets more important and really fast settling integrator is wanted. More time is lost to the fixed short pluses needed for settling. This limits the usefull range (looks like 4/16 of the range are lost in this example). Jitter and becomes more relevant as a noise source. Even worse may be other delays (ps range is enough) caused in the µC that can cause INL errors.Even without such a fast modulation one may want to consider separate syncronization to a stable clock (e.g. with 74AC74 flip flops) to avoid juster and delay modulation from the µC. This would likely be with a slower clock not 96 MHz anyway.The RP2040 could still be interesting as it may be able to run the ADC part in parallel to normal operation. AFAIK the µC internal ADC has some flaws so that the usable resolution is more like 8 or 10 bits.

author: iMo
author_rank: Super Contributor
timestamp: April 12, 2024, 12:20:27 pm
content: In his example as of today on his github a single pwm modulation cycle is made of 32 clocks, where the clock is set to 96MHz/5=19.2MHz.The single pwm cycle is therefore 1.67us (say 600kHz). It is perhaps his testing setting. You may set the PIO's SM clock as you wish (CPU_clock/div). I've been running the code on my rp2040-zero and I can see that timing on the scope. You may overclock CPUs (there are 2) to 300-400MHz max, btw.All the instructions above are single clock (say 5ns at 200MHz), with additional prolongation of any instruction, and the sidepin(s) set/clr in parallel as well - that is a pretty impressive combination.For example a single 1 clock instructionjmp Y-- beginning side 1 decrements the 32bit register Y, jumps to "beginning" label if Y is not 0, sets a "sidebit" output pin to 1, and makes this instruction 14 clocks long.. Imagine what could you do with your MS ADC design if you had this gadget handy..You may have 2 PIO instances with 4 SMs in each, DMAing the SM'es data via a 4/8 words deep in/out FIFOs into/from the CPU0 or CPU1 (or any peripherals, afaik). No need to use an external FPGA for many apps. The 9 instr assembler is not easy to read, and there is a lot of various tricks you may do with it as well, so one need some time to get grip on it..

author: Kleinstein
author_rank: Super Contributor
timestamp: April 12, 2024, 05:09:14 pm
content: The PIO part should be capable to control a MS ADC. The limiting factor is however not so much the digital control part, but the analog part (e.g. settling of the integrator with 2 x OPA140 or similar) takes some 200 ns or so. So the shortest pulses should be no less than some 500 ns to get reasonable good settling. This sets a practical limit for the modulation speed of some 200-300 kHz - faster gets sensitive to settling effects or looses quite some of the input range.The speed for the modulation is a compromise. Fast allows to use a small integration capactor and thus allow low residual charge noise (only relevant for short integration). Fast modulation also allow a fast rundown and gets less INL from DA. One the other side faster modulaton gets you more INL error from settling effects, more INL error from delay modulation, more noise from jitter, switch capacitance and noise in the charge injection.My ADC version uses the µC internal ADC and here the ADC inside the RP2040 is not that great, though still OK. The RP2040 would need an external comparator - other µC can incluce the comparator.The main point where fast control and also fast modulation could really make a difference is when it comes to a fast rundown to get really fast conversions (e.g. > 10000 SPS). However for really fast conversion the MS-ADC (especially the version with a rundown) may not be the best choice anyway. Modern SAR chips and also some SD ADC chips get pretty good at 100 kSPS or 1 MSPS.

author: NNNI
author_rank: Regular Contributor
timestamp: April 14, 2024, 11:16:40 pm
content: First off: Extremely sorry for not replying to the previous messages sooner. I am unfortunately not very active here, and somehow I completely missed the fact that this thread had replies (I don't get E-Mail notifications).iMo did send me a private message regarding the topic of this thread, but somehow it never occurred to me to check. I will read the messages and questions in detail and get back as soon as possible.I was wondering why the GitHub repo for the project was suddenly getting so many stars, never occurred to me that it might be from here...diminddl, who is collaborating with me on this project and is responsible for the software side, wrote a post on Hackaday explaining the code:https://hackaday.io/project/190528-multislope-adc/log/217945-code-overview, I hope this answers some questions.

author: NNNI
author_rank: Regular Contributor
timestamp: April 15, 2024, 09:36:40 am
content: Regarding the modulation frequency: Yes, the PIO clock divider is set to 5 for testing.The original intention of the 96MHz underclock (I have stably overclocked the RP2040 to 400MHz) was to have a PIO clock divider of 10 to get a 9.6MHz PIO clock. That results in each PIO instruction taking 1.04167us. Each PWM cycle is 32 clock cycles long, and therefore a period of 3.333us (300kHz modulation frequency). This was chosen so there would be an integer number of PWM cycles in both a 50Hz and 60Hz PLC (20ms/3.333us = 6000 PWM cycles, 16.667ms/3.333us = 5000 PWM cycles).

author: iMo
author_rank: Super Contributor
timestamp: April 15, 2024, 09:59:13 am
content: I've been playing with the digital part, getting familiar with the PIO+MCU combo..I've wired my junkbox MAX1247 ADC and running the modded test chunk of code, watching what is going on. Of course I've played with various settings. My ADC works fine with 2MHz SPI clock, with LM385-2.5V ref and 1N4148 (5mA If) as the source I get rock stable reading with occasional 1LSB excursion for both pre- and -post MS readings (btw. all on a solderless breadboard with jumpers and my pico-zero dingsbums). Also my pico has got linear voltage regulator.The first residual measurement occurs 20-40us (it depends on ADC SPI clock) before the start of the MS cycle, that might be too long before the MEAS=1, I guess. It is because you wait on DMA reading the ADC SPI.Why not use an another channel for ADC, such it reads the ADC in parallel with the beginning of the MS cycle?Simply issue the irq0, wait for ADC_acquisition time (perhaps 1-2us) and do not stall the PIO during the ADC SPI DMA..PS: in the MCU section I've asked whether we know the typical jitter of the clocks generated by the rp2040 pll. Soon or later somebody here will ask that too (as the clock jitter has been identified as a potential troublemaker with 6+ digits)..Worst case you may run the MCU off an external 50MHz canned oscillator.

author: Kleinstein
author_rank: Super Contributor
timestamp: April 15, 2024, 10:10:40 am
content: 300 kHz modulation period for the run-up sounds much more sensible (similar to 34401 and 3458), though still relatively fast. It may be needed for the MS3 (34401) like version with no rundown. Otherwise fast modulation makes jitter more relevant and with just the RP2040 there is a chance for quite some jitter from the PLL. For the jitter I can see the difference between an 74HC74 and 74AC74 for synchronization, even with slower modulation (~100 kHz).

author: iMo
author_rank: Super Contributor
timestamp: April 15, 2024, 10:22:58 am
content: The 2040 strategy with jitter is to set the internal pll as close as possible to 1500MHz, and then divide down to say those 125MHz (or other cpu clock). Then the jitter should be lowest, DS says. For example the Si570 gadgets worked with 4.7GHz pll and achieved pretty low jitter, perhaps the 2040 follows that too (better it needs to be measured, considering their ADC design flaw).

author: NNNI
author_rank: Regular Contributor
timestamp: April 15, 2024, 10:42:40 am
content: QuoteThis is exactly what I was planning and working on last year.

author: iMo
author_rank: Super Contributor
timestamp: April 15, 2024, 04:24:17 pm
content: Ok, I see..What I do not understand fully (a 2040 beginner here..) is following:QuoteWhy do you send the ADC value to the TX FIFO of the PIO instance?That delays the MAES rising edge by XXus when the integrator's input voltage has been already disconnected (so it may change during the "XXus long" preADC conversion)..What I thought above is to have the ADC channel "independent" of the PIO instance (so both will do in parallel, no need to stall the SM..). Something like that..PS: below what I see now.. preADC samples some 12uS before MAES=1 and postADC about 4-5us after MAES=0 (with 2MHz spi).

author: PCB.Wiz
author_rank: Super Contributor
timestamp: April 17, 2024, 12:59:42 am
content: Quote from: iMo on April 15, 2024, 10:22:58 amYes, the VCO's are usually current controlled oscillators, giving the best jitter at higher power/highest MHz.Quote from: iMo on April 15, 2024, 10:22:58 amre Si570 area : If you want to look at cased i2c oscillators here is table I drew up a while back, that shows jitter-GHz are certainly related, and they tend to use higher MHz, xtals for lower jitter. (and probably smaller size too)Code:~~~~~~~~~~~~~~~~ SiLabs i2c Oscillators ~~~~~~~~~~~~~~~~~~~~Device SpeedGrade Xtal Out(MHz.CMOS) MinFvco(GHz) MaxFvco(GHz) Icc JitterSi564.A 152.6 0.2~3000 10.8 13.122222222 87mA CMOS 95fs RMSSi549.A 152.6 0.2~1500 10.8 12.511886114 87mA CMOS 95fs RMSSi549.B 152.6 0.2~800 10.8 12.206718160 87mA CMOS 95fs RMSSi549.C 152.6 0.2~325 10.8 12.206718160 87mA CMOS 95fs RMSSi544.A 55.05 0.2~1500 10.8 12.550082103 74mA CMOS 150fs RMSSi544.B 55.05 0.2~800 10.8 12.109728345 74mA CMOS 150fs RMSSi544.C 55.05 0.2~325 10.8 12.109728345 74mA CMOS 150fs RMSSi564.A 3GHz out $42Si570 114.28 10~160M 4.850 5.670 90mA CMOS 0.62pstypSi599 39.17 10~810 4.85 5.67 90mA CMOS 0.7psSi514 31.98MHz 0.1~250M 2.080 2.500 21mA CMOS 0.8psSi5351A.QFN20 25~27 0.002~200 0.6 0.9 22mA CMOS ~40ps ppSi5351A.MSOP10 25~27 0.002~200 0.6 0.9 22mA CMOS ~70ps ppThose are highly flexible but not especially cheap.Over in the Audio sandpit, there are many complex oscillators offered up, but this one looks to be simple, using a 74LVCU04 gatehttps://www.diyaudio.com/community/attachments/twtmc-p-pdf.615086/Note they use a large can, custom crystal when chasing extreme numbers.Addit3: I found another variant, a Pico gate Pierce, shows the crystal matters most for low Hz phase noise.https://www.thewellaudio.com/wp-content/uploads/TWTMC-PPG-V2_User_Manual.pdfNote they test here with batteries and shielded.At the simpler end, Nisshinbo offer a NJU6385, in a DFN6 package,https://www.nisshinbo-microdevices.co.jp/en/products/quartz-crystal-oscillator-ic/spec/?product=nju6385that part claims impressive low jitter and noise. (I think tested at 49.152MHz )●Phase noise-103dBc/Hz(Typ.) @10Hz Offset-163dBc/Hz(Typ.) @1kHz Offset●RMS Jitter 0.05psec(Typ.) @12kHz to 20MHzNot much mention of power supply, but these inverter oscillators would likely benefit from a modern, low noise local regulator.It's hard to tell how much secret sauce is in that NJU6385, or if it is just a DFN packaged standard unit ?ie how much better is it really, than a 74LVCU04 or 1GU04 oscillators above ?The Pico gate info above, suggests less secret sauce, but NJU6385 is small and includes C and biasing.Mouser do stock the similar NJU6311, in MSOP10, with divider choices.The lowest ESR crystal generally available looks to be ABLS-LR-12.000MHZ-T in HC-49/US (SMD) ESR <15 OhmsAddit: Another option point, for high end instruments like ADC's, could be crystals like ECS's aged models : a slight premium on jellybean crystals.Their ESR is higher, than the larger ABLS-LR, but they have been pre annealed/aged - maybe that matters more ?ECS-120-10-33B-CKM-TR3 12.000 MHz 10 pF ECS-33B 10/10 ppm -20 ~ +70C 1 ppm Aging 3225 ESR <100 Ohmshttps://ecsxtal.com/news-resources/how-ecs-inc-b-series-crystal-oscillators-support-your-future-forward-technology/That looks easy to retro fit onto a RP2040 board, as I think they use 3225 commonly.Addit2: Another reference point on the KISS/Cost/performance curve, is to simply bolt on the 'best TCXO' like the ATX-H12-F-12.000MHz-F25-TNumbers are a tad worse than the NJU6385 claims, but it's all in one package, and spec'd out of the box.An alias/branding clone of that ATX-H12 looks to be the FT2MHUPM12.0, showing stock at Newark, strangely a bit cheaper than the ATX-H12, at under $2 ?These Abracon parts spec (ATX-H12 / FT2MHUPM12.0)Phase Noise (@ 10 MHz Carrier, @ 25°C ±2°C)@10Hz offset -98 dBc/Hz Typical -94 dBc/Hz Max@100Hz offset -122 dBc/Hz Typical -118 dBc/Hz Max@1kHz offset -145 dBc/Hz Typical -141 dBc/Hz MaxThat would be easy to add to a RP2040 board, to check.

author: iMo
author_rank: Super Contributor
timestamp: April 17, 2024, 06:03:04 am
content: Yep, I collected many various Si570s (20y back while messing with the first SDR radios), afaik they output till 1.5Ghz based on the part number suffix and type of output, cmos till 160MHz-250MHz, lvds till 1.5Ghz. Expensive, indeed.Now, how the rp2040 does perform?

author: Kleinstein
author_rank: Super Contributor
timestamp: April 17, 2024, 07:08:49 am
content: The Si570 is made for low jitter and this comes at the cost of quite high power consumption. The µC internal PLL is more build for low power and this comes with more jitter. The question is just how much.With a modulation in the 100-300 kHz range the jitter level to worry about is if one gets better than a few ps RMS for a frequency offset of some 200-600 kHz. AFAIK 74AC gates and likely the 74LV4053 switches have RMS jitter of some 1 ps. The target specs for the clock are better than some -110 dBc for a 100 kHz offset. Most oscillators are OK with this. No need for a special grade oscillator.For the supply good decoupling can be needed for the oscillator - not sure of the solution on the RP2040 board is good enoughIf the jitter of the µC is an issue one could still consider the external synchronization like it is done with most DMMs (e.g. 34401, 3458, K200x). This needs an external flipflop, like 74AC74 or similar. If the RP2040 is still running with the PLL, the PIO software would also need some synchronization part to get a correct setup time / phase relative to the master clock.The external sync would also avoid issues from the µC internal operation effecting output delays or the PLL, that can effect the INL. Though small, I have seen such an effect with an AVR.So there can be another reason to use external synchronization, not just jitter.

author: iMo
author_rank: Super Contributor
timestamp: April 17, 2024, 07:25:30 am
content: And what about the 50/60Hz mains? Do we need the sync there as well? Most dmms have it.QuoteThe PIO runs from a "clock" derived off the pll, but the MCU works fully async of the PIO as the data transfer PIO<->MCU gets via I/O FIFOs, there is no direct interaction between the PIO SM and the MCU (or anything else, the residual ADC is r/w async via FIFO too) at the "particular hw signal level" during a MS cycle (MS cycle being the "runup PWM modulation" as you call it), afaik. So the PIO SM clock "is" the master clock, imho.The only critical interaction as of today is when the MCU requests the PIO SM to "make a single XXX PLC long measurement" with a single MS cycle in it (with the pre- and post- residual ADC readings), that request is not synced to anything today (the SW on the github is just a MS3 cycle testing stuff, not a working DMM) and most probably subject to a large sw/system jitter (as it works with interrupts/DMA/FIFOs/USB_printf in a free while() loop).PS: that could be done easily by calling the MScycle request in an interrupt, where the interrupt will be triggered by an external edge ("the sampling rate" generated by the MCU), and within the interrupt the 4 data received from the MScycle will be written into a sw FIFO. The FIFO data could be then read by the main loop. There will be a jitter in that sampling period, like sub usecond, I would guess.

author: Kleinstein
author_rank: Super Contributor
timestamp: April 17, 2024, 09:54:00 am
content: In most case one can get away without the ADC synchoronized to mains. As the integration times is than a mulitiple of mains periods one would have to wait nearly a full period after the short rundown. This makes a full sync here not that attractive. It could still be nice to have the option to synchronize the start of the conversion to some trigger signal - not just mains.Running a PLL to have the clock direct linked to mains, as done in a few meters (e.g. Prema, Solartron) would make it hard to get low jitter. So many other don't use this. The alternative may be using a fixed crystal clock and if really needed adjust the number of clock cycles in a conversion to follow main frequency variations. It needs some extra math to handle the result than.Using the PIO clock as the master clock may or may not work. If there is too much jitter or delay/frequency modulation (e.g. via supply or internal states or other io pins) one may have to use external syncronization and than an external master clock. That clock would than also feed the PLL. The PIO clock would be a multiple of the master clcok and would need some extra SW to synchronize to the master clock at least somewhat. Otherwise there could a the risk to no get a proper setup time for the sync flip flops.The alternative may be to run the whole system without PLL, e.g. from a 16 MHz clock. The µC may still be fast enough. No PLL is the way I run my STM32L051 based version.

author: iMo
author_rank: Super Contributor
timestamp: April 17, 2024, 10:08:49 am
content: Now, let us start simple. Let us assume (for a while) the PIO's clock is "perfect".An MCU interrupt triggered by the MCU's PWM output (the set period of the "DMM's sampling rate", like 4x per second) requests PIO to provide a single 10PLC measurement, and the PIO performs the requested measurement (== preADC, MScycle 200ms long, postADC), then the PIO returns the preADC, PWMA/PWMB count and postADC values, those values are read by the MCU afterwards.There will be no jitter within PIO's MScycle, but there will be a "small" jitter (say sub usec) in the sampling period (because it is triggered via the interrupt).How that jitter in the sampling period influences a typical measurement?PS: outside the single "10PLC measurment" the PIO performs "dithering" as it is done today.PS1: there is a jitter in the start of the preADC and the postADC as those are triggered by interrupts as well..PS2: "MScycle" means the runup charge balancing sequence..

author: Kleinstein
author_rank: Super Contributor
timestamp: April 17, 2024, 10:45:04 am
content: Any jitter with the auxiliary ADC should not be that bad, if this is in hold phases of the integrator. The drift should be rather low (e.g. a few LSB per ms).In most applications a slight jitter in when the conversion actually starts is also not that bad. After all the conversions are usually integrating over quite some time (e.g. 16 ms and up).The actual integration time should still be accurate to the clock cylce. In many cases just a preset number of modulation cycles. A vaiation there would change the gain.

author: iMo
author_rank: Super Contributor
timestamp: April 17, 2024, 10:54:20 am
content: As of today the preADC and postADC samplings are below XX usecs before/after MScycle (incl interrupt jitter, the XX depends on the ADC SPI clock) while the integrator is on hold.. (see above my scope shot at 2MHz SPI clock aprox 12us pre- and 5us post-)..So the moral of the story here is - everything in this design will be jittery/async, except the "MScycle runup charge balancing sequence"..

author: diminddl
author_rank: Newbie
timestamp: April 17, 2024, 10:05:04 pm
content: Quote from: iMo on April 15, 2024, 04:24:17 pmHello, I am the one who wrote the software for this thing, and I would like to clear up some things.First of all, the code was essentially frozen mid development (at least for me, according to my last commit to the repo) 2 years ago. So forgive me if I won't explainexactlywhy some stuff was done the way it was.Also, I was (just like you) still learning to use the RP2040, PIO and it's SDK at that point, so some things are far from optimal. I mention some of them in the hackaday write-up mentioned earlier (that was written after an extra year of experience with the platform).QuoteThe answer is we don't. If you look at the code it actually puts in just a 1.Code:pio_sm_put(pio, multislopeSM, (uint32_t)1);And if you look at the PIO code and the attached comment:Code:out NULL, 32 side 0 ; stall until DMA finished reading the ADCThis was just a crude way of stalling the state machine and letting the reside ADC read out the residue. This operation indeed is a bit jittery (because we are relying on the CPU to react to the interrupt, set everything up and trigger the reading), but as it was explained to me at the time, as long as all the switches are off, meaning they are not injecting any charge into the integrator, then the absolute time that the residue reading happens doesn't really matter (within reason).The plan was to optimize the PIO code enough to be able to include a crude SPI readout block in a different state machine within the same PIO instance, this would allow us to use the inter state machine interrupts with a predictable 1 cycle delay to fire the readout of the reside ADC. But me and NNNI both got busy at the same time so we never got around to fully implementing that.If you have any other questions about the PIO, or the RP2040 in general, fell free to do so, I will try my best to answer them.

author: PCB.Wiz
author_rank: Super Contributor
timestamp: April 18, 2024, 06:20:05 am
content: Quote from: Kleinstein on April 17, 2024, 09:54:00 amHaving that option would certainly allow easy A-B comparison testing.I listed a couple of Abracon TXCO's above that come in 12MHz, and I've found some very low phase noise oscillators for Audio from NDK, impressive for a 2520 case.Ultra low phase jitter：Typ. 43fs Phase noise Typ : -115dBc @ 10Hz, -164 dBc @ 1 kHz offset frequency.Digikey has these in codes NSC5083D-24.576M, NSC5083D-45.158M, NSC5083D-49.152M at $2.80/1To use those, you could feed OSCOUT via a resistor to the XIN pin, boot with the OSC tri-stated (so 12MHz) and then use a GPIO pin to enable the new master clock once ready.NDK do quote 24MHz and 48MHz as possible order codes, likely with some MOQ. 22.5792 MHz is the lowest valid freq, the 2520 package likely cannot fit lower xtals.I've not used a RP2040 PLL, but at 24.576MHz I think there is a viable 48MHz USB solution with a ~381ppm offset, with *41/(3*7) VCO = 1007.616Another solution may exist for 45.158MHz 45.158*17 = 767.686/(4*4) = 47.980375 ~409ppmExternal D-FF could be clocked from this master clock, if needed.

author: iMo
author_rank: Super Contributor
timestamp: April 18, 2024, 06:48:50 am
content: @diminddl: Hi, thanks for the clarification! Yep, I like the design because of its simplicity. Of course, messing with the 2040 and its PIO requires some lead in..I've been playing with the sw part only at this stage - the C source - and slowly getting the grip..I made small cleanups here and there (mostly to make it easier to read and save a couple of bits), added the PWM_Sampling_rate signal generation with an interrupt which sets a flag at each sampling period start such I can sync the start of the xPLC measurement and it works fine.Also I investigated the issue NNNI indicated in past with the wrong sequence of the auxADC readings, and after my cleanup of the flag handling it still works. As a proof I've been changing the auxADC input voltage (with help of the MAES signal) such I can see which is pre- and which post- auxADC reading, and it works fine, it seems.Code:void pio_irq(){gpio_put(CS, false);irq_set_enabled(DMA_IRQ_0, true);dma_start_channel_mask((1u << dma_tx) | (1u << dma_rx));if (pio0_hw->irq & 1) {// PIO0 IRQ0 fired means we need to take first MCP reading// start DMAs simultaneously// enable IRQfirstAuxADCreading = true;pio0_hw->irq = 1;}else if (pio0_hw->irq & 2) {// PIO0 IRQ1 fired means it's time for the second readingfirstAuxADCreading = false;pio0_hw->irq = 2;}}// MSADC SAMPLING periodvoid my_PLC_PERIOD_isr() // fired by the PWM at PIN0 (example), max Speriod 120ms @96MHz CPU clock{MeasurePLC = true;pwm_clear_irq(pwm_gpio_to_slice_num(PINpwm)); //Clear the interrupt flag}The stuff with the DMAing auxADC and PIO does not need to be modified at this stage as the 10-20us lost with the stalling the SM plays no significant role there, as has been discussed above.Also the jittery coming from the interrupts/FIFOs etc. will most probably not have significant influence provided the MScycle charge balancing sequence itself is rock stable (the part where MAES=1), so far let say it is stable (unless there is a larger pll jitter, that needs to be investigated).One thing is the "configureDMA();" at the end of the DMA interrupt handler routine.. Can we somehow re-arm the DMA without calling the huge "complete DMA config"? I've tried my best but I was not successful so far.PS: note the math with the reading the auxADC SPI data below is for my MAX1247 ADC..Code:void dma_irq_handler() {// Clear interrupt.// and disable the interruptdma_hw->ints0 = (1u << dma_rx);irq_set_enabled(DMA_IRQ_0, false);gpio_put(CS, true);uint16_t auxADCreading = ((DMA_SPI_ADC_readBuffer << 8) | (DMA_SPI_ADC_readBuffer)) >> 3;if(firstAuxADCreading) {auxADCresultPreMultislope = auxADCreading;} else {auxADCresultPostMultislope = auxADCreading;}pio_sm_put(pio, multislopeSM, (uint32_t)1);configureDMA(); // HOW TO GET RID OF THIS CHUNK??? :)}With the synced measurement in the main - example only, still not a working DMMCode:..// Start running our PIO program in the state machinepio_sm_set_enabled(pio, multislopeSM, true);irq_set_enabled(PWM_IRQ_WRAP, true);get_counts(pio, multislopeSM, 1);while(true){if (MeasurePLC==true){MeasurePLC = false;counts = get_counts(pio, multislopeSM, PWMcyclesPerMS); //Multisloping for 20ms (example)sample_ID++;difference = PWMcyclesPerMS - counts; // PWMA and PWMB charge buckets counted during a single MScycleprintf("%d, %d, %d, %d, %d, %d\n", sample_ID, counts, difference,auxADCresultPreMultislope, auxADCresultPostMultislope, (auxADCresultPostMultislope - auxADCresultPreMultislope));}}..Code:55890, 0, 6000, 484, 1159, 67555891, 0, 6000, 484, 1159, 67555892, 0, 6000, 484, 1158, 67455893, 0, 6000, 484, 1159, 67555894, 0, 6000, 484, 1159, 67555895, 0, 6000, 484, 1159, 67555896, 0, 6000, 484, 1159, 67555897, 0, 6000, 484, 1159, 67555898, 0, 6000, 484, 1159, 67555899, 0, 6000, 484, 1159, 67555900, 0, 6000, 484, 1159, 67555901, 0, 6000, 484, 1159, 67555902, 0, 6000, 484, 1159, 67555903, 0, 6000, 484, 1159, 67555904, 0, 6000, 484, 1159, 67555905, 0, 6000, 484, 1159, 67555906, 0, 6000, 484, 1159, 67555907, 0, 6000, 484, 1159, 67555908, 0, 6000, 484, 1159, 675

author: Kleinstein
author_rank: Super Contributor
timestamp: April 18, 2024, 08:04:27 am
content: The TXCO's are impressive, but not really needed. There are quite some common xtal oscillators with jitter of around 1ps or better. Jitter becomes relevant for the ADC noise when the jitter is higher than some 5 ps. Old style 74HC... have jitter around 2 ps and the difference between a 74HC74 and 74AC74 is barely visible. Similar 74HC4053 gives slightly more noise then 74LV4053, likely from more jitter.The µC internal PLL may well be the weak point. I have not found jitter data in the RP2040 datasheet. However they mention the compromise between jitter and power consumption for the choice of the VCO frequency. So jitter likely is somewhat noticable. The DS for the STM32G071 (a possible alternative µC ) gives jitter specs of typical 40 ps RMS period jitter. This is quite a lot and would be a real issue. That µC would need to run without PLL and / or use external synchronization. The RP2040 may be slightly better, as it is not so much trimmed for low power. However I don't expect is to be more than 40 times better than the STM32G to reach the 1 ps range. For the ADC the frequency offset is in the 100 kHz range and thus a more difficult case than period jitter.To avoid the extra noise from jitter the RP2040 based ADC would thus likely need expternal synchronization with an external flip flop. This would solve the jitter problem and also help with more determistic delay modulation. The clock on the RP2040 module could be a real issue (I got large INL errors with a crstal at an AVR). The PIO system should be powerfull enough to also do the crude phase lock from PIO clock to an external clock - so one could likely still use the PLL. The alternative may be a slower (e.g. 10-20 MHz) external clock for the µC and PIO system and than possibly skip the external flip-flop.To keep things really simple, one could still use the RP2040 internal ADC. It is not very good with the bug that limits the good sections to some 9 bits. Depending on the rest of the MS-ADC design it can still be good enough. E.g. in my version I only really use some 7-8 bits.I would really prefer the µC internal ADC and use an external oscillator and flip-flop for syncorinization.In most cases one would not use USB in direct combination with the ADC function. Usually some isolation barrier is wanted between the high resolution ADC and the PC connection for EMI reasons.Isolating USB is possible but tricky. It is much easier to have an isolated UART and than a UART to USB bridge (FT232 like or maybe a RP2040) for the PC connected side.

author: iMo
author_rank: Super Contributor
timestamp: April 18, 2024, 08:21:33 am
content: Quote from: Kleinstein on April 18, 2024, 08:04:27 amBut you are using rundown+auxADC, this design has none rundown, so I doubt the 2040's internal ADC would be suitable. In opposite, my guess would be to go even with a better auxADC in this desigh as is today.. (..I've found in my junkbox a nice MAX11166/67 16bitter in 3x3mm 12 pin packagewith true bipolar +/-5V input, perhaps usefull here). Another option here would be the introduction of a rundown..

author: Kleinstein
author_rank: Super Contributor
timestamp: April 18, 2024, 09:20:35 am
content: There were a few versions of the MS based ADC. The case with no rundown (thus MS3 or MS4 similar) would indeed want a better ADC and also relatively fast modulation. Ideally one would use the aux ADC in the fly (as with the HP meters) and thus not stop the intgration at all. This would allow to look at the residual charge for more than just the start and end and this way get additional resolution, a bit similar to SD ADCs.Since they stopped the integration, I thought that they would also use at least a fast (full reference) rundown.A fast rundown would reduce the demand on the ADC by about a factor of 50 (clock / modulation period). PIO should also be able to do the fast rundown, though this may need a little more code. The rundown part is what really makes the PIO worth while - just the run-up part is easy also with PWM hardware and a normal µC.

author: iMo
author_rank: Super Contributor
timestamp: April 18, 2024, 09:29:10 am
content: In current PIO SM code there is a couple of instructions left (max number of PIO instructions is 32, shared among all 4 state machines in the particular PIO). Currently 23 instr is used.A talented PIO guy may perhaps push the fast rundown into those 9 instructions..When removing the dithering you may introduce a fast rundown esily, imho. When not removing the dithering you have to use the second PIO somehow if those 9 instructions left would be not enough, that would be complicated.But what you get with the fast rundown here? When not switching to different ref voltages/currents the integrator's slope will stay the same, so you may count 0..31 (or 0..15??) SM clocks in a single fast rundown, imho..PS: but sure, after the fast rundown you will end up closer to zero integrator output voltage, thus auxADC input voltage range could be much smaller..

author: NNNI
author_rank: Regular Contributor
timestamp: April 18, 2024, 11:36:33 am
content: iMo: Thanks for taking the time to try and understand my design and work with it, it definitely helps a lot to have an outside perspective for new ideas and improvements. As diminddl already mentioned, the repository was essentially left as such after the last set of experiments in June/July 2023, so there are a lot of things unfinished and not properly documented. I am trying my best to finish up my existing project backlog (among other things) and hope to get back to it in a few months.kleinstein: Thanks for the insight regarding jitter and its effects on a multislope ADC.PCB.Wiz: Once again, thanks for providing more information regarding low-jitter clock sources. This is something I will be looking at in the future.Regarding rundown - the previous 'test' version of this ADC did have a rundown phase implemented in PIO (see image attached) based on this paper:https://dspace.mit.edu/bitstream/handle/1721.1/84880/868678609-MIT.pdf?sequence=2. I had banding issues with that ADC as well. You can find the code here:https://github.com/NNNILabs/6.5-Digit-Multislope-ADC/tree/main/Multilslope%20IIA

author: iMo
author_rank: Super Contributor
timestamp: April 18, 2024, 11:59:21 am
content: Ok, so you went for 16 clocks up with the voltage, then down while counting the clocks till the comparator switched.But that would require to not saturate somewhere..I mean with a constant slope (using the same ref+ and ref- as during the runup), in 16 clocks (off 32) you would add up half of the full scale to the final residual voltage. Now, the question is where the final residual voltage typically ended up (before adding half of the full scale), such it all fits.Like final residual voltage=8V (for example), plus 5V (16 clocks) = 13V that could be off the analog span.

author: Kleinstein
author_rank: Super Contributor
timestamp: April 18, 2024, 03:01:45 pm
content: Where the voltage ends after the normal run-up can vary with the input voltage. Chances are one can avoid the extremes a little, but not much more. The headroom of the integrator may not be such an issue, especially if one has time to read the residual charge and does not need to do it very fast (e.g. on the fly).Using a fixed step up for the start is possible, but not effective. One can be more effective (faster and less need for integrator headroom) by also looking at the comparator for the initial up part: go up for some 2 cylces past the comparator saying that the sign is right. One may need some minimum for the step to have more time for settling. There are than mainly 2 cases, that can still be handled the same way:a) a short up phase of the minimum length and than a possibly longer down phase for the endb) a longer up phase and than only a short (e.g. 3 or 4 cycles) down phase, just to get the zero crossing from the same direction as in the case before.So the result would have 2 extra reference times as contributions to the result.Nominally the slope for the up-down part are linked to the power from the run-up steps. If the pulses are rather short and settling not perfect one may need a small correction. Similar, when the positive and negatve ref. voltage are not exactly the same there is a small correction term for the variable time references are active. Depending on the hardware one may want those extra correction(s) or can get away without them.

author: PCB.Wiz
author_rank: Super Contributor
timestamp: April 18, 2024, 07:53:39 pm
content: Quote from: Kleinstein on April 18, 2024, 08:04:27 amThere are also different forms of jitter spec, this from a Epson part, SG-210SCBA (now EOL?) (0.3 to 19ps depending on jitter type)plus you also need to worry about possible micro-step effects of crystals.Quote from: NNNI on April 18, 2024, 11:36:33 amIt's always interesting to do a refresh.I found quite a few parts have 'come and gone', and it seems you can get high spec 2520 package parts for not much premium.The appeal there is you can easily try a high spec part and see if there is really any measurable difference.It's even possible to have dual operation, with High-Spec faster source user switched with a 12MHz Xtal or osc for booting.

author: iMo
author_rank: Super Contributor
timestamp: April 19, 2024, 09:37:04 am
content: Quote from: Kleinstein on April 18, 2024, 03:01:45 pmSo the key message here is to approach the "end zero crossing" always from the same side (for example from "positive side") in order to eliminate the "comparator hysteresis" errors.The steps, for example, when talking PIO in this case, we want approach comparator always from the "positive" side:0. runup ended, switch both Vref switches off1. look at the comparator (2 SM clocks)2. if comparator shows positive side - set Vref switches such the integrator's voltage goes down (1 clock)3. count the SM clocks till comparator changes while crossing the zero (2 clocks per count)4. send the count to MCU (1 clock)..2. if comparator shows negative side - set Vref switches such the integrator's voltage goes up (32 clocks)3. switch Vref switches such the integrator's voltage goes down (1 clock)4. count the SM clocks till comparator changes while crossing the zero (2 clocks per count)5. send the count to MCU (1 clock)Is that ok?This has to fit inside the 9 instructions left..

author: Kleinstein
author_rank: Super Contributor
timestamp: April 19, 2024, 12:02:16 pm
content: There is no need to switch of the reference for the start of the rundown. One would ideally start with the reference (e.g. negative) that is already active at the end of run-up. The runup can be so to start with one ref. and end with the other.Having the negative ref. phase for a fixed 32 cycles only if needed is not good. The idea is to always have a negative and positive phase, just with different lengths.The steps would be like this:count neg_ref loopsloop until the comparator detects a positive integrator voltagemaybe add a little delay (e.g. 2 to 4 cycles) - could be used to send the first part of the resultswitch the reference to positivecount pos_ref loopsloop until the comparator detects a negative integrator voltageturn off the referencesend the rest of the result (pos_ref counts)The loops to count and wait for the comparator could likely be 2 cycles long. One would beJMP (X--) ; just count from $FFFFJMP (PIN) ; jump upand the other direction asJMP (PIN) ; leave loopJMP (Y--) ; jump up

author: iMo
author_rank: Super Contributor
timestamp: April 19, 2024, 04:34:38 pm
content: This is now 32 instructions.The assumption is the runup always ends up on the negative side (below zero)..Code:.program ms.side_set 1; 1 side set bit for the MEAS pin; don't forget to enable auto pushstart:set pins, 0 side 0mov X, !NULL side 0 ; set X to 0xFFFFFFFFout Y, 32 side 0 ; read the number desired countsirq 0 side 0 ; first residue ADC readingout NULL, 32 side 0 ; stall until DMA finished reading the ADCbeginning:set pins, 1 side 1jmp pin pwmhigh side 1set pins, 2 side 1 jmp Y-- beginning side 1 jmp finish side 0pwmhigh:jmp X-- dummy side 1 dummy:nop side 1 set pins, 2 side 1jmp Y-- beginning side 1jmp finish side 0finish:in X, 32 side 0 ; push PWM to FIFO, after the push X=0, Y=0; let us assume the runup finished on negative siderundown:mov X, !NULL side 0 ; set X to 0xFFFFFFFFcountX:jmp X-- loop1 side 0loop1:jmp pin countX side 0 ; if COMP==0 we are on positive sidein X, 32 side 0 ; send X to FIFOmov X, !NULL side 0 ; set X to 0xFFFFFFFFset pins, 2 side 0 ; set switch such we go downwards towards zerocountY:jmp pin rndwend side 0 ; if COMP==1 we crossed zero, endjmp X-- countY side 0 ; count Yrndwend:in X, 32 side 0 ; send Y to FIFOset pins, 0 side 0 ; set PWMA/PWMB offirq 1 side 0 ; second residue ADC readingout NULL, 32 side 0 ; stall until DMA finished reading the ADC.wrap_targetdither:jmp !OSRE start side 0 ; jump out of desaturation when the OSR has dataset pins, 1 side 0 ; set pin polarityjmp pin dither side 0 ; check if the integrator is still highset pins, 2 side 0 .wrap

author: NNNI
author_rank: Regular Contributor
timestamp: April 19, 2024, 04:52:28 pm
content: By the way, if the positive and negative reference current switch pins can also be incorporated into sideset, a lot of instructions can be saved. This is something I tested successfully, code attached. However, there are certain compromises. Since the delay cycles and sideset pins share the same 5 bits, the more sideset pins you use, the fewer delay cycles you can program. With this code, the duty cycles have changed from 1/16 and 15/16 to 1/8 and 7/8. There are also a few more nops, which to me seem like wasted instructions. However, there's not much that can be done regarding that.Code:.program ms.side_set 3;Additional notes:;PWM duty: 1/8, 7/8start:mov X, !NULL side 0out Y, 32 side 0;irq wait 0 side 0 ;IRQ;out NULL, 32 side 0 ;IRQpwmstart:jmp pin pwmhigh side 5jmp X-- pwmlow side 3pwmhigh:nop  side 5nop  side 5jmp Y-- pwmstart side 3jmp finish side 0pwmlow:nop  side 3nop side 3jmp Y-- pwmstart side 3jmp finish side 0finish:in X, 32 side 0;irq wait 1 side 0 ;IRQ;out NULL, 32 side 0 ;IRQ.wrap_targetdither:jmp !OSRE start side 0jmp pin dither side 4nop  side 2.wrapSimilarly, if a separate switch was used to short the integrator when no measurement is taking place, the dithering code can also be avoided. Of course, with a 4053 switch (triple SPDT) this is not possible, but with a modern (and arguably more suited to the job) part like the TMUX1134, this can be implemented.

author: iMo
author_rank: Super Contributor
timestamp: April 19, 2024, 05:14:20 pm
content: Frankly, I would rather go opposite way - to increase the "delayed" counts in the runup, say 2x, and double the SM clock frequency.That allows to count more clocks in the rundown.. (provided my math is ok)..

author: NNNI
author_rank: Regular Contributor
timestamp: April 19, 2024, 05:36:17 pm
content: There's probably a better way to handle that - push rundown to the second PIO instance with a lower clock divider. That way, the PIO instance that handles multislope runup can be run at a reasonable clock speed, and the rundown PIO instance can have higher resolution.However, that brings me to the question: what's the advantage of rundown vs reading residue using an ADC?

author: iMo
author_rank: Super Contributor
timestamp: April 19, 2024, 05:43:35 pm
content: Using the second PIO is feasible, sure. We need to have the final design of the rundown ready and we may try to place that into the second PIO.The small HW issue will be with the handling of the PWMA and PWMB signals, as those have to be manipulated from both PIOs then.PS: Kleinstein likes to have the end of the runup at the negative side. Years back I made tons of simulations here with the runup, but cannot remember how the runups ended up. My feeling is the runup may end up at both sides. Perhaps there is a trick..

author: Kleinstein
author_rank: Super Contributor
timestamp: April 19, 2024, 07:11:28 pm
content: One can have the runup end at a fixed state. The runup is a squence of 3 parts, e.g.:1) fixed positive (short)2) positive or negative depending on the comparator reading (usually longer, like 10 x more than the short phases)3) fixed negative (short)The code with more side effects already has such a sequence.The way with just using the auxiliary ADC has a limited resolution for the resudual charge. One point here is that the ADC gain depends on the integrator gain and this includes the inegration capacitor.With an old style PP or PS integration capacitor the thermal drift of the capacitance could limit the usable resolution from the auxiliray ADC. With a C0G capacitor this would be a bit less of an issue.Especially with shorter integration like 1 PLC the runup part has only some 1000-6000 steps and thus maybe some 10-12 bits of resolution from this. Because of the start and stop part and with an not so ideal time for the comparator reading one can loose 1 or 2 bits. Getting more than 10 bits from a 1 PLC runup needs a relatively fast modulation and this can come with compromises. The rest would have to come from the auxiliry ADC. It gets even worse as shorter integration. Unless one really goes for 14 or 16 bits one may run into quantization limits.The rundown part adds resolution and thus less need for fast modulation and less demand on the auxiliary ADC. This way a µC internal ADC (e.g. 10 bits) can be suficient. It takes a little extra time for the rundown, but not that much to be a problem at 1 PLC or slower.

author: iMo
author_rank: Super Contributor
timestamp: April 19, 2024, 07:40:31 pm
content: Quote from: Kleinstein on April 19, 2024, 07:11:28 pmThat ends the runup at the "fixed negative" part 3), but where does the "voltage level" end at the end of the 3rd part above?PS: I've been asking that because in case the runup voltage ends "above zero", we have to provide similar/symmetrical rundown sequence as we did when it ended "below zero" (on the negative side) as well. Both will not fit in the PIO_0.

author: Kleinstein
author_rank: Super Contributor
timestamp: April 19, 2024, 08:14:05 pm
content: The voltage at the end can be positive or negative depending on the input voltage. Usually one can not exclude one sign or the other. So a rundown would have to cope with both cases I am afraid

author: iMo
author_rank: Super Contributor
timestamp: April 19, 2024, 08:25:32 pm
content: Now, when we agree the runup's end voltage may end up anywhere (positive or negative), would be above "positive" and "negative" symmetrical rundown sequences work fine?As I indicated above a recommendation I saw somewhere said the rundown sequences (starting at positive or negative voltage) have to approach (at their end) the comparator always from the same side (ie positive) in order to compensate for comparator's hysteresis (and perhaps for other errors too).. That means they cannot be symmetrical.An example is the Landsberg's rundown NNNI implemented in his MS II - you go always up into positive (positive or negative runup's end voltage regardless) and then down to zero (crossing zero from the same positive side of the comparator).

author: Kleinstein
author_rank: Super Contributor
timestamp: April 19, 2024, 08:46:41 pm
content: The two step run-down can work with any starting charge. It just needs a little (but not much) heatroom for the start. The sequence is not really symmetrical, but it is still the same sequence of steps, just different times. So not just the same direction for the end, but also all the reference transitions in the same sequence, just with 2 variable times. A condition can be the any of the phases should not be too short as settling at the integrator takes some time.

author: iMo
author_rank: Super Contributor
timestamp: April 19, 2024, 09:01:13 pm
content: Frankly, I've been looking for a symmetrical perfectly deterministic rundown..Those not fully symmetrical rundowns with varying/different times etc lead to a voodoo where one juggle with esoteric 15 digits floating point coefficients in order to get a reasonable results..

author: Kleinstein
author_rank: Super Contributor
timestamp: April 19, 2024, 10:19:05 pm
content: The rundown part is only a relatively small part of the result. The question is only if the reference for the rundown are more accurate than a high resolution ADC and stable capacitor, that would be the alternative.If the postive and negative reference are the same size, not extra constant is needed to calculate the result. Ideally the difference between the reference (including a possible offset of the integrator input voltage) is an additional correction parameter, that has a limited effect. Measuring that parameter is relatively simple by comparing the case of no reference and both references at the same time. It is a little extra effort for a kind of "factory calibration", but the later math is not so bad. No need to go above some 16 bits, as the rundown part is still only a relatively small part of the result.How would a fully symmetric rundown look like ? Only one direction and thus a comparator reading from both directions is not really a good option. It adds the comparator hysteresis / delay problem and also the problem with a very short pulse close to zero initial charge.A fixed sequence with 2 variable times is kind of the natural choice. The system is fully determistic. There is no big difference from starting positive of negative. At zero res. charge one gets 2 short pulses and when away from zero one of the pulses gets longer and the short one stays the same. There is just some freedom in the design on how short the pulses can get. Adding a few more cycles there is usually not such an issue.A possibly tricky point may be the effect of short pulses in the runup. This way the runup steps may be tiny bit different from just the ref. strength and time. In the shown simple runup scheme the number of short pulse directly follows the runup result and a slightly modified cal. constant could compensate. With not too fast a modulation and thus enough time for the short pulses this should still not be a problem.

author: iMo
author_rank: Super Contributor
timestamp: April 20, 2024, 07:24:47 am
content: So the above routine for the rundown should work as follows (as per KL's description as I have understood it), we have Vref+ and Vref- both 10V (please comment below sequence in VERY DETAIL directly in the below text describing the steps, such we may understand and close this rundown stuff finally and test):***********0. the runup phase ended, the residual voltage RV is somewhere between +/-10VRundown:1. when the comparator shows RV is below zero Volt set Vref switch such we go UP with RV, otherwise set Vref such we go DOWN with RV, reset X2. count with X the SM clocks till the comparator crosses the zero Volt3. send X to FIFO, set the Vref switch to the opposite direction, reset X4. count with X the SM clocks till the comparator crosses the zero Volt5. send X to FIFO6. switch off both Vrefs such the integrator is on holdResidual ADC reading:7. do the second auxADC reading***********etc..Thus at the end of single PLCcycle measurement we gota) preADC value,b) PWMA runup counts,c) PWMB runup counts,d) rundown X counts,e) rundown Y counts,f) postADC value.Is that OK?

author: Kleinstein
author_rank: Super Contributor
timestamp: April 20, 2024, 09:20:24 am
content: The way it is described would use the comparator in different directions and do the extra wiggle for the other direction, that is a bit pointless.Depending on the direction one will get a quite different residual charge from the reaction time (comparator and synchornization in the µC and possible external to the clock).The problem is already the step 1. The idea is not getting a symmetry in the procedure, but a fixed sequency on how the reference switches.The first part should always be the same reference (ideally the one that is active at the end of runup anyway). So no need to look at the comparator first. This reference would be used even if it moves the integrator a little bit away from zero.So no looking at the comparator in step1 and always the same ref. (e.g. negative).The 2nd step is than not waiting for a zero crossing, but wait for the right sign (e.g. positive). The right sign may be present already from the start and than this counting look will be just one pass.To have enough setting time one may have to add a little delay before switching the reference to the other value (e.g. positive). Sending the first counts may be enough delay.The next step is than a similar counting loop for the other sign (e.g. always positive). At the end both reference would be off.If the first counting loop had to do more loops the overshoot is small and the 2nd loop will be close to the minimum length.If there is time (e.g. longer integration) one could wait a little to let the fast part of the DA and the ampölifier settle before doing the resudual ADC conversion.The result would not need separate PWMA and PWMB counts for the runup, as the total count for the steps is fixed (e.g. given as a parameter to set the integration time). So counting one side is enough.

author: iMo
author_rank: Super Contributor
timestamp: April 20, 2024, 06:51:38 pm
content: QuoteWhat is the "right sign"? Right sign of what?We have only three (3) things here during the rundown process at hand:1. Vref switch PWMA2. Vref switch PWMB3. output of the comparator, which could be "0", or "1", where one input of the comparator is Grounded (0 Volt)."Waiting on zero crossing" means we wait till the RV (Residual Voltage, here it is the same as "integrator voltage") voltage goes from "negative" to "positive", or from "positive" to "negative", where zero is 0 Volt.QuoteWhere (by what) your "right sign" is indicated? How I get the information on the right sign when the RV moves away of zero?

author: Kleinstein
author_rank: Super Contributor
timestamp: April 20, 2024, 08:46:57 pm
content: The counting lops are waiting for a comparator output and this sign of the integrator output voltage.

author: iMo
author_rank: Super Contributor
timestamp: April 21, 2024, 06:46:23 am
content: Quote from: Kleinstein on April 20, 2024, 08:46:57 pmOur counting loops above wait for a comparator output, so I still have pretty hard time to understand how is your idea on this simple rundown process in this design like..I would be happy to formalize that simple rundown process based on your valuable hints, but I am not native English speaker, so perhaps the problem is on my side..

author: Kleinstein
author_rank: Super Contributor
timestamp: April 21, 2024, 07:42:46 am
content: Maybe it is easier to show a suggested code for the rundown. I hope I got it right - I have not used the RP2040 PIO programming thus far.The code part would be just after the run-up part and before starting the residue ADC.Code:.program run-down.side_set 3; 3 side bits for ref. pos(1) + neg(2) + meas(4); meas could be done separate if more delay is neededin X, 32 side 2 ; send X to FIFO (runup-counts), ref to neg , input offmov X, !NULL side 2 ; set X to 0xFFFFFFFFcount_neg:jmp pin end_neg side 2jmp X-- count_neg side 2 ; count , jump to close the loopend_neg:in X, 32 side 2  ; send X to FIFO (counts for neg ref.) , some delay for minimum pulse length for settlingcount_pos:jmp X-- cout side 1 ; count , no real jumpcont:jmp pin count_pos side 1count_end:in X, 32 side 0 ; send X to FIFO (counts for neg+pos ref.); add some delay ( more like a loop for a few µs to allow the amplifier and fast DA to settle); start the residue ADC

author: iMo
author_rank: Super Contributor
timestamp: April 22, 2024, 07:30:38 am
content: Thanks, so you have combined the first comparator check (whether we are on the negative or positive side) with counting when we are already on positive side (thus counting the negative charge till zero Volt) after runup's end.Thus,1) when the integrator's voltage at the start of the rundown was negative (COMP==1), the result will be X=0+POS,2) when the integrator's voltage at the start of the rundown was positive (COMP==0), the result will be X=NEG+0.Having 3 sideset bits would limit the instr. stretching in runup to max +3 (instr ), however..With MEAS in "set" it will be +7, which allows 1:8 modulation and might perhaps fit..

author: iMo
author_rank: Super Contributor
timestamp: April 22, 2024, 08:25:11 am
content: This is with 1:8 modulation, MEAS is the single set bit, PWMA/PWMB/INPUT two sidebits (in the below source marked as "P" and they need to be set accordingly in the final source).It looks like it is now 31 instructions, but the instr. have to be doublechecked..The dithering loop could be perhaps made of less instr. now..After the rundown there is enough time for settling as the auxADC is called via interrupt and it samples around the middle of the first 8 SPI bits (it depends on the ADC chip used), moreover you may stretch the instructions before the second auxADC as well.PS: so we get following results off a single PLC measurement1. pre- auxADC reading2. runup count3. rundown's negative charge count4. rundown's negative+positive charge count5. post- auxADC readingCode:.program ms.side_set 2; 1 set bit for the MEAS pin; 2 sideset bits for PWMA/PWMB/INPUT setting; don't forget to enable auto pushstart:set pins, 0 side P ; MEAS=0mov X, !NULL side P ; set X to 0xFFFFFFFFout Y, 32 side P ; read the number desired countsirq 0 side P ; first residue readingout NULL, 32 side P ; stall until DMA finished reading the ADCbeginning:set pins, 1 side P ; MEAS=1jmp pin pwmhigh side Pset pins, 1 side P  ; was 15jmp Y-- beginning side P  ; was 13set pins, 0 side P ; MEAS=0jmp finish_rup side Ppwmhigh:jmp X-- dummy side P  ; was 15dummy:nop side P  ; was 11set pins, 1 side P ; MEAS=1jmp Y-- beginning side Pset pins, 0 side P ; MEAS=0jmp finish_rup side P ; MEAS=0finish_rup:in X, 32 side P ; send X to FIFO (runup-counts), ref to neg , input offrundown:mov X, !NULL side P ; set X to 0xFFFFFFFFcount_neg:jmp pin end_neg side Pjmp X-- count_neg side P ; count , jump to close the loopend_neg:in X, 32 side P  ; send X to FIFO (counts for neg ref.) , some delay for minimum pulse length for settlingcount_pos:jmp X-- cout side P ; count , no real jumpcont:jmp pin count_pos side Pcount_end:in X, 32 side P ; send X to FIFO (counts for neg+pos ref.)rundown_end:irq 1 side P ; second residue readingout NULL, 32 side P ; stall until DMA finished reading the ADC.wrap_targetdither:jmp !OSRE start side P ; jump out of desaturation when the OSR has dataset pins, 0 side P ; set pin polarityjmp pin dither side P ; check if the integrator is still highset pins, 0 side P  ; set pin polarity.wrap

author: Kleinstein
author_rank: Super Contributor
timestamp: April 22, 2024, 09:44:37 am
content: The 8:1 modulation may be a bit to little. So one would ideally want a longer delay for the mittle part of the runup. There is no need to limit this to an easy binary ratio like 1:8 or 1:32.Especially with the rundown one usually wants a relatively fast clock and thus longer delay.In the code the very start with set pin = 0 to turn off the input is not really needed. once the ADC has run it will end with meas = 0. If the conversion is aborted, one would needed to discharge the integrator anyway, as it may well be saturated.So one could skip the first command.The code is still a mix of using side channel and set pins (for the dithering part). As it is tricky to add delay otherwise it may be better to not use the side channels.The 2 rundown cases are not really 0 + pos or neg + 0. The other reference is still used for a short sime. The positive part is not even fixed, it can still vary a littlel (like +-1 cout) from noise and comparator hysteresis.

author: iMo
author_rank: Super Contributor
timestamp: April 22, 2024, 10:10:09 am
content: Perhaps it is feasible to stretch out some instructions inside the runup loops such we will get a better modulation ratio.Not using sidebits here may add up the "set" instructions, imho, and it may not fit into the 32 instructions then.Now we are at 31. Hopefully the X register does not zero itself after the "in X, 32" instruction, then you would have to set it to "FF.." and we are at 32.As we basically have the preADC+runup+rundown+postADC+dithering framework "ready", people may start to try to optimize the code further on.PS: removing the "dithering" and moving "sideset" signals to "set" (thus none sideset bits) would allow up to 1:32 modulation ratio, and perhaps 5bits (+/- 1LSB) rundown resolution..

author: iMo
author_rank: Super Contributor
timestamp: April 22, 2024, 12:48:52 pm
content: Here it is with all three signals in "set pins", none in sideset, modulation (for example) set to 2:64 clocks.None dithering.The rundown part not tested yet as I do not have the analog part handy.The runup timings of the PWMA, PWMB and MEAS look ok (on the first glance) on my scope.29 instructions at this moment..PS: the rundown result with the below code will be calculated (my current understanding, please confirm, my math gets rusty):Result = 3 - 2*RDN + RDNPwhere RDN and RDNP are the results returned by the PIO from the rundown.Edit: small fixCode:.program ms; MEAS PWMB PWMA signals in "set pins" with 4+2+1 weights; don't forget to enable auto pushstart:set pins, (0+0) ; switch all off (not required perhaps)mov X, !NULL ; set X to 0xFFFFFFFFout Y, 32 ; read the number of desired countsirq 0 ; first auxADC residue readingout NULL, 32 ; stall until DMA finished reading the ADCbeginning:set pins, (4+1) ; MEAS=1jmp pin pwmhighset pins, (4+2)  ; was 15jmp Y-- beginning  ; was 13set pins, (0+2) ; MEAS=0jmp finishpwmhigh:jmp X-- dummy  ; was 15dummy:nop  ; was 11set pins, (4+2)jmp Y-- beginningset pins, (0+2) ; MEAS=0jmp finishfinish:in X, 32 ; send X to FIFO (runup-counts), ref to neg, input off; rundownmov X, !NULL ; set X to 0xFFFFFFFFcount_neg:jmp pin end_negjmp X-- count_neg ; count, jump to close the loopend_neg:in X, 32  ; send X to FIFO (counts for neg ref.), some delay for minimum pulse length for settlingset pins, (0+1)count_pos:jmp X-- cont ; count, no real jumpcont:jmp pin count_poscount_end:set pins, (0+0) ; turn switches offin X, 32 ; send X to FIFO (counts for neg+pos ref.)irq 1 ; second auxADC residue readingout NULL, 32 ; stall until DMA finished reading the ADC% c-sdk {// Helper function (for use in C program) to initialize this PIO programvoid ms_program_init(PIO pio, uint sm, uint offset, uint pin, uint input, float div, uint pin_MEAS) {// Sets up state machine and wrap target. This function is automaticallypio_sm_config c = ms_program_get_default_config(offset);// Allow PIO to control GPIO pin (as output)pio_gpio_init(pio, pin);pio_gpio_init(pio, pin+1);pio_gpio_init(pio, pin_MEAS);// set the pin for jump if pin high instructionsm_config_set_jmp_pin(&c, input);// Connect pin to SET pin (control with 'set' instruction)sm_config_set_set_pins(&c, pin, 3);// Set the pin direction to output (in PIO)pio_sm_set_consecutive_pindirs(pio, sm, pin, 2, true); // 2 pins for PWM high and lowpio_sm_set_consecutive_pindirs(pio, sm, pin_MEAS, 1, true); // 1 pin for MEAS pin// Set auto push to ISRsm_config_set_in_shift(&c, false, true, 32);sm_config_set_out_shift(&c, false, true, 32);// Set the clock divider for the state machinesm_config_set_clkdiv(&c, div);// Load configuration and jump to start of the programpio_sm_init(pio, sm, offset, &c);}%}And the reading of the additional rundown results off the PIO's FIFO is easy (and it works):Code:void get_counts(PIO pio, uint sm , uint32_t countNum){pio_sm_put_blocking(pio, sm, countNum - 1);counts = ~pio_sm_get_blocking(pio, sm); // MS runup countRDN = ~pio_sm_get_blocking(pio, sm); // rundown negative chargeRDNP = ~pio_sm_get_blocking(pio, sm); // rundown negative+positive charge}

author: iMo
author_rank: Super Contributor
timestamp: April 25, 2024, 09:48:07 pm
content: Quote from: Kleinstein on April 22, 2024, 09:44:37 amHow do you handle the situation where ie. the positive part jitters +/-1 count?Especially when doing post-auxADC measurement?

author: Kleinstein
author_rank: Super Contributor
timestamp: April 26, 2024, 06:32:00 am
content: Both the negative and positive ref. counts are included in the result. This applies to both cases with the positive and negative charge to start with. So not special handling needed for cases when the short pulse at the end can have slightly different length.The problem is not the cases with a short positive or short negative pulse . There is anyway also the case near zero resudual charge when both pulses are short.The slight complication with a rundown come from a not perfect balance between the positive and negative reference. For the run-up part either the positive or negative reference is active. So the relevant scale factor is the difference between the 2 run-up step cases and thus the difference (including the sign) positive an negative reference currents. For the rundown part there are 3 possile states with positive, negative or no active reference. One can write the positive/negative ref. as: +-0.5 * (pos-neg) + 0.5 (pos+neg) . The main part is still from the difference, like in the run-up, but there is an additional correction term from the sum of the references. With ideal symmetry this would be zero, but the circuit is usually not ideal and thus the extra small correction term with the sum of the reference currents. Ideally one would measure it in an extra calibration procedure (could be only once at the initial calibration) and include the correction term. The alternative would be highly accurate resistors (e.g. 0.05% range).The - 2*RDN + RDNP from is for perfect symmetry. With the correction for possible asymmetry there is an additional small term proportional to RDNP. The post aux_adc would than add another term for additional resolution with a separate cal factor.

author: iMo
author_rank: Super Contributor
timestamp: April 26, 2024, 07:34:36 am
content: Yep, I've made an excel sheet to see the stuff in more detail, based on the paper linked in this thread, so I may play with the values (version 0).The runup phase could have, say, X mV (or less) resolution, the rundown (in this design), say XX uVolts.Then the auxADC on top of it - I have no math yet how to incorporate it into the end result, so as you indicate it would be matter of a calibration.. Still thinking how to formalize the rundown uncertainty and auxADC such it fits together smoothly..PS: replaced the table because of an error, RrefP,N=Rin

author: Kleinstein
author_rank: Super Contributor
timestamp: April 26, 2024, 09:15:25 am
content: It is not a good idea to have different resistors for the input and reference currents. To get compensation of the switch resistance TC they should be the same.Instead of a smaller resistor for the references a higher voltage (e.g. 14 V = 2 x raw reference) is the better way.The times for RDN and RDNP should not get down all the way to zero. It would be more like 4 or 5 cylces as a minimum to allow for settling. For the result a constant added part is not important as one will subtract a zero reading anyway.For the uncertainty the contributions from the parts (run-up, rundown difference of reference, rundown sum of reference and the residual ADC) is the relevant factor. With 1 PLC (20ms) the runup step are some 1/2000 for the full scale. With longer integration even more comes from the run-up. The run-down makes up some 2 run-up steps and in the current configuration some 120 cycles, the residual charge ADC is for 1 of the rundown steps or some 10 ppm of the FS.

author: iMo
author_rank: Super Contributor
timestamp: April 26, 2024, 09:29:23 am
content: The numbers in the table are just examples, I will put the excel table here when it settles. Edit: Moreover there is an error in the table, I calculated with Vref/2 values..In your rundown's code above there are now 4+3 SM clocks for settling the NEG and 4 SM clocks for settling of POS. Could be stretched further on as one would need..The runup timing could be modded easily by playing with the clock counts as well, I have now 4+60 SM clocks (1/16 ratio) and it just works.Code:; 60 to 4 SM clocks modulation (60+4=64 clocks)..beginning:set pins, (4+1)  ;jmp pin pwmhighset pins, (4+2)  ;jmp Y-- beginning  ;set pins, (0+2)jmp finishpwmhigh:jmp X-- dummy  ;dummy:nop  ;set pins, (4+2)  ;jmp Y-- beginningset pins, (0+2)jmp finishfinish:..

author: NNNI
author_rank: Regular Contributor
timestamp: April 26, 2024, 12:24:17 pm
content: iMo, once again, thanks for your work on the code. I never really considered using set pins for everything (both reference switches and input switch), this enables use of all delay bits for up to 32 cycles and ultimately saves much needed program space.I am honestly not convinced about additional rundown when a residue ADC is already present. Based on my naive assumptions, if runup gives me roughly 12 bits of resolution and the residue ADC is also 12 bits, 20 bits (roughly 6.5 digits) should be possible. That way, only one constant would need to be calibrated to match runup and residue ADC readings.

author: iMo
author_rank: Super Contributor
timestamp: April 26, 2024, 01:34:35 pm
content: @NNNI: I've been interested in a deeper understanding of pros and cons of the rundown+auxADC alchemy as well, therefore my playing with the code and tables..Your hw is ready for the experiment with that combo, so you may try. I think the key message here is the auxADC is of less "quality" than the rundown process, therefore anything which would "de-load" the auxADC helps. You get rather small voltage at the integrator's output after the rundown, so the auxADC will handle much smaller input voltage range.My main concern are the various coefficients you have to get somehow and apply "accordingly" to all those elements such you get a result..But we have here people with hands-on experience, so let us learn from them..

author: Kleinstein
author_rank: Super Contributor
timestamp: April 26, 2024, 02:19:32 pm
content: The main scale factor for the rundown is still the same as the runup. So ideally just the number of clock cycles per run-up set. It's only small corrections from asymmetry and settling effects during runup that may apply. Especially the correction for settling may not be needed unless the modulation is really fast (I don't need it at 8 digit resolution). The way with rundown may have 1 or maybe 2 correction constants, while the resudual ADC directly needs a pretty stable auxiliary ADC and a more critical cal factor there. Getting full 12 bits from the residue is pushing it: there is extra noise from the 2nd conversion and the gain factor and integrator capacitance have limited stability. After rundown the auxiliary ADC is something like 30 times less critical.The rundown part is usually quite stable, as it uses the same reference as the runup.For just 6.5. digits (with 1 or 10 PLC) just the resudue ADC can be OK. When aiming for more (especially high resolution already with short integration like 1 ms) the extra resolution from the rundown can really help. Getting more resolution from faster modulation is challanging on the integrator.A downside with the extra rundown is a bit of extra time needed and also more code, which may be an issue with the limited code space for PIO. One may want a bit slower modulation or at least longer minimum pulse lengths to avoid the settling effect - for the resolution the fast runup is not longer needed.

author: iMo
author_rank: Super Contributor
timestamp: April 26, 2024, 02:27:07 pm
content: I've updated above table, there are RDN and RDP "fixed" clocks (5 as an example), and the zero values returned by RDN and RDP (an example) to see the runup values and diffs, where the RDP always returns at least "1" (we make the decrement before the comparator check).Also my understanding is the rundown process above returns max 31n+1p (or 0n+30p) "net" counts, where one count == 2 SM clocks (thus rundown_resolution = runup_resolution/60 ).

author: iMo
author_rank: Super Contributor
timestamp: April 27, 2024, 07:34:05 am
content: Here is the excel table you may play with v1.0.If you may find an issue pls do report..PS: the formula used:Code:Vin = (Vref * Rin / Rref) * (PWMcharge * (2 * RUPN - MS_N) + 2 * ( 2 * RDN - RDNP + 1)+ RDNfix - RDPfix) / (PWMperiod * MS_N)Update: v1.1 with fixed PWM clocks inputUpdate: v1.2 with fixed rundown calculationUpdate: v1.3 with fixed rundown calculation - the RDPfix and RDNfix are single SM clock values, RDP and RDN are 2 SM clocks counter valuesUpdate: v1.4 fix - everything shall be related to 56 SM clocks of charge (PWM_charge)..

author: Kleinstein
author_rank: Super Contributor
timestamp: April 27, 2024, 08:47:04 am
content: The run-up modulation with a 4/60 or 60/4 modulation has a usefull part of 60-4 = 56 cycles that are actually modulated. It is not just the 4 cycles that are effectively lost, but also the 4 the other polarity.Depending on the integrator hardware 4 cycles (500 ns) for the shortest pulses and settling looks about right.This gives the residual charge a range of about +-60 cycles range. depending on the delay between reading the comparator and the start of the feedback the range may get a little larger than just 1 feedback step. This way the run-down part could get a little larger than just -31 to + 30 counts. The range is more approximate than accurately calculted through.A big question is how good the jitter is and if one needs / wants external synchronization to a more stable clock. Chances are the clock from the RP pico is not good enough and would at least need an external oscillator. It is not so much jitter, modulation of the crystal frequency depending on how neighboring pins are set or how much current is drawn. At the very least the pins for the ref. modulation should be away from the clock.

author: iMo
author_rank: Super Contributor
timestamp: April 28, 2024, 12:11:46 pm
content: Updated to a perhaps the final version, where I returned to the traditional formula, which works properly only when the rundown charges are related to the "PWM charge" (56 in our case above).The rundown range is +/- (0..27) counters diff counts (that is 56 SM clocks, also mind there are the RDN and RDNP inputs now as per the PIO source). The rundown now returns "reasonable" values, imho, which fit the both resolutions "smoothly".For example the above runup resolution is 9800uV and the rundown resolution 175uV in 56 steps.Still the question is how to handle the +/-1 noise in the rundown results and the incorporation of the noisy auxADC results..

author: NNNI
author_rank: Regular Contributor
timestamp: April 28, 2024, 03:31:08 pm
content: I finally took the time to read through all of the messages posted and process them properly.I think I finally see some merit in removing as much charge from the integrator as the clock resolution will allow. As per the Landsberg rundown scheme, if I use the same clock to carry out rundown as I use for runup, the rundown counts can basically just be added to the runup counts. This eliminates the need for more constants that would need to be calibrated somehow. The effects of comparator hysteresis can be removed to a large extent by using some kind of zero-crossing slope amplifier, similar to the one described by Jim Williams in National Semiconductor App Note 260. This way, we don't need to add a certain amount of clock cycles' worth of charge into the integrator to compensate for comparator hysteresis. The board I designed has a footprint for such a slope amplifier, but I removed it since it had some issues. I will have to experiment with it some more. The residue ADC will have to digitize a much smaller integration range, I guess calculating that range mathematically and figuring out gain such that the small amount of charge left in the integrator spans the residue ADC's range will be most beneficial.Of course, the latter part depends on the integrator starting and ending within that specific limited range. Dithering might necessitate a larger voltage range on the residue ADC. I will have to play around with my board to see what kind of numbers I get.Regarding jitter, the numbers from a crude test performed by a friend indicate around 50ps RMS jitter, measured between successive rising edges of a GPIO toggling at 20MHz (done using PIO) with a 400MHz overclock. I am not sure how much of this comes from the crystal and how much from the PLL, and if a better crystal will make a difference. More (proper!) measurements will have to be made.

author: Kleinstein
author_rank: Super Contributor
timestamp: April 28, 2024, 04:02:19 pm
content: The crystal clock jitter is usually on the order of 1 ps RMS. So the measured 50 ps are most likely mostly from the PLL. This number also makes sense - it is about what the STM32G071 datasheet gives for a different µC with internal PLL. Jitter is usually not 100% white phase noise, but may have some extra lower frequency component. So when the clock is divided down (even with an ideal divider) the period jitter can go up. For the mudulation patter (some 5-20µs period) the effective noise could be a littler higher than the period jittter.The noise added from jitter is about RMS jitter divided by the integration time times the reference strenght times the square root of the number of ref. switching events. As a number example maybe 50 ps / 20 ms * 28 V * sqrt(4000) = 4.4 µV rms.50 ps jitter would add a noticeable noise source to the ADC, especially when using relatively fast modulation. It could still be OK for the 6-7 digit range. For lower noise one would likely need external synchronization directly to a stable clock. This could bring the jitter down to the 1-3 ps range.

author: NNNI
author_rank: Regular Contributor
timestamp: April 28, 2024, 04:26:09 pm
content: Thanks for the example calculation, it was very insightful.There is always the option of running the RP2040 without a PLL from an external 48MHz clock (which would also work out in terms of timing, 48MHz is exactly half of the 96MHz I chose for the previous code). I am not sure if this would yield much improvement.Would I be right in assuming that the faster a logic IC is meant to be clocked, the lower the jitter? For example, the SN74LVTH273  can be clocked at up to 150MHz. The latch can be clocked from the same oscillator that is feeding the RP2040, that might help with synchronization issues.:https://www.ti.com/lit/ds/symlink/sn74lvth273-ep.pdf

author: Kleinstein
author_rank: Super Contributor
timestamp: April 28, 2024, 04:42:52 pm
content: The faster locic chip usually add less jitter, though it is not a direct link. I had a hard time finding some jitter specs for the logic chips. An an analog devices application note (AN 501) there are a few numbers:74HCT... ~ 2.2 ps74ACT... ~ 1 ps74LS... 5 psThe 74LVTH and similar modern CMOS series are likely more like the ACT.Depending on the code to run, one may not need that much clock. After all the RP2040 has 2 cores. So not need to get close to the 50 MHz max for an external clock.In my ADC version I use only 8 MHz, though I see it getting tight in some places to do the math. The same clock for the sync and RP2040 is definitely a good idea. If the PIO runs slower one would still want a phase adjust step and than could still use the PLL for the µC clock.A direct USB link and thus need for the 48 MHz is not really there, as one usually wants an isolation layer to USB.

author: iMo
author_rank: Super Contributor
timestamp: April 28, 2024, 05:53:21 pm
content: Quote from: Kleinstein on April 28, 2024, 04:42:52 pmWhy do you need that perfect sync at the clock level between 2040 and PIO? The 2040 and PIO have nothing common with the clocking, there is no clock domain crossing with missing sync. Those are fully independent, because they communicate via FIFO/interrupts (this handles the domain crossing), a kind of async communication.The PIO is a bunch of cmos logic stuff, with perhaps 1ps or less jitter, which has no "direct signal lines" to the CPU, except the clock line.The CPU and PIO share the clock in 2040, but there is no need on phasing or whatever. The design here is different to your AVR/ARM designs where your peripheries and core CPU were somehow phase depended, imho.

author: Kleinstein
author_rank: Super Contributor
timestamp: April 28, 2024, 08:18:47 pm
content: There is no need for a perfect sync betwen the CPU and PIO part. Usually this is given as the PIO clock is from a divider. Only the possible fractional divider could cause trouble.The sync problem would appear, when the CPU runs from the PLL and than external sync FF are used to directly synchronize to an external clock. This case is triky and if possible I would avoid it because of the complications with the phase, even if the PIO clock would be the same as the PLL input clock.The more realistic case is an external clock (e.g. 20 MHz range) to directly run the CPUs. The PIO clock could even be a bit lower to get the delays without extra code.Chances are one can skip an external sync step, though there is possibly a tiny bit of delay modulation from the µC internal state that could lead to a little INL.If needed / wanted an external sync with 2 flip flops (the input path is not that critical and could be direct) is not that complicated if there is no PLL involved.

author: iMo
author_rank: Super Contributor
timestamp: April 28, 2024, 09:04:07 pm
content: NNNI may test that easily (including the new rundown) while running off the stock 12MHz crystal against the PLL version. A stable canned XO/TCXO would be even better. The 48MHz is needed, however, as you want to upload the binary to the 2040 easily, and you will do it many times, sure.On the other hand I would be much more concerned about the noise around the comparator and auxADC.. That introduces errors and I would be happy to see some real data coming off the above code, such we may play with the math. Perhaps NNNI finds some free time for running it on his pcb, its just a copy/paste exercise..

author: Kleinstein
author_rank: Super Contributor
timestamp: April 28, 2024, 09:19:45 pm
content: To make use of the extra resolution gained from the rundown part one would need additional gain for the residue ADC. Without extra gain there is not much gained.The comparator noise should not be an issue - it only increases the range that the residue ADC has to cover a little.For the aux ADC it is often more the amplifier than the actual ADC noise. With less resolution needed from the aux ADC it would be less than before.Including the rundown part makes the aux ADC less critical (get some 5 bits from the rundown instead) and even the internal ADC may than be good enough.Wanting the 12 MHz for an easy code download is a good point.

author: NNNI
author_rank: Regular Contributor
timestamp: April 28, 2024, 09:30:40 pm
content: I was just about to bring up the point about being able to upload code via USB. It is very convenient and fast. However, programming via the SWD pins (using a Raspberry Pi debugger, for example) is another alternative. I am not sure how much SWD programming is dependent on system clock.I am honestly not sure when I will be getting back to the project. I left it in a rather messy state, so getting everything running and familiarizing myself with the code diminddl and I worked on nearly a year ago will take some time, plus I have to finish testing my own ideas first. The project files are available, so it should be possible to get your own set of boards for experimentation, or replicate the core circuit (it's quite simple) on a breadboard. I understand your eagerness for the results, but all I ask for is a little patience till I can get everything sorted on my side.

author: PCB.Wiz
author_rank: Super Contributor
timestamp: April 28, 2024, 10:48:29 pm
content: Quote from: iMo on April 28, 2024, 09:04:07 pmAn external Osc is certainly easy to try.TCXO's need care, as some use digital corrections that give small jumps in frequency as the temperature varies.Some vendors now call their better TCXOs analog compensated - eghttps://ecsxtal.com/news-resources/what-are-the-benefits-of-using-analog-compensated-tcxos/I'm thinking the ideal isan oscillator that is (very) stable over the integration time.That means long term drift is less important, & it is best to focus to avoid effects like micro-jumps or other disturbances.The close-in phase noise is looking like the best indicator of that.A bit of thermal mass around the oscillator can help reduce temperature slope effects, and a local low noise regulator can isolate supply variations.Quote from: iMo on April 28, 2024, 09:04:07 pmYou just need to be able to generate 48MHz for the USB, so more clock choices exist.I've not found a very low phase noise oscillator at 48MHz yet, tho NDK say they can cover 20-50MHz in their NZ2520SDA family. Just needs some MOQAddit : chip1stop do show a NZ2520SDA 48MHz order code, so I've asked the MOQ on that. (they also have codes for 35MHz and 54MHz, not indicated by NDK ?)

author: iMo
author_rank: Super Contributor
timestamp: April 29, 2024, 06:34:41 am
content: Quote from: NNNI on April 28, 2024, 09:30:40 pmYep, the analog part of the design is an another story which we have not elaborated yetMy basic motivation has been to have a look at the 2040/PIO and its applicability. Of course it could be done by a stm32xxx (here we lack the PIO) or an fpga+MCU (here the complexity is higher) as well.Hopefully rPi company will come with the rp2041 soon - with the fixed ADC, and with 4xPIO with 256 instructions each

author: Kleinstein
author_rank: Super Contributor
timestamp: April 29, 2024, 07:46:23 am
content: There is no need for a super stable clock. The point is jitter over a time frame of some 10 µs. The switches and an optional buffer to improve the isolation would add a few ps of jitter anyway. So a standard crystal oscillator should be good enough. The crystal directly at the RP2040 as for the RP-pico could have an issue with the internal state effecting the clock - I had this issue with the AVR and this caused quite some INL error (e.g. 10 ppm range). Chances are 12 MHz directly with no PLL could be fast enough for the ADC, though this would not allow to use the USB while using the ADC.

author: NNNI
author_rank: Regular Contributor
timestamp: April 29, 2024, 01:07:32 pm
content: iMo, I got a chance to talk to Eben Upton at Maker Faire Hannover 2023. He mentioned that the instruction memory for PIO was closely coupled to the architecture, so more memory is apparently not the easiest to implement. He did hint at using out exec to overcome this limitation, but that comes with its own challenges.I was looking at suitable crystals, and apparently a 48MHz version of the crystal  Jaromir used in the ADC for his NVM project  exists. I was not able to find jitter specs in the datasheet. But as Kleinstein says, a 'regular' oscillator will probably suffice, since a latch like the '273 will add its own jitter. The 48MHz version  of the temperature compensated crystal series PCB.Wiz recommended is available at a reasonable price in single quantities from Mouser.Once I have the issues with the code sorted out, I think it would make for an interesting comparison to see how well the latched version performs.:https://www.mouser.com/datasheet/2/137/SG5032CAN_en-961596.pdf:https://github.com/jaromir-sukuba/nvm/blob/main/hardware/Schematics_pdf/HOMER/rnvm_homer.pdf:https://www.mouser.com/datasheet/2/122/ECS_3225MVQ-1825332.pdf

author: Kleinstein
author_rank: Super Contributor
timestamp: April 29, 2024, 03:57:39 pm
content: I would not go for just a crystal, as the frequency can be effected by the µC and this can cause nasty INL problems.There are relatively cheap boxed oscillators that can do the job (some 1 ps jitter specs seem to common).The question is if one needs external latches / flip flops for an extra sync. step. The extra external sync step may reduce the jitter a little and reduce possible delay modulations at the µC, but it also adds power consumption and possibly EMI problems. There is a good chance that one could skip it.With an external sync one would likely use a relatively low clock (like 12 MHz), which should make the USB use easy.Without an external sync one may opt for a faster clock (maybe 48 MHz if one wants USB while the ADC is active).For the processing power already 12 MHz should be sufficient. A DMM would anyway have a 2nd µC at the output / interface side.

author: iMo
author_rank: Super Contributor
timestamp: April 30, 2024, 07:12:57 am
content: Quote from: Kleinstein on April 29, 2024, 03:57:39 pmIn your latest MS ADC schematics here (the AVR based one ) you are passing the 2 channel selection signals of the 4053 (VrefP and VrefN switches) via two FFs (1x 74AC74), while the two FFs are clocked directly from the canned xtal oscillator box. That could be added into the design, and bypassed when not needed.

author: Kleinstein
author_rank: Super Contributor
timestamp: April 30, 2024, 10:56:13 am
content: The extra flip flops synchronize the ref. signals directly to the clock. It is not so much for the jitter, but more for small INL effects when the µC state effects the delay. For the AVR this effect is visible though still not that much of an issue ( < 0.1 ppm FS for the INL). I have tried both with and without the extra FF with not much difference.

author: NNNI
author_rank: Regular Contributor
timestamp: May 06, 2024, 09:00:52 am
content: QuoteKleinstein mentioned this, does it have something to do with kTC noise? I am not really familiar with that concept, I would be glad if it could be elaborated upon.

author: Kleinstein
author_rank: Super Contributor
timestamp: May 06, 2024, 09:28:12 am
content: For the residual charge in the integrator it is likely not yet at the kTC limit and the reset noise would only apply for a reset of the integrator and not reading the charge with an auxiliary ADC. The noise is more from the amplifier(s) voltage noise that than translates to charge noise with the capacitance as factor.Reset noise or kTC noise can be relevant at the reference swiches, if the switches are at the integrator input (like the 4053 at the 34401). Here the switch part with it's capacitance in the 10 pF range is connected / disconnected to the integrator multiple times. With these switching events the kTC charge noise applies and adds to the noise - often not a major noise source, but it could with fast modulation and high capacitance switches.

author: NNNI
author_rank: Regular Contributor
timestamp: May 07, 2024, 09:11:54 pm
content: I have been reading up on different types of jitter , and I was wondering which kind of jitter would have the most effect on the noise/linearity of an integrating ADC, perhaps it is a mix of everything, with each kind of jitter having a certain effect (more noise, worse INL, etc.).:https://www.sitime.com/support/resource-library/application-notes/an10007-clock-jitter-definitions-and-measurement-methods#Phase-Jitter

author: Kleinstein
author_rank: Super Contributor
timestamp: May 07, 2024, 09:33:12 pm
content: The relevant jitter should be mainly for time intervals of some 1-10 µs. So a little more than just period jitter and still not really long time jitter. It is probably kind of a mix of the short and long pulse lengths in the run-up modulation. The point is how the PWM ratio changes from the nominal.In the frequency offset plot this would be a frequency offset of some 100 kHz - so not very close in, but also not period jitter.In most cases the actual oscillator should be less of an issue. A limiting factor could be the actual switch part. Here jitter specs are rare. The more precision type switches are usually slower than typical logic chips and thus more jitter is expected there. I selcted the 74LV4053 not just for low cost, but also for a good speed.

author: NNNI
author_rank: Regular Contributor
timestamp: May 08, 2024, 09:55:32 am
content: I wonder how a more modern switch with lower on resistance and charge injection will fare in that regard, such as the TMUX1133/4 . I don't know if there is an easy way to test for jitter in an analog switch.:https://www.ti.com/lit/ds/symlink/tmux1134.pdf?ts=1715116885492

author: Ecogeek
author_rank: Contributor
timestamp: May 08, 2024, 10:37:40 am
content: I've been researching the ADC in the HP Agilent 34401A the MUX switch HC4053 seems to be operated in the most non-linear slope of the Ron/V curve. I know operating into a virtual ground, gives the voltage around +/- 20mV, but the Ron slope still is very large and will impact on the voltage to be measured. The manufacturers vary in specifications quite a bit so device selection is important. You are correct the non-SOIC -16 packages that are now available TMUX4053 and your choice are significantly improved in Ron and linearity. I also do not understand why HP in the 34401A ground the VEE instead of connecting it to -5Volts giving the Ron Voltage close to the middle of VCC-VEE with the lowest Ron and lowest resistance slope?This is not to mention the high variation change in R between channels at the lower VCC-VEE voltage, and not to mention the resultant TC with varying channel Ron.Others with more knowledge may wish to add why the 4053 device seems to work so well in several legacy HP equipment when the device data shows it could be much better operating at a greater VCC-VEE range, and if it was possible to use some of the newer MUX would/should be exceptional?

author: Kleinstein
author_rank: Super Contributor
timestamp: May 08, 2024, 05:18:53 pm
content: The voltage at the switch is still relatively small and with a 5 V supply for the HC4053 the nonlinear part is not that bad. It still give a little U² contribution to the ADC result. The 34401 uses a rather low input current with 100 K at the input. I have tested the HC4053 in comparison. With 50 K input resistors the square part is barely visible. With more current (e.g. 20 K for a 10 V range) it gets significant.The main point helping is getting a lower R_on - here the LV4053 has about 1/3 the R_on and thus corresponding less (scales like (R_on/R_input)² ) nonlinear part.Speed wise the 74HC4053 and even more the LV4053 are quite good, compared to DG419 or similar, more analog oriented chips. This may well help with jitter.The lower voltage FET switches have usually a better ration of Ron to capacitance and often also higher speed.The TMUX1133 has very low R_on, but slightly higher capacitance. So these chips would want a smaller input resistor. One than has to watch out more for resistor self heating as a nonlinear effect.So they may be an option if a lower resistance is wanted (e.g. a smaller voltage range, like 5 V or for super low noise).I don't know why HP used no -5 V. A point here could be the charge injection: this is quite good near the negative supply. It could also be as simple as not having a -5 V supply and it may not be worth it. After all the MS3 in the 34401 is more designed for low cost, not for high performance.The resistance is usually quite high in the center of the range and the chage injection also changes with voltage.Testing jitter for the CMOS switches could be similar to logic gates, switch between 2 voltages. This would slightly different from just current steering, but close.I have seen slight variations in the ADC noise with different brands / types of 4053 switches (Cd4053, HC4053 (TI + ST), max4053 and LV4053). The LV4053 was on top with noise and Ron/linearity and the leakage was also good. It may not be the absolute best switch chip, but pretty good and cheap / easily available (even as DIP).

author: NNNI
author_rank: Regular Contributor
timestamp: May 08, 2024, 08:50:29 pm
content: I'm not quite sure if I understand exactly what causes the U2INL error. I was initially advised that it could be because of power coefficient of the reference resistors (and hence the quadratic shape). Is it the temperature coefficient of the analog switch that is much larger than that of a resistor network like the NOMC (which specifies +/-25ppm max. absolute tempco ) and therefore contributes more to the INL for a given current and power dissipation, or is another mechanism at play?I did some back-of-the-envelope calculations for the switch/resistor configuration I used in my latest design (10K NOMCT/TI SN74LV4053): (100/10K)2which is 100ppm, and that's approximately what I got as the peak of the ADC's INL quadratic curve.:https://www.vishay.com/docs/60007/nomc.pdf

author: Kleinstein
author_rank: Super Contributor
timestamp: May 08, 2024, 10:34:13 pm
content: A U² term comes from the nonlinear on-resistance of the CMOS switch for the input signal. As an approximation the voltage drop on the on resistance partially subtracts from the effective gate voltage. This makes R_on to go up with a positive input current and R_on go down with a negative input voltage. The voltage drop is small and thus a mainly linear effect on the resistance and thus linear effect on the gain (or actually 1/gain). A linear change in the gain gives a U² contribution. To get rough numbers one could look at how R_on changes with the supply voltage or the signal voltage.With 10 K of resistance with a LV4053 one would get quite some INL - at least with a 10 V full scale range and likely already at 5 V.The termal effect gives a U³ part. Here the change in the resistance is proportional to the power and this U². The added term to the result is thus 3rd power. As a thermal effect it is a delayed effect. It takes a few seconds for the resistor array to warm up. The relevant TC should not be the absolute TC, but the TC matching: the same change to the input and ref. resistors would cancel out. From my experiance the TC matching is often quite good (e.g. 1 ppm/K range) for the resistor arrays with an intermediate resistance (5 K to 100 K). The DS values seem to be for the whole range of resistors, with more effect of the bond wires for the lower value resistors.The switch on resistance has a high TC, but there is usually also matching between the input and the ref. channels. Also the switches are only a small part of the total resistance.

author: NNNI
author_rank: Regular Contributor
timestamp: May 09, 2024, 04:57:09 pm
content: As for the switch capacitance, I assume it would mostly affect the reference switching. The switching times are then limited to how quickly the switch common terminal charges up to Ron*Iref.

author: Kleinstein
author_rank: Super Contributor
timestamp: May 09, 2024, 07:50:14 pm
content: The capacitance at the input switch should not be that relevant, as it is not operated that often. Usually the swiches for the input and references are the same anyway to get compensation of R_on drift.The swiching times are usually longer than just Ron*C_switch. Chances are a large part is from the gate drive stage with a significant higher resistance. So it is more that internal stage to set the speed.R_on * C_switch woud be some 20 ohms * 10 pF = 200 ps, which is faster than the actual swiching speed.The speed on fast the ref. input node settles to the new voltage is also determined by the integrator - usually the integrator input is not a perfect virtual ground, but needs some time (e.g. 100-500 ns) for the integrator input to settle. The swich common node is also normally aready at R_on*Iref, as the same I_ref is flowing essentially all the time, just switching between the 2 paths. It is more typical to have a short break before make time in which the node can charge up even higher. The capacitance here limits how far the voltage spikes. A few ns time a fraction of 1 mA would be on the order of 1 pC of charge pulse, somewhat comparable to the swiches own charge injection.

author: NNNI
author_rank: Regular Contributor
timestamp: July 23, 2024, 12:33:13 pm
content: 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:Code: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 onn_pos - number of times the positive reference was turned onRUU - 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*RUDwhere:n_rundown_neg - number of 1/8 runup units the negative reference was turned onn_rundown_pos - number of 1/8 runup units the positive reference was turned onStep 3:N3 = residue_before - residue_afterwhere:residue_before - residue ADC reading before runupresidue_after - residue ADC reading after runupStep 4:FINAL = N1 + N2 + N3where:FINAL - final result, in units of residue ADC countsN1 - 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 LSBThe 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.

author: Kleinstein
author_rank: Super Contributor
timestamp: July 23, 2024, 01:38:26 pm
content: For the integrator compensation the divider between the 2 OP-amps is one part. The other part to adjust / trim is some RC series element to ground at the integrator input. This can help dampen ringing. The divider 10K/1 K may be a bit sluggish, not very fast, but should still be stable.With 4 K / 1 K one may be on the fast side with likely quite some ringing.For a first idea on the compensation one could at a simulation instead of real hardware. The question here is how well details of the OP-amp like output impedance are modeled.The scope picture still has quite same fast oscillation / ringing as background. This could be from the µC / a ground loop or a probing issue.The settling time for the integrator should be on the order of 500 ns to maybe 1 µs for the slow version.A timing resolution of only 1/8 if the 75 kHz run-up cycle looks low. I would have expected a modulation more like 1/32 or 31/32 for the lower frequency.

author: NNNI
author_rank: Regular Contributor
timestamp: July 23, 2024, 02:55:14 pm
content: Because I have already pretty much reached the limits of instruction memory, 1/32 and 31/32 would be very hard. However, 1/16 and 15/16 is certainly possible. What concerns me in the latter case is integrator settling. The fixed part at the start of the runup cycle is only (1/75kHz)*(1/16) = 833ns. I would have to make a lot of optimizations to the integrator to get it to settle in that time.The board already has a 100Ω/100pF (the values were an arbitrary choice and were not calculated/simulated when the board was designed) damping network at the summing junction. The spikes on the output of the first stage op-amps are not because of a probing issue - I had a similar suspicion, so I used the ground spring, but the spikes were still there.I've already simulated the configuration in LTspice, although I'm not sure to what extent I could trust the simulation. I've attached the .asc file if someone wants to take a look. You might need to download the OPAx140 SPICE model from the TI website and remove the unnecessary .inc statements.

author: NNNI
author_rank: Regular Contributor
timestamp: July 25, 2024, 08:53:31 am
content: I increased runup resolution to 1/16 and 15/16. That resulted in a smaller residue voltage after fast rundown, so I had to increase the gain of the scaling amplifier for the residue ADC, that gave me a boost in resolution.I also tried another runup scheme (see attached image, 'Runup 2') suggested to me by Jaromir. The fixed parts at the start and end of each cycle should have 0 current flowing into the integrator (apart from input current, and reference mismatch during the first constant part), because the references are on or off at the same time. The middle variable section depends on the comparator state. this method only causes a 0V to ±Iref step into the integrator, instead of the -Iref to +Iref step with the complementary PWM runup ('Runup 1' in the image).These changes resulted in a noise (with shorted inputs) of 1.87μVrms.

author: Kleinstein
author_rank: Super Contributor
timestamp: July 25, 2024, 09:38:48 am
content: The runup pattern 2 can have a slight added effect from the state of one reference effecting the way the integrator settles to the changing the other reference. For the transients it can make a small difference if the positive or negative reference is switched first. The effect may well be small enough to be not an issue. At least this adds up proportional to the signal and thus a more a gain effect to the run-up steps.A similar effect applies to the settling effect with short pulses in the 1st run-up scheme. This number of pulses scales with the signal and thus a similar possible effect.A setting with 1/16 and 15/16 would also effect the useful range at the input. This gives 14/16= 7/8 of the reference as usefull range. the 1/8 and 7/8 only allow for 6/8 = 3/4 of the reference range and thus may need a higher ref. or smaller resistors for the reference paths. At least it get hard to get +-10 V with a +-14 V reference.1.9 µV of RMS noise is not bad, but also not great.

author: iMo
author_rank: Super Contributor
timestamp: July 25, 2024, 09:43:51 am
content: Quote from: NNNI on July 25, 2024, 08:53:31 amAt which NPLC is the noise measured?Greetings to Jaromir

author: NNNI
author_rank: Regular Contributor
timestamp: July 25, 2024, 09:58:22 am
content: Apologies for not mentioning that, all measurements so far were done at 1 PLC.

author: iMo
author_rank: Super Contributor
timestamp: July 25, 2024, 10:03:04 am
content: Afaik Jaromir did 0.6uVrms with 10NPLC in his design in past.1.9uV/3 = the same, imho..PS: my 34401A does 0.7uVrms at 100NPLC (while measuring the ADR1001).

author: NNNI
author_rank: Regular Contributor
timestamp: July 25, 2024, 10:06:51 am
content: As Kleinstein mentioned, there is still some room for improvement.For example, I am not using flip-flops and an external crystal oscillator to 're-clock' the runup switch signals from the MCU yet, I am expecting a significant improvement after that change. The resistor network is still a 10kΩ NOMCT, so the reference currents are ±1.4mA. INL because of Ron modulation or PCR in this case will be rather large, that is yet to be tested. The integrator is also presented a significant dynamic load. Increasing the resistor network to 50kΩ should in theory reduce both problems and decrease noise (perhaps not as much) and reduce INL. The current board also uses an LM399, which I will be replacing with an ADR1399.

author: iMo
author_rank: Super Contributor
timestamp: July 25, 2024, 10:12:00 am
content: Yep, ADR1399 is 2x better than 399 noise-wise, also the switcher in your 2040 has to be eliminated. Try to power up the whole stuff off the batteries (not the external battery banks as they may contain a switcher too, but plain Nx18650 with linear Vregs)..

author: NNNI
author_rank: Regular Contributor
timestamp: July 25, 2024, 10:13:33 am
content: The switching regulator was the first thing to go, that has bitten me too many times now! The 3.3V rail is being powered by an LDO now, and the entire board from a bench power supply (which is, of course, linear).

author: iMo
author_rank: Super Contributor
timestamp: July 25, 2024, 10:18:27 am
content: Quote from: NNNI on July 25, 2024, 10:13:33 amBut the linear bench PSUs leak as wellTry with batteries (and put the batteries inside your cookie box as well).PS: Like 5+5 pieces of 18650 Li-Ion (+/-21V max) 4 lin Vregs. for +15V, -15V, with a tap at +8.4V for 5V and 3.3V I suppose..

author: Kleinstein
author_rank: Super Contributor
timestamp: July 25, 2024, 11:25:32 am
content: For the start the linear bench supply can be OK. The switcher at the RP2040 could add jitter and clock variations. Not sure how much, but an external clock could get rid of that and than the switcher may not be that bad. Still the expternal clock would want a stable supply too and not really the switcher.It would be mainly for later use that battery supply or a low leakage transformer / SMPS would be an issue. For the initial test the more normal supply should be OK.When doing a test with a short or the internal reference, the ref. noise is not that important. It gets an issue when reading an external voltage though.For the noise level the 34401 should be around 2 µV_RMS for 10 PLC. So getting a slightly better noise level with 1 PLC is not that bad.Still other modern meters like KS3446x are more closer to 1 µV.The clock could be part of the noise source due to the PLL, that may not be super low jitter.This is not just about jitter, but the clock at the µC could also get modulated depending on the signal and thus add INL errors. I have seen that with my AVR version gettting an INL error on the order of 20 ppm from that (an external clock fixed that). Even than small interference from the UART / µC internal ADC were detectable without an external flip flop.With a ref. current of 1.4 mA one could get low noise, but at the cost of extra INL errors. Increasing the resistor network for the integrator input to 50 K would add some noise ( ~ 300 nV RMS noise from the resistors, not much compared to 2 µV, but still the main principle noise sources).I consider 50 K a reasonable compromise among the available standard values.

author: iMo
author_rank: Super Contributor
timestamp: July 25, 2024, 12:56:51 pm
content: An anecdotal comment - I remember issues with the atmega1284 (a nice mcu, btw) where the adjacent serial RX and one of the crystal clock pins caused malfunction of the bootloaders when the oscillator was set for a lower swing mode (lower current). Setting the xtal oscillator to the high power mode cured the issue..Quote from: Kleinstein on July 25, 2024, 11:25:32 am

author: jaromir
author_rank: Unknown
timestamp: July 26, 2024, 07:18:35 am
content: Quote from: iMo on July 25, 2024, 10:03:04 amAttached is sample run of ~180 samples at 1PLC - that is not only ADC, but complete voltmeter with input amplifier, switching, overvoltage protection and related stuff. Standard deviation is ~700nV.Just for a good measure I attached INL sweep of my latest voltmeter creation.Sorry for digressing.

author: iMo
author_rank: Super Contributor
timestamp: July 26, 2024, 07:42:38 am
content: @Jaromir: Hi, thanks, so my memory was wrong!Your 700nVrms at 1NPLC means aprox 210nVrms at 10NPLC and 65nVrms at 100NPLC, am I right?

author: jaromir
author_rank: Unknown
timestamp: July 26, 2024, 08:18:08 am
content: At 10NPLC it is roughly like that (~200nV measured), 100NPLC is already in the region of quickly diminishing returns, due to the increasing influence of 1/f noise.For practical measurements I typically use autozero-ed 10PLC sampling (to get rid of the 1/f noise) and average of multiple samples instead of longer than 10PLC integration period. AFAIK this is common approach used in commercial meters.I would suggest discussing this or other aspects of my ADC in one of the multislope threads, or at our annual technology meeting in Kingstown.

author: iMo
author_rank: Super Contributor
timestamp: July 26, 2024, 08:27:46 am
content: Ok, thanks, I've just remembered the coef is aprox 3x when going 10x with NPLC.And sure, let us meet in the Rawacou Park pub before the Meeting..

author: Kleinstein
author_rank: Super Contributor
timestamp: July 26, 2024, 08:43:50 am
content: For the longer integration and especially with averaging it makes sense to look at the data with auto zero mode. This suppresses much of the 1/f noise, but adds factor of square root 2 to the white noise. For the data it abviously makes sense to note which case is used.The DMM front end may also add noise - that data for the DMMs are obviously for the complete meters and not just the ADC. The simple protection with 100 K ohms series resistance and a balancing 100 K in the zero link would add (add as squares of cause) some 300 nV RMS to 1 PLC Az mode.

author: NNNI
author_rank: Regular Contributor
timestamp: July 26, 2024, 09:02:21 am
content: I just did some INL runs, and the results are pretty interesting. I think the sawtooth like shape means that I got the calibration constants for the residue ADC wrong.My calibration scheme is as follows: Disconnect input from the integrator, turn on +ref for 1/16 of a runup cycle, measure residue difference to obtain a 'runup-down' (RUD) value, then turn on -ref for 1/16 of a runup cycle, measure difference to obtain a 'runup-up' (RUU) value, and use them in the formula I posted above.Update: there was an error in the runup math, INL after the fix is also posted.

author: Kleinstein
author_rank: Super Contributor
timestamp: July 26, 2024, 07:31:12 pm
content: Even with the fix the INL curve still looks not that great. The General parabola shape with the U² part is expected from the R_on modulation due to the rather high input current. The more local variations are what looks strange and not so good.The scale factor calibration with only a short pulse may not be very accurate. It includes the effect of 2 switching events that can add a bit extra charge injection. Ideally the pattern to test would be more like 2+x µs positive and 2-x µs of negative. With x of some 0.2 to 0.5. So the same pulse squence, just a little different pulse length. One would likely also need a few repeats and a way to make sure to stay inside the valid range: e.g. decide on which type of pulse to use depending on the charge to start with.There may also be a problem with the INL test or noise (e.g. ref. noise or drift). There is quite some difference between the different runs.

author: iMo
author_rank: Super Contributor
timestamp: August 09, 2024, 08:39:24 am
content: Quote from: iMo on April 29, 2024, 06:34:41 amThe new 2350 with 9.2b ENOB ADC and still only 32 instructions per PIO (with 4 SMs)..They enhanced the PIO's number (3 now) and PIOs functionality, however.Btw., I've searched through the 2350 datasheet, searching for "32 instructions" and "64 instructions" and found only a single info in the Fig.43..

author: diminddl
author_rank: Newbie
timestamp: August 11, 2024, 10:06:25 pm
content: Quote from: iMo on August 09, 2024, 08:39:24 amI believe the PIO architecture has a fixed 5 bit (32 value) program counter, all instructions expect this and I would imagine that re designing it from scratch didn't make much sense. PIO did get some other more subtle improvements that are nice. Also, since the new PIO IRQs can communicate between blocks you can pretty trivially harvest all the instructions in other blocks. Using the inter state machine IRQ flags you are looking at 96 instructions with a bit of overhead.

author: wanghar
author_rank: Contributor
timestamp: March 03, 2025, 02:51:36 am
content: @JaromirThe linearity measurements are very promissing and impressive. Appreciated if you could create a new thread updating the latest progress on ADCs and NVM project.