Merge: Fixing wakeup deadlock during cutoff (#7)

* averaging measred battery voltage

* bugfix in average battery voltage, using average vbatt only in telemetry

* sending status message on any change of cutoff state

* bugfix with DCD deadlock after wakeup

* some random debugging with deadlock

* more debugging

* bugfix in measuring Vbatt voltage, vbatt averager separated from getter

* some comments
sr9wxz_new_configuration_for_ZZ06
SP8EBC 2022-04-20 22:30:29 +02:00 zatwierdzone przez GitHub
rodzic 0c481f7d42
commit 4896c6255e
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 4AEE18F83AFDEB23
17 zmienionych plików z 480 dodań i 94 usunięć

Wyświetl plik

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<launchConfiguration type="ilg.gnumcueclipse.debug.gdbjtag.openocd.launchConfigurationType">
<stringAttribute key="ilg.gnumcueclipse.debug.gdbjtag.PERIPHERALS" value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;peripherals&gt;&#10; &lt;peripheral name=&quot;GPIOB&quot;/&gt;&#10; &lt;peripheral name=&quot;GPIOC&quot;/&gt;&#10; &lt;peripheral name=&quot;GPIOA&quot;/&gt;&#10; &lt;peripheral name=&quot;TIM3&quot;/&gt;&#10;&lt;/peripherals&gt;&#10;"/>
<stringAttribute key="ilg.gnumcueclipse.debug.gdbjtag.PERIPHERALS" value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;peripherals&gt;&#10; &lt;peripheral name=&quot;RTC&quot;/&gt;&#10; &lt;peripheral name=&quot;ADC2&quot;/&gt;&#10; &lt;peripheral name=&quot;RCC&quot;/&gt;&#10;&lt;/peripherals&gt;&#10;"/>
<booleanAttribute key="ilg.gnumcueclipse.debug.gdbjtag.openocd.doContinue" value="true"/>
<booleanAttribute key="ilg.gnumcueclipse.debug.gdbjtag.openocd.doDebugInRam" value="false"/>
<booleanAttribute key="ilg.gnumcueclipse.debug.gdbjtag.openocd.doFirstReset" value="true"/>

Wyświetl plik

@ -24,9 +24,14 @@ void io_pwr_init(void);
void io_ext_watchdog_config(void);
void io_ext_watchdog_service(void);
#ifdef PARAMETEO
void io_vbat_meas_init(int16_t a_coeff, int16_t b_coeff);
uint16_t io_vbat_meas_get(void);
uint16_t io_vbat_meas_average(uint16_t sample);
#endif
#define VBAT_MEAS_A_COEFF 1000
#define VBAT_MEAS_B_COEFF 95
inline void io_5v_isol_sw_enable(void) {
// ParaMETEO - UC_CNTRL_VS

Wyświetl plik

@ -6,7 +6,7 @@
#include "config_data.h"
#define SW_VER "EA05"
#define SW_DATE "09042022"
#define SW_DATE "17042022"
#define SYSTICK_TICKS_PER_SECONDS 100
#define SYSTICK_TICKS_PERIOD 10
@ -18,6 +18,22 @@
#define OWN_APRS_MSG_LN 160
// backup registers (ParaMETEO)
// 0 -> powersave status
// 1 -> last sleep rtc time
// 2 -> last wakeup rtc time
// 3 -> controller configuration status
// 4 -> wakeup events MSB, sleep events LSB
#ifdef STM32L471xx
#define REGISTER RTC->BKP0R
#define REGISTER_LAST_SLEEP RTC->BKP1R
#define REGISTER_LAST_WKUP RTC->BKP2R
#define REGISTER_COUNTERS RTC->BKP4R
#define REGISTER_MONITOR RTC->BKP5R
#define REGISTER_LAST_SLTIM RTC->BKP6R
#endif
extern uint32_t master_time;
extern const config_data_mode_t * main_config_data_mode;
@ -55,14 +71,40 @@ extern srl_context_t* main_gsm_srl_ctx_ptr;
extern uint8_t main_kiss_enabled;
extern uint8_t main_woken_up;
extern char after_tx_lock;
extern unsigned short rx10m, tx10m, digi10m, digidrop10m, kiss10m;
//void main_set_monitor(int8_t bit);
uint16_t main_get_adc_sample(void);
void main_service_cpu_load_ticks(void);
/**
* Inline used to trace an execution flow across main for(;;) loop and some
* powersaving functions. In case of software fault it's value may help to trace
* at witch point the crash has occured
*/
inline void main_set_monitor(int8_t bit) {
#ifdef STM32L471xx
// enable access to backup domain
PWR->CR1 |= PWR_CR1_DBP;
if (bit >= 0) {
REGISTER_MONITOR |= (1 << bit);
}
else {
REGISTER_MONITOR = 0;
}
PWR->CR1 &= (0xFFFFFFFF ^ PWR_CR1_DBP);
#endif
}
inline uint32_t main_get_master_time(void) {
return master_time;
}

Wyświetl plik

@ -30,7 +30,11 @@
* How long in minutes the controller will sleep in L7 state between checking
* if battery has been charged.
*/
#define PWR_SAVE_CUTOFF_SLEEP_TIME_IN_MINUTES 4
#define PWR_SAVE_CUTOFF_SLEEP_TIME_IN_MINUTES 10
/**
* Do not uncomment this on production devices
*/
//#define INHIBIT_CUTOFF
#endif /* INCLUDE_PWR_SAVE_CONFIGURATION_H_ */

Wyświetl plik

@ -15,5 +15,12 @@ extern uint8_t rte_main_trigger_modbus_status;
extern uint8_t rte_main_trigger_wx_packet;
extern uint16_t rte_main_battery_voltage;
extern uint16_t rte_main_average_battery_voltage;
extern uint16_t rte_main_wakeup_count;
extern uint16_t rte_main_going_sleep_count;
extern uint32_t rte_main_last_sleep_master_time;
#endif

104
src/io.c
Wyświetl plik

@ -25,7 +25,14 @@
#if defined(PARAMETEO)
LL_GPIO_InitTypeDef GPIO_InitTypeDef;
int16_t io_vbat_a_coeff, io_vbat_b_coeff;
int16_t io_vbat_a_coeff = 0, io_vbat_b_coeff = 0;
#define VBATT_HISTORY_LN 16
static uint16_t io_vbatt_history[VBATT_HISTORY_LN];
static uint8_t io_vbatt_history_it = 0;
#define MINIMUM_SENSEFUL_VBATT_VOLTAGE 512u
#endif
void io_oc_init(void) {
@ -154,10 +161,13 @@ void io_ext_watchdog_service(void) {
void io_vbat_meas_init(int16_t a_coeff, int16_t b_coeff) {
#ifdef STM32L471xx
io_vbat_a_coeff = a_coeff;
io_vbat_b_coeff = b_coeff;
#ifdef PARAMETEO
if (a_coeff != io_vbat_a_coeff || b_coeff != io_vbat_b_coeff) {
io_vbat_a_coeff = a_coeff;
io_vbat_b_coeff = b_coeff;
memset(io_vbatt_history, 0x00, VBATT_HISTORY_LN);
}
GPIO_InitTypeDef.Mode = LL_GPIO_MODE_ANALOG;
GPIO_InitTypeDef.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
@ -176,8 +186,14 @@ void io_vbat_meas_init(int16_t a_coeff, int16_t b_coeff) {
// RCC->AHB2ENR &= (0xFFFFFFFF ^ RCC_AHB2ENR_ADCEN);
// RCC->AHB2ENR |= RCC_AHB2ENR_ADCEN;
// the adc should be disabled now, but just to be sure that this is a case
ADC2->CR &= (0xFFFFFFFF ^ ADC_CR_ADEN);
// check if ADC is enabled
if ((ADC2->CR & ADC_CR_ADEN) != 0) {
// disable it
ADC2->CR |= ADC_CR_ADDIS;
// and wait for disabling to complete
while((ADC2->CR & ADC_CR_ADDIS) == ADC_CR_ADDIS);
}
// exit from deep-power-down mode
ADC2->CR &= (0xFFFFFFFF ^ ADC_CR_DEEPPWD);
@ -211,37 +227,93 @@ void io_vbat_meas_init(int16_t a_coeff, int16_t b_coeff) {
#endif
}
uint16_t io_vbat_meas_get(void) {
/**
* This function will measure current B+ voltage using ADC and return
* either average (if 0) or current / momentary value (non zero)
*/
uint16_t io_vbat_meas_get() {
uint16_t out = 0;
#ifdef STM32L471xx
#ifdef PARAMETEO
float temp = 0.0f;
// start ADC
ADC2->CR |= ADC_CR_ADEN;
// if ADC is not enabled
if ((ADC2->CR & ADC_CR_ADEN) == 0) {
// start ADC
ADC2->CR |= ADC_CR_ADEN;
// wait for startup
while((ADC2->ISR & ADC_ISR_ADRDY) == 0);
// wait for startup
while((ADC2->ISR & ADC_ISR_ADRDY) == 0);
}
// start conversion
ADC2->CR |= ADC_CR_ADSTART;
// wait for conversion to finish
while((ADC2->ISR & ADC_ISR_EOC) != ADC_ISR_EOC) {
;
while((ADC2->ISR & ADC_ISR_EOC) == 0) {
if ((ADC2->ISR & ADC_ISR_EOS) != 0) {
break;
}
}
// get conversion result
out = ADC2->DR;
// disable ADC
ADC2->CR &= (0xFFFFFFFF ^ ADC_CR_ADEN);
// if end of sequence flag is not cleared
if ((ADC2->ISR & ADC_ISR_EOS) != 0) {
ADC2->ISR |= ADC_ISR_EOS;
}
// disable conversion
ADC2->CR |= ADC_CR_ADSTP;
// adc has a resulution of 12bit, so with VDDA of 3.3V it gives about .00081V per division
temp = (float)out * 0.00081f; // real voltage on ADC input
out = (uint16_t) (temp * (float)io_vbat_a_coeff + (float)io_vbat_b_coeff);
#endif
return out;
}
uint16_t io_vbat_meas_average(uint16_t sample) {
uint16_t out = 0;
int i = 0;
uint32_t average_acc = 0;
// if the iterator reached the end of buffer
if (io_vbatt_history_it >= VBATT_HISTORY_LN) {
// reset it to the begining
io_vbatt_history_it = 0;
}
// but new sample in the buffer
io_vbatt_history[io_vbatt_history_it++] = sample;
for (i = 0; i < VBATT_HISTORY_LN; i++) {
// break from the loop if buffer isn't fully filled with data
if (io_vbatt_history[i] < MINIMUM_SENSEFUL_VBATT_VOLTAGE) {
break;
}
// sum sample
average_acc += io_vbatt_history[i];
}
// if whole buffer has been used for average calculation
if (i >= VBATT_HISTORY_LN) {
// replace output
out = (uint16_t)(average_acc / VBATT_HISTORY_LN);
}
return out;
}

Wyświetl plik

@ -89,6 +89,8 @@ void it_handlers_set_priorities(void) {
#ifdef STM32L471xx
void RTC_WKUP_IRQHandler(void) {
main_woken_up = 1;
// clear pending interrupt
NVIC_ClearPendingIRQ(RTC_WKUP_IRQn);
@ -96,14 +98,12 @@ void RTC_WKUP_IRQHandler(void) {
EXTI->PR1 |= EXTI_PR1_PIF20;
main_set_monitor(12);
system_clock_configure_l4();
pwr_save_exit_from_stop2();
rte_main_battery_voltage = io_vbat_meas_get();
pwr_save_pooling_handler(main_config_data_mode, main_config_data_basic, 1, rte_main_battery_voltage);
}
#endif

Wyświetl plik

@ -19,6 +19,8 @@
#include "gsm/sim800c_engineering.h"
#include "gsm/sim800c_poolers.h"
#include "gsm/sim800c_gprs.h"
#include "http_client/http_client.h"
#include "aprsis.h"
#endif
@ -101,7 +103,11 @@
// backup registers (ParaMETEO)
// 0 -> powersave status
// 1 -> last sleep rtc time
// 2 -> last wakeup rtc time
// 3 -> controller configuration status
// 4 -> wakeup events MSB, sleep events LSB
// 5 -> monitor
#define CONFIG_FIRST_RESTORED (1)
@ -220,10 +226,6 @@ umb_retval_t main_umb_retval = UMB_UNINITIALIZED;
// result of CRC calculation
uint32_t main_crc_result = 0;
char after_tx_lock;
unsigned short rx10m = 0, tx10m = 0, digi10m = 0, digidrop10m = 0, kiss10m = 0;
#if defined(STM32L471xx)
LL_GPIO_InitTypeDef GPIO_InitTypeDef;
@ -231,6 +233,14 @@ gsm_sim800_state_t main_gsm_state;
#endif
#if defined(PARAMETEO)
uint8_t main_woken_up = 0;
#endif
char after_tx_lock;
unsigned short rx10m = 0, tx10m = 0, digi10m = 0, digidrop10m = 0, kiss10m = 0;
static void message_callback(struct AX25Msg *msg) {
}
@ -497,7 +507,7 @@ int main(int argc, char* argv[]){
pwr_save_init(main_config_data_mode->powersave);
// initialize B+ measurement
io_vbat_meas_init(1000, 95);
io_vbat_meas_init(VBAT_MEAS_A_COEFF, VBAT_MEAS_B_COEFF);
#endif
// initalizing separated Open Collector output
@ -712,7 +722,7 @@ int main(int argc, char* argv[]){
main_wx_srl_ctx_ptr->te_pin = GPIO_Pin_8;
main_wx_srl_ctx_ptr->te_port = GPIOA;
#endif
#if defined(PARAMETEO)
#if defined(STM32L471xx)
main_wx_srl_ctx_ptr->te_pin = LL_GPIO_PIN_8;
main_wx_srl_ctx_ptr->te_port = GPIOA;
@ -941,8 +951,7 @@ int main(int argc, char* argv[]){
if (main_config_data_mode->gsm == 1) {
gsm_sim800_init(&main_gsm_state, 1);
http_client_init(&main_gsm_state, main_gsm_srl_ctx_ptr, 0);
//http_client_init(&main_gsm_state, main_gsm_srl_ctx_ptr, 0);
//aprsis_init(&main_gsm_srl_ctx, &main_gsm_state, "SP8EBC", 10, 23220);
}
#endif
@ -954,11 +963,16 @@ int main(int argc, char* argv[]){
beacon_send_own(0);
#endif
delay_fixed(1500);
telemetry_send_status_powersave_registers(REGISTER_LAST_SLEEP, REGISTER_LAST_WKUP, REGISTER_COUNTERS, REGISTER_MONITOR, REGISTER_LAST_SLTIM);
}
// Infinite loop
while (1)
{
main_set_monitor(-1);
// incrementing current cpu ticks
main_current_cpu_idle_ticks++;
@ -969,6 +983,7 @@ int main(int argc, char* argv[]){
;
}
main_set_monitor(0);
#if defined(PARATNC_HWREV_A) || defined(PARATNC_HWREV_B) || defined(PARATNC_HWREV_C)
// read the state of a button input
if (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0)) {
@ -1003,6 +1018,24 @@ int main(int argc, char* argv[]){
}
#endif
#if defined(PARAMETEO)
if (main_woken_up == 1) {
// io_vbat_meas_init(VBAT_MEAS_A_COEFF, VBAT_MEAS_B_COEFF);
rte_main_battery_voltage = io_vbat_meas_get();
// reinitialize APRS radio modem to clear all possible intermittent state caused by
// switching power state in the middle of reception APRS packet
ax25_new_msg_rx_flag = 0;
main_ax25.dcd = false;
main_woken_up = 0;
main_set_monitor(1);
}
#endif
main_set_monitor(11);
// if new packet has been received from radio channel
if(ax25_new_msg_rx_flag == 1) {
@ -1135,11 +1168,19 @@ int main(int argc, char* argv[]){
rtu_serial_pool();
}
main_set_monitor(2);
// get all meteo measuremenets each 65 seconds. some values may not be
// downloaded from sensors if _METEO and/or _DALLAS_AS_TELEM aren't defined
if (main_wx_sensors_pool_timer < 10) {
rte_main_battery_voltage = io_vbat_meas_get();
rte_main_average_battery_voltage = io_vbat_meas_average(rte_main_battery_voltage);
// meas average will return 0 if internal buffer isn't filled completely
if (rte_main_average_battery_voltage == 0) {
rte_main_average_battery_voltage = rte_main_battery_voltage;
}
if (main_modbus_rtu_master_enabled == 1) {
rtu_serial_start();
@ -1171,19 +1212,31 @@ int main(int argc, char* argv[]){
}
main_set_monitor(3);
main_wx_sensors_pool_timer = 65500;
}
if (main_one_minute_pool_timer < 10) {
main_set_monitor(4);
#ifndef _MUTE_OWN
packet_tx_handler(main_config_data_basic, main_config_data_mode);
#endif
main_set_monitor(5);
#ifdef STM32L471xx
if (main_config_data_mode->gsm == 1) {
gsm_sim800_poolers_one_minute(main_gsm_srl_ctx_ptr, &main_gsm_state);
gsm_sim800_poolers_one_minute(main_gsm_srl_ctx_ptr, &main_gsm_state);
// if (gsm_sim800_gprs_ready == 1) {
// retval = http_client_async_get("http://pogoda.cc:8080/meteo_backend/status", strlen("http://pogoda.cc:8080/meteo_backend/status"), 0xFFF0, 0x1, 0);
// }
}
#endif
@ -1192,7 +1245,7 @@ int main(int argc, char* argv[]){
if (main_one_second_pool_timer < 10) {
//digi_pool_viscous();
main_set_monitor(6);
digi_pool_viscous();
@ -1221,6 +1274,8 @@ int main(int argc, char* argv[]){
analog_anemometer_direction_handler();
}
main_set_monitor(7);
main_one_second_pool_timer = 1000;
}
else if (main_one_second_pool_timer < -10) {
@ -1247,6 +1302,8 @@ int main(int argc, char* argv[]){
if (main_ten_second_pool_timer < 10) {
main_set_monitor(8);
if (rte_main_trigger_wx_packet == 1) {
packet_tx_send_wx_frame();
@ -1256,13 +1313,17 @@ int main(int argc, char* argv[]){
#ifdef PARAMETEO
// inhibit any power save switching when modem transmits data
if (!main_afsk.sending) {
if (!main_afsk.sending && main_woken_up == 0) {
pwr_save_pooling_handler(main_config_data_mode, main_config_data_basic, packet_tx_get_minutes_to_next_wx(), rte_main_battery_voltage);
}
#endif
main_set_monitor(9);
#ifdef STM32L471xx
if (main_config_data_mode->gsm == 1) {
// TODO
// retval = aprsis_connect_and_login(TEST_IP, strlen(TEST_IP), 14580);
//
// if (retval == 0) {
@ -1295,6 +1356,8 @@ int main(int argc, char* argv[]){
main_ten_second_pool_timer = 10000;
}
main_set_monitor(10);
}
// Infinite loop, never return.

Wyświetl plik

@ -140,6 +140,15 @@ void packet_tx_handler(const config_data_basic_t * const config_basic, const con
SendWXFrame(rte_wx_average_windspeed, rte_wx_max_windspeed, rte_wx_average_winddirection, rte_wx_temperature_average_external_valid, rte_wx_pressure_valid, rte_wx_humidity_valid);
/**
* debug
*
* #define REGISTER_LAST_SLEEP RTC->BKP1R
#define REGISTER_LAST_WKUP RTC->BKP2R
#define REGISTER_COUNTERS RTC->BKP4R
*
*/
#ifdef EXTERNAL_WATCHDOG
io_ext_watchdog_service();
#endif
@ -209,6 +218,8 @@ void packet_tx_handler(const config_data_basic_t * const config_basic, const con
if (packet_tx_telemetry_counter >= packet_tx_telemetry_interval) {
telemetry_send_status_powersave_registers(REGISTER_LAST_SLEEP, REGISTER_LAST_WKUP, REGISTER_COUNTERS, REGISTER_MONITOR, REGISTER_LAST_SLTIM);
packet_tx_multi_per_call_handler();
// if there weren't any erros related to communication with DS12B20 from previous function call
@ -301,7 +312,6 @@ void packet_tx_handler(const config_data_basic_t * const config_basic, const con
rte_wx_wind_qf = AN_WIND_QF_UNKNOWN;
}
if (config_mode->victron == 1) {
telemetry_send_values_pv(rx10m, digi10m, rte_pv_battery_current, rte_pv_battery_voltage, rte_pv_cell_voltage, dallas_qf, pressure_qf, humidity_qf, wind_qf);
}
@ -314,11 +324,11 @@ void packet_tx_handler(const config_data_basic_t * const config_basic, const con
// if _METEO will be enabled, but without _DALLAS_AS_TELEM the fifth channel will be used to transmit temperature from MS5611
// which may be treated then as 'rack/cabinet internal temperature'. Dallas DS12B10 will be used for ragular WX frames
telemetry_send_values(rx10m, tx10m, digi10m, rte_main_battery_voltage, digidrop10m, rte_wx_temperature_internal_valid, dallas_qf, pressure_qf, humidity_qf, wind_qf, pwr_save_currently_cutoff, config_mode);
telemetry_send_values(rx10m, tx10m, digi10m, rte_main_average_battery_voltage, digidrop10m, rte_wx_temperature_internal_valid, dallas_qf, pressure_qf, humidity_qf, wind_qf, pwr_save_currently_cutoff, config_mode);
}
else {
// if user will disable both _METEO and _DALLAS_AS_TELEM value will be zeroed internally anyway
telemetry_send_values(rx10m, tx10m, digi10m, rte_main_battery_voltage, digidrop10m, 0.0f, dallas_qf, pressure_qf, humidity_qf, wind_qf, pwr_save_currently_cutoff, config_mode);
telemetry_send_values(rx10m, tx10m, digi10m, rte_main_average_battery_voltage, digidrop10m, 0.0f, dallas_qf, pressure_qf, humidity_qf, wind_qf, pwr_save_currently_cutoff, config_mode);
}
#else
// if _DALLAS_AS_TELEM will be enabled the fifth channel will be set to temperature measured by DS12B20

Wyświetl plik

@ -18,14 +18,12 @@
#include "packet_tx_handler.h"
#include "wx_handler.h"
#include "main.h"
#include "telemetry.h"
#include "rte_main.h"
#include "drivers/analog_anemometer.h"
#define REGISTER RTC->BKP0R
#define INHIBIT_PWR_SWITCH_PERIODIC_H 1
#define IN_STOP2_MODE (1 << 1)
#define IN_C0_STATE (1 << 2)
@ -51,6 +49,12 @@ int16_t pwr_save_sleep_time_in_seconds = -1;
*/
int8_t pwr_save_currently_cutoff = 0;
/**
* This stores a previous value of 'pwr_save_currently_cutoff' which is required to
* trigger a status message when controller goes into low battery voltage or cutoff state
*/
int8_t pwr_save_previously_cutoff = 0;
/**
* This is cutoff voltage at which the power saving subsystem will keep ParaMETEO constantly
* in L7 mode and wakeup once every 20 minutes to check B+ once again
@ -160,7 +164,13 @@ void pwr_save_init(config_data_powersave_mode_t mode) {
*/
void pwr_save_enter_stop2(void) {
rte_main_battery_voltage = io_vbat_meas_get();
uint16_t counter = 0;
// set 31st monitor bit
main_set_monitor(31);
// clear main battery voltage to be sure that it'd be updated???
rte_main_battery_voltage = 0;
analog_anemometer_deinit();
@ -174,11 +184,22 @@ void pwr_save_enter_stop2(void) {
RTC->WPR = 0xCA;
RTC->WPR = 0x53;
// unlock an access to backup domain
pwr_save_unclock_rtc_backup_regs();
// save an information that STOP2 mode has been applied
RTC->BKP0R |= IN_STOP2_MODE;
// save a timestamp when micro has been switched to STOP2 mode
REGISTER_LAST_SLEEP = RTC->TR;
// increment the STOP2 sleep counters
counter = (uint16_t)(REGISTER_COUNTERS & 0xFFFF);
counter++;
REGISTER_COUNTERS = (REGISTER_COUNTERS & 0xFFFF0000) | counter;
pwr_save_lock_rtc_backup_regs();
SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
@ -198,6 +219,31 @@ void pwr_save_enter_stop2(void) {
*/
void pwr_save_exit_from_stop2(void) {
uint32_t counter = 0;
// set 30th minitor bit
main_set_monitor(30);
// unlock access to backup registers
pwr_save_unclock_rtc_backup_regs();
// save a timestamp of this wakeup event
REGISTER_LAST_WKUP = RTC->TR;
// increase wakeup counter
counter = (uint32_t)((REGISTER_COUNTERS & 0xFFFF0000) >> 16);
counter++;
// check counter overflow conditions
if (counter > 0xFFFF) {
counter = 0;
}
REGISTER_COUNTERS = (REGISTER_COUNTERS & 0x0000FFFF) | (counter << 16);
pwr_save_lock_rtc_backup_regs();
// packet tx timers values
packet_tx_counter_values_t timers;
@ -240,6 +286,8 @@ void pwr_save_exit_from_stop2(void) {
default:
break;
}
main_set_monitor(29);
}
int pwr_save_switch_mode_to_c0(void) {
@ -450,6 +498,8 @@ void pwr_save_switch_mode_to_l6(uint16_t sleep_time) {
return;
}
main_set_monitor(28);
// turn OFF +5V_S (and internal VHF radio module in HW-RevB)
io___cntrl_vbat_s_disable();
@ -471,6 +521,8 @@ void pwr_save_switch_mode_to_l6(uint16_t sleep_time) {
// set for C3 mode
REGISTER |= IN_L6_STATE;
REGISTER_LAST_SLTIM = sleep_time;
// lock access to backup
pwr_save_lock_rtc_backup_regs();
@ -485,6 +537,8 @@ void pwr_save_switch_mode_to_l6(uint16_t sleep_time) {
pwr_save_enter_stop2();
main_set_monitor(27);
}
@ -494,6 +548,8 @@ void pwr_save_switch_mode_to_l7(uint16_t sleep_time) {
return;
}
main_set_monitor(26);
// turn OFF +5V_S (and internal VHF radio module in HW-RevB)
io___cntrl_vbat_s_disable();
@ -515,6 +571,8 @@ void pwr_save_switch_mode_to_l7(uint16_t sleep_time) {
// set for C3 mode
REGISTER |= IN_L7_STATE;
REGISTER_LAST_SLTIM = sleep_time;
// lock access to backup
pwr_save_lock_rtc_backup_regs();
@ -529,6 +587,8 @@ void pwr_save_switch_mode_to_l7(uint16_t sleep_time) {
led_control_led2_bottom(false);
pwr_save_enter_stop2();
main_set_monitor(25);
}
void pwr_save_pooling_handler(const config_data_mode_t * config, const config_data_basic_t * timers, int16_t minutes_to_wx, uint16_t vbatt) {
@ -541,6 +601,11 @@ void pwr_save_pooling_handler(const config_data_mode_t * config, const config_da
// by default use powersave mode from controller configuration
config_data_powersave_mode_t psave_mode = config->powersave;
main_set_monitor(24);
// save previous state
pwr_save_previously_cutoff = pwr_save_currently_cutoff;
// check if battery voltage measurement is done and senseful
if (vbatt < MINIMUM_SENSEFUL_VBATT_VOLTAGE) {
// inhibit both cutoff and aggresive powersave if vbatt measurement is either not
@ -548,21 +613,44 @@ void pwr_save_pooling_handler(const config_data_mode_t * config, const config_da
vbatt = 0xFFFFu;
}
// check if battery voltage is below low voltage level
if (vbatt <= pwr_save_aggressive_powersave_voltage) {
// if battery voltage is low swtich to aggressive powersave mode
pwr_save_currently_cutoff |= CURRENTLY_VBATT_LOW;
#ifdef INHIBIT_CUTOFF
vbatt = 0xFFFFu;
#endif
psave_mode = PWSAVE_AGGRESV;
if (vbatt > PWR_SAVE_STARTUP_RESTORE_VOLTAGE_DEF) {
pwr_save_currently_cutoff = 0;
main_set_monitor(23);
}
else {
pwr_save_currently_cutoff &= (0xFF ^ CURRENTLY_VBATT_LOW);
if (vbatt <= PWR_SAVE_CUTOFF_VOLTAGE_DEF) {
main_set_monitor(22);
// if the battery voltage is below cutoff level and the ParaMETEO controller is currently not cut off
pwr_save_currently_cutoff |= CURRENTLY_CUTOFF;
}
// check if battery voltage is below low voltage level
if (vbatt <= PWR_SAVE_AGGRESIVE_POWERSAVE_VOLTAGE) {
main_set_monitor(21);
// if battery voltage is low swtich to aggressive powersave mode
pwr_save_currently_cutoff |= CURRENTLY_VBATT_LOW;
}
}
main_set_monitor(20);
// check if cutoff status has changed
if (pwr_save_currently_cutoff != pwr_save_previously_cutoff) {
telemetry_send_status_powersave_cutoff(vbatt, pwr_save_previously_cutoff, pwr_save_currently_cutoff);
}
if (vbatt <= pwr_save_cutoff_voltage && ((pwr_save_currently_cutoff & CURRENTLY_CUTOFF) == 0)) {
// if the battery voltage is below cutoff level and the ParaMETEO controller is currently not cut off
pwr_save_currently_cutoff |= CURRENTLY_CUTOFF;
if ((pwr_save_currently_cutoff & CURRENTLY_CUTOFF) != 0) {
main_set_monitor(19);
// clear all previous powersave indication bits as we want to go sleep being already in L7 state
pwr_save_clear_powersave_idication_bits();
@ -571,22 +659,15 @@ void pwr_save_pooling_handler(const config_data_mode_t * config, const config_da
pwr_save_switch_mode_to_l7(60 * PWR_SAVE_CUTOFF_SLEEP_TIME_IN_MINUTES);
return;
}
else if (vbatt <= pwr_save_startup_restore_voltage && ((pwr_save_currently_cutoff & CURRENTLY_CUTOFF) != 0)) {
// clear all previous powersave indication bits as we want to go sleep being already in L7 state
pwr_save_clear_powersave_idication_bits();
// if the ParaMETEO is cutted off currently but battery hasn't been charged above restore voltage
pwr_save_switch_mode_to_l7(60 * PWR_SAVE_CUTOFF_SLEEP_TIME_IN_MINUTES);
if ((pwr_save_currently_cutoff & CURRENTLY_VBATT_LOW) != 0) {
main_set_monitor(18);
return;
}
else {
// if battery level is above restore voltage and aggressive powersave voltage
pwr_save_currently_cutoff &= (0xFF ^ CURRENTLY_CUTOFF);
psave_mode = PWSAVE_AGGRESV;
}
// get current counter values
packet_tx_get_current_counters(&counters);
@ -705,6 +786,8 @@ void pwr_save_pooling_handler(const config_data_mode_t * config, const config_da
}
else { // WX
if (minutes_to_wx > 2) {
main_set_monitor(17);
// if there is more than two minutes to send wx packet
pwr_save_switch_mode_to_l7((timers->wx_transmit_period * 60) - 120);
}
@ -747,6 +830,8 @@ void pwr_save_pooling_handler(const config_data_mode_t * config, const config_da
// if stations is configured to send wx packet less often than every 5 minutes
if (minutes_to_wx > 1) {
main_set_monitor(16);
// if there is more than one minute to wx packet
pwr_save_switch_mode_to_l7((timers->wx_transmit_period * 60) - 60); // TODO: !!!
}
@ -765,6 +850,8 @@ void pwr_save_pooling_handler(const config_data_mode_t * config, const config_da
// if station is configured to sent wx packet in every 5 minutes or more often
if (minutes_to_wx > 1) {
main_set_monitor(15);
pwr_save_switch_mode_to_l6((timers->wx_transmit_period * 60) - 60); // TODO: !!!
}
else {
@ -785,6 +872,8 @@ void pwr_save_pooling_handler(const config_data_mode_t * config, const config_da
}
else { // WX
if (minutes_to_wx > 1) {
main_set_monitor(14);
// if there is more than one minute to send wx packet
pwr_save_switch_mode_to_l7((timers->wx_transmit_period * 60) - 60);
}
@ -812,6 +901,8 @@ void pwr_save_pooling_handler(const config_data_mode_t * config, const config_da
}
}
main_set_monitor(13);
if (reinit_sensors != 0) {
// reinitialize all i2c sensors
wx_force_i2c_sensor_reset = 1;

Wyświetl plik

@ -16,6 +16,16 @@ uint8_t rte_main_trigger_modbus_status = 0;
uint8_t rte_main_trigger_wx_packet = 0;
#ifdef PARAMETEO
uint16_t rte_main_battery_voltage;
uint16_t rte_main_average_battery_voltage = 0;
uint16_t rte_main_wakeup_count = 0;
uint16_t rte_main_going_sleep_count = 0;
uint32_t rte_main_last_sleep_master_time = 0;
#endif

Wyświetl plik

@ -94,6 +94,9 @@ void telemetry_send_status(void);
void telemetry_send_status_raw_values_modbus(void);
void telemetry_send_status_powersave_cutoff(uint16_t battery_voltage, int8_t vbatt_low, int8_t cutoff);
void telemetry_send_status_powersave_registers(uint32_t register_last_sleep, uint32_t register_last_wakeup, uint32_t register_counters, uint32_t monitor, uint32_t last_sleep_time);
#ifdef __cplusplus
}
#endif

Wyświetl plik

@ -20,7 +20,7 @@ void beacon_send_own(uint16_t voltage) {
main_own_aprs_msg_len = sprintf(main_own_aprs_msg, "=%s%c%c%s%c%c %s", main_string_latitude, main_config_data_basic->n_or_s, main_symbol_f, main_string_longitude, main_config_data_basic->e_or_w, main_symbol_s, main_config_data_basic->comment);
}
else {
main_own_aprs_msg_len = sprintf(main_own_aprs_msg, "=%s%c%c%s%c%c %s Vbatt %dV", main_string_latitude, main_config_data_basic->n_or_s, main_symbol_f, main_string_longitude, main_config_data_basic->e_or_w, main_symbol_s, main_config_data_basic->comment, (int)voltage);
main_own_aprs_msg_len = sprintf(main_own_aprs_msg, "=%s%c%c%s%c%c %s [Vbatt: %dV]", main_string_latitude, main_config_data_basic->n_or_s, main_symbol_f, main_string_longitude, main_config_data_basic->e_or_w, main_symbol_s, main_config_data_basic->comment, (int)voltage);
}
main_own_aprs_msg[main_own_aprs_msg_len] = 0;
ax25_sendVia(&main_ax25, main_own_path, main_own_path_ln, main_own_aprs_msg, main_own_aprs_msg_len);

Wyświetl plik

@ -19,6 +19,16 @@
uint16_t telemetry_counter = 0;
#ifdef PARAMETEO
#include "pwr_save.h"
const char * telemetry_vbatt_normal = "VBATT_GOOD";
const char * telemetry_vbatt_low = "VBATT_LOW";
const char * telemetry_vbatt_cutoff = "VBATT_CUTOFF";
const char * telemetry_vbatt_unknown = "VBATT_UNKNOWN";
#endif
void telemetry_send_chns_description_pv(const config_data_basic_t * const config_basic) {
// a buffer to assembly the 'call-ssid' string at the begining of the frame
@ -549,5 +559,56 @@ void telemetry_send_status_raw_values_modbus(void) {
#endif
}
void telemetry_send_status_powersave_cutoff(uint16_t battery_voltage, int8_t previous_cutoff, int8_t current_cutoff) {
const char *p, *c;
// telemetry_vbatt_unknown
if ((previous_cutoff & CURRENTLY_CUTOFF) != 0) {
p = telemetry_vbatt_cutoff;
}
else if ((previous_cutoff & CURRENTLY_VBATT_LOW) != 0) {
p = telemetry_vbatt_low;
}
else if (((previous_cutoff & CURRENTLY_CUTOFF) == 0) && (previous_cutoff & CURRENTLY_VBATT_LOW) == 0){
p = telemetry_vbatt_normal;
}
else {
p = telemetry_vbatt_unknown;
}
if ((current_cutoff & CURRENTLY_CUTOFF) != 0) {
c = telemetry_vbatt_cutoff;
}
else if ((current_cutoff & CURRENTLY_VBATT_LOW) != 0) {
c = telemetry_vbatt_low;
}
else if (((current_cutoff & CURRENTLY_CUTOFF) == 0) && (current_cutoff & CURRENTLY_VBATT_LOW) == 0){
c = telemetry_vbatt_normal;
}
else {
c = telemetry_vbatt_unknown;
}
main_wait_for_tx_complete();
memset(main_own_aprs_msg, 0x00, sizeof(main_own_aprs_msg));
main_own_aprs_msg_len = sprintf(main_own_aprs_msg, ">[powersave cutoff change][Vbatt: %dV][previous: %d - %s][currently: %d - %s]", battery_voltage, previous_cutoff, p, current_cutoff, c);
ax25_sendVia(&main_ax25, main_own_path, main_own_path_ln, main_own_aprs_msg, main_own_aprs_msg_len);
//while (main_ax25.dcd == 1);
afsk_txStart(&main_afsk);
main_wait_for_tx_complete();
}
void telemetry_send_status_powersave_registers(uint32_t register_last_sleep, uint32_t register_last_wakeup, uint32_t register_counters, uint32_t monitor, uint32_t last_sleep_time) {
main_wait_for_tx_complete();
memset(main_own_aprs_msg, 0x00, sizeof(main_own_aprs_msg));
main_own_aprs_msg_len = sprintf(main_own_aprs_msg, ">[powersave registers][register_last_sleep: 0x%lX][register_last_wakeup: 0x%lX][register_counters: 0x%lX][monitor: 0x%lX][last_sleep_time: 0x%lX]",register_last_sleep, register_last_wakeup, register_counters, monitor, last_sleep_time);
ax25_sendVia(&main_ax25, main_own_path, main_own_path_ln, main_own_aprs_msg, main_own_aprs_msg_len);
//while (main_ax25.dcd == 1);
afsk_txStart(&main_afsk);
main_wait_for_tx_complete();
}

Wyświetl plik

@ -46,7 +46,6 @@ void SendWXFrame(uint16_t windspeed, uint16_t windgusts, uint16_t winddirection,
if (wind_speed_mph > wind_gusts_mph) {
return;
rte_main_reboot_req = 1;
}
pressure = (unsigned)(cisnienie * 10);

Wyświetl plik

@ -425,6 +425,39 @@ int system_clock_configure_l4(void)
return 0;
}
void system_clock_start_rtc_l4(void) {
// starting RTC
RCC->BDCR |= RCC_BDCR_RTCEN;
// enable write access to RTC registers by writing two magic words
RTC->WPR = 0xCA;
RTC->WPR = 0x53;
// enter the clock set mode
RTC->ISR |= RTC_ISR_INIT;
// wait for going into clock set mode
while((RTC->ISR & RTC_ISR_INITF) == 0);
// set date
RTC->DR = 0x0021A820;
// set time
RTC->TR = 0x00232711;
// exit RTC set mode
RTC->ISR &= (0xFFFFFFFF ^ RTC_ISR_INIT);
// disable wakeup interrupt and wakeup interrupt
RTC->CR = 0;
// wait for wakeup timer to disable
while((RTC->ISR & RTC_ISR_WUTWF) == 0);
// set the source clock for RTC wakeup as CK_SPRE
RTC->CR |= RTC_CR_WUCKSEL_2;
}
int system_clock_configure_rtc_l4(void) {
int retval = 0;
@ -434,6 +467,9 @@ int system_clock_configure_rtc_l4(void) {
// check if LSE is working now
uint8_t lse_is_working = ((RCC->BDCR & RCC_BDCR_LSERDY) > 0) ? 1 : 0;
// enable access to backup domain
PWR->CR1 |= PWR_CR1_DBP;
// if LSE is not working reinitialize everything
if (lse_is_working == 0) {
@ -449,9 +485,6 @@ int system_clock_configure_rtc_l4(void) {
// but clear reset flag before
RCC->BDCR &= (0xFFFFFFFF ^ RCC_BDCR_BDRST);
// enable access to backup domain
PWR->CR1 |= PWR_CR1_DBP;
// set the clock source for RTC clock to LSE
RCC->BDCR |= RCC_BDCR_RTCSEL_0;
@ -463,35 +496,13 @@ int system_clock_configure_rtc_l4(void) {
// wait for LSE to start
while((RCC->BDCR & RCC_BDCR_LSERDY) == 0);
// starting RTC
RCC->BDCR |= RCC_BDCR_RTCEN;
// enable write access to RTC registers by writing two magic words
RTC->WPR = 0xCA;
RTC->WPR = 0x53;
// enter the clock set mode
RTC->ISR |= RTC_ISR_INIT;
// wait for going into clock set mode
while((RTC->ISR & RTC_ISR_INITF) == 0);
// set date
RTC->DR = 0x0021A820;
// set time
RTC->TR = 0x00232711;
// exit RTC set mode
RTC->ISR &= (0xFFFFFFFF ^ RTC_ISR_INIT);
// set the source clock for RTC wakeup as CK_SPRE
RTC->CR |= RTC_CR_WUCKSEL_2;
}
// starting and configuring the RTC itself
system_clock_start_rtc_l4();
// disable access do backup domain
PWR->CR1 &= (0xFFFFFFFF ^ PWR_CR1_DBP);
return retval;
}
@ -501,6 +512,11 @@ void system_clock_configure_auto_wakeup_l4(uint16_t seconds) {
// enable access to backup domain
PWR->CR1 |= PWR_CR1_DBP;
// check if RTC is working
if ((RCC->BDCR & RCC_BDCR_RTCEN) == 0) {
system_clock_start_rtc_l4();
}
// enable write access to RTC registers by writing two magic words
RTC->WPR = 0xCA;
RTC->WPR = 0x53;
@ -534,6 +550,9 @@ void system_clock_configure_auto_wakeup_l4(uint16_t seconds) {
// enable wakeup interrupt
NVIC_EnableIRQ(RTC_WKUP_IRQn);
// disable access do backup domain
PWR->CR1 &= (0xFFFFFFFF ^ PWR_CR1_DBP);
}

Wyświetl plik

@ -670,7 +670,7 @@ void rtu_get_raw_values_string(char* out, uint16_t out_buffer_ln, uint8_t* gener
f6_value = rte_wx_modbus_rtu_f6.registers_values[0];
string_ln = snprintf(out, out_buffer_ln, ">F1V %X, F2V %X, F3V %X, F4V %X, F5V %X, F6V %X",
string_ln = snprintf(out, out_buffer_ln, ">[F1V: %X][F2V: %X][F3V: %X][F4V: %X][F5V: %X][F6V: %X]",
(int) f1_value,
(int) f2_value,
(int) f3_value,