0% acharam este documento útil (0 voto)
2 visualizações14 páginas

Tutorial ESP32S3 Rust MicroPython

Este documento é um tutorial abrangente que compara o uso de MicroPython e Rust no desenvolvimento de firmware para a placa ESP32-S3. Ele aborda desde a configuração do ambiente até a implementação de projetos práticos, como controle de LED, leitura de sensores I2C, e conectividade Wi-Fi. O material é voltado para programadores que desejam transitar de Python para Rust, enfatizando as diferenças de abordagem entre as duas linguagens.
Direitos autorais
© All Rights Reserved
Levamos muito a sério os direitos de conteúdo. Se você suspeita que este conteúdo é seu, reivindique-o aqui.
Formatos disponíveis
Baixe no formato PDF, TXT ou leia on-line no Scribd
0% acharam este documento útil (0 voto)
2 visualizações14 páginas

Tutorial ESP32S3 Rust MicroPython

Este documento é um tutorial abrangente que compara o uso de MicroPython e Rust no desenvolvimento de firmware para a placa ESP32-S3. Ele aborda desde a configuração do ambiente até a implementação de projetos práticos, como controle de LED, leitura de sensores I2C, e conectividade Wi-Fi. O material é voltado para programadores que desejam transitar de Python para Rust, enfatizando as diferenças de abordagem entre as duas linguagens.
Direitos autorais
© All Rights Reserved
Levamos muito a sério os direitos de conteúdo. Se você suspeita que este conteúdo é seu, reivindique-o aqui.
Formatos disponíveis
Baixe no formato PDF, TXT ou leia on-line no Scribd

ESP32-S3 com Rust e

MicroPython
Tutorial completo, comparativo e prático

Material orientado para quem já programa em Python e quer migrar para firmware profissional em Rust, usando
ESP32-S3.
1. Visão geral do ecossistema
O ESP32-S3 é uma placa excelente para estudar embarcados modernos porque reúne GPIO,
ADC, PWM, I2C, SPI, UART, Wi-Fi, BLE e USB nativos numa plataforma barata e muito
documentada. A ideia deste material é te mostrar o mesmo problema resolvido com duas
mentalidades: MicroPython para validação rápida e Rust para firmware robusto.

Figura 1 - Comparação de mentalidade entre MicroPython e Rust no ESP32-S3.

Quando escolher cada abordagem


 MicroPython: ideal para validar pinagem, testar sensor, descobrir endereço I2C, confirmar
alimentação e prototipar rápido.
 Rust com esp-hal: ideal para firmware bare-metal, previsível, com controle fino de
periféricos.
 Rust com esp-idf-svc: ideal quando Wi-Fi, MQTT, HTTP, NVS e OTA entram forte no projeto.

2. Placa, pinagem e cuidados reais


Antes de escrever qualquer linha de código, confira três coisas: alimentação, tensão lógica e
pinos realmente livres. No ESP32-S3, alguns pinos têm função especial na placa de
desenvolvimento e alguns podem ficar ligados ao subsistema de flash/PSRAM, dependendo do
módulo.

 Trabalhe sempre em 3,3 V na lógica do ESP32-S3.


 Não aplique 5 V em GPIO nem em ADC.
 Evite usar GPIO19/GPIO20 se estiver usando USB Serial/JTAG nativo.
 Confirme no guia da sua placa quais pinos estão livres no header.
Figura 2 - Visão esquemática de uma DevKit ESP32-S3 e pontos que mais importam no início.

Checklist de bancada
 Cabo USB de dados, não apenas de carga.
 Protoboard, jumpers, resistor de 220 ohms para LED e um botão NA.
 Sensor I2C simples como BME280 ou AHT20.
 Display OLED SSD1306 I2C opcional, mas muito didático.
 GPS UART opcional para o capítulo de serial.

3. Preparando o ambiente no Windows


3.1 MicroPython
 Baixe o firmware correto da variante ESP32_GENERIC_S3 ou da placa equivalente.
 Grave o firmware com esptool ou utilitário semelhante.
 Acesse REPL por porta serial para validar que a placa está viva.
 Use Thonny, mpremote ou terminal serial para subir scripts.

# Exemplo de gravação com esptool (ajuste a porta COM e o arquivo .bin)


[Link] --chip esp32s3 --port COM5 erase_flash
[Link] --chip esp32s3 --port COM5 --baud 460800 write_flash -z 0x0
ESP32_GENERIC_S3.bin

3.2 Rust no ESP32-S3


No ESP32-S3, o caminho mais estável é instalar o toolchain com suporte Xtensa via espup, e
depois usar espflash para gravar a placa. Para projeto bare-metal, use esp-hal. Para Wi-Fi e
serviços de aplicação, use esp-idf-svc.

