2024-12-03
04:09 AM
- last edited on
2024-12-03
07:06 AM
by
Maxime_MARCHETT
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)
{
}
}
Solved! Go to Solution.
2024-12-04 03:11 AM
What I suggest is to add a flag as volatile unit8_t dutyCycleData = 0 ; make it 1 when you get a new calculation time, copy the duty cycle value to a volatile variable say back_dutycycle. Read the backed duty cycle in the while(1) loop, clear the flag. only side effect is that you may get just the previous data, which many not be that bad since the duty cycle is measured in every cycle.
2024-12-04 03:18 AM - edited 2024-12-04 03:18 AM
And it's still getting "stuck" with that addition?
So what debugging have you done to see what's happening?
Is your "no edges" timer ever triggering?
Please re-post the code legibly.
2024-12-09 02:30 AM
sir i am trying to implement you're suggestion but i am unable to do it. can you edit your suggestion in code or can you share any data, document regarding to that.
2024-12-09 03:19 AM
I can't help you more than give the suggestion above.
JW
2024-12-09 11:58 PM
hii sir ,as per youre suggestion i implement my code.
#include "stm32l4xx_hal.h"
// Global variables
volatile uint32_t t1 = 0, t2 = 0; // Captured timer values
volatile float duty_c = 0; // Calculated duty cycle
volatile uint32_t timeout_flag = 0; // Timeout flag
uint32_t timeout_threshold_ms = 500; // Timeout threshold in milliseconds
TIM_HandleTypeDef htim2; // Timer 2 handle
// Function prototypes
void SystemClock_Config(void);
void Error_Handler(void);
void TIM2_Init(void);
void handle_signal_loss(void);
int main(void) {
HAL_Init();
SystemClock_Config();
// Initialize Timer 2 for input capture
TIM2_Init();
// Start input capture for both channels
HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_1); // Rising edge
HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_2); // Falling edge
while (1) {
if (timeout_flag) {
timeout_flag = 0; // Reset the flag
handle_signal_loss();
}
// Main application logic
}
}
// Timer 2 initialization
void TIM2_Init(void) {
__HAL_RCC_TIM2_CLK_ENABLE();
TIM_IC_InitTypeDef sConfigIC;
htim2.Instance = TIM2;
htim2.Init.Prescaler = 79; // Timer clock = 1 MHz (assuming 80 MHz system clock)
htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
htim2.Init.Period = 0xFFFF; // Maximum count value
htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
HAL_TIM_IC_Init(&htim2);
// Configure Channel 1 for rising edge detection
sConfigIC.ICPolarity = TIM_ICPOLARITY_RISING;
sConfigIC.ICSelection = TIM_ICSELECTION_DIRECTTI;
sConfigIC.ICPrescaler = TIM_ICPSC_DIV1;
sConfigIC.ICFilter = 0;
HAL_TIM_IC_ConfigChannel(&htim2, &sConfigIC, TIM_CHANNEL_1);
// Configure Channel 2 for falling edge detection
sConfigIC.ICPolarity = TIM_ICPOLARITY_FALLING;
HAL_TIM_IC_ConfigChannel(&htim2, &sConfigIC, TIM_CHANNEL_2);
}
// Input capture callback
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim) {
static uint32_t last_edge_time = 0;
if (htim->Instance == TIM2) {
if (htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1) {
// Rising edge captured: Period start
t1 = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1);
if (t1 != 0) {
t2 = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_2); // Falling edge captured
duty_c = ((float)t2 / t1) * 100.0; // Calculate duty cycle
// Reset the timeout mechanism
__HAL_TIM_SET_COUNTER(&htim2, 0);
timeout_flag = 0;
last_edge_time = HAL_GetTick(); // Update last active time
}
}
}
}
// Timer overflow callback (timeout detection)
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
if (htim->Instance == TIM2) {
// Check for timeout condition
if ((HAL_GetTick() - last_edge_time) > timeout_threshold_ms) {
timeout_flag = 1; // Set the timeout flag
}
}
}
// Handle signal loss
void handle_signal_loss(void) {
printf("Signal lost! Timeout occurred.\n");
// Handle signal loss condition here (e.g., reset variables, trigger an error state)
duty_c = 0;
}
// System clock configuration (implement as needed for your MCU)
void SystemClock_Config(void) {
// Configure system clock here (use CubeMX for guidance)
}
// Error handler
void Error_Handler(void) {
while (1) {
// Stay here for debugging
}
}
sir but still it not work.as per my knowledge for the measurement of duty cycle we totally relies on capture callback function ,and this function only trigger when edge is detected in input. For 0 and 100% duty cycle there are no edges therefore this function never activated and measure the duty cycle. I guess when we gives 0% or 100% duty cycle mcu go in hang mode therefore it is not able to measure 0% or 100% duty cycle. suggest any other solution sir.
Thankyou.
2024-12-10 01:47 AM
@saurabhkore wrote:this function only trigger when edge is detected in input. For 0 and 100% duty cycle there are no edges therefore this function never activated and measure the duty cycle. .
Exactly - that's why you need a separate timer that times-out when there are no edges.
2024-12-10 02:43 AM
sir can you tell me where we implement this timer inside capture callback function or outside somewhere. because if we implement this timer inside the capture call back then defiantly it will not allow to another timer to execute it work.
because condition is very straight forward ,if there is edge means capture callback is active and we get output else all things are hanged.
2024-12-10 03:01 AM
Think of it like a "Watchdog" timer: each time you get a capture callback, you restart the "watchdog".
Therefore it will only time-out after there have been no capture callbacks for the timeout time.
2024-12-10 03:45 AM - edited 2024-12-10 03:47 AM
The idea is that you set the pwm variable to be set to zero when no edge is detected. You can either reset it to zero in your main or in your timer2. How are you going to use this pwm value? Is it going to be used for display or some other purpose. If you do the resetting using timer2, I feel you have to re-trigger every time an edge is detected, so that it will be in sync. So my suggestion is to reset the pwm value to zero, after you copy it to another variable. You can set a flag, newData, when you get edge and reset in main.
2024-12-10 05:45 AM
I don't use Cube/HAL, but in the above code - which to me looks to be AI-generated - I don't see how the Update interrupt to be enabled.
Also, there would need to be some mechanism to reset the timeout-timer (which in this case is apparently the same TIM2), maybe using Reset mode of the slave-mode controller, as in the "PWM input" described in RM.
JW