My problem with PWM from TimerThree Library

_BV is just a macro as you've found, so the end result of that is

TCCR3A |= 32;

because COM3B1 is 5 and 1<<5 = 32. Therefore TCCR3B was either 0 or 32 before the operation.

If it was 0 it becomes 32, if it was 32 it stays 32.

Any other value and it becomes some value > 32, but it can never be 0 after that OR.

So how does it become 0? Something must be screwing with it elsewhere, or maybe your reporting it at the wrong time/place.


Rob

Thanks so much for that Nick, you have explained that wonderfully and I can now understand that better.
So, shifting that bit 5 places gives the value of 32 I normally see in this TCCR3A register.
I didn't realise that what I was looking at pointed back to a bit position within that register.

So, just to summarise my program flow around the use of this TimerThree function.

Firstly, I have removed the TimerThree generated 1000mSec interrupt used to call a routine.
That interrupt has been replaced with a standard 1000mSec millis() time check, which works fine.

In my setup() I do the following;

Timer3.initialise(100000);                             // initialise timer 3 and set for a 100mSec period
Timer3.pwm(pin_TurbineDumpPWM, 0);      // pre-initialise the pwm on pin 2 and set for 0% duty cycle

Nick, I need to do that second step to setup the correct operating mode for pwm on specified pin, (you did question my use of it in an earlier post)
When you call the Timer3.pwm, that is where DDRE and TCCR3A get set.

Then in my routine that gets called each 100mSec I do the following;

Timer3.setPwmDuty(pin_TurbineDumpPWM, hydroPID.cvPID)

In the above routine, DDRE and TCCR3A are not re-set at all, and it is assumed that they will hold their initial values from the initial setup function
This function is called by Timer3.pwm and from the Timer3 documentation it states the following;

setPwmDuty(pin, duty)
A fast shortcut for setting the pwm duty for a given pin if you have already set it up by calling pwm() earlier.
This avoids the overhead of enabling pwm mode for the pin, setting the data direction register, checking for optional period adjustments etc. that are mandatory when you call pwm()

Rob, just noticed your post, yes, what you are saying is clear, I can understand that.

But still the problem..

Paul

Rob,

or maybe your reporting it at the wrong time/place.

To check the various values of Timer3 I have inserted the following debugs in the Timer3.setPwmDuty(..) function.
The very function I loop through each 100mSec
I know the values are continuously updated as the TCNT3 counts, as do the actual PWM as set and is seen in both variables 'dutyCycleDebug' and 'OCR3BDebug'

void TimerThree::setPwmDuty(char pin, int duty)
{
  unsigned long dutyCycle = pwmPeriod;
  dutyCycle *= duty;
  dutyCycle >>= 10;
  if(pin == 5) OCR3A = dutyCycle;
  if(pin == 2) OCR3B = dutyCycle;
  if(pin == 3) OCR3C = dutyCycle;

  dutyCycleDebug = dutyCycle;		        // XXX debug
  OCR3BDebug = OCR3B;				// XXX debug
  ICR3Debug = ICR3;				// XXX debug
  TCCR3ADebug = TCCR3A;				// XXX debug
  TCCR3BDebug = TCCR3B;				// XXX debug
  TCNT3Debug = TCNT3;				// XXX debug

}

Check out the 'Alarms' page and you can see them all ticking away nicely.
When the problem hits, those values still tick away, except that TCCR3ADebug which is equated to TCCR3A has been set to zero.
Reset the board and away it goes for another few days.

Something must be screwing with it elsewhere

Somewhere, somehow.........

I'm sure someone wiser than me mentioned to me today

Ain't programming fun? , some grayish nomad from up north

Paul

I checked for the occurence of TCCR3A being used elsewhere in the project, and this is the result I get with the reference check;

There are 8 matches, all of which are in the Timer3 library.
You will notice in the image the function disablePwm(..), where TCCR3A bits are cleared, but this function is not called in my program.
In the search section, line 26 is part of the Timer3 initialise function.

There's some smokey black magic happening in there somewhere.....

Paul

Can you please assemble a sketch that just demonstrates your problems with the Timer 3 PWM output? Then I can test that and check what is really happening. Thanks.

From my main program I have cut out the components that relate specifically to TimerThree.

/*-------------------------------------------------------------------------
    Timer3_test.cpp

    Created on: Dec 14, 2012
        Author: Paul Alting van Geusau
        A very simple sketch to check the operation of the TimerThree Library
        for reliable and continuous PWM operation.
        
        Step 1. initialise the Timer3 for correct mode, PWM on pin 2 with a period of 100 milli second period
        Step 2. call a function every 100 milli seconds to call the Timer3.setPwmDuty(..) function

 */

