5.5 CRC Guide

This chapter describes the file composition and 16 public functions of the CRC driver in the N32H49x standard peripheral library, together with 2 examples. The CRC peripheral computes a checksum over a 32-bit or 16-bit data stream, and additionally provides an 8-bit independent data register and an LRC exclusive-OR check; for the initial value, endianness and clean-method settings, see the “Cyclic redundancy check (CRC)” chapter of the user manual.

5.5.1 Related files

Relative path Purpose
firmware/n32h49x_std_periph_driver/inc/n32h49x_crc.h Defines the register bits and masks for the 32-bit and 16-bit checksums, and declares the 16 public functions
firmware/n32h49x_std_periph_driver/src/n32h49x_crc.c Implements the 16 functions above: 32-bit data-register handling and result readback, independent data-register access, CRC16 and LRC format configuration, single-word and buffer computation, and result readback
projects/n32h49x_EVAL/examples/CRC/ CRC example root directory, containing the CalCRC and CRC_DMA examples
projects/n32h49x_EVAL/examples/CRC/CalCRC/ Project directory composition of this example: MDK-ARM/, EWARM/, inc/, src/, readme.txt
projects/n32h49x_EVAL/bsp/ Common board files referenced by this example: the UART log function

5.5.2 API reference

Search API16 functions

The following 16 public functions are listed in the declaration order of n32h49x_crc.h in 4 groups; each entry gives a summary and the original comment above the function in n32h49x_crc.c.

32-bit CRC

CRC32_ResetCrc, CRC32_CalcCrc, CRC32_CalcBufCrc, CRC32_GetCrc

Independent data register

CRC32_SetIDat, CRC32_GetIDat

16-bit CRC and LRC

__CRC16_SetLittleEndianFmt, __CRC16_SetBigEndianFmt, __CRC16_SetCleanEnable, __CRC16_SetCleanDisable, __CRC16_CalcCrc, __CRC16_SetCrc, __CRC16_GetCrc, __CRC16_SetLRC, __CRC16_GetLRC

16-bit buffer

CRC16_CalcBufCrc

void CRC32_ResetCrc(void)Resets the CRC Data register (DAT).
Source comment
name    CRC32_ResetCrc.
fun     Resets the CRC Data register (DAT).
param   none
return  none
uint32_t CRC32_CalcCrc(uint32_t Data)Computes the 32-bit CRC of a given data word(32-bit).
Source comment
name    CRC32_CalcCrc.
fun     Computes the 32-bit CRC of a given data word(32-bit).
param   Data :
          - data word(32-bit) to compute its CRC
return  32-bit CRC
uint32_t CRC32_CalcBufCrc(const uint32_t pBuffer[], uint32_t BufferLength)Computes the 32-bit CRC of a given buffer of data word(32-bit).
Source comment
name    CRC32_CalcBufCrc.
fun     Computes the 32-bit CRC of a given buffer of data word(32-bit).
param   pBuffer :
          - pointer to the buffer containing the data to be computed
param   BufferLength :
          - length of the buffer to be computed
return  32-bit CRC
uint32_t CRC32_GetCrc(void)Returns the current CRC value.
Source comment
name    CRC32_GetCrc.
fun     Returns the current CRC value.
param   none
return  32-bit CRC
void CRC32_SetIDat(uint8_t IDValue)Stores a 8-bit data in the Independent Data(ID) register.
Source comment
name    CRC32_SetIDat.
fun     Stores a 8-bit data in the Independent Data(ID) register.
param   IDValue :
          - 8-bit value to be stored in the ID register
return  none
uint8_t CRC32_GetIDat(void)Returns the 8-bit data stored in the Independent Data(ID) register.
Source comment
name    CRC32_GetIDat.
fun     Returns the 8-bit data stored in the Independent Data(ID) register.
param   none
return  8-bit value of the ID register
void __CRC16_SetLittleEndianFmt(void)Set the calculate data to little endian format.
Source comment
name    __CRC16_SetLittleEndianFmt.
fun     Set the calculate data to little endian format.
param   none
return  none
void __CRC16_SetBigEndianFmt(void)Set the calculate data to big endian format.
Source comment
name    __CRC16_SetBigEndianFmt.
fun     Set the calculate data to big endian format.
param   none
return  none
void __CRC16_SetCleanEnable(void)Enable Clean CRC16 value.
Source comment
name    __CRC16_SetCleanEnable.
fun     Enable Clean CRC16 value.
param   none
return  none
void __CRC16_SetCleanDisable(void)Disable Clean CRC16 value.
Source comment
name    __CRC16_SetCleanDisable.
fun     Disable Clean CRC16 value.
param   none
return  none
uint16_t __CRC16_CalcCrc(uint8_t Data)Computes the 16-bit CRC of a given data word(8-bit).
Source comment
name    __CRC16_CalcCrc.
fun     Computes the 16-bit CRC of a given data word(8-bit).
param   Data :
          - data word(8-bit) to compute its CRC
return  16-bit CRC
void __CRC16_SetCrc(uint8_t Data)write a 8-bit data in the 16-bit CRC Data register.
Source comment
name    __CRC16_SetCrc.
fun     write a 8-bit data in the 16-bit CRC Data register.
param   Data :
          - 8-bit data value to be writed in the 16-bit CRC Data register
return  none
uint16_t __CRC16_GetCrc(void)Returns the current CRC value.
Source comment
name    __CRC16_GetCrc.
fun     Returns the current CRC value.
param   none
return  16-bit CRC
void __CRC16_SetLRC(uint8_t Data)Write LRC initial value.
Source comment
name    __CRC16_SetLRC.
fun     Write LRC initial value.
param   Data :
          - 8-bit data
return  none
uint8_t __CRC16_GetLRC(void)Returns the current LRC value.
Source comment
name    __CRC16_GetLRC.
fun     Returns the current LRC value.
param   none
return  8-bit LRC
uint16_t CRC16_CalcBufCrc(const uint8_t pBuffer[], uint32_t BufferLength)Computes the 16-bit CRC of a given buffer of data word(8-bit).
Source comment
name    CRC16_CalcBufCrc.
fun     Computes the 16-bit CRC of a given buffer of data word(8-bit).
param   pBuffer :
          - pointer to the buffer containing the data to be computed
param   BufferLength :
          - length of the buffer to be computed
return  16-bit CRC

5.5.3 Demo descriptions

This section describes the 2 CRC examples: CalCRC cross-checks the hardware CRC32 and CRC16 results against a software implementation, and CRC_DMA uses DMA to move data into the CRC data registers.

5.5.3.1 CalCRC hardware and software checksum comparison

Example directory: projects/n32h49x_EVAL/examples/CRC/CalCRC/

Enable the CRC clock and initialize the log→Compute the 32-bit buffer CRC with the hardware API→Compute the reference value of the same buffer in software→Compare the two and print the conclusion→Verify the 16-bit buffer CRC the same way

Item Source analysis
Function Computes the checksum of the 114-word DataBuffer with CRC32_CalcBufCrc and compares it with the software implementation GetCRC32_Software (initial value 0xffffffff);
then computes the checksum of the 8-byte Buffer with CRC16_CalcBufCrc and compares it with GetCRC16_Software (initial value 0x00);
both comparison results are printed over UART.
Source files src/main.c: main, ReverseBits, GetCRC16_Software, GetCRC32_Software;
inc/main.h: includes n32h49x_crc.h and other headers;
src/n32h49x_it.c, inc/n32h49x_it.h: interrupt service routines (exception handlers only);
readme.txt: function, environment and usage notes;
MDK-ARM/, EWARM/: Keil and IAR projects.
Key configuration Clock: RCC_EnableAHBPeriphClk(RCC_AHB_PERIPHEN_CRC, ENABLE);
Data: DataBuffer is 114 32-bit words and Buffer is 8 bytes;
Software counterpart: CRC32 initial value 0xffffffff and CRC16 initial value 0x00, with the polynomials CRC32_DFE_POLY and CRC16_DFE_POLY used only by the software implementation.
Program and data path main enables the CRC clock and calls log_init;
CRC32_CalcBufCrc produces the hardware 32-bit checksum and GetCRC32_Software the reference value, which are compared before printing the conclusion;
then CRC16_CalcBufCrc and GetCRC16_Software repeat the same comparison for the 8-byte buffer.
Main APIs CRC32_CalcBufCrc, CRC16_CalcBufCrc
Verification The UART prints “CRC32 calculation is correct!” and “CRC16 calculation is correct!” when the hardware result matches the software value;
otherwise it prints the corresponding error message.
Use note The software counterpart processes the same buffer bit by bit and is used to cross-check the hardware result;
the example finishes both comparisons before the main loop and does not rely on interrupts;
the buffer lengths come from BUFFER_SIZE and a literal, so keep both lengths consistent when porting.
Core-code walkthrough and porting

The example computes the checksum of the same buffer with both the hardware API and a software implementation and compares them, verifying the CRC32 and CRC16 paths.

