freeze: Teensy 3.2 + multiple ATTiny85 I2C

Status
Not open for further replies.

superslot

Member
Hi all,
I'm trying to solve an i2c issue from some time now .. and I'm at a stall point where I really need some hint.

I'm using a teensy 3.2 with n.1 Adafruit SSD2306 oled display (i2c) and n.3 ATTiny85 attached to the i2c bus.

[OVERVIEW]
1) the purpose is to use the ATTiny85 as independent hifreq counters and display results by the teensy (plus other remote feature eventually ... this is why I love the Teensy!)
2) Initially for the display I was using the SSD1306_text (I just need text) with some bug fixes and I got what I needed...
3) problem is: after some random time everything is getting stuck, to a point that I need to power cycle

[DETAILS]
to interface the 5v peripherals I use a i2c adaptor from sparkfun, which already has pullups to 1Kohm (PCA9306) so I should be ok on levels.

the ATTiny85 is counting on one pin (uint64_t internal counter) with some sw debounce (see code below) and sends the value over i2c when requested.
Each of the n.3 ATTiny85 has a different address.

[DEBUG]
Initially I was under the impression that my fixes to the SSD1306_text library were the culprit, so I decided to load the Adafruit oled demo (the classical example).
the idea is that it should work even if I have the 3 attiny85 attached to the bus ... basically idle because they are never asked to send data by the master i2c (teensy)

Even the Adafruit demo is getting stuck "randomly", to a point that I need to power cycle.
The problem is the following:
1) I run the i2cScan on teensy (looping every 0.5s) and I can see all the 4 devices, no problems
2) I load the adafruit oled demo ... is getting stuck after few secs
3) without power cycle the diplay/attiny I load the i2cScan again .. and I get a bunch of errors, like the display bus is in a very weird state.
4) powercycle everything and the i2cScan works again .. no issues

So I decided to remove the ATTiny85 one by one:
1) with TWO attiny85 ... the problem is there, i2c display is getting stuck
2) if leave ONLY ONE attiny85: not a single problem, the display demo runs forever, but the attiny is running _the_same_code_ on the same i2c addr !!!

I tried to understand if this is a logic level issue, but voltage on the bus seems fine all the time,
and I don;t see the ATTiny85 to trigger a "false i2c request"

[HELP]
Anyone out there that has a display and a couple of attiny85 and wants to try?

It is certainly some issue on the tristate of the bus ... but I can't see why it should,
since the ATTiny85 are never asked to reply by the Adafruit demo...

anyone having multiple ATTiny85 runnig on the i2c bus of a Teensy??

:)

Note: the bus length is very short... less than 40mm from the teensy to the display (1st) and the very last ATTiny85



Code:
#include <stdint.h>
#include "avr/interrupt.h"
#include "TinyWireS.h"   

/* NOTE: make sure you change the slave addr on each ATTiny85 */
#define I2C_SLAVE_ADDR             (0x0A)  

#define COUNT32_PIN                   (1)
#define COUNT32_DEBOUNCE_MS          (20) //~8ms

#define CONT32_RISING              (HIGH)
#define CONT32_FALLING              (LOW)

unsigned long isrCtrlTime = 0;
unsigned long debounceCtrlTime = 0;

volatile uint64_t count64 = 0;
volatile uint8_t  count64_debounce_ms = COUNT32_DEBOUNCE_MS;
volatile uint8_t i2cReqCount = 0;

/* ************************************************************************* */
/* INPUT DEBOUCE CONFIG */
/* ************************************************************************* */
void debounceConfigInit()
{
    pinMode(3, INPUT); 
    pinMode(4, INPUT);

    uint8_t d1 = (HIGH==digitalRead(3))?1:0; //PB3 = bit1
    uint8_t d0 = (HIGH==digitalRead(4))?1:0; //PB4 = bit0 
    uint8_t val = d0 + 2*d1;

    switch(val)
    {
      case 0 : count64_debounce_ms = 0; break;  //0ms 
      case 1 : count64_debounce_ms = 1; break;  //8ms 
      case 2 : count64_debounce_ms = 3; break;  //24ms 
      case 3 : count64_debounce_ms = 8; break;  //64ms 
      default : count64_debounce_ms = 2; //16 ms
    }    
    
    debounceCtrlTime = millis();
}


/* ************************************************************************* */
/* ISR */
/* ************************************************************************* */
//void countISR()
ISR(PCINT0_vect)
{
  /* handle interrupt on rising only */
  if(CONT32_FALLING == digitalRead(COUNT32_PIN))
  {
    return;  
  }
  
  unsigned long deltaTimeMs = millis();
  deltaTimeMs = (isrCtrlTime <= deltaTimeMs) ? 
    (deltaTimeMs-isrCtrlTime) : (0xFFFFFFFF + deltaTimeMs - isrCtrlTime);  
      
  /*
   * SOFTWARE DEBOUNCE
   */
  if(count64_debounce_ms < deltaTimeMs)
  {
    isrCtrlTime = millis();
    count64++;
  }
}


