From d41c63f9484e0ce1d07166aa8bd77daf7e4bdee3 Mon Sep 17 00:00:00 2001 From: Thomas Kolb Date: Sat, 21 Sep 2019 16:00:33 +0200 Subject: [PATCH] Added new float state; Some fixes Typical charge cycle: MPPT until 14.4V, then switch to CV and hold 14.4V. After 2 hours switch to float charging at 13.8V. --- src/main.c | 154 +++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 120 insertions(+), 34 deletions(-) diff --git a/src/main.c b/src/main.c index aab9070..4b13f8c 100644 --- a/src/main.c +++ b/src/main.c @@ -17,7 +17,7 @@ #include "lcd.h" #include "debug.h" -#define CONV_PWM_PERIOD 960 +#define CONV_PWM_PERIOD 360 #define CONV_PWM_MAX (98*CONV_PWM_PERIOD/100) #define TIM_CH_CONV TIM_OC1 @@ -31,6 +31,7 @@ enum OperState { Bootstrap, ConvConstVoltage, + ConvFloat, ConvConstCurrent, ConvMPP, Idle, @@ -358,6 +359,21 @@ struct PowerState { fxp_t power_avg; }; +static void load_on(void) +{ + gpio_set(GPIOA, GPIO15); +} + +static void load_off(void) +{ + gpio_clear(GPIOA, GPIO15); +} + +static bool load_status(void) +{ + return gpio_get(GPIOA, GPIO15) != 0; +} + static void report_status(struct PowerState *power_state, int32_t pwm, enum OperState operState) { @@ -387,6 +403,10 @@ static void report_status(struct PowerState *power_state, fxp_format(power_state->temp_avg, number, 1); debug_send_string(number); + debug_send_string(":"); + + fxp_format_int(load_status(), number); + debug_send_string(number); debug_send_string("\r\n"); } @@ -415,7 +435,7 @@ struct MPPState { #define MPP_TEST_DURATION (MPP_TEST_IGNORE_DURATION + MPP_TEST_ACCU_DURATION) #define MPP_TEST_STEPS 6 -const int32_t mpp_pwm_offsets[MPP_TEST_STEPS] = {-3, 4, -16, 15}; +const int32_t mpp_pwm_offsets[MPP_TEST_STEPS] = {-1, 2, -6, 5}; static void mpp_run( uint32_t time_in_state, struct MPPState *mpp_state, @@ -522,16 +542,6 @@ static void mpp_run( } } -static void load_on(void) -{ - gpio_set(GPIOA, GPIO15); -} - -static void load_off(void) -{ - gpio_clear(GPIOA, GPIO15); -} - int main(void) { //uint32_t cpuload = 0; @@ -554,6 +564,8 @@ int main(void) fxp_t pErr = 0, iErr = 0; fxp_t controlAction = 0; + fxp_t setPoint = 0; + uint32_t sleep_time = 10; uint64_t force_display_update_time = 1000; @@ -569,11 +581,13 @@ int main(void) fxp_t AVG_FACT = fxp_from_float(0.01f); fxp_t AVG_FACT_INV = fxp_sub(fxp_from_int(1), AVG_FACT); - fxp_t MAX_VOLTAGE = fxp_from_float(14.400f); - fxp_t CONST_VOLTAGE = fxp_from_float(13.800f); + fxp_t MPP_MAX_VOLTAGE = fxp_from_float(14.400f); + fxp_t CONST_VOLTAGE = MPP_MAX_VOLTAGE; + fxp_t CONST_FLOAT_VOLTAGE = fxp_from_float(13.800f); fxp_t MAX_CURRENT = fxp_from_float( 5.000f); - fxp_t MPP_VOLTAGE_THR = fxp_sub(CONST_VOLTAGE, fxp_from_float(0.500f)); + fxp_t VOLTAGE_THR_CV_TO_MPP = fxp_sub(CONST_VOLTAGE, fxp_from_float(0.300f)); + fxp_t VOLTAGE_THR_FLOAT_TO_MPP = fxp_sub(CONST_FLOAT_VOLTAGE, fxp_from_float(0.300f)); fxp_t MPP_CURRENT_THR = fxp_sub(MAX_CURRENT, fxp_from_float(0.500f)); // input voltage must exceed output voltage by this value to leave idle mode @@ -584,21 +598,21 @@ int main(void) // // If the battery voltage is below LOAD_LOW_VOLTAGE_THRESHOLD, the battery // voltage is monitored more closely during idle mode. - fxp_t LOAD_ON_THRESHOLD = fxp_from_float(13.000f); - fxp_t LOAD_OFF_THRESHOLD = fxp_from_float(11.200f); - fxp_t LOAD_LOW_VOLTAGE_THRESHOLD = fxp_from_float(11.600f); + fxp_t LOAD_ON_THRESHOLD = fxp_from_float(13.500f); + fxp_t LOAD_OFF_THRESHOLD = fxp_from_float(12.500f); + fxp_t LOAD_LOW_VOLTAGE_THRESHOLD = fxp_from_float(12.600f); // Calculated values //fxp_t VIN_SCALE = fxp_from_float(3.3f * (100 + 10.0f) / 10.0f / 4095.0f); //fxp_t VOUT_SCALE = fxp_from_float(3.3f * (100 + 12.0f) / 12.0f / 4095.0f); // Calibrated from measurements - fxp_t VIN_SCALE = fxp_from_float(36.41f / 4096.0f); - fxp_t VOUT_SCALE = fxp_from_float(30.87f / 4096.0f); + fxp_t VIN_SCALE = fxp_from_float(36.23f / 4096.0f); + fxp_t VOUT_SCALE = fxp_from_float(30.75f / 4096.0f); // current = adc • 0.00166 + -0.0725 = adc • m + t - fxp_t ADC2CURRENT_M = fxp_from_float( 0.00166f); - fxp_t ADC2CURRENT_T = fxp_from_float(-0.07250f); + fxp_t ADC2CURRENT_M = fxp_from_float( 0.00225f); + fxp_t ADC2CURRENT_T = fxp_from_float(-0.2255f); /* if power changes by more than this factor, MPP is tested again */ MPP_MAX_POWER_CHANGE_FACTOR = fxp_from_float(0.2f); @@ -739,14 +753,18 @@ int main(void) timer_set_oc_value(TIM1, TIM_CH_BOOTSTRAP, 24); if(time_in_state >= 10) { // bootstrap duration in ms - //iErr = 0; + // bootstrap off + timer_set_oc_value(TIM1, TIM_CH_BOOTSTRAP, 0); + + // go to next state operState = nextState; } break; case ConvConstVoltage: - // bootstrap off - timer_set_oc_value(TIM1, TIM_CH_BOOTSTRAP, 0); + if(time_in_state == 0) { + iErr = 0; + } // calculate error values pErr = fxp_sub(CONST_VOLTAGE, power_state.vout_avg); @@ -771,6 +789,76 @@ int main(void) timer_set_oc_value(TIM1, TIM_CH_CONV, pwm); +#ifdef DEBUG + if((time_in_state % 100) == 0) { + debug_send_string("pErr: "); + fxp_format(pErr, msg, 3); + debug_send_string(msg); + debug_send_string(" iErr: "); + fxp_format(iErr, msg, 3); + debug_send_string(msg); + debug_send_string(" controlAction: "); + fxp_format(controlAction, msg, 3); + debug_send_string(msg); + sentSomething = 1; + } +#endif + + if(time_in_state > 3600*1000) { + operState = ConvFloat; + } + + if(time_in_state > 5000 && fxp_to_int(controlAction) > CONV_PWM_MAX && power_state.current_avg < CURRENT_THRESHOLD) { + operState = Bootstrap; + nextState = ConvConstVoltage; + } + + if(time_in_state > 1000 && power_state.vout_avg < VOLTAGE_THR_CV_TO_MPP) { + pwm = CONV_PWM_MAX * 8 / 10; + operState = ConvMPP; + } + + if(power_state.current_avg > MAX_CURRENT) { + operState = ConvConstCurrent; + } + + if(power_state.vin_avg < power_state.vout_avg) { + operState = Idle; + } + break; + + case ConvFloat: + if(time_in_state < 120000) { + setPoint = + fxp_add(CONST_VOLTAGE, + fxp_mult(fxp_sub(CONST_FLOAT_VOLTAGE, CONST_VOLTAGE), fxp_div(time_in_state, 120000))); + } else { + setPoint = CONST_FLOAT_VOLTAGE; + } + + // calculate error values + pErr = fxp_sub(setPoint, power_state.vout_avg); + iErr = fxp_add(iErr, pErr); + + // limit integral error range + if (iErr > IERR_LIMIT) iErr = IERR_LIMIT; + else if(iErr < -IERR_LIMIT) iErr = -IERR_LIMIT; + + // calculate the controller output ("action") + controlAction = fxp_add( + fxp_mult(pErr, PGAIN_CV), + fxp_mult(iErr, IGAIN_CV)); + + pwm = fxp_to_int(controlAction); + + if(pwm > CONV_PWM_MAX) { + pwm = CONV_PWM_MAX; + } else if(pwm < 0) { + pwm = 0; + } + + timer_set_oc_value(TIM1, TIM_CH_CONV, pwm); + #ifdef DEBUG if((time_in_state % 100) == 0) { debug_send_string("pErr: "); @@ -791,7 +879,8 @@ int main(void) nextState = ConvConstVoltage; } - if(time_in_state > 1000 && power_state.vout_avg < MPP_VOLTAGE_THR) { + if(time_in_state > 1000 && power_state.vout_avg < VOLTAGE_THR_FLOAT_TO_MPP) { + pwm = CONV_PWM_MAX * 8 / 10; operState = ConvMPP; } @@ -809,9 +898,6 @@ int main(void) iErr = 0; } - // bootstrap off - timer_set_oc_value(TIM1, TIM_CH_BOOTSTRAP, 0); - // calculate error values pErr = fxp_sub(MAX_CURRENT, power_state.current_avg); iErr = fxp_add(iErr, pErr); @@ -844,15 +930,12 @@ int main(void) operState = ConvMPP; } - if(power_state.vout_avg > MAX_VOLTAGE) { + if(power_state.vout_avg > MPP_MAX_VOLTAGE) { operState = ConvConstVoltage; } break; case ConvMPP: - // bootstrap off - timer_set_oc_value(TIM1, TIM_CH_BOOTSTRAP, 0); - mpp_run(time_in_state, &mpp_state, &power_state, &pwm); if(pwm > mpp_state.mppMaxPWM) { @@ -883,7 +966,7 @@ int main(void) pwm = mpp_state.mppMaxPWM; } - if(power_state.vout_avg > MAX_VOLTAGE) { + if(power_state.vout_avg > MPP_MAX_VOLTAGE) { operState = ConvConstVoltage; } @@ -984,6 +1067,9 @@ int main(void) case ConvConstVoltage: lcd_send_string("CV "); break; + case ConvFloat: + lcd_send_string("FLT"); + break; case ConvMPP: lcd_send_string("MPP"); break;