While the suggested approach from PeterJ is fine, its cleaner to decouple the "data layer" logic (EEPROM access) from the CRC routine.
This CRC-32 can be universally used, its not bound to program specific behavior:
// CCITT CRC-32 (Autodin II) polynomial
uint32_t CalcCRC32(uint32_t crc, uint8_t *buffer, uint16_t length) {
while(length--) {
crc = crc ^ *buffer++;
for (uint8_t j=0; j < 8; j++) {
if (crc & 1)
crc = (crc >> 1) ^ 0xEDB88320;
else
crc = crc >> 1;
}
}
return crc;
}
Then you just feed blocks of data to the CRC function like you see fit and as required by your application.
This usage example is just written down. It uses the fictional function eeprom_read() which reads a block of data from EEPROM. We start at EEPROM address 0.
const uint8_t BLOCKLENGTH = 128;
uint32_t crc32;
uint8_t buffer[BLOCKLENGTH]; // temporary data buffer
crc32 = 0xFFFFFFFF; // initial CRC value
for (uint16_t i=0; i < NUMBEROFBLOCKS; i++) {
eeprom_read(BLOCKLENGTH * i, buffer, BLOCKLENGTH); // read block number i from EEPROM into buffer
crc32 = CalcCRC32(crc32, buffer, BLOCKLENGTH); // update CRC
}
// crc32 is your final CRC here
Note that NUMBEROFBLOCKS is just a placeholder. I hope you get the idea.
Your code looks fine. However writing driver on your own can be time consuming and is prone to errors. Microchip supplies basic libraries and I2C EEPROM as well.
Are you sure both lines have pull-ups ( resistors to 3V ) ? Without this no bits will be generated by PIC.
Here is an example for working I2C EEPROM driver which can use both plib or manual hardware I2C on PIC32 or PIC16/18(HW_CFG_SENSOR).
void i2cSetupMaster(unsigned int BaudRate)
{
#ifdef I2C_USE_PLIB
#ifndef HW_CFG_SENSOR
I2CEnable(I2C_MOD,0);
I2CConfigure(I2C_MOD,0);
I2CSetFrequency(I2C_MOD,GetPeripheralClock(), BaudRate);
I2CEnable(I2C_MOD,1);
#else
ANSELC = 0;
TRISC3 = 1;
TRISC4 = 1;
SSP1ADD = 39; // 39 @ 16Mhz = 100khz SCL pin clock period = ((ADD<7:0> + 1) *4)/FOSC
OpenI2C1(MASTER,SLEW_OFF);
#endif
#else
I2C_CONbits.ON = 0;
idleI2C();
//BRG
// I2C_BRG = BaudRate; // 0x0C2; //( (sourceClock/i2cClock)/2 ) - 2; // 100Khz at 40Mhz PBCLK
// I2C3ADD = 0x09;//( (_XTAL_FREQ/100000) /4 )-1;
I2CConfigure(I2C_MOD, I2C_ENABLE_SMB_SUPPORT); //I2C_ENABLE_SMB_SUPPORT
I2CSetFrequency(I2C_MOD, GetPeripheralClock(), BaudRate);
idleI2C();
//I2C_CONbits.ACKDT = 0; //send ACK on recieved byte
I2C_CONbits.STRICT = 0;
I2C_CONbits.SMEN = 1; //SMB bus compliant
//enable, master, no collision
I2C_CONbits.DISSLW = 1; //Slew rate control disabled for Standard Speed mode (100 kHz)
I2C_STATbits.I2COV = 0;
I2C_CONbits.ON = 1;
DelayMs(2);
#endif
}
bool i2cSendByte(unsigned char byte)
{
#ifdef I2C_USE_PLIB
#ifndef HW_CFG_SENSOR
if (I2CTransmitterIsReady(I2C_MOD))
{
return I2CSendByte( I2C_MOD, byte );
}
#else
putcI2C(byte);
while(SSPSTATbits.R_NOT_W){}
return 1;
#endif
#else
I2C_TRN = byte;
int timeout = 0;
msspWait(); //wait until byte is latched
while ( I2C_STATbits.TRSTAT == 1) {
timeout++;
if ( timeout > MAX_WAIT_CYCLES) {
return 0x00;
}
};
if ( msspOVF() || msspBWcol() ) { return 0; } //send failed
else { return 1; } //success
#endif
}
/********** Write fixed length in page portions *****************/
void seqWriteEE (byte deviceAddr, word Addr, word bytes, byte* buff)
{
#ifdef MEM_I2C_HARDWARE
i2cSetupMaster( I2C_BRG_100kHz ); //concurrency enable
/*If the master should transmit more than 64 bytes prior to
generating the Stop condition, the address counter will
roll over and the previously received data will be overwritten.*/
CurrentDeviceAddr = deviceAddr;
int pages = (int)(bytes / i2cMemPageSize);
int singleBytes = (int) (bytes % i2cMemPageSize);
word writeAddr = Addr;
int pageInc = 0;
if ( bytes >= i2cMemPageSize)
{
word BufferPos;
for (pageInc = 0; pageInc < pages; pageInc++)
{
writeAddr += pageInc > 0 ? i2cMemPageSize :0 ;
BufferPos = pageInc*i2cMemPageSize;
WriteSectorBytesAtAddr(writeAddr,&buff[BufferPos],i2cMemPageSize);
}
if (singleBytes > 0){
BufferPos = pages*i2cMemPageSize;
writeAddr += i2cMemPageSize;
WriteSectorBytesAtAddr(writeAddr,&buff[BufferPos],singleBytes);
}
}
else
{
WriteSectorBytesAtAddr(Addr,buff,bytes);
}
#else
i2cSetupMaster( I2C_BRG_100kHz ); //concurrency enable
/*If the master should transmit more than 64 bytes prior to
generating the Stop condition, the address counter will
roll over and the previously received data will be overwritten.*/
CurrentDeviceAddr = deviceAddr;
int pages = (int)(bytes / i2cMemPageSize);
int singleBytes = (int) (bytes % i2cMemPageSize);
word writeAddr = Addr;
int pageInc = 0;
if ( bytes >= i2cMemPageSize)
{
word BufferPos;
for (pageInc = 0; pageInc < pages; pageInc++)
{
writeAddr += pageInc > 0 ? i2cMemPageSize :0 ;
BufferPos = pageInc*i2cMemPageSize;
WriteSectorBytesAtAddr(writeAddr,&buff[BufferPos],i2cMemPageSize);
}
if (singleBytes > 0){
BufferPos = pages*i2cMemPageSize;
writeAddr += i2cMemPageSize;
WriteSectorBytesAtAddr(writeAddr,&buff[BufferPos],singleBytes);
}
}
else
{
WriteSectorBytesAtAddr(Addr,buff,bytes);
}
#endif
}
void WriteSectorBytesAtAddr(word Addr, byte* buff, word bytes){
if ( IsWriteOnSectorBoundries(Addr,bytes) ){
word buffPos;
word SecEndAddr = GetSectorEndForWriteAddr(Addr);
word SecBytesToEnd = SecEndAddr-Addr;
int binc = 0;
StartWriteAtAddr(Addr);
for(binc=0; binc< SecBytesToEnd; binc++)
{
i2cSendByte(buff[binc]);
}
FinishSectorWrite();
StartWriteAtAddr(Addr+SecBytesToEnd);
word BytesToEnd = bytes - SecBytesToEnd;
buffPos = SecBytesToEnd;
for(binc=0; binc< BytesToEnd; binc++)
{
i2cSendByte(buff[buffPos+binc]);
}
FinishSectorWrite();
}else{
StartWriteAtAddr(Addr);
int binc = 0;
for(binc=0; binc<bytes; binc++)
{
i2cSendByte(buff[binc]);
}
FinishSectorWrite();
}
}
However you will not get far without even most basic DSO. There's just too many things that can go wrong.
Best Answer
You say it's a write protection pin, implying that asserting it prevents writes. Note that the pin name is written with a bar over it in the schematic. That means negative logic. Tying it low therefore asserts its function. If it is truly a write protect pin, then you are preventing writes by tying it low.
Since you didn't provide a link to the datasheet, I'll leave it to you to check what the function and polarity of the pin really are.