i2c devices

Questions on control of serial busses
YahooArchive
Posts: 1462
Joined: Fri Oct 19, 2012 5:11 am

Re: i2c devices

Post by YahooArchive »

I am still having problem with the same HMC6352 device - use C

Using a scope I see the address on SDA correct, but the clock on SCL is
going at too high a rate.

I look at the source code of i2c_shift and don't see how this is happening.
With no device on the I2C bus - just the pull up the SDA line looks good but
the SCL is being pull low at the high rate - must be outside the i2c_shift
loop - in an interrupt service somehow???

Change pins around with the same result

Have tried Armmite IO pins 5 SDA and 6 SCL - 6 SDA and 5 SCL and the fast
clock is the same.

Thoughts anyone?



YahooArchive
Posts: 1462
Joined: Fri Oct 19, 2012 5:11 am

Re: i2c devices

Post by YahooArchive »

> > With no device on the I2C bus - just the pull up the SDA line looks good but
> > the SCL is being pull low at the high rate - must be outside the i2c_shift
> > loop - in an interrupt service somehow???
>

The bit banged code in both BASIC and C is just that, bit banged in software.
For i2c the lines are pulled low, but rely on the EXTERNAL pullup resistor to
pull them up.

The routines look for an ACK bit from the slave about 2 microseconds after the
clock. If the SDA line is floating, its quite possible it would interpret that
as an ACK.

Generally 1-10K values are recommended for i2c, depending on how long the wires
are.

YahooArchive
Posts: 1462
Joined: Fri Oct 19, 2012 5:11 am

Re: i2c devices

Post by YahooArchive »

Report about the following

1) change back to 3.3V but no obvious change
2) Read one byte the readin is still 00

will try the most simple operation for I2C on 24LC04. will post again

Brian

YahooArchive
Posts: 1462
Joined: Fri Oct 19, 2012 5:11 am

Re: i2c devices

Post by YahooArchive »

So I had moved pins around enough time I had SDA and SCL mixed up. So it was
SDA with a 2 usec clock looking output. Pull ups are 4.7k so the clock
looks very good and the data line looks like it outputs the data and a 2
usec clock together. Hard to get a good trigger to see exactly what is going
on. The rise times look good but I have some 2.2k handy and could switch out
the 4.7k pull ups.

Bill

YahooArchive
Posts: 1462
Joined: Fri Oct 19, 2012 5:11 am

Re: i2c devices

Post by YahooArchive »

I think I see too issues which are shown in the attached scope images

1. The ACK comes after the read - slow device ? or it needs one more
clock to ACK and the read already happened

2. After some time a 2 microsecond clock occurs on the floated SDA
line even with no device on the I2C bus

Bill

YahooArchive
Posts: 1462
Joined: Fri Oct 19, 2012 5:11 am

Re: i2c devices

Post by YahooArchive »

Guess what I thought was the ACK is a drive SDA low in "stop"

Bill

YahooArchive
Posts: 1462
Joined: Fri Oct 19, 2012 5:11 am

Re: i2c devices

Post by YahooArchive »

Pulled the I2C code from the lib to a main for debug - removed from
I2Cstart the check to grab the bus and now get a good ACK on the address.
Continuing to debug.



void i2c_start (int sda_pin, int scl_pin) {

FLT_SCL_HIGH; FLT_SDA_HIGH; // don't drive SDA or SCL,

SET_SCL_LOW; SET_SDA_LOW; // drive both low when enabled

DRV_SDA_LOW;

i2c_stall();

DRV_SCL_LOW;

}

YahooArchive
Posts: 1462
Joined: Fri Oct 19, 2012 5:11 am

Re: i2c devices

Post by YahooArchive »

Got a ACK back on the address, but had to work some other projects. Will get
back to it next week.

YahooArchive
Posts: 1462
Joined: Fri Oct 19, 2012 5:11 am

Re: i2c devices

Post by YahooArchive »

Got it working with the code below - Note the change of read 8 bits to 10
bits - must be a stop/start bit issue. No sure if the clock stretching is
needed. Should be able to work back to a minimum changed code, but moving on
to other code development since this works and this device is only in our
prototype board. We are using a different SPI device going forward.



Bill



#define SET_SCL_HIGH GPIO_IOSET = scl_pin
#define SET_SDA_HIGH GPIO_IOSET = sda_pin

#define SET_SCL_LOW GPIO_IOCLR = scl_pin
#define SET_SDA_LOW GPIO_IOCLR = sda_pin

#define DRV_SCL_LOW GPIO_IODIR |= scl_pin
#define FLT_SCL_HIGH GPIO_IODIR &= ~scl_pin
#define DRV_SDA_LOW GPIO_IODIR |= sda_pin
#define FLT_SDA_HIGH GPIO_IODIR &= ~sda_pin


char I2Cdelay = 0; // when 0 -- 340Kb

void i2c_stall() {
volatile register int reg1;

if (I2Cdelay) {
reg1 = I2Cdelay;
while (reg1--);
}
}

void i2c_start (int sda_pin, int scl_pin) {

FLT_SCL_HIGH;
FLT_SDA_HIGH;
SET_SCL_LOW;
SET_SDA_LOW;
DRV_SDA_LOW;

i2c_stall();

DRV_SCL_LOW;

// int start;
//
// FLT_SCL_HIGH; FLT_SDA_HIGH; // don't drive SDA or SCL,
// SET_SCL_LOW; SET_SDA_LOW; // drive both low whenenabled
//
// start = T0_TC;
//
// while (T0_TC-start < 100000) {
//
// while ((GPIO_IOPIN & (scl_pin | sda_pin)) != (scl_pin |sda_pin)) { // wait for bus to be idle
// while ((GPIO_IOPIN & (scl_pin | sda_pin)) != (scl_pin |sda_pin)) if(T0_TC-start > 100000) break;
// }
// DRV_SDA_LOW; // drive SDA low
// if ((GPIO_IOPIN & (scl_pin | sda_pin)) != scl_pin) { // checkwe got control
// FLT_SCL_HIGH; FLT_SDA_HIGH;
// release both
// } else {
//// i2c_stall();
//// GPIO_IODIR |= 4; // may be redundant when usingpullups
// DRV_SCL_LOW; // drive SCL low
// break; // FIXME assume we got
control
// }
// }
}

void i2c_stop (int sda_pin, int scl_pin) {
DRV_SDA_LOW; // drive SDA low
FLT_SCL_HIGH; // release SCL high

i2c_stall();

FLT_SDA_HIGH; // release SDA high
}

// shift out 8 bits, return ACK, leave SCL low, SDA float -- probably drivenby slave for a bit

char i2c_shift (int sda_pin, int scl_pin, char value) { // returnsTRUE when ACK'd

int i;

i = 7;
//i2c_stall();
while (i >= 0) {
DRV_SCL_LOW; // drive SCL low
//while(GPIO_IOPIN & scl_pin){}
i2c_stall();

//i2c_stall();

if (value & (1 << i)) FLT_SDA_HIGH; // release SDAhigh

else DRV_SDA_LOW; // driveSDA low

//i2c_stall();

FLT_SCL_HIGH; // release SCL high
while(!(GPIO_IOPIN * scl_pin)){}

i2c_stall();
i--;
}

DRV_SCL_LOW; // drive SCL low
FLT_SDA_HIGH; // let SDA float

i2c_stall();
i2c_stall();

FLT_SCL_HIGH; // release SCL high
while(!(GPIO_IOPIN * scl_pin)){}

i = GPIO_IOPIN & sda_pin; // check ACK here (save value in i, 0was ACK'd

i2c_stall();

DRV_SCL_LOW; // drive SCL low

return i == 0; // was it ACK'd
}


#ifdef USE2LISTS

void I2CIN (int sda_pin, int scl_pin, int addr, int outCnt, char *outList,
int cnt,char *list) { // U16 to allow -1 for unused

#else

void I2CIN (int sda_pin, int scl_pin, int addr, int opt1, int opt2, int
opt3, int opt4, int opt5, int cnt,char *list) { // U16 to allow -1 for
unused

#endif

unsigned char itsOK; // also set to 0 when last data sent
unsigned char data;
unsigned char i;

initList(cnt,list);

sda_pin = gpioPinMap[sda_pin];
scl_pin = gpioPinMap[scl_pin];

i2c_start(sda_pin, scl_pin);
itsOK = 1;

if ((opt1 != -1)) {
itsOK = i2c_shift(sda_pin, scl_pin, addr & 0xfe);
if (itsOK) itsOK = i2c_shift(sda_pin, scl_pin, opt1);
if ((opt2 != -1) && itsOK) itsOK = i2c_shift(sda_pin, scl_pin,
opt2);
if ((opt3 != -1) && itsOK) itsOK = i2c_shift(sda_pin, scl_pin,
opt3);
if ((opt4 != -1) && itsOK) itsOK = i2c_shift(sda_pin, scl_pin,
opt4);
if ((opt5 != -1) && itsOK) itsOK = i2c_shift(sda_pin, scl_pin,
opt5);
}

if (itsOK) {
if (opt1 != -1) {
FLT_SDA_HIGH; // release SDA high

i2c_stall();

FLT_SCL_HIGH; // release SCL high
DRV_SDA_LOW; // drive SDA low -- repeated START

i2c_stall();
}

if (i2c_shift(sda_pin, scl_pin, addr | 1)) { // readthis time

do {
data = 0;
i = 10; //changed from 8 to 10 - stop - start bitissue?
while (i > 0) {
DRV_SCL_LOW; // drive SCL low

i2c_stall();

i--;
FLT_SCL_HIGH; // release SCL high
while(!(GPIO_IOPIN * scl_pin)){}

i2c_stall();

data |= (GPIO_IOPIN & sda_pin)? (1 << i) :0;
}
DRV_SCL_LOW; // drive SCL low
if ((itsOK = saveList(data))) DRV_SDA_LOW; //
ACK for repeated read

i2c_stall();
// i2c_stall();
i2c_stall();

FLT_SCL_HIGH; // release SCL high
while(!(GPIO_IOPIN * scl_pin)){}

i2c_stall();

// master (me would ACK here for a sequenctial read

DRV_SCL_LOW; // drive SCL low

FLT_SDA_HIGH; // release SDA high
// i2c_stall();

} while (itsOK);
}
}
i2c_stop(sda_pin, scl_pin);
}

int I2COUT (int sda_pin, int scl_pin, int addr, int cnt, char *list) {
unsigned char itsOK;

initList(cnt,list);
sda_pin = gpioPinMap[sda_pin];
scl_pin = gpioPinMap[scl_pin];

i2c_start(sda_pin, scl_pin);
itsOK = i2c_shift(sda_pin, scl_pin, addr & 0xfe);

if (itsOK) {
while (readList() > 0) {
if (!i2c_shift(sda_pin, scl_pin, list_value)) { itsOK = 0;
break; }
}
}

i2c_stop(sda_pin, scl_pin);
return itsOK;
}

YahooArchive
Posts: 1462
Joined: Fri Oct 19, 2012 5:11 am

Re: i2c devices

Post by YahooArchive »

> Bruce - LOW is still used in the i2c_start SUB in the 'Untested Clock
Stretched' I2C.bas file uploaded to this site. If this file is run with release
7.43f or later an invalid START is generated. Don't know if this has any part in
Brians problem.

Thanks Chris-

I updated the file with the current i2c.bas that does not use HIGH/LOW

We don't have a slave device that does clock stretching, so we can't test that.
But it will be tested on a normal i2c device later this week.

To use clock stretching --

#define I2C_SLAVE_CLOCK_STRETCHING
#include

Post Reply