cancel
Showing results for 
Search instead for 
Did you mean: 

My I2C is very slow, need help :)

jean_prieur
Associate III
Posted on February 18, 2015 at 12:42

Hello everybody,

I have a problem with I2C on STM32F4 I communicate with a touchpad controller: everything is OK, I can configure this I2C controller and get its datas. But when I communicate it takes a lot of time and I can see my uC slowing down. It's strange because I don't send it a lot of datas and it don't send me a lot of datas. And the I2C clock speed is 400kHz. And even sometimes the communication freeze my program... I attached my code below, can you please advise me on what going wrong? Thanks a lot and have a good day! I2C DRIVER:

/* Direction = I2C_Direction_Transmitter or I2C_Direction_Receiver */
void
I2C1_Repeated_Start(uint8_t direction)
{
// Send I2C1 START condition
I2C_GenerateSTART(I2C1, ENABLE);
// wait for I2C1 EV5 --> Slave has acknowledged start condition
while
(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));
// Clear flag
I2C_ClearFlag(I2C1, I2C_FLAG_AF);
// Send slave Address for write
I2C_Send7bitAddress(I2C1, TP_ADRESS<<1, direction);
if
(direction == I2C_Direction_Transmitter)
{
while
(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
}
else
if
(direction == I2C_Direction_Receiver)
{
while
(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));
}
}
/* Direction = I2C_Direction_Transmitter or I2C_Direction_Receiver */
void
I2C1_Start(uint8_t direction)
{
// wait until I2C1 is not busy anymore
while
(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY));
// Send I2C1 START condition
I2C_GenerateSTART(I2C1, ENABLE);
// wait for I2C1 EV5 --> Slave has acknowledged start condition
while
(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));
// Clear flag
I2C_ClearFlag(I2C1, I2C_FLAG_AF);
// Send slave Address for write
I2C_Send7bitAddress(I2C1, TP_ADRESS<<1, 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(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
}
else
if
(direction == I2C_Direction_Receiver)
{
while
(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));
}
}
void
I2C1_Stop(
void
)
{
// Send I2C1 STOP Condition
I2C_GenerateSTOP(I2C1, ENABLE);
// Clear flag
I2C_ClearFlag(I2C1, I2C_FLAG_AF);
}
void
I2C1_Wr(uint8_t data)
{
I2C_SendData(I2C1, data);
// wait for I2C1 EV8_2 --> byte has been transmitted
while
(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
// Clear flag
I2C_ClearFlag(I2C1, I2C_FLAG_AF);
}
uint8_t I2C1_Read_Ack(
void
)
{
// enable acknowledge of recieved data
I2C_AcknowledgeConfig(I2C1, ENABLE);
// wait until one byte has been received
while
( !I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED) );
// read data from I2C data register and return data byte
uint8_t data = I2C_ReceiveData(I2C1);
// Clear flag
I2C_ClearFlag(I2C1, I2C_FLAG_AF);
return
data;
}
uint8_t I2C1_Read(
void
)
{
// enable acknowledge of recieved data
I2C_AcknowledgeConfig(I2C1, DISABLE);
// wait until one byte has been received
while
( !I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED));
// read data from I2C data register and return data byte
uint8_t data = I2C_ReceiveData(I2C1);
// Clear flag
I2C_ClearFlag(I2C1, I2C_FLAG_AF);
return
data;
}

CALCULATE FINGER POSITION:

void
CALCULATE_POSITION(
void
)
{
I2C1_Start(I2C_Direction_Transmitter); 
// Communication started
I2C1_Wr(0x01); 
// Send data address
I2C1_Repeated_Start(I2C_Direction_Receiver); 
// Issue repeated start signal
info = I2C1_Read_Ack(); 
// Read the data (01 Info Byte)
if
(info > 128){ 
// If there are any active coordinates, read all the bytes
// Touch 1
ID_1 = I2C1_Read_Ack(); 
// Read the data (02 ID 1)
x_h_1 = I2C1_Read_Ack(); 
// Read the data (03 X 1 High Byte)
x_l_1 = I2C1_Read_Ack(); 
// Read the data (04 X 1 Low Byte)
y_h_1 = I2C1_Read_Ack(); 
// Read the data (05 Y 1 High Byte)
y_l_1 = I2C1_Read_Ack();
t_h_1 = I2C1_Read_Ack(); 
// Read the data (07 Touch Strength 1 High Byte)
t_l_1 = I2C1_Read(); 
// Read the data (08 Touch Strength 1 Low Byte)
I2C1_Stop(); 
// Close communication window
}
}

3 REPLIES 3
Posted on February 18, 2015 at 14:01

Perhaps a more state-full implementation that doesn't spend all it's time in while() loops.

Suggest you profile the code an figure where it's burning all your time.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
jean_prieur
Associate III
Posted on February 18, 2015 at 14:58

Thanks Clive1,

To remove the while() loops I need to use I2C interrupts isn't it ?

I have troubles to find on the internet a simple communication example with interrupts. I imagine that the function 

I2C1_EV_IRQHandler

is called at each interrupt, and inside I can get the last I2C event, and depending on the event (e.g.

I2C_EVENT_MASTER_MODE_SELECT

 or

I2C_FLAG_BUSY

) I can launch the according action?

Seems a little bit complicated, is there an easier way to use interrups?

Thanks!

Posted on February 18, 2015 at 15:07

Well I guess you could use threads and yield.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..