/* ************************************************************************* */
/* I2C */
/* ************************************************************************* */

void requestEvent()
{  
  //NOTE: count64 is 64bit, i.e. 8bytes
  //      the maste is aware of this and must call 8 times.
  
  uint8_t shft = (i2cReqCount & 0x07) * 8;
  TinyWireS.send( (byte) ((count64 >> shft)&0xFF) );
  i2cReqCount++;

  //digitalWrite(3,((i2cReqCount&0x01)?HIGH:LOW));
}

/* ************************************************************************* */
/* MAIN */
/* ************************************************************************* */
void setup() {

  /* init I2C Slave mode */
  TinyWireS.begin(I2C_SLAVE_ADDR);      
  TinyWireS.onRequest(requestEvent);
  
  isrCtrlTime = millis();

  /* SETUP INTERRUPTS, enable PB1 on change */
  GIMSK = 0b00100000;    // turns on pin change interrupts
  PCMSK = 0b00000010;    // turn on interrupts on pins PB1,
  sei();                 // enables interrupts

  pinMode(COUNT32_PIN, INPUT);

  debounceConfigInit();
}

void loop() {

  TinyWireS_stop_check();
}
 
Last edited:
Can you check if any of the I2C lines are pulled low when it freezes?

If they are. Disconnect the ICs one by one until the lines are released.
This will tell you which device is not releasing the I2C
 
Hi Xenoamor,
the problem is that I suspect the display is the one going foobar for some reason.
infact it does not recover (i.e. reply) even if I remove the attiny.

but ... trying to debug, I did another test:
instead of "counting on a pin" of the attiny85 I used the same pin as output, going HIGH if there was a TinyWireS request triggered.

and I never saw the ATTiny85 to go high .. so they were never involved in a i2c transaction.

something is affecting the i2c electrical bus to a point that the display is not responsive anymore, but with a scope I see the levels being ~4v for "1" and 0.1v for "0" when the transaction are initially working.

I never get past the first "line demo" of the adafruit sketch if I connect two attiny85
 
You may need stronger/weaker pullups.
What are your line lengths?

Check your voltages at the end of the lines with the tinys attached. See if there's a voltage drop
 
Last edited:
mmm ... stronger than 1kohm? really?

there is indeed a little bit of voltage drop on the output of the PCA9306, the level is around 4v when the display is working (power supply is a bench supply 5A .. and is dead on 5V flat)
but the level is the same as the one I have when there is only the display attached

having said so .. I had the same concern, maybe the pca converter does not handle the load on isolated "1" (which will be tiny spikes) and everything goes bad.

I just need to find a good level shifter for i2c ... any suggestion?

btw: the total lenght of the bus is 40mm from the teensy to the last slave att85
 
correct, they are all on a different i2c address (0x0a, 0x0b, 0x0c while the display is 0x3c). I did run the i2cScanner sketch on the teensy multiple times and I can see them to respond to these addresses.

thanks Paul
 
Hi all, just a quick update:
I did try another level shifter (the BSS138 4ch bidirectional from Adafruit) thinking that the extra n.3 ATTin85 could be the cause of an higher load on the port.

same exact issue ... the display demo does get frozen on the first line draw demo...

so ... if it is not electrical .. must be an protocol issue ... scratching my head on this one...
:-(
 
Can you try what I suggested?

When it freezes measure the voltage on the data lines and write them down.

Then remove a atTiny and check again, noting the result

Keep remove stuff until the levels readjust
 
ok.

when the display freezes I have SCL at 4v (high) and SDA at 0.2v (low).
These are the levels after the level shifter of course (where 3.3v->5v)

I removed the atTiny one by one ... nothing changed, same levels.
Looks like the display itself is blocked in a bad state.

So I tried a "combination" of the display and ONE of the atTiny to see if I have one faulty unit.
each of the permutation (display+ATT85_0x0A, display+ATT85_0x0B, display+ATT85_0x0C) went fine ... not a sigle glitch of the display demo patterns..

at this point I;m suspecting the ATTiny all togheter might have some effect on the bus when they are "in batch".
something like capacitance/load and when we launch the display demo to the i2c oled display some commands get corrupted (at high freq) and will put the display i2c state machine in a bad state.

any suggestion on how to buffer/tristate the output of the ATT85?

FORGOT TO MENTION:
the freeze shows up as soon as I have TWO ATTiny85 on the i2c bus together with the display.
what really puzzles me is that if I simply launch the i2cScanner sketch I have no problem, even with all 3 of them.
but ... looking at the sketch code it is just waiting for a reply... no checks .. so maybe it is not a valid test.
 
Last edited:
after more debugging I believe the issue is at protocol level.

I;ve seen few notes on TinyWireS (i2c slave on ATTiny85) repo in github about issue with i2c on Raspberry Pi because the master (Rpi) does not handle clock stretching properly...
I wonder if we have the same issue here .. due to the difference in sys clock between teensy and ATTiny

I've done the following:
1) connected to the i2c port of Teensy 3.2 a second level shifter, taking care of the pullup resistor so that the parallel is ~2K for SDA and SCL
2) the first level shifter is connected only to the Adafruit oled display
3) the second level shifter goes to the ATTiny 85

