Verilog: el puerto del receptor MIDI falla cuando se presionan más de dos teclas al mismo tiempo [cerrado]

1

Estoy diseñando un puerto de receptor MIDI (utilizando Altera CLPD MAX 7000S). El dispositivo muestrea el segundo byte que recibe y emite el valor binario en un LED. El dispositivo funciona bien cada vez que ingreso notas MIDI (usando el software MIDI-OX) a una velocidad normal. Sin embargo, siempre que ingrese notas demasiado rápido, o ingrese dos notas al mismo tiempo, no funciona correctamente (sale a LEDs incorrectos cada vez que ingrese cualquier nota).

Este es mi código Verilog. Muestreo el bit MIDI en el medio.

//using a 4MHz clock using a 31250bit/s baud rate (1 bit -> 32 us; all 10 bits -> 320us  -> 10.3 bits -> 11 bits)
module timer(input clk, input reset, input enable, output [10:0] out);
reg [10:0] timer;
initial timer = 11'b0;
assign out = timer;

always @(posedge clk) begin
    if(!reset)  //if reset is pressed, set timer back to 0
        timer <= 11'b00000000000;
    else if(enable == 1'b1) //if enable is high
            begin
                timer <= timer + 11'b00000000001; //increment counter every time
                if(timer == 11'b11111111111)     //if counter reaches max value (should never reach it)
                    timer <= 11'b00000000000; //set it back to 0
            end
    else
        timer <= 11'b00000000000; // if enable is low, set the timer to 0
end
endmodule


module rx(input clk, input reset, input in, output [7:0] out);

parameter IDLE = 2'b01;
parameter BYTE_CUR = 2'b10;
parameter BYTE_END = 2'b11;
parameter HIGH = 1'b1;
parameter LOW = 1'b0;

reg [7:0] LEDs;
initial LEDs = 8'b0;

reg [7:0] LED;
initial LED = 8'b0;
assign out = LED;


reg [1:0] state;
initial state = IDLE;

reg [2:0] byteNo; 
initial byteNo = 3'b000;

reg timer_en;
initial timer_en = 1'b0;

wire timer_en_wire;
assign timer_en_wire = timer_en;

wire [10:0] timer_wire;

timer t(.clk(clk), .reset(reset), .enable(timer_en_wire), .out(timer_wire)); 

always @(posedge clk) begin
    if(!reset)
    begin
        LEDs <= 8'b0;
        LED <= 8'b0;
        timer_en <= 1'b0;
        state <= IDLE;
        byteNo <= 3'b000;
    end 
    else begin
    if(state == IDLE && in == LOW) // if IDLE and detect a LOW on the input line, start bit has arrived
    begin
        state <= BYTE_CUR;  //change state to BYTE_CUR
        byteNo <= byteNo + 3'b001; // increment byteNo
        timer_en <= 1'b1; // enable the timer
    end
    if(state == BYTE_CUR) //currently a byte
    begin
        case(timer_wire)
            11'b00011000000: LEDs[7] <= in; // 1.5 BT
            11'b00101000000: LEDs[6] <= in; // 2.5 BT
            11'b00111000000: LEDs[5] <= in; // 3.5 BT
            11'b01001000000: LEDs[4] <= in; // 4.5 BT
            11'b01011000000: LEDs[3] <= in; // 5.5 BT
            11'b01101000000: LEDs[2] <= in; // 6.5 BT
            11'b01111000000: LEDs[1] <= in; // 7.5 BT
            11'b10001000000: LEDs[0] <= in; // 8.5 BT
            11'b10100000000: begin   // 10 BT
                state <= BYTE_END;
                timer_en <= 1'b0;
            end
        endcase
    end
    if(state == BYTE_END) //if byte has ended
    begin
        if(byteNo == 3'b010) // if byte number is 2, output the lights
        begin
            LED <= LEDs;
        end
        if(byteNo == 3'b101) // if byte number is 5, clear the output
        begin
            LED <= 3'b000;
        end
        if(byteNo == 3'b110) // if byte number is 6, reset byte counter to 0
        begin
            byteNo <= 3'b000;
        end
        state <= IDLE; //set state back to IDLE
    end
    end
end

endmodule
    
pregunta Rish

1 respuesta

3

Veo dos problemas potenciales.

En primer lugar, su entrada in es asíncrona a su reloj interno, por lo que debe sincronizarla antes de usarla en su máquina de estado. El problema específico involucra la transición de IDLE (codificado 2'b01 ) a BYTE_CUR (codificado 2'b10 ) - esto requiere que cambien ambas variables de estado, y la entrada asíncrona podría hacer que se evalúen de manera diferente, lo que resulta en una transición al estado 2'b00 o 2'b11 , que no es lo que pretendes.

Segundo, tienes este contador de tres bits llamado byteNo . (Por cierto, esto también se ve afectado adversamente por la entrada asíncrona). Parece que está asumiendo que cada mensaje tiene una longitud de 6 bytes, y que el número de la nota es el segundo byte del mensaje. No estoy seguro de dónde obtienes esto, no está en ninguna especificación MIDI que haya visto.

En general, los mensajes de canal tienen una longitud de 3 bytes, y comprenden un byte de estado (por ejemplo, "note on") y dos bytes de datos (por ejemplo, número de nota y velocidad). La mayoría de los dispositivos MIDI omitirán el segundo y los siguientes bytes de estado al enviar múltiples mensajes de "nota en" en rápida sucesión, lo que significa que podría estar mirando una secuencia de bytes como:

Note On | Note # | Vel. | Note # | Vel. | Note # | Vel. | ...

En otras palabras, necesita una máquina de estado mucho más sofisticada que haga un seguimiento del byte de estado más reciente y luego analice los bytes de datos subsiguientes en consecuencia.

    
respondido por el Dave Tweed

Lea otras preguntas en las etiquetas