Analog In

12 Nov 2011

Hi All,

Has anyone figured out how to get good results reading Analog in? I posed a few days ago about how to get a good voltage sample and after seting it all up I find completly unstable readings... Then I search the site and find it's a common problem talked about for awhile now...

Is there a way around this using digital in, reading a frequency signal or some other method?

Thanks in Advance

Tim

12 Nov 2011

If you do not require a ridiculous sample rate,(grabbing audio for example) then there are a few things you can do:

1: use a digital filter, most coders use is rolling average, NOT MY Favorite. I use a median filter, but this does mean you might need to increase your sample frequency, to avoid latency.

2: a simple capacitor across Analogue in, and ground, near ADC pin,

if possible, part of our voltage divider circuit, or from the feed resistor.

if you are able to do so, then make the MBED create a *CSV file, and use EXCEL to view your results, and you can also optimism your filter there.

Hope this helps

Ceri

12 Nov 2011

Thanks Ceri,

I do need a pretty fast sampling rate... Do you have an example of how to set up a median filter?

BTW: I actually went so far as to disconnect the voltage sensor wire and short the mbed ADC to ground... It actually still was flickering bogas data... Appears this is the first true weakness I've found with this device.

Tim

12 Nov 2011

It is (as far as i am aware) common across almost all micros.

Don't forget, there is an awful lot of STUFF going on inside that little black square !!! Especially if you are using CAN, (found that out the hard way)

Also if you have not got a smooth power rails, and good decoupling, then you will get noise.

//Entry point ..
while (1)
{
Raw_ADC = Read_ADC ();

// do something useful ...

wait (100)
}

The Filter,

depending om how much noise you have (use a log file and test with EXCEL) a MEDIAN 7 is probably best value,

Basically you take 7 samples, close together, sort in ascending order, and use the middle value.

//Entry point ..

int Results[8];

while (1)
{

Results[0] = Read_ADC ();  wait (2);
Results[1] = Read_ADC ();  wait (2);
....
Results[5] = Read_ADC ();  wait (2);
Results[6] = Read_ADC ();  wait (2);

Sort();    // see Google :)

Raw_ADC = Results[3];

// do something useful ...

wait (100-(2*7));
}

Hope this is useful,

Enjoy

Ceri.

13 Nov 2011

I ended up using a completly different approach. After running a bunch of tests and looking at the behaivor of the mbed. I concluded that when the "Static" does occur in the reading, that the static value is almost random. And that there was no real pattern that I could find...

So the thought came to me that two analog in pins most likely would never produce the same errant reading values at the same time... So what I did was tie two ananlog in pins together to act as a pair. And only when both pins read the same value would I consider the reading valid.

The only exception to this rule was when they would both read 1 (100%). The full scale error is common enough that at times they would both read this errant value at the same time. So I simply excluded a full scale reading. So this code gives me pretty reliable readings in the 0-99% scale. Wich is plenty good enough for what I need...

Here is the program...

BTW: I only send the values to the PC when the voltage has changed...

I'm actually pretty happy. This is working quite well and runs very fast...

Best Regards,

#include "mbed.h"

AnalogIn aIn1a(p17), aIn1b(p18);
DigitalOut pNeg1(p13),pNeg2(p14), pSig(p15);
DigitalOut led1(LED1),led2(LED2),led3(LED3),led4(LED4);

// Declare serial transmission
Serial pc(USBTX,USBRX);


struct v_Data {
char aIn1Pct;
float aIn1Volt;
} vData, vDataSent;

