TODOPIC

Microcontroladores PIC => Todo en microcontroladores PIC => Mensaje iniciado por: BrunoF en 18 de Abril de 2009, 19:45:52

Título: Algoritmos para calcular CRC5 CRC7 CRC8 CRC16 CRC24 CRC32
Publicado por: BrunoF en 18 de Abril de 2009, 19:45:52
Archivo adjunto con las rutinas al final del post, para lenguajes C y ASM

Debido a la cantidad de gente que ha estado consultandome por privado y al mail cómo realizar un CRC para diversos dispositivos(como los iButtons) me decidí a realizar las rutinas para calcular los 3 CRC más comunes: 8,16 y 32.

Entiendo que muchos hayan encontrado difícil entender o lograr conseguir un algoritmo que funcione según sus necesidades, ya que en la web el CRC no está muchas veces debidamente explicado. Tampoco es mi idea aclarar ésto. Si bien podría explicar básicamente de qué se trata sólo estaría hablando más de lo mísmo. Googlen para eso. No voy a explicar el por qué éstos algoritmos que publico a continuación funcionan.
   La explicación no es sencilla si no se poseen conocimientos avanzados de sistema binario, instrucciones de uC PIC y cálculo matemático. Si me parece pertinente y necesario en el futuro lo explicaré con gusto.Sin embargo, sí voy a explicar algo que trastorna a muchos que es cómo obtener el polinomio que se utiliza en el algorítmo basandose en el polinomio dado.

¿Listos? ¡Vamos!

Para realizar el cálculo del CRC de una determinada cantidad de bytes, primero hay ciertas convenciones que debemos averiguar(en caso que estemos trabajando con un CRC impuesto) o debemos establecer(en caso que nosotros realicemos nuestro CRC propio y personal).

el algoritmo de un CRC tiene 4 variables básicas de entrada que necesitamos para determinar su correcto cálculo:

un dato de entrada(value), que es el byte(en mis ejemplos son siempre de 8 bits de longitud. Para más bits hay que modificar mis algoritmos) del cual vamos a calcular su CRC;
un polinomio: que es el divisor de "value", y requiere de ciertos conocimientos para ser elegido adecuadamente. Exísten varios polinomios populares que son los más utilizados;
un valor entrada: es un valor(de 8, 16 o 32 bits) con el cual se realiza una XOR entre el mísmo y "value" apenas comienza el cálculo del CRC;
un valor salida: es un valor(de 8, 16 o 32 bits) con el cual se realiza una XOR entre el mísmo y "value" al final del cálculo del CRC;

El dato obviamente es el djavascript:ChangeEditor(5)ividendo y es necesario, el polinomio también lo es. Los valores de entrada y salida pueden ser usados como puede que no.Eso depende del método empleado.

Si no utilizan valor de salida y/o valor de entrada, recuerden poner su/s byte/s a cero antes de realizar el cálculo del CRC.Caso contrario el CRC les va a dar...MAL(99% probable)

Por ejemplo: MAXIM en su DOW CRC (http://pdfserv.maxim-ic.com/en/an/AN27.pdf) utiliza un valor de entrada, pero no de salida. Averigüen bien lo siguiente:

¿Qué polinomio utiliza?
¿Se utiliza una variable de entrada?
¿Se utiliza una variable de salida?

Una vez averiguados esos datos, procederemos a ver cúal es el CRC que debemos usar. A este dato nos los da el Polinomio. el CRC que deberemos usar será el grado del polinomio -1.

Ejemplo:

P(x) = x^{16} + x^{15} + x^2 + 1


El grado del polinomio es 16. Por lo que el CRC deberá ser de GRADO(P(x)) = 16. Usaremos el algoritmo de CRC16.



Acá viene una parte misteriosa del asunto. No he encontrado web alguna que hable realmente de cómo calcular el valor de la variable polinomio partiendo de su función polinómica.
Muchos me han consultado cómo hago para calcularlo. Si comprenden bien el funcionamiento binario del cálculo del CRC, podrán apreciar que se calcula de la siguiente manera:

Utilicemos el polinomio de más arriba:

P(x) = x^{16} + x^{15} + x^2 + 1


Pasos:

1)Transformar cada término del polinomio en su equivalente binario. Realizando ésto nos queda:

b11000000000000101


Para llegar a este valor, lo que hice sencillamente ha sido:

P(2) = 2^{16} + 2^{15} + 2^2 + 1=98309= b11000000000000101


El número 2 es el utilizado para el valor de x, porque estamos utilizando sistema binario(2 elementos).

2) Eliminar el bit de mayor peso,quedandonos ahora:

b1000000000000101


3) Espejar el valor binario, quedandonos:

b1010000000000001


Listo, tenemos nuestro valor polinómico para usar en el algoritmo. Lo pasamos a Hexadecimal si queremos, para que sea más legible:

b1010000000000001=10100000 00000001=1010 0000 0000 0001=A001=0xA001


Entonces, utilizaremos el valor 0xA001 en nuestra variable polinomio



