How to use CRCBIT and/or CRCNIB for CRC7 (for MMC)? — Parallax Forums

# How to use CRCBIT and/or CRCNIB for CRC7 (for MMC)?

Posts: 14,157
For uSD, you can ignore the CRC, but eMMC is making me use it...

I tried for a second to use the assembly commands CRCNIB and CRCBIT to speed it up.
But, I can't figure it out...

Anybody know how to do this?

Here's my Spin2 version that works:
```PUB crc7(buffer,count):r | crc, c,i, j,n 'calculate crc of series of bytes for MMC
crc := 0
repeat j from 1 to count
c := byte[buffer++]
'Number of loops is 8 for first bytes, 7 for last byte
if j==count
n:=7
else
n:=8
repeat i from 1 to n
crc <<= 1
if c&\$80
crc+=1
if crc&\$80
crc^=\$9
c<<=1
crc:=crc & \$7F
r := (crc<<1)+1
return r
```
«1

• Posts: 14,157
edited 2020-06-01 21:05
Looking at @JonnyMac code, I see what I think is the reverse of the polynomial... Maybe that is the trick I was missing.
http://forums.parallax.com/discussion/171293/crc8

• Posts: 18,069
edited 2020-06-01 21:16
Ray,
You may have to reverse the byte c before running the rep loop, and the last loop will need to be 7
You should be able to do something like this
```  rep     @.done, #8
shr     c, #1       wc
crcbit  crc, #\$9
.done
```
Sorry, dont have time to test atm.

or using the crcnib
```  shl     c, #24 'get into top byte
setq    c
crcnib  crc, #\$9
crcnib  crc, #\$9
```
• Posts: 8
The polynomial does indeed need to be reversed since CRCBIT does right shifts instead of left shifts towards the msb. Also, the result is bit-reversed.
With the traditional way of shifting in bits, there needs to be preliminary shifts to load the data into the crc result. Not so with CRCBIT since the
incoming bit and the outgoing bit are xor'd to see if the poly needs xor'ing into the result.

• Posts: 14,157
edited 2020-06-02 00:39
Ok, I'm slowly figuring this out...
I see SMBus is "CRC8_MAXIM" there. The actual polynomial is \$31, but we need to use the reversed version, \$8C, with the CRCBIT routine, as shown by @JonnyMac
Also, that page says both the input and the output are bit reversed. But, this seems to be done automatically by CRCBIT somehow...

Also, I see a lot of people are using a table to do this... Maybe that's the way to go. I'll just use the LUT, once I figure out how to translate CRC8_MAXIM into CRC7 for MMC...

Or, maybe I can just make the table without actually figuring anything out...
• Posts: 18,069
Ray,
Just use the crcbit or crcnib. You'll be glad you did! Sorry I'm busy at work so I can't get it done for you just now but perhaps later.

