AnsweredAssumed Answered

I2C code error and port damaged

Question asked by shr.jsenr on Jun 9, 2017

I am using STM32Fxx library. I am not using STMCubemx. Issue I am facing is that the first time I run I2C communication after turning on MCU, the busy flag timeout occurs.

while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY))  { if (++timeout > 2000)  return; }  

I2C_GenerateSTART(I2C1, ENABLE);

what could be the reason for I2C_FLAG_BUSY flag to be set although the line is free ?

I have also initialized GPIO pins while initializing

On running I2C communication after that, on transmitting 7 bit address using

"I2C_Send7bitAddress(I2C2, 0x34<<1, I2C_Direction_Transmitter);"

the device timeouts every time. Do I need to add any other function before the above function ?

Timeout function is below

"while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED))"

On doing this operation repeatedly, both of my I2C1 and I2C2 ports are damaged. The MCU is unable to pull them low after issuing I2C start command. (3.3V on SCL, SDA pins after I2C Start.)

Is the 7-bit address timeout occurring because of Nack or some other reasons ?

Do I need to initialize GPIO pins for I2C initialization ?

SCL and SDA pins are pulled up using 3.3k ohm resistors. I doubt if I2C initialization part is correct. I have tried most options to initialize I2C Initialization structure. I tried using GPIO_OType as GPIO_OType_PP and GPIO_OType_OD but there is no difference. Because of this, my I2C1 and I2C2 ports are also damaged. I have been unable to locate the problem. When I2C1 and I2C2 pins were OK, timeout occurred every time after sending 7-bit address.

Using bit banging for I2C with same 7-bit address, it works fine.[before sda and scl pins are responsive]

My code is below:

/********************************* I2C code ********************************/

void I2C_initialize(void)
{
        GPIO_InitTypeDef GPIO_InitStruct;
        I2C_InitTypeDef I2C_InitStruct;

        RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2, ENABLE); // enable APB1 peripheral clock for I2C2
        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE); // enable clock for SCL and SDA pins

        GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF; // set pins to alternate function
        GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; // set GPIO speed
        GPIO_InitStruct.GPIO_OType = GPIO_OType_OD;
        GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL; // enable pull up resistors
        GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10;
        GPIO_Init(GPIOB, &GPIO_InitStruct); // init GPIOB
        GPIO_InitStruct.GPIO_Pin = GPIO_Pin_11;
        GPIO_Init(GPIOB, &GPIO_InitStruct); // init GPIOB

        // Connect I2C2 pins to AF
        GPIO_PinAFConfig(GPIOB, GPIO_PinSource10, GPIO_AF_I2C2); // SCL
        GPIO_PinAFConfig(GPIOB, GPIO_PinSource11, GPIO_AF_I2C2); // SDA

        I2C_DeInit(I2C2);
        //I2C_Cmd(I2C2, ENABLE);

        // configure I2C2
        I2C_InitStruct.I2C_ClockSpeed = 50000; // 100kHz
        I2C_InitStruct.I2C_Mode = I2C_Mode_I2C; // I2C mode
        I2C_InitStruct.I2C_DutyCycle = I2C_DutyCycle_2; // 50% duty cycle --> standard
        I2C_InitStruct.I2C_OwnAddress1 = 0x00; // own address, not relevant in master mode
        I2C_InitStruct.I2C_Ack = I2C_Ack_Disable; // disable acknowledge when reading (can be changed later on)
        I2C_InitStruct.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit; // set address length to 7 bit addresses
        I2C_Init(I2C2, &I2C_InitStruct); // init I2C2

        I2C_Cmd(I2C2, ENABLE);// enable I2C2
}

void I2C_write(uint8_t data)
{
        I2C_SendData(I2C2, data);
        // wait for I2C2 EV8_2 --> byte has been transmitted
        while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
}

uint8_t I2C_read_nack(I2C_TypeDef* I2Cx)
{
        uint8_t data;
        // Disable acknowledge of received data
        I2C_AcknowledgeConfig(I2Cx, DISABLE);
        I2C_GenerateSTOP(I2Cx, ENABLE);

        // wait until one byte has been received
        while( !I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_RECEIVED) );
        // read data from I2C data register and return data byte
        data = I2C_ReceiveData(I2Cx);
        return data;
}

void get_data(void)
{
        uint8_t state = 0, data;
        uint16_t timeout = 0;

        Uart1_Printf("Start\n");
        while(I2C_GetFlagStatus(I2C2, I2C_FLAG_BUSY)) { if (++timeout > 2000){   Uart1_Printf("Busy\n");  return; } }
        I2C_GenerateSTART(I2C2, ENABLE);
        Delay_us(10);

        Uart1_Printf("check start event\n");
        while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT))
        {       Delay_us(1);
                if (++timeout >= 2000)
                {
                        Uart1_Printf("Stop\n");
                        I2C_GenerateSTOP(I2C2, ENABLE);
                        return;
                }
        }
        Delay_us(10);

        Uart1_Printf("master transmit\n");
        I2C_Send7bitAddress(I2C2, 0x34<<1, I2C_Direction_Transmitter); // send device I2C address
        Delay_ms(10);

        while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED))
        {
                if (timeout++ >= 2000) /****** timeout occurring here every time hence unable to proceed *****/
                {
                        Uart1_Printf("master transmit event timeout\n");
                        I2C_GenerateSTOP(I2C2, ENABLE);
                        return;
                }
        }
        Delay_us(10);
        Uart1_Printf("TX 00\n");
        I2C_write(0x00);
        Uart1_Printf("TX 01\n");
        I2C_write(0x01);

        Uart1_Printf("Stop\n");
        I2C_GenerateSTOP(I2C2, ENABLE);

        Uart1_Printf("Restart\n");
        while(I2C_GetFlagStatus(I2C2, I2C_FLAG_BUSY)) { if (++timeout > 2000) {Uart1_Printf("Restart timeout\n"); break; }}
        I2C_GenerateSTART(I2C2, ENABLE);
        Delay_us(10);

        Uart1_Printf("check restart event\n");
        while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT))
        { Delay_us(1);
                if (++timeout >= 2000)
                {
                        Uart1_Printf("Stop\n");
                        I2C_GenerateSTOP(I2C2, ENABLE); //I2C_engine_stop();
                        return;
                }
        }
        Delay_us(10);

        Uart1_Printf("master receive\n");
        I2C_Send7bitAddress(I2C2, 0x34<<1, I2C_Direction_Receiver); // send device I2C address
        Delay_us(10);

        while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED))
        {
                if (timeout++ >= 2000)
                {
                        Uart1_Printf("master receive event timeout\n");
                        I2C_GenerateSTOP(I2C2, ENABLE); //I2C_engine_stop();
                        return;
                }
        }

        data = I2C_read_nack(I2C2);
        Uart1_Printf("data: %d\n", data);
}

/********************************* Main code ******************************* /

int main(void)
{
        // other initializations
        I2C_initialize();
        while (1)
        {
                if (switch)
                {
                        get_data();
                }
        }
}

/********************************* Output ********************************* /

Start

Busy

 

Start
check start event
master transmit
master transmit timeoutevent
Stop

Outcomes