Caso práctico: Supresión de ruido con choque de RF

Esquemático — Caso práctico: Supresión de ruido con choque de RF

Nivel: Medio – Demostrar la alta impedancia del inductor a altas frecuencias para bloquear el ruido en las líneas de alimentación.

Objetivo y caso de uso

Construirá un filtro paso bajo LR utilizando un choque de RF para aislar una línea de alimentación de CC del ruido de CA de alta frecuencia. Al superponer una señal de CA sobre una fuente de tensión de CC, observará cómo la reactancia del inductor, dependiente de la frecuencia, permite el paso de la CC mientras atenúa fuertemente el ruido de alta frecuencia antes de que llegue a la carga.

Este concepto de circuito es muy útil en el mundo real para:
* Evitar que el ruido de conmutación de alta frecuencia entre en circuitos de sensores analógicos sensibles.
* Filtrar la interferencia de radiofrecuencia (RFI) de líneas largas de suministro de energía.
* Aislar diferentes bloques funcionales que comparten un raíl de alimentación común en un PCB.
* Proteger la electrónica de comunicación y audio del automóvil contra el zumbido del alternador.

Resultado esperado:
* La señal de entrada mixta (V_IN_MIX) mostrará un offset de CC estable combinado con un rizado significativo de alta frecuencia.
* La tensión de salida (V_OUT_CLEAN) en la carga mostrará un nivel de CC estable con el ruido de CA enormemente reducido.
* Un análisis FFT (Transformada Rápida de Fourier) de la entrada revelará una gran componente a 0 Hz (CC) y un pico prominente de alta frecuencia.
* Un análisis FFT de la salida mostrará el pico de alta frecuencia casi completamente suprimido, confirmando la acción de bloqueo del choque.

Público objetivo: Estudiantes de electrónica de nivel intermedio que aprenden sobre componentes reactivos y superposición de CA/CC.

Materiales

  • V1: fuente de CC de 5 V, función: fuente de alimentación principal de CC
  • V2: fuente de CA de onda senoidal de 500 mV de pico a 100 kHz, función: simulador de ruido de alta frecuencia
  • L1: inductor de 1 mH, función: choque de RF para bloquear el ruido de alta frecuencia
  • R1: resistencia de 100 Ω, función: simulación de carga

Guía de conexionado

  • V1: se conecta entre V_DC y 0
  • V2: se conecta entre V_IN_MIX y V_DC
  • L1: se conecta entre V_IN_MIX y V_OUT_CLEAN
  • R1: se conecta entre V_OUT_CLEAN y 0

Diagrama de bloques conceptual

Conceptual block diagram — 1mH RF Choke
Lectura rápida: entradas → bloque principal → salida (actuador o medida). Resume el esquemático ASCII de la siguiente sección.

Esquemático

[ V1: 5 V DC Source ] --(V_DC)--> [ V2: AC Noise Simulator ] --(V_IN_MIX)--> [ L1: 1mH RF Choke ] --(V_OUT_CLEAN)--> [ R1: 100 Ω Load ] --> GND
Esquema Eléctrico

Diagrama eléctrico

Diagrama electrico del caso: Caso práctico: Supresión de ruido con choque de RF
Generado desde la netlist SPICE validada del caso.

🔒 Este diagrama eléctrico es premium. Con el pase de 7 días o la suscripción mensual podrás desbloquear el material didáctico completo y el pack PDF listo para imprimir.🔓 Ver planes de acceso premium

Mediciones y pruebas

  1. Conecte una sonda de osciloscopio a V_IN_MIX con la pinza de tierra conectada al nodo 0. Configure el acoplamiento del canal en CC. Debería observar una línea base de 5 V de CC con una onda senoidal de 100 kHz y 1 V pico a pico montada sobre ella.
  2. Conecte una segunda sonda de osciloscopio a V_OUT_CLEAN. Observe que la tensión de CC se mantiene en aproximadamente 5 V, pero el rizado de alta frecuencia de 100 kHz se atenúa drásticamente debido a la alta reactancia inductiva (XL = 2\pi fL) del choque.
  3. Active la función matemática FFT (Transformada Rápida de Fourier) en el osciloscopio para el canal V_IN_MIX. Note el pico masivo a 0 Hz (que representa la componente de CC de 5 V) y el pico de ruido distintivo a 100 kHz.
  4. Aplique la función FFT al canal V_OUT_CLEAN. Compare la magnitud del pico de 100 kHz con la medición de entrada; debería estar significativamente reducido, demostrando con éxito las capacidades de bloqueo de alta frecuencia del inductor.

Netlist SPICE y simulación

Netlist SPICE de referencia (ngspice) — extractoNetlist SPICE completo (ngspice)

* Noise suppression with RF choke
.width out=256

* Main DC power supply (5V)
V1 V_DC 0 DC 5

* High-frequency noise simulator (500mV peak, 100kHz sine wave superimposed on DC)
V2 V_IN_MIX V_DC SINE(0 500m 100k)

* RF choke to block high-frequency noise (1mH)
L1 V_IN_MIX V_OUT_CLEAN 1m

* Load simulation (100 ohms)
* ... (truncated in public view) ...

Copia este contenido en un archivo .cir y ejecútalo con ngspice.

🔒 Parte del contenido de esta sección es premium. Con el pase de 7 días o la suscripción mensual tendrás acceso al contenido completo (materiales, conexionado, compilación detallada, validación paso a paso, troubleshooting, mejoras/variantes y checklist) y podrás descargar el pack PDF listo para imprimir.

* Noise suppression with RF choke
.width out=256

* Main DC power supply (5V)
V1 V_DC 0 DC 5

* High-frequency noise simulator (500mV peak, 100kHz sine wave superimposed on DC)
V2 V_IN_MIX V_DC SINE(0 500m 100k)

* RF choke to block high-frequency noise (1mH)
L1 V_IN_MIX V_OUT_CLEAN 1m

* Load simulation (100 ohms)
R1 V_OUT_CLEAN 0 100

* Analysis directives
.op
* Simulate for 100us to capture 10 full cycles of the 100kHz noise
.tran 0.1u 100u
.print tran V(V_IN_MIX) V(V_OUT_CLEAN) V(V_DC) I(L1)

.end

Resultados de Simulación (Transitorio)

Resultados de Simulación (Transitorio)
Análisis: The simulation shows a 5V DC signal with a superimposed 500mV peak 100kHz sine wave at the input (V_IN_MIX ranges from 4.5V to 5.5V). At the output (V_OUT_CLEAN), the voltage ranges from 4.92V to 5.12V, indicating that the 1mH RF choke significantly attenuates the high-frequency noise while passing the DC component to the 100-ohm load.
Show raw data table (1008 rows)
Index   time            v(v_in_mix)     v(v_out_clean)  v(v_dc)         l1#branch
0	0.000000e+00	5.000000e+00	5.000000e+00	5.000000e+00	5.000000e-02
1	1.000000e-09	5.000314e+00	5.000000e+00	5.000000e+00	5.000000e-02
2	2.000000e-09	5.000628e+00	5.000000e+00	5.000000e+00	5.000000e-02
3	4.000000e-09	5.001257e+00	5.000000e+00	5.000000e+00	5.000000e-02
4	8.000000e-09	5.002513e+00	5.000001e+00	5.000000e+00	5.000001e-02
5	1.600000e-08	5.005026e+00	5.000004e+00	5.000000e+00	5.000004e-02
6	3.200000e-08	5.010052e+00	5.000016e+00	5.000000e+00	5.000016e-02
7	6.400000e-08	5.020101e+00	5.000064e+00	5.000000e+00	5.000064e-02
8	1.280000e-07	5.040169e+00	5.000256e+00	5.000000e+00	5.000256e-02
9	2.280000e-07	5.071384e+00	5.000808e+00	5.000000e+00	5.000808e-02
10	3.280000e-07	5.102316e+00	5.001665e+00	5.000000e+00	5.001665e-02
11	4.280000e-07	5.132845e+00	5.002818e+00	5.000000e+00	5.002818e-02
12	5.280000e-07	5.162850e+00	5.004261e+00	5.000000e+00	5.004261e-02
13	6.280000e-07	5.192212e+00	5.005985e+00	5.000000e+00	5.005985e-02
14	7.280000e-07	5.220816e+00	5.007980e+00	5.000000e+00	5.007980e-02
15	8.280000e-07	5.248548e+00	5.010236e+00	5.000000e+00	5.010236e-02
16	9.280000e-07	5.275299e+00	5.012741e+00	5.000000e+00	5.012741e-02
17	1.028000e-06	5.300963e+00	5.015481e+00	5.000000e+00	5.015481e-02
18	1.128000e-06	5.325440e+00	5.018443e+00	5.000000e+00	5.018443e-02
19	1.228000e-06	5.348633e+00	5.021613e+00	5.000000e+00	5.021613e-02
20	1.328000e-06	5.370449e+00	5.024976e+00	5.000000e+00	5.024976e-02
21	1.428000e-06	5.390804e+00	5.028515e+00	5.000000e+00	5.028515e-02
22	1.528000e-06	5.409616e+00	5.032213e+00	5.000000e+00	5.032213e-02
23	1.628000e-06	5.426812e+00	5.036054e+00	5.000000e+00	5.036054e-02
... (984 more rows) ...

Errores comunes y cómo evitarlos

  • Usar un inductor con una baja frecuencia de autorresonancia (SRF): Todos los inductores tienen capacitancia parásita de devanado. Si la frecuencia del ruido supera la SRF del inductor, el componente se comporta como un condensador y permite que el ruido de alta frecuencia pase directamente. Verifique siempre que la SRF esté muy por encima de la frecuencia de ruido objetivo.
  • Ignorar la resistencia de CC (DCR) del inductor: Los inductores están hechos de alambre enrollado que naturalmente posee resistencia. Altas corrientes de carga pasando por un inductor con alta DCR causarán una caída de tensión de CC inaceptable. Elija un choque con una DCR adecuadamente baja para su carga.
  • Saturación del núcleo debido a alta corriente de CC: Si la carga consume más corriente continua que la especificación de saturación del inductor (Isat), el flujo magnético del núcleo se satura. Esto hace que la inductancia caiga drásticamente, destruyendo su capacidad de filtrado. Compruebe siempre la especificación de corriente de saturación.

Solución de problemas

  • Síntoma: El ruido de alta frecuencia sigue estando muy presente en V_OUT_CLEAN.
  • Causa: El valor del inductor es demasiado bajo para proporcionar una reactancia significativa a la frecuencia del ruido simulado, o se ha superado su SRF.
  • Solución: Aumente el valor de la inductancia (por ejemplo, escale de 10 µH a 1 mH) o verifique los límites de frecuencia del choque específico que se está utilizando.
  • Síntoma: Caída significativa de tensión de CC en V_OUT_CLEAN bajo carga (por ejemplo, leyendo 4 V en lugar de 5 V).
  • Causa: La resistencia interna de CC (DCR) del inductor es demasiado alta en relación con la resistencia de carga R1.
  • Solución: Reemplace el inductor por uno físicamente más grande que utilice un alambre más grueso, lo que reduce la DCR, o aumente la resistencia de carga si está consumiendo más corriente de la prevista.
  • Síntoma: El choque se calienta en exceso durante el funcionamiento.
  • Causa: La corriente de CC consumida por la carga excede la especificación de corriente térmica continua (Irms) del inductor.
  • Solución: Seleccione un inductor de potencia de mayor especificación capaz de manejar de forma segura la corriente de carga en estado estable.

Posibles mejoras y extensiones

  • Formar un filtro paso bajo LC: Añada un condensador de desacoplo (por ejemplo, 100 nF o 1 µF) en paralelo a la carga (entre V_OUT_CLEAN y 0). Esto crea un filtro de segundo orden, proporcionando una caída mucho más pronunciada y una atenuación de ruido inmensamente superior en comparación con la configuración LR simple.
  • Implementar un filtro Pi: Utilice una disposición Condensador-Inductor-Condensador (C-L-C) para proporcionar una supresión de ruido bidireccional. Esto no solo limpia la energía que entra a la carga, sino que también evita que cualquier ruido de conmutación generado por la carga contamine la línea principal de suministro de CC.

