0

I built a small PCB that has some LEDs (bare NeoPixel 5050) and an IR receiver on it. The microcontroller is an ATtiny85, and the PCB is powered by a LiPoly battery (3.7V). The circuit normally stays in ULP sleep mode until a pin change interrupt wakes the circuit. The pin change interrupt is tied to the IR receiver so when the receiver gets a signal from a remote (38kHz modulated IR burst) a lighting sequence is triggered. I have multiple of these PCBs running the exact same code (shown below). When the PCBs receive an IR signal they all start at the same time, but then after a few seconds they start to drift apart. The lighting needs to be synchronized. What is the reason for this drift and how can I eliminate it? Is it due to different battery voltages? That would be the only physical difference between any two PCBs. Thanks for your help.

#define IR_PIN      4
#define LIGHT_PIN   0
#define DELAY_TIME  200

#include <Adafruit_NeoPixel.h>
#define NUM_PIXELS  2
Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUM_PIXELS, LIGHT_PIN, NEO_GRB + NEO_KHZ800);

#include "avr/interrupt.h"
#include "avr/sleep.h"

void setup() {
  pinMode(IR_PIN, INPUT);
  strip.begin();
  pixelsOff();
}

void loop() {
  sleep();

  for (int i = 0; i < 5; i++) {
    pixelsOnRed();
    delay(DELAY_TIME);
    pixelsOff();
    delay(DELAY_TIME);
    pixelsOnGreen();
    delay(DELAY_TIME);
    pixelsOff();
    delay(DELAY_TIME);
  }

  for (int i = 0; i < 5; i++) {
    pixelsOnBlue();
    delay(DELAY_TIME);
    pixelsOff();
    delay(DELAY_TIME);
    pixelsOnRed();
    delay(DELAY_TIME);
    pixelsOff();
    delay(DELAY_TIME);
  }

  for (int i = 0; i < 5; i++) {
    pixelsOnGreen();
    delay(DELAY_TIME);
    pixelsOff();
    delay(DELAY_TIME);
    pixelsOnRed();
    delay(DELAY_TIME);
    pixelsOff();
    delay(DELAY_TIME);
  }
}

void pixelsOff() {
  strip.setPixelColor(0, 0, 0, 0);
  strip.setPixelColor(1, 0, 0, 0);
  strip.show();
}

void pixelsOnRed() {
  strip.setPixelColor(0, 255, 0, 0);
  strip.setPixelColor(1, 255, 0, 0);
  strip.show();
}

void pixelsOnGreen() {
  strip.setPixelColor(0, 0, 255, 0);
  strip.setPixelColor(1, 0, 255, 0);
  strip.show();
}

void pixelsOnBlue() {
  strip.setPixelColor(0, 0, 0, 255);
  strip.setPixelColor(1, 0, 0, 255);
  strip.show();
}

ISR(PCINT0_vect)
{
    //This is not needed for the current sketch
}

void sleep() {
    GIMSK |= _BV(PCIE);                     // Enable Pin Change Interrupts
    PCMSK |= _BV(PCINT4);                   // Use PB3 as interrupt pin
    ADCSRA &= ~_BV(ADEN);                   // ADC off
    set_sleep_mode(SLEEP_MODE_PWR_DOWN);    // replaces above statement

    sleep_enable();                         // Sets the Sleep Enable bit in the MCUCR Register (SE BIT)
    sei();                                  // Enable interrupts
    sleep_cpu();                            // sleep

    cli();                                  // Disable interrupts
    PCMSK &= ~_BV(PCINT3);                  // Turn off PB3 as interrupt pin
    sleep_disable();                        // Clear SE bit
    ADCSRA |= _BV(ADEN);                    // ADC on

    sei();                                  // Enable interrupts
} 
  • 2
    What is your clock source? – Majenko Jun 30 '17 at 15:45
  • @Majenko internal 8MHz oscillator – Alex Wulff Jun 30 '17 at 15:59
  • 1
    That's about the worse clock source you can get. – Edgar Bonet Jun 30 '17 at 16:01
  • @EdgarBonet in your opinion is it bad enough to produce the drift I experienced? – Alex Wulff Jun 30 '17 at 16:04
  • It is very likely. – Edgar Bonet Jun 30 '17 at 16:05
1

What is the reason for this drift and how can I eliminate it?

two solutions:

1) try using crystal oscillators;

2) try driving on arduino with the other arduino's clock output.

1

Assuming internal RC oscillator:

In the datasheet:

By default, the Internal RC Oscillator provides an approximate 8.0 MHz clock. Though voltage and temperature dependent, this clock can be very accurately calibrated by the user. See “Calibrated Internal RC Oscillator Accuracy” on page 164 and “Internal Oscillator Speed” on page 192 for more details. The device is shipped with the CKDIV8 Fuse programmed. See “System Clock Prescaler” on page 31 for more details

And page 192 shows a graph of frequency vs voltage.

On 164 it says:

It is possible to manually calibrate the internal oscillator to be more accurate than default factory calibration. Please note that the oscillator frequency depends on temperature and voltage. Voltage and temperature characteristics can be found in Figure 22-40 on page 193 and Figure 22-41 on page 193.

So yes, conclusive evidence there that the voltage will affect the frequency.

  • Pretty sure the Arduino uses a 16mhz crystal rather than the internal oscillator. dailylearningnotes.blogspot.com/2010/03/… – bigjosh Jun 30 '17 at 15:56
  • @bigjosh "The" Arduino....? READ THE QUESTION: "I built a small PCB that has some LEDs (bare NeoPixel 5050) and an IR receiver on it. The microcontroller is an ATtiny85"... That's not an Uno (ONE of the MANY forms of Arduino) – Majenko Jun 30 '17 at 15:58
  • Thanks, this is insightful. I didn't know that voltage and temperature could affect the oscillator. The only concern I have is that both batteries were charged up to their full 4.2v before use and both PCBs are right next to each other. Maybe small differences in both can produce cascading drift like I saw. I'll take a look at the calibration – Alex Wulff Jun 30 '17 at 16:02
  • @Majenko So true! Comment respectfully withdrawn! :) – bigjosh Jun 30 '17 at 16:17
  • It may be possible to characterize the drift between the two and compensate. To a 1st aprox, you might just be able to let them both run for a while, then measure the speed difference and then slow down the faster one to cancel out the difference. To a 2nd aprox, you could characterize the voltage dependency on each adn then measure and compensate in real-time. But agree with others- easiest probably to use XTAL or a way of syncing (wire, IR LED, etc). – bigjosh Jul 1 '17 at 15:22
0

Other answers have noted that the internal RC oscillator's frequency is voltage and temperature dependent. If you have good control over voltage and temperature, consider manually or automatically calibrating the clocks of your several ATtiny85's.

Absent that control, consider adding crystals or ceramic resonators to your circuits, or set up a synchronization protocol using IR. For example, if your IR transmitter is programmable, have it send a synchronization character as often as necessary to adequately synchronize the lights. If your IR transmitter is not programmable, add an IR LED and driver to one or more of your ATtiny85's, and send synchronization characters at regular intervals.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.