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