机灵小老鼠 发表于 2025-3-27 17:37:41

请教USB传输中CRC5的计算问题,谢谢

我始终不能使用 在线-ip33 中的计算工具,将图中的给出的传输包中的CRC5计算正确

图中: ADDR=2,ENDP=0,那在在线-ip33 中, 选择CRC计算类型是 CRC-5/USB,
现在7位ADDR 和 4位ENDP,低位在前的位数据排列为0100 000 0000,
请问我填写CRC计算的数据是 0x40 0x00 吗?得到CRC5的计算结果是 0x18,
和图片中的 crc5=0x15 不同. 请问该如何计算呢? 谢谢

机灵小老鼠 发表于 2025-3-27 17:40:21

而数据传输包中的CRC16, 直接按照实例数据,使用 在线-ip33 的CRC-16/USB计算工具, 计算出来的结果和实例的CRC16数据是一致的!

机灵小老鼠 发表于 2025-3-27 17:41:00

CRC5存在数据的补位问题,不知道如何处理?

ercircle 发表于 2025-3-27 21:03:06



搜刮了下github,找到两个比较权威的仓库有crc5函数,其中CRC5_MSBfirst计算结果和图中一致可以参考下

opentitan/hw/dv/dpi/usbdpi/usb_crc.c at master · lowRISC/opentitan
wireshark/wsutil/crc5.c at master · wireshark/wireshark




示例代码:
#include <stdint.h>
#include <stdio.h>
#define INT_SIZE 32// Assumes 32-bit integer size
uint32_t CRC5_MSBfirst(uint32_t dwInput, int iBitcnt) {
const uint32_t poly5 = (0x05 << (INT_SIZE - 5));
uint32_t crc5 = (0x1f << (INT_SIZE - 5));
uint32_t udata = (dwInput << (INT_SIZE - iBitcnt));

if ((iBitcnt < 1) || (iBitcnt > INT_SIZE)) {// Validate iBitcnt
    return 0xffffffff;
}

while (iBitcnt--) {
    if ((udata ^ crc5) & (0x1 << (INT_SIZE - 1))) {// bit4 != bit4?
      crc5 <<= 1;
      crc5 ^= poly5;
    } else {
      crc5 <<= 1;
    }

    udata <<= 1;
}

// Shift back into position
crc5 >>= (INT_SIZE - 5);

// Invert contents to generate crc field
crc5 ^= 0x1f;

return crc5;
}// CRC5()


/* This is the little endian version, so you can feed an 11 bit data
* value and get back 5 bits to OR in to the top to construct 16 bits
*
* Adapted by mdhayter
*/

uint32_t CRC5(uint32_t dwInput, int iBitcnt) {
const uint32_t poly5 = 0x14;
uint32_t crc5 = 0x1f;
uint32_t udata = dwInput;

if ((iBitcnt < 1) || (iBitcnt > INT_SIZE)) {// Validate iBitcnt
    return 0xffffffff;
}

while (iBitcnt--) {
    if ((udata ^ crc5) & 0x01) {
      crc5 >>= 1;
      crc5 ^= poly5;
    } else {
      crc5 >>= 1;
    }

    udata >>= 1;
}

// Invert contents to generate crc field
crc5 ^= 0x1f;

return crc5;
}// CRC5()

static uint8_t crc5_usb_bits(uint32_t v, int vl, uint8_t ival)
{
    /* This function is based on code posted by John Sullivan to Wireshark-dev
   * mailing list on Jul 21, 2019.
   *
   * "One of the properties of LFSRs is that a 1 bit in the input toggles a
   *completely predictable set of register bits *at any point in the
   *future*. This isn't often useful for most CRC caculations on variable
   *sized input, as the cost of working out which those bits are vastly
   *outweighs most other methods."
   *
   * In USB 2.0, the CRC5 is calculated on either 11 or 19 bits inputs,
   * and thus this approach is viable.
   */
    uint8_t rv = ival;
    static const uint8_t bvals = {
      0x1e, 0x15, 0x03, 0x06, 0x0c, 0x18, 0x19, 0x1b,
      0x1f, 0x17, 0x07, 0x0e, 0x1c, 0x11, 0x0b, 0x16,
      0x05, 0x0a, 0x14
    };
    for (int i = 0; i < vl; i++) {
      if (v & (1 << i)) {
            rv ^= bvals;
      }
    }
    return rv;
}
uint8_t crc5_usb_11bit_input(uint16_t input)
{
    return crc5_usb_bits(input, 11, 0x02);
}

int main() {
    uint8_t addr = 0x20;
    uint8_t endp = 0;
    uint32_t combined_data = ((uint32_t)addr << 4) | (endp & 0x0F); // 组合 7 位 ADDR 和 4 位 ENDP
    printf("combined_data 结果: 0x%04X\n", combined_data);
    uint8_t result = CRC5_MSBfirst(combined_data,11);
    printf("MSB CRC5 结果: 0x%02X\n", result);
    printf("MSB CRC5 ~结果: 0x%02X\n", (~result) & 0xFF);
   result = CRC5(combined_data,11);
    printf("LSB CRC5 结果: 0x%02X\n", result);
    printf("LSB CRC5 ~结果: 0x%02X\n", (~result) & 0xFF);

    auto x = crc5_usb_11bit_input(combined_data);
    printf("crc5_usb_11bit_input LSB 结果: 0x%02X\n", x);
    return 0;
}

机灵小老鼠 发表于 2025-3-27 21:50:06

明天我来试试程序计算,非常感谢您的指点!

机灵小老鼠 发表于 2025-3-30 18:55:54

把程序移植到 擎天柱 核心板上,KC251 编译测试了一下, 使用USB已知数据计算了 CRC5, 结果符合样本数据(见 www.usbzh.com 中usb报文)
具体结果描述参见 main.c 中说明;
下面附上整个工程,再次感谢 ercircle 的指点!

ercircle 发表于 2025-3-30 22:58:10

机灵小老鼠 发表于 2025-3-30 18:55
把程序移植到 擎天柱 核心板上,KC251 编译测试了一下, 使用USB已知数据计算了 CRC5, 结果符合样本数据( ...

{:4_250:}真棒,指点谈不上,一起学习
页: [1]
查看完整版本: 请教USB传输中CRC5的计算问题,谢谢