CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug Reports on this forum. Send them to support@ccsinfo.com

ADS1115 problem

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
art



Joined: 21 May 2015
Posts: 181

View user's profile Send private message

ADS1115 problem
PostPosted: Fri Mar 13, 2020 1:31 am     Reply with quote

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: 15723

View user's profile Send private message

PostPosted: Fri Mar 13, 2020 3:20 am     Reply with quote

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: 7349
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Fri Mar 13, 2020 5:04 am     Reply with quote

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

View user's profile Send private message

PostPosted: Sat Mar 14, 2020 12:05 am     Reply with quote

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: 15723

View user's profile Send private message

PostPosted: Sat Mar 14, 2020 1:26 am     Reply with quote

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

View user's profile Send private message

PostPosted: Sat Mar 14, 2020 9:53 pm     Reply with quote

Dear Ttelmah

Code:

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: 15723

View user's profile Send private message

PostPosted: Sun Mar 15, 2020 4:15 am     Reply with quote

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

View user's profile Send private message

PostPosted: Sun Mar 15, 2020 7:53 pm     Reply with quote

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: 7349
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Sun Mar 15, 2020 8:03 pm     Reply with quote

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: 15723

View user's profile Send private message

PostPosted: Mon Mar 16, 2020 12:43 am     Reply with quote

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: 21064

View user's profile Send private message

PostPosted: Mon Mar 16, 2020 12:58 am     Reply with quote

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

View user's profile Send private message

PostPosted: Mon Mar 16, 2020 1:22 am     Reply with quote

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

View user's profile Send private message

PostPosted: Mon Mar 16, 2020 1:53 am     Reply with quote

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: 15723

View user's profile Send private message

PostPosted: Mon Mar 16, 2020 2:39 am     Reply with quote

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.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
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