B.Noll 5 Posted June 9, 2011 Share Posted June 9, 2011 While searching an ADC samplecode for the g2231 I found one that made use of the floating point lib to get an accurate reading of the ADC return value. As the g2231 is a 2k chip that is a silly thing to do. The goal for the code was to get an accuracy that is similar to a 4 digit DMM. Ok, let's think about this. When using the internal reference (2.5V) the resolution we can get is 2.5V / 1024 = 0.002441 Volt. We can see that the last digit will jump because 10 BIT is not enough. Ok, let's try the 2nd reference with 1.5V / 1024 = 0.001468. Not to bad but still not good enough. Also I'de like to have a range from 0-2.5 V. By testing the code I mentioned before a constant had been used to make the reading look accurate, however, as there was only one constant in use to correct the ADC the result was quite poor compared to a DMM. As we all know in real life there is no perfect ADC and if we only have the linear errors in mind we will find at least an offset and a gain error. So the problem to solve looked like: - avoid floating point - get the accuracy of floating point - correct the ADC errors - get more then 10 BIT out of the g2231 The following code will do what we need and the codesize is only 576 Byte. I used a well know oversampling technique to get 12 BIT out of the ADC and calculate all corrections by fixed point arithmetic. Instead of calculating on a base by 10 I used base 2 instead as this will allow us to get the result by a simple shift operation. Once the code was working I could still see some jumps in the last digit caused by a ripple of arround 4 mVolt caused by the poor USB powersource of the Launchpad. So I have added also a low pass filter in Software to get rid of the remaining noise. The ADC result will be displayed @ the MSP430 USB Application COM Port. I have used the Soft. Uart code by NJC but slightly modified it to have a putChar function. To adjust your ADC and get the RawValues (AdcRawHigh, AdcRawLow) for the calculation of the constants use "return (AvgSum >> 8);" instead of the original return statement "return AdcVal;" and ignore the decimal point. In function "AdcValOut" use "while (m != 4)" to display all digits of the RawValues. So here we are, let me share this code snippet with you. Please try out the code and let me know your findings. Have fun, Bernd g2231AdcTestCode.c RobG, lvagasi, Rickta59 and 2 others 5 Quote Link to post Share on other sites
bluehash 1,581 Posted June 9, 2011 Share Posted June 9, 2011 Thanks for sharing your code B.Noll and welcome to the Forums! Quote Link to post Share on other sites
Mac 67 Posted June 10, 2011 Share Posted June 10, 2011 Bernd, may I ask which compiler you're using, please? I can't seem to find "inttypes.h" in my CCSv4 install... Cheerful regards, Mike Quote Link to post Share on other sites
B.Noll 5 Posted June 10, 2011 Author Share Posted June 10, 2011 Hi Mike, I use IAR EWB but inttypes.h belongs to the standard library so you should have it somewhere. http://en.wikipedia.org/wiki/Inttypes.h Have a look. Quote Link to post Share on other sites
gordon 229 Posted June 10, 2011 Share Posted June 10, 2011 inttypes.h is a C99 thing, though. According to this and this, CCS is C89. Quote Link to post Share on other sites
Mac 67 Posted June 10, 2011 Share Posted June 10, 2011 Hi Mike, I use IAR EWB but inttypes.h belongs to the standard library so you should have it somewhere. http://en.wikipedia.org/wiki/Inttypes.h Have a look. Hi Bernd, Thank you, I found the "inttypes.h" file. And thank you for posting a very nice example program and method for MSP430. Cheerful regards, Mike Quote Link to post Share on other sites
RobG 1,892 Posted June 10, 2011 Share Posted June 10, 2011 @B.Noll If you want to avoid floating point, you can use reference that divides by 1024, like I did. Quote Link to post Share on other sites
B.Noll 5 Posted June 10, 2011 Author Share Posted June 10, 2011 Hi Rob, you didn't check the given code, I do not make use of floating point. I found an example that did it but of course it make no sense at all. I do all corrections by fixed point arithmetic and simple shift operations. Bernd Quote Link to post Share on other sites
B.Noll 5 Posted June 10, 2011 Author Share Posted June 10, 2011 Rob, I followed the given link but to be honest, I can not see any error correction at all. Second option is internal Vref (1.5V or 2.5V) which is much better choice but the result has to be also calculated. Of course and my example shows how to do it in a very effective way by also getting a 12 BIT result + Filter. Quote Link to post Share on other sites
RobG 1,892 Posted June 10, 2011 Share Posted June 10, 2011 Don't get me wrong, I think you did a great job with your code, I am just suggesting another way of dealing with the calculation problem and no, I do not have any error correction or averaging in my example. Personally, I am not a big fan of oversampling, I just think getting 12bit resolution from a 10bit ADC is a little bit (or 2bit) silly Quote Link to post Share on other sites
B.Noll 5 Posted June 11, 2011 Author Share Posted June 11, 2011 Hi Rob, I just think getting 12bit resolution from a 10bit ADC is a little bit (or 2bit) silly I don't think so as I already explained before the resolution we can get is 2.5V / 1024 = 0.002441 Volt = 2.44 mVolt. For a 4 digit DMM you need a resolution of 1 mVolt so we need oversampling here. Lets have a look at your explanation... (2500mV/1024) * ADC10ME It's actually 2500/1023, but for simplicity let's use 1024... 2500/1023 is wrong even if you find such an example calculation in some data sheets. You have to count the 0 as well. Example: 0000000000 is your 1st return code from a 10 BIT ADC 0000000001 0000........... 1111111111 is your last so from 0 - 1023 = 1024 and your calculation is correct :-) The maximum return value is 1023 but the steps that a 10 BIT ADC can do is 1024. Cheers, Bernd Quote Link to post Share on other sites
RobG 1,892 Posted June 11, 2011 Share Posted June 11, 2011 Hi Rob, I just think getting 12bit resolution from a 10bit ADC is a little bit (or 2bit) silly I don't think so as I already explained before the resolution we can get is 2.5V / 1024 = 0.002441 Volt = 2.44 mVolt. For a 4 digit DMM you need a resolution of 1 mVolt so we need oversampling here. Just because you need 1mV resolution, doesn't mean you can get it. Oversampling works by assumption and it works best for things like audio or video signals, where there's a constant change, and not so well for measuring, especially when DC is involved. For example, you have a 4bit ADC, from 0V-15V. You oversample it to get 6bit resolution, or 0.25V. When the voltage falls from 1V down to 0V in let's say sampletime * 4, you'll get the following readings: 0.75V, 0.5V, 0.25V, 0V. Now, when your voltage falls from 1V down to 0.6V, then back up to 1V, and back to 0.6V, your reading will be steady 1V. Then when it falls to 0.4V, your readings will be... 0.75V, 0.5V, 0.25V, 0V and will stay at 0V. So it looks like accuracy is there, but it's false. When I get some time, I will support it with drawings. Lets have a look at your explanation... (2500mV/1024) * ADC10ME It's actually 2500/1023, but for simplicity let's use 1024... 2500/1023 is wrong even if you find such an example calculation in some data sheets. You have to count the 0 as well. Example: 0000000000 is your 1st return code from a 10 BIT ADC 0000000001 0000........... 1111111111 is your last so from 0 - 1023 = 1024 and your calculation is correct :-) The maximum return value is 1023 but the steps that a 10 BIT ADC can do is 1024. Cheers, Bernd My calculations are correct, but not with 1024, 1023 should be used. Here's 2bit example, reference voltage is 4V. Resolution according calculations you are suggesting: 4V/4(2bit) = 1V, so 00=0V, 01=1V, 10=2V, 11=3V, looks like 4V will be displayed as 3V. According to calculations that should be used, 4V/(4(2bit)-1)=1.33V, and 00=0V, 01=1.33V, 10=2.66, 11=4V, full range from 0v-4V. Here's another example, 3bit, 8V ref. 000-001-010-011-100-101-110-111 bad, 8V/8(3bit) 0V-1V-2V-3V-4V-5V-6V-7V good, 8V/(8(3bit)-1) 0V-1.14V-2.29V-3.43V-4.57V-5.71V-6.86V-8V As you can see, you have to always subtract one when calculating steps, otherwise you will get the number of possible values, not the step. And I think I will stick to datasheets. Quote Link to post Share on other sites
B.Noll 5 Posted June 11, 2011 Author Share Posted June 11, 2011 Mh, intersting discussion :-) Ok, let's take a 2 BIT ADC and let's assume a range of 0-4 V. The result we get: ADC Value 0V + | 00 | | 1V + | 01 | | 2V + | 10 | | 3V + | 11 | | 4V + So the ADC will divide the range from 0-4 V in 4 portions, each has a range of 1V. The key point is how many different numbers can be generated by 2 BIT's and that's exactly 4 because 0 is a number as well. Keep in mind that an ADC return value does not stand for a sepcific Voltage, it stands for a range of Volt. If the return value of the ADC is 10 (decimal = 2) then the Voltage is somewhere in the range between 2V - 3V. Where exactly ? we dont know. Let's think about a 10 BIT ADC. This time you will get 4/1024 portions. The range of each portion will become smaller but this does not mean that we have less then 1024. However, the last ADC Value will be 1024-1. So think about it. In respect to the oversampling example you gave I would agree but if you use a 10 BIT ADC and calculate the noise you need to make that oversampling then I can tell you by experience that getting 2 BIT's more is very easy. Simply test the code on your Launchpad and put a DMM beside it. If you want to have more details, please have a look. http://www.atmel.com/dyn/resources/prod ... oc8003.pdf Bernd Quote Link to post Share on other sites
RobG 1,892 Posted June 11, 2011 Share Posted June 11, 2011 Let's start off with oversampling. I will continue to insist that it is good but only for a specific applications. Oversampling is based on assumption that if first measurement was A and the second measurement was B, the value must be exactly (A+B)/2 or for two bit, (A+B+C+D)/4. You cannot get detail from nothing. It's like in those movies where they "enhance" a blurry photo and are able to reproduce the entire page of text from 4x4 pixel area. So the ranges are 0-1, 1-2, 2-3, 3-4, that's 4 ranges that you can have with 4bit. Now, how do you display 0-1, 0 or 1? 1-2, 1 or 2? 2-3, 2 or 3? 3-4, 3 or 4? If you decide to go lower, you will have 0-3, if higher then 1-4. You would need 5 values to display a full range 0-4. 0.0-0.4, 0.5-1.4, 1.5-2.4, 2.5-3.4, 3.5-4.0 If you divide ref by 3, you can cover the entire range with 4 values 0-0.6, 0.7-2.0, 2.1-3.4, 3.5-4.0 Quote Link to post Share on other sites
oPossum 1,083 Posted June 11, 2011 Share Posted June 11, 2011 The lowest and highest codes returned by the ADC are 1/2 LSB wide as Rob has explained. This is necessary to ensure that those codes represent VrefLow and VrefHigh +/- 1/2 LSB. Averaging will give you an average reading - nothing more. It does not provide more ENOB or "filter out the noise." One huge flaw in the Atmel app note is the lack of attention to quantization error. You can't just filter it out. If you want 10 ENOB use a SAR ADC with 12 bits. The ENOB will always be less than the physical bit count. Using a SAR ADC for a DMM is a poor choice. It should be dual slope or quad slope. A good sigma delta would be OK, but not great. Quote Link to post Share on other sites
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.