From 070fc42ad57d23ab87979463af5665c7ba93d1b4 Mon Sep 17 00:00:00 2001 From: Manfred Steiner Date: Sat, 3 Aug 2024 11:22:22 +0200 Subject: [PATCH] ... --- .../test_2024-07-23/.gdb_history | 0 .../test_2024-07-23/.gdbinit | 0 .../test_2024-07-23/.gitignore | 0 .../.vscode/c_cpp_properties.json | 18 + .../test_2024-07-23/.vscode/launch.json | 0 .../test_2024-07-23/.vscode/settings.json | 0 .../test_2024-07-23/.vscode/tasks.json | 0 .../arduino-nano-5v/test_2024-07-23/Makefile | 82 +++ .../test_2024-07-23/README.md | 0 .../test_2024-07-23/src/adafruit/bme280.cpp | 0 .../test_2024-07-23/src/adafruit/bme280.h | 0 .../test_2024-07-23/src/adafruit/ens160.cpp | 0 .../test_2024-07-23/src/adafruit/ens160.h | 0 .../test_2024-07-23/src/adafruit/sensor.h | 0 .../test_2024-07-23/src/i2cmaster.cpp | 2 +- .../test_2024-07-23/src/i2cmaster.hpp | 0 .../test_2024-07-23/src/i2cslave.cpp | 0 .../test_2024-07-23/src/i2cslave.hpp | 0 .../test_2024-07-23/src/main.cpp | 277 ++++++++++ .../test_2024-07-23/src/main.hpp | 3 +- .../test_2024-07-23/src/units/encoder.cpp | 8 +- .../test_2024-07-23/src/units/encoder.hpp | 4 +- .../test_2024-07-23/src/units/i2c.cpp | 242 ++++----- .../test_2024-07-23/src/units/i2c.hpp | 2 +- .../test_2024-07-23/src/units/ieee485.cpp | 110 ++++ .../test_2024-07-23/src/units/ieee485.hpp | 3 +- .../test_2024-07-23/src/units/lcd.cpp | 257 +++++++++ .../test_2024-07-23/src/units/lcd.hpp | 34 ++ .../test_2024-07-23/src/units/led.cpp | 134 +++++ .../test_2024-07-23/src/units/led.hpp | 28 + .../nano-644/test_2024-07-23/.gdb_history | 9 + software/nano-644/test_2024-07-23/.gdbinit | 2 + software/nano-644/test_2024-07-23/.gitignore | 4 + .../.vscode/c_cpp_properties.json | 0 .../test_2024-07-23/.vscode/launch.json | 37 ++ .../test_2024-07-23/.vscode/settings.json | 26 + .../test_2024-07-23/.vscode/tasks.json | 23 + .../{ => nano-644}/test_2024-07-23/Makefile | 0 software/nano-644/test_2024-07-23/README.md | 1 + .../test_2024-07-23/src/adafruit/bme280.cpp | 512 ++++++++++++++++++ .../test_2024-07-23/src/adafruit/bme280.h | 373 +++++++++++++ .../test_2024-07-23/src/adafruit/ens160.cpp | 374 +++++++++++++ .../test_2024-07-23/src/adafruit/ens160.h | 188 +++++++ .../test_2024-07-23/src/adafruit/sensor.h | 224 ++++++++ .../test_2024-07-23/src/i2cmaster.cpp | 143 +++++ .../test_2024-07-23/src/i2cmaster.hpp | 28 + .../nano-644/test_2024-07-23/src/i2cslave.cpp | 92 ++++ .../nano-644/test_2024-07-23/src/i2cslave.hpp | 32 ++ .../test_2024-07-23/src/main.cpp | 23 +- .../nano-644/test_2024-07-23/src/main.hpp | 20 + .../test_2024-07-23/src/units/encoder.cpp | 86 +++ .../test_2024-07-23/src/units/encoder.hpp | 22 + .../test_2024-07-23/src/units/i2c.cpp | 300 ++++++++++ .../test_2024-07-23/src/units/i2c.hpp | 42 ++ .../test_2024-07-23/src/units/ieee485.cpp | 8 +- .../test_2024-07-23/src/units/ieee485.hpp | 21 + .../test_2024-07-23/src/units/lcd.cpp | 8 +- .../test_2024-07-23/src/units/lcd.hpp | 3 +- .../test_2024-07-23/src/units/led.cpp | 6 +- .../test_2024-07-23/src/units/led.hpp | 3 +- .../test_2024-07-23/src/units/modbus.cpp | 28 +- .../test_2024-07-23/src/units/modbus.hpp | 3 +- .../test_2024-07-23/src/units/motor.cpp | 16 +- .../test_2024-07-23/src/units/motor.hpp | 3 +- .../test_2024-07-23/src/units/portexp.cpp | 20 +- .../test_2024-07-23/src/units/portexp.hpp | 3 +- .../test_2024-07-23/src/units/poti.cpp | 10 +- .../test_2024-07-23/src/units/poti.hpp | 3 +- .../test_2024-07-23/src/units/r2r.cpp | 12 +- .../test_2024-07-23/src/units/r2r.hpp | 3 +- .../test_2024-07-23/src/units/rgb.cpp | 12 +- .../test_2024-07-23/src/units/rgb.hpp | 3 +- .../test_2024-07-23/src/units/seg7.cpp | 14 +- .../test_2024-07-23/src/units/seg7.hpp | 3 +- .../test_2024-07-23/src/units/switch.cpp | 6 +- .../test_2024-07-23/src/units/switch.hpp | 3 +- .../test_2024-07-23/src/units/uart1.cpp | 8 +- .../test_2024-07-23/src/units/uart1.hpp | 3 +- 78 files changed, 3741 insertions(+), 226 deletions(-) rename software/{ => arduino-nano-5v}/test_2024-07-23/.gdb_history (100%) rename software/{ => arduino-nano-5v}/test_2024-07-23/.gdbinit (100%) rename software/{ => arduino-nano-5v}/test_2024-07-23/.gitignore (100%) create mode 100644 software/arduino-nano-5v/test_2024-07-23/.vscode/c_cpp_properties.json rename software/{ => arduino-nano-5v}/test_2024-07-23/.vscode/launch.json (100%) rename software/{ => arduino-nano-5v}/test_2024-07-23/.vscode/settings.json (100%) rename software/{ => arduino-nano-5v}/test_2024-07-23/.vscode/tasks.json (100%) create mode 100644 software/arduino-nano-5v/test_2024-07-23/Makefile rename software/{ => arduino-nano-5v}/test_2024-07-23/README.md (100%) rename software/{ => arduino-nano-5v}/test_2024-07-23/src/adafruit/bme280.cpp (100%) rename software/{ => arduino-nano-5v}/test_2024-07-23/src/adafruit/bme280.h (100%) rename software/{ => arduino-nano-5v}/test_2024-07-23/src/adafruit/ens160.cpp (100%) rename software/{ => arduino-nano-5v}/test_2024-07-23/src/adafruit/ens160.h (100%) rename software/{ => arduino-nano-5v}/test_2024-07-23/src/adafruit/sensor.h (100%) rename software/{ => arduino-nano-5v}/test_2024-07-23/src/i2cmaster.cpp (98%) rename software/{ => arduino-nano-5v}/test_2024-07-23/src/i2cmaster.hpp (100%) rename software/{ => arduino-nano-5v}/test_2024-07-23/src/i2cslave.cpp (100%) rename software/{ => arduino-nano-5v}/test_2024-07-23/src/i2cslave.hpp (100%) create mode 100644 software/arduino-nano-5v/test_2024-07-23/src/main.cpp rename software/{ => arduino-nano-5v}/test_2024-07-23/src/main.hpp (79%) rename software/{ => arduino-nano-5v}/test_2024-07-23/src/units/encoder.cpp (91%) rename software/{ => arduino-nano-5v}/test_2024-07-23/src/units/encoder.hpp (80%) rename software/{ => arduino-nano-5v}/test_2024-07-23/src/units/i2c.cpp (50%) rename software/{ => arduino-nano-5v}/test_2024-07-23/src/units/i2c.hpp (95%) create mode 100644 software/arduino-nano-5v/test_2024-07-23/src/units/ieee485.cpp rename software/{ => arduino-nano-5v}/test_2024-07-23/src/units/ieee485.hpp (78%) create mode 100644 software/arduino-nano-5v/test_2024-07-23/src/units/lcd.cpp create mode 100644 software/arduino-nano-5v/test_2024-07-23/src/units/lcd.hpp create mode 100644 software/arduino-nano-5v/test_2024-07-23/src/units/led.cpp create mode 100644 software/arduino-nano-5v/test_2024-07-23/src/units/led.hpp create mode 100644 software/nano-644/test_2024-07-23/.gdb_history create mode 100644 software/nano-644/test_2024-07-23/.gdbinit create mode 100644 software/nano-644/test_2024-07-23/.gitignore rename software/{ => nano-644}/test_2024-07-23/.vscode/c_cpp_properties.json (100%) create mode 100644 software/nano-644/test_2024-07-23/.vscode/launch.json create mode 100644 software/nano-644/test_2024-07-23/.vscode/settings.json create mode 100644 software/nano-644/test_2024-07-23/.vscode/tasks.json rename software/{ => nano-644}/test_2024-07-23/Makefile (100%) create mode 100644 software/nano-644/test_2024-07-23/README.md create mode 100644 software/nano-644/test_2024-07-23/src/adafruit/bme280.cpp create mode 100644 software/nano-644/test_2024-07-23/src/adafruit/bme280.h create mode 100644 software/nano-644/test_2024-07-23/src/adafruit/ens160.cpp create mode 100644 software/nano-644/test_2024-07-23/src/adafruit/ens160.h create mode 100644 software/nano-644/test_2024-07-23/src/adafruit/sensor.h create mode 100644 software/nano-644/test_2024-07-23/src/i2cmaster.cpp create mode 100644 software/nano-644/test_2024-07-23/src/i2cmaster.hpp create mode 100644 software/nano-644/test_2024-07-23/src/i2cslave.cpp create mode 100644 software/nano-644/test_2024-07-23/src/i2cslave.hpp rename software/{ => nano-644}/test_2024-07-23/src/main.cpp (91%) create mode 100644 software/nano-644/test_2024-07-23/src/main.hpp create mode 100644 software/nano-644/test_2024-07-23/src/units/encoder.cpp create mode 100644 software/nano-644/test_2024-07-23/src/units/encoder.hpp create mode 100644 software/nano-644/test_2024-07-23/src/units/i2c.cpp create mode 100644 software/nano-644/test_2024-07-23/src/units/i2c.hpp rename software/{ => nano-644}/test_2024-07-23/src/units/ieee485.cpp (91%) create mode 100644 software/nano-644/test_2024-07-23/src/units/ieee485.hpp rename software/{ => nano-644}/test_2024-07-23/src/units/lcd.cpp (97%) rename software/{ => nano-644}/test_2024-07-23/src/units/lcd.hpp (83%) rename software/{ => nano-644}/test_2024-07-23/src/units/led.cpp (86%) rename software/{ => nano-644}/test_2024-07-23/src/units/led.hpp (71%) rename software/{ => nano-644}/test_2024-07-23/src/units/modbus.cpp (82%) rename software/{ => nano-644}/test_2024-07-23/src/units/modbus.hpp (81%) rename software/{ => nano-644}/test_2024-07-23/src/units/motor.cpp (87%) rename software/{ => nano-644}/test_2024-07-23/src/units/motor.hpp (79%) rename software/{ => nano-644}/test_2024-07-23/src/units/portexp.cpp (89%) rename software/{ => nano-644}/test_2024-07-23/src/units/portexp.hpp (71%) rename software/{ => nano-644}/test_2024-07-23/src/units/poti.cpp (75%) rename software/{ => nano-644}/test_2024-07-23/src/units/poti.hpp (71%) rename software/{ => nano-644}/test_2024-07-23/src/units/r2r.cpp (68%) rename software/{ => nano-644}/test_2024-07-23/src/units/r2r.hpp (71%) rename software/{ => nano-644}/test_2024-07-23/src/units/rgb.cpp (84%) rename software/{ => nano-644}/test_2024-07-23/src/units/rgb.hpp (71%) rename software/{ => nano-644}/test_2024-07-23/src/units/seg7.cpp (90%) rename software/{ => nano-644}/test_2024-07-23/src/units/seg7.hpp (71%) rename software/{ => nano-644}/test_2024-07-23/src/units/switch.cpp (86%) rename software/{ => nano-644}/test_2024-07-23/src/units/switch.hpp (72%) rename software/{ => nano-644}/test_2024-07-23/src/units/uart1.cpp (85%) rename software/{ => nano-644}/test_2024-07-23/src/units/uart1.hpp (77%) diff --git a/software/test_2024-07-23/.gdb_history b/software/arduino-nano-5v/test_2024-07-23/.gdb_history similarity index 100% rename from software/test_2024-07-23/.gdb_history rename to software/arduino-nano-5v/test_2024-07-23/.gdb_history diff --git a/software/test_2024-07-23/.gdbinit b/software/arduino-nano-5v/test_2024-07-23/.gdbinit similarity index 100% rename from software/test_2024-07-23/.gdbinit rename to software/arduino-nano-5v/test_2024-07-23/.gdbinit diff --git a/software/test_2024-07-23/.gitignore b/software/arduino-nano-5v/test_2024-07-23/.gitignore similarity index 100% rename from software/test_2024-07-23/.gitignore rename to software/arduino-nano-5v/test_2024-07-23/.gitignore diff --git a/software/arduino-nano-5v/test_2024-07-23/.vscode/c_cpp_properties.json b/software/arduino-nano-5v/test_2024-07-23/.vscode/c_cpp_properties.json new file mode 100644 index 0000000..93c17af --- /dev/null +++ b/software/arduino-nano-5v/test_2024-07-23/.vscode/c_cpp_properties.json @@ -0,0 +1,18 @@ +{ + "configurations": [ + { + "name": "Linux AVR", + "includePath": [ + "/usr/lib/avr/include/**", + "/usr/lib/gcc/avr/**" + ], + "defines": [], + "compilerPath": "/usr/bin/avr-gcc", + "compilerArgs": [ "-mmcu=atmega328p", "-DF_CPU=16000000", "-Os" ], + "cStandard": "gnu11", + "cppStandard": "gnu++11", + "intelliSenseMode": "linux-gcc-x64" + } + ], + "version": 4 +} diff --git a/software/test_2024-07-23/.vscode/launch.json b/software/arduino-nano-5v/test_2024-07-23/.vscode/launch.json similarity index 100% rename from software/test_2024-07-23/.vscode/launch.json rename to software/arduino-nano-5v/test_2024-07-23/.vscode/launch.json diff --git a/software/test_2024-07-23/.vscode/settings.json b/software/arduino-nano-5v/test_2024-07-23/.vscode/settings.json similarity index 100% rename from software/test_2024-07-23/.vscode/settings.json rename to software/arduino-nano-5v/test_2024-07-23/.vscode/settings.json diff --git a/software/test_2024-07-23/.vscode/tasks.json b/software/arduino-nano-5v/test_2024-07-23/.vscode/tasks.json similarity index 100% rename from software/test_2024-07-23/.vscode/tasks.json rename to software/arduino-nano-5v/test_2024-07-23/.vscode/tasks.json diff --git a/software/arduino-nano-5v/test_2024-07-23/Makefile b/software/arduino-nano-5v/test_2024-07-23/Makefile new file mode 100644 index 0000000..aa7ba13 --- /dev/null +++ b/software/arduino-nano-5v/test_2024-07-23/Makefile @@ -0,0 +1,82 @@ +.PHONY: all info flash picocom clean +$(shell mkdir -p dist >/dev/null) +$(shell mkdir -p build >/dev/null) +$(shell mkdir -p sim >/dev/null) + +NAME="test_2024-07-23_nano-5v" +SRC= $(wildcard src/*.c src/*.cpp src/*/*.cpp) +OBJ = $(SRC:src/%.c=build/%.o) +OBJ_SIM = $(SRC:src/%.c=sim/%.o) + +DEVICE=atmega328p + +CC= avr-g++ +CFLAGS= -Wall -mmcu=$(DEVICE) -Os -DF_CPU=16000000 -c +LFLAGS= -Wall -mmcu=$(DEVICE) -Os -DF_CPU=16000000 -Wl,-u,vfprintf -lprintf_flt -lm + +CFLAGS_SIM= -Wall -mmcu=$(DEVICE) -Og -DF_CPU=16000000 -g -c +LFLAGS_SIM= -Wall -mmcu=$(DEVICE) -Og -DF_CPU=16000000 -g -Wl,-u,vfprintf -lprintf_flt -lm + + +all: dist/$(NAME).elf dist/$(NAME).s dist/$(NAME).hex sim/$(NAME).elf sim/$(NAME).s info + +info: + @echo + @avr-size --mcu=$(DEVICE) --format=avr dist/$(NAME).elf + +.depend: $(SRC) + $(CC) -MM $(SRC) > .depend + +-include $(DEPENDFILE) + +dist/$(NAME).elf: .depend $(OBJ) + $(CC) $(LFLAGS) -o $@ $(OBJ) + +dist/%.s: dist/%.elf + avr-objdump -d $< > $@ + +dist/%.hex: dist/%.elf + avr-objcopy -O ihex $(HEX_FLASH_FLAGS) $< $@ + +sim/$(NAME).elf: .depend $(OBJ_SIM) + $(CC) $(LFLAGS_SIM) -o $@ $(OBJ_SIM) + + +build/%.o: src/%.c + $(CC) $(CFLAGS) -o $@ $< + +sim/%.o: src/%.c + $(CC) $(CFLAGS_SIM) -o $@ $< + +sim/%.s: sim/%.elf + avr-objdump -d $< > $@ + +simuc: sim/$(NAME).elf + simuc --board arduino $< + +gdb: sim/$(NAME).elf + avr-gdb $< + +isp-328p: + avrdude -c usbasp -p m328p + +isp-flash-328p: dist/$(NAME).elf all + avrdude -c usbasp -p m328p -e -U flash:w:$< + +flash-328p: dist/$(NAME).elf all + avrdude -c arduino -p m328p -P /dev/ttyUSB0 -b 115200 -e -U flash:w:$< + + +picocom: + # picocom sends CR for ENTER -> convert cr (\r) to lf (\n) + picocom -b 115200 --omap crlf /dev/ttyUSB0 + +isp-fuse-328p: + avrdude -c usbasp -p m328p -U lfuse:w:0x62:m -U hfuse:w:0xD9:m -U efuse:w:0xFF:m -U lock:w:0xFF:m + +clean: + @rm -r dist + @rm -r build + @rm -r sim + @find . -type f -name ".depend" -exec rm {} \; + @echo "clean done" diff --git a/software/test_2024-07-23/README.md b/software/arduino-nano-5v/test_2024-07-23/README.md similarity index 100% rename from software/test_2024-07-23/README.md rename to software/arduino-nano-5v/test_2024-07-23/README.md diff --git a/software/test_2024-07-23/src/adafruit/bme280.cpp b/software/arduino-nano-5v/test_2024-07-23/src/adafruit/bme280.cpp similarity index 100% rename from software/test_2024-07-23/src/adafruit/bme280.cpp rename to software/arduino-nano-5v/test_2024-07-23/src/adafruit/bme280.cpp diff --git a/software/test_2024-07-23/src/adafruit/bme280.h b/software/arduino-nano-5v/test_2024-07-23/src/adafruit/bme280.h similarity index 100% rename from software/test_2024-07-23/src/adafruit/bme280.h rename to software/arduino-nano-5v/test_2024-07-23/src/adafruit/bme280.h diff --git a/software/test_2024-07-23/src/adafruit/ens160.cpp b/software/arduino-nano-5v/test_2024-07-23/src/adafruit/ens160.cpp similarity index 100% rename from software/test_2024-07-23/src/adafruit/ens160.cpp rename to software/arduino-nano-5v/test_2024-07-23/src/adafruit/ens160.cpp diff --git a/software/test_2024-07-23/src/adafruit/ens160.h b/software/arduino-nano-5v/test_2024-07-23/src/adafruit/ens160.h similarity index 100% rename from software/test_2024-07-23/src/adafruit/ens160.h rename to software/arduino-nano-5v/test_2024-07-23/src/adafruit/ens160.h diff --git a/software/test_2024-07-23/src/adafruit/sensor.h b/software/arduino-nano-5v/test_2024-07-23/src/adafruit/sensor.h similarity index 100% rename from software/test_2024-07-23/src/adafruit/sensor.h rename to software/arduino-nano-5v/test_2024-07-23/src/adafruit/sensor.h diff --git a/software/test_2024-07-23/src/i2cmaster.cpp b/software/arduino-nano-5v/test_2024-07-23/src/i2cmaster.cpp similarity index 98% rename from software/test_2024-07-23/src/i2cmaster.cpp rename to software/arduino-nano-5v/test_2024-07-23/src/i2cmaster.cpp index 21ff990..9b1bd5d 100644 --- a/software/test_2024-07-23/src/i2cmaster.cpp +++ b/software/arduino-nano-5v/test_2024-07-23/src/i2cmaster.cpp @@ -103,7 +103,7 @@ bool I2cMaster::readBytes (uint8_t *buffer, uint8_t len) { bool I2cMaster::writeBytes (const uint8_t *buffer, uint8_t len) { while (len-- > 0) { - // printf("[wB:len=%d, byte=%02x]", len + 1, *buffer); + // printf_P(PSTR("[wB:len=%d, byte=%02x]"), len + 1, *buffer); TWDR = *buffer++; TWCR = (1 << TWINT) | (1 << TWEN); // send data byte timer = 5; diff --git a/software/test_2024-07-23/src/i2cmaster.hpp b/software/arduino-nano-5v/test_2024-07-23/src/i2cmaster.hpp similarity index 100% rename from software/test_2024-07-23/src/i2cmaster.hpp rename to software/arduino-nano-5v/test_2024-07-23/src/i2cmaster.hpp diff --git a/software/test_2024-07-23/src/i2cslave.cpp b/software/arduino-nano-5v/test_2024-07-23/src/i2cslave.cpp similarity index 100% rename from software/test_2024-07-23/src/i2cslave.cpp rename to software/arduino-nano-5v/test_2024-07-23/src/i2cslave.cpp diff --git a/software/test_2024-07-23/src/i2cslave.hpp b/software/arduino-nano-5v/test_2024-07-23/src/i2cslave.hpp similarity index 100% rename from software/test_2024-07-23/src/i2cslave.hpp rename to software/arduino-nano-5v/test_2024-07-23/src/i2cslave.hpp diff --git a/software/arduino-nano-5v/test_2024-07-23/src/main.cpp b/software/arduino-nano-5v/test_2024-07-23/src/main.cpp new file mode 100644 index 0000000..f5b0f3e --- /dev/null +++ b/software/arduino-nano-5v/test_2024-07-23/src/main.cpp @@ -0,0 +1,277 @@ +#include +#include +#include +#include + +#include +#include + +#include "main.hpp" +#include "units/encoder.hpp" +#include "units/i2c.hpp" +#include "units/led.hpp" +#include "units/ieee485.hpp" +#include "units/led.hpp" +#include "units/lcd.hpp" + + +// #include "units/switch.hpp" +// #include "units/rgb.hpp" +// #include "units/seg7.hpp" +// #include "units/poti.hpp" +// #include "units/r2r.hpp" +// #include "units/motor.hpp" +// #include "units/portexp.hpp" +// #include "units/uart1.hpp" +// #include "units/modbus.hpp" + + + + +extern "C" { + void __cxa_pure_virtual () { + } + + int __cxa_guard_acquire(uint8_t *g) { + return 0; + } + + void __cxa_guard_release(uint8_t *g) {} + + void __cxa_guard_abort(uint8_t *g) {} + + + int uart_putchar(char c, FILE *stream) { + if (c == '\n') { + uart_putchar('\r', stream); + } + if (stream == stdout) { + loop_until_bit_is_set(UCSR0A, UDRE0); + UDR0 = c; + } + return 0; + } + + + uint64_t volatile systemMillis = 0; + uint8_t volatile uartBuffer[32]; + uint8_t volatile rIndex = 0; + uint8_t volatile wIndex = 0; + + int uart_getchar (FILE *stream) { + // if (rIndex == wIndex) { + // // nothing in buffer + // return EOF; + // } + // printf_P(PSTR(" r%d"), rIndex); + while (rIndex == wIndex) { + // wait for character + } + + // don't use "char c" because german special characters would lead to negative return -> stream error + // char c = uartBuffer[rIndex++]; + + uint8_t c = uartBuffer[rIndex++]; + // printf_P(PSTR("(%02x) "), c); + if (c == '\r') { + c = '\n'; + } + putchar(c); // echo on terminal + return c; + } + + static FILE mystdout = { 0, 0, _FDEV_SETUP_WRITE , 0, 0, uart_putchar, NULL, 0 }; + static FILE mystdin = { 0, 0, _FDEV_SETUP_READ , 0, 0, NULL, uart_getchar, 0 }; + + static volatile uint32_t timer1ms = 0; + static volatile int keyUart0 = EOF; + + Led led; + // Switch sw; + // Rgb rgb; + // Seg7 seg7; + // Poti poti; + Encoder encoder; + // R2r r2r; + // Motor motor; + // PortExp portExp; + Lcd lcd; + // Uart1 uart1; + // Modbus modbus; + Ieee485 ieee485; + I2c i2cSparkfun(I2c::SparkFunEnvCombo); + I2c i2cMaster(I2c::Master); + I2c i2cSlave(I2c::Slave); + +} + +void setTimer (uint32_t ms) { + ATOMIC_BLOCK(ATOMIC_FORCEON) { + timer1ms = ms; + } +} + +int wait (uint32_t ms) { + setTimer(ms); + do { + ATOMIC_BLOCK(ATOMIC_FORCEON) { + ms = timer1ms; + } + } while (ms > 0 && keyUart0 == EOF); + return keyUart0; +} + +int main () { + + // Nano-644 LEDs (Green, Orange, Red) + DDRC |= (1 << DDC4) | (1 << DDC3) | (1 << DDC2); + PORTC &= ~((1 << PORT4) | (1 << PORT3) | (1 << PORT2)); + + // Nano-644 push button SW2 + DDRC &= ~(1 << DDC5); + PORTC |= (1 << PORT5); // enable internal pullup resistor + + // UART0 interface on Nano-644 + UCSR0A = (1 << U2X0); + UCSR0B = (1 << RXCIE0) | (1 << RXEN0) | (1 <getName()); + printf_P(PSTR("\n")); + } + printf_P(PSTR("\nSelect unit: ")); + rIndex = 0; wIndex = 0; + fgets(s, sizeof(s), stdin); + } while (sscanf(s, "%x", &i) != 1 || i < 0 || i >= sizeof(unit) / sizeof(unit[0]) ); + + TestUnit *pu = unit[i]; + printf_P(PSTR("\n\n[%s]: "), pu->getName()); + keyUart0 = EOF; + + for (uint8_t subtest = 0; subtest < 0xff; subtest++) { + printf_P(PSTR("\n%4d: "), subtest); + if (pu->run(subtest) < 0) { + break; + } + if (keyUart0 == 27) { + keyUart0 = EOF; + break; + } + keyUart0 = EOF; + } + pu->cleanup(); + } +} + +uint64_t millis () { + volatile uint64_t millis = systemMillis; + ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { + millis = systemMillis; + } + return millis; +} + +#ifndef USART0_RX_vect + #define USART0_RX_vect USART_RX_vect +#endif +ISR (USART0_RX_vect) { + uint8_t b = UDR0; + keyUart0 = b; + uartBuffer[wIndex++] = b; + // printf_P(PSTR(" w%d(%02x)"), wIndex, b); + if (wIndex == rIndex) { + // buffer overflow, kick out oldest byte + rIndex++; + } +} + +#ifdef USART1_RX_vect + ISR (USART1_RX_vect) { + uint8_t b = UDR1; + if (modbus.enabled) { + modbus.handleRxByte(b); + } + if (uart1.enabled) { + uart1.handleRxByte(b); + } + if (ieee485.enabled) { + ieee485.handleRxByte(b); + } + } +#endif + +ISR (TWI_vect) { + if (i2cMaster.enabled) { + i2cMaster.handleTwiIrq(); + } else if (i2cSlave.enabled) { + i2cSlave.handleTwiIrq(); + } else if (i2cSparkfun.enabled) { + i2cSparkfun.handleTwiIrq(); + } else { + TWCR = (1 << TWINT); // clear interrupt request bit and disable TWI + } +} + +ISR (TIMER2_COMPA_vect) { // every 100us + static uint16_t timer500ms = 0; + static uint8_t timer100us = 0; + + if (encoder.enabled) { + encoder.tick100us(); + } + #ifdef MOTOR_HPP + if (motor.enabled) { + motor.tick100us(); + } + #endif + + timer100us++; + if (timer100us >= 10) { + timer100us = 0; + if (timer1ms > 0) { + timer1ms--; + } + systemMillis++; + i2cMaster.tick1ms(); + i2cSlave.tick1ms(); + i2cSparkfun.tick1ms(); + } + + timer500ms++; + if (timer500ms >= 5000) { + PORTC ^= (1 << PORTC3); // orange LED blinking + timer500ms = 0; + } +} + diff --git a/software/test_2024-07-23/src/main.hpp b/software/arduino-nano-5v/test_2024-07-23/src/main.hpp similarity index 79% rename from software/test_2024-07-23/src/main.hpp rename to software/arduino-nano-5v/test_2024-07-23/src/main.hpp index de2c1e1..f60ec89 100644 --- a/software/test_2024-07-23/src/main.hpp +++ b/software/arduino-nano-5v/test_2024-07-23/src/main.hpp @@ -2,6 +2,7 @@ #define MAIN_HPP #include +#include #define ENTER '\r' #define CTRLC '\003' @@ -13,7 +14,7 @@ class TestUnit { public: virtual int8_t run (uint8_t subtest) = 0; virtual void cleanup () = 0; - virtual const char *getName () = 0; + virtual PGM_P getName () = 0; }; #endif \ No newline at end of file diff --git a/software/test_2024-07-23/src/units/encoder.cpp b/software/arduino-nano-5v/test_2024-07-23/src/units/encoder.cpp similarity index 91% rename from software/test_2024-07-23/src/units/encoder.cpp rename to software/arduino-nano-5v/test_2024-07-23/src/units/encoder.cpp index 3b8ce8f..bc84f48 100644 --- a/software/test_2024-07-23/src/units/encoder.cpp +++ b/software/arduino-nano-5v/test_2024-07-23/src/units/encoder.cpp @@ -28,7 +28,7 @@ void Encoder::cleanup () { int8_t Encoder::run (uint8_t subtest) { switch (subtest) { case 0: { - printf("init"); + printf_P(PSTR("init")); DDRB &= ~((1 << PB2) | (1 << PB1) | (1 << PB0)); PORTB |= (1 << PORTB2) | (1 << PORTB1) | (1 << PORTB0); // enable pullup enabled = 1; @@ -37,8 +37,8 @@ int8_t Encoder::run (uint8_t subtest) { case 1: { while (wait(10) == EOF) { - printf("\r => Encoder (push to clear): "); - printf("%5d (0x%02x) ", count, (uint8_t)count); + printf_P(PSTR("\r => Encoder (push to clear): ")); + printf_P(PSTR("%5d (0x%02x) "), count, (uint8_t)count); if ((PINB & (1 << PINB2)) == 0) { reset(); } @@ -47,7 +47,7 @@ int8_t Encoder::run (uint8_t subtest) { } case 2: { - printf("\r => Encoder end%30s", " "); + printf_P(PSTR("end")); break; } } diff --git a/software/test_2024-07-23/src/units/encoder.hpp b/software/arduino-nano-5v/test_2024-07-23/src/units/encoder.hpp similarity index 80% rename from software/test_2024-07-23/src/units/encoder.hpp rename to software/arduino-nano-5v/test_2024-07-23/src/units/encoder.hpp index f28584c..10bcc0f 100644 --- a/software/test_2024-07-23/src/units/encoder.hpp +++ b/software/arduino-nano-5v/test_2024-07-23/src/units/encoder.hpp @@ -3,7 +3,7 @@ #include #include "../main.hpp" - +#include class Encoder : public TestUnit { public: @@ -14,7 +14,7 @@ class Encoder : public TestUnit { Encoder () { reset(); enabled = 0; }; virtual void cleanup (); virtual int8_t run (uint8_t subtest); - virtual const char *getName () { return "Encoder"; } + virtual PGM_P getName () { return PSTR("Encoder"); } void reset () { count = 0; } void tick100us (); }; diff --git a/software/test_2024-07-23/src/units/i2c.cpp b/software/arduino-nano-5v/test_2024-07-23/src/units/i2c.cpp similarity index 50% rename from software/test_2024-07-23/src/units/i2c.cpp rename to software/arduino-nano-5v/test_2024-07-23/src/units/i2c.cpp index 64454cd..4c5934f 100644 --- a/software/test_2024-07-23/src/units/i2c.cpp +++ b/software/arduino-nano-5v/test_2024-07-23/src/units/i2c.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include @@ -7,18 +8,17 @@ #include "../adafruit/bme280.h" #include "../main.hpp" - // Sparkfun https://www.sparkfun.com/products/22858 // ENS160 address 0x53 (air quality sensor) // BME280 address 0x77 /humidity/temperature sensor) // register 0xfe: humidity_7:0 // register 0xfd: humidity_15:8 -const char *I2c::getName () { +PGM_P I2c::getName () { switch (mode) { - case SparkFunEnvCombo: return "I2C-Sparkfun Env-Combo"; - case Master: return "I2C-Master"; - case Slave: return "I2C-Slave"; + case SparkFunEnvCombo: return PSTR("I2C-Sparkfun Env-Combo"); + case Master: return PSTR("I2C-Master"); + case Slave: return PSTR("I2C-Slave"); } return "?"; } @@ -40,40 +40,40 @@ int8_t I2c::run (uint8_t subtest) { ADMUX = (1 << ADLAR) | (1 << REFS0); // ADC0, VREF=AVCC=3.3V ADCSRA = (1 << ADEN) | 7; // ADC Enable, Prescaler 128 enabled = true; - printf("init"); + printf_P(PSTR("init")); } else if (subtest == 1 && mode == I2c::SparkFunEnvCombo) { - printf(" BM280 ... "); + printf_P(PSTR(" BM280 ... ")); if (!bm280.begin()) { - printf("ERROR"); + printf_P(PSTR("E1")); return -1; } - printf("OK, ENS160 ... "); + printf_P(PSTR("OK, ENS160 ... ")); if (!ens160.begin()) { - printf("ERROR"); + printf_P(PSTR("E2")); return -1; } if (!ens160.setMode(ENS160_OPMODE_STD)) { - printf("ERROR"); + printf_P(PSTR("E3")); return -1; } if (!ens160.set_envdata(25.0, 65)) { - printf("ERROR"); + printf_P(PSTR("E4")); return -1; } - printf("OK"); + printf_P(PSTR("OK")); float accTemp = 0, accHumidity = 0; int8_t accCount = -1; do { // BME280 float p = bm280.readPressure(); - printf("\n => BM280: P= %.3fbar", (double)p / 100000.0); + printf_P(PSTR("\n => BM280: P= %.3fbar"), (double)p / 100000.0); float t = bm280.readTemperature(); - printf(", T= %.2f°C", (double)t); + printf_P(PSTR(", T= %.2f°C"), (double)t); float h = bm280.readHumidity(); - printf(", H= %.2f%%", (double)h); + printf_P(PSTR(", H= %.2f%%"), (double)h); if (accCount >= 0 && !isnanf(h) && !isnan(t)) { accTemp += t; @@ -95,7 +95,7 @@ int8_t I2c::run (uint8_t subtest) { // -> ES160 has not enough distance to BM280 // This solution causes only a +0.3°C higher temperatur value if (accCount < 0 || accCount >= 32) { - printf(" | ENS160 ("); + printf_P(PSTR(" | ENS160 (")); if (accCount > 0) { h = accHumidity / accCount; t = accTemp / accCount; @@ -104,11 +104,11 @@ int8_t I2c::run (uint8_t subtest) { } accCount = 0; if (!ens160.set_envdata(t, h)) { - printf("E1)"); + printf_P(PSTR("E1)")); } else { - printf("%.1f°C/%.1f%%): ", (double)t, (double)h); + printf_P(PSTR("%.1f°C/%.1f%%): "), (double)t, (double)h); if (!ens160.setMode(ENS160_OPMODE_STD)) { - printf("E2"); + printf_P(PSTR("E2")); } else { for (uint8_t i = 0; i < 100; i++) { _delay_ms(15); @@ -117,31 +117,31 @@ int8_t I2c::run (uint8_t subtest) { if (status & ENS160_DATA_STATUS_NEWDAT) { ENS160_DATA data; if (ens160.readData(&data)) { - printf(" aqi=%d(", data.aqi); + printf_P(PSTR(" aqi=%d("), data.aqi); switch(data.aqi) { - case 1: printf("excellent"); break; - case 2: printf("good"); break; - case 3: printf("moderate"); break; - case 4: printf("poor"); break; - case 5: printf("unhealthy"); break; - default: printf("?"); break; + case 1: printf_P(PSTR("excellent")); break; + case 2: printf_P(PSTR("good")); break; + case 3: printf_P(PSTR("moderate")); break; + case 4: printf_P(PSTR("poor")); break; + case 5: printf_P(PSTR("unhealthy")); break; + default: printf_P(PSTR("?")); break; } - printf("), tvoc=%dppb", data.tvoc); - printf(", eco2=%d(", data.eco2); + printf_P(PSTR("), tvoc=%dppb"), data.tvoc); + printf_P(PSTR(", eco2=%d("), data.eco2); if (data.eco2 < 400) { - printf("?"); + printf_P(PSTR("?")); } else if (data.eco2 < 600) { - printf("excellent"); + printf_P(PSTR("excellent")); } else if (data.eco2 < 800) { - printf("good"); + printf_P(PSTR("good")); } else if (data.eco2 < 1000) { - printf("fair"); + printf_P(PSTR("fair")); } else if (data.eco2 < 1500) { - printf("poor"); + printf_P(PSTR("poor")); } else { - printf("dad"); + printf_P(PSTR("bad")); } - printf(")"); + printf_P(PSTR(")")); } break; } @@ -149,7 +149,7 @@ int8_t I2c::run (uint8_t subtest) { } } if (!ens160.setMode(ENS160_OPMODE_IDLE)) { - printf("E3"); + printf_P(PSTR("E3")); } } } @@ -158,7 +158,7 @@ int8_t I2c::run (uint8_t subtest) { } else if (subtest == 1 && mode == I2c::Master) { if (!master.begin(0x01)) { - printf("E1"); + printf_P(PSTR("E1")); return -1; } do { @@ -167,22 +167,22 @@ int8_t I2c::run (uint8_t subtest) { ADCSRA |= (1 << ADSC); // start ADC while (ADCSRA & (1 << ADSC)) {} // wait for result buffer[0] = ADCH; - printf("\n write 0x%02x", buffer[0]); + printf_P(PSTR("\n write 0x%02x"), buffer[0]); if (!master.write(buffer, 1)) { - printf(" -> ERROR"); + printf_P(PSTR(" -> ERROR")); } - printf(", read "); + printf_P(PSTR(", read ")); if (master.read(buffer, 1)) { - printf("0x%02x", buffer[0]); + printf_P(PSTR("0x%02x"), buffer[0]); } else { - printf(" -> ERROR"); + printf_P(PSTR(" -> ERROR")); } } while (wait(1000) == EOF); master.end(); } else if (subtest == 1 && mode == I2c::Slave) { if (!slave.begin(0x01, false)) { - printf("E1"); + printf_P(PSTR("E1")); return -1; } do { @@ -191,13 +191,13 @@ int8_t I2c::run (uint8_t subtest) { ADCSRA |= (1 << ADSC); // start ADC while (ADCSRA & (1 << ADSC)) {} // wait for result slave.write(ADCH); - printf("\n => from master: 0x%02x -> to master: 0x%02x", fromMaster, ADCH); + printf_P(PSTR("\n => from master: 0x%02x -> to master: 0x%02x"), fromMaster, ADCH); } } while (wait(0) == EOF); slave.end(); } else { - printf("end"); + printf_P(PSTR("end")); return -1; } wait(500); @@ -215,86 +215,86 @@ void I2c::handleTwiIrq () { } } -uint16_t I2c::startRead (uint8_t address) { - TWCR = (1 << TWINT) | (1 << TWSTA) | (1 << TWEN); // send START condition - while (!(TWCR & (1 << TWINT))) {}; // wait until last action done - uint8_t sr = TWSR & 0xf8; - if (sr != 0x08 && sr != 0x10) { - return 0x0100 | sr; - } +// uint16_t I2c::startRead (uint8_t address) { +// TWCR = (1 << TWINT) | (1 << TWSTA) | (1 << TWEN); // send START condition +// while (!(TWCR & (1 << TWINT))) {}; // wait until last action done +// uint8_t sr = TWSR & 0xf8; +// if (sr != 0x08 && sr != 0x10) { +// return 0x0100 | sr; +// } - TWDR = (address << 1) | 0x01; // address + READ (R/W = 1) - TWCR = (1 << TWINT) | (1 << TWEN); // send address/RW - while (!(TWCR & (1 << TWINT))) {}; // wait until last action done - sr = TWSR & 0xf8; - if (sr != 0x40) { - return 0x0200 | sr; - } - return 0; -} +// TWDR = (address << 1) | 0x01; // address + READ (R/W = 1) +// TWCR = (1 << TWINT) | (1 << TWEN); // send address/RW +// while (!(TWCR & (1 << TWINT))) {}; // wait until last action done +// sr = TWSR & 0xf8; +// if (sr != 0x40) { +// return 0x0200 | sr; +// } +// return 0; +// } -uint16_t I2c::startWrite (uint8_t address) { - TWCR = (1 << TWINT) | (1 << TWSTA) | (1 << TWEN); // send START condition - while (!(TWCR & (1 << TWINT))) {}; // wait until last action done - uint8_t sr = TWSR & 0xf8; - if (sr != 0x08 && sr != 0x10) { - return 0x0300 | sr; - } +// uint16_t I2c::startWrite (uint8_t address) { +// TWCR = (1 << TWINT) | (1 << TWSTA) | (1 << TWEN); // send START condition +// while (!(TWCR & (1 << TWINT))) {}; // wait until last action done +// uint8_t sr = TWSR & 0xf8; +// if (sr != 0x08 && sr != 0x10) { +// return 0x0300 | sr; +// } - TWDR = (address << 1) | 0x00; // address + WRITE (R/W = 0) - TWCR = (1 << TWINT) | (1 << TWEN); // send address/RW - while (!(TWCR & (1 << TWINT))) {}; // wait until last action done - sr = TWSR & 0xf8; - if (sr != 0x18) { - return 0x0400 | sr; - } - return 0; -} +// TWDR = (address << 1) | 0x00; // address + WRITE (R/W = 0) +// TWCR = (1 << TWINT) | (1 << TWEN); // send address/RW +// while (!(TWCR & (1 << TWINT))) {}; // wait until last action done +// sr = TWSR & 0xf8; +// if (sr != 0x18) { +// return 0x0400 | sr; +// } +// return 0; +// } -void I2c::stop () { - TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWSTO); -} +// void I2c::stop () { +// TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWSTO); +// } -uint16_t I2c::writeData (uint8_t size, const uint8_t *data) { - while (size-- > 0) { - TWDR = *data++; - TWCR = (1 << TWINT) | (1 << TWEN); // send data byte - while (!(TWCR & (1 << TWINT))) {}; // wait until last action done - uint8_t sr = TWSR & 0xf8; - if (sr != 0x28) { - return 0x0500 | sr; - } - } - return 0; -} +// uint16_t I2c::writeData (uint8_t size, const uint8_t *data) { +// while (size-- > 0) { +// TWDR = *data++; +// TWCR = (1 << TWINT) | (1 << TWEN); // send data byte +// while (!(TWCR & (1 << TWINT))) {}; // wait until last action done +// uint8_t sr = TWSR & 0xf8; +// if (sr != 0x28) { +// return 0x0500 | sr; +// } +// } +// return 0; +// } -uint16_t I2c::writeByte (uint8_t data) { - return writeData(1, &data); -} +// uint16_t I2c::writeByte (uint8_t data) { +// return writeData(1, &data); +// } -uint16_t I2c::readData (uint8_t size, uint8_t *data) { - while (size-- > 0) { - if (size > 0) { - TWCR = (1 << TWEA) | (1 << TWINT) | (1 << TWEN); // read data byte with ACK enabled - } else { - TWCR = (1 << TWINT) | (1 << TWEN); // read data byte with ACK disabled - } - while (!(TWCR & (1 << TWINT))) {}; // wait until last action done - uint8_t sr = TWSR & 0xf8; - if ((size > 0 && sr != 0x50) || (size == 0 && sr != 0x58)) { - return 0x0600 | sr; - } - *data++ = TWDR; - } - return 0; -} +// uint16_t I2c::readData (uint8_t size, uint8_t *data) { +// while (size-- > 0) { +// if (size > 0) { +// TWCR = (1 << TWEA) | (1 << TWINT) | (1 << TWEN); // read data byte with ACK enabled +// } else { +// TWCR = (1 << TWINT) | (1 << TWEN); // read data byte with ACK disabled +// } +// while (!(TWCR & (1 << TWINT))) {}; // wait until last action done +// uint8_t sr = TWSR & 0xf8; +// if ((size > 0 && sr != 0x50) || (size == 0 && sr != 0x58)) { +// return 0x0600 | sr; +// } +// *data++ = TWDR; +// } +// return 0; +// } -int32_t I2c::compensateBm280T (int32_t adcT) { - // int32_t var1, var2, t; - // var1 = ((((adcT >> 3) - ((int32_t)bm280.digT[0] << 1))) * ((int32_t)bm280.digT[1])) >> 11; - // var2 = (((((adcT >> 4) - ((int32_t)bm280.digT[0])) * ((adcT >> 4) - ((int32_t)bm280.digT[0]))) >> 12) * ((int32_t)bm280.digT[2])) >> 14; - // bm280.tFine = var1 + var2; - // t = (bm280.tFine * 5 + 128) >> 8; - // return t; - return -1; -} \ No newline at end of file +// int32_t I2c::compensateBm280T (int32_t adcT) { +// // int32_t var1, var2, t; +// // var1 = ((((adcT >> 3) - ((int32_t)bm280.digT[0] << 1))) * ((int32_t)bm280.digT[1])) >> 11; +// // var2 = (((((adcT >> 4) - ((int32_t)bm280.digT[0])) * ((adcT >> 4) - ((int32_t)bm280.digT[0]))) >> 12) * ((int32_t)bm280.digT[2])) >> 14; +// // bm280.tFine = var1 + var2; +// // t = (bm280.tFine * 5 + 128) >> 8; +// // return t; +// return -1; +// } diff --git a/software/test_2024-07-23/src/units/i2c.hpp b/software/arduino-nano-5v/test_2024-07-23/src/units/i2c.hpp similarity index 95% rename from software/test_2024-07-23/src/units/i2c.hpp rename to software/arduino-nano-5v/test_2024-07-23/src/units/i2c.hpp index b439038..e1f1802 100644 --- a/software/test_2024-07-23/src/units/i2c.hpp +++ b/software/arduino-nano-5v/test_2024-07-23/src/units/i2c.hpp @@ -28,7 +28,7 @@ class I2c : public TestUnit { void tick1ms () { master.tick1ms(); slave.tick1ms(); } virtual void cleanup (); virtual int8_t run (uint8_t subtest); - virtual const char *getName (); + virtual PGM_P getName (); void handleTwiIrq (); uint16_t startRead (uint8_t address); uint16_t startWrite (uint8_t address); diff --git a/software/arduino-nano-5v/test_2024-07-23/src/units/ieee485.cpp b/software/arduino-nano-5v/test_2024-07-23/src/units/ieee485.cpp new file mode 100644 index 0000000..414efb2 --- /dev/null +++ b/software/arduino-nano-5v/test_2024-07-23/src/units/ieee485.cpp @@ -0,0 +1,110 @@ +#include +#include +#include +#include + +#include "ieee485.hpp" +#include "../main.hpp" + +#ifdef __AVR_ATmega328P__ + +// Nano-328P +// ------------------------------------ +// IEE485 not supported (no UART1) + +void Ieee485::cleanup () {} +int8_t Ieee485::run (uint8_t subtest) { + return -1; +} + +#endif + + +#ifdef __AVR_ATmega644P__ + +// Nano-644 +// ------------------------------------ +// PB0 ... nRE .. Read enable +// PB1 ... DE .. Data enable + +#define SET_nRE (PORTB |= (1 << PB0)) +#define CLR_nRE (PORTB &= ~(1 << PB0)) +#define SET_DE (PORTB |= (1 << PB1)) +#define CLR_DE (PORTB &= ~(1 << PB1)) + +void Ieee485::cleanup () { + enabled = 0; + + ADMUX = 0; + ADCSRA = 0; + + UCSR1A = 0; + UCSR1B = 0; + UCSR1C = 0; + UBRR1H = 0; + UBRR1L = 0; + PORTD &= ~(1 << PD2); + DDRB &= ~((1 << PB1) | (1 << PB0)); + PORTB &= ~((1 << PB1) | (1 << PB0)); +} + +int8_t Ieee485::run (uint8_t subtest) { + if (subtest == 0) { + // Poti + ADMUX = (1 << ADLAR) | (1 << REFS0); // ADC0, VREF=AVCC=3.3V + ADCSRA = (1 << ADEN) | 7; // ADC Enable, Prescaler 128 + + // Modbus + SET_nRE; + CLR_DE; + DDRB |= (1 << PB1) | (1 << PB0); + + // UART1 interface on Nano-644 + PORTD |= (1 << PD2); // enable RxD1 pullup + UCSR1A = (1 << U2X1); + UCSR1B = (1 << RXCIE1) | (1 << RXEN1) | (1 < send Byte 0x%02x"), ADCH); + int b; + ATOMIC_BLOCK(ATOMIC_FORCEON) { + b = receivedByte; + receivedByte = -1; + } + if (b >= 0) { + printf_P(PSTR("\n => receive Byte: 0x%02x"), b); + } + } + + } else { + printf_P(PSTR("end")); + return -1; + } + + return 0; +} + +void Ieee485::handleRxByte (uint8_t b) { + receivedByte = b; +} + +#endif \ No newline at end of file diff --git a/software/test_2024-07-23/src/units/ieee485.hpp b/software/arduino-nano-5v/test_2024-07-23/src/units/ieee485.hpp similarity index 78% rename from software/test_2024-07-23/src/units/ieee485.hpp rename to software/arduino-nano-5v/test_2024-07-23/src/units/ieee485.hpp index d72f337..677963f 100644 --- a/software/test_2024-07-23/src/units/ieee485.hpp +++ b/software/arduino-nano-5v/test_2024-07-23/src/units/ieee485.hpp @@ -3,6 +3,7 @@ #include #include "../main.hpp" +#include class Ieee485 : public TestUnit { public: @@ -13,7 +14,7 @@ class Ieee485 : public TestUnit { Ieee485 () { enabled = 0; receivedByte = -1; } virtual void cleanup (); virtual int8_t run (uint8_t subtest); - virtual const char *getName () { return "IEEE485"; } + virtual const char *getName () { return PSTR("IEEE485"); } void handleRxByte (uint8_t); }; diff --git a/software/arduino-nano-5v/test_2024-07-23/src/units/lcd.cpp b/software/arduino-nano-5v/test_2024-07-23/src/units/lcd.cpp new file mode 100644 index 0000000..fa24879 --- /dev/null +++ b/software/arduino-nano-5v/test_2024-07-23/src/units/lcd.cpp @@ -0,0 +1,257 @@ +#include +#include +#include + +#include "lcd.hpp" +#include "../main.hpp" + +#ifdef __AVR_ATmega644P__ + + // Nano-644 + // --------------------------------------------------------------- + // PA3 ..... E --> LCD Enable (Verbindung via J25 erforderlich) + // PD6 ..... R/W --> Read/Write: Read=1, Write=0 + // PD7 ..... RS --> Register Select: Command=0, Data=1 + // PB7:0 ... Data --> Achtung von 5V LCD nicht lesen! + + + // #define LCD_3V3 + #ifdef LCD_3V3 + #define DATA_PIN PINB + #endif + + void Lcd::initDDR () { + DDRA |= (1 << PA3); + DDRB = 0xff; + DDRD |= (1 << PD7) | (1 << PD6); + } + + void Lcd::cleanup () { + DDRA &= ~(1 << PA3); + DDRB = 0; + DDRD &= ~((1 << PD7) | (1 << PD6)); + } + + void Lcd::setRS () { PORTD |= (1 << PD7); } + void Lcd::clrRS () { PORTD &= ~(1 << PD7); } + void Lcd::setRW () { PORTD |= (1 << PD6); } + void Lcd::clrRW () { PORTD &= ~(1 << PD6); } + void Lcd::setE () { PORTA |= (1 << PA3); } + void Lcd::clrE () { PORTA &= ~(1 << PA3); } + + void Lcd::setData (uint8_t data) { + PORTB = data; + } +#endif + +#ifdef __AVR_ATmega328P__ + + // Arduino Nano (5V) + // --------------------------------------------------------------- + // PC3 ..... E --> LCD Enable (Verbindung via J25 erforderlich) + // PD3 ..... R/W --> Read/Write: Read=1, Write=0 + // PD2 ..... RS --> Register Select: Command=0, Data=1 + // PD4 ..... Data0 + // PB0 ..... Data1 + // PD7 ..... Data2 + // PD6 ..... Data3 + // PB2 ..... Data4 + // PB3 ..... Data5 + // PB4 ..... Data6 + // PB5 ..... Data7 + + void Lcd::initDDR () { + DDRB |= (1 << PB5) | (1 << PB4) | (1 << PB3) | (1 << PB2) | (1 << PB0); + DDRD |= (1 << PD7) | (1 << PD6) | (1 << PD4) | (1 << PD3) | (1 << PD2); + } + + void Lcd::cleanup () { + DDRB &= ~((1 << PB5) | (1 << PB4) | (1 << PB3) | (1 << PB2) | (1 << PB0)); + DDRD &= ~((1 << PD7) | (1 << PD6) | (1 << PD4) | (1 << PD3) | (1 << PD2)); + } + + void Lcd::setRS () { PORTD |= (1 << PD2); } + void Lcd::clrRS () { PORTD &= ~(1 << PD2); } + void Lcd::setRW () { PORTD |= (1 << PD3); } + void Lcd::clrRW () { PORTD &= ~(1 << PD3); } + void Lcd::setE () { PORTC |= (1 << PC3); } + void Lcd::clrE () { PORTC &= ~(1 << PC3); } + + void Lcd::setData (uint8_t data) { + if (data & 0x01) PORTD |= (1 << PD4); else PORTD &= ~((1 << PD4)); + if (data & 0x02) PORTB |= (1 << PB0); else PORTB &= ~((1 << PB0)); + if (data & 0x04) PORTD |= (1 << PD7); else PORTD &= ~((1 << PD7)); + if (data & 0x08) PORTD |= (1 << PD6); else PORTD &= ~((1 << PD6)); + if (data & 0x10) PORTB |= (1 << PB2); else PORTB &= ~((1 << PB2)); + if (data & 0x20) PORTB |= (1 << PB3); else PORTB &= ~((1 << PB3)); + if (data & 0x40) PORTB |= (1 << PB4); else PORTB &= ~((1 << PB4)); + if (data & 0x80) PORTB |= (1 << PB5); else PORTB &= ~((1 << PB5)); + } +#endif + +// Befehle für das Display + +#define DISP_CLEAR 0b00000001 // Display clear +#define DISP_ON 0b00001111 // Display on +#define DISP_OFF 0b00001011 // Display off +#define CURSOR_ON 0b00001111 // Cursor on +#define CURSOR_OFF 0b00001101 // Cursor off +#define BLINK_ON 0b00001111 // Cursor Blink +#define BLINK_OFF 0b00001110 // Cursor No Blink + +int8_t Lcd::run (uint8_t subtest) { + if (subtest == 0) { + init(); + #ifdef LCD_3V3 + printf_P(PSTR("init 3.3V LCD")); + #else + printf_P(PSTR("init 5V LCD")); + #endif + + } else if (subtest == 1) { + for (uint8_t i = 0; i < 20 * 4; i++) { + char c = (char)(i + 32); + if (i % 20 == 0) { + setCursor(i / 20 + 1, 1); + } + writeData(c); + while (isBusy()) {}; + } + // setCursor(1, 1); + // writeString(" 1234567890<>,;.:-_#+"); + // setCursor(2, 1); + // writeString("abcdefghijklmnopqrst"); + // setCursor(3, 1); + // writeString("uvwxyzABCDEFGHIJKLMN"); + // setCursor(4, 1); + // writeString("OPQRSTUVWXYZ "); + printf_P(PSTR("LCD beschrieben")); + while (wait(1) == EOF) { + } + + } else { + printf_P(PSTR("end")); + return -1; + } + wait(500); + return 0; +} + +void Lcd::init () { + clrRW(); + clrRS(); + clrE(); + setData(0); + initDDR(); + _delay_ms(16); // min 15ms warten für Reset des Displays + + setData( 0b00111011 ); // 8bit Modus, 5x7 Zeichen, Mehrzeilen Display + clrRW(); // write + clrRS(); // command + setE(); // E = 1 (transfer start) + _delay_us(10); // min. 10us + clrE(); // E = 0 (transfer end) + _delay_ms(5); // min. 4.1ms + + setData( 0b00111011 ); // 8bit Modus, 5x7 Zeichen, Mehrzeilen Display + clrRW(); // write + clrRS(); // command + setE(); // E = 1 (transfer start) + _delay_us(10); // min. 10us + clrE(); // E = 0 (transfer end) + _delay_us(100); // min. 100us + + setData( 0b00111011 ); // 8bit Modus, 5x7 Zeichen, Mehrzeilen Display + clrRW(); // write + clrRS(); // command + setE(); // E = 1 (transfer start) + _delay_us(10); // min. 10us + clrE(); // E = 0 (transfer end) + _delay_us(100); // min. 100us + + writeCommand(DISP_OFF); // Display aus + while(isBusy()) {}; + writeCommand(DISP_ON); // Display ein + while(isBusy()) {}; + writeCommand( BLINK_OFF & CURSOR_OFF); // Blink aus und Cursor aus + while(isBusy()) {}; + writeCommand(DISP_CLEAR);// Clear display + while(isBusy()) {}; +} + +uint8_t Lcd::isBusy () { + #ifdef LCD_3V3 + // DIR_DATA_PORT = 0; + // SET_RW_PIN; // read + // CLR_RS_PIN; // command + // SET_E_PIN; // E = 1 (transfer start) + // _delay_us(10); + // uint8_t busy = DATA_PIN & 0x80; // read bit 7 (busy bit) + // CLR_E_PIN; // E = 0 (transfer end) + // CLR_RW_PIN; + // DIR_DATA_PORT = 0xff; + // return busy != 0; + _delay_us(200); + return 0; + #else + _delay_us(200); + return 0; + #endif + +} + +void Lcd::writeCommand (uint8_t cmd) { + setData(cmd); + clrRW(); // write + clrRS(); // command + setE(); // E = 1 (transfer start) + _delay_us(10); // min. 10us + clrE(); // E = 0 (transfer end) + writeData(0); +} + +void Lcd::setDDRamAddr (uint8_t address) { + setData(address | 0x80); + clrRW(); // write + clrRS(); // command + setE(); // E = 1 (transfer start) + _delay_us(10); // min. 10us + clrE(); // E = 0 (transfer end) + _delay_us(10); // min. 10us + writeData(0); +} + +void Lcd::writeString (const char *s) { + while (*s) { + writeData(*s++); + while (isBusy()) {}; + } +} + +void Lcd::writeData (uint8_t data) { + setData(data); + setRS(); // data + clrRW(); // write + setE(); // E = 1 (transfer start) + _delay_us(10); // min. 10us + clrE(); // E = 0 (transfer end) + _delay_us(10); // min. 10us + clrRS(); + writeData(0); +} + +void Lcd::setCursor (uint8_t row, uint8_t column) { + uint8_t b; + if (column > 20) { + return; + } + switch (row) { + case 1: b = 0x00 + column - 1; break; + case 2: b = 0x40 + column - 1; break; + case 3: b = 0x14 + column - 1; break; + case 4: b = 0x54 + column - 1; break; + default: return; + } + setDDRamAddr(b); + while (isBusy()) {}; +} diff --git a/software/arduino-nano-5v/test_2024-07-23/src/units/lcd.hpp b/software/arduino-nano-5v/test_2024-07-23/src/units/lcd.hpp new file mode 100644 index 0000000..142a13f --- /dev/null +++ b/software/arduino-nano-5v/test_2024-07-23/src/units/lcd.hpp @@ -0,0 +1,34 @@ +#ifndef LCD_HPP +#define LCD_HPP + +#include +#include "../main.hpp" +#include + +class Lcd : public TestUnit { + public: + Lcd () {}; + virtual void cleanup (); + virtual int8_t run (uint8_t subtest); + virtual PGM_P getName () { return PSTR("Lcd"); } + + private: + void init (); + void initDDR (); + uint8_t isBusy (); + void writeCommand (uint8_t); + void setDDRamAddr (uint8_t); + void writeString (const char *s); + void writeData (uint8_t); + void setCursor (uint8_t row, uint8_t column); + void setRS (); + void clrRS (); + void setRW (); + void clrRW (); + void setE (); + void clrE (); + void setData (uint8_t data); + +}; + +#endif \ No newline at end of file diff --git a/software/arduino-nano-5v/test_2024-07-23/src/units/led.cpp b/software/arduino-nano-5v/test_2024-07-23/src/units/led.cpp new file mode 100644 index 0000000..6dc6253 --- /dev/null +++ b/software/arduino-nano-5v/test_2024-07-23/src/units/led.cpp @@ -0,0 +1,134 @@ +#include +#include +#include + +#include "led.hpp" +#include "../main.hpp" + +#ifdef __AVR_ATmega644P__ + + // Nano-644 + // --------------------------------------------------------------- + // PD4 ..... Red + // PD5 ..... Orange/Yellow + // PD6 ..... Green + // PD7 ..... Blue + + void Led::initDDR () { + DDRD |= (1 << PD7) | (1 << PD6) | (1 << PD5) | (1 << PD4); + } + + void Led::cleanup () { + DDRD &= ~((1 << PD7) | (1 << PD6) | (1 << PD5) | (1 << PD4)); + PORTD &= ~((1 << PD7) | (1 << PD6) | (1 << PD5) | (1 << PD4)); + } + + void Led::setLed (LED led, bool on) { + if (on) { + switch(led) { + case RED: PORTD |= (1 << PD4); break; + case ORANGE: PORTD |= (1 << PD5); break; + case GREEN: PORTD |= (1 << PD6); break; + case BLUE: PORTD |= (1 << PD7); break; + } + } else { + switch(led) { + case RED: PORTD &= ~(1 << PD4); break; + case ORANGE: PORTD &= ~(1 << PD5); break; + case GREEN: PORTD &= ~(1 << PD6); break; + case BLUE: PORTD &= ~(1 << PD7); break; + } + } + } + + void Led::ledToggle (LED led) { + case RED: PORTD ^= (1 << PD4); break; + case ORANGE: PORTD ^= (1 << PD5); break; + case GREEN: PORTD ^= (1 << PD6); break; + case BLUE: PORTD ^= (1 << PD7); break; + } + +#endif + +#ifdef __AVR_ATmega328P__ + + // Arduino-Nano-5V + // --------------------------------------------------------------- + // PD5 ..... Red + // PB1 ..... Orange/Yellow + // PD3 ..... Green + // PD2 ..... Blue + + void Led::initDDR () { + DDRD |= (1 << PD5) | (1 << PD3) | (1 << PD2); + DDRB |= (1 << PB1); + } + + void Led::cleanup () { + DDRD &= ~((1 << PD5) | (1 << PD3) | (1 << PD2)); + DDRB &= ~(1 << PB1); + PORTD &= ~((1 << PD5) | (1 << PD3) | (1 << PD2)); + PORTB &= ~(1 << PB1); + } + + void Led::setLed (LED led, bool on) { + if (on) { + switch(led) { + case RED: PORTD |= (1 << PD5); break; + case ORANGE: PORTB |= (1 << PB1); break; + case GREEN: PORTD |= (1 << PD3); break; + case BLUE: PORTD |= (1 << PD2); break; + } + } else { + switch(led) { + case RED: PORTD &= ~(1 << PD5); break; + case ORANGE: PORTB &= ~(1 << PB1); break; + case GREEN: PORTD &= ~(1 << PD3); break; + case BLUE: PORTD &= ~(1 << PD2); break; + } + } + } + + void Led::ledToggle (LED led) { + switch(led) { + case RED: PORTD ^= (1 << PD5); break; + case ORANGE: PORTB ^= (1 << PB1); break; + case GREEN: PORTD ^= (1 << PD3); break; + case BLUE: PORTD ^= (1 << PD2); break; + } + } + +#endif + +void Led::ledOn (LED led) { + setLed(led, true); +} + +void Led::ledOff (LED led) { + setLed(led, false); +} + + +int8_t Led::run (uint8_t subtest) { + if (subtest == 0) { + initDDR(); + printf_P(PSTR("init")); + + } else if (subtest <= 16) { + subtest = (subtest - 1) % 4; + switch (subtest) { + case 0: ledOff(BLUE); ledOn(RED); break; + case 1: ledOff(RED); ledOn(ORANGE); break; + case 2: ledOff(ORANGE); ledOn(GREEN); break; + case 3: ledOff(GREEN); ledOn(BLUE); break; + } + printf_P(PSTR("Test LED PD%d"), subtest + 4); + + } else { + printf_P(PSTR("end")); + return -1; + } + wait(500); + return 0; +} + diff --git a/software/arduino-nano-5v/test_2024-07-23/src/units/led.hpp b/software/arduino-nano-5v/test_2024-07-23/src/units/led.hpp new file mode 100644 index 0000000..0a28f2d --- /dev/null +++ b/software/arduino-nano-5v/test_2024-07-23/src/units/led.hpp @@ -0,0 +1,28 @@ +#ifndef LED_HPP +#define LED_HPP + +#include +#include "../main.hpp" +#include + +class Led : public TestUnit { + public: + enum LED { RED, ORANGE, GREEN, BLUE }; + + + public: + Led () {}; + virtual void cleanup (); + virtual int8_t run (uint8_t subtest); + virtual PGM_P getName () { return PSTR("Led"); } + + void setLed (LED led, bool on); + void ledOn (LED led); + void ledOff (LED led); + void ledToggle (LED led); + + private: + void initDDR (); +}; + +#endif \ No newline at end of file diff --git a/software/nano-644/test_2024-07-23/.gdb_history b/software/nano-644/test_2024-07-23/.gdb_history new file mode 100644 index 0000000..3339046 --- /dev/null +++ b/software/nano-644/test_2024-07-23/.gdb_history @@ -0,0 +1,9 @@ +target remote :1234 +layout split +stepi +quit +target remote :1234 +layout split +stepi +b *main+9 +quit diff --git a/software/nano-644/test_2024-07-23/.gdbinit b/software/nano-644/test_2024-07-23/.gdbinit new file mode 100644 index 0000000..139597f --- /dev/null +++ b/software/nano-644/test_2024-07-23/.gdbinit @@ -0,0 +1,2 @@ + + diff --git a/software/nano-644/test_2024-07-23/.gitignore b/software/nano-644/test_2024-07-23/.gitignore new file mode 100644 index 0000000..a959910 --- /dev/null +++ b/software/nano-644/test_2024-07-23/.gitignore @@ -0,0 +1,4 @@ +.depend +**/build +**/dist +**/sim diff --git a/software/test_2024-07-23/.vscode/c_cpp_properties.json b/software/nano-644/test_2024-07-23/.vscode/c_cpp_properties.json similarity index 100% rename from software/test_2024-07-23/.vscode/c_cpp_properties.json rename to software/nano-644/test_2024-07-23/.vscode/c_cpp_properties.json diff --git a/software/nano-644/test_2024-07-23/.vscode/launch.json b/software/nano-644/test_2024-07-23/.vscode/launch.json new file mode 100644 index 0000000..f29cf2e --- /dev/null +++ b/software/nano-644/test_2024-07-23/.vscode/launch.json @@ -0,0 +1,37 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Build", + // "request": "launch", + "type": "node-terminal", + "preLaunchTask": "build" + },{ + "name": "Flash", + // "request": "launch", + "type": "node-terminal", + "preLaunchTask": "flash" + },{ + "name": "Clean", + // "request": "launch", + "type": "node-terminal", + "preLaunchTask": "clean" + },{ + // es muss mit simuc --board arduino dist/programm.elf der Simulator + // gestartet werden. Dessen gdb-stub öffnet auf localhost:1234 einen Port + "name": "Debug (simuc)", + "type": "cppdbg", + "request": "launch", + "program": "${workspaceFolder}/sim/atmega328p.elf", + "cwd": "${workspaceFolder}", + "externalConsole": false, + "MIMode": "gdb", + "miDebuggerPath": "/usr/bin/avr-gdb", + "miDebuggerServerAddress": ":1234", + "preLaunchTask": "build" + } + ] +} diff --git a/software/nano-644/test_2024-07-23/.vscode/settings.json b/software/nano-644/test_2024-07-23/.vscode/settings.json new file mode 100644 index 0000000..b2e94c9 --- /dev/null +++ b/software/nano-644/test_2024-07-23/.vscode/settings.json @@ -0,0 +1,26 @@ +{ + "[c]": { + "editor.insertSpaces": true, + "editor.tabSize": 3, + "editor.detectIndentation": false + }, + "[cpp]": { + "editor.insertSpaces": true, + "editor.tabSize": 3, + "editor.detectIndentation": false + }, + "[h]": { + "editor.insertSpaces": true, + "editor.tabSize": 3, + "editor.detectIndentation": false + }, + "[hpp]": { + "editor.insertSpaces": true, + "editor.tabSize": 3, + "editor.detectIndentation": false + }, + "cSpell.words": [], + "cSpell.ignorePaths": [ + "**/*.json", "**/*.c", "**/*.h", "**/*.cpp", "**/*.hpp", "**/Makefile" + ] +} diff --git a/software/nano-644/test_2024-07-23/.vscode/tasks.json b/software/nano-644/test_2024-07-23/.vscode/tasks.json new file mode 100644 index 0000000..74fb1c7 --- /dev/null +++ b/software/nano-644/test_2024-07-23/.vscode/tasks.json @@ -0,0 +1,23 @@ +{ + // See https://go.microsoft.com/fwlink/?LinkId=733558 + // for the documentation about the tasks.json format + "version": "2.0.0", + "tasks": [{ + "label": "build", + "type": "shell", + "command": "make", + "problemMatcher":[ + "$gcc" + ] + },{ + "label": "clean", + "type": "shell", + "command": "make", + "args": [ "clean" ], + },{ + "label": "flash", + "type": "shell", + "command": "make", + "args": [ "flash" ], + }] +} \ No newline at end of file diff --git a/software/test_2024-07-23/Makefile b/software/nano-644/test_2024-07-23/Makefile similarity index 100% rename from software/test_2024-07-23/Makefile rename to software/nano-644/test_2024-07-23/Makefile diff --git a/software/nano-644/test_2024-07-23/README.md b/software/nano-644/test_2024-07-23/README.md new file mode 100644 index 0000000..c4d5e14 --- /dev/null +++ b/software/nano-644/test_2024-07-23/README.md @@ -0,0 +1 @@ +# Testprogramm diff --git a/software/nano-644/test_2024-07-23/src/adafruit/bme280.cpp b/software/nano-644/test_2024-07-23/src/adafruit/bme280.cpp new file mode 100644 index 0000000..95a0f49 --- /dev/null +++ b/software/nano-644/test_2024-07-23/src/adafruit/bme280.cpp @@ -0,0 +1,512 @@ +#include "bme280.h" +#include +#include + +Adafruit_BME280 theBME280; +Adafruit_BME280_Temp bm280TempSensor; +Adafruit_BME280_Pressure bm280PressureSensor; +Adafruit_BME280_Humidity bm280HumiditySensor; + +Adafruit_BME280::Adafruit_BME280() { + static I2cMaster i2cDevice; + t_fine_adjust = 0; + temp_sensor = &bm280TempSensor; + pressure_sensor = &bm280PressureSensor; + humidity_sensor = &bm280HumiditySensor; + i2c_dev = &i2cDevice; +} + +bool Adafruit_BME280::begin (uint8_t addr) { + if (!i2c_dev->begin(addr)) { + return false; + } + return init(); +} + +bool Adafruit_BME280::init() { + _sensorID = read8(BME280_REGISTER_CHIPID); + if (_sensorID != 0x60) { + return false; + } + write8(BME280_REGISTER_SOFTRESET, 0xB6); + _delay_ms(10); // wait for chip to wake up. + + // if chip is still reading calibration, delay + while (isReadingCalibration()) { + _delay_ms(10); + } + + readCoefficients(); // read trimming parameters, see DS 4.2.2 + setSampling(); // use defaults + _delay_ms(100); + + return true; +} + +/*! + * @brief setup sensor with given parameters / settings + * + * This is simply a overload to the normal begin()-function, so SPI users + * don't get confused about the library requiring an address. + * @param mode the power mode to use for the sensor + * @param tempSampling the temp samping rate to use + * @param pressSampling the pressure sampling rate to use + * @param humSampling the humidity sampling rate to use + * @param filter the filter mode to use + * @param duration the standby duration to use + */ +void Adafruit_BME280::setSampling(sensor_mode mode, + sensor_sampling tempSampling, + sensor_sampling pressSampling, + sensor_sampling humSampling, + sensor_filter filter, + standby_duration duration) { + _measReg.mode = mode; + _measReg.osrs_t = tempSampling; + _measReg.osrs_p = pressSampling; + + _humReg.osrs_h = humSampling; + _configReg.filter = filter; + _configReg.t_sb = duration; + _configReg.spi3w_en = 0; + + // making sure sensor is in sleep mode before setting configuration + // as it otherwise may be ignored + write8(BME280_REGISTER_CONTROL, MODE_SLEEP); + + // you must make sure to also set REGISTER_CONTROL after setting the + // CONTROLHUMID register, otherwise the values won't be applied (see + // DS 5.4.3) + write8(BME280_REGISTER_CONTROLHUMID, _humReg.get()); + write8(BME280_REGISTER_CONFIG, _configReg.get()); + write8(BME280_REGISTER_CONTROL, _measReg.get()); +} + +/*! + * @brief Writes an 8 bit value over I2C or SPI + * @param reg the register address to write to + * @param value the value to write to the register + */ +void Adafruit_BME280::write8(byte reg, byte value) { + byte buffer[2]; + buffer[1] = value; + if (i2c_dev) { + buffer[0] = reg; + i2c_dev->write(buffer, 2); + } +} + +/*! + * @brief Reads an 8 bit value over I2C or SPI + * @param reg the register address to read from + * @returns the data byte read from the device + */ +uint8_t Adafruit_BME280::read8(byte reg) { + uint8_t buffer[1]; + if (i2c_dev) { + buffer[0] = uint8_t(reg); + i2c_dev->write_then_read(buffer, 1, buffer, 1); + } + return buffer[0]; +} + +/*! + * @brief Reads a 16 bit value over I2C or SPI + * @param reg the register address to read from + * @returns the 16 bit data value read from the device + */ +uint16_t Adafruit_BME280::read16(byte reg) { + uint8_t buffer[2]; + + if (i2c_dev) { + buffer[0] = uint8_t(reg); + i2c_dev->write_then_read(buffer, 1, buffer, 2); + } + return uint16_t(buffer[0]) << 8 | uint16_t(buffer[1]); +} + +/*! + * @brief Reads a signed 16 bit little endian value over I2C or SPI + * @param reg the register address to read from + * @returns the 16 bit data value read from the device + */ +uint16_t Adafruit_BME280::read16_LE(byte reg) { + uint16_t temp = read16(reg); + return (temp >> 8) | (temp << 8); +} + +/*! + * @brief Reads a signed 16 bit value over I2C or SPI + * @param reg the register address to read from + * @returns the 16 bit data value read from the device + */ +int16_t Adafruit_BME280::readS16(byte reg) { return (int16_t)read16(reg); } + +/*! + * @brief Reads a signed little endian 16 bit value over I2C or SPI + * @param reg the register address to read from + * @returns the 16 bit data value read from the device + */ +int16_t Adafruit_BME280::readS16_LE(byte reg) { + return (int16_t)read16_LE(reg); +} + +/*! + * @brief Reads a 24 bit value over I2C + * @param reg the register address to read from + * @returns the 24 bit data value read from the device + */ +uint32_t Adafruit_BME280::read24(byte reg) { + uint8_t buffer[3]; + + if (i2c_dev) { + buffer[0] = uint8_t(reg); + i2c_dev->write_then_read(buffer, 1, buffer, 3); + } + return uint32_t(buffer[0]) << 16 | uint32_t(buffer[1]) << 8 | + uint32_t(buffer[2]); +} + +/*! + * @brief Take a new measurement (only possible in forced mode) + @returns true in case of success else false + */ +bool Adafruit_BME280::takeForcedMeasurement(void) { + bool return_value = false; + // If we are in forced mode, the BME sensor goes back to sleep after each + // measurement and we need to set it to forced mode once at this point, so + // it will take the next measurement and then return to sleep again. + // In normal mode simply does new measurements periodically. + if (_measReg.mode == MODE_FORCED) { + return_value = true; + // set to forced mode, i.e. "take next measurement" + write8(BME280_REGISTER_CONTROL, _measReg.get()); + // Store current time to measure the timeout + uint32_t timeout_start = millis(); + // wait until measurement has been completed, otherwise we would read the + // the values from the last measurement or the timeout occurred after 2 sec. + while (read8(BME280_REGISTER_STATUS) & 0x08) { + // In case of a timeout, stop the while loop + if ((millis() - timeout_start) > 2000) { + return_value = false; + break; + } + _delay_ms(1); + } + } + return return_value; +} + +/*! + * @brief Reads the factory-set coefficients + */ +void Adafruit_BME280::readCoefficients(void) { + _bme280_calib.dig_T1 = read16_LE(BME280_REGISTER_DIG_T1); + _bme280_calib.dig_T2 = readS16_LE(BME280_REGISTER_DIG_T2); + _bme280_calib.dig_T3 = readS16_LE(BME280_REGISTER_DIG_T3); + + _bme280_calib.dig_P1 = read16_LE(BME280_REGISTER_DIG_P1); + _bme280_calib.dig_P2 = readS16_LE(BME280_REGISTER_DIG_P2); + _bme280_calib.dig_P3 = readS16_LE(BME280_REGISTER_DIG_P3); + _bme280_calib.dig_P4 = readS16_LE(BME280_REGISTER_DIG_P4); + _bme280_calib.dig_P5 = readS16_LE(BME280_REGISTER_DIG_P5); + _bme280_calib.dig_P6 = readS16_LE(BME280_REGISTER_DIG_P6); + _bme280_calib.dig_P7 = readS16_LE(BME280_REGISTER_DIG_P7); + _bme280_calib.dig_P8 = readS16_LE(BME280_REGISTER_DIG_P8); + _bme280_calib.dig_P9 = readS16_LE(BME280_REGISTER_DIG_P9); + + _bme280_calib.dig_H1 = read8(BME280_REGISTER_DIG_H1); + _bme280_calib.dig_H2 = readS16_LE(BME280_REGISTER_DIG_H2); + _bme280_calib.dig_H3 = read8(BME280_REGISTER_DIG_H3); + _bme280_calib.dig_H4 = ((int8_t)read8(BME280_REGISTER_DIG_H4) << 4) | + (read8(BME280_REGISTER_DIG_H4 + 1) & 0xF); + _bme280_calib.dig_H5 = ((int8_t)read8(BME280_REGISTER_DIG_H5 + 1) << 4) | + (read8(BME280_REGISTER_DIG_H5) >> 4); + _bme280_calib.dig_H6 = (int8_t)read8(BME280_REGISTER_DIG_H6); +} + +/*! + * @brief return true if chip is busy reading cal data + * @returns true if reading calibration, false otherwise + */ +bool Adafruit_BME280::isReadingCalibration(void) { + uint8_t const rStatus = read8(BME280_REGISTER_STATUS); + + return (rStatus & (1 << 0)) != 0; +} + +/*! + * @brief Returns the temperature from the sensor + * @returns the temperature read from the device + */ +float Adafruit_BME280::readTemperature(void) { + int32_t var1, var2; + + int32_t adc_T = read24(BME280_REGISTER_TEMPDATA); + if (adc_T == 0x800000) // value in case temp measurement was disabled + return NAN; + adc_T >>= 4; + + var1 = (int32_t)((adc_T / 8) - ((int32_t)_bme280_calib.dig_T1 * 2)); + var1 = (var1 * ((int32_t)_bme280_calib.dig_T2)) / 2048; + var2 = (int32_t)((adc_T / 16) - ((int32_t)_bme280_calib.dig_T1)); + var2 = (((var2 * var2) / 4096) * ((int32_t)_bme280_calib.dig_T3)) / 16384; + + t_fine = var1 + var2 + t_fine_adjust; + + int32_t T = (t_fine * 5 + 128) / 256; + + return (float)T / 100; +} + +/*! + * @brief Returns the pressure from the sensor + * @returns the pressure value (in Pascal) read from the device + */ +float Adafruit_BME280::readPressure(void) { + int64_t var1, var2, var3, var4; + + readTemperature(); // must be done first to get t_fine + + int32_t adc_P = read24(BME280_REGISTER_PRESSUREDATA); + if (adc_P == 0x800000) // value in case pressure measurement was disabled + return NAN; + adc_P >>= 4; + + var1 = ((int64_t)t_fine) - 128000; + var2 = var1 * var1 * (int64_t)_bme280_calib.dig_P6; + var2 = var2 + ((var1 * (int64_t)_bme280_calib.dig_P5) * 131072); + var2 = var2 + (((int64_t)_bme280_calib.dig_P4) * 34359738368); + var1 = ((var1 * var1 * (int64_t)_bme280_calib.dig_P3) / 256) + + ((var1 * ((int64_t)_bme280_calib.dig_P2) * 4096)); + var3 = ((int64_t)1) * 140737488355328; + var1 = (var3 + var1) * ((int64_t)_bme280_calib.dig_P1) / 8589934592; + + if (var1 == 0) { + return 0; // avoid exception caused by division by zero + } + + var4 = 1048576 - adc_P; + var4 = (((var4 * 2147483648UL) - var2) * 3125) / var1; + var1 = (((int64_t)_bme280_calib.dig_P9) * (var4 / 8192) * (var4 / 8192)) / + 33554432; + var2 = (((int64_t)_bme280_calib.dig_P8) * var4) / 524288; + var4 = ((var4 + var1 + var2) / 256) + (((int64_t)_bme280_calib.dig_P7) * 16); + + float P = var4 / 256.0; + + return P; +} + +/*! + * @brief Returns the humidity from the sensor + * @returns the humidity value read from the device + */ +float Adafruit_BME280::readHumidity(void) { + int32_t var1, var2, var3, var4, var5; + + readTemperature(); // must be done first to get t_fine + + int32_t adc_H = read16(BME280_REGISTER_HUMIDDATA); + if (adc_H == 0x8000) // value in case humidity measurement was disabled + return NAN; + + var1 = t_fine - ((int32_t)76800); + var2 = (int32_t)(adc_H * 16384); + var3 = (int32_t)(((int32_t)_bme280_calib.dig_H4) * 1048576); + var4 = ((int32_t)_bme280_calib.dig_H5) * var1; + var5 = (((var2 - var3) - var4) + (int32_t)16384) / 32768; + var2 = (var1 * ((int32_t)_bme280_calib.dig_H6)) / 1024; + var3 = (var1 * ((int32_t)_bme280_calib.dig_H3)) / 2048; + var4 = ((var2 * (var3 + (int32_t)32768)) / 1024) + (int32_t)2097152; + var2 = ((var4 * ((int32_t)_bme280_calib.dig_H2)) + 8192) / 16384; + var3 = var5 * var2; + var4 = ((var3 / 32768) * (var3 / 32768)) / 128; + var5 = var3 - ((var4 * ((int32_t)_bme280_calib.dig_H1)) / 16); + var5 = (var5 < 0 ? 0 : var5); + var5 = (var5 > 419430400 ? 419430400 : var5); + uint32_t H = (uint32_t)(var5 / 4096); + + return (float)H / 1024.0; +} + +/*! + * Calculates the altitude (in meters) from the specified atmospheric + * pressure (in hPa), and sea-level pressure (in hPa). + * @param seaLevel Sea-level pressure in hPa + * @returns the altitude value read from the device + */ +float Adafruit_BME280::readAltitude(float seaLevel) { + // Equation taken from BMP180 datasheet (page 16): + // http://www.adafruit.com/datasheets/BST-BMP180-DS000-09.pdf + + // Note that using the equation from wikipedia can give bad results + // at high altitude. See this thread for more information: + // http://forums.adafruit.com/viewtopic.php?f=22&t=58064 + + float atmospheric = readPressure() / 100.0F; + return 44330.0 * (1.0 - pow(atmospheric / seaLevel, 0.1903)); +} + +/*! + * Calculates the pressure at sea level (in hPa) from the specified + * altitude (in meters), and atmospheric pressure (in hPa). + * @param altitude Altitude in meters + * @param atmospheric Atmospheric pressure in hPa + * @returns the pressure at sea level (in hPa) from the specified altitude + */ +float Adafruit_BME280::seaLevelForAltitude(float altitude, float atmospheric) { + // Equation taken from BMP180 datasheet (page 17): + // http://www.adafruit.com/datasheets/BST-BMP180-DS000-09.pdf + + // Note that using the equation from wikipedia can give bad results + // at high altitude. See this thread for more information: + // http://forums.adafruit.com/viewtopic.php?f=22&t=58064 + + return atmospheric / pow(1.0 - (altitude / 44330.0), 5.255); +} + +/*! + * Returns Sensor ID found by init() for diagnostics + * @returns Sensor ID 0x60 for BME280, 0x56, 0x57, 0x58 BMP280 + */ +uint32_t Adafruit_BME280::sensorID(void) { return _sensorID; } + +/*! + * Returns the current temperature compensation value in degrees Celsius + * @returns the current temperature compensation value in degrees Celsius + */ +float Adafruit_BME280::getTemperatureCompensation(void) { + return float((t_fine_adjust * 5) >> 8) / 100.0; +}; + +/*! + * Sets a value to be added to each temperature reading. This adjusted + * temperature is used in pressure and humidity readings. + * @param adjustment Value to be added to each temperature reading in Celsius + */ +void Adafruit_BME280::setTemperatureCompensation(float adjustment) { + // convert the value in C into and adjustment to t_fine + t_fine_adjust = ((int32_t(adjustment * 100) << 8)) / 5; +}; + + +/**************************************************************************/ +/*! + @brief Gets the sensor_t data for the BME280's temperature sensor +*/ +/**************************************************************************/ +void Adafruit_BME280_Temp::getSensor(sensor_t *sensor) { + /* Clear the sensor_t object */ + memset(sensor, 0, sizeof(sensor_t)); + + /* Insert the sensor name in the fixed length char array */ + strncpy(sensor->name, "BME280", sizeof(sensor->name) - 1); + sensor->name[sizeof(sensor->name) - 1] = 0; + sensor->version = 1; + sensor->sensor_id = _sensorID; + sensor->type = SENSOR_TYPE_AMBIENT_TEMPERATURE; + sensor->min_delay = 0; + sensor->min_value = -40.0; /* Temperature range -40 ~ +85 C */ + sensor->max_value = +85.0; + sensor->resolution = 0.01; /* 0.01 C */ +} + +/**************************************************************************/ +/*! + @brief Gets the temperature as a standard sensor event + @param event Sensor event object that will be populated + @returns True +*/ +/**************************************************************************/ +bool Adafruit_BME280_Temp::getEvent(sensors_event_t *event) { + /* Clear the event */ + memset(event, 0, sizeof(sensors_event_t)); + + event->version = sizeof(sensors_event_t); + event->sensor_id = _sensorID; + event->type = SENSOR_TYPE_AMBIENT_TEMPERATURE; + event->timestamp = millis(); + event->temperature = theBME280.readTemperature(); + return true; +} + +/**************************************************************************/ +/*! + @brief Gets the sensor_t data for the BME280's pressure sensor +*/ +/**************************************************************************/ +void Adafruit_BME280_Pressure::getSensor(sensor_t *sensor) { + /* Clear the sensor_t object */ + memset(sensor, 0, sizeof(sensor_t)); + + /* Insert the sensor name in the fixed length char array */ + strncpy(sensor->name, "BME280", sizeof(sensor->name) - 1); + sensor->name[sizeof(sensor->name) - 1] = 0; + sensor->version = 1; + sensor->sensor_id = _sensorID; + sensor->type = SENSOR_TYPE_PRESSURE; + sensor->min_delay = 0; + sensor->min_value = 300.0; /* 300 ~ 1100 hPa */ + sensor->max_value = 1100.0; + sensor->resolution = 0.012; /* 0.12 hPa relative */ +} + +/**************************************************************************/ +/*! + @brief Gets the pressure as a standard sensor event + @param event Sensor event object that will be populated + @returns True +*/ +/**************************************************************************/ +bool Adafruit_BME280_Pressure::getEvent(sensors_event_t *event) { + /* Clear the event */ + memset(event, 0, sizeof(sensors_event_t)); + + event->version = sizeof(sensors_event_t); + event->sensor_id = _sensorID; + event->type = SENSOR_TYPE_PRESSURE; + event->timestamp = millis(); + event->pressure = theBME280.readPressure() / 100; // convert Pa to hPa + return true; +} + +/**************************************************************************/ +/*! + @brief Gets the sensor_t data for the BME280's humidity sensor +*/ +/**************************************************************************/ +void Adafruit_BME280_Humidity::getSensor(sensor_t *sensor) { + /* Clear the sensor_t object */ + memset(sensor, 0, sizeof(sensor_t)); + + /* Insert the sensor name in the fixed length char array */ + strncpy(sensor->name, "BME280", sizeof(sensor->name) - 1); + sensor->name[sizeof(sensor->name) - 1] = 0; + sensor->version = 1; + sensor->sensor_id = _sensorID; + sensor->type = SENSOR_TYPE_RELATIVE_HUMIDITY; + sensor->min_delay = 0; + sensor->min_value = 0; + sensor->max_value = 100; /* 0 - 100 % */ + sensor->resolution = 3; /* 3% accuracy */ +} + +/**************************************************************************/ +/*! + @brief Gets the humidity as a standard sensor event + @param event Sensor event object that will be populated + @returns True +*/ +/**************************************************************************/ +bool Adafruit_BME280_Humidity::getEvent(sensors_event_t *event) { + /* Clear the event */ + memset(event, 0, sizeof(sensors_event_t)); + + event->version = sizeof(sensors_event_t); + event->sensor_id = _sensorID; + event->type = SENSOR_TYPE_RELATIVE_HUMIDITY; + event->timestamp = millis(); + event->relative_humidity = theBME280.readHumidity(); + return true; +} diff --git a/software/nano-644/test_2024-07-23/src/adafruit/bme280.h b/software/nano-644/test_2024-07-23/src/adafruit/bme280.h new file mode 100644 index 0000000..b842782 --- /dev/null +++ b/software/nano-644/test_2024-07-23/src/adafruit/bme280.h @@ -0,0 +1,373 @@ +// https://github.com/adafruit/Adafruit_BME280_Library + +/*! + * @file Adafruit_BME280.h + * + * Designed specifically to work with the Adafruit BME280 Breakout + * ----> http://www.adafruit.com/products/2650 + * + * These sensors use I2C or SPI to communicate, 2 or 4 pins are required + * to interface. + * + * Adafruit invests time and resources providing this open source code, + * please support Adafruit and open-source hardware by purchasing + * products from Adafruit! + * + * Written by Kevin "KTOWN" Townsend for Adafruit Industries. + * + * BSD license, all text here must be included in any redistribution. + * See the LICENSE file for details. + * + */ + +#ifndef __BME280_H__ +#define __BME280_H__ + +// #include "Arduino.h" + +// #include +// #include +// #include + + +#include "../i2cmaster.hpp" +#include "../main.hpp" +#define byte uint8_t + + + +#include +#include +#include "sensor.h" + +/*! + * @brief default I2C address + */ +#define BME280_ADDRESS (0x77) // Primary I2C Address + /*! + * @brief alternate I2C address + */ +#define BME280_ADDRESS_ALTERNATE (0x76) // Alternate Address + +/*! + * @brief Register addresses + */ +enum { + BME280_REGISTER_DIG_T1 = 0x88, + BME280_REGISTER_DIG_T2 = 0x8A, + BME280_REGISTER_DIG_T3 = 0x8C, + + BME280_REGISTER_DIG_P1 = 0x8E, + BME280_REGISTER_DIG_P2 = 0x90, + BME280_REGISTER_DIG_P3 = 0x92, + BME280_REGISTER_DIG_P4 = 0x94, + BME280_REGISTER_DIG_P5 = 0x96, + BME280_REGISTER_DIG_P6 = 0x98, + BME280_REGISTER_DIG_P7 = 0x9A, + BME280_REGISTER_DIG_P8 = 0x9C, + BME280_REGISTER_DIG_P9 = 0x9E, + + BME280_REGISTER_DIG_H1 = 0xA1, + BME280_REGISTER_DIG_H2 = 0xE1, + BME280_REGISTER_DIG_H3 = 0xE3, + BME280_REGISTER_DIG_H4 = 0xE4, + BME280_REGISTER_DIG_H5 = 0xE5, + BME280_REGISTER_DIG_H6 = 0xE7, + + BME280_REGISTER_CHIPID = 0xD0, + BME280_REGISTER_VERSION = 0xD1, + BME280_REGISTER_SOFTRESET = 0xE0, + + BME280_REGISTER_CAL26 = 0xE1, // R calibration stored in 0xE1-0xF0 + + BME280_REGISTER_CONTROLHUMID = 0xF2, + BME280_REGISTER_STATUS = 0XF3, + BME280_REGISTER_CONTROL = 0xF4, + BME280_REGISTER_CONFIG = 0xF5, + BME280_REGISTER_PRESSUREDATA = 0xF7, + BME280_REGISTER_TEMPDATA = 0xFA, + BME280_REGISTER_HUMIDDATA = 0xFD +}; + +/**************************************************************************/ +/*! + @brief calibration data +*/ +/**************************************************************************/ +typedef struct { + uint16_t dig_T1; ///< temperature compensation value + int16_t dig_T2; ///< temperature compensation value + int16_t dig_T3; ///< temperature compensation value + + uint16_t dig_P1; ///< pressure compensation value + int16_t dig_P2; ///< pressure compensation value + int16_t dig_P3; ///< pressure compensation value + int16_t dig_P4; ///< pressure compensation value + int16_t dig_P5; ///< pressure compensation value + int16_t dig_P6; ///< pressure compensation value + int16_t dig_P7; ///< pressure compensation value + int16_t dig_P8; ///< pressure compensation value + int16_t dig_P9; ///< pressure compensation value + + uint8_t dig_H1; ///< humidity compensation value + int16_t dig_H2; ///< humidity compensation value + uint8_t dig_H3; ///< humidity compensation value + int16_t dig_H4; ///< humidity compensation value + int16_t dig_H5; ///< humidity compensation value + int8_t dig_H6; ///< humidity compensation value +} bme280_calib_data; +/*=========================================================================*/ + +class Adafruit_BME280; + +/** Adafruit Unified Sensor interface for temperature component of BME280 */ +class Adafruit_BME280_Temp : public Adafruit_Sensor { +public: + /** @brief Create an Adafruit_Sensor compatible object for the temp sensor + @param parent A pointer to the BME280 class */ + Adafruit_BME280_Temp() { _sensorID = 280; } + bool getEvent(sensors_event_t *); + void getSensor(sensor_t *); + +private: + int _sensorID; +}; + +/** Adafruit Unified Sensor interface for pressure component of BME280 */ +class Adafruit_BME280_Pressure : public Adafruit_Sensor { +public: + /** @brief Create an Adafruit_Sensor compatible object for the pressure sensor + @param parent A pointer to the BME280 class */ + Adafruit_BME280_Pressure() { _sensorID = 280; } + bool getEvent(sensors_event_t *); + void getSensor(sensor_t *); + +private: + int _sensorID; +}; + +/** Adafruit Unified Sensor interface for humidity component of BME280 */ +class Adafruit_BME280_Humidity : public Adafruit_Sensor { +public: + /** @brief Create an Adafruit_Sensor compatible object for the humidity sensor + @param parent A pointer to the BME280 class */ + Adafruit_BME280_Humidity() { _sensorID = 280;} + bool getEvent(sensors_event_t *); + void getSensor(sensor_t *); + +private: + int _sensorID; +}; + +/**************************************************************************/ +/*! + @brief Class that stores state and functions for interacting with BME280 IC +*/ +/**************************************************************************/ +class Adafruit_BME280 { +public: + /**************************************************************************/ + /*! + @brief sampling rates + */ + /**************************************************************************/ + enum sensor_sampling { + SAMPLING_NONE = 0b000, + SAMPLING_X1 = 0b001, + SAMPLING_X2 = 0b010, + SAMPLING_X4 = 0b011, + SAMPLING_X8 = 0b100, + SAMPLING_X16 = 0b101 + }; + + /**************************************************************************/ + /*! + @brief power modes + */ + /**************************************************************************/ + enum sensor_mode { + MODE_SLEEP = 0b00, + MODE_FORCED = 0b01, + MODE_NORMAL = 0b11 + }; + + /**************************************************************************/ + /*! + @brief filter values + */ + /**************************************************************************/ + enum sensor_filter { + FILTER_OFF = 0b000, + FILTER_X2 = 0b001, + FILTER_X4 = 0b010, + FILTER_X8 = 0b011, + FILTER_X16 = 0b100 + }; + + /**************************************************************************/ + /*! + @brief standby duration in ms + */ + /**************************************************************************/ + enum standby_duration { + STANDBY_MS_0_5 = 0b000, + STANDBY_MS_10 = 0b110, + STANDBY_MS_20 = 0b111, + STANDBY_MS_62_5 = 0b001, + STANDBY_MS_125 = 0b010, + STANDBY_MS_250 = 0b011, + STANDBY_MS_500 = 0b100, + STANDBY_MS_1000 = 0b101 + }; + + // constructors + Adafruit_BME280(); + + bool begin(uint8_t addr = BME280_ADDRESS); + bool init(); + + void setSampling(sensor_mode mode = MODE_NORMAL, + sensor_sampling tempSampling = SAMPLING_X16, + sensor_sampling pressSampling = SAMPLING_X16, + sensor_sampling humSampling = SAMPLING_X16, + sensor_filter filter = FILTER_OFF, + standby_duration duration = STANDBY_MS_0_5); + + bool takeForcedMeasurement(void); + float readTemperature(void); + float readPressure(void); + float readHumidity(void); + + float readAltitude(float seaLevel); + float seaLevelForAltitude(float altitude, float pressure); + uint32_t sensorID(void); + + float getTemperatureCompensation(void); + void setTemperatureCompensation(float); + +protected: + I2cMaster *i2c_dev = NULL; ///< Pointer to I2C bus interface + // Adafruit_SPIDevice *spi_dev = NULL; ///< Pointer to SPI bus interface + + Adafruit_BME280_Temp *temp_sensor; + Adafruit_BME280_Pressure *pressure_sensor; + Adafruit_BME280_Humidity *humidity_sensor; + + void readCoefficients(void); + bool isReadingCalibration(void); + + void write8(byte reg, byte value); + uint8_t read8(byte reg); + uint16_t read16(byte reg); + uint32_t read24(byte reg); + int16_t readS16(byte reg); + uint16_t read16_LE(byte reg); // little endian + int16_t readS16_LE(byte reg); // little endian + + uint8_t _i2caddr; //!< I2C addr for the TwoWire interface + int32_t _sensorID; //!< ID of the BME Sensor + int32_t t_fine; //!< temperature with high resolution, stored as an attribute + //!< as this is used for temperature compensation reading + //!< humidity and pressure + + int32_t t_fine_adjust; //!< add to compensate temp readings and in turn + //!< to pressure and humidity readings + + bme280_calib_data _bme280_calib; //!< here calibration data is stored + + /**************************************************************************/ + /*! + @brief config register + */ + /**************************************************************************/ + struct config { + // inactive duration (standby time) in normal mode + // 000 = 0.5 ms + // 001 = 62.5 ms + // 010 = 125 ms + // 011 = 250 ms + // 100 = 500 ms + // 101 = 1000 ms + // 110 = 10 ms + // 111 = 20 ms + unsigned int t_sb : 3; ///< inactive duration (standby time) in normal mode + + // filter settings + // 000 = filter off + // 001 = 2x filter + // 010 = 4x filter + // 011 = 8x filter + // 100 and above = 16x filter + unsigned int filter : 3; ///< filter settings + + // unused - don't set + unsigned int none : 1; ///< unused - don't set + unsigned int spi3w_en : 1; ///< unused - don't set + + /// @return combined config register + unsigned int get() { return (t_sb << 5) | (filter << 2) | spi3w_en; } + }; + config _configReg; //!< config register object + + /**************************************************************************/ + /*! + @brief ctrl_meas register + */ + /**************************************************************************/ + struct ctrl_meas { + // temperature oversampling + // 000 = skipped + // 001 = x1 + // 010 = x2 + // 011 = x4 + // 100 = x8 + // 101 and above = x16 + unsigned int osrs_t : 3; ///< temperature oversampling + + // pressure oversampling + // 000 = skipped + // 001 = x1 + // 010 = x2 + // 011 = x4 + // 100 = x8 + // 101 and above = x16 + unsigned int osrs_p : 3; ///< pressure oversampling + + // device mode + // 00 = sleep + // 01 or 10 = forced + // 11 = normal + unsigned int mode : 2; ///< device mode + + /// @return combined ctrl register + unsigned int get() { return (osrs_t << 5) | (osrs_p << 2) | mode; } + }; + ctrl_meas _measReg; //!< measurement register object + + /**************************************************************************/ + /*! + @brief ctrl_hum register + */ + /**************************************************************************/ + struct ctrl_hum { + /// unused - don't set + unsigned int none : 5; + + // pressure oversampling + // 000 = skipped + // 001 = x1 + // 010 = x2 + // 011 = x4 + // 100 = x8 + // 101 and above = x16 + unsigned int osrs_h : 3; ///< pressure oversampling + + /// @return combined ctrl hum register + unsigned int get() { return (osrs_h); } + }; + ctrl_hum _humReg; //!< hum register object +}; + +extern Adafruit_BME280 theBME280; + +#endif diff --git a/software/nano-644/test_2024-07-23/src/adafruit/ens160.cpp b/software/nano-644/test_2024-07-23/src/adafruit/ens160.cpp new file mode 100644 index 0000000..ef23404 --- /dev/null +++ b/software/nano-644/test_2024-07-23/src/adafruit/ens160.cpp @@ -0,0 +1,374 @@ +/* + ScioSense_ENS160.h - Library for the ENS160 sensor with I2C interface from ScioSense + 2023 Mar 23 v6 Christoph Friese Bugfix measurement routine, prepare next release + 2021 Nov 25 v5 Martin Herold Custom mode timing fixed + 2021 Feb 04 v4 Giuseppe de Pinto Custom mode fixed + 2020 Apr 06 v3 Christoph Friese Changed nomenclature to ScioSense as product shifted from ams + 2020 Feb 15 v2 Giuseppe Pasetti Corrected firmware flash option + 2019 May 05 v1 Christoph Friese Created + based on application note "ENS160 Software Integration.pdf" rev 0.01 +*/ + +#include "ens160.h" +#include "math.h" +#include +#include +#include + +ScioSense_ENS160::ScioSense_ENS160 () { + _revENS16x = 0; + + //Isotherm, HP0 252°C / HP1 350°C / HP2 250°C / HP3 324°C / measure every 1008ms + _seq_steps[0][0] = 0x7c; + _seq_steps[0][1] = 0x0a; + _seq_steps[0][2] = 0x7e; + _seq_steps[0][3] = 0xaf; + _seq_steps[0][4] = 0xaf; + _seq_steps[0][5] = 0xa2; + _seq_steps[0][6] = 0x00; + _seq_steps[0][7] = 0x80; +} + +bool ScioSense_ENS160::begin () { + i2cDevice.begin(ENS160_I2CADDR_1); + _delay_ms(ENS160_BOOTING); + if (reset()) { + if (checkPartID()) { + if (setMode(ENS160_OPMODE_IDLE)) { + if (clearCommand()) { + if (getFirmware()) { + return true; + } + } + } + } + } + return false; + +} + +bool ScioSense_ENS160::write8 (byte reg, byte value) { + byte buffer[2]; + buffer[1] = value; + buffer[0] = reg; + return i2cDevice.write(buffer, 2); +} + +bool ScioSense_ENS160::read8 (byte reg, byte *value) { + uint8_t buffer[1]; + buffer[0] = uint8_t(reg); + return i2cDevice.write_then_read(buffer, 1, value, 1); +} + +bool ScioSense_ENS160::read16 (byte reg, uint16_t *value) { + uint8_t buffer[1]; + buffer[0] = uint8_t(reg); + return i2cDevice.write_then_read(buffer, 1, (uint8_t *)value, 2); +} + +bool ScioSense_ENS160::read16LE (byte reg, uint16_t *value) { + uint16_t tmp; + if (read16(reg, &tmp)) { + *value = ((tmp & 0xff) << 8) | (tmp >> 8); + return true; + } + return false; +} + +bool ScioSense_ENS160::readBytes (byte reg, uint8_t *bytes, uint8_t len) { + uint8_t buffer[1]; + buffer[0] = uint8_t(reg); + return i2cDevice.write_then_read(buffer, 1, buffer, len); +} + + +// Sends a reset to the ENS160. Returns false on I2C problems. +bool ScioSense_ENS160::reset () { + if (write8(ENS160_REG_OPMODE, ENS160_OPMODE_RESET)) { + _delay_ms(ENS160_BOOTING); + return true; + } + _delay_ms(ENS160_BOOTING); + return false; +} + +// Reads the part ID and confirms valid sensor +bool ScioSense_ENS160::checkPartID () { + uint16_t part_id; + + read16(ENS160_REG_PART_ID, &part_id); + _delay_ms(ENS160_BOOTING); + + if (part_id == ENS160_PARTID) { + _revENS16x = 0; + return true; + + } else if (part_id == ENS161_PARTID) { + _revENS16x = 1; + return true; + } + + return false; +} + +// Initialize idle mode and confirms +bool ScioSense_ENS160::clearCommand () { + uint8_t status; + + if (write8(ENS160_REG_COMMAND, ENS160_COMMAND_NOP)) { + if (write8(ENS160_REG_COMMAND, ENS160_COMMAND_CLRGPR)) { + _delay_ms(ENS160_BOOTING); + if (read8(ENS160_REG_DATA_STATUS, &status)) { + return true; + } + } + } + _delay_ms(ENS160_BOOTING); + return false; +} + +// Read firmware revisions +bool ScioSense_ENS160::getFirmware () { + uint8_t i2cbuf[3]; + + if (clearCommand()) { + _delay_ms(ENS160_BOOTING); + if (write8(ENS160_REG_COMMAND, ENS160_COMMAND_GET_APPVER)) { + if (readBytes(ENS160_REG_GPR_READ_4, i2cbuf, 3)) { + _fw_ver_major = i2cbuf[0]; + _fw_ver_minor = i2cbuf[1]; + _fw_ver_build = i2cbuf[2]; + _revENS16x = this->_fw_ver_major > 6 ? 1 : 0; + _delay_ms(ENS160_BOOTING); + return true; + } + } + } + _delay_ms(ENS160_BOOTING); + return false; +} + +// Set operation mode of sensor +bool ScioSense_ENS160::setMode (uint8_t mode) { + //LP only valid for rev>0 + if ((mode == ENS160_OPMODE_LP) and (_revENS16x == 0)) { + return false; + } + if (write8(ENS160_REG_OPMODE, mode)) { + _delay_ms(ENS160_BOOTING); + return true; + } + _delay_ms(ENS160_BOOTING); + return false; +} + +// Initialize definition of custom mode with steps +bool ScioSense_ENS160::initCustomMode (uint16_t stepNum) { + if (stepNum > 0) { + _stepCount = stepNum; + if (setMode(ENS160_OPMODE_IDLE)) { + if (clearCommand()) { + if (write8(ENS160_REG_COMMAND, ENS160_COMMAND_SETSEQ)) { + _delay_ms(ENS160_BOOTING); + return true; + } + } + } + } + _delay_ms(ENS160_BOOTING); + return false; +} + +// Add a step to custom measurement profile with definition of duration, enabled data acquisition and temperature for each hotplate +bool ScioSense_ENS160::addCustomStep (uint16_t time, bool measureHP0, bool measureHP1, bool measureHP2, bool measureHP3, uint16_t tempHP0, uint16_t tempHP1, uint16_t tempHP2, uint16_t tempHP3) { + uint8_t seq_ack; + uint8_t temp; + + _delay_ms(ENS160_BOOTING); + + temp = (uint8_t)(((time / 24) - 1) << 6); + if (measureHP0) { + temp = temp | 0x20; + } + if (measureHP1) { + temp = temp | 0x10; + } + if (measureHP2) { + temp = temp | 0x08; + } + if (measureHP3) { + temp = temp | 0x04; + } + if (!write8(ENS160_REG_GPR_WRITE_0, temp)) { + return false; + } + temp = (uint8_t)(((time / 24) - 1) >> 2); + if (!write8(ENS160_REG_GPR_WRITE_1, temp)) { + return false; + } + if (!write8(ENS160_REG_GPR_WRITE_2, (uint8_t)(tempHP0 / 2))) { + return false; + } + if (!write8(ENS160_REG_GPR_WRITE_3, (uint8_t)(tempHP1 / 2))) { + return false; + } + if (write8(ENS160_REG_GPR_WRITE_4, (uint8_t)(tempHP2 / 2))) { + return false; + } + if (write8(ENS160_REG_GPR_WRITE_5, (uint8_t)(tempHP3 / 2))) { + return false; + } + + if (write8(ENS160_REG_GPR_WRITE_6, (uint8_t)(_stepCount - 1))) { + return false; + } + + if (_stepCount == 1) { + if (!write8(ENS160_REG_GPR_WRITE_7, 128)) { + return false; + } + } else { + if (!write8(ENS160_REG_GPR_WRITE_7, 0)) { + return false; + } + } + _delay_ms(ENS160_BOOTING); + + if (!read8(ENS160_REG_GPR_READ_7, &seq_ack)) { + return false; + } + _delay_ms(ENS160_BOOTING); + + if ((ENS160_SEQ_ACK_COMPLETE | _stepCount) != seq_ack) { + _stepCount++; + return false; + } + + return true; +} + +bool ScioSense_ENS160::readStatus (uint8_t *status) { + return read8(ENS160_REG_DATA_STATUS, status); +} + +bool ScioSense_ENS160::readData (ENS160_DATA *data) { + uint8_t buffer[1] = { 0x21 }; + return i2cDevice.write_then_read(buffer, 1, (uint8_t *)data, sizeof(ENS160_DATA)); +} + +// Perform prediction measurement and stores result in internal variables +bool ScioSense_ENS160::measure (bool waitForNew) { + uint8_t i2cbuf[8]; + uint8_t status; + + // Set default status for early bail out + if (waitForNew) { + do { + if (!read8(ENS160_REG_DATA_STATUS, &status)) { + return false; + } + _delay_ms(1); + } while (!IS_NEWDAT(status)); + } else { + if (!read8(ENS160_REG_DATA_STATUS, &status)) { + return false; + } + } + + + // Read predictions + if (IS_NEWDAT(status)) { + if (!readBytes(ENS160_REG_DATA_AQI, i2cbuf, 7)) { + return false; + } + return false; + _data_aqi = i2cbuf[0]; + _data_tvoc = i2cbuf[1] | ((uint16_t)i2cbuf[2] << 8); + _data_eco2 = i2cbuf[3] | ((uint16_t)i2cbuf[4] << 8); + if (_revENS16x > 0) { + _data_aqi500 = ((uint16_t)i2cbuf[5]) | ((uint16_t)i2cbuf[6] << 8); + } else { + _data_aqi500 = 0; + } + return true; + } + + return false; +} + +// Perfrom raw measurement and stores result in internal variables +bool ScioSense_ENS160::measureRaw (bool waitForNew) { + uint8_t i2cbuf[8]; + uint8_t status; + + // Set default status for early bail out + if (waitForNew) { + do { + _delay_ms(1); + if (!read8(ENS160_REG_DATA_STATUS, &status)) { + return false; + } + } while (!IS_NEWGPR(status)); + } else { + if (!read8(ENS160_REG_DATA_STATUS, &status)) { + return false; + } + } + + if (IS_NEWGPR(status)) { + + // Read raw resistance values + if (!readBytes(ENS160_REG_GPR_READ_0, i2cbuf, 8)) { + return false; + } + _hp0_rs = CONVERT_RS_RAW2OHMS_F((uint32_t)(i2cbuf[0] | ((uint16_t)i2cbuf[1] << 8))); + _hp1_rs = CONVERT_RS_RAW2OHMS_F((uint32_t)(i2cbuf[2] | ((uint16_t)i2cbuf[3] << 8))); + _hp2_rs = CONVERT_RS_RAW2OHMS_F((uint32_t)(i2cbuf[4] | ((uint16_t)i2cbuf[5] << 8))); + _hp3_rs = CONVERT_RS_RAW2OHMS_F((uint32_t)(i2cbuf[6] | ((uint16_t)i2cbuf[7] << 8))); + + // Read baselines + if (!readBytes(ENS160_REG_DATA_BL, i2cbuf, 8)) { + return false; + } + _hp0_bl = CONVERT_RS_RAW2OHMS_F((uint32_t)(i2cbuf[0] | ((uint16_t)i2cbuf[1] << 8))); + _hp1_bl = CONVERT_RS_RAW2OHMS_F((uint32_t)(i2cbuf[2] | ((uint16_t)i2cbuf[3] << 8))); + _hp2_bl = CONVERT_RS_RAW2OHMS_F((uint32_t)(i2cbuf[4] | ((uint16_t)i2cbuf[5] << 8))); + _hp3_bl = CONVERT_RS_RAW2OHMS_F((uint32_t)(i2cbuf[6] | ((uint16_t)i2cbuf[7] << 8))); + + if (!read8(ENS160_REG_DATA_MISR, i2cbuf)) { + return false; + } + _misr = i2cbuf[0]; + return true; + } + + return false; +} + + +// Writes t (degC) and h (%rh) to ENV_DATA. Returns false on I2C problems. +bool ScioSense_ENS160::set_envdata (float t, float h) { + uint16_t t_data = (uint16_t)((t + 273.15f) * 64.0f); + uint16_t rh_data = (uint16_t)(h * 512.0f); + return this->set_envdata210(t_data, rh_data); +} + +// Writes t and h (in ENS210 format) to ENV_DATA. Returns false on I2C problems. +bool ScioSense_ENS160::set_envdata210 (uint16_t t, uint16_t h) { + //uint16_t temp; + uint8_t trh_in[4]; + + //temp = (uint16_t)((t + 273.15f) * 64.0f); + trh_in[0] = t & 0xff; + trh_in[1] = (t >> 8) & 0xff; + + //temp = (uint16_t)(h * 512.0f); + trh_in[2] = h & 0xff; + trh_in[3] = (h >> 8) & 0xff; + + if (!i2cDevice.writeByteAndBuffer(ENS160_REG_TEMP_IN, trh_in, 4)) { + return false; + } + + return true; +} diff --git a/software/nano-644/test_2024-07-23/src/adafruit/ens160.h b/software/nano-644/test_2024-07-23/src/adafruit/ens160.h new file mode 100644 index 0000000..fb6925d --- /dev/null +++ b/software/nano-644/test_2024-07-23/src/adafruit/ens160.h @@ -0,0 +1,188 @@ +/* + ScioSense_ENS160.h - Library for the ENS160 sensor with I2C interface from ScioSense + 2023 Mar 23 v6 Christoph Friese Bugfix measurement routine, prepare next release + 2021 July 29 v4 Christoph Friese Changed nomenclature to ScioSense as product shifted from ams + 2020 Apr 06 v3 Christoph Friese Changed nomenclature to ScioSense as product shifted from ams + 2020 Feb 15 v2 Giuseppe Pasetti Corrected firmware flash option + 2019 May 05 v1 Christoph Friese Created + based on application note "ENS160 Software Integration.pdf" rev 0.01 +*/ + +#ifndef __SCIOSENSE_ENS160_H_ +#define __SCIOSENSE_ENS160_H_ + +#include "../i2cmaster.hpp" +#include +#define byte uint8_t + +// #if (ARDUINO >= 100) +// #include "Arduino.h" +// #else +// #include "WProgram.h" +// #endif + +// #include + +// Chip constants +#define ENS160_PARTID 0x0160 +#define ENS161_PARTID 0x0161 +#define ENS160_BOOTING 10 + +// 7-bit I2C slave address of the ENS160 +#define ENS160_I2CADDR_0 0x52 //ADDR low +#define ENS160_I2CADDR_1 0x53 //ADDR high + +// ENS160 registers for version V0 +#define ENS160_REG_PART_ID 0x00 // 2 byte register +#define ENS160_REG_OPMODE 0x10 +#define ENS160_REG_CONFIG 0x11 +#define ENS160_REG_COMMAND 0x12 +#define ENS160_REG_TEMP_IN 0x13 +#define ENS160_REG_RH_IN 0x15 +#define ENS160_REG_DATA_STATUS 0x20 +#define ENS160_REG_DATA_AQI 0x21 +#define ENS160_REG_DATA_TVOC 0x22 +#define ENS160_REG_DATA_ECO2 0x24 +#define ENS160_REG_DATA_BL 0x28 +#define ENS160_REG_DATA_T 0x30 +#define ENS160_REG_DATA_RH 0x32 +#define ENS160_REG_DATA_MISR 0x38 +#define ENS160_REG_GPR_WRITE_0 0x40 +#define ENS160_REG_GPR_WRITE_1 ENS160_REG_GPR_WRITE_0 + 1 +#define ENS160_REG_GPR_WRITE_2 ENS160_REG_GPR_WRITE_0 + 2 +#define ENS160_REG_GPR_WRITE_3 ENS160_REG_GPR_WRITE_0 + 3 +#define ENS160_REG_GPR_WRITE_4 ENS160_REG_GPR_WRITE_0 + 4 +#define ENS160_REG_GPR_WRITE_5 ENS160_REG_GPR_WRITE_0 + 5 +#define ENS160_REG_GPR_WRITE_6 ENS160_REG_GPR_WRITE_0 + 6 +#define ENS160_REG_GPR_WRITE_7 ENS160_REG_GPR_WRITE_0 + 7 +#define ENS160_REG_GPR_READ_0 0x48 +#define ENS160_REG_GPR_READ_4 ENS160_REG_GPR_READ_0 + 4 +#define ENS160_REG_GPR_READ_6 ENS160_REG_GPR_READ_0 + 6 +#define ENS160_REG_GPR_READ_7 ENS160_REG_GPR_READ_0 + 7 + +//ENS160 data register fields +#define ENS160_COMMAND_NOP 0x00 +#define ENS160_COMMAND_CLRGPR 0xCC +#define ENS160_COMMAND_GET_APPVER 0x0E +#define ENS160_COMMAND_SETTH 0x02 +#define ENS160_COMMAND_SETSEQ 0xC2 + +#define ENS160_OPMODE_RESET 0xF0 +#define ENS160_OPMODE_DEP_SLEEP 0x00 +#define ENS160_OPMODE_IDLE 0x01 +#define ENS160_OPMODE_STD 0x02 +#define ENS160_OPMODE_LP 0x03 +#define ENS160_OPMODE_CUSTOM 0xC0 + +#define ENS160_BL_CMD_START 0x02 +#define ENS160_BL_CMD_ERASE_APP 0x04 +#define ENS160_BL_CMD_ERASE_BLINE 0x06 +#define ENS160_BL_CMD_WRITE 0x08 +#define ENS160_BL_CMD_VERIFY 0x0A +#define ENS160_BL_CMD_GET_BLVER 0x0C +#define ENS160_BL_CMD_GET_APPVER 0x0E +#define ENS160_BL_CMD_EXITBL 0x12 + +#define ENS160_SEQ_ACK_NOTCOMPLETE 0x80 +#define ENS160_SEQ_ACK_COMPLETE 0xC0 + +#define IS_ENS160_SEQ_ACK_NOT_COMPLETE(x) (ENS160_SEQ_ACK_NOTCOMPLETE == (ENS160_SEQ_ACK_NOTCOMPLETE & (x))) +#define IS_ENS160_SEQ_ACK_COMPLETE(x) (ENS160_SEQ_ACK_COMPLETE == (ENS160_SEQ_ACK_COMPLETE & (x))) + +#define ENS160_DATA_STATUS_NEWDAT 0x02 +#define ENS160_DATA_STATUS_NEWGPR 0x01 + +#define IS_NEWDAT(x) (ENS160_DATA_STATUS_NEWDAT == (ENS160_DATA_STATUS_NEWDAT & (x))) +#define IS_NEWGPR(x) (ENS160_DATA_STATUS_NEWGPR == (ENS160_DATA_STATUS_NEWGPR & (x))) +#define IS_NEW_DATA_AVAILABLE(x) (0 != ((ENS160_DATA_STATUS_NEWDAT | ENS160_DATA_STATUS_NEWGPR ) & (x))) + +#define CONVERT_RS_RAW2OHMS_I(x) (1 << ((x) >> 11)) +#define CONVERT_RS_RAW2OHMS_F(x) (pow (2, (float)(x) / 2048)) + +typedef struct { + uint8_t aqi; + uint16_t tvoc; + uint16_t eco2; +} ENS160_DATA; + +class ScioSense_ENS160 { + + public: + ScioSense_ENS160(); + + void setI2C(uint8_t sda, uint8_t scl); // Function to redefine I2C pins + + bool begin(); // Init I2C communication, resets ENS160 and checks its PART_ID. Returns false on I2C problems or wrong PART_ID. + uint8_t revENS16x() { return this->_revENS16x; } // Report version of sensor (0: ENS160, 1: ENS161) + bool setMode(uint8_t mode); // Set operation mode of sensor + + bool initCustomMode(uint16_t stepNum); // Initialize definition of custom mode with steps + bool addCustomStep(uint16_t time, bool measureHP0, bool measureHP1, bool measureHP2, bool measureHP3, uint16_t tempHP0, uint16_t tempHP1, uint16_t tempHP2, uint16_t tempHP3); + // Add a step to custom measurement profile with definition of duration, enabled data acquisition and temperature for each hotplate + + bool readData (ENS160_DATA *data); + bool readStatus(uint8_t *status); + bool measure(bool waitForNew); // Perform measurement and stores result in internal variables + bool measureRaw(bool waitForNew); // Perform raw measurement and stores result in internal variables + bool set_envdata(float t, float h); // Writes t (degC) and h (%rh) to ENV_DATA. Returns "0" if I2C transmission is successful + bool set_envdata210(uint16_t t, uint16_t h); // Writes t and h (in ENS210 format) to ENV_DATA. Returns "0" if I2C transmission is successful + uint8_t getMajorRev() { return this->_fw_ver_major; } // Get major revision number of used firmware + uint8_t getMinorRev() { return this->_fw_ver_minor; } // Get minor revision number of used firmware + uint8_t getBuild() { return this->_fw_ver_build; } // Get build revision number of used firmware + + uint8_t getAQI() { return this->_data_aqi; } // Get AQI value of last measurement + uint16_t getTVOC() { return this->_data_tvoc; } // Get TVOC value of last measurement + uint16_t geteCO2() { return this->_data_eco2; } // Get eCO2 value of last measurement + uint16_t getAQI500() { return this->_data_aqi500; } // Get AQI500 value of last measurement + uint32_t getHP0() { return this->_hp0_rs; } // Get resistance of HP0 of last measurement + uint32_t getHP1() { return this->_hp1_rs; } // Get resistance of HP1 of last measurement + uint32_t getHP2() { return this->_hp2_rs; } // Get resistance of HP2 of last measurement + uint32_t getHP3() { return this->_hp3_rs; } // Get resistance of HP3 of last measurement + uint32_t getHP0BL() { return this->_hp0_bl; } // Get baseline resistance of HP0 of last measurement + uint32_t getHP1BL() { return this->_hp1_bl; } // Get baseline resistance of HP1 of last measurement + uint32_t getHP2BL() { return this->_hp2_bl; } // Get baseline resistance of HP2 of last measurement + uint32_t getHP3BL() { return this->_hp3_bl; } // Get baseline resistance of HP3 of last measurement + uint8_t getMISR() { return this->_misr; } // Return status code of sensor + + private: + I2cMaster i2cDevice; + bool reset(); // Sends a reset to the ENS160. Returns false on I2C problems. + bool checkPartID(); // Reads the part ID and confirms valid sensor + bool clearCommand(); // Initialize idle mode and confirms + bool getFirmware(); // Read firmware revisions + + uint8_t _revENS16x; // ENS160 or ENS161 connected? (FW >7) + + uint8_t _fw_ver_major; + uint8_t _fw_ver_minor; + uint8_t _fw_ver_build; + + uint16_t _stepCount; // Counter for custom sequence + + uint8_t _data_aqi; + uint16_t _data_tvoc; + uint16_t _data_eco2; + uint16_t _data_aqi500; + uint32_t _hp0_rs; + uint32_t _hp0_bl; + uint32_t _hp1_rs; + uint32_t _hp1_bl; + uint32_t _hp2_rs; + uint32_t _hp2_bl; + uint32_t _hp3_rs; + uint32_t _hp3_bl; + uint16_t _temp; + int _slaveaddr; // Slave address of the ENS160 + uint8_t _misr; + + uint8_t _seq_steps[1][8]; + + bool write8(byte reg, byte value); + bool read8 (byte reg, byte *value); + bool read16 (byte reg, uint16_t *value); + bool read16LE (byte reg, uint16_t *value); + bool readBytes (byte reg, uint8_t *bytes, uint8_t len); +}; + + +#endif diff --git a/software/nano-644/test_2024-07-23/src/adafruit/sensor.h b/software/nano-644/test_2024-07-23/src/adafruit/sensor.h new file mode 100644 index 0000000..ac7e454 --- /dev/null +++ b/software/nano-644/test_2024-07-23/src/adafruit/sensor.h @@ -0,0 +1,224 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software< /span> + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* Update by K. Townsend (Adafruit Industries) for lighter typedefs, and + * extended sensor support to include color, voltage and current */ + +#ifndef _ADAFRUIT_SENSOR_H +#define _ADAFRUIT_SENSOR_H + +#ifndef ARDUINO +#include +#elif ARDUINO >= 100 +#include "Arduino.h" +#include "Print.h" +#else +#include "WProgram.h" +#endif + +/* Constants */ +#define SENSORS_GRAVITY_EARTH (9.80665F) /**< Earth's gravity in m/s^2 */ +#define SENSORS_GRAVITY_MOON (1.6F) /**< The moon's gravity in m/s^2 */ +#define SENSORS_GRAVITY_SUN (275.0F) /**< The sun's gravity in m/s^2 */ +#define SENSORS_GRAVITY_STANDARD (SENSORS_GRAVITY_EARTH) +#define SENSORS_MAGFIELD_EARTH_MAX \ + (60.0F) /**< Maximum magnetic field on Earth's surface */ +#define SENSORS_MAGFIELD_EARTH_MIN \ + (30.0F) /**< Minimum magnetic field on Earth's surface */ +#define SENSORS_PRESSURE_SEALEVELHPA \ + (1013.25F) /**< Average sea level pressure is 1013.25 hPa */ +#define SENSORS_DPS_TO_RADS \ + (0.017453293F) /**< Degrees/s to rad/s multiplier \ + */ +#define SENSORS_RADS_TO_DPS \ + (57.29577793F) /**< Rad/s to degrees/s multiplier */ +#define SENSORS_GAUSS_TO_MICROTESLA \ + (100) /**< Gauss to micro-Tesla multiplier */ + +/** Sensor types */ +typedef enum { + SENSOR_TYPE_ACCELEROMETER = (1), /**< Gravity + linear acceleration */ + SENSOR_TYPE_MAGNETIC_FIELD = (2), + SENSOR_TYPE_ORIENTATION = (3), + SENSOR_TYPE_GYROSCOPE = (4), + SENSOR_TYPE_LIGHT = (5), + SENSOR_TYPE_PRESSURE = (6), + SENSOR_TYPE_PROXIMITY = (8), + SENSOR_TYPE_GRAVITY = (9), + SENSOR_TYPE_LINEAR_ACCELERATION = + (10), /**< Acceleration not including gravity */ + SENSOR_TYPE_ROTATION_VECTOR = (11), + SENSOR_TYPE_RELATIVE_HUMIDITY = (12), + SENSOR_TYPE_AMBIENT_TEMPERATURE = (13), + SENSOR_TYPE_OBJECT_TEMPERATURE = (14), + SENSOR_TYPE_VOLTAGE = (15), + SENSOR_TYPE_CURRENT = (16), + SENSOR_TYPE_COLOR = (17), + SENSOR_TYPE_TVOC = (18), + SENSOR_TYPE_VOC_INDEX = (19), + SENSOR_TYPE_NOX_INDEX = (20), + SENSOR_TYPE_CO2 = (21), + SENSOR_TYPE_ECO2 = (22), + SENSOR_TYPE_PM10_STD = (23), + SENSOR_TYPE_PM25_STD = (24), + SENSOR_TYPE_PM100_STD = (25), + SENSOR_TYPE_PM10_ENV = (26), + SENSOR_TYPE_PM25_ENV = (27), + SENSOR_TYPE_PM100_ENV = (28), + SENSOR_TYPE_GAS_RESISTANCE = (29), + SENSOR_TYPE_UNITLESS_PERCENT = (30), + SENSOR_TYPE_ALTITUDE = (31) +} sensors_type_t; + +/** struct sensors_vec_s is used to return a vector in a common format. */ +typedef struct { + union { + float v[3]; ///< 3D vector elements + struct { + float x; ///< X component of vector + float y; ///< Y component of vector + float z; ///< Z component of vector + }; ///< Struct for holding XYZ component + /* Orientation sensors */ + struct { + float roll; /**< Rotation around the longitudinal axis (the plane body, 'X + axis'). Roll is positive and increasing when moving + downward. -90 degrees <= roll <= 90 degrees */ + float pitch; /**< Rotation around the lateral axis (the wing span, 'Y + axis'). Pitch is positive and increasing when moving + upwards. -180 degrees <= pitch <= 180 degrees) */ + float heading; /**< Angle between the longitudinal axis (the plane body) + and magnetic north, measured clockwise when viewing from + the top of the device. 0-359 degrees */ + }; ///< Struct for holding roll/pitch/heading + }; ///< Union that can hold 3D vector array, XYZ components or + ///< roll/pitch/heading + int8_t status; ///< Status byte + uint8_t reserved[3]; ///< Reserved +} sensors_vec_t; + +/** struct sensors_color_s is used to return color data in a common format. */ +typedef struct { + union { + float c[3]; ///< Raw 3-element data + /* RGB color space */ + struct { + float r; /**< Red component */ + float g; /**< Green component */ + float b; /**< Blue component */ + }; ///< RGB data in floating point notation + }; ///< Union of various ways to describe RGB colorspace + uint32_t rgba; /**< 24-bit RGBA value */ +} sensors_color_t; + +/* Sensor event (36 bytes) */ +/** struct sensor_event_s is used to provide a single sensor event in a common + * format. */ +typedef struct { + int32_t version; /**< must be sizeof(struct sensors_event_t) */ + int32_t sensor_id; /**< unique sensor identifier */ + int32_t type; /**< sensor type */ + int32_t reserved0; /**< reserved */ + int32_t timestamp; /**< time is in milliseconds */ + union { + float data[4]; ///< Raw data */ + sensors_vec_t acceleration; /**< acceleration values are in meter per second + per second (m/s^2) */ + sensors_vec_t + magnetic; /**< magnetic vector values are in micro-Tesla (uT) */ + sensors_vec_t orientation; /**< orientation values are in degrees */ + sensors_vec_t gyro; /**< gyroscope values are in rad/s */ + float temperature; /**< temperature is in degrees centigrade (Celsius) */ + float distance; /**< distance in centimeters */ + float light; /**< light in SI lux units */ + float pressure; /**< pressure in hectopascal (hPa) */ + float relative_humidity; /**< relative humidity in percent */ + float current; /**< current in milliamps (mA) */ + float voltage; /**< voltage in volts (V) */ + float tvoc; /**< Total Volatile Organic Compounds, in ppb */ + float voc_index; /**< VOC (Volatile Organic Compound) index where 100 is + normal (unitless) */ + float nox_index; /**< NOx (Nitrogen Oxides) index where 100 is normal + (unitless) */ + float CO2; /**< Measured CO2 in parts per million (ppm) */ + float eCO2; /**< equivalent/estimated CO2 in parts per million (ppm + estimated from some other measurement) */ + float pm10_std; /**< Standard Particulate Matter <=1.0 in parts per million + (ppm) */ + float pm25_std; /**< Standard Particulate Matter <=2.5 in parts per million + (ppm) */ + float pm100_std; /**< Standard Particulate Matter <=10.0 in parts per + million (ppm) */ + float pm10_env; /**< Environmental Particulate Matter <=1.0 in parts per + million (ppm) */ + float pm25_env; /**< Environmental Particulate Matter <=2.5 in parts per + million (ppm) */ + float pm100_env; /**< Environmental Particulate Matter <=10.0 in parts per + million (ppm) */ + float gas_resistance; /**< Proportional to the amount of VOC particles in + the air (Ohms) */ + float unitless_percent; /** +#include + +#include "i2cmaster.hpp" + +I2cMaster::I2cMaster () { + address = 0; + timer = 0; +} + +void I2cMaster::tick1ms () { + if (timer > 0) { + timer--; + } +} + +bool I2cMaster::begin (uint8_t addr) { + this->address = addr; + // TWBR = 13; // 100kHz (TWPS1:0 = 00), TWBR = (F_CPU - 16 * 100000) / (2 * 100000 * 4); + TWBR = 100; // 50kHz (TWPS1:0 = 00), TWBR = (F_CPU - 16 * 50000) / (2 * 50000 * 4); + TWCR = (1 << TWEN); + return true; +} + +void I2cMaster::end () { + TWCR = (1 << TWEN); + TWBR = 0; +} + +bool I2cMaster::read (uint8_t *buffer, uint8_t len) { + if (start(true)) { + if (readBytes(buffer, len)) { + if (stop()) { + return true; + } + } + } + return false; +} + + +bool I2cMaster::write (const uint8_t *buffer, uint8_t len) { + if (start(false)) { + if (writeBytes(buffer, len)) { + if (stop()) { + return true; + } + } + } + return false; +} + +bool I2cMaster::writeByteAndBuffer (uint8_t byte, const uint8_t *buffer, uint8_t len) { + if (start(false)) { + do { + TWDR = byte; + TWCR = (1 << TWINT) | (1 << TWEN); // send byte + while (!(TWCR & (1 << TWINT))) {}; // wait until last action done + if ((TWSR & 0xf8) != 0x28) { + return false; + } + byte = *buffer++; + } while (len-- > 0); + return true; + } + return false; +} + + +bool I2cMaster::write_then_read (const uint8_t *write_buffer, uint8_t write_len, uint8_t *read_buffer, uint8_t read_len) { + if (start(false)) { + if (writeBytes(write_buffer, write_len)) { + if (start(true)) { + if (readBytes(read_buffer, read_len)) { + if (stop()) { + return true; + } + } + } + } + } + return false; +} + +// ------------------------------------------------------------- + +bool I2cMaster::readBytes (uint8_t *buffer, uint8_t len) { + while (len-- > 0) { + if (len > 0) { + TWCR = (1 << TWEA) | (1 << TWINT) | (1 << TWEN); // read data byte with ACK enabled + } else { + TWCR = (1 << TWINT) | (1 << TWEN); // read data byte with ACK disabled + } + while (!(TWCR & (1 << TWINT))) {}; // wait until last action done + uint8_t sr = TWSR & 0xf8; + if ((len > 0 && sr != 0x50) || (len == 0 && sr != 0x58)) { + return false; + } + *buffer++ = TWDR; + } + return true; +} + +bool I2cMaster::writeBytes (const uint8_t *buffer, uint8_t len) { + while (len-- > 0) { + // printf_P(PSTR("[wB:len=%d, byte=%02x]"), len + 1, *buffer); + TWDR = *buffer++; + TWCR = (1 << TWINT) | (1 << TWEN); // send data byte + timer = 5; + while (timer > 0 && !(TWCR & (1 << TWINT))) {}; // wait until last action done + if (!timer || (TWSR & 0xf8) != 0x28) { + return false; + } + } + return true; +} + + +bool I2cMaster::start (bool read) { + TWCR = (1 << TWINT) | (1 << TWSTA) | (1 << TWEN); // send START condition + timer = 5; + while (timer > 0 && !(TWCR & (1 << TWINT))) {}; // wait until last action done + uint8_t sr = TWSR & 0xf8; + if (!timer || (sr != 0x08 && sr != 0x10)) { + return false; + } + TWDR = (address << 1) | (read ? 1 : 0); // address + R/nW + TWCR = (1 << TWINT) | (1 << TWEN); // send address/RW + timer = 5; + while (timer > 0 && !(TWCR & (1 << TWINT))) {}; // wait until last action done + sr = TWSR & 0xf8; + if (!timer || (!read && sr != 0x18) || (read && sr != 0x40)) { + return false; + } + return true; +} + +bool I2cMaster::stop () { + TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWSTO); + while (TWCR & ( 1 << TWSTO)); + return true; +} + diff --git a/software/nano-644/test_2024-07-23/src/i2cmaster.hpp b/software/nano-644/test_2024-07-23/src/i2cmaster.hpp new file mode 100644 index 0000000..e70326c --- /dev/null +++ b/software/nano-644/test_2024-07-23/src/i2cmaster.hpp @@ -0,0 +1,28 @@ +#ifndef I2C_MASTER +#define I2C_MASTER + +#include + +class I2cMaster { + public: + static void end (); + + public: + I2cMaster (); + void tick1ms (); + bool begin (uint8_t addr); + bool read (uint8_t *buffer, uint8_t len); + bool write(const uint8_t *buffer, uint8_t len); + bool write_then_read(const uint8_t *write_buffer, uint8_t write_len, uint8_t *read_buffer, uint8_t read_len); + bool writeByteAndBuffer (uint8_t byte, const uint8_t *buffer, uint8_t len); + + private: + uint8_t address; + uint8_t timer; + bool start (bool read); + bool stop (); + bool writeBytes (const uint8_t *buffer, uint8_t len); + bool readBytes (uint8_t *buffer, uint8_t len); +}; + +#endif \ No newline at end of file diff --git a/software/nano-644/test_2024-07-23/src/i2cslave.cpp b/software/nano-644/test_2024-07-23/src/i2cslave.cpp new file mode 100644 index 0000000..2bf6ac2 --- /dev/null +++ b/software/nano-644/test_2024-07-23/src/i2cslave.cpp @@ -0,0 +1,92 @@ +#include +#include +#include + +#include "i2cslave.hpp" + +I2cSlave::I2cSlave () { + timer = 0; + fromMaster.rIndex = 0; + fromMaster.wIndex = 0; + toMaster.rIndex = 0; + toMaster.wIndex = 0; +} + +void I2cSlave::tick1ms () { + if (timer > 0) { + timer--; + } +} + +bool I2cSlave::begin (uint8_t addr, bool acceptGeneralCalls) { + if (addr > 127) { + return false; + } + TWAR = addr << 1 | (acceptGeneralCalls ? 1 : 0); + TWBR = 100; // 50kHz (TWPS1:0 = 00), TWBR = (F_CPU - 16 * 50000) / (2 * 50000 * 4); + TWCR = (1 << TWEA) | (1 << TWEN) | (1 << TWIE); + return true; +} + +void I2cSlave::end () { + TWCR = (1 << TWEN); + TWBR = 0; +} + +int I2cSlave::read () { + return getByte(fromMaster); +} + +void I2cSlave::write (uint8_t byte) { + putByte(toMaster, byte); +} + + +void I2cSlave::putByte (RingBuffer& buffer, uint8_t byte) { + ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { + buffer.data[buffer.wIndex++] = byte; + if (buffer.wIndex >= sizeof(buffer.data)) { + buffer.wIndex = 0; + } + if (buffer.wIndex == buffer.rIndex) { + buffer.rIndex++; + if (buffer.rIndex >= sizeof(buffer.data)) { + buffer.rIndex = 0; + } + } + } +} + +int I2cSlave::getByte (RingBuffer& buffer) { + uint8_t b; + ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { + if (buffer.rIndex == buffer.wIndex) { + return EOF; + } + b = buffer.data[buffer.rIndex++]; + if (buffer.rIndex >= sizeof(buffer.data)) { + buffer.rIndex = 0; + } + } + return b; +} + +void I2cSlave::handleTWIIsr () { + uint8_t sr = TWSR & 0xf8; + switch (sr) { + case 0x80: { // Previously addressed with own SLA+W; data has been received; ACK has been returned + putByte(fromMaster, TWDR); + TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWIE); // no TWEA -> only one byte accepted + break; + } + case 0xa8: { // Own SLA+R has been received; ACK has been returned + int response = getByte(toMaster);; + TWDR = response < 0 ? 0x00 : (uint8_t)response; + TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWIE); // no TWEA -> only one byte accepted + break; + } + default: TWCR = (1 << TWINT) | (1 << TWEA) | (1 << TWEN) | (1 << TWIE); break; + } + +} + diff --git a/software/nano-644/test_2024-07-23/src/i2cslave.hpp b/software/nano-644/test_2024-07-23/src/i2cslave.hpp new file mode 100644 index 0000000..2fe2dc7 --- /dev/null +++ b/software/nano-644/test_2024-07-23/src/i2cslave.hpp @@ -0,0 +1,32 @@ +#ifndef I2C_SLAVE +#define I2C_SLAVE + +#include + +class I2cSlave { + private: + typedef struct { + uint8_t rIndex; + uint8_t wIndex; + uint8_t data[8]; + } RingBuffer; + + public: + I2cSlave (); + void tick1ms (); + bool begin (uint8_t addr, bool acceptGeneralCalls); + void end (); + void handleTWIIsr (); + int read (); + void write (uint8_t byte); + + private: + uint8_t timer; + RingBuffer fromMaster; + RingBuffer toMaster; + void putByte (RingBuffer& buffer, uint8_t byte); + int getByte (RingBuffer& buffer); + +}; + +#endif \ No newline at end of file diff --git a/software/test_2024-07-23/src/main.cpp b/software/nano-644/test_2024-07-23/src/main.cpp similarity index 91% rename from software/test_2024-07-23/src/main.cpp rename to software/nano-644/test_2024-07-23/src/main.cpp index c363d60..0223927 100644 --- a/software/test_2024-07-23/src/main.cpp +++ b/software/nano-644/test_2024-07-23/src/main.cpp @@ -1,7 +1,9 @@ #include +#include +#include #include + #include -#include #include #include "main.hpp" @@ -56,7 +58,7 @@ extern "C" { // // nothing in buffer // return EOF; // } - // printf(" r%d", rIndex); + // printf_P(PSTR(" r%d"), rIndex); while (rIndex == wIndex) { // wait for character } @@ -65,7 +67,7 @@ extern "C" { // char c = uartBuffer[rIndex++]; uint8_t c = uartBuffer[rIndex++]; - // printf("(%02x) ", c); + // printf_P(PSTR("(%02x) "), c); if (c == '\r') { c = '\n'; } @@ -150,23 +152,24 @@ int main () { uint16_t i; char s[4]; do { - printf("\n\n=============================\n\n"); - printf("Available units:\n\n"); + printf_P(PSTR("\n\n=============================\n\n")); + printf_P(PSTR("Available units:\n\n")); for (i = 0; i < sizeof(unit) / sizeof(unit[0]); i++) { TestUnit *pu = unit[i]; - printf("%3x ... %s\n", i, pu->getName()); + printf_P(PSTR("%3x ... "), i); + printf_P(pu->getName()); } - printf("\nSelect unit: "); + printf_P(PSTR("\nSelect unit: ")); rIndex = 0; wIndex = 0; fgets(s, sizeof(s), stdin); } while (sscanf(s, "%x", &i) != 1 || i < 0 || i >= sizeof(unit) / sizeof(unit[0]) ); TestUnit *pu = unit[i]; - printf("\n\n[%s]: ", pu->getName()); + printf_P(PSTR("\n\n[%s]: "), pu->getName()); keyUart0 = EOF; for (uint8_t subtest = 0; subtest < 0xff; subtest++) { - printf("\n%4d: ", subtest); + printf_P(PSTR("\n%4d: "), subtest); if (pu->run(subtest) < 0) { break; } @@ -192,7 +195,7 @@ ISR (USART0_RX_vect) { uint8_t b = UDR0; keyUart0 = b; uartBuffer[wIndex++] = b; - // printf(" w%d(%02x)", wIndex, b); + // printf_P(PSTR(" w%d(%02x)"), wIndex, b); if (wIndex == rIndex) { // buffer overflow, kick out oldest byte rIndex++; diff --git a/software/nano-644/test_2024-07-23/src/main.hpp b/software/nano-644/test_2024-07-23/src/main.hpp new file mode 100644 index 0000000..f60ec89 --- /dev/null +++ b/software/nano-644/test_2024-07-23/src/main.hpp @@ -0,0 +1,20 @@ +#ifndef MAIN_HPP +#define MAIN_HPP + +#include +#include + +#define ENTER '\r' +#define CTRLC '\003' + +extern int wait (uint32_t ms); +extern uint64_t millis (); + +class TestUnit { + public: + virtual int8_t run (uint8_t subtest) = 0; + virtual void cleanup () = 0; + virtual PGM_P getName () = 0; +}; + +#endif \ No newline at end of file diff --git a/software/nano-644/test_2024-07-23/src/units/encoder.cpp b/software/nano-644/test_2024-07-23/src/units/encoder.cpp new file mode 100644 index 0000000..bc84f48 --- /dev/null +++ b/software/nano-644/test_2024-07-23/src/units/encoder.cpp @@ -0,0 +1,86 @@ +#include +#include + +#include "encoder.hpp" +#include "../main.hpp" + +// PB0/T0 ... Encoder A +// PB1/T1 ... Encoder B +// PB2/INT2 ... push switch of encoder (pushed = 0) + +// Encoder signals on rotation clockwise 1 step: +// A -----____------ one char app. 1ms..2ms (rotation speed) +// B -------___----- +// one step when: A = 0, B= 1->0 + +// Encoder signals on rotation counterclockwise 1 step: +// A -----____------ one char app. 1ms..2ms (rotation speed) +// B --______----- +// one step when: A = 0, B= 0->1 + + +void Encoder::cleanup () { + DDRB &= ~((1 << PB2) | (1 << PB1) | (1 << PB0)); + PORTB &= ~((1 << PORTB2) | (1 << PORTB1) | (1 << PORTB0)); + enabled = 0; +} + +int8_t Encoder::run (uint8_t subtest) { + switch (subtest) { + case 0: { + printf_P(PSTR("init")); + DDRB &= ~((1 << PB2) | (1 << PB1) | (1 << PB0)); + PORTB |= (1 << PORTB2) | (1 << PORTB1) | (1 << PORTB0); // enable pullup + enabled = 1; + return 0; + } + + case 1: { + while (wait(10) == EOF) { + printf_P(PSTR("\r => Encoder (push to clear): ")); + printf_P(PSTR("%5d (0x%02x) "), count, (uint8_t)count); + if ((PINB & (1 << PINB2)) == 0) { + reset(); + } + } + return 0; + } + + case 2: { + printf_P(PSTR("end")); + break; + } + } + + return -1; +} + +struct EncoderState { + uint8_t a:1; // signal A + uint8_t b:1; // signal B +}; + +void Encoder::tick100us () { + static EncoderState lastState = { 1, 1 }; + static EncoderState lastStableState = { 1, 1 }; + + if ((DDRB & 0x03) || (PORTB & 0x07) != 0x07) { + count = 0; + return; // Enocder pins not configured + } + EncoderState nextState = { (PINB & 0x01) == 0x01, (PINB & 0x02) == 0x02 }; + if (nextState.a == lastState.a && nextState.b == lastState.b) { + if (lastStableState.a == 0 && nextState.b != lastStableState.b) { + if (nextState.b == 0) { + count = count < 127 ? count + 1 : 127; + } else { + count = count > -128 ? count - 1 : -128; + } + } + lastStableState.a = nextState.a; + lastStableState.b = nextState.b; + } + lastState.a = nextState.a; + lastState.b = nextState.b; +} + diff --git a/software/nano-644/test_2024-07-23/src/units/encoder.hpp b/software/nano-644/test_2024-07-23/src/units/encoder.hpp new file mode 100644 index 0000000..10bcc0f --- /dev/null +++ b/software/nano-644/test_2024-07-23/src/units/encoder.hpp @@ -0,0 +1,22 @@ +#ifndef ENCODER_HPP +#define ENCODER_PP + +#include +#include "../main.hpp" +#include + +class Encoder : public TestUnit { + public: + uint8_t enabled; + int8_t count; + + public: + Encoder () { reset(); enabled = 0; }; + virtual void cleanup (); + virtual int8_t run (uint8_t subtest); + virtual PGM_P getName () { return PSTR("Encoder"); } + void reset () { count = 0; } + void tick100us (); +}; + +#endif \ No newline at end of file diff --git a/software/nano-644/test_2024-07-23/src/units/i2c.cpp b/software/nano-644/test_2024-07-23/src/units/i2c.cpp new file mode 100644 index 0000000..4c5934f --- /dev/null +++ b/software/nano-644/test_2024-07-23/src/units/i2c.cpp @@ -0,0 +1,300 @@ +#include +#include +#include +#include +#include + +#include "i2c.hpp" +#include "../adafruit/bme280.h" +#include "../main.hpp" + +// Sparkfun https://www.sparkfun.com/products/22858 +// ENS160 address 0x53 (air quality sensor) +// BME280 address 0x77 /humidity/temperature sensor) +// register 0xfe: humidity_7:0 +// register 0xfd: humidity_15:8 + +PGM_P I2c::getName () { + switch (mode) { + case SparkFunEnvCombo: return PSTR("I2C-Sparkfun Env-Combo"); + case Master: return PSTR("I2C-Master"); + case Slave: return PSTR("I2C-Slave"); + } + return "?"; +} + +void I2c::cleanup () { + enabled = false; + TWCR = (1 << TWEN); + TWBR = 0; + ADMUX = 0; + ADCSRA = 0; +} + +int8_t I2c::run (uint8_t subtest) { + if (subtest == 0) { + TWBR = 13; // 100kHz (TWPS1:0 = 00), TWBR = (F_CPU - 16 * 100000) / (2 * 100000 * 4); + TWBR = 28; // 50kHz (TWPS1:0 = 00), TWBR = (F_CPU - 16 * 50000) / (2 * 50000 * 4); + TWBR = 100; // 50kHz (TWPS1:0 = 00), TWBR = (F_CPU - 16 * 50000) / (2 * 50000 * 4); + TWCR = (1 << TWEN); + ADMUX = (1 << ADLAR) | (1 << REFS0); // ADC0, VREF=AVCC=3.3V + ADCSRA = (1 << ADEN) | 7; // ADC Enable, Prescaler 128 + enabled = true; + printf_P(PSTR("init")); + + } else if (subtest == 1 && mode == I2c::SparkFunEnvCombo) { + printf_P(PSTR(" BM280 ... ")); + if (!bm280.begin()) { + printf_P(PSTR("E1")); + return -1; + } + printf_P(PSTR("OK, ENS160 ... ")); + if (!ens160.begin()) { + printf_P(PSTR("E2")); + return -1; + } + if (!ens160.setMode(ENS160_OPMODE_STD)) { + printf_P(PSTR("E3")); + return -1; + } + if (!ens160.set_envdata(25.0, 65)) { + printf_P(PSTR("E4")); + return -1; + } + + printf_P(PSTR("OK")); + float accTemp = 0, accHumidity = 0; + int8_t accCount = -1; + + do { + // BME280 + float p = bm280.readPressure(); + printf_P(PSTR("\n => BM280: P= %.3fbar"), (double)p / 100000.0); + float t = bm280.readTemperature(); + printf_P(PSTR(", T= %.2f°C"), (double)t); + float h = bm280.readHumidity(); + printf_P(PSTR(", H= %.2f%%"), (double)h); + + if (accCount >= 0 && !isnanf(h) && !isnan(t)) { + accTemp += t; + accHumidity += h; + accCount++; + } + + bm280.setSampling( + Adafruit_BME280::MODE_NORMAL, + Adafruit_BME280::SAMPLING_X16, + Adafruit_BME280::SAMPLING_X16, + Adafruit_BME280::SAMPLING_X16, + Adafruit_BME280::FILTER_OFF, + Adafruit_BME280::STANDBY_MS_1000 + ); + + // ENS160 only activated every 32s to avoid wrong temperature measuerment + // if ES160 would be continously active, the temperature would be 4°C higher + // -> ES160 has not enough distance to BM280 + // This solution causes only a +0.3°C higher temperatur value + if (accCount < 0 || accCount >= 32) { + printf_P(PSTR(" | ENS160 (")); + if (accCount > 0) { + h = accHumidity / accCount; + t = accTemp / accCount; + accTemp = 0; + accHumidity = 0; + } + accCount = 0; + if (!ens160.set_envdata(t, h)) { + printf_P(PSTR("E1)")); + } else { + printf_P(PSTR("%.1f°C/%.1f%%): "), (double)t, (double)h); + if (!ens160.setMode(ENS160_OPMODE_STD)) { + printf_P(PSTR("E2")); + } else { + for (uint8_t i = 0; i < 100; i++) { + _delay_ms(15); + uint8_t status; + if (ens160.readStatus(&status)) { + if (status & ENS160_DATA_STATUS_NEWDAT) { + ENS160_DATA data; + if (ens160.readData(&data)) { + printf_P(PSTR(" aqi=%d("), data.aqi); + switch(data.aqi) { + case 1: printf_P(PSTR("excellent")); break; + case 2: printf_P(PSTR("good")); break; + case 3: printf_P(PSTR("moderate")); break; + case 4: printf_P(PSTR("poor")); break; + case 5: printf_P(PSTR("unhealthy")); break; + default: printf_P(PSTR("?")); break; + } + printf_P(PSTR("), tvoc=%dppb"), data.tvoc); + printf_P(PSTR(", eco2=%d("), data.eco2); + if (data.eco2 < 400) { + printf_P(PSTR("?")); + } else if (data.eco2 < 600) { + printf_P(PSTR("excellent")); + } else if (data.eco2 < 800) { + printf_P(PSTR("good")); + } else if (data.eco2 < 1000) { + printf_P(PSTR("fair")); + } else if (data.eco2 < 1500) { + printf_P(PSTR("poor")); + } else { + printf_P(PSTR("bad")); + } + printf_P(PSTR(")")); + } + break; + } + } + } + } + if (!ens160.setMode(ENS160_OPMODE_IDLE)) { + printf_P(PSTR("E3")); + } + } + } + + } while (wait(1000) == EOF); + + } else if (subtest == 1 && mode == I2c::Master) { + if (!master.begin(0x01)) { + printf_P(PSTR("E1")); + return -1; + } + do { + uint8_t buffer[1]; + // read poti + ADCSRA |= (1 << ADSC); // start ADC + while (ADCSRA & (1 << ADSC)) {} // wait for result + buffer[0] = ADCH; + printf_P(PSTR("\n write 0x%02x"), buffer[0]); + if (!master.write(buffer, 1)) { + printf_P(PSTR(" -> ERROR")); + } + printf_P(PSTR(", read ")); + if (master.read(buffer, 1)) { + printf_P(PSTR("0x%02x"), buffer[0]); + } else { + printf_P(PSTR(" -> ERROR")); + } + } while (wait(1000) == EOF); + master.end(); + + } else if (subtest == 1 && mode == I2c::Slave) { + if (!slave.begin(0x01, false)) { + printf_P(PSTR("E1")); + return -1; + } + do { + int fromMaster = slave.read(); + if (fromMaster != EOF) { + ADCSRA |= (1 << ADSC); // start ADC + while (ADCSRA & (1 << ADSC)) {} // wait for result + slave.write(ADCH); + printf_P(PSTR("\n => from master: 0x%02x -> to master: 0x%02x"), fromMaster, ADCH); + } + } while (wait(0) == EOF); + slave.end(); + + } else { + printf_P(PSTR("end")); + return -1; + } + wait(500); + return 0; +} + +void I2c::handleTwiIrq () { + if (mode == I2c::Slave) { + DDRD |= (1 << PD7); + PORTD |= (1 << PD7); + slave.handleTWIIsr(); + PORTD &= ~(1 << PD7); + } else { + TWCR |= (1 << TWINT); // clear Interrupt Request + } +} + +// uint16_t I2c::startRead (uint8_t address) { +// TWCR = (1 << TWINT) | (1 << TWSTA) | (1 << TWEN); // send START condition +// while (!(TWCR & (1 << TWINT))) {}; // wait until last action done +// uint8_t sr = TWSR & 0xf8; +// if (sr != 0x08 && sr != 0x10) { +// return 0x0100 | sr; +// } + +// TWDR = (address << 1) | 0x01; // address + READ (R/W = 1) +// TWCR = (1 << TWINT) | (1 << TWEN); // send address/RW +// while (!(TWCR & (1 << TWINT))) {}; // wait until last action done +// sr = TWSR & 0xf8; +// if (sr != 0x40) { +// return 0x0200 | sr; +// } +// return 0; +// } + +// uint16_t I2c::startWrite (uint8_t address) { +// TWCR = (1 << TWINT) | (1 << TWSTA) | (1 << TWEN); // send START condition +// while (!(TWCR & (1 << TWINT))) {}; // wait until last action done +// uint8_t sr = TWSR & 0xf8; +// if (sr != 0x08 && sr != 0x10) { +// return 0x0300 | sr; +// } + +// TWDR = (address << 1) | 0x00; // address + WRITE (R/W = 0) +// TWCR = (1 << TWINT) | (1 << TWEN); // send address/RW +// while (!(TWCR & (1 << TWINT))) {}; // wait until last action done +// sr = TWSR & 0xf8; +// if (sr != 0x18) { +// return 0x0400 | sr; +// } +// return 0; +// } + +// void I2c::stop () { +// TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWSTO); +// } + +// uint16_t I2c::writeData (uint8_t size, const uint8_t *data) { +// while (size-- > 0) { +// TWDR = *data++; +// TWCR = (1 << TWINT) | (1 << TWEN); // send data byte +// while (!(TWCR & (1 << TWINT))) {}; // wait until last action done +// uint8_t sr = TWSR & 0xf8; +// if (sr != 0x28) { +// return 0x0500 | sr; +// } +// } +// return 0; +// } + +// uint16_t I2c::writeByte (uint8_t data) { +// return writeData(1, &data); +// } + +// uint16_t I2c::readData (uint8_t size, uint8_t *data) { +// while (size-- > 0) { +// if (size > 0) { +// TWCR = (1 << TWEA) | (1 << TWINT) | (1 << TWEN); // read data byte with ACK enabled +// } else { +// TWCR = (1 << TWINT) | (1 << TWEN); // read data byte with ACK disabled +// } +// while (!(TWCR & (1 << TWINT))) {}; // wait until last action done +// uint8_t sr = TWSR & 0xf8; +// if ((size > 0 && sr != 0x50) || (size == 0 && sr != 0x58)) { +// return 0x0600 | sr; +// } +// *data++ = TWDR; +// } +// return 0; +// } + +// int32_t I2c::compensateBm280T (int32_t adcT) { +// // int32_t var1, var2, t; +// // var1 = ((((adcT >> 3) - ((int32_t)bm280.digT[0] << 1))) * ((int32_t)bm280.digT[1])) >> 11; +// // var2 = (((((adcT >> 4) - ((int32_t)bm280.digT[0])) * ((adcT >> 4) - ((int32_t)bm280.digT[0]))) >> 12) * ((int32_t)bm280.digT[2])) >> 14; +// // bm280.tFine = var1 + var2; +// // t = (bm280.tFine * 5 + 128) >> 8; +// // return t; +// return -1; +// } diff --git a/software/nano-644/test_2024-07-23/src/units/i2c.hpp b/software/nano-644/test_2024-07-23/src/units/i2c.hpp new file mode 100644 index 0000000..e1f1802 --- /dev/null +++ b/software/nano-644/test_2024-07-23/src/units/i2c.hpp @@ -0,0 +1,42 @@ +#ifndef I2C_HPP +#define I2C_HPP + +#include +#include "../main.hpp" +#include "../adafruit/bme280.h" +#include "../adafruit/ens160.h" +#include "../i2cmaster.hpp" +#include "../i2cslave.hpp" + + +class I2c : public TestUnit { + public: + typedef enum I2cMode { SparkFunEnvCombo, Master, Slave } I2cMode; + + private: + I2cMode mode; + Adafruit_BME280 bm280; + ScioSense_ENS160 ens160; + I2cMaster master; + I2cSlave slave; + + public: + bool enabled; + + public: + I2c (I2cMode mode) { enabled = false; this->mode = mode; } + void tick1ms () { master.tick1ms(); slave.tick1ms(); } + virtual void cleanup (); + virtual int8_t run (uint8_t subtest); + virtual PGM_P getName (); + void handleTwiIrq (); + uint16_t startRead (uint8_t address); + uint16_t startWrite (uint8_t address); + void stop (); + uint16_t writeByte (uint8_t data); + uint16_t writeData (uint8_t size, const uint8_t *data); + uint16_t readData (uint8_t size, uint8_t *data); + int32_t compensateBm280T (int32_t adcT); +}; + +#endif \ No newline at end of file diff --git a/software/test_2024-07-23/src/units/ieee485.cpp b/software/nano-644/test_2024-07-23/src/units/ieee485.cpp similarity index 91% rename from software/test_2024-07-23/src/units/ieee485.cpp rename to software/nano-644/test_2024-07-23/src/units/ieee485.cpp index 4fba45f..89e25ec 100644 --- a/software/test_2024-07-23/src/units/ieee485.cpp +++ b/software/nano-644/test_2024-07-23/src/units/ieee485.cpp @@ -53,7 +53,7 @@ int8_t Ieee485::run (uint8_t subtest) { UBRR1L = F_CPU / 8 / 9600 - 1; enabled = 1; - printf("init"); + printf_P(PSTR("init")); } else if (subtest == 1) { CLR_nRE; CLR_DE; @@ -67,19 +67,19 @@ int8_t Ieee485::run (uint8_t subtest) { while ((UCSR1A & (1 << TXC1)) == 0) {} CLR_DE; CLR_nRE; - printf("\n => send Byte 0x%02x", ADCH); + printf_P(PSTR("\n => send Byte 0x%02x"), ADCH); int b; ATOMIC_BLOCK(ATOMIC_FORCEON) { b = receivedByte; receivedByte = -1; } if (b >= 0) { - printf("\n => receive Byte: 0x%02x", b); + printf_P(PSTR("\n => receive Byte: 0x%02x"), b); } } } else { - printf("end"); + printf_P(PSTR("end")); return -1; } diff --git a/software/nano-644/test_2024-07-23/src/units/ieee485.hpp b/software/nano-644/test_2024-07-23/src/units/ieee485.hpp new file mode 100644 index 0000000..677963f --- /dev/null +++ b/software/nano-644/test_2024-07-23/src/units/ieee485.hpp @@ -0,0 +1,21 @@ +#ifndef IEEE485_HPP +#define IEEE485_HPP + +#include +#include "../main.hpp" +#include + +class Ieee485 : public TestUnit { + public: + uint8_t enabled; + int16_t receivedByte; + + public: + Ieee485 () { enabled = 0; receivedByte = -1; } + virtual void cleanup (); + virtual int8_t run (uint8_t subtest); + virtual const char *getName () { return PSTR("IEEE485"); } + void handleRxByte (uint8_t); +}; + +#endif \ No newline at end of file diff --git a/software/test_2024-07-23/src/units/lcd.cpp b/software/nano-644/test_2024-07-23/src/units/lcd.cpp similarity index 97% rename from software/test_2024-07-23/src/units/lcd.cpp rename to software/nano-644/test_2024-07-23/src/units/lcd.cpp index 0781b6a..91d0845 100644 --- a/software/test_2024-07-23/src/units/lcd.cpp +++ b/software/nano-644/test_2024-07-23/src/units/lcd.cpp @@ -65,9 +65,9 @@ int8_t Lcd::run (uint8_t subtest) { // DDRB = 0xff; init(); #ifdef LCD_3V3 - printf("init 3.3V LCD"); + printf_P(PSTR("init 3.3V LCD")); #else - printf("init 5V LCD"); + printf_P(PSTR("init 5V LCD")); #endif } else if (subtest == 1) { @@ -87,12 +87,12 @@ int8_t Lcd::run (uint8_t subtest) { // writeString("uvwxyzABCDEFGHIJKLMN"); // setCursor(4, 1); // writeString("OPQRSTUVWXYZ "); - printf("LCD beschrieben"); + printf_P(PSTR("LCD beschrieben")); while (wait(1) == EOF) { } } else { - printf("end"); + printf_P(PSTR("end")); return -1; } wait(500); diff --git a/software/test_2024-07-23/src/units/lcd.hpp b/software/nano-644/test_2024-07-23/src/units/lcd.hpp similarity index 83% rename from software/test_2024-07-23/src/units/lcd.hpp rename to software/nano-644/test_2024-07-23/src/units/lcd.hpp index 11e7749..14561b0 100644 --- a/software/test_2024-07-23/src/units/lcd.hpp +++ b/software/nano-644/test_2024-07-23/src/units/lcd.hpp @@ -3,13 +3,14 @@ #include #include "../main.hpp" +#include class Lcd : public TestUnit { public: Lcd () {}; virtual void cleanup (); virtual int8_t run (uint8_t subtest); - virtual const char *getName () { return "Lcd"; } + virtual PGM_P getName () { return PSTR("Lcd"); } void init (); uint8_t isBusy (); diff --git a/software/test_2024-07-23/src/units/led.cpp b/software/nano-644/test_2024-07-23/src/units/led.cpp similarity index 86% rename from software/test_2024-07-23/src/units/led.cpp rename to software/nano-644/test_2024-07-23/src/units/led.cpp index fe48a40..a35ca81 100644 --- a/software/test_2024-07-23/src/units/led.cpp +++ b/software/nano-644/test_2024-07-23/src/units/led.cpp @@ -14,16 +14,16 @@ int8_t Led::run (uint8_t subtest) { if (subtest == 0) { DDRD |= (1 << DDD7) | (1 << DDD6) | (1 << DDD5) | (1 << DDD4); PORTD &= ~((1 << PORTD7) | (1 << PORTD6) | (1 << PORTD5) | (1 << PORTD4)); - printf("init"); + printf_P(PSTR("init")); } else if (subtest <= 16) { subtest = (subtest - 1) % 4; PORTD &= ~((1 << PORTD7) | (1 << PORTD6) | (1 << PORTD5) | (1 << PORTD4)); PORTD |= (1 << (subtest + 4)); - printf("Test LED PD%d", subtest + 4); + printf_P(PSTR("Test LED PD%d"), subtest + 4); } else { - printf("end"); + printf_P(PSTR("end")); return -1; } wait(500); diff --git a/software/test_2024-07-23/src/units/led.hpp b/software/nano-644/test_2024-07-23/src/units/led.hpp similarity index 71% rename from software/test_2024-07-23/src/units/led.hpp rename to software/nano-644/test_2024-07-23/src/units/led.hpp index a76983b..acff045 100644 --- a/software/test_2024-07-23/src/units/led.hpp +++ b/software/nano-644/test_2024-07-23/src/units/led.hpp @@ -3,13 +3,14 @@ #include #include "../main.hpp" +#include class Led : public TestUnit { public: Led () {}; virtual void cleanup (); virtual int8_t run (uint8_t subtest); - virtual const char *getName () { return "Led"; } + virtual PGM_P getName () { return PSTR("Led"); } }; #endif \ No newline at end of file diff --git a/software/test_2024-07-23/src/units/modbus.cpp b/software/nano-644/test_2024-07-23/src/units/modbus.cpp similarity index 82% rename from software/test_2024-07-23/src/units/modbus.cpp rename to software/nano-644/test_2024-07-23/src/units/modbus.cpp index 28b1bca..ec74d50 100644 --- a/software/test_2024-07-23/src/units/modbus.cpp +++ b/software/nano-644/test_2024-07-23/src/units/modbus.cpp @@ -43,7 +43,7 @@ int8_t Modbus::run (uint8_t subtest) { UBRR1L = F_CPU / 8 / 9600 - 1; enabled = 1; - printf("init"); + printf_P(PSTR("init")); } else if (subtest >= 1 && subtest <= 4) { uint8_t nre, de, b; @@ -54,7 +54,7 @@ int8_t Modbus::run (uint8_t subtest) { case 4: nre = 0; de = 1; b = 0xaa; break; default: return -1; } - printf(" DE=%u, nRE=%u send 0x%02x... ", de, nre, b); + printf_P(PSTR(" DE=%u, nRE=%u send 0x%02x... "), de, nre, b); if (nre) { SET_nRE; } else { @@ -70,19 +70,19 @@ int8_t Modbus::run (uint8_t subtest) { UDR1 = b; _delay_ms(1); if (receivedBytes > 0) { - printf("0x%02x received", received[0]); + printf_P(PSTR("0x%02x received"), received[0]); receivedBytes = 0; } else { - printf("no byte received"); + printf_P(PSTR("no byte received")); } - printf(" ... press key to proceed"); + printf_P(PSTR(" ... press key to proceed")); while (wait(0xffffffff) == EOF) {} CLR_DE; SET_nRE; } else if (subtest == 5) { static uint8_t frame[] = { 0x01, 0x04, 0x00, 0x00, 0x00, 0x02, 0x71, 0xcb }; - printf("Modbus: lese Spannung von Eastron SDM-230 (Einphasenzähler)"); + printf_P(PSTR("Modbus: lese Spannung von Eastron SDM-230 (Einphasenzähler)")); SET_DE; CLR_nRE; _delay_us(100); @@ -96,21 +96,21 @@ int8_t Modbus::run (uint8_t subtest) { } while ((UCSR1A & (1 << TXC1)) == 0) {} CLR_DE; - printf("\n => Sending:"); + printf_P(PSTR("\n => Sending:")); for (uint8_t i = 0; i < sizeof(frame); i++) { - printf(" 0x%02x", frame[i]); + printf_P(PSTR(" 0x%02x"), frame[i]); } int k = wait(100); - printf("\n RxD1:"); + printf_P(PSTR("\n RxD1:")); if (receivedBytes == 0) { - printf("?"); + printf_P(PSTR("?")); } else { for (uint8_t i = 0; i < receivedBytes; i++) { if (i == sizeof(frame)) { - printf(" "); + printf_P(PSTR(" ")); } - printf(" 0x%02x", received[i]); + printf_P(PSTR(" 0x%02x"), received[i]); } } if (receivedBytes >= 16) { @@ -122,7 +122,7 @@ int8_t Modbus::run (uint8_t subtest) { f.b[1] = received[13]; f.b[2] = received[12]; f.b[3] = received[11]; - printf(" -> %4.8fV\n", (double)f.value); + printf_P(PSTR(" -> %4.8fV\n"), (double)f.value); } if (k != EOF) { break; @@ -131,7 +131,7 @@ int8_t Modbus::run (uint8_t subtest) { } while (wait(1000) == EOF); } else { - printf("end"); + printf_P(PSTR("end")); return -1; } wait(500); diff --git a/software/test_2024-07-23/src/units/modbus.hpp b/software/nano-644/test_2024-07-23/src/units/modbus.hpp similarity index 81% rename from software/test_2024-07-23/src/units/modbus.hpp rename to software/nano-644/test_2024-07-23/src/units/modbus.hpp index 14580f8..d0f6c48 100644 --- a/software/test_2024-07-23/src/units/modbus.hpp +++ b/software/nano-644/test_2024-07-23/src/units/modbus.hpp @@ -3,6 +3,7 @@ #include #include "../main.hpp" +#include class Modbus : public TestUnit { public: @@ -15,7 +16,7 @@ class Modbus : public TestUnit { Modbus () { enabled = 0; receivedBytes = 0; } virtual void cleanup (); virtual int8_t run (uint8_t subtest); - virtual const char *getName () { return "Modbus"; } + virtual PGM_P getName () { return PSTR("Modbus"); } void handleRxByte (uint8_t); }; diff --git a/software/test_2024-07-23/src/units/motor.cpp b/software/nano-644/test_2024-07-23/src/units/motor.cpp similarity index 87% rename from software/test_2024-07-23/src/units/motor.cpp rename to software/nano-644/test_2024-07-23/src/units/motor.cpp index be6abd8..429d39a 100644 --- a/software/test_2024-07-23/src/units/motor.cpp +++ b/software/nano-644/test_2024-07-23/src/units/motor.cpp @@ -18,7 +18,7 @@ void Motor::cleanup () { int8_t Motor::run (uint8_t subtest) { switch (subtest) { case 0: { - printf("init"); + printf_P(PSTR("init")); ADMUX = (1 << ADLAR) | (1 << REFS0); // ADC0, VREF=AVCC=3.3V ADCSRA = (1 << ADEN) | 7; // ADC Enable, Prescaler 128 TCCR0A = (1 << COM0A1) | (1 << WGM01) | (1 << WGM00); // Fast PWM on OC0A @@ -31,12 +31,12 @@ int8_t Motor::run (uint8_t subtest) { } case 1: { - printf("\n"); + printf_P(PSTR("\n")); while (wait(10) == EOF) { ADCSRA |= (1 << ADSC); // start ADC while (ADCSRA & (1 << ADSC)) {} // wait for result - printf("\r => ADC0=%3d", ADCH); + printf_P(PSTR("\r => ADC0=%3d"), ADCH); ADMUX = (1 << ADLAR) | (1 << REFS1) | (1 << REFS0) | 2; // ADC2, VREF=2.5V @@ -47,11 +47,11 @@ int8_t Motor::run (uint8_t subtest) { dutyCycle = 255; } OCR0A = dutyCycle; - printf(" PWM/OC0A=%3d", dutyCycle); + printf_P(PSTR(" PWM/OC0A=%3d"), dutyCycle); ADCSRA |= (1 << ADSC); // start ADC while (ADCSRA & (1 << ADSC)) {} // wait for result - printf(" ADC2=%3d", ADCH); + printf_P(PSTR(" ADC2=%3d"), ADCH); ADMUX = (1 << ADLAR) | (1 << REFS0); // ADC0, VREF=AVCC=3.3V if ((PINA & (1<< PA3)) == 0) { @@ -66,9 +66,9 @@ int8_t Motor::run (uint8_t subtest) { } float rpm = 60.0 / (float)timer / 0.0001; if (timer > 0) { - printf(" n= %4d U/min", (int)rpm); + printf_P(PSTR(" n= %4d U/min"), (int)rpm); } else { - printf(" no rotation"); + printf_P(PSTR(" no rotation")); } } @@ -76,7 +76,7 @@ int8_t Motor::run (uint8_t subtest) { } case 2: { - printf("\r => end"); + printf_P(PSTR("end")); break; } } diff --git a/software/test_2024-07-23/src/units/motor.hpp b/software/nano-644/test_2024-07-23/src/units/motor.hpp similarity index 79% rename from software/test_2024-07-23/src/units/motor.hpp rename to software/nano-644/test_2024-07-23/src/units/motor.hpp index 35fcf9c..74623ca 100644 --- a/software/test_2024-07-23/src/units/motor.hpp +++ b/software/nano-644/test_2024-07-23/src/units/motor.hpp @@ -3,6 +3,7 @@ #include #include "../main.hpp" +#include class Motor : public TestUnit { public: @@ -13,7 +14,7 @@ class Motor : public TestUnit { Motor () { enabled = 0; rpmTimer = 0; }; virtual void cleanup (); virtual int8_t run (uint8_t subtest); - virtual const char *getName () { return "Motor"; } + virtual PGM_P getName () { return PSTR("Motor"); } void tick100us (); }; diff --git a/software/test_2024-07-23/src/units/portexp.cpp b/software/nano-644/test_2024-07-23/src/units/portexp.cpp similarity index 89% rename from software/test_2024-07-23/src/units/portexp.cpp rename to software/nano-644/test_2024-07-23/src/units/portexp.cpp index 5ed192e..bcc2052 100644 --- a/software/test_2024-07-23/src/units/portexp.cpp +++ b/software/nano-644/test_2024-07-23/src/units/portexp.cpp @@ -36,7 +36,7 @@ int8_t writeByte (uint8_t addr, uint8_t b) { SPDR = 0x40; // WRITE BYTE while ((SPSR & (1 << SPIF)) == 0) {} if (SPDR != 0) { - printf("E1"); + printf_P(PSTR("E1")); PORTA |= (1 << PA7); // SPI nCS 0 -> 1 return -1; } @@ -44,7 +44,7 @@ int8_t writeByte (uint8_t addr, uint8_t b) { SPDR = addr; // register address while ((SPSR & (1 << SPIF)) == 0) {} if (SPDR != 0) { - printf("E2"); + printf_P(PSTR("E2")); PORTA |= (1 << PA7); // SPI nCS 0 -> 1 return -1; } @@ -52,7 +52,7 @@ int8_t writeByte (uint8_t addr, uint8_t b) { SPDR = b; // value while ((SPSR & (1 << SPIF)) == 0) {} if (SPDR != 0) { - printf("E3"); + printf_P(PSTR("E3")); PORTA |= (1 << PA7); // SPI nCS 0 -> 1 return -1; } @@ -74,19 +74,19 @@ int8_t PortExp::run (uint8_t subtest) { // SPCR |= (1 << SPE) | (1 << MSTR) | (1 << SPR1) | (1 << SPR0); // SPI enable , Master, f=12MHz/128=93,75kHz SPCR = (1 << SPE) | (1 << MSTR); // SPI enable , Master, f=12MHz/4 = 3MHz - printf("init"); + printf_P(PSTR("init")); } else if (subtest == 1) { while (wait(500) == EOF) { - printf("\n => start ..."); + printf_P(PSTR("\n => start ...")); for (uint8_t i = 0; i < 8; i++) { writeByte(0, ~(1 << i)); // IODIRA (Bank = 0) // writeByte(0, 0x00); // IODIRA (Bank = 0) - all output writeByte(0x12, (1 << i)); // GPIOA (Bank = 0) - printf("\n Bank0 - GPA%d = 1", i); + printf_P(PSTR("\n Bank0 - GPA%d = 1"), i); wait(200); writeByte(0x12, 0); // GPIOA (Bank = 0) - printf("\n Bank0 - GPA%d = 0", i); + printf_P(PSTR("\n Bank0 - GPA%d = 0"), i); writeByte(0, 0xff); // IODIRA (Bank = 0) wait(200); } @@ -94,17 +94,17 @@ int8_t PortExp::run (uint8_t subtest) { writeByte(1, ~(1 << i)); // IODIRB (Bank = 0) // writeByte(1, 0x00); // IODIRB (Bank = 0) - all output writeByte(0x13, (1 << i)); // GPIOB (Bank = 0) - printf("\n Bank0 - GPB%d = 1", i); + printf_P(PSTR("\n Bank0 - GPB%d = 1"), i); wait(200); writeByte(0x13, 0); // GPIOB (Bank = 0) - printf("\n Bank0 - GPB%d = 0", i); + printf_P(PSTR("\n Bank0 - GPB%d = 0"), i); writeByte(1, 0xff); // IODIRB (Bank = 0) wait(200); } } } else { - printf("end"); + printf_P(PSTR("end")); return -1; } wait(500); diff --git a/software/test_2024-07-23/src/units/portexp.hpp b/software/nano-644/test_2024-07-23/src/units/portexp.hpp similarity index 71% rename from software/test_2024-07-23/src/units/portexp.hpp rename to software/nano-644/test_2024-07-23/src/units/portexp.hpp index 7db858a..cacea83 100644 --- a/software/test_2024-07-23/src/units/portexp.hpp +++ b/software/nano-644/test_2024-07-23/src/units/portexp.hpp @@ -3,13 +3,14 @@ #include #include "../main.hpp" +#include class PortExp : public TestUnit { public: PortExp () {}; virtual void cleanup (); virtual int8_t run (uint8_t subtest); - virtual const char *getName () { return "PortExp"; } + virtual PGM_P getName () { return PSTR("PortExp"); } }; #endif \ No newline at end of file diff --git a/software/test_2024-07-23/src/units/poti.cpp b/software/nano-644/test_2024-07-23/src/units/poti.cpp similarity index 75% rename from software/test_2024-07-23/src/units/poti.cpp rename to software/nano-644/test_2024-07-23/src/units/poti.cpp index 5f8fcdb..d316a0b 100644 --- a/software/test_2024-07-23/src/units/poti.cpp +++ b/software/nano-644/test_2024-07-23/src/units/poti.cpp @@ -12,25 +12,25 @@ void Poti::cleanup () { int8_t Poti::run (uint8_t subtest) { switch (subtest) { case 0: { - printf("init"); + printf_P(PSTR("init")); ADMUX = (1 << REFS0); // ADC0, VREF=AVCC=3.3V ADCSRA = (1 << ADEN) | 7; // ADC Enable, Prescaler 128 return 0; } case 1: { - printf("\n"); + printf_P(PSTR("\n")); while (wait(10) == EOF) { - printf("\r => Measure ADC0: "); + printf_P(PSTR("\r => Measure ADC0: ")); ADCSRA |= (1 << ADSC); // start ADC while (ADCSRA & (1 << ADSC)) {} // wait for result - printf("%4d (0x%03x)", ADC, ADC); + printf_P(PSTR("%4d (0x%03x)"), ADC, ADC); } return 0; } case 2: { - printf("\r => ADC end%20s", " "); + printf_P(PSTR("end")); break; } } diff --git a/software/test_2024-07-23/src/units/poti.hpp b/software/nano-644/test_2024-07-23/src/units/poti.hpp similarity index 71% rename from software/test_2024-07-23/src/units/poti.hpp rename to software/nano-644/test_2024-07-23/src/units/poti.hpp index df368e8..2ca46e3 100644 --- a/software/test_2024-07-23/src/units/poti.hpp +++ b/software/nano-644/test_2024-07-23/src/units/poti.hpp @@ -3,13 +3,14 @@ #include #include "../main.hpp" +#include class Poti : public TestUnit { public: Poti () {}; virtual void cleanup (); virtual int8_t run (uint8_t subtest); - virtual const char *getName () { return "Poti"; } + virtual PGM_P getName () { return PSTR("Poti"); } }; #endif \ No newline at end of file diff --git a/software/test_2024-07-23/src/units/r2r.cpp b/software/nano-644/test_2024-07-23/src/units/r2r.cpp similarity index 68% rename from software/test_2024-07-23/src/units/r2r.cpp rename to software/nano-644/test_2024-07-23/src/units/r2r.cpp index 40b24e1..60f9ab1 100644 --- a/software/test_2024-07-23/src/units/r2r.cpp +++ b/software/nano-644/test_2024-07-23/src/units/r2r.cpp @@ -12,27 +12,27 @@ void R2r::cleanup () { int8_t R2r::run (uint8_t subtest) { switch (subtest) { case 0: { - printf("init"); + printf_P(PSTR("init")); ADMUX = (1 << REFS0) | 2; // ADC2, VREF=AVCC=3.3V ADCSRA = (1 << ADEN) | 7; // ADC Enable, Prescaler 128 return 0; } case 1: { - printf("\n"); + printf_P(PSTR("\n")); while (wait(10) == EOF) { - printf("\r => Measure ADC2: "); + printf_P(PSTR("\r => Measure ADC2: ")); ADCSRA |= (1 << ADSC); // start ADC while (ADCSRA & (1 << ADSC)) {} // wait for result - printf("%4d (0x%03x)", ADC, ADC); + printf_P(PSTR("%4d (0x%03x)"), ADC, ADC); uint8_t sw = (ADC + 32) / 64; - printf(" SW9:6 = %d %d% d %d ", sw >> 3, (sw >> 2) & 0x01, (sw >> 1) & 0x01, sw & 0x01 ); + printf_P(PSTR(" SW9:6 = %d %d% d %d "), sw >> 3, (sw >> 2) & 0x01, (sw >> 1) & 0x01, sw & 0x01 ); } return 0; } case 2: { - printf("\r => R2R end%20s", " "); + printf_P(PSTR("end")); break; } } diff --git a/software/test_2024-07-23/src/units/r2r.hpp b/software/nano-644/test_2024-07-23/src/units/r2r.hpp similarity index 71% rename from software/test_2024-07-23/src/units/r2r.hpp rename to software/nano-644/test_2024-07-23/src/units/r2r.hpp index 974c7a7..6088ce5 100644 --- a/software/test_2024-07-23/src/units/r2r.hpp +++ b/software/nano-644/test_2024-07-23/src/units/r2r.hpp @@ -3,13 +3,14 @@ #include #include "../main.hpp" +#include class R2r : public TestUnit { public: R2r () {}; virtual void cleanup (); virtual int8_t run (uint8_t subtest); - virtual const char *getName () { return "R2R"; } + virtual PGM_P getName () { return PSTR("R2R"); } }; #endif \ No newline at end of file diff --git a/software/test_2024-07-23/src/units/rgb.cpp b/software/nano-644/test_2024-07-23/src/units/rgb.cpp similarity index 84% rename from software/test_2024-07-23/src/units/rgb.cpp rename to software/nano-644/test_2024-07-23/src/units/rgb.cpp index 200bffd..6f08cb5 100644 --- a/software/test_2024-07-23/src/units/rgb.cpp +++ b/software/nano-644/test_2024-07-23/src/units/rgb.cpp @@ -14,13 +14,13 @@ int8_t Rgb::run (uint8_t subtest) { case 0: { DDRB |= (1 << DDB2) | (1 << DDB1) | (1 << DDB0); PORTB |= (1 << PORTB2) | (1 << PORTB1) | (1 << PORTB0); // all OFF - printf("init"); + printf_P(PSTR("init")); return 0; } case 1: { PORTB &= ~(1 << PORTB0); // ON - printf("Red"); + printf_P(PSTR("Red")); wait(2000); return 0; } @@ -28,7 +28,7 @@ int8_t Rgb::run (uint8_t subtest) { case 2: { PORTB |= (1 << PORTB0); PORTB &= ~(1 << PORTB1); // ON - printf("Green"); + printf_P(PSTR("Green")); wait(2000); return 0; } @@ -36,20 +36,20 @@ int8_t Rgb::run (uint8_t subtest) { case 3: { PORTB |= (1 << PORTB1); PORTB &= ~(1 << PORTB2); // ON - printf("Blue"); + printf_P(PSTR("Blue")); wait(2000); return 0; } case 4: { PORTB &= ~((1 << PORTB2) | (1 << PORTB1) | (1 << PORTB0)); - printf("All"); + printf_P(PSTR("All")); wait(2000); return 0; } case 5: { - printf("end"); + printf_P(PSTR("end")); break; } } diff --git a/software/test_2024-07-23/src/units/rgb.hpp b/software/nano-644/test_2024-07-23/src/units/rgb.hpp similarity index 71% rename from software/test_2024-07-23/src/units/rgb.hpp rename to software/nano-644/test_2024-07-23/src/units/rgb.hpp index 2fa8a72..cb5641d 100644 --- a/software/test_2024-07-23/src/units/rgb.hpp +++ b/software/nano-644/test_2024-07-23/src/units/rgb.hpp @@ -3,13 +3,14 @@ #include #include "../main.hpp" +#include class Rgb : public TestUnit { public: Rgb () {}; virtual void cleanup (); virtual int8_t run (uint8_t subtest); - virtual const char *getName () { return "Rgb"; } + virtual PGM_P getName () { return PSTR("Rgb"); } }; #endif \ No newline at end of file diff --git a/software/test_2024-07-23/src/units/seg7.cpp b/software/nano-644/test_2024-07-23/src/units/seg7.cpp similarity index 90% rename from software/test_2024-07-23/src/units/seg7.cpp rename to software/nano-644/test_2024-07-23/src/units/seg7.cpp index d2fdbb9..6ca477e 100644 --- a/software/test_2024-07-23/src/units/seg7.cpp +++ b/software/nano-644/test_2024-07-23/src/units/seg7.cpp @@ -42,7 +42,7 @@ int8_t Seg7::run (uint8_t subtest) { PORTD &= ~((1 < #include "../main.hpp" +#include class Seg7 : public TestUnit { public: Seg7 () {}; virtual void cleanup (); virtual int8_t run (uint8_t subtest); - virtual const char *getName () { return "Seg7"; } + virtual PGM_P getName () { return PSTR("Seg7"); } }; #endif \ No newline at end of file diff --git a/software/test_2024-07-23/src/units/switch.cpp b/software/nano-644/test_2024-07-23/src/units/switch.cpp similarity index 86% rename from software/test_2024-07-23/src/units/switch.cpp rename to software/nano-644/test_2024-07-23/src/units/switch.cpp index 33d483c..9f738e5 100644 --- a/software/test_2024-07-23/src/units/switch.cpp +++ b/software/nano-644/test_2024-07-23/src/units/switch.cpp @@ -23,7 +23,7 @@ int8_t Switch::run (uint8_t subtest) { switch ((subtest - 1) % 4) { case 0: case 2: { if ((PINA & (1 << bit)) == 0) { - printf("Release SW%d (PA%d) ", bit + 1, bit); + printf_P(PSTR("Release SW%d (PA%d) "), bit + 1, bit); while ((PINA & (1 << bit)) == 0 && wait(0) == EOF) {} wait(10); } @@ -32,7 +32,7 @@ int8_t Switch::run (uint8_t subtest) { case 1: { if ((PINA & (1 << bit)) != 0) { - printf("Press SW%d (PA%d) ", bit + 1, bit); + printf_P(PSTR("Press SW%d (PA%d) "), bit + 1, bit); while ((PINA & (1 << bit)) != 0 && wait(0) == EOF) {} wait(10); } @@ -40,7 +40,7 @@ int8_t Switch::run (uint8_t subtest) { } case 3: { - printf("end"); + printf_P(PSTR("end")); return 0; } } diff --git a/software/test_2024-07-23/src/units/switch.hpp b/software/nano-644/test_2024-07-23/src/units/switch.hpp similarity index 72% rename from software/test_2024-07-23/src/units/switch.hpp rename to software/nano-644/test_2024-07-23/src/units/switch.hpp index 8bdcd74..a4caf2f 100644 --- a/software/test_2024-07-23/src/units/switch.hpp +++ b/software/nano-644/test_2024-07-23/src/units/switch.hpp @@ -3,13 +3,14 @@ #include #include "../main.hpp" +#include class Switch : public TestUnit { public: Switch () {}; virtual void cleanup (); virtual int8_t run (uint8_t subtest); - virtual const char *getName () { return "Switch"; } + virtual PGM_P getName () { return PSTR("Switch"); } }; #endif \ No newline at end of file diff --git a/software/test_2024-07-23/src/units/uart1.cpp b/software/nano-644/test_2024-07-23/src/units/uart1.cpp similarity index 85% rename from software/test_2024-07-23/src/units/uart1.cpp rename to software/nano-644/test_2024-07-23/src/units/uart1.cpp index 7ef9504..02f411e 100644 --- a/software/test_2024-07-23/src/units/uart1.cpp +++ b/software/nano-644/test_2024-07-23/src/units/uart1.cpp @@ -37,16 +37,16 @@ int8_t Uart1::run (uint8_t subtest) { UBRR1L = F_CPU / 8 / 115200 - 1; stderr = &mystderr; enabled = 1; - printf("init"); + printf_P(PSTR("init")); } else if (subtest == 1) { do { - printf("\n => send text via UART1 now..."); - fprintf(stderr, "Hello UART1, ECHO-Modus active\n"); + printf_P(PSTR("\n => send text via UART1 now...")); + fprintf_P(stderr, PSTR("Hello UART1, ECHO-Modus active\n")); } while (wait(5000) == EOF); } else { - printf("end"); + printf_P(PSTR("end")); return -1; } wait(500); diff --git a/software/test_2024-07-23/src/units/uart1.hpp b/software/nano-644/test_2024-07-23/src/units/uart1.hpp similarity index 77% rename from software/test_2024-07-23/src/units/uart1.hpp rename to software/nano-644/test_2024-07-23/src/units/uart1.hpp index 23c9b7f..16b6425 100644 --- a/software/test_2024-07-23/src/units/uart1.hpp +++ b/software/nano-644/test_2024-07-23/src/units/uart1.hpp @@ -3,6 +3,7 @@ #include #include "../main.hpp" +#include class Uart1 : public TestUnit { public: @@ -12,7 +13,7 @@ class Uart1 : public TestUnit { Uart1 () { enabled = 0; } virtual void cleanup (); virtual int8_t run (uint8_t subtest); - virtual const char *getName () { return "Uart1"; } + virtual PGM_P getName () { return PSTR("Uart1"); } void handleRxByte (uint8_t); }; -- 2.39.5