timer control register question

I am working on a library to use timer3 to generate process timing with a 2ms resolution and three pwm signals.
I have been paguing PaulS with my syntax and color issues and he has been a great help. Thanks PaulS.
I have had some problems with setting the TCCR3B register.

changing any of the WGM3x bits makes the timer stop running, nothing i do seems to effect the clock setting bits, they always read back as 011.

the frequency of the PWM is correct as if the select bits were 001 no prescaler. The PWM times are as set in the sketch. ????? what am i missing.

i know what the first thing you are going to say "up load the files so we can see them".
so here they are.
the header file.

/*ProcessTimer.h
 *  Interrupt and PWM utilities for 16 bit Timer1 on ATmega1281
 */
#include <WProgram.h>
#include <avr/io.h>
#include <inttypes.h>
 
class Ptimer {
      public:
            Ptimer();
            void setCount(int);
            int getCount();
            boolean done();
            boolean doneFlag;
             int count;
      private:
       };
class ProcessTimer{
      public:
            ProcessTimer(Ptimer *p);

          void setPwm5(int);
          void setPwm2(int);
          void setPwm3(int);
          
          void startPwm5();
          void startPwm2();
          void startPwm3();
          
          void stopPwm5();
          void stopPwm2();
          void stopPwm3();
             void startIntrrupts(); //this is a debuging thing
          void scanArray();  // called by isr
            Ptimer *ptArray;
            byte getTCCRA();
            byte getTCCRB();
      private:
            int maxPwm;
            byte arraySize;      
};

the class file:

/*ProcessTimer.cpp
 *  Process Timer and PWM utilities for 16 bit Timer3 on ATmega1281
 *
 */

#include "ProcessTimer.h"

Ptimer::Ptimer(){
      count = 0;
      doneFlag = true;
};
void Ptimer::setCount(int c){
      count=c;
      doneFlag=false;
      };
int Ptimer::getCount(){
      return count;
};
boolean Ptimer::done(){
      return doneFlag;
}
ProcessTimer::ProcessTimer(Ptimer *p){
      ptArray = p;
      arraySize = sizeof(p);
      
// initalize timer 1
      maxPwm = 32000;
      ICR3 = maxPwm;
// ICR3 is TOP in p & f correct pwm mode
// TCC3A COM3A1 COM3A0       COM3B1       COM3B0       COM3C1       COM3C0       WGM11       WGM10
// Clear OC1A/OC1B/OC1C on compare match
      TCCR3A &= ~(_BV(COM3A0) |_BV(COM3B0) | _BV(COM3C0));  
      TCCR3A |= (_BV(COM3A1) |_BV(COM3B1) | _BV(COM3C1));
// wave generation mode
//TCC3B             ICNC3       ICES3       –       WGM13       WGM12       CS12       CS11       CS10
// timer mode
//      TCCR3B |=  (_BV(WGM33));
//      TCCR3B |=  (_BV(WGM32));

//      TCCR3A |=  (_BV(WGM31));
      TCCR3A |=  (_BV(WGM30));
// clear clock select
//      TCCR3B &= ~(_BV(CS32) | _BV(CS31) | _BV(CS30));      
// no prescaler
//      TCCR3B |= (_BV(CS30));
        TCCR3B = 1;
      OCR3A = 0;
      OCR3B = 0;
      OCR3C = 0;
      pinMode(5, OUTPUT);   
      pinMode(3, OUTPUT);
      pinMode(2, OUTPUT);
      TIMSK3 = _BV(TOIE1);                        // sets the timer overflow interrupt enable bit
      sei();                                                            // interrupts are globally enabled
//      TIMSK3 &= ~_BV(TOIE1); //stop interrupts      
}
void ProcessTimer::scanArray(){                        //called by isr
      byte i;
      Ptimer *p = ptArray;
// some day see if this works
// doneFlag = (*p).count) ? (*p--).count : false;
      for(i=0 ; i < arraySize ; i++){

            if((*p).count==0){
                  (*p).doneFlag = true;
            }
            else{
                  (*p).count--;
            };
      }
}
//ISR(TIMER3_OVF_vect){
//myProcessTimer.scan();
//};
void ProcessTimer::startIntrrupts(){
      TIMSK1 = _BV(TOIE1);
};
void ProcessTimer::setPwm5(int dutyCycle){
      OCR3A = dutyCycle > maxPwm ? maxPwm : dutyCycle;
};
void ProcessTimer::setPwm2(int dutyCycle){
      OCR3B = dutyCycle > maxPwm ? maxPwm : dutyCycle;
};
void ProcessTimer::setPwm3(int dutyCycle){
      OCR3C = dutyCycle > maxPwm ? maxPwm : dutyCycle;
};
void ProcessTimer::startPwm5(){
      TCCR3A |= _BV(COM3A1);
};
void ProcessTimer::startPwm2(){
      TCCR3A |= _BV(COM3B1);
};
void ProcessTimer::startPwm3(){
      TCCR3A |= _BV(COM3C1);
};
void ProcessTimer::stopPwm5(){
      TCCR3A &= ~_BV(COM3A1);
};
void ProcessTimer::stopPwm2(){
      TCCR3A &= ~_BV(COM3B1);
};
void ProcessTimer::stopPwm3(){
      TCCR3A &= ~_BV(COM3C1);
};
// temporary for debuging
byte ProcessTimer::getTCCRA(){
return TCCR3A;
};
byte ProcessTimer::getTCCRB(){
return TCCR3B;
};

