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.

tabla tomada de: https://people.ece.cornell.edu/land/courses/ece5760/FinalProjects/f2009/kr334_ask43/kr334_ask43/kr334_ask43/index.html
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]

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:


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:


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.
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.

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.



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.

Para ver el programa completo puedes descargarlo en: https://github.com/Adrizcorp/ece10243upb2016/tree/master/Estudiantes/guillermo/solucion_himnodelaalegria_karplus_guitarra
Referencias: