cancel
Showing results for 
Search instead for 
Did you mean: 

I2C problems

brj
Associate II
Posted on January 28, 2009 at 11:49

I2C problems

21 REPLIES 21
brj
Associate II
Posted on May 17, 2011 at 12:30

Btw.

I2C Example5 suffers from the same problem (when reading only 1 byte)

/BRJ

brj
Associate II
Posted on May 17, 2011 at 12:30

Hello all,

Finally had some time to test the solution presented by viktor2,

and you are right, no extra pulses in a read operation.

The difference between your code snippet and mine was when to set the stop bit in CR1.

Apparantly you have to set the stop bit before reception of the last byte from the eeprom. Then it will issue NACK and then a STOP condition.

e.g.

/* While there is data to be read */

while(NumByteToRead)

{

if (NumByteToRead == 1) { /* Send STOP Condition */

I2C_GenerateSTOP(I2C2, ENABLE);

}

error = WaitForI2C2EventTimed (I2C_EVENT_MASTER_BYTE_RECEIVED);

if (error) { ReInitI2cDriver(); return 1; }

/* Read a byte from the EEPROM */

*pBuffer = I2C_ReceiveData(I2C2);

if you (like I did) poll reception of a byte and then set the stop bit, you get 8 additional SCL clocks followed by NACK and STOP condition

/BRJ

trevor1
Associate II
Posted on May 17, 2011 at 12:30

Forgive me if this is a little off topic.

I too struggled with I2C for some time. Eventually I ported some bit banging code for I2C in software.

It's very little code (less than the ST lib I2C code), much easier to understand and if you are intending to just poll the I2C hardware anyway it's just as fast -- I had to slow mine down with delays. OK, it might not clock at 10Mhz but all the I2C chips I interface to are 100 - 400 kHz max anyway.

Happy to share this code if anyone wants it. Happy to be educated as to why this is not a good way forward.

Regards

Trevor

viktor3
Associate II
Posted on May 17, 2011 at 12:30

brj

You may use the code below to write ''len'' bytes(>0) to an eeprom. It uses page write :

#define PGSZE 16 // For 24C16

#define EEPROM_ADDRESS 0xA0 // EEprom address (in my case)

s16 wr_i2c_n(I2C_TypeDef *I2C, u16 eeprom_addr, u8 *s, u16 len)

{

u16 i;

u8 device_addr = (EEPROM_ADDRESS | eeprom_addr >> 7) & 0xfe;

for(i=1; i<=len; i++, eeprom_addr++)

{

if((i==1) || (eeprom_addr%PGSZE == 0))

{

I2C->CR1 |= (1<

while(!check_event(I2C, 0x00030001));

I2C->DR = device_addr;

while(!check_event(I2C, 0x00070082));

I2C->DR = eeprom_addr;

while(!check_event(I2C, 0x00070084));

}

I2C->DR =*s++;

while(!check_event(I2C, 0x00070084));

if(i==len || (eeprom_addr%PGSZE == PGSZE-1))

{

I2C->CR1 |= (1<

do

{

I2C->CR1 |= (1<

(void) I2C->SR1;

I2C->DR = EEPROM_ADDRESS;

} while(!(I2C->SR1 & 0x0002));

I2C->SR1 &= ~0x0400;

}

}

I2C->CR1 |= (1<

while(!check_event(I2C, 0x00000001));

return 0;

}

hugoliang
Associate
Posted on May 17, 2011 at 12:30

Hello All.

My problem is save with nikhil1.

I cannot be able to write on two consecutive steps using I2C_EE_BufferWrite function. It must be insert enough long time delay during them in order to make its working correctly.

Without delay, the program will stop at EV6 testing in the second write process.

Would you please give me some suggestion?

Thank you!

brj
Associate II
Posted on May 17, 2011 at 12:30

Hello,

Remember to respect the internal write cycle of an eeprom.

As I remember it is app. 5ms per byte on a 24C64.

lanconelli
Associate
Posted on May 17, 2011 at 12:30

Quote:

On 24-04-2008 at 21:51, Anonymous wrote:

while(len)

{

if(len == 1) I2C->CR1 |= (1<

while(!check_event(I2C, 0x00030040));

if(len == 2) I2C->CR1 &= ~(1<

*buffer++ = I2C->DR;

len--;

}

Hi,

I wrote similar code, but I found it is not working in all conditions.

If you get an interrupt in the while loop that requires a time to be

served greater than i2c byte time (9 x i2c bit period) you may set the

NACK bit (or i2c stop) in the wrong position, breaking the bus transfer.

As explained by lanchon, i2c polling receive is working for sure only

if you receive just one byte at a time.

Another solution is to disable interrupts, but it's not a viable solution

for me.

Correct me if I'm wrong, but I've spent a whole week on this problem without any other solutions.

I suggest ST to design a simpler and better I2C macrocell for the next STM32 family!! :-]

Cheers,

Claudio Lanconelli

lanchon
Associate III
Posted on May 17, 2011 at 12:30

> I wrote similar code, but...

note that I haven't looked at other people's code, so no comment. (but I've posted my own somewhere.)

> As explained by lanchon, i2c polling receive is working for sure only

if you receive just one byte at a time.

assuming that execution of your code is best effort instead of real-time (no guarantees of processor availability or progress), my observation is that you can safely receive 1 byte or 3 or more bytes, but not 2.

I've talked about this in other posts (you might want to search) but I don't remember detailing exactly how to safely receive 3 or more bytes without RT guarantees. it goes something like this:

the macrocell has a one byte receive buffer. after receiving a byte the buffer is populated and signal ''not empty'' (or something like that) is triggered. the macrocell goes on to receive the next byte and you have the current ''byte time'' to empty the buffer. if you do, after receiving the 2nd byte the buffer is again populated and reception continues undisturbed. if not, the I2C clock is stretched if possible (both as master or slave), halting reception at the byte's end till the buffer is emptied. this blocks the data sender and provides flow control. otherwise if it's not possible to stretch the clock (stm32 is slave and stretching is disabled) an RX overrun error is triggered.

now, to safely receive 3 or more bytes you need to use a clock stretching mode, and you need to force a stall of the I2C pipeline. (this is suboptimal in that it reduces bus bandwidth.)

to read n bytes where n >= 3:

repeat n-3 times:

{

wait till ''buffer not empty'' flag

read buffer

}

// now exactly 3 bytes are pending to be received: bytes n-2, n-1, and n.

wait till ''bus stalled'' flag

// (this flag might be RX overrun; I don't remember its name,

// but there is a flag that signals when the clock is being stretch.)

// now things are looking like this:

// -byte n-2 has been received and moved into the buffer.

// -byte n-1 has been received and, since the buffer is full, the clock is being stretched and the byte is pending to be transferred to the buffer.

// -note that byte n-1 HAS ALREADY BEEN ACKNOWLEDGED to the sender.

// -transmission of byte n hasn't yet started.

change the acknowledge flag so that next bytes are NACKed

read buffer // (byte n-2) this unstalls the pipeline.

wait till ''buffer not empty'' flag // the flag here should already be set, but let's be safe.

read buffer // (byte n-1)

wait till ''buffer not empty'' flag

read buffer // (byte n)

two notes:

-there's an interruption in flow between bytes n-1 and n; reduces performance but it's otherwise not a problem.

-there's more stuff to do to guarantee a correctly placed stop signal; I don't remember but I think it's similar to the case of just one byte (get my code and see). what I do remember is that there's definitely a way to do it safely.

as to why 2 bytes can't be received: there's no way to stall the pipe before the last byte, so you can't safely change from RX ACK to RX NACK mode without real-time guarantees

the macrocell design bug: it's designed to be operable in non-real-time scenarios (implements clock stretching), and to have good performance (uninterrupted reception by way of a one byte receive buffer). however, having a ''pipelined'' receive means that a pipelined RX ACK/NACK flag is needed (I mean a shadowed flag). but they didn't think of this and so:

-non-real-time reception can't be done without stalling (negating benefits of the buffer),

-under some conditions the pipe can't be stalled at all, and so the hardware is rendered useless.

jj
Associate II
Posted on May 17, 2011 at 12:30

STOne-32-

Thank you - much appreciated. May I offer some comments/suggestions?

a) Announcement of Pending Release of ''problem solving'' Ap Note. My firm - and I would expect others - may have made similar efforts to your welcome, new release. I had ''no idea'' that ST was working to improve and/or resolve issues with the I2C module - without such advice we may have duplicated your efforts and ''re-invented the wheel.'' Some advisory would be welcome.

b) Many of your forum posters have made ''highly specific'' identification of weaknesses discovered w/in the I2C module. The new note - while offering improvements - is silent with regard to, ''What's been improved, what's still ''in process.'' (note I did not say ''fixed.'') This detail would speed & ease our ability to perform a mass analysis of your update. Further - this would eliminate needless frustration caused by our exercising/testing functions which, ''have not yet improved'' - in this release.

c) I would benefit from/appreciate seeing a listing of ''all affected files'' which the new release has ''touched.'' This would heighten our odds of success and raise goodwill toward ST.

Know that I speak for many when I offer our thanks...

16-32micros
Associate III
Posted on May 17, 2011 at 12:30

Hi

ST has released recently a new Application Note :

AN2824 : STM32F10xxx advanced I²C examples :

http://www.st.com/stonline/products/literature/an/15021.pdf

http://www.st.com/stonline/products/literature/an/15021.pdf

This AN covers most of I2C cases and examples and enriches the FWLibrary offer to better use our STM32 I2C peripheral.

Cheers,

STOne-32.