328p timer pwm trouble

I need to arbitrarily set a pin high for a given time using timers on a 328p, but am having trouble doing so. I am trying to create a PWM signal, that is synchronized with my main loop, but has accurate timing and is non-blocking.

I am trying to achieve this for example on pin 9 (OC1A, PB1) by using timer 1 in normal mode (since this only clears my pin if COM1A1 is set). Then when it is time to output the pulse (simulated by delay() in this case), I would set pin 9 to HIGH and reset the timer (TCNT1) to 0 to restart the timer, so it automatically clears my pin when it is time.

void setup() {
  //using pin 9, OC1A, PB1
  DDRB |= _BV(1);  // set to output
  //clear pin on compare match, normal mode, 8th prescaler
  TCCR1A = B10000000;
  TCCR1B = B00000010;
  OCR1A = 2000;  //output compare value (1ms in this case with 8th prescaler for 16MHz)
}

void loop() {
  delay(9);
  PORTB |= _BV(1);  //set pin
  TCNT1 = 0;        //reset timer
}

However with this code my pin is always LOW and never gets set. As an experiment I setup TCCR1A to toggle my pin and that works as expected, so the timers are working. Why does my pin never gets set in loop()?

Synchronised in the sense of whenever your main loop is in a certain line of code then the PWM-pin should change from LOW to HIGH exactly in that moment?
or
synchronised in the sense of enabling / disabling creating = switching on/off the PWM-signal at a certain line of code of your main-loop but it doesn't matter if the PWM-signal is already HIGH or LOW in this moment?

PWM at what frequency?

accurate timing
precise and synchronised down the the nano-second? or what would be the minimum precision needed so that you call in "synchronised"?

If you describe in detail the project as a whole it will become easier to answer your questions

At least a timing diagram that shows what IO-pins hsould habe what logic level at which time and how are the multiple IO-pin-states timely related to each other would help to understand what you want to do

best regards Stefan

Your first statement. I am building a flight controller and would like to output the motor PWM signals immediately after the PID calculations are done.
It should have a resolution of at least 8 bits (or higher) and would be nice if I could achieve this without CPU intervention, i.e. with peripherals.

There is no reason to synchronize in that manner. If there are no delays/blocking code the loop will spin maybe thousands of times a second so even without any form of synching changes in the PID will be enacted in PWM within microseconds.
Synching the way you are talking about will only cause issues because the speed of the loop() is never accurate or consistent.

There definitely is. If I use the servo library (or regular pwm generation), the response of the copter is much more sluggish and harder to tune. I now have an implementation which does what I want to achieve, but with blocking code.
The PID loop is synchronized to when the IMU has new data available.

I figured it out. If I have pins configured for PWM (i.e. the Compare Output Mode is not 0), I cannot set and clear pins with the Data Register.

The solution is to briefly set the Compare Output Mode to set the pin, force a compare output using Control Register C and then reset the Compare Output Mode to clear the pin.

So this code creates a 1ms pulse every time the delay() is over in loop(), just what I needed.

void setup() {
  //using pin 9, OC1A, PB1
  DDRB |= _BV(1);  // set to output
  //compare output mode to Clear, normal mode, 8th prescaler
  TCCR1A = _BV(COM1A1);
  TCCR1B = _BV(CS11);
  OCR1A = 2000;  //output compare value (1ms in this case with 8th prescaler)
}

void loop() {
  delay(9);
  TCCR1A = _BV(COM1A1) | _BV(COM1A0);  //set compare output mode to Set
  TCNT1 = 0;                           //reset timer
  TCCR1C = _BV(FOC1A);                 //force output compare
  TCCR1A = _BV(COM1A1);                //set compare output mode to Clear
}

The MPU remains blocked for 9 ms which is no good.

Thx mate :sweat_smile:

So, means are to be explored to achieve your objective waveform without blocking the MCU.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.