Módulo 2.4

PWM: Control de Potencia

Modulación por ancho de pulso para control analógico con señales digitales

Santi Scagliusi, PhD

Comenzar arrow_downward
waves
Duty Cycle
0% a 100%
lightbulb
LED Dimming
Control de brillo
settings
Servomotores
Control de posición
code
Zephyr API
pwm_set_dt()

Qué es PWM

Control analógico con señales digitales: la clave está en el tiempo.

help Por qué necesitamos PWM

Los microcontroladores solo pueden generar señales digitales (0V o 3.3V). PWM permite simular voltajes intermedios alternando rápidamente entre encendido y apagado.

Pulse Width Modulation = Modulación por Ancho de Pulso
lightbulb
Analogía: Es como encender y apagar una lámpara muy rápido. Si está encendida el 50% del tiempo, percibimos la mitad del brillo, aunque la lámpara solo conoce ON y OFF.
Período de la señal
Periodo = TON + TOFF
Frecuencia
f = 1 / Periodo
Duty Cycle (Ciclo de trabajo)
DC = TON / Periodo x 100%

Senal PWM y Duty Cycle

Mayor duty cycle = mayor voltaje promedio de salida.

Comparacion de Duty Cycles

25% DC 0.83V 50% DC 1.65V 75% DC 2.48V 1 Periodo Senal PWM V promedio
tune

Visualizador Interactivo de PWM

1 kHz
Senal PWM V promedio TON
50%
Presets:
Duty Cycle
50%
V equivalente
1.65V
Tiempo HIGH
500 us
Periodo
1000 us
Salida LED
Brillo: 50%
0V 3.3V
Calculo
Vmax 3.3V
DC 50%
Vavg 1.65V
Temporizado
TON = 500 us
TOFF = 500 us
Periodo = 1000 us
Freq = 1 kHz
0%
Siempre OFF
Vavg = 0V
25%
1/4 del tiempo ON
Vavg = 0.83V
50%
Mitad del tiempo ON
Vavg = 1.65V
100%
Siempre ON
Vavg = 3.3V
check_circle
Voltaje promedio: Vavg = Vmax x Duty Cycle. Con Vmax = 3.3V y DC = 50%, obtenemos 1.65V promedio.

Módulo PWM del nRF

Contador up/down con multiples canales independientes.

autorenew Contador Up/Down

El modulo PWM usa un contador que sube de 0 al valor maximo y luego baja. Cuando el contador cruza el valor de comparacion, la salida cambia de estado.

Compare Contador triangular
info
Ventaja del contador up/down: Genera señales PWM centradas, ideales para control de motores donde se requiere simetría en la conmutación.

account_tree Multiples canales

Cada modulo PWM tiene varios canales. Todos comparten el mismo periodo (frecuencia) pero cada canal puede tener su propio duty cycle y polaridad.

CH0
DC: 25%
Normal
CH1
DC: 50%
Normal
CH2
DC: 75%
Invertido
CH3
No usado
Especificaciones PWM nRF52840
Módulos PWM 4 (PWM0-PWM3)
Canales por modulo 4
Resolucion 15 bits
Frecuencia base 16 MHz

Aplicaciones de PWM

Desde LEDs hasta motores: PWM está en todas partes.

lightbulb

LED Dimming

Control de brillo sin cambiar la corriente. Frecuencias tipicas: 1-10 kHz.

f > 100Hz evita parpadeo
settings

Servomotores

Control de posición angular. Periodo fijo de 20ms, pulso de 1-2ms.

50Hz, pulse 1-2ms
speed

Control de motores

Velocidad de motores DC. Frecuencias tipicas: 20-50 kHz.

Alta f = menos ruido
bolt

Conversion de potencia

Reguladores switching, fuentes DC-DC. Frecuencias: 100kHz-2MHz.

Buck, Boost, etc.

Control de servomotor: Mapeo pulso-angulo

-90 0 +90
Angulo Pulso Duty Cycle
-90 grados 1.0 ms 5%
0 grados 1.5 ms 7.5%
+90 grados 2.0 ms 10%
warning
Importante: El periodo debe ser exactamente 20ms (50Hz). Variar el periodo puede danar el servo o causar comportamiento erratico.

API PWM de Zephyr

Funciones y estructuras para controlar PWM desde el codigo.

1. Configuracion en prj.conf

prj.conf
CONFIG_PWM=y
CONFIG_LOG=y

2. Estructura pwm_dt_spec

Definicion de la estructura
struct pwm_dt_spec {
const struct device *dev; // Dispositivo PWM
uint32_t channel; // Canal (0-3)
uint32_t period; // Periodo en ns
pwm_flags_t flags; // Polaridad
};

3. Funciones principales

PWM_DT_SPEC_GET(node_id)
Obtiene la especificacion PWM desde el devicetree.
pwm_is_ready_dt(spec)
Verifica si el dispositivo PWM está listo.
pwm_set_dt(spec, period, pulse)
Configura periodo y ancho de pulso (ambos en ns).
pwm_set_pulse_dt(spec, pulse)
Cambia solo el ancho de pulso (mantiene el periodo).
schedule
Macros de tiempo:
PWM_MSEC(x) - milisegundos a nanosegundos
PWM_USEC(x) - microsegundos a nanosegundos
lightbulb
Polaridad: PWM_POLARITY_NORMAL = pin HIGH durante el pulso. PWM_POLARITY_INVERTED = pin LOW durante el pulso (util para LEDs conectados a VCC).

Devicetree para PWM

Definicion del hardware PWM mediante overlays.

LED con PWM (desde board DTS)

nrf52840dk.dts (extracto)
/* Definicion de LEDs con PWM */
pwm_leds {
compatible = "pwm-leds";
pwm_led0: pwm_led0 {
pwms = <&pwm0 0 PWM_MSEC(20) PWM_POLARITY_INVERTED>;
};
};
Formato de la propiedad pwms
pwms = <&pwm_controller canal periodo flags>;
pwm_controller: &pwm0, &pwm1, etc.
canal: 0, 1, 2, 3
periodo: PWM_MSEC(20), PWM_USEC(1000)
flags: PWM_POLARITY_NORMAL/INVERTED

Overlay para servomotor

app.overlay
/ {
servo: servo {
compatible = "pwm-servo";
pwms = <&pwm1 0 PWM_MSEC(20) PWM_POLARITY_NORMAL>;
min-pulse = <PWM_USEC(1000)>; // 1ms = -90 grados
max-pulse = <PWM_USEC(2000)>; // 2ms = +90 grados
};
};
warning
PWM_POLARITY_INVERTED: Necesario cuando el LED está conectado entre el pin y VCC (en lugar de GND). La mayoría de los dev kits usan esta configuración.

Ejemplo: Control de LED

Fade de LED usando PWM con Zephyr - Inicializacion.

src/main.c - Inicializacion
#include <zephyr/drivers/pwm.h>
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(pwm_led, LOG_LEVEL_INF);
/* Obtener spec desde alias en DT */
#define PWM_LED0_NODE DT_ALIAS(pwm_led0)
static const struct pwm_dt_spec pwm_led =
PWM_DT_SPEC_GET(PWM_LED0_NODE);
int main(void) {
if (!pwm_is_ready_dt(&pwm_led)) {
LOG_ERR("PWM device not ready");
return -1;
}
// Continua en siguiente slide...

Flujo del codigo

1
PWM_DT_SPEC_GET
Obtiene configuracion del devicetree
2
pwm_is_ready_dt
Verifica que el hardware esta listo
lightbulb
DT_ALIAS: Usa el alias pwm_led0 definido en el devicetree del board para obtener la configuracion PWM.

Ejemplo: Control de LED

Loop principal - Efecto fade.

src/main.c - Loop principal
/* Fade LED de 0% a 100% */
while (1) {
for (int i = 0; i <= 100; i++) {
uint32_t pulse =
(PWM_MSEC(20) * i) / 100;
pwm_set_pulse_dt(&pwm_led, pulse);
k_msleep(20);
}
for (int i = 100; i >= 0; i--) {
uint32_t pulse =
(PWM_MSEC(20) * i) / 100;
pwm_set_pulse_dt(&pwm_led, pulse);
k_msleep(20);
}
}
}

