From 4ebb231346a04a8c621680442fad86aa57ad609d Mon Sep 17 00:00:00 2001 From: Thomas Kolb Date: Sun, 25 Sep 2022 15:57:05 +0200 Subject: [PATCH] Preparations for dedicated configuration flash page --- .gitignore | 3 + Makefile | 2 +- ldscripts/lnsc-2420-debug.ld | 5 ++ ldscripts/lnsc-2420-release.ld | 10 ++- src/flash_config.h | 117 +++++++++++++++++++++++++++++++++ utils/config_b26.yaml | 108 ++++++++++++++++++++++++++++++ utils/config_dev.yaml | 108 ++++++++++++++++++++++++++++++ utils/config_to_hex.py | 69 +++++++++++++++++++ 8 files changed, 420 insertions(+), 2 deletions(-) create mode 100644 src/flash_config.h create mode 100644 utils/config_b26.yaml create mode 100644 utils/config_dev.yaml create mode 100755 utils/config_to_hex.py diff --git a/.gitignore b/.gitignore index fd691c5..f8f3e6b 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,6 @@ # Vim swap files .*.sw? + +# generated config HEX files +utils/*.hex diff --git a/Makefile b/Makefile index 914eb14..9865c8d 100644 --- a/Makefile +++ b/Makefile @@ -32,7 +32,7 @@ LDFLAGS+=--static \ -nostartfiles -Wl,--gc-sections \ -mthumb -mcpu=cortex-m0 -mthumb -mfloat-abi=soft -# the LD script +# the LD script (RAM-only does not work because the code is too large) #LDFLAGS+=-Tldscripts/lnsc-2420-$(BUILD).ld LDFLAGS+=-Tldscripts/lnsc-2420-release.ld diff --git a/ldscripts/lnsc-2420-debug.ld b/ldscripts/lnsc-2420-debug.ld index 097d4ca..541b106 100644 --- a/ldscripts/lnsc-2420-debug.ld +++ b/ldscripts/lnsc-2420-debug.ld @@ -7,6 +7,7 @@ MEMORY { /*rom (rx) : ORIGIN = 0x08000000, LENGTH = 64K*/ + conf (r) : ORIGIN = 0x08007c00, LENGTH = 1K ram (rwx) : ORIGIN = 0x20000000, LENGTH = 4K } @@ -96,6 +97,10 @@ SECTIONS . = ALIGN(4); end = .; + + .conf : { + __conf_start = .; + } >conf } PROVIDE(_stack = ORIGIN(ram) + LENGTH(ram)); diff --git a/ldscripts/lnsc-2420-release.ld b/ldscripts/lnsc-2420-release.ld index 0b7c6ba..09fd4ca 100644 --- a/ldscripts/lnsc-2420-release.ld +++ b/ldscripts/lnsc-2420-release.ld @@ -3,10 +3,18 @@ /* Define memory regions. */ MEMORY { - rom (rx) : ORIGIN = 0x08000000, LENGTH = 32K + rom (rx) : ORIGIN = 0x08000000, LENGTH = 31K + conf (r) : ORIGIN = 0x08007c00, LENGTH = 1K ram (rwx) : ORIGIN = 0x20000000, LENGTH = 4K } /* Include the common ld script. */ INCLUDE cortex-m-generic.ld +SECTIONS +{ + .conf : { + __conf_start = .; + . = ALIGN(4); + } >conf +} diff --git a/src/flash_config.h b/src/flash_config.h new file mode 100644 index 0000000..412d2c2 --- /dev/null +++ b/src/flash_config.h @@ -0,0 +1,117 @@ +#ifndef FLASH_CONFIG_H +#define FLASH_CONFIG_H + +#include + +extern uint8_t __conf_start; + +#define FLASH_CONFIG_BASE_PTR ((uint8_t*)(&__conf_start)) + +/***** Calibration factors *****/ + +/* Calibration factor defined here are divided by 1000 to determine the actual + * scaling factor. Therefore, if the voltage determined by the firmware is 2% + * lower than the actual voltage, you have to scale by 1.02 and therefore + * specify 1020 in this list. */ + +#define FLASH_CONFIG_CAL_FACTOR_U_BAT (*(uint16_t*)(FLASH_CONFIG_BASE_PTR + 0x0000)) +#define FLASH_CONFIG_CAL_FACTOR_U_SOLAR (*(uint16_t*)(FLASH_CONFIG_BASE_PTR + 0x0002)) +#define FLASH_CONFIG_CAL_FACTOR_U_SW (*(uint16_t*)(FLASH_CONFIG_BASE_PTR + 0x0004)) +#define FLASH_CONFIG_CAL_FACTOR_I_SOLAR (*(uint16_t*)(FLASH_CONFIG_BASE_PTR + 0x0006)) +#define FLASH_CONFIG_CAL_FACTOR_I_LOAD (*(uint16_t*)(FLASH_CONFIG_BASE_PTR + 0x0008)) + +/***** General configuration *****/ + +/* Battery regulation corridor width (in mV). */ +#define FLASH_CONFIG_U_BAT_REGULATION_CORRIDOR (*(uint32_t*)(FLASH_CONFIG_BASE_PTR + 0x0100)) + +/* Initial charge battery voltage threshold (in mV). */ +#define FLASH_CONFIG_U_BAT_INITIAL_FULL (*(uint32_t*)(FLASH_CONFIG_BASE_PTR + 0x0104)) + +/* Cancel initial charge voltage hold below this battery voltage (in mV). */ +#define FLASH_CONFIG_U_BAT_INITIAL_HOLD_CANCEL (*(uint32_t*)(FLASH_CONFIG_BASE_PTR + 0x0108)) + +/* Transition to floating voltage levels after this time (in ms). */ +#define FLASH_CONFIG_INITIAL_CHARGE_HOLD_TIME (*(uint32_t*)(FLASH_CONFIG_BASE_PTR + 0x010C)) + +/* Duration of the transistion from initial charging to float (in ms). */ +#define FLASH_CONFIG_INITIAL_TO_FLOAT_TRANSITION_TIME (*(uint32_t*)(FLASH_CONFIG_BASE_PTR + 0x0110)) + +/* Float charge battery voltage threshold (in mV). */ +#define FLASH_CONFIG_U_BAT_FLOAT_FULL (*(uint32_t*)(FLASH_CONFIG_BASE_PTR + 0x0114)) + +/* Minimum voltage difference to U_bat that the solar panels must produce + * before charging is resumed after it was switched off (in mV). */ +#define FLASH_CONFIG_SLEEP_SOLAR_EXCESS_VOLTAGE (*(uint32_t*)(FLASH_CONFIG_BASE_PTR + 0x0118)) + +/* Minimum charge current required before charging is stopped to save power at + * the charge pump (in mA). */ +#define FLASH_CONFIG_SLEEP_SOLAR_CURRENT (*(uint32_t*)(FLASH_CONFIG_BASE_PTR + 0x011C)) + +/* Delay between state change and sleep state check (in ms). */ +#define FLASH_CONFIG_SLEEP_STATE_DELAY (*(uint32_t*)(FLASH_CONFIG_BASE_PTR + 0x0120)) + +/* Delay between charging switch state change and sleep state check(in ms). */ +#define FLASH_CONFIG_SLEEP_SWITCH_DELAY (*(uint32_t*)(FLASH_CONFIG_BASE_PTR + 0x0124)) + +/* Maximum allowed microcontroller temperature (in units of 0.1 °C). If this + * temperature is exceeded, charging is stopped. The load is kept on. Do not + * set this too high as the heat has to propagate from the power MOSFETs. */ +#define FLASH_CONFIG_INTERNAL_TEMPERATURE_LIMIT (*(uint32_t*)(FLASH_CONFIG_BASE_PTR + 0x0128)) + +/* Resume operation below this temperature (in units of 0.1 °C). */ +#define FLASH_CONFIG_INTERNAL_TEMPERATURE_RECOVERY (*(uint32_t*)(FLASH_CONFIG_BASE_PTR + 0x012C)) + + +/* Thresholds for load control */ + +/* Voltage above which the load is turned on (in mV). */ +#define FLASH_CONFIG_U_BAT_LOAD_ON (*(uint32_t*)(FLASH_CONFIG_BASE_PTR + 0x0130)) +/* Voltage below which the load is turned off (in mV). */ +#define FLASH_CONFIG_U_BAT_LOAD_OFF (*(uint32_t*)(FLASH_CONFIG_BASE_PTR + 0x0134)) + +/* Current at which the overload protection triggers (in mA). */ +#define FLASH_CONFIG_LOAD_CURRENT_LIMIT_MA (*(uint32_t*)(FLASH_CONFIG_BASE_PTR + 0x0138)) + +/* 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 + 0x013C)) + +/* Minimum voltage that the charge pump must produce above U_bat before any + * power FET is switched on (in mV). */ +#define FLASH_CONFIG_MIN_CHARGE_PUMP_EXCESS_VOLTAGE (*(uint32_t*)(FLASH_CONFIG_BASE_PTR + 0x0140)) + +/* 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 + 0x0144)) + + +/* Measurement Averaging: + * Alpha is specified in units of 1/1000. 1000 means that only the latest + * value is relevant, 0 means that the measurement has no influence. The latter + * is useless. + * + * The formula to calculate the next averaged value avg from a measurement meas is: + * avg[k] = meas * (alpha/1000) + avg[k-1] * (1 - alpha/1000) + * + * For overload protection (battery voltage, load current), the latest values + * are always used. + * */ + +/* Averaging factor for load current. */ +#define FLASH_CONFIG_AVG_ALPHA_I_SOLAR (*(uint32_t*)(FLASH_CONFIG_BASE_PTR + 0x0148)) +#define FLASH_CONFIG_AVG_ALPHA_I_LOAD (*(uint32_t*)(FLASH_CONFIG_BASE_PTR + 0x014C)) +#define FLASH_CONFIG_AVG_ALPHA_U_BAT (*(uint32_t*)(FLASH_CONFIG_BASE_PTR + 0x0150)) +#define FLASH_CONFIG_AVG_ALPHA_U_SW (*(uint32_t*)(FLASH_CONFIG_BASE_PTR + 0x0154)) +#define FLASH_CONFIG_AVG_ALPHA_U_SOLAR (*(uint32_t*)(FLASH_CONFIG_BASE_PTR + 0x0158)) +#define FLASH_CONFIG_AVG_ALPHA_TEMP (*(uint32_t*)(FLASH_CONFIG_BASE_PTR + 0x015C)) + + +/* Generic configuration */ + +/* Time (in ms) to stay active in idle state before entering deep sleep. */ +#define FLASH_CONFIG_DEEPSLEEP_DELAY (*(uint32_t*)(FLASH_CONFIG_BASE_PTR + 0x0160)) + +/* Deep sleep duration (in seconds). */ +#define FLASH_CONFIG_DEEPSLEEP_DURATION (*(uint32_t*)(FLASH_CONFIG_BASE_PTR + 0x0164)) + +#endif // FLASH_CONFIG_H diff --git a/utils/config_b26.yaml b/utils/config_b26.yaml new file mode 100644 index 0000000..8175032 --- /dev/null +++ b/utils/config_b26.yaml @@ -0,0 +1,108 @@ +# Values for the device at the B26 tower + +calibration: + # Calibration factor defined here are divided by 1000 to determine the actual + # scaling factor. Therefore, if the voltage determined by the firmware is 2% + # lower than the actual voltage, you have to scale by 1.02 and therefore + # specify 1020 in this list. + CAL_FACTOR_U_BAT: 994 + CAL_FACTOR_U_SOLAR: 997 + CAL_FACTOR_U_SW: 996 + CAL_FACTOR_I_SOLAR: 1015 + CAL_FACTOR_I_LOAD: 1000 + +config: + # Thresholds for charging control + + # Battery regulation corridor width (in mV). + U_BAT_REGULATION_CORRIDOR: 100 + + # Initial charge battery voltage threshold (in mV). + # stop charging if battery voltage reaches this threshold + U_BAT_INITIAL_FULL: 28600 + + # Cancel initial charge voltage hold below this battery voltage (in mV). + U_BAT_INITIAL_HOLD_CANCEL: 27000 + + # Transition to floating voltage levels after this time (in ms). + INITIAL_CHARGE_HOLD_TIME: 1800000 + + # Duration of the transistion from initial charging to float (in ms). + INITIAL_TO_FLOAT_TRANSITION_TIME: 600000 + + # Float charge battery voltage threshold (in mV). + # stop charging if battery voltage reaches this threshold + U_BAT_FLOAT_FULL: 27600 + + # Minimum voltage difference to U_bat that the solar panels must produce + # before charging is resumed after it was switched off (in mV). + SLEEP_SOLAR_EXCESS_VOLTAGE: 1000 + + # Minimum charge current required before charging is stopped to save power at + # the charge pump (in mA). + SLEEP_SOLAR_CURRENT: 1 + + # Delay between state change and sleep state check (in ms). + SLEEP_STATE_DELAY: 60000 + + # Delay between charging switch state change and sleep state check(in ms). + SLEEP_SWITCH_DELAY: 1000 + + # Maximum allowed microcontroller temperature (in units of 0.1 °C). If this + # temperature is exceeded, charging is stopped. The load is kept on. Do not + # set this too high as the heat has to propagate from the power MOSFETs. + INTERNAL_TEMPERATURE_LIMIT: 500 + + # Resume operation below this temperature (in units of 0.1 °C). + INTERNAL_TEMPERATURE_RECOVERY: 450 + + + # Thresholds for load control + + # Voltage above which the load is turned on (in mV). + U_BAT_LOAD_ON: 27000 + # Voltage below which the load is turned off (in mV). + U_BAT_LOAD_OFF: 24000 + + # Current at which the overload protection triggers (in mA). + LOAD_CURRENT_LIMIT_MA: 10000 + + # Inrush tolerance time (in ms). Overload protection is not enforced for this + # time after load power-on. + LOAD_CURRENT_INRUSH_TIME: 10 + + # Minimum voltage that the charge pump must produce above U_bat before any + # power FET is switched on (in mV). + MIN_CHARGE_PUMP_EXCESS_VOLTAGE: 10000 + + # The minimum time the load must be off before it can be switched on again (in ms). + LOAD_ON_DELAY: 10000 + + + # Measurement Averaging: + # Alpha is specified in units of 1/1000. 1000 means that only the latest + # value is relevant, 0 means that the measurement has no influence. The latter + # is useless. + # + # The formula to calculate the next averaged value avg from a measurement meas is: + # avg[k] = meas * (alpha/1000) + avg[k-1] * (1 alpha/1000) + # + # For overload protection (battery voltage, load current), the latest values + # are always used. + + # Averaging factor for load current. + AVG_ALPHA_I_SOLAR: 10 + AVG_ALPHA_I_LOAD: 10 + AVG_ALPHA_U_BAT: 100 + AVG_ALPHA_U_SW: 100 + AVG_ALPHA_U_SOLAR: 100 + AVG_ALPHA_TEMP: 10 + + + # Generic configuration + + # Time (in ms) to stay active in idle state before entering deep sleep. + DEEPSLEEP_DELAY: 1000 + + # Deep sleep duration (in seconds). + DEEPSLEEP_DURATION: 10 diff --git a/utils/config_dev.yaml b/utils/config_dev.yaml new file mode 100644 index 0000000..8a65a4d --- /dev/null +++ b/utils/config_dev.yaml @@ -0,0 +1,108 @@ +# Values for the development device + +calibration: + # Calibration factor defined here are divided by 1000 to determine the actual + # scaling factor. Therefore, if the voltage determined by the firmware is 2% + # lower than the actual voltage, you have to scale by 1.02 and therefore + # specify 1020 in this list. + CAL_FACTOR_U_BAT: 1012 + CAL_FACTOR_U_SOLAR: 1015 + CAL_FACTOR_U_SW: 1006 + CAL_FACTOR_I_SOLAR: 3980 + CAL_FACTOR_I_LOAD: 1000 + +config: + # Thresholds for charging control + + # Battery regulation corridor width (in mV). + U_BAT_REGULATION_CORRIDOR: 100 + + # Initial charge battery voltage threshold (in mV). + # stop charging if battery voltage reaches this threshold + U_BAT_INITIAL_FULL: 28600 + + # Cancel initial charge voltage hold below this battery voltage (in mV). + U_BAT_INITIAL_HOLD_CANCEL: 27000 + + # Transition to floating voltage levels after this time (in ms). + INITIAL_CHARGE_HOLD_TIME: 1800000 + + # Duration of the transistion from initial charging to float (in ms). + INITIAL_TO_FLOAT_TRANSITION_TIME: 600000 + + # Float charge battery voltage threshold (in mV). + # stop charging if battery voltage reaches this threshold + U_BAT_FLOAT_FULL: 27600 + + # Minimum voltage difference to U_bat that the solar panels must produce + # before charging is resumed after it was switched off (in mV). + SLEEP_SOLAR_EXCESS_VOLTAGE: 1000 + + # Minimum charge current required before charging is stopped to save power at + # the charge pump (in mA). + SLEEP_SOLAR_CURRENT: 1 + + # Delay between state change and sleep state check (in ms). + SLEEP_STATE_DELAY: 60000 + + # Delay between charging switch state change and sleep state check(in ms). + SLEEP_SWITCH_DELAY: 1000 + + # Maximum allowed microcontroller temperature (in units of 0.1 °C). If this + # temperature is exceeded, charging is stopped. The load is kept on. Do not + # set this too high as the heat has to propagate from the power MOSFETs. + INTERNAL_TEMPERATURE_LIMIT: 500 + + # Resume operation below this temperature (in units of 0.1 °C). + INTERNAL_TEMPERATURE_RECOVERY: 450 + + + # Thresholds for load control + + # Voltage above which the load is turned on (in mV). + U_BAT_LOAD_ON: 27000 + # Voltage below which the load is turned off (in mV). + U_BAT_LOAD_OFF: 24000 + + # Current at which the overload protection triggers (in mA). + LOAD_CURRENT_LIMIT_MA: 10000 + + # Inrush tolerance time (in ms). Overload protection is not enforced for this + # time after load power-on. + LOAD_CURRENT_INRUSH_TIME: 10 + + # Minimum voltage that the charge pump must produce above U_bat before any + # power FET is switched on (in mV). + MIN_CHARGE_PUMP_EXCESS_VOLTAGE: 10000 + + # The minimum time the load must be off before it can be switched on again (in ms). + LOAD_ON_DELAY: 10000 + + + # Measurement Averaging: + # Alpha is specified in units of 1/1000. 1000 means that only the latest + # value is relevant, 0 means that the measurement has no influence. The latter + # is useless. + # + # The formula to calculate the next averaged value avg from a measurement meas is: + # avg[k] = meas * (alpha/1000) + avg[k-1] * (1 alpha/1000) + # + # For overload protection (battery voltage, load current), the latest values + # are always used. + + # Averaging factor for load current. + AVG_ALPHA_I_SOLAR: 10 + AVG_ALPHA_I_LOAD: 10 + AVG_ALPHA_U_BAT: 100 + AVG_ALPHA_U_SW: 100 + AVG_ALPHA_U_SOLAR: 100 + AVG_ALPHA_TEMP: 10 + + + # Generic configuration + + # Time (in ms) to stay active in idle state before entering deep sleep. + DEEPSLEEP_DELAY: 1000 + + # Deep sleep duration (in seconds). + DEEPSLEEP_DURATION: 10 diff --git a/utils/config_to_hex.py b/utils/config_to_hex.py new file mode 100755 index 0000000..f96949c --- /dev/null +++ b/utils/config_to_hex.py @@ -0,0 +1,69 @@ +#!/usr/bin/env python3 + +import sys +import struct + +import yaml +from intelhex import IntelHex + +BASE_ADDR = 0x08007C00 + +CALIBRATION_KEY_TO_OFFSET = { + "CAL_FACTOR_U_BAT": 0x0000, + "CAL_FACTOR_U_SOLAR": 0x0002, + "CAL_FACTOR_U_SW": 0x0004, + "CAL_FACTOR_I_SOLAR": 0x0006, + "CAL_FACTOR_I_LOAD": 0x0008, + } + +CONFIG_KEY_TO_OFFSET = { + "U_BAT_REGULATION_CORRIDOR": 0x0100, + "U_BAT_INITIAL_FULL": 0x0104, + "U_BAT_INITIAL_HOLD_CANCEL": 0x0108, + "INITIAL_CHARGE_HOLD_TIME": 0x010C, + "INITIAL_TO_FLOAT_TRANSITION_TIME": 0x0110, + "U_BAT_FLOAT_FULL": 0x0114, + "SLEEP_SOLAR_EXCESS_VOLTAGE": 0x0118, + "SLEEP_SOLAR_CURRENT": 0x011C, + "SLEEP_STATE_DELAY": 0x0120, + "SLEEP_SWITCH_DELAY": 0x0124, + "INTERNAL_TEMPERATURE_LIMIT": 0x0128, + "INTERNAL_TEMPERATURE_RECOVERY": 0x012C, + "U_BAT_LOAD_ON": 0x0130, + "U_BAT_LOAD_OFF": 0x0134, + "LOAD_CURRENT_LIMIT_MA": 0x0138, + "LOAD_CURRENT_INRUSH_TIME": 0x013C, + "MIN_CHARGE_PUMP_EXCESS_VOLTAGE": 0x0140, + "LOAD_ON_DELAY": 0x0144, + "AVG_ALPHA_I_SOLAR": 0x0148, + "AVG_ALPHA_I_LOAD": 0x014C, + "AVG_ALPHA_U_BAT": 0x0150, + "AVG_ALPHA_U_SW": 0x0154, + "AVG_ALPHA_U_SOLAR": 0x0158, + "AVG_ALPHA_TEMP": 0x015C, + "DEEPSLEEP_DELAY": 0x0160, + "DEEPSLEEP_DURATION": 0x0164, + } + + +if __name__ == "__main__": + output = IntelHex() + + if len(sys.argv) < 3: + print(f"usage: {sys.argv[0]} ") + sys.exit(1) + + with open(sys.argv[1], 'r') as configfile: + config = yaml.safe_load(configfile) + + for key, offset in CALIBRATION_KEY_TO_OFFSET.items(): + value = config['calibration'][key] + enc_bytes = struct.pack('