How to sync PWM and PID calculation

I have a logic that controls the input of a RC speed controller, for this I use a Fast PWM on the Baby-O

	TCCR1A = (1<<COM1A1) | (0<<COM1A0) | (1<<WGM11); // clear OC1A on compare, fast pwm 10 bit (mode14)
	TCCR1B = (1<<WGM13) | (1<<WGM12) | (1<<CS11); // CS11 prescaler 8 
	ICR1 = 50000; //native pwm 20 ms = 50 Hz frequency Prescaler 8 Freq 50 = 20.000.000 / 8 * 50 = 50.000
	OCR1A = 2400; // At start we send out 0.9 ms, motor is off

When my logic reads some sensors and decides to change the motor rpm it changed the OCR1A value

        OCR1A = (2400 + more);

The logic does not match the frequency of the pwm output, if it changes the value of OCR1A when the pwm pulse is being sent it needs 20 ms to deliver the new value to the speed controller and if it is just before there is no time delay.

I want to sync the PID calculation and the PWM output adjustment, the calculation is faster than 20 ms, can I use an interrupt on TIMER1 COMPB to trigger the calculation, in this way I can have my results available just before the next pwm is sent to the RC speed controller.

Can this work next to a PWM

ISR(TIMER1_COMPB_vect) { dopid = 1; }

in main I will loop the calculation with a statement

if (dopid == 1) { calculatie_all; dopid = 0; }
And the set OCR1B high enough to have the OCR1A value available just before the ICR value is reached


Your plan seems reasonable. Don’t forget to declare dopid as volatile, so the ISR can modify it . If you are not familiar with the volatile variable qualifier, you can read more about it here.

- Jeremy

True, if you forget the volatile definition it will not run.

My logic does two things, calculate the PID value and log the information on a logomatic V2 data logger. So the plan is to start the calculation as late as possible and log everything in the waiting period.

For test I will replace one of the logging values with the TCNT1 value taken just after calculation, in that way I can see where my calculation ended.

The application is running as expected. Now I want to optimise the starting moment of the calculation.

At the beginning and end of the calculation I save the time

      if (dopid ==1)
      startcalc = TCNT1;
      // followed by te calculation
      endcalc = TCNT1;

The calculation duration is endcalc - startcalc

The result is sent to a serial out so I can read the number. Every 25 calculations two results are unreadable, I guess I should stop the timer before saving the timer value, and restart.

What is the best way to stop and start a timer?

Could you post an example of the output your are getting? How are you sending the Serial data? Could you post your entire code? (You might try simplifying code by removing irrelevant parts to the issue.)

- Jeremy

I found an easier way to compare the timing of the pwm and COMPB by using the SLO-scope

The pwm pulse created with the OCR1A setting is 1-2ms on a repeat frequency of 20ms, this becomes channel A

The COMPB triggers the dopid cycle which runs ok. In the calculation I bring a pin high before executing the calculation and low at the end of the calculation. this becomes channel B. Now I can see both pulses in the SLO-scope. Adjusting the OCR1B value allows me to shift the calculation closer to the start of the pwm pulse.

This visual adjustment is good enough as calculation and pwm are now synchronised and the gap approx 1ms is a lot better than the 1 to 18ms random gap I have now.

The calculation takes place very fast compared to the 2ms pulse out from the controller. I added a 1ms delay to the calculation to make it visible in the SLO scope. The output line of the calculation is input B and attached to a buzzer, therefore the signal is a bit noisy.

With an ICR value of 50.000, OCR1A of 5000 and an OCR1B value of 45000 the calculation is ready in time to write the new OCR1A value before the pwm is sent out. This makes the response a lot quicker.