Attiny85: I2C master hangs without slave #692
Replies: 4 comments 3 replies
-
How was this solved on the '328p? I find the I2C protocol very confounding, like it was created for the explicit purpose of confusing people trying to debug it, |
Beta Was this translation helpful? Give feedback.
-
Remarkable. I am using a AT85 with a sketch where I scan for the address of a LCD 16x2 I2C display first, before I activate it, as the display backpack prints come with different I2C addresses. Also when no display is connected to the I2C bus it will detect that. I extracted below part of my sketch, that will demonstrate scanning of the I2C display address and then printing the address. [edit] maybe important to notice. I am using Attinycore 2.0 and the digispark Liquidcrystal_I2C library for the Attiny and in that library I had to replace "tinywirem" back into "wire" as the Attinycore now supports the standard wire command
|
Beta Was this translation helpful? Give feedback.
-
@hmeijdam , I will give it a try with external pull-ups, but it does not make sense to me. The setup works perfectly with one slave (magnetometer), which means at85 pull-ups are active and doing their job. The setup even works when both magnetometer (slave ID 0xE) and debug-nano (slave ID 0x7) are connected. The setup also can read magnetometer when debug-nano is not present. It hangs only when it addresses debug-nano and gets NACK. |
Beta Was this translation helpful? Give feedback.
-
Why are you using a modified library and tinywirem when ATTinyCore includes a universal wire that works with unmodified libraries? |
Beta Was this translation helpful? Give feedback.
-
I have found another bug in the USI I2C code, that makes the I2C bus hang when the addressed slave is not present.
the sketch is very simple. It is used to detect if a specific slave is present on the bus. Essentially the master is just driving the bus with slave address and detecting ack/NACK. Regardless of ack or NACK, The code is supposed to issue stop and leave the bus idle. The error code tells if the targeted slave responded or not.
#include <wire.h>
byte err;
Wire.begin();
Wire.beginTransmission(0x07); //for slave with ID 7
err = Wire.endTransmission(true):
if (err==0) {
} else if (err==2) {
} else {
}
This code works in nano. For nano, the core picks up TWI library, which issues stop even if NACK is received for slave address.
However, same code hangs the bus (no STOP issued) for attiny85 if there is NACK on slave address. The core picks up usi_twi libraries for attiny85. Wire.endTransmission() calls USI_TWI_Start_Transceiver_With_Data_Stop(). The following piece of code exists (return FALSE) the function without issuing STOP if NACK happens at address phase (line 182).
Code for issuing STOP is at line 210, which is not executed in NACK situation. These 3 lines should be also included right before return(FALSE) in the code above.
if (stop) {
USI_TWI_Master_Stop(); // Send a STOP condition on the TWI bus.
}
With the bus at this state, other slaves on the bus act weird.
What I am trying to do
In my setup, at85 is I2C master with 2 slaves on I2C bus. One is a mangnetometer, an the other is a nano acting as slave (for debugging purpose) with address 7. At85 periodically reads all 3 axes of the magnetometer, and immediately writes same values to slave 7. Then it reads a register in slave 7 for further actions. This goes on and on. The nano prints all received values in human readable format to serial port. It also accepts commands from serial port. When a command comes via serial port, nano stores that in a variable. When at85 reads the register in slave 7, this variable is returned to at85. At85 takes further action based on this variable value, like configuring the magnetometer, storing/retrieving parameters in at85 eeprom, etc.
basically, nano is being used as a debugging channel, as it is very hard to debug using just at85.
the setup works beautifully when nano is present on the bus. But I want to burn the code unchanged into at85 even for production version, where debug-nano will be absent. The unchanged code allows me to debug even on production board just by connecting the nano on the I2C bus. The idea is that on production board, after at85 taken mag reading, it will first detect if the slave 7 is present. If present, it will relay the mag value to slave 7, otherwise skip this step.
the setup works when master is implemented using a nano. But fails if it’s at85. That’s because of the above bug, which leaves the bus hanging, and magnetometer does not behave as expected for subsequent readings.
Beta Was this translation helpful? Give feedback.
All reactions