TCCR1A was not declared in this scope?

I found the below code on the net for driving a fan using PWM and its throwing a bunch of errors. I"m using a Mega 2560

Shouldnt the IDE understand what TCCR1A, COM1B1, COM1B0, WGM11, WGM10 etc are or do they need to be declared?

sketch_aug10a:65: error: 'TCCR1A' was not declared in this scope
sketch_aug10a:65: error: 'COM1B1' was not declared in this scope
sketch_aug10a:65: error: 'COM1B0' was not declared in this scope
sketch_aug10a:65: error: 'COM1C1' was not declared in this scope
sketch_aug10a:65: error: 'WGM11' was not declared in this scope
sketch_aug10a:65: error: 'WGM10' was not declared in this scope
sketch_aug10a:66: error: 'TCCR1B' was not declared in this scope
sketch_aug10a:66: error: 'WGM13' was not declared in this scope
sketch_aug10a:66: error: 'WGM12' was not declared in this scope
sketch_aug10a:66: error: 'CS11' was not declared in this scope
sketch_aug10a:67: error: 'TCCR1C' was not declared in this scope
sketch_aug10a:68: error: 'OCR1AH' was not declared in this scope
sketch_aug10a:69: error: 'OCR1AL' was not declared in this scope
sketch_aug10a:71: error: 'OCR1BH' was not declared in this scope
sketch_aug10a:72: error: 'OCR1BL' was not declared in this scope
sketch_aug10a:73: error: 'OCR1CH' was not declared in this scope
sketch_aug10a:74: error: 'OCR1CL' was not declared in this scope

// Definition of Arduino type
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
#define  IS_MEGA  (1)
#define  IS_UNO   (0)
#else
#define  IS_MEGA  (0)
#define  IS_UNO   (1)
#endif

// Analog output (i.e PWM) pins. These must be chosen so that we can change the PWM frequency without affecting the millis()
// function or the MsTimer2 library. So don't use timer/counter 1 or 2. See comment in setup() function.
// THESE PIN NUMBERS MUST NOT BE CHANGED UNLESS THE CODE IN setup(), setTransistorFanSpeed() AND setDiodeFanSpeed() IS CHANGED TO MATCH!
#if IS_UNO
// On the Uno we can only use the OC1B pin, so these pin numbers are both 10
const int transistorFanPin = 10;     // OC1B
const int diodeFanPin = 10;          // OC1B
#else
// On the Mega we use OC1B and OC1C
const int transistorFanPin = 12;     // OC1B
const int diodeFanPin = 13;          // OC1C
#endif

// Definitions for PWM fan control
const unsigned char maxFanSpeed = 80;   // this is calculated as 16MHz divided by 8 (prescaler), divided by 25KHz (target PWM frequency from Intel specification) 

void setup()
{
  // Set up the PWM pins for a PWM frequency close to the recommended 25KHz for the Intel fan spec.
  // We can't get this frequency using the default TOP count of 255, so we have to use a custom TOP value.
  
#if IS_UNO

  // Only timer/counter 1 is free because TC0 is used for system timekeeping (i.e. millis() function),
  // and TC2 is used for our 1-millisecond tick. TC1 controls the PWM on Arduino pins 9 and 10.
  // However, we can only get PWM on pin 10 (controlled by OCR1B) because we are using OCR1A to define the TOP value.
  // Using a prescaler of 8 and a TOP value of 80 gives us a frequency of 16000/(8 * 80) = 25KHz exactly.
  TCCR1A = (1 << COM1B1) | (1 << COM1B0) | (1 << WGM11) | (1 << WGM10);  // OC1A (pin 9) disconnected, OC1B (pin 10) = inverted fast PWM  
 #ifdef FAN_AUDIO_TEST
  // test code to get 440Hz output (= concert A) to test the logic 
  OCR1AH = 0;
  OCR1BL = 71;  // 50% duty cycle 
  TCCR1B = (1 << WGM13) | (1 << WGM12) | (1 << CS12);  // TOP = OCRA, prescaler = 256

  OCR1AL = 141; // TOP = 141, 16000000 / (256 * 142) = 440.014
  OCR1BH = 0;
 #else
  OCR1AH = 0;
  OCR1AL = 79;  // TOP = 79
  TCCR1B = (1 << WGM13) | (1 << WGM12) | (1 << CS11);  // TOP = OCR0A, prescaler = 8

  OCR1BH = 0;
  OCR1BL = maxFanSpeed;  // max fan speed (i.e. pin 5 initially low all the time)  
 #endif

  TCNT1H = 0;
  TCNT1L = 0; 
#else

  // On the Mega we use TC1 and OCR1B, OCR1C
  TCCR1A = (1 << COM1B1) | (1 << COM1B0) | (1 << COM1C1) | (1 << COM1C1) | (1 << WGM11) | (1 << WGM10);  // OC1A disconnected, OC1B = OC1C inverted fast PWM  
  TCCR1B = (1 << WGM13) | (1 << WGM12) | (1 << CS11);  // TOP = OCR1A, prescaler = 8
  TCCR1C = 0;
  OCR1AH = 0;
  OCR1AL = 79;  // TOP = 79

  OCR1BH = 0;
  OCR1BL = maxFanSpeed;
  OCR1CH = 0;
  OCR1CL = maxFanSpeed;
  
  TCNT1H = 0;
  TCNT1L = 0;
#endif
  
  // We have to enable the ports as outputs before PWM will work.
  pinMode(transistorFanPin, OUTPUT);
  pinMode(diodeFanPin, OUTPUT);
}

// Set the transistor fan speed, where 0 <= fanSpeed <= maxFanSpeed
void setTransistorFanSpeed(unsigned char fanSpeed)
{
  OCR1BH = 0;
  OCR1BL = fanSpeed;
}

// Set the diode fan speed, where 0 <= fanSpeed <= maxFanSpeed
void setDiodeFanSpeed(unsigned char fanSpeed)
{
#if IS_UNO
  OCR1BH = 0;
  OCR1BL = fanSpeed;
#else
  OCR1CH = 0;
  OCR1CL = fanSpeed;
#endif
}

That looks like a piece of code that I wrote. If you have put it in your main sketch file, and you have set the board type to Arduino Uno or Arduino Mega, then the IDE should know the definitions of those values. If you have put it in a separate .cpp or .h file, then you need to #include "Arduino.h" first.

1 Like

He's right you know... Works perfectly fine on the Uno (excepting the lack of loop()) but switch to the Mega 2560 or the 1280 and it doesn't compile with just those stated errors.

Looking into the header files... The uno (iom328p.h) has TCCR1A defined within it. The iom2560.h file doesn't - it includes <avr/iomxx0_1.h> which does have it defined.

There's only one copy of that file at ./hardware/tools/avr/lib/avr/include/avr/iomxx0_1.h, so why it's not getting defined I'm not so sure.

Ok, gotcha... it's the crumby preprocessor.

The IDE is inserting the #include <Arduino.h> inside the #if IS_UNO block, so it never gets added for the Mega.

Add something like

unsigned char defeatTheCrumbyPreprocessor;

as the very first line of the sketch and it works.

Suffice it to say this isn't a problem on UECIDE :wink:

@dc42 - I think it could well be - your name looks familiar. It is in my main sketch.
@majenko - that did the trick. I've no idea what defeatTheCrumbyPreprocessor does but it works :slight_smile:

GregM:
@dc42 - I think it could well be - your name looks familiar. It is in my main sketch.
@majenko - that did the trick. I've no idea what defeatTheCrumbyPreprocessor does but it works :slight_smile:

The Arduino IDE has to insert

#include <Arduino.h>

into your sketch in order for it to find all the predefined registers and functions. The sensible place to put it is as the very first line of the code, but it doesn't. It finds the first line that isn't either blank, a comment, or a peprocessor directive (#...) and inserts it just after that.

It doesn't understand what the preprocessor directives do though, so it gets easily confused. As a result, the first line it finds that isn't a preprocessor directive, comment, or empty, is the line

const int transistorFanPin = 10;     // OC1B

inside the block

#if IS_UNO
// On the Uno we can only use the OC1B pin, so these pin numbers are both 10
const int transistorFanPin = 10;     // OC1B
const int diodeFanPin = 10;          // OC1B
#else
// On the Mega we use OC1B and OC1C
const int transistorFanPin = 12;     // OC1B
const int diodeFanPin = 13;          // OC1C
#endif

Because of that it inserts the include file just before that const:

#if IS_UNO
// On the Uno we can only use the OC1B pin, so these pin numbers are both 10
#include <Arduino.h>
const int transistorFanPin = 10;     // OC1B
const int diodeFanPin = 10;          // OC1B
#else
// On the Mega we use OC1B and OC1C
const int transistorFanPin = 12;     // OC1B
const int diodeFanPin = 13;          // OC1C
#endif

So you can see that it would only work properly on an Uno as nothing else would have the Arduino.h file included.

By adding a line at the start that isn't a preprocessor directive, and isn't a comment, you're forcing the IDE to insert the include directive much earlier making it available to all types of board instead of just the Uno.

Thanks for the great explanation.

Rather than adding a random line of code, you could just move this line:

// Definitions for PWM fan control
const unsigned char maxFanSpeed = 80;   // this is calculated as 16MHz divided by 8 (prescaler), divided by 25KHz (target PWM frequency from Intel specification)

to the very top of the sketch

dc42:
That looks like a piece of code that I wrote. If you have put it in your main sketch file, and you have set the board type to Arduino Uno or Arduino Mega, then the IDE should know the definitions of those values. If you have put it in a separate .cpp or .h file, then you need to #include "Arduino.h" first.

worked for me on Particle Photon board. however I included Arduino.h after and it fixed the
TCCR1A was not declared in this scope