Electronic – Trouble getting I2C working on STM32 (stm32f103c8t6)

i2cmicrocontrollerstm32stm32f103c8t6stm32f10x

I'm starting out with I2C. I have a development board with stm32f103c8t6 to which I have connected GY-68 board with BMP180 barometric pressure sensor. Documentation of BMP180 describes Chip-id register [0xD0] which holds a constant value of [0x55] and can be a good way of testing if the I2C communication is working.

I am trying to read this register, but my code does not work. I am not sure if my setup is correct, because neither the BMP180 address nor register addres seem to be transmitted.

The board has an external clock set to 8MHz which I am confident is setup properly, because I have working UART which I use to check if the registers are set.

I have calculated CCR and TRISE with this instructions

void initI2C()
{
RCC->APB1ENR |= RCC_APB1ENR_I2C1EN | RCC_APB2ENR_IOPAEN;
GPIOB->CRL |= (1 << 31);// Set pin B7(SDA) to alternate out open drain max 10MHz
GPIOB->CRL |= (1 << 30);
GPIOB->CRL &= ~(1 << 29);
GPIOB->CRL |= (1 << 28);

GPIOB->CRL |= (1 << 27);// Set pin B6(SCL) to alternate push pull max 10MHz
GPIOB->CRL &= ~(1 << 26);// I have also tried open drain 
GPIOB->CRL &= ~(1 << 25);
GPIOB->CRL |= (1 << 24);
I2C1->CR2 |= 0x08;       // Set clock to 8MHz
I2C1->CCR = 0x28;        // Set CCR
I2C1->CCR &= ~(1 << 15); // Sm Mode
I2C1->CCR &= ~(1 << 14); // Duty cycle for Fm mode
I2C1->TRISE = 0x09;      // Set clock rise time
I2C1->CR1 |= 1;          // Enable peripheral
I2C1->CR1 |= (1 << 8);   // Set start bit
while (!(I2C1->SR1 &= 1)) // Wait for start condition generated
{} //Never passes
I2C1->OAR1 = 0xEE; // Set Address
I2C1->DR = 0xD0; // Set address of id register
while (!(I2C1->SR1 &= (1 << 1))) // Wait for end of address transmission
{} // Never passes even with above while commented
while (!(I2C1->SR1 &= (1 << 6))) // Wait for data register not empty
{} // Never passes even with all above while commented
}

Now I know I don't read the register value here, but the the start condition never is generated, the address is never transmitted and the data register is not transmitted. I am reading some activity on both SDA and SCL pins with my multimeter, but I don't have oscilloscope to check exactly.

Any help would be appreciated.

Best Answer

This might not answer all issues but a lot of them.

RCC->APB1ENR |= RCC_APB1ENR_I2C1EN | RCC_APB2ENR_IOPAEN;

By it's definition, the IOPAEN bit is in APB2, not APB1. Also what troubles me is that code would like to enable IOPA but port A is not used while port B is.

// Set pin B6(SCL) to alternate push pull max 10MHz

By definition, I2C uses open drain signaling. Don't use push pull, unless you really know that you can use it with your I2C chips, and even then, what would be the point of it.

while (!(I2C1->SR1 &= 1)) // Wait for start condition generated

While being valid C language, it will try to write back to the status register. Most likely you want:

while (!(I2C1->SR1 & 1)) // Wait for start condition generated