2
\$\begingroup\$

I am trying to interface my STM32F4 Discovery board with a sensor that works over i2c, since the sensor required a specialized i2c protocol, I decided to implement my functions using registers. But when I am trying to send a byte and check the BTF bit of the SR1 Register if the byte transfer is finished, it never seems to get cleared and my code hangs in the while loop indefinitely.

        while (!(I2C3->SR1 & I2C_SR1_BTF)) ;

And if I manage to pass that while loop commenting that out then it stuck while waiting for the address transmission bit.

while (!(I2C3->SR1 & I2C_SR1_ADDR))  // Read Request Adress set

Whole snippet :

unsigned int axI2CWriteRead(unsigned char bus_unused_param, unsigned char addr,
                        unsigned char *pTx, unsigned short txLen,
                        unsigned char *pRx, unsigned short *pRxLen)

extern I2C_HandleTypeDef hi2c3;
HAL_StatusTypeDef status;
uint8_t t;
*pRxLen = 0;
memset(pRx, 0, 2);
uint8_t rxData[255] = {0};
uint8_t index = 0;

    I2C3->CR1 |= I2C_CR1_START;
    while(!(I2C3->SR1&I2C_SR1_SB));
    I2C3->DR = 0x90;
    while (!(I2C3->SR1 & I2C_SR1_ADDR))
        if (I2C3->SR1 & I2C_SR1_AF)
         return I2C_FAILED;

    t=I2C3->SR2;
    while(index < txLen)
    {
        unsigned char a = *(pTx+index);
        I2C3->DR = a;
        while (!(I2C3->SR1 & I2C_SR1_BTF)) ;
        index ++;
    }

    index = 0;
    I2C3->CR1 |= I2C_CR1_START;/* Generate Start */
    t = I2C3->DR;
    while(!(I2C3->SR1&I2C_SR1_SB));// Wait until SB is set
    I2C3->DR = 0x90|0x01;

    while (!(I2C3->SR1 & I2C_SR1_ADDR)) //Wait for flag ADDR=1
        if (I2C3->SR1 & I2C_SR1_AF)
         return I2C_FAILED;

    t = I2C3->SR2; //Read SR2 for deleting ADDR

    while(!(I2C3->SR1&I2C_SR1_RXNE));
    rxData[index]=I2C3->DR;

    uint8_t messageLength = rxData[index];
    while (index <= messageLength)
    {
        while(!(I2C3->SR1&I2C_SR1_RXNE));
        if(index == messageLength)
        {
            I2C3->CR1 &= ~I2C_CR1_ACK;
        }
        else
        {
            I2C3->CR1 |= I2C_CR1_ACK;
        }

        rxData[++index] = I2C3->DR;
    }
    I2C3->CR1 |= I2C_CR1_STOP;

        *pRxLen = rxData[0] + 1;
        memcpy(pRx, rxData, *pRxLen);


if (status != HAL_OK)
    return I2C_FAILED;

return I2C_OK;

When I check the i2c bus, I can see Transmission of the address was done correctly but data byte has never been written on the SDA line.

Logic Analyzer

Do you have any idea what might cause the data not being sent or what might cause the Address sent bit of I2C_SR1 not being set ?

Note :I am using 6.8k pull up resistors

\$\endgroup\$
  • 1
    \$\begingroup\$ Try waiting for I2C_SR1_TXE before sending the first data byte. What do the status registers contain before and after sending? \$\endgroup\$ – berendi - protesting May 19 '19 at 6:17
  • \$\begingroup\$ adding a while ((I2C3->SR1 & I2C_SR1_TXE)) ; didnt change anything but your suggestion of checking status registers wielded interesting results. Value of SR1 is 10000000000 before sending (1024 in decimal) and 10110000010 (1410) after the transmission. Thats a lot of error flags \$\endgroup\$ – Dogus Ural May 19 '19 at 11:40
  • \$\begingroup\$ I suspected my pulldowns for i2c speed of 100kHz might be too low so I changed the i2c bus speed to 400khz. The SR1 Value changed to 10000000010 (1026), with Bit 1 ADDR:Address sent is set although I did a read on SR1 prior to this to clear this bit. \$\endgroup\$ – Dogus Ural May 19 '19 at 12:49
  • \$\begingroup\$ ADDR is cleared by reading SR1 and then SR2. \$\endgroup\$ – berendi - protesting May 20 '19 at 8:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.