Create an RFM diagnostic program

i2c
Savanni D'Gerinel 2022-06-27 20:05:01 -04:00
parent d86b6c596b
commit fffa9b3e89
4 changed files with 419 additions and 4 deletions

View File

@ -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"; };

120
rfm69hcw/rfm.c Normal file
View File

@ -0,0 +1,120 @@
/*
Copyright 2022, Savanni D'Gerinel <savanni@luminescent-dreams.com>
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 <https://www.gnu.org/licenses/>.
*/
#include <rfm.h>
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;
}

54
rfm69hcw/rfm.h Normal file
View File

@ -0,0 +1,54 @@
/*
Copyright 2022, Savanni D'Gerinel <savanni@luminescent-dreams.com>
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 <https://www.gnu.org/licenses/>.
*/
#ifndef __RFM_H__
#define __RFM_H__
#include <base.h>
#include <spi.h>
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

209
rfm_diagnostic/main.c Normal file
View File

@ -0,0 +1,209 @@
/*
Copyright 2022, Savanni D'Gerinel <savanni@luminescent-dreams.com>
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 <https://www.gnu.org/licenses/>.
*/
#include <avr/io.h>
#include <util/delay.h>
#include <base.h>
#include <spi.h>
#include <rfm.h>
#include <display.h>
#include <stdio.h>
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);
}
}