interrupt routine acting weird STM32F103C8 - Page 1
Forum section: electronics / beginners

author: haseeb zaib
author_rank: Contributor
timestamp: November 09, 2021, 05:28:13 am
content: Hello everyone I am trying to create precise delays using Timer in stm32f103C8. The only problem is,when I use timer in interrupt mode, the processor just never leaves the interrupt routine, even the main loop does not work for some reason, but If I use timer without interrupt mode and try to generate delay it works fine.My timer specificationClock at 72Mhzprescalar 0period 71from formula I am getting 1MHZ which equals to 1Usso interrupt fire at every 1Us, this makes delay calculation easy, now to both of the codes using interrupt routine and without itthe only problem which I can think of is that the interrupt is firing so often that nothing else could even execute. I have not tried by increasing the prescalar value and setting period to something to give me 1Mhz but will give it a try. I can make same stuff in baremetal without using HAL(most shittest lib I have ever seen for a beginner) but I don't want to lose functionality of HAL as I don't want to always initialize gpio clock using registers and with registers the interrupt service routine works as intended. I think so the problem is that interrupt is firing just to frequently.IDE STM32CUBEIDECode://with interrupt routineint main(void){/* USER CODE BEGIN 1 *//* USER CODE END 1 *//* MCU Configuration--------------------------------------------------------*//* Reset of all peripherals, Initializes the Flash interface and the Systick. */HAL_Init();/* USER CODE BEGIN Init *//* USER CODE END Init *//* Configure the system clock */SystemClock_Config();/* USER CODE BEGIN SysInit *//* USER CODE END SysInit *//* Initialize all configured peripherals */MX_GPIO_Init();MX_TIM4_Init();/* USER CODE BEGIN 2 *///HAL_TIM_Base_Start(&htim4);/* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1){/* USER CODE END WHILE */printf("HELLO WORLD");dMs(10000);/* USER CODE BEGIN 3 */}/* USER CODE END 3 */}void dUs(int uS){HAL_TIM_Base_Start(&htim4);systicks = 0;while(systicks <uS){// HAL_TIM_Base_Start_IT(&htim4);}HAL_TIM_Base_Stop(&htim4);}void dMs(int mS){HAL_TIM_Base_Start_IT(&htim4);systicks = 0;while(systicks <(mS * 1000)){// HAL_TIM_Base_Start_IT(&htim4);}HAL_TIM_Base_Stop_IT(&htim4);}void HAL_TIM_PeriodElapsedCallback (TIM_HandleTypeDef * htim){systicks++;printf("systicks =%d\n\r",systicks);//printf(systicks);//TIM4->SR &= ~TIM_SR_UIF;}Code://without interrupt this works fine//timer overflows every 1uS//Prescalar = 0//period = 71//clock = 72Mhz//required freq = 72Mhz/(prescalar+1)(period+1);// will get 1Mhz freq which equal to 1Us//this code works perfectly fine and gives proper delaysvoid dUs(int uS){//HAL_TIM_Base_Start_IT(&htim2);systicks = 0;__HAL_TIM_SET_COUNTER(&htim2,0);counter = 0;while(systicks <uS){counter = __HAL_TIM_GET_COUNTER(&htim2);systicks = systicks + counter;// HAL_TIM_Base_Start_IT(&htim4);}//HAL_TIM_Base_Stop_IT(&htim2);}void dMs(int mS)// set the counter value a 0{//HAL_TIM_Base_Start_IT(&htim2);systicks = 0;__HAL_TIM_SET_COUNTER(&htim2,0);counter = 0;while(systicks < (mS * 1000) ){counter = __HAL_TIM_GET_COUNTER(&htim2);systicks = systicks + counter;// HAL_TIM_Base_Start_IT(&htim4);}//HAL_TIM_Base_Stop_IT(&htim2);}int main(void){/* USER CODE BEGIN 1 *//* USER CODE END 1 *//* MCU Configuration--------------------------------------------------------*//* Reset of all peripherals, Initializes the Flash interface and the Systick. */HAL_Init();/* USER CODE BEGIN Init *//* USER CODE END Init *//* Configure the system clock */SystemClock_Config();/* USER CODE BEGIN SysInit *//* USER CODE END SysInit *//* Initialize all configured peripherals */MX_GPIO_Init();MX_TIM2_Init();/* USER CODE BEGIN 2 */HAL_TIM_Base_Start(&htim2);/* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1){/* USER CODE END WHILE */printf("hi haseeb\n");HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_13);dMs(1000); //delay of 1 SEC/* USER CODE BEGIN 3 */}/* USER CODE END 3 */}

