ÍNDICE DE CONTEÚDO
Olá caro leitor, como vai? Sim o momento chegou, o suporte ao WIFI do ESP32 chegou ao Zephyr RTOS, transformando esse projeto em mais uma alternativa de uso ao ESP-IDF para o desenvolvimento de aplicações para esse pequeno chip notável da Espressif. Com esse suporte no lugar, resolvi então quebrar um pouco do meu hiato de artigos e aproveitar para trazer um outro assunto junto com esse que muitos me perguntam: “Como ter uma aplicação com o Zephyr RTOS fora do diretório do projeto”.
Existem vantagens notáveis para a criação da sua aplicação com o Zephyr fora do diretório de exemplos, dentre elas podemos citar uma muito impactante, a independência entre os projetos, de forma que é possível que ambos corram com suas manutenções e repositórios separados, sem que o código de aplicação toque no código do kernel e vice-versa.
Nesse texto vamos criar uma aplicação com o uso do WIFI do ESP32 e out-of-tree do Zephyr.
Entendendo o suporte do ESP32 no Zephyr RTOS
O suporte do ESP32 no Zephyr evoluiu bastante ao longo das últimas atualizações do projeto, revelando-se um grande esforço da comunidade que mantém o projeto, reforçado pela própria Espressif que atualmente contribui para o suporte. Com isso branch main do Zephyr para o ESP32 suporta:
- Drivers para UART;
- Drivers para I2C;
- Drivers para SPI;
- Drivers para GPIO;
- Drivers para memoria Flash;
- Driver para PWM utilizando o LEDC;
- Suporte para WiFI;
- Suporte para Bluetooth.
É esperado que, em termos de release, essas funcionalidades cheguem na próxima versão do kernel, que é a 2.6. Enquanto isso não ocorre, usuários podem utilizar o ESP32 através do já citado branch main.
Seminário Linux Embarcado 2024: Evento Presencial em São Paulo
Participe do Seminário Linux Embarcado 2024 em São Paulo. Conhecimento técnico, palestras, workshops e oportunidade de networking com profissionais experientes.
Quero minha aplicação fora da árvore do Zephyr!
Mas você, usuário do ESP32 que quer testar o Zephyr, provavelmente gostaria de ter aquela sensação de limpeza, da sua aplicação está apenas consumindo os recursos do Zephyr certo? Então vamos deixar as coisas mais interessantes para você. Então no lugar de usar os samples dentro do kernel, vamos por outro caminho mais legal e mais profissional.
O primeiro passo, se você ainda não tem o Zephyr instalado em sua máquina, sugiro que comece com o melhor post introdutório sobre o assunto, esse aqui: https://embarcados.com.br/zephyr-rtos-no-esp32-primeiros-passos/. Após conferir que está tudo bem com sua instalação vamos ao próximo passo. Utilizarei o VSCode para ilustrar, mas o leitor é livre para utilizar o editor e gerenciador que lhe convir.
O primeiro passo, é criar um diretório para seu projeto, no meu caso, o esp32_sta_wifi_out_of_tree, dentro dele crie uma pasta para seus arquivos C, eu escolhi o nome src, e por último adicione dentro do diretório da sua aplicação o arquivo CMakeLists.txt, dentro da pasta src, você pode colocar seu arquivo main.c, não esqueça o prj.conf, esse arquivo contém configuração padrão do seu projeto que apresentaremos em seguida.
A seguinte estrutura deve estar no seu projeto (aqui demonstrada com o comando tree no terminal):
1 2 3 4 5 6 7 8 9 |
ulipe@pop-os:~/espressif_work$ tree esp32_sta_wifi_out_of_tree/ esp32_sta_wifi_out_of_tree/ ├── CMakeLists.txt ├── prj.conf ├── README.rst └── src └── main.c 1 directory, 4 files |
Agora vamos começar a rechear os arquivos, atenção aos comentários onde houver:
CMakeLists.txt:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
# SPDX-License-Identifier: Apache-2.0 # Obrigatorio: o Zephyr exige cmake minimo para funcionar cmake_minimum_required(VERSION 3.13.1) # Obrigatório: O cmake precisa achar o Zephyr find_package(Zephyr HINTS $ENV{ZEPHYR_BASE}) # Obrigatorio: mas o nome fica do seu gosto: project(esp32_wifi_station) # Obrigatorio: adicione aqui seus arquivos C para o simbolo de sources FILE(GLOB app_sources src/*.c) # Obrigatorio: em seguida alimente o simbolo "app" com os arquivos adicionados target_sources(app PRIVATE ${app_sources}) |
prj.conf:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
# Habilite o susbsitema de wifi CONFIG_WIFI=y # Dentre os drivers, escolha o do ESP32 CONFIG_WIFI_ESP32=y CONFIG_HEAP_MEM_POOL_SIZE=98304 # Precisamos tambem da stack TCP/IP do Zephyr CONFIG_NETWORKING=y CONFIG_NET_L2_ETHERNET=y CONFIG_NET_IPV6=n CONFIG_NET_IPV4=y CONFIG_NET_DHCPV4=y CONFIG_NET_MGMT=y CONFIG_NET_MGMT_EVENT=y CONFIG_NET_LOG=y CONFIG_NET_SHELL=n # O mbedTLS é o TLS padrao para conexoes seguras CONFIG_MBEDTLS=y CONFIG_MBEDTLS_ENTROPY_ENABLED=y CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED=y CONFIG_MBEDTLS_ECP_ALL_ENABLED=y # SSID e senha do wifi onde pretende conectar CONFIG_ESP32_WIFI_SSID="ssid" CONFIG_ESP32_WIFI_PASSWORD="password" |
src/main.c:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 |
/* * Copyright (c) 2020 Espressif Systems (Shanghai) Co., Ltd. * * SPDX-License-Identifier: Apache-2.0 */ #include <zephyr.h> #include <sys/printk.h> #include <esp_wifi.h> #include <esp_timer.h> #include <esp_event.h> #include <net/net_if.h> #include <net/net_core.h> #include <net/net_context.h> #include <net/net_mgmt.h> #include <logging/log.h> LOG_MODULE_REGISTER(esp32_wifi_sta, LOG_LEVEL_DBG); static struct net_mgmt_event_callback dhcp_cb; static void handler_cb(struct net_mgmt_event_callback *cb, uint32_t mgmt_event, struct net_if *iface) { if (mgmt_event != NET_EVENT_IPV4_DHCP_BOUND) { return; } char buf[NET_IPV4_ADDR_LEN]; LOG_INF("Your address: %s", log_strdup(net_addr_ntop(AF_INET, &iface->config.dhcpv4.requested_ip, buf, sizeof(buf)))); LOG_INF("Lease time: %u seconds", iface->config.dhcpv4.lease_time); LOG_INF("Subnet: %s", log_strdup(net_addr_ntop(AF_INET, &iface->config.ip.ipv4->netmask, buf, sizeof(buf)))); LOG_INF("Router: %s", log_strdup(net_addr_ntop(AF_INET, &iface->config.ip.ipv4->gw, buf, sizeof(buf)))); } void main(void) { struct net_if *iface; /* Registra o callback responsavel por capturar eventos * da stack tcp/ip */ net_mgmt_init_event_callback(&dhcp_cb, handler_cb, NET_EVENT_IPV4_DHCP_BOUND); net_mgmt_add_event_callback(&dhcp_cb); /* Pede a interface de rede padrao da stack TCP/IP * Nesse caso o WiFI do esp32 */ iface = net_if_get_default(); if (!iface) { LOG_ERR("wifi interface not available"); return; } /* Nessa demo, vamos pedir um endereço IP pelo DHCP */ net_dhcpv4_start(iface); /* As linhas abaixo referem-se a configuração do * wifi em termos de ssid e senha */ if (!IS_ENABLED(CONFIG_ESP32_WIFI_STA_AUTO)) { wifi_config_t wifi_config = { .sta = { .ssid = CONFIG_ESP32_WIFI_SSID, .password = CONFIG_ESP32_WIFI_PASSWORD, }, }; /* Finalmente chamamos as funções especificas do * driver de wifi do ESP32 */ esp_err_t ret = esp_wifi_set_mode(WIFI_MODE_STA); /* configuramos */ ret |= esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config); /* e pedimos a conexao para o AP desejado */ ret |= esp_wifi_connect(); if (ret != ESP_OK) { LOG_ERR("connection failed"); } } } |
Agora temos todo o projeto pronto para ser compilado, e pronto para uso, lembrando que a partir desse ponto outros arquivos C poderiam ser adicionados bastando alterar o CMakelists.txt.
Antes de tudo, como o driver WIFI do ESP32 interage com o Zephyr:
Antes de partirmos para programar o nosso ESP32, vamos verificar rapidamente como a stack WIFI do chip da Espressif interage com o restante do RTOS. Como já dito antes o Zephyr é organizado em grupos dentre eles podemos citar os notáveis: kernel, drivers e subsistemas, a stack TCP/IP do zephyr é considerado um subsistema, pois embora pertença ao RTOS ela possui um propósito específico.
A stack de rede do Zephyr possui pontos que são comuns, e conectados aos drivers através de uma interface de abstração. Essa interface por sua vez é dividida por tecnologias, possuindo implementações comuns entre uma dada tecnologia de rede (ex.: CAN, Bluetooth, WIFI), no nível mas baixo existem as implementações dependente de plataforma como exemplificados pelo layer Network Device Drivers. Esse layer contém as devidas implementações onde dentre elas encontra-se um driver de WIFI baseada na stack distribuida pela Espressif para os chips ESP32.
O adaptador de rede acaba sendo desenvolvido em duas partes, sendo uma localizada na árvore do Zephyr, e outra no módulo hal do ESP32, onde são colocadas as adaptações entre o código feito para o ESP-IDF e a forma como o Zephyr implementa um dado driver.
O resultado final disso é a identificação do ESP32 como sendo uma interface de rede nativa do Zephyr, que está ciente da existência do RTOS, como verificaremos na sessão a seguir.
Tudo pronto, hora de compilar mandar o app para dentro do ESP32
Com o ambiente preparado, agora vamos ver o resultado do funcionamento do WIFI do ESP32 pelo Zephyr, o primeiro ponto relevante a se lembrar é que o comando de build do Zephyr deve ser executado dentro do diretório do seu projeto.
Em seguida prepare o ambiente o ambiente, navegue até o diretório onde sua cópia do Zephyr está em seguida:
1 |
$ west zephyr-export |
Agora vá para o diretório do seu projeto e exporte as variáveis de ambiente do Zephyr:
1 2 3 |
$ export ZEPHYR_TOOLCHAIN_VARIANT="espressif" $ export ESPRESSIF_TOOLCHAIN_PATH="${HOME}/.espressif/tools/xtensa-esp32-elf/esp-2020r2-8.2.0/xtensa-esp32-elf/" $ export PATH=$PATH:$ESPRESSIF_TOOLCHAIN_PATH/bin |
Com isso, conecte sua placa ESP32 na porta usb do seu computador, e execute o seguinte comando para compilar a aplicação:
1 |
$ west build -besp32 |
Se a compilação terminar com sucesso você deve ver algo parecido no terminal:
1 2 3 4 5 6 7 8 9 10 11 |
[324/324] Linking C executable zephyr/zephyr.elf Memory region Used Size Region Size %age Used iram0_0_seg: 82188 B 128 KB 62.70% irom0_0_seg: 246918 B 3342304 B 7.39% dram0_0_seg: 121456 B 180736 B 67.20% dram0_1_seg: 90768 B 113840 B 79.73% drom0_0_seg: 46476 B 4194272 B 1.11% rtc_iram_seg: 0 GB 8 KB 0.00% rtc_slow_seg: 0 GB 4 KB 0.00% IDT_LIST: 0 GB 8 KB 0.00% esptool.py v3.0 |
Um lembrete importante, caso queira distribuir os binários da sua aplicação para outras pessoas, os arquivos para gravar o ESP32 estão localizados no diretório build/zephyr possuindo as extensões .bin e .elf para uso em debug.
Agora grave o microcontrolador e acesse os logs com a ferramenta de terminal serial de sua preferência, no meu caso eu prefiro a picocom por ser super simples de usar:
1 |
$ sudo apt install picocom |
E finalmente o comando de flash:
1 |
$ west flash && picocom -b 115200 /dev/ttyUSB0 |
Você deve ver algo do tipo se o comando der certo:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
-- west flash: rebuilding ninja: no work to do. -- west flash: using runner esp32 -- runners.esp32: Flashing ESP32 on /dev/ttyUSB0 (921600bps) esptool.py v3.0 Serial port /dev/ttyUSB0 Connecting...... Chip is ESP32-D0WD (revision 1) Features: WiFi, BT, Dual Core, 240MHz, VRef calibration in efuse, Coding Scheme None Crystal is 40MHz MAC: ac:67:b2:6f:9f:ec Uploading stub... Running stub... Stub running... Changing baud rate to 921600 Changed. Configuring flash size... Auto-detected Flash size: 4MB Flash params set to 0x0220 Wrote 32768 bytes at 0x00001000 in 0.5 seconds (558.1 kbit/s)... Hash of data verified. Wrote 16384 bytes at 0x00008000 in 0.2 seconds (703.0 kbit/s)... Hash of data verified. Wrote 393216 bytes at 0x00010000 in 5.0 seconds (631.4 kbit/s)... Hash of data verified. |
E por fim temos o WIFI mostrando funcionamento pelo terminal serial:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
*** Booting Zephyr OS build v2.6.0-rc2-39-g94e8c2eb81f3 *** I (917) wifi:mode : sta (ac:67:b2:6f:9f:ec) [00:00:00.922,000] <inf> esp32_wifi: WIFI_EVENT_STA_START I (2970) wifi:new:<13,0>, old:<1,1>, ap:<255,255>, sta:<13,0>, prof:1 I (3617) wifi:state: init -> auth (b0) I (3624) wifi:state: auth -> assoc (0) I (3632) wifi:state: assoc -> run (10) I (3646) wifi:connected with robot, aid = 2, channel 13, BW20, bssid = 1c:3b:f3:bc:ec:7c I (3646) wifi:security: WPA2-PSK, phy: bgn, rssi: -27 I (3647) wifi:pm start, type: 1 I (3731) wifi:AP's beacon interval = 102400 us, DTIM period = 1 [00:00:03.651,000] <inf> esp32_wifi: WIFI_EVENT_STA_CONNECTED [00:00:05.939,000] <inf> net_dhcpv4: Received: 192.168.0.100 [00:00:05.939,000] <inf> esp32_wifi_sta: Your address: 192.168.0.100 [00:00:05.939,000] <inf> esp32_wifi_sta: Lease time: 7200 seconds [00:00:05.939,000] <inf> esp32_wifi_sta: Subnet: 255.255.255.0 [00:00:05.939,000] <inf> esp32_wifi_sta: Router: 192.168.0.1 |
Se quiser, tente dar um ping no seu ESP32 por qualquer outro computador conectado à mesma rede por exemplo:
1 2 3 4 5 6 7 |
ulipe@pop-os:~/espressif_work/esp32_sta_wifi_out_of_tree$ ping 192.168.0.100 PING 192.168.0.100 (192.168.0.100) 56(84) bytes of data. 64 bytes from 192.168.0.100: icmp_seq=1 ttl=64 time=125 ms 64 bytes from 192.168.0.100: icmp_seq=2 ttl=64 time=44.4 ms 64 bytes from 192.168.0.100: icmp_seq=3 ttl=64 time=65.5 ms 64 bytes from 192.168.0.100: icmp_seq=4 ttl=64 time=83.9 ms 64 bytes from 192.168.0.100: icmp_seq=5 ttl=64 time=197 ms |
Conclusão
O ESP32 tem ganhado suporte a diferentes projetos de código aberto, além do próprio ESP-IDF, e com o Zephyr RTOS não foi diferente, o que beneficia o usuário do chip de poder ter a flexibilidade para selecionar os componentes de software que mais se adequam a realidade da aplicação a ser desenvolvida. No Zephyr, o suporte dos chips da Espressif tem crescido com boa consistência trazendo suporte às funcionalidades básicas em conjunto com os periféricos mais interessantes como WIFI e Bluetooth.
Espero que esse artigo encoraje você, leitor, a partir desse exemplo, iniciar com aplicações mais próximas do uso real desses chips como conectá-lo ao broker MQTT de sua preferência. Como sempre dúvidas e questionamentos são sempre bem vindos, e fiquem ligados, o suporte de chips da Espressif no projeto Zephyr só tende a crescer.
Referências
[1] Projeto Zephyr: https://www.zephyrproject.org/
[2] ESP32 – Zephyr: https://docs.zephyrproject.org/latest/boards/xtensa/esp32/doc/index.html
[3] Zephyr network stack architecture: https://docs.zephyrproject.org/latest/guides/networking/net-stack-architecture.html
[4] Projeto exemplo desse artigo no github:https://github.com/uLipe/esp32_sta_wifi_out_of_tree
É possível acessar o dado de RF do WIFI a partir do Zephyr? Pergunto isso porque um módulo esp32 com essa opção poderia virar um SDR transceptor de baixo custo.
olá Felipe.
Não consegui captar onde está o out-of-tree do projeto. Parece um projeto comum feito no zephyr.