attiny85 and TimerOne.h

I have been programming my ATTiny from an Ard Uno using this approach: http://hlt.media.mit.edu/?p=1229

im using the same method

I believe the HLT core uses Counter/Timer0 for millis(). Not sure if they use Timer1. If not, or if it's used for something you don't use or care about, you should be able to appropriate it.

.... not sure how to do that.... Could you pleaaaase help me?

ok i've been strangling with the code (im a complete newbie...)

//Pin connected to Pin 12 of 74HC595 (Latch)
int latchPin = 0;
//Pin connected to Pin 11 of 74HC595 (Clock)
int clockPin = 1;
//Pin connected to Pin 14 of 74HC595 (Data)
int dataPin = 2;
uint8_t led[8];
long counter1 = 0;
long counter2 = 0;
//unsigned long  time;
long previousMillis = 0; 
long interval = 10000;

void setup() {
//set pins to output
pinMode(latchPin, OUTPUT);
pinMode(clockPin, OUTPUT);
pinMode(dataPin, OUTPUT);
led[0] = B11111111;
led[1] = B10000001;
led[2] = B10111101;
led[3] = B10100101;
led[4] = B10100101;
led[5] = B10111101;
led[6] = B10000001;
led[7] = B11111111;
//Timer1.initialize(10000);
//Timer1.attachInterrupt(screenUpdate);
}
void loop() {
     

    
counter1++;
if (counter1 >=100000) {counter2++;}
if (counter2 >= 10000) {
counter1 = 0;
counter2 = 0;
for (int i=0; i<8; i++) {
led[i]= ~led[i];
}

}
unsigned long currentMillis = micros(); 
  if(currentMillis - previousMillis > interval) {
    // save the last time you blinked the LED
    previousMillis = currentMillis;
    screenUpdate();
}
delay(500);
}
void screenUpdate() {


uint8_t row = B00000001;
for (byte k = 0; k < 9; k++) {
// Open up the latch ready to receive data!
digitalWrite(latchPin, LOW);
shiftIt(~row );
shiftIt(led[k] ); // LED array
// Close the latch, sending the data in the registers out to the
//matrix
digitalWrite(latchPin, HIGH);
row = row << 1;
}
}

void shiftIt(byte dataOut) {
// Shift out 8 bits LSB first,
// on rising edge of clock
boolean pinState;
//clear shift register read for sending data
digitalWrite(dataPin, LOW);
// for each bit in dataOut send out a bit
for (int i=0; i<8; i++) {
//set clockPin to LOW prior to sending bit
digitalWrite(clockPin, LOW);
// if the value of DataOut and (logical AND) a bitmask
// are true, set pinState to 1 (HIGH)
if ( dataOut & (1<<i) ) {
pinState = HIGH;
}
else {pinState = LOW;
}
//sets dataPin to HIGH or LOW depending on pinState
digitalWrite(dataPin, pinState);
//send bit out on rising edge of clock
digitalWrite(clockPin, HIGH);
digitalWrite(dataPin, LOW);
}
//stop shifting
digitalWrite(clockPin, LOW);

}

but what it does is a very quick flickering .... But i believe is a start... :blush:

EDIT: So news...
If i upload the code to my arduino and use it works.
If i upload it to the ATtiny85 there goes the flickering again... So i suppose is has to do with the internal clock... Is there any way to fix this?

pyrforos:
.... not sure how to do that.... Could you pleaaaase help me?

I'll give it a shot, what's your clock frequency?

thank you
I believe is 8MHz(or 1???)

Well if you haven't changed the fuses from the factory setting, then it's using the internal 8MHz RC oscillator divided by eight, so the CPU clock is 1MHz.

I wrote this using WinAVR. I don't currently have the HLT core installed, but I did test it with Arduino Tiny and it worked (although I imagine it stepped all over its millis() function in the process, ha!). I think it should work with HLT, but I recommend you try it standalone first. Just copy the entire code below into a new sketch, wire an LED to pin 3 (on the DIP package, I assume you're using a DIP?) and see if it blinks on for a second, then off for a second.

If that works, then you only need about the last 30 lines of code as indicated by the comments, try adding those into your sketch. In your setup() function, replace "Timer1.initialize(10000);" and "Timer1.attachInterrupt(screenUpdate);" with "setupTimer1(screenUpdate);".

This is pretty much quick-and-dirty code for a very specific purpose, based on how I understood the requirement. Let me know how (if) it works for you!