#include    "timer3_test.h"
#include    "TimerThree.h"

//  const    type        variable        =   value      comment
    const    uint8_t     pin_PWM         =    2;      // PWM from OCR3B
             uint32_t    lastIntTime     =    0;      // last time through the timerInterrupt loop:
    const    uint32_t    intPeriod       =    100;    // delay period to call timerInterrupt loop:


//-------------------------------------------------------------------------
//    void setup()
//
void setup() {
//  Serial.begin(115200);

    pinMode(pin_PWM, OUTPUT);                         // configure pin 2 for output:

    Timer3.initialize(100000);                        // initialize Timer3, and set a 100 milli second period:
    Timer3.pwm(pin_PWM, 0);                           // pre-initialise the pwm on pin 2 and set for 0% duty cycle:
}

//-------------------------------------------------------------------------
//    void loop()
//
void loop() {
    if (millis() - lastIntTime >= intPeriod) {        // is it time to call the process100mS routine:
        process100mS();
        lastIntTime = millis();
    }
}

//-------------------------------------------------------------------------
//    void process100mS()
//    Instead of PID output, we just give it a steady value of 512 for the test
//
void process100mS() {
    Timer3.setPwmDuty(pin_PWM, 512);                  // set the pwm with the output of the pid output to control the SSR:
}

And header file

#ifndef Timer3_test_
    #define Timer3_test_
    #include "Arduino.h"

    // function definitions for the project
    void loop();
    void setup();
    void process100mS();


#endif /* Timer3_test_ */

Edit: remember that I have also made a small change in the TimerThree library in the function setPeriod(..) as mentioned earlier and as follows;

void TimerThree::setPeriod(long microseconds)
{            // (F_CPU * microseconds) / 2000000 was original but changed to (F_CPU / 2000000) * microseconds due to potentail overflow condition.
  long cycles = (F_CPU / 2000000) * microseconds;

  // rest of function

}

Note: I am using the Freetronics Ether-Mega, so a 2560 based system.

Paul

I ran this slightly modified sketch (added a serial print):

/*-------------------------------------------------------------------------
    Timer3_test.cpp

    Created on: Dec 14, 2012
        Author: Paul Alting van Geusau
        A very simple sketch to check the operation of the TimerThree Library
        for reliable and continuous PWM operation.
        
        Step 1. initialise the Timer3 for correct mode, PWM on pin 2 with a period of 100 milli second period
        Step 2. call a function every 100 milli seconds to call the Timer3.setPwmDuty(..) function

 */

#include    "TimerThree.h"

//  const    type        variable        =   value      comment
    const    uint8_t     pin_PWM         =    2;      // PWM from OCR3B
             uint32_t    lastIntTime     =    0;      // last time through the timerInterrupt loop:
    const    uint32_t    intPeriod       =    100;    // delay period to call timerInterrupt loop:


//-------------------------------------------------------------------------
//    void setup()
//
void setup() {
    Serial.begin(115200);
    Serial.println ("Starting sketch ...");
    
    pinMode(pin_PWM, OUTPUT);                         // configure pin 2 for output:

    Timer3.initialize(100000);                        // initialize Timer3, and set a 100 milli second period:
    Timer3.pwm(pin_PWM, 0);                           // pre-initialise the pwm on pin 2 and set for 0% duty cycle:
}

//-------------------------------------------------------------------------
//    void loop()
//
void loop() {
    if (millis() - lastIntTime >= intPeriod) {        // is it time to call the process100mS routine:
        process100mS();
        lastIntTime = millis();
    }
}

//-------------------------------------------------------------------------
//    void process100mS()
//    Instead of PID output, we just give it a steady value of 512 for the test
//
void process100mS() {
    Timer3.setPwmDuty(pin_PWM, 512);                  // set the pwm with the output of the pid output to control the SSR:
}

I didn't bother with the .h file. I modified Timer3 as you showed.

This is the result:

That's correct isn't it? 100 mS for one full pulse, 50% duty cycle. That was on an Arduino Mega2560 board.

That's correct isn't it? 100 mS for one full pulse, 50% duty cycle. That was on an Arduino Mega2560 board.

Nick, yes that is correct, the period is 100mSec, with a 50% duty cycle as we are feeding 512 into Timer3.setPwmDuty(..)
On an Arduino 2560 board.

Paul

Right, so to save me re-reading everything above, the problem is ...?

Yes, I can understand the thread is getting longer and easy to loose the issue I am having.

Importantly
After a period of time my Arduino stops providing the pwm wiggling on pin 2.
Even though I still call a function to do so every 100mSec, though it should continue regardless of this call.
All other functions in my program continue to operate normally when this problem is present.

In this test we provide a static value of 512 but on my board, this value will range over 0 to 1023 depending on my PID loop controller, hence the 100mSec update.
The period before the failure occurs can vary, I have found it to be typically one to three days, apparently no set period.

For example I reset my board last night and awoke this morning to find no pwm happening when there should have been, my battery bank hit 30Vdc.

Many thanks Nick for your assistance.

Paul

Well, can you reproduce this? Try different values. In particular, extreme ones (eg. 0, 1023 or close to that).

Nick,

Try different values. In particular, extreme ones (eg. 0, 1023 or close to that)

On the board running the program the values do go from 0 to 1023 and anything in between.

When the PID is not putting out any output, it is zero and that is what is fed into the function Timer3.setPwmDuty(..).
Then when the PID is wanting maximum output, that is 1023, that is what is fed into that same function.

So, the value going into the function every 100mSec is more or less constantly on the move.
The problem is not to do with the value I provide to the function I am certain, more that Timer Control Register 3A (TCCR3A) becomes cleared to zero at some point in time.

Paul

Now, every 100mSec I make a call to a TimerThree function, the PWM function, and this is where TCCR3A is able to be changed, as follows;

Well why do you call that every 100 mS? You don't need to change the period, do you? Only the duty cycle.

The thing is, it is hard to debug from snippets. Stuff you don't think is relevant might actually be the problem. Just as an example the Servo library clears TCCR3A.

I feel confident that the hardware registers don't just clear themselves for no reason. Something in your code, or in a library, is doing it. Possibly due to a buffer overrun somewhere.

Nick

Well why do you call that every 100 mS? You don't need to change the period, do you? Only the duty cycle.

I call the Timer3.setPwmDuty(..) every 100mSec because I need to give a new duty value to the function as provided from the PID output.
I am not changing the value of the Timer3 pwm period at all.

I hope you're not getting confused by the fact that I have the Timer3 period set to 100mSec as well as my function call to set the duty being called every 100mSec.

In the test program, you can see that I initialise the Timer3 with a 100mSec period.
Then quite apart from this, I have a call to the process100ms routine being called every 100mSec.

The two are totally separate timings.

Paul

Does this code have interrupts? For something that goes wrong very occasionally it sounds like a timing issue.

Nick

Something in your code, or in a library, is doing it. Possibly due to a buffer overrun somewhere

Check post #22, where I check for all references of TCCR3A in the complete project, only found in the Timer3 library.
All my dealings with Timer3 are via those very functions as in the test program, nothing else.

Does this code have interrupts?

No interrupts anymore, as I mentioned in reply post #20

Firstly, I have removed the TimerThree generated 100mSec interrupt used to call a routine.
That interrupt has been replaced with a standard 100mSec millis() time check, which works fine.

Which is what we have in the test, it is from my actual program.

For something that goes wrong very occasionally it sounds like a timing issue

Well, yes, timing of sorts I guess, being that it takes a while for the problem to manifest itself.

I am feeling somewhat stuck and a little embarrassed as I think I should be able to sort this out.
But it is proving to be a curly one.

Paul

OK, let me ask you this. If I changed that test code to randomly generate a number in the range 0 to 1023 (or you do it), and then let it run for a couple of days, is your theory that the PWM output will eventually stop?

is your theory that the PWM output will eventually stop?

Not so much my theory, but my experience, yes.
It sounds so totally strange, I see no reason whatsoever that it should stop, but stop it does.

Maybe put some extra serial debugs in the test code, such as what I have and I hope you have seen on my web page.
Particularly TCCR3A, that is the one that is getting changed, bit 5 from being set to being cleared.

I will do some tests on hard coding the value and writing on the Timer3.pwm(..) function just as it does in Timer3.setPwmDuty(..) function to find out what happens.

I do appreciate your help Nick, and Rob too.

Paul

I'm trying to get my Mega running so I can try the code, can't get past the dreaded "sync" error.

In an attempt to at least fix the symptoms, how about running a watchdog task that checks the TCCR3A value and changes it to 32 if 0. For that matter just write 32 every time but record that the value was wrong.

Such a weird thing smells of memory leaks or an overflow somewhere. Bloody hard to find normally.


Rob