Andrew Dodd

 Home

PWM with Timer 3 on Arduino Yun

Just a quick post with an example sketch for how to setup timer 3 on an Arduino Yun to control the brightness of an LED.

I had to go through figuring this out while experimenting with brightness and flash patterns.

Anyway….

  • It’s just a simple sketch.
  • I’m not really sure why a prescaler of 1 doesn’t work (I guess the LED switches on and off too quickly).
  • I’m not going to explain the ins and outs of a PWM for LED control (there are lot of good examples on the web).
  • The “brightness” value is really just the ratio of ON time to OFF time vs the rollover value (255).
  • The actual perceived brightness for any LED will not be linear…you have to compensate for how the eye works and how the LED makes light (in a real product).
// Exmaple using PWM (Timer 3) for brightness control
enum {
  RED_PIN = 13,
  STEP = 5,
};

int dir = STEP;
int brightness = 0;

void setup() {
  Serial.begin(9600);
  pinMode(RED_PIN, OUTPUT);
  
  noInterrupts(); // disable all interrupts
  // Waveform Generation
  // ===================
  //  Mode  Mode of Operation  TOP       Update of OCRnx at    TOVn Flag Set on
  //    3 - Fast PWM, 8-bit    0x00FF          TOP                  BOTTOM
 
  // 14.10.2 Timer/Counter3 Control Register A – TCCR3A
  // 7      6      5      4      3      2      1      0
  // COM3A1 COM3A0 COM3B1 COM3B0 COM3C1 COM3C0 WGM31  WGM30 
  // 0      0      0      0      0      0      0      1
  TCCR3A = 0x01;
  // 14.10.4 Timer/Counter3 Control Register B – TCCR3B
  // 7      6      5      4      3      2      1      0
  // ICNC3  ICES3  –      WGM33  WGM32  CS32   CS31   CS30
  // 0      0      0      0      1      1      0      1
  TCCR3B = 0x0D;

  // Enable Overflow and Output Compare 1 interrupt
  TIMSK3 |= (1 << TOIE3) | (1 << OCIE3A);
  OCR3AH = 0;
  OCR3AL = 0;
  interrupts(); // enable all interrupts
}

// On the compare interrupt, set the pin low
ISR(TIMER3_COMPA_vect) {
    digitalWrite(RED_PIN, LOW);
}

// On the timer rollover interrupt, set the pin high if the brightness is non-zero
ISR(TIMER3_OVF_vect) {
  digitalWrite(RED_PIN, brightness > 0);
  OCR3AL = brightness;
}

void loop() {
  delay(500);

  // Step up or down by STEP size
  brightness += dir;
  // Clip to the 0..255 range
  brightness = min(brightness, 255);
  brightness = max(brightness, 0);

  // Change the step direction if at the limit
  if (brightness == 255) {
    dir = -STEP;
  }
  if (brightness == 0) {
    dir = STEP;
  }
  Serial.print("Brightness:");
  Serial.print(brightness);
  Serial.println("");
}