//Example for Arduino forum.
//Use ATtiny85 Timer/Counter1 to call a function every 10ms.
//In setup(), call setupTimer1() and pass it the name of your function which will
//run as part of the interrupt service routine (ISR) every 10ms. This function must take no
//arguments, return nothing, and should run as quickly as possible. The delay() and millis()
//functions will not work while the ISR is running and so should be avoided.
//Works with 1MHz or 8MHz system clock (others may be possible, but I got lazy).
//
//In this example, the myISR() function simply turns an LED on for a second, then off for a second.
//Connect the LED to DIP pin 3 (PB4).
//
//Jack Christensen 18Oct2011
//
//Scotchware License: If we meet some day, and you think this is worth it, you can buy me a scotch.

#include <avr/io.h>
#include <avr/interrupt.h>

//function prototypes
void setupTimer1(void (*isrPointer)(void));
void setup(void);
void loop(void);
void myISR(void);

#define LED PORTB4                  //connect LED to this pin

#ifndef ARDUINO                     //main() function not required in Arduino environment
int main(void) {
    setup();
    for(;;) {loop();}
    return 0;
}
#endif

void setup(void) {
    DDRB |= _BV(LED);               //set the LED pin as an output
    setupTimer1(myISR);             //set timer1 up to call myISR every 10ms
}

void loop(void) {
}

void myISR() {                      //this function will be called every 10ms
    static uint8_t myCounter;

    if (++myCounter == 100) {       //has a second elapsed?
        myCounter = 0;
        PINB |= _BV(LED);           //toggle the LED
    }
}

//Copy code from here down, AND uncomment the following line and move it near the top of your sketch BEFORE the setup() function.
//void setupTimer1(void (*isrPointer)(void));        //function prototype for setupTimer1()
void (*userISR)(void);              //pointer to the user's ISR

void setupTimer1(void (*isrPointer)(void)) {
    userISR = isrPointer;           //save the pointer to the user's ISR
    //set timer1 up to generate an interrupt every millisecond
    TCCR1 |= _BV(CTC1);             //clear timer1 when it matches the value in OCR1C
    TIMSK |= _BV(OCIE1A);           //enable interrupt when OCR1A matches the timer value
    sei();                          //enable global interrupts
    OCR1A = 124;                    //set the match value for interrupt
    OCR1C = 124;                    //and the same match value to clear the timer
#if F_CPU == 1000000                //1MHz system clock
    TCCR1 |= _BV(CS12);             //set prescaler to divide by 8 (this starts the timer)
#elif F_CPU == 8000000              //8MHz system clock
    TCCR1 |= _BV(CS12) | _BV(CS11) | _BV(CS10);    //set prescaler to divide by 64 (this starts the timer)
#else
    Clock must be 1MHz or 8MHz!     //Error, only 1MHz or 8MHz clock (F_CPU) supported.
#endif
}

ISR(TIMER1_COMPA_vect) {            //handles the Timer1 Compare Match A interrupt
    static uint8_t interruptCount;

    if (++interruptCount == 10) {   //have there been 10 interrupts? (i.e. 10ms)
        interruptCount = 0;         //yes, reset the counter
        userISR();                  //and call the user's ISR
    }
}

a veryy big thanks mate!(LOL Scotchware License XD XD)

Well it blinks but for about 9 or 10 sec ,but if i chanche the value of

   if (++myCounter == 100) {       //has a second elapsed?

to
  if (++myCounter == 10) {       //has a second elapsed? is seems to be working :slight_smile: for the blinky

im sorry, doesn't work on the project... i tried to play with the values but with no success...

Is it maybe blinking every 8 seconds? Maybe it thinks the clock is 8MHz when it's actually 1MHz. Comment out the lines indicated below, this will hard-code it for a 1MHz clock.

//#if F_CPU == 1000000                //1MHz system clock
    TCCR1 |= _BV(CS12);             //set prescaler to divide by 8 (this starts the timer)
//#elif F_CPU == 8000000              //8MHz system clock
//    TCCR1 |= _BV(CS12) | _BV(CS11) | _BV(CS10);    //set prescaler to divide by 64 (this starts the timer)
//#else
//    Clock must be 1MHz or 8MHz!     //Error, only 1MHz or 8MHz clock (F_CPU) supported.
//#endif

it works but the flickering stays... its like the update function is actually enough slow to mess up your eyes

Thinking some more on this.

From what you've said, I suspect you are telling the IDE (via Tools > Board) that you have an ATtiny85 @ 8MHz, but in fact it's running at 1MHz. Have you reset the fuses from their factory default values? Can you use AVRDUDE to read out the fuse bytes? What are their values? The factory defaults are Low Fuse=0x62, High Fuse=0xDF, Extended Fuse=0xFF. If you will change the Low Fuse to 0xE2, that will change the clock to 8MHz, which will work better for you I think.

Choosing different clock frequencies via Tools > Board in the IDE does not change the clock frequency in the hardware, it just tells the compiler what speed the clock is set to. So obviously the two need to match.

Then also be sure to uncomment these lines in the code, despite my previous post:

#if F_CPU == 1000000                //1MHz system clock
    TCCR1 |= _BV(CS12);             //set prescaler to divide by 8 (this starts the timer)
#elif F_CPU == 8000000              //8MHz system clock
    TCCR1 |= _BV(CS12) | _BV(CS11) | _BV(CS10);    //set prescaler to divide by 64 (this starts the timer)
#else
    Clock must be 1MHz or 8MHz!     //Error, only 1MHz or 8MHz clock (F_CPU) supported.
#endif

sorry for the delay...
No i did not touch any of the fuses... i don't know how to...
im on linux so i cant use avrdude, only arduino IDE, and the only option in boards is the name of the chip am using.

Not sure about Linux, but on Windows, avrdude is installed as part of the Arduino IDE, under hardware\tools\avr\bin.

But, lacking that, you could also change the clock prescaler on the fly! I should look at HLT again, maybe it assumes an 8MHz clock. Let's proceed on that assumption, and also factory fuse settings. Enter these as the first two lines in setup() to set the clock to 8MHz:

    CLKPR = 0x80;    //set the Clock Prescaler Change Enable bit
    CLKPR = 0x00;    //set the Clock Prescaler to divide by one

I installed HLT, and all of the entries in the boards.txt file have 1MHz clocks. I added one with 8MHz as below (also modified the name on the existing one to be clear it's 1MHz).

# modified the next line only
attiny85usbtinyisp.name=ATtiny85 @ 1MHz (w/ USB Tiny ISP)
attiny85usbtinyisp.upload.using=arduino:usbtinyisp
attiny85usbtinyisp.upload.maximum_size=8192
attiny85usbtinyisp.build.mcu=attiny85
attiny85usbtinyisp.build.f_cpu=1000000L
attiny85usbtinyisp.build.core=attiny45_85

# new entry
attiny85usbtinyisp8.name=ATtiny85 @ 8 MHz (w/ USB Tiny ISP)
attiny85usbtinyisp8.upload.using=arduino:usbtinyisp
attiny85usbtinyisp8.upload.maximum_size=8192
attiny85usbtinyisp8.build.mcu=attiny85
attiny85usbtinyisp8.build.f_cpu=8000000L
attiny85usbtinyisp8.build.core=attiny45_85

HOWEVER, something is funny with my demo code. It works when the 8MHz board is selected via Tools > Boards, but when using the 1MHz entry, the LED only blinks every eight seconds. Haven't figured out why yet, but I think you observed the same thing earlier. The same code works as expected at 1MHz with WinAVR or Arduino Tiny. Anyhoo, add an 8MHz entry to boards.txt, and try the code below, the LED should blink every second.

//Example for Arduino forum.
//Use ATtiny85 Timer/Counter1 to call a function every 10ms.
//In setup(), call setupTimer1() and pass it the name of your function which will
//run as part of the interrupt service routine (ISR) every 10ms. This function must take no
//arguments, return nothing, and should run as quickly as possible. The delay() and millis()
//functions will not work while the ISR is running and so should be avoided.
//Works with 1MHz or 8MHz system clock (others may be possible, but I got lazy).
//
//In this example, the myISR() function simply turns an LED on for a second, then off for a second.
//Connect the LED to DIP pin 3 (PB4).
//
//Jack Christensen 18Oct2011
//
//Scotchware License: If we meet some day, and you think this is worth it, you can buy me a scotch.

#include <avr/io.h>
#include <avr/interrupt.h>

//function prototypes
void setupTimer1(void (*isrPointer)(void));
void setup(void);
void loop(void);
void myISR(void);

#define LED PORTB4                  //connect LED to this pin

#ifndef ARDUINO                     //main() function not required in Arduino environment
int main(void) {
    setup();
    for(;;) {loop();}
    return 0;
}
#endif

void setup(void) {
#if F_CPU == 8000000                //8MHz system clock
    CLKPR = 0x80;                   //set the Clock Prescaler Change Enable bit
    CLKPR = 0x00;                   //set the Clock Prescaler to divide by one (8Mhz assuming factory default fuses)
#endif
    DDRB |= _BV(LED);               //set the LED pin as an output
    setupTimer1(myISR);             //set timer1 up to call myISR every 10ms
}

void loop(void) {
}

void myISR() {                      //this function will be called every 10ms
    static uint8_t myCounter;
    
    if (++myCounter == 100) {       //has a second elapsed?
        myCounter = 0;
        PINB |= _BV(LED);           //toggle the LED
    }
}

//Copy code from here down, AND uncomment the following line and move it near the top of your sketch BEFORE the setup() function.
//void setupTimer1(void (*isrPointer)(void));        //function prototype for setupTimer1()
void (*userISR)(void);              //pointer to the user's ISR

void setupTimer1(void (*isrPointer)(void)) {
    userISR = isrPointer;           //save the pointer to the user's ISR
    //set timer1 up to generate an interrupt every millisecond
    TCCR1 |= _BV(CTC1);             //clear timer1 when it matches the value in OCR1C
    TIMSK |= _BV(OCIE1A);           //enable interrupt when OCR1A matches the timer value
    sei();                          //enable global interrupts
    OCR1A = 124;                    //set the match value for interrupt
    OCR1C = 124;                    //and the same match value to clear the timer
#if F_CPU == 1000000                //1MHz system clock
    TCCR1 |= _BV(CS12);             //set prescaler to divide by 8 (this starts the timer)
#elif F_CPU == 8000000              //8MHz system clock
    TCCR1 |= _BV(CS12) | _BV(CS11) | _BV(CS10);    //set prescaler to divide by 64 (this starts the timer)
#else
#error Only 1MHz or 8MHz clock (F_CPU) supported!
#endif
}

ISR(TIMER1_COMPA_vect) {            //handles the Timer1 Compare Match A interrupt
    static uint8_t interruptCount;
    
    if (++interruptCount == 10) {   //have there been 10 interrupts? (i.e. 10ms)
        interruptCount = 0;         //yes, reset the counter
        userISR();                  //and call the user's ISR
    }
}

I figured it out. The HLT core uses Timer/Counter1 for PWM, so there were some conflicting values set in TCCR1. Changed the code below to ruthlessly set the registers as it needs them. So, if you want to use PWM, it may not work, and will certainly not work the same. If you don't need it, then this approach could be OK.

The code below should blink the LED once per second when used with HLT either with a clock frequency of 1MHz or 8MHz. It assumes the ATtiny85 has default factory fuse settings, and if compiled for 8MHz, it adjusts the clock prescaler register accordingly. For your application, I'd definitely run at 8MHz, because it sounds like you're doing some sort of multiplexing and the speed is important.

//Example for Arduino forum.
//Use ATtiny85 Timer/Counter1 to call a function every 10ms.
//In setup(), call setupTimer1() and pass it the name of your function which will
//run as part of the interrupt service routine (ISR) every 10ms. This function must take no
//arguments, return nothing, and should run as quickly as possible. The delay() and millis()
//functions will not work while the ISR is running and so should be avoided.
//Works with 1MHz or 8MHz system clock (others may be possible, but I got lazy).
//If used with the HTL core (http://hlt.media.mit.edu/?p=1229), PWM may not work,
//as HLT uses Timer/Counter1 for PWM.
//
//In this example, the myISR() function simply turns an LED on for a second, then off for a second.
//Connect the LED to DIP pin 3 (PB4).
//
//Jack Christensen 18Oct2011
//
//Scotchware License: If we meet some day, and you think this is worth it, you can buy me a scotch.

#include <avr/io.h>
#include <avr/interrupt.h>

//function prototypes
void setupTimer1(void (*isrPointer)(void));
void setup(void);
void loop(void);
void myISR(void);

#define LED PORTB4                  //connect LED to this pin

#ifndef ARDUINO                     //main() function not required in Arduino environment
int main(void) {
    setup();
    for(;;) {loop();}
    return 0;
}
#endif

void setup(void) {
#if F_CPU == 8000000                //8MHz system clock
    CLKPR = 0x80;                   //set the Clock Prescaler Change Enable bit
    CLKPR = 0x00;                   //set the Clock Prescaler to divide by one (8Mhz assuming factory default fuses)
#endif
    DDRB |= _BV(LED);               //set the LED pin as an output
    setupTimer1(myISR);             //set timer1 up to call myISR every 10ms
}

void loop(void) {
}

void myISR() {                      //this function will be called every 10ms
    static uint8_t myCounter;
    
    if (++myCounter == 100) {       //has a second elapsed?
        myCounter = 0;
        PINB |= _BV(LED);           //toggle the LED
    }
}

//Copy code from here down, AND uncomment the following line and move it near the top of your sketch BEFORE the setup() function.
//void setupTimer1(void (*isrPointer)(void));        //function prototype for setupTimer1()
void (*userISR)(void);              //pointer to the user's ISR

void setupTimer1(void (*isrPointer)(void)) {
    userISR = isrPointer;           //save the pointer to the user's ISR
    //set timer1 up to generate an interrupt every millisecond
    TCCR1 = _BV(CTC1);              //clear timer1 when it matches the value in OCR1C
    TIMSK |= _BV(OCIE1A);           //enable interrupt when OCR1A matches the timer value
    sei();                          //enable global interrupts
    OCR1A = 124;                    //set the match value for interrupt
    OCR1C = 124;                    //and the same match value to clear the timer
#if F_CPU == 1000000                //1MHz system clock
    TCCR1 |= _BV(CS12);             //set prescaler to divide by 8 (this starts the timer)
#elif F_CPU == 8000000              //8MHz system clock
    TCCR1 |= _BV(CS12) | _BV(CS11) | _BV(CS10);    //set prescaler to divide by 64 (this starts the timer)
#else
#error Only 1MHz or 8MHz clock (F_CPU) supported!
#endif
}

ISR(TIMER1_COMPA_vect) {            //handles the Timer1 Compare Match A interrupt
    static uint8_t interruptCount;
    
    if (++interruptCount == 10) {   //have there been 10 interrupts? (i.e. 10ms)
        interruptCount = 0;         //yes, reset the counter
        userISR();                  //and call the user's ISR
    }
}

hi again..
wow! you did some work! I apologise again for the delay but i've been craaazy running...
so i tried your code with the attiny85 and i get this error on compile

In file included from /usr/lib/gcc/avr/4.5.3/../../../avr/include/util/delay.h:44:0,
                 from /usr/lib/gcc/avr/4.5.3/../../../avr/include/avr/delay.h:37,
                 from /home/pyrforos/Documents/electronic projects/hardware/attiny45_85/cores/attiny45_85/wiring_private.h:32,
                 from /home/pyrforos/Documents/electronic projects/hardware/attiny45_85/cores/attiny45_85/WInterrupts.c:36:
/usr/lib/gcc/avr/4.5.3/../../../avr/include/math.h:426:15: error: expected identifier or ‘(’ before ‘double’
/usr/lib/gcc/avr/4.5.3/../../../avr/include/math.h:426:15: error: expected ‘)’ before ‘>=’ token

pyrforos:
hi again..
wow! you did some work! I apologise again for the delay but i've been craaazy running...
so i tried your code with the attiny85 and i get this error on compile

Not sure what's going on there. Did you try to run the code standalone, exactly as I posted? Do that first, before trying to integrate it into your project, just to be sure it works as expected.

I'm confused by those error messages, as my example code uses neither double nor math.h. I copied my latest code from the post above, and it compiles fine either with HLT or with Arduino Tiny. Your compile errors seem to be in math.h. Have you made changes in that area? If not, I might consider a reinstall, as it may have been changed inadvertently.

Sorry to pull this old post out from the dead but I have a few questions as to the operation of Jack's code. It's been extremely helpful to me and I've been spending quite a bit of time poking and prodding at it as I try to implement a software PWM for the ATTiny.

My questions are specific to this part of the code:

If I understand this correctly, the prescalar TCCR1, as set here, waits for 64 clock ticks and then increments the Timer/Counter by 1, and then when the Timer/Counter reaches 124 (the value of OCR1A) it triggers the interrupt. Then per your ISR you wait for 10 interrupts before you trigger the user's ISR function.

Apparently there's a bit of a balance here with these three different tunable values and that brings me to two questions. Would it be accurate to suggest that OCR1A and OCR1C be divided by 10 and then eliminate the interruptCount block could be eliminated? Also, is it most efficient to set the highest, appropriate prescalar and then adjust OCR1A/OCR1C values afterwards or does the balance between those values not yield any benefit?