ATTiny85 not sending data over I2C

I'm using the Adafruit 7 Segment LED Backpack in a project. But, when I connect it to the Tiny, it doesn't change at all. It has power, as the green light is on. It is running off of 5V, which is in its specification. It's not a problem with the display, as I tested it with CircuitPython on a Pi Pico (at 3V if that's important) and it worked fine. That leads me to believe it's a problem with the code. My code is below. It compiles without issue, and connecting an LED to flash at certain points, it is indeed running the code - but the display is not reacting. I have double checked my wiring and it is in the correct pins. The tiny is running at 1MHz. There are pull-up resistors built into the LED Backpack. Please help.

/* SevenSegTest_tiny
  This is a demonstration of using the Adafruit 4-digit 
  7-segment LED backpack with an ATtiny uC. 
  http://www.adafruit.com/category/37_103 
  ht16
  It requires the TinyWireM library for I2C communication
  and the Tiny_LEDBackpack library for the various display
  functions.  
  TinyWireM library obtained from http://www.scenelight.nl/?wpfb_dl=22
  
   NOTE: Tested successfully on ATtiny85, using 4700ohm pull-up
   resistors on SCL and SDA lines. Tested using 1MHz internal clock.
   ATtiny85 physical pin7 --> SCL pin on LED Backpack
   ATtiny85 physical pin5 --> SDA pin on LED Backpack
   
   NOTE: Tested successfully on ATtiny84, using 4700ohm pull-up
   resistors on SCL and SDA lines. Tested using 1MHz internal clock
   ATtiny84 physical pin9 --> SCL pin on LED Backpack
   ATtiny84 physical pin7 --> SDA pin on LED Backpack
   
   Tested with and without AVRISP mkII hooked up, works fine both
   ways.
   
   Additionally tested on ATtiny84 using 8MHz internal clock. To
   enable this functionality, you must alter the USI_TWI_Master.h
   file in the TinyWireM library to run at 8MHz. Search for the 
   line near the top that reads:
   #define SYS_CLK   1000.0  // [kHz]	Default for ATtiny2313
   and change the 1000 to 8000. 
   
   Also tested with 10k ohm pull-up resistors on SDA and SCL lines.
   
  This demo also uses a regular LED attached to 
  ATtiny84 physical pin 2 (Arduino pin 10) to show 
  that the sketch is running. 
*/
#include <TinyWireM.h>
#include <Tiny_LEDBackpack.h>

Tiny_7segment sevenseg = Tiny_7segment();
int led = 10; // indicator LED for ATtiny84. Connect with 100-470ohm resistor

#define i2c_addr 0x70 // stock address for Adafruit 7-segment LED backpack

void setup() {
  pinMode(led, OUTPUT);
  digitalWrite(led,HIGH);
  delay(1500);
  digitalWrite(led,LOW);
  delay(300); 
  sevenseg.begin(i2c_addr); // initialize HT16K33 controller
//  sevenseg.blinkRate(2); // set blink rate (0,1,2 or 3)
  sevenseg.clear(); // clear all digits on display
  sevenseg.writeDisplay(); // push data to display
  delay(1000);
}

