From 66d8e3d9f291c86722ff6d41343255db024dc3b0 Mon Sep 17 00:00:00 2001 From: Simon Guigui Date: Fri, 22 Nov 2019 17:33:13 +0100 Subject: [PATCH 1/2] add necessary machinary to build firmware with Arduino Makefile - the Dockerfile contains all required dependencies - firmware patch: c++ doesn't allow forward declaration --- Firmware/.gitignore | 1 + Firmware/Zero2Go-Omini/Dockerfile | 31 ++++++++++++++++++++++++ Firmware/Zero2Go-Omini/Makefile | 16 ++++++++++++ Firmware/Zero2Go-Omini/Zero2Go-Omini.ino | 18 ++++++++++++++ README.md | 16 ++++++++++++ 5 files changed, 82 insertions(+) create mode 100644 Firmware/.gitignore create mode 100644 Firmware/Zero2Go-Omini/Dockerfile create mode 100644 Firmware/Zero2Go-Omini/Makefile diff --git a/Firmware/.gitignore b/Firmware/.gitignore new file mode 100644 index 0000000..1b2211d --- /dev/null +++ b/Firmware/.gitignore @@ -0,0 +1 @@ +build* diff --git a/Firmware/Zero2Go-Omini/Dockerfile b/Firmware/Zero2Go-Omini/Dockerfile new file mode 100644 index 0000000..5412c11 --- /dev/null +++ b/Firmware/Zero2Go-Omini/Dockerfile @@ -0,0 +1,31 @@ +FROM ubuntu:19.10 + +RUN apt-get -yq update \ + && apt-get -yq --no-install-suggests --no-install-recommends install \ + wget \ + git \ + avrdude \ + python-serial \ + xz-utils \ + ca-certificates \ + make \ + && apt-get clean \ + && rm -rf /var/lib/apt/lists/* + +RUN wget https://downloads.arduino.cc/arduino-1.8.10-linux64.tar.xz \ + && tar xf *.tar.xz -C /opt \ + && rm *.tar.xz + +RUN git clone https://github.com/sudar/Arduino-Makefile -b 1.5.2 /opt/arduino-mk + +RUN git clone https://github.com/SpenceKonde/ATTinyCore.git -b v1.1.4 /opt/ATTinyCore + +RUN git clone https://github.com/orangkucing/WireS.git /opt/WireS \ + && cd /opt/WireS \ + && git reset --hard 776ffa23b6b9b8ae17b21e10357e22b09e7e9510 + +RUN git clone https://github.com/orangkucing/analogComp /opt/analogComp + +WORKDIR /src + +CMD ["make"] diff --git a/Firmware/Zero2Go-Omini/Makefile b/Firmware/Zero2Go-Omini/Makefile new file mode 100644 index 0000000..4a88fa7 --- /dev/null +++ b/Firmware/Zero2Go-Omini/Makefile @@ -0,0 +1,16 @@ +TARGET = Zero2Go-Omini.ino +ARDUINO_DIR = /opt/arduino-1.8.10 +USER_LIB_PATH = /opt + +# Programmer type: +ISP_PROG = usbasp + +# https://github.com/SpenceKonde/ATTinyCore (1.5+) +ALTERNATE_CORE = ATTinyCore +ALTERNATE_CORE_PATH = /opt/ATTinyCore +BOARD_TAG = attinyx41 +BOARD_SUB = 841 +F_CPU = 8000000L + +# Path to the Arduino Makefile +include /opt/arduino-mk/Arduino.mk diff --git a/Firmware/Zero2Go-Omini/Zero2Go-Omini.ino b/Firmware/Zero2Go-Omini/Zero2Go-Omini.ino index 085a084..f0e7c1f 100644 --- a/Firmware/Zero2Go-Omini/Zero2Go-Omini.ino +++ b/Firmware/Zero2Go-Omini/Zero2Go-Omini.ino @@ -63,6 +63,24 @@ volatile unsigned long buttonStateChangeTime = 0; volatile unsigned long voltageQueryTime = 0; +void timer1_enable(); +void cutPower(); +void powerOn(); +void redLightOn(); +void suggestShutdown(); +void redLightOff(); +void initializeRegisters(); +void updateRegister(int index, byte value); +float getVoltage(int pin); +int getIntegerPart(float v); +int getDecimalPart(float v); +unsigned int getPowerCutPreloadTimer(); +void receiveEvent(int count); +boolean addressEvent(uint16_t slaveAddress, uint8_t startCount); +void requestEvent(); +void comparatorStatusChanged(); +void sleep(); + void setup() { // initialize pin states and make sure power is cut diff --git a/README.md b/README.md index f999ea5..9d19260 100644 --- a/README.md +++ b/README.md @@ -11,3 +11,19 @@ The firmware is compiled and uploaded to Zero2Go Omini via Arduino IDE (with ATT The software is written in BASH. More information about the firmware and software can be found in the user manual: http://www.uugear.com/doc/Zero2Go_Omini_UserManual.pdf + +# Firmware build instructions + +You can use the provided Dockerfile and Makefile (made with [Arduino-Makefile](https://github.com/sudar/Arduino-Makefile/)) to quickly set up a build environment with all the required dependencies.: + +``` +cd Firmware/Zero2Go-Omini +docker build -t zero2go-omini . +``` + +The firmware can then be built with: + +``` +cd Firmware/Zero2Go-Omini +docker run -ti -v $(pwd):/src zero2go-omini:latest +``` From 8525b8ffbd68047dc509b65ba1f70e90b69bcd9d Mon Sep 17 00:00:00 2001 From: Simon Guigui Date: Fri, 3 Jan 2020 16:45:01 +0100 Subject: [PATCH 2/2] add hardware watchdog feature When this feature is enabled, if the pi fails to reset the watchdog timer, a full power cycle is triggered. Setting i2c register 0x10 to a non-zero value enables the feature and sets the watchdog timeout. --- Firmware/Zero2Go-Omini/Zero2Go-Omini.ino | 60 ++++++++++++++++++++++-- 1 file changed, 55 insertions(+), 5 deletions(-) diff --git a/Firmware/Zero2Go-Omini/Zero2Go-Omini.ino b/Firmware/Zero2Go-Omini/Zero2Go-Omini.ino index f0e7c1f..033f21b 100644 --- a/Firmware/Zero2Go-Omini/Zero2Go-Omini.ino +++ b/Firmware/Zero2Go-Omini/Zero2Go-Omini.ino @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -38,8 +39,9 @@ #define I2C_CONF_BULK_ALWAYS_ON 13 // always enable bulk converter: 1=yes, 0=no #define I2C_CONF_POWER_CUT_DELAY 14 // the delay (x10) before power cut: default=50 (5 sec) #define I2C_CONF_RECOVERY_VOLTAGE 15 // voltage (x10) that triggers recovery, 255=disabled +#define I2C_CONF_WATCHDOG_TIMEOUT 16 // set watchdog timeout, reset watchdog, 0=disabled -#define I2C_REG_COUNT 16 // number of I2C registers +#define I2C_REG_COUNT 17 // number of I2C registers volatile byte i2cReg[I2C_REG_COUNT]; @@ -59,10 +61,14 @@ volatile boolean forcePowerCut = false; volatile boolean wakeupByWatchdog = false; +volatile boolean watchdogEnabled = false; + volatile unsigned long buttonStateChangeTime = 0; volatile unsigned long voltageQueryTime = 0; +volatile unsigned long watchdogCounter = 0; + void timer1_enable(); void cutPower(); void powerOn(); @@ -80,6 +86,9 @@ boolean addressEvent(uint16_t slaveAddress, uint8_t startCount); void requestEvent(); void comparatorStatusChanged(); void sleep(); +void resetWatchdog(); +void watchdog_enable(); +void watchdog_disable(); void setup() { @@ -169,6 +178,14 @@ void loop() { suggestShutdown(); } } + + // the watchdog feature relies on the attiny watchdog + if (i2cReg[I2C_CONF_WATCHDOG_TIMEOUT] && !watchdogEnabled) { + watchdog_enable(); + } + if (!i2cReg[I2C_CONF_WATCHDOG_TIMEOUT] && watchdogEnabled) { + watchdog_disable(); + } } } @@ -193,6 +210,8 @@ void initializeRegisters() { i2cReg[I2C_CONF_POWER_CUT_DELAY] = 50; i2cReg[I2C_CONF_RECOVERY_VOLTAGE] = 255; + i2cReg[I2C_CONF_WATCHDOG_TIMEOUT] = 0; + // make sure product name is stored EEPROM.update(0, 'Z'); EEPROM.update(1, 'e'); @@ -220,14 +239,18 @@ void watchdog_enable() { cli(); WDTCSR |= _BV(WDIE); byte wdp = (i2cReg[I2C_CONF_BLINK_INTERVAL] > 9 ? 8 : i2cReg[I2C_CONF_BLINK_INTERVAL]); + wdp = wdp < 6 ? 6 : wdp; wdp = (((wdp & B00001000) << 2) | (wdp & B11110111)); WDTCSR |= wdp; sei(); + watchdogEnabled = true; + watchdogCounter = 0; } void watchdog_disable() { WDTCSR = 0; + watchdogEnabled = false; } @@ -287,6 +310,9 @@ void sleep() { float vrec = ((float)i2cReg[I2C_CONF_RECOVERY_VOLTAGE]) / 10; if (vmax >= vrec) { wakeupByWatchdog = false; // recovery from low voltage shutdown + } else { + // inhibit watchdog feature when voltage is too low + watchdogCounter = 0; } } } @@ -424,7 +450,20 @@ void requestEvent() { // watchdog interrupt routine ISR (WDT_vect) { - // no need to do anything here + if (i2cReg[I2C_CONF_WATCHDOG_TIMEOUT]) { + // minimum timeout is 1m20s (10*8s) + unsigned long timeout = (i2cReg[I2C_CONF_WATCHDOG_TIMEOUT] + 9); + // timeout is made independant of the attiny watchdog prescaler + timeout *= (1 << (9 - (((WDTCSR & B00100000) >> 2) | (WDTCSR & B00000111)))); + watchdogCounter++; + if (watchdogCounter >= timeout){ + // watchdog timeout, trigger a reboot + watchdogCounter = 0; + cutPower(); + _delay_ms (5000); + powerOn(); + } + } } @@ -493,14 +532,25 @@ void comparatorStatusChanged() { } } +void resetWatchdog() { + watchdogCounter = 0; + redLightOn(); + _delay_ms(50); + redLightOff(); +} // update I2C register, save to EEPROM if it is configuration void updateRegister(int index, byte value) { - i2cReg[index] = value; - if (index >= I2C_CONF_ADDRESS) { - EEPROM.update(index, value); + if (i2cReg[index] != value) { + i2cReg[index] = value; + if (index >= I2C_CONF_ADDRESS) { + EEPROM.update(index, value); + } } if (index == I2C_CONF_BULK_ALWAYS_ON) { powerOn(); } + if (index == I2C_CONF_WATCHDOG_TIMEOUT) { + resetWatchdog(); + } }