The other day I was working on my BT-Gateway project, I wanted to set up ESP-NOW connection between HX711 scale running with ESP8266 board and the gateway on ESP32-S3. At this time I am using Arduino IDE to develop against ESP8266 and ESP-IDF framework for ESP32. The example code for ESP-NOW in ESP-IDF is using CRC to validate the message integrity.
crc_cal = esp_crc16_le(UINT16_MAX, (uint8_t const *)buf, data_len);
The function is defined in esp_crc.h file as a wrapper for esp_rom_crc16_le() in esp_rom_crc.c alongside with a number of other functions for 32 bit CRC in both Big and Little Endians.
I started looking for a CRC function for ESP8266. The RTCUserMemory example comes with calculateCRC32() function which I copied over and made myself a connection.
Bummer! CRC calculated on both sides did not match! So I went ahead to look in the algorithm, and those are the few things that I found:
CRC algorithm implementation vary by a few parameters:
- Number of bits, i.e. length (obvious)
- Polynomial used in the algo
- Initial value
- XOR for the output (usually invert or not)
- a number of other parameters
Moreover, there is a common check for CRC – for input of “123456789” (byte array 0x31, 0x32 … 0x39), there is a well-known expected value for different implementations. And there is a neat document listing the different implementations – [link] [PDF]. Running such test on both ESP32 and ESP8266 I was able to find which one is implemented on ESP32 and match the parameters in the function on ESP8266.
// CRC-32/CKSUM// width=32 poly=0x04c11db7 init=0x00000000 refin=false refout=false xorout=0xffffffff check=0x765e7680 residue=0xc704dd7b name=”CRC-32/CKSUM”crc_cal = esp_crc32_be(UINT32_MAX, (uint8_t const *)buf, data_len);
Another curious implementation detail that I found, is that CRC can either be computed on the spot (as ESP8266 is doing), or calculated using a more lightweight algorithm which makes use of a 256-element table array of pre-calculated values, this is how it is implemented in ESP32/ESP-IDF.
Here is the implementation of the CRC function for ESP8266 which is compatible with esp_crc32_be() on ESP32:
#include <stdint.h>
#include <stddef.h>// CRC-32/CKSUM
// width=32 poly=0x04c11db7 init=0x00000000 refin=false refout=false xorout=0xffffffff check=0x765e7680 residue=0xc704dd7b name=”CRC-32/CKSUM”
#define CRC32_POLY 0x04C11DB7
uint32_t crc32_be(const uint8_t* data, size_t length) {
uint32_t crc = 0x0;while (length–) {
crc ^= (*data++) << 24; // move byte into MSB of crcfor (uint8_t i = 0; i < 8; i++) {
if (crc & 0x80000000) {
crc = (crc << 1) ^ CRC32_POLY;
} else {
crc <<= 1;
} } }return crc ^ 0xFFFFFFFF;
}
As you can see, I didn’t dive deep into the math, even though there is a comprehensive Wikipedia page for that [link] but only focused on whatever is necessary to solve compatibility issues.