Interacting with I2C devices is usually done with a microcontroller and an I2C library, but sometimes either the microcontroller is not supporting I2C or you have some other restrictions which do not allow you to use the provided I2C library. For that reason you can always Bitbang the I2C protocol a.k.a emulate the behavior of this protocol by manually toggling the pins.

The following example is using Bitbanging to communicate with an EEPROM device (ST – M24C02). However you can easily alter it and use in your own application. Beware that you have to change several parts of the code to work on you application, this example is only for reference.

gpio_t eeprom_sda={GPIOE,0U};
gpio_t eeprom_scl={GPIOC,17U};
gpio_t eeprom_wp={GPIOE,9U};


void initialize()
{
    gpio_initialize(&eeprom_wp);
    gpio_initialize(&eeprom_sda);
    gpio_initialize(&eeprom_scl);
    gpio_set_direction(eeprom_wp,gpioOutput);
    gpio_set_direction(eeprom_sda,gpioOutput);
    gpio_set_direction(eeprom_scl,gpioOutput);
    gpio_on(&eeprom_wp);
    gpio_on(&eeprom_sda);
    gpio_on(&eeprom_scl);
    gpio_off(&eeprom_wp);
}


void i2c_start_condition(void)
{
    gpio_on(&eeprom_sda);
    gpio_on(&eeprom_scl);
    gpio_off(&eeprom_sda);
    gpio_off(&eeprom_scl);
}


void i2c_stop_condition(void)
{
    gpio_off(&eeprom_sda);
    gpio_on(&eeprom_scl);
    gpio_on(&eeprom_sda);
    gpio_off(&eeprom_scl);
}


void i2c_write_ack(uint8_t data)
{
    uint8_t ack;
    for(int i = 0; i < 8; i++)
    {
        if(data & 0x80)
            gpio_on(&eeprom_sda);
        else
            gpio_off(&eeprom_sda);
        data  <<= 1;
      	gpio_on(&eeprom_scl);
      	gpio_off(&eeprom_scl);
    }
    gpio_set_direction(eeprom_sda,gpioInput);
    gpio_on(&eeprom_scl);
    for(int i = 0; i < 20; i++)
        __NOP();
    ack = gpio_read(&eeprom_sda);
    gpio_off(&eeprom_scl);
    gpio_set_direction(eeprom_sda,gpioOutput);
}


void i2c_write(uint8_t data)
{
    for(int i = 0; i < 8; i++)
    {
        if(data & 0x80)
            gpio_on(&eeprom_sda);
        else
            gpio_off(&eeprom_sda);
        data  <<= 1;
      	gpio_on(&eeprom_scl);
      	gpio_off(&eeprom_scl);
    }
}


uint8_t i2c_read(void)
{
    uint8_t result = 0x00;
    gpio_set_direction(eeprom_sda,gpioInput);
    for(int i = 0; i < 8; i++)
    {
        result <<= 1;
        gpio_on(&eeprom_scl);
        result |= ( gpio_read(&eeprom_sda) ==0 ? 0 : 1);
      	gpio_off(&eeprom_scl);
    }
    gpio_set_direction(eeprom_sda,gpioOutput);
    return result;
}


void eeprom_write (uint8_t address, uint8_t byte_address, uint8_t data)
{
    i2c_start_condition();
    i2c_write_ack(address);
    i2c_write_ack(byte_address);
    i2c_write(data);
    i2c_stop_condition();
}


uint8_t i2c_write_slave(uint8_t address, uint8_t byte_address)
{
    uint8_t result = 0x00;
    i2c_start_condition();
    i2c_write_ack(address);
    i2c_write_ack(byte_address);
    i2c_start_condition();
    i2c_write_ack(address | 1);
    result = i2c_read();
    return result;
}

 

 

 

Author

Write A Comment