Welcome to Laser Pointer Forums - discuss green laser pointers, blue laser pointers, and all types of lasers

Buy Site Supporter Role (remove some ads) | LPF Donations

Links below open in new window

FrozenGate by Avery

Anyone familiar with Attiny13 programming?

Sorry for not jumping in sooner. Life has been crazy here.

I know you deleted the posts but I remember the gist of them from my email notifications. You won't be able to use any Hex programmer, or any physical flashing device that requires a hex programmer or IDE (program used to program things in). The Atmel family chips (ATTiny, ATMega, etc) all require a specific type of IDE, and it turns out that the Arduino IDE is simply the most user friendly and basic program to do this in, especially since it is free, widespread, and has a HUGE support base.

I'll read up on your other thread and see if there's any more pertinent info you've let out.

I can certainly walk you through the process I use for flashing these chips, but you'll need a Arduino of some kind (I'd grab a UNO if I were you, but clones work just as well as long as they're functional).

Alright, so the good news is that the higher quality AVR programmer I ordered works great, and I've been flashing code revisions onto an ATTINY85 over and over again with absolutely no issues.

The bad news, is that our code doesn't work :(

The code, as it stood in Sig's post here, simply lit up all 3 channels, and then wouldn't respond to buttons.

1) I debugged first by putting some code right after the button press that blinked all three channels, and was able to identify that the button press was working. However, it never actually changed channel combinations, they always ended up lit up.

