In this post I’m going to show you how to connect to a wifi network.
The esp-idf framework includes a wifi driver that manages the wifi interface of the esp32 chip. The driver exposes API calls the programmer can use to interact with it; you’ve already used some of those APIs in my previous 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()); |
The driver is executed in parallel with the main program and communicates with it using events:
In the main program you have to define a function that will be the event handler, i.e. a function called by the wifi driver every time it has to notify a new event:
static esp_err_t event_handler(void *ctx, system_event_t *event) {...} |
then you have to tell the framework the name of your function:
ESP_ERROR_CHECK(esp_event_loop_init(event_handler, NULL)); |
The list of the events the framework may generate is included in the esp_event.h file. The events related to the wifi driver when working in station mode have SYSTEM_EVENT_STA as name prefix:
The connection to a wifi network follows this flow diagram:
- the main program configures and starts the driver via API calls
- after having completed its internal tasks, the driver notifies that it has successfully started triggering the event SYSTEM_EVENT_STA_START
- the event handler, once received that event, can call the esp_wifi_connect() API to ask the driver to connect to the network specified during the configuration phase
- when the connection is completed and after having obtained a valid IP address (if the DHCP service is used), the driver triggers the event SYSTEM_EVENT_STA_GOT_IP
- now the event handler can inform the main program that the connection has been completed
Tasks synchronization
In the process described above, the main program waits for the connection to be completed before executing its own instructions. It’s therefore important to understand how to synchronize the different elements: the main program, the event handler and the wifi driver. FreeRTOS offers different ways to make the tasks communicate: one of the simplest is via events. Events, in FreeRTOS, are managed using event groups and event bits.
Event bits are similar to flags, visible to the different tasks:
- the programmer can create as many event bits as he needs
- tasks can activate (set) o deactivate (clear) the different bits
- a task can pause its execution waiting for one of more bits to be set
Event bits are grouped into event groups, each of them usually contains 8 event bits. Event bits in an event group are numbered depending on their “position” (BIT0, BIT1…):
The program
The complete program is available in my Github repository. Let’s review the main sections:
static EventGroupHandle_t wifi_event_group; const int CONNECTED_BIT = BIT0; [...] wifi_event_group = xEventGroupCreate(); |
The program defines an event group (wifi_event_group) and an event bit (CONNECTED_BIT). In the app_main() the event group is created using the FreeRTOS xEventGroupCreate() method.
#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)); |
The configuration of the wifi network starts with the definition of two constants: the SSID name and the password (WIFI_SSID e WIFI_PASS). The constants are then used to initialize the wifi_config struct; struct which is then passed as parameter to the esp_wifi_set_config method.
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; |
The event handler manages the different events triggered by the wifi driver as explained above. In particular, once the connection is established (STA_GOT_IP event), sets the CONNECTED_BIT event bit. On the contrary, in case of disconnection it clears the same event bit.
xEventGroupWaitBits(wifi_event_group, CONNECTED_BIT, false, true, portMAX_DELAY); |
The main task pauses its execution until the connection to the wifi network is perfomed, waiting for the CONNECTED_BIT bit to be set. The portMAX_DELAY constant will cause the task to block indefinitely (without a timeout).
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)); |
When the connection is established, the main task prints out the network parameters (IP address, netmask and gateway). The TCPIP_ADAPTER_IF_STA constant represents (see tcpip_adapter.h) the network interface of the esp32 chip when working in station mode.
Here’s a screenshot of the program in execution:
To make its output clearer, I turned off the default logging of the wifi driver with the instruction:
esp_log_level_set("wifi", ESP_LOG_NONE); |
and disabled the buffering for the standard output:
setvbuf(stdout, NULL, _IONBF, 0); |
hi
nice post!
hope we read more of this art from you.
best wishes
rudi 😉
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 😉
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.
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?
Hi, I had the same problem, commenting the line :
//setvbuf(stdout, NULL, _IONBF, 0);
solved the problem for me
Thanks! It solved also for me… I’m going to fix all the examples in the repository
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!!
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?
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
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 ?
Hi, my sources are the official documentation, the official forum (esp32.com) and many tutorials/videos other makers publish everyday on the Internet!
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.
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.
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:
[…]
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
Risolto.
Alla fine ho cambiato modulo e quest’ultimo funziona.
Dovrò approfondire perchè l’altro da quei problemi
Grazie.
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
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