Skip to content

CT.11: Señales del sistema. Medición con el LEDOscopio

Juan Gonzalez-Gomez edited this page May 18, 2024 · 358 revisions

Descripción

Estudiaremos los fundamentos de las señales del sistema: las que funcionan con el reloj del sistema y que son muy rápidas. Aprenderemos a generarlas, retrasarlas, combinarlas mediante las operaciones básicas y a visualizarlas en los LEDs con el LEDOscopio. Los conceptos mostrados serán de gran ayuda para comprender los cuadernos técnicos más avanzados

Historial

  • 2022-Julio-24: Version inicial del cuaderno técnico
  • 2024-Mayo-18: Ejemplos adaptados a la nueva toolchain: apio-0.9.4. Eliminado el error en la verificación. Probados con icestudio 0.12. Los pantallazos de los ejemplos no se han actualizado todavía

Icestudio

Todos los ejemplos se han probado con Icestudio 0.12. Usa esta versión o superior

Colecciones

  • CT11: Colección con TODOS los ejemplos de este cuaderno técnico
  • iceSignals: Colección para este cuaderno técnica. Descargar e instalar. Usa esta versión o superior
  • LEDOscopio: Bloques para medir las señales del sistema

Ejemplos

Todos los ejemplos de este cuaderno técnico están accesibles desde el menú Archivo/Ejemplos/CT11 de Icestudio, una vez instalada y selecciona la colección CT11

Contenido

Introducción

Las señales del sistema son aquellas que tienen frecuencias cercanas a la del reloj del sistema y que usamos para gobernar a otros circuitos. La unidad del tiempo es el ciclo. Son señales muy rápidas, y por tanto difíciles de visualizar y depurar

Hay una señal del sistema que hemos usado muchísimo: el tic. Es el pulso mínimo, que tiene una anchura de 1 ciclo. Lo usamos para representar un evento, como por ejemplo la pulsación de un botón, la llegada de un byte por el puerto serie, la orden de escritura en una memoria...

En esta figura vemos el estado de dos señales durante 5 ciclos de reloj, desde el ciclo i hasta el ciclo i+4. La señal 1 es un pulso que dura 2 ciclos, mientras que la señal 2 dura 1 ciclo (es por tanto un tic)

No podemos medir nada menor a un ciclo (es nuestra resolución temporal). Trabajar en ciclos tiene la ventaja de que nos da igual la velocidad real. Por ejemplo, el circuito para generar un pulso de una anchura determinada (en ciclos) será el mismo para cualquier placa, con independencia de la frecuencia de su reloj (12Mhz, 16Mhz, 50Mhz, 100Mhz...)

En el caso de la placa Alhambra II, el reloj es de 12Mhz, por lo que cada ciclo dura 1/12Mhz = 83.3ns

Arranque del circuito: Ciclo 0

Todo empieza en el ciclo 0. Una vez que la FPGA se ha configurado, arranca el ciclo 0 y nuestro circuito empieza a funcionar. Los biestables tendrán sus valores de inicialización listos a partir de este ciclo

En esta figura vemos lo que ocurre con dos señales en los primeros cuatro ciclos de reloj. Las señales están inicializadas desde el ciclo 0, y van cambiando sus valores. El primer flanco de subida llega al finalizar el ciclo 0 y comenzar el 1

La señal superior es una señal para inicializar circuitos (señal de reset). En el ciclo 0 está activa (1) y luego se pone a 0 en el resto de ciclos

La señal inferior emite un tic en el ciclo 2 para arrancar otro circuito

En este Cuaderno técnico aprenderemos a generar señales como estas, que se usan para inicializar y arrancar otros circuitos. La clave para trabajar con señales del sistema desde el ciclo 0 es medirlas y visualizarlas

LEDOscopio

Las FPGAs nos permiten diseñar cualquier circuito digital. Dado que el hardware funciona en paralelo, podemos crear circuitos para realizar mediciones y añadirlos a nuestros diseños. El LEDOscopio es un analizador lógico extremadamente simple, que nos permite observar unos pocos ciclos de una señal en los LEDs

Se encuentra en la colección iceLedoscope. Y hay de varios tipos

Empezaremos por el LEDOscopio más simple: Uno que muestra los primeros 4 ciclos de la señal, en 4 LEDs

Vamos a hacer un experimento para aprender a usar el LEDOscopio. En esta imagen se muestran las dos señales (de mayor y menos peso) de un contador de 2 bits que se incrementa en cada ciclo de reloj (un contador del sistema de 2 bits)

En este circuito de ejemplo se ha conectado el bit de menor peso (bit 0) del contador a un LEDOscopio de 4-bits. Al cargarlo en la placa vemos en los LEDs del 0 al 3 el estado en los ciclos del 0 al 3

(01-contador-LEDoscopio.ice)

Un LED endendido se corresponde con la señal a 1 en ese ciclo, y un LED apagado es la señal a 0

Observamos que hay una correspondencia 1-1 entre los LEDs y los ciclos de la señal. ¡Vemos la señal!

Esta es la maravilla del LEDOscopio, que nos permite observar señales MUY RÁPIDAS (La señal es de 6 MHz), sin necesidad de utilizar equipos externos. Es una herramienta tremendamente útil para comprobar el funcionamiento de muchos de nuestros circuitos, y garantizar su funcionamiento

Y además nos permite ver lo que ocurre desde el ciclo 0, justo al arrancar nuestros circuitos

Start: Señales de arranque

Comenzamos con el estudio de diferentes señales básico, y cómo las podemos generar utilizando componentes fundamentales

Introducción

Las señales más básicas que podemos generar son las constantes: 0 y 1. Son señales que toman un valor inicial (0 ó 1) y lo mantienen durante toda la vida del circuito. Son señales que No cambian

Por ejemplo, en esta gráfica se muestran las señales a y b, que tienen los valores constantes 1 y 0 respectivamente

En el dibujo sólo se muestran sus valores durante los 4 primeros ciclos, pero permanecen con esos valores durante todo el tiempo, hasta que se quite la alimentación del circuito

Estas señales se generan con los bloques constantes 0 y 1. Podemos utilizar dos LEDoscopios de 4 bits para comprobar sus valores en los 4 primeros ciclos de reloj. Este es el circuito de pruebas:

(02-senales-constantes.ice)

Al cargar el circuito y probarlo en la Alhambra II observamos cómo los LEDs 0-3 se encienden (señal a) y los LEDs 4-7 están apagados (señal b)

Construyendo la señal de start

La señal no constante más básica que se puede generar la denominamos señal de start. Tiene una pinta como la mostrada en esta gráfica. Está a nivel 1 durante el primero ciclo de reloj, y el resto del tiempo está a 0 (hasta que el circuito se apague)

Se denomina señal de start porque nos sirve para inicializar o arrancar otros circuitos. Es una señal muy básico pero MUY IMPORTANTE

¿Cómo podemos generar una señal así?. Utilizando los elementos fundamentales de los circuitos digitales: un biestable D y un bit constante. Los biestables D tienen la propiedad de mantener el valor durante un ciclo de reloj y luego captura el nuevo valor que llegue por su entrada. Esta operación la repiten en cada ciclo de reloj del sistema

(03-start-generation.ice)

Cargamos el circuito en la placa. Vemos la señal de start en los LEDs. El LED 0 está encendido y los LEDS 1-3 apagados. Esto significa que hay un tic activo en el ciclo 0, y luego se pone a 0 en el resto de ciclos: es justo una señal de start

El bloque Start

Esta señal de start la podemos usar directamente a partir del bloque start: Genera un tic inicial en el primer ciclo reloj, y luego permanece a 0

Su implementación es como ya la conocemos:

Retrasando señales

Una operación básica que hacemos con las señales es retrasarlas: se obtiene la misma señal, con su misma forma, pero que empieza un ciclo más tarde

La operación de traso se implementa con los Biestables D. Cada Biestable D retrasa la señal un ciclo. De hecho, se llaman biestables D por esta propiedad: D es de Delay (Retraso)

En esta figura se muestran dos señales de start. La primera comienza en el ciclo 0 (Señal a), y la segunda (señal b) se ha retrasado un ciclo

La señal a se obtiene directamente del bloque start. Su salida se introduce por el Biestable D obteniéndose la señal b, que se lee a través del LEDOscopio para ver su forma

(04-start-delay-1.ice)

En este dibujo vemos la salida del LEDOscopio, y cómo la señal b tiene la forma esperada: Es la señal de start retrasada un ciclo, por eso sólo se enciende el LED1 (Ciclo 1)

Si queremos realizar retrasos mayores, basta con conectar en serie los biestables D. Una cadena de N biestables en serie provoca un retraso de N ciclos. En este dibujo se muestran dos biestables D encadenados, que provocan un retraso de 2 ciclos

En este diagrama vemos las señales a, b y c. La primera es una señal de start. La segunda está retrasada 1 ciclo, y la tercera 2 ciclos

Para comprobarlo usamos este circuito de ejemplo. La señal c está conectada al LEDOscopio para observar el retraso

(05-start-delay-2.ice)

En esta figura se muestra el resultado. Ahora sólo se enciende el LED 2 (Ciclo 2)

Generando una señal patrón

La conexión en serie de Biestables D nos permite establecer los valores que se quiere tener en cada ciclo, y así podemos generar cualquier patrón. En esta figura se muestra una señal con el patrón 0101. La señal toma un valor diferente en cada ciclo. A partir del quinto ciclo su valor se fija a 0. En esta tabla se muestra el patrón a generar:

Ciclo: Ciclo 0 Ciclo 1 Ciclo 2 Ciclo 3 Ciclos > 3
Valor: 0 1 0 1 0

Para su generación usamos 4 biestables D conectados en Serie. El situado más a la derecha es el que contiene el bit mostrado en el ciclo 0. El biestable conectado a su izquierda contiene el bit que se mostrará en el ciclo 1 (con un ciclo de retraso). El de su izquierda el bit que saldrá en el ciclo 2 (dos ciclos de retraso)... y así sucesivamente

(06-pattern-generation-1.ice)

La señal s se visualiza con el LEDOscopio. Se comprueba que efectivamente aparece el patrón 0101 en los LEDs

Operaciones con señales

Otra manera de construir señales es partir de señales básicas y aplicar operaciones entre ellas: Inversiones (NOT), uniones (OR), intersecciones (AND) y diferencias (XOR)

La operación de "diferencia" es una XOR que en realidad no es la típica operación de diferencia (a - b), sino que muestra los ciclos que son diferentes entre las dos señales. Lo que está a 0 significa que es igual en ambas señales

En las siguientes secciones veremos ejemplos de todas estas operaciones, mostrándolas en un LEDOscopio de 8 LEDs

Inversión (NOT)

La operación de inversión es unaria, y se realiza con la puerta lógica NOT. En este ejemplo se invierne una señal de start y se muestra en un LEDosciloscopio de 8 LEDs

(07-not-operation.ice)

Este es el resultado. Los LEDs del 1 al 7 están endendidos. El LED0 está apagado

Unión (OR)

La operación de unión se realiza con dos señales y la puerta OR. Como ejemplo vamos a generar un pulso de 2 ciclos de anchura que se pone a uno en el ciclo 1

Esta señal se podría generar perfectamente como un patrón (Como vimos en el apartado anterior), colocando tres biestables D en serie inicializados con los valores 0, 1, 1 y conectando un 0 en la entrada del de la izquierda. Pero en este ejemplo lo vamos a generar utilizando la operación de Unión y retrasos

Las operaciones concretas para generar esta señal se muestran en este dibujo

Partimos de una señal de arranque, que llamamos a. La retrasamos un ciclo para generar la señal b. Esto de representamos con la operación b=r(a), donde r() es una función que retrasa un ciclo. Ahora obtenemos la suma de las dos funciones: a+b para combinarlas. Y finalmente la retrasamos un ciclo para obtener la función s.

De manera algebraica, la expresión de la señal s en función de a es la siguiente:

s = r(a + r(a))

Este es el circuito para generar la señal s a partir de las operaciones anteriores

(08-or-operation.ice)

Al cargarlo en la placa vemos la señal s en el LEDoscopio de 8 LEDs. Efectivamente, sólo los LEDs 1 y 2 están encendidos

Intersección (AND)

La operación de intersección se realiza con dos señales y la puerta AND. Como ejemplo vamos a realizar la intersección de un pulso inicial de 2 ciclos con el mismo pulso pero retrasado un ciclo. Las operaciones y señales intermedias se muestran en esta figura:

Partimos de una seña inicial (a), que es un pulso de 2 ciclos de anchura. En este caso lo generamos como señal patrón, utilizando 2 biestables en serie. Pero en vez de utilizarlos de manera discreta, se ha usado un Registro de desplazamiento a la derecha, que en su interior contiene estos dos biestables en serie

Utilizando un biestable del sistema (Sys-DFF) retrasamos este pulso para obtener la señal b, que es r(a)

Ahora realizamos la intersección de ambas señales, a y b, por lo que obtenemos la señal final: s = a.b = a.r(a)

El circuito de ejemplo que realiza esta operación es el siguiente:

(09-and-operation.ice)

Al cargarlo en la placa vemos la señal s en el LEDoscopio de 8 LEDs. Sólo el LEDs 1 está encendido

Diferencia (XOR)

La operación de diferencia (XOR) se realiza con dos señales y la puerta XOR. Como ejemplo vamos a realizar la operación XOR entre las mismas señales de apartado anterior: un pulso inicial de 2 ciclos con el mismo pulso pero retrasado un ciclo. Las operaciones y señales intermedias se muestran en esta figura:

Partimos de una seña inicial (a), que es un pulso de 2 ciclos de anchura. En este caso lo generamos como señal patrón, utilizando 2 biestables en serie. Pero en vez de utilizarlos de manera discreta, se ha usado un Registro de desplazamiento a la derecha, que en su interior contiene estos dos biestables en serie

Utilizando un biestable del sistema (Sys-DFF) retrasamos este pulso para obtener la señal b, que es r(a)

Ahora realizamos la operación XOR entre ambas señales, a y b, por lo que obtenemos la señal final: s = a xor b = a xor r(a)

El circuito de ejemplo que realiza esta operación es el siguiente:

(10-xor-operation.ice)

Al cargarlo en la placa vemos la señal s en el LEDoscopio de 8 LEDs. Sólo los LEDs 0 y 2 está encendidos

Bloque Sys-Delay: Retrasando una señal N ciclos

Hay una operación fundamental: Retrasar una señal un número determinado de ciclos (N). Ya sabemos cómo hacerlo: basta con colocar N biestables D del sistema encadenados. Así, si queremos retrasar una señal 32 ciclos, hay que encadenar 32 biestables D. O lo que es equivalente, un registro de desplazamiento de 32 bits

Sin embargo, en muchas aplicaciones la señal a retrasar es un tic, y no una señal con una forma más compleja. En estos casos se puede implementar de manera más compacta, gastando menos recursos. Es el bloque Sys-Delay. Existen diferentes variaciones de este bloque:

Los bloques más óptimos son los que implementan un retraso fijo, que es potencia de dos: 2, 4, 8, 16, 32... Luego están los que implementan un retraso variable, a los que se les pasa la cantidad de ciclos a retrasar por su entrada N. O bien este valor N también se puede pasar como parámetro. Los circuitos de retraso variables son más complejos y consumen más recursos

Señales de Interfaz

Todos los bloques de retraso tienen una interfaz común, que no sólo es propia de ellos sino que la tienen todos los circuitos que llamamos Máquinas simples (y que analizaremos en otros cuadernos técnicos). Estas señales son:

  • Señales de entrada:

    • start: Es el tic (pulso de 1-ciclo) que arranca el circuito. Por aquí se introduce el pulso que queremos retrasar
  • Señales de salida:

    • busy: Señal de ocupado. Indica si el bloque de retraso está funcionando, o está inactivo
    • done: Señal de terminado. Es el pulso de salida (tic) que se genera cuando se ha cumplido el retraso indicado
    • n: Ciclo actual. Según el bloque de delay, empieza en el ciclo 0 y termina en N-1, o bien empieza en el 1 y termina en el N, donde N es el número de ciclos a retrasar. Es una señal auxiliar que se permite a otros circuitos conocer el tiempo actual en ciclos, y realizar las operaciones necesarias

En esta figura se muestran las señales de interfaz del bloque ejemplo Sys-Delay-x08, que sirve para retrasar 8 ciclos el tic de entrada. Pero son las mismas para el resto de bloques Sys-Delay

En este cronograma se muestra un ejemplo de las señales de interfaz, para un temporiador genéricos que retrasa N ciclos el pulso de entrada

La señal n, que indica el ciclo actual, NO SE HA DIBUJADO, porque su semántica depende del tipo de bloque. En algunos empieza contando desde 0, pero en otros desde 1

Sys-delay de retardo fijo

Estos bloques de retardo son los más optimizados. Nos permiten realizar un retraso cuyo valor es una potencia de 2: 2, 4, 8, 16, 32... Los valores de la señal n de salida, que indica el ciclo actual van desde 0 hasta N-1, donde N es la potencia de dos. Así, para un bloque de 4 ciclos de retraso, los valores de n serán 0,1,2 y 3

En esta figura se muestran algunos de estos bloques de retardo fijo

Vamos a Analizar algunos de ellos, para entender su funcionamiento

Sys-delay-x01: Retardo de 1 ciclo

El retardo de un ciclo se puede hacer con un biestable D del sistema, sin embargo el bloque Sys-delay-x01 tiene las señales de interfaz estándar y permite intercambiar unos bloques de delay por otros, sin tener que recablear

El cronograma se muestra en esta figura:

Las señales busy, done y n, todas de un bit, son iguales

En este ejemplo se realiza la medición con el LEDOscopio, de la señal done

(11-sys-delay-x01.ice)

Este es el resultado al analizarlo con el LEDoscopio:

Las etiquetas n y busy están disponibles para medirlas también con el LEDOscopio. Como son iguales a done, no haremos la medición (se deja como un ejercicio para el lector)

Implementación

La implementación de este bloque es muy sencilla. Se usa un biestable D del sistema (Sys-DFF) cuya salida se usa como salida done, busy y n

Sys-delay-x02: Retardo de 2 ciclos

El retraso de 2 ciclos se realiza muy fácilmente colocando 2 biestables D del sistema en serie, o bien un registro de desplazamiento de 2 bits. Sin embargo, en el bloque Sys-Delay-x02 se implementa una solución general que consume menos recursos, aunque sólo sirve para retrasar señales de tipo tic. En la parte de implementación analizaremos todas las posibilidades de implementación

El cronograma se muestra en esta figura:

La señal done está retrasada 2 ciclos con respecto a start, según lo esperado. Ahora la señal de busy es diferente: es un pulso de 2 ciclos de anchura, ya que el componente tarda 2 ciclos en terminar. La señal n es de un bit, y coincide con done. Indica el ciclo de espera en el que se encuentra, comenzando por 0. Los dos ciclos de espera son n=0 y n=1

Ejemplo 12: Midiendo el bloque Sys-delay-x02

En este ejemplo se retrasa un tic inicial dos ciclos. Se está midiendo la señal done, pero están las etiquetas busy y n disponibles para conectar al LEDOscopio para realizar su medición

(12-sys-delay-x02.ice)

En este dibujo se muestran los resultados de las mediciones de las señales de busy y done

Implementación 1

Realizaremos diferentes implementaciones, para comprender el funcionamiento, conocer los recursos empleados y entender mejor la solución definitiva

La primera implementación es la más sencilla. Se usa un registro de desplazamiento de dos bits para retrasar un tic inicial 2 ciclos. Sólo tiene la señal de salida (done), que se mide con el LEDOscopio

(13-sys-delay-x02-impl-1.ice)

Esta implementación (medida sin el LEDOscopio) consume 5 bloques lógicos

Recurso Cantidad
LC 5

La ventaja de esta implementación es que sirve para retrasar cualquier señal, y no sólo los tics

Implementación 2

Queremos que el bloque sys-delay disponga de las salidas de busy y n. La implementación se logra añadiendo un biestable RS que arranca con start y que se resetea al final, transcurridos los dos ciclos. Esto lo hacemos con la señal de salida del registro de desplazamiento

(14-sys-delay-x02-impl-2.ice)

Cuando llega la señal start, por un lado entra en el registro de desplazamiento para generar el retraso de los 2 ciclos, y por otro activa el Biestable RS para indicar que el circuito está ocpado funcionando. La señal de salida done se lleva al reset del biestable para desactivarlo, y que busy se ponga a cero

Esta implementación consume un poco más que la anterior: 6 bloques lógicos

Recurso Cantidad
LC 6

Implementación 3

La implementación 2 es muy fácil de entender, pero no escala bien. Si ahora queremos, por ejemplo, hacer un retraso de 32 ciclos, habría que usar un registro de desplazamiento de 32 bits (32 biestables). Utilizando un contador conseguimos el mismo resultado pero consumiendo menos biestables

Para realizar el delay de 2 ciclos usamos un contador de 1 bit, que se implementa con un biestable T:

(15-sys-delay-x02-impl-3.ice)

La señal de start activa el Biestable RS para indicar que el circuito está funcionando. Cuando el biestable está activo, el contador tiene un '1' en su entrada de cuenta, y en cada ciclo de reloj del sistema se incrementa. Como el retraso es de sólo 2 bits, cuando se incrementa el contador pasa de 0 a 1, y se desactiva el Biestable RS

Esta es una solución que escala muy bien, y consume poco registros: 5 bloques lógicos (lo mismo que la implemantación 1)

Recurso Cantidad
LC 5

Aunque sólo sirve para retrasar el tic de entrada (y no una señal genérica)

Sys-delay-x04: Retardo de 4 ciclos

El bloque Sys-delay-x04 retarda 4 ciclos de reloj el tic recibido por su entrada

El cronograma de su funcionamiento se muestra en esta figura:

Ejemplo 16: Midiendo el bloque Sys-delay-x04

En este ejemplo se retrasa un tic inicial cuatro ciclos. Se está midiendo la señal done, pero está la etiquetas busy disponible para conectar al LEDOscopio para realizar su medición

(16-sys-delay-x04.ice)

En este dibujo se muestran los resultados de las mediciones de las señales de busy y done

Implementación_

Este bloque ya está implementado de la forma final: Un biestable RS para almacenar el estado del circuito (ON/OFF) y un contador de 2-bits para llevar la cuenta de los 4 ciclos. La salida max del contador, que se pone a uno cuando el contador alcanza el valor máximo (3), se usa como señal done. Esta señal es la que se usa también para resetear el biestable RS, y apagar el circuito

Esta implementación (medida sin el LEDOscopio) consume 7 bloques lógicos

Recurso Cantidad
LC 7

Sys-delay-x08: Retardo de 8 ciclos

El bloque para hacer un retardo de 8 ciclos es similar al de 4, y se pone aquí como último ejemplo para entender cómo funcionan los bloques de retardo fijo. El resto de bloques Sys-delay de retardo fijo son similares, pero cambiando el número de bits

El cronograma de su funcionamiento se muestra en esta figura:

Ejemplo 17: Midiendo el bloque Sys-delay-x08

En este ejemplo se retrasa un tic inicial ocho ciclos. Se está midiendo la señal done, pero está la etiquetas busy disponible para conectar al LEDOscopio para realizar su medición. Se utiliza un LEDOscopio de 16 bits, pero como la Alhambra-II sólo tiene 8 LEDs, se visualizan en 2 ventanas de 8 bits

(17-sys-delay-x08.ice)

Inicialmente se ve la ventana 0, en la que todos los LEDs están a 0, porque el tic inicial del ciclo 0, al retrasarlo 8 ciclos, se vería en el ciclo 9, que no está visible en la ventana 0. Al apretar el pulsador SW1 se cambia a la ventana 1 y se comprueba que el primer LED efectivamente está encendido

En este dibujo se muestran los resultados de las mediciones de la señal de Done, en ambas ventanas:

Y en este otro se muestra la señal de busy:

Implementación_

La implementación del bloque sys-delay-x08 es la misma que para el resto de bloques de esta familia: Un biestable RS y un contador de 3 bits. En general, para un retraso R (potencia de 2), se necesita un biestable RS y un contador de N bits, donde 2**N es R

Al arrancar el circuito, con la señal start, se activa el biestable RS. Cuando se alcanza el valor máximo del contador, este biestable se vuelve a poner a 0

Esta implementación (medida sin el LEDOscopio) consume 8 bloques lógicos

Recurso Cantidad
LC 8

Sys-delay de retardo variable

Esta familia de bloques nos permiten realizar un retardo de N tics, donde ahora N NO tiene porqué ser una potencia de 2, sino cualquier valor mayor a 1. El tamaño de estos bloques depende el número de bits utilizamos para representar el retardo máximo. Por ejemplo, para un bloque de 3 bits, el retardo máximo será de 7 ciclos. El retardo que podemos usar, N, estará comprendido entre 2 (retardo mínimo) y 7 (retardo máximo)

Estos bloques consumen más recursos que los de retardo fijo, por lo que si vamos a utilizar un retardo que es potencia de dos, es mejor usar los de retardo fijo

El retardo N a utilizar se puede introducir de dos maneras: mediante una entrada de bus, o bien mediante un parámetro. Por ello tenemos dos tipos de bloques: sys-delay-xN y sys-delay-xN-K

La salida de bus n indica el ciclo actual, PERO es ligeramente diferente a la salida n de los bloques de retardo fijo. Su valor comienza en 1 y llega hasta el número total de ciclos de retraso: N. Así, si queremos especificar un retardo de 5 ciclos, los valores que salen por n son 1, 2, 3, 4 y 5

La semántica del número de retrasos, N, es el número total de ciclos, y NO su valor máximo. Se ha hecho así para que no haya confusión. De esta forma, si queremos un retardo de 7 ciclos, hacemos que N=7

Hay que tener cuidado con los valores máximos introducidor por N. Ya que si, por ejemplo, queremos un retardo de 8 ciclos (N=8), necesitamos 4 bits para representar ese valor (Ya que 8 en binario es 1000). En los de retardo fijo, como están optimizados, un retardo de 8 ciclos lo conseguimos con 3 bits

El valor N de retraso tiene que ser siempre >=2. Es decir, que el retardo mínimo es 2. Si queremos utilizar un retardo de 1, debemos utilizar bien un biestable D del sistema o el bloque Sys-Delay-x01

Sys-Delay-xN: Retardo por entrada

Estos bloques tienen una entrada de bus, N[], por donde se indica el retardo a realizar. Este valor está comprendido entre 0 (Sin retardo) y N (el retardo que queremos)

Note Es importante indicar que el valor N introducido debe permanecer constante durante el funcionamiento del circuito: Debe tener un valor estable mientras la señal busy está a uno. Cuando está a 0, se puede cambiar

Todos los bloques de este tipo son iguales. La única diferencia está en el número de bits usados, lo que nos determina el valor máximo (N) de retardo que queremos. Así por ejemplo, en el componente mostrado en este ejemplo el tamaño es de 3 bits. Esto nos permite espeficiar retardos entre 2 y 7 ciclos.

Si necesitamos hacer retardos mayores, hay que incluir un componente con más bits (y que ocupará más recursos)