Hagamos un ejemplo con un CRC8 popular, el DOW CRC8 usado por MAXIM en los IButtons:

Revisando la AN27 de Maxim, veremos que su polinomio es:

P(x) =x^8 + x^5 + x^4+ 1


Respetando los pasos que comenté haremos entonces:

1) Calcular el valor del polinimo con x=2 y pasar el resultado a binario:

P(2)=2^8 + 2^5 + 2^4 + 1=305= b100110001


2)Quitarle el bit de mayor peso:

b00110001


3)Espejarlo:

b10001100=1000 1100=0x8C


Listo. Tenemos nuestro polinomio. Ahora si leemos en la AN27, veremos que este CRC en particular utiliza un valor de entrada pero no de salida.
El valor de entrada para el primer byte del cálculo de una cadena de bytes es 0x00. Los posteriores valores corresponden al valor del CRC calculado para el byte previo.

A ver si puedo ilustrar bien esto. Supongamos que quiero calcular el CRC de la siguiente cadena de bytes: 0x55,0x34,0x24,0x11,0x01

Para calcularlo debería ir sometiendo byte per byte al CRC,pero teniendo en cuenta que la variable de entrada de un byte es el CRC calculado previo.

paso por paso:

CRC1 = calcular CRC8 con: value =0x55  poly =0x8C  enter_value=0x00 y  exit_value=0x00
CRC2 = calcular CRC8 con: value =0x34  poly =0x8C  enter_value=CRC1 y  exit_value=0x00
CRC3 = calcular CRC8 con: value =0x24  poly =0x8C  enter_value=CRC2 y  exit_value=0x00
CRC4 = calcular CRC8 con: value =0x11  poly =0x8C  enter_value=CRC3 y  exit_value=0x00
CRCF = calcular CRC8 con: value =0x01  poly =0x8C  enter_value=CRC4 y  exit_value=0x00


El CRC Final(CRCF) será el CRC buscado. Como verán, en este CRC se realiza una XOR al inicio del cálculo entre el CRC previo y el dato actual. Esto es debido a que mejora la diversificación de distintos CRC.

Espero que les haya servido la explicación. A continuación adjunto los archivos con los algorítmos correspondientes. Éxitos en su comprobación de datos.

BrunoF.



Actualización:

Corregí errores con el grado del polinomio de la explicación. Perdón por el error.

Agrego al archivo adjunto las rutinas para el cálculo de CRC5 para CCS y assmebly, así también como la de CRC24 para lenguaje assembly(gracias MigSantiago por mencionar la CRC5 del USB la cual había olvidado);

Menciono los CRC más comunes que pueden toparse al trabajar con uCs(posteen si saben de otros y los vamos agregando!):

CRC5:
USB: polinomio:
x^5+x^2+1
(0x14)

CRC7:
MMC-SD: polinomio:
x^7+x^3+1
(0x48)

CRC8:
iButton: polinomio:
x^8+x^5+x^4+1
(0x8C)

CRC16:
USB: polinomio:
x^{16}+x^{15}+x^2+1
(0xA001)
iButton: polinomio:
x^{16}+x^{15}+x^2+1
(0xA001)



Actualización:

Agregado CRC7...

Saludos.
Título: Re: Algoritmos para calcular CRC: CRC8, CRC16 y CRC32
Publicado por: Nocturno en 19 de Abril de 2009, 01:24:00
Muy interesante, Bruno. Gracias
Título: Re: Algoritmos para calcular CRC: CRC8, CRC16 y CRC32
Publicado por: migsantiago en 19 de Abril de 2009, 12:07:24
Qué bueno que lo explicas de forma sencilla. Tienes razón, todas las explicaciones que he intentado leer son muy difíciles de entender.

A ver si puedo aportar algo con el CRC5 usado en USB  :?
Título: Re: Algoritmos para calcular CRC: CRC8, CRC16 y CRC32
Publicado por: BrunoF en 19 de Abril de 2009, 14:57:02
Gracias migsantiago, ahí agregue el CRC5.
Título: Re: Algoritmos para calcular CRC: CRC8, CRC16 y CRC32
Publicado por: migsantiago en 19 de Abril de 2009, 21:15:47
 :D

Entonces acabas de hacerme la tarea de la escuela  :mrgreen:
Título: Re: Algoritmos para calcular CRC5 CRC7 CRC8 CRC16 CRC24 CRC32
Publicado por: migsantiago en 02 de Mayo de 2009, 13:13:27
Hola Bruno

A ver si me quedó bien el cálculo siguiendo tu algoritmo:

Código: [Seleccionar]
int8 CRC5(int8 value, int8 poly, int8 init_value, int8 exit_value){

     int8 res,i;
     res=value;   
     res^=init_value;

     for(i=0;i<5;i++){
         if(res & 1){
             res>>= 1;
             res^=poly;
         }else{
             res>>= 1;
         }
     }

    res^=exit_value;
    return (int)res;
}

CRC 5 USB

Polinomio = x5 + x2 + 1
Equivale a: 100101
Borrando el bit de mayor peso: 00101
Espejeando: 10100 = 0x14

