← All projects
Basics Intermediate

ESP32 or Arduino Uno: What Breaks When You Move a Sketch From One Board to the Other

The same `setup()` and `loop()`, but ints of different sizes, a 1023 ADC against a 4095 one, 5 V against 3.3 V, and no printf. Twelve differences that make a sketch from the internet fail to compile or quietly misbehave — and how to fix them.

Difficulty
Intermediate
Time
30 min
Category
Basics
Updated

Why it matters

Most examples on the internet are written for an Arduino Uno, while projects are more and more often built on an ESP32 — and the other way round: someone takes a ready ESP32 sketch and flashes it onto a Nano. The language is the same and the functions look alike, but the boards are very different. Below are the differences that break sketches most often, from compile errors to silent bugs.

A quick comparison

Arduino Uno (ATmega328P) ESP32
Core 8-bit, 16 MHz 32-bit, 2 × 240 MHz
RAM 2 KB 320 KB (+ PSRAM)
Logic 5 V 3.3 V
ADC 10-bit, 0–1023, linear 12-bit, 0–4095, non-linear
PWM analogWrite() only on ~ pins LEDC on any output
Interrupts D2 and D3 only any GPIO
Wi-Fi / Bluetooth none yes

The language: int, double and printf

  1. int is 16 bits on AVR. int x = 30000; x += 5000; gives −30536 on an Uno and 35000 on an ESP32. Use long / unsigned long or int32_t for millis, counters and products. 60 * 1000 is especially sneaky — on an Uno it already overflows: write 60000UL.
  2. double is float on AVR. Only 6–7 significant digits. On an ESP32 double is a real 64-bit type.
  3. No Serial.printf() on AVR. ESP32 sketches with printf do not compile on an Uno. Replace it with a chain of Serial.print(), or use snprintf() into a buffer.
  4. %f does not work in AVR sprintf — it prints ? instead of the number. For decimals use dtostrf(value, width, digits, buf).

The hardware: voltages and pins

  1. 5 V on an ESP32 input does damage. A sensor powered from 5 V that outputs 5 V (HC-SR04 ECHO, some relay modules) needs a divider or a level shifter.
  2. 3.3 V from an ESP32 may not be enough. 5 V modules (relays, HC-SR501, an LCD 1602) are unreliable from 3.3 V, and a 3.3 V logic "one" is sometimes not recognised by 5 V logic.
  3. The ADC: 1023 vs 4095. map(analogRead(A0), 0, 1023, …) gives four times too much on an ESP32, and the reverse on an Uno. The ESP32 ADC is also non-linear near its ends — for accuracy there is analogReadMilliVolts(), which AVR does not have.
  4. PWM. The ESP32 3.x core has analogWrite() too, but for frequency and resolution use ledcAttach(pin, freq, bits) and ledcWrite(pin, duty). On an Uno PWM exists only on 3, 5, 6, 9, 10 and 11, at a fixed 490 Hz (980 Hz on 5 and 6). analogWrite() on a pin without ~ simply switches it fully on or off.
  5. Interrupts. On an Uno attachInterrupt() works only for D2 and D3, and its first argument is the interrupt number — so write digitalPinToInterrupt(pin), not just pin. On an ESP32 the handler is marked IRAM_ATTR; AVR has no such keyword.
  6. Pin numbers. LED_BUILTIN is 13 on an Uno and 2 on an ESP32 DevKit. I2C is A4/A5 on an Uno and 21/22 on an ESP32; SPI is 13/12/11/10 against 18/19/23/5.

Memory and libraries

  1. 2 KB of RAM. A 128×64 OLED buffer alone is 1 KB, half of an Uno's memory. Big Strings, arrays and libraries that run "easily" on an ESP32 overflow the stack on an Uno without any message — the board just resets. Keep string constants in flash: Serial.println(F("text")).
  2. Single-platform libraries. WiFi.h, Preferences.h, ESP32Servo.h and TFT_eSPI do not exist on AVR. On an Uno use EEPROM.h instead of Preferences and Servo.h instead of ESP32Servo. And the reverse: libraries that poke AVR registers (TimerOne, SoftwareSerial in old versions) do not compile on an ESP32; there you have HardwareSerial Serial2 and hardware timers.

Try it in the simulator

The simulator reproduces all of these differences. Pick a board in the list next to the examples, and the example opens already adapted to it. Compare, for example, potentiometer and PWM on an ESP32 with the same example on an Uno: ledcWrite became analogWrite, 4095 became 1023, and printf a chain of print. Try writing Serial.printf() for the Uno yourself — the compiler tells you what to use instead.