En este cronograma se muestran los valores de las señales cuando se realiza un retardo de 5 ciclos, usando el componente Sys-Delay-xN de 3 bits:

Ejemplo 18: Retraso de 3 ciclos

En este ejemplo se retrasa un tic inicial 3 ciclos. Dado que el retraso es de 3 ciclos, necesitamos usar al menos un bloque Sys-Delay-xN de 2 ó más bits. El que consumiría menos recursos es el de 2 bits, pero el resultado sería el mismo si se usa otro de más bits

(18-sys-delay-xN-3-ciclos.ice)

El retraso se lo estamos introduciendo por la entrada N, usando una constante de 2 bits. Pero, por supuesto, este valor podría venir de cualquier otro circuito y NO sólo de una constante

El cronograma se muestra en esta figura

En este dibujo se muestran los resultados de las mediciones de las señales de busy y done

Ejemplo 19: Retraso de 5 ciclos

En este ejemplo se retrasa un tic inicial 5 ciclos. Necesitamos usar al menos un bloque Sys-Delay-xN de 3 ó más bits

(19-sys-delay-xN-5-ciclos.ice)

En este dibujo se muestran los resultados de las mediciones de las señales de busy y done

Implementación_

Los bloques Sys-delay-xN están implementados utilizando un biestable RS para almacenar el estado del circuito, y un contador módulo M con reset, cuyo valor inicial es 1

Este circuito, muy simplificado, funciona perfectamente, aunque sólo es válido cuando la entrada N es estrictamente mayor a 1. Para N=0 ó N=1 el circuito no es válido

Sys-Delay-xN-K: Retardo por parámetro

Estos bloques son similares a los anteriores (Sys-Delay-xN) PERO el retraso se introduce como un parámetro en vez de como una entrada (es por tanto un valor constante, que no puede cambiar durante la vida del circuito).

Por el parámetro N se introduce el retraso en ciclos. Este valor tiene que ser estrictamente superior a 1. Los valores N=0 y N=1 NO SON VÁLIDOS

Ejemplo 20: Retraso de 5 ciclos

Este circuito realiza un retraso de 5 ciclos, igual que el ejemplo 19, pero usando el bloque sys-Delay-xN-K de 3 bits

(20-sys-delay-xN-K.5-ciclos.ice)

Los resultados son exactamente iguales que en el ejemplo anterior

Implementación_

La implementación es directa a partir de una constante y un bloque Sys-delay-xN

Generando un pulso

Los pulsos son señales que inicialmente están en reposo (0), luego se activan (1) durante un cierto número de ciclos y finalmente vuelven a la situación inicial de reposo. El pulso más corto que se puede generar ya lo conocemos: el tic. Es un pulso que dura sólo 1 ciclo de reloj

Los pulsos se utilizan muchísimo. Son las señales que nos indican que ha sucedido un evento, como por ejemplo la existencia de datos disponibles, o la señal E de los displays de cristal líquito (LCD). Se usa para que el LCD capture los datos de entrada. Los pulsos también sirven para mantener encendido un periférico, como por ejemplo un LED, durante un tiempo

Se necesitan dos evento para definir un pulso: un evento inicial, que marca el inicio del pulso (transición de 0 a 1) y un evento final, que indica su fin (transición de 1 a 0). Ambos eventos están separados N ciclos de reloj

Implementación de pulsos

Los pulsos se generan usando un Biestable RS. Por su entrada de set se introduce la señal que arranca el pulso (evento de inicio) mientras que por la entrada de reset la señal para terminarlo (evento de fin)

El evento final es el mismo que el inicial, pero separados N ciclos en el tiempo. Eso se consigue con un circuito de retraso, como los que ya los conocemos. El evento inicial es un simple tic. Por ello, el esquema básico de un generador de pulsos es el que se muestra en esta figura:

Ejemplo 21: Pulso de 2 ciclos de anchura

Como ejemplo usaremos este esquema básico para obtener un pulso de 2 ciclos de retraso. El pulso se genera al recibirse un tic inicial. Usamos dos biestables D del sistema para generar el retardo, y el biestable RS para obtener el pulso

(21-two-cycles-pulse.ice)

El cronograma de este circuito se muestra en esta figura

Lo comprobamos con el LEDOscopio, y vemos que efectivamente este circuito produce un pulso de 2 ciclos de anchura

Ejemplo 22: Pulso de N ciclos de anchura

El bloque Sys-Delay-xN tiene un Biestable RS interno para generar la señal de Busy. Pues bien, esta señal es exactamente el pulso de N ciclos de anchura. Así que para generar un pulso de N ciclos basta con usar un bloque Sys-Delay-xN

En este ejemplo se genera un pulso de 6 ciclos de anchura, y se mide con el LEDOscopio

(22-N-cycles-pulse.ice)

Este es el resultado:

Trabajando en ns

El tiempo se mide en ciclos, que son unidades indivisibles. Hablamos de 1,2,3 ó N ciclos, pero no podemos medir 1.5 ciclos, por ejemplo. Dependiendo de la frecuencia del reloj del sistema, cada ciclo se corresponde un tiempo,que es igual al periodo del reloj (T)

En la tarjeta Alhambra II y muchas otras, el reloj del sistema tiene una frecuencia de 12Mhz, cuyo periodo es T = 1 / 12Mhz = 83.3ns. Así, un ciclo de reloj se corresponde con 83.3 ns

No es posible realizar retrasos de cualquier cantidad, sino sólo en múltiplos del periodo de reloj. En esta tabla se muestra la equivalencia entre ciclos y el tiempo en ns

Se calcula utilizando la siguiente fórmula:

Tiempo (ns) = (1 / 12) * 1000 * Ciclos
Ciclos Tiempo (ns) Ciclos Tiempo (ns)
1 83.3 11 916.6
2 166.6 12 1000
3 250 13 1083.3
4 333.3 14 1166.6
5 416.6 15 1250
6 500 16 1333.3
7 583.3 17 1416.6
8 666.6 18 1500
9 750 19 1583.3
10 833.3 20 1666.6

Observa que para los ciclos múltiplos de 3, se obtienen tiempos exactos en ns. Por ejemplo, 12 ciclos equivalen a un tiempo de 1000 ns (1ms)

Los circuitos de retraso funcionan en ciclos. Pero en muchas aplicaciones nos resulta más sencillo expresarlo en ns. Necesitamos realizar la conversión de nano segundos a ciclos. Esto lo hacemos aplicando la siguiente fórmula:

Ciclos = Ceil(0.012 * tiempo)  

Donde tiempo es el tiempo en nano-segundos y Ceil() es la función de redondeo al alza

Este es el código en python para realizar ese cálculo:

import sys
import math

if (len(sys.argv) <= 1):
  print("Retardo no especificado")
  sys.exit(0);


#-- El primer argumetno es el retardo en ns
R = float(sys.argv[1])

#-- Convertir a Ciclos
Ciclos = math.ceil(0.012 * R)

#-- Clacular el retardo real
R_real = Ciclos / 0.012

#-- Calcular el error
error = abs(R_real - R)

print(f"* Retardo objetivo: {R} ns")
print(f"* Ciclos: {Ciclos}") 
print(f"* Retardo real: {R_real:.1f} ns")
print(f"* Error: {error:.1f} ns")

Este es un ejemplo de uso: Convertir de 800ns a ciclos

obijuan@Hoth:~$ python3 ns2c.py 800
* Retardo objetivo: 800.0 ns
* Ciclos: 10
* Retardo real: 833.3 ns
* Error: 33.3 ns

Como 800ns no es múltiplo de un periodo, son necesarios 10 ciclos, pero el retardo real entonces es de 833.3ns, y el error es de 33.3ns

Bloque ns

El bloque ns realiza la conversión de nanosegundos a ciclos. Funciona como una constante, que sirve para introducirla en los bloques que tienen entrada de ciclos, como los de delay

En esta figura se muestra el bloque ns de 2-bits. Cómo máximo la salida puede ser 3, que se corresponde a 250ns. Si el número de ns introducidos es mayor que su máximo, el valor de ciclos obtenido será incorrecto

En este ejemplo se muestra un circuito que genera un pulso de 500ns de anchura

(23-retardo-500ns.ice)

Un retraso de 500ns se corresponde con 6 ciclos, a la frecuencia de 12Mhz, por eso en las mediciones en el LEDOscopio es lo que se ve:

Si lo medimos con un osciloscopio externo, comprobamos que efectivamnete el pulso es de 500ns

El pulso medido es de 500ns porque esta cantidad se corresponde exactamente con 6 ciclos de reloj. Sin embargo, si se introduce otra cantidad no exacta habrá un error, y el pulso tendrá una anchura diferente a la especificada en el bloque ns

Detección de flancos

Las señales binarias de nuestros circuitos sólo pueden estar en dos estados: 0 ó 1. Las transiciones de un valor a otro se denominan flancos y tenemos dos tipos:

  • Flancos de subida: Transición de 0 a 1. Ocurre un flanco de subida cuando el valor de la señal en un ciclo es 0 y pasa a valer 1 en el ciclo siguiente
  • Flancos de bajada: Transición de 1 a 0. El flanco de bajada ocurre cuando la señal vale 1 en un ciclo, y pasa a 0 en el ciclo siguiente

Así, si observamos un pulso de una anchura de N ciclos, vemos que está formado por dos flancos, uno de subida y otro de bajada. Entre ambos la señal permanece a 1, sin cambios

Los flancos los detectamos con unos circuitos que se llaman detectores de flancos. Nos indican cuándo ha ocurrido un cambio en la señal. Tenemos de tres tipos: Detectores de flancos de subida, de flancos de bajada, o detectores de ambos flancos:

Todos estos bloques emiten por su salida un pulso de 1 ciclo de anchura (tic) cuando detectan el flanco correspondiente

Detección de flancos de subida

El bloque para detectar flancos de subida se llama Rising-Edge. La señal llega por su entrada, y por la salida se genera un tic cuando se detecta un flanco de subida

En este Cronograma se detalla su funcionamiento. Por la entrada se introdcuen dos pulsos, y por su salida se obtienen 2 tics, cada uno correspondiente a su flanco de subida

Ejemplo 24: Detección de flancos de subida de una señal

En este ejemplo se detectan los flancos de subida de una señal como la mostrada en el cronograma anterior: está formada por un pulso de 3 ciclos de anchura, seguido de un de 2 ciclos de anchura. Ambos están separados 1 ciclo, y el primero comienza en el ciclo 1

Este es el circuito:

(24-rising-edge.ice)

La señal generada se pasa por el detector de Flancos de subida y se introduce en el LEDOscopio para medirla. El resultado se muestra en esta figura. Se ha incluido también la medición de la señal original, para compararla con el cronograma del apartado anterior

Retraso 0: Detectando un tic

El detector de flancos de subida tiene un retraso de 0 ciclos. Esto significa que si introducimos un tic por su entrada, en la salida obtenemos el mismo tic, sin retrasar. En esta figura vemos el cronograma:

En el ejemplo 25 lo comprobamos experimentalmente. Por un lado medimos un pulso inicial (tic) y por otro lado, lo pasamos por el detector de flancos de subida y lo medimos

(25-rising-edge-tic.ice)

En esta figura se muestra el resultado de las mediciones. Ambas señales son iguales

Implementación del detector de Flancos de subida

El detector de flancos de subida utiliza un biestable D del sistema para almacenar el valor de la señal en el ciclo anterior, y este valor se compara con el que tiene en el ciclo actual. Si el ciclo anterior era 0 y resulta que ahora la señal vale 1, significa que ha llegado un flanco de subida. Esta comparación se hace con una puerta AND

Detección de flancos de bajada

El bloque para detectar flancos de bajada se llama Falling-Edge. La señal llega por su entrada, y por la salida se genera un tic cuando se detecta un flanco de bajada

En este Cronograma se detalla su funcionamiento. Por la entrada se introdcuen dos pulsos, y por su salida se obtienen 2 tics, cada uno correspondiente a su flanco de bajada

Ejemplo 26: Detección de flancos de bajada de una señal

En este ejemplo se detectan los flancos de bajada de una señal como la mostrada en el cronograma anterior: está formada por un pulso de 3 ciclos de anchura, seguido de un de 2 ciclos de anchura. Ambos están separados 1 ciclo, y el primero comienza en el ciclo 1

Este es el circuito:

(26-rising-edge-tic.ice)

La señal generada se pasa por el detector de Flancos de bajada y se introduce en el LEDOscopio para medirla. El resultado se muestra en esta figura. Se ha incluido también la medición de la señal original, para compararla con el cronograma del apartado anterior

Retraso 0: Detectando un flanco de bajada en un tic

El detector de flancos de bajada tiene un retraso de 0 ciclos con respecto al ciclo en el que la señal se pone a 0. En este cronograma se introduce un tic por su entrada. En la salida obtenemos otro tic que está retrasado un ciclo:

Sin embargo, NO hay retraso en el flanco de bajada. En la señal de entrada la señal se pone a 0 en el ciclo 2. Y es justo en ese ciclo, el 2, donde la señal de salida se pone a 1, indicando que hay un flanco de bajada. El flanco de bajada se produce en el ciclo 2. Y en ese mismo ciclo se señaliza su aparación

En el ejemplo 27 lo comprobamos experimentalmente. Por un lado medimos un pulso inicial (tic) y por otro lado, lo pasamos por el detector de flancos de bajada y lo medimos

(27-falling-edge-tic.ice)

En esta figura se muestra el resultado de las mediciones

Implementación del detector de Flancos de bajada

El detector de flancos de bajada utiliza un biestable D del sistema para almacenar el valor de la señal en el ciclo anterior, y este valor se compara con el que tiene en el ciclo actual. Si el ciclo anterior era 1 y resulta que ahora la señal vale 0, significa que ha llegado un flanco de bajada. Esta comparación se hace con una puerta AND

Detección de ambos flancos

El bloque para detectar flancos se llama Edges. La señal llega por su entrada, y por la salida se genera un tic cuando se detecta un flanco de subida o uno de bajada

En este Cronograma se detalla su funcionamiento. Por la entrada se introdcuen dos pulsos, y por su salida se obtienen 4 tics, cada uno correspondiente a un flanco de subida o de bajada

Ejemplo 28: Detección de flancos de subida y bajada de una señal

En este ejemplo se detectan los flancos de subida y bajada de una señal como la mostrada en el cronograma anterior: está formada por un pulso de 3 ciclos de anchura, seguido de un de 2 ciclos de anchura. Ambos están separados 1 ciclo, y el primero comienza en el ciclo 1

Este es el circuito:

(28-edge-detection.ice)

La señal generada se pasa por el detector de Flancosa y se introduce en el LEDOscopio para medirla. El resultado se muestra en esta figura. Se ha incluido también la medición de la señal original, para compararla con el cronograma del apartado anterior

Detectando los flancos de un tic

En un tic, al igual que en el resto de pulsos, hay 2 flancos. Por tanto, cuando introducimos un tic en el detector de flancos se obtiene como salida un pulso de 2 ciclos de anchura, que se corresponde con la unión de los dos tics obtenidos por los detectores de subida y bajadas indepedienetes

En el ejemplo 29 lo comprobamos experimentalmente. Por un lado medimos un pulso inicial (tic) y por otro lado, lo pasamos por el detector de flancos de bajada y lo medimos

(29-edge-detection-tic.ice)

En esta figura se muestra el resultado de las mediciones

Implementación del detector de Flancos

Una forma sencilla de implementar el detector es mediante la unión de los dos detectores: de subida y bajada, usando una puerta OR. Sin embargo, estamos gastando un biestable para cada detector. Es posible realizar una implementación más optimizada usando sólo un biestable D del sistema y los circuitos combinacionales necesarios para detectar la relación entre el ciclo anterior y el actual

Sólo si hay cambios en estos ciclos, significa que ha llegado un flanco de algún tipo. Por ello basta con usar una puerto XOR que precisamente se pone a 1 sólo cuando hay cambios

Conclusiones

Saber manejar y medir las señales del sistema es necesario para generar las señales de sincronización de nuestros circuitos. También sabemos crear pulsos, lo que será muy útil para construir señales periódicas. Con todo esto ya tendremos las herramientas para implementar controladores

Autor

Licencia

Créditos y agradecimientos

  • Carlos Venegas. Muchísimas gracias por toda tu ayuda y tus aportaciones 😄

Enlaces

Clone this wiki locally