It uses the PIC24's built in CRC engine, and despite AN1148A it took me a while to get going. It's fully tested and in use, so I hope it saves someone some time.
//---------------------------------------------------------------------
//
// FUNCTION : pec_calculation
//
// PARAMETERS: pui8Buffer is a buffer up to 255 bytes long
// ui8Length is the length of the message
// DESCRIPTION: 8 Bit CRC; Polynomial is X^8+X^2+X+1
//
// RETURNS: The checksum of the SMBus (I2C) message
//
//---------------------------------------------------------------------
UINT8 pec_calculation(UINT8 *pu8Buffer, UINT8 u8Length)
{
#define POYNOMIAL_LENGTH 8
CRCCONbits.PLEN = POYNOMIAL_LENGTH -1;
CRCXOR = 0x0006; // XOR polynomial is (X^8)+(X^2)+X+1, the final 1 isn't written
CRCCONbits.CSIDL = 1; // Stop module when device enters idle mode
CRCWDAT = 0; // Pre-load value
CRCCONbits.CRCGO = 1; // Start CRC module
do
{
while(CRCCONbits.CRCFUL){}; // Do not overflow FIFO
*(UINT8*) &CRCDAT = *pu8Buffer++; // Need to byte write this register or it doesn't work
} while (--u8Length != 0);
while(CRCCONbits.CRCFUL){}; // Wait for FIFO to empty
*(UINT8*) &CRCDAT = 0;
Nop();
Nop();
while (!CRCCONbits.CRCMPT){}; // Wait for calculation to finish
CRCCONbits.CRCGO = 0; // Stop CRC module
return (UINT8)(CRCWDAT & 0x00FF);
#undef POYNOMIAL_LENGTH
}