  | 
	  | 
		 
	 
	
		| View previous topic :: View next topic   | 
	 
	
	
		| Author | 
		Message | 
	 
	
		
			snibbe
 
 
  Joined: 06 Jan 2005 Posts: 4
  
			
			 
			 
			
			
			
			
			
			
			
  
		  | 
		
			
				| WORKING I2C MASTER AND SLAVE LOGGER : MULTI-BYTE | 
			 
			
				 Posted: Sun Jan 09, 2005 2:05 pm     | 
				     | 
			 
			
				
  | 
			 
			
				I have had a very difficult time getting 2 pics to communicate via I2C. After working several weeks on and off, I've modified two examples and now have working code I would like to share in the hopes it save some of you time! The code allows one 16-bit word to be read and written from the slave. You can easily modify this to transmit and receive more data, or change the first piece of data to a command byte. The key to multi-byte reading is to read requesting an ACK: i2c_read(1) for every byte but the last: i2c_read(0).
 
This is pasted straight from my working programs. Thanks especially to "valemike". The slave is primarily his code. The master is modified from EX_EXTEE.
 
 
SLAVE CODE:
 
 
 	  | Code: | 	 		  #include <16F876A.H>
 
 
// 10-bit A/D conversion
 
#device ADC=10
 
#fuses HS,NOWDT,NOPROTECT,NOLVP
 
 
#use Delay(Clock=20000000)
 
#use rs232(baud=9600,xmit=PIN_C6,rcv=PIN_C7,brgh1ok)
 
 
unsigned char read_i2c(void); 
 
void i2c_interrupt_handler(void); 
 
void i2c_initialize(void); 
 
void i2c_error(void); 
 
void write_i2c(unsigned char transmit_byte); 
 
 
#INT_SSP 
 
void ssp_interupt () 
 
{ 
 
    i2c_interrupt_handler(); 
 
} 
 
 
 
/* 16f87X bytes */ 
 
/* Change it per chip */ 
 
#byte PIC_SSPBUF=0x13 
 
#byte PIC_SSPADD=0x93 
 
#byte PIC_SSPSTAT=0x94 
 
#byte PIC_SSPCON1=0x14 
 
#byte PIC_SSPCON2=0x91 
 
 
/* Bit defines */ 
 
#define PIC_SSPSTAT_BIT_SMP     0x80 
 
#define PIC_SSPSTAT_BIT_CKE     0x40 
 
#define PIC_SSPSTAT_BIT_DA      0x20 
 
#define PIC_SSPSTAT_BIT_P       0x10 
 
#define PIC_SSPSTAT_BIT_S       0x08 
 
#define PIC_SSPSTAT_BIT_RW      0x04 
 
#define PIC_SSPSTAT_BIT_UA      0x02 
 
#define PIC_SSPSTAT_BIT_BF      0x01 
 
 
#define PIC_SSPCON1_BIT_WCOL    0x80 
 
#define PIC_SSPCON1_BIT_SSPOV   0x40 
 
#define PIC_SSPCON1_BIT_SSPEN   0x20 
 
#define PIC_SSPCON1_BIT_CKP     0x10 
 
#define PIC_SSPCON1_BIT_SSPM3   0x08 
 
#define PIC_SSPCON1_BIT_SSPM2   0x04 
 
#define PIC_SSPCON1_BIT_SSPM1   0x02 
 
#define PIC_SSPCON1_BIT_SSPM0   0x01 
 
 
#define PIC_SSPCON2_BIT_GCEN    0x80 
 
#define PIC_SSPCON2_BIT_ACKSTAT 0x40 
 
#define PIC_SSPCON2_BIT_ACKDT   0x20 
 
#define PIC_SSPCON2_BIT_ACKEN   0x10 
 
#define PIC_SSPCON2_BIT_RCEN    0x08 
 
#define PIC_SSPCON2_BIT_PEN     0x04 
 
#define PIC_SSPCON2_BIT_RSEN    0x02 
 
#define PIC_SSPCON2_BIT_SEN     0x01 
 
 
 
#define RX_BUF_LEN  32 
 
#define NODE_ADDR   0x02    /* I2C address of the slave node */ 
 
 
unsigned char slave_buffer[RX_BUF_LEN]; 
 
int buffer_index; 
 
int comms_error; 
 
int debug_state; 
 
 
 
void i2c_initialize(void) 
 
{ 
 
   /* Set up SSP module for 7-bit */ 
 
   PIC_SSPCON1 = 0x36;   /* 0011 0101 */ 
 
   PIC_SSPADD = NODE_ADDR;  /* Set the slave's address */ 
 
   PIC_SSPSTAT = 0x00;     /* Clear the SSPSTAT register. */ 
 
   enable_interrupts(INT_SSP);  /* Enable MSSP interrupts. */ 
 
}    
 
 
void i2c_interrupt_handler(void) 
 
{ 
 
 
    unsigned char i2c_mask = 0x2D;  /* 0010 1101 */ 
 
    unsigned char temp_sspstat; 
 
    unsigned char this_byte; 
 
    unsigned char tx_byte; 
 
    int x; 
 
    
 
    /* Mask out the unnecessary bits */ 
 
    temp_sspstat = PIC_SSPSTAT & i2c_mask; 
 
    
 
    switch (temp_sspstat) 
 
    { 
 
        /* Write operation, last byte was an address, buffer is full */ 
 
        case 0x09:   /* 0000 1001 */ 
 
            /* Clear the receive buffer */ 
 
            for (x=0; x<RX_BUF_LEN; x++) 
 
            { 
 
               slave_buffer[x] = 0x00; 
 
            } 
 
            buffer_index = 0;  /* Clear the buffer index */ 
 
            this_byte = read_i2c();   /* Do a dummy read of PIC_SSPBUF */ 
 
            
 
            debug_state = 1; 
 
            break; 
 
        
 
        /* Write operation, last byte was data, buffer is full */ 
 
        case 0x29:   /* 0010 1001 */ 
 
            /* Point to the buffer */ 
 
            this_byte = read_i2c();  /* Get the byte from the SSP */ 
 
            slave_buffer[buffer_index] = this_byte; /* Put it into the buffer */ 
 
            buffer_index++; /* Increment the buffer pointer */ 
 
            /* Get the current buffer index */ 
 
            /* Subtract the buffer length */ 
 
            /* Has the index exceeded the buffer length? */ 
 
            if (buffer_index >= RX_BUF_LEN) 
 
            { 
 
               buffer_index = 0; /* Yes, clear the buffer index. */ 
 
            } 
 
            debug_state = 2; 
 
            break; 
 
        
 
        /* Read operation; last byte was an address, buffer is empty */ 
 
        case 0x0C:   /* 0000 1100 */ 
 
            buffer_index = 0; /* Clear the buffer index */ 
 
            /* Point to the buffer */ 
 
            tx_byte = slave_buffer[buffer_index]; /* Get byte from the buffer */ 
 
            write_i2c(tx_byte); /* Write the byte to PIC_SSPBUF */ 
 
            buffer_index++; /* increment the buffer index */ 
 
            debug_state = 3; 
 
            break; 
 
        
 
        /* Read operation; last byte was data, buffer is empty */ 
 
        case 0x2C:   /* 0010 1100 */ 
 
            /* Get the current buffer index */ 
 
            /* Subtract the buffer length */ 
 
            /* Has the index exceeded the buffer length? */ 
 
            if (buffer_index >= RX_BUF_LEN) 
 
            { 
 
                buffer_index = 0; /* Yes, clear the buffer index */ 
 
            }    
 
            /* Point to the buffer */ 
 
            /* Get the byte */ 
 
            tx_byte = slave_buffer[buffer_index]; 
 
            write_i2c(tx_byte);  /* Write to PIC_SSPBUF */ 
 
            buffer_index++; /* increment the buffer index */ 
 
            debug_state = 4; 
 
            break; 
 
            
 
        /* A NACK was received when transmitting data back from the master. */ 
 
        /* Slave logic is reset in this case. R_W=0, D_A=1, and BF=0. */ 
 
        /* If we don't stop in this state, then something is wrong!! */ 
 
        case 0x28:   /* 0010 1000 */ 
 
            debug_state = 5; 
 
            break; 
 
        
 
        /* Something went wrong!! */ 
 
        default: 
 
            i2c_error(); 
 
            break; 
 
    } 
 
} 
 
 
void i2c_error(void) 
 
{ 
 
    comms_error = 1; 
 
    printf ("I2C ERROR!\r\n"); 
 
} 
 
 
void write_i2c(unsigned char transmit_byte) 
 
{  
 
    unsigned char write_collision = 1; 
 
    
 
    while (PIC_SSPSTAT & PIC_SSPSTAT_BIT_BF) /* Is BF bit set in PIC_SSPSTAT? */ 
 
    { 
 
        /* If yes, then keep waiting */ 
 
    } 
 
    
 
    while (write_collision) 
 
    { 
 
        /* If not, then do the i2c_write. */    
 
        PIC_SSPCON1 &= ~PIC_SSPCON1_BIT_WCOL;  /* Clear the WCOL flag */ 
 
        PIC_SSPBUF = transmit_byte; 
 
    
 
        /* Was there a write collision? */ 
 
        if (PIC_SSPCON1 & PIC_SSPCON1_BIT_WCOL) 
 
        { 
 
            /* Yes there was a write collision. */ 
 
            write_collision = 1; 
 
        } 
 
        else 
 
        { 
 
            /* NO, there was no write collision. */ 
 
            /* The transmission was successful */ 
 
            write_collision = 0; 
 
        } 
 
    } 
 
    PIC_SSPCON1 |= PIC_SSPCON1_BIT_CKP;  /* Release the clock. */ 
 
} 
 
 
/* This function returns the byte in SSPBUF */ 
 
unsigned char read_i2c(void) 
 
{ 
 
    return PIC_SSPBUF; 
 
} 
 
 
void main(void) 
 
{ 
 
    debug_state = 0; 
 
    i2c_initialize(); 
 
    enable_interrupts(GLOBAL); 
 
   printf("i2c slave 09 Jan 2005\n\r\n\r");
 
    
 
    while (1) 
 
    { 
 
        if (debug_state) 
 
        { 
 
            // printf ("debug state = %d\r\n", debug_state); 
 
            debug_state = 0; 
 
        } 
 
 
      
 
    } 
 
}  | 	  
 
 
MASTER CODE:
 
 
 	  | Code: | 	 		  #include <16F876A.H>
 
 
// 10-bit A/D conversion
 
#device ADC=10
 
#fuses HS,NOWDT,NOPROTECT,NOLVP
 
 
#use Delay(Clock=20000000)
 
#use rs232(baud=9600,xmit=PIN_C6,rcv=PIN_C7,brgh1ok)
 
 
#include <input.c>
 
 
#define EEPROM_SDA  PIN_C4
 
#define EEPROM_SCL  PIN_C3
 
#define SLAVE_ADDRESS 0x02
 
 
#use i2c(master, sda=EEPROM_SDA, scl=EEPROM_SCL, FORCE_HW)
 
 
void 
 
initI2C()
 
{
 
   output_float(EEPROM_SCL);
 
   output_float(EEPROM_SDA);
 
}
 
 
void
 
writeI2C(INT16 word)
 
{
 
   i2c_start(); 
 
   //delay_ms(1); 
 
   i2c_write(SLAVE_ADDRESS);  /* Device Address */ 
 
   //delay_ms(1); 
 
   i2c_write(word & 0x00ff); 
 
   //delay_ms(1);
 
   i2c_write((word & 0xff00) >> 8);
 
   //delay_ms(1);
 
   i2c_stop();
 
}
 
 
INT16
 
readI2C()
 
{
 
   BYTE b1=0, b2=0;
 
   i2c_start();   // restart condition 
 
   i2c_write(SLAVE_ADDRESS + 1); 
 
   b1 = i2c_read(1);
 
   //delay_ms(1);
 
   b2 = i2c_read(0);
 
   //delay_ms(1);
 
   i2c_stop(); 
 
   return make16(b2, b1);
 
}
 
 
INT16 gethexword() {
 
   BYTE lo,hi;
 
 
   hi = gethex();
 
   lo = gethex();
 
 
   return make16( hi,lo );
 
}
 
 
void main() {
 
 
   int cmd;
 
   INT16 value;
 
 
   initI2C();
 
 
   printf("i2c master 09 Jan 2005\n\r\n\r");
 
 
   do {
 
      do {
 
         printf("\r\nRead or Write: ");
 
         cmd=getc();
 
         cmd=toupper(cmd);
 
         putc(cmd);
 
      } while ( (cmd!='R') && (cmd!='W') );
 
 
     if(cmd=='R') {
 
        value = 0;
 
        value = readI2C();
 
        printf("\r\nValue: %lX\r\n",value );
 
     } else if(cmd=='W') {
 
         printf("\r\nNew 16-bit value: ");
 
         value = gethexword();
 
         printf("\n\r");
 
         writeI2C(value);
 
      }
 
 
   } while (TRUE);
 
} | 	 
  | 
			 
		  | 
	 
	
		  | 
	 
	
		
			picer
 
 
  Joined: 25 Jan 2005 Posts: 28 Location: Taxahoma 
			
			 
			 
			
			
			
			
			
			
			
  
		  | 
		
			
				 | 
			 
			
				 Posted: Tue Feb 08, 2005 12:42 pm     | 
				     | 
			 
			
				
  | 
			 
			
				| I just loaded both of these, slave in 819, master in 877A. I get the READ/WRITE from rs232 and when I hit W and put a value in it never returns and I have to reset the pic.  If I disconnect the two I see a quick clock pulse from the 877A and it returns to read/write, if I reconnect I see nothing at all and read/write don't work.  Looks like both data and clock on the 877A are high, both on the 819 are low with a scope on those pins.  I changed the values to the 819, looks like the only difference is the 819 doesn't have sspcon2. Any idea on where to go from here to trouble shoot, never done i2c before.  I used the examples unmodified other than commenting out sspcon2 stuff for the 819. | 
			 
		  | 
	 
	
		  | 
	 
	
		
			fuzzy
 
 
  Joined: 26 Feb 2005 Posts: 64
  
			
			 
			 
			
			
			
			
			
			
			
  
		  | 
		
			
				 | 
			 
			
				 Posted: Fri Mar 04, 2005 7:39 pm     | 
				     | 
			 
			
				
  | 
			 
			
				| when connected how is bus voltage? high or low? if low you have to put a pullup resistor on both lines, i use 5,6K and if still low you have to set TRIS high for these pins. I had problem with TRIS and i had to force CK pin high using this command: variable=input(pin_c3); in this case this pin was used as input and remained high. In normal condition I2C bus have to stay high. | 
			 
		  | 
	 
	
		  | 
	 
	
		
			raf
 
 
  Joined: 13 Mar 2005 Posts: 3 Location: Paris 
			
			 
			 
			
			
			
			
			
			
			
  
		  | 
		
			
				 | 
			 
			
				 Posted: Sun Mar 13, 2005 9:15 am     | 
				     | 
			 
			
				
  | 
			 
			
				I've load these examples for my apllication (two 18f4431 in I2c) i've changed register values and some other things but it still doesn't work. I try (in first) to send a byte from the master to the slave. I use CCS with mplab and an ICD2 programmer. 
 
I've a problem with interruption. when SSPCON=0x36 (slave mode) the interruption never happen. And when SSPCON=0x3E (slave mode + start and stop interuption) an interrupton happen with a start but it seems that SSPBUF does not receive data (BF is never set).
 
 
Please if someone knows what I can do to resolve this tell me!!!! | 
			 
		  | 
	 
	
		  | 
	 
	
		
			UFAnders
 
 
  Joined: 13 Apr 2005 Posts: 36 Location: Michigan 
			
			 
			 
			 
			 
			 
			
			
			
			
  
		  | 
		
			
				| SSP Interrupt not executing | 
			 
			
				 Posted: Sat Jun 25, 2005 3:48 pm     | 
				     | 
			 
			
				
  | 
			 
			
				Snibbe, I have no idea why I can't get your routine to work on my chip...
 
 
I have re-defined the SSP control registers to match that of the 18F2520, but for some reason the SSP interrupt always goes to the default case once I try to read data back from the slave. I can send it values fine as hyperterminal shows the correct hex numbers contained in the slave (as entered on the master side). Once I try to read anything from the slave, however, I get the "I2C ERROR".
 
 
Here are my slave's SSP registers upon trying to read from the slave:
 
 	  | Quote: | 	 		  I2C ERROR!
 
SSPBUF=11
 
SSPADD=10
 
SSPSTAT=0C
 
SSPCON1=66
 
SSPCON2=00 | 	  
 
 
Anyone ever run into this? Thanks for your help! | 
			 
		  | 
	 
	
		  | 
	 
	
		
			Phil
 
 
  Joined: 09 Sep 2003 Posts: 12
  
			
			 
			 
			
			
			
			
			
			
			
  
		  | 
		
			
				 | 
			 
			
				 Posted: Mon Jul 04, 2005 7:41 am     | 
				     | 
			 
			
				
  | 
			 
			
				Just a quick note!
 
 
For some reason I've experienced the same when trying to write to the slave. I redeclared my #use i2c to use software I2C ( took out "FORCE_HW") and that seems to do the trick. | 
			 
		  | 
	 
	
		  | 
	 
	
		
			treitmey
 
 
  Joined: 23 Jan 2004 Posts: 1094 Location: Appleton,WI   USA 
			
			 
			 
			
			 
			
			
			
			
			
  
		  | 
		
			
				 | 
			 
			
				 Posted: Wed Oct 26, 2005 7:21 am     | 
				     | 
			 
			
				
  | 
			 
			
				| If clearing the buffer is taking too much time,.. don't do it.  It should be just a matter of reseting the indexes.  Try it and see. | 
			 
		  | 
	 
	
		  | 
	 
	
		
			mcpublic
 
 
  Joined: 01 Nov 2005 Posts: 10
  
			
			 
			 
			
			
			
			
			
			
			
  
		  | 
		
			
				| Advice on porting i2c master slave example | 
			 
			
				 Posted: Tue Nov 01, 2005 1:30 pm     | 
				     | 
			 
			
				
  | 
			 
			
				Snibbe's "WORKING I2C MASTER AND SLAVE LOGGER : MULTI-BYTE" works great at 20MHz, but at slower clock speeds, you have to do one of the following:
 
 
a) Master: insert delay after i2c_write(SLAVE_ADDRESS) in writeI2C() function (a 100us delay seems to work okay at 10Mhz)
 
b) Slave: read SSPBUF before clearing slave_buffer[] in i2c_interrupt_handler() case 0x09 -- (should fix problem in theory, but I haven't tested this myself)
 
c) Slave: choose a smaller value for RX_BUF_LEN (4 works nicely).  When len=32 at 10MHz the interrupt handler takes a whopping 150us to service the address byte.  If the master sends data too fast, a fatal i2c error occurs in the slave.
 
 
I have successfully ported the slave code to an 16F876A running at 10MHz and to a 16F819 running off its internal 8MHz oscillator.  I am still debugging the 18F2525 port.  Alas, I have yet to witness an an SSP interrupt. | 
			 
		  | 
	 
	
		  | 
	 
	
		
			sonicdeejay
 
 
  Joined: 20 Dec 2005 Posts: 112
  
			
			 
			 
			
			
			
			
			
			
			
  
		  | 
		
			
				 | 
			 
			
				 Posted: Mon Feb 06, 2006 11:31 pm     | 
				     | 
			 
			
				
  | 
			 
			
				guys,,,any update on 18F2525??
 
 
 
I am planning to comunicate 2 PIC18F2525 ...
 
 
 
 	  | Code: | 	 		  * 16f87X bytes */ 
 
/* Change it per chip */ 
 
#byte PIC_SSPBUF=0x13 
 
#byte PIC_SSPADD=0x93 
 
#byte PIC_SSPSTAT=0x94 
 
#byte PIC_SSPCON1=0x14 
 
#byte PIC_SSPCON2=0x91 
 
 
/* Bit defines */ 
 
#define PIC_SSPSTAT_BIT_SMP     0x80 
 
#define PIC_SSPSTAT_BIT_CKE     0x40 
 
#define PIC_SSPSTAT_BIT_DA      0x20 
 
#define PIC_SSPSTAT_BIT_P       0x10 
 
#define PIC_SSPSTAT_BIT_S       0x08 
 
#define PIC_SSPSTAT_BIT_RW      0x04 
 
#define PIC_SSPSTAT_BIT_UA      0x02 
 
#define PIC_SSPSTAT_BIT_BF      0x01 
 
 
#define PIC_SSPCON1_BIT_WCOL    0x80 
 
#define PIC_SSPCON1_BIT_SSPOV   0x40 
 
#define PIC_SSPCON1_BIT_SSPEN   0x20 
 
#define PIC_SSPCON1_BIT_CKP     0x10 
 
#define PIC_SSPCON1_BIT_SSPM3   0x08 
 
#define PIC_SSPCON1_BIT_SSPM2   0x04 
 
#define PIC_SSPCON1_BIT_SSPM1   0x02 
 
#define PIC_SSPCON1_BIT_SSPM0   0x01 
 
 
#define PIC_SSPCON2_BIT_GCEN    0x80 
 
#define PIC_SSPCON2_BIT_ACKSTAT 0x40 
 
#define PIC_SSPCON2_BIT_ACKDT   0x20 
 
#define PIC_SSPCON2_BIT_ACKEN   0x10 
 
#define PIC_SSPCON2_BIT_RCEN    0x08 
 
#define PIC_SSPCON2_BIT_PEN     0x04 
 
#define PIC_SSPCON2_BIT_RSEN    0x02 
 
#define PIC_SSPCON2_BIT_SEN     0x01 | 	  
 
 
 
how can I change those info to suit my PIC18F2525.. | 
			 
		  | 
	 
	
		  | 
	 
	
		
			mcpublic
 
 
  Joined: 01 Nov 2005 Posts: 10
  
			
			 
			 
			
			
			
			
			
			
			
  
		  | 
		
			
				| Porting to 18F2525/4525 | 
			 
			
				 Posted: Tue Feb 07, 2006 8:01 am     | 
				     | 
			 
			
				
  | 
			 
			
				I do have an update for the 18F2525/4525.  I'm sure you can read the datasheet to get the 18F SSP register addresses.
 
 
The key difference between the 876A SSP module wrt i2c slave is that addresses below 0x20 don't work.  Microchip tech support says the engineers were just trying to adhere better to the spec, but I'm sure they wish it had been done with better documentation. | 
			 
		  | 
	 
	
		  | 
	 
	
		
			sonicdeejay
 
 
  Joined: 20 Dec 2005 Posts: 112
  
			
			 
			 
			
			
			
			
			
			
			
  
		  | 
		
			
				| Re: Porting to 18F2525/4525 | 
			 
			
				 Posted: Fri Feb 10, 2006 10:12 pm     | 
				     | 
			 
			
				
  | 
			 
			
				 	  | mcpublic wrote: | 	 		  I do have an update for the 18F2525/4525.  I'm sure you can read the datasheet to get the 18F SSP register addresses.
 
 
The key difference between the 876A SSP module wrt i2c slave is that addresses below 0x20 don't work.  Microchip tech support says the engineers were just trying to adhere better to the spec, but I'm sure they wish it had been done with better documentation. | 	  
 
 
 