int main() {

    //  set the baud rate
    pc.baud(115200);

    //  Use a pot on p13 and p14 for test voltage
    //  Test voltage from the pot is feed to BOTH p17 & p18 together
    //  p17 & p18 are tied to ground with a 104 ceramic cap.
    
    pNeg1 = pNeg2 = 0;
    pSig = 1;

    while (1){
    
        //set led displys
        led1 = 1;
        led2 = (vData.aIn1Volt > 1.0);
        led3 = (vData.aIn1Volt > 2.0);
        led4 = (vData.aIn1Volt > 3.0);
    
    
        char cIn1a = (aIn1a.read()*100);
        char cIn1b = (aIn1b.read()*100);
        
        //  If errant readings on either of the analog in reading pair then do not process the reading
        //  Filter out any 100% reading as this happens enough where both aIn pins could be at error at the same time
        //  0-99% accuracy is good enough
        if((cIn1a == cIn1b) && (cIn1a < 100)){
        
            // Set the voltage info in the structure       
            vData.aIn1Pct = cIn1a;
            vData.aIn1Volt = (3.3 * ((float)cIn1a / 100));
            
            // Send voltage info to PC only if values have changed
            if(vData.aIn1Pct != vDataSent.aIn1Pct){
              vDataSent.aIn1Pct = vData.aIn1Pct;
              pc.printf("TEST=[%d][%.2f];\r\n",vData.aIn1Pct, vData.aIn1Volt);            
            }
               
        }
        
        wait(.05);
        
    }
    
}

13 Nov 2011

Here is the output when I slowly move the pot slider from min to max...

TEST=[1][0.03]; TEST=[2][0.07]; TEST=[3][0.10]; TEST=[5][0.17]; TEST=[8][0.26]; TEST=[9][0.30]; TEST=[10][0.33]; TEST=[11][0.36]; TEST=[12][0.40]; TEST=[13][0.43]; TEST=[14][0.46]; TEST=[15][0.50]; TEST=[16][0.53]; TEST=[17][0.56]; TEST=[18][0.59]; TEST=[19][0.63]; TEST=[20][0.66]; TEST=[22][0.73]; TEST=[23][0.76]; TEST=[24][0.79]; TEST=[25][0.82]; TEST=[26][0.86]; TEST=[27][0.89]; TEST=[28][0.92]; TEST=[29][0.96]; TEST=[30][0.99]; TEST=[31][1.02]; TEST=[32][1.06]; TEST=[33][1.09]; TEST=[34][1.12]; TEST=[35][1.15]; TEST=[36][1.19]; TEST=[37][1.22]; TEST=[38][1.25]; TEST=[39][1.29]; TEST=[40][1.32]; TEST=[41][1.35]; TEST=[42][1.39]; TEST=[43][1.42]; TEST=[44][1.45]; TEST=[45][1.49]; TEST=[46][1.52]; TEST=[47][1.55]; TEST=[48][1.58]; TEST=[49][1.62]; TEST=[50][1.65]; TEST=[53][1.75]; TEST=[54][1.78]; TEST=[55][1.82]; TEST=[57][1.88]; TEST=[58][1.91]; TEST=[59][1.95]; TEST=[60][1.98]; TEST=[61][2.01]; TEST=[62][2.05]; TEST=[63][2.08]; TEST=[64][2.11]; TEST=[66][2.18]; TEST=[67][2.21]; TEST=[68][2.24]; TEST=[69][2.28]; TEST=[70][2.31]; TEST=[71][2.34]; TEST=[72][2.38]; TEST=[73][2.41]; TEST=[74][2.44]; TEST=[75][2.47]; TEST=[76][2.51]; TEST=[77][2.54]; TEST=[78][2.57]; TEST=[79][2.61]; TEST=[80][2.64]; TEST=[81][2.67]; TEST=[82][2.71]; TEST=[83][2.74]; TEST=[84][2.77]; TEST=[85][2.81]; TEST=[86][2.84]; TEST=[87][2.87]; TEST=[88][2.90]; TEST=[89][2.94]; TEST=[90][2.97]; TEST=[93][3.07]; TEST=[94][3.10]; TEST=[95][3.13]; TEST=[96][3.17]; TEST=[97][3.20]; TEST=[98][3.23]; TEST=[99][3.27];

14 Nov 2011

Hello, Tim.

About a year ago I played around with a single-turn, trim pot. plugged into a breadboard, and noticed that the readings into an AnalogIn were jumpy, but I never pursued it because I had no application that needed it. At the time I thought that it might be the pot moving around in the breadboard. However, your discussion has rekindled my interest, and this time I used a single-turn, panel mount potentiometer, 50K, carbon track. I soldered wires to the pot's terminals and inserted the ends in the breadboard. Here are the results of my first three runs:

