reading data over i2c from a attiny85

I’ve recently bought a ATTINY85, with the idea to read analog data, and send it out digitally over i2c. The reason behind this is that I eventually want to hook the attiny up to a esp8266, since that chip doesn’t have any usabe analog pins.

to get started, I programmed the attiny with the arduino IDE with this code:

#include "TinyWireS.h"                  // wrapper class for I2C slave routines
#define I2C_SLAVE_ADDR  0x27            // i2c slave address 

void setup(){
  TinyWireS.begin(I2C_SLAVE_ADDR);      // init I2C Slave mode
}

void loop(){
  byte byteRcvd = 0;
  if (TinyWireS.available()){           // got I2C input!
   
    TinyWireS.send(5);           // send 5 back to master

  }
}

after that I hooked it up to a adruino nano in this way:

pin attiny → pin arduino nano

pin4 → gnd
pin5 → a4
pin7 → a5
pin8 → 3.3v

When I run this i2c scanner code on the arduino, it finds the attiny on 0x27:

// --------------------------------------
// i2c_scanner
//
// Version 1
//    This program (or code that looks like it)
//    can be found in many places.
//    For example on the Arduino.cc forum.
//    The original author is not know.
// Version 2, Juni 2012, Using Arduino 1.0.1
//     Adapted to be as simple as possible by Arduino.cc user Krodal
// Version 3, Feb 26  2013
//    V3 by louarnold
// Version 4, March 3, 2013, Using Arduino 1.0.3
//    by Arduino.cc user Krodal.
//    Changes by louarnold removed.
//    Scanning addresses changed from 0...127 to 1...119,
//    according to the i2c scanner by Nick Gammon
//    http://www.gammon.com.au/forum/?id=10896
// Version 5, March 28, 2013
//    As version 4, but address scans now to 127.
//    A sensor seems to use address 120.
// Version 6, November 27, 2015.
//    Added waiting for the Leonardo serial communication.
//
//
// This sketch tests the standard 7-bit addresses
// Devices with higher bit address might not be seen properly.
//
 
#include <Wire.h>
 
 
void setup()
{
  Wire.begin();
 
  Serial.begin(115200);
  while (!Serial);             // Leonardo: wait for serial monitor
  Serial.println("\nI2C Scanner");
}
 
 
void loop()
{
  byte error, address;
  int nDevices;
 
  Serial.println("Scanning...");
 
  nDevices = 0;
  for(address = 1; address < 127; address++ )
  {
    // The i2c_scanner uses the return value of
    // the Write.endTransmisstion to see if
    // a device did acknowledge to the address.
    Wire.beginTransmission(address);
    error = Wire.endTransmission();
 
    if (error == 0)
    {
      Serial.print("I2C device found at address 0x");
      if (address<16)
        Serial.print("0");
      Serial.print(address,HEX);
      Serial.println("  !");
 
      nDevices++;
    }
    else if (error==4)
    {
      Serial.print("Unknow error at address 0x");
      if (address<16)
        Serial.print("0");
      Serial.println(address,HEX);
    }    
  }
  if (nDevices == 0)
    Serial.println("No I2C devices found\n");
  else
    Serial.println("done\n");
 
  delay(5000);           // wait 5 seconds for next scan
}

However, when I try to read it, I’m getting stuck. I tried to read 1 byte with this code:

#include <Wire.h>

void setup() {
  Wire.begin();        // join i2c bus (address optional for master)
  Serial.begin(9600);  // start serial for output
  Serial.println("starting");    
}

void loop() {
  Serial.println("begin loop");     
  Wire.requestFrom(0x27, 1);   
  Serial.println("after request"); 


  while (Wire.available()) { // slave may send less than requested
    char c = Wire.read(); // receive a byte as character
    Serial.print(c);         // print the character
    Serial.println("reading");      
  }

  Serial.println("looping");        
  delay(500);
}

All I see is

starting
begin loop

and then it seems to halt.

I’ve also connected it to the esp8266, there I get the same results. The scanner finds it, but when I try to read it (using this library: GitHub - pasko-zh/brzo_i2c: Brzo I2C is a fast I2C Implementation written in Assembly for the esp8266) All I get is “Bus not free” errors.

I did use 4.7k pullups on scl and sda by the way.

I’m wondering where I’m going wrong. I think the problem is at the attiny side. I’ve programmed it using 8Mhz internal clock. In this tutorial, they’re talking about using “16 MHz (Internal PLL)” but I don’t have that option in the arduino IDE. Not sure if that’s related to my issue.

The attiny itself seems to be ok by the way, before starting with i2c, I tested some blink sketches.

erikNL:
I eventually want to hook the attiny up to a esp8266, since that chip doesn't have any usabe analog pins.

It does have one. But most modules of the ESP don't have it broken out. The ESP-12 has.

erikNL:
to get started, I programmed the attiny with the arduino IDE with this code:

