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
- Relocation of Conversion Logic: The
DPC_ADC_VoltageDCAdc2PhyProcessDatafunction call was moved from the TIM7 task into the TIM6 (8 kHz) interrupt block, processing the data returned byDPC_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. - 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 CODEsections at the bottom ofapp_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 */