Add sleep

This commit is contained in:
Terra 2022-04-24 21:05:49 +02:00
parent 17b6e0487b
commit d1c052ac90
6 changed files with 236 additions and 139 deletions

View File

@ -2,7 +2,7 @@
#include <RHReliableDatagram.h> #include <RHReliableDatagram.h>
#include <RH_RF95.h> #include <RH_RF95.h>
#include <SPI.h> #include <SPI.h>
#include <TemperatureZero.h> #include <TemperatureZero.h>´
#define CLIENT_ADDRESS 1 #define CLIENT_ADDRESS 1
@ -44,75 +44,84 @@ void setup()
pinMode(LED_BUILTIN, OUTPUT); pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, HIGH); digitalWrite(LED_BUILTIN, HIGH);
// Acivating Motor and Digital Outputs, but at LOW level /*// Acivating Motor and Digital Outputs, but at LOW level
pinMode(10, OUTPUT); pinMode(10, OUTPUT);
digitalWrite(10, LOW); digitalWrite(10, LOW);
pinMode(12, OUTPUT); pinMode(12, OUTPUT);
digitalWrite(12, LOW); digitalWrite(12, LOW);
pinMode(6, OUTPUT); pinMode(6, OUTPUT);
digitalWrite(6, LOW); digitalWrite(6, LOW);
pinMode(7, OUTPUT); pinMode(7, OUTPUT);
digitalWrite(7, LOW); digitalWrite(7, LOW);
// explcitly activate inputs, to avoid conflicts // explcitly activate inputs, to avoid conflicts
pinMode(38, INPUT); pinMode(38, INPUT);
pinMode(2, INPUT); pinMode(2, INPUT);
pinMode(5, INPUT); pinMode(5, INPUT);
pinMode(11, INPUT); pinMode(11, INPUT);
// Configuring ADC // Configuring ADC
analogReference(AR_INTERNAL2V23); analogReference(AR_INTERNAL2V23);
analogReadResolution(12); analogReadResolution(12);
SerialUSB.begin(9600); SerialUSB.begin(9600);
//while (!SerialUSB) ; // Wait for serial port to be available //while (!SerialUSB) ; // Wait for serial port to be available
if (!rfManager.init()) if (!rfManager.init())
SerialUSB.println("init failed"); SerialUSB.println("init failed");
rfm95.setModemConfig(MODEM_CONFIG); rfm95.setModemConfig(MODEM_CONFIG);
// Defaults after init are 434.0MHz, 13dBm, Bw = 125 kHz, Cr = 4/5, Sf = 128chips/symbol, CRC on // Defaults after init are 434.0MHz, 13dBm, Bw = 125 kHz, Cr = 4/5, Sf = 128chips/symbol, CRC on
// The default transmitter power is 13dBm, using PA_BOOST. // The default transmitter power is 13dBm, using PA_BOOST.
// If you are using RFM95/96/97/98 modules which uses the PA_BOOST transmitter pin, then // If you are using RFM95/96/97/98 modules which uses the PA_BOOST transmitter pin, then
// you can set transmitter powers from 2 to 20 dBm: // you can set transmitter powers from 2 to 20 dBm:
rfm95.setTxPower(MODEM_POWER, false); rfm95.setTxPower(MODEM_POWER, false);
rfm95.setFrequency(MODEM_FREQ); rfm95.setFrequency(MODEM_FREQ);
// You can optionally require this module to wait until Channel Activity // You can optionally require this module to wait until Channel Activity
// Detection shows no activity on the channel before transmitting by setting // Detection shows no activity on the channel before transmitting by setting
// the CAD timeout to non-zero: // the CAD timeout to non-zero:
// rfm95.setCADTimeout(10000); // rfm95.setCADTimeout(10000);
// on-chip teperature sensor // on-chip teperature sensor
TempZero.init(); TempZero.init();
// activate all five "outputs" for a short period during startup (left to right) // activate all five "outputs" for a short period during startup (left to right)
digitalWrite(BOOSTEN_PIN, HIGH); digitalWrite(BOOSTEN_PIN, HIGH);
delay(1000); delay(1000);
digitalWrite(BOOSTEN_PIN,LOW); digitalWrite(BOOSTEN_PIN, LOW);
digitalWrite(10, HIGH); digitalWrite(10, HIGH);
delay(1000); delay(1000);
digitalWrite(10,LOW); digitalWrite(10, LOW);
digitalWrite(12, HIGH); digitalWrite(12, HIGH);
delay(1000); delay(1000);
digitalWrite(12,LOW); digitalWrite(12, LOW);
digitalWrite(6, HIGH); digitalWrite(6, HIGH);
delay(1000); delay(1000);
digitalWrite(6,LOW); digitalWrite(6, LOW);
digitalWrite(7, HIGH); digitalWrite(7, HIGH);
delay(1000); delay(1000);
digitalWrite(7,LOW); digitalWrite(7, LOW);
// Print Status Report // Print Status Report
PrintSR(); PrintSR();
// switch of LED after startup // switch of LED after startup
digitalWrite(LED_BUILTIN, LOW);
rfm95.sleep();*/
digitalWrite(LED_BUILTIN, LOW); digitalWrite(LED_BUILTIN, LOW);
for (int i = 0; i < 10; i++)
{
digitalWrite(LED_BUILTIN, HIGH);
delay(100);
digitalWrite(LED_BUILTIN, LOW);
delay(100);
}
} }
@ -125,13 +134,36 @@ uint8_t buf[RH_RF95_MAX_MESSAGE_LEN];
void loop() void loop()
{ {
while (!USBDevice.connected())
{
LowPower.sleep(1000);
USBDevice.init();
}
for (int i = 0; i < 10; i++)
{
digitalWrite(LED_BUILTIN, HIGH);
delay(100);
digitalWrite(LED_BUILTIN, LOW);
delay(100);
}
/*if (USBDevice.connected())
digitalWrite(LED_BUILTIN, HIGH);
else
digitalWrite(LED_BUILTIN, LOW);*/
return;
digitalWrite(BOOSTEN_PIN, HIGH);
delay(2000);
digitalWrite(BOOSTEN_PIN, LOW);
delay(2000);
LowPower.deepSleep(4000);
return;
/* /*
SerialUSB.println("Sending to rf95_reliable_datagram_server"); SerialUSB.println("Sending to rf95_reliable_datagram_server");
// Send a message to manager_server // Send a message to manager_server
if (rfManager.sendtoWait(data, sizeof(data), SERVER_ADDRESS)) if (rfManager.sendtoWait(data, sizeof(data), SERVER_ADDRESS))
{ {
SerialUSB.println("...got an ACK"); SerialUSB.println("...got an ACK");
// Now wait for a reply from the server // Now wait for a reply from the server
uint8_t len = sizeof(buf); uint8_t len = sizeof(buf);
@ -147,29 +179,29 @@ void loop()
{ {
SerialUSB.println("No reply, is rf95_reliable_datagram_server running?"); SerialUSB.println("No reply, is rf95_reliable_datagram_server running?");
} }
} }
else else
SerialUSB.println("sendtoWait failed"); SerialUSB.println("sendtoWait failed");
*/ */
// TICK-ROUTINE // TICK-ROUTINE
if(LoopState && millis() > nextTick) if (LoopState && millis() > nextTick)
{ {
switch (LoopState){ switch (LoopState) {
case 1: // Read and print Currents case 1: // Read and print Currents
SerialUSB.print(float(analogRead(A1))/DIVIDER_mA, 3); SerialUSB.print(float(analogRead(A1)) / DIVIDER_mA, 3);
SerialUSB.print("\t"); SerialUSB.print("\t");
SerialUSB.print(float(analogRead(A2))/DIVIDER_mA, 3); SerialUSB.print(float(analogRead(A2)) / DIVIDER_mA, 3);
SerialUSB.print("\t"); SerialUSB.print("\t");
SerialUSB.println(float(analogRead(A3))/DIVIDER_mA, 3); SerialUSB.println(float(analogRead(A3)) / DIVIDER_mA, 3);
break; break;
case 2: // Read and print Voltages case 2: // Read and print Voltages
SerialUSB.print(float(analogRead(A1))/DIVIDER_V, 3); SerialUSB.print(float(analogRead(A1)) / DIVIDER_V, 3);
SerialUSB.print("\t"); SerialUSB.print("\t");
SerialUSB.print(float(analogRead(A2))/DIVIDER_V, 3); SerialUSB.print(float(analogRead(A2)) / DIVIDER_V, 3);
SerialUSB.print("\t"); SerialUSB.print("\t");
SerialUSB.println(float(analogRead(A3))/DIVIDER_V, 3); SerialUSB.println(float(analogRead(A3)) / DIVIDER_V, 3);
break; break;
case 3: // Read and print all GPIO and DigINPUTs case 3: // Read and print all GPIO and DigINPUTs
@ -191,7 +223,7 @@ void loop()
break; break;
case 4: // Read and Print Battery Voltage case 4: // Read and Print Battery Voltage
SerialUSB.println(float(analogRead(BATMON_PIN))/918, 3); SerialUSB.println(float(analogRead(BATMON_PIN)) / 918, 3);
break; break;
case 5: // Read and Print internal Temperature case 5: // Read and Print internal Temperature
@ -208,7 +240,7 @@ void loop()
inByte = SerialUSB.read(); inByte = SerialUSB.read();
SerialUSB.read(); SerialUSB.read();
if(LoopState == 1) if (LoopState == 1)
digitalWrite(BOOSTEN_PIN, LOW); digitalWrite(BOOSTEN_PIN, LOW);
//else if(LoopState == 4) //else if(LoopState == 4)
// msTick = 500; // msTick = 500;
@ -246,21 +278,21 @@ void loop()
default: default:
LoopState = 0; LoopState = 0;
PrintSR(); PrintSR();
break; break;
} }
} }
/* /*
delay(5000); delay(5000);
rfm95.sleep(); rfm95.sleep();
delay(5000); delay(5000);
LowPower.deepSleep(10000); LowPower.deepSleep(10000);
*/ */
} }
void PrintSR(){ void PrintSR() {
// Status Report: Dumps a bunch of usefull information to SerialUSB // Status Report: Dumps a bunch of usefull information to SerialUSB
// Toggle LED // Toggle LED
@ -292,14 +324,14 @@ void PrintSR(){
SerialUSB.print("Internal Temperature (°C): "); SerialUSB.print("Internal Temperature (°C): ");
SerialUSB.println(TempZero.readInternalTemperature()); SerialUSB.println(TempZero.readInternalTemperature());
SerialUSB.print("Battery Voltage (V): "); SerialUSB.print("Battery Voltage (V): ");
SerialUSB.println(float(analogRead(BATMON_PIN))/918); SerialUSB.println(float(analogRead(BATMON_PIN)) / 918);
if(digitalRead(LED_BUILTIN)) if (digitalRead(LED_BUILTIN))
SerialUSB.println("Built-In LED ON"); SerialUSB.println("Built-In LED ON");
else else
SerialUSB.println("Built-In LED OFF"); SerialUSB.println("Built-In LED OFF");
if(digitalRead(BOOSTEN_PIN)) if (digitalRead(BOOSTEN_PIN))
SerialUSB.println("LoopSupply ENABLED (12...15 V)"); SerialUSB.println("LoopSupply ENABLED (12...15 V)");
else else
SerialUSB.println("LoopSupply DISABLED"); SerialUSB.println("LoopSupply DISABLED");

View File

@ -36,7 +36,7 @@ client_address = 0x1234
server_address = 0x0001 server_address = 0x0001
# In ms # In ms
sensor_update_interval = 3000 sensor_update_interval = 5000
device_update_interval = 7000 device_update_interval = 7000
jitter = 1000 jitter = 1000

View File

@ -2,6 +2,7 @@
#define FLASH_DEBUG 0 #define FLASH_DEBUG 0
#define EEPROM_EMULATION_SIZE 1024 #define EEPROM_EMULATION_SIZE 1024
#include <FlashStorage_SAMD.h> #include <FlashStorage_SAMD.h>
#include <ArduinoLowPower.h>
MNConfiguration configuration; MNConfiguration configuration;
RH_RF95 radio(RF_SS_PIN, RF_IRQ_PIN); RH_RF95 radio(RF_SS_PIN, RF_IRQ_PIN);
@ -16,6 +17,9 @@ uint32_t last_server_message_id = 0;
//void init_mn(bool is_client = true) //void init_mn(bool is_client = true)
void initMN() void initMN()
{ {
if (batteryVoltage() < 3.5 && !USBDevice.connected()) // Shut off below this voltage, down to 3.1 V should be OK if the regulator has a dropout of 400 mV and conducts fully if its output is below 3.3 V
LowPower.deepSleep();
//_is_client = is_client; //_is_client = is_client;
EEPROM.setCommitASAP(false); // Don't unnecessarily write to the EEPROM EEPROM.setCommitASAP(false); // Don't unnecessarily write to the EEPROM
@ -90,6 +94,7 @@ void initMN()
temperature_sensor.init(); temperature_sensor.init();
initializeDevices(); initializeDevices();
initRTC();
} }
void test() void test()
@ -266,6 +271,8 @@ bool send(uint8_t data[], uint8_t len)
bool success = true; bool success = true;
success = success & radio.send(full_data, 2 + 2 + 4 + 1 + len + HASH_LENGTH); success = success & radio.send(full_data, 2 + 2 + 4 + 1 + len + HASH_LENGTH);
radio.waitPacketSent(); // What does the returned value here indicate? radio.waitPacketSent(); // What does the returned value here indicate?
radio.setModeIdle();
radio.sleep();
return success; return success;
} }
@ -276,6 +283,8 @@ bool receive()
if (radio.recv(buffer, &len)) if (radio.recv(buffer, &len))
{ {
radio.setModeIdle();
radio.sleep();
uint16_t target_address = buffer[0] + ((uint16_t)buffer[1] << 8); uint16_t target_address = buffer[0] + ((uint16_t)buffer[1] << 8);
if ((target_address == configuration.client_address || target_address == 0xFFFF) && buffer[2] == (configuration.server_address & 0xFF) && buffer[3] == (configuration.server_address >> 8 & 0xFF)) if ((target_address == configuration.client_address || target_address == 0xFFFF) && buffer[2] == (configuration.server_address & 0xFF) && buffer[3] == (configuration.server_address >> 8 & 0xFF))
{ {
@ -344,9 +353,7 @@ DeviceBase* getDevice(uint8_t pointer)
device->pin = 0xFF; device->pin = 0xFF;
} }
else else
{
memcpy(reinterpret_cast<uint8_t*>(device) + 4, &configuration_memory[pointer], device->size()); memcpy(reinterpret_cast<uint8_t*>(device) + 4, &configuration_memory[pointer], device->size());
}
return device; return device;
} }
@ -401,3 +408,41 @@ void sendDeviceData()
memcpy(&data[5], &temperature, 4); memcpy(&data[5], &temperature, 4);
send(data, 9); send(data, 9);
} }
void initRTC() // https://github.com/arduino-libraries/RTCZero/blob/master/src/RTCZero.cpp
{
PM->APBAMASK.reg |= PM_APBAMASK_RTC;
#ifndef CRYSTALLESS
SYSCTRL->XOSC32K.reg = SYSCTRL_XOSC32K_ONDEMAND |
SYSCTRL_XOSC32K_RUNSTDBY |
SYSCTRL_XOSC32K_EN32K |
SYSCTRL_XOSC32K_XTALEN |
SYSCTRL_XOSC32K_STARTUP(6) |
SYSCTRL_XOSC32K_ENABLE;
#endif
GCLK->GENDIV.reg = GCLK_GENDIV_ID(2) | GCLK_GENDIV_DIV(4);
while (GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY);
#ifdef CRYSTALLESS
GCLK->GENCTRL.reg = (GCLK_GENCTRL_GENEN | GCLK_GENCTRL_SRC_OSCULP32K | GCLK_GENCTRL_ID(2) | GCLK_GENCTRL_DIVSEL );
#else
GCLK->GENCTRL.reg = (GCLK_GENCTRL_GENEN | GCLK_GENCTRL_SRC_XOSC32K | GCLK_GENCTRL_ID(2) | GCLK_GENCTRL_DIVSEL );
#endif
while (GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY);
GCLK->CLKCTRL.reg = (uint32_t)((GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK2 | (RTC_GCLK_ID << GCLK_CLKCTRL_ID_Pos)));
while (GCLK->STATUS.bit.SYNCBUSY);
RTC->MODE0.CTRL.reg &= ~RTC_MODE0_CTRL_ENABLE; // disable RTC
RTC->MODE0.CTRL.reg |= RTC_MODE0_CTRL_SWRST; // software reset
RTC->MODE0.CTRL.reg = RTC_MODE0_CTRL_PRESCALER_DIV1024 | RTC_MODE0_CTRL_MODE_COUNT32;
RTC->MODE0.CTRL.reg &= ~RTC_MODE0_CTRL_MATCHCLR; // disable clear on match
RTC->MODE0.CTRL.reg |= RTC_MODE0_CTRL_ENABLE; // enable RTC
}
uint32_t getRTC()
{
return RTC->MODE1.COUNT.reg;
}

