Author Topic: I2c bit banging, AT89C55WD, EEPROM BL24C04 interfacing  (Read 1846 times)

0 Members and 1 Guest are viewing this topic.

Offline Vindhyachal.taknikiTopic starter

  • Frequent Contributor
  • **
  • Posts: 491
I2c bit banging, AT89C55WD, EEPROM BL24C04 interfacing
« on: April 16, 2016, 03:53:03 pm »
1. I am using AT89C55WD(40 pin DIP), with 12Mhz crystal.
Have to interface BL24C04 with it.

2. System is +5V powered & I have made bit banging code in C for it.
I have kept 50kbps speed. Took refereence from here while making code ( http://saeedsolutions.blogspot.in/2012/10/pic16f84a-i2c-bit-banging-code-proteus.html )

3. I have simualted code in proteus & seems to be working as values shown in its I2c debugger.

4. One issue I think may be its very small delay. At 50kbps , 1 bit delay is 20us, half bit delay is 10us & quarter bit delay is 5us. In codeI have used nop statements for 10us & 5us.

5. In link above, blogger has used quarter(5us)/half(10us) but delay at many places. I dont know why quarter(5us) bit delay is used. Below is code. Is it ok?

Code: [Select]
sbit sda = P1^7;
sbit scl = P1^6;

#define i2c_speed_kbps     50
#define half_bit_delay_us  10     /* ( (1*1000000) / (i2c_speed_kbps*1000) )/ 2  */
#define delay_10us()       _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_();
#define delay_5us()       _nop_(); _nop_(); _nop_(); _nop_(); _nop_();


void all_tasks_manager(void)
{       
    uint8_t temp;
   
    i2c_init();
   
/* write to eeprom */
    i2c_start();
    while( 1U == i2c_write_byte(0xa0U) )
    {
        i2c_start();
    }
/* address */   
    i2c_write_byte(0x00U);
/* value */   
    i2c_write_byte(0x05U);
/* stop */   
    i2c_stop();
   
    wait_delay_us(50000);
 
/* write to eeprom */
    i2c_start();
    while( 1U == i2c_write_byte(0xa0U) )
    {
        i2c_start();
    }   
/* address */   
    i2c_write_byte(0x00U);   
    i2c_restart(); 
    i2c_write_byte(0xa1U);
    temp = i2c_read_byte();
    i2c_send_nack();
   
    i2c_stop();
   
    while(1); 
   
} /* function ends here */   


void i2c_init(void)
{
    sda = 1U;
    scl = 1U;
}

void i2c_start(void)
{
    scl = 1U;
    sda = 1U;

/* half bit delay for 50kbps which is 10us for 12Mhz it is 10 nops */   
    delay_10us();
   
    sda = 0U;
   
/* half bit delay for 50kbps which is 10us for 12Mhz it is 10 nops */   
    delay_10us();
}


void i2c_restart(void)
{
scl = 0U;
   
/* half bit delay/2 for 50kbps which is 5us for 12Mhz it is 5 nops */   
    delay_5us();
   
    sda = 1U;
   
/* half bit delay/2 for 50kbps which is 5us for 12Mhz it is 5 nops */   
    delay_5us();

    scl = 1U;

/* half bit delay/2 for 50kbps which is 5us for 12Mhz it is 5 nops */   
    delay_5us();

    sda = 0U;

/* half bit delay/2 for 50kbps which is 5us for 12Mhz it is 5 nops */   
    delay_5us();
 
}


void i2c_stop(void)
{
    scl = 0U;
   
/* half bit delay/2 for 50kbps which is 5us for 12Mhz it is 5 nops */   
    delay_5us();

    sda = 0U;
   
/* half bit delay/2 for 50kbps which is 5us for 12Mhz it is 5 nops */   
    delay_5us();
   
    scl = 1U;
   
/* half bit delay/2 for 50kbps which is 5us for 12Mhz it is 5 nops */   
    delay_5us();
   
    sda = 1U;
   
/* half bit delay/2 for 50kbps which is 5us for 12Mhz it is 5 nops */   
    delay_5us();
   
}


void i2c_send_ack(void)
{
    scl = 0U;
   
/* half bit delay/2 for 50kbps which is 5us for 12Mhz it is 5 nops */   
    delay_5us();
   
    sda = 0U;
   
/* half bit delay/2 for 50kbps which is 5us for 12Mhz it is 5 nops */   
    delay_5us();
   
    scl = 1U;
   
/* half bit delay for 50kbps which is 10us for 12Mhz it is 10 nops */   
    delay_10us();
   
}


void i2c_send_nack(void)
{
    scl = 0U;

/* half bit delay/2 for 50kbps which is 5us for 12Mhz it is 5 nops */   
    delay_5us();   
   
    sda = 1U;
   
/* half bit delay/2 for 50kbps which is 5us for 12Mhz it is 5 nops */   
    delay_5us(); 
   
    scl = 1U;
   
/* half bit delay for 50kbps which is 10us for 12Mhz it is 10 nops */   
    delay_10us();
   
}


uint8_t i2c_write_byte(uint8_t byte)
{
    uint8_t cnt;
   
for(cnt = 0U ; cnt < 8U ; cnt++)
{
        scl = 0U;
 
    /* half bit delay/2 for 50kbps which is 5us for 12Mhz it is 5 nops */   
        delay_5us();
       
       
if( (byte << cnt) & 0x80U )
        {
            sda = 1U;
        }
        else
        {
            sda = 0U;
        }   

    /* half bit delay/2 for 50kbps which is 5us for 12Mhz it is 5 nops */   
        delay_5us();
       
        scl = 1U;
       
    /* half bit delay for 50kbps which is 10us for 12Mhz it is 10 nops */   
        delay_10us();
    }

/* get ack from slave */
    scl = 0U;
    sda = 1U;
   
/* half bit delay for 50kbps which is 10us for 12Mhz it is 10 nops */   
    delay_10us();
   
    scl = 1U;
   
/* half bit delay for 50kbps which is 10us for 12Mhz it is 10 nops */   
    delay_10us();

return sda;
}


uint8_t i2c_read_byte(void)
{
    uint8_t cnt;
    uint8_t rxdata = 0U;
    uint8_t temp;
   
for(cnt = 0U ; cnt < 8U ; cnt++)
{
        scl = 0U;
        sda = 1U;
       
    /* half bit delay for 50kbps which is 10us for 12Mhz it is 10 nops */   
        delay_10us();     
       
        scl = 1U;
       
    /* half bit delay/2 for 50kbps which is 5us for 12Mhz it is 5 nops */   
        delay_5us();
       
        temp = sda;
rxdata = rxdata | (temp << (7U - cnt));
       
    /* half bit delay/2 for 50kbps which is 5us for 12Mhz it is 5 nops */   
        delay_5us();
       
}
 
    return rxdata;
}
 

Offline Vindhyachal.taknikiTopic starter

  • Frequent Contributor
  • **
  • Posts: 491
Re: I2c bit banging, AT89C55WD, EEPROM BL24C04 interfacing
« Reply #1 on: April 18, 2016, 06:24:17 am »
I have checked on hardware, MCU: AT89C55WD, 12Mhz crsytal & BL24C04.
It is working.

For me exact performance of 50kbps is not required, because I have to read it only once on startup & write only once.
 

Offline Vindhyachal.taknikiTopic starter

  • Frequent Contributor
  • **
  • Posts: 491
Re: I2c bit banging, AT89C55WD, EEPROM BL24C04 interfacing
« Reply #2 on: April 22, 2016, 08:23:33 am »
How byte addressing is done in 24C04 eeprom.
24C04 has 4K of eeprom, so byte address range  0 to 4095 i.e 0 to 0x0FFFH. So byte address require two  bytes.
But here in Maxim app note, it only sends one byte to address the byte ( https://www.maximintegrated.com/en/app-notes/index.mvp/id/4649 ).
Foe example, if I have to write at address location 0x00, I should send two 0's.
Similarly for 4095 adress, I should send 0xff & 0xff.

But here codes works by sending one bytes only.

1. I have tested the code by sending one byte adress, & it is workign on hardware. I haven't tested by sending two byte address.
2. This is below codes for writing multiple bytes & reading back. Any comments/suggestions on it.
Performance wise I dont require to be exact 50kbps. Since I have to read/write only once at startup.

Code: [Select]
/* AT89C55WD, 12Mhz crystal, 1us inst time */
sbit sda = P1^7;
sbit scl = P1^6;

#define i2c_speed_kbps     50
#define half_bit_delay_us  10     /* ( (1*1000000) / (i2c_speed_kbps*1000) )/ 2  */

#define delay_10us()       _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_();
#define delay_5us()        _nop_(); _nop_(); _nop_(); _nop_(); _nop_();

#include "regx55.h"
#include "i2c.h"




static uint8_t eeprom_write_mutiple_bytes(uint8_t address , uint8_t byte[] , uint8_t no_bytes)
{
    uint8_t cnt;
    uint8_t cnt2;
    uint8_t err = 0U;
   
    cnt = 10U;
   
/* write to eeprom */
    i2c_start();
    while( (1U == i2c_write_byte(0xa0U)) && (--cnt) )
    {
    /* stop */   
        i2c_stop();         
    /* delay 100ms */   
        for(cnt2 = 0U ; cnt2 < 20U ; cnt2++)
        {
            wait_delay_us_complete(DELAY_10000_US_TH , DELAY_10000_US_TL);
        }       
       
        i2c_start();
    }
    if(0U == cnt)
    {
        err = 1U;
    }

/* if no error */   
    if(0U == err)
    {
    /* address */
        i2c_write_byte(address);
               
        for(cnt = 0U ; cnt < no_bytes ; cnt++)
        {
            (void)i2c_write_byte(byte[cnt]);
        }
       
    /* stop */   
        i2c_stop();       
       
    }

/* delay 100ms */   
    for(cnt = 0U ; cnt < 15U ; cnt++)
    {
        wait_delay_us_complete(DELAY_10000_US_TH , DELAY_10000_US_TL);
    }
   
    return err;
   
}





static uint8_t eeprom_read_mutiple_bytes(uint8_t address , uint8_t byte[] , uint8_t no_bytes)
{
    uint8_t cnt;
    uint8_t cnt2;
    uint8_t err = 0U;
   
    cnt = 10U;
   
/* write to eeprom */
    i2c_start();
    while( (1U == i2c_write_byte(0xa0U)) && (--cnt) )
    {
    /* stop */   
        i2c_stop();         
    /* delay 100ms */   
        for(cnt2 = 0U ; cnt2 < 20U ; cnt2++)
        {
            wait_delay_us_complete(DELAY_10000_US_TH , DELAY_10000_US_TL);
        }       
       
        i2c_start();
    }
    if(0U == cnt)
    {
        err = 1U;
    }

/* if no error */   
    if(0U == err)
    {
    /* address */
        i2c_write_byte(address);
       
    /* restart */
        i2c_restart();
       
        i2c_write_byte(0xa1U);
       
    /* address */   
        byte[0] = i2c_read_byte();
       
        for(cnt = 1U ; cnt < no_bytes ; cnt++)
        {
            i2c_send_ack();
            byte[cnt] = i2c_read_byte();
        }
       
    /* nack */
        i2c_send_nack();
       
    /* stop */   
        i2c_stop();       
       
    }

/* delay 100ms */   
    for(cnt = 0U ; cnt < 15U ; cnt++)
    {
        wait_delay_us_complete(DELAY_10000_US_TH , DELAY_10000_US_TL);
    }
   
    return err;
   
}


static void i2c_start(void)
{
    scl = 1U;
    sda = 1U;

/* half bit delay for 50kbps which is 10us for 12Mhz it is 10 nops */   
    delay_10us();
   
    sda = 0U;
   
/* half bit delay for 50kbps which is 10us for 12Mhz it is 10 nops */   
    delay_10us();

}




static void i2c_restart(void)
{
scl = 0U;
   
/* half bit delay/2 for 50kbps which is 5us for 12Mhz it is 5 nops */   
    delay_5us();
   
    sda = 1U;
   
/* half bit delay/2 for 50kbps which is 5us for 12Mhz it is 5 nops */   
    delay_5us();

    scl = 1U;

/* half bit delay/2 for 50kbps which is 5us for 12Mhz it is 5 nops */   
    delay_5us();

    sda = 0U;

/* half bit delay/2 for 50kbps which is 5us for 12Mhz it is 5 nops */   
    delay_5us();
 
}




static void i2c_stop(void)
{
    scl = 0U;
   
/* half bit delay/2 for 50kbps which is 5us for 12Mhz it is 5 nops */   
    delay_5us();

    sda = 0U;
   
/* half bit delay/2 for 50kbps which is 5us for 12Mhz it is 5 nops */   
    delay_5us();
   
    scl = 1U;
   
/* half bit delay/2 for 50kbps which is 5us for 12Mhz it is 5 nops */   
    delay_5us();
   
    sda = 1U;
   
/* half bit delay/2 for 50kbps which is 5us for 12Mhz it is 5 nops */   
    delay_5us();
   
}




static void i2c_send_ack(void)
{
    scl = 0U;
   
/* half bit delay/2 for 50kbps which is 5us for 12Mhz it is 5 nops */   
    delay_5us();
   
    sda = 0U;
   
/* half bit delay/2 for 50kbps which is 5us for 12Mhz it is 5 nops */   
    delay_5us();
   
    scl = 1U;
   
/* half bit delay for 50kbps which is 10us for 12Mhz it is 10 nops */   
    delay_10us();
   
}




static void i2c_send_nack(void)
{
    scl = 0U;

/* half bit delay/2 for 50kbps which is 5us for 12Mhz it is 5 nops */   
    delay_5us();   
   
    sda = 1U;
   
/* half bit delay/2 for 50kbps which is 5us for 12Mhz it is 5 nops */   
    delay_5us(); 
   
    scl = 1U;
   
/* half bit delay for 50kbps which is 10us for 12Mhz it is 10 nops */   
    delay_10us();
   
}




static uint8_t i2c_write_byte(uint8_t byte)
{
    uint8_t cnt;
   
for(cnt = 0U ; cnt < 8U ; cnt++)
{
        scl = 0U;
 
    /* half bit delay/2 for 50kbps which is 5us for 12Mhz it is 5 nops */   
        delay_5us();
       
       
if( (byte << cnt) & 0x80U )
        {
            sda = 1U;
        }
        else
        {
            sda = 0U;
        }   

    /* half bit delay/2 for 50kbps which is 5us for 12Mhz it is 5 nops */   
        delay_5us();
       
        scl = 1U;
       
    /* half bit delay for 50kbps which is 10us for 12Mhz it is 10 nops */   
        delay_10us();
    }

/* get ack from slave */
    scl = 0U;
    sda = 1U;
   
/* half bit delay for 50kbps which is 10us for 12Mhz it is 10 nops */   
    delay_10us();
   
    scl = 1U;
   
/* half bit delay for 50kbps which is 10us for 12Mhz it is 10 nops */   
    delay_10us();

return sda;

}




static uint8_t i2c_read_byte(void)
{
    uint8_t cnt;
    uint8_t rxdata = 0U;
    uint8_t temp;
   
for(cnt = 0U ; cnt < 8U ; cnt++)
{
        scl = 0U;
        sda = 1U;
       
    /* half bit delay for 50kbps which is 10us for 12Mhz it is 10 nops */   
        delay_10us();     
       
        scl = 1U;
       
    /* half bit delay/2 for 50kbps which is 5us for 12Mhz it is 5 nops */   
        delay_5us();
       
        temp = sda;
rxdata = rxdata | (temp << (7U - cnt));
       
    /* half bit delay/2 for 50kbps which is 5us for 12Mhz it is 5 nops */   
        delay_5us();
       
}
 
    return rxdata;

}
 

Offline Vindhyachal.taknikiTopic starter

  • Frequent Contributor
  • **
  • Posts: 491
Re: I2c bit banging, AT89C55WD, EEPROM BL24C04 interfacing
« Reply #3 on: April 22, 2016, 04:35:37 pm »
yes got it. It has 2 pages of 256 bytes each. pages are selected in device address register bit.
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf