Leyendo un flujo de datos en serie con Verilog

2

Estoy usando un FPGA para muestrear un flujo de datos en serie (en este caso, se trata de audio PCM). Básicamente, hay dos señales:

  • Reloj de bits: una señal de reloj básica (onda cuadrada)
  • Datos: el bit a leer está presente en el flanco ascendente del reloj

Actualmente, tengo una detección de borde asíncrona en el reloj de bits. Básicamente, una bandera irá a alta durante un ciclo de reloj cuando el reloj de bits esté en el flanco ascendente. Mi enfoque fue esperar por esta bandera. Cuando el indicador sube, tomo el valor de la línea de datos y lo coloco en un índice de mi búfer. Sin embargo, no creo que esto esté funcionando correctamente. ¿No puedo simplemente muestrear el valor de hardware de la línea de datos? ¿Necesito amortiguarlo? Aquí está mi código de referencia:

always @(posedge clk) begin // posedge of system clock

    if(bclk_rise == 1) begin // Rising edge on BCLK detected, sample the bit and place it in the correct buffer index

        audio_data[data_count] <= data; // 'data' is the wire type that's connected to the ADC data line

        data_count <= data_count + 1; // 5-bit value, gets reset to zero every 32 loops

    end

end
    
pregunta crocboy

1 respuesta

2

Tienes dos requisitos aquí:

  1. Debe asegurarse de muestrear esos datos en el momento correcto de acuerdo con las necesidades del bus.
  2. Debe sincronizar estos datos en el dominio del reloj de su sistema.

Hay un par de maneras de satisfacer estas necesidades.

Primero, si el reloj del bus es lo suficientemente lento por debajo del reloj de tu sistema, entonces puedes sincronizar el reloj del bus con el dominio de tu reloj con un doble flop. Luego use un detector de bordes simple para determinar cuándo es el borde ascendente. Esto se utiliza para muestrear con seguridad la línea de datos del bus. Tenga en cuenta que esto logra # 2 automáticamente. Además, como se señaló aquí , esta es la forma preferida de hacer esto en un FPGA.

Este método tiene el inconveniente de que los datos se muestrean entre dos y tres relojes del sistema más tarde que el borde del reloj del bus "en el pin". Si esto es demasiado largo (debido a que el reloj de tu sistema no es lo suficientemente rápido en comparación), tienes que ir por un camino alternativo.

En este método, muestrea antes de sincronizar con el dominio del reloj del sistema. El motivo es asegurarse de que esté tomando muestras en el momento adecuado de acuerdo con el bus.

always @(posedge bclk) begin  // positive edge of bus clock
    sampled_data <= data;
end

En este punto, ha muestreado datos que son una señal en el dominio bclk. Debe sincronizarlo con el dominio del reloj de su sistema. Para hacer esto, debes usar handshaking o FIFO.

Una forma que funciona es hacer el registro de desplazamiento en el dominio del reloj de bus para obtener datos paralelos. Luego, páselo a través de un FIFO de doble reloj al otro dominio. Los FPGA tienen primitivas solo para este uso.

// Latch the data in the bclk domain
always @(posedge bclk) begin
    fifo_d <= {fifo_d[30:0], data};

    data_count <= data_count + 1;
    if (data_count == 31)
        fifo_wr <= 1'b1;  // This will latch fifo_d to the dual clock fifo input
    else
        fifo_wr <= 1'b0;
end

// Read the data out of the FIFO in the system clock domain.
always @(posedge clk) begin
    if (fifo_ready)
        synchronized_data <= fifo_q;   // Now the data is in your domain.
end

Otras notas:

Al igual que con cualquier E / S en el borde del FPGA, así como entre dominios de reloj, deberá definir correctamente las restricciones de tiempo. Describir los detalles es un poco demasiado general para este foro, pero como lo recomiendan los comentarios de Greg, este documento es una buena fuente para comprender las necesidades del cruce del dominio del reloj. Los proveedores de FPGA tienden a tener también anotaciones decentes para el retardo de entrada y las definiciones de retardo de salida.

    
respondido por el caveman

Lea otras preguntas en las etiquetas