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.

MSP432E401Y: Hardware CRC for 16-bit CCITT standard always has 0xFF for upper byte

Part Number: MSP432E401Y


Hi TI Experts,

I am trying to implement the hardware CRC on the MSP432E401Y. I need to use the CRC_POLYNOMIAL_CRC_16_CCITT standard to match a HW CRC I am calculating on the MSP430 (which only has one standard). I am calculating this on 4 bytes of data, adding the data 1 byte at a time. The seed (initial value) is 0xFFFF.

I have attached my code below, which is the standard example code for hardware CRC calculation on the MSP432. I have only changed src to 4 bytes, src_size and the params used by the CRC driver to suit my needs.

/*
 * Copyright (c) 2019, Texas Instruments Incorporated
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * *  Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * *  Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * *  Neither the name of Texas Instruments Incorporated nor the names of
 *    its contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

/*
 *  ======== crc.c ========
 */
#include <stdint.h>
#include <stddef.h>
#include <stdlib.h>

/* Driver Header files */
#include <ti/drivers/UART.h>
#include <ti/drivers/CRC.h>

/* Driver configuration */
#include "ti_drivers_config.h"

/* Expected CRC for CRC_32_IEEE with full endianness reversal */
static const uint32_t expectedCrc = 0x4C4B4461;

/* Example test vector */
static const size_t srcSize = 4;
static const uint8_t src [] = {
    0x12, 0x34, 0x56, 0x78
};

static const char preOpMessage[] = "Performing CRC_32_IEEE with endianness reversal... ";
static const char postOpMessage[] = "Check successful.\r\n";

/* ======== mainThread ======== */
void *mainThread(void *arg0)
{
    int_fast16_t status;
    uint16_t result;

    CRC_Handle handle;
    CRC_Params params;

    UART_Handle uart;
    UART_Params uartParams;

    /* Initialize the drivers */
    CRC_init();
    UART_init();

    /* Create a UART with data processing off. */
    UART_Params_init(&uartParams);
    uartParams.writeDataMode = UART_DATA_BINARY;
    uartParams.readDataMode = UART_DATA_BINARY;
    uartParams.readReturnMode = UART_RETURN_FULL;
    uartParams.readEcho = UART_ECHO_OFF;
    uartParams.baudRate = 115200;

    uart = UART_open(CONFIG_UART_0, &uartParams);

    if (uart == NULL) {
        /* UART_open() failed */
        while (1);
    }

    UART_write(uart, preOpMessage, sizeof(preOpMessage));

    /* Set data processing options, including endianness control */
    CRC_Params_init(&params);
    params.byteSwapInput = CRC_BYTESWAP_UNCHANGED;
    params.returnBehavior = CRC_RETURN_BEHAVIOR_BLOCKING;
    params.polynomial = CRC_POLYNOMIAL_CRC_16_CCITT;
    params.dataSize = CRC_DATA_SIZE_8BIT;
    params.seed = 0xFFFF;
    //params.programmablePoly = 0x1021;
    //params.programmablePolyOrder = 3;

    /* Open the driver using the settings above */
    handle = CRC_open(CONFIG_CRC_0, &params);
    if (handle == NULL)
    {
        /* If the handle is already open, execution will stop here */
        while(1);
    }

    /* Calculate the CRC of all 32 bytes in the source array */
    status = CRC_calculateFull(handle, src, srcSize, &result);
    if (status != CRC_STATUS_SUCCESS)
    {
        /* If the CRC engine is busy or if an error occurs execution will stop here */
        while(1);
    }

    /* This is another way of achieving the same result; for instance
     * if data is arriving in blocks (over UART) this method may be preferable.
     * CRC_reset() may be used to clear an ongoing partial if the result is no
     * longer needed. CRC_finalise() also resets the state. */
    status = CRC_addData(handle, src, srcSize/2);
    if (status != CRC_STATUS_SUCCESS)
    {
        /* If the CRC engine is busy or if an error occurs execution will stop here */
        while(1);
    }

    status = CRC_addData(handle, &src[srcSize/2], srcSize/2);

    /* Extract the result from the internal state */
    CRC_finalize(handle, &result);

    if (status != CRC_STATUS_SUCCESS)
    {
        /* If the CRC engine is busy or if an error occurs execution will stop here */
        while(1);
    }

    UART_write(uart, postOpMessage, sizeof(postOpMessage));

    /* Close the driver to allow other users to access this driver instance */
    CRC_close(handle);
    UART_close(uart);

    return NULL;
}

