You dont have javascript enabled! Please enable it!

Caso práctico: control RUN/STOP por voz con ULX3S

Caso práctico: conmutar RUN/STOP por voz en ULX3S — hero

Objetivo y caso de uso

Qué construirás: Un detector compacto de ráfagas de actividad de voz en FPGA sobre una Radiona ULX3S (Lattice ECP5-85F) usando un micrófono MEMS I2S INMP441. Una ráfaga hablada corta y fuerte como “go” o “stop” conmuta una salida de estado de banco entre RUN y STOP con baja latencia y lógica completamente local.

Por qué importa / Casos de uso

  • Control de estado manos libres mientras sueldas, mides con puntas o sostienes piezas con ambas manos ocupadas.
  • Señalización clara en el banco: un LED para RUN, uno para STOP, más un LED de actividad que reacciona a la energía de audio detectada.
  • Indicación compartida en laboratorio sin PC, SO ni pila de red, manteniendo el tiempo de respuesta predecible y típicamente por debajo de 50–100 ms desde la ráfaga hasta el cambio de estado.
  • Entrenamiento práctico en FPGA sobre captura I2S de 24 bits, extracción de envolvente, umbralización, temporización de antirrebote/confirmación y bloqueo de eventos usando solo una pequeña fracción de los recursos del ECP5.

Resultado esperado

  • La FPGA muestrea audio I2S de 24 bits desde el INMP441, lo convierte en una envolvente de amplitud simple y marca ráfagas por encima de un umbral configurable.
  • Una ráfaga hablada corta cerca del micrófono activa una transición de estado solo después de una ventana de confirmación, reduciendo conmutaciones falsas por ruido de fondo o golpes en el banco.
  • Tres LEDs proporcionan realimentación inmediata: RUN, STOP y actividad de audio, con comportamiento de conmutación estable y un intervalo de bloqueo configurable entre eventos.
  • La simulación demuestra rechazo al silencio, detección de ráfagas, temporización de bloqueo y conmutación correcta RUN/STOP, con objetivos prácticos de ajuste como latencia de detección por debajo de 100 ms y baja carga de FPGA.

Audiencia: Estudiantes intermedios de FPGA con experiencia básica en diseño digital y herramientas de línea de comandos; Nivel: Intermedio

Arquitectura/flujo: Micrófono I2S INMP441 → receptor de reloj de bits/selección de palabra → captura de muestras de 24 bits → medición de valor absoluto/envolvente → umbral + contador de confirmación → máquina de estados de bloqueo/conmutación → LEDs RUN/STOP/audio.

Diagrama de bloques conceptual

Vista de alto nivel: qué entra, qué procesa cada bloque y qué sale del sistema.

Arquitectura funcional

Micrófono I2S INMP441

receptor de reloj de bits/selección de pa…

captura de muestras de 24 bits

medición de valor absoluto/envolvente

umbral + contador de confirmación

máquina de estados de bloqueo/conmutación

LEDs RUN/STOP/audio

Flujo conceptual de señales y responsabilidades entre bloques del dispositivo.

Ruta de validación

Código fuente

Verilator

Yosys

Implementación hardware

Resumen conceptual de las herramientas usadas para comprobar el material publicado.

Requisitos previos

Deberías sentirte cómodo con:

  • Conceptos básicos de FPGA:
  • relojes
  • lógica síncrona
  • contadores
  • máquinas de estados
  • Verilog básico:
  • módulos
  • registros y wires
  • bloques always
  • parámetros
  • Herramientas de compilación por línea de comandos en Linux
  • Programación por USB de la placa ULX3S

Software recomendado:

  • yosys
  • nextpnr-ecp5
  • ecppack
  • openFPGALoader
  • verilator

Limitación importante:

  • Este proyecto no es reconocimiento de voz.
  • Es un detector simple de eventos de voz fuerte ajustado para aproximar ráfagas tipo comando mediante reglas de umbral, duración y enfriamiento.
  • No identifica palabras habladas de forma fiable en entornos ruidosos.

Materiales

Hardware exacto

Usa exactamente:

  • Radiona ULX3S (Lattice ECP5-85F)
  • Micrófono MEMS I2S INMP441
  • LEDs de estado (integrados en la placa o externos)

Elementos adicionales

  • Cable USB para programación y alimentación de la ULX3S
  • Cables jumper para protoboard
  • Multímetro u osciloscopio opcional para comprobar señales
  • Un área razonablemente silenciosa para el ajuste inicial

Por qué este hardware encaja

  • La ULX3S ECP5-85F tiene suficiente lógica para una pequeña etapa frontal de audio sin IP del fabricante.
  • El INMP441 expone una interfaz digital estándar I2S.
  • Los LEDs proporcionan realimentación inmediata de hardware sin software adicional.

Configuración y conexión

Señales del INMP441

Pines típicos del INMP441:

  • VDD
  • GND
  • SCK o BCLK
  • WS o LRCLK
  • SD
  • L/R

El micrófono normalmente es un esclavo I2S, por lo que la FPGA debe generar:

  • reloj de bits
  • selección de palabra

Y la FPGA debe muestrear:

  • datos serie

Alimentación y niveles lógicos

El INMP441 usa lógica y alimentación de 3.3 V. Usa solo 3.3 V con el micrófono.

Resumen de conexiones

FunciónPin INMP441Nombre de señal FPGA ULX3SDirecciónNotas
AlimentaciónVDD3V3Placa -> micrófonoUsar solo 3.3 V
TierraGNDGNDComúnSe requiere tierra compartida
Reloj de bitsSCK/BCLKmic_bclkFPGA -> micrófonoGenerado por la FPGA
Selección de palabraWS/LRCLKmic_wsFPGA -> micrófonoGenerada por la FPGA
Datos serieSDmic_sdMicrófono -> FPGAMuestreado por la FPGA
Selección de canalL/RGND o 3V3EstáticoSelecciona un canal
LED RUNLEDled_runFPGA -> LEDON cuando está en ejecución
LED STOPLEDled_stopFPGA -> LEDON cuando está detenido
LED de actividadLEDled_activityFPGA -> LEDON durante actividad de audio

Notas de cableado

  1. Conecta VDD a 3.3 V, no a 5 V.
  2. Conecta la tierra entre la placa y el micrófono.
  3. Fija L/R a un nivel lógico definido. En este tutorial, usa GND para seleccionar el canal izquierdo.
  4. Mantén los cables cortos.
  5. Si el cableado de tus LED es activo en bajo, inviértelo en el HDL o en las restricciones para que coincida con tu hardware.

Formato I2S elegido

Para este tutorial:

  • Reloj de entrada de FPGA: 25 MHz
  • Reloj de bits I2S: 1.5625 MHz por división entera
  • Tamaño de palabra: 32 bits por canal
  • Frecuencia de muestreo: aproximadamente 24.414 kHz porque 1.5625 MHz / 64 = 24.414 kHz

Esa frecuencia de muestreo es adecuada para un detector simple de estilo actividad de voz.


Archivos del proyecto

fpga-voice-led/
├── voice_led_top.v
├── tb_voice_led_top.v
└── ulx3s_voice_led.lpf

Módulo superior en Verilog

voice_led_top.v

Vista pública parcial del archivo validado. El código completo se muestra a miembros y en PDF/Print.

