Connect with us

I2C Understanding of ACK and NAK?

Discussion in 'Microcontrollers, Programming and IoT' started by Daljeet12, Oct 14, 2019.

  1. Daljeet12

    Daljeet12

    19
    0
    Jun 16, 2018
    I do not understand how to implement i2c coding for white box (ACK/NACK Bit) shown in image.


    upload_2019-10-14_21-21-6.png

    When writing to the slave, the master writes 8 bits of data (slave address) and select write mode

    master must check ACK or NAK from the slave as it is writing bytes. If it receives ACK, it continues to send the next byte . If it receives NAK, then it must stop transmission and issue a stoP condition.

    (if someone can help with rough code for explanation it would be appreciated )
     
  2. Harald Kapp

    Harald Kapp Moderator Moderator

    9,376
    1,907
    Nov 17, 2011
    Which processor do you use? Have you checked whether there is a library doing the I²C stuff for this processor? Looking into that library may teach you the stuff you are looking for.
     
  3. Daljeet12

    Daljeet12

    19
    0
    Jun 16, 2018
    I have 8051 and PIC16F877A microcontroller

    I am trying to implement this in coding

    My program supposed to do following things

    Generate
    • Start
    • sto
    • repeat Start
    • get ACK/NAK from a slave being written
    • generate ACK/ANK to a slave being read
    • write the first byte of a a slave address with R/W- bit to specify read or write transactions
    • write a data byte to a slave - maybe combine with get ACK/ANK
    • read a data byte from a slave - maybe combine with generate ACK/NAK
     
  4. Harald Kapp

    Harald Kapp Moderator Moderator

    9,376
    1,907
    Nov 17, 2011
    Use your favorite search engine with these terms:
    "8051 i²c library"
    "PIC16F877A i²c library"
    Read the documentation of the libraries, study the code. This should answer many of your questions.
     
    Daljeet12 and (*steve*) like this.
  5. Daljeet12

    Daljeet12

    19
    0
    Jun 16, 2018
    I am trying to understand this code https://aticleworld.com/interfacing-eeprom-using-i2c/
    Code:
    #include <reg51.h>
    //Delay for I2c
    #define I2C_DELAY    50
    //Define Led Toggle Time
    #define TOGGLE_LED  20000
    //control address of 24lc64
    #define device_addr 0xA0
    #define ACK_BIT    0
    //Define the Pin for the I2c and lec
    
    sbit SDA_BUS = P2^0;
    sbit SCL_BUS = P2^1;
    sbit Led = P3^0;
    
    /*=========================================
       Prototypes for I2c functions
     ==========================================*/
    void InitI2c(void);
    void StartI2c(void);
    void RepeatedStartI2c(void);
    void StopI2c(void);
    void SendAckBit(void);
    void SendNackBit(void);
    void delay(unsigned int);
    bit write_i2c(unsigned char);
    unsigned char read_i2c(void);
    void write_byte_to_eeprom(unsigned int,unsigned char);
    unsigned char  read_byte_from_eeprom(unsigned int);
    
    /*=========================================
       Definition of I2c functions
     ==========================================*/
    /**
    \brief of  delay function.
    This function provide the delay which is used in clock generation.
    */
    void delay(unsigned int d)
    {
        unsigned int i;
        for(i=0; i<d; i++);
    }
    
    /**\brief of InitI2c function.
    This function  use to make the data line and clock line idle to put the both line high
    */
    void InitI2c(void)
    {
        SDA_BUS =1;
        SCL_BUS =1;
    }
    /**
    \brief of StartI2c function.
    
    This function performs the start operation to initiate the communication.
    */
    void StartI2c(void)
    {
        SDA_BUS  = 1;
        SCL_BUS  = 1;
        delay(I2C_DELAY);
        SDA_BUS  = 0;
        delay(I2C_DELAY);
    }
    /**
    \brief of void RepeatedStartI2c function.
    When master does not want to relaese the control from the bus then it assert the repeated
    start condition on the i2c bus.
    */
    void RepeatedStartI2c()
    {
        SCL_BUS  = 0;
        delay(I2C_DELAY/2);
        SDA_BUS  = 1;
        delay(I2C_DELAY/2);
        SCL_BUS  = 1;
        delay(I2C_DELAY/2);
        SDA_BUS  = 0;
        delay(I2C_DELAY);
    }
    /**
    \brief of void StopI2c function.
    When master want to stop the communication then it will assert the stop condition to the i2c bus.
    */
    void StopI2c(void)
    {
        SCL_BUS  = 0;
        delay(I2C_DELAY/2);
        SDA_BUS  = 0;
        delay(I2C_DELAY/2);
        SCL_BUS  = 1;
        delay(I2C_DELAY/2);
        SDA_BUS  = 1;
        delay(I2C_DELAY);
    }
    /**
    \brief of  SendAckBit function.
    This function use to send the acknoledgement(ACK) bit the i2c bus.
    */
    void SendAckBit()
    {
        SCL_BUS  = 0;
        delay(I2C_DELAY/2);
        SDA_BUS  = 0;
        delay(I2C_DELAY/2);
        SCL_BUS  = 1;
        delay(I2C_DELAY);
    }
    /**
    \brief of  SendNackBit function.
    This function use to send the Non-acknoledgement(NACK) bit the i2c bus.
    */
    void SendNackBit(void)
    {
        SCL_BUS  = 0;
        delay(I2C_DELAY/2);
        SDA_BUS  = 1;
        delay(I2C_DELAY/2);
        SCL_BUS  = 1;
        delay(I2C_DELAY);
    }
    /**
    \brief of write_i2c function.
    This function use to send signle byte to the I2C Data Bus
    */
    bit write_i2c(unsigned char byte)
    {
        unsigned char i;
        for(i=0; i<8; i++)
        {
            SCL_BUS  = 0;
            delay(I2C_DELAY);
            if((byte<<i)&0x80)
                SDA_BUS  = 1;
            else
                SDA_BUS  = 0;
            delay(I2C_DELAY/2);
            SCL_BUS  = 1;
            delay(I2C_DELAY);
        }
    //ack from slave //
        SCL_BUS  = 0;
        SDA_BUS  = 0;
        delay(I2C_DELAY/2);
        SCL_BUS  = 1;
        delay(I2C_DELAY);
        return SDA_BUS;
    }
    /**
    \brief of write_i2c function.
    This function use to read the data from the I2C data bus
    */
    unsigned char read_i2c(void)
    {
        unsigned char i,d, rxdata=0;
        for(i=0; i<8; i++)
        {
            SCL_BUS  = 0;
            SDA_BUS  = 1;
            delay(I2C_DELAY);
            SCL_BUS  = 1;
            delay(I2C_DELAY/2);
            d=SDA_BUS;
            rxdata=rxdata|(d<<7-i);
            delay(I2C_DELAY);
        }
        return rxdata;
    }
    
    I don't understand this part of the code
    A function write_i2c return a value and pass the value
    Code:
    \brief of write_i2c function.
    This function use to send signle byte to the I2C Data Bus
    */
    bit write_i2c(unsigned char byte)
    {
        unsigned char i;
        for(i=0; i<8; i++)
        {
            SCL_BUS  = 0;
            delay(I2C_DELAY);
            if((byte<<i)&0x80)
                SDA_BUS  = 1;
            else
                SDA_BUS  = 0;
            delay(I2C_DELAY/2);
            SCL_BUS  = 1;
            delay(I2C_DELAY);
        }
    //ack from slave //
        SCL_BUS  = 0;
        SDA_BUS  = 0;
        delay(I2C_DELAY/2);
        SCL_BUS  = 1;
        delay(I2C_DELAY);
        return SDA_BUS;
    }
     
  6. Harald Kapp

    Harald Kapp Moderator Moderator

    9,376
    1,907
    Nov 17, 2011
    The for loop sends a byte as a series of bits.
    The last part returns the status of the ACK/NACK bit from the I²C slave.
    The signals are controlled by setting the port bits (SCL_BUS, SDA_BUS) to eiterh 0 (low) or 1 (high).
    Timing is controlled by the delay() function.
    Draw a timing diagram following the instruction sequence to understand what's going on.
     
    Daljeet12 likes this.
  7. Daljeet12

    Daljeet12

    19
    0
    Jun 16, 2018
    as i have read following function's, both function generate start condition
    Code:
    void I2CStart()
    {
        SDA = 0;  /* clear SDA */
        SCL = 0;   /* clear SCL */
    }
    Code:
    void I2C_start(void)
    {
        if(SCL)
        SCL = 0;        /* Clear SCL */
    
        SDA = 1;        /* Set SDA */
        SCL = 1;        /* Set SCL */
    
        I2C_delay();
    
        SDA = 0;        /* Clear SDA */
    
        I2C_delay();
    
        SCL = 0;        /* Clear SCL */
    }
    The default state of SDA and SCL line is high.
    My understanding A high to low transition of SDA line while the SCL line is high called the START condition. according this situation first code is not valid for start condition

    which is valid function to generate start condition
     
  8. Harald Kapp

    Harald Kapp Moderator Moderator

    9,376
    1,907
    Nov 17, 2011
    Both functions may be valid. It depends on the context where and how they are used. Although the second function looks more elaborate, the first function may work equally well if it is called from another routine that ensures the correct environment, namely SDA=high and SCL=0.

    You can't evaluate the correctness of a subroutine without inspecting the context.
     
    Daljeet12 likes this.
  9. Daljeet12

    Daljeet12

    19
    0
    Jun 16, 2018
    I am trying to write my own routine for start and stop conditions
    • Start is generated when SDA goes 1-0 when SCL=1
    • Stop is generated when SDA goes 0-1 when SCL=1
    What kind of code we can write for the following:

    Code:
    void START (void)
    {
      SDA = 0 ;  Clear DATA
      SCL = 1;   Set clock to 1
    }
    void STOP (void)
    {
      SDA = 0 ;  Clear DATA
      SCL = 1;   Set clock to 1
    }
    
    does above statement performs the start and stop task
     
  10. Harald Kapp

    Harald Kapp Moderator Moderator

    9,376
    1,907
    Nov 17, 2011
    Think about why in the code example from post #7 this delay statement is used:
    Code:
        I2C_delay();
     
  11. Daljeet12

    Daljeet12

    19
    0
    Jun 16, 2018
    I am sorry I couldn't find the reason after spending long time on the internet why delay needed

    I saw some code They don't use delay https://www.8051projects.net/wiki/I2C_Implementation_on_8051

    I am totally lost here both codes are confusing me
     
  12. Harald Kapp

    Harald Kapp Moderator Moderator

    9,376
    1,907
    Nov 17, 2011
    The 8051 may be slow enough for this to work without delay - I frankly do not know.
    However, I²C requires a defined timing, specifically setup and hold times between changes in clock and data. On a fast processor simply toggling the port bits one after another may violate these conditions. Therefore delays are routinely used to ensure proper timing sequences.
     
    Daljeet12 likes this.
  13. Daljeet12

    Daljeet12

    19
    0
    Jun 16, 2018
    @Harald Kapp Thank you . I am sure you have worked on I2C communication

    I understand the simple code to set or clear port bits

    Code:
    Port1..0 = 1 /* set port bit P1.0 to 1
    Port1..0 = 0 /* clear  port bit P1.0 to 0
    
    same for SDA and SCL
    
    SDA = 1 /* set SDA to 1
    SCL = 0 /* clear  SCL to 0
    A change in the state of the data line from high to low, while the clock line is high, defines a START condition

    I don't understand the transition of SDA and SCL for start condition in I2C communication
     
    Last edited: Oct 21, 2019
Ask a Question
Want to reply to this thread or ask your own question?
You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.
Electronics Point Logo
Continue to site
Quote of the day

-