CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

Problem with hanging I2C bus.

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
monsun



Joined: 17 Jan 2012
Posts: 17

View user's profile Send private message

Problem with hanging I2C bus.
PostPosted: Wed Apr 07, 2021 6:17 am     Reply with quote

Hello everyone,
I've two devices slave with PIC24FV16KM202 and master with PIC24FV32KA304

compiler 5.093

master is using crystal 14745600Hz
slave is using internal osc on 8MHz


Line is long about 10cm pulluped to 5V with 3.3kOhm

Every thing works ok master make thousand of readings from slave but on some circumstances slave I2C hangs. Master discover problem with communication with slave and tries to reset_cpu() himself.

Slave device have WDT but it doesn't initiate.
I've uart port for service communication between PC and Slave, and PC software communicate with Slave during this I2C hangs state without any problems. So firmware is working somehow ok.

Could any one analyze my INT_SSP on slave and master function, on any mistakes i don't see?
Do you guys have any ideas on how to debug this?

Slave:
Code:

#use i2c(SLAVE, FORCE_HW, I2C1, RESTART_WDT, address=0xCC, stream=I2C_PORT)

volatile UNSIGNED int8 incoming;
volatile UNSIGNED int8 state;
volatile UNSIGNED int8 local_register_address=0;
volatile static UNSIGNED int8 i2c_buffer[17];

#INT_SSP
void i2c_isr(){
   state=i2c_isr_state(I2C_PORT);
   
   IF(state<=0x80)
   {//Master is sending data
      IF(state==0x80)
         incoming=i2c_read(I2C_PORT,2);
      ELSE
         incoming=i2c_read(I2C_PORT,1);

      IF(state==1){//First received byte is local register address
         local_register_address=incoming;
      }
      ELSE IF(state>=2 && state!=0x80)
      {
         i2c_buffer[local_register_address]=incoming;
         local_register_address++;
      }
   }

   IF(state>=0x80){//Master is requesting data
      i2c_write(I2C_PORT,i2c_buffer[local_register_address]);
      local_register_address++;
   }
 }


Master:
Code:

#use i2c(MASTER, I2C1, FAST=400000, FORCE_HW, stream=I2C_SENSOR)

unsigned int8 dech_GetResult(unsigned int8 sensor_address, float *result){
  union bytefloat{
    unsigned int8 buffer[4];
    float float_num;
  }float_union;
 
  sensor_address<<=1;
 
  i2c_start();
  i2c_write(sensor_address);  // transmit to slave device
  i2c_write((unsigned int8)9);      // sends address to read result
  i2c_stop();                 // stop transmitting
 
  i2c_start();
  i2c_write(sensor_address+1);  // transmit to slave device  +1 to read
 
  #IFDEF __pcd__
  float_union.buffer[0] = i2c_read(TRUE);
  float_union.buffer[1] = i2c_read(TRUE);
  float_union.buffer[2] = i2c_read(TRUE);
  float_union.buffer[3] = i2c_read(FALSE);
  #ENDIF
  #IFDEF __pch__
  float_union.buffer[3] = i2c_read(TRUE);
  float_union.buffer[2] = i2c_read(TRUE);
  float_union.buffer[1] = i2c_read(TRUE);
  float_union.buffer[0] = i2c_read(FALSE);
  convert_ieee_to_microchip(&float_union.buffer[0]);
  #ENDIF
   
  *result=float_union.float_num;
  return 1;
}
Ttelmah



Joined: 11 Mar 2010
Posts: 19496

View user's profile Send private message

PostPosted: Wed Apr 07, 2021 6:33 am     Reply with quote

Normally in I2C, there are two different type of 'hang'. The first is where the
slave has missed something, the second is where the slave is holding
the clock. On the former, the correct requirement for the master is to send
extra clocks (up to 9). Try this before resetting the master.
If the slave is holding the clock, it is it that has to reset (the master can't
do anything).

The big problem with what you describe is clock speed. Generally you need
the slave to be able to handle it's state changes before the master wants
the next thing to happen. Having a slave that runs a lot slower than the
master, will often give problems....

This is what the watchdog should do. It sounds as if you are incorrectly
resetting the watchdog. The key is that the code that resets this should
only get called if the chip is doing everything it should (including presumably
receiving new data on the I2C). You need to remove 'RESTART_WDT' from
your I2C code, and instead restart it yourself if things are working.
The 'RESTART_WDT' abilities in CCS, are _awful_ code. The key is that
for a watchdog to actually do anything useful, you need to ensure that
the watchdog can only get restarted, if everything in the code is working
correctly. Having 'internal' restarts scattered around in delays, and in the
I2C handler code, basically makes the watchdog 'useless'.
monsun



Joined: 17 Jan 2012
Posts: 17

View user's profile Send private message

PostPosted: Wed Apr 07, 2021 6:55 am     Reply with quote

Is there any way to distinguish those two states?
"The first is where the slave has missed something, the second is where the slave is holding the clock."
Slave is working as sensor front end so it is basically continuously making measurements and i2c inquiries from master are asynchronous, and i don't have idea how to measure if slave i2c is stuck or not. I'm reseting watch dog in few important places outside INT_SSP

Could you say something more about this:
"On the former, the correct requirement for the master is to send
extra clocks (up to 9). "
How to put it into practice?

I have one place in slave program where i'm disabling interrupts, maybe sometimes i timing it with i2c inquiries and this is the place where it stucks?
I've edited this code because it was from function which isn't used.
Now code is ok and it's only one place during "working" state when int_ssp is disabled
Code:

    disable_interrupts(INT_SSP);
      memcpy(&i2c_buffer[9],wynik_unia.lval,4);
      i2c_buffer[13]=flaga_result_ready;
   enable_interrupts(INT_SSP);


Last edited by monsun on Wed Apr 07, 2021 7:20 am; edited 1 time in total
Ttelmah



Joined: 11 Mar 2010
Posts: 19496

View user's profile Send private message

PostPosted: Wed Apr 07, 2021 6:56 am     Reply with quote

Simply read the SCL line in the master. If it is low the slave is holding the
clock.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
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