I2C communication question

JohnInTX

Joined Jun 26, 2012
4,787
I don't understand what that means
C:
 /* check for last byte */
            if(ByteCount == 7)
               SendNAk()    /* NAK if last byte */  Is this line wrong ?
               I2C_Stop();
               return Failure
            else    
              SendACK();    /* ACK for all bytes */    Is this line wrong ?
              return Success
You do not send ACK or NAK when WRITING to the slave. You READ ACK or NAK FROM the slave when writing to the slave.

#59: why???
 
Last edited:

Thread Starter

Gajyamadake

Joined Oct 9, 2019
310
You do not send ACK or NAK when WRITING to the slave. You READ ACK or NAK FROM the slave when writing to the slave.

#59: why???
That's what I advised but there are problems with the C here:
for ( ByteCount= 0; ByteCount < 8; ByteCount++)
*(BytesToSend + ByteCount));
You are not actually sending any data bytes
That's was answer of post 58 in simple c. I will store the bytes into array then I will pass content of array by reference
 

Thread Starter

Gajyamadake

Joined Oct 9, 2019
310
OK. What about the other problems I noted with WriteI2C?
okay @JohnInTX now look at this WriteI2C function. Does it make any sense now ?

Write address of internal register to DS1307

C:
unsigned int WriteI2C(unsigned int SlaveAddress, unsigned int ByteCount,  unsigned int *BytesToSend)
{
    for ( ByteCount = 0; ByteCount < 8; ByteCount++)
    {
        I2CStart();

        I2C_SendByte(Slave_Address);

        GetACK_NAK = I2C_GetACK_NAK();
     
        if(GetACK_NAK == ACK)
        {
             *BytesToSend + ByteCount;
         
             I2C_Stop();
         
             return Success;
        }
        else
        {
            I2C_Stop();
            return Failure;    
        }
    }
}

int main (void)

{
    unsigned int ByteCount = 0;
 
    unsigned int SlaveAddress = 10000000;
 
    int array[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07};
 
    WriteI2C(unsigned int SlaveAddress, unsigned int ByteCount, array )
 
    return 0;
}
 
Last edited:

JohnInTX

Joined Jun 26, 2012
4,787
It makes sense but it is wrong. Trace the code in your head. Does it do what it needs to do?
What is the purpose of the function parameter ‘ByteCount’? See #56.
How many times are you sending Start?
Besides the slave address, does it ever send any data?
 

Thread Starter

Gajyamadake

Joined Oct 9, 2019
310
It makes sense but it is wrong. Trace the code in your head. Does it do what it needs to do?
What is the purpose of the function parameter ‘ByteCount’? See #56.
How many times are you sending Start?
Besides the slave address, does it ever send any data?
@JohnInTX look at this flow chart to write data to DS1307. if this is correct then I may be able to write code easily

Flow chart is not complete because I have limited version but it show the process to write data to DS1307
 

Attachments

JohnInTX

Joined Jun 26, 2012
4,787
That is not the way the DS1307 works.

Can we get back to the WriteI2C function? Because if you complete that, you can write to the DS1307 or ANY I2C device, including the DS1307.
 

Thread Starter

Gajyamadake

Joined Oct 9, 2019
310
That is not the way the DS1307 works.

Can we get back to the WriteI2C function? Because if you complete that, you can write to the DS1307 or ANY I2C device, including the DS1307
I'm trying to understand but don't know why I can't understand. Now I am losing my passion too
 
Last edited:

JohnInTX

Joined Jun 26, 2012
4,787
Please read #56 again.
You have changed the topic from general I2C to writing to the DS1307.
The topic of this thread is general I2C and I described how to write a GENERAL PURPOSE function to write ANY I2C device, including the DS1307. You started to write that then you changed to trying to write to the DS1307 in a completely different (and wrong) way.

If you go back and read #56 again, you will see that WriteI2C is designed to:
write to ANY slave - using the passed SlaveAddress parameter.
write ANY number of bytes - using the passed ByteCount parameter
write ANY data - using the pointer to char BytesToSend parameter

Once you have implemented WriteI2C, you can use it to write the DS1307 or any other I2C device just by changing the parameters.

You need to
Send START
Send the Slave Address and get the ACK
Use a loop to send the number of bytes specified by ByteCount and get ACK after each one
Get each byte from a char array pointed to by *BytesToSend

When done or on any NAK, send STOP
Return OK if all bytes were sent and ACKed else return ERROR.

Refer to the I2C spec if you need to.