I am cross-checking my result with this online CRC calculator Online CRC-8 CRC-16 CRC-32 Calculator (crccalc.com), and the result should be in the first row (CRC-16/CCITT-FALSE).

Data: 0x12, 0x34, 0x56, 0x78

The result I get from my code: 0xFFEC

The result from the online calculator: 0x30EC

Below is a snapshot of the result from the online calculator.

No matter which combination of data I try, the lower byte (EC in this case) is correct, but the upper byte is either FF or some other value that is wrong.

Is there a mistake with my implementation of the CRC driver on the MSP432?

Any help is much appreciated.

Thanks.

  • Hi,

      I will look into it and get back with you. 

  • Hi,

     For some reason, the below line is not correctly saving the CRC checksum to the result variable although the CRC hardware calculates the checksum to be 030EC. You can view the CRC module in register window to confirm. The SDK CRC driver is also new to me. I'm not sure what is wrong with it. 

    line 111  CRC_calculateFull(handle, src, srcSize, &result);

    I will suggest you first put a breakpoint at breakpoint in the calculateCpu. As you step through the function, watch how CCM_CRCSEED value change each time a new byte is written to it. As you can see the CRCSEED becomes 0x30EC. It is that the CRC value is not correctly saved to the result variable. 

     I also try using native CRC peripheral driver instead of TI-RTOS CRC driver and I'm able to reproduce the same checksum. Please take a look at below.  There are several things I did in order to make the hardware CRC match the online CRC calculator. 

     1. The input data needs to be 0x78563412. When you put 0x12345678 on the online calculator, it is taking 0x12 as the first byte followed by 0x34 as the second bytes and so forth. However, for the hardware the first byte of 0x12345678 is actually 0x78, not 0x12. 

     - Since you want to specify 8-bit as the size of the input data then the number of items in the array should be 4 since there are four bytes in in the input data 0x78563412. 

    #include <stdbool.h>
    #include <stdint.h>
    #include "ti/devices/msp432e4/driverlib/inc/hw_ccm.h"
    #include "ti/devices/msp432e4/driverlib/driverlib.h"
    #include "pinout.h"
    #include "uartstdio.h"
    
    //*****************************************************************************
    //
    //! \addtogroup example_list
    //! <h1>CRC-32 Demo (crc32)</h1>
    //!
    //! Simple demo showing a CRC-32 operation using the CCM module.
    //!
    //! Please note that the use of uDMA is not required for the operation of the
    //! CRC module.  It is for demostration purposes only.
    //
    //*****************************************************************************
    
    //*****************************************************************************
    //
    // Configuration defines.
    //
    //*****************************************************************************
    #define CCM_LOOP_TIMEOUT        500000
    
    
    
    //*****************************************************************************
    //
    // The error routine that is called if the driver library encounters an error.
    //
    //*****************************************************************************
    #ifdef DEBUG
    void
    __error__(char *pcFilename, uint32_t ui32Line)
    {
    }
    #endif
    
    uint32_t g_ui32Result=0;
    
    uint32_t ui32datain;
    
    int
    main(void)
    {
        ui32datain = 0x78563412;
        
        //
        // Enable the CRC module.
        //
        SysCtlPeripheralEnable(SYSCTL_PERIPH_CCM0);
        //
        // Wait for the CRC module to be ready.
        //
        while(!SysCtlPeripheralReady(SYSCTL_PERIPH_CCM0))
        {
        }
        //
        // Configure the CRC module.
        //
        CRCConfigSet(CCM0_BASE,
                     CRC_CFG_INIT_SEED |
                     CRC_CFG_TYPE_P1021 |
                     CRC_CFG_SIZE_8BIT);
        //
        // Set the seed value.
        //
        CRCSeedSet(CCM0_BASE, 0xFFFF);
    
        g_ui32Result = CRCDataProcess(CCM0_BASE, &ui32datain, 4, false);
    
    
        while(1);
    }

  • Hi,

      I think I sort of got it working. Please see below what I modified in red. 

    /* Example test vector */
    static const size_t srcSize = 4;
    static const uint8_t src [] = {
    0x12, 0x34, 0x56, 0x78
    };

    static const char preOpMessage[] = "Performing CRC_32_IEEE with endianness reversal... ";
    static const char postOpMessage[] = "Check successful.\r\n";

    /* ======== mainThread ======== */
    void *mainThread(void *arg0)
    {
    int_fast16_t status;
    uint16_t result;  // Make result a uint16_t. 

    CRC_Handle handle;
    CRC_Params params;

    UART_Handle uart;
    UART_Params uartParams;

    /* Initialize the drivers */
    CRC_init();
    UART_init();

    /* Create a UART with data processing off. */
    UART_Params_init(&uartParams);
    uartParams.writeDataMode = UART_DATA_BINARY;
    uartParams.readDataMode = UART_DATA_BINARY;
    uartParams.readReturnMode = UART_RETURN_FULL;
    uartParams.readEcho = UART_ECHO_OFF;
    uartParams.baudRate = 115200;

    uart = UART_open(CONFIG_UART_0, &uartParams);

    if (uart == NULL) {
    /* UART_open() failed */
    while (1);
    }

    UART_write(uart, preOpMessage, sizeof(preOpMessage));

    /* Set data processing options, including endianness control */
    CRC_Params_init(&params);
    params.byteSwapInput = CRC_BYTESWAP_UNCHANGED;
    params.returnBehavior = CRC_RETURN_BEHAVIOR_BLOCKING;
    params.polynomial = CRC_POLYNOMIAL_CRC_16_CCITT;
    params.dataSize = CRC_DATA_SIZE_32BIT; // Make it a 32bit data size even though the input is stored in a 8-bit array.
    params.seed = 0xFFFF;

    /* Open the driver using the settings above */
    handle = CRC_open(CONFIG_CRC_0, &params);
    if (handle == NULL)
    {
    /* If the handle is already open, execution will stop here */
    while(1);
    }

    /* Calculate the CRC of all 32 bytes in the source array */
    status = CRC_calculateFull(handle, src, srcSize, &result);
    if (status != CRC_STATUS_SUCCESS || result != expectedCrc)
    {
    /* If the CRC engine is busy or if an error occurs execution will stop here */
    while(1);
    }

  • Hi Charles, 

    Thank you for getting back to me and finding a workaround to this (using CRC_DATA_SIZE_32BIT).

    However, this means that I would not be able to add data to the CRC module as it arrives through the comms bus using the CRC_addData code below, is that correct? I tried but the result failed while checking the CRC_STATUS_SUCCESS.

    status = CRC_addData(handle, &src[srcSize/2], srcSize/2);
    
    /* Extract the result from the internal state */
    CRC_finalize(handle, &result);
    
    if (status != CRC_STATUS_SUCCESS)
        {
            /* If the CRC engine is busy or if an error occurs execution will stop here */
            while(1);
        }

    Furthermore, the application requires calculating the CRC for data as small as 3 bytes. If I changed the srcSize and src data like below, the calculation would not work anymore for both the CRC_calculateFull and CRC_addData methods.

    /* Example test vector */
    static const size_t srcSize = 3;
    static const uint8_t src [] = {
    0x12, 0x34, 0x56
    };

    Do you have a workaround for this on TI-RTOS that would allow me to calculate the 16-bit CCITT CRC on 3 bytes of data?

    Thank you for your help on this.



    As for the CRC peripheral driver, I'm afraid using TI-RTOS is a requirement for our project. Can the CRC peripheral driver be used from within TI-RTOS? If not, I do not think it would be viable.

  • Hi,

      There is an issue with the TI-RTOS driver that I need to modify. Please see below what I did and it works for me. 

    First, I modified the CRCMSP432E4.c file. This is a SDK file that I copy to the current project to make the modification. There is a typecasting problem when dealing with CRC_DATA_SIZE_8BIT. With what it is originally, it will have the upper byte of the 16-bit word equal to 0xFF. The line I modify is line 263. There could be a more elegant way to change the driver such as to also support 8bit polynomial but for your specific 16bit CRC16_CCITT requirement this will work.

    I change from:

    *((uint8_t*) resultLocation) = (uint8_t) crcResult;

    to:

    *((uint16_t*) resultLocation) = (uint16_t) crcResult;

     

    /*
     * Copyright (c) 2019, Texas Instruments Incorporated
     * All rights reserved.
     *
     * Redistribution and use in source and binary forms, with or without
     * modification, are permitted provided that the following conditions
     * are met:
     *
     * *  Redistributions of source code must retain the above copyright
     *    notice, this list of conditions and the following disclaimer.
     *
     * *  Redistributions in binary form must reproduce the above copyright
     *    notice, this list of conditions and the following disclaimer in the
     *    documentation and/or other materials provided with the distribution.
     *
     * *  Neither the name of Texas Instruments Incorporated nor the names of
     *    its contributors may be used to endorse or promote products derived
     *    from this software without specific prior written permission.
     *
     * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
     * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
     * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
     * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
     * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
     * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
     * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     */
    
    /* Drivers */
    #include <ti/drivers/CRC.h>
    #include <ti/drivers/crc/CRCMSP432E4.h>
    #include <ti/drivers/power/PowerMSP432E4.h>
    #include <ti/drivers/cryptoutils/sharedresources/CryptoResourceMSP432E4.h>
    
    /* Driverlib */
    #include <ti/devices/DeviceFamily.h>
    #include DeviceFamily_constructPath(inc/msp432.h)
    #include DeviceFamily_constructPath(driverlib/crc.h)
    #include DeviceFamily_constructPath(driverlib/types.h)
    #include DeviceFamily_constructPath(driverlib/sysctl.h)
    #include DeviceFamily_constructPath(driverlib/inc/hw_ccm.h)
    
    /* Forward declarations */
    static void resetHardware(void);
    static void cleanup(CRC_Handle handle);
    static void calculateCpu(CRC_DataSize size, CRC_ByteSwap swap, const void *source, size_t sourceBytes);
    static int_fast16_t calculate(CRC_Handle handle, const void *source, size_t sourceBytes);
    static void setResultLocation(CRC_DataSize size, void* resultLocation, uint32_t crcResult);
    static int_fast16_t getHwConfigRegister(const CRC_Params *params, uint32_t *crcConfig);
    
    /* External symbols defined in the board file */
    extern const CRC_Config CRC_config[];
    extern const uint_least8_t CRC_count;
    
    /* Static globals */
    static uint8_t isInitialized = false;
    
    /* There is currently a bug in the MSPE4 Driverlib where the SHW and SBHW
     * definitions are swapped. These definitions are used instead. */
    #define CRC_CONFIG_ENDIAN_SBHW     0x00000010  // Swap byte in half-word
    #define CRC_CONFIG_ENDIAN_SHW      0x00000020  // Swap half-word
    
    /* ======== CRC_init ======== */
    void CRC_init(void) {
        uintptr_t key;
    
        key = HwiP_disable();
    
        if (!isInitialized) {
    
            /* CCM hardware has a rare issue where any given power state change can cause the state to hang.
             * As a workaround, we only change the power state once, at init(), and do not power it down. */
            resetHardware();
            isInitialized = true;
        }
    
        HwiP_restore(key);
    }
    
    /* ======== CRC_open ======== */
    CRC_Handle CRC_open(uint_least8_t index, const CRC_Params *params) {
        CRC_Handle handle;
        CRCMSP432E4_Object *object;
        uintptr_t key;
        int_fast16_t status;
    
        handle = (CRC_Handle) &CRC_config[index];
        object = handle->object;
    
        /* If params are NULL, use defaults */
        if (params == NULL) {
            params = (const CRC_Params *) &CRC_defaultParams;
        }
    
        key = HwiP_disable();
    
        if (!isInitialized || object->isOpen) {
            HwiP_restore(key);
            return NULL;
        }
    
        status = getHwConfigRegister(params, &object->configRegister);
        if (status != CRC_STATUS_SUCCESS) {
            HwiP_restore(key);
            return NULL;
        }
    
        object->isOpen = true;
        HwiP_restore(key);
    
        object->returnBehavior = params->returnBehavior;
        object->callbackFxn = params->callbackFxn;
        object->timeout = params->timeout;
    
        object->ongoingPartial = 0;
        object->resultRawPartial = 0;
        object->resultProcessedPartial = 0;
    
        object->seed = params->seed;
        object->dataSize = params->dataSize;
        object->finalXorValue = params->finalXorValue;
        object->byteSwapInput = params->byteSwapInput;
    
        CryptoResourceMSP432E4_CRC_incrementRefCount();
        return handle;
    }
    
    /* ======== CRC_calculateFull ======== */
    int_fast16_t CRC_calculateFull(CRC_Handle handle, const void *source, size_t sourceBytes, void *result) {
        CRCMSP432E4_Object *object = handle->object;
        int_fast16_t status;
    
        status = calculate(handle, source, sourceBytes);
        setResultLocation(object->dataSize, result, object->resultProcessedPartial);
    
        if (object->returnBehavior == CRC_RETURN_BEHAVIOR_CALLBACK) {
            object->callbackFxn(handle, CRC_STATUS_SUCCESS, result);
        }
        return status;
    }
    
    /* ======== CRC_addData ======== */
    int_fast16_t CRC_addData(CRC_Handle handle, const void *source, size_t numBytes) {
        CRCMSP432E4_Object *object = handle->object;
        int_fast16_t status;
    
        if (object->ongoingPartial) {
            object->seed = object->resultRawPartial;
        }
        object->ongoingPartial = 1;
        status = calculate(handle, source, numBytes);
    
        if (object->returnBehavior == CRC_RETURN_BEHAVIOR_CALLBACK) {
            object->callbackFxn(handle, status, NULL);
            return CRC_STATUS_SUCCESS;
        } else {
            return status;
        }
    }
    
    /* ======== CRC_finalize ======== */
    void CRC_finalize(CRC_Handle handle, void *result) {
        CRCMSP432E4_Object *object = handle->object;
    
        object->ongoingPartial = 0;
        setResultLocation(object->dataSize, result, object->resultProcessedPartial);
    }
    
    void CRC_reset(CRC_Handle handle) {
        CRCMSP432E4_Object *object = handle->object;
    
        object->ongoingPartial = 0;
    }
    
    /* ======== CRC_close ======== */
    void CRC_close(CRC_Handle handle) {
        CRCMSP432E4_Object *object = handle->object;
    
        cleanup(handle);
        CryptoResourceMSP432E4_CRC_decrementRefCount();
        object->isOpen = false;
    }
    
    /* ======== calculate ========
     * Configures the hardware using the configuration provided by setupOperation
     * and kicks off calculation of the checksum for the provided bytes */
    static int_fast16_t calculate(CRC_Handle handle, const void *source, size_t sourceBytes) {
        CRCMSP432E4_Object *object = handle->object;
    
        if (object->dataSize == CRC_DATA_SIZE_32BIT && (sourceBytes % 4) != 0) {
            return CRC_STATUS_LEFTOVER_BYTES_PRESENT;
        }
    
        if (SemaphoreP_OK != CryptoResourceMSP432E4_CRC_tryLock(object->timeout)) {
            return CRC_STATUS_RESOURCE_UNAVAILABLE;
        }
    
        HWREG(CCM0_BASE + CCM_O_CRCCTRL) = object->configRegister;
        HWREG(CCM0_BASE + CCM_O_CRCSEED) = object->seed;
    
        /* Use the CPU to calculate the CRC (result available in the peripheral register) */
        calculateCpu(object->dataSize, object->byteSwapInput, source, sourceBytes);
        /* Extract the result into the object, reset the CRC state and then return */
        cleanup(handle);
    
        return CRC_STATUS_SUCCESS;
    }
    
    /* ======== calculateCpu ========
     * Performs a CRC calculation using the CPU. Returns after completion. */
    static void calculateCpu(CRC_DataSize size, CRC_ByteSwap swap, const void *source, size_t sourceBytes) {
        if (size == CRC_DATA_SIZE_8BIT) {
            uint8_t *source8 = (uint8_t *) source;
    
            while (sourceBytes--) {
                HWREG(CCM0_BASE + CCM_O_CRCDIN) = *(source8++);
            }
        }
        else if (size == CRC_DATA_SIZE_32BIT) {
            uint32_t *source32 = (uint32_t *) source;
            sourceBytes /= 4;
    
            while (sourceBytes--) {
                HWREG(CCM0_BASE + CCM_O_CRCDIN) = *(source32++);
            }
        }
    }
    
    /* ======== cleanup ========
     * Call this after the calculation finishes to move the results out of the CCM,
     * and close/reset all the relevant handles/statics. */
    static void cleanup (CRC_Handle handle) {
        CRCMSP432E4_Object *object = handle->object;
    
        object->resultRawPartial = HWREG(CCM0_BASE + CCM_O_CRCSEED);
        object->resultProcessedPartial = HWREG(CCM0_BASE + CCM_O_CRCRSLTPP) ^ object->finalXorValue;
    
        CryptoResourceMSP432E4_CRC_releaseLock();
    }
    
    /* ======== resetHardware ========
     * Enables and resets the CCM. */
    static void resetHardware() {
        SysCtlPeripheralEnable(SYSCTL_PERIPH_CCM0);
        while (!SysCtlPeripheralReady(SYSCTL_PERIPH_CCM0))
        { }
    
        /* Soft reset the accelerator */
        SysCtlPeripheralReset(SYSCTL_PERIPH_CCM0);
        while (!SysCtlPeripheralReady(SYSCTL_PERIPH_CCM0))
        { }
    }
    
    /* ======== setResultLocation ========
     * Correctly applies crcResult to resultLocation for different bit widths */
    static void setResultLocation(CRC_DataSize size, void* resultLocation, uint32_t crcResult) {
        switch (size) {
            case CRC_DATA_SIZE_8BIT:
                *((uint16_t*) resultLocation) = (uint16_t) crcResult;
                break;
            case CRC_DATA_SIZE_32BIT:
                *((uint32_t*) resultLocation) = crcResult;
                break;
            default:
                break;
        }
    }
    
    /* ======== getHwConfigRegister ========
     * Uses the settings in the operation to put together configuration register settings.
     * Returns CRC_OPERATION_NOT_SUPPORTED for config errors or CRC_STATUS_SUCCESS. */
    static int_fast16_t getHwConfigRegister(const CRC_Params *params, uint32_t *crcConfig) {
        /* Always manually control the seed instead of using the builtin
        options for 0x0 and 0xf. This avoids additional processing work
        and makes the partial API easier to use. */
        *crcConfig = CRC_CFG_INIT_SEED;
    
        /* No support for 16-bit data on MSP432E4 */
        switch (params->dataSize) {
            case CRC_DATA_SIZE_8BIT:
                *crcConfig |= CRC_CFG_SIZE_8BIT;
                break;
            case CRC_DATA_SIZE_32BIT:
                *crcConfig |= CRC_CFG_SIZE_32BIT;
                break;
            default:
                return CRC_STATUS_OPERATION_NOT_SUPPORTED;
        }
    
        /* There is no HW support for processing options in 8-bit mode,
        and supporting them in SW would take too much processing time for
        BLOCKING and CALLBACK modes. Instead, throw an error.
        The CRC_ByteSwap enum documents this limitation. */
        if (params->dataSize == CRC_DATA_SIZE_8BIT &&
                params->byteSwapInput != CRC_BYTESWAP_UNCHANGED) {
            return CRC_STATUS_OPERATION_NOT_SUPPORTED;
        }
    
        switch (params->byteSwapInput) {
            case CRC_BYTESWAP_UNCHANGED:
                break; /* No action required */
            case CRC_BYTESWAP_HALF_WORDS:
                *crcConfig |= CRC_CONFIG_ENDIAN_SHW;
                break;
            case CRC_BYTESWAP_BYTES_IN_HALF_WORDS:
                *crcConfig |= CRC_CONFIG_ENDIAN_SBHW;
                break;
            case CRC_BYTESWAP_BYTES_AND_HALF_WORDS:
                *crcConfig |= CRC_CONFIG_ENDIAN_SHW | CRC_CONFIG_ENDIAN_SBHW;
                break;
        }
    
        if (params->reverseInputBits) {
            *crcConfig |= CCM_CRCCTRL_BR;
        }
    
        if (params->reverseOutputBits) {
            *crcConfig |= CRC_CFG_OBR;
        }
    
        if (params->invertOutputBits) {
            *crcConfig |= CRC_CFG_RESINV;
        }
    
        switch (params->polynomial) {
            case CRC_POLYNOMIAL_CRC_16_IBM:
                *crcConfig |= CRC_CFG_TYPE_P8005;
                break;
            case CRC_POLYNOMIAL_CRC_16_CCITT:
                *crcConfig |= CRC_CFG_TYPE_P1021;
                break;
            case CRC_POLYNOMIAL_CRC_32_IEEE:
                *crcConfig |= CRC_CFG_TYPE_P4C11DB7;
                break;
            case CRC_POLYNOMIAL_CRC_32C:
                *crcConfig |= CRC_CFG_TYPE_P1EDC6F41;
                break;
            case CRC_POLYNOMIAL_CRC_TCP:
                *crcConfig |= CRC_CFG_TYPE_TCPCHKSUM;
                break;
            default:
                return CRC_STATUS_OPERATION_NOT_SUPPORTED;
        }
    
        return CRC_STATUS_SUCCESS;
    }
    

    Second, you will need to manually add a DeviceFamily_MSP432E401Y symbol in order to compile properly the above driver file. 

    Third, this is what I have for the example. See attached below. I use 3 bytes as input and it is giving the correct result. 

    /*
     * Copyright (c) 2019, Texas Instruments Incorporated
     * All rights reserved.
     *
     * Redistribution and use in source and binary forms, with or without
     * modification, are permitted provided that the following conditions
     * are met:
     *
     * *  Redistributions of source code must retain the above copyright
     *    notice, this list of conditions and the following disclaimer.
     *
     * *  Redistributions in binary form must reproduce the above copyright
     *    notice, this list of conditions and the following disclaimer in the
     *    documentation and/or other materials provided with the distribution.
     *
     * *  Neither the name of Texas Instruments Incorporated nor the names of
     *    its contributors may be used to endorse or promote products derived
     *    from this software without specific prior written permission.
     *
     * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
     * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
     * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
     * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
     * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
     * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
     * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     */
    
    /*
     *  ======== crc.c ========
     */
    #include <stdint.h>
    #include <stddef.h>
    #include <stdlib.h>
    
    /* Driver Header files */
    #include <ti/drivers/UART.h>
    #include <ti/drivers/CRC.h>
    
    /* Driver configuration */
    #include "ti_drivers_config.h"
    
    /* Expected CRC for CRC_32_IEEE with full endianness reversal */
    static const uint32_t expectedCrc = 0x12FD;
    
    /* Example test vector */
    static const size_t srcSize = 3;
    static const uint8_t src [] = {
        0x12, 0x34, 0x56
    };
    
    static const char preOpMessage[] = "Performing CRC_32_IEEE with endianness reversal... ";
    static const char postOpMessage[] = "Check successful.\r\n";
    
    /* ======== mainThread ======== */
    void *mainThread(void *arg0)
    {
        int_fast16_t status;
        uint16_t result;
    
        CRC_Handle handle;
        CRC_Params params;
    
        UART_Handle uart;
        UART_Params uartParams;
    
        /* Initialize the drivers */
        CRC_init();
        UART_init();
    
        /* Create a UART with data processing off. */
        UART_Params_init(&uartParams);
        uartParams.writeDataMode = UART_DATA_BINARY;
        uartParams.readDataMode = UART_DATA_BINARY;
        uartParams.readReturnMode = UART_RETURN_FULL;
        uartParams.readEcho = UART_ECHO_OFF;
        uartParams.baudRate = 115200;
    
        uart = UART_open(CONFIG_UART_0, &uartParams);
    
        if (uart == NULL) {
            /* UART_open() failed */
            while (1);
        }
    
        UART_write(uart, preOpMessage, sizeof(preOpMessage));
    
        /* Set data processing options, including endianness control */
        CRC_Params_init(&params);
        params.byteSwapInput = CRC_BYTESWAP_UNCHANGED;
        params.returnBehavior = CRC_RETURN_BEHAVIOR_BLOCKING;
        params.polynomial = CRC_POLYNOMIAL_CRC_16_CCITT;
        params.dataSize = CRC_DATA_SIZE_8BIT;
        params.seed = 0xFFFF;
    
        /* Open the driver using the settings above */
        handle = CRC_open(CONFIG_CRC_0, &params);
        if (handle == NULL)
        {
            /* If the handle is already open, execution will stop here */
            while(1);
        }
    
    
        /* This is another way of achieving the same result; for instance
         * if data is arriving in blocks (over UART) this method may be preferable.
         * CRC_reset() may be used to clear an ongoing partial if the result is no
         * longer needed. CRC_finalise() also resets the state. */
        status = CRC_addData(handle, src, srcSize);
        if (status != CRC_STATUS_SUCCESS)
        {
            /* If the CRC engine is busy or if an error occurs execution will stop here */
            while(1);
        }
    
        /* Extract the result from the internal state */
        CRC_finalize(handle, &result);
    
        if (status != CRC_STATUS_SUCCESS || result != expectedCrc)
        {
            /* If the CRC engine is busy or if an error occurs execution will stop here */
            while(1);
        }
    
        UART_write(uart, postOpMessage, sizeof(postOpMessage));
    
        /* Close the driver to allow other users to access this driver instance */
        CRC_close(handle);
        UART_close(uart);
    
        return NULL;
    }
    

  • Hi Charles, 

    I now have a CCITT CRC16 that I can calculate on the MSP432 for a given buffer which matches the CRC16 calculated on the MSP430. 

    Do you think it's worth notifying TI about this driver bug/issue with the MSP432E401Y TI-RTOS CRC driver? Even with this workaround, the driver is still unreliable as there may be more functionality that does not work according to the API documentation. Maybe they can provide an update to the TI-RTOS driver libraries?

    Either way, my problem has been solved for now. Thank you very much for this workaround.