-
Notifications
You must be signed in to change notification settings - Fork 13.3k
ESP8266 as a I2C slave #5762
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Do you use in your circuit two pull-up resistors? |
I have external pull-up resistors (on SDA and SLC), which in any case I don't believe I need since there is only 2 devices on the bus, 1 master and 1 slave. |
Hi @gotfredsen I have the same issue here. This driver works well between two ESP8266 (e.g. Adafruit HUZZAH ESP8266 Breakout - one being master and the other slave). But it does not work using one ESP8266 and another board (w/ different driver - e.g. Teensy 3.x). Anyone had success using 2 different boards/drivers ? I tried without pull-up resistors, then with (4k7, 2k2, 2k7, 10k) and also with different clocks... No success in any of these cases. |
Hi, Is the problem solved?I have the same issue here. This driver works well between two ESP8266,But it does not work using one ESP8266 and arduino uno |
per #5226 (comment)
What is the maximum reachable & sustainable clock frequency between esp8266 hardware i2c master and software i2c slave ? |
I have the same issue. I can get the ESP8266 to work as a master with my Mega2560, but when I flip the roles where the ESP8266 is in slave mode it doesn't appear to respond to either request or receive event. Tried setClock at 50000, 100000, 200000, and 400000. Also, on the same bus I have a PCA9685 that responds to the mega when it's the master with no problem. Using a 5v/3.3v level shifter between the two sides (also skipped that and ran the mega at 3.3v too with no luck). The ESP8266 in my case is Adafruit's HUZZAH. Edit: after trolling through the related issue threads here on this topic I'll just stick with using this device and my mega as multi-masters where the esp can spam the mega as needed. Where the mega needs to get something to the esp it can do so when the esp asks (on some polling interval). |
I'm testing esp8266 (wemos DI mini) as slave with esp32 (micropython) as master, as far I can tell, esp8266 receive from ESP32 but cannot sent any data back. Micropython error is:
execute without problem and my debug on esp8266 slave reports all correctly:
my ESP32 communicate with attiny without any problems. |
I have exactly the same issue like thread opener @gotfredsen. I further investigated with a logic analyzer and sigrok's pulseview app. From what I see is: esp8266 has - running at 80MHz - not enough performance for receiving at 100kHz with the current implementation. For research I used master_writer and slave_receiver. Block A withAddress Block B noAddress Hopefully @pasko-zh finds time to finish #2055. I could attach some screenshots of pulseview for the test cases above, if this is of any interest. |
Unfortunately, @pasko-zh's code is licensed under GPL3, which is incompatible with our repo license. Unless that very nice implementation changes licensing, or we get an explicit exception, we can't integrate it directly here. |
I've looked at @pasko-zh's code, and while it looks really nicely built and organized (best comments in ASM I've seen in a long time), I don't think it really solves the problems here. From what I read, brzo-i2c is a master-mode only implementation, and it's fully busy-waiting (i.e. 100% of CPU while running). For master transactions, that's probably fine and the most direct way to make it happen. His scope traces look really gorgeous this way! But on a slave, you need to do IRQ triggered operations or else you can't use the 8266 to do anything else besides busy-waiting (i.e. no wifi, no anything). The current slave code is slow because it probably spends >50% of its active CPU time in OS IRQ handling code before the ROM calls our IRQ handler (saving processor state, etc.) So it loses edges easily and that limits the slave clock rate it can work at. It also is going to be hit by IRQ disable windows when doing WiFi operations, increasing the required clock cycle for stable operation. Something that short-circuits the OS IRQ handling and does the slave FSM immediately, with minimal register usage, and which makes the IRQs NMI if possible, might be able to move the needle. Or, a creative (ab)use of the I2S port might be able to do it. There is a PR #6326 which focused on reducing IRAM usage, but which should also (because of using fewer instructions) run at slightly higher frequencies. @schliepi, would you be able to give it a try and see if it helps in any way (or if it busts slave mode completely)? |
Some further investigation later. Is it really OS IRQ handling that slows slave mode down? This is the simple Arduino sketch:
Measuring with logic analyzer at 24MHz: 4us until my code executes in iterrupt? I read this over at espressif
|
IIRC, there's not a separate IRQ vector for each pin change, only one general GPIO IRQ. That pin change IRQ then needs to figure out which callback to call, so I am pretty sure there's a reasonable amount of code being executed before the first insn of our callback gets executed. I would be happy to be proven otherwise, because if it's in our code we can try and do something about it! A test you can automate would be to use |
@gemu2015 had problems with i2c too. He found a solution for his driver (for Tasmota) |
CC @Tech-TX |
I'll look into it, but if the IRQ response time is 4us then the slave code won't work with most masters. In the spec there's a zero minimum hold time requirement on SDA after SCL falls from the master. That needs a latch to catch reliably. The data won't be there when we eventually read it, if the read is delayed by 4us. I can check it on a 'scope to see what it's doing and get better resolution. The GPES = (1 << D1) pin wiggles above I already have the definitive timing for: |
BTW, the full comment on the Espressif BBS is this:
Note the date. There have been significant changes to the core since 2015. The most recent (this week) test of GPIO interrupt latency with the current core is: GPIO Interrupt latency at 80MHz, code supposedly in IRAM: GPIO Interrupt latency at 160MHz, code supposedly in IRAM: The times are exact +/- 5ns, the 'cycles' are a rough equivalent in machine cycles; the machine cycles aren't exact. Due to the difference @ 80/160, it looks like there's a cache miss somewhere, as that would show greater effect at 160MHz. I tried bumping my D1 Mini boards up to QIO 80MHz and couldn't see any difference, so I guess the core isn't executing that speed init for my flash chips.
You always need external pull-up resistors on SDA and SCL if you expect it to run reliably or else you're driving the bus with a sawtooth. Using only the ~50K internal pull-ups in the chip violates the I2C spec on risetime. The only reason the internal pull-ups are even included in the library is because sooo many people don't know anything about I2C. Common values for external pull-up resistors is 4.7K to 10K, even lower if you're running at 400KHz or faster. Most modules include pull-up resistors in the 10K range, which is sufficient for 100KHz bus speeds, and usually works at 400KHz. |
Reducing 2.7.0 scope. This is to be handled as part of the ongoing Wire rework. |
I have a Pi Zero W that's on it's first boot, and updates are taking forever. I think I can drive the I2C port a couple of different ways. There's some helpful hints regarding RPi and I2C here: Sorry, never seen a Micro:Bit. You have to compile @ 160MHz CPU speed to get the slave to talk at 50KHz. I haven't tried it yet with an 80MHz CPU compile and slower bus speeds. That's next on my list of Things To Test. I'll have some more info later on. Apparently the Pi hardware supports clock stretching, but the driver doesn't (or didn't). It's hard to tell for sure. |
I've been looking further, and here's a good breakdown on why people are having problems with the Pi: The ESP8266 I2C library is working within the I2C spec even now. The Ras Pi is violating the spec two different ways, and will have problems with numerous other devices that stretch. We can only go so far to fix someone else's broken hardware implementation. |
I trying to communicate through i2c from esp32 to esp8266. Probably problem with esp8266, it doesn`t working as slave. I have no success, maybe someone can help or tried to do that? |
Amazing. This works! A few things I also think people should know - hell, I wish I knew before:
|
@Tech-TX Could you give a hint on what "connected appropriately"? So I imagine you put pull-up resistors on scl and sda, between them and 3.3V, I take it? I tried this, but I'm having lots of trouble to get data transferred. From the pi to the Wemos D1 Mini I get a few packets sent, then a 121 Remote I/O error. From the Wemos to the Pi I never get any data that makes sense. |
I have the same problem, I have a WeMos D1 Mini (ESP8266). In Arduino IDE I am unable to get it work in I2C slave mode. How did some people here made it work in slave mode? |
I have also the same problem. I can't run the ESP8266(NodeMCU v3 - 1.0) with CC430 as slave. Reverse of it which CC430 as slave receiver and NodeMCU is master sender I can get all of the chars. However I can't get any character if I use NodemMCU as slave receiver. |
Edit: Sorry, my answer was not relevant to the question. |
Thank you for replying.
I did almost a week of research and answers told that the ESP8266 does not support I2C slave mode due to its hardware processing design.
The ESP8266-EX chips does support full I2C modes. Therefore I bought the EX version.The regular big chunky with the silver shield ESP8266 does not support I2C slave.
I read that two ESP8266, one master and one slave can work, but when a master is another type of chip brand, it will not work.
The only way to get it to work is by writing your own assembly code with interrupts for a software implementation of I2C slave (which is still not practical due to slow data rates).
SPI and all other protocols are not useful to me. The I2C protocol in multi-master mode suits my needs.
On Tuesday, January 5, 2021, 9:20:21 AM EST, Jiri Bilek <[email protected]> wrote:
Are you sending the right data to the ESP8266? Are you aware that there is a proprietary protocol running on the SPI layer the ESP only recognize?
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub, or unsubscribe.
|
I know you will not like this answer, but from my experience you will waste massive amount of valuable time to get the esp8266 working as I2C slave. It will not work due to the fact the company decided not give support in the hardware design for the esp8266 to work as a salve.
You have two options:
1) Write your own I2C slave code in pure assembly language with the concept of interrupts, this will give you I2C slave mode but the data rates will be slow and unreliable overall.
2) Buy the ESP8266-EX chips (these does not have the silver shield). This particular chip is the better and newer version compared to the regular ESP8266 and supports full mode of I2C.
Good luck.
On Tuesday, January 5, 2021, 9:02:52 AM EST, firtinahg <[email protected]> wrote:
I have also the same problem. I can't run the ESP8266(NodeMCU v3 - 1.0) with CC430 as slave. Reverse of it which CC430 as slave receiver and NodeMCU is master sender I can get all of the chars. However I can't get any character if I use NodemMCU as slave receiver.
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub, or unsubscribe.
|
@rajhlinux Sorry, I was mistaken, I have no experience in I2C slave communication in ESP8266. Please ignore my previous post. |
My research further up in this issue showed ESP8266 not being able to catch up to I2C speed 100kHz. When using an Arduino Uno as master and ESP8266 as slave, I had to slow down I2C speed to 25kHz to get it working. But this resarch was before refactoring of I2C code happened. I cannot say how much better (or worse?) it got. ESP8266 user interrupt response time to a changing input pin simply is too slow. |
I have the Espressif ESP8266-MOD chips. The one with the big silver metallic shield.
I have tired many Arduino sketches to run the the I2C slave mode for the ESP8266 (Yes, I have installed the latest ESP Arduino cores) and never got it to work.
Also tried running at 25 KHz and no luck.
Yes, interrupt I2C implementation is too slow and not worth it.
It's like a hit or miss, some people got it to work some don't, really weird. I think it could be because there are few variations of the ESP8266 chips. Such as "AI thinker" also makes ESP8266 chips (maybe they pay royalties to Espressif).Some people do not realize that even the manufacturer (Espressif) states in their datasheet that only I2C master works but not slave.
Because of this, I now always check all the specifications of a microcontroller before buying. Just because you see a microcontroller advertised having I2C, you'll need to further inspect the datasheet.There's even problems with I2C slave with ESP32.
On Wednesday, January 6, 2021, 03:33:06 AM EST, schliepi <[email protected]> wrote:
My research further up in this issue showed ESP8266 not being able to catch up to I2C speed 100kHz. When using an Arduino Uno as master and ESP8266 as slave, I had to slow down I2C speed to 25kHz to get it working.
But this resarch was before refactoring of I2C code happened. I cannot say how much better (or worse?) it got.
ESP8266 user interrupt response time to a changing input pin simply is too slow.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub, or unsubscribe.
|
If I remember right I got around my issues with it not slaving right by using the bus with multi-master. Effectively I set it up so that both my desired Arduino master was a master and the ESP was also a master. The two of them work fine like this and my Arduino handles the other slaves as well. For those that want the ESP to be a slave try the multi-master approach.
Edit: trashed mail reply leftovers. Also, I just read this thread on Git and my original comment does mention multi-master as well.
|
Thank You for your quick reply.
Yes, sorry if I wasn't clear. I was trying to make my ESP as a slave for an implementation for it to be a multi-master. There are techniques and approaches where in a given multi-master system, a master should be "listening" for incoming data in I2C slave mode. The benefits for this approach is that the multi-master device is always listening (slave mode) and does not need to provide a clock signal, therefore it will always be listening in the I2C bus. This implementation is a quick alternative from using the "CAN Bus Protocol". When the ESP multi-master device needs to send data it is in the (master-mode). The programmer needs to implement collision detection for a multi-master device utilizing both as a slave and master modes.From my experience the ESP8266 does not work for the above multi-master implementation.
Also the older ESP8266 (Also know as "ESP12E" or "ESP12F" with the metallic shield) does not work in I2C slave mode even with software implementation. The newer ESP8266-EX does work as slave/master mode. If anyone needs to implement the ESP in slave mode, they should first consider is obtaining the "ESP8266-EX", make sure it has "EX" (This chip does not have the metallic shield and is almost 4 times smaller than the ESP12E or ESP12F.)
On Wednesday, January 6, 2021, 12:15:16 PM EST, jasondickert <[email protected]> wrote:
If I remember right I got around my issues with it not slaving right by using the bus with multi-master. Effectively I set it up so that both my desired Arduino master was a master and the ESP was also a master. The two of them work fine like this and my Arduino handles the other slaves as well. For those that want the ESP to be a slave try the multi-master approach.
On Jan 6, 2021, at 11:55 AM, rajhlinux <[email protected]<mailto:[email protected]>> wrote:
I have the Espressif ESP8266-MOD chips. The one with the big silver metallic shield.
I have tired many Arduino sketches to run the the I2C slave mode for the ESP8266 (Yes, I have installed the latest ESP Arduino cores) and never got it to work.
Also tried running at 25 KHz and no luck.
Yes, interrupt I2C implementation is too slow and not worth it.
It's like a hit or miss, some people got it to work some don't, really weird. I think it could be because there are few variations of the ESP8266 chips. Such as "AI thinker" also makes ESP8266 chips (maybe they pay royalties to Espressif).Some people do not realize that even the manufacturer (Espressif) states in their datasheet that only I2C master works but not slave.
Because of this, I now always check all the specifications of a microcontroller before buying. Just because you see a microcontroller advertised having I2C, you'll need to further inspect the datasheet.There's even problems with I2C slave with ESP32.
On Wednesday, January 6, 2021, 03:33:06 AM EST, schliepi <[email protected]<mailto:[email protected]>> wrote:
My research further up in this issue showed ESP8266 not being able to catch up to I2C speed 100kHz. When using an Arduino Uno as master and ESP8266 as slave, I had to slow down I2C speed to 25kHz to get it working.
But this resarch was before refactoring of I2C code happened. I cannot say how much better (or worse?) it got.
ESP8266 user interrupt response time to a changing input pin simply is too slow.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub, or unsubscribe.
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub<#5762 (comment)>, or unsubscribe<https://github.com/notifications/unsubscribe-auth/ADUD3HEHSQQDH6JTXKA3CPDSYSIZRANCNFSM4GXXETQA>.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub, or unsubscribe.
|
For documentation, as I've got it hooked up at the moment:
Master #include <Arduino.h>
#include <Wire.h>
#include <PolledTimeout.h>
#define SDA_PIN D1
#define SCL_PIN D2
const int16_t I2C_MASTER = 0x42;
const int16_t I2C_SLAVE = 0x08;
void setup() {
Wire.setClock(20000L);
Serial.begin(9600);
Serial.println("Master started");
Wire.begin(SDA_PIN, SCL_PIN, I2C_MASTER);
}
byte x = 0;
void loop() {
using periodic = esp8266::polledTimeout::periodicMs;
static periodic nextPing(1000);
if (nextPing) {
Serial.println("Ping");
Wire.beginTransmission(I2C_SLAVE);
Wire.write("x is ");
Wire.write(x);
Wire.endTransmission();
x++;
}
delay(100);
} Slave #include <Arduino.h>
#include <Wire.h>
#define SDA_PIN D1
#define SCL_PIN D2
const int16_t I2C_MASTER = 0x42;
const int16_t I2C_SLAVE = 0x08;
void requestEvent() {
Serial.println("Req");
}
void receiveEvemt(int a) {
Serial.println("Rec");
}
void setup() {
Serial.begin(9600);
Serial.println("Started");
Wire.begin(SDA_PIN, SCL_PIN, I2C_SLAVE);
Wire.onRequest(requestEvent);
Wire.onReceive(receiveEvemt);
}
void loop() {
delay(100);
} Setting down the clock using Build was done using PlatformIO 3.0.0 (2023-02-01) on Ubuntu KDE 20.04.5 LTS |
Basic Infos
Platform
Settings in IDE
Problem Description
While ESP8266(I2C Master) to ESP8266(I2C Slave) works, with a pinch†, I cannot get ESP8266 to work as an I2C Slave towards Raspberry Pi, Micro:Bit and others.
The sketch below works perfectly as an ESP8266 I2C slave used with a ESP8266 I2C Master, but not otherwise.
I can detect‡, the slave on a RPi using
i2cdetect -y 1
, but can't communicate with the slave. I have tried frequency change, clock stretching in Arduino, 3 different libraries on the RPi, and I have tried in MicroPython on a Micro:Bit to no avail.† In order to have the ESP8266 Master to work, I have to call the
Wire.begin()
with an address, like a Master address, that is not standard, but otherwise it won't work for me.‡
i2cdetect -y 1
only works 80% of the time, and while seemingly high, it is not 100% of the time like with all other I2C slaves.MCVE Sketch
Debug Messages
More attempts: Just to make sure I haven't lost it, I tried with another WiFi board, the Arduino MKR1000, and the above code (except for the pin allocations), and it worked perfectly.
Here is the RPi code, btw:
The text was updated successfully, but these errors were encountered: