I'm trying to use timers 3 and 4 of a Mega 2560 to generate PWM at 25 kHz. I am only able to get an output on the first pin ("A", e.g. pin 5 for timer 3) of each timer; nothing I've done has enabled the other pins.
Here's my setup function:
void setupTimer3() {
// Set pins as outputs
pinMode(2, OUTPUT); // FAN1
pinMode(3, OUTPUT); // FAN2
pinMode(5, OUTPUT); // FAN3
digitalWrite(2, HIGH);
digitalWrite(3, HIGH);
digitalWrite(5, HIGH);
// Enable the PWM outputs OC3A, OC3B and OC3C on digital pins 5, 2 and 3
TCCR3A = _BV(COM3A1) | _BV(COM3B1) | _BV(COM3C1);
// Set phase and frequency correct PWM and prescaler of 0 on timer 3
TCCR3B = _BV(WGM33) | _BV(CS30);
// 320 = ~25 kHz
ICR3 = 320;
// set outputs to 50%
OCR3A = 160;
OCR3B = 160;
OCR3C = 160;
}
This code is largely taken from MartinL's post at
The line TCCR3A = _BV(COM3A1) | _BV(COM3B1) | _BV(COM3C1) ought to enable all three pins, but only pin 5 actually outputs the PWM. (And with an equivalent function for timer 4, only pin 6 has an output.)
I'm doing something wrong, but don't know what. Any help would be appreciated!
Thanks for confirming the code, John. I had commented out just about everything in my code that wasn't included in my post, but went back to completely remove everything except the setup function. That still had the same problem. So I got out another Mega board and lo and behold, it worked on all three channels.
It turns out I had not one, but two Megas that had partial hardware failure. The first board suffered a 5V-to-ground short when probing things, though it seemed to work OK afterwards. I'm not surprised that could have biffed some I/O, depending on just what shorted. [ Lesson learned -- put a piece of spaghetti over exposed 5V pins on headers! ]
So I got out another Mega, but this one suffered a 12V-to-ground short because of a part specification error (mine) on the shield -- a part spec'd for 9V was on the 12V power input, and it failed short. After correcting that, the board seemed to work fine in early testing. But it had the weird timer problem. Since the short was on the 12V side, I'm not sure why it affected the 5V Arduino components, but apparently it did. This was confusing, because the symptom was pretty much the same as on the first board.
I plugged the shield (minus shorted diode) into a new Mega, and everything is working as it should be. Your confirmation that the code looked OK got me to where I could check the hardware, so thanks!
You have chosen "inverting mode"; so, OC3A, OC3B and OC3C pins will initially remain at LOW states. Therefore, remove the following three lines from the sketch:
Inverting-mode is when COMnx1 and COMnx0 are both set: TCCR3A = _BV(COM3A1) | _BV(COM3A0) |_BV(COM3B1) | _BV(COM3B0) | _BV(COM3C1) | _BV(COM3C0);
The PWM mode is correctly set for normal PWM.
I don't think those three lines will cause a problem either way. Removing them would not hurt.
Thanks for the replies, John and GolemMostafa! As mentioned above, the problem turned out to be an unfortunate sequence of self-inflicted hardware issues.
I included the digitalWrite lines as par of debugging; originally I didn't have them, and there's no need to include them. Since this is a fan controller running at 25 kHz, I don't think the starting phase is too important.
Regarding setting TCCR3A and TCCR3B, I'm not sure why they would need to be zeroed -- I am setting both from scratch with the two setup lines I had. (i.e., I'm not or-ing them with the existing values. It might be more obvious if I preset them to zero, though.
As we are not sure whether these registers were manipulated or not by the init() function called by main() before starting the setup() function. So, let us reset them before loading new values by | (or) operation.
I'm sure you're correct from a non-obfuscation point of view, but unless I misunderstand the syntax, my setting lines didn't OR new values into the registers, they overwrote them ("=" instead of "|=" as the first operator).
This operation makes or only the referred bit and then assigns the new value to that bit position without affecting other bits. For example:
TCCR3B |= 1<<CS30;
The above code performs or (|) operation between 1 and CS30-bit of TCCR3B Register. The result of the operation is assigned at CS30-bit of TCCR3B Register.