[SOLVED] PWM Fails when adjusting Timer 1 Pin 9 (Fast PWM ICR1 BOTTOM TOP)

Very Confusing PWM is not working when I attempt to change Timer 1

My desired mode (I Think) is:

**Mode **
**WGM13 **
**WGM12 **
**WGM11 **
**WGM10 **
Timer/Counter Mode of **Operation **
**Top **
Update of **OCR1x at **
TOV1 Flag **Set on **
7
0
1
1
1
Fast PWM, 10-Bit
0x3FF
BOTTOM
TOP

Page 132 of the Datasheet

I am attempting to set PWM to handle a specific trigger I can not use mode 8 PWM, Phase and Frequency Corrected because the start time and end time of the Pulse width is relative to the center of the pulse.
My goal is to have a fixed known end time. I am not worried about phase and frequency being correct

I am using the timer1 library Google Code Archive - Long-term storage for Google Code Project Hosting.
Documentation for the timer1 library is Found at Arduino Playground - Timer1
My Attempted change in the library to switch to mode 7:

TimerOne & PWMTimerOne::initialize(long microseconds)
{
  TCCR1A = 0;                 // clear control register A 
 // TCCR1B = _BV(WGM13);        // set mode 8: phase and frequency correct pwm, stop the timer
  TCCR1B = _BV(WGM10)|_BV(WGM11)|_BV(WGM12); //****** Changed to ******* set mode 7: Fast pwm, stop the timer
  setPeriod(microseconds);
  return *this;
}

The Basic code for testing:

#include <PWMTimerOne.h>    // http://www.arduino.cc/playground/Code/Timer1
#include "Interrupts.h"
InterruptsClass Interrupt;

volatile int Duty = 1024 * .1;
volatile int ActualPeriod = 8333;
volatile unsigned long LastTime;
volatile unsigned long TimerValue;
void SetPWM() {
  unsigned long Time = micros();
  Timer1.setPwmDuty(9, Duty);
  Timer1.setPeriod(constrain(Time - LastTime, 8300, 8400));
  Timer1.start();     //and start it up with timer at zero
  ActualPeriod = Time - LastTime;
  LastTime = Time;
  TimerValue =  Timer1.read();
  static unsigned long SpamTimer;
  if ( (unsigned long)(millis() - SpamTimer) >= (100)) {
    SpamTimer = millis();
    sei(); // re enable other interrupts at this point, so Serial Print doesn't flop
    Serial.print(ActualPeriod);
    Serial.print("\t ");
    Serial.println(TimerValue);
  }
}
void setup() {
  Serial.begin(115200);
  Serial.println("AC Phase Control Test");

  Timer1.initialize(ActualPeriod);  //AC Frequency is 8.3333 milliseconds @ 60HZ,
  //pick a period that gives you a little headroom.
  Timer1.stop();            //stop the counter
  Timer1.pwm(9, 0, ActualPeriod);//.InvertPwm(9);
  attachInterrupt(0, SetPWM,FALLING); // PWM Calibration Pulse input
}

void loop() {
  static unsigned long SpamTimer;
  if ( (unsigned long)(millis() - SpamTimer) >= (100)) {
    SpamTimer = millis();
    Duty += 10;  // Shift the Duty Cycle 
    if (Duty >= 1024) Duty = 10;
  }
}

Note the code compiles:

I need the pulse to set the start of the next PWM Sequence
My operating frequency is 120HZ US AC power
Ideally I need to PWM to be inverted so the Pulse starts low then rises somewhere in the middle set by duty cycle and drops at an exact spot set by the calibration trigger (Zero crossing circuit input on Pin2)

Currently I can calibrate the PWM but it is referenced to the center of the pulse not the edge.

What am I missing, Nothing I try generates results and I haven't found the solution yet.

  • Any documents better describing PWM Register Setup,
  • Code examples using the Fast PWM 10-bit mode 7 (any level of complexity)
  • Corrections / additions to my code if you would like
  • Any Help

Anything Please :slight_smile:

Thanks in advance

Z

Do you need to set the appropriate bits 7:4 in TCCR1A to get the output pin to toggle when the counter matches? I think you have set them all to 0.

It's a while since I wrote code to get PWM working using the registers but I don't recall having a problem - and unfortunately I cannot remember what I did it for so I can't locate my code. But I think I will need to do it for another new project.