Data path: RCC_EnableAHBPeriphClk enables the CRC clock → log_init initializes the log → CRC32_CalcBufCrc computes the hardware 32-bit checksum → GetCRC32_Software computes the reference value → the two are compared and printed → CRC16_CalcBufCrc and GetCRC16_Software repeat the comparison for the 8-byte buffer

1. Enable the CRC clock. main first turns on the CRC peripheral clock and then initializes the UART log.

src/main.csrc/main.c · main
    /* LED3 port is default used for JTAG, must remap first */
    RCC_EnableAHBPeriphClk(RCC_AHB_PERIPHEN_CRC, ENABLE);

The CRC computation only needs the peripheral clock and uses no GPIO, so keep this line when porting.

2. Compute and compare the 32-bit checksum. It first calls CRC32_CalcBufCrc for the hardware result, then uses GetCRC32_Software with initial value 0xffffffff for the reference value, and prints success when the two are equal.

src/main.csrc/main.c · main
    /* Compute the 32bit CRC of "DataBuffer" */
    CRC32Value = CRC32_CalcBufCrc((uint32_t*)DataBuffer, BUFFER_SIZE);

    /* Compute the 32bit CRC of "DataBuffer" by software*/
    CRCValue   = GetCRC32_Software((uint32_t*)DataBuffer, BUFFER_SIZE, 0xffffffff);

    if( CRC32Value == CRCValue )
    {
        printf(" CRC32 calculation is correct! \r\n");
    }
    else
    {
        printf(" CRC32 calculation error! \r\n");
    }

The software initial value must match the hardware data-register default, otherwise the two results cannot be compared directly.

3. Compute and compare the 16-bit checksum. The 8-byte buffer uses CRC16_CalcBufCrc, and GetCRC16_Software computes the reference value from initial value 0x00.

src/main.csrc/main.c · main
    /* Compute the 16bit CRC of an array */
    CRC16Value = CRC16_CalcBufCrc((uint8_t*)Buffer, 8);

    /* Compute the 16bit CRC of an array by software*/
    CRCValue   = GetCRC16_Software((uint8_t*)Buffer, 8, 0x00);

    if( CRC16Value == CRCValue )
    {
        printf("CRC16 calculation is correct! \r\n");
    }
    else
    {
        printf("CRC16 calculation error! \r\n");
    }

The 16-bit and 32-bit paths use different polynomials and initial values, so confirm that both sides use the same set of parameters before comparing.

4. Software counterpart. GetCRC32_Software processes the buffer bit by bit and updates the checksum with the standard polynomial, serving as the reference for the hardware result.

src/main.csrc/main.c · GetCRC32_Software
    for(i = 0; i < len; i ++)
    {
        xbit = 0x80000000;

        for (bits = 0; bits < 32; bits++)
        {
            if (crc32 & 0x80000000)
            {
                crc32 <<= 1;
                crc32 ^= CRC32_DFE_POLY;
            }
            else
            {
                crc32 <<= 1;
            }

            if (buf[i] & xbit)
            {
                crc32 ^= CRC32_DFE_POLY;
            }

            xbit >>= 1;
        }
    }

When porting to another checksum standard, both the polynomial and the shift direction must change together, not just the constant.

Corresponding source files: src/main.c

5.5.3.2 CRC_DMA checksum computation by DMA transfer

Example directory: projects/n32h49x_EVAL/examples/CRC/CRC_DMA/

Enable the CRC and DMA1 clocks→Reset the CRC data register→Use DMA to move the word buffer into the CRC32 data register and read the result back→Use DMA to move the byte buffer for the CRC16 and LRC computation→Read the CRC16 and LRC results back into memory and check them

