ATtiny85 Master and Slave communication with I2C

Hi Guys,

I am working on a project for Water tank level monitoring and control. the plan is to have a master Attiny85 communicating with two slaves, each slave is attached to ultrasonic sensors that will be used to measure the water levels in the Tanks. (one slave is on the roof where the tanks are and another is in the basement where I have a reserve tank and a water pump)

The slave controller would ping and measure the distance and then save it in an array to send it back to the Master when requested. The Master saves the data received (distances) and then displays that on an LCD connected through I2C as well. The master would also control a water pump in case the water level in the tanks goes below a certain level.

tested the slave and there is no issues with the measurements, however when it comes to the data being received on the Master that is not happening. I would appreciate your assistance.

I am using Master library from: Arduino Playground - USIi2c
and slave library from: GitHub - rambo/TinyWire: My modifications to TinyWire Arduino libs

I am not sure if I have implemented the code correctly or not or if I am missing anything in there

Master controller code (only what is related to I2C)

#include <TinyWireM.h>                 // I2C Master lib for ATTinys which use USI
int DataArray [2][2];                  // Data array that holds the received distance (or other values) from the Slave controllers

int ADDR[] = {0x5, 0x6};             // Contains the addresses of the slave Attiny controllers for data collection {uppoer controller(roof), lower controller (basement)



void setup(){
  TinyWireM.begin();             // initialize I2C lib
  DataArray[1][1] = 0;           // Set the initial pump status to  OFF
  delay (1000);
}


void loop(){
  
  GetData();     // Read the distances from all sensors and store it in the distance array
  delay (2000);  // wait a few sec before the next reading
}


void GetData ()    // Function to read the distance from the Upper Sensors 
{ 
  for (int i=0; i<2; i++) {
   for (int j=0; j<2; j++) {               //LOOP to Store the data in the distance array
   TinyWireM.requestFrom(ADDR[i],1);       // Request 1 bytes from the sensor controllers
    DataArray[i][j] = TinyWireM.receive(); // ask for the actual data
    delay(200);
   } 
  }
}

code for slave controller

 #include "TinyWireS.h"                // wrapper class for I2C slave routines
 #include <TinyNewPing.h>
 
 #define I2C_SLAVE_ADDR  0x5           // i2c slave address (5)
 
 int trigPin[] = {1, 4};               // define the trigger pins for Attiny85 // Originally {1, 3, 4} for three sensors;
 int distance[2]={10,20};                     // array to hold the distances 
 byte index = 0;
 
 NewPing sonar[] = {                   // initialize the 2 sonars inside an array
   NewPing  (trigPin[0], trigPin[0]),  
   NewPing  (trigPin[1], trigPin[1])
 }; 
 
 void setup(){
   Serial.begin(9600);
   for (int i=0; i<2; i++) {  // set the sensors' Pin mode
     pinMode(trigPin[i],OUTPUT);
   }  
   TinyWireS.begin(I2C_SLAVE_ADDR);      // init I2C Slave mode
// TinyWireS.onReceive(receiveEvent);    // not using this
   TinyWireS.onRequest(requestEvent);    
 }  
 
 
 void loop(){
   TinyWireS_stop_check();
   for (int i=0; i<2; i++){
     distance[i] = sonar[i].convert_cm(sonar[i].ping_median(10)); // ping 10 times and get the average back in and then convert to cm  
    }
   
   Serial.print("byte: "); Serial.print(distance[0]);   // output debugging
   Serial.print(", byte: "); Serial.print(distance[1]); // output debugging
   Serial.print("index: "); Serial.println(index);      // output debugging
   Serial.println("*********************"); // output debugging
   //tws_delay(500); 


 }

void requestEvent()
{
    TinyWireS.send(byte(distance[index]));
    Serial.print(" What is sent index: "); Serial.print(index); Serial.print(" : "); Serial.println(distance[index]);
    Serial.println("##############");
    index++;
    if (index = 2) {
      index = 0;                           //reset the index to zero if it goes out of the limit
    }
}

have you been able to send simple values ? just to test the communication link and such ?

what is the length of your I2C ? I2C is not for long distances like basement to roof.

Hi Dave,

This is still on the breadboard for now, however for the distance I will be using the Philips P82B715PN to buffer the bus, it is supposed to support 20 or more meters with that.

to be true I haven't tested with simple values, however I have put a trigger in the slave code to print to the serial whenever the "onrequest" handler is triggered and I am not getting anything there :roll_eyes:

did you spot any issues with the code for the I2C communication?

I will try with simple values and post back

So I have simplified the code on both the master and slave and the master print on the LCD the received value, the vlaue displayed is always "1".

Master

#include <TinyWireM.h>                 // I2C Master lib for ATTinys which use USI
#include <LiquidCrystal_I2C.h>

void setup(){
  TinyWireM.begin();             // initialize I2C lib
  lcd.init();                    //initiate the LCD (16 charachters wide, 2 lines high)
  lcd.backlight();
  // ********                    // create the LCD custome characters
  lcd.createChar(0, Full);
  lcd.createChar(1, Quarter3);
  lcd.createChar(2, Half);
  lcd.createChar(3, Quarter);
  lcd.createChar(4, Empty);
  lcd.createChar(5, Pump1);
  lcd.createChar(6, Pump2);
  DataArray[1][1] = 0;           // Set the initial pump status to  OFF
  pinMode(Relay_PIN, OUTPUT);    // set the relay pin mode
  
  
  delay (1000);
}


