Escrito por Guillermo Acevedo
 
Diseño
 
En esta practica desarrollaremos un filtro FIR en hardware, para este caso en especifico, realizaremos un filtro rechaza-banda para ventana Hamming entre 3000Hz y 13000Hz de orden 20 con una frecuencia de muestreo de 44100Hz, para lograr esto, utilizaremos el siguiente diseño:
Como observamos en la imagen, lo primero que tenemos que hacer es buscar el NCO en los open cores, y conectarlo a una ROM hecha en la FPGA para tomar diferentes valores de frecuencia, este tiene como salida una señal que simula una señal seno con la frecuencia deseada, utilizaremos un modulo llamado  waveform_gen, este esta escrito en VHDL, asi que realizamos la instanciación en verilog y lo instanciamos en nuestro modulo principal. Simulamos el modulo  waveform_gen y el resultado de el es:
 
Ver una señal análoga Modelsim parece difícil cuando se ve, pero en realidad se puede realizar fácilmente de la siguiente manera:
Para lograr esto, damos click derecho sobre la señal que queremos ver, escogemos la opcion de format y pinchamos en analog (automatic), para que automáticamente de el tamaño de la señal y no salga de los margenes que se nos da para dibujar la señal.
 
 
 
Creamos luego el modulo div_freq y colocamos en su entrada 31'd566, el cual hace referencia a una frecuencia de 44100Hz.
El siguiente es la ROM para las frecuencias que vamos a pasar para el NCO, para eso utilizamos el principio de la multiplexión de señales y las controlaremos por medio de los SW que tenemos en la tarjeta, para esto utilizamos la formula dada por el creador del modulo waveform_gen para generar las frecuencias.
Dependiendo de la señan de los sw sale una valor que es enviado al NCO para producir las señales senoidales
 
 
 
Procedemos ahora a crear nuestro modulo FIR, para el cual, debemos obtener primero los coeficientes del filtro en Matlab, para ello utilizaremos el código de FIR SW Design, este nos da unos coeficientes entre 0 y 1, nosotros tenemos que escalarlos para ingresarlos facilmente en la FPGA y no trabajar con decimales, utilizaremos para este caso un escalonaje de 8 bits, es decir, multiplicaremos los valores dados anteriormente por 256, es decir 2^8. El filtro hecho con Matlab queda como:
Con coeficientes de 
-0,00148636112047322 0,000610781534272632 -0,00669201059088164 -0,00275624156299243 0,0303606416472069 0,0219128277898686 0,00449108715728677 0,132599993943691 0,179821495619680 -0,165922289863956 0,543677517903215 -0,172948355895413 0,195655602021611 0,151061333326642 0,00538349072957317 0,0278386935227264 0,0412726372637053 -0,00404892024397716 -0,0105945089674328 0,000972578512282662 -0,00186606153195758
respectivamente
al escalonar estas variables, el resultado es:
 
Como podemos observar en la imagen, se desplaza el filtro en su magnitud en dB, sus coeficientes quedan:
 0     0     1     0    -3    -6     2    15    13    -9   233    -9    13    15     2    -6    -3     0     1     0     0
respectivamente
 
Ya que hay números negativos, tenemos que pasar todo a complemento a 2 y a hexadecimal, haciendo esto, nos quedan los valores:
0000    0000    0001    0000    FFFD    FFFA    0002    000F    000D    FFF7    00E9    FFF7    000D   000F    0002    FFFA    FFFD    0000    0001    0000     0000
respectivamente  
Guardamos esto en un archivo llamado coef.txt, el cual utilizaremos mas adelante.
 
Creamos nuestro modulo fir, con sus respectivas señales de entrada y salida:
 
Necesitamos un clk, una entrada de audio, que es por donde entra nuestra señal senoidal, audio_out es nuestra salida, los coef, que son para ingresar coeficientes desde el NIOS II, pero aqui no se hablara de eso, y una entrada para los SW.
Se crean registros para la entrada de los valores senoidales, ya que son 21 coeficientes, solo pueden haber 21 valores en los registros de entrada, se crean 2 cables para realizar en ellos las operaciones correspondientes.
 
 
Debemos llegar a este diseño, que es como funciona este tipo de filtros:
Donde z^-1 significa un retardo, es decir, el dato anterior de la entrada, y en los amplificadores se colocan los valores de los coeficientes hallados anteriormente, luego de esto, se realiza la suma de todos los valores hasta llegar a un valor final, como el filtro es de orden 20 tenemos 21 coeficientes, es decir, tendremos 21 retardos, 21 amplificadores y 20 sumas.
Seguido a esto, inicializamos los coeficientes, para eso utilizaremos initial $readmemh para leer un archivo, entonces colocamos:
 
 
Luego de eso, inicializamos los valores de la dirección [0] de los registros y de los cables, es decir, vamos a tomar los valores en la entrada del NCO cada pulso de reloj, también tomaremos los de coef. En el caso de multi[0] va a ser igual al valor de la entrada en la posicion [0] por el valor del coef en la direccion [0], y sum[0] sera multi de la posición [20] +multi de la posición [19], el valor de la suma [19] que sera la ultima, sera la salida del sistema escalada 8 bits, es decir, la salida no tomara los 8 bits menos significativos que serian los 256 que multiplicamos al escalar en Matlab.
 
Ahora utilizamos los generate para realizar las asignaciones, donde vamos a realizar las sumas, de la suma anterior con la siguiente multiplicación en el primer generate y en el segundo se pasa el valor del registro al siguiente registro y borra el ultimo valor, para los valores de la seniodal y para los coeficientes.
 
Luego instanciamos en verilog nuestro modulo y lo pegamos en nuestro modulo principal
 
Se crean algunos cables, como el de clk_44100 que es el que lleva la señal de la salida del div_freq al FIR, el cable seno transporta transporta la señal de salida del NCO,  audio_out_fir, es la salida del FIR y se conecta al multiplexor, el cual dependiendo del estado del KEY[0] deja pasar la señal de salida del FIR o la del NCO.
 
Para finalizar debemos instanciar el modulo del dac, y conectar los cables de entrada del multiplexor y su salida seria la frecuencia analogica.
 
Por ultimo, tenemos la simulación del filtro, en Modelsim, en la cual tenemos un modulo con la generación de la señal seno, la selección de la frecuencia, para alguna de las guardadas en la ROM, y tenemos el filtro, el cual, como podemos observar en la siguiente figura, tenemos una onda seno con diferentes frecuencias, podemos observar que sus amplitudes son las mismas, cuando observamos la señal filtrada, nos damos cuenta de que los valores de las frecuencias son iguales, pero dependiendo de la frecuencia utilizada la señal se atenúa, cuando tenemos un 110 en la señal del SW, obtenemos la máxima atenuación, cabe resaltar que se puede llegar a mejores resultados si se utiliza otro tipo de ventana, si aumentamos la precisión o si aumentamos el numero de bits en el escalamiento.
 
En el siguiente link podrán encontrar los diferentes archivos utilizados en esta practica, el programa completo con los módulos en un .qar de quartus, el archivo de los coeficientes en un .txt y el archivo de Matlab con el cual se tomaron los coeficientes, y el código utilizado para la simulación del filtro. https://github.com/Adrizcorp/ece10243upb2016/tree/master/Estudiantes/guillermo/archivos_FIR
 
 
 
 
 
 
Referencias

 

 Written By Juan David Delgado
 
FILTRO FIR (FILTRO DE RESPUESTA FINITA AL IMPULSO)
 
 
Son conocidos como filtros digitales no recursivos debido a que no poseen la retroalimentación que es la parte recursiva de un filtro. Pueden ser diseñados usando diferentes métodos, pero la mayoría de ellos esta diseñado a la aproximación del filtro ideal. El objetivo no es lograr un filtro idea, ya que es casi imposible, la idea es lograr la mayor cantidad de características buenas posibles. La función de transferencia del filtro FIR se aproxima al ideal a medida de que el orden del filtro aumenta, pero asi mismo aumenta la complejidad y la cantidad de tiempo necesaria para procesar las muestras de entrada de la señal que es filtrada. 
 
               
 
El resultado de respuesta en frecuencia puede ser una función monótona o una función osciladora con cierto rango de frecuencia. La forma de onda de la respuesta en frecuencia depende del método usado en el proceso de diseño así como también de los parámetros usados.
 
Existen varios métodos usados para diseñar los filtros FIR, el mas comun es el metodo de la ventana porque es simple y eficiente, el metodo de muestreo de frecuencia es facil de usar, pero tiene una atenuación baja el la banda de detención. 
 
 
DISEÑO
 
Para poder diseñar este tipo de filtro primero se deben tener claros ciertos conceptos.
 
 
                Tipos de Filtro
  • Filtro Pasa Bajo (Low-Pass Filter): Este tipo de filtro se caracteriza por permitir el paso de las frecuencias más bajas y atenuar las frecuencias más altas.
  • Filtro Pasa Alto (High-Pass Filter): Este tipo de filtro se caracteriza porque en su respuesta en frecuencia se atenúan las componentes de baja frecuencia y permite el paso en alta frecuencia.
  • Filtro Pasa Banda (Band-Pass Filter): Este filtro se caracteriza por dejar pasar un determinado rango de frecuencias de una señal y atenúa el paso del resto.
  • Filtro Rechaza Banda (Band-Stop Filter): Este filtro no permite el paso de señales cuyas frecuencias se encuentran comprendidas entre las frecuencias de corte superior e inferior.
 
Dependiendo del filtro se debe tener en cuenta dos posibilidades:
 
  • Pasa Bajo:  
 
  • Pasa Alto
 
  • Pasa Banda:
 
  • Rechaza Banda:
 
                Tipos de Ventana
  • Bartlett: Entrega un punto L en la ventana en la columna del vector w, L debe ser un entero positivo. Los coeficientes de la ventana se pueden calcular: 
 
  • Hann: Devuelve un punto L simetrico en la columna del vector w, L debe ser un entero positivo. Los coeficientes pueden ser calculados: 
  • Bartlett-Hanning: Esta ventana tiene un lóbulo principal en el origen y descomposición asintóticamente en los lóbulos laterales en ambos lados. Es una combinación lineal tabulada de las ventanas Bartlett y Hann con lóbulos laterales más bajos que Bartlett y Hann y con lóbulos laterales mucho más bajo que tanto Bartlett y ventanas de Hamming.
 
 
 
  • Hamming: Los coeficientes de la ventana de Hamming se pueden calcular con la siguiente ecuación:
 
  • Bohman: Es la convolución de la media duracion de dos lobulos cosenoidales. En el dominio del tiempo, es el producto de una ventana triangular y un ciclo sencillo de un coseno con un termino añadido para fijar la primera derivada a cero en el limite. Los coeficientes se pueden calcular:
 
  • Blackman: Los coeficientes se pueden calcular:
 
 
  • Blackman-Harris: La ventana es mínima cuando los lóbulos laterales se hacen mínimos. Los coeficientes se pueden calcular:
                    Cuando es simétrico:
 
                    Cuando es periódico: 
 
 
 
 
Una vez se tengan estos conceptos claros, se procede a diseñar el filtro en MATLAB.
 
  • La primera parte del código consiste en asignar los parámetros que se usaran en el filtro. Entonces para empezar limpiamos todo lo que se tenia antes para evitar problemas, luego si se procede a asignar los parámetros.
        
                       
 
  • La segunda parte del codigo consiste en establecer que tipo de ventana y que tipo de filtro se usaran.
  • La tercera parte es diseñar el filtro que usaremos, el funcionamiento que debe seguir el filtro se muestra en la siguiente imagen
La señal X[n] entra a un vector temporal Z, el cual ira multiplicandose con los coeficientes generados dependiendo del tipo de ventana y de filtro, y la señal de salida sera la sumatoria respectiva de la sumatoria de estas multiplicaciones. Este procedimiento se lleva a cabo en un ciclo, empezando desde que solo se llena una posición de cada vector hasta que todos los datos de la señal de entrada han entrado.
 
El código es el siguiente:
 
Los vectores "y" "h" "m" se inicializan todos en ceros.
 
 
Ejercicio:
 
Diseñe un filtro rechaza banda que elimine el ruido de la canción a una frecuencia de muestreo de 44100 Hz, el orden del filtro es 70. Use la ventana de Hamming. 
 
Código:
 
 
En esta primera parte del código se declararon los parámetros que se usaran en el proceso de filtración del audio. Se declaro la frecuencia de corte mínima y la frecuencia de corte máxima que es la que permitirá filtrar el ruido existente entre esas frecuencias. Se estableció también el valor de la frecuencia de de muestre, también el valor de el orden del filtro, que recordando debe ser par.
 
 
En la linea 17 del código la ecuación del w(i) se usa la del tipo de ventana Hamming, en la linea 19 y 21 son las ecuaciones correspondientes al tipo de filtro que en este caso es un filtro rechaza banda. En la linea 23 se hace la multiplicación de la frecuencia del tipo de ventana con el valor correspondiente al filtro rechaza banda para generar los coeficientes del filtro. 
En la linea 29 se establece que la señal de entrada "x" sera la lectura de un archivo de audio, el cual podrá encontrar en el archivo Filtro.rar. ademas en la linea 32 se gráfica la señal entrante que se muestra en la imagen de la señal sin filtrar mas adelante.
 
En esta parte final se procede a filtrar la señal como se comento anteriormente y se gráfica la señal de salida "y" ya filtrada que se muestra en la imagen de a continuación. 
 
 
Como se observa en la figura, el ruido que existía antes de ser filtrada la señal desapareció luego del filtro.
 
En el vídeo se puede escuchar la señal sin filtrar

Vídeo de YouTube

 
Ahora se puede escuchar la señal filtrada
 

Vídeo de YouTube

AQUI encontrara la canción sin filtrar y el código en MATLAB para que lo pruebe y experimente con otros tipos de ventan y filtros.
 
 
Referecences:
 
 
Downloads:
By: Fabio Hernández
 

INTRODUCCIÓN:

 
El presente documento pretende mostrar la manera de generar software para una imagen de Linux implementada en la De0nano SOC, para ello se hará un pequeño marco teórico, luego se explicaran los recursos que se necesitan para realizar el tutorial y por ultimo se hará la explicación para generar un programa utilizando periféricos.
 
 
REQUERIMIENTOS:

 
 
MARCO TEÓRICO:
 
  • ARM CORTEX A9:  El procesador ARM Cortex-A9 tiene arquitectura RISC (Reduced Instruction Set Computer). Esta aritmética y operadores lógicas se realizan a través de registros de propósito general. Los datos se mueven entre la memoria y estos registros por medio de instrucciones de carga y almacenamiento.
    El tamaño de las palabras del procesador es de 32 bits, donde el bit más significativo es el que se encuentra mas a la izquierda y los menos significativos mas a la derecha de la palabra.
Actualmente la arquitectura ARM, con diseños en los que se integran más de 30.000 transistores, está presente en un gran número de dispositivos electrónicos utilizados por usuarios particulares y profesionales, y a diario se venden más de 16 millones de productos basados en esta arquitectura de ARM Holdings. 
 
  • LINUX la palabra linux actualmente puede hacer referencia a un núcleo de sistema operativo o a un sistema operativo, dependiendo del contexto. Linux se empezó a crear en 1991 por un joven llamado Linus Torvalds quien mediante simples ideas y con la ayuda de muchas personas lanzó la versión 0.01 de Linux de manera gratuita y a través del tiempo paso de tener 10239 lineas de código a tener mas de 14000000 y su código fuente puede ser descargado de manera gratuita en la red. Linux es famoso por su terminal en la cual se introducen diferentes comandos para tener control del sistema operativo, entre los comandos mas importantes se encuentran:
      • CAT: cat (de concatenar), es una utilidad que nos permite visualizar el contenido de un archivo de texto sin la necesidad de un editor. Para utilizarlo solo debemos mencionarlo junto al archivo que deseamos visualizar: 
$ cat prueba.txt 
      • LS: ls (de listar), permite listar el contenido de un directorio o fichero. La sintaxis es:
$ ls /home/directorio ​
 
      • CD: cd (de change directory), es como su nombre lo indica el comando que necesitarás para acceder a una ruta distinta de la que te encuentras. Por ejemplo, si estas en el directorio /home y deseas acceder a /home/ejercicios, seria:
$ cd /home/ejercicios 
 
Si estas en el directorio /home y deseas acceder a /home/ejercicios, seria:
 
$cd ..
 
      • CP: cp ( de copy o copiar), copia un archivo o directorio origen a un archivo o directorio destino. Por ejemplo, para copiar el archivo prueba.txt ubicado en /home a un directorio de respaldo, podemos usar:
$ cp/home/prueba.txt /home/respaldo/prueba.txt
 
      • MV: mv (de move), mueve un archivo a una ruta específica, y a diferencia de cp, lo elimina del origen finalizada la operación. Por ejemplo:
$ mv /home/prueba.txt /home/respaldos/prueba2.txt
 
      • RM: rm (de remove), es el comando necesario para borrar un archivo o directorio. Para borrar el archivo prueba.txt ubicado en /home, ejecutamos:
$ rm /home/prueba.txt
 
 
Usted puede encontrar mas de 400 comandos en el siguiente enlace: 
http://blog.desdelinux.net/mas-de-400-comandos-para-gnulinux-que-deberias-conocer/


  • DESCRIPCIÓN DE LOS PERIFÉRICOS:  la siguiente imagen muestra los periféricos conectados a la Ciclone V SOC a los cuales se puede tener acceso mediante un sistema operativo que se implemente en el ARM. 
 
A continuación se explicara cada uno de ellos:

  • LTC 2x7 Headeres un header de 14 pines, que es usado principalmente para comunicaciones con tarjetas de la empresa Linear Technology. es conectado mediante puertos SPI Master e I2C del HPS, también se pueden usar como GPIO, SPI, o I2C con el HPS, la conexión entre el HPS y el LTC se muestra a continuación:
 
  • Push-buttons & LEDs: Similar a la FPGA, el HPS también tiene sus propios switchs, buttons, LEds que pueden ser controladas desde la programación interna del HPS. Tenga en cuenta que el push-button al que se puede tener acceso es llamado User push Button y el LED es llamado USER LED. Como se muestra en la imagen:
 
  • Gigabit Ethernet: La de0nano SOC soporta transferencias de datos vía Gigabit Ethernet a través de un chip externo Micrel KSZ9031RN PHY que soporta interfaces RGMII MAC, la conexión RJ-45-Ethernet Chip-HPS se muestra a continuación:
    •  
    • UART: La de0nano SOC tiene una interfaz UART conectada con el HPS. esta interfaz no soporta control de señales por HW. La interfaz física es implementada con un conversor UART-USB a través de un FT232R chip como se muestra a continuación:
  • Memoria DDR3: La memoria DDR3 tiene una capacidad de 1GB con un ancho de banda para datos de 32 bits, las señales deben ser conectadas a través de un controlador dedicado con una velocidad de 400 MHz.
 
  • Micro SD Card Socket: La de0nano SOC tiene una interfaz para una tarjeta Micro SD, con x4 lineas de datos. Esto sirve como un almacenamiento interno para el HPS, pero también puede servir como el boot de un sistema operativo como se hace en una Raspberry Pi. La siguiente imagen muestra la conexión entre la SD y el HPS.
 
 
 
  • MEMORY MAP CYCLONE V SOC:  El HPS de la Cyclone V SOC, maneja diferentes direcciones de memoria que van dirigidas directamente hacia los perifericos descritos anteriormente, para poder por ejemplo apagar y prender el User LED, usted debera apuntar a la dirección de memoría del User LED y escribir en el registro "1" o "0" dependiendo si lo desea apagar o prender, en la siguiente tabla se encuentran todas las direcciones de memoria de los diferentes periféricos:
 
