Shop OBEX P1 Docs P2 Docs Learn Events
Increasing ADC Stability by Design or Filtering — Parallax Forums

Increasing ADC Stability by Design or Filtering

Sparks-R-FunSparks-R-Fun Posts: 388
edited 2007-06-19 01:51 in General Discussion
I am designing a SX28 based device to interface with an existing machine. Among other things, the machine applies a 10 VDC signal to a 10K pot and uses the variable voltage output to control the speed of a motor.

It is not possible (within the confines of the project) to monitor the speed of the motor directly. (I already considered that.) Yet I need to display the motor speed (more accurately I need to display the value of the signal applied to the motor speed controller) as a number between 0.0 and 8.0. Basically I need to sample a 0-10V DC signal and quantize it to 81 discrete values.

To accomplish this I am using a continuous-bit-stream sigma-delta ADC ISR that seems to function as designed. However, its output is not as stable as I require. The raw numbers jump around quite a bit. I am oversampling by eight times, which helps... but not enough.

The final display value should not change at all unless the user physically adjusts the pot. For example, it is not acceptable to have the displayed value alternate between two values then the pot is stationary as is happening now. I need it to pick a value to display and stay with that value. It needs to have some kind of hysteresis and probably some filtering as well. This is where I desire assistance.

I am looking for help, ideas, things to try and references to informative documentation that might help me create a more stable display. I have checked the execution frequency of my ISR and the stability of the input signal. Both appear to be free of any obvious glitches.

I suspect that I may need to "tune" my analog circuit (a 1.5K and 4.7K resistor plus a 1uF capacitor being sampled to twelve bits at 14.4KHz) or apply some digital filtering to the raw values.

I am hoping someone can either provide some pointers or ask the right questions so that I can improve my existing system which so far is just not stable enough for it to settle upon a single value when the input is not changing.

Can anyone help me to better understand how to improve this?

- Sparks
«1

Comments

  • pjvpjv Posts: 1,903
    edited 2007-05-30 03:28
    Hi Sparks;

    You should be able to get a stable reading with only 81 quantization levels. Possibly your ISR might not be as stable as you think, or the same for your power supply. Twelve bits is do-able, but you only need 7 or 8 bits. I have used a digital filter technique to smooth out 12 and 14 bit readings from temperature sensing RTD's, and got things stable to a few dozen microvolts. So it IS possible, but you should not require that level of performance.

    Do realize that if the sensed voltage is right on the edge of a quantization step, then it might bounce back and forth that one count, as it should. But if that is objectionable, then a little DSP work on the numbe can take care of that.

    If you would post yor code, then we might eliminate the the ISR timing issues. Also possibly a schematic...... personally I would opt for resistors much larger than the ones you specified, and a capacitor much smaller.

    Cheers,

    Peter (pjv)
  • metron9metron9 Posts: 1,100
    edited 2007-05-30 15:34
    Instead of using fixed quantization levels you can adjust the quantization while you read the ADC. This will prevent the edge problem pjv writes about in the previous post.

    I would test the data from the circuit using the ADC for minimum and maximum values over a period of time for each voltage level. this will help you define the initial quantization parameters, from there the high and low will move in tandem up and down the scale. Additionally you could make the quantization flexible for noisy conditions, throwing out data that comes in way out of bounds during your averaging loop when reading the ADC.

    It is important to understand how people may move the POT as well. One project my brother in law worked on for a medical device had a POT that had no stop on either side, you just keep turning it right or left. (there must be a name for these pots) anyway they found out the users were spinning the knob so fast their algorithm for reading the direction of the pot did not work as it might read 10 then 100 then 360 must be going up, but if spun very fast it might actually be going backwards (left) and just being read at 10 100 and 360. Not sure what solution they came up with but I think it was a label "DO NOT SPIN KNOB FAST!" or something to that effect.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Think Inside the box first and if that doesn't work..
    Re-arrange what's inside the box then...
    Think outside the BOX!
  • Tracy AllenTracy Allen Posts: 6,657
    edited 2007-05-30 17:27
    Is the sigma-delta circuit constructed right next to the pins of the SX chip? That is, the integration capacitor and the input and feedback resistors. Parasitics can really rough up the results. I agree with Peter about the values: (1.5K and 4.7K resistor plus a 1uF capacitor). Those seem too low for the R's and too high for the C, especially when reading a voltage off a 10kohm potentiometer.

    Is is possible there is motor noise or AC hum being induced in the wire that comes from the potentiometer wire to the ADC? If so, it may need to be shielded. For 60 or 50 hz rejection, the ADC can be set to integrate in multiples of the AC line period. A lowpass filter or window average might help some to slow down the bobbling. There is going to be a tradeoff between stability and speed of response as the user turns the dial.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Tracy Allen
    www.emesystems.com
  • Sparks-R-FunSparks-R-Fun Posts: 388
    edited 2007-05-30 17:47
    Unfortunately I have very little experience with analog to digital conversion techniques. So I do not have a good sense of what kind of results I should expect to see. I have been trying to read about the subject. I expect that a very accurate ADC might dither about its least significant bit. I also expected that I might have to drop the two smallest bits or maybe the least three... but I am dropping four now and it is still just not stable. I must be doing something wrong but I need help figuring out what it is.

    Here is the code I am using for my continuous bitstream ADC. It is the very first thing that runs in my interrupt routine in order to keep the timing and thus the result as accurate as possible.
    
        '----------------------
        ' Take an Analog Sample
        '----------------------
    
        OutPin = ~InPin                                    ' Toggle the Output Pin.
    
        If InPin = 1 Then                                ' Check for a High value.
            Inc AnalogTempValue                            ' Increment the Temporary Value.
            
            If AnalogTempValue = 0 Then                    ' Check for value rollover.
                Inc AnalogHiRezTempValue                ' Increment the rollover value.
            EndIf
        EndIf
    
        DJNZ AnalogSampleCount, DoneSampling            ' Check for Count rollever.
            DJNZ AnalogHiRezCount, DoneSampling            ' Check for extra counts completion.
    
                AnalogHiRezCount = 15                    ' Set for an additional four bits.
    
                AnalogTempValue = AnalogTempValue SHR 4    ' Drop the four lowest bits
                AnalogHiRezTempValue = AnalogHiRezTempValue SHL 4        ' Adjust the four highest bits
                AnalogValue = AnalogTempValue + AnalogHiRezTempValue    ' Update the Analog Value
    
                AnalogTempValue = 0                ' Clear the Analog sample Value.
                AnalogHiRezTempValue = 0        ' Clear the oversampled Analog sample Value.
    
    DoneSampling:
        '----------------------
    
    


    I have experimented with different resistor and capacitor combinations but may not understand enough of the theory of operation to pick better values. I did read that a larger capacitor tends to yield more stable results at the expense of a longer sampling time. That is why I am presently using a 1uF capacitor instead of something smaller. Would a 0.01uF capacitor be better?

    It is my understanding that a smaller capacitor would need to be sampled more quickly. (This is not a problem but is also not something required by the design.) I did try some smaller values and to a point saw no noticeable difference. The larger capacitor does take longer to reach the steady state voltage. However, once it is there, it pretty much stays there since the interrupt routine strives to keep the same voltage on a continual basis. What would I gain by using a smaller capacitor?

    I agree in thinking that higher value resistors should theoretically be better. I tried some higher ones but they did not work well. I think I lost some of the range or resolution over the run of the pot. Any ideas on what I should use?

    I have attached a schematic of the ADC portion.


    Thanks for the help be it generic or specific.

    - Sparks
    441 x 300 - 5K
  • Sparks-R-FunSparks-R-Fun Posts: 388
    edited 2007-05-30 18:05
    Tracy,

    My sigma-delta circuit is near the SX pins. It is currently on a breadboard and only about a half inch away. There is no motor noise nearby (Yet!). When finished it will be housed in a metal industrial panel sealed to withstand washdown. I am hoping that will shield it sufficiently from nearby motors.

    There are florescent lights about six feet overhead and being on a large breadboard some of the connecting wires are six to fifteen inches in length, especially for off-board connections. They are probably making great aerials! And now that you bring it to my attention, I wonder if being only seven inches from a PC with an open case might be contributing to my poor readings. sad.gif

    I will try to better shield my circuit from RFI and see if that improves the situation.

    Thanks for the idea!

    - Sparks
  • BeanBean Posts: 8,129
    edited 2007-05-30 18:37
    Sparks,

    I would just use the SX/B "ANALOGIN" command. It's tricky to get all the paths the same length and the ANALOGIN command does it for you. And you don't put it in an interrupt routine, it "primes" the capacitor, I've used it on several projects and it works pretty well.

    Your 1.5K and 470 ohm resistors seems really small. I would try a smaller cap value and larger resistor values.

    Bean.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    “The United States is a nation of laws -· poorly written and randomly enforced.” - Frank Zappa

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    www.hittconsulting.com


    Post Edited (Bean (Hitt Consulting)) : 5/30/2007 6:45:45 PM GMT
  • Sparks-R-FunSparks-R-Fun Posts: 388
    edited 2007-05-30 19:24
    Thanks for the document, Bean. I am quite familiar with it. It served as my primary starting point! So maybe I must go back to the beginning.

    I tried to take what you were doing with the ANALOGIN command and perform the same steps in my ISR. Later I read some additional documents that lead me to believe I could increase the resolution simply by sampling more bits. I tried that but it does not seem to have helped sufficiently. I left out the priming step since my understanding is that by running continuously in an ISR it would self prime and stay primed.

    The reason I tried to write my own analog input function is that I need to have a background UART running. (I think I am using your code for that as well.) Additional data to be displayed is being received serially.

    Actually, if you string together several of my past questions you may see that I have been working on this project on and off for several months. I had the analog input working as far as increasing and decreasing in response to voltage changes. After that I moved on to accomplish other things. Now that I am trying to display the returned values the jitter I am seeing is driving me crazy!

    I do not know if I have a logic error, unexpected noise in the system or poor circuit design that is causing my problem

    How much noise, jitter or numerical variation should I expect to see on a 8-bit sample using this method?

    I just might return to the ANALOGIN command in an attempt to isolate my circuit from my software.

    Thank you for the help.

    - Sparks
  • pjvpjv Posts: 1,903
    edited 2007-05-30 19:59
    Hello Sparks;

    A couple of observations:

    Firstly, breadboards can be a great attractor for noise.... so who knows what impact that is having; but probably not good.

    Secondly, your schematic indicates a 470 ohm charging resistor, whereas your words speak about 4K7 ohms. If indeed the value is 470 ohms, and the sampling interval is 14.4 KHz, or 70 uSec, then in one sample the voltage on the capacitor will rise or fall by about 350 mVolts. That is approximately one fifteenth of the whole 5 Volt supply range of the SX, and hence a quantization of only 15 (approx) steps. So only 4 bits can be resolved; never mind 12 or 14. The bit readings beyond 4 will be relatively meaningless.

    On the other hand, if the resistor were 4K7 as you stated, then the quantization steps at 70 uSec get to be about 10 times as small, say 35 mV. In a range of 5 volts SX supply that means about 143 steps.... about 7.5 bits. Again, the "extra" bits you are counting are not meaningful.

    As a rule of thumb (not exact), I suggest that the charge/discharge RC time constant wants to be equal to the sample time multiplied by the number of steps in the desired bit resolution. So at 70 uSec samples and 8 bits (256 steps) results in 70 * 256 = 18 mSec. Using your 1 uF capacitor (not a leaky electrolytic I hope), you should use an 18K value for R2.

    Resistor R1 in your schematic will set the input range. So, since the ADC C-MOS switching threshold sits at 2.5 volts for a 5 Volt supply, and that is represented by resistor R2 at 18K, then the value for R1 should be the maximum input of 8 Volts divided by the 2.5 threshold Volts times R1. That calculates to 8 / 2.5*18 = 58 K.

    Actually, a 58 K load on a 10 K source pot is a fairly heavy load (about 10%), and will yield considerable non-linearity as the pot is dialed. Better to have the load resistor 100 times the source resistance, so I would prefer to scale the calculated values up by a factor of 10. That will then also permit reducing the 1 uF capacitor by a factor of 10, yet keeping the same time constant.

    The actual input range of the calculated values will be approximately 7.5 volts to minus 2.5 Volts for a 5 Volt supply.

    Try it; I think you'll find that it works.

    Cheers,

    Peter (pjv)
  • Sparks-R-FunSparks-R-Fun Posts: 388
    edited 2007-05-30 21:17
    Wow! Ok. Yes.

    There is so much to consider. This is the help I was hoping to receive though.

    Can anyone point me to a good reference on the topic? pjv how to you know this stuff?

    First, let me offer some updates and clarifications. The case is now back on the PC without yielding any noticeable improvement. However it does have a huge Plexiglas window in the side so that might not be stopping any RF leaks.

    I originally had a 4.7k resistor in place as there were higher resistors in use originally. The 4.7K and the 1.5K positions were also likely reversed so that R1 was always about three times larger than R2 . At some point I thought I was getting a better range of numbers with lower values. (I did not have a good way to tune this circuit.)

    I also doubled my ISR rate and then just ran my UART and clock tick subroutines on every other interrupt. The ADC gets serviced first on each interrupt with constant timing. My interrupt period was measured to be 34.5uS

    pjv, if you are correct (and by reputation you really know your stuff) then you have easily explained why I seem to be receiving junk. I am curious to know more about how to calculate those values!
    pjv said...
    ...in one sample the voltage on the capacitor will rise or fall by about 350 mVolts.
    pjv said...
    ...hence a quantization of only 15 (approx) steps...
    Hmmm... So I should not let the voltage change over one sample period any more than I expect to be able to report that change. Ok, ok... I know I am going to sound really dumb but I thought that it was more of a statistics problem as in the more times you sample the signal (let's assume it is not changing) the more accurately you can claim to know its value. I thought counting up more bits gave me better accuracy simply because I had more points of comparison. Yikes!
    pjv said...
    Using your 1 uF capacitor (not a leaky electrolytic I hope)...
    *GULP* It was not at the time the you wrote that. I am sure I had one in there previously. Do they really leak that much?
    pjv said...
    ...a 58 K load on a 10 K source pot is a fairly heavy load (about 10%), and will yield considerable non-linearity...
    I was aware of this but not sure now to get around it as higher resistance was definitely producing more disappointing results.

    I will reread your post some more and try your suggestions. One thing that is still not clear to me, though I suspect it has something to due with the RC time constant, is why a smaller capacitor is better.

    I will let you know if I am able to get more stable readings. It sounds like I have been way off!

    Thank you for your help.

    - Sparks
  • Tracy AllenTracy Allen Posts: 6,657
    edited 2007-05-31 03:39
    It definitely seems that the component values need to be reconsidered before issues of noise pickup.

    If this ADC is built on one of those white plugin breadboards, well, that is really not recommended for this kind of circuit. There are so many uncontrolled capacitances and inductances. It is best if you can built it dead bug style, by soldering R1, R2 and C right to the pins of the SX chip, very short leads, or at least build up the circuit on perf board. The effects of the breadboard and parasitics become greater as the resistor values are increased. By the way, how fast is your ISR update? Faster too means more effect of parasitics.

    Another capacitor on the side of R1 by the wiper of the potentiometer, for extra filtering.

    I'm going to disagree with Peter a tiny bit about the value of R1, just the math, not the conclusions. Suppose R2 is chosen to be 18 kohms. When the top end of R1 is at +8.0 volts, the feedback must be be able to pull the RB.3 input down to the 2.5 volt threshold. That is as low as it can go, output RB.2 100% at Vss. That makes a voltage divider:

    Vin * {R2 / (R1 + R2)} = Vthreshold

    and with R2=18k and Vthreshold=2.5 volts,

    8.0 * {18 / (R1 + 18)} = 2.5

    Solve for R1 and you get:

    R1 = (Vin - Vthreshold) * R2 / Vthreshold
    . = (8 - 2.5) * 18 / 2.5
    . = 39.6 kohms

    If R1 is made larger, like 58k, the actual range will be larger than 8 volts, which is a good idea, because you don't want the converter to saturate at 100% duty cycle at either Vss or Vdd.

    With R1 = 58kohm resistor, you can solve for the maximum Vin. There is really nothing too mysterious about this. It is a DC analysis. No time factors involved. Nothing to do with C.

    Vin * {R2 / (R1 + R2)} = Vthreshold

    Vin = Vth * (1 + R1/R2)
    . = 2.5 * (1 + 58 / 18)
    . = 10.5 volts

    The input range is symmetical around the threshold. So with R1=58k and R2=18k, the maximum input range would be -5.5 volts to + 10.5 volts. 8 volts on each side of +2.5. When the input is at -5.5 volts, the duty cycle will be 100% at Vdd, and that is the upper limit that can hold the input at the required 2.5 volt threshold. The duty cycle varies from 100% high at Vin = -5.5 volts to 100% low at Vin = +10.5 volts. When the input is at +8 volts, output feedback pin will spend about 85% of the time at Vss and 15% at Vdd, in order to maintain the input pin at 2.5 volts.

    The AC analysis has to be added on top of the DC analysis. How fast do the updates on the capacitor have to be done to hold the input within a certain window around 2.5 volts, as pjv outlined.

    The duty cycle conversion result will not be linear with the angle of the potentiometer. The 58k will load it down and distort the linearity. Maybe no big deal. If you go for a higher still value of R1, that will narrow down the range of duty cycle values, but will improve the linearity.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Tracy Allen
    www.emesystems.com
  • pjvpjv Posts: 1,903
    edited 2007-05-31 12:14
    Hi Sparks;

    OOPS!!

    Tracy is right...... my calculation for the voltage divider was stated incorrectly; for an input voltage of 7.5 volts (simply chosen as an approximation of 3 times the 2.5 volt threshold) the value of R1 plus R2 is (approximately) 54 K, and that then makes R1 equal to 54K minus 18 K which is·36 K as Tracy said. For 8 volt input, R1 scales a little higher. In any case, these were approximations as the loading on the pot will throw things off, and some final fine tuning needs to be done once the actual value of R1 and the input range is selected.

    My apologies for not being thorough!

    Cheers,

    Peter (pjv)

    Post Edited (pjv) : 5/31/2007 12:20:48 PM GMT
  • ellizardellizard Posts: 106
    edited 2007-05-31 18:37
    HI Everybody

    What about isolating the pot with a voltage follower?

    just a consideration.........................(dumb maybe?)

    regards
    Stefano
  • Sparks-R-FunSparks-R-Fun Posts: 388
    edited 2007-05-31 23:11
    Alright, I have received a lot of feedback and made a lot of changes. The arrangement is the same but the numbers have changed. This is what I have right now.

    ADC cycle = 34.5uS
    8-bit value returned
    C = 0.1uF
    R1 = 262K calculated (270K used)
    R2 = 88K calculated (82K used)

    I want to clarify that the voltage range is 0-10VDC. The range of the display is 0.0-8.0 and is an arbitrary "speed" indication for the motor.

    Unfortunately, the ADC does not seem to work at all with the values given above. The result returned is always zero! If I lower the value of R2 significantly, the ADC begins to work again.

    Here is how I arrived at those values.
    The ADC takes a sample every 34.5uS, which is twice my UART sampling rate.
    The ADC will take an 8-bit reading comprised of 256 samples.


    Calculating R1
    Tracy Allen has explained the use of this formula for the calculation of R1:
    R1 = (Vin - Vthreshold) * R2 / Vthreshold

    The maximum input will be 10V so...
    R1 = (10.0 - 2.5) * 88 / 2.5
    R1 = 264K

    In place of the calculated 264K resistor a 270K resistor was handy and used instead.


    Calculating R2
    According to pjv I should aim for an RC time constant of Sample_Time * Number_of_Samples. So I am looking at (34.5E-6) * (256) = 8.832E-3s or 8.8ms. This suggests an R2 value of 8.8K for a 1uF capacitor or 88K for a 0.1uF capacitor. I am not sure why a smaller capacitor is better other than the fact that it allows a larger resistor to be used. The larger resistor is better for this case since I must read the output of a 10K pot.

    In place of the calculated 88K resistor an 82K resistor was handy and used instead.


    As a result the ADC returns only zeros. Where did I go wrong?

    - Sparks
  • pjvpjv Posts: 1,903
    edited 2007-06-01 00:38
    Hi Sparks;

    The numbers are all correct, so something else is afoot now..... this doesn't make sense, so please post your whole actual code. The previous snippet might not show the actual problem.

    Also please realize that with the calculated values, the input range is minus 5 volts to plus 10 volts, and that is represented by the count range from 0 to 255.

    Cheers,

    Peter (pjv)

    Post Edit.......

    You ARE using CMOS levels with the pull-ups on the input bit turned OFF· RIGHT!!!!!!!!

    Post Edited (pjv) : 6/1/2007 12:43:33 AM GMT
  • Sparks-R-FunSparks-R-Fun Posts: 388
    edited 2007-06-01 02:09
    Hmmm...
    pjv said...
    You ARE using CMOS levels with the pull-ups on the input bit turned OFF RIGHT!!!!!!!!
    Heh. Thanks for the idea, pjv. You are really thinking hard about this. Thankfully I am not THAT stu...
    (pause)
    Hold on. I'll check.

    Ok. *gulp* Yes I am. I really am THAT stupid!


    The CMOS input level was set but I forgot all about the pull-up being enabled from the time when that input was previously used for reading a button.
    I probably would have never figured that out on my own! Thank you so much. idea.gif



    With that problem identified I am reading a high value of 243 at 10.03 volts and a low value of 123 at 0.005 volts. However the return values are as unstable as ever. At the high end, the highest and lowest of nine consecutive samples differed by a value of 11. At the low end, the highest and lowest of nine consecutive samples differed by a value of 23.

    For comparison, when using a different microcontroller that has a built in 10-bit ADC I was able to obtain values within a three digit span for most samples. This would occasionally extend to a five digit span once out of every one hundred samples or so (roughly estimated). This was accomplished by reading the same pot and by dropping the two least significant bits to convert to an 8-bit result. This was all on the same breadboard and arrangement. I simply moved the jumper wire from the pot wiper between the two microcontrollers.

    I am not sure how favorably that compares with what I should be able to achieve with a proper design but it may offer some indication of the kind of RFI noise and parasitic capacitances affecting the breadboard design. The final circuit will be on a custom PCB.

    I guess my question now is what is my next logic step? Is it reasonable to think that I should be able to achieve even better results with a better design?

    To Sumarize: The input pin is set to the CMOS threshold. The pull-up resistor is now off! The interrupt seems rock solid. (I toggle a pin when I enter it and have checked this with a logic analyzer.)

    I am thinking the next logical step is to increase my interrupt rate and recalculate my component values. Does anyone have any more thoughts?


    - Sparks


    P.S. Thanks again pjv for figuring out that I might have left a pull-up enabled. That was awesome! blush.gif
  • pjvpjv Posts: 1,903
    edited 2007-06-01 04:30
    Hi Sparks;

    Hmmmmm..... can't figure why it's not stable to about 2 counts; one statistical and one for grace. I presume the power supply is short-term stable? Do you have any Parallax SX28 proto boards to wire this up on?

    If not, I've got a bunch and I'll wire one here and send it to you with code, ready to go, although it will be in assembler as I have not yet learned SX/B. You'll need to tell us a bit about the serial comms requirements though. Actually, come think of it this could be an interesting exercise for others in the forum to follow and copy.

    And, please DO post your code. Who knows what's lurking there. The pull-ups was just a lucky guess that didn't show up in your code snippet.

    I have used these A/D's with good success hundreds of times, and I do believe I understand them well, so it's got to be something we're not seeing just now. At 50 MHz a 1 instruction ISR timing inconsistency will introduce an error of about 0.15%; and at 4 mHz about 10 times that, say 1.5%.

    Cheers,

    Peter (pjv)

    Post Edit.......

    Hold it, hold it...... now I'm the stupid one. You did say you used the input also for (temporarily ?) sensing a button????? Of course you can't do that while the ADC is running, but of course you already knew that. So at boot time or while the ADC is not active, it's·OK, but be careful here, there are timing and recovery issues....

    Can you give us a DETAILED description of what you are ACTUALLY doing as well as what you're trying to achieve? It's really tough troubleshooting while we are guessing. YOU know what's going on, but WE don't!

    Posted full code could really help.

    Cheers, (isn't this fun ??!!!)

    Peter (pjv)

    Post Post Edit;

    If it turns out that it's just noise and not errors (errors should be fixed, not masked), then I have some light DSP tricks, about 8·or so instructions,·that will make the reading·absolutely rock solid.

    Cheers, and good night

    Peter (pjv)


    Post Edited (pjv) : 6/1/2007 4:50:32 AM GMT
  • Tracy AllenTracy Allen Posts: 6,657
    edited 2007-06-01 06:39
    Sparks,

    The reading of 123 when the input is zero volts seems much too high, even accounting for the 23 unit instability. It should be more like 85. What happens if you connect a short wire directly from the top of the 270k resistor to ground, in fact directly to the ground pin on the SX? What I am thinking of is some sort of ground loop. Sometimes the ground path on breadboards is very roundabout.

    It's important because the sigma-delta is using a ground point inside on the SX chip as its point of reference, and any voltage induced on wires to the remote ground constitutes an error signal. This is particularly important with sigma-delta on the SX, because the input pin is hovering precisely at its crossover point and operating in its linear region, where it (the chip, not the input pin) is drawing a relatively high and fluctuating current. Also, the output feedback pin is switching back and forth rapidly, which also puts spikes of current on the ground line. The chip has to be especially well bypassed and careful consideration has to be given to all power current paths. This can all come clean in a printed circuit board. I was also wondering if there is anything else going on on other pins of the SX? For example, if RB.4 is toggling up and down rapidly to drive some other process, it could both add more noise to the power supply and also couple capacitively into RB.3, the ADC input pin.

    The other microprocessor you used for comparison might have a different type of ADC, successive approximation say, that does not create so much switching noise. Some processors even go to the trouble of turning off other digital circuitry while they read the ADC.

    Then again, noise might not be an issue, and there is a problem with the software. That is what makes troubleshooting fun! Multiple sufficient causes.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Tracy Allen
    www.emesystems.com

    Post Edited (Tracy Allen) : 6/1/2007 6:53:06 AM GMT
  • metron9metron9 Posts: 1,100
    edited 2007-06-01 13:57
    Somebody said...
    The other microprocessor you used for comparison might have a different type of ADC, successive approximation say, that does not create so much switching noise. Some processors even go to the trouble of turning off other digital circuitry while they read the ADC.

    Sparks is testing my co-processor with this and if I understand his last PM that is the other microprocessor.

    The ADC on the MEGA48 is 10 bit and uses successive approximation, I left adjust the result to 8 bits. The chip is running at 20mhz with a prescaler of 128. I use the sleep mode that does indeed shut down the chip while the measurement is made. It also uses it's own 1.1V internal reference so Sparks is dividing the input voltage down as well so 0.11V reads 25 and 10V reads 255.

    So toggling pins while a reading is made can be very bad even when there is a separate ADC chip taking measurements.

    I think the problem is not defined however. Is it the ADC or is the voltage being read actually fluctuating and ithe ADC is working as it should?

    I would put a known 5V regulated supply voltage directly to the ADC input (or through the divider if using the 1.1ref so you can test the ADC in isolation.

    Instead of reading just a few readings scrolling by, use a counter and an array to count a span of 6 units above and below the test voltage and scroll those numbers on the debug screen, make 255 measurements and log each one so you can quantify how much ripple you really have.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Think Inside the box first and if that doesn't work..
    Re-arrange what's inside the box then...
    Think outside the BOX!
  • Sparks-R-FunSparks-R-Fun Posts: 388
    edited 2007-06-07 23:37
    Hi. I'm back... well, sort of back, I guess.

    I wish to apologize for dropping the momentum on this thread. I was receiving a lot of input but then had an unplanned change in my schedule. As a result I have spent about an hour total at my desk in the past six days! So not much progress on my analog circuit has been made.

    I will try to post an update early next week if I can not get to it tomorrow. I have answers to some of the questions raised and even rebuilt the analog input section on an SX-Tech board. However, I have not been able to test it yet.

    In the mean time, a big thanks goes out to all who have tried to help me with this. I will try to return to it next week!

    - Sparks
  • Sparks-R-FunSparks-R-Fun Posts: 388
    edited 2007-06-12 03:47
    Thank you for your patience everyone. smile.gif I believe I am ready to pick this up again!

    To recap, I am attempting to create a continuously running sigma-delta analog-to-digital converter using an SX28. So far the stability of my return values has been rather disappointing. (See Original-Results-01.gif)

    I think the ADC is not working as well as expected because I have not sufficiently understood the requirements for ensuring acceptable performance. In fact, I think it would likely be much easier to fix if it were not working at all! Sometimes electronics are like that.


    Answers to Previously Raised Questions

    I will begin again by addressing some previous questions that had been asked about my original program and intent. Then I will proceed to describe what I have done in the meantime and how my new test program is setup.

    The following statements are replies to previous questions asked about my original program and intent.
    • 1.) (pjv) Using the ADC input for reading a button (hence leaving the enabled pull-up) was done in a previous version of the circuit and code well before the ADC was added. I am not using any ADC pin for a dual purpose. I simply forgot about the pullup when I reassigned the pin.
    • 2.) (pjv) I am not sure how much additional detail you desire about my original program. I will provide a functional overview now. If you desire still more detail, keep asking.

      Here are some additional details on my original (FULL) program:
      Sparks-R-Fun said...
      The SX is responding to four user interface buttons, the 10K pot and a bi-directional serial link running at 4800 bps. The serial link connects to another micro-controller, currently another SX I have also programmed. (More on that later.)

      The SX is also connected to an LCD running in 4-bit parallel mode and an EEPROM communicating over I2C. The SX displays system information and/or assists in changing system parameters by means of a user interface with menus that are retrieved from the EEPROM.

      The SX either displays the information it receives from the other micro-controller or informs the other micro-controller of system parameters that have been changed by the user.

      So far this has all worked sufficiently well! The last step of the initial design phase was to add the ADC capability to one of the micro-controllers. As such the ADC works... but so far not well enough to be acceptable for this application.

      The second micro-controller, hereafter called SX-2, is tracking the state of numerous switches and buttons on the machine and reading a binary sensor or two. SX-2 tracks and responds to all machine inputs and controls all machine outputs except for the pot controlled motor which is not microprocessor controlled. SX-2 also runs a seven-day clock that triggers certain timed events.

      The current time as well as event elapsed time or time remaining and the machine state are contained in information packets SX-2 periodically sends over the serial link to the SX running the display.
      Fortunately, I think all of that can mostly be ignored. However, it may help in some way to keep in mind the grand scheme of the design. All of that has in fact been working well. Aside from some limited program space concerns, I do not think adding the ADC should adversely affect the current system operation.

      Now to answer a few more questions…
    • 3.) (Tracy Allen) When I ground R1 where it connects with C I receive all zeros from my test setup which I will describe a little later. I have not yet tried it on my original circuit as part of it is presently dismantled.
    • 4.) (Tracy Allen) I imagine there is quite a lot going on with other pins during the entire time the ADC is running. At stated above it is sometimes talking I2C to an EEPROM and almost always receiving new serial information and updating the LCD. However, I have cut out most all of that in the attached test program to see if it improves the ADC results.
    • 5.) (Metron9) As correctly assumed, I have been testing Metron9's co-processor occasionally in place of SX-2 and among other things have been trying to compare its ADC results against my own. (I will not report on that now to save confusion.)
    • 6.) (ellizard) I originally considered that I might need to use an op-amp or similar buffer circuit especially since I must read a voltage from a 10K pot. Some of the other posters think I ought to be able to read it directly without much trouble. Would anyone care to comment on the voltage follower idea?
    All in all it seems like I have stepped into a realm of complexity higher than I expected with this analog to digital converter. However, if I can master the particulars enough to incorporate sigma-delta ADCs into this and future designs it will be a valuable experience. Hopefully, as pjv has mused, this thread may also serve as a valuable reference for others as well.

    Now for a bit of a change!


    The New Test Circuit

    To assist those who are willing to assist me, I am attaching an updated schematic to reflect the current ADC component values of my entirely separate test circuit build on an SX28 proto-board. (R1 = 820K, R2 = 820K, C = 0.01uF) I am also attaching a stripped down version of my program that runs on the test circuit. Finally, I am attaching some screen shots showing 50-sample logs of the output from my ADC test circuit. All tests were performed with the pot motionless! It is the difference in returned values when the pot is completely still that I seek to minimize.

    To make things easier on everyone I have tried to strip the attached program to only the essentials, the UART, the ADC and some support logic. The interrupt routine is retained exactly as I am running it in my original application with two small exceptions.

    The first minor difference is that I have added a "NewADCValue = TRUE" statement which my original program does not have. I added this bit flag to my test program so that I can detect when a new sample value is ready. Then I just send it to the serial port without sending unnecessary duplicate values. The original program does not need this statement since it simply displays whatever the most recent value is when the display is updated.

    The second minor difference is that I have switched from Inverted to True serial mode by simply changing the definitions of the constants ZERO_STATE and ONE_STATE. This allows me to not use a MAX232 serial driver on the proto-board though one is used in the original design. Also, I have not hooked up the PC's serial transmit pin, only its receive pin!

    I think that for the duration of this thread it will now suffice to only refer to the attached test program or to subsequent updates to it that may be posted as follow-ups. I think that since this test program performs nearly the same as my full program that getting the test program to run properly is the best place to focus.

    Also, for the purpose of focusing on getting a decent ADC result I will be supplying the 10K pot with 5V from the SX28 proto-board until further notice rather than the 10V required for the design. This way, if someone cares to duplicate my test setup they can easily do so with an SX28 proto-board, a 10K pot and the resistors and capacitor stated. I will try to post a picture of the testing setup when I can.


    Attachments

    The following items are attached:

    Original-Results-01.gif <--- Shows 50 consecutive samples from the attached program when run on my original circuit using the values R1 = 2.7M, R2 = 820K, C = 0.01uF with 10V supplied to the pot.

    ADC-Test-Circuit-01.gif <--- Shows the schematic for the new test circuit built entirely on an SX28 proto-board.

    TEST-ADC-UART-02.SXB <--- Is the program used for the test results shown.

    Test-Results-01.gif <--- Shows 50 consecutive samples from the attached program when run on the test circuit using the values R1 = 820K, R2 = 820K, C = 0.01uF with 5V supplied to the pot which is at its minimum position.

    Test-Results-02.gif <--- Shows 50 consecutive samples from the attached program when run on the test circuit using the values R1 = 820K, R2 = 820K, C = 0.01uF with 5V supplied to the pot which is at its middle position.

    Test-Results-03.gif <--- Shows 50 consecutive samples from the attached program when run on the test circuit using the values R1 = 820K, R2 = 820K, C = 0.01uF with 5V supplied to the pot which is at its maximum position.


    I know I have posted a lot of information. I hope it will be helpful to anyone trying to help me. A big thanks goes out to everyone who has already offered help!

    - Sparks
    431 x 1006 - 29K
    431 x 1006 - 27K
    431 x 1006 - 27K
    431 x 1006 - 27K
    441 x 300 - 3K
  • Sparks-R-FunSparks-R-Fun Posts: 388
    edited 2007-06-12 03:48
    Sorry...

    Here is the ADC and UART test code!

    - Sparks
  • pjvpjv Posts: 1,903
    edited 2007-06-12 14:24
    Hi Sparks;

    OK, now here is some poor skills on my part, and that is SX/B. In reading your SX/B code I believe that the A/D pin sampling is NOT done in the ISR. Loading and compiling the SX/B and viewing the assembler listing appears to confirm that.

    The pin sampling for the ADC must happen at EXACTLY the same time every cycle, and this can typically only be achieved by putting it in the ISR, in fact ahead of anything else in the ISR that may have variable execution paths hence variable execution times. This is of paramount importance if you want stable readings.

    Unless I'm somehow mistaken in reading the SX/B code; move your ADC code to the ISR (I thought from your previous description it WAS there) and your problem will be solved.

    Cheers,

    Peter (pjv)
  • Sparks-R-FunSparks-R-Fun Posts: 388
    edited 2007-06-12 22:03
    Hey, Peter! (pjv)

    Thanks for looking at my code even though SX/B is not an area of high familiarity for you.

    My ISR calls the Process_UART subroutine, which was so named because originally it contained just the UART. Now it contains the ADC code and a small clock counter as well.

    The ADC code is the first code that is run inside the ISR. I understood that to be important. The ISR looks a little different because at one time it extended past a page boundary and generated a compiler error. To solve this I placed most of the code in the Process_UART subroutine. In order to call the subroutine in SX/B it must first be declared. Since it is being declared so early and within the body of the ISR itself it is necessary to include a statement to jump over the subroutine declaration.(*) Unfortunately, this adds several cycles to the ISR, which I am sure must make you cringe! However, the timing for calling the Process_UART subroutine is always the same. So it should work, at least in that regard.

    The ISR runs as close to 28800Hz as the SX can be configured with a 20MHz clock. I can probably run it faster if that would be better. (I actually thought a longer sample time would be more accurate.) 28800Hz was chosen since the 4800bps UART was already in place and running with three times over sampling. (More oversampling would probably be better but this was working fine for me.) When I started having problems with the ADC and posting about my trouble I decided to increase the ADC rate to double the UART rate thinking that might help. To accomplsih this there is a bit flag called ISRADCOnly that is checked and toggled on every interrupt. If it is TRUE then the ADC code is the only part of the ISR code that runs. This allows the ADC to run at twice the rate of the UART.

    I am attaching a picture of my test setup in the hopes that it might clarify my arrangement. I do, however, need to correct the fact that I stated it was built on a proto-board when in fact it was built on an SX-Tech board.

    Thanks for reading this.

    - Sparks



    (* - Now that I think about it some more, since Process_UART is never called from anywhere but the ISR I could actually remove the jump over its declaration and instead of returning at the end I could simply jump back! But right now I am not so concerned with code efficiency as I am with obtaining a stable and accurate result.)
    917 x 676 - 109K
  • metron9metron9 Posts: 1,100
    edited 2007-06-13 04:25
    what is the Dielectric code for the capacitor you are using MAX. Capacitance change over temperature? Perhaps this is a problem. I know when I was experimenting with some Z5U caps they worked like a thermistor when you touch them, lots of variance in capacitance.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Think Inside the box first and if that doesn't work..
    Re-arrange what's inside the box then...
    Think outside the BOX!
  • Sparks-R-FunSparks-R-Fun Posts: 388
    edited 2007-06-13 04:44
    The 0.01uF capacitor is a 100V 10% monolithic ceramic capacitor made by EPCOS Inc. It is Digi-Key part number P4904-ND. My interpretation of the data sheet is that it is a dielectric Class 2 with a delta-C over C variation of +-15%.

    Of course, all of that means very little to me right now. I have no idea if that is good or not!

    - Sparks
  • pjvpjv Posts: 1,903
    edited 2007-06-13 04:50
    Hi Sparks;

    I just don't get it. I built and coded one up this evening, pumping 8 bit ADC readings out at 9600 to a CRT, and it is stable within 2 counts in the raw..... NO filtering.

    Send me a PM and I'll ship you one on a Parallax protoboard all bult and coded up tomorrow. Or alternately I could send you my RTOS/ADC/UART assembler code. Sorry, at this time I can't be of much help in SX/B.

    Let me know.

    This is just too bizzare!

    Cheers,

    Peter (pjv)
  • Sparks-R-FunSparks-R-Fun Posts: 388
    edited 2007-06-13 19:14
    Hi, Peter.

    Thank you for all of the help you have been offering me with my ADC stability problems. I am perplexed over something that I thought would be fairly straightforward and easy. It turns out that I either overlooked or misunderstood a few important things. It may also be the case that such an ADC simply will not be very stable when built on a breadboard.

    I do have an SX48 proto-board available that I can use. Ultimately I need to determine if my less-than-stellar results are due to programming implementation, part selection and arrangement or my environment. Being able to start from a known good implementation should certainly assist in that determination!

    If you send me a working proto-board it should answer the environment question right away. It is awfully nice for you to offer that! However, if it is not an environmental problem that I am having, and it seems unlikely to me that it is, then I will need to examine and/or modify the software or swap components to determine what is different about what works well and what does not. In that case I might be able to achieve similar results starting with your software and the proto-board and components that I already have. I am fine with that approach.

    I have sent you a private message.


    I am curious, though. Can a few others comment on their experiences and the stability of their results? I thought this was quite common and want to know if my experience is way outside the norm.

    Thanks everyone!

    - Sparks
  • Tracy AllenTracy Allen Posts: 6,657
    edited 2007-06-14 00:31
    I have to gasp when I see the board layout. There are several big loops of wire, and the integration capacitor and input resistor are on the opposite side of the board from the feedback resistor. The ground for the capacitor is plugged into the Vss edge connector, which has a long ground path back to the regulator and then to the SX chip. Take a look at the ground path on the tech board. It comes to the SX chip diametrically opposite on the PCB from where the Vss plug terminals are. Think of Vss inside the chip as the reference point for the ADC measurement. But the Vss point where the capacitor is attached is in another country when noise and lead inductance are considered.

    A parallel situation and cautionary tale arose when Chip Gracey was trying to get the sigma-delta converter going on the original propeller demo board. It had unacceptably noisy readings when it was constructed on the white breadboad. The short of it is that Chip put the feedback and input resistor and the integration capacitor as surface mount parts right next to the pins of the Propeller chip and the ground of the capacitor also right to a neighboring Prop power pin. I do mean, right next to it. That worked and that is the way it came out in the revised version of the demo board. Granted that was operating with a 12.5 nanosecond clock period, but the same considerations hold true even at lower speeds.

    I can't say for sure that the same thing is happening here, versus software issues. The tightest wiring would be for you to take the SX28 out of its socket and bend up the pins for RB2 and RB3, and solder the components right to the pins and the capacitor ground to Vss on the chip. Then plug it back into the socket, leaving those two pins up, and the input R would hang up in the air for the connection to the potentiometer.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Tracy Allen
    www.emesystems.com
  • pjvpjv Posts: 1,903
    edited 2007-06-14 15:09
    Hi Sparks;

    I found your problem....... it wasn't noise; at least not in the regular sense.

    In your ADC routine you intend to flip the output (drive) bit high when the input (sense) bit is low, and flip the output bit low when the sense pin is high, and·this is what shoud be done.

    The problem is, (and I guess it's not easy to see with SX/B as at the higher level you are at least somewhat insulated from the native machine code) the instructions used sample the input for a low to possibly flip the output high, and then sample the input AGAIN, this time for a·high·to possibly flip the output low. You are sampling twice, and the output high/low decision is not based on the same, single·sample.

    Then on top of that you sample the input a third time to decide whether or not to increment the ADC accumulator.

    Because the ADC works with the input line near the input switching threshold, any small excursions will affect the determination of whether the input line was high or low at any moment, and in fact setting the drive high or low (and not at the·identical ISR·instant) impacts these perturbations.

    In essence your first sample may decide to flip the output high. The second sample two instructions after the first sample might decide, due to minor noise,·to return the output back·to low. Which one was right?? And then the separate decision whether or not to increment the accumulator........

    So I have made a small modification to your code, to take only one single sample, and the work with that one sample to determine whether the output should be high or low, and output that decision with a single high/low write to the port, always at exactly the same ISR instant. Further more, I use the state of the drive output to determine whether or not to increment the accumulator.

    Works great on one of those "white" wireless patchboards....... a variance of 1 or 2 counts. But do continue to design for the lowest noise.... it's always a good practice.

    As for component values (not at all critical), use a·330 K ohm·feedback resistor, and scale the input resistor to achieve the range you want, and for·7.5 volts·that would be somewhere around 1 Meg, and a 0.1 capacitor. That yields a time constant of about 20 millisec; about the right ballpark.

    Have fun and be happy!

    Cheers,

    Peter (pjv)
  • Tracy AllenTracy Allen Posts: 6,657
    edited 2007-06-14 17:48
    Wow! With such friends one can really be happy!

    I was evidently overly pessimistic with my noise concerns on the breadboard, given the operating frequency and the required resolution.

    Still, here is a less draconian layout, that does not require bending up any pins.

    attachment.php?attachmentid=47746

    All the components are soldered in the form of a tepee and plugged directly into the signal connector strip on the tech board. The connection to ground is made to rb.4, which is configured as a low output. And for good measure and symmetry, the connection to Vdd with a second capacitor (equal in value to the first one) is made to rb.1, configured as a high output. Those outputs act like a Kelvin connection to the power supply inside the chip.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Tracy Allen
    www.emesystems.com

    Post Edited (Tracy Allen) : 6/14/2007 5:53:43 PM GMT
    360 x 270 - 36K
Sign In or Register to comment.