Build Scratch Firmware and Configure IO Pins for ESP32
Build Scratch Firmware and Configure IO Pins for ESP32
Section titled “Build Scratch Firmware and Configure IO Pins for ESP32”Prerequisites
Section titled “Prerequisites”- Completed Scratch Visual Programming Basics with mBlock installed
- Arduino IDE with ESP32 Arduino Core installed
- ESP32 development board connected to the computer via USB
Key Concepts
Section titled “Key Concepts”What is the Firmata protocol? How does it differ from mBlock’s compile-and-upload approach?
mBlock works by: compiling blocks into Arduino C++ code → uploading to ESP32 → every modification requires re-compilation.
Firmata works differently: you flash a special “Firmata firmware” onto the ESP32 that communicates with the PC in real time over USB serial. The Scratch program on the PC sends Firmata commands, the ESP32 executes them and returns results — enabling real-time pin control without re-flashing.
| Comparison | mBlock Compile-and-Upload | Firmata Firmware |
|---|---|---|
| Requires compilation after changes | Yes, every time | No, takes effect in real time |
| Best for | Fixed-logic education | Repeated IO debugging |
| Runs offline | Yes | Requires continuous USB connection |
| Learning curve | Low | Medium |
When should I choose the Firmata approach?
- Repeatedly tuning sensor values or motor positions
- Needing real-time observation of pin state changes
- Workshops requiring quick hardware configuration changes
- Rapid IO iteration during prototype validation
Implementation Steps
Section titled “Implementation Steps”How do I install the ConfigurableFirmata firmware on ESP32?
- Open Arduino IDE
- Go to Sketch > Include Library > Manage Libraries
- Search for
ConfigurableFirmataand install it (by firmata) — the DHT sensor library dependency is installed automatically - Go to File > Examples > ConfigurableFirmata > ConfigurableFirmata to open the example sketch
Which feature modules can be enabled or disabled in the firmware?
Open ConfigurableFirmata.ino. At the top of the file, #define macros control feature modules:
/* Module selection: uncomment according to your project needs */#define FirmataSerial Serial // Use USB serial (default)// #define SERIAL_BAUD 115200 // Baud rate, default is 57600
#define DIGITAL_INPUT_PULLUP // Enable digital input with pull-up#define DIGITAL_INPUT // Enable digital input#define DIGITAL_OUTPUT // Enable digital output#define ANALOG_INPUT // Enable analog input#define ANALOG_OUTPUT // Enable PWM analog output// #define SERVO // Enable servo control// #define I2C // Enable I2C// #define STEPPER // Enable stepper motor// #define ONEWIRE // Enable OneWire (e.g. DS18B20)// #define DHT // Enable DHT temperature/humidity sensorFor most IoT projects, keeping DIGITAL_INPUT, DIGITAL_OUTPUT, and ANALOG_INPUT is sufficient. Uncomment additional modules only if your project uses motors or I2C peripherals.
How do I flash the firmware and verify that Scratch can control pins in real time?
- In Arduino IDE, select Tools > Board > ESP32 Dev Module
- Select the correct serial port and click Upload
- Open the Serial Monitor (baud rate 57600) — you should see Firmata startup messages
- In mBlock, select Devices > Arduino Uno, go to Connect and choose the corresponding port
- Drag a “set pin 2 to HIGH” block — the ESP32’s built-in LED should light up immediately, with no compilation wait
Pin Configuration
Section titled “Pin Configuration”How do I tell the Firmata firmware which pins connect to what?
The Firmata firmware does not know in advance which pins your project connects to which components. You need to explicitly declare each pin’s IO mode in the systemResetCallback() function using Firmata.setPinMode():
void systemResetCallback() { /* Configure pin modes according to your actual wiring below */
// ---- Digital Output ---- Firmata.setPinMode(2, PIN_MODE_OUTPUT); // LED indicator (GPIO 2) Firmata.setPinMode(16, PIN_MODE_OUTPUT); // Relay (GPIO 16) Firmata.setPinMode(17, PIN_MODE_OUTPUT); // Buzzer (GPIO 17)
// ---- Digital Input ---- Firmata.setPinMode(0, PIN_MODE_INPUT); // Button (GPIO 0, onboard button) Firmata.setPinMode(5, PIN_MODE_INPUT); // Limit switch (GPIO 5)
// ---- Analog Input (ADC) ---- Firmata.setPinMode(34, PIN_MODE_ANALOG); // Potentiometer (ADC1_CH6, GPIO 34) Firmata.setPinMode(35, PIN_MODE_ANALOG); // Photoresistor (ADC1_CH7, GPIO 35) Firmata.setPinMode(36, PIN_MODE_ANALOG); // Analog sensor (ADC1_CH0, GPIO 36 — SVP) Firmata.setPinMode(39, PIN_MODE_ANALOG); // Analog sensor (ADC1_CH3, GPIO 39 — SVN)
// ---- PWM Output (LED dimming) ---- Firmata.setPinMode(4, PIN_MODE_PWM); // LED dimming (GPIO 4) Firmata.setPinMode(18, PIN_MODE_PWM); // Motor speed (GPIO 18) // ESP32 PWM note: Not all GPIOs support PWM // Recommended GPIOs: 2,4,5,12-19,21-23,25-27,32-33
// ---- Servo (uncomment #define SERVO above first) ---- // Firmata.setPinMode(13, PIN_MODE_SERVO); // Servo signal wire (GPIO 13) // Firmata.setPinMode(14, PIN_MODE_SERVO); // Servo signal wire (GPIO 14)
// ---- I2C (uncomment #define I2C above first) ---- // Wire.begin(); // Default SDA=GPIO21, SCL=GPIO22}After configuration, recompile and upload. The Scratch side only needs to use the corresponding pin blocks to control the hardware.
What limitations do ESP32 ADC pins have?
- GPIO 34-39 are input-only pins: They can only be used for analog input (
PIN_MODE_ANALOG) and cannot be set as digital outputs - ADC2 conflicts with Wi-Fi: GPIO 25-27 and 32-33 belong to ADC2, which is unavailable when Wi-Fi is enabled — prefer ADC1 (GPIO 32-36)
- GPIO 6-11 are occupied by Flash: These pins are connected to the ESP32’s external Flash — avoid using them as regular I/O
Can I set pin mode from Scratch blocks without modifying the firmware?
Some tools support setting pin mode at runtime from blocks:
when Arduino starts set pin 2 to OUTPUT ← Set mode at runtime (supported by some tools) set pin 2 to HIGH ← Turn on LEDHowever, this has limitations — some tools don’t support dynamic pin mode setting from blocks. Recommended practice: configure all pins once in systemResetCallback(), then just read/write from Scratch.
Can I configure pins from Python instead of Scratch?
Yes. Use Python + pymata4 to configure pins on the host side — no need to re-flash the ESP32 when changing pin assignments:
from pymata4 import pymata4
board = pymata4.Pymata4(com_port="/dev/cu.usbserial-XXXX")
# Configure pinsboard.set_pin_mode(2, board.OUTPUT) # LEDboard.set_pin_mode(0, board.INPUT) # Buttonboard.set_pin_mode(34, board.ANALOG) # Potentiometer
# Use themboard.digital_write(2, 1) # Turn on LEDvalue = board.analog_read(34) # Read potentiometerThis approach is suitable for advanced users who want pin configuration managed on the host side.
Complete example: how do I configure pins for a Factory Display project?
Assume a Factory Display ESP32 project with the following wiring:
| Component | GPIO | Type |
|---|---|---|
| Status LED | GPIO 2 | Digital Output |
| Display Backlight | GPIO 16 | PWM Output |
| Button 1 | GPIO 0 | Digital Input (pull-up) |
| Button 2 | GPIO 4 | Digital Input |
| Temperature Sensor (DS18B20) | GPIO 5 | OneWire |
| Potentiometer | GPIO 34 | Analog Input |
Corresponding systemResetCallback() configuration:
void systemResetCallback() { Firmata.setPinMode(2, PIN_MODE_OUTPUT); // Status LED Firmata.setPinMode(16, PIN_MODE_PWM); // Display backlight dimming Firmata.setPinMode(0, PIN_MODE_INPUT); // Button 1 (onboard pull-up) Firmata.setPinMode(4, PIN_MODE_INPUT); // Button 2 Firmata.setPinMode(5, PIN_MODE_INPUT); // Temperature sensor (OneWire) Firmata.setPinMode(34, PIN_MODE_ANALOG); // Potentiometer}Verification
Section titled “Verification”- ConfigurableFirmata example compiles and uploads successfully to the ESP32
- Serial Monitor (baud rate 57600) shows Firmata startup messages
- The correct IO pin modes are configured in
systemResetCallback() - mBlock connects to the ESP32 via Firmata and pin control blocks work in real time
Troubleshooting
Section titled “Troubleshooting”Scratch connects via Firmata but the ESP32 does not respond — what now?
Check in this order:
- Is the firmware flashed correctly? Open the Serial Monitor (57600) — you should see Firmata startup messages. If no output, the firmware may not be flashed properly
- Is the serial port occupied? Close all programs using the serial port (Arduino IDE Serial Monitor, other terminals, etc.)
- Does the baud rate match? The baud rate in mBlock must match the firmware setting (default 57600)
- Are the pins configured? Check that
Firmata.setPinMode()is called insystemResetCallback()for every pin you intend to use - Are you using restricted pins? GPIO 6-11 are connected to Flash, GPIO 34-39 are input-only — confirm your pins support the intended function
ADC2 pins return no values?
ADC2 (GPIO 25-27, 32-33) is unavailable when Wi-Fi is enabled. Move the analog sensor to an ADC1 pin (GPIO 32-36) to resolve this.
Best Practices
Section titled “Best Practices”- Use Firmata for real-time interaction scenarios: Far more efficient than repeated compile-upload cycles when debugging IO states
- Document pin configurations: Maintain a pin mapping table (Excel/Google Sheet or Markdown) that stays in sync with the
systemResetCallback()configuration - Distinguish development from delivery phases: Use Firmata + Scratch for rapid iteration during prototyping; switch to Arduino IDE or PlatformIO compiled firmware for the final product
Summary
Section titled “Summary”- Firmata firmware enables Scratch to control ESP32 pins in real time over USB, without repeated compile-upload cycles
- Use
Firmata.setPinMode()insidesystemResetCallback()to pre-configure each pin’s IO mode - ESP32 ADC pins have limitations: GPIO 34-39 are input-only, ADC2 is unavailable with Wi-Fi
- Python/pymata4 can configure pins on the host side — no need to re-flash the ESP32 for changes
- Maintain a pin mapping document and keep it in sync with the firmware configuration
References
Section titled “References”- ConfigurableFirmata GitHub
- Firmata Protocol Official Site
- pymata4 - Python Firmata Client
- ESP32 GPIO Pin Reference
We provide ESP32 ODM design-to-manufacturing services. From prototype to production — the team behind this tutorial can build it with you.
Talk to us →