Add support for calibrating current sensors

Hw_conf can define CURRENT_CAL1,2,3 to set individual calibrations for each current sensor.

By default no calibration is used. (x1.0)

For example this is used on the A50S by looping a calibrated current using a power supply through each phase. Then the correction is saved in external eeprom to persist across firmware updates.

Tested on FOC, DC and BLDC modes.
This commit is contained in:
Euan 2024-02-05 23:47:45 +00:00
parent c5b8bb7feb
commit af65f521de
6 changed files with 60 additions and 46 deletions

View File

@ -120,6 +120,9 @@
// Current ADC to amperes factor
#define FAC_CURRENT ((V_REG / 4095.0) / (CURRENT_SHUNT_RES * CURRENT_AMP_GAIN))
#define FAC_CURRENT1 ((V_REG / 4095.0) / (CURRENT_SHUNT_RES * CURRENT_AMP_GAIN )) * CURRENT_CAL1
#define FAC_CURRENT2 ((V_REG / 4095.0) / (CURRENT_SHUNT_RES * CURRENT_AMP_GAIN )) * CURRENT_CAL2
#define FAC_CURRENT3 ((V_REG / 4095.0) / (CURRENT_SHUNT_RES * CURRENT_AMP_GAIN )) * CURRENT_CAL3
#define VOLTAGE_TO_ADC_FACTOR ( VIN_R2 / (VIN_R2 + VIN_R1) ) * ( 4096.0 / V_REG )

View File

@ -383,6 +383,16 @@
#endif
#endif
#ifndef CURRENT_CAL1
#define CURRENT_CAL1 1.0
#endif
#ifndef CURRENT_CAL2
#define CURRENT_CAL2 1.0
#endif
#ifndef CURRENT_CAL3
#define CURRENT_CAL3 1.0
#endif
#ifndef HW_MAX_CURRENT_OFFSET
#define HW_MAX_CURRENT_OFFSET 620
#endif

View File

@ -2442,17 +2442,18 @@ static lbm_value ext_raw_adc_current(lbm_value *args, lbm_uint argn) {
mcpwm_foc_get_current_offsets(&ofs1, &ofs2, &ofs3, motor == 2);
float ph1, ph2, ph3;
mcpwm_foc_get_currents_adc(&ph1, &ph2, &ph3, motor == 2);
float scale = FAC_CURRENT;
float scale1, scale2, scale3;
scale1 = FAC_CURRENT1; scale2 = FAC_CURRENT2; scale3 = FAC_CURRENT3;
if (argn == 3 && lbm_dec_as_i32(args[2]) != 0) {
scale = 1.0;
scale1 = 1.0; scale2 = 1.0; scale3 = 1.0;
ofs1 = 0.0; ofs2 = 0.0; ofs3 = 0.0;
}
switch(phase) {
case 1: return lbm_enc_float((ph1 - ofs1) * scale);
case 2: return lbm_enc_float((ph2 - ofs2) * scale);
case 3: return lbm_enc_float((ph3 - ofs3) * scale);
case 1: return lbm_enc_float((ph1 - ofs1) * scale1);
case 2: return lbm_enc_float((ph2 - ofs2) * scale2);
case 3: return lbm_enc_float((ph3 - ofs3) * scale3);
default: return ENC_SYM_EERROR;
}
}

View File

