How to convert - Uno -> ATtiny85

I have a code which run on UNO and I would really prefer if I could use ATtiny85.
But my knowledge of interrupts is not good, so I hope for some help.

#include "SSD1306Ascii.h"                          
   #include "SSD1306AsciiAvrI2c.h"              
   #define I2C_ADDRESS 0x3C                     
   SSD1306AsciiAvrI2c OLED; 
//*********************************** varable definitions  *********************
   unsigned long abort_time = millis();
   float rpm ;
   volatile byte intp_flag = 0 ;
   byte intrp_pin = 3 ;
   volatile unsigned long start_time = 0 ;   //start platen index pulse time value
   volatile unsigned long end_time   = 0 ;   //end platen index time value
//************************************************************************
void setup() {
  OLED.begin(&Adafruit128x32, I2C_ADDRESS);
  OLED.setFont(ZevvPeep8x16);
  // --- Measuring pin --------------------------------------------------------------  
  pinMode(intrp_pin, INPUT_PULLUP); //set interrupt pin for arduino uno must be pin 3
  vis();
}
//************************************************************************
void loop(){
  rpm_calc() ;       //rpm function calculation
  disp_msg() ;       //display function
  delay(1000) ;
}
//*************************** rpm calculation  **************************************
void rpm_calc(){
  float calc_time  = 0;
  interrupt_handle() ;     //read the start index pulse time
  calc_time = (end_time - start_time) / 1000000.0;
  rpm = ( 1.0 / calc_time) * 60.0 ;
}
//*******************************interrupt handle function ***************************
void interrupt_handle(){
  intp_flag   = 0 ;
  abort_time = millis();
  attachInterrupt(digitalPinToInterrupt(3), index_pulse_time, FALLING);
  do{
    if  (millis() - abort_time > 5000){pwr_off_msg();}
  } while (intp_flag <= 2) ;
  detachInterrupt(digitalPinToInterrupt(3));
}
//********************************read time  function ******************************
void  index_pulse_time2(){
  if (intp_flag == 1) {
    start_time = micros(); //read index start time
  }
  if (intp_flag == 2){
    end_time = micros(); //read index end time
  }
  intp_flag = intp_flag + 1 ;
}
//*********************************display rpm function ***************************
void disp_msg(){
   OLED.setCursor(0,2);OLED.print("           ");
   OLED.setCursor(0,2);OLED.print("RPM: ");OLED.print(rpm,2);
}
//*****************************no switch Power OFFF message **********************
void  pwr_off_msg(){                                             
  do{
   OLED.setCursor(0,2);OLED.print("          "); 
   OLED.setCursor(0,2);OLED.print("Power off");
   delay(1000);
  }while (digitalRead(3) != 1);
}
//******************************************************************************
void  index_pulse_time(){
  switch (intp_flag) {
    case 0:break;
    case 1:start_time = micros();break;
    case 2:end_time = micros();
  }
  intp_flag = intp_flag + 1 ;
}
//***************************************************************************
void vis(){
   OLED.clear();
   OLED.setCursor(0,0);                      
   OLED.print("Beogram 1000");  
}
//***************************************************************************

Does that OLED display library create a frame buffer? If so, it's not compatible with the t85 because the frame buffer would be 128x32 bits, which is 128×4 =512 bytes which is how much ram is available in total on the t85 leaving no room for other variables in ram.

Many of the adafruit libraries dynamically allocate buffers, so you dont fet a warning at compile tine about available ram

The libraries:

   #include "SSD1306Ascii.h"                         
   #include "SSD1306AsciiAvrI2c.h"

are compatible with ATtiny85 and dont create a frame buffer.

I am using the libraries in several other sketcehs for ATtiny 85

INT0
PB2
Arduino pin 2

If this is not the answer you need a more informative question might be in order.

You are using external interrupts to measure the period between two pulses.
On the uno (ATmega328p) you have a choice of two pins (int0 and int1). On the attiny85 you have only int0.
If int0 is not free on the attiny85, you may be able to use pin change interrupts instead because these support more pins.

