Aziz Bench

Calcolo PWM: frequenza e risoluzione

Scegli il chip e la frequenza che ti serve: scopri quanti bit di risoluzione del duty ottieni, la frequenza esatta, i valori di divisore o timer e il codice per Arduino, ESPHome e gli SDK.

Risoluzione del duty
13bit
8192 passi a 5 kHz
Frequenza ottenuta
5 kHzesatta
Passo minimo
24,4 ns0,0122 % del periodo
Divisore
1,953clock APB, 80 MHz
Segnale
acceso 100 µsperiodo 200 µs
Chip e software
Software

Arduino-ESP32 3.x prende il clock del PWM dal quarzo su tutti i chip tranne l’ESP32 originale, e questo limita la risoluzione. ESPHome sceglie la risoluzione da solo.

Segnale
Hz

In hertz: 5000 sono 5 kHz.

%

Impostazioni e codice

Clock e divisoreClock APB a 80 MHz, divisore 1,953 (div_param 500), 13 bit: il timer gira a 5 kHz.
Valore da scrivere50 % = 4096 su 8192. Scrivi 8192 per tenere l’uscita sempre accesa, 0 per tenerla spenta.
Intervallo possibileA 5 kHz: da 1 a 13 bit. A 13 bit: da 0,119 Hz a 9,7656 kHz.
Impostazioni condiviseL’ESP32 ha 16 canali PWM e 8 timer: i canali sullo stesso timer condividono frequenza e risoluzione.

Codice

Cambia il numero del pin con il tuo: i valori corrispondono al risultato qui sopra.

Arduino-ESP32 3.x
const int PWM_PIN = 4;          // GPIO
const uint32_t PWM_FREQ = 5000;     // Hz
const uint8_t PWM_RES = 13;        // bit: 0–8192

void setup() {
  ledcAttach(PWM_PIN, PWM_FREQ, PWM_RES);
  ledcWrite(PWM_PIN, 4096);        // 50 %
}

void loop() {}
ESPHome
output:
  - platform: ledc
    pin: GPIO4
    id: pwm_out
    frequency: 5kHz

light:
  - platform: monochromatic
    output: pwm_out
    name: "LED"
ESP-IDF
#include "driver/ledc.h"
#include "esp_err.h"

void app_main(void)
{
    ledc_timer_config_t timer = {
        .speed_mode = LEDC_LOW_SPEED_MODE,
        .duty_resolution = LEDC_TIMER_13_BIT,
        .timer_num = LEDC_TIMER_0,
        .freq_hz = 5000,
        .clk_cfg = LEDC_AUTO_CLK,
    };
    ESP_ERROR_CHECK(ledc_timer_config(&timer));

    ledc_channel_config_t channel = {
        .gpio_num = 4,
        .speed_mode = LEDC_LOW_SPEED_MODE,
        .channel = LEDC_CHANNEL_0,
        .timer_sel = LEDC_TIMER_0,
        .duty = 4096,              // 50 %
        .hpoint = 0,
    };
    ESP_ERROR_CHECK(ledc_channel_config(&channel));
}

Risoluzione massima alle frequenze più usate

FrequenzaRisoluzione
50 Hz20 bit
490 Hz17 bit
1 kHz16 bit
5 kHz13 bit
20 kHz11 bit
25 kHz11 bit
40 kHz10 bit
100 kHz9 bit
1 MHz6 bit

Consigli

Arduino-ESP32 3.x: ledcAttach(pin, freq, resolution) sostituisce ledcSetup() e ledcAttachPin() della versione 2.x, e ledcWrite() vuole il pin, non il canale.

L’ESP32 ha due gruppi di 8 canali: high-speed, che applica subito il nuovo duty, e low-speed. Arduino-ESP32 usa prima il gruppo high-speed.

Ogni canale prende la frequenza da un timer (ce ne sono 8): due uscite con frequenze diverse richiedono due timer.

Per i LED usa almeno 1,25 kHz: l’IEEE 1789 considera a basso rischio un PWM tutto acceso / tutto spento da 1250 Hz in su, e da circa 3 kHz anche per le persone sensibili.

Testo pronto da incollare in un forum o in una issue.

Perché frequenza e risoluzione sono legate

Una periferica PWM conta gli impulsi di un clock: il contatore fissa il periodo, il valore di confronto quanto tempo l’uscita resta accesa. Con n bit di risoluzione il contatore ha bisogno di 2^n impulsi di clock per periodo, quindi la frequenza massima è il clock diviso 2^n. A 80 MHz, con 8 bit si arriva a 312,5 kHz, con 13 bit a 9,77 kHz e con 1 bit a 40 MHz, ma con il duty bloccato al 50 %.

f(max) = f(clock) / 2^bit
f = f(clock) / (divisore × 2^bit)

Anche il divisore ha un limite superiore, quindi le frequenze basse richiedono più bit, non meno: su un ESP32-S3 con il clock a 80 MHz, a 50 Hz servono almeno 11 bit.

ESP32: la periferica LEDC

Tutti gli ESP32 generano il PWM con la periferica LEDC: un divisore con 8 bit di parte frazionaria, da 1 a circa 1024, e un contatore fino a 20 bit su ESP32, C5, C6, H2 e P4, 14 bit su S2, S3 e C3. Il clock può essere l’APB a 80 MHz (un’uscita del PLL sui chip più recenti, 96 MHz sull’H2), il quarzo (40 MHz; 32 MHz sull’H2, 40 o 48 MHz sul C5), un oscillatore RC interno oppure, su ESP32 e S2, il REF_TICK a 1 MHz.

Arduino-ESP32 3.x prende il clock del PWM dal quarzo su tutti i chip tranne l’ESP32 originale. Così a ogni risoluzione la frequenza massima scende, della metà dove un quarzo a 40 MHz prende il posto di un clock a 80 MHz: su un ESP32-S3, a 5 kHz si ottengono 12 bit invece di 13. Se chiami ledcSetClockSource(LEDC_AUTO_CLK) prima di ledcAttach(), il driver sceglie il clock più veloce; la funzione c’è da Arduino-ESP32 3.0.5. ESPHome usa il clock APB dove c’è e sceglie la risoluzione da solo.

Raspberry Pi Pico: RP2040 e RP2350

Ogni slice PWM ha un contatore a 16 bit che riparte da zero dopo TOP e un divisore da 1 a 255 + 15/16 a passi di 1/16. La frequenza è il clock di sistema diviso per (TOP + 1) e per il divisore, e ancora per 2 in modalità phase-correct. Dato che TOP può avere qualsiasi valore, il Pico centra esattamente quasi tutte le frequenze: a 125 MHz, 25 kHz si ottengono con TOP 4999 e divisore 1, circa 12,3 bit.

Arduino Uno e Nano: i timer dell’ATmega328P

Il Timer0 e il Timer2 sono a 8 bit, il Timer1 a 16 bit, ognuno con una serie fissa di prescaler N. La frequenza dipende da N e da TOP: clock / (N × (TOP + 1)) in fast PWM, clock / (2 × N × TOP) in phase-correct. analogWrite() li lascia con prescaler 64: 976,6 Hz sui pin 5 e 6, 490,2 Hz sui pin 3, 9, 10 e 11. Per altre frequenze il Timer1 con TOP in ICR1 mantiene entrambi i pin e fino a 16 bit: un segnale da 25 kHz per una ventola sul pin 9 si ottiene con ICR1 = 639 senza prescaler.

ESP8266

L’ESP8266 non ha un PWM hardware: il core Arduino ed ESPHome lo generano via software, da 100 Hz a 40 kHz nel core Arduino, con un range di serie di 255. Secondo la documentazione del core, le frequenze alte tengono impegnata la CPU.

Quale frequenza per cosa

UsoFrequenzaPerché
Luminosità dei LED1,25 kHz o piùL’IEEE 1789 considera a basso rischio di sfarfallio un PWM tutto acceso / tutto spento da 1250 Hz
Servo da modellismo50 Hz, impulsi da 1 a 2 msUn impulso ogni 20 ms; la durata dell’impulso fissa l’angolo
Ventola PC a 4 fili25 kHz (21–28 kHz)Specifica Intel per le ventole PWM a 4 fili
Motore DCcirca 20 kHz o piùOltre le frequenze udibili; controlla il limite del driver
Buzzer passivoLa frequenza della nota, 50 %La frequenza è l’altezza del suono

Valori di serie delle varie piattaforme

PiattaformaanalogWrite() di serieRisoluzione massimaClock del PWM
ESP32 (Arduino-ESP32 3.x)1 kHz, 8 bit20 bitAPB 80 MHz o REF_TICK 1 MHz (AUTO)
ESP32-S2, S3, C3 (Arduino-ESP32 3.x)1 kHz, 8 bit14 bitXTAL 40 MHz di serie
ESP32-C5, C6, P4 (Arduino-ESP32 3.x)1 kHz, 8 bit20 bitXTAL 40 MHz di serie (C5: 40 o 48 MHz)
ESP32-H2 (Arduino-ESP32 3.x)1 kHz, 8 bit20 bitXTAL 32 MHz di serie
RP2040, RP2350 (Arduino-Pico)1 kHz, range 25516 bitClock di sistema: 200 MHz (Pico), 150 MHz (Pico 2)
ATmega328P (Uno, Nano)490 Hz (pin 3, 9, 10, 11), 976,6 Hz (pin 5, 6), 8 bit16 bit (Timer1)16 MHz con prescaler 64
ESP8266 (core Arduino 3.x)1 kHz, range 255Range fino a 65535PWM software

Fonti: driver LEDC e file delle capacità dei SoC di ESP-IDF (release 5.5), esp32-hal-ledc.c e documentazione dell’API LEDC di Arduino-ESP32 3.x, componenti ledc, rp2040_pwm ed esp8266_pwm di ESPHome, datasheet dell’RP2040 e hardware_pwm del pico-sdk, wiring_analog.cpp di Arduino-Pico, datasheet Microchip dell’ATmega328P e core Arduino AVR, guida di riferimento del core Arduino per ESP8266, specifica Intel delle ventole PWM a 4 fili, IEEE 1789-2015 nella sintesi del Dipartimento dell’Energia statunitense, libreria Servo di Arduino.

Domande frequenti

Qual è la frequenza PWM massima sull’ESP32?

40 MHz, con 1 bit di risoluzione e duty fisso al 50 %: il clock a 80 MHz diviso 2. Per una regolazione utilizzabile, con 8 bit si arriva a 312,5 kHz e con 10 bit a 78,1 kHz. Con Arduino-ESP32 3.x sui chip diversi dall’ESP32 originale, il clock di serie dal quarzo abbassa questi valori (della metà sui chip con quarzo a 40 MHz e clock APB o PLL a 80 MHz), a meno di chiamare ledcSetClockSource(LEDC_AUTO_CLK), disponibile dalla versione 3.0.5.

Perché ledcAttach() fallisce con “requested frequency and duty resolution can not be achieved”?

Perché il divisore deve restare tra 1 e circa 1024. Se la frequenza è troppo alta per i bit che hai chiesto, abbassa la risoluzione. Se è troppo bassa, alza la risoluzione: con meno bit serve un divisore più grande. Il calcolatore mostra l’intervallo valido per entrambi.

Che frequenza PWM serve per una ventola PC a 4 pin?

25 kHz: la specifica Intel accetta da 21 a 28 kHz. Un ESP32 a 25 kHz arriva a 11 bit con il clock a 80 MHz; un Arduino Uno ottiene 25 kHz sul pin 9 con il Timer1 e ICR1 = 639. Comanda la linea PWM della ventola con un’uscita open-drain o un transistor, perché la ventola ha già un pull-up su quella linea.

Come comando un servo in PWM con l’ESP32?

A 50 Hz con 14 bit un passo vale circa 1,2 µs, abbastanza fine per un servo: 1,5 ms corrispondono a 1229, 1 ms a 819 e 2 ms a 1638. In ESPHome collega un output ledc a 50 Hz al componente servo; con Arduino puoi usare anche una libreria come ESP32Servo.

Perché sui pin 5 e 6 dell’Arduino Uno la frequenza PWM è diversa?

I pin 5 e 6 usano il Timer0 in fast PWM (976,6 Hz), gli altri il Timer1 e il Timer2 in phase-correct (490,2 Hz). Il Timer0 conta anche millis(), quindi cambiane il prescaler solo se puoi convivere con millis() e delay() sballati.

Che risoluzione PWM serve per i LED?

Con 8 bit (256 passi) la regolazione si vede a scatti a bassa luminosità, dove l’occhio nota di più le piccole variazioni; con 12 bit o più e una curva gamma le dissolvenze sono fluide. Tieni la frequenza a 1,25 kHz o più per uno sfarfallio basso.

Le due uscite di una slice PWM del Pico possono avere frequenze diverse?

No: A e B condividono il contatore, quindi hanno la stessa frequenza e lo stesso TOP, e può cambiare solo il duty. Se ti servono frequenze diverse usa pin su slice diverse.