Aplicando el CRC 5 a un byte

Entrada 0xAA
Polinomio 0x14
Valor Inicial 0x00
Valor Final 0x00


Resultado XOR Valor Inicial:
10101010
00000000
------------
10101010 = Resultado

Realizar lo siguiente 5 veces (CRC 5)
 + Si el bit 0 de Resultado es 1, rotar a la derecha 1 vez y aplicar Resultado XOR Polinomio
 + Si el bit 0 de Resultado es 0, solo rotar a la derecha 1 vez

Ciclo 1
10101010 -> 01010101
Ciclo 2
01010101 -> 00101010 -> 00101010 XOR 00010100 = 00111110
Ciclo 3
00111110 -> 00011111
Ciclo 4
00011111 -> 00001111 -> 00001111 XOR 00010100 = 00011011
Ciclo 5
00011011 -> 00001101 -> 00001101 XOR 00010100 = 00011001

Calcular Resultado XOR Valor Final

00011001 XOR 00000000 = 00011001

Cálculo del CRC: 00011001 = 0x19

¿Está bien hecho?  :o

EDITO:
Leyendo más veces tu tutorial creo que encontré un error:

Citar
Entonces, utilizaremos el valor 0xA002 en nuestra variable polinomio

Creo que debería ser 0xA001.

Y en el adjunto de las funciones en la de CRC8 pones que calcula polinomios de 9 bits pero es de 8  :mrgreen:

Una duda: ¿Qué significa el siguiente código?

Código: [Seleccionar]
cout << res << "\n";
Gracias Bruno.
Título: Re: Algoritmos para calcular CRC5 CRC7 CRC8 CRC16 CRC24 CRC32
Publicado por: BrunoF en 02 de Mayo de 2009, 14:34:25
¿Está bien hecho?  :o

Sí. 10 puntos.

EDITO:
Leyendo más veces tu tutorial creo que encontré un error:

Citar
Entonces, utilizaremos el valor 0xA002 en nuestra variable polinomio

Creo que debería ser 0xA001.

Si. Es un error, gracias. Lo que pasa fue que hice un ejemplo primero con un polinomio que daba 0xA002 y luego, como era tan parecido al CRC16 que se usaba para los i-buttons(0xA001), decidi cambiarlo y eso quedó del anterior.


Y en el adjunto de las funciones en la de CRC8 pones que calcula polinomios de 9 bits pero es de 8  :mrgreen:

Sí. Lo que pasa es que si te fijas, los polinomios tienen 1 bit más que el polinomio del algorítmo.
Fijate que el polinomio del CRC5 que acabas de usar tiene 6 bits: 100101, pero luego el polinomio resultante para el algoritmo solo tiene 5 bits: 0x14 = 10100. Esto es parte de la teoría del algoritmo usado, y es bastante lógico ya que recordemos que el CRC es el resto de una división. Por definición, el resto siempre debe ser menor al divisor. Entonces, en binario, eso significa que el resto puede tener, a lo sumo, un bit menos que el divisor. Esto solo sucede en el sistema binario, ejemplo:


si hago 15 / 8 = 1 con resto=7. Fijate que como es sistema decimal, el resto tiene 1 dígito al igual que el divisor.


si ahora lo hago en binario:
1111 / 1000 = 1 con resto= 111. El resto tiene 3 bits, contra 4 que tiene el divisor. Este es el resto mas grande que puede quedar, y solo puede a lo sumo tener 1 bit menos que el divisor.

Por este motivo, se descarta el bit de mayor peso del polinomio al calcularlo(el 2do paso) ya que no aporta realmente al cálculo y en un CRC8, por ejemplo,obligaría tal vez a tener que usar 2 bytes para calcular el CRC. Similar con CRC16 y CRC32.

Una duda: ¿Qué significa el siguiente código?

Código: [Seleccionar]
cout << res << "\n";
Gracias Bruno.

No se donde lo leíste. Lo que pasa es que yo programé la parte de C en el DEV-C++ y se ve que han quedado "restos". Espero que al menos esté comentado. el cout lo usaba yo para imprimir en consola el resultado del CRC cuando estaba debugueando el código que iba haciendo.

Saludos.
Título: Re: Algoritmos para calcular CRC5 CRC7 CRC8 CRC16 CRC24 CRC32
Publicado por: migsantiago en 02 de Mayo de 2009, 14:43:23
Ah qué bien  :-/

El código del cout viene en la función del CRC16 y CRC32 pero ahora veo que solo hay que comentarlo.

Gracias Bruno.
Título: Re: Algoritmos para calcular CRC5 CRC7 CRC8 CRC16 CRC24 CRC32
Publicado por: migsantiago en 08 de Mayo de 2009, 17:18:13
Una duda gigantesca...

Citar
8.3.5  Cyclic Redundancy Checks

...

