Friday 22 February 2019

Interfacing EEPROM to LPC2148 using I2C protocol.



I2C is a two-wire synchronous serial communication protocol. SDA line is used for transferring data and SCK is used for transferring clock information. Every device connected to an I2C bus has a unique address. I2C communication protocol involves communication between a slave and a master. The device which initiates the communication and which provides the clock is referred to as a master device. The devices which receive the clock signal and receive/transmit data according to the clock signal is termed as a slave device. Each device on the bus is accessed using its slave address.

Block Diagram: 
I2C Protocol

Communication Process in an I2C bus:
I2C frame:
I2C Frame
 where,
 S: Start bit
 ACK: Acknowledgment
 P: Stop bit
Start bit, Slave address 7bit+R/W,8bit data and stop bit all are transmitted from master to slave.
ACK bit is from slave to master.

START Condition:

STEP-1
First the MCU will issue a START condition. The devices connected to the bus will listen to the START condition and will stay ready to begin the communication process.
STEP-2

Then MCU will send the address of the device with which it needs to communicate. Master indicates the action to be performed with the device whether to read or write along with the address.
STEP-3

All devices connected to the bus will receive the address and will compare it with its own address. If the addresses match with each other, the device will send back an ACKNOWLEDGEMENT signal to the master device. If they  don’t match they will simply wait for the bus to be released with a STOP condition.
STEP-4

Once the MCU sends the address and corresponding device acknowledges, the MCU can start transmitting or receiving data.
STEP-5

When the data transmission or reception is complete, the MCU will stop communicating by sending a STOP condition.

STOP Condition:
STEP-6
STOP condition indicates that the bus is released and it can be used by any other master (if any) connected to the I2C bus.

After a master generate a start condition I2C bus will solely belong to it. The bus will be freed only if the master generate a STOP condition. Any other master connected to the bus can access the bus after a STOP is identified on the bus.
If the master device which uses the bus needs to communicate with a different slave it should generate a RESTART. Instead if it tries to stop current communication and then start again it may lose access to the bus. RESTART is nothing but a start signal without a stop in the bus.

I2C Module in LPC2148:

Features:

  • Two fast I2C buses (I2C0, I2C1)
  • Standard I2C compliant bus interfaces that may be configured as Master, Slave, or Master/Slave.
  • Programmable clock to allow adjustment of multiple I2C data transfer rates.
    • Standard- 100 kbps
    • Fast- 400 kbps
    • High Speed- 3.4 Mbps
  • Bidirectional data transfer between masters and slaves.
  • Serial clock synchronization allows devices with different bit rates to communicate via one serial bus.
  • Serial clock synchronization can be used as a handshake mechanism to suspend and resume serial transfer.
  • The I2C bus may be used for test and diagnostic purposes.

Pin Description:

Pin description