Just run a single known character thru the crcnib once (just a nibble( and compare the result with your spin code. Retry with the crc initialised to 0 or \$FF, try reversing the characters bits, and the reverse of the polynomial (\$31 and \$8C). There are not a lot of combinations here and you should find one that matches your spin. BTW Are you sure your spin is correct?
• Posts: 14,157
The Spin code is correct. The eMMC chip won't talk unless it is correct.
• Posts: 18,069
It’s quite unusual that the last char only uses 7 bits to accumulate in the crc.
I’ll try and find some time to test it with the crcbit crcnib instructions.
• Posts: 14,157
I think I'm seeing that I need to use the crc with bits inverted and also the result has bits inverted. Maybe that's the clue we need...
• Posts: 18,069
@Rayman
Spent quite some time on this this morning.
I cannot get your code to give the correct results. If you want me to spend any more time on it I need a working program that I can compile with serial output that I can test with. Either pnut or fastspin is fine.

This sequence is a know valid one for SD cards
\$40 \$00 \$00 \$00 \$00 \$95
where \$95 is the crc value.
From what I've been able to research, the final crc value calculated is \$4A which is then shl #1 and add #1 to give \$95.

In hindsight I probably should have gone back to study the algorithm again. I haven't done it since the 80's.

I found this c code but I cannot run it to verify if it works and i don;t understand the "for" statement
```#include <stdbool.h>

crc_t crc_update(crc_t crc, const void *data, size_t data_len)
{
const unsigned char *d = (const unsigned char *)data;
unsigned int i;
bool bit;
unsigned char c;

while (data_len--) {
c = *d++;
for (i = 0x80; i > 0; i >>= 1) {
bit = crc & 0x40;
if (c & i) {
bit = !bit;
}
crc <<= 1;
if (bit) {
crc ^= 0x09;
}
}
crc &= 0x7f;
}
return crc & 0x7f;
}
```
• Posts: 18,069
This is supposed to be the lookup table, but again I cannot see that it gives the correct results either
```/*
* Table for CRC-7 (polynomial x^7 + x^3 + 1).
* This is a big-endian CRC (msbit is highest power of x),
* aligned so the msbit of the byte is the x^6 coefficient
* and the lsbit is not used.
*/
const u8 crc7_be_syndrome_table[256] = {
0x00, 0x12, 0x24, 0x36, 0x48, 0x5a, 0x6c, 0x7e,
0x90, 0x82, 0xb4, 0xa6, 0xd8, 0xca, 0xfc, 0xee,
0x32, 0x20, 0x16, 0x04, 0x7a, 0x68, 0x5e, 0x4c,
0xa2, 0xb0, 0x86, 0x94, 0xea, 0xf8, 0xce, 0xdc,
0x64, 0x76, 0x40, 0x52, 0x2c, 0x3e, 0x08, 0x1a,
0xf4, 0xe6, 0xd0, 0xc2, 0xbc, 0xae, 0x98, 0x8a,
0x56, 0x44, 0x72, 0x60, 0x1e, 0x0c, 0x3a, 0x28,
0xc6, 0xd4, 0xe2, 0xf0, 0x8e, 0x9c, 0xaa, 0xb8,
0xc8, 0xda, 0xec, 0xfe, 0x80, 0x92, 0xa4, 0xb6,
0x58, 0x4a, 0x7c, 0x6e, 0x10, 0x02, 0x34, 0x26,
0xfa, 0xe8, 0xde, 0xcc, 0xb2, 0xa0, 0x96, 0x84,
0x6a, 0x78, 0x4e, 0x5c, 0x22, 0x30, 0x06, 0x14,
0xac, 0xbe, 0x88, 0x9a, 0xe4, 0xf6, 0xc0, 0xd2,
0x3c, 0x2e, 0x18, 0x0a, 0x74, 0x66, 0x50, 0x42,
0x9e, 0x8c, 0xba, 0xa8, 0xd6, 0xc4, 0xf2, 0xe0,
0x0e, 0x1c, 0x2a, 0x38, 0x46, 0x54, 0x62, 0x70,
0x82, 0x90, 0xa6, 0xb4, 0xca, 0xd8, 0xee, 0xfc,
0x12, 0x00, 0x36, 0x24, 0x5a, 0x48, 0x7e, 0x6c,
0xb0, 0xa2, 0x94, 0x86, 0xf8, 0xea, 0xdc, 0xce,
0x20, 0x32, 0x04, 0x16, 0x68, 0x7a, 0x4c, 0x5e,
0xe6, 0xf4, 0xc2, 0xd0, 0xae, 0xbc, 0x8a, 0x98,
0x76, 0x64, 0x52, 0x40, 0x3e, 0x2c, 0x1a, 0x08,
0xd4, 0xc6, 0xf0, 0xe2, 0x9c, 0x8e, 0xb8, 0xaa,
0x44, 0x56, 0x60, 0x72, 0x0c, 0x1e, 0x28, 0x3a,
0x4a, 0x58, 0x6e, 0x7c, 0x02, 0x10, 0x26, 0x34,
0xda, 0xc8, 0xfe, 0xec, 0x92, 0x80, 0xb6, 0xa4,
0x78, 0x6a, 0x5c, 0x4e, 0x30, 0x22, 0x14, 0x06,
0xe8, 0xfa, 0xcc, 0xde, 0xa0, 0xb2, 0x84, 0x96,
0x2e, 0x3c, 0x0a, 0x18, 0x66, 0x74, 0x42, 0x50,
0xbe, 0xac, 0x9a, 0x88, 0xf6, 0xe4, 0xd2, 0xc0,
0x1c, 0x0e, 0x38, 0x2a, 0x54, 0x46, 0x70, 0x62,
0x8c, 0x9e, 0xa8, 0xba, 0xc4, 0xd6, 0xe0, 0xf2
```
• Posts: 14,157
edited 2020-06-02 23:06

filename is crc7expl.zip

It seems this kind of thing is ancient history and not so many people still remember how to do it by hand

There is a left shift and a +1 at the very end.
I think that 1 at the end is actually the stop bit, which is why it is not included in the above...

Here is the important part:
```/****************/
static unsigned char Encode(unsigned char Seed, unsigned char Input, unsigned char Depth)
/* --
Produce a 7 bit CRC value Msb first.
Seed is last round or initial round shift register
value (lower 7 bits significant).
Input is an 8 bit value from byte stream being CRCd.
CRC register is seeded initially with the value 0 prior
to mixing in the variable packet data.
Depth is usually 8, but the last time is 7 to shift in
the augment string of 7 zeros.
*****************/
{
/*begin-Encode. -
local defs: */
register unsigned char regval;      // shift register byte.
register unsigned char count;
register unsigned char cc;          // data to manipulate.
#define POLYNOM (0x9)        // polynomical value to XOR when 1 pops out.

/*BODY*/

regval = Seed;    // get prior round's register value.
cc = Input;       // get input byte to generate CRC, MSB first.

/* msb first of byte for Depth elements */
for (count = Depth     // set count to 8 or 7.
; count--        // for count # of bits.
;  cc <<= 1     // shift input value towards MSB to get next bit.
)
{
// Shift seven bit register left and put in MSB value of input to LSB.
regval = (regval << 1) + ((cc & 0x80) ? 1 : 0);
// Test D7 of shift register as MSB of byte, test if 1 and therefore XOR.
if (regval & 0x80)
regval ^= POLYNOM;
} // end byte loop.
return (regval & 0x7f);    // return lower 7 bits of CRC as value to use.
}
/*...
end-Encode.
.....*/

void CCRC7Dlg::OnBnClickedButton1()
{
char* cp;     // pointer into command line argument list.
int walker;    // index into argv parameter list.
int value, nuval;    // temporary values from cmd line and CRC generator.
unsigned char CrcAccum; // local storage of each round of CRC.
UpdateData(true);

//fake command line input
int argc;
char argv[100];
argc = 5;+32;  //#characters  6 +payload
argv[1] = 64;// +1;  //64==CMD0, 64+1=CMD1
for (int i=2;i<40;i++)
argv[i] = 0;

// 7 bit shift register CRC computation across 5 byte SD message field
//   with 6th byte of message being the CRC field generated herein.
if (argc != (1 + 5))
{
//fprintf(stderr, "\nCRC_7 command line syntax error.\n");
//fprintf(stderr, "Requires 5 argument(s) to encode w/crc value\n");
//fprintf(stderr, "Usage is :\nCRC_7 0 0 0 0 0\n");
//fprintf(stderr, " or similar with decimal value for each byte.\n");
//fprintf(stderr, "  Use CRC_7 64 0 0 0 0\n   to generate example run.\n\n");
//return 1;
// EARLY EXIT, CMND LINE SYNTAX ERROR
}

// start w/seed of 0 per algorithm.
CrcAccum = 0;

// loop through 5 command line decimal values. Display in HEX to
//  stdout, can be captured via >> on cmdline.
for (walker = 1; walker < argc; walker++)
{
//cp = &argv[walker]; //RJA added &
value = argv[walker];//RJA changing text to char for input cp;// atoi(cp);
nuval = Encode(CrcAccum, value, 8);
//printf(" CRC remainder of 0x%02X for 0x%02X input byte.\n"
//	, nuval
//	, value
//);
CrcAccum = nuval;    // reload crc accum.
}

// mix in last 7 bits of 0s to augment, and then shift final CRC
//  remainder left and OR in fixed 1 LSB.
nuval = Encode(CrcAccum, 0, 7);
value = (nuval << 1) + 1;
//printf("CRC remainder after augment is 0x%02X with FINAL CRC byte of 0x%02X.\n"
//	, nuval
//	, value
//);
return;//0;
}
```
• Posts: 18,069
edited 2020-06-02 23:15
From discussions I see, it seems that the crc7 implementation was botched. That's not uncommon as Microcom botched the implementation of the CCITT16. I've coded it many times before but I just cannot seem to get this one right. I'm not a c programmer so I cannot be sure I'm converting the c to spin to see how it is working. I'm looking at the basics again to see if I can just do it in pasm.

You need to verify a spin program that takes \$40 \$00 \$00 \$00 \$00 and gives \$65. I can then convert it to pasm and then use the crcbit/crcnib instructions.
• Posts: 14,157
See above
The shift and 1 at end is the stop bit
• Posts: 6,347
Here's some C code that generates the correct CRC.
```#include <stdio.h>

unsigned char crc7(unsigned char *buf, int len)
{
int i, j;
unsigned char crc, val;

crc = 0;
for (i = 0; i < len; i++)
{
val = buf[i];
for (j = 0; j < 8; j++)
{
crc <<= 1;
if ((val & 0x80) ^ (crc & 0x80))
crc ^=0x09;
val <<= 1;
}
}
crc = (crc << 1) | 1;

return(crc);
}

int main()
{
unsigned char sample1[] = {0x40, 0x00, 0x00, 0x00, 0x00, 0x95};
unsigned char sample2[] = {0x48, 0x00, 0x00, 0x01, 0xAA, 0x87};

printf("CRC = %x\n", crc7(sample1, 5));
printf("CRC = %x\n", crc7(sample2, 5));

return 0;
}
```
• Posts: 14,157
Nice. Looks like a much more compact version of the C code I found...
• Posts: 6,347
edited 2020-06-03 00:47
Here's the crc7 routine in Spin. I converted it using cspin, but I haven't verified that it generates the correct values.

EDIT: I replaced byte[@crc] with just crc, and masked it to 8 bits at the end.
EDIT2: I also replaced byte[@val] with just val. cspin was trying very hard to maintain 8-bit values.
```PUB crc7(buf, len) | i, j, crc, val
crc := 0
i := 0
repeat while (i < len)
val := byte[buf][i]
j := 0
repeat while (j < 8)
crc <<= 1
if ((val & \$80) ^ (crc & \$80))
crc ^= \$09
val <<= 1
j++
i++
crc := (crc << 1) | 1
return crc & 255
```
• Posts: 14,157
There is working spin2 code in the top post...

Like to make it faster with new crcnib instruction ...
• Posts: 5,283
edited 2020-06-03 01:32
Here is something that may help if you want to use CRCBIT (untested, so you may need to validate it, I just took Dave Hein's CRC code and translated it to PASM2). CRCNIB could be faster if that can be used instead. If the FIFO is free that could speed it up instead of the rdbyte too.
```    mov     len, ##LENGTH
mov     crc, #0 wc
loop
rdbyte  data, ptra++
rep     #2, #8
shr     data, #1 wc
crcbit  crc, #\$90 ' reverse of 09 for opposite CRCBIT working order
djnz    len, #loop
rev     crc
shr     crc, #24
or      crc, #1
EDIT:
and     crc, #\$FF ' for just 7 bit crc shifted after stop bit included.   EDIT2: actually redundant
```
• Posts: 18,069
edited 2020-06-03 01:24
@Rayman
The spin code at the top post is not giving the correct result for the initial command 0 which must be \$95 but it returns \$93
```    crc := crc7(@buf2, 5)
ser.TxHex8(crc)
ser.TxCR()

PUB crc7(buff,count):r | crc, c,i, j,n 'calculate crc of series of bytes for MMC
crc := 0
repeat j from 1 to count
c := byte[buff++]
'Number of loops is 8 for first bytes, 7 for last byte
if j==count
n:=7
else
n:=8
repeat i from 1 to n
crc <<= 1
if c&\$80
crc+=1
if crc&\$80
crc^=\$9
c<<=1
crc:=crc & \$7F
r := (crc<<1)+1
return r

DAT
buf2        byte    \$40,0,0,0,0,\$95
```

What is happening is that it is getting the wrong input characters
Found a bug in my code - just retrying.

Yes, the crc generated is wrong:(

It also generates the wrong value \$1B which should be \$87 for the command8
```buf8        byte    \$48,\$00,\$00,\$01,\$AA,\$87
```
• Posts: 14,157
I think the first byte is actually \$40+0
• Posts: 14,157
I promise it works... Here's the code that calls it:
```    'Send command and sometimes get response
'first, need to calculate CRC7
cmdout[0]:=\$40+op
cmdout[1]:=(parm>>24)&\$FF
cmdout[2]:=(parm>>16)&\$FF
cmdout[3]:=(parm>>8)&\$FF
cmdout[4]:=(parm>>0)&\$FF
cmdout[5]:=0
c:=crc7(@cmdout,6)
```
• Posts: 14,157
@rogloh That looks like it might work.
I’ll try tomorrow ...
Late here...
• Posts: 6,347
@Rayman, I also got \$93 with your code, until I realized that it needs an extra zero at the end. I cleaned up my spin code, and it only needs 5 bytes, and not 6.
```PUB crc7(buf, len) : crc | val
repeat len
val := byte[buf++]
repeat 8
crc <<= 1
if (val ^ crc) & \$80
crc ^= \$09
val <<= 1
crc := ((crc << 1) | 1) & 255
```
• Posts: 14,157
The sixth byte is always zero and it only does 7 bits of crc on it...
• Posts: 6,347
Yes, I see that, but it's a little less efficient to do it that way.
• Posts: 5,283
edited 2020-06-03 01:40
Yeah give it a go if you want try to use inline PASM2 in your SPIN2 for this. Only 22 clocks plus rdbyte delay per byte (unless you can use the fifo which would speed it up to perhaps 24 clocks per byte total in the main loop one the fifo is primed.

An alternate CRCNIB may speed this up even more. I'm just not 100% sure what the xx values are. Maybe they are just the same as the single bit case and the HW just figures it out for you. This could then be as fast as 14 clocks per byte if the fifo is used.
```    mov     len, ##LENGTH
mov     crc, #0 wc
loop
rdbyte  data, ptra++
rev     data
setq    data
crcnib  crc, #xx ' what constant value to use?
crcnib  crc, #xx
djnz    len, #loop
rev     crc
shr     crc, #24
or      crc, #1
```
• Posts: 18,069
That 6th \$0 byte was it. Spent hours on this
I'll try crcnib now
• Posts: 14,157
edited 2020-06-03 14:45
@rogloh I can't make this last code work... I'll try the first...
• Posts: 2,685
edited 2020-06-03 19:27
This Spin2 code seems to work:
```PUB crc7(buf, len) : crc | i,val
repeat i from 0 to len-1
val := byte[buf][i] << 24
org
setq    val
crcnib  crc,#\$90>>1
crcnib  crc,#\$90>>1
end
return (crc rev 6) << 1 | 1
```

or with the outer loop also in PASM:
```PUB crc7(buf, len) : crc | val
org
cr7lp   rdbyte  val,buf
shl     val,#24
setq    val
crcnib  crc,#\$90>>1
crcnib  crc,#\$90>>1
djnz    len,#cr7lp
end
return (crc rev 6) << 1 | 1
```
Andy
• Posts: 14,157
edited 2020-06-03 20:25
Thanks Andy, I'll try that.

I think I'm seeing that I got hung up by the code I found and that last 7 bits of zero it does.
Although it works, it is unlike all the other code...

Now, I have code that just works on the first 5 bytes and doesn't have that dummy 6th byte:
```PUB crc7_c(buffer,count):r | crc, c,i, j,n,len 'calculate crc of series of bytes for MMC
crc := 0
repeat j from 1 to count-1
c := byte[buffer++]
repeat i from 1 to 8
crc <<= 1
if ((c^crc)&\$80)>0
crc^=\$9
c<<=1
crc:=crc & \$7F
r := (crc<<1)+1
return r
```

Was just about to figure this all out, but maybe Andy beat me to it...
Or, maybe @"Dave Hein" or @rogloh would work this way too...