PIC Development Board with PK3

Thread Starter

Djsarakar

Joined Jul 26, 2020
489
@JohnInTX @trebla

I'm sure I'm doing what I've been told but still problem is not solved. LCD program in post #297 is already loaded in Microcontroller. The problem is that display show the data sometime and sometime don't show I've done continuity test for each LCD connection and ALL seems fine for me

1624430380980.png

I just got the new problem right now when I try to program board Target device ID is invalid device ID. I double checked connection between PIK kit 3 and board All is fine but I don't understand what's wrong

1624431071389.png
 

Attachments

Last edited:

Thread Starter

Djsarakar

Joined Jul 26, 2020
489
I've just removed red wire and now I can program board. It will too early for me to say that problem is solved but the positive thing is that I've run programs for LCD, RTC and EEPROM. For now all these programs are working well on the board. I will keep testing all the programs for the day If I don't get any problem with board then only I will work with ADS1115

1624437320547.png


I've recorded video of RTC but I don't know how to upload video in mp4 format
 
Last edited:

ericgibbs

Joined Jan 29, 2010
21,448
I've recorded video of RTC but I don't know how to upload video in mp4 format
hi,
A method I use is to add a .txt extension to the MP4 file eg: Dj.mp4.txt

Try that and I will check it out, by downloading and removing the .txt

E
 

Thread Starter

Djsarakar

Joined Jul 26, 2020
489
hi,
A method I use is to add a .txt extension to the MP4 file eg: Dj.mp4.txt

Try that and I will check it out, by downloading and removing the .txt

E
okay I've saved Dj.mp4.txt in This PC-> Documents
When I want to upload video I click on attach files button. I get one windows so when I search Dj.mp4.txt I don't get in This PC-> Documents

1624440339122.png
 
Last edited:

Thread Starter

Djsarakar

Joined Jul 26, 2020
489
@JohnInTX

There is a good news The problem with the board is now fixed. I ran the all previous working program yesterday. I have tested board for all day yesterday. I'm sure there is no issue with board now. I think decoupling capacitor wasn't on the board that caused the problem. may be i could be wrong but right now i have no problem with the board
 

Thread Starter

Djsarakar

Joined Jul 26, 2020
489
Everything is fine now so I thought to test ADS1115

This is my connection for ADS1115
1624533141567.png
As you said I just used working code of EEPROM. I only changed the address of EPPROM. I've written the address of ADS1115 in place of EEPROM address in below program

#define EEPROM_ADDRESS 0x90
#define Word_Address1 0x01

C:
//
#define _XTAL_FREQ 20000000     // crystal 20MHz

// PIC18F45K80 Configuration Bit Settings
// CONFIG1L
#pragma config RETEN = ON       // VREG Sleep Enable bit (Ultra low-power regulator is Enabled (Controlled by SRETEN bit))
#pragma config INTOSCSEL = LOW  // LF-INTOSC Low-power Enable bit (LF-INTOSC in Low-power mode during Sleep)
// SOSCSEL = No Setting
#pragma config XINST = OFF      // Extended Instruction Set (Disabled)
// CONFIG1H
#pragma config FOSC = HS2       // HS oscillator (high power, 16 MHz-25 MHz
#pragma config PLLCFG = OFF     // PLL x4 Enable bit (Disabled)
#pragma config FCMEN = OFF      // Fail-Safe Clock Monitor (Disabled)
#pragma config IESO = OFF       // Internal External Oscillator Switch Over Mode (Disabled)
// CONFIG2L
#pragma config PWRTEN = ON      // Power Up Timer (Enabled)
#pragma config BOREN = OFF      // Brown Out Detect (Disabled in hardware, SBOREN disabled)
#pragma config BORV = 0         // Brown-out Reset Voltage bits (3.0V)
#pragma config BORPWR = LOW     // BORMV Power level (BORMV set to low power level)
// CONFIG2H
#pragma config WDTEN = OFF      // Watchdog Timer (WDT disabled in hardware; SWDTEN bit disabled)
#pragma config WDTPS = 1        // Watchdog Postscaler (1:1)
// CONFIG3H
#pragma config CANMX = PORTC    // ECAN Mux bit (ECAN TX and RX pins are located on RC6 and RC7, respectively)
#pragma config MSSPMSK = MSK5   // MSSP address masking (5 bit address masking mode)
#pragma config MCLRE = ON      // Master Clear Enable (MCLR Enabled, RE3 Disabled)
// CONFIG4L
#pragma config STVREN = OFF     // Stack Overflow Reset (Disabled)
#pragma config BBSIZ = BB1K     // Boot Block Size (1K word Boot Block size)
// CONFIG5L
#pragma config CP0 = ON         // Code Protect 00800-01FFF (Enabled)
#pragma config CP1 = ON         // Code Protect 02000-03FFF (Enabled)
#pragma config CP2 = ON         // Code Protect 04000-05FFF (Enabled)
#pragma config CP3 = ON         // Code Protect 06000-07FFF (Enabled)
// CONFIG5H
#pragma config CPB = ON         // Code Protect Boot (Enabled)
#pragma config CPD = ON         // Data EE Read Protect (Enabled)
// CONFIG6L
#pragma config WRT0 = ON        // Table Write Protect 00800-01FFF (Enabled)
#pragma config WRT1 = ON        // Table Write Protect 02000-03FFF (Enabled)
#pragma config WRT2 = ON        // Table Write Protect 04000-05FFF (Enabled)
#pragma config WRT3 = ON        // Table Write Protect 06000-07FFF (Enabled)
// CONFIG6H
#pragma config WRTC = ON        // Config. Write Protect (Enabled)
#pragma config WRTB = ON        // Table Write Protect Boot (Enabled)
#pragma config WRTD = ON        // Data EE Write Protect (Enabled)
// CONFIG7L
#pragma config EBTR0 = ON       // Table Read Protect 00800-01FFF (Enabled)
#pragma config EBTR1 = ON       // Table Read Protect 02000-03FFF (Enabled)
#pragma config EBTR2 = ON       // Table Read Protect 04000-05FFF (Enabled)
#pragma config EBTR3 = ON       // Table Read Protect 06000-07FFF (Enabled)
// CONFIG7H
#pragma config EBTRB = ON       // Table Read Protect Boot (Enabled)
// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.

