Sonsivri
 
*
Welcome, Guest. Please login or register.
Did you miss your activation email?
November 27, 2024, 01:57:11 13:57


Login with username, password and session length


Pages: [1]
Print
Author Topic: Output compare mode question - STM32  (Read 10803 times)
0 Members and 1 Guest are viewing this topic.
metal
Global Moderator
Hero Member
*****
Offline Offline

Posts: 2420

Thank You
-Given: 862
-Receive: 678


Top Topic Starter


« on: January 21, 2017, 12:44:02 12:44 »

I need to run TIM1 in output compare mode as follows:
- Slave mode: RESET
- Trigger source: T1_ED, polarity rising
- Clock source: Internal clock
- OC Output: CH2

My questions:

1. Once the trigger input detects a rising edge, the timer counter should start counting, when it reaches the compare value, what really happens to the timer counter, does it keep counting till it overflows and then starts again from zero, does the timer counter stop without losing current value waiting till the next trigger where in this case it doesn't start from zero, or is the timer counter reset to zero waiting till the next trigger?

2. I assume that counter period should be set to the max interval required, might be set to the same value as the compare register value?

3. What is the effect of auto-reload enable/disable in my configuration?

4. What is the forced mode, I can't understand what is meant by "regardless of the counter value the output channel can be set/reset by software"?

5. What is the effect of using ETR as clearing source?

thanks a lot
« Last Edit: January 21, 2017, 01:36:57 13:36 by metal » Logged
mars01
V.I.P
Hero Member
*****
Offline Offline

Posts: 537

Thank You
-Given: 697
-Receive: 1774



« Reply #1 on: January 21, 2017, 09:04:09 21:04 »

Reading this may help: https://trix.io/output-compare-on-stm32/
Also, Section 2.6 in this app note: http://www.st.com/content/ccc/resource/technical/document/application_note/54/0f/67/eb/47/34/45/40/DM00042534.pdf/files/DM00042534.pdf/jcr:content/translations/en.DM00042534.pdf
Logged
metal
Global Moderator
Hero Member
*****
Offline Offline

Posts: 2420

Thank You
-Given: 862
-Receive: 678


Top Topic Starter


« Reply #2 on: January 22, 2017, 04:25:09 04:25 »

thanks, it was helpful.

How can I read the prescaler and auto reload register values using HAL?
Also, if I wanted to change prescaler and ARR, should I have to go through the timer init process again, is ther a way to make it faster?
Logged
mars01
V.I.P
Hero Member
*****
Offline Offline

Posts: 537

Thank You
-Given: 697
-Receive: 1774



« Reply #3 on: January 22, 2017, 10:09:36 10:09 »

It seems that the counter, autoreload and prescaler registers can be read and written by software anytime, even when the counter is running.
You read the prescaler register into a variable like any other register...

I think those two documents will shed more light on the issue:

http://www.st.com/content/ccc/resource/technical/document/application_note/group0/91/01/84/3f/7c/67/41/3f/DM00236305/files/DM00236305.pdf/jcr:content/translations/en.DM00236305.pdf

and

http://visualgdb.com/tutorials/arm/stm32/timers/hal/

LE: You can read this also:
http://www.k-space.org/Class_Info/STM32_Lec5.pdf

BTW, VisualGDB seems like a nice VisualStudio plugin ... Smiley
« Last Edit: January 22, 2017, 10:16:54 10:16 by mars01 » Logged
metal
Global Moderator
Hero Member
*****
Offline Offline

Posts: 2420

Thank You
-Given: 862
-Receive: 678


Top Topic Starter


« Reply #4 on: January 23, 2017, 02:27:38 02:27 »

I see, then I must play the old fashion:

TIM1->ARR = 0xyyyy;
TIM1->CCR2 = 0xzzzz;

in order to change the delay at which the pulse occurs and the pulse width which is equal to ARR-CCR2, in my case channel 2 of OC for TIM1.

thanks!
Logged
metal
Global Moderator
Hero Member
*****
Offline Offline

Posts: 2420

Thank You
-Given: 862
-Receive: 678


Top Topic Starter


« Reply #5 on: January 23, 2017, 03:51:49 03:51 »

BTW, why does HAL_TIM_PWM_PulseFinishedCallback fires two times, one at the pulse start and one at the pulse end, how can I differentiate between the two states of the pulse?
Logged
mars01
V.I.P
Hero Member
*****
Offline Offline

Posts: 537

Thank You
-Given: 697
-Receive: 1774



« Reply #6 on: January 23, 2017, 04:53:45 04:53 »

Others say that it is fired everytime something happen with Capture / Compare.
Not much in the manual here: http://www.st.com/content/ccc/resource/technical/document/user_manual/72/52/cc/53/05/e3/4c/98/DM00154093.pdf/files/DM00154093.pdf/jcr:content/translations/en.DM00154093.pdf

I guess you will have to look into the implementation of the function...
Actually, what do you want to do?

LE: the Interrupt handler, you can see that the function get called at every output compare event ... Inside the called function you will have to check for the event that interest you, evaluate the register bits to get more information.

Code:
void HAL_TIM_IRQHandler(TIM_HandleTypeDef *htim)
2771 {
2772  /* Capture compare 1 event */
2773  if(__HAL_TIM_GET_FLAG(htim, TIM_FLAG_CC1) != RESET)
2774  {
2775    if(__HAL_TIM_GET_IT_SOURCE(htim, TIM_IT_CC1) !=RESET)
2776    {
2777      {
2778        __HAL_TIM_CLEAR_IT(htim, TIM_IT_CC1);
2779        htim->Channel = HAL_TIM_ACTIVE_CHANNEL_1;
2780
2781        /* Input capture event */
2782        if((htim->Instance->CCMR1 & TIM_CCMR1_CC1S) != 0x00)
2783        {
2784          HAL_TIM_IC_CaptureCallback(htim);
2785        }
2786        /* Output compare event */
2787        else
2788        {
2789          HAL_TIM_OC_DelayElapsedCallback(htim);
2790          HAL_TIM_PWM_PulseFinishedCallback(htim);
2791        }
2792        htim->Channel = HAL_TIM_ACTIVE_CHANNEL_CLEARED;
2793      }
2794    }
2795  }
2796  /* Capture compare 2 event */
2797  if(__HAL_TIM_GET_FLAG(htim, TIM_FLAG_CC2) != RESET)
2798  {
2799    if(__HAL_TIM_GET_IT_SOURCE(htim, TIM_IT_CC2) !=RESET)
2800    {
2801      __HAL_TIM_CLEAR_IT(htim, TIM_IT_CC2);
2802      htim->Channel = HAL_TIM_ACTIVE_CHANNEL_2;
2803      /* Input capture event */
2804      if((htim->Instance->CCMR1 & TIM_CCMR1_CC2S) != 0x00)
2805      {
2806        HAL_TIM_IC_CaptureCallback(htim);
2807      }
2808      /* Output compare event */
2809      else
2810      {
2811        HAL_TIM_OC_DelayElapsedCallback(htim);
2812        HAL_TIM_PWM_PulseFinishedCallback(htim);
2813      }
2814      htim->Channel = HAL_TIM_ACTIVE_CHANNEL_CLEARED;
2815    }
2816  }
2817  /* Capture compare 3 event */
2818  if(__HAL_TIM_GET_FLAG(htim, TIM_FLAG_CC3) != RESET)
2819  {
2820    if(__HAL_TIM_GET_IT_SOURCE(htim, TIM_IT_CC3) !=RESET)
2821    {
2822      __HAL_TIM_CLEAR_IT(htim, TIM_IT_CC3);
2823      htim->Channel = HAL_TIM_ACTIVE_CHANNEL_3;
2824      /* Input capture event */
2825      if((htim->Instance->CCMR2 & TIM_CCMR2_CC3S) != 0x00)
2826      {
2827        HAL_TIM_IC_CaptureCallback(htim);
2828      }
2829      /* Output compare event */
2830      else
2831      {
2832        HAL_TIM_OC_DelayElapsedCallback(htim);
2833        HAL_TIM_PWM_PulseFinishedCallback(htim);
2834      }
2835      htim->Channel = HAL_TIM_ACTIVE_CHANNEL_CLEARED;
2836    }
2837  }
2838  /* Capture compare 4 event */
2839  if(__HAL_TIM_GET_FLAG(htim, TIM_FLAG_CC4) != RESET)
2840  {
2841    if(__HAL_TIM_GET_IT_SOURCE(htim, TIM_IT_CC4) !=RESET)
2842    {
2843      __HAL_TIM_CLEAR_IT(htim, TIM_IT_CC4);
2844      htim->Channel = HAL_TIM_ACTIVE_CHANNEL_4;
2845      /* Input capture event */
2846      if((htim->Instance->CCMR2 & TIM_CCMR2_CC4S) != 0x00)
2847      {
2848        HAL_TIM_IC_CaptureCallback(htim);
2849      }
2850      /* [b]Output compare event[/b] */
2851      else
2852      {
2853        HAL_TIM_OC_DelayElapsedCallback(htim);
2854        HAL_TIM_PWM_PulseFinishedCallback(htim);
2855      }
2856      htim->Channel = HAL_TIM_ACTIVE_CHANNEL_CLEARED;
2857    }
2858  }
2859  /* TIM Update event */
2860  if(__HAL_TIM_GET_FLAG(htim, TIM_FLAG_UPDATE) != RESET)
2861  {
2862    if(__HAL_TIM_GET_IT_SOURCE(htim, TIM_IT_UPDATE) !=RESET)
2863    {
2864      __HAL_TIM_CLEAR_IT(htim, TIM_IT_UPDATE);
2865      HAL_TIM_PeriodElapsedCallback(htim);
2866    }
2867  }
2868  /* TIM Break input event */
2869  if(__HAL_TIM_GET_FLAG(htim, TIM_FLAG_BREAK) != RESET)
2870  {
2871    if(__HAL_TIM_GET_IT_SOURCE(htim, TIM_IT_BREAK) !=RESET)
2872    {
2873      __HAL_TIM_CLEAR_IT(htim, TIM_IT_BREAK);
2874      HAL_TIMEx_BreakCallback(htim);
2875    }
2876  }
2877
2878    /* TIM Break input event */
2879  if(__HAL_TIM_GET_FLAG(htim, TIM_FLAG_BREAK2) != RESET)
2880  {
2881    if(__HAL_TIM_GET_IT_SOURCE(htim, TIM_IT_BREAK) !=RESET)
2882    {
2883      __HAL_TIM_CLEAR_IT(htim, TIM_IT_BREAK);
2884      HAL_TIMEx_BreakCallback(htim);
2885    }
2886  }
2887
2888  /* TIM Trigger detection event */
2889  if(__HAL_TIM_GET_FLAG(htim, TIM_FLAG_TRIGGER) != RESET)
2890  {
2891    if(__HAL_TIM_GET_IT_SOURCE(htim, TIM_IT_TRIGGER) !=RESET)
2892    {
2893      __HAL_TIM_CLEAR_IT(htim, TIM_IT_TRIGGER);
2894      HAL_TIM_TriggerCallback(htim);
2895    }
2896  }
2897  /* TIM commutation event */
2898  if(__HAL_TIM_GET_FLAG(htim, TIM_FLAG_COM) != RESET)
2899  {
2900    if(__HAL_TIM_GET_IT_SOURCE(htim, TIM_IT_COM) !=RESET)
2901    {
2902      __HAL_TIM_CLEAR_IT(htim, TIM_FLAG_COM);
2903      HAL_TIMEx_CommutationCallback(htim);
2904    }
2905  }
2906 }
2907
« Last Edit: January 23, 2017, 05:15:47 05:15 by mars01 » Logged
metal
Global Moderator
Hero Member
*****
Offline Offline

Posts: 2420

Thank You
-Given: 862
-Receive: 678


Top Topic Starter


« Reply #7 on: January 24, 2017, 08:21:17 08:21 »

The reason it calls HAL_TIM_PWM_PulseFinishedCallback twice is that CC1 and CC2 are both causing capture compare interrupt to fire when I trace in the interrupt handler. Inside the callback, if I check for either CC1 or CC2, both will be valid, my mistake might be that I have been checking only for (__HAL_TIM_GET_IT_SOURCE(htim, TIM_IT_CC1) !=RESET) and (__HAL_TIM_GET_IT_SOURCE(htim, TIM_IT_CC1) !=RESET) without paying attention to the flags (__HAL_TIM_GET_FLAG(htim, TIM_FLAG_CC1) != RESET) and (__HAL_TIM_GET_FLAG(htim, TIM_FLAG_CC2) != RESET), may be this explains why __HAL_TIM_GET_IT_SOURCE is always true for CC1 and CC2. Today I will check for the flags as well, following the interrupt handler method and see if I can catch CC2 only, and for one time.. The annoying thing I can speak about is that only CC2 is enabled, why does CC1 cause an interrupt to fire, is simply unknown for me.. I traced the code, and saw that CC2 is enabled.. i must dig more to see why CC1 is enabled..
Logged
metal
Global Moderator
Hero Member
*****
Offline Offline

Posts: 2420

Thank You
-Given: 862
-Receive: 678


Top Topic Starter


« Reply #8 on: January 25, 2017, 05:35:59 17:35 »

The correct way of filtering interrupts correctly appears to be this way:

When looking at the way interrupt is checked
Code:
  /* Capture compare 2 event */
  if(__HAL_TIM_GET_FLAG(htim, TIM_FLAG_CC2) != RESET)
  {
    if(__HAL_TIM_GET_IT_SOURCE(htim, TIM_IT_CC2) !=RESET)
    {
      __HAL_TIM_CLEAR_IT(htim, TIM_IT_CC2);
      htim->Channel = HAL_TIM_ACTIVE_CHANNEL_2;
      /* Input capture event */
      if((htim->Instance->CCMR1 & TIM_CCMR1_CC2S) != 0x00U)
      {
        HAL_TIM_IC_CaptureCallback(htim);
      }
      /* Output compare event */
      else
      {
        HAL_TIM_OC_DelayElapsedCallback(htim);
        HAL_TIM_PWM_PulseFinishedCallback(htim);
      }
      htim->Channel = HAL_TIM_ACTIVE_CHANNEL_CLEARED;
    }
  }

Two important lines are
Code:
      __HAL_TIM_CLEAR_IT(htim, TIM_IT_CC2);
      htim->Channel = HAL_TIM_ACTIVE_CHANNEL_2;

this indicates that in our code we can never use
Code:
if(__HAL_TIM_GET_FLAG(htim, TIM_FLAG_CC2) != RESET)
because interrupt has been already cleared by
Code:
__HAL_TIM_CLEAR_IT(htim, TIM_IT_CC2);

Why? Looking at __HAL_TIM_GET_FLAG and __HAL_TIM_CLEAR_IT
Code:
#define __HAL_TIM_GET_FLAG(__HANDLE__, __FLAG__)          (((__HANDLE__)->Instance->SR &(__FLAG__)) == (__FLAG__))
and
Code:
#define __HAL_TIM_CLEAR_IT(__HANDLE__, __INTERRUPT__)     ((__HANDLE__)->Instance->SR = ~(__INTERRUPT__))
 in other words the bit in SR register is cleared already by the time our code reaches the callback function.. in my case the flag is TIM_IT_CC2..

So, the correct way to do it is like this:

Code:
/* USER CODE BEGIN 4 */
void HAL_TIM_PWM_PulseFinishedCallback(TIM_HandleTypeDef *htim)
{
static uint8_t flag = 0;
if( htim->Instance == TIM1 && htim->Channel == HAL_TIM_ACTIVE_CHANNEL_2 )
  {
if(__HAL_TIM_GET_IT_SOURCE(htim, TIM_IT_CC2) != RESET)
{
if (__HAL_TIM_GET_AUTORELOAD(htim) == 25000)
__HAL_TIM_SET_AUTORELOAD(htim, 55000);
else
__HAL_TIM_SET_AUTORELOAD(htim, 25000);
}
}
}
/* USER CODE END 4 */

It is important to use HAL_TIM_ACTIVE_CHANNEL_2 as a flag to detect the interrupt rather than using TIM_IT_CC2 IF in SR.. the weird thing is that __HAL_TIM_GET_IT_SOURCE checks if the interrupt is enabled in TIMx_DIER ..! So, I am not really sure if I should be using if(__HAL_TIM_GET_IT_SOURCE(htim, TIM_IT_CC2) != RESET) or not..

BTW, answering some of my own questions:

ARR or period in HAL language can be read/set using __HAL_TIM_GET_AUTORELOAD/__HAL_TIM_SET_AUTORELOAD

Pulse can be  read/set using __HAL_TIM_GET_COMPARE/__HAL_TIM_SET_COMPARE

but the actual pulse length is (ARR-CCRx) i.e. (period - Pulse)..

I still don't understand why CC1 OC gets fired...
« Last Edit: January 25, 2017, 05:47:15 17:47 by metal » Logged
metal
Global Moderator
Hero Member
*****
Offline Offline

Posts: 2420

Thank You
-Given: 862
-Receive: 678


Top Topic Starter


« Reply #9 on: January 26, 2017, 10:30:40 22:30 »

Actually, what do you want to do?

A dimmer. The approach of IC and PWM mode 1 is not stable (the one explained in mastering STM32), rather the trigger mode with TI1FP1 and PWM mode 2 is better plus I 've also seen mE doing it this way i.e. trigger and PWM2 Ex 9, though not using HAL madness.

What I am thinking about is when I want to change the intensity, I must change both ARR and CCR2, but when is the right time to do it? after pulse has started, finished? Zero-crossing thing triggers the timer to start counting, should I disable to the timer during that half where I change ARR and CCR2 values?

cubemx project is attached..
« Last Edit: January 26, 2017, 10:34:24 22:34 by metal » Logged
Buddy
Junior Member
**
 Warned
Offline Offline

Posts: 48

Thank You
-Given: 7
-Receive: 19


« Reply #10 on: January 27, 2017, 05:43:02 05:43 »

Metal, I suggest you to use Matlab to generate the code for you. It's easier.
Logged
metal
Global Moderator
Hero Member
*****
Offline Offline

Posts: 2420

Thank You
-Given: 862
-Receive: 678


Top Topic Starter


« Reply #11 on: January 27, 2017, 09:34:53 09:34 »

I did not know that matlab can do that, I also don't know how to use matlab :S
it is not about easier or more difficult, is it the same idea as flowcode? I mean adding blocks and suddenly seeing the code being generated?
Logged
Pages: [1]
Print
Jump to:  


DISCLAIMER
WE DONT HOST ANY ILLEGAL FILES ON THE SERVER
USE CONTACT US TO REPORT ILLEGAL FILES
ADMINISTRATORS CANNOT BE HELD RESPONSIBLE FOR USERS POSTS AND LINKS

... Copyright © 2003-2999 Sonsivri.to ...
Powered by SMF 1.1.18 | SMF © 2006-2009, Simple Machines LLC | HarzeM Dilber MC