2022-05-29 02:09 PM
I am using an STM32F411, and am attempting to use I2C to communicate with an MPU-6050 (relevant datasheet info attached).
I've tried to setup I2C in accordance with the timing requirements on the MPU-6050 datasheet:
#define MPU6050_PIN_CL (6)
#define MPU6050_PIN_DA (7)
int8_t Mpu6050_Init(void)
{
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOBEN;
RCC->APB1ENR |= RCC_APB1ENR_I2C1EN;
GPIOB->MODER |= (0b10 << (MPU6050_PIN_CL * 2)) |
(0b10 << (MPU6050_PIN_DA * 2));
GPIOB->AFR[0] |= (GPIO_AFRL_AFRL4 << (MPU6050_PIN_CL * 4)) |
(GPIO_AFRL_AFRL4 << (MPU6050_PIN_DA * 4));
GPIOB->OTYPER |= (0b1 << MPU6050_PIN_CL) |
(0b1 << MPU6050_PIN_DA);
GPIOB->OSPEEDR |= (0b11 << (MPU6050_PIN_CL * 2)) |
(0b11 << (MPU6050_PIN_DA * 2));
GPIOB->PUPDR |= (0b01 << (MPU6050_PIN_CL * 2)) |
(0b01 << (MPU6050_PIN_DA * 2));
I2C1->CR1 = I2C_CR1_SWRST;
I2C1->CR1 &= ~I2C_CR1_SWRST;
I2C1->CR2 |= 0x08;
I2C1->CCR = 0x78;
I2C1->TRISE = 0x03;
I2C1->CR1 |= I2C_CR1_PE;
return 0;
}
To generate a start condition and begin communicating, I am using this code:
I2C1->CR1 |= I2C_CR1_START;
while (!(I2C1->SR1 & I2C_SR1_SB));
I2C1->DR = 0b1101000;
while (!(I2C1->SR1) | !(I2C1->SR2));
I2C1->CR1 |= I2C_CR1_STOP;
However, it seems to get stuck when waiting for the start bit to appear.
Attaching up both lines to a logic analyzer confirms that nothing is happening:
Does anyone have any ideas where I've gone wrong?
2022-05-29 05:51 PM
Before using the I2C, enable its clock in RCC.
2022-05-30 03:20 AM
The RCC clock for I2C1 is already enabled in the first piece of code I shared (line 8: "RCC->APB1ENR |= RCC_APB1ENR_I2C1EN;")
2022-05-30 05:46 AM
What is D0, D1, D2 on the picture?
Each time you are in doubt, first read out and check the relevant registers content.
GPIOB->AFR[0] |= (GPIO_AFRL_AFRL4 << (MPU6050_PIN_CL * 4)) |
(GPIO_AFRL_AFRL4 << (MPU6050_PIN_DA * 4));
This probably does not do what you think it does.
JW
2022-05-30 09:13 AM
D0, D1 and D2 are the channels of the logic analyzer (however only D0 and D2 are relevant since D1 is not connected up). D0 is attached to the CL line and D2 is attached to the DA line.
Seems I misunderstood what "GPIO_AFRL_AFRL4" is defined as, changed this to "0b0100" and am now seeing more what I would expect to see:
However, when extending the existing code further by adding "I2C1->DR = 0x78;" before the stop condition, nothing further happens. Do I have to sandwich start/stop conditions around every transmission? After writing to DR, I am reading the TXE bit in the SR register and it is not being set to 1 (which would indicate that the register is empty and that more data can be written to it). Also, is the ack automatically handled, or do I need to pull DA high manually?
2022-05-30 11:03 AM
There is no ACK from the slave.
There may be many reasons for that; among other things you are using the 7-bit address of MPU6050 (provided the pin determining LSB of 7-bit address is grounded) but you have to left-shift it by one and leave LSB of the resulting byte 0 for Write (or 1 for Read, but you want to Write first).
You also have to follow the procedure outlined in RM. I am not going to do that for you, but I doubt
> while (!(I2C1->SR1) | !(I2C1->SR2));
is the proper condition to find out end of address stage.
JW