diff --git a/flake.nix b/flake.nix index f41a19a..fb42f67 100644 --- a/flake.nix +++ b/flake.nix @@ -207,6 +207,8 @@ psrc = ./i2c; pbuildInputs = [ (packages."x86_64-linux"."dio" { inherit gcc cflags; }) + (packages."x86_64-linux"."shift-register" { inherit gcc cflags; }) + (packages."x86_64-linux"."display" { inherit gcc cflags; }) ]; }; @@ -326,6 +328,32 @@ ]; }; + packages."x86_64-linux"."lux-sensor_" = + let + pkgs = import nixpkgs { system = "x86_64-linux"; }; + avr = pkgs.pkgsCross.avr.buildPackages; + in packages."x86_64-linux"."lux-sensor" { gcc = "${avr.gcc}/bin/avr-gcc"; cflags = mcu_cflags atmega32u4; avr = true; }; + packages."x86_64-linux"."lux-sensor" = + { gcc, cflags, avr }: + let + pkgs = import nixpkgs { system = "x86_64-linux"; }; + in mkProgram { + pkgs = pkgs; + gcc = gcc; + cflags = cflags; + pname = "lux-sensor"; + psrc = ./lux-sensor; + inherit avr; + + pbuildInputs = [ + (packages."x86_64-linux"."dio" { 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; }) + ]; + }; + devShell."x86_64-linux" = let pkgs = import nixpkgs { system = "x86_64-linux"; }; diff --git a/i2c/i2c.c b/i2c/i2c.c index 9fa5c1b..ff9eb2d 100644 --- a/i2c/i2c.c +++ b/i2c/i2c.c @@ -11,6 +11,8 @@ You should have received a copy of the GNU General Public License along with thi */ #include +#include +#include #include "i2c.h" void i2c_delay(void) { @@ -18,10 +20,12 @@ void i2c_delay(void) { } inline void set_sda(i2c_bus_t *bus) { + bus->sda_state = true; dio_set_direction(&bus->sda, LINE_IN); } inline void clear_sda(i2c_bus_t *bus) { + bus->sda_state = false; dio_set_direction(&bus->sda, LINE_OUT); } @@ -30,10 +34,12 @@ inline uint8_t read_sda(i2c_bus_t *bus) { } inline void set_scl(i2c_bus_t *bus) { + bus->scl_state = true; dio_set_direction(&bus->scl, LINE_IN); } inline void clear_scl(i2c_bus_t *bus) { + bus->scl_state = false; dio_set_direction(&bus->scl, LINE_OUT); } @@ -41,18 +47,22 @@ inline uint8_t read_scl(i2c_bus_t *bus) { return dio_read(&bus->scl); } -void i2c_init(i2c_bus_t *bus) { +i2c_bus_t *i2c_init(dio_t clock, dio_t data) { + i2c_bus_t *bus = malloc(sizeof(i2c_bus_t)); + bus->sda = data; + bus->scl = clock; + dio_set(&bus->sda, 0); dio_set(&bus->scl, 0); set_sda(bus); set_scl(bus); + + return bus; } -void i2c_start_condition(i2c_bus_t *bus, i2c_error_e *error) { +void i2c_start(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; @@ -63,9 +73,7 @@ void i2c_start_condition(i2c_bus_t *bus, i2c_error_e *error) { clear_scl(bus); } -void i2c_end_condition(i2c_bus_t *bus, i2c_error_e *error) { - if (*error != i2c_ok) return; - +void i2c_end(i2c_bus_t *bus, i2c_error_e *error) { clear_sda(bus); i2c_delay(); @@ -91,13 +99,32 @@ void i2c_end_condition(i2c_bus_t *bus, i2c_error_e *error) { } } +void i2c_restart(i2c_bus_t *bus, i2c_error_e *error) { + if (*error != i2c_ok) return; + + set_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_start(bus, error); +} + 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); + } else { + clear_sda(bus); } i2c_delay(); @@ -131,6 +158,7 @@ uint8_t i2c_read_bit(i2c_bus_t *bus, i2c_error_e *error) { i2c_delay(); set_scl(bus); + i2c_delay(); int count = 0; while (read_scl(bus) == 0) { if (count == 5) { @@ -140,7 +168,6 @@ uint8_t i2c_read_bit(i2c_bus_t *bus, i2c_error_e *error) { count++; i2c_delay(); } - i2c_delay(); bit = read_sda(bus); clear_scl(bus); @@ -164,21 +191,22 @@ void i2c_write_byte(i2c_bus_t *bus, uint8_t value, i2c_error_e *error) { return; } -uint8_t i2c_read_byte(i2c_bus_t *bus, i2c_error_e *error) { +uint8_t i2c_read_byte(i2c_bus_t *bus, bool final_nak, 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); + 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; + if (*error != i2c_ok || final_nak) { + i2c_error_e tmp_status; + i2c_write_bit(bus, 1, &tmp_status); + return value; } i2c_write_bit(bus, 0, error); + return value; } @@ -195,3 +223,20 @@ void i2c_host_write(i2c_bus_t *bus, uint8_t address, uint8_t *data, size_t lengt } } */ + +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; + } +} diff --git a/i2c/i2c.h b/i2c/i2c.h index 2e2f4fb..5241a76 100644 --- a/i2c/i2c.h +++ b/i2c/i2c.h @@ -23,7 +23,10 @@ typedef enum { } i2c_error_e; typedef struct { + bool sda_state; dio_t sda; + + bool scl_state; dio_t scl; } i2c_bus_t; @@ -35,8 +38,17 @@ typedef struct { } i2c_client_t; */ -void i2c_init(i2c_bus_t *); +i2c_bus_t * i2c_init(dio_t, dio_t); + +void i2c_start(i2c_bus_t *bus, i2c_error_e *error); +void i2c_end(i2c_bus_t *bus, i2c_error_e *error); +void i2c_restart(i2c_bus_t *bus, i2c_error_e *error); + +void i2c_write_byte(i2c_bus_t *bus, uint8_t value, i2c_error_e *error); +uint8_t i2c_read_byte(i2c_bus_t *bus, bool final_nak, i2c_error_e *error); // void i2c_host_write(i2c_host_t *, uint8_t, uint8_t, size_t, i2c_error_e); +void i2c_status_to_string(i2c_error_e status, char msg[20]); + #endif diff --git a/lux-sensor/main.c b/lux-sensor/main.c new file mode 100644 index 0000000..5de9a48 --- /dev/null +++ b/lux-sensor/main.c @@ -0,0 +1,82 @@ +#include +#include +#include +#include + +int main(void) { + display_t display = { + .reg = { + .output = { .ddr = &DDRF, .port = &PORTF, .pin = &PINF, .addr = 7 }, + .shift_clock = { .ddr = &DDRF, .port = &PORTF, .pin = &PINF, .addr = 6 }, + .latch_clock = { .ddr = &DDRF, .port = &PORTF, .pin = &PINF, .addr = 5 }, + }, + }; + + display_init(&display); + + + i2c_bus_t *bus = i2c_init( + (dio_t){ .ddr = &DDRB, .port = &PORTB, .pin = &PINB, .addr = 5 }, + (dio_t){ .ddr = &DDRB, .port = &PORTB, .pin = &PINB, .addr = 6 } + ); + + i2c_error_e status = i2c_ok; + i2c_start(bus, &status); + i2c_write_byte(bus, 0x39 << 1, &status); + i2c_write_byte(bus, 0x80, &status); + i2c_write_byte(bus, 0x03, &status); + i2c_end(bus, &status); + + if (status != i2c_ok) { + display_clear(&display); + display_write_message(&display, "early abort"); + } + + _delay_ms(500); + + uint8_t count = 0; + while(1) { + /* + int id = 0; + + status = i2c_ok; + i2c_start(bus, &status); + i2c_write_byte(bus, 0x39 << 1, &status); + i2c_write_byte(bus, 0x80, &status); + i2c_restart(bus, &status); + i2c_write_byte(bus, (0x39 << 1) | 1, &status); + id = i2c_read_byte(bus, true, &status) & 0x03; + i2c_end(bus, &status); + */ + + int lux = 0; + int ir = 0; + i2c_start(bus, &status); + i2c_write_byte(bus, 0x39 << 1, &status); + i2c_write_byte(bus, 0x8c, &status); + i2c_restart(bus, &status); + i2c_write_byte(bus, 0x39 << 1 | 1, &status); + lux = i2c_read_byte(bus, false, &status); + lux |= i2c_read_byte(bus, true, &status) << 8; + i2c_end(bus, &status); + + i2c_start(bus, &status); + i2c_write_byte(bus, 0x39 << 1, &status); + i2c_write_byte(bus, 0x8e, &status); + i2c_restart(bus, &status); + i2c_write_byte(bus, 0x39 << 1 | 1, &status); + ir = ((int)i2c_read_byte(bus, false, &status)); + ir |= ((int)i2c_read_byte(bus, true, &status)) << 8; + i2c_end(bus, &status); + + char msg[20] = ""; + display_clear(&display); + snprintf(msg, 20, "[%d] %x, %x", count, lux, ir); + display_write_message(&display, msg); + display_set_location(&display, 1, 0); + i2c_status_to_string(status, msg); + display_write_message(&display, msg); + _delay_ms(1000); + count++; + } +}