the test pde:

/*processTimerTest1.pde
this thing changes all the time
*/
#include "ProcessTimer.h"
#include <Streaming.h>

Ptimer timerArray[4];

ProcessTimer PT(timerArray);

void setup()
{
PT.setPwm5(8000);
PT.setPwm3(16000);
PT.setPwm2(24000);
PT.startPwm5();
PT.startPwm3();
PT.startPwm2();
timerArray[0].setCount(1000);

Serial.begin(9600);
};


ISR(TIMER3_OVF_vect)
{

  PT.scanArray();
};

void loop()
{
      if(timerArray[0].done()){
        timerArray[0].setCount(1000);
        Serial <<"TCCR3A  "<<_BIN(PT.getTCCRA())<<"   "<< "TCCR3B  "<<_BIN(PT.getTCCRB())<<endl;
      };
};

when the test program runs it prints:

TCCR3A 10101001 TCCR3B 11

TCCR3A 10101001 TCCR3B 11

TCCR3A 10101001 TCCR3B 11

TCCR3A 10101001 TCCR3B 11

TCCR3A 10101001 TCCR3B 11

TCCR3A 10101001 TCCR3B 11

endlessly the pwm out puts are of the correct ratio
and the period is 2 ms. which should not be with TCCRB = 11
clock calc

boy oh boy am i confused.

it needs a lot of cleaning up but it works.
takes a bit if memory"
Binary sketch size: 4062 bytes (of a 126976 byte maximum)"

if you don't have streaming you should it works great and won't rot your teeth and takes 0 memory. of course the code it produces takes memory, hey you get nothing for free.

/*
Streaming.h - Arduino library for supporting the << streaming operator

Copyright (c) 2010 Mikal Hart.  All rights reserved.



This library is free software; you can redistribute it and/or

modify it under the terms of the GNU Lesser General Public

License as published by the Free Software Foundation; either

version 2.1 of the License, or (at your option) any later version.



This library is distributed in the hope that it will be useful,

but WITHOUT ANY WARRANTY; without even the implied warranty of

MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU

Lesser General Public License for more details.



You should have received a copy of the GNU Lesser General Public

License along with this library; if not, write to the Free Software

Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA

*/



#ifndef ARDUINO_STREAMING

#define ARDUINO_STREAMING



#include <WProgram.h>



#define STREAMING_LIBRARY_VERSION 4



// Generic template

template<class T> 

inline Print &operator <<(Print &stream, T arg) 

{ stream.print(arg); return stream; }



struct _BASED 

{ 

  long val; 

  int base;

  _BASED(long v, int b): val(v), base(b) 

  {}

};



#define _HEX(a)     _BASED(a, HEX)

#define _DEC(a)     _BASED(a, DEC)

#define _OCT(a)     _BASED(a, OCT)

#define _BIN(a)     _BASED(a, BIN)

#define _BYTE(a)    _BASED(a, BYTE)



// Specialization for class _BASED

// Thanks to Arduino forum user Ben Combee who suggested this 

// clever technique to allow for expressions like

//   Serial << _HEX(a);



inline Print &operator <<(Print &obj, const _BASED &arg)

{ obj.print(arg.val, arg.base); return obj; } 



#if ARDUINO >= 18

// Specialization for class _FLOAT

// Thanks to Michael Margolis for suggesting a way

// to accommodate Arduino 0018's floating point precision

// feature like this:

//   Serial << _FLOAT(gps_latitude, 6); // 6 digits of precision



struct _FLOAT

{

  float val;

  int digits;

  _FLOAT(double v, int d): val(v), digits(d)

  {}

};



inline Print &operator <<(Print &obj, const _FLOAT &arg)

