Caso práctico: Control PWM de servos con FPGA en DE10‑Lite

Caso práctico: Control PWM de servos con FPGA en DE10‑Lite — hero

Objetivo y caso de uso

Qué construirás: Un generador PWM de 50 Hz en Verilog en la Intel DE10-Lite para controlar un servo RC.

Para qué sirve

  • Control preciso de ángulos en servos RC para aplicaciones robóticas.
  • Generación de señales PWM para proyectos de automatización del hogar.
  • Implementación de sistemas de control en modelos a escala de vehículos.
  • Desarrollo de prototipos de dispositivos que requieren control de movimiento.

Resultado esperado

  • Señal PWM estable de 50 Hz con pulso variable entre 1.0 ms y 2.0 ms.
  • Control de posición del servo con precisión de 1° a 180°.
  • Latencia de respuesta del servo inferior a 50 ms en condiciones de carga normal.
  • Consumo de corriente del sistema inferior a 500 mA durante la operación.

Público objetivo: Estudiantes y entusiastas de la electrónica; Nivel: Básico

Arquitectura/flujo: Generación de señal PWM en Verilog -> Envío a la FPGA DE10-Lite -> Control del servo RC.

Nivel: Básico

Introducción

En este caso práctico aprenderás a generar una señal PWM específica para controlar un servomotor hobby (tipo RC) utilizando una FPGA de la familia Intel MAX 10, concretamente la placa Intel/Altera DE10-Lite (MAX 10). Implementaremos el generador de PWM en Verilog y lo validaremos tanto con instrumentos de medida (si dispones de ellos) como con la respuesta física del servomotor. Mantendremos el enfoque estrictamente práctico: generar una señal estable de 50 Hz con un pulso de 1.0 ms a 2.0 ms que corresponda a ángulos aproximados de 0° a 180° en un servo típico.

El objetivo “pwm-servo-control” guía todas las decisiones: herramientas, conexiones, código y validación están centrados en controlar uno o más servos de manera fiable desde la DE10‑Lite, respetando límites de potencia/seguridad y buenas prácticas de diseño digital.

Prerrequisitos

Sistema operativo y herramientas confirmadas

  • Sistemas operativos compatibles:
  • Linux: Ubuntu 20.04 LTS (64-bit) recomendado para este tutorial.
  • Windows 10 (64-bit) como alternativa (se proporcionan rutas/ejecutables equivalentes).
  • Toolchain (edición y versiones exactas):
  • Intel Quartus Prime Lite Edition 21.1 (Build 850 06/23/2021)
    • Linux (instalación por defecto): /opt/intelFPGA_lite/21.1/quartus
    • Windows (instalación por defecto): C:\intelFPGA_lite\21.1\quartus
  • ModelSim – Intel FPGA Edition 21.1 (opcional, solo si quieres simular)
    • Linux: /opt/intelFPGA_lite/21.1/modelsim_ase
    • Windows: C:\intelFPGA_lite\21.1\modelsim_ase
  • Controlador de programación:
    • Intel USB‑Blaster II (driver instalado y reconocido por el sistema).

Conocimientos previos mínimos

  • Conceptos básicos de HDL/Verilog (módulos, señales, siempre con reloj).
  • Manejo básico de terminal (Linux o PowerShell/CMD en Windows).
  • Conocimientos básicos de señales PWM para servos:
  • Frecuencia típica: 50 Hz (periodo 20 ms).
  • Ancho de pulso: 1.0 ms (≈0°), 1.5 ms (≈90°), 2.0 ms (≈180°).

Materiales

  • Placa FPGA: Intel/Altera DE10-Lite (MAX 10), dispositivo MAX 10 10M50DAF484C7G.
  • Cable USB tipo mini‑B (incluido con la DE10‑Lite): para alimentación y JTAG (USB‑Blaster II).
  • Servomotor hobby (por ejemplo, SG90, MG90S, o similar de 4.8–6.0 V).
  • Fuente externa de 5 V para el servo, con corriente suficiente:
  • Recomendado ≥1 A si es un servo pequeño (SG90 ~250–650 mA pico).
  • Prototipo/conexión:
  • Cables dupont macho‑hembra para conectar la señal PWM desde el header GPIO_0 de la DE10‑Lite al pin de señal del servo.
  • Cables para GND común entre la DE10‑Lite y la fuente del servo.
  • Breadboard (opcional, para organizar las conexiones).
  • Instrumentación (opcional pero recomendable):
  • Multímetro para verificar GND común y los 5 V de la fuente del servo.
  • Osciloscopio o analizador lógico para observar la señal PWM de 50 Hz.
  • Accesorios del servo:
  • Brazo o horn del servo montado para observar movimiento angular.

