• AVR Freaks

Helpful ReplyHot!PIC24 Hardware CRC

Author
NKurzman
A Guy on the Net
  • Total Posts : 18852
  • Reward points : 0
  • Joined: 2008/01/16 19:33:48
  • Location: 0
  • Status: online
2014/04/03 11:24:00 (permalink)
0

PIC24 Hardware CRC

I am trying to get the CRC Generator for PIC24HJ128GP202 running
I am not having much Luck.
A have a Table driven on, But I may need two polynomilas s why not the HW
Looking at the Past Posts, I did not see a lot of success.
Here is my Code.
Am I doing something wrong.
Also It appears single stepping may be an issue.
Also for x16 + x15 + x2 + 1 should the Polynomial be 0xA001 or 0x8005
 
#define CRC16_POLYNOMIAL ((unsigned short int)0xA001) /*x16 + x15 + x2 + 1 */
 
unsigned short int crc16Compute (const unsigned char *msg, unsigned short int nBytes, unsigned short int InitialValue)
{
   unsigned short int byte;

   CRCCONbits.CRCGO = 0; // in sure CRC Shifter is stopped
   CRCCONbits.PLEN = 16-1; // 16 bit CRC length
   CRCXOR = CRC16_POLYNOMIAL;
   CRCDAT = 0x0000;
   CRCWDAT = InitialValue; // Initial value
   CRCCONbits.CRCGO = 1; // start the CRC Shifter
   for (byte = 0; byte < nBytes; ++byte)
   {
      CRCDAT=msg[byte]; // Load the CRC FIFO
      //while(CRCCONbits.CRCFUL == 1){}; // Wait till FIFO is not full before writing next data
      while(CRCCONbits.CRCMPT == 0){}; // wait for the FIFO to Empty
   }
   CRCDAT = 0x0000; // LastWrite to shift out the Data
   while(CRCCONbits.CRCMPT == 0){}; // wait for the FIFO to Empty
   CRCCONbits.CRCGO = 0; // stop the CRC Shifter
   Nop();
   Nop();
   return CRCWDAT; // return the result
}

#1
t.kerr
Super Member
  • Total Posts : 90
  • Reward points : 0
  • Joined: 2013/10/11 03:55:20
  • Location: USA
  • Status: offline
Re: PIC24 Hardware CRC 2014/04/03 16:22:59 (permalink)
0
This post isn't much help, but I had so much trouble with the hardware CRC module that I finally gave up.  I thought it would be as easy as setting up a polynomial and streaming data through the CRC engine, but not so.  See the example code in the attached application note (AN1148).  You still need to set up loops and conditional tests, and the code in my opinion is much less readable than a common software algorithm implementation.  Luckily for me, the processor was fast enough for my application; I had just hoped to simplify things with a hardware implementation.  Hopefully the code in the app note will be helpful to you.
#2
NKurzman
A Guy on the Net
  • Total Posts : 18852
  • Reward points : 0
  • Joined: 2008/01/16 19:33:48
  • Location: 0
  • Status: online
Re: PIC24 Hardware CRC 2014/04/03 19:02:06 (permalink)
0
Thanks I will take a look.
It maybe time to contact my Microchip F.A.E.
 
The table is fine for me.
But 256 for 8 bit 512 for 16 bit + another 512 for a second 16 bit polynomial.
Plan C is a nibble table that is on 64 bytes ((16 *2) * 2) But I need to calculate the tables and test it.
 
It is in there it should work.
to bad the sample is so weak.
#3
NorthGuy
Super Member
  • Total Posts : 6222
  • Reward points : 0
  • Joined: 2014/02/23 14:23:23
  • Location: Northern Canada
  • Status: online
Re: PIC24 Hardware CRC 2014/04/03 21:07:33 (permalink)
5 (1)
0x8004, I guess 0x8005 will do too.
 
I don't think you need CDAT = 0 at the beginning because this 0 will be processed as a part of the data.
#4
carlos7890
New Member
  • Total Posts : 3
  • Reward points : 0
  • Joined: 2012/08/04 13:22:15
  • Location: 0
  • Status: offline
Re: PIC24 Hardware CRC 2014/09/06 14:07:30 (permalink)
0
Hi t:
I want to calculate the CRC witch data of 8 bits, but the variable VWORD always increments by two.
I do not understand the following paragraph which I copied the Reference Manual for PIC24.
 
