cancel
Showing results for 
Search instead for 
Did you mean: 

I2C problem

janosch
Associate II
Posted on July 07, 2008 at 09:57

I2C problem

6 REPLIES 6
janosch
Associate II
Posted on May 17, 2011 at 12:38

Hey,

I got a strange problem with my I2C. Everything works fine (at low speeds 20kHz), as long as I do not plug in USB. As soon as I plug in the USB-Cable I2C communication breaks.

I debugged the whole thing and found out, that the last interrupt-state I got was I2C_EVENT_MASTER_MODE_SELECT. My code handles this event correct and calls I2C_Send7bitAddress(). After playing around with the oscilloscope I found out, that the STM32 ignores the address write, and just issues a stop condition shortly after the start condition. An error event is not fired. As this error only occurres if USB is connected, I think it might be a race condition from the master mode select event not being handled fast enough.

Any Ideas how to solve this ?

I use Firmwarelib V2.0.0 with USB-lib V2.2.0 with an own build environment based on the Codesourcery toolchain together with an Olimex STM32-H103 board.

lanchon
Associate II
Posted on May 17, 2011 at 12:38

if you're using interrupts to handle I2C events, raise the preempt priority of the I2C interrupt above that of the USB ints.

if you're using polling (or you want to have a more solid int-based implementation) change your I2C code so that it never depends on realtime behavior. this can be done for some but not all I2C uses, due to shortcomings in the design of the I2C macrocell. (for instance, a thing that apparently can't be safely done is reading exactly two bytes from a peripheral.) if you want take a look at the code I posted in this forum and search for comments on the subject.

janosch
Associate II
Posted on May 17, 2011 at 12:38

Hi Lanchon,

thanks for your reply. Actually raising the preempt priority helped a bit. Everythink works now stable at 20 kHz. As soon as I switch to a little faster speed (30 kHz) I suffer from the same problem. As my target speed is 400 kHz this is a problem :( I allready read through everything on I2C in this forum and couldn't find any answer to my problem. Most code posted here is designed for polling from the main loop, but this is not suitable for my problem, as I must read out many sensors synchroniously over different bussed in a short period of time.

Actually I think the problem I am facing isn't a design flaw in the I2C hardware, but rather a documentation flaw. I think I might write the slave address at the wrong time, and this causes my problems. I allready figured out, that the firmwarelib is missing the event 0x00070080, which is needed for continuous sending. Anyway, it would be nice if the documentation would really describe the hardware and could be read without digging through the library (for instance EVs are not described in the RM) rather than providing a howto for programing it.

Anyway, I will now try do debug this issue by writing every event that occurs into a ringbuffer and dig through them after communication broke.

If anyone has an idea how to solve this and save me from the digging I would really appreciate this 😉

janosch
Associate II
Posted on May 17, 2011 at 12:38

Ok, I debugged the whole thing and found out, that I get flooded with interrupts where the state of SR1 and SR2 is 0x00070080. As I identified this event as TxE, I react with either start or stop condition in case that I all bytes are transmitted. The I2C-Hardware reacts correct and stops sending data, but it continues to generate interrupts.

As a workaround I disabled the I2C_IT_BUF interrupt and wrote some data to DR, so that the BTF flag is never set. This works, but is rather an evil hack than a solution. If someone knows how to disable this interrupt in a clean way, please let me know. If this is not possible at all, I would suggest that this issue is added to the errata and documented in the reference manual.

lanchon
Associate II
Posted on May 17, 2011 at 12:38

> I think the problem I am facing isn't a design flaw in the I2C hardware, but rather a documentation flaw

IMHO there are design flaws. the family man has errors too.

the family manual asks you to wait for specific single-bit events one after the other. the macrocell was clearly designed to be used that way. the firmware samples look for event combinations instead; that's unnecessarily complex and invites all kinds of failures. my advice is that you completely forget what you saw in the samples and code from scratch according to the family manual.

I did this for a very little polling-based driver that's posted here. you could use that code as a guide showing the sequence of events that must be handled and produced or you could start from scratch, but the sequence of events apply to both polling and int-based solutions.

but know that the family manual has errors. when coded to the fam man specs, the driver misbehaved under stress; I had to do changes to make it stable. (the posted code was stress-tested and never observed to fail.)

> I allready figured out, that the firmwarelib is missing the event 0x00070080, which is needed for continuous sending.

sometimes pauses are required in the stream to safely handle communications (unless you can guarantee realtime performance of your code), that's part of the design flaws. in these situations, not pausing introduces realtime requirements, and when these are not met (under stress) the code fails.

niklas
Associate II
Posted on May 17, 2011 at 12:38

Hi Janosch

I've been on vacation, otherwise I perhaps would have been able to save you some hours of work 🙂

I worked with my I2C driver in the beginning of this year. I dont use the firmware lib in my code but I used it for reference together with the supplied examples. I experienced the same problems as you did with contiuous interrups and missing event definitions.

I too stored the events in a buffer and I also contacted helpdesk to get some support. In short the conclusion in the end was:

* The I2C examples sucks.

* There are missing event definitions in the firmware lib.

* It is not possible to have ITBUFEN enabled when generating the STOP, if you do not use the PEC (using PEC was not an option to me).

I got the code working by disabling ITBUFEN when generating the STOP and then enableing it again, but I was not really confortable with that solution. I ended up with not using ITBUFEN at all, but only using ITEVTEN.

I think the I2C hardware is quite difficult to interface on this controller compared to others that I have worked with, but now it seems to be working quite ok.

/Niklas