Do I have to use the default SPI/I2C/UART pins when connecting modules to my board?
No, you don't have to use the default SPI, I2C and UART pins marked on the pinout card and board header labels.
I2C and SPI pins have chosen defaults because in the Arduino IDE and CircuitPython, you can just create an I2C instance (for example), without passing in the IO and it's still required to work, so the defaults are marked on the pinout card.
However, you can use any free IO on the headers for these protocols. The ESP32 chip internally reroutes them to maintain hardware peripheral functionality (assuming you haven't exceeded each peripheral's hardware limits).
When using non-default pins, pass the new IO pins in the constructor to specify custom pins instead of defaults.
UART pins also have Arduino defaults, but you must initialise which IO to use when creating your UART instance. For example, to use IO10 as RX and IO11 as TX in Arduino:
Serial1.begin(9600, SERIAL_8N1, 10, 11);
For SPI chip select (CS) pins, you can connect that to any free IO on your board and update your code accordingly.
Hardware Peripheral Availability
The number of available hardware peripherals varies by chip:
| Peripheral | ESP32 | ESP32-S2 | ESP32-S3 |
|---|---|---|---|
| SPI | 3 | 3 | 3 |
| I2C | 2 | 2 | 2 |
| UART | 3 | 2 | 3 |