проект запущен шим идет, нужно запустить с пид регулятором вывести все измерения в структуру
This commit is contained in:
@@ -7,6 +7,48 @@
|
||||
#define HRTIM_TIMER_C_INDEX 2U
|
||||
#define ADC_SAMPLE_TIME_47CYCLES 5U
|
||||
#define HRTIM_DLL_READY_TIMEOUT 1000000UL
|
||||
#define DCDC_MIN_PERIOD_TICKS 100UL
|
||||
#define DCDC_MAX_PERIOD_TICKS 0xFFFFUL
|
||||
#define DCDC_MAX_PERMILLE 1000UL
|
||||
|
||||
/*
|
||||
## Live configuration
|
||||
|
||||
The compile-time macros in `app_config.h` only seed this object. After reset,
|
||||
edit `g_dcdc_config` in Keil Watch and the 1 ms service loop applies the new
|
||||
values to HRTIM and the control loop.
|
||||
*/
|
||||
volatile DCDC_RuntimeConfig g_dcdc_config =
|
||||
{
|
||||
#if DCDC_PWM_TEST_ENABLE
|
||||
DCDC_MODE_PWM_TEST,
|
||||
#elif DCDC_POWER_STAGE_ENABLE
|
||||
DCDC_MODE_CLOSED_LOOP,
|
||||
#else
|
||||
DCDC_MODE_MONITOR,
|
||||
#endif
|
||||
DCDC_CONNECT_USBPD_INPUT,
|
||||
{
|
||||
DCDC_PWM_FREQUENCY_HZ,
|
||||
DCDC_PWM_TEST_DUTY_PERMILLE,
|
||||
900U,
|
||||
DCDC_PWM_TEST_DEADTIME_ENABLE,
|
||||
DCDC_PWM_TEST_DEADTIME_TICKS,
|
||||
DCDC_PWM_TEST_DEADTIME_TICKS
|
||||
},
|
||||
{
|
||||
DCDC_TARGET_VOUT_MV,
|
||||
DCDC_MIN_VIN_MV,
|
||||
DCDC_MAX_VOUT_MV,
|
||||
DCDC_MAX_INPUT_CURRENT_MA,
|
||||
DCDC_HARD_INPUT_CURRENT_MA
|
||||
},
|
||||
{
|
||||
DCDC_KP_TICKS_PER_100MV,
|
||||
DCDC_KI_TICKS_PER_100MV,
|
||||
DCDC_CURRENT_LIMIT_KP
|
||||
}
|
||||
};
|
||||
|
||||
static DCDC_State s_state = DCDC_STATE_STOPPED;
|
||||
static DCDC_Fault s_fault = DCDC_FAULT_NONE;
|
||||
@@ -22,8 +64,11 @@ static bool hrtim1_timer_c_init(void);
|
||||
static bool hrtim1_wait_dll_ready(void);
|
||||
static void hrtim1_outputs_enable(bool enable);
|
||||
static void hrtim1_set_duty(uint32_t duty_ticks);
|
||||
static uint32_t hrtim_period_from_clock(void);
|
||||
static uint32_t hrtim_period_from_frequency(uint32_t frequency_hz);
|
||||
static uint32_t permille_to_ticks(uint32_t permille);
|
||||
static void hrtim1_apply_pwm_config(void);
|
||||
static uint32_t hrtim_max_duty_ticks(void);
|
||||
static uint32_t clamp_u32(uint32_t value, uint32_t min_value, uint32_t max_value);
|
||||
static uint32_t adc_raw_to_mv(uint16_t raw);
|
||||
static uint32_t sense_mv_to_voltage_mv(uint32_t sense_mv, uint32_t scale_ppm);
|
||||
static uint32_t sense_mv_to_current_ma(uint32_t sense_mv);
|
||||
@@ -61,17 +106,46 @@ void DCDC_Start(void)
|
||||
return;
|
||||
}
|
||||
|
||||
#if DCDC_CONNECT_USBPD_INPUT
|
||||
set_usbpd_input_switch(true);
|
||||
#endif
|
||||
set_usbpd_input_switch(g_dcdc_config.connect_usbpd_input != 0U);
|
||||
|
||||
s_integrator_ticks = 0;
|
||||
hrtim1_apply_pwm_config();
|
||||
hrtim1_set_duty(DCDC_START_DUTY_TICKS);
|
||||
HRTIM1->sMasterRegs.MCR |= HRTIM_MCR_TCCEN;
|
||||
hrtim1_outputs_enable(true);
|
||||
s_state = DCDC_STATE_RUNNING;
|
||||
}
|
||||
|
||||
void DCDC_StartPwmTest(void)
|
||||
{
|
||||
uint32_t test_duty_ticks;
|
||||
|
||||
if (s_fault != DCDC_FAULT_NONE)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!s_hrtim_ready)
|
||||
{
|
||||
latch_fault(DCDC_FAULT_HRTIM);
|
||||
return;
|
||||
}
|
||||
|
||||
hrtim1_apply_pwm_config();
|
||||
test_duty_ticks = permille_to_ticks(g_dcdc_config.pwm.test_duty_permille);
|
||||
if (test_duty_ticks == 0U)
|
||||
{
|
||||
test_duty_ticks = 1U;
|
||||
}
|
||||
|
||||
set_usbpd_input_switch(false);
|
||||
s_integrator_ticks = 0;
|
||||
hrtim1_set_duty(test_duty_ticks);
|
||||
HRTIM1->sMasterRegs.MCR |= HRTIM_MCR_TCCEN;
|
||||
hrtim1_outputs_enable(true);
|
||||
s_state = DCDC_STATE_PWM_TEST;
|
||||
}
|
||||
|
||||
void DCDC_Stop(void)
|
||||
{
|
||||
hrtim1_outputs_enable(false);
|
||||
@@ -81,6 +155,59 @@ void DCDC_Stop(void)
|
||||
s_state = DCDC_STATE_STOPPED;
|
||||
}
|
||||
|
||||
void DCDC_Service1ms(void)
|
||||
{
|
||||
DCDC_Mode mode = DCDC_GetMode();
|
||||
|
||||
DCDC_ApplyRuntimeConfig();
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
case DCDC_MODE_MONITOR:
|
||||
if ((s_state == DCDC_STATE_PWM_TEST) || (s_state == DCDC_STATE_RUNNING))
|
||||
{
|
||||
DCDC_Stop();
|
||||
}
|
||||
break;
|
||||
|
||||
case DCDC_MODE_PWM_TEST:
|
||||
if (s_state != DCDC_STATE_PWM_TEST)
|
||||
{
|
||||
DCDC_StartPwmTest();
|
||||
}
|
||||
break;
|
||||
|
||||
case DCDC_MODE_CLOSED_LOOP:
|
||||
if (s_state != DCDC_STATE_RUNNING)
|
||||
{
|
||||
DCDC_Start();
|
||||
}
|
||||
if (s_state == DCDC_STATE_RUNNING)
|
||||
{
|
||||
DCDC_ControlStep();
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void DCDC_ApplyRuntimeConfig(void)
|
||||
{
|
||||
if (!s_hrtim_ready)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
hrtim1_apply_pwm_config();
|
||||
|
||||
if (s_state == DCDC_STATE_PWM_TEST)
|
||||
{
|
||||
hrtim1_set_duty(permille_to_ticks(g_dcdc_config.pwm.test_duty_permille));
|
||||
}
|
||||
}
|
||||
|
||||
void DCDC_ControlStep(void)
|
||||
{
|
||||
DCDC_Measurements m;
|
||||
@@ -95,19 +222,19 @@ void DCDC_ControlStep(void)
|
||||
return;
|
||||
}
|
||||
|
||||
if (m.vin_mv < DCDC_MIN_VIN_MV)
|
||||
if (m.vin_mv < g_dcdc_config.limits.min_vin_mv)
|
||||
{
|
||||
latch_fault(DCDC_FAULT_UNDERVOLTAGE);
|
||||
return;
|
||||
}
|
||||
|
||||
if (m.vout_mv > DCDC_MAX_VOUT_MV)
|
||||
if (m.vout_mv > g_dcdc_config.limits.max_vout_mv)
|
||||
{
|
||||
latch_fault(DCDC_FAULT_OVERVOLTAGE);
|
||||
return;
|
||||
}
|
||||
|
||||
if (m.iin_ma > DCDC_HARD_INPUT_CURRENT_MA)
|
||||
if (m.iin_ma > g_dcdc_config.limits.hard_current_ma)
|
||||
{
|
||||
latch_fault(DCDC_FAULT_OVERCURRENT);
|
||||
return;
|
||||
@@ -121,10 +248,10 @@ void DCDC_ControlStep(void)
|
||||
*
|
||||
* This is deliberately readable, not a final compensated SMPS loop.
|
||||
*/
|
||||
feed_forward = (int32_t)(((uint64_t)DCDC_TARGET_VOUT_MV * s_period_ticks) / m.vin_mv);
|
||||
error_mv = (int32_t)DCDC_TARGET_VOUT_MV - (int32_t)m.vout_mv;
|
||||
feed_forward = (int32_t)(((uint64_t)g_dcdc_config.limits.target_vout_mv * s_period_ticks) / m.vin_mv);
|
||||
error_mv = (int32_t)g_dcdc_config.limits.target_vout_mv - (int32_t)m.vout_mv;
|
||||
|
||||
s_integrator_ticks += (error_mv * DCDC_KI_TICKS_PER_100MV) / 100;
|
||||
s_integrator_ticks += (error_mv * g_dcdc_config.loop.ki_ticks_per_100mv) / 100;
|
||||
if (s_integrator_ticks > 3000)
|
||||
{
|
||||
s_integrator_ticks = 3000;
|
||||
@@ -135,12 +262,13 @@ void DCDC_ControlStep(void)
|
||||
}
|
||||
|
||||
duty = feed_forward +
|
||||
((error_mv * DCDC_KP_TICKS_PER_100MV) / 100) +
|
||||
((error_mv * g_dcdc_config.loop.kp_ticks_per_100mv) / 100) +
|
||||
s_integrator_ticks;
|
||||
|
||||
if (m.iin_ma > DCDC_MAX_INPUT_CURRENT_MA)
|
||||
if (m.iin_ma > g_dcdc_config.limits.current_limit_ma)
|
||||
{
|
||||
duty -= (int32_t)((m.iin_ma - DCDC_MAX_INPUT_CURRENT_MA) * DCDC_CURRENT_LIMIT_KP);
|
||||
duty -= (int32_t)((m.iin_ma - g_dcdc_config.limits.current_limit_ma) *
|
||||
g_dcdc_config.loop.current_limit_kp);
|
||||
}
|
||||
|
||||
if (duty < (int32_t)DCDC_MIN_DUTY_TICKS)
|
||||
@@ -174,6 +302,20 @@ void DCDC_ReadMeasurements(DCDC_Measurements *out)
|
||||
out->vout_mv = sense_mv_to_voltage_mv(vout_sense_mv, DCDC_VOUT_SCALE_PPM);
|
||||
}
|
||||
|
||||
DCDC_Mode DCDC_GetMode(void)
|
||||
{
|
||||
switch ((DCDC_Mode)g_dcdc_config.mode)
|
||||
{
|
||||
case DCDC_MODE_MONITOR:
|
||||
case DCDC_MODE_PWM_TEST:
|
||||
case DCDC_MODE_CLOSED_LOOP:
|
||||
return (DCDC_Mode)g_dcdc_config.mode;
|
||||
|
||||
default:
|
||||
return DCDC_MODE_MONITOR;
|
||||
}
|
||||
}
|
||||
|
||||
DCDC_State DCDC_GetState(void)
|
||||
{
|
||||
return s_state;
|
||||
@@ -205,12 +347,24 @@ const char *DCDC_StateText(DCDC_State state)
|
||||
{
|
||||
case DCDC_STATE_STOPPED: return "stopped";
|
||||
case DCDC_STATE_READY: return "ready";
|
||||
case DCDC_STATE_PWM_TEST:return "pwm-test";
|
||||
case DCDC_STATE_RUNNING: return "running";
|
||||
case DCDC_STATE_FAULT: return "fault";
|
||||
default: return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
const char *DCDC_ModeText(DCDC_Mode mode)
|
||||
{
|
||||
switch (mode)
|
||||
{
|
||||
case DCDC_MODE_MONITOR: return "monitor";
|
||||
case DCDC_MODE_PWM_TEST: return "pwm-test";
|
||||
case DCDC_MODE_CLOSED_LOOP: return "closed-loop";
|
||||
default: return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
const char *DCDC_FaultText(DCDC_Fault fault)
|
||||
{
|
||||
switch (fault)
|
||||
@@ -303,9 +457,11 @@ static bool hrtim1_timer_c_init(void)
|
||||
|
||||
RCC->APB2ENR |= RCC_APB2ENR_HRTIM1EN;
|
||||
(void)RCC->APB2ENR;
|
||||
RCC->APB2RSTR |= RCC_APB2RSTR_HRTIM1RST;
|
||||
RCC->APB2RSTR &= ~RCC_APB2RSTR_HRTIM1RST;
|
||||
|
||||
HRTIM1->sCommonRegs.ODISR = HRTIM_ODISR_TC1ODIS | HRTIM_ODISR_TC2ODIS;
|
||||
s_period_ticks = hrtim_period_from_clock();
|
||||
s_period_ticks = hrtim_period_from_frequency(g_dcdc_config.pwm.frequency_hz);
|
||||
|
||||
HRTIM1->sCommonRegs.ICR = HRTIM_ICR_DLLRDYC;
|
||||
HRTIM1->sCommonRegs.DLLCR = HRTIM_DLLCR_CALEN |
|
||||
@@ -326,11 +482,18 @@ static bool hrtim1_timer_c_init(void)
|
||||
timer->CMP2xR = hrtim_max_duty_ticks();
|
||||
timer->CMP3xR = 1000U;
|
||||
|
||||
timer->DTxR =
|
||||
((DCDC_DEADTIME_RISING_TICKS & 0x1FFUL) << HRTIM_DTR_DTR_Pos) |
|
||||
((DCDC_DEADTIME_FALLING_TICKS & 0x1FFUL) << HRTIM_DTR_DTF_Pos) |
|
||||
(HRTIM_DTR_DTPRSC_1 | HRTIM_DTR_DTPRSC_0);
|
||||
|
||||
#if DCDC_PWM_TEST_ENABLE
|
||||
/*
|
||||
* Complementary HRTIM test without dead-time/fault handling:
|
||||
* PB12/CHC1 goes active at period and inactive at CMP1.
|
||||
* PB13/CHC2 goes active at CMP1 and inactive at period.
|
||||
*/
|
||||
timer->SETx1R = HRTIM_SET1R_PER;
|
||||
timer->RSTx1R = HRTIM_RST1R_CMP1;
|
||||
timer->SETx2R = HRTIM_SET2R_CMP1;
|
||||
timer->RSTx2R = HRTIM_RST2R_PER;
|
||||
timer->OUTxR = 0U;
|
||||
#else
|
||||
/*
|
||||
* Complementary buck PWM:
|
||||
* CHC1 goes active at period event and inactive at CMP1.
|
||||
@@ -342,6 +505,9 @@ static bool hrtim1_timer_c_init(void)
|
||||
timer->SETx2R = HRTIM_SET2R_CMP1;
|
||||
timer->RSTx2R = HRTIM_RST2R_PER;
|
||||
timer->OUTxR = HRTIM_OUTR_DTEN | HRTIM_OUTR_FAULT1_1 | HRTIM_OUTR_FAULT2_1;
|
||||
#endif
|
||||
|
||||
hrtim1_apply_pwm_config();
|
||||
|
||||
/* Trigger point for future synchronized ADC sampling. */
|
||||
HRTIM1->sCommonRegs.ADC1R = HRTIM_ADC1R_AD1TCC3;
|
||||
@@ -389,26 +555,64 @@ static void hrtim1_set_duty(uint32_t duty_ticks)
|
||||
s_duty_ticks = duty_ticks;
|
||||
}
|
||||
|
||||
static uint32_t hrtim_period_from_clock(void)
|
||||
static uint32_t hrtim_period_from_frequency(uint32_t frequency_hz)
|
||||
{
|
||||
uint64_t ticks = (((uint64_t)SystemCoreClock * 32ULL) + (DCDC_PWM_FREQUENCY_HZ / 2ULL)) /
|
||||
DCDC_PWM_FREQUENCY_HZ;
|
||||
uint64_t ticks;
|
||||
|
||||
if (ticks < 100ULL)
|
||||
if (frequency_hz == 0U)
|
||||
{
|
||||
ticks = 100ULL;
|
||||
frequency_hz = DCDC_PWM_FREQUENCY_HZ;
|
||||
}
|
||||
else if (ticks > 0xFFFFULL)
|
||||
|
||||
ticks = (((uint64_t)SystemCoreClock * 32ULL) + (frequency_hz / 2ULL)) /
|
||||
frequency_hz;
|
||||
|
||||
if (ticks < DCDC_MIN_PERIOD_TICKS)
|
||||
{
|
||||
ticks = 0xFFFFULL;
|
||||
ticks = DCDC_MIN_PERIOD_TICKS;
|
||||
}
|
||||
else if (ticks > DCDC_MAX_PERIOD_TICKS)
|
||||
{
|
||||
ticks = DCDC_MAX_PERIOD_TICKS;
|
||||
}
|
||||
|
||||
return (uint32_t)ticks;
|
||||
}
|
||||
|
||||
static uint32_t permille_to_ticks(uint32_t permille)
|
||||
{
|
||||
permille = clamp_u32(permille, 0U, DCDC_MAX_PERMILLE);
|
||||
return (uint32_t)(((uint64_t)s_period_ticks * permille) / DCDC_MAX_PERMILLE);
|
||||
}
|
||||
|
||||
static void hrtim1_apply_pwm_config(void)
|
||||
{
|
||||
HRTIM_Timerx_TypeDef *timer = &HRTIM1->sTimerxRegs[HRTIM_TIMER_C_INDEX];
|
||||
uint32_t period_ticks = hrtim_period_from_frequency(g_dcdc_config.pwm.frequency_hz);
|
||||
uint32_t rising_ticks = clamp_u32(g_dcdc_config.pwm.deadtime_rising_ticks, 0U, 0x1FFU);
|
||||
uint32_t falling_ticks = clamp_u32(g_dcdc_config.pwm.deadtime_falling_ticks, 0U, 0x1FFU);
|
||||
|
||||
s_period_ticks = period_ticks;
|
||||
timer->PERxR = period_ticks;
|
||||
timer->DTxR =
|
||||
(rising_ticks << HRTIM_DTR_DTR_Pos) |
|
||||
(falling_ticks << HRTIM_DTR_DTF_Pos) |
|
||||
(HRTIM_DTR_DTPRSC_1 | HRTIM_DTR_DTPRSC_0);
|
||||
|
||||
if (g_dcdc_config.pwm.deadtime_enable != 0U)
|
||||
{
|
||||
timer->OUTxR |= HRTIM_OUTR_DTEN;
|
||||
}
|
||||
else
|
||||
{
|
||||
timer->OUTxR &= ~HRTIM_OUTR_DTEN;
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t hrtim_max_duty_ticks(void)
|
||||
{
|
||||
uint32_t max_ticks = DCDC_MAX_DUTY_TICKS;
|
||||
uint32_t max_permille = clamp_u32(g_dcdc_config.pwm.max_duty_permille, 1U, DCDC_MAX_PERMILLE);
|
||||
uint32_t max_ticks = permille_to_ticks(max_permille);
|
||||
|
||||
if (s_period_ticks > 10U && max_ticks >= (s_period_ticks - 1U))
|
||||
{
|
||||
@@ -418,6 +622,21 @@ static uint32_t hrtim_max_duty_ticks(void)
|
||||
return max_ticks;
|
||||
}
|
||||
|
||||
static uint32_t clamp_u32(uint32_t value, uint32_t min_value, uint32_t max_value)
|
||||
{
|
||||
if (value < min_value)
|
||||
{
|
||||
return min_value;
|
||||
}
|
||||
|
||||
if (value > max_value)
|
||||
{
|
||||
return max_value;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
static uint32_t adc_raw_to_mv(uint16_t raw)
|
||||
{
|
||||
return ((uint32_t)raw * ADC_REFERENCE_MV) / ADC_FULL_SCALE_COUNTS;
|
||||
|
||||
Reference in New Issue
Block a user