Thank you for taking your time to help.

The point of interrupt for ATtiny 85 - PB2.

I have changed to PB2 before trying to load the code to ATtin85.

This is the part of the code changed:

void interrupt_handle(){
  intp_flag = 0;abort_time = millis();
  attachInterrupt(digitalPinToInterrupt(2), index_pulse_time, FALLING);
  do{
    if(millis() - abort_time > 5000){pwr_off_msg();}
  }while(intp_flag <= 2) ;
  detachInterrupt(digitalPinToInterrupt(2));
}

This is not the solution.

error:

exit status 1
'digitalPinToInterrupt' was not declared in this scope

Then I tried to remove “digitalPinToInterrupt”
and try loading this code

void interrupt_handle(){
  intp_flag = 0;abort_time = millis();
  attachInterrupt(2, index_pulse_time, FALLING);
  do{
    if(millis() - abort_time > 5000){pwr_off_msg();}
  }while(intp_flag <= 2) ;
  detachInterrupt(2);
}

I got a long list of errors like:

error: ‘TWCR’ was not declared in this scope
error: ‘TWSR’ was not declared in this scope
error: ‘TWINT’ was not declared in this scope

I have a feeling using the "detachInterrupt(2);"
is the problem ???

Well, instead of:
detachInterrupt(digitalPinToInterrupt(2));

You could just use:
detachInterrupt(0 );

The same with attachInterrupt().

Which Attiny Arduino core are you using ?

I am using:
#include "SSD1306Ascii.h"
#include "SSD1306AsciiAvrI2c.h"

for ATtiny85

as you can see in the "full sketch" in the top post.

classic:
I am using:
#include "SSD1306Ascii.h"
#include "SSD1306AsciiAvrI2c.h"

for ATtiny85

as you can see in the "full sketch" in the top post.

I think you have misunderstood the question.
You must of added a core to the arduino IDE to allow you to generate code for the ATTiny series.
DrAzzy, author of post #1 in this thread maintains one. There is at least one other produced by damellis

Odd is that digitalPinToInterrupt() appears not to be supported.

TWSR and the rest of them being undefined indicates that you're using an I2C library that doesnt support the ATTiny parts (which have a USI instead of TWI peripheral of the atmega parts). It looks like avri2c display library is the offender here. Since you didnt post the full error or where the library comes from I couldn't tell you if its pulling in an incompatible version of Wire.h or implements i2c itself - if it's the former, my ATTinyCore (v1.1.x or later, iirc) includes a version of Wire.h that selects a compatible i2c implementation for the hardware you're running on; if the latter, that library cannot be made to work on the tinies without a major overhaul (reimplementing its i2c stuff to use the usi)

You also are trying to busywait in an ISR - that wont work, because interrupts are disabled while in another ISR, so millis() will not increase and it will spin forever. It would be highly likely to cause other problems as well - ISRs should aim to run almost instantly. Millis() will be thrown off if the ISR takes longer than around 1 ms to run, received serial characters will be lost before that, and so on. Only work which can only be done in the ISR should be done there.

#include “SSD1306Ascii.h” #include “SSD1306AsciiAvrI2c.h”
The library I am using is found [here:]https://github.com/greiman/SSD1306Ascii[/url]

Loading the ATtiny85:
Arduino IDE v1.8.10 - and using UNO as ISP.


I have now found the following possible problem:
I am using an OLED display - I2C - 128x32 - pin on ATtiny85 PB2 (pin7) and PB0 (pin5)

I need an external interrupt function - using and infrared “tracker sensor”.
As i can understand the ATtiny85 pin for external interrupt is also PB2 (pin7).


I have really been using Google but I cannot find any suggestions how to solve this or
actually exampels of

ATtiny85 <-> OLED I2C display <-> infrared tracker sensor

I am hoping for suggestions of how to solve this problem.
I have of course the application running on UNO.

The application is a speed measuring modul for a gramophone.

OK. If you have a spare Attiny85 pin, you may be able to use a pin-change interrupt instead of an external interrupt (repeated from post #4). Post a schematic diagram of your circuit (picture of a hand drawn circuit is OK) so it is clear which pins you have free.

Just to be clear, you have said that the OLED / ATtiny85 combination works for you in other projects so the issue is purely with the external interrupt ?

Edit:
Maybe this helps: Pin Change Interrupts on ATtiny85 – The Wandering Engineer

I have a spare pin - PB1 (pin6)
I have attached a circuit diagram and the dotted line is the output of the infrared modul to PB1.

To your question:
The code / sketch is working on UNO (different pinning of course).

OP's circuit:

OK. Try:

  1. changing intrp_pin to 1.
  2. add this in setup(): GIMSK = 0b00100000; // turns on pin change interrupts
  3. replace attachInterrupt(digitalPinToInterrupt(3), index_pulse_time, FALLING) with: PCMSK = 0b00000010 ;
  4. replace detachInterrupt(digitalPinToInterrupt(3)) with: PCMSK = 0b00000000 ;
  5. rename function index_pulse_time() to: ISR(PCINT0_vect)

You should also consider restructuring the sketch. Apart from what has already been mentioned about using millis() in an ISR, your attaching and detaching interrupts is odd. Better would be to leave these attached and determine the new state on any change in the ISR.

6v6gt - Thank you very much.
I will have to wait until tomorrow for changing and testing.
I will be back :slight_smile:

The SSD1306AsciiAvrI2c.h pulls in it's own avri2c library. Said library does not appear to be compatible with the tiny85 ir other devices that use a USI.

If you have previously made those displays work on a tiny85 (it sounds like you have), go back to your old working code and figure out what was different there. There is no way that the libraries you linked ever worked on the t85, utility/Avri2c in that library, pulled in by SSD1306AsciiAvrI2c, relies on registers that dont exist on the t85. So either you had a magic version of the library that was compatible with the tiny and used that, or you used a different library.

His problem is not just with external interrupt! The external interrupt issue is comparatively small at this point (and several of us clearly know how to solve it); until hes got the display sorted, all the interrupt-fun the world wont mak this compile.

DrAzzy - This is very important information for me. I will stop using this library of course.
Yes I have a couple of applications with this library .
These application drives display's and as input - the A0 (analog) - TrueRMA meter modules.
And in these application - NO need at all for sensors / interrupt.

I will use another library with a small foodprint for ATtiny85.
The ATTinyCore are developed by you?

Perhaps you have an exampel which I could build the design on.

6v6gt:
OP's circuit:

OK. Try:

  1. changing intrp_pin to 1.
  2. add this in setup(): GIMSK = 0b00100000; // turns on pin change interrupts
  3. replace attachInterrupt(digitalPinToInterrupt(3), index_pulse_time, FALLING) with: PCMSK = 0b00000010 ;
  4. replace detachInterrupt(digitalPinToInterrupt(3)) with: PCMSK = 0b00000000 ;
  5. rename function index_pulse_time() to: ISR(PCINT0_vect)

You should also consider restructuring the sketch. Apart from what has already been mentioned about using millis() in an ISR, your attaching and detaching interrupts is odd. Better would be to leave these attached and determine the new state on any change in the ISR.

6v6gt
I have implemented your suggestion.
When compiling / loading the code to ATtiny85 - I am getting this error:

expected unqualified-id before string constant

for this: void ISR(PCINT0_vect)

Another point - what should the index_pulse_time2() be changed to?

void ISR(PCINT0_vect){
  switch(intp_flag){
    case 0:break;
    case 1:start_time = micros();break;
    case 2:end_time = micros();
  }
  intp_flag = intp_flag + 1;
}
//******************************************************
void index_pulse_time2(){
  if(intp_flag == 1){start_time = micros();}   //read index start time
  if (intp_flag == 2){end_time = micros();}    //read index end time
  intp_flag = intp_flag + 1 ;
}

I did change some of the other suggestion in the code too.
The full code for ATtiny85 is here:
(The code is not working - see the earlier post)

   #include "SSD1306Ascii.h"                          
   #include "SSD1306AsciiAvrI2c.h"           
   #define I2C_ADDRESS 0x3C                     
   SSD1306AsciiAvrI2c OLED;
//***********************************varable definitions *******************************
   unsigned long abort_time;
   float rpm ;
   volatile byte intp_flag = 0 ;  
   volatile unsigned long start_time = 0 ;   //start platen index pulse time value
   volatile unsigned long end_time   = 0 ;   //end platen index time value
//*********************************************************************************
void setup() {
  OLED.begin(&Adafruit128x32, I2C_ADDRESS);
  OLED.clear();
  // --- Measuring pin --------------------------------------------------------------  
  pinMode(1, INPUT_PULLUP);
  GIMSK = 0b00000000;    //pin change interrupts
  PCMSK = 0b00000010;    // Attach interrupt
  // --- Start text -----------------------------------------------------------------
  vis();
}
//*********************************************************************************
void loop(){
  rpm_calc() ;       //rpm function calculation
  disp_msg() ;       //display function
  unsigned long waitMillis= millis(); 
  while(millis() - waitMillis < 1000);
}
//*************************** rpm calculation  *****************************************
void rpm_calc(){
  float calc_time  = 0;
  interrupt_handle() ;     //read the start index pulse time
  calc_time = (end_time - start_time) / 1000000.0;
  rpm = ( 1.0 / calc_time) * 60.0 ;
}
//*******************************interrupt handle function *******************************
void interrupt_handle(){
  intp_flag = 0;abort_time = millis();
  do{if(millis() - abort_time > 5000){pwr_off_msg();}
  }while(intp_flag <= 2);
}
//*********************************************************************************************
void ISR(PCINT0_vect){
  switch(intp_flag){
    case 0:break;
    case 1:start_time = micros();break;
    case 2:end_time = micros();
  }
  intp_flag = intp_flag + 1;
}
//********************************read time  function ********************************
void index_pulse_time2(){
  if(intp_flag == 1){start_time = micros();}   //read index start time
  if (intp_flag == 2){end_time = micros();}    //read index end time
  intp_flag = intp_flag + 1 ;
}
//*********************************display rpm function *******************************
void disp_msg(){
   OLED.clear();OLED.setFont(ZevvPeep8x16);
   OLED.setCursor(0,2);OLED.print("RPM: ");
   OLED.setCursor(40,0);
   OLED.setFont(fixednums15x31);
   OLED.print(rpm,2);
}
//*****************************no switch Power OFFF message ************************
void pwr_off_msg(){
  OLED.setFont(ZevvPeep8x16);OLED.clear();                                             
  do{OLED.setCursor(30,2);OLED.print("POWER OFF");
  unsigned long waitMillis= millis(); while(millis() - waitMillis < 500);
  }while(digitalRead(1) != 1);
}
//**********************************************************************************
void vis(){
  OLED.setFont(ZevvPeep8x16);OLED.clear();
  OLED.setCursor(0,0);OLED.print("Thorens TD124-II"); 
  unsigned long waitMillis = millis(); 
  while (millis() - waitMillis < 3000); 
}
//**********************************************************************************
  1. remove the void return type from here:

void ISR( PCINT0_vect )

  1. where is this routine referenced in your sketch ? :

void index_pulse_time2()

If you post error messages from the compilation process, please include all the errors message(s) listed in the log. For example, are you still seeing a shower of error messages as listed at the end of your post #5 ?

Edit:

I've just noticed that you have not correctly answered this question from post #11:

Just to be clear, you have said that the OLED / ATtiny85 combination works for you in other projects so the issue is purely with the external interrupt ?

It was not referring to the Uno, it was referring to the combination of libraries that you are using and the ATtiny85.
#include "SSD1306Ascii.h"
#include "SSD1306AsciiAvrI2c.h"

Have you had these all working together in other projects ? From what DrAzzy has said in #15, this is unlikely.