avr/i2c/device.c

148 lines
3.6 KiB
C

i2c_device_t * i2c_device_init(dio_t clock, dio_t data, uint8_t address, uint8_t register_count) {
i2c_device_t *self = malloc(sizeof(i2c_device_t) + register_count);
self->sda = data;
self->scl = clock;
self->addr = address;
self->bus_state_e = IDLE;
self->register_count = register_count;
self->target_register = -1;
for (int i = 0; i < register_count; i++) {
self->registers[i] = 0;
}
return self
}
/*
void i2c_device_write_bit(i2c_bus_t *bus, uint8_t value, i2c_error_e *error) {
if (*error != i2c_ok) return;
while (read_scl(bus) != 0) {
if (value) {
set_sda(bus);
} else {
clear_sda(bus);
}
}
}
void i2c_device_write_byte(i2c_bus_t *bus, uint8_t value, i2c_error_e *error) {
for (int i = 7; i >= 0; i--) {
i2c_write_bit(bus, value & _BV(i), error);
}
}
uint8_t i2c_device_read_bit(i2c_bus_t *bus, i2c_error_e *error) {
if (*error != i2c_ok) return 0;
while (read_scl(bus) == 0) {
i2c_delay();
}
return read_sda(bus);
}
uint8_t i2c_device_read_byte(i2c_bus_t *bus, i2c_error_e *error) {
if (*error != i2c_ok) return 0;
uint8_t value = 0;
for (int i = 0; i < 8; i++) {
value = (value << 1) | i2c_device_read_bit(bus, error);
}
return value;
}
void i2c_status_to_string(i2c_error_e status, char msg[20]) {
switch (status) {
case i2c_ok:
snprintf(msg, 20, "ok");
break;
case i2c_arbitration_lost:
snprintf(msg, 20, "arbitration lost");
break;
case i2c_timeout:
snprintf(msg, 20, "timeout");
break;
case i2c_nak:
snprintf(msg, 20, "nak");
break;
}
}
void i2c_wait_for_idle(i2c_device_t *bus, i2c_error_e *error) {
switch (bus_state) {
case ACTIVE:
if (dio_read(&i2c.scl) && !dio_read(&i2c.sda)) {
state = INACTIVE_1;
}
break;
case INACTIVE_1:
if (dio_read(&i2c.scl) && dio_read(&i2c.sda)) {
state = IDLE;
} else {
state = ACTIVE;
}
break;
case IDLE:
break;
}
}
bool i2c_is_idle(i2c_device_t *bus) {
return bus->state == IDLE,
}
*/
void i2c_device_step(i2c_device_t *self) {
uint8_t sda = dio_read(self.sda);
uint8_t scl = dio_read(self.scl);
i2c_error_e status = i2c_ok;
switch (self->state) {
case IDLE:
if (!sda) self->state = START_SDA;
break;
case START_SDA:
if (sda) {
self->state = IDLE;
break;
}
if (!scl) self->state = START;
break;
case START:
uint8_t header = i2c_device_read_byte(self, &status);
uint8_t addr = header >> 1;
uint8_t mode = header & 0x01;
if addr == self->addr {
self->state = ACTIVE_LISTEN;
if (mode) {
self->direction = DEVICE_TO_HOST;
} else {
self->direction = HOST_TO_DEVICE;
}
i2c_device_write_bit(self, 0, &status);
} else {
self->state = ACTIVE_IGNORE;
}
break;
case ACTIVE_LISTEN:
// Do all of the stuff to read data from the host
break;
case ACTIVE_IGNORE:
break;
case INACTIVE:
break;
}
}
/*
void i2c_device_release_clock(i2c_device_bus_t *bus) {
dio_set(bus->scl);
}
*/