|
|
View previous topic :: View next topic |
Author |
Message |
art
Joined: 21 May 2015 Posts: 181
|
ADS1115 problem |
Posted: Fri Mar 13, 2020 1:31 am |
|
|
Hi,
i've build an ADC project using ADS1115 module (16bit ADC) and connect to PIC18F4550. My code below works, however the lsb output increase by 16. Why it increase by 16? It should increase by 1 from 0,1,2,3,4.....255. Please help me how to fix this problem.
Code: |
#include <18F4550.h>
#fuses HS,HSPLL,NOWDT,NOPROTECT,NOLVP,NODEBUG,USBDIV,PLL5,CPUDIV1,VREGEN
#device ADC=10 //8
#use delay(clock=48000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7,ERRORS)
#include <string.h>
#include <input.c>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <ctype.h>
#include <74595.c>
#include <usb_cdc.h>
#use i2c(Master,sda=PIN_B2,scl=PIN_B3,FORCE_SW)
void main()
{
char c;
char d,key;
usb_init_cs();
while (TRUE)
{
usb_task();
if (usb_cdc_kbhit())
{
c=usb_cdc_getc();
if (c=='\n') {putc('\r'); putc('\n');}
if (c=='\r') {putc('\r'); putc('\n');}
while(true)
{
ART:
d = usb_cdc_getc();
if(d=='F') // push F for ADC Measurement
{
while (key!=32) // push SPACE BAR to stop
{
int1 flag0;
int1 flag1;
int1 flag2;
int1 flag3;
int1 flag4;
int1 flag5;
int1 flag6;
long int msb;
long int lsb;
while(1){
//after a writing, flags go to 0 if master received ACK from slave
flag0=1;
flag1=1;
flag2=1;
flag3=1;
flag4=1;
flag5=1;
flag6=1;
//-------------------------configuration--------------------------------//
i2c_start();
flag0=i2c_write(0b10010000); // address = 0x90 | 0 -> write
flag1=i2c_write(0b00000001); // 0x01 -> config register
flag2=i2c_write(0b10100011); // 1 -> os, 010 -> an1-an3, 001 -> +-4.096 range, 0/1 -> continuous/single conversion
flag3=i2c_write(0b10000011); // default
i2c_stop();
//----------------------------reading-----------------------------------//
i2c_start();
flag4=i2c_write(0b10010000); // address = 0x90 | 0 -> write
flag5=i2c_write(0b00000000); // 0x00/0x01 -> conversion/config register
i2c_stop();
delay_ms(100);
i2c_start();
flag6=i2c_write(0b10010001); // address = 0x90 | 1 -> read
msb = i2c_read();
lsb = i2c_read(0); // No ACK from master
i2c_stop();
//----------------------------output------------------------------------//
delay_ms(500);
printf(usb_cdc_putc," %li\n ", lsb);
}
} key=0;
}
}
}
}
}
|
Code: |
0
16
32
48
64
80
96
112
128
144
160
176
192
208
224
240
0 (reading will repeat from 0 --> 240)
|
|
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19518
|
|
Posted: Fri Mar 13, 2020 3:20 am |
|
|
So what are you actually applying to the Ain1 input to generate these values?.
Personally, I'd time things very differently. Trigger the conversion, then pause,
Then select the result register, and read immediately. Assuming that the
register will remain latched for a long pause, is asking a lot.
Your pause for conversion only needs to be 8mSec.
General comments:
Avoid using terms like 'long'. Explicitly declare variables the size you want
them. It'll avoid problems later...
Why are you declaring the variables that can only receive 'bytes' as 'long'?.
Waste of space.
Give your definitions and config values 'names':
Code: |
#include <18F4550.h>
#fuses HS,HSPLL,NOWDT,NOPROTECT,NOLVP,NODEBUG,USBDIV,PLL5,CPUDIV1,VREGEN
#device ADC=10 //8
#use delay(clock=48000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7,ERRORS)
#include <string.h>
#include <input.c>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <ctype.h>
#include <74595.c>
#include <usb_cdc.h>
#use i2c(Master,sda=PIN_B2,scl=PIN_B3,FORCE_SW)
#define CONFIG_REG 1
#define CONV_RESULT 0
#define CHIP_ADDR 0x90
#define RD 1
//MSB config
#define FOUR096 (0b001<<1) //4.096v
#define AN1AND3 (0b010<<4) //AN1 & AN3
#define SINGLE 1 //single conversion
#define START 0x80 //start conversion
//LSB config
#define SPS128 (0b100<<5) //128 samples/second
#define COMP_OFF (0b00011) //comparator disabled
//generally declare the variables once at the start of the code. Inline
//is 'nominally' supported, but can cause issues.
void main(void)
{
char d;
union {
BYTE bytes[2];
signed int16 value;
} combiner;
int1 run_adc=FALSE;
int1 flag0;
int1 flag1;
int1 flag2;
int1 flag3;
int1 flag4;
int1 flag5;
int1 flag6;
usb_init_cs();
while(TRUE)
{
usb_task();
if (usb_cdc_kbhit())
{
d=usb_cdc_getc();
//F starts conversions space stops
if (d=='F')
run_adc=TRUE; //start conversions
if (d==' ')
run_adc=FALSE; //stop conversions
}
if (run_adc)
{
i2c_start();
flag0=i2c_write(CHIP_ADDR); // address = 0x90 | 0 -> write
flag1=i2c_write(CONFIG_REG); // 0x01 -> config register
flag2=i2c_write(START | SINGLE | AN1AND3 | FOUR096); // 1 -> os, 010 -> an1-an3, 001 -> +-4.096 range, 0/1 -> continuous/single conversion
flag3=i2c_write(SPS128 | COMP_OFF); // default
i2c_stop();
//Now pause for conversion
//----------------------------reading-----------------------------------//
delay_ms(10);
i2c_start();
flag4=i2c_write(CHIP_ADDR); // address = 0x90 | 0 -> write
flag5=i2c_write(CONV_RESULT); // select result register
i2c_start(); //restart
flag6=i2c_write(CHIP_ADDR | RD); // address = 0x90 | 1 -> read
combiner.bytes[1]= i2c_read();
combiner.bytes[0]= i2c_read(0); // No ACK from master
i2c_stop();
//--------------
//display result - should give correctly signed value
printf(usb_cdc_putc,"VALUE %ld\n ", combiner.value);
//print the LSB for diagnostics
printf(usb_cdc_putc,"LSB %u\n ", combiner.bytes[0]);
delay_ms(600); //delay to slow down
}
}
}
|
|
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9229 Location: Greensville,Ontario
|
|
Posted: Fri Mar 13, 2020 5:04 am |
|
|
On the analog side.....
ANY ADC over 8 bits MUST have GREAT attention to PCB, layout, filtering, shielding, PSU design, etc. !
For testing, use a high precision voltage reference NOT a pot connected to VDD. Hopefully you have a quality oscilloscope to monitor the analog signal.
You can short the input with a 2" length of wire. Take 1000 readings, they should all be zero.....but I'll bet they won't be. |
|
|
LostInSpace
Joined: 09 Mar 2010 Posts: 13
|
|
Posted: Sat Mar 14, 2020 12:05 am |
|
|
There is some chatter on the web that this part requires 'repeated-start' I2C commands instead of 'Stop' then 'Start' to work correctly. Might be worth looking into. Hope this helps. _________________ HTH - Steve H. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19518
|
|
Posted: Sat Mar 14, 2020 1:26 am |
|
|
If you look at the suggestion I posted, that is what I did.
Quite a few chips require the address change to be done that way, which
is why I used this. So 'not surprised' if there is an issue using the stop
start approach (though the data sheet does say this should be OK). The
example in the data sheet does it using a restart. |
|
|
art
Joined: 21 May 2015 Posts: 181
|
|
Posted: Sat Mar 14, 2020 9:53 pm |
|
|
Dear Ttelmah
Quote: | Your pause for conversion only needs to be 8mSec. |
I did not see, where you put this 8mSec in your code ? |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19518
|
|
Posted: Sun Mar 15, 2020 4:15 am |
|
|
I put 10mSec. The conversion takes nominally 7.8mSec, so 10 seemed a
sensible value allowing for error in the clocks.
The AD1115, specifies it's internal oscillator as +/- 10%, while the PIC
is running off a crystal, so should be better than 0.005%. Total max
error is then just over 10%. Allowing this means the worst case timing
could be up to 8.6uSec. So 10, gives a nice little margin... |
|
|
art
Joined: 21 May 2015 Posts: 181
|
|
Posted: Sun Mar 15, 2020 7:53 pm |
|
|
Dear Ttelmah
I've just test your code and it gives the same result as mine, when i increase input voltage from 0V onwards. Result as below:
VALUE 0
VALUE 16
VALUE 32
VALUE 48
VALUE 64
......
Problem is no VALUE 1,2,3....15. Why? |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9229 Location: Greensville,Ontario
|
|
Posted: Sun Mar 15, 2020 8:03 pm |
|
|
Try a simple program...
Have it JUST increment and send numbers to your PC (0 to 65535), with a small time delay between sends (say 250ms).
Confirm THAT works.
Show us your program and tell us what happens.
It could be something on the PC side (terminal prgram not setup correctly). |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19518
|
|
Posted: Mon Mar 16, 2020 12:43 am |
|
|
As Jay says rule out everything else.
If is still doesn't work I'd say you have a faulty/damaged chip.
Almost 'classic' for a chip that is not actually genuine. Where did you
buy it from?. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Mon Mar 16, 2020 12:58 am |
|
|
art wrote: |
VALUE 0
VALUE 16
VALUE 32
VALUE 48
VALUE 64
Problem is no VALUE 1,2,3....15. Why?
|
Ttelmah asked you a question about this:
Ttelmah wrote: | What are you actually applying to the Ain1 input to generate these values ? |
Please answer the question. |
|
|
art
Joined: 21 May 2015 Posts: 181
|
|
Posted: Mon Mar 16, 2020 1:22 am |
|
|
Dear PCM programmer
I connect a 60V DC power supply to a series of resistor. Output of 4.096V connect to AN1 and AN3 of ADS1115. |
|
|
art
Joined: 21 May 2015 Posts: 181
|
|
Posted: Mon Mar 16, 2020 1:53 am |
|
|
Dear Ttelmah
Quote: |
Almost 'classic' for a chip that is not actually genuine. Where did you
buy it from?
|
I bought it from SHOPEE for only USD1.50. Maybe it is not genuine. I'm thinking of replacing the IC on the module with the genuine parts. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19518
|
|
Posted: Mon Mar 16, 2020 2:39 am |
|
|
Seriously if you have 60v anywhere near to the chip you risk destroying it.
A 'series resistor' is not a safe way to generate a voltage for this. You
need some form of hardware protection to absolutely ensure the input
voltage cannot go above the supply.
Note the comments in the data sheet where it tells you that if the
input protection diodes may be turned on by the voltage you supply,
you should add your own external Schottky protection diodes...
What is your Vdd?.
What you are saying, does not give how you are changing the input
voltage to give the different values. You would need to change the input
voltage by 0.000125v to give a single step of the detected value. A
count of '16', corresponds to 2mV change.
If this value is being divided by resistors, you do realise that
unless these are ultra high precision types, the division will be inaccurate.
Also, the input load the chip generates changes as it samples. So a divider
that gives a voltage of xxV before sampling will give a different value when
it is actually sampling. If you want to read a voltage from a potential
divider, you need a precision op-amp to give a stable voltage as the
chip reads.
You do realise the chip does not read the voltage on AN1?. It reads the
_difference_ in voltage between AN1, and AN3. What is AN3
connected to?.
Searches 'online' reveal people talking about the Chinese 'knock off'
versions of this chip running 'out of spec slow', and that the best
way to work is to wire the ALERT line and test for this, before reading. |
|
|
Juzujka
Joined: 15 Oct 2020 Posts: 1
|
|
Posted: Thu Oct 15, 2020 11:57 am |
|
|
art wrote: | Dear Ttelmah
Quote: |
Almost 'classic' for a chip that is not actually genuine. Where did you
buy it from?
|
I bought it from SHOPEE for only USD1.50. Maybe it is not genuine. I'm thinking of replacing the IC on the module with the genuine parts. |
Hello, Art!
Have you found the root of your problem?
I have bought the Arduino module with ADS1115. And I find the same problem.
Output code increase by 16.
I have tried different sample rates, PGA coefficients, then I connect a precision potentiometer.
Output values are multiples of 16.
Have you tried chip from other sellers? |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|