ESP32 (6) – Collegamento ad una rete wifi

by luca
20 comments

In questo post vi mostrerò come effettuare il collegamento ad una rete wifi.

Il framework esp-idf include un driver wifi che si occupa della gestione dell’interfaccia wifi del modulo esp32. Tale driver mette a disposizione delle API che il programma può utilizzare; alcune di queste API le abbiamo già viste nel precedente tutorial:

ESP_ERROR_CHECK(esp_wifi_init(&wifi_config));
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
ESP_ERROR_CHECK(esp_wifi_start());

Il driver wifi viene eseguito in parallelo al programma principale e comunica con questo tramite eventi:

esp32-wifi02

Nel programma principale dobbiamo definire una funzione che farà da event handler, ovvero che sarà chiamata dal driver wifi ogni volta che un nuovo evento deve essere notificato:

static esp_err_t event_handler(void *ctx, system_event_t *event)
{...}

dobbiamo quindi indicare al framework il nome di tale funzione:

ESP_ERROR_CHECK(esp_event_loop_init(event_handler, NULL));

L’elenco dei diversi eventi generati dal framework è presente nel file esp_event.h. Per quanto riguarda il driver wifi in modalità station, gli eventi sono quelli con prefisso SYSTEM_EVENT_STA:

esp32-wifi03

Il collegamento ad una rete wifi avviene secondo questo flusso logico:

esp32-wifi04

  • il programma principale effettua delle chiamate API per configurare ed avviare il driver
  • terminate le attività interne, il driver notifica che l’avvio è avvenuto con successo tramite l’evento SYSTEM_EVENT_STA_START
  • l’event handler, una volta ricevuta la notifica di avvio del driver, può eseguire l’API esp_wifi_connect() per chiedere al driver il collegamento alla rete wifi specificata in fase di configurazione
  • una volta effettuato il collegamento e ottenuto un indirizzo IP (se utilizziamo il servizio DHCP), il driver lo notifica tramite l’evento SYSTEM_EVENT_STA_GOT_IP
  • ora l’event handler può informare il programma principale che il collegamento alla rete è avvenuto con successo

Sincronizziamo i tasks

Il processo descritto sopra prevede che il programma principale aspetti l’avvenuto collegamento alla rete wifi prima di eseguire le sue attività. E’ quindi necessario capire come sincronizzare i diversi elementi coinvolti: programma principale, event handler e driver wifi. Similmente a quanto abbiamo già visto, FreeRTOS mette a disposizione del programmatore un sistema di eventi per fare comunicare i diversi tasks. La gestione degli eventi in FreeRTOS avviene tramite event groupsevent bits.

Possiamo immaginare gli event bits come delle “bandiere” (flags) visibili dai diversi tasks:

  • il programmatore può definire un numero arbitrario di event bits
  • i task possono alzare (set) o abbassare (clear) i diversi bits
  • i task possono interrompere la loro esecuzione aspettando che uno o più bit siano attivati

Infine gli event bits sono raggruppati in event groups, ognuno dei quali normalmente contiene 8 event bits. Gli event bits all’interno di un event group sono nominati in base alla loro “posizione” (BIT0, BIT1…):

esp32-wifi05

Il programma

Il programma completo si trova nel mio repository Github. Commentiamo le parti principali:

static EventGroupHandle_t wifi_event_group;
const int CONNECTED_BIT = BIT0;
[...]
wifi_event_group = xEventGroupCreate();

Il programma definisce un event group (wifi_event_group) e un event bit (CONNECTED_BIT). All’interno di app_main() tale event group viene creato utilizzando il metodo xEventGroupCreate() di FreeRTOS.

#define WIFI_SSID "MYSSID"
#define WIFI_PASS "MYPASSWORD"
[...]
wifi_config_t wifi_config = {
  .sta = {
    .ssid = WIFI_SSID,
    .password = WIFI_PASS,
  },
};
ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config));