void loop(){
  int x=100;
    lcd.clear(); // Clear the LCD screen
   TinyWireM.requestFrom(/*ADDR[i]*/0x5,1);       // Request 1 bytes from the sensor controllers
    x = TinyWireM.receive();
    lcd.print(x);

   delay (2000);  // wait a few sec before the next reading
}

SLAVE

 #include "TinyWireS.h"                // wrapper class for I2C slave routines
 #include <TinyNewPing.h>
 
 #define I2C_SLAVE_ADDR  0x5           // i2c slave address (5)
 
 int trigPin[] = {1, 4};               // define the trigger pins for Attiny85 // Originally {1, 3, 4} for three sensors;
 int distance[2]={10,20};                     // array to hold the distances 
 int index = 10;

 void setup(){
   Serial.begin(9600);
   for (int i=0; i<2; i++) {  // set the sensors' Pin mode
     pinMode(trigPin[i],OUTPUT);
   }  
   TinyWireS.begin(I2C_SLAVE_ADDR);      // init I2C Slave mode
// TinyWireS.onReceive(receiveEvent);    // not using this
   TinyWireS.onRequest(requestEvent);    
 }  
 
 
 void loop(){
   TinyWireS_stop_check();
 }
void requestEvent()
{
    TinyWireS.send(index);
    index++;
}

Did you connect pull up resistors on sda and scl?
I would simplify even more the code, like the ones in the arduino wire examples. And would start by testing 1 master and 1 slave. If that works, then Id add more slaves like the lcd and other attinys.

Anyway, I'd try first using a common and tested I2C master (like arduino uno for example with wire library) with an attiny85 as slave. If this works, then I would use an attiny85 as a master and see whats going on.

mart256:
Did you connect pull up resistors on sda and scl?
I would simplify even more the code, like the ones in the arduino wire examples. And would start by testing 1 master and 1 slave. If that works, then Id add more slaves like the lcd and other attinys.

Anyway, I'd try first using a common and tested I2C master (like arduino uno for example with wire library) with an attiny85 as slave. If this works, then I would use an attiny85 as a master and see whats going on.

Hi Mart256,

I was actually trying with a microduino the past few days and finally got it working with the slave, I have to clock it at 16Mhz to really get the results the way I would like it to be. (with the LCD)

Trying the same code again with the tiny Master still didn't get back with the results but I am still trying to see if I would be able to get it working, I am not sure if this could be related to the I2C master library, so I am trying to find an alternative to test with.

Microduino as master and attiny as slave? What did you clock at 16 mhz?attiny at 8mhz? Thanks for the answer Im planning on doing something similar later.

yep, Microduino as master and tiny as slave, and tiny at 16Mhz (iguess) I used the internal 16Mhz PLL option and burnt the bootloader) I am not sure if this got the tiny to work at 16Mgh or not, but when I did this the results started showing. I now need to get the master working on the tiny as well now.

any suggestions for a tiny Master library alternative?

shomar:
yep, Microduino as master and tiny as slave, and tiny at 16Mhz (iguess) I used the internal 16Mhz PLL option and burnt the bootloader) I am not sure if this got the tiny to work at 16Mgh or not, but when I did this the results started showing. I now need to get the master working on the tiny as well now.

any suggestions for a tiny Master library alternative?

I dont know other I2C library than the one you posted. Maybe rethink about your master, maybe you can use instead atmega8, 168 or 328p which are capable of I2C.

well the project is small and I went with the tiny85 since the master needs I2C and 1 pin to control the relay. I still think chips like these will be a waste for such a small project.

I will give the tiny a few more tests and then see if it doesn't work I will go with one of these other controller.

Thank you for the help anyway.

Just an update.

I got it working finally with two attiny controllers as master and slave. I configured the master to run at 16Mhz and the slave at 1Mhz and it is working fine now.

I still can't figure out how this affects the whole thing, so it would be great if any one can explain?

Thanks.

The only explanation for that is a problem with the I2C library.

shomar:
Just an update.

I got it working finally with two attiny controllers as master and slave. I configured the master to run at 16Mhz and the slave at 1Mhz and it is working fine now.

I still can't figure out how this affects the whole thing, so it would be great if any one can explain?

Thanks.

Great, could you write please the fuses you used to enable 16mhz on attiny85?

mart256:
Great, could you write please the fuses you used to enable 16mhz on attiny85?

It's in the datasheet.

fungus:

mart256:
Great, could you write please the fuses you used to enable 16mhz on attiny85?

It's in the datasheet.

Thank you I'll check now.

mart256:
Great, could you write please the fuses you used to enable 16mhz on attiny85?

I have no idea about the fuses :frowning: I used the arduino IDE core set to 16Mhz internal clock and did burn bootloader. I am not sure what settings have been pushed to be true.

shomar:

mart256:
Great, could you write please the fuses you used to enable 16mhz on attiny85?

I have no idea about the fuses :frowning: I used the arduino IDE core set to 16Mhz internal clock and did burn bootloader. I am not sure what settings have been pushed to be true.

Look under "PLL" in the "Clock Sources" section of the datasheet.

I've got similar problem with attiny85 master and slave communication.
Working case: Master 1 Mhz and Slave 8 Mhz.
If I changed master to 8 Mhz (change .h/.cpp,burn loader, tune, upload sketch), SCL pin is always at LOGIC 0. Then I change Master to 1 Mhz (change .h/.cpp, burn loader, upload sketch) everything is ok.