/media/uploads/bprier/first_three_runs.gif

You may have to scroll to the right to see the legend. The second run had no spikes, possibly because I turned the pot more slowly. I think the problem of the spikes stems from the wiper in the pot losing contact with the resistive track. As the wiper brushes over the resistive material the microscopic roughness causes contact bounce. Here is my fourth run where I rotated the pot back-and-forth quickly, along with my fifth run where I turned the pot very slowly:

/media/uploads/bprier/runs_4_and_5.gif

There are spikes going to ground, along with partial spkes, and spikes going to the high side! Similar to debouncing a switch, I added a cap between the AnalogIn pin and ground to hold the voltage if the wiper should lose contact. As you can see, the results are much better:

/media/uploads/bprier/with_capacitor_to_ground.gif

To finish it up, I also graphed your data, Tim:

/media/uploads/bprier/tims_data.gif

This experiment shows that sometimes a simple piece of harware (in this case, a capacitor) can greatly simplify the software. I had a somewhat similar experience recently, replaceing software with software. I had a LabVIEW app making RPC (remote procedure calls) to the mbed over USB. Initially I had LabVIEW doing all of the work, but later I added just a little more code to the mbed and it made things a whole lot easier in the LabVIEW code.

14 Nov 2011

Hi Bob, Thank you for sharing your experience and data too... When I used a cap on a single analog in pin I was still getting many "Spikes" and errant readings. I did a search on the forum and found that many folks were seeing the same issue. My post was to show that there was a different way to deal with the problem besides using Average or Means math as a solution. Based on my tests I truely believe the errant readings were coming from with-in the mbed itself. Even with a cap on the pin, and no movement of the pot at all, I was seeing spikes and random readings. By using two aIn pins an comparing their readings, the errant readings get canceled out (excluded) when both pins do not agree. That was my point... My attempts to use a cap to filter out the abnormal readings on a single pin did not work in my case... Believe me, I wish a single cap would have fixed it. Tim

15 Nov 2011

Thanks, Tim. Someone else just notified me on another link http://mbed.org/forum/electronics/post/14577/ about the same kind of problem with AnalogIn.

I also read again your earlier post about connecting ground to the AnalogIn pin instead of a pot. I missed that the first time, because my mind was on the contact issue with the pot wiper. Speaking of which, I have several new, panel-mount potentiometers from RadioShack, and on the back of the packaging is printed Sliding Noise: <47mV. Now, if the wiper were near either end of the pot, couldn't noise make the value overflow or underflow. I would think a well-designed ADC would just "top out", or bottom out. I believe that I saw in the literature somewhere that the mbed ADC is a successive approximation register (SAR) type, which shouldn't have that problem.

The literature also mentions that the analog inputs are all multiplexed into a single ADC, which is very typical. I've heard that multiplexers can have noise issues as well. Incidentally, in your code where you have it read two pins, it's a good thing they are being read by the same ADC, because otherwise the likelyhood of two readings from two different ADCs exactly matching would be slim. It's normally a good idea in a program to allow some tolerance for "matching" values, and not test for equality. (I also saw in your code that you were using some 0.1 uF caps. I'm sorry I missed that!)

15 Nov 2011

Hello,

thanks for putting me to this discussion. So now i know, that i´m not alone with this problem.

So my conclusion is, that there is a bug somewhere inside the mbed micro or inside the mbed lib!

1. You are sampling the same souce voltage with two different ADC-pins.

2. The same ADC is sampling the voltage, but within two HW chanals. The question is, if the sample and hold circuit is latching all the analogue values at the same time?

3. You are getting readings which are different more then 50% of full scale!

Sorry, that could not be only noise, espscially when both ADC-Pins are grounded!

Something in the mbed micro or in the mbed lib is going wrong.

Is there somebody who is able to do this test again, but without using the mbed lib? I´m not able to code in that way so closed to the HW. I do not know how to set all the registers in a propper way.

But i feel that there is something going wrong.

There are some possible reasons:

- Maybe the ADC state machine is disturbed through a happaning inside the micro.

- There is an (timer-)interrupt who is destroying the originaly proper readed ADC-value.

- Inside the mbed lib someting is going wrong.

15 Nov 2011

Hi,

Not sure the following is really relevant (or not) to this thread but here goes...

I'm using the 'big brother' LPC1788 part on another project & IIRC this has basically the same ADC module. On that I've found that the ADC behaviour is quite poor when run across serveral ADC channels (currently using 6 of the 8 available channels) at full rate (400kHz) but remarkably better when run at say 200kHz...

Has anyone tried repeating these tests on mbed using different smapling rates?

It's always possible I've mucked up somethig with my code on the LPC1788 though ;-)

Cheers,

Jez

18 Nov 2011

The ADC LPC1768 has a maximum clock rate of 13MHz. Conversions take 65 cycles thereby giving a maximum sampling rate of 200kHz. I am not too sure about the LPC1788. It could be 400ish if the ADC can be clocked to 25MHz.

18 Nov 2011

Hi Igor,

The LPC1788 manual says that the 12 bit ADC takes 31 clocks (up to 12.4MHz) to perform a fully accurate conversion which gives it a conversion rate of 400kHz - but it wouldn't be the first time there's a type in the user manual ;-)

I was just wondering if people had tried running the ADC on the mbed at slower sample rates & if so whether that had any effect on the 'glitches' being seen on the output values from the ADC...

Cheers,

Jez

19 Nov 2011

Hi everyone,

I finally got out my second mbed, which I was saving in case I damaged the first one, and used it to run the pot-into-AnalogIn experiment. When I graphed the data it had a few spikes like the graph in my earlier post (see above), but, as before, those spikes went away when I added a small amount of capacitance (2200 pF) between AnalogIn and ground. I then borrowed a third mbed from a co-worker, with the same results. So, there are at least three mbeds in existence that don't give spurious readings.

Has anyone run the code on the AnalogIn page of the Handbook which reads the analog input values into an array and then, after all readings are done, sends the data over USB? I ran that code, and it takes 1024 readings with a 1 ms delay between each, allowing only about a second to turn the pot, so I increased the delay to 10 ms in order to have more time to turn the pot back and forth. It then takes another 10 seconds (!) to send the array to TeraTerm (at 9600 baud). If you're having trouble with spurious readings, I would try that code because it separates the gathering of data from the sending of data to the terminal.

Also, what terminal emulators are you guys using? And what baud rate? I would like to re-run this using one of them. Someone mentioned PuTTY, so I might try that. I'm thinking that if the mbed is taking AnalogIn readings and sending those readings inside of the same loop there might be a conflict with some terminal emulators that causes spurious values to be received. The AnalogIn readings could be okay, but what the terminal is receiving might not be.

There is another piece of code on the AnalogIn page of the handbook that uses the four mbed LEDs as a crude bar graph. I haven't tried that code yet, but it has the advantage of not sending the data over serial at all.

19 Nov 2011

Jez and Igor,

Regarding sampling rate, if an AnalogIn read() is performed in a loop, then wouldn't the sampling rate be the rate at which it loops? For example, I have been running 1024 loops with a single read() and a 10 ms delay in each loop, so the conversion rate would only have to be about 100 Hz. Or are you thinking that each read() takes and averages many samples?

To test whether or not it is averaging many samples to create one reading, I used read_u16() which returns a 16-bit integer in the range 0x0000 to 0xFFFF, instead of using read() which returns a float in the range 0.0 to 1.0. Now, read_u16() is interesting because the ADC is only 12 bits, so how does it make a 16-bit value? My thinking was that it simply shifts the 12-bit value left four bits. For example, a 12-bit ADC value of 0xABC would become a 16-bit value of 0xABC0. If averaging were going on, that rightmost hex digit would probably not be 0; it could be 1, 2, 3 or any other hex digit. So I looked at some of my data:

0430 05F0 0BB0 11B1 1821 1E31 23F2 2982 2FD2 3583 3B23 40A4 45E4 4BC4 5145 5665 5C15 6206 67D6 6E26 7457 7AD7 80B8 8708 8CF8 9309 98E9 9EA9 A4AA AA9A

I was surprised! Look at the rightmost and leftmost digit in each value. Notice that the least significant hex digit is exactly the same as the most significant. That means that when the left shift was done, it was a circular shift, rather than shifting in zeroes. This seems to indicate that each of those readings is in fact a single sample rather than multiple conversions that were averaged together (unless they were averaged as 12-bit values and then left-shifted, which I doubt).

19 Nov 2011

Guys,

Have a look at this thread. This issue has been discussed here before.

Bob, I do not think it is terminal related. When I first noticed this issue, I placed the values in a long buffer to avoid sending serial data while sampling.

Also, some time ago (see here), the AnalogIn library was updated to speed up the conversion rate and add a median filter (3 samples) for the final output of AnalogIn.read().

As for the shifting, have a look at this thread. The 12 bit value is turned into 16 bit by taking the 4 most significant bits and appending them as the 4 least significant bits to make a 16 bit number that is linearly scaled.

EDIT: Just noticed that v29 is still in beta.. the median filter is not implemented in v28.

20 Nov 2011

If you are interested then I have written a crude oscilloscope program, Using the new BASIC HID interface, which can send data at very high rates.

You can simply change the messages, to suit your requirements.

I have also noticed that the Hi nibble is copied to the low nibble, very curious ? I have also seen a bit more nose than I would of expected. But I did not have them connected to anything (floating)

Look for my post, and give the code a spin.

Ceri

21 Nov 2011

Igor, thanks for the three, very good links. I like your comment on one of the threads, "Is this [compiler version] ever going to be released?" It reminds me of a bumper sticker a vendor was handing out at one company I worked for. The sticker said, "On every project there comes a time when you have to shoot the engineer and start production."

And speaking of versions, how does one check the firmware version in their mbed? Or the serial number? Seems to me I saw some code snippets on the latter, but I would think there would be a simple way of checking it.

21 Nov 2011

Haha..

To see what version you are using, open any project tree in the compiler and select the mbed library. To the right of the screen you should see the details about the mbed library used in the current project. To use the beta libary, remove the old 'mbed' library from the project and import a new library. Use this URL for the v29 beta: http://mbed.org/projects/libraries-testing/svn/beta. It should show up as 'beta' within your project tree.

22 Nov 2011

I was still using version 26 from November 2010! The current release version of the compiler is 28, and the beta is at version 36.

Running a tight loop with no delay, and which put the read values into an array, I was getting only one spike to the positive rail out of 1024 reads. After adding a 2200 pF capacitor between ground and AnalogIn, that spike and minor spikes went away. (This was using two 10K resistors in series between ground and Vout, and a tap off the divider into pin 15.)

I would recommend that anyone who is having trouble with AnalogIn readings try the beta mbed library.

22 Nov 2011

Hi All,

I've been following all your converstations. Some of it I understand but not all... I know my "Dual Read & Compare" method is not the best solution but it works and has allowed me to continue development of my project.

I would however like to be able to simply use a single A-In pin with a cap to get my measurement. I also want to avoid any math or buffering as this needs to run fast (like it does now).

So to dummy it down for me... Am I hearing that the latest version of the mbed library has resolved some of the noise, spikes, etc... I was seeing in my inital testing?

Best Regards

Tim

23 Nov 2011

The beta has done two things for AnalogIn:

1) Sampling rate has been increased (i.e. reads are up to 3 times faster now)

2) Each read() takes 3 consecutive samples and outputs the middle one. It does all this in a signle read read().

I don't know if this will be 'fast' enough for you. It depends on the project requirements. But you should see a big improvement on both fronts.

Let us know how it goes :)

09 Feb 2016

Hello, can someone help me? I need a program that send the 20v voltage from mbed analog output pin 18 to a device. also, I can read that on a tear terminal program on the PC. Is that possible? thank you