Atmel SAM G55 CRCCU CRC32 计算不可复制

Atmel SAM G55 CRCCU CRC32 calculation not replicateable

我们在我们的一个应用程序中使用了 Atmel SAM G55。在某些时候,我们想在 x86 系统上计算一个 CRC32 并将其传递给 G55(Arm 32 位)。

对于 G55,我们使用 CRCCU 来计算 CRC32:

uint32_t crccu_crc32(uint8_t *p_buffer, uint32_t ul_length, uint32_t *pcrc)
{
    uint32_t ul_crc;
    uint32_t ul_timeout = 0;
    if (*pcrc == ~0) {
        /* Reset the CRCCU */
        crccu_reset(CRCCU);
    }
    memset((void *)&_crc_dscr, 0, sizeof(crccu_dscr_type_t));
    _crc_dscr.ul_tr_addr = (uint32_t) p_buffer;
    /* Transfer width: byte, interrupt enable */
    _crc_dscr.ul_tr_ctrl = (uint32_t)ul_length | (2 << 24);
    /* Configure CRCCU mode */
    crccu_configure_mode(CRCCU, CRCCU_MR_ENABLE | CRCCU_MR_PTYPE_CCITT8023 | CRCCU_MR_DIVIDER(0));
    /* Start the CRC calculation */
    crccu_enable_dma(CRCCU);

    /* Wait for calculation ready */
    while ((crccu_get_dma_status(CRCCU) == CRCCU_DMA_SR_DMASR) &&
           (ul_timeout++ < 0xFFFFFFFF)) {
    }
    if (ul_timeout == 0xFFFFFFFF) {
        return 1;
    }
    /* Get CRC value */
    *pcrc = crccu_read_crc_value(CRCCU);
    return 0;
}

这个函数与 ASF4 的 CRC-HAL 松散相关并且工作正常(至少我们是这么认为的)。 但是,我们无法在我们的 x86 机器上计算相同的 CRC32。

为了测试 CRC32 计算,我们使用以下测试数组:

uint32_t chksmtest[8] = {6448116,148714,884134,43,5487416,45486,8484384,64817};

使用 CRCCU 计算 CRC32 得到 0x4d4ee8cc 结果。 我们在 x86 机器上尝试了几种 CRC32 实现,但无法复制此结果。我们知道CRCCU先计算CRC32LSB(G55 reference page 901) and the polynomial is 0x04C11DB7 (G55 reference page 916).

即使颠倒位 and/or 字节顺序,我们也无法复制结果。我们必须使用哪种 CRC32 实现来存档与 CRCCU 相同的结果?我们尝试了 libiberty 实现以及 W3 实现。

您的硬件正在使用多项式 0x04c11db7 计算 non-reflected 32 位 CRC,初始值为 0xffffffff,没有最终异或。该 CRC 有一个名称:CRC-32/MPEG-2.

如前所述,您提供的 32 位值按 little-endian 顺序处理,最低有效字节在前。

当且仅当 下面的 C 代码在 little-endian 机器(例如 x86)上是 运行 时,它将产生您想要的结果:

#include <stddef.h>

unsigned crc32_mpeg2(unsigned crc, void const *mem, size_t len) {
    unsigned char const *data = mem;
    if (data == NULL)
        return 0xffffffff;
    while (len--) {
        crc ^= (unsigned)(*data++) << 24;
        for (unsigned k = 0; k < 8; k++)
            crc = crc & 0x80000000 ? (crc << 1) ^ 0x4c11db7 : crc << 1;
    }
    return crc & 0xffffffff;
}

#include <stdio.h>
#include <stdint.h>

int main(void) {
    uint32_t chksmtest[8] =
        {6448116,148714,884134,43,5487416,45486,8484384,64817};
    printf("0x%08x\n", crc32_mpeg2(crc32_mpeg2(0, NULL, 0), chksmtest, 8 * 4));
    return 0;
}

输出:

0x4d4ee8cc

以上是一个简单的bit-wise实现。您可以查看 crcany 在软件中为该 CRC 生成更高效的 CRC 实现。