Corso ESP-IDF, puntata 2: installare l’ambiente
Io: Cheap, oggi si installa ESP-IDF. Mi preparo a un pomeriggio di download e variabili d’ambiente?
Cheap: Dalla versione 6.0 c’è un installatore apposta, l’EIM. Gratis, con finestra grafica o da riga di comando. Tu scegli, lui scarica.
Io: E l’adattatore USB-seriale da cassetto? Lo tiro fuori?
Cheap: Lascialo dov’è. Il C6 ha la seriale USB dentro il chip: un cavo e basta. Meno pezzi, meno spese.
Io: Poi?
Cheap: Poi idf.py: un comando per creare, configurare, compilare, scrivere e ascoltare la scheda. E una scorciatoia da imparare a memoria: Ctrl+] per uscire dal monitor.
Io: Perché proprio quella?
Cheap: Perché tutti la prima volta premono Ctrl+C. E non succede quello che si aspettano.
In questa puntata
Obiettivi
- Installare ESP-IDF v6.1 su Windows, Linux o macOS con il metodo che la documentazione raccomanda: l’ESP-IDF Installation Manager (EIM).
- Attivare l’ambiente nel terminale e sapere a cosa servono l’estensione per VS Code ed Espressif-IDE.
- Usare
idf.pyper l’intero ciclo:create-project,set-target,menuconfig,build,flash,monitor,size,fullclean. - Capire che cosa produce la build e dove finisce ogni file nella flash.
- Riconoscere le porte seriali della ESP32-C6-DevKitC-1, compresa la USB Serial/JTAG integrata, e risolvere gli errori più comuni.
Prerequisiti: Puntata 1 “ESP-IDF in una mappa” (pubblicazione in arrivo); un PC con Windows, Linux o macOS; una ESP32-C6-DevKitC-1 e un cavo USB-C che porti anche i dati, non solo l’alimentazione.
Che cosa installiamo davvero
La documentazione v6.1 elenca tre ingredienti:
- la toolchain, cioè compilatore, linker e debugger per il chip (per il C6, che è RISC-V, gli strumenti
riscv32-esp-elf); - gli strumenti di build: CMake, che descrive il progetto, e Ninja, che esegue la compilazione;
- ESP-IDF vero e proprio: librerie, driver, sorgenti e gli script Python che tengono insieme il resto.
Python fa da collante: idf.py, esptool e il monitor sono scritti in Python. Dalla 6.0 servono almeno Python 3.10 e CMake 3.22.1.
Il metodo raccomandato: ESP-IDF Installation Manager
Per la v6.1 la guida “Get Started” indica un solo strumento per installare ESP-IDF, la toolchain e gli strumenti di build: l’ESP-IDF Installation Manager, in breve EIM. Esiste in due forme:
- GUI (interfaccia grafica): la scelta consigliata per la maggior parte delle persone;
- CLI (riga di comando): comoda per l’integrazione continua (CI/CD) e le installazioni automatiche.
Entrambe si scaricano dalla pagina di download dell’EIM in versione online (scarica ciò che serve durante l’installazione) oppure offline (pacchetto completo, per PC senza Internet).
Installare l’EIM
| Sistema | Prerequisiti | Installare l’EIM con un gestore di pacchetti |
|---|---|---|
| Windows | Git e Python: l’EIM li controlla e propone di installarli se mancano |
winget install Espressif.EIM (GUI) oppure winget install Espressif.EIM-CLI
|
| Linux (Debian, Ubuntu) | se usi APT, nessuno da installare a mano | aggiungi il repository APT di Espressif, poi sudo apt install eim (GUI e CLI) o sudo apt install eim-cli
|
| Linux (Fedora e simili) | quelli elencati nella documentazione dell’EIM | aggiungi il repository DNF, poi sudo dnf install eim o sudo dnf install eim-cli
|
| macOS | brew install libgcrypt glib pixman sdl2 libslirp dfu-util cmake python |
brew tap espressif/eim, poi brew install --cask eim-gui o brew install eim
|
Installare ESP-IDF con l’EIM
Dalla GUI: New Installation → Start Installation, poi Easy Installation → Start Easy Installation; superati i controlli compare Ready to Install e l’EIM installa l’ultima versione stabile con le impostazioni predefinite. Per scegliere la versione o la cartella c’è invece Custom Installation.
Dalla CLI i comandi documentati sono tre:
eim install # ultima versione stabile, impostazioni predefinite
eim wizard # procedura guidata interattiva
eim install -i v6.1 # una versione precisa (la guida usa come esempio v5.4.2)
Attivare l’ambiente
Prima di usare idf.py bisogna attivare l’ambiente nel terminale: percorsi della toolchain, ambiente virtuale Python, variabile IDF_PATH. Le strade documentate sono queste:
- dalla GUI dell’EIM: Manage Installations → Open Dashboard, scegli la versione e premi Open IDF Terminal;
- su Windows, dopo l’installazione da CLI: l’EIM mette sul desktop un collegamento che apre PowerShell con l’ambiente già pronto (la guida cita come esempio
IDF_v5.4.2_Powershell); - su Linux e macOS: alla fine l’EIM stampa il comando da eseguire, del tipo
source ".../tools/activate_idf_v5.4.2.sh"(anche qui l’esempio della guida è per la 5.4.2).
Il metodo precedente, con gli script install.bat, install.ps1 o install.sh e poi export nella cartella di ESP-IDF, è ancora documentato come legacy e funziona. Per un’installazione nuova, però, la strada è l’EIM.
Gli IDE: VS Code ed Espressif-IDE
Le versioni installate con l’EIM si possono usare in due ambienti grafici:
- Visual Studio Code con l’ESP-IDF Extension for VS Code, che permette di sviluppare, compilare, scrivere la flash e monitorare la scheda senza uscire dall’editor;
- Espressif-IDE, basato su Eclipse CDT, con i plugin IDF già inclusi.
Ciascuno ha la sua documentazione, linkata in fondo. Nel corso useremo la riga di comando: è uguale su tutti i sistemi e non cambia quando cambiano i menu.
idf.py: un comando per tutto il ciclo
idf.py guida CMake, Ninja, esptool e il monitor. Va lanciato dentro la cartella del progetto, cioè quella con il CMakeLists.txt principale, oppure indicandola con -C cartella.
| Comando | Che cosa fa |
|---|---|
idf.py create-project nome |
crea un progetto minimo dal modello tools/templates/sample_project: CMakeLists.txt, main/CMakeLists.txt e main/nome.c con un app_main() vuoto |
idf.py set-target esp32c6 |
sceglie il chip; svuota la cartella build e rigenera sdkconfig (il vecchio diventa sdkconfig.old) |
idf.py menuconfig |
apre il menu di configurazione testuale e salva le scelte in sdkconfig
|
idf.py build |
configura e compila; è incrementale: se nulla è cambiato non rifà nulla |
idf.py -p PORTA flash |
compila se serve e scrive bootloader, tabella partizioni e app |
idf.py -p PORTA monitor |
apre il monitor seriale (IDF Monitor) |
idf.py size |
riassume l’occupazione di RAM e flash; size-components e size-files la dettagliano per componente e per file |
idf.py fullclean |
cancella tutto il contenuto della cartella build; la configurazione (sdkconfig) resta |
Una sessione tipica, dal nulla alla scheda che parla:
idf.py create-project primo_progetto
cd primo_progetto
idf.py set-target esp32c6
idf.py menuconfig # facoltativo: per hello world vanno bene i default
idf.py -p COM5 flash monitor # COM5 è un esempio: usa la tua porta
Più comandi nella stessa riga vengono eseguiti nell’ordine giusto: flash monitor compila, scrive e apre il monitor. Se la porta è sempre la stessa, puoi metterla nella variabile d’ambiente ESPPORT e omettere -p; se non indichi nessuna porta, idf.py prova da solo quelle USB disponibili.
Il target, prima di tutto
Il target conta più di quanto sembri. Se non lo fissi in nessun modo (né con set-target, né con la variabile IDF_TARGET, né con CONFIG_IDF_TARGET in sdkconfig.defaults), il sistema di build compila per il chip ESP32 originale. Il programma compila senza errori, poi al momento di scriverlo sul C6 esptool si ferma con un messaggio del tipo “This chip is ESP32-C6, not ESP32. Wrong chip argument?”. Per questo, in ogni progetto nuovo, il primo comando è idf.py set-target esp32c6. Nel corso il target non è scritto nei progetti degli esercizi: lo fissi tu, una volta, con quel comando.
sdkconfig e sdkconfig.defaults
Tutte le opzioni di configurazione (Kconfig) finiscono nel file sdkconfig, che menuconfig modifica. Il file sdkconfig.defaults, se c’è, contiene solo le opzioni che vuoi diverse dai valori di ESP-IDF. Attenzione al dettaglio: sdkconfig.defaults viene usato quando sdkconfig si crea da zero, oppure per le opzioni che sdkconfig non contiene ancora. Se cambi un valore in sdkconfig.defaults dopo la prima build, devi cancellare sdkconfig (o rifare set-target) perché abbia effetto. Lo vedrai nell’esercizio 02.2. Anatomia completa del progetto nella Puntata 3 (pubblicazione in arrivo).
Flash veloce
Dalla 6.1 idf.py flash salva nella cartella build una copia di ciò che ha scritto (file *_flashed.bin); la volta dopo riscrive solo i settori cambiati e verifica la flash, e se la verifica fallisce rifà tutto. Per forzare una scrittura completa c’è idf.py flash -a (o --all): la guida la consiglia per schede nuove o appena cancellate con idf.py -p PORTA erase-flash.
Che cosa produce la build
Una build riuscita termina con “Project build complete” e lascia nella cartella build diversi file. Quelli da conoscere subito:

esptool usa sul C6 con la tabella partizioni predefinita.-
bootloader/bootloader.bin: il bootloader di secondo stadio, compilato come un piccolo progetto a parte. Sul C6 va all’indirizzo0x0della flash. -
partition_table/partition-table.bin: la tabella delle partizioni, all’indirizzo predefinito0x8000. Con la tabella predefinita “Single factory app, no OTA” contiene una partizionenvs, unaphy_inite l’appfactorya0x10000. -
nome_progetto.bin: l’applicazione, a0x10000. Il nome viene dalla rigaproject()delCMakeLists.txt. -
nome_progetto.elfenome_progetto.map: il programma con tutti i simboli e la mappa del linker. Non si scrivono sulla scheda, ma servono al monitor per tradurre gli indirizzi in file e riga, e aidf.py sizeper i conti. -
flash_project_args,flash_app_args,flasher_args.json: dove va ciascun file. Con questi si può scrivere la scheda anche senzaidf.py, per esempio conesptool ... write-flash @build/flash_project_args.
Il monitor seriale
idf.py monitor avvia IDF Monitor, un terminale seriale con qualche abilità in più. Si collega a 115 200 baud, la velocità predefinita della console del C6, e colora le righe di log secondo il livello (errore, avviso, informazione…), riconoscendolo dalla lettera iniziale. Quando il chip va in panic e stampa indirizzi di codice, il monitor li cerca nel file .elf e scrive accanto file e numero di riga. Dettagli nella Puntata 5 (pubblicazione in arrivo).
Tutti i tasti premuti vanno alla scheda, tranne due: Ctrl+] e Ctrl+T. Il primo esce; il secondo apre un piccolo menu, cioè va seguito da un altro tasto:
| Scorciatoia | Azione |
|---|---|
Ctrl+] |
esce dal monitor |
Ctrl+T poi Ctrl+X (o X) |
esce anch’essa: utile se sulla tua tastiera Ctrl+] è scomodo |
Ctrl+T poi Ctrl+H (o H) |
mostra tutte le scorciatoie |
Ctrl+T poi Ctrl+R
|
resetta la scheda tramite la linea RTS, se collegata |
Ctrl+T poi Ctrl+F
|
sospende il monitor, ricompila e riscrive tutto, poi riprende |
Ctrl+T poi Ctrl+A (o A) |
come sopra, ma solo l’app: più veloce |
Ctrl+T poi Ctrl+Y
|
ferma o riprende la stampa a schermo |
Ctrl+T poi Ctrl+L
|
avvia o ferma il salvataggio dell’uscita su file |
Ctrl+T poi Ctrl+I (o I) |
aggiunge o toglie l’orario all’inizio di ogni riga |
E Ctrl+C? Nel monitor non esce: interrompe l’applicazione e avvia GDB, il debugger, e per farlo richiede un’opzione (CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME) che per impostazione predefinita è disattivata. Quando premi Invio, il monitor manda alla scheda un CR (ritorno carrello): è il valore predefinito per i chip reali, e ci servirà nell’esercizio 02.3.
Porte seriali e USB Serial/JTAG del C6
La ESP32-C6-DevKitC-1 ha due connettori USB-C, e tutti e due servono ad alimentare la scheda e a scrivere la flash:
- “USB-to-UART”: passa da un ponte USB-seriale montato sulla scheda, collegato alla UART0 del chip;
- “ESP32-C6 USB”: va direttamente ai piedini USB del chip, GPIO13 (D+) e GPIO12 (D−), dove c’è il controller USB Serial/JTAG.

Il controller USB Serial/JTAG è un dispositivo USB a funzione fissa, realizzato interamente in hardware. Offre tre cose: una console seriale bidirezionale (la parte CDC-ACM, cioè la classe USB delle porte seriali), la scrittura della flash con esptool e idf.py flash, e il debug JTAG, anche in contemporanea con la seriale (Puntata 6, pubblicazione in arrivo). Non si riprogramma per fare altro: per dispositivi USB personalizzati servono i chip con USB OTG.
Come appare sul PC
Il sistema operativo vede la parte seriale come una porta qualsiasi:
-
Windows: una porta
COMin Gestione dispositivi; scollega e ricollega la scheda e guarda quale porta sparisce e ricompare. -
Linux:
/dev/ttyACM*(il ponte UART appare invece come/dev/ttyUSB*). Lancials /dev/tty*prima e dopo aver collegato la scheda. -
macOS:
/dev/cu*; anche quils /dev/cu.*prima e dopo.
Per la seriale di solito non serve installare nulla. Per la parte JTAG, su Windows possono servire i driver USB: la documentazione indica il pulsante Install Drivers nella dashboard dell’EIM, oppure il comando eim install-drivers. Su Linux, per il JTAG, vanno aggiunte le regole udev di OpenOCD.
Quale porta per la console
Nella v6.1 il canale della console si sceglie in Component config → ESP-STDIO → Channel for console output. Sul C6 il predefinito è la UART0, con una console secondaria sulla USB Serial/JTAG (opzione CONFIG_ESP_CONSOLE_SECONDARY_USB_SERIAL_JTAG). Quindi i log escono da entrambi i connettori, ma la secondaria è solo in uscita: per leggere tasti dalla USB bisogna fare della USB Serial/JTAG la console principale, con CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG=y. È quello che farai nell’esercizio 02.3.
Di norma il controller USB Serial/JTAG mette da solo il chip in modalità download. Se non ci riesce (alla primissima scrittura, se l’app ha riconfigurato i piedini USB o se il chip è in deep sleep, perché in quel caso il dispositivo USB sparisce dal PC) si fa a mano: tieni premuto BOOT, premi e rilascia RESET, poi rilascia BOOT. Il pulsante BOOT è collegato a GPIO9, il piedino che sceglie la modalità di avvio.
Errori comuni
| Sintomo | Causa probabile | Rimedio |
|---|---|---|
flash non apre la porta |
la porta è occupata: un monitor ancora aperto, PuTTY, un altro terminale | chiudi ogni programma che usa la porta; esci dal monitor con Ctrl+], non chiudendo la finestra |
| “Permission denied” su Linux | l’utente non può leggere e scrivere la porta seriale |
sudo usermod -a -G dialout $USER (su Arch il gruppo è uucp), poi esci e rientra nella sessione |
| “This chip is ESP32-C6, not ESP32” | target mai impostato: il progetto è compilato per ESP32 |
idf.py set-target esp32c6, poi di nuovo flash
|
| “Failed to connect” | il chip non entra in modalità download | BOOT premuto, RESET, rilascia BOOT; poi ripeti il comando |
| Errori strani di CMake o di percorso | spazi nel percorso del progetto o di ESP-IDF | sposta il progetto in una cartella senza spazi |
| Nessuna riga sul monitor | porta sbagliata, console su un altro canale, o livello di log a “No output” | controlla la porta, Channel for console output e Log Level in menuconfig; premi RESET |
idf.py sconosciuto |
ambiente non attivato in questo terminale | apri il terminale dall’EIM o esegui lo script di attivazione |
Esercizi
★ Esercizio 02.1 — Il mio primo progetto
Crea un progetto con idf.py create-project primo_progetto (il modello è tools/templates/sample_project; nella v6.1 tra gli esempi di examples/get-started trovi invece hello_world e blink). Imposta il target esp32c6 e scrivi un app_main() che all’avvio stampi un messaggio personalizzato con il nome del chip, preso da CONFIG_IDF_TARGET, e poi, una volta al secondo, una riga Contatore: N con N che cresce da 0. Compila, scrivi la scheda e apri il monitor con un solo comando. Guarda anche idf.py size e il contenuto della cartella build.
Risultato atteso
I (296) main_task: Calling app_main()
Ciao da Cheap! Primo progetto ESP-IDF su esp32c6.
Contatore: 0
Contatore: 1
Contatore: 2
...
I numeri tra parentesi sono millisecondi dall’avvio e possono essere diversi. Il comportamento sulla scheda è da provare al banco.
Suggerimenti
-
vTaskDelay()vuole tick, non millisecondi: converti conpdMS_TO_TICKS(1000). - Per stampare un
uint32_tin modo portabile usaPRIu32da<inttypes.h>. -
CONFIG_IDF_TARGETsta insdkconfig.h: includilo. - Comando unico:
idf.py -p PORTA flash monitor; esci conCtrl+].
★★ Esercizio 02.2 — Livelli di log
Nello stesso stile, scrivi un ciclo che ogni secondo produce un messaggio INFO (ESP_LOGI) con il numero del giro, ogni cinque giri un WARN (ESP_LOGW), a ogni giro un DEBUG (ESP_LOGD) con i giri che mancano al prossimo avviso, e un VERBOSE (ESP_LOGV). All’avvio stampa il valore di CONFIG_LOG_DEFAULT_LEVEL. Il livello di log predefinito va scelto in sdkconfig.defaults con l’opzione CONFIG_LOG_DEFAULT_LEVEL_DEBUG=y (menu Component config → Log → Log Level → Default log verbosity). Poi prova CONFIG_LOG_DEFAULT_LEVEL_INFO=y e CONFIG_LOG_DEFAULT_LEVEL_WARN=y e annota cosa cambia.
Risultato atteso (livello Debug)
I (310) livelli: Livello di log predefinito: 4
I (310) livelli: Giro 1
D (310) livelli: Dettaglio: prossimo avviso fra 4 giri
I (1310) livelli: Giro 2
D (1310) livelli: Dettaglio: prossimo avviso fra 3 giri
...
I (4310) livelli: Giro 5
W (4310) livelli: Avviso: sono passati altri 5 giri
D (4310) livelli: Dettaglio: prossimo avviso fra 5 giri
Con Debug possono comparire righe D anche dai componenti di sistema durante l’avvio, perché il livello predefinito vale per tutti i tag. Con Info spariscono tutte le righe D; con Warning restano solo le W. La riga Verbose non compare mai, a meno di scegliere Verbose come livello. Il comportamento sulla scheda è da provare al banco.
Suggerimenti
-
sdkconfig.defaultsvale solo quandosdkconfignon c’è o non contiene l’opzione: dopo ogni modifica cancellasdkconfig(oppure rifaiidf.py set-target esp32c6) e ricompila. - Il “livello massimo” (
CONFIG_LOG_MAXIMUM_LEVEL) è, per impostazione predefinita, uguale a quello predefinito: i messaggi più dettagliati non entrano nemmeno nel firmware. Confrontaidf.py sizetra Debug e Warning. - Il formato di riga è livello, millisecondi tra parentesi, tag, messaggio:
I (56) boot: ....
★★★ Esercizio 02.3 — Eco maiuscolo
Collega il connettore “ESP32-C6 USB” e scrivi un programma che legge i caratteri digitati nel monitor e li rimanda subito convertiti in maiuscolo; quando premi Invio, ristampa la riga completa con la sua lunghezza. Fai della USB Serial/JTAG la console principale con CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG=y in sdkconfig.defaults. Per leggere segui l’esempio ufficiale examples/peripherals/usb_serial_jtag/usb_serial_jtag_echo: installa il driver con usb_serial_jtag_driver_install() e leggi con usb_serial_jtag_read_bytes(). Poi chiama usb_serial_jtag_vfs_use_driver(), così anche printf e i log passano dal driver.
Risultato atteso (digitando “ciao cheap” e Invio)
I (305) eco: Pronto: scrivi qualcosa e premi Invio.
CIAO CHEAP
Riga (10 caratteri): CIAO CHEAP
Il comportamento sulla scheda è da provare al banco.
Suggerimenti
- Nel
main/CMakeLists.txtaggiungiPRIV_REQUIRES esp_driver_usb_serial_jtag, come nell’esempio di riferimento. - Il monitor manda CR quando premi Invio, altri terminali LF o CR+LF: gestisci tutti e due i caratteri e ignora le righe vuote.
-
toupper()eisprint()di<ctype.h>lavorano sui caratteri ASCII; le lettere accentate arrivano come più byte UTF-8 e conviene lasciarle stare. - Limita la riga a un buffer fisso (per esempio 64 caratteri) e scarta i caratteri in più.
- Sfida nella sfida: gestisci il backspace (0x08, e 0x7F che molti terminali mandano al suo posto) rimandando
"\b \b".
Le soluzioni complete sono nello ZIP degli esercizi del corso, cartella 02-installare-ambiente.
Verifica
- Qual è il metodo d’installazione raccomandato per ESP-IDF v6.1 e in quali due forme si presenta?
- Che cosa succede se compili un progetto senza aver mai impostato il target, e come te ne accorgi?
- Quali file binari scrive
idf.py flashsul C6 e a quali indirizzi, con la tabella partizioni predefinita? - Come si esce da IDF Monitor? E che cosa fa invece
Ctrl+C? - Con la configurazione predefinita, perché vedi i log anche sul connettore “ESP32-C6 USB” ma non puoi mandare comandi alla scheda da lì?
Riepilogo
- Dalla 6.0 si installa con l’EIM, in GUI o CLI, online o offline; servono Python 3.10 o più recente e percorsi senza spazi.
- L’ambiente va attivato in ogni terminale: dalla dashboard dell’EIM, dal collegamento sul desktop o con lo script
activate_idf_.... -
idf.pycopre l’intero ciclo; il primo comando di ogni progetto èset-target esp32c6. - La build produce bootloader (
0x0sul C6), tabella partizioni (0x8000) e app (0x10000), più.elfe.mapper monitor e analisi. - Nella 6.1
idf.py flashriscrive solo ciò che è cambiato;-aforza la scrittura completa. - Il monitor si chiude con
Ctrl+];Ctrl+Tapre il menu delle scorciatoie. - Il C6 ha la USB Serial/JTAG integrata: seriale, flash e JTAG con un solo cavo. Per leggere tasti da lì serve
CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG=y.
Nella prossima puntata
Apriamo il progetto e guardiamo dentro: i due CMakeLists.txt, i componenti e il componente main, il rapporto tra sdkconfig, sdkconfig.defaults e menuconfig, e come aggiungere opzioni Kconfig nostre al menu di configurazione.
Per approfondire
- Get Started: installazione con l’EIM e primo progetto (v6.1, ESP32-C6)
- Establish Serial Connection with ESP32-C6
- IDF Frontend: idf.py
- IDF Monitor e le sue scorciatoie
- USB Serial/JTAG Controller Console
- Migration guide 6.1: strumenti (flash veloce)
- Documentazione dell’ESP-IDF Installation Manager (EIM)
- ESP-IDF Extension for VS Code
- Guida utente della ESP32-C6-DevKitC-1
Corso ESP-IDF di Web App Portal. Testi CC BY-NC-SA 4.0, codice MIT. ESP-IDF è un marchio di Espressif Systems; gli altri marchi appartengono ai rispettivi proprietari.