cargo install espup --locked


espup install
cargo install espflash --locked
cargo install cargo-generate
 No Windows, abra um novo terminal depois do espup para herdar o ambiente configurado.
 Para projeto bare-metal, a base mais segura é o template/examples do ecossistema esp-hal.
 Para projeto com ESP-IDF, o esp-idf-template reduz muito o atrito inicial.

4. Projeto 1 - LED e botão com debounce


Este é o projeto certo para começar porque ensina saída digital, entrada digital, pull-up e
tratamento de bounce. A mesma ligação serve para MicroPython e Rust.

Figura 3 - Ligação recomendada para LED externo e botão com pull-up interno.

Objetivo
 Ao pressionar o botão, alternar o estado do LED.
 Evitar múltiplos disparos causados pelo bounce mecânico.

MicroPython - versão completa


from machine import Pin
import time

led = Pin(2, [Link])


btn = Pin(0, [Link], Pin.PULL_UP)

estado_led = 0
ultimo_estado = 1
instante_mudanca = time.ticks_ms()
while True:
leitura = [Link]()

if leitura != ultimo_estado:
instante_mudanca = time.ticks_ms()

if time.ticks_diff(time.ticks_ms(), instante_mudanca) > 30:


if ultimo_estado == 1 and leitura == 0:
estado_led = 1 - estado_led
[Link](estado_led)

ultimo_estado = leitura
time.sleep_ms(5)
Leitura didática: o botão fica em nível alto por causa do pull-up. Ao pressionar, o pino é aterrado
e cai para 0. O atraso de 30 ms não é para 'deixar bonito'; ele existe para ignorar oscilações do
contato.

Rust com esp-hal - versão de estudo


#![no_std]
#![no_main]

use esp_backtrace as _;
use esp_hal::{
clock::CpuClock,
delay::Delay,
gpio::{Input, InputConfig, Level, Output, OutputConfig, Pull},
main,
};

#[main]
fn main() -> ! {
let config = esp_hal::Config::default().with_cpu_clock(CpuClock::max());
let peripherals = esp_hal::init(config);
let mut delay = Delay::new();

let mut led = Output::new(


peripherals.GPIO2,
Level::Low,
OutputConfig::default(),
);

let button = Input::new(


peripherals.GPIO0,
InputConfig::default().with_pull(Pull::Up),
);
let mut led_on = false;
let mut last = true;
let mut stable_count = 0u8;

loop {
let now = button.is_high();

if now == last {
if stable_count < 10 {
stable_count += 1;
}
} else {
stable_count = 0;
}

if stable_count == 5 && last && !now {


led_on = !led_on;
if led_on {
led.set_high();
} else {
led.set_low();
}
}

last = now;
delay.delay_millis(5);
}
}

O que você aprende aqui


 MicroPython te entrega o pino pronto para uso.
 Rust te obriga a converter o pino em um driver tipado de entrada ou saída.
 No Rust, ownership do periférico evita uso indevido e conflitos de inicialização.

5. Projeto 2 - Sensor I2C (BME280 ou AHT20)


Aqui a regra de ouro é simples: antes de tentar a biblioteca do sensor, prove que o barramento
está vivo. No I2C, a fase mais importante do bring-up é confirmar endereço, tensão, pull-up e
continuidade dos fios.
Figura 4 - Exemplo de barramento I2C compartilhando BME280 e OLED SSD1306.

MicroPython - primeiro passo: escanear o barramento


from machine import Pin, I2C
import time

i2c = I2C(0, scl=Pin(18), sda=Pin(17), freq=400000)

while True:
print("I2C scan:", [hex(x) for x in [Link]()])
[Link](2)
Se aparecer 0x76 ou 0x77, o BME280 provavelmente respondeu. Se aparecer 0x38, o AHT20
provavelmente respondeu. Se não aparecer nada, o erro normalmente é elétrico: alimentação
errada, fio trocado, GND ausente ou pinos incorretos.

MicroPython - leitura conceitual do sensor


# Exemplo didático: a forma exata depende da biblioteca instalada
# Supondo um driver BME280 em [Link]

import time
from machine import Pin, I2C
import bme280

i2c = I2C(0, scl=Pin(18), sda=Pin(17), freq=400000)


sensor = bme280.BME280(i2c=i2c)

while True:
temp, press, hum = [Link]
print("Temp:", temp, "Press:", press, "Umid:", hum)
[Link](1)

Rust - inicialização do barramento


#![no_std]
#![no_main]