#pragma warning disable 520

#include <xc.h>

unsigned char Result1;
unsigned char Result2;
unsigned char Result3;
unsigned char Result4;

// The code should set the R/W bit according to its function
#define EEPROM_ADDRESS      0x90    
#define Word_Address1       0x01


#define LCD_RS              LATBbits.LATB4
#define LCD_TRIS_RS         TRISBbits.TRISB4
#define LCD_RW              LATBbits.LATB5
#define LCD_TRIS_RW         TRISBbits.TRISB5
#define LCD_E               LATBbits.LATB6
#define LCD_TRIS_E          TRISBbits.TRISB6

#define  LCDPORT            LATD
#define  LCDTRISD           LATD

void Port_Initialized (void);
void WriteNibble(unsigned char command);
void WaitLCDBusy(void);
void WriteCommand(unsigned char command);

void Port_Initialized (void)
{
// LATx registers
    LATA =  0x00;
    LATB =  0x00;
    LATC =  0x00;
    LATD =  0x00;
    LATE =  0x00;

//  TRISx registers
    TRISA = 0x00;      // All are output, Unused
    TRISB = 0x00;      // all are output, Unused
    TRISC = 0x18;      // Slave SDA and CLOCK
    TRISD = 0x00;      // LCD
    TRISE = 0x00;      // All are output, Unused

    ANCON0 = 0x00;     // set to digital port
    ANCON1 = 0x00;     // Set to digital port
    CM1CON = 0x00;     // Comparator off
    CM2CON = 0x00;     // Comparator off
    ADCON0 = 0x00;     // A/D conversion Disabled
    ADCON1 = 0x00;     // A/D conversion Disabled
    ADCON2 = 0x00;     // A/D conversion Disabled
}

// Wait for 5 ms
void WaitLCDBusy(void)
{
    __delay_ms(5);
}

//Send a command to the LCD
void WriteCommand(unsigned char command)
{
    WaitLCDBusy();                        //wait until not busy
    LCD_RS = 0;                           //setup to send command
    WriteNibble(command);                 //write the high nibble
    WriteNibble( (unsigned char)(command<<4) ); //then the low nibble
}

//Initialized  LCD
void LCD_Initialized()
{
    LCDTRISD &=0x0f;                //ensure data bits are output
    LCD_E=0;                        //clear enable
    LCD_RS = 0;                     //going to write command
    LCD_TRIS_E=0;                   //Set enable to output
    LCD_TRIS_RS=0;                  //set RS to output
    LCD_TRIS_RW=0;
    LCD_RW=0;
    __delay_ms(30);                 //delay for LCD to initialise.
    WriteNibble(0x30);              //Required for initialisation
    __delay_ms(5);                  //required delay
    WriteNibble(0x30);              //Required for initialisation
    __delay_ms(1);                  //required delay
    WriteCommand(0x20);             //set to 4 bit interface
    WriteCommand(0x2c);             //set to 4 bit interface, 2 line and 5*10 font
    WriteCommand(0x01);             //clear display
    WriteCommand(0x06);             //move cursor right after write
    WriteCommand(0x0C);             //turn on display
}

//Send a character to the LCD
void WriteChar(unsigned char chr)
{
    WaitLCDBusy();                         //wait until not busy
    LCD_RS=1;                              //Setup to send character
    WriteNibble(chr);                      //write the high nibble    
    WriteNibble( (unsigned char)(chr<<4)); //then the low nibble
}

//Send any 4 bits to the LCD
void WriteNibble(unsigned char command)
{
    LCDPORT &= 0x0f;                        //clear the data bits
    LCDPORT|=((command & 0xf0));            //or in the new data
    LCD_E = 1;                              //enable the LCD interface
    NOP();                                  // delay of 1uS
    NOP();
    NOP();
    LCD_E = 0;                              //disable it
}

void LCD_Data( unsigned char *string)
{
    while (*string != '\0')
    {
      WriteChar(*string);
        string++;
    }
}

//Initialize I2C in master mode
void I2C_Initialized(void)
{
    SSPSTAT=0x80; //Slew rate control is disabled for Standard Speed mode (100 kHz and 1 MHz)
    SSPCON1=0x28; // I2C Master mode, clock = FOSC/(4 * (SSPADD + 1))
    SSPCON2=0x00;
    SSPADD = 49;
    //100kHz clock @ 20MHz Fosc SSPADD = ( (Fosc/4) / BiteRate )-1
   // SSPADD = ( 20MHz / 100KHz ) - 1 = 49
}

// Send an I2C START
// Return 0 if all ok, 1 if bus collision
__bit I2C_Start(void)
{
    BCLIF = 0;  //Clear 'Bus collision" flag
    SEN = 1;    //initiate a START cycle
    while (SEN);    //wait until it has been sent
    return BCLIF;   //return value of BCLIF flag
}
// Send an I2C STOP
void I2C_Stop(void)
{
    PEN = 1;    //initiate a STOP cycle
    while (PEN);    //wait until it has been sent
}