Más Casos Prácticos en Prometeo.blog

Encuentra este producto y/o libros sobre este tema en Amazon

Ir a Amazon

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.

Quiz rápido

Pregunta 1: ¿Cuál es el objetivo principal del circuito descrito en el artículo?




Pregunta 2: ¿Qué componente se utiliza específicamente para bloquear el ruido de alta frecuencia en este circuito?




Pregunta 3: ¿Cómo se comporta la reactancia del inductor frente a las señales de alta frecuencia?




Pregunta 4: ¿Qué tipo de señal permite pasar el inductor hacia la carga con mayor facilidad?




Pregunta 5: Según el texto, ¿cuál es una aplicación real de este concepto de circuito?




Pregunta 6: ¿Qué se espera observar en la señal de entrada mixta (V_IN_MIX)?




Pregunta 7: ¿Qué función cumple el filtro paso bajo LR en una placa de circuito impreso (PCB)?




Pregunta 8: ¿De qué depende la reactancia del inductor en este circuito?




Pregunta 9: ¿Qué problema soluciona este circuito en la electrónica de comunicación de un automóvil?




Pregunta 10: ¿Qué se espera que ocurra con la tensión de salida (V_OUT_CLEAN) en comparación con la entrada?




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:


Caso práctico: Resonancia en circuito tanque LC

Esquemático — Caso práctico: Resonancia en circuito tanque LC

Nivel: Medio | Analizar el intercambio de energía y determinar la frecuencia de resonancia de un tanque LC alimentado por CA.

Objetivo y caso de uso

En este caso práctico, construirás un circuito tanque LC en paralelo alimentado por una fuente de onda senoidal de CA a través de una resistencia en serie. Al realizar un barrido de la frecuencia de entrada, observarás el punto exacto donde las reactancias inductiva y capacitiva se anulan, maximizando la impedancia del circuito.

Comprender la resonancia LC es esencial en la electrónica moderna porque estos circuitos son los bloques de construcción fundamentales de la selección de frecuencia. Las aplicaciones en el mundo real incluyen:
* Sintonización de radiofrecuencia (RF): Seleccionar la frecuencia de una estación específica mientras se rechazan otras.
* Filtrado de audio y señales: Crear filtros pasa banda o rechaza banda (notch) para eliminar el ruido.
* Transferencia de energía inalámbrica: Maximizar la eficiencia del acoplamiento inductivo entre las bobinas transmisora y receptora.
* Circuitos osciladores: Generar señales de reloj estables para microcontroladores y transceptores.

Resultado esperado:
* Calcularás la frecuencia de resonancia teórica basándote en los valores de $L$ y $C$ elegidos.
* La corriente total extraída de la fuente (Itotal) caerá a su valor mínimo en la resonancia.
* El voltaje a través del tanque LC (VLC) alcanzará su pico en la frecuencia de resonancia.
* Observarás cómo la energía oscila continuamente de un lado a otro entre el campo eléctrico del condensador y el campo magnético del inductor.

Público objetivo: Estudiantes de electrónica de nivel intermedio que están en transición de los conceptos básicos de CC a los circuitos reactivos de CA.

Materiales

  • V1: Fuente de voltaje de CA de 5 V pico a pico, función: generador de onda senoidal para barrido de frecuencia
  • R1: Resistencia de 1 kΩ, función: impedancia de la fuente para permitir variaciones de voltaje a través del tanque
  • L1: Inductor de 10 mH, función: almacenamiento de energía magnética
  • C1: Condensador cerámico o de película de 100 nF, función: almacenamiento de energía eléctrica

Guía de conexionado

  • V1: Conecta el terminal positivo al nodo IN y el terminal negativo al nodo 0 (GND).
  • R1: Conecta un pin al nodo IN y el otro pin al nodo TANK.
  • L1: Conecta un pin al nodo TANK y el otro pin al nodo 0 (GND).
  • C1: Conecta un pin al nodo TANK y el otro pin al nodo 0 (GND).

Diagrama de bloques conceptual

Conceptual block diagram — LC Tank Circuit
Lectura rápida: entradas → bloque principal → salida (actuador o medida). Resume el esquemático ASCII de la siguiente sección.

Esquemático

[ V1: 5 V AC ] --(IN)--> [ R1: 1k ohm ] --(Node TANK)--+--> [ L1: 10mH ] --> GND
                                                      |
                                                      +--> [ C1: 100nF ] --> GND
Esquema Eléctrico

Diagrama eléctrico

Diagrama electrico del caso: Caso práctico: Resonancia en circuito tanque LC
Generado desde la netlist SPICE validada del caso.

🔒 Este diagrama eléctrico es premium. Con el pase de 7 días o la suscripción mensual podrás desbloquear el material didáctico completo y el pack PDF listo para imprimir.🔓 Ver planes de acceso premium

Mediciones y pruebas

  1. Calcular la frecuencia de resonancia teórica (fr):
    Utiliza la fórmula fr = (1 / 2\pi\sqrtLC). Con L = 10 mH y C = 100 nF, la frecuencia de resonancia esperada es aproximadamente 5032 Hz.
  2. Configurar el barrido de frecuencia:
    Configura V1 para emitir una onda senoidal de 5 V pico a pico. Comienza con una frecuencia de 1 kHz y auméntala gradualmente hasta 10 kHz.
  3. Medir VLC (Voltaje del tanque):
    Monitorea la amplitud del voltaje en el nodo TANK con respecto al nodo 0 (GND) usando un osciloscopio o un voltímetro de CA. A medida que te acercas a 5 kHz, la amplitud del voltaje aumentará de manera constante, alcanzando un máximo pronunciado exactamente en la resonancia, y luego caerá a medida que la frecuencia siga aumentando.
  4. Medir Itotal (Corriente de la fuente):
    Mide la corriente que fluye a través de R1 (esto se puede hacer observando la diferencia de voltaje entre IN y TANK y aplicando la ley de Ohm: Itotal = ((VIN – VTANK) / R1)). Ten en cuenta que en resonancia, el tanque LC en paralelo presenta la máxima impedancia, lo que significa que Itotal caerá a su mínimo.
  5. Calcular el factor Q del circuito:
    Identifica las frecuencias de -3dB (mitad de potencia) por encima y por debajo del pico de resonancia para encontrar el ancho de banda ($BW$). El factor de calidad es Q = (fr / BW).

Netlist SPICE y simulación

Netlist SPICE de referencia (ngspice) — extractoNetlist SPICE completo (ngspice)

* Practical case: Resonance in LC tank circuit
.width out=256

* 5V peak-to-peak implies an amplitude of 2.5V. 
* The resonant frequency of 10mH and 100nF is approximately 5033 Hz.
* We configure V1 with both a transient sine wave at resonance and an AC magnitude for optional AC analysis.
V1 IN 0 DC 0 AC 2.5 SIN(0 2.5 5033)

* Source impedance
R1 IN TANK 1k

* LC Tank circuit components
L1 TANK 0 10mH
* ... (truncated in public view) ...

Copia este contenido en un archivo .cir y ejecútalo con ngspice.

🔒 Parte del contenido de esta sección es premium. Con el pase de 7 días o la suscripción mensual tendrás acceso al contenido completo (materiales, conexionado, compilación detallada, validación paso a paso, troubleshooting, mejoras/variantes y checklist) y podrás descargar el pack PDF listo para imprimir.

* Practical case: Resonance in LC tank circuit
.width out=256

* 5V peak-to-peak implies an amplitude of 2.5V. 
* The resonant frequency of 10mH and 100nF is approximately 5033 Hz.
* We configure V1 with both a transient sine wave at resonance and an AC magnitude for optional AC analysis.
V1 IN 0 DC 0 AC 2.5 SIN(0 2.5 5033)

* Source impedance
R1 IN TANK 1k

* LC Tank circuit components
L1 TANK 0 10mH
C1 TANK 0 100nF

* Operating point and Transient analysis
.op
.tran 1u 2m

* Print directives for logging the input and output (resonance) nodes
.print tran V(IN) V(TANK) I(L1)

.end

Resultados de Simulación (Transitorio)

Resultados de Simulación (Transitorio)
Análisis: The transient simulation shows the input voltage V(IN) oscillating as a sine wave with a 2.5V amplitude (5V peak-to-peak). The voltage at the tank node V(TANK) closely follows V(IN) with nearly the same amplitude, and the inductor current oscillates, confirming the resonant behavior of the LC tank circuit at the specified frequency.
Show raw data table (2015 rows)
Index   time            v(in)           v(tank)         l1#branch
0	0.000000e+00	0.000000e+00	0.000000e+00	0.000000e+00
1	1.000000e-08	7.905818e-04	7.905026e-08	7.905026e-14
2	1.084006e-08	8.569951e-04	8.624878e-08	8.629565e-14
3	1.252017e-08	9.898217e-04	1.017615e-07	1.020896e-13
4	1.588039e-08	1.255475e-03	1.394809e-07	1.426210e-13
5	2.260084e-08	1.786781e-03	2.416948e-07	2.707046e-13
6	3.604174e-08	2.849394e-03	5.532131e-07	8.049184e-13
7	5.708432e-08	4.512980e-03	1.327631e-06	2.783809e-12
8	8.603868e-08	6.802053e-03	2.965106e-06	8.998482e-12
9	1.305078e-07	1.031768e-02	6.769425e-06	3.064276e-11
10	1.955195e-07	1.545732e-02	1.514065e-05	1.018634e-10
11	2.946313e-07	2.329267e-02	3.431881e-05	3.469641e-10
12	4.417944e-07	3.492633e-02	7.707420e-05	1.166612e-09
13	6.644501e-07	5.252635e-02	1.741480e-04	3.963414e-09
14	9.972436e-07	7.882720e-02	3.917455e-04	1.337970e-08
15	1.499113e-06	1.184727e-01	8.834917e-04	4.537981e-08
16	2.252017e-06	1.778899e-01	1.987598e-03	1.534626e-07
17	3.252017e-06	2.566456e-01	4.126641e-03	4.591745e-07
18	4.252017e-06	3.351447e-01	7.022468e-03	1.016630e-06
19	5.252017e-06	4.133086e-01	1.066173e-02	1.900840e-06
20	6.252017e-06	4.910592e-01	1.502968e-02	3.185410e-06
21	7.252017e-06	5.683189e-01	2.011023e-02	4.942405e-06
22	8.252017e-06	6.450102e-01	2.588597e-02	7.242215e-06
23	9.252017e-06	7.210565e-01	3.233820e-02	1.015342e-05
... (1991 more rows) ...

Errores comunes y cómo evitarlos

  • Usar un condensador polarizado en un circuito de CA: Los condensadores electrolíticos generalmente están polarizados y pueden fallar o explotar si se someten a voltajes de CA inversos. Usa siempre condensadores no polarizados (como cerámicos o de película) para un tanque LC.
  • Ignorar la resistencia equivalente en serie (ESR) del inductor: Los inductores reales consisten en largas bobinas de alambre, lo que añade resistencia parásita de CC al tanque. Si el factor Q medido es mucho menor de lo esperado (resultando en un pico más ancho y plano), la ESR del inductor suele ser la culpable.
  • Confundir la frecuencia angular (\omega) con la frecuencia estándar ($f$): Recuerda que \omega = (1 / \sqrtLC) produce resultados en radianes por segundo. Debes dividir entre 2\pi para obtener la frecuencia en Hertz.

Solución de problemas

  • Síntoma: La frecuencia de resonancia medida es significativamente mayor o menor que los 5032 Hz calculados.
    • Causa: Tolerancias de los componentes. Los condensadores cerámicos estándar pueden tener una tolerancia del ±20%, y los inductores a menudo tienen un ±10%.
    • Solución: Mide los valores exactos de L1 y C1 usando un medidor LCR y vuelve a calcular la frecuencia esperada.
  • Síntoma: VLC no muestra un pico notable durante el barrido; el voltaje se mantiene relativamente plano.
    • Causa: El rango de barrido de frecuencia elegido no cubre el punto de resonancia, o R1 es demasiado pequeña, cortocircuitando efectivamente el tanque a la fuente de voltaje rígida.
    • Solución: Revisa los cálculos matemáticos para tus valores específicos de $L$ y $C$ para asegurar que el rango de barrido abarque fr. Asegúrate de que R1 tenga el tamaño adecuado (1 kΩ es un buen punto de partida).
  • Síntoma: Se observa distorsión o recorte de la señal en el nodo TANK.
    • Causa: La fuente de CA podría estar sobreexcitando el circuito, o se está produciendo saturación del núcleo en el inductor (si se usa un núcleo de ferrita muy pequeño con corrientes altas).
    • Solución: Reduce la amplitud de V1 de 5 V a 1 V pico a pico y comprueba si la onda senoidal vuelve a ser limpia.

Posibles mejoras y extensiones

  • Variar la resistencia de amortiguamiento: Cambia R1 por diferentes valores (ej. 470 Ω, 10 kΩ) o añade una resistencia directamente en paralelo con el tanque LC. Observa y registra cómo esto afecta la agudeza del pico de resonancia (el factor Q).
  • Construir un oscilador activo: Retira la fuente de CA y conecta el tanque LC a un transistor o un amplificador operacional con retroalimentación positiva (como una configuración Colpitts o Hartley) para crear un circuito independiente que genere su propia onda senoidal continua en la frecuencia de resonancia.

Más Casos Prácticos en Prometeo.blog

Encuentra este producto y/o libros sobre este tema en Amazon

Ir a Amazon

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.

Quiz rápido

Pregunta 1: ¿Cuál es el objetivo principal del caso práctico descrito en el texto?




Pregunta 2: ¿Qué ocurre exactamente en el punto de frecuencia de resonancia en el circuito tanque LC descrito?




Pregunta 3: ¿Cómo se alimenta el circuito tanque LC en este caso práctico?




Pregunta 4: ¿Por qué es esencial comprender la resonancia LC en la electrónica moderna?




Pregunta 5: En la sintonización de radiofrecuencia (RF), ¿para qué se utiliza un circuito LC?




Pregunta 6: ¿Qué tipo de filtros se pueden crear con circuitos LC para eliminar el ruido en señales de audio?




Pregunta 7: ¿Cuál es el papel de la resonancia LC en la transferencia de energía inalámbrica?




Pregunta 8: ¿Para qué se utilizan los circuitos LC en los circuitos osciladores?




Pregunta 9: ¿Qué método se menciona en el texto para encontrar la frecuencia de resonancia del circuito?




Pregunta 10: A nivel físico, ¿qué fenómeno principal se analiza en un tanque LC alimentado por CA?




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:


Caso práctico: Almacenamiento en convertidor Boost

Esquemático — Caso práctico: Almacenamiento en convertidor Boost

Nivel: Medio | Comprender el almacenamiento de energía magnética para elevar el voltaje.

Objetivo y caso de uso

En este caso práctico, construirás un convertidor Boost básico de lazo abierto para demostrar cómo un inductor almacena y libera energía magnética para elevar un voltaje de CC.

Por qué es útil:
* Permite que los dispositivos alimentados por batería funcionen a voltajes más altos (por ejemplo, generando 5 V a partir de una sola celda de iones de litio de 3.7 V).
* Alimenta tiras de LEDs que requieren un voltaje directo alto y constante.
* Captura y eleva el voltaje en sistemas de recolección de energía y frenado regenerativo.
* Proporciona rieles de alimentación versátiles en dispositivos electrónicos portátiles compactos sin requerir múltiples baterías.

Resultado esperado:
* Observarás que la corriente del inductor (I_inductor) aumenta cuando el interruptor está cerrado y disminuye cuando se abre.
* El voltaje de salida (V_out) será demostrablemente mayor que la fuente de voltaje de entrada.
* Registrarás la relación directa entre el ciclo de trabajo (Duty Cycle) del interruptor y la magnitud resultante de V_out.

Público objetivo y nivel:
Estudiantes de electrónica de nivel intermedio que están aprendiendo los fundamentos de las fuentes de alimentación conmutadas.

Materiales

  • V1: Fuente de CC de 5 V, función: entrada de alimentación principal
  • V2: Fuente de voltaje de pulsos (0-5 V, 100kHz, 50% de ciclo de trabajo), función: señal PWM para el interruptor
  • L1: Inductor de 100 µH, función: almacenamiento de energía magnética
  • M1: MOSFET de canal N (ej. IRLZ44N), función: elemento de conmutación principal
  • D1: Diodo Schottky (ej. 1N5819), función: evita la corriente inversa desde el capacitor
  • C1: Capacitor de 47 µF, función: suavizado del voltaje de salida
  • R1: Resistor de 100 Ω, función: carga básica para descargar el capacitor

Guía de conexionado

  • V1: se conecta entre VIN y 0 (GND).
  • V2: se conecta entre GATE_PWM y 0 (GND).
  • L1: se conecta entre VIN y SW_NODE.
  • M1: el Drenador (Drain) se conecta a SW_NODE, la Puerta (Gate) se conecta a GATE_PWM, el Surtidor (Source) se conecta a 0 (GND).
  • D1: el Ánodo se conecta a SW_NODE, el Cátodo se conecta a VOUT.
  • C1: se conecta entre VOUT y 0 (GND).
  • R1: se conecta entre VOUT y 0 (GND).

Diagrama de bloques conceptual

Conceptual block diagram — Boost Converter
Lectura rápida: entradas → bloque principal → salida (actuador o medida). Resume el esquemático ASCII de la siguiente sección.

Esquemático

Control Signal:
[ V2: PWM (0-5 V) ] --(GATE_PWM)--> [ M1:Gate ]

Power & Switching Path:
[ V1: 5 V DC ] --(VIN)--> [ L1: 100µH ] --(SW_NODE)--> [ M1:Drain ] --(Switch)--> [ M1:Source ] --> GND
                                             |
Boost Output & Load:                         |
                                            +--> [ D1: Schottky ] --(VOUT)--> [ R1: 100 Ω ] --> GND
                                                                       |
                                                                       +--> [ C1: 47µF ] --> GND
Esquema Eléctrico

Diagrama eléctrico

Diagrama electrico del caso: Caso práctico: Almacenamiento en convertidor Boost
Generado desde la netlist SPICE validada del caso.

🔒 Este diagrama eléctrico es premium. Con el pase de 7 días o la suscripción mensual podrás desbloquear el material didáctico completo y el pack PDF listo para imprimir.🔓 Ver planes de acceso premium

Mediciones y pruebas

  1. Comprobación del estado inicial: Aplica V1 (5 V) con V2 apagado (0% de ciclo de trabajo). Mide VOUT. El voltaje debería ser de aproximadamente 4.7 V (la entrada de 5 V menos la caída de voltaje directo del diodo Schottky).
  2. Activación de la conmutación: Activa V2 para suministrar una onda cuadrada de 100kHz con un ciclo de trabajo del 50%. Mide VOUT a través de R1. El voltaje debería subir a aproximadamente 9 V-10 V, demostrando la acción de elevación.
  3. Observación de la corriente del inductor: Mide la corriente que fluye a través de L1 (I_inductor). Observarás una forma de onda triangular. La pendiente ascendente ocurre mientras M1 está ENCENDIDO (almacenamiento de energía), y la pendiente descendente ocurre mientras M1 está APAGADO (liberación de energía hacia VOUT).
  4. Mapeo del ciclo de trabajo: Ajusta el ciclo de trabajo de V2 del 30% al 70% en incrementos del 10%. Registra VOUT en cada paso para verificar que un ciclo de trabajo mayor produce un voltaje de salida mayor.

Netlist SPICE y simulación

Netlist SPICE de referencia (ngspice) — extractoNetlist SPICE completo (ngspice)

* Boost converter storage

* Main power input
V1 VIN 0 DC 5

* PWM signal for the switch (100kHz, 50% duty cycle)
V2 GATE_PWM 0 PULSE(0 5 0 10n 10n 5u 10u)

* Magnetic energy storage
L1 VIN SW_NODE 100u

* Main switching element (N-channel MOSFET)
* Drain: SW_NODE, Gate: GATE_PWM, Source: 0, Bulk: 0
M1 SW_NODE GATE_PWM 0 0 IRLZ44N

* Prevents reverse current from capacitor
* Anode: SW_NODE, Cathode: VOUT
D1 SW_NODE VOUT 1N5819

* Output voltage smoothing
* ... (truncated in public view) ...

Copia este contenido en un archivo .cir y ejecútalo con ngspice.

🔒 Parte del contenido de esta sección es premium. Con el pase de 7 días o la suscripción mensual tendrás acceso al contenido completo (materiales, conexionado, compilación detallada, validación paso a paso, troubleshooting, mejoras/variantes y checklist) y podrás descargar el pack PDF listo para imprimir.

* Boost converter storage

* Main power input
V1 VIN 0 DC 5

* PWM signal for the switch (100kHz, 50% duty cycle)
V2 GATE_PWM 0 PULSE(0 5 0 10n 10n 5u 10u)

* Magnetic energy storage
L1 VIN SW_NODE 100u

* Main switching element (N-channel MOSFET)
* Drain: SW_NODE, Gate: GATE_PWM, Source: 0, Bulk: 0
M1 SW_NODE GATE_PWM 0 0 IRLZ44N

* Prevents reverse current from capacitor
* Anode: SW_NODE, Cathode: VOUT
D1 SW_NODE VOUT 1N5819

* Output voltage smoothing
C1 VOUT 0 47u

* Basic load to discharge capacitor
R1 VOUT 0 100

* Models
.model IRLZ44N NMOS(Level=1 VTO=2.0 KP=10.0 RS=0.05 RD=0.05)
.model 1N5819 D(IS=1e-6 RS=0.1 N=1.05 EG=0.69 XTI=2)

* Output Directives
* VOUT is the main output, GATE_PWM is the input stimulus
.print tran V(VOUT) V(GATE_PWM) V(SW_NODE) V(VIN) I(L1)

* Analysis
* Time constant is R*C = 4.7ms. Simulating for 10ms to observe steady-state boost voltage.
.op
.tran 0.1u 10m

.end

Resultados de Simulación (Transitorio)

Resultados de Simulación (Transitorio)
Análisis: The simulation shows the boost converter operating correctly. The output voltage (VOUT) starts near 5V and rises to a steady-state value of approximately 9.6V, with the switch node (SW_NODE) switching between ~0V and ~10V as driven by the 100kHz PWM signal.
Show raw data table (119800 rows)
Index   time            v(vout)         v(gate_pwm)     v(sw_node)      v(vin)          l1#branch
0	0.000000e+00	4.702912e+00	0.000000e+00	5.000000e+00	5.000000e+00	4.702912e-02
1	1.000000e-10	4.702912e+00	5.000000e-02	4.999798e+00	5.000000e+00	4.702912e-02
2	2.000000e-10	4.702912e+00	1.000000e-01	4.999798e+00	5.000000e+00	4.702912e-02
3	4.000000e-10	4.702912e+00	2.000000e-01	4.999797e+00	5.000000e+00	4.702912e-02
4	8.000000e-10	4.702912e+00	4.000000e-01	4.999797e+00	5.000000e+00	4.702912e-02
5	1.600000e-09	4.702912e+00	8.000000e-01	4.999797e+00	5.000000e+00	4.702912e-02
6	3.200000e-09	4.702912e+00	1.600000e+00	4.999797e+00	5.000000e+00	4.702913e-02
7	6.400000e-09	4.702910e+00	3.200000e+00	8.651034e-03	5.000000e+00	4.710899e-02
8	1.000000e-08	4.702907e+00	5.000000e+00	6.306948e-03	5.000000e+00	4.728872e-02
9	1.064000e-08	4.702906e+00	5.000000e+00	6.311218e-03	5.000000e+00	4.732068e-02
10	1.192000e-08	4.702905e+00	5.000000e+00	6.319746e-03	5.000000e+00	4.738460e-02
11	1.448000e-08	4.702902e+00	5.000000e+00	6.336800e-03	5.000000e+00	4.751244e-02
12	1.960000e-08	4.702897e+00	5.000000e+00	6.370908e-03	5.000000e+00	4.776811e-02
13	2.984000e-08	4.702887e+00	5.000000e+00	6.439123e-03	5.000000e+00	4.827946e-02
14	5.032000e-08	4.702866e+00	5.000000e+00	6.575553e-03	5.000000e+00	4.930212e-02
15	9.128000e-08	4.702825e+00	5.000000e+00	6.848406e-03	5.000000e+00	5.134738e-02
16	1.732000e-07	4.702743e+00	5.000000e+00	7.394086e-03	5.000000e+00	5.543754e-02
17	2.732000e-07	4.702643e+00	5.000000e+00	8.060152e-03	5.000000e+00	6.042981e-02
18	3.732000e-07	4.702543e+00	5.000000e+00	8.726166e-03	5.000000e+00	6.542142e-02
19	4.732000e-07	4.702443e+00	5.000000e+00	9.392128e-03	5.000000e+00	7.041236e-02
20	5.732000e-07	4.702343e+00	5.000000e+00	1.005804e-02	5.000000e+00	7.540264e-02
21	6.732000e-07	4.702243e+00	5.000000e+00	1.072390e-02	5.000000e+00	8.039225e-02
22	7.732000e-07	4.702143e+00	5.000000e+00	1.138970e-02	5.000000e+00	8.538119e-02
23	8.732000e-07	4.702043e+00	5.000000e+00	1.205546e-02	5.000000e+00	9.036947e-02
... (119776 more rows) ...

Errores comunes y cómo evitarlos

  • Usar un diodo rectificador estándar (ej. 1N4007): Los diodos estándar son demasiado lentos para apagarse a 100kHz, lo que provoca pérdidas de conmutación masivas y una mala conversión de voltaje. Usa siempre un diodo de recuperación rápida o Schottky como el 1N5819.
  • Saturación del núcleo del inductor: Si la clasificación de corriente máxima del inductor es menor que la corriente máxima de conmutación, el núcleo magnético se saturará. El inductor actuará entonces como un cortocircuito, destruyendo potencialmente el MOSFET. Verifica siempre la clasificación de corriente de saturación del inductor.
  • Operar sin carga: Hacer funcionar un convertidor boost sin una resistencia de carga (R1) puede hacer que el voltaje de salida aumente continuamente con cada ciclo de conmutación, alcanzando teóricamente el infinito y destruyendo el capacitor de salida o el MOSFET. Incluye siempre una carga mínima.

Solución de problemas

  • Síntoma: El voltaje de salida es igual al voltaje de entrada (menos la caída del diodo).
  • Causa: El MOSFET no está conmutando. V2 podría estar desconectado o el nivel de voltaje es demasiado bajo para superar el umbral de la puerta del MOSFET.
  • Solución: Verifica la señal GATE_PWM con un osciloscopio. Usa un MOSFET de nivel lógico si tu señal PWM está limitada a 3.3 V o 5 V.
  • Síntoma: El MOSFET se calienta extremadamente rápido.
  • Causa: El inductor se está saturando, o el MOSFET tiene una alta resistencia de encendido (RDS(on)) y está experimentando altas pérdidas de conducción.
  • Solución: Cambia el inductor por uno con una mayor clasificación de corriente. Asegúrate de que el voltaje de accionamiento de la puerta sea suficiente para encender completamente el MOSFET.
  • Síntoma: Voltaje de salida inestable o con mucha ondulación (ripple).
  • Causa: El capacitor de salida C1 es demasiado pequeño para la carga o tiene una alta Resistencia Serie Equivalente (ESR).
  • Solución: Aumenta la capacitancia de C1 o coloca un capacitor cerámico en paralelo con el capacitor electrolítico para reducir la ESR general.

Posibles mejoras y extensiones

  • Control de lazo cerrado: Agrega un divisor de voltaje en la salida conectado a un amplificador de error o a la entrada analógica de un microcontrolador. Ajusta dinámicamente el ciclo de trabajo PWM para mantener un VOUT constante independientemente de los cambios en R1 (la carga).
  • Rectificación síncrona: Reemplaza el diodo Schottky D1 con un segundo MOSFET de canal P o canal N accionado. Conmutar este segundo MOSFET de forma síncrona (inversamente a M1) reduce la caída de voltaje típica de un diodo, mejorando significativamente la eficiencia general del convertidor.

Más Casos Prácticos en Prometeo.blog

Encuentra este producto y/o libros sobre este tema en Amazon

Ir a Amazon

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.

Quiz rápido

Pregunta 1: ¿Cuál es el objetivo principal del convertidor Boost descrito en el texto?




Pregunta 2: ¿Qué sucede con la corriente del inductor cuando el interruptor se cierra?




Pregunta 3: ¿Cuál de las siguientes es una aplicación útil del convertidor Boost mencionada en el artículo?




Pregunta 4: ¿Qué sucede con la corriente del inductor cuando el interruptor se abre?




Pregunta 5: ¿Cómo es el voltaje de salida (V_out) en comparación con la fuente de voltaje de entrada en este circuito?




Pregunta 6: ¿Qué tipo de relación existe entre el ciclo de trabajo (Duty Cycle) del interruptor y la magnitud resultante de V_out?




Pregunta 7: ¿Qué tipo de lazo de control utiliza el convertidor Boost básico que se construirá en el caso práctico?




Pregunta 8: ¿Por qué es útil el convertidor Boost para alimentar tiras de LEDs?




Pregunta 9: Además de dispositivos a batería y LEDs, ¿en qué otro sistema se captura y eleva el voltaje usando esta tecnología?




Pregunta 10: ¿Qué ventaja ofrece el convertidor Boost en dispositivos electrónicos portátiles compactos?




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:


Caso práctico: Protección contra picos inductivos

Prototipo de Protección contra picos inductivos (Maker Style)

Nivel: Medio | Objetivo: Analizar la tensión transitoria generada al desconectar un inductor y mitigarla utilizando un diodo flyback.

Objetivo y caso de uso

En este caso práctico, construirás un circuito de inductor conmutado monitorizado por un osciloscopio para observar el destructivo pico de tensión (retroceso inductivo o inductive kickback) que ocurre cuando la corriente se interrumpe abruptamente. Luego, instalarás un diodo flyback en paralelo con la carga inductiva para limitar de forma segura esta tensión transitoria.

Por qué es útil:
* Previene daños catastróficos por sobretensión en componentes de conmutación sensibles como transistores, MOSFETs y pines de microcontroladores.
* Reduce significativamente la interferencia electromagnética (EMI) y la interferencia de radiofrecuencia (RFI) causadas por la formación de arcos de alta tensión a través de los contactos de interruptores mecánicos.
* Aumenta la fiabilidad, seguridad y vida útil de los sistemas de alimentación, controladores de motores y circuitos accionados por relés.

Resultado esperado:
* Sin el diodo, abrir el interruptor producirá un pico de tensión negativo masivo en el osciloscopio, que a menudo alcanza cientos de voltios.
* Con el diodo flyback instalado, el pico transitorio se limitará inmediatamente a un nivel seguro de aproximadamente -0.7 V.
* La energía magnética almacenada se disipará de forma segura como una corriente circulante que decae constantemente a través del bucle inductor-resistencia-diodo.

Público objetivo y nivel: Estudiantes de electrónica de nivel intermedio que aprenden sobre componentes reactivos, almacenamiento de energía y técnicas de protección de circuitos.

Materiales

  • V1: fuente de alimentación de 12 V CC, función: fuente de energía principal
  • SW1: interruptor de palanca o pulsador SPST, función: control de conexión del circuito
  • L1: inductor de 100 mH, función: almacenamiento de energía magnética
  • R1: resistencia de 100 Ω, función: limita la corriente en estado estacionario a 120 mA
  • D1: diodo rectificador 1N4007, función: protección flyback

Guía de conexionado

  • V1: se conecta entre el nodo VCC (positivo) y el nodo 0 (tierra).
  • SW1: se conecta entre el nodo VCC y el nodo SW_OUT.
  • L1: se conecta entre el nodo SW_OUT y el nodo L_MID.
  • R1: se conecta entre el nodo L_MID y el nodo 0.
  • D1: se conecta entre el nodo 0 (Ánodo) y el nodo SW_OUT (Cátodo) para polarización inversa durante el funcionamiento normal con el interruptor cerrado.

Diagrama de bloques conceptual

Conceptual block diagram — Flyback Protection
Lectura rápida: entradas → bloque principal → salida (actuador o medida). Resume el esquemático ASCII de la siguiente sección.

Esquemático

VCC (12 V) --> [ SW1: SPST Switch ] --(SW_OUT)--> [ L1: 100mH Inductor ] --(L_MID)--> [ R1: 100 Ω Resistor ] --> GND
                                         ^
                                         |
                              (Cathode)  |
                           [ D1: 1N4007 Flyback ]
                              (Anode)    ^
                                         |
                                        GND
Esquema Eléctrico

Diagrama eléctrico

Diagrama eléctrico del caso: Protección contra picos inductivos
Generado desde la netlist SPICE validada del caso.

🔒 Este diagrama eléctrico es premium. Con el pase de 7 días o la suscripción mensual podrás desbloquear el material didáctico completo y el pack PDF listo para imprimir.🔓 Ver planes de acceso premium

Mediciones y pruebas

  1. Conecta la sonda del osciloscopio al nodo SW_OUT y conecta la pinza de tierra al nodo 0. Configura el disparador (trigger) del osciloscopio en flanco de bajada, modo de disparo único (single-shot).
  2. Comienza con el diodo flyback (D1) completamente desconectado del circuito.
  3. Cierra el interruptor (SW1) para permitir que fluya la corriente. Espera un momento para que el campo magnético en el inductor se establezca por completo.
  4. Abre rápidamente el interruptor (SW1). Observa la captura del osciloscopio; verás un transitorio de tensión negativo masivo ya que el inductor actúa como una fuente de corriente, forzando la corriente a través de la apertura del interruptor.
  5. Conecta el diodo flyback (D1), verificando que el cátodo (extremo con la franja) se conecte al nodo SW_OUT y el ánodo se conecte al nodo 0.
  6. Repite el proceso de conmutación. La traza del osciloscopio mostrará ahora el transitorio negativo limitado de forma segura a aproximadamente -0.7 V, ya que el diodo se polariza en directa para proporcionar una ruta de descarga segura.

Netlist SPICE y simulación

Netlist SPICE de referencia (ngspice) — extractoNetlist SPICE completo (ngspice)

* Inductive peak protection
.width out=256

V1 VCC 0 DC 12

* SW1 modeled as a voltage-controlled switch connecting VCC to SW_OUT
S1 VCC SW_OUT SW_CTRL 0 SW_MODEL
V_SW_CTRL SW_CTRL 0 PULSE(0 5 100u 1u 1u 500u 1000u)
.model SW_MODEL SW(VT=2.5 VH=0.1 RON=0.01 ROFF=100Meg)

L1 SW_OUT L_MID 100m
R1 L_MID 0 100

* ... (truncated in public view) ...

Copia este contenido en un archivo .cir y ejecútalo con ngspice.

