esp8266 / Arduino

ESP8266 core for Arduino
GNU Lesser General Public License v2.1
15.99k stars 13.33k forks source link

ESP8266 as a I2C slave #5762

Open gotfredsen opened 5 years ago

gotfredsen commented 5 years ago

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

#include <Wire.h>
void requestEvent() {
  Wire.write("At your service!");
}
void setup() {
  Wire.begin(2,14,0x08);           
  Wire.onRequest(requestEvent);
}
void loop() {
}

Debug Messages

Debug messages go here

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:

import pigpio
pi = pigpio.pi()
handle = pi.i2c_open(1,8,0)
(count, data) = pi.i2c_read_device(handle, 16)
print(data)
pi.i2c_close(handle)
pi.stop()
pat1 commented 5 years ago

Do you use in your circuit two pull-up resistors?

gotfredsen commented 5 years ago

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.

r3na commented 5 years ago

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.

rousir commented 5 years ago

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

d-a-v commented 5 years ago

per https://github.com/esp8266/Arduino/pull/5226#issuecomment-478329905

This driver works well between two ESP8266

What is the maximum reachable & sustainable clock frequency between esp8266 hardware i2c master and software i2c slave ?

jasondickert commented 5 years ago

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

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).

nedoskiv commented 5 years ago

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:

>>> i2c.readfrom_mem_into(48, 0x14, data)

OSError: [Errno 19] ENODEV
It is I2C timeout/IO error

>> > i2c.writeto_mem(48, 0x04, b'\x00\x00\x01')

execute without problem and my debug on esp8266 slave reports all correctly:

loop1
processevent: 4,0,0,1,

my ESP32 communicate with attiny without any problems.

schliepi commented 5 years ago

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. Even at 160MHz there was no success at 100kHz. atmega328p works like a charm - it encodes/decodes i2c in hardware. esp8266 does not.

For research I used master_writer and slave_receiver. I tried two different Wire.begin() followed by Wire.setClock() for master_writer. Of course for each test case only one steClock-line active

Block A withAddress Wire.begin(SDA_PIN, SCL_PIN, I2C_MASTER); //Wire.setClock(50000L); // this results in 30.8kHz - success //Wire.setClock(100000L); // this results in 40.8kHz - success //Wire.setClock(400000L); // this results in 58.8kHz - success

Block B noAddress // patched core_esp8266_sic.cpp to accept setClock(25000L) Wire.begin(SDA_PIN, SCL_PIN); // join i2c bus (address optional for master) //Wire.setClock(25000L); // this results in 28.6kHz - success //Wire.setClock(50000L); // this results in 54.1kHz - no success //Wire.setClock(100000L); // this results in 90.9kHz - no success //Wire.setClock(200000L); // this results in 166.7kHz - no success

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.

devyte commented 5 years ago

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.

earlephilhower commented 5 years ago

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)?

schliepi commented 5 years ago

Some further investigation later. Is it really OS IRQ handling that slows slave mode down? Simple test setup how long it takes after input pin signal change until IRQ handler runs: D1 directly connected to D2. Interrupt attached to D2. When called set lines D5 and D6 low. So when I set D1 low, I expect some delay, an then D5 and D6 get pulled low.

This is the simple Arduino sketch:

#include <PolledTimeout.h>

#define D1_LOW()   (GPES = (1 << D1)) //Enable D1 (becomes output and since GPO is 0 for the pin, it will pull the line low)
#define D1_HIGH()  (GPEC = (1 << D1)) //Disable D1 (becomes input and since it has pullup it will go high)
#define D1_READ()  ((GPI & (1 << D1)) != 0)
#define D2_READ()  ((GPI & (1 << D2)) != 0)
#define D5_LOW()   (GPES = (1 << D5)) //Enable D5 (becomes output and since GPO is 0 for the pin, it will pull the line low)
#define D5_HIGH()  (GPEC = (1 << D5)) //Disable D5 (becomes input and since it has pullup it will go high)
#define D6_LOW()   (GPES = (1 << D6)) //Enable D6 (becomes output and since GPO is 0 for the pin, it will pull the line low)
#define D6_HIGH()  (GPEC = (1 << D6)) //Disable D6 (becomes input and since it has pullup it will go high)

void ICACHE_RAM_ATTR onD2Change();

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);           // start serial for output
  Serial.println();
  Serial.printf("getChipId     = %08X\n", ESP.getChipId());
  Serial.printf("getCpuFreqMHz = %8d\n", ESP.getCpuFreqMHz());

  pinMode(D1, INPUT_PULLUP);
  pinMode(D2, INPUT_PULLUP);
  pinMode(D5, INPUT_PULLUP);
  pinMode(D6, INPUT_PULLUP);

  attachInterrupt(digitalPinToInterrupt(D2), onD2Change, CHANGE);
}

