cancel
Showing results for 
Search instead for 
Did you mean: 

I2C problems

tiche79
Associate II
Posted on March 26, 2014 at 16:10

Hi

I'm trying to write and read some data into a EEPROM (AT24MAC402) with my STM32F417 in I2C but the program loops in the START and don't write or read in the EEPROM. There is a status in ''stm32f4xx_i2c.c'' that stays in ERROR and never past in SUCCES.

I think that the Salve Address is correct so I do not know where the problem may be

Thanks for your help

Here is my program:

/**

 ******************************************************************************

 * @file     Test_I2C/main.c

 * @author   DVC-Co

 * @version V1.0.1

 * @date     04-February-2014

 * @brief   Main program body

 ******************************************************************************

 */

/* Includes */

#include ''stm32f4xx.h''

#include ''stm32f4_discovery.h''

#define SLAVE_ADDRESS 0xA0 

/* Private variables */

uint8_t received_data[2];

uint8_t I2C_read_ack(I2C_TypeDef* I2Cx);

uint8_t I2C_read_nack(I2C_TypeDef* I2Cx);

/* Private function prototypes */

void init_I2C1(void);

void I2C_start(I2C_TypeDef* I2Cx, uint8_t address, uint8_t direction);

void I2C_write(I2C_TypeDef* I2Cx, uint8_t data);

void I2C_stop(I2C_TypeDef* I2Cx);

/**

**===========================================================================

**

**  Abstract: main program

**

**===========================================================================

*/

int main(void)

{

init_I2C1(); // initialize I2C peripheral

while(1)

{

I2C_start(I2C1, SLAVE_ADDRESS<<1, I2C_Direction_Transmitter); // start a transmission in Master transmitter mode

I2C_write(I2C1, 0x20); // write one byte to the slave

I2C_write(I2C1, 0x03); // write another 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[0] = I2C_read_ack(I2C1); // read one byte and request another byte

received_data[1] = I2C_read_nack(I2C1); // read one byte and don't request another byte, stop transmission

}

}

void init_I2C1(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 I2C1 to two different

* pairs of pins:

* 1. SCL on PB6 and SDA on PB7

* 2. SCL on PB8 and SDA on PB9

*/

GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7; // 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_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);

}

void I2C_start(I2C_TypeDef* I2Cx, uint8_t address, uint8_t direction)

{

//I2C_ClearFlag(I2Cx, I2C_FLAG_BUSY);

// wait until I2C1 is not busy anymore

while(I2C_GetFlagStatus(I2Cx, I2C_FLAG_BUSY));

// Send I2C1 START condition

I2C_GenerateSTART(I2Cx, ENABLE);

// wait for I2C1 EV5 --> Slave has acknowledged start condition

while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_MODE_SELECT));

// Send slave Address for write

I2C_Send7bitAddress(I2Cx, address, direction);

/* wait for I2C1 EV6, check if

* either Slave has acknowledged Master transmitter or

* Master receiver mode, depending on the transmission

* direction

*/

if(direction == I2C_Direction_Transmitter)

{

while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));

He stuck here

}

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)

{

I2C_SendData(I2Cx, data);

// wait for I2C1 EV8_2 --> byte has been transmitted

while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED));

}

/* This function reads one byte from the slave device

 * and acknowledges the byte (requests another byte)

 */

uint8_t I2C_read_ack(I2C_TypeDef* I2Cx)

{

// enable acknowledge of recieved 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

uint8_t data = I2C_ReceiveData(I2Cx);

return data;

}

/* This function reads one byte from the slave device

 * and doesn't acknowledge the recieved data

 */

uint8_t I2C_read_nack(I2C_TypeDef* I2Cx)

{

// disabe 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

uint8_t data = I2C_ReceiveData(I2Cx);

return data;

}

/* This funtion issues a stop condition and therefore

 * releases the bus

 */

void I2C_stop(I2C_TypeDef* I2Cx)

{

// Send I2C1 STOP Condition

I2C_GenerateSTOP(I2Cx, ENABLE);

}

10 REPLIES 10
stm322399
Senior
Posted on April 02, 2014 at 17:20

Oh, lucky you are, I just tumbled on the following:

static uint8_t I2C_read8(uint8_t regnum)
{
int maxloop = 1000000;
uint8_t value;
I2C_GenerateSTART(I2C1, ENABLE);
while ( I2C_GetFlagStatus(I2C1, I2C_FLAG_SB) == RESET ) if (!maxloop--) goto error;
I2C_Send7bitAddress(I2C1, IOEXP_ADDR*2, I2C_Direction_Transmitter);
while ( I2C_GetFlagStatus(I2C1, I2C_FLAG_ADDR) == RESET ) if (!maxloop--) goto error;
I2C_GetFlagStatus(I2C1, I2C_FLAG_MSL);
while ( I2C_GetFlagStatus(I2C1, I2C_FLAG_TXE) == RESET ) if (!maxloop--) goto error;
I2C_SendData(I2C1, regnum);
I2C_AcknowledgeConfig(I2C1, DISABLE);
I2C_GenerateSTART(I2C1, ENABLE);
while ( I2C_GetFlagStatus(I2C1, I2C_FLAG_SB) == RESET ) if (!maxloop--) goto error;
I2C_Send7bitAddress(I2C1, IOEXP_ADDR*2, I2C_Direction_Receiver);
while ( I2C_GetFlagStatus(I2C1, I2C_FLAG_ADDR) == RESET ) if (!maxloop--) goto error;
I2C_GetFlagStatus(I2C1, I2C_FLAG_MSL);
while ( I2C_GetFlagStatus(I2C1, I2C_FLAG_RXNE) == RESET ) if (!maxloop--) goto error;
value = I2C_ReceiveData(I2C1);
I2C_GenerateSTOP(I2C1, ENABLE);
while ( I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY) == SET ) if (!maxloop--) goto error;
return value;
error:
LOG_ERROR();
return 0;
}

Beware that this routine is a special case for reading a single byte only.

static uint16_t I2C_read16(uint8_t regnum)
{
int maxloop = 1000000;
uint8_t valueL, valueH;
I2C_GenerateSTART(I2C1, ENABLE);
while ( I2C_GetFlagStatus(I2C1, I2C_FLAG_SB) == RESET ) if (!maxloop--) goto error;
I2C_Send7bitAddress(I2C1, IOEXP_ADDR*2, I2C_Direction_Transmitter);
while ( I2C_GetFlagStatus(I2C1, I2C_FLAG_ADDR) == RESET ) if (!maxloop--) goto error;
I2C_GetFlagStatus(I2C1, I2C_FLAG_MSL);
while ( I2C_GetFlagStatus(I2C1, I2C_FLAG_TXE) == RESET ) if (!maxloop--) goto error;
I2C_SendData(I2C1, regnum);
I2C_AcknowledgeConfig(I2C1, DISABLE);
I2C_GenerateSTART(I2C1, ENABLE);
while ( I2C_GetFlagStatus(I2C1, I2C_FLAG_SB) == RESET ) if (!maxloop--) goto error;
I2C_Send7bitAddress(I2C1, IOEXP_ADDR*2, I2C_Direction_Receiver);
while ( I2C_GetFlagStatus(I2C1, I2C_FLAG_ADDR) == RESET ) if (!maxloop--) goto error;
I2C1->CR1 |= I2C_CR1_POS;
I2C_GetFlagStatus(I2C1, I2C_FLAG_MSL);
while ( I2C_GetFlagStatus(I2C1, I2C_FLAG_RXNE) == RESET ) if (!maxloop--) goto error;
valueL = I2C_ReceiveData(I2C1);
while ( I2C_GetFlagStatus(I2C1, I2C_FLAG_RXNE) == RESET ) if (!maxloop--) goto error;
valueH = I2C_ReceiveData(I2C1);
I2C_GenerateSTOP(I2C1, ENABLE);
while ( I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY) == SET ) if (!maxloop--) goto error;
return valueL | (valueH<<8);
error:
LOG_ERROR();
return 0;
}

Reading 2 byte is again a special case. To read N>2 bytes, you just need to set ACK before the first reception, and clear ACK at the N-1 received byte (see previous post)