Cada uno de los anteriores periféricos contiene diferentes puertos dentro del HPS, estos puertos se muestran a continuación:
 
De esta manera por ejemplo si se quiere encender el User LED se debe ir a la dirección de memoria del puerto GPIO 62,  esto se hace haciendo uso de los registros
de escritura y lectura propios  de la dirección de memoria correspondiente a los GPIOs, en este enlace se encuentra la descripción de los diferentes registros.
          
Si consultó el enlace se habrá dado cuenta que los registros de datos (valor) y su dirección (lectura o escritura) se modifican a través de dos registros específicos; el gpio_swporta_dr y el gpio_swporta_ddr.



La descripción de estos dos registros se muestra a continuación:


Usted puede ver la aplicación de lo explicado aquí.

 

DESARROLLO:

 
  • LINUX TEST:  
    • Lo primero que se debe realizar es verificar que la tarjeta SD esté insertada en la ranura correspondiente dentro en la De0nano SOC, esta SD tiene una imagen de Linux de fabrica, luego debe conectar el cable USB que antes conectaba para programar la FPGA en el puerto llamado UART, como se muestra en la siguiente imagen: 
 
    • Siguiente conectar el cable USB al computador, ir al administrador de dispositivos y tener el cuenta el número del nuevo puerto COM que se ha generado.
    • Luego abra el Putty y configure como se muestra en la siguiente imagen:
    • Inicie sesión como root, y escriba ls, esto mostrará los archivos que se encuentran en el directorio donde usted se encuentra
    •  Usted puede ver los dispositivos que se encuentran conectados al sistema operativo y su dirección de memoria en escribiendo lo siguiente
 
  • ECLIPSE DS-5 LICENSE: 
