Estoy usando un FPGA para muestrear un flujo de datos en serie (en este caso, resulta ser audio PCM). Básicamente, hay dos señales:
Actualmente, tengo una detección de borde asíncrona en el reloj de bits. Entonces, básicamente, una bandera subirá durante un ciclo de reloj cuando el reloj de bits esté en el borde ascendente. Mi enfoque fue esperar esta bandera. Cuando la bandera sube, tomo el valor de la línea de datos y lo pongo en un índice de mi búfer. Sin embargo, no creo que esto esté funcionando correctamente. ¿No puedo simplemente probar el valor del 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
Tienes dos requisitos aquí:
Hay un par de maneras de satisfacer estas necesidades.
Primero, si el reloj del bus es lo suficientemente lento por debajo del reloj de su sistema, puede sincronizar el reloj del bus con su dominio de reloj con un doble flop. Luego use un detector de borde simple para determinar cuándo es el borde ascendente. Esto se utiliza para muestrear de forma segura la línea de datos del bus. Tenga en cuenta que esto logra el # 2 automáticamente. Además, como se indica aquí , esta es la forma preferida de hacer esto en un FPGA.
Este método tiene el inconveniente de que los datos se muestrean en algún lugar entre dos y tres relojes del sistema más tarde que el borde del reloj del bus 'en el pin' real. Si esto es demasiado largo (debido a que el reloj de su sistema no es lo suficientemente rápido en comparación), debe buscar 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 según el autobús.
always @(posedge bclk) begin // positive edge of bus clock
sampled_data <= data;
end
En este punto, tiene sampled_data, que es una señal en el dominio bclk. Debe sincronizarlo con el dominio del reloj de su sistema. Para hacer esto, debe usar un apretón de manos o un FIFO.
Una forma que funciona es hacer el registro de desplazamiento en el dominio del reloj del 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 de la FPGA, así como entre dominios de reloj, deberá definir correctamente las restricciones de tiempo. Describir los detalles es demasiado general para este foro, pero como se recomienda en 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 escritos decentes para las definiciones de retardo de entrada y retardo de salida también.
cocodrilo
posedge bclk
debido a algunas cosas asincrónicas (no lo entiendo completamente): doulos.com/knowhow/fpga/synchronisationcavernícola
cavernícola
cocodrilo
posedge bclk
, ¿no tendría que hacer algo especial en mi archivo de código/restricciones para convertirlo en una entrada sincronizada?greg