diff --git a/display-i2c/main.c b/display-i2c/main.c index 0205d10..1c2b82d 100644 --- a/display-i2c/main.c +++ b/display-i2c/main.c @@ -1,5 +1,6 @@ #include #include +#include int main(void) { display_t display = { diff --git a/flake.nix b/flake.nix index 18c9546..f41a19a 100644 --- a/flake.nix +++ b/flake.nix @@ -195,6 +195,21 @@ ]; }; + packages."x86_64-linux"."i2c" = + { gcc, cflags }: + let + pkgs = import nixpkgs { system = "x86_64-linux"; }; + in mkLibrary { + pkgs = pkgs; + gcc = gcc; + cflags = cflags; + pname = "i2c"; + psrc = ./i2c; + pbuildInputs = [ + (packages."x86_64-linux"."dio" { inherit gcc cflags; }) + ]; + }; + packages."x86_64-linux"."prime-tx" = { gcc, cflags }: let @@ -304,9 +319,10 @@ pbuildInputs = [ (packages."x86_64-linux"."dio" { inherit gcc cflags; }) - (packages."x86_64-linux"."spi" { inherit gcc cflags; }) - (packages."x86_64-linux"."shift-register" { inherit gcc cflags; }) (packages."x86_64-linux"."display" { inherit gcc cflags; }) + (packages."x86_64-linux"."i2c" { inherit gcc cflags; }) + (packages."x86_64-linux"."shift-register" { inherit gcc cflags; }) + (packages."x86_64-linux"."spi" { inherit gcc cflags; }) ]; }; diff --git a/i2c/i2c.c b/i2c/i2c.c index ee5af6c..6a91d7f 100644 --- a/i2c/i2c.c +++ b/i2c/i2c.c @@ -13,42 +13,185 @@ You should have received a copy of the GNU General Public License along with thi #include #include "i2c.h" -void i2c_init_host(i2c_host_t *bus, i2c_error_e *error) { - dio_set_direction(&bus->sda, LINE_OUT); - dio_set(&bus->sda, 1); - - dio_set_direction(&bus->scl, LINE_OUT); - dio_set(&bus->scl, 1); +void i2c_delay(void) { + _delay_us(5); } -void i2c_init_client(i2c_client_t *bus, i2c_error_e *error) { +inline void set_sda(i2c_bus_t *bus) { dio_set_direction(&bus->sda, LINE_IN); +} + +inline void clear_sda(i2c_bus_t *bus) { + dio_set(&bus->sda, 0); + dio_set_direction(&bus->sda, LINE_OUT); +} + +inline uint8_t read_sda(i2c_bus_t *bus) { + return dio_read(&bus->sda); +} + +inline void set_scl(i2c_bus_t *bus) { dio_set_direction(&bus->scl, LINE_IN); } -void i2c_host_write_packet(i2c_host_t *bus, uint8_t value, i2c_error_e *error) { - dio_set(&bus->sda, 0); +inline void clear_scl(i2c_bus_t *bus) { dio_set(&bus->scl, 0); + dio_set_direction(&bus->scl, LINE_OUT); +} - for (int i = 7; i >= 0; i--) { - dio_set(&bus->sda, value & _BV(i)); - /* - if (value & _BV(i)) { - dio_set(&bus->sda, 1); - } else { - dio_set(&bus->sda, 0); - } - */ - dio_set(&bus->scl, 1); - dio_set(&bus->scl, 0); +inline uint8_t read_scl(i2c_bus_t *bus) { + return dio_read(&bus->scl); +} + +void i2c_init_host(i2c_bus_t *bus) { + set_sda(bus); + set_scl(bus); +} + +/* +void i2c_init_client(i2c_client_t *bus) { + set_sda(bus); + set_scl(bus); +} +*/ + +void i2c_start_condition(i2c_bus_t *bus, i2c_error_e *error) { + if (*error != i2c_ok) return; + + // TODO: handle the restart state + + if (read_sda(bus) == 0) { + *error = i2c_arbitration_lost; + return; } - dio_set_direction(&bus->scl, LINE_IN); - + clear_sda(bus); + i2c_delay(); + clear_scl(bus); } -void i2c_host_write(i2c_host_t *bus, uint8_t address, uint8_t *data, size_t length, i2c_error_e *error) { - if (*error) return; +void i2c_end_condition(i2c_bus_t *bus, i2c_error_e *error) { + if (*error != i2c_ok) return; + + clear_sda(bus); + i2c_delay(); + + set_scl(bus); + + int count = 0; + while (read_scl(bus) == 0) { + if (count == 5) { + *error = i2c_timeout; + return; + } + count++; + i2c_delay(); + } + + i2c_delay(); + + set_sda(bus); + i2c_delay(); + + if (read_sda(bus) == 0) { + *error = i2c_arbitration_lost; + } +} + +void i2c_write_bit(i2c_bus_t *bus, uint8_t value, i2c_error_e *error) { + if (*error != i2c_ok) return; + + if (value) { + clear_sda(bus); + } else { + set_sda(bus); + } + i2c_delay(); + + set_scl(bus); + i2c_delay(); + + int count = 0; + while (read_scl(bus) == 0) { + if (count == 5) { + *error = i2c_timeout; + return; + } + count++; + i2c_delay(); + } + + + if (value && (read_sda(bus) == 0)) { + *error = i2c_arbitration_lost; + } + + clear_scl(bus); +} + +uint8_t i2c_read_bit(i2c_bus_t *bus, i2c_error_e *error) { + uint8_t bit; + + if (*error != i2c_ok) return 0; + + set_sda(bus); + i2c_delay(); + + set_scl(bus); + int count = 0; + while (read_scl(bus) == 0) { + if (count == 5) { + *error = i2c_timeout; + return 0; + } + count++; + i2c_delay(); + } + i2c_delay(); + + bit = read_sda(bus); + clear_scl(bus); + return bit; +} + +void i2c_write_byte(i2c_bus_t *bus, uint8_t value, i2c_error_e *error) { + if (*error != i2c_ok) return; + + for (int i = 7; i >= 0; i--) { + i2c_write_bit(bus, value & _BV(i), error); + } + + uint8_t nak = i2c_read_bit(bus, error); + if (*error != i2c_ok) return; + + if (nak) { + *error = i2c_nak; + } + + return; +} + +uint8_t i2c_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_read_bit(bus, error); + } + + if (*error != i2c_ok) { + i2c_error_e tmp_error; + i2c_write_bit(bus, 1, &tmp_error); + return 0; + } + + i2c_write_bit(bus, 0, error); + return value; +} + +/* +void i2c_host_write(i2c_bus_t *bus, uint8_t address, uint8_t *data, size_t length, i2c_error_e *error) { + if (*error != i2c_ok) return; i2c_host_write_packet(bus, address << 1, error); if (*error != ok) return; @@ -58,3 +201,4 @@ void i2c_host_write(i2c_host_t *bus, uint8_t address, uint8_t *data, size_t leng if (*error != ok) return; } } +*/ diff --git a/i2c/i2c.h b/i2c/i2c.h index 520851c..69548df 100644 --- a/i2c/i2c.h +++ b/i2c/i2c.h @@ -13,27 +13,31 @@ You should have received a copy of the GNU General Public License along with thi #ifndef __I2C_H__ #define __I2C_H__ -#include +#include typedef enum { - ok, - nak + i2c_ok, + i2c_arbitration_lost, + i2c_timeout, + i2c_nak, } i2c_error_e; typedef struct { dio_t sda; - dio_t clk; -} i2c_host_t; + dio_t scl; +} i2c_bus_t; +/* typedef struct { dio_t sda; - dio_t clk; + dio_t scl; uint8_t addr; -} +} i2c_client_t; +*/ -void i2c_init_host(i2c_host_t *, i2c_error_e *); -void i2c_init_client(i2c_client_t *, i2c_error_e *); +void i2c_init_host(i2c_bus_t *); +// void i2c_init_client(i2c_client_t *); -void i2c_host_write(i2c_host_t *, uint8_t, uint8_t, size_t, i2c_error_e); +// void i2c_host_write(i2c_host_t *, uint8_t, uint8_t, size_t, i2c_error_e); #endif