Is the internal clock not good enough???

I am having a problem with a new project I made and I’m not 100% sure what the cause is, is 1 MHz internal clock not good enough??

I have made a navigation light controller for a model airplane that reads the pwm and changes modes accordingly. Everything worked perfect when I had the project on my UNO but I moved everything over to an attiny84 and I am getting RANDOM episodes of the lights blinking/skipping beats when its not supposed to. Sometimes it will happen 3-10 times a minute and sometimes it wont do it for 2-3 minutes.

I checked the output voltage on the airplane and it is stable only fluctuates a max of 0.02v once in a while.

I checked the pwm from the airplane (used the UNO) and the pwm only varies +/- 4usec (hysteresis in my code allows for a +/- 100usec variation)

What I think the problem is, is that the internal clock is skipping beats/jittering which is causing the pwm to be read inaccurately (either too high >2500usec or too low <500usec) making the lights default to the off mode

Would running at a higher 8mhz internal be better or
will it be a better idea to use an external 1 MHz crystal, or is there something else I should be looking into???

(deleted)

I did try at 8mhz internal and it seems like it no longer does it or if it does it happens so fast I cant see it. But now I am confused as to why 8mhz would be better/make a difference since I have been using an interrupt to read the pwm. The range I am reading is between 1100 to 1700usec, which I thought is well within the limits of 1 MHz clock.

Even though it worked on an UNO, the problem could be in the code. Could be a race condition, low memory, etc.

What is a race condition ? and the sketch only uses 38% program space and only 9% of dynamic memory on the attiny84 so I don't think low memory is an issue.

I thought it might be in the code but then I was thinking it works fine on the uno (and as far as mcu) the only clock differences are the 16mhz speed and being more accurate external.

like every adventure this thing is rattling my brain lol

Could happen if you are using ISRs in your code and are not careful about how you update variables.

here is a snipit of my code where I determine which mode to choose based on the pwm value, could my issue just be that the pwm is changing during the if/else if condition? in which case I should disable the interrupt while it is determining which mode it should choose…

 if ((pulse_width >= (pos1 - 100)) && (pulse_width <= (pos1 + 100))) {

        strobeReset();
        strobe();
        switchState = 1;
      }
      else if ((pulse_width >= (pos2 - 100)) && (pulse_width <= (pos2 + 100))) {

        strobeReset();
        strobe();
        switchState = 2;
      }
      else if ((pulse_width >= (pos3 - 100)) && (pulse_width <= (pos3 + 100))) {

        if (lastSwitchState != 3) {
          wigState = LOW;
          preWigwagMillis = millis() - 500;
        }
        strobeReset();
        strobe();
        wigwag();
        switchState = 3;
      }

Don't post snippet, post the whole sketch. Looking at snippets in all but the simplest cases is a waste of time.

Here is the whole code

TAB1

#include <EEPROM.h>
#include "EEPROMAnything.h"
/**************
  STROBE PINS
* *****************************************************/
const byte L_Strobe = 2;
const byte R_Strobe = 7;
const byte T_Strobe = 5;

/*******************
  STROBE SEQUENCE
* *****************************************************/
const byte strobeInterval1 = 90;      //led(s) on
const byte strobeInterval2 = 50;      //led(s) off
const byte strobeInterval3 = 30;      //led(s) on
const byte strobeInterval4 = 50;      //led(s) off
const byte strobeInterval5 = 30;      //led(s) on
const long strobeInterval6 = 1500;    //led(s) off
const long wigwagInterval = 500;


/***********
  VARIABLES
* *****************************************************/
byte strobeState = 1;  // set the strobe state
byte switchState = 0;
byte wigState = LOW;
byte wagState = LOW;
byte lastSwitchState = 0;
long preStrobeMillis = 0;
long preWigwagMillis = 0;        //set negative so the first time through the loop it automatically turns on
volatile int prevTime = 0;
volatile int pulse_width;
volatile unsigned long timer_start;
volatile int last_interrupt_time;
volatile byte switch_type;
int pos0 = 0;
int pos1 = 0;
int pos2 = 0;
int pos3 = 0;
byte soft_button_state = LOW;
byte last_soft_state = LOW;
byte incrementing = true;


