This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Unexpected Results from TM4C129 CRC-32 Calculations



Hey guys,


I'm trying to calculate some CRC-32 values using the TM4C129's CRC peripheral, but I'm running into some issues and I'm unable to get the peripheral to behave the way I'd like it to.


As a reference, I tried passing the ASCII string "Test" through two CRC utilities:


Online tool - http://www.lammertbies.nl/comm/info/crc-calculation.html

crcmod Python module - https://pypi.python.org/pypi/crcmod/1.7


Both of these tools generate a CRC-32 of 0x784DD132 from "Test", so these two are obviously doing the same calculation. My problem is that, regardless of how I've thought of configuring it, the TM4C129 CRC peripheral is not able to match the output from these tools.

Here's the snippet that I was testing with:

  uint32_t delay = 40000000;
  SysCtlPeripheralEnable(SYSCTL_PERIPH_CCM0);
  SysCtlDelay(delay);
  SysCtlPeripheralReset(SYSCTL_PERIPH_CCM0);
  SysCtlDelay(delay);

  uint8_t data[4] = {'T', 'e', 's', 't'};
  uint32_t result;
  CRCConfigSet(CCM0_BASE, CRC_CFG_SIZE_8BIT | CRC_CFG_ENDIAN_SBHW | | CRC_CFG_ENDIAN_SHW | CRC_CFG_TYPE_P4C11DB7 | CRC_CFG_INIT_0 | CRC_CFG_RESINV);
  SysCtlDelay(delay);
  result = CRCDataProcess(CCM0_BASE, (uint32_t *) data, 4, true);

Python's crcmod module can be configured in various ways, and its documentation said that for a regular CRC-32, you use a reversed algorithm with an initial value of 0 and XOR the output with 0xFFFFFFFF. It isn't clear what it means by a "reversed algorithm", so I tried OR'ing in all the combinations of CRC_CFG_OBR and CRC_CFG_IBR with the config macro I used. I also used the half-word and half-word byte swaps so the input would be big-endian. Here are the results:

None of the combinations mentioned above generated the same CRC as the reference tools. I'm guessing that my configuration of the peripheral is incorrect, but I've tried a pretty wide range of configurations and nothing seems to be working. If anyone could steer me in the right direction is would be greatly appreciated.


