Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

Arduino code to PIC

Status
Not open for further replies.

Nigel Goodwin

Super Moderator
Most Helpful Member
I've been playing with a CRC routine I grabbed from an Arduino library, with a view to transferring data from Arduino to PIC, or PC to PIC etc. and adding a CRC to provide a little error checking, as it could be via wire, radio, or anything else - I also want to try and add it to PHP on a server, so I can check data coming from that.

However, while the routine compiles perfect under XC8, the output is completely different to the Arduino Uno, and often doesn't change as the numerical input does.

C:
// common subroutine

uint32_t crcCalc(uint8_t *buf, uint16_t bufSize)
{

    const uint32_t crcTable[16] =
    {
        0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac,
        0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,
        0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c,
        0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c
    };

    uint32_t crc = ~0L;

    for (uint16_t index = 0 ; index < bufSize  ; ++index)
    {
        crc = crcTable[(crc ^ buf[index]) & 0x0f] ^ (crc >> 4);
        crc = crcTable[(crc ^ (buf[index] >> 4)) & 0x0f] ^ (crc >> 4);
        crc = ~crc;
    }
    return crc;
}

// Arduino test code
uint32_t tempnum = 65123;

void setup() {
  // initialize serial communication at 9600 bits per second:
  Serial.begin(9600);
  Serial.println("CRC32 Test");
}

// the loop routine runs over and over again forever:
void loop() {
  Serial.println(tempnum);
  Serial.println(crcCalc(tempnum, sizeof(tempnum)));
  Serial.println(crcCalc(tempnum, sizeof(tempnum)), HEX);
  Serial.println();
  tempnum++;
  delay(5000);        // delay in between reads for stability
}

// XC8 test code
Serial_Println(" ");
    Serial_Println("CRC32 test");
    
    uint32_t testnum = 65123;
    
    while(1)
    {
        lcdPrintNumber(testnum, DEC);
        Serial_Println(" ");
        lcdPrintNumber(crcCalc(testnum, sizeof(testnum)), DEC);
        Serial_Println(" ");
        lcdPrintNumber(crcCalc(testnum, sizeof(testnum)), HEX);
        Serial_Println(" ");
        Serial_Println(" ");
        testnum++;
        fiveSecDelay();
    }

The outputs, using the base number 65123 are like this:

Code:
// Arduino output
CRC32 Test
65123
3546579263
D364813F

65124
1191761199
4708D52F

65125
4124761098
F5DADC0A

65126
2142370248
7FB1F9C8

65127
1772435312
69A53770

// XC8 output
CRC32 test
65123
1822041184
6C9A2460
 
65124
1822041184
6C9A2460
 
65125
1822041184
6C9A2460
 
65126
1822041184
6C9A2460
 
65127
1822041184
6C9A2460

If you add a 1 to the front of the base number (165123), then each XC8 output is different, but none are the same as the Arduino output fed with 165123.

Any ideas why the PIC version doesn't work correctly?, are the bytes in the variable perhaps in a different order?, but that wouldn't explain the repeating unchanged output from 65123?.
 
I hope its something simple like what just happened to me..

if you write;-

int myvar; in XC8 is defaults to unsigned, but other compilers default to signed... Just a quick check.. This caused me some headache recently as I always use MCC18 c compiler previously.
 
I hope its something simple like what just happened to me..

if you write;-

int myvar; in XC8 is defaults to unsigned, but other compilers default to signed... Just a quick check.. This caused me some headache recently as I always use MCC18 c compiler previously.
The variables are all specifically set to unsigned (uint32_t) - as far as I was aware signed was the default for int on most compilers, but using int32 or uint32 should take care of it either way (presumably?).
 
Little more info - if you feed the CRC routine a string, it works fine on both Arduino and PIC, with identical results - but examining the individual bytes read from buf[index] they are wrong for numeric variables on the Arduino as well as on the PIC.
 