void setup() {

  pinMode(L_Strobe, OUTPUT);
  pinMode(R_Strobe, OUTPUT);
  pinMode(T_Strobe, OUTPUT);
  pinMode(0, OUTPUT);
  pinMode(1, OUTPUT);
  pinMode(3, OUTPUT);
  pinMode(6, OUTPUT);
  pinMode(9, OUTPUT);
  pinMode(10, OUTPUT);
  timer_start = 0;
  attachInterrupt(0, pulse_calc, CHANGE);

  delay(20);

  while ((pulse_width == 0) || (pulse_width < 500) || (pulse_width > 2500)) {
    digitalWrite(0, HIGH);
    digitalWrite(10, HIGH);

    delay(75);

    digitalWrite(0, LOW);
    digitalWrite(10, LOW);

    delay(75);
  }

  if (pulse_width < 1500) {
    Radio_Calibration();
  }



  Load_EEPROM();

    delay(10);

}

void loop() {

  switch (switch_type) {

    detachInterrupt(0);  // should I detach the interrupt during this part of the code
                                  // so the pwm value doesn't change while determining the mode??

    case 4:

      if ((pulse_width >= (pos1 - 100)) && (pulse_width <= (pos1 + 100))) {

        strobeReset();
        strobe();
        switchState = 1;
      }
      else if ((pulse_width >= (pos2 - 100)) && (pulse_width <= (pos2 + 100))) {

        strobeReset();
        strobe();
        switchState = 2;
      }
      else if ((pulse_width >= (pos3 - 100)) && (pulse_width <= (pos3 + 100))) {

        if (lastSwitchState != 3) {
          wigState = LOW;
          preWigwagMillis = millis() - 500;
        }
        strobeReset();
        strobe();
        wigwag();
        switchState = 3;
      }

      else {
        switchState = 0;
      }

      break;






    case 2:

      if ((pulse_width >= (pos1 - 100)) && (pulse_width <= (pos1 + 100))) {
        soft_button_state = HIGH;
      }

      else {
        soft_button_state = LOW;
      }


      



      if (soft_button_state != last_soft_state) {
        // if the state has changed, increment the counter
        if (soft_button_state == HIGH && incrementing == true) {
          // if the current state is HIGH then the button
          // wend from off to on:
          switchState++;

          if (switchState == 3) {
            incrementing = false;
          }
        }

        else if (soft_button_state == LOW && incrementing == false) {
          switchState--;

          if (switchState == 0) {
            incrementing = true;
          }
        }
      }


      // save the current state as the last state,
      //for next time through the loop
      last_soft_state = soft_button_state;


      if (switchState == 1) {
        strobeReset();
        strobe();
      }

      else if (switchState == 2) {
        strobeReset();
        strobe();
      }

      else if (switchState == 3) {
        if (lastSwitchState != 3) {
          wigState = LOW;
          preWigwagMillis = millis() - 500;
        }
        strobeReset();
        strobe();
        wigwag();
      }

      break;
  }

  timer_start = 0;
  attachInterrupt(0, pulse_calc, CHANGE);





  if (switchState != lastSwitchState) {

    if (switchState == 1) {
      digitalWrite(1, HIGH);
      digitalWrite(3, HIGH);
      digitalWrite(6, HIGH);
      digitalWrite(9, HIGH);
      digitalWrite(0, LOW);
      digitalWrite(10, LOW);

      if (lastSwitchState != 2) {
        analogWrite(T_Strobe, 50);
      }
    }

    else if (switchState == 2) {
      digitalWrite(1, HIGH);
      digitalWrite(3, HIGH);
      digitalWrite(6, HIGH);
      digitalWrite(9, HIGH);
      digitalWrite(0, HIGH);
      digitalWrite(10, HIGH);


      if ((lastSwitchState != 1) || (lastSwitchState != 3)) {
        analogWrite(T_Strobe, 50);
      }
    }

    else if (switchState == 3) {
      digitalWrite(1, HIGH);
      digitalWrite(3, HIGH);
      digitalWrite(6, HIGH);
      digitalWrite(9, HIGH);

      if (lastSwitchState != 2) {
        analogWrite(T_Strobe, 50);
      }
    }

    else if (switchState == 0) {
      digitalWrite(1, LOW);
      digitalWrite(3, LOW);
      digitalWrite(6, LOW);
      digitalWrite(9, LOW);
      digitalWrite(0, LOW);
      digitalWrite(10, LOW);
      digitalWrite(L_Strobe, LOW);
      digitalWrite(R_Strobe, LOW);
      analogWrite(T_Strobe, 0);
      strobeState = 1;
    }
  }

  lastSwitchState = switchState;





}

TAB2

