From 9da2c6b0876fd3017e9ee089a9a59bc8b9715db0 Mon Sep 17 00:00:00 2001 From: Nathael Pajani Date: Wed, 13 Dec 2023 23:02:41 +0100 Subject: [PATCH] Rework of the main algorithm, to be tested --- v10/comm.h | 1 + v10/config.c | 5 +- v10/config.h | 1 + v10/interface.c | 4 +- v10/main.c | 569 ++++++++++++++++++++++++++---------------------- v10/version.h | 2 +- 6 files changed, 318 insertions(+), 264 deletions(-) diff --git a/v10/comm.h b/v10/comm.h index d2fc29d..c1d35bb 100644 --- a/v10/comm.h +++ b/v10/comm.h @@ -22,6 +22,7 @@ #ifndef COMM_H #define COMM_H +#include "data.h" /***************************************************************************** */ /* Rx interrupt handler for system configuration over USB */ diff --git a/v10/config.c b/v10/config.c index dc834b7..c35240b 100644 --- a/v10/config.c +++ b/v10/config.c @@ -242,8 +242,7 @@ void scialys_systick_and_timers_config(void) /* Configure the fake zero-cross generation timer to 100Hz. * Do not start it now, it will be started by the first real zero-cross detected in order to - * generate the other half zc (not seen by system due to hardware design) - * Also sarted by config when DC mode is set */ + * generate the other half zc (not seen by system due to hardware design) */ timer_set_match(LPC_TIMER_32B0, CHAN0, (clk_cycles_ac_zc * 100)); /* Configure the power tracking timer. @@ -419,7 +418,7 @@ uint32_t sunny_days_prod_value = 0; * grid_power_limit is in kVA, max_intensity in mA */ void update_max_intensity(void) { - max_intensity = sc_conf.grid_power_limit * 1000 * 1000 / 230; + max_intensity = (uint32_t)(sc_conf.grid_power_limit * 1000 * 1000) / 230; uprintf(UART0, "Max intensity is %dmA\n", max_intensity); } /* Update sunny_days_prod_value (Watt to mA) */ diff --git a/v10/config.h b/v10/config.h index d97ed99..4fdb31c 100644 --- a/v10/config.h +++ b/v10/config.h @@ -52,6 +52,7 @@ /* This struct is stored to user flash when user validates new configuration * and read from user flash upon statup * Default values are defined within config.c + * Note that temperature values are stored as hundredth of degrees centigrade (1/100) * * Meaning of fields : * diff --git a/v10/interface.c b/v10/interface.c index 5ccac17..f1db754 100644 --- a/v10/interface.c +++ b/v10/interface.c @@ -213,7 +213,7 @@ extern int water_centi_degrees; extern uint32_t solar_prod_value; extern uint32_t home_conso_value; extern volatile uint8_t command_val; -extern int manual_activation_request; +extern uint8_t manual_activation_request; static int interface_mode = MODE_RUN; @@ -240,7 +240,7 @@ void interface_update(char heat_mode) if (interface_mode == MODE_RUN) { if (button_pressed != 0) { if (button_pressed & BUTTON_OK) { - manual_activation_request = -1; /* Tells main loop that a request has been triggered */ + manual_activation_request = 1; /* Tells main loop that a request has been triggered */ } if (button_pressed & BUTTON_UP) { interface_mode = MODE_CONFIG; diff --git a/v10/main.c b/v10/main.c index 5ae9c57..c61764a 100644 --- a/v10/main.c +++ b/v10/main.c @@ -22,6 +22,7 @@ *************************************************************************** */ +#include "lib/utils.h" #include "config.h" #include "interface.h" #include "time.h" @@ -31,7 +32,7 @@ #include "uSD.h" -#define MODULE_VERSION 0x0A +#define MODULE_VERSION 0x0A #define MODULE_NAME "Scialys uC" @@ -42,19 +43,21 @@ /* This multiplier is used for all durations and delays which are stored in number of hours */ #define T_MULT (3600 * 1000 / DEC_PERIOD) -/* Max water temperature. Internal protection which cannot be overriden by configuration */ -#define ABSOLUTE_MAX_WATER_TEMP (90 * 100) /* Hundredth of degrees C : 90°C */ +/* Max water temperature. Internal protection which cannot be overriden by configuration + * Note that configuration should not allow temperature above 90°C */ +#define ABSOLUTE_MAX_WATER_TEMP (92 * 100) /* Hundredth of degrees C : 92°C */ -/* Number of main loops during which we keep the mosfets ON in order to keep them safe */ -#define OVERVOLTAGE_PROTECTION_CYCLES 100 -/* Flags and counters */ -uint8_t forced_heater_mode = 0; /* Flag only */ +/* Flags and counters for forced modes */ +uint8_t forced_heater_mode = 0; /* Flag and force type (enum force_types) */ +uint8_t manual_activation_request = 0; /* Flag */ +uint16_t forced_target_temp = 0; uint32_t forced_heater_delay = 0; /* Flag and counter */ -uint32_t forced_heater_time = 0; /* Flag and counter */ -uint8_t manual_forced_heater = 0; /* Flag only */ -int manual_activation_request = 0; /* Flag and counter */ +uint32_t forced_heater_duration = 0; /* Flag and counter */ +uint8_t forced_cmd_val = 0; + +/* Error flags */ int8_t internal_temp_error_shutdown = 0; /* Flag and error code */ uint8_t external_disable = 0; /* Flag only */ uint8_t mosfet_temp_shutdown = 0; /* Flag only */ @@ -67,12 +70,15 @@ enum modes { mode_forced = 'F', /* Auto Forced heating */ mode_manual = 'M', /* Manual Forced heating */ mode_delayed_heat_prod = 'P', /* Pause */ - mode_overprod = 'O', /* Over production, try to start other loads */ mode_temp_OK = 'T', /* Max temperature reached */ mode_overvoltage = 'V', /* Overvoltage detected */ mode_overtemp = 'H', /* Mosfet over-temperature detected */ }; +/* Current running mode */ +volatile char mode = mode_heat; +volatile char old_mode = mode_heat; + /* Water temperature */ int water_centi_degrees = 0; @@ -92,24 +98,30 @@ struct rtc_time now; /***************************************************************************** */ -/* Decrementer for forced heating modes timers */ +/* Decrementer + * - decrease forced heating modes timers + * - decrease overvoltage protection timer + */ void handle_dec_request(uint32_t curent_tick) { - /* Manual forced mode */ - if (manual_activation_request > 0) { - manual_activation_request--; - } - /* Automatic forced mode */ - if (forced_heater_mode == 1) { + /* Forced mode */ + if (forced_heater_mode > FORCE_TYPE_OFF) { if (forced_heater_delay > 0) { forced_heater_delay--; } else { - if (forced_heater_time > 0) { - forced_heater_time--; + if (forced_heater_duration > 0) { + forced_heater_duration--; } } } + /* Update Over-Voltage information to exit over-voltage protection mode */ + if (overvoltage > 0) { + uint8_t ov_tmp = (gpio_read(overvoltage_pin) ? 1 : 0); + if (ov_tmp == 0) { + overvoltage--; + } + } } @@ -117,7 +129,12 @@ void handle_dec_request(uint32_t curent_tick) /***************************************************************************** */ /* AC control */ -volatile int act_cmd = 0; /* Start off */ +/* Handle the power command */ +volatile uint8_t act_cmd = 0; /* Start off */ +volatile uint8_t command_val = 0; /* Value displayed on interface */ + +extern uint32_t power_delay[101]; +volatile uint32_t zc_cnt = 0; void set_ctrl_duty_cycle(uint8_t value) { @@ -131,20 +148,33 @@ void set_ctrl_duty_cycle(uint8_t value) } } -void ac_switch_on(uint32_t flags) +/* Over-voltage protection */ +/* Number of DEC_PERIOD during which we keep the mosfets ON in order to keep them safe */ +#define OVERVOLTAGE_PROTECTION_CYCLES 100 +#define PROTECTION_CMD_VAL 100 +void overvoltage_protect(uint32_t gpio) { - gpio_clear(ac_ctrl); + gpio_clear(ac_ctrl); /* Turn mosfets ON */ + timer_stop(LPC_TIMER_32B1); /* Stop mosfets timer */ + set_ctrl_duty_cycle(PROTECTION_CMD_VAL); /* Update "actual command" */ + overvoltage = OVERVOLTAGE_PROTECTION_CYCLES; + gpio_set(fan_ctrl); /* Turn on FAN immediatly */ + /* Change current working mode */ + old_mode = mode; + mode = mode_overvoltage; } -extern uint32_t power_delay[101]; -volatile uint32_t zc_cnt = 0; +/* Used as timer callback to turn ON mosfets */ +void ac_switch_on(uint32_t flags) +{ + gpio_clear(ac_ctrl); +} -/* - * Zero crossing handler (either detected or fake one) +/* Zero crossing handler (either detected or fake one) * If command is at 100%, only set (keep ?) Mosfets ON (gpio_clear) * Else, start with mosfets OFF, in order not to have to break established current. - * FIXME : If U and I not in sync, we should sync to I nul, not V nul. + * FIXME : If U and I not in sync, we should sync to I nul, not U nul. */ void zero_cross(uint32_t unused) { @@ -178,17 +208,14 @@ void zero_cross_detect(uint32_t unused) } - -/* Handle the power command */ -volatile uint8_t command_val = 0; -int8_t old_cmd = 0; /* Used to store cmd value when entering over-voltage protection mode */ +/***************************************************************************** */ +/* Update current command depending on current mode and power production and consumption */ #define FAN_COUNTER_START_VAL (15 * 1000) -static uint16_t fan_on = 0; -uint8_t force_fan = 0; +volatile uint16_t fan_on = 0; +volatile uint8_t force_fan = 0; extern uint8_t test_force_fan; /* Request to force fan ON from test menu */ -#define PROTECTION_CMD_VAL 100 -static uint8_t linky_disable = 0; +volatile uint8_t linky_test = 0; #define CMD_UP_DELAY_RESET_VALUE 3 void handle_cmd_update(uint32_t curent_tick) { @@ -196,135 +223,99 @@ void handle_cmd_update(uint32_t curent_tick) static uint8_t cmd_up_delay = CMD_UP_DELAY_RESET_VALUE; int delta = solar_prod_value - home_conso_value; - /* Forced over-voltage protection or test mode */ - if (overvoltage != 0) { - cmd = PROTECTION_CMD_VAL; - goto cmd_update_end; - } else if (old_cmd != -1) { - /* Get back to normal after over-voltage protection */ - cmd = old_cmd; - old_cmd = -1; - } - - /* Reset force_fan to current test value */ - force_fan = test_force_fan; - - /* Mosfet temperature limit reached, turn ON all mosfets to prevent internal damage of board */ - if (mosfet_temp_shutdown == 1) { - cmd = PROTECTION_CMD_VAL; - force_fan = 1; - goto cmd_update_end; - } - - /* Water max temperature protection with hysteresys */ - if ((water_centi_degrees > ABSOLUTE_MAX_WATER_TEMP) || - (water_centi_degrees > sc_conf.conf_max_temp) || - (water_centi_degrees > max_temp_hysteresys)) { - cmd = 0; - max_temp_hysteresys = (ABSOLUTE_MAX_WATER_TEMP - 150); /* 1.5 °C */ - if (max_temp_hysteresys > sc_conf.conf_max_temp) { - max_temp_hysteresys = (sc_conf.conf_max_temp - 150); /* 1.5 °C */ - } - goto cmd_update_end; - } else if (water_centi_degrees < max_temp_hysteresys) { - /* Remove Hysteresys */ - max_temp_hysteresys = ABSOLUTE_MAX_WATER_TEMP; - } - - /* Unable to read internal temperature or temperature above max internal temp : turn off heating */ - if (internal_temp_error_shutdown < 0) { - cmd = 0; - force_fan = 1; - goto cmd_update_end; - } - /* Which is the current mode ? */ - if (forced_heater_mode == 1) { - /* Forced heating mode */ - if ((forced_heater_delay == 0) && (forced_heater_time > 0)) { - cmd = sc_conf.auto_forced_mode_value; - goto cmd_update_limited_end; - } - if (manual_forced_heater > 0) { - cmd = sc_conf.manual_forced_mode_value; - goto cmd_update_limited_end; - } - /* Entering forced heating mode from temperature getting below threshold, - * wait some delay before effective forced heating */ - if (forced_heater_time == 0) { - forced_heater_delay = sc_conf.auto_forced_heater_delay * T_MULT; - forced_heater_time = forced_heater_delay + (sc_conf.auto_forced_heater_duration * T_MULT); - } - } - if (delta < -1280) { - /* Much more power used than produced */ - if (cmd > 10) { - cmd -= 10; - } else { - cmd = 0; - } - } else if (delta < -64) { - /* More power used than produced */ - if (cmd > 0) { - cmd--; - } - } else if (delta > 1280) { - /* Much more production than used power */ - if (cmd <= 98) { - cmd += 2; - } else { - cmd = 100; - } - } else if (delta > 192) { - /* More production, but do not rise too quickly when getting close - * to balance to prevent oscilations */ - if (cmd_up_delay > 0) { - cmd_up_delay--; - } else { - cmd_up_delay = CMD_UP_DELAY_RESET_VALUE; - if (cmd < 100) { - cmd++; + switch (mode) { + case mode_overvoltage: + /* End over-voltage protection ? */ + if (overvoltage == 0) { + mode = old_mode; + } else { + cmd = PROTECTION_CMD_VAL; } - } - } - -cmd_update_limited_end: - command_val = cmd; - /* Limit external power used when in force mode ! */ - if (delta < -max_intensity) { - cmd = 0; - linky_disable |= 16; - if ((forced_heater_delay == 0) && (forced_heater_time > 0)) { - /* Wait for 100 * 100ms (10s) before trying to heat again */ - forced_heater_delay = 100; - } - if (manual_forced_heater > 0) { - /* Re-increment by one the delay */ - manual_activation_request++; - } - } - /* Test for Linky - FIXME */ -#if 0 - linky_disable = 0; - if ((cmd > 48) && (cmd < 100)) { - if (water_centi_degrees > (50 * 100)) { - if (delta > 6000) { - linky_disable = 2; - cmd = 100; + break; + case mode_overtemp: + /* End over-temperature protection ? */ + if ((mosfet_temp_shutdown == 0) && (internal_temp_error_shutdown >= 0)) { + mode = old_mode; } else { - linky_disable = 4; - cmd = 48; + cmd = 0; + force_fan = 1; } - } else { - linky_disable = 8; - cmd = 100; - } + break; + case mode_manual: + case mode_forced: + /* Forced heating mode */ + if ((forced_heater_delay == 0) && (forced_heater_duration > 0)) { + /* Limit external power used when in force mode ! */ + if (delta >= 0) { + cmd = forced_cmd_val; + } else if (delta < -max_intensity) { + if (cmd >= 10) { + cmd -= 10; + } else { + cmd = 0; + } + } else if (cmd < forced_cmd_val) { + if (cmd == 0) { + /* Start with a high enough value to avoid triggering overvoltage protection */ + cmd = min(forced_cmd_val, 40); + } else { + cmd++; + } + } + break; + } + /* FALTHROUGH : automatic force delay period, try to use what is available anyway */ + case mode_ext_disable: + case mode_delayed_heat_prod: + /* automatic force disabled due to current production, try to use what is available */ + case mode_heat: + /* Set load power according to extra power production */ + if (delta < -1280) { + /* Much more power used than produced */ + if (cmd > 10) { + cmd -= 10; + } else { + cmd = 0; + } + } else if (delta < -64) { + /* More power used than produced */ + if (cmd > 0) { + cmd--; + } + } else if (delta > 1280) { + /* Much more production than used power */ + if (cmd == 0) { + /* Start with a high enough value to avoid triggering overvoltage protection */ + cmd = 40; + } else if (cmd <= 98) { + cmd += 2; + } else { + cmd = 100; + } + } else if (delta > 192) { + /* More production, but do not rise too quickly when getting close + * to balance to prevent oscilations */ + if (cmd_up_delay > 0) { + cmd_up_delay--; + } else { + cmd_up_delay = CMD_UP_DELAY_RESET_VALUE; + if (cmd < 100) { + cmd++; + } + } + } + break; + case mode_temp_OK: + default: + cmd = 0; + break; } -#endif -cmd_update_end: + /* Reset force_fan to current test value */ + force_fan |= test_force_fan; /* Update FAN command (start or stop FAN) */ - if ((cmd > 0) || (force_fan == 1)) { + if ((cmd > 0) || force_fan) { fan_on = FAN_COUNTER_START_VAL; gpio_set(fan_ctrl); } else { @@ -334,121 +325,169 @@ cmd_update_end: gpio_clear(fan_ctrl); } } - //command_val = cmd; + +#if 0 + /* Test for Linky - FIXME */ + linky_test = 0; + if ((cmd > 48) && (cmd < 100)) { + if (water_centi_degrees > (50 * 100)) { + linky_test = 2; + cmd = 48; + } else { + linky_test = 4; + cmd = 100; + } + } +#endif + + /* Store command for display */ + command_val = cmd; /* Set Control Output duty cycle */ set_ctrl_duty_cycle(cmd); } -/* Over-voltage protection */ -void overvoltage_protect(uint32_t gpio) -{ - gpio_clear(ac_ctrl); /* Turn mosfets ON */ - timer_stop(LPC_TIMER_32B1); /* Stop mosfets timer */ - set_ctrl_duty_cycle(PROTECTION_CMD_VAL); /* Update "actual command" */ - overvoltage = OVERVOLTAGE_PROTECTION_CYCLES; - gpio_set(fan_ctrl); /* Turn on FAN immediatly */ - old_cmd = command_val; /* Save current command value (to be restored after overvoltage protection */ -} - +/***************************************************************************** */ /* Update current working mode depending on environnement */ -volatile char mode = mode_heat; /* Debug info */ + +/* There's three possible scenario and a few limits which define the command value. + * Possible scenario by order of priority : + * - Manual forced mode : + * This mode is entered when the user presses the "OK" button on the interface when the interface + * is in mode "run", which sets manual_activation_request to 1 + * This mode lasts for as much as sc_conf.manual_activation_duration (hours) or until + * sc_conf.manual_target_heater_temp is reached + * Which target is used depends on sc_conf.manual_force_type. + * In this mode, heating is made at sc_conf.manual_forced_mode_value, unless local energy + * consumption goes beyond sc_conf.grid_power_limit + * - Automatic force mode : + * This mode is entered when the water temperature goes below sc_conf.enter_forced_mode_temp + * This mode lasts for as much as sc_conf.auto_forced_heater_duration (hours) or until + * sc_conf.auto_forced_target_heater_temp is reached + * Which target is used depends on sc_conf.auto_force_type. + * In this mode, heating starts only after a delay of sc_conf.auto_forced_heater_delay (hours) in + * order to wait for possible automatic heating from the local energy produced. This is usefull to + * prevent heating while another appliance is being used for a short time, or right after the + * morning showers while the local energy production system may produce enough energy during the + * day to come. + * Automatic heating can happen during the delay period, and in this case automatic force mode is + * only delayed further if sc_conf.source_has_power_ok is reached by the local energy production + * and exited only if sc_conf.auto_forced_target_heater_temp is reached by the water temperature. + * In this mode, heating is made at sc_conf.auto_forced_mode_value unless local energy + * consumption goes beyond sc_conf.grid_power_limit + * - Automatic heating : + * In this mode (which is the main purpose of this module) heating is controlled by the difference + * between local energy production and local energy consumption. + * + * Limits : + * - Water temperature : + * There are two "software" temperature limits and one "hardware" limit. + * The hardware limit comes from the water tank heating system and cannot be overriden. + * It is unkown and irrelevant to this algorithm. It is the only real "security" limit. + * The two other limits are software ones : one hard-coded upper limit of 90°C which is not + * advertised to the user, and one configurable through sc_conf.conf_max_temp. + * Reching these limits should stop heating completely, unless there's an overvoltage condition. + * - External disable switch : + */ + volatile char* msg = NULL; void mode_update(void) { - /* Default mode : try to heat the water tank */ - mode = mode_heat; - - /* Need to enter Forced heating mode ? */ - if ((water_centi_degrees < sc_conf.enter_forced_mode_temp) && (sc_conf.auto_force_type != FORCE_TYPE_OFF)) { - if (forced_heater_mode == 0) { - msg = "Water temp low, entering forced mode\n"; - forced_heater_mode = 1; - } - status_led(red_on); - mode = mode_forced; - } else if (forced_heater_mode == 1) { - int exit_forced = 0; - /* End of forced heating ? (target reached) ? */ - switch (sc_conf.auto_force_type) { - case FORCE_TYPE_TIMER: - case FORCE_TYPE_TARGET: - if (water_centi_degrees > sc_conf.auto_forced_target_heater_temp) { - exit_forced = 1; - } - break; - case FORCE_TYPE_MIN: - if (water_centi_degrees > sc_conf.auto_forced_target_heater_temp) { - exit_forced = 1; - } - case FORCE_TYPE_MAX: - if (water_centi_degrees > sc_conf.auto_forced_target_heater_temp) { - exit_forced = 1; - } - } - if (exit_forced == 1) { - status_led(red_off); - msg = "Water temp OK, forced mode exit\n"; - forced_heater_mode = 0; - mode = mode_temp_OK; - } else { - mode = mode_forced; - } + /* Check protections first */ + if ((mode == mode_overvoltage) || (mode == mode_overtemp)) { + return; } - - /* Do not force if there is a lot of sun, it may be enough to heat again soon - * 'sunny_days_prod_value' is computed from 'sc_conf.source_has_power_ok' - */ - if ((solar_prod_value > sunny_days_prod_value) && (forced_heater_mode == 1)) { - mode = mode_delayed_heat_prod; - forced_heater_mode = 0; + /* Mosfet temperature limit reached or internal temperature above max internal temp */ + if ((mosfet_temp_shutdown != 0) || (internal_temp_error_shutdown < 0)) { + old_mode = mode; + mode = mode_overtemp; + return; } - /* Do not force heating if disabled by external command */ - external_disable = (gpio_read(ext_disable_in_pin) ? 0 : 1); /* Invert : input is pulled low when external disable is ON */ - if ((external_disable == 1) && (forced_heater_mode != 0)) { - forced_heater_mode = 0; - mode = mode_ext_disable; - msg = "Forced mode disabled by external input\n"; + /* Water temperature reached config limit ? */ + if (water_centi_degrees >= sc_conf.conf_max_temp) { + mode = mode_temp_OK; /* Max temperature reached */ + return; } - /* Get Over-Temperature information */ - mosfet_temp_shutdown = (gpio_read(overtemperature_pin) ? 0 : 1); /* Invert : Temp switch is NC type */ - if (mosfet_temp_shutdown != 0) { - mode = mode_overtemp; - } + /* Default mode : try to heat the water tank */ + mode = mode_heat; - /* Update Over-Voltage information - Only used to exit over-voltage protection mode */ - if (overvoltage > 0) { - uint8_t ov_tmp = (gpio_read(overvoltage_pin) ? 1 : 0); - if (ov_tmp == 0) { - overvoltage--; - } - mode = mode_overvoltage; + /* Did the user request a forced heating ? */ + if (manual_activation_request == 1) { + msg = "Entering manual forced mode\n"; + forced_heater_mode = sc_conf.manual_force_type; + forced_target_temp = sc_conf.manual_target_heater_temp; + forced_heater_duration = sc_conf.manual_activation_duration * T_MULT; + forced_cmd_val = sc_conf.manual_forced_mode_value; + forced_heater_delay = 0; + manual_activation_request = 2; } - if (sc_conf.never_force == 1) { - forced_heater_mode = 0; + /* Do we need automatic forced heating ? */ + if ((forced_heater_mode == FORCE_TYPE_OFF) && (water_centi_degrees < sc_conf.enter_forced_mode_temp)) { + forced_heater_mode = sc_conf.auto_force_type; + if (forced_heater_mode != FORCE_TYPE_OFF) { + msg = "Water temp low, entering forced mode\n"; + forced_target_temp = sc_conf.auto_forced_target_heater_temp; + forced_heater_duration = sc_conf.auto_forced_heater_duration * T_MULT; + forced_cmd_val = sc_conf.auto_forced_mode_value; + forced_heater_delay = sc_conf.auto_forced_heater_delay * T_MULT; + } } - /* Did the user request a forced heating ? */ - if (manual_activation_request != 0) { - forced_heater_mode = 1; - mode = mode_manual; - if (manual_activation_request == -1) { - msg = "Entering manual forced mode\n"; - manual_activation_request = sc_conf.manual_activation_duration * T_MULT; - manual_forced_heater = 1; + /* Handle specific cases when forced heating is ON */ + if (forced_heater_mode != FORCE_TYPE_OFF) { + int exit_forced = 0; /* Need to reach 2 to exit forced heating */ + /* End of forced heating ? (target reached) ? */ + if (water_centi_degrees > forced_target_temp) { + if ((forced_heater_mode == FORCE_TYPE_MIN) || (forced_heater_mode == FORCE_TYPE_TARGET)) { + msg = "Water temp OK, forced mode exit\n"; + exit_forced = 2; + } else { + exit_forced = 1; + } + } + if (forced_heater_duration == 0) { + if ((forced_heater_mode == FORCE_TYPE_MIN) || (forced_heater_mode == FORCE_TYPE_TIMER)) { + msg = "Water heating timer elapsed, forced mode exit\n"; + exit_forced = 2; + } else { + exit_forced++; + } } - if (manual_activation_request < 10) { - msg = "Leaving manual forced mode\n"; + if (exit_forced >= 2) { + /* Exit condition reached */ + forced_heater_mode = FORCE_TYPE_OFF; manual_activation_request = 0; + mode = mode_heat; + } else { + if (manual_activation_request == 2) { + mode = mode_manual; + } else if (solar_prod_value > sunny_days_prod_value) { + /* Do not force if there is a lot of sun, it may be enough to heat again soon + * 'sunny_days_prod_value' is computed from 'sc_conf.source_has_power_ok' + */ + mode = mode_delayed_heat_prod; + if (forced_heater_delay < 100) { + forced_heater_delay = 100; /* FIXME : add some time (N * DEC_PERIOD) to the delay value */ + } + } else { + mode = mode_forced; + } + } + /* Do not force heating if disabled by external command */ + if (external_disable == 1) { + forced_heater_mode = FORCE_TYPE_OFF; + mode = mode_ext_disable; + msg = "Forced mode disabled by external input\n"; + } + /* Do not force heating if disabled by configuration */ + if (sc_conf.never_force == 1) { + forced_heater_mode = FORCE_TYPE_OFF; + mode = mode_heat; + msg = "Forced mode disabled by configuration\n"; } - } - - /* Command at 100% and still more production than energy used ? */ - if ((command_val == 100) && (solar_prod_value > home_conso_value)) { - mode = mode_overprod; } } @@ -475,8 +514,9 @@ void store_data(uint32_t cur_tick) /* Each flag is set if seen once within the interval */ data.flags |= (fan_on ? 1 : 0) | (force_fan << 1); - data.flags |= (((internal_temp_error_shutdown < 0) ? 1 : 0) << 2); - data.flags |= (mosfet_temp_shutdown << 3) | (overvoltage << 4); + data.flags |= ((internal_temp_error_shutdown < 0) ? (0x01 << 2) : 0); + data.flags |= (mosfet_temp_shutdown << 3); + data.flags |= ((overvoltage > 0) ? (0x01 << 4) : 0); data.flags |= (external_disable << 5); data.flags |= (forced_heater_mode << 6) | (manual_activation_request << 7); @@ -499,7 +539,7 @@ void store_data(uint32_t cur_tick) data.deci_degrees_disp = data.deci_degrees_disp / nb_val; data.load_power_lowest = data.load_power_lowest / nb_val; data.load_power_highest = data.load_power_highest / nb_val; - /* Add "fixed ones */ + /* Add "fixed" ones */ data.command_val = command_val; data.act_cmd = act_cmd; data.mode = mode; @@ -513,6 +553,7 @@ void store_data(uint32_t cur_tick) } } +/* Send data on UEXT communication port for slave module or communication extention */ void slave_send_data(void) { static struct scialys_data data; @@ -539,6 +580,7 @@ void slave_send_data(void) comm_tx(&data); } + /***************************************************************************** */ int main(void) { @@ -555,13 +597,18 @@ int main(void) scialys_systick_and_timers_config(); + /* Changing load type is not allowed without turning the module off, so checking outside of main loop is OK */ + if (sc_conf.load_type == LOAD_TYPE_DC) { + add_systick_callback(zero_cross_detect, 20); + } + uprintf(UART0, "System setup complete.\n"); msleep(100); status_led(green_only); while (1) { /* Feed the dog */ - if ((solar_prod_value != 0) && (home_conso_value != 0)) { + if ((solar_prod_value != 0) && (home_conso_value != 0) && (water_centi_degrees < ABSOLUTE_MAX_WATER_TEMP)) { watchdog_feed(); } @@ -571,14 +618,20 @@ int main(void) /* Update water tank temperature */ water_centi_degrees = water_temp_update(UART0); + /* Get Over-Temperature information */ + mosfet_temp_shutdown = (gpio_read(overtemperature_pin) ? 0 : 1); /* Invert : Temp switch is NC type */ + + /* Read external disable pin */ + external_disable = (gpio_read(ext_disable_in_pin) ? 0 : 1); /* Invert : input is pulled low when external disable is ON */ + /* Update current mode */ mode_update(); /* Display */ /* only update twice per second */ cur_tick = systick_get_tick_count(); - if ((cur_tick < last_tick_update) || ((~0 - last_tick_update) < 500)) { - /* simple tick wrapping handling */ + /* simple tick wrapping handling */ + if (cur_tick < last_tick_update) { last_tick_update = 0; } if (cur_tick > (last_tick_update + 500)) { @@ -594,7 +647,7 @@ int main(void) /* Data Log */ if (1) { - external_disable |= linky_disable; + external_disable |= linky_test; uprintf(UART0, "#%c:%d:%d:%d:%d:%d:%d:", mode, loop++, solar_prod_value, home_conso_value, water_centi_degrees, deci_degrees_power, deci_degrees_disp); diff --git a/v10/version.h b/v10/version.h index c6d1575..07f4504 100644 --- a/v10/version.h +++ b/v10/version.h @@ -1,3 +1,3 @@ #define MODULE_VERSION_STR "v0.10.2" #define SOFT_VERSION_STR "T" -#define COMPILE_VERSION "75" +#define COMPILE_VERSION "76" -- 2.43.0