For CRC generation and checking, the shift registers in the generator and checker are seeded with an all-
ones pattern.  For each data bit sent or received, the high order bit of the current remainder is XORed with
the data bit and then the remainder is shifted left one bit and the low-order bit set to zero.  If the result of
that XOR is one, then the remainder is XORed with the generator polynomial.
When the last bit of the checked field is sent, the CRC in the generator is inverted and sent to the checker
MSb first.  When the last bit of the CRC is received by the checker and no errors have occurred, the
remainder will be equal to the polynomial residual.
A CRC error exists if the computed checksum remainder at the end of a packet reception does not match the
residual.
Bit stuffing requirements must be met for the CRC, and this includes the need to insert a zero at the end of a
CRC if the preceding six bits were all ones.

8.3.5.1 Token CRCs
A five-bit CRC field is provided for tokens and covers the ADDR and ENDP fields of IN, SETUP, and
OUT tokens or the time stamp field of an SOF token.  The PING and SPLIT special tokens also include a
five-bit CRC field.  The generator polynomial is:

G(X) = X5 + X2 + 1

The binary bit pattern that represents this polynomial is 00101B.  If all token bits are received without error,
the five-bit residual at the receiver will be 01100B.

Esa es la sección que define el cálculo del CRC5 para USB. Mi enorme duda es que al final dice que el residuo de 5 bits será de 01100 solo si no hubo errores de transmisión...

- ¿Todos los residuos deben dar 01100?
- Para el cálculo de 0xAA como dato mi residuo fue de 0x19, ¿está mal para USB?

Intenté usar un valor inicial de 0xFF pero el resultado no da 01100. También intenté aplicar el valor final 0xFF pero nada.

Bruno, ¿sabes si tu método es distinto al que usa el USB?
Título: Re: Algoritmos para calcular CRC5 CRC7 CRC8 CRC16 CRC24 CRC32
Publicado por: migsantiago en 08 de Mayo de 2009, 18:15:39
Quisiera agregar que el CRC 5 USB se calcula sobre 11bits (ADDR + ENDP).

