Rev 139 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed
/*
* i2cbb.c
*
* Bit Banging I2C code for any Atmel device
* The I2CBB_DELAY delay (in header) may need to be tweaked
* for different clock speeds, 10 if a fast enough
* speed, 100 if your having problems and dont need
* the speed. 7 seems to work well with an Attiny85
* running the PLL 16.5Mhz clock.
*
* Base code from Raul
* http://codinglab.blogspot.com.au/2008/10/i2c-on-avr-using-bit-banging.html
*/
#include <avr/io.h>
#include <util/delay.h>
#include "config.h"
#include "avrutil.h"
#include "i2cbb.h"
#define I2CBB_DATA_HI()\
I2CBB_DDR &= ~ (1 << I2CBB_DAT);\
I2CBB_PORT |= (1 << I2CBB_DAT);
#define I2CBB_DATA_LO()\
I2CBB_DDR |= (1 << I2CBB_DAT);\
I2CBB_PORT &= ~ (1 << I2CBB_DAT);
#define I2CBB_CLOCK_HI()\
I2CBB_DDR &= ~ (1 << I2CBB_CLK);\
I2CBB_PORT |= (1 << I2CBB_CLK);
#define I2CBB_CLOCK_LO()\
I2CBB_DDR |= (1 << I2CBB_CLK);\
I2CBB_PORT &= ~ (1 << I2CBB_CLK);
void i2cbb_WriteBit(unsigned char c) {
if (c > 0) {
I2CBB_DATA_HI();
}
else {
I2CBB_DATA_LO();
}
I2CBB_CLOCK_HI();
while ((I2CBB_PIN & (1 << I2CBB_CLK)) == 0);
_delay_us(I2CBB_DELAY);
I2CBB_CLOCK_LO();
//_delay_us(I2CBB_DELAY);
if (c > 0) {
_delay_us(I2CBB_DELAY); // Added
I2CBB_DATA_LO();
}
// _delay_us(I2CBB_DELAY);
}
unsigned char i2cbb_ReadBit() {
I2CBB_DATA_HI();
I2CBB_CLOCK_HI();
while ((I2CBB_PIN & (1 << I2CBB_CLK)) == 0);
_delay_us(I2CBB_DELAY);
unsigned char c = I2CBB_PIN;
I2CBB_CLOCK_LO();
//_delay_us(I2CBB_DELAY);
return (c >> I2CBB_DAT) & 1;
}
// Inits bitbanging port, must be called before using the functions below
//
void i2cbb_Init() {
I2CBB_PORT &= ~ ((1 << I2CBB_DAT) | (1 << I2CBB_CLK));
I2CBB_CLOCK_HI();
I2CBB_DATA_HI();
_delay_us(I2CBB_DELAY);
}
// Send a START Condition
//
void i2cbb_Start() {
// set both to high at the same time
I2CBB_DDR &= ~ ((1 << I2CBB_DAT) | (1 << I2CBB_CLK));
_delay_us(I2CBB_DELAY);
I2CBB_DATA_LO();
_delay_us(I2CBB_DELAY);
I2CBB_CLOCK_LO();
_delay_us(I2CBB_DELAY);
}
// Send a STOP Condition
//
void i2cbb_Stop() {
I2CBB_DATA_LO();
I2CBB_CLOCK_LO();
_delay_us(I2CBB_DELAY);
_delay_us(I2CBB_DELAY);
I2CBB_CLOCK_HI();
_delay_us(I2CBB_DELAY);
_delay_us(I2CBB_DELAY);
I2CBB_DATA_HI();
//_delay_us(I2CBB_DELAY);
}
// write a byte to the I2C slave device
unsigned char i2cbb_Write(unsigned char c) {
uint8_t i;
for (i=0; i < 8; i++) {
i2cbb_WriteBit(c & 128);
c <<= 1;
}
return i2cbb_ReadBit();
//return 0;
}
// read a byte from the I2C slave device
//
unsigned char i2cbb_Read(unsigned char ack) {
unsigned char res = 0;
uint8_t i;
for (i = 0; i < 8; i++) {
res <<= 1;
res |= i2cbb_ReadBit();
}
if (ack > 0) {
i2cbb_WriteBit(0);
}
else {
i2cbb_WriteBit(1);
}
//_delay_us(I2CBB_DELAY);
return res;
}