MSP430 Assembly Language Tools v15.9.0.STS User's Guide
SLAU131 - REVISED SEPTEMBER, 2015

C CRC Reference Implementation

This appendix contains source code in C for a reference implementation of a CRC calculation routine that is compatible with the linker-generated CRC tables (Section C.9). This code is found in the file labeled ref_crc.c.

This appendix also contains source code for a simple example application using linker-generated CRC tables and copy tables Section C.10. The application contains several tasks which share a common run area. Linker-generated copy tables move the tasks from their load addresses to the run address. The application also uses the reference CRC calculation routine to compute CRC values which are compared against the linker-generated values.

This code is for reference only, and no warranty is made as to its suitability for any purpose.

C.9 Reference CRC Calculation Routine

To run a stand-alone test of the reference implementation of CRC computation, follow these steps:

  1. Create a CCS project with an empty main.c file.
  2. Copy the contents of example_c1.c (Example C-1) to the main.c file.
  3. Create a crc_tbl.h file in the project, and copy the contents of Example 8-29 to that file.
  4. Build and test the project. You should see the following printf() statement results:
  5. CRC_32_PRIME: 74b85ade CRC_8_PRIME: 10 CRC16_802_15_4: b83d

Example C-1 Reference Implementation of a CRC Calculation Function: example_c1.c

/*****************************************************************************/ /* Reference implementation of a CRC calculation function */ /* gen_crc is the interface function which should be called from the */ /* application. There is also a stand-alone test mode that can be used */ /* if _RUN_MAIN is defined. */ /*****************************************************************************/ /*---------------------------------------------------------------------------*/ /* This file does NOT implement a general-purpose CRC function. */ /* Specifically, it does not handle parameterization by initial value, bit */ /* reflection, or final XOR value. This implementation is intended only to */ /* implement the CRC funtions used by the linker for MSP430 CRC tables. The */ /* algorithms used by the linker are selected to match the CRC algorithms in */ /* the PRIME and IEEE 802.15.4-2006 standards. MSP430 crc hardware supports */ /* CRC16_802_15_4 (CRC_CCITT). To understand CRCs in general, especially */ /* what other parameters exist, see: */ /* */ /* "A Painless Guide To CRC Error Detection Algorithms" likely at: */ /* http://www.ross.net/crc/download/crc_v3.txt */ /* Author : Ross Williams (ross@guest.adelaide.edu.au.). */ /* Date : 3 June 1993. */ /* Status : Public domain (C code). */ /*---------------------------------------------------------------------------*/ #include <msp430.h>#include <stdio.h>#include <stdlib.h>#include <limits.h>/*---------------------------------------------------------------------------*/ /* These are the CRC algorithms supported by the linker. MPS430 crc hardware */ /* supports CRC16_802_15_4 (CRC_CCITT). These must match the values in */ /* crc_tbl.h */ /*---------------------------------------------------------------------------*/ #define CRC32_PRIME 0 #define CRC16_802_15_4 1 #define CRC16_ALT 2 #define CRC8_PRIME 3 typedef struct crc_config_t { int id; int degree; unsigned long poly; } crc_config_t; const crc_config_t crc_config[] = { { CRC32_PRIME, 32, 0x04c11db7 }, { CRC16_802_15_4, 16, 0x1021 }, { CRC16_ALT, 16, 0x8005 }, { CRC8_PRIME, 8, 0x07 } }; unsigned long crc_table[256] = { 0 }; const crc_config_t *find_config(int id) { size_t i; for (i = 0; i < sizeof(crc_config) / sizeof(*crc_config); i++) if (crc_config[i].id == id) return &crc_config[i]; fprintf(stderr, "invalid config id %d\n", id); exit(EXIT_FAILURE); return NULL; } /*---------------------------------------------------------------------------*/ /* Table-driven version */ /*---------------------------------------------------------------------------*/ unsigned long generate_mask(int degree) { unsigned long half = (1ul << (degree / 2)) - 1; return half << (degree / 2) | half; } void generate_crc_table(const crc_config_t *config) { int i, j; unsigned long bit, crc; unsigned long high_bit = (1ul << (config->degree - 1)); unsigned long mask = generate_mask(config->degree); for (i = 0; i < 256; i++) { crc = (unsigned long)i << config->degree - 8; for (j = 0; j < 8; j++) { bit = crc & high_bit; crc <<= 1; if (bit) crc^= config->poly; } crc_table[i] = crc & mask; } } /*****************************************************************************/ /* gen_crc - Return the CRC value for the data using the given CRC algorithm */ /* int id : identifies the CRC algorithm */ /* char *data : the data */ /* size_t len : the size of the data */ /*****************************************************************************/ unsigned long gen_crc(int id, const unsigned char *data, size_t len) { /*-----------------------------------------------------------------------*/ /* Note: this is not a general-purpose CRC function. It does not handle */ /* parameterization by initial value, bit reflection, or final XOR */ /* value. This CRC function is specialized to the CRC algorithms in the */ /* linker used for MSP430 CRC tables. */ /*-----------------------------------------------------------------------*/ /* This CRC function is not intended to be optimal; it is written such */ /* that it works and generates the same result on all 8-bit and 16-bit */ /* targets, including MSP430, other TI DSPs, and typical desktops. */ /*-----------------------------------------------------------------------*/ const crc_config_t *config = find_config(id); unsigned long crc = 0; unsigned long mask = generate_mask(config->degree); size_t i; generate_crc_table(config); for (i = 0; i < len; i++) { unsigned int datum = data[i]; /*--------------------------------------------------------------------*/ /* This loop handles 16-bit chars when we compile on 16-bit machines. */ /*--------------------------------------------------------------------*/ int n; for (n = 0; n < (CHAR_BIT / 8); n++) { unsigned long octet = ((datum >> (8 * n)) & 0xff); unsigned long term1 = (crc << 8); int idx = ((crc >> (config->degree - 8)) & 0xff) ^ octet; crc = term1 ^ crc_table[idx]; } } return crc & mask; } /*****************************************************************************/ /* main - If requested, compute the CRC of test data using each algorithm. */ /*****************************************************************************/ int main(void) { const unsigned char data[] = { 0, 'a', 0, 'b', 0, 'c', 0, 'd' }; /* CRC_8_PRIME: 0x70 */ /* CRC_16_802: 0x1bd3 */ /* CRC_32_PRIME: 0x4beab53b */ const unsigned char *p = (const unsigned char *)data; unsigned long crc; crc = gen_crc(CRC32_PRIME, p, sizeof data); printf("CRC_32_PRIME: %08lx\n", crc); crc = gen_crc(CRC8_PRIME, p, sizeof data); printf("CRC_8_PRIME: %02lx\n", crc); crc = gen_crc(CRC16_802_15_4, p, sizeof data); printf("CRC16_802_15_4: %04lx\n", crc); return 0; }

C.10 Linker-Generated Copy Tables and CRC Tables

In this example, three tasks exist in separate load areas. As each is needed, it is copied into the common run area and executed. A separate copy table is generated for each task (see table() operator in ex1.cmd). CRC values for the task functions are verified as well. See Example C-7 for the crc_table() operator calls.

To run a simple example that uses copy tables and CRC tables, follow these steps:

  1. Create a CCS project with an empty main.c file.
  2. Create following files in the project and copy code into the files from the following examples:
  3. Edit the linker command file (*.cmd) provided for your target in the CCS project. Add the UNION statement in Example C-7 to the SECTION directives in the file.
  4. Build and test the project. You should see the result: "Copy table and CRC tasks PASSED".

Example C-2 Main Routine for Example Application: main.c

#include <msp430.h>#include <stdio.h>#include <cpy_tbl.h>#include <crc_tbl.h>extern COPY_TABLE task1_ctbl; extern COPY_TABLE task2_ctbl; extern COPY_TABLE task3_ctbl; extern CRC_TABLE task1_crctbl; extern CRC_TABLE union_crctbl; /****************************************************************************/ /* copy_in - provided by the RTS library to copy code from its load */ /* address to its run address. */ /* my_check_CRC - verify that the CRC values stored in the given table */ /* match the computed value at run time, using load address. */ /* taskX - perform a simple task. These routines share the same run */ /* address. */ /****************************************************************************/ extern void copy_in(COPY_TABLE *tp); extern unsigned int my_check_CRC(CRC_TABLE *tp); extern void task1(void); extern void task2(void); extern void task3(void); int x = 0; main() { unsigned int ret_val = 0; unsigned int CRC_ok = 1; printf("Start task copy test with CRC checking.\n"); printf("Check CRC of task1 section.\n"); ret_val = my_check_CRC(&task1_crctbl); if (ret_val == 1) printf("\nPASSED: CRCs for task1_crc_tbl match.\n"); else { CRC_ok = 0; printf("\nFAILED: CRCs for task1_crc_tbl do NOT match.\n"); } /*************************************************************************/ /* Copy task1 into the run area and execute it. */ /*************************************************************************/ copy_in(&task1_ctbl); task1(); printf("Check CRC of UNION.\n"); if ((ret_val = my_check_CRC(&union_crctbl)) == 1) printf("\nPASSED: CRCs for union_crc_tbl match.\n"); else { CRC_ok = 0; printf("\nFAILED: CRCs for union_crc_tbl do NOT match.\n"); } copy_in(&task2_ctbl); task2(); copy_in(&task3_ctbl); task3(); printf("Copy table and CRC tasks %s!!\n", ((CRC_ok == 1 && x == 6)) ? "PASSED" : "FAILED"); }

