Skip to main content
SWenn.1
Senior III
December 31, 2022
Solved

stm32l476 nucleo board --- experimenting with output compare timer 3 channel 1??

  • December 31, 2022
  • 14 replies
  • 3879 views

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:

  1. I had to code the macro (see below) bcz CubeMx doesn't seem to check the UIE bit when setting up as compare output.....Can anyone comment as to why?
__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:

  1. I notice with breakpoints set neither the macro nor the call after it clear the UIF flag....Why is this??(I have attached pic below showing enables or IRQs set and flags set
  2. I never get into the CC1 portion of the interrupt...any thoughts as to why?? as the expression solves to a '1'
  3. Where do I find the various priorities of the flags that can cause an interrupt in TIMER3?? is the UIE higher priority than the CCxE?
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
			}
 
		}
	}
}

0693W00000Y7AAaQAN.png

This topic has been closed for replies.
Best answer by waclawek.jan

> 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

14 replies

SWenn.1
SWenn.1Author
Senior III
January 3, 2023

Thank you very much for the insight! I really appreciate it.....What I cannot get my head around is that first I am doing nothing else (no other peripherals other than the serial wire debug) is being done....Nothing configured and while loop is empty....My system clock has been slowed to 20MHz....I don't see how it is possible that going into an interrupt reading a counter (bare metal) and adding 1000 clock cycles wouldn't be slow enough for the processor to accurately do...I can do this all day in an MSP430 and never miss a beat at 20MHz...I purposely slowed things down and enlarged the count value to test this.

There must be something that can guarantee exact timing?? This would be absolutely useless if you wanted to take consistent continuous A/Ds for FFT work........

I have no other interrupts in the system.....Is there a way to push up my priority (my understanding is 0 is the highest) or increase CCR1 OVER UID?.....

 HAL_NVIC_SetPriority(TIM3_IRQn, 0, 0);

SWenn.1
SWenn.1Author
Senior III
January 3, 2023

As you suggested earlier CCR > ARR....

below code is getting me closer....still a little jitter

void TIM3_IRQHandler(void)
{
 /* USER CODE BEGIN TIM3_IRQn 0 */
	/*check update IRQ flag*/
	if (htim3.Instance->SR & TIM_SR_CC1IF)
	{
		
		uint32_t temp = htim3.Instance->CNT;
 
		htim3.Instance->SR = ~TIM_SR_CC1IF;
 
		if (temp + 1000 > htim3.Instance->ARR)
			htim3.Instance->CCR1 = htim3.Instance->ARR - temp + 1000;
		else
			htim3.Instance->CCR1 = htim3.Instance->CNT + 1000;
 
		HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5);
	}

waclawek.jan
Super User
January 3, 2023

> uint32_t temp = htim3.Instance->CNT;

Note, that you are still basing your calculation on the CNT, which is counting thus subject to interrupt latency plus execution time from ISR beginning to the point of readout. If you measure precisely, you'll see distance between edges somewhat larger than 1000 counts, maybe 1050 or so.

For precise calculation you would need to advance the CCRx, so it changes as 1000-2000-3000 etc.

Also a minor correction at the rollover: note, that after ARR comes 0, so you want your formula for the (tmp + 1000) > ARR to be (tmp + 1000 - ARR - 1).

JW

SWenn.1
SWenn.1Author
Senior III
January 3, 2023

The real trick here I realized is that in the MSP world I traditionally let the counter roll over at max count in which case when a value is added to CCR if it is larger than 16 bits it just wraps around nicely and all is well. I am sure if I placed a max count on the counter in the MSP world I would have the same issue. In STM world with higher clocks and 32 bit registers I guess I was thinking of limiting the max count.