Escrito por Guillermo Acevedo
 
Objetivos:
  • Diseñar e implementar una aceleración para el algoritmos de karplus strong por medio de hardware, realizando un hardware especifico para nuestro sistema controlado por medio del software.
  • Conocer el principio de la aceleración de algoritmos por medio de hardware y su implementación
 
Diseño
 
En esta practica se realiza la implementación hardware del el algoritmo de karplus strong, para tener los sonidos de una guitarra, en la anterior practica se implementó de manera software, en esta se realizara desde el punto de vista software, es decir, haciendo la analogia con una guitarra real, antes teníamos el software como dedos y guitarra, esta vez los dedos serán el software y el hardware en la FPGA sera la guitarra, cuando el software induce la nota y el tiempo, el sonido se creara en la FPGA y saldrá por un pin que emula ser un convertidor digital-analógico, se quiere implementar el siguiente diseño:
 
 
 
El divisor de frecuencia va conectado al dato para tener la frecuencia deseada y al clk del sistema, del NIOS, se selecciona la nota que se enviara, el nois_en elige que datos pasan por el multiplexor, se escogieron 500 registros ya que según la tabla el máximo valor al que se llegara es 469.
 
 
 Qsys
 
Lo primero que se debe hacer es ingresar al Qsys, y colocar nuevos puertos paralelos de entrada y salida, los cuales serán noise, noise_en, sel_nota, noise_pulse como se muestra en la siguiente figura, se conectan el clk al reloj de 50Mhz, se conecta el reset al reset del sistema, s1 se conecta al data master, y la conexión externa se exporta con el nombre deseado y generamos automáticamente las direcciones.
 
 
Se debe generar el HDL verilog, y debe aparecer en la jerarquía los puertos que acabamos de agregar, como se muestra en la siguiente figura:
 
 
Verilog karplus strong
 
Generamos un nuevo archivo de verilog, y creamos el modulo de karplus strong, debemos instanciar allí las entradas y las salidas del sistema, para este tendremos en las entradas un clk, reset, el vector noise [15:0], noise_en, vector sel_nota [9:0], noise_pulse, vector div_freq_in[31:0] y la salida syn_guitar[15:0]
 
Para poder diseñar lo anteriormente descrito se debe crear un registro de tamaño 500 y de 16 bits, y el registro z, el cual es un retenedor de orden 1, es decir retiene el dato anterior por un pulso de reloj. 
Se crean wires para transmitir los datos, en el wire current_value se guarda el dato de salida del valor seleccionado de sel_nota.
En el wire feedback se realiza la suma de los valores current_value y z, es decir, el valor seleccionado en la salida mas el valor anterior divididos en 2, por eso la suma se realiza de 15:1 y no de 15:0, ya que una división en 2 elimina el ultimo bit. 
Se crea también un cable para transmitir la frecuencia de la salida del divisor de frecuencia llamado clk_div_freq.
En la primera figura podemos observar 2 multiplexores, uno decide si pasa ruido, o si pasa el valor de feedback, y el otro decide si pasa el valor de la frecuencia del pulso de ruido o clk_div_freq. Para el primero se asigna directamente a la salida syn_guitar el valor; para el segundo se crea un wire llamado clock, el cual sera la señal de reloj con la cual trabajara nuestro sistema.
Luego de esto se debe instanciar el modulo de division de frecuencia dentro de nuestro modulo de karplus strong para poder utilizarlo, conectamos a la entrada div_freq_in y a la salida de este modulo clk_div_freq.
En el primer always se realiza cada vez que hay un flanco de subida en el wire clock, en el se guarda el valor anterior en z.
Lo anteriormente mencionado se puede observar en la siguiente imagen:
 
 
para inicializar los valores del registro utilizaremos el generate, el cual posee un pre compilador para traducir el código descrito en alto nivel a lenguaje de descripción de hardware, esta vez utilizaremos un for para ello, utilizamos 499 de los 500 registros en esto. Creamos un nuevo always dentro del for, que trabaja con cada flanco de subida del wire clock, y el valor de line_length en en registro actual es igual al valor line_length del registro menor a el.
 
 
Implementación
 