That's not how you make it a slave. See the slave example :slight_smile:

septillion:
It does have one. But most modules of the ESP don’t have it broken out. The ESP-12 has.

yes, but it only accepts values between 0 and 1v, wich makes it pretty useless…

septillion:
That’s not how you make it a slave. See the slave example :slight_smile:

this is the slave example, I only simplified it a little.
I now uploaded the actual sample code, which is:

/* ATtiny85 as an I2C Slave            BroHogan                           1/12/11
 * Example of ATtiny I2C slave receiving and sending data to an Arduino master.
 * Gets data from master, adds 10 to it and sends it back.
 * SETUP:
 * ATtiny Pin 1 = (RESET) N/U                      ATtiny Pin 2 = (D3) N/U
 * ATtiny Pin 3 = (D4) to LED1                     ATtiny Pin 4 = GND
 * ATtiny Pin 5 = I2C SDA on DS1621  & GPIO        ATtiny Pin 6 = (D1) to LED2
 * ATtiny Pin 7 = I2C SCK on DS1621  & GPIO        ATtiny Pin 8 = VCC (2.7-5.5V)
 * NOTE! - It's very important to use pullups on the SDA & SCL lines!
 * Current Rx & Tx buffers set at 32 bytes - see usiTwiSlave.h
 * Credit and thanks to Don Blake for his usiTwiSlave code. 
 * More on TinyWireS usage - see TinyWireS.h
 */


#include "TinyWireS.h"                  // wrapper class for I2C slave routines

#define I2C_SLAVE_ADDR  0x26            // i2c slave address (38)
#define LED1_PIN         4              // ATtiny Pin 3
#define LED2_PIN         1              // ATtiny Pin 6

void setup(){
  pinMode(LED1_PIN,OUTPUT);             // for general DEBUG use
  pinMode(LED2_PIN,OUTPUT);             // for verification
  Blink(LED1_PIN,2);                    // show it's alive
  TinyWireS.begin(I2C_SLAVE_ADDR);      // init I2C Slave mode
}


void loop(){
  byte byteRcvd = 0;
  if (TinyWireS.available()){           // got I2C input!
    byteRcvd = TinyWireS.receive();     // get the byte from master
    Blink(LED1_PIN,byteRcvd);           // master must wait for this to finish before calling Wire.requestFrom
    byteRcvd += 10;                     // add 10 to what's received
    TinyWireS.send(byteRcvd);           // send it back to master

    Blink(LED2_PIN,1);                  // show we transmitted
  }
}


void Blink(byte led, byte times){ // poor man's display
  for (byte i=0; i< times; i++){
    digitalWrite(led,HIGH);
    delay (250);
    digitalWrite(led,LOW);
    delay (175);
  }
}

and modified my master code into:

#include <Wire.h>

void setup() {
  Wire.begin();        // join i2c bus (address optional for master)
  Serial.begin(9600);  // start serial for output
  Serial.println("starting");
}

void loop() {
 
  Wire.beginTransmission(0x26); // transmit to device 
  Wire.write(5); 
  Wire.endTransmission(); 
  
  Serial.println("begin loop");         
  Wire.requestFrom(0x26, 1);    // request 1 byte from slave device 0x26
  Serial.println("after request");        


  while (Wire.available()) { // slave may send less than requested
    char c = Wire.read(); // receive a byte as character
    Serial.print(c);         // print the character
    Serial.println("reading");        
  }

  Serial.println("looping");         



  delay(500);
}

unfortunately, I now get stuck even earlier, I only see “starting”, and nothing else.
The attiny is still findable via i2c

ok, turns out there are multiple tinyWire libraries out there. I was using the one that is downloadable here: http://playground.arduino.cc/Code/USIi2c

I now switched to this one: GitHub - rambo/TinyWire: My modifications to TinyWire Arduino libs

Using this example, it works like a charm:

#define I2C_SLAVE_ADDRESS 0x4 // Address of the slave
 
#include <TinyWireS.h>
 
int i=0;
 
void setup()
{
    TinyWireS.begin(I2C_SLAVE_ADDRESS); // join i2c network
    //TinyWireS.onReceive(receiveEvent); // not using this
    TinyWireS.onRequest(requestEvent);
 
    // Turn on LED when program starts
    pinMode(1, OUTPUT);
    digitalWrite(1, HIGH);
}
 
void loop()
{
    // This needs to be here
    TinyWireS_stop_check();
}
 
// Gets called when the ATtiny receives an i2c request
void requestEvent()
{
    TinyWireS.send(i);
    i++;
}
[code]

erikNL:
yes, but it only accepts values between 0 and 1v, wich makes it pretty useless...

No it does not! The ADC in the Uno is also better (voltage wise) when you set it to the 1,1V ref. Just add a voltage divider and you're done :wink: So it's just your lack of knowledge, not the device, that makes it useless :smiley: