filament-counter-v2/code/i2c_master.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
DDRA |= (1 << 4) | (1 << 6);
// 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
PORTA |= (1 << 4);
// Verify that SCL becomes high
while (!( PINA & (1 << 4) ));
// GENERATE START CONDITION
// Force SDA LOW
PORTA &= ~(1 << 6);
// Pull SCL LOW
PORTA &= ~(1 << 4);
// Release SDA
PORTA |= (1 << 6);
return i2c_write(address);
}
uint8_t i2c_write(uint8_t data)
{
// Pull SCL LOW
PORTA &= ~(1 << 4);
// Setup data
USIDR = data;
// Send 8 bits on bus
i2c_clock(8);
// Enable SDA as input
DDRA &= ~(1 << 6);
// 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.
DDRA &= ~(1 << 6);
// 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
PORTA &= ~(1 << 6);
// Release SCL
PORTA |= (1 << 4);
// Wait for SCL to go high
while (!( PINA & (1 << 4) ));
// Release SDA
PORTA |= (1 << 6);
}
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 (!( PINA & (1 << 4)));
// 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
DDRA |= (1 << 6);
return reg_temp;
}