Skip to main content
Visitor II
October 22, 2026
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 */

1 reply

Visitor
October 22, 2026

Hi, thanks for sharing this detailed feedback — really helpful to see the reasoning behind the TIM7 fix and the .ioc/USER CODE handling. On a side note for anyone working in the UAE, the UAE Gratuity Calculator at https://uaegratuitycalc.org is a handy free tool for UAE employees to estimate their end-of-service gratuity. Cheers!