This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

MSP430FR5994: CRC hardware implementation

Part Number: MSP430FR5994
Other Parts Discussed in Thread: MSP430WARE

Hi, Please I need an example CCS projects that demonstrate the use of linker-generated CRC tables to compute CRC at runtime onMSP430FR5994 using the CRC hardware module. I have accessed the following sources to get an understanding of how to generate CRC tables, 

MSP430 Assembly Language Tools v18.1.0.LTS User's Guide (Rev. R) (ti.com)

From the Experts: Perform cyclic redundancy checking using linker-generated CRC tables - Tools Insider - Archives - TI E2E support forums

  • Hi Peace,

    There aren't any full examples of this from what I can find for MSP430. 

    There are quite a few old threads that discuss the use of the crc-tables in the linker (see here: https://e2e.ti.com/support/microcontrollers/msp-low-power-microcontrollers-group/msp430/f/msp-low-power-microcontroller-forum/898475/compiler-msp430f5438a-appending-crc-to-the-output-file).

    For examples on how to use the internal CRC module in the MSP430, take a look at the crc_16 and crc_32 examples in resource explorer (https://dev.ti.com/tirex/explore/node?node=A__AF7oKdOr-S4f69Qk8zW6KA__msp430ware__IOGqZri__LATEST&placeholder=true&search=MSP430FR5994)

    Best Regards,
    Brandon Fisher

  • Hi Brandon, thanks for the information, I have been able to generate the CRC table for the code and constant data section, with the linker generated table confirmed with two CRC RECORD in the .map file. However, in order to confirm this CRC values in the application code, I have an issue in trying to access the values that will be passed through the CRC hardware peripheral. Do i need a specific function to access the values in the memory range from which the

    initial CRC value was generated?

  • You just need a pointer to the start of the section and the section size, both of which are contained in a CRC_RECORD, referenced within the linker's generated CRC_TABLE structure for each output section. Then feed byte-by-byte into the peripheral. You'll need to create your own function to seed the CRC module and feed the bytes into it, as TI does not supply one. For example, a basic function I've used looks like:

    //Calculate the CRC16 using the CRC32 module. Only
    //perform CRC16_802_15_4 (CRC16_CCITT). The linker
    //does this byte-wise, load only 1 byte at a time.
    uint8_t calcCRCOverMemRange(CRC_RECORD *crcRec)
    {
       uint8_t *i;
    
       //Size is in 8-bit addressable units
       uint8_t *lastAddress = (uint8_t*)crcRec->addr + (crcRec->size);
    
       //Set initial value for CRC Module per the
       //crc_defines.h Algorithm Specifiers
       CRC16INIRESW0 = 0x0000;
    
       for(i = (uint8_t*)crcRec->addr; i < lastAddress; i++)
       {
           CRC16DIRBW0_L = *i;
       }
    
       if(CRC16INIRESW0 != crcRec->crc_value)
           return 1;
    
       return 0;
    }

  • Thank you Seth, I have a similar implementation like the one you sent, but so far I was using driverlib functions as below, this has been giving the error, as it always return a wrong CRC value. However when I switched to registers, it works properly. Can you help me take a look at the code below using driverlib, perhaps I may be calling the wrong function

    uint16_t saf_crc::GetCRC(uint8_t *addr, size_t len)
    {
    
        uint16_t crc_result = 0;
        uint8_t *current_addr;
    
        // Reset the CRC signature and set the initial seed
        CRC_setSeed(CRC32_BASE, CRC_Init);
    
        // Calculate the ending address
        uint8_t *end_addr = addr + len;
    
        // Iterate over the memory region from the starting address to the ending address
        for (current_addr = addr; current_addr < end_addr; current_addr++)
        {
            // Add the value into the CRC signature
            CRC_set8BitData(CRC32_BASE, *current_addr);
        }
    
        // Get the CRC result
        crc_result = CRC_getResult(CRC32_BASE);
        return crc_result;
    }
     

    This is sample call of the above function

    CRC_RECORD crc_rec = p_crc_table->recs[0];

    saf_crc::s_crc_val.crc_cal_val = saf_crc::GetCRC((uint8_t *)crc_rec.addr, crc_rec.size);


    if (saf_crc::s_crc_val.crc_cal_val != crc_rec.crc_value)
    {
    //do something
    GPIO_toggleOutputOnPin(
    GPIO_PORT_P1,
    GPIO_PIN0);
    }

    else
    {
    //do something
    GPIO_toggleOutputOnPin(
    GPIO_PORT_P1,
    GPIO_PIN1);
    }
    __delay_cycles(100000);

    thank you for your assistance

  • I do not use DriverLib so I can't be 100% certain. However, you can look into the DriverLib's .h and .c files to see the problem. Just compare what they are doing to what the working register code does. The source code is in [MSP430WARE_INSTALL_DIR]\driverlib\driverlib\MSP430FR5xx_6xx

    The code I posted uses the CRC32 module in CRC16 mode, and bytes are fed in reversed bit order. I don't believe your code is doing the same thing.

  • It works properly now by feeding the bytes in reversed bit order as you pointed out

    uint16_t saf_crc::GetCRC(uint8_t *addr, size_t len)
    {
            uint16_t crc_result = 0;
            uint8_t *current_addr;
    
            // Reset the CRC signature and set the initial seed
            CRC_setSeed(CRC_BASE, CRC_Init);
    
            // Calculate the ending address
            uint8_t *end_addr = addr + len;
    
            // Iterate over the memory region from the starting address to the ending address
            for (current_addr = addr; current_addr < end_addr; current_addr++)
            {
                // Add the value into the CRC signature
                CRC_set8BitDataReversed(CRC_BASE, *current_addr);
            }
    
            // Get the CRC result
            crc_result = CRC_getResult(CRC_BASE);
            return crc_result;
    
    }

    Also this also works using CRC32 in 16bit mode as you pointed out

    uint16_t saf_crc::GetCRC(uint8_t *addr, size_t len)
    {
            uint16_t crc_result = 0;
            uint8_t *current_addr;
    
            // Reset the CRC signature and set the initial seed
            CRC32_setSeed(CRC_Init, CRC16_MODE);
    
            // Calculate the ending address
            uint8_t *end_addr = addr + len;
    
            // Iterate over the memory region from the starting address to the ending address
            for (current_addr = addr; current_addr < end_addr; current_addr++)
            {
                // Add the value into the CRC signature
                CRC32_set8BitDataReversed(*current_addr, CRC16_MODE);
            }
    
            // Get the CRC result
            crc_result = CRC32_getResult(CRC16_MODE);
            return crc_result;
    
    }

    Thank you for your assistance.

**Attention** This is a public forum