132 lines
2.3 KiB
C
132 lines
2.3 KiB
C
#include "i2c_master.h"
|
|
#include <avr/io.h>
|
|
|
|
uint8_t i2c_clock(uint8_t type);
|
|
|
|
void i2c_init(void)
|
|
{
|
|
// Define SCL and SDA as Output
|
|
DDRB |= (1 << 0) | (1 << 2);
|
|
|
|
// Preload dataregister with "released level" data
|
|
USIDR = 0xFF;
|
|
|
|
// Use SCL and SDA pins
|
|
// Select clock sources
|
|
USICR = (1 << USIWM1) | (1 << USICS1) | (1 << USICLK);
|
|
|
|
// Clear flags and reset counter
|
|
USISR = (1 << USISIF) | (1 << USIOIF) | (1 << USIPF) | (1 << USIDC);
|
|
}
|
|
|
|
uint8_t i2c_start(uint8_t address)
|
|
{
|
|
// FOR REPEATED START
|
|
// Release SCL
|
|
PORTB |= (1 << 2);
|
|
// Verify that SCL becomes high
|
|
while (!( PINB & (1 << 2) ));
|
|
|
|
// GENERATE START CONDITION
|
|
// Force SDA LOW
|
|
PORTB &= ~(1 << 0);
|
|
|
|
// Pull SCL LOW
|
|
PORTB &= ~(1 << 2);
|
|
// Release SDA
|
|
PORTB |= (1 << 0);
|
|
|
|
return i2c_write(address);
|
|
}
|
|
|
|
uint8_t i2c_write(uint8_t data)
|
|
{
|
|
// Pull SCL LOW
|
|
PORTB &= ~(1 << 2);
|
|
// Setup data
|
|
USIDR = data;
|
|
|
|
// Send 8 bits on bus
|
|
i2c_clock(8);
|
|
|
|
// Enable SDA as input
|
|
DDRB &= ~(1 << 0);
|
|
|
|
// Receive 1 bit on bus & Check for NACK
|
|
if (i2c_clock(1) & (1 << 0))
|
|
{
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
uint8_t i2c_read(uint8_t nack)
|
|
{
|
|
// Enable SDA as input.
|
|
DDRB &= ~(1 << 0);
|
|
// Read 8 bits
|
|
uint8_t result = i2c_clock(8);
|
|
|
|
if (nack)
|
|
{
|
|
// Load NACK
|
|
USIDR = 0xFF;
|
|
}
|
|
else
|
|
{
|
|
// Load ACK
|
|
USIDR = 0x00;
|
|
}
|
|
|
|
i2c_clock(1);
|
|
return result;
|
|
}
|
|
|
|
void i2c_stop(void)
|
|
{
|
|
// Pull SDA low
|
|
PORTB &= ~(1 << 0);
|
|
// Release SCL
|
|
PORTB |= (1 << 2);
|
|
// Wait for SCL to go high
|
|
while (!( PINB & (1 << 2) ));
|
|
|
|
// Release SDA
|
|
PORTB |= (1 << 0);
|
|
}
|
|
|
|
uint8_t i2c_clock(uint8_t count)
|
|
{
|
|
uint8_t reg_temp = (1 << USISIF) | (1 << USIOIF) | (1 << USIPF) | (1 << USIDC);
|
|
// Counter counts number of edges
|
|
// Overflow signals end of transmission
|
|
reg_temp |= 16 - (count * 2);
|
|
|
|
USISR = reg_temp;
|
|
|
|
// Set clock source & toggle clock prepare
|
|
reg_temp = (1 << USIWM1) | (1 << USICS1) | (1 << USICLK) | (1 << USITC);
|
|
do
|
|
{
|
|
// Generate positve SCL edge.
|
|
USICR = reg_temp;
|
|
|
|
// Wait for SCL to go high
|
|
while (!( PINB & (1 << 2)));
|
|
|
|
// Generate negative SCL edge
|
|
USICR = reg_temp;
|
|
}
|
|
// Wait for counter overflow (all edges are completed)
|
|
while (!( USISR & (1 << USIOIF)));
|
|
|
|
// Read data
|
|
reg_temp = USIDR;
|
|
// Load dataregister with "released level" data
|
|
USIDR = 0xFF;
|
|
|
|
// Enable SDA as output
|
|
DDRB |= (1 << 0);
|
|
return reg_temp;
|
|
}
|