ESP32 (6) – Collegamento ad una rete wifi

luca 16/01/2017 14

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);

14 Comments »

  1. rudi ;-) 16/01/2017 at 11:47 - Reply

    hi

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

    best wishes
    rudi ;-)

    • luca 17/01/2017 at 14:00 - Reply

      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 ;)

  2. Andrew 17/01/2017 at 02:18 - Reply

    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.

    • luca 17/01/2017 at 13:55 - Reply

      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?

    • lind 26/04/2017 at 12:07 - Reply

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

      • luca 26/04/2017 at 12:57 - Reply

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

  3. Rodolfo 24/05/2017 at 13:46 - Reply

    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!!

    • luca 25/05/2017 at 15:02 - Reply

      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?

      • Rodolfo 29/05/2017 at 10:09 - Reply

        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

  4. Kartik Sikka 22/07/2017 at 16:59 - Reply

    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 ?

    • luca 24/07/2017 at 09:15 - Reply

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

  5. Emilio 15/09/2017 at 09:23 - Reply

    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.

    • luca 16/09/2017 at 15:58 - Reply

      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.

Leave A Response »

Questo sito usa i cookie per poterti offrire una migliore esperienza di navigazione maggiori informazioni

Questo sito utilizza i cookie per fonire la migliore esperienza di navigazione possibile. Continuando a utilizzare questo sito senza modificare le impostazioni dei cookie o clicchi su "Accetta" permetti al loro utilizzo.

Chiudi