Pay attention to what you are doing. You changed the data types in the formal declaration of WriteI2C. You are not sending from an array of unsigned int, you are sending from an array of unsigned char. The slave address is not an integer, it is an unsigned char also. The function does not need to return an unsigned int, just an unsigned char.

Use a flow char or pseudo-code to fix what you started in #57 using the notes I posted in #58 and finish the WriteI2C function.

Once you have WriteI2C complete you can write all of the DS1307 registers using:

C:
// Define data to write
unsigned char RegData[]={0x00, 0,1,2,3,4,5,6,7};   // 9 bytes, register address + 8 bytes of data to write to the registers starting at register address 0x00

WriteI2C(0x0d, 9, RegData); // Slave Address = 0dh, 9 bytes to write, data located at RegData[0]
Simple!
 
Last edited:

JohnInTX

Joined Jun 26, 2012
4,787
This is the function when it will execute it will give result that may be Success or Failure. function parameter SlaveAddress pass the address of DS1307. function parameter ByteCount pass the integer value. function parameter *BytesToSend pass pointer to integer

Code:
unsigned int WriteI2C(unsigned int SlaveAddress, unsigned int ByteCount,  unsigned int *BytesToSend)
{
...............
}
What is ByteCount, and *BytesToSend . What is purpose of passing ByteCount, unsigned int *BytesToSend ? I am sending nine bytes to ds1307. one byte is address of ds1307 and eight bytes are the address of ds130s registers. I think it ByteCount counts how many bytes I have sent And BytesToSend pass data from 00h to 007h
See #69
 

Thread Starter

Gajyamadake

Joined Oct 9, 2019
310
Getting busy for the holidays.
Here's a flow chart describing WriteI2C. You should be able to generate code from that.
Enjoy.
Code:
I2C_SendByte(SlaveAddr & 0xFE)
1101 0000 & 1111 1110 = 1101 0000

What is meaning of following line ?
I2C_SendByte(1101 0000 )
 

JohnInTX

Joined Jun 26, 2012
4,787
Code:
I2C_SendByte(SlaveAddr & 0xFE)
1101 0000 & 1111 1110 = 1101 0000
The AND function guarantees that the R/W- bit in the slave address is 0 to ensure a write. It is to guard against programmer mistakes and to allow using one slave address for both read and write (the read routine would set that bit).
 

Thread Starter

Gajyamadake

Joined Oct 9, 2019
310
The AND function guarantees that the R/W- bit in the slave address is 0 to ensure a write. It is to guard against programmer mistakes and to allow using one slave address for both read and write (the read routine would set that bit).
I have written a simple code in c to pass char array

C:
#include<stdio.h>
void I2C_SendByte ( int ByteCount,  unsigned char *DataBufferP)
{
   int i;
   for ( i = 0; i < ByteCount; i++)
         printf("\n %x store at %p ",*(DataBufferP+i),(DataBufferP+i));
}
int main (void)
{
    int ByteCount = 9;
    unsigned char RegData[]={0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,0x07};
    I2C_SendByte(ByteCount, RegData);  
  return 0;
}
0 store at 0061FF23
0 store at 0061FF24
1 store at 0061FF25
2 store at 0061FF26
3 store at 0061FF27
4 store at 0061FF28
5 store at 0061FF29
6 store at 0061FF2A
7 store at 0061FF2B

Is it a correct way ?
 

JohnInTX

Joined Jun 26, 2012
4,787
It shows one way to access characters in an array but it is not what the flow chart says that I2C_SendByte() should do. Please stay focused on the task at hand abd write the code for WriteI2C as shown in the flow chart.
 
Last edited:

Thread Starter

Gajyamadake

Joined Oct 9, 2019
310
It shows one way to access characters in an array but it is not what the flow chart says that I2C_SendByte() should do. Please stay focused on the task at hand abd write the code for WriteI2C as shown in the flow chart.
Please Look at these codes
C:
void I2C_Start();
void I2C_Stop();
unsigned char I2C_SendByte(unsigned char data);  // send 8 bits to the slave - also used to send slave address
unsigned char I2C_GetACK_NAK();  // clock once and read ACK or NAK after sending a byte. Return result
unsigned char I2C_ReadByte(char *c);  // clock SCL 8 times and read 8 bits from slave to c
unsigned char I2C_SendACK();  // clock once with SDA=0 to ACK slave
unsigned char I2C_SendNAK();  // clock once with SDA=1 to NAK slave
unsigned char I2C_SendRepeatStart();  // get the bus to idle then send repeat start condition

