2022-01-24 02:59 PM
Dear all,
I've been trying to generate "LL_ADC_REG_TRIG_EXT_HRTIM_TRG1" with HRTIM to trigger a dual simultaneous conversion of the ADC of my STM32G474 based project.
I use LL drivers so, to my understanding the code to enable the trigger on the HRTIM side should be:
// HRTIM Peripheral clock enable
LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_HRTIM1);
// HRTIM DLL (Delay-Locked-Loop) Calibration
LL_HRTIM_ConfigDLLCalibration(HRTIM1, LL_HRTIM_DLLCALIBRATION_MODE_CONTINUOUS, LL_HRTIM_DLLCALIBRATION_RATE_3);
while(LL_HRTIM_IsActiveFlag_DLLRDY(HRTIM1) == RESET){};
// > HRTIM Master Configuration
LL_HRTIM_TIM_SetPrescaler(HRTIM1, LL_HRTIM_TIMER_MASTER, LL_HRTIM_PRESCALERRATIO_MUL4);
LL_HRTIM_TIM_SetPeriod(HRTIM1, LL_HRTIM_TIMER_MASTER, iInverter_PWM_Level);
LL_HRTIM_TIM_SetRepetition(HRTIM1, LL_HRTIM_TIMER_MASTER, 0x00);
// Time Base Settings:
LL_HRTIM_TIM_SetCounterMode(HRTIM1, LL_HRTIM_TIMER_MASTER, LL_HRTIM_MODE_CONTINUOUS);
// Timing Unit:
LL_HRTIM_TIM_SetInterleavedMode(HRTIM1, LL_HRTIM_TIMER_MASTER, LL_HRTIM_INTERLEAVED_MODE_DISABLED);
LL_HRTIM_TIM_DisableHalfMode(HRTIM1, LL_HRTIM_TIMER_MASTER);
LL_HRTIM_TIM_DisableStartOnSync(HRTIM1, LL_HRTIM_TIMER_MASTER);
LL_HRTIM_TIM_DisableResetOnSync(HRTIM1, LL_HRTIM_TIMER_MASTER);
LL_HRTIM_TIM_SetDACTrig(HRTIM1, LL_HRTIM_TIMER_MASTER, LL_HRTIM_DACTRIG_NONE);
LL_HRTIM_TIM_EnablePreload(HRTIM1, LL_HRTIM_TIMER_MASTER);
LL_HRTIM_TIM_SetUpdateGating(HRTIM1, LL_HRTIM_TIMER_MASTER, LL_HRTIM_UPDATEGATING_INDEPENDENT);
LL_HRTIM_TIM_SetBurstModeOption(HRTIM1, LL_HRTIM_TIMER_MASTER, LL_HRTIM_BURSTMODE_MAINTAINCLOCK);
LL_HRTIM_TIM_SetUpdateTrig(HRTIM1, LL_HRTIM_TIMER_MASTER, LL_HRTIM_UPDATETRIG_NONE);
// Wait for configuration applied
while(LL_HRTIM_IsActiveFlag_DLLRDY(HRTIM1) == RESET){};
// > HRTIM Trigger to START ADC Conversion
LL_HRTIM_ConfigADCTrig(HRTIM1, LL_HRTIM_ADCTRIG_1, LL_HRTIM_ADCTRIG_UPDATE_MASTER, LL_HRTIM_ADCTRIG_SRC13_MPER);
LL_HRTIM_SetADCPostScaler(HRTIM1, LL_HRTIM_ADCTRIG_1, 20);
While, on the ADC side, it should be:
// Setup ADC1 as the master ADC:
// - Receive the start of conversion from the HRTIM MASTER TRG1
// - Setup the Scan sequence length, default is disabled.
// - Disable sequencer discontinuity.
// - Setup the Regular Conversion Mode in Single Conversion per Trigger
ADC_REG_InitStruct.TriggerSource = LL_ADC_REG_TRIG_EXT_HRTIM_TRG1;
ADC_REG_InitStruct.SequencerLength = LL_ADC_REG_SEQ_SCAN_DISABLE;
ADC_REG_InitStruct.SequencerDiscont = LL_ADC_REG_SEQ_DISCONT_DISABLE;
ADC_REG_InitStruct.ContinuousMode = LL_ADC_REG_CONV_SINGLE;
ADC_REG_InitStruct.DMATransfer = LL_ADC_REG_DMA_TRANSFER_UNLIMITED;
ADC_REG_InitStruct.Overrun = LL_ADC_REG_OVR_DATA_OVERWRITTEN;
LL_ADC_REG_Init(ADC1, &ADC_REG_InitStruct);
LL_ADC_SetGainCompensation(ADC1, 0);
LL_ADC_SetOverSamplingScope(ADC1, LL_ADC_OVS_DISABLE);
Right now the code is working, generating Center-Aligned PWM signals on Channels A,C,E,F and also acquiring ADC in dual synchronous mode with successful DMA transfer (when used with SOFTWARE trigger).... I really cannot understand what's missing from my configuration.
I've also analysed the B-G474E-DPOW1 Application Demo code (that use HRTIM ADC Trigger) and, apart from using HAL, it really seem the same. Maybe I miss an enable somewhere?
Thank you in advance for any help,
Davide
Solved! Go to Solution.
2022-02-03 05:53 AM
Hello Davide,
I developed a short test code to check your use case. Initially I got the same behavior because I forgot to call LL_ADC_REG_StartConversion(ADC1) after the HRTIM1/ADC1 initialization step.
Now I get something working as expected. You'll find attached a zip file containing the source code I used to investigate this point (+ IAR project config.). I ran this code on a MB1428 board.
Le me know whether or not it helps.
regards,
François
2022-01-25 12:51 PM
I've still haven't found a solution to the HRTIM ADC Trigger, but I've managed a workaround in calling the LL_ADC_REG_StartConversion inside TIMER B HRTIM_TIMB_IRQn_IRQHandler.
TIMER B is a dedicated UP-COUNTING timer, with CMP1 configured at 50% DutyCycle.
The workaround is functional, but not optimal, even if the TIMER B is "statically configured" the IRQ does not latch with a constant period, sometime pulses are skipped (TIMER B CMP1 is the only and highest IRQ).
Here follows the TIMER B init code:
// > HRTIM Channel B Configuration Block (ADC SW Trigger)
// Time Base Settings:
LL_HRTIM_TIM_SetPrescaler(HRTIM1, LL_HRTIM_TIMER_B, LL_HRTIM_PRESCALERRATIO_MUL8);
LL_HRTIM_TIM_SetPeriod(HRTIM1, LL_HRTIM_TIMER_B, iInverter_PWM_Level);
LL_HRTIM_TIM_SetRepetition(HRTIM1, LL_HRTIM_TIMER_B, 0x00);
// Time Base Settings:
// The Timer is set in Up-Down Center-Aligned Mode. It's event generation IP is
// configured in "crest" mode (events are generated when counter reach period value).
// By now only the master timer PER event is used, slave event are just configured.
LL_HRTIM_TIM_SetCountingMode(HRTIM1, LL_HRTIM_TIMER_B, LL_HRTIM_COUNTING_MODE_UP);
LL_HRTIM_TIM_SetRollOverMode(HRTIM1, LL_HRTIM_TIMER_B, LL_HRTIM_ROLLOVER_MODE_PER);
LL_HRTIM_TIM_SetFaultEventRollOverMode(HRTIM1, LL_HRTIM_TIMER_B, LL_HRTIM_ROLLOVER_MODE_PER);
LL_HRTIM_TIM_SetBMRollOverMode(HRTIM1, LL_HRTIM_TIMER_B, LL_HRTIM_ROLLOVER_MODE_PER);
LL_HRTIM_TIM_SetADCRollOverMode(HRTIM1, LL_HRTIM_TIMER_B, LL_HRTIM_ROLLOVER_MODE_PER);
LL_HRTIM_TIM_SetOutputRollOverMode(HRTIM1, LL_HRTIM_TIMER_B, LL_HRTIM_ROLLOVER_MODE_PER);
// Time Base Settings:
// Counter in Free-Run (Continuous Mode)
LL_HRTIM_TIM_SetCounterMode(HRTIM1, LL_HRTIM_TIMER_B, LL_HRTIM_MODE_CONTINUOUS);
// Timing Unit:
LL_HRTIM_TIM_SetInterleavedMode(HRTIM1, LL_HRTIM_TIMER_B, LL_HRTIM_INTERLEAVED_MODE_DISABLED);
LL_HRTIM_TIM_DisableHalfMode(HRTIM1, LL_HRTIM_TIMER_B);
LL_HRTIM_TIM_DisableStartOnSync(HRTIM1, LL_HRTIM_TIMER_B);
LL_HRTIM_TIM_DisableResetOnSync(HRTIM1, LL_HRTIM_TIMER_B);
LL_HRTIM_TIM_SetDACTrig(HRTIM1, LL_HRTIM_TIMER_B, LL_HRTIM_DACTRIG_NONE);
LL_HRTIM_TIM_DisablePreload(HRTIM1, LL_HRTIM_TIMER_B); // Must be disabled as CNT1 is used.
LL_HRTIM_TIM_SetUpdateGating(HRTIM1, LL_HRTIM_TIMER_B, LL_HRTIM_UPDATEGATING_INDEPENDENT);
LL_HRTIM_TIM_SetBurstModeOption(HRTIM1, LL_HRTIM_TIMER_B, LL_HRTIM_BURSTMODE_MAINTAINCLOCK);
LL_HRTIM_TIM_DisablePushPullMode(HRTIM1, LL_HRTIM_TIMER_B);
LL_HRTIM_TIM_SetUpdateTrig(HRTIM1, LL_HRTIM_TIMER_B, u32_HRTIM_UpdateTrig);
LL_HRTIM_TIM_DisableResyncUpdate(HRTIM1, LL_HRTIM_TIMER_B);
LL_HRTIM_TIM_SetResetTrig(HRTIM1, LL_HRTIM_TIMER_B, u32_HRTIM_ResetTrig);
// Compare Unit 1:
// Duty is set to 50% FIXED, as this is for ADC Trigger Generation
LL_HRTIM_TIM_SetComp1Mode(HRTIM1, LL_HRTIM_TIMER_B, u32_HRTIM_SetComp1Mode);
LL_HRTIM_TIM_SetCompare1(HRTIM1, LL_HRTIM_TIMER_B, (iInverter_PWM_Level>>1));
// Wait for configuration applied
while(LL_HRTIM_IsActiveFlag_DLLRDY(HRTIM1) == RESET){};
// Enable TIMERB CMP1 interrupt */
LL_HRTIM_EnableIT_CMP1(HRTIM1, LL_HRTIM_TIMER_B );
NVIC_EnableIRQ( HRTIM1_TIMB_IRQn );
NVIC_SetPriority( HRTIM1_TIMB_IRQn, 0 );
The ISR code to manage TIMERB CMP1, toggle of a pin (simulating ADC Triggering):
void HRTIM_TIMB_IRQn_IRQHandler (void) { //HRTIM_Master_IRQn_IRQHandler( void ){
// Code must check for a specific enabled flag
if( LL_HRTIM_IsActiveFlag_CMP1( HRTIM1, LL_HRTIM_TIMER_B ) == 1 ){
LL_HRTIM_ClearFlag_CMP1( HRTIM1, LL_HRTIM_TIMER_B );
vGpioAPI_Toggle(xGpioAPI_XMI_GPIO2);
}
}
Here follows the scope acquisitions of the issue, highlighted in red:
2022-01-28 07:33 AM
2022-02-03 01:26 AM
Dear @Francois VILMAIN ,
Thank you for your answer.
I've tried to replicate the configuration you've suggested but I still get an erroneous behaviour of the HRTIM peripheral.
That's my minima init of HRTIM, that results in the same Common & Master register configuration as indicated in your register snapshot.
HRTIM1->sMasterRegs.MCR |= 0x2001000B;
HRTIM1->sMasterRegs.MDIER |= 0x00000010;
HRTIM1->sMasterRegs.MCNTR = 0x00000000;
HRTIM1->sMasterRegs.MPER = 2*iInverter_PWM_Level;
HRTIM1->sMasterRegs.MCMP1R = iInverter_PWM_Level;
// a) CMP1 Tentative
LL_HRTIM_ConfigADCTrig(HRTIM1, LL_HRTIM_ADCTRIG_1, LL_HRTIM_ADCTRIG_UPDATE_MASTER, LL_HRTIM_ADCTRIG_SRC13_MCMP1);
// b) MPER Tentative
//LL_HRTIM_ConfigADCTrig(HRTIM1, LL_HRTIM_ADCTRIG_1, LL_HRTIM_ADCTRIG_UPDATE_MASTER, LL_HRTIM_ADCTRIG_SRC13_MPER);
// Postascaler
LL_HRTIM_SetADCPostScaler(HRTIM1, LL_HRTIM_ADCTRIG_1, 20);
On the ADC Side, EXTSE bits have the right pattern [10101], EXTEN have rising edge [01].
That is done by the following instructions:
// Enable the ADC external trigger
LL_ADC_REG_SetTriggerSource( ADC1, LL_ADC_REG_TRIG_EXT_HRTIM_TRG1 );
LL_ADC_REG_SetTriggerEdge(ADC1, LL_ADC_REG_TRIG_EXT_RISING);
If, instead of External, I configure the ADC to use the Software Trigger with "LL_ADC_REG_SetTriggerSource( ADC1, LL_ADC_REG_TRIG_SOFTWARE )", the acquisition pattern starts and complete without issue.
I believe my problem is that the HRTIM is not generating the TRG1 but I really cannot understand the reason. Attached you can find my registers snapshot: maybe you can spot the elephant in the room.
Thank you,
Davide
2022-02-03 05:53 AM
Hello Davide,
I developed a short test code to check your use case. Initially I got the same behavior because I forgot to call LL_ADC_REG_StartConversion(ADC1) after the HRTIM1/ADC1 initialization step.
Now I get something working as expected. You'll find attached a zip file containing the source code I used to investigate this point (+ IAR project config.). I ran this code on a MB1428 board.
Le me know whether or not it helps.
regards,
François
2022-02-04 05:16 AM
Dear @Francois VILMAIN ,
And that's the missing piece!
Coming from F4s I've always used LL_ADC_REG_StartConversionExtTrig( ADC1, ExternalTrigger). Not seeing the function inside the library I've thought that it was not necessary anymore, but of course it is.
Regards,
Davide