STM32F103RB and I2C interface
Hi all,
using the STEVAL-PCC009V2 demo board I've connected an external EEPROM 24LC02 to this board by means of the I2C1 peripheral through the lines PB6 (SCL) and PB7 (SDA), these lines are available through the connector J2 (30 pin connectors on board).
I'm based on some code found over the net and adapted it to my microcontroller (STM32F103RBT6) and peripheral (I2C1).
For your reference here below the code that I've used to perform the peripheral init, byte read, byte write and multiple byte write task.
The following defeine is used for timout checking purpose:
#define I2C_TIMEOUT_MAX 100000Here below the peripheral initialization procedure, to be called before doing any operation through the I2C port.
void I2C_Memory_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
I2C_InitTypeDef I2C_InitStruct;
// Enable APB1 clock and peripheral
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO,ENABLE);
// SCL and SDA pins config
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_OD;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStruct);
GPIO_PinRemapConfig(GPIO_Remap_I2C1,DISABLE);
I2C_DeInit(I2C1);
// I2C1 config
I2C_InitStruct.I2C_Mode = I2C_Mode_I2C;
I2C_InitStruct.I2C_DutyCycle = I2C_DutyCycle_2;
I2C_InitStruct.I2C_OwnAddress1 = 0x00;
I2C_InitStruct.I2C_Ack = I2C_Ack_Disable;
I2C_InitStruct.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
I2C_InitStruct.I2C_ClockSpeed = 100000; // Hz
I2C_Init(I2C1, &I2C_InitStruct);
I2C_Cmd(I2C1, ENABLE);
}then for reading a byte:
int I2C_Memory_Read(I2C_TypeDef* I2Cx, uint8_t address)
{
uint32_t timeout = I2C_TIMEOUT_MAX;
uint8_t Data = 0;
I2C_GenerateSTART(I2Cx, ENABLE);
timeout = I2C_TIMEOUT_MAX;
while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_MODE_SELECT))
{
if ((timeout--) == 0) return -1;
}
I2C_Send7bitAddress(I2Cx, 0xA0, I2C_Direction_Transmitter);
timeout = I2C_TIMEOUT_MAX;
while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED))
{
if ((timeout--) == 0) return -1;
}
I2C_SendData(I2Cx, address);
timeout = I2C_TIMEOUT_MAX;
while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED))
{
if ((timeout--) == 0) return -1;
}
I2C_GenerateSTART(I2Cx, ENABLE);
timeout = I2C_TIMEOUT_MAX;
while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_MODE_SELECT))
{
if ((timeout--) == 0) return -1;
}
I2C_Send7bitAddress(I2Cx, 0xA0, I2C_Direction_Receiver);
timeout = I2C_TIMEOUT_MAX;
while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED))
{
if ((timeout--) == 0) return -1;
}
I2C_AcknowledgeConfig(I2Cx, DISABLE);
timeout = I2C_TIMEOUT_MAX;
while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_RECEIVED))
{
if ((timeout--) == 0) return -1;
}
I2C_GenerateSTOP(I2Cx, ENABLE);
Data = I2C_ReceiveData(I2Cx);
return Data;
}For writing a single byte:
int I2C_Memory_Write(I2C_TypeDef* I2Cx, uint8_t address, uint8_t data)
{
uint32_t timeout = I2C_TIMEOUT_MAX;
I2C_GenerateSTART(I2Cx, ENABLE);
timeout = I2C_TIMEOUT_MAX;
while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_MODE_SELECT))
{
if ((timeout--) == 0) return -1;
}
I2C_Send7bitAddress(I2Cx, 0xA0, I2C_Direction_Transmitter); // Control Byte 0xA0
timeout = I2C_TIMEOUT_MAX;
while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED))
{
if ((timeout--) == 0) return -1;
}
I2C_SendData(I2Cx, address);
timeout = I2C_TIMEOUT_MAX;
while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED))
{
if ((timeout--) == 0) return -1;
}
I2C_SendData(I2Cx, data);
timeout = I2C_TIMEOUT_MAX;
while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED))
{
if ((timeout--) == 0) return -1;
}
I2C_GenerateSTOP(I2Cx, ENABLE);
return 0;
}To perform a multiple byte writing sequence you have to write the control byte, the address and then the bytes in sequence, after the last one byte you have to generate the STOP bit to instruct the EEPROM to start the writing task, so with a simple modification of the basic write function by means of an array and a counter of the bytes to transmit also this task is easy to do.
int I2C_Memory_Write_Bytes(I2C_TypeDef* I2Cx, uint8_t address, uint8_t data[], uint8_t ndata)
{
uint8_t index = 0;
uint32_t timeout = I2C_TIMEOUT_MAX;
I2C_GenerateSTART(I2Cx, ENABLE);
timeout = I2C_TIMEOUT_MAX;
while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_MODE_SELECT))
{
if ((timeout--) == 0) return -1;
}
I2C_Send7bitAddress(I2Cx, 0xA0, I2C_Direction_Transmitter);
timeout = I2C_TIMEOUT_MAX;
while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED))
{
if ((timeout--) == 0) return -1;
}
I2C_SendData(I2Cx, address);
timeout = I2C_TIMEOUT_MAX;
while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED))
{
if ((timeout--) == 0) return -1;
}
// Send ndata bytes stored inside the data[] array
for (index = 0; index<ndata; index++)
{
I2C_SendData(I2Cx, data[index]);
timeout = I2C_TIMEOUT_MAX;
while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED))
{
if ((timeout--) == 0) return -1;
}
}
// STOP bit generation to end the transmission and start the writing task inside the EEPROM
I2C_GenerateSTOP(I2Cx, ENABLE);
return 0;
}Hope it can help.
Best regards
Fabio
