| 
	
	|  |  |  
	
		| View previous topic :: View next topic |  
		| Author | Message |  
		| frank_the_programmer 
 
 
 Joined: 05 Feb 2024
 Posts: 7
 
 
 
			    
 
 | 
			
				| Reset I2C On Lockup? |  
				|  Posted: Wed Aug 28, 2024 7:26 pm |   |  
				| 
 |  
				| Hey all. I've been using the CCS C Compiler for a while now and I have some nice looking code, but I can't figure how to make my I2C routines fool proof. I'm putting this dsPIC33FJ128GP204 through its paces trying to find edge cases. 
 I've been able to consistently recreate an I2C lockup by shorting the clock or data lines. If anyone knows a way to reset the I2C or reboot the device on a detected error send your ideas this way! Thanks.
 |  |  
		|  |  
		| jeremiah 
 
 
 Joined: 20 Jul 2010
 Posts: 1401
 
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Wed Aug 28, 2024 8:28 pm |   |  
				| 
 |  
				| I'm sure others will have good tips for making it stable. 
 For resetting, did you try:
 Setting the I2C PMD bit to 1
 Setting the I2C PMD bit to 0
 redo the setup of the I2C
 |  |  
		|  |  
		| Ttelmah 
 
 
 Joined: 11 Mar 2010
 Posts: 19966
 
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Thu Aug 29, 2024 4:09 am |   |  
				| 
 |  
				| The key thing on i2C, is to handle the situation where a peripheral has not completed a read transaction.
 Imagine you are talking to a peripheral, and something happens. The chip
 restarts. You now have a device that is part way through a transaction,
 and potentially expecting clocks. If you then wake up your I2C driver,
 and start trying to talk to it, it won't work...
   
  	  | Quote: |  	  | Details: It is generally known that the I2C bus can hang if an I2C master is removed from the bus
 in the middle of a data read. This can occur because the I2C protocol does not mandate
 a minimum clock rate. Therefore, if a master is reset in the middle of a read while a
 slave is driving the data line low, the slave will continue driving the data line low while it
 waits for the next clock edge. This prevents bus masters from initiating transfers. If this
 condition is detected, the following three steps will clear the bus hang condition:
 1. An I2C master must generate up to 9 clock cycles.
 2. After each clock cycle, the data pin must be observed to determine whether it has
 gone high while the clock is high.
 3. As soon as the data pin is observed high, the master can initiate a start condition.
 
 | 
 
 In this situation, since the data line is being held low by the slave, the
 master device cannot send an I2C start. Result disaster....
 
 What has to happen is that you have to send I2C clock pulses to the
 device till it completes it's transaction. This then releases the bus, and
 you can start correctly. Now the PIC I2C peripheral won't do this, since it
 won't receive a correct response to an I2C start being sent.
 
 So:
 1) Setup the I2C using #use I2C, with NOINIT.
 2) At the start of the main, read the I2C data line.
 3) If this is low, the bus is being held be a peripheral. If so, simply operate
 the clock line yourself in code.
 Remember not too fast. 5uSec low, then 5uSec 'float'. Then back to
 testing the data line.
 4) Once the SDA line releases, simply call i2c_init for the bus.
 
 This releases the device that is driving the bus.
   
 As a further comment to this using the NOINIT, and I2C_init option, also
 allows you at any time to reset the master device. You can just use:
 
 I2C_INIT(YourStreamName, FALSE);
 
 to turn ff the I2C peripheral, and:
 
 I2C_INIT(YourStreamName, TRUE);
 
 To re-initialise the I2C peripheral and re-enable it.
 |  |  
		|  |  
		| frank_the_programmer 
 
 
 Joined: 05 Feb 2024
 Posts: 7
 
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Mon Sep 02, 2024 8:08 am |   |  
				| 
 |  
				| Thanks for the speed replies. I took a few days to test the suggested methods and I think I got something that works! Adding NOINIT on the #use i2c worked great after initializing in main. 
 Using your methods I was able to add an i2c activity monitor. if the i2c slave interrupt doesn't see any activity for 2 seconds it restarts the i2c with i2c_init(0) and shortly after i2c_init(1). This works great and now the bus fully recovers. Thanks again everyone.
 |  |  
		|  |  
		| Ttelmah 
 
 
 Joined: 11 Mar 2010
 Posts: 19966
 
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Mon Sep 02, 2024 10:30 am |   |  
				| 
 |  
				| A critical thing you did not mention. That you were dealing with being a slave device.
 The 'check the line' part is for the master device.
 If you are losing packets from a master, resetting the bus is sensible, but
 does suggest you may be not correctly handling one of the bus errors.
 Is it possible you are getting a buffer overrun, or a bus collision?. Both
 will be flagged and can be tested for in your handler.
 |  |  
		|  |  
		|  |  
  
	| 
 
 | You cannot post new topics in this forum You cannot reply to topics in this forum
 You cannot edit your posts in this forum
 You cannot delete your posts in this forum
 You cannot vote in polls in this forum
 
 |  
 Powered by phpBB © 2001, 2005 phpBB Group
 
 |