2025-02-04 07:02 AM
I am using STM32 with the following peripherals:
My setup:
When using these settings, the ADC half-complete and complete callbacks are triggered correctly, meaning ADC DMA is working. However, nothing seems to happen in the while(1) loop in main().
Could it be related to TIM7 interrupt priority, DMA behavior, or CPU being blocked?
Is the DMA transfer taking over completely, preventing execution in while(1)?
Any insights or suggestions would be greatly appreciated!
Solved! Go to Solution.
2025-02-05 01:16 AM
@BitCurious wrote:
do you mean in stm32g4xx_it.c ?
Yes. To convince you that even you comment the callbacks the interrupt still fired and the IRQ handler is executed.
But I recommend to disable the ADC NVIC config and check if you reach the while loop.
2025-02-04 07:27 AM
Hello,
May be due to the CPU load due to the interrupt timing rate and the CPU was not able to get a time slot to reach the while loop. As soon as it exits the interrupt it returns in it again. If you disable the interrupt do you reach the while(1)?
2025-02-04 07:29 AM - edited 2025-02-04 07:29 AM
30 kHz * half-complete and complete callbacks = 60k interrupts/s ?
That's alot, especially when using HAL. Try lowering the freq. generously by increasing PSC until "something happens" in the main loop. You may use the DWT cycle counter to estimate the length your code spends in the interrupts or use some logic analyzer for that.
Solved: How do you measure the execution CPU cycles for a ... - STMicroelectronics Community
hth
KnarfB
2025-02-04 10:55 PM
You could toggle different IO pins in each of the interrupt handlers. Set the IO at the start of the interrupt handler and reset it at the end of the handler - that way you can check how often the handler is called and how efficient/inefficient the code is. The BSRR is the easiest and most efficient and safest way to toggle the bits - eg.
#define RED_LED_ON GPIOB->BSRR = GPIO_BSRR_BS_14
#define RED_LED_OFF GPIOB->BSRR = GPIO_BSRR_BR_14
2025-02-04 11:25 PM
> However, nothing seems to happen in the while(1) loop in main().
What exactly you mean, i.e. what is supposed to happen there ?
You would need to share this specific code.
Many (example) applications just have a "while (1) {} " at the end of main, and all the work happens in the interrupt chain.
> Is the DMA transfer taking over completely, preventing execution in while(1)?
No, DMA cannot do that.
Once started it operates independant of the core, and can at most co-opt some bus cycles.
> Could it be related to TIM7 interrupt priority, ...
Again, I suggest to share the related interrupt code.
Careless interrupt callbacks can consume 100+% of core cycles.
2025-02-05 12:44 AM
It seems the issue is related to the timer settings. Even after commenting out the ADC half and complete callbacks, the program still doesn’t reach while(1). However, when I increase ARR or PSC, the issue is resolved.
Initially, with PSC: 3-1 & ARR: 13-1, the timer frequency was 3.85 MHz, and while(1) was unresponsive. Now, with PSC: 13-1 & ARR: 5-1, the frequency is 2.31 MHz, and the program runs normally.
Is there a specific limit or best practice when configuring timers? My goal is to generate a 30 kHz signal using DAC with 128 samples, with a 150 MHz clock and PSC: 13-1, ARR: 3-1. Should I reduce the number of points or adjust the frequency further?
2025-02-05 12:48 AM - edited 2025-02-05 12:50 AM
@BitCurious wrote:
It seems the issue is related to the timer settings. Even after commenting out the ADC half and complete callbacks
Commenting the callbacks doesn't mean the interrupt handler is not executed. Bear in mind that the callback is called from the interrupt handler and it's declared as __weak.
Put breakpoint in the ADC interrupt handler then you can confirm or disable the ADC NVIC interrupt.
2025-02-05 12:57 AM
You can reply as follows:
In while(1), I need to process ADC values (a sampled sine wave) to compute amplitude and phase shift with respect to the DAC output or input signal. This involves mathematical computations like averaging, square root calculations, etc.
The DMA is handling ADC sampling, and the ADC complete callback stores the processed values. However, when PSC: 3-1 & ARR: 13-1, the program doesn't reach while(1). If I increase ARR/PSC, it starts working.
and the callbacks I have is given below:
void HAL_ADC_ConvHalfCpltCallback(ADC_HandleTypeDef* hadc)
{
Real_Sum = 0;
Imag_Sum = 0;
for(i = 0; i< HALF_NUM_OF_SAMPLES;i++)
{
Real_Sum += (int32_t)adc_buffer[i] * Reference_Sinus[i];
Imag_Sum += (int32_t)adc_buffer[i] * Reference_Cosinus[i];
}
counter_half++;
}
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
for(i = HALF_NUM_OF_SAMPLES ; i< NUM_OF_SAMPLES;i++)
{
Real_Sum += (int32_t)adc_buffer[i] * Reference_Sinus[i];
Imag_Sum += (int32_t)adc_buffer[i] * Reference_Cosinus[i];
}
Out_Real = Real_Sum;
Out_Imag = Imag_Sum;
counter_full++;
}
2025-02-05 01:07 AM - edited 2025-02-05 01:08 AM
Does the 30 kHz signal waveform really change every period?
Do you really need the DAC for generating the waveform?
As @SofLit pointed out, better look in the stm32*_it.c file for the bare interrupt handler, comment out the call into HAL, and repeat your tests. You might want to walk away from HAL for the handler to increase the performance.
"while(1) was unresponsive" and "the program runs normally" are quite vague formulations. The main loop will run whenever no interrupt is active (the CPU is in thread mode) so you get a percentage and breaks due to interruption. This may affect your code more than just 0/1.
hth
KnarfB
2025-02-05 01:08 AM
do you mean in stm32g4xx_it.c ?
/**
* @brief Conversion complete callback in non-blocking mode.
* @PAram hadc ADC handle
* @retval None
*/
__weak void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hadc);
/* NOTE : This function should not be modified. When the callback is needed,
function HAL_ADC_ConvCpltCallback must be implemented in the user file.
*/
}
/**
* @brief Conversion DMA half-transfer callback in non-blocking mode.
* @PAram hadc ADC handle
* @retval None
*/
__weak void HAL_ADC_ConvHalfCpltCallback(ADC_HandleTypeDef *hadc)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hadc);
/* NOTE : This function should not be modified. When the callback is needed,
function HAL_ADC_ConvHalfCpltCallback must be implemented in the user file.
*/
}
I took this ADC half and complete callbacks from stm32g4xx_hal_adc.c, there it was declred as weak.
void DMA1_Channel1_IRQHandler(void)
{
/* USER CODE BEGIN DMA1_Channel1_IRQn 0 */
/* USER CODE END DMA1_Channel1_IRQn 0 */
HAL_DMA_IRQHandler(&hdma_dac1_ch1);
/* USER CODE BEGIN DMA1_Channel1_IRQn 1 */
/* USER CODE END DMA1_Channel1_IRQn 1 */
}
/**
* @brief This function handles DMA1 channel2 global interrupt.
*/
void DMA1_Channel2_IRQHandler(void)
{
/* USER CODE BEGIN DMA1_Channel2_IRQn 0 */
/* USER CODE END DMA1_Channel2_IRQn 0 */
HAL_DMA_IRQHandler(&hdma_adc1);
/* USER CODE BEGIN DMA1_Channel2_IRQn 1 */
/* USER CODE END DMA1_Channel2_IRQn 1 */
}
where should i put the breakpoint?