diff --git a/src/main.c b/src/main.c index d446f80..fc39d0b 100644 --- a/src/main.c +++ b/src/main.c @@ -21,6 +21,7 @@ enum OperState { Bootstrap, ConvConstVoltage, + ConvConstCurrent, Idle, }; @@ -203,21 +204,32 @@ int main(void) char number[FXP_STR_MAXLEN]; uint8_t sentSomething = 0; + int32_t pwm; + enum OperState operState = Bootstrap; + enum OperState nextState = ConvConstVoltage; enum OperState lastState = operState; fxp_t vin, vout, current; + fxp_t vin_avg = 0, vout_avg = 0, current_avg = 0; fxp_t pErr, iErr = 0; fxp_t controlAction; - fxp_t PGAIN = fxp_from_float( 20.000f); - fxp_t IGAIN = fxp_from_float( 1.000f); - fxp_t IERR_LIMIT = fxp_from_int(10000); + fxp_t PGAIN_CV = fxp_from_float( 50.000f); + fxp_t IGAIN_CV = fxp_from_float( 0.300f); + fxp_t IERR_LIMIT = fxp_from_int(4000); + + fxp_t PGAIN_CC = fxp_from_float( 50.000f); + fxp_t IGAIN_CC = fxp_from_float( 0.300f); fxp_t CURRENT_THRESHOLD = fxp_from_float(0.05f); - fxp_t maxVoltage = fxp_from_float(11.000f); + fxp_t AVG_FACT = fxp_from_float(0.10f); + fxp_t AVG_FACT_INV = fxp_sub(fxp_from_int(1), AVG_FACT); + + fxp_t maxVoltage = fxp_from_float(12.000f); + fxp_t maxCurrent = fxp_from_float( 5.000f); // Calculated values //fxp_t VIN_SCALE = fxp_from_float(3.3f * (100 + 12.4f) / 12.4f / 4095.0f); @@ -229,6 +241,8 @@ int main(void) fxp_t VOUT_SCALE = fxp_from_float(12.6f / 1620.0f); fxp_t CURRENT_SCALE = fxp_from_float(9.01f / 4095.0f); + fxp_t CURRENT_OFFSET = fxp_from_float(0.049); + init_clock(); init_gpio(); init_adc(); @@ -246,37 +260,6 @@ int main(void) // let the ADC+DMA do its work adc_start_conversion_regular(ADC1); - - /* - - // Ramp up target voltage - if((targetVoltage < TARGET_VOLTAGE) && (voltRampUpCountdown-- == 0)) { - targetVoltage += 2.0f; - voltRampUpCountdown = VOLTAGE_UP_INTERVAL; - - if(targetVoltage > TARGET_VOLTAGE) { - targetVoltage = TARGET_VOLTAGE; - } - } - - // read ADC value - while(!adc_eoc(ADC1)); - adcval = adc_read_regular(ADC1); - - // scale current measurement - curVoltage = VOLTAGE_MEAS_MAX * adcval / 4096.0f; - - - // calculate resulting PWM value - if(controlAction > MAX_DUTY_CYCLE) { - pwm_value = (int)(PWM_PERIOD * MAX_DUTY_CYCLE); - } else if(controlAction > 0) { - pwm_value = (int)(controlAction * PWM_PERIOD); - } else { - pwm_value = 0; - } - */ - // *** Do some calculations while ADC converts *** if(lcd_setup()) { @@ -287,13 +270,13 @@ int main(void) lcd_set_cursor_pos(1, 0); - fxp_format(vin, number, 1); + fxp_format(vin_avg, number, 1); fxp_right_align(number, msg, 4, ' '); lcd_send_string("I:"); lcd_send_string(msg); lcd_send_string("V "); - fxp_format(vout, number, 1); + fxp_format(vout_avg, number, 1); fxp_right_align(number, msg, 4, ' '); lcd_send_string("O:"); lcd_send_string(msg); @@ -301,7 +284,7 @@ int main(void) lcd_set_cursor_pos(0, 10); - scaled_val = fxp_mult(current, fxp_from_int(1000)); // A -> mA + scaled_val = fxp_mult(current_avg, fxp_from_int(1000)); // A -> mA fxp_format(scaled_val, number, 0); fxp_right_align(number, msg, 4, ' '); lcd_send_string(msg); @@ -330,6 +313,11 @@ int main(void) vin = fxp_mult(fxp_from_int(adc_values[0]), VIN_SCALE); vout = fxp_mult(fxp_from_int(adc_values[1]), VOUT_SCALE); current = fxp_mult(fxp_from_int(adc_values[2]), CURRENT_SCALE); + current = fxp_sub(current, CURRENT_OFFSET); + + vin_avg = fxp_add(fxp_mult(vin, AVG_FACT), fxp_mult(vin_avg, AVG_FACT_INV)); + vout_avg = fxp_add(fxp_mult(vout, AVG_FACT), fxp_mult(vout_avg, AVG_FACT_INV)); + current_avg = fxp_add(fxp_mult(current, AVG_FACT), fxp_mult(current_avg, AVG_FACT_INV)); // Main FSM if(timebase_ms >= 1000) { @@ -342,7 +330,7 @@ int main(void) if(time_in_state >= 5) { // bootstrap duration in ms iErr = fxp_from_int(500); - operState = ConvConstVoltage; + operState = nextState; } break; @@ -351,7 +339,7 @@ int main(void) timer_set_oc_value(TIM1, TIM_CH_BOOTSTRAP, 0); // calculate error values - pErr = fxp_sub(maxVoltage, vout); + pErr = fxp_sub(maxVoltage, vout_avg); iErr = fxp_add(iErr, pErr); // limit integral error range @@ -360,15 +348,10 @@ int main(void) // calculate the controller output ("action") controlAction = fxp_add( - fxp_mult(pErr, PGAIN), - fxp_mult(iErr, IGAIN)); + fxp_mult(pErr, PGAIN_CV), + fxp_mult(iErr, IGAIN_CV)); - int32_t pwm = fxp_to_int(controlAction); - - if(pwm > 5000 && current < CURRENT_THRESHOLD) { - operState = Bootstrap; - break; - } + pwm = fxp_to_int(controlAction); if(pwm >= CONV_PWM_MAX) { timer_set_oc_value(TIM1, TIM_CH_CONV, CONV_PWM_MAX); @@ -377,6 +360,52 @@ int main(void) } else { timer_set_oc_value(TIM1, TIM_CH_CONV, 0); } + + if(time_in_state > 1000 && pwm > CONV_PWM_MAX && current < CURRENT_THRESHOLD) { + operState = Bootstrap; + nextState = ConvConstVoltage; + } + + if(current_avg > maxCurrent) { + operState = ConvConstCurrent; + } + break; + + case ConvConstCurrent: + // bootstrap off + timer_set_oc_value(TIM1, TIM_CH_BOOTSTRAP, 0); + + // calculate error values + pErr = fxp_sub(maxCurrent, current_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_CC), + fxp_mult(iErr, IGAIN_CC)); + + pwm = fxp_to_int(controlAction); + + if(pwm >= CONV_PWM_MAX) { + timer_set_oc_value(TIM1, TIM_CH_CONV, CONV_PWM_MAX); + } else if(pwm > 0) { + timer_set_oc_value(TIM1, TIM_CH_CONV, pwm); + } else { + timer_set_oc_value(TIM1, TIM_CH_CONV, 0); + } + + if(time_in_state > 1000 && pwm > CONV_PWM_MAX && current < CURRENT_THRESHOLD) { + operState = Bootstrap; + nextState = ConvConstCurrent; + } + + if(vout_avg > maxVoltage) { + operState = ConvConstVoltage; + } break; case Idle: @@ -396,6 +425,25 @@ int main(void) if(operState != lastState) { time_in_state = 0; lastState = operState; + + lcd_set_cursor_pos(0, 7); + switch(operState) { + case Idle: + lcd_send_string("ID"); + break; + case Bootstrap: + lcd_send_string("BS"); + break; + case ConvConstCurrent: + lcd_send_string("CC"); + break; + case ConvConstVoltage: + lcd_send_string("CV"); + break; + default: + lcd_send_string("??"); + break; + } } else { time_in_state++; }