Go Down

Topic: Adjust TIMER ICRn & OCRnx without glitch after the change? (Read 118 times) previous topic - next topic

gabenix

Hello all, I have Arduino code that uses timer 1 in "PWM Phase Correct Mode" to generate a random frequency.

I am having issues after the ICR & OCR registers are changed - there is often a brief glitch when OCR1A/B are not set properly at the beginning of the new cycle. I imagine the problem has something to do with the overflow or interrupt flags not being updated. To overcome this, I have used a short delay before turning on the outputs in order to "wait out" the glitch, however I'd rather not use a delay. I know this can be overcome by properly resetting the correct registers, I just do not know how to reset them.

Any help would be greatly appreciated. See code below:

Code: [Select]
unsigned long previousMillis = 0;
int active = false;
int pulseTime = 100;
int periodTime = 200;

void setup() {
  pinMode(9,0);
  pinMode(10,0);

  TCCR1A = 0;
  TCCR1B = 0;
  TCNT1 = 0;
  TCCR1A |= _BV(COM1A1) | _BV(COM1A0);
  TCCR1A |= _BV(COM1B1);
  TCCR1A |= _BV(WGM11);
  TCCR1B |= _BV(WGM13);
  TCCR1B |= _BV(CS10);
}

void loop() {
  unsigned long currentMillis = millis();
  if ( active == false ){
    if (currentMillis - previousMillis < pulseTime) {
      active = true;
      ICR1 = random(150, 300); // 26.6KHz to 53KHz
      OCR1A = floor( ICR1 * .55 );
      OCR1B = floor( ICR1 * .45 );
      delay(5);
      pinMode(9,1);
      pinMode(10,1);
    }
    else if ( currentMillis - previousMillis > periodTime ){  previousMillis = currentMillis; }
  }
  else if ( active == true && currentMillis - previousMillis >= pulseTime ) {
      active = false;
      OCR1A = ICR1;
      OCR1B = 0;
      pinMode(9,0);
      pinMode(10,0);
  }
}

johnwasser

So you are using WGM Mode 10.  TOP is in ICR1 and the OCR1x registers update when the timer reaches TOP.  You should probably calculate the new TOP first, then set OCR1A and OCR1B, and then set ICR1.

I don't know what your are trying to do with those pinMode() calls but I suspect it's not doing what you intended.

What are the two waveforms supposed to look like?  I can't quite figure out your three timers.

You probably don't need floor() since the register is an integer and the float values will get truncated.
Send Bitcoin tips to: 1G2qoGwMRXx8az71DVP1E81jShxtbSh5Hp

gabenix

Thank you for the response John! Turning off pin 9 & 10 outputs via pinMode is what I'm having to do to overcome the effect of the glitch - the problem I want to resolve. The signal is used to drive a center-tapped flyback transformer - if I do not turn the pins off, the circuit will experience a brief short during the glitch from both OCRA & OCRB signals being high simultaneously ( when ICR/OCRx  registers are changed ) - this short temporarily overloads the circuit drawing several amps of power and placing a large strain on the components, albeit ever so brief. Turning the pins off for at least 5ms is a fix for the problem.

I've tried several combinations of manipulating OCRx ICR registers to remedy the problem including the order they are done (ICR last) and have not been able to fix the problem - in fact, changing OCRx values prior to changing the ICR value (assuming the next ICR value will be significantly higher or lower from the prior) tends to exacerbate the problem. There must be some other registers that can be reset so that the timer and flags all reset and begin again from a null zero state...?

gabenix

I could try the below order of operations:

OCR1B = 0; // The bottom is constant so we know this will always be OFF given any ICR value.
OCR1A = newOCR1A;
ICR1 = newICR1;
OCR1B = newOCR1B;

However I feel like I've already tried this as well, but perhaps not. I believe this solution may still have an issue if the flag is not reset depending on where within the previous count these changes occur with respect to the extent/significance of the change in ICR1..?

johnwasser

OK.  So what are the two waveforms supposed to look like?

Note: When you use pinMode() you should use the named modes: INPUT, OUTPUT, or INPUT_PULLUP.  Using numbers like 0 and 1 makes it hard to understand the purpose of the pinMode() call. 
Send Bitcoin tips to: 1G2qoGwMRXx8az71DVP1E81jShxtbSh5Hp

gabenix

Hey John, OCR1A and OCR1B are 180 degrees out of phase and together create a 90% duty-cycle (45% per channel) alternating signal allowing for 10% dead-time per transition when both outputs are brought low to avoid hardware switching delays and shoot-through. please see the below attached drawing I created for you to visualize the output waveform.

[EDIT added after original post] I would like to add that I do not technically have a situation where shoot-through is the problem persay - the issue is that immediately after the values/registers are changed, one of the outputs is high for too long a time thereby over-saturating the transformer and permitting excess current to short to ground through the transformer.[END EDIT]


cattledog

Have you tried changing the timer values (ICR1,OCR1A,OCR1B) in either a TIMER1_CAPT_vect (called when ICR1 is matched at TOP) or in an TIMER1_OVF_vect which I think is set at BOTTOM.?

Have you tried mode 8 (phase and frequency correct) as well as mode 10?

gabenix

Have you tried changing the timer values (ICR1,OCR1A,OCR1B) in either a TIMER1_CAPT_vect (called when ICR1 is matched at TOP) or in an TIMER1_OVF_vect which I think is set at BOTTOM.?

Have you tried mode 8 (phase and frequency correct) as well as mode 10?
G'day Aussie dog! I have not attempted either method, but both seem to have promise - perhaps more-so when combined together. I will not be able to test these for a few days, however I will provide an update with results when I can. Thanks!

Go Up