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

I2C Clone

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



Joined: 24 Apr 2017
Posts: 17

View user's profile Send private message

I2C Clone
PostPosted: Tue May 16, 2017 1:34 pm     Reply with quote

All,

I'm trying to clone the I2C slave behavior of an obsolete part.

What's working now
Today I can talk between master and slave using the example slave and 2401.c examples. I can request and send 16 bytes in succession.

Problem Statement I am getting hung up with how to respond to a request for information with a 2 byte command, where this obsolete part has up to 5 commands it can respond to. Basically I am not sure how to search through multiple commands in the ISR and respond accordingly.

Assuming the SSP interrupt finds a match for the part address, the slave needs to determine which command was sent and then respond with the appropriate payload.
I am using a PIC18F25k20 as a slave to respond to one of 5 commands from the master (FPGA).
To simplify debugging I created the same code the obolete part reponds to today (today it responds to an FPGA, I am using another PIC dev board as a fill in MASTER) – using part data sheet and have proven that the obsolete part does indeed respond appropriately to these commands.

Now I just need to make the new hardware I2C slave(PIC18F25k20) do the same.

I have shown just one of the 5 commands below.
Code:

MASTER Function:

BYTE read_registers(int8 t) {     
                                                             
   i2c_start();
   i2c_write(0x2E); //DEVICE ADDRESS WRITE
   i2c_write(0x00); //REG MSB COMMAND
   i2c_write(0x40); //REG LSB   COMMAND                             
   i2c_start();
   i2c_write(0x2F); //DEVICE ADDRESS READ
   reg1 = i2c_read(1);//clock stretch
   reg2 = i2c_read(1);//clock stretch
   reg3 = i2c_read(1);//clock stretch
   reg4 = i2c_read(1);//clock stretch
   reg5 = i2c_read(1);//clock stretch
   reg6 = i2c_read(1);//clock stretch
   reg7 = i2c_read(1);//clock stretch
   reg8 = i2c_read(1);//clock stretch
   reg9 = i2c_read(1);//clock stretch
   reg10 = i2c_read(0);//clock stretch
   i2c_stop();
   return(reg1,reg2, reg3,reg4, reg5,reg6, reg7,reg8, reg9,reg10);


Code:

SLAVE ISP

#INT_SSP                                               
void ssp_interrupt(){                                               
                                     
   unsigned int8 incoming, state, x, buffer[3],val[10];                                         
                                               
   state = i2c_isr_state();                             
                                   
    if(state < 0x80){                    //Master is sending data
      incoming = i2c_read();           
      if(state == 0)                     //First received byte               
         buffer[0] = incoming;                                 
      if(state == 1)                     //Second received byte 
         buffer[1] = incoming; 
      if(state== 2)                      //Third received byte     
         buffer[2] = incoming;                   
    }                                           
                                       
   if (state >= 0x80){               
                                   
      if(buffer[1] ==0x40){//command 1   
         for(x=0;x<10;x++){               
            i2c_write(val[x]);     
         }                     
                                       
      }
      //else if....  command 2   
     
      //else if....  command 3   
                       
      //else if....  command 4   
                                 
      //else...      command 5   
   }   
}


Am I on the right track with searching and responding to bytes 2&3?
jeremiah



Joined: 20 Jul 2010
Posts: 1358

View user's profile Send private message

PostPosted: Tue May 16, 2017 2:20 pm     Reply with quote

Couple of things:

1.
You are not handling the isr states completely.
1a.
When state == 0, the byte read is the I2C address. You are reading it as data...is this intentional?
1b.
You need to read the i2c buffer when state == 0x80 as this is also an address byte and must be read.

Look at the example in the compiler manual (it has typos, but the intent is there, so I modified out the typos):
Code:

#INT_SSP
void i2c_isr() {
   state = i2c_isr_state();
   if(state== 0 )
      i2c_read();
   if(state == 0x80)
      i2c_read(2);
   if(state >= 0x80)
      i2c_write(send_buffer[state - 0x80]);
   else if(state > 0)
      rcv_buffer[state - 1] = i2c_read();
}


Notice how it reads on all values 0 to 0x80, and tosses out the values for 0 and 80 but saves the other values inbetween.

2.
you are using a for loop in a single event ISR. The ISR is meant to handle one byte at a time. You are gonna need to get rid of that for loop and just have some logic to pick the right byte from your buffer based on the i2c_isr_state value.
TYDOM17



Joined: 24 Apr 2017
Posts: 17

View user's profile Send private message

PostPosted: Tue May 16, 2017 4:29 pm     Reply with quote

Thanks for the help jeremiah,

You are right I was reading the I2C address as data, I will remove this.

I will follow the example in the book and then run a check on the address byte value outside the ISR using a flag method.

Can you tell me what the 2 does in the i2c_read(2) function call?

According to the book there are only 2 options 0 or 1 for i2c_read.
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Tue May 16, 2017 5:43 pm     Reply with quote

Apparently you have some book on CCS C. Jeremiah was referring to
the CCS manual (a pdf file) here:
http://www.ccsinfo.com/downloads/ccs_c_manual.pdf
It explains all the parameters for i2c_read(), including the 2.

Also, the example that Jeremiah is talking about is in the CCS manual,
not your book. Look in the CCS manual in the section on i2c_isr_state()
(pages 231-232 in the Acrobat reader). It has the #int_ssp example
code, with typos, that he's referring to.
TYDOM17



Joined: 24 Apr 2017
Posts: 17

View user's profile Send private message

PostPosted: Thu Jun 15, 2017 1:44 pm     Reply with quote

Sorry in advance for the long reply – I’ve tried to keep this short.

Prototype ISR routine works
I now have a working prototype at my desk with master and slave getting along nicely using the code below. The SSP interrupt (including flags) appear to stretch out the clock nicely allowing for the master to send up to 10 bytes in succession (ring buffer) such that the slave is able to read these bytes in, buffer them and then act on the received buffer when there is a match in the 2 byte slave register address.

As stated before this clone is trying to emulate an obsolete I2C part which was designed to model its registers after EEPROM with 2 byte implicit register addresses. For this reason, all responses to implicit register address include 10 bytes, the first 2 bytes are the address with the next 8 being data just like older eeprom. However, when I change my master (PIC18F25K20) out for the intended (not simulated) master (FPGA) the I2C bus is having some real issues.

New Issues
The 1st command from the master (FPGA running @ 50kHz) with address 0x00,0x00 comes through just fine and I respond with 10 bytes including address 0x00,0x00. Then along comes address 0x00,0x40 – no problem here. Then along comes address 0x00,0x48 and my slave can only respond with address 0x00,0x40 and associated payload for that register. All proceeding addresses including 0x00,0x50 - 0x00,0xFF behave the same way.

Debugging
When I include the printf debugging statements I am able to see the following come through the rx_buffers.

Quote:

I2C SLAVE NOW SNIFFER FOR BYTES
00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00
00 02 00 00 00 00 00 00 00 00
00 02 54 00 00 00 00 00 00 00
00 02 54 47 00 00 00 00 00 00
00 02 54 47 14 00 00 00 00 00
00 02 54 47 14 95 00 00 00 00
00 02 54 47 14 95 75 00 00 00
00 02 54 47 14 95 75 6E 00 00
00 02 54 47 14 95 75 6E 00 00
00 02 54 47 14 95 75 6E 00 00
00 00 54 47 14 95 75 6E 00 00
00 00 54 47 14 95 75 6E 00 00
00 00 54 47 14 95 75 6E 00 00
00 40 54 47 14 95 75 6E 00 00
00 40 54 47 14 95 75 6E 00 00
00 40 54 47 14 95 75 6E 00 00
00 40 54 47 14 95 75 6E 00 00
00 48 54 47 14 95 75 6E 00 00
00 48 54 47 14 95 75 6E 00 00
00 48 54 47 14 95 75 6E 00 00
00 48 54 47 14 95 75 6E 00 00
00 50 54 47 14 95 75 6E 00 00
00 50 54 47 14 95 75 6E 00 00
00 50 54 47 14 95 75 6E 00 00
00 50 54 47 14 95 75 6E 00 00
00 58 54 47 14 95 75 6E 00 00
00 58 54 47 14 95 75 6E 00 00
00 58 54 47 14 95 75 6E 00 00
00 58 54 47 14 95 75 6E 00 00
00 58 54 47 14 95 75 6E 00 00
00 58 54 47 14 95 75 6E 00 00
00 58 54 47 14 95 75 6E 00 00
00 58 54 47 14 95 75 6E 00 00
00 58 54 47 14 95 75 6E 00 00
00 58 54 47 14 95 75 6E 00 00
00 58 54 47 14 95 75 6E 00 00
00 58 54 47 14 95 75 6E 00 00
00 58 54 47 14 95 75 6E 00 00


slave code
Code:
#include <18F25K20.h>                                                                                                                                                                                   
#FUSES INTRC_IO, NOMCLR                                                                     
#use delay(clock=16Mhz, internal)                                                                                           
#use rs232(baud=38400,INVERT,parity=N,xmit=PIN_C7,rcv=PIN_C6)                 
#use i2c(SLAVE,FORCE_HW,I2C1,address=0x2E)               
                                                                                                                       
#define I2C_EN     PIN_A5                                 
#define LED        PIN_B1                                                                 
#define E2PWR      PIN_B3                       
#define HUMTEMP    PIN_B4                                                                     
                                           
#include <DS1302_TE.C>                           
                                                                                 
unsigned int8 incoming, state, x, send_buffer[10],rcv_buffer[10]={0,0,0,0,0,0,0,0,0,0};                                                       
unsigned int8 address,data[4],buffer[16],z=0,cmdlsb,cmdmsb,cnt,nshocks=1;                         
int8 DAY,MON,YEAR,DOW,HR,MIN,SEC,tt1,tt2,tt3,tt4,tt5,tt6,tt7,tt8,tt9;     
INT16 DAY2,MON2,YEAR2,DOW2,HR2,MIN2,SEC2,tlsb,tcsb,tmsb,zeros;             
int8 tlsb_low,tcsb_low,tmsb_low,tlsb_high,tcsb_high,tmsb_high;         
int1 sspflag=0,hstateflag=0;                                                             
                                                                               
void timestamp(){                                                     
   rtc_get_date(DAY,MON,YEAR,DOW);                                 
   rtc_get_time(HR,MIN,SEC);                                 
                                       
   SEC   = 0b00111010;// 6 bits                 
   MIN   = 0b00100111;// 6 bits                   
   MON   = 0b00000000;// 5 bits         
   
   HR    = 0b00000001;// 5 bits                       
   DAY   = 0b00000011;// 5 bits               
   DOW   = 0b00000010;// 3 bits           
   YEAR  = 0b01110000;// 8 bits   
   zeros = 0x00;      // 9 bits                       
                                                             
   SEC2=SEC;                       
   MIN2=MIN;                                               
   MON2=MON;                             
   YEAR2=YEAR;                                       
                                                     
   tlsb = ((MON2 <<12)|(MIN2 << 6)| SEC2);     
   //printf("tlsb = %LX  ",tlsb);     
                                           
   tcsb = (zeros <<5 | HR);                 
   //printf("clsb = %LX  ",tcsb);                             
                                                                             
   tmsb = ((YEAR2 <<8)|(DOW << 5)| DAY);                 
   //printf("clsb = %LX  ",tmsb);         
                                                     
         
   tlsb_low  = tlsb;               
   tlsb_high = tlsb>>8;     
                                                             
   tcsb_low  = tcsb;                                           
   tcsb_high = tcsb>>8;               
                                                                                                                           
   tmsb_low  = tmsb;                               
   tmsb_high = tmsb>>8;                                                                         
                                   
   //i2c_write(tmsb_high);   
   //i2c_write(tmsb_low);                                                                                                           
   //i2c_write(tcsb_high);         
   //i2c_write(tcsb_low);   
   //i2c_write(tlsb_high);       
   //i2c_write(tlsb_low);       
             
   //printf("[%X][%X][%X][%X][%X][%X]\n\r",tlsb_high,tlsb_low,tcsb_high,tcsb_low,tmsb_high,tmsb_low);         
                                           
}                                                                           
                                                       
                                                                                                   
void main(){                                         
                                       
   output_high(I2C_EN);     
   output_high(E2PWR);     
   output_high(HUMTEMP);                           
   output_high(LED);                           
   delay_ms(200);                                         
   printf("\n\rI2C SLAVE NOW SNIFFER FOR BYTES\n\r");   
   output_low(LED);                       
   rtc_init();                                                                                     
                       
///////////////////////////  DATE STAMP MANUAL  ///////////////////////////////
//   rtc_set_datetime(22,5,17,1,10,38); // already set, leaving alone for now
                               
///////////////////////////  INITIALIZE INTERRUPTS  ///////////////////////////
   enable_interrupts(INT_SSP);                                             
   enable_interrupts(GLOBAL);                 
                                       
///////////////////////////////////////////////////////////////////////////////
                                                                       
   while (TRUE){                       
                                             
                               
      if(hstateflag==1){
         disable_interrupts(INT_SSP);                                             
         disable_interrupts(GLOBAL);                                   
         if     (cmdlsb==0x00){        //GET STATUS REGISTER SUMMARY                       
            //timestamp();                       
            i2c_write(0x00);                                 
            i2c_write(0x00);                     
            i2c_write(0x02);                 
            i2c_write(0x00);             
            i2c_write(0x5C);       
            i2c_write(0x88);                 
            i2c_write(0x00);         
            i2c_write(0x14);
            i2c_write(0x75);
            i2c_write(0xA9);   
                                                                       
         }                                                                                                             
         else if(cmdlsb==0x02 && tt3!=0){// ASSUME THE FPGA IS TRYING TO SET TIME - DON'T RESPOND   
            //timestamp();             
            i2c_write(0x00);                                         
            i2c_write(0x02);                           
            i2c_write(tt1);                   
            i2c_write(tt2);                                                                                                           
            i2c_write(tt3);   
            i2c_write(tt4);         
            i2c_write(tt5);   
            i2c_write(tt6);                                   
                                                                             
         }                       
         else if(cmdlsb==0x02){                                                                                         
                                                             
         }     
                                         
         else if(cmdlsb==0x40){// GET 1ST PAGE SUMMARY 
            //timestamp();                       
            i2c_write(0x00);                                 
            i2c_write(0x40);                                                                                                           
            i2c_write(2);//shock event cnt               
            i2c_write(0);//status                                                                                   
            i2c_write(3);//status         
            i2c_write(3);//status                                                                                                         
            i2c_write(3);//status 
            i2c_write(3);//status               
            i2c_write(3);//status       
            i2c_write(3);//status             
                                                             
         }                                                   
         else if(cmdlsb==0x48){// GET 2ns PAGE SUMMARY       
            //timestamp();                       
            i2c_write(0x00);                   
            i2c_write(0x48);                                     
            i2c_write(1);//shock event cnt               
            i2c_write(0);//status                         
            i2c_write(4);//status 
            i2c_write(4);//status                                                                                                         
            i2c_write(4);//status 
            i2c_write(4);//status 
            i2c_write(4);//status       
            i2c_write(4);//status                       
         }                                                                           
         else if(cmdlsb==0x50){// GET 3rd PAGE SUMMARY         
            //timestamp();               
            i2c_write(0x00);                             
            i2c_write(0x50);                                     
            i2c_write(0xFF);                   
            i2c_write(0xFF);                             
            i2c_write(0xFF);                   
            i2c_write(0xFF);   
            i2c_write(0xFF);                           
            i2c_write(0xFF);                         
            i2c_write(0xFF);                   
            i2c_write(0xFF); 
         }                                                                                 
         else               //DEFAULT GARBAGE DATA                                     
            i2c_write(77);       
         hstateflag=0;   
         enable_interrupts(INT_SSP);                                             
         enable_interrupts(GLOBAL);   
      }   
     
                                                     
      if(sspflag==1){                                                                                                       
         disable_interrupts(INT_SSP);                                             
         disable_interrupts(GLOBAL);       
                                                                                           
         cmdmsb=rcv_buffer[0];//MSB
         cmdlsb=rcv_buffer[1];//LSB           
         tt1=   rcv_buffer[2];                   
         tt2=   rcv_buffer[3];                 
         tt3=   rcv_buffer[4];                           
         tt4=   rcv_buffer[5];                                                                                   
         tt5=   rcv_buffer[6];                                                                                     
         tt6=   rcv_buffer[7];           
         tt7=   rcv_buffer[8];               
         tt8=   rcv_buffer[9];                     
         printf("%X %X %X %X %X %X %X %X %X %X\n\r",                                                                           
         rcv_buffer[0],rcv_buffer[1],rcv_buffer[2],rcv_buffer[3],rcv_buffer[4],rcv_buffer[5],rcv_buffer[6],rcv_buffer[7],rcv_buffer[8],rcv_buffer[9]);           
         sspflag=0;     
                                                                         
         enable_interrupts(INT_SSP);                                               
         enable_interrupts(GLOBAL);           
      }                                       
 
 
   }                                                           
}                                             
                                                                                       
                                               
#INT_SSP                                               
void ssp_interrupt(){                                               
   output_high(LED);                                     
                                           
   state = i2c_isr_state();                                                   
   if(state== 0 )     //MATCH /W- read to clear int but tosses out the value       
      i2c_read();                               
   if(state == 0x80)  //MATCH R/- read to clear int but tosses out the value   
      i2c_read(2);                                 
   if(state >= 0x80){ //TRANSMIT RECIEVED, 0x81 to 0xFF RESPOND WITH I2CWRITE
      hstateflag=1;   //SET FLAG - service the i2c_write with if, else-if statments                                 
   }                                                             
   else if(state > 0) //reads in all values 1 to 79                           
      rcv_buffer[state - 1] = i2c_read();//fills up buffer[] 1 through 79   
      //this really means that it can take up to 78 i2c write commands in succession   
   sspflag=1;               
   output_low(LED);                   
}     


master code snippet
Code:
BYTE read_status_register() {               
                                         
   i2c_start();
   i2c_write(0x2E); //DEVICE ADDRESS WRITE           
   i2c_write(0x00); //REG MSB       
   i2c_write(0x00); //REG LSB   
   i2c_stop(); //ADDED THIS TO REPLICATE THE PROBLEM                         
   i2c_start();                                             
   i2c_write(0x2F); //DEVICE ADDRESS READ
   reg1           = i2c_read(1);//clock stretch 
   reg2           = i2c_read(1);//clock stretch     
   NA              = i2c_read(1);//clock stretch
   NA              = i2c_read(1);//clock stretch
   NA              = i2c_read(1);//clock stretch
   NA              = i2c_read(1);//clock stretch                 
   NA               = i2c_read(1);//clock stretch
   NA              = i2c_read(1);//clock stretch
   NA              = i2c_read(1);//clock stretch             
   NA              = i2c_read(0);//clock stretch       
   i2c_stop();   
   delay_us(10);
  //NA place holder for name of real data
   return(reg1,reg2,shk_evnt_cnt,status_bits,ts_first_msb,ts_first_lsb,ts_middle_msb,ts_middle_lsb,ts_end_msb,ts_end_lsb);
}



Big Picture View
All commands responses you see in the slave code work on my bench between obsolete part and my design, however only the obsolete works all the time with the FPGA.

My Questions
Is there anything I am doing in my while loop or SSP_ISR that appears wrong? Why would my code respond to address 0x00,0x48 with data from the 0x00,0x40 else if statement? Surely I must be doing something wrong and just can't see it.

Bowing down in supplication before the PICMASTERs

Thanks in advance for your time.
TYDOM17



Joined: 24 Apr 2017
Posts: 17

View user's profile Send private message

PostPosted: Thu Jun 15, 2017 4:17 pm     Reply with quote

Yikes, I found my mistake.Shocked

Sometimes typing things out really forces you too look at everything. Idea

My mistake was in responding with multiple i2c_write commands back to back in my if/else if statements rather then setting up the send_buffer[] values for one single.

Code:
i2c_write(send_buffer[state-0x80]);     


FPGA and PIC are happy now.

I'll get back on the forum when I a cleaned up generic version to share in the example code section.
temtronic



Joined: 01 Jul 2010
Posts: 9246
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Thu Jun 15, 2017 4:22 pm     Reply with quote

Just had a quick look and this caught my eye...

From the master snippet...
Quote:
return(reg1,reg2,shk_evnt_cnt,status_bits,ts_first_msb,ts_first_lsb,ts_middle_msb,ts_middle_lsb,ts_end_msb,ts_end_lsb);

I've always assumed that return() could only return one variable..

Hopefully someone can enlighten me if this is true as the CCS manual I have only shows 1 variable or 1 value being allowed...
jeremiah



Joined: 20 Jul 2010
Posts: 1358

View user's profile Send private message

PostPosted: Fri Jun 16, 2017 6:15 am     Reply with quote

temtronic wrote:
just had a quick look and this caught my eye...

fromt the master snippet...
return(reg1,reg2,shk_evnt_cnt,status_bits,ts_first_msb,ts_first_lsb,ts_middle_msb,ts_middle_lsb,ts_end_msb,ts_end_lsb);

I've always assumed that return() could only return one variable..

Hopefully someone can enlighten me if this is true as the CCS manual I have only shows 1 variable or 1 value being allowed...


It does only return 1 variable, but C allows comma separated statements and will pass the last statement in the list to the return. It's a not very often used feature of C.

In this context it is a very odd line as it really doesn't do anything in their code.

I typically use it for macros that are meant to act as functions that return a value.

EDIT: If you look at my snprintf macro here, you will see me using comma separated statements so that my macro returns a value at the end:
https://www.ccsinfo.com/forum/viewtopic.php?t=53652
Ttelmah



Joined: 11 Mar 2010
Posts: 19552

View user's profile Send private message

PostPosted: Fri Jun 16, 2017 7:21 am     Reply with quote

It is an error here...
Just means he only gets the last value.
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