filament-counter/code/i2c_master.c
2021-06-27 16:01:56 +03:00

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;
}