Reproductor MIDI
David Antonio Montoya
Daniel 2rturo Silva
Daniel Steven Moncada
Contents |
[edit] Calificación
Porcentaje | Presentación 20% | Informe 30% | Funcionamiento 50% |
---|---|---|---|
1 Entrega 10% | 0.5 | 0.5 | 0.5 |
2 Entrega 30% | 1 | 1 | 0 |
3 Entrega 20% | 1 | 1 | 0 |
[edit] Descripción del formato MIDI
MIDI (de las siglas en inglés Musical Instruments Digital Interface) es un protocolo estandarizado para la comunicación entre dispositivos musicales (sintentizadores de audio, amplificadores, analizadores mucicales y software computacional). Hay varias formas en las que se puede dar un mensaje en formato MIDI, y a continuación se muestra:
Cada mensaje comienza con un byte de estatus, en donde el octavo bit (más significativo) es el bit de set. Después de esto, varios bytes de información se envían, en donde el bit más significativo siempre será cero. De acuerdo a esto, los bytes de información tienen valores de 7 bits (0-127 en decimal, 0x00-0x7F en hexadecimal), y los bytes de status siempre se encuentran en un rango entre 128-255 decimal, 0x80-0xFF hexadecimal.
Los mensajes MIDI deben cumplir estrictamente el tipo de mensaje, sólo exceptuando los mensajes exclusivos del sistema.
Ahora bien, los bytes del formado MIDI consisten en 10 bits, no en 8 bits como usualmente se arreglan los números binarios. Estos bits se envían a una velocidad de 31250 bits/segundo.
[edit] Diagrama de Bloques del proyecto:
Descripcion del proyecto
El proyecto consiste en un reproductor de formato MIDI (inicialmente). Para tal fin, utilizaremos la tarajeta de desarrollo SIE, que cuenta con periféricos tales como una FPGA Spartan 3E Xc3S500, y módulos para la memoria ram, un dispositvo NAND, además de puertos I/O.
Para poder llevar a cabo la reproducción del erchivo en formato MIDI, debemos guardar el archivo en la memoria (ya sea NAND, o la memoria RAM). En este punto, accederemos a las posiciones de memoria que contienen toda la inforamación del archivo. Después de esto,se envía la inforamción obtenida en la memoria a un controlador para el formato MIDI (previamente diseñado en lenguaj C) que decpdificará la información y la enviará a un conversor digital-analógico. Finalmente, la señal de audio saldrá por una etapa de potencia que amplificará la señal de salida.
Adicionalmente a esto, existe la posibilidad de aplicar un par de filtros: un filtro digital a la salida del controlador MIDI, y otro filtro analógico a la salida del conversor digital-analógico para atenuar cualquier ruido caracetrístico.
Finalmente, se implementará una interfaz gráfica, aprovechando el display LCD con el que cuenta la tarjeta de desarrollo SIE.
Descripción de tareas Hardware y Software:
Para poder llevar a cabo el proyecto, se deben dividir las tareas Software y las tareas Hardware. Como dispositivos periféricos principales tenemos un display LCD, una etapa de potencia, y por ende, un juego de periféricos que nos ayudarán a controlar la reproducción del archivo. (Play/pause, Stop, Fw, Rw); además de eso, los controladores necesarios para el uso de las memorias, ya sea la memoria flash NAND, o la memoria RAM.
Ahora bien, las tareas Software serán las propias del procesador, control de las señales de Read y Write, rutinas para llamados de interrupciones y su control, y todas las distintas señales de control para los demás dispositivos (procesador-módulo de control).
Software y hardware a utilizar en el proyecto.
El software necesario para realizar nuestro proyecto consiste en los siguientes programas: Ise Webpack: necesario para la compilación y síntesis de códigos en VHDL/Verilog. Códigos del procesador Plasma-Mips. (con códigos VHDL). Compilador de Linux GCC. Herramientas de software libre para la compilación de códigos en VHDL (GHDL) y para la simulación y su posterior visualización (GTKWave). Matlab: Resolución de dudas y posible creación de los filtros digitales. KiCad: Creación y simulación de la placa hija (PCB).
El hardware necesario para el montaje del proyecto es:
Tarjeta de desarrollo SIE. Tarjeta hija para la etapa de potencia. Display LCD (adjunto a la placa de desarrollo SIE). Controles para la reproducción.
Cronograma:
Semana | Fecha | Actividad |
---|---|---|
S1 | 16 - 22 de agosto | Comprension del Procesador Plasma |
S2 | 23 - 30 de agosto | Adquisición de Información |
S3 | 31 agosto- 06 septiembre | Edición de proyecto en la wiki www.qi-hadware.com |
S4 | 7 - 14 septiembre | Propuesta del Proyecto |
S5 | 15 - 22 septiembre | Elaboración de PCB tarjeta hija |
S6- S7 | 23 de septiembre - 8 octubre | Programación de Modulo del controlador MIDI |
S8 | 9 - 17 octubre | Programacion Modulo de Conversor Digital Análogo |
S9 | 18 - 25 octubre | Manejo de Visualización LCD |
S10 | 26 de octubre - 2 de noviembre | Implementacion tarjeta hija |
S11 | 3 - 10 de noviembre | Manejo de LCD |
S12 | 11 - 18 de noviembre | Pruebas Generales |
S13 | 19 - 26 de noviembre | Entrega final |
[edit] Hardware adicional
Para lograr amplificar sonido, debemos utilizar un conversor digital-analógico, de tal manera que las señales analógicas puedan ser amplificadas para ser reproducidas posteriormente. Para lograr esta conversión, utilizaremos un circuito integrado DAC 0808, cuya configuración básica nos permitirá obtener señales analógicas. Ahora bien, para amplificar estas señales, se plantea un montaje amplificador consistente en un amplificador operacional. El amplificador operacional a utilizar en este caso será un LM741. Finalmente, se utilizará un regulador de tensión que nos permitirá utilizar valores de 5V y de 3.3V en toda la placa, sin necesidad de fuentes adicionales (utilizaremos el circuito integrado LD1117S50).
[edit] Diagrama de flujo del controlador MIDI
[edit] Arquitectura del proyecto
[edit] Generador de ondas seno
Para poder convertir una señal digital a una onda de sonido, podemos utilizar un generador de ondas seno, creado en VHDL. Para obtener la frecuencia deseada en nuestro generador de senos, utilizamos la siguiente ecuación:
A continuación se muestra la tabla de los valores obtenidos:
El código se muestra a continuación, y la simulación también.
library ieee; use ieee.std_logic_1164.all; use IEEE.STD_LOGIC_arith.all; use IEEE.STD_LOGIC_unsigned.all; use work.sine_lut_pkg.all; package dds_synthesizer_pkg is component dds_synthesizer generic( ftw_width : integer ); port( clk_i : in std_logic; rst_i : in std_logic; ftw_i : in std_logic_vector(ftw_width-1 downto 0); phase_i : in std_logic_vector(PHASE_WIDTH-1 downto 0); phase_o : out std_logic_vector(PHASE_WIDTH-1 downto 0); ampl_o : out std_logic_vector(AMPL_WIDTH-1 downto 0) ); end component; end dds_synthesizer_pkg; package body dds_synthesizer_pkg is end dds_synthesizer_pkg; -- Entity Definition library ieee; use ieee.std_logic_1164.all; use IEEE.STD_LOGIC_arith.all; use IEEE.STD_LOGIC_unsigned.all; use work.sine_lut_pkg.all; entity dds_synthesizer is generic( ftw_width : integer := 32 ); port( clk_i : in std_logic; rst_i : in std_logic; ftw_i : in std_logic_vector(ftw_width-1 downto 0); phase_i : in std_logic_vector(PHASE_WIDTH-1 downto 0); phase_o : out std_logic_vector(PHASE_WIDTH-1 downto 0); ampl_o : out std_logic_vector(AMPL_WIDTH-1 downto 0) ); end dds_synthesizer; architecture dds_synthesizer_arch of dds_synthesizer is signal ftw_accu : std_logic_vector(ftw_width-1 downto 0); signal phase : std_logic_vector(PHASE_WIDTH-1 downto 0); signal lut_in : std_logic_vector(PHASE_WIDTH-3 downto 0); signal lut_out : std_logic_vector(AMPL_WIDTH-1 downto 0); signal lut_out_delay : std_logic_vector(AMPL_WIDTH-1 downto 0); signal lut_out_inv_delay : std_logic_vector(AMPL_WIDTH-1 downto 0); signal quadrant_2_or_4 : std_logic; signal quadrant_3_or_4 : std_logic; signal quadrant_3_or_4_delay : std_logic; signal quadrant_3_or_4_2delay : std_logic; begin phase_o <= phase; quadrant_2_or_4 <= phase(PHASE_WIDTH-2); quadrant_3_or_4 <= phase(PHASE_WIDTH-1); lut_in <= phase(PHASE_WIDTH-3 downto 0) when quadrant_2_or_4 = '0' else conv_std_logic_vector(2**(PHASE_WIDTH-2)-conv_integer(phase(PHASE_WIDTH-3 downto 0)), PHASE_WIDTH-2); ampl_o <= lut_out_delay when quadrant_3_or_4_2delay = '0' else lut_out_inv_delay; process (clk_i, rst_i) begin if rst_i = '1' then ftw_accu <= (others => '0'); phase <= (others => '0'); lut_out <= (others => '0'); lut_out_delay <= (others => '0'); lut_out_inv_delay <= (others => '0'); quadrant_3_or_4_delay <= '0'; quadrant_3_or_4_2delay <= '0'; elsif clk_i'event and clk_i = '1' then ftw_accu <= ftw_accu + ftw_i; phase <= ftw_accu(ftw_width-1 downto ftw_width-PHASE_WIDTH) + phase_i; if quadrant_2_or_4 = '1' and phase(PHASE_WIDTH - 3 downto 0) = conv_std_logic_vector (0, PHASE_WIDTH - 2) then lut_out <= conv_std_logic_vector(2**(AMPL_WIDTH - 1) - 1, AMPL_WIDTH); else lut_out <= sine_lut(conv_integer(lut_in)); end if; quadrant_3_or_4_delay <= quadrant_3_or_4; quadrant_3_or_4_2delay <= quadrant_3_or_4_delay; lut_out_inv_delay <= conv_std_logic_vector(-1*conv_integer(lut_out), AMPL_WIDTH); lut_out_delay <= lut_out; end if; end process; end dds_synthesizer_arch;
A continuación se muestra el testbench del código:
library ieee; use ieee.std_logic_1164.all; use IEEE.STD_LOGIC_arith.all; use IEEE.STD_LOGIC_unsigned.all; use work.dds_synthesizer_pkg.all; use work.sine_lut_pkg.all; entity dds_synthesizer_tb is generic( clk_period : time := 10 ns; ftw_width : integer := 32 ); end dds_synthesizer_tb; architecture dds_synthesizer_tb_arch of dds_synthesizer_tb is signal clk,rst : std_logic := '0'; signal ftw : std_logic_vector(ftw_width-1 downto 0); signal init_phase : std_logic_vector(phase_width-1 downto 0); signal phase_out : std_logic_vector(phase_width-1 downto 0); signal ampl_out : std_logic_vector(ampl_width-1 downto 0); begin dds_synth: dds_synthesizer generic map( ftw_width => ftw_width ) port map( clk_i => clk, rst_i => rst, ftw_i => ftw, phase_i => init_phase, phase_o => phase_out, ampl_o => ampl_out ); init_phase <= (others => '0'); ftw <= conv_std_logic_vector(2147483,ftw_width); --20us period @ 100MHz, ftw_width=32 clk <= not clk after clk_period/2; rst <= '1','0' after 2*clk_period; end dds_synthesizer_tb_arch;
Ahora bien, se presenta la simulación del código, que presenta una onda seno:
[edit] Mapa de memoria
A continuación se muestra el código correspondiente al mapa de memoria:
//*-------------------------------------------------------------------- * TITLE: Plasma Hardware Defines * AUTHOR: Steve Rhoads (rhoadss@yahoo.com) * DATE CREATED: 12/17/05 * FILENAME: plasma.h * PROJECT: Plasma CPU core * COPYRIGHT: Software placed into the public domain by the author. * Software 'as is' without warranty. Author liable for nothing. * DESCRIPTION: * Plasma Hardware Defines *--------------------------------------------------------------------*/ #ifndef __PLASMA_H__ #define __PLASMA_H__ /*********** Hardware addesses ***********/ #define RAM_INTERNAL_BASE 0x00000000 //8KB #define RAM_EXTERNAL_BASE 0x10000000 //1MB #define RAM_EXTERNAL_SIZE 0x00100000 #define UART_BASE 0x20000000 #define UART_WRITE 0x20000000 #define UART_READ 0x20000000 #define UART_STATUS 0x20000010 #define IRQ_MASK 0x20000010 #define IRQ_STATUS 0x20000020 #define dds_synthesizer 0X20000030//Generador de ondas senoidales. #define visualizacion 0x20000040//LCD. #define Controles 0x20000050//Controles de reproducción (FW, RW, STOP, PAUSE). #define Peripheric_4 0x20000060 #define ETHERNET_REG 0x20000070 #define FLASH_BASE 0x30000000 /*********** GPIO out bits ***************/ #define ETHERNET_MDIO 0x00200000 #define ETHERNET_MDIO_WE 0x00400000 #define ETHERENT_MDC 0x00800000 #define ETHERNET_ENABLE 0x01000000 /*********** Interrupt bits **************/ #define IRQ_UART_READ_AVAILABLE 0x01 #define IRQ_UART_WRITE_AVAILABLE 0x02 #define IRQ_COUNTER18_NOT 0x04 #define IRQ_COUNTER18 0x08 #define IRQ_ETHERNET_RECEIVE 0x10 #define IRQ_ETHERNET_TRANSMIT 0x20 #define IRQ_GPIO31_NOT 0x40 #define IRQ_GPIO31 0x80 /*********** Ethernet buffers ************/ #define ETHERNET_RECEIVE 0x13ff0000 #define ETHERNET_TRANSMIT 0x13fe0000 #endif //__PLASMA_H__