Skip to content
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

Support for I2C slave mode #1330

Closed
kdsoo opened this issue Dec 30, 2015 · 38 comments
Closed

Support for I2C slave mode #1330

kdsoo opened this issue Dec 30, 2015 · 38 comments

Comments

@kdsoo
Copy link

kdsoo commented Dec 30, 2015

I'm trying to run Adafruit esp8266 breakout as i2c slave using gpio 13 as scl and 14 as sda.
Going through the Wire library code, I found it inapplicable to run esp as i2c slave with changed pin configuration.
For ordinary use of Wire library for i2c slave configuration, we put slave address as Wire.begin() argument like "Wire.begin(address)"
But considering Wire.pins() deprecated, there is no way to change i2c pin configuration. Am I getting right?
So, how could I use esp as i2c slave with changed pin configuration?
Any pointer will be appreciated.

Want to back this issue? Post a bounty on it! We accept bounties via Bountysource.

@Links2004
Copy link
Collaborator

the ESP currently only support I2C master mode you can not run it in slave mode.

@kdsoo
Copy link
Author

kdsoo commented Dec 31, 2015

@Links2004 Thanks. I'll look for alternative interface to give commands to ESP.

@isparkes
Copy link

Is there an underlying reason not to implement slave mode, or is it just a "didn't get round to it yet" situation? If it's just a matter of priorities, I'd have a go at implementing slave mode...

@Links2004
Copy link
Collaborator

there is no technical limitation, simple no one has done it yet.

@isparkes
Copy link

OK, great. I need it for a project I am doing. If I can get it to work reliably, I'll make a pull request for it.

@igrr igrr changed the title Run as I2C slave with pin changed Support for I2C slave mode Feb 29, 2016
@francox-sg
Copy link

yes!!! i need this library for my proyect, esp i2c slave is a priority for the community, if not, i2c can´t be implemmented completely (sorry for my english)

@francox-sg
Copy link

and... i can´t install the new library version of esp arduino ide....

@isparkes
Copy link

isparkes commented Mar 3, 2016

I looked into this, and I don't see an easy way to do this at the moment. The SDK does not provide support for interrupts, and therefore the interrupt driven slave mode which requires this is not an easy implementation at the moment.

@Links2004
Copy link
Collaborator

there are interrupts, only for GPIO16 not.
we use them for attachInterrupt for example.
https://github.com/esp8266/Arduino/blob/master/cores/esp8266/core_esp8266_wiring_digital.c#L112
https://github.com/esp8266/Arduino/blob/master/cores/esp8266/core_esp8266_wiring_digital.c#L137
how fast you can go with simple use attachInterrupt needs to be tested.
but default I2C run at 100kHz or for high speed 400kHz, I think this is reachable.

@isparkes
Copy link

isparkes commented Mar 7, 2016

Yes, I see that now. I was kind of hoping that the SDK would bring support for Slave Mode, but it doesn't. However with the point you bring, I agree, it should be possible to implement it outside of the SDK.

@chrischsc
Copy link

I would be really interested in this. Any progress or investigations so far?

@Seriga
Copy link

Seriga commented Apr 22, 2016

Can anyone have some developments for the implementation of the slave mode?

@ESP32DE
Copy link

ESP32DE commented May 1, 2016

@judge2005
Copy link

Hi,

Well I've read through the espressiff topic listed above, and Am still not sure what the status is. There are a lot of code snippets, but there doesn't seem to be a complete posted solution, and it seems like there are still open questions. I don't have the time or the equipment to try and mold it all into a library, or even a chunk of code that I could just use. Do other people agree with my assessment of that thread? If you don't, could you post a complete, self contained solution?

Thanks - Paul

@bjoham
Copy link

bjoham commented Jan 30, 2017

I have done it. See http://www.esp8266.com/viewtopic.php?f=33&t=13546&p=0&e=0&sid=7f3455a872dbecf1ef55add30b106aae

@jhonoryza
Copy link

@bjoham can u push the implementation i2c-slave to the master branch? :)

@bjoham
Copy link

bjoham commented May 13, 2017

Done! (???)

@Testato
Copy link
Contributor

Testato commented May 23, 2017

@bjoham
are you pushed a PR for your work ?
It is very interesting merge it to master branch