// Send an I2C REPEATED START
void I2C_Restart(void)
{
    RSEN = 1;    //initiate a REPEATED START cycle
    while (RSEN);    //wait until it has been sent
}

//Receive one byte. ackflag=0 to send ACK, or 1 to send NAK in reply
//Send one byte. Return 0 if ACK received, or 1 if NAK received
__bit I2C_Sendbyte(unsigned char dat)
{
    SSPBUF = dat;

    asm("nop");     // wait a little for R_W to be set

    while (R_W);    //wait until byte sent and ACK/NAK received
    return ACKSTAT;
}

unsigned char I2C_Recvbyte(unsigned char ackflag)
{
    RCEN = 1;   // initiate a RECEIVE cycle
    ACKDT =(__bit)ackflag;    //specify if we should send ACK or NAK after receiving
    while (RCEN);   //wait until RECEIVE has completed
    ACKEN = 1;  //initiate an ACK cycle
    while (ACKEN);  //wait until it has completed
    return SSPBUF;
}

//Send an array of data to an I2C device.
//Return 0 if all OK, 1 if bus error, 2 if slave address NAK, 3 if slave register NAK, 4 if slave data NAK
unsigned char EEPROM_Write(unsigned char slave_address, unsigned char start_reg, unsigned char buflen, const unsigned char * bufptr)
{
    if (I2C_Start() )   //send a start, and check if it succeeded
        return 1;   //abort if bus collision
    //send the I2C slave address (force R/W bit low)
    if (I2C_Sendbyte(slave_address & 0xfe))
    {
        I2C_Stop(); //if address was NAKed, terminate the cycle
        return 2;   //and return error code
    }
    //send the device register index
    if (I2C_Sendbyte(start_reg))
    {
        I2C_Stop(); //if register was NAKed, terminate the cycle
        return 3;   //and return error code
    }
    //send the data. buflen might be zero!
    for (; buflen>0; --buflen)
    {
        if (I2C_Sendbyte(*bufptr++))
        {
            I2C_Stop(); //if register was NAKed, terminate the cycle
            return 4;   //and return error code
        }
    }
    I2C_Stop();
    return 0;   //no error
}

//Receive an array of data from an I2C device.
//Return 0 if all OK, 1 if bus error, 2 if slave address NAK, 3 if slave register NAK
unsigned char EEPROM_Read(unsigned char slave_address, unsigned char start_reg, unsigned char buflen, unsigned char * bufptr)
{
    //do a dummy zero length write cycle to set the register address
    unsigned char retval = EEPROM_Write(slave_address, start_reg, 0, 0);
    if (retval)
    {
        return retval;  //abort if there was an error
    }
    //now start the READ cycle
    if (I2C_Start() )   //send a start, and check if it succeeded
        return 1;   //abort if bus collision
    //send the I2C slave address (force the R/W bit high)
    if (I2C_Sendbyte(slave_address | 0x01))
    {
        I2C_Stop(); //if address was NAKed, terminate the cycle
        return 2;   //and return error code
    }
    //receive the data.
    for (; buflen>0; --buflen)
    {
        unsigned char ackflag = (buflen == 1);   //1 if this is the last byte to receive => send NAK

        *bufptr++ = I2C_Recvbyte(ackflag);
    }
    I2C_Stop();
    return 0;   //no error
}
const unsigned char EEPROM_data[] =
{
    0x07,   // Count 7
    0x06,   // Count 6
    0x05,   // Count 5
    0x04,   // Count 4
    0x03,   // Count 3
    0x02,   // Count 2
    0x01,   // Count 1
};
unsigned char rd_buf[7];

// Test variable for one byte transfer
const unsigned char testchar = 'A';
unsigned char testchar_readback[17];  // init to this to see difference after read

void main(void)
{
     unsigned char i = 0;

     unsigned char Data1 [10]="xx";

     Port_Initialized ();
     LCD_Initialized();
     I2C_Initialized();
     //LCD_Data(Data1);

    // Write test buffer
     Result1 = EEPROM_Write(EEPROM_ADDRESS , Word_Address1 , sizeof(EEPROM_data), EEPROM_data);
     __delay_ms(10);

    // Read test buffer back
     Result2 = EEPROM_Read(EEPROM_ADDRESS, Word_Address1 , sizeof(rd_buf), rd_buf) ;
     __delay_ms(10);


     // Read back ONE number from 0x01
     Result4 = EEPROM_Read(EEPROM_ADDRESS, 0x00 , 8, rd_buf);                   // read first 8 bytes of EEPROM data
    __delay_ms(10);

    for (i = 0; i < 8; i++)                                                     // output buffer contents address 0 to 7
    {
        Data1[0] = ((rd_buf[i] >> 4) & 0x0f) + '0';                             // hex conversion - high nibble
        Data1[1] = (rd_buf[i] & 0x0f) + '0';                                    // hex conversion - low nibble
        LCD_Data(Data1);
    }
    while(1);
}
When I ran program on the board I get the error code 4 as shown in debug window. Result prove that when I send address of ADS1115, ADS1115 acknowledge the address,

This was only test program to see slave is ACK/NACK

1624533281758.png
 
Last edited:

JohnInTX

Joined Jun 26, 2012
4,787
I've just removed red wire and now I can program board
Good news but you still need both Vdd and both Vss pins hooked to power.

As you said I just used working code of EEPROM. I only changed the address of EPPROM. I've written the address of ADS1115 in place of EEPROM address in below program
Using the working code of EEPROM is fine BUT you need to send data that makes sense to the ADS1115. The I2C read/write code will work for anything but the data has to make sense to the chip you are talking to.
Look at what you are sending to the ADS1115. Does that make sense for the chip?
 

trebla

Joined Jun 29, 2019
599
There is an example in the datasheet section "Quickstart Guide". In the beginning of your code you must initilialize the AD chip, just use your EEPROM_Write() function but with correct data as pointed in "1.Write to Config register:"
 

Thread Starter

Djsarakar

Joined Jul 26, 2020
489
Look at what you are sending to the ADS1115. Does that make sense for the chip?
@JohnInTX Does this make sense to send ADS1115?

1. Write to Config register:
– First byte: 0b10010000 (first 7-bit I2C address followed by a low R/W bit)
– Second byte: 0b00000001 (points to Config register)
– Third byte: 0b10000100 (MSB of the Config register to be written)
– Fourth byte: 0b10000011 (LSB of the Config register to be written)
2. Write to Address Pointer register:
– First byte: 0b10010000 (first 7-bit I2C address followed by a low R/W bit)

1624548197655.png



C:
//
#define _XTAL_FREQ 20000000     // crystal 20MHz

// PIC18F45K80 Configuration Bit Settings
// CONFIG1L
#pragma config RETEN = ON       // VREG Sleep Enable bit (Ultra low-power regulator is Enabled (Controlled by SRETEN bit))
#pragma config INTOSCSEL = LOW  // LF-INTOSC Low-power Enable bit (LF-INTOSC in Low-power mode during Sleep)
// SOSCSEL = No Setting
#pragma config XINST = OFF      // Extended Instruction Set (Disabled)
// CONFIG1H
#pragma config FOSC = HS2       // HS oscillator (high power, 16 MHz-25 MHz
#pragma config PLLCFG = OFF     // PLL x4 Enable bit (Disabled)
#pragma config FCMEN = OFF      // Fail-Safe Clock Monitor (Disabled)
#pragma config IESO = OFF       // Internal External Oscillator Switch Over Mode (Disabled)
// CONFIG2L
#pragma config PWRTEN = ON      // Power Up Timer (Enabled)
#pragma config BOREN = OFF      // Brown Out Detect (Disabled in hardware, SBOREN disabled)
#pragma config BORV = 0         // Brown-out Reset Voltage bits (3.0V)
#pragma config BORPWR = LOW     // BORMV Power level (BORMV set to low power level)
// CONFIG2H
#pragma config WDTEN = OFF      // Watchdog Timer (WDT disabled in hardware; SWDTEN bit disabled)
#pragma config WDTPS = 1        // Watchdog Postscaler (1:1)
// CONFIG3H
#pragma config CANMX = PORTC    // ECAN Mux bit (ECAN TX and RX pins are located on RC6 and RC7, respectively)
#pragma config MSSPMSK = MSK5   // MSSP address masking (5 bit address masking mode)
#pragma config MCLRE = ON      // Master Clear Enable (MCLR Enabled, RE3 Disabled)
// CONFIG4L
#pragma config STVREN = OFF     // Stack Overflow Reset (Disabled)
#pragma config BBSIZ = BB1K     // Boot Block Size (1K word Boot Block size)
// CONFIG5L
#pragma config CP0 = ON         // Code Protect 00800-01FFF (Enabled)
#pragma config CP1 = ON         // Code Protect 02000-03FFF (Enabled)
#pragma config CP2 = ON         // Code Protect 04000-05FFF (Enabled)
#pragma config CP3 = ON         // Code Protect 06000-07FFF (Enabled)
// CONFIG5H
#pragma config CPB = ON         // Code Protect Boot (Enabled)
#pragma config CPD = ON         // Data EE Read Protect (Enabled)
// CONFIG6L
#pragma config WRT0 = ON        // Table Write Protect 00800-01FFF (Enabled)
#pragma config WRT1 = ON        // Table Write Protect 02000-03FFF (Enabled)
#pragma config WRT2 = ON        // Table Write Protect 04000-05FFF (Enabled)
#pragma config WRT3 = ON        // Table Write Protect 06000-07FFF (Enabled)
// CONFIG6H
#pragma config WRTC = ON        // Config. Write Protect (Enabled)
#pragma config WRTB = ON        // Table Write Protect Boot (Enabled)
#pragma config WRTD = ON        // Data EE Write Protect (Enabled)
// CONFIG7L
#pragma config EBTR0 = ON       // Table Read Protect 00800-01FFF (Enabled)
#pragma config EBTR1 = ON       // Table Read Protect 02000-03FFF (Enabled)
#pragma config EBTR2 = ON       // Table Read Protect 04000-05FFF (Enabled)
#pragma config EBTR3 = ON       // Table Read Protect 06000-07FFF (Enabled)
// CONFIG7H
#pragma config EBTRB = ON       // Table Read Protect Boot (Enabled)
// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.

#pragma warning disable 520

#include <xc.h>

#define ADC_ADDRESS_WRITE        0x90 //first 7-bit I2C address with a low R/W bit
#define CONFIG_REGISTER          0x01 // points to Config register
#define MSB_CONFIG_REGISTER      0x84 // MSB of the Config register to be written
#define LSB_CONFIG_REGISTER      0x83 //LSB of the Config register to be written


void Port_Initialized (void)
{
// LATx registers
    LATA =  0x00;
    LATB =  0x00;
    LATC =  0x00;
    LATD =  0x00;
    LATE =  0x00;

//  TRISx registers
    TRISA = 0x00;    // All are output, Unused
    TRISB = 0x00;    // all are output, Unused
    TRISC = 0x18;    // SDA SCL
    TRISD = 0x00;    // all are output, Unused
    TRISE = 0x00;    // All are output, Unused

    ANCON0 = 0x00;    // Set to digital port
    ANCON1 = 0x00;    // Set to digital port
    CM1CON = 0x00;    // Comparator off
    CM2CON = 0x00;    // Comparator off
    ADCON0 = 0x00;    // A/D conversion Disabled
    ADCON1 = 0x00;    // A/D conversion Disabled
    ADCON2 = 0x00;    // A/D conversion Disabled
}

//Initialize I2C in master mode
void I2C_Initialized(void)
{
    SSPSTAT=0x80; //Slew rate control is disabled for Standard Speed mode (100 kHz and 1 MHz)
    SSPCON1=0x28; // I2C Master mode, clock = FOSC/(4 * (SSPADD + 1))
    SSPCON2=0x00;
    SSPADD = 49;
}

// Send an I2C START
// Return 0 if all ok, 1 if bus collision
__bit I2C_Start(void)
{
    BCLIF = 0;        //Clear 'Bus collision" flag
    SEN = 1;          //initiate a START cycle
    while (SEN);      //wait until it has been sent
    return BCLIF;     //return value of BCLIF flag
}

// Send an I2C STOP
void I2C_Stop(void)
{
    PEN = 1;          //initiate a STOP cycle
    while (PEN);      //wait until it has been sent
}

//Receive one byte. ackflag=0 to send ACK, or 1 to send NAK in reply
//Send one byte. Return 0 if ACK received, or 1 if NAK received
__bit I2C_Sendbyte(unsigned char dat)
{
    SSPBUF = dat;
    NOP();          //wait a little for R_W to be set
    while (R_W);    //wait until byte sent and ACK/NAK received
    return ACKSTAT;
}

//Return 0 if all OK,
unsigned char ADC_Write(unsigned char adc_address, unsigned char config_register, unsigned char MSB_config, unsigned char LSB_config )
{
    if (I2C_Start() )   //send a start, and check if it succeeded
        return 1;   //abort if bus collision

    //send the I2C slave address
    if (I2C_Sendbyte(adc_address))  //
    {
        I2C_Stop(); //if address was NAKed, terminate the cycle
        return 2;   //and return error code
    }
    //send the Config register
    if (I2C_Sendbyte(config_register))
    {
        I2C_Stop(); //if register was NAKed, terminate the cycle
        return 3;   //and return error code
    }

    //send MSB of Config register
    if (I2C_Sendbyte(MSB_config))
    {
        I2C_Stop(); //terminate the cycle
        return 4;   //and return error code
    }

    //send the LSB ofConfig register
    if (I2C_Sendbyte(LSB_config))
    {
        I2C_Stop(); // terminate the cycle
        return 5;   //and return error code
    }

    I2C_Stop();
    return 0;   //no error
}

unsigned char ADC_Send;
void main(void)
{

    Port_Initialized ();
    I2C_Initialized();

    ADC_Send = ADC_Write(ADC_ADDRESS_WRITE , CONFIG_REGISTER, MSB_CONFIG_REGISTER, LSB_CONFIG_REGISTER );
    __delay_ms(10);

    while(1);
}
 

JohnInTX

Joined Jun 26, 2012
4,787
Does this make sense to send ADS1115?
What doesn't make sense is why, despite all advice to the contrary, you have once again changed working, tested I2C code. I just don't understand. Are you intending to rewrite your code completely for each device?
But:
1) Yes, that sequence should write 2 bytes to the configuration register.
2) I don't understand what you are asking here. The I2C code automatically writes the address pointer on EVERY transaction, or at least it used to.
 

Thread Starter

Djsarakar

Joined Jul 26, 2020
489
you have once again changed working, tested I2C code.
It is my understanding that ADS1115 is different slave device from these two slave EEPROM and DS1307.

EEPROM and DS1307 automatically increment the register address so that we only have to write data where as ADS1115 requires alternate writes of address and data,
Datasheet show config register and pointer register have to write alternate address and data. That's why I've changed a code

Please correct if this is not right.
 

JohnInTX

Joined Jun 26, 2012
4,787
It is my understanding that ADS1115 is different slave device from these two slave EEPROM and DS1307.
That is correct. And the original I2C code takes that slave address as its first parameter, right? So all you have to do is pass the slave address corresponding to the device you want to read or write and the code works from there.

EDIT: When I said 'changing the code' I meant that you re-wrote the actual I2C routines again. Obviously, you change the slave address and other parameters to the I2C routines to make them do different things but it is not necessary nor desirable to change the I2C functions for every new thing.

EEPROM and DS1307 automatically increment the register address so that we only have to write data where as ADS1115 requires alternate writes of address and data,
Datasheet show config register and pointer register have to write alternate address and data. That's why I've changed a code
It is correct that the EEPROM and RTC increment the pointer address automatically and the ADS1115 does not. But that does not mean that you have to write new code. You just need to call the same code more than once.

Review the parameter list for I2C_Write:
unsigned char I2C_Write(unsigned char slave_address, unsigned char start_reg, unsigned char buflen, const unsigned char * bufptr)
slave_address
selects the device
start_reg is the byte that sets the internal register pointer - same for all of your I2C devices
buflen - is how many data bytes to write after the register pointer
bufptr - is a pointer to where the data is - zero, one, or many bytes, it doesn't matter. As you saw in the EEPROM and RTC tests, whatever is in the buffer you point to will by sent to the I2C device's internal registers beginning at the register indicated by start_reg.

To write 1234h to the ADS1115 configuration register just do:
C:
unsigned char data_buffer[8]; //or some number big enough to hold stuff for you
data_buffer[0] = 0x12h;
data_buffer[1]= 0x34h;

result = I2C_Write(ADS_SLAVE_ADDRESS, 0x01, 2, data_buffer);
For setup data, it may be better to declare a dedicated value:
C:
unsigned char ADC_init[]= {0x12,0x34};
result = I2C_Write(ADS_SLAVE_ADDRESS, 0x01, 2, ADC_init);
There. Done. No reason to do anything else.
What could be easier?
 
Last edited:

Thread Starter

Djsarakar

Joined Jul 26, 2020
489
Review the parameter list for I2C_Write:
okay I haven't done any change in I2C routine now. I only replace name of slave device.

1. Write to Config register:
– First byte: 0b10010000 (first 7-bit I2C address followed by a low R/W bit)
– Second byte: 0b00000001 (points to Config register)
– Third byte: 0b10000100 (MSB of the Config register to be written)
– Fourth byte: 0b10000011 (LSB of the Config register to be written)

I've done up to above step in code

C:
//
#define _XTAL_FREQ 20000000     // crystal 20MHz

// PIC18F45K80 Configuration Bit Settings
// CONFIG1L
#pragma config RETEN = ON       // VREG Sleep Enable bit (Ultra low-power regulator is Enabled (Controlled by SRETEN bit))
#pragma config INTOSCSEL = LOW  // LF-INTOSC Low-power Enable bit (LF-INTOSC in Low-power mode during Sleep)
// SOSCSEL = No Setting
#pragma config XINST = OFF      // Extended Instruction Set (Disabled)
// CONFIG1H
#pragma config FOSC = HS2       // HS oscillator (high power, 16 MHz-25 MHz
#pragma config PLLCFG = OFF     // PLL x4 Enable bit (Disabled)
#pragma config FCMEN = OFF      // Fail-Safe Clock Monitor (Disabled)
#pragma config IESO = OFF       // Internal External Oscillator Switch Over Mode (Disabled)
// CONFIG2L
#pragma config PWRTEN = ON      // Power Up Timer (Enabled)
#pragma config BOREN = OFF      // Brown Out Detect (Disabled in hardware, SBOREN disabled)
#pragma config BORV = 0         // Brown-out Reset Voltage bits (3.0V)
#pragma config BORPWR = LOW     // BORMV Power level (BORMV set to low power level)
// CONFIG2H
#pragma config WDTEN = OFF      // Watchdog Timer (WDT disabled in hardware; SWDTEN bit disabled)
#pragma config WDTPS = 1        // Watchdog Postscaler (1:1)
// CONFIG3H
#pragma config CANMX = PORTC    // ECAN Mux bit (ECAN TX and RX pins are located on RC6 and RC7, respectively)
#pragma config MSSPMSK = MSK5   // MSSP address masking (5 bit address masking mode)
#pragma config MCLRE = ON      // Master Clear Enable (MCLR Enabled, RE3 Disabled)
// CONFIG4L
#pragma config STVREN = OFF     // Stack Overflow Reset (Disabled)
#pragma config BBSIZ = BB1K     // Boot Block Size (1K word Boot Block size)
// CONFIG5L
#pragma config CP0 = ON         // Code Protect 00800-01FFF (Enabled)
#pragma config CP1 = ON         // Code Protect 02000-03FFF (Enabled)
#pragma config CP2 = ON         // Code Protect 04000-05FFF (Enabled)
#pragma config CP3 = ON         // Code Protect 06000-07FFF (Enabled)
// CONFIG5H
#pragma config CPB = ON         // Code Protect Boot (Enabled)
#pragma config CPD = ON         // Data EE Read Protect (Enabled)
// CONFIG6L
#pragma config WRT0 = ON        // Table Write Protect 00800-01FFF (Enabled)
#pragma config WRT1 = ON        // Table Write Protect 02000-03FFF (Enabled)
#pragma config WRT2 = ON        // Table Write Protect 04000-05FFF (Enabled)
#pragma config WRT3 = ON        // Table Write Protect 06000-07FFF (Enabled)
// CONFIG6H
#pragma config WRTC = ON        // Config. Write Protect (Enabled)
#pragma config WRTB = ON        // Table Write Protect Boot (Enabled)
#pragma config WRTD = ON        // Data EE Write Protect (Enabled)
// CONFIG7L
#pragma config EBTR0 = ON       // Table Read Protect 00800-01FFF (Enabled)
#pragma config EBTR1 = ON       // Table Read Protect 02000-03FFF (Enabled)
#pragma config EBTR2 = ON       // Table Read Protect 04000-05FFF (Enabled)
#pragma config EBTR3 = ON       // Table Read Protect 06000-07FFF (Enabled)
// CONFIG7H
#pragma config EBTRB = ON       // Table Read Protect Boot (Enabled)
// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.

#pragma warning disable 520

#include <xc.h>

unsigned char Result1;
unsigned char Result2;
unsigned char Result3;
unsigned char Result4;

// The code should set the R/W bit according to its function
#define ADS1115_ADDRESS      0x90         //I2C slave address of ADS1115 (8 bit format)
#define Word_Address1        0x01         // Points to Config register


