Implementación de compensación de retardo de propagación de línea para maestro BiSS en software

Continuando con una pregunta que hice hace algún tiempo: Implementación simple de la interfaz BiSS C para un codificador de posición . He implementado un maestro BiSS simple (punto a punto) para comunicarse con un codificador. A frecuencias inferiores a 2 MHz y longitudes de cable cortas, el software funciona perfectamente utilizando el módulo SPI en el microcontrolador PIC.

Sin embargo, probé alta velocidad (3 a 10 MHz) y un cable de 10 m, que debería funcionar. Me encontré con un problema de retraso de propagación. Parece que el protocolo necesita una implementación de compensación de retraso ciclo por ciclo.

Un fragmento de TI TIDU410 que muestra el problema

Probé un enfoque en el que dependo de la secuencia de inicio (ACK y bit de inicio) y cambio el resultado en 1 o 2 o 3 bits dependiendo de cuántos relojes se retrasó el bit de inicio. Pero no funciona todo el tiempo, el problema parece ser que los datos pueden cambiar en cualquier fracción del reloj (por ejemplo: 1/8, 1/4, 1, 1.5), por lo que MISO no está decodificando a la derecha. tiempo todo el tiempo.

¿Alguien tiene ideas sobre la forma correcta de implementar dicha función en el microcontrolador? (Puedo agregar un par de componentes discretos y puertas lógicas si es necesario) pero no un FPGA.

*EDITAR (Captura de pantalla del osciloscopio) usando funciones SPI estándar *ingrese la descripción de la imagen aquí

Captura de pantalla del osciloscopio al colocar datos directamente en el búfer SPI sin esperar ni ninguna función en absolutoingrese la descripción de la imagen aquí

Captura de pantalla cuando se usa el modo Buffered, 2 spi escribe. Tenga en cuenta que la señal está limpia, pero la sonda del osciloscopio y el pin de tierra no estaban inactivos al tomar la foto.ingrese la descripción de la imagen aquí

¿Cuál es tu velocidad de reloj mcu?
@BeB00, estoy corriendo a 60MIPS, 16.67ns es el tiempo de instrucción (en caso de que se esté preguntando sobre el golpe de bits)
bueno, no puede cambiar la forma en que funciona el periférico SPI, por lo que golpear bits es prácticamente lo único que puede hacer a menos que desee obtener un chip externo. Para 10 MHz, 80 MIPS serían más cómodos, pero 60 podrían funcionar
@BeB00, ¿hay alguna forma mejorada de golpear bits, mejor que la lectura de puertos y la escritura LAT, para mejorar la inmunidad al ruido/fallas (algo así como supermuestreo o lecturas múltiples del mismo bit?
Que yo sepa, en general no. No hay periféricos especiales para leer/escribir pines en un microcontrolador pic típico.
¿Qué procesador PIC usas?
@Dorian, DSPIC33EP (serie MU) actualmente para este proyecto, otros PIC tengo acceso a PIC32MK y PIC32MZ
Ya veo, ¿qué velocidad se usa en el gráfico?
¿Puede publicar el código utilizado para leer el SPI activo para este gráfico?
@ElectronS, ¿realmente se da cuenta de cuál es la limitación con un esclavo que responde al maestro a altas velocidades y con longitudes de línea significativas?
@Andyaka, sí, me doy cuenta, pero este Protocolo funciona a esta velocidad y con esta longitud con seguridad (con compensación de retraso de línea). TI tiene una placa de desarrollo para esto (www.ti.com/lit/ug/tidu794a/tidu794a.pdf), pero usan un módulo integrado en su microcontrolador (un módulo SPI ligeramente modificado) con todas estas funciones incluidas, pero No puedo permitirme este procesador de gama alta, ni el ASIC personalizado de la empresa IC-haus. y quiero explorar las limitaciones de mi hardware y software. perdon por la extensión del comentario :)
¿Puede implementar maestro a esclavo? Entonces, para la respuesta del esclavo, intercambie roles para que el maestro original tome el reloj del nuevo maestro (el antiguo esclavo). ¿Hay suficiente inteligencia en el extremo esclavo para implementar esto?
Uh, no sé si Andy quiso decir esto, pero la respuesta me golpeó como una tormenta. Use SPI en modo esclavo y use un pin diferente (usando la comparación de salida o algo así) para generar la señal de reloj para el esclavo PIC y BISS. De esa manera, la señal del reloj será constante y sin interrupciones. Si de alguna manera bloquea el reloj que va al PIC, puede compensar el retraso como se indica en el protocolo BISS
@Dorian, buena idea, tiene sentido. solo la última parte sobre la activación del reloj no la entiendo. y, por cierto, estoy usando un oscilador de reloj de 10 mhz para OSCIN Pin (use PLL para hacer 120 mhz para obtener los 60 MIPS)
Para comenzar más tarde que el reloj BISS.
No use pines OSCIN u OSCOUT, puede estropear el reloj de su sistema, vea la respuesta actualizada.

Respuestas (1)

Supongo que el retraso es de alguna manera constante o con un pequeño jitter y la señal llega a SPI en buena forma.

Actualizado después de las observaciones de OP de que la comunicación SPI no es consecutiva como supuse, por lo que se pierden algunos bits entre fotogramas.

Actualice después de la sugerencia de Andy, la solución correcta es usar el sensor BISS y PIC SPI en modo esclavo y generar dos relojes, ya sea externamente controlados por una salida PIC o internamente usando la comparación de salida del temporizador, o de otra manera

Con ambos relojes inactivos en "1", inicie DMA para recibir SPI, inicie el reloj de la interfaz BISS, agrupe el bit ACK y luego inicie el reloj PIC SPI. El muestreo en el medio asegurará suficiente margen de riesgo. Los datos se alinearán en palabras, no es necesario cambiarlos. El segundo DMA para transmisión ficticia ya no es necesario.

Puede encontrar en el documento de Microchip sobre el módulo de comparación de salida, página 9, cómo usar el módulo de comparación de salida para generar un reloj a partir de un nivel alto. La velocidad puede ser de hasta 1/8 del reloj del sistema.

Dependiendo de las capacidades de PIC, podría ser posible que el pin del reloj SPI (entrada porque usamos SPI en modo esclavo) se controle mediante el uso de PPS sin usar otro pin y una conexión cableada externa.

En este caso, usando el cambio de software como se muestra a continuación, la placa se puede usar sin ninguna modificación de hardware.

Usando la solución de OP para cambiar los datos retrasados:

Para obtener lecturas confiables, lo primero que debe hacer es cambiar el bit SMPx de la fase de muestra de entrada de datos para muestrear los datos al final en lugar del medio como supongo que es. O en el medio si es al final ahora

ingrese la descripción de la imagen aquí

(La imagen tiene un error, el primer borde de la "muestra al final" no es un borde de lectura activo).

Sería mejor saber por software qué borde de muestra es mejor usar.

La descripción se hace para datos de cambio de esclavo SPI en el primer flanco descendente, para la interfaz BISS que cambia ACK en el segundo flanco ascendente, puede hacer las correcciones necesarias agregando 0.5 Tckh o 1.5 Tckh al retraso.

Ponga su reloj SPI en el valor utilizable más alto Ckh (período Tckh), cuente los bits hasta que llegue ACK, cambie el bit de fase de muestra de entrada de datos SMPx, envíe otro mensaje y cuente los bits nuevamente.

Eso le dará una aproximación de medio período de reloj de la demora. Úselo para elegir el punto de muestreo para el reloj que realmente usa Ck (período Tck). Si la velocidad que usas es como mucho la mitad entonces es suficiente.

Si las lecturas tienen el mismo número de "1" hasta ACK, entonces el retraso es entre (N_ones) x Tckh y (N_ones + 1/2) x Tckk

Si la lectura final tiene un "1" más que el retardo está entre (N_unos + 1/2) x Tck y N_unos+1 x Tck

Volvamos al reloj que realmente usará. Si un multiplicador del período de reloj Tck toca el área de retardo, use la muestra en el medio, si no, use la muestra al final. Si usó Ckh más del doble, entonces use el tiempo de muestreo más alejado del área de retardo.

Actualice, corrigió la representación invertida de la señal en el texto y agregue algún gráfico para una mejor comprensión

Mismo número de uno usando reloj rápido, retraso entre 5 y 5.5 Tckh:

ingrese la descripción de la imagen aquí

El muestreo en el medio usando un reloj rápido lee un "1" adicional. Retardo entre 5,5 y 6 Tckh. ( 6 "1" para muestrear en el medio, no 5 como está en la imagen )

ingrese la descripción de la imagen aquí

Usando el reloj SPI, use el borde de muestreo más alejado del área de retardo. ingrese la descripción de la imagen aquí

Los diagramas se realizaron utilizando el editor en línea WaveDorm

con respecto a la primera oración, la señal llega a SPI en muy buena forma (lo confirmo con Oscillscope con cable GND corto). el Delay debe ser constante para una configuración específica (velocidad y duración).
lo que presentó es brillante, dado que actualmente estoy muestreando en el borde descendente, intentaré cambiar eso a la velocidad en la que no funciona y veré los resultados, en ese caso, haré una especie de función de calibración que elegirá el polaridad de muestreo basada en algunos ciclos de lectura. Volveré cuando pueda confirmar el resultado, gracias :)
Después de una hora de prueba, la solución que propusiste funcionó parcialmente (algunos bits aún están erróneos), luego de esos errores encontré el problema, está en la pausa entre palabras enviadas. Dado que estoy usando arquitectura de 16 bits y uso SPI en modo de 16 bits (palabra, no byte) y estoy enviando/recibiendo 2 palabras, hay una pausa de aproximadamente 3 relojes entre las 2 palabras. Este retraso está causando un problema con el algoritmo de compensación de retraso, AHORA parece que tengo que averiguar si puedo eliminar este retraso o tengo que usar PIC32 (spi de 32 bits), ¿tienes alguna idea?
He añadido una captura de pantalla a la pregunta...
Me di cuenta de que creo que todos asumimos que los bytes se envían de forma consecutiva ya que hablabas de cambiar bytes. Es por eso que estaba preguntando sobre el código, para ver si se puede mejorar para la comunicación consecutiva.
@ElectronS, ¿el uso de SPI almacenado en búfer (mejorado) aún mantiene la ruptura entre bytes?
Lamentablemente, DSPIC33/PIC24 no es compatible con el modo de búfer mejorado, FRM (SPI), página 6, nota 1
Supongo que es porque es compatible con DMA, probaré DMA ahora, espero que elimine la demora entre PALABRAS enviadas
@ElectronS podría no funcionar con DMA porque veo que usa la transferencia SPI realizada y supongo que está relacionado con los datos SPI listos que tienen un retraso de medio reloj. Es posible que deba escribir dos palabras en el búfer de TX antes de iniciar el DMA de TX para tener el búfer siempre lleno
tiene razón, no lo hizo, la próxima prueba será en PIC32, solo para probar el concepto. en todos los casos, muchas gracias por la respuesta bien escrita y mejorada :) te mereces más que una recompensa tonta, lo mantengo abierto solo para permitir que otros contribuyan (solo 95 vistas de la pregunta hasta ahora)
por cierto, ¿cómo dibujaste estos diagramas de reloj?
Hay una herramienta en línea, no la tenga a mano ahora. Tienes razón, debería poner una referencia al menos. Hay más cosas que puedes probar, pero ahora estoy un poco ocupado, volveré más tarde.
@ElectronS No use funciones SPI, simplemente escriba el registro SPI TX dos veces y vea qué sucede. ¿Todavía tienes el descanso?
bravo de nuevo, escrito 2 veces seguidas, no envía otra palabra, ya que todavía está enviando, pero cuando escribo a spi tx 5 veces seguidas (SPI1BUF = 0xFFFF), ¡funcionó! el retraso se reduce de 750ns a 300ns aproximadamente (ver la nueva captura de pantalla). pero no se eliminó por completo
Además, la escritura constante en SP1BUF hace que la lectura de los datos entrantes sea imposible (ya que es el mismo registro), mi función original hizo lo siguiente: SP1BUF = dummy, while (!SPI1STATbits.SPIRBF), temp1 = SPI1BUF. luego repita esas 3 líneas, después de eso temp3 = temp1<<16 + temp2.
Todavía algo no está bien, no creo que tenga que ver algo el tiempo de escribir 5, más bien el tiempo. El quinto fue en mejor momento. Al escribir dos palabras, se deben enviar dos palabras, ya que una va a la derecha en el registro de desplazamiento y la otra se almacena en el búfer. Tengo un PIC24FJ disponible, tiene la misma unidad SPI, haré una prueba el lunes. Su pregunta también es muy desafiante y está en mi área de interés.
tenías razón, tenía el búfer deshabilitado, ahora cuando lo habilito, 2 veces escribir en SPI1BUF funciona, el retraso ahora es de 150 ns aproximadamente 1 ciclo (creo que esto es intencional), agregué otra foto, mostrando un problema potencial, ya que 1 bit de datos está en la zona donde no está presente el borde del reloj, por lo tanto, no se decodificará
@ElectronS Intente cambiar el modo de reloj a. ¿Quizás algunos modos no tienen el retraso?
Pasé 7 horas hoy trabajando con el método brillante que propusieron después de la sugerencia de Andy, sin embargo, no tuve éxito. Generé un reloj de 10Mhz (usando la comparación de salida) y lo conecté al reloj SPI y puse el módulo SPI en Esclavo, sin embargo, no importa cuánto lo intenté, solo recibo la primera palabra. Parece que el módulo necesita la pausa (o una pequeña pausa entre las palabras enviadas). Lo verifiqué usando el modo de búfer y verificando el registro de estado de SPI. No sé si publicar un fragmento del código ayudaría. Gracias de todos modos por el esfuerzo.
@ElectronS Me probaré mañana. ¿Has probado a usar el modo de 8 bits?
no, no probé el modo de 8 bits, continuaré probando, el problema es que esta es la primera vez que uso el modo esclavo y faltan algunos detalles importantes del FRM. como (debe cargar datos ficticios para enviar, como cuando usa el modo Maestro) ... sí, pruébelo usted mismo y dígame qué sucede
@ElectronS Creo que me equivoqué, tal vez no alimentar el registro SPI TX genera un error que impide más lecturas. Intente primero alimentar dos palabras y luego agrupe la transferencia SPI completa para más escrituras. 100% no se necesita un descanso entre palabras, después de todo es un esclavo.
¡Finalmente, estoy feliz de anunciar que funcionó! a toda velocidad, el problema del esclavo SPI era (como he leído en el foro de Microchip) podría atascarse y funcionar de manera poco confiable si recibe un reloj con el SPIbuffer (en modo mejorado) vacío, estaba poniendo caracteres en el búfer, pero no después inicialización Entonces agregando SPI1BUF= 0x Dummy , después de OpenSPI(function) . lo hizo funcionar :)
Otro problema que podría enfrentar y que yo tengo, es que si genera más relojes de los requeridos, digamos 40, los datos recibidos serán incorrectos (2 palabras correctas y 1 media palabra), la próxima vez que lleguen los datos serán afines a los vieja media palabra de basura. Entonces, después de cada operación, reinicio el SPI, para vaciar el búfer RX FIFO del exceso de datos.
@ElectronS ¡Buenas noticias! Así que mi conjetura matutina fue buena. Estaba luchando con eso en este momento. Puede poner sus hallazgos en su pregunta para otros que puedan necesitar. No el código fuente, pero al menos alguna guía.
Sabía que el esclavo SPI debe tener datos en SPIbuf, y lo estaba haciendo antes de generar el reloj (comparación de salida) en la función de lectura BISS. sin embargo, la primera vez que se genera el reloj (en OC inicializar) en ese momento hay caracteres en el búfer, es por eso que no entendí el punto, por lo que fue realmente complicado conocer el problema. Publicaré una respuesta que contenga los consejos y trucos si eso ayuda. pero realmente gracias por la paciencia y la buena ayuda que necesitaba para interactuar y desafiarme a mí mismo con otro compañero ingeniero, no podría haberlo hecho sin USTED :))
En cualquier momento, fue algo que aprender para mí.