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

Multimaster I2C hangs while reading

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



Joined: 04 Dec 2015
Posts: 2
Location: Italy

View user's profile Send private message

Multimaster I2C hangs while reading
PostPosted: Fri Dec 04, 2015 6:30 am     Reply with quote

Dear guys,

I am working on a multimaster i2c network with PIC18F23K22. Up to now my prototype has 3 devices acting as master (we will call them mini-master) that write to a single (4th) device (called slave-core) their information. First question: the project will require me to have around 100 mini-masters linked on the same i2c bus that will rarely write burst of data to the slave-core. Do you think it is feasible and reliable? May it work, provided some buffers to decrease bus capacitance?

Second question is about bus conflicts or something similar which I don't understand.

Hereunder you will find my code. Basically my master protocol is:
start + addressWrite + data byte1 + data byte2 + data byte3 + restart + addressRead + data byte1 + data byte2 + data byte3 + stop
When used separately, every mini-master writes and read correctly, as well as the slave-core.
Since I expected bus conflicts I designed the firmware below where each mini-master writes its info and wait some time before repeating it. Time is different for every mini-master so that conflicts will happen.
It works for a while, since I see by debugging that the slave-core reads correctly data from the three mini-masters. But the oscilloscope shows me that after some time (which is not repeatable) one of the mini-master stop sending and after another while a second one stops leaving the third working alone. The slave-core continues to read and send data correctly.

By debugging the device that stops (not always the same, but usually the one called i2cMyAdd = 0x16) it hangs in the i2c function, in particular at the stage of sending the ackowledge bit. I found out this by looking at the disassembly listing. Setting the program counter to the next instruction it returns to the end of the first i2cRead instruction just to hang again on the next one. This is repeatable and happens on all the three i2cRead.

I tried a lot in solving this issue, first by placing the #INT_BUSCOL code. It does not hang here, so I think it is correct, but please, can you have a look also to this part of the code?
Then I tried to start the i2c transmission only after checking if the bus is idle or a stop bit has been received. But nothing changed.
In my mind it works but evidently in my PICs minds it's not. What am I missing? Do you see anything on which I can work on?

The code is here. Between the slave-core and the mini-master there is just the main, which I comment and uncomment

Thanks for helping me

Code:

#include <18F23K22.h>
#include <pindef.h>

/* these two are examples in pindef.h
#byte   PIR2      = 0xFA1         // BCL1IF belongs to it                     default 0x00
#bit    SSP1IF      = PIR1.3      // set to signal an interrupt on the i2c bus
*/

#include <i2cOpCode.h>

// Configurazione PIC
#fuses noWDT,noPROTECT,PUT,noBROWNOUT,noLVP,INTRC_IO
// #fuses ICSP1

#use delay (clock=32000000)  // Attenzione al clock!!!

#use i2c(multi_master, I2C1 ,FAST=400000, FORCE_HW, stream=i2cEM)
#use i2c(slave, I2C2, ADDRESS=ediAddW, FORCE_HW, stream=i2cES)

int i2cState, i2cDataR[3], i2cDataW[3], addressMatch;
int i = 0, ack = 0;
int i2cAddComputed = 0x12; // available addresses are the even ones from 0x12 -> 0xEE (for a total of 110 addresses)
int ledDelay;
int i2cDataMem[50][2], contatore;
int ssp1con1Rst, ssp1con2Rst, ssp1con3Rst, ssp1statRst;


int I2CAddRW(int inI2CAdd, int1 rw)
{   
//    rw = 0 -> master wants to write
//    rw = 1 -> master wants to read
   return (inI2CAdd|rw);
} // end I2CAddRW


void i2cDataToSend(int operCode, int data1, int data2)
{
   i2cDataW[0] = operCode;
   i2cDataW[1] = data1;
   i2cDataW[2] = data2;
} // end i2cDataToSend


void initVariables(void)
{
   int col;
   
   for(col = 0; col < 3; col++)
   {
      i2cDataR[col] = 0;
      i2cDataW[col] = 0;
   }
   
   for(col = 0; col < 2; col++)
   {
      for(rig = 0; rig < 50; rig++)
         i2cDataMem[rig][col] = 0;
   }
   
   i = 0;
   ack = 0;
   i2cAddComputed = 0x12;
   ledDelay = 500;
   contatore = 0;
   
   ssp1con1Rst = SSP1CON1;
   ssp1con2Rst = SSP1CON2;
   ssp1con3Rst = SSP1CON3;
   ssp1statRst = SSP1STAT;
 
} // end initVariables


void decodeOpCode(void)
{
   switch(i2cDataR[0])
   {
      case _reset:
         break;
      
      case _NESWAdd:
         if(!i2cAddMatrix[i2cDataR[1]][i2cDataR[2]])
         {
            i2cAddMatrix[i2cDataR[1]][i2cDataR[2]] = i2cAddComputed;
            i2cAddComputed+=2;                                 // use only even address since the last bit is ignored and the odd one is the same as the precedent
         }
         i2cDataToSend(_sendI2CAdd, i2cAddMatrix[i2cDataR[1]][i2cDataR[2]], 0xFE);
         break;
      
      case _slider:
         ledDelay = i2cDataR[1];
         i2cDataToSend(_acknowledge, 0, 0);
         break;

      case _button:
         ledDelay = i2cDataR[1];
         i2cDataToSend(_acknowledge, 0, 0);
         break;
      
      case _sendI2CAdd:
         i2c_slaveaddr(i2cES, i2cDataR[1]);
         i2cAddMatrix[1][2] = i2cDataR[1];
         break;
         
      case _testConfW:
         if (contatore < 50)
         {
            i2cDataMem[contatore][0] = i2cDataR[1];
            i2cDataMem[contatore++][1] = i2cDataR[2];
            i2cDataToSend(_acknowledge, 0, 0);
         }
         break;
            
      case _acknowledge:
         break;
               
      default:
         break;
   } // end case
   
} // end decodeOpCode()   



#int_buscol
void isr_buscol(void)
{
   // reset hardware
   #asm
   nop
   #endasm
   while((!P)&&!(input(sdaEdiM)&&input(sclEdiM)&&!P&&!S));      // wait untill you detect a stop or the bus is idle
   SSP1CON1   = ssp1con1;
   SSP1CON2   = ssp1con2;
   SSP1CON3   = ssp1con3;
   SSP1BUF    = 0xFF;
   SSP1STAT   = ssp1stat;
   BCL1IF   = 0;
//   WCOL   = 0;
//   SSPOV   = 0;
//   SSP1BUF = 0xFF;
//   RW      = 0;
//   ACKEN   = 0;
//   SEN      = 0;
//   PEN      = 0;
//   RSEN   = 0;
   ack      = 2;
}   


#int_ssp2
void isr_i2c1ES(void)
{

   i2cState = i2c_isr_state(i2cES);
   if (i2cState == 0)                                       // received a matching address and Master wants to write
   {
      addressMatch = i2c_read(i2cES, 1);
   }
   if (i2cState == 0x80)                                    // received a matching address and Master wants to read
   {
      i2c_write(i2cES, i2cDataW[0]);
   }   
   if(i2cState > 0x80)                                       // Master is requesting data; i2cState increments by one every byte transmitted
   {
      if (i2cState == 0x81)
      {
         i2c_write(i2cES, i2cDataW[1]);                        // Write op code
      }
      if (i2cState == 0x82)
      {
         i2c_write(i2cES, i2cDataW[2]);
         i2cEndTx = 1;                                    // i2c Flag of end transmission
      }   
   }   
   if((i2cState >= 1)&&(i2cState < 0x80))                        // Master is sending data; i2cState increments every byte read
   {
      if(i2cState < 3)
         i2cDataR[i2cState - 1] = i2c_read(i2cES, 1);             // i2c_read(1) (do ack) should be used always but the last reading
      if(i2cState == 3)
      {
         i2cDataR[i2cState - 1] = i2c_read(i2cES, 1);            // i2c_read(0) (don't ack) should be used always but the last reading
         decodeOpCode();
      }
      
   }
} // end #int_ssp2



/////////////////////////////////////////////////
////
//// SLAVE-CORE
////
/////////////////////////////////////////////////
//
//
//
//// master
//void main()
//{
//   int i2cAddToCall;
//   
//   setup_oscillator(OSC_32MHZ);   
//   
//   initVariables();
//   
//   delay_ms(10);
//   enable_interrupts(GLOBAL);
//   enable_interrupts(INT_SSP2);
//   
//   while(1)
//   {   
//      delay_ms(1000);
//   }
//
//}


///////////////////////////////////////////////
//
// MINI-MASTER
//
///////////////////////////////////////////////



// master
void main()
{
   int i2cMyAdd;
   setup_oscillator(OSC_32MHZ); // Attenzione al clock!   
   
   initVariables();
   i2cMyAdd = 0x16; // <-- the three mini-masters have just this as a difference: 0x12, 0x14, 0x16
   
   delay_ms(10);
   enable_interrupts(GLOBAL);
   enable_interrupts(INT_SSP2);
   enable_interrupts(INT_BUSCOL);
   
   while(1)
   {
      i2cDataToSend(_testConfW, i2cMyAdd, i++);
      while((!P)&&!(input(sdaEdiM)&&input(sclEdiM)&&!P&&!S));
      i2c_start(i2cEM);
      ack = i2c_write(i2cEM, ediAddW);
      if(!ack)
      {
         ack = i2c_write(i2cEM, i2cDataW[0]);
         if(!ack)
         {
            ack = i2c_write(i2cEM, i2cDataW[1]);
            if(!ack)
            {
               ack = i2c_write(i2cEM, i2cDataW[2]);
               if(!ack)
               {
                  i2c_start(i2cEM);
                  ack = i2c_write(i2cEM, ediAddR);
                  if(!ack)
                  {
                     i2cDataR[0] = i2c_read(i2cEM, 1); // <- it hangs during the ackowledge sequence in these i2cRead. ACKEN never goes low!
                     i2cDataR[1] = i2c_read(i2cEM, 1);
                     i2cDataR[2] = i2c_read(i2cEM, 0);
                  }
               }
            }
         }
      }         
      i2c_stop(i2cEM);
      decodeOpCode();
      enable_interrupts(INT_SSP2);
   
      if(i2cMyAdd == 0x16)
         delay_ms(1);
      if(i2cMyAdd == 0x14)
         delay_ms(3);
      if(i2cMyAdd == 0x12)
         delay_ms(9);
   }

}
Ttelmah



Joined: 11 Mar 2010
Posts: 19551

View user's profile Send private message

PostPosted: Fri Dec 04, 2015 9:18 am     Reply with quote

Your int_buscol code is wrong. You are restoring the registers, with themselves, not the Rst copies.....

As a separate comment, try to avoid bus collisions. Read the clock line, and verify is it high, and stays high for a short time, before initiating the transaction.

delay_cycles(1);

codes as a nop.

Yes, you will need buffers.
LucaM



Joined: 04 Dec 2015
Posts: 2
Location: Italy

View user's profile Send private message

PostPosted: Wed Dec 09, 2015 5:22 am     Reply with quote

Thank you Ttelmah for going through my code.
I am following your advices, but up to now I've got no success. I'll keep you guys updated on my progresses
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