Merge pull request #2860 from openmv/update_crc_code
Some checks are pending
🔎 Check Code Formatting / formatting-check (push) Waiting to run
🔥 Firmware Build / build-firmware (0, ARDUINO_GIGA) (push) Waiting to run
🔥 Firmware Build / build-firmware (0, ARDUINO_NANO_33_BLE_SENSE) (push) Waiting to run
🔥 Firmware Build / build-firmware (0, ARDUINO_NANO_RP2040_CONNECT) (push) Waiting to run
🔥 Firmware Build / build-firmware (0, ARDUINO_NICLA_VISION) (push) Waiting to run
🔥 Firmware Build / build-firmware (0, ARDUINO_PORTENTA_H7) (push) Waiting to run
🔥 Firmware Build / build-firmware (0, DOCKER) (push) Waiting to run
🔥 Firmware Build / build-firmware (0, OPENMV2) (push) Waiting to run
🔥 Firmware Build / build-firmware (0, OPENMV3) (push) Waiting to run
🔥 Firmware Build / build-firmware (0, OPENMV4) (push) Waiting to run
🔥 Firmware Build / build-firmware (0, OPENMV4P) (push) Waiting to run
🔥 Firmware Build / build-firmware (0, OPENMVPT) (push) Waiting to run
🔥 Firmware Build / build-firmware (0, OPENMV_AE3) (push) Waiting to run
🔥 Firmware Build / build-firmware (0, OPENMV_N6) (push) Waiting to run
🔥 Firmware Build / build-firmware (0, OPENMV_RT1060) (push) Waiting to run
🔥 Firmware Build / build-firmware (1, OPENMV_N6) (push) Waiting to run
🔥 Firmware Build / code-size-report (push) Blocked by required conditions
🔥 Firmware Build / stable-release (push) Blocked by required conditions
🔥 Firmware Build / development-release (push) Blocked by required conditions

common: Update crc code.
This commit is contained in:
Ibrahim Abdelkader 2025-09-25 19:15:12 +03:00 committed by GitHub
commit 7f439f56de
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 457 additions and 113 deletions

View File

@ -174,6 +174,11 @@ MPY_CFLAGS += -DMICROPY_PY_IMU=1
MPY_MKARGS += MICROPY_PY_IMU=1
endif
ifeq ($(MICROPY_PY_CRC), 1)
MPY_CFLAGS += -DMICROPY_PY_CRC=1
MPY_MKARGS += MICROPY_PY_CRC=1
endif
ifeq ($(MICROPY_PY_BTREE), 1)
MPY_CFLAGS += -DMICROPY_PY_BTREE=1
MPY_MKARGS += MICROPY_PY_BTREE=1

View File

@ -20,6 +20,7 @@ MICROPY_PY_TOF = 1
MICROPY_PY_ULAB = 1
MICROPY_PY_DISPLAY = 1
MICROPY_PY_IMU = 1
MICROPY_PY_CRC = 1
MICROPY_PY_AUDIO = 1
MICROPY_PY_ML = 1
MICROPY_PY_ML_TFLM = 1

View File

@ -30,6 +30,7 @@ MICROPY_PY_CSI = 1
MICROPY_PY_CSI_NG = 1
MICROPY_PY_FIR = 1
MICROPY_PY_IMU = 1
MICROPY_PY_CRC = 1
MICROPY_PY_ULAB = 1
MICROPY_PY_DISPLAY = 1
MICROPY_PY_TV = 1

View File

@ -23,50 +23,83 @@
*/
#include "omv_crc.h"
// CRC16 lookup table for polynomial 0xF94F (HD=6, len=135)
static const uint16_t crc16_table[256] = {
0x0000, 0xBAAD, 0xCFF7, 0x755A, 0x2543, 0x9FEE, 0xEAB4, 0x5019,
0x4A86, 0xF02B, 0x8571, 0x3FDC, 0x6FC5, 0xD568, 0xA032, 0x1A9F,
0x950C, 0x2FA1, 0x5AFB, 0xE056, 0xB04F, 0x0AE2, 0x7FB8, 0xC515,
0xDF8A, 0x6527, 0x107D, 0xAAD0, 0xFAC9, 0x4064, 0x353E, 0x8F93,
0x90B5, 0x2A18, 0x5F42, 0xE5EF, 0xB5F6, 0x0F5B, 0x7A01, 0xC0AC,
0xDA33, 0x609E, 0x15C4, 0xAF69, 0xFF70, 0x45DD, 0x3087, 0x8A2A,
0x05B9, 0xBF14, 0xCA4E, 0x70E3, 0x20FA, 0x9A57, 0xEF0D, 0x55A0,
0x4F3F, 0xF592, 0x80C8, 0x3A65, 0x6A7C, 0xD0D1, 0xA58B, 0x1F26,
0x9BC7, 0x216A, 0x5430, 0xEE9D, 0xBE84, 0x0429, 0x7173, 0xCBDE,
0xD141, 0x6BEC, 0x1EB6, 0xA41B, 0xF402, 0x4EAF, 0x3BF5, 0x8158,
0x0ECB, 0xB466, 0xC13C, 0x7B91, 0x2B88, 0x9125, 0xE47F, 0x5ED2,
0x444D, 0xFEE0, 0x8BBA, 0x3117, 0x610E, 0xDBA3, 0xAEF9, 0x1454,
0x0B72, 0xB1DF, 0xC485, 0x7E28, 0x2E31, 0x949C, 0xE1C6, 0x5B6B,
0x41F4, 0xFB59, 0x8E03, 0x34AE, 0x64B7, 0xDE1A, 0xAB40, 0x11ED,
0x9E7E, 0x24D3, 0x5189, 0xEB24, 0xBB3D, 0x0190, 0x74CA, 0xCE67,
0xD4F8, 0x6E55, 0x1B0F, 0xA1A2, 0xF1BB, 0x4B16, 0x3E4C, 0x84E1,
0x8D23, 0x378E, 0x42D4, 0xF879, 0xA860, 0x12CD, 0x6797, 0xDD3A,
0xC7A5, 0x7D08, 0x0852, 0xB2FF, 0xE2E6, 0x584B, 0x2D11, 0x97BC,
0x182F, 0xA282, 0xD7D8, 0x6D75, 0x3D6C, 0x87C1, 0xF29B, 0x4836,
0x52A9, 0xE804, 0x9D5E, 0x27F3, 0x77EA, 0xCD47, 0xB81D, 0x02B0,
0x1D96, 0xA73B, 0xD261, 0x68CC, 0x38D5, 0x8278, 0xF722, 0x4D8F,
0x5710, 0xEDBD, 0x98E7, 0x224A, 0x7253, 0xC8FE, 0xBDA4, 0x0709,
0x889A, 0x3237, 0x476D, 0xFDC0, 0xADD9, 0x1774, 0x622E, 0xD883,
0xC21C, 0x78B1, 0x0DEB, 0xB746, 0xE75F, 0x5DF2, 0x28A8, 0x9205,
0x16E4, 0xAC49, 0xD913, 0x63BE, 0x33A7, 0x890A, 0xFC50, 0x46FD,
0x5C62, 0xE6CF, 0x9395, 0x2938, 0x7921, 0xC38C, 0xB6D6, 0x0C7B,
0x83E8, 0x3945, 0x4C1F, 0xF6B2, 0xA6AB, 0x1C06, 0x695C, 0xD3F1,
0xC96E, 0x73C3, 0x0699, 0xBC34, 0xEC2D, 0x5680, 0x23DA, 0x9977,
0x8651, 0x3CFC, 0x49A6, 0xF30B, 0xA312, 0x19BF, 0x6CE5, 0xD648,
0xCCD7, 0x767A, 0x0320, 0xB98D, 0xE994, 0x5339, 0x2663, 0x9CCE,
0x135D, 0xA9F0, 0xDCAA, 0x6607, 0x361E, 0x8CB3, 0xF9E9, 0x4344,
0x59DB, 0xE376, 0x962C, 0x2C81, 0x7C98, 0xC635, 0xB36F, 0x09C2
0x0000, 0xF94F, 0x0BD1, 0xF29E, 0x17A2, 0xEEED, 0x1C73, 0xE53C,
0x2F44, 0xD60B, 0x2495, 0xDDDA, 0x38E6, 0xC1A9, 0x3337, 0xCA78,
0x5E88, 0xA7C7, 0x5559, 0xAC16, 0x492A, 0xB065, 0x42FB, 0xBBB4,
0x71CC, 0x8883, 0x7A1D, 0x8352, 0x666E, 0x9F21, 0x6DBF, 0x94F0,
0xBD10, 0x445F, 0xB6C1, 0x4F8E, 0xAAB2, 0x53FD, 0xA163, 0x582C,
0x9254, 0x6B1B, 0x9985, 0x60CA, 0x85F6, 0x7CB9, 0x8E27, 0x7768,
0xE398, 0x1AD7, 0xE849, 0x1106, 0xF43A, 0x0D75, 0xFFEB, 0x06A4,
0xCCDC, 0x3593, 0xC70D, 0x3E42, 0xDB7E, 0x2231, 0xD0AF, 0x29E0,
0x836F, 0x7A20, 0x88BE, 0x71F1, 0x94CD, 0x6D82, 0x9F1C, 0x6653,
0xAC2B, 0x5564, 0xA7FA, 0x5EB5, 0xBB89, 0x42C6, 0xB058, 0x4917,
0xDDE7, 0x24A8, 0xD636, 0x2F79, 0xCA45, 0x330A, 0xC194, 0x38DB,
0xF2A3, 0x0BEC, 0xF972, 0x003D, 0xE501, 0x1C4E, 0xEED0, 0x179F,
0x3E7F, 0xC730, 0x35AE, 0xCCE1, 0x29DD, 0xD092, 0x220C, 0xDB43,
0x113B, 0xE874, 0x1AEA, 0xE3A5, 0x0699, 0xFFD6, 0x0D48, 0xF407,
0x60F7, 0x99B8, 0x6B26, 0x9269, 0x7755, 0x8E1A, 0x7C84, 0x85CB,
0x4FB3, 0xB6FC, 0x4462, 0xBD2D, 0x5811, 0xA15E, 0x53C0, 0xAA8F,
0xFF91, 0x06DE, 0xF440, 0x0D0F, 0xE833, 0x117C, 0xE3E2, 0x1AAD,
0xD0D5, 0x299A, 0xDB04, 0x224B, 0xC777, 0x3E38, 0xCCA6, 0x35E9,
0xA119, 0x5856, 0xAAC8, 0x5387, 0xB6BB, 0x4FF4, 0xBD6A, 0x4425,
0x8E5D, 0x7712, 0x858C, 0x7CC3, 0x99FF, 0x60B0, 0x922E, 0x6B61,
0x4281, 0xBBCE, 0x4950, 0xB01F, 0x5523, 0xAC6C, 0x5EF2, 0xA7BD,
0x6DC5, 0x948A, 0x6614, 0x9F5B, 0x7A67, 0x8328, 0x71B6, 0x88F9,
0x1C09, 0xE546, 0x17D8, 0xEE97, 0x0BAB, 0xF2E4, 0x007A, 0xF935,
0x334D, 0xCA02, 0x389C, 0xC1D3, 0x24EF, 0xDDA0, 0x2F3E, 0xD671,
0x7CFE, 0x85B1, 0x772F, 0x8E60, 0x6B5C, 0x9213, 0x608D, 0x99C2,
0x53BA, 0xAAF5, 0x586B, 0xA124, 0x4418, 0xBD57, 0x4FC9, 0xB686,
0x2276, 0xDB39, 0x29A7, 0xD0E8, 0x35D4, 0xCC9B, 0x3E05, 0xC74A,
0x0D32, 0xF47D, 0x06E3, 0xFFAC, 0x1A90, 0xE3DF, 0x1141, 0xE80E,
0xC1EE, 0x38A1, 0xCA3F, 0x3370, 0xD64C, 0x2F03, 0xDD9D, 0x24D2,
0xEEAA, 0x17E5, 0xE57B, 0x1C34, 0xF908, 0x0047, 0xF2D9, 0x0B96,
0x9F66, 0x6629, 0x94B7, 0x6DF8, 0x88C4, 0x718B, 0x8315, 0x7A5A,
0xB022, 0x496D, 0xBBF3, 0x42BC, 0xA780, 0x5ECF, 0xAC51, 0x551E,
};
__attribute__((weak)) void omv_crc_init(void) {
// CRC32 lookup table for polynomial 0xFA567D89
const uint32_t crc32_table[256] = {
0x00000000, 0xFA567D89, 0x0EFA869B, 0xF4ACFB12, 0x1DF50D36, 0xE7A370BF, 0x130F8BAD, 0xE959F624,
0x3BEA1A6C, 0xC1BC67E5, 0x35109CF7, 0xCF46E17E, 0x261F175A, 0xDC496AD3, 0x28E591C1, 0xD2B3EC48,
0x77D434D8, 0x8D824951, 0x792EB243, 0x8378CFCA, 0x6A2139EE, 0x90774467, 0x64DBBF75, 0x9E8DC2FC,
0x4C3E2EB4, 0xB668533D, 0x42C4A82F, 0xB892D5A6, 0x51CB2382, 0xAB9D5E0B, 0x5F31A519, 0xA567D890,
0xEFA869B0, 0x15FE1439, 0xE152EF2B, 0x1B0492A2, 0xF25D6486, 0x080B190F, 0xFCA7E21D, 0x06F19F94,
0xD44273DC, 0x2E140E55, 0xDAB8F547, 0x20EE88CE, 0xC9B77EEA, 0x33E10363, 0xC74DF871, 0x3D1B85F8,
0x987C5D68, 0x622A20E1, 0x9686DBF3, 0x6CD0A67A, 0x8589505E, 0x7FDF2DD7, 0x8B73D6C5, 0x7125AB4C,
0xA3964704, 0x59C03A8D, 0xAD6CC19F, 0x573ABC16, 0xBE634A32, 0x443537BB, 0xB099CCA9, 0x4ACFB120,
0x2506AEE9, 0xDF50D360, 0x2BFC2872, 0xD1AA55FB, 0x38F3A3DF, 0xC2A5DE56, 0x36092544, 0xCC5F58CD,
0x1EECB485, 0xE4BAC90C, 0x1016321E, 0xEA404F97, 0x0319B9B3, 0xF94FC43A, 0x0DE33F28, 0xF7B542A1,
0x52D29A31, 0xA884E7B8, 0x5C281CAA, 0xA67E6123, 0x4F279707, 0xB571EA8E, 0x41DD119C, 0xBB8B6C15,
0x6938805D, 0x936EFDD4, 0x67C206C6, 0x9D947B4F, 0x74CD8D6B, 0x8E9BF0E2, 0x7A370BF0, 0x80617679,
0xCAAEC759, 0x30F8BAD0, 0xC45441C2, 0x3E023C4B, 0xD75BCA6F, 0x2D0DB7E6, 0xD9A14CF4, 0x23F7317D,
0xF144DD35, 0x0B12A0BC, 0xFFBE5BAE, 0x05E82627, 0xECB1D003, 0x16E7AD8A, 0xE24B5698, 0x181D2B11,
0xBD7AF381, 0x472C8E08, 0xB380751A, 0x49D60893, 0xA08FFEB7, 0x5AD9833E, 0xAE75782C, 0x542305A5,
0x8690E9ED, 0x7CC69464, 0x886A6F76, 0x723C12FF, 0x9B65E4DB, 0x61339952, 0x959F6240, 0x6FC91FC9,
0x4A0D5DD2, 0xB05B205B, 0x44F7DB49, 0xBEA1A6C0, 0x57F850E4, 0xADAE2D6D, 0x5902D67F, 0xA354ABF6,
0x71E747BE, 0x8BB13A37, 0x7F1DC125, 0x854BBCAC, 0x6C124A88, 0x96443701, 0x62E8CC13, 0x98BEB19A,
0x3DD9690A, 0xC78F1483, 0x3323EF91, 0xC9759218, 0x202C643C, 0xDA7A19B5, 0x2ED6E2A7, 0xD4809F2E,
0x06337366, 0xFC650EEF, 0x08C9F5FD, 0xF29F8874, 0x1BC67E50, 0xE19003D9, 0x153CF8CB, 0xEF6A8542,
0xA5A53462, 0x5FF349EB, 0xAB5FB2F9, 0x5109CF70, 0xB8503954, 0x420644DD, 0xB6AABFCF, 0x4CFCC246,
0x9E4F2E0E, 0x64195387, 0x90B5A895, 0x6AE3D51C, 0x83BA2338, 0x79EC5EB1, 0x8D40A5A3, 0x7716D82A,
0xD27100BA, 0x28277D33, 0xDC8B8621, 0x26DDFBA8, 0xCF840D8C, 0x35D27005, 0xC17E8B17, 0x3B28F69E,
0xE99B1AD6, 0x13CD675F, 0xE7619C4D, 0x1D37E1C4, 0xF46E17E0, 0x0E386A69, 0xFA94917B, 0x00C2ECF2,
0x6F0BF33B, 0x955D8EB2, 0x61F175A0, 0x9BA70829, 0x72FEFE0D, 0x88A88384, 0x7C047896, 0x8652051F,
0x54E1E957, 0xAEB794DE, 0x5A1B6FCC, 0xA04D1245, 0x4914E461, 0xB34299E8, 0x47EE62FA, 0xBDB81F73,
0x18DFC7E3, 0xE289BA6A, 0x16254178, 0xEC733CF1, 0x052ACAD5, 0xFF7CB75C, 0x0BD04C4E, 0xF18631C7,
0x2335DD8F, 0xD963A006, 0x2DCF5B14, 0xD799269D, 0x3EC0D0B9, 0xC496AD30, 0x303A5622, 0xCA6C2BAB,
0x80A39A8B, 0x7AF5E702, 0x8E591C10, 0x740F6199, 0x9D5697BD, 0x6700EA34, 0x93AC1126, 0x69FA6CAF,
0xBB4980E7, 0x411FFD6E, 0xB5B3067C, 0x4FE57BF5, 0xA6BC8DD1, 0x5CEAF058, 0xA8460B4A, 0x521076C3,
0xF777AE53, 0x0D21D3DA, 0xF98D28C8, 0x03DB5541, 0xEA82A365, 0x10D4DEEC, 0xE47825FE, 0x1E2E5877,
0xCC9DB43F, 0x36CBC9B6, 0xC26732A4, 0x38314F2D, 0xD168B909, 0x2B3EC480, 0xDF923F92, 0x25C4421B,
};
}
__attribute__((weak)) uint16_t omv_crc16_start(const void *buf, size_t len) {
const uint8_t *data = (const uint8_t *) buf;
uint16_t crc = OMV_CRC16_INIT;
__attribute__((weak)) omv_crc_t omv_crc_start(const void *buf, size_t size) {
const uint8_t *data = (const uint8_t *)buf;
omv_crc_t crc = OMV_CRC_INIT;
for (size_t i = 0; i < size; i++) {
for (size_t i = 0; i < len; i++) {
uint8_t index = (crc >> 8) ^ data[i];
crc = (crc << 8) ^ crc16_table[index];
}
@ -74,13 +107,36 @@ __attribute__((weak)) omv_crc_t omv_crc_start(const void *buf, size_t size) {
return crc;
}
__attribute__((weak)) omv_crc_t omv_crc_update(omv_crc_t crc, const void *buf, size_t size) {
const uint8_t *data = (const uint8_t *)buf;
__attribute__((weak)) uint16_t omv_crc16_update(uint16_t crc, const void *buf, size_t len) {
const uint8_t *data = (const uint8_t *) buf;
for (size_t i = 0; i < size; i++) {
for (size_t i = 0; i < len; i++) {
uint8_t index = (crc >> 8) ^ data[i];
crc = (crc << 8) ^ crc16_table[index];
}
return crc;
}
__attribute__((weak)) uint32_t omv_crc32_start(const void *buf, size_t len) {
const uint8_t *data = (const uint8_t *) buf;
uint32_t crc = OMV_CRC32_INIT;
for (size_t i = 0; i < len; i++) {
uint8_t index = (crc >> 24) ^ data[i];
crc = (crc << 8) ^ crc32_table[index];
}
return crc;
}
__attribute__((weak)) uint32_t omv_crc32_update(uint32_t crc, const void *buf, size_t len) {
const uint8_t *data = (const uint8_t *) buf;
for (size_t i = 0; i < len; i++) {
uint8_t index = (crc >> 24) ^ data[i];
crc = (crc << 8) ^ crc32_table[index];
}
return crc;
}

View File

@ -27,37 +27,74 @@
#include <stddef.h>
#include <stdbool.h>
// 0xBAAD is ironically good - HD=5 up to 108 bits, HD=4 up to 7985 bits
#define OMV_CRC_POLY (0xBAAD)
#define OMV_CRC_INIT (0xFFFF)
#define OMV_CRC_SIZE (16)
typedef uint16_t omv_crc_t;
// CRC size enumeration
typedef enum {
OMV_CRC16 = 16,
OMV_CRC32 = 32
} omv_crc_size_t;
// Initialize CRC hardware (if available)
void omv_crc_init(void);
// HD=6 up to 114 bits
#define OMV_CRC16_POLY (0xF94F)
#define OMV_CRC16_INIT (0xFFFF)
// Start CRC calculation for buffer data
omv_crc_t omv_crc_start(const void *buf, size_t size);
// HD=6 up to 32738 bits (~4K)
#define OMV_CRC32_POLY (0xFA567D89)
#define OMV_CRC32_INIT (0xFFFFFFFF)
// Update CRC with additional buffer data
omv_crc_t omv_crc_update(omv_crc_t crc, const void *buf, size_t size);
// Default software implementations
uint16_t omv_crc16_start(const void *buf, size_t len);
uint16_t omv_crc16_update(uint16_t crc, const void *buf, size_t len);
// Read CRC value from the last 2 bytes of buffer
static inline omv_crc_t omv_crc_read(const void *buf, size_t size) {
const uint8_t *crc_buf = (const uint8_t *)buf + size - 2;
return *((omv_crc_t*) crc_buf);
uint32_t omv_crc32_start(const void *buf, size_t len);
uint32_t omv_crc32_update(uint32_t crc, const void *buf, size_t len);
// Public API functions
static inline uint32_t omv_crc_start(omv_crc_size_t size, const void *buf, size_t len) {
if (size == OMV_CRC16) {
return omv_crc16_start(buf, len);
} else if (size == OMV_CRC32) {
return omv_crc32_start(buf, len);
}
return 0;
}
// Calculate CRC and write it to the last 2 bytes of buffer
static inline void omv_crc_write(void *buf, size_t size) {
omv_crc_t crc = omv_crc_start(buf, size - 2);
uint8_t *crc_buf = (uint8_t *)buf + size - 2;
crc_buf[0] = crc & 0xFF;
crc_buf[1] = (crc >> 8) & 0xFF;
static inline uint32_t omv_crc_update(omv_crc_size_t size, uint32_t crc, const void *buf, size_t len) {
if (size == OMV_CRC16) {
return omv_crc16_update((uint16_t) crc, buf, len);
} else if (size == OMV_CRC32) {
return omv_crc32_update(crc, buf, len);
}
return crc;
}
// Read CRC value from the last bytes of buffer
static inline uint32_t omv_crc_read(omv_crc_size_t crc_size, const void *buf, size_t size) {
const uint8_t *crc_buf = (const uint8_t *) buf + size - (crc_size == OMV_CRC16 ? 2 : 4);
if (crc_size == OMV_CRC16) {
return *((uint16_t *) crc_buf);
} else {
return *((uint32_t *) crc_buf);
}
}
// Calculate CRC and write it to the last bytes of buffer
static inline void omv_crc_write(omv_crc_size_t crc_size, void *buf, size_t size) {
uint32_t crc = omv_crc_start(crc_size, buf, size - (crc_size == OMV_CRC16 ? 2 : 4));
uint8_t *crc_buf = (uint8_t *) buf + size - (crc_size == OMV_CRC16 ? 2 : 4);
if (crc_size == OMV_CRC16) {
crc_buf[0] = crc & 0xFF;
crc_buf[1] = (crc >> 8) & 0xFF;
} else {
crc_buf[0] = crc & 0xFF;
crc_buf[1] = (crc >> 8) & 0xFF;
crc_buf[2] = (crc >> 16) & 0xFF;
crc_buf[3] = (crc >> 24) & 0xFF;
}
}
// Calculate and check if CRC matches the one stored in buffer
static inline bool omv_crc_check(const void *buf, size_t size) {
return omv_crc_read(buf, size) == omv_crc_start(buf, size - 2);
static inline bool omv_crc_check(omv_crc_size_t crc_size, const void *buf, size_t size) {
return omv_crc_read(crc_size, buf, size) == omv_crc_start(crc_size, buf, size - (crc_size == OMV_CRC16 ? 2 : 4));
}
#endif // __OMV_CRC_H__

97
modules/py_crc.c Normal file
View File

@ -0,0 +1,97 @@
/*
* SPDX-License-Identifier: MIT
*
* Copyright (C) 2025 OpenMV, LLC.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* CRC Python module for testing CRC implementations.
*/
#if MICROPY_PY_CRC
#include "py/runtime.h"
#include "py/obj.h"
#include "omv_crc.h"
// CRC16 function
static mp_obj_t py_crc16(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kwargs) {
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_data, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
{ MP_QSTR_value, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
};
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args, pos_args, kwargs, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
mp_buffer_info_t bufinfo;
mp_get_buffer_raise(args[0].u_obj, &bufinfo, MP_BUFFER_READ);
uint16_t crc;
if (args[1].u_obj == MP_OBJ_NULL) {
crc = omv_crc16_start(bufinfo.buf, bufinfo.len);
} else {
uint16_t prev_crc = mp_obj_get_int_truncated(args[1].u_obj) & 0xFFFF;
crc = omv_crc16_update(prev_crc, bufinfo.buf, bufinfo.len);
}
return mp_obj_new_int_from_uint(crc);
}
static MP_DEFINE_CONST_FUN_OBJ_KW(py_crc16_obj, 1, py_crc16);
// CRC32 function
static mp_obj_t py_crc32(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kwargs) {
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_data, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
{ MP_QSTR_value, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
};
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args, pos_args, kwargs, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
mp_buffer_info_t bufinfo;
mp_get_buffer_raise(args[0].u_obj, &bufinfo, MP_BUFFER_READ);
uint32_t crc;
if (args[1].u_obj == MP_OBJ_NULL) {
crc = omv_crc32_start(bufinfo.buf, bufinfo.len);
} else {
uint32_t prev_crc = mp_obj_get_int_truncated(args[1].u_obj);
crc = omv_crc32_update(prev_crc, bufinfo.buf, bufinfo.len);
}
return mp_obj_new_int_from_uint(crc);
}
static MP_DEFINE_CONST_FUN_OBJ_KW(py_crc32_obj, 1, py_crc32);
// Module globals table
static const mp_rom_map_elem_t crc_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_crc) },
{ MP_ROM_QSTR(MP_QSTR_crc16), MP_ROM_PTR(&py_crc16_obj) },
{ MP_ROM_QSTR(MP_QSTR_crc32), MP_ROM_PTR(&py_crc32_obj) },
};
static MP_DEFINE_CONST_DICT(crc_module_globals, crc_module_globals_table);
// Define module object
const mp_obj_module_t crc_user_cmodule = {
.base = { &mp_type_module },
.globals = (mp_obj_dict_t *) &crc_module_globals,
};
// Register the module to make it available in Python
MP_REGISTER_MODULE(MP_QSTR_crc, crc_user_cmodule);
#endif // MICROPY_PY_CRC

View File

@ -25,46 +25,78 @@
#include "global_map.h"
#include "omv_crc.h"
#define CRC0 ((CRC_Type *)CRC0_BASE)
// There seems to be a mismatch between how the Alif HW CRC32 algorithm
// works and the other HW CRCs and the software implementation.
// Just leaving this here just in case it works on a different series.
#if 0
#define CRC0 ((CRC_Type *) CRC0_BASE)
static bool crc_initialized = false;
static bool crc32_initialized = false;
static void crc_calculate(CRC_Type *crc, const void *buf, uint32_t len, uint32_t *value);
void omv_crc_init(void) {
crc_clear_config(CRC0);
crc_enable_16bit(CRC0);
crc_enable_custom_poly(CRC0);
crc_set_custom_poly(CRC0, OMV_CRC_POLY);
crc_set_seed(CRC0, OMV_CRC_INIT);
crc_enable(CRC0);
crc_initialized = true;
static void omv_crc32_init(void) {
CRC0->CRC_CONTROL = CRC_32C |
CRC_CUSTOM_POLY |
CRC_ALGO_32_BIT_SIZE;
CRC0->CRC_SEED = OMV_CRC32_INIT;
CRC0->CRC_POLY_CUSTOM = OMV_CRC32_POLY;
crc32_initialized = true;
}
omv_crc_t omv_crc_start(const void *buf, size_t size) {
if (!crc_initialized) {
omv_crc_init();
uint32_t omv_crc32_start(const void *buf, size_t len) {
uint32_t result = OMV_CRC32_INIT;
if (!crc32_initialized) {
omv_crc32_init();
}
if (size == 0) {
return OMV_CRC_INIT;
if (len == 0) {
return OMV_CRC32_INIT;
}
uint32_t result = 0;
crc_calculate_16bit(CRC0, buf, size, &result);
return (omv_crc_t)result;
crc_calculate(CRC0, buf, len, &result);
return result;
}
omv_crc_t omv_crc_update(omv_crc_t crc, const void *buf, size_t size) {
if (!crc_initialized) {
omv_crc_init();
uint32_t omv_crc32_update(uint32_t crc, const void *buf, size_t len) {
uint32_t result = crc;
if (!crc32_initialized) {
omv_crc32_init();
}
if (size == 0) {
if (len == 0) {
return crc;
}
// Set current CRC value and calculate incrementally
crc_set_seed(CRC0, crc);
uint32_t result = 0;
crc_calculate_16bit(CRC0, buf, size, &result);
return (omv_crc_t)result;
crc_calculate(CRC0, buf, len, &result);
return result;
}
static void crc_calculate(CRC_Type *crc, const void *buf, uint32_t len, uint32_t *value) {
const uint8_t *data = (const uint8_t *) buf;
if ((len % 4) == 0) {
// Use hardware only if length is multiple of 4
crc->CRC_SEED = *value;
crc->CRC_CONTROL |= CRC_INIT_BIT;
// Hardware path - process all data as 32-bit words
const uint32_t *data32 = (const uint32_t *) data;
for (uint32_t i = 0; i < len / 4; i++) {
crc->CRC_DATA_IN_32_0 = data32[i];
}
*value = crc->CRC_OUT;
} else {
// Software path - use lookup table
uint32_t result = *value;
extern const uint32_t crc32_table[256];
for (uint32_t i = 0; i < len; i++) {
uint8_t index = (result >> 24) ^ data[i];
result = (result << 8) ^ crc32_table[index];
}
*value = result;
}
}
#endif

View File

@ -31,43 +31,66 @@
static CRC_HandleTypeDef hcrc = {0};
static bool crc_initialized = false;
void omv_crc_init(void) {
static void omv_crc_init(void) {
hcrc.Instance = CRC;
hcrc.InputDataFormat = CRC_INPUTDATA_FORMAT_BYTES;
hcrc.Init.DefaultPolynomialUse = DEFAULT_POLYNOMIAL_DISABLE;
hcrc.Init.GeneratingPolynomial = OMV_CRC_POLY;
hcrc.Init.DefaultInitValueUse = DEFAULT_INIT_VALUE_DISABLE;
hcrc.Init.InitValue = OMV_CRC_INIT;
hcrc.Init.CRCLength = CRC_POLYLENGTH_16B;
hcrc.Init.InputDataInversionMode = CRC_INPUTDATA_INVERSION_NONE;
hcrc.Init.OutputDataInversionMode = CRC_OUTPUTDATA_INVERSION_DISABLE;
hcrc.InputDataFormat = CRC_INPUTDATA_FORMAT_BYTES;
hcrc.Init.CRCLength = CRC_POLYLENGTH_32B;
hcrc.Init.InitValue = OMV_CRC32_INIT;
hcrc.Init.GeneratingPolynomial = OMV_CRC32_POLY;
HAL_CRC_Init(&hcrc);
crc_initialized = true;
}
omv_crc_t omv_crc_start(const void *buf, size_t size) {
uint16_t omv_crc16_start(const void *buf, size_t len) {
if (!crc_initialized) {
omv_crc_init();
}
if (size == 0) {
return OMV_CRC_INIT;
// Set CRC16 polynomial and length directly
WRITE_REG(hcrc.Instance->POL, OMV_CRC16_POLY);
MODIFY_REG(hcrc.Instance->CR, CRC_CR_POLYSIZE, CRC_POLYLENGTH_16B);
if (len == 0) {
return OMV_CRC16_INIT;
}
return (omv_crc_t) HAL_CRC_Calculate(&hcrc, (uint32_t *)buf, size);
return (uint16_t) HAL_CRC_Calculate(&hcrc, (uint32_t *) buf, len);
}
omv_crc_t omv_crc_update(omv_crc_t crc, const void *buf, size_t size) {
if (!crc_initialized) {
omv_crc_init();
}
if (size == 0) {
uint16_t omv_crc16_update(uint16_t crc, const void *buf, size_t len) {
if (len == 0) {
return crc;
}
return (omv_crc_t) HAL_CRC_Accumulate(&hcrc, (uint32_t *)buf, size);
return (uint16_t) HAL_CRC_Accumulate(&hcrc, (uint32_t *) buf, len);
}
uint32_t omv_crc32_start(const void *buf, size_t len) {
if (!crc_initialized) {
omv_crc_init();
}
// Set CRC32 polynomial and length directly
WRITE_REG(hcrc.Instance->POL, OMV_CRC32_POLY);
MODIFY_REG(hcrc.Instance->CR, CRC_CR_POLYSIZE, CRC_POLYLENGTH_32B);
if (len == 0) {
return OMV_CRC32_INIT;
}
return HAL_CRC_Calculate(&hcrc, (uint32_t *) buf, len);
}
uint32_t omv_crc32_update(uint32_t crc, const void *buf, size_t len) {
if (len == 0) {
return crc;
}
return HAL_CRC_Accumulate(&hcrc, (uint32_t *) buf, len);
}
#endif // STM32F7 || STM32H7 || STM32N6

92
tools/gen_crc_table.py Executable file
View File

@ -0,0 +1,92 @@
#!/usr/bin/env python3
#
# This file is part of the OpenMV project.
# Copyright (C) 2025 OpenMV, LLC.
#
# This work is licensed under the MIT license, see the file LICENSE for details.
#
# Generate CRC lookup tables for OpenMV CRC implementation
import argparse
def generate_crc16_table(polynomial):
"""Generate CRC16 lookup table"""
table = []
for i in range(256):
crc = i << 8
for _ in range(8):
if crc & 0x8000:
crc = (crc << 1) ^ polynomial
else:
crc = crc << 1
crc &= 0xFFFF
table.append(crc)
return table
def generate_crc32_table(polynomial):
"""Generate CRC32 lookup table"""
table = []
for i in range(256):
crc = i << 24
for _ in range(8):
if crc & 0x80000000:
crc = (crc << 1) ^ polynomial
else:
crc = crc << 1
crc &= 0xFFFFFFFF
table.append(crc)
return table
def format_c_array(table, name, data_type):
"""Format array as C code"""
lines = [f"static const {data_type} {name}[256] = {{"]
for i in range(0, len(table), 8):
row = table[i : i + 8]
if data_type == "uint16_t":
formatted_row = ", ".join(f"0x{val:04X}" for val in row)
else: # uint32_t
formatted_row = ", ".join(f"0x{val:08X}" for val in row)
lines.append(f" {formatted_row},")
lines.append("};")
return "\n".join(lines)
def main():
parser = argparse.ArgumentParser(
description="Generate CRC lookup tables for OpenMV CRC implementation"
)
parser.add_argument(
"--crc16-poly",
type=lambda x: int(x, 0),
default=0xF94F,
help="CRC16 polynomial (default: 0xF94F)",
)
parser.add_argument(
"--crc32-poly",
type=lambda x: int(x, 0),
default=0xFA567D89,
help="CRC32 polynomial (default: 0xFA567D89)",
)
args = parser.parse_args()
# Generate CRC16 table
crc16_table = generate_crc16_table(args.crc16_poly)
# Generate CRC32 table
crc32_table = generate_crc32_table(args.crc32_poly)
print(f"// CRC16 lookup table for polynomial 0x{args.crc16_poly:04X}")
print(format_c_array(crc16_table, "crc16_table", "uint16_t"))
print()
print(f"// CRC32 lookup table for polynomial 0x{args.crc32_poly:08X}")
print(format_c_array(crc32_table, "crc32_table", "uint32_t"))
if __name__ == "__main__":
main()