2) I removed the randomness code, and the EEPROM reading, and arbitrarily set the first color choice in hard code, and removed option 8 (random) entirely. I also increased trigger count from 10 to 25 and introduced a 10 ms delay after each increment. Now the paired down code works. I can move through modes 1 through 7. But I had to pull out the randomness code to do it :( Here's what the butchered (but working) code looks like:

Code:
// RHD's TTL Color Selector
// Programming by Matt "Sigurthr" Giordano 08/18/2014
// Website: www.SigurthrEnterprises.com
// Email: Sigurthr@SigurthrEnterprises.com
// and by Things of LaserPointerForums.com 08/15/2014

// ATTiny85 Physical Pinout - innermost designation is code addressable
//                   _______
// Reset           _|  |_|  |_   Vcc
// ADC3 Pin3   3   _|       |_ 2 Pin2 ADC1
// ADC2 Pin4  A2   _| ATT85 |_ 1 Pin1 Digital-1
// Gnd             _|       |_ 0 Pin0 Digital-0
//                  |_______|
  

#include <EEPROM.h> // include the EEPROM Memory library
boolean pinOptions[7][3] = { // Array of pin combinations (1 = on, 0 = off)
  {1,1,1},
  {1,0,0},
  {1,1,0},
  {0,1,0},
  {0,1,1},
  {0,0,1},
  {1,0,1}
};

byte PressDetects = 0;
byte ButtonPin = 3; // see pinout
byte ColorOnePin = 0; // see pinout
byte ColorTwoPin = 1; // see pinout
byte ColorThreePin = 2; // see pinout
byte MemVar;
byte ButtonPinState;
byte ColorChoice;
byte MemoryLocation = 1;
byte TriggerCount = 25; // threshold for debounce

void setup (){ // this subroutine runs once upon startup
  // Choosing 3 arbitrarily
  MemVar = 0;
  pinMode (0, OUTPUT); // set pin 0 to output
  pinMode (1, OUTPUT); // set pin 1 to output
  pinMode (2, OUTPUT); // set pin 2 to output
  pinMode (3, INPUT); // set pin 3 to input
}

void loop(){ // this subroutine runs continuously after setup finishes
  ButtonPinState = digitalRead(ButtonPin);  // read ButtonPin to ButtonPinState  
  if (ButtonPinState == HIGH){ // when ButtonPinState is HIGH...
    ++ PressDetects; // increment detection variable
    delay(10);
  }
  if (PressDetects >= TriggerCount) { // when threshold is exceeded...
    ++ MemVar; // increment memory variable
    PressDetects = 0; // reset button detector
    if (MemVar >= 8){ // on 8th button press...
      MemVar = 1; // reset color
    }    
  }
  ColorChoice = MemVar; 
  digitalWrite(ColorOnePin, pinOptions[ColorChoice-1][0]);
  digitalWrite(ColorTwoPin, pinOptions[ColorChoice-1][1]);
  digitalWrite(ColorThreePin, pinOptions[ColorChoice-1][2]);
}
 
Last edited:





Double posting to avoid any confusion as to the code I'm referring to.

I've narrowed the problem down to the EEPROM code. This code WORKS (in that it allows for color changing, but of course doesn't save state because there is no read/write to EEPROM:

Code:
#include <EEPROM.h> // include the EEPROM Memory library
boolean pinOptions[7][3] = { // Array of pin combinations (1 = on, 0 = off)
  {1,1,1},
  {1,0,0},
  {1,1,0},
  {0,1,0},
  {0,1,1},
  {0,0,1},
  {1,0,1}
};

byte PressDetects = 0;
byte ButtonPin = 3; // see pinout
byte ColorOnePin = 0; // see pinout
byte ColorTwoPin = 1; // see pinout
byte ColorThreePin = 2; // see pinout
byte MemVar;
byte ButtonPinState;
byte ColorChoice;
byte MemoryLocation = 1;
byte TriggerCount = 25; // threshold for debounce

void setup (){ // this subroutine runs once upon startup
  // Choosing 3 arbitrarily
  MemVar = 0;
  pinMode (0, OUTPUT); // set pin 0 to output
  pinMode (1, OUTPUT); // set pin 1 to output
  pinMode (2, OUTPUT); // set pin 2 to output
  pinMode (3, INPUT); // set pin 3 to input
}

void loop(){ // this subroutine runs continuously after setup finishes
  ButtonPinState = digitalRead(ButtonPin);  // read ButtonPin to ButtonPinState  
  if (ButtonPinState == HIGH){ // when ButtonPinState is HIGH...
    ++ MemVar; // increment memory variable
    if (MemVar >= 8){ // on 8th button press...
      MemVar = 1; // reset color
    }
  }
  ColorChoice = MemVar; 
  digitalWrite(ColorOnePin, pinOptions[ColorChoice-1][0]);
  digitalWrite(ColorTwoPin, pinOptions[ColorChoice-1][1]);
  digitalWrite(ColorThreePin, pinOptions[ColorChoice-1][2]);
  delay(250);
}

This code does NOT work, in that the output stays white, and I can't even switch colors. It's like it's frozen and doesn't respond to the button at all. The only difference is the addition of READ/WRITE functions for the color state.

Code:
#include <EEPROM.h> // include the EEPROM Memory library
boolean pinOptions[7][3] = { // Array of pin combinations (1 = on, 0 = off)
  {1,1,1},
  {1,0,0},
  {1,1,0},
  {0,1,0},
  {0,1,1},
  {0,0,1},
  {1,0,1}
};

byte PressDetects = 0;
byte ButtonPin = 3; // see pinout
byte ColorOnePin = 0; // see pinout
byte ColorTwoPin = 1; // see pinout
byte ColorThreePin = 2; // see pinout
byte MemVar;
byte ButtonPinState;
byte ColorChoice;
byte MemoryLocation = 1;
byte TriggerCount = 25; // threshold for debounce

void setup (){ // this subroutine runs once upon startup
  // Choosing 3 arbitrarily
  MemVar = 0;
  MemVar = EEPROM.read(MemoryLocation); // read EEPROM on power on
  pinMode (0, OUTPUT); // set pin 0 to output
  pinMode (1, OUTPUT); // set pin 1 to output
  pinMode (2, OUTPUT); // set pin 2 to output
  pinMode (3, INPUT); // set pin 3 to input
}

void loop(){ // this subroutine runs continuously after setup finishes
  ButtonPinState = digitalRead(ButtonPin);  // read ButtonPin to ButtonPinState  
  if (ButtonPinState == HIGH){ // when ButtonPinState is HIGH...
    ++ MemVar; // increment memory variable
    if (MemVar >= 8){ // on 8th button press...
      MemVar = 1; // reset color
    }
    EEPROM.write(MemoryLocation, MemVar); // write color to memory      
  }
  ColorChoice = MemVar; 
  digitalWrite(ColorOnePin, pinOptions[ColorChoice-1][0]);
  digitalWrite(ColorTwoPin, pinOptions[ColorChoice-1][1]);
  digitalWrite(ColorThreePin, pinOptions[ColorChoice-1][2]);
  delay(250);
}
 
Try using these functions. I'm not sure if the Arduino EEPROM libraries are portable to the ATTINY's.
Code:
void EEPROM_write(unsigned char ucAddress, unsigned char ucData)
{
/* Wait for completion of previous write */
while(EECR & (1<<EEPE))
;
/* Set Programming mode */
EECR = (0<<EEPM1)|(0<<EEPM0);
/* Set up address and data registers */
EEAR = ucAddress;
EEDR = ucData;
/* Write logical one to EEMPE */
EECR |= (1<<EEMPE);
/* Start eeprom write by setting EEPE */
EECR |= (1<<EEPE);
}

Code:
unsigned char EEPROM_read(unsigned char ucAddress)
{
/* Wait for completion of previous write */
while(EECR & (1<<EEPE))
;
/* Set up address register */
EEAR = ucAddress;
/* Start eeprom read by writing EERE */
EECR |= (1<<EERE);
/* Return data from data register */
return EEDR;
}
 
Last edited:
Ah, you're right.

Did you initialize the EEPROM? IIRC it reads all 1's until you write to it, you may have to upload code to set it to within a valid range for it to work. Not sure what will happen if it returns 255 with the current code.
 
Last edited:
Ah, you're right.

Did you initialize the EEPROM? IIRC it reads all 1's until you write to it, you may have to upload code to set it to within a valid range for it to work. Not sure what will happen if it returns 255 with the current code.

Good call, that's probably part of the problem. I wonder if EEPROM is reset with each programming?

In any event, I have reprogrammed this chip 30 or 40 times now, and the pins are getting weak, so I may need to hold off on more programming until more chips arrive.
 
Good call, that's probably part of the problem. I wonder if EEPROM is reset with each programming?

EEPROM is preserved through each programming in other AVR's I've used. It still may be a good idea to write an if statement to check if it's out of range upon startup.
 
This code does NOT work, in that the output stays white, and I can't even switch colors. It's like it's frozen and doesn't respond to the button at all. The only difference is the addition of READ/WRITE functions for the color state.

I believe this might be due to the fact that on the first time through the loop, MemVar might be equal to 0 (assuming nothing has been written to that address yet). This might cause the program to crash on the digitalWrite since [-1][0] would be invalid.

Try adding this after the EEPROM.read in the setup():

Code:
if(MemVar < 1)
   MemVar = 1;
else if (MemVar > 7)
   MemVar = 1;

edit: Seems I was a little slow. Glad ARG had the same thought.
 
Last edited:
  • Like
Reactions: ARG
Reading through the thread a little more, I see that you originally wanted to do PWM? I don't think that would be too hard to add. It looks like the ATtiny85 only has 2 hardware PWM outputs, but you could add the 3rd in software or even run all 3 in software. This is a really low overhead program (basically nothing if you moved the button to an interrupt routine instead of polling every loop). Assuming you're running an 8MHz clock, I think you could easily run 3 software PWM signals up to a few hundred kHz each.

If you're interested, I could sketch out some code when I have time.
 
Last edited:
Reading through the thread a little more, I see that you originally wanted to do PWM? I don't think that would be too hard to add. It looks like the ATtiny85 only has 2 hardware PWM outputs, but you could add the 3rd in software or even run all 3 in software. This is a really low overhead program (basically nothing if you moved the button to an interrupt routine instead of polling every loop). Assuming you're running an 8MHz clock, I think you could easily run 3 software PWM signals up to a few hundred kHz each.

If you're interested, I could sketch out some code when I have time.

If you could even show me how to move the button press to an interrupt, that would be hugely helpful. Right now I'm running at 1 mhz, but I gather that's no big deal to change to 8 without requiring an external crystal?

There is software PWM code online that I've looked at, and can probably use almost as-is.
 
If you could even show me how to move the button press to an interrupt, that would be hugely helpful. Right now I'm running at 1 mhz, but I gather that's no big deal to change to 8 without requiring an external crystal?

I'll have to look into which pins on the ATtiny85 can be used for interrupts, but I believe it has two. Basic structure will look like this:

Code:
void setup() {

  (previous setup code)

  attachInterrupt(ButtonPin, ButtonISR, RISING) // sets up interrupt service routine that is called each time ButtonPin goes high (rising edge)

}

void loop() {

  (Sofware PWM)

}

void ButtonISR {
    ++ MemVar; // increment memory variable
    if (MemVar >= 8){ // on 8th button press...
      MemVar = 1; // reset color
    }
    EEPROM.write(MemoryLocation, MemVar); // write color to memory
    ColorChoice = MemVar;
}
 
I'll have to look into which pins on the ATtiny85 can be used for interrupts, but I believe it has two. Basic structure will look like this:

Code:
void setup() {

  (previous setup code)

  attachInterrupt(ButtonPin, ButtonISR, RISING) // sets up interrupt service routine that is called each time ButtonPin goes high (rising edge)

}

void loop() {

  (Sofware PWM)

}

void ButtonISR {
    ++ MemVar; // increment memory variable
    if (MemVar >= 8){ // on 8th button press...
      MemVar = 1; // reset color
    }
    EEPROM.write(MemoryLocation, MemVar); // write color to memory
    ColorChoice = MemVar;
}

Cool :) Would be neat if it could run that way. Would it still be necessary to software de-bounce? One concern I have is that using the "delay 150ms" approach at the end of a button press will create problems for software PWM. The approach of simply counting button counts until a threshold was hit didn't really work well either. It needed at least 200+ counts at 1 Mhz, so at 8 Mhz it might need 1500+. The counter didn't seem to work when set to anything above 255.
 