"The smallest data element that can be written into the FIFO is one byte. When
PLEN3:PLEN0 ≤ 7, every byte write into the FIFO increments VWORD by one, or by two, for
every word write operation."
Someone could tell me how to do it so that the pointer VWORD is increased by one?
Thank you
#5
davekw7x
Entropy++
  • Total Posts : 1882
  • Reward points : 0
  • Joined: 2012/01/16 12:01:07
  • Location: Second star on the right, straight on till morning
  • Status: offline
Re: PIC24 Hardware CRC 2014/09/07 14:03:54 (permalink)
4 (1)
carlos7890
... VWORD always increments by two....
 
"The smallest data element that can be written into the FIFO is one byte...

 
In magic shows, many significant tricks are done with mirrors.
 
In C programs, many significant tricks are done with pointers (sometimes it may seem like magic, but it's really fundamental):
 
From one of my projects with dsPIC33EP256GP502: (Register names for other CPUs may be a little different, but the idea is the same.)


uint8_t CRC_ChecksumBytes(uint8_t *data, int number, uint8_t crc_init)
{
    //Define a pointer to use for writing a single byte at a time
    // to CRCDATL.
    //
    volatile uint8_t *datareg = (uint8_t *)&CRCDATL;
.
.
.
    // In the loop where you copy the data to the CRC engine
    //
       *datareg = *(data++);
 

 
 
Regards,
 
Dave
post edited by davekw7x - 2014/09/07 14:22:23

Sometimes I just can't help myself...
#6
davekw7x
Entropy++
  • Total Posts : 1882
  • Reward points : 0
  • Joined: 2012/01/16 12:01:07
  • Location: Second star on the right, straight on till morning
  • Status: offline
Re: PIC24 Hardware CRC 2014/09/07 19:05:26 (permalink) ☄ Helpfulby Batloid 2020/07/30 13:07:31
5 (4)
To the OP:  Sorry I didn't notice this thread when you originally posted.  I have one 24HJ project that I never finished, but I did explore the CRC module.
 
Here's the deal for 16-bit CRCs using PIC Hardware.  I'm thinking the OP knows (most of) this, but I summarize the things that I learned.
 
1. For a 16-bit CRC the message going through the CRC engine must have an even number of bytes.  If you have an odd number of bytes in your message, save the odd one for last and do it with a software-shift or table lookup technique (using the CRC calculated from the first words to load the CRC register for the final shift).
 
2.  The scheme implemented in the CRC module requires that you append some zero bits after you have done all of the shifts for the actual calculation.  A 16-bit CRC requires 16 extra bits (two byes or one word).  These extra zero bits are not part of the CRC mathematical definition and will not be part of any "brute-force" crc shift algorithm that you want to use to check the results.  They are not part of the message.  They are just to "flush" the stuff out of the CRC hardware as implemented.
 
3. I use on-line CRC generators such as the one at http://www.zorc.breitbandkatze.de/crc.html to validate.


4. Polynomials in just of about all of the literature do not show the most significant bit and the least-significant bit is usually 1.  For the Microchip CRC engine the msb is 1 but is not part of the polynomial value that you load into the XOR register.  The lsb is always assumed to be 1.  It doesn't matter if you set the lsb or not, the hardware treats it as 1.
 
So: Your polynomial can be given to the CRC engine as 0x8005 or 0x8004.  I usually let the lsb be set so that I can hand the same polynomial definition to a software-shift routine, and my software routines do exactly what they are told (so if you mean 0x8005, you give it 0x8005).
 
 
Now, I always define some kind of test before I write code, so...
 
 
Example from the web site i linked above:
 
CRC Order: 16
CRC Polynom: 8005
Initial Value: 0
Uncheck the "reverse data bytes" and "reverse CRC result before final XOR"check boxes

Data sequence 12345678
(Note that these are ASCII chars, so the message has eight bytes: 0x31, 0x32, ...)
There is a way to get non-ASCII binary values in the message, but I'll just use these for now.

Click "compute!"

And I see

95FD (hex), 8 data bytes


 
Now, I'm ready for my program.  (Pretty much like yours except for the byte write stuff.)
 
I usually make (at least) two functions:
One to initialize the CRC engine.  This one is very simple.  Others (for devices with 32-bit CRC modules) might be a little more involved.  Not much.

// A degree 16 polynomial is the largest possible for this device (PIC24HJxxxGP202).
// For a degree 16 polynomial, PLEN = 15
// TODO: Check for valid length.
//
void Crc16Init(uint16_t poly, int poly_degree)
{
    CRCCONbits.PLEN = poly_degree - 1;
    CRCXOR = poly;
}

 Then a function to feed an array of bytes (or in some cases an array of 16-bit words) to the shifter.
 
Now...
 
To feed bytes to a 16-bit CRC polynomial with Microchip CRC modules there are two ways:
 
1. Pack the bytes, two to a word and assign that to the CRCDAT register.
 

 
uint16_t Crc16SendBytes(uint8_t *data, int length, uint16_t InitCrcWord)
{
    CRCWDAT = InitCrcWord;
    CRCCONbits.CRCGO = 1;
    while (!CRCCONbits.CRCMPT)
        ;
    int i;
    // Takes about 4.6 us for eight bytes on a 24HJ running at 40 MIPS
    uint16_t dataword;
    for (i = 0; i < length; i += 2) {
        dataword = ((uint16_t)(*data)<< 8) + *(data+1);
        data += 2;
        while (CRCCONbits.CRCFUL)
            ;
        CRCDAT = dataword;
    }

    // Make sure it can take the last bytes
    while (CRCCONbits.CRCFUL)
        ;
 
    // 16-bit writes two zero bytes to flush out the system
    CRCDAT = 0;
 
    // Wait until everything has been taken from the FIFO
    // IT's still shifting, so give it a little extra after that
    while (!CRCCONbits.CRCMPT)
        ;
    Nop();
    Nop();
    Nop();
    Nop();
    Nop();
    CRCCONbits.CRCGO = 0;
    return CRCWDAT;



 
2. The other way is to feed a byte at a time to the CRCDAT register.  As I mentioned to the highjacker, you have to make sure it does a byte write, not a word write. So the loop goes like this:
 

    // Takes about 5.6 us for eight bytes on a 24HJ running at 40 MIPS
    uint8_t *dpt = (uint8_t *)&CRCDAT;
    for (i = 0; i < length; i ++) {
        while (CRCCONbits.CRCFUL)
            ;
        *dpt = *(data++);
    }

 
 
Unlike the 32-bit modules for certain other PICs, there is no affirmative way to test to see that all shifting has been done.  When the FIFO is empty, there is still some shifting for a few clock pulses.  I think a couple of Nops would be sufficient, given the other stuff going on, but I give it a couple extra just for kicks.
 
Anyhow the test goes something like this
 

uint8_t msg1_8[8] = {'1', '2', '3', '4', '5', '6', '7', '8'};

int main()
{
    // Initialize clocks, UART, other I/O, etc...
 
    printf("\n\n24HJ128GP202 CRC Test Program\n");
    printf("Compiled with XC16 version %d on %s at %s\n",
            __XC16_VERSION, __DATE__, __TIME__);
    printf("PIC24HJ128GP202 running at %d MIPs\n", MIPS);
    printf("CRC polynomial = 0x%04X, degree = %d\n", poly, poly_degree);
    printf("Initial value for calculation = 0x%04X\n", initial_crc);
 
    printf("The mesage: ");
    for (i = 0; i < sizeof(msg1_8); i++) {
        printf(" 0x%02x", msg1_8[i]);
    }
    printf("\n");
 
    Crc16Init(poly, poly_degree);
    LED2 = 1; // Look at timing on 'scope
    uint16_t value = Crc16SendBytes(msg1_8, 8, initial_crc);
    LED2 = 0;
    printf("CRC value = 0x%04X\n", value);

 
Output:
 
24HJ128GP202 CRC Test Program
Compiled with XC16 version 1021 on Sep  7 2014 at 18:16:49
PIC24HJ128GP202 running at 40 MIPs
CRC polynomial = 0x8005, degree = 16
Initial value for calculation = 0x0000
The mesage:  0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38
CRC value = 0x95FD



Taa-daa!
 
 
Regards,

Dave
post edited by davekw7x - 2014/09/12 21:47:46

Sometimes I just can't help myself...
#7
Batloid
New Member
  • Total Posts : 5
  • Reward points : 0
  • Joined: 2019/02/18 07:41:56
  • Location: 0
  • Status: offline
Re: PIC24 Hardware CRC 2020/07/30 13:16:41 (permalink)
0
Even more, I modified de code generated by MCC (MpLab Code Configurator) for a DSPIC33EP64GP502, and used this code in the PIC24FJ64GA106.
Both code was tested in the same conditions.
PIC24FJ64GA106 @ 32mhz (16MIPS)
The result was.
Your code: 16,178 us
MCC adapted code: 64,25us
 
If someone ask why I modified the code, it was because MCC at the date does not have de CRC module for this PIC24.
 
Regads
Alejandro Cabral
 
 
#8
Jump to:
© 2020 APG vNext Commercial Version 4.5