{ obj.print(arg.val, arg.digits); return obj; }

#endif



// Specialization for enum _EndLineCode

// Thanks to Arduino forum user Paul V. who suggested this

// clever technique to allow for expressions like

//   Serial << "Hello!" << endl;



enum _EndLineCode { endl };



inline Print &operator <<(Print &obj, _EndLineCode arg) 

{ obj.println(); return obj; }



#endif

found a bug and fixed it so here is an updated class file and a new pde file
i wasn't bumping the pointer in the scan. So now I know at least two of the process timers are working, hopes for the rest.

still no joy on the timer control register problem.

/*ProcessTimer.cpp
 *  Process Timer and PWM utilities for 16 bit Timer3 on ATmega1281
 *
 */

#include "ProcessTimer.h"

Ptimer::Ptimer(){
      count = 0;
      doneFlag = true;
};
void Ptimer::setCount(int c){
      count=c;
      doneFlag=false;
      };
int Ptimer::getCount(){
      return count;
};
boolean Ptimer::done(){
      return doneFlag;
}
ProcessTimer::ProcessTimer(Ptimer *p){
      ptArray = p;
      arraySize = sizeof(p);
      
// initalize timer 1
      maxPwm = 32000;
      ICR3 = maxPwm;
// ICR3 is TOP in p & f correct pwm mode
// TCC3A COM3A1 COM3A0       COM3B1       COM3B0       COM3C1       COM3C0       WGM11       WGM10
// Clear OC1A/OC1B/OC1C on compare match
      TCCR3A &= ~(_BV(COM3A0) |_BV(COM3B0) | _BV(COM3C0));  
      TCCR3A |= (_BV(COM3A1) |_BV(COM3B1) | _BV(COM3C1));
// wave generation mode
//TCC3B             ICNC3       ICES3       –       WGM13       WGM12       CS12       CS11       CS10
// timer mode
//      TCCR3B |=  (_BV(WGM33));
//      TCCR3B |=  (_BV(WGM32));

//      TCCR3A |=  (_BV(WGM31));
      TCCR3A |=  (_BV(WGM30));
// clear clock select
//      TCCR3B &= ~(_BV(CS32) | _BV(CS31) | _BV(CS30));      
// no prescaler
//      TCCR3B |= (_BV(CS30));
        TCCR3B = 1;
      OCR3A = 0;
      OCR3B = 0;
      OCR3C = 0;
      pinMode(5, OUTPUT);   
      pinMode(3, OUTPUT);
      pinMode(2, OUTPUT);
      TIMSK3 = _BV(TOIE1);                        // sets the timer overflow interrupt enable bit
      sei();                                                            // interrupts are globally enabled
//      TIMSK3 &= ~_BV(TOIE1); //stop interrupts      
}
void ProcessTimer::scanArray(){                        //called by isr
      byte i;
      Ptimer *p = ptArray;
// some day see if this works
// doneFlag = (*p).count) ? (*p--).count : false;
      for(i=0 ; i < arraySize ; i++,p++){

            if((*p).count==0){
                  (*p).doneFlag = true;
            }
            else{
                  (*p).count--;
            };
      }
}
//ISR(TIMER3_OVF_vect){
//myProcessTimer.scan();
//};
void ProcessTimer::startIntrrupts(){
      TIMSK1 = _BV(TOIE1);
};
void ProcessTimer::setPwm5(int dutyCycle){
      OCR3A = dutyCycle > maxPwm ? maxPwm : dutyCycle;
};
void ProcessTimer::setPwm2(int dutyCycle){
      OCR3B = dutyCycle > maxPwm ? maxPwm : dutyCycle;
};
void ProcessTimer::setPwm3(int dutyCycle){
      OCR3C = dutyCycle > maxPwm ? maxPwm : dutyCycle;
};
void ProcessTimer::startPwm5(){
      TCCR3A |= _BV(COM3A1);
};
void ProcessTimer::startPwm2(){
      TCCR3A |= _BV(COM3B1);
};
void ProcessTimer::startPwm3(){
      TCCR3A |= _BV(COM3C1);
};
void ProcessTimer::stopPwm5(){
      TCCR3A &= ~_BV(COM3A1);
};
void ProcessTimer::stopPwm2(){
      TCCR3A &= ~_BV(COM3B1);
};
void ProcessTimer::stopPwm3(){
      TCCR3A &= ~_BV(COM3C1);
};
// temporary for debuging
byte ProcessTimer::getTCCRA(){
return TCCR3A;
};
byte ProcessTimer::getTCCRB(){
return TCCR3B;
};
/*processorTimerTest1.pde
*/
#include "ProcessTimer.h"
#include <Streaming.h>

