after many hours of googling, i decided to share my problem and ask the valuable Community how to fix my problem.
I need to interface my DUE to an application-specific chip that is using the I2C port.
I showed the waveforms of the bus to the designer of this chip (i work at STMicro) and he told me that it’s not good to have the SDATA to change (HI->LO) in the proximity of the change (HI->LO) of the clock because, being the IC multiple-start ready, it could read the condition as another start. And i can tell by the missing ACK that something is not going correctly.
My desire is to change the HOLD time of the SDATA so it will change “far away” (~1/4 of the clock period) from the change of the SCLK so the bus won’t read it as a restart.
Does anybody know if this is feasible? i’ll dive now in the specification of the A3 to see if there is a register that allow me to do that but the number of pages scares me!
A picture of the I2C signals would help ;) If possible also a analog capture to see if the signal is bouncing all over the place. If the chip is fast, it could see that condition as a start. Normally it is not a problem when mixing 100kHz and 400kHz devices. The official NXP I2C documents show in some figures that the SDA may be changed after the SCL is set low. However, the data hold time after SCL is set low (tHD;DAT) can be 0 us. It is only 5us with CBUS. So it can be anything from 0 us and above, but not below.
I have never heard of a register that could set an extra hold delay for SDA.
Do you have something special ? Perhaps different wire for SCL with more capacitance that slows it down ? Or different pullup resistors ? Mixing standard, Fast and Fast Mode Plus ? A weaker clock signal than the data signal ?
thank you for your attention!
i’ll add some waveforms as soon as possible. i’m using a DSO quad and it’s not the best for such fine analysis, i need a good scope. By the way, i found this at page 741 of the spec:
33.11.5 TWI Clock Waveform Generator Register
Address: 0x4008C010 (0), 0x40090010 (1)
TWI_CWGR is only used in Master mode.
• CLDIV: Clock Low Divider
The SCL low period is defined as follows:
• CHDIV: Clock High Divider
The SCL high period is defined as follows:
• CKDIV: Clock Divider
The CKDIV is used to increase both SCL high and low periods.
AFAIK, there must be a master clock from which all the timings are derived (prescaled) and i was wondering if these CLDIV and CHDIV can be what i (maybe ‘we’…) need.
Being a beginner with Arduino, may i ask you how can I read and write directly the registers of the Atmel?
I don't know the Due, only the basic ATmega328P microcontroller.
This is the manufacturers page: http://www.atmel.com/devices/sam3x8e.aspx
This is the Wire.cpp for the Due: https://github.com/arduino/Arduino/blob/master/hardware/arduino/sam/libraries/Wire/Wire.cpp This is the lower level twi.ccp for the Due: https://github.com/arduino/Arduino/blob/master/hardware/arduino/sam/system/libsam/source/twi.c
Fuffa: My desire is to change the HOLD time of the SDATA so it will change "far away" (~1/4 of the clock period) from the change of the SCLK so the bus won't read it as a restart. Does anybody know if this is feasible?
This is a great question and I wonder if the original poster had any success. The fall of SDA is too close to the fall of SCL.
Looks like the code governing the default behavior is within twi.c in a function called TWI_SetClock. The function takes two parameters, the desired TWI clock rate (ie. 100000) and the master clock (depends on the processor, I happen to have 64000000) and produces the values to load into the TWI_CWGR register. It bases the calculation of CLDIV on a 50% duty cycle, then loads the same CLDIV value into both CLDIV and CHDIV in TWI_CWGR. In my case, CKDIV=1, CLDIV=CHDIV=158. This gives a 50% duty cycle clock at 100kHz for a CPU running at 64MHz.
I found using the calculations in the data sheet that increasing CLDIV to 188 and reducing CHDIV to 128 gives a 40% duty cycle and a t_HIGH of 4us, which is the I2C minimum. Note that CLDIV is increased to lengthen the off time, and CHDIV must be decreased by the same amount so that the overall clock speed of 100kHz is maintained.
Okay I tried this and while the duty cycle is changed exactly as it should be, SDA continues to fall roughly 100ns after SCL.
The I2C spec says that this delay can be zero, but that all devices must internally hold SDA for 300ns after SCL falls. So in an ideal world, letting SCL and SDA fall at the same time would not be a problem. In the real world in which there is undershoot ringing on falling edges, falling at the same time leads to larger undershoot swings and signal crosstalk, so SCL is more likely to trigger a double clock.
The SAM3 is not a great CPU for field wiring sensors over I2C, and I suspect this is why so many people have had trouble with I2C on the Due, since this is a common use case for Arduino.
NXP's PCA9618 datasheet http://www.nxp.com/documents/data_sheet/PCA9618.pdf suggests adding an isolator on SDA to induce a wider margin between the fall of SCL and SDA. Haven't tried this, and this particular part is only available in quantities of 10k, but a similar single channel isolator might be worth a try.
The PCA9618 includes an internal glitch filter, so that it will ignore glitches rather than expand them, this also means that the minimum propagation delay is on the order of 46 ns and is reasonably stable over temperature and supply voltage. Although this is not sufficient to provide the SDA delay requirement of the SMBus hold time specification of 300 ns, many parts that cannot be used with the 0 ns hold time of the I2C-bus specification only require a few ns of hold time to work correctly in a system. For these applications, the PCA9618 is an effective solution.