• AVR Freaks

I2C Lock up recovery and timeout

Author
GunkutA
Junior Member
  • Total Posts : 107
  • Reward points : 0
  • Joined: 2019/01/10 00:09:38
  • Location: 0
  • Status: offline
2019/05/22 23:46:48 (permalink)
0

I2C Lock up recovery and timeout

Hello I am trying to get data from 3 smart batteries by using SMBus. ( I use PIC18F26K83) Since they all have same address I use mux. The SMBus communication works correctly if all of the batteries are connected. But in case of a missing battery, I2C lock up inside of the SMBus write/read code. And after that lock eventhough I reset the SMBus. It keeps giving me sometimes wrong and sometimes correct datas. So my questions:
1) How should I make the recovery from a lock up? The way I am following: 
I disable I2C module : I2C1CON0.B7=0;     //reset SMBus . Then I call my I2C_Init() function again.
Does this way looks appropriate?
2)In order to get if there is a timeout I use while loops inside my SMBus write/read code which is this:
waitCount=1000;

   I2C1STAT1.B2=1;// CLRBF=1, EMPTIES TRANSMIT BUFFER,i.e. TXBE=1


      I2C1ADB1=0x16; //Address for smart battery
      I2C1TXB =0x0E; //Relative SOC
      while (!I2C1STAT0.B7&&waitCount!=0) { // BUS FREE BFRE=1
       delay_us(1);
     waitCount--;}
     if(waitCount==0){
     flag=1;
     return;
    }
     waitCount=1000;
      I2C1CNT=1; //BYTE COUNT REGISTER
      I2C1CON0.B6=1; //RSEN=1;
               //******START**********
      I2C1CON0.B5=1; //MASTER START BIT


      while(!I2C1CON0.B3&&waitCount!=0){ //Master Data request
     delay_us(1);
     waitCount--;}
      if(waitCount==0){
     flag=1;
     return;
     }
     waitCount=1000;


       while(!I2C1Stat1.B5&&waitCount!=0){ //Transmit Buffer empty status bit.
         delay_us(1);
     waitCount--;}
      if(waitCount==0){
     flag=1;
     return;
     }
     waitCount=1000;

          //Transmit buffer cleared


 I2C1ADB1= (0x16 | 0x01);
 I2C1CNT=1;
 I2C1CON0.B5=1; //MASTER START BIT
 I2C1CON0.B6=0; //RSEN=1;

 while(!I2C1stat1.B0&&waitCount!=0){ //RXBF Receive Buffer Full Status Bit
delay_us(1);
     waitCount--;}
      if(waitCount==0){
     flag=1;
     return;
     }
     waitCount=1000;

  //I2C2RxB has received a new data.
 Data_10 =I2C1RXB ;

      }

 
So for each while function I wait 1000 us. Is this enough or should I increase it?
 
And this is the main routine if anybody wonders: (mux functions work correctly in all the times so I can select channels)
 
 

    while(1){
    led=1;
    reset=0;
    delay_ms(5);
    reset=1;
    mux1();
    delay_ms(5);
  SMBus_Data();
  if(flag){ //Battery1 timeout occured
    I2C1CON0.B7=0; //reset SMBus
    SMBus_Setup1(); //Init the SMBus again
    delay_ms(10);
    battery1_on=0; //Battery1 is not connected
    battery1=0; //Value for battery1 is zero
    flag=0;} //Reset the flag
    
    else{ //If no timeout for battery1
    battery1_on=1; //battery1 is on
   battery1=Data_10;} //battery1's value
   reset=0;
   delay_ms(5);
   reset=1;
    mux2();
    delay_ms(5);

    SMBus_Data();
    if(flag){ //Timeout for battery2 occured
    I2C1CON0.B7=0; //reset SMBus
    SMBus_Setup1(); //Initialise the SMBus again
    delay_ms(10);
    battery2_on=0; //Battery2 is not connected
    battery2=0; //Value for battery2 is zero
    flag=0;}
   
    else{ //If no timeout occured for battery2
    battery2_on=1; //Battery2 is on
    battery2=Data_10 ; } //Value of battery2
    reset=0;
    delay_ms (5);
    reset=1;
    mux3();
    delay_ms(5);
    SMBus_Data();
    if(flag){ //Timeout occured for battery3
    I2C1CON0.B7=0; //reset SMBus
    SMBus_Setup1(); //Init the SMBus again
    delay_ms(10);
    battery3_on=0; // Value for battery3 is zero
    battery3=0; //Battery3 is not connected
    flag=0;} //Reset the timeout flag
    else{ //If no timeout occured
    battery3_on=1; //Battery3 is connected
    battery3=Data_10 ; } // Battery3's value
    battery_count=battery1_on+battery2_on+battery3_on; // Get how many batteries are connected
    avarage = ((battery1_on*battery1)+(battery2_on*battery2)+(battery3_on*battery3))/battery_count; // Get the average value of the batteries

 
Edit: I use MicroC.
#1

0 Replies Related Threads

    Jump to:
    © 2019 APG vNext Commercial Version 4.5