Skip to main content
wolfram2
Associate
June 15, 2012
Question

I²C read operation freezing

Posted on June 15, 2012 at 18:08

Hello guys,

I've got the following problem: I'm trying to read a register of a gyroscope with I²C. Everything works fine as long as I'm using several delays during the I²C communication. This wasn't a problem until yet, where I noticed that exact those delays lock the CPU completely down. So now I need to figure out why this code keeps freezing without delays:

uint8_t I2C_Read_Byte(uint8_t __slave_addr, uint8_t __reg_addr)

{

    uint8_t __retval;

    while (I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY));

    I2C_GenerateSTART(I2C1, ENABLE);

    while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));

    I2C_Send7bitAddress(I2C1, __slave_addr, I2C_Direction_Transmitter);

    while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));

    I2C_SendData(I2C1, __reg_addr);

    while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED)) ;

    I2C_GenerateSTART(I2C1, ENABLE);

    while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));

    I2C_Send7bitAddress(I2C1, __slave_addr, I2C_Direction_Receiver);

    while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));

    Delay_us(57); /* freezing without delay */

    while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED)) ;

    I2C_AcknowledgeConfig(I2C1, DISABLE);

    __retval = I2C_ReceiveData(I2C1);

    Delay_us(101); /* same here */

    I2C_GenerateSTOP(I2C1, ENABLE);

    Delay_us(111); /* and here */

    I2C_AcknowledgeConfig(I2C1, ENABLE);

    return __retval;

}

I'd be very greatful for any help!

Best regards and thanks in advance,

Wolfram
    This topic has been closed for replies.

    12 replies

    emalund
    Associate III
    June 19, 2012
    Posted on June 19, 2012 at 17:45

    The I2C bus is a beast

    incorrect

    The ST32 implementation of the I2C bus is a beast

    correct

    Erik
    wolfram2
    wolfram2Author
    Associate
    July 8, 2012
    Posted on July 08, 2012 at 10:15

    Awesome!

    I managed to solve it now! The problem indeed was the AcknowledgeConfig. Seems like one of the devices doesn't acknowledge the writte read address operation. Correct code now is:

    uint8_t I2C_Read_Byte(uint8_t __slave_addr, uint8_t __reg_addr)

    {

        uint8_t __retval;

        while (I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY));

        I2C_GenerateSTART(I2C1, ENABLE);

        while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));

        I2C_Send7bitAddress(I2C1, __slave_addr, I2C_Direction_Transmitter);

        while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));

        I2C_SendData(I2C1, __reg_addr);

        while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED)) ;

        I2C_GenerateSTART(I2C1, ENABLE);

        while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));

        I2C_Send7bitAddress(I2C1, __slave_addr, I2C_Direction_Receiver);

        while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));

        I2C_AcknowledgeConfig(I2C1, DISABLE);

        while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED)) ;

        __retval = I2C_ReceiveData(I2C1);

        I2C_GenerateSTOP(I2C1, ENABLE);

        I2C_AcknowledgeConfig(I2C1, ENABLE);

        return __retval;

    }

    I managed to push the time footprint of the function down to 2480 - 2500 µs :) Yay!

    But then I realised another problem: the timers weren't working at all. No matter what I set the timer to (TIM1, Period 360000, Clock_Div_1, Count_Up, UpdateInterrupt) I would just constantly run at 1MHz. I then thought ''oh, I have to clar the interrupt pending bit''. But then the timer just fired one single time ang got stuck then. Also manually resetting the counter to 0 didn't work. So I ended up with using the SysTick, set to 200Hz (360000 Ticks @ 72MHz).

    Thanks for all your help!

    Best regards,

    Wolfram