Skip to main content
Associate
Oct 22, 2026 9:52 PM UTC
Question

Technical Feedback: Feedback Latency and TIM7 Initialization in STDES-VIENNARECT Reference Firmware

 

1. Executive Summary

During evaluation of the vienna_stm32g474 reference project, a data-rate decoupling effect was identified in the main PFC voltage control loop. The physical DC-link voltage feedback structure (VOLTAGE_ADC_DC_IN_PHY) is calculated inside a 2 kHz telemetry task (TIM7), but it is consumed by the main cascaded controller (DPC_LCT_PFC_Ctrl) operating within the 20 kHz interrupt loop (TIM2).

Although the raw ADC data is sampled at 20 kHz (TIM2) and is immediately available in the Data Layer via DPC_CDT_DcVoltageRead(), the conversion to physical units is delayed by the low-frequency task. This feedback latency was previously masked by a 16-bit register truncation error in TIM7, which forced its real execution frequency up to ~8.7 kHz. Testing confirms that relocating the physical voltage scale conversion (DPC_ADC_VoltageDCAdc2PhyProcessData) to the 8 kHz voltage loop task (TIM6) resolves this constraint, optimizing PI controller responsiveness and improving grid current waveform quality.

 

2. Technical Analysis

Observation A: Feedback Update Rate in Cascaded Loop

In app_vienna.c, the core control loop function DPC_LCT_PFC_Ctrl runs under the high-frequency TIM2 (20 kHz) interrupt instance, where the raw ADC conversion data is collected. Under the VOLTAGE_LOOP state, the inner execution directly utilizes VOLTAGE_ADC_DC_IN_PHY->Vdc_tot to perform the DC voltage regulation:

 

// Executed at 20 kHz (TIM2 Interrupt)
case Run_PFC_Mode:
DPC_LCT_PFC_Ctrl(&pPFC_CTRL, &V_DQO_CTRL, &GridCurrentDQO, &GridVoltageDQO, &VOLTAGE_ADC_DC_IN_PHY);
...

 

However, the physical scale conversion function DPC_ADC_VoltageDCAdc2PhyProcessData is assigned to the lower-frequency telemetry task under TIM7:

 

// Nominally assigned to 2 kHz (TIM7 Interrupt)
else if(htim->Instance == DPC_ApplTIM_TypeDef5) {
DPC_ADC_VoltageDCAdc2PhyProcessData(&DPC_ADC_Conf, (uint32_t*)DPC_CDT_DcVoltageRead(), &VOLTAGE_ADC_DC_IN_PHY);
...
}

 

  • Impact: Since the conversion function accesses the already updated Data Layer via DPC_CDT_DcVoltageRead(), running it at a lower rate introduces an artificial stepped feedback profile (10 control cycles of stale data at 20 kHz execution). This introduces phase lag regarding the 300 Hz / 600 Hz DC-link voltage ripples. Relocating this physical processing to the TIM6 (8 kHz) interrupt block allows the cascaded voltage loop to operate on significantly fresher physical feedback.

Observation B: TIM7 16-Bit Register Calculation

The initialization routine DPC_MISC_ApplTimer_Init configures DPC_ApplTIM_TypeDef5 (TIM7) using the following target value:

 

#define DPC_VR_RefreshTime3_DESIDERED           2000 // 2 kHz

 

  • Mechanism: TIM7 is a 16-bit basic timer peripheral with a maximum Auto-Reload Register (ARR) capacity of 0xFFFF (65535). The clock configuration logic results in an integer value overflow when calculating the required ARR ticks for a 2 kHz target on a 170 MHz system clock.
  • Interaction: Due to bit truncation upon writing to the 16-bit register, TIM7 defaults to an effective operating frequency of ~8.7 kHz instead of 2 kHz. This increased update rate closely matched the 8 kHz grid sensing rate, minimizing the feedback latency under factory testing defaults.

3. Implemented Modifications & Solutions

  1. Relocation of Conversion Logic: The DPC_ADC_VoltageDCAdc2PhyProcessData function call was moved from the TIM7 task into the TIM6 (8 kHz) interrupt block, processing the data returned by DPC_CDT_DcVoltageRead(). This ensures that the 20 kHz voltage loop controller receives physical feedback refreshed at the maximum available sampling frequency of the voltage control loop.
  2. TIM7 Prescaler Adjustment: The hardware clock prescaler (PSC) for TIM7 was changed from 0 to 1 in the STM32CubeMX configuration interface. This scales the peripheral clock down to 85 MHz, allowing the required ARR value to fit within the valid 16-bit range and establishing the correct nominal 2000 Hz telemetry rate.

4. Software Maintenance & CubeMX Compatibility

  • TIM7 Prescaler: The change to the TIM7 hardware prescaler is stored directly inside the STM32CubeMX project file (.ioc) and is successfully preserved across code generation cycles.
  • Code Integrity: The application architecture encapsulates the core control functions and timer callback routines inside the standard protected USER CODE sections at the bottom of app_vienna.c. Relocating the processing functions between timer instances does not interfere with the auto-generation layout and is not overwritten by STM32CubeMX:

 

