Legacy branch migration
This commit is contained in:
341
firmware/drivers/output.c
Normal file
341
firmware/drivers/output.c
Normal file
@@ -0,0 +1,341 @@
|
||||
/**** Includes ****/
|
||||
#include "output.h"
|
||||
|
||||
/**** Private definitions ****/
|
||||
typedef struct {
|
||||
uint8_t active;
|
||||
uint8_t time;
|
||||
} warn_t;
|
||||
|
||||
typedef struct {
|
||||
warn_t supply_voltage;
|
||||
warn_t supply_current;
|
||||
warn_t supply_power;
|
||||
warn_t output_voltage;
|
||||
warn_t output_current;
|
||||
warn_t output_power;
|
||||
warn_t output_open;
|
||||
warn_t output_short;
|
||||
warn_t output_mismatch;
|
||||
} warnings_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t supply_uvlo;
|
||||
uint8_t supply_ovp;
|
||||
uint8_t supply_ocp;
|
||||
uint8_t supply_opp;
|
||||
uint8_t output_ovp;
|
||||
uint8_t output_ocp;
|
||||
uint8_t output_opp;
|
||||
uint8_t output_open;
|
||||
uint8_t output_short;
|
||||
} faults_t;
|
||||
|
||||
/**** Private constants ****/
|
||||
static const uint16_t LIM_SUPPLY_UVLO = 8000; //mV
|
||||
static const uint16_t LIM_SUPPLY_OVP = 18000; //mV
|
||||
static const uint16_t LIM_SUPPLY_OCP = 7000; //mA
|
||||
static const uint16_t LIM_SUPPLY_OPP = 40000; //mW
|
||||
|
||||
static const uint16_t LIM_OUTPUT_OVP = 12000; //mV
|
||||
static const uint16_t LIM_OUTPUT_OCP = 7000; //mA
|
||||
static const uint16_t LIM_OUTPUT_OPP = 40000; //mW
|
||||
|
||||
static const uint16_t LIM_OUTPUT_OPEN = 40000; //mR
|
||||
static const uint16_t LIM_OUTPUT_SHORT = 750; //mR
|
||||
|
||||
static const uint16_t LIM_OUTPUT_MATCH = 100; //mV
|
||||
|
||||
static const uint8_t OCP_WARNING_LIMIT = 10; //cycles
|
||||
static const uint8_t SHORT_WARNING_LIMIT = 50; //cycles
|
||||
|
||||
static const uint16_t MAX_OUTPUT_VOLTAGE = 10000; //mV
|
||||
static const uint16_t MIN_OUTPUT_VOLTAGE = 100; //mV
|
||||
|
||||
static const uint16_t COOLDOWN_TIME = 5000;
|
||||
|
||||
/**** Private variables ****/
|
||||
static warnings_t warnings;
|
||||
static faults_t faults;
|
||||
|
||||
static uint16_t target_output = 0;
|
||||
static uint16_t adj_target = 0;
|
||||
|
||||
static int32_t hb_volt_sum = 0;
|
||||
|
||||
static uint8_t new_target = 1;
|
||||
|
||||
static uint8_t steady_state = 0;
|
||||
|
||||
static faultState_t fault_state = F_NONE;
|
||||
|
||||
static uint16_t cooldown_timer = 0;
|
||||
|
||||
static outState_t out_state = O_OFF;
|
||||
|
||||
/**** Private function declarations ****/
|
||||
static void Process_Warnings(analog_t* meas);
|
||||
static uint8_t Process_Faults(void);
|
||||
|
||||
static void ProcessWarningTime(warn_t* w);
|
||||
static uint8_t isAnyFaultActive(faults_t* f);
|
||||
static uint8_t isFaultWarningActive(warnings_t* w, faults_t* f);
|
||||
static void ResetFaults(faults_t* f);
|
||||
|
||||
/**** Public function definitions ****/
|
||||
void Output_Enable(void)
|
||||
{
|
||||
ResetFaults(&faults);
|
||||
target_output = 0;
|
||||
out_state = O_ACTIVE;
|
||||
HB_SetTarget(0) ;
|
||||
HB_SetLowSide(1);
|
||||
HB_Enable();
|
||||
}
|
||||
|
||||
void Output_Update(analog_t* meas)
|
||||
{
|
||||
Process_Warnings(meas);
|
||||
|
||||
// Convert Warnings to Faults
|
||||
uint8_t active_fault = Process_Faults();
|
||||
|
||||
/// Ignore faults
|
||||
active_fault = 0;
|
||||
|
||||
// Determine coil state
|
||||
switch(out_state)
|
||||
{
|
||||
case O_ACTIVE:
|
||||
if(active_fault)
|
||||
{
|
||||
// Disable output
|
||||
HB_Disable();
|
||||
out_state = O_FAULTED;
|
||||
break;
|
||||
};
|
||||
|
||||
//Do target adjustment logic
|
||||
if(steady_state >= 10)
|
||||
{
|
||||
//Calculate average HB voltage
|
||||
hb_volt_sum /= 11;
|
||||
|
||||
// Calculate feedback adjusted HB output
|
||||
int32_t error = hb_volt_sum - (int32_t)target_output;
|
||||
int32_t temp = (int32_t)adj_target - error;
|
||||
// Limit to 16bits
|
||||
if(temp<=0) adj_target = 0;
|
||||
else if(temp >= 0x0000FFFF) adj_target = 0xFFFF;
|
||||
else adj_target = (uint16_t)temp;
|
||||
steady_state = 0;
|
||||
hb_volt_sum = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
hb_volt_sum += meas->hb_voltage;
|
||||
steady_state++;
|
||||
}
|
||||
|
||||
// Closed loop or open loop target set
|
||||
if(new_target)
|
||||
{
|
||||
// Set open-loop HB output
|
||||
HB_SetTarget(target_output);
|
||||
adj_target = target_output;
|
||||
steady_state = 0;
|
||||
new_target = 0;
|
||||
hb_volt_sum = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
HB_SetTarget(adj_target);
|
||||
}
|
||||
|
||||
// Update output
|
||||
HB_UpdateOutput(meas->supply_voltage);
|
||||
break;
|
||||
|
||||
case O_FAULTED:
|
||||
if(!active_fault)
|
||||
{
|
||||
//Return to normal state
|
||||
HB_Enable();
|
||||
out_state = O_ACTIVE;
|
||||
}
|
||||
break;
|
||||
|
||||
default: //OFF
|
||||
if(HB_IsEnabled()) HB_Disable();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Output_SetTarget(uint16_t voltage)
|
||||
{
|
||||
if(voltage > MAX_OUTPUT_VOLTAGE) voltage = MAX_OUTPUT_VOLTAGE;
|
||||
else if((voltage > 0)&&(voltage < MIN_OUTPUT_VOLTAGE)) voltage = MIN_OUTPUT_VOLTAGE;
|
||||
|
||||
if(voltage != target_output) new_target = 1;
|
||||
target_output = voltage;
|
||||
}
|
||||
|
||||
outState_t Output_GetOutputState(void)
|
||||
{
|
||||
return out_state;
|
||||
}
|
||||
|
||||
/**** Private function definitions ****/
|
||||
static void Process_Warnings(analog_t* meas)
|
||||
{
|
||||
// Supply UVLO and OVP
|
||||
if((meas->supply_voltage > LIM_SUPPLY_OVP)||(meas->supply_voltage < LIM_SUPPLY_UVLO)) warnings.supply_voltage.active = 1;
|
||||
else warnings.supply_voltage.active = 0;
|
||||
|
||||
// Supply OCP
|
||||
if(meas->supply_current > LIM_SUPPLY_OCP) warnings.supply_current.active = 1;
|
||||
else warnings.supply_current.active = 0;
|
||||
|
||||
// Supply OPP
|
||||
if(meas->supply_power > LIM_SUPPLY_OPP) warnings.supply_power.active = 1;
|
||||
else warnings.supply_power.active = 0;
|
||||
|
||||
// Halfbridge output conditions
|
||||
// Output Target mismatch
|
||||
if(HB_IsOutputMatch(meas->hb_voltage, LIM_OUTPUT_MATCH) == 0) warnings.output_mismatch.active = 1;
|
||||
else warnings.output_mismatch.active = 0;
|
||||
|
||||
// Output OCP
|
||||
if((HB_IsLowOn())&&(meas->hb_currnet > LIM_OUTPUT_OCP)) warnings.output_current.active = 1;
|
||||
else warnings.output_current.active = 0;
|
||||
|
||||
// Output OVP
|
||||
if((HB_IsLowOn())&&(meas->hb_voltage > LIM_OUTPUT_OVP)) warnings.output_voltage.active = 1;
|
||||
else warnings.output_voltage.active = 0;
|
||||
|
||||
// Output OPP
|
||||
if((HB_IsEnabled())&&(meas->hb_power > LIM_OUTPUT_OPP)) warnings.output_power.active = 1;
|
||||
else warnings.output_power.active = 0;
|
||||
|
||||
// Output Short
|
||||
if((HB_IsEnabled())&&(meas->hb_resistance < LIM_OUTPUT_SHORT)) warnings.output_short.active = 1;
|
||||
else warnings.output_short.active = 0;
|
||||
|
||||
// Output Open - Load loss
|
||||
if((HB_IsEnabled())&&(meas->hb_resistance > LIM_OUTPUT_OPEN)) warnings.output_open.active = 1;
|
||||
else warnings.output_open.active = 0;
|
||||
|
||||
ProcessWarningTime(&warnings.supply_voltage);
|
||||
ProcessWarningTime(&warnings.supply_current);
|
||||
ProcessWarningTime(&warnings.supply_power);
|
||||
ProcessWarningTime(&warnings.output_mismatch);
|
||||
ProcessWarningTime(&warnings.output_voltage);
|
||||
ProcessWarningTime(&warnings.output_current);
|
||||
ProcessWarningTime(&warnings.output_power);
|
||||
ProcessWarningTime(&warnings.output_open);
|
||||
ProcessWarningTime(&warnings.output_short);
|
||||
}
|
||||
|
||||
static uint8_t Process_Faults(void)
|
||||
{
|
||||
// Check warnings to escalate to fault
|
||||
// Supply OCP
|
||||
if(warnings.supply_current.time > OCP_WARNING_LIMIT) faults.supply_ocp = 1;
|
||||
|
||||
// Output OCP
|
||||
if(warnings.output_current.time > OCP_WARNING_LIMIT) faults.output_ocp = 1;
|
||||
|
||||
// Output short
|
||||
if(warnings.output_short.time > SHORT_WARNING_LIMIT) faults.output_short = 1;
|
||||
|
||||
switch(fault_state)
|
||||
{
|
||||
case F_ACTIVE:
|
||||
// Check if fault still active
|
||||
if(!isFaultWarningActive(&warnings, &faults))
|
||||
{
|
||||
// Fault cause ended, go to cooldown
|
||||
cooldown_timer = COOLDOWN_TIME;
|
||||
fault_state = F_COOLDOWN;
|
||||
};
|
||||
break;
|
||||
|
||||
case F_COOLDOWN:
|
||||
// Check if fault reoccurs
|
||||
if(isFaultWarningActive(&warnings, &faults))
|
||||
{
|
||||
fault_state = F_ACTIVE;
|
||||
break;
|
||||
};
|
||||
|
||||
// Wait for cooldown timer, reset fault flags
|
||||
if(cooldown_timer) cooldown_timer--;
|
||||
else
|
||||
{
|
||||
ResetFaults(&faults);
|
||||
fault_state = F_NONE;
|
||||
}
|
||||
break;
|
||||
|
||||
default: //NONE
|
||||
// Check for new faults
|
||||
if(isAnyFaultActive(&faults))
|
||||
{
|
||||
// Start fault process
|
||||
fault_state = F_ACTIVE;
|
||||
};
|
||||
break;
|
||||
}
|
||||
|
||||
if(fault_state != F_NONE) return 1;
|
||||
else return 0;
|
||||
}
|
||||
|
||||
static void ProcessWarningTime(warn_t* w)
|
||||
{
|
||||
if((w->active)&&(w->time < 0xFF)) w->time++;
|
||||
else if(w->active == 0) w->time = 0;
|
||||
}
|
||||
|
||||
static uint8_t isAnyFaultActive(faults_t* f)
|
||||
{
|
||||
if(f->supply_uvlo) return 1;
|
||||
if(f->supply_ovp) return 1;
|
||||
if(f->supply_ocp) return 1;
|
||||
if(f->supply_opp) return 1;
|
||||
if(f->output_ovp) return 1;
|
||||
if(f->output_ocp) return 1;
|
||||
if(f->output_opp) return 1;
|
||||
if(f->output_open) return 1;
|
||||
if(f->output_short) return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint8_t isFaultWarningActive(warnings_t* w, faults_t* f)
|
||||
{
|
||||
if((f->supply_uvlo) && (w->supply_voltage.active)) return 1;
|
||||
if((f->supply_ovp) && (w->supply_voltage.active)) return 1;
|
||||
if((f->supply_ocp) && (w->supply_current.active)) return 1;
|
||||
if((f->supply_opp) && (w->supply_power.active) ) return 1;
|
||||
if((f->output_ovp) && (w->output_voltage.active)) return 1;
|
||||
if((f->output_ocp) && (w->output_current.active)) return 1;
|
||||
if((f->output_opp) && (w->output_power.active) ) return 1;
|
||||
if((f->output_open) && (w->output_open.active) ) return 1;
|
||||
if((f->output_short) && (w->output_short.active) ) return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ResetFaults(faults_t* f)
|
||||
{
|
||||
f->supply_uvlo = 0;
|
||||
f->supply_ovp = 0;
|
||||
f->supply_ocp = 0;
|
||||
f->supply_opp = 0;
|
||||
f->output_ovp = 0;
|
||||
f->output_ocp = 0;
|
||||
f->output_opp = 0;
|
||||
f->output_open = 0;
|
||||
f->output_short = 0;
|
||||
}
|
||||
Reference in New Issue
Block a user