Instanciamos nuestro modulo de karplus strong y lo pegamos en en modulo principal, borramos las señales internas, creamos wires nuevos para interconectar nuestro modulo con el modulo del NIOS,  wire de noise_nios, wire de guita_syn el cual es la salida del modulo kuartus, el cual se conectara mas adelante, wire de sel_nota que transmite cual es la nota seleccionada, wire de noise_en que transmite el enable creado por el NIOS, wire de noise_pulse el cual transporta los pulsos de la salida noise_pulse del NIOS. 
 
 
Se conectan respectivamente con los periféricos de los modulos del NIOS y el de karplus, los cuales, en su gran mayoria, poseen un nombre muy parecido a su respectivo wire, como se observa en la siguiente figura:
 
Instanciamos ahora el modulo dac_nano, el cual emula un convertidor digital-análogo, conectamos a su entrada el wire guita_syn, con su bit mas significativo negado ya que este es el del signo, y su salida la conectamos a un pin de salida del GPIO.
 
Observamos el RTL del diseño para observar que todo halla quedado bien conectado, el resultado es el siguiente:
podemos observar que todo esta conectado de acuerdo a nuestros requerimientos, observemos a continuación lo que se ve en nuestro modulo de karplus strong en el RTL:
Esto se debe a que tenemos conectados dentro de el con solo el generate 500 flip flops, con los otros elementos se interconectan para producir este resultado.
 
Para terminar este diseño hardware se debe guardar todo y compilar el diseño, podemos ver el diseño hardware en el archivo DE0_NaNO_SOC_practica_nios2.qar que se encuentra en los archivos para descargar; nos dirigimos ahora a realizar nuestro código software
 
Software
abrimos el software de eclipse para NIOS II, creamos una nueva aplicacion and BSP from template
 
abrimos el archivo SOPC generado por el diseño hardware, le colocamos un nombre a nuestro proyecto y seleccionamos en project template a hello world y damos en finish.
 
Creamos nuestro proyecto, ahora vamos a nuestro proyecto, damos click derecho en el proyecto y elegimos en crear una nueva carpeta, la cual llamaremos karplus, en la que guardaremos los archivos .h y .c que vamos a utilizar.
 
en la carpeta que creamos hacemos click derecho y creamos un nuevo header file, luego realizamos lo mismo con un source file, despues de crearlos cambiamos sus nombres por karplus.h y karplus.c respectivamente
 
 
abrimos el archivo karplus.h, en el cual vamos a incluir las librerías necesarias para este trabajo, en el también definimos cada una de las notas de las cuerdas con sus respectivos trastes según la tabla dada al principio y por ultimo definimos las funciones que vamos a utilizar; para ver la tabla completa definida de las notas mira el archivo https://github.com/Adrizcorp/ece10243upb2016/blob/master/Estudiantes/guillermo/solucion_guitarra/software/nios_2/karplus/karplus.h.
 
Teniendo en cuenta las funciones que vamos a utilizar abrimos el karplus.c, y en el vamos a definir cada cada función y describirlos, en el primero, inject_noise se realiza un for para inyectar el ruido a los 500 flip flops, y envía los pulsos de noise_pulse cada vez que envía un dato.
 
 
En la función init_karplus, se inicializan las variables y en la función de set_karplus_frequency se da la velocidad de muestreo de nuestro audio, para este caso sera de 44100Hz, por ultimo, en la función play tone se selecciona la nota, se indica el tiempo en mili-segundos de la duracion de la nota, 
 Por ultimo editamos el archivo hello_world.c, en ella incluimos nuestra libreria #include "./karplus/karplus.h", y en nuestro int main inicializamos con init_karplus y damos la frecuencia de muestreo con se_karplus_frequency, luego de esto en nuestro while infinito escribimos las notas y los tiempos deseados para producir una canción, en este caso tenemos la opción para  probar cada uno de los valores de la tabla, sonar la canción del himno de la alegría, o que suene a canción O Christmas Tree Tannenbaum.
 
Referencias: