2015-01-07 03:51 AM
I am trying to use the I2C peripheral on the STM32 I am finding that about half the time the address isn't being sent. What happens is that the data line is going low (start condition is set) the clock line goes low then high without any clock pulses then the data line is going high (stop condition). Other times communication works successfully.
Code: (Peripheral clock enable and GPIO configuration is handled elsewhere)uint8 Address;
uint8 * Data;
uint8 DataNumBytes;
uint8 CurrentDataPosition;
void
i2cInitialise(
void
)
{
/* Set frequency system clock is running at. */
I2C_MODULE(1)->CR2 &= ~I2C_CR2_FREQ_MSK;
I2C_MODULE(1)->CR2 |= I2C_CR2_FREQ(24);
/* Set as fast mode */
I2C_MODULE(1)->CCR |= I2C_CCR_FS;
/* Set duty cycle */
I2C_MODULE(1)->CCR |= I2C_CCR_DUTY;
/* Configure clock frequency to ~100khz */
I2C_MODULE(1)->CCR &= ~I2C_CCR_CCR_MSK;
I2C_MODULE(1)->CCR |= I2C_CCR_CCR(9);
/* Configure maximum rise time to 300ns */
I2C_MODULE(1)->TRISE = I2C_TRISE_TRISE(8);
/* Enable Interrupts */
I2C_MODULE(1)->CR2 |= I2C_CR2_ITEVTEN;
I2C_MODULE(1)->CR2 |= I2C_CR2_ITERREN;
I2C_MODULE(1)->CR2 |= I2C_CR2_ITBUFEN;
/* Enable peripheral. */
I2C_MODULE(1)->CR1 |= I2C_CR1_PE;
}
void
i2cSendDataPacket(uint8 address, uint8 * data, uint8 dataNumBytes)
{
/* Record data to be transmitted */
Address = address;
Data = data;
DataNumBytes = dataNumBytes;
CurrentDataPosition = 0;
/* Set start condition */
I2C_MODULE(1)->CR1 |= I2C_CR1_START;
}
void
I2C2_EV_IRQHandler(
void
)
{
int32 statusRegister1 = 0;
int32 statusRegister2 = 0;
/* Read SR1 register - this is needed to clear event flags */
statusRegister1 = I2C_MODULE(1)->SR1;
if
(statusRegister1 & I2C_SR1_SB)
/* Start condition has been set */
{
/* Write address to DR */
I2C_MODULE(1)->DR = Address;
}
else
if
(statusRegister1 & I2C_SR1_ADDR)
/* Address has been sent */
{
/* Read SR2 register - this is needed to clear address sent flag */
statusRegister2 = I2C_MODULE(1)->SR2;
/* Send data */
I2C_MODULE(1)->DR = Data[CurrentDataPosition];
CurrentDataPosition++;
}
else
if
(statusRegister1 & I2C_SR1_TxE)
{
if
(CurrentDataPosition < DataNumBytes)
{
/* Send data */
I2C_MODULE(1)->DR = Data[CurrentDataPosition];
CurrentDataPosition++;
}
else
{
/* Set stop condition */
I2C_MODULE(1)->CR1 |= I2C_CR1_STOP;
}
}
}
#i2c #stm32f100 #i2c #stm32f100
2015-01-07 07:09 AM
I have accidentally come across a solution. While trying to solve the problem I added quite a few debug variables into the code to try to understand what was going wrong. Communication then started working reliably. For some reason adding a delay before leaving the interrupt routine helps to stabilise the communication. I did notice that there is a final interrupt after the stop condition is set where SR1 is actually empty. If this interrupt doesn't happen the chances are that the next transmission will fail. My adjusted code is below.
uint8 Address;
uint8 * Data;
uint8 DataNumBytes;
uint8 CurrentDataPosition;
void
i2cInitialise(
void
)
{
/* Set frequency system clock is running at. */
I2C_MODULE(1)->CR2 &= ~I2C_CR2_FREQ_MSK;
I2C_MODULE(1)->CR2 |= I2C_CR2_FREQ(24);
/* Set as fast mode */
I2C_MODULE(1)->CCR |= I2C_CCR_FS;
/* Set duty cycle */
I2C_MODULE(1)->CCR |= I2C_CCR_DUTY;
/* Configure clock frequency to ~100khz */
I2C_MODULE(1)->CCR &= ~I2C_CCR_CCR_MSK;
I2C_MODULE(1)->CCR |= I2C_CCR_CCR(9);
/* Configure maximum rise time to 300ns */
I2C_MODULE(1)->TRISE = I2C_TRISE_TRISE(8);
/* Enable Interrupts */
I2C_MODULE(1)->CR2 |= I2C_CR2_ITEVTEN;
I2C_MODULE(1)->CR2 |= I2C_CR2_ITERREN;
I2C_MODULE(1)->CR2 |= I2C_CR2_ITBUFEN;
/* Enable peripheral. */
I2C_MODULE(1)->CR1 |= I2C_CR1_PE;
}
void
i2cSendDataPacket(uint8 address, uint8 * data, uint8 dataNumBytes)
{
/* Record data to be transmitted */
Address = address;
Data = data;
DataNumBytes = dataNumBytes;
CurrentDataPosition = 0;
/* Set start condition */
I2C_MODULE(1)->CR1 |= I2C_CR1_START;
}
void
I2C2_EV_IRQHandler(
void
)
{
int32 delay = 0;
int32 statusRegister1 = 0;
int32 statusRegister2 = 0;
/* Read SR1 register - this is needed to clear event flags */
statusRegister1 = I2C_MODULE(1)->SR1;
if
(statusRegister1 & I2C_SR1_SB)
/* Start condition has been set */
{
/* Write address to DR */
I2C_MODULE(1)->DR = Address;
}
else
if
(statusRegister1 & I2C_SR1_ADDR)
/* Address has been sent */
{
/* Read SR2 register - this is needed to clear address sent flag */
statusRegister2 = I2C_MODULE(1)->SR2;
/* Send data */
I2C_MODULE(1)->DR = Data[CurrentDataPosition];
CurrentDataPosition++;
}
else
if
(statusRegister1 & I2C_SR1_TxE)
{
if
(CurrentDataPosition < DataNumBytes)
{
/* Send data */
I2C_MODULE(1)->DR = Data[CurrentDataPosition];
CurrentDataPosition++;
}
else
{
/* Set stop condition */
I2C_MODULE(1)->CR1 |= I2C_CR1_STOP;
delay++;
delay++;
delay++;
}
}
}