(http://img21.imageshack.us/img21/8631/crc5.jpg)
Título: Re: Algoritmos para calcular CRC5 CRC7 CRC8 CRC16 CRC24 CRC32
Publicado por: migsantiago en 09 de Mayo de 2009, 00:25:47
Bueno, ya estudié más y no coincide el método de crc hasta donde entiendo, pero afortunadamente tengo un analizador por hardware usb y en los ejemplos vienen algunos trenes de pulsos y sus respectivos CRC5.

(http://img14.imageshack.us/img14/4278/crc5.png)

(http://img5.imageshack.us/img5/9599/crc52.png)

En el 2do ejemplo, el valor de frame tiene 11 bits que están transmitidos desde el LSb hasta el MSb. El valor es:

Frame: 0000 0111 0011 0010

Si aplico el algoritmo como en el primer ejemplo...

Frame = 0x0732
Polinomio = 0x14
Valor Inicial = 0x00
Valor final = 0x00

El CRC resultante me da 00101 pero el que sale en el analizador es 00011 (el LSb se envía primero).

Ahora realizando el mismo caso pero con...

Frame = 0x0732
Polinomio = 0x14
Valor Inicial = 0xFF
Valor final = 0x00

En este caso me da 01100, pero tampoco coincide con 00011.  :(

Seguiré investigando.
Título: Re: Algoritmos para calcular CRC5 CRC7 CRC8 CRC16 CRC24 CRC32
Publicado por: BrunoF en 09 de Mayo de 2009, 02:09:58
Hola Santi! Estoy medio enfermo y no ando mucho por la PC. Puede que los CRC que no sean 8 o 16 tengan errores en su cálculo. Estuve mirando un poco pero no encontré ninguna tabla CRC5, eso es lo mas fácil para ver si el algoritmo responde bien.

Por ahi mirando en este link lo entendés un poco mejor a  los CRC usados por el USB:

http://www.usb.org/developers/whitepapers/crcdes.pdf

Sin embargo comparto tu idea de que no están andando. Por lo que leí en ese pdf, enter_value deberia ser 0x1F y exit_value también.
Título: Re: Algoritmos para calcular CRC5 CRC7 CRC8 CRC16 CRC24 CRC32
Publicado por: BrunoF en 09 de Mayo de 2009, 07:22:35

- ¿Todos los residuos deben dar 01100?

No. El CRC justamente es un método que intenta siempre obtener resultados muy distintos aun cuando cambia solo 1 bit de la trama para poder comprobar posibles errores durante el envio.

Bueno, los algoritmos no están mal pero si incompletos. Pasa que los algoritmos que expuse solo arrojan el CRC(correcto) cuando la cantidad de bits de la trama a enviar coincide con la cantidad de bits del CRC que se utiliza, es decir tramas de 8 bits para CRC8, tramas de 5 bits para CRC5,etc. Esto fue por migrar de CRC8 y CRC16,a CRC no multiplos de un byte, como CRC5,CRC7 y demás.

En el pdf que te indiqué arriba vienen un par de ejemplos de CRC5:

el crc5 10101000111 es 10111
el crc5 01011100101 es 11100

y otros mas....

Te dejo la subrutina modificada del CRC5 para que funcione correctamente con tramas de 11 bits, asi también como la llamada para obtener el CRC5 correcto.

Código: C
  1. char CRC5(long value, char poly, char init_value, char exit_value){
  2.  
  3.      char i;
  4.      long res;
  5.  
  6.      res=value;
  7.    
  8.      res^=init_value;
  9.                   //reacomodado para 11bits de trama
  10.      for(i=0;i<11;i++){
  11.          if(res & 1){
  12.              res>>= 1;
  13.              res^=poly;
  14.          }else{
  15.              res>>= 1;
  16.          }
  17.      }
  18.      
  19.      res^=exit_value;
  20.                 //solo quedarse con el byte bajo(solo sirven los 5 bits de menor peso, el resto deberian ser ceros)
  21.      return (int8)res;
  22. }

y para el ejemplo de trama '01011100101' llamarías así:

    int8 tmp;

    tmp=CRC5(741,0x14,0x1F,0x1F);

y debería devolver el valor decimal 28(11100). Caso contrario decime que me equivoqué en algo del algoritmo de arriba. :mrgreen:

Un saludo.












Título: Re: Algoritmos para calcular CRC5 CRC7 CRC8 CRC16 CRC24 CRC32
Publicado por: migsantiago en 09 de Mayo de 2009, 11:46:06
Vientos y recontra vientos  :D

Déjame probarlas y hacerlas a mano y te confirmo si funcionan correctamente. Ayer en clase nos estuvimos peleando con los bits y con muchas XORs intentando llegar a lo que el CRC5 de las imágenes mostraban, pero no llegamos a nada.

Gracias Sr. Bruno
Título: Re: Algoritmos para calcular CRC5 CRC7 CRC8 CRC16 CRC24 CRC32
Publicado por: blackcat en 09 de Mayo de 2009, 13:54:20
Hola! ...

Muchas gracias por sus aportes ... en especial a BrunoF

Un dia estaba tratando de entender esta cuestion del CRC pero igual me hice bolas, entonces lo deje tirado, ahora que estoy leyendo tu post me volví a interesar pero a lo que yo entendia de CRC me quedé mas confundido (como siempre!  :D)....

En toda clase hay alguien que hace una pregunta tonta que siempre aclara las dudas de muchos ... me manifiesto, esta es mi pregunta tonta:

La cosa es que voy a transmitir una trama variable que contiene como máximo 128bytes ... se hace por RS232 y va de byte en byte ... yo entendía lo siguiente:

1-) El transmisor envia la trama y al final coloca el CRC .. es decir, si transmito 100bytes, calculo el CRC de esos 100bytes y coloco el CRC al final ... si fuere CRC16 entonces se transmiten 102bytes ...

2-) El receptor ya sabe que va a recibir 100 bytes (no interesa como), y que va a recibir 2 bytes extra de CRC ... ahora según un profesor (que sabe poco de implementacion de CRC! ) me dice que hay dos formas de saber si la trama llego bien:

    A-) Volviendo a calcular el CRC de los 100bytes y comparar con el CRC recibido.
    B-) Calcular el CRC de los 102 bytes, si el CRC da un valor particular como 0x0000 o 0xFFFF quiere decir que esta bueno.

Yo vi en internet varios algoritmos de CRC, probé todos pero ninguno me hacia según la verificación que explique en la parte B.

Ahora, baje los algoritmos que BrunoF propone ... pero veo que solo calcula CRC para tramas de 8, 16 etc bits....

¿Como puedo hacer una verificacion de tramas largas y variables?
¿Existe la verificacion que explico en la parte B?

Saludos!
 


   
Título: Re: Algoritmos para calcular CRC5 CRC7 CRC8 CRC16 CRC24 CRC32
Publicado por: BrunoF en 09 de Mayo de 2009, 15:00:52
Hola blackcat!

Cuando uno realiza un CRC en varias etapas, es decir, como por ejemplo en el caso que exponés, el valor de entrada(enter_value en mis algoritmos) es el CRC previo calculado, es decir:

En una trama de 100 bytes, si usas CRC16 deberás primero pactar: El polinomio a utilizar; si se utiliza un valor de entrada inicial distinto de cero y si se utiliza un valor de salida distinto de cero.

Como estamos frente a un CRC16 lo lógico es por ejemplo, tomar de a dos bytes por vez, y someterlos al cálculo del CRC. Supongamos que decido que mi algoritmo utilizará un valor de entrada inicial distinto de cero. Esto quiere decir que, cuando calcule mi primer CRC16(los primeros dos bytes de la trama) haré:

res1= CRC16(byte1byte0, polinomio, 0xFFFF,0x0000)

Fijemonos que aqui le paso los javascript:ChangeEditor(5)argumentos necesarios:
"byte1byte0" serian los primeros 2 bytes de la trama;
el "polinomio" dependería del polinomio elegido(aclaro que mi algoritmo utiliza POLINOMIOS INVERTIDOS(reversed));
"0xFFFF" es un valor con el cual se realizará una XOR con "byte1byte0" al entrar a la rutina del CRC que protegerá a mis bits en caso de que sean ceros.
"0x0000" significa que al terminar de calcular el CRC no modifico el valor obtenido(se realiza la XOR con "byte1byte0" pero no afecta a su valor original);