void Radio_Calibration() {

  byte blink_count = 0;


  while (blink_count < 5) {
    all_lights_flash();
    blink_count++;
  }

  delay(2000);
  pos0 = pulse_width;


  all_lights_flash();

  delay(2000);
  pos1 = pulse_width;


  while (blink_count < 7) {
    all_lights_flash();
    blink_count++;
  }

  delay(2000);
  pos2 = pulse_width;


  while (blink_count < 10) {
    all_lights_flash();
    blink_count++;
  }

  delay(2000);
  pos3 = pulse_width;


  if ((pos1 < (pos2 + 100)) && (pos1 > (pos2 - 100)) && (pos2 < (pos3 + 100)) && (pos2 > (pos3 - 100))) {
    switch_type = 2;

    while (blink_count < 12) {
      all_lights_flash();
      blink_count++;
    }
  }


  else {
    switch_type = 4;

    while (blink_count < 14) {
      all_lights_flash();
      blink_count++;
    }
  }

  delay(2000);




  //EEPROM STORE ANYTHING STORE POS VALUES

    int eeprom_address = 0;
    
    eeprom_address += EEPROM_writeAnything(eeprom_address, pos0);
    eeprom_address += EEPROM_writeAnything(eeprom_address, pos1);
    eeprom_address += EEPROM_writeAnything(eeprom_address, pos2);
    eeprom_address += EEPROM_writeAnything(eeprom_address, pos3);
    eeprom_address += EEPROM_writeAnything(eeprom_address, switch_type);

}

TAB3

void Load_EEPROM() {

  
    int eeprom_address = 0;
    
    eeprom_address += EEPROM_readAnything(eeprom_address, pos0);
    eeprom_address += EEPROM_readAnything(eeprom_address, pos1);
    eeprom_address += EEPROM_readAnything(eeprom_address, pos2);
    eeprom_address += EEPROM_readAnything(eeprom_address, pos3);
    eeprom_address += EEPROM_readAnything(eeprom_address, switch_type);


}

TAB4

#include <EEPROM.h>
#include <Arduino.h>  // for type definitions

 template <class T> int EEPROM_writeAnything(int ee, const T& value)
{
     const byte* p = (const byte*)(const void*)&value;
     unsigned int i;
     for (i = 0; i < sizeof(value); i++)
           EEPROM.write(ee++, *p++);
     return i;
}

 template <class T> int EEPROM_readAnything(int ee, T& value)
{
     byte* p = (byte*)(void*)&value;
     unsigned int i;
     for (i = 0; i < sizeof(value); i++)
           *p++ = EEPROM.read(ee++);
     return i;
}

TAB5

void strobeON() {
  digitalWrite(L_Strobe, HIGH);
  digitalWrite(R_Strobe, HIGH);
  analogWrite(T_Strobe, 255);
}


void strobeOFF() {
  digitalWrite(L_Strobe, LOW);
  digitalWrite(R_Strobe, LOW);
  analogWrite(T_Strobe, 50);
}


void strobeReset() {
  if (lastSwitchState == 0) {
    preStrobeMillis = millis();
  }
}


void strobe() {


  if ((strobeState == 1) && (millis() - preStrobeMillis >= strobeInterval6)) {
    strobeON();
    strobeState ++;
    preStrobeMillis = millis();
  }
  else if ((strobeState == 2) && (millis() - preStrobeMillis >= strobeInterval1)) {
    strobeOFF();
    strobeState ++;
    preStrobeMillis = millis();
  }
  else if ((strobeState == 3) && (millis() - preStrobeMillis >= strobeInterval2)) {
    strobeON();
    strobeState ++;
    preStrobeMillis = millis();
  }
  else if ((strobeState == 4) && (millis() - preStrobeMillis >= strobeInterval3)) {
    strobeOFF();
    strobeState ++;
    preStrobeMillis = millis();
  }
  else if ((strobeState == 5) && (millis() - preStrobeMillis >= strobeInterval4)) {
    strobeON();
    strobeState ++;
    preStrobeMillis = millis();
  }
  else if ((strobeState == 6) && (millis() - preStrobeMillis >= strobeInterval5)) {
    strobeOFF();
    strobeState = 1;
    preStrobeMillis = millis();
  }
}


void wigwag() {

  if (millis() - preWigwagMillis >= wigwagInterval) {
    // check the last time you blinked the LED

    // if the LED is off turn it on and vice-versa:
    if (wigState == LOW) {
      wigState = HIGH;
      wagState = LOW;
    } else {
      wigState = LOW;
      wagState = HIGH;
    }

    // set the LED with the ledState of the variable:
    digitalWrite(10, wigState);
    digitalWrite(0, wagState);
    preWigwagMillis = millis();

  }
}


void all_lights_flash() {
  digitalWrite(1, HIGH);
  digitalWrite(3, HIGH);
  digitalWrite(6, HIGH);
  digitalWrite(9, HIGH);
  digitalWrite(0, HIGH);
  digitalWrite(10, HIGH);
  digitalWrite(L_Strobe, HIGH);
  digitalWrite(R_Strobe, HIGH);
  digitalWrite(T_Strobe, HIGH);

  delay(100);

  digitalWrite(1, LOW);
  digitalWrite(3, LOW);
  digitalWrite(6, LOW);
  digitalWrite(9, LOW);
  digitalWrite(0, LOW);
  digitalWrite(10, LOW);
  digitalWrite(L_Strobe, LOW);
  digitalWrite(R_Strobe, LOW);
  digitalWrite(T_Strobe, LOW);

  delay(200);
}

TAB6

void pulse_calc()
{

  //if the pin has gone HIGH, record the microseconds since the Arduino started up
  if (digitalRead(8) == HIGH)
  {
    timer_start = micros();
  }
  //otherwise, the pin has gone LOW
  else
  {
    //only worry about this if the timer has actually started
    if (timer_start != 0)
    {
      //record the pulse time
      pulse_width = ((volatile int)micros() - timer_start);
      //restart the timer
      timer_start = 0;

      last_interrupt_time = micros();
    }
  }


  //record the interrupt time so that we can tell if the receiver has a signal from the transmitter
}

You do have a 0.1uF bypass cap close to the tiny's power pins? I have had intermittent bouts of crazy behavior on tiny84 and tiny85 before realizing that I had forgotten to add the bypass cap.

PaulRB:
You do have a 0.1uF bypass cap close to the tiny's power pins? I have had intermittent bouts of crazy behavior on tiny84 and tiny85 before realizing that I had forgotten to add the bypass cap.

The supply was already smooth but I added one and it didn't do anything to improve the issue

You need to use unsigned longs to store millis() return values, not longs - I think using signed longs will make it break when millis() rolls over.

You detach that interrupt.... and then you reattach it....
Does it break your code if the pin goes high, then loop rolls around, you detach the interrupt. Now the pin goes low and high again unbeknownst to the ISR, and you reattach the interrupt. Then pin goes low again - but you've not tended to the variable where you're tracking the time, so it now looks like the pulse was much longer than it was...

ebolton92:
The supply was already smooth but I added one and it didn't do anything to improve the issue

Doesn't matter if the supply is smooth. You still always need that 0.1uf decoupling cap cap, and it must be close to the power and ground pins on the chip (you may also need a higher value cap if the power supply isn't smooth enough). It will not work if you put it on the end of long wires, or at the other end of your breadboard, or between the rails on a breadboard - it needs to be close to the power/ground pins on the chip. I had to trash a batch of boards I made because I put the cap too far away from the attiny. I think the 'tiny's are more sensitive to this than 'megas.

or between the rails on a breadboard

I must have been lucky then. Always found that worked OK. I do normally connect the chip to the + & - rails on the same side of the breadboard and put the cap no more than a few holes away. Also I have never used an external crystal with tinys, only the internal clock @ 1 or 8MHz.

I changed longs to unsigned longs and still no resolution.

Did you read what I said about the interrupt? That part is absolutely a logic flaw in your code - I have no idea if the impact of it would be what you observed though.

DrAzzy:
Did you read what I said about the interrupt? That part is absolutely a logic flaw in your code - I have no idea if the impact of it would be what you observed though.

That part wasn't there when I originally made the thread and decided to remove it for the reasons you mentioned and because a lot of my code is run in that section.

I might remove the interrupt and use pulseIn just before I need to read the signal since I wont be changing the modes that often and when I do change the mode (interrupt or not) the change isn't applied until the next time through the loop anyway.

But who knows if that will cure the problem since I have NO clue what the problem is.

So I exchanged the interrupt for pulseIn and the code worked correctly on the uno, but again it is randomly turning on/ off lights at 1mhz (worse now than with the interrupt) but it works flawlessly at 8 MHz.

I cant figure out why it works at 8 MHz and not 1 and its driving me nuts...

I think I might have figured it out somewhat, I believe the problem is with reading the value and storing it to the EEPROM because when I hardcode the pos0 thru pos3 values (not load them from eeprom everything works correctly at 1mhz) but I haven't been able to pinpoint it.

any further help will be greatly appreciated