cancel
Showing results for 
Search instead for 
Did you mean: 

I2C2 hangs at while(!I2C_CheckEvent(LSM_I2C, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));

harinath
Associate III
Posted on May 18, 2012 at 06:21

I have STM32-P103 board which uses STM32F103RB micro. I connected an I2C sensor to I2C2 pins. STM32-P103 board, MPU6050 sensor breakout board schematics are below :

0690X000006052GQAQ.png I use only 4 pins of the sensor, SCL, SDA, Vcc, GND.I have the following Initialization code & reading code:

#define MPU6050_I2C I2C2
#define MPU6050_I2C_RCC_Periph RCC_APB1Periph_I2C2
#define MPU6050_I2C_Port GPIOB
#define MPU6050_I2C_SCL_Pin GPIO_Pin_10
#define MPU6050_I2C_SDA_Pin GPIO_Pin_11
#define MPU6050_I2C_RCC_Port RCC_APB2Periph_GPIOB
#define MPU6050_I2C_Speed 100000
void
MPU6050_I2C_Init(
void
)
{
I2C_InitTypeDef I2C_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
/* Enable I2C and GPIO clocks */
RCC_APB1PeriphClockCmd(MPU6050_I2C_RCC_Periph, ENABLE);
RCC_APB2PeriphClockCmd(MPU6050_I2C_RCC_Port, ENABLE);
/* Configure I2C pins: SCL and SDA */
GPIO_InitStructure.GPIO_Pin = MPU6050_I2C_SCL_Pin | MPU6050_I2C_SDA_Pin;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
GPIO_Init(MPU6050_I2C_Port, &GPIO_InitStructure);
I2C_DeInit(MPU6050_I2C);
/* I2C Peripheral Enable */
I2C_Cmd(MPU6050_I2C, ENABLE);
/* I2C configuration */
I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
I2C_InitStructure.I2C_OwnAddress1 = 0x68;
// This is sensor address
I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
I2C_InitStructure.I2C_ClockSpeed = MPU6050_I2C_Speed;
/* Apply I2C configuration after enabling it */
I2C_Init(MPU6050_I2C, &I2C_InitStructure);
}
void
I2C_BufferRead(u8 slAddr, u8* pBuffer, u8 ReadAddr, u16 NumByteToRead)
{
// ENTR_CRT_SECTION();
/* While the bus is busy */
while
(I2C_GetFlagStatus(MPU6050_I2C, I2C_FLAG_BUSY));
/* Send START condition */
I2C_GenerateSTART(MPU6050_I2C, ENABLE);
/* Test on EV5 and clear it */
while
(!I2C_CheckEvent(MPU6050_I2C, I2C_EVENT_MASTER_MODE_SELECT));
/* Send 
MPU6050 address for write */
I2C_Send7bitAddress(MPU6050_I2C, slAddr, I2C_Direction_Transmitter);
/* Test on EV6 and clear it */
while
(!I2C_CheckEvent(MPU6050_I2C, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
/* Clear EV6 by setting again the PE bit */
I2C_Cmd(MPU6050_I2C, ENABLE);
/* Send the MPU6050_Magn's internal address to write to */
I2C_SendData(MPU6050_I2C, ReadAddr);
/* Test on EV8 and clear it */
while
(!I2C_CheckEvent(MPU6050_I2C, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
/* Send STRAT condition a second time */
I2C_GenerateSTART(MPU6050_I2C, ENABLE);
/* Test on EV5 and clear it */
while
(!I2C_CheckEvent(MPU6050_I2C, I2C_EVENT_MASTER_MODE_SELECT));
/* Send MPU6050 address for read */
I2C_Send7bitAddress(MPU6050_I2C, slAddr, I2C_Direction_Receiver);
/* Test on EV6 and clear it */
while
(!I2C_CheckEvent(MPU6050_I2C, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));
/* While there is data to be read */
while
(NumByteToRead)
{
if
(NumByteToRead == 1)
{
/* Disable Acknowledgement */
I2C_AcknowledgeConfig(MPU6050_I2C, DISABLE);
/* Send STOP Condition */
I2C_GenerateSTOP(MPU6050_I2C, ENABLE);
}
/* Test on EV7 and clear it */
if
(I2C_CheckEvent(MPU6050_I2C, I2C_EVENT_MASTER_BYTE_RECEIVED))
{
/* Read a byte from the MPU6050 */
*pBuffer = I2C_ReceiveData(MPU6050_I2C);
/* Point to the next location where the byte read will be saved */
pBuffer++;
/* Decrement the read bytes counter */
NumByteToRead--;
}
}
/* Enable Acknowledgement to be ready for another reception */
I2C_AcknowledgeConfig(MPU6050_I2C, ENABLE);
// EXT_CRT_SECTION();
}

I call the I2C_BufferRead function just after initialization.Execution hangs at

while
(!I2C_CheckEvent(MPU6050_I2C, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));

Any helpappreciated. Thank you #stm32f103rb #i2c2
10 REPLIES 10
alok472
Associate II
Posted on May 18, 2012 at 08:29

for I2C, strongly suggest to use AN2824  STM32F10xxx devices: optimized I²C examples.

it works always !!

frankmeyer9
Associate II
Posted on May 18, 2012 at 10:29

Is it this problem ?

http://www.keil.com/forum/18440/

harinath
Associate III
Posted on May 18, 2012 at 12:16

@fm

http://www.keil.com/forum/18440/

I checked that thread before posting here.

I2Cx-> OAR1 = (I2C_InitStruct-> I2C_AcknowledgedAddress | I2C_InitStruct-> I2C_OwnAddress1);

when this line excuted,

I2Cx-> OAR1 =0x4068 = 0x4000 | 0x0068

Seems it is not a problem. The optimized I2C sample also has the same line inside the function: I2C_Init(

I2C_TypeDef * I2Cx, I2C_InitTypeDef * I2C_InitStruct)

My first post is edited with clear connection diagram. I doubt pull-up resistors. STM32 board as well as MPU6050 sensor board has pull-up resistors. will it be a problem ? Thank you
frankmeyer9
Associate II
Posted on May 18, 2012 at 12:41

The issue described is a common I2C problem - an address mismatch in 7 Bit mode.

You should check how the supplier of the I2C slave specifies the address of the device. The LSB of the address is the R/W bit, and is specified by the standard. Sometimes you see suppliers define 8 Bit addresses, assuming the LSB to be zero, and sometimes they specify 7 Bit addresses, occupying bits 7..1. Check what is sent on the bus, and compare with the addresses the master and slave expect.

As a side note:

In this cases, it is an advantage to have bitbanging code available for I2C. It gives you the opportunity to single-step though the code, and use a multimeter to check the bus...

harinath
Associate III
Posted on May 18, 2012 at 13:27

@fm, The data sheet says :

The slave address of the MPU-6050 is b110100X which is 7 bits long. The LSB bit of the 7 bit address is determined by the logic level on pin AD0. This allows two MPU-6050s to be connected to the same I2C bus. When used in this configuration, the address of the one of the devices should be b1101000 (pin AD0 is logic low) and the address of the other should be b1101001 (pin AD0 is logic high).

I have AD0 pin connected to GND. which means 7 bit address is b1101000. 

 

Datasheet says : 

http://invensense.com/mems/gyro/documents/PS-MPU-6000A.pdf

To read the internal MPU-6050 registers, the master sends a start condition, followed by the I2C address and a write bit, and then the register address that is going to be read. Upon receiving the ACK signal from the MPU-6050, the master transmits a start signal followed by the slave address and read bit. As a result, the MPU-6050 sends an ACK signal and the data. The communication ends with a not acknowledge (NACK) signal and a stop bit from master. The NACK condition is defined such that the SDA line remains high at the 9th clock cycle. 

To write the internal MPU-6050 registers, the master transmits the start condition (S), followed by the I2C address and the write bit (0). At the 9th clock cycle (when the clock is high), the MPU-6050 acknowledges the transfer. Then the master puts the register address (RA) on the bus. After the MPU-6050 acknowledges the reception of the register address, the master puts the register data onto the bus. This is followed by the ACK signal, and data transfer may be concluded by the stop condition (P). To write multiple bytes after the last

ACK signal, the master can continue outputting data rather than transmitting a stop signal. In this case, the MPU-6050 automatically increments the register address and loads the data to the appropriate register. 

Is my code ok ?

 

 

Thank you
frankmeyer9
Associate II
Posted on May 18, 2012 at 19:11

An address of b110100X means either 0xD0/0xD1 or 0xD2/0xD3, depending on the AD0 pin configuration. The LSB is determined by the access type. It is 0 for write access, and one 1 for read access to the slave. If you see this as ''7 Bit address and Read/Write Bit'' or ''two 8 Bit addresses for Read and Write access'' is a matter of interpretation. A slave device consumes always 2 addresses on the bus.

I only have some older code that works with bitbanging and awaits a rewrite to use the hardware I2C interface. Maybe I can check your code over the weekend.

I strongly suggest to check the actual events on the bus with a scope. Otherwise it might get hard to track down problems.

alok472
Associate II
Posted on May 19, 2012 at 05:47

My first post is edited with clear connection diagram. I doubt pull-up resistors. STM32 board as well as MPU6050 sensor board has pull-up resistors. will it be a problem

 

in your schematics, there are 10k PU on both side. This makes effectively 5K PU. This should not be a problem

harinath
Associate III
Posted on May 21, 2012 at 08:48

@alokm : I checked the sensor breakout board with Arduino, it works ( note pull ups are 10k). Of course you are right, pull-ups of 5k should not be a problem.

There might be problem in the I2C code or library or something. But I'm sure hardware is not causing the problem.

Optimized I2c Sample code has functions to just Master buffer_read & buffer_write. In my case the execution has not reached the read code, it stuck before it.

@fm: suggested something regarding 7-bit address. Which might be causing the problem, because it stuck in the while loop just after sending the 7-bit address.

So, I must experiment what he says( though i did not understand exactly what he said).

Would you explain few different cases how to dig this one please?

Thank you

frankmeyer9
Associate II
Posted on May 21, 2012 at 10:26

How good do you know the I2C standard ?

Each device has two addresses. The bits 7 to 1 are defined by the device, bit 0 is defined by the access type. For a write access bit 0 is 0, for a read access, it is one. Thus it depends on the following action what address you actually need. I still suggest to check the address sending with a scope - are you seeing the correct address ? I successfully reached the stage of reproducing your problem. However I did not have the time to debug in detail. I suggest to debug into the

I2C_Send7bitAddress

() function, to see the values filled in the registers, and compare it with the values read back from the scope. I guess you are first trying to read the WHO_AM_I register of the device, and setting the register offset with a write access, thus the address should be even.