void onD2Change() {
  D5_LOW();
  D6_LOW();
  D5_HIGH();
  D6_HIGH();
}

void loop() {
  // put your main code here, to run repeatedly:
  using periodic = esp8266::polledTimeout::periodicFastMs;
  static periodic nextPing(5);

  if (nextPing) {
    if (D1_READ() == 1) {
      D1_LOW();
    } else {
      D1_HIGH();
    }
  }
}

Measuring with logic analyzer at 24MHz: Time for D5 going low after D1/D2 going high: 4us. Time for D6 going low after D5 going low: 80ns. 5762-intr-speed

4us until my code executes in iterrupt? Am I measuring wrong? Running at 160MHz the times getting halved.

I read this over at espressif https://bbs.espressif.com/viewtopic.php?t=360#p1358

We test the normal latency is about 1~1.2us

earlephilhower commented 5 years ago

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 ESP.getCycleCount(). That's an internal 80MHz counter (even when core is at 160) and you can copy it just before writing to GPIO-Set and grab it again right at the top of your callback. Then in the main routine after some hardcoded delay you can do a delta from end-start and get the "speed of light" for IRQs...

Jason2866 commented 5 years ago

@gemu2015 had problems with i2c too. He found a solution for his driver (for Tasmota) https://github.com/arendst/Sonoff-Tasmota/pull/6360#issuecomment-530687041 EDIT: Ignore. Not related!

devyte commented 4 years ago

CC @Tech-Tx There are some known issues with I2C. I think stability should be improved first before this goes further. Pushing back.

Tech-TX commented 4 years ago

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: 44ns @ 80MHz, 35.25ns @ 160 from iram, 88ns @ 80MHz, 74ns @ 160 from flash so all I have to do is add a pin wiggle in the first line of Twi::onSclChange and I can subtract that and tell you exactly how long the response time is to within ~5ns. It's too late tonight, so I'll check it tomorrow.

Tech-TX commented 4 years ago

BTW, the full comment on the Espressif BBS is this:

Re: ESP interrupt latency Postby netlook » Thu Apr 16, 2015 1:43 pm

We test the normal latency is about 1~1.2us , Now the API "ETS_SPI_INTR_ATTACH(isr_handler, void *)" is directly attached on the interrupt vector.

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: CHANGE = 3.880us, ~310 cycles @ 12.5ns/cycle RISING = 3.921us, ~314 cycles FALLING = 3.921us, ~314 cycles

GPIO Interrupt latency at 160MHz, code supposedly in IRAM: CHANGE = 2.056us, ~329 cycles @ 6.25ns/cycle RISING = 2.081us, ~333 cycles FALLING = 2.081us, ~333 cycles

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.

@gotfredsen

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.

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.

devyte commented 4 years ago

Reducing 2.7.0 scope. This is to be handled as part of the ongoing Wire rework.

Tech-TX commented 4 years ago

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: https://www.abelectronics.co.uk/kb/article/1089/i2c--smbus-and-raspbian-stretch-linux notably that the clock wanders all over the place on the 3B, 3B+ and Zero W, and he has a fix to lock it down. The testing I just did with the slave side shows that the '8266 slave works from ~76KHz down to ~6.5KHz. Go faster and it NAKs, go slower and it looks like the event timer gets a timeout.

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. edit: at 80MHz, the slave operates solidly from 39KHz down to ~6.5KHz. It runs erratically from 40-43KHz, not recommended.

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.

Tech-TX commented 4 years ago

Update: success on the first try. I don't know what you folks are all doing wrong. I have a fresh install of the bloated Raspbian w/ desktop running on a Pi Zero W. I opened /boot/config.txt and added: dtparam=12c_arm=on dtparam=i2c1_baudrate=50000 and then down at the bottom added core_freq=250 as I didn't want the I2C bus clock wandering (see that link I posted just above)

I popped open a terminal window and ran sudo i2cdetect -y 1, and the Slave_Receiver was seen the first time and every time thereafter at address 0x08, no misses. Getting cocky, I next entered i2ctransfer 1 w28@0x08 0x01 0x41+ and the slave printed ABCDEFGHIJKLMNOPQRSTUVWXYZ91 on it's terminal monitor on the other computer. Hmmm. Looks like my Pi user already has i2c privileges, so I didn't need the sudo with i2cdetect. For someone that hasn't turned on a Linux command prompt since the pre-1.0 Slackware days, it wasn't too hard. I don't know what problems you're having, but it's working for me. Here's screenshots for proof: RPi monitor