Have you tried getting PWM to work in a short program without any library?

...R

Could it be something as simple as a missing pinMode( 9, OUTPUT) statement ?

Robin2:
Do you need to set the appropriate bits 7:4 in TCCR1A to get the output pin to toggle when the counter matches? I think you have set them all to 0.

It's a while since I wrote code to get PWM working using the registers but I don't recall having a problem - and unfortunately I cannot remember what I did it for so I can't locate my code. But I think I will need to do it for another new project.

Have you tried getting PWM to work in a short program without any library?

...R

I'm sure you are on the right track Robin2. The pin toggle part would be different for how timer1 library normally does it.
I am so green at direct timer control I'm literally reaching in throwing mud and hoping something sticks :slight_smile:
It is almost 5am here I still need a few more hours sleep to function. But anyone with additional details on pin toggle settings. Please post it. Thanks.
Z

Also an example of CTC pin toggle with Timer1 if it helps (second code sample):
http://forum.arduino.cc/index.php?topic=443343.msg3051379#msg3051379

6v6gt:
Also an example of CTC pin toggle with Timer1 if it helps (second code sample):
2 stroke ignition on atmega328 - #4 by 6v6gt - Programming Questions - Arduino Forum

Thanks for your fast reply. I'm not at my computer to test this but looking at your example it looks like this is what I may be missing:

// Toggle OC1A on Compare Match
    TCCR1A |= (1 << COM1A0);

I'm eager to try this but I must sleep first :slight_smile: or I'll self district. Or worse smoke my Arduino.
I'll read and accept all help. Also I'll post my working example. I'm sure that the other recent post on AC phase control will be highly interested in my results.
Thanks again
Z

What you're trying to accomplish seems similar to this: AC Phase Control

dlloyd:
What you're trying to accomplish seems similar to this: AC Phase Control

