0
\$\begingroup\$

I am doing I2C project with MPU6050 using STM32F4DISCOVERY board. The ADDR bit in SR1 register is clearing in one instruction execution without reading SR2 register. Because of clearing ADDR bit, I can't do acknowledge disable is made during EV6 in single byte receiving case.

The datasheet states:

ADDR: Address sent (master mode)/matched (slave mode) This bit is cleared by software reading SR1 register followed reading SR2.

In case a single byte has to be received, the Acknowledge disable is made during EV6 (before ADDR flag is cleared) and the STOP condition generation is made after EV6.

If I write any instruction (or declaration) between I2C->DR=address|0 and while(!(I2C2->SR1 & (1<<1))) in below code, then ADDR flag is cleared without reading the SR2 register (I2C2->SR2).

if(direction==i2c_transmitter_mode)
{

    I2C2->DR = address | 0;//SEND ADDRESS WITH ZERO LAST BIT
    while(!(I2C2->SR1 & (1<<1)))
    {
        if(--i2c1_timeout==00)
        {
            return 1;
        }
    }
    I2C2->SR2;
    return 0;

}

How can I fix this problem?

\$\endgroup\$
1
  • \$\begingroup\$ I am also facing the same issue, could you please post the solution if it got resolved. \$\endgroup\$
    – user347193
    Aug 14 at 17:39

2 Answers 2

1
\$\begingroup\$

You can fix it by using the correct bit. ADDR bit is not 1<<7 but 1<<1.

\$\endgroup\$
2
  • \$\begingroup\$ Sir,you are right.But the waiting loop is being continuing with ADDR. Both ADDR AND TXE are set after transmission of address.But ADDR is reset immediately after set .so,i am using TXE bit for waiting and checking AF flag.I am getting WHO_AM_I register value of MPU6050.But problem is ADDR \$\endgroup\$
    – naresh
    Oct 19, 2019 at 5:31
  • \$\begingroup\$ much more issues in those 5 lines of code OP has :) \$\endgroup\$ Oct 19, 2019 at 12:07
1
\$\begingroup\$
  1. Do not use magic numbers like 1<<1 1<<7 on those complex uCs. Use human readable definitions.

  2. Your sequence is wqrong

    I2C1 -> CR1 |= I2C_CR1_START;
    while(!(I2C1 -> SR1 & I2C_SR1_SB ));
    I2C1 -> DR = addr;
    while(!(I2C1 -> SR1 & I2C_SR1_ADDR));
    (void)I2C1 -> SR2;

it is a very simple version - you should add timeouts, error checking, address ACK checking etc. But it shows the general idea.

  1. I2C2->DR = address | 0; - it does not clear the last bit. Actually it does nothing. My advice - read about bitwise operators

to clear the particular bit:

address &= ~(1 << bitnumber);
I2C2->DR = address;

or for the bit zero

address &= ~(1 << 0);
I2C2->DR = address;

why I did not write address &= 0xfffffffe; - because it less understandable for humans. If you see the code with ~ you know that someone is zeroing some bits.

\$\endgroup\$
5
  • \$\begingroup\$ sir,i followed below sequence using functions l I2C1 -> CR1 |= I2C_CR1_START; while(!(I2C1 -> SR1 & I2C_SR1_SB )); I2C1 -> DR = addr; while(!(I2C1 -> SR1 & I2C_SR1_ADDR)); (void)I2C1 -> SR2; \$\endgroup\$
    – naresh
    Oct 19, 2019 at 19:44
  • \$\begingroup\$ I will follow your suggestions.I am getting WHO_AM_I register value of MPU6050.But problem is ADDR. please help me.Thank you for your reply \$\endgroup\$
    – naresh
    Oct 19, 2019 at 19:59
  • \$\begingroup\$ I don't have intention to clear the address.my intention to sent 0xD0 address to DR register in master transmission mode and send 0xD1 for receiving mode using I2C2->DR = address | 1. \$\endgroup\$
    – naresh
    Oct 19, 2019 at 20:09
  • \$\begingroup\$ | is a or operator. Oring with zero does nothing. U gave the way of clearing particular bits \$\endgroup\$ Oct 19, 2019 at 21:12
  • \$\begingroup\$ sir,leave it about | operator.please concentrate on my ADDR problem \$\endgroup\$
    – naresh
    Oct 20, 2019 at 4:55

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.