void loop(){
  sevenseg.drawColon(true); // draw colon
  sevenseg.writeDisplay(); // push data to display
  delay(500);
  // Example of writing a multi-digit integer to the display
  sevenseg.print(1234); // print integer
  sevenseg.writeDisplay(); // push data to display
  delay(500);
  // Example of writing a multi-digit floating point number
  // to the display. The 2nd argument specifies 
  // how many digits to display after the decimal. Omit the 
  // 2nd argument for integer values. 
  sevenseg.print(56.7, 1); // print a floating point number
  sevenseg.writeDisplay(); // push data to display
  delay(500);
  sevenseg.clear(); // clear display before writing raw digit
  sevenseg.writeDisplay();
  
  // Example of writing a single digit to a specified position on the
  // display. The 1st argument is the digit position (0,1,3,4), 2nd
  // value is the numeric value to display (0-9, a-F), and the 3rd 
  // value is whether to show the decimal point. Note that if you
  // don't clear the display ahead of time, any previously displayed 
  // values in other digits will remain visible. Digit position 2 is
  // the colon, so we don't try to write numbers to it. 
  sevenseg.writeDigitNum(3, 9, true); // position 3, value 9, show decimal)
  sevenseg.writeDisplay(); // push the data to the display
  delay(500);

  //-----------------------------------------------------------------
  // Example of a hard-coded write using the
  // TinyWireM library by itself. This doesn't use the Tiny_LEDBackpack
  // library at all. 
//  delay(100);
//  TinyWireM.beginTransmission(0x70); // device address
//  TinyWireM.send(0x02); // digit address (0x00, 0x02, 0x06, 0x08)
//  TinyWireM.send(0x4F); // send bitmask for number to display
//  TinyWireM.endTransmission(); // push data to display
//  TinyWireM.beginTransmission(0x70); //device address
//  TinyWireM.send(0x08); // starting address (4th digit = 0x08)
//  TinyWireM.send(0x7F); // send bitmask for number to display
//  TinyWireM.endTransmission(); // push data to display  
   //----------------------------------------------------------------
   
   //----------------------------------------------------------------
   // Hard coded example of turning on colon using TinyWireM library
//   TinyWireM.beginTransmission(0x70);
//   TinyWireM.send(0x04);  // position of colon
//   TinyWireM.send(0xFF); // send a 255 to turn on the colon
//   TinyWireM.endTransmission(); // push data to display
//   delay(500);
   //----------------------------------------------------------------
   
  //----------------------------------------------------------------- 
  // Bit mask codes. These can be used with writeDigitRaw to
  // print various letters and symbols in a digit on the
  // seven segment LED display. 
  // The first argument is the position
  // on the 4-digit display, starting at 0 (far left),
  // ending at 4 (far right), with position 2 being 
  // the colon (so you'll skip this position usually).
  // The second argument is an integer that corresponds
  // to the binary representation of the combination of
  // 7 segments making up each digit. 
  //         0
  //      ------
  //   5  |     | 1
  //      |  6  |
  //      ------ 
  //   4  |     | 2
  //      |     |
  //      ------   o7 
  //         3
  // For example, to make upper case A, you want to 
  // light up segments 0,1,2,4,5,6.
  // The binary representation would be b01110111.
  //           The bit positions are -->b76543210
  // The corresponding integer value is 119 for A. 
  // Use a binary-to-decimal calculator to convert.
  // Below is a list of codes for letters and symbols
//  sevenseg.writeDigitRaw(0,119); // 119 = "A"
//  sevenseg.writeDigitRaw(0,124); // 124 = "b"
//  sevenseg.writeDigitRaw(0,57); // 57 = "C"
//  sevenseg.writeDigitRaw(0,94); // 94 = "d"
//  sevenseg.writeDigitRaw(0,121); // 121 = "E"
//  sevenseg.writeDigitRaw(0,113); // 113  = "F"
//  sevenseg.writeDigitRaw(0,125); // 125 = "G"
//  sevenseg.writeDigitRaw(0,118); // 118 = "H"
//  sevenseg.writeDigitRaw(0,116); // 116 = "h"
//  sevenseg.writeDigitRaw(0,6); // 6 = "I" aka 1
//  sevenseg.writeDigitRaw(0,4); // 4 = "i"
//  sevenseg.writeDigitRaw(0,30); // 30 = "J"
//  sevenseg.writeDigitRaw(0,56); // 56 = "L"
//  sevenseg.writeDigitRaw(0,84); // 84 = "n"
//  sevenseg.writeDigitRaw(0,92); // 92 = "o"
//  sevenseg.writeDigitRaw(0,115); // 115 = "P"
//  sevenseg.writeDigitRaw(0,103); // 103 = "q" aka 9
//  sevenseg.writeDigitRaw(0,80); // 80 = "r"
//  sevenseg.writeDigitRaw(0,109); // 109 = "S" aka 5
//  sevenseg.writeDigitRaw(0,70); // 70 = "t"
//  sevenseg.writeDigitRaw(0,28); // 28 = "u"
//  sevenseg.writeDigitRaw(0,62); // 62 = "U"
//  sevenseg.writeDigitRaw(0,110); // 110 = "y"
//  sevenseg.writeDigitRaw(0,64); // 64 = "-" negative sign
//  sevenseg.writeDigitRaw(0,34); // 34 = " " " double quote
//  sevenseg.writeDigitRaw(0,32); // 32 = "'" apostrophe (upper left)
//  sevenseg.writeDigitRaw(0,2); // 2 = "'" apostrophe (upper right)  
//  sevenseg.writeDigitRaw(0,8); // 8 = "_" underscore
//  sevenseg.writeDigitRaw(0,1); // 1 = "-" overbar
//  sevenseg.writeDigitRaw(0,16); // 16 = lower left bar
//  sevenseg.writeDigitRaw(0,4); // 4 = lower right bar
//  sevenseg.writeDigitRaw(0,128); // 128 = "." decimal
//  sevenseg.writeDigitRaw(0,0); // blank
//  sevenseg.writeDigitRaw(2,255); // 255 = ":"  colon, always position 2
/* *********************
   Always follow a writeDigitRaw command with the
   writeDisplay(); command to push the data to the
   display.
************************ */
//  sevenseg.writeDisplay(); // push data to display

  // Example using writeDigitRaw to write numbers or characters
  // to specific digits on the display. This spells 'run'.
  sevenseg.writeDigitRaw(0,80); // specify position and code, 80 = 'r'
  sevenseg.writeDigitRaw(1,28); // specify position and code, 28 = 'u'
  sevenseg.writeDigitRaw(3,84); // specify position and code, 84 = 'n'
  sevenseg.writeDisplay(); // push data to display
  delay(1000);


  //---------------------------------------------------------------
  // A cute trick to make a little "processing" indicator
  // This will light each of the outer segments of a digit
  // in series, making a rotating indicator. The outer 
  // segments are conveniently set up with bit mask values
  // that are increasing multiples of 2.
  sevenseg.clear(); 
  sevenseg.writeDisplay();
  for (int wait = 0; wait < 3; wait++) { // repeat multiple times
    for (int i = 1; i < 64; i *= 2) {
      sevenseg.writeDigitRaw(0,i);
      sevenseg.writeDisplay(); // push data to display
      delay(100);
    }
  }
  //-----------------------------------------------------------------
  // Another animation that lights each of the decimal points in
  // succession. 
  for (int wait = 0; wait < 3; wait++) { // repeat multiple times
    for (int i = 0; i < 5; i++) {
     if (i == 2) i++;  // This is needed to skip over position 2
     sevenseg.writeDigitRaw(i,128); // light the decimal at position i
     sevenseg.writeDisplay();  // push data to display
     delay(100);
     sevenseg.writeDigitRaw(i,0); // clear the decimal at position i
     sevenseg.writeDisplay(); // push data to display
    }
  }
  
  // Flash the external LED to indicate that the sketch is running
  // in case the 7-segment LED display isn't working.
  digitalWrite(led,HIGH);
  delay(200);
  digitalWrite(led,LOW);
  delay(200);

}