Hardware: Pi Zero W, and a Wemos D1 Mini connected appropriately with 10K pull-up resistors on SCL and SDA. Latest Raspbian on the Pi with just the distribution files. Arduino 1.8.10 with the git install for the ESP8266 (latest, of course) and the default slave_receiver example program. Nothing special.

Tech-TX commented 4 years ago

I've been looking further, and here's a good breakdown on why people are having problems with the Pi: http://www.advamation.com/knowhow/raspberrypi/rpi-i2c-bug.html Compiling the slave side with a CPU Frequency of 160 MHz should minimize the slave clock stretches, but it won't eliminate them. The only stretches I see are on the ACK of the address, and they're around 150% the normal duration of SCL low. It stretches again about 170% width after the ACK for the address from a Repeated Start (if used). I can't do anything about that without a complete re-write of the slave, which I'm planning now. Don't hold your breath, as blue is probably not a good color for you. :wink:

slave stretch

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.

razzner commented 4 years ago

I trying to communicate through i2c from esp32 to esp8266. esp32 as master and esp8266 slave.

Probably problem with esp8266, it doesn`t working as slave.

I have no success, maybe someone can help or tried to do that?

oculos commented 4 years ago

Update: success on the first try. I don't know what you folks are all doing wrong. I have a fresh install of the bloated Raspbian w/ desktop running on a Pi Zero W. I opened /boot/config.txt and added: dtparam=12c_arm=on dtparam=i2c1_baudrate=50000 and then down at the bottom added core_freq=250 as I didn't want the I2C bus clock wandering (see that link I posted just above)

Hardware: Pi Zero W, and a Wemos D1 Mini connected appropriately with 10K pull-up resistors on SCL and SDA. Latest Raspbian on the Pi with just the distribution files. Arduino 1.8.10 with the git install for the ESP8266 (latest, of course) and the default slave_receiver example program. Nothing special.

Amazing. This works! A few things I also think people should know - hell, I wish I knew before:

oculos commented 4 years ago

Hardware: Pi Zero W, and a Wemos D1 Mini connected appropriately with 10K pull-up resistors on SCL and SDA. Latest Raspbian on the Pi with just the distribution files. Arduino 1.8.10 with the git install for the ESP8266 (latest, of course) and the default slave_receiver example program. Nothing special.

@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.

rajhlinux commented 3 years ago

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?

firtinahg commented 3 years ago

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.

JiriBilek commented 3 years ago

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?

Edit: Sorry, my answer was not relevant to the question.

rajhlinux commented 3 years ago

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 notifications@github.com 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.

rajhlinux commented 3 years ago

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 notifications@github.com 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.

JiriBilek commented 3 years ago

@rajhlinux Sorry, I was mistaken, I have no experience in I2C slave communication in ESP8266. Please ignore my previous post.

schliepi commented 3 years ago

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.

rajhlinux commented 3 years ago

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 <notifications@github.com> 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.

jasondickert commented 3 years ago

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.

rajhlinux commented 3 years ago

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 <notifications@github.com> 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 notifications@github.com<mailto:notifications@github.com> 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 notifications@github.com<mailto:notifications@github.com> 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 GitHubhttps://github.com/esp8266/Arduino/issues/5762#issuecomment-755424717, or unsubscribehttps://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.

jonasborn commented 1 year ago

For documentation, as I've got it hooked up at the moment: D1 Mini as master, NodeMCU v2 as slave

`PLATFORM: Espressif 8266 (4.1.0) > NodeMCU 1.0 (ESP-12E Module)
HARDWARE: ESP8266 80MHz, 80KB RAM, 4MB Flash
PACKAGES: 
 - framework-arduinoespressif8266 @ 3.30101.0 (3.1.1) 
 - tool-esptool @ 1.413.0 (4.13) 
 - tool-esptoolpy @ 1.30000.201119 (3.0.0) 
 - tool-mklittlefs @ 1.203.210628 (2.3) 
 - tool-mkspiffs @ 1.200.0 (2.0) 
 - toolchain-xtensa @ 2.100300.220621 (10.3.0)
LDF: Library Dependency Finder -> https://bit.ly/configure-pio-ldf
LDF Modes: Finder ~ chain, Compatibility ~ soft
Found 37 compatible libraries
Scanning dependencies...
Dependency Graph
|-- Wire @ 1.0`

image

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 Wire.setClock(20000L); was needed to get it working. Other clock times were not tested.

Without setting the clock: image

Build was done using PlatformIO 3.0.0 (2023-02-01) on Ubuntu KDE 20.04.5 LTS Edit: Formatting