# Not getting acknowledgement from MPU 9250 I2C slave using STM32F401RE

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.

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
if(I2C1->SR1 & I2C_SR1_AF)
return -1; //if ack fail return
if(!(I2C1->SR1 & I2C_SR1_AF))  return 2;

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:

Setup:

• 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. Oct 2 '18 at 15:50
• Do you have any pull up resistors on SCL and SDA? Oct 2 '18 at 16:00
• 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. Oct 2 '18 at 16:03
• What TRISE register? What is the resistance of the pull ups? Post an image of your setup, what is the cable/wire length? Oct 2 '18 at 16:09
• 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. 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.

• 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. 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.

EDIT:

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.

• Okay thanks, i'll have a go at adjusting the pull-ups and get back to you. Oct 2 '18 at 16:33
• 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. Oct 3 '18 at 9:42