🔒 Parte del contenido de esta sección es premium. Con el pase de 7 días o la suscripción mensual tendrás acceso al contenido completo (materiales, conexionado, compilación detallada, validación paso a paso, troubleshooting, mejoras/variantes y checklist) y podrás descargar el pack PDF listo para imprimir.

* Inductive peak protection
.width out=256

V1 VCC 0 DC 12

* SW1 modeled as a voltage-controlled switch connecting VCC to SW_OUT
S1 VCC SW_OUT SW_CTRL 0 SW_MODEL
V_SW_CTRL SW_CTRL 0 PULSE(0 5 100u 1u 1u 500u 1000u)
.model SW_MODEL SW(VT=2.5 VH=0.1 RON=0.01 ROFF=100Meg)

L1 SW_OUT L_MID 100m
R1 L_MID 0 100

* Flyback protection diode
D1 0 SW_OUT 1N4007
.model 1N4007 D(IS=1e-9 N=1.9 RS=0.03 BV=1000 IBV=5e-08 CJO=10p VJ=0.7 M=0.5 TT=1e-07)

.op
.tran 1u 2000u
.print tran V(SW_CTRL) V(SW_OUT) V(L_MID) V(VCC) I(L1)

.end

Resultados de Simulación (Transitorio)

Resultados de Simulación (Transitorio)
Análisis: El análisis transitorio cubre de 0 s a 2 ms y captura el intervalo de conmutación. El nodo de conmutación y la corriente de la bobina quedan acotados, coherente con la ruta de flyback que protege el interruptor. Rangos principales: l1#branch 120 nA -> 62.7 mA; v(sw_out) -884 mV -> 12 V; v(l_mid) 12 uV -> 6.27 V.
Show raw data table (2088 rows)
Index   time            v(sw_ctrl)      v(sw_out)       v(l_mid)        v(vcc)          l1#branch
0	0.000000e+00	0.000000e+00	1.199996e-05	1.199996e-05	1.200000e+01	1.199996e-07
1	1.000000e-08	0.000000e+00	1.199996e-05	1.199996e-05	1.200000e+01	1.199996e-07
2	2.000000e-08	0.000000e+00	1.199996e-05	1.199996e-05	1.200000e+01	1.199996e-07
3	4.000000e-08	0.000000e+00	1.199996e-05	1.199996e-05	1.200000e+01	1.199996e-07
4	8.000000e-08	0.000000e+00	1.199996e-05	1.199996e-05	1.200000e+01	1.199996e-07
5	1.600000e-07	0.000000e+00	1.199996e-05	1.199996e-05	1.200000e+01	1.199996e-07
6	3.200000e-07	0.000000e+00	1.199996e-05	1.199996e-05	1.200000e+01	1.199996e-07
7	6.400000e-07	0.000000e+00	1.199996e-05	1.199996e-05	1.200000e+01	1.199996e-07
8	1.280000e-06	0.000000e+00	1.199996e-05	1.199996e-05	1.200000e+01	1.199996e-07
9	2.280000e-06	0.000000e+00	1.199996e-05	1.199996e-05	1.200000e+01	1.199996e-07
10	3.280000e-06	0.000000e+00	1.199996e-05	1.199996e-05	1.200000e+01	1.199996e-07
11	4.280000e-06	0.000000e+00	1.199996e-05	1.199996e-05	1.200000e+01	1.199996e-07
12	5.280000e-06	0.000000e+00	1.199996e-05	1.199996e-05	1.200000e+01	1.199996e-07
13	6.280000e-06	0.000000e+00	1.199996e-05	1.199996e-05	1.200000e+01	1.199996e-07
14	7.280000e-06	0.000000e+00	1.199996e-05	1.199996e-05	1.200000e+01	1.199996e-07
15	8.280000e-06	0.000000e+00	1.199996e-05	1.199996e-05	1.200000e+01	1.199996e-07
16	9.280000e-06	0.000000e+00	1.199996e-05	1.199996e-05	1.200000e+01	1.199996e-07
17	1.028000e-05	0.000000e+00	1.199996e-05	1.199996e-05	1.200000e+01	1.199996e-07
18	1.128000e-05	0.000000e+00	1.199996e-05	1.199996e-05	1.200000e+01	1.199996e-07
19	1.228000e-05	0.000000e+00	1.199996e-05	1.199996e-05	1.200000e+01	1.199996e-07
20	1.328000e-05	0.000000e+00	1.199996e-05	1.199996e-05	1.200000e+01	1.199996e-07
21	1.428000e-05	0.000000e+00	1.199996e-05	1.199996e-05	1.200000e+01	1.199996e-07
22	1.528000e-05	0.000000e+00	1.199996e-05	1.199996e-05	1.200000e+01	1.199996e-07
23	1.628000e-05	0.000000e+00	1.199996e-05	1.199996e-05	1.200000e+01	1.199996e-07
... (2064 more rows) ...

Errores comunes y cómo evitarlos

  • Invertir la polaridad del diodo: Colocar el diodo con el ánodo apuntando al nodo de tensión positiva crea un cortocircuito directo a tierra cuando el interruptor está cerrado. Esto destruirá el diodo o activará la protección contra sobrecorriente de la fuente de alimentación. Asegúrate siempre de que el cátodo apunte hacia el potencial más alto.
  • Usar un diodo con una capacidad de corriente inadecuada: El diodo flyback debe manejar de forma segura una corriente directa pico igual a la corriente en estado estacionario del inductor justo antes de la conmutación. Utiliza siempre diodos rectificadores, Schottky o de recuperación rápida con la clasificación adecuada.
  • Omitir la resistencia en serie: Conectar un inductor puro directamente a una fuente de CC de alta corriente actúa casi como un cortocircuito una vez que el campo magnético está completamente establecido. Incluye siempre una resistencia en serie limitadora de corriente, o asegúrate de que el inductor (como la bobina de un relé) tenga suficiente resistencia interna de CC.

Solución de problemas

  • Síntoma: La fuente de alimentación se apaga o su LED de límite de corriente se enciende inmediatamente al cerrar el interruptor.
    • Causa: El diodo flyback está instalado al revés, creando un cortocircuito desde la fuente de alimentación a tierra.
    • Solución: Desconecta la alimentación inmediatamente y dale la vuelta al diodo para que su extremo con la franja (cátodo) apunte hacia el nodo del interruptor.
  • Síntoma: Sigue apareciendo un pico de tensión masivo en el osciloscopio incluso con el diodo supuestamente instalado.
    • Causa: El diodo puede haberse abierto debido a un evento previo de sobrecorriente, o la conexión de la protoboard está suelta.
    • Solución: Verifica la continuidad del diodo usando el modo de diodo de un multímetro, y comprueba el asentamiento físico de los pines en los nodos del interruptor y de tierra.
  • Síntoma: La traza del osciloscopio muestra oscilaciones de alta frecuencia (ringing) en lugar de una limitación limpia.
    • Causa: Capacitancia parásita en el interruptor, el cableado o las sondas del osciloscopio que interactúan con el inductor.
    • Solución: Asegúrate de que la sonda del osciloscopio esté correctamente compensada (se recomienda el modo x10 para picos de alta tensión) y mantén los cables de tierra lo más cortos físicamente posible.

Posibles mejoras y extensiones

  • Conmutación automatizada con un MOSFET: Reemplaza el interruptor mecánico con un MOSFET de canal N accionado por un generador de ondas cuadradas (configurado como un interruptor de lado bajo) para observar la limitación repetitiva en el osciloscopio en tiempo real.
  • Descarga rápida usando un diodo Zener: Añade un diodo Zener con la clasificación adecuada en serie con el diodo flyback estándar (ánodo conectado a ánodo). Esto permite que el inductor descargue su energía mucho más rápido limitando la tensión a un nivel más alto, pero estrictamente controlado.

Más Casos Prácticos en Prometeo.blog

Encuentra este producto y/o libros sobre este tema en Amazon

Ir a Amazon

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.

Quiz rápido

Pregunta 1: ¿Cuál es el objetivo principal del caso práctico descrito en el texto?




Pregunta 2: ¿Cuál es el objetivo principal del caso práctico descrito en el texto?




Pregunta 3: ¿Cuál es el objetivo principal del caso práctico descrito en el texto?




Pregunta 4: ¿Cuál es el objetivo principal del caso práctico descrito en el texto?




Pregunta 5: ¿Cuál es el objetivo principal del caso práctico descrito en el texto?




Pregunta 6: ¿Cuál es el objetivo principal del caso práctico descrito en el texto?




Pregunta 7: ¿Cuál es el objetivo principal del caso práctico descrito en el texto?




Pregunta 8: ¿Cuál es el objetivo principal del caso práctico descrito en el texto?




Pregunta 9: ¿Cuál es el objetivo principal del caso práctico descrito en el texto?




Pregunta 10: ¿Cuál es el objetivo principal del caso práctico descrito en el texto?




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:


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

Caso práctico: control RUN/STOP por voz con 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.

Nota educativa de validación

Antes de publicar este caso, el contenido pasó la puerta automática de validación de Prometeo con estado PASS. Para este perfil FPGA/ULX3S, los bloques de Verilog sintetizable se comprobaron con Yosys (read_verilog) y el conjunto Verilog de diseño/test se revisó con Verilator. El validador también comprobó la estructura de los bloques de código, que los comandos usen opciones copiables con guiones ASCII, que no aparezcan stacks no soportados y que esté disponible la toolchain ULX3S/ECP5 (yosys, nextpnr-ecp5, ecppack, openFPGALoader).

Evidencia de validación publicada

  • Resultado automático: PASS.
  • Estructura parseada: 52 apartados, 1 tablas y 12 bloques de código detectados en el contenido publicado.
  • Código comprobado: 2 Verilog/Yosys-Verilator, 7 Bash/copy-paste checks.
  • Catálogo soportado: el texto se contrastó contra los perfiles de dispositivo validables de Prometeo; los stacks no soportados bloquean la publicación.
  • Hallazgos del informe: sin hallazgos bloqueantes.

Esta validación confirma compatibilidad sintáctica y de herramientas para el código publicado, pero no sustituye la prueba física sobre tu revisión exacta de ULX3S, tu archivo de restricciones de pines y tu 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.


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ón Pin INMP441 Nombre de señal FPGA ULX3S Dirección Notas
Alimentación VDD 3V3 Placa -> micrófono Usar solo 3.3 V
Tierra GND GND Común Se requiere tierra compartida
Reloj de bits SCK/BCLK mic_bclk FPGA -> micrófono Generado por la FPGA
Selección de palabra WS/LRCLK mic_ws FPGA -> micrófono Generada por la FPGA
Datos serie SD mic_sd Micrófono -> FPGA Muestreado por la FPGA
Selección de canal L/R GND o 3V3 Estático Selecciona un canal
LED RUN LED led_run FPGA -> LED ON cuando está en ejecución
LED STOP LED led_stop FPGA -> LED ON cuando está detenido
LED de actividad LED led_activity FPGA -> LED ON 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

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.

Encuentra este producto y/o libros sobre este tema en Amazon

Ir a Amazon

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.

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:


Caso práctico: monitor GPS NMEA con ULX3S

Caso práctico: monitor GPS NMEA con ULX3S — hero

Objetivo y caso de uso

Qué construirás: Un monitor GPS práctico basado en FPGA usando la Radiona ULX3S (Lattice ECP5-85F), un módulo GPS u-blox NEO-6M y cableado UART de 3.3 V. Recibirá datos NMEA a 9600 baudios, analizará sentencias de tiempo y posición con latencia de actualización inferior a un segundo, y mostrará actividad UART, estado de fix y cambios clave de estado en los LED de la ULX3S.

Por qué importa / Casos de uso

  • Verificación en banco del módulo GPS: Confirma rápidamente que un NEO-6M está alimentado, transmite sentencias NMEA válidas y responde a 9600 baudios sin abrir un terminal serie en una PC.
  • Diagnóstico portátil de instalación: Usa alimentación USB para comprobar el progreso del fix, el tráfico UART en vivo y las coordenadas cambiantes en campo antes de conectar el sistema anfitrión final; la actualización visible típica de estado es de 1 Hz en línea con la salida NMEA común.
  • Formación en diseño digital: Demuestra el manejo real en FPGA de recepción UART asíncrona, análisis de flujo ASCII y validación de sentencias en lugar de una simple demostración de loopback.
  • Prototipo de monitor serie autónomo: Crea un gps-nmea-position-time-monitor compacto para puesta en marcha de temporización, seguimiento y navegación con una carga de FPGA muy baja, típicamente muy por debajo del 5% de lógica y efectivamente 0% de uso de GPU.

Resultado esperado

  • Un diseño funcional para ULX3S que reciba de forma confiable datos NMEA UART de 3.3 V desde el NEO-6M a 9600 baudios.
  • Tiempo UTC analizado y campos básicos de posición a partir de sentencias comunes como GPRMC o GPGGA, con respuesta visible en LED dentro de un período de sentencia.
  • Indicación de estado para ausencia de datos, tráfico serie activo, recepción de sentencias y presencia de fix GPS, útil para pruebas rápidas en banco.
  • Una referencia reutilizable en FPGA para cargas de trabajo de análisis serie de bajo ancho de banda donde el rendimiento es mínimo pero el comportamiento determinista del hardware importa.

Audiencia: Aprendices de FPGA, desarrolladores embebidos y técnicos que validan hardware GPS; Nivel: Principiante a intermedio

Arquitectura/flujo: El NEO-6M entrega NMEA por UART de 3.3 V → el receptor UART de la ULX3S muestrea bytes serie con lógica temporizada por bit → el analizador extrae los campos de tiempo, fix y coordenadas de sentencias ASCII → la lógica de estado actualiza los LED a una cadencia de sentencias de aproximadamente 1 Hz con latencia interna de procesamiento del orden de milisegundos.

Nota educativa de validación

Antes de publicar este caso, el contenido pasó la puerta automática de validación de Prometeo con estado PASS. Para este perfil FPGA/ULX3S, los bloques de Verilog sintetizable se comprobaron con Yosys (read_verilog) y el conjunto Verilog de diseño/test se revisó con Verilator. El validador también comprobó la estructura de los bloques de código, que los comandos usen opciones copiables con guiones ASCII, que no aparezcan stacks no soportados y que esté disponible la toolchain ULX3S/ECP5 (yosys, nextpnr-ecp5, ecppack, openFPGALoader).

Evidencia de validación publicada

  • Resultado automático: PASS.
  • Estructura parseada: 48 apartados, 1 tablas y 12 bloques de código detectados en el contenido publicado.
  • Código comprobado: 3 Verilog/Yosys-Verilator, 6 Bash/copy-paste checks.
  • Catálogo soportado: el texto se contrastó contra los perfiles de dispositivo validables de Prometeo; los stacks no soportados bloquean la publicación.
  • Hallazgos del informe: sin hallazgos bloqueantes.

Esta validación confirma compatibilidad sintáctica y de herramientas para el código publicado, pero no sustituye la prueba física sobre tu revisión exacta de ULX3S, tu archivo de restricciones de pines y tu cableado real.

Nota educativa de seguridad

Este prototipo es un monitor educativo de datos GPS, no un instrumento certificado de navegación, temporización, automoción, aviación, marina, industrial o de seguridad crítica.

Puntos de seguridad y limitación:

  • Usa solo cableado UART de 3.3 V hacia la entrada de la FPGA, a menos que hayas verificado positivamente la compatibilidad eléctrica.
  • Muchas placas breakout GPS difieren en alimentación y comportamiento de E/S. Comprueba tu módulo exacto antes de conectarlo.
  • No uses este proyecto para tomar decisiones en tiempo real para:
  • vehículos
  • drones
  • embarcaciones
  • navegación personal en zonas peligrosas
  • infraestructuras críticas de temporización
  • Las configuraciones de banco alimentadas por USB pueden provocar errores accidentales de cableado. Apaga siempre antes de recablear.
  • Este tutorial no cubre diseño de carcasas para exterior, protección contra sobretensiones, protección ESD ni endurecimiento ambiental.
  • Si pruebas al aire libre, asegura cables y placas para que no generen riesgos de tropiezo o exposición al clima.
  • La indicación de fix en este proyecto refleja el estado NMEA analizado, no una corrección absoluta garantizada de posición.

Diagrama de bloques conceptual

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

Arquitectura funcional

El NEO-6M entrega NMEA por UART de 3.3 V

el receptor UART de la ULX3S muestrea byt…

el analizador extrae los campos de tiempo…

la lógica de estado actualiza los LED a u…

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

Antes de comenzar, deberías sentirte cómodo con:

  • Flujo de trabajo básico de FPGA desde la línea de comandos
  • Módulos Verilog simples y diseño síncrono
  • Conceptos de UART:
  • tasa de baudios
  • bit de inicio
  • bit de parada
  • formato 8N1
  • Edición de archivos de texto y ejecución de comandos de shell en Linux

Entorno anfitrión recomendado:

  • PC o portátil con Linux
  • Cable USB para programación/alimentación de la ULX3S
  • Adaptador USB-UART opcional si deseas inspeccionar la salida del GPS de forma independiente antes de conectarlo a la FPGA

Herramientas de software requeridas:

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

Materiales

Usa exactamente estos elementos de hardware:

Elemento Modelo exacto Propósito
Placa FPGA Radiona ULX3S (Lattice ECP5-85F) Plataforma FPGA principal
Módulo GPS u-blox NEO-6M GPS module Fuente de datos NMEA por UART
Nivel de voltaje serie 3.3 V UART wiring Conexión directa segura a nivel lógico
Cable USB Micro-USB o USB-C según la revisión de ULX3S Alimentación y programación
Cables jumper Hembra-hembra o mixtos según sea necesario Conexiones entre ULX3S y NEO-6M
Computadora Host Linux Compilación, programación y comprobaciones serie opcionales

Nota importante específica del modelo

Muchas placas breakout NEO-6M se alimentan con 5 V pero aun así exponen una TX de nivel lógico de 3.3 V. Debes verificar tu módulo específico. Este tutorial asume:

  • El VCC del módulo GPS se alimenta de acuerdo con el requisito de la placa breakout
  • La salida TX del GPS presentada a la FPGA es compatible con 3.3 V
  • La conexión UART directa se realiza solo mediante cableado UART de 3.3 V

Configuración/Conexión

Aquí no se usa un diagrama del circuito; sigue el texto exactamente.

Plan de señales

Este proyecto necesita solo tres conexiones eléctricas esenciales:

  1. Tierra común
  2. GPS TX -> entrada FPGA de la ULX3S
  3. Alimentación para el módulo GPS

Esquema práctico de conexión recomendado

  • Conecta NEO-6M GND a ULX3S GND
  • Conecta NEO-6M TX a un pin GPIO de entrada elegido en la ULX3S
  • Alimenta el módulo GPS desde una fuente adecuada:
  • Si tu breakout NEO-6M acepta 5 V en VCC, puedes alimentarlo desde una fuente segura de 5 V, asegurando aun así que la TX vista por la FPGA sea lógica de 3.3 V
  • Si tu breakout requiere 3.3 V en VCC, aliméntalo desde una línea regulada de 3.3 V
  • No conectes GPS RX a menos que específicamente quieras enviar comandos de configuración más adelante; no es necesario para este monitor

Selección de pines usada en este tutorial

Para mantener el diseño concreto, el nivel superior de la FPGA usa:

  • clk_25mhz como reloj del sistema
  • gps_rx_i como entrada UART desde el módulo GPS
  • led[7:0] como indicadores de salida

Para la ULX3S, los nombres reales de pines del encapsulado varían según el conjunto de restricciones de la placa. El flujo de trabajo más seguro es:

  1. Empezar desde la plantilla de restricciones conocida y funcional de tu placa ULX3S
  2. Reemplazar solo las señales usadas aquí
  3. Mantener el oscilador y los pines LED coincidiendo con la revisión de tu placa

En el ejemplo validado a continuación, se proporciona un archivo de restricciones en el estilo esperado por nextpnr-ecp5. Si tu revisión exacta de ULX3S tiene alias diferentes, ajusta solo los nombres de pin LOCATE COMP usando el pinout oficial de la ULX3S.

Significado de los LED usado por este proyecto

  • led[0]: latido, demuestra que la FPGA está funcionando
  • led[1]: pulso de actividad de caracteres UART
  • led[2]: línea NMEA válida completada
  • led[3]: sentencia RMC válida detectada
  • led[4]: estado RMC = A (fix activo)
  • led[5]: conmuta cuando se actualiza el campo de tiempo
  • led[6]: conmuta cuando se actualiza el campo de latitud
  • led[7]: conmuta cuando se actualiza el campo de longitud

Esto proporciona evidencia útil en campo sin necesidad de una pantalla.

Código validado

gps_uart_rx.v

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

