Tag Archives: I2C Conundrums

I2C Conundrums

Resolved  - working though still don't know why Arduino single write was causing problems - however - got a way around it.

Firstly why am I doing this i2c thing? Well, the little ESP8266 is a wonderful thing but there are some chips out there that are really neat and work on I2c. More’s the point there are some REALLY cheap and powerful Arduino-compatible boards out there which benefit from the vast wealth of Arduino libraries – but don’t have WIFI..

So it occurred to me to add an I2c interface to my software – to talk to the likes of the Arduino.

And that it does – kind of – but I’m hitting a brick wall on return data. That is, return data over one byte – well, kind of… let me explain.

The ESP i2c is of course bit-banged because the chip itself does not do I2c – but it is fast at 80Mbps so you would expect it would work without issue. I am using the i2c master software that comes in the Espressif SDK – I’m using version 2.00. I’m programming in C.

The Arduino code is  using the latest Arduino IDE 1.69 and straight forward WIRE code. This is the SLAVE.

I can send multiple bytes to the Arduino - no problem - and I can get a byte back into the ESP no problem.

Now bearing in mind that [a] my experience with i2c is minimal [b] the Arduino I2c looks completely different to the ESP I2c....

When I first wrote this – I was getting reboot problems with the ESP when trying to return multiple bytes. Not every time – just every now and then.

I checked my code and I am initialising the I2c every time I use it – for various reasons.  When I put a logic analyser on the 2 i2c lines, I could see what looked like good i2c – but at the start, a whole load of clock pulses. 48 of them in fact. I went into the Espressif code only to find a loop in the initialisation – (it is in i2c.c).

void ICACHE_FLASH_ATTR
i2c_master_init(void)
{
/*
uint8 i;

    i2c_master_setDC(1, 0);
i2c_master_wait(5);

    // when SCL = 0, toggle SDA to clear up
i2c_master_setDC(0, 0) ;
i2c_master_wait(5);
i2c_master_setDC(1, 0) ;
i2c_master_wait(5);

    // set data_cnt to max value
for (i = 0; i < 28; i++) {
i2c_master_setDC(1, 0);
i2c_master_wait(5);    // sda 1, scl 0
i2c_master_setDC(1, 1);
i2c_master_wait(5);    // sda 1, scl 1
}

    // reset all
i2c_master_stop();
return;
*/

i2c_master_setDC(1, 1);
}

I have absolutely no idea why that is in there but it does not appear to be part of the I2c specification – so I cut it out – all that’s needed at the beginning as far as I can see is for data and clock to be high. The main init routine which calls this one (i2c_master_gpio_init()) sets the pins up the right way (pins 4 and 5 by default).

Well, this did not seem to have a lot of effect – except that now I can’t crash the ESP8266.

So – I can send data to an Arduino with I2c slave running – and I can receive a byte back – wheeeeee.

If I return one byte to the ESP - all is fine - works perfectly – but then the rot….
So --- Arduino...

//function that executes whenever data is requested by master
// this function is registered as an event, see setup()
void requestEvent() {
Wire.write(retParam); // *****
}

That works – and now the ESP

i2c_master_gpio_init();
i2c_master_start();
i2c_master_writeByte((arg1<<1)|1);
if (!i2c_master_checkAck())
{
i2c_master_stop();
os_sprintf(strValue, "duff i2c");
}
else
{
uint8_t a;
a=i2c_master_readByte(); //*******
i2c_master_stop();
os_sprintf(strValue, "%d",a);
}

That also works... but add another write for the Arduino where I've put stars *** and another read in the ESP code where I've put stars – even with a i2c_master_send_ack() in between - it does not work – the second byte is returned (not the first) and then a  255  is returned.

So here is the multi-byte return on the ESP side..

      a=i2c_master_readByte();
i2c_master_send_ack();
b=i2c_master_readByte();

      i2c_master_stop();
os_sprintf(strValue, "%d %d",a,b);

Sending 2 bytes from the Arduino…

void requestEvent() {
Wire.write(33);
Wire.write(45);
}

FAILS!!!

This however SEEMS to succeed and since my other change – seems to work reliably.

Wire.write("This is it you know",X);
// where X is how many chars to send out - I've tested 19 chars repeatedly.

In the above I’m just returning the first 2 bytes of course and this can be turned into byte arrays  or whatever..

I2c logic

But the question is – WHY does the first version screw up?

Anyway here is the ESP code that works with the above where X is 19...

i2c_master_gpio_init();
                  i2c_master_start();
                  i2c_master_writeByte((arg1<<1)|1); // send a read command
                  if (!i2c_master_checkAck())
                      {
                          i2c_master_stop();
                          os_sprintf(strValue, "duff i2c");
                      }
                  else
                      {
                            uint8_t buff[40],a;
#define I2CINB 19
                            for (a=0;a<I2CINB;a++) {
                                buff[a]=i2c_master_readByte();
                                if (a<(I2CINB-1)) i2c_master_send_ack();
                            }
                            buff[a]=0;
                          i2c_master_send_nack();
                            i2c_master_stop();
                            os_sprintf(strValue, "%s",buff);
                      }

Lovely – now I need to find some i2c chips to experiment with. I have an ATMEGA1284 setup to respond to i2c for port input, output with PWM and analog in where appropriate – the 1284 you may recall has a lot more pins than the Arduino.  I have a few variations of miniature boards on the way to test. When I really go to town on this I’ll no doubt blog it.

Facebooktwittergoogle_pluspinterestlinkedin