Cool :) Would be neat if it could run that way. Would it still be necessary to software de-bounce? One concern I have is that using the "delay 150ms" approach at the end of a button press will create problems for software PWM. The approach of simply counting button counts until a threshold was hit didn't really work well either. It needed at least 200+ counts at 1 Mhz, so at 8 Mhz it might need 1500+. The counter didn't seem to work when set to anything above 255.

You can debounce with something like this:

Code:
void ISR()
{
  static unsigned long last_ISR = 0; // set static so it doesn't lose value on exit
  unsigned long interrupt_time = millis();
  // If interrupts come faster than 80ms, assume it's a bounce and ignore
  if (interrupt_time - last_ISR > 80) 
    (same ISR code as before)

  last_ISR = interrupt_time;
}

This should take care of any button issues. It will only be called on the rising edge, thus will not continue to be called if held down.

As for why it was overrunning at 255, it was probably a "byte" type which is only 8 bits ->2^8 = 0-255 possible values. If you need a variable to hold a larger number, "int" is (usually for 8-bit microcontroller) 2 bytes --> 2^16 = 0-65235 (if unsigned).
 
Probably needs an interrupt vector.

I think you're right. I saw other arduino code so thought that maybe the attachInterrupt function would work the same.

Check out the code near the bottom of this page:
Pin Change Interrupts on ATtiny85 | The Wandering Engineer

You'll only need an interrupt on PB3 so you'll just change out the mask line as so:
Code:
PCMSK = 0b00001000;    // turn on interrupts on pin PB3

And then just replace "void ButtonISR" with "ISR(PCINT0_vect)"

Edit: looking at the datasheet, it appears the ISR will be called anytime the pin changes. You may need to add in an if statement with a digitalRead() again to determine whether it is high or low.
 
Last edited:


Back
Top