Verilog Práctico
Capítulo 14. Generando Tonos
En este capítulo veremos cómo generar tonos de distintas frecuencias con la Alhambra FPGA y además aprenderemos algo muy útil e importante en Verilog, interconectar módulos.
Esquema
El esquema de conexión es muy sencillo. Tan solo necesitamos un transistor, un altavoz y un par de resistencias.
Monta el circuito como en la imagen y conéctalo a la salida D0 de la Alhambra FPGA. La resistencia de 47 Ohm es opcional, para bajar un poco el volumen. También se puede alimentar el altavoz con 3,3V.
Ejemplo 1. Generador de tonos simples.
Código Verilog
El código Verilog consiste en un generador de frecuencias de 1 Hz. La salida del generador de frecuencias la aplicamos a una entrada de una puerta AND cuya salida activamos con el switch 1 de la Alhambra. Cuando pulsamos SW1 dejamos pasar la señal de 1 Hz hacia el altavoz, así no está siempre sonando.
module simple_tone (clk, sw1, out);
input clk;
input sw1;
reg tone;
output out;
reg [19:0] cnt;
parameter freq = 12000;
always @(posedge clk)
begin
cnt <= cnt + 1;
if (cnt == freq)
begin
tone <= ~tone;
cnt <= 0;
end
end
and (out, sw1, tone);
endmodule
Archivo .pcf
set_io sw1 10
set_io out 119
set_io clk 21
¿Qué es lo que hemos sintetizado en la Alhambra FPGA?
Dentro del bloque always tenemos un contador que se incrementa una unidad con cada flanco positivo del reloj. Este contador lo comparamos con un valor constante, en este caso 12.000.
Cuando el contador llega a 12.000 invertimos el valor de la señal binaria tone haciéndola pasar de 0 a 1 constantemente: tone <= ~tone y reseteamos el contador a cero: cnt <= 0
La cifra de 12.000 no es aleatoria. Dado que la Alhambra tiene un reloj de 12 MHz, en contar hasta 12.000 tarda 1 ms luego f = 1 / 0,001 = 1 KHz. Cambiando el valor del parámetro freq obtenemos tonos de distintas frecuencias.
Como decíamos más arriba, la señal tone la aplicamos a la entrada de una puerta AND cuya salida activamos con el switch 1 de la Alhambra, para que el altavoz sólo suene cuando pulsamos SW1.
Ejemplo 2. Generador de dos tonos + multiplexor
En este ejemplo vamos a generar dos tonos de distinta frecuencia. Conectaremos las salidas del generador de tonos, a las entradas de un multiplexor 2 - 1 para obtener, en la salida, una señal de alarma de dos tonos.
Crearemos dos módulos con una declaración module / endmodule y guardaremos cada uno en un archivo .v diferente. Después uniremos las entradas y salidas; aprenderemos a interconectar diferentes módulos mediante cables.
Código Verilog
Este código es similar al del ejemplo 1, pero con dos contadores independientes cnt1 y cnt2 y dos parámetros de distinto valor 60000 y 6000 para generar dos tonos de distinta frecuencia: 200 Hz y 2 KHz.
Generador de 2 tonos
module two_tones_generator (input wire reloj, output reg Hz_200, KHz_2);
reg [19:0] cnt1, cnt2;
always @(posedge reloj)
begin
cnt1 <= cnt1 + 1;
cnt2 <= cnt2 + 1;
if (cnt1 == 60000) // 200 Hz
begin
Hz_200 <= ~Hz_200;
cnt1 <= 0;
end
if (cnt2 == 6000) // 2 KHz
begin
KHz_2 <= ~ KHz_2;
cnt2 <= 0;
end
end
endmodule
Multiplexor 2-1
Utilizamos un prescaler para obtener un reloj clk2 personalizado, que se encargará de conmutar el valor de la entrada sel del multiplexor.
Dependiendo del bit que pongamos en la declaración assign clk2 = prescaler[21]; obtenemos el tiempo de conmutación entre los dos tonos. Esta técnica ya la hemos empleado anteriormente para hacer contadores automáticos en los capítulos 3 y 4.
module mux2_1 (input in1, in2, reloj, output reg out);
reg sel;
reg [24:0] prescaler = 0;
wire clk2;
assign clk2 = prescaler[21];
always @ (posedge reloj)
begin
prescaler <= prescaler + 1;
end
always @ (posedge clk2)
begin
sel <= sel + 1;
end
always @ (sel) begin
case (sel)
1'b0 : out = in1;
1'b1 : out = in2;
endcase
end
endmodule
Cómo unir dos módulos
Para unir los módulos tone generator y multiplexor vamos a crear un tercer módulo tone_mixer donde declaramos los cables w1 y w2 que unen las salidas del generador de tonos con las entradas del multiplexor.
Es lo que se llama diseño estructural; particionar circuitos complejos en otros más sencillos facilitando así el diseño.
La inclusión de módulos de nivel inferior dentro de un módulo de nivel superior se llama jerarquía y se hace instanciando, es decir, invocando a un módulo desde otro.
La sintaxis es:
nombre_del_modulo <identificador> (.puerto_1(wire_1), .puerto_2(wire_2));
Donde puerto_n son las E/S de los módulos y wire_n son las señales a las que están conectados los puertos. El nombre del puerto está precedido de un punto .puerto_1 y el nombre de la señal a la que está conectando va entre paréntesis (wire_1) y cada conexión se separa mediante comas.
Esta forma de interconectar módulos se llama Mapeo Explícito y el orden en que se listan las conexiones no importa, por eso es menos dado a equivocaciones.
Existe otra técnica para conectar módulos llamada Mapeo Posicional. No lo voy a explicar para no enrollarme en exceso, lo dejo como tarea para casa.
Resumiendo, el módulo que interconecta el generador y el multiplexor queda como sigue:
module tone_mixer (input wire clk, output wire spk);
wire w1, w2;
two_tones_generator MOD_1 (.reloj(clk), .Hz_200(w1), .KHz_2(w2));
mux2_1 MOD_2 (.reloj(clk), .out(spk), .in1(w1), .in2(w2));
endmodule
El archivo .pcf tiene solamente dos puertos, la señal de reloj clk y la salida spk hacia el altavoz:
set_io spk 119
set_io clk 21
Los tres archivos .v con los tres módulos, se guardan en la misma carpeta junto con el archivo .pcf
Lo subimos a la Alhambra y lo que vemos y oímos en la salida son dos señales de 200 Hz y 2 Khz alternándose, así obtenemos una señal de alarma de dos tonos.
Normas de interconexión entre módulos
La conexión de dos módulos debe respetar unas reglas.
Internamente, las entradas de un módulo siempre son tipo net. Externamente las conexiones pueden venir de una variable tipo reg o net.
Internamente, las salidas de un módulo pueden ser tipo reg o net y sólo se pueden conectar a una variable externa tipo net.
Ejemplo 3. Generador de notas musicales
Para finalizar vamos a llevar el ejemplo anterior un poco más lejos. Haremos un generador de 8 notas musicales que sacaremos por una salida mediante un multiplexor 8-1.
La forma de programar el generador de notas es igual que en el ejemplo 2, pero ahora con 8 contadores que conmutaran 8 señales digitales apara conseguir las frecuencias de las notas musicales DO, RE, MI, FA, SOL, LA, SI.
Bueno, en realidad he añadido DO sostenido para que sea más fácil implementar el multiplexor 8-1.
El código Verilog del generador de notas y el multiplexor no lo he pegado porque son muchas líneas, pero lo puedes descargar más abajo. Recuerda que los tres archivos .v deben estar en la misma carpeta, igual que en ejemplo 2.
La forma de instanciar (interconectar) el generador de notas con el multiplexor es la siguiente.
Eso es todo, espero que os haya gustado
¡Hasta pronto!
Links
El generador del notas musicales lo he sacado del Open FPGA Verilog Tutorial del gran Obijuan, capítulos 17, 18 y 19
Descargas
Descarga los ejemplos 1, 2 y 3 aquí abajo.