#esp32s3 — Public Fediverse posts
Live and recent posts from across the Fediverse tagged #esp32s3, aggregated by home.social.
-
Erste Schritte mit #eInk #Display und homeassistant. Daten drauf zu malen sieht aber nach ner yaml Hölle aus. @schlomo hat wohl nen grafischen yaml generator dafür gebaut aber das schau ich mir an nem anderen Abend an.
Triggert schon sehr #micropython auch mal drauf los zu lassen. Leider ist als controller ein #esp32s3 drauf und nichts stromsparenderes. Wird vermutlich aber eh auf dem Schreibtisch einen Platz finden. -
Erste Schritte mit #eInk #Display und homeassistant. Daten drauf zu malen sieht aber nach ner yaml Hölle aus. @schlomo hat wohl nen grafischen yaml generator dafür gebaut aber das schau ich mir an nem anderen Abend an.
Triggert schon sehr #micropython auch mal drauf los zu lassen. Leider ist als controller ein #esp32s3 drauf und nichts stromsparenderes. Wird vermutlich aber eh auf dem Schreibtisch einen Platz finden. -
Erste Schritte mit #eInk #Display und homeassistant. Daten drauf zu malen sieht aber nach ner yaml Hölle aus. @schlomo hat wohl nen grafischen yaml generator dafür gebaut aber das schau ich mir an nem anderen Abend an.
Triggert schon sehr #micropython auch mal drauf los zu lassen. Leider ist als controller ein #esp32s3 drauf und nichts stromsparenderes. Wird vermutlich aber eh auf dem Schreibtisch einen Platz finden. -
Erste Schritte mit #eInk #Display und homeassistant. Daten drauf zu malen sieht aber nach ner yaml Hölle aus. @schlomo hat wohl nen grafischen yaml generator dafür gebaut aber das schau ich mir an nem anderen Abend an.
Triggert schon sehr #micropython auch mal drauf los zu lassen. Leider ist als controller ein #esp32s3 drauf und nichts stromsparenderes. Wird vermutlich aber eh auf dem Schreibtisch einen Platz finden. -
Erste Schritte mit #eInk #Display und homeassistant. Daten drauf zu malen sieht aber nach ner yaml Hölle aus. @schlomo hat wohl nen grafischen yaml generator dafür gebaut aber das schau ich mir an nem anderen Abend an.
Triggert schon sehr #micropython auch mal drauf los zu lassen. Leider ist als controller ein #esp32s3 drauf und nichts stromsparenderes. Wird vermutlich aber eh auf dem Schreibtisch einen Platz finden. -
Reflective LCD Slabtop Terminal Runs Homebrewed Solar OS
-
Each #MeshNetworking radio test cycle requires rebuilding and uploading separate #ESP32S3 firmware images 4 each #TBeamSupreme, because each unit has different blocker rules to simulate network topology.
Moving the compile step from my older Intel workstation to a Ryzen 7950 box cuts roughly 8–9 minutes from each iteration. That adds up fast when testing, retesting, and chasing radio anomalies.
https://salemdata.net/johnpress/?p=974
#Reticulum #PlatformIO #EmbeddedSystems #Forgejo #Gentoo #HardwareHacking
-
Each #MeshNetworking radio test cycle requires rebuilding and uploading separate #ESP32S3 firmware images 4 each #TBeamSupreme, because each unit has different blocker rules to simulate network topology.
Moving the compile step from my older Intel workstation to a Ryzen 7950 box cuts roughly 8–9 minutes from each iteration. That adds up fast when testing, retesting, and chasing radio anomalies.
https://salemdata.net/johnpress/?p=974
#Reticulum #PlatformIO #EmbeddedSystems #Forgejo #Gentoo #HardwareHacking
-
ESP-FLY micro drone kit offers ESP32-S3-based flight control and ESP-NOW support
-
Last week we exhibited at Embedded World in Nuremberg.
This video presents some of the demos from our booth, running on embedded devices with Slint 👇
https://www.youtube.com/shorts/3w64sO7fjFM
#embedded #Slint #EmbeddedWorld #RP2350 #ESP32 #ESP32S3 #ESP32P4 #Renesas #toradex
-
Last week we exhibited at Embedded World in Nuremberg.
This video presents some of the demos from our booth, running on embedded devices with Slint 👇
https://www.youtube.com/shorts/3w64sO7fjFM
#embedded #Slint #EmbeddedWorld #RP2350 #ESP32 #ESP32S3 #ESP32P4 #Renesas #toradex
-
Умная колонка своими руками
В этой статье я расскажу, как сделать своими руками две умные колонки, полностью поддерживающие русский язык: 1) На микроконтроллере esp32s3, используя XiaoZhi 2) На Raspberry Pi автономную голосовую колонку с камерой, которая будет работать и распознавать всё, что не только слышит, но и видит перед собой, даже при отсутствии Интернета! С локально запущенными моделями ИИ, связка Ollama+Gemma3:1b+Moondream+OpenWakeWord+Whisper.cpp+Silero TTS А также расскажу, как подключить обе эти колонки к Home Assistant для управления устройствами умного дома.
https://habr.com/ru/articles/1005272/
#xiaozhi #esp32s3 #голосовой_ассистент #whisper #silero #ollama #raspberrypi
-
Робот Xiaozhi: беседа двух роботов
Дополнение к моей предыдущей мини-статье по роботу Xiaozhi. Я заказал детали и комплектующие, чтобы собрать такого робота самостоятельно. Сборка данного робота не доставляет существенных проблем.
https://habr.com/ru/articles/996420/
#робот #Xiaozhi #esp32cam #esp32s3 #программирование_микроконтроллеров #искусственный_интеллект #голосовой_ассистент
-
Vorstellung des #LilyGo #TEnergy #ESP32S3 Boards mit integriertem 18650-Batteriehalter
--> https://cool-web.de/esp8266-esp32/review-lilygo-t-energy-s3-18650-battery.htm
#Espressif #ESP32 #Akku #LiIon #Batterie #Zelle #Stromversorgung #Elektronik #Maker #DIY #Mikrocontroller #MadeInChina #China #Chinatech
-
Vorstellung des #LilyGo #TEnergy #ESP32S3 Boards mit integriertem 18650-Batteriehalter
--> https://cool-web.de/esp8266-esp32/review-lilygo-t-energy-s3-18650-battery.htm
#Espressif #ESP32 #Akku #LiIon #Batterie #Zelle #Stromversorgung #Elektronik #Maker #DIY #Mikrocontroller #MadeInChina #China #Chinatech
-
Installation des 8-Channel-LoRaWAN-Gateway M2 Starter Kit von Seeed Studio
--> https://cool-web.de/lora/seeed-sensecap-m2-multi-channel-lorawan-indoor-gateway-installation.htm
#LoRa #LoRaWAN #Seeed #SenseCAP #M2 #Gateway #Sensoren #XIAO #ESP32S3 #DHT11 #Grove #Base #Shield #Wio #E5 #STM32 #EU868 #Funk #DIY #Elektronik #Maker #Mikrocontroller
-
Installation des 8-Channel-LoRaWAN-Gateway M2 Starter Kit von Seeed Studio
--> https://cool-web.de/lora/seeed-sensecap-m2-multi-channel-lorawan-indoor-gateway-installation.htm
#LoRa #LoRaWAN #Seeed #SenseCAP #M2 #Gateway #Sensoren #XIAO #ESP32S3 #DHT11 #Grove #Base #Shield #Wio #E5 #STM32 #EU868 #Funk #DIY #Elektronik #Maker #Mikrocontroller
-
Installation des 8-Channel-LoRaWAN-Gateway M2 Starter Kit von Seeed Studio
--> https://cool-web.de/lora/seeed-sensecap-m2-multi-channel-lorawan-indoor-gateway-installation.htm
#LoRa #LoRaWAN #Seeed #SenseCAP #M2 #Gateway #Sensoren #XIAO #ESP32S3 #DHT11 #Grove #Base #Shield #Wio #E5 #STM32 #EU868 #Funk #DIY #Elektronik #Maker #Mikrocontroller
-
Installation des 8-Channel-LoRaWAN-Gateway M2 Starter Kit von Seeed Studio
--> https://cool-web.de/lora/seeed-sensecap-m2-multi-channel-lorawan-indoor-gateway-installation.htm
#LoRa #LoRaWAN #Seeed #SenseCAP #M2 #Gateway #Sensoren #XIAO #ESP32S3 #DHT11 #Grove #Base #Shield #Wio #E5 #STM32 #EU868 #Funk #DIY #Elektronik #Maker #Mikrocontroller
-
Installation des 8-Channel-LoRaWAN-Gateway M2 Starter Kit von Seeed Studio
--> https://cool-web.de/lora/seeed-sensecap-m2-multi-channel-lorawan-indoor-gateway-installation.htm
#LoRa #LoRaWAN #Seeed #SenseCAP #M2 #Gateway #Sensoren #XIAO #ESP32S3 #DHT11 #Grove #Base #Shield #Wio #E5 #STM32 #EU868 #Funk #DIY #Elektronik #Maker #Mikrocontroller
-
Arduino with Multiple Displays – Part 3
Whilst messing around a little more with my Arduino with Multiple Displays – Part 2, I’ve optimised the code a little and found out a bit more about these displays!
In this part, I’m actually using a PCB that can hold four displays, powered by a Waveshare Zero device. More on that here: Waveshare Zero Multi Display PCB Design.
Warning! I strongly recommend using old or second hand equipment for your experiments. I am not responsible for any damage to expensive instruments!
These are the key Arduino tutorials for the main concepts used in this project:
- Arduino with Multiple Displays
- https://emalliab.wordpress.com/2025/07/19/small-microcontroller-displays/
If you are new to microcontrollers, see the Getting Started pages.
Parts list
- A Waveshare Zero format board or similar
- 4x 0.96″ ST7735 60×180 SPI TFT displays.
- Built Waveshare Zero Multi Display PCB
- Breadboard and jumper wires.
Recall that I’m using displays that look like this – note the order of the pins.
Although even with displays that look exactly the same, it appears there can be differences in how they are used software wise. More on that later.
The Circuit
For two displays, I can reuse the circuit from Arduino with Multiple Displays – Part 2. For more displays, it is possible to cascade more displays using jumper wires, but I’ve used my PCB.
The pins to be used for various Waveshare Zero boards is covered in part 2.
The Code
Whilst using these displays, I found that the colours can be inverted in some of them compared to others. Typically, I’ve found that I might have to use either of the following two options to drive them correctly:
tft.initR(INITR_MINI160x80);
tft.initR(INITR_MINI160x80_PLUGIN);These represent different Adafruit displays as before, but they generally work for me.
However there is another thing to watch out for. These displays are 16-bit colour displays, which means each colour value is a 16-bit word with red, green and blue elements represented by 5, 6 and 5 bits. This means two of the colours have a resolution of 0 to 31, and one has 0 to 63.
But the ordering seems different for different displays. The default Adafruit library appears to assume RGB ordering, but my displays seem to be BGR. This means that if I use the provided short-cuts for colours, the red and blue elements are swapped.
Consequently, I defined my own colours along with a macro to allow me to provide RGB values and turn it into the device-specific 16-bit value as required.
In the following, I define the bit-shift number for each of red, green and blue and the use that in a macro “ST_COL” shifting the value to the correct place in the 5-6-5 format. Red and blue are the 5-bit colours and green is the 6-bit colour, so in each case I take the most significant bits which means each colour can still be defined in terms of 0..255 RGB values.
// Format is 16-bit 5-6-5 B-G-R
// Allow 0..255 in component values, by only taking
// most significant bits (5 or 6) from each value.
// bbbbbggggggrrrrr
#define ST_COL(r,g,b) (((r&0xF8)>>3)|((g&0xFC)<<3)|((b&0xF8)<<8))
#define ST_BLACK ST_COL(0,0,0)
#define ST_GREY ST_COL(64,64,64)
#define ST_WHITE ST_COL(255,255,255)
#define ST_BLUE ST_COL(0,0,255)
#define ST_GREEN ST_COL(0,255,0)
#define ST_RED ST_COL(255,0,0)
#define ST_YELLOW ST_COL(255,255,0)
#define ST_MAGENTA ST_COL(255,0,255)
#define ST_CYAN ST_COL(0,255,255)I’m also building up to seeing if I can drive more than four displays, so I’ve also changed the code to allow me to iterate across a number of displays.
#define NUM_TFTS 4
int tftTypes[NUM_TFTS] = {
INITR_MINI160x80, INITR_MINI160x80,
INITR_MINI160x80, INITR_MINI160x80,
};
int tftCS[NUM_TFTS] = {SPI_SS, 6, 5, 4};
#define TFT_RST 7
#define TFT_DC 11
Adafruit_ST7735 *tft[NUM_TFTS];
void setup() {
int rstPin = TFT_RST;0
for (int i=0; i<NUM_TFTS; i++) {
tft[i] = new Adafruit_ST7735(&MySPI, tftCS[i], TFT_DC, rstPin);
rstPin = -1;
tft[i]->initR(tftTypes[i]);
tft[i]->setRotation(3);
tft[i]->fillScreen(ST_BLACK);
}
}
void loop() {
for (int i=0; i<NUM_TFTS; i++) {
unsigned long time = millis();
tft[i]->fillRect(10, 20, tft[i]->width(), 20, ST_BLACK);
tft[i]->setTextColor(ST_GREEN);
tft[i]->setCursor(10, 20);
tft[i]->print(i);
tft[i]->print(":");
tft[i]->print(time, DEC);
}
}Each instance of the display code is now created dynamically and stored in an array which can then be iterated over when it comes to putting things on each display.
Notice how the reset pin definition is set to -1 after the first initialisation. This ensures that subsequent instantiations won’t reset displays that have already been set up.
The final code actually allows up to eight displays to be included by setting NUM_TFTS at the top to two or four.
The GPIO usage being assumed is described here: Waveshare Zero Multi Display PCB Build Guide.
Closing Thoughts
Approaching the code in this way allows me to experiment more easily with more than four displays.
If my PCB works as I’m hoping I should be able to cascade them to get eight displays – assuming the Waveshare Zero is up to driving eight of course.
Kevin
#arduinoUno #define #esp32c3 #ESP32s3 #rp2040 #st7735 #tftDisplay #WaveshareZero
-
Arduino with Multiple Displays – Part 3
Whilst messing around a little more with my Arduino with Multiple Displays – Part 2, I’ve optimised the code a little and found out a bit more about these displays!
In this part, I’m actually using a PCB that can hold four displays, powered by a Waveshare Zero device. More on that here: Waveshare Zero Multi Display PCB Design.
Warning! I strongly recommend using old or second hand equipment for your experiments. I am not responsible for any damage to expensive instruments!
These are the key Arduino tutorials for the main concepts used in this project:
- Arduino with Multiple Displays
- https://emalliab.wordpress.com/2025/07/19/small-microcontroller-displays/
If you are new to microcontrollers, see the Getting Started pages.
Parts list
- A Waveshare Zero format board or similar
- 4x 0.96″ ST7735 60×180 SPI TFT displays.
- Built Waveshare Zero Multi Display PCB
- Breadboard and jumper wires.
Recall that I’m using displays that look like this – note the order of the pins.
Although even with displays that look exactly the same, it appears there can be differences in how they are used software wise. More on that later.
The Circuit
For two displays, I can reuse the circuit from Arduino with Multiple Displays – Part 2. For more displays, it is possible to cascade more displays using jumper wires, but I’ve used my PCB.
The pins to be used for various Waveshare Zero boards is covered in part 2.
The Code
Whilst using these displays, I found that the colours can be inverted in some of them compared to others. Typically, I’ve found that I might have to use either of the following two options to drive them correctly:
tft.initR(INITR_MINI160x80);
tft.initR(INITR_MINI160x80_PLUGIN);These represent different Adafruit displays as before, but they generally work for me.
However there is another thing to watch out for. These displays are 16-bit colour displays, which means each colour value is a 16-bit word with red, green and blue elements represented by 5, 6 and 5 bits. This means two of the colours have a resolution of 0 to 31, and one has 0 to 63.
But the ordering seems different for different displays. The default Adafruit library appears to assume RGB ordering, but my displays seem to be BGR. This means that if I use the provided short-cuts for colours, the red and blue elements are swapped.
Consequently, I defined my own colours along with a macro to allow me to provide RGB values and turn it into the device-specific 16-bit value as required.
In the following, I define the bit-shift number for each of red, green and blue and the use that in a macro “ST_COL” shifting the value to the correct place in the 5-6-5 format. Red and blue are the 5-bit colours and green is the 6-bit colour, so in each case I take the most significant bits which means each colour can still be defined in terms of 0..255 RGB values.
// Format is 16-bit 5-6-5 B-G-R
// Allow 0..255 in component values, by only taking
// most significant bits (5 or 6) from each value.
// bbbbbggggggrrrrr
#define ST_COL(r,g,b) (((r&0xF8)>>3)|((g&0xFC)<<3)|((b&0xF8)<<8))
#define ST_BLACK ST_COL(0,0,0)
#define ST_GREY ST_COL(64,64,64)
#define ST_WHITE ST_COL(255,255,255)
#define ST_BLUE ST_COL(0,0,255)
#define ST_GREEN ST_COL(0,255,0)
#define ST_RED ST_COL(255,0,0)
#define ST_YELLOW ST_COL(255,255,0)
#define ST_MAGENTA ST_COL(255,0,255)
#define ST_CYAN ST_COL(0,255,255)I’m also building up to seeing if I can drive more than four displays, so I’ve also changed the code to allow me to iterate across a number of displays.
#define NUM_TFTS 4
int tftTypes[NUM_TFTS] = {
INITR_MINI160x80, INITR_MINI160x80,
INITR_MINI160x80, INITR_MINI160x80,
};
int tftCS[NUM_TFTS] = {SPI_SS, 6, 5, 4};
#define TFT_RST 7
#define TFT_DC 11
Adafruit_ST7735 *tft[NUM_TFTS];
void setup() {
int rstPin = TFT_RST;0
for (int i=0; i<NUM_TFTS; i++) {
tft[i] = new Adafruit_ST7735(&MySPI, tftCS[i], TFT_DC, rstPin);
rstPin = -1;
tft[i]->initR(tftTypes[i]);
tft[i]->setRotation(3);
tft[i]->fillScreen(ST_BLACK);
}
}
void loop() {
for (int i=0; i<NUM_TFTS; i++) {
unsigned long time = millis();
tft[i]->fillRect(10, 20, tft[i]->width(), 20, ST_BLACK);
tft[i]->setTextColor(ST_GREEN);
tft[i]->setCursor(10, 20);
tft[i]->print(i);
tft[i]->print(":");
tft[i]->print(time, DEC);
}
}Each instance of the display code is now created dynamically and stored in an array which can then be iterated over when it comes to putting things on each display.
Notice how the reset pin definition is set to -1 after the first initialisation. This ensures that subsequent instantiations won’t reset displays that have already been set up.
The final code actually allows up to eight displays to be included by setting NUM_TFTS at the top to two or four.
The GPIO usage being assumed is described here: Waveshare Zero Multi Display PCB Build Guide.
Closing Thoughts
Approaching the code in this way allows me to experiment more easily with more than four displays.
If my PCB works as I’m hoping I should be able to cascade them to get eight displays – assuming the Waveshare Zero is up to driving eight of course.
Kevin
#arduinoUno #define #esp32c3 #ESP32s3 #rp2040 #st7735 #tftDisplay #WaveshareZero
-
Arduino with Multiple Displays – Part 2
As I mentioned in my last post on Arduino with Multiple Displays I’m going to look at other microcontrollers too. This post takes a wander through my Waveshare Zero and similar format boards that each support one of the RP2040, ESP32-C3 or ESP32-S3.
Warning! I strongly recommend using old or second hand equipment for your experiments. I am not responsible for any damage to expensive instruments!
These are the key Arduino tutorials for the main concepts used in this project:
- Arduino with Multiple Displays
- https://emalliab.wordpress.com/2025/07/19/small-microcontroller-displays/
If you are new to microcontrollers, see the Getting Started pages.
Parts list
- A Waveshare Zero format board or similar
- 2x 0.96″ ST7735 60×180 SPI TFT displays.
- Breadboard and jumper wires.
Once again I’m using displays that look like this – note the order of the pins.
The Circuit
All circuits are a variation on the above, requiring the following ideal connections:
DisplayFunctionRP2040ESP32-C3ESP32-S3BLKBacklight control
(not required)N/CN/CN/CCSChip select
One per display.5 or any SPI0 CS1010DCData/Command888RESReset1499SDAData (MOSI)3 or any SPI0 MOSI6 or 711SCLClock (SCLK)2 or any SPI0 SCLK4 or 612VCCPower3V33V33V3GNDGroundGNDGNDGNDFor the explanations of the pin choices, and what it means for the code, see the following sections.
ESP32-S3 Zero
In the Arduino IDE, using board ESP32-> Waveshare ESP32-S3-Zero.
There are several SPI buses on the ESP32-S3, but they have fixed uses as follows (see the ESP32-S3 Technical Reference Manual Chapter 30 “SPI Controller”):
- SPI 0: Reserved for internal use.
- SPI 1: Reserved for internal use.
- SPI 2: General purpose use – often called FSPI in the documentation.
- SPI 3: General purpose use – often called SPI or SPI3.
Sometimes the two SPI buses are called VSPI and HSPI but I think that is really terminology from the original ESP32 rather than the ESP32-S3.
The ESP32 Arduino core for the Waveshare ESP32-S3 Zero variant defines the following:
// Mapping based on the ESP32S3 data sheet - alternate for SPI2
static const uint8_t SS = 34; // FSPICS0
static const uint8_t MOSI = 35; // FSPID
static const uint8_t MISO = 37; // FSPIQ
static const uint8_t SCK = 36; // FSPICLKBy default the Adafruit libraries will use the boards default SPI interface, as defined in the variants.h file – i.e. the above.
When it comes to assigning SPI devices to GPIO there are a few considerations (see the “ESP32-S3 Technical Reference Manual, Chapter 6 “IO MUX and GPIO Matrix”):
- In general, any GPIO can be mapped onto any SPI function. However…
- Some GPIO have special “strapping” functions so are best avoided.
- Some GPIOs have a default SPI function that bypasses the GPIO MUX routing, so allows for better performance (see section 6.6 “Direct Input and Output via IO MUX”).
From my reading of the reference manual I believe the following are default “non-MUX” SPI connections:
In the previous table, where SPI3 is mentioned, then the entry for “Direct IO via IO MUX” is set to “no”, so I’m guessing that isn’t available.
But now we can see why the Arduino core is using GPIO 34-37, but we can also see that GPIO 10-13 would be an alternative (fast) option too.
The problem is that not all of GPIO 34-37 are broken out on a Waveshare ESP32-S3 Zero, so I need to use the alternative pinouts. Aside: this makes no sense to me that these are the defaults in the Waveshare ESP32-S3 Zero’s “variant.h” file, but anyway…
To use a different SPI interface requires using a constructor that passes in an initialised SPI instance. There is an example in the ESP32 core for setting up multiple SPI buses here: https://github.com/espressif/arduino-esp32/blob/master/libraries/SPI/examples/SPI_Multiple_Buses/SPI_Multiple_Buses.ino
This leads to the pins as defined in the previous table, and the code below to setup one of the displays.
#include <Adafruit_GFX.h> // Core graphics library
#include <Adafruit_ST7735.h> // Hardware-specific library for ST7735
#include <SPI.h>
#define SPI_SS 10
#define SPI_MOSI 11
#define SPI_SCLK 12
#define SPI_MISO 13
SPIClass MySPI(FSPI);
#define TFT_CS SPI_SS
#define TFT_RST 9
#define TFT_DC 8
Adafruit_ST7735 tft = Adafruit_ST7735(&MySPI, TFT_CS, TFT_DC, TFT_RST);
void setup() {
MySPI.begin(SPI_SCLK, SPI_MISO, SPI_MOSI, SPI_SS);
pinMode(SPI_SS, OUTPUT);
tft.initR(INITR_MINI160x80_PLUGIN);
}ESP32-C3 Zero
In the Arduino IDE, using board ESP32-> ESP32C3 Dev Module.
Again there are several SPI buses on the ESP32-C3, with the same fixed uses as follows (see the ESP32-C3 Technical Reference Manual Chapter 30 “SPI Controller”):
- SPI 0: Reserved for internal use.
- SPI 1: Reserved for internal use.
- SPI 2: General purpose use – sometimes called GP-SPI in the documentation.
The ESP32-C3 also has a very similar SPI arrangement to the ESP32-S3, in that whilst any pin can be configured for SPI usage, there are certain hard-wired optional arrangements that bypass the GPIO routing matrix.
The faster (direct to IO MUX) pins are as follows (more here):
- CS0 – 10
- SCLK – 6
- MISO – 2
- MOSI – 7
Curiously, the general ESP32-C3 Arduino variant defines them as follows:
static const uint8_t SS = 7;
static const uint8_t MOSI = 6;
static const uint8_t MISO = 5;
static const uint8_t SCK = 4;From the Technical Reference manual, we can see that the default Arduino definitions above, do not support the non-routed, direct-to-IO MUX pin mappings, which from the table below do indeed map onto GPIO 2, 6, 7, 10.
In terms of using a Waveshare ESP32-C3 Zero, both combinations would be supported on the broken out GPIO, so from a software point of view, the Adafruit libraries could be used “as is” with the default mapping, or with a custom SPI definition (as shown above) with the more bespoke, but faster, mapping.
RP2040 Zero
This is using the (unofficial) RP2040 core from here: https://github.com/earlephilhower/arduino-pico, where this is an entry: RP2040 -> Waveshare RP2040 Zero.
The RP2040 has two SPI peripherals and the SPI functions are mapped onto specific sets of GPIO pins. This gives a range of flexibility, but not arbitrary flexibility. The board definition file for the Waveshare RP2040 Zero provides this as a default:
// SPI
#define PIN_SPI0_MISO (4u)
#define PIN_SPI0_MOSI (3u)
#define PIN_SPI0_SCK (2u)
#define PIN_SPI0_SS (5u)
#define PIN_SPI1_MISO (12u)
#define PIN_SPI1_MOSI (15u)
#define PIN_SPI1_SCK (14u)
#define PIN_SPI1_SS (13u)Note that the SPI1 pins for the Waveshare RP2040 Zero are not all on the standard header connections, some are on the additional pin headers across the bottom.
Using a bespoke configuration is possible using a series of calls to set the SPI pins as shown below.
SPI.setRX(SPI_MISO);
SPI.setCS(SPI_SS);
SPI.setSCK(SPI_SCLK);
SPI.setTX(SPI_MOSI);
SPI.begin(true);To use pins for SPI1, replace SPI above with SPI1. As long as this happens prior to the call to the Adafruit libraries, everything works fine.
A Common Option
It would be nice to find a set of physical pin connections that I know would always work regardless of the board in use: RP2040, ESP32-S3 or ESP32-C3.
With careful noting of the RP2040 limitations, I think that is largely possible with the following. Even though the GPIO numbers are different, the physical pins are common on all three boards.
DisplayFunctionWS PinRP2040ESP32-C3ESP32-S3BLKBacklight control
(not required)N/CN/CN/CCS1Chip select
Display 1H2 P6GP5GP9GP10DCData/CommandH2 P5GP4GP10GP11RESResetH2 P9GP8GP6GP7SDAData (MOSI)H2 P8GP7GP7GP8SCLClock (SCLK)H2 P7GP6GP8GP9VCCPowerH1 P33V33V33V3GNDGroundH1 P2GNDGNDGNDCS2CS Display 2H1 P9GP14GP5GP6CS3CS Display 3H1 P8GP15GP4GP5CS4CS Display 4H1 P7GP26GP3GP4A couple of notes:
- I’ve avoided pins 1-4 on header 2, as the ESP32-C3 can’t use them for SPI and they support either the UART or USB.
- I’ve had to include a MISO (SPI RX) pin in each configuration too, so I’ve just picked something that can be ignored. For RP2040 that has to be one of GP0, GP4 or GP16 however, which could clash with either the UART, the above configuration for DC pin, or the onboard WS2812 LED, but there isn’t much that can be done.
- I’ve allowed three consecutive pins on the first header for optional additional CS pins for displays 2 to 4.
Here is the full set of configurable code for the above:
#include <Adafruit_GFX.h> // Core graphics library
#include <Adafruit_ST7735.h> // Hardware-specific library for ST7735
#include <SPI.h>
//#define WS_RP2040_ZERO
//#define WS_ESP32C3_ZERO
#define WS_ESP32S3_ZERO
#ifdef WS_RP2040_ZERO
#define SPI_SS 5
#define SPI_MOSI 7
#define SPI_SCLK 6
#define SPI_MISO 4 // Not used
#define SPI_BUS SPI
#define TFT_CS1 SPI_SS
#define TFT_CS2 14
#define TFT_CS3 15
#define TFT_CS4 26
#define TFT_RST 8
#define TFT_DC 4
#endif
#ifdef WS_ESP32C3_ZERO
#define SPI_SS 9
#define SPI_MOSI 7
#define SPI_SCLK 8
#define SPI_MISO 0 // Not used
SPIClass MySPI(FSPI);
#define TFT_CS1 SPI_SS
#define TFT_CS2 5
#define TFT_CS3 4
#define TFT_CS4 3
#define TFT_RST 6
#define TFT_DC 10
#endif
#ifdef WS_ESP32S3_ZERO
#define SPI_SS 10
#define SPI_MOSI 8
#define SPI_SCLK 9
#define SPI_MISO 1 // Not used
SPIClass MySPI(FSPI);
#define TFT_CS1 SPI_SS
#define TFT_CS2 6
#define TFT_CS3 5
#define TFT_CS4 4
#define TFT_RST 7
#define TFT_DC 11
#endif
#ifdef WS_RP2040_ZERO
Adafruit_ST7735 tft1 = Adafruit_ST7735(TFT_CS1, TFT_DC, TFT_RST);
Adafruit_ST7735 tft2 = Adafruit_ST7735(TFT_CS2, TFT_DC, -1);
#else
Adafruit_ST7735 tft1 = Adafruit_ST7735(&MySPI, TFT_CS1, TFT_DC, TFT_RST);
Adafruit_ST7735 tft2 = Adafruit_ST7735(&MySPI, TFT_CS2, TFT_DC, -1);
#endif
void setup() {
#ifdef WS_RP2040_ZERO
SPI_BUS.setRX(SPI_MISO);
SPI_BUS.setCS(SPI_SS);
SPI_BUS.setSCK(SPI_SCLK);
SPI_BUS.setTX(SPI_MOSI);
SPI_BUS.begin(true);
#else
MySPI.begin(SPI_SCLK, SPI_MISO, SPI_MOSI, SPI_SS);
pinMode(SPI_SS, OUTPUT);
#endif
tft1.initR(INITR_MINI160x80_PLUGIN);
tft2.initR(INITR_MINI160x80_PLUGIN);
tft1.setRotation(3);
tft1.fillScreen(ST77XX_BLACK);
tft2.setRotation(3);
tft2.fillScreen(ST77XX_BLACK);
}
void loop() {
unsigned long time = millis();
tft1.fillRect(10, 20, tft1.width(), 20, ST77XX_BLACK);
tft1.setTextColor(ST77XX_GREEN);
tft1.setCursor(10, 20);
tft1.print(time, DEC);
delay(100);
time = millis();
tft2.fillRect(10, 20, tft2.width(), 20, ST77XX_BLACK);
tft2.setTextColor(ST77XX_MAGENTA);
tft2.setCursor(10, 20);
tft2.print(time, DEC);
delay(400);
}Closing Thoughts
It is a little annoying that these great boards don’t share a re-usable, common pinout in terms of naming and positions, but I guess that isn’t the main focus for these systems.
Still, it seems that a common hardware pinout can be made that supports many displays, which is great, as I’d really like to get a number of them onto a PCB!
Kevin
#arduinoUno #esp32c3 #ESP32s3 #rp2040 #st7735 #tftDisplay #WaveshareZero
-
Arduino with Multiple Displays – Part 2
As I mentioned in my last post on Arduino with Multiple Displays I’m going to look at other microcontrollers too. This post takes a wander through my Waveshare Zero and similar format boards that each support one of the RP2040, ESP32-C3 or ESP32-S3.
Warning! I strongly recommend using old or second hand equipment for your experiments. I am not responsible for any damage to expensive instruments!
These are the key Arduino tutorials for the main concepts used in this project:
- Arduino with Multiple Displays
- https://emalliab.wordpress.com/2025/07/19/small-microcontroller-displays/
If you are new to microcontrollers, see the Getting Started pages.
Parts list
- A Waveshare Zero format board or similar
- 2x 0.96″ ST7735 60×180 SPI TFT displays.
- Breadboard and jumper wires.
Once again I’m using displays that look like this – note the order of the pins.
The Circuit
All circuits are a variation on the above, requiring the following ideal connections:
DisplayFunctionRP2040ESP32-C3ESP32-S3BLKBacklight control
(not required)N/CN/CN/CCSChip select
One per display.5 or any SPI0 CS1010DCData/Command888RESReset1499SDAData (MOSI)3 or any SPI0 MOSI6 or 711SCLClock (SCLK)2 or any SPI0 SCLK4 or 612VCCPower3V33V33V3GNDGroundGNDGNDGNDFor the explanations of the pin choices, and what it means for the code, see the following sections.
ESP32-S3 Zero
In the Arduino IDE, using board ESP32-> Waveshare ESP32-S3-Zero.
There are several SPI buses on the ESP32-S3, but they have fixed uses as follows (see the ESP32-S3 Technical Reference Manual Chapter 30 “SPI Controller”):
- SPI 0: Reserved for internal use.
- SPI 1: Reserved for internal use.
- SPI 2: General purpose use – often called FSPI in the documentation.
- SPI 3: General purpose use – often called SPI or SPI3.
Sometimes the two SPI buses are called VSPI and HSPI but I think that is really terminology from the original ESP32 rather than the ESP32-S3.
The ESP32 Arduino core for the Waveshare ESP32-S3 Zero variant defines the following:
// Mapping based on the ESP32S3 data sheet - alternate for SPI2
static const uint8_t SS = 34; // FSPICS0
static const uint8_t MOSI = 35; // FSPID
static const uint8_t MISO = 37; // FSPIQ
static const uint8_t SCK = 36; // FSPICLKBy default the Adafruit libraries will use the boards default SPI interface, as defined in the variants.h file – i.e. the above.
When it comes to assigning SPI devices to GPIO there are a few considerations (see the “ESP32-S3 Technical Reference Manual, Chapter 6 “IO MUX and GPIO Matrix”):
- In general, any GPIO can be mapped onto any SPI function. However…
- Some GPIO have special “strapping” functions so are best avoided.
- Some GPIOs have a default SPI function that bypasses the GPIO MUX routing, so allows for better performance (see section 6.6 “Direct Input and Output via IO MUX”).
From my reading of the reference manual I believe the following are default “non-MUX” SPI connections:
In the previous table, where SPI3 is mentioned, then the entry for “Direct IO via IO MUX” is set to “no”, so I’m guessing that isn’t available.
But now we can see why the Arduino core is using GPIO 34-37, but we can also see that GPIO 10-13 would be an alternative (fast) option too.
The problem is that not all of GPIO 34-37 are broken out on a Waveshare ESP32-S3 Zero, so I need to use the alternative pinouts. Aside: this makes no sense to me that these are the defaults in the Waveshare ESP32-S3 Zero’s “variant.h” file, but anyway…
To use a different SPI interface requires using a constructor that passes in an initialised SPI instance. There is an example in the ESP32 core for setting up multiple SPI buses here: https://github.com/espressif/arduino-esp32/blob/master/libraries/SPI/examples/SPI_Multiple_Buses/SPI_Multiple_Buses.ino
This leads to the pins as defined in the previous table, and the code below to setup one of the displays.
#include <Adafruit_GFX.h> // Core graphics library
#include <Adafruit_ST7735.h> // Hardware-specific library for ST7735
#include <SPI.h>
#define SPI_SS 10
#define SPI_MOSI 11
#define SPI_SCLK 12
#define SPI_MISO 13
SPIClass MySPI(FSPI);
#define TFT_CS SPI_SS
#define TFT_RST 9
#define TFT_DC 8
Adafruit_ST7735 tft = Adafruit_ST7735(&MySPI, TFT_CS, TFT_DC, TFT_RST);
void setup() {
MySPI.begin(SPI_SCLK, SPI_MISO, SPI_MOSI, SPI_SS);
pinMode(SPI_SS, OUTPUT);
tft.initR(INITR_MINI160x80_PLUGIN);
}ESP32-C3 Zero
In the Arduino IDE, using board ESP32-> ESP32C3 Dev Module.
Again there are several SPI buses on the ESP32-C3, with the same fixed uses as follows (see the ESP32-C3 Technical Reference Manual Chapter 30 “SPI Controller”):
- SPI 0: Reserved for internal use.
- SPI 1: Reserved for internal use.
- SPI 2: General purpose use – sometimes called GP-SPI in the documentation.
The ESP32-C3 also has a very similar SPI arrangement to the ESP32-S3, in that whilst any pin can be configured for SPI usage, there are certain hard-wired optional arrangements that bypass the GPIO routing matrix.
The faster (direct to IO MUX) pins are as follows (more here):
- CS0 – 10
- SCLK – 6
- MISO – 2
- MOSI – 7
Curiously, the general ESP32-C3 Arduino variant defines them as follows:
static const uint8_t SS = 7;
static const uint8_t MOSI = 6;
static const uint8_t MISO = 5;
static const uint8_t SCK = 4;From the Technical Reference manual, we can see that the default Arduino definitions above, do not support the non-routed, direct-to-IO MUX pin mappings, which from the table below do indeed map onto GPIO 2, 6, 7, 10.
In terms of using a Waveshare ESP32-C3 Zero, both combinations would be supported on the broken out GPIO, so from a software point of view, the Adafruit libraries could be used “as is” with the default mapping, or with a custom SPI definition (as shown above) with the more bespoke, but faster, mapping.
RP2040 Zero
This is using the (unofficial) RP2040 core from here: https://github.com/earlephilhower/arduino-pico, where this is an entry: RP2040 -> Waveshare RP2040 Zero.
The RP2040 has two SPI peripherals and the SPI functions are mapped onto specific sets of GPIO pins. This gives a range of flexibility, but not arbitrary flexibility. The board definition file for the Waveshare RP2040 Zero provides this as a default:
// SPI
#define PIN_SPI0_MISO (4u)
#define PIN_SPI0_MOSI (3u)
#define PIN_SPI0_SCK (2u)
#define PIN_SPI0_SS (5u)
#define PIN_SPI1_MISO (12u)
#define PIN_SPI1_MOSI (15u)
#define PIN_SPI1_SCK (14u)
#define PIN_SPI1_SS (13u)Note that the SPI1 pins for the Waveshare RP2040 Zero are not all on the standard header connections, some are on the additional pin headers across the bottom.
Using a bespoke configuration is possible using a series of calls to set the SPI pins as shown below.
SPI.setRX(SPI_MISO);
SPI.setCS(SPI_SS);
SPI.setSCK(SPI_SCLK);
SPI.setTX(SPI_MOSI);
SPI.begin(true);To use pins for SPI1, replace SPI above with SPI1. As long as this happens prior to the call to the Adafruit libraries, everything works fine.
A Common Option
It would be nice to find a set of physical pin connections that I know would always work regardless of the board in use: RP2040, ESP32-S3 or ESP32-C3.
With careful noting of the RP2040 limitations, I think that is largely possible with the following. Even though the GPIO numbers are different, the physical pins are common on all three boards.
DisplayFunctionWS PinRP2040ESP32-C3ESP32-S3BLKBacklight control
(not required)N/CN/CN/CCS1Chip select
Display 1H2 P6GP5GP9GP10DCData/CommandH2 P5GP4GP10GP11RESResetH2 P9GP8GP6GP7SDAData (MOSI)H2 P8GP7GP7GP8SCLClock (SCLK)H2 P7GP6GP8GP9VCCPowerH1 P33V33V33V3GNDGroundH1 P2GNDGNDGNDCS2CS Display 2H1 P9GP14GP5GP6CS3CS Display 3H1 P8GP15GP4GP5CS4CS Display 4H1 P7GP26GP3GP4A couple of notes:
- I’ve avoided pins 1-4 on header 2, as the ESP32-C3 can’t use them for SPI and they support either the UART or USB.
- I’ve had to include a MISO (SPI RX) pin in each configuration too, so I’ve just picked something that can be ignored. For RP2040 that has to be one of GP0, GP4 or GP16 however, which could clash with either the UART, the above configuration for DC pin, or the onboard WS2812 LED, but there isn’t much that can be done.
- I’ve allowed three consecutive pins on the first header for optional additional CS pins for displays 2 to 4.
Here is the full set of configurable code for the above:
#include <Adafruit_GFX.h> // Core graphics library
#include <Adafruit_ST7735.h> // Hardware-specific library for ST7735
#include <SPI.h>
//#define WS_RP2040_ZERO
//#define WS_ESP32C3_ZERO
#define WS_ESP32S3_ZERO
#ifdef WS_RP2040_ZERO
#define SPI_SS 5
#define SPI_MOSI 7
#define SPI_SCLK 6
#define SPI_MISO 4 // Not used
#define SPI_BUS SPI
#define TFT_CS1 SPI_SS
#define TFT_CS2 14
#define TFT_CS3 15
#define TFT_CS4 26
#define TFT_RST 8
#define TFT_DC 4
#endif
#ifdef WS_ESP32C3_ZERO
#define SPI_SS 9
#define SPI_MOSI 7
#define SPI_SCLK 8
#define SPI_MISO 0 // Not used
SPIClass MySPI(FSPI);
#define TFT_CS1 SPI_SS
#define TFT_CS2 5
#define TFT_CS3 4
#define TFT_CS4 3
#define TFT_RST 6
#define TFT_DC 10
#endif
#ifdef WS_ESP32S3_ZERO
#define SPI_SS 10
#define SPI_MOSI 8
#define SPI_SCLK 9
#define SPI_MISO 1 // Not used
SPIClass MySPI(FSPI);
#define TFT_CS1 SPI_SS
#define TFT_CS2 6
#define TFT_CS3 5
#define TFT_CS4 4
#define TFT_RST 7
#define TFT_DC 11
#endif
#ifdef WS_RP2040_ZERO
Adafruit_ST7735 tft1 = Adafruit_ST7735(TFT_CS1, TFT_DC, TFT_RST);
Adafruit_ST7735 tft2 = Adafruit_ST7735(TFT_CS2, TFT_DC, -1);
#else
Adafruit_ST7735 tft1 = Adafruit_ST7735(&MySPI, TFT_CS1, TFT_DC, TFT_RST);
Adafruit_ST7735 tft2 = Adafruit_ST7735(&MySPI, TFT_CS2, TFT_DC, -1);
#endif
void setup() {
#ifdef WS_RP2040_ZERO
SPI_BUS.setRX(SPI_MISO);
SPI_BUS.setCS(SPI_SS);
SPI_BUS.setSCK(SPI_SCLK);
SPI_BUS.setTX(SPI_MOSI);
SPI_BUS.begin(true);
#else
MySPI.begin(SPI_SCLK, SPI_MISO, SPI_MOSI, SPI_SS);
pinMode(SPI_SS, OUTPUT);
#endif
tft1.initR(INITR_MINI160x80_PLUGIN);
tft2.initR(INITR_MINI160x80_PLUGIN);
tft1.setRotation(3);
tft1.fillScreen(ST77XX_BLACK);
tft2.setRotation(3);
tft2.fillScreen(ST77XX_BLACK);
}
void loop() {
unsigned long time = millis();
tft1.fillRect(10, 20, tft1.width(), 20, ST77XX_BLACK);
tft1.setTextColor(ST77XX_GREEN);
tft1.setCursor(10, 20);
tft1.print(time, DEC);
delay(100);
time = millis();
tft2.fillRect(10, 20, tft2.width(), 20, ST77XX_BLACK);
tft2.setTextColor(ST77XX_MAGENTA);
tft2.setCursor(10, 20);
tft2.print(time, DEC);
delay(400);
}Closing Thoughts
It is a little annoying that these great boards don’t share a re-usable, common pinout in terms of naming and positions, but I guess that isn’t the main focus for these systems.
Still, it seems that a common hardware pinout can be made that supports many displays, which is great, as I’d really like to get a number of them onto a PCB!
Kevin
#arduinoUno #esp32c3 #ESP32s3 #rp2040 #st7735 #tftDisplay #WaveshareZero
-
ESP32 S3 DevKit Experimenter PCB Build Guide
Here are the build notes for my ESP32 S3 DevKit Experimenter PCB Design.
Warning! I strongly recommend using old or second hand equipment for your experiments. I am not responsible for any damage to expensive instruments!
If you are new to electronics and microcontrollers, see the Getting Started pages.
Bill of Materials
- ESP32S3 DevKit Experimenter PCB (GitHub link below)
- ESP32S2 DevKitC (official or clone – see ESP32 S3 DevKit)
- MIDI Circuit:
- 1x H11L1 optoisolator
- 1x 1N4148 or 1N914 signal diode
- Resistors: 1x 10Ω, 1x 33Ω, 1x 220Ω, 1×470Ω
- 1x 100nF capacitor
- Either: 2x MIDI DIN sockets (see photos and PCB for footprint)
- Or: 2x 3.5mm stereo TRS sockets (see photos and PCB for footprint)
- Pin headers and jumpers
- Optional: 6-way DIP socket
- Audio Output Circuit:
- Resistors: 2x 1K, 2x 2K
- 2x 10uF non-polar capacitors
- 2x 33nF ceramic capacitors
- 1x 3.5mm stereo TRS socket
- Power Circuit:
- 1x 7805 regulator
- Electrolytic Capacitors: 1x 100uF, 1x 10uF
- 1x 100nF Ceramic Capacitor
- SPST switch with 2.54mm pitch connectors
- 2-way header pins
- 2.1mm barrel jack socket (see photos and PCB for footprint)
- 8x 10K potentiometers (see photos and PCB for footprint)
- Optional: 2x 22-way pin header sockets
- Additional pin headers or sockets as required
Each circuit module is effectively optional. The position of the 22-way headers will depend on which type of module is used. The clone versions are 1 pin row wider than the official version.
There are some solder-bridge configuration options too, which will be discussed later.
Build Steps
Taking a typical “low to high” soldering approach, this is the suggested order of assembly:
- All resistors and diode.
- DIP socket (if used) and TRS socket(s).
- Disc capacitors.
- Switch
- Jumper and pin headers.
- 22-way pin sockets (if used).
- Non-polar and electrolytic capacitors.
- 7805 regulator.
- Potentiometers.
- DIN sockets.
Here are some build photos for the MIDI DIN version of the board. If using MIDI TRS sockets, then these can be installed at the same time as the audio socket.
If using 22-way headers for the DevKit, then the position will depend on which type of DevKit module is being used. In the photo below, I’ve installed 3 sets of 22-way headers to allow me to use either a clone or official module.
The remaining components can almost be installed in any order that makes sense at the time.
Once the main build is complete, two additional capacitors are required for the audio PWM output circuit. Two 33nF capacitors should be soldered across the 1K resistors. This is probably best done on the underside of the PCB as shown below.
Ignore the red patch wire. I managed to cut through a track whilst clipping the excess leads after soldering.
Configuration Options
The following are configurable and can be set by using pin headers and jumpers; solder bridges; or possibly wire links.
- UART for MIDI – pin header + jumpers.
- Audio Output – can be disconnected by breaking solder jumpers on rear of the board under 1K/2K resistors.
- GPIO used for RV3 and RV8 – can be set using solder jumpers on rear of the board under RV3 and RV8.
Testing
I recommend performing the general tests described here: PCBs.
WARNING: The DevKit can be powered from either the USB sockets or the new power circuit, but not both at the same time.
The sample application section includes some simple sketches that can be used to test the functionality of the board.
PCB Errata
There are the following issues with this PCB:
- I should have oriented the DevKit the other way up so that the USB sockets were on the edge of the board, not overhanging the prototyping area!
- The Audio filter requires additional capacitors (see notes).
Enhancements:
- None
Sample Applications
Analog Potentiometers
The following will read all 8 pots and echo the values to the serial monitor.
void setup() {
Serial.begin(115200);
}
void loop() {
for (int i=0; i<8; i++) {
int aval = analogRead(A0+i);
Serial.print(aval);
Serial.print("\t");
}
Serial.print("\n");
delay(100);
}Audio PWM Output
The following will output a 440 Hz sine wave on the PWM channel on GPIO 15. Change to 16 to see the other one.
int pwm_pin = 15;#define NUM_SAMPLES 256uint8_t sinedata[NUM_SAMPLES];#define PWM_RESOLUTION 8#define PWM_FREQUENCY 48000#define TIMER_FREQ 10000000#define TIMER_RATE 305#define FREQ2INC(f) (f*2)uint16_t acc, inc;void ARDUINO_ISR_ATTR timerIsr (void) { acc += inc; ledcWrite (pwm_pin, sinedata[acc >> 8]);}hw_timer_t *timer = NULL;void setup () { ledcSetClockSource(LEDC_AUTO_CLK); for (int i=0; i<NUM_SAMPLES; i++) { sinedata[i] = 127 + (uint8_t) (127.0 * sin (((float)i * 2.0 * 3.14159) / (float)NUM_SAMPLES)); } timer = timerBegin(TIMER_FREQ); timerAttachInterrupt(timer, &timerIsr); timerAlarm(timer, TIMER_RATE, true, 0); ledcAttach(pwm_pin, PWM_FREQUENCY, PWM_RESOLUTION); inc = FREQ2INC(440);}void loop () { }I’m getting a pretty good signal with a 33nF filter capacitor, but the signal still retails some bias. I’m getting a Vpp of around 1.1V.
But it starts out with a swing from around -200mV to +900mV. But this slowly improves over time and after a few minutes is much closer to a nominal -500mV to +600mV. I guess that is probably my cheap capacitors!
MIDI
Most of the MIDI monitors, routers and sending projects I have should work with the MIDI setup. In the default configuration, using UART0 (GPIO 43/44) for MIDI, that appears as Serial0 or the default MIDI configuration (more on serial ports on the ESP32S3 here: ESP32 S3 DevKit).
So the Simple MIDI Serial Monitor should just work and anything sent to the board should:
- Illuminate the on-board (RGB) LED.
- Echo back out to the MIDI OUT port.
Here is the full test code:
#include <MIDI.h>
MIDI_CREATE_DEFAULT_INSTANCE();
void setup() {
MIDI.begin(MIDI_CHANNEL_OMNI);
pinMode (LED_BUILTIN, OUTPUT);
}
void loop() {
if (MIDI.read()) {
if (MIDI.getType() == midi::NoteOn) {
digitalWrite (LED_BUILTIN, HIGH);
delay (100);
digitalWrite (LED_BUILTIN, LOW);
}
}
}Note: as the MIDI is (probably) hanging of UART0 which is also routed to the USB “COM” port, it will be easier to upload via the USB “USB” port. This won’t clash with the MIDI circuitry on UART0.
Closing Thoughts
I seem to be having a run of “doh” moments with a few of these PCBs, but then that is the price I pay for taking shortcuts by only designing them in my head rather than prototyping them first!
But arguably, it is still a lot easier using a soldered PCB than attempting to build the various elements on solderless breadboard, so in a way that is what these prototypes are largely for.
So apart from the filter issue which is actually fairly easily solved, this seems to work pretty well.
Kevin
-
ESP32 S3 DevKit Experimenter PCB Design
This a version of the ESP32 WROOM Mozzi Experimenter PCB for the latest ESP32-S3 DevKitC board I’ve found.
For the background on the boards themselves, see my notes here: ESP32 S3 DevKit.
Warning! I strongly recommend using old or second hand equipment for your experiments. I am not responsible for any damage to expensive instruments!
If you are new to Microcontrollers, see the Getting Started pages.
The Circuit
This is mostly just breaking out the pins of the ESP32S3 DevKitC to header pins, but there are a couple of additional features too:
- There are additional rows of headers. The idea is to support the official and clone boards, which means coping with the fact the clone boards are 1 row of pins wider than the official boards.
- There is MIDI IN and OUT with jumpers to select UART0 or UART1.
- There is a stereo PWM output circuit (see notes below).
- There are 8 potentiometers connected to ADC1.
- There is a 7805 or equivalent regulator to provide power if required.
One slight complication is the possibility that GPIO3 (ADC1_CH2) is required as a STRAPPING pin or that GPIO8 (ADC1_CH7) is required for I2C (more in the previous post) so there is a solder bridge option for either of them to switch over to GPIO10 (ADC1_CH9) instead.
The complete GPIO usage is as follows:
GPIO0On board BOOT buttonGPIO 1-8Potentiometer 1-8GPIO 10Optional replacement for GPIO 3 or 8GPIO 15, 16PWM audio outputGPIO 43, 44MIDI if UART0 is selectedGPIO 17, 18MIDI if UART1 is selectedGPIO 1-20Analog breakout area*GPIO 21, 38-49Digital breakout area*GPIO 38 or 48Onboard RGB LED* As already mentioned some of these have alternative or preferred functions.
Audio PWM Output
I based this on the output circuit for my ESP32 WROOM Mozzi Experimenter PCB Design, but I was forgetting that the original ESP32 has a DAC and so only requires a potential divider to reduce the voltage levels and a capacitor to remove the DC bias.
The ESP32S3 does not have a DAC, so the output will have to be via PWM if no external DAC is added. This means this output circuit really needs a low-pass filter to smooth out the pulses from the PWM signal.
That hasn’t been included in the design, but can be implemented by adding capacitors across the terminals of the 1K resistors, as shown below.
Following the discussion from Arduino PWM Output Filter Circuit, we can see that a 2K/1K potential divider can (loosely) be treated as a ~666K resistor for the purposes of a low-pass filter calculation. So this gives me various options in terms of capacitor size as follows.
ResistorCapacitorRoll-off frequency666K10nF24 kHz666K33nF7 kHz666K68nF3.5 kHz666K100nF2.4 kHzThe greatest smoothing will come with the lowest cut-off, but 2.4kHz or 3.5kHz will limit the higher audio frequencies somewhat. But a 10nF might not give me enough smoothing.
It will also depend somewhat on the PWM frequency chosen. The higher, i.e. above the audio frequency range required, the better.
I’ll start with adding 33nF and see how that looks then might change with some experimentation.
If an external DAC is used, then there are solder jumpers provided that can be broken to disconnect this part of the circuit anyway.
PCB Design
I initially considered only breaking out GPIO pins that weren’t being used for additional functions, but then decided I’d just break them all out alongside the prototyping area. Any pins that might be problematic or have an existing function on the board are labelled in brackets – e.g. (GPIO 43).
The solder jumpers for the GPIO/ADC choices are on the underside of the board.
As previously mentioned, the headers are arranged such that it will support the official DevKitC or the slightly wider clones.
The jumper for UART selection for MIDI can serve as a “disable MIDI to allow use of the serial port” function too if required.
There is also a twin jumper option for direct 5V input instead of going via the barrel jack and regulator.
Closing Thoughts
The omission of the capacitors in the PWM filter is a small annoyance, but it is relatively easily fixed.
Apart from that, there is a fair bit included on this board. It should serve as a good platform for further experimentation.
Kevin