cancel
Showing results for 
Search instead for 
Did you mean: 

pwm duty cycle measurement for 0% duty cycle

saurabhkore
Associate II

I am working on STM32L476RG mcu for duty cycle measurement of PWM signal. I share my code with you. it working fine but when i switch off pwm input coded stuck there and it shows previous reading .when i again given input then it measure the duty cycle correctly. so my question is that why code stuck at 0% duty cycle or when no PWM input provide to it. please check my code and share any solution .

 

 

void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
   if (htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1) // If the interrupt is triggered by channel 1
   {
      // Read the IC value
      ICValue = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1);
      if (ICValue != 0)
      {
      // calculate the Duty Cycle
      Duty = (HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_2) *100)/ICValue;
      Frequency = 90000000/ICValue;
      }
   }

}

Int main(void)
{
  HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_1);
  HAL_TIM_IC_Start(&htim2, TIM_CHANNEL_2);

  while(1)
  {

  }
}

 

 

11 REPLIES 11

If there are no edges in the input signal, there are no captures and thus no interrupts either. You have to work around it as an exception.

One way to do it would be to have a periodic interrupt - either using the same interrupt or other - with a period longer than the longest expected PWM input period. In the periodic interrupt you set a (volatile) flag, and in the capture interrupt you clear it. If upon entering the periodic interrupt again you find out that the flag was not cleared, that means that there was no capture interrupt, and that would mean zero PWM duty cycle.

JW

As @waclawek.jan says, 0% duty cycle isn't really PWM at all - there is no modulation - it's just steady-state OFF.

Similarly for 100% - that's just steady-state ON.

 

Please see the Posting Tips for how to properly post source code:

https://community.st.com/t5/community-guidelines/how-to-write-your-question-to-maximize-your-chances-to-find-a/ta-p/575228

@SofLit has edited it for you)

thankyou sir,

According to you're suggestion i implement one more timer but it is still stuck at 0% input. please check my code once.

volatile uint32_t ICValue = 0; // To store the input capture value
volatile uint32_t Duty = 0; // To store duty cycle
volatile uint32_t Frequency = 0; // To store frequency
volatile uint8_t pwmCapturedFlag = 0; // Flag to check if PWM capture interrupt was triggered
volatile uint8_t zeroDutyCycleFlag = 0; // Flag for zero duty cycle detection

// Capture callback for PWM input signal (TIM2 Channel 1)
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
if (htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1) // If interrupt triggered by channel 1
{
// Read the IC value (PWM period)
ICValue = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1);

if (ICValue != 0) // If the period is non-zero
{
// Calculate the duty cycle based on captured values
Duty = (HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_2) * 100) / ICValue;
Frequency = 90000000 / ICValue; // Assuming clock speed of 90 MHz
}

// Clear the pwmCapturedFlag (PWM interrupt was triggered)
pwmCapturedFlag = 0;
}
}

// Periodic interrupt (TIM3 interrupt, e.g., every 1 ms)
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if (htim->Instance == TIM3) // Check if the interrupt is from TIM3
{
// Check if pwmCapturedFlag is still set, indicating no PWM capture interrupt occurred
if (pwmCapturedFlag == 1)
{
// No capture interrupt occurred, so the duty cycle is 0%
zeroDutyCycleFlag = 1;
Duty = 0; // Zero duty cycle detected
}
else
{
zeroDutyCycleFlag = 0; // Normal duty cycle
}

// Set the pwmCapturedFlag to indicate that the periodic interrupt occurred
pwmCapturedFlag = 1; // The next period is waiting for capture
}
}

int main(void)
{
// Initialize peripherals, HAL, and timers
HAL_Init();

// Start input capture interrupt for PWM signal (TIM2 Channel 1)
HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_1);

// Start the regular timer for the second channel (TIM2 Channel 2)
HAL_TIM_IC_Start(&htim2, TIM_CHANNEL_2);

// Start a periodic timer (TIM3, for example, for 1ms interrupt)
HAL_TIM_Base_Start_IT(&htim3); // TIM3 as periodic interrupt

while(1)
{
// Here, you can process or use the Duty and Frequency values
if (zeroDutyCycleFlag == 1)
{
// Zero duty cycle detected, you can take action here
}
else
{
// Non-zero duty cycle detected, use the duty and frequency values
}
}
}

 


@saurabhkore wrote:

i implement one more timer but it is still stuck at 0% input. }


So why have you marked this as solved?

To unmark it, see: https://community.st.com/t5/community-guidelines/help-others-to-solve-their-issues/ta-p/575256#:~:text=If%20you%20accidentally%20chose%20the%20wrong%20post%20as%20solution%2C%20you%20can%20always%20revert%20this%20action%20by%20clicking%20%22Not%20the%20Solution%22

 

Please see the Posting Tips for how to properly post source code:

https://community.st.com/t5/community-guidelines/how-to-write-your-question-to-maximize-your-chances-to-find-a/ta-p/575228

 


@saurabhkore wrote:

please check my code once.


Have you checked it ?

What testing/debugging have you done to see what's happening?

sorry sir, i am new here. next time i will improve my posts.

Thankyou.

> it is still stuck at 0% input

What does it mean, exactly? Where is it stuck?

JW

saurabhkore
Associate II

sir i simplify my statements.

here we are try to measure duty cycle of pwm signal .existing code successfully measure the correct duty cycle but once pwm input is zero or duty cycle is zero ,in this case in live expression of cube ide it shows duty cycle value is previous one ,and it show that value only means stuck there. if i again given pwm input then again it measure proper value. i mention example with following sequence.

pwm input duty cycle=49.88%

measure duty cycle by stm=48.99%

pwm input duty cycle=0%

measure duty cycle by stm=48.99%

pwm input duty cycle=55%

measure duty cycle by stm=55%

pwm input duty cycle=0%

measure duty cycle by stm=55%

In short i am fail to measure or fail to capture 0% duty cycle.

 

So did you follow @waclawek.jan's suggestion - the first reply in this thread - to have a timer to detect the "no edges seen" case?

yes sir.