module gps_uart_rx #(
    parameter integer CLK_HZ = 25000000,
    parameter integer BAUD   = 9600
) (
    input  wire clk,
    input  wire rst,
    input  wire rx,
    output reg  data_valid,
    output reg [7:0] data_byte
);

    localparam integer CLKS_PER_BIT = CLK_HZ / BAUD;
    localparam integer HALF_BIT     = CLKS_PER_BIT / 2;

    reg [15:0] clk_count = 0;
    reg [3:0]  bit_index = 0;
    reg [7:0]  rx_shift  = 8'h00;
    reg [2:0]  state     = 0;
    reg        rx_meta   = 1'b1;
    reg        rx_sync   = 1'b1;

    localparam S_IDLE  = 3'd0;
    localparam S_START = 3'd1;
    localparam S_DATA  = 3'd2;
    localparam S_STOP  = 3'd3;

    always @(posedge clk) begin
        rx_meta <= rx;
        rx_sync <= rx_meta;
    end

    always @(posedge clk) begin
        if (rst) begin
            state      <= S_IDLE;
            clk_count  <= 0;
            bit_index  <= 0;
            rx_shift   <= 8'h00;
            data_byte  <= 8'h00;
            data_valid <= 1'b0;
        end else begin
            data_valid <= 1'b0;

            case (state)
                S_IDLE: begin
                    clk_count <= 0;
                    bit_index <= 0;
                    if (rx_sync == 1'b0) begin
                        state <= S_START;
                    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.

module gps_uart_rx #(
    parameter integer CLK_HZ = 25000000,
    parameter integer BAUD   = 9600
) (
    input  wire clk,
    input  wire rst,
    input  wire rx,
    output reg  data_valid,
    output reg [7:0] data_byte
);

    localparam integer CLKS_PER_BIT = CLK_HZ / BAUD;
    localparam integer HALF_BIT     = CLKS_PER_BIT / 2;

    reg [15:0] clk_count = 0;
    reg [3:0]  bit_index = 0;
    reg [7:0]  rx_shift  = 8'h00;
    reg [2:0]  state     = 0;
    reg        rx_meta   = 1'b1;
    reg        rx_sync   = 1'b1;

    localparam S_IDLE  = 3'd0;
    localparam S_START = 3'd1;
    localparam S_DATA  = 3'd2;
    localparam S_STOP  = 3'd3;

    always @(posedge clk) begin
        rx_meta <= rx;
        rx_sync <= rx_meta;
    end

    always @(posedge clk) begin
        if (rst) begin
            state      <= S_IDLE;
            clk_count  <= 0;
            bit_index  <= 0;
            rx_shift   <= 8'h00;
            data_byte  <= 8'h00;
            data_valid <= 1'b0;
        end else begin
            data_valid <= 1'b0;

            case (state)
                S_IDLE: begin
                    clk_count <= 0;
                    bit_index <= 0;
                    if (rx_sync == 1'b0) begin
                        state <= S_START;
                    end
                end

                S_START: begin
                    if (clk_count == HALF_BIT) begin
                        if (rx_sync == 1'b0) begin
                            clk_count <= 0;
                            state <= S_DATA;
                        end else begin
                            state <= S_IDLE;
                        end
                    end else begin
                        clk_count <= clk_count + 16'd1;
                    end
                end

                S_DATA: begin
                    if (clk_count == CLKS_PER_BIT - 1) begin
                        clk_count <= 0;
                        rx_shift[bit_index] <= rx_sync;
                        if (bit_index == 4'd7) begin
                            bit_index <= 0;
                            state <= S_STOP;
                        end else begin
                            bit_index <= bit_index + 4'd1;
                        end
                    end else begin
                        clk_count <= clk_count + 16'd1;
                    end
                end

                S_STOP: begin
                    if (clk_count == CLKS_PER_BIT - 1) begin
                        clk_count <= 0;
                        if (rx_sync == 1'b1) begin
                            data_byte <= rx_shift;
                            data_valid <= 1'b1;
                        end
                        state <= S_IDLE;
                    end else begin
                        clk_count <= clk_count + 16'd1;
                    end
                end

                default: begin
                    state <= S_IDLE;
                end
            endcase
        end
    end
endmodule

gps_nmea_monitor.v

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

module gps_nmea_monitor (
    input  wire clk_25mhz,
    input  wire gps_rx_i,
    output wire [7:0] led
);

    wire rx_valid;
    wire [7:0] rx_byte;

    reg rst = 1'b0;

    gps_uart_rx #(
        .CLK_HZ(25000000),
        .BAUD(9600)
    ) u_rx (
        .clk(clk_25mhz),
        .rst(rst),
        .rx(gps_rx_i),
        .data_valid(rx_valid),
        .data_byte(rx_byte)
    );

    reg [23:0] hb_counter = 24'd0;
    reg hb_led = 1'b0;

    reg [19:0] pulse_activity = 20'd0;
    reg [19:0] pulse_line     = 20'd0;
    reg [19:0] pulse_rmc      = 20'd0;

    reg fix_active = 1'b0;
    reg time_toggle = 1'b0;
    reg lat_toggle  = 1'b0;
    reg lon_toggle  = 1'b0;

    reg [7:0] line_pos = 8'd0;
    reg [7:0] field_pos = 8'd0;

    reg in_line = 1'b0;
    reg candidate_rmc = 1'b0;
    reg rmc_seen_this_line = 1'b0;

    reg [7:0] id_buf [0:4];
    reg [7:0] field_buf [0:15];
    reg [4:0] field_len = 5'd0;

    integer i;

    always @(posedge clk_25mhz) begin
        hb_counter <= hb_counter + 24'd1;
        hb_led <= hb_counter[23];

        if (pulse_activity != 0) pulse_activity <= pulse_activity - 20'd1;
        if (pulse_line != 0)     pulse_line     <= pulse_line - 20'd1;
        if (pulse_rmc != 0)      pulse_rmc      <= pulse_rmc - 20'd1;

        if (rx_valid) begin
            pulse_activity <= 20'd500000;

            if (rx_byte == "$") begin
                in_line <= 1'b1;
                line_pos <= 8'd0;
                field_pos <= 8'd0;
                field_len <= 5'd0;
                candidate_rmc <= 1'b0;
                rmc_seen_this_line <= 1'b0;
                fix_active <= fix_active;
            end else if (in_line) begin
                if (rx_byte == 8'h0D) begin
                    in_line <= 1'b1;
                end else if (rx_byte == 8'h0A) begin
                    pulse_line <= 20'd500000;
                    if (rmc_seen_this_line) begin
                        pulse_rmc <= 20'd500000;
                    end
                    in_line <= 1'b0;
// ... 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 gps_nmea_monitor (
    input  wire clk_25mhz,
    input  wire gps_rx_i,
    output wire [7:0] led
);

    wire rx_valid;
    wire [7:0] rx_byte;

    reg rst = 1'b0;

    gps_uart_rx #(
        .CLK_HZ(25000000),
        .BAUD(9600)
    ) u_rx (
        .clk(clk_25mhz),
        .rst(rst),
        .rx(gps_rx_i),
        .data_valid(rx_valid),
        .data_byte(rx_byte)
    );

    reg [23:0] hb_counter = 24'd0;
    reg hb_led = 1'b0;

    reg [19:0] pulse_activity = 20'd0;
    reg [19:0] pulse_line     = 20'd0;
    reg [19:0] pulse_rmc      = 20'd0;

    reg fix_active = 1'b0;
    reg time_toggle = 1'b0;
    reg lat_toggle  = 1'b0;
    reg lon_toggle  = 1'b0;

    reg [7:0] line_pos = 8'd0;
    reg [7:0] field_pos = 8'd0;

    reg in_line = 1'b0;
    reg candidate_rmc = 1'b0;
    reg rmc_seen_this_line = 1'b0;

    reg [7:0] id_buf [0:4];
    reg [7:0] field_buf [0:15];
    reg [4:0] field_len = 5'd0;

    integer i;

    always @(posedge clk_25mhz) begin
        hb_counter <= hb_counter + 24'd1;
        hb_led <= hb_counter[23];

        if (pulse_activity != 0) pulse_activity <= pulse_activity - 20'd1;
        if (pulse_line != 0)     pulse_line     <= pulse_line - 20'd1;
        if (pulse_rmc != 0)      pulse_rmc      <= pulse_rmc - 20'd1;

        if (rx_valid) begin
            pulse_activity <= 20'd500000;

            if (rx_byte == "$") begin
                in_line <= 1'b1;
                line_pos <= 8'd0;
                field_pos <= 8'd0;
                field_len <= 5'd0;
                candidate_rmc <= 1'b0;
                rmc_seen_this_line <= 1'b0;
                fix_active <= fix_active;
            end else if (in_line) begin
                if (rx_byte == 8'h0D) begin
                    in_line <= 1'b1;
                end else if (rx_byte == 8'h0A) begin
                    pulse_line <= 20'd500000;
                    if (rmc_seen_this_line) begin
                        pulse_rmc <= 20'd500000;
                    end
                    in_line <= 1'b0;
                end else if (rx_byte == ",") begin
                    if (field_pos == 8'd0) begin
                        if ((id_buf[0] == "G") &&
                            (id_buf[1] == "P" || id_buf[1] == "N") &&
                            (id_buf[2] == "R") &&
                            (id_buf[3] == "M") &&
                            (id_buf[4] == "C")) begin
                            candidate_rmc <= 1'b1;
                            rmc_seen_this_line <= 1'b1;
                        end
                    end else if (candidate_rmc) begin
                        if (field_pos == 8'd1 && field_len != 0) begin
                            time_toggle <= ~time_toggle;
                        end
                        if (field_pos == 8'd2 && field_len != 0) begin
                            if (field_buf[0] == "A")
                                fix_active <= 1'b1;
                            else
                                fix_active <= 1'b0;
                        end
                        if (field_pos == 8'd3 && field_len != 0) begin
                            lat_toggle <= ~lat_toggle;
                        end
                        if (field_pos == 8'd5 && field_len != 0) begin
                            lon_toggle <= ~lon_toggle;
                        end
                    end

                    field_pos <= field_pos + 8'd1;
                    field_len <= 5'd0;
                end else if (rx_byte == "*") begin
                    if (candidate_rmc) begin
                        if (field_pos == 8'd1 && field_len != 0) begin
                            time_toggle <= ~time_toggle;
                        end
                        if (field_pos == 8'd2 && field_len != 0) begin
                            if (field_buf[0] == "A")
                                fix_active <= 1'b1;
                            else
                                fix_active <= 1'b0;
                        end
                        if (field_pos == 8'd3 && field_len != 0) begin
                            lat_toggle <= ~lat_toggle;
                        end
                        if (field_pos == 8'd5 && field_len != 0) begin
                            lon_toggle <= ~lon_toggle;
                        end
                    end
                end else begin
                    if (field_pos == 8'd0) begin
                        if (line_pos < 8'd5) begin
                            id_buf[line_pos] <= rx_byte;
                        end
                        line_pos <= line_pos + 8'd1;
                    end else begin
                        if (field_len < 5'd16) begin
                            field_buf[field_len] <= rx_byte;
                            field_len <= field_len + 5'd1;
                        end
                    end
                end
            end
        end
    end

    assign led[0] = hb_led;
    assign led[1] = (pulse_activity != 0);
    assign led[2] = (pulse_line != 0);
    assign led[3] = (pulse_rmc != 0);
    assign led[4] = fix_active;
    assign led[5] = time_toggle;
    assign led[6] = lat_toggle;
    assign led[7] = lon_toggle;

endmodule

tb_gps_nmea_monitor.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_gps_nmea_monitor;

    reg clk = 1'b0;
    reg gps_rx_i = 1'b1;
    wire [7:0] led;

    gps_nmea_monitor dut (
        .clk_25mhz(clk),
        .gps_rx_i(gps_rx_i),
        .led(led)
    );

    always #20 clk = ~clk; // 25 MHz

    localparam integer BIT_NS = 104166; // approx 9600 baud

    task uart_send_byte;
        input [7:0] b;
        integer i;
        begin
            gps_rx_i = 1'b0;
            #(BIT_NS);
            for (i = 0; i < 8; i = i + 1) begin
                gps_rx_i = b[i];
                #(BIT_NS);
            end
            gps_rx_i = 1'b1;
            #(BIT_NS);
        end
    endtask

    task uart_send_string;
        input [8*96-1:0] s;
        integer i;
        reg [7:0] ch;
// ... 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_gps_nmea_monitor;

    reg clk = 1'b0;
    reg gps_rx_i = 1'b1;
    wire [7:0] led;

    gps_nmea_monitor dut (
        .clk_25mhz(clk),
        .gps_rx_i(gps_rx_i),
        .led(led)
    );

    always #20 clk = ~clk; // 25 MHz

    localparam integer BIT_NS = 104166; // approx 9600 baud

    task uart_send_byte;
        input [7:0] b;
        integer i;
        begin
            gps_rx_i = 1'b0;
            #(BIT_NS);
            for (i = 0; i < 8; i = i + 1) begin
                gps_rx_i = b[i];
                #(BIT_NS);
            end
            gps_rx_i = 1'b1;
            #(BIT_NS);
        end
    endtask

    task uart_send_string;
        input [8*96-1:0] s;
        integer i;
        reg [7:0] ch;
        begin
            for (i = 95; i >= 0; i = i - 1) begin
                ch = s[i*8 +: 8];
                if (ch != 8'h00)
                    uart_send_byte(ch);
            end
        end
    endtask

    initial begin
        #(1000000);

        uart_send_string({
            "$GPRMC,123519,V,4807.038,N,01131.000,E,0.0,0.0,230394,003.1,W*53",
            8'h0D, 8'h0A
        });

        #(2000000);

        uart_send_string({
            "$GPRMC,123520,A,4807.038,N,01131.000,E,0.1,0.0,230394,003.1,W*52",
            8'h0D, 8'h0A
        });

        #(5000000);

        $display("LED state = %b", led);
        if (led[4] !== 1'b1) begin
            $display("ERROR: fix_active LED did not assert");
            $fatal;
        end

        $display("PASS: RMC monitor parsed active fix.");
        $finish;
    end

endmodule

ulx3s_gps_nmea.lpf

Ajusta los nombres exactos de pin LOCATE COMP si tu revisión de ULX3S es diferente. Mantén los nombres de señal sin cambios.

BLOCK RESETPATHS;
BLOCK ASYNCPATHS;

FREQUENCY PORT "clk_25mhz" 25 MHZ;

LOCATE COMP "clk_25mhz" SITE "G2";

LOCATE COMP "gps_rx_i" SITE "P17";
IOBUF PORT "gps_rx_i" IO_TYPE=LVCMOS33 PULLMODE=UP;

LOCATE COMP "led[0]" SITE "B2";
LOCATE COMP "led[1]" SITE "C2";
LOCATE COMP "led[2]" SITE "C1";
LOCATE COMP "led[3]" SITE "D2";
LOCATE COMP "led[4]" SITE "D1";
LOCATE COMP "led[5]" SITE "E2";
LOCATE COMP "led[6]" SITE "E1";
LOCATE COMP "led[7]" SITE "F2";

IOBUF PORT "led[0]" IO_TYPE=LVCMOS33;
IOBUF PORT "led[1]" IO_TYPE=LVCMOS33;
IOBUF PORT "led[2]" IO_TYPE=LVCMOS33;
IOBUF PORT "led[3]" IO_TYPE=LVCMOS33;
IOBUF PORT "led[4]" IO_TYPE=LVCMOS33;
IOBUF PORT "led[5]" IO_TYPE=LVCMOS33;
IOBUF PORT "led[6]" IO_TYPE=LVCMOS33;
IOBUF PORT "led[7]" IO_TYPE=LVCMOS33;

Comandos de compilación/grabación/ejecución

Crea un directorio de trabajo y coloca allí los cuatro archivos.

1) Lint con Verilator

verilator --lint-only -Wall -Wno-DECLFILENAME gps_uart_rx.v gps_nmea_monitor.v tb_gps_nmea_monitor.v

2) Ejecutar simulación

verilator -Wall -Wno-DECLFILENAME --binary gps_uart_rx.v gps_nmea_monitor.v tb_gps_nmea_monitor.v
./obj_dir/Vtb_gps_nmea_monitor

La línea final esperada en consola debe incluir:

PASS: RMC monitor parsed active fix.

3) Sintetizar para ECP5-85F

Importante: la síntesis debe usar solo archivos sintetizables.

yosys -p "read_verilog gps_uart_rx.v gps_nmea_monitor.v; synth_ecp5 -top gps_nmea_monitor -json gps_nmea_monitor.json"

4) Place and route

Usa el encapsulado ULX3S correcto para la revisión de tu placa. Un objetivo común de ULX3S ECP5-85F es CABGA381.

nextpnr-ecp5 --85k --package CABGA381 --json gps_nmea_monitor.json --lpf ulx3s_gps_nmea.lpf --textcfg gps_nmea_monitor.config

5) Empaquetar bitstream

ecppack gps_nmea_monitor.config gps_nmea_monitor.bit

6) Programar la ULX3S

openFPGALoader -b ulx3s gps_nmea_monitor.bit

7) Ejecutar en hardware

  • Alimenta la ULX3S por USB
  • Alimenta correctamente el NEO-6M
  • Conecta:
  • GPS GND -> ULX3S GND
  • GPS TX -> pin gps_rx_i de la ULX3S usado en el LPF
  • Coloca el GPS donde sea posible recibir satélites:
  • al aire libre es lo mejor
  • cerca de una ventana despejada puede funcionar
  • Observa los LED durante 10 a 60 segundos

Validación paso a paso

1) Validar el módulo GPS de forma independiente si es necesario

Antes de involucrar la FPGA, suele ser útil confirmar que el GPS está emitiendo datos NMEA:

  • Conecta la TX del NEO-6M a la entrada de un adaptador USB-UART conocido y funcional
  • Abre un terminal serie a 9600
  • Busca líneas como:
  • $GPRMC,...
  • $GPGGA,...

Si no ves texto NMEA legible, corrige eso primero.

2) Validar el comportamiento de la simulación

Después de ejecutar la simulación con Verilator:

  • Confirma que la prueba termina con PASS
  • Confirma que no aparecen errores fatales
  • La simulación inyecta:
  • una línea RMC con estado no válido (V)
  • una línea RMC con estado activo (A)
  • El resultado esperado es que:
  • la lógica UART reciba bytes
  • el analizador detecte RMC
  • led[4] pase a 1

3) Validar la configuración de la FPGA

Después de openFPGALoader:

  • Confirma que la herramienta informa que se encontró el dispositivo ULX3S
  • Confirma que no se muestra ningún error de carga del bitstream
  • Después de programar:
  • led[0] debería parpadear como latido
  • Si el latido no parpadea, la imagen de FPGA no se está ejecutando correctamente

4) Validar la actividad UART en hardware

Con el GPS conectado y alimentado:

  • led[1] debería generar pulsos o parecer activo con frecuencia cuando llegan caracteres NMEA
  • led[2] debería generar pulsos cuando terminan líneas completas
  • led[3] debería generar pulsos cuando se vean sentencias RMC

Interpretación:

  • led[1] apagado todo el tiempo:
  • problema de cableado
  • mapeo de pin incorrecto
  • nivel de voltaje incorrecto
  • tasa de baudios incorrecta
  • GPS sin alimentación
  • led[1] activo pero led[3] nunca activo:
  • el analizador no está viendo RMC
  • corrupción serie
  • formato de mensaje/talker inesperado

5) Validar la indicación de fix

Observa led[4]:

  • led[4] = 0 significa que el último estado RMC analizado no estaba activo (V) o que todavía no se ha visto una línea activa válida
  • led[4] = 1 significa que se ha analizado una sentencia RMC con estado A

Este es el criterio principal de éxito para un monitor GPS útil.

6) Validar actualizaciones continuas en campo

Observa los indicadores de actualización:

  • led[5] conmuta cuando se actualiza el campo de tiempo
  • led[6] conmuta cuando se actualiza el campo de latitud
  • led[7] conmuta cuando se actualiza el campo de longitud

Si estos cambian con el tiempo mientras led[3] genera pulsos, la FPGA está analizando campos clave de posición/tiempo en lugar de limitarse a detectar tráfico UART bruto.

7) Comportamiento esperado realista

En una sesión práctica:

  • En interiores sin vista al cielo:
  • normalmente aparece actividad UART
  • puede haber RMC
  • el fix puede seguir inválido durante mucho tiempo
  • Al aire libre:
  • un fix activo suele ser mucho más probable
  • led[4] debería encenderse finalmente
  • los indicadores de campo deberían seguir cambiando

Solución de problemas

Ningún LED responde excepto quizá el latido

Comprueba:

  • ¿El módulo GPS está alimentado correctamente?
  • ¿La tierra está compartida entre el GPS y la ULX3S?
  • ¿La TX del GPS está realmente conectada a la entrada FPGA elegida?
  • ¿Usaste el pin LPF correcto para la revisión real de tu placa ULX3S?

El latido funciona, pero no hay actividad UART

Posibles causas:

  • Tasa de baudios incorrecta:
  • la mayoría de los módulos NEO-6M usan 9600 baudios por defecto, pero verifica el tuyo
  • Nivel lógico de TX del GPS incompatible o ausente
  • Incompatibilidad de ubicación de pin en el LPF
  • Cable jumper roto
  • Módulo GPS no completamente alimentado o sin arrancar

Hay actividad UART, pero no detección de RMC

Posibles causas:

  • Tu GPS entrega GNRMC en lugar de GPRMC
  • este diseño ya acepta tanto GPRMC como GNRMC
  • Corrupción serie debido a mal cableado
  • Temporización de baudios incorrecta porque el reloj de tu placa no es realmente de 25 MHz
  • Ruido en la entrada RX

Se detecta RMC, pero el fix nunca se activa

Esto a menudo significa que el diseño FPGA está bien y que el problema es el entorno del GPS.

Prueba:

  • Moverte al aire libre
  • Esperar más tiempo para un arranque en frío
  • Comprobar la conexión de la antena
  • Verificar el estado del módulo con un terminal serie en la PC

Errores de compilación en nextpnr o en el mapeo LPF

Causas probables:

  • El encapsulado CABGA381 no coincide con tu placa
  • Los nombres de pin de LED o reloj son incorrectos para tu revisión de ULX3S
  • Los nombres de pin de restricciones necesitan adaptarse desde los archivos oficiales de ULX3S

Si hace falta, mantén el Verilog sin cambios y ajusta solo el LPF.

Mejoras

Una vez que el monitor base funcione, puedes ampliarlo hasta convertirlo en un instrumento de campo más capaz.

Mejoras prácticas

  • Añadir salida de siete segmentos u OLED
  • Mostrar la hora UTC directamente en la pantalla local
  • Exponer valores analizados por una segunda UART
  • Enviar estado compacto legible por máquina a una PC o microcontrolador
  • Añadir verificación de checksum
  • Mejorar la confianza en que las sentencias analizadas no están corruptas
  • Soportar más sentencias NMEA
  • Analizar GGA para altitud y conteo de satélites
  • Añadir tiempo de espera de fix
  • Apagar el LED de fix si no llega ninguna sentencia activa durante varios segundos
  • Registrar estadísticas de sentencias
  • Contar líneas por segundo, tramas inválidas y transiciones de fix
  • Páginas de modo controladas por botones
  • Un modo para estado de tráfico bruto, otro para tendencias del estado de fix

Mejoras de ingeniería

  • Añadir un FIFO pequeño entre UART y analizador
  • Añadir comprobaciones explícitas de encuadre de línea CR/LF
  • Añadir botones con anti-rebote para borrar banderas de estado
  • Usar un analizador de máquina de estados finitos más estricto para ID de sentencias y campos
  • Exportar bytes de campos analizados a un banco de registros simple para acceso futuro desde un host

Lista de verificación final

Usa esta lista antes de declarar el proyecto completo:

  • [ ] Usé la familia de hardware exacta: FPGA
  • [ ] Usé el modelo exacto: Radiona ULX3S (Lattice ECP5-85F) + u-blox NEO-6M GPS module + 3.3 V UART wiring
  • [ ] El GPS y la ULX3S comparten una tierra común
  • [ ] La TX del GPS está conectada al pin de entrada FPGA definido en el LPF
  • [ ] Verifiqué que la lógica UART del GPS es segura para 3.3 V
  • [ ] El lint de Verilator se completó sin errores bloqueantes
  • [ ] La simulación imprimió PASS: RMC monitor parsed active fix.
  • [ ] La síntesis de Yosys se completó correctamente
  • [ ] nextpnr-ecp5 se completó correctamente para el objetivo ECP5-85F
  • [ ] El bitstream se empaquetó con ecppack
  • [ ] La placa se programó con openFPGALoader -b ulx3s
  • [ ] led[0] parpadea después de programar
  • [ ] led[1] muestra actividad UART cuando el GPS está conectado
  • [ ] led[3] indica que se están reconociendo sentencias RMC
  • [ ] led[4] se enciende cuando el GPS informa un fix activo
  • [ ] led[5], led[6] y led[7] cambian a medida que se actualizan los campos de tiempo/posición

Si todos los elementos están marcados, tienes un gps-nmea-position-time-monitor práctico basado en FPGA que es genuinamente útil para diagnóstico de módulos GPS y educación sobre datos serie.

Encuentra este producto y/o libros sobre este tema en Amazon

Ir a Amazon

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.

Quiz rápido

Pregunta 1: ¿Qué placa FPGA se utiliza para construir el monitor GPS según el artículo?




Pregunta 2: ¿Qué módulo GPS se especifica para este proyecto?




Pregunta 3: ¿A qué velocidad de baudios se reciben los datos del módulo GPS?




Pregunta 4: ¿Qué tipo de cableado y voltaje se utiliza para la comunicación con el GPS?




Pregunta 5: ¿Qué formato de datos transmite el módulo GPS para ser analizado?




Pregunta 6: ¿Dónde se visualiza la actividad UART y el estado de fix del GPS?




Pregunta 7: ¿Cuál es la latencia esperada para la actualización de sentencias de tiempo y posición?




Pregunta 8: ¿Qué ventaja ofrece este monitor para la verificación en banco del módulo GPS?




Pregunta 9: ¿Cuál es la frecuencia típica de actualización visible de estado en este sistema?




Pregunta 10: Para la formación en diseño digital, ¿qué demuestra este proyecto en la FPGA?




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: