Determinación de constantes de comando para el diseño de protocolos en serie

Parece suceder con bastante frecuencia que estoy trabajando en un sistema que incorpora un conjunto de comandos en serie (SPI o asíncrono).

Como tal, generalmente tengo que armar un conjunto de valores de bytes de comando arbitrarios que representen posibles comandos.

Como tal, parece que me encuentro tratando de maximizar la distinción entre posibles comandos. Por ejemplo, si tengo un total de 4 comandos, elegiría algo como:

 0x81, 0b10000001
 0x42, 0b01000010
 0x24, 0b00100100
 0X18, 0b00011000

o mejor aún (ya que permite una mayor expansión)

0xA5, 0b10100101
0x5A, 0b01011010
0X99, 0b10011001
0x66, 0b01100110
0x96, 0b10010110
0x69, 0b01101001

Ambos tienen la ventaja de ser muy distintos, por lo que el ruido tiene pocas posibilidades de corromper uno para parecerse al otro, y también es posible determinar (manualmente) el comando usando solo un analizador lógico u canal de osciloscopio.

Entonces, dada la suposición de que está diseñando un protocolo arbitrario y la suposición de que el ruido no es una consideración importante, ¿cuáles son los buenos consejos y/o comentarios sobre la mejor manera de elegir constantes binarias para la definición de comando de una interfaz serial?

En realidad, esto parece bastante aplicable a cualquier situación en la que esté utilizando comandos binarios entre dos (¡o más!) sistemas.

Realmente no está claro cuál es su objetivo aquí. ¿Realmente espera una alta tasa de error de bit en su enlace de comunicaciones, o simplemente una falla ocasional? ¿Es realmente solo el byte de comando el que debe protegerse o todo el paquete/mensaje? Normalmente, es la última respuesta para ambos, y un mecanismo de suma de verificación/reintento es el enfoque habitual.
@DaveTweed: no estaría de acuerdo en que es una pregunta vaga, soy un poco vago sobre lo que debo considerar al elegir palabras de comando. Creo que es bastante seguro asumir una tasa de error baja. La pregunta es realmente: suponiendo un sistema de suma de comprobación suficiente para detectar cualquier error de bit, ¿qué otras consideraciones son útiles al elegir valores para un protocolo?
Básicamente, tengo un sistema en el que tengo algunas comunicaciones en serie a bordo. Todo está bastante bien empaquetado y el ruido no es una gran consideración. Como tal, estoy en la posición de necesitar armar un protocolo mínimo, y me pregunto qué tienen en cuenta otras personas en una situación similar, y/o si solo elegir constantes de la parte superior de mi cabeza es una muy mala idea. por alguna razón me estoy perdiendo en este momento.
@FakeName, al editar una nueva suposición "que el ruido no es una consideración importante", ha dado tres respuestas, que fueron muy buenas respuestas a la pregunta original, irrelevante. ¿Tal vez sería mejor mantener esta pregunta como estaba y abrir una nueva pregunta con las nuevas suposiciones?
@ThePhoton: bueno, dos de las respuestas se escribieron después de la edición, así que no estoy tan seguro.

Respuestas (3)

La palabra es Distancia de Hamming , que es el número de símbolos diferentes entre dos códigos cualesquiera. Si usara cualquier combinación posible de un código de 8 bits, su distancia de Hamming es 1: un cambio de solo 1 bit le dará un nuevo código válido. Eso significa que incluso los errores de 1 bit no se pueden detectar y menos corregir.

Ahora toma el cubo de Hamming:

ingrese la descripción de la imagen aquí

Aquí solo hay 2 códigos válidos de 3 bits: 000y 111. La distancia de Hamming es 3, lo que significa que se pueden detectar menos de 3 bits de error. Los errores de un solo bit pueden incluso corregirse: si el código debe ser 000y usted tiene 001, eso es un solo bit. Si mide la distancia en el cubo a los dos códigos válidos, tendrá que seguir 2 aristas para llegar a 111, pero solo 1 arista para 000. Entonces, es un error de un solo bit, y luego puede corregirlo, o un error de varios bits, que puede detectar (porque no es un código válido) pero no corregir (no sabe si debería ser 000o 111).

Hace mucho tiempo, vi un programa de la Universidad Abierta de la BBC sobre codificación donde explicaban cómo una matriz de Hadamard proporciona una lista de códigos con una distancia de Hamming de n para un 2 norte × 2 norte matriz. La construcción de una matriz de Hadamard es interesante en sí misma y un buen ejercicio de programación. Comience con un solo bit:

1

ahora haces una matriz de 2 por 2 bits, siguiendo esta regla: copia 1en todos los cuadrantes, excepto en el inferior derecho, donde colocas la inversa:

