Estoy programando un FPGA Altera usando Quartus II v9.0 para contar los pulsos del codificador y enviarlos a un programa externo de LabVIEW (vea el diagrama a continuación). Pude depurar un problema con mi código gracias a la comunidad de StackExchange , pero ahora tengo un descontrol intermitente en el recuento de mi codificador.
A medida que muevo mi codificador, mi código de LabVIEW muestra el conteo actual correctamente. Cuando dejo de mover el codificador, el conteo se detiene aproximadamente la mitad del tiempo y la otra mitad simplemente se desvanece. Sospecho que el codificador se está atascando en un estado intermedio y una de mis fases está aleteando. ¿Hay algún truco que pueda usar para filtrar esto, o un método mejor para contar los pulsos del codificador que pueda programar en mi Altera FPGA?
simular este circuito : esquema creado con CircuitLab
El bloque de 4 entradas XOR
se ejecuta como:
(IN1 xor IN2) xor (IN3 xor IN4)
Las señales Count enable
y Count direction
van a una función de contador integrada de 32 bits ( LPM_COUNTER
) en mi Altera FPGA programada con Quartus II v9.0. La salida de este contador se almacena en un búfer ( LPM_BUSTRI
) y se lee usando un programa de LabVIEW siempre que el código de LabVIEW lo necesite. Tengo un código de LabVIEW similar que lee otros búferes de la FPGA que funciona bien, por lo que estoy bastante seguro de que el problema radica en alguna parte de mi FPGA.
He intentado agregar un retardo de activación a las señales A
y B
que solo registra un cambio en la señal si esa señal se ha mantenido alta o baja durante una cierta cantidad de ciclos de reloj (probé 2 y 4 hasta ahora). Esto parecía empeorar el problema. También intenté agregar un cuarto juego de chanclas DQ, que no tuvo ningún efecto evidente.
¡Gracias por su ayuda!
Capture la entrada en lugar del contador para ver si el rebote es su problema. Si tiene alcance de almacenamiento, use el activador de borde para obtener la captura. De lo contrario, intente agregar rebote entre Reg1/Reg2 y entre Reg4/5.
Para implementar esto, use un registro de desplazamiento de 8 o 16 elementos alimentado desde A sincronizado. Tome el AND y el ~OR de entre todos los bits del registro de desplazamiento, estos le dan señales de "todo listo" y "todo despejado". Use esto como el ajuste y restablecimiento de un registro de salida, que alimentaría REG2. Lo mismo para B -> REG 5.
Si encuentra que esto todavía falla, puede probar con un reloj más bajo o extender el registro de desplazamiento. Por encima de las 16 etapas, probablemente sea mejor remodelarlo como un contador binario y un bit de último estado. En cada ciclo, si el estado es diferente al último, restablezca el contador y actualice el último estado. Si el contador se desborda sin borrarse, ese es su disparador para configurar/restablecer la salida.
Reg1
, Reg4
se utilizan como sincronizadores de cruce de reloj, ya que las entradas A
y B
son asíncronas con respecto a CLK1
. Se nota porque no hacen nada más que retrasar las señales en un ciclo. Dado que desea que el tiempo de configuración máximo disponible para la metaestabilidad se asiente entre las etapas del sincronizador, no desea ninguna lógica intermedia que agregue demora de enrutamiento. Además, si el sincronizador está logrando algo, desea que esa lógica use la señal limpia después del sincronizador.(Q & ~reset) | set
donde set = & shift_reg_bits;
y reset = ~ |shift_reg_bits;
. No conozco LabVIEW, eso es Verilog.Lo siento, habría respondido esto antes, pero estaba fuera de la ciudad con acceso limitado a Internet. Veo que Shuckc ya respondió esto, pero siento que tengo una solución que sería superior.
El problema con eliminar rebotes y/o filtrar A y B es que puede evitar que su decodificador funcione a la velocidad máxima (y, por lo tanto, perder cuentas), agrega complicaciones, aumenta el tamaño de la lógica y, lo más importante, no es necesario.
Comience manteniendo los seis registros que ya tiene en su esquema. Llamemos a la salida de Reg2 y Reg5 como A y B. La salida de Reg3 y Reg6 se llama A_prev y B_prev, que es básicamente el valor de A y B para el reloj anterior.
A continuación, crea una tabla de verdad más o menos así:
A_prev, B_prev, A, B, Count_En, Count_Dir
0 0 0 0 0 0
0 0 0 1 1 0
...etc...
Tendrás que llenar toda la tabla de verdad tú mismo, pero entiendes la idea. Básicamente, observa el estado actual de A y B, junto con los valores anteriores de A y B, y decide si desea aumentar o disminuir su contador. Ahora crea algo de lógica para implementar esta tabla de verdad. Te recomiendo que también registres la salida de esta tabla de verdad, antes de enviar las señales al contador.
Esta tabla de verdad encaja en un par de LUT de 4 entradas (el componente básico de la mayoría de los FPGA). Esencialmente, esto es súper pequeño. Registrar la salida de esta tabla de verdad también requiere esencialmente una lógica cero, ya que cada LUT en el FPGA tiene un Flip-flop en las salidas de los LUTS. Compare esto con hacer un poco de filtrado/eliminación de rebotes, lo que podría requerir 16 o 32 flip-flops y limita la utilidad de las LUT no utilizadas. Entonces, esta lógica es 1/16 o 1/32 del tamaño de la versión filtrada/rebotada.
Si está utilizando un FPGA más nuevo que tiene una LUT de 6 entradas que se puede dividir en 2 LUT más pequeñas, este diseño utiliza incluso menos recursos lógicos.
El registro de la salida permite que su lógica se ejecute a más de 100 MHz en la mayoría de los FPGA modernos, o hace que cumplir con sus limitaciones de tiempo sea mucho más fácil cuando se encuentra a velocidades de reloj más lentas. Si bien esto no parece importante, no cuesta nada y mejora en gran medida la solidez de este diseño y permite reutilizarlo más fácilmente en proyectos futuros donde su reloj principal es más rápido.
Lo bueno de este diseño es que A_in o B_in pueden cambiar literalmente en cada borde de su reloj de 25 MHz. Si tiene un poco de ruido o rebote en sus entradas, puede hacer que su contador "vibre" de un lado a otro entre dos señales adyacentes, pero esto también podría suceder con una versión filtrada/sin rebote.
La razón por la que este diseño no necesita filtrar/eliminar rebotes A y B es porque puede operar tan rápido como lo permita su reloj de 25 MHz. No puede confundirse con una entrada ruidosa o que cambia rápidamente, como podía hacerlo su diseño anterior.
Una de mis molestias favoritas es la decodificación en cuadratura mal implementada. Por lo general, es una mala implementación de software lo que hace que el decodificador pierda o salte pulsos, pero ocasionalmente una implementación de hardware también lo hará. No estoy diciendo que filtrar/eliminar el rebote de las entradas en cuadratura omitirá los pulsos, pero digo que este enfoque es mejor en todos los sentidos, incluida la velocidad máxima a la que puede aceptar pulsos.
carajo
jimmyb
Ingeniero
Shieldfoss
Ingeniero
usuario3624
Ingeniero