Ptimer timerArray[4];

ProcessTimer PT(timerArray);

void setup()
{
PT.setPwm5(8000);
PT.setPwm3(16000);
PT.setPwm2(24000);
PT.startPwm5();
PT.startPwm3();
PT.startPwm2();
timerArray[0].setCount(1000);
timerArray[1].setCount(2000);
Serial.begin(9600);
};


ISR(TIMER3_OVF_vect)
{

  PT.scanArray();
};

void loop()
{
    if(timerArray[0].done()){
      timerArray[0].setCount(1000);
      Serial <<"TCCR3A  "<<_BIN(PT.getTCCRA())<<"   "<< "TCCR3B  "<<_BIN(PT.getTCCRB())<<endl;
    };
    if(timerArray[1].done()){
      timerArray[1].setCount(2000);
      timerArray[0].setCount(500);
      Serial <<"timer1 says Hi"<<endl;
    };
};

In the ProcessTimer.cpp i changed the control register set up to this:

      maxPwm = 32000;
      ICR3 = maxPwm;
// ICR3 is TOP in p & f correct pwm mode
// TCC3A COM3A1 COM3A0       COM3B1       COM3B0       COM3C1       COM3C0       WGM11       WGM10
// Clear OC3A/OC3B/OC3C on compare match

      TCCR3A = 0x10101010;
// wave generation mode
//TCC3B             ICNC3       ICES3       –       WGM13       WGM12       CS12       CS11       CS10
// timer mode

        TCCR3B = 0x0011001;

That is pretty explicit.

and processTimerTest1.pde as in my last post outputs this:

timer1 says Hi

TCCR3A  10111001   TCCR3B  11

TCCR3A  10111001   TCCR3B  11

timer1 says Hi

TCCR3A  10111001   TCCR3B  11

TCCR3A  10111001   TCCR3B  11

timer1 says Hi

which is not what i set. Any ideas ?

if i put the timer initalization of timer3 in the .pde file instead of the class constructor it works like it should.
the exact same code in the constructor doesn't work

/*processorTimerTest1.pde
*/
#include "ProcessTimer.h"
#include <Streaming.h>

Ptimer timerArray[4];

ProcessTimer PT(timerArray);

void setup()
{
TCCR3A = 0;
TCCR3A = 0b10101010;
TCCR3B = 0;
TCCR3B = 0b00011001;
ICR3 = 32000;
TIMSK3 = _BV(TOIE1); // sets the timer overflow interrupt enable bit
sei();
PT.setPwm5(8000);
PT.setPwm3(16000);
PT.setPwm2(24000);
PT.startPwm5();
PT.startPwm3();
PT.startPwm2();
timerArray[0].setCount(1000);
timerArray[1].setCount(2000);
Serial.begin(9600);
};

ISR(TIMER3_OVF_vect)
{
PT.scanArray();
};

void loop()
{
if(timerArray[0].done()){
timerArray[0].setCount(1000);
Serial <<"TCCR3A "<<_BIN(TCCR3A)<<" "<< "TCCR3B "<<_BIN(TCCR3B)<<endl;
};
if(timerArray[1].done()){
timerArray[1].setCount(2000);
timerArray[0].setCount(500);
Serial <<"timer1 says Hi"<<endl;
Serial <<"ICR3 "<<ICR3<<endl;
};
};

output

ICR3 32000

TCCR3A 10101010 TCCR3B 11001

TCCR3A 10101010 TCCR3B 11001

timer1 says Hi

ICR3 32000

TCCR3A 10101010 TCCR3B 11001

TCCR3A 10101010 TCCR3B 11001

timer1 says Hi

ICR3 32000

TCCR3A 10101010 TCCR3B 11001

There are a number of issues with class constructors on the Arduino. You really need to have no code in the constructor. Instead, create a begin() method (like Serial.begin()) where the code that would normally go in the constructor goes, instead. Then, call that begin method to initiate the instance.

It's not the exact same code...
0x10101010 != 0b10101010

Thanks Paul I will keep that in mind. I think i just got a lesson in that. I saw that and changed it Mitch, but it didn't make any difference. Moving the initialisation to set up made everything work and i am good with that.

I don't usually write c++ code, too old fashioned, I thought it would be fun to give it a try for some of this.

Now i have some timers that won't hold up the loop, and i understand the 1280 timer hardware some what.

I am happy with the mega, I have had it almost two weeks now and am making good progress toward some real use.