Preparación y conexión

Antes de conectar nada, ten en cuenta:
– No alimentes el servo desde el puerto USB de la DE10-Lite. Usa una fuente externa de 5 V dedicada.
– Es imprescindible compartir GND entre la fuente del servo y la placa DE10-Lite para que la señal PWM sea referenciada correctamente.
– La salida de la FPGA es de 3.3 V (nivel alto). Los servos RC suelen aceptar señal de control 3.3 V sin problema; verifica la hoja de datos si usas modelos especiales.

Puertos/recursos de la DE10-Lite que utilizaremos

  • Reloj de sistema: CLOCK_50 (50 MHz).
  • Entradas: SW[3:0] (DIP switches) para seleccionar el ángulo deseado (16 posiciones).
  • Botón: KEY[0] como reset (activo en bajo).
  • LED de usuario: LEDR[0] para indicar actividad (test de vida/estado PWM).
  • Conector de expansión: GPIO_0, línea GPIO_0[0] para la señal PWM hacia el servo.

Tabla de señales y conexiones

La placa DE10-Lite provee headers GPIO serigrafiados en la PCB con nombres como GPIO_0[0], GPIO_0[1], etc. Utilizaremos GPIO_0[0] como salida PWM. El GND del servo debe unirse al GND de la placa. La alimentación del servo proviene de la fuente externa de 5 V.

Elemento Señal FPGA Header/etiqueta en PCB Conectar a Comentarios
Reloj CLOCK_50 CLOCK_50 Interno a la placa; no requiere cableado externo.
Reset KEY[0] KEY0 Pulsador en placa; activo en bajo.
Selectores SW[3:0] SW0..SW3 DIP switches en placa para posición del servo.
PWM hacia servo GPIO_0[0] Conector GPIO_0, línea [0] Señal del servo (cable amarillo/blanco) Salida a 3.3 V; apto como señal de control.
Tierra común GND GND en GPIO_0 GND del servo y GND de la fuente 5 V GNDs deben unirse.
Alimentación servo +5 V de fuente externa al V+ del servo (cable rojo) Nunca desde la DE10‑Lite.

Pasos de conexión (resumen):
1. Con la DE10‑Lite apagada (USB desconectado), prepara tu fuente de 5 V para el servo.
2. Une GND de la fuente 5 V con un pin GND del conector GPIO_0 de la DE10‑Lite (GND común).
3. Alimenta el servo con +5 V (cable rojo) desde la fuente externa y GND (cable negro) a GND común.
4. Desde la DE10‑Lite, saca un cable desde GPIO_0[0] al pin de señal del servo (cable amarillo/blanco).
5. Conecta la DE10‑Lite por USB al PC; no conectes nunca la salida de 5 V del servo al 5 V de la placa.

Nota: En la serigrafía del header GPIO_0 de la DE10‑Lite encontrarás rotuladas las líneas GPIO_0[n] y GND. Si tienes dudas, consulta el manual de la DE10‑Lite para ubicar GND y, si es posible, verifica continuidad con un multímetro.

Código completo (Verilog y ficheros de constraints)

A continuación se muestran los módulos Verilog y un fichero SDC mínimo. El diseño define un generador PWM con periodo de 20 ms y ancho de pulso entre 1.0 ms y 2.0 ms. Usamos la frecuencia de reloj de 50 MHz nativa de la DE10‑Lite, por lo que 1 ms equivale a 50.000 ticks.

Módulo pwm_servo.v

Este módulo encapsula la lógica de PWM para el servo. Recibe el reloj, reset y una posición de 4 bits, y genera la salida PWM con 50 Hz.

// File: rtl/pwm_servo.v
// Generador PWM para servomotor RC (50 Hz, 1.0 ms a 2.0 ms).
// Ajuste lineal de ancho de pulso en función de pos[3:0] (0..15).

module pwm_servo #(
    parameter integer CLK_HZ    = 50_000_000,  // Reloj de 50 MHz en DE10-Lite
    parameter integer FRAME_HZ  = 50,          // 50 Hz -> periodo 20 ms
    parameter integer MIN_US    = 1000,        // 1.0 ms
    parameter integer MAX_US    = 2000         // 2.0 ms
)(
    input  wire       clk,     // CLOCK_50
    input  wire       rst_n,   // Reset activo en bajo (KEY0)
    input  wire [3:0] pos,     // Posición 0..15 (16 pasos)
    output reg        pwm      // Señal PWM hacia el servo
);

    // Cálculos en ticks del reloj para 20 ms y 1..2 ms
    localparam integer PERIOD_TICKS = CLK_HZ / FRAME_HZ;             // 1_000_000
    localparam integer TICKS_PER_US = CLK_HZ / 1_000_000;            // 50
    localparam integer MIN_TICKS    = MIN_US * TICKS_PER_US;         // 50_000
    localparam integer MAX_TICKS    = MAX_US * TICKS_PER_US;         // 100_000
    localparam integer STEP_COUNT   = 15;                             // 0..15 -> 16 pasos
    localparam integer STEP_TICKS   = (MAX_TICKS - MIN_TICKS) / STEP_COUNT; // ~3333

    reg [19:0] frame_cnt;  // 0..999_999 caben en 20 bits
    reg [19:0] width_ticks;

    // Actualizamos el ancho de pulso según pos
    always @(*) begin
        // Saturación de seguridad (por si pos > 15)
        if (pos[3:0] == 4'd0) begin
            width_ticks = MIN_TICKS[19:0];
        end else if (pos[3:0] >= 4'd15) begin
            width_ticks = MAX_TICKS[19:0];
        end else begin
            width_ticks = MIN_TICKS[19:0] + (pos * STEP_TICKS[19:0]);
        end
    end

    // Contador de periodo y comparación para PWM
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            frame_cnt <= 20'd0;
            pwm       <= 1'b0;
        end else begin
            if (frame_cnt >= (PERIOD_TICKS - 1)) begin
                frame_cnt <= 20'd0;
            end else begin
                frame_cnt <= frame_cnt + 20'd1;
            end
            // PWM: nivel alto mientras frame_cnt < width_ticks
            if (frame_cnt < width_ticks) begin
                pwm <= 1'b1;
            end else begin
                pwm <= 1'b0;
            end
        end
    end

endmodule

Puntos clave:
– Con 50 MHz, el periodo de 20 ms son exactamente 1.000.000 de ciclos: esto facilita mucho la implementación.
– 1 ms = 50.000 ciclos; 2 ms = 100.000 ciclos.
– Se mapea pos[3:0] = 0..15 a 1.0 ms..2.0 ms linealmente. pos=8 (aprox. mitad) ≈ 1.5 ms.

Módulo top_de10lite_servo.v

Top de la DE10‑Lite. Usa CLOCK_50, KEY[0] como reset, SW[3:0] para posición, LEDR[0] como indicador, y publica la señal PWM en GPIO_0[0]. Para compatibilidad con los constraints de la placa, exponemos puertos con nombres estándar empleados por los proyectos de referencia.

// File: rtl/top_de10lite_servo.v
// Top para DE10-Lite (MAX 10) - Control PWM de servo por GPIO_0[0]

module top_de10lite_servo (
    input  wire        CLOCK_50,    // Reloj 50 MHz
    input  wire [9:0]  SW,          // Usamos SW[3:0]
    input  wire [1:0]  KEY,         // KEY[0] = reset activo en bajo
    output wire [9:0]  LEDR,        // LEDR[0] indicador
    inout  wire [35:0] GPIO_0       // Usaremos GPIO_0[0] como PWM
);
    // Reset activo en bajo desde KEY[0]
    wire rst_n = KEY[0];

    // Selección de posición desde SW[3:0]
    wire [3:0] pos_sel = SW[3:0];

    // PWM generado
    wire pwm_out;

    // Instancia del generador PWM
    pwm_servo #(
        .CLK_HZ   (50_000_000),
        .FRAME_HZ (50),
        .MIN_US   (1000),
        .MAX_US   (2000)
    ) u_pwm_servo (
        .clk   (CLOCK_50),
        .rst_n (rst_n),
        .pos   (pos_sel),
        .pwm   (pwm_out)
    );

    // Asignación a GPIO_0[0] como salida; el resto en alta impedancia
    // Nota: tratamos GPIO_0 como bus bidireccional y forzamos solo [0]
    assign GPIO_0[0]   = pwm_out;
    assign GPIO_0[35:1] = {35{1'bz}};

    // LED de indicación: LEDR[0] copia el PWM para ver actividad
    assign LEDR[0] = pwm_out;

    // Apaga otros LEDs para evitar confusión
    assign LEDR[9:1] = 9'b0;

endmodule

Puntos clave:
– KEY[0] es reset activo en bajo; suelta el botón para permitir que el PWM corra.
– Verás LEDR[0] “parpadear” muy débilmente (el pulso de 1–2 ms en 20 ms no es perceptible como parpadeo claro en un LED; se usa solo como test de actividad).
– GPIO_0[0] es la única línea conducida; el resto del bus queda en alta impedancia para no interferir con otros pines del header.

Constraints: SDC mínimo (reloj)

Define el reloj de 50 MHz. Puedes guardar este archivo como constraints/de10_lite.sdc:

# File: constraints/de10_lite.sdc
create_clock -name CLOCK_50 -period 20.000 [get_ports {CLOCK_50}]

Asignaciones de pines (.qsf)

Para utilizar correctamente los pines físicos de la DE10-Lite sin equivocaciones, es lo más seguro partir del “Golden Reference Design” de Terasic para la DE10‑Lite e importar sus asignaciones de pines (que ya mapean CLOCK_50, SW, KEY, LEDR y GPIO_0[*] a los pines correctos del MAX 10).

  • Descarga el proyecto de referencia “DE10-Lite Golden Top” desde la página de Terasic correspondiente a la DE10-Lite.
  • Localiza el fichero .qsf del proyecto Golden (por ejemplo: DE10_LITE_Golden_Top.qsf).
  • En las instrucciones de compilación te muestro cómo importar ese .qsf a nuestro proyecto desde línea de comandos.

Esto garantiza coherencia absoluta con el hardware sin que debas teclear manualmente números de pin.

Compilación, programación y ejecución

A continuación se muestran pasos reproducibles con comandos exactos, tanto en Linux como en Windows, usando Quartus Prime Lite 21.1.

Estructura de directorios recomendada

  • Crea un directorio de trabajo, por ejemplo: ~/fpga/de10lite_pwm_servo (Linux) o C:\work\de10lite_pwm_servo (Windows).
  • Estructura:

  • rtl/pwm_servo.v

  • rtl/top_de10lite_servo.v
  • constraints/de10_lite.sdc
  • scripts/create_project.tcl
  • scripts/import_pins.tcl
  • scripts/program.tcl
  • (copia) constraints/DE10_LITE_Golden_Top.qsf ← importarás este archivo

Script TCL para crear el proyecto (create_project.tcl)

Este script crea el proyecto, añade fuentes y constraints y configura el dispositivo MAX 10 correcto.

# File: scripts/create_project.tcl
# Uso: quartus_sh -t scripts/create_project.tcl

set proj_name "de10lite_pwm_servo"
set proj_dir  [file normalize "."]

# Rutas relativas
set rtl_dir        [file join $proj_dir "rtl"]
set constr_dir     [file join $proj_dir "constraints"]
set sdc_file       [file join $constr_dir "de10_lite.sdc"]

# Crear proyecto
project_new $proj_name -overwrite

# Familia y dispositivo (DE10-Lite MAX 10)
set_global_assignment -name FAMILY "MAX 10"
set_global_assignment -name DEVICE 10M50DAF484C7G

# Top level
set_global_assignment -name TOP_LEVEL_ENTITY top_de10lite_servo

# Añadir fuentes Verilog
set_global_assignment -name VERILOG_FILE [file join $rtl_dir "pwm_servo.v"]
set_global_assignment -name VERILOG_FILE [file join $rtl_dir "top_de10lite_servo.v"]

# Añadir constraints SDC
set_global_assignment -name SDC_FILE $sdc_file

# Guardar y cerrar
project_close

Script TCL para importar asignaciones de pines del Golden Top (import_pins.tcl)

Este script importa las asignaciones de pines del proyecto de referencia de Terasic. Asegúrate de colocar el archivo DE10_LITE_Golden_Top.qsf dentro de constraints/.

# File: scripts/import_pins.tcl
# Uso: quartus_sh -t scripts/import_pins.tcl

set proj_name "de10lite_pwm_servo"
set proj_dir  [file normalize "."]

# Archivo QSF del Golden Top (ajusta el nombre si difiere)
set golden_qsf [file join $proj_dir "constraints" "DE10_LITE_Golden_Top.qsf"]

if {![file exists $golden_qsf]} {
    puts "ERROR: No se encontró $golden_qsf"
    exit 1
}

project_open $proj_name

# Cargamos el paquete de asignaciones para importar
load_package assignments

# Importa asignaciones del QSF Golden
import_assignments $golden_qsf

# Aseguramos estándar de E/S 3.3V para GPIO_0[0] (suele estar ya en el Golden, reforzamos)
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to "GPIO_0[0]"

# Guardar y cerrar
export_assignments
project_close

Script TCL para programar por JTAG (program.tcl)

Este script detecta un USB‑Blaster y programa el .sof resultante.

# File: scripts/program.tcl
# Uso: quartus_sh -t scripts/program.tcl

set proj_name "de10lite_pwm_servo"
set sof_file  [file join "." "output_files" "${proj_name}.sof"]

if {![file exists $sof_file]} {
    puts "ERROR: No existe ${sof_file}. Compila primero."
    exit 1
}

# Programación: método JTAG
# Si tienes múltiples cables, puedes usar -c "USB-BlasterII" o similar.
exec quartus_pgm -m jtag -o "p;$sof_file"

Secuencia de comandos (Linux)

  1. Variables de entorno (si no añadiste Quartus al PATH):
  2. Añade a tu shell:
    • export PATH=/opt/intelFPGA_lite/21.1/quartus/bin:$PATH
  3. Crear proyecto:
  4. quartus_sh -t scripts/create_project.tcl
  5. Importar pines del Golden Top:
  6. Copia el archivo DE10_LITE_Golden_Top.qsf a constraints/.
  7. Ejecuta: quartus_sh -t scripts/import_pins.tcl
  8. Compilar:
  9. quartus_sh –flow compile de10lite_pwm_servo
  10. Comprobar cable JTAG:
  11. jtagconfig
    • Debe listar “USB‑BlasterII” y el dispositivo MAX 10.
  12. Programar:
  13. quartus_sh -t scripts/program.tcl
  14. Alternativa directa:
    • quartus_pgm -m jtag -o «p:output_files/de10lite_pwm_servo.sof»

Secuencia de comandos (Windows)

  1. Abre “Intel Quartus Prime 21.1 Command Prompt (64-bit)” o configura PATH:
  2. set PATH=C:\intelFPGA_lite\21.1\quartus\bin64;%PATH%
  3. Crear proyecto:
  4. quartus_sh.exe -t scripts\create_project.tcl
  5. Importar pines:
  6. Copia DE10_LITE_Golden_Top.qsf a constraints.
  7. quartus_sh.exe -t scripts\import_pins.tcl
  8. Compilar:
  9. quartus_sh.exe –flow compile de10lite_pwm_servo
  10. Comprobar cable:
  11. jtagconfig.exe
  12. Programar:
  13. quartus_pgm.exe -m jtag -o «p;output_files\de10lite_pwm_servo.sof»

Notas:
– Si el driver del USB‑Blaster II no está instalado, en Windows debes instalarlo desde el directorio: C:\intelFPGA_lite\21.1\quartus\drivers.
– En Linux, puede requerirse permisos udev para acceso al USB‑Blaster II.

Validación paso a paso

Objetivo: Verificar que la salida PWM en GPIO_0[0] es de 50 Hz y que su ancho de pulso varía de ~1.0 ms a ~2.0 ms al cambiar SW[3:0], y observar el movimiento del servo.

  1. Preparación:
  2. Asegúrate de que GND de la fuente externa y la DE10-Lite estén unidos.
  3. Verifica con el multímetro que la fuente da 5.0 V antes de conectar el servo.
  4. Encendido:
  5. Conecta la DE10-Lite al PC por USB.
  6. Alimenta el servo con la fuente de 5 V.
  7. Programación:
  8. Programa el .sof (ver sección anterior).
  9. Verificación básica con LED:
  10. Observa LEDR[0]. Estará encendido muy brevemente en cada periodo de 20 ms; a simple vista puede parecer tenue/constante, lo cual es normal.
  11. Medida de la señal PWM (osciloscopio o analizador lógico):
  12. Sonda en GPIO_0[0] (punta) y GND (masa).
  13. Configura el osciloscopio a 5 ms/div aprox. y trigger en flanco ascendente.
  14. Deberías ver:
    • Periodo ~20.0 ms (50 Hz).
    • Pulso alto de:
    • SW[3:0] = 0000 → ~1.0 ms
    • SW[3:0] = 1000 → ~1.5 ms
    • SW[3:0] = 1111 → ~2.0 ms
    • Entre esos valores, pasos de ~0.066 ms (≈ 66–67 µs) por incremento de 1 en SW (debido a STEP_TICKS ~3333).
  15. Validación con el servo:
  16. Con SW[3:0] en 0000, el servo debe posicionarse cerca del extremo (≈0°).
  17. Con SW[3:0] en 1000, el servo debe apuntar al medio (≈90°).
  18. Con SW[3:0] en 1111, el servo debe moverse al otro extremo (≈180°).
  19. Cambia gradualmente los switches para ver movimientos suaves a pasos. Si el servo vibra sin moverse, revisa GND común y niveles de señal.

Resultados esperados:
– Señal estable, sin jitter visible a simple vista en el osciloscopio.
– Servo respondiendo coherentemente a los cambios de SW[3:0].

Troubleshooting (errores típicos y soluciones)

  1. Servo vibra o no se mueve:
  2. Causa probable: Falta de GND común entre la fuente del servo y la DE10-Lite.
  3. Solución: Asegura que GND (DE10-Lite) y GND (fuente 5 V del servo) estén unidos.
  4. Servo se reinicia o hace ruidos fuertes al arrancar:
  5. Causa: Fuente de 5 V insuficiente (caída de tensión en picos de corriente).
  6. Solución: Usa una fuente más robusta (≥1 A para un servo pequeño), cables cortos y gruesos.
  7. No aparece el dispositivo en jtagconfig:
  8. Causa: Driver de USB‑Blaster II no instalado o permisos insuficientes en Linux.
  9. Solución: Instala el driver (Windows) o configura reglas udev (Linux). Prueba otro puerto USB/cable.
  10. Quartus compila pero el PWM no aparece en el pin:
  11. Causa: Asignaciones de pines incorrectas/no importadas.
  12. Solución: Importa el QSF del Golden Top (ver scripts/import_pins.tcl) y recompila.
  13. Señal con frecuencia/anchos incorrectos:
  14. Causa: CLOCK_50 no es reconocido o SDC ausente.
  15. Solución: Verifica que constraints/de10_lite.sdc esté en el proyecto y define create_clock de 50 MHz. Recompila.
  16. El servo no reconoce la señal (no responde) pero el osciloscopio muestra PWM:
  17. Causa: Nivel de señal 3.3 V vs servo anómalo que requiere 5 V en control (no habitual).
  18. Solución: Prueba otro servo estándar (SG90/MG90S) o interponer un buffer de nivel; confirma la masa común.
  19. Warnings múltiples en pines no utilizados (GPIO_0[*]):
  20. Causa: El Golden QSF asigna más pines de los usados.
  21. Solución: Son inofensivos. Puedes ignorarlos o mantener el bus GPIO_0 como inout para compatibilidad, como en el top.
  22. LEDR[0] parece fijo y no parpadea:
  23. Causa: El pulso alto de 1–2 ms en una ventana de 20 ms no se percibe como parpadeo visible.
  24. Solución: Usa un osciloscopio para validar; el LED es solo un indicador de actividad.

Mejoras y variantes

  • Más resolución:
  • Cambia pos a 8 bits para 256 pasos de 1.0–2.0 ms. Ajusta el cálculo de STEP_TICKS: divide (MAX_TICKS – MIN_TICKS) entre 255.
  • Suavizado (rampa):
  • Implementa un interpolador que cambie width_ticks de forma gradual para evitar movimientos bruscos (pasos cada frame).
  • Control por potenciómetro:
  • La MAX 10 integra ADC. Puedes leer un potenciómetro (con divisor) y mapear el valor a 1.0–2.0 ms. Requiere IP del ADC de MAX 10 y su configuración en Quartus.
  • Múltiples servos:
  • Instancia varios pwm_servo (GPIO_0[1], GPIO_0[2], …) compartiendo el mismo frame_cnt o independientes; cuida la capacidad de corriente de la fuente de 5 V (dimensiona).
  • Centro ajustable:
  • Añade offset y límites calibrables para compensar servos con ángulos útiles asimétricos.
  • Uso de PLL:
  • No es necesario, pero podrías generar tick a 1 MHz para cálculos en microsegundos exactos si usas otra frecuencia de reloj.

Checklist de verificación

  • [ ] Instalé Quartus Prime Lite 21.1 y (opcional) ModelSim – Intel FPGA Edition 21.1.
  • [ ] El USB‑Blaster II aparece en jtagconfig.
  • [ ] Creé la estructura de proyecto y coloqué los archivos en rutas correctas.
  • [ ] Ejecuté scripts/create_project.tcl sin errores.
  • [ ] Importé constraints/DE10_LITE_Golden_Top.qsf con scripts/import_pins.tcl.
  • [ ] Compilé el proyecto: quartus_sh –flow compile de10lite_pwm_servo finaliza OK.
  • [ ] Programé la FPGA con el .sof sin errores.
  • [ ] Verifiqué GND común entre la DE10-Lite y la fuente del servo.
  • [ ] Conecté GPIO_0[0] a la señal del servo, 5 V externo al servo y GND común.
  • [ ] Observé un PWM de 50 Hz y anchos 1.0–2.0 ms (osciloscopio/analizador lógico).
  • [ ] El servo se mueve al cambiar SW[3:0] (0≈0°, 8≈90°, 15≈180°).
  • [ ] El sistema es estable (sin resets ni vibración excesiva).

Apéndice: comandos útiles y referencias rápidas

  • Ver dispositivos JTAG:
  • Linux: jtagconfig
  • Windows: jtagconfig.exe
  • Compilación incremental (si cambias solo Verilog):
  • quartus_sh –flow compile de10lite_pwm_servo
  • Programación directa:
  • quartus_pgm -m jtag -o «p;output_files/de10lite_pwm_servo.sof»
  • Rutas por defecto (Linux):
  • Quartus: /opt/intelFPGA_lite/21.1/quartus/bin
  • ModelSim (opcional): /opt/intelFPGA_lite/21.1/modelsim_ase/bin

Con este caso práctico has cubierto el ciclo completo: definición del objetivo pwm-servo-control, preparación de materiales, conexión segura, desarrollo en Verilog, compilación en Intel Quartus Prime Lite 21.1 para la Intel/Altera DE10-Lite (MAX 10), programación por JTAG y validación física y mediante instrumentación. Este es un punto de partida sólido para expandir hacia múltiples servos, control analógico con ADC, y técnicas de suavizado/planificación de movimiento.

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é tipo de señal se genera para controlar un servomotor hobby?




Pregunta 2: ¿Cuál es la frecuencia de la señal PWM que se debe generar?




Pregunta 3: ¿Qué ángulo corresponde a un pulso de 1.0 ms en un servomotor típico?




Pregunta 4: ¿Qué herramienta se recomienda para el diseño en este tutorial?




Pregunta 5: ¿Qué sistema operativo se recomienda para este tutorial?




Pregunta 6: ¿Qué controlador se necesita para programar la FPGA?




Pregunta 7: ¿Cuál es el rango de pulsos que se debe generar para el servomotor?




Pregunta 8: ¿Qué se necesita para validar la señal generada?




Pregunta 9: ¿Qué conocimientos previos son necesarios para seguir el tutorial?




Pregunta 10: ¿Qué placa se utiliza en este tutorial?




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

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

Sígueme:
Scroll to Top