Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

I2C problem on STM32 (can't generate a start)

Status
Not open for further replies.

nicklasp

Newbie level 4
Joined
Mar 5, 2012
Messages
5
Helped
1
Reputation
2
Reaction score
1
Trophy points
1,283
Activity points
1,330
Hi!
I am new to this forum and seeking help. I am working on a PMBus compliance tester. PMBus extends SMBus which extends the I2C bus. :cool:

I think I have initialized the I2C peripheral on a STM32F103ZE correct. However, I cannot generate a start condition. I am using pull-up resistors and the signals is high all the time.

This is my code:
Code:
   unsigned int dier;
   unsigned short cnt;
   unsigned short tmpreg = 0;
   unsigned short freqrange = 0;
   unsigned short result = 0;

   /* Enable periphereal clocks */
   RCC->APB2ENR |= RCC_APB2ENR_IOPBEN;
   RCC->APB2ENR |= RCC_APB2ENR_AFIOEN;
   RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;
   RCC->APB1ENR |= RCC_APB1ENR_I2C1EN;

   /* Pin: Alternate function, open drain */
   GPIOB->CRL |= (GPIO_CRL_CNF6_0  |
                  GPIO_CRL_CNF6_1  |
                  GPIO_CRL_CNF7_0  |
                  GPIO_CRL_CNF7_1  |
                  GPIO_CRL_CNF5_0  |
                  GPIO_CRL_CNF5_1  |
                  GPIO_CRL_MODE5_0 | 
                  GPIO_CRL_MODE5_1 | 
                  GPIO_CRL_MODE6_0 | 
                  GPIO_CRL_MODE6_1 | 
				      GPIO_CRL_MODE7_0 | 
				      GPIO_CRL_MODE7_1 );  

   /* Enable I2C1 reset state */
   RCC->APB1RSTR |= RCC_APB1RSTR_I2C1RST;  
   /* Release I2C1 from reset state */
   RCC->APB1RSTR &= ~RCC_APB1RSTR_I2C1RST;
   
   /*---------------------------- I2C1 CR2 Configuration ------------------------*/
   /* Get the I2Cx CR2 value */
   tmpreg = I2C1->CR2;
   /* Clear frequency FREQ[5:0] bits */
   tmpreg &= ((unsigned char)0xFFC0);
   /* Get pclk1 frequency value */
   RCC_GetClocksFreq(&rcc_clocks);
   pclk1 = rcc_clocks.PCLK1_Frequency;
   /* Set frequency bits depending on pclk1 value */
   freqrange = (unsigned short)(pclk1 / 1000000);
   /* Write to I2Cx CR2 */
   I2C1->CR2 = ((freqrange) | I2C_CR2_ITEVTEN | I2C_CR2_ITERREN );

   /*---------------------------- I2Cx CCR Configuration --------------------*/
   /* Disable the selected I2C peripheral to configure TRISE */
   I2C1->CR1 = 0;

   /* Reset tmpreg value */
   /* Clear F/S, DUTY and CCR[11:0] bits */
   tmpreg = 0;

   /* Configure speed in standard mode */
   result = (unsigned short)(pclk1 / (I2C_CLOCKSPEED << 1));
   /* Set speed value for standard mode */
   tmpreg |= result;	  
   /* Set Maximum Rise Time for standard mode */
   I2C1->TRISE = freqrange + 1; 
   /* Write to I2C CCR */
   I2C1->CCR = tmpreg;

   /*---------------------------- I2Cx CR1 Configuration --------------------*/
   /* Enable the selected I2C peripheral */
   I2C1->CR1 =  I2C_CR1_PE;//       | 
              //   I2C_CR1_SMBUS   | 
		        //   I2C_CR1_SMBTYPE ; 
		         //  I2C_CR1_ENPEC   |
		 		  //   I2C_CR1_ACK     );

   /*---------------------------- I2Cx OAR Configuration --------------------*/
   /* Set I2Cx Own Address1 and acknowledged address */
   I2C1->OAR1 = ((SMB_ADR_HOST << 1) + (1 << 14));

   /*---------------------------- Setup I2C IRQs ----------------------------*/
   NVIC_SetPriority(I2C1_EV_IRQn, SMB_IRQ_PRIO);
   NVIC_EnableIRQ(I2C1_EV_IRQn);
   
   NVIC_SetPriority(I2C1_ER_IRQn, SMB_IRQ_PRIO);
   NVIC_EnableIRQ(I2C1_ER_IRQn);


   /* Generates the start condition */
   I2C1->CR1 |=  I2C_CR1_START;
   /* Wait until the START condition is generated on the bus: 
      the START bit is cleared by hardware */
   while ((I2C1->CR1&0x100) == 0x100);

Now, I am stuck at the last while-loop since the start condition is never generated.
I have been working with this problem for long time now and would really need som guidance.

Here are some printscreens from the debugger:
25_1330932049.png


7_1330932049.png
 

skogsjanne

Full Member level 3
Joined
May 28, 2009
Messages
172
Helped
26
Reputation
52
Reaction score
26
Trophy points
1,308
Activity points
2,084
We needed an I2C interface and failed to get it to work. My picture of what we found in the errata was that we need DMA and highest priority interrupt to get it to work.
My memory may be wrong, but since we only need to transfer very little data we decided to bitbang the I2C interface. Much less trouble than to work around the bugs.

Maybe you need higher throughput and in that case I guess you will have to go with the hardware interface. I suspect that if you read the errata again you will find the problem.

Good luck!
 

p.luc

Junior Member level 3
Joined
Feb 7, 2012
Messages
25
Helped
8
Reputation
16
Reaction score
8
Trophy points
1,283
Activity points
1,415
Try to check the SR1 bit0 instead of CR1.
You will have a lot of problems by checking the registers that way. Try to use the latest I2C libraries from ST; functions like I2C_CheckEvent() or I2C_GetLastEvent may help.
Someone at ST screwed up the I2C controller interface big-time. You may pass through a lot of states like "sending the N-1 or N-2" bytes in master mode, etc.
I will try to google some decent code, but I see that some few uses the I2C interrupt mode in the proper way.
 

nicklasp

Newbie level 4
Joined
Mar 5, 2012
Messages
5
Helped
1
Reputation
2
Reaction score
1
Trophy points
1,283
Activity points
1,330
Try to check the SR1 bit0 instead of CR1.
You will have a lot of problems by checking the registers that way. Try to use the latest I2C libraries from ST; functions like I2C_CheckEvent() or I2C_GetLastEvent may help.
Someone at ST screwed up the I2C controller interface big-time. You may pass through a lot of states like "sending the N-1 or N-2" bytes in master mode, etc.
I will try to google some decent code, but I see that some few uses the I2C interrupt mode in the proper way.

I have tried to outcomment that line that checks the CR1 register and still no interrupt is generated and no start condition is seen on the pins.
As soon as I set the START bit a start condition should be seen on the pins and an interrupt should be generated. But nothing happens.
I have looked at configuration hundred of times and I belive that the configuration should be correct. But there is propably some detail that I have missed.
 

p.luc

Junior Member level 3
Joined
Feb 7, 2012
Messages
25
Helped
8
Reputation
16
Reaction score
8
Trophy points
1,283
Activity points
1,415
Sorry for the late answer.

If the pin is not moving you should check the other end of the I2C pins. Perhaps it's an output to 0 stretching down the line.
If it's not connected, try to configure the pin as an output and move it to exclude HW problems (you can do it directly in debug, with the keil interface you have in the screenshots).
 

nicklasp

Newbie level 4
Joined
Mar 5, 2012
Messages
5
Helped
1
Reputation
2
Reaction score
1
Trophy points
1,283
Activity points
1,330
If the pin is not moving you should check the other end of the I2C pins. Perhaps it's an output to 0 stretching down the line.

The I2C pins are not connected to anything else than the pull-up resistors so there is not another output stretching down the line.

If it's not connected, try to configure the pin as an output and move it to exclude HW problems (you can do it directly in debug, with the keil interface you have in the screenshots).
I am not sure if I understand what you mean... do you mean that there could be some problems with the I2C peripheral?
 

p.luc

Junior Member level 3
Joined
Feb 7, 2012
Messages
25
Helped
8
Reputation
16
Reaction score
8
Trophy points
1,283
Activity points
1,415
The I2C pins are not connected to anything else than the pull-up resistors so there is not another output stretching down the line.


I am not sure if I understand what you mean... do you mean that there could be some problems with the I2C peripheral?

You said that the pin is always high. There are 2 possibilities: you see the pin high because of the pull-up AND because the pin is still an input (misconfiguration, broken, etc), OR because the pin is an output and it's high.

For the first, try to set the pin as a low output and verify it goes down. If not, there is something very wrong.

Anyway, try to run some simple example from the ST library at least to check with the debugger the order of the initialization.
 

Zari44

Newbie level 1
Joined
Mar 19, 2013
Messages
1
Helped
0
Reputation
0
Reaction score
0
Trophy points
1,281
Activity points
1,298
hello, I have another problem with I2C on STM32F107VB.

I want to communicate with compass HMC5883L.
I2C initialisation:


Code C - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
void HMC5883L_I2C_Init()
{
  I2C_InitTypeDef  I2C_InitStructure;
  GPIO_InitTypeDef GPIO_InitStructure;
 
  /* Enable I2C and GPIO clocks */
  RCC_APB1PeriphClockCmd(HMC5883L_I2C_RCC_Periph, ENABLE);
  RCC_APB2PeriphClockCmd(HMC5883L_I2C_RCC_Port, ENABLE);
 
  /* Configure I2C pins: SCL and SDA */
  GPIO_InitStructure.GPIO_Pin           =  GPIO_Pin_6 | GPIO_Pin_7;
  GPIO_InitStructure.GPIO_Speed         = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode          = GPIO_Mode_AF_OD;
  GPIO_Init(HMC5883L_I2C_Port, &GPIO_InitStructure);
 
  /* I2C configuration */
  I2C_InitStructure.I2C_Mode                = I2C_Mode_I2C;
  I2C_InitStructure.I2C_DutyCycle           = I2C_DutyCycle_2;
  I2C_InitStructure.I2C_OwnAddress1         = 0x3C;
 // HMC5883L 7-bit adress = 0x1E;
  I2C_InitStructure.I2C_Ack                 = I2C_Ack_Enable;
  I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
  I2C_InitStructure.I2C_ClockSpeed          = 100000;
  
  /* Apply I2C configuration after enabling it */
  I2C_Init(I2C1, &I2C_InitStructure);
  
  I2C_Cmd(I2C1, ENABLE);
}


When I want to write a byte to my I2C slave it goes ok when I send start command. But after start when I send device write adress my code goes into inifinite loop like this:


Code C - [expand]
1
2
/* Test on EV6 and clear it */
  while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));



where I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED is ((uint32_t)0x00070082) /* BUSY, MSL, ADDR, TXE and TRA flags */

Unfotrunatelly instead of EV6 on I2C bus to occur in I2C Status registers 1 and 2 I can read:

SR2 0 _> Master Mode
SR2 1 -> Communication ongoint on the bus
SR1 10 -> ACK failure

Can anyone help me with it?
I got ready library and my slave device also worked few weeks ago on arduino.

Any ideas?
 
Last edited by a moderator:

Evgeny Soroka

Newbie level 2
Joined
Mar 5, 2014
Messages
2
Helped
0
Reputation
0
Reaction score
0
Trophy points
1
Activity points
12
I had an identical problem with STM32F429.

As insane as it sounds add a delay between this

Code:
RCC->APB1RSTR |= RCC_APB1RSTR_I2C1RST;  

[B]insert delay here. I added 10000uS delay.[/B] 

   /* Release I2C1 from reset state */
   RCC->APB1RSTR &= ~RCC_APB1RSTR_I2C1RST;

I had the same problem as you for 2 days until I realized that resetting the i2c peripheral and then turning off reset instantly does not actually reset anything. The reference manual and datasheet says absolutely nothing about this. I was extremely frustrated for days until I stumbled on to this.

If you add the delay you will see the start bit flag go high in i2c_SR1 and the interrupt I2C1_EV_IRQHandler will happen.
 

ftsolutions

Full Member level 5
Joined
Nov 19, 2009
Messages
242
Helped
71
Reputation
142
Reaction score
68
Trophy points
1,308
Location
United States
Activity points
3,707
Evgeny makes an important point - I haven't used the STM32 part, but I have observed issues with other peripherals in other vendors' ARM processors when you try to do too much and end up creating a RMW (Ready modify write) situation. In some cases, the peripheral doesn't have the time to respond to the initial bit change. In other cases, the compiler optimizes the operation so that either a cached/local copy of the hardware register's previous contents are used, or only the final results are written out. Be aware that peripheral controllers require some clock cycles of their own to process and transition to the next state reliably.
 

Evgeny Soroka

Newbie level 2
Joined
Mar 5, 2014
Messages
2
Helped
0
Reputation
0
Reaction score
0
Trophy points
1
Activity points
12
Evgeny makes an important point - I haven't used the STM32 part, but I have observed issues with other peripherals in other vendors' ARM processors when you try to do too much and end up creating a RMW (Ready modify write) situation. In some cases, the peripheral doesn't have the time to respond to the initial bit change. In other cases, the compiler optimizes the operation so that either a cached/local copy of the hardware register's previous contents are used, or only the final results are written out. Be aware that peripheral controllers require some clock cycles of their own to process and transition to the next state reliably.

Usually ST is good about warning users about these necessary delays in the reference manual, but in this case I can find no information about it. Its frustrating. Slows development time.
 

DTFT

Newbie level 6
Joined
Feb 18, 2014
Messages
11
Helped
4
Reputation
8
Reaction score
4
Trophy points
3
Activity points
79
Hi, if you still haven't figured it out, I have successfully configured the I2C on the STM32F4 before, which is similar. My code is in assembly and does not use the ST libraries, but I would be happy to post relevant functions. Let me know if you still need help.

Another suggestion in general would be to find an ST demo application such as Waveplayer that uses the I2C peripheral. That way you can make sure your hardware is not (or is) the problem.
 

babar_ali

Full Member level 3
Joined
Dec 22, 2010
Messages
150
Helped
37
Reputation
74
Reaction score
37
Trophy points
1,308
Location
Friedrichshafen, Germany
Activity points
2,088
Well here is my I2C code. Its works perfectly on stm32f407
Code:
void I2C3_init(uint32_t I2C_baudrate)
{
	I2C_InitTypeDef I2C_InitStructure;
	I2C_DeInit(I2C3); // Deinit I2C3 
	// configure I2C3 
	I2C_InitStructure.I2C_ClockSpeed 			= I2C_baudrate;		// 100kHz
	I2C_InitStructure.I2C_Mode 					= I2C_Mode_I2C;		// I2C mode
	I2C_InitStructure.I2C_DutyCycle 			= I2C_DutyCycle_2;	// 50% duty cycle --> standard
	I2C_InitStructure.I2C_OwnAddress1 			= 0x00;				// own address, not relevant in master mode
	I2C_InitStructure.I2C_Ack 					= I2C_Ack_Enable;	// Enable acknowledge when reading (can be changed later on)
	I2C_InitStructure.I2C_AcknowledgedAddress 	= I2C_AcknowledgedAddress_7bit; // set address length to 7 bit addresses
	I2C_Init(I2C3, &I2C_InitStructure);			// init I2Cx
	I2C_Cmd(I2C3, ENABLE); 	// Enable I2C3
}
void I2C_GPIO_Config()
{
	GPIO_InitTypeDef GPIO_InitStructure;
	
	//Configure the GPIO_LED pin 
	GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_3; 
	GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_OUT;
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; 
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_NOPULL;
	GPIO_Init(GPIOI, &GPIO_InitStructure);

	/* setup SCL and SDA pins
		* You can connect the I2Cx functions to two different
		* pins:
		* 1. SCL on PH7  
		* 2. SDA on PH8
	*/
	GPIO_InitStructure.GPIO_Pin 	= GPIO_Pin_7 | GPIO_Pin_8; 	// we are going to use PB6 and PB9
	GPIO_InitStructure.GPIO_Mode 	= GPIO_Mode_AF;				// set pins to alternate function
	GPIO_InitStructure.GPIO_Speed	= GPIO_Speed_50MHz;			// set GPIO speed
	GPIO_InitStructure.GPIO_OType	= GPIO_OType_OD;			// set output to open drain --> the line has to be only pulled low, not driven high
	GPIO_InitStructure.GPIO_PuPd 	= GPIO_PuPd_UP;				// enable pull up resistors
	GPIO_Init(GPIOH, &GPIO_InitStructure);	
	
	// Connect I2Cx pins to AF  
	GPIO_PinAFConfig(GPIOH, GPIO_PinSource7, GPIO_AF_I2C3);	// SCL
	GPIO_PinAFConfig(GPIOH, GPIO_PinSource8, GPIO_AF_I2C3); // SDA
}
/*===============================================================================================================*/
										/* I2C_Write_Byte */
/*===============================================================================================================*/
void I2C_Write_Byte(I2C_TypeDef* I2Cx, uint8_t reg_addr , uint8_t reg_data, uint8_t dev_Addr)
{
	//USART_SendData_s( USART3,"I2C_GetFlagStatus:\r\n");
	while(I2C_GetFlagStatus(I2Cx, I2C_FLAG_BUSY));/* While the bus is busy */

	//USART_SendData_s( USART3,"I2C_GenerateSTART:\r\n");
	I2C_GenerateSTART(I2Cx, ENABLE);/* Send I2C3 START condition */
	while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_MODE_SELECT));

	//USART_SendData_s( USART3,"Sending Device address:\r\n");
	I2C_Send7bitAddress(I2Cx, dev_Addr , I2C_Direction_Transmitter);/* Send Device slave Address for write */
	while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));

	//USART_SendData_s( USART3,"Sending register address:\r\n");
	I2C_SendData(I2Cx, reg_addr);/* Send the Device internal register address */
	while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED));

	//USART_SendData_s( USART3,"Sending Data:\r\n");
	I2C_SendData(I2Cx, reg_data);/* Send I2C3 EEPROM data */
	while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED));

	I2C_AcknowledgeConfig(I2Cx, DISABLE);/* Disable Acknowledgement */	
	Delay(1);/* Generate 12.285uS delay which is required*/
	//USART_SendData_s( DEBUG_COM,"I2C_GenerateSTOP:\r\n");
	I2C_GenerateSTOP(I2Cx, ENABLE);/* Send I2C3 STOP Condition */
	Delay(1);/* Generate 12.285uS delay which is required*/

	I2C_AcknowledgeConfig(I2Cx,ENABLE);/* Enable Acknowledgement to be ready for another reception */
}
/*===============================================================================================================*/
										/* I2C_Read_Byte */
/*===============================================================================================================*/
uint8_t I2C_Read_Byte(I2C_TypeDef* I2Cx, uint8_t reg_addr, uint8_t dev_Addr)
{
	char Red_reg;
	/*------------------------------ Start Dummy write ----------------------------------------*/

	//USART_SendData_s( DEBUG_COM,"I2C_GetFlagStatus:\r\n");
	while(I2C_GetFlagStatus(I2Cx, I2C_FLAG_BUSY));/* While the bus is busy */

	//USART_SendData_s( DEBUG_COM,"I2C_GenerateSTART:\r\n");
	I2C_GenerateSTART(I2Cx, ENABLE);/* Send I2C3 START condition */
	while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_MODE_SELECT));

	//USART_SendData_s( DEBUG_COM,"Sending Device address:\r\n");
	I2C_Send7bitAddress(I2Cx, dev_Addr, I2C_Direction_Transmitter);/* Send Device slave Address for write */
	while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));

	//USART_SendData_s( DEBUG_COM,"Sending register address:\r\n");
	I2C_SendData(I2Cx, reg_addr);/* Send the Device internal register address */
	while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED));

	/*------------------------------- Dummy write End -----------------------------------------*/
	/*------------------------------ Random Read Start ----------------------------------------*/

	//USART_SendData_s( DEBUG_COM,"Sending Repeated start:\r\n");
	I2C_GenerateSTART(I2Cx, ENABLE);/* Send STRAT condition a second time called repeated start*/
	while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_MODE_SELECT));

	//USART_SendData_s( DEBUG_COM,"Sending Device address:\r\n");
	I2C_Send7bitAddress(I2Cx, (dev_Addr | 0x01) , I2C_Direction_Receiver);/* Send Device slave Address for read */
	while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));

	/* Test on I2C3 EV7 and clear it */ /* Check for BUSY, MSL and RXNE flags =(EV7)*/
	while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_RECEIVED));

	Red_reg = I2C_ReceiveData(I2Cx);

	I2C_AcknowledgeConfig(I2Cx, DISABLE);/* Disable Acknowledgement */
	Delay(1);/* Generate 12.285uS delay which is required*/
	I2C_GenerateSTOP(I2Cx, ENABLE);/* Send I2C3 STOP Condition */
	Delay(1);/* Generate 12.285uS delay which is required*/
	//I2C_AcknowledgeConfig(I2C3,ENABLE);/* Enable Acknowledgement to be ready for another reception */

	//USART_SendData_s(USART3,"I2C read done..\r\n");	
	return Red_reg;/*Return data which is to be read from device*/
}
Enjoy!
 

richiechen

Newbie level 4
Joined
Oct 19, 2012
Messages
7
Helped
1
Reputation
2
Reaction score
1
Trophy points
1,283
Activity points
1,334
Gosh...

I am facing the same problem.. Please help!!!!
The I2C simply does not send any start...... Even at the very first cycle before address could be sent....

Best,
Richie
 

DTFT

Newbie level 6
Joined
Feb 18, 2014
Messages
11
Helped
4
Reputation
8
Reaction score
4
Trophy points
3
Activity points
79
Richie, what model STM32 are you using? Also can you post your I2C peripheral configuration code, including where you configure the peripheral clock - then we can have a look.
 

richiechen

Newbie level 4
Joined
Oct 19, 2012
Messages
7
Helped
1
Reputation
2
Reaction score
1
Trophy points
1,283
Activity points
1,334
Dear all...

The mistake turns out to be that we chose "simulator" instead of "debugger" in the project setting....
Best,
Richie
 

Realy

Junior Member level 1
Joined
Apr 7, 2014
Messages
16
Helped
1
Reputation
2
Reaction score
1
Trophy points
3
Activity points
95
i see your question.i'm a china engineer,We often use simulation of the iic,because it's not stable for STM32.so ......
 
Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Top