cancel
Showing results for 
Search instead for 
Did you mean: 

I2C read bytes problem

csdominik
Associate III
Posted on October 21, 2011 at 01:39

Hello, my name is Dominik. Im using STM32F103 for a long time, but 2 weeks ago i have to play with i2c for the first time.

Of course I have done my ''homework'' and read about it, use Reference manual, errata, examples etc.

After few days I manage to establish connection with sensors via I2C. But the problem is that while the initialization (sending init buffer to sensor) is going very good (because the led if blinking, with means that the sensor is doing the sampling), the reading is going very bad. I mean I receive only 1 byte, and the byte is 225 (decimal), and the 2nd byte is 0 whatever register I read.

The pull up : 4k7 to 3V3. 

The sequence (idea):

Init {

start();

send(addr_write);

send(register);

send(value); 

stop();

}

sensor_read{

enable_ack();

start()

send(addr_write);

send(register);

start(); // restart 

send(addr_read);

msb = read();

lsb = read();

disable_ack();

dummy = read();

stop();

enable_ack();

}

The real code : 

&sharpdefine I2C_SPEED 1000

//todo przed chwila bylo 40 000

void I2C_Setup(void)

{

    GPIO_InitTypeDef  GPIO_InitStructure;

    I2C_InitTypeDef  I2C_InitStructure;

    /*enable I2C*/

    I2C_Cmd(I2C1,ENABLE);

    /* I2C1 clock enable */

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);

    /* I2C1 SDA and SCL configuration */

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;

    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;

    GPIO_Init(GPIOB, &GPIO_InitStructure);

    //SCL is pin06 and SDA is pin 07 for I2C1

    /* I2C1 configuration */

    I2C_InitStructure.I2C_Mode = I2C_Mode_SMBusHost;

    I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;

    I2C_InitStructure.I2C_OwnAddress1 = 0x00;

    I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;

    I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;

    I2C_InitStructure.I2C_ClockSpeed = I2C_SPEED ;

    I2C_Init(I2C1, &I2C_InitStructure);

    /*!< Enable SMBus Alert interrupt */

    I2C_ITConfig(I2C1, I2C_IT_ERR, ENABLE);    //dont think this is necessary

}

void SFR08_GetChar(void)

{

unsigned short zm1=0,zm2=0,zm3=0;

 /* ACK enable */

I2C_AcknowledgeConfig(I2C1, ENABLE);

 /* Wait for i2c buss not bussy */

while (I2C_GetFlagStatus(I2C1,I2C_FLAG_BUSY)); // Test on BUSY Flag

 /* Force sensor to get new values, and range in cm */

I2C_GenerateSTART(I2C1,ENABLE);

while(!I2C_GetFlagStatus(I2C1, I2C_FLAG_SB));

I2C_SendData(I2C1, SFR_W); //same as I2C_Send7bitAddress(I2C1, SFR_W, I2C_Direction_Transmitter);

while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));// Test on ADDR Flag

I2C_SendData(I2C1, 0x00); // chose register 0x00

while(!I2C_GetFlagStatus(I2C1,I2C_FLAG_TXE));

I2C_SendData(I2C1, 0x51); // fill the 0x00 register with 0x51 to range in cm

while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_TRANSMITTED));

I2C_GenerateSTOP(I2C1, ENABLE);

while(I2C_GetFlagStatus(I2C1, I2C_FLAG_STOPF)); // stop bit flag

delay_ms(100); // minimum 64 ms, conversion time for sensor

  /* Get new values */

zm1  = (uint16_t)SFR08ReadShort(0x01); // read form register 0x01 // just this one would be enough

zm2  = (uint16_t)SFR08ReadShort(0x02); // read from register 0x02

zm3  = (uint16_t)SFR08ReadShort(0x03); // read form register 0x03

}

long SFR08ReadShort(unsigned char address1)

{

uint8_t msb=0, lsb=0; // unsigned char

unsigned char dummy1;//dummy2;

unsigned short data;

I2C_AcknowledgeConfig(I2C1, ENABLE);

// Test on BUSY Flag

while (I2C_GetFlagStatus(I2C1,I2C_FLAG_BUSY));

I2C_GenerateSTART(I2C1, ENABLE);

while(!I2C_GetFlagStatus(I2C1, I2C_FLAG_ADDR));

I2C_SendData(I2C1,SFR_W); // write 0xEE <- write

// Test on ADDR Flag

while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));

I2C_SendData(I2C1,address1); // write register address

while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_TRANSMITTED));

/* restart */

I2C_GenerateSTART(I2C1, ENABLE);

while(!I2C_GetFlagStatus(I2C1, I2C_FLAG_SB));

I2C_SendData(I2C1,SFR_R); // write 0xEF <- READ  // same as send 7bit add

while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));

/* Receive */

msb = I2C_ReceiveData(I2C1);

while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED)); // wait for 

lsb = I2C_ReceiveData(I2C1);

while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED));

// just in case , i get 3 bytes, but the 3rd is 0x00 too.

/* before last one, disable ACK */

I2C_NACKPositionConfig(I2C1, I2C_NACKPosition_Current);

I2C_AcknowledgeConfig(I2C1, DISABLE);

dummy1 = I2C_ReceiveData(I2C1);

while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED));

I2C_GenerateSTOP(I2C1, ENABLE);

while(I2C_GetFlagStatus(I2C1, I2C_FLAG_STOPF)); // stop bit flag

data  = msb<<8;

data |= lsb;

return data;

}

Is there anything wrong? The same situation is with secound sensor on bus. But the values there are like -4010, while should me about +100 to +1200.

Thank you for your time.

#i2c #read-bytes
5 REPLIES 5
ColdWeather
Senior
Posted on October 21, 2011 at 10:28

Hi!

Because of double buffering NACK should be prepared when TWO bytes left to receive yet, not just before the last byte. Look in docs for special cases when receiving one or two bytes along with the POS bit that defines, where ACK/NACK to be placed.

emalund
Associate III
Posted on October 21, 2011 at 16:39

check the errata - it's UGLY

Erik

csdominik
Associate III
Posted on October 24, 2011 at 23:37

The original post was too long to process during our migration. Please click on the provided URL to read the original post. https://st--c.eu10.content.force.com/sfc/dist/version/download/?oid=00Db0000000YtG6&ids=0680X000006I6aZ&d=%2Fa%2F0X0000000brH%2FNu7naxR_SINTlUwqCE6rLHBUj25kCVdekI1Fb5LNOuE&asPdf=false
Posted on October 25, 2011 at 01:18

As you don't provide the complete code, one has to ask if you have in fact enabled the GPIOA clock before initializing the pins.

Have you observed the pin signals with a scope or logic analyzer?

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
csdominik
Associate III
Posted on October 26, 2011 at 01:00

Hello, I have RCC_Init before I2C1 initialization. In Rcc_Init I enable clocks for all GPIO ports.

Tomorrow I will check my hardware with oscilloscope, and than reply.