Item Source analysis
Function Uses DMA to move data into the CRC data registers and complete the checks: TestCrc32AndDma transfers 114 words and yields a CRC32 result of 0x379E9F06;
TestCrc16AndDma transfers 456 bytes and yields a CRC16 result of 0x5268 and an LRC result of 0x00;
each result is read back and printed.
Source files src/main.c: main;
src/crc_dma.c: TestCrc32AndDma, TestCrc16AndDma and the buffers CRC_original_word_data, CRC_original_byte_data;
inc/main.h: includes n32h49x_crc.h, n32h49x_dma.h and other headers;
src/n32h49x_it.c, inc/n32h49x_it.h: interrupt service routines;
readme.txt: function, environment and usage notes;
MDK-ARM/, EWARM/: Keil and IAR projects.
Key configuration Clock: enables the CRC and DMA1 clocks;
DMA: DMA1_CH1 with Mem2Mem enabled;
WORD width is used for the word transfer and BYTE width for the byte transfer, with the memory-to-peripheral direction for writing the data register and the peripheral-to-memory direction for reading results;
the burst length is selected from the burst_mode_len parameter (2 to 7) as DMA_BURST_LEN_2 through DMA_BURST_LEN_7.
Program and data path main enables the clocks and calls CRC32_ResetCrc to reset the data register;
TestCrc32AndDma(0, 2) moves CRC_original_word_data into CRC->CRC32DAT, waits for DMA_FLAG_TC1 and reads the result with CRC32_GetCrc, then moves CRC->CRC32D back to memory;
TestCrc16AndDma(0, 2) writes the initial values, moves CRC_original_byte_data into CRC->CRC16DAT, reads back __CRC16_GetCrc and __CRC16_GetLRC, and moves CRC->CRC16D and CRC->LRC back to memory.
Main APIs CRC32_ResetCrc, CRC32_GetCrc, __CRC16_SetCrc, __CRC16_SetLRC, __CRC16_SetCleanEnable, __CRC16_SetBigEndianFmt, __CRC16_GetCrc, __CRC16_GetLRC
Verification The UART prints the CRC32 result after the DMA transfer (expected 0x379E9F06), the CRC16 result (expected 0x5268) and the LRC result (expected 0x00);
any mismatch prints the corresponding error message.
Use note CRC32 writes 114 words into CRC->CRC32DAT and CRC16 writes 456 bytes into CRC->CRC16DAT;
the CRC16 initial value 0x00 is written before the transfer, with clean enabled and big-endian format selected;
results can be read from the registers directly or moved back to memory by a peripheral-to-memory DMA transfer.
Core-code walkthrough and porting

The example uses DMA to move data into the CRC data registers and completes the CRC32, CRC16 and LRC computations, then reads the results back into memory for checking.

Data path: RCC_EnableAHBPeriphClk enables the CRC and DMA1 clocks → CRC32_ResetCrc resets the data register → TestCrc32AndDma uses DMA to move data into CRC->CRC32DAT and reads the result back → TestCrc16AndDma writes the initial values, moves data into CRC->CRC16DAT and reads back CRC16 and LRC

1. Enable the clocks and reset the data register. main enables both the CRC and DMA1 clocks, resets the CRC data register and then runs the two tests.

src/main.csrc/main.c · main
int main(void)
{
    /* Enable CRC and DMA clock */
    RCC_EnableAHBPeriphClk(RCC_AHB_PERIPHEN_CRC | RCC_AHB_PERIPHEN_DMA1, ENABLE);

    log_init();

    printf(" CRC DMA test start.\r\n");

    CRC32_ResetCrc();

    TestCrc32AndDma(0, 2);
    TestCrc16AndDma(0, 2);

Resetting the data register makes each test start from a defined initial value; the two arguments are the burst mode and the burst length.

2. Configure DMA to move the word buffer into the CRC32 data register. TestCrc32AndDma sets the peripheral address to CRC->CRC32DAT and the memory address to CRC_original_word_data, with the memory-to-peripheral direction and Mem2Mem and WORD width.

src/crc_dma.csrc/crc_dma.c · TestCrc32AndDma
    /*Memory->CRC32DAT*/
    DMA_InitStructure.PeriphAddr = (uint32_t)&CRC->CRC32DAT;
    DMA_InitStructure.MemAddr = (uint32_t)CRC_original_word_data;
    DMA_InitStructure.Direction = DMA_DIR_PERIPH_DST;
    DMA_InitStructure.Mem2Mem = DMA_M2M_ENABLE;
    DMA_InitStructure.MemDataSize = DMA_MEM_DATA_WIDTH_WORD;
    DMA_InitStructure.PeriphDataSize = DMA_PERIPH_DATA_WIDTH_WORD;
    DMA_InitStructure.MemoryInc = DMA_MEM_INC_ENABLE;
    DMA_InitStructure.PeriphInc = DMA_PERIPH_INC_DISABLE;
    DMA_InitStructure.CircularMode = DMA_MODE_NORMAL;
    DMA_InitStructure.Priority = DMA_PRIORITY_VERY_HIGH;
    DMA_InitStructure.BufSize = 114;
    DMA_InitStructure.BurstCmd = DMA_BURST_DISABLE;

The peripheral address does not increment, so every word is written to the same data register; the buffer length must match the real data length.

3. Start the DMA and read the CRC32 result back. After enabling the channel it waits for DMA_FLAG_TC1 and then reads the checksum with CRC32_GetCrc and prints it.

src/crc_dma.csrc/crc_dma.c · TestCrc32AndDma
    DMA_Init(DMA1_CH1, &DMA_InitStructure);

    DMA_EnableChannel(DMA1_CH1, ENABLE);

    while(!DMA_GetFlagStatus(DMA_FLAG_TC1, DMA1));

    DMA_DeInit(DMA1_CH1);

    CRC32_Value = CRC32_GetCrc();

    printf("The CRC 32 code after Memory->CRC32DAT DMA transmission is %08x.\r\n", CRC32_GetCrc());

Wait for the transfer-complete flag before reading the result, otherwise the checksum may not be updated yet.

4. Write the CRC16 and LRC initial values and configure the byte transfer. TestCrc16AndDma first writes the CRC16 and LRC initial values 0x00, enables clean and selects big endian, then moves 456 bytes into CRC->CRC16DAT.

src/crc_dma.csrc/crc_dma.c · TestCrc16AndDma
    /*CRC 16 and LRC big endian test wirh 0 initial value*/
    __CRC16_SetCrc(0x00);
    __CRC16_SetLRC(0x00);
    __CRC16_SetCleanEnable();
    __CRC16_SetBigEndianFmt();
src/crc_dma.csrc/crc_dma.c · TestCrc16AndDma
    /*Memory->CRC.CRC16DAT*/
    DMA_InitStructure.PeriphAddr = (uint32_t)&CRC->CRC16DAT;
    DMA_InitStructure.MemAddr = (uint32_t)CRC_original_byte_data;
    DMA_InitStructure.Direction = DMA_DIR_PERIPH_DST;
    DMA_InitStructure.Mem2Mem = DMA_M2M_ENABLE;
    DMA_InitStructure.MemDataSize = DMA_MEM_DATA_WIDTH_BYTE;
    DMA_InitStructure.PeriphDataSize = DMA_PERIPH_DATA_WIDTH_BYTE;
    DMA_InitStructure.MemoryInc = DMA_MEM_INC_ENABLE;
    DMA_InitStructure.PeriphInc = DMA_PERIPH_INC_DISABLE;
    DMA_InitStructure.CircularMode = DMA_MODE_NORMAL;
    DMA_InitStructure.Priority = DMA_PRIORITY_VERY_HIGH;
    DMA_InitStructure.BufSize = 456;

The byte transfer switches to BYTE width; the initial values and clean setting must be done before the transfer and the order cannot be reversed.

5. Read the CRC16 and LRC results back. After the transfer it reads __CRC16_GetCrc and __CRC16_GetLRC and compares them with the expected values.

src/crc_dma.csrc/crc_dma.c · TestCrc16AndDma
    CRC16_Value = __CRC16_GetCrc();
    LRC_Value = __CRC16_GetLRC();

    printf("The CRC 16 code after Memory->CRC.CRC16DAT DMA transmission is %04x.\r\n", __CRC16_GetCrc());

    if(CRC16_Value != 0x5268)
    {
        printf("The CRC 16 code computed through DMA transmission is error,it should be 0x5268.\r\n");
    }

    printf("The LRC code after Memory->CRC.CRC16DAT DMA transmission is %02x.\r\n", __CRC16_GetLRC());

    if(LRC_Value != 0x00)
    {
        printf("The LRC code computed through DMA transmission is error,it should be 0x00.\r\n");
    }

The expected values depend on both the data contents and the initial values, so these two constants must be updated together when another data set is used.

Corresponding source files: src/main.c, src/crc_dma.c

5.5.4 Notes and troubleshooting

Scenario Check & action Source
CRC32 reset Writing 1 to the RESET bit resets CRC32R to 0xFFFFFFFF, and the bit is cleared by hardware automatically without manual clearing. User manual
CRC16 endianness The ENDIAN bit configures the parsing order of the CRC16 data, deciding whether the input is parsed as big endian or little endian. User manual
Clean method The CLEAR bit is self-clearing and sets the CRC value from 0xFFFF_FFFF to the default 0x0000. User manual
Independent data register CRC32IDAT is a general-purpose data register and is not affected by the RESET bit. User manual
Initial value When an initial value is required, write it to CRC_CRC16D or CRC_CRC32D first, otherwise the computation continues from the previous result. User manual
LRC check LRC is an exclusive-OR check, and software should clear the LRC initial value before the next computation. User manual
Data width CRC16DAT supports 8-bit, 16-bit and 32-bit write operations. User manual
Nations Technologies DevKit Docs

Datasheets, SDK, driver APIs and demo guides for Nations Technologies MCU development kits, organized by chip series.

© 2026 Nations Technologies Inc. All rights reserved.粤ICP备11069485号This site uses cookie-free anonymous analytics.