cancel
Showing results for 
Search instead for 
Did you mean: 

How to fade PWM without Delay?

xpp07
Senior

I have L432KC nucleo. I’ve set Timer 1 for PWM generation. I’m controlling the duty cycle via the CCR register. When increasing o decreasing the duty cycle, I want it to be slow. It works with a for loop and delay. But HAL_Delay prevents from doing another thing in the loop. Is there another way of doing this?

8 REPLIES 8
T J
Lead

can you show your code ?

you could set a flag to decrease in steps...

you could set the PWM timer over flow interrupt ON

and if the flag is set decrement/increment the PWM dutyCycle if your conditions are right...

Alan Chambers
Associate II

Perhaps use a second timer to manage the duty cycle. So TIM1 does PWM at 10kHz (say), and TIM2 changes the duty at 100Hz (say). Fewer interrupts that way, but at the cost of a timer. I generally use a software timer implementation based around SysTick for this sort of thing.

xpp07
Senior

This is what I have: two functions, one to go up and another to fade out.

The problem is I don't want to use HAL_Delay, as I can't do anything else until the for loop is done.

void ramp_down(){
 
	int real_dutyCycle = 8*command_dutyC;
	for (int fadeValue = actual_dutyC;fadeValue == real_dutyCycle;fadeValue -= 1) {
			    		htim1.Instance->CCR1=fadeValue;
			    	    // wait for 30 milliseconds to see the dimming effect
			    	    HAL_Delay(30);
	}
	actual_dutyC = real_dutyCycle;
}
 
void ramp_up(){
 
	int real_dutyCycle = 8*command_dutyC;
	for (int fadeValue = actual_dutyC;fadeValue == real_dutyCycle;fadeValue += 1) {
			    		htim1.Instance->CCR1=fadeValue;
			    	    // wait for 30 milliseconds to see the dimming effect
			    	    HAL_Delay(30);
	}
actual_dutyC = real_dutyCycle;
}

T J
Lead

Yes, you need a state machine, easy enough..

are you running RTOS ?

I use a single thread and check all my state machines every mS

In your case you would initialise the CCR1 in Start_Ramp_Down();

htim1.Instance->CCR1=fadeValue;

and then set a flag like this...

set some global vars; 
 
char mSint,secondInt,seconds,minuteInt;
char resetActualDutyCycle_mS,rampingDown;
int real_dutyCycle,actual_dutyC,fadeValue;
int16_t mS;
 
in Systick(){  // add these lines
	msint = true;
	mS++;
	if(mS>=1000){
	mS=0;
	secondInt=true;
	seconds++;
	if(seconds>=60){
	seconds=0;
	minuteInt = true;
	}
}
 
void start_ramp_down(){ 
  real_dutyCycle = 8*command_dutyC;
  rampingDown = true;  
  fadeValue = actual_dutyC;
    htim1.Instance->CCR1=fadeValue;
    // wait for 30 milliseconds to see the dimming effect
    //HAL_Delay(30);
    resetActualDutyCycle_mS = 30; //mS
    CurrentDutyCycle_mS = resetActualDutyCycle_mS;
}
 
under while(1){
 
checkStateMachines();
}
 
checkStateMachines(){  //every mS
  if(msInt){		// this remains running forever
    mSint = false;
    if(rampingDown ) // state machine flag
    if(!CurrentDutyCycle_mS --){  //this checks if the 30mS is over.
      CurrentDutyCycle_mS = resetActualDutyCycle_mS;  // this resets the 30mS counter
 
      if(fadeValue > real_dutyCycle){
        fadeValue -=1;
        htim1.Instance->CCR1=fadeValue;
      }else //reached end
      {
        rampingDown = false; // this will stop the statemachine
        actual_dutyC = real_dutyCycle;
      }
 
// check other states/flags here every mS
    }
}

well that's the general idea

Jeroen3
Senior

A different approach to loops is to use a moving average filter on the PWM value.

Changing the PWM setpoint has to pass through the moving average filter, that you can make as slow as you'd like by changing the calculation interval or by cascading multiple.

https://dsp.stackexchange.com/questions/20333/how-to-implement-a-moving-average-in-c-without-a-buffer

xpp07
Senior

Thank you. I'm not running RTOS actually. I will review your ideas. It would take me a while to get it working as I'm not a software-oriented guy.

Put the code in the TIM update interrupt, rather than waiting.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
xpp07
Senior

Do you mean setting another timer interrupt and put the code in it?