Skip to main content
GKlim
Associate II
March 19, 2019
Question

Problem with data transfer between 2 MCUs via I2C

  • March 19, 2019
  • 2 replies
  • 838 views

Hello, dear collegues!

Please help me with I2C!

I use I2C to transfer data between 2 controllers: STM32F051C8T6(Master) and STM32F100C8T6 (Slave). When I use laboratory power supply, it works without some problems. But when I use external power supply based on the pulse transformer, it does not work. Program stops in some infinitie loop and waits for some flag.

Please, help with this problem!

My code is bellow!

//for transmiting
 
uint16_t Load_FROM_Single (uint8_t word_number)
{
uint8_t msb;
uint8_t lsb;
uint16_t retval;
 
I2C_10BitAddressingModeCmd(I2C1,DISABLE);
I2C_SlaveAddressConfig(I2C1,25); 
I2C1->CR2&= ~I2C_CR2_RD_WRN; 
I2C_NumberOfBytesConfig(I2C1,1);
I2C_AutoEndCmd(I2C1,DISABLE); 
 
I2C_GenerateSTART(I2C1,ENABLE); 
 
int timeout=0;
while((!I2C_GetFlagStatus(I2C1,I2C_FLAG_TXIS))&&( timeout!=1000))
{
timeout++;
}
if (timeout==1000) {
	I2C_DeInit(I2C1);
	Simple_Delay(100);
	I2C1_Init();
	Simple_Delay(100);
	return 0;
}
timeout=0;
I2C_SendData(I2C1,word_number);
while((!I2C_GetFlagStatus(I2C1,I2C_FLAG_TC))&&( timeout!=1000)) //Передача закончена - вы�?тавил�?�? бит TC в реги�?тре ISR
{
timeout++;
}
if (timeout==1000) {
	I2C_DeInit(I2C1);
	Simple_Delay(100);
	I2C1_Init();
	Simple_Delay(100);
	return 0;
}
timeout=0;
I2C_GenerateSTOP(I2C1,ENABLE); 
I2C_GenerateSTOP(I2C1,DISABLE);
I2C_ClearFlag(I2C1,I2C_FLAG_STOPF);
 
 
I2C1->CR2|=I2C_CR2_RD_WRN; 
I2C_NumberOfBytesConfig(I2C1,2);
I2C_AcknowledgeConfig(I2C1,ENABLE);
 
I2C_GenerateSTART(I2C1,ENABLE); 
 
while((!I2C_GetFlagStatus(I2C1,I2C_FLAG_RXNE))&&( timeout!=1000))
{
timeout++;
}
if (timeout==1000) {
	I2C_DeInit(I2C1);
	Simple_Delay(100);
	I2C1_Init();
	Simple_Delay(100);
	return 0;
}
timeout=0;
lsb=I2C1->RXDR;
I2C_AcknowledgeConfig(I2C1,DISABLE);
while((!I2C_GetFlagStatus(I2C1,I2C_FLAG_RXNE))&&( timeout!=1000))
{
timeout++;
}
if (timeout==1000) {
	I2C_DeInit(I2C1);
	Simple_Delay(100);
	I2C1_Init();
	Simple_Delay(100);
	return 0;
}
timeout=0;
msb=I2C1->RXDR;
while((!I2C_GetFlagStatus(I2C1,I2C_FLAG_TC))&&( timeout!=1000)) 
{
timeout++;
}
if (timeout==1000) {
	I2C_DeInit(I2C1);
	Simple_Delay(100);
	I2C1_Init();
	Simple_Delay(100);
	return 0;
}
timeout=0;
I2C_GenerateSTOP(I2C1,ENABLE);
I2C_GenerateSTOP(I2C1,DISABLE);
I2C_ClearFlag(I2C1,I2C_FLAG_STOPF);
retval=(msb<<8)+lsb;
return retval+1;
}
 
//for recieving
 
int Load_TO (uint16_t Pxxx_val, uint8_t Pxxx_numb)
{
	int k=0;
uint8_t msb;
uint8_t lsb;
uint8_t c=0;
 
I2C_10BitAddressingModeCmd(I2C1,DISABLE);
I2C_SlaveAddressConfig(I2C1,25);
I2C1->CR2&= ~I2C_CR2_RD_WRN; 
I2C_NumberOfBytesConfig(I2C1,3);
I2C_AutoEndCmd(I2C1,DISABLE); 
I2C_GenerateSTART(I2C1,ENABLE); 
int timeout=0;
while((!I2C_GetFlagStatus(I2C1,I2C_FLAG_TXIS))&&( timeout!=1000))
{
timeout++;
}
if (timeout==1000) {
	I2C_DeInit(I2C1);
	Simple_Delay(100);
	I2C1_Init();
	Simple_Delay(100);
	return 0;
}
timeout=0;
I2C_SendData(I2C1,Pxxx_numb);
while((!I2C_GetFlagStatus(I2C1,I2C_FLAG_TXIS))&&( timeout!=1000))
{
timeout++;
}
if (timeout==1000) {
	I2C_DeInit(I2C1);
	Simple_Delay(100);
	I2C1_Init();
	Simple_Delay(100);
	return 0;
}
timeout=0;
lsb=(uint8_t)(Pxxx_val);
I2C_SendData(I2C1,lsb);
while((!I2C_GetFlagStatus(I2C1,I2C_FLAG_TXIS))&&( timeout!=1000))
{
timeout++;
}
if (timeout==1000) {
	I2C_DeInit(I2C1);
	Simple_Delay(100);
	I2C1_Init();
	Simple_Delay(100);
	return 0;
}
timeout=0;
msb=(uint8_t)((Pxxx_val>>8));
I2C_SendData(I2C1,msb);
while((!I2C_GetFlagStatus(I2C1,I2C_FLAG_TC))&&( timeout!=1000))
{
timeout++;
}
if (timeout==1000) {
	I2C_DeInit(I2C1);
	Simple_Delay(100);
	I2C1_Init();
	Simple_Delay(100);
	return 0;
}
timeout=0;
I2C_GenerateSTOP(I2C1,ENABLE); 
I2C_GenerateSTOP(I2C1,DISABLE);
I2C_ClearFlag(I2C1,I2C_FLAG_STOPF);
return 1;
}
 
 
//On STM32F100C8T6 I use interupts
 
void I2C1_EV_IRQHandler(void) //Обработчик прерываний от I2C1 -
//
{
 
	if(I2C1->SR1&I2C_SR1_ADDR) 
	{
 
	I2C1->SR1;
	I2C1->SR2;
	 b=1;
	}
	if(I2C1->SR1&I2C_SR1_RXNE)
	{
		switch(c)
	 {
			case 0:
			{
				a=I2C_ReceiveData(I2C1);
				c++;
				break;
			}
			case 1:
	 	{
	 		lsb=I2C_ReceiveData(I2C1);
	 	 c++;
	 	 break;
	 	}
	 	case 2:
	 	{
	 	 msb=I2C_ReceiveData(I2C1);
	 	 i[a]=(msb<<8)+lsb;
	 	 c=0;
	 	 a=0;
	 	 msb=0;
	 	 lsb=0;
	 	 break;
	 	}
	 }
	}
	if((I2C1->SR1&I2C_SR1_TXE)&&(b==1))
	{
		switch (c)
	 {
	 	case 0: 
	 	{
	 		lsb=(uint8_t)((i[a])); 
	 		I2C_SendData(I2C1,lsb); 
	 	 c++;
	 		break;
	 	}
	 	case 1: 
	 	{
	 	 msb=(uint8_t)((i[a]>>8));
	 	 I2C_SendData(I2C1,msb);
	 	 c=0; 
	 	 a=a+1;
	 	 break;
	 	}
	 }
	}
	if((I2C1->SR1&I2C_SR1_AF)) 
	{
		I2C1->CR1=I2C1->CR1;
		I2C1->SR1&= ~I2C_SR1_AF;
		c=0;//Сбра�?ываем �?четчик
		a=0;
	}
	if(I2C1->SR1&I2C_SR1_STOPF)
	{
		//i[2*n-1]=I2C_ReceiveData(I2C1);//Сохранили по�?ледний прин�?тый байт
		I2C1->CR1=I2C1->CR1;
		I2C1->SR1&= ~I2C_SR1_AF;//Сбро�? флага
		c=0;
	}
	if(a==n)
	{
		a=0;
		b=0;
	}
}

.

    This topic has been closed for replies.

    2 replies

    AvaTar
    Senior III
    March 19, 2019

    > When I use laboratory power supply, it works without some problems. But when I use external power supply based on the pulse transformer, it does not work.

    That points to your power supply as culprit.

    > Program stops in some infinitie loop and waits for some flag.

    I suspect EMI causes noise/pulses on the I2C lines, and the devices catch false clock signals.

    I would suggest to check for noise/ripple at the supply lines, and improve decoupling. Perhaps also decrease I2C pull-up resistor values.

    GKlim
    GKlimAuthor
    Associate II
    March 19, 2019

    Currently 4.7K resistors are mounted, according to datasheet. Which value could I use instead? I don't quait understand how it improve transmition.

    S.Ma
    Principal
    March 19, 2019

    Yep, monitor with oscilloscope mcu vdd, sda and scl. Check the pull up resistor values. Probe close to each stm32 ground. Add to your code a simple check that verify that both sda and scl are high level before master communicates. This way you can breakpoint and catch what happens on the bus witg oscilloscope.