Skip to content

Commit

Permalink
Merge pull request #99 from WattRex/feature/MID_PWR
Browse files Browse the repository at this point in the history
Feature/mid pwr
  • Loading branch information
pastorpflores authored Jun 30, 2023
2 parents 354f0aa + 08df49a commit 78b03f1
Show file tree
Hide file tree
Showing 7 changed files with 607 additions and 1 deletion.
6 changes: 6 additions & 0 deletions firmware/Sources/HAL/HAL_PWM/hal_pwm.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
/**********************************************************************************/
/* Definition of local symbolic constants */
/**********************************************************************************/

#define MIN_PWM 96
/**********************************************************************************/
/* Definition of local function like macros */
Expand All @@ -35,6 +36,7 @@
/* Definition of local variables */
/**********************************************************************************/
static HRTIM_CompareCfgTypeDef pCompareCfg = {0};
uint32_t * max_steps;
/**********************************************************************************/
/* Definition of exported variables */
/**********************************************************************************/
Expand Down Expand Up @@ -70,6 +72,7 @@ HAL_PWM_result_e HAL_PwmInit(void){
MX_HRTIM1_Init();
if (EPC_ST_ERR_COUNTER==0){
HAL_PWM_period = (hhrtim1.Instance->sTimerxRegs[0].PERxR);

res = HAL_PWM_RESULT_SUCCESS;
}
return res;
Expand All @@ -78,10 +81,12 @@ HAL_PWM_result_e HAL_PwmInit(void){

HAL_PWM_result_e HAL_PwmSetDuty(const uint32_t duty){
// Get the period of the timer, as will be the maximum value to compare

uint32_t pwm_duty;
if (duty>=HAL_PWM_period){
// The maximum duty to apply is the period configured -1
pwm_duty = HAL_PWM_period -1;

}
//If duty between max and min values
else if (duty>=MIN_PWM){
Expand All @@ -94,6 +99,7 @@ HAL_PWM_result_e HAL_PwmSetDuty(const uint32_t duty){

// Write the value to compare in the register.
pCompareCfg.CompareValue = pwm_duty;
// pCompareCfg.CompareValue = 5007;
// Apply the compare configuration to the dessire timer unit in this case HRTIM-A1
HAL_PWM_result_e res = HAL_HRTIM_WaveformCompareConfig(&hhrtim1, HRTIM_TIMERINDEX_TIMER_A, HRTIM_COMPAREUNIT_1, &pCompareCfg);;
return res;
Expand Down
2 changes: 1 addition & 1 deletion firmware/Sources/HAL/HAL_PWM/hal_pwm.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ extern uint32_t HAL_PWM_period;
/**********************************************************************************/
/* Definition of exported constant data */
/**********************************************************************************/

#define HAL_PWM_MAX_DUTY 100000 //steps of duty
/**********************************************************************************/
/* Declaration of exported function prototypes */
/**********************************************************************************/
Expand Down
317 changes: 317 additions & 0 deletions firmware/Sources/MID/MID_PWR/mid_pwr.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,317 @@
/*********************************************************************************
* @file : mid_pwr.c
* @brief : Implementation of MID_PWR
***********************************************************************************/

/**********************************************************************************/
/* Include common and project definition header */
/**********************************************************************************/
#include "hal_pwm.h"
#include "hal_gpio.h"
#include "epc_conf.h"

/**********************************************************************************/
/* Include headers of the component */
/**********************************************************************************/
#include "mid_pwr.h"
#include "mid_reg.h"

/**********************************************************************************/
/* Include other headers */
/**********************************************************************************/
/**********************************************************************************/
/* Definition of local types (typedef, enum, struct, union) */
/**********************************************************************************/

typedef enum{
SOA_ok = 0x0u,
SOA_over_pwr,
SOA_under_pwr
}SOA_e;

typedef int32_t fp_t;
/**********************************************************************************/
/* Definition of local symbolic constants */
/**********************************************************************************/
#define _FP_FACTOR (1 << EPC_CONF_FP_N_FRAC_BITS)
#define _SCALING_FACTOR_MILIS 1000
#define _SCALING_FACTOR_DECIS 10


/**********************************************************************************/
/* Definition of local function like macros */
/**********************************************************************************/
// reference: http://www.sunshine2k.de/articles/coding/fp/sunfp.html#ch42
/**
* @fn dSI_to_FP(value)
* @brief Converts the value given in deciUnits to the fixed point specified and return it.
* @param value, Value in deciunits
*/
#define dSI_to_FP(value) ((fp_t) value * _FP_FACTOR / _SCALING_FACTOR_DECIS)
/**
* @fn mSI_to_FP(value)
* @brief Converts the value given in miliUnits to the fixed point specified
* @param value, Value in miliunits
*/
#define mSI_to_FP(value) ((fp_t) value * _FP_FACTOR / _SCALING_FACTOR_MILIS)

/**
* @fn sum_to_FP(sum1,sum2)
* @brief Make the sum of 2 values in fixed point, return the result in fp
* @param sum1, first operand
* @param sum2, second operand
*/
#define sum_FP(sum1,sum2) (sum1 + sum2)
/**
* @fn sub_FP(sub1,sub2)
* @brief Make the difference of 2 values in fixed point, return the result in fp
* @param sub1, first operand
* @param sub2, second operand
*/
#define sub_FP(sub1,sub2) (sub1 - sub2)
/**
* @fn mul_FP(fac1,fac2)
* @brief Make the multiplication of 2 values in fixed point, return the result in fp
* @param fac1, first operand
* @param fac2, second operand
*/
#define mul_FP(fac1,fac2) ((fp_t)(((int64_t)(fac1) * (int64_t)(fac2)>>EPC_CONF_FP_N_FRAC_BITS)))

/**
* @fn FP_to_mSI(value)
* @brief Converts the value given in fixed point to miliUnits
* @param value, Value in miliunits
*/
#define FP_to_mSI(value) ((int16_t) ( (int64_t)(value) * _SCALING_FACTOR_MILIS >> EPC_CONF_FP_N_FRAC_BITS))
/**
* @fn FP_to_dSI(value)
* @brief Converts the value given in fixed point to deciUnits
* @param value, Value in miliunits
*/
#define FP_to_dSI(value) ((int16_t) ( (int64_t)(value) * _SCALING_FACTOR_DECIS >> EPC_CONF_FP_N_FRAC_BITS))
/**
* @fn FP_to_SI(value)
* @brief Converts the value given in fixed point to Units
* @param value, Value in miliunits
*/
#define FP_to_SI(value) ((int16_t) ( (int64_t)(value) >> EPC_CONF_FP_N_FRAC_BITS))

/**********************************************************************************/
/* Definition of exported constant data */
/**********************************************************************************/
extern uint32_t HAL_PWM_period;
/**********************************************************************************/
/* Declaration of local function prototypes */
/**********************************************************************************/

/**
* @fn static MID_PWR_result_e _calculatePI(const int16_t ref, const int16_t meas, const MID_PWR_Mode_e mode,
const MID_REG_limit_s limits, int32_t * action)
* @brief Apply a specefic PI,
* @param ref, value to have as reference
* @param meas, value measured from sensor
* @param mode, type of PI to apply
* @param limits, limits to use in the PI
* @param action_res, pointer to the action to apply
* @return @ref MID_PWR_RESULT_SUCCESS if calculated correctly,
* @ref MID_PWR_RESULT_BUSY, @ref MID_PWR_RESULT_TIMEOUT or
* @ref MID_PWR_RESULT_ERROR otherwise.
*/
static MID_PWR_result_e _calculatePI(const int16_t ref, const int16_t meas,
const MID_PWR_Mode_e mode, const MID_REG_limit_s limits, int16_t * action_res);

/**
* @fn static SOA_e _checkSOA(const int16_t I, const uint16_t V, const MID_REG_limit_s limits)
* @brief Check the device is working under the safe operating area, all the measures must refer to the low side of the EPC.
* @param I, Value of the current.
* @param V, Value of the voltage
* @param limits, register in which are stored the maximum and minimum values of power.
* @return @ref SOA_ok if not traspassing the limits,
* @ref SOA_over_pwr, the upper limit has been surpassed.
* @ref SOA_under_pwr, the lower limit has been surpassed.
*/
static SOA_e _checkSOA(const int16_t I, const uint16_t V, const MID_REG_limit_s limits);

/**********************************************************************************/
/* Definition of local constant data */
/**********************************************************************************/
#define Q16_SCALE_FACTOR 65536 // 2^16
/**********************************************************************************/
/* Definition of local variables */
/**********************************************************************************/
static fp_t last_error[3] = {0, 0, 0}; //I, V, P PI values
static fp_t integral[3] = {0, 0, 0}; //I, V, P PI values
static uint16_t duty, d0 = 0; //action duty goes from 0 to 9215

/**********************************************************************************/
/* Definition of exported variables */
/**********************************************************************************/

/**********************************************************************************/
/* Definition of imported variables */
/**********************************************************************************/
extern uint32_t HAL_PWM_period;
/**********************************************************************************/
/* Definition of local functions */
/**********************************************************************************/

static SOA_e _checkSOA(const int16_t I, const uint16_t V, const MID_REG_limit_s limits){
SOA_e res = SOA_ok;
int16_t power = (int16_t)(((int32_t)I * (int32_t)V) /100000); // 10^-3(mW) *10^-3 (mW) / 10^-5 -> dW
if (power > limits.lsPwrMax)
res = SOA_over_pwr;
else if (power < limits.lsPwrMin)
res = SOA_under_pwr;
return res;
}

static MID_PWR_result_e _calculatePI(const int16_t ref, const int16_t meas, const MID_PWR_Mode_e mode,
const MID_REG_limit_s limits, int16_t * action_res){

// Get values for the specific PI
int16_t upper_limit, lower_limit; //int32 because of duty
fp_t kp,ki;
static fp_t fp_ref, fp_input;
static fp_t error;
static fp_t accion, proporcional = 0;
fp_t up_limit_I = 2097152000;
fp_t low_limit_I = -2097152000;

// set limits for saturation
if (mode != MID_PWR_MODE_CC){ //out for pwr or v PI is allways current
upper_limit = (limits.lsCurrMax) ;
lower_limit = (limits.lsCurrMin) ;
if (mode == MID_PWR_MODE_CV){
kp= EPC_CONF_PWR_KP_V;
ki= EPC_CONF_PWR_KI_V;
fp_ref = mSI_to_FP(ref);
fp_input = mSI_to_FP(meas);

}else{
kp= EPC_CONF_PWR_KP_P;
ki= EPC_CONF_PWR_KI_P;
fp_ref = dSI_to_FP(ref);
fp_input = dSI_to_FP(meas);
}
}else if (mode == MID_PWR_MODE_CC){ // for i PI actions is the Duty to apply
upper_limit = (HAL_PWM_period -1);
lower_limit = HAL_PWM_MIN_PWM;
kp= EPC_CONF_PWR_KP_I;
ki= EPC_CONF_PWR_KI_I;
fp_ref = mSI_to_FP(ref);
fp_input = mSI_to_FP(meas);
}


// error = (double)(reference - input);
error = sub_FP(fp_ref,fp_input);

// proporcional = kp_I * error;
proporcional = mul_FP(kp,error);

// integral = integral + ki_I * last_error;
fp_t temp;
temp = mul_FP(ki,last_error[mode]);
integral[mode] = sum_FP(integral[mode],temp);


if(integral[mode] >= up_limit_I){
integral[mode] = up_limit_I;
}else if(integral[mode] <= low_limit_I){
integral[mode] = low_limit_I;
}

last_error[mode] = error;
// accion = proporcional + integral[mode];
accion = sum_FP(proporcional,integral[mode]);


if (mode == MID_PWR_MODE_CC){
*action_res = FP_to_SI(accion);
}else{
*action_res = FP_to_mSI(accion);
}
if(*action_res >= upper_limit){
*action_res = upper_limit;
}else if(*action_res <= lower_limit){
*action_res = lower_limit;
}
return MID_PWR_RESULT_SUCCESS;
}

/**********************************************************************************/
/* Definition of exported functions */
/**********************************************************************************/

MID_PWR_result_e MID_PwrSetOutput(const MID_PWR_Output_e outputMode){
MID_PWR_result_e res = MID_PWR_RESULT_ERROR;
res = (MID_PWR_result_e) HAL_GpioSet(HAL_GPIO_OUT_OutDisable, outputMode);
if (outputMode == MID_PWR_Enable && res == MID_PWR_RESULT_SUCCESS){
last_error[0] = 0;
last_error[1] = 0;
last_error[2] = 0;
integral[0] = d0 * _FP_FACTOR;
integral[1] = 0;
integral[2] = 0;
if (res == MID_PWR_RESULT_SUCCESS){
res |= (MID_PWR_result_e) HAL_PwmSetDuty(d0);
res |= HAL_PwmStart();
}
}
else if (outputMode == MID_PWR_Disable && res == MID_PWR_RESULT_SUCCESS){
res |= HAL_PwmStop();
}
return res;
}

MID_PWR_result_e MID_PwrApplyCtrl(const int16_t ref, const uint16_t V_LS, const int16_t I_LS, const MID_PWR_Mode_e control_mode, const MID_REG_limit_s limits){
MID_PWR_result_e res = MID_PWR_RESULT_ERROR;
int16_t curr_ref, actual_power;
int16_t new_duty;
switch (control_mode) { //first PI, if needed (in Pwr and V refs)
case MID_PWR_MODE_CP:
actual_power = (int16_t)(((int32_t)I_LS * (int32_t)V_LS) /100000); // dW
res = _calculatePI(ref, actual_power, MID_PWR_MODE_CP, limits, &curr_ref);
break;
case MID_PWR_MODE_CV:
res = _calculatePI(ref, V_LS, MID_PWR_MODE_CV, limits, &curr_ref);
break;
case MID_PWR_MODE_CC: //First PI not needed.
curr_ref = ref;
res = MID_PWR_RESULT_SUCCESS;
break;
default:
res = MID_PWR_RESULT_ERROR;
}
if (res == MID_PWR_RESULT_SUCCESS){

// I action at this point is allways under the limits. The pwr and V PI saturate the action
// and I ref from APP_CTRL is allways in limit

SOA_e SOA_status = _checkSOA(curr_ref, V_LS, limits);
if (SOA_status == SOA_over_pwr){
curr_ref = (int32_t)(limits.lsPwrMax*100) / V_LS;
}
else if (SOA_status == SOA_under_pwr){
curr_ref = (int32_t)(limits.lsPwrMin*100) / V_LS;
}
// calculate current PI
//Ignore warning as action for current PI will be a value of duty between 0-9215
res = _calculatePI(curr_ref, I_LS, MID_PWR_MODE_CC, limits, &new_duty);
if (res == MID_PWR_RESULT_SUCCESS){
duty = new_duty;
res = (MID_PWR_result_e) HAL_PwmSetDuty((uint32_t)duty);
}
}
return res;
}

MID_PWR_result_e MID_PwrCalculateD0(const uint16_t V_HS, const uint16_t V_LS){
MID_PWR_result_e res = MID_PWR_RESULT_ERROR;
uint32_t new_d0 = (V_LS * ((HAL_PWM_period-1)-HAL_PWM_MIN_PWM)) / V_HS;
if (new_d0 <= (HAL_PWM_period-1) && new_d0 >= 0){
d0 = new_d0;
res = MID_PWR_RESULT_SUCCESS;
}
return res;
}
Loading

0 comments on commit 78b03f1

Please sign in to comment.