crcCalc(uint8_t *buf

It's expecting a pointer; a char array string is passed as a pointer, but the CRC test using numbers is passing the number instead of a pointer to it.

Try passing the address?
lcdPrintNumber(crcCalc(&testnum, sizeof(testnum)), DEC);
 
crcCalc(uint8_t *buf

It's expecting a pointer; a char array string is passed as a pointer, but the CRC test using numbers is passing the number instead of a pointer to it.

Try passing the address?
lcdPrintNumber(crcCalc(&testnum, sizeof(testnum)), DEC);

I 'think' I tried that, but I'll give it another go. The original routine was working on a multiformat structure, so failing that I'll try using a structure instead of a plain numeric variable.
 
I use a CRC generator module in a pic24. It was a bit of pain to get working, as the MPLAB simulator didn't include the CRC generator, so I had to test my code on the PIC itself.

It's some time ago now that I did this. I seem to remember that the output of the CRC generator seemed to lag behind by one data word, so that a dummy word had to be run through the CRC generator at the end to get the right answer. I can look up the details if you want.
 
crcCalc(uint8_t *buf

It's expecting a pointer; a char array string is passed as a pointer, but the CRC test using numbers is passing the number instead of a pointer to it.

Try passing the address?
lcdPrintNumber(crcCalc(&testnum, sizeof(testnum)), DEC);
Well damn - it works!! :D

I wonder where I'd mistakenly stuck the '&' previously?, when it didn't work?

Arduino test
CRC32 Test
65123
619184820
24E802B4

65124
3107928589
B93F3A0D

65125
25386344
1835D68

65126
322368134
1336F286

65127
2877986275
AB8A95E3

65128
4092167605
F3E985B5

XC8 test
CRC32 test
65123
619184820
24E802B4

65124
3107928589
B93F3A0D

65125
25386344
1835D68

65126
322368134
1336F286

65127
2877986275
AB8A95E3

65128
4092167605
F3E985B5

Strangely enough, while XC8 worked exactly like that, the Arduino failed with an error - and I had to add a cast:

C:
Serial.println(crcCalc((uint8_t*)&tempnum, sizeof(tempnum)), HEX);

I also added the same cast to XC8 afterwards, which still worked the same.

Thanks for your help.
 
I also added the same cast to XC8 afterwards, which still worked the same.
If you don't add the cast, XC8 will issue warnings about "illegal conversion between pointer types".
 
Been there.... The ampersand is the easiest bug to make, damn hard to track down... Good ol' JRW .. I should have spotted that... But I think I'm showing my age a bit!!!

I'm still trying to work out where I might have put it, that didn't help? - perhaps it was something stupid, like in front of the variable in the sizeof(), by mistake?.
 
Some other that may be useful, if you are CRCing different items before combining them to a single data buffer or block for transmission?

The GNU / GCC CRC32 routine uses this; rather than a fixed initialisation value of 0xFFFFFFFF in the routine, you pass that to it; or the result of the previous CRC, if you are adding more to the same buffer / packet.

Presumably int is 32 bit with the DCC compiler.

Code:
unsigned int
xcrc32 (const unsigned char *buf, int len, unsigned int init)
...
unsigned int crc = init;

That would make the PIC routine

Code:
uint32_t crcCalc(uint8_t *buf, uint16_t bufSize, uint32_t init)
{

    const uint32_t crcTable[16] =
    {
        0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac,
        0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,
        0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c,
        0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c
    };

    uint32_t crc = init;

    for (uint16_t index = 0 ; index < bufSize  ; ++index)
    {
        crc = crcTable[(crc ^ buf[index]) & 0x0f] ^ (crc >> 4);
        crc = crcTable[(crc ^ (buf[index] >> 4)) & 0x0f] ^ (crc >> 4);
        crc = ~crc;
    }
    return crc;
}
 
Some other that may be useful, if you are CRCing different items before combining them to a single data buffer or block for transmission?

The GNU / GCC CRC32 routine uses this; rather than a fixed initialisation value of 0xFFFFFFFF in the routine, you pass that to it; or the result of the previous CRC, if you are adding more to the same buffer / packet.

Presumably int is 32 bit with the DCC compiler.

Code:
unsigned int
xcrc32 (const unsigned char *buf, int len, unsigned int init)
...
unsigned int crc = init;

That would make the PIC routine

Code:
uint32_t crcCalc(uint8_t *buf, uint16_t bufSize, uint32_t init)
{

    const uint32_t crcTable[16] =
    {
        0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac,
        0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,
        0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c,
        0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c
    };

    uint32_t crc = init;

    for (uint16_t index = 0 ; index < bufSize  ; ++index)
    {
        crc = crcTable[(crc ^ buf[index]) & 0x0f] ^ (crc >> 4);
        crc = crcTable[(crc ^ (buf[index] >> 4)) & 0x0f] ^ (crc >> 4);
        crc = ~crc;
    }
    return crc;
}
Right, I see what you mean - so if you were wanting to CRC two strings together you would feed the CRC from the first string as the init for the second (and so on), nice.

I've been trying to convert the routine to PHP, but struggling somewhat, as PHP doesn't do unsigned integers :(
 
PHP has various options included for CRC32 - either
crc32(),
hash("crc32", $str)
hash("crc32b", $str)

hash returns the result as hex text rather thah a 32 bit value & the two variants use different polynomials - the CCITT or the Ethernet (and .zip etc) ones.

See if any return the same results as your PIC version?
 
OK - got it sorted out (sort of?).

I went at it from a different direction, as from C to PHP was proving troublesome (no unsigned integers in PHP).

I particularly liked the Arduino routine because it used a nice small lookup table, but in the end I had to use a larger one, and only CRC16 not CRC32.

So my 'different direction' was to download a PHP CRC routine, make sure that worked on my server - and then convert that to work under XC8 - and while it's still a pretty large table, been 16 bit it's smaller than most 32 bit ones.

My main use for it is to upload setup changes to remote loggers, these are the URL and files they connect to, and also the timer settings (daily, weekly, hourly, the exact time to do it etc.) While it always works perfectly for me when testing, I've had a couple which have died during changes - but worked perfectly when reinitialised, which restores the original defaults. As they are mostly sat in holes in the ground in far off places it makes it difficult to access them, and I suspect the issue could well be down to very poor signal strength, and corruption of the incoming data?. Part of the data I log is signal strength, and some are working on VERY poor signal levels.
 
I went at it from a different direction, as from C to PHP was proving troublesome (no unsigned integers in PHP).
It's a piggin long way from assembler!!! I know you are VERY conversant with asm but high level languages include people..

You have come a LOOONG way my friend...

Incidentally... Somewhere I have an ASM routine ( albeit for Hitachi ) that requires NO table for CRC16... Algorithm I need to transpose to C...

Looking as we speak..
 
You do not need a table for any CRC, it's just a speed-up method.
The basic system is just a software shift register with XORs added at various points.

There is a good example diagram here:

That's showing CRC16 CCITT; the polynomial values for it (16, 12, 5) are implemented by XORs at the inputs of those stages through the shift register, with the 16th stage being the loop back around to the input.

And an equivalent C source here:

Or one for a CRC32 function:
 
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top