tough time with AT24C16 EEPROM, code attached

Thread Starter

hadeedunhaad

Joined Apr 22, 2011
24
hi all, i'm stuck with this eeprom for last one week. Initially i could write and read from EEPROM (AT24C16), but any one in an execution, that is if i write a byte then my next function of reading a byte wont work and vice versa. And the page read/write was also not working. So i started to sniff around my 'stop' protocol for I2C, but to no avail. I continued troubleshooting and now i ended up with NOTHING. I've lost even my previous output. No read and no write. Im using AT89C2051 micro-controller. Code is provided below. Any help will be greatly appreciated.

; program for AT89C2051

; layout details
; write protect pin (eeprom) is connected to gnd
; Xtal used is 20Mhz
; R4 memmory address1
; R5 eeprom data
; status led connected to p1.3 is sinked for switching ON
; SDA and SCL pins are provided with pull ups - 4.7k

led EQU P1.3 ; Led for the status indication
sda EQU P3.7 ;
scl EQU P1.2 ;
;===============================================

ORG 0000h
sjmp start
;===============================================

ORG 0030h ; Initialization

start:

mov sp, #30h ; moving the stack pointer
setb led ; put the LED off

;======================================================== Main Program


mov r4,#00h ;mem location
mov r5,#14h ;data
lcall write_data

mov r4,#01h ;mem location
mov r5,#15h ;data
lcall write_data

clr led

sjmp $

;==========================================================

;=========================================================
; Sub routines for I2C communication (EEPROM)
;=========================================================

write_data:
acall eeprom_start
mov a,#0a0h
acall send_data
mov a,r4 ;location address
acall send_data
mov a,r5 ;data to be send
lcall send_data
acall eeprom_stop
ret
;=========================================================
read_data:
acall eeprom_start
mov a,#0a0h
acall send_data
mov a,r4 ;location address
acall send_data
acall eeprom_start
mov a,#0a1h
acall send_data
acall get_data
acall eeprom_stop
ret
;=========================================================
eeprom_start:
setb scl
nop
setb sda
nop
nop
clr sda
nop
clr scl
nop
nop
nop
ret
;=========================================================
eeprom_stop: setb sda
nop
nop
setb scl
nop
nop
clr scl
nop
nop
nop
ret
;=========================================================
send_data: mov r7,#00h
senda: rlc a
mov sda,c
acall clock
inc r7
cjne r7,#08,senda
setb sda
nop
setb scl
jb sda, $
clr scl
nop
nop
nop
; acall eeprom_delay
ret
;=========================================================
get_data:
mov r7,#00h
setb sda
get: setb scl
nop
nop
mov c,sda
rlc a
inc r7
clr scl
nop
nop
nop
cjne r7,#08,get
mov r1,a
ret
;=========================================================
clock : setb scl
nop
nop
clr scl
nop
nop
nop
ret
;=========================================================
eeprom_delay : mov r7,#16 ;delay of 4.9 msec
eepromd: mov r2,#0ffh
djnz r2,$
djnz r7,eepromd
ret
;=====================================================
/*
ack:
setb sda
nop
setb scl
nop
nop
clr sda
nop
nop
clr scl
nop
nop
nop
ret
;=====================================================
no_ack:
clr sda
setb scl
nop
nop
setb sda
clr scl
nop
nop
nop
ret */
;=====================================================
end;
 

Thread Starter

hadeedunhaad

Joined Apr 22, 2011
24
Hey all ! is there no one who can help me in this. Im waiting and i cant find any answer. i'm re posting my code.


Rich (BB code):
; layout details
; write protect pin (eeprom) is connected to gnd

; Xtal used is 20Mhz
; R4 memmory address1
; R5 eeprom data
; status led connected to p1.3 is sinked for switching ON
; SDA and SCL pins are provided with pull ups - 4.7k

led            EQU     P1.3          ; Led for the status indication
sda         EQU     P3.7          ;
scl            EQU     P1.2          ;
;===============================================
   
   ORG 0000h
   sjmp start    
;===============================================

   ORG 0030h                            ; Initialization 
        
 start:
 
 mov   sp,  #30h      ; moving the stack pointer
 setb  led               ; put the LED off    
                                                                                                                                                                                                                                                                                                     
 ;======================================================== Main Program
  
                
       mov r4,#00h              ;mem location
       mov r5,#14h              ;data
    lcall write_data    
                                 
    mov r4,#01h              ;mem location    
    mov r5,#15h              ;data
    lcall write_data

    clr led
    
    sjmp $
                
;==========================================================
       
;=========================================================
; Sub routines for I2C communication (EEPROM)                       
;=========================================================

write_data:     
                acall eeprom_start
                mov a,#0a0h          
                acall send_data
                mov a,r4              ;location address
                acall send_data
                mov a,r5              ;data to be send
                lcall send_data
                acall eeprom_stop
                   ret   
;=========================================================
read_data: 
                acall eeprom_start
                mov a,#0a0h
                acall send_data
                mov a,r4          ;location address
                acall send_data
                acall eeprom_start
                mov a,#0a1h
                acall send_data
                acall get_data
                acall eeprom_stop
                ret
;=========================================================
eeprom_start:  
                setb scl
                nop
                setb sda
                nop
                nop
                clr sda
                nop
                clr scl
                nop
                nop
                 nop               
                ret
;=========================================================
eeprom_stop:   setb sda
               nop
               nop
               setb scl
               nop
               nop
               clr scl
               nop
               nop
               nop
               ret
;=========================================================
send_data:     mov r7,#00h
       senda:  rlc a
               mov sda,c
               acall clock
               inc r7
               cjne r7,#08,senda
               setb sda
               nop
               setb scl    
               jb sda, $ 
               clr scl
               nop
               nop                        
               nop
            ;  acall eeprom_delay
               ret                                       
;=========================================================
get_data:
               mov r7,#00h
               setb sda
          get: setb scl
               nop
               nop
               mov c,sda
                  rlc a
               inc r7
               clr scl
               nop
               nop
               nop
               cjne r7,#08,get
               mov r1,a
               ret
;=========================================================
clock :        setb scl
               nop
               nop
               clr scl
               nop
               nop
               nop
               ret
;=========================================================
eeprom_delay :  mov r7,#16      ;delay of  4.9 msec 
       eepromd: mov r2,#0ffh
                djnz r2,$
                djnz r7,eepromd
                ret
;=====================================================    
/*
 ack:
     setb sda
    nop
    setb scl
     nop
    nop
    clr sda
    nop
    nop
    clr scl
     nop
    nop
    nop
 ret
;=====================================================
 no_ack:
      clr sda
     setb scl
     nop
     nop
     setb sda
     clr scl
     nop
     nop     
     nop
 ret   */
;=====================================================       
end;
 

GetDeviceInfo

Joined Jun 7, 2009
1,642
this is writing/reading an RTC at address 0xD0

Rich (BB code):
//------------------------------------------------------------------------------
// I/O Port Defines
//------------------------------------------------------------------------------
#define   SDL   P2_1   // Serial data
#define   SCK   P2_0   // Serial clock
#define   M41T56   0xD0   // RTC address
//------------------------------------------------------------------------------
// I2C Functions - Bit Banged
//------------------------------------------------------------------------------
void i2c_start (void);      // Sends I2C Start Trasfer
void i2c_stop (void);      // Sends I2C Stop Trasfer
void i2c_write (BYTE input_data); // Writes data over the I2C bus
BYTE i2c_read ();    // Reads data from the I2C bus
 
//------------------------------------------------------------------------------
// I2C Peripheral Function Prototypes
//------------------------------------------------------------------------------
BYTE read_device(BYTE Device, BYTE Reg);
void write_device (BYTE Device, BYTE Reg, BYTE Data); 
 
void main (void)
{
 BYTE x;
 BYTE Val;
 // Set time
 write_device(M41T56,0x00,0x00);   // Secs
 write_device(M41T56,0x01,0x00);   // mins
 write_device(M41T56,0x02,0x00);   // hrs
 write_device(M41T56,0x03,0x01);   // days
 write_device(M41T56,0x04,0x21);   // date
 write_device(M41T56,0x05,0x02);   // month
 write_device(M41T56,0x06,0x09);   // year
 write_device(M41T56,0x07,0x00);   // control
 // Looping read out of time registers
 while(1)
 {
  for(x=0; x<8; x++)
  {
   Val = read_device(M41T56,0x00 + x);
  }
  delay(5000);
 }
}
 
void write_device (BYTE Device, BYTE Reg, BYTE Data) 
{
    i2c_start();                     // Send I2C Start Transfer
    i2c_write(Device);           // Send identifier I2C address - Write
    i2c_write(Reg);               // Send control byte to device
    i2c_write(Data);     
    i2c_stop();                    // Send I2C Stop Transfer
}
 
 
BYTE read_device(BYTE Device, BYTE Reg)
{
    BYTE data_in;
    i2c_start();                     // Send I2C Start Transfer
    i2c_write(Device);            // Send identifier I2C address - Write
    i2c_write(Reg);                // Send control byte to device (last 2 bits is the channel)
    i2c_stop();                      // Send I2C Stop Transfer
    i2c_start();                     // Send I2C Start Transfer
    i2c_write(Device | 0x01);  // Send identifier I2C address - Read
    data_in = i2c_read();       // Read the channel number
    return (data_in);                 
}
 
 
 //------------------------------------------------------------------------------
// I2C Functions - Bit Banged
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
//  Routine: i2c_start
// Inputs:  none
// Outputs: none
// Purpose: Sends I2C Start Trasfer - State "B"
//------------------------------------------------------------------------------
void i2c_start (void)
{
 SDL = HIGH;       // Set data line high
 SCK = HIGH;       // Set clock line high
 SDL = LOW;       // Set data line low (START SIGNAL)
 SCK = LOW;        // Set clock line low
}
//------------------------------------------------------------------------------
//  Routine: i2c_stop
// Inputs:  none
// Outputs: none
// Purpose: Sends I2C Stop Trasfer - State "C"
//------------------------------------------------------------------------------
void i2c_stop (void)
{
 BYTE input_var;
 SCK = LOW;        // Set clock line low
 SDL = LOW;       // Set data line low
 SCK = HIGH;       // Set clock line high
 SDL = HIGH;       // Set data line high (STOP SIGNAL)
 input_var = SDL;      // Put port pin into HiZ
}
//------------------------------------------------------------------------------
//  Routine: i2c_write
// Inputs:  output byte
// Outputs: none
// Purpose: Writes data over the I2C bus
//------------------------------------------------------------------------------
void i2c_write (BYTE output_data)
{
 BYTE index;
 for(index = 0; index < 8; index++)   // Send 8 bits to the I2C Bus
 {                                    
       SDL = ((output_data & 0x80) ? 1 : 0);  // Output the data bit to the I2C Bus
       output_data  <<= 1;              // Shift the byte by one bit
       SCK = HIGH;               // Clock the data into the I2C Bus
       SCK = LOW;     
 }
       SDL = HIGH;        // Put data pin into read mode
       SCK = HIGH;                // Clock the ACK from the I2C Bus
       SCK = LOW;     
}
//------------------------------------------------------------------------------
//  Routine: i2c_read
// Inputs:  none
// Outputs: input byte
// Purpose: Reads data from the I2C bus
//------------------------------------------------------------------------------
BYTE i2c_read (void)
{
    BYTE index, input_data;
    SDL = 1;       // Put data pin into read mode
    input_data = 0x00;
    for(index = 0; index < 8; index++)   // Send 8 bits to the I2C Bus
    {
        input_data <<= 1;     // Shift the byte by one bit
        SCK = HIGH;               // Clock the data into the I2C Bus
        input_data |= SDL;        // Input the data from the I2C Bus
        SCK = LOW;     
    }
    return (input_data);
}
 
Last edited:
You need to go back to the data book on i2c and make sure all your commands are correct.
Also check your timing, it could be you are clocking too quickly.
 

Thread Starter

hadeedunhaad

Joined Apr 22, 2011
24
again all, here is the present status.
It returned to the earlier state. Reading is possible and Writing is possible separately. Hence i don't doubt much on my clocking delay. Thanks for your suggestion nigelwright7557. And also i had put my initial delays based upon the data sheet and now i've placed more timings.

I noticed the following things. Before that im posting my current code.

Rich (BB code):
; layout details
; write protect pin (eeprom) is connected to gnd

; Xtal used is 20Mhz
; R4 memmory address1
; R5 eeprom data
; status led connected to p1.3 is sinked for switching ON
; SDA and SCL pins are provided with pull ups - 4.7k

led            EQU     P1.3          ; Led for the status indication
sda         EQU     P3.7          ;
scl            EQU     P1.2          ;
;===============================================
   
   ORG 0000h
   sjmp start    
;===============================================

   ORG 0030h                            ; Initialization 
        
 start:
 
 mov   sp,  #30h             ; moving the stack pointer
 setb  led                 ; put the LED off    
                                                                                                                                                                                                                                                                                                     
 ;======================================================== Main Function 
  

    mov r4,#00h                ;mem location
    mov r5,#11h                ;data
    lcall write_data    
    mov a,#11h              ;data to be send
    lcall send_data
    mov a,#11h              ;data to be send
    lcall send_data
    mov a,#11h              ;data to be send
    lcall send_data
    mov a,#11h              ;data to be send
    lcall send_data
    acall eeprom_stop

    mov r4,#05h              ;mem location
     mov r5,#22h              ;data
    lcall write_data
    acall eeprom_stop

/*                                              

readagain:
    mov r4,#04h              ;mem location    
    lcall read_data
    cjne r1, #11h, readagain         */

    clr led
    
    sjmp $
                
;==========================================================
       
;=========================================================
; Sub routines for I2C communication (EEPROM)                       
;=========================================================

write_data:     
                acall eeprom_start
                mov a,#0a0h          
                acall send_data
                mov a,r4              ;location address
                acall send_data
                mov a,r5              ;data to be send
                lcall send_data
             ;     acall eeprom_stop
                   ret   
;=========================================================
read_data: 
             
                acall eeprom_start
                mov a,#0a0h
                acall send_data
                mov a,r4          ;location address
                acall send_data
                acall eeprom_start
                mov a,#0a1h
                acall send_data
                acall get_data
                acall eeprom_stop
                ret
;=========================================================
eeprom_start:  
                setb sda
                nop
                setb scl
                nop
                nop
                nop
                clr sda
                nop
                nop
                clr scl
                nop
                nop
                 nop               
                ret
;=========================================================
eeprom_stop:   
               clr sda
               nop
               nop
               nop
               nop
               nop
               nop
               setb scl
               nop
               nop
               nop
               nop
               nop
               nop
               setb sda
               nop
               nop
               nop
               ret
;=========================================================
send_data:     mov r7,#00h
       senda:  rlc a
               mov sda,c
               acall clock
               inc r7
               cjne r7,#08,senda
               setb sda
               nop
               nop
               nop
               setb scl    
               jb sda, $ 
               clr scl
               nop
               nop                        
               nop
               nop
               nop
               nop
            ;  acall eeprom_delay
               ret                                       
;=========================================================
get_data:
               mov r7,#00h
       get:       setb sda
               nop
               setb scl
               nop
               nop
               mov c,sda
                  rlc a
               inc r7
               clr scl
               nop
               nop
               nop
               cjne r7,#08,get
               mov r1,a
               ret
;=========================================================
clock :        setb scl
               nop
               nop
               nop
               nop
               clr scl
               nop
               nop
               nop
               nop
               nop
               nop
               ret
;=========================================================
eeprom_delay :  mov r7,#16      ;delay of  4.9 msec 
       eepromd: mov r2,#0ffh
                djnz r2,$
                djnz r7,eepromd
                ret
;=====================================================    
/*
 ack:
     setb sda
    nop
    setb scl
     nop
    nop
    clr sda
    nop
    nop
    clr scl
     nop
    nop
    nop
 ret
;=====================================================
 no_ack:
      clr sda
     setb scl
     nop
     nop
     setb sda
     clr scl
     nop
     nop     
     nop
 ret   */
;=====================================================       
end;
If the above code is burned then the output is :
Memory location 00 to 04 are written with '11' and the next function of writing the same value to mem location 05 doesn't work :confused: The led doesn't blink in this case. This shows the program is somewhere stuck inside the second function. So the only thing i can suspect is something is happening in my stop protocol.

similarly if i do the below modifications in my 'main function'

Rich (BB code):
 ;======================================================== Main Function 
  
/*
    mov r4,#00h                ;mem location
    mov r5,#11h                ;data
    lcall write_data    
    mov a,#11h              ;data to be send
    lcall send_data
    mov a,#11h              ;data to be send
    lcall send_data
    mov a,#11h              ;data to be send
    lcall send_data
    mov a,#11h              ;data to be send
    lcall send_data
    acall eeprom_stop

    mov r4,#05h              ;mem location
       mov r5,#22h              ;data
    lcall write_data
    acall eeprom_stop
                                                        */
                                           

readagain:
    mov r4,#04h              ;mem location    
    lcall read_data
    cjne r1, #11h, readagain         

    clr led
    
    sjmp $
                
;==========================================================
It reads perfectly and the led blinks.
It shows me both read and write protocols are working smooth. But when there is a 'stop' function called then the following function doesn't seems to be working.

Please help me out from this if any one of you could figure it out.

Thank you "GetDeviceInfo" for your code. Even though its in C which i dont use, still i checked and found it matching to my code.

Awaiting your responses. Thank you all for your patience and support.
 

Thread Starter

hadeedunhaad

Joined Apr 22, 2011
24
alas ! the problem got solved, thank you friends for you support.:)

FYI, following is the change which i made to my code.

Rich (BB code):
send_data:   
               mov b,a
               mov r7,#00h
     sends: rlc a
               mov sda,c
               acall clock
               inc r7
               cjne r7,#08,sends
               acall ack
               jnc tookof  
               mov a,b
               acall I2C_stop
               acall I2C_start
               sjmp send_data
      tookof:
               ret
 
Top