Yes, I am just using the example code..

1. I would like to suggest you to operate the display unit first using Arduino UNO. After that migrate those codes to ATtiny85 having change as nedeed.

2. Are you programming stand-alone ATtint85 using AVR Programmer or Parallel Programmer?

3. Are you programming ATtiny85 using Digispark ATtiny85 Dev Board (Fig-1)? This is a very convenient Platform that I use to develop ATtiny85 based product/project.
image
Figure-1:

4. Are you using ATTinyCore for the MCU?

Does not exist for ATtiny85? If using ATTinyCore, then 0, ..., 5 are valid numerical numbers for PB0, ..., PB5 port pins.

1: It does indeed work with an Arduino UNO R3. The Tiny_LEDBackpack library is a rewrite of the original, meaning it should work - but it doesn't.

2: I'm using the Tiny AVR Programmer from Sparkfun.

3: I'm just using a bare ATTiny85 in the programmer.

4: That was a mistake - I accidentally left that in. I do know that it only has pins 0 to 5, and I used those when testing with an LED. I'm plugging in I2C to SDA - 0, and SCL - 2.

Are you using Arduino IDE to develop the sketch for your ATtiny85? If so, you need to install the ATTinyCore and then fuse the Intel-Hex fromatted file into the MCU using the your AVR Programmer.

Yes, I am using ATTinyCore, and I am using the 'Upload Using Programmer' Button. Code does send to it, and it does run it. It just doesn't seem to be sending data to the display.

Can you try the following sketch to check that your-I2C display unit is detected at address 0x70? Connect a LED at PB1-pin with a series resistor to indicate error message.

#include<Wire.h>
#define LED 1    //PB1 = MISO pin onboard LED

void setup()
{
  Wire.begin();
  pinMode(LED, OUTPUT);

  //-------system reset indication-----
  for (int i = 0; i < 3; i++)
  {
    digitalWrite(LED, HIGH);
    delay(200);
    digitalWrite(LED, LOW);
    delay(200);
  }
 
  Wire.beginTransmission(0x70);
  byte busStatus = Wire.endTransmission();
  if (busStatus != 0)
  {
    while(true)  //display is not found
	{
	   	    digitalWrite(LED, HIGH);
    		delay(100);
    		digitalWrite(LED, LOW);
    		delay(100);
	}
  }
}

void loop()
{
  
}

I can't use Wire as it isn't supported by the ATTiny85. I'll have to use TinyWireM.

The LED rapidly flashes. The display isn't found.
The display is supplied with power - it has the green LED on the back.

I don't agree. The following sketch has worked very well with my ATtiny85 of the Digispark Board and ATTinyCore at 16 MHz (PLL).

#include<Wire.h>
#include<LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2);
#define LED 1    //PB1 = MISO pin onboard LED

void setup()
{
  Wire.begin();
  pinMode(LED, OUTPUT);
  analogReference(DEFAULT); //1.1V Vref

  //-------system reset indication-----
  for (int i = 0; i < 3; i++)
  {
    digitalWrite(LED, HIGH);
    delay(200);
    digitalWrite(LED, LOW);
    delay(200);
  }
  lcd.begin();//or lcd.init();
  lcd.backlight();
  lcd.setCursor(0, 0);  //DPos (0-15), LPos (0-1)
  //----------------------
  Wire.beginTransmission(0x27);
  byte busStatus = Wire.endTransmission();
  if (busStatus != 0)
  {
     	While(true)
	{
	   	digitalWrite(LED, HIGH);
    		delay(100);
    		digitalWrite(LED, LOW);
    		delay(100);
	}
  }
  lcd.print("I2CLCD is found!");
  delay(2000);
  lcd.clear();
}

void loop()
{
  lcd.setCursor(0, 0);
  digitalWrite(LED, HIGH);   //debug message to see MCU reset
  delay(1000);
  digitalWrite(LED, LOW);
  delay(1000);
  //------------------
  unsigned y = analogRead(A0);
  float testVolt = (5.0 / 1023) * y;
  lcd.print(testVolt, 1);
  lcd.print(" V");
}

From the looks of things, your board has an I2C interface. Mine doesn't, it uses USI (Universal Serial Interface). Wire isn't supported as it expects hardware I2C.

You may connect the display unit with UNO and run the following Scanner Program to find the 7-bit Slave Address.

#include <Wire.h>

void setup()
{
  Serial.begin(115200);
  Serial.println("Address search");
  Serial.println("-------------------------");

  Wire.begin();
  byte i2c = 0x00;
  for (int i = 0; i < 0x7F; i++)
  {
    Serial.print("Search at [");
    Serial.print(i2c, HEX);
    Serial.print("]: ");
    Wire.beginTransmission(i2c);
    byte busStatus = Wire.endTransmission();
    if (busStatus == 0)
    {
      Serial.println("Device Found...!");
    }
    else
    {
      Serial.println("Device not found...!");
    }
    i2c++;
  }

}

void loop()
{

}

The ATtiny85 has seperate I2C Interface in addition to USI Interface.

The UNO finds the display at 0x70 as usual.

The ATTiny85 doesn't have hardware I2C. It only has USI, software I2C, which connects at pins 0 and 2. This is why you can't use the Wire library, it is written to work with actual hardware I2C but the Tiny doesn't have it, forcing you to use TinyWireM or S.

Here's the datasheet. Go to page 112, it shows that it has to use the USI for I2C (or Two-Wire). Nowhere does it mention hardware I2C.

Maybe it's worth mentioning that Pin 0 (SDA) is used by the AVR flasher as an LED pin, as an indicator - but this pin isn't set up in code. The LED doesn't flash at all during the code.

According to ATTinyCore 's documentation, it includes its own version of Wire.
Maybe you should check it.

This fixed it. The SDA line was being overtaken by the LED, and so it couldn't connect. Removing it from the programmer and onto a breadboard fixed it.

1 Like

What is your perception on the hardware I2C Interface of ATtiny85? Is it still a software matter?

This instance was a hardware matter - but the Tiny doesn't have I2C, only USI.

Refer to Fig-1 below, the SDA (pin-5) and SCL (pin-7) are the lines for the hardware I2C Bus of ATtiny85 MCU. They are the alternate functions of PB0/PB2 lines. The SDA/SCL lines become active when the following codes are included in the sketch:

#include<Wire.h>
Wire.begin();


Figure-1:

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.