148 lines
3.6 KiB
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);
|
|
}
|
|
*/
|