I ran a little test to make sure the ESP-12E is able to communicate with the ATtiny85 via I2C.
These are the connections required:
D1 and D2 are both pulled up to 3V3 on the ESP-12E with 10K resistors. The ESP-12E and the ATtiny85 are connected via different USB cables (ATtiny85 via the Arduino Uno) to the same USB hub.
The sketch for the ESP-12E (I2C master):
The sketch for the ATtiny85 (I2C slave):
The expected output from the ESP-12E is:
tx = 1
rx = 12
tx = 2
tx = 13
tx = 3
rx = 14
and so on, all with the LED blinking on the ATtiny85 at roughly 1Hz.
There are very few sources I could find on the Internet on interfacing ESP-12E (or ESP8266) with ATtiny via I2C, so let this post be a confirmation that it can be done quite easily.
I took note of Liebman's comment below and added this line:
Wire.setClockStretchLimit(1500);
Works a treat, and I was able to run ATtiny85 at 1MHz without impacting the reliability of the I2C communication with ESP-12E.
The other thing I realized was that running the ATtiny85 at 1MHz is unreliable for I2C communication. After an indeterminate amount of time, it will get stuck. The author himself says that it has never been tested for 1MHz. So to get it working reliably, I had to run the ATtiny85 at 8MHz. This can be done by setting the internal clock to 8MHz from the "Tools" menu:
then burning the correct fuses by selecting "Burn Bootloader":
After I did that, the communication has been verified to go on reliably for hours without any hiccup.
However, because of this increase in clock speed, I had to make minor changes to the Timer1 interrupt logic. At 8Mhz, the slowest interrupt rate that can be achieved is 0.5Hz (twice a second). As such, I had to add a counter to the ISR to set timer1 to true every second time the ISR is called.
â–º Breadboard diagram created using Fritzing.
These are the connections required:
D1 and D2 are both pulled up to 3V3 on the ESP-12E with 10K resistors. The ESP-12E and the ATtiny85 are connected via different USB cables (ATtiny85 via the Arduino Uno) to the same USB hub.
The sketch for the ESP-12E (I2C master):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | #include <stdint.h> #include <Wire.h> byte tx = 0; void debug(const char *format, ...) { char buf[256]; va_list ap; va_start(ap, format); vsnprintf(buf, sizeof(buf), format, ap); va_end(ap); Serial.println(buf); } void setup() { Serial.begin(115200); Wire.begin(); Wire.setClockStretchLimit(1500); } void loop() { Wire.beginTransmission(0x26); Wire.write(++tx); Wire.endTransmission(); debug("tx = %d", tx); Wire.requestFrom(0x26, 1); if (Wire.available() >= 1) { byte rx = Wire.read(); debug("rx = %d", (int)rx); } delay(1000); } |
The sketch for the ATtiny85 (I2C slave):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | #include <avr/io.h> #include <avr/wdt.h> #include <avr/sleep.h> #include <avr/interrupt.h> #include "TinyWireS.h" #define I2C_SLAVE_ADDR 0x26 // i2c slave address (38) bool timer1 = false, led = true; byte numInterrupts = 0, recvByte = 0; // Interrupt service routine for timer1 ISR(TIMER1_COMPA_vect) { timer1 = true; } void requestEvent() { TinyWireS.send(recvByte + 11); } void receiveEvent(uint8_t howMany) { if (TinyWireS.available() && howMany == 1) recvByte = TinyWireS.receive(); } void setup() { // Misc setup pinMode(3, OUTPUT); set_sleep_mode(SLEEP_MODE_IDLE); // Setup timer1 to interrupt every second TCCR1 = 0; // Stop timer TCNT1 = 0; // Zero timer GTCCR = _BV(PSR1); // Reset prescaler OCR1A = 243; // T = prescaler / 1MHz = 0.004096s; OCR1A = (1s/T) - 1 = 243 OCR1C = 243; // Set to same value to reset timer1 to 0 after a compare match TIMSK = _BV(OCIE1A); // Interrupt on compare match with OCR1A // Start timer in CTC mode; prescaler = 4096; TCCR1 = _BV(CTC1) | _BV(CS13) | _BV(CS12) | _BV(CS10); sei(); TinyWireS.begin(I2C_SLAVE_ADDR); TinyWireS.onReceive(receiveEvent); TinyWireS.onRequest(requestEvent); } void loop() { // This is required by TinyWire TinyWireS_stop_check(); // Blink LED if (timer1) { timer1 = false; digitalWrite(3, led ? HIGH : LOW); led = !led; } // Sleep to save power sleep_enable(); sleep_cpu(); } |
The expected output from the ESP-12E is:
tx = 1
rx = 12
tx = 2
tx = 13
tx = 3
rx = 14
and so on, all with the LED blinking on the ATtiny85 at roughly 1Hz.
There are very few sources I could find on the Internet on interfacing ESP-12E (or ESP8266) with ATtiny via I2C, so let this post be a confirmation that it can be done quite easily.
I took note of Liebman's comment below and added this line:
Wire.setClockStretchLimit(1500);
Works a treat, and I was able to run ATtiny85 at 1MHz without impacting the reliability of the I2C communication with ESP-12E.
Notes:
- Changed LED output PIN from PB1 to PB3. Since PB1 is involved in the programming of ATtiny85, it is possible to encounter intermittent failure with the upload of programs when the LED is blinking. Changing the output PIN to PB3 (which is not connected to the programmer) eliminates this issue.
- Since PB0 and PB2 are used for programming the ATtiny85 as well as I2C communication with the ESP-12E, these connections have to be removed from the ATtiny85 before uploading a program.
I've found that setting the clock pre-scaler on the ATtiny85 to to 2, reducing the clock from 8mhz to 4mhz in setup() will reduce power consumption by ~ 50% for non sleep modes. I2C with the ESP still seemed to function, I also attempted 1mhz but I also found that I2C fails on the ATtiny85. The only side effect is that any standard Arduino timing functions will not be correct, which does not matter for my implementation as I don't use them, I'm time keeping with a DS3231 RTC.
ReplyDeleteATtiny85 works fine at 1mhz. The issue us that the ESP as a master has a fairly short limit on clock stretch support. This is configurable and I've had good luck, so far, using 1500us as opposed to the default 230us. I've tested with USIWire as well as the "wire" library supplied with ATTinyCore.
ReplyDeletewhere is the TinyWireS.h can download? I had try many TinyWireS.h that all cant use the "TinyWireS.onReceive(receiveEvent);" ....
ReplyDeletethanks
Is possible using I2C and UART on the same time ?
ReplyDelete