This is I needa change rite?? the image is taken from PIC18F2525 datasheet.
 
 
 
  Last edited by sonicdeejay on Sat Feb 11, 2006 1:36 pm; edited 1 time in total | 
			 
		  | 
	 
	
		  | 
	 
	
		
			mcpublic
 
 
  Joined: 01 Nov 2005 Posts: 10
  
			
			 
			 
			
			
			
			
			
			
			
  
		  | 
		
			
				| Re: Porting to 18F2525/4525 | 
			 
			
				 Posted: Fri Feb 10, 2006 11:09 pm     | 
				     | 
			 
			
				
  | 
			 
			
				Yes, this is the right table of register addresses.
 
Let me know if you have any more questions.
 
FYI, almost every problem I ran into was solved
 
by adding delays between i2c master commands. | 
			 
		  | 
	 
	
		  | 
	 
	
		
			mcpublic
 
 
  Joined: 01 Nov 2005 Posts: 10
  
			
			 
			 
			
			
			
			
			
			
			
  
		  | 
		
			
				| PIC18F4525 port code | 
			 
			
				 Posted: Mon Feb 13, 2006 2:54 pm     | 
				     | 
			 
			
				
  | 
			 
			
				Here is the stripped-down hardware i2c slave code 
 
ported to a PIC18f4525 running at 10MHz (no 4x PLL!)
 
Below is the master code with some commentary
 
 
--Tim
 
 
 	  | Code: | 	 		  
 
//// i2c 16-BIT SLAVE CODE
 
 
// Author: valemike
 
 
#define UNIT_TEST
 
 
// Assumes PIC18F4525 @ 10MHz
 
 
#ifdef UNIT_TEST
 
  #include <18f4525.h>
 
 
  #fuses HS,NOLVP,NOWDT,PUT
 
 
  // Pins
 
 
  // RS-232
 
  #define RX_PIN        PIN_C7
 
  #define TX_PIN        PIN_C6
 
 
  // config
 
 
  #use delay(clock=10000000, restart_wdt)
 
  #use rs232(baud=9600, xmit=TX_PIN, rcv=RX_PIN) //+++ up baud rate?
 
 
  void main (void);
 
 
#endif // UNIT_TEST
 
 
// Prototypes
 
 
unsigned char read_i2c(void);
 
void i2c_interrupt_handler(void);
 
void i2c_initialize(void);
 
void i2c_error(unsigned int temp_sspstat);
 
void write_i2c(unsigned char transmit_byte);
 
void toggle_light(void);
 
void wait_for_bf_low(void);
 
 
#INT_SSP
 
void ssp_interupt ()
 
{
 
  i2c_interrupt_handler();
 
}
 
 
/* PIC Registers */
 
 
#byte PIC_SSPBUF   = 0xfc9
 
#byte PIC_SSPADD   = 0xfc8
 
#byte PIC_SSPSTAT  = 0xfc7
 
#byte PIC_SSPCON1  = 0xfc6
 
#byte PIC_PIE1     = 0xf9d
 
#byte PIC_TRISC    = 0xf94
 
 
#byte PIC_SSPCON2  = 0xfc5
 
 
/* Bit defines */
 
#define PIC_SSPSTAT_BIT_SMP     0x80
 
#define PIC_SSPSTAT_BIT_CKE     0x40
 
#define PIC_SSPSTAT_BIT_DA      0x20
 
#define PIC_SSPSTAT_BIT_P       0x10
 
#define PIC_SSPSTAT_BIT_S       0x08
 
#define PIC_SSPSTAT_BIT_RW      0x04
 
#define PIC_SSPSTAT_BIT_UA      0x02
 
#define PIC_SSPSTAT_BIT_BF      0x01
 
 
#define PIC_SSPCON1_BIT_WCOL    0x80
 
#define PIC_SSPCON1_BIT_SSPOV   0x40
 
#define PIC_SSPCON1_BIT_SSPEN   0x20
 
#define PIC_SSPCON1_BIT_CKP     0x10
 
#define PIC_SSPCON1_BIT_SSPM3   0x08
 
#define PIC_SSPCON1_BIT_SSPM2   0x04
 
#define PIC_SSPCON1_BIT_SSPM1   0x02
 
#define PIC_SSPCON1_BIT_SSPM0   0x01
 
 
#define PIC_SSPCON2_BIT_GCEN    0x80
 
#define PIC_SSPCON2_BIT_ACKSTAT 0x40
 
#define PIC_SSPCON2_BIT_ACKDT   0x20
 
#define PIC_SSPCON2_BIT_ACKEN   0x10
 
#define PIC_SSPCON2_BIT_RCEN    0x08
 
#define PIC_SSPCON2_BIT_PEN     0x04
 
#define PIC_SSPCON2_BIT_RSEN    0x02
 
#define PIC_SSPCON2_BIT_SEN     0x01
 
 
/* Parameters */
 
 
#define RX_BUF_LEN  4 //8 //32
 
#define LOGBUF_MASK 0x07
 
#define NODE_ADDR   0x20 /* I2C address of the slave node (avoid addr masking) */
 
 
unsigned char slave_buffer[RX_BUF_LEN];
 
 
int buffer_index;
 
int comms_error;
 
int debug_state;
 
 
void i2c_initialize(void)
 
{
 
  debug_state = 0;
 
 
  /* Set up SSP module for 7-bit */
 
  while (PIC_SSPCON2 & 0x1f) {
 
    // ACKEN RCEN PEN RSEN SEN all must be zero
 
  };
 
  PIC_SSPSTAT = 0x00;     /* Clear the SSPSTAT register. */
 
  PIC_SSPCON1 = 0x36;   /* 0011 0101 */
 
  PIC_SSPADD = NODE_ADDR;  /* Set the slave's address */
 
  /* init buffers */
 
  buffer_index = 0;
 
  /* Go */
 
  enable_interrupts(INT_SSP);  /* Enable MSSP interrupts. */
 
}   
 
 
void i2c_interrupt_handler(void)
 