#define LCD_RS              LATBbits.LATB4
#define LCD_TRIS_RS         TRISBbits.TRISB4
#define LCD_RW              LATBbits.LATB5
#define LCD_TRIS_RW         TRISBbits.TRISB5
#define LCD_E               LATBbits.LATB6
#define LCD_TRIS_E          TRISBbits.TRISB6

#define  LCDPORT            LATD
#define  LCDTRISD           LATD

void Port_Initialized (void);
void WriteNibble(unsigned char command);
void WaitLCDBusy(void);
void WriteCommand(unsigned char command);

void Port_Initialized (void)
{
// LATx registers
    LATA =  0x00;
    LATB =  0x00;
    LATC =  0x00;
    LATD =  0x00;
    LATE =  0x00;

//  TRISx registers
    TRISA = 0x00;      // All are output, Unused
    TRISB = 0x00;      // all are output, Unused
    TRISC = 0x18;      // Slave SDA and CLOCK
    TRISD = 0x00;      // LCD
    TRISE = 0x00;      // All are output, Unused

    ANCON0 = 0x00;     // set to digital port
    ANCON1 = 0x00;     // Set to digital port
    CM1CON = 0x00;     // Comparator off
    CM2CON = 0x00;     // Comparator off
    ADCON0 = 0x00;     // A/D conversion Disabled
    ADCON1 = 0x00;     // A/D conversion Disabled
    ADCON2 = 0x00;     // A/D conversion Disabled
}

// Wait for 5 ms
void WaitLCDBusy(void)
{
    __delay_ms(5);
}

//Send a command to the LCD
void WriteCommand(unsigned char command)
{
    WaitLCDBusy();                        //wait until not busy
    LCD_RS = 0;                           //setup to send command
    WriteNibble(command);                 //write the high nibble
    WriteNibble( (unsigned char)(command<<4) ); //then the low nibble
}

//Initialized  LCD
void LCD_Initialized()
{
    LCDTRISD &=0x0f;                //ensure data bits are output
    LCD_E=0;                        //clear enable
    LCD_RS = 0;                     //going to write command
    LCD_TRIS_E=0;                   //Set enable to output
    LCD_TRIS_RS=0;                  //set RS to output
    LCD_TRIS_RW=0;
    LCD_RW=0;
    __delay_ms(30);                 //delay for LCD to initialise.
    WriteNibble(0x30);              //Required for initialisation
    __delay_ms(5);                  //required delay
    WriteNibble(0x30);              //Required for initialisation
    __delay_ms(1);                  //required delay
    WriteCommand(0x20);             //set to 4 bit interface
    WriteCommand(0x2c);             //set to 4 bit interface, 2 line and 5*10 font
    WriteCommand(0x01);             //clear display
    WriteCommand(0x06);             //move cursor right after write
    WriteCommand(0x0C);             //turn on display
}

//Send a character to the LCD
void WriteChar(unsigned char chr)
{
    WaitLCDBusy();                         //wait until not busy
    LCD_RS=1;                              //Setup to send character
    WriteNibble(chr);                      //write the high nibble    
    WriteNibble( (unsigned char)(chr<<4)); //then the low nibble
}

//Send any 4 bits to the LCD
void WriteNibble(unsigned char command)
{
    LCDPORT &= 0x0f;                        //clear the data bits
    LCDPORT|=((command & 0xf0));            //or in the new data
    LCD_E = 1;                              //enable the LCD interface
    NOP();                                  // delay of 1uS
    NOP();
    NOP();
    LCD_E = 0;                              //disable it
}

void LCD_Data( unsigned char *string)
{
    while (*string != '\0')
    {
      WriteChar(*string);
        string++;
    }
}

//Initialize I2C in master mode
void I2C_Initialized(void)
{
    SSPSTAT=0x80; //Slew rate control is disabled for Standard Speed mode (100 kHz and 1 MHz)
    SSPCON1=0x28; // I2C Master mode, clock = FOSC/(4 * (SSPADD + 1))
    SSPCON2=0x00;
    SSPADD = 49;
    //100kHz clock @ 20MHz Fosc SSPADD = ( (Fosc/4) / BiteRate )-1
   // SSPADD = ( 20MHz / 100KHz ) - 1 = 49
}

// Send an I2C START
// Return 0 if all ok, 1 if bus collision
__bit I2C_Start(void)
{
    BCLIF = 0;  //Clear 'Bus collision" flag
    SEN = 1;    //initiate a START cycle
    while (SEN);    //wait until it has been sent
    return BCLIF;   //return value of BCLIF flag
}
// Send an I2C STOP
void I2C_Stop(void)
{
    PEN = 1;    //initiate a STOP cycle
    while (PEN);    //wait until it has been sent
}

// Send an I2C REPEATED START
void I2C_Restart(void)
{
    RSEN = 1;    //initiate a REPEATED START cycle
    while (RSEN);    //wait until it has been sent
}

//Receive one byte. ackflag=0 to send ACK, or 1 to send NAK in reply
//Send one byte. Return 0 if ACK received, or 1 if NAK received
__bit I2C_Sendbyte(unsigned char dat)
{
    SSPBUF = dat;

    asm("nop");     // wait a little for R_W to be set

    while (R_W);    //wait until byte sent and ACK/NAK received
    return ACKSTAT;
}

unsigned char I2C_Recvbyte(unsigned char ackflag)
{
    RCEN = 1;   // initiate a RECEIVE cycle
    ACKDT =(__bit)ackflag;    //specify if we should send ACK or NAK after receiving
    while (RCEN);   //wait until RECEIVE has completed
    ACKEN = 1;  //initiate an ACK cycle
    while (ACKEN);  //wait until it has completed
    return SSPBUF;
}

//Send an array of data to an I2C device.
//Return 0 if all OK, 1 if bus error, 2 if slave address NAK, 3 if slave register NAK, 4 if slave data NAK
unsigned char ADS1115_Write(unsigned char slave_address, unsigned char start_reg, unsigned char buflen, const unsigned char * bufptr)
{
    if (I2C_Start() )   //send a start, and check if it succeeded
        return 1;   //abort if bus collision
    //send the I2C slave address (force R/W bit low)
    if (I2C_Sendbyte(slave_address & 0xfe))  //
    {
        I2C_Stop(); //if address was NAKed, terminate the cycle
        return 2;   //and return error code
    }
    //send the device register index
    if (I2C_Sendbyte(start_reg))
    {
        I2C_Stop(); //if register was NAKed, terminate the cycle
        return 3;   //and return error code
    }
    //send the data. buflen might be zero!
    for (; buflen>0; --buflen)
    {
        if (I2C_Sendbyte(*bufptr++))
        {
            I2C_Stop(); //if register was NAKed, terminate the cycle
            return 4;   //and return error code
        }
    }
    I2C_Stop();
    return 0;   //no error
}

//Receive an array of data from an I2C device.
//Return 0 if all OK, 1 if bus error, 2 if slave address NAK, 3 if slave register NAK
unsigned char ADS1115_Read(unsigned char slave_address, unsigned char start_reg, unsigned char buflen, unsigned char * bufptr)
{
    //do a dummy zero length write cycle to set the register address
    unsigned char retval = ADS1115_Write(slave_address, start_reg, 0, 0);
    if (retval)
    {
        return retval;  //abort if there was an error
    }
    //now start the READ cycle
    if (I2C_Start() )   //send a start, and check if it succeeded
        return 1;   //abort if bus collision
    //send the I2C slave address (force the R/W bit high)
    if (I2C_Sendbyte(slave_address | 0x01))
    {
        I2C_Stop(); //if address was NAKed, terminate the cycle
        return 2;   //and return error code
    }
    //receive the data.
    for (; buflen>0; --buflen)
    {
        unsigned char ackflag = (buflen == 1);   //1 if this is the last byte to receive => send NAK

        *bufptr++ = I2C_Recvbyte(ackflag);
    }
    I2C_Stop();
    return 0;   //no error
}
const unsigned char ADS1115_data[] =
{
 
    0x84,  //
    0x83,  //
};
unsigned char rd_buf[7];

// Test variable for one byte transfer
const unsigned char testchar = 'A';
unsigned char testchar_readback[17];  // init to this to see difference after read

void main(void)
{
     unsigned char i = 0;

     unsigned char Data1 [10]="xx";

     Port_Initialized ();
     LCD_Initialized();
     I2C_Initialized();
     //LCD_Data(Data1);

    // Write test buffer
     Result1 = ADS1115_Write(ADS1115_ADDRESS , Word_Address1 , sizeof(ADS1115_data), ADS1115_data);
     __delay_ms(10);

    // Read test buffer back
     Result2 = ADS1115_Read(ADS1115_ADDRESS, Word_Address1 , sizeof(rd_buf), rd_buf) ;
     __delay_ms(10);

                     
    while(1);
}

1624611834873.png


2. Write to Address Pointer register:
– First byte: 0b10010000 (first 7-bit I2C address followed by a low R/W bit)
– Second byte: 0b00000000 (points to Conversion register)

C:
Result1 = ADS1115_Write(ADS1115_ADDRESS , 0x00 , sizeof(ADS1115_data), ADS1115_data);
How to write to Address Pointer register?
 
Last edited:

Thread Starter

Djsarakar

Joined Jul 26, 2020
489
This is almost same as writing configuration data, but instead of writing ADS1115 address + 3 bytes you must send address + one byte as mentioned in datasheet.
I thought I should modified i2c functions after reading ADS1115 datasheet #332.

I'm waiting for @JohnInTX response. I don't understand what I need to pass in place of sizeof(ADS1115_data), ADS1115_data for Address Pointer register
C:
Result1 = ADS1115_Write(ADS1115_ADDRESS , 0x00 , sizeof(ADS1115_data), ADS1115_data);
 
Last edited:

trebla

Joined Jun 29, 2019
599
For sending one byte you must send the address, the pointer register (0x00), sizeof data is 0 and i believe the data variable itself can be a random because it will be not sent if you look at the for() routine in ADS1115_Write() function definition.
 

JohnInTX

Joined Jun 26, 2012
4,787
I'm waiting for @JohnInTX response. I don't understand what I need to pass in place of sizeof(ADS1115_data), ADS1115_data for Address Pointer register
Review the parameter list for I2C_Write:
unsigned char I2C_Write(unsigned char slave_address, unsigned char start_reg, unsigned char buflen, const unsigned char * bufptr)
slave_address
selects the device
start_reg is the byte that sets the internal register pointer - same for all of your I2C devices
buflen - is how many data bytes to write after the register pointer
bufptr - is a pointer to where the data is - zero, one, or many bytes, it doesn't matter. As you saw in the EEPROM and RTC tests, whatever is in the buffer you point to will by sent to the I2C device's internal registers beginning at the register indicated by start_reg.
I showed examples in #335.

I thought I should modified i2c functions after reading ADS1115 datasheet #332.
As agreed, don't do that.

Why do you think you need to set the Address Pointer register beyond what the read / write routines already do?
 
Top