Compare commits
5 commits
ext_sensor
...
main
Author | SHA1 | Date | |
---|---|---|---|
Thomas Kolb | e6891aed78 | ||
Thomas Kolb | 19735ee550 | ||
Thomas Kolb | e8dff1f017 | ||
Thomas Kolb | bd08440584 | ||
Thomas Kolb | 2cedcb712a |
35
src/addon_io.c
Normal file
35
src/addon_io.c
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
#include <libopencm3/stm32/gpio.h>
|
||||||
|
|
||||||
|
#include "pinout.h"
|
||||||
|
|
||||||
|
#include "addon_io.h"
|
||||||
|
|
||||||
|
static const uint32_t OUTPUT_LIST[2] = {ADDON_ISO_IO_OUT1, ADDON_ISO_IO_OUT2};
|
||||||
|
|
||||||
|
void addon_io_init(void)
|
||||||
|
{
|
||||||
|
// Isolated outputs configuration: output, initially low = off
|
||||||
|
gpio_clear(ADDON_ISO_IO_PORT, ADDON_ISO_IO_OUT1 | ADDON_ISO_IO_OUT2);
|
||||||
|
gpio_mode_setup(ADDON_ISO_IO_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, ADDON_ISO_IO_OUT1 | ADDON_ISO_IO_OUT2);
|
||||||
|
|
||||||
|
// Isolated inputs configuration: input, no pull resistors
|
||||||
|
gpio_mode_setup(ADDON_ISO_IO_PORT, GPIO_MODE_INPUT, GPIO_PUPD_NONE, ADDON_ISO_IO_IN);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void addon_io_iso_out_on(uint8_t idx)
|
||||||
|
{
|
||||||
|
gpio_set(ADDON_ISO_IO_PORT, OUTPUT_LIST[idx]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void addon_io_iso_out_off(uint8_t idx)
|
||||||
|
{
|
||||||
|
gpio_clear(ADDON_ISO_IO_PORT, OUTPUT_LIST[idx]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool addon_io_read_iso_in(void)
|
||||||
|
{
|
||||||
|
return gpio_get(ADDON_ISO_IO_PORT, ADDON_ISO_IO_IN) != 0;
|
||||||
|
}
|
14
src/addon_io.h
Normal file
14
src/addon_io.h
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
#ifndef ADDON_IO_H
|
||||||
|
#define ADDON_IO_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
void addon_io_init(void);
|
||||||
|
|
||||||
|
void addon_io_iso_out_on(uint8_t idx);
|
||||||
|
void addon_io_iso_out_off(uint8_t idx);
|
||||||
|
|
||||||
|
bool addon_io_read_iso_in(void);
|
||||||
|
|
||||||
|
#endif // ADDON_IO_H
|
|
@ -8,6 +8,7 @@
|
||||||
#include "charge_pump.h"
|
#include "charge_pump.h"
|
||||||
#include "rs485.h"
|
#include "rs485.h"
|
||||||
#include "flash_config.h"
|
#include "flash_config.h"
|
||||||
|
#include "addon_io.h"
|
||||||
|
|
||||||
#include "charge_control.h"
|
#include "charge_control.h"
|
||||||
|
|
||||||
|
@ -26,7 +27,8 @@ static const char *DISCHARGE_STATE_TEXT[DISCHARGE_NUM_STATES] = {
|
||||||
"WAIT_CHARGEPUMP",
|
"WAIT_CHARGEPUMP",
|
||||||
"OK",
|
"OK",
|
||||||
"VOLTAGE_LOW",
|
"VOLTAGE_LOW",
|
||||||
"OVERCURRENT"
|
"OVERCURRENT",
|
||||||
|
"OVERCURRENT_DELAY"
|
||||||
};
|
};
|
||||||
|
|
||||||
static enum ChargeState charge_state;
|
static enum ChargeState charge_state;
|
||||||
|
@ -54,6 +56,7 @@ static fxp_t u_bat_load_on;
|
||||||
static fxp_t u_bat_load_off;
|
static fxp_t u_bat_load_off;
|
||||||
|
|
||||||
static fxp_t load_current_limit;
|
static fxp_t load_current_limit;
|
||||||
|
static fxp_t load_current_limit_delay;
|
||||||
|
|
||||||
static fxp_t internal_temperature_limit;
|
static fxp_t internal_temperature_limit;
|
||||||
static fxp_t internal_temperature_recovery;
|
static fxp_t internal_temperature_recovery;
|
||||||
|
@ -64,6 +67,8 @@ static fxp_t external_temperature_recovery;
|
||||||
static fxp_t sleep_solar_current;
|
static fxp_t sleep_solar_current;
|
||||||
static fxp_t sleep_solar_excess_voltage;
|
static fxp_t sleep_solar_excess_voltage;
|
||||||
|
|
||||||
|
static uint32_t overload_retry_time;
|
||||||
|
|
||||||
|
|
||||||
static enum ChargeState control_solar_charging(
|
static enum ChargeState control_solar_charging(
|
||||||
fxp_t corridor_high,
|
fxp_t corridor_high,
|
||||||
|
@ -243,12 +248,18 @@ static void solar_fsm_update(uint64_t uptime_ms, struct MeasurementResult *meas)
|
||||||
case CHARGE_LOW_EXTERNAL_TEMPERATURE:
|
case CHARGE_LOW_EXTERNAL_TEMPERATURE:
|
||||||
if(charge_state_entered) {
|
if(charge_state_entered) {
|
||||||
power_switch_solar_off();
|
power_switch_solar_off();
|
||||||
|
|
||||||
|
// switch on the heater via the isolated I/O addon board
|
||||||
|
addon_io_iso_out_on(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// this state can only be entered if the BMP280 measurement is valid, so
|
// this state can only be entered if the BMP280 measurement is valid, so
|
||||||
// no need to check it again here.
|
// no need to check it again here.
|
||||||
if(bmp280_get_temperature() > external_temperature_recovery) {
|
if(bmp280_get_temperature() > external_temperature_recovery) {
|
||||||
charge_state = CHARGE_WAIT_CHARGEPUMP;
|
charge_state = CHARGE_WAIT_CHARGEPUMP;
|
||||||
|
|
||||||
|
// switch the heater off again when this state is left
|
||||||
|
addon_io_iso_out_off(0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -287,7 +298,20 @@ static void load_fsm_update(uint64_t uptime_ms, struct MeasurementResult *meas)
|
||||||
|
|
||||||
if((meas->i_load > load_current_limit)
|
if((meas->i_load > load_current_limit)
|
||||||
&& (discharge_time_in_state > FLASH_CONFIG_LOAD_CURRENT_INRUSH_TIME)) {
|
&& (discharge_time_in_state > FLASH_CONFIG_LOAD_CURRENT_INRUSH_TIME)) {
|
||||||
|
if(load_current_limit_delay == 0) {
|
||||||
|
// switch off immediately
|
||||||
|
power_switch_load_off();
|
||||||
discharge_state = DISCHARGE_OVERCURRENT;
|
discharge_state = DISCHARGE_OVERCURRENT;
|
||||||
|
} else {
|
||||||
|
discharge_state = DISCHARGE_OVERCURRENT_DELAY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if((overload_retry_time != FLASH_CONFIG_OVERLOAD_RETRY_TIME) &&
|
||||||
|
(discharge_time_in_state > 300000)) {
|
||||||
|
// overload did not trigger for 5 minutes, so we assume it’s stable and
|
||||||
|
// reset the retry time delay.
|
||||||
|
overload_retry_time = FLASH_CONFIG_OVERLOAD_RETRY_TIME;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(meas->avg_u_bat < u_bat_load_off) {
|
if(meas->avg_u_bat < u_bat_load_off) {
|
||||||
|
@ -304,17 +328,36 @@ static void load_fsm_update(uint64_t uptime_ms, struct MeasurementResult *meas)
|
||||||
// Can only switch on again after a specific amount of time has passed
|
// Can only switch on again after a specific amount of time has passed
|
||||||
if((meas->avg_u_bat > u_bat_load_on)
|
if((meas->avg_u_bat > u_bat_load_on)
|
||||||
&& (discharge_time_in_state > FLASH_CONFIG_LOAD_ON_DELAY)) {
|
&& (discharge_time_in_state > FLASH_CONFIG_LOAD_ON_DELAY)) {
|
||||||
|
discharge_state = DISCHARGE_WAIT_CHARGEPUMP;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DISCHARGE_OVERCURRENT_DELAY:
|
||||||
|
if(meas->i_load < load_current_limit) {
|
||||||
|
// current recovered
|
||||||
discharge_state = DISCHARGE_OK;
|
discharge_state = DISCHARGE_OK;
|
||||||
|
} else if(discharge_time_in_state >= FLASH_CONFIG_OVERLOAD_DELAY_TIME) {
|
||||||
|
// switch off immediately
|
||||||
|
power_switch_load_off();
|
||||||
|
discharge_state = DISCHARGE_OVERCURRENT;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DISCHARGE_OVERCURRENT:
|
case DISCHARGE_OVERCURRENT:
|
||||||
// Battery voltage is too low, so keep the load switched off
|
// Current limit reached
|
||||||
if(discharge_state_entered) {
|
if(discharge_state_entered) {
|
||||||
power_switch_load_off();
|
power_switch_load_off();
|
||||||
}
|
}
|
||||||
|
|
||||||
// no way out except reset
|
// Overload recovery
|
||||||
|
if(discharge_time_in_state >= overload_retry_time) {
|
||||||
|
// double the overload retry time for the next turn if it is less than 7 days
|
||||||
|
if(overload_retry_time < (7*24*3600*1000)) {
|
||||||
|
overload_retry_time *= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
discharge_state = DISCHARGE_WAIT_CHARGEPUMP;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -360,6 +403,8 @@ void charge_control_init(void)
|
||||||
|
|
||||||
sleep_solar_current = fxp_div(FXP_FROM_INT(FLASH_CONFIG_SLEEP_SOLAR_CURRENT), FXP_FROM_INT(1000));
|
sleep_solar_current = fxp_div(FXP_FROM_INT(FLASH_CONFIG_SLEEP_SOLAR_CURRENT), FXP_FROM_INT(1000));
|
||||||
sleep_solar_excess_voltage = fxp_div(FXP_FROM_INT(FLASH_CONFIG_SLEEP_SOLAR_EXCESS_VOLTAGE), FXP_FROM_INT(1000));
|
sleep_solar_excess_voltage = fxp_div(FXP_FROM_INT(FLASH_CONFIG_SLEEP_SOLAR_EXCESS_VOLTAGE), FXP_FROM_INT(1000));
|
||||||
|
|
||||||
|
overload_retry_time = FLASH_CONFIG_OVERLOAD_RETRY_TIME;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,7 @@ enum DischargeState
|
||||||
DISCHARGE_OK,
|
DISCHARGE_OK,
|
||||||
DISCHARGE_VOLTAGE_LOW,
|
DISCHARGE_VOLTAGE_LOW,
|
||||||
DISCHARGE_OVERCURRENT,
|
DISCHARGE_OVERCURRENT,
|
||||||
|
DISCHARGE_OVERCURRENT_DELAY,
|
||||||
|
|
||||||
DISCHARGE_NUM_STATES
|
DISCHARGE_NUM_STATES
|
||||||
};
|
};
|
||||||
|
|
|
@ -86,6 +86,10 @@ extern uint8_t __conf_start;
|
||||||
* time after load power-on. */
|
* time after load power-on. */
|
||||||
#define FLASH_CONFIG_LOAD_CURRENT_INRUSH_TIME (*(uint32_t*)(FLASH_CONFIG_BASE_PTR + 0x0144))
|
#define FLASH_CONFIG_LOAD_CURRENT_INRUSH_TIME (*(uint32_t*)(FLASH_CONFIG_BASE_PTR + 0x0144))
|
||||||
|
|
||||||
|
/* Inrush tolerance time (in ms). Overload protection is not enforced for this
|
||||||
|
* time after load power-on. */
|
||||||
|
#define FLASH_CONFIG_LOAD_CURRENT_INRUSH_TIME (*(uint32_t*)(FLASH_CONFIG_BASE_PTR + 0x0144))
|
||||||
|
|
||||||
/* Minimum voltage that the charge pump must produce above U_bat before any
|
/* Minimum voltage that the charge pump must produce above U_bat before any
|
||||||
* power FET is switched on (in mV). */
|
* power FET is switched on (in mV). */
|
||||||
#define FLASH_CONFIG_MIN_CHARGE_PUMP_EXCESS_VOLTAGE (*(int32_t*)(FLASH_CONFIG_BASE_PTR + 0x0148))
|
#define FLASH_CONFIG_MIN_CHARGE_PUMP_EXCESS_VOLTAGE (*(int32_t*)(FLASH_CONFIG_BASE_PTR + 0x0148))
|
||||||
|
@ -93,6 +97,14 @@ extern uint8_t __conf_start;
|
||||||
/* The minimum time the load must be off before it can be switched on again (in ms). */
|
/* The minimum time the load must be off before it can be switched on again (in ms). */
|
||||||
#define FLASH_CONFIG_LOAD_ON_DELAY (*(uint32_t*)(FLASH_CONFIG_BASE_PTR + 0x014c))
|
#define FLASH_CONFIG_LOAD_ON_DELAY (*(uint32_t*)(FLASH_CONFIG_BASE_PTR + 0x014c))
|
||||||
|
|
||||||
|
/* Overload delay time (in ms). If load current is too high for this duration,
|
||||||
|
* load is switched permanently off. */
|
||||||
|
#define FLASH_CONFIG_OVERLOAD_DELAY_TIME (*(uint32_t*)(FLASH_CONFIG_BASE_PTR + 0x0170))
|
||||||
|
|
||||||
|
/* Overload retry time (in ms). Load is switched on again after this time if
|
||||||
|
* overload condition has triggered. */
|
||||||
|
#define FLASH_CONFIG_OVERLOAD_RETRY_TIME (*(uint32_t*)(FLASH_CONFIG_BASE_PTR + 0x0174))
|
||||||
|
|
||||||
|
|
||||||
/* Measurement Averaging:
|
/* Measurement Averaging:
|
||||||
* Alpha is specified in units of 1/1000. 1000 means that only the latest
|
* Alpha is specified in units of 1/1000. 1000 means that only the latest
|
||||||
|
@ -123,6 +135,8 @@ extern uint8_t __conf_start;
|
||||||
/* Deep sleep duration (in seconds). */
|
/* Deep sleep duration (in seconds). */
|
||||||
#define FLASH_CONFIG_DEEPSLEEP_DURATION (*(uint32_t*)(FLASH_CONFIG_BASE_PTR + 0x016c))
|
#define FLASH_CONFIG_DEEPSLEEP_DURATION (*(uint32_t*)(FLASH_CONFIG_BASE_PTR + 0x016c))
|
||||||
|
|
||||||
|
/* FIXME: next free memory location: 0x178. Update when adding a value! */
|
||||||
|
|
||||||
|
|
||||||
/* Functions */
|
/* Functions */
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
#include "measurement.h"
|
#include "measurement.h"
|
||||||
#include "deepsleep.h"
|
#include "deepsleep.h"
|
||||||
#include "bmp280.h"
|
#include "bmp280.h"
|
||||||
|
#include "addon_io.h"
|
||||||
|
|
||||||
#include "pinout.h"
|
#include "pinout.h"
|
||||||
#include "flash_config.h"
|
#include "flash_config.h"
|
||||||
|
@ -304,6 +305,7 @@ int main(void)
|
||||||
init_clock();
|
init_clock();
|
||||||
init_rtc();
|
init_rtc();
|
||||||
|
|
||||||
|
addon_io_init();
|
||||||
rs485_init();
|
rs485_init();
|
||||||
charge_pump_init();
|
charge_pump_init();
|
||||||
power_switch_init();
|
power_switch_init();
|
||||||
|
@ -379,6 +381,9 @@ int main(void)
|
||||||
if((timebase_ms - charge_control_idle_since) > FLASH_CONFIG_DEEPSLEEP_DELAY) {
|
if((timebase_ms - charge_control_idle_since) > FLASH_CONFIG_DEEPSLEEP_DELAY) {
|
||||||
low_power_mode(FLASH_CONFIG_DEEPSLEEP_DURATION);
|
low_power_mode(FLASH_CONFIG_DEEPSLEEP_DURATION);
|
||||||
charge_control_was_idle = false;
|
charge_control_was_idle = false;
|
||||||
|
|
||||||
|
// correct the time base after deep sleep
|
||||||
|
timebase_ms += FLASH_CONFIG_DEEPSLEEP_DURATION * 1000;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
10
src/pinout.h
10
src/pinout.h
|
@ -43,6 +43,8 @@
|
||||||
#define RS485_TX_PIN GPIO6
|
#define RS485_TX_PIN GPIO6
|
||||||
#define RS485_RX_PIN GPIO7
|
#define RS485_RX_PIN GPIO7
|
||||||
|
|
||||||
|
/*** Expansion connector signals ***/
|
||||||
|
|
||||||
/* BMP280 I²C */
|
/* BMP280 I²C */
|
||||||
|
|
||||||
#define BMP280_I2C_PORT GPIOA
|
#define BMP280_I2C_PORT GPIOA
|
||||||
|
@ -50,4 +52,12 @@
|
||||||
#define BMP280_I2C_SCL GPIO9
|
#define BMP280_I2C_SCL GPIO9
|
||||||
#define BMP280_I2C_SDA GPIO10
|
#define BMP280_I2C_SDA GPIO10
|
||||||
|
|
||||||
|
/* Isolated inputs and outputs on I/O addon board */
|
||||||
|
|
||||||
|
#define ADDON_ISO_IO_PORT GPIOA
|
||||||
|
|
||||||
|
#define ADDON_ISO_IO_OUT1 GPIO5
|
||||||
|
#define ADDON_ISO_IO_OUT2 GPIO6
|
||||||
|
#define ADDON_ISO_IO_IN GPIO7
|
||||||
|
|
||||||
#endif // PINOUT_H
|
#endif // PINOUT_H
|
||||||
|
|
|
@ -79,6 +79,15 @@ config:
|
||||||
# time after load power-on.
|
# time after load power-on.
|
||||||
LOAD_CURRENT_INRUSH_TIME: 10
|
LOAD_CURRENT_INRUSH_TIME: 10
|
||||||
|
|
||||||
|
# Overload delay time (in ms). If load current is too high for this duration,
|
||||||
|
# load is switched permanently off.
|
||||||
|
FLASH_CONFIG_OVERLOAD_DELAY_TIME: 10
|
||||||
|
|
||||||
|
# Overload retry time (in ms). Load is switched on again after this time if
|
||||||
|
# overload condition has triggered. If overload immediately triggers again,
|
||||||
|
# this time is doubled.
|
||||||
|
FLASH_CONFIG_OVERLOAD_RETRY_TIME: 10000
|
||||||
|
|
||||||
# Minimum voltage that the charge pump must produce above U_bat before any
|
# Minimum voltage that the charge pump must produce above U_bat before any
|
||||||
# power FET is switched on (in mV).
|
# power FET is switched on (in mV).
|
||||||
MIN_CHARGE_PUMP_EXCESS_VOLTAGE: 10000
|
MIN_CHARGE_PUMP_EXCESS_VOLTAGE: 10000
|
||||||
|
|
|
@ -45,6 +45,8 @@ CONFIG_KEY_TO_OFFSET = {
|
||||||
"AVG_ALPHA_TEMP": 0x0164,
|
"AVG_ALPHA_TEMP": 0x0164,
|
||||||
"DEEPSLEEP_DELAY": 0x0168,
|
"DEEPSLEEP_DELAY": 0x0168,
|
||||||
"DEEPSLEEP_DURATION": 0x016c,
|
"DEEPSLEEP_DURATION": 0x016c,
|
||||||
|
"FLASH_CONFIG_OVERLOAD_DELAY_TIME": 0x0170,
|
||||||
|
"FLASH_CONFIG_OVERLOAD_RETRY_TIME": 0x0174
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue