I am using an STM32F401RE development board to communicate over I2C to an MPU9250 based breakout board sensor. So far I have set the start condition, and sent the slave address/write bit to the device, but I am not getting any acknowledgement. I have tried slowing down the SCL frequency to 50KHz, and speeding up the rise time, but still nothing. The slave address I am sending to the device is 0x68. I am relatively new to bare metal programming, so any advice would be much appreciated.

Code from I2C header:

void I2c_Init(uint8_t slaveAddr) {

  I2C1->CR1 &= ~I2C_CR1_PE;
  RCC->AHB1ENR |= (1ul << 1); //enable gpio clock
  RCC->APB1ENR |= (1ul << 21);// enable i2c clock

  GPIOB->MODER &= ~(3ul << 16);
  GPIOB->MODER |= (2ul << 16); //set pb8 to af mode 
  GPIOB->MODER &= ~(3ul << 18);
  GPIOB->MODER |= (2ul << 18); //set pb9 to af mode 

  GPIOB->AFR[1] &= ~(0xF << 0); //pin 8 i2c af 
  GPIOB->AFR[1] |= (4ul << 0);

  GPIOB->AFR[1] &= ~(0xF << 4); //pin 9 i2c af 
  GPIOB->AFR[1] |= (4ul << 4);

  GPIOB->OTYPER |= (1ul << 8); //set pb8 to open drain 
  GPIOB->OTYPER |= (1ul << 9); //set pb9 to open drain 

  GPIOB->OSPEEDR &= ~(3ul << 16);
  GPIOB->OSPEEDR |= (2ul << 16); //set pb8 to fast mode 
  GPIOB->OSPEEDR &= ~(3ul << 18);
  GPIOB->OSPEEDR |= (2ul << 18); //set pb9 to fast mode 

  GPIOB->PUPDR &= ~(3ul << 16);
  GPIOB->PUPDR &= ~(3ul << 18);

  I2C1->CR2 &= ~(0x3F << 0); //reset freqyency bits
  I2C1->CR2 = I2C_CR2_FREQ_3; //set register bits to 0x00000008 8MHz
  I2C1->CCR &= ~(1ul << 15); //set bit 15 to 0 sm mode
  I2C1->CCR &= ~(0xFFF << 0); //clear bits 0-11 for scl
  I2C1->CCR |= (0x28 << 0); // setup scl clock as 100Khz by 5000ns / PCLK 125 = 40 (0x28) /////////////50hz 20000ns/125 = 160 = 0xA0
  I2C1->TRISE &= ~(0x3F << 0); //clear bits 0 -5;
  I2C1->TRISE |=  (0x03 << 0); // set rise time to 1000/PCLK = 0x08 + 1 ////////for 300ns//////  300/125 = 0x02 + 1
  I2C1->OAR1 = (1ul << 14);
  //I2C1->OAR2 &= (1ul << 0);
  I2C1->CR1 |= I2C_CR1_PE | I2C_CR1_ACK;// | I2C_CR1_POS;


int write_i2c(uint8_t slaveAddr, uint8_t dat) {

  I2C1->CR1 |= I2C_CR1_START; //start bit init
  while (!(I2C1->SR1 & I2C_SR1_SB)); //wait for start confirm
  I2C1->DR = slaveAddr & ~(1ul << 7);// ~I2C_OAR1_ADD0; // send slave address and write bit
  while (!(I2C1->SR1 & I2C_SR1_ADDR))  // wait for address confirm
      if(I2C1->SR1 & I2C_SR1_AF)
          return -1; //if ack fail return 
      if(!(I2C1->SR1 & I2C_SR1_AF))  return 2;

  I2C1->SR1; //sr read
  I2C1->SR2; //sr2 read
  I2C1->DR &= ~(0xFF << 0); //clear data reg
  I2C1->DR |= (dat << 0); // send data
  while (!(I2C1->SR1 & (I2C_SR1_BTF | I2C_SR1_AF ))); //wait for data confirm

  I2C1->CR1 |= I2C_CR1_STOP; //stop bit
  return 0;

Scope output:

enter image description here


enter image description here

  • \$\begingroup\$ IMHO, you have something wrong with the bus. You can see that it makes difficult to rise the signal 0->1, while no problem from 1->0. So it is not caused by capacitance of the bus, rather wrong driving. \$\endgroup\$ Oct 2 '18 at 15:50
  • \$\begingroup\$ Do you have any pull up resistors on SCL and SDA? \$\endgroup\$ Oct 2 '18 at 16:00
  • \$\begingroup\$ I thought that the rise time from low to high is caused by the pull-up resistors on the SDA and SCL pins, and the TRISE register on the master device. The board I am using has pull-up resistors. \$\endgroup\$ Oct 2 '18 at 16:03
  • \$\begingroup\$ What TRISE register? What is the resistance of the pull ups? Post an image of your setup, what is the cable/wire length? \$\endgroup\$ Oct 2 '18 at 16:09
  • \$\begingroup\$ The TRISE register sets the maximum rise time for SCL. The resistors on the board are 10K. I'll add a picture of my setup to the main post. \$\endgroup\$ Oct 2 '18 at 16:16

You are using an incorrect address. The seven-bit address of your slave is 1101000 (assuming AD0=0). That means that the 8-bit address byte for a write would be 11010000, or 0xD0.

I also agree with Marko Buršič suggestion to clean up the rising edges by reducing the pullup resistance.

  • \$\begingroup\$ Thank you very much, that worked. I tried looping over each of the 127 possible addresses but nothing worked so I assumed it was my SDA/SCL lines. I think this was a case of me not understanding my bitwise operations well enough. \$\endgroup\$ Oct 3 '18 at 9:35

Before you search for code problems, you should have a bus properly working. Some devices have built on pull ups, but 10k is rather to high resistance.

You should enable the MCU pull ups as well, or add another 10k in parallel.


Now let's see what you get from the scope: 0110 1000, which is 0x68 hex, right? But you should have 7-bit address + R/W bit = 11010000 Somehow you don't shift to the left properly in your program.

  • \$\begingroup\$ Okay thanks, i'll have a go at adjusting the pull-ups and get back to you. \$\endgroup\$ Oct 2 '18 at 16:33
  • \$\begingroup\$ Yeah it turns out my address was incorrect, was getting confused over how the bits are transmitted and did not shift it properly. Thanks for your help. \$\endgroup\$ Oct 3 '18 at 9:42

Your Answer

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

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