unsigned char WriteI2C (unsigned char SlaveAddr, int ByteCount,  unsigned char *DataBufferP)
{
    unsigned char ReturnValue;   unsigned char NAK= 1;
    I2C_Start();
    I2C_SendByte(SlaveAddr & 0xFE)
    ReturnValue = I2C_GetACK_NAK();

    if(ReturnValue == NAK)
        I2C_Stop();
    else
        for (ByteCount =9; ByteCount ==0; ByteCount--)
               I2C_SendByte(*DataBufferP)
               ReturnValue = I2C_GetACK_NAK();
               if(ReturnValue == NAK)
                   I2C_Stop();           
               ++*DataBufferP 
int main ()
{
    int ByteCount = 9;
    unsigned char SlaveAddr = 0xD0;
    unsigned char RegData[]={0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};
    I2C_SendByte(SlaveAddr, ByteCount, RegData);
    return 0;
    }
 
Last edited:

JohnInTX

Joined Jun 26, 2012
4,787
Trace the code using the flow chart as a guide. Does it match?
*DataBufferP is used correctly.

Problems:
Why are you initializing ByteCount in the 'for' loop? ByteCount is a variable passed to WriteI2C so it can be used to write a variable number of bytes.
Your code flow does not always send I2C stoP. How would you get out of the 'for' loop if you got a NAK back?
ACK and NAK are constants, not variables. I would suggest:
#define ACK 0
#define NAK 1

main is sloppy sloppy sloppy. Why are you calling I2C_SendByte? Slow down, pay attention to each step and re-check before posting.
 
Last edited:

BobaMosfet

Joined Jul 1, 2009
2,211
@Gajyamadake
A different approach is necessary. Pick an MCU. PIC or ATMEGA, and see if someone will help you. Time to do, not just talk. Talking isn't working, you aren't comprehending. And if, as you stated above, you are 'losing your passion,' then I recommend you consider a different direction of interest, IMHO.
 

Thread Starter

Gajyamadake

Joined Oct 9, 2019
310
A different approach is necessary. Pick an MCU. PIC or ATMEGA, and see if someone will help you. Time to do, not just talk. Talking isn't working, you aren't comprehending.
@BobaMosfet I appreciated your advice but what's wrong with current approach. I am new boy in embedded world. Things are not easy for me but I am trying my best. I have learned so much in this thread. And I am still trying to understand some things that can be learned myself by spending a some time. I wanted to come back by figuring out some facts by myself. And i am doing thats why I am taking time

And if, as you stated above, you are 'losing your passion,' then I recommend you consider a different direction of interest, IMHO.
you know why I am fan of @JohnInTX because look at his passion He helped me a lot. And if I made a mistake on somewhere , he never gives negative thoughts. he is motivating me to keep working
 

Thread Starter

Gajyamadake

Joined Oct 9, 2019
310
Trace the code using the flow chart as a guide. Does it match?
I have matched code with flow chart and I have written code as shown in flow chart as per my understanding
C:
#define ACK 0
#define NAK 1

void I2C_Start();
void I2C_Stop();
unsigned char I2C_SendByte(unsigned char data);  // send 8 bits to the slave - also used to send slave address
unsigned char I2C_GetACK_NAK();  // clock once and read ACK or NAK after sending a byte. Return result
unsigned char I2C_ReadByte(char *c);  // clock SCL 8 times and read 8 bits from slave to c
unsigned char I2C_SendACK();  // clock once with SDA=0 to ACK slave
unsigned char I2C_SendNAK();  // clock once with SDA=1 to NAK slave
unsigned char I2C_SendRepeatStart();  // get the bus to idle then send repeat start condition

unsigned char WriteI2C (unsigned char SlaveAddr, int ByteCount,  unsigned char *DataBufferP)
{
    unsigned char ReturnValue; 
  
    I2C_Start();
    I2C_SendByte(SlaveAddr & 0xFE)
    ReturnValue = I2C_GetACK_NAK();

    if(ReturnValue == NAK)
        I2C_Stop();
        return ReturnValue;
      
    while (ByteCount == 0}
    {
        I2C_SendByte(*DataBufferP)
        ReturnValue = I2C_GetACK_NAK();

        if(ReturnValue == NAK)
            I2C_Stop();
            return ReturnValue;
          
        ++DataBufferP
        --ByteCount      
    }
    I2C_Stop();
        return ReturnValue;
}

int main ()
{
    int ByteCount = 9;
    unsigned char test1;
    unsigned char SlaveAddr = 0xD0;
    unsigned char RegData[]={0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};
    test1 = WriteI2C(SlaveAddr, ByteCount, RegData);
    return 0;
 }
 
Last edited:
Top