th_sak
Active Member
Offline
Posts: 141
Thank You
-Given: 150
-Receive: 149
|
|
« on: August 06, 2012, 03:31:41 15:31 » |
|
Hello everyone. I have some issues with this ADC chip. When I try to read back the voltage of any input I always get random numbers. I wrote a program for IAR C compiler which is based on TI's app note SLAA168 "Interfacing the TLC2552 and TLV2542 to the MSP430F149". Any suggestions? Thank's in advance. #include <ioavr.h>
#ifndef _TLC2552_H_ #define _TLC2552_H_
#define uc unsigned char #define ui unsigned int
#warning Define the correct I/O pins in TLC2552.h
/* DDR Definitions */ #define ADC_SCL_DDR DDRC #define ADC_CS_DDR DDRA #define ADC_DO_DDR DDRD
/* PORT Definitions */ #define ADC_SCL_PORT PORTC #define ADC_CS_PORT PORTA #define ADC_DO_PORT PORTD
#define ADC_DO_PIN PIND
/* Pin Definitions */ #define ADC_SCL_Pin 1 #define ADC_CS_Pin 1 #define ADC_DO_Pin 7
void adc_init(void); void adc_reset (void); void toggle_scl (uc times); int adc_read (void);
#endif
#include "delay.h" #include <intrinsics.h> #include <ioavr.h> #include "TLC2552.h"
ui ch_A, ch_B;
void adc_init(void) { ADC_SCL_DDR |= (1<<ADC_SCL_Pin); ADC_CS_DDR |= (1<<ADC_CS_Pin); ADC_DO_DDR &= ~(1<<ADC_DO_Pin); ADC_SCL_PORT &= ~(1<<ADC_SCL_Pin); ADC_CS_PORT |= (1<<ADC_CS_Pin); ADC_DO_PORT &= ~(1<<ADC_DO_Pin); delay_us(10); __watchdog_reset(); }
void adc_reset (void) { uc i; ADC_CS_PORT &= ~(1<<ADC_CS_Pin); __no_operation(); for(i=0;i<6;i++) { ADC_SCL_PORT &= ~(1<<ADC_SCL_Pin); __no_operation(); ADC_SCL_PORT |= (1<<ADC_SCL_Pin); __no_operation(); } ADC_CS_PORT |= (1<<ADC_CS_Pin); __watchdog_reset(); }
void toggle_scl (uc times) { uc i; for(i=0;i<times;i++) { ADC_SCL_PORT &= ~(1<<ADC_SCL_Pin); __no_operation(); ADC_SCL_PORT |= (1<<ADC_SCL_Pin); __no_operation(); } __watchdog_reset(); }
int adc_read (void) { uc i; adc_reset(); ADC_CS_PORT &= ~(1<<ADC_CS_Pin); toggle_scl(16); toggle_scl(32); ADC_CS_PORT |= (1<<ADC_CS_Pin); toggle_scl(8); ADC_CS_PORT &= ~(1<<ADC_CS_Pin); for(i=0;i<16;i++) { ADC_SCL_PORT &= ~(1<<ADC_SCL_Pin); __no_operation(); ADC_SCL_PORT |= (1<<ADC_SCL_Pin); __no_operation(); if(ADC_DO_PIN & (1<<ADC_DO_Pin)) ch_A |= 1; ch_A = ch_A <<1; } ch_A = (ch_A & 0xFFF); toggle_scl(32); ADC_CS_PORT |= (1<<ADC_CS_Pin); toggle_scl(8); ADC_CS_PORT &= ~(1<<ADC_CS_Pin); for(i=0;i<16;i++) { ADC_SCL_PORT &= ~(1<<ADC_SCL_Pin); __no_operation(); ADC_SCL_PORT |= (1<<ADC_SCL_Pin); __no_operation(); if(ADC_DO_PIN & (1<<ADC_DO_Pin)) ch_B |= 1; ch_B = ch_B <<1; } ch_B = (ch_B & 0xFFF);
toggle_scl(32); ADC_CS_PORT |= (1<<ADC_CS_Pin); toggle_scl(8); ADC_CS_PORT &= ~(1<<ADC_CS_Pin);
__watchdog_reset(); return(ch_A); }
|
|
|
Logged
|
|
|
|
Ganymed
Newbie
Offline
Posts: 9
Thank You
-Given: 4
-Receive: 7
|
|
« Reply #1 on: January 09, 2013, 01:46:21 13:46 » |
|
I think you have a mistake in the adc_read-function. You should read the output data on the falling edge of SCL. The output data changes on the rising edge of SCL. And why do you set the CL-Signal to low at the end of the function?
|
|
|
Logged
|
|
|
|
th_sak
Active Member
Offline
Posts: 141
Thank You
-Given: 150
-Receive: 149
|
|
« Reply #2 on: January 09, 2013, 03:26:05 15:26 » |
|
Thank's for the answer, but I have solved the problem. Here is the working code for reading channel1: #include "delay.h" #include <intrinsics.h> #include <ioavr.h> #include "TLC2552.h"
volatile ui ch_A, ch_B;
void adc_init(void) { ADC_SCL_DDR |= (1<<ADC_SCL_Pin); ADC_CS_DDR |= (1<<ADC_CS_Pin); ADC_DO_DDR &= ~(1<<ADC_DO_Pin); ADC_SCL_PORT &= ~(1<<ADC_SCL_Pin); ADC_CS_PORT |= (1<<ADC_CS_Pin); ADC_DO_PORT &= ~(1<<ADC_DO_Pin); delay_us(10); }
void adc_reset (void) { uc i; ADC_CS_PORT &= ~(1<<ADC_CS_Pin); for(i=0;i<5;i++) { ADC_SCL_PORT &= ~(1<<ADC_SCL_Pin); delay_us(1); ADC_SCL_PORT |= (1<<ADC_SCL_Pin); delay_us(1); } ADC_CS_PORT |= (1<<ADC_CS_Pin); }
void toggle_scl (uc times) { uc i; for(i=0;i<times;i++) { ADC_SCL_PORT &= ~(1<<ADC_SCL_Pin); delay_us(1); ADC_SCL_PORT |= (1<<ADC_SCL_Pin); delay_us(1); } }
void adc_read1 (void) { ADC_CS_PORT &= ~(1<<ADC_CS_Pin); toggle_scl(16); toggle_scl(32); }
int adc_read (void) { uc i;
ADC_CS_PORT &= ~(1<<ADC_CS_Pin); for(i=0;i<16;i++) { if(ADC_DO_PIN & (1<<ADC_DO_Pin)) ch_A |= 1; ch_A <<= 1; ADC_SCL_PORT |= (1<<ADC_SCL_Pin); delay_us(1); ADC_SCL_PORT &= ~(1<<ADC_SCL_Pin); } ch_A >>= 4; ch_A &= 0x0FFF; toggle_scl(32); ADC_CS_PORT |= (1<<ADC_CS_Pin); toggle_scl(8); ADC_CS_PORT &= ~(1<<ADC_CS_Pin);
for(i=0;i<16;i++) {
if(ADC_DO_PIN & (1<<ADC_DO_Pin)) ch_B |= 1; ch_B <<= 1; ADC_SCL_PORT |= (1<<ADC_SCL_Pin); delay_us(1); ADC_SCL_PORT &= ~(1<<ADC_SCL_Pin); } ch_B >>= 4; ch_B &= 0x0FFF; toggle_scl(32); ADC_CS_PORT |= (1<<ADC_CS_Pin); toggle_scl(8); return(ch_A); }
|
|
|
Logged
|
|
|
|
Ganymed
Newbie
Offline
Posts: 9
Thank You
-Given: 4
-Receive: 7
|
|
« Reply #3 on: January 09, 2013, 04:04:37 16:04 » |
|
This modification is exactly what I meant. Nice to hear that it work.
|
|
|
Logged
|
|
|
|
flo0319
Junior Member
Offline
Posts: 81
Thank You
-Given: 7
-Receive: 17
|
|
« Reply #4 on: January 12, 2013, 09:28:16 09:28 » |
|
Why do you not use SPI port? and for what needs you 12bits ADC and is not enough 10bits ADC? you prefer to lose 3 pins with TLC2552 and not just 1 pin with internal ADC?
if you need more then 10bits for ADC you can make a Pseudo-resolution, you read 4 (or more) consecutive values for the same channel and every value you can shift to 12 or 14 bits, after this you can calculate an average value that is on 12 or 14 bits.
|
|
|
Logged
|
|
|
|
metal
Global Moderator
Hero Member
Offline
Posts: 2420
Thank You
-Given: 862
-Receive: 678
Top Topic Starter
|
|
« Reply #5 on: January 12, 2013, 03:34:18 15:34 » |
|
Yes you are right, he could use the SPI port. He used 12-bit ADC because he needs it!?
Do you have a working (over-sampling) code for your suggestion that we can try here?
|
|
|
Logged
|
|
|
|
flo0319
Junior Member
Offline
Posts: 81
Thank You
-Given: 7
-Receive: 17
|
|
« Reply #6 on: January 12, 2013, 05:54:11 17:54 » |
|
Yes you are right, he could use the SPI port. He used 12-bit ADC because he needs it!?
Do you have a working (over-sampling) code for your suggestion that we can try here?
I can write an example: for (i=0 :i<10;i++) // 10 reads { ad12_temp_values[i] = adc_read(channel) << 2 ; // suppose that adc_read() return a 10bits value right aligned //_delay_us(100); // between 2 consecutive reads can be inserted a delay, this delay depends of project type or ADC speed } ch0_12b_value = 0; for(i=0;i<10;i++) ch0_12b_value+=ad12_temp_values[i];
ch0_12b_value /=10;
|
|
|
Logged
|
|
|
|
solutions
Hero Member
Offline
Posts: 1826
Thank You
-Given: 656
-Receive: 905
|
|
« Reply #7 on: January 12, 2013, 07:02:31 19:02 » |
|
Why do you not use SPI port? and for what needs you 12bits ADC and is not enough 10bits ADC? you prefer to lose 3 pins with TLC2552 and not just 1 pin with internal ADC?
if you need more then 10bits for ADC you can make a Pseudo-resolution, you read 4 (or more) consecutive values for the same channel and every value you can shift to 12 or 14 bits, after this you can calculate an average value that is on 12 or 14 bits.
That's magical. While I know you can average noise with oversampling to get more SNR out of a signal, I don't see how you can get beyond the n-bit quantization limit of the hardware. If I shift right 8 for each reading, then average 256 samples, do I get an 18 bit ADC? Do you have a published reference for this alchemy you are proposing? thanks
|
|
|
Logged
|
|
|
|
flo0319
Junior Member
Offline
Posts: 81
Thank You
-Given: 7
-Receive: 17
|
|
« Reply #8 on: January 12, 2013, 08:09:37 20:09 » |
|
You can not increase your hardware capabilities, but because what you read is not very stable , the LSB bit can oscillate and if you make 10 reads you can have some values with +/- 1 or 2 bits, so, if you shift this values with 2 or 4 bits when average is calculated the value is in really 12 or 14 bits,
the average is just a good approximation for the real value, for ex. with 4.096V AD reference and 10 bits resolution for every bit you have 4mV, if you signal is between 398mV and 402mV your value is 100, but some times this signal can oscillate between 397mV and 399mV or between 401mV and 403V, you can achieve a good accuracy with just 10bits ADC but with a pseudo resolution of 12 or 14 bits
|
|
|
Logged
|
|
|
|
metal
Global Moderator
Hero Member
Offline
Posts: 2420
Thank You
-Given: 862
-Receive: 678
Top Topic Starter
|
|
« Reply #9 on: January 12, 2013, 10:58:50 22:58 » |
|
I do remember now (after I accidentally found my files!). I did some work on this topic back in October 2012 along with Proteus simulation. I took the required files from this project. I only used required functions that yielded 11 bit resolution. Later on modified it to get 12 bit resolution after I tried to understand what really was going on. The original project has apparently used 11-bit oversampling. If you look at page 8 in doc8003.pdf, the parameters appear to be correct in Guido's codes in analog.c When I tried to understand what he did and read more in that document, I modified the necessary parameters to accommodate it for 12 bit resolution, I also modified new_analog_u_result type from int16_t to int32_t. Actually, it works very well!? But I 've never tried it in the real world. I don't know how accurately I followed that document, may be more people are interested in trying it on a real HW. P.S. solutions: hope your monitor is not faded ;- )
|
|
|
Logged
|
|
|
|
flo0319
Junior Member
Offline
Posts: 81
Thank You
-Given: 7
-Receive: 17
|
|
« Reply #10 on: January 12, 2013, 11:25:17 23:25 » |
|
your code: raw_analog_u_result[chpos]=currentadc; // // we do 16 bit oversampling to get 12bit ADC resolution chpos=(chpos+1)%16; // rotate over 16 //analog_result[1]=0;[font=Verdana][b] while(i<16){ new_analog_u_result+=raw_analog_u_result[i]; i++; }[/b][/font] new_analog_u_result=new_analog_u_result>>2; // 12bit
in your code when add all 16s values from raw_analog_u_result[] it's like (n<<4), so in this mode you have 14bits value, after this you have a (n>>2) for making to 12bits. I have used this method at a filter for an acceleration sensor in a slot car, but is very important what you need to do. In this project I have used the acceleration variation and not the instant acceleration. So @solutions, now I hope that you think is not "MAGICAL" anymore
|
|
« Last Edit: January 12, 2013, 11:29:57 23:29 by flo0319 »
|
Logged
|
|
|
|
Ichan
Hero Member
Offline
Posts: 833
Thank You
-Given: 312
-Receive: 392
|
|
« Reply #11 on: January 13, 2013, 06:47:59 06:47 » |
|
Others may have different experience, but for me oversampling to get higher resolution is just doesn't work. The natural existence of white noise (i call it random of random noise) on the input signal is a very rare, mostly we deal with powerline noise (hum) which is not random enough (periodic and quite constant amplitude). I ever read some about specially injecting white noise on the input to get a good oversampling result, but i don't remember where. Metal, i play a bit with your files, make a little modifications: - adc ratiometric reading, where the adc input feed from external vref via resistor devider - 1/10 in this case.
- modify the code so the adc ref is to external vref, and display the value of ADC directly not converting it float or any.
- read and display both ch0 which is 10 bit and ch1 which is oversampled to 12 bit (in your code).
- nothing else
Attached the screen capture of isis and all other files, look at the lcd display: - First line is 10 bit ch0 reading:
- 102 on the right is the adc value which is true as int(1024/10) = 102
- 408 on the left is the adc value scaled up to 12 bit (<< 2) for comparison.
- Second line is 12 bit oversampled ch1 reading:
- 407 on the left is adc value which is wrong, it should be 410 as int(4096/10) = 410 (or maybe 409)
- 101 on the right is adc value scaled down to 10 bit (>> 2) again for comparison.
So it doesn't work on proteus - some years ago i experienced this with real hardware, even worst. It will be good if anyone tried themself in real, and share the experience. -ichan.
|
|
|
Logged
|
There is Gray, not only Black or White.
|
|
|
flo0319
Junior Member
Offline
Posts: 81
Thank You
-Given: 7
-Receive: 17
|
|
« Reply #12 on: January 13, 2013, 08:39:46 08:39 » |
|
@Ichan , in @metal program for channel 1 is used a filter with 15 old value + instant value, but for channel 0 is used just the instant value from this reason is a little difference between channel 1 and channel 0, if you put a POT to input and insert down to low signal , you can view that filter work good. the main project was digital power source http://www.tuxgraphics.org/electronics/201005/bench-power-supply-v3.shtml, where is used oversampling for the voltage control loop. also, in your ex. you use an external reference what is the + for resistive divider, so, any variation in reference is canceled by this configuration, but in a project you want to measure external signals and not to watch at 10% from your reference, because this value anytime will be 10% with a simulator we need to know how to work, if you simulate just ideal signals, never can have good performance in real environment. this topic start from an external adc converter with 12 bits resolution, are all 12bits necessary? or 10bits with oversampling is enough?
|
|
|
Logged
|
|
|
|
th_sak
Active Member
Offline
Posts: 141
Thank You
-Given: 150
-Receive: 149
|
|
« Reply #13 on: January 13, 2013, 11:35:53 11:35 » |
|
Why do you not use SPI port? and for what needs you 12bits ADC and is not enough 10bits ADC? you prefer to lose 3 pins with TLC2552 and not just 1 pin with internal ADC?
if you need more then 10bits for ADC you can make a Pseudo-resolution, you read 4 (or more) consecutive values for the same channel and every value you can shift to 12 or 14 bits, after this you can calculate an average value that is on 12 or 14 bits.
I didn't use hardware SPI because I want to connect DO, SCL, CS in pins that are note connected with the internal SPI peripheral. If you see the .h file in my first post you will understand. For my application 10bits are not enough. I'm using a DAC also connected to the same pins, except for the CS pin of course and I don't mind loosing some pins in order to have accuracy in my measurements. I'm aware of AVR121: Enhancing ADC resolution by oversampling, but I'm not a fan of empiric ways like this.
|
|
« Last Edit: January 13, 2013, 12:05:47 12:05 by th_sak »
|
Logged
|
|
|
|
flo0319
Junior Member
Offline
Posts: 81
Thank You
-Given: 7
-Receive: 17
|
|
« Reply #14 on: January 13, 2013, 12:25:13 12:25 » |
|
What type of signal use you for input? and also if you use atmega32 why do you not use 16PWM on Timer1 for DAC?
Anybody can use what he want, I just try to make some suggestion
|
|
|
Logged
|
|
|
|
metal
Global Moderator
Hero Member
Offline
Posts: 2420
Thank You
-Given: 862
-Receive: 678
Top Topic Starter
|
|
« Reply #15 on: January 13, 2013, 01:07:25 13:07 » |
|
If you watched Dave Jones videos when he designed the PSU, he examined the possibility of using PWM, and results were not satisfying, so using a resistor ladder DAC is much better, less noise and stable without the need to design a filter that will finally not yield the desired results. I remember he used a DAC IC, not a resistor ladder, but the idea of using PWM is not favorable here.
|
|
« Last Edit: January 13, 2013, 01:09:43 13:09 by metal »
|
Logged
|
|
|
|
solutions
Hero Member
Offline
Posts: 1826
Thank You
-Given: 656
-Receive: 905
|
|
« Reply #16 on: January 13, 2013, 08:18:03 20:18 » |
|
I didn't use hardware SPI because I want to connect DO, SCL, CS in pins that are note connected with the internal SPI peripheral. If you see the .h file in my first post you will understand. For my application 10bits are not enough.
How about 16? http://www.maximintegrated.com/datasheet/index.mvp/id/3068
|
|
|
Logged
|
|
|
|
th_sak
Active Member
Offline
Posts: 141
Thank You
-Given: 150
-Receive: 149
|
|
« Reply #17 on: January 14, 2013, 05:02:00 17:02 » |
|
I'm making a digitally controlled power supply and I want to achieve high resolution in both output voltage and output current measurements. Before I select this ADC I was searching for a few days in MAXIM and TI and I found a lot of chips available as samples, but this is a hobby project and I don't wand to play around with SSOP chips with fine pitch pins. Thank's for the suggestions, I already know these technics, I'm not a beginner, but as I said in my previous message I don't like tricks and empiric ways just to make a less expensive but more complicated circuit, that probably won't work.
|
|
|
Logged
|
|
|
|
flo0319
Junior Member
Offline
Posts: 81
Thank You
-Given: 7
-Receive: 17
|
|
« Reply #18 on: January 14, 2013, 06:11:36 18:11 » |
|
I understand now. I suppose that you want to use an open loop control and a large scale. If you can change your pins assigned I suggest you to use SPI for communication with ADC and DAC. With software SPI the MCU work to much (I think this is not so important for you now) , using interrupts on hardware spi you can write a routine for automatic read (from ADC) and write (to DAC) with a predefined constant frequency, and in main loop you need to make just HMI and power control.
|
|
|
Logged
|
|
|
|
|