diff --git a/flake.nix b/flake.nix index b215a46..ebdbfa8 100644 --- a/flake.nix +++ b/flake.nix @@ -22,7 +22,7 @@ MCU = "attiny85"; CHIP_SELECT = "AVR_ATtiny85"; F_CPU = "8000000"; - CFLAGS = ''-O -finline-functions -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -Wall -Wstrict-prototypes -DF_CPU=${F_CPU} -std=gnu99 -D__${CHIP_SELECT}__=1 -mmcu=${MCU}''; + CFLAGS = ''-O -finline-functions -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -Wall -Werror -Wstrict-prototypes -DF_CPU=${F_CPU} -std=gnu99 -D__${CHIP_SELECT}__=1 -mmcu=${MCU}''; buildPhase = '' ${avr.gcc}/bin/avr-gcc ${CFLAGS} -I${src}/base -o base.o -c ${src}/base/base.c @@ -51,7 +51,7 @@ MCU = "atmega32u4"; CHIP_SELECT = "AVR_ATmega32u4"; F_CPU = "8000000"; - CFLAGS = ''-O -finline-functions -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -Wall -Wstrict-prototypes -DF_CPU=${F_CPU} -std=gnu99 -D__${CHIP_SELECT}__=1 -mmcu=${MCU} -DAVR=1''; + CFLAGS = ''-O -finline-functions -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -Wall -Werror -Wstrict-prototypes -DF_CPU=${F_CPU} -std=gnu99 -D__${CHIP_SELECT}__=1 -mmcu=${MCU} -DAVR=1''; INCLUDE_DIRS = lib.concatStringsSep " " (map (dir: "-I${src}/${dir}") includes); buildPhase = '' @@ -82,7 +82,7 @@ MCU = "atmega32u4"; CHIP_SELECT = "AVR_ATmega32u4"; F_CPU = "8000000"; - CFLAGS = ''-O -finline-functions -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -Wall -Wstrict-prototypes -DF_CPU=${F_CPU} -std=gnu99 -D__${CHIP_SELECT}__=1 -mmcu=${MCU} -DAVR=1''; + CFLAGS = ''-O -finline-functions -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -Wall -Werror -Wstrict-prototypes -DF_CPU=${F_CPU} -std=gnu99 -D__${CHIP_SELECT}__=1 -mmcu=${MCU} -DAVR=1''; INCLUDE_DIRS = lib.concatStringsSep " " (map (dir: "-I${src}/${dir}") includes); buildPhase = '' @@ -111,7 +111,7 @@ MCU = "atmega32u4"; CHIP_SELECT = "AVR_ATmega32u4"; F_CPU = "8000000"; - CFLAGS = ''-O -finline-functions -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -Wall -Wstrict-prototypes -DF_CPU=${F_CPU} -std=gnu99 -D__${CHIP_SELECT}__=1 -mmcu=${MCU} -DAVR=1''; + CFLAGS = ''-O -finline-functions -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -Wall -Werror -Wstrict-prototypes -DF_CPU=${F_CPU} -std=gnu99 -D__${CHIP_SELECT}__=1 -mmcu=${MCU} -DAVR=1''; INCLUDE_DIRS = lib.concatStringsSep " " (map (dir: "-I${src}/${dir}") includes); buildPhase = '' @@ -129,6 +129,38 @@ ''; }; + packages."x86_64-linux"."rfm_diagnostic" = + let + pkgs = import nixpkgs { system = "x86_64-linux"; }; + lib = pkgs.lib; + avr = pkgs.pkgsCross.avr.buildPackages; + in pkgs.stdenv.mkDerivation rec { + name = "lcd"; + src = ./.; + + includes = [ "base" "display" "shift_register" "spi" "rfm69hcw" ]; + + MCU = "atmega32u4"; + CHIP_SELECT = "AVR_ATmega32u4"; + F_CPU = "8000000"; + CFLAGS = ''-O -finline-functions -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -Wall -Werror -Wstrict-prototypes -DF_CPU=${F_CPU} -std=gnu99 -D__${CHIP_SELECT}__=1 -mmcu=${MCU} -DAVR=1''; + INCLUDE_DIRS = lib.concatStringsSep " " (map (dir: "-I${src}/${dir}") includes); + + buildPhase = '' + ${avr.gcc}/bin/avr-gcc ${CFLAGS} ${INCLUDE_DIRS} -o base.o -c ${src}/base/base.c + ${avr.gcc}/bin/avr-gcc ${CFLAGS} ${INCLUDE_DIRS} -o spi.o -c ${src}/spi/spi.c + ${avr.gcc}/bin/avr-gcc ${CFLAGS} ${INCLUDE_DIRS} -o reg.o -c ${src}/shift_register/shift_register.c + ${avr.gcc}/bin/avr-gcc ${CFLAGS} ${INCLUDE_DIRS} -o display.o -c ${src}/display/display.c + ${avr.gcc}/bin/avr-gcc ${CFLAGS} ${INCLUDE_DIRS} -o rfm.o -c ${src}/rfm69hcw/rfm.c + ${avr.gcc}/bin/avr-gcc ${CFLAGS} ${INCLUDE_DIRS} -o main.o -c ${src}/rfm_diagnostic/main.c + ${avr.gcc}/bin/avr-gcc ${CFLAGS} -o main.elf main.o display.o rfm.o reg.o spi.o base.o + $OBJCOPY -O ihex main.elf main.hex + ''; + installPhase = '' + mkdir $out + cp main.elf main.hex $out + ''; + }; devShell."x86_64-linux" = let pkgs = import nixpkgs { system = "x86_64-linux"; }; diff --git a/rfm69hcw/rfm.c b/rfm69hcw/rfm.c new file mode 100644 index 0000000..6600354 --- /dev/null +++ b/rfm69hcw/rfm.c @@ -0,0 +1,120 @@ +/* +Copyright 2022, Savanni D'Gerinel + +This file is part of Savanni's AVR library. + +Lumeto is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + +Lumeto is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with Lumeto. If not, see . +*/ + + +#include + +void rfm_write(rfm_t *rfm, uint8_t reg, uint8_t *data, size_t length) { + spi_acquire(&rfm->spi); + spi_transfer_byte(&rfm->spi, _BV(7) | reg); + for (size_t i = 0; i < length; i++) { + spi_transfer_byte(&rfm->spi, data[i]); + } + spi_release(&rfm->spi); +} + +void rfm_read(rfm_t *rfm, uint8_t reg, uint8_t *data, size_t length) { + spi_acquire(&rfm->spi); + spi_transfer_byte(&rfm->spi, reg); + for (size_t i = 0; i < length; i++) { + data[i] = spi_transfer_byte(&rfm->spi, 0); + } + spi_release(&rfm->spi); +} + +void rfm_initialize(rfm_t *rfm) { + spi_initialize(&rfm->spi); +} + +void rfm_packet_format(rfm_t *rfm, packet_format_e format, size_t length) { + switch (format) { + case unlimited: + rfm_write(rfm, 0x37, (uint8_t [1]){ 0 }, 1); + rfm_write(rfm, 0x38, (uint8_t [1]){ 0 }, 1); + break; + case fixed: + rfm_write(rfm, 0x37, (uint8_t [1]){ 0 }, 1); + rfm_write(rfm, 0x38, (uint8_t [1]){ length }, 1); + break; + case variable: + rfm_write(rfm, 0x37, (uint8_t [1]){ _BV(7) }, 1); + rfm_write(rfm, 0x38, (uint8_t [1]){ 0 }, 1); + break; + } +} + +uint8_t rfm_temperature(rfm_t *rfm) { + uint8_t ready = 0; + uint8_t temp; + rfm_write(rfm, 0x4e, (uint8_t [1]){ _BV(3) }, 1); + _delay_ms(1); + + uint8_t i = 0; + while (!(ready & _BV(2)) && i < 10) { + rfm_read(rfm, 0x4e, &ready, 1); + i++; + _delay_us(100); + } + + rfm_read(rfm, 0x4f, &temp, 1); + + return temp; +} + +uint8_t rfm_mode(rfm_t *rfm) { + uint8_t mode_flag; + rfm_read(rfm, 0x01, &mode_flag, 1); + return mode_flag; +} + +uint8_t rfm_status(rfm_t *rfm) { + uint8_t status_flag; + rfm_read(rfm, 0x28, &status_flag, 1); + return status_flag; +} + +void rfm_listen(rfm_t *rfm) { + rfm_write(rfm, 0x01, (uint8_t [1]){ _BV(6) }, 1); + _delay_ms(100); +} + +uint32_t rfm_frequency(rfm_t *rfm) { + uint8_t frequency_bytes[3]; + uint32_t frequency; + rfm_read(rfm, 0x07, &frequency_bytes[2], 1); + rfm_read(rfm, 0x08, &frequency_bytes[1], 1); + rfm_read(rfm, 0x09, &frequency_bytes[0], 1); + + frequency = frequency_bytes[2]; + frequency = frequency << 8; + frequency += frequency_bytes[1]; + frequency = frequency << 8; + frequency += frequency_bytes[0]; + return frequency * 61; +} + +uint8_t rfm_set_mode(rfm_t *rfm, mode_e mode) { + uint8_t mode_flags; + rfm_read(rfm, 0x01, &mode_flags, 1); + mode_flags = mode_flags & 0b11100011; + /* + mode_flags += (mode << 2); + rfm_write(rfm, 0x01, &mode_flags, 1); + */ + return mode_flags; +} + +uint8_t rfm_irq_1(rfm_t *rfm) { + uint8_t irq; + rfm_read(rfm, 0x27, &irq, 1); + return irq; +} diff --git a/rfm69hcw/rfm.h b/rfm69hcw/rfm.h new file mode 100644 index 0000000..6243222 --- /dev/null +++ b/rfm69hcw/rfm.h @@ -0,0 +1,54 @@ +/* +Copyright 2022, Savanni D'Gerinel + +This file is part of Savanni's AVR library. + +Lumeto is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + +Lumeto is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with Lumeto. If not, see . +*/ + +#ifndef __RFM_H__ +#define __RFM_H__ + +#include +#include + +typedef struct RFM { + spi_t spi; + gpio_t irq; + gpio_t reset; +} rfm_t; + +typedef enum packet_format { + unlimited, + fixed, + variable, +} packet_format_e; + +typedef enum MODE { + sleep, + standby, + fs, + tx, + rx +} mode_e; + +void rfm_initialize(rfm_t *rfm); +void rfm_packet_format(rfm_t *rfm, packet_format_e format, size_t length); + +void rfm_send_data(rfm_t *rfm, uint8_t *data, size_t length); +void rfm_receive_data(rfm_t *rfm, uint8_t *data, size_t length); + +uint8_t rfm_mode(rfm_t *rfm); +uint8_t rfm_status(rfm_t *rfm); +uint8_t rfm_temperature(rfm_t *rfm); +uint32_t rfm_frequency(rfm_t *rfm); + +void rfm_listen(rfm_t *rfm); +uint8_t rfm_set_mode(rfm_t *rfm, mode_e mode); +uint8_t rfm_irq_1(rfm_t *rfm); + +#endif diff --git a/rfm_diagnostic/main.c b/rfm_diagnostic/main.c new file mode 100644 index 0000000..2b6d351 --- /dev/null +++ b/rfm_diagnostic/main.c @@ -0,0 +1,209 @@ +/* +Copyright 2022, Savanni D'Gerinel + +This file is part of Savanni's AVR library. + +Lumeto is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + +Lumeto is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with Lumeto. If not, see . +*/ + +#include +#include +#include +#include +#include +#include +#include + +void display_current_mode(display_t *display, rfm_t *rfm) { + display_clear(display); + + uint8_t mode = rfm_mode(rfm); + char msg[40]; + sprintf(msg, "Mode: 0x%02x", mode); + + display_write_message(display, msg); + display_set_location(display, 1, 0); + display_write_message(display, ": "); + + if (mode & _BV(7)) { + display_write_message(display, "SO "); + } + if (mode & _BV(6)) { + display_write_message(display, "LO "); + } + if (mode & _BV(5)) { + display_write_message(display, "LA "); + } + uint8_t tr_op_mode = (mode & 0b00011100) >> 2; + switch (tr_op_mode) { + case 0: display_write_message(display, "Sleep"); + break; + case 1: display_write_message(display, "Standby"); + break; + case 2: display_write_message(display, "FS"); + break; + case 3: display_write_message(display, "TX"); + break; + case 4: display_write_message(display, "RS"); + } +} + +void display_temperature(display_t *display, rfm_t *rfm) { + display_clear(display); + + uint8_t temperature = rfm_temperature(rfm); + + display_write_message(display, "Temperature:"); + display_set_location(display, 1, 0); + char temp_str[8]; + sprintf(temp_str, ": %d", temperature); + display_write_message(display, temp_str); +} + +void display_status_flags(display_t *display, rfm_t *rfm) { + display_clear(display); + + display_write_message(display, "Status:"); + display_set_location(display, 1, 0); + display_write_message(display, ": "); + + uint8_t status = rfm_status(rfm); + + if (status & _BV(7)) { + display_write_message(display, "FF "); + } + if (status & _BV(6)) { + display_write_message(display, "FNE "); + } + if (status & _BV(5)) { + display_write_message(display, "FL "); + } + if (status & _BV(4)) { + display_write_message(display, "FO "); + } + if (status & _BV(3)) { + display_write_message(display, "PS "); + } + if (status & _BV(2)) { + display_write_message(display, "PR "); + } + if (status & _BV(1)) { + display_write_message(display, "Ok "); + } +} + +void display_irq_flags(display_t *display, rfm_t *rfm) { + display_clear(display); + + display_write_message(display, "IRQ:"); + display_set_location(display, 1, 0); + display_write_message(display, ": "); + + uint8_t flags = rfm_irq_1(rfm); + + if (flags & _BV(7)) { + display_write_message(display, "MR "); + } + if (flags & _BV(6)) { + display_write_message(display, "RR "); + } + if (flags & _BV(5)) { + display_write_message(display, "TR "); + } + if (flags & _BV(4)) { + display_write_message(display, "PL "); + } + if (flags & _BV(3)) { + display_write_message(display, "RS "); + } + if (flags & _BV(2)) { + display_write_message(display, "TO "); + } + if (flags & _BV(1)) { + display_write_message(display, "AO "); + } + if (flags & _BV(0)) { + display_write_message(display, "SM "); + } +} + +void display_frequency(display_t *display, rfm_t *rfm) { + display_clear(display); + + display_write_message(display, "Frequency: "); + display_set_location(display, 1, 0); + + uint32_t frequency = rfm_frequency(rfm); + char temp_str[32]; + sprintf(temp_str, ": %lu", frequency); + display_write_message(display, temp_str); +} + +void display_bits(display_t *display, uint8_t bits) { + display_clear(display); + + char value[8]; + sprintf(value, "0x%02x", bits); + display_write_message(display, value); + display_set_location(display, 1, 0); + for (int i = 7; i >= 0; i--) { + if (bits & _BV(i)) { + display_write_message(display, "1"); + } else { + display_write_message(display, "0"); + } + } +} + +int main(void) { + display_t display = { + .reg = { + .output = { .ddr = &DDRB, .port = &PORTB, .pin = &PINB, .addr = 5 }, + .latch_clock = { .ddr = &DDRB, .port = &PORTB, .pin = &PINB, .addr = 6 }, + .shift_clock = { .ddr = &DDRB, .port = &PORTB, .pin = &PINB, .addr = 7 }, + }, + .register_select = { .ddr = &DDRF, .port = &PORTF, .pin = &PINF, .addr = 1 }, + .enable = { .ddr = &DDRF, .port = &PORTF, .pin = &PINF, .addr = 0 }, + }; + display_init(&display); + + rfm_t rfm = { + .spi = { + .clock = { .ddr = &DDRB, .port = &PORTB, .pin = &PINB, .addr = 1 }, + .data_out = { .ddr = &DDRB, .port = &PORTB, .pin = &PINB, .addr = 2 }, + .data_in = { .ddr = &DDRB, .port = &PORTB, .pin = &PINB, .addr = 3 }, + .chip_select = { .ddr = &DDRB, .port = &PORTB, .pin = &PINB, .addr = 4 }, + }, + .irq = { .ddr = &DDRE, .port = &PORTE, .pin = &PINE, .addr = 6 }, + .reset = { .ddr = &DDRD, .port = &PORTD, .pin = &PIND, .addr = 4 }, + }; + + rfm_initialize(&rfm); + + _delay_ms(15); + display_enable(&display); + + display_clear(&display); + display_write_message(&display, "Waking up"); + _delay_ms(1000); + + /* + rfm_set_mode(&rfm, standby); + */ + rfm_listen(&rfm); + + while(1) { + display_status_flags(&display, &rfm); + _delay_ms(5000); + display_current_mode(&display, &rfm); + _delay_ms(5000); + display_irq_flags(&display, &rfm); + _delay_ms(5000); + display_frequency(&display, &rfm); + _delay_ms(5000); + } +}