Example C-3 Checking CRC Values: check_crc.c

#include <stdio.h>#include <crc_tbl.h>/****************************************************************************/ /* gen_crc() - computes the CRC value of data using the CRC algorithm ID */ /* specified. Found in ref_crc.c */ /****************************************************************************/ unsigned long gen_crc(int id, const unsigned char *data, size_t len); unsigned int my_check_CRC(CRC_TABLE *tp) { int i; unsigned int ret_val = 1; uint32_t my_crc; printf("\n\nTABLE INFO: rec size=%d, num_rec=%d.", tp->rec_size, tp->num_recs); for (i = 0; i < tp->num_recs; i++) { CRC_RECORD crc_rec = tp->recs[i]; /**************************************************/ /* COMPUTE CRC OF DATA STARTING AT crc_rec.addr */ /* FOR crc_rec.size UNITS. USE */ /* crc_rec.crc_alg_ID to select algorithm. */ /* COMPARE COMPUTED VALUE TO crc_rec.crc_value. */ /**************************************************/ my_crc = gen_crc(crc_rec.crc_alg_ID, (unsigned char *)crc_rec.addr, crc_rec.size); #if defined(__LARGE_CODE_MODEL__) && !defined(__LARGE_DATA_MODEL__) printf("\nCRC record: alg=%x, addr=%lx, size=%lx, crc=%lx, my_crc=%x.", crc_rec.crc_alg_ID, crc_rec.addr, crc_rec.size, crc_rec.crc_value, my_crc); #else printf("\nCRC record: alg=%x, addr=%x, size=%x, crc=%lx, my_crc=%lx.", crc_rec.crc_alg_ID, crc_rec.addr, crc_rec.size, crc_rec.crc_value, my_crc); #endif if (my_crc == crc_rec.crc_value) printf("\nCRCs match for record %d.\n", i); else { ret_val = 0; printf("\nCRCs DO NOT match for record %d.\n", i); } } return ret_val; }

Example C-4 Task1 Routine: task1.c

#include <stdio.h>extern int x; #pragma CODE_SECTION(task1, ".task1_scn") void task1(void) { printf("hit task1, x is %d\n", x); x += 1; }

Example C-5 Task2 Routine: task2.c

#include <stdio.h>extern int x; #pragma CODE_SECTION(task2, ".task2_scn") void task2(void) { printf("hit task2, x is %d\n", x); x += 2; }

Example C-6 Task3 Routine: task3.c

#include <stdio.h>extern int x; #pragma CODE_SECTION(task3, ".task3_scn") void task3(void) { printf("hit task3, x is %d\n", x); x += 3; }

Example C-7 Command File Addition

UNION { .task2_scn: load = FLASH, table(_task2_ctbl) .task3_scn: load = FLASH, table(_task3_ctbl) .task1_scn: load = FLASH, table(_task1_ctbl), crc_table(_task1_crctbl) } run = FLASH2, crc_table(_union_crctbl, algorithm=CRC16_802_15_4)
Submit Documentation Feedback

Copyright© 2015, Texas Instruments Incorporated. An IMPORTANT NOTICE for this document addresses availability, warranty, changes, use in safety-critical applications, intellectual property matters and other important disclaimers.