The first test is to run the i2cScanner sketch: no problems here. .. I can see all the devices on the i2c chain.

The second test is to run the oled demo display: same issues here...
Sometime I can see HALF of the logo on the display, and then the rest of the screen is random noise. This makes me thinking to the fact that the i2c protocol is all corrupted,semantically, and the only culprit can be the ATTiny.

I don;t know if this is a clock speed issue between the i2c clock of Teensy or the sys_clock of ATTiny85 (8Mhz) or a combination of both..
but I'm quite sure the USI hw of the tiny85 is altering the line at some point ... and the display goes ... blah!

if I test the display "alone" or the ATTiny85 "alone" I don't see any issue.

I'm not an expert of i2c details and will take me sometime to debug the TinyWireS code when working with teensy,
but looks like there is some incompatibility problem between Teensy i2c and ATTiny+TinyWireS ... at least when multiple i2c devices are on the same bus
 
What clock speed are you running your ATTiny's at? And what I2c speed are you trying to run at (dictated by parameter passed to Wire.begin if I recall)?

I've done some work interfacing a T3.1 with multiple ATTiny841's (very different I2c hardware setup though in terms of registers) but if I recall correctly, the datasheet stipulated that max I2c speed could not be more than 1/16th of the main clock speed. This may or may not be the same case for the 85's.
 
Last edited:
mmm ... the ATTiny is running at 8Mhz (internal) to keep the hw to the minimum (the final goal is to attach 16 counters on the bus).

I'm not setting any custom param on the Teensy so I suppose it is running i2c in "fast" mode, 400Khz.
this should be ok, since 8MHz/16==500kHz

thanks for your help!

[UPDATE]
checking the attiny85 datasheet it does mention that the maximum speed is fck/2 ..
seems a little high to me ... but anyhow 400kHz should be fine imho

15.3.6 Clock speed considerations
Maximum frequency for SCL and SCK is fCK / 2. This is also the maximum data transmit and receive rate in both
two- and three-wire mode. In two-wire slave mode the Two-wire Clock Control Unit will hold the SCL low until the
slave is ready to receive more data. This may reduce the actual data rate in two-wire mode.
 
Last edited:
Hi folks,
I think I got a smoking gun on this one...

Since I'm using Teensy 3.2 I decided to move the Adafruit_SSD1306 lib from using Wire.h to the i2c_t3.h.
I simply wanted to see if the improved library had some difference.

while doing this I realized the Adafruit lib is doing a "dirty" trick when opening the Wire port for a "display" call...
it is saving the global variable TWBR (from wire.h), bumping the speed of the i2c to 400K, drawing the display and then restoring the TWBR value.

so I had the doubt that having n.3 ATTiny85 attached on the same bus might altering the total capacitance of the bus,
degrading the signal for 400K and causing some instructions to freeze/confuse the oled display.

to prove this I moved the Adafruit_SSD2306 to i2c_t3 (removing that trick) and opened the bus with a proper speed (with i2c_t3 call).

indeed at a bitrate of 200 everything works again, with all 3 ATTiny attached.
if instead I open with a speed of 400 ... same exact issue as before, the display get frozen after few steps of the line_draw demo.

---
So ... I assume the output stage of the ATTiny85 is not good for i2c when we chain many of them on the same bus, even if the bus is really short (40mm)
but I want to have the display to work at max speed, and also I have a small eeprom on the same bus to save some custom parameters.

Next step (thanks to the powerful Teensy!) is to use the first i2c port for display and eeprom, and the second port just for the ATTiny chain of counters,
I will lower the frequency of the second bus as much as I need to keep the communication reliable, since I just query those counters every few second, and they reply with a uint64_t value only,
I should have plenty of speed since the query of the counters is not "mission critical" ... it's just a polling "every second or so".
 
Update: so far .. so good.

splitting on two i2c bus and using a 200kHz freq for the ATTiny85 daisy chain seems to be the solution.
I'm currently using n.4 ATTiny85 and it did run for more than 24h without a problem...

I'll let it go for a 24h/7d test and I'll post my findings ... but I think this is a good solution
(it also gives me more freedom since I have one bus dedicated only to my atiny and I can use the whole i2c addressing range if I need to..)
 
Kudos to superslot for tracking this particular issue down and reporting back once the problem was resolved!! I've read dozens of i2c threads that just fade out, making it impossible to know whether any of the proposed diagnostic/therapeutic approaches were effective.
 
Status
Not open for further replies.
Back
Top