View File

@ -189,4 +189,6 @@ void storeDevice(uint8_t pointer, DeviceBase* device); // Stores a device at the
void loopMN(); void loopMN();
void sendSensorData(); void sendSensorData();
void sendDeviceData(); void sendDeviceData();
void initRTC();
uint32_t getRTC();
#endif #endif

View File

@ -5,41 +5,32 @@
//#define IS_CLIENT //#define IS_CLIENT
//#define IS_SERVER //#define IS_SERVER
unsigned long tick_tracker_sensors = 0; unsigned long tick_tracker_sensors = 0;
unsigned long tick_tracker_device = 0; unsigned long tick_tracker_device = 0;
unsigned long next_tick_sensors = 0; unsigned long next_tick_sensors = 0;
unsigned long next_tick_device = 0; unsigned long next_tick_device = 0;
unsigned long offset = 0;
// Class to manage message delivery and receipt, using the rfm95 declared above
//RHReliableDatagram rfManager(rfm95, CLIENT_ADDRESS);
// Internal on-chip Temperature sensor
void setup() void setup()
{ {
SerialUSB.begin(115200); SerialUSB.begin(115200);
//while (!SerialUSB); //while (!SerialUSB);
/*for (int i = 0; i < 5; i++) /*for (int i = 0; i < 5; i++)
{ {
delay(1000); delay(1000);
SerialUSB.println("owo"); SerialUSB.println("owo");
}*/ }*/
initMN(); initMN();
/*for (int i = 0; i < 2; i++) /*for (int i = 0; i < 2; i++)
{ {
delay(1000); delay(1000);
SerialUSB.println("awa"); SerialUSB.println("awa");
} }
printStatusReport();*/ printStatusReport();*/
tick_tracker_sensors = millis(); tick_tracker_sensors = millis();
tick_tracker_device = millis(); tick_tracker_device = millis();
} }
void loop() void loop()
{ {
if (SerialUSB.available()) if (SerialUSB.available())
@ -70,7 +61,7 @@ void loop()
SerialUSB.println(configuration.devices[i]); SerialUSB.println(configuration.devices[i]);
if (configuration.devices[i] != 255) if (configuration.devices[i] != 255)
{ {
for(int j = 0; j < sizeof(AnalogInput); j++) for (int j = 0; j < sizeof(AnalogInput); j++)
{ {
SerialUSB.print(reinterpret_cast<uint8_t*>(devices[i])[j]); SerialUSB.print(reinterpret_cast<uint8_t*>(devices[i])[j]);
SerialUSB.print(" "); SerialUSB.print(" ");
@ -84,10 +75,8 @@ void loop()
SerialUSB.print("Battery voltage: "); SerialUSB.print("Battery voltage: ");
SerialUSB.println(batteryVoltage()); SerialUSB.println(batteryVoltage());
SerialUSB.println(); SerialUSB.print("RTC time: ");
SerialUSB.println(sizeof(uint16_t) + 1 * (sizeof(float) + sizeof(uint8_t) * 2)); SerialUSB.println(RTC->MODE1.COUNT.reg);
SerialUSB.println(sizeof(uint16_t));
SerialUSB.println(1 * (sizeof(float) + sizeof(uint8_t) * 2));
SerialUSB.println("END"); SerialUSB.println("END");
break; break;
@ -140,7 +129,9 @@ void loop()
loopMN(); loopMN();
if (millis() >= next_tick_sensors) long now_time = millis() + offset;
if (now_time >= next_tick_sensors)
{ {
sendSensorData(); sendSensorData();
tick_tracker_sensors = tick_tracker_sensors + configuration.sensor_update_interval; tick_tracker_sensors = tick_tracker_sensors + configuration.sensor_update_interval;
@ -150,7 +141,7 @@ void loop()
digitalWrite(LED_BUILTIN, LOW); digitalWrite(LED_BUILTIN, LOW);
} }
if (millis() >= next_tick_device) if (now_time >= next_tick_device)
{ {
sendDeviceData(); sendDeviceData();
tick_tracker_device = tick_tracker_device + configuration.device_update_interval; tick_tracker_device = tick_tracker_device + configuration.device_update_interval;
@ -159,4 +150,25 @@ void loop()
delay(2); delay(2);
digitalWrite(LED_BUILTIN, LOW); digitalWrite(LED_BUILTIN, LOW);
} }
long next_tick_device_dt = next_tick_device - now_time;
long next_tick_sensors_dt = next_tick_sensors - now_time;
long min_delay = min(next_tick_device_dt, next_tick_sensors_dt);
if (min_delay > 1000 && !USBDevice.connected())
{
power_sleep(min_delay);
offset += min_delay;
//USBDevice.init()
}
}
void power_sleep(uint32_t milliseconds)
{
radio.setModeIdle();
//radio.sleep(); Doesn't work
setLoopPower(OFF);
LowPower.sleep(milliseconds);
radio.setModeIdle();
delay(100);
} }

View File

@ -1,18 +1,24 @@
Setup: Setup:
Install SAMD boards in Arduino IDE Install SAMD boards in Arduino IDE
Install Arduino Low Power Install Arduino Low Power
Install TemperatureZero Install TemperatureZero
Install libraries from MultiNode/Libraries Install libraries from MultiNode/Libraries
Upload MultiNode/MultiNode.ino Upload MultiNode/MultiNode.ino
Execute MultiNode/Configurator.py while it is attached Execute MultiNode/Configurator.py while it is attached
RasPi: RasPi:
# Install https://www.airspayce.com/mikem/bcm2835/ on Raspberry Pi (maybe not) # Install https://www.airspayce.com/mikem/bcm2835/ on Raspberry Pi (maybe not)
sudo apt-get install pip sudo apt-get install pip
pip install numpy pyLoraRFM9x pyblake2 toml pip install numpy pyLoraRFM9x pyblake2 toml
C++ programs need to be executed with sudo, or set permissions to use bcm2835 as user C++ programs need to be executed with sudo, or set permissions to use bcm2835 as user
Execute RasPi/RXTest.py Execute RasPi/RXTest.py
Reconfiguring a node:
Attach it via USB
Press the reset button (left of USB connector)
It will not enter sleep until it is unplugged