Correct I2C sequence on STM32F1 for reading 2 bytes?
06:30 02 Jan 2026

I'm trying to interface between and stm32f103 and a light sensor using I2C using the Lower-Layer libraries. I have to read 2 bytes of data from the sensor and I'm using the sequence of register writes and reads described in ST's manual (AN2824 and the STM32 reference manual):

  • set POS and set ACK
  • send ADDR
  • wait for ADDR and clear ADDR
  • clear ACK
  • wait for BTF to be set
  • send STOP
  • read data twice
  • clear POS and set ACK (to be ready for another reception)

STM32 reference manual I2C sequence

This works, but only works to read data ONCE! When I try to call this ReadLightI2C a second time, it gets stuck on the BTF which never gets set, so the BlinkNrOfTimes(3) never gets reached. I tried a bunch of changes but didn't get it working. Any help would be greatly appreciated! Here's some of my code:

int main()  
{  
    ConfigureClock();  
  
    ConfigureLedGPIO();  
    ConfigureI2C();  
  
    ReadLightI2C(false);  
    BlinkNrOfTimes(1);  
    ReadLightI2C(true);

    return 0;  
}  
void ConfigureI2C()  
{  
    LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_I2C1);  
    LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_GPIOB);  
  
    LL_GPIO_InitTypeDef gpioDef = {0};  
    LL_GPIO_StructInit(&gpioDef);  
    gpioDef.Pin = LL_GPIO_PIN_6 | LL_GPIO_PIN_7;  
    gpioDef.Mode = LL_GPIO_MODE_ALTERNATE;  
    gpioDef.Speed = LL_GPIO_SPEED_FREQ_HIGH;  
    gpioDef.OutputType = LL_GPIO_OUTPUT_OPENDRAIN;  
  
    if (LL_GPIO_Init(GPIOB, &gpioDef) == ERROR)  
    {  
        BlinkError();  
    }  
  
    LL_I2C_InitTypeDef i2cDef;  
    LL_I2C_StructInit(&i2cDef);  
  
    i2cDef.ClockSpeed = 36000;  
    i2cDef.TypeAcknowledge = LL_I2C_ACK;  
    i2cDef.DutyCycle = LL_I2C_DUTYCYCLE_16_9;  
  
    if (LL_I2C_Init(I2C1, &i2cDef) == ERROR)  
    {  
        BlinkError();  
    }  
  
    LL_I2C_Disable(I2C1);  
  
    while (LL_I2C_IsEnabled(I2C1))  
    {  
    }  
}  
uint16_t ReadLightI2C(bool secondTime)  
{  
    LL_I2C_Enable(I2C1);  
  
    while (LL_I2C_IsEnabled(I2C1) == false)  
    {  
    }  
  
    LL_I2C_AcknowledgeNextData(I2C1, LL_I2C_ACK);  
  
    // SEND MEASUREMENT INSTRUCTION  
  
    LL_I2C_GenerateStartCondition(I2C1);  
  
    while (LL_I2C_IsActiveFlag_SB(I2C1) != SET)  
    {  
    }  
    // EV5  
    // SB = 1  
    // Cleared by reading SR1 (reading SB flag) and writing DR (TransmitData)  
  
    uint8_t writeCommand = SENSOR_ADDR << 1;  
    LL_I2C_TransmitData8(I2C1, writeCommand);  
  
    while (LL_I2C_IsActiveFlag_ADDR(I2C1) != SET)  
    {  
        if (LL_I2C_IsActiveFlag_AF(I2C1) == SET)  
        {  
            BlinkError();  
        }  
    }  
    // EV6  
    // ADDR = 1  
    // cleared by reading SR1 (reading ADDR flag) and reading SR2 (clearing ADDR flag)  
  
    LL_I2C_ClearFlag_ADDR(I2C1);  
  
    // EV8_1  
    // TXE = 1  
    // Make sure transmit register is empty before we start sending data  
    while (LL_I2C_IsActiveFlag_TXE(I2C1) != SET)  
    {  
    }  
  
    // EV8  
    // TXE = 1  
    LL_I2C_TransmitData8(I2C1, ONE_TIME_HIGH_RES);  
  
    while (LL_I2C_IsActiveFlag_BTF(I2C1) != SET)  
    {  
    }  
    // EV8_2  
    // TXE = 1 && BTF = 1  
  
    LL_I2C_GenerateStopCondition(I2C1);  
  
    LL_mDelay(MEASURE_TIME_HIGH_RES_MS);  
  
    while (LL_I2C_IsActiveFlag_BUSY(I2C1) == SET)  
    {  
    }  
  
    // RECEIVE MEASUREMENT DATA  
  
    LL_I2C_GenerateStartCondition(I2C1);  
  
    while (LL_I2C_IsActiveFlag_SB(I2C1) != SET)  
    {  
    }  
    // EV5  
    // SB = 1  
    // Cleared by reading SR1 (reading SB flag) and writing DR (TransmitData)  
  
    LL_I2C_EnableBitPOS(I2C1);  
    LL_I2C_AcknowledgeNextData(I2C1, LL_I2C_ACK);  
  
    uint8_t readCommand = (SENSOR_ADDR << 1) | 0x01;  
    LL_I2C_TransmitData8(I2C1, readCommand);  
  
    while (LL_I2C_IsActiveFlag_ADDR(I2C1) != SET)  
    {  
        if (LL_I2C_IsActiveFlag_AF(I2C1) == SET)  
        {  
            BlinkNrOfTimes(1);  
            BlinkError();  
        }  
    }  
    // EV6  
    // ADDR = 1  
    // cleared by reading SR1 (reading ADDR flag) and reading SR2 (clearing ADDR flag)  
  
    LL_I2C_ClearFlag_ADDR(I2C1);  
  
    LL_I2C_AcknowledgeNextData(I2C1, LL_I2C_NACK);  
  
    while (LL_I2C_IsActiveFlag_BTF(I2C1) != SET)  
    {  
    }  
  
    LL_I2C_GenerateStopCondition(I2C1);  
  
    if (secondTime)  
        BlinkNrOfTimes(3);  
  
    uint16_t data = LL_I2C_ReceiveData8(I2C1);  
    data = data << 8;  
    data |= LL_I2C_ReceiveData8(I2C1);  
  
    while (LL_I2C_IsActiveFlag_BUSY(I2C1) == SET)  
    {  
    }  
  
    LL_I2C_DisableBitPOS(I2C1);  
    LL_I2C_AcknowledgeNextData(I2C1, LL_I2C_ACK);  
  
    return data;  
}
c embedded stm32 i2c