Como resultado, "res1" contendrá un valor de 16 bits con el CRC calculado, ahora, al calcular el CRC para los próximos dos bytes de la trama, se realizaría así:

res2= CRC16(byte3byte2, polinomio, res1,0x0000)

Si nos fijamos, no solo varian los datos de entrada(que es lógico) sino que además ahora el valor de entrada es el CRC16 calculado previamente("res1"). Esta es la manera en la que se van encadenando los datos y sus respectivos CRC.

Si seguimos con la mísma lógica, los próximos dos bytes de la trama se calcularían...(piensenlo y anotenlo y luego corroboren para ver si me van siguiendo....)
.....
........
................
res3= CRC16(byte5byte4, polinomio, res2,0x0000)

¿Bien?

Entonces, básicamente, el algoritmo del CRC consta de 3 partes importantes:

1)Primero se realiza una XOR entre los datos de entrada y un valor("enter_value" en mi algoritmo);
2)Se realiza el cálculo del CRC del valor obtenido en 1);
3)Se realiza otra XOR entre el valor obtenido en 2) y otro valor("exit_value" en mi algoritmo).


Vamos a verificar si lo que dijo tu profe tiene sentido(aunque yo ya sé la respuesta  :D):

Supongamos una trama de 100 bytes; no entremos en detalles en los valores de los bytes de la trama;supongamos sencillamente que:
"X" representa los 100 bytes de trama
y que el CRC calculado da "C"
Entonces, mi trama estaría compuesta por: "XC"

Método a)

Recibo el paquete "XC" de 102 bytes. Realizo 50 veces(2 bytes por vez) el calculo del CRC16 de la trama "X", y finalmente el CRC que obtengo tiene(o debería tener mejor dicho) un valor "C" si la trama enviada no está corrupta.
Comparo el C obtenido con el C calculado. Son iguales. Perfecto;

Método b)
Recibo el paquete "XC" de 102 bytes. Realizo 50 veces(2 bytes por vez) el calculo del CRC16 de la trama "X", y finalmente el CRC que obtengo tiene(o debería tener mejor dicho) un valor "C" si la trama enviada no está corrupta.
En lugar de compararlo, voy a someter la "C" de la trama recibida con el CRC calculado de la trama "X".

La llamada a la función CRC16 quedaría:

Caso a)

resf= CRC16(C, polinomio, C,0x0000)

La primera "C" corresponde al valor de los dos ultimos bytes de la trama(que sería el CRC recibido), la segunda "C" corresponde al valor CRC final calculado de la trama "X"(porque seguiríamos encandenando los CRCs calculados según lo que expuse más arriba).

Fíjate lo que pasa:

1)Primero se realiza una XOR entre los datos de entrada(C) y un valor(C)("enter_value" en mi algoritmo):
Entonces quedaría C XOR C = 0

2)Se realiza el cálculo del CRC del valor obtenido en 1):
Expongo aquí la LEY DE LA NADA: :mrgreen: :mrgreen:
¿De la nada qué sacamos? ¡NADA! Entonces, si el valor del cual calcular el CRC es 0, el CRC dará 0. Esto sucede con todos los CRC. El resto de 0 es 0. Siempre.
Entonces, el resultado de este paso será 0.
3)Se realiza otra XOR entre el valor obtenido en 2) y otro valor("exit_value" en mi algoritmo):
Realizamos entonces ahora la XOR entre lo calculado previamente(0) y el valor de salida(0x0000). La XOR dará 0.

Entonces, podemos asegurar que la trama está correcta porque el CRC final de los 102 bytes dará 0.

Caso b)

Similar al caso a), sólo que cuando se utiliza un valor de 0xFFF para "exit_value", en el último cálculo del CRC la llamada quedaría:

resf= CRC16(C, polinomio, C,0xFFFF)

1) C XOR C = 0
2)CRC 0 = 0
3) 0 XOR 0xFFFF = 0xFFFF

Por lo que tu profesor tiene razón. Puede dar 0x0000 o 0xFFFFF según los parámetros de salida elegidos.

Saludos.








Título: Re: Algoritmos para calcular CRC5 CRC7 CRC8 CRC16 CRC24 CRC32
Publicado por: migsantiago en 09 de Mayo de 2009, 17:00:30
Bruno, te confirmo que el algoritmo esta vez funciona correctamente. Lo aplique sobre las 2 gráficas que puse arriba y salió OK.

Solo un pequeño detalle, en la función hay que declarar long res; en vez de long value;.

Gracias y ojalá te recuperes pronto.  :mrgreen:
Título: Re: Algoritmos para calcular CRC5 CRC7 CRC8 CRC16 CRC24 CRC32
Publicado por: BrunoF en 09 de Mayo de 2009, 17:56:50
ups! Es verdad! Ahora lo corrijo. me alegro que funcione. Gracias por preguntar.

:D
Título: Re: Algoritmos para calcular CRC5 CRC7 CRC8 CRC16 CRC24 CRC32
Publicado por: Suky en 08 de Noviembre de 2009, 23:00:56
Buenas! Estoy tratando de entender como calcular el CRC del protocolo DNP3 y me está ganando  :8} Paso a explicar como se calcula así me dan una mano de como aplicar el código desarrollado por Bruno si es aplicable  :?

El polinomio que se utiliza es:
p(x)=x^16+x^13+x^12+x^11+x^10+x^8+x^6+x^5+x^2+1
y esto equivale a 10011110101100101. Aplicando lo descripto por Bruno en el primer post se llega a que poly=0xA6BC.

Según las especificaciones del protocolo para calcular el CRC debo multiplicar el bloque de datos (de 8 a 128 bits) por 0x10000 (216), el resultado dividirlo en modulo 2 por el polinomio, y el CRC resulta de invertir el resto. Como aplicaría el algoritmo que desarrolla Bruno en este caso  :?:

Saludos!
Título: Re: Algoritmos para calcular CRC5 CRC7 CRC8 CRC16 CRC24 CRC32
Publicado por: BrunoF en 09 de Noviembre de 2009, 07:00:29
Hola Suky. Si. En teoria cualquier CRC puede ser aplicado a los algoritmos.

En tu caso estás ante un CRC16.

El bloque de datos es siempre multiplo de 8(bits)? O puede que no lo sea necesariamente?.

El CRC que mencionas parece no utilizar valor de entrada, entonces comenzaria con 0x0000(que me parece que iria en lugar del 0x10000 que mencionas). Por lo que comentas el CRC con el que queres trabajar tambien utiliza 0xFFFF por unica vez como valor de salida(porque decis que "el CRC resulta de invertir el resto...").

Cabe destacar que todos los algoritmos que estan presentes aqui utilizan el polinomio reverso(reversed poly).


Realizando algunas pruebas, se ve que rula bien si se eligen bien los parametros:

(http://www.todopic.com.ar/foros/index.php?action=dlattach;topic=25627.0;attach=10447)

Código: C
  1. long CRC16(char value, long poly, long init_value, long exit_value){
  2.      long res;
  3.      long i;
  4.  
  5.      res=value;
  6.  
  7.      res^=init_value;
  8.  
  9.      for(i=0;i<8;i++){
  10.          if(res & 1){
  11.              res>>= 1;
  12.              res^=poly;
  13.          }else{
  14.              res>>= 1;
  15.          }
  16.      }
  17.     res^=exit_value;
  18.     return res;
  19. }
  20.  
  21. int main(int argc, char *argv[])
  22. {
  23.     //QCoreApplication a(argc, argv);
  24.     char datos[]="123456789";
  25.     uint i;
  26.     long inival;
  27.  
  28.     inival=0x0000;
  29.     for(i=0;i<strlen(datos);i++){
  30.         inival=CRC16(datos[i],0xA6BC,inival,0x0000);
  31.     }
  32.  
  33.     inival^=0xFFFF;
  34.     printf("El CRC de la cadena: %s es: %X\n",datos,inival);
  35.  
  36.     return a.exec();
  37. }

Título: Re: Algoritmos para calcular CRC5 CRC7 CRC8 CRC16 CRC24 CRC32
Publicado por: jansuini en 09 de Noviembre de 2009, 07:49:43
Suky
Una consulta:
que estás haciendo en DNP?
Si necesitas algún ensayo de maestro ó esclavo avisame que puedo hacerlo.
Sds
Jorge
Título: Re: Algoritmos para calcular CRC5 CRC7 CRC8 CRC16 CRC24 CRC32
Publicado por: Suky en 09 de Noviembre de 2009, 09:49:46
 :-/ Muchas gracias Bruno, me complique la vida con los valores de entrada y salida, hice varias combinaciones (fuerza bruta porque no logré entender como aplicarlo  :8}) pero no me daba  :mrgreen: Gracias nuevamente!

Suky
Una consulta:
que estás haciendo en DNP?
Si necesitas algún ensayo de maestro ó esclavo avisame que puedo hacerlo.
Sds
Jorge

Por ahora trato de entenderlo! Para luego aplicarlo a un sistema re-conector de alta tensión. Toda la información al respecto me vendría bárbaro!!! :-/


Saludos!
Título: Re: Algoritmos para calcular CRC5 CRC7 CRC8 CRC16 CRC24 CRC32
Publicado por: jansuini en 09 de Noviembre de 2009, 13:40:29
Suky:
lo que tengo es una rtu con DNP maestro y esclavo ,por eso puedo simularlas .En que provincia estas?
Jorge
Título: Re: Algoritmos para calcular CRC5 CRC7 CRC8 CRC16 CRC24 CRC32
Publicado por: IngRandall en 23 de Septiembre de 2011, 11:32:22
todos  los crc tienes que hacerle el espejo al polinomio o es solo si este lo indica?????? saben algo acerca de crc del protocolo bsap de bristol?????
Título: Re: Algoritmos para calcular CRC5 CRC7 CRC8 CRC16 CRC24 CRC32
Publicado por: BrunoF en 23 de Septiembre de 2011, 13:14:30
El espejo se realiza para poder realizarar el cálculo mediante el método que implemento, nada más.

Desconozco sobre ese protocolo.

Saludos.
Título: Re: Algoritmos para calcular CRC5 CRC7 CRC8 CRC16 CRC24 CRC32
Publicado por: PalitroqueZ en 15 de Abril de 2014, 23:26:41
Bruno, desaparecieron las imagenes al principio del tema :(
Título: Re: Algoritmos para calcular CRC5 CRC7 CRC8 CRC16 CRC24 CRC32
Publicado por: BrunoF en 16 de Abril de 2014, 01:52:26
Hola Pedro,

sí. Es un problema seguramente del LaTeX que no está funcionando el generador de imágenes y se pierde. Tengo que revisar si puedo repararlo...

Saludos!
Título: Re: Algoritmos para calcular CRC5 CRC7 CRC8 CRC16 CRC24 CRC32
Publicado por: elotrogonzalo en 25 de Junio de 2014, 10:06:50
Hola BrunoF, podrías subir en un rar las fotos del primer post para poder entender mejor? justo estoy aprendiendo sobre el calculo de crc y me di con que no puedo ver las fotos jeje. Tengo unas dudas al respecto con las rutinas propuestas por que anteriormente estuve viendo esta rutina:

http://www.nongnu.org/avr-libc/user-manual/group__util__crc.html#ga95371c87f25b0a2497d9cba13190847f

uint16_t crc16_update(uint16_t crc, uint8_t a)
    {
        int i;

        crc ^= a;
        for (i = 0; i < 8; ++i)
        {
            if (crc & 1)
                crc = (crc >> 1) ^ 0xA001;
            else
                crc = (crc >> 1);
        }

        return crc;
    }

dudas:

un ejemplo podría ser el siguiente? crc16_update(0xFFFF, undato);

El valor crc inicial hay que pasarle FFFF? la variable "a" de ésta rutina seria el dato a calcularle el crc no?

Yo quiero hacer lo siguiente: tengo una trama de 22 bytes y quiero adjuntarle el crc, entonces

CRC16 = 0xFFFF;

for(i = 0; i < 21; i++)
{
     CRC16 = crc16_update(CRC16, buffer);
}

y luego de ésto obtendría el crc de ésa trama verdad?

Espero puedan corregirme! Saludos.
Título: Re: Algoritmos para calcular CRC5 CRC7 CRC8 CRC16 CRC24 CRC32
Publicado por: Micom en 21 de Julio de 2014, 20:16:42
Seria bueno armar un pdf con esta información tan valiosa, y mantener el orden que tiene de origen para que no se pierda. saludos
Título: Re: Algoritmos para calcular CRC5 CRC7 CRC8 CRC16 CRC24 CRC32
Publicado por: BrunoF en 21 de Julio de 2014, 21:09:52
Hola BrunoF, podrías subir en un rar las fotos del primer post para poder entender mejor? justo estoy aprendiendo sobre el calculo de crc y me di con que no puedo ver las fotos jeje. Tengo unas dudas al respecto con las rutinas propuestas por que anteriormente estuve viendo esta rutina:

http://www.nongnu.org/avr-libc/user-manual/group__util__crc.html#ga95371c87f25b0a2497d9cba13190847f

uint16_t crc16_update(uint16_t crc, uint8_t a)
    {
        int i;

        crc ^= a;
        for (i = 0; i < 8; ++i)
        {
            if (crc & 1)
                crc = (crc >> 1) ^ 0xA001;
            else
                crc = (crc >> 1);
        }

        return crc;
    }

dudas:

un ejemplo podría ser el siguiente? crc16_update(0xFFFF, undato);

El valor crc inicial hay que pasarle FFFF? la variable "a" de ésta rutina seria el dato a calcularle el crc no?

Yo quiero hacer lo siguiente: tengo una trama de 22 bytes y quiero adjuntarle el crc, entonces

CRC16 = 0xFFFF;

for(i = 0; i < 21; i++)
{
     CRC16 = crc16_update(CRC16, buffer);
}

y luego de ésto obtendría el crc de ésa trama verdad?

Espero puedan corregirme! Saludos.

Hola, perdoná la demora. Sí, si el algoritmo que usan invierte el valor de entrada, entonces sería correcto. Igualmente a veces no lo invierten. Depende de la implementación. Por lo general, se invierte por única vez al ingresar al procesamiento de una trama.

Voy a intentar ver lo de las imágenes. En realidad es un fallo del generador del LaTEX. Saludos.
Título: Re: Algoritmos para calcular CRC5 CRC7 CRC8 CRC16 CRC24 CRC32
Publicado por: BrunoF en 21 de Julio de 2014, 21:39:46
He corregido el procesador de LaTeX. Ahora las imágenes de las fórmulas deberían verse bien.

Saludos.