Skip to main content
jordi
Associate II
September 4, 2009
Question

Error interrupt I2C Example1

  • September 4, 2009
  • 11 replies
  • 3397 views
Posted on September 04, 2009 at 17:24

Error interrupt I2C Example1

    This topic has been closed for replies.

    11 replies

    jordi
    jordiAuthor
    Associate II
    May 17, 2011
    Posted on May 17, 2011 at 12:31

    Hi,

    I want to add error handling in the I2C example 1. So I've add the error interrupt:

    I2C_ITConfig(I2C1, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR, ENABLE );

    If I don't connect the master & slave, I expect an Acknowledge failure Interrupt after sending the slave address, but this doesn't happen.

    By contrast, if I monitor the I2C_FLAG_AF with the I2C_GetFlagStatus(I2C1,I2C_FLAG_AF) function in the main loop, I can see that the AF Flag is really set after a short time. Why isn't also fired the I2C1_ER_IRQHandler interrupt?

    Thanks

    [ This message was edited by: jordi.pallisanunez on 25-04-2008 16:15 ]

    guyvo67
    Associate III
    May 17, 2011
    Posted on May 17, 2011 at 12:31

    Guys,

    Yes I encountered also hang behaviour in the I2C IRQ handler. (receiver)

    My priority is put highest 0 and I send 84 bytes from one cortex to another. This works perfect but as soon there's some charge on my free RTOS tasks the interrupt on the receiver side starts to hang. Moreover this holds the cortex in the I2C int (highest priority) routine so the RTOS systick gets no feed and my system is dead.

    I put a break point on this line:

    evt = I2C_GetLastEvent(I2C2);

    switch (evt){

    .....

    And the event assigned was 0x20054. This value is even not defined in the ST header. So I added a case default line like:

    default:

    I2C_ClearITPendingBit(I2C2, I2C_IT_EVT);

    break;

    I tried to clear I2C_IT_EVT , which i'm not sure I can do, but still the same unknown event value. And I can confirm that I get no error in that case as well. So I still can't get a comfortable feeling when I use I2C on the cortex. I saw other threads as well pointing to hang on EVs. So is there something critical even a small detail that we don't know here?

    So my questions to you guys:

    Did you tested the I2C in loop/charge or with other interrupts going on at the same time ?

    Did you tested the I2C using a RTOS of some kind with tasks charge at same time ?

    Cheers

    -G

    stephan2399
    Associate
    May 17, 2011
    Posted on May 17, 2011 at 12:31

    Hello,

    I have the same problem. Have anybody solved it?

    Thanks

    daniels2
    Visitor II
    May 17, 2011
    Posted on May 17, 2011 at 12:31

    Hi

    I've tried the same thing when I get an Acknowledge failure the appropriate error handling interrupt is not fired yet if I force an AF high it is reset transparently in uvision. This seems to be an intermittent problem also i can get locked into an infinite loop where the interrupt functio is called but the AF trap is not executed.

    /*******************************************************************************

    * Function Name : I2C1_EV_IRQHandler

    * Description : This function handles I2C1 Event interrupt request.

    * Input : None

    * Output : None

    * Return : None

    *******************************************************************************/

    void I2C1_EV_IRQHandler(void)

    {

    uint8_t tbuff;

    switch (I2C_GetLastEvent(I2C1))

    {

    /* Test on I2C1 EV1 and clear it */

    case I2C_EVENT_SLAVE_RECEIVER_ADDRESS_MATCHED:

    ResetRxTx_Buffers();

    break;

    /* Test on I2C1 EV2 and clear it */

    case I2C_EVENT_SLAVE_BYTE_RECEIVED:

    tbuff = I2C_ReceiveData(I2C1);

    i2c_Rx_Decode(&tbuff);

    break;

    case I2C_EVENT_SLAVE_TRANSMITTER_ADDRESS_MATCHED:

    ResetTxBuffer();

    i2c_Tx_encode();

    break;

    /* Test on I2C1 EV4 and clear it */

    case I2C_EVENT_SLAVE_STOP_DETECTED:

    /* Clear STOPF flag */

    I2C_ClearFlag(I2C1, I2C_FLAG_STOPF);

    ResetRxTx_Buffers();

    /* Disable I2C2 interrupts */

    break;

    case I2C_EVENT_SLAVE_BYTE_TRANSMITTED:

    i2c_Tx_encode();

    break;

    case I2C_EVENT_SLAVE_ACK_FAILURE:

    I2C_ClearFlag(I2C1, I2C_IT_AF);

    ResetRxTx_Buffers();

    break;

    default:

    //clock held low by

    break;

    }

    }

    jvaque
    Associate
    May 17, 2011
    Posted on May 17, 2011 at 12:31

    Hi all!

    I can't offer you a solution, but I had lots of problems with I2C with STM32 in the past. After discussions with ST support, I realized that the events defined on the libraries (the ones used on the examples) do not cover all the possible cases, just the ''ideal cases''.

    The best way to work with I2C is to read the reference manual RM0008, and treat the events as described in figures 232 to 235. These figures on the same time define exactly the possible events (keep in mind that in the real world one can have combinations of different events, so take care when implementing, I wouldn't follow the way the examples implement it with switch and case ).

    Ah, and try to use DMA, because when a I2C DMA transfer is started, one doesn't have to bother with interrupts and events until a STOP is received or has to be sent!

    Regards,

    [ This message was edited by: jvaque on 03-09-2009 10:05 ]

    guyvo67
    Associate III
    May 17, 2011
    Posted on May 17, 2011 at 12:31

    Daniels,

    Quote:

    /* Test on I2C1 EV4 and clear it */

    case I2C_EVENT_SLAVE_STOP_DETECTED:

    /* Clear STOPF flag */

    I2C_ClearFlag(I2C1, I2C_FLAG_STOPF);

    ResetRxTx_Buffers();

    /* Disable I2C2 interrupts */

    break;

    Be aware that you have to do an extra read for the stop like:

    I2C_ClearFlag(I2C1, I2C_FLAG_STOPF);

    I2C_CMD(I2C1,ENABLE)

    Maybe you do this in your ResetRxTx_Buffers routine but I can't see that.

    To all guys suffering on I2C hangs,

    I did some further testing still no exact cause but if the I2C interrupt enters the blocked state the order of events on the slave receiver just before the hang I capture are:

    1. evt = 0x50

    2. evt = 0x200052

    3. evt = 0x200054 (always that value and hang)

    --> SCL is pulled low

    All these events are not described in the ST header. Of course I can break this endless looping with my watchdog. So i'm still suspecting a software cause corrupting the GetEvent routine. I continue in my tests. Maybe I check even further with logic analyzer.

    -G

    [ This message was edited by: guyvo67 on 03-09-2009 08:45 ]

    guyvo67
    Associate III
    May 17, 2011
    Posted on May 17, 2011 at 12:31

    dmatheis,

    why should I (re)enable the I2C interface?

    In rm0008 on page 647:

    –Cleared by software readingthe SR1 register followed by a write in the CR1 register

    So this sequence is needed to clear the STOPF flag.

    -G

    dmatheis
    Associate III
    May 17, 2011
    Posted on May 17, 2011 at 12:31

    Quote:

    Be aware that you have to do an extra read for the stop like:

    I2C_ClearFlag(I2C1, I2C_FLAG_STOPF);

    I2C_CMD(I2C1,ENABLE)

    Hi guyvo67,

    why should I (re)enable the I2C interface? I thought after reading the stop-flag there is no communication on the bus and I could disable it.

    [ This message was edited by: dmatheis on 04-09-2009 10:52 ]

    guyvo67
    Associate III
    May 17, 2011
    Posted on May 17, 2011 at 12:31

    GOOD NEWS:

    system running :

    core = 72M

    I2C = 400k ( don't forget the I2C_DutyCycle_16_9 )

    I2C1/2 at int0

    freeRTOS running with 8 tasks

    So as you probably could read in this thread it's all about the capturing of the right events at the right moment. Well in fact it is believe me.

    I introduced a new event:

    I2C_EVENT_SLAVE_BYTE_RECEIVED_AND_STOP ((u32)0x00000050)

    Which means that there's a byte received and also a stop condition. These two together are never captured when you follow the ST examples. You need to capture this state when the cortex is very busy. Apparently the I2C hardware is faster than the software can handle and misses the last byte recieved in the I2C_EVENT_SLAVE_BYTE_RECEIVED. So two events are signalled together at the hardware level and this is not proper handled by the ST examples.

    This was only the slave side and of course this can happen on the master side too. But my program is running now with the extra event simply as:

    case I2C_EVENT_SLAVE_BYTE_RECEIVED_AND_STOP:

    buffer[idx++] = I2C_ReceiveData(I2C2);

    (void)(I2C_GetITStatus(I2C2, I2C_IT_STOPF));

    I2C_Cmd(I2C2, ENABLE);

    break;

    I don't know which states on the master that suffers from this timing issue yet because I haven't seen it so far. But I keep you all posted of tests. ( over night run with full charge )

    Strange thing is that ST didn't provide this dual state in the event list. Maybe they think that the examples are only meant to run once ;)

    Sequel of testing:

    I had to add one more event case at the receiver:

    I2C_EVENT_SLAVE_BYTE_RECEIVED_WITH_BTF ((u32)0x00020044)

    This is to handle the clock stretching. In fact you can put the same code in this case as you do for I2C_EVENT_SLAVE_BYTE_RECEIVED which is reading the byte in your buffer so it's out of the shift register and ready to receive another byte.

    At the master I also had to add :

    I2C_EVENT_MASTER_BYTE_TRANSMITTED ( declared in ST header )

    This also covers the clock stretching but at the master. You just send you data byte in the case as you do with I2C_EVENT_MASTER_BYTE_TRANSMITTING.

    My tests ran for hours without any problems now.

     

    Resume and things to keep in mind:

     

     

    1. At slave foresee I2C_EVENT_SLAVE_BYTE_RECEIVED_AND_STOP to capture EV2/EV4 when they are signalled together

     

     

    2. At slave foresee I2C_EVENT_SLAVE_BYTE_RECEIVED_WITH_BTF to handle clock stretching if enabled.

     

     

    3. At master foresee I2C_EVENT_MASTER_BYTE_TRANSMITTED to handle slock stretching if enabled

     

     

    4. Analyse your own application on a state diagram level and try to port this out to the available events. Don't hesitate to make your own combinations

     

     

    5. Be aware that I2C hardware level is sometimes faster than your software layer can handle.

     

     

    6. ST didn't make events in the header to capture the clock stretching on the slave receiver.

     

     

    Important notes in rm0008:

     

     

    SLAVE:

     

     

    If RxNE is set and the data in the DR register is not read before the end of the next data

     

    reception, the BTF bit is set and the interface waits until BTF is cleared by a read from

     

    I2C_SR1 followed by a read from the I2C_DR register, stretching SCL low

     

     

    MASTER:

     

     

    If TxE is set and a data byte was not written in the DR register before the end of the last data

     

    transmission, BTF is set and the interface waits until BTF is cleared by a read from I2C_SR1

     

    followed by a write to I2C_DR, stretching SCL low.

     

     

    Concerning my case this topic is closed. Thanks for the reactions it gave me some food for thoughts and ideas.

    Cheers

    -G

    [ This message was edited by: guyvo67 on 06-09-2009 13:16 ]

    guyvo67
    Associate III
    May 17, 2011
    Posted on May 17, 2011 at 12:31

    Quote:

    I can't offer you a solution, but I had lots of problems with I2C with STM32 in the past. After discussions with ST support, I realized that the events defined on the libraries (the ones used on the examples) do not cover all the possible cases, just the ''ideal cases''.

    Yes the value of the events I get you can not even make them with combining or oring the bits together with those defined in ST header. That makes it very strange. Maybe the people of ST could modify the i2c firmware in order to give the developers a honest change to catch all events and interrupts.

    Quote:

    The best way to work with I2C is to read the reference manual RM0008, and treat the events as described in figures 232 to 235. These figures on the same time define exactly the possible events (keep in mind that in the real world one can have combinations of different events, so take care when implementing, I wouldn't follow the way the examples implement it with switch and case ).

    Well I think that STs firmware lib should cover all the possible event cases anyway. Sure if you write your own handler totally in assembler I'm pretty sure these bugs will not appear but it's only I2C even not SPI or ethernet so I think you can drive this totally in C. eg with 300k you only have ca 3µs on period given a cortex at 72M this is still 250 cycles. Besides the I2C is done in hardware without bit banging so I expect this to be fast and accurate.

    Quote:

    Ah, and try to use DMA, because when a I2C DMA transfer is started, one doesn't have to bother with interrupts and events until a STOP is received or has to be sent!

    Also here a bit overkill to use DMA on I2C. But I will give it try anyway. Indeed you reduce the number events which will have a good influence on timings. Again, this should not be last resort solution as it's only I2C and with clock stretching enabled you are pretty sure the protocol can be handled even with servicing other interrupts at the same time.

    -G