{
 
 
    unsigned char i2c_mask = 0x2D;  /* 0010 1101 */
 
    unsigned char temp_sspstat;
 
    unsigned char this_byte;
 
    unsigned char tx_byte;
 
    int x;
 
   
 
    //toggle_light(); //DBG
 
 
    /* log SSPSTAT */
 
 
    /* Mask out the unnecessary bits */
 
    temp_sspstat = PIC_SSPSTAT & i2c_mask;
 
   
 
    switch (temp_sspstat) {
 
      /* Write operation, last byte was an address, buffer is full */
 
    case 0x09:   /* 0000 1001 */
 
      /* Clear the receive buffer */
 
      for (x=0; x<RX_BUF_LEN; x++)
 
   {
 
     slave_buffer[x] = 0x00;
 
   }
 
      buffer_index = 0;  /* Clear the buffer index */
 
      this_byte = read_i2c();   /* Do a dummy read of PIC_SSPBUF */
 
           
 
      debug_state = 1;
 
      break;
 
       
 
      /* Write operation, last byte was data, buffer is full */
 
    case 0x29:   /* 0010 1001 */
 
      /* Point to the buffer */
 
      this_byte = read_i2c();  /* Get the byte from the SSP */
 
      slave_buffer[buffer_index] = this_byte; /* Put it into the buffer */
 
      buffer_index++; /* Increment the buffer pointer */
 
#ifdef I2C_DAEMON
 
      // If enough data is in, this would move it to application's double buffer
 
      i2c_double_buffer_daemon();
 
#endif // I2C_DAEMON
 
      /* Get the current buffer index */
 
      /* Subtract the buffer length */
 
      /* Has the index exceeded the buffer length? */
 
      if (buffer_index >= RX_BUF_LEN)
 
   {
 
     buffer_index = 0; /* Yes, clear the buffer index. */
 
   }
 
      debug_state = 2;
 
      break;
 
       
 
      /* Read operation; last byte was an address, buffer is empty */
 
    case 0x0C:   /* 0000 1100 */
 
    label_0c:
 
      buffer_index = 0; /* Clear the buffer index */
 
      /* Point to the buffer */
 
      tx_byte = slave_buffer[buffer_index]; /* Get byte from the buffer */
 
      write_i2c(tx_byte); /* Write the byte to PIC_SSPBUF */
 
      buffer_index++; /* increment the buffer index */
 
      debug_state = 3;
 
      break;
 
       
 
      /* Read operation; last byte was data, buffer is empty */
 
    case 0x2C:   /* 0010 1100 */
 
      /* Get the current buffer index */
 
      /* Subtract the buffer length */
 
      /* Has the index exceeded the buffer length? */
 
      if (buffer_index >= RX_BUF_LEN)
 
   {
 
     buffer_index = 0; /* Yes, clear the buffer index */
 
   }   
 
      /* Point to the buffer */
 
      /* Get the byte */
 
      tx_byte = slave_buffer[buffer_index];
 
      write_i2c(tx_byte);  /* Write to PIC_SSPBUF */
 
      buffer_index++; /* increment the buffer index */
 
      debug_state = 4;
 
      break;
 
           
 
      /* A NACK was received when transmitting data back [to] the master. */
 
      /* Slave logic is reset in this case. R_W=0, D_A=1, and BF=0. */
 
      /* If we don't stop in this state, then something is wrong!! */
 
    case 0x28:   /* 0010 1000 */
 
      debug_state = 5;
 
      break;
 
       
 
      /* Read operation; last byte was address, buffer is full */
 
    case 0x0d:
 
      this_byte = read_i2c();   // Do a dummy read of PIC_SSPBUF to clear it
 
      wait_for_bf_low();
 
      goto label_0c; // reduced to the normal case
 
      /* Something went wrong!! */
 
    default:
 
      debug_state = 0xe;
 
      break;
 
    }
 
    //red_light(); //DBG
 
}
 
 
unsigned int error_sspstat;
 
 
void i2c_error(unsigned int temp_sspstat)
 
{
 
    comms_error = 1;
 
    error_sspstat = temp_sspstat;
 
}
 
 
void write_i2c(unsigned char transmit_byte)
 
{ 
 
    unsigned char write_collision = 1;
 
   
 
    while (PIC_SSPSTAT & PIC_SSPSTAT_BIT_BF) /* Is BF bit set in PIC_SSPSTAT? */
 
    {
 
        /* If yes, then keep waiting */
 
    }
 
   
 
    while (write_collision)
 
    {
 
        /* If not, then do the i2c_write. */   
 
        PIC_SSPCON1 &= ~PIC_SSPCON1_BIT_WCOL;  /* Clear the WCOL flag */
 
        PIC_SSPBUF = transmit_byte;
 
   
 
        /* Was there a write collision? */
 
        if (PIC_SSPCON1 & PIC_SSPCON1_BIT_WCOL)
 
        {
 
            /* Yes there was a write collision. */
 
            write_collision = 1;
 
        }
 
        else
 
        {
 
            /* NO, there was no write collision. */
 
            /* The transmission was successful */
 
            write_collision = 0;
 
        }
 
    }
 
    PIC_SSPCON1 |= PIC_SSPCON1_BIT_CKP;  /* Release the clock. */
 
}
 
 
/* This function returns the byte in SSPBUF */
 
unsigned char read_i2c(void)
 
{
 
    return PIC_SSPBUF;
 
}
 
 
#ifdef UNIT_TEST
 
void main (void)
 
{
 
  debug_state = 0;
 
  i2c_initialize();
 
  enable_interrupts(GLOBAL);
 
   
 
 main_loop:
 
  //while (1)
 
  {
 
    if (debug_state)
 
      {
 
   debug_state = 0;
 
      }
 
  goto main_loop;
 
  }
 
}
 
#endif // UNIT_TEST
 
 
void wait_for_bf_low(void)
 
{
 
 bf_loop:
 
  if (PIC_SSPSTAT & 0x1) { //BF=1
 
    goto bf_loop;
 
  }
 
  else {
 
  }
 
}
 
 | 	  
 
 
Here is the stripped-down master code.
 
In UNIT_TEST mode, it automatically tests
 
to see if the whole system works.
 
If it sees nacks, it reports that.
 
Usually this means the slave missed
 
some or all the commands sent by the 
 
master.  If it missed all the commands
 
(3 nacks) then maybe the slave is totally dead
 
or wrong address.  If it only misses one
 
or two commands (e.g. 1 nack) then it is
 
probably a timing issue.  Add delays in the
 
master.
 
 
 	  | Code: | 	 		  
 
//// i2c 16-BIT MASTER CODE
 
 
// Author: snibbe
 
 
/* This is pasted straight from my working programs. Thanks especially
 
to "valemike". The slave is primarily his code. The master is modified
 
from EX_EXTEE. */
 
 
#define UNIT_TEST
 
//#define SYNC_TEST // test double buffering
 
 
// Assumes PIC18F4525 @ 10MHz
 
 
#ifdef UNIT_TEST
 
 
  #include <18f4525.h>
 
 
  #fuses HS,NOLVP,NOWDT,PUT
 
 
  // Pins
 
 
  // RS-232
 
  #define RX_PIN        PIN_C7
 
  #define TX_PIN        PIN_C6
 
 
  // config
 
 
  #use delay(clock=10000000, restart_wdt)
 
  #use rs232(baud=9600, xmit=TX_PIN, rcv=RX_PIN) //+++ up baud rate?
 
 
  // conditional proto
 
 
  void main (void);
 
 
#endif // UNIT_TEST
 
 
#define SLAVE_ADDRESS 0x20 // addr=2 reserved, note address masking
 
 
#define EEPROM_SDA  PIN_C4
 
#define EEPROM_SCL  PIN_C3
 
 
#use i2c(master, sda=EEPROM_SDA, scl=EEPROM_SCL, FORCE_HW)
 
 
#byte PIC_SSPCON2  = 0xfc5
 
 
// 1/9/2006 ** needed longer delay to work at 10MHz
 
#define I2C_DELAY_US           16 // worked 20 //Worked 32 //75 //100
 
#define I2C_INTERBYTE_DELAY_US 60 // worked 80
 
 
int i2c_nack;
 
 
// Protos
 
 
void initI2C (void);
 
void writeI2C (int16 word, unsigned int slave_addr);
 
int16 readI2C (unsigned int slave_addr);
 
 
// code
 
 
void initI2C (void)
 
{
 
   output_float(EEPROM_SCL);
 
   output_float(EEPROM_SDA);
 
}
 
 
void writeI2C (int16 word, unsigned int slave_addr)
 
{
 
   i2c_nack=0;
 
   i2c_start();
 
   delay_us(I2C_DELAY_US);
 
   i2c_write(slave_addr);  /* Device Address */
 
   if (PIC_SSPCON2 & 0x40) i2c_nack++;
 
   delay_us(I2C_INTERBYTE_DELAY_US);
 
   i2c_write(word & 0x00ff);            //LSB first
 
   if (PIC_SSPCON2 & 0x40) i2c_nack++;
 
   delay_us(I2C_INTERBYTE_DELAY_US);
 
   i2c_write((word & 0xff00) >> 8);     //MSB second
 
   if (PIC_SSPCON2 & 0x40) i2c_nack++;
 
   delay_us(I2C_DELAY_US);
 
   i2c_stop();
 
}
 
 
int16 readI2C (unsigned int slave_addr)
 
{
 
   BYTE b1=0, b2=0;
 
   i2c_nack=0;
 
   i2c_start();   // restart condition
 
   delay_us(I2C_DELAY_US);
 
   i2c_write(slave_addr + 1);
 
   if (PIC_SSPCON2 & 0x40) i2c_nack++;
 
   delay_us(I2C_INTERBYTE_DELAY_US);
 
   b1 = i2c_read(1);
 
   if (PIC_SSPCON2 & 0x40) i2c_nack++;
 
   delay_us(I2C_INTERBYTE_DELAY_US);
 
   b2 = i2c_read(0);
 
   if (PIC_SSPCON2 & 0x40) i2c_nack++;
 
   delay_us(I2C_DELAY_US);
 
   i2c_stop();
 
   return make16(b2, b1);
 
}
 
 
#ifdef UNIT_TEST
 
  #ifndef SYNC_TEST
 
    #define TEST_VAL 0x1234
 
  #else // SYNC_TEST
 
    #define TEST_VAL1 0xfb2d // LSB: distance=45 MSB: slope=-5
 
    #define TEST_VAL2 0x0d19 // LSB: distance=25 MSB: slope=13
 
    #define TEST_VAL3 0xe019 // LSB: distance=25 MSB: slope=-20
 
  #endif //~SYNC_TEST
 
 
void main () 
 
{
 
#ifndef SYNC_TEST
 
  int16 value;
 
#endif //~SYNC_TEST
 
 
  // wait for LCD to boot
 
  putc('4');
 
  delay_ms(1000); 
 
  putc('3');
 
  delay_ms(1000); 
 
  putc('2');
 
  delay_ms(1000); 
 
  putc('1');
 
  delay_ms(1000); 
 
 
  puts ("");
 
  puts ("i2c unit test");
 
  puts (__DATE__ " " __TIME__);
 
 
  // Initialize
 
  initI2C();
 
 
#ifdef SYNC_TEST
 
 
 sync_loop:
 
 
  writeI2C(TEST_VAL1, SLAVE_ADDRESS);
 
  if (i2c_nack) {
 
    printf("%d nacks on write 1\r\n", i2c_nack);
 
  }
 
  else {
 
    puts("Successful write 1");
 
  }
 
  delay_us(333);
 
 
  writeI2C(TEST_VAL2, SLAVE_ADDRESS);
 
  if (i2c_nack) {
 
    printf("%d nacks on write 2\r\n", i2c_nack);
 
  }
 
  else {
 
    puts("Successful write 2");
 
  }
 
  delay_us(333);
 
 
  writeI2C(TEST_VAL3, SLAVE_ADDRESS);
 
  if (i2c_nack) {
 
    printf("%d nacks on write 3\r\n", i2c_nack);
 
  }
 
  else {
 
    puts("Successful write 3");
 
  }
 
  delay_us(333);
 
 
  goto sync_loop;
 
 
#else //~SYNC_TEST
 
 
  // Write
 
  value = TEST_VAL;
 
  writeI2C(value, SLAVE_ADDRESS);
 
  if (i2c_nack) {
 
    printf("%d nack(s) on write\r\n", i2c_nack);
 
  }
 
  else {
 
    puts("Successful write");
 
  }
 
 
  // Read
 
  value = 0;
 
  value = readI2C(SLAVE_ADDRESS);
 
  if (value == TEST_VAL) {
 
    puts("Successful read!");
 
  }
 
  else {
 
    printf("Failed read: %lX\r\n", value);
 
  }
 
  if (i2c_nack) {
 
    printf("%d nack(s) on read\r\n", i2c_nack);
 
  }
 
#endif // SYNC_TEST
 
}
 
#endif // UNIT_TEST
 
 | 	 
  | 
			 
		  | 
	 
	
		  | 
	 
	
		
			mcpublic
 
 
  Joined: 01 Nov 2005 Posts: 10
  
			
			 
			 
			
			
			
			
			
			
			
  
		  | 
		
			
				| Debugging this i2c code -- you will want to use a scope! | 
			 
			
				 Posted: Mon Feb 13, 2006 3:13 pm     | 
				     | 
			 
			
				
  | 
			 
			
				I would not have gotten anywhere porting this i2c code to different processors and different clock speeeds if I didn't (a) have an understanding of i2c signalling (especially the ack/clock-stretching at the end of each "packet"), and (b) if I didn't have a scope to watch the i2c clock and data lines.
 
 
You might get lucky, and this will all "just work" but I feel obliged to warn folks who don't have much hardware experience that this code is not really "plug-and-play."  In particular, the PIC i2c hardware is incredible timing sensitive.  
 
 
Also, not all PIC SSP modules are the same.  There was a significant "upgrate" from the PIC16F876A to the later PIC18F series.   This is why the code originally posted on this forum didn't work without changing the slave address.  
 
 
Note that some SSP modules are "slave only" meaning they expect you to do all the master stuff in software.  This is fine as long as you aren't doing multiple-master stuff.  The nack detection is probably not doable in software, but if it is, it would be a pain.
 
 
I found the following technique useful.  It let me see with a scope if the slave's interrupt routine was taking too long.  Three probes: SDA_PIN, SCL_PIN, and RED_LED_PIN.  If the interrupt routine doesn't finish until the next packet, you need to shorten it.  E.g. don't clear buffer, just reset pointer, as previously noted. (Yes, I noticed that interrupt is misspelled as "interupt", but the compiler doesn't care).
 
 
 	  | Code: | 	 		  #INT_SSP
 
void ssp_interupt ()
 
{
 
  #use fast_io(LED_PORT)
 
  output_high(RED_LED_PIN);
 
  i2c_interrupt_handler();
 
  output_low(RED_LED_PIN);
 
  #use standard_io(LED_PORT)
 
}
 
 | 	 
  | 
			 
		  | 
	 
	
		  | 
	 
	
		
			Ken481
 
 
  Joined: 27 Mar 2006 Posts: 5
  
			
			 
			 
			
			
			
			
			
			
			
  
		  | 
		
			
				| I2C works fine when ICD is plugged in, but not without | 
			 
			
				 Posted: Mon Mar 27, 2006 12:37 pm     | 
				     | 
			 
			
				
  | 
			 
			
				I can Write any 16-bit word to the slave and Read it back just fine on the master when the ICD is plugged in to the slave board.  But when I unplug the ICD from the slave board, I Read FFFF.   The slave is a 16F877A running at 20Mhz and the master is a 18F252 running at 10Mhz.  Whether the ICD program is launched or closed, I get this same result.  Is the #byte PIC_TRISC = 0x87 statement correct? Also, I don't know if it is relevant but the voltage on the MCLR pin to Gnd is 4.00V when the ICD is plugged in and 5.00V when not plugged in.  
 
 
[code][ i2c 16-BIT SLAVE CODE
 
 
// Author: valemike
 
 
#define UNIT_TEST
 
 
// Assumes PIC18F4525 @ 10MHz
 
 
#ifdef UNIT_TEST
 
  //#include <18f4525.h>
 
    #include <16F877A.h>
 
 
  #fuses HS,NOLVP,NOWDT,PUT
 
 
  // Pins
 
 
  // RS-232
 
  #define RX_PIN        PIN_C7
 
  #define TX_PIN        PIN_C6
 
 
  // config
 
 
  #use delay(clock=10000000, restart_wdt)
 
  #use rs232(baud=9600, xmit=TX_PIN, rcv=RX_PIN) //+++ up baud rate?
 
  //#use rs232(DEBUGGER)
 
  void main (void);
 
 
#endif // UNIT_TEST
 
 
// Prototypes
 
 
unsigned char read_i2c(void);
 
void i2c_interrupt_handler(void);
 
void i2c_initialize(void);
 
void i2c_error(unsigned int temp_sspstat);
 
void write_i2c(unsigned char transmit_byte);
 
void toggle_light(void);
 
void wait_for_bf_low(void);
 
 
#INT_SSP
 
void ssp_interupt ()
 
{
 
  i2c_interrupt_handler();
 
}
 
 
/* PIC Registers */
 
#byte PIC_SSPBUF=0x13
 
#byte PIC_SSPADD=0x93
 
#byte PIC_SSPSTAT=0x94
 
#byte PIC_SSPCON1=0x14
 
#byte PIC_SSPCON2=0x91
 
 
#byte PIC_PIE1     = 0x8c
 
#byte PIC_TRISC    = 0x87
 
 
 
 
/* Bit defines */
 
#define PIC_SSPSTAT_BIT_SMP     0x80
 
#define PIC_SSPSTAT_BIT_CKE     0x40
 
#define PIC_SSPSTAT_BIT_DA      0x20
 
#define PIC_SSPSTAT_BIT_P       0x10
 
#define PIC_SSPSTAT_BIT_S       0x08
 
#define PIC_SSPSTAT_BIT_RW      0x04
 
#define PIC_SSPSTAT_BIT_UA      0x02
 
#define PIC_SSPSTAT_BIT_BF      0x01
 
 
#define PIC_SSPCON1_BIT_WCOL    0x80
 
#define PIC_SSPCON1_BIT_SSPOV   0x40
 
#define PIC_SSPCON1_BIT_SSPEN   0x20
 
#define PIC_SSPCON1_BIT_CKP     0x10
 
#define PIC_SSPCON1_BIT_SSPM3   0x08
 
#define PIC_SSPCON1_BIT_SSPM2   0x04
 
#define PIC_SSPCON1_BIT_SSPM1   0x02
 
#define PIC_SSPCON1_BIT_SSPM0   0x01
 
 
#define PIC_SSPCON2_BIT_GCEN    0x80
 
#define PIC_SSPCON2_BIT_ACKSTAT 0x40
 
#define PIC_SSPCON2_BIT_ACKDT   0x20
 
#define PIC_SSPCON2_BIT_ACKEN   0x10
 
#define PIC_SSPCON2_BIT_RCEN    0x08
 
#define PIC_SSPCON2_BIT_PEN     0x04
 
#define PIC_SSPCON2_BIT_RSEN    0x02
 
#define PIC_SSPCON2_BIT_SEN     0x01
 
 
/* Parameters */
 
 
#define RX_BUF_LEN  8 //8 //32
 
#define LOGBUF_MASK 0x07
 
#define NODE_ADDR   0x02 /* I2C address of the slave node (avoid addr masking) */
 
 
unsigned char slave_buffer[RX_BUF_LEN];
 
 
int buffer_index;
 
int comms_error;
 
int debug_state;
 
 
void i2c_initialize(void)
 
{
 
  debug_state = 0;
 
 
  /* Set up SSP module for 7-bit */
 
  while (PIC_SSPCON2 & 0x1f) {
 
    // ACKEN RCEN PEN RSEN SEN all must be zero
 
  };
 
  PIC_SSPSTAT = 0x00;     /* Clear the SSPSTAT register. */
 
  PIC_SSPCON1 = 0x36;   /* 0011 0101 */
 
  PIC_SSPADD = NODE_ADDR;  /* Set the slave's address */
 
  /* init buffers */
 
  buffer_index = 0;
 
  /* Go */
 
  enable_interrupts(INT_SSP);  /* Enable MSSP interrupts. */
 
}
 
 
void i2c_interrupt_handler(void)
 
{
 
 
    unsigned char i2c_mask = 0x2D;  /* 0010 1101 */
 
    unsigned char temp_sspstat;
 
    unsigned char this_byte;
 
    unsigned char tx_byte;
 
    int x;
 
 
    //toggle_light(); //DBG
 
 
    /* log SSPSTAT */
 
 
    /* Mask out the unnecessary bits */
 
    temp_sspstat = PIC_SSPSTAT & i2c_mask;
 
 
    switch (temp_sspstat) {
 
      /* Write operation, last byte was an address, buffer is full */
 
    case 0x09:   /* 0000 1001 */
 
      /* Clear the receive buffer */
 
      for (x=0; x<RX_BUF_LEN; x++)
 
   {
 
     slave_buffer[x] = 0x00;
 
   }
 
      buffer_index = 0;  /* Clear the buffer index */
 
      this_byte = read_i2c();   /* Do a dummy read of PIC_SSPBUF */
 
 
      debug_state = 1;
 
      break;
 
 
      /* Write operation, last byte was data, buffer is full */
 
    case 0x29:   /* 0010 1001 */
 
      /* Point to the buffer */
 
      this_byte = read_i2c();  /* Get the byte from the SSP */
 
      slave_buffer[buffer_index] = this_byte; /* Put it into the buffer */
 
      buffer_index++; /* Increment the buffer pointer */
 
#ifdef I2C_DAEMON
 
      // If enough data is in, this would move it to application's double buffer
 
      i2c_double_buffer_daemon();
 
#endif // I2C_DAEMON
 
      /* Get the current buffer index */
 
      /* Subtract the buffer length */
 
      /* Has the index exceeded the buffer length? */
 
      if (buffer_index >= RX_BUF_LEN)
 
   {
 
     buffer_index = 0; /* Yes, clear the buffer index. */
 
   }
 
      debug_state = 2;
 
      break;
 
 
      /* Read operation; last byte was an address, buffer is empty */
 
    case 0x0C:   /* 0000 1100 */
 
    label_0c:
 
      buffer_index = 0; /* Clear the buffer index */
 
      /* Point to the buffer */
 
      tx_byte = slave_buffer[buffer_index]; /* Get byte from the buffer */
 
      write_i2c(tx_byte); /* Write the byte to PIC_SSPBUF */
 
      buffer_index++; /* increment the buffer index */
 
      debug_state = 3;
 
      break;
 
 
      /* Read operation; last byte was data, buffer is empty */
 
    case 0x2C:   /* 0010 1100 */
 
      /* Get the current buffer index */
 
      /* Subtract the buffer length */
 
      /* Has the index exceeded the buffer length? */
 
      if (buffer_index >= RX_BUF_LEN)
 
   {
 
     buffer_index = 0; /* Yes, clear the buffer index */
 
   }
 
      /* Point to the buffer */
 
      /* Get the byte */
 
      tx_byte = slave_buffer[buffer_index];
 
      write_i2c(tx_byte);  /* Write to PIC_SSPBUF */
 
      buffer_index++; /* increment the buffer index */
 
      debug_state = 4;
 
      break;
 
 
      /* A NACK was received when transmitting data back [to] the master. */
 
      /* Slave logic is reset in this case. R_W=0, D_A=1, and BF=0. */
 
      /* If we don't stop in this state, then something is wrong!! */
 
    case 0x28:   /* 0010 1000 */
 
      debug_state = 5;
 
      break;
 
 
      /* Read operation; last byte was address, buffer is full */
 
    case 0x0d:
 
      this_byte = read_i2c();   // Do a dummy read of PIC_SSPBUF to clear it
 
      wait_for_bf_low();
 
      goto label_0c; // reduced to the normal case
 
      /* Something went wrong!! */
 
    default:
 
      debug_state = 0xe;
 
      break;
 
    }
 
    //red_light(); //DBG
 
}
 
 
unsigned int error_sspstat;
 
 
void i2c_error(unsigned int temp_sspstat)
 
{
 
    comms_error = 1;
 
    error_sspstat = temp_sspstat;
 
}
 
 
void write_i2c(unsigned char transmit_byte)
 
{
 
    unsigned char write_collision = 1;
 
 
    while (PIC_SSPSTAT & PIC_SSPSTAT_BIT_BF) /* Is BF bit set in PIC_SSPSTAT? */
 
    {
 
        /* If yes, then keep waiting */
 
    }
 
 
    while (write_collision)
 
    {
 
        /* If not, then do the i2c_write. */
 
        PIC_SSPCON1 &= ~PIC_SSPCON1_BIT_WCOL;  /* Clear the WCOL flag */
 
        PIC_SSPBUF = transmit_byte;
 
 
        /* Was there a write collision? */
 
        if (PIC_SSPCON1 & PIC_SSPCON1_BIT_WCOL)
 
        {
 
            /* Yes there was a write collision. */
 
            write_collision = 1;
 
        }
 
        else
 
        {
 
            /* NO, there was no write collision. */
 
            /* The transmission was successful */
 
            write_collision = 0;
 
        }
 
    }
 
    PIC_SSPCON1 |= PIC_SSPCON1_BIT_CKP;  /* Release the clock. */
 
}
 
 
/* This function returns the byte in SSPBUF */
 
unsigned char read_i2c(void)
 
{
 
    return PIC_SSPBUF;
 
}
 
 
#ifdef UNIT_TEST
 
void main (void)
 
{
 
  debug_state = 0;
 
  i2c_initialize();
 
  enable_interrupts(GLOBAL);
 
 
 main_loop:
 
  //while (1)
 
  {
 
    if (debug_state)
 
      {
 
   debug_state = 0;
 
      }
 
  goto main_loop;
 
  }
 
}
 
#endif // UNIT_TEST
 
 
void wait_for_bf_low(void)
 
{
 
 bf_loop:
 
  if (PIC_SSPSTAT & 0x1) { //BF=1
 
    goto bf_loop;
 
  }
 
  else {
 
  }
 
}
 
]
 
 
 
 
 
 
master code:
 
 
 
//// i2c 16-BIT MASTER CODE
 
 
// Author: snibbe
 
 
/* This is pasted straight from my working programs. Thanks especially
 
to "valemike". The slave is primarily his code. The master is modified
 
from EX_EXTEE. */
 
 
#define UNIT_TEST
 
//#define SYNC_TEST // test double buffering
 
 
// Assumes PIC18F4525 @ 10MHz
 
 
#ifdef UNIT_TEST
 
 
  //#include <18f4525.h>
 
  #include <18f252.h>
 
  #fuses HS,NOLVP,NOWDT,PUT
 
 
  // Pins
 
 
  // RS-232
 
  #define RX_PIN        PIN_C7
 
  #define TX_PIN        PIN_C6
 
 
  // config
 
 
  #use delay(clock=10000000, restart_wdt)
 
  #use rs232(baud=9600, xmit=TX_PIN, rcv=RX_PIN) //+++ up baud rate?
 
 
  // conditional proto
 
 
  void main (void);
 
 
#endif // UNIT_TEST
 
 
#define SLAVE_ADDRESS 0x02 // addr=2 reserved, note address masking
 
 
#define EEPROM_SDA  PIN_C4
 
#define EEPROM_SCL  PIN_C3
 
 
#use i2c(master, sda=EEPROM_SDA, scl=EEPROM_SCL, FORCE_HW)
 
 
#byte PIC_SSPCON2  = 0x91
 
 
// 1/9/2006 ** needed longer delay to work at 10MHz
 
#define I2C_DELAY_US           16 // worked 20 //Worked 32 //75 //100
 
#define I2C_INTERBYTE_DELAY_US 60 // worked 80
 
 
int i2c_nack;
 
 
// Protos
 
 
void initI2C (void);
 
void writeI2C (int16 word, unsigned int slave_addr);
 
int16 readI2C (unsigned int slave_addr);
 
 
// code
 
 
void initI2C (void)
 
{
 
   output_float(EEPROM_SCL);
 
   output_float(EEPROM_SDA);
 
}
 
 
void writeI2C (int16 word, unsigned int slave_addr)
 
{
 
   i2c_nack=0;
 
   i2c_start();
 
   delay_us(I2C_DELAY_US);
 
   i2c_write(slave_addr);  /* Device Address */
 
   if (PIC_SSPCON2 & 0x40) i2c_nack++;
 
   delay_us(I2C_INTERBYTE_DELAY_US);
 
   i2c_write(word & 0x00ff);            //LSB first
 
   if (PIC_SSPCON2 & 0x40) i2c_nack++;
 
   delay_us(I2C_INTERBYTE_DELAY_US);
 
   i2c_write((word & 0xff00) >> 8);     //MSB second
 
   if (PIC_SSPCON2 & 0x40) i2c_nack++;
 
   delay_us(I2C_DELAY_US);
 
   i2c_stop();
 
}
 
 
int16 readI2C (unsigned int slave_addr)
 
{
 
   BYTE b1=0, b2=0;
 
   i2c_nack=0;
 
   i2c_start();   // restart condition
 
   delay_us(I2C_DELAY_US);
 
   i2c_write(slave_addr + 1);
 
   if (PIC_SSPCON2 & 0x40) i2c_nack++;
 
   delay_us(I2C_INTERBYTE_DELAY_US);
 
   b1 = i2c_read(1);
 
   if (PIC_SSPCON2 & 0x40) i2c_nack++;
 
   delay_us(I2C_INTERBYTE_DELAY_US);
 
   b2 = i2c_read(0);
 
   if (PIC_SSPCON2 & 0x40) i2c_nack++;
 
   delay_us(I2C_DELAY_US);
 
   i2c_stop();
 
   return make16(b2, b1);
 
}
 
 
#ifdef UNIT_TEST
 
  #ifndef SYNC_TEST
 
    #define TEST_VAL 0x1234
 
  #else // SYNC_TEST
 
    #define TEST_VAL1 0xfb2d // LSB: distance=45 MSB: slope=-5
 
    #define TEST_VAL2 0x0d19 // LSB: distance=25 MSB: slope=13
 
    #define TEST_VAL3 0xe019 // LSB: distance=25 MSB: slope=-20
 
  #endif //~SYNC_TEST
 
 
void main ()
 
{
 
#ifndef SYNC_TEST
 
  int16 value;
 
#endif //~SYNC_TEST
 
 
  // wait for LCD to boot
 
  putc('4');
 
  delay_ms(1000);
 
  putc('3');
 
  delay_ms(1000);
 
  putc('2');
 
  delay_ms(1000);
 
  putc('1');
 
  delay_ms(1000);
 
 
  puts ("");
 
  puts ("i2c unit test");
 
  puts (__DATE__ " " __TIME__);
 
 
  // Initialize
 
  initI2C();
 
 
#ifdef SYNC_TEST
 
 
 sync_loop:
 
 
  writeI2C(TEST_VAL1, SLAVE_ADDRESS);
 
  if (i2c_nack) {
 
    printf("%d nacks on write 1\r\n", i2c_nack);
 
  }
 
  else {
 
    puts("Successful write 1");
 
  }
 
  delay_us(333);
 
 
  writeI2C(TEST_VAL2, SLAVE_ADDRESS);
 
  if (i2c_nack) {
 
    printf("%d nacks on write 2\r\n", i2c_nack);
 
  }
 
  else {
 
    puts("Successful write 2");
 
  }
 
  delay_us(333);
 
 
  writeI2C(TEST_VAL3, SLAVE_ADDRESS);
 
  if (i2c_nack) {
 
    printf("%d nacks on write 3\r\n", i2c_nack);
 
  }
 
  else {
 
    puts("Successful write 3");
 
  }
 
  delay_us(333);
 
 
  goto sync_loop;
 
 
#else //~SYNC_TEST
 
 
  // Write
 
  value = TEST_VAL;
 
  writeI2C(value, SLAVE_ADDRESS);
 
  if (i2c_nack) {
 
    printf("%d nack(s) on write\r\n", i2c_nack);
 
  }
 
  else {
 
    puts("Successful write");
 
  }
 
 
  // Read
 
  value = 0;
 
  value = readI2C(SLAVE_ADDRESS);
 
  if (value == TEST_VAL) {
 
    puts("Successful read!");
 
  }
 
  else {
 
    printf("Failed read: %lX\r\n", value);
 
  }
 
  if (i2c_nack) {
 
    printf("%d nack(s) on read\r\n", i2c_nack);
 
  }
 
#endif // SYNC_TEST
 
}
 
#endif // UNIT_TEST | 
			 
		  | 
	 
	
		  | 
	 
	
		 | 
	 
 
  
	 
	    
	   | 
	
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
  
		 |