Calculo del pulso

3
Calcular pulso
pulse = (periodo * porcentaje) / 100
4
pwm_set_pulse_dt
Aplica el nuevo duty cycle
check_circle
Nota: Usamos pwm_set_pulse_dt() en lugar de pwm_set_dt() porque el periodo ya esta definido en el devicetree y no cambia.

Ejemplo: Control de Servo

Configuracion y funcion de conversion angulo-pulso.

src/servo.c - Configuracion
#include <zephyr/drivers/pwm.h>
#define SERVO_NODE DT_NODELABEL(servo)
static const struct pwm_dt_spec servo =
PWM_DT_SPEC_GET(SERVO_NODE);
/* Leer limites desde devicetree */
#define SERVO_MIN DT_PROP(SERVO_NODE, min_pulse)
#define SERVO_MAX DT_PROP(SERVO_NODE, max_pulse)
/* Convierte angulo (-90 a +90) a pulso */
void set_servo_angle(int angle) {
if (angle < -90) angle = -90;
if (angle > 90) angle = 90;
uint32_t pulse = SERVO_MIN +
((SERVO_MAX - SERVO_MIN) *
(angle + 90)) / 180;
pwm_set_pulse_dt(&servo, pulse);
}
Formula de mapeo
pulse = MIN + (MAX - MIN) x (angle + 90) / 180
lightbulb
DT_PROP: Lee propiedades personalizadas del devicetree. Esto permite cambiar los limites del servo sin recompilar el codigo.

Ejemplo: Control de Servo

Funcion main y ejemplos de calculo.

src/servo.c - Main
int main(void) {
if (!pwm_is_ready_dt(&servo)) {
return -1;
}
// Barrer de -90 a +90 grados
while (1) {
for (int a = -90; a <= 90; a += 5) {
set_servo_angle(a);
k_msleep(50);
}
k_msleep(500);
}
}
Ejemplos de calculo
Angulo = -90 grados
pulse = 1000 + (2000-1000) x (-90+90)/180 = 1000 us
Angulo = 0 grados
pulse = 1000 + (2000-1000) x (0+90)/180 = 1500 us
Angulo = +90 grados
pulse = 1000 + (2000-1000) x (90+90)/180 = 2000 us

Resumen del Modulo

Conceptos clave sobre PWM en sistemas embebidos NRF.

waves

Duty Cycle

El porcentaje de tiempo que la senal esta en HIGH determina el voltaje promedio de salida. 50% DC = 50% de Vmax.

settings

Aplicaciones

LEDs (1-10kHz), servos (50Hz, pulso 1-2ms), motores DC (20-50kHz), conversion de potencia (100kHz+).

code

Zephyr API

PWM_DT_SPEC_GET para config, pwm_is_ready_dt para validar, pwm_set_pulse_dt para cambiar duty cycle.

tips_and_updates

"PWM es el puente entre el mundo digital del micro y el mundo analogico de los actuadores."

La frecuencia adecuada depende de la aplicacion: suficientemente alta para evitar parpadeo, pero no tan alta que aumente las perdidas por conmutacion.

Referencia Rapida

Formulas importantes
DC = TON / Periodo x 100%
Vavg = Vmax x DC
f = 1 / Periodo
Funciones clave
Obtener spec PWM_DT_SPEC_GET()
Verificar pwm_is_ready_dt()
Configurar pwm_set_pulse_dt()
arrow_forward Siguiente modulo

2.5 Protocolo SPI

Comunicacion sincrona de alta velocidad con perifericos externos.