CRC16 XModem woes

This may be something i have stared at for hours and missing the obvious, but here goes.
Communicating with a 7 segment 4digit display with its own RS232 controller.

Using a Terminal program i can send working commands to the display via a pc / Rpi.
I then used the following code in the Arduinio IDE with a Mega 2560 and it works great.

If i want to change the 4 digits displayed, i can do so but have to use an online CRCcalculator to get the CRC addition.

This works perfectly, for simple 4 digits of a known fixed value.

However i would like to create 4 random digits and then apply the CRC and send.

Arduino Mega Code:
byte message2[] = {0xFE, 0x0B, 0x01, 0x01, 0x01, 0x14, 0x01, 0x01, 0x01, 0x01, 0xFF, 0x54, 0x66 }; // displays 1111 on the display.
Serial1.write(message2, sizeof(message2));

Those between **** **** in the above code will be my random generated numbers and then the appropriate CRC at the end will of course be changed.

I have tried many examples online and none seem to work, what am i missing,?

The other values in this statement( outside of the **** ****) control the card in the display and will stay the same.

Any help would be awesome, i am pulling whats left of my hair out.
Thanks in advance,

Paul

Manufacturer datasheet includes this code for CRC : Copied exactly, however i have found other mistakes in the packet so i would expect others.

unsigned int CRC16(unsigned char *ptr,unsigned int count)
{
unsigned int crc=0;
unsigned char i;
while (count>0)
{count--;
crc=(crc^(((unsigned int)*ptr)<<8));
for(i=0;i<8;i++)
{
if(crc&0x8000)crc= ((crc<<1)^0x1021);
else crc<<=1;
}
ptr++
}
return crc;
}

Please follow the forum rules and post all the code, using code tags (<code> button in post editor).

Also post examples of the input, the output and the correct answer for your failed CRC tests.

1 Like

Also, use Tools/Auto Format your code before posting.

Hi @paultyrer ,

Welcome to the forum..

sending in the below array to your crc function returns 21,606 or hex 5466..

maybe you were sending in the whole array, the last 2 bytes is the added checksum..

good luck.. ~q

q.
I really appreciate your help. Can i ask how you implemented the array?
Yes the completed array had the 2 byte checksum, i obtain the checksum from the online CRC calculator. I have yet to figure out how to get the Mega to do this. Thank you.
Paul

I used your array just reduced the count passed into it by 2, sizeof(message2)-2..

when it returns the word you can separate the bytes using lowByte() and highByte()..

put them into the last 2 bytes and you should be good to go..

only other thing I would caution on is using native ints, would be better to use std ints..

unsigned int would be changed to uint16_t..

on 8 and 16 bit avr int is 16 bits, 2 bytes, on 32 bits mcu’s they are 32 bits, 4 bytes..

using std ints makes the code more portable..

here’s a WoKi for you..

good luck..~q

THANK YOU x20
This has helped me a great deal.

Thank you.......

1 Like

Use this library

1 Like

Using the CRC library

//
//    FILE: CRC16_test_xmodem.ino
//  AUTHOR: Rob Tillaart
// PURPOSE: demo
//     URL: https://github.com/RobTillaart/CRC


#include "CRC16.h"
#include "CRC.h"

uint8_t message1[] = {0xFE, 0x0B, 0x01, 0x01, 0x01, 0x14, 0x42, 0xAA, 0x5C, 0xF1, 0xFF, 0x54, 0x66 };
uint8_t message2[] = {0xFE, 0x0B, 0x01, 0x01, 0x01, 0x14, 0x01, 0x01, 0x01, 0x01, 0xFF, 0x54, 0x66 };

CRC16 crc(CRC16_XMODEM_POLYNOME,
          CRC16_XMODEM_INITIAL,
          CRC16_XMODEM_XOR_OUT,
          CRC16_XMODEM_REV_IN,
          CRC16_XMODEM_REV_OUT);


void setup()
{
  Serial.begin(115200);
  Serial.println();
  Serial.println(__FILE__);
  Serial.print("CRC_LIB_VERSION: ");
  Serial.println(CRC_LIB_VERSION);
  Serial.println();

  crc.restart();
  crc.add((uint8_t *) message2, 11);
  Serial.println(crc.calc(), HEX);

  crc.restart();
  crc.add((uint8_t *) message1, 11);
  Serial.println(crc.calc(), HEX);

  //  confirmed with https://crccalc.com/
}


void loop()
{
}


//  -- END OF FILE --


output confirms the 01 01 01 01 checksum 5466

CRC_LIB_VERSION: 1.0.4

5466
50EB

Give it a try

I was able to piece together code that did what i wanted. However i need to add the crc checksum to the end of my initial byte array and send back out via Serial1 to the display.

This will create random numbers between 1 and 3000, then split the digits to place into the byte data, uses this whole array to create crc, This works perfectly.

I need to add the crc checksum to the end of the initial byte data and send.
Hopefully this makes sense. I have been thinking about this all night lol.

THANK YOU TO ALL for replying, i very much appreciate your help.
Paul

int myInt; // Decimal value 1-9999

// Polynomial: x^16 + x^12 + x^5 + 1 (0x1021)
uint16_t crc_xmodem_update(uint16_t crc, uint8_t data) {
  int i;
  crc = crc ^ ((uint16_t)data << 8);
  for (i = 0; i < 8; i++) {
    if (crc & 0x8000)
      crc = (crc << 1) ^ 0x1021; // The Xmodem polynomial
    else
      crc <<= 1;
  }
  return crc;
}

uint16_t calc_crc(byte *msg, int n) {
  uint16_t x = 0x0000; // Xmodem uses an initial value of 0x0000
  while (n--) {
    x = crc_xmodem_update(x, (uint16_t)*msg++);
  }
  return x;
}

void setup() {
  Serial.begin(9600);
  Serial1.begin(9600,SERIAL_8N1);


}

void loop() {
  // put your main code here, to run repeatedly:
  myInt =random(1,3000);// makes a random number
  
Serial.print ("Random Number :  " );
Serial.print (myInt);// print random number

// split number n into its digits
byte ones = myInt % 10;
byte tens = (myInt / 10) % 10;
byte hund = (myInt / 100) % 10;
byte thou = (myInt / 1000) % 10;

  
  while (!Serial);
  
  //byte crc2=(9);

  byte data[] = {0xFE,0x0F, 0x01, 0x01, 0x01, 0x24,0x01,0x02,0x03,0x04, thou, hund, tens, ones,0xFF};
  uint16_t crc_out;

  crc_out = calc_crc(data, sizeof(data));

  Serial.print("  Calculated CRC-16 Xmodem: 0x  ");
  Serial.print(crc_out, HEX);
  Serial.println("  ");
  
  //All works, i need to add the crc_out 2 bytes to the end of the byte data and then send,
//testing code here


//testing over


 
}

1 Like

Serial is bit by bit, byte by byte. There is no need to append the CRC to the byte array.

Use Serial1.write(); to write one byte at a time, first the contents of byte array, then the two bytes of the 16 bit CRC, in the correct order.