I2CCONSET Register(x=0/1):

  • Writing a 1 to a bit in this register causes corresponding bit in the I2C control register to set.
  • Writing a 0 has no effect.
  •  

    Bit 1:0 – Reserved 

    Bit 2 – AA (Assert Acknowledge Flag)
    When set to 1, Acknowledge (SDA LOW) is returned during acknowledge clock pulse on SCL. Otherwise, Not acknowledge (SDA HIGH) is returned. 


    Bit 3 – SI (I2C Interrupt Flag)
    I2C serial interrupt, SI=1, indicate state change. 


    Bit 4 – STO (Stop Flag)
    STOP conditon, STO=1, sends stop condition

    Bit 5 – STA (Start Flag)
    START conditon, STA=1,send start condition 
    Setting this bit causes the I2C interface to enter in master mode and transmit a START condition.

    Bit 6 – I2CEN (I2C Interface Enable) 

    I2CEN=1, I2C interface enable .

    Bit 7 – Reserved 



    I2CxCONCLR Register(x=0/1):


    Bit 1:0 – Reserved

    Bit 2 – AAC(Assert Acknowledgment Flag Clear)
    Setting this bit clears the AA bit in I2CCONSET register.

    Bit 3 – SIC(I2C interrupt flag clear)
    Setting this bit clears the SIC bit in I2CCONSET register.

    Bit 4 – Reserved

    Bit 5 – STAC(START Flag Clear)
    Setting this bit clears the STAC bit in I2CCONSET register.

    Bit 6 – I2CENC(I2C interface disable)
    Setting this bit clears the I2CENC bit in I2CCONSET register.

    Bit 7 – Reserved



    I2CxDAT Register(x=0/1): 

    It is I2C data register.Ii is 8 bit read/ write register.It contains data is to be transmitted or received.

    Note: This register only read or written only SI=1.


    SCL Cycle:


    SCL duty cycle
    The Frequency and duty cycle of SCL is decided using I2CxSCLL and  I2CxSCLH. The I2CxSCLL contain Toff(Low time) and I2CxSCLH contain Ton(High time).
    The frequency is calculated as follows:



    Consider PCLK= 15Mhz and I2C bit frequency is 100Khz.
    So, I2C0SCLL=I2C0SCLH= 75 (0xFB)


    I2CxSCLL Register(x=0/1):

    It is 16 bit register.It is I2C SCL Low duty cycle register.
    This register contains the value for SCL low time of the cycle. 


    I2CxSCLH Register(x=0/1):

    It is 16 bit register.It is I2C SCL High duty cycle register.
    This register contains the value for SCL High time of the cycle.
      
    SI bit:


    Features of EEPROM:
    • The AT24C512 provides 524,288 bits of serial electrically erasable and programmable read only memory (EEPROM) organized as 65,536 words of 8 bits each. 
    • The device’s cascadable feature allows up to four devices to share a common two-wire bus. 
    • The device is optimized for use in many industrial and commercial applications where low power and low-voltage operation are essential. 




    Programming Steps:

    1) Initialization
    •  Select I2C0 using PINSEL0.
    • Enable I2C interface using I2C0CONSET register.
    • Find the value of I2C0SCLL and I2C0SCLH for frequency 100Khz.

     void I2C_Init()
         {
              PINSEL0|=0x00000050; // select I2C0 ,SDA0 & SCL0 
              I2C0CONCLR=0xFF;   //Clear All bits
              I2C0CONSET=0x40;    //Set I2C Enable
              I2C0SCLH=75;    //Set I2C_Clock = 100Khz
              I2C0SCLL=75;    //with 50% duty cycle
         }



      2) START
      • Set start condition using I2C0CONSET register.
      • wait up to SI bit=1.
      • Clear start condition bit and SI bit using I2C0CONCLR register.

        void Send_Start()
            {
              I2C0CONSET=0x20;                 //Set start conditon 
              while(!(I2C0CONSET&0x08)); //Check SI Flag
              I2C0CONCLR=0x28;               //Clear SI flag
            }

       

      Code:

      //Interfacing EEPROM to LPC2148 using I2C protocol.

       #include<LPC214x.h>
      void LCD_init(void);
      void LCD_cmd(unsigned char cmd);
      void LCD_data(unsigned char data);
      void LCD_writestring(unsigned char *str);
      void I2C_init(void);
      void byte_write(unsigned char address, unsigned char location, unsigned char data);
      void send_start(void);
      void send_stop(void);
      unsigned char byte_read(unsigned char address,unsigned char location);
      void msdelay(unsigned int time);

      void main()
      {
          int i;
          unsigned char read_data;
          unsigned char write_data[10]={0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4A};
          PINSEL0=0x00000050;
          PINSEL1=0x00000000;
          PINSEL2=0x00000000;
          IODIR1=0x07<<16;                    //RS,RW,En
          IODIR0=0xFF<<16;                    //data lines
          LCD_init();
          I2C_init();
          LCD_writestring("Writing from I2C");

          for(i=0;i<10;i++)
          {
              byte_write(0xA0,i,write_data[i]);
               
              msdelay(100);
              }
              LCD_cmd(0xC0);
              for(i=0;i<10;i++)
              {
              read_data=byte_read(0xA0,i);
            
              LCD_data(read_data);
          }
      }

      void LCD_init(void)
      {
          LCD_cmd(0x38);
          msdelay(100);
          LCD_cmd(0x01);
          msdelay(100);
          LCD_cmd(0x0E);
          msdelay(100);
          LCD_cmd(0x06);
          msdelay(100);
          LCD_cmd(0x80);
      }

      void LCD_cmd(unsigned char cmd)
      {
          IOCLR0=0x0FF<<16;                   //RS=0
          IOCLR1=0x01<<16;                    //RW=0
          IOCLR1=0x01<<17;               
          IOSET0=cmd<<16;                     //data
          IOSET1=0x01<<18;                    //en=1
          msdelay(100);
          IOCLR1=0x01<<18;                    //en=0
      }

      void LCD_data(unsigned char data)
      {
          IOCLR0=0x0FF<<16;                   //RS=0
          IOSET1=0x01<<16;                    //RW=1
          IOCLR1=0x01<<17;                  
          IOSET0=data<<16;                     //data
          IOSET1=0x01<<18;                    //en=1
          msdelay(100);
          IOCLR1=0x01<<18;                    //en=0  
      }

      void LCD_writestring(unsigned char *str)
      {
          int i=0;
          while(str[i]!='\0')
          {
              LCD_data(str[i]);
              msdelay(100);
              i++;
          }
      }

      void I2C_init(void)
      {
          I2C0CONCLR=0xFF;
          I2C0CONSET=0x40;                    //enable I2C
          I2C0SCLH=75;     //0x4B
          I2C0SCLL=75;     //0x4B
      }

      void byte_write(unsigned char address, unsigned char location, unsigned char data)
      {
          I2C0CONCLR=0xFF;
          I2C0CONSET=0x40;
        
          send_start();                     //send start condition
        
          while(!(I2C0CONSET&0x08));        //check SI flag
          I2C0CONCLR=0x28;                  //clear SI flag and start
        
          I2C0DAT=address&0xFE;             //selecting address in
          while(!(I2C0CONSET&0x08));        //check SI flag
          I2C0CONCLR=0x28;                  //clear SI flag and start
        
          I2C0DAT=location;                 //sending memory location
          while(!(I2C0CONSET&0x08));        //check SI flag
          I2C0CONCLR=0x28;                  //clear SI flag and start
        
          I2C0DAT=data;
          while(!(I2C0CONSET&0x08));        //check SI flag
          I2C0CONCLR=0x28;                  //clear SI flag and start flag
        
          send_stop();                      //send stop bit
      }

      void send_start()
      {
          I2C0CONSET=0x20;
      }

      void send_stop()
      {
          I2C0CONSET=0x10;
      }

      unsigned char byte_read(unsigned char address,unsigned char location)
      {
          unsigned char data;
          I2C0CONCLR=0xFF;
          I2C0CONSET=0x40;
        
          send_start();
        
          while(!(I2C0CONSET&0x08));        //check SI flag
          I2C0CONCLR=0x28;                  //clear SI flag and start
        
          I2C0DAT=address&0xFE;             //selecting address in
          while(!(I2C0CONSET&0x08));        //check SI flag
          I2C0CONCLR=0x28;                  //clear SI flag and start
        
          I2C0DAT=location;                 //sending memory location
          while(!(I2C0CONSET&0x08));        //check SI flag
          I2C0CONCLR=0x28;                  //clear SI flag and start
        
          send_start();                     //repeated start
        
          while(!(I2C0CONSET&0x08));        //check SI flag
          I2C0CONCLR=0x28;
        
          I2C0DAT=address|0x01;
          while(!(I2C0CONSET&0x08));        //check SI flag
          I2C0CONCLR=0x28;
          I2C0CONCLR=0x04;                  //NACK
        
          while(!(I2C0CONSET&0x08));        //check SI flag
          I2C0CONCLR=0x28;
          data=I2C0DAT;
          send_stop();
        
          return data;  
      }

      void msdelay(unsigned int time)
      {
          int i,j;
          for(i=0;i<time;i++)
          {
              for(j=0;j<1008;j++)
              {
              }
          }
      }

       



      //Interfacing EEPROM to LPC2148 using I2C protocol.(UART+LCD)



       #include<LPC214x.h>
      void LCD_init(void);
      void LCD_cmd(unsigned char cmd);
      void LCD_data(unsigned char data);
      void LCD_writestring(unsigned char *str);
      void I2C_init(void);
      void byte_write(unsigned char address, unsigned char location, unsigned char data);
      void send_start(void);
      void send_stop(void);
      unsigned char byte_read(unsigned char address,unsigned char location);
      void msdelay(unsigned int time);

      void uart0Init(void)    
      {
          // port 0 tx P0.1 and rx P0.0 selected
          U0LCR=0x83; //8bit data, no parity, 1 stop bit
          U0DLL=97;// 9600 baud rate @15Mhz Pclk
          U0LCR=0x03;// DLAB=0

      }
      void uart0Putch(unsigned char ch)
      {
          U0THR=ch;    // Transmitter holding register
          while(!(U0LSR & 0x20));// wait still THR=0
      }
      void UART0_Txstring(unsigned char *Str)
      {
      int i=0;
      while(Str[i]!='\0')
       {
         uart0Putch(Str[i]);
         i++;
       }
      }



      int main()
      {
          int i;
          unsigned char read_data;
          unsigned char write_data[10]={0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4A};
          PINSEL0=0x00000055;
          PINSEL1=0x00000000;
          PINSEL2=0x00000000;
          IODIR1=0x07<<16;                    //RS,RW,En
          IODIR0=0xFF<<16;                    //data lines
          LCD_init();
      uart0Init(); 
          I2C_init();
          LCD_writestring("Writing from I2C"); 
      UART0_Txstring("Writing from I2C");
          for(i=0;i<10;i++)
          {
              byte_write(0xA0,i,write_data[i]); 
      uart0Putch(write_data[i]);
                
              msdelay(100);
              }
              LCD_cmd(0xC0);
      uart0Putch(0x0d);
         UART0_Txstring("reading from I2C");
              for(i=0;i<10;i++)
              {
              read_data=byte_read(0xA0,i);
              uart0Putch(read_data);
              LCD_data(read_data);
          }
      }

      void LCD_init(void)
      {
          LCD_cmd(0x38);
          msdelay(100);
          LCD_cmd(0x01);
          msdelay(100);
          LCD_cmd(0x0E);
          msdelay(100);
          LCD_cmd(0x06);
          msdelay(100);
          LCD_cmd(0x80);
      }

      void LCD_cmd(unsigned char cmd)
      {
          IOCLR0=0x0FF<<16;                   //RS=0
          IOCLR1=0x01<<16;                    //RW=0
          IOCLR1=0x01<<17;                
          IOSET0=cmd<<16;                     //data
          IOSET1=0x01<<18;                    //en=1
          msdelay(100);
          IOCLR1=0x01<<18;                    //en=0
      }

      void LCD_data(unsigned char data)
      {
          IOCLR0=0x0FF<<16;                   //RS=0
          IOSET1=0x01<<16;                    //RW=1
          IOCLR1=0x01<<17;                   
          IOSET0=data<<16;                     //data
          IOSET1=0x01<<18;                    //en=1
          msdelay(100);
          IOCLR1=0x01<<18;                    //en=0   
      }

      void LCD_writestring(unsigned char *str)
      {
          int i=0;
          while(str[i]!='\0')
          {
              LCD_data(str[i]);
              msdelay(100);
              i++;
          }


      void I2C_init(void)
      {
          I2C0CONCLR=0xFF;
          I2C0CONSET=0x40;                    //enable I2C
          I2C0SCLH=75;     //0x4B
          I2C0SCLL=75;     //0x4B
      }

      void byte_write(unsigned char address, unsigned char location, unsigned char data)
      {
          I2C0CONCLR=0xFF;
          I2C0CONSET=0x40;
         
          send_start();                     //send start condition
         
          while(!(I2C0CONSET&0x08));        //check SI flag
          I2C0CONCLR=0x28;                  //clear SI flag and start 
         
          I2C0DAT=address&0xFE;             //selecting address in 
          while(!(I2C0CONSET&0x08));        //check SI flag
          I2C0CONCLR=0x28;                  //clear SI flag and start 
         
          I2C0DAT=location;                 //sending memory location
          while(!(I2C0CONSET&0x08));        //check SI flag
          I2C0CONCLR=0x28;                  //clear SI flag and start 
         
          I2C0DAT=data;
          while(!(I2C0CONSET&0x08));        //check SI flag
          I2C0CONCLR=0x28;                  //clear SI flag and start flag
         
          send_stop();                      //send stop bit
      }

      void send_start()
      {
          I2C0CONSET=0x20;
      }

      void send_stop()
      {
          I2C0CONSET=0x10;
      }

      unsigned char byte_read(unsigned char address,unsigned char location)
      {
          unsigned char data;
          I2C0CONCLR=0xFF;
          I2C0CONSET=0x40;
         
          send_start();
         
          while(!(I2C0CONSET&0x08));        //check SI flag
          I2C0CONCLR=0x28;                  //clear SI flag and start 
         
          I2C0DAT=address&0xFE;             //selecting address in 
          while(!(I2C0CONSET&0x08));        //check SI flag
          I2C0CONCLR=0x28;                  //clear SI flag and start 
         
          I2C0DAT=location;                 //sending memory location
          while(!(I2C0CONSET&0x08));        //check SI flag
          I2C0CONCLR=0x28;                  //clear SI flag and start 
         
          send_start();                     //repeated start
         
          while(!(I2C0CONSET&0x08));        //check SI flag
          I2C0CONCLR=0x28; 
         
          I2C0DAT=address|0x01;
          while(!(I2C0CONSET&0x08));        //check SI flag
          I2C0CONCLR=0x28; 
          I2C0CONCLR=0x04;                  //NACK
         
          while(!(I2C0CONSET&0x08));        //check SI flag
          I2C0CONCLR=0x28; 
          data=I2C0DAT;
          send_stop();
         
          return data;   
      }

      void msdelay(unsigned int time)
      {
          int i,j;
          for(i=0;i<time;i++)
          {
              for(j=0;j<1008;j++)
              {
              }
          }
      }

        

       Code:

        //Interfacing EEPROM to LPC2148 using I2C protocol.

         
        #include <lpc214x.h>
        #define RS (1<<16)
        #define RW (1<<17)
        #define E (1<<18)

        #define I2C_ENABLE  1 << 6     //I2C Enable bit
        #define I2C_START 1 << 5     //Start Bit
        #define I2C_STOP  1 << 4     //Stop Bit
        #define I2C_SI  1 << 3     //I2C interrupt flag
        #define I2C_AACK   1 << 2     //assert ACK flag

        #define EEPROM_Addr 0xA0     //device address
        #define I2Cwrite 0x00   //LSB bit 0 (write)
        #define I2Cread  0x01   //LSB bit 1 (read)

        unsigned char write_array[4] ={'P','I','C','T'};
        unsigned char read_array[4];
        unsigned char val[4];

         //Calibrated to 1ms
        void  delay_ms(unsigned char time)
        {
         unsigned int  i, j;
         for (j=0; j<time; j++)
         {
          for(i=0; i<8002; i++);
         }
        }

        void LCD_command(unsigned char command)
        {
         IOCLR0 = 0xFF<<16; // Clear LCD Data lines
         IOCLR1=RS;     // RS=0 for command
         IOCLR1=RW;     // RW=0 for write
         IOSET0=command<<16; // put command on data line
         IOSET1=E;   // en=1
         delay_ms(10) ;   // delay
         IOCLR1=E;    // en=0
        }

        void LCD_data(unsigned char data)
        {
         IOCLR0 = 0xFF<<16; // Clear LCD Data lines
         IOSET1=RS;     // RS=1 for data
         IOCLR1=RW;     // RW=0 for write
         IOSET0= data<<16;  // put command on data line
         IOSET1=E;   //en=1
         delay_ms(10) ;    //delay
         IOCLR1=E;   //en=0
         }

        void LCD_init()
        {
         LCD_command(0x38); //8bit mode and 5x8 dotes (function set)
         delay_ms(10) ;   // delay
         LCD_command(0x0c); //display on, cursor off, cursor char blinking off(display on/off)
         delay_ms(10) ;   // delay
         LCD_command(0x0e);  //cursor increment and display shift(entry mode set)
         delay_ms(10) ;   // delay
         LCD_command(0x01);  //clear lcd (clear command)
         delay_ms(10) ;   // delay
         LCD_command(0x80);
         delay_ms(10) ;//set cursor to 0th location 1st lne

        }

        void LCD_write_string(unsigned char *string)
        {
        int i=0;
          while(string[i]!='\0')
          {
              LCD_data(string[i]);
              i=i+1;  //sending data on LCD byte by byte
          }
        }

        void I2CInit(void)
        {
        PINSEL0 = 0x00000050;       //P0.2 -> SCL0  P0.3 -> SDA0
        I2C0CONCLR  = I2C_ENABLE | I2C_START | I2C_STOP | I2C_SI | I2C_AACK; //clear all the bits in CONTROL register
        I2C0SCLH = 0x4B ;       //set the high time of i2c clock; (15mhz / 100khz / 2)
        I2C0SCLL = 0x4B ;       //set the low time of i2c clock;
        I2C0CONSET = I2C_ENABLE ;     //enable the I2C Interface
        }      

        void I2CStart(void)          //Function to initiate a start condition on the I2C bus
        {
        I2C0CONCLR = (I2C_START | I2C_STOP | I2C_SI | I2C_AACK);  // clear all the bits in CONCLR register
        I2C0CONSET = (I2C_ENABLE );            //Enable the I2C interface
        I2C0CONSET = (I2C_START);           //set the STA bit
        while(!(I2C0CONSET& I2C_SI));  //wait till interrupt flag becomes set
        }


        void I2CStop(void)
        {
           I2C0CONSET = I2C_STOP;          //set STOP bit
        }


        void I2Csend(unsigned char data)
        {

        I2C0DAT = data;
        I2C0CONCLR = I2C_START | I2C_STOP ;      // clear start bit for next operation
        I2C0CONCLR = I2C_SI;                     // clear interrupt flag
        while(!(I2C0CONSET& I2C_SI));//wait till interrupt flag becomes set
        }

        unsigned char I2Cget(void)
        {
        unsigned char data;

        I2C0CONCLR = I2C_START | I2C_STOP;
        I2C0CONCLR = I2C_SI;         // clear interrupt flag
        I2C0CONSET = I2C_AACK;            // send ack to continue further data transfer
        while(!(I2C0CONSET& I2C_SI)); //wait till interrupt flag becomes set
        data = I2C0DAT;
        return data;
        }


        int main(void)
        {
         unsigned int i,j;
         IODIR1= 0x07<<16; //P1.18, P1.17, P1.16 as output
         IODIR0= 0xFF<<16;  //Configure P0.23 - P0.16 as output
         LCD_init();    //Initialize LCD 16x2
         I2CInit();

        LCD_write_string("Writing Data");
        LCD_command(0xC0);
        I2CStart();     //Assert START
        I2Csend(EEPROM_Addr | I2Cwrite);  //Device address with LSB bit 0
        I2Csend(0x13);         //Address higher byte
        I2Csend(0x49);
        for(i=0;i<4;i++)
        {
        I2Csend(write_array[i]); //write the array to EEPROM
        LCD_data(write_array[i]);
        delay_ms(1000);
        }
        I2CStop();  //Assert STOP
        delay_ms(8000);
        LCD_command(0xC0); // Display on second line of LCD
        LCD_command(0x01); // Clear screen

         

        LCD_command(0x80); // Display on first line of LCD
        LCD_write_string("Reading Data");
        I2CStart();        //Assert START
        I2Csend(EEPROM_Addr | I2Cwrite);  //Device address with LSB bit 0 (Dummy Write)
        I2Csend(0x13);     //Address higher byte
        I2Csend(0x49);   //Address lower byte
        I2CStart();       //Assert Restart
        I2Csend(EEPROM_Addr | I2Cread);  //Reading I2Cread=1

        LCD_command(0xC0);
        for(i=0;i<4;i++)
        {
        read_array[i] = I2Cget();   //Read EEPROM
        LCD_data(read_array[i]);
        delay_ms(1000);
        }
        I2CStop();       //Assert STOP

        while (1);
         return 0;
        }





         

        No comments:

        Post a Comment