use esp_backtrace as _;
use esp_hal::{
clock::CpuClock,
i2c::master::{Config as I2cConfig, I2c},
main,
};

#[main]
fn main() -> ! {
let config = esp_hal::Config::default().with_cpu_clock(CpuClock::max());
let peripherals = esp_hal::init(config);

let i2c = I2c::new(


peripherals.I2C0,
I2cConfig::default(),
)
.unwrap()
.with_sda(peripherals.GPIO17)
.with_scl(peripherals.GPIO18);

// Passe `i2c` para o driver do BME280/AHT20 compatível com embedded-hal.

loop {}
}
No Rust, o barramento vira um recurso tipado que você entrega a um driver de dispositivo. Essa
mudança de mentalidade é muito importante: em vez de pensar 'eu mando bytes na mão', você
passa a pensar 'eu uso um driver que encapsula o protocolo'.

Problemas clássicos em I2C


 SDA e SCL invertidos.
 Módulo alimentado em 5 V mas com pull-up inadequado para 3,3 V.
 Falta de GND comum.
 Biblioteca errada para o endereço real do módulo.
 Módulo com seletor de endereço soldado para outro valor.
6. Projeto 3 - OLED SSD1306
O OLED é excelente para aprender barramento compartilhado, buffer de imagem e atualização
periódica sem precisar abrir terminal serial o tempo inteiro.

MicroPython - exemplo completo


from machine import Pin, I2C
import ssd1306
import time

i2c = I2C(0, scl=Pin(18), sda=Pin(17), freq=400000)


oled = ssd1306.SSD1306_I2C(128, 64, i2c)

contador = 0
while True:
[Link](0)
[Link]("ESP32-S3", 0, 0)
[Link]("MicroPython", 0, 16)
[Link]("cont = {}".format(contador), 0, 32)
[Link]()
contador += 1
[Link](1)

Rust - raciocínio equivalente


// Esqueleto conceitual:
// 1) inicialize I2C
// 2) crie a interface para o display SSD1306
// 3) atualize o frame buffer
// 4) envie o buffer ao display

// No ecossistema Rust, procure crates compatíveis com embedded-hal


// como ssd1306 + embedded-graphics.
Para estudar, o importante é entender a separação: o barramento I2C pertence ao driver do
display, e o texto ou desenho pertence ao frame buffer. No Rust, essa fronteira costuma ficar
mais clara do que no MicroPython.

7. Projeto 4 - ADC com potenciômetro


Este projeto ensina leitura analógica e ruído. Ele parece simples, mas é o primeiro contato com
problemas que software sozinho não resolve.
Figura 5 - Ligação segura de um potenciômetro de 10k a 3,3 V para teste de ADC.

MicroPython - leitura direta


from machine import ADC, Pin
import time

adc = ADC(Pin(1))

while True:
print(adc.read_u16())
time.sleep_ms(200)

Rust - estrutura de estudo


// Fluxo típico no Rust:
// 1) inicialize a unidade ADC
// 2) configure o canal analógico (por exemplo GPIO1 em ADC1)
// 3) leia uma amostra
// 4) aplique filtragem se necessário

Filtro simples por média móvel


# MicroPython
amostras = [0] * 8
indice = 0

while True:
amostras[indice] = adc.read_u16()
indice = (indice + 1) % len(amostras)
media = sum(amostras) // len(amostras)
print("filtrado:", media)
A grande lição aqui é que 'ler ADC' não é o desafio principal. O desafio real é tratar ruído, usar
referência coerente e respeitar o range elétrico da entrada.

8. Projeto 5 - PWM para LED e servo


PWM é o momento em que muita gente percebe a diferença entre API fácil e hardware real. No
MicroPython você aplica PWM ao pino. No hardware, por baixo, existe timer + canal + saída.

MicroPython - dimmer de LED


from machine import Pin, PWM
import time

pwm = PWM(Pin(2), freq=1000, duty_u16=0)

while True:
for d in range(0, 65535, 2000):
pwm.duty_u16(d)
time.sleep_ms(15)
for d in range(65535, 0, -2000):
pwm.duty_u16(d)
time.sleep_ms(15)

Servo - ideia prática


 Freqüência típica: 50 Hz.
 Pulso mínimo aproximado: 1,0 ms.
 Centro aproximado: 1,5 ms.
 Pulso máximo aproximado: 2,0 ms.

No Rust, use o periférico de PWM entendendo a relação entre timer, frequência e duty cycle.
Isso melhora muito quando você precisa controlar mais de um canal sem bagunçar a
frequência.

9. Projeto 6 - UART com GPS


