STM32F4 serial communication custom data package (CRC32 check)

Introduction

  1. The time stamp is generally 32 bits, and a single serial communication is 8 bits, so a 32-bit can be decomposed into four 8-bits, and sent in the form of a data packet
    /* custom data packet
    * + ---------- + -------- + ----------- + ---------------- ---- + ---------- +
    * | preamble | 000000 | length | data message | parity |
    * + ---------- + -------- + ----------- + ---------------- ---- + ---------- +
    * |<-- 8 --->|<- 16 ->|<--- 8 --->|<------- 96 ------->|<-- 32 - ->| */
    
  2. In order to ensure that the data is complete and correct, the crc32 check is used
  3. The receiving device performs software crc32 calculation and verification

Article directory

  • 1. Hardware CRC32
  • 2. Software CRC32 (check table)
  • 3. Test
    • 1. MCU routines
    • 2.linux serial communication decoding test

1. Hardware CRC32

reference blog

__asm uint32_t Revbit (uint32_t data)
{<!-- -->
RBIT R0, R0
BX LR
}

__asm uint32_t Revswap(uint32_t data)
{<!-- -->
REV R0, R0
BX LR
}

void crc32_init(void)
{<!-- -->
__HAL_RCC_CRC_CLK_ENABLE();
CRC->CR = CRC_CR_RESET;
}

uint32_t crc32_cal(uint32_t data)
{<!-- -->
CRC->DR = Revbit(Revswap(data));
return (Revbit(CRC->DR)^0xFFFFFFFF);
}

uint32_t crc32_cal_buffer(uint32_t *buffer, uint32_t length)
{<!-- -->
uint32_t i = 0;
CRC->CR = CRC_CR_RESET;
for(i = 0; i < length - 1; i ++ )
{<!-- -->
crc32_cal(buffer[i]);
}
return crc32_cal(buffer[i]);
}

2. Software CRC32 (check table)

static const uint32_t tbl_CRC32[] =
{<!-- -->
    0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
    0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
    0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
    0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
    0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
    0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
    0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
    0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
    0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
    0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
    0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
    0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
    0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
    0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
    0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
    0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
    0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
    0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
    0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
    0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
    0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
    0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
    0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
    0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
    0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
    0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
    0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
    0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
    0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
    0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
    0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
    0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
    0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
    0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
    0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
    0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
    0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
    0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
    0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
    0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
    0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
    0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
    0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
};

uint32_t crc32(uint8_t *input, uint32_t len)
{<!-- -->
uint32_t crc = 0xFFFFFFFF, i;

for (i = 0; i < len; i ++ )
{<!-- -->
crc = tbl_CRC32[(crc ^ input[i]) & amp; 0xff ] ^ (crc >> 8);
}

return crc ^ 0xFFFFFFFF;
}

3. Test

1. MCU routine

#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/usart/usart.h"
#include "./SYSTEM/delay/delay.h"
#include "./BSP/LED/led.h"
#include "./BSP/KEY/key.h"
#include "./BSP/CRC/crc32.h"


int main(void)
{<!-- -->
uint32_t data[4], crc_result_H, crc_result_S;
uint8_t buffer[24];

    HAL_Init(); /* Initialize HAL */
    sys_stm32_clock_init(336, 8, 2, 7); /* Initialize the clock, 168Mhz */
    delay_init(168); /* initialization delay */
    usart_init(115200); /* Initialize the serial port */
    led_init(); /* Initialize the LED */
    key_init(); /* Initialize key */
crc32_init(); /* Initialize CRC32 */
\t
/* custom data package
* + ---------- + -------- + ----------- + ---------------- ---- + ---------- +
* | preamble | 000000 | length | data message | parity |
* + ---------- + -------- + ----------- + ---------------- ---- + ---------- +
* |<-- 8 --->|<- 16 ->|<--- 8 --->|<------- 96 ------->|<-- 32 - ->| */
data[0] = (data[0] & 0U) | 0xCCU << 24 | 0xCU;
data[1] = 100;
data[2] = 1684750330;
data[3] = 111111111;
crc_result_H = crc32_cal_buffer(data, 4);
\t
buffer[0] = data[0] >> 24;
buffer[1] = data[0] >> 16;
buffer[2] = data[0] >> 8;
buffer[3] = data[0];
buffer[4] = data[1] >> 24;
buffer[5] = data[1] >> 16;
buffer[6] = data[1] >> 8;
buffer[7] = data[1];
buffer[8] = data[2] >> 24;
buffer[9] = data[2] >> 16;
buffer[10] = data[2] >> 8;
buffer[11] = data[2];
buffer[12] = data[3] >> 24;
buffer[13] = data[3] >> 16;
buffer[14] = data[3] >> 8;
buffer[15] = data[3];
buffer[16] = crc_result_H >> 24;
buffer[17] = crc_result_H >> 16;
buffer[18] = crc_result_H >> 8;
buffer[19] = crc_result_H;
\t
crc_result_S = crc32(buffer, 16);
buffer[20] = crc_result_S >> 24;
buffer[21] = crc_result_S >> 16;
buffer[22] = crc_result_S >> 8;
buffer[23] = crc_result_S;
    while(1)
    {<!-- -->
for (uint8_t i =0; i < 24; i ++ )
{<!-- -->
usart_send_byte( & g_uart4_handle, buffer[i]);
}
delay_ms(1000);
    }
}

// Serial port HEX output, CRC32 calculated by software and hardware are both D8 BA E4 74
CC 00 00 0C 00 00 00 64 64 6B 3F FA 06 9F 6B C7 D8 BA E4 74 D8 BA E4 74

2.linux serial communication decoding test

The main code for interpreting the data packet is posted here, refer to the open source software RTKLIB https://github.com/tomojitakasu/RTKLIB/blob/master/src/rtcm.c

typedef struct
{<!-- -->
    uint32_t Sec;
    uint32_t Nsec;
    uint32_t FrameNum;
}Time_Frame_Header;

typedef struct
{<!-- -->
    Time_Frame_Header data;
    uint8_t buff[200]; /* message buffer */
    uint32_t nbyte; /* number of bytes in message buffer */
    uint32_t len; /* message length (bytes) */
}Serial_Data_Bag;

static int8_t input_message(Serial_Data_Bag *bag, uint8_t data)
{<!-- -->
    /* synchronize frame */
    if (bag->nbyte == 0)
    {<!-- -->
        if (data != CCPREAMB) return 0;
        bag->buff[bag->nbyte + + ] = data;
        return 0;
    }
    bag->buff[bag->nbyte + + ] = data;
    
    if (bag->nbyte == 4)
    {<!-- -->
        bag->len = getbitu(bag->buff, 24, 8) + 4; /* packet length without parity */
    }
    if (bag->nbyte < 4 || bag->nbyte < bag->len + 4) return 0;
    bag->nbyte = 0; // Receive a packet of theoretical length here! ! reset nbyte

    /* check packet */
    if (crc32(bag->buff, bag->len) != getbitu(bag->buff, bag->len*8, 32))
    {<!-- -->
        ROS_ERROR("serial_data_bag parity error: len=%d byte\\
", bag->len);
        return 0;
    }
    /* The message has passed the test completely and starts to interpret the message */
    uint32_t ind = 32;
    bag->data.FrameNum = getbitu(bag->buff, ind, 32); ind + = 32;
    bag->data.Sec = getbitu(bag->buff, ind, 32); ind + = 32;
    bag->data.Nsec = getbitu(bag->buff, ind, 32);
    
    return 1;
}