1 1
1 0

El siguiente nivel (este es un algoritmo recursivo) aplica la misma regla a la matriz de 2 por 2, de modo que obtiene una matriz de 4 por 4. En cada cuadrante copias la matriz anterior, excepto en el inferior derecho donde la inviertes:

1 1   1 1
1 0   1 0

1 1   0 0
1 0   0 1 

Etcétera. En el siguiente nivel tendremos 8 códigos (líneas) con una Distancia de Hamming de 3:

1 1 1 1   1 1 1 1
1 0 1 0   1 0 1 0
1 1 0 0   1 1 0 0
1 0 0 1   1 0 0 1

1 1 1 1   0 0 0 0
1 0 1 0   0 1 0 1
1 1 0 0   0 0 1 1
1 0 0 1   0 1 1 0

Puede extender Hadamard Matrix tanto como desee. Si desea detectar errores de hasta 6 bits, tendrá una matriz de 64 por 64. Este tipo de codificación de errores hacia adelante se utiliza, por ejemplo, en comunicaciones espaciales, donde la distancia de la nave espacial puede ser tan grande que la señal se vuelve extremadamente ruidosa. El hecho de que solo haya un número limitado de códigos válidos, a pesar de su gran longitud, permite la detección de una señal por debajo del umbral de ruido.

Primero debe decidir contra qué está tratando de protegerse y qué quiere que haga el sistema en caso de error de transmisión. También debe considerar la posibilidad de corrupción de datos y cuáles son los costos si los datos incorrectos se interpretan como datos válidos.

Para la comunicación a bordo, generalmente ignora todo el problema. Es probable que ya esté haciendo muchas suposiciones de que la salida de un chip digital aparecerá correctamente en la entrada de otros en la misma placa. La comunicación en serie entre dos dispositivos en la misma placa no es diferente. El tipo de perturbación que causaría un error en la señalización cableada directa a bordo probablemente también causaría otros problemas o estaría tan fuera de las especificaciones que no es razonable protegerse. Por ejemplo, alguien que arrastra los pies sobre una alfombra y luego aplica 10 kV de electricidad estática a cualquier conductor expuesto en el tablero abierto causará todo tipo de fallas, pero eso también es un abuso que está fuera de las especificaciones.

Si cree que la comunicación en serie tendrá una tasa de error de bits pequeña pero lo suficientemente significativa como para que no pueda ignorarla, entonces el esquema habitual es enviar datos en paquetes con sumas de verificación. El receptor ignora cualquier paquete con suma de verificación no válida. Una suma de verificación diseñada correctamente utilizará menos bits y, por lo tanto, tendrá menos gastos generales que un enfoque torpe como limitar el espacio del código de operación para que no haya dos códigos de operación separados por 1 bit entre sí. Piénselo y verá que básicamente está enviando un código de operación más pequeño y los bits adicionales son una suma de verificación de bajo rendimiento. Solo puede detectar errores de un bit en el código de operación, no puede corregirlo y no ayuda al resto del mensaje. Si la tasa de error de bits es baja, la posibilidad de un error de un solo bit en un paquete completo es baja.

Si es lo suficientemente bueno como para simplemente descartar los comandos incorrectos, entonces puede detenerse allí. Si necesita saber que un comando se recibió correctamente, debe usar algún tipo de esquema de comunicación bidireccional. La forma más simple es que el receptor envía un ACK (adecuadamente envuelto en un paquete de suma de verificación, por supuesto), y el transmisor no envía nada nuevo hasta que se recibe el ACK. Si no se recibe el ACK después de un tiempo de espera, el transmisor envía el último paquete nuevamente. Los protocolos más complicados permiten que el transmisor se adelante al receptor, por lo que generalmente hay un número de secuencia o similar codificado en cada paquete. Hay muchas maneras, y algunas de ellas son bastante elegantes. TCP, por ejemplo, hace esto con un flujo de bytes arbitrario.

 

Intentaría alguna forma de corrección de errores hacia adelante en cada comando. Si sabemos cuántos comandos distintos necesitamos, entonces podemos elegir un código existente (Hamming, Reed-Solomon, etc.) y usar la forma más redundante que aún quepa en un byte. Una ventaja es que existen algoritmos establecidos para ayudarlo a decodificar los bytes corruptos.

Tiendo a ir con LRC, ya que son estúpidamente fáciles de implementar. Esto no es una gran cantidad de datos (tal vez 5-10 bytes), y reenviar el paquete no es gran cosa. FEC es muy, muy exagerado en esta aplicación.
Seguro que es una exageración, pero FEC sigue siendo una forma conveniente de generar palabras de código máximamente diferentes, ya que esa es prácticamente la idea detrás de FEC.