module voice_led_top(
    input  wire clk_25mhz,
    input  wire mic_sd,
    output reg  mic_bclk = 1'b0,
    output reg  mic_ws   = 1'b0,
    output wire led_run,
    output wire led_stop,
    output wire led_activity
);

    reg [3:0] bclk_div = 4'd0;
    reg       bclk_prev = 1'b0;
    reg [5:0] bit_count = 6'd0;
    reg [5:0] slot_bit_index = 6'd0;
    reg [31:0] shift_reg = 32'd0;
    reg [23:0] sample_left = 24'd0;
    reg        sample_strobe = 1'b0;

    reg [31:0] envelope = 32'd0;
    reg        activity = 1'b0;
    reg [15:0] burst_count = 16'd0;
    reg [15:0] holdoff_count = 16'd0;
    reg        run_state = 1'b0;

    wire bclk_rise;
    wire signed [23:0] signed_sample;
    wire [23:0] abs_sample;
    wire [31:0] envelope_next;

    localparam [31:0] ENV_THRESHOLD      = 32'd200000;
    localparam [15:0] BURST_MIN_SAMPLES  = 16'd1200;
    localparam [15:0] BURST_MAX_SAMPLES  = 16'd9000;
    localparam [15:0] HOLDOFF_SAMPLES    = 16'd18000;

    assign bclk_rise = (bclk_prev == 1'b0) && (mic_bclk == 1'b1);
    assign signed_sample = sample_left;
    assign abs_sample = signed_sample[23] ? (~signed_sample + 24'd1) : signed_sample;
    assign envelope_next = envelope - (envelope >> 4) + {8'd0, abs_sample};

    always @(posedge clk_25mhz) begin
        bclk_prev <= mic_bclk;

        if (bclk_div == 4'd7) begin
            bclk_div <= 4'd0;
            mic_bclk <= ~mic_bclk;
        end else begin
            bclk_div <= bclk_div + 4'd1;
        end
    end

    always @(posedge clk_25mhz) begin
        sample_strobe <= 1'b0;

        if (bclk_rise) begin
            if (bit_count == 6'd63) begin
                bit_count <= 6'd0;
// ... continúa para miembros en el código completo validado ...

🔒 Parte del código validado es premium. Con el pase de 7 días o la suscripción mensual podrás consultar el archivo completo validado.

module voice_led_top(
    input  wire clk_25mhz,
    input  wire mic_sd,
    output reg  mic_bclk = 1'b0,
    output reg  mic_ws   = 1'b0,
    output wire led_run,
    output wire led_stop,
    output wire led_activity
);

    reg [3:0] bclk_div = 4'd0;
    reg       bclk_prev = 1'b0;
    reg [5:0] bit_count = 6'd0;
    reg [5:0] slot_bit_index = 6'd0;
    reg [31:0] shift_reg = 32'd0;
    reg [23:0] sample_left = 24'd0;
    reg        sample_strobe = 1'b0;

    reg [31:0] envelope = 32'd0;
    reg        activity = 1'b0;
    reg [15:0] burst_count = 16'd0;
    reg [15:0] holdoff_count = 16'd0;
    reg        run_state = 1'b0;

    wire bclk_rise;
    wire signed [23:0] signed_sample;
    wire [23:0] abs_sample;
    wire [31:0] envelope_next;

    localparam [31:0] ENV_THRESHOLD      = 32'd200000;
    localparam [15:0] BURST_MIN_SAMPLES  = 16'd1200;
    localparam [15:0] BURST_MAX_SAMPLES  = 16'd9000;
    localparam [15:0] HOLDOFF_SAMPLES    = 16'd18000;

    assign bclk_rise = (bclk_prev == 1'b0) && (mic_bclk == 1'b1);
    assign signed_sample = sample_left;
    assign abs_sample = signed_sample[23] ? (~signed_sample + 24'd1) : signed_sample;
    assign envelope_next = envelope - (envelope >> 4) + {8'd0, abs_sample};

    always @(posedge clk_25mhz) begin
        bclk_prev <= mic_bclk;

        if (bclk_div == 4'd7) begin
            bclk_div <= 4'd0;
            mic_bclk <= ~mic_bclk;
        end else begin
            bclk_div <= bclk_div + 4'd1;
        end
    end

    always @(posedge clk_25mhz) begin
        sample_strobe <= 1'b0;

        if (bclk_rise) begin
            if (bit_count == 6'd63) begin
                bit_count <= 6'd0;
            end else begin
                bit_count <= bit_count + 6'd1;
            end

            if (bit_count == 6'd31) begin
                mic_ws <= 1'b1;
            end else if (bit_count == 6'd63) begin
                mic_ws <= 1'b0;
            end

            if (bit_count == 6'd31 || bit_count == 6'd63) begin
                slot_bit_index <= 6'd0;
            end else begin
                slot_bit_index <= slot_bit_index + 6'd1;
            end

            shift_reg <= {shift_reg[30:0], mic_sd};

            if (mic_ws == 1'b0 && slot_bit_index == 6'd23) begin
                sample_left <= {shift_reg[22:0], mic_sd};
                sample_strobe <= 1'b1;
            end
        end
    end

    always @(posedge clk_25mhz) begin
        if (sample_strobe) begin
            envelope <= envelope_next;
            activity <= (envelope_next > ENV_THRESHOLD);

            if (holdoff_count != 16'd0) begin
                holdoff_count <= holdoff_count - 16'd1;
                burst_count <= 16'd0;
            end else begin
                if (envelope_next > ENV_THRESHOLD) begin
                    if (burst_count != 16'hFFFF) begin
                        burst_count <= burst_count + 16'd1;
                    end
                end else begin
                    if (burst_count >= BURST_MIN_SAMPLES &&
                        burst_count <= BURST_MAX_SAMPLES) begin
                        run_state <= ~run_state;
                        holdoff_count <= HOLDOFF_SAMPLES;
                    end
                    burst_count <= 16'd0;
                end
            end
        end
    end

    assign led_run = run_state;
    assign led_stop = ~run_state;
    assign led_activity = activity;

endmodule


Banco de pruebas

tb_voice_led_top.v

Vista pública parcial del archivo validado. El código completo se muestra a miembros y en PDF/Print.

`timescale 1ns/1ps

module tb_voice_led_top;

    reg clk_25mhz = 1'b0;
    reg mic_sd = 1'b0;
    wire mic_bclk;
    wire mic_ws;
    wire led_run;
    wire led_stop;
    wire led_activity;

    integer i;
    integer k;
    reg [31:0] slot_word;

    voice_led_top dut (
        .clk_25mhz(clk_25mhz),
        .mic_sd(mic_sd),
        .mic_bclk(mic_bclk),
        .mic_ws(mic_ws),
        .led_run(led_run),
        .led_stop(led_stop),
        .led_activity(led_activity)
    );

    always #20 clk_25mhz = ~clk_25mhz;

    task send_i2s_left_sample;
        input [23:0] s;
        begin
            while (mic_ws !== 1'b0) begin
                @(posedge mic_bclk);
            end

            slot_word = {s, 8'h00};

            for (i = 31; i >= 0; i = i - 1) begin
                @(negedge mic_bclk);
                mic_sd = slot_word[i];
            end

            while (mic_ws !== 1'b1) begin
                @(posedge mic_bclk);
            end

            for (i = 31; i >= 0; i = i - 1) begin
                @(negedge mic_bclk);
                mic_sd = 1'b0;
            end
        end
// ... continúa para miembros en el código completo validado ...

🔒 Parte del código validado es premium. Con el pase de 7 días o la suscripción mensual podrás consultar el archivo completo validado.

`timescale 1ns/1ps

module tb_voice_led_top;

    reg clk_25mhz = 1'b0;
    reg mic_sd = 1'b0;
    wire mic_bclk;
    wire mic_ws;
    wire led_run;
    wire led_stop;
    wire led_activity;

    integer i;
    integer k;
    reg [31:0] slot_word;

    voice_led_top dut (
        .clk_25mhz(clk_25mhz),
        .mic_sd(mic_sd),
        .mic_bclk(mic_bclk),
        .mic_ws(mic_ws),
        .led_run(led_run),
        .led_stop(led_stop),
        .led_activity(led_activity)
    );

    always #20 clk_25mhz = ~clk_25mhz;

    task send_i2s_left_sample;
        input [23:0] s;
        begin
            while (mic_ws !== 1'b0) begin
                @(posedge mic_bclk);
            end

            slot_word = {s, 8'h00};

            for (i = 31; i >= 0; i = i - 1) begin
                @(negedge mic_bclk);
                mic_sd = slot_word[i];
            end

            while (mic_ws !== 1'b1) begin
                @(posedge mic_bclk);
            end

            for (i = 31; i >= 0; i = i - 1) begin
                @(negedge mic_bclk);
                mic_sd = 1'b0;
            end
        end
    endtask

    task send_silence;
        input integer n;
        begin
            for (k = 0; k < n; k = k + 1) begin
                send_i2s_left_sample(24'd0);
            end
        end
    endtask

    task send_burst;
        input integer n;
        begin
            for (k = 0; k < n; k = k + 1) begin
                if (k[0]) begin
                    send_i2s_left_sample(24'h180000);
                end else begin
                    send_i2s_left_sample(24'hE80000);
                end
            end
        end
    endtask

    initial begin
        $display("Starting simulation");

        send_silence(3000);
        $display("Initial state: led_run=%0d led_stop=%0d led_activity=%0d",
                 led_run, led_stop, led_activity);

        send_burst(2000);
        send_silence(3000);
        $display("After burst 1: led_run=%0d led_stop=%0d led_activity=%0d",
                 led_run, led_stop, led_activity);

        send_burst(1500);
        send_silence(4000);
        $display("After burst 2 during holdoff: led_run=%0d led_stop=%0d led_activity=%0d",
                 led_run, led_stop, led_activity);

        send_silence(20000);
        send_burst(2000);
        send_silence(3000);
        $display("After burst 3: led_run=%0d led_stop=%0d led_activity=%0d",
                 led_run, led_stop, led_activity);

        $finish;
    end

endmodule


Restricciones

ulx3s_voice_led.lpf

Usa ubicaciones de pines FPGA que coincidan con la revisión exacta de tu placa ULX3S y con los pines del encabezado externo que realmente cableaste. El ejemplo siguiente está sintácticamente completo, pero los valores SITE deben coincidir con el cableado físico de tu placa antes de programar el hardware.

BLOCK RESETPATHS;
BLOCK ASYNCPATHS;

FREQUENCY PORT "clk_25mhz" 25.0 MHz;

LOCATE COMP "clk_25mhz" SITE "G2";
IOBUF PORT "clk_25mhz" IO_TYPE=LVCMOS33;

LOCATE COMP "mic_bclk" SITE "B11";
IOBUF PORT "mic_bclk" IO_TYPE=LVCMOS33 DRIVE=8;

LOCATE COMP "mic_ws" SITE "A10";
IOBUF PORT "mic_ws" IO_TYPE=LVCMOS33 DRIVE=8;

LOCATE COMP "mic_sd" SITE "B10";
IOBUF PORT "mic_sd" IO_TYPE=LVCMOS33;

LOCATE COMP "led_run" SITE "K4";
IOBUF PORT "led_run" IO_TYPE=LVCMOS33 DRIVE=8;

LOCATE COMP "led_stop" SITE "M3";
IOBUF PORT "led_stop" IO_TYPE=LVCMOS33 DRIVE=8;

LOCATE COMP "led_activity" SITE "J3";
IOBUF PORT "led_activity" IO_TYPE=LVCMOS33 DRIVE=8;

Compilar y ejecutar

Crea primero un directorio de compilación:

mkdir -p build

1) Analizar el diseño

verilator --lint-only -Wall -Wno-DECLFILENAME voice_led_top.v tb_voice_led_top.v

2) Ejecutar el banco de pruebas

verilator -Wall -Wno-DECLFILENAME --binary tb_voice_led_top.v voice_led_top.v
./obj_dir/Vtb_voice_led_top

3) Sintetizar para ECP5

yosys -p "read_verilog voice_led_top.v; synth_ecp5 -top voice_led_top -json build/voice_led_top.json"

4) Colocar y rutear

nextpnr-ecp5 \
  --85k \
  --json build/voice_led_top.json \
  --lpf ulx3s_voice_led.lpf \
  --textcfg build/voice_led_top.config

5) Empaquetar el bitstream

ecppack build/voice_led_top.config build/voice_led_top.bit

6) Programar la placa

openFPGALoader -b ulx3s build/voice_led_top.bit

Método de validación

Este proyecto solo hace una afirmación limitada sobre el comportamiento del hardware: que el diseño puede detectar una ráfaga de audio fuerte y corta y conmutar LEDs bajo ajustes adecuados de umbral y temporización.

Procedimiento de validación

Usa este método para validar la afirmación:

  1. Validación estática
  2. Ejecuta el lint de Verilator.
  3. Evidencia: no hay errores de sintaxis ni de elaboración.

  4. Validación de comportamiento

  5. Ejecuta el banco de pruebas proporcionado.
  6. Evidencia:

    • el arranque muestra led_run=0 led_stop=1
    • la primera ráfaga válida conmuta a led_run=1 led_stop=0
    • la segunda ráfaga durante el bloqueo no conmuta
    • la tercera ráfaga después del bloqueo vuelve a conmutar
  7. Validación de implementación

  8. Ejecuta Yosys, nextpnr-ecp5 y ecppack.
  9. Evidencia:

    • se crea la netlist JSON
    • la colocación y el ruteo se completan
    • el bitstream se genera correctamente
  10. Validación en hardware

  11. Programa la ULX3S.
  12. Pronuncia una ráfaga corta y fuerte cerca del micrófono.
  13. Evidencia:
    • led_activity parpadea durante el habla
    • led_run y led_stop conmutan solo después de una ráfaga con duración aceptable
    • ráfagas repetidas inmediatas dentro del bloqueo no conmutan el estado

Evidencia esperada

Patrón esperado de salida de consola en simulación:

  • Initial state: led_run=0 led_stop=1
  • After burst 1: led_run=1 led_stop=0
  • After burst 2 during holdoff: led_run=1 led_stop=0
  • After burst 3: led_run=0 led_stop=1

La evidencia en hardware debe ser un comportamiento visual directo de los LEDs coherente con la lógica anterior.


Puesta en marcha del hardware

Prueba A: confirmar relojes generados

Si tienes un osciloscopio o analizador lógico:

  • Comprueba que mic_bclk esté activo
  • Comprueba que mic_ws conmute más lentamente que mic_bclk

Prueba B: línea base en silencio

Con una sala silenciosa:

  • led_activity debería permanecer mayormente en OFF
  • Los LEDs de estado RUN/STOP deberían mantenerse estables

Prueba C: ráfaga hablada corta

Habla cerca del micrófono:

  • led_activity debería parpadear durante la ráfaga
  • una ráfaga válida debería conmutar RUN/STOP

Prueba D: comportamiento de bloqueo

Habla de nuevo inmediatamente:

  • led_activity puede parpadear
  • RUN/STOP no debería conmutar durante el bloqueo

Prueba E: comportamiento tras el bloqueo

Espera aproximadamente un segundo y luego habla de nuevo:

  • el estado debería volver a conmutar

Ajuste

Si el detector es demasiado sensible o no lo suficiente, ajusta estas constantes en voice_led_top.v:

  • ENV_THRESHOLD
  • aumenta si el ruido activa la actividad
  • disminuye si no se detecta el habla
  • BURST_MIN_SAMPLES
  • disminuye si se ignoran ráfagas cortas
  • aumenta si golpes o clics activan conmutaciones
  • BURST_MAX_SAMPLES
  • disminuye si sonidos largos de fondo activan conmutaciones
  • aumenta si tus ráfagas habladas son más largas
  • HOLDOFF_SAMPLES
  • aumenta para suprimir conmutaciones repetidas
  • disminuye si la interfaz se siente demasiado lenta

Nota educativa de validación

Antes de la publicación, este caso superó la compuerta automatizada de validación de Prometeo con estado PASS. Para este perfil FPGA/ULX3S, los bloques Verilog sintetizables se comprobaron con Yosys (read_verilog) y el conjunto de diseño/pruebas Verilog se analizó con Verilator. El validador también comprobó la estructura de los bloques de código, opciones de comandos ASCII seguras para copiar/pegar, pilas no compatibles y la disponibilidad de la cadena de herramientas ULX3S/ECP5 (yosys, nextpnr-ecp5, ecppack, openFPGALoader).

Esta validación confirma la sintaxis y la compatibilidad de herramientas para el código publicado, pero no sustituye las pruebas físicas en tu revisión exacta de placa ULX3S, archivo de restricciones de pines y cableado real.

Nota educativa de seguridad

Nota educativa de seguridad

Este proyecto es un experimento educativo de audio FPGA de bajo voltaje. No lo uses para controlar maquinaria peligrosa, tensión de red, calentadores, motores, dispositivos médicos ni ningún sistema crítico para la seguridad. Los detectores de voz/ruido pueden activarse falsamente por habla, golpes, ventiladores, música u otros sonidos. Si más adelante añades relés o controladores de potencia, usa aislamiento y circuitería de control adecuados.


Solución de problemas

Ningún LED responde

Comprueba:

  1. Que la placa se programó correctamente
  2. Que clk_25mhz coincide con el pin de reloj real de la ULX3S
  3. Que los pines de los LED coinciden con tu hardware
  4. Que el LPF coincide con la revisión de tu placa

led_activity siempre en OFF

Causas posibles:

  • micrófono sin alimentación
  • cableado incorrecto de mic_sd
  • falta mic_bclk o mic_ws
  • umbral demasiado alto

Acciones:

  • verifica 3.3 V en el micrófono
  • verifica tierra común
  • mide mic_bclk y mic_ws
  • baja ENV_THRESHOLD

led_activity siempre en ON

Causas posibles:

  • mic_sd flotante
  • mala conexión a tierra
  • umbral demasiado bajo
  • temporización I2S incorrecta

Acciones:

  • acorta los cables
  • asegura la tierra
  • sube ENV_THRESHOLD
  • confirma que L/R está fijado a un nivel válido

La actividad funciona, pero RUN/STOP nunca conmuta

Esto normalmente significa que la temporización de la ráfaga está fuera de la ventana aceptada.

Acciones:

  • baja BURST_MIN_SAMPLES
  • sube BURST_MAX_SAMPLES
  • prueba ráfagas habladas más cortas y consistentes

nextpnr-ecp5 falla

Normalmente esto es un problema de restricciones.

Acciones:

  • verifica el mapa de pines de la ULX3S
  • mueve las señales a pines de E/S válidos
  • actualiza el LPF a la revisión real de tu placa y a los pines de cabecera elegidos

Mejoras

Posibles extensiones:

  1. Añadir una entrada de anulación con pulsador
  2. Añadir salida de depuración UART para la envolvente y cambios de estado
  3. Mejorar el detector de envolvente con promedio o lógica de pico-decaimiento
  4. Detectar diferentes patrones de ráfaga en lugar de conmutación simple
  5. Añadir un controlador con transistor o MOSFET para indicadores de mayor tamaño y bajo voltaje

No conectes pines de FPGA directamente a cargas de alta corriente.


Lista de verificación final

  • [ ] Usé una Radiona ULX3S (Lattice ECP5-85F) con un micrófono MEMS I2S INMP441
  • [ ] El micrófono está alimentado con 3.3 V
  • [ ] Las tierras están compartidas
  • [ ] L/R está fijado a un nivel lógico definido
  • [ ] Mi LPF coincide con mi cableado real de la ULX3S
  • [ ] El lint de Verilator se completó sin errores fatales
  • [ ] El banco de pruebas mostró el comportamiento de conmutación esperado
  • [ ] La síntesis con Yosys se completó correctamente
  • [ ] nextpnr-ecp5 se completó correctamente para --85k
  • [ ] El bitstream se programó con openFPGALoader -b ulx3s
  • [ ] led_activity responde al habla cercana o a ráfagas de sonido fuerte
  • [ ] led_run y led_stop conmutan solo con ráfagas válidas
  • [ ] Ajusté las constantes de umbral y temporización para mi configuración

Si todos los elementos se cumplen, tienes un proyecto práctico de FPGA ULX3S para captura de audio I2S y control simple de LED activado por ráfagas.

        <div class="amazon-affiliate">
          <p><strong>Encuentra este producto y/o libros sobre este tema en Amazon</strong></p>
          <p><a class="amazon-affiliate-btn" href="https://amzn.to/4mt8r4C" target="_blank" rel="nofollow sponsored noopener">Ir a Amazon</a></p>
          <p class="amazon-affiliate-disclaimer">Como afiliado de Amazon, gano con las compras que cumplan los requisitos. Si compras a través de este enlace, ayudas a mantener este proyecto.</p>
        </div>

Quiz rápido

Pregunta 1: ¿Qué dispositivo se utiliza como micrófono en este proyecto?




Pregunta 2: ¿Cuál es la placa FPGA principal mencionada en el texto?




Pregunta 3: ¿Cuál es el propósito principal del detector de ráfagas de voz?




Pregunta 4: ¿Qué ventaja ofrece este sistema al trabajar en el banco de pruebas?




Pregunta 5: ¿Cuál es el tiempo de respuesta típico desde la ráfaga de voz hasta el cambio de estado?




Pregunta 6: ¿Qué tipo de captura de audio realiza la FPGA desde el micrófono INMP441?




Pregunta 7: ¿Qué elementos visuales se utilizan para la señalización clara en el banco?




Pregunta 8: ¿Qué característica destaca del sistema en cuanto a su dependencia de otros equipos?




Pregunta 9: ¿Qué procesamiento realiza la FPGA con la señal de audio capturada?




Pregunta 10: ¿Cuántos recursos de la FPGA ECP5 se utilizan para este proyecto?




Carlos Núñez Zorrilla
Carlos Núñez Zorrilla
Electronics & Computer Engineer

Ingeniero Superior en Electrónica de Telecomunicaciones e Ingeniero en Informática (titulaciones oficiales en España).

Sígueme:
Scroll al inicio