2014-01-02 09:26 AM
Hello everyone. I probably have some usual problem about i2c communication. Namely, I have the following code and trying to read MPU6050 WHO_AM_I register(http://www.invensense.com/mems/gyro/mpu6050.html). The address of MPU6050 is 0x68 << 1(0xD0) but when i try to read it i stuck at
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)); The whole code is given: //#include ''MPU6050.h'' #include ''stm32f4xx_i2c.h'' #include ''stm32f4xx_gpio.h'' #include ''stm32f4xx_rcc.h'' //int16_t AccelGyro[6]={0}; int main() { int i = 0; GPIO_InitTypeDef GPIO_InitStruct; I2C_InitTypeDef I2C_InitStruct; u8* pBuffer; // enable clock for SCL and SDA pins RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE); // enable APB1 peripheral clock for I2C1 RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE); GPIO_InitStruct.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9; // we are going to use PB6 and PB7 GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF; // set pins to alternate function GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; // set GPIO speed GPIO_InitStruct.GPIO_OType = GPIO_OType_OD; // set output to open drain --> the line has to be only pulled low, not driven high GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP; // enable pull up resistors GPIO_Init(GPIOB, &GPIO_InitStruct); // init GPIOB // Connect I2C1 pins to AF GPIO_PinAFConfig(GPIOB, GPIO_PinSource8, GPIO_AF_I2C1); // SCL GPIO_PinAFConfig(GPIOB, GPIO_PinSource9, GPIO_AF_I2C1); // SDA // configure I2C1 I2C_InitStruct.I2C_ClockSpeed = 100000; // 100kHz I2C_InitStruct.I2C_Mode = I2C_Mode_I2C; // I2C mode I2C_InitStruct.I2C_DutyCycle = I2C_DutyCycle_2; // 50% duty cycle --> standard I2C_InitStruct.I2C_OwnAddress1 = 0x00; // own address, not relevant in master mode I2C_InitStruct.I2C_Ack = I2C_Ack_Enable; // disable acknowledge when reading (can be changed later on) I2C_InitStruct.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_10bit; // set address length to 7 bit addresses I2C_Init(I2C1, &I2C_InitStruct); // init I2C1 // enable I2C1 I2C_Cmd(I2C1, ENABLE); /* While the bus is busy */ while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY)); /* Send START condition */ I2C_GenerateSTART(I2C1, ENABLE); /* Test on EV5 and clear it */ while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT)); /* Send MPU6050 address for write */ I2C_Send7bitAddress(I2C1, 0xD0, I2C_Direction_Transmitter); /* Test on EV6 and clear it */ while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)); /* Clear EV6 by setting again the PE bit */ I2C_Cmd(I2C1, ENABLE); /* Send the MPU6050's internal address to write to */ I2C_SendData(I2C1, 0x75); /* Test on EV8 and clear it */ while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED)); /* Send STRAT condition a second time */ I2C_GenerateSTART(I2C1, ENABLE); /* Test on EV5 and clear it */ while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT)); /* Send MPU6050 address for read */ I2C_Send7bitAddress(I2C1, 0xD1, I2C_Direction_Receiver); /* Test on EV6 and clear it */ while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));2014-01-02 09:39 AM
Hi
''I probably have some usual problem about i2c communication.'' Do you know the I2C protocol? http://en.wikipedia.org/wiki/I%C2%B2C ''when i try to read it i stuck at while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));'' Looking at the code - you will get to the while() statement in a few nano seconds. http://en.wikipedia.org/wiki/Nano- I think you device will not be ready in that amount of time! This is not just a coding problem - this is 'understand your system/electronics' problem!2014-01-02 09:49 AM
Thank you sung.chen_chung,
I am familiar with the i2c, and i am using this http://eliaselectronics.com/stm32f4-tutorials/stm32f4-i2c-master-tutorial/ as a reference. I don't see any delays between the I2C command so I assumed that my solution will work. What do you suggest?2014-01-02 10:00 AM
Hi
Strictly speaking ''I think you device will not be ready in that amount of time!'' is my intuitive guess. To really see what is going on - put an oscilloscope on the data and clock and see what is happening. If it is due to the device not being ready - put in a 100ms delay before the I2C access. OR try triggering the I2C access from a button push.2014-01-02 10:15 AM
Thanks, I added a for loop with __NOP() and it is working now. I don't have oscilloscope since I am on a vacation :) Anyway, how to do it in a smarter way(asynchronously)?