author: DavidAlfa
author_rank: Super Contributor
timestamp: November 09, 2021, 09:27:14 am
content: Yes, that's exactly that.You have 72 instructions to enter the interrupt, save the context, run the interrupt code, restore the context and return.1MHz irq is insane. What are you trying to do?

author: capt bullshot
author_rank: Super Contributor
timestamp: November 09, 2021, 10:07:11 am
content: As DavidAlfa said, 1MHz interrupt rate is rather insane. Might work if you don't use the HAL callbacks but define the interrupt routine yourself, but it's very difficult (or just impossible) to keep it's execution time below 1us. With all the HAL callback layering, it's futile.Anyway, better don't use printf() within interrupt routines.

author: Doctorandus_P
author_rank: Super Contributor
timestamp: November 09, 2021, 10:26:31 am
content: I have not done much STM32 stuff (yet). If I remember well though, then ISR flags are not cleared automatically, and you have to clear them in the interrupt manually.Firing ISR's at 1MHz is indeed a bit much. You can debug your code by for example triggering it at 1kHz and do some performance measurement.But if you want to do precise timing, then don't rely on software. Use a hardware peripheral to do the timing for you.

author: DavidAlfa
author_rank: Super Contributor
timestamp: November 09, 2021, 11:28:26 am
content: HAL is not that bad. But it requires some time to understand and get used to. After that, it's actually pretty easy and well structured.The BIG problem with HAL is the stupid, useless documentation.In the end it's not a HAL: You still need to crunch every reference manual page to understand how everything works to see what HAL is doing and how to use it.I'd call it "code helper and some macros".About the HAL interrupts, you can always out your own code in the irq itself (stm32f1xx_it.c).If you know what you're doing, you can simply clear the flag and return, skipping the HAL call.Ex.:Code:void TIM2_IRQHandler(void){/* USER CODE BEGIN TIM2_IRQn 0 */__HAL_TIM_DISABLE(&htim2);__HAL_TIM_CLEAR_FLAG(&htim2,TIM_IT_UPDATE);return; // Skip HAL IRQ handler, because I know there's nothing else to do.// But this will be different when you're using DMA or other complex modes. HAL must check every combination, because it needs to work for everyone./* USER CODE END TIM2_IRQn 0 */HAL_TIM_IRQHandler(&htim2);/* USER CODE BEGIN TIM2_IRQn 1 *//* USER CODE END TIM2_IRQn 1 */}The issue is 99.99% caused by interrupt overlapping. It's triggered again before leaving.For small delays, like microseconds, don't use interrupts, instead use a function that triggers the timer and waits for it to reach the requested count.As you see, the interrupt overhead can actually make it worse compared to simple polling.If you want to keep using the interrupt, don't use 1us for the interrupt, which is crazy and terribly inefficient.This might work better: Set the timer in downcounting mode, prescaler 71 (1uS clock), load (microseconds-1) into the counter and enable the timer.When the interrupt is triggered, stop the timer to stop the interrupt happening and wasting cpu power.That way the interrupt happens only once, after the desired time, and stops there.Ex. for 10uS, set the counter to 9. The timer will do 9,8...1,0,(Interrupt). You'll be avoiding the silly 1us interrupts.The downside is that you can ony run one delay at once, contrary to running the timer at 1MHz and decreasing some counters, which provide virtually unlimited delays.In any case, using interrupts will add delay to the desired timing, polling will be more accurate.Code:void delay_us(uin16_t us){__HAL_TIM_SET_COUNTER(&htim2, us-1);__HAL_TIM_ENABLE(&htim2); // Now the timer is running. The interrupt will happen after the specified time is elapsed}void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim){ // Interrupt callbackif(htim==&htim2){ // Check it's our delay timer__HAL_TIM_DISABLE(&htim2);__HAL_TIM_CLEAR_FLAG(&htim2, TIM_IT_UPDATE);do_whatever_after_time_is_done();}}

author: haseeb zaib
author_rank: Contributor
timestamp: November 09, 2021, 02:04:11 pm
content: Quote from: DavidAlfa on November 09, 2021, 11:28:26 amI agree its not that bad but documentation is just so bad, there are so many commands which I cant even find in documentation for some reason or they are just some where else and that confuses me so much about HAL.

author: haseeb zaib
author_rank: Contributor
timestamp: November 09, 2021, 02:07:40 pm
content: Yes guys the issue was firing interrupt at 1MHz speed, I knew from the start that it was insane, but I said it would work fine because when ever I need to execute delay command only then I will activate the interrupt and after it finished, I could deactivate it, but the interrupt was firing so quick it did not even do that.Well I am now looking into systick delay and DWT. I also came to know that there is systick command which works similar to arduino millis.