// Credit where its due : seeprom routines i have converted Peter Daneegers software bit bang routines to hard i2c with minor changes. /* I2C Status Message Codes (Master mode) */ #define START_TXD 0x08 /* Start condition for bus transmited */ #define REPEAT_START_TXD 0x10 /* Repeated Start condition for bus transmited */ #define ADDRESS_TXD_ACK 0x18 /* Address plus write sent, ack received */ #define ADDRESS_TXD_NOACK 0x20 /* Address plus write sent, NO ack received! */ #define DATA_TXD_ACK 0x28 /* Data sent, ack received */ #define DATA_TXD_NOACK 0x30 /* Data sent, NO ack received! */ #define ARB_LOST 0x38 /* I2C Master Arbitration Lost */ #define ADDRESS_RXD_ACK 0x40 /* Address plus read sent, ack received */ #define ADDRESS_RXD_NOACK 0x48 /* Address plus read sent, NO ack received! */ #define DATA_RXD_ACK 0x50 /* Data received, ack sent */ #define DATA_RXD_NOACK 0x58 /* Data received, NO ack sent! */ // I2CON Register bit values for bit masking operations. #define I2B_I2EN 0x40 #define I2B_STA 0x20 #define I2B_STO 0x10 #define I2B_SI 0x08 #define I2B_AA 0x04 #define I2BX_I2EN 0xBF #define I2BX_STA 0xDF #define I2BX_STO 0xEF #define I2BX_SI 0xF7 #define I2BX_AA 0xFB // Page size of eeprom 2^n here 2^3=8 #define WRITEPAGE 3 // Function protypes. bit hi2c_in(bit, uchar *); bit hi2c_out(uchar); bit hi2c_stop(void); bit hi2c_start(void); bit read_pcf8591(uchar *, uchar); bit Seepromwrite( uint adr, uchar *s, uchar n ); bit Seepromread( uint adr, uchar *s, uchar n ); // Generates start condition on i2c bus returns 1 if error else returns 0. bit hi2c_start(void) { I2CON=0x00; // I2C speed set using I2SCL & I2SCH I2CON|=I2B_I2EN; // Enable I2C Bus. I2CON|=I2B_STA; // Send Start condition. while (!(I2CON & I2B_SI) ); // Wait for si. if ( (I2STA!= START_TXD) && (I2STA!=REPEAT_START_TXD)) // If Status not as expected. { I2CON&=I2BX_STA; // Clear start bit; I2CON|=I2B_STO; // Send stop stop condition. I2CON&=I2BX_SI; // Clear SI. while ( I2CON & I2B_STO ); // Wait till hardware clears stop bit. I2CON&=I2BX_I2EN; // Disable I2C Bus. return 1; // return error. } I2CON&=I2BX_STA; // Clear start bit; return 0; } // Generates stop condition returns 1 if error else 0. bit hi2c_stop(void) { I2CON|=I2B_STO; // Send stop stop condition. I2CON&=I2BX_SI; // Clear SI. while ( I2CON & I2B_STO ); // Wait till hardware clears stop bit. I2CON&=I2BX_I2EN; // Disable I2C Bus. return 0; } // Reads byte from i2c bus parameters ack to send pointer to uchar to store data. // Returns 1 if error in operation. bit hi2c_in(bit ack, uchar *i2rxdata) { if ( ack ) // set auto acknowledge flag if ack is to be sent. I2CON|= I2B_AA; else I2CON&= I2BX_AA; I2CON&=I2BX_SI; // Clear SI. while (!( I2CON & I2B_SI ) ); // Wait for SI. if ((I2STA!= DATA_RXD_ACK) && (I2STA!= DATA_RXD_NOACK)) // If status not as expected. { I2CON|=I2B_STO; // Send stop stop condition. I2CON&=I2BX_SI; // Clear SI. while ( I2CON & I2B_STO ); // Wait till hardware clears stop bit. I2CON&=I2BX_I2EN; // Disable I2C Bus. return 1; // Return error. } *i2rxdata=I2DAT; // Store received data. return 0; // Return no error. } // Transmits a byte on i2c bus parameter byte to send. // Returns 1 if error occured. bit hi2c_out(uchar i2txdata) { I2DAT=i2txdata; // Put data to transmit in register. I2CON&=I2BX_SI; // Clear SI. while ( ! ( I2CON & I2B_SI ) ); // Wait for SI. if ((I2STA!=DATA_TXD_ACK) && (I2STA!=ADDRESS_TXD_ACK) && (I2STA!=ADDRESS_RXD_ACK)) // If status not as expected. { I2CON|=I2B_STO; // Send stop stop condition. I2CON&=I2BX_SI; // Clear SI. while ( I2CON & I2B_STO ); // Wait till hardware clears stop bit. I2CON&=I2BX_I2EN; // Disable I2C Bus. return 1; // Return error. } return 0; // Return no error. } // Reads a value from ADC PCF8591 Parameters pointer to uchar to store result and channel no to read. // Returns 1 if error occured in operation. bit read_pcf8591( uchar *adrdbuff, uchar adch) { if(hi2c_start()) // Send start condition. return 1; if(hi2c_out(0x90)) // Send device address + write. return 1; if(hi2c_out(adch)) // send channel number to read. return 1; hi2c_stop(); // Send stop condition. if(hi2c_start()) // send start condition. return 1; if(hi2c_out(0x91)) // Send device address + Read. return 1; if(hi2c_in(1, adrdbuff)) // Dummy read data from ADC send ack. return 1; if(hi2c_in(1, adrdbuff)) // Dummy read data from ADC send ack. return 1; if(hi2c_in(1, adrdbuff)) // Dummy read data from ADC send ack. return 1; if(hi2c_in(1, adrdbuff)) // Dummy read data from ADC send ack. return 1; if(hi2c_in(0, adrdbuff)) // Final Read data from ADC send nack. return 1; hi2c_stop(); // Send stop condition. return 0; // Return no error. } // Sends address of memory location in seeprom to read or write. // Returns 1 if error occured else returns 0. // Parameters address high and low bytes rd/wr bit. bit Seepromadr( uchar adrh, uchar adrl, bit rd ) { uchar devadr=0xa2; //I2C Bus Address 0. devadr |= rd; //Or the RD/WR bit. hi2c_start(); //Send a start codition. if( hi2c_out( devadr )) //Send the device address. return 1; if(!rd) //If Write Operation. { if( hi2c_out( adrh )) //Send the address high byte. return 1; return hi2c_out( adrl ); //Send the address low byte. } return 0; // Return no error. } // Writes specified no. of bytes to seeprom. // Parameters starting address location, pointer to data buffer, no. of bytes to write. // Returns 1 if error occured else returns 0. bit Seepromwrite( uint adr, uchar *s, uchar n ) { uchar i; do { // Acknowledge pooling for eeprom since seeproms dont respond when busy writing. for( i = 255;; ) { if( 0 == Seepromadr( adr>>8, adr, 0) ) break; // receive ACK = write finished hi2c_stop(); if( 0 == --i ) // try it 25.5msec return 1; // Timeout } if( 0 == n ) return hi2c_stop(); // all bytes written i = adr & ((1 << WRITEPAGE) - 1); // prepare write boundary check do { if( hi2c_out( *s )) { hi2c_stop(); return 1; // Write error } s++; adr++; }while( --n && ++i < (1 << WRITEPAGE)); hi2c_stop(); }while(1); } // Reads specified no. of bytes from seeprom. // Parameters starting address location, pointer to data buffer, no. of bytes to read // Returns 1 if error occured else returns 0. bit Seepromread( uint adr, uchar *s, uchar n ) { if( Seepromadr( adr>>8, adr, 0)) return 1; // EEPROM not connected do { if( Seepromadr( adr>>8, 0, 1)) // repeat start for read return 1; for(;;) { bit ack = --n && ++adr & 0xff; // last byte or last in page if( hi2c_in(ack, s) ) return 1; s++; if( !ack ) break; } }while( n ); hi2c_stop(); // send stop condition. return 0; // return no error. } //*****************************************************************