void MX_Vienna_Init(void)
{
/* PACK CODE BEGIN 2 */
// Initialization logic
/* PACK CODE END 2 */
}

void MX_Vienna_Process(void)
{
/* PACK CODE BEGIN 3 */
// Background task logic
/* PACK CODE END 3 */
}

/* USER CODE BEGIN 4 */
// ==================== USER CODE PROTECTED ZONE ====================
bool DPC_FSM_WAIT_Func(void) {...}
bool DPC_FSM_IDLE_Func(void) {...}
...
void DPC_Appl_TIM_Callback(TIM_HandleTypeDef *htim) {
// Relocation of DPC_ADC_VoltageDCAdc2PhyProcessData to TIM6 implemented here
}
...
/* USER CODE END 4 */

2 replies

Associate
Nov 1, 2026 2:40 PM UTC

Update / Addendum to Technical Feedback:

Further analysis of the DPC (Digital Power Conversion) library core functions reveals that the relocation of DPC_ADC_VoltageDCAdc2PhyProcessData to TIM6 is not necessary if the original firmware architecture constraints are maintained. Instead, a minor variable integration discrepancy was identified in the main 20 kHz loop (TIM2).

Root Cause & Variable Mismatch

Inside DPC_Appl_TIM_Callback (TIM2), the cascaded control loop receives the physical voltage structure:

 

DPC_LCT_PFC_Ctrl(&pPFC_CTRL, &V_DQO_CTRL, &GridCurrentDQO, &GridVoltageDQO, &VOLTAGE_ADC_DC_IN_PHY);

 

This passes absolute physical Volts (Vdc_tot \(\approx \) 800.0 V) to the internal fVdcFeed parameter of the control structure.

However, the internal DC Feedforward decoupling task (DPC_LCT_FeedForwardDC_Ctrl) performs a normalization division:

 

pCDC_sub->fVtdFF_Ctrl = fVtd_ctrl_sub / fVdc_sub;

 

For this dynamic decoupling to scale the duty cycle output correctly without saturating the PWM modulator, fVdc_sub must be a normalized Per-Unit (PU) value, which is exactly what VOLTAGE_ADC_DC_IN_NORM.Vdc_tot (\(\approx \) 1.0 – 1.7) provides. Under the factory default configuration, these advanced decoupling and feedforward tasks are bypassed via definition flags (RESET), masking the scaling mismatch.

Proposed Alternative Solution

If a developer intends to activate the advanced control features bVDC_FF_Enable = SET  , the optimal fix is to update the passed argument inside the 20 kHz (TIM2) task:

  • Change from: &VOLTAGE_ADC_DC_IN_PHY
  • Change to: &VOLTAGE_ADC_DC_IN_NORM

Impact on CPU Load & Telemetry

Since VOLTAGE_ADC_DC_IN_NORM is already calculated natively at 8 kHz inside TIM6, making this change allows the high-frequency control loop to consume pre-scaled, low-latency data.

Consequently, the floating-point intensive physical conversion DPC_ADC_VoltageDCAdc2PhyProcessData can remain safely inside the low-frequency TIM7 task strictly for telemetry and low-speed logging, preventing unnecessary CPU execution overhead in the mid-frequency interrupt vectors.

Associate
Nov 10, 2026 1:35 AM UTC

*** FURTHER UPDATE: Retraction of Previous Workaround and Insights on Scaling Dependencies ***

Hello Community,

Regarding my previous update stating:
"If we look closer at the TIM2 loop... the argument of DPC_LCT_PFC_Ctrl should be switched from &VOLTAGE_ADC_DC_IN_PHY to &VOLTAGE_ADC_DC_IN_NORM"

Please disregard that statement, as further practical evaluation shows that this approach is mathematically incorrect for this framework.

After a closer analytical review of the sequential execution paths inside the DPC library (specifically DPC_LCT_CDC() and the surrounding control layers), it is evident that the voltage loop PI controller coefficients (DPC_VR_VCTRL_KP / DPC_VR_VCTRL_KI) and the reference target (PFC_VDC_Ref = 800), as exported by eDesignStudio, are structurally scaled to operate strictly on absolute physical Units (Volts).

If the control loop input argument is switched to the normalized structure, the effective feedback gain inside the error calculator drops by a factor of nearly 800, leading to controller saturation. Keeping the physical scale conversion (DPC_ADC_VoltageDCAdc2PhyProcessData) coupled with the physical PI loop path is necessary to preserve the mathematical scale integrity.

As a result, to maintain correct loop scaling and avoid controller malfunction, the DC Feed-Forward feature (bVDC_FF_Enable) should be kept disabled (RESET), matching the baseline configuration of the reference design.