Here's an example which works in my application.
I struggled somewhat, now I know its because I had to use char ptrs in stead of 16bit int pointers (because CCIT is LSB order first, so we pick 1 byte from the buffer, shift it 8 times to make it 16bit to validate the upper MSB bit 0x8000).
Most causes found when people struggle with 16bit CRC (while 8bit most of the time works):
- Buffer should be called by 8bit ptr
- Shifting BEFORE the XOR!
- Never use int or unsigned int.. but use short! My application runs on 16 and 32bit Microchip PIC's and using ints results in 16bit values on the 16bit pic and 32bit values (so lot of zeros!) on 32bit platforms.
BOOL = unsigned char.
UINT16 = unsigned short.
The function runs in code, so not a while/forloop.
When done, the CRC is copied to the address pointed by *crc.
This way all ather tasks (M95 modem, MCP's I2C, Flash logs, TCP/IP etc. will be handled without too large delays).
BOOL CRC_16(UINT16 ui16_Bytes, char *src, UINT16 *crc)
{
static BOOL bNew = FALSE;
static UINT16 remainder = 0;
static UINT16 i = 0;
static UINT16 ui16_Loc_bytes;
static char *ptr;
static char locData;
if(!bNew)
{
ui16_Loc_bytes = ui16_Bytes;
ptr = src;
locData = *ptr;
i = 8;
remainder = 0x0000;
bNew = TRUE;
}
if(ui16_Loc_bytes)
{
if(i == 8)
{
remainder ^= (((UINT16)locData)<<8); //Only 8bits at a time filled with zeros
}
if(i)
{
if (remainder & 0x8000)
{
remainder = (remainder << 1);
remainder ^= POLYNOMIAL_16;
}
else
{
remainder = (remainder << 1);
}
i--;
}
else
{
ui16_Loc_bytes--;
ptr++;
locData = *ptr;
//ptr++;
i = 8;
}
}
else
{
bNew = FALSE;
*crc = remainder;
return TRUE;
}
return FALSE;
}
if(SDKaart.ui16_RecBytes >= SDKaart.ui16_ByteLen)//30-5-2018 edited SDKaart.CMD[SDKaart.ui8_ActiefCMD].ui16_RecLen)
{
SD_DESELECT;
if(SDKaart.bInitReady && SDKaart.b_BlockRead)
{
if(CRC_16(512,(char*)&SDKaart.Mem_Block.SD_Buffer[0], &SDKaart.ui16_MemBlock_CRC))
{
if((((UINT16)SDKaart.Mem_Block.SD_Buffer[512]<<8)|(UINT16)SDKaart.Mem_Block.SD_Buffer[513]) == SDKaart.ui16_MemBlock_CRC)
{
SDKaart.bRXReady = TRUE;
SDKaart.TXStat = SPI_IDLE;
printf("CRC16 OK %x\r\n",SDKaart.ui16_MemBlock_CRC);
}
else
{
SDKaart.bRXReady = TRUE;
SDKaart.TXStat = SPI_IDLE;
printf("CRC16 %u != 0x%x 0x%x\r\n",SDKaart.ui16_MemBlock_CRC,SDKaart.Mem_Block.SD_Buffer[512], SDKaart.Mem_Block.SD_Buffer[513] );
}
//printf("CRC citt: %u\r\n", Calculate_CRC_CCITT((char *)&SDKaart.Mem_Block.SD_Buffer[0],512));
}
}
else
{
SDKaart.bRXReady = TRUE;
SDKaart.TXStat = SPI_IDLE;
}
}
else
{
if(SD_SPI_TX_READY)
{
SDKaart.bNewSPIByte = TRUE;
SPI1BUF = SD_EMPTY_BYTE;
}
}
I have used many crcs found online, but a lottt didn't work.
Be aware a lot of online "examples" do use <<1 behind the XOR, but it must be done before xor.
POLY_16 is 0x1021.
Next oppurtunity is to build a table picker. :)
Greetz, John