2011-10-20 04:39 PM
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 000void 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 Flagwhile (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-bytes2011-10-21 01:28 AM
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.2011-10-21 07:39 AM
check the errata - it's UGLY
Erik2011-10-24 02:37 PM
2011-10-24 04:18 PM
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?2011-10-25 04:00 PM
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.