Antes de continuar con el tutorial, se debe activar alguna licencia para Eclipse DS-5, para ello siga los siguientes pasos:  
 
 
    • Abra Eclipse DS-5 y vaya a help--> ARM LICENSE MANAGER
 
    • De click en add license y seleccione como se muestra a continuación:
    • De click en Next y y pegue el número que se copió con anterioridad:
 
    •  Seleccione el Hardware mediante el cual se tiene conexión a internet (en este caso se esta conectado a una red Wi-Fi):
 
    • Cree una cuenta o ingrese con una cuenta ya existente y de click en finish:
    • Edite la licencia de acuerdo a sus necesidades y con esto ya tiene acceso a las características del programa necesarias para continuar el tutorial. 
      • Cree la cuenta usando el siguiente link, aveces el link para crear la cuenta no funciona en el formulario de la aplicacion.
 
  • FIRST HELLO WORLD:
    • Para ello debe abrir el programa Eclipse for DS-5 e ir a file--> New Project --> C project y seleccionar GCC 4X como se muestra en la siguiente imagen: 
    • Vaya a la carpeta del proyecto que se generó, dele click derecho --> properties  --> c/c++ build --> settings --> Includes y añada un nuevo path como se indica en la imagen: 
 
    • Vaya a la ruta donde se encuentra la carpeta Altera instalada y añada los directorios que se muestra a continuación:  
 
    • Ahora vaya a a miscellaneus y copie el texto -lm -lpthread y de click en ok como se muestra en la imagen: 

 
    • Agregue un nuevo archivo .c y llamelo main.c como se muestra a continuación: 
    • En el archivo main.c escriba el código que se muestra a continuación y construya el proyecto (Build project) : 
 
    • Usted habrá notado que se generó una nueva carpeta llamada binaries con un archivo binario principal, este archivo es el que se debe portar al sistema operativo con el fin de ejecutar el programa que hemos escrito, para ello vaya a la carpeta, usted puede encontrar la ruta del archivo como se muestra en la siguiente imagen:
 
    • Conecte el cable Ethernet de la De0nano SOC a la red, haga un Warm Reset al Linux y en Putty escriba ifconfig y copie la dirección ip que se muestra a continuación:
 
    • Vaya a Window --> Open Perspective --> Other y seleccione Remote System Explorer:
    • En Local de click Derecho --> New connection --> SSH Only --> y agregue la dirección IP copiada:
 
    • Es recomendable crear un contraseña de acceso al sistema operativo en la terminal de Linux desde el PuTTY como se muestra a continuación:
 
    • Vuelva al DS5 Eclipse, vaya al nuevo proyecto generado y abra la carpeta root, añada User ID root y la contraseña creada en el paso anterior: 
    •     Ahora en la carpeta Root usted tiene acceso a todo el sistema de ficheros de Linux, el siguiente paso es ejecutar el código anteriormente escrito en el sistema operativo, para ello hay dos caminos, el primero es copiar el archivo BSP que se creo anteriormente en la ruta home/root, cambiar los permisos a ejecutable, volver a PuTTY y desde allí ejecutar el programa como se muestra a continuación:
 
    • La otra manera es hacer un debug desde el DS5 Eclipse, para ello debe regresar a la c/c++ perspective, dar click derecho en el proyecto y ejecutar el Build configurations y configurar como se muestra a continuación:
 
    • Una vez de click en Debug se abrirá una nueva Perspectiva, desde allí de click en continue y rectifique que el programa se hallá ejecutado como se muestra a continuación:
 
 
 
  • ACCEDIENDO A GPIOS:
    • Lo primero que se debe hacer es crear un nuevo proyecto llamado ejemplo1 siguiendo los primeros cuatro pasos del item anterior:
    • En el main.c copie el siguiente Codigo

      /*
       * main.c
       *
       *  Created on: Jun 20, 2016
       *      Author: Holguer
       */
      
      #include <stdio.h> 					// Libreria encargada de printf y scanf, comunicaci�n serial
      #include <unistd.h>					// Libreria para realizar usleep (retardos)
      #include <fcntl.h>					// Libreria para realizar escritura y lectura de la memoria
      #include <sys/mman.h>				// Libreria para realizar mapeo de memoria
      #include "socal.h"					// Funciones para escritura en palabras de GPIOs
      #include "hps.h"					// Instancia las direcci�nes de GPIOs del HPS
      #include "alt_gpio.h"				// Configuracion de GPIOs
      #include "hwlib.h"					// Definici�n de hardware
      
      #define HW_REGS_BASE ( ALT_STM_OFST ) // Define HW_REGS_BASE como
      #define HW_REGS_SPAN ( 0x04000000 )   // Tama�o de la region de memoria
      #define HW_REGS_MASK ( HW_REGS_SPAN - 1 ) // enmascaramiento del tama�o de la region de memoria
      
      #define USER_IO_DIR     (0x01000000)
      #define BIT_LED         (0x01000000)
      #define BUTTON_MASK     (0x02000000)
      
      int main(int argc, char **argv) { //
      
      	void *virtual_base;
      	int fd;
      	uint32_t scan_input;
      	int i;
      	// map the address space for the LED registers into user space so we can interact with them.
      	// we'll actually map in the entire CSR span of the HPS since we want to access various registers within that span
      	if ((fd = open("/dev/mem", ( O_RDWR | O_SYNC))) == -1) { // open abre archivos abre la memoria RDWR de forma sincrona ir a consola cd dev -- ls aparece el mem el men contiene todo el elspacio qe el sistema operativo tiene acceso a travez del mmu que es el management memory unit
      		printf("ERROR: could not open \"/dev/mem\"...\n"); // si es -1 el dev men no existe y sale un error
      		return (1);
      	} // de lo contrario en fd se guarda el puntero que apunta a la direccion de dev/mem en fd se guarda ese valor
      
      	virtual_base = mmap( NULL, HW_REGS_SPAN, ( PROT_READ | PROT_WRITE),
      	MAP_SHARED, fd, HW_REGS_BASE); // mapea el mapa de memoria  y se limita para que no tenga acceso a otro lugar con mmap cuyos argumentos se pueden ver en la funcion---vamos a escribir o leer, map_shared significa que es una memoria compartida, fd direccion de memoria, hw_regs_base empiezan registros de perifericos todos inician en fc
      
      	if (virtual_base == MAP_FAILED) {  // si falla envia error
      		printf("ERROR: mmap() failed...\n");
      		close(fd);
      		return (1);
      	}
      	// initialize the pio controller
      	// led: set the direction of the HPS GPIO1 bits attached to LEDs to output
      	alt_setbits_word(
      			( virtual_base + ( ( uint32_t )( ALT_GPIO1_SWPORTA_DDR_ADDR ) & ( uint32_t )( HW_REGS_MASK ) ) ),
      			USER_IO_DIR);
      	int numero_flashes = 0;
      	int delay = 300;
      	/*if (argc > 1) { // argumento del main
      		if (argc > 2) {
      			sscanf(argv[2], "%d", &delay);
      		} else {
      			sscanf(argv[1], "%d", &numero_flashes);
      		}
      	} else {
      		printf("please use the next input style: ./ejemplo_gpio3 #flashes \n");
      		printf("or input style: ./ejemplo_gpio3 #flashes #delay \n");
      	}*/
      
      	printf("led test\r\n");
      	printf("the led flash 2 times\r\n");
      	for (i = 0; i < 2; i++) {
      		alt_setbits_word(
      				( virtual_base + ( ( uint32_t )( ALT_GPIO1_SWPORTA_DR_ADDR ) & ( uint32_t )( HW_REGS_MASK ) ) ),
      				BIT_LED);
      		usleep(delay * 1000);
      		alt_clrbits_word(
      				( virtual_base + ( ( uint32_t )( ALT_GPIO1_SWPORTA_DR_ADDR ) & ( uint32_t )( HW_REGS_MASK ) ) ),
      				BIT_LED);
      		usleep(delay* 1000);
      	}
      
      	printf("user key test \r\n");
      	printf("press key to control led\r\n");
      	while (1) {
      		scan_input =
      				alt_read_word(
      						( virtual_base + ( ( uint32_t )( ALT_GPIO1_EXT_PORTA_ADDR ) & ( uint32_t )( HW_REGS_MASK ) ) ));
      		//usleep(1000*1000);
      		if (~scan_input & BUTTON_MASK)
      			alt_setbits_word(
      					( virtual_base + ( ( uint32_t )( ALT_GPIO1_SWPORTA_DR_ADDR ) & ( uint32_t )( HW_REGS_MASK ) ) ),
      					BIT_LED);
      		else
      			alt_clrbits_word(
      					( virtual_base + ( ( uint32_t )( ALT_GPIO1_SWPORTA_DR_ADDR ) & ( uint32_t )( HW_REGS_MASK ) ) ),
      					BIT_LED);
      	} */
      	// clean up our memory mapping and exit
      	if (munmap(virtual_base, HW_REGS_SPAN) != 0) {
      		printf("ERROR: munmap() failed...\n");
      		close(fd);
      		return (1);
      	}
      
      	close(fd);
      	return (0);
      }
      

       

    • Modifique el hwlib.h como se muestra en la siguiente imagen:
    • Genere el proyecto (Build proyect) y ejecutelo siguiendo los pasos descritos anteriormente:
    • El resultado se muestra en el siguiente video:

Vídeo de YouTube

    • Ahora haga las siguientes modificaciones:
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include "socal.h"
#include "hps.h"
#include "alt_gpio.h"
#include "hwlib.h"

#define HW_REGS_BASE (ALT_STM_OFST)
#define HW_REGS_SPAN (0x04000000)
#define HW_REGS_MASK (HW_REGS_SPAN - 1)

#define USER_IO_DIR (0x01000000)
#define BIT_LED (0x01000000)
#define BUTTON_MASK (0x02000000)

#define LED_SET() alt_setbits_word((virtual_base + ((uint32_t)(ALT_GPIO1_SWPORTA_DR_ADDR) & (uint32_t)(HW_REGS_MASK))), BIT_LED)
#define LED_CLR() alt_clrbits_word((virtual_base + ((uint32_t)(ALT_GPIO1_SWPORTA_DR_ADDR) & (uint32_t)(HW_REGS_MASK))), BIT_LED)
#define READ_KEY() alt_read_word((virtual_base + ((uint32_t)(ALT_GPIO1_EXT_PORTA_ADDR) & (uint32_t)(HW_REGS_MASK))))

int main(int argc, char **argv)
{

    void *virtual_base;
    int fd;
    uint32_t scan_input;
    int i;
    // map the address space for the LED registers into user space so we can interact with them.
    // we'll actually map in the entire CSR span of the HPS since we want to access various registers within that span
    if ((fd = open("/dev/mem", (O_RDWR | O_SYNC))) == -1)
    {
        printf("ERROR: could not open \"/dev/mem\"...\n");
        return (1);
    }

    virtual_base = mmap(NULL, HW_REGS_SPAN, (PROT_READ | PROT_WRITE), MAP_SHARED, fd, HW_REGS_BASE);

    if (virtual_base == MAP_FAILED)
    {
        printf("ERROR: mmap() failed...\n");
        close(fd);
        return (1);
    }
    // initialize the pio controller
    // led: set the direction of the HPS GPIO1 bits attached to LEDs to output
    alt_setbits_word((virtual_base + ((uint32_t)(ALT_GPIO1_SWPORTA_DDR_ADDR) & (uint32_t)(HW_REGS_MASK))), USER_IO_DIR);

    int numero_flashes = 0;
    int delay = 100;

    if (argc > 1)
    {
        sscanf(argv[1], "%d", &numero_flashes);
        if (argc > 2)
        {
            sscanf(argv[2], "%d", &delay);
        }
    }
    else
    {
        printf("Please use the next input style: ./%s #flashes\n", argv[0]);
        printf("or use the next input style: ./%s #flashes delay\n", argv[0]);
        return 0;
    }

    printf("led test\r\n");
    printf("the led flashes %d times\r\n", numero_flashes);
    for (i = 0; i < numero_flashes; i++)
    {
        LED_SET();
        usleep(delay * 1000);
        LED_CLR();
        usleep(delay * 1000);
    }
    /*printf("user key test \r\n");
printf("press key to control led\r\n");
while(1){
scan_input =READ_KEY();
//usleep(1000*1000);
if(~scan_input&BUTTON_MASK){
LED_SET();
}
else{
LED_CLR();
}
}*/

    // clean up our memory mapping and exit
    if (munmap(virtual_base, HW_REGS_SPAN) != 0)
    {
        printf("ERROR: munmap() failed...\n");
        close(fd);
        return (1);
    }
    close(fd);
    return (0);
}
 
    • Vuelva a generar el proyecto (Build Proyect) y ejecútelo, el resultado se muestra a continuación:

Vídeo de YouTube

 
 

