2018-02-01 12:37 AM
Hi,
I'm working on STM32F215 and I generate a PWM output on TIM1. This signal is going to an other device.
For synchronization purposes on this signal, I would like to get the rising and falling edge of it.
My first thought is to link the PWM ouptut directly to a EXTI pin in order to get my edges interrupt.
I just begin working withTimerbut I'm just there is a simple way to get those PWM informations.
Could you please help me with a code example/interrupt configuration ?
Thank you very much,
Marc
#interrput #tim-pwm #stm32f2 Note: this post was migrated and contained many threaded conversations, some content may be missing.Solved! Go to Solution.
2018-02-01 06:28 AM
Drill into the HAL_TIM_PWM_Start_IT method.
You'll see it sets the Compare event interrupt with;
__HAL_TIM_ENABLE_IT(htim, TIM_IT_CCx);
Directly after your Start IT call, add the following to also enable the Update event;
__HAL_TIM_ENABLE_IT(htim, TIM_IT_UPDATE);
in your case, based on your code sample, it would look like;
HAL_TIM_PWM_Start_IT(&_t_HTIM1, TIM_CHANNEL_3)
__HAL_TIM_ENABLE_IT(&_t_HTIM1, TIM_IT_UPDATE);
If you are using a CubeMX generated project,
you have to check both interrupts
the interrupts can be handled in
TIM1_UP_TIM10_IRQHandler(void) for the update event
TIM1_CC_IRQHandler(void) for the compare event
or you can provide your own own handlers for the weak methods;
void HAL_TIM_PWM_PulseFinishedCallback(TIM_HandleTypeDef *htim) for the compare event
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) for the update event
If you are using count UP, active HIGH polarity;
Update event is rising edge, state is HIGH in handler
Compare event is falling edge, state is LOW in handler
Note, if you were using another timer, say TIM2,
There would only be one global interrupt checkbox in cubemx,
The global handler would be;
TIM2_IRQHandler
and the your implementations of;
void HAL_TIM_PWM_PulseFinishedCallback(TIM_HandleTypeDef *htim) for the compare event
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) for the update event
would be common to all your compare and update interrupt enabled timers.
2018-02-01 01:25 AM
Rising and falling edge of PWM corresponds to Update and Compare events. Depending on PWM mode and output polarity setting which one is which. So you simply enable interrupt from Update and respective Compare in TIMx_DIER, and then in the ISR you check in TIMx_SR which one of them has happened (for TIM1 particularly, there are separate interrupt vectors for update and for the captures, so you don't need to distinguish them in the ISR).
JW
2018-02-01 06:28 AM
Drill into the HAL_TIM_PWM_Start_IT method.
You'll see it sets the Compare event interrupt with;
__HAL_TIM_ENABLE_IT(htim, TIM_IT_CCx);
Directly after your Start IT call, add the following to also enable the Update event;
__HAL_TIM_ENABLE_IT(htim, TIM_IT_UPDATE);
in your case, based on your code sample, it would look like;
HAL_TIM_PWM_Start_IT(&_t_HTIM1, TIM_CHANNEL_3)
__HAL_TIM_ENABLE_IT(&_t_HTIM1, TIM_IT_UPDATE);
If you are using a CubeMX generated project,
you have to check both interrupts
the interrupts can be handled in
TIM1_UP_TIM10_IRQHandler(void) for the update event
TIM1_CC_IRQHandler(void) for the compare event
or you can provide your own own handlers for the weak methods;
void HAL_TIM_PWM_PulseFinishedCallback(TIM_HandleTypeDef *htim) for the compare event
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) for the update event
If you are using count UP, active HIGH polarity;
Update event is rising edge, state is HIGH in handler
Compare event is falling edge, state is LOW in handler
Note, if you were using another timer, say TIM2,
There would only be one global interrupt checkbox in cubemx,
The global handler would be;
TIM2_IRQHandler
and the your implementations of;
void HAL_TIM_PWM_PulseFinishedCallback(TIM_HandleTypeDef *htim) for the compare event
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) for the update event
would be common to all your compare and update interrupt enabled timers.
2018-02-01 06:50 AM
Hi,
Thank you for your answer!
My code is based on the STM Cube generated code.
Ok, so I enabled TIM1_UP_TIM10_IRQn and TIM1_CC_IRQn in the dedicated MSP function.
This is my OC configuration :
__t_ConfigOC.OCMode = TIM_OCMODE_PWM1;
__t_ConfigOC.Pulse = 63; // default 6.3ms __t_ConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH; __t_ConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH; __t_ConfigOC.OCFastMode = TIM_OCFAST_DISABLE; __t_ConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET; __t_ConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET;I start the PWM using HAL_TIM_PWM_Start_IT(&_t_HTIM1, TIM_CHANNEL_3) function.
I go to the CC Handler but not into the Update Handler. Do I miss something?
Thank you,
Marc
2018-02-01 07:02 AM
I don't use Cube. Have you set both interrupt enable bits in TIMx_DIER?
JW
2018-02-01 07:04 AM
OCiREF xor OCiP is the signal you need. OCiP (polarity) is readily available. OCiREF is not but can be extracted from the counter value and match point.
Not difficult at all if you can take a look at the datasheet.
edit:
I wrote this little piece to test out the concept above:
//reset TIM3OC3's state
//timer: upcounting
char OC3_get(TIM_TypeDef *TIMx) {
int tmp = TIMx->CNT < TIMx->CCR3; //1 if CNTR < CCR3
switch (TIMx->CCMR2 & TIM_CCMR2_OC3M) {
//0b110->PWM mode 1: OC3REF active if CNTR < CCR3
case TIM_CCMR2_OC3M_2 | TIM_CCMR2_OC3M_1 | 0x00: tmp = !tmp; break; //do nothing (positive logic)
//0b111->PWM mode 2: OC3REF active if CNTR > CCR3
case TIM_CCMR2_OC3M_2 | TIM_CCMR2_OC3M_1 | TIM_CCMR2_OC3M_0: tmp = tmp; break; //negative logic
default: break; //should list out all other cases
}
return (TIMx->CCER & TIM_CCER_CC3P)?tmp:!tmp;
}
In the mains loop, I had this:
if (TIM3OC3_get()) IO_SET(LEDG_PORT, LEDG); else IO_CLR(LEDG_PORT, LEDG); //if OC3 is high, set LEDG, otherwise, clear it
The TIM3OC3 was set up to output a PWM waveform, to be replicated on LEDG.
When ran on STM32F100RB, the code does precisely what it was supposed to.
Note: 1) as shown in OC3_get(), I didn't list out all cases. 2) the logic becomes slightly more complex is deadtime management is activated. 3) the code doesn't rely on anything other than the device header file so it should run under any libraries.
2018-02-01 08:16 AM
Both interrupts can be handled with the global
TIM1_IRQHandler
AFAIK there's no such.
(for TIM1 particularly, there are separate interrupt vectors for update and for the captures, so you don't need to distinguish them in the ISR)
JW
2018-02-01 08:20 AM
Hi John!
Thank you very much.
I see now in the 'HAL_TIM_PWM_Start_IT' function, it enables only CCx.
The 'HAL_TIM_Base_Start_IT' function performes the __HAL_TIM_ENABLE_IT(htim, TIM_IT_UPDATE);
I get into both interrupts now.
Thank you guys,
Marc2018-02-01 08:38 AM
If he generated the project with CubeMX, and enabled the TIM1 global interrupt there is!
he would have a handler like this;
void TIM1_IRQHandler(void)
{ /* USER CODE BEGIN TIM2_IRQn 0 *//* USER CODE END TIM2_IRQn 0 */
HAL_TIM_IRQHandler(&htim1); /* USER CODE BEGIN TIM2_IRQn 1 *//* USER CODE END TIM2_IRQn 1 */
}It calls HAL_TIM_IRQHandler(&htim1);
which then calls the event specific handlers;
void HAL_TIM_PWM_PulseFinishedCallback(TIM_HandleTypeDef *htim)
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
2018-02-01 08:44 AM
Does CubeMX generate also the vector table source?
JW