@ -2881,9 +2881,9 @@ static THD_FUNCTION(sample_send_thread, arg) {
buffer_append_float32_auto(buffer, (float)m_vzero_samples[ind_samp], &index);
buffer_append_float32_auto(buffer, (float)m_curr_fir_samples[ind_samp], &index);
} else {
buffer_append_float32_auto(buffer, (float)m_curr0_samples[ind_samp] * FAC_CURRENT, &index);
buffer_append_float32_auto(buffer, (float)m_curr1_samples[ind_samp] * FAC_CURRENT, &index);
buffer_append_float32_auto(buffer, (float)m_curr2_samples[ind_samp] * FAC_CURRENT, &index);
buffer_append_float32_auto(buffer, (float)m_curr0_samples[ind_samp] * FAC_CURRENT1, &index);
buffer_append_float32_auto(buffer, (float)m_curr1_samples[ind_samp] * FAC_CURRENT2, &index);
buffer_append_float32_auto(buffer, (float)m_curr2_samples[ind_samp] * FAC_CURRENT3, &index);
buffer_append_float32_auto(buffer, ((float)m_ph1_samples[ind_samp] / 4096.0 * V_REG) * ((VIN_R1 + VIN_R2) / VIN_R2) * ADC_VOLTS_PH_FACTOR, &index);
buffer_append_float32_auto(buffer, ((float)m_ph2_samples[ind_samp] / 4096.0 * V_REG) * ((VIN_R1 + VIN_R2) / VIN_R2) * ADC_VOLTS_PH_FACTOR, &index);
buffer_append_float32_auto(buffer, ((float)m_ph3_samples[ind_samp] / 4096.0 * V_REG) * ((VIN_R1 + VIN_R2) / VIN_R2) * ADC_VOLTS_PH_FACTOR, &index);

View File

@ -1562,12 +1562,12 @@ void mcpwm_adc_inj_int_handler(void) {
if (conf->motor_type == MOTOR_TYPE_DC) {
if (direction) {
#ifdef HW_HAS_3_SHUNTS
curr_tot_sample = -(GET_CURRENT3() - curr2_offset);
curr_tot_sample = -(GET_CURRENT3() - curr2_offset) * FAC_CURRENT3;;
#else
curr_tot_sample = -(GET_CURRENT2() - curr1_offset);
curr_tot_sample = -(GET_CURRENT2() - curr1_offset) * FAC_CURRENT2;;
#endif
} else {
curr_tot_sample = -(GET_CURRENT1() - curr0_offset);
curr_tot_sample = -(GET_CURRENT1() - curr0_offset) * FAC_CURRENT1;;
}
} else {
static int detect_now = 0;
@ -1593,52 +1593,52 @@ void mcpwm_adc_inj_int_handler(void) {
*/
if (state == MC_STATE_FULL_BRAKE) {
float c0 = (float)ADC_curr_norm_value[0];
float c1 = (float)ADC_curr_norm_value[1];
float c2 = (float)ADC_curr_norm_value[2];
float c0 = (float)ADC_curr_norm_value[0] * FAC_CURRENT1;
float c1 = (float)ADC_curr_norm_value[1] * FAC_CURRENT2;
float c2 = (float)ADC_curr_norm_value[2] * FAC_CURRENT3;
curr_tot_sample = sqrtf((c0*c0 + c1*c1 + c2*c2) / 1.5);
} else {
#ifdef HW_HAS_3_SHUNTS
if (direction) {
switch (comm_step) {
case 1: curr_tot_sample = -(float)ADC_curr_norm_value[2]; break;
case 2: curr_tot_sample = -(float)ADC_curr_norm_value[2]; break;
case 3: curr_tot_sample = -(float)ADC_curr_norm_value[1]; break;
case 4: curr_tot_sample = -(float)ADC_curr_norm_value[1]; break;
case 5: curr_tot_sample = -(float)ADC_curr_norm_value[0]; break;
case 6: curr_tot_sample = -(float)ADC_curr_norm_value[0]; break;
case 1: curr_tot_sample = -(float)ADC_curr_norm_value[2] * FAC_CURRENT3; break;
case 2: curr_tot_sample = -(float)ADC_curr_norm_value[2] * FAC_CURRENT3; break;
case 3: curr_tot_sample = -(float)ADC_curr_norm_value[1] * FAC_CURRENT2; break;
case 4: curr_tot_sample = -(float)ADC_curr_norm_value[1] * FAC_CURRENT2; break;
case 5: curr_tot_sample = -(float)ADC_curr_norm_value[0] * FAC_CURRENT1; break;
case 6: curr_tot_sample = -(float)ADC_curr_norm_value[0] * FAC_CURRENT1; break;
default: break;
}
} else {
switch (comm_step) {
case 1: curr_tot_sample = -(float)ADC_curr_norm_value[1]; break;
case 2: curr_tot_sample = -(float)ADC_curr_norm_value[1]; break;
case 3: curr_tot_sample = -(float)ADC_curr_norm_value[2]; break;
case 4: curr_tot_sample = -(float)ADC_curr_norm_value[2]; break;
case 5: curr_tot_sample = -(float)ADC_curr_norm_value[0]; break;
case 6: curr_tot_sample = -(float)ADC_curr_norm_value[0]; break;
case 1: curr_tot_sample = -(float)ADC_curr_norm_value[1] * FAC_CURRENT2; break;
case 2: curr_tot_sample = -(float)ADC_curr_norm_value[1] * FAC_CURRENT2; break;
case 3: curr_tot_sample = -(float)ADC_curr_norm_value[2] * FAC_CURRENT3; break;
case 4: curr_tot_sample = -(float)ADC_curr_norm_value[2] * FAC_CURRENT3; break;
case 5: curr_tot_sample = -(float)ADC_curr_norm_value[0] * FAC_CURRENT1; break;
case 6: curr_tot_sample = -(float)ADC_curr_norm_value[0] * FAC_CURRENT1; break;
default: break;
}
}
#else
if (direction) {
switch (comm_step) {
case 1: curr_tot_sample = -(float)ADC_curr_norm_value[1]; break;
case 2: curr_tot_sample = -(float)ADC_curr_norm_value[1]; break;
case 3: curr_tot_sample = (float)ADC_curr_norm_value[0]; break;
case 4: curr_tot_sample = (float)ADC_curr_norm_value[1]; break;
case 5: curr_tot_sample = -(float)ADC_curr_norm_value[0]; break;
case 6: curr_tot_sample = -(float)ADC_curr_norm_value[0]; break;
case 1: curr_tot_sample = -(float)ADC_curr_norm_value[1] * FAC_CURRENT2; break;
case 2: curr_tot_sample = -(float)ADC_curr_norm_value[1] * FAC_CURRENT2; break;
case 3: curr_tot_sample = (float)ADC_curr_norm_value[0] * FAC_CURRENT1; break;
case 4: curr_tot_sample = (float)ADC_curr_norm_value[1] * FAC_CURRENT2; break;
case 5: curr_tot_sample = -(float)ADC_curr_norm_value[0] * FAC_CURRENT1; break;
case 6: curr_tot_sample = -(float)ADC_curr_norm_value[0] * FAC_CURRENT1; break;
default: break;
}
} else {
switch (comm_step) {
case 1: curr_tot_sample = (float)ADC_curr_norm_value[1]; break;
case 2: curr_tot_sample = (float)ADC_curr_norm_value[0]; break;
case 3: curr_tot_sample = -(float)ADC_curr_norm_value[1]; break;
case 4: curr_tot_sample = -(float)ADC_curr_norm_value[1]; break;
case 5: curr_tot_sample = -(float)ADC_curr_norm_value[0]; break;
case 6: curr_tot_sample = -(float)ADC_curr_norm_value[0]; break;
case 1: curr_tot_sample = (float)ADC_curr_norm_value[1] * FAC_CURRENT2; break;
case 2: curr_tot_sample = (float)ADC_curr_norm_value[0] * FAC_CURRENT1; break;
case 3: curr_tot_sample = -(float)ADC_curr_norm_value[1] * FAC_CURRENT2; break;
case 4: curr_tot_sample = -(float)ADC_curr_norm_value[1] * FAC_CURRENT2; break;
case 5: curr_tot_sample = -(float)ADC_curr_norm_value[0] * FAC_CURRENT1; break;
case 6: curr_tot_sample = -(float)ADC_curr_norm_value[0] * FAC_CURRENT1; break;
default: break;
}
}
@ -1722,7 +1722,7 @@ void mcpwm_adc_inj_int_handler(void) {
}
}
last_current_sample = curr_tot_sample * FAC_CURRENT;
last_current_sample = curr_tot_sample;
// Filter out outliers
if (fabsf(last_current_sample) > (conf->l_abs_current_max * 1.2)) {

View File

@ -2830,8 +2830,8 @@ void mcpwm_foc_adc_int_handler(void *p, uint32_t flags) {
float curr1;
if (is_second_motor) {
curr0 = (GET_CURRENT1() - conf_other->foc_offsets_current[0]) * FAC_CURRENT;
curr1 = (GET_CURRENT2() - conf_other->foc_offsets_current[1]) * FAC_CURRENT;
curr0 = (GET_CURRENT1() - conf_other->foc_offsets_current[0]) * FAC_CURRENT1;
curr1 = (GET_CURRENT2() - conf_other->foc_offsets_current[1]) * FAC_CURRENT2;
TIMER_UPDATE_DUTY_M1(motor_other->m_duty1_next, motor_other->m_duty2_next, motor_other->m_duty3_next);
} else {
curr0 = (GET_CURRENT1_M2() - conf_other->foc_offsets_current[0]) * FAC_CURRENT;
@ -2839,8 +2839,8 @@ void mcpwm_foc_adc_int_handler(void *p, uint32_t flags) {
TIMER_UPDATE_DUTY_M2(motor_other->m_duty1_next, motor_other->m_duty2_next, motor_other->m_duty3_next);
}
#else
float curr0 = (GET_CURRENT1() - conf_other->foc_offsets_current[0]) * FAC_CURRENT;
float curr1 = (GET_CURRENT2() - conf_other->foc_offsets_current[1]) * FAC_CURRENT;
float curr0 = (GET_CURRENT1() - conf_other->foc_offsets_current[0]) * FAC_CURRENT1;
float curr1 = (GET_CURRENT2() - conf_other->foc_offsets_current[1]) * FAC_CURRENT2;
TIMER_UPDATE_DUTY_M1(motor_other->m_duty1_next, motor_other->m_duty2_next, motor_other->m_duty3_next);
#ifdef HW_HAS_DUAL_PARALLEL
@ -3042,9 +3042,9 @@ void mcpwm_foc_adc_int_handler(void *p, uint32_t flags) {
}
#endif
float ia = ADC_curr_norm_value[0 + norm_curr_ofs] * FAC_CURRENT;
float ib = ADC_curr_norm_value[1 + norm_curr_ofs] * FAC_CURRENT;
float ic = ADC_curr_norm_value[2 + norm_curr_ofs] * FAC_CURRENT;
float ia = ADC_curr_norm_value[0 + norm_curr_ofs] * FAC_CURRENT1;
float ib = ADC_curr_norm_value[1 + norm_curr_ofs] * FAC_CURRENT2;
float ic = ADC_curr_norm_value[2 + norm_curr_ofs] * FAC_CURRENT3;
// This has to be done for the skip function to have any chance at working with the
// observer and control loops.