dlloyd Thank you! This is great and Is an excellent example. I may (and quite possibly will) end up doing this. Your link is way better than what I've been doing in the past which is why I've headed in this direction.
I am still looking to understand timers better and this discussion will help. There is tones of information of timers and interrupts but very little on using timers to fully manipulate PWM (at least to a level that I can understand without everyone's help).
Thank you and Karma to you
Z

It Works!!!!!!
My goal AC Power Phase Control using PWM rather than using timers or polling micros().
The reason is that too many interrupts are annoying and destructive to overall code function. I need something that was extremely light on processor time.

The Sketch uses 1,210 bytes (3%) of program storage space on my UNO

I've simplified it as much as I can and added some notes. Other notes and portions of code came from the Timer1 library.

This is obviously an early version and it may have bugs
Can anyone test it with 50HZ

/* AC Phase Dimmer Control using PWM
 *  By ZHomeSlice 
 *  I don't think I've seen this done before anywhere
 *  
 *  It Works!!!!!! Thanks To everyone at Arduino.cc 
 *  This uses Timer1 attached to Pin9 for 1024 bit resolution of Phase Control using Pulse Width Modulation!!!!
 *  No Program Overhead hardware control of dimming using PWM !!!
 *    
 * Only known Glitch is near 100% with Duty set above 954 the output is already at max but the light will flicker
 * This occurs near the zero crossing point.
 *  if (Duty >= 1024-70) Direction = -1;  
 */

#define RESOLUTION 65536    // Timer1 is 16 bit
#define PHASEDURATION 16666
unsigned int pwmPeriod;
unsigned char clockSelectBits;

void ZeroCross()
{
  shiftedStart(PHASEDURATION * 0.5);     //and start it up with timer at zero
}

void setPeriod(long microseconds)    // AR modified for atomic access
{
  long cycles = (F_CPU / 2000000) * microseconds;                                // the counter runs backwards after TOP, interrupt is at BOTTOM so divide microseconds by 2
  if (cycles < RESOLUTION)              clockSelectBits = _BV(CS10);             // no prescale, full xtal
  else if ((cycles >>= 3) < RESOLUTION) clockSelectBits = _BV(CS11);             // prescale by /8
  else if ((cycles >>= 3) < RESOLUTION) clockSelectBits = _BV(CS11) | _BV(CS10); // prescale by /64
  else if ((cycles >>= 2) < RESOLUTION) clockSelectBits = _BV(CS12);             // prescale by /256
  else if ((cycles >>= 2) < RESOLUTION) clockSelectBits = _BV(CS12) | _BV(CS10); // prescale by /1024
  else        cycles = RESOLUTION - 1, clockSelectBits = _BV(CS12) | _BV(CS10);  // request was out of bounds, set as maximum

  char oldSREG = SREG;
  cli();              // Disable interrupts for 16 bit register access
  ICR1 = pwmPeriod = cycles;        // ICR1 is TOP in p & f correct pwm mode
  SREG = oldSREG;
  TCCR1B &= ~(_BV(CS10) | _BV(CS11) | _BV(CS12));
  TCCR1B |= clockSelectBits;   // reset clock select register, and starts the clock
}

void shiftedStart(long microseconds)
{
  long cycles = (F_CPU / 2000000) * microseconds;
  unsigned int tcnt1;
  TIMSK1 &= ~_BV(TOIE1);        // AR added
  GTCCR |= _BV(PSRSYNC);        // AR added - reset prescaler (NB: shared with all 16 bit timers);
  char oldSREG = SREG;               // AR - save status register
  cli();                        // AR - Disable interrupts
  TCNT1 = cycles;
  SREG = oldSREG;               // AR - Restore status register
  TCCR1B |= clockSelectBits;
}

void setPwmDuty(int duty)
{
  unsigned long dutyCycle = pwmPeriod;
  dutyCycle *= duty;
  dutyCycle >>= 10;
  char oldSREG = SREG;
  cli();
  OCR1A = OCR1A = ICR1 - dutyCycle; // invert 0-1024 range 
  SREG = oldSREG;
}

void disablePwm(char pin)
{
  TCCR1A &= ~_BV(COM1A1);   // clear the bit that enables pwm on PB1
}

void setup()
{
  pinMode(2,INPUT_PULLUP);
  TCCR1A = 0;                            // clear control register A
  TCCR1A = _BV(COM1A0) | _BV(COM1A1)     // Clear OC1A on Compare Match, set
                                         // OC1A at BOTTOM (Inverting mode)
           | _BV(WGM11);                 // Fast PWM, top at ICR1
  TCCR1B = _BV(WGM12)  | _BV(WGM13);     //       ditto
  setPeriod(PHASEDURATION);
  TCCR1B &= ~(_BV(CS10) | _BV(CS11) | _BV(CS12));        // clears all clock selects bits (stop the counter)
  DDRB |= _BV(PORTB1);                                   // sets data direction register for pwm output pin
  TCCR1A |= _BV(COM1A1);                                 // activates the output pin
  setPwmDuty(0);
  attachInterrupt(0, ZeroCross, FALLING);
}

void loop()
{
  static int Direction = 1;
  static int Duty = 0;
  static unsigned long ATimer; 
  if ((unsigned long)(millis() - ATimer) >= (10))
  {
    ATimer = millis();
    Duty += Direction;
    if (Duty >= 1024-70) Direction = -1; // anything above 954 for me will cause drop in power at 954 I'm at 100% anyways so have trimmed it here.
    if (Duty <= 1) Direction = 1;
    setPwmDuty(Duty);
  }
}

Example output:
image1.jpg
image2.jpg
image3.jpg
Thanks Again

Z

Here is a class version to make things simple Try it out and let me know If you have problems

Change the AC Frequency in the .h file

#define PHASEDURATION 16666 // 60HZ
//#define PHASEDURATION 20000 // 50HZ

#include "ACPhaseControlPin9.h"
void ZeroCross()
{
  AC.shiftedStart(); //Calibrate the Timer with AC
}
void setup()
{
  AC.initialize(14); // Timer Mode 14 (Fast PWM ICR1 BOTTOM TOP)
  pinMode(2,INPUT_PULLUP);
  attachInterrupt(0, ZeroCross, FALLING);
}

void loop()
{
  static int Direction = 1;
  static int Duty = 0;
  static unsigned long ATimer; 
  if ((unsigned long)(millis() - ATimer) >= (10))
  {
    ATimer = millis();
    Duty += Direction;
    if (Duty >= 1024-70) Direction = -1; // anything above 954 for me will cause drop in power at 954 I'm at 100% anyways so have trimmed it here.
    if (Duty <= 1) Direction = 1;
    AC.setPwmDuty(Duty); // << Control the Dimmer Here!
  }
}

Z

ACPhaseControlPin9.cpp (5.44 KB)

ACPhaseControlPin9.h (743 Bytes)