cancel
Showing results for 
Search instead for 
Did you mean: 

Problem with data transfer between 2 MCUs via I2C

GKlim
Associate II

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;
	}
}

.

3 REPLIES 3
AvaTar
Lead

> 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.

S.Ma
Principal

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.

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