Escrito por: Alix Angarita


 
En el manual a continuación se explica un método de debug adicional que es muy interesante debido a que no requiere programación, ya que sólo utiliza comandos.
Ésta herramienta es System Console.
 
¡Recuerde tener abierto el proyecto al que le quiere hacer debug!.  El que se usó en esta ocasión está en la sección de archivos, o lo puede descargar aquí.  
Luego vaya a Tools > System Debugging Tools > System Tools.
 
 
Se abrirá la ventana del System Console así:
 
 
Fíjese en el System Explorer, el panel de la izquierda.  Si aparece como en la pantalla revise la conexión de la FPGA a su PC, asegúrese de que esté conectada en el puerto JTAG.
Cuando se encuentre correctamente conectada presione el botón Refresh Connections.
 
Ahora la ventana debería mostrarse correctamente, el System Explorer se mostrará ahora así:
 
                
 
En la nueva vista del System Explorer se revisa el directorio soc_system para identificar los periféricos conectados al JTAG, estos son aquellos a los cuales vamos a poder acceder usando la Tcl Console el cuál funciona de manera similar a la terminal de Linux.
 
En este momento podemos empezar el debug, para ello vamos a la consola y digitamos lo siguiente:
 
 
Cuando digite el comando deben aparecer dos paths, de los cuales nos interesa el phy_0, con el siguiente comando podemos elegirlo
 
 
A continuación se crea una variable de entorno llamada jd_path, se manda un streaming de datos con list, dentro de corchetes cuadrados se ponen los elementos.
 
 
Se solicitan los master con este comando, y se ven dos disponibles, uno de la fpga y otro de el hps.
 
 
Igual que al elegir el path se elige el master, que en este caso será el de la FPGA.  Se reclaman el path y se apunta para escribir y leer en los periféricos vistos antes.  
 
 
Ahora escribiremos en los leds aprovechando esta herramienta, pero para ello se requiere la dirección específica del puerto, para ello se retorna al Qsys y se revisan las características del periférico, en este caso:
 
 
Usando el comando master_write_32, y la variable de entorno c_path, se copia la dirección en la cual se quiere escribir y a continuación el valor que se quiere escribir.  Recordar que los espacios son clave para ejecutar los comandos correctamente.
 
Y ya con esto debería mostrarse el número indicado en la FPGA, en este caso sólo el último led encendería.  Pruebe escribiendo un valor diferente, por ejemplo si escribimos el valor 0xF0 los leds encenderían de la siguiente manera:
 
 
De la misma manera con el comando master_read_32 y la dirección de los switches se puede leer su estado:
 
 
Por ejemplo, si pone los switches en la posición de la imagen, al ejecutar el comando debería obtenerse algo como se muestra en la siguiente imagen.
 
 
 
 
¡Así de sencillo es interactuar con la System Console para hacer debug de un proyecto con HPS muy fácilmente!
 
 
 
 
 
 
 
 
 
Summary Written by Fabio Hernandez
 
HARD PROCESSOR SYSTEM (HPS)
 
 
-------------------------------------------------------------------------------------------------------------------------------------------------
 
Introducción
 
Tenemos 2 nuclos de procesamiento ARM cortex-A9,cada uno son su propio cache 
se tienen un cache intermediario,segunda etapa de chache un poco mas grande que se comparten.
se tienen perifericos GPIO,Ethernet un periferico destinado SPI,UART,TIMERs,JTAG,DMA...
 
Tenemos una interconeccion por medio de buses de datos que se conectan a la fpga
se puede conectar por medio de una interconeccion similar a la avalon, se transmiten datos del HPS ala FPGA y de la FPGA al HPS.
Podemos configurar directamente la FPGA directamente por medio del procesador ARM
Podemos hacer que los perifericos salgan a los pines de la FPGA.
 
El ARM tiene canales de comunicación que son Master se llaman axi, los canales axi tienen un ancho de banda dependiendo del canal que se utilice.
 
HPS-TO-FPGA esta destinado para que el HPS se comunique directamente ala FPGA alcanzando un rendimiento bastante alto y un ancha de banda bastante grande, podemos trasmitir datos de hasta 128 bits
FPGA-TO-HPS esta destinado para trasmitir datos de la FPGA al procesador tambien de un ancho de 128 bits
se tiene otro bus de datos de bajo rendimiento (lightweight), bi-direccional de 32 bits.
 
 
 
 
 
 
1.HPS FEATURES
 
 
 
 
2.SYSTEM MANAGEMENT
 

  • CLOCKS Y CLOCK MANAGER 
 


 

 
 


 
 
 
 


 



 
 


 
 
 

  • RESETS AND RESET MANAGER





 
 
 

  • FPGA MANAGER



 

 
 
 

  • SYSTEM MANAGER


 

 

 
 
 
 

  • SCAN MANAGER

 

 

  • SECURITY MANAGER




 


3.INTERCONNECT












 
4.MEMORY AND MEMORY CONTROLLERS
 














 

5.DMA CONTROLLER




 

Vídeo de YouTube