AnsweredAssumed Answered

STM32L100RC I2C1 SDA pulled constantly low

Question asked by lepisto.juho on Mar 8, 2016
Latest reply on Jan 11, 2018 by Clive One
Hello,

I'm having problems with STM32L100RC I2C1 peripheral on PB6 and PB7. The lines are pulled to MCU Vcc with 1k resistors. The problem is that when I configure the PB6 and PB7 as I2C1 pins, the MCU pulls SDA line low, the I2C busy flag is set and the I2C1 peripheral is stuck.

The initialisation code is following:
    #define I2C_SDA_PIN                      GPIO_Pin_7
    #define I2C_SDA_GPIO_PORT                GPIOB
    #define I2C_SDA_GPIO_CLK                 RCC_AHBPeriph_GPIOB


    #define I2C_SCL_PIN                      GPIO_Pin_6
    #define I2C_SCL_GPIO_PORT                GPIOB
    #define I2C_SCL_GPIO_CLK                 RCC_AHBPeriph_GPIOB

void v_Initialise_I2c(void)
{
    uint16_t u16_delay;
    uint8_t u8_clock_cycles = 0;
    GPIO_InitTypeDef GPIO_InitStructure;
    I2C_InitTypeDef  I2C_InitStructure;
    NVIC_InitTypeDef t_i2c_vector;
 
    /* GPIOB Periph clock enable */
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE);
 
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_40MHz;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
 
    // Set SCL and SDA as inputs.
    GPIO_InitStructure.GPIO_Pin = I2C_SDA_PIN | I2C_SCL_PIN;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
    GPIO_Init(I2C_SDA_GPIO_PORT, &GPIO_InitStructure);
    GPIO_SetBits(I2C_SCL_GPIO_PORT, I2C_SCL_PIN | I2C_SDA_PIN);
 
    if ((GPIO_ReadInputDataBit(I2C_SDA_GPIO_PORT, I2C_SDA_PIN) == 0) || (GPIO_ReadInputDataBit(I2C_SCL_GPIO_PORT, I2C_SCL_PIN) == 0))
    {
        if (GPIO_ReadInputDataBit(I2C_SDA_GPIO_PORT, I2C_SDA_PIN) == 0)
        {
            DEBUG_PRINT(3, "SDA line down!");
        }
        if (GPIO_ReadInputDataBit(I2C_SCL_GPIO_PORT, I2C_SCL_PIN) == 0)
        {
            DEBUG_PRINT(3, "SCL line down!");
        }
        DEBUG_PRINT(3, "Generate clock to release line.");
 
        // Set SCL as output
        GPIO_InitStructure.GPIO_Pin = I2C_SCL_PIN;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
        GPIO_Init(I2C_SCL_GPIO_PORT, &GPIO_InitStructure);
 
        while (GPIO_ReadInputDataBit(I2C_SDA_GPIO_PORT, I2C_SDA_PIN) == 0)
        {
            GPIO_ResetBits(I2C_SCL_GPIO_PORT, I2C_SCL_PIN);
            u16_delay = 15;
            while (u16_delay--)
            {
                __NOP();
            }
            GPIO_SetBits(I2C_SCL_GPIO_PORT, I2C_SCL_PIN);
            u16_delay = 15;
            while (u16_delay--)
            {
                __NOP();
            }
            WDRESET;
        }
        DEBUG_PRINT(3, "Done!");
    }
 
    GPIO_PinAFConfig(I2C_SDA_GPIO_PORT, GPIO_PinSource7, GPIO_AF_I2C1);
    GPIO_PinAFConfig(I2C_SCL_GPIO_PORT, GPIO_PinSource6, GPIO_AF_I2C1);
 
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
    GPIO_InitStructure.GPIO_Pin = I2C_SCL_PIN | I2C_SDA_PIN;
    GPIO_Init(I2C_SDA_GPIO_PORT, &GPIO_InitStructure);
 
    /* I2C1 and I2C2 Periph clock enable */
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
 
    I2C_Cmd(I2C1, DISABLE);
    I2C_DeInit(I2C1);
    I2C_Cmd(I2C1, ENABLE);
 
    I2C_StructInit(&I2C_InitStructure);
 
    I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
    I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
    I2C_InitStructure.I2C_OwnAddress1 = 0x00;
    I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
    I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
    I2C_InitStructure.I2C_ClockSpeed = 100000;
 
    I2C_Init(I2C1, &I2C_InitStructure);
 
    /* Enable and set EV and ER interrupts as high priority interrupts. */
    t_i2c_vector.NVIC_IRQChannel = I2C1_EV_IRQn;
    t_i2c_vector.NVIC_IRQChannelPreemptionPriority = 0;
    t_i2c_vector.NVIC_IRQChannelSubPriority = 2;
    t_i2c_vector.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&t_i2c_vector);
 
    t_i2c_vector.NVIC_IRQChannel = I2C1_ER_IRQn;
    t_i2c_vector.NVIC_IRQChannelPreemptionPriority = 0;
    t_i2c_vector.NVIC_IRQChannelSubPriority = 3;
    NVIC_Init(&t_i2c_vector);
 
    I2C_ClearITPendingBit(I2C1, ALL_I2C_INTERRUPTS);
    I2C_ITConfig(I2C1, I2C_IT_BUF | I2C_IT_EVT | I2C_IT_ERR, ENABLE);
 
    I2C_SoftwareResetCmd(I2C1, ENABLE);
    Delay(10);
    I2C_SoftwareResetCmd(I2C1, DISABLE);
 
    return;
}

The lines are pulled low when GPIO_PinAFConfig() is called. I've even added the clock pulse generation in case the slave pulls the SDA low. I've checked with an oscilloscope that the line is pulled low by the MCU. Why is this? Is there something wrong with my initialisations?

Thanks in advance!

-Juho L

Outcomes