UART é um ótimo projeto para consolidar pinos, baud rate, fluxo de bytes e parsing. O exemplo
mais didático é um GPS NMEA.
Figura 6 - Ligação UART cruzando TX e RX entre ESP32-S3 e módulo GPS.

MicroPython - leitura simples


from machine import UART
import time

uart = UART(1, baudrate=9600, tx=17, rx=18)

while True:
if [Link]():
linha = [Link]()
if linha:
print(linha)
time.sleep_ms(100)

Rust - ideia equivalente


// No Rust:
// 1) configure UART1 ou UART0
// 2) associe TX e RX aos GPIOs
// 3) leia o buffer serial
// 4) faça parsing das sentenças NMEA ($GPGGA, $GPRMC, etc.)
Aqui o Rust brilha quando você começa a escrever parser robusto, trabalhar com checksum e
transformar a serial em uma máquina de estados.
10. Projeto 7 - Wi-Fi STA
Neste ponto do curso, a recomendação mais prática é: faça o primeiro teste de rede em
MicroPython, depois migre para Rust com esp-idf-svc se o projeto realmente for conectado.

MicroPython - conexão STA


import network
import time

SSID = "SEU_WIFI"
SENHA = "SUA_SENHA"

wlan = [Link]()
[Link](True)
[Link](SSID, SENHA)

while not [Link]():


print("Conectando...")
time.sleep_ms(300)

print("Conectado:", [Link]())

Rust com esp-idf-svc - fluxo mental


// Estrutura típica de um projeto com esp-idf-svc:
// 1) Peripherals::take()
// 2) criar event loop
// 3) abrir NVS padrão
// 4) criar EspWifi
// 5) aplicar ClientConfiguration
// 6) start(), connect(), wait_netif_up()
Quando a conectividade entra em cena, o esp-idf-svc compensa porque já embrulha serviços
importantes como Wi-Fi, HTTP, MQTT, NVS e OTA.

11. Projeto 8 - BLE e rádio


No ESP32-S3, BLE abre caminho para beacon, provisionamento e troca de dados locais. Para
prototipar comportamento, MicroPython é confortável. Para firmware bare-metal com rádio, o
crate esp-radio é o caminho atual no ecossistema Rust.

12. Como migrar um projeto de MicroPython para Rust


Etapa Em MicroPython Em Rust

Testar ligações, endereços Repetir a mesma ligação já


Bring-up elétrico
I2C, resposta serial validada
Usar Pin/I2C/UART/PWM Converter pinos e periféricos
Periférico
diretamente em drivers tipados

Mais rigoroso em compile


Tratamento de erro Mais flexível em runtime
time

Escalabilidade Ótimo para prova de conceito Melhor para firmware final

Regra prática que funciona muito bem: valide hardware em MicroPython, congele a pinagem e
só então porte a lógica estável para Rust.

13. Estrutura recomendada de estudo


 Semana 1: LED, botão e UART.
 Semana 2: I2C com scan, sensor e OLED.
 Semana 3: ADC, PWM e servo.
 Semana 4: Wi-Fi, HTTP/MQTT e persistência.
 Semana 5: portar os dois primeiros projetos de MicroPython para Rust.

14. Checklist de depuração


 A placa aparece na porta COM correta?
 O cabo USB transporta dados?
 Existe GND comum entre todos os módulos?
 A tensão do módulo é realmente 3,3 V?
 Os GPIO escolhidos não conflitam com USB/flash/PSRAM?
 No I2C, o scan encontra algum endereço?
 No UART, TX e RX estão cruzados corretamente?
 No ADC, o sinal está dentro do range e sem 5 V?

15. Conclusão
MicroPython e Rust não competem; eles se complementam muito bem no ESP32-S3. Use
MicroPython para aprender o hardware rápido. Use Rust para consolidar o hardware
corretamente. Quando você adota essa estratégia, o desenvolvimento fica mais rápido, o
firmware fica mais confiável e a migração deixa de ser dolorosa.

Apêndice - Referências oficiais para continuar


 Rust on ESP Book - toolchain, async, visão geral do ecossistema.
 esp-hal - documentação e exemplos da HAL bare-metal.
 ESP-IDF Programming Guide - GPIO, ADC, LEDC/PWM, USB Serial/JTAG.
 ESP32-S3 DevKitC-1 User Guide e datasheet do ESP32-S3.
 MicroPython - quick reference do ESP32, machine.I2C, [Link], tutorial PWM, tutorial
inicial do ESP32.
 esp-idf-svc - wrappers de Wi-Fi, HTTP, MQTT, NVS e OTA.
 esp-radio - Wi-Fi, BLE e ESP-NOW no ecossistema bare-metal.

Você também pode gostar