La configurazione della rete wifi avviene tramite la definizione di due costanti (WIFI_SSID e WIFI_PASS). Tali costanti sono poi utilizzate per creare la struttura wifi_config, struttura che viene passata come parametro al metodo esp_wifi_set_config.

static esp_err_t event_handler(void *ctx, system_event_t *event)
{
switch(event->event_id) {
 
  case SYSTEM_EVENT_STA_START:
    esp_wifi_connect();
    break;
  case SYSTEM_EVENT_STA_GOT_IP:
    xEventGroupSetBits(wifi_event_group, CONNECTED_BIT);
    break;  
  case SYSTEM_EVENT_STA_DISCONNECTED:
    xEventGroupClearBits(wifi_event_group, CONNECTED_BIT);
    break;

L’event handler gestisce i diversi eventi generati dal driver wifi come illustrato sopra. In particolare, una volta stabilita la connessione (evento STA_GOT_IP), attiva l’event bit CONNECTED_BIT; al contrario in caso di disconnessione disattiva (clear) tale event bit.

xEventGroupWaitBits(wifi_event_group, CONNECTED_BIT, false, true, portMAX_DELAY);

Il task principale (main_task) si mette in pausa fino al completamento della connessione alla rete wifi attendendo l’attivazione del bit CONNECTED_BIT. La costante portMAX_DELAY indica che l’attesa deve avvenire per un tempo indefinito.

tcpip_adapter_ip_info_t ip_info;
ESP_ERROR_CHECK(tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_STA, &ip_info));
printf("IP Address:  %s\n", ip4addr_ntoa(&ip_info.ip));
printf("Subnet mask: %s\n", ip4addr_ntoa(&ip_info.netmask));
printf("Gateway:     %s\n", ip4addr_ntoa(&ip_info.gw));

Una volta stabilita la connessione, il task principale visualizza i parametri di rete (indirizzo IP, netmask e gateway). La costante TCPIP_ADAPTER_IF_STA rappresenta (vedi file tcpip_adapter.h) l’interfaccia di rete quando il chip esp32 è in modalità station.

Ecco uno screenshot del programma in esecuzione:

esp32-wifi06

Per rendere l’output più chiaro, ho spento il logging di default del driver wifi con l’istruzione:

esp_log_level_set("wifi", ESP_LOG_NONE);

e disabilitato il buffering di standard output:

setvbuf(stdout, NULL, _IONBF, 0);

Related Posts

20 comments

rudi ;-) 16 gennaio 2017 - 11:47

hi

nice post!
hope we read more of this art from you.

best wishes
rudi 😉

Reply
luca 17 gennaio 2017 - 14:00

Thanks Rudi, it’s great to read you here: I followed your posts on the official forum! I’m going to post a tutorial every week, a lot of peripherals in this little chip 😉

Reply
Andrew 17 gennaio 2017 - 02:18

Somehow your code from github doesn’t work on my ESP32. The program is simple and straightforward, thanks for all those details… but it throws ‘Guru Meditation Error of type LoadProhibited occurred on core 0. Exception was unhandled.’ My other WiFi programs work fine though.

Reply
luca 17 gennaio 2017 - 13:55

Hi Andew… very strange: I’ve just compiled the example again and it runs fine on my ESP32 board. Are you using the release 1.0 of the framework or is it updated with the latest commits?

Reply
lind 26 aprile 2017 - 12:07

Hi, I had the same problem, commenting the line :
//setvbuf(stdout, NULL, _IONBF, 0);
solved the problem for me

Reply
luca 26 aprile 2017 - 12:57

Thanks! It solved also for me… I’m going to fix all the examples in the repository

Reply
lucadentella.it – ESP32 (18) – Access Point 20 maggio 2017 - 15:39

[…] il chip esp32 in STAtion Mode, ovvero come client che si collega ad una rete wifi esistente. In un precedente articolo ho spiegato in dettaglio come interagiscono i vari componenti del framework esp-idf per […]

Reply
Rodolfo 24 maggio 2017 - 13:46

Hello Luca,

Thank for your guides! I’m planning to follow them all 🙂

I’m having a problem with this one. I downloaded your code from Github and I have the following errors:

const int CONNECTED_BIT = BIT0; // BIT0 could not be resolved

tcpip_adapter_ip_info_t ip_info; // tcpip_adapter_ip_info_t could not be resolved

I tried including #include “tcpip_adapter.h” (Path and Symbols, GNU C, add the folder tcpip_adapter under components) and adding a #include “tcpip_adapter.h” in the main. But the include is also not resolved.

I tried also rebuilding the index. But still the same problem.

Any advice? Thanks!!

Reply
luca 25 maggio 2017 - 15:02

Hi Rodolfo, this is strange… I can compile the example with the latest framework. For example I include esp_event_loop.h, which includes esp_event.h which includes tcpip_adapter.h that defines tcpip_adapter_ip_info_t. Are you sure your esp-idf repository is updated and complete?

Reply
Rodolfo 29 maggio 2017 - 10:09

Now it’s even stranger. I erased part of the code that was directly using tcpip functions and left esp_event_loop. Now it compiles… When seeing esp_event.h, there is a warning saying that the include is not found. But it’s not an error. I’m using the latest esp-idf on OSX. Maybe it’s a good idea to reinstall everything again. Will keep you posted. Thanks

Reply
Kartik Sikka 22 luglio 2017 - 16:59

Hi luca ,
I have been reading your posts on ESP 32 , they are amazing .

I have one question that , form where do you collect the info to write the code ?

I want to write my own code for ESP 32 for some application , How do I proceed ?

Reply
luca 24 luglio 2017 - 09:15

Hi, my sources are the official documentation, the official forum (esp32.com) and many tutorials/videos other makers publish everyday on the Internet!

Reply
Emilio 15 settembre 2017 - 09:23

Hi,
congrats for the great job and your dedication to this!!
I guess the code should compile using Arduino IDE, if so, it halts in setup() at “configure the wifi connection and start the interface” with error: C99 designator ‘ssid’ outside aggregate initializer.
The only thing I did is copy/paste in the IDE added void loop() and changed the main to setup().
Is it correct?
Thanks again.

Reply
luca 16 settembre 2017 - 15:58

Hi Emilio, this code (and in general my tutorials) are not meant to be used with Arduino IDE but with the official esp-idf framework.

Reply
lucadentella.it – ESP32lights 8 gennaio 2018 - 09:12

[…] il collegamento ad una rete wifi e l’utilizzo dei pin digitali del chip esp32 per il controllo del relay sono stati oggetto […]

Reply
Stefano 12 febbraio 2018 - 16:13

Ciao Luca, per iniziare ti faccio i complimenti per il grande lavoro che hai fatto.
Ho un modulo ESP-WROOM-32 sul quale ho provato un po’ di esempi dell’ambiente ESP-IDF e funzionano.
Ho provato a compilare il tuo esempio sulla connessione wifi, ma appena riavvio l’esp dopo l’upload, sul monitor vedo a rotazione sempre questi messaggi:
[…]

Reply
luca 26 febbraio 2018 - 14:54

ciao Stefano, ho rivisto recentemente tutti i sorgenti per renderli compatibili con le nuove versioni di esp-idf… prova nuovamente prendendo l’esempio da Github

Reply
Stefano 13 febbraio 2018 - 21:50

Risolto.
Alla fine ho cambiato modulo e quest’ultimo funziona.
Dovrò approfondire perchè l’altro da quei problemi
Grazie.

Reply
Ivan 6 ottobre 2018 - 21:46

Ciao Luca,
mi spieghi la necessità di
while (1)
{
vTaskDelay(1000 / portTICK_RATE_MS);
}

in mai_task, ho provato a toglierlo, ma non si collega più alla rete wifi. Non capisco il perchè.

Grazie

Reply
luca 8 ottobre 2018 - 07:15

ciao, serve per mettere in “pausa” quel task in modo che FreeRTOS possa eseguire anche gli altri tasks del programma, tra i quali quello che si occupa proprio della connessione wifi

Reply

Leave a Comment