2014-03-26 08:10 AM
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 beThanks for your helpHere 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);}2014-03-26 08:24 AM
I'am pretty sure that you don't need to shift the address 1 bit left when you call I2C_start. Your address (0xA0) look to be already shifted (otherwise the additional shift will throw the MSbit out of the argument).
2014-03-26 08:38 AM
I removed the shift but It stuck in the function ''I2C_CheckEvent'' and put the status in ERROR.
ErrorStatus I2C_CheckEvent(I2C_TypeDef* I2Cx, uint32_t I2C_EVENT){ uint32_t lastevent = 0; uint32_t flag1 = 0, flag2 = 0; ErrorStatus status = ERROR; /* Check the parameters */ assert_param(IS_I2C_ALL_PERIPH(I2Cx)); assert_param(IS_I2C_EVENT(I2C_EVENT)); /* Read the I2Cx status register */ flag1 = I2Cx->SR1; flag2 = I2Cx->SR2; flag2 = flag2 << 16; /* Get the last event value from I2C status register */ lastevent = (flag1 | flag2) & FLAG_MASK; /* Check whether the last event contains the I2C_EVENT */ if ((lastevent & I2C_EVENT) == I2C_EVENT) { /* SUCCESS: last event is equal to I2C_EVENT */ status = SUCCESS; } else { /* ERROR: last event is different from I2C_EVENT */status = ERROR;
} /* Return status */ return status;}2014-03-26 08:55 AM
So the I2C controller does not end in the state you expect. Can you tell us the values of SR1 and SR2, so we can check what's going wrong ?
2014-03-27 05:12 AM
If you have access to one :
Look at the I2C waveforms on an Oscilloscope or logic analyser.2014-03-28 01:38 AM
Now the program look like write in the memory because the functions ''I2C_write'' are running but after it remains in the function ''I2C_read_nack(I2C1)'' and SR1 and SR2 are 0
int main(void){ init_I2C1(); // initialize I2C peripheral while(1) { I2C_start(I2C1, SLAVE_ADDRESS, I2C_Direction_Transmitter);OK
I2C_write(I2C1, 0x00);
OK
I2C_write(I2C1, 0x03);
OK
I2C_stop(I2C1);
OK
I2C_start(I2C1, SLAVE_ADDRESS, I2C_Direction_Receiver);
OK
received_data[0] = I2C_read_ack(I2C1);
OK
received_data[1] = I2C_read_nack(I2C1);Loop here
I2C_stop(I2C1); }}2014-03-28 02:09 AM
I2C Master reception is not the easiest part to code, and the way you did it does not look the good one to me.
Basically, I2C reception starts as soon as you acknowledged the address (event I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED). The RM says that you must prepare the I2C controller for reception *before* this step, in particular when you expect to read only 1 or 2 bytes. In other words, I2C_start is likely to be modified because it behave differently in function of the data direction and the number of bytes to exchange. Look at the reference manual section 27.3.3, and pay special attention to what it say under ''Master Receiver'' and ''For 2-byte reception''. The procedure is clearly depicted and should work for you.2014-03-28 08:46 AM
Thanks, I will check
2014-04-02 07:38 AM
to be migrated, sourceId: 40192:697285D7-A9CA-445D-B16C-F23BF0E3B1A3
2014-04-02 08:08 AM
I do not have any code sample for a simple example, but I am pretty sure that there exists a lot of them, and maybe from this forum.
Below is the sequence of operations performed by an I2C driver that uses interrupt. To help you using this code without interrupts I put in comment the flag you must wait to go the next step:I2C->CR1 = I2C_CR1_START | I2C_CR1_PE;
// Wait here for I2C_SR1_SB to be set
I2C_Send7bitAddress(port->i2c, SLAVE_ADDR<<
1
, I2C_Direction_Transmitter);
// Wait here for I2C_SR1_ADDR to be set
I2C_GetFlagStatus(port->i2c, I2C_FLAG_MSL);
// Wait here for I2C_SR1_TXE to be set
I2C_SendData(port->i2c, 0x9A);
I2C->CR1 = I2C_CR1_START | I2C_CR1_PE;
// Wait here for I2C_SR1_SB to be set
I2C_Send7bitAddress(port->i2c, SLAVE_ADDR<<
1
, I2C_Direction_Receiver);
// Wait here for I2C_SR1_ADDR to be set
I2C->CR1 = I2C_CR1_PE | I2C_CR1_ACK;
I2C_GetFlagStatus(port->i2c, I2C_FLAG_MSL);
// Wait here for I2C_SR1_RXNE to be set
rxbyte[0] = I2C_ReceiveData(port->i2c);
// Wait here for I2C_SR1_RXNE to be set
rxbyte[1] = I2C_ReceiveData(port->i2c);
I2C->CR1 = I2C_CR1_PE | I2C_CR1_STOP;
// Wait here for I2C_SR1_RXNE to be set
rxbyte[2] = I2C_ReceiveData(port->i2c);
I2C->CR1 = 0;
Normally you should succeed in reading those 3 bytes from your device. Note that I assumed that your device has an internal auto-incrementing address for reading those bytes.