Thanks

  • Hello Matthew,

    Why is the configuration of CRC using two endianess and why is there a "||" operator instead of "|"

     CRC_CFG_ENDIAN_SBHW | | CRC_CFG_ENDIAN_SHW

    Regards

    Amit

  • Hey Amit,


    The operator mismatch was just an editing problem with my post. After I pasted my code into the post I added the endianness flags manually and used the wrong operator. I've been testing with bitwise-OR.

    I only tried the two endianness flags after I had troubles getting the right results without them. I don't know how the other tools I tested with are implemented, so I thought that the storage of the ASCII characters in the TM4C129's memory might change how it's fed into the CRC peripheral. After taking a look at the datasheet and Tivaware implementation it looks like these don't have any effect since the bytes are fed into the CRC's data in register sequentially and endianness isn't a factor.

    I just ran a super inefficient test that ran through every combination of macros with the peripheral configured for 32-bit data input. It's ugly, but here's the code:

      uint32_t delay = 4000000;
      SysCtlPeripheralEnable(SYSCTL_PERIPH_CCM0);
      SysCtlDelay(delay);
      SysCtlPeripheralReset(SYSCTL_PERIPH_CCM0);
      SysCtlDelay(delay);
    
      uint8_t data[4] = {'T', 'e', 's', 't'};
      uint32_t results[32];
    
      /// Macros that evry calculation uses
      uint32_t baseMacro = CRC_CFG_INIT_0 | CRC_CFG_SIZE_32BIT | CRC_CFG_TYPE_P4C11DB7;
      /// Every combination of macros not related to Endianness
      uint32_t macros[8] = { 0,
          CRC_CFG_RESINV,
          CRC_CFG_RESINV | CRC_CFG_OBR,
          CRC_CFG_RESINV | CRC_CFG_IBR,
          CRC_CFG_RESINV | CRC_CFG_IBR | CRC_CFG_OBR,
          CRC_CFG_OBR,
          CRC_CFG_OBR | CRC_CFG_IBR,
          CRC_CFG_IBR};
    
      uint32_t endiannessMacros[4] = { 0,
          CRC_CFG_ENDIAN_SBHW,
          CRC_CFG_ENDIAN_SHW,
          CRC_CFG_ENDIAN_SBHW |  CRC_CFG_ENDIAN_SHW};
    
      for (int i = 0; i < 8; ++i) {
        for (int j = 0; j < 4; j++) {
          CRCConfigSet(CCM0_BASE, baseMacro | macros[i] | endiannessMacros[j]);
          SysCtlDelay(delay);
          results[i*4 + j] = CRCDataProcess(CCM0_BASE, (uint32_t *) data, 1, true);
          SysCtlDelay(delay);
        }
      }

    After this code finished, none of the elements of results matches the CRC calculated using the other tools. The TM4C129 is running at 120MHz so each of the SysCtlDelay() calls works out to 100ms which I imagine is long enough for the CRC peripheral to fully settle.

  • Hello Matthew,

    I had to modify the test program you had as follows

    uint32_t result;

    int
    main(void)
    {
        uint32_t delay = 400;
        SysCtlPeripheralEnable(SYSCTL_PERIPH_CCM0);
        SysCtlDelay(delay);
        SysCtlPeripheralReset(SYSCTL_PERIPH_CCM0);
        SysCtlDelay(delay);

        uint8_t data[4] = {'T', 'e', 's', 't'};

        CRCConfigSet(CCM0_BASE, CRC_CFG_SIZE_8BIT | CRC_CFG_TYPE_P4C11DB7 | CRC_CFG_INIT_0);
        SysCtlDelay(delay);
        result = CRCDataProcess(CCM0_BASE, (uint32_t *) data, 4, true);

        while(1);
    }

    and checked it against the online CRC32 calculator.

    http://depa.usst.edu.cn/chenjq/www2/software/crc/CRC_Javascript/CRCcalculation.htm

    Both ended up with the same result

    Regards

    Amit

  • Hey Amit,

    Thanks for the reply. Interestingly enough, that tool gives different results from the ones I was testing with, so the issue seems to be more in understanding how these tools work.

    I initially thought that the TM4C129 would need to verify CRC-32 values calculated by an external tool (specifically the Python tool I posted), but it turns out that the specific CRC check I'm concerned with is both checked and generated by the TM4C129, so all that matters is consistency (i.e. the same algorithm is used for generating/checking) and the specific algorithm used is irrelevant. I might investigate this further when I have the time, but for now I don't think I have much of an issue.

    Thanks again.

  • Hello Matthew,

    I was also taken aback when I saw different results from different web-tools. There is definitely some thing about each of these tools compute the CRC (one thought is that they are using some different seed and/or polynomial pair)

    Anyways, good to see you are ungated.

    Regards

    Amit

  • Hey Amit,

    It looks like I'm not quite out of the woods yet. After generating some CRCs, I wanted to see if I could verify them as well. Since the peripheral is configured to operate on single bytes, I wasn't sure how the 32-bit result would need to be stored in memory for it to work when passed back through the CRC peripheral in 8-bit mode. To do this, I added the following to the end of my test:

        /// CRC is 0xE199ABD9
        uint8_t wordOrder[8] = {'T', 'e', 's', 't', 0xD9, 0xAB, 0x99, 0xE1 };
        uint8_t byteOrder[8] = {'T', 'e', 's', 't', 0xE1, 0x99, 0xAB, 0xD9 };

    Things get weird here though. If I add the following, everything works out great:

        delay = 40000000;  ///1s. Lots of time.
        SysCtlDelay(delay);
        uint32_t byteResult = CRCDataProcess(CCM0_BASE, (uint32_t*)byteOrder, 8, true); // == 0
        SysCtlDelay(delay);
        uint32_t wordResult = CRCDataProcess(CCM0_BASE, (uint32_t*)wordOrder, 8, true); // != 0

    From these results, it looks like the byteOrder array is the way it should be stored. However, if I run this instead, the values don't match up:

        delay = 40000000;  ///1s. Lots of time.
        SysCtlDelay(delay);
        uint32_t wordResult = CRCDataProcess(CCM0_BASE, (uint32_t*)wordOrder, 8, true); // != 0
        SysCtlDelay(delay);
        uint32_t byteResult = CRCDataProcess(CCM0_BASE, (uint32_t*)byteOrder, 8, true); // != 0?

    Even though I'm inserting a full one second delay between calculations, it looks like the second CRC calculation gets messed up due to the first calculation. Finally, if I replace the test with this, it works again:

        delay = 40000000;  ///1s. Lots of time.
        SysCtlDelay(delay);
        uint32_t wordResult = CRCDataProcess(CCM0_BASE, (uint32_t*)wordOrder, 8, true); // != 0
        SysCtlDelay(delay);
        CRCConfigSet(CCM0_BASE, CRC_CFG_SIZE_8BIT | CRC_CFG_TYPE_P4C11DB7 | CRC_CFG_INIT_0);
        SysCtlDelay(delay);
        uint32_t byteResult = CRCDataProcess(CCM0_BASE, (uint32_t*)byteOrder, 8, true); // == 0

    It seems like the peripheral only works here if I reconfigure it between calculations. Is this the expected behaviour, a known bug or something else? I don't see anything in the datasheet/Tivaware documentation mentioning that you need to rewrite the CRCCTRL register for each calculation, but that's what it looks like from my testing.

    Any thoughts?

  • Hello Matthew,

    You are correct there. When doing separate calculations, the CRC must be re-initialized, otherwise it uses the current CRC output for the next computation.

    Regards

    Amit