Re: Registro de desplazamiento con carga paralela asíncrona.

926 views
Skip to first unread message
Message has been deleted

Democrito

unread,
Apr 15, 2017, 3:23:38 AM4/15/17
to FPGAwars: explorando el lado libre
He eliminado el anterior post y lo he re-editado con la intención de que sea más comprensible.

Hola!

Hace ya muchos meses que buscaba la manera de hacer un registro de desplazamiento con carga paralela, pero el problema que tenía (yo) es que era incapaz de seguir las reglas del diseño síncrono. No hace mucho me hice uno, y me funciona bien, pero es un diseño de estar por casa; una cosa que no me hacía mucha gracia era la necesidad de tener que dar un pulso además de poner el "load" (para la carga paralela) a 1. Todo esto lo publiqué en este hilo (post 41).

Leyendo los tutoriales de Obijuan, él tiene un registro de desplazamiento con carga paralela, pero está adaptado para ir en función de un baudio determinado, porque es un transmisor para puerto serie. Todo lo que vi ahí es sencillo de comprender (gracias a lo bien explicado que está), y yo necesitaba eso mismo, pero la señal de los baudios debía ser una entrada de pulsos sin referencias temporales. El problema era resolver cómo generar una señal de "CP" ("Baudgen.v" en el 'código' descriptivo de Obijuan) independientemente del tiempo. Y lo solucioné hace pocos días de esta manera:

Me he tomado la libertad de copiar y modificar una imagen del tutorial de Obijuan que puedes encontrar aquí.


En realidad esto también funciona sin el FFD0, pero lo he añadido porque por alguna razón que desconozco es recomendable y parece ser que tiene relación con las reglas del diseño síncrono. La idea de añadir otro flip-flop más la tomé del lector de cuadratura (encoder) que publiqué en el post nº41 mencionado anteriormente, y que tampoco es de mi autoría, sino una adaptación para Icestudio.

Una vez resuelta esta parte, ya pude tomar el código que tiene Obijuan en su tutorial y adaptarlo para mi registro de desplazamiento con carga paralela asíncrona.

El código descriptivo en Verilog es el siguiente:


reg [2:0] FFD=0; // 3 bits flips-flops tipo D.
always @(posedge clk) FFD <= {FFD[1:0], cp}; // Registro de desplazamiento a izquierda.
wire pulso= FFD[1] & !FFD[2]; // Esto es una AND con una de sus entradas negada.

reg load_r;
always @(posedge clk)
    load_r <= load;

reg [31:0] shifter;
always @(posedge clk)
    if (load_r)                 //-- Modo carga
        shifter <= d;
    else if (!load_r && pulso)  //-- Modo desplazamiento
        shifter <= {1'b0, shifter[31:1]}; // Registro de desplazamiento a derecha.

assign qs = shifter[0];         // Salida por el bit menos significativo.

Esto es un registro de desplazamiento como en los chips estandar, es decir, que si el load está 1 hace la carga paralela, y cuando se pone a 0, cada vez que el CLK (el externo, no el reloj de 12MHz) recibe un pulso, se desplazan los bits.

Yo estoy utilizando mucho los registros de desplazamiento para comunicar la FPGA con un microcontrolador. Esta manera de trabajar es muy parecido a la comunicación SPI.

Y para terminar un ejemplo para leer los bits desplazado desde un Arduino, el código sería el siguiente:


Este código ya se publicó en otro post, sólo cambia la parte que hace la carga (variable 'ld'), aquí es de manera directa.


#define NOP __asm__ __volatile__ ("nop\n\t") // "No OPeration", para permitir un ciclo de reloj sin hacer nada; se utilizará como "nano-pausa" (un ciclo de reloj).

// Patillaje.
const byte din = 5;  // Número de pin de la entrada de datos series provenientes de la FPGA. (Registro de desplazamiento con la información de los pulsos del encoder óptico. 32 bits)
const byte clk = 6;  // Número de pin de la señal de pulso para el registro de desplazamiento en la FPGA. (idem)
const byte ld  = 7;  // Número de pin de la señal para cargar el contador de pulsos al registro de desplazamiento en la FPGA. (idem)

// Variable general.
int  cnt = 0;                        // Contador general para el bucle For-Next.

// Acumulador de pulsos.
long pulsos = 0;                     // Contador de pulsos.
long aux    = (2^32)-1;              // Variables auxiliar para comparar si hay cambios. Cargamos al valor máximo para que imprima el valor desde el comienzo y no salga la pantalla vacía.

void setup()
{  
  Serial.begin(115200);              // Configuración del puerto serie virtual.
  
  pinMode(din, INPUT);               // din  como entrada. Estos son los tres pines para la lectura del registro de desplazamiento en la FPGA. (pin 5)
  pinMode(clk, OUTPUT);              // clk  como salida. (pin 6)
  pinMode(ld,  OUTPUT);              // ld   como salida. (pin 7)
  digitalWrite(clk, LOW);            // Esas dos salidas se inician con cero.
  digitalWrite(ld,  LOW);
}

void loop()
{
    digitalWrite(ld,  HIGH);          // Carga del registro de desplazamiento en la FPGA.
    NOP;                              // Un pequeño delay porque no se debe (en teoría) poner una instrucción seguida de otra en la que cambia el estado el mismo pin; en este caso es Load.
    digitalWrite(ld,  LOW);           // Hecho esto vuelve a cero.
    
    pulsos=0;                         // Ponemos a cero la variable pulsos; luego en el bucle "for" se irán poniendo a 1 los bits correspondientes.
    for (cnt = 0; cnt < 32; cnt++)    // Lectura del registro de desplazamiento.
    {
      if (digitalRead(din)) bitSet(pulsos, cnt);  // Inicialmente todos los bits de la variable "pulsos" están a cero. Aquí va poniendo a 1 los bits correspondientes.
      
      digitalWrite(clk, HIGH);        // Flanco de subida de clk para pasar al siguiente bit del registro de desplazamiento de la FPGA.
      NOP;                            // Un pequeño delay porque no se debe (en teoría) poner una instrucción seguida de otra en la que cambia el estado el mismo pin; en este caso es clk.
      digitalWrite(clk, LOW);         // Se pone a cero la señal clk para completar el pulso.
    }

    if (aux != pulsos)                // Si se produce algún cambio de contaje se muestra por el puerto serie.
    {
      Serial.println(pulsos);         
      aux = pulsos;                   // Igualamos para luego ver si hay cambios.
    }                                 
}
    

Adjunto ejemplos aquí descritos.

Saludos!

Registro de desplazamiento con carga paralela asincrona V2.ice
Lector_de_registro_de_desplazamiento_de_32bits_carga_asincrona.ino

Democrito

unread,
Apr 15, 2017, 8:27:55 AM4/15/17
to FPGAwars: explorando el lado libre
Recuerda que se trata de hacer un registro de desplazamiento asíncrono, pero que ha de cumplir con las reglas del diseño síncrono.

Al diseño de registro de desplazamiento anterior le he dado una vuelta más "de tuerca" para cumplir con las reglas del diseño síncrono y he registrado la salida serie.

Quedando así:  (ahora el patillaje está pensado para la Icezum Alhambra, y de 8 bits para verse más sencillo.)


reg [2:0] FFD=0; // 3 bits flips-flops tipo D.
always @(posedge clk) FFD <= {FFD[1:0], cp}; // Registro de desplazamiento a derecha.
wire pulso=FFD[1] & !FFD[2];

reg load_r;
always @(posedge clk)
    load_r <= load;

reg [7:0] shifter;
always @(posedge clk)
    if (load_r)                 //-- Modo carga
        shifter <= d;
    else if (!load_r && pulso)  //-- Modo desplazamiento
        shifter <= {1'b0, shifter[31:1]}; // Registro de desplazamiento a izquierda.

reg qs;
always @(posedge clk)
    qs <= shifter[0]; // Salida serie registrada.
    

Adjunto ejemplo ICE.


RegistroDesplazamiento8bits.ice

Jose Pico

unread,
Apr 17, 2017, 6:02:58 PM4/17/17
to FPGAwars: explorando el lado libre
 Muchas Gracias por tu información!

Te adjunto un registro de desplazamiento universal que tengo realizado por si quieres también  pegarle un vistazo.

Saludos
8_Shift_Universal.ice

Democrito

unread,
Apr 17, 2017, 7:31:59 PM4/17/17
to FPGAwars: explorando el lado libre
Hola José,

Te agradezco mucho el ejemplo que has puesto!

Saludos!

James

unread,
Apr 18, 2017, 4:26:34 AM4/18/17
to FPGAwars: explorando el lado libre
Hola de nuevo José,

Soy el mismo Demócrito que en los mensajes anteriores pero desde otra cuenta. Anoche, por lo tarde que era, no me detuve a mirar con calma el adjunto que pusiste, sólo le eché un ojo. Tu circuito es un registro de desplazamiento completo porque permite desplazar a derecha e izquierda, carga paralela y reseteo. Lo que trataba de compartir en este hilo era que además siguiese las reglas del diseño síncrono y para ello ha de tener una señal de reloj independiente de la señal que le damos para hacer desplazar los bits dentro del registro de desplazamiento. Por eso en el diseño que puse hay la tradicional señal de reloj de 12MHz, que es lo que sincroniza el circuito, pero para desplazar los bits uso otra patilla llamada "CP" (Clock Pulse).

En principio el diseño que pusiste trabajará sin problemas, pero corres el riesgo de que al aumentar la complejidad del diseño comience a tener comportamientos inesperados, por eso se hace tanto incapié en el diseño síncrono.

Es otra manera de "pensar" los circuitos. Al comienzo me costó mucho comprender el concepto, pero poco a poco le voy pillando el "truquillo" (es una forma de hablar), y cómo de costumbre, con muchos tropiezos por el camino...

Saludos y gracias de nuevo por compartir!

Jose Pico

unread,
Apr 19, 2017, 7:23:17 AM4/19/17
to fpga-wars-explora...@googlegroups.com
Gracias!

--


Has recibido este mensaje porque estás suscrito a un tema del grupo "FPGAwars: explorando el lado libre" de Grupos de Google.


Para cancelar la suscripción a este tema, visita https://groups.google.com/d/topic/fpga-wars-explorando-el-lado-libre/JhEzTXqtDuA/unsubscribe.


Para cancelar la suscripción a este grupo y a todos sus temas, envía un correo electrónico a fpga-wars-explorando-el...@googlegroups.com.


Para publicar en este grupo, envía un correo electrónico a fpga-wars-explora...@googlegroups.com.


Visita este grupo en https://groups.google.com/group/fpga-wars-explorando-el-lado-libre.


Para ver esta conversación en el sitio web, visita https://groups.google.com/d/msgid/fpga-wars-explorando-el-lado-libre/7b3fe5c4-7b4e-4fa6-a802-ffbca2ea2c76%40googlegroups.com.


Para acceder a más opciones, visita https://groups.google.com/d/optout.


Reply all
Reply to author
Forward
0 new messages