@mfatiga
Copy link

mfatiga commented Jun 29, 2017

What's going on with this issue? Is there any reason this is not merged to master yet? #3287

@newbee42
Copy link

Hello all,

i am not very familiar with the concepts of git/github. However i ask myself, when the corrected Version including i2c slave support is available for regular arduino style programmer. I need this possibility to set esp8266 into the slave mode. So far i could see, a merge was done of the correct code with the main source code, so what are the next steps?

At all developpers of this code: thank you for the support of the ESP8266 platform, and go further, especially with i2c slave mode :o)

newbee42

@bjoham
Copy link

bjoham commented Jul 14, 2017

If there are steps missing for others to try this out, please let me know. I have not fully grasped how to do these things yet.

On my list, there are still the action points on testing (and fixing) the functional issues reported earlier.

@bjoham
Copy link

bjoham commented Jul 14, 2017

My setup still works without (noticable) issues on the I2C side.

From the temperature graph from the last few weeks, however, it is apparent that painting the temperature sensor's housing with a non-white color was not a good idea. Perhaps it could be used as a good-weather detector... (The sensor is on the north side of the house and since we have long nights during the summer, there are two temperature spikes every day with clear skies.)

thermiq

@newts
Copy link

newts commented Aug 4, 2017

Thanks for the i2c slave stuff. I am looking into it now for a project. What did you do for your weather data? I am looking at something similar maybe I want to simulate a SHT-3X chip to display outdoor weather data on a cheap temperature/humidity display like this: https://www.amazon.com/gp/product/B000XTJRRA/ref=oh_aui_detailpage_o00_s00?ie=UTF8&psc=1

The idea is I have wunderground station and can get the temperature and humidity via wifi and provide it to the display device as if I was a SHT-3X.

jv

@devyte
Copy link
Collaborator

devyte commented Oct 19, 2017

It seems that the referenced PR is still not merged.

@pdewilde
Copy link

Bump

@cmoine
Copy link

cmoine commented Apr 23, 2018

Instead of a PR which seems complicated, could we have a snippet/source code instead ?

@palto42
Copy link

palto42 commented Apr 23, 2018

You can find the code in the pull request #3287 (see commits)
There seems to several open comments in the pull request for I2C slave support, guess that's why it's not accepted in current format. To me it looks that mainly some code clean-up is requested.

@devyte
Copy link
Collaborator

devyte commented Oct 26, 2018

Fixed in #5226 .

@dav1d-wright
Copy link

Hello,

I have Version 2.5.2 installed but I can't get the I2C slave mode to work. Even with the Arduino slave_receiver example it does not work. Can someone help me on this? Here is my code:

// Wire Slave Receiver
// by devyte
// based on the example by Nicholas Zambetti <http://www.zambetti.com>

// Demonstrates use of the Wire library
// Receives data as an I2C/TWI slave device
// Refer to the "Wire Master Writer" example for use with this

// This example code is in the public domain.


#include <Wire.h>

#define SDA_PIN 12
#define SCL_PIN 13

const int16_t I2C_SLAVE = 0x12;

void setup() {
  Serial.begin(115200);           // start serial for output

  Wire.begin(SDA_PIN, SCL_PIN, I2C_SLAVE); // new syntax: join i2c bus (address required for slave)
  Wire.onReceive(receiveEvent); // register event
}

void loop() {
  delay(1000);
  Serial.println("Loop");
}

// function that executes whenever data is received from master
// this function is registered as an event, see setup()
void receiveEvent(size_t howMany) {

  (void) howMany;
  while (1 < Wire.available()) { // loop through all but the last
    char c = Wire.read(); // receive byte as a character
    Serial.print(c);         // print the character
  }
  int x = Wire.read();    // receive byte as an integer
  Serial.println(x);         // print the integer
}

I am displaying the communication lines on a scope and don't see the slave ACKs

@earlephilhower
Copy link
Collaborator

@wrd90, I'm doing a big rewrite on the I2C code to reduce the memory footprint in #6326. Unfortunately, for me it's been an exercise in hand optimization as I'm not actively using anything over an I2C now. That said, though, I've gone over the FSMs a few times (they're hairier than I would have thought) and might be able to work through some cases by hand and see what's going on.

Can you provide some full logic analyzer traces of SCA/SDL over the entire communications that are failing? A picture is worth a thousand words, as they say...

@earlephilhower
Copy link
Collaborator

Oh yeah, if you could capture at a 10x+ multiple of SCLK since there are dependencies on the order of signals changing that would be most useful. (i.e. if SCLK comes in 10ns before a SDA transition vs. 10ns after a SDA change then things could follow a different path)

@dav1d-wright
Copy link

Hi @earlephilhower and thanks for the quick reply! That sounds great already thank you! I can certainly provide some scope screenshots by tomorrow.
Have you already been able to pin point the rough arwa where this issue might be located? Maybe I could be of some assistance.
Do you maybe have an intermediate copy of the code that might provide some fixes?

@earlephilhower
Copy link
Collaborator

earlephilhower commented Jul 26, 2019

No fixes yet, sorry. I've just been trying to make sure the slimmed-down version has only the same bugs as the original code. :)

With a waveform where you can tell which xisition precedes another, though, it's simple enough to trace the logic. It looks like basically slave I2C is straightforward (again, famous last words), if it detects its address (which it seems to be, since you're seeing returned data), with it just having to ship in/out the data bits and the nack flag...

@dav1d-wright
Copy link

Hello @earlephilhower,

I'm sorry I didn't have enough time yesterday after all. I am attaching the screenshots, and I uploaded CSV files to my Dropbox, since I can't share upload them here. I hope they are what you need!

Best,
David

https://www.dropbox.com/s/eihh534q58dmu1p/scope_1_SBUS1_I2C.csv?dl=0
https://www.dropbox.com/s/3ktnc7mamqqro5i/scope_1_SCL1.csv?dl=0
https://www.dropbox.com/s/lopkz5s3fsmtdou/scope_1_SDA1.csv?dl=0

scope_0

scope_2

@earlephilhower
Copy link
Collaborator

I'm traveling for a few days but will give these a look when I get back. The CSVs looks like they have good sampling rates so edge ordering should be easy to catch.

@earlephilhower
Copy link
Collaborator

Scratch my last comment, on further inspection I see it trying to generate ACK in the prior state:

case TWIP_SEND_ACK:
if (scl) {
// ignore
} else {
if (twip_mode == TWIPM_IDLE) {
if ((twi_data & 0xFE) != twi_addr) {
// ignore
} else {
SDA_LOW();
}
} else {
if (!twi_ack) {
// ignore
} else {
SDA_LOW();
}
}
twip_state = TWIP_WAIT_ACK;
}

My guess, then, is that the address is not matching the expected value. Adding in some printfs when it hits the TWI_SEND_ACK state of the current twi_data that it's captured would be instructive. Either it's not getting to this state at all, in which case there'd be no printouts, or it's getting there but with maybe an extra or missing shift so it's out-of-sync.

@Git-Bruno
Copy link

Hi, I am seeing the same behavior that David reported with all bytes sent from a I2C master device to a WEMOS Mini Pro board beiing NACK'ed.
I run SDK 2.5.2 too. The I2C master clock is around 180kHz.
I have added code in the onSclChange function in core_esp8266_si2c.cpp to toggle a GPIO pin to get the SCL value echoed to a test pin :

// GPIO15 is D8 on WEMOS Mini
#define GPIO15_H (GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, 1<<15))
#define GPIO15_L (GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, 1<<15))
#define GPIO15(x) ((x)?GPIO15_H:GPIO15_L)
void ICACHE_RAM_ATTR onSclChange(void)
{
static uint8_t sda;
static uint8_t scl;
sda = SDA_READ();
scl = SCL_READ();
GPIO15(scl);
.....

The screenshot attached shows that there is a significant delay in toggling the test pin on SCL changes and that some SCL changes are not echoed to the test pin.
The more changes on SDA the worst the situation gets. I presume this is because calls to the onSclChange()
SCL_echo
get more delayed by calls to onSdaChange().
Setting the WEMOS clock to 160MHz (default is 80MHz) helps a little bit but not all SCL changes are echoed.
No sure why there is this 6µs between a SCL change front and the pin toggling as the test is done witn the slave_receiver.ino sketch with on I2C slave code running.

Best,
Bruno

@bjoham
Copy link

bjoham commented Aug 1, 2019 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests