Minimize clock stretching with arduino as slave in I2C

Hi!

I'm trying to emulate a slave in a i2c network with an Arduino Uno and the Wire library. Unfortunately I've run into a problem which I suspect is because the master doesn't support clock stretching.

Here is how the original slave handles it:

And here is how the Arduino responds:

This is my code:

#include <Wire.h>

u8 rBuf[] = {0x0A, 0xC1, 0x64, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};

void setup() {
  Wire.begin(0x58);
  Wire.onRequest(readRequest);
}

void loop() {
  delay(100);
}

void readRequest() {
  Wire.write(rBuf, 8);
}

Is there some way to reduce the stretching? Can I use a different library? Should I switch to another MC?

Thank you for the very nice pictures.

The single Wire.write( rBuf , 8 ) is the minimum. The Arduino as a Slave uses clock pulse stretching. If the Master does not support it, then it is sadly not possible to use an Arduino.

There is no way around it with other Arduino boards, it is not possible :cry:

If writing a register-address and reading a few bytes is all that is needed, then perhaps you can replace it with an 256-byte EEPROM which you can fill with your own data. The EEPROM must be located at 0x58, I don't know if that is possible.

Address 0x58 can be for example a TPA2016 amplifier or a SGP30 gas sensor. What is your Slave device ?

Koepel:
Thank you for the very nice pictures.

The single Wire.write( rBuf , 8 ) is the minimum. The Arduino as a Slave uses clock pulse stretching. If the Master does not support it, then it is sadly not possible to use an Arduino.

There is no way around it with other Arduino boards, it is not possible :cry:

If writing a register-address and reading a few bytes is all that is needed, then perhaps you can replace it with an 256-byte EEPROM which you can fill with your own data. The EEPROM must be located at 0x58, I don't know if that is possible.

Address 0x58 can be for example a TPA2016 amplifier or a SGP30 gas sensor. What is your Slave device ?

That's unfortunate. Would I be able to write directly to the TWI instead of going through the Wire library? If this still is not possible then I'll probably switch to a pic since they seem to have more control in this department. Any other devboard recommendations are also welcome.

No I need to alter the data on the fly so I don't think it's possible with a EEPROM. Maybe if the EEPROM (doesn't need to be static so ram would work too) had two interfaces so it could be written to by the arduino at the same time it is read on by the master.

I'm trying to emulate the ir camera in a Wii remote controller. The master is a BCM2042. Neither the master nor the camera have any datasheet so I don't know anything for sure.

A normal I2C device has a hardware interface for I2C and does not need clock pulse stretching.

A microcontroller or processor has a I2C interface that is a combination of hardware and software. They all need to stretch the clock pulse because of the software part. They need some time to run the code.
Using the TWI registers can not fix that. I don't know what a PIC can do, but that is probably no solution as well.

Suppose a Master does not support clock pulse stretching, then it will continue to send clock pulses and it will ignore that the clock is held low by the Slave.
When looking at the non-working picture, the Master generates 9 clock pulses after the Slave releases the clock :o That means that the Master is reading the clock and is waiting until the Slave releases the clock. That is very nice. At least there is something in the Master that does support it. Perhaps it is supported in hardware and not in software.
You could do a few more test to see if you can get further with this, but the chances are low. I'm afraid you have to give up on this project :confused:

But I thought that the clock stretching may be reduced if I write directly to the TWI? Because then I would skip the copying of my buffer to Wire's buffer and then to the TWI and instead maybe only copy once from my buffer to TWI.

Yea I know that it's weird how it acts like it's recognizing the data but it still doesn't work.

I know for a fact that this is possible since there is another person who has done a very similar project but with a pic here.

FPGA's are also cool and I've wanted to use them in a project for a while, so maybe that would work? Since it would skip the software part.

Copying data does not take a lot of time. It is something that the compiler can optimize very well.
You might be able to reduce the clock pulse stretching, but not by a lot. It is still interrupt driven and there is still code that needs to run.

What would be a normal timeout for the clock pulse stretching ? Perhaps something between 1 ms or 25 ms ? The SMBus has a timeout of 25 ms.
The gaps I see in your screen dumps seems to be much shorter.

If you want a faster response, then you can try a Arduino board with a SAMD21 processor. For example the Arduino Zero or a MKR board.

The PIC is very interesting.
Here are the I2C functions: ClassicPlus/MSSP.c at master · JSnowden33/ClassicPlus · GitHub.
It works in the same way. It is also interrupt driven and it must use clock pulse stretching as well.

If you start with a FPGA, you should start with something simple. This is far from simple. Perhaps you can find a full example for a I2C Slave.

Just have to say thanks for all the replies :slight_smile:

It could be a fun experiment to copy the data directly at least. You don't happen to know any good resources for learning how to communicate with TWI directly?

What do you mean by timeout? How long the slave can hold the clock low? In that case it's infinite. If it never stops that's what's called freezing of the bus (there is probably a fancier word out there). I've read that many devices using I2C also support SMBUS and have adopted that timeout you were talking about. And in my case I think that's true since in my early experiments I managed to get a response like that. Unfortunately the Logic Analyzer I had to give back since it was borrowed and I can't test this again for some time.

So why do you think the PIC works and not my AVR? I know the code is different but that can easily be fixed. And I don't think that's the problem since the captures from the real deal and from my emulator are identical except for the stretching.

The FPGA is already ordered so we shall see in a month or so when it arrives. I was thinking like you said of using a prebuilt i2c core.

pepperonipingu:
You don't happen to know any good resources for learning how to communicate with TWI directly?

The datasheet 8)
There are libraries that use the hardware registers. I did not remember one, because I didn't like them. I don't know if one of them has implemented the Slave mode, I don't think so.

pepperonipingu:
So why do you think the PIC works and not my AVR?

That is the 100000 dollar question.
I think it is likely that the PIC is faster for the I2C. That is the only difference we know at the moment. It would be weird if that makes the difference, but it is not impossible.

pepperonipingu:
the captures from the real deal and from my emulator are identical except for the stretching.

The real world does not work like that. There could be a difference in voltage levels. Maybe you use a different ground when connecting something else. Maybe a signal is too strong and causes current peaks.
The Arduino Uno and Arduino Mega 2560 have a filter for reading SDA and SCL and they have a slew-rate limiter for the output of SDA and SCL. The newer Arduino boards have processors that don't have that.