Shop OBEX P1 Docs P2 Docs Learn Events
ADC auto-calibration — Parallax Forums

ADC auto-calibration

I'm currently experimenting with the smartpin auto-calibration feature. I try to measure the phase currents of an AC motor as accurate as possible. I have 180MHz sysclock and programmed the ADCs to 8192 clocks period and SINC2 filtering mode. So I should get 14 bits resolution and ~22ksps.

I have three current sensors and 6 pins altogether. The stategy is to use a pin pair per sensor with one pin measuring the actual input voltage while the other is used for self-calibration measuring ground and VIO levels. The code looks quite ugly and is hardly readable because lots of ALTD/ALTS to handle indexing and source/destination switching. I use a table driven state machine to handle the switching.
DAT ' adc calibration state machine table
' bit#0 -> rewind
' bit#1 -> Ain source odd
' bit#2 -> Avg source odd
' bit#3 -> 256 instead of 4 samples
' bit#4 -> do calibration calculations 
' bit#5 -> avg = vio
' bits 16..15 -> mode0 VVV
' bits 18..17 -> mode1 VVV

adc_states	
  long	%00_11<<15 + %000000 ' swap channels, switch U1 to GIO
  long	%00_11<<15 + %001100 ' sample U0, average U1 GIO
  long	%01_11<<15 + %010000 ' switch U1 to VIO, calib GIO
  long	%01_11<<15 + %001100 ' sample U0, average U1 VIO
  long	%11_11<<15 + %110000 ' switch U1 to In, calib VIO
  long	%11_00<<15 + %000010 ' swap channels, switch U0 to GIO
  long	%11_00<<15 + %001010 ' sample U1, average U0 GIO
  long	%11_01<<15 + %010010 ' switch U0 to VIO, calib GIO
  long	%11_01<<15 + %001010 ' sample U1, average U0 VIO
  long	%11_11<<15 + %110011 ' switch U0 to In, calib VIO, rewind

' 			%AAAA_BBBB_FFF_PPPVVV_OHHHLLL_TT_MMMMM_0
'adc_mode	long	%0000_0000_000_100011_0000000_00_11000_0
'gio_mode	long	%0000_0000_000_100000_0000000_00_11000_0
'vio_mode	long	%0000_0000_000_100001_0000000_00_11000_0
{			%VVV = ADC config
			000: GIO, 1x (~5 volt range, centred on VIO/2)
			001: VIO, 1x       "
			010: PinB, 1x      "
			011: PinA, 1x      "
			100: PinA, 3.16x (~1.58 volt range, centred on VIO/2)
			101: PinA, 10x   (~0.5 volt range, centred on VIO/2)
			110: PinA, 31.6x (~0.158 volt range, centred on VIO/2)
			111: PinA, 100x  (~0.05 volt range, centred on VIO/2)
}
Every time I change the smartpin mode (signal source) I wait 4 samples before I actually use the results. Because each pin needs two calibration values (GND and VIO) and a gap for filter settling I need 5 states per pin or 10 states altogether.
Ground and VIO values are averaged over 256 samples. Offset and gain correction values are calculated and stored in another table (12 entries, gain+offset per pin).

Gain/Offset correction is done like this (simplified code without ALTD/S)
		mov	x,adcRaw
		sub	x,offset	' offset correction
		fges	x,#0
		mul	x,gain	' gain correction
		shr	x,#13
		fle	x,##$FFFF
		sub	x,##$8000	' 16 bits unsigned -> signed
		mov	result,x

The correction values are calculated like this:
		mov	x,avgSumG
		shr	adc,#8		' average = sum/256
		mov offset,x

		mov	x,avgSumV
		sub	x,avgSumG
		qfrac	#1<<5,x 	' 2^29/average(vio-gio)
		getqx	gain
The constant #1<<5 comes from the multiplication of all included resolutions (ADC 14 bits, result 15 bits, average sum 8 bits = 37 bits) and the shifting of 32 bits of qfrac vs. qdiv.
«1

Comments

  • The whole thing seems to work, at least to some degree. If I dump the raw ADC values of the individual states I get something like this:
    Pin	U0	U1	V0	V1	W0	W1
    GIO	$0B25	$09D1	$09E3	$0AAC	$0B27	$0A2B
    VIO	$3534	$347D	$3428	$34BA	$355F	$3505
    Sensor	$209A	$1F87	$1F9B	$2046	$2094	$1FF5
    Gain	$C2C6	$BFFA	$C1CD	$C2CB	$C209	$BF2B
    
    The sensor value is the ADC input at idle state (no motor current) and includes some extra offset (from the sensor independant of the ADC offset). The output looks imperfect but at least credible.

    However, I've noticed that I don't get the same results when I short the inputs to GND or VIO with a jumper wire. The ADC readings are always around 1% higher than the internally switched GIO and VIO readings. I wonder if there is some bias current or offset voltage in my circuit or if the switches internal to the P2 are leaking a bit. It could also be that my code is still buggy and suffers from "cross-talk" between internal variables (4 sample settle time doesn't work or averages are not cleared correctly...)

    If I look at the corrected samples I get fairly stable values for pin pair V0/V1 which has relatively well matched gain and quite a lot of ripple for the other pin pairs.

    Has anybody else tried this out and has some experience what accuracy can be expected? If there is little temperature drift maybe it would be better to only do a static offset adjustment once at startup and quit the continous "chopper stabilisastion" .
  • BTW, you may ask why I measure all three phase currents instead of only two which is common practice in motor control applications. I know, the third phase could be calculated as W = -(U + V) according to the node rule (sum of all currents to and from the star joint is zero). But if you do so you get doubled noise and doubled (worst case) offset error for the third phase.

    On most microprocessors ADC inputs are expensive but not on the P2. So I decided to measure all three phase currents at least in the prototype. I could always ignore the third to compare if it makes a difference. If not I could leave out the third sensor in the production version later (and save the current sensor which IS expensive).
  • ErNaErNa Posts: 1,752
    It definitely makes sense to measure all three currents, as the error introduced is smaller (average), leak currents can be detected and as the single phases vary periodically, the highest current always is measured with highest precision and contributes most to torque ( at least: a simplistic view )
  • cgraceycgracey Posts: 14,206
    Remember that the SINC2 mode is incorporating data from the prior sample and the prior-prior sample. When you switch sources (pin/GIO/VIO), only on the third reading will you get a value that is from nothing but the new source.
  • Yes, I planned it that way. Because I don't know exactly when the switch over happens I even give it 4 samples to settle. However I haven't debugged it carefully enough so I could guarantee that this is acually working as expected.
  • Now I have recorded all samples and calculation results of one channel of 2 pins over one full cycle of the state machine. I have reduced the averaging from 256 to 16 samples to make the listing shorter.

    We can see that the input switching works as expected and the ADC is allowed 4 sample times to settle to the new source. The value stabilizes after the 3rd sample. The calculated offset and gain values also look plausible.
  • ManAtWorkManAtWork Posts: 2,178
    edited 2020-02-26 09:47
    We can see that there is no crosstalk between the pins. If there was we should se a change on pin U0 when pin U1 switches from GIO to VIO, for example. There might be some capacitive coupling (silicon rev B ) but it's lost in the noise as sampling time is 8192 clocks and quite long.

    However, there is a small step in the result when switching over from pin U0 to U1. This level change remains there even after some cycles of calibration and shows up as ripple in the signal. This might be caused by a changing bias current fed into the source impedance (~2k ohm) of the sensor. I'll check if it is reduced when I connect a source with nearly zero impedance.
  • The ripple has around $40/$8000 or 0.2% full scale amplitude, not 1% as I said earlier (the final result has 16 bits instead of 14). It stays the same for both the actual sensor signal and the low imedance 1.8V supply.

    In terms of acccuracy this is fully tolerable. However, a square wave of 40mA (20A full scale) and ~250Hz (88 samples state machine cycle) would produce a hearable sound and should be avoided.
  • Now that my software scope is working I have some visible waveforms instead of only hexdumps. The picture shows actual motor current while a sine wave PWM pattern is applied. Scaling is 0.2ms/div horizontal and 0.1A/div vertical. The distortion of the sine wave is caused by mechanical/magnetical cogging of the rotor. However, there's a clearly visible "interference" square wave mixed to the actual signal which is not caused by the PWM switching. Samples are taken synchronously to the PWM cycle so the ripple caused by the PWM itself can't be visible.

    The amplitude is around 50mA peak-peak. The state machine that schedules the automatic ADC calibration changes the input pin aprox. every 2ms. The active input pin samples the sensor signal while the other is used in the background to measure GND and VIO levels. So in theory offset and gain errors of the ADC circuits inside the chip should be compensated. However, it seems that the rsistance of the analogue switches are not perfectly matched or there are bias or leakage currents that are dependent on the selected signal source. (if they were constant they should be cancelled out by auto-calibration)

    I have 3 current sensors and 3 ADC pin pairs which all behave nearly the same. Theres a remarkably differing offset and gain error in the raw data for each pin. But the ripple in the compensated data is 40..60mA peak-peak for all 3 pairs.
    537 x 547 - 6K
  • So the superimposed square wave seems to be about 580 Hz, does that correspond to anything such as a rpm?

    Which pin numbers are being used for the pairs? Are the 3 pairs contiguous, or could there be something digital in between the pairs (i ask because we saw a small offset when doing dac testing due to the current drawn by the pin pad block itself)

    Have you checked the VIO voltage at a pin to see whether it also has any of that 580 Hz present?

    When I did testing on each ADC channel I did see quite a different offset per pin, however I did not see the difference in gain error that you report

  • evanhevanh Posts: 16,023
    edited 2020-05-06 04:50
    ManAtWork wrote: »
    We can see that there is no crosstalk between the pins. If there was we should se a change on pin U0 when pin U1 switches from GIO to VIO, for example. There might be some capacitive coupling (silicon rev B ) but it's lost in the noise as sampling time is 8192 clocks and quite long.
    The problem crosstalk area, between pin pairs (RevA/B), is located in front of the analogue mux. So switching to GIO or VIO won't meassurably change the crosstalk loading on the other pin.

    However, there is a small step in the result when switching over from pin U0 to U1. This level change remains there even after some cycles of calibration and shows up as ripple in the signal. This might be caused by a changing bias current fed into the source impedance (~2k ohm) of the sensor. I'll check if it is reduced when I connect a source with nearly zero impedance.
    Is this the interfering square wave in your latest report. ie: When switching between two pins?

  • Sorry, the horizontal scale was wrong, it's 1ms/div actually, not 0.2ms. And the timing is not exact, I record 256 samples per full screen (10 raster units) where I actually should record 220 (22kHz sampling rate). So the waveform is slightly "compressed". The frequency of the square wave is 250Hz (1 cycle per 4ms).

    From the debug hexdumps I can see that there is a step in the signal exactly the moment the input pin is switched. The U sensor signal is connected to P44 to P47 (pins 71 to 75), V to P48 to P51 and W to P52 to P55. Each sensor is connected to 4 pins alltogether. I use two pins for ADC and two pins for fast overcurrent detection (DAC compare mode, not implemented yet).

    The VIO for the ADC pins is fed from an extra linear voltage regulator connected to pins 73, 79, 85 and 91 to minimize digital noise. Scematic and layout can be viewed in this thread.

    The RevA/B crosstalk issue shouldn't matter in this case when both pins of a pair are connected to the same signal. I'll check if I can measure any traces of the square wave at the physical pins with a real scope.
  • And BTW, I've already checked that the superimposed square wave has nothing to do with the source impedance. It stays there when I short the ADC input node to the 1.8V supply of the P2 core voltage. And I also have checked that it's not a aliasing/subsampling effect caused by asynchronous sampling vs. PWM frequency. My control loop code outputs one data packet per loop pass to the PWM slave processor on the HV side and takes one ADC sample per loop pass. I can see with the (real) scope that the data transmission and PWM switching are perfectly phase locked.

    And again, I don't complain about missing precision. We are talking about an error of 40mA at a full input scale of 40A (+/-20A). Thats 0.1%. Most other microprocessors are limited to 12bit ADC resolution and have much worse gain and offset error specs. It's just an inconvenience because it causes audible ringing as soon as the control loop is closed. So I have to "iron it out" somehow.
  • evanhevanh Posts: 16,023
    ManAtWork wrote: »
    From the debug hexdumps I can see that there is a step in the signal exactly the moment the input pin is switched. The U sensor signal is connected to P44 to P47 (pins 71 to 75), V to P48 to P51 and W to P52 to P55. Each sensor is connected to 4 pins alltogether.
    That's darn good then. I'd guess than flipping input sources like that is going to be very hard to null out all differences in DC offset. Why are doing that in the first place?

  • I'm not sure if I understand the question. The alternatives to flipping input pins would be:
    1) doing no GIO/VIO calibration at all
    This would mean I could only implement a static offset compensation. I can measure the ADC input before enabling the power stage so that I know that the motor current is zero. Once the motor runs there would be no chance to measure the offset again so this couldn't compensate temperature drift. Also, I couldn't do any gain error compensation. Matched gain errors of all 3 channels wouldn't matter at all. The velocity control loop cancels out all inaccuracies of the current control loop as long as they are below 20 or 30%. But unbalanced gain errors between winding currents cause cogging.

    2) time multiplexed GIO/VIO calibration with only one pin per sensor
    As the sigma delta ADC requires 3 samples to settle after an input change this would require significantly long time slots where I can't sample the actual signal. I'd need 6-times oversampling and loose at least 2 bits of resolution.

    3) using external ADCs with better precision
    This not only costs money and board space. I'd like to do a performance benchmark to see what is possible with the P2.
  • evanhevanh Posts: 16,023
    ManAtWork wrote: »
    2) time multiplexed GIO/VIO calibration with only one pin per sensor
    As the sigma delta ADC requires 3 samples to settle after an input change this would require significantly long time slots where I can't sample the actual signal. I'd need 6-times oversampling and loose at least 2 bits of resolution.
    Ah, that's the why.

  • evanhevanh Posts: 16,023
    One way it might improve on what you've got, while still using the prop2's ADCs, is by doing a one-off span calibration at the beginning and then raw sampling non-stop from one pin and relying on the paired pin for supplying all the GIO/VIO relative variations. Particularly compensating thermal drift. This compensation I'm expecting to be heavily low-pass filtered so it won't be fast acting.

    You'll probably lose some accuracy against your current solution but you get to eliminate those teeth.

    PS: It is just wild guessing from this end, btw. I've not done much with the ADCs.

  • Yes, could work but requires some experiments and especially requires more propeller chips to test. I'm not feeling good assuming that the thermal drift of two adjacent pins does always match even if I know that they do on one particular chip. It might be the same on other chips but you can't be sure.

    For the moment I'd rather try sticking to the flip-pin method and doing a statical delta-offset compensation, i.e. measuring the amplitude of the "ghost" square wave once at startup and synchronously subtracting it from the signal. This has much more complexity than your simple approach but the worst case is not much worse than the 0,1% error, now.

    Uncalibrated error is really high, something like 10% full scale. If the drift of adjacent pins differs by only 10% then it would still mean 1% error which is ten times the current error with calibrartion.
  • cgraceycgracey Posts: 14,206
    edited 2020-05-07 07:04
    ManAtWork, are you sure that superimposed noise is not coming from the even-odd companion pin? On the new silicon which is coming in, we no longer have the adjacent pin measurement mode, since the resistor was disconnected. This stops crosstalk between pins. One thing you can do on Rev B silicon is to tie the same signal into a pin pair, together. This way, there is no crosstalk, as there is only one signal going into the pin pair.
  • That was my thought at first too Chip, but ManAtWork says above they are connecting the same signal to all four pins, using two for ADC, plus two for fast Pin A>D comparator alarm
  • Hello Chip, good that you are here. I'd like to hear your professional opinion...

    Yes I'm sure that the RevB crosstalk problem has nothing to do with this phenomenon.
    The U sensor signal is connected to P44 to P47 (pins 71 to 75), V to P48 to P51 and W to P52 to P55. Each sensor is connected to 4 pins alltogether. I use two pins for ADC and two pins for fast overcurrent detection (DAC compare mode, not implemented yet). The VIO for the ADC pins is fed from an extra linear voltage regulator connected to pins 73, 79, 85 and 91 to minimize digital noise. Schematic and layout can be viewed in this thread.
    The waveform I posted was recorded using P44/P45 (pins 71/72).

    But I remeber that you said that something is on your to-do list for the next silicon revision about the ADC input multiplexers. I don't remeber exactly what it was and I can't find the post at the moment. It had something to do with placing the muxes before or behind some resistors to improve accuracy.

    Never mind... But the question is, could it be possible that the GIO/VIO modes have enough tolerance from pin to pin that it explains the staircase-effect I'm seeing? Or in other words, what accuracy (gain and offset error, pin-to-pin matching) can I expect when using auto-calibration? Is that 0.1% tolerance inside the usual design margin?
  • evanhevanh Posts: 16,023
    ManAtWork wrote: »
    But I remeber that you said that something is on your to-do list for the next silicon revision about the ADC input multiplexers. I don't remeber exactly what it was and I can't find the post at the moment. It had something to do with placing the muxes before or behind some resistors to improve accuracy.
    There wasn't any plan to make that change - because of cost. Chip just said it would have been the better way in hindsight. Any to-do's of that costly a change will depend on good sales of what we have now.
  • Yes, I'm fully aware that any change to the hardware is very expensive and will probably never happen. I just mentioned it because it was the only thing I remembered. Chip knows best how the P2 works internally. So if he says "this could be a logical consequence of *** (insert some magic word here like "unbalanced leakage currents", "unobtanium quantum effects" or anything else outside my knowledge) then I at least know that it makes no sense to search for other reasons. And I hope I'll get a hint of how to make the best possible workaround in software.
  • evanhevanh Posts: 16,023
    Didn't sound like you fully understood when saying "next silicon revision". Which could even be taken to mean Rev C.

  • evanhevanh Posts: 16,023
    I'm not sure anyone has done things better than you have. There was some ADC data gathered early on but nothing completed. Here's something I just bumped into - https://forums.parallax.com/discussion/169269/accurate-dac-reference-data-voltages-from-p2-silicon

  • cgraceycgracey Posts: 14,206
    edited 2020-05-07 13:17
    Well, you can't use GIO and VIO calibration values from one pin on another. Every pin is different and must be calibrated to itself.

    I'm not sure if that applies in this case, but it would explain staircase steps that are correlated with calibrations.
  • Chip, of course, each pin is calibrated seperately. (see post #1 and #2) Using the VIO/GIO samples to calibrate a different pin was a suggestion of Evanh (in this post). I don't think that's a good idea either.

    I can show some hexdumps that show the actual samples of each pin and how my code uses them to calculate the calibration values for offset and gain. I could even write a demonstration program that runs on an EVAL board without my special hardware if necessary.

    Again, could you please answer my question: Do you think it is possible that the 0.1% steps could be explained by some effect inside the P2 chip or do you believe my code is faulty?
  • On the ADC front RJSM did some good testing looking at the variation of ENOB by pin number, see this thread.
    https://forums.parallax.com/discussion/169602/characterizing-p2-eval-analog-performance

    ManAtWork I just wanted to check your maths on the bits vs sampling rate, if you're at 180 MHz and 22ksps that'd be 13 bits which is 8192 count, rather than 14 bits, or are you claiming 14 bits because of using paired pins?

    There is also an ADC Noise thread where we look at how GIO and VIO calibration values vary with respect to both temperature (induced self heating by clock rate) and by pin number and board number. I compared my board with OzProp's to get some idea of the variation from chip to chip (at least for a sample size of 2). Evanh plotted the results nicely
    https://forums.parallax.com/discussion/download/124010/20-300%20Mhz%20%2859%20pins%29A.png

    I don't currently have an explanation for why you'd see a ~120Hz square wave like you are, but would suggest trying a simpler (non SINC) approach to recording the data to see whether the interference is still present. Eg let P44 and P45 record your Sinc data acquisition, as you have it now, but put simpler 14 bit VIO - Vinput - GIO - Vinput sequence measuring on P46 and see how closely it corresponds with your state machine + sinc approach. I'd also try connecting a plain old battery to rule out "everything else" (I know you've already connected 1v8 rail but that could also be contributing to the square wave)

    Soon we will have a lot more chips and can do some chip-to-chip comparisons across the batch

    We'll find this gremlin...

  • ManAtWork wrote: »
    I can show some hexdumps that show the actual samples of each pin and how my code uses them to calculate the calibration values for offset and gain.

    I just recalled that I've already done that. Please see my post from Feb 26th. (XLS attached)

    Explanation of data columns:
    state = bit pattern encoding for state machine
    raw U0 = raw data from ADC pin P44, 14 bit SINC2 filtering
    raw U1 = raw data from ADC pin P45
    avg = sum for averaging of calibration value
    offsU0 = offset for P44
    gainU0 = gain for P44
    offsU1 = offset for P45
    gainU1 = gain for P45
    result = calibrated output data

    Motor current is 0.0A
    offset in output is caused by offset voltage of current sensor


  • Ok I did look at the spreadsheet but didn't realise there were two different measurement methods there.
    Is each row of the spreadsheet a finite time, eg 1 adc sample?
Sign In or Register to comment.