AnsweredAssumed Answered

I2C problems - ADDR bit is not set

Question asked by ashraf.salahuddin on May 24, 2014
Hi everyone, 
I'm trying to implement I2C1 on stm32f4-discovery to let the kit contact with a light-to-digital sensor TSL2581CS ..
In the following code, the 

<b>I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)</b>

returns ERROR although, BUSY, MSL, TxE and TRA are set and the AF bit is not set meaning that the address sent is acknowledged !!?? 

here's the whole code 
<b>
#include <stm32f4xx.h>


// this slave address belongs to the STM32F4-Discovery board's 
#define SLAVE_ADDRESS 0x39 // the slave address (example)


void I2C1_init(void){


     GPIO_InitTypeDef GPIO_InitStruct;
     I2C_InitTypeDef I2C_InitStruct;


     // enable APB1 peripheral clock for I2C1
     RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
     // enable clock for SCL and SDA pins
     RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);


     /* setup SCL and SDA pins
      * You can connect the I2C1 functions to two different
      * pins:
      * 1. SCL on PB6 or PB8  
      * 2. SDA on PB7 or PB9
      */
     GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;       // we are going to use PB6 and PB9
     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_PinSource6, GPIO_AF_I2C1);     // SCL
     GPIO_PinAFConfig(GPIOB, GPIO_PinSource7, 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_Disable;                    // disable acknowledge when reading (can be changed later on)
     I2C_InitStruct.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit; // set address length to 7 bit addresses
     I2C_Init(I2C1, &I2C_InitStruct);                                        // init I2C1


     // enable I2C1
     I2C_Cmd(I2C1, ENABLE);
}


/* This function issues a start condition and 
 * transmits the slave address + R/W bit
 * 
 * Parameters:
 *           I2Cx --> the I2C peripheral e.g. I2C1
 *           address --> the 7 bit slave address
 *           direction --> the transmission direction can be:
 *                               I2C_Direction_Tranmitter for Master transmitter mode
 *                               I2C_Direction_Receiver for Master receiver
 */
void I2C_start(I2C_TypeDef* I2Cx, uint8_t address, uint8_t direction){
     /*
      * EV5 : start bit sent (BUSY, MSL, SB)
      * EV6 : slave acknowledged address (BUSY, MSL, ADDR)
      * EV8 : DR ready for new byte to transmit, transmit buffer empty (BUSY, MSL, TxE)
      * EV9 : new byte received in the DR, receive buffer not empty (BUSY, MSL, RxNE) 
      */
     
     
     // Wait until I2C1 is not busy any more ## Check flag BUSY = 0 
     while(I2C_GetFlagStatus(I2Cx, I2C_FLAG_BUSY));
  
     // Send I2C1 START condition            ## Signal START on the bus 
     I2C_GenerateSTART(I2Cx, ENABLE);


     // Wait for I2C1 EV5(BUSY,MSL,SB)--> Slave has acknowledged start condition ## START correct
     while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_MODE_SELECT));


     // Send slave Address for write 
     I2C_Send7bitAddress(I2Cx, address, direction);


     /* wait for I2Cx EV6 (BUSY, MSL, ADDR, TXE,TRA), check if 
      * either Slave has acknowledged Master transmitter or
      * Master receiver mode, depending on the transmission direction  ##Slave address acknowledged
      */ 
     if(direction == I2C_Direction_Transmitter){
          while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
     }
     else if(direction == I2C_Direction_Receiver){
          while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));
     }
}


/* This function transmits one byte to the slave device
 * Parameters:
 *          I2Cx --> the I2C peripheral e.g. I2C1 
 *          data --> the data byte to be transmitted
 */
void I2C_write(I2C_TypeDef* I2Cx, uint8_t data)
{
     // wait for I2C1 EV8 --> last byte is still being transmitted (last byte in SR, buffer empty), next byte can already be written
     while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTING));
     I2C_SendData(I2Cx, data);
}




/* This function reads one byte from the slave device 
 * and acknowledges the byte (requests another byte)
 */
uint8_t I2C_read_ack(I2C_TypeDef* I2Cx){
     uint8_t data;
     // enable acknowledge of received data
     I2C_AcknowledgeConfig(I2Cx, ENABLE);
     // wait until one byte has been received
     while( !I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_RECEIVED) );
     // read data from I2C data register and return data byte
     data = I2C_ReceiveData(I2Cx);
     return data;
}


/* This function reads one byte from the slave device
 * and doesn't acknowledge the received data 
 * after that a STOP condition is transmitted
 */
uint8_t I2C_read_nack(I2C_TypeDef* I2Cx){
     uint8_t data;
     // disable acknowledge of received data
     // nack also generates stop condition after last byte received
     // see reference manual for more info
     I2C_AcknowledgeConfig(I2Cx, DISABLE);
     I2C_GenerateSTOP(I2Cx, ENABLE);
     // wait until one byte has been received
     while( !I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_RECEIVED) );
     // read data from I2C data register and return data byte
     data = I2C_ReceiveData(I2Cx);
     return data;
}


/* This function issues a stop condition and therefore
 * releases the bus
 */
void I2C_stop(I2C_TypeDef* I2Cx){


     // Send I2C1 STOP Condition after last byte has been transmitted
     I2C_GenerateSTOP(I2Cx, ENABLE);
     // wait for I2C1 EV8_2 --> byte has been transmitted
     while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
}


int main(void){
     uint8_t received_data;
     received_data += 0;
     
     I2C1_init();                                                                                                                     // initialize I2C peripheral


     I2C_start(I2C1, SLAVE_ADDRESS<<1, I2C_Direction_Transmitter); // start a transmission in Master transmitter mode
     I2C_write(I2C1, 0x01);                                                                                            // write one byte to the slave
     I2C_stop(I2C1);                                                                                                           // stop the transmission
     
     I2C_start(I2C1, SLAVE_ADDRESS<<1, I2C_Direction_Receiver);       // start a transmission in Master receiver mode
     received_data = I2C_read_nack(I2C1); // read one byte and don't request another byte, stop transmission


     while(1);
}
</b>

now what's the problem ??

Outcomes