2022-12-31 03:24 PM
Good afternoon everyone....
I am trying to learn more about the stm32 and am using a nucleo L476 and an oscilloscope. In particular I want to understand more about the output compares of the timers. I have read many an app-note , user guide and data sheet regarding these and am now at the stage of testing stuff out.....I am running into complete confusion with respect to this...
I have a 26MHz clock with a prescaler of 26 -1 (should be a 1MHz Cnt clock). I have the ARR register loaded with 100 - 1 (should create an UIF event every 100us). I am using CubeMX to set this up. There are a few questions:
__HAL_TIM_ENABLE_IT(&htim3, TIM_IT_UPDATE);
The following below is my ISR.....My attempt was to have UIF interrupt me every 10khz (see above comment on this), turn the output on and arm the CCR with counter + 10. My thought was that after this expires (CNTR clock is 1MHz so my expectation was 10us later) I would get a CC1R interrupt and then clear the output using FORCED_ACTIVE and INACTIVE statements. There are a few things here:
void HAL_TIM_OC_DelayElapsedCallback(TIM_HandleTypeDef *htim)
{
if (htim == &htim3)
{
if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1)
{
if (__HAL_TIM_GET_FLAG(htim, TIM_FLAG_CC1))
{
__HAL_TIM_CLEAR_FLAG(htim, TIM_IT_CC1);
htim->Instance->SR &= ~TIM_SR_CC1IF;
htim->Instance->CCR1 = 0;
htim->Instance->CCMR1 = 0; //clears mode output bits --- freezes output
htim->Instance->CCMR1 |= TIM_OCMODE_FORCED_INACTIVE; //forces output to 0??
}
else if (__HAL_TIM_GET_FLAG(htim, TIM_FLAG_UPDATE))
{
__HAL_TIM_CLEAR_FLAG(htim, TIM_IT_UPDATE); //clear UIF Flag
htim->Instance->SR &= ~TIM_SR_UIF;
htim->Instance->CCR1 = htim->Instance->CNT + 10;
htim->Instance->CCMR1 = 0; //clears mode output bits --- freezes output
htim->Instance->CCMR1 |= TIM_OCMODE_FORCED_ACTIVE; //set output to 1 immediately
}
}
}
}
Solved! Go to Solution.
2023-01-02 09:11 PM
> htim3.Instance->CCR1 = htim3.Instance->CNT + 1000;
This does not result in interrupts exactly 1000 clocks apart. CNT keeps counting after the compare happens, so the next CCR1 includes interrupt latency and execution time, so the second CCR1 will be something like 2050, the third 3100, etc.
And when CCRx>ARR, compare thus interrupt happens at Update.
JW
PS. note that if you have other, higher or same priority, interrupts in your system, interrupt latency may increase dramatically
2022-12-31 07:20 PM
Use minimal compiler optimisation code to be able to put breakpoints in most places, even use asm nop as breakpoint spots.
Try using output compare first to make a pwm, and using jumper wire, feed it to the same timer, other channel, programmed as input capture. This may help with minimal lab equipment.needed (although oscilloscope -not logic analysers- is prime debug hw tool for embedded devices)
2023-01-01 01:49 AM
To make the thing simple, get rid of HAL completely and operate on timer registers only. This way you get full control over the timer register settings and of course also reduce the number of lines in your code by at least 80%.
How do you know that the flags are not cleared? They are getting set every 100 us, so you can't notice them being cleared using the debugger. The timer is still running when you single-step.
Do not use logic operations on TIM SR for clearing the flags - this is very common error leading to events being lost.
Wrong:
htim->Instance->SR &= ~TIM_SR_UIF;
Good:
htim->Instance->SR = ~TIM_SR_UIF;
2023-01-01 03:23 AM
How do you start the timer?
You may slow down everything by a factor of say 1000 by using a different prescaler. Then you might be able to better watch events, maybe with help of printf tracing, a cheap logic analyzer at the outputs, LED blinking, and so on.
Using of HAL or register level is a matter of the learning path you prefer. Mixing both to achieve relatively simple things might add unneccessary complexity.
hth
KnarfB
2023-01-01 06:51 AM
I have breakpoints right within the ISR Callback on the line that should clear the flag. I step over this and the state of the flag doesn't clear. I've set the break on both the HAL and the register line and neither do the job.
To your point about the Wrong: Good:
Yes the &= and |= is a habit of mine....I think I am safe doing your way bcz the register in question only supports writes of 0. In MSP world I never have issues with this , would I really see issues in the STM by doing this?
2023-01-01 07:04 AM
You step over this, and the flag clears the it sets again in 100 us. You cant's see it cleared.
Using &= means "clear the selected flag and all other flags set during the execution of this statement". It's not what you want - you may write more than one 0 to the SR this way.
2023-01-01 09:06 AM
got it on the first point...thanks
Not sure how &= clears other flags....
TIM_SR_UIF = 0x0000 0001 ---> ~TIM_SR_UIF = 0xFFFF FFF7 ----> "anding" this with anything ONLY affects bit 0, which according to the document is how you clear bit 0, by writing a 0 to the flag....all other bits will stay as they are AND be unaffected. This is what you want so when you leave the ISR callback you go right back into it if another flag has been sent...Withing the callback you must have conditional if statements to catch each and every flag....am I missing something here???
For what it's worth:
I am used to doing if else statements within the ISR with each of my if/else statements checking ONLY ONE flag. That way you only have to process a short piece of code within the ISR assuming only one flag has been set (which in my experience is most always the case). In the event two flags are set it is no big deal bcz you service the first, pop out and immediately pop back in to service the second. If I were to clear all flags I would have to attend to all flags in the ISR I would have to have an IF for each flag and go thru the process independent of whether the flag was set or not which would spend processing time and keep the processor awake (ie in high power mode).....I am coming at it from a background of having products that must sleep at 3uA - 5uA (max) of power and last battery life of 8 years.
2023-01-01 10:39 AM
Please check out the following instruction, from stm32l4xx_hal_tim.h:
#define __HAL_TIM_CLEAR_IT(__HANDLE__, __INTERRUPT__) ((__HANDLE__)->Instance->SR = ~(__INTERRUPT__))
2023-01-01 09:43 PM
Sanity check : when breakpoint, the hw maybe still running. Watching timer registers will steal the code's job. Relaunch the code after breakpoint and watching timer values. Is timer frozen when breakpoint?
2023-01-02 06:07 AM
I have a SystemClk of 80MHz, an AHB1 clock of 20MHz, a TIM3 divisor of 4 and the counter period set to 500....Effectively giving me an UIF every 10kHz. I was able to get code working by deleting the HAL callback within TIM3_IRQHandler and write my own....I've written my own function within the IRQ and it is working....below is a snapshot of code (with 2 breakpoints and registers) I do have some questions....
I understand breakpoints can be tricky especially within ISR but if the IDE isn't